瀏覽代碼

Merge remote-tracking branch 'origin/hl' into zzw_sift_wheel

# Conflicts:
#	CMakeLists.txt
#	error_code/error_code.h
#	laser/Laser.cpp
#	laser/Laser.h
#	laser/LivoxLaser.cpp
#	laser/LivoxLaser.h
#	laser/LivoxMid100Laser.cpp
#	laser/LivoxMid100Laser.h
#	laser/laser_parameter.pb.cc
#	laser/laser_parameter.pb.h
#	laser/laser_parameter.proto
#	laser/laser_task_command.cpp
#	laser/laser_task_command.h
#	main.cpp
#	task/task_command_manager.h
#	tool/StdCondition.cpp
#	tool/StdCondition.h
#	tool/pathcreator.cpp
#	tool/pathcreator.h
zx 5 年之前
父節點
當前提交
b779afe78a
共有 64 個文件被更改,包括 4769 次插入1184 次删除
  1. 二進制
      Document/Laser.png
  2. 二進制
      Document/LivoxLaser.png
  3. 二進制
      Document/binary_buf.png
  4. 二進制
      Document/laser_task_command.png
  5. 二進制
      Document/laser功能模块图.eddx
  6. 二進制
      Document/laser功能模块图.png
  7. 二進制
      Document/laser数据流程图.eddx
  8. 二進制
      Document/laser数据流程图.png
  9. 二進制
      Document/laser程序流程图.eddx
  10. 二進制
      Document/laser程序流程图.png
  11. 二進制
      Document/task_command_manager.png
  12. 二進制
      Document/thread_condition.png
  13. 二進制
      Document/thread_safe_queue.png
  14. 二進制
      Document/智象停车测量软件设计文档 .docx
  15. 51 15
      error_code/error_code.cpp
  16. 32 74
      error_code/error_code.h
  17. 476 320
      laser/Laser.cpp
  18. 135 121
      laser/Laser.h
  19. 304 0
      laser/Laser.puml
  20. 253 105
      laser/LivoxLaser.cpp
  21. 52 20
      laser/LivoxLaser.h
  22. 230 0
      laser/LivoxLaser.puml
  23. 192 128
      laser/LivoxMid100Laser.cpp
  24. 22 6
      laser/LivoxMid100Laser.h
  25. 2 1
      laser/Point3D.h
  26. 323 0
      laser/Sick511FileLaser.cpp
  27. 55 0
      laser/Sick511FileLaser.h
  28. 343 0
      laser/TcpLaser.cpp
  29. 68 0
      laser/TcpLaser.h
  30. 352 0
      laser/UdpLaser.cpp
  31. 61 0
      laser/UdpLaser.h
  32. 65 140
      laser/laser_parameter.pb.cc
  33. 42 110
      laser/laser_parameter.pb.h
  34. 82 65
      laser/laser_task_command.cpp
  35. 50 41
      laser/laser_task_command.h
  36. 114 0
      laser/laser_task_command.puml
  37. 0 0
      main.cpp
  38. 二進制
      png/Laser.png
  39. 二進制
      png/LivoxLaser.png
  40. 二進制
      png/binary_buf.png
  41. 二進制
      png/laser_task_command.png
  42. 二進制
      png/laser功能模块图.eddx
  43. 二進制
      png/laser功能模块图.png
  44. 二進制
      png/laser数据流程图.eddx
  45. 二進制
      png/laser数据流程图.png
  46. 二進制
      png/laser程序流程图.eddx
  47. 二進制
      png/laser程序流程图.png
  48. 二進制
      png/task_command_manager.png
  49. 二進制
      png/thread_condition.png
  50. 二進制
      png/thread_safe_queue.png
  51. 16 1
      task/task_command_manager.cpp
  52. 20 15
      task/task_command_manager.h
  53. 82 0
      task/task_command_manager.puml
  54. 319 0
      tool/binary_buf.cpp
  55. 88 0
      tool/binary_buf.h
  56. 85 0
      tool/binary_buf.puml
  57. 17 21
      tool/pathcreator.cpp
  58. 3 1
      tool/pathcreator.h
  59. 144 0
      tool/thread_condition.cpp
  60. 114 0
      tool/thread_condition.h
  61. 96 0
      tool/thread_condition.puml
  62. 34 0
      tool/thread_safe_queue.cpp
  63. 339 0
      tool/thread_safe_queue.h
  64. 108 0
      tool/thread_safe_queue.puml

二進制
Document/Laser.png


二進制
Document/LivoxLaser.png


二進制
Document/binary_buf.png


二進制
Document/laser_task_command.png


二進制
Document/laser功能模块图.eddx


二進制
Document/laser功能模块图.png


二進制
Document/laser数据流程图.eddx


二進制
Document/laser数据流程图.png


二進制
Document/laser程序流程图.eddx


二進制
Document/laser程序流程图.png


二進制
Document/task_command_manager.png


二進制
Document/thread_condition.png


二進制
Document/thread_safe_queue.png


二進制
Document/智象停车测量软件设计文档 .docx


+ 51 - 15
error_code/error_code.cpp

@@ -31,7 +31,7 @@ Error_manager::Error_manager(const Error_manager & error_manager)
 }
 //赋值构造
 Error_manager::Error_manager(Error_code error_code, Error_level error_level,
-    char* p_error_description, int description_length)
+    const char* p_error_description, int description_length)
 {
     pm_error_description=NULL;
     m_error_code = error_code;
@@ -63,7 +63,7 @@ void Error_manager::error_manager_init()
     return;
 }
 //初始化
-void Error_manager::error_manager_init(Error_code error_code, Error_level error_level, char* p_error_description, int description_length)
+void Error_manager::error_manager_init(Error_code error_code, Error_level error_level, const char* p_error_description, int description_length)
 {
     m_error_code = error_code;
     m_error_level = error_level;
@@ -79,7 +79,7 @@ void Error_manager::error_manager_init(Error_code error_code, Error_level error_
     return ;
 }
 //重置
-void Error_manager::error_manager_reset(Error_code error_code, Error_level error_level, char* p_error_description, int description_length)
+void Error_manager::error_manager_reset(Error_code error_code, Error_level error_level, const char* p_error_description, int description_length)
 {
     m_error_code = error_code;
     m_error_level = error_level;
@@ -176,11 +176,11 @@ char* Error_manager::get_error_description()
 //复制错误描述,(深拷贝)
 //output:p_error_description     错误描述的字符串指针,不可以为NULL,必须要有实际的内存
 //output:description_length      错误描述的字符串长度,不可以为0,长度最好足够大,一般256即可。
-void Error_manager::copy_error_description(char* p_error_description, int description_length)
+void Error_manager::copy_error_description(const char* p_error_description, int description_length)
 {
     if(p_error_description != NULL && pm_error_description != NULL)
     {
-        char *pt_source = p_error_description;
+        char *pt_source = (char *)p_error_description;
         char* pt_destination = pm_error_description;
 
         int t_length_min = m_description_length;
@@ -241,7 +241,7 @@ void Error_manager::set_error_level_location(Error_level error_level)
     return;
 }
 //设置错误描述
-void Error_manager::set_error_description(char* p_error_description, int description_length)
+void Error_manager::set_error_description(const char* p_error_description, int description_length)
 {
     reallocate_memory_and_copy_string(p_error_description, description_length);
     return ;
@@ -254,13 +254,13 @@ void Error_manager::set_error_description(std::string & error_description_string
 }
 
 //尾部追加错误描述
-void Error_manager::add_error_description(char* p_error_description, int description_length)
+void Error_manager::add_error_description(const char* p_error_description, int description_length)
 {
     if(p_error_description !=NULL)
     {
         char* pt_description_front = pm_error_description;
         int t_description_front_length = m_description_length;
-        char* pt_description_back = p_error_description;
+        char* pt_description_back = (char *)p_error_description;
         int t_description_back_length = 0;
 
         if(description_length == 0)
@@ -272,7 +272,7 @@ void Error_manager::add_error_description(char* p_error_description, int descrip
                 pt_description_back++;
             }
             t_description_back_length++;
-            pt_description_back = p_error_description;
+            pt_description_back = (char *)p_error_description;
         }
         else
         {
@@ -317,7 +317,7 @@ bool Error_manager::is_equal_error_manager(const Error_manager & error_manager)
 }
 //比较并覆盖错误,讲低级错误转为字符串存放于描述中,
 //如果错误相同,则保留this的,将输入参数转入描述。
-void Error_manager::compare_and_cover_error( Error_manager & error_manager)
+void Error_manager::compare_and_cover_error(const Error_manager & error_manager)
 {
     if(this->m_error_code == SUCCESS)
     {
@@ -325,7 +325,7 @@ void Error_manager::compare_and_cover_error( Error_manager & error_manager)
     }
     else if (error_manager.m_error_code == SUCCESS)
     {
-        //
+		return;
     }
     else
     {
@@ -345,12 +345,48 @@ void Error_manager::compare_and_cover_error( Error_manager & error_manager)
         {
             t_string_inside_length = ERROR_NAMAGER_TO_STRING_FRONT_LENGTH + error_manager.m_description_length;
             pt_string_inside = (char*)malloc(t_string_inside_length);
-            error_manager.translate_error_to_string(pt_string_inside, t_string_inside_length);
+			((Error_manager & )error_manager).translate_error_to_string(pt_string_inside, t_string_inside_length);
 
             add_error_description(pt_string_inside,t_string_inside_length);
         }
     }
 }
+//比较并覆盖错误,讲低级错误转为字符串存放于描述中,
+//如果错误相同,则保留this的,将输入参数转入描述。
+void Error_manager::compare_and_cover_error( Error_manager * p_error_manager)
+{
+	if(this->m_error_code == SUCCESS)
+	{
+		error_manager_reset(*p_error_manager);
+	}
+	else if (p_error_manager->m_error_code == SUCCESS)
+	{
+		//
+	}
+	else
+	{
+		Error_manager t_error_manager_new;
+		char* pt_string_inside = NULL;
+		int t_string_inside_length = 0;
+		if(this->m_error_level < p_error_manager->m_error_level)
+		{
+			t_string_inside_length = ERROR_NAMAGER_TO_STRING_FRONT_LENGTH + this->m_description_length;
+			pt_string_inside = (char*)malloc(t_string_inside_length);
+			translate_error_to_string(pt_string_inside, t_string_inside_length);
+
+			error_manager_reset(*p_error_manager);
+			add_error_description(pt_string_inside,t_string_inside_length);
+		}
+		else
+		{
+			t_string_inside_length = ERROR_NAMAGER_TO_STRING_FRONT_LENGTH + p_error_manager->m_description_length;
+			pt_string_inside = (char*)malloc(t_string_inside_length);
+			p_error_manager->translate_error_to_string(pt_string_inside, t_string_inside_length);
+
+			add_error_description(pt_string_inside,t_string_inside_length);
+		}
+	}
+}
 
 //将所有的错误信息,格式化为字符串,用作日志打印。
 //output:p_error_description     错误汇总的字符串指针,不可以为NULL,必须要有实际的内存
@@ -428,13 +464,13 @@ void Error_manager::free_description()
 //重新分配错误描述的内存,并从外部拷贝新的(深拷贝)
 //input:p_error_description     错误描述的字符串指针,可以为NULL,
 //input:description_length      错误描述的字符串长度,如果为0,则从p_error_description里面获取有效的长度
-void Error_manager::reallocate_memory_and_copy_string(char* p_error_description, int description_length)
+void Error_manager::reallocate_memory_and_copy_string(const char* p_error_description, int description_length)
 {
     free_description();
 
     if(p_error_description != NULL)
     {
-        char* pt_source = p_error_description;
+        char* pt_source = (char *)p_error_description;
         char* pt_destination = NULL;
 
         if(description_length == 0)
@@ -446,7 +482,7 @@ void Error_manager::reallocate_memory_and_copy_string(char* p_error_description,
                 pt_source++;
             }
             m_description_length++;
-            pt_source = p_error_description;
+            pt_source = (char *)p_error_description;
         }
         else
         {

+ 32 - 74
error_code/error_code.h

@@ -58,34 +58,40 @@ enum Error_code
     PARAMETER_ERROR                 = 0x00000102,//参数错误,传入参数不符合规范时,
     POINTER_MALLOC_FAIL             = 0x00000103,//手动分配内存失败
 
+    CLASS_BASE_FUNCTION_CANNOT_USE  = 0x00000201,//基类函数不允许使用,必须使用子类的
+
 
 //    错误码的规范,
 //    错误码是int型,32位,十六进制。
 //    例如0x12345678
-//    12表示功能模块,例如:laser雷达模块                框架制定
+//    12表示功能模块,例如:laser雷达模块               框架制定
 //    34表示文件名称,例如:laser_livox.cpp             框架制定
 //    56表示具体的类,例如:class laser_livox           个人制定
 //    78表示类的函数,例如:laser_livox::start();       个人制定
 //    注:错误码的制定从1开始,不要从0开始,
 //        0用作错误码的基数,用来位运算,来判断错误码的范围。
 
-//    laser模块
+//    laser扫描模块
     LASER_ERROR_BASE                = 0x01000000,
 
-//    laser.cpp文件
-
+//    laser_base基类
+	LASER_BASE_ERROR_BASE			= 0x01010000,
     LASER_TASK_PARAMETER_ERROR      = 0x01010001,   //雷达任务输入参数错误
-    LASER_TASK_TYPE_ERROR,
     LASER_CONNECT_FAILED,
-    LASER_LIVOX_SKD_INIT_FAILED,
+	LASER_START_FAILED,
+	LASER_CHECK_FAILED				,
+	LASER_STATUS_ERROR,								//雷达状态错误
 
 
-//    laser_livox.cpp的错误码
+    LASER_LIVOX_SKD_INIT_FAILED,
+
+//    livox子类
     LIVOX_ERROR_BASE                = 0x01020000,
     LIVOX_START_FAILE               = 0x01020101,
+	LIVOX_TASK_TYPE_ERROR,							//livox任务类型错误
 
 
-    //PLC error code  ...
+     //PLC error code  ...
     PLC_ERROR_BASE                  = 0x02010000,
     PLC_UNKNOWN_ERROR,
     PLC_EMPTY_TASK,
@@ -108,6 +114,8 @@ enum Error_code
     LOCATER_Y_OUT_RANGE_BY_PLC,
     LOCATER_MEASURE_HEIGHT_CLOUD_UNINIT,
     LOCATER_MEASURE_HEIGHT_CLOUD_EMPTY,
+    LOCATER_HEIGHT_OUT_RANGE,
+    LOCATER_ANGLE_OUT_RANGE,
     LOCATER_INPUT_CLOUD_UNINIT,
 
 
@@ -136,7 +144,6 @@ enum Error_code
     LOCATER_3DCNN_KMEANS_FAILED,
     LOCATER_3DCNN_IIU_FAILED,
     LOCATER_3DCNN_INPUT_CLOUD_EMPTY,
-    LOCATER_3DCNN_PCA_OUT_CLOUD_EMPTY,
 
     //System_manager error from 0x04010000-0x0401FFFF
     SYSTEM_READ_PARAMETER_ERROR=0x04010100,
@@ -146,64 +153,12 @@ enum Error_code
     //terminor_command_executor.cpp from 0x04010200-0x040102FF
     TERMINOR_NOT_READY=0x04010200,
     TERMINOR_INPUT_LASER_NULL,
-    TERMINOR_NOT_CONTAINS_LASER,
     TERMINOR_INPUT_PLC_NULL,
     TERMINOR_INPUT_LOCATER_NULL,
     TERMINOR_CREATE_WORKING_THREAD_FAILED,
     TERMINOR_FORCE_QUIT,
     TERMINOR_LASER_TIMEOUT,
     TERMINOR_POST_PLC_TIMEOUT,
-    TERMINOR_CHECK_RESULTS_ERROR,
-
-    ////Hardware limit from 0x05010000 - 0x0501ffff
-    ///railing.cpp from 0x05010100-0x050101ff
-    HARDWARE_LIMIT_LEFT_RAILING=0x05010100,         //左栏杆限制
-    HARDWARE_LIMIT_RAILING_PARAMETER_ERROR,
-    HARDWARE_LIMIT_RAILING_ERROR,
-    HARDWARE_LIMIT_CENTER_X_LEFT,
-    HARDWARE_LIMIT_CENTER_X_RIGHT,
-    HARDWARE_LIMIT_CENTER_Y_TOP,
-    HARDWARE_LIMIT_CENTER_Y_BOTTOM,
-    HARDWARE_LIMIT_HEIGHT_OUT_RANGE,
-    HARDWARE_LIMIT_ANGLE_OUT_RANGE,
-    //termonal_limit from 0x05010200-0x050102ff
-    HARDWARE_LIMIT_TERMINAL_LEFT_ERROR,
-    HARDWARE_LIMIT_TERMINAL_RIGHT_ERROR,
-    HARDWARE_LIMIT_TERMINAL_LR_ERROR,
-
-
-    //wj_lidar error from 0x06010000-0x0601FFFF
-        WJ_LIDAR_CONNECT_FAILED=0x06010000,
-    WJ_LIDAR_UNINITIALIZED,
-    WJ_LIDAR_READ_FAILED,
-    WJ_LIDAR_WRITE_FAILED,
-    WJ_LIDAR_GET_CLOUD_TIMEOUT,
-
-    //wj lidar protocol error from 0x06020000-0x0602FFFF
-        WJ_PROTOCOL_ERROR_BASE=0x06020000,
-    WJ_PROTOCOL_INTEGRITY_ERROR,
-    WJ_PROTOCOL_PARSE_FAILED,
-    WJ_PROTOCOL_EMPTY_PACKAGE,
-    WJ_PROTOCOL_EXCEED_MAX_SIZE,
-
-    //wj region detect error from 0x06030000-0x0603FFFF
-        WJ_REGION_EMPTY_CLOUD=0x06030000,
-    WJ_REGION_RECTANGLE_ANGLE_ERROR,
-    WJ_REGION_RECTANGLE_SIZE_ERROR,
-    WJ_REGION_RECTANGLE_SYMMETRY_ERROR,
-    WJ_REGION_CLUSTER_SIZE_ERROR,
-
-    //wj manager error from 0x06040000-0x0604FFFF
-    WJ_MANAGER_UNINITIALIZED=0x06040000,
-    WJ_MANAGER_LIDAR_DISCONNECTED,
-    WJ_MANAGER_PLC_DISCONNECTED,
-    WJ_MANAGER_EMPTY_CLOUD,
-
-    WJ_LIDAR_TASK_EMPTY_RESULT=0x06050000,
-    WJ_LIDAR_TASK_EMPTY_TASK,
-    WJ_LIDAR_TASK_WRONG_TYPE,
-    WJ_LIDAR_TASK_INVALID_TASK,
-    WJ_LIDAR_TASK_MEASURE_FAILED,
 
 
 
@@ -258,7 +213,7 @@ public://外部接口函数
     Error_manager(const Error_manager & error_manager);
     //赋值构造
     Error_manager(Error_code error_code, Error_level error_level = NORMAL,
-                  char* p_error_description = NULL, int description_length = 0);
+                  const char* p_error_description = NULL, int description_length = 0);
     //赋值构造
     Error_manager(Error_code error_code, Error_level error_level , std::string & error_aggregate_string);
     //析构函数
@@ -268,12 +223,12 @@ public://外部接口函数
     void error_manager_init();
     //初始化
     void error_manager_init(Error_code error_code, Error_level error_level = NORMAL,
-                            char* p_error_description = NULL, int description_length = 0);
+                            const char* p_error_description = NULL, int description_length = 0);
     //初始化
     void error_manager_init(Error_code error_code, Error_level error_level , std::string & error_aggregate_string);
     //重置
     void error_manager_reset(Error_code error_code, Error_level error_level = NORMAL,
-                             char* p_error_description = NULL, int description_length = 0);
+                             const char* p_error_description = NULL, int description_length = 0);
     //重置
     void error_manager_reset(Error_code error_code, Error_level error_level , std::string & error_aggregate_string);
     //重置
@@ -305,7 +260,7 @@ public://外部接口函数
     //复制错误描述,(深拷贝)
     //output:p_error_description     错误描述的字符串指针,不可以为NULL,必须要有实际的内存
     //output:description_length      错误描述的字符串长度,不可以为0,长度最好足够大,一般256即可。
-    void copy_error_description(char* p_error_description, int description_length);
+    void copy_error_description(const char* p_error_description, int description_length);
     //复制错误描述,(深拷贝)
     //output:error_description_string     错误描述的string
     void copy_error_description(std::string & error_description_string);
@@ -319,23 +274,26 @@ public://外部接口函数
     //错误等级,设定到固定值
     void set_error_level_location(Error_level error_level);
     //设置错误描述
-    void set_error_description(char* p_error_description, int description_length = 0);
+    void set_error_description(const char* p_error_description, int description_length = 0);
     //设置错误描述
     void set_error_description(std::string & error_description_string);
 
     //尾部追加错误描述
-    void add_error_description(char* p_error_description, int description_length = 0);
+    void add_error_description(const char* p_error_description, int description_length = 0);
     //尾部追加错误描述
     void add_error_description(std::string & error_description_string);
 
     //比较错误是否相同,
     // 注:只比较错误码和等级
-    bool is_equal_error_manager(const Error_manager & error_manager);
-    //比较并覆盖错误,讲低级错误转为字符串存放于描述中,
-    //如果错误相同,则保留this的,将输入参数转入描述。
-    void compare_and_cover_error( Error_manager & error_manager);
-
-    //将所有的错误信息,格式化为字符串,用作日志打印。
+	bool is_equal_error_manager(const Error_manager & error_manager);
+	//比较并覆盖错误,讲低级错误转为字符串存放于描述中,
+	//如果错误相同,则保留this的,将输入参数转入描述。
+	void compare_and_cover_error(const Error_manager & error_manager);
+	//比较并覆盖错误,讲低级错误转为字符串存放于描述中,
+	//如果错误相同,则保留this的,将输入参数转入描述。
+	void compare_and_cover_error( Error_manager * p_error_manager);
+
+	//将所有的错误信息,格式化为字符串,用作日志打印。
     //output:p_error_description     错误汇总的字符串指针,不可以为NULL,必须要有实际的内存
     //output:description_length      错误汇总的字符串长度,不可以为0,长度最好足够大,一般256即可。
     void translate_error_to_string(char* p_error_aggregate, int aggregate_length);
@@ -361,7 +319,7 @@ public:
     //重新分配错误描述的内存,并从外部拷贝新的(深拷贝)
     //input:p_error_description     错误描述的字符串指针,可以为NULL,
     //input:description_length      错误描述的字符串长度,如果为0,则从p_error_description里面获取有效的长度
-    void reallocate_memory_and_copy_string(char* p_error_description, int description_length = 0);
+    void reallocate_memory_and_copy_string(const char* p_error_description, int description_length = 0);
 
     //重新分配错误描述的内存,并从外部拷贝新的(深拷贝)
     //input:error_aggregate_string     错误描述的string

+ 476 - 320
laser/Laser.cpp

@@ -1,409 +1,565 @@
+
+
 #include "Laser.h"
-#include "../tool/MeasureTopicPublisher.h"
 
-CBinaryData::CBinaryData()
-	:m_buf(0)
-	,m_length(0)
+
+Laser_base::Laser_base(int laser_id, Laser_proto::laser_parameter laser_param)
+:m_laser_id(laser_id)
+,m_laser_param(laser_param)
+,m_laser_scan_flag(false)
+,m_laser_statu(LASER_DISCONNECT)
+,m_points_count(0)
+,m_save_flag(false)
 {
+	mp_thread_receive = NULL;
+	mp_thread_transform = NULL;
+	mp_thread_publish = NULL;
+	init_laser_matrix();
+	mp_laser_task = NULL;
 }
-CBinaryData::CBinaryData(const char* buf, int len, DATA_type type)
-    :m_buf(0),m_length(0)
+Laser_base::~Laser_base()
 {
-	if (len > 0)
-	{
-		m_buf = (char*)malloc(len);
-		memcpy(m_buf, buf, len);
-		m_length = len;
-	}
+	
+	disconnect_laser();
+	close_save_path();
 }
-CBinaryData::CBinaryData(const CBinaryData& data)
-    :m_buf(0),m_length(0)
+
+//雷达链接设备,为3个线程添加线程执行函数。
+Error_manager Laser_base::connect_laser()
 {
-	if (m_buf)
+	//检查雷达状态
+	if ( m_laser_statu != LASER_DISCONNECT )
 	{
-		free(m_buf);
-		m_buf = 0;
-		m_length = 0;
+	    return Error_manager(Error_code::LASER_STATUS_ERROR, Error_level::MINOR_ERROR,
+	    					" Laser_base::connect_laser  m_laser_statu != LASER_DISCONNECT ");
 	}
-	if (data.Length() > 0)
+	else
 	{
-		m_buf = (char*)malloc(data.Length());
-		memcpy(m_buf, data.Data(), data.Length());
-		m_length = data.Length();
+		//这里不建议用detach,而是应该在disconnect里面使用join
+		//创建接受缓存的线程,不允许重复创建
+		if (mp_thread_receive != NULL)
+		{
+			return Error_manager(Error_code::LASER_CONNECT_FAILED, Error_level::MINOR_ERROR,
+								 " mp_thread_receive is alive ");
+		}
+		else
+		{
+			//接受缓存的线程,线程存活,暂停运行
+			m_condition_receive.reset(false, false, false);
+			mp_thread_receive = new std::thread(&Laser_base::thread_receive, this);
+		}
+		//转化数据的线程,不允许重复创建
+		if (mp_thread_transform != NULL)
+		{
+			return Error_manager(Error_code::LASER_CONNECT_FAILED, Error_level::MINOR_ERROR,
+								 " mp_thread_transform is alive ");
+		}
+		else
+		{
+			//转化数据的线程,线程存活,暂停运行
+			m_condition_transform.reset(false, false, false);
+			mp_thread_transform = new std::thread(&Laser_base::thread_transform, this);
+		}
+		//发布信息的线程,不允许重复创建
+		if (mp_thread_publish != NULL)
+		{
+			return Error_manager(Error_code::LASER_CONNECT_FAILED, Error_level::MINOR_ERROR,
+								 " mp_thread_publish is alive ");
+		}
+		else
+		{
+			//发布信息的线程,线程存活,循环运行,
+			//注:mp_thread_publish 需要线程持续不断的往上位机发送信息,不受任务的影响。
+			m_condition_publish.reset(false, true, false);
+			mp_thread_publish = new std::thread(&Laser_base::thread_publish, this);
+		}
+
+		m_laser_statu = LASER_READY;
+
 	}
+	return Error_code::SUCCESS;
 }
-CBinaryData::~CBinaryData()
+//雷达断开链接,释放3个线程
+Error_manager Laser_base::disconnect_laser()
 {
-    if (m_buf && m_length)
+	//终止队列,防止 wait_and_pop 阻塞线程。
+	m_queue_laser_data.termination_queue();
+	//杀死3个线程,强制退出
+	if (mp_thread_receive)
 	{
-		free(m_buf);
-		m_length = 0;
+		m_condition_receive.kill_all();
 	}
+	if (mp_thread_transform)
+	{
+		m_condition_transform.kill_all();
+	}
+	if (mp_thread_publish)
+	{
+		m_condition_publish.kill_all();
+	}
+	//回收3个线程的资源
+	if (mp_thread_receive)
+	{
+		mp_thread_receive->join();
+		delete mp_thread_receive;
+		mp_thread_receive = NULL;
+	}
+	if (mp_thread_transform)
+	{
+		mp_thread_transform->join();
+		delete mp_thread_transform;
+		mp_thread_transform = 0;
+	}
+	if (mp_thread_publish)
+	{
+		mp_thread_publish->join();
+		delete mp_thread_publish;
+		mp_thread_publish = NULL;
+	}
+	//清空队列
+	m_queue_laser_data.clear_and_delete();
+
+	if ( m_laser_statu != LASER_FAULT  )
+	{
+		m_laser_statu = LASER_DISCONNECT;
+	}
+	return Error_code::SUCCESS;
 }
-char* CBinaryData::Data()const {
-	return m_buf;
-}
-int CBinaryData::Length()const {
-	return m_length;
-}
-CBinaryData& CBinaryData::operator=(const CBinaryData& data)
+
+
+//对外的接口函数,负责接受并处理任务单,
+//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+Error_manager Laser_base::execute_task(Task_Base* p_laser_task)
 {
-	if (m_buf)
+	//检查指针
+	if(p_laser_task == NULL)
 	{
-		free(m_buf);
-		m_buf = 0;
-		m_length = 0;
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 "Laser_base::execute_task failed, POINTER_IS_NULL");
 	}
-	if (data.Length() > 0)
+	else
 	{
-		m_buf = (char*)malloc(data.Length());
-		memcpy(m_buf, data.Data(), data.Length());
-		m_length = data.Length();
+		return Error_manager(Error_code::CLASS_BASE_FUNCTION_CANNOT_USE, Error_level::NEGLIGIBLE_ERROR,
+							 "Laser_base::execute_task cannot use");
 	}
-	return *this;
 }
-bool CBinaryData::operator==(const char* str)
+//检查雷达状态,是否正常运行
+Error_manager Laser_base::check_laser()
 {
-	int length = strlen(str);
-	return  (strncmp((const char*)m_buf, str, length) == 0);
+	if ( is_ready() )
+	{
+		return Error_code::SUCCESS;
+	}
+	return Error_manager(Error_code::LASER_CHECK_FAILED, Error_level::MINOR_ERROR,
+						" check_laser failed ");
 }
-const char* CBinaryData::operator+(int n)
+//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+Error_manager Laser_base::start_scan()
 {
-	if (n < m_length)
-		return m_buf + n;
+	LOG(INFO) << " Laser_base::start_scan "<< this;
+	if ( is_ready() )
+	{
+		//启动雷达扫描
+		m_laser_scan_flag=true;				//启动雷达扫描
+		m_laser_statu = LASER_BUSY;			//雷达状态 繁忙
+		m_condition_receive.notify_all(true);		//唤醒接受线程
+		m_condition_transform.notify_all(true);	//唤醒转化线程
+		//重置数据
+		m_points_count=0;
+		m_queue_laser_data.clear_and_delete();
+		m_last_data.clear();
+		return Error_code::SUCCESS;
+	}
 	else
-		return NULL;
-}
-CBinaryData& CBinaryData::operator+(CBinaryData& data)
-{
-	if (data.Length() > 0)
 	{
-		int length = m_length + data.Length();
-		char* buf = (char*)malloc(length);
-		memcpy(buf, m_buf, m_length);
-		memcpy(buf + m_length, data.Data(), data.Length());
-		free(m_buf);
-		m_buf = buf;
-		m_length = length;
+		return Error_manager(Error_code::LASER_START_FAILED, Error_level::MINOR_ERROR,
+							 "Laser_base::start_scan() is not ready ");
 	}
-	return *this;
 }
-char& CBinaryData::operator[](int n)
+//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+Error_manager Laser_base::stop_scan()
 {
-	if (n >= 0 && n < m_length)
-		return m_buf[n];
+	LOG(INFO) << " Laser_base::stop_scan "<< this;
+	//stop_scan 只是将 m_laser_scan_flag 改为 stop。
+	//然后多线程内部判断 m_laser_scan_flag,然后自动停止线程
+	m_laser_scan_flag=false;
+	return Error_code::SUCCESS;
 }
-//////////////
-
-Laser_base::Laser_base(int id, Laser_proto::laser_parameter laser_param)
-	:m_ThreadRcv(0)
-	,m_ThreadPro(0)
-	,m_ThreadPub(0)
-	,m_id(id)
-    ,m_points_count(0)
-	,m_statu(eLaser_disconnect)
-	,m_dMatrix(0)
-	, m_point_callback_fnc(0)
-	, m_point_callback_pointer(0)
-	,m_laser_param(laser_param)
-	,m_bscan_start(false)
+
+//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+Error_manager Laser_base::end_task()
 {
-    mp_laser_task = NULL;
-}
+	LOG(INFO) << " Laser_base::end_task "<< this;
+	m_laser_scan_flag=false;
+	m_condition_receive.notify_all(false);
+	m_condition_transform.notify_all(false);
+	m_points_count=0;
+	m_queue_laser_data.clear_and_delete();
+	m_last_data.clear();
 
+	close_save_path();
 
-Laser_base::~Laser_base()
-{
-	if (m_dMatrix)
+	//在结束任务单时,将雷达任务状态改为 TASK_OVER 已结束
+	if(mp_laser_task !=NULL)
 	{
-		free(m_dMatrix);
-		m_dMatrix = 0;
+		//判断任务单的错误等级,
+		if ( mp_laser_task->get_task_error_manager().get_error_level() > Error_level::MINOR_ERROR)
+		{
+			if ( m_laser_statu == LASER_BUSY )
+			{
+				//故障等级为 NORMAL NEGLIGIBLE_ERROR MINOR_ERROR,则恢复待机,可以接受下一次的任务单
+				m_laser_statu = LASER_READY;
+			}
+
+		}
+		else
+		{
+			//故障等级为 MAJOR_ERROR CRITICAL_ERROR,则雷达故障,不可以再接受任务单。
+			m_laser_statu = LASER_FAULT;
+		}
+		//强制改为TASK_OVER,不管它当前在做什么。
+		mp_laser_task->set_task_statu(TASK_OVER);
 	}
+	return Error_code::SUCCESS;
 }
 
-Error_manager Laser_base::check_error()
-{
-    return SUCCESS;
-}
 
-bool Laser_base::Start()
+
+//设置保存文件的路径,并打开文件,
+Error_manager Laser_base::set_open_save_path(std::string save_path,bool is_save)
 {
+	m_save_flag = is_save;
+	m_points_log_tool.close();
+	m_binary_log_tool.close();
 
-    m_bscan_start=true;
-	m_statu = eLaser_busy;
-	m_bStart_capture.Notify(true);
-    m_points_count=0;
-	return true;
+	if (is_save == false)
+	{
+		return Error_code::SUCCESS;
+	}
+	else
+	{
+		m_save_path = save_path;
+		char pts_file[255] = { 0 };
+		sprintf(pts_file, "%s/pts%d.txt", save_path.c_str(), m_laser_id+1);
+		m_points_log_tool.open(pts_file);
+		std::cout << "huli m_points_log_tool path "<< pts_file << std::endl;
+
+		char bin_file[255] = { 0 };
+		sprintf(bin_file, "%s/laser%d.data", save_path.c_str(), m_laser_id+1);
+		m_binary_log_tool.open(bin_file,true);
+		std::cout << "huli m_binary_log_tool path "<< bin_file << std::endl;
+
+		return Error_code::SUCCESS;
+	}
 }
-
-bool Laser_base::Stop()
+//关闭保存文件,推出前一定要执行
+Error_manager Laser_base::close_save_path()
 {
-    m_bscan_start=false;
-	m_bStart_capture.Notify(false);
+	m_save_flag = false;
+	m_points_log_tool.close();
 	m_binary_log_tool.close();
-	m_pts_log_tool.close();
-	m_statu=eLaser_ready;
-
-	//在停止雷达时,将雷达任务状态改为 TASK_OVER 已结束
-	if(mp_laser_task !=NULL)
-    {
-        mp_laser_task->set_task_statu(TASK_OVER);
-	    /*if(mp_laser_task->get_statu() == TASK_WORKING)
-        {
-
-        }*/
-    }
-
-	return true;
+	return Error_code::SUCCESS;
 }
 
-void Laser_base::SetMetrix(double* data)
+//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+bool Laser_base::is_ready()
 {
-	if (m_dMatrix == 0)
-	{
-		m_dMatrix = (double*)malloc(12 * sizeof(double));
-	}
-	memcpy(m_dMatrix, data, 12 * sizeof(double));
+	return ( get_laser_statu() == LASER_READY );
 }
-void Laser_base::SetPointCallBack(PointCallBack fnc, void* pointer)
+//获取雷达状态
+Laser_statu Laser_base::get_laser_statu()
 {
-	m_point_callback_fnc = fnc;
-	m_point_callback_pointer = pointer;
+	return m_laser_statu;
 }
-
-bool Laser_base::Connect()
+//获取雷达id
+int Laser_base::get_laser_id()
 {
-	m_bThreadRcvRun.Notify(true);
-	if(m_ThreadRcv==0)
-		m_ThreadRcv = new std::thread(&Laser_base::thread_recv, this);
-	m_ThreadRcv->detach();
-
-	m_bThreadProRun.Notify(true);
-	if(m_ThreadPro==0)
-		m_ThreadPro = new std::thread(&Laser_base::thread_toXYZ, this);
-	m_ThreadPro->detach();
-
-    if(m_ThreadPub==0)
-        m_ThreadPub = new std::thread(threadPublish, this);
-    m_ThreadPub->detach();
-
-	return true;
+	return m_laser_id;
 }
-void Laser_base::Disconnect()
+
+//线程执行函数,将二进制消息存入队列缓存,
+void Laser_base::thread_receive()
 {
-	if (m_ThreadRcv)
+	LOG(INFO) << " thread_receive start "<< this;
+	//接受雷达消息,每次循环只接受一个 Binary_buf
+	while (m_condition_receive.is_alive())
 	{
-		delete m_ThreadRcv;
-		m_ThreadRcv = 0;
+		m_condition_receive.wait();
+		if ( m_condition_receive.is_alive() )
+		{
+			//tp_binaty_buf的内存 需要手动分配,然后存入链表。
+			//m_queue_laser_data的内存由 Laser_base 基类管理。
+			Binary_buf* tp_binaty_buf = new Binary_buf();
+			//获取雷达的通信消息缓存
+			if (this->receive_buf_to_queue(*tp_binaty_buf))
+			{
+				//将缓存 存入队列。
+				//thread_receive存入前要手动分配内存,thread_transform取出后要记得释放。
+				m_queue_laser_data.push(tp_binaty_buf);
+				std::cout << "huli thread_receive " << m_queue_laser_data.size() << std::endl;
+			}
+			else
+			{
+				delete tp_binaty_buf;
+				tp_binaty_buf=NULL;
+
+				//接受线程无法接受到数据的同时,也收到了雷达停止扫描的信息,那么线程停止
+				//如果m_laser_scan_flag停止扫描,但是receive_buf_to_queue仍然能够接受到数据。那么线程继续运行。
+				//m_laser_scan_flag停止的瞬间,可能还有残留的数据,需要继续执行。
+				if ( !m_laser_scan_flag )
+				{
+					//停止线程,m_condition_receive.wait() 函数将会阻塞。
+					m_condition_receive.set_pass_ever(false);
+				}
+			}			
+		}
 	}
+	LOG(INFO) << " thread_receive end :"<<this;
+	return;
+}
 
-    if (m_ThreadPub)
-    {
-        delete m_ThreadPub;
-        m_ThreadPub = 0;
-    }
 
-	if (m_ThreadPro)
+//线程执行函数,转化并处理三维点云。
+void Laser_base::thread_transform()
+{
+	LOG(INFO) << " thread_transform start "<< this;
+	//转化雷达数据,每次循环只转化一个 Binary_buf,然后得到 t_point3D_cloud.size() 个三维点,
+	while (m_condition_transform.is_alive())
 	{
-		delete m_ThreadPro;
-		m_ThreadPro = NULL;
+		m_condition_transform.wait();
+		if ( m_condition_transform.is_alive() )
+		{
+			//tp_binaty_buf的内存 从链表取出时,就自带内存了。需要手动释放。
+			//m_queue_laser_data的内存由 Laser_base 基类管理。
+			Binary_buf* tp_binaty_buf=NULL;
+			//第1步,从队列中取出缓存。
+			int huli_test = m_queue_laser_data.size();
+			//thread_receive存入前要手动分配内存,thread_transform取出后要记得释放。
+			bool t_pop_flag = m_queue_laser_data.try_pop(tp_binaty_buf);
+			if ( t_pop_flag )
+			{
+			    std::cout << "huli m_queue_laser_data.size() last = " << huli_test << std::endl;
+				std::cout << "huli m_queue_laser_data.size() now = " << m_queue_laser_data.size() << std::endl;
+
+			}
+
+			//第2步,处理数据,缓存转化缓存为三维点。
+			//如果获取到了 Binary_buf,或者上次有未完成的 m_last_data,那么就执行数据转化。
+			//注注注注注意了,扫描停止后,m_last_data一定要保证清空,不能有垃圾数据残留,这会阻塞线程的暂停
+			if (t_pop_flag || m_last_data.get_length() > 0)
+			{
+				std::cout << "huli thread_transform " << m_queue_laser_data.size() << std::endl;
+				std::cout << "huli t_pop_flag = "<< t_pop_flag << std::endl;
+				//缓存类型
+				Buf_type t_buf_type = BUF_UNKNOW;
+				//雷达扫描结果,三维点云(雷达自身坐标系)
+				std::vector<CPoint3D> t_point3D_cloud;
+				//第2.1步,缓存转化为三维点。
+				if (t_pop_flag)
+				{
+					if (tp_binaty_buf == NULL)
+					{
+						//try_pop返回true,但是tp_binaty_buf没有数据,直接跳过。这个一般不可能出现。
+						continue;
+					}
+					else
+					{
+						//保存雷达通信 二进制的源文件。
+						if(m_save_flag)
+						{
+							m_binary_log_tool.write(tp_binaty_buf->get_buf(), tp_binaty_buf->get_length());
+						}
+						//缓存转化为三维点。传入新的缓存,
+						t_buf_type= this->transform_buf_to_points(tp_binaty_buf, t_point3D_cloud);
+					}					
+				}
+				else if(m_last_data.get_length() > 0)
+				{
+					//缓存转化为三维点。没有新消息,就传null,这将处理 m_last_data 上一次遗留的缓存。
+					t_buf_type = this->transform_buf_to_points(NULL, t_point3D_cloud);
+				}
+
+				//第2.2步,判断t_buf_type,处理雷达数据。并存入任务单
+				if (t_buf_type == BUF_UNKNOW || t_buf_type == BUF_READY)
+				{
+					//跳过这次循环。
+					continue;
+				}
+				else if (t_buf_type == BUF_DATA || t_buf_type == BUF_START || t_buf_type == BUF_STOP)
+				{
+					//循环处理雷达数据
+					for (int i = 0; i < t_point3D_cloud.size(); ++i)
+					{
+						//三维点的坐标变换,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
+						CPoint3D t_point = transform_by_matrix(t_point3D_cloud[i]);
+						//保存雷达扫描 三维点云的最终结果。
+						if(m_save_flag) {
+							char buf[64] = {0};
+							sprintf(buf, "%f %f %f\n", t_point.x, t_point.y, t_point.z);
+							m_points_log_tool.write(buf, strlen(buf));
+//							std::cout << "huli m_points_log_tool.write" << std::endl;
+						}
+
+						//此时 t_point 为雷达采集数据的结果,转换后的三维点云。
+						//将每个点存入任务单里面的点云容器。
+						if(mp_laser_task!=NULL)
+						{
+							Error_manager t_error= mp_laser_task->task_push_point(pcl::PointXYZ(t_point.x,t_point.y,t_point.z));
+							if ( t_error != Error_code::SUCCESS )
+							{
+								mp_laser_task->get_task_error_manager().compare_and_cover_error(t_error);
+								stop_scan();
+							}
+						}
+					}
+					//统计扫描点个数。
+					m_points_count += t_point3D_cloud.size();
+					//思科雷达停止扫描。
+					if (t_buf_type == BUF_STOP)
+					{
+						//注:这个只是思科的雷达停止处,不同的雷达在不同的地方调用 stop_scan
+						stop_scan();
+					}
+				}
+			}
+			else
+			{
+				//转化线程 不需要数据的同时,也收到了雷达停止扫描的信息并且接受线程已经停止,那么停止转化线程,
+				//注:必须先停止接受线程,再停止转化线程。转化线程停止之后即可结束任务。
+				//如果m_laser_scan_flag停止扫描,接受线程和转化线程还有未完成的数据。那么线程继续运行。
+				//m_laser_scan_flag停止的瞬间,可能还有残留的数据,需要继续执行。防止数据遗留。
+				if ( !m_laser_scan_flag && m_condition_receive.get_pass_ever() == false)
+				{
+					//停止线程,m_condition_transform.wait() 函数将会阻塞。
+					m_condition_transform.set_pass_ever(false);
+
+					//mp_thread_transform 停止时,雷达扫描任务彻底完成,此时结束任务
+					end_task();
+				}
+			}
+
+			//第3步,手动释放缓存
+			if ( tp_binaty_buf != NULL )
+			{
+				delete tp_binaty_buf;
+			}
+		}
 	}
-	m_statu = eLaser_disconnect;
+	LOG(INFO) << " thread_transform end "<< this;
+	return;
 }
 
 
-//对外的接口函数,负责接受并处理任务单,
-//input:laser_task 雷达任务单,必须是子类,并且任务正确。(传引用)
-Error_manager Laser_base::execute_task(Task_Base* p_laser_task)
+//公开发布雷达信息的功能函数,
+Error_manager Laser_base::publish_laser_to_message()
 {
-    return SUCCESS;
+	return Error_code::SUCCESS;
+	/*
+	globalmsg::msg msg;
+	msg.set_msg_type(globalmsg::eLaser);
+
+	globalmsg::laserStatus status;
+	if(GetStatu()==eLaser_ready) status=globalmsg::eLaserConnected;
+	else if(GetStatu()==eLaser_disconnect) status=globalmsg::eLaserDisconnected;
+	else if(GetStatu()==eLaser_busy) status=globalmsg::eLaserBusy;
+	else  status=globalmsg::eLaserUnknown;
+
+	msg.mutable_laser_msg()->set_id(m_laser_id);
+	msg.mutable_laser_msg()->set_laser_status(status);
+	msg.mutable_laser_msg()->set_queue_data_count(m_queue_laser_data.size());
+	msg.mutable_laser_msg()->set_cloud_count(m_points_count);
+	MeasureTopicPublisher::GetInstance()->Publish(msg.SerializeAsString());
+	 */
 }
-
-
-void Laser_base::SetSaveDir(std::string strDir,bool bSaveFile)
+//线程执行函数,公开发布雷达的相关信息,用作上位机的监视。
+void Laser_base::thread_publish(Laser_base *p_laser)
 {
-    if(m_laser_param.is_save_txt()) {
-        m_pts_log_tool.close();
-    }
-    if(m_laser_param.is_save_banary()) {
-        m_binary_log_tool.close();
-    }
-
-    if(m_laser_param.is_save_txt())
-    {
-        m_pts_save_path = strDir;
-        char pts_file[255] = {0};
-        sprintf(pts_file, "%s/pts%d.txt", strDir.c_str(), m_id + 1);
-        m_pts_log_tool.open(pts_file);
-    }
-    if(m_laser_param.is_save_banary()) {
-        char bin_file[255] = {0};
-        sprintf(bin_file, "%s/laser%d.data", strDir.c_str(), m_id + 1);
-        m_binary_log_tool.open(bin_file, true);
-    }
-}
+	LOG(INFO) << " thread_publish start ";
+	if(p_laser==NULL)
+	{
+		return;
+	}
 
-void Laser_base::thread_recv()
-{
-	while (m_bThreadRcvRun.WaitFor(1))
+	while (p_laser->m_condition_publish.is_alive())
 	{
-		if (m_bStart_capture.WaitFor(1) == false)
-			continue;
-		CBinaryData* data=new CBinaryData();
-		if (this->RecvData(*data))
-		{
-			m_queue_laser_data.push(data);
-		}
-		else
+		p_laser->m_condition_publish.wait();
+		if ( p_laser->m_condition_publish.is_alive() )
 		{
-			delete data;
-            data=0;
+			p_laser->publish_laser_to_message();
+			//每隔300ms,发送一次雷达信息状态。
+			std::this_thread::sleep_for(std::chrono::milliseconds(300));
 		}
-		
 	}
+
+	LOG(INFO) << " thread_publish end ";
+	return;
 }
 
-CPoint3D Laser_base::transfor(CPoint3D point)
+
+
+//初始化变换矩阵,设置默认值
+Error_manager Laser_base::init_laser_matrix()
 {
-	if (m_dMatrix)
+	if ( LASER_MATRIX_ARRAY_SIZE == 12 )
 	{
-		CPoint3D result;
-		double x = point.x;
-		double y = point.y;
-		double z = point.z;
-		result.x = x * m_dMatrix[0] + y*m_dMatrix[1] + z*m_dMatrix[2] + m_dMatrix[3];
-		result.y = x * m_dMatrix[4] + y*m_dMatrix[5] + z*m_dMatrix[6] + m_dMatrix[7];
-		result.z = x * m_dMatrix[8] + y*m_dMatrix[9] + z*m_dMatrix[10] + m_dMatrix[11];
-		return result;
+		//详见转化的算法transfor。保证转化前后坐标一致。
+		mp_laser_matrix[0] = 1;
+		mp_laser_matrix[1] = 0;
+		mp_laser_matrix[2] = 0;
+		mp_laser_matrix[3] = 0;
+		mp_laser_matrix[4] = 0;
+		mp_laser_matrix[5] = 1;
+		mp_laser_matrix[6] = 0;
+		mp_laser_matrix[7] = 0;
+		mp_laser_matrix[8] = 0;
+		mp_laser_matrix[9] = 0;
+		mp_laser_matrix[10] = 1;
+		mp_laser_matrix[11] = 0;
 	}
 	else
 	{
-		return point;
+		for (int i = 0; i < LASER_MATRIX_ARRAY_SIZE; ++i)
+		{
+			//设为0之后,变换之后,新的点坐标全部为0
+			mp_laser_matrix[i] = 0;
+		}
 	}
+	return Error_code::SUCCESS;
 }
-
-void Laser_base::thread_toXYZ()
+//设置变换矩阵,用作三维点的坐标变换,
+Error_manager Laser_base::set_laser_matrix(double* p_matrix, int size)
 {
-	while (m_bThreadProRun.WaitFor(1))
+	if ( p_matrix == NULL )
 	{
-		if (m_bStart_capture.WaitFor(1) == false)
-		{
-			m_queue_laser_data.clear();
-			continue;
-		}
-        CBinaryData* pData=NULL;
-        bool bPop = m_queue_laser_data.try_pop(pData);
-        DATA_type type = eUnknow;
-        if (bPop || m_last_data.Length() != 0)
-        {
-            std::vector<CPoint3D> cloud;
-            if (bPop)
-            {
-                if (pData == NULL)
-                    continue;
-                if(m_laser_param.is_save_banary())
-                {
-                    m_binary_log_tool.write(pData->Data(), pData->Length());
-                }
-                type= this->Data2PointXYZ(pData, cloud);
-            }
-            else
-            {
-                type = this->Data2PointXYZ(NULL, cloud);
-            }
-            if (type == eUnknow)
-            {
-                delete pData;
-                continue;
-            }
-
-            if (type == eData || type == eStart || type == eStop)
-            {
-                for (int i = 0; i < cloud.size(); ++i)
-                {
-                    CPoint3D point = transfor(cloud[i]);
-                    if(m_laser_param.is_save_txt()) {
-                        char buf[64] = {0};
-                        sprintf(buf, "%f %f %f\n", point.x, point.y, point.z);
-                        m_pts_log_tool.write(buf, strlen(buf));
-                    }
-
-                    //此时cloud为雷达采集数据的结果,转换后的三维点云。
-                    //将每个点存入任务单里面的点云容器。
-
-                    if(mp_laser_task!=NULL)
-                    {
-                        Error_manager code=mp_laser_task->push_point(pcl::PointXYZ(point.x,point.y,point.z));
-
-                    }
-                }
-                m_points_count+=cloud.size();
-                if (type == eStop)
-                {
-                    if(m_laser_param.is_save_txt()) {
-                        m_pts_log_tool.close();
-                    }
-                    if(m_laser_param.is_save_banary()) {
-                        m_binary_log_tool.close();
-                    }
-                    m_statu = eLaser_ready;
-
-                    //在停止雷达时,将雷达任务状态改为 TASK_OVER 已结束
-                    if(mp_laser_task !=NULL)
-                    {
-                        if(mp_laser_task->get_statu() == TASK_WORKING)
-                        {
-                            mp_laser_task->set_task_statu(TASK_OVER);
-                        }
-                    }
-                }
-
-            }
-            else if (type == eReady)
-            {
-                if(m_laser_param.is_save_txt()) {
-                    m_pts_log_tool.close();
-                }
-                if(m_laser_param.is_save_banary()) {
-                    m_binary_log_tool.close();
-                }
-                m_statu = eLaser_ready;
-            }
-
-
-            delete pData;
-        }
-		
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 " set_laser_matrix p_matrix IS_NULL ");
+	}
+	else if ( size != LASER_MATRIX_ARRAY_SIZE )
+	{
+	    return Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR,
+	    					" set_laser_matrix  size is not Match");
+	}
+	else
+	{
+		memcpy(mp_laser_matrix, p_matrix, LASER_MATRIX_ARRAY_SIZE * sizeof(double));
+		return Error_code::SUCCESS;
 	}
 }
-
-
-#include "unistd.h"
-void Laser_base::threadPublish(Laser_base *laser)
+//三维点的坐标变换的功能函数,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
+CPoint3D Laser_base::transform_by_matrix(CPoint3D point)
 {
-    if(laser==0) return ;
-    while(laser->m_bThreadRcvRun.WaitFor(1))
-    {
-        laser->PublishMsg();
-        usleep(1000*300);
-    }
+	CPoint3D result;
+	double x = point.x;
+	double y = point.y;
+	double z = point.z;
+	result.x = x * mp_laser_matrix[0] + y*mp_laser_matrix[1] + z*mp_laser_matrix[2] + mp_laser_matrix[3];
+	result.y = x * mp_laser_matrix[4] + y*mp_laser_matrix[5] + z*mp_laser_matrix[6] + mp_laser_matrix[7];
+	result.z = x * mp_laser_matrix[8] + y*mp_laser_matrix[9] + z*mp_laser_matrix[10] + mp_laser_matrix[11];
+	return result;
 }
 
 
-void Laser_base::PublishMsg()
-{
-    laser_message::laserMsg msg;
-
-    laser_message::laserStatus status;
-    if(GetStatu()==eLaser_ready) status=laser_message::eLaserConnected;
-    else if(GetStatu()==eLaser_disconnect) status=laser_message::eLaserDisconnected;
-    else if(GetStatu()==eLaser_busy) status=laser_message::eLaserBusy;
-    else  status=laser_message::eLaserUnknown;
 
-    msg.set_id(m_id);
-    msg.set_laser_status(status);
-    msg.set_queue_data_count(m_queue_laser_data.size());
-    msg.set_cloud_count(m_points_count);
-    MeasureTopicPublisher::GetInstance()->Publish(msg.SerializeAsString());
 
-}

+ 135 - 121
laser/Laser.h

@@ -1,154 +1,168 @@
+
+/*
+ * laser雷达核心模块,主要是负责管理所有的雷达设备,按需采集三维点。
+ * 由上层下发任务单,雷达模块按照任务指示,进行相应的雷达扫描。
+ * 转换和拼接为标准参考系的三维坐标点云。
+ * 然后通过任务单返回上层。
+ */
+
 #ifndef __LASER__HH__
 #define __LASER__HH__
 #include "Point2D.h"
 #include "Point3D.h"
 #include "LogFiles.h"
+
 #include <glog/logging.h>
-#include "../tool/StdCondition.h"
+
 #include "laser_parameter.pb.h"
-#include "laser_message.pb.h"
-#include "../error_code/error_code.h"
 #include "laser_task_command.h"
-#include "../tool/threadSafeQueue.h"
-
-
-//雷达消息的类型
-//在通信消息的前面一部分字符串,表示这条消息的类型。
-//在解析消息的时候,先解析前面的消息类型,来判断这条消息的功用
-enum DATA_type
-{
-	eStart          =0,
-	eReady          =1,
-	eData           =2,
-	eStop           =3,
-	eHerror         =4,
-	eUnknow         =5,
-};
-
-//通信消息的二进制数据,
-//这里用字符串,来存储雷达的通信消息的原始数据
-//CBinaryData的内容格式:消息类型 + 消息数据
-class CBinaryData
-{
-public:
-	CBinaryData();
-	CBinaryData(const CBinaryData& data);
-	~CBinaryData();
-	CBinaryData(const char* buf, int len, DATA_type type= eUnknow);
-    CBinaryData& operator=(const CBinaryData& data);
-	bool operator==(const char* str);
-	const char* operator+(int n);
-	CBinaryData& operator+(CBinaryData& data);
-	char& operator[](int n);
-	char*		Data()const;
-	int			Length()const;
 
-protected:
-	char*			m_buf;
-	int				m_length;
-};
+#include "../error_code/error_code.h"
+#include "../tool/binary_buf.h"
+#include "../tool/thread_safe_queue.h"
+#include "../tool/thread_condition.h"
 
 
 
-///////////////////////////////////////////////
 
-//雷达的工作状态,
-//在start和stop中要切换状态
-enum eLaserStatu
+//雷达工作状态,基类三线程的状态
+//connect_laser 和  disconnect_laser  	中要切换状态 LASER_DISCONNECT <===> LASER_READY
+//start_scan 和 stop_scan 和 end_task	中要切换状态 LASER_READY <===> LASER_BUSY
+enum Laser_statu
 {
-    eLaser_ready        =0,	        //雷达正常待机,空闲
-    eLaser_busy         =1,			//雷达正在工作,正忙
-    eLaser_disconnect   =2,	        //雷达断连
-    eLaser_error        =3,         //雷达错误
+	//默认值 LASER_DISCONNECT	=0
+	LASER_DISCONNECT	=0,	        //雷达断连
+	LASER_READY			=1,			//雷达正常待机,空闲
+	LASER_BUSY			=2,	        //雷达正在工作,正忙
+	LASER_FAULT			=3,         //雷达错误
 };
 
-//回调函数,当有事件触发是,便会自动调用回调函数,
-//typedef从定义,将其简化为PointCallBack,方便后面多次使用
-typedef void (*PointCallBack)(CPoint3D ,  void* );
+//雷达变换矩阵的数组长度,默认为12个参数, size = 3 * ( 3 + 1 ) ,旋转加平移,没有缩放
+#define LASER_MATRIX_ARRAY_SIZE 12
 
 //雷达的基类,不能直接使用,必须子类继承
 class Laser_base
 {
 public:
-    //唯一的构造函数,按照设备名称和雷达参数来创建实例。
-    //input:id: 雷达设备的id,(唯一索引)
-    //input:laser_param:雷达的参数,
-    //注:利用protobuf创建stLaserCalibParam类,然后从文件读取参数
-	Laser_base(int id,Laser_proto::laser_parameter laser_param);
-	virtual ~Laser_base();
-	///��������Դ
-	virtual bool Connect();
-	virtual void Disconnect();
-
+	Laser_base() = delete;
+	Laser_base(const Laser_base& other) = delete;
+	//唯一的构造函数,按照设备名称和雷达参数来创建实例。
+	//input:id: 雷达设备的id,(唯一索引)
+	//input:laser_param:雷达的参数,
+	//注:利用protobuf创建 laser_parameter 类,然后从文件读取参数
+	Laser_base(int laser_id,Laser_proto::laser_parameter laser_param);
+	//析构函数
+	~Laser_base();
+
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
 	//对外的接口函数,负责接受并处理任务单,
-	//input:p_laser_task 雷达任务单,必须是子类,并且任务正确。
-    virtual Error_manager execute_task(Task_Base* p_laser_task);
-    //检查雷达状态,是否正常运行
-    Error_manager check_error();
-
-	///��ʼ��ֹͣ�ɼ�
-	virtual bool Start();
-	virtual bool Stop();
-	///���õ��Ʊ任���󣨱궨������
-	void SetMetrix(double* data);
-	///���û�ȡ��ά��ص�����
-	void SetPointCallBack(PointCallBack fnc,void* pointer);
+	//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+	//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
 
 public:
-	///�������ݴ洢·��
-	void			SetSaveDir(std::string strDir,bool bSave=true);
-	///��ѯ�״��Ƿ����
-    bool			IsReady() { return (GetStatu() == eLaser_ready && m_queue_laser_data.size()==0); }
+	//设置保存文件的路径,并打开文件,
+	Error_manager set_open_save_path(std::string save_path,bool is_save=true);
+	//关闭保存文件,推出前一定要执行
+	Error_manager close_save_path();
+	//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+	virtual bool is_ready();
+
+	//获取雷达id
+	int get_laser_id();
+
 
-    virtual eLaserStatu     GetStatu(){return m_statu;}
-	int				ID() { return m_id; }
 protected:
-	////��ȡԭʼ���ݰ�
-	virtual bool RecvData(CBinaryData& data) = 0;
-	////����ԭʼ���ݰ��ɵ���
-	virtual DATA_type Data2PointXYZ(CBinaryData* pData, std::vector<CPoint3D>& points)=0;
-	void thread_recv();
-	void thread_toXYZ();
-	////���Ʊ任
-	virtual CPoint3D transfor(CPoint3D point);
+	//接受二进制消息的功能函数,每次只接受一个CBinaryData
+	// 纯虚函数,必须由子类重载,
+	virtual bool receive_buf_to_queue(Binary_buf& binary_buf) = 0;
+	//线程执行函数,将二进制消息存入队列缓存,
+	void thread_receive();
+
+	//将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
+	// 纯虚函数,必须由子类重载,
+	virtual Buf_type transform_buf_to_points(Binary_buf* p_binary_buf, std::vector<CPoint3D>& point3D_cloud)=0;
+	//线程执行函数,转化并处理三维点云。
+	void thread_transform();
+
+	//公开发布雷达信息的功能函数,
+	Error_manager publish_laser_to_message();
+	//线程执行函数,公开发布雷达的相关信息,用作上位机的监视。
+	static void thread_publish(Laser_base* p_laser);
+
+	//获取雷达状态
+	Laser_statu get_laser_statu();
 protected:
-    static void threadPublish(Laser_base* laser);
-    void PublishMsg();
+	//初始化变换矩阵,设置默认值
+	Error_manager init_laser_matrix();
+	//设置变换矩阵,用作三维点的坐标变换,
+	Error_manager set_laser_matrix(double* p_matrix, int size);
+
+	//三维点的坐标变换的功能函数,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
+	virtual CPoint3D transform_by_matrix(CPoint3D point);
+
+
 protected:
-	std::thread*		m_ThreadRcv;
-	std::thread*		m_ThreadPro;
-	std::thread*        m_ThreadPub;
-	StdCondition		m_bThreadRcvRun;
-	StdCondition		m_bThreadProRun;
-	int					m_id;
-	int                 m_points_count;
-
-	std::mutex          m_scan_lock;
-
-	bool                m_bscan_start;
-	eLaserStatu			m_statu;
-    Laser_proto::laser_parameter  m_laser_param;////����
-
-    //���ݴ������
-	threadsafe_queue<CBinaryData*>		m_queue_laser_data;     // ���ݶ���
-	CBinaryData							m_last_data;			//��һ��������δ�������		
-	double*								m_dMatrix;              
-	PointCallBack						m_point_callback_fnc;
-	void*								m_point_callback_pointer;
-
-
-    //���ݴ洢
-	CLogFile		m_binary_log_tool;										//�洢������
-	CLogFile		m_pts_log_tool;										//�洢����
-	std::string		m_pts_save_path;
-	StdCondition	m_bStart_capture;
-
-    //任务单的指针,实际内存由应用层管理,
-    //接受任务后,指向新的任务单
-    Laser_task *  mp_laser_task;
+	//为了保证多线程的数据安全,修改共享数据必须加锁。  atomic 和 安全队列 可以不加锁进行读写
+	//建议:判断标志位使用 atomic, 容器要封装并使用 安全容器,
+	std::mutex          				m_laser_lock;            	//雷达数据锁
+
+	std::atomic<int>					m_laser_id;                 //雷达设备id
+	Laser_proto::laser_parameter  		m_laser_param;				//雷达的配置参数
+	//雷达变换矩阵,三维点的坐标变换的矩阵,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
+	//必须在set_laser_matrix之后,才能使用。(connect时,从雷达的配置参数导入)
+	double								mp_laser_matrix[LASER_MATRIX_ARRAY_SIZE];	//雷达变换矩阵
+	//雷达扫描事件的标志位,受start和stop控制,然后其他线程判断m_scan_flag标准位,来进行启停。
+	std::atomic<bool>                	m_laser_scan_flag;          //雷达扫描的使能标志位
+	//雷达状态和任务状态同步,m_scan_flag停止之后,还要等任务执行完成,才会切回 ready。
+	std::atomic<Laser_statu>			m_laser_statu;             	//雷达工作状态,基类三线程的状态
+	//注:m_laser_statu是基类的三线程的状态,和livox sdk后台线程状态没有任何关系。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+
+	std::atomic<int>            		m_points_count;         	//雷达采集点的计数
+	Thread_safe_queue<Binary_buf*>		m_queue_laser_data;         //二进制缓存的队列容器
+	Binary_buf							m_last_data;			    //上一个二进制缓存,用作数据拼接
+
+
+	std::atomic<bool> 					m_save_flag;           		//雷达保存文件的使能标志位
+	std::string							m_save_path;            	//雷达保存文件的保存路径
+	CLogFile							m_binary_log_tool;          //二进制缓存的日志工具
+	CLogFile							m_points_log_tool;          //三维点云的日志工具
+
+
+	//线程指针的内存管理,由Connect和Disconnect进行分配和释放。
+	std::thread*						mp_thread_receive;    		//接受缓存的线程指针
+	Thread_condition					m_condition_receive;		//接受缓存的条件变量
+	std::thread*						mp_thread_transform;   		//转化数据的线程指针
+	Thread_condition					m_condition_transform;		//转化数据的条件变量
+	std::thread*        				mp_thread_publish;   		//发布信息的线程指针
+	Thread_condition					m_condition_publish;		//发布信息的条件变量
+
+	//任务单的指针,实际内存由应用层管理,
+	//接受任务后,指向新的任务单
+	Laser_task *  						mp_laser_task;        		//任务单的指针
+
 };
 
 
+//雷达的注册类,
+//雷达模块可能有多个不同的雷达,这些雷达需要制定不同的子类,从laser基类继承。
+//使用类的多态,从基类操作不同的子类。
+//雷达的注册器为单例模式,没有任何成员变量。
+//里面定义了 static std::map<std::string, CreateLaserFunc>* g_map  注册表,作为永久的内存。
+//然后提供了注册函数和访问函数,来操作这段静态变量(唯一,永久)
 class LaserRegistory
 {
 	typedef Laser_base*  (*CreateLaserFunc)(int id, Laser_proto::laser_parameter laser_param);
@@ -158,7 +172,7 @@ public:
 	}
 	static Laser_base* CreateLaser(std::string name, int id,Laser_proto::laser_parameter laser_param) {
 		if (GetFuncMap().count(name) == 0)
-            return 0;
+			return 0;
 		return GetFuncMap()[name](id,laser_param);
 	}
 private:

+ 304 - 0
laser/Laser.puml

@@ -0,0 +1,304 @@
+@startuml
+skinparam classAttributeIconSize 0
+
+<<<<<<< HEAD
+title  Laser_base  雷达的基类
+=======
+title  Laser_base
+>>>>>>> origin/hl
+
+
+
+enum Laser_statu
+{
+//雷达工作状态,基类三线程的状态
+//connect_laser 和  disconnect_laser  	中要切换状态 LASER_DISCONNECT <===> LASER_READY
+//start_scan 和 stop_scan 和 end_task	中要切换状态 LASER_READY <===> LASER_BUSY
+//默认值 LASER_DISCONNECT	=0
+	LASER_DISCONNECT	=0,	        //雷达断连
+	LASER_READY			=1,			//雷达正常待机,空闲
+	LASER_BUSY			=2,	        //雷达正在工作,正忙
+	LASER_FAULT			=3,         //雷达错误
+}
+
+
+
+class Laser_base
+{
+//雷达的基类,不能直接使用,必须子类继承
+==public:==
+	Laser_base() = delete;
+	Laser_base(const Laser_base& other) = delete;
+..
+	//唯一的构造函数,按照设备名称和雷达参数来创建实例。
+	//input:id: 雷达设备的id,(唯一索引)
+	//input:laser_param:雷达的参数,
+	//注:利用protobuf创建 laser_parameter 类,然后从文件读取参数
+	Laser_base(int laser_id,Laser_proto::laser_parameter laser_param);
+	//析构函数
+	~Laser_base();
+..
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
+	//对外的接口函数,负责接受并处理任务单,
+	//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+	//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
+==public:==
+	//设置保存文件的路径,并打开文件,
+	Error_manager set_open_save_path(std::string save_path,bool is_save=true);
+	//关闭保存文件,推出前一定要执行
+	Error_manager close_save_path();
+	//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+	virtual bool is_ready();
+	//获取雷达id
+	int get_laser_id();
+==protected:==
+	//接受二进制消息的功能函数,每次只接受一个CBinaryData
+	// 纯虚函数,必须由子类重载,
+	virtual bool receive_buf_to_queue(Binary_buf& binary_buf) = 0;
+	//线程执行函数,将二进制消息存入队列缓存,
+	void thread_receive();
+..
+	//将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
+	// 纯虚函数,必须由子类重载,
+	virtual Buf_type transform_buf_to_points(Binary_buf* p_binary_buf, std::vector<CPoint3D>& point3D_cloud)=0;
+	//线程执行函数,转化并处理三维点云。
+	void thread_transform();
+..
+	//公开发布雷达信息的功能函数,
+	Error_manager publish_laser_to_message();
+	//线程执行函数,公开发布雷达的相关信息,用作上位机的监视。
+	static void thread_publish(Laser_base* p_laser);
+..
+	//获取雷达状态
+	Laser_statu get_laser_statu();
+==protected:==
+	//初始化变换矩阵,设置默认值
+	Error_manager init_laser_matrix();
+	//设置变换矩阵,用作三维点的坐标变换,
+	Error_manager set_laser_matrix(double* p_matrix, int size);
+..
+	//三维点的坐标变换的功能函数,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
+	virtual CPoint3D transform_by_matrix(CPoint3D point);
+==protected:==
+	//为了保证多线程的数据安全,修改共享数据必须加锁。  atomic 和 安全队列 可以不加锁进行读写
+	//建议:判断标志位使用 atomic, 容器要封装并使用 安全容器,
+	std::mutex          				m_laser_lock;            	//雷达数据锁
+..
+	std::atomic<int>					m_laser_id;                 //雷达设备id
+	Laser_proto::laser_parameter  		m_laser_param;				//雷达的配置参数
+	//雷达变换矩阵,三维点的坐标变换的矩阵,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
+	//必须在set_laser_matrix之后,才能使用。(connect时,从雷达的配置参数导入)
+	double								mp_laser_matrix[LASER_MATRIX_ARRAY_SIZE];	//雷达变换矩阵
+	//雷达扫描事件的标志位,受start和stop控制,然后其他线程判断m_scan_flag标准位,来进行启停。
+	std::atomic<bool>                	m_laser_scan_flag;          //雷达扫描的使能标志位
+	//雷达状态和任务状态同步,m_scan_flag停止之后,还要等任务执行完成,才会切回 ready。
+	std::atomic<Laser_statu>			m_laser_statu;             	//雷达工作状态,基类三线程的状态
+	//注:m_laser_statu是基类的三线程的状态,和livox sdk后台线程状态没有任何关系。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+..
+	std::atomic<int>            		m_points_count;         	//雷达采集点的计数
+	Thread_safe_queue<Binary_buf*>		m_queue_laser_data;         //二进制缓存的队列容器
+	Binary_buf							m_last_data;			    //上一个二进制缓存,用作数据拼接
+..
+	std::atomic<bool> 					m_save_flag;           		//雷达保存文件的使能标志位
+	std::string							m_save_path;            	//雷达保存文件的保存路径
+	CLogFile							m_binary_log_tool;          //二进制缓存的日志工具
+	CLogFile							m_points_log_tool;          //三维点云的日志工具
+..
+	//线程指针的内存管理,由Connect和Disconnect进行分配和释放。
+	std::thread*						mp_thread_receive;    		//接受缓存的线程指针
+	Thread_condition					m_condition_receive;		//接受缓存的条件变量
+	std::thread*						mp_thread_transform;   		//转化数据的线程指针
+	Thread_condition					m_condition_transform;		//转化数据的条件变量
+	std::thread*        				mp_thread_publish;   		//发布信息的线程指针
+	Thread_condition					m_condition_publish;		//发布信息的条件变量
+..
+	//任务单的指针,实际内存由应用层管理,
+	//接受任务后,指向新的任务单
+	Laser_task *  						mp_laser_task;        		//任务单的指针
+}
+
+
+class CPoint3D
+{
+//三维点
+	double x, y, z;
+}
+
+class CLogFile
+{
+//日志文件
+	void open(const char *_Filename, bool binary = false);
+	void write(const char *_Str, streamsize _Count);
+	void close();
+	fstream m_file;
+    std::mutex m_lock;
+}
+
+class laser_parameter
+{
+//雷达参数
+}
+
+
+class Laser_task
+{
+//雷达模块的任务指令,从Task_Base继承,
+//补充了雷达专属的数据输入和输出
+==public:==
+    //初始化任务单,必须初始化之后才可以使用,(必选参数)
+    Error_manager task_init(Task_statu task_statu,
+                            pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
+                            std::mutex* p_task_cloud_lock);
+..
+    //初始化任务单,必须初始化之后才可以使用,(可选参数)
+    Error_manager task_init(Task_statu task_statu,
+                            std::string & task_statu_information,
+                            unsigned int task_frame_maxnum,
+                            pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
+                            std::mutex* p_task_cloud_lock);
+..
+    //push点云,把 point_xyz 添加到 p_task_point_cloud 里面。
+    Error_manager task_push_point(pcl::PointXYZ point_xyz);
+==protected:==
+    //点云的采集帧数最大值,任务输入
+    unsigned int                    m_task_frame_maxnum;
+    //点云保存文件的路径,任务输入
+    std::string                     m_task_save_path;
+    //三维点云的数据保护锁,任务输入
+    std::mutex*                     mp_task_cloud_lock;
+    //采集结果,三维点云容器的智能指针,任务输出
+    //这里只是指针,实际内存由应用层管理,初始化时必须保证内存有效。
+    pcl::PointCloud<pcl::PointXYZ>::Ptr        mp_task_point_cloud;
+}
+
+
+class Task_Base
+{
+//任务单基类
+==public:==
+    //初始化任务单,初始任务单类型为 UNKONW_TASK
+    virtual Error_manager init();
+    //更新任务单
+    Error_manager update_statu(Task_statu task_statu,std::string statu_information="");
+    //获取任务类型
+    Task_type   get_task_type();
+==protected:==
+    Task_type                   m_task_type;                    //任务类型
+    Task_statu                  m_task_statu;                   //任务状态
+    std::string                 m_task_statu_information;       //任务状态说明
+	Error_manager               m_task_error_manager;//错误码,任务故障信息,任务输出
+}
+
+Laser_task <-- Task_Base : inherit
+
+class Error_manager
+{
+//错误码管理
+}
+
+
+class Binary_buf
+{
+//二进制缓存,
+	//比较前面部分的buf是否相等,使用 other.m_length 为标准
+	bool is_equal_front(const Binary_buf& other);
+	//比较前面部分的buf是否相等,len为0时,使用strlen(buf)为标准,不比较结束符'\0'
+	bool is_equal_front(const char* p_buf, int len = 0);
+..
+	char* get_buf()const;
+	int	get_length()const;
+--
+	char*		mp_buf;				//二进制缓存指针
+	int			m_length;			//二进制缓存长度
+}
+
+
+class Thread_condition
+{
+	bool wait();
+	//等待一定的时间(默认时间单位:毫秒ms),由 is_pass_wait 决定是否阻塞。
+	bool wait_for_millisecond(unsigned int millisecond);
+	//唤醒已经阻塞的线程,唤醒一个线程
+	void notify_one(bool pass_ever, bool pass_once = false);
+	//唤醒已经阻塞的线程,唤醒全部线程
+	void notify_all(bool pass_ever, bool pass_once = false);
+	//杀死所有的线程,强制退出线程函数,只是操作受当前Thread_condition影响的所有线程
+	void kill_all();
+	//判断是否或者,return !m_kill_flag
+	bool is_alive();
+==protected:==
+	static bool is_pass_wait(Thread_condition * other);
+..
+	std::atomic<bool> 		m_kill_flag;			//是否杀死线程,让线程强制退出,
+	std::atomic<bool> 		m_pass_ever;			//线程能否直接通过等待,对后面的线程也生效。
+	std::atomic<bool> 		m_pass_once;			//线程能否直接通过等待,一次(通过一次之后,wait里面自动改为false)
+	std::mutex 				m_mutex;				//线程的锁
+	std::condition_variable m_condition_variable;	//线程的条件变量
+}
+
+
+class Thread_safe_queue <<    template<class T>    >>
+{
+	//等待并弹出数据,成功弹出则返回true
+	bool wait_and_pop(T& value);
+	//尝试弹出数据,成功弹出则返回true
+	bool try_pop(T& value);
+	//等待并弹出数据,成功弹出则返回true
+	std::shared_ptr<T> wait_and_pop();
+	//尝试弹出数据,成功弹出则返回true
+	std::shared_ptr<T> try_pop();
+	//插入一项,并唤醒一个线程,
+	bool push(T new_value);
+	//清除队列,只是将队列的实例抛出。T是实例内存,系统自动回收的。
+	bool clear();
+	//清除队列,抛出之后还要delete指针。T是动态内存,需要手动回收的。
+	bool clear_and_delete();
+==public:==
+	//判空
+	bool empty();
+	//获取队列大小
+	size_t size();
+	//设置队列为退出状态。并唤醒所有的线程,使其通过wait
+	void termination_queue();
+	//唤醒队列,恢复所有的功能函数。wait_and_pop会继续阻塞。
+	void wake_queue();
+	//获取退出状态
+	bool get_termination_flag();
+	//判断是否可以直接通过wait,  m_data_queue不为空或者m_termination终止时都可以通过等待。
+	bool is_pass();
+==protected:==
+	std::mutex 						m_mutex;				//队列的锁
+	std::queue<std::shared_ptr<T>> 	m_data_queue;			//队列数据,使用智能指针shared_ptr
+	std::condition_variable 		m_data_cond;			//条件变量
+	std::atomic<bool> 				m_termination_flag;		//终止标志位
+}
+
+
+
+Laser_base <-- Laser_statu : include
+Laser_base <-- CPoint3D : include
+Laser_base <-- CLogFile : include
+Laser_base <-- laser_parameter : include
+Laser_base <-- Laser_task : include
+Laser_base <-- Error_manager : include
+Laser_base <-- Binary_buf : include
+Laser_base <-- Thread_condition : include
+Laser_base <-- Thread_safe_queue : include
+
+
+
+@enduml

+ 253 - 105
laser/LivoxLaser.cpp

@@ -11,24 +11,213 @@ std::map<std::string, CLivoxLaser*> CLivoxLaser::g_sn_laser= std::map<std::strin
 CLivoxLaser*						CLivoxLaser::g_all_laser[kMaxLidarCount] = { 0 };
 unsigned int  CLivoxLaser::g_count[kMaxLidarCount] = { 0 };
 
-void CLivoxLaser::UpdataHandle()
+
+
+
+
+CLivoxLaser::CLivoxLaser(int id, Laser_proto::laser_parameter laser_param)
+:Laser_base(id, laser_param)
 {
-	std::string sn = m_laser_param.sn();
-	if (g_sn_handle.find(sn) != g_sn_handle.end())
+	//设备livox扫描最大帧数
+	m_frame_maxnum = laser_param.frame_num();
+	//判断参数类型,
+	if(laser_param.type()=="Livox")
 	{
-		m_handle = g_sn_handle[sn];
+		//填充雷达设备的广播码
+		g_sn_laser.insert(std::make_pair(laser_param.sn(), this));
+		//初始化livox
+		InitLivox();
 	}
+}
+
+CLivoxLaser::~CLivoxLaser()
+{
+
+}
 
+//雷达链接设备,为3个线程添加线程执行函数。
+Error_manager CLivoxLaser::connect_laser()
+{
+	return Laser_base::connect_laser();
+}
+//雷达断开链接,释放3个线程
+Error_manager CLivoxLaser::disconnect_laser()
+{
+	return Laser_base::disconnect_laser();
 }
+//对外的接口函数,负责接受并处理任务单,
+//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+Error_manager CLivoxLaser::execute_task(Task_Base* p_laser_task)
+{
+	LOG(INFO) << " CLivoxLaser::execute_task start  "<< this;
+	Error_manager t_error;
+	Error_manager t_result;
+
+	//检查指针
+	if (p_laser_task == NULL) {
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 "Laser_base::porform_task failed, POINTER_IS_NULL");
+	}
+	//检查任务类型,
+	if (p_laser_task->get_task_type() != LASER_TASK)
+	{
+		return Error_manager(Error_code::LIVOX_TASK_TYPE_ERROR, Error_level::MINOR_ERROR,
+							 "laser task type error != LASER_TASK");
+	}
 
+	//接受任务,并将任务的状态改为TASK_SIGNED已签收
+	mp_laser_task = (Laser_task *) p_laser_task;
+	mp_laser_task->set_task_statu(TASK_SIGNED);
 
-bool CLivoxLaser::IsScanComplete()
+	//检查消息内容是否正确,
+	//检查三维点云指针
+	if (mp_laser_task->get_task_point_cloud().get() == NULL)
+	{
+		t_result.error_manager_reset(Error_code::POINTER_IS_NULL,
+											Error_level::MINOR_ERROR,
+											"execute_task mp_task_point_cloud is null");
+		//将任务的状态改为 TASK_OVER 结束任务
+		mp_laser_task->set_task_statu(TASK_OVER);
+		//返回错误码
+		mp_laser_task->set_task_error_manager(t_result);
+		return t_result;
+	}
+	else
+	{
+		m_frame_maxnum=mp_laser_task->get_task_frame_maxnum();
+
+
+		//设置保存文件的路径
+		std::string save_path = mp_laser_task->get_task_save_path();
+		t_error = set_open_save_path(save_path);
+		if ( t_error != Error_code::SUCCESS )
+		{
+			//文件保存文件的路径的设置 允许失败。继续后面的动作
+			t_result.compare_and_cover_error(t_error);
+		}
+		//启动雷达扫描
+		t_error = start_scan();
+		if ( t_error != Error_code::SUCCESS )
+		{
+			t_result.compare_and_cover_error(t_error);
+
+			//将任务的状态改为 TASK_OVER 结束任务
+			mp_laser_task->set_task_statu(TASK_OVER);
+			//返回错误码
+			mp_laser_task->set_task_error_manager(t_result);
+			return t_result;
+		}
+		else
+		{
+			//将任务的状态改为 TASK_WORKING 处理中
+			mp_laser_task->set_task_statu(TASK_WORKING);
+		}
+	}
+	//返回错误码
+	if (t_result != Error_code::SUCCESS)
+	{
+		mp_laser_task->set_task_error_manager(t_result);
+	}
+	return t_result;
+}
+
+//检查雷达状态,是否正常运行
+Error_manager CLivoxLaser::check_laser()
+{
+	return Laser_base::check_laser();
+}
+//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+Error_manager CLivoxLaser::start_scan()
+{
+	LOG(INFO) << " livox start :"<<this;
+	//清空livox子类的队列,
+	m_queue_livox_data.clear_and_delete();
+	g_count[m_handle] = 0;
+	return Laser_base::start_scan();
+}
+//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+Error_manager CLivoxLaser::stop_scan()
+{
+	return Laser_base::stop_scan();
+}
+//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+Error_manager CLivoxLaser::end_task()
+{
+	return Laser_base::end_task();
+}
+
+//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+bool CLivoxLaser::is_ready()
 {
-    if(mp_laser_task!=NULL)
-	    return g_count[m_handle] >= mp_laser_task->get_task_points_number();
-    else
-        return false;
+	//livox雷达设备的状态,livox sdk后台线程的状态
+	if ( m_laser_statu == LASER_READY &&
+		 g_devices[m_handle].device_state != kDeviceStateDisconnect  )
+	{
+		true;
+	}
+	else
+	{
+	    false;
+	}
+}
+
+//接受二进制消息的功能函数,每次只接受一个CBinaryData
+// 纯虚函数,必须由子类重载,
+bool CLivoxLaser::receive_buf_to_queue(Binary_buf& binary_buf)
+{
+	Binary_buf* tp_livox_buf;
+	if (m_queue_livox_data.try_pop(tp_livox_buf))
+	{
+		binary_buf = *tp_livox_buf;
+		delete tp_livox_buf;
+		std::cout << "huli m_queue_livox_data.try_pop" << std::endl;
+		return true;
+	}
+	return false;
 }
+//将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
+// 纯虚函数,必须由子类重载,
+Buf_type CLivoxLaser::transform_buf_to_points(Binary_buf* p_binary_buf, std::vector<CPoint3D>& point3D_cloud)
+{
+	if ( p_binary_buf ==NULL )
+	{
+		return BUF_UNKNOW;
+	}
+	else
+	{
+		//livox的二进制数据格式就是三维点坐标。直接强行转化指针类型即可
+		LivoxRawPoint *tp_Livox_data = (LivoxRawPoint *)p_binary_buf->get_buf();
+		//计算这一帧数据有多少个三维点。
+		int t_count = p_binary_buf->get_length() / (sizeof(LivoxRawPoint));
+
+		if (t_count <= 0)
+		{
+			return BUF_UNKNOW;
+		}
+		else
+		{
+			//转变三维点格式,并存入vector。
+			for (int i = 0; i < t_count; ++i)
+			{
+				//LivoxRawPoint 转为 CPoint3D
+				//int32_t 转 double。不要信号强度
+				LivoxRawPoint t_livox_point = tp_Livox_data[i];
+				CPoint3D t_point3D;
+				t_point3D.x = t_livox_point.x;
+				t_point3D.y = t_livox_point.y;
+				t_point3D.z = t_livox_point.z;
+				point3D_cloud.push_back(t_point3D);
+//				std::cout << "huli points:" << t_point3D.x << " : " << t_point3D.y << " : " << t_point3D.z<< std::endl;
+			}
+			return BUF_DATA;
+		}
+	}
+
+}
+
+
 
 void CLivoxLaser::InitLivox()
 {
@@ -52,22 +241,22 @@ void CLivoxLaser::InitLivox()
 	}
 }
 
-CLivoxLaser::CLivoxLaser(int id, Laser_proto::laser_parameter laser_param)
-	:Laser_base(id, laser_param)
+bool CLivoxLaser::IsScanComplete()
 {
-	
-	m_frame_maxnum = laser_param.frame_num();
-	if(laser_param.type()=="Livox")
-		g_sn_laser.insert(std::make_pair(laser_param.sn(), this));
-
-	InitLivox();
+	//雷达的采集帧数判断,直接比较任务单里面的帧数最大值
+	if(mp_laser_task!=NULL)
+		return g_count[m_handle] >= mp_laser_task->get_task_frame_maxnum();
+	else
+		return false;
 }
 
-
-
-
-CLivoxLaser::~CLivoxLaser()
+void CLivoxLaser::UpdataHandle()
 {
+	std::string sn = m_laser_param.sn();
+	if (g_sn_handle.find(sn) != g_sn_handle.end())
+	{
+		m_handle = g_sn_handle[sn];
+	}
 }
 
 void CLivoxLaser::OnSampleCallback(uint8_t status, uint8_t handle, uint8_t response, void *data) {
@@ -89,7 +278,7 @@ void CLivoxLaser::OnDeviceChange(const DeviceInfo *info, DeviceEvent type)
 	if (info == NULL) {
 		return;
 	}
-	
+
 	uint8_t handle = info->handle;
 	if (handle >= kMaxLidarCount) {
 		return;
@@ -115,12 +304,15 @@ void CLivoxLaser::OnDeviceChange(const DeviceInfo *info, DeviceEvent type)
 
 	if (g_devices[handle].device_state == kDeviceStateConnect)
 	{
-		
-		if (g_devices[handle].info.state == kLidarStateNormal) {
-			if (g_devices[handle].info.type == kDeviceTypeHub) {
+
+		if (g_devices[handle].info.state == kLidarStateNormal)
+		{
+			if (g_devices[handle].info.type == kDeviceTypeHub)
+			{
 				HubStartSampling(OnSampleCallback, NULL);
 			}
-			else {
+			else
+			{
 				LidarStartSampling(handle, OnSampleCallback, NULL);
 			}
 			g_devices[handle].device_state = kDeviceStateSampling;
@@ -138,7 +330,7 @@ void CLivoxLaser::OnDeviceBroadcast(const BroadcastDeviceInfo *info)
 	bool result = false;
 	uint8_t handle = 0;
 	result = AddLidarToConnect(info->broadcast_code, &handle);
-	
+
 	if (result == kStatusSuccess) {
 		/** Set the point cloud data for a specific Livox LiDAR. */
 		SetDataCallback(handle, LidarDataCallback, NULL);
@@ -155,16 +347,17 @@ void CLivoxLaser::OnDeviceBroadcast(const BroadcastDeviceInfo *info)
 			g_sn_handle[sn] = handle;
 		else
 			g_sn_handle.insert(std::make_pair(sn,handle));
-		
+
 	}
 
 }
 
 void CLivoxLaser::LidarDataCallback(uint8_t handle, LivoxEthPacket *data, uint32_t data_num, void *client_data)
 {
-	///?????????????? ?????????handle
+//	std::cout << "huli LidarDataCallback" << std::endl;
+
 	CLivoxLaser* livox = g_all_laser[handle];
-	if (livox == 0)
+	if (livox == NULL)
 	{
 		if (g_handle_sn.find(handle) != g_handle_sn.end())
 		{
@@ -178,99 +371,54 @@ void CLivoxLaser::LidarDataCallback(uint8_t handle, LivoxEthPacket *data, uint32
 			}
 		}
 	}
+//	std::cout << "huli LidarDataCallback " << std::endl;
+
 
-	
 	if (data && livox)
 	{
-		if (livox->m_bStart_capture.WaitFor(1))
+//		std::cout << "huli m_laser_scan_flag = " << livox->m_laser_scan_flag << std::endl;
+
+		//判断雷达扫描标志位
+		if (livox->m_laser_scan_flag)
 		{
 			if (livox->IsScanComplete())
 			{
-				livox->Stop();
+				std::cout << "huli qwe point count = " << livox->g_count[livox->m_handle] << std::endl;
+				livox->stop_scan();
 				return;
 			}
+			else
+			{
+				std::cout << "huli asd point count = " << livox->g_count[livox->m_handle] << std::endl;
+
+			}
+//			std::cout << "huli LidarDataCallback " << std::endl;
+
 			if (g_count[handle] >= livox->m_frame_maxnum)
 				return;
 			uint64_t cur_timestamp = *((uint64_t *)(data->timestamp));
 			LivoxRawPoint *p_point_data = (LivoxRawPoint *)data->data;
-			
-			CBinaryData* data_bin = new CBinaryData((char*)p_point_data, data_num * sizeof(LivoxRawPoint));
+
+			Binary_buf* data_bin = new Binary_buf((char*)p_point_data, data_num * sizeof(LivoxRawPoint));
 			livox->m_queue_livox_data.push(data_bin);
+			std::cout << "huli m_queue_livox_data.push " << std::endl;
+
 			g_count[handle]++;
-			
+
 		}
-        else if(livox->m_statu!=eLaser_ready)
+	/*	else
 		{
-			//?????????????????
-			livox->m_statu = eLaser_ready;
-            usleep(10*1000);
-		}
-	}
-	
-}
+			std::cout << "huli 1z error " << "data = "<< data  << std::endl;
+			std::cout << "huli 1z error " << "livox = "<< livox  << std::endl;
 
-eLaserStatu CLivoxLaser::GetStatu()
-{
-    if(g_devices[m_handle].device_state == kDeviceStateConnect||
-            g_devices[m_handle].device_state == kDeviceStateSampling)
-    {
-        m_statu=eLaser_ready;
-    }
-    if(g_devices[m_handle].device_state == kDeviceStateDisconnect)
-    {
-        m_statu=eLaser_disconnect;
-    }
-    return m_statu;
-}
-
-bool CLivoxLaser::Connect()
-{
-	return Laser_base::Connect();
-}
-void CLivoxLaser::Disconnect() 
-{
-	Laser_base::Disconnect();
-}
-bool CLivoxLaser::Start()
-{
-	LOG(INFO) << " livox start :"<<this;
-	m_queue_livox_data.clear();
-	g_count[m_handle] = 0;
-	return Laser_base::Start();
-}
-bool CLivoxLaser::Stop()
-{
-	return Laser_base::Stop();
-}
-
-bool CLivoxLaser::RecvData(CBinaryData& data)
-{
-	CBinaryData* livox_data;
-	if (m_queue_livox_data.try_pop(livox_data))
-	{
-		data = *livox_data;
-		delete livox_data;
-		return true;
+			//?????????????????
+			livox->m_laser_statu = LASER_READY;
+			usleep(10*1000);
+		}*/
 	}
-	return false;
-}
-DATA_type CLivoxLaser::Data2PointXYZ(CBinaryData* pData, std::vector<CPoint3D>& points)
-{
-	LivoxRawPoint *p_point_data = (LivoxRawPoint *)pData->Data();
-	int count = pData->Length() / (sizeof(LivoxRawPoint));
-	
-	if (count <= 0)
-		return eUnknow;
-	for (int i = 0; i < count; ++i)
+	else
 	{
-		LivoxRawPoint point = p_point_data[i];
-		CPoint3D pt;
-		pt.x = point.x;
-		pt.y = point.y;
-		pt.z = point.z;
-		points.push_back(pt);
+		std::cout << "huli 2z error " << "data = "<< data  << std::endl;
+		std::cout << "huli 2z error " << "livox = "<< livox  << std::endl;
 	}
-	return eData;
 }
-
-

+ 52 - 20
laser/LivoxLaser.h

@@ -5,40 +5,72 @@
 #include "livox_sdk.h"
 #include <map>
 
-
+//大疆livox雷达,从Laser_base继承。
 class CLivoxLaser :public Laser_base
 {
 protected:
-	typedef enum {
-		kDeviceStateDisconnect = 0,
-		kDeviceStateConnect = 1,
-		kDeviceStateSampling = 2,
+	//雷达设备状态,livox管理底层sdk,后台线程的工作状态
+	typedef enum
+	{
+		kDeviceStateDisconnect = 0,		//雷达设备状态	断开连接
+		kDeviceStateConnect = 1,		//雷达设备状态	连接正常
+		kDeviceStateSampling = 2,		//雷达设备状态	正在扫描
 	} DeviceState;
-	typedef struct {
-		uint8_t handle;
-		DeviceState device_state;
-		DeviceInfo info;
+
+	//雷达设备信息,
+	typedef struct
+	{
+		uint8_t handle;					//雷达控制句柄
+		DeviceState device_state;		//雷达设备状态
+		DeviceInfo info;				//雷达基本信息
 	} DeviceItem;
 
 
 public:
+	CLivoxLaser() = delete;
+	CLivoxLaser(const CLivoxLaser& other) = delete;
+	//唯一的构造函数,按照设备名称和雷达参数来创建实例。
+	//input:id: 雷达设备的id,(唯一索引)
+	//input:laser_param:雷达的参数,
+	//注:利用protobuf创建 laser_parameter 类,然后从文件读取参数
 	CLivoxLaser(int id, Laser_proto::laser_parameter laser_param);
 	~CLivoxLaser();
 
-	virtual bool Connect();
-	virtual void Disconnect();
-	virtual bool Start();
-	virtual bool Stop();
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
+	//对外的接口函数,负责接受并处理任务单,
+	//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+	//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
+
+	//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+	virtual bool is_ready();
 
 protected:
-	virtual bool RecvData(CBinaryData& data);
-	virtual DATA_type Data2PointXYZ(CBinaryData* pData, std::vector<CPoint3D>& points);
-	virtual bool IsScanComplete();
-	virtual void UpdataHandle();
-	virtual eLaserStatu GetStatu();
-	
+	//接受二进制消息的功能函数,每次只接受一个CBinaryData
+	// 纯虚函数,必须由子类重载,
+	virtual bool receive_buf_to_queue(Binary_buf& binary_buf);
+	//将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
+	// 纯虚函数,必须由子类重载,
+	virtual Buf_type transform_buf_to_points(Binary_buf* p_binary_buf, std::vector<CPoint3D>& point3D_cloud);
+
+
+
 protected:
 	static void InitLivox();
+	virtual bool IsScanComplete();
+	virtual void UpdataHandle();
 	static void LidarDataCallback(uint8_t handle, LivoxEthPacket *data, uint32_t data_num, void *laser);
 	static void OnDeviceChange(const DeviceInfo *info, DeviceEvent type);
 	static void OnDeviceBroadcast(const BroadcastDeviceInfo *info);
@@ -47,7 +79,7 @@ protected:
 protected:
 	uint8_t									m_handle;
 	unsigned int							m_frame_maxnum;
-	threadsafe_queue<CBinaryData*>			m_queue_livox_data;
+	Thread_safe_queue<Binary_buf*>			m_queue_livox_data;
 
 	static DeviceItem						g_devices[kMaxLidarCount];
 	

+ 230 - 0
laser/LivoxLaser.puml

@@ -0,0 +1,230 @@
+@startuml
+skinparam classAttributeIconSize 0
+
+<<<<<<< HEAD
+title  CLivoxLaser 大疆livox雷达
+=======
+title  CLivoxLaser
+>>>>>>> origin/hl
+
+
+
+
+class CLivoxLaser
+{
+//大疆livox雷达,从Laser_base继承。
+==protected:==
+	//雷达设备状态,livox管理底层sdk,后台线程的工作状态
+	typedef enum
+	{
+		kDeviceStateDisconnect = 0,		//雷达设备状态	断开连接
+		kDeviceStateConnect = 1,		//雷达设备状态	连接正常
+		kDeviceStateSampling = 2,		//雷达设备状态	正在扫描
+	} DeviceState;
+..
+	//雷达设备信息,
+	typedef struct
+	{
+		uint8_t handle;					//雷达控制句柄
+		DeviceState device_state;		//雷达设备状态
+		DeviceInfo info;				//雷达基本信息
+	} DeviceItem;
+==public:==
+	CLivoxLaser() = delete;
+	CLivoxLaser(const CLivoxLaser& other) = delete;
+	//唯一的构造函数,按照设备名称和雷达参数来创建实例。
+	CLivoxLaser(int id, Laser_proto::laser_parameter laser_param);
+	~CLivoxLaser();
+..
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
+	//对外的接口函数,负责接受并处理任务单,
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
+..
+	//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+	virtual bool is_ready();
+==protected:==
+	//接受二进制消息的功能函数,每次只接受一个CBinaryData
+	virtual bool receive_buf_to_queue(Binary_buf& binary_buf);
+	//将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
+	virtual Buf_type transform_buf_to_points(Binary_buf* p_binary_buf, std::vector<CPoint3D>& point3D_cloud);
+==protected:==
+	static void InitLivox();
+	virtual bool IsScanComplete();
+	virtual void UpdataHandle();
+	static void LidarDataCallback(uint8_t handle, LivoxEthPacket *data, uint32_t data_num, void *laser);
+	static void OnDeviceChange(const DeviceInfo *info, DeviceEvent type);
+	static void OnDeviceBroadcast(const BroadcastDeviceInfo *info);
+	static void OnSampleCallback(uint8_t status, uint8_t handle, uint8_t response, void *data);
+==protected:==
+	uint8_t									m_handle;
+	unsigned int							m_frame_maxnum;
+	Thread_safe_queue<Binary_buf*>			m_queue_livox_data;
+	static DeviceItem						g_devices[kMaxLidarCount];
+	static std::map<uint8_t,std::string>	g_handle_sn;
+	static std::map<std::string, uint8_t>	g_sn_handle;
+	static std::map<std::string, CLivoxLaser*> g_sn_laser;
+	static CLivoxLaser*						g_all_laser[kMaxLidarCount];
+	static unsigned int						g_count[kMaxLidarCount];
+}
+
+
+class Laser_base
+{
+//雷达的基类,不能直接使用,必须子类继承
+==public:==
+	Laser_base() = delete;
+	Laser_base(const Laser_base& other) = delete;
+..
+	//唯一的构造函数,按照设备名称和雷达参数来创建实例。
+	//input:id: 雷达设备的id,(唯一索引)
+	//input:laser_param:雷达的参数,
+	//注:利用protobuf创建 laser_parameter 类,然后从文件读取参数
+	Laser_base(int laser_id,Laser_proto::laser_parameter laser_param);
+	//析构函数
+	~Laser_base();
+..
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
+	//对外的接口函数,负责接受并处理任务单,
+	//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+	//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
+==public:==
+	//设置保存文件的路径,并打开文件,
+	Error_manager set_open_save_path(std::string save_path,bool is_save=true);
+	//关闭保存文件,推出前一定要执行
+	Error_manager close_save_path();
+	//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+	virtual bool is_ready();
+	//获取雷达id
+	int get_laser_id();
+==protected:==
+	//接受二进制消息的功能函数,每次只接受一个CBinaryData
+	// 纯虚函数,必须由子类重载,
+	virtual bool receive_buf_to_queue(Binary_buf& binary_buf) = 0;
+	//线程执行函数,将二进制消息存入队列缓存,
+	void thread_receive();
+..
+	//将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
+	// 纯虚函数,必须由子类重载,
+	virtual Buf_type transform_buf_to_points(Binary_buf* p_binary_buf, std::vector<CPoint3D>& point3D_cloud)=0;
+	//线程执行函数,转化并处理三维点云。
+	void thread_transform();
+..
+	//公开发布雷达信息的功能函数,
+	Error_manager publish_laser_to_message();
+	//线程执行函数,公开发布雷达的相关信息,用作上位机的监视。
+	static void thread_publish(Laser_base* p_laser);
+..
+	//获取雷达状态
+	Laser_statu get_laser_statu();
+==protected:==
+	//初始化变换矩阵,设置默认值
+	Error_manager init_laser_matrix();
+	//设置变换矩阵,用作三维点的坐标变换,
+	Error_manager set_laser_matrix(double* p_matrix, int size);
+..
+	//三维点的坐标变换的功能函数,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
+	virtual CPoint3D transform_by_matrix(CPoint3D point);
+==protected:==
+	//为了保证多线程的数据安全,修改共享数据必须加锁。  atomic 和 安全队列 可以不加锁进行读写
+	//建议:判断标志位使用 atomic, 容器要封装并使用 安全容器,
+	std::mutex          				m_laser_lock;            	//雷达数据锁
+..
+	std::atomic<int>					m_laser_id;                 //雷达设备id
+	Laser_proto::laser_parameter  		m_laser_param;				//雷达的配置参数
+	//雷达变换矩阵,三维点的坐标变换的矩阵,从雷达自己的坐标系,转化到公共坐标系,(目前以plc为公共坐标系)
+	//必须在set_laser_matrix之后,才能使用。(connect时,从雷达的配置参数导入)
+	double								mp_laser_matrix[LASER_MATRIX_ARRAY_SIZE];	//雷达变换矩阵
+	//雷达扫描事件的标志位,受start和stop控制,然后其他线程判断m_scan_flag标准位,来进行启停。
+	std::atomic<bool>                	m_laser_scan_flag;          //雷达扫描的使能标志位
+	//雷达状态和任务状态同步,m_scan_flag停止之后,还要等任务执行完成,才会切回 ready。
+	std::atomic<Laser_statu>			m_laser_statu;             	//雷达工作状态,基类三线程的状态
+	//注:m_laser_statu是基类的三线程的状态,和livox sdk后台线程状态没有任何关系。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+..
+	std::atomic<int>            		m_points_count;         	//雷达采集点的计数
+	Thread_safe_queue<Binary_buf*>		m_queue_laser_data;         //二进制缓存的队列容器
+	Binary_buf							m_last_data;			    //上一个二进制缓存,用作数据拼接
+..
+	std::atomic<bool> 					m_save_flag;           		//雷达保存文件的使能标志位
+	std::string							m_save_path;            	//雷达保存文件的保存路径
+	CLogFile							m_binary_log_tool;          //二进制缓存的日志工具
+	CLogFile							m_points_log_tool;          //三维点云的日志工具
+..
+	//线程指针的内存管理,由Connect和Disconnect进行分配和释放。
+	std::thread*						mp_thread_receive;    		//接受缓存的线程指针
+	Thread_condition					m_condition_receive;		//接受缓存的条件变量
+	std::thread*						mp_thread_transform;   		//转化数据的线程指针
+	Thread_condition					m_condition_transform;		//转化数据的条件变量
+	std::thread*        				mp_thread_publish;   		//发布信息的线程指针
+	Thread_condition					m_condition_publish;		//发布信息的条件变量
+..
+	//任务单的指针,实际内存由应用层管理,
+	//接受任务后,指向新的任务单
+	Laser_task *  						mp_laser_task;        		//任务单的指针
+}
+
+class CLivoxMid100Laser
+{
+==public:==
+	CLivoxMid100Laser(int id, Laser_proto::laser_parameter laser_param);
+	~CLivoxMid100Laser();
+..
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
+	//对外的接口函数,负责接受并处理任务单,
+	//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+	//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
+..
+	//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+	virtual bool is_ready();
+==protected:==
+	virtual bool IsScanComplete();
+	virtual void UpdataHandle();
+==protected:==
+	uint8_t		m_handle1;
+	uint8_t		m_handle2;
+	uint8_t		m_handle3;
+}
+
+Laser_base -> CLivoxLaser : inherit
+CLivoxLaser -> CLivoxMid100Laser : inherit
+
+
+@enduml

+ 192 - 128
laser/LivoxMid100Laser.cpp

@@ -5,160 +5,224 @@ RegisterLaser(LivoxMid100)
 
 
 CLivoxMid100Laser::CLivoxMid100Laser(int id, Laser_proto::laser_parameter laser_param)
-	:CLivoxLaser(id, laser_param)
+:CLivoxLaser(id, laser_param)
 {
-	m_frame_maxnum = laser_param.frame_num();
-	if (laser_param.type() == "LivoxMid100")
+	//设备livox扫描最大帧数
+    m_frame_maxnum = laser_param.frame_num();
+	//判断参数类型,
+    if (laser_param.type() == "LivoxMid100")
+    {
+        std::string sn = laser_param.sn();
+        std::string sn1 = sn, sn2 = sn, sn3 = sn;
+        sn1 += "1";
+        sn2 += "2";
+        sn3 += "3";
+        g_sn_laser.insert(std::make_pair(sn1, this));
+        g_sn_laser.insert(std::make_pair(sn2, this));
+        g_sn_laser.insert(std::make_pair(sn3, this));
+		//初始化livox
+		InitLivox();
+    }
+}
+CLivoxMid100Laser::~CLivoxMid100Laser()
+{
+
+}
+
+//雷达链接设备,为3个线程添加线程执行函数。
+Error_manager CLivoxMid100Laser::connect_laser()
+{
+	Error_manager t_error;
+	//设置点云变换矩阵
+	double matrix[12]={0};
+	matrix[0]=m_laser_param.mat_r00();
+	matrix[1]=m_laser_param.mat_r01();
+	matrix[2]=m_laser_param.mat_r02();
+	matrix[3]=m_laser_param.mat_r03();
+
+	matrix[4]=m_laser_param.mat_r10();
+	matrix[5]=m_laser_param.mat_r11();
+	matrix[6]=m_laser_param.mat_r12();
+	matrix[7]=m_laser_param.mat_r13();
+
+	matrix[8]=m_laser_param.mat_r20();
+	matrix[9]=m_laser_param.mat_r21();
+	matrix[10]=m_laser_param.mat_r22();
+	matrix[11]=m_laser_param.mat_r23();
+	t_error = set_laser_matrix(matrix, 12);
+	if ( t_error != Error_code::SUCCESS )
 	{
-		std::string sn = laser_param.sn();
-		std::string sn1 = sn, sn2 = sn, sn3 = sn;
-		sn1 += "1";
-		sn2 += "2";
-		sn3 += "3";
-		g_sn_laser.insert(std::make_pair(sn1, this));
-		g_sn_laser.insert(std::make_pair(sn2, this));
-		g_sn_laser.insert(std::make_pair(sn3, this));
+		return t_error;
 	}
+	return CLivoxLaser::connect_laser();
+}
+//雷达断开链接,释放3个线程
+Error_manager CLivoxMid100Laser::disconnect_laser()
+{
+	return CLivoxLaser::disconnect_laser();
 }
 
-void CLivoxMid100Laser::UpdataHandle()
+
+
+//对外的接口函数,负责接受并处理任务单,
+//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+Error_manager CLivoxMid100Laser::execute_task(Task_Base* p_laser_task)
 {
-	std::string sn = m_laser_param.sn();
-	std::string sn1 = sn, sn2 = sn, sn3 = sn;
-	sn1 += "1";
-	sn2 += "2";
-	sn3 += "3";
-	if (g_sn_handle.find(sn1) != g_sn_handle.end())
+	LOG(INFO) << " CLivoxMid100Laser::execute_task start  "<< this;
+	Error_manager t_error;
+	Error_manager t_result;
+
+	//检查指针
+	if (p_laser_task == NULL) {
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 "Laser_base::porform_task failed, POINTER_IS_NULL");
+	}
+	//检查任务类型,
+	if (p_laser_task->get_task_type() != LASER_TASK)
 	{
-		m_handle1 = g_sn_handle[sn1];
+		return Error_manager(Error_code::LIVOX_TASK_TYPE_ERROR, Error_level::MINOR_ERROR,
+							 "laser task type error != LASER_TASK");
 	}
-	if (g_sn_handle.find(sn2) != g_sn_handle.end())
+
+	//接受任务,并将任务的状态改为TASK_SIGNED已签收
+	mp_laser_task = (Laser_task *) p_laser_task;
+	mp_laser_task->set_task_statu(TASK_SIGNED);
+
+	//检查消息内容是否正确,
+	//检查三维点云指针
+	if (mp_laser_task->get_task_point_cloud().get() == NULL)
 	{
-		m_handle2 = g_sn_handle[sn2];
+		t_result.error_manager_reset(Error_code::POINTER_IS_NULL,
+									 Error_level::MINOR_ERROR,
+									 "execute_task mp_task_point_cloud is null");
+		//将任务的状态改为 TASK_OVER 结束任务
+		mp_laser_task->set_task_statu(TASK_OVER);
+		//返回错误码
+		mp_laser_task->set_task_error_manager(t_result);
+		return t_result;
 	}
-	if (g_sn_handle.find(sn3) != g_sn_handle.end())
+	else
 	{
-		m_handle3 = g_sn_handle[sn3];
+		m_frame_maxnum=mp_laser_task->get_task_frame_maxnum();
+
+
+		//设置保存文件的路径
+		std::string save_path = mp_laser_task->get_task_save_path();
+		t_error = set_open_save_path(save_path);
+		if ( t_error != Error_code::SUCCESS )
+		{
+			//文件保存文件的路径的设置 允许失败。继续后面的动作
+			t_result.compare_and_cover_error(t_error);
+		}
+		//启动雷达扫描
+		t_error = start_scan();
+		if ( t_error != Error_code::SUCCESS )
+		{
+			t_result.compare_and_cover_error(t_error);
+
+			//将任务的状态改为 TASK_OVER 结束任务
+			mp_laser_task->set_task_statu(TASK_OVER);
+			//返回错误码
+			mp_laser_task->set_task_error_manager(t_result);
+			return t_result;
+		}
+		else
+		{
+			//将任务的状态改为 TASK_WORKING 处理中
+			mp_laser_task->set_task_statu(TASK_WORKING);
+		}
 	}
-}
-bool CLivoxMid100Laser::IsScanComplete()
-{
-    if(mp_laser_task==NULL)
-    {
-        return false;
-    }
-    else {
-        int frame_count=mp_laser_task->get_task_points_number();
-        return g_count[m_handle1] >= frame_count && g_count[m_handle2] >= frame_count
-            && g_count[m_handle2] >= frame_count;
-    }
+	//返回错误码
+	if (t_result != Error_code::SUCCESS)
+	{
+		mp_laser_task->set_task_error_manager(t_result);
+	}
+	return t_result;
 }
 
-eLaserStatu CLivoxMid100Laser::GetStatu()
+//检查雷达状态,是否正常运行
+Error_manager CLivoxMid100Laser::check_laser()
 {
-    bool cond1=g_devices[m_handle1].device_state == kDeviceStateConnect ||
-               g_devices[m_handle1].device_state == kDeviceStateSampling;
-    bool cond2=g_devices[m_handle2].device_state == kDeviceStateConnect ||
-               g_devices[m_handle2].device_state == kDeviceStateSampling;
-    bool cond3=g_devices[m_handle3].device_state == kDeviceStateConnect ||
-               g_devices[m_handle3].device_state == kDeviceStateSampling;
-    if (cond1 && cond2 && cond3) {
-        if(m_queue_laser_data.size()==0 && m_bscan_start==false)
-            m_statu = eLaser_ready;
-        else
-            m_statu = eLaser_busy;
-    }
-    else {
-        m_statu = eLaser_disconnect;
-    }
-
-
-    return m_statu;
-
+	return CLivoxLaser::check_laser();
 }
 
-bool CLivoxMid100Laser::Connect()
+//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+Error_manager CLivoxMid100Laser::start_scan()
 {
-    //设置点云变换矩阵
-    double matrix[12]={0};
-    matrix[0]=m_laser_param.mat_r00();
-    matrix[1]=m_laser_param.mat_r01();
-    matrix[2]=m_laser_param.mat_r02();
-    matrix[3]=m_laser_param.mat_r03();
-
-    matrix[4]=m_laser_param.mat_r10();
-    matrix[5]=m_laser_param.mat_r11();
-    matrix[6]=m_laser_param.mat_r12();
-    matrix[7]=m_laser_param.mat_r13();
-
-    matrix[8]=m_laser_param.mat_r20();
-    matrix[9]=m_laser_param.mat_r21();
-    matrix[10]=m_laser_param.mat_r22();
-    matrix[11]=m_laser_param.mat_r23();
-    SetMetrix(matrix);
-    return CLivoxLaser::Connect();
+	LOG(INFO) << " livoxMid100 start :" << m_laser_param.sn();
+	//清空livox子类的队列,
+	m_queue_livox_data.clear_and_delete();
+	g_count[m_handle1] = 0;
+	g_count[m_handle2] = 0;
+	g_count[m_handle3] = 0;
+	return CLivoxLaser::start_scan();
 }
-void CLivoxMid100Laser::Disconnect()
+//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+Error_manager CLivoxMid100Laser::stop_scan()
 {
-    CLivoxLaser::Disconnect();
+	LOG(INFO)<<" livoxmid100 stoped !!!"<<m_laser_param.sn();
+	return CLivoxLaser::stop_scan();
 }
-
-bool CLivoxMid100Laser::Stop()
+//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+Error_manager CLivoxMid100Laser::end_task()
 {
-    LOG(INFO)<<" livoxmid100 stoped !!!"<<m_laser_param.sn();
-    return CLivoxLaser::Stop();
+	return CLivoxLaser::end_task();
 }
-bool CLivoxMid100Laser::Start()
+//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+bool CLivoxMid100Laser::is_ready()
 {
-		LOG(INFO) << " livoxMid100 start :" << m_laser_param.sn();
-		m_queue_livox_data.clear();
-		g_count[m_handle1] = 0;
-		g_count[m_handle2] = 0;
-		g_count[m_handle3] = 0;
-		return Laser_base::Start();
+	//3个livox雷达设备的状态,livox sdk后台线程的状态
+	bool cond1=g_devices[m_handle1].device_state == kDeviceStateConnect ||
+			   g_devices[m_handle1].device_state == kDeviceStateSampling;
+	bool cond2=g_devices[m_handle2].device_state == kDeviceStateConnect ||
+			   g_devices[m_handle2].device_state == kDeviceStateSampling;
+	bool cond3=g_devices[m_handle3].device_state == kDeviceStateConnect ||
+			   g_devices[m_handle3].device_state == kDeviceStateSampling;
+
+	if ( cond1 && cond2 && cond3 && m_laser_statu == LASER_READY )
+	{
+		true;
+	}
+	else
+	{
+		false;
+	}
 }
 
-Error_manager CLivoxMid100Laser::execute_task(Task_Base* p_laser_task)
-{
-    Error_manager t_error_manager;
-//检查指针
-    if (p_laser_task == NULL) {
-        return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
-                             "Laser_base::porform_task failed, POINTER_IS_NULL");
-    }
-    if (p_laser_task->get_task_type() != LASER_TASK) {
-        return Error_manager(Error_code::LASER_TASK_TYPE_ERROR, Error_level::MINOR_ERROR,
-                             "laser task type error");
-    }
-
-
-//接受任务,并将任务的状态改为TASK_SIGNED已签收
-    mp_laser_task = (Laser_task *) p_laser_task;
-    mp_laser_task->set_task_statu(TASK_SIGNED);
 
-
-//检查消息内容是否正确,
-//检查点云指针
-    if (mp_laser_task->get_task_point3d_cloud_vector().get() == NULL) {
-        t_error_manager.error_manager_reset(Error_code::POINTER_IS_NULL,
-                                            Error_level::MINOR_ERROR,
-                                            "Laser_base::porform_task failed, POINTER_IS_NULL");
-    }
-    else{
-        m_frame_maxnum=mp_laser_task->get_task_points_number();
-//将任务的状态改为 TASK_WORKING 处理中
-        mp_laser_task->set_task_statu(TASK_WORKING);
-        std::string save_path = mp_laser_task->get_save_path();
-        SetSaveDir(save_path);
-//启动雷达扫描
-        Start();
-    }
-//返回错误码
-    if (t_error_manager != Error_code::SUCCESS) {
-        mp_laser_task->set_task_error_manager(t_error_manager);
-    }
-    return t_error_manager;
-}
-CLivoxMid100Laser::~CLivoxMid100Laser()
+void CLivoxMid100Laser::UpdataHandle()
 {
+	std::string sn = m_laser_param.sn();
+	std::string sn1 = sn, sn2 = sn, sn3 = sn;
+	sn1 += "1";
+	sn2 += "2";
+	sn3 += "3";
+	if (g_sn_handle.find(sn1) != g_sn_handle.end())
+	{
+		m_handle1 = g_sn_handle[sn1];
+	}
+	if (g_sn_handle.find(sn2) != g_sn_handle.end())
+	{
+		m_handle2 = g_sn_handle[sn2];
+	}
+	if (g_sn_handle.find(sn3) != g_sn_handle.end())
+	{
+		m_handle3 = g_sn_handle[sn3];
+	}
 }
+bool CLivoxMid100Laser::IsScanComplete()
+{
+	//雷达的采集帧数判断,直接比较任务单里面的帧数最大值
+	if(mp_laser_task==NULL)
+	{
+		return false;
+	}
+	else
+	{
+		int frame_count=mp_laser_task->get_task_frame_maxnum();
+		return g_count[m_handle1] >= frame_count && g_count[m_handle2] >= frame_count
+			   && g_count[m_handle2] >= frame_count;
+	}
+}

+ 22 - 6
laser/LivoxMid100Laser.h

@@ -10,17 +10,33 @@ public:
 	CLivoxMid100Laser(int id, Laser_proto::laser_parameter laser_param);
 	~CLivoxMid100Laser();
 
-    virtual bool Connect();
-    virtual void Disconnect();
-    virtual bool Start();
-    virtual bool Stop();
-    virtual eLaserStatu GetStatu();
-    Error_manager execute_task(Task_Base* p_laser_task);
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
+	//对外的接口函数,负责接受并处理任务单,
+	//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+	//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
+
+	//判断雷达状态是否为待机,如果已经准备好,则可以执行任务。
+	//子类重载 is_ready(),里面增加livox sdk后台线程状态的判断。
+	virtual bool is_ready();
+
 
 protected:
 	virtual bool IsScanComplete();
 	virtual void UpdataHandle();
 
+
 protected:
 	uint8_t		m_handle1;
 	uint8_t		m_handle2;

+ 2 - 1
laser/Point3D.h

@@ -4,6 +4,7 @@ class CPoint3D
 {
 public:
 	double x, y, z;
+
 	CPoint3D();
 	~CPoint3D();
     CPoint3D(double c1, double c2, double c3);
@@ -12,7 +13,7 @@ public:
 	{
 		*this = pt;
 	}
-    void Translate(double cx, double cy, double cz); //ת»¯
+    void Translate(double cx, double cy, double cz); //ת��
 };
 
 #endif

+ 323 - 0
laser/Sick511FileLaser.cpp

@@ -0,0 +1,323 @@
+
+#include "Sick511FileLaser.h"
+#include <unistd.h>
+
+RegisterLaser(Sick511File);
+CSick511FileLaser::CSick511FileLaser(int id, Laser_proto::laser_parameter laser_param)
+:Laser_base(id, laser_param)
+,m_start_read(false)
+{
+}
+
+CSick511FileLaser::~CSick511FileLaser()
+{
+	if (m_stream_read.is_open())
+		m_stream_read.close();
+}
+
+
+
+//雷达链接设备,为3个线程添加线程执行函数。
+Error_manager CSick511FileLaser::connect_laser()
+{
+	std::string ip = m_laser_param.laser_ip();
+	char file[255] = { 0 };
+	sprintf(file, "%s/laser%d.data", ip.c_str(), m_laser_id + 1);
+	if (m_stream_read.is_open())
+	{
+		m_stream_read.close();
+	}
+	m_stream_read.open(file, ios::in | ios::binary);
+	if (!m_stream_read.good())
+		return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+							 "m_stream_read.open error ");
+	m_laser_statu = LASER_READY;
+	m_file = file;
+	return Laser_base::connect_laser();
+}
+//雷达断开链接,释放3个线程
+Error_manager CSick511FileLaser::disconnect_laser()
+{
+	if(m_stream_read.is_open())
+		m_stream_read.close();
+	return Laser_base::disconnect_laser();
+}
+//对外的接口函数,负责接受并处理任务单,
+//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+Error_manager CSick511FileLaser::execute_task(Task_Base* p_laser_task)
+{
+
+}
+//检查雷达状态,是否正常运行
+Error_manager CSick511FileLaser::check_laser()
+{
+
+}
+//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+Error_manager CSick511FileLaser::start_scan()
+{
+	std::lock_guard<std::mutex> lk(m_mutex);
+
+	if (!this->is_ready())
+		return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+							" is_ready error ");
+
+	m_start_read = true;
+	return Laser_base::start_scan();
+
+}
+//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+Error_manager CSick511FileLaser::stop_scan()
+{
+	std::lock_guard<std::mutex> lk(m_mutex);
+	m_start_read = false;
+	return Error_code::SUCCESS;
+}
+//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+Error_manager CSick511FileLaser::end_task()
+{
+
+}
+
+
+
+Buf_type CSick511FileLaser::transform_buf_to_points(Binary_buf* pData, std::vector<CPoint3D>& points)
+{
+	////ƴ���ϴ�δ�������
+
+	Buf_type type = BUF_UNKNOW;
+	Binary_buf frame;
+
+	if (m_last_data.get_length() > 0)
+	{
+		if (pData)
+			frame = m_last_data + (*pData);
+		else
+			frame = m_last_data;
+		m_last_data = Binary_buf();
+	}
+	else if(pData)
+	{
+		frame = (*pData);
+	}
+	else
+	{
+		return type;
+	}
+
+	int head = FindHead(frame.get_buf(), frame.get_length());
+	int tail = FindTail(frame.get_buf(), frame.get_length());
+
+	if (tail >= 0)
+	{
+		if (tail < frame.get_length() - 1)		//���������
+		{
+			m_last_data = Binary_buf(frame.get_buf() + tail + 1, frame.get_length() - tail - 1);
+		}
+		if (head >= 0 && head < tail)
+		{
+			////���
+			Binary_buf data(frame.get_buf() + head, tail - head + 1);
+			if (data.is_equal_front( "$SLSSTP"))
+				type = BUF_STOP;
+			else if (data.is_equal_front( "$SLSSTA"))
+				type = BUF_START;
+			else if (data.is_equal_front( "$SCLRDY"))
+				type = BUF_READY;
+			else if (data.is_equal_front( "$SHWERR"))
+				type = BUF_ERROR;
+			else if (data.is_equal_front( "$N"))
+				type = BUF_DATA;
+
+			if (type == BUF_DATA)
+			{
+				////��������
+				points.clear();
+				if (data.get_length() <= 29)
+					return type;
+
+				////����
+				unsigned char angle_1 = 0;
+				unsigned char angle_2 = 0;
+				memcpy(&angle_1, (data.get_buf())+26, 1);
+				memcpy(&angle_2, (data.get_buf())+27, 1);
+				float beta_a = float(angle_1 * 256 + angle_2)*0.01;
+				float start_angle = 0.0;
+				float freq = 0.0;
+
+				std::vector<float> distance;
+				if (GetData(&data, distance, freq, start_angle))
+				{
+					float beta = (beta_a)*DEGREES;
+					float sin_beta = sin(beta);
+					float cos_beta = cos(beta);
+					for (int i = 0; i < distance.size(); ++i)
+					{
+						if (distance[i] < 0.001)
+							continue;
+
+						float alpha = (start_angle + i*freq - 90.0) * DEGREES;
+						float sin_alpha = sin(alpha);
+						float cos_alpha = cos(alpha);
+
+						float x = distance[i] * sin_alpha;
+						float y = distance[i] * cos_alpha * sin_beta;
+						float z = distance[i] * cos_alpha * cos_beta;
+
+						points.push_back(CPoint3D(x, y, z));
+					}
+					//points.push_back(CPoint3D(double(distance.size()), start_angle, freq));
+				}
+
+			}
+			else if (type == BUF_STOP)
+			{
+				m_laser_statu = LASER_READY;
+			}
+		}
+	}
+	else if (head >= 0)
+	{
+		m_last_data = Binary_buf(frame.get_buf() + head, frame.get_length() - head);
+	}
+
+	return type;
+}
+
+bool CSick511FileLaser::receive_buf_to_queue(Binary_buf& data)
+{
+	if (m_start_read == false)
+		return false;
+	if (!m_stream_read.is_open())
+		return false;
+
+	if (m_stream_read.eof())
+	{
+		stop_scan();
+		m_stream_read.close();
+		usleep(100*1000);
+		m_stream_read.open(m_file.c_str(), ios::in | ios::binary);
+	}
+
+	char buf[512] = { 0 };
+	m_stream_read.read(buf, 512);
+	int count = m_stream_read.gcount();
+	if (count > 0)
+	{
+		Binary_buf bin_data(buf, count);
+		data = bin_data;
+		return true;
+	}
+	return false;
+}
+
+int CSick511FileLaser::FindHead(char* buf, int b_len)
+{
+	int i = 0;
+	if (b_len < 2)
+		return 0;
+	for (i = 0; i <= b_len; i++)
+	{
+		if (b_len > 10)
+		{
+			if (buf[i] == '$'&& buf[i + 1] == 'N' && buf[i + 7] == 'S'
+				&&buf[i + 8] == '5'&&buf[i + 9] == '1'&&buf[i + 10] == '1')
+				return i;
+		}
+		if (b_len > 7)
+		{
+			if (buf[i] == '$'&& buf[i + 1] == 'S'&&buf[i + 7] == '*')
+				return i;
+		}
+	}
+	return -1;
+}
+
+int CSick511FileLaser::FindTail(char* buf, int b_len)
+{
+	int i = 0;
+
+	for (i = 0; i <= b_len; i++)
+	{
+		if (b_len >= i + 5)
+		{
+			if (buf[i] == '*' && buf[i + 3] == '\r'&&buf[i + 4] == '\n')
+				return i + 4;
+		}
+	}
+	return -9999999;
+}
+
+bool CSick511FileLaser::GetData(Binary_buf* pData, std::vector<float>& distance,
+								float& freq, float& start_angle)
+{
+	struct stData
+	{
+		const char* data;
+		int length;
+	};
+	std::vector<struct stData> strDatas;
+	int start = 0;
+	int end = 0;
+	int LMDscandata_index = -1;
+	for (int i = 0; i < pData->get_length(); ++i)
+	{
+		if ((*pData)[i] == ' ')
+		{
+			end = i;
+			if (end > start)
+			{
+				struct stData strData;
+//				strData.data = (*pData + start);
+				strData.data = ( pData->get_buf() + start);
+				strData.length = end - start;
+
+				strDatas.push_back(strData);
+				if (strncmp(strData.data, "LMDscandata", 11) == 0)
+					LMDscandata_index = strDatas.size() - 1;
+			}
+			end = i + 1;
+			start = end;
+		}
+	}
+
+	if (strDatas.size() > 26 + LMDscandata_index - 1)
+	{
+		struct stData start_angle_str = strDatas[23 + LMDscandata_index - 1];
+		long start_angle_l = Str0x2Long(start_angle_str.data, start_angle_str.length);
+		start_angle = float(start_angle_l)*0.01;
+
+		struct stData freq_str = strDatas[24 + LMDscandata_index - 1];
+		long freq_l = Str0x2Long(freq_str.data, freq_str.length);
+		freq = float(freq_l)*0.0001;
+
+		struct stData count_str = strDatas[25 + LMDscandata_index - 1];
+		long count = Str0x2Long(count_str.data, count_str.length);
+		if (strDatas.size() >= 26 + LMDscandata_index - 1 + count)
+		{
+			for (int i = 26 + LMDscandata_index - 1; i < 26 + LMDscandata_index - 1 + count; ++i)
+			{
+				float dis = float(Str0x2Long(strDatas[i].data, strDatas[i].length));
+				distance.push_back(dis);
+			}
+			return true;
+		}
+	}
+	return false;
+}
+long CSick511FileLaser::Str0x2Long(const char* data, int len)
+{
+	long sum = 0;
+	for (int i = 0; i < len; ++i)
+	{
+		char c = data[i];
+		int n = 0;
+		if (c >= 48 && c <= 57)
+			n = c - 48;
+		else if (c >= 65 && c <= 70)
+			n = c - 65 + 10;
+		sum += n*pow(16, len - i - 1);
+	}
+	return sum;
+}

+ 55 - 0
laser/Sick511FileLaser.h

@@ -0,0 +1,55 @@
+/*************************
+sick 511 �״� �ļ����ݽ���
+*************************/
+#ifndef __SICK_511_LASER_FILE__HH
+#define __SICK_511_LASER_FILE__HH
+#include "Laser.h"
+#include <fstream>
+class CSick511FileLaser :
+	public Laser_base
+{
+public:
+	CSick511FileLaser(int id, Laser_proto::laser_parameter laser_param);
+	virtual ~CSick511FileLaser();
+
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
+	//对外的接口函数,负责接受并处理任务单,
+	//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+	//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
+
+protected:
+	//接受二进制消息的功能函数,每次只接受一个CBinaryData
+	// 纯虚函数,必须由子类重载,
+	virtual bool receive_buf_to_queue(Binary_buf& data);
+	//将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
+	// 纯虚函数,必须由子类重载,
+	virtual Buf_type transform_buf_to_points(Binary_buf* pData, std::vector<CPoint3D>& points);
+
+
+protected:
+	int FindHead(char* buf, int b_len);
+	int FindTail(char* buf, int b_len);
+protected:
+	virtual bool GetData(Binary_buf* pData, std::vector<float>& distance,
+		float& freq, float& start_angle);
+	long Str0x2Long(const char* data, int len);
+
+protected:
+	std::ifstream	m_stream_read;
+	std::string		m_file;
+	bool			m_start_read;
+	std::mutex		m_mutex;
+};
+#endif

+ 343 - 0
laser/TcpLaser.cpp

@@ -0,0 +1,343 @@
+#include "TcpLaser.h"
+#include <stdlib.h>
+#include <unistd.h>
+
+RegisterLaser(Tcp);
+CTcpLaser::CTcpLaser(int id, Laser_proto::laser_parameter laser_param)
+	:Laser_base(id,laser_param)
+{
+}
+
+CTcpLaser::~CTcpLaser()
+{
+}
+
+
+
+
+//雷达链接设备,为3个线程添加线程执行函数。
+Error_manager CTcpLaser::connect_laser()
+{
+	std::string ip = m_laser_param.laser_ip();
+	int			port = m_laser_param.laser_port();
+	int			remoteport = m_laser_param.laser_port_remote();
+	if (ip == "" || port < 0)
+		return Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR,
+							" m_laser_param PARAMRTER ERROR ");
+
+	//��ʼ��Socket
+	//WSAStartup(MAKEWORD(1, 1), &m_wsd);
+	//����Socket����
+	m_socket = socket(AF_INET, SOCK_STREAM, 0);
+	if (m_socket <= 0)
+		return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+							 " m_laser_param PARAMRTER ERROR ");
+
+	m_send_addr.sin_family = AF_INET;
+	m_send_addr.sin_addr.s_addr = inet_addr(ip.c_str());
+	m_send_addr.sin_port = htons(remoteport);
+
+	if (0 != ::connect(m_socket, (struct sockaddr *)&m_send_addr, sizeof(struct sockaddr)))
+		return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+							 " connect m_socket ERROR ");
+	m_last_data_time = clock();
+	return Laser_base::connect_laser();
+}
+//雷达断开链接,释放3个线程
+Error_manager CTcpLaser::disconnect_laser()
+{
+	if (m_socket > 0)
+	{
+		close(m_socket);
+		//	WSACleanup();
+		m_socket = -1;
+	}
+	return Laser_base::disconnect_laser();
+}
+//对外的接口函数,负责接受并处理任务单,
+//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+Error_manager CTcpLaser::execute_task(Task_Base* p_laser_task)
+{
+
+}
+//检查雷达状态,是否正常运行
+Error_manager CTcpLaser::check_laser()
+{
+
+}
+//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+Error_manager CTcpLaser::start_scan()
+{
+	std::lock_guard<std::mutex> lk(m_mutex);
+	if (!this->is_ready())
+		return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+							"  is_ready ERROR ");
+
+	const char* sendMsg = "$SLSSTA*0A\r\n";
+	if (Send(sendMsg, strlen(sendMsg)))
+	{
+		return Laser_base::start_scan();
+	}
+	return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+						" Send error ");
+}
+//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+Error_manager CTcpLaser::stop_scan()
+{
+	char sendMsg[] = "$SLSSTP*1B\r\n";
+	std::lock_guard<std::mutex> lk(m_mutex);
+	if (Send(sendMsg, strlen(sendMsg)))
+		return Error_code::SUCCESS;
+	return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+						" error ");
+}
+//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+Error_manager CTcpLaser::end_task()
+{
+
+}
+
+
+Buf_type CTcpLaser::transform_buf_to_points(Binary_buf* pData, std::vector<CPoint3D>& points)
+{
+	////ƴ���ϴ�δ�������
+
+	Buf_type type = BUF_UNKNOW;
+	Binary_buf frame;
+
+	if (m_last_data.get_length() > 0)
+	{
+		if (pData)
+			frame = m_last_data + (*pData);
+		else
+			frame = m_last_data;
+		m_last_data = Binary_buf();
+	}
+	else if (pData)
+	{
+		frame = (*pData);
+	}
+	else
+	{
+		return type;
+	}
+
+	int head = FindHead(frame.get_buf(), frame.get_length());
+	int tail = FindTail(frame.get_buf(), frame.get_length());
+
+	if (tail >= 0)
+	{
+		if (tail < frame.get_length() - 1)		//���������
+		{
+			m_last_data = Binary_buf(frame.get_buf() + tail + 1, frame.get_length() - tail - 1);
+		}
+		if (head >= 0 && head < tail)
+		{
+			////���
+			Binary_buf data(frame.get_buf() + head, tail - head + 1);
+			if (data.is_equal_front("$SLSSTP") )
+				type = BUF_STOP;
+			else if (data.is_equal_front( "$SLSSTA"))
+				type = BUF_START;
+			else if (data.is_equal_front( "$SCLRDY"))
+				type = BUF_READY;
+			else if (data.is_equal_front( "$SHWERR"))
+				type = BUF_ERROR;
+			else if (data.is_equal_front( "$N"))
+				type = BUF_DATA;
+
+			if (type == BUF_DATA)
+			{
+				////��������
+				points.clear();
+				if (data.get_length() <= 29)
+					return type;
+
+				////����
+				unsigned char angle_1 = 0;
+				unsigned char angle_2 = 0;
+				memcpy(&angle_1, (data.get_buf())+26, 1);
+				memcpy(&angle_2, (data.get_buf())+27, 1);
+				float beta_a = float(angle_1 * 256 + angle_2)*0.01;
+				float start_angle = 0.0;
+				float freq = 0.0;
+
+				std::vector<float> distance;
+				if (GetData(&data, distance, freq, start_angle))
+				{
+					float beta = (beta_a)*DEGREES;
+					float sin_beta = sin(beta);
+					float cos_beta = cos(beta);
+					for (int i = 0; i < distance.size(); ++i)
+					{
+						if (distance[i] < 0.001)
+							continue;
+
+						float alpha = (start_angle + i*freq - 90.0) * DEGREES;
+						float sin_alpha = sin(alpha);
+						float cos_alpha = cos(alpha);
+
+						float x = distance[i] * sin_alpha;
+						float y = distance[i] * cos_alpha * sin_beta;
+						float z = distance[i] * cos_alpha * cos_beta;
+
+						points.push_back(CPoint3D(x, y, z));
+					}
+					//points.push_back(CPoint3D(double(distance.size()), start_angle, freq));
+				}
+
+			}
+		}
+	}
+	else if (head >= 0)
+	{
+		m_last_data = Binary_buf(frame.get_buf() + head, frame.get_length() - head);
+	}
+
+	return type;
+}
+
+bool CTcpLaser::receive_buf_to_queue(Binary_buf& data)
+{
+	char buf[4096] = { 0 };
+	int bytesRead = Recv(buf, 4096);
+	if (bytesRead > 0)
+	{
+		Binary_buf bin_data(buf, bytesRead);
+		data = bin_data;
+		m_last_data_time = clock();
+		return true;
+	}
+	return false;
+}
+
+int CTcpLaser::FindHead(char* buf, int b_len)
+{
+	int i = 0;
+	if (b_len < 2)
+		return 0;
+	for (i = 0; i <= b_len; i++)
+	{
+		if (b_len > 10)
+		{
+			if (buf[i] == '$'&& buf[i + 1] == 'N' && buf[i + 7] == 'S'
+				&&buf[i + 8] == '5'&&buf[i + 9] == '1'&&buf[i + 10] == '1')
+				return i;
+		}
+		if (b_len > 7)
+		{
+			if (buf[i] == '$'&& buf[i + 1] == 'S'&&buf[i + 7] == '*')
+				return i;
+		}
+	}
+	return -1;
+}
+
+int CTcpLaser::FindTail(char* buf, int b_len)
+{
+	int i = 0;
+
+	for (i = 0; i <= b_len; i++)
+	{
+		if (b_len >= i + 5)
+		{
+			if (buf[i] == '*' && buf[i + 3] == '\r'&&buf[i + 4] == '\n')
+				return i + 4;
+		}
+	}
+	return -9999999;
+}
+
+bool CTcpLaser::Send(const char* sendbuf, int len)
+{
+	int ret = 0;
+	do
+	{
+        ret = send(m_socket, sendbuf, strlen(sendbuf), 0);
+	} while (ret < 0);
+	return ret == len;
+}
+int CTcpLaser::Recv(char* recvbuf, int len)
+{
+	struct sockaddr_in sddr_from;
+	int ret = 0;
+	do
+	{
+        ret = recv(m_socket, recvbuf, 4096, 0);
+	} while (ret < 0);
+	return ret;
+}
+
+bool CTcpLaser::GetData(Binary_buf* pData, std::vector<float>& distance,
+	float& freq, float& start_angle)
+{
+	struct stData
+	{
+		const char* data;
+		int length;
+	};
+	std::vector<struct stData> strDatas;
+	int start = 0;
+	int end = 0;
+	int LMDscandata_index = -1;
+	for (int i = 0; i < pData->get_length(); ++i)
+	{
+		if ((*pData)[i] == ' ')
+		{
+			end = i;
+			if (end > start)
+			{
+				struct stData strData;
+//				strData.data = (*pData + start);
+				strData.data = (pData->get_buf() + start);
+				strData.length = end - start;
+
+				strDatas.push_back(strData);
+				if (strncmp(strData.data, "LMDscandata", 11) == 0)
+					LMDscandata_index = strDatas.size() - 1;
+			}
+			end = i + 1;
+			start = end;
+		}
+	}
+
+	if (strDatas.size() > 26 + LMDscandata_index - 1)
+	{
+		struct stData start_angle_str = strDatas[23 + LMDscandata_index - 1];
+		long start_angle_l = Str0x2Long(start_angle_str.data, start_angle_str.length);
+		start_angle = float(start_angle_l)*0.01;
+
+		struct stData freq_str = strDatas[24 + LMDscandata_index - 1];
+		long freq_l = Str0x2Long(freq_str.data, freq_str.length);
+		freq = float(freq_l)*0.0001;
+
+		struct stData count_str = strDatas[25 + LMDscandata_index - 1];
+		long count = Str0x2Long(count_str.data, count_str.length);
+		if (strDatas.size() >= 26 + LMDscandata_index - 1 + count)
+		{
+			for (int i = 26 + LMDscandata_index - 1; i < 26 + LMDscandata_index - 1 + count; ++i)
+			{
+				float dis = float(Str0x2Long(strDatas[i].data, strDatas[i].length));
+				distance.push_back(dis);
+			}
+			return true;
+		}
+	}
+	return false;
+}
+long CTcpLaser::Str0x2Long(const char* data, int len)
+{
+	long sum = 0;
+	for (int i = 0; i < len; ++i)
+	{
+		char c = data[i];
+		int n = 0;
+		if (c >= 48 && c <= 57)
+			n = c - 48;
+		else if (c >= 65 && c <= 70)
+			n = c - 65 + 10;
+		sum += n*pow(16, len - i - 1);
+	}
+	return sum;
+}

+ 68 - 0
laser/TcpLaser.h

@@ -0,0 +1,68 @@
+/*************************
+sick 511 �״� tcpЭ�����ӿ��ư�
+*************************/
+
+#pragma once
+#include "Laser.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <mutex>
+
+#define LASER_DATA_TIME_OUT		10000
+
+class CTcpLaser :
+	public Laser_base
+{
+public:
+	CTcpLaser(int id, Laser_proto::laser_parameter laser_param);
+	~CTcpLaser();
+
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
+	//对外的接口函数,负责接受并处理任务单,
+	//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+	//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
+
+protected:
+	//接受二进制消息的功能函数,每次只接受一个CBinaryData
+	// 纯虚函数,必须由子类重载,
+	virtual bool receive_buf_to_queue(Binary_buf& data);
+	//将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
+	// 纯虚函数,必须由子类重载,
+	virtual Buf_type transform_buf_to_points(Binary_buf* pData, std::vector<CPoint3D>& points);
+
+
+private:
+	bool	Send(const char* sendbuf, int len);                          // ����ָ��
+	int		Recv(char* recvbuf, int len);                           // ��������
+	static int FindHead(char* buf, int b_len);
+	static int FindTail(char* buf, int b_len);
+private:
+	bool GetData(Binary_buf* pData, std::vector<float>& distance,
+		float& freq, float& start_angle);
+	long Str0x2Long(const char* data, int len);
+
+private:
+#pragma region udp��ر���
+	int				m_socket;
+    //WSADATA			m_wsd;
+	struct sockaddr_in m_send_addr;	
+	std::mutex		m_mutex;
+	clock_t			m_last_data_time;
+#pragma endregion
+
+};
+

+ 352 - 0
laser/UdpLaser.cpp

@@ -0,0 +1,352 @@
+
+#include "UdpLaser.h"
+#include <stdlib.h>
+#include <unistd.h>
+
+RegisterLaser(Udp);
+CUdpLaser::CUdpLaser(int id, Laser_proto::laser_parameter laser_param)
+	:Laser_base(id,laser_param)
+{
+}
+
+
+CUdpLaser::~CUdpLaser()
+{
+}
+
+
+
+//雷达链接设备,为3个线程添加线程执行函数。
+Error_manager CUdpLaser::connect_laser()
+{
+	std::string ip = m_laser_param.laser_ip();
+	int			port = m_laser_param.laser_port();
+	int			remoteport = m_laser_param.laser_port_remote();
+	if (ip == "" || port < 0)
+		return Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR,
+							" m_laser_param PARAMRTER_ERROR ");
+
+	//��ʼ��Socket
+	//WSAStartup(MAKEWORD(1, 1), &m_wsd);
+	//����Socket����
+	m_socket = socket(AF_INET, SOCK_DGRAM, 0);
+	if (m_socket <= 0)
+		return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+							" m_socket PARAMRTER_ERROR ");
+
+	struct sockaddr_in sddr_udp;
+	sddr_udp.sin_family = AF_INET;
+	sddr_udp.sin_addr.s_addr = htons(INADDR_ANY);
+	sddr_udp.sin_port = htons(port);
+
+	m_send_addr.sin_family = AF_INET;
+	m_send_addr.sin_addr.s_addr = inet_addr(ip.c_str());
+	m_send_addr.sin_port = htons(remoteport);
+
+	if(-1==bind(m_socket, (struct sockaddr *)&sddr_udp, sizeof(struct sockaddr)))
+		return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+							" bind m_socket  ERROR ");
+
+	return Laser_base::connect_laser();
+}
+//雷达断开链接,释放3个线程
+Error_manager CUdpLaser::disconnect_laser()
+{
+	if (m_socket > 0)
+	{
+
+		close(m_socket);
+		//WSACleanup();
+		m_socket = -1;
+	}
+	return Laser_base::disconnect_laser();
+}
+//对外的接口函数,负责接受并处理任务单,
+//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+Error_manager CUdpLaser::execute_task(Task_Base* p_laser_task)
+{
+
+}
+//检查雷达状态,是否正常运行
+Error_manager CUdpLaser::check_laser()
+{
+
+}
+//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+Error_manager CUdpLaser::start_scan()
+{
+	std::lock_guard<std::mutex> lk(m_mutex);
+	if (!this->is_ready())
+		return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+							"is_ready error ");
+
+	const char* sendMsg = (char*)"$SLSSTA*0A\r\n";
+	if (Send(sendMsg, strlen(sendMsg)))
+	{
+		m_laser_statu = LASER_BUSY;
+
+		return Laser_base::start_scan();
+	}
+	return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+						" Send error ");
+}
+//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+Error_manager CUdpLaser::stop_scan()
+{
+	const char sendMsg[] = "$SLSSTP*1B\r\n";
+	std::lock_guard<std::mutex> lk(m_mutex);
+	if (Send(sendMsg, strlen(sendMsg)))
+		return Error_code::SUCCESS;
+	return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+						" Send error ");
+}
+//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+Error_manager CUdpLaser::end_task()
+{
+
+}
+
+
+Buf_type CUdpLaser::transform_buf_to_points(Binary_buf* pData, std::vector<CPoint3D>& points)
+{
+	////ƴ���ϴ�δ�������
+
+	Buf_type type = BUF_UNKNOW;
+	Binary_buf frame;
+
+	if (m_last_data.get_length() > 0)
+	{
+		if (pData)
+			frame = m_last_data + (*pData);
+		else
+			frame = m_last_data;
+		m_last_data = Binary_buf();
+	}
+	else if (pData)
+	{
+		frame = (*pData);
+	}
+	else
+	{
+		return type;
+	}
+
+	int head = FindHead(frame.get_buf(), frame.get_length());
+	int tail = FindTail(frame.get_buf(), frame.get_length());
+	if (tail >= 0)
+	{
+		if (tail < frame.get_length() - 1)		//���������
+		{
+			m_last_data = Binary_buf(frame.get_buf() + tail + 1, frame.get_length() - tail - 1);
+		}
+		if (head >= 0 && head < tail)
+		{
+			////���
+			Binary_buf data(frame.get_buf() + head, tail - head + 1);
+			if (data.is_equal_front( "$SLSSTP"))
+				type = BUF_STOP;
+			else if (data.is_equal_front( "$SLSSTA"))
+				type = BUF_START;
+			else if (data.is_equal_front( "$SCLRDY"))
+				type = BUF_READY;
+			else if (data.is_equal_front( "$SHWERR"))
+				type = BUF_ERROR;
+			else if (data.is_equal_front( "$N"))
+				type = BUF_DATA;
+
+			if (type == BUF_DATA)
+			{
+				////��������
+				points.clear();
+				if (data.get_length() <= 29)
+					return type;
+
+				////����
+				unsigned char angle_1 = 0;
+				unsigned char angle_2 = 0;
+				memcpy(&angle_1, (data.get_buf())+26, 1);
+				memcpy(&angle_2, (data.get_buf())+27, 1);
+				float beta_a = float(angle_1 * 256 + angle_2)*0.01;
+				float start_angle = 0.0;
+				float freq = 0.0;
+
+				std::vector<float> distance;
+				if (GetData(&data, distance, freq, start_angle))
+				{
+					
+					float beta = (beta_a)*DEGREES;
+					float sin_beta = sin(beta);
+					float cos_beta = cos(beta);
+					for (int i = 0; i < distance.size(); ++i)
+					{
+						if (distance[i] < 0.001)
+							continue;
+
+						float alpha = (start_angle + i*freq - 90.0) * DEGREES;
+						float sin_alpha = sin(alpha);
+						float cos_alpha = cos(alpha);
+
+						float x = distance[i] * sin_alpha;
+						float y = distance[i] * cos_alpha * sin_beta;
+						float z = distance[i] * cos_alpha * cos_beta;
+
+						points.push_back(CPoint3D(x, y, z));
+					}
+					//points.push_back(CPoint3D(double(distance.size()), start_angle, freq));
+				}
+
+			}
+		}
+	}
+	else if (head >= 0)
+	{
+		m_last_data = Binary_buf(frame.get_buf() + head, frame.get_length() - head);
+	}
+	
+	return type;
+}
+
+bool CUdpLaser::receive_buf_to_queue(Binary_buf& data)
+{
+	char buf[4096 * 10] = { 0 };
+    int bytesRead = Recv(buf, 4096);
+	if (bytesRead > 0)
+	{
+		Binary_buf bin_data(buf, bytesRead);
+		data = bin_data;
+		return true;
+	}
+	return false;
+}
+
+int CUdpLaser::FindHead(char* buf, int b_len)
+{
+	int i = 0;
+	if (b_len < 2)
+		return 0;
+	for (i = 0; i <= b_len; i++)
+	{
+		if (b_len > 10)
+		{
+			if (buf[i] == '$'&& buf[i + 1] == 'N' && buf[i + 7] == 'S'
+				&&buf[i + 8] == '5'&&buf[i + 9] == '1'&&buf[i + 10] == '1')
+				return i;
+		}
+		if (b_len >7)
+		{
+			if (buf[i] == '$'&& buf[i + 1] == 'S'&&buf[i + 7]=='*')
+				return i;
+		}
+	}
+	return -1;
+}
+
+int CUdpLaser::FindTail(char* buf, int b_len)
+{
+	int i = 0;
+	
+	for (i = 0; i <= b_len; i++)
+	{
+		if (b_len >=i+ 5)
+		{
+			if (buf[i] == '*' && buf[i + 3] == '\r'&&buf[i + 4] == '\n')
+				return i+4;
+		}
+	}
+	return -9999999;
+}
+
+bool CUdpLaser::Send(const char* sendbuf, int len)
+{
+	int ret = 0;
+	do 
+	{
+        ret = sendto(m_socket, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&m_send_addr, sizeof(struct sockaddr));
+	} while (ret < 0);
+	return ret == len;
+}
+int CUdpLaser::Recv(char* recvbuf, int len)
+{
+	struct sockaddr_in sddr_from;
+    socklen_t clientLen = sizeof(sddr_from);
+	int ret = 0;
+	do
+	{
+        ret = recvfrom(m_socket, recvbuf, 4096, 0, (struct sockaddr*)&sddr_from, &clientLen);
+	} while (ret < 0);
+	return ret;
+}
+
+bool CUdpLaser::GetData(Binary_buf* pData, std::vector<float>& distance,
+	float& freq, float& start_angle)
+{
+	struct stData
+	{
+		const char* data;
+		int length;
+	};
+	std::vector<struct stData> strDatas;
+	int start = 0;
+	int end = 0;
+	int LMDscandata_index = -1;
+	for (int i = 0; i < pData->get_length(); ++i)
+	{
+		if ((*pData)[i] == ' ')
+		{
+			end = i;
+			if (end > start)
+			{
+				struct stData strData;
+//				strData.data = (*pData + start);
+				strData.data = (pData->get_buf() + start);
+				strData.length = end - start;
+				
+				strDatas.push_back(strData);
+				if (strncmp(strData.data, "LMDscandata", 11) == 0)
+					LMDscandata_index = strDatas.size() - 1;
+			}
+			end = i + 1;
+			start = end;
+		}
+	}
+
+	if (strDatas.size() > 26 + LMDscandata_index - 1)
+	{
+		struct stData start_angle_str = strDatas[23 + LMDscandata_index - 1];
+		long start_angle_l = Str0x2Long(start_angle_str.data, start_angle_str.length);
+		start_angle = float(start_angle_l)*0.01;
+
+		struct stData freq_str = strDatas[24 + LMDscandata_index - 1];
+		long freq_l = Str0x2Long(freq_str.data, freq_str.length);
+		freq = float(freq_l)*0.0001;
+
+		struct stData count_str = strDatas[25 + LMDscandata_index - 1];
+		long count = Str0x2Long(count_str.data, count_str.length);
+		if (strDatas.size() >= 26 + LMDscandata_index - 1 + count)
+		{
+			for (int i = 26 + LMDscandata_index - 1; i < 26 + LMDscandata_index - 1 + count; ++i)
+			{
+				float dis = float(Str0x2Long(strDatas[i].data, strDatas[i].length));
+				distance.push_back(dis);
+			}
+			return true;
+		}
+	}
+	return false;
+}
+long CUdpLaser::Str0x2Long(const char* data, int len)
+{
+	long sum = 0;
+	for (int i = 0; i < len; ++i)
+	{
+		char c = data[i];
+		int n = 0;
+		if (c >= 48 && c <= 57)
+			n = c - 48;
+		else if (c >= 65 && c <= 70)
+			n = c - 65 + 10;
+		sum += n*pow(16, len - i - 1);
+	}
+	return sum;
+}

+ 61 - 0
laser/UdpLaser.h

@@ -0,0 +1,61 @@
+/*************************
+sick 511 �״� updЭ�����ӿ��ư�
+*************************/
+#pragma once
+#include "Laser.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <mutex>
+class CUdpLaser : public Laser_base
+{
+public:
+	CUdpLaser(int id, Laser_proto::laser_parameter laser_param);
+	virtual ~CUdpLaser();
+
+	//雷达链接设备,为3个线程添加线程执行函数。
+	virtual Error_manager connect_laser();
+	//雷达断开链接,释放3个线程
+	virtual Error_manager disconnect_laser();
+	//对外的接口函数,负责接受并处理任务单,
+	//input:p_laser_task 雷达任务单,基类的指针,指向子类的实例,(多态)
+	//注:这个函数为虚函数,实际的处理任务的代码由子类重载并实现。
+	virtual Error_manager execute_task(Task_Base* p_laser_task);
+	//检查雷达状态,是否正常运行
+	virtual Error_manager check_laser();
+	//雷达的启动接口函数, 让雷达进行扫描,一般需要子类重载,不同的雷达开始方式不同。
+	virtual Error_manager start_scan();
+	//雷达的停止接口函数, 让雷达停止扫描,一般需要子类重载,不同的雷达结束方式不同。
+	virtual Error_manager stop_scan();
+	//结束任务单,stop之后,要检查线程状态和数据结果,然后才能 end_task
+	virtual Error_manager end_task();
+
+protected:
+	//接受二进制消息的功能函数,每次只接受一个CBinaryData
+	// 纯虚函数,必须由子类重载,
+	virtual bool receive_buf_to_queue(Binary_buf& data);
+	//将二进制消息转化为三维点云的功能函数,每次只转化一个CBinaryData,
+	// 纯虚函数,必须由子类重载,
+	virtual Buf_type transform_buf_to_points(Binary_buf* pData, std::vector<CPoint3D>& points);
+	
+
+private:
+	bool Send(const char* sendbuf, int len);                          // ����ָ��
+	int Recv(char* recvbuf, int len);                           // ��������
+	static int FindHead(char* buf, int b_len);
+	static int FindTail(char* buf, int b_len);
+private:
+	bool GetData(Binary_buf* pData, std::vector<float>& distance,
+		float& freq, float& start_angle);
+	long Str0x2Long(const char* data, int len);
+
+protected:
+#pragma region udp��ر���
+	int				m_socket;
+//	WSADATA			m_wsd;
+	struct sockaddr_in m_send_addr;
+	std::mutex		m_mutex;
+#pragma endregion
+};
+

+ 65 - 140
laser/laser_parameter.pb.cc

@@ -109,11 +109,11 @@ const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUT
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Laser_proto::laser_parameter, sn_),
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Laser_proto::laser_parameter, frame_num_),
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Laser_proto::laser_parameter, type_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Laser_proto::laser_parameter, is_save_banary_),
-  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Laser_proto::laser_parameter, is_save_txt_),
   0,
   3,
   4,
+  13,
+  14,
   15,
   16,
   17,
@@ -124,8 +124,6 @@ const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUT
   22,
   23,
   24,
-  25,
-  26,
   5,
   6,
   7,
@@ -133,12 +131,10 @@ const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUT
   9,
   10,
   11,
-  13,
+  12,
   1,
-  27,
+  25,
   2,
-  12,
-  14,
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Laser_proto::Laser_parameter_all, _has_bits_),
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Laser_proto::Laser_parameter_all, _internal_metadata_),
   ~0u,  // no _extensions_
@@ -148,8 +144,8 @@ const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUT
   ~0u,
 };
 static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
-  { 0, 33, sizeof(::Laser_proto::laser_parameter)},
-  { 61, 67, sizeof(::Laser_proto::Laser_parameter_all)},
+  { 0, 31, sizeof(::Laser_proto::laser_parameter)},
+  { 57, 63, sizeof(::Laser_proto::Laser_parameter_all)},
 };
 
 static ::google::protobuf::Message const * const file_default_instances[] = {
@@ -179,7 +175,7 @@ void protobuf_RegisterTypes(const ::std::string&) {
 void AddDescriptorsImpl() {
   InitDefaults();
   static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
-      "\n\025laser_parameter.proto\022\013Laser_proto\"\360\004\n"
+      "\n\025laser_parameter.proto\022\013Laser_proto\"\266\004\n"
       "\017laser_parameter\022\020\n\010laser_ip\030\001 \001(\t\022\022\n\nla"
       "ser_port\030\002 \001(\003\022\031\n\021laser_port_remote\030\003 \001("
       "\003\022\022\n\007mat_r00\030\004 \001(\001:\0011\022\022\n\007mat_r01\030\005 \001(\001:\001"
@@ -194,13 +190,12 @@ void AddDescriptorsImpl() {
       "nslation_z\030\025 \001(\001\022\030\n\rinstall_angle\030\026 \001(\001:"
       "\0010\022\034\n\016scan_direction\030\027 \001(\010:\004true\022\n\n\002sn\030\030"
       " \001(\t\022\027\n\tframe_num\030\031 \001(\003:\0043000\022\016\n\004type\030\032 "
-      "\001(\t:\000\022\035\n\016is_save_banary\030\033 \001(\010:\005false\022\031\n\013"
-      "is_save_txt\030\034 \001(\010:\004true\"M\n\023Laser_paramet"
-      "er_all\0226\n\020laser_parameters\030\001 \003(\0132\034.Laser"
-      "_proto.laser_parameter"
+      "\001(\t:\000\"M\n\023Laser_parameter_all\0226\n\020laser_pa"
+      "rameters\030\001 \003(\0132\034.Laser_proto.laser_param"
+      "eter"
   };
   ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
-      descriptor, 742);
+      descriptor, 684);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "laser_parameter.proto", &protobuf_RegisterTypes);
 }
@@ -249,8 +244,6 @@ const int laser_parameter::kScanDirectionFieldNumber;
 const int laser_parameter::kSnFieldNumber;
 const int laser_parameter::kFrameNumFieldNumber;
 const int laser_parameter::kTypeFieldNumber;
-const int laser_parameter::kIsSaveBanaryFieldNumber;
-const int laser_parameter::kIsSaveTxtFieldNumber;
 #endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 laser_parameter::laser_parameter()
@@ -291,10 +284,9 @@ void laser_parameter::SharedCtor() {
   sn_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(&laser_port_, 0, static_cast<size_t>(
-      reinterpret_cast<char*>(&is_save_banary_) -
-      reinterpret_cast<char*>(&laser_port_)) + sizeof(is_save_banary_));
+      reinterpret_cast<char*>(&install_angle_) -
+      reinterpret_cast<char*>(&laser_port_)) + sizeof(install_angle_));
   scan_direction_ = true;
-  is_save_txt_ = true;
   mat_r00_ = 1;
   mat_r01_ = 1;
   mat_r02_ = 1;
@@ -372,25 +364,24 @@ void laser_parameter::Clear() {
   }
   if (cached_has_bits & 65280u) {
     ::memset(&translation_x_, 0, static_cast<size_t>(
-        reinterpret_cast<char*>(&is_save_banary_) -
-        reinterpret_cast<char*>(&translation_x_)) + sizeof(is_save_banary_));
+        reinterpret_cast<char*>(&install_angle_) -
+        reinterpret_cast<char*>(&translation_x_)) + sizeof(install_angle_));
     scan_direction_ = true;
-    is_save_txt_ = true;
     mat_r00_ = 1;
-  }
-  if (cached_has_bits & 16711680u) {
     mat_r01_ = 1;
     mat_r02_ = 1;
+  }
+  if (cached_has_bits & 16711680u) {
     mat_r03_ = 1;
     mat_r10_ = 1;
     mat_r11_ = 1;
     mat_r12_ = 1;
     mat_r13_ = 1;
     mat_r20_ = 1;
-  }
-  if (cached_has_bits & 251658240u) {
     mat_r21_ = 1;
     mat_r22_ = 1;
+  }
+  if (cached_has_bits & 50331648u) {
     mat_r23_ = 1;
     frame_num_ = GOOGLE_LONGLONG(3000);
   }
@@ -778,34 +769,6 @@ bool laser_parameter::MergePartialFromCodedStream(
         break;
       }
 
-      // optional bool is_save_banary = 27 [default = false];
-      case 27: {
-        if (static_cast< ::google::protobuf::uint8>(tag) ==
-            static_cast< ::google::protobuf::uint8>(216u /* 216 & 0xFF */)) {
-          set_has_is_save_banary();
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
-                 input, &is_save_banary_)));
-        } else {
-          goto handle_unusual;
-        }
-        break;
-      }
-
-      // optional bool is_save_txt = 28 [default = true];
-      case 28: {
-        if (static_cast< ::google::protobuf::uint8>(tag) ==
-            static_cast< ::google::protobuf::uint8>(224u /* 224 & 0xFF */)) {
-          set_has_is_save_txt();
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
-                 input, &is_save_txt_)));
-        } else {
-          goto handle_unusual;
-        }
-        break;
-      }
-
       default: {
       handle_unusual:
         if (tag == 0) {
@@ -854,62 +817,62 @@ void laser_parameter::SerializeWithCachedSizes(
   }
 
   // optional double mat_r00 = 4 [default = 1];
-  if (cached_has_bits & 0x00008000u) {
+  if (cached_has_bits & 0x00002000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(4, this->mat_r00(), output);
   }
 
   // optional double mat_r01 = 5 [default = 1];
-  if (cached_has_bits & 0x00010000u) {
+  if (cached_has_bits & 0x00004000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(5, this->mat_r01(), output);
   }
 
   // optional double mat_r02 = 6 [default = 1];
-  if (cached_has_bits & 0x00020000u) {
+  if (cached_has_bits & 0x00008000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(6, this->mat_r02(), output);
   }
 
   // optional double mat_r03 = 7 [default = 1];
-  if (cached_has_bits & 0x00040000u) {
+  if (cached_has_bits & 0x00010000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(7, this->mat_r03(), output);
   }
 
   // optional double mat_r10 = 8 [default = 1];
-  if (cached_has_bits & 0x00080000u) {
+  if (cached_has_bits & 0x00020000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(8, this->mat_r10(), output);
   }
 
   // optional double mat_r11 = 9 [default = 1];
-  if (cached_has_bits & 0x00100000u) {
+  if (cached_has_bits & 0x00040000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(9, this->mat_r11(), output);
   }
 
   // optional double mat_r12 = 10 [default = 1];
-  if (cached_has_bits & 0x00200000u) {
+  if (cached_has_bits & 0x00080000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(10, this->mat_r12(), output);
   }
 
   // optional double mat_r13 = 11 [default = 1];
-  if (cached_has_bits & 0x00400000u) {
+  if (cached_has_bits & 0x00100000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(11, this->mat_r13(), output);
   }
 
   // optional double mat_r20 = 12 [default = 1];
-  if (cached_has_bits & 0x00800000u) {
+  if (cached_has_bits & 0x00200000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(12, this->mat_r20(), output);
   }
 
   // optional double mat_r21 = 13 [default = 1];
-  if (cached_has_bits & 0x01000000u) {
+  if (cached_has_bits & 0x00400000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(13, this->mat_r21(), output);
   }
 
   // optional double mat_r22 = 14 [default = 1];
-  if (cached_has_bits & 0x02000000u) {
+  if (cached_has_bits & 0x00800000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(14, this->mat_r22(), output);
   }
 
   // optional double mat_r23 = 15 [default = 1];
-  if (cached_has_bits & 0x04000000u) {
+  if (cached_has_bits & 0x01000000u) {
     ::google::protobuf::internal::WireFormatLite::WriteDouble(15, this->mat_r23(), output);
   }
 
@@ -949,7 +912,7 @@ void laser_parameter::SerializeWithCachedSizes(
   }
 
   // optional bool scan_direction = 23 [default = true];
-  if (cached_has_bits & 0x00002000u) {
+  if (cached_has_bits & 0x00001000u) {
     ::google::protobuf::internal::WireFormatLite::WriteBool(23, this->scan_direction(), output);
   }
 
@@ -964,7 +927,7 @@ void laser_parameter::SerializeWithCachedSizes(
   }
 
   // optional int64 frame_num = 25 [default = 3000];
-  if (cached_has_bits & 0x08000000u) {
+  if (cached_has_bits & 0x02000000u) {
     ::google::protobuf::internal::WireFormatLite::WriteInt64(25, this->frame_num(), output);
   }
 
@@ -978,16 +941,6 @@ void laser_parameter::SerializeWithCachedSizes(
       26, this->type(), output);
   }
 
-  // optional bool is_save_banary = 27 [default = false];
-  if (cached_has_bits & 0x00001000u) {
-    ::google::protobuf::internal::WireFormatLite::WriteBool(27, this->is_save_banary(), output);
-  }
-
-  // optional bool is_save_txt = 28 [default = true];
-  if (cached_has_bits & 0x00004000u) {
-    ::google::protobuf::internal::WireFormatLite::WriteBool(28, this->is_save_txt(), output);
-  }
-
   if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         _internal_metadata_.unknown_fields(), output);
@@ -1025,62 +978,62 @@ void laser_parameter::SerializeWithCachedSizes(
   }
 
   // optional double mat_r00 = 4 [default = 1];
-  if (cached_has_bits & 0x00008000u) {
+  if (cached_has_bits & 0x00002000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(4, this->mat_r00(), target);
   }
 
   // optional double mat_r01 = 5 [default = 1];
-  if (cached_has_bits & 0x00010000u) {
+  if (cached_has_bits & 0x00004000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(5, this->mat_r01(), target);
   }
 
   // optional double mat_r02 = 6 [default = 1];
-  if (cached_has_bits & 0x00020000u) {
+  if (cached_has_bits & 0x00008000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(6, this->mat_r02(), target);
   }
 
   // optional double mat_r03 = 7 [default = 1];
-  if (cached_has_bits & 0x00040000u) {
+  if (cached_has_bits & 0x00010000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(7, this->mat_r03(), target);
   }
 
   // optional double mat_r10 = 8 [default = 1];
-  if (cached_has_bits & 0x00080000u) {
+  if (cached_has_bits & 0x00020000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(8, this->mat_r10(), target);
   }
 
   // optional double mat_r11 = 9 [default = 1];
-  if (cached_has_bits & 0x00100000u) {
+  if (cached_has_bits & 0x00040000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(9, this->mat_r11(), target);
   }
 
   // optional double mat_r12 = 10 [default = 1];
-  if (cached_has_bits & 0x00200000u) {
+  if (cached_has_bits & 0x00080000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(10, this->mat_r12(), target);
   }
 
   // optional double mat_r13 = 11 [default = 1];
-  if (cached_has_bits & 0x00400000u) {
+  if (cached_has_bits & 0x00100000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(11, this->mat_r13(), target);
   }
 
   // optional double mat_r20 = 12 [default = 1];
-  if (cached_has_bits & 0x00800000u) {
+  if (cached_has_bits & 0x00200000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(12, this->mat_r20(), target);
   }
 
   // optional double mat_r21 = 13 [default = 1];
-  if (cached_has_bits & 0x01000000u) {
+  if (cached_has_bits & 0x00400000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(13, this->mat_r21(), target);
   }
 
   // optional double mat_r22 = 14 [default = 1];
-  if (cached_has_bits & 0x02000000u) {
+  if (cached_has_bits & 0x00800000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(14, this->mat_r22(), target);
   }
 
   // optional double mat_r23 = 15 [default = 1];
-  if (cached_has_bits & 0x04000000u) {
+  if (cached_has_bits & 0x01000000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(15, this->mat_r23(), target);
   }
 
@@ -1120,7 +1073,7 @@ void laser_parameter::SerializeWithCachedSizes(
   }
 
   // optional bool scan_direction = 23 [default = true];
-  if (cached_has_bits & 0x00002000u) {
+  if (cached_has_bits & 0x00001000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(23, this->scan_direction(), target);
   }
 
@@ -1136,7 +1089,7 @@ void laser_parameter::SerializeWithCachedSizes(
   }
 
   // optional int64 frame_num = 25 [default = 3000];
-  if (cached_has_bits & 0x08000000u) {
+  if (cached_has_bits & 0x02000000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(25, this->frame_num(), target);
   }
 
@@ -1151,16 +1104,6 @@ void laser_parameter::SerializeWithCachedSizes(
         26, this->type(), target);
   }
 
-  // optional bool is_save_banary = 27 [default = false];
-  if (cached_has_bits & 0x00001000u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(27, this->is_save_banary(), target);
-  }
-
-  // optional bool is_save_txt = 28 [default = true];
-  if (cached_has_bits & 0x00004000u) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(28, this->is_save_txt(), target);
-  }
-
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields(), target);
@@ -1251,28 +1194,16 @@ size_t laser_parameter::ByteSizeLong() const {
       total_size += 2 + 8;
     }
 
-    // optional bool is_save_banary = 27 [default = false];
-    if (has_is_save_banary()) {
-      total_size += 2 + 1;
-    }
-
     // optional bool scan_direction = 23 [default = true];
     if (has_scan_direction()) {
       total_size += 2 + 1;
     }
 
-    // optional bool is_save_txt = 28 [default = true];
-    if (has_is_save_txt()) {
-      total_size += 2 + 1;
-    }
-
     // optional double mat_r00 = 4 [default = 1];
     if (has_mat_r00()) {
       total_size += 1 + 8;
     }
 
-  }
-  if (_has_bits_[16 / 32] & 16711680u) {
     // optional double mat_r01 = 5 [default = 1];
     if (has_mat_r01()) {
       total_size += 1 + 8;
@@ -1283,6 +1214,8 @@ size_t laser_parameter::ByteSizeLong() const {
       total_size += 1 + 8;
     }
 
+  }
+  if (_has_bits_[16 / 32] & 16711680u) {
     // optional double mat_r03 = 7 [default = 1];
     if (has_mat_r03()) {
       total_size += 1 + 8;
@@ -1313,8 +1246,6 @@ size_t laser_parameter::ByteSizeLong() const {
       total_size += 1 + 8;
     }
 
-  }
-  if (_has_bits_[24 / 32] & 251658240u) {
     // optional double mat_r21 = 13 [default = 1];
     if (has_mat_r21()) {
       total_size += 1 + 8;
@@ -1325,6 +1256,8 @@ size_t laser_parameter::ByteSizeLong() const {
       total_size += 1 + 8;
     }
 
+  }
+  if (_has_bits_[24 / 32] & 50331648u) {
     // optional double mat_r23 = 15 [default = 1];
     if (has_mat_r23()) {
       total_size += 1 + 8;
@@ -1412,57 +1345,51 @@ void laser_parameter::MergeFrom(const laser_parameter& from) {
       install_angle_ = from.install_angle_;
     }
     if (cached_has_bits & 0x00001000u) {
-      is_save_banary_ = from.is_save_banary_;
+      scan_direction_ = from.scan_direction_;
     }
     if (cached_has_bits & 0x00002000u) {
-      scan_direction_ = from.scan_direction_;
+      mat_r00_ = from.mat_r00_;
     }
     if (cached_has_bits & 0x00004000u) {
-      is_save_txt_ = from.is_save_txt_;
+      mat_r01_ = from.mat_r01_;
     }
     if (cached_has_bits & 0x00008000u) {
-      mat_r00_ = from.mat_r00_;
+      mat_r02_ = from.mat_r02_;
     }
     _has_bits_[0] |= cached_has_bits;
   }
   if (cached_has_bits & 16711680u) {
     if (cached_has_bits & 0x00010000u) {
-      mat_r01_ = from.mat_r01_;
+      mat_r03_ = from.mat_r03_;
     }
     if (cached_has_bits & 0x00020000u) {
-      mat_r02_ = from.mat_r02_;
+      mat_r10_ = from.mat_r10_;
     }
     if (cached_has_bits & 0x00040000u) {
-      mat_r03_ = from.mat_r03_;
+      mat_r11_ = from.mat_r11_;
     }
     if (cached_has_bits & 0x00080000u) {
-      mat_r10_ = from.mat_r10_;
+      mat_r12_ = from.mat_r12_;
     }
     if (cached_has_bits & 0x00100000u) {
-      mat_r11_ = from.mat_r11_;
+      mat_r13_ = from.mat_r13_;
     }
     if (cached_has_bits & 0x00200000u) {
-      mat_r12_ = from.mat_r12_;
+      mat_r20_ = from.mat_r20_;
     }
     if (cached_has_bits & 0x00400000u) {
-      mat_r13_ = from.mat_r13_;
+      mat_r21_ = from.mat_r21_;
     }
     if (cached_has_bits & 0x00800000u) {
-      mat_r20_ = from.mat_r20_;
+      mat_r22_ = from.mat_r22_;
     }
     _has_bits_[0] |= cached_has_bits;
   }
-  if (cached_has_bits & 251658240u) {
+  if (cached_has_bits & 50331648u) {
     if (cached_has_bits & 0x01000000u) {
-      mat_r21_ = from.mat_r21_;
-    }
-    if (cached_has_bits & 0x02000000u) {
-      mat_r22_ = from.mat_r22_;
-    }
-    if (cached_has_bits & 0x04000000u) {
       mat_r23_ = from.mat_r23_;
     }
-    if (cached_has_bits & 0x08000000u) {
+    if (cached_has_bits & 0x02000000u) {
       frame_num_ = from.frame_num_;
     }
     _has_bits_[0] |= cached_has_bits;
@@ -1505,9 +1432,7 @@ void laser_parameter::InternalSwap(laser_parameter* other) {
   swap(translation_y_, other->translation_y_);
   swap(translation_z_, other->translation_z_);
   swap(install_angle_, other->install_angle_);
-  swap(is_save_banary_, other->is_save_banary_);
   swap(scan_direction_, other->scan_direction_);
-  swap(is_save_txt_, other->is_save_txt_);
   swap(mat_r00_, other->mat_r00_);
   swap(mat_r01_, other->mat_r01_);
   swap(mat_r02_, other->mat_r02_);

+ 42 - 110
laser/laser_parameter.pb.h

@@ -260,13 +260,6 @@ class laser_parameter : public ::google::protobuf::Message /* @@protoc_insertion
   double install_angle() const;
   void set_install_angle(double value);
 
-  // optional bool is_save_banary = 27 [default = false];
-  bool has_is_save_banary() const;
-  void clear_is_save_banary();
-  static const int kIsSaveBanaryFieldNumber = 27;
-  bool is_save_banary() const;
-  void set_is_save_banary(bool value);
-
   // optional bool scan_direction = 23 [default = true];
   bool has_scan_direction() const;
   void clear_scan_direction();
@@ -274,13 +267,6 @@ class laser_parameter : public ::google::protobuf::Message /* @@protoc_insertion
   bool scan_direction() const;
   void set_scan_direction(bool value);
 
-  // optional bool is_save_txt = 28 [default = true];
-  bool has_is_save_txt() const;
-  void clear_is_save_txt();
-  static const int kIsSaveTxtFieldNumber = 28;
-  bool is_save_txt() const;
-  void set_is_save_txt(bool value);
-
   // optional double mat_r00 = 4 [default = 1];
   bool has_mat_r00() const;
   void clear_mat_r00();
@@ -426,10 +412,6 @@ class laser_parameter : public ::google::protobuf::Message /* @@protoc_insertion
   void clear_has_frame_num();
   void set_has_type();
   void clear_has_type();
-  void set_has_is_save_banary();
-  void clear_has_is_save_banary();
-  void set_has_is_save_txt();
-  void clear_has_is_save_txt();
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::internal::HasBits<1> _has_bits_;
@@ -446,9 +428,7 @@ class laser_parameter : public ::google::protobuf::Message /* @@protoc_insertion
   double translation_y_;
   double translation_z_;
   double install_angle_;
-  bool is_save_banary_;
   bool scan_direction_;
-  bool is_save_txt_;
   double mat_r00_;
   double mat_r01_;
   double mat_r02_;
@@ -702,13 +682,13 @@ inline void laser_parameter::set_laser_port_remote(::google::protobuf::int64 val
 
 // optional double mat_r00 = 4 [default = 1];
 inline bool laser_parameter::has_mat_r00() const {
-  return (_has_bits_[0] & 0x00008000u) != 0;
+  return (_has_bits_[0] & 0x00002000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r00() {
-  _has_bits_[0] |= 0x00008000u;
+  _has_bits_[0] |= 0x00002000u;
 }
 inline void laser_parameter::clear_has_mat_r00() {
-  _has_bits_[0] &= ~0x00008000u;
+  _has_bits_[0] &= ~0x00002000u;
 }
 inline void laser_parameter::clear_mat_r00() {
   mat_r00_ = 1;
@@ -726,13 +706,13 @@ inline void laser_parameter::set_mat_r00(double value) {
 
 // optional double mat_r01 = 5 [default = 1];
 inline bool laser_parameter::has_mat_r01() const {
-  return (_has_bits_[0] & 0x00010000u) != 0;
+  return (_has_bits_[0] & 0x00004000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r01() {
-  _has_bits_[0] |= 0x00010000u;
+  _has_bits_[0] |= 0x00004000u;
 }
 inline void laser_parameter::clear_has_mat_r01() {
-  _has_bits_[0] &= ~0x00010000u;
+  _has_bits_[0] &= ~0x00004000u;
 }
 inline void laser_parameter::clear_mat_r01() {
   mat_r01_ = 1;
@@ -750,13 +730,13 @@ inline void laser_parameter::set_mat_r01(double value) {
 
 // optional double mat_r02 = 6 [default = 1];
 inline bool laser_parameter::has_mat_r02() const {
-  return (_has_bits_[0] & 0x00020000u) != 0;
+  return (_has_bits_[0] & 0x00008000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r02() {
-  _has_bits_[0] |= 0x00020000u;
+  _has_bits_[0] |= 0x00008000u;
 }
 inline void laser_parameter::clear_has_mat_r02() {
-  _has_bits_[0] &= ~0x00020000u;
+  _has_bits_[0] &= ~0x00008000u;
 }
 inline void laser_parameter::clear_mat_r02() {
   mat_r02_ = 1;
@@ -774,13 +754,13 @@ inline void laser_parameter::set_mat_r02(double value) {
 
 // optional double mat_r03 = 7 [default = 1];
 inline bool laser_parameter::has_mat_r03() const {
-  return (_has_bits_[0] & 0x00040000u) != 0;
+  return (_has_bits_[0] & 0x00010000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r03() {
-  _has_bits_[0] |= 0x00040000u;
+  _has_bits_[0] |= 0x00010000u;
 }
 inline void laser_parameter::clear_has_mat_r03() {
-  _has_bits_[0] &= ~0x00040000u;
+  _has_bits_[0] &= ~0x00010000u;
 }
 inline void laser_parameter::clear_mat_r03() {
   mat_r03_ = 1;
@@ -798,13 +778,13 @@ inline void laser_parameter::set_mat_r03(double value) {
 
 // optional double mat_r10 = 8 [default = 1];
 inline bool laser_parameter::has_mat_r10() const {
-  return (_has_bits_[0] & 0x00080000u) != 0;
+  return (_has_bits_[0] & 0x00020000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r10() {
-  _has_bits_[0] |= 0x00080000u;
+  _has_bits_[0] |= 0x00020000u;
 }
 inline void laser_parameter::clear_has_mat_r10() {
-  _has_bits_[0] &= ~0x00080000u;
+  _has_bits_[0] &= ~0x00020000u;
 }
 inline void laser_parameter::clear_mat_r10() {
   mat_r10_ = 1;
@@ -822,13 +802,13 @@ inline void laser_parameter::set_mat_r10(double value) {
 
 // optional double mat_r11 = 9 [default = 1];
 inline bool laser_parameter::has_mat_r11() const {
-  return (_has_bits_[0] & 0x00100000u) != 0;
+  return (_has_bits_[0] & 0x00040000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r11() {
-  _has_bits_[0] |= 0x00100000u;
+  _has_bits_[0] |= 0x00040000u;
 }
 inline void laser_parameter::clear_has_mat_r11() {
-  _has_bits_[0] &= ~0x00100000u;
+  _has_bits_[0] &= ~0x00040000u;
 }
 inline void laser_parameter::clear_mat_r11() {
   mat_r11_ = 1;
@@ -846,13 +826,13 @@ inline void laser_parameter::set_mat_r11(double value) {
 
 // optional double mat_r12 = 10 [default = 1];
 inline bool laser_parameter::has_mat_r12() const {
-  return (_has_bits_[0] & 0x00200000u) != 0;
+  return (_has_bits_[0] & 0x00080000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r12() {
-  _has_bits_[0] |= 0x00200000u;
+  _has_bits_[0] |= 0x00080000u;
 }
 inline void laser_parameter::clear_has_mat_r12() {
-  _has_bits_[0] &= ~0x00200000u;
+  _has_bits_[0] &= ~0x00080000u;
 }
 inline void laser_parameter::clear_mat_r12() {
   mat_r12_ = 1;
@@ -870,13 +850,13 @@ inline void laser_parameter::set_mat_r12(double value) {
 
 // optional double mat_r13 = 11 [default = 1];
 inline bool laser_parameter::has_mat_r13() const {
-  return (_has_bits_[0] & 0x00400000u) != 0;
+  return (_has_bits_[0] & 0x00100000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r13() {
-  _has_bits_[0] |= 0x00400000u;
+  _has_bits_[0] |= 0x00100000u;
 }
 inline void laser_parameter::clear_has_mat_r13() {
-  _has_bits_[0] &= ~0x00400000u;
+  _has_bits_[0] &= ~0x00100000u;
 }
 inline void laser_parameter::clear_mat_r13() {
   mat_r13_ = 1;
@@ -894,13 +874,13 @@ inline void laser_parameter::set_mat_r13(double value) {
 
 // optional double mat_r20 = 12 [default = 1];
 inline bool laser_parameter::has_mat_r20() const {
-  return (_has_bits_[0] & 0x00800000u) != 0;
+  return (_has_bits_[0] & 0x00200000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r20() {
-  _has_bits_[0] |= 0x00800000u;
+  _has_bits_[0] |= 0x00200000u;
 }
 inline void laser_parameter::clear_has_mat_r20() {
-  _has_bits_[0] &= ~0x00800000u;
+  _has_bits_[0] &= ~0x00200000u;
 }
 inline void laser_parameter::clear_mat_r20() {
   mat_r20_ = 1;
@@ -918,13 +898,13 @@ inline void laser_parameter::set_mat_r20(double value) {
 
 // optional double mat_r21 = 13 [default = 1];
 inline bool laser_parameter::has_mat_r21() const {
-  return (_has_bits_[0] & 0x01000000u) != 0;
+  return (_has_bits_[0] & 0x00400000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r21() {
-  _has_bits_[0] |= 0x01000000u;
+  _has_bits_[0] |= 0x00400000u;
 }
 inline void laser_parameter::clear_has_mat_r21() {
-  _has_bits_[0] &= ~0x01000000u;
+  _has_bits_[0] &= ~0x00400000u;
 }
 inline void laser_parameter::clear_mat_r21() {
   mat_r21_ = 1;
@@ -942,13 +922,13 @@ inline void laser_parameter::set_mat_r21(double value) {
 
 // optional double mat_r22 = 14 [default = 1];
 inline bool laser_parameter::has_mat_r22() const {
-  return (_has_bits_[0] & 0x02000000u) != 0;
+  return (_has_bits_[0] & 0x00800000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r22() {
-  _has_bits_[0] |= 0x02000000u;
+  _has_bits_[0] |= 0x00800000u;
 }
 inline void laser_parameter::clear_has_mat_r22() {
-  _has_bits_[0] &= ~0x02000000u;
+  _has_bits_[0] &= ~0x00800000u;
 }
 inline void laser_parameter::clear_mat_r22() {
   mat_r22_ = 1;
@@ -966,13 +946,13 @@ inline void laser_parameter::set_mat_r22(double value) {
 
 // optional double mat_r23 = 15 [default = 1];
 inline bool laser_parameter::has_mat_r23() const {
-  return (_has_bits_[0] & 0x04000000u) != 0;
+  return (_has_bits_[0] & 0x01000000u) != 0;
 }
 inline void laser_parameter::set_has_mat_r23() {
-  _has_bits_[0] |= 0x04000000u;
+  _has_bits_[0] |= 0x01000000u;
 }
 inline void laser_parameter::clear_has_mat_r23() {
-  _has_bits_[0] &= ~0x04000000u;
+  _has_bits_[0] &= ~0x01000000u;
 }
 inline void laser_parameter::clear_mat_r23() {
   mat_r23_ = 1;
@@ -1158,13 +1138,13 @@ inline void laser_parameter::set_install_angle(double value) {
 
 // optional bool scan_direction = 23 [default = true];
 inline bool laser_parameter::has_scan_direction() const {
-  return (_has_bits_[0] & 0x00002000u) != 0;
+  return (_has_bits_[0] & 0x00001000u) != 0;
 }
 inline void laser_parameter::set_has_scan_direction() {
-  _has_bits_[0] |= 0x00002000u;
+  _has_bits_[0] |= 0x00001000u;
 }
 inline void laser_parameter::clear_has_scan_direction() {
-  _has_bits_[0] &= ~0x00002000u;
+  _has_bits_[0] &= ~0x00001000u;
 }
 inline void laser_parameter::clear_scan_direction() {
   scan_direction_ = true;
@@ -1245,13 +1225,13 @@ inline void laser_parameter::set_allocated_sn(::std::string* sn) {
 
 // optional int64 frame_num = 25 [default = 3000];
 inline bool laser_parameter::has_frame_num() const {
-  return (_has_bits_[0] & 0x08000000u) != 0;
+  return (_has_bits_[0] & 0x02000000u) != 0;
 }
 inline void laser_parameter::set_has_frame_num() {
-  _has_bits_[0] |= 0x08000000u;
+  _has_bits_[0] |= 0x02000000u;
 }
 inline void laser_parameter::clear_has_frame_num() {
-  _has_bits_[0] &= ~0x08000000u;
+  _has_bits_[0] &= ~0x02000000u;
 }
 inline void laser_parameter::clear_frame_num() {
   frame_num_ = GOOGLE_LONGLONG(3000);
@@ -1330,54 +1310,6 @@ inline void laser_parameter::set_allocated_type(::std::string* type) {
   // @@protoc_insertion_point(field_set_allocated:Laser_proto.laser_parameter.type)
 }
 
-// optional bool is_save_banary = 27 [default = false];
-inline bool laser_parameter::has_is_save_banary() const {
-  return (_has_bits_[0] & 0x00001000u) != 0;
-}
-inline void laser_parameter::set_has_is_save_banary() {
-  _has_bits_[0] |= 0x00001000u;
-}
-inline void laser_parameter::clear_has_is_save_banary() {
-  _has_bits_[0] &= ~0x00001000u;
-}
-inline void laser_parameter::clear_is_save_banary() {
-  is_save_banary_ = false;
-  clear_has_is_save_banary();
-}
-inline bool laser_parameter::is_save_banary() const {
-  // @@protoc_insertion_point(field_get:Laser_proto.laser_parameter.is_save_banary)
-  return is_save_banary_;
-}
-inline void laser_parameter::set_is_save_banary(bool value) {
-  set_has_is_save_banary();
-  is_save_banary_ = value;
-  // @@protoc_insertion_point(field_set:Laser_proto.laser_parameter.is_save_banary)
-}
-
-// optional bool is_save_txt = 28 [default = true];
-inline bool laser_parameter::has_is_save_txt() const {
-  return (_has_bits_[0] & 0x00004000u) != 0;
-}
-inline void laser_parameter::set_has_is_save_txt() {
-  _has_bits_[0] |= 0x00004000u;
-}
-inline void laser_parameter::clear_has_is_save_txt() {
-  _has_bits_[0] &= ~0x00004000u;
-}
-inline void laser_parameter::clear_is_save_txt() {
-  is_save_txt_ = true;
-  clear_has_is_save_txt();
-}
-inline bool laser_parameter::is_save_txt() const {
-  // @@protoc_insertion_point(field_get:Laser_proto.laser_parameter.is_save_txt)
-  return is_save_txt_;
-}
-inline void laser_parameter::set_is_save_txt(bool value) {
-  set_has_is_save_txt();
-  is_save_txt_ = value;
-  // @@protoc_insertion_point(field_set:Laser_proto.laser_parameter.is_save_txt)
-}
-
 // -------------------------------------------------------------------
 
 // Laser_parameter_all

+ 82 - 65
laser/laser_task_command.cpp

@@ -7,16 +7,18 @@
 //并将结果填充到Laser_task,返回给应用层
 
 #include "laser_task_command.h"
-//构造函数
+//构造函数,构造函数锁定任务类型为LASER_TASK,后续不允许更改
 Laser_task::Laser_task()
 {
+    //构造函数锁定任务类型为LASER_TASK,后续不允许更改
     m_task_type = LASER_TASK;
     m_task_statu = TASK_CREATED;
     //m_task_statu_information默认为空
 
-    m_task_points_number = 0;
-    pm_task_point3d_cloud_vector = NULL;
+    m_task_frame_maxnum = 0;
+    mp_task_point_cloud = NULL;
     //m_task_error_manager 默认为空
+    mp_task_cloud_lock=NULL;
 }
 //析构函数
 Laser_task::~Laser_task()
@@ -25,101 +27,118 @@ Laser_task::~Laser_task()
 }
 
 //初始化任务单,必须初始化之后才可以使用,(必选参数)
-//input:task_type 任务类型
-// input:task_statu任务状态
-// output:p_task_point3d_cloud_vector三维点云容器指针
-//注:task_points_number默认为0,如果为0,则使用laser默认的点云的采集数量
-Error_manager Laser_task::task_init( Task_statu task_statu,
-                                     pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point3d_cloud_vector,
-                                     std::mutex* lock)
+// input:task_statu 任务状态
+// output:p_task_point_cloud 三维点云容器的智能指针
+// input:p_task_cloud_lock 三维点云的数据保护锁
+//注:task_frame_maxnum默认为0,如果为0,则使用laser默认的点云的采集帧数最大值 TASK_FRAME_MAXNUM_DEFAULT
+Error_manager Laser_task::task_init(Task_statu task_statu,
+                                    pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
+                                    std::mutex* p_task_cloud_lock)
 {
-    if(p_task_point3d_cloud_vector.get() == NULL)
+    if(p_task_point_cloud.get() == NULL)
     {
         return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
-                             "Laser_task::task_init failed");
+                             "Laser_task::task_init p_task_point_cloud is null");
     }
-    if(lock==NULL)
+    if(p_task_cloud_lock==NULL)
     {
-        return Error_manager(PARAMETER_ERROR,NORMAL,"laser task input lock is null");
+        return Error_manager(POINTER_IS_NULL,MINOR_ERROR,"laser task input lock is null");
     }
-    mp_cloud_lock=lock;
+
     m_task_statu = task_statu;
     m_task_statu_information.clear();
 
-    m_task_points_number = 0;
-    pm_task_point3d_cloud_vector = p_task_point3d_cloud_vector;
+    m_task_frame_maxnum = TASK_FRAME_MAXNUM_DEFAULT;
+    mp_task_cloud_lock=p_task_cloud_lock;
+    mp_task_point_cloud = p_task_point_cloud;
     m_task_error_manager.error_manager_clear_all();
 
     return Error_code::SUCCESS;
 }
 
 //初始化任务单,必须初始化之后才可以使用,(可选参数)
-//    input:task_type 任务类型
 //    input:task_statu任务状态
 //    input:task_statu_information状态说明
-//    input:task_points_number点云的采集数量
-//    output:p_task_point3d_cloud_vector三维点云容器指针
-//注:task_points_number默认为0,如果为0,则使用laser默认的点云的采集数量
+//    input:task_frame_maxnum点云的采集帧数最大值
+//    output:p_task_point_cloud三维点云容器的智能指针
+// input:p_task_cloud_lock 三维点云的数据保护锁
+//注:task_frame_maxnum默认为0,如果为0,则使用laser默认的点云的采集帧数最大值 TASK_FRAME_MAXNUM_DEFAULT
 Error_manager Laser_task::task_init(Task_statu task_statu,
                                     std::string & task_statu_information,
-                                    int task_points_number,
-                                    pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point3d_cloud_vector,
-                                    std::mutex* lock)
+                                    unsigned int task_frame_maxnum,
+                                    pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
+                                    std::mutex* p_task_cloud_lock)
 {
-    if(p_task_point3d_cloud_vector.get() == NULL)
+    if(p_task_point_cloud.get() == NULL)
     {
         return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
-                             "Laser_task::task_init failed");
+                             "Laser_task::task_init p_task_point_cloud is null");
     }
-    if(lock==NULL)
+    if(p_task_cloud_lock==NULL)
     {
-        return Error_manager(PARAMETER_ERROR,NORMAL,"laser task input lock is null");
+        return Error_manager(POINTER_IS_NULL,MINOR_ERROR,"laser task input lock is null");
     }
-    mp_cloud_lock=lock;
+
     m_task_statu = task_statu;
     m_task_statu_information = task_statu_information;
 
-    m_task_points_number = task_points_number;
-    pm_task_point3d_cloud_vector = p_task_point3d_cloud_vector;
+    if(task_frame_maxnum == 0)
+    {
+        m_task_frame_maxnum = TASK_FRAME_MAXNUM_DEFAULT;
+    }
+    else
+    {
+        m_task_frame_maxnum = task_frame_maxnum;
+    }
+    mp_task_cloud_lock=p_task_cloud_lock;
+    mp_task_point_cloud = p_task_point_cloud;
     m_task_error_manager.error_manager_clear_all();
 
     return Error_code::SUCCESS;
 }
 
-//push点云
-Error_manager Laser_task::push_point(pcl::PointXYZ point)
+//push点云,把 point_xyz 添加到 p_task_point_cloud 里面。
+Error_manager Laser_task::task_push_point(pcl::PointXYZ point_xyz)
 {
-    if(mp_cloud_lock==NULL)
+    if(mp_task_cloud_lock==NULL)
     {
-        return Error_manager(PARAMETER_ERROR,NORMAL,"push_point laser task input lock is null");
+        return Error_manager(POINTER_IS_NULL,MINOR_ERROR,
+                             "push_point laser task input lock is null");
     }
-    if(pm_task_point3d_cloud_vector.get()==NULL)
+    if(mp_task_point_cloud.get()==NULL)
     {
         return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
-                            "Laser_task::push_point failed");
+                             "Laser_task::task_push_point p_task_point_cloud is null");
     }
-    mp_cloud_lock->lock();
-    pm_task_point3d_cloud_vector->push_back(point);
-    mp_cloud_lock->unlock();
+    //加锁,并添加三维点。
+    mp_task_cloud_lock->lock();
+    mp_task_point_cloud->push_back(point_xyz);
+    mp_task_cloud_lock->unlock();
     return SUCCESS;
 }
 
-//获取 点云的采集数量
-int Laser_task::get_task_points_number()
+
+
+
+//获取 点云的采集帧数最大值
+unsigned int Laser_task::get_task_frame_maxnum()
 {
-    return m_task_points_number;
+    return m_task_frame_maxnum;
 }
-//获取 三维点云容器
-pcl::PointCloud<pcl::PointXYZ>::Ptr Laser_task::get_task_point3d_cloud_vector()
+//获取采集的点云保存路径
+std::string Laser_task::get_task_save_path()
 {
-    return pm_task_point3d_cloud_vector;
+    return m_task_save_path;
 }
-//获取 错误码
-Error_manager Laser_task::get_task_error_manager()
+//获取 三维点云容器的智能指针
+pcl::PointCloud<pcl::PointXYZ>::Ptr Laser_task::get_task_point_cloud()
 {
-    return m_task_error_manager;
+    return mp_task_point_cloud;
 }
 
+
+
+
 //设置 任务状态
 void Laser_task::set_task_statu(Task_statu task_statu)
 {
@@ -130,15 +149,21 @@ void Laser_task::set_task_statu_information(std::string & task_statu_information
 {
     m_task_statu_information = task_statu_information;
 }
-//设置 点云的采集数量
-void Laser_task::set_task_points_number(int task_points_number)
+//设置 点云的采集帧数最大值
+void Laser_task::set_task_frame_maxnum(unsigned int task_frame_maxnum)
 {
-    m_task_points_number = task_points_number;
+    m_task_frame_maxnum = task_frame_maxnum;
+
 }
-//设置 三维点云容器
-void Laser_task::set_task_point3d_cloud_vector(pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point3d_cloud_vector)
+//设置采集的点云保存路径
+void Laser_task::set_task_save_path(std::string task_save_path)
 {
-    pm_task_point3d_cloud_vector = p_task_point3d_cloud_vector;
+    m_task_save_path=task_save_path;
+}
+//设置 三维点云容器的智能指针
+void Laser_task::set_task_point_cloud(pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud)
+{
+    mp_task_point_cloud = p_task_point_cloud;
 }
 //设置 错误码
 void Laser_task::set_task_error_manager(Error_manager & error_manager)
@@ -146,16 +171,8 @@ void Laser_task::set_task_error_manager(Error_manager & error_manager)
     m_task_error_manager = error_manager;
 }
 
-//获取采集的点云保存路径
-std::string Laser_task::get_save_path()
-{
-    return m_save_path;
-}
-//设置采集的点云保存路径
-void Laser_task::set_save_path(std::string save_path)
-{
-    m_save_path=save_path;
-}
+
+
 
 
 

+ 50 - 41
laser/laser_task_command.h

@@ -20,75 +20,84 @@
 
 #include "../task/task_command_manager.h"
 
+//任务点云的采集帧数最大值,默认值1000
+#define TASK_FRAME_MAXNUM_DEFAULT               1000
+
 //雷达模块的任务指令,从Task_Base继承,
 //补充了雷达专属的数据输入和输出
 class Laser_task:public Task_Base
 {
 public:
-    //构造函数
+    //构造函数,构造函数锁定任务类型为LASER_TASK,后续不允许更改
     Laser_task();
     //析构函数
     ~Laser_task();
 
     //初始化任务单,必须初始化之后才可以使用,(必选参数)
-    //input:task_type 任务类型
-    // input:task_statu任务状态
-    // output:p_task_point3d_cloud_vector三维点云容器指针
-    //注:task_points_number默认为0,如果为0,则使用laser默认的点云的采集数量
+    // input:task_statu 任务状态
+    // output:p_task_point_cloud 三维点云容器的智能指针
+    // input:p_task_cloud_lock 三维点云的数据保护锁
+    //注:task_frame_maxnum默认为0,如果为0,则使用laser默认的点云的采集帧数最大值 TASK_FRAME_MAXNUM_DEFAULT
     Error_manager task_init(Task_statu task_statu,
-                            pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point3d_cloud_vector,
-                            std::mutex* lock);
+                            pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
+                            std::mutex* p_task_cloud_lock);
 
     //初始化任务单,必须初始化之后才可以使用,(可选参数)
-    //    input:task_type 任务类型
     //    input:task_statu任务状态
     //    input:task_statu_information状态说明
-    //    input:task_points_number点云的采集数量
-    //    output:p_task_point3d_cloud_vector三维点云容器指针
-    //    lock:
-    //注:task_points_number默认为0,如果为0,则使用laser默认的点云的采集数量
+    //    input:task_frame_maxnum点云的采集帧数最大值
+    //    output:p_task_point_cloud 三维点云容器的智能指针
+    // input:p_task_cloud_lock 三维点云的数据保护锁
+    //注:task_frame_maxnum默认为0,如果为0,则使用laser默认的点云的采集帧数最大值 TASK_FRAME_MAXNUM_DEFAULT
     Error_manager task_init(Task_statu task_statu,
                             std::string & task_statu_information,
-                            int task_points_number,
-                            pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point3d_cloud_vector,
-                            std::mutex* lock);
-
-    //获取 点云的采集数量
-    int get_task_points_number();
-    //push点云
-    Error_manager push_point(pcl::PointXYZ point);
-    //获取 三维点云容器
-    pcl::PointCloud<pcl::PointXYZ>::Ptr get_task_point3d_cloud_vector();
-    //获取 错误码
-    Error_manager get_task_error_manager();
+                            unsigned int task_frame_maxnum,
+                            pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
+                            std::mutex* p_task_cloud_lock);
+
+    //push点云,把 point_xyz 添加到 p_task_point_cloud 里面。
+    Error_manager task_push_point(pcl::PointXYZ point_xyz);
+
+
+public:
+    //获取 点云的采集帧数最大值
+    unsigned int get_task_frame_maxnum();
+    //获取采集的点云保存路径
+    std::string get_task_save_path();
+    //获取 三维点云容器的智能指针
+    pcl::PointCloud<pcl::PointXYZ>::Ptr get_task_point_cloud();
+
+
+
 
     //设置 任务状态
     void set_task_statu(Task_statu task_statu);
     //设置 任务状态说明
     void set_task_statu_information(std::string & task_statu_information);
-    //设置 点云的采集数量
-    void set_task_points_number(int task_points_number);
-    //设置 三维点云容器
-    void set_task_point3d_cloud_vector(pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point3d_cloud_vector);
+    //设置 点云的采集帧数最大值
+    void set_task_frame_maxnum(unsigned int task_frame_maxnum);
+    //设置采集的点云保存路径
+    void set_task_save_path(std::string task_save_path);
+    //设置 三维点云容器的智能指针
+    void set_task_point_cloud(pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud);
     //设置 错误码
     void set_task_error_manager(Error_manager & error_manager);
-    //获取采集的点云保存路径
-    std::string get_save_path();
-    //设置采集的点云保存路径
-    void set_save_path(std::string save_path);
+
 
 protected:
-    //点云的采集数量,任务输入
-    int                             m_task_points_number;
-    std::string                     m_save_path;
-    //采集结果,三维点云容器,任务输出
+    //点云的采集帧数最大值,任务输入
+    unsigned int                    m_task_frame_maxnum;
+
+    //点云保存文件的路径,任务输入
+    std::string                     m_task_save_path;
+
+    //三维点云的数据保护锁,任务输入
+    std::mutex*                     mp_task_cloud_lock;
+    //采集结果,三维点云容器的智能指针,任务输出
     //这里只是指针,实际内存由应用层管理,初始化时必须保证内存有效。
-    pcl::PointCloud<pcl::PointXYZ>::Ptr        pm_task_point3d_cloud_vector;
+    pcl::PointCloud<pcl::PointXYZ>::Ptr        mp_task_point_cloud;
+
 
-    //错误码,任务故障信息,任务输出
-    Error_manager                   m_task_error_manager;
-    //
-    std::mutex*                     mp_cloud_lock;
 };
 
 

+ 114 - 0
laser/laser_task_command.puml

@@ -0,0 +1,114 @@
+@startuml
+skinparam classAttributeIconSize 0
+
+<<<<<<< HEAD
+title  Laser_task 雷达模块的任务指令
+=======
+title  binary_buf是二进制缓存
+>>>>>>> origin/hl
+
+note left of Laser_task
+//laser_task_command,是雷达任务指令的相关功能
+//功能:用作应用层向laser模块传输任务,的指令消息
+
+//用法:应用层直接调用laser的接口函数,并将Laser_task类作为参数传递
+//CLaser类则按照Laser_task的功能码和指定的参数,执行相应的功能
+//并将结果填充到Laser_task,返回给应用层
+end note
+
+
+class Laser_task
+{
+//雷达模块的任务指令,从Task_Base继承,
+//补充了雷达专属的数据输入和输出
+==public:==
+    //构造函数,构造函数锁定任务类型为LASER_TASK,后续不允许更改
+    Laser_task();
+    //析构函数
+    ~Laser_task();
+..
+    //初始化任务单,必须初始化之后才可以使用,(必选参数)
+    // input:task_statu 任务状态
+    // output:p_task_point_cloud 三维点云容器的智能指针
+    // input:p_task_cloud_lock 三维点云的数据保护锁
+    //注:task_frame_maxnum默认为0,如果为0,则使用laser默认的点云的采集帧数最大值 TASK_FRAME_MAXNUM_DEFAULT
+    Error_manager task_init(Task_statu task_statu,
+                            pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
+                            std::mutex* p_task_cloud_lock);
+..
+    //初始化任务单,必须初始化之后才可以使用,(可选参数)
+    //    input:task_statu任务状态
+    //    input:task_statu_information状态说明
+    //    input:task_frame_maxnum点云的采集帧数最大值
+    //    output:p_task_point_cloud 三维点云容器的智能指针
+    // input:p_task_cloud_lock 三维点云的数据保护锁
+    //注:task_frame_maxnum默认为0,如果为0,则使用laser默认的点云的采集帧数最大值 TASK_FRAME_MAXNUM_DEFAULT
+    Error_manager task_init(Task_statu task_statu,
+                            std::string & task_statu_information,
+                            unsigned int task_frame_maxnum,
+                            pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud,
+                            std::mutex* p_task_cloud_lock);
+..
+    //push点云,把 point_xyz 添加到 p_task_point_cloud 里面。
+    Error_manager task_push_point(pcl::PointXYZ point_xyz);
+==public:==
+    //获取 点云的采集帧数最大值
+    unsigned int get_task_frame_maxnum();
+    //获取采集的点云保存路径
+    std::string get_task_save_path();
+    //获取 三维点云容器的智能指针
+    pcl::PointCloud<pcl::PointXYZ>::Ptr get_task_point_cloud();
+..
+    //设置 任务状态
+    void set_task_statu(Task_statu task_statu);
+    //设置 任务状态说明
+    void set_task_statu_information(std::string & task_statu_information);
+    //设置 点云的采集帧数最大值
+    void set_task_frame_maxnum(unsigned int task_frame_maxnum);
+    //设置采集的点云保存路径
+    void set_task_save_path(std::string task_save_path);
+    //设置 三维点云容器的智能指针
+    void set_task_point_cloud(pcl::PointCloud<pcl::PointXYZ>::Ptr p_task_point_cloud);
+    //设置 错误码
+    void set_task_error_manager(Error_manager & error_manager);
+==protected:==
+    //点云的采集帧数最大值,任务输入
+    unsigned int                    m_task_frame_maxnum;
+    //点云保存文件的路径,任务输入
+    std::string                     m_task_save_path;
+    //三维点云的数据保护锁,任务输入
+    std::mutex*                     mp_task_cloud_lock;
+    //采集结果,三维点云容器的智能指针,任务输出
+    //这里只是指针,实际内存由应用层管理,初始化时必须保证内存有效。
+    pcl::PointCloud<pcl::PointXYZ>::Ptr        mp_task_point_cloud;
+}
+
+
+class Task_Base
+{
+//任务单基类
+==public:==
+    //初始化任务单,初始任务单类型为 UNKONW_TASK
+    virtual Error_manager init();
+..
+    //更新任务单
+    Error_manager update_statu(Task_statu task_statu,std::string statu_information="");
+..
+    //获取任务类型
+    Task_type   get_task_type();
+..
+    //获取任务单状态
+    Task_statu  get_statu();
+..
+    //获取状态说明
+    std::string get_statu_information();
+==protected:==
+    Task_type                   m_task_type;                    //任务类型
+    Task_statu                  m_task_statu;                   //任务状态
+    std::string                 m_task_statu_information;       //任务状态说明
+	Error_manager               m_task_error_manager;//错误码,任务故障信息,任务输出
+}
+
+Laser_task <-- Task_Base : inherit
+
+@enduml

+ 0 - 0
main.cpp


二進制
png/Laser.png


二進制
png/LivoxLaser.png


二進制
png/binary_buf.png


二進制
png/laser_task_command.png


二進制
png/laser功能模块图.eddx


二進制
png/laser功能模块图.png


二進制
png/laser数据流程图.eddx


二進制
png/laser数据流程图.png


二進制
png/laser程序流程图.eddx


二進制
png/laser程序流程图.png


二進制
png/task_command_manager.png


二進制
png/thread_condition.png


二進制
png/thread_safe_queue.png


+ 16 - 1
task/task_command_manager.cpp

@@ -42,4 +42,19 @@ Task_statu  Task_Base::get_statu()
 std::string Task_Base::get_statu_information()
 {
     return m_task_statu_information;
-}
+}
+
+//获取 错误码
+Error_manager& Task_Base::get_task_error_manager()
+{
+	return m_task_error_manager;
+}
+//设置 错误码
+void Task_Base::set_task_error_manager(Error_manager & error_manager)
+{
+	m_task_error_manager = error_manager;
+}
+
+
+
+

+ 20 - 15
task/task_command_manager.h

@@ -6,25 +6,25 @@
 #define TASK_COMAND_MANAGER_H
 #include <string>
 #include "../error_code/error_code.h"
+
 //任务类型
 enum Task_type
 {
-    LASER_TASK=0,           //雷达扫描任务
-    LOCATE_TASK,            //测量任务
-    PLC_TASK,                //上传PLC任务
-    WJ_TASK,
-    UNKNOW_TASK             //未知任务单/初始化
+	UNKNOW_TASK             =0,				//未知任务单//初始化,默认值
+	LASER_TASK              =1,             //雷达扫描任务,
+    LOCATE_TASK             =2,             //测量任务
+    PLC_TASK                =3,             //上传PLC任务
 };
-//任务状态
+//任务状态,如果任务故障,任务状态改为TASK_OVER,然后在m_task_error_manager 补充错误码。
 enum Task_statu
 {
-    TASK_CREATED=0,     //创建状态
-    TASK_SIGNED,        //已签收
-    TASK_WORKING,       //处理中
-    TASK_OVER           //已结束
+    TASK_CREATED            =0,             //创建状态,默认值
+    TASK_SIGNED             =1,             //已签收
+    TASK_WORKING            =2,             //处理中
+    TASK_OVER               =3,             //已结束
 };
 
-//
+//任务单基类
 class Task_Base
 {
 public:
@@ -41,13 +41,18 @@ public:
     Task_statu  get_statu();
     //获取状态说明
     std::string get_statu_information();
-
+	//获取 错误码
+	Error_manager& get_task_error_manager();
+	//设置 错误码
+	void set_task_error_manager(Error_manager & error_manager);
 protected:
     Task_Base();
 protected:
-    Task_type                   m_task_type;
-    Task_statu                  m_task_statu;               //任务状态
-    std::string                 m_task_statu_information;        //任务状态说明
+    Task_type                   m_task_type;					//任务类型
+    Task_statu                  m_task_statu;					//任务状态
+    std::string					m_task_statu_information;		//任务状态说明
+	//错误码,任务故障信息,任务输出
+	Error_manager               m_task_error_manager;
 };
 
 #endif //TASK_COMAND_MANAGER_H

+ 82 - 0
task/task_command_manager.puml

@@ -0,0 +1,82 @@
+@startuml
+@startuml
+skinparam classAttributeIconSize 0
+
+<<<<<<< HEAD
+title  Task_Base 任务单基类
+=======
+title  binary_buf是二进制缓存
+>>>>>>> origin/hl
+
+
+
+enum Task_type
+{
+//任务类型
+	UNKNOW_TASK             =0,				//未知任务单//初始化,默认值
+	LASER_TASK              =1,             //雷达扫描任务,
+    LOCATE_TASK             =2,             //测量任务
+    PLC_TASK                =3,             //上传PLC任务
+}
+
+
+enum Task_statu
+{
+//任务状态,如果任务故障,任务状态改为TASK_OVER,然后在m_task_error_manager 补充错误码。
+    TASK_CREATED            =0,             //创建状态,默认值
+    TASK_SIGNED             =1,             //已签收
+    TASK_WORKING            =2,             //处理中
+    TASK_OVER               =3,             //已结束
+}
+
+
+
+
+class Task_Base
+{
+//任务单基类
+==public:==
+    ~Task_Base();
+..
+    //初始化任务单,初始任务单类型为 UNKONW_TASK
+    virtual Error_manager init();
+..
+    //更新任务单
+    //task_statu: 任务状态
+    //statu_information:状态说明
+    Error_manager update_statu(Task_statu task_statu,std::string statu_information="");
+..
+    //获取任务类型
+    Task_type   get_task_type();
+..
+    //获取任务单状态
+    Task_statu  get_statu();
+..
+    //获取状态说明
+    std::string get_statu_information();
+..
+	//获取 错误码
+	Error_manager& get_task_error_manager();
+..
+	//设置 错误码
+	void set_task_error_manager(Error_manager & error_manager);
+==protected:==
+    Task_Base();
+==protected:==
+    Task_type                   m_task_type;                    //任务类型
+    Task_statu                  m_task_statu;                   //任务状态
+    std::string                 m_task_statu_information;       //任务状态说明
+	//错误码,任务故障信息,任务输出
+	Error_manager               m_task_error_manager;
+}
+
+class Error_manager
+{
+//错误码管理
+}
+Task_Base <-- Error_manager : include
+
+
+Task_Base <-- Task_type : include
+Task_Base <-- Task_statu : include
+@enduml

+ 319 - 0
tool/binary_buf.cpp

@@ -0,0 +1,319 @@
+
+/*
+ * binary_buf是二进制缓存
+ * 这里用字符串,来存储雷达的通信消息的原始数据
+ * Binary_buf 的内容格式:消息类型 + 消息数据
+ *
+ * 例如思科的雷达的消息类型
+ * ready->ready->start->data->data->data->stop->ready->ready
+ *
+ * 提供了 is_equal 系列的函数,来进行判断前面的消息类型
+ * 
+ * 注意了:m_buf是中间可以允许有‘\0’的,不是单纯的字符串格式
+ * 			末尾也不一定是‘\0’
+ */
+
+#include "binary_buf.h"
+
+#include <string>
+#include <string.h>
+
+Binary_buf::Binary_buf()
+{
+	mp_buf = NULL;
+	m_length = 0;
+}
+
+Binary_buf::Binary_buf(const Binary_buf& other)
+{
+	mp_buf = NULL;
+	m_length = 0;
+
+	if ( other.m_length > 0 && other.mp_buf != NULL)
+	{
+		mp_buf = (char*)malloc(other.m_length);
+		memcpy(mp_buf, other.mp_buf, other.m_length);
+		m_length = other.m_length;
+	}
+}
+
+Binary_buf::~Binary_buf()
+{
+	if ( mp_buf )
+	{
+		free(mp_buf);
+		mp_buf = NULL;
+	}
+	m_length = 0;
+}
+
+
+//使用参数构造,深拷贝,len为0时,使用strlen(buf),不存储结束符'\0'
+Binary_buf::Binary_buf(const char* p_buf, int len)
+{
+	mp_buf = NULL;
+	m_length = 0;
+
+	if ( p_buf != NULL)
+	{
+		if (len <= 0)
+		{
+			len = strlen(p_buf);
+		}
+
+		mp_buf = (char*)malloc(len);
+		memcpy(mp_buf, p_buf, len);
+		m_length = len;
+	}
+}
+
+//重载=,深拷贝,
+Binary_buf& Binary_buf::operator=(const Binary_buf& other)
+{
+	clear();
+
+	if ( other.m_length > 0 && other.mp_buf != NULL)
+	{
+		mp_buf = (char*)malloc(other.m_length);
+		memcpy(mp_buf, other.mp_buf, other.m_length);
+		m_length = other.m_length;
+	}
+	return *this;
+}
+
+//重载=,深拷贝,使用strlen(buf),不存储结束符'\0'
+Binary_buf& Binary_buf::operator=(const char* p_buf)
+{
+	clear();
+
+	if ( p_buf != NULL)
+	{
+		int len = strlen(p_buf);
+		mp_buf = (char*)malloc(len);
+		memcpy(mp_buf, p_buf, len);
+		m_length = len;
+	}
+	return *this;
+}
+
+//重载+,other追加在this的后面,
+Binary_buf& Binary_buf::operator+(Binary_buf& other)
+{
+	if (other.mp_buf != NULL && other.m_length > 0)
+	{
+		int t_length_total = m_length + other.m_length;
+		char* tp_buf_total = (char*)malloc(t_length_total);
+		memcpy(tp_buf_total, mp_buf, m_length);
+		memcpy(tp_buf_total + m_length, other.mp_buf, other.m_length);
+		free(mp_buf);
+		mp_buf = tp_buf_total;
+		m_length = t_length_total;
+	}
+	return *this;
+}
+
+//重载+,追加在this的后面,使用strlen(buf),不存储结束符'\0'
+Binary_buf& Binary_buf::operator+(const char* p_buf)
+{
+	if (p_buf != NULL )
+	{
+		int t_length_back = strlen(p_buf);
+		int t_length_total = m_length + t_length_back;
+		char* tp_buf_total = (char*)malloc(t_length_total);
+		memcpy(tp_buf_total, mp_buf, m_length);
+		memcpy(tp_buf_total + m_length, p_buf, t_length_back);
+		free(mp_buf);
+		mp_buf = tp_buf_total;
+		m_length = t_length_total;
+	}
+	return *this;
+}
+
+//重载[],允许直接使用数组的形式,直接访问buf的内存。注意,n值必须在0~m_length之间,
+char& Binary_buf::operator[](int n)
+{
+	if (n >= 0 && n < m_length)
+	{
+		return mp_buf[n];
+	}
+	else
+	{
+		throw (n);
+	}
+}
+
+
+//判空
+bool Binary_buf::is_empty()
+{
+	if ( mp_buf != NULL && m_length > 0 )
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+//清空
+void Binary_buf::clear()
+{
+	if ( mp_buf )
+	{
+		free(mp_buf);
+		mp_buf = NULL;
+	}
+	m_length = 0;
+}
+
+
+//比较前面部分的buf是否相等,使用 other.m_length 为标准
+bool Binary_buf::is_equal_front(const Binary_buf& other)
+{
+	if ( other.mp_buf == NULL || other.m_length <= 0 )
+	{
+		if ( mp_buf == NULL || m_length <= 0 )
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if ( mp_buf != NULL && m_length > 0 )
+		{
+			if ( other.m_length > m_length )
+			{
+				return false;
+			}
+			return  (strncmp((const char*)mp_buf, other.mp_buf, other.m_length) == 0);
+		}
+		else
+		{
+			return false;
+		}
+
+	}
+}
+
+//比较前面部分的buf是否相等,len为0时,使用strlen(buf)为标准,不比较结束符'\0'
+bool Binary_buf::is_equal_front(const char* p_buf, int len)
+{
+	if ( p_buf == NULL )
+	{
+		if ( mp_buf == NULL || m_length <= 0 )
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if ( mp_buf != NULL && m_length > 0 )
+		{
+			if ( len == 0 )
+			{
+				len = strlen(p_buf);
+			}
+			if ( len > m_length )
+			{
+				return false;
+			}
+			return  (strncmp((const char*)mp_buf, p_buf, len) == 0);
+		}
+		else
+		{
+			return false;
+		}
+
+	}
+}
+
+//比较的buf是否全部相等,
+bool Binary_buf::is_equal_all(const Binary_buf& other)
+{
+	if ( other.mp_buf == NULL || other.m_length <= 0 )
+	{
+		if ( mp_buf == NULL || m_length <= 0 )
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if ( mp_buf != NULL && m_length > 0 )
+		{
+			if ( other.m_length != m_length )
+			{
+				return false;
+			}
+			return  (strncmp((const char*)mp_buf, other.mp_buf, other.m_length) == 0);
+		}
+		else
+		{
+			return false;
+		}
+
+	}
+}
+//比较的buf是否全部相等,不比较结束符'\0'
+bool Binary_buf::is_equal_all(const char* p_buf)
+{
+	if ( p_buf == NULL )
+	{
+		if ( mp_buf == NULL || m_length <= 0 )
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if ( mp_buf != NULL && m_length > 0 )
+		{
+			int	len = strlen(p_buf);
+			if ( len != m_length )
+			{
+				return false;
+			}
+			return  (strncmp((const char*)mp_buf, p_buf, len) == 0);
+		}
+		else
+		{
+			return false;
+		}
+
+	}
+}
+
+
+
+
+char*	Binary_buf::get_buf()const
+{
+	return mp_buf;
+}
+
+int		Binary_buf::get_length()const
+{
+	return m_length;
+}
+
+
+
+
+

+ 88 - 0
tool/binary_buf.h

@@ -0,0 +1,88 @@
+
+/*
+ * binary_buf是二进制缓存
+ * 这里用字符串,来存储雷达的通信消息的原始数据
+ * Binary_buf 的内容格式:消息类型 + 消息数据
+ *
+ * 例如思科的雷达的消息类型
+ * ready->ready->start->data->data->data->stop->ready->ready
+ *
+ * 提供了 is_equal 系列的函数,来进行判断前面的消息类型
+ *
+ * 注意了:m_buf是中间可以允许有‘\0’的,不是单纯的字符串格式
+ * 			末尾也不一定是‘\0’
+ */
+
+#ifndef LIDARMEASURE_BINARY_BUF_H
+#define LIDARMEASURE_BINARY_BUF_H
+
+
+//雷达消息的类型
+//在通信消息的前面一部分字符串,表示这条消息的类型。
+//在解析消息的时候,先解析前面的消息类型,来判断这条消息的功用
+enum Buf_type
+{
+	//默认值 BUF_UNKNOW = 0
+	BUF_UNKNOW   		=0,	//未知消息
+	BUF_READY  			=1,	//待机消息
+	BUF_START 			=2,	//开始消息
+	BUF_DATA   			=3,	//数据消息
+	BUF_STOP  			=4,	//结束消息
+	BUF_ERROR   		=5,	//错误消息
+};
+
+
+//二进制缓存,
+class Binary_buf
+{
+public:
+	Binary_buf();
+	Binary_buf(const Binary_buf& other);
+	~Binary_buf();
+
+	//使用参数构造,深拷贝,len为0时,使用strlen(buf),不存储结束符'\0'
+	Binary_buf(const char* p_buf, int len = 0);
+	//重载=,深拷贝,
+	Binary_buf& operator=(const Binary_buf& other);
+	//重载=,深拷贝,使用strlen(buf),不存储结束符'\0'
+	Binary_buf& operator=(const char* p_buf);
+	//重载+,other追加在this的后面,
+	Binary_buf& operator+(Binary_buf& other);
+	//重载+,追加在this的后面,使用strlen(buf),不存储结束符'\0'
+	Binary_buf& operator+(const char* p_buf);
+	//重载[],允许直接使用数组的形式,直接访问buf的内存。注意,n值必须在0~m_length之间,
+	char& operator[](int n);
+
+	//判空
+	bool is_empty();
+	//清空
+	void clear();
+
+	//比较前面部分的buf是否相等,使用 other.m_length 为标准
+	bool is_equal_front(const Binary_buf& other);
+	//比较前面部分的buf是否相等,len为0时,使用strlen(buf)为标准,不比较结束符'\0'
+	bool is_equal_front(const char* p_buf, int len = 0);
+
+	//比较的buf是否全部相等,
+	bool is_equal_all(const Binary_buf& other);
+	//比较的buf是否全部相等,不比较结束符'\0'
+	bool is_equal_all(const char* p_buf);
+
+
+
+public:
+	char* get_buf()const;
+	int	get_length()const;
+
+protected:
+	char*		mp_buf;				//二进制缓存指针
+	int			m_length;			//二进制缓存长度
+
+private:
+
+};
+
+
+
+
+#endif //LIDARMEASURE_BINARY_BUF_H

+ 85 - 0
tool/binary_buf.puml

@@ -0,0 +1,85 @@
+@startuml
+skinparam classAttributeIconSize 0
+
+title  binary_buf是二进制缓存
+
+note left of Binary_buf
+/*
+ * binary_buf是二进制缓存
+ * 这里用字符串,来存储雷达的通信消息的原始数据
+ * Binary_buf 的内容格式:消息类型 + 消息数据
+ *
+ * 例如思科的雷达的消息类型
+ * ready->ready->start->data->data->data->stop->ready->ready
+ *
+ * 提供了 is_equal 系列的函数,来进行判断前面的消息类型
+ *
+ * 注意了:m_buf是中间可以允许有‘\0’的,不是单纯的字符串格式
+ * 			末尾也不一定是‘\0’
+ */
+end note
+
+
+
+enum Buf_type
+{
+//雷达消息的类型
+//在通信消息的前面一部分字符串,表示这条消息的类型。
+//在解析消息的时候,先解析前面的消息类型,来判断这条消息的功用
+	//默认值 BUF_UNKNOW = 0
+	BUF_UNKNOW   		=0,	//未知消息
+	BUF_READY  			=1,	//待机消息
+	BUF_START 			=2,	//开始消息
+	BUF_DATA   			=3,	//数据消息
+	BUF_STOP  			=4,	//结束消息
+	BUF_ERROR   		=5,	//错误消息
+}
+
+
+
+class Binary_buf
+{
+//二进制缓存,
+==public:==
+	Binary_buf();
+	Binary_buf(const Binary_buf& other);
+	~Binary_buf();
+..
+	//使用参数构造,深拷贝,len为0时,使用strlen(buf),不存储结束符'\0'
+	Binary_buf(const char* p_buf, int len = 0);
+	//重载=,深拷贝,
+	Binary_buf& operator=(const Binary_buf& other);
+	//重载=,深拷贝,使用strlen(buf),不存储结束符'\0'
+	Binary_buf& operator=(const char* p_buf);
+	//重载+,other追加在this的后面,
+	Binary_buf& operator+(Binary_buf& other);
+	//重载+,追加在this的后面,使用strlen(buf),不存储结束符'\0'
+	Binary_buf& operator+(const char* p_buf);
+	//重载[],允许直接使用数组的形式,直接访问buf的内存。注意,n值必须在0~m_length之间,
+	char& operator[](int n);
+..
+	//判空
+	bool is_empty();
+	//清空
+	void clear();
+..
+	//比较前面部分的buf是否相等,使用 other.m_length 为标准
+	bool is_equal_front(const Binary_buf& other);
+	//比较前面部分的buf是否相等,len为0时,使用strlen(buf)为标准,不比较结束符'\0'
+	bool is_equal_front(const char* p_buf, int len = 0);
+
+	//比较的buf是否全部相等,
+	bool is_equal_all(const Binary_buf& other);
+	//比较的buf是否全部相等,不比较结束符'\0'
+	bool is_equal_all(const char* p_buf);
+==public:==
+	char* get_buf()const;
+	int	get_length()const;
+==protected:==
+	char*		mp_buf;				//二进制缓存指针
+	int			m_length;			//二进制缓存长度
+==private:==
+}
+
+
+@enduml

+ 17 - 21
tool/pathcreator.cpp

@@ -4,6 +4,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <time.h>
+#include "../error_code/error_code.h"
 #include <stdint.h>
 #include <stdio.h>
 
@@ -17,11 +18,16 @@ PathCreator::~PathCreator()
 
 }
 
+int PathCreator::GetCurPath(std::string& path)
+{
+     path=m_current_path;
+     return SUCCESS;
+}
 std::string PathCreator::GetCurPath()
 {
     return m_current_path;
 }
-bool PathCreator::Mkdir(std::string dirName)
+int PathCreator::Mkdir(std::string dirName)
 {
     uint32_t beginCmpPath = 0;
     uint32_t endCmpPath = 0;
@@ -56,39 +62,29 @@ bool PathCreator::Mkdir(std::string dirName)
                     if(mkdir(curPath.c_str(), /*S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH*/0777) == -1)
                     {
                         printf("mkdir(%s) failed\n", curPath.c_str());
-                        return false;
+                        return FAILED;
                     }
                 }
             }
         }
         m_current_path=fullPath;
-        return true;
+        return SUCCESS;
 
 }
 
-bool PathCreator::CreateDatePath(std::string root, bool add_time)
+int PathCreator::CreateDatePath(std::string root)
 {
     time_t tt;
     time( &tt );
     tt = tt + 8*3600;  // transform the time zone
     tm* t= gmtime( &tt );
     char buf[255]={0};
-    if (add_time)
-    {
-        sprintf(buf, "%s/%d%02d%02d-%02d%02d%02d", root.c_str(),
-                t->tm_year + 1900,
-                t->tm_mon + 1,
-                t->tm_mday,
-                t->tm_hour,
-                t->tm_min,
-                t->tm_sec);
-    }
-    else
-    {
-        sprintf(buf, "%s/%d%02d%02d", root.c_str(),
-                t->tm_year + 1900,
-                t->tm_mon + 1,
-                t->tm_mday);
-    }
+    sprintf(buf,"%s/%d%02d%02d-%02d%02d%02d",root.c_str(),
+               t->tm_year + 1900,
+               t->tm_mon + 1,
+               t->tm_mday,
+               t->tm_hour,
+               t->tm_min,
+               t->tm_sec);
     return Mkdir(buf);
 }

+ 3 - 1
tool/pathcreator.h

@@ -7,8 +7,10 @@ class PathCreator
 public:
     PathCreator();
     ~PathCreator();
+    int GetCurPath(std::string& path);
+    int Mkdir(std::string dir);
+    int CreateDatePath(std::string root);
     std::string GetCurPath();
-    bool Mkdir(std::string dir);
     bool CreateDatePath(std::string root, bool add_time = true);
 protected:
     std::string m_current_path;

+ 144 - 0
tool/thread_condition.cpp

@@ -0,0 +1,144 @@
+
+
+/* Thread_condition 是多线程的条件控制类,主要是控制线程的启停和退出
+ * 线程创建后,一般是循环运行,
+ * 为了防止线程暂满整个cpu,那么需要线程在不工作的是否进入等待状态。
+ * Thread_condition 就可以控制线程的运行状态。
+ *
+	std::atomic<bool> m_pass_ever		//线程能否直接通过等待,对后面的线程也生效。
+	std::atomic<bool> m_pass_once		//线程能否直接通过等待,一次(通过一次之后,wait里面自动改为false)
+ * 外部调用notify系列的函数,唤醒等待的线程,让线程执行功能函数。
+ * 如果需要线程循环多次执行功能函数,那么就使用 notify_all(true),后面的线程可以直接通过等待了。
+ * 再使用 notify_all(false) ,即可停止线程,让其继续等待。
+ * 如果只想要线程执行一次,那就使用 notify_all(false, true)
+ * 注:notify_all(false, true)和notify_one(false, true) 一样,只能让其中一个线程执行一次
+ *
+ * m_kill_flag //是否杀死线程,让线程强制退出,
+ * 外部调用 kill_all() 函数,可以直接通知线程自动退出。
+	//杀死所有的线程,强制退出线程函数,只是操作受当前Thread_condition影响的所有线程
+	//唤醒所有线程,使其通过等待,但是不能运行功能函数,必须直接return
+	// 注:只是修改m_kill为true,需要线程函数实时检测kill的状态,来return线程。
+	//		通过等待之后,也要检查kill的状态,如果为真,那么就不能执行功能函数,应该直接return
+
+ 注:notify唤醒线程之后,wait里面的判断函数会重新判断。
+ */
+
+#include "thread_condition.h"
+
+Thread_condition::Thread_condition()
+{
+	m_kill_flag = false;
+	m_pass_ever = false;
+	m_pass_once = false;
+}
+Thread_condition::~Thread_condition()
+{
+	kill_all();
+}
+
+//无限等待,由 is_pass_wait 决定是否阻塞。
+//返回m_pass,
+bool Thread_condition::wait()
+{
+	std::unique_lock<std::mutex> loc(m_mutex);
+	m_condition_variable.wait(loc,std::bind(is_pass_wait,this));
+	bool t_pass = is_pass_wait(this);
+	m_pass_once = false;
+	return t_pass;
+}
+//等待一定的时间(默认时间单位:毫秒ms),由 is_pass_wait 决定是否阻塞。
+//return:is_pass_wait的结果,	true:线程直接通过等待,false:线程超时了,然后通过等待。
+//注意了:线程阻塞期间,是不会return的。
+bool Thread_condition::wait_for_millisecond(unsigned int millisecond)
+{
+	std::unique_lock<std::mutex> loc(m_mutex);
+	m_condition_variable.wait_for(loc, std::chrono::milliseconds(millisecond), std::bind(is_pass_wait, this));
+	bool t_pass = is_pass_wait(this);
+	m_pass_once = false;
+	return t_pass;
+}
+
+
+//唤醒已经阻塞的线程,唤醒一个线程
+//pass_ever 或者 pass_once 为真时,才能唤醒线程。都为假时,线程进入等待。
+void Thread_condition::notify_one(bool pass_ever, bool pass_once)
+{
+	std::unique_lock<std::mutex> loc(m_mutex);
+	m_pass_ever = pass_ever;
+	m_pass_once = pass_once;
+	m_condition_variable.notify_one();
+}
+//唤醒已经阻塞的线程,唤醒全部线程
+//pass_ever 或者 pass_once 为真时,才能唤醒线程。都为假时,线程进入等待。
+void Thread_condition::notify_all(bool pass_ever, bool pass_once)
+{
+	std::unique_lock<std::mutex> loc(m_mutex);
+	m_pass_ever = pass_ever;
+	m_pass_once = pass_once;
+	m_condition_variable.notify_all();
+}
+//注:notify_all(false, true)和notify_one(false, true) 一样,只能让其中一个线程执行一次
+
+
+//杀死所有的线程,强制退出线程函数,只是操作受当前Thread_condition影响的所有线程
+//唤醒所有线程,使其通过等待,但是不能运行功能函数,必须直接return
+// 注:只是修改m_kill为true,需要线程函数实时检测kill的状态,来return线程。
+//		通过等待之后,也要检查kill的状态,如果为真,那么就不能执行功能函数,应该直接return
+void Thread_condition::kill_all()
+{
+	std::unique_lock<std::mutex> loc(m_mutex);
+	m_kill_flag = true;
+	m_condition_variable.notify_all();
+}
+
+//判断是否或者,return !m_kill_flag
+bool Thread_condition::is_alive()
+{
+	return !m_kill_flag;
+}
+
+
+bool Thread_condition::get_kill_flag()
+{
+	return m_kill_flag;
+}
+bool Thread_condition::get_pass_ever()
+{
+	return m_pass_ever;
+}
+bool Thread_condition::get_pass_once()
+{
+	return m_pass_once;
+}
+void Thread_condition::set_kill_flag(bool kill)
+{
+	m_kill_flag = kill;
+}
+void Thread_condition::set_pass_ever(bool pass_ever)
+{
+	m_pass_ever = pass_ever;
+}
+void Thread_condition::set_pass_once(bool pass_once)
+{
+	m_pass_once = pass_once;
+}
+void Thread_condition::reset(bool kill, bool pass_ever, bool pass_once)
+{
+	m_kill_flag = kill;
+	m_pass_ever = pass_ever;
+	m_pass_once = pass_once;
+}
+
+
+//判断线程是否可以通过等待,wait系列函数的判断标志
+//注:m_kill或者m_pass为真时,return true
+bool Thread_condition::is_pass_wait(Thread_condition * other)
+{
+	if ( other == NULL )
+	{
+		throw (other);
+		return false;
+	}
+	return (other->m_kill_flag || other->m_pass_ever || other->m_pass_once);
+}
+

+ 114 - 0
tool/thread_condition.h

@@ -0,0 +1,114 @@
+
+
+/* Thread_condition 是多线程的条件控制类,主要是控制线程的启停和退出
+ * 线程创建后,一般是循环运行,
+ * 为了防止线程暂满整个cpu,那么需要线程在不工作的是否进入等待状态。
+ * Thread_condition 就可以控制线程的运行状态。
+ *
+	std::atomic<bool> m_pass_ever		//线程能否直接通过等待,对后面的线程也生效。
+	std::atomic<bool> m_pass_once		//线程能否直接通过等待,一次(通过一次之后,wait里面自动改为false)
+ * 外部调用notify系列的函数,唤醒等待的线程,让线程执行功能函数。
+ * 如果需要线程循环多次执行功能函数,那么就使用 notify_all(true),后面的线程可以直接通过等待了。
+ * 再使用 notify_all(false) ,即可停止线程,让其继续等待。
+ * 如果只想要线程执行一次,那就使用 notify_all(false, true)
+ * 注:notify_all(false, true)和notify_one(false, true) 一样,只能让其中一个线程执行一次
+ *
+ * m_kill_flag //是否杀死线程,让线程强制退出,
+ * 外部调用 kill_all() 函数,可以直接通知线程自动退出。
+	//杀死所有的线程,强制退出线程函数,只是操作受当前Thread_condition影响的所有线程
+	//唤醒所有线程,使其通过等待,但是不能运行功能函数,必须直接return
+	// 注:只是修改m_kill为true,需要线程函数实时检测kill的状态,来return线程。
+	//		通过等待之后,也要检查kill的状态,如果为真,那么就不能执行功能函数,应该直接return
+
+ 注:notify唤醒线程之后,wait里面的判断函数会重新判断。
+ */
+
+#ifndef LIDARMEASURE_THREAD_CONDITION_H
+#define LIDARMEASURE_THREAD_CONDITION_H
+
+#include <ratio>
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <mutex>
+#include <condition_variable>
+
+
+class Thread_condition
+{
+public:
+	Thread_condition();
+	Thread_condition(const Thread_condition& other) = delete;
+	~Thread_condition();
+
+	//无限等待,由 is_pass_wait 决定是否阻塞。
+	//返回m_pass,
+	bool wait();
+	//等待一定的时间(默认时间单位:毫秒ms),由 is_pass_wait 决定是否阻塞。
+	//return:is_pass_wait的结果,	true:线程直接通过等待,false:线程超时了,然后通过等待。
+	//注意了:线程阻塞期间,是不会return的。
+	bool wait_for_millisecond(unsigned int millisecond);
+
+	//等待一定的时间(时间单位可调),由 is_pass_wait 决定是否阻塞。
+	//return:is_pass_wait的结果,	true:线程直接通过等待,false:线程超时了,然后通过等待。
+	//注意了:线程阻塞期间,是不会return的。
+	template<typename _Rep, typename _Period>
+	bool wait_for_ex(const std::chrono::duration<_Rep, _Period>& time_duration);
+
+	//唤醒已经阻塞的线程,唤醒一个线程
+	//pass_ever 或者 pass_once 为真时,才能唤醒线程。都为假时,线程进入等待。
+	void notify_one(bool pass_ever, bool pass_once = false);
+	//唤醒已经阻塞的线程,唤醒全部线程
+	//pass_ever 或者 pass_once 为真时,才能唤醒线程。都为假时,线程进入等待。
+	void notify_all(bool pass_ever, bool pass_once = false);
+	//注:notify_all(false, true)和notify_one(false, true) 一样,只能让其中一个线程执行一次
+
+	//杀死所有的线程,强制退出线程函数,只是操作受当前Thread_condition影响的所有线程
+	//唤醒所有线程,使其通过等待,但是不能运行功能函数,必须直接return
+	// 注:只是修改m_kill为true,需要线程函数实时检测kill的状态,来return线程。
+	//		通过等待之后,也要检查kill的状态,如果为真,那么就不能执行功能函数,应该直接return
+	void kill_all();
+
+	//判断是否或者,return !m_kill_flag
+	bool is_alive();
+
+public:
+
+	bool get_kill_flag();
+	bool get_pass_ever();
+	bool get_pass_once();
+	void set_kill_flag(bool kill);
+	void set_pass_ever(bool pass_ever);
+	void set_pass_once(bool pass_once);
+	void reset(bool kill = false, bool pass_ever = false, bool pass_once = false);
+
+protected:
+	//判断线程是否可以通过等待,wait系列函数的判断标志
+	//注:m_kill或者m_pass为真时,return true
+	static bool is_pass_wait(Thread_condition * other);
+
+	std::atomic<bool> 		m_kill_flag;			//是否杀死线程,让线程强制退出,
+	std::atomic<bool> 		m_pass_ever;			//线程能否直接通过等待,对后面的线程也生效。
+	std::atomic<bool> 		m_pass_once;			//线程能否直接通过等待,一次(通过一次之后,wait里面自动改为false)
+
+	std::mutex 				m_mutex;				//线程的锁
+	std::condition_variable m_condition_variable;	//线程的条件变量
+
+private:
+
+};
+
+//等待一定的时间(时间单位可调),由 is_pass_wait 决定是否阻塞。
+//return:is_pass_wait的结果,	true:线程直接通过等待,false:线程超时了,然后通过等待。
+//注意了:线程阻塞期间,是不会return的。
+template<typename _Rep, typename _Period>
+bool Thread_condition::wait_for_ex(const std::chrono::duration<_Rep, _Period>& time_duration)
+{
+	std::unique_lock<std::mutex> loc(m_mutex);
+	m_condition_variable.wait_for(loc, std::chrono::duration<_Rep, _Period>(time_duration), std::bind(is_pass_wait, this));
+	bool t_pass = is_pass_wait(this);
+	m_pass_once = false;
+	return t_pass;
+}
+
+#endif //LIDARMEASURE_THREAD_CONDITION_H

+ 96 - 0
tool/thread_condition.puml

@@ -0,0 +1,96 @@
+@startuml
+skinparam classAttributeIconSize 0
+
+title  Thread_condition 是多线程的条件控制类,主要是控制线程的启停和退出
+note left of Thread_condition
+/* Thread_condition 是多线程的条件控制类,主要是控制线程的启停和退出
+ * 线程创建后,一般是循环运行,
+ * 为了防止线程暂满整个cpu,那么需要线程在不工作的是否进入等待状态。
+ * Thread_condition 就可以控制线程的运行状态。
+ *
+	std::atomic<bool> m_pass_ever		//线程能否直接通过等待,对后面的线程也生效。
+	std::atomic<bool> m_pass_once		//线程能否直接通过等待,一次(通过一次之后,wait里面自动改为false)
+ * 外部调用notify系列的函数,唤醒等待的线程,让线程执行功能函数。
+ * 如果需要线程循环多次执行功能函数,那么就使用 notify_all(true),后面的线程可以直接通过等待了。
+ * 再使用 notify_all(false) ,即可停止线程,让其继续等待。
+ * 如果只想要线程执行一次,那就使用 notify_all(false, true)
+ * 注:notify_all(false, true)和notify_one(false, true) 一样,只能让其中一个线程执行一次
+ *
+ * m_kill_flag //是否杀死线程,让线程强制退出,
+ * 外部调用 kill_all() 函数,可以直接通知线程自动退出。
+	//杀死所有的线程,强制退出线程函数,只是操作受当前Thread_condition影响的所有线程
+	//唤醒所有线程,使其通过等待,但是不能运行功能函数,必须直接return
+	// 注:只是修改m_kill为true,需要线程函数实时检测kill的状态,来return线程。
+	//		通过等待之后,也要检查kill的状态,如果为真,那么就不能执行功能函数,应该直接return
+
+ 注:notify唤醒线程之后,wait里面的判断函数会重新判断。
+ */
+end note
+
+
+
+class Thread_condition
+{
+==public:==
+	Thread_condition();
+	Thread_condition(const Thread_condition& other) = delete;
+	~Thread_condition();
+..
+	//无限等待,由 is_pass_wait 决定是否阻塞。
+	//返回m_pass,
+	bool wait();
+..
+	//等待一定的时间(默认时间单位:毫秒ms),由 is_pass_wait 决定是否阻塞。
+	//return:is_pass_wait的结果,	true:线程直接通过等待,false:线程超时了,然后通过等待。
+	//注意了:线程阻塞期间,是不会return的。
+	bool wait_for_millisecond(unsigned int millisecond);
+..
+	//等待一定的时间(时间单位可调),由 is_pass_wait 决定是否阻塞。
+	//return:is_pass_wait的结果,	true:线程直接通过等待,false:线程超时了,然后通过等待。
+	//注意了:线程阻塞期间,是不会return的。
+	template<typename _Rep, typename _Period>
+	bool wait_for_ex(const std::chrono::duration<_Rep, _Period>& time_duration);
+..
+	//唤醒已经阻塞的线程,唤醒一个线程
+	//pass_ever 或者 pass_once 为真时,才能唤醒线程。都为假时,线程进入等待。
+	void notify_one(bool pass_ever, bool pass_once = false);
+..
+	//唤醒已经阻塞的线程,唤醒全部线程
+	//pass_ever 或者 pass_once 为真时,才能唤醒线程。都为假时,线程进入等待。
+	void notify_all(bool pass_ever, bool pass_once = false);
+	//注:notify_all(false, true)和notify_one(false, true) 一样,只能让其中一个线程执行一次
+..
+	//杀死所有的线程,强制退出线程函数,只是操作受当前Thread_condition影响的所有线程
+	//唤醒所有线程,使其通过等待,但是不能运行功能函数,必须直接return
+	// 注:只是修改m_kill为true,需要线程函数实时检测kill的状态,来return线程。
+	//		通过等待之后,也要检查kill的状态,如果为真,那么就不能执行功能函数,应该直接return
+	void kill_all();
+..
+	//判断是否或者,return !m_kill_flag
+	bool is_alive();
+==public:==
+	bool get_kill_flag();
+	bool get_pass_ever();
+	bool get_pass_once();
+	void set_kill_flag(bool kill);
+	void set_pass_ever(bool pass_ever);
+	void set_pass_once(bool pass_once);
+	void reset(bool kill = false, bool pass_ever = false, bool pass_once = false);
+==protected:==
+	//判断线程是否可以通过等待,wait系列函数的判断标志
+	//注:m_kill或者m_pass为真时,return true
+	static bool is_pass_wait(Thread_condition * other);
+
+	std::atomic<bool> 		m_kill_flag;			//是否杀死线程,让线程强制退出,
+	std::atomic<bool> 		m_pass_ever;			//线程能否直接通过等待,对后面的线程也生效。
+	std::atomic<bool> 		m_pass_once;			//线程能否直接通过等待,一次(通过一次之后,wait里面自动改为false)
+
+	std::mutex 				m_mutex;				//线程的锁
+	std::condition_variable m_condition_variable;	//线程的条件变量
+
+==private:==
+
+}
+
+
+@enduml

+ 34 - 0
tool/thread_safe_queue.cpp

@@ -0,0 +1,34 @@
+
+
+/*
+ * (1)这个实现要求构建工具支持C++11的atomic std::mutex condition_veriable功能。这是C++11的基础特性,一般2011年以后的C++编译器都能支持。 例如,visual studio 2012以上。
+
+(2)这个类的实现中有两处使用了unique_lock而不是lock_guard,这是data_cond.wait所需要的,unique_lock是lock_guard的增强版。
+
+通过std::move的使用(前提是我们实现的类型T定义了移动构造函数和移动赋值函数),能利用移动语义带来的性能优势。
+
+使用shared_ptr<T>返回元素,用户无需释放元素的内存。
+
+
+原文链接:https://blog.csdn.net/weixin_41855721/article/details/81703818
+引用了他的思路,增加了一些功能函数, 补充了注释说明
+
+ termination_queue
+ 	// 在退出状态下,所有的功能函数不可用,返回false或者null。
+	// wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
+
+ pop系列函数
+	//(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
+	//(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
+	//(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
+
+注注注注注意了:模板类不支持分离编译。 模板类的实现必须放在头文件
+ 为了方便阅读和编程规范,依然将声明和实现分开,就像是把cpp文件的代码复制到h文件的尾部。
+
+ 如果将实现放到cpp里面,那么就要为cpp文件加 ifndef define endif
+ 然后在调用方include包含cpp文件,但是这样不好。
+ * */
+
+#include "thread_safe_queue.h"
+
+

+ 339 - 0
tool/thread_safe_queue.h

@@ -0,0 +1,339 @@
+
+
+/*
+ * (1)这个实现要求构建工具支持C++11的atomic mutex condition_veriable功能。这是C++11的基础特性,一般2011年以后的C++编译器都能支持。 例如,visual studio 2012以上。
+
+(2)这个类的实现中有两处使用了unique_lock而不是lock_guard,这是data_cond.wait所需要的,unique_lock是lock_guard的增强版。
+
+通过std::move的使用(前提是我们实现的类型T定义了移动构造函数和移动赋值函数),能利用移动语义带来的性能优势。
+
+使用shared_ptr<T>返回元素,用户无需释放元素的内存。
+
+
+原文链接:https://blog.csdn.net/weixin_41855721/article/details/81703818
+ 增加了一些功能函数,
+ 补充了注释说明
+
+ termination_queue
+ 	// 在退出状态下,所有的功能函数不可用,返回false或者null。
+	// wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
+
+ pop系列函数
+	//(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
+	//(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
+	//(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
+
+注注注注注意了:模板类不支持分离编译。 模板类的实现必须放在头文件
+ 为了方便阅读和编程规范,依然将声明和实现分开,就像是把cpp文件的代码复制到h文件的尾部。
+
+ 如果将实现放到cpp里面,那么就要为cpp文件加 ifndef define endif 防止重定义。
+ 然后在调用方include包含cpp文件,但是这样不好。
+
+
+ * */
+
+#ifndef LIDARMEASURE_THREAD_SAFE_QUEUE_H
+#define LIDARMEASURE_THREAD_SAFE_QUEUE_H
+
+#include <queue>
+
+#include <atomic>
+#include <mutex>
+#include <condition_variable>
+
+
+template<class T>
+class Thread_safe_queue
+{
+public:
+	Thread_safe_queue();
+	Thread_safe_queue(const Thread_safe_queue& other);
+	~Thread_safe_queue();
+
+	//(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
+	//(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
+	//(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
+
+	//等待并弹出数据,成功弹出则返回true
+	// 队列为空则无限等待,termination终止队列,则返回false
+	bool wait_and_pop(T& value);
+	//尝试弹出数据,成功弹出则返回true
+	//队列为空 或者 termination终止队列,返回false
+	bool try_pop(T& value);
+	//等待并弹出数据,成功弹出则返回true
+	// 队列为空则无限等待,termination终止队列,则返回false
+	std::shared_ptr<T> wait_and_pop();
+	//尝试弹出数据,成功弹出则返回true
+	//队列为空 或者 termination终止队列,返回false
+	std::shared_ptr<T> try_pop();
+	//插入一项,并唤醒一个线程,
+	//如果成功插入,则返回true,  失败则返回false
+	//注:只能唤醒一个线程,防止多线程误判empty()
+	bool push(T new_value);
+	//清除队列,只是将队列的实例抛出。T是实例内存,系统自动回收的。
+	bool clear();
+	//清除队列,抛出之后还要delete指针。T是动态内存,需要手动回收的。
+	bool clear_and_delete();
+
+public:
+	//判空
+	bool empty();
+	//获取队列大小
+	size_t size();
+	//设置队列为退出状态。并唤醒所有的线程,使其通过wait
+	// 在退出状态下,所有的功能函数不可用,必须直接返回false或者null。
+	// wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
+	void termination_queue();
+	//唤醒队列,恢复所有的功能函数。wait_and_pop会继续阻塞。
+	void wake_queue();
+	//获取退出状态
+	bool get_termination_flag();
+	//判断是否可以直接通过wait,  m_data_queue不为空或者m_termination终止时都可以通过等待。
+	bool is_pass();
+
+protected:
+	std::mutex 						m_mutex;				//队列的锁
+	std::queue<std::shared_ptr<T>> 	m_data_queue;			//队列数据,使用智能指针shared_ptr
+	std::condition_variable 		m_data_cond;			//条件变量
+	std::atomic<bool> 				m_termination_flag;		//终止标志位
+
+private:
+
+
+};
+
+
+
+
+
+
+
+
+template<class T>
+Thread_safe_queue<T>::Thread_safe_queue()
+{
+	m_termination_flag = false;
+}
+template<class T>
+Thread_safe_queue<T>::Thread_safe_queue(const Thread_safe_queue& other)
+{
+	std::unique_lock<std::mutex> lock_this(m_mutex);
+	std::unique_lock<std::mutex> lock_other(other.m_mutex);
+	m_data_queue = other.data_queue;
+	m_termination_flag = other.m_termination_flag;
+}
+template<class T>
+Thread_safe_queue<T>::~Thread_safe_queue()
+{
+	//析构时,终止队列,让线程通过等待,方便线程推出。
+	termination_queue();
+}
+
+//(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
+//(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
+//(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
+
+//等待并弹出数据,成功弹出则返回true
+// 队列为空则无限等待,termination终止队列,则返回false
+template<class T>
+bool Thread_safe_queue<T>::wait_and_pop(T& value)
+{
+	if ( m_termination_flag )
+	{
+		return false;
+	}
+	else
+	{
+		std::unique_lock<std::mutex> lk(m_mutex);
+		//无限等待,一直阻塞,除非有新的数据加入或者终止队列
+		m_data_cond.wait(lk, [this]
+		{ return ((!m_data_queue.empty()) || m_termination_flag); });
+		if (m_termination_flag)
+		{
+			return false;
+		}
+		else
+		{
+			value = move(*m_data_queue.front());
+			m_data_queue.pop();
+			return true;
+		}
+	}
+}
+//尝试弹出数据,成功弹出则返回true
+//队列为空 或者 termination终止队列,返回false
+template<class T>
+bool Thread_safe_queue<T>::try_pop(T& value)
+{
+	if ( m_termination_flag )
+	{
+		return false;
+	}
+	else
+	{
+		std::unique_lock<std::mutex> lk(m_mutex);
+		if (m_data_queue.empty())
+		{
+			return false;
+		}
+		else
+		{
+			value = move(*m_data_queue.front());
+			m_data_queue.pop();
+			return true;
+		}
+	}
+}
+//等待并弹出数据,成功弹出则返回true
+// 队列为空则无限等待,termination终止队列,则返回false
+template<class T>
+std::shared_ptr<T> Thread_safe_queue<T>::wait_and_pop()
+{
+	if ( m_termination_flag )
+	{
+		return NULL;
+	}
+	else
+	{
+		std::unique_lock<std::mutex> lk(m_mutex);
+		//无限等待,一直阻塞,除非有新的数据加入或者终止队列
+		m_data_cond.wait(lk, [this]
+		{ return ((!m_data_queue.empty()) || m_termination_flag); });
+		if (m_termination_flag)
+		{
+			return NULL;
+		}
+		else
+		{
+			std::shared_ptr<T> res = m_data_queue.front();
+			m_data_queue.pop();
+			return res;
+		}
+	}
+}
+//尝试弹出数据,成功弹出则返回true
+//队列为空 或者 termination终止队列,返回false
+template<class T>
+std::shared_ptr<T> Thread_safe_queue<T>::try_pop()
+{
+	if ( m_termination_flag )
+	{
+		return NULL;
+	}
+	else
+	{
+		std::unique_lock<std::mutex> lk(m_mutex);
+		if (m_data_queue.empty())
+		{
+			return NULL;
+		}
+		else
+		{
+			std::shared_ptr<T> res = m_data_queue.front();
+			m_data_queue.pop();
+			return res;
+		}
+	}
+}
+//插入一项,并唤醒一个线程,
+//如果成功插入,则返回true,  失败则返回false
+//注:只能唤醒一个线程,防止多线程误判empty()
+template<class T>
+bool Thread_safe_queue<T>::push(T new_value)
+{
+	if (m_termination_flag)
+	{
+		return false;
+	}
+	else
+	{
+		std::shared_ptr<T> data(std::make_shared<T>(move(new_value)));
+		std::unique_lock<std::mutex> lk(m_mutex);
+		m_data_queue.push(data);
+		m_data_cond.notify_one();
+		return true;
+	}
+}
+//清除队列,只是将队列的实例抛出。T是实例内存,系统自动回收的。
+template<class T>
+bool Thread_safe_queue<T>::clear()
+{
+		std::unique_lock<std::mutex> lk(m_mutex);
+		while (!m_data_queue.empty())
+		{
+			m_data_queue.pop();
+		}
+		return true;
+
+}
+//清除队列,抛出之后还要delete指针。T是动态内存,需要手动回收的。
+template<class T>
+bool Thread_safe_queue<T>::clear_and_delete()
+{
+		std::unique_lock<std::mutex> lk(m_mutex);
+		while (!m_data_queue.empty())
+		{
+			T res = NULL;
+			res = move(*m_data_queue.front());
+			m_data_queue.pop();
+			if(res != NULL)
+			{
+				delete(res);
+
+			}
+		}
+	return true;
+
+}
+
+//判空
+template<class T>
+bool Thread_safe_queue<T>::empty()
+{
+	std::unique_lock<std::mutex> lk(m_mutex);
+	return m_data_queue.empty();
+}
+//获取队列大小
+template<class T>
+size_t Thread_safe_queue<T>::size()
+{
+	std::unique_lock<std::mutex> lk(m_mutex);
+	return m_data_queue.size();
+}
+//设置队列为退出状态。并唤醒所有的线程,使其通过wait
+// 在退出状态下,所有的功能函数不可用,必须直接返回false或者null。
+// wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
+template<class T>
+void Thread_safe_queue<T>::termination_queue()
+{
+	std::unique_lock<std::mutex> lk(m_mutex);
+	m_termination_flag = true;
+	m_data_cond.notify_all();
+}
+//唤醒队列,恢复所有的功能函数。wait_and_pop会继续阻塞。
+template<class T>
+void Thread_safe_queue<T>::wake_queue()
+{
+	std::unique_lock<std::mutex> lk(m_mutex);
+	m_termination_flag = false;
+	m_data_cond.notify_all();
+}
+//获取退出状态
+template<class T>
+bool Thread_safe_queue<T>::get_termination_flag()
+{
+	return m_termination_flag;
+}
+//判断是否可以直接通过wait,  m_data_queue不为空或者m_termination终止时都可以通过等待。
+template<class T>
+bool Thread_safe_queue<T>::is_pass()
+{
+	return (!m_data_queue.empty() || m_termination_flag);
+}
+
+
+
+
+
+
+#endif //LIDARMEASURE_THREAD_SAFE_QUEUE_H

+ 108 - 0
tool/thread_safe_queue.puml

@@ -0,0 +1,108 @@
+@startuml
+skinparam classAttributeIconSize 0
+
+title  Thread_safe_queue 安全线程队列
+
+note left of Thread_safe_queue
+
+/*
+ * (1)这个实现要求构建工具支持C++11的atomic mutex condition_veriable功能。这是C++11的基础特性,一般2011年以后的C++编译器都能支持。 例如,visual studio 2012以上。
+
+(2)这个类的实现中有两处使用了unique_lock而不是lock_guard,这是data_cond.wait所需要的,unique_lock是lock_guard的增强版。
+
+通过std::move的使用(前提是我们实现的类型T定义了移动构造函数和移动赋值函数),能利用移动语义带来的性能优势。
+
+使用shared_ptr<T>返回元素,用户无需释放元素的内存。
+
+
+原文链接:https://blog.csdn.net/weixin_41855721/article/details/81703818
+ 增加了一些功能函数,
+ 补充了注释说明
+
+ termination_queue
+ 	// 在退出状态下,所有的功能函数不可用,返回false或者null。
+	// wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
+
+ pop系列函数
+	//(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
+	//(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
+	//(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
+
+注注注注注意了:模板类不支持分离编译。 模板类的实现必须放在头文件
+ 为了方便阅读和编程规范,依然将声明和实现分开,就像是把cpp文件的代码复制到h文件的尾部。
+
+ 如果将实现放到cpp里面,那么就要为cpp文件加 ifndef define endif 防止重定义。
+ 然后在调用方include包含cpp文件,但是这样不好。
+
+
+ * */
+end note
+
+
+
+class Thread_safe_queue <<    template<class T>    >>
+{
+==public:==
+	Thread_safe_queue();
+	Thread_safe_queue(const Thread_safe_queue& other);
+	~Thread_safe_queue();
+..
+	//(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
+	//(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
+	//(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
+	//等待并弹出数据,成功弹出则返回true
+	// 队列为空则无限等待,termination终止队列,则返回false
+	bool wait_and_pop(T& value);
+..
+	//尝试弹出数据,成功弹出则返回true
+	//队列为空 或者 termination终止队列,返回false
+	bool try_pop(T& value);
+..
+	//等待并弹出数据,成功弹出则返回true
+	// 队列为空则无限等待,termination终止队列,则返回false
+	std::shared_ptr<T> wait_and_pop();
+..
+	//尝试弹出数据,成功弹出则返回true
+	//队列为空 或者 termination终止队列,返回false
+	std::shared_ptr<T> try_pop();
+..
+	//插入一项,并唤醒一个线程,
+	//如果成功插入,则返回true,  失败则返回false
+	//注:只能唤醒一个线程,防止多线程误判empty()
+	bool push(T new_value);
+..
+	//清除队列,只是将队列的实例抛出。T是实例内存,系统自动回收的。
+	bool clear();
+..
+	//清除队列,抛出之后还要delete指针。T是动态内存,需要手动回收的。
+	bool clear_and_delete();
+==public:==
+	//判空
+	bool empty();
+..
+	//获取队列大小
+	size_t size();
+..
+	//设置队列为退出状态。并唤醒所有的线程,使其通过wait
+	// 在退出状态下,所有的功能函数不可用,必须直接返回false或者null。
+	// wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
+	void termination_queue();
+..
+	//唤醒队列,恢复所有的功能函数。wait_and_pop会继续阻塞。
+	void wake_queue();
+..
+	//获取退出状态
+	bool get_termination_flag();
+..
+	//判断是否可以直接通过wait,  m_data_queue不为空或者m_termination终止时都可以通过等待。
+	bool is_pass();
+==protected:==
+	std::mutex 						m_mutex;				//队列的锁
+	std::queue<std::shared_ptr<T>> 	m_data_queue;			//队列数据,使用智能指针shared_ptr
+	std::condition_variable 		m_data_cond;			//条件变量
+	std::atomic<bool> 				m_termination_flag;		//终止标志位
+==private:==
+}
+
+
+@enduml