瀏覽代碼

20200223,master

huli 4 年之前
當前提交
e91f300787
共有 80 個文件被更改,包括 29651 次插入0 次删除
  1. 93 0
      CMakeLists.txt
  2. 729 0
      communication/communication.pb.cc
  3. 530 0
      communication/communication.pb.h
  4. 14 0
      communication/communication.proto
  5. 93 0
      communication/communication_message.cpp
  6. 122 0
      communication/communication_message.h
  7. 610 0
      communication/communication_socket_base.cpp
  8. 165 0
      communication/communication_socket_base.h
  9. 847 0
      dispatch/carrier_base.cpp
  10. 152 0
      dispatch/carrier_base.h
  11. 82 0
      dispatch/carrier_task.cpp
  12. 72 0
      dispatch/carrier_task.h
  13. 216 0
      dispatch/dispatch_communication.cpp
  14. 185 0
      dispatch/dispatch_communication.h
  15. 113 0
      dispatch/dispatch_manager.cpp
  16. 99 0
      dispatch/dispatch_manager.h
  17. 536 0
      error_code/dispatch.error_code.h
  18. 547 0
      error_code/error_code.cpp
  19. 542 0
      error_code/error_code.h
  20. 41 0
      hulitest.sh
  21. 152 0
      main.cpp
  22. 2817 0
      message/dispatch_message.pb.cc
  23. 1974 0
      message/dispatch_message.pb.h
  24. 135 0
      message/dispatch_message.proto
  25. 3815 0
      message/measure_message.pb.cc
  26. 2658 0
      message/measure_message.pb.h
  27. 144 0
      message/measure_message.proto
  28. 3306 0
      message/message_base.pb.cc
  29. 2411 0
      message/message_base.pb.h
  30. 210 0
      message/message_base.proto
  31. 12 0
      proto.sh
  32. 26 0
      setting/communication.prototxt
  33. 86 0
      setting/laser.prototxt
  34. 54 0
      setting/locate.prototxt
  35. 10 0
      setting/snap7_communication.prototxt
  36. 182 0
      snap7_communication/plc_data.cpp
  37. 75 0
      snap7_communication/plc_data.h
  38. 85 0
      snap7_communication/s7_plc.cpp
  39. 32 0
      snap7_communication/s7_plc.h
  40. 161 0
      snap7_communication/snap7_buf.cpp
  41. 79 0
      snap7_communication/snap7_buf.h
  42. 686 0
      snap7_communication/snap7_communication.pb.cc
  43. 439 0
      snap7_communication/snap7_communication.pb.h
  44. 12 0
      snap7_communication/snap7_communication.proto
  45. 326 0
      snap7_communication/snap7_communication_base.cpp
  46. 102 0
      snap7_communication/snap7_communication_base.h
  47. 123 0
      system/system_communication.cpp
  48. 46 0
      system/system_communication.h
  49. 415 0
      system/system_executor.cpp
  50. 85 0
      system/system_executor.h
  51. 161 0
      task/task_base.cpp
  52. 142 0
      task/task_base.h
  53. 80 0
      task/task_base.puml
  54. 56 0
      task/task_command_manager.cpp
  55. 42 0
      task/task_command_manager.h
  56. 12 0
      task/task_command_manager.puml
  57. 341 0
      tool/binary_buf.cpp
  58. 91 0
      tool/binary_buf.h
  59. 85 0
      tool/binary_buf.puml
  60. 41 0
      tool/common_data.cpp
  61. 57 0
      tool/common_data.h
  62. 94 0
      tool/pathcreator.cpp
  63. 18 0
      tool/pathcreator.h
  64. 0 0
      tool/pcl_cloud_with_lock.cpp
  65. 30 0
      tool/pcl_cloud_with_lock.h
  66. 139 0
      tool/point2D_tool.cpp
  67. 81 0
      tool/point2D_tool.h
  68. 42 0
      tool/proto_tool.cpp
  69. 56 0
      tool/proto_tool.h
  70. 4 0
      tool/singleton.cpp
  71. 81 0
      tool/singleton.h
  72. 175 0
      tool/thread_condition.cpp
  73. 183 0
      tool/thread_condition.h
  74. 96 0
      tool/thread_condition.puml
  75. 262 0
      tool/thread_pool.h
  76. 6 0
      tool/thread_safe_list.cpp
  77. 350 0
      tool/thread_safe_list.h
  78. 34 0
      tool/thread_safe_queue.cpp
  79. 338 0
      tool/thread_safe_queue.h
  80. 108 0
      tool/thread_safe_queue.puml

+ 93 - 0
CMakeLists.txt

@@ -0,0 +1,93 @@
+project(nnxx_tests)
+
+cmake_minimum_required(VERSION 3.5)
+
+set (CMAKE_CXX_STANDARD 11)
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(nanomsg REQUIRED nanomsg)
+FIND_PACKAGE(Protobuf REQUIRED)
+FIND_PACKAGE(Glog REQUIRED)
+FIND_PACKAGE(OpenCV REQUIRED)
+FIND_PACKAGE(PCL REQUIRED)
+
+
+MESSAGE(WARN "pcl:: ${PCL_INCLUDE_DIRS} --- ${PCL_LIBRARIES}")
+include_directories(
+        /usr/local/include
+		/usr/local/include/snap7
+        ${PCL_INCLUDE_DIRS}
+        ${OpenCV_INCLUDE_DIRS}
+        ${PROTOBUF_INCLUDE_DIRS}
+        laser
+        Locate
+        communication
+        message
+        error_code
+        tool
+	system
+)
+link_directories("/usr/local/lib")
+
+message(STATUS ${EXECUTABLE_OUTPUT_PATH})
+
+
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/error_code error_src )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/message message_src )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/lidar_locate locate_src )
+#aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/robot robot_src )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/laser LASER_SRC )
+#aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/plc PLC_SRC )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/locate LOCATE_SRC )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/terminor TERMINOR_SRC )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/task TASK_MANAGER_SRC )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/tool TOOL_SRC )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/communication COMMUNICATION_SRC )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/system SYSTEM_SRC )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/dispatch DISPATCH_SRC )
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/snap7_communication SNAP7_COMMUNICATION_SRC )
+
+
+add_executable(terminal
+        main.cpp
+        ${error_src}
+        ${locate_src}
+        ${robot_src}
+        ${message_src}
+
+        ${LASER_SRC}
+        ${PLC_SRC}
+        ${TERMINOR_SRC}
+        ${LOCATE_SRC}
+        ${TASK_MANAGER_SRC}
+        ${TOOL_SRC}
+		${COMMUNICATION_SRC}
+		${SNAP7_COMMUNICATION_SRC}
+        ${SYSTEM_SRC}
+		${DISPATCH_SRC}
+
+		)
+
+
+
+target_link_libraries(terminal
+        /usr/local/lib/libglog.a
+        /usr/local/lib/libgflags.a
+#        /usr/local/lib/liblivox_sdk_static.a
+#        /usr/local/apr/lib/libapr-1.a
+        nnxx
+        nanomsg
+
+        ${PROTOBUF_LIBRARIES}
+        ${OpenCV_LIBS}
+        ${GLOG_LIBRARIES}
+        ${PCL_LIBRARIES}
+        ${PROTOBUF_LIBRARIES}
+
+        libtensorflow_cc.so
+        #tf_3dcnn_api.so
+        pointSIFT_API.so
+		snap7
+        -lpthread
+        )
+

+ 729 - 0
communication/communication.pb.cc

@@ -0,0 +1,729 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: communication.proto
+
+#include "communication.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// This is a temporary google only hack
+#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+#include "third_party/protobuf/version.h"
+#endif
+// @@protoc_insertion_point(includes)
+namespace Communication_proto {
+class Communication_parameterDefaultTypeInternal {
+ public:
+  ::google::protobuf::internal::ExplicitlyConstructed<Communication_parameter>
+      _instance;
+} _Communication_parameter_default_instance_;
+class Communication_parameter_allDefaultTypeInternal {
+ public:
+  ::google::protobuf::internal::ExplicitlyConstructed<Communication_parameter_all>
+      _instance;
+} _Communication_parameter_all_default_instance_;
+}  // namespace Communication_proto
+namespace protobuf_communication_2eproto {
+void InitDefaultsCommunication_parameterImpl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  ::google::protobuf::internal::InitProtobufDefaultsForceUnique();
+#else
+  ::google::protobuf::internal::InitProtobufDefaults();
+#endif  // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  {
+    void* ptr = &::Communication_proto::_Communication_parameter_default_instance_;
+    new (ptr) ::Communication_proto::Communication_parameter();
+    ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
+  }
+  ::Communication_proto::Communication_parameter::InitAsDefaultInstance();
+}
+
+void InitDefaultsCommunication_parameter() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsCommunication_parameterImpl);
+}
+
+void InitDefaultsCommunication_parameter_allImpl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  ::google::protobuf::internal::InitProtobufDefaultsForceUnique();
+#else
+  ::google::protobuf::internal::InitProtobufDefaults();
+#endif  // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  protobuf_communication_2eproto::InitDefaultsCommunication_parameter();
+  {
+    void* ptr = &::Communication_proto::_Communication_parameter_all_default_instance_;
+    new (ptr) ::Communication_proto::Communication_parameter_all();
+    ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
+  }
+  ::Communication_proto::Communication_parameter_all::InitAsDefaultInstance();
+}
+
+void InitDefaultsCommunication_parameter_all() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsCommunication_parameter_allImpl);
+}
+
+::google::protobuf::Metadata file_level_metadata[2];
+
+const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Communication_proto::Communication_parameter, _has_bits_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Communication_proto::Communication_parameter, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Communication_proto::Communication_parameter, bind_string_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Communication_proto::Communication_parameter, connect_string_vector_),
+  0,
+  ~0u,
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Communication_proto::Communication_parameter_all, _has_bits_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Communication_proto::Communication_parameter_all, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Communication_proto::Communication_parameter_all, communication_parameters_),
+  0,
+};
+static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, 7, sizeof(::Communication_proto::Communication_parameter)},
+  { 9, 15, sizeof(::Communication_proto::Communication_parameter_all)},
+};
+
+static ::google::protobuf::Message const * const file_default_instances[] = {
+  reinterpret_cast<const ::google::protobuf::Message*>(&::Communication_proto::_Communication_parameter_default_instance_),
+  reinterpret_cast<const ::google::protobuf::Message*>(&::Communication_proto::_Communication_parameter_all_default_instance_),
+};
+
+void protobuf_AssignDescriptors() {
+  AddDescriptors();
+  ::google::protobuf::MessageFactory* factory = NULL;
+  AssignDescriptors(
+      "communication.proto", schemas, file_default_instances, TableStruct::offsets, factory,
+      file_level_metadata, NULL, NULL);
+}
+
+void protobuf_AssignDescriptorsOnce() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 2);
+}
+
+void AddDescriptorsImpl() {
+  InitDefaults();
+  static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+      "\n\023communication.proto\022\023Communication_pro"
+      "to\"M\n\027Communication_parameter\022\023\n\013bind_st"
+      "ring\030\001 \001(\t\022\035\n\025connect_string_vector\030\002 \003("
+      "\t\"m\n\033Communication_parameter_all\022N\n\030comm"
+      "unication_parameters\030\001 \001(\0132,.Communicati"
+      "on_proto.Communication_parameter"
+  };
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+      descriptor, 232);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "communication.proto", &protobuf_RegisterTypes);
+}
+
+void AddDescriptors() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
+}
+// Force AddDescriptors() to be called at dynamic initialization time.
+struct StaticDescriptorInitializer {
+  StaticDescriptorInitializer() {
+    AddDescriptors();
+  }
+} static_descriptor_initializer;
+}  // namespace protobuf_communication_2eproto
+namespace Communication_proto {
+
+// ===================================================================
+
+void Communication_parameter::InitAsDefaultInstance() {
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Communication_parameter::kBindStringFieldNumber;
+const int Communication_parameter::kConnectStringVectorFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Communication_parameter::Communication_parameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
+    ::protobuf_communication_2eproto::InitDefaultsCommunication_parameter();
+  }
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:Communication_proto.Communication_parameter)
+}
+Communication_parameter::Communication_parameter(const Communication_parameter& from)
+  : ::google::protobuf::Message(),
+      _internal_metadata_(NULL),
+      _has_bits_(from._has_bits_),
+      _cached_size_(0),
+      connect_string_vector_(from.connect_string_vector_) {
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  bind_string_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (from.has_bind_string()) {
+    bind_string_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.bind_string_);
+  }
+  // @@protoc_insertion_point(copy_constructor:Communication_proto.Communication_parameter)
+}
+
+void Communication_parameter::SharedCtor() {
+  _cached_size_ = 0;
+  bind_string_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+Communication_parameter::~Communication_parameter() {
+  // @@protoc_insertion_point(destructor:Communication_proto.Communication_parameter)
+  SharedDtor();
+}
+
+void Communication_parameter::SharedDtor() {
+  bind_string_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void Communication_parameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Communication_parameter::descriptor() {
+  ::protobuf_communication_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_communication_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
+}
+
+const Communication_parameter& Communication_parameter::default_instance() {
+  ::protobuf_communication_2eproto::InitDefaultsCommunication_parameter();
+  return *internal_default_instance();
+}
+
+Communication_parameter* Communication_parameter::New(::google::protobuf::Arena* arena) const {
+  Communication_parameter* n = new Communication_parameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Communication_parameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:Communication_proto.Communication_parameter)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  connect_string_vector_.Clear();
+  cached_has_bits = _has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    GOOGLE_DCHECK(!bind_string_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
+    (*bind_string_.UnsafeRawStringPointer())->clear();
+  }
+  _has_bits_.Clear();
+  _internal_metadata_.Clear();
+}
+
+bool Communication_parameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:Communication_proto.Communication_parameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string bind_string = 1;
+      case 1: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_bind_string()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->bind_string().data(), static_cast<int>(this->bind_string().length()),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "Communication_proto.Communication_parameter.bind_string");
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      // repeated string connect_string_vector = 2;
+      case 2: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(18u /* 18 & 0xFF */)) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_connect_string_vector()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->connect_string_vector(this->connect_string_vector_size() - 1).data(),
+            static_cast<int>(this->connect_string_vector(this->connect_string_vector_size() - 1).length()),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "Communication_proto.Communication_parameter.connect_string_vector");
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:Communication_proto.Communication_parameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:Communication_proto.Communication_parameter)
+  return false;
+#undef DO_
+}
+
+void Communication_parameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:Communication_proto.Communication_parameter)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  // optional string bind_string = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->bind_string().data(), static_cast<int>(this->bind_string().length()),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "Communication_proto.Communication_parameter.bind_string");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->bind_string(), output);
+  }
+
+  // repeated string connect_string_vector = 2;
+  for (int i = 0, n = this->connect_string_vector_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->connect_string_vector(i).data(), static_cast<int>(this->connect_string_vector(i).length()),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "Communication_proto.Communication_parameter.connect_string_vector");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      2, this->connect_string_vector(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        _internal_metadata_.unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:Communication_proto.Communication_parameter)
+}
+
+::google::protobuf::uint8* Communication_parameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:Communication_proto.Communication_parameter)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  // optional string bind_string = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->bind_string().data(), static_cast<int>(this->bind_string().length()),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "Communication_proto.Communication_parameter.bind_string");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->bind_string(), target);
+  }
+
+  // repeated string connect_string_vector = 2;
+  for (int i = 0, n = this->connect_string_vector_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->connect_string_vector(i).data(), static_cast<int>(this->connect_string_vector(i).length()),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "Communication_proto.Communication_parameter.connect_string_vector");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(2, this->connect_string_vector(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:Communication_proto.Communication_parameter)
+  return target;
+}
+
+size_t Communication_parameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:Communication_proto.Communication_parameter)
+  size_t total_size = 0;
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        _internal_metadata_.unknown_fields());
+  }
+  // repeated string connect_string_vector = 2;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->connect_string_vector_size());
+  for (int i = 0, n = this->connect_string_vector_size(); i < n; i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->connect_string_vector(i));
+  }
+
+  // optional string bind_string = 1;
+  if (has_bind_string()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->bind_string());
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Communication_parameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:Communication_proto.Communication_parameter)
+  GOOGLE_DCHECK_NE(&from, this);
+  const Communication_parameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const Communication_parameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Communication_proto.Communication_parameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Communication_proto.Communication_parameter)
+    MergeFrom(*source);
+  }
+}
+
+void Communication_parameter::MergeFrom(const Communication_parameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:Communication_proto.Communication_parameter)
+  GOOGLE_DCHECK_NE(&from, this);
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  connect_string_vector_.MergeFrom(from.connect_string_vector_);
+  if (from.has_bind_string()) {
+    set_has_bind_string();
+    bind_string_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.bind_string_);
+  }
+}
+
+void Communication_parameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Communication_proto.Communication_parameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Communication_parameter::CopyFrom(const Communication_parameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Communication_proto.Communication_parameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Communication_parameter::IsInitialized() const {
+  return true;
+}
+
+void Communication_parameter::Swap(Communication_parameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Communication_parameter::InternalSwap(Communication_parameter* other) {
+  using std::swap;
+  connect_string_vector_.InternalSwap(&other->connect_string_vector_);
+  bind_string_.Swap(&other->bind_string_);
+  swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Communication_parameter::GetMetadata() const {
+  protobuf_communication_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_communication_2eproto::file_level_metadata[kIndexInFileMessages];
+}
+
+
+// ===================================================================
+
+void Communication_parameter_all::InitAsDefaultInstance() {
+  ::Communication_proto::_Communication_parameter_all_default_instance_._instance.get_mutable()->communication_parameters_ = const_cast< ::Communication_proto::Communication_parameter*>(
+      ::Communication_proto::Communication_parameter::internal_default_instance());
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Communication_parameter_all::kCommunicationParametersFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Communication_parameter_all::Communication_parameter_all()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
+    ::protobuf_communication_2eproto::InitDefaultsCommunication_parameter_all();
+  }
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:Communication_proto.Communication_parameter_all)
+}
+Communication_parameter_all::Communication_parameter_all(const Communication_parameter_all& from)
+  : ::google::protobuf::Message(),
+      _internal_metadata_(NULL),
+      _has_bits_(from._has_bits_),
+      _cached_size_(0) {
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  if (from.has_communication_parameters()) {
+    communication_parameters_ = new ::Communication_proto::Communication_parameter(*from.communication_parameters_);
+  } else {
+    communication_parameters_ = NULL;
+  }
+  // @@protoc_insertion_point(copy_constructor:Communication_proto.Communication_parameter_all)
+}
+
+void Communication_parameter_all::SharedCtor() {
+  _cached_size_ = 0;
+  communication_parameters_ = NULL;
+}
+
+Communication_parameter_all::~Communication_parameter_all() {
+  // @@protoc_insertion_point(destructor:Communication_proto.Communication_parameter_all)
+  SharedDtor();
+}
+
+void Communication_parameter_all::SharedDtor() {
+  if (this != internal_default_instance()) delete communication_parameters_;
+}
+
+void Communication_parameter_all::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Communication_parameter_all::descriptor() {
+  ::protobuf_communication_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_communication_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
+}
+
+const Communication_parameter_all& Communication_parameter_all::default_instance() {
+  ::protobuf_communication_2eproto::InitDefaultsCommunication_parameter_all();
+  return *internal_default_instance();
+}
+
+Communication_parameter_all* Communication_parameter_all::New(::google::protobuf::Arena* arena) const {
+  Communication_parameter_all* n = new Communication_parameter_all;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Communication_parameter_all::Clear() {
+// @@protoc_insertion_point(message_clear_start:Communication_proto.Communication_parameter_all)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    GOOGLE_DCHECK(communication_parameters_ != NULL);
+    communication_parameters_->Clear();
+  }
+  _has_bits_.Clear();
+  _internal_metadata_.Clear();
+}
+
+bool Communication_parameter_all::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:Communication_proto.Communication_parameter_all)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .Communication_proto.Communication_parameter communication_parameters = 1;
+      case 1: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
+               input, mutable_communication_parameters()));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:Communication_proto.Communication_parameter_all)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:Communication_proto.Communication_parameter_all)
+  return false;
+#undef DO_
+}
+
+void Communication_parameter_all::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:Communication_proto.Communication_parameter_all)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  // optional .Communication_proto.Communication_parameter communication_parameters = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, *this->communication_parameters_, output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        _internal_metadata_.unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:Communication_proto.Communication_parameter_all)
+}
+
+::google::protobuf::uint8* Communication_parameter_all::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:Communication_proto.Communication_parameter_all)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  // optional .Communication_proto.Communication_parameter communication_parameters = 1;
+  if (cached_has_bits & 0x00000001u) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageToArray(
+        1, *this->communication_parameters_, deterministic, target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:Communication_proto.Communication_parameter_all)
+  return target;
+}
+
+size_t Communication_parameter_all::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:Communication_proto.Communication_parameter_all)
+  size_t total_size = 0;
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        _internal_metadata_.unknown_fields());
+  }
+  // optional .Communication_proto.Communication_parameter communication_parameters = 1;
+  if (has_communication_parameters()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSize(
+        *this->communication_parameters_);
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Communication_parameter_all::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:Communication_proto.Communication_parameter_all)
+  GOOGLE_DCHECK_NE(&from, this);
+  const Communication_parameter_all* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const Communication_parameter_all>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Communication_proto.Communication_parameter_all)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Communication_proto.Communication_parameter_all)
+    MergeFrom(*source);
+  }
+}
+
+void Communication_parameter_all::MergeFrom(const Communication_parameter_all& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:Communication_proto.Communication_parameter_all)
+  GOOGLE_DCHECK_NE(&from, this);
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from.has_communication_parameters()) {
+    mutable_communication_parameters()->::Communication_proto::Communication_parameter::MergeFrom(from.communication_parameters());
+  }
+}
+
+void Communication_parameter_all::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Communication_proto.Communication_parameter_all)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Communication_parameter_all::CopyFrom(const Communication_parameter_all& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Communication_proto.Communication_parameter_all)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Communication_parameter_all::IsInitialized() const {
+  return true;
+}
+
+void Communication_parameter_all::Swap(Communication_parameter_all* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Communication_parameter_all::InternalSwap(Communication_parameter_all* other) {
+  using std::swap;
+  swap(communication_parameters_, other->communication_parameters_);
+  swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Communication_parameter_all::GetMetadata() const {
+  protobuf_communication_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_communication_2eproto::file_level_metadata[kIndexInFileMessages];
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+}  // namespace Communication_proto
+
+// @@protoc_insertion_point(global_scope)

+ 530 - 0
communication/communication.pb.h

@@ -0,0 +1,530 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: communication.proto
+
+#ifndef PROTOBUF_communication_2eproto__INCLUDED
+#define PROTOBUF_communication_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3005000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_table_driven.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace protobuf_communication_2eproto {
+// Internal implementation detail -- do not use these members.
+struct TableStruct {
+  static const ::google::protobuf::internal::ParseTableField entries[];
+  static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
+  static const ::google::protobuf::internal::ParseTable schema[2];
+  static const ::google::protobuf::internal::FieldMetadata field_metadata[];
+  static const ::google::protobuf::internal::SerializationTable serialization_table[];
+  static const ::google::protobuf::uint32 offsets[];
+};
+void AddDescriptors();
+void InitDefaultsCommunication_parameterImpl();
+void InitDefaultsCommunication_parameter();
+void InitDefaultsCommunication_parameter_allImpl();
+void InitDefaultsCommunication_parameter_all();
+inline void InitDefaults() {
+  InitDefaultsCommunication_parameter();
+  InitDefaultsCommunication_parameter_all();
+}
+}  // namespace protobuf_communication_2eproto
+namespace Communication_proto {
+class Communication_parameter;
+class Communication_parameterDefaultTypeInternal;
+extern Communication_parameterDefaultTypeInternal _Communication_parameter_default_instance_;
+class Communication_parameter_all;
+class Communication_parameter_allDefaultTypeInternal;
+extern Communication_parameter_allDefaultTypeInternal _Communication_parameter_all_default_instance_;
+}  // namespace Communication_proto
+namespace Communication_proto {
+
+// ===================================================================
+
+class Communication_parameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Communication_proto.Communication_parameter) */ {
+ public:
+  Communication_parameter();
+  virtual ~Communication_parameter();
+
+  Communication_parameter(const Communication_parameter& from);
+
+  inline Communication_parameter& operator=(const Communication_parameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  #if LANG_CXX11
+  Communication_parameter(Communication_parameter&& from) noexcept
+    : Communication_parameter() {
+    *this = ::std::move(from);
+  }
+
+  inline Communication_parameter& operator=(Communication_parameter&& from) noexcept {
+    if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
+      if (this != &from) InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+  #endif
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Communication_parameter& default_instance();
+
+  static void InitAsDefaultInstance();  // FOR INTERNAL USE ONLY
+  static inline const Communication_parameter* internal_default_instance() {
+    return reinterpret_cast<const Communication_parameter*>(
+               &_Communication_parameter_default_instance_);
+  }
+  static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
+    0;
+
+  void Swap(Communication_parameter* other);
+  friend void swap(Communication_parameter& a, Communication_parameter& b) {
+    a.Swap(&b);
+  }
+
+  // implements Message ----------------------------------------------
+
+  inline Communication_parameter* New() const PROTOBUF_FINAL { return New(NULL); }
+
+  Communication_parameter* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CopyFrom(const Communication_parameter& from);
+  void MergeFrom(const Communication_parameter& from);
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
+
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void InternalSwap(Communication_parameter* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return NULL;
+  }
+  inline void* MaybeArenaPtr() const {
+    return NULL;
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated string connect_string_vector = 2;
+  int connect_string_vector_size() const;
+  void clear_connect_string_vector();
+  static const int kConnectStringVectorFieldNumber = 2;
+  const ::std::string& connect_string_vector(int index) const;
+  ::std::string* mutable_connect_string_vector(int index);
+  void set_connect_string_vector(int index, const ::std::string& value);
+  #if LANG_CXX11
+  void set_connect_string_vector(int index, ::std::string&& value);
+  #endif
+  void set_connect_string_vector(int index, const char* value);
+  void set_connect_string_vector(int index, const char* value, size_t size);
+  ::std::string* add_connect_string_vector();
+  void add_connect_string_vector(const ::std::string& value);
+  #if LANG_CXX11
+  void add_connect_string_vector(::std::string&& value);
+  #endif
+  void add_connect_string_vector(const char* value);
+  void add_connect_string_vector(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& connect_string_vector() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_connect_string_vector();
+
+  // optional string bind_string = 1;
+  bool has_bind_string() const;
+  void clear_bind_string();
+  static const int kBindStringFieldNumber = 1;
+  const ::std::string& bind_string() const;
+  void set_bind_string(const ::std::string& value);
+  #if LANG_CXX11
+  void set_bind_string(::std::string&& value);
+  #endif
+  void set_bind_string(const char* value);
+  void set_bind_string(const char* value, size_t size);
+  ::std::string* mutable_bind_string();
+  ::std::string* release_bind_string();
+  void set_allocated_bind_string(::std::string* bind_string);
+
+  // @@protoc_insertion_point(class_scope:Communication_proto.Communication_parameter)
+ private:
+  void set_has_bind_string();
+  void clear_has_bind_string();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> connect_string_vector_;
+  ::google::protobuf::internal::ArenaStringPtr bind_string_;
+  friend struct ::protobuf_communication_2eproto::TableStruct;
+  friend void ::protobuf_communication_2eproto::InitDefaultsCommunication_parameterImpl();
+};
+// -------------------------------------------------------------------
+
+class Communication_parameter_all : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Communication_proto.Communication_parameter_all) */ {
+ public:
+  Communication_parameter_all();
+  virtual ~Communication_parameter_all();
+
+  Communication_parameter_all(const Communication_parameter_all& from);
+
+  inline Communication_parameter_all& operator=(const Communication_parameter_all& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  #if LANG_CXX11
+  Communication_parameter_all(Communication_parameter_all&& from) noexcept
+    : Communication_parameter_all() {
+    *this = ::std::move(from);
+  }
+
+  inline Communication_parameter_all& operator=(Communication_parameter_all&& from) noexcept {
+    if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
+      if (this != &from) InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+  #endif
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Communication_parameter_all& default_instance();
+
+  static void InitAsDefaultInstance();  // FOR INTERNAL USE ONLY
+  static inline const Communication_parameter_all* internal_default_instance() {
+    return reinterpret_cast<const Communication_parameter_all*>(
+               &_Communication_parameter_all_default_instance_);
+  }
+  static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
+    1;
+
+  void Swap(Communication_parameter_all* other);
+  friend void swap(Communication_parameter_all& a, Communication_parameter_all& b) {
+    a.Swap(&b);
+  }
+
+  // implements Message ----------------------------------------------
+
+  inline Communication_parameter_all* New() const PROTOBUF_FINAL { return New(NULL); }
+
+  Communication_parameter_all* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CopyFrom(const Communication_parameter_all& from);
+  void MergeFrom(const Communication_parameter_all& from);
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
+
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void InternalSwap(Communication_parameter_all* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return NULL;
+  }
+  inline void* MaybeArenaPtr() const {
+    return NULL;
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional .Communication_proto.Communication_parameter communication_parameters = 1;
+  bool has_communication_parameters() const;
+  void clear_communication_parameters();
+  static const int kCommunicationParametersFieldNumber = 1;
+  const ::Communication_proto::Communication_parameter& communication_parameters() const;
+  ::Communication_proto::Communication_parameter* release_communication_parameters();
+  ::Communication_proto::Communication_parameter* mutable_communication_parameters();
+  void set_allocated_communication_parameters(::Communication_proto::Communication_parameter* communication_parameters);
+
+  // @@protoc_insertion_point(class_scope:Communication_proto.Communication_parameter_all)
+ private:
+  void set_has_communication_parameters();
+  void clear_has_communication_parameters();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::Communication_proto::Communication_parameter* communication_parameters_;
+  friend struct ::protobuf_communication_2eproto::TableStruct;
+  friend void ::protobuf_communication_2eproto::InitDefaultsCommunication_parameter_allImpl();
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Communication_parameter
+
+// optional string bind_string = 1;
+inline bool Communication_parameter::has_bind_string() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Communication_parameter::set_has_bind_string() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void Communication_parameter::clear_has_bind_string() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void Communication_parameter::clear_bind_string() {
+  bind_string_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_bind_string();
+}
+inline const ::std::string& Communication_parameter::bind_string() const {
+  // @@protoc_insertion_point(field_get:Communication_proto.Communication_parameter.bind_string)
+  return bind_string_.GetNoArena();
+}
+inline void Communication_parameter::set_bind_string(const ::std::string& value) {
+  set_has_bind_string();
+  bind_string_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:Communication_proto.Communication_parameter.bind_string)
+}
+#if LANG_CXX11
+inline void Communication_parameter::set_bind_string(::std::string&& value) {
+  set_has_bind_string();
+  bind_string_.SetNoArena(
+    &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
+  // @@protoc_insertion_point(field_set_rvalue:Communication_proto.Communication_parameter.bind_string)
+}
+#endif
+inline void Communication_parameter::set_bind_string(const char* value) {
+  GOOGLE_DCHECK(value != NULL);
+  set_has_bind_string();
+  bind_string_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:Communication_proto.Communication_parameter.bind_string)
+}
+inline void Communication_parameter::set_bind_string(const char* value, size_t size) {
+  set_has_bind_string();
+  bind_string_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:Communication_proto.Communication_parameter.bind_string)
+}
+inline ::std::string* Communication_parameter::mutable_bind_string() {
+  set_has_bind_string();
+  // @@protoc_insertion_point(field_mutable:Communication_proto.Communication_parameter.bind_string)
+  return bind_string_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Communication_parameter::release_bind_string() {
+  // @@protoc_insertion_point(field_release:Communication_proto.Communication_parameter.bind_string)
+  clear_has_bind_string();
+  return bind_string_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Communication_parameter::set_allocated_bind_string(::std::string* bind_string) {
+  if (bind_string != NULL) {
+    set_has_bind_string();
+  } else {
+    clear_has_bind_string();
+  }
+  bind_string_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), bind_string);
+  // @@protoc_insertion_point(field_set_allocated:Communication_proto.Communication_parameter.bind_string)
+}
+
+// repeated string connect_string_vector = 2;
+inline int Communication_parameter::connect_string_vector_size() const {
+  return connect_string_vector_.size();
+}
+inline void Communication_parameter::clear_connect_string_vector() {
+  connect_string_vector_.Clear();
+}
+inline const ::std::string& Communication_parameter::connect_string_vector(int index) const {
+  // @@protoc_insertion_point(field_get:Communication_proto.Communication_parameter.connect_string_vector)
+  return connect_string_vector_.Get(index);
+}
+inline ::std::string* Communication_parameter::mutable_connect_string_vector(int index) {
+  // @@protoc_insertion_point(field_mutable:Communication_proto.Communication_parameter.connect_string_vector)
+  return connect_string_vector_.Mutable(index);
+}
+inline void Communication_parameter::set_connect_string_vector(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:Communication_proto.Communication_parameter.connect_string_vector)
+  connect_string_vector_.Mutable(index)->assign(value);
+}
+#if LANG_CXX11
+inline void Communication_parameter::set_connect_string_vector(int index, ::std::string&& value) {
+  // @@protoc_insertion_point(field_set:Communication_proto.Communication_parameter.connect_string_vector)
+  connect_string_vector_.Mutable(index)->assign(std::move(value));
+}
+#endif
+inline void Communication_parameter::set_connect_string_vector(int index, const char* value) {
+  GOOGLE_DCHECK(value != NULL);
+  connect_string_vector_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:Communication_proto.Communication_parameter.connect_string_vector)
+}
+inline void Communication_parameter::set_connect_string_vector(int index, const char* value, size_t size) {
+  connect_string_vector_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:Communication_proto.Communication_parameter.connect_string_vector)
+}
+inline ::std::string* Communication_parameter::add_connect_string_vector() {
+  // @@protoc_insertion_point(field_add_mutable:Communication_proto.Communication_parameter.connect_string_vector)
+  return connect_string_vector_.Add();
+}
+inline void Communication_parameter::add_connect_string_vector(const ::std::string& value) {
+  connect_string_vector_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:Communication_proto.Communication_parameter.connect_string_vector)
+}
+#if LANG_CXX11
+inline void Communication_parameter::add_connect_string_vector(::std::string&& value) {
+  connect_string_vector_.Add(std::move(value));
+  // @@protoc_insertion_point(field_add:Communication_proto.Communication_parameter.connect_string_vector)
+}
+#endif
+inline void Communication_parameter::add_connect_string_vector(const char* value) {
+  GOOGLE_DCHECK(value != NULL);
+  connect_string_vector_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:Communication_proto.Communication_parameter.connect_string_vector)
+}
+inline void Communication_parameter::add_connect_string_vector(const char* value, size_t size) {
+  connect_string_vector_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:Communication_proto.Communication_parameter.connect_string_vector)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+Communication_parameter::connect_string_vector() const {
+  // @@protoc_insertion_point(field_list:Communication_proto.Communication_parameter.connect_string_vector)
+  return connect_string_vector_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+Communication_parameter::mutable_connect_string_vector() {
+  // @@protoc_insertion_point(field_mutable_list:Communication_proto.Communication_parameter.connect_string_vector)
+  return &connect_string_vector_;
+}
+
+// -------------------------------------------------------------------
+
+// Communication_parameter_all
+
+// optional .Communication_proto.Communication_parameter communication_parameters = 1;
+inline bool Communication_parameter_all::has_communication_parameters() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Communication_parameter_all::set_has_communication_parameters() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void Communication_parameter_all::clear_has_communication_parameters() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void Communication_parameter_all::clear_communication_parameters() {
+  if (communication_parameters_ != NULL) communication_parameters_->Clear();
+  clear_has_communication_parameters();
+}
+inline const ::Communication_proto::Communication_parameter& Communication_parameter_all::communication_parameters() const {
+  const ::Communication_proto::Communication_parameter* p = communication_parameters_;
+  // @@protoc_insertion_point(field_get:Communication_proto.Communication_parameter_all.communication_parameters)
+  return p != NULL ? *p : *reinterpret_cast<const ::Communication_proto::Communication_parameter*>(
+      &::Communication_proto::_Communication_parameter_default_instance_);
+}
+inline ::Communication_proto::Communication_parameter* Communication_parameter_all::release_communication_parameters() {
+  // @@protoc_insertion_point(field_release:Communication_proto.Communication_parameter_all.communication_parameters)
+  clear_has_communication_parameters();
+  ::Communication_proto::Communication_parameter* temp = communication_parameters_;
+  communication_parameters_ = NULL;
+  return temp;
+}
+inline ::Communication_proto::Communication_parameter* Communication_parameter_all::mutable_communication_parameters() {
+  set_has_communication_parameters();
+  if (communication_parameters_ == NULL) {
+    communication_parameters_ = new ::Communication_proto::Communication_parameter;
+  }
+  // @@protoc_insertion_point(field_mutable:Communication_proto.Communication_parameter_all.communication_parameters)
+  return communication_parameters_;
+}
+inline void Communication_parameter_all::set_allocated_communication_parameters(::Communication_proto::Communication_parameter* communication_parameters) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete communication_parameters_;
+  }
+  if (communication_parameters) {
+    ::google::protobuf::Arena* submessage_arena = NULL;
+    if (message_arena != submessage_arena) {
+      communication_parameters = ::google::protobuf::internal::GetOwnedMessage(
+          message_arena, communication_parameters, submessage_arena);
+    }
+    set_has_communication_parameters();
+  } else {
+    clear_has_communication_parameters();
+  }
+  communication_parameters_ = communication_parameters;
+  // @@protoc_insertion_point(field_set_allocated:Communication_proto.Communication_parameter_all.communication_parameters)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace Communication_proto
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_communication_2eproto__INCLUDED

+ 14 - 0
communication/communication.proto

@@ -0,0 +1,14 @@
+syntax = "proto2";
+package Communication_proto;
+
+message Communication_parameter
+{
+    optional string bind_string = 1;
+    repeated string connect_string_vector = 2;
+
+}
+
+message Communication_parameter_all
+{
+    optional Communication_parameter        communication_parameters=1;
+}

+ 93 - 0
communication/communication_message.cpp

@@ -0,0 +1,93 @@
+//
+// Created by huli on 2020/6/29.
+//
+
+#include "communication_message.h"
+
+
+Communication_message::Communication_message()
+{
+	m_message_type = eBase_msg;
+	m_receive_time = std::chrono::system_clock::now();
+	m_timeout_ms = std::chrono::milliseconds(5000);		//超时默认5秒
+	m_sender = eEmpty;
+	m_receiver = eEmpty;
+//	m_message_buf = "";
+}
+
+Communication_message::Communication_message(std::string message_buf)
+{
+	m_message_type = eBase_msg;
+	m_receive_time = std::chrono::system_clock::now();
+	m_timeout_ms = std::chrono::milliseconds(5000);		//超时默认5秒
+	m_sender = eEmpty;
+	m_receiver = eEmpty;
+	m_message_buf = message_buf;
+}
+
+Communication_message::Communication_message(char* p_buf, int size)
+{
+	m_message_type = eBase_msg;
+	m_receive_time = std::chrono::system_clock::now();
+	m_timeout_ms = std::chrono::milliseconds(5000);		//超时默认5秒
+	m_sender = eEmpty;
+	m_receiver = eEmpty;
+	m_message_buf = std::string(p_buf, size);
+}
+
+
+
+Communication_message::~Communication_message()
+{
+
+}
+
+bool Communication_message::is_over_time()
+{
+	if ( std::chrono::system_clock::now() - m_receive_time > m_timeout_ms)
+	{
+	    return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+
+void Communication_message::reset(const message::Base_info& base_info, std::string receive_string)
+{
+	m_message_type = (Message_type)(base_info.msg_type());
+
+	m_receive_time = std::chrono::system_clock::now();
+	m_timeout_ms = std::chrono::milliseconds(base_info.timeout_ms());
+	m_sender = (Communicator)(base_info.sender());
+	m_receiver = (Communicator)(base_info.receiver());
+	m_message_buf = receive_string;
+}
+
+Communication_message::Message_type Communication_message::get_message_type()
+{
+	return m_message_type;
+}
+Communication_message::Communicator Communication_message::get_sender()
+{
+	return m_sender;
+}
+Communication_message::Communicator Communication_message::get_receiver()
+{
+	return m_receiver;
+}
+std::string& Communication_message::get_message_buf()
+{
+	return m_message_buf;
+}
+
+std::chrono::system_clock::time_point Communication_message::get_receive_time()
+{
+	return m_receive_time;
+}
+
+
+
+

+ 122 - 0
communication/communication_message.h

@@ -0,0 +1,122 @@
+//
+// Created by huli on 2020/6/29.
+//
+
+#ifndef NNXX_TESTS_COMMUNICATION_MESSAGE_H
+#define NNXX_TESTS_COMMUNICATION_MESSAGE_H
+
+#include "../error_code/error_code.h"
+
+#include <time.h>
+#include <sys/time.h>
+#include <chrono>
+//#include <iosfwd>
+
+#include <string>
+#include "../message/message_base.pb.h"
+
+
+class Communication_message
+{
+public:
+	//消息类型定义,每个在网络上传输的消息必须含有这个属性
+	enum Message_type
+	{
+		eBase_msg=0x00,
+		eCommand_msg=0x01,                      //指令消息
+
+
+		eLocate_status_msg=0x11,                //定位模块状态消息
+		eLocate_request_msg=0x12,               //定位请求消息
+		eLocate_response_msg=0x13,              //定位反馈消息
+
+		eLocate_sift_request_msg = 0x14,            //预测算法请求消息
+		eLocate_sift_response_msg = 0x15,           //预测算法反馈消息
+
+		eDispatch_status_msg=0x21,                //调度模块硬件状态消息
+		eDispatch_request_msg=0x22,              //请求调度消息
+		eDispatch_response_msg=0x23,             //调度结果反馈消息
+
+		eParkspace_allocation_status_msg=0x31,  //车位分配模块状态消息,包括车位信息
+		eParkspace_allocation_request_msg=0x32, //请求分配车位消息
+		eParkspace_allocation_response_msg=0x33,//分配车位结果反馈消息
+		eParkspace_search_request_msg = 0x34,		//查询车位请求消息
+		eParkspace_search_response_msg = 0x35,		//查询车位反馈消息
+		eParkspace_release_request_msg = 0x36,		//释放车位请求消息
+		eParkspace_release_response_msg = 0x37,		//释放车位反馈消息
+		eParkspace_force_update_request_msg = 0x38,	//手动修改车位消息
+		eParkspace_force_update_response_msg = 0x39,//手动修改车位反馈消息
+		eParkspace_confirm_alloc_request_msg = 0x3A,//确认分配车位请求消息
+		eParkspace_confirm_alloc_response_msg = 0x3B,//确认分配车位反馈消息
+
+
+		eStore_command_request_msg=0x41,        //终端停车请求消息
+		eStore_command_response_msg=0x42,       //停车请求反馈消息
+		ePickup_command_request_msg=0x43,       //取车请求消息
+		ePickup_command_response_msg=0x44,       //取车请求反馈消息
+
+
+
+		eStoring_process_statu_msg=0x90,        //停车指令进度条消息
+		ePicking_process_statu_msg=0x91,        //取车指令进度消息
+
+
+		eCentral_controller_statu_msg=0xa0,     //中控系统状态消息
+
+
+		eEntrance_manual_operation_msg=0xb0,            //针对出入口状态操作的手动消息
+		eProcess_manual_operation_msg=0xb1,             //针对流程的手动消息
+
+	};
+
+//通讯单元
+	enum Communicator
+	{
+		eEmpty=0x0000,
+		eMain=0x0001,    //主流程
+
+		eTerminor=0x0100,
+		//车位表
+		eParkspace=0x0200,
+		//测量单元
+		eMeasurer=0x0300,
+		//测量单元
+		eMeasurer_sift_server=0x0301,
+		//调度机构
+		eDispatch=0x0400,
+		//...
+
+	};
+public:
+	Communication_message();
+	Communication_message(std::string message_buf);
+	Communication_message(char* p_buf, int size);
+	Communication_message(const Communication_message& other)= default;
+	Communication_message& operator =(const Communication_message& other)= default;
+	~Communication_message();
+public://API functions
+	bool is_over_time();
+public://get or set member variable
+	void reset(const message::Base_info& base_info, std::string receive_string);
+
+	Message_type get_message_type();
+	Communicator get_sender();
+	Communicator get_receiver();
+	std::string& get_message_buf();
+	std::chrono::system_clock::time_point get_receive_time();
+
+protected://member variable
+	Message_type								m_message_type;				//消息类型
+	std::chrono::system_clock::time_point		m_receive_time;				//接收消息的时间点
+	std::chrono::milliseconds					m_timeout_ms;				//超时时间, 整个软件都统一为毫秒
+	Communicator								m_sender;					//发送者
+	Communicator								m_receiver;					//接受者
+
+	std::string									m_message_buf;				//消息数据
+
+private:
+
+};
+
+
+#endif //NNXX_TESTS_COMMUNICATION_MESSAGE_H

+ 610 - 0
communication/communication_socket_base.cpp

@@ -0,0 +1,610 @@
+
+
+
+#include "communication_socket_base.h"
+#include "../tool/proto_tool.h"
+
+Communication_socket_base::Communication_socket_base()
+{
+	m_communication_statu = COMMUNICATION_UNKNOW;
+
+	mp_receive_data_thread = NULL;
+	mp_analysis_data_thread = NULL;
+	mp_send_data_thread = NULL;
+	mp_encapsulate_data_thread = NULL;
+
+	m_analysis_cycle_time = 1000;//默认1000ms,就自动解析(接受list)
+	m_encapsulate_cycle_time = 1000;//默认1000ms,就自动发送一次状态信息
+}
+
+Communication_socket_base::~Communication_socket_base()
+{
+	communication_uninit();
+}
+
+//初始化 通信 模块。如下三选一
+Error_manager Communication_socket_base::communication_init()
+{
+	LOG(INFO) << " ---Communication_socket_base::communication_init() run--- "<< this;
+
+	return  communication_init_from_protobuf(COMMUNICATION_PARAMETER_PATH);
+}
+
+//初始化 通信 模块。从文件读取
+Error_manager Communication_socket_base::communication_init_from_protobuf(std::string prototxt_path)
+{
+	Communication_proto::Communication_parameter_all t_communication_parameter_all;
+	if(!  proto_tool::read_proto_param(prototxt_path,t_communication_parameter_all) )
+	{
+		return Error_manager(COMMUNICATION_READ_PROTOBUF_ERROR,MINOR_ERROR,
+		"Communication_socket_base read_proto_param  failed");
+	}
+
+	return communication_init_from_protobuf(t_communication_parameter_all);
+}
+
+//初始化 通信 模块。从protobuf读取
+Error_manager Communication_socket_base::communication_init_from_protobuf(Communication_proto::Communication_parameter_all& communication_parameter_all)
+{
+	LOG(INFO) << " ---Communication_socket_base::communication_init_from_protobuf() run--- "<< this;
+	Error_manager t_error;
+
+	if ( communication_parameter_all.communication_parameters().has_bind_string() )
+	{
+		t_error = communication_bind(communication_parameter_all.communication_parameters().bind_string());
+		if ( t_error != Error_code::SUCCESS )
+		{
+			return t_error;
+		}
+	}
+	std::cout << "communication_parameter_all.communication_parameters().connect_string_vector_size() " <<
+		communication_parameter_all.communication_parameters().connect_string_vector_size()<< std::endl;
+	for(int i=0;i<communication_parameter_all.communication_parameters().connect_string_vector_size();++i)
+	{
+		t_error = communication_connect( communication_parameter_all.communication_parameters().connect_string_vector(i) );
+		if ( t_error != Error_code::SUCCESS )
+		{
+			return t_error;
+		}
+	}
+
+	//启动通信, run thread
+	communication_run();
+
+	return Error_code::SUCCESS;
+}
+
+//初始化
+Error_manager Communication_socket_base::communication_init(std::string bind_string, std::vector<std::string>& connect_string_vector)
+{
+	LOG(INFO) << " ---Communication_socket_base::communication_init() run--- "<< this;
+	Error_manager t_error;
+
+	t_error = communication_bind(bind_string);
+	if ( t_error != Error_code::SUCCESS )
+	{
+		return t_error;
+	}
+
+	t_error = communication_connect(connect_string_vector);
+	if ( t_error != Error_code::SUCCESS )
+	{
+		return t_error;
+	}
+
+	//启动通信, run thread
+	communication_run();
+
+	return Error_code::SUCCESS;
+}
+//bind
+Error_manager Communication_socket_base::communication_bind(std::string bind_string)
+{
+	Error_manager t_error;
+	int t_socket_result;
+
+	//m_socket 自己作为一个服务器, 绑定一个端口
+	t_socket_result = m_socket.bind(bind_string);
+	if ( t_socket_result <0 )
+	{
+		return Error_manager(Error_code::COMMUNICATION_BIND_ERROR, Error_level::MINOR_ERROR,
+							 " m_socket.bind error ");
+	}
+	LOG(INFO) << " ---Communication_socket_base::communication_bind() bind::  "<< bind_string << "  " << this;
+
+	return Error_code::SUCCESS;
+}
+//connect
+Error_manager Communication_socket_base::communication_connect(std::vector<std::string>& connect_string_vector)
+{
+	Error_manager t_error;
+	for (auto iter = connect_string_vector.begin(); iter != connect_string_vector.end(); ++iter)
+	{
+		t_error = communication_connect(*iter);
+		if ( t_error != Error_code::SUCCESS )
+		{
+			return t_error;
+		}
+	}
+	return Error_code::SUCCESS;
+}
+//connect
+Error_manager Communication_socket_base::communication_connect(std::string connect_string)
+{
+	Error_manager t_error;
+	int t_socket_result;
+	//m_socket 和远端通信, 连接远端服务器的端口
+	t_socket_result = m_socket.connect(connect_string);
+	if ( t_socket_result <0 )
+	{
+		return Error_manager(Error_code::COMMUNICATION_CONNECT_ERROR, Error_level::MINOR_ERROR,
+							 " m_socket.connect error ");
+	}
+	LOG(INFO) << " ---Communication_socket_base::communication_connect() connect::  "<< connect_string << "  " << this;
+
+	return Error_code::SUCCESS;
+}
+//启动通信, run thread
+Error_manager Communication_socket_base::communication_run()
+{
+	m_communication_statu = COMMUNICATION_READY;
+	//启动4个线程。
+	//接受线程默认循环, 内部的nn_recv进行等待, 超时1ms
+	m_receive_condition.reset(false, false, false);
+	mp_receive_data_thread = new std::thread(&Communication_socket_base::receive_data_thread, this);
+	//解析线程默认等待, 需要接受线程去唤醒, 超时1ms, 超时后主动遍历m_receive_data_list
+	m_analysis_data_condition.reset(false, false, false);
+	mp_analysis_data_thread = new std::thread(&Communication_socket_base::analysis_data_thread, this);
+	//发送线程默认循环, 内部的wait_and_pop进行等待,
+	m_send_data_condition.reset(false, true, false);
+	mp_send_data_thread = new std::thread(&Communication_socket_base::send_data_thread, this);
+	//封装线程默认等待, ...., 超时1ms, 超时后主动 封装心跳和状态信息,
+	m_encapsulate_data_condition.reset(false, false, false);
+	mp_encapsulate_data_thread = new std::thread(&Communication_socket_base::encapsulate_data_thread, this);
+
+	return Error_code::SUCCESS;
+}
+
+
+//反初始化 通信 模块。
+Error_manager Communication_socket_base::communication_uninit()
+{
+	//终止list,防止 wait_and_pop 阻塞线程。
+	m_receive_data_list.termination_list();
+	m_send_data_list.termination_list();
+
+	//杀死4个线程,强制退出
+	if (mp_receive_data_thread)
+	{
+		m_receive_condition.kill_all();
+	}
+	if (mp_analysis_data_thread)
+	{
+		m_analysis_data_condition.kill_all();
+	}
+	if (mp_send_data_thread)
+	{
+		m_send_data_condition.kill_all();
+	}
+	if (mp_encapsulate_data_thread)
+	{
+		m_encapsulate_data_condition.kill_all();
+	}
+	//回收4个线程的资源
+	if (mp_receive_data_thread)
+	{
+		mp_receive_data_thread->join();
+		delete mp_receive_data_thread;
+		mp_receive_data_thread = NULL;
+	}
+	if (mp_analysis_data_thread)
+	{
+		mp_analysis_data_thread->join();
+		delete mp_analysis_data_thread;
+		mp_analysis_data_thread = 0;
+	}
+	if (mp_send_data_thread)
+	{
+		mp_send_data_thread->join();
+		delete mp_send_data_thread;
+		mp_send_data_thread = NULL;
+	}
+	if (mp_encapsulate_data_thread)
+	{
+		mp_encapsulate_data_thread->join();
+		delete mp_encapsulate_data_thread;
+		mp_encapsulate_data_thread = NULL;
+	}
+
+	//清空list
+	m_receive_data_list.clear_and_delete();
+	m_send_data_list.clear_and_delete();
+
+	m_communication_statu = COMMUNICATION_UNKNOW;
+	m_socket.close();
+
+	return Error_code::SUCCESS;
+}
+
+
+void Communication_socket_base::set_analysis_cycle_time(unsigned int analysis_cycle_time)
+{
+	m_analysis_cycle_time = analysis_cycle_time;
+}
+void Communication_socket_base::set_encapsulate_cycle_time(unsigned int encapsulate_cycle_time)
+{
+	m_encapsulate_cycle_time = encapsulate_cycle_time;
+}
+
+
+
+
+//mp_receive_data_thread 接受线程执行函数,
+//receive_data_thread 内部线程负责接受消息
+void Communication_socket_base::receive_data_thread()
+{
+	LOG(INFO) << " Communication_socket_base::receive_data_thread start "<< this;
+
+	//通信接受线程, 负责接受socket消息, 并存入 m_receive_data_list
+	while (m_receive_condition.is_alive())
+	{
+		m_receive_condition.wait_for_ex(std::chrono::microseconds(1));
+		if ( m_receive_condition.is_alive() )
+		{
+			std::this_thread::yield();
+
+			std::string t_receive_string;
+			{//这个大括号表示只对 recv 和 send 加锁, 不要因为后面的复杂逻辑影响通信效率
+				std::unique_lock<std::mutex> lk(m_mutex);
+				//flags为1, 非阻塞接受消息, 如果接收到消息, 那么接受数据长度大于0
+				t_receive_string = m_socket.recv<std::string>(1);
+			}
+			if ( t_receive_string.size()>0 )
+			{
+				//如果这里接受到了消息, 在这提前解析消息最前面的Base_msg (消息公共内容), 用于后续的check
+				message::Base_msg t_base_msg;
+				if( t_base_msg.ParseFromString(t_receive_string) )
+				{
+					//第一次解析之后转化为, Communication_message, 自定义的通信消息格式
+					Communication_message  * tp_communication_message = new Communication_message;
+					tp_communication_message->reset(t_base_msg.base_info(), t_receive_string);
+					//检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的.
+					if ( check_msg(tp_communication_message) == SUCCESS )
+					{
+						bool is_push = m_receive_data_list.push(tp_communication_message);
+						//push成功之后, tp_communication_message内存的管理权限交给链表, 如果失败就要回收内存
+						if ( is_push )
+						{
+							//唤醒解析线程一次,
+							m_analysis_data_condition.notify_all(false, true);
+						}
+						else
+						{
+//						push失败, 就要回收内存
+							delete(tp_communication_message);
+							tp_communication_message = NULL;
+//					return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+//										 " m_receive_data_list.push error ");
+						}
+					}
+					else
+					{
+						delete(tp_communication_message);
+						tp_communication_message = NULL;
+					}
+
+
+				}
+				//解析失败, 就当做什么也没发生, 认为接收消息无效,
+			}
+			//没有接受到消息, 返回空字符串
+		}
+	}
+
+	LOG(INFO) << " Communication_socket_base::receive_data_thread end "<< this;
+	return;
+}
+
+//检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的.
+Error_manager Communication_socket_base::check_msg(Communication_message*  p_msg)
+{
+	//通过 p_msg->get_message_type() 和 p_msg->get_receiver() 判断这条消息是不是给我的.
+	//子类重载时, 增加自己模块的判断逻辑, 以后再写.
+	if ( p_msg->get_message_type() == Communication_message::Message_type::eBase_msg
+		 && p_msg->get_receiver() == Communication_message::Communicator::eMain )
+	{
+		return Error_code::SUCCESS;
+	}
+	else
+	{
+		//无效的消息,
+		return Error_manager(Error_code::INVALID_MESSAGE, Error_level::NEGLIGIBLE_ERROR,
+							 " INVALID_MESSAGE error ");	}
+}
+
+//mp_analysis_data_thread 解析线程执行函数,
+//analysis_data_thread 内部线程负责解析消息
+void Communication_socket_base::analysis_data_thread()
+{
+	LOG(INFO) << " Communication_socket_base::analysis_data_thread start "<< this;
+
+	//通信解析线程, 负责巡检m_receive_data_list, 并解析和处理消息
+	while (m_analysis_data_condition.is_alive())
+	{
+		bool t_pass_flag = m_analysis_data_condition.wait_for_millisecond(m_analysis_cycle_time);
+		if ( m_analysis_data_condition.is_alive() )
+		{
+			std::this_thread::yield();
+			//如果解析线程被主动唤醒, 那么就表示 收到新的消息, 那就遍历整个链表
+			if ( t_pass_flag )
+			{
+				analysis_receive_list();
+			}
+				//如果解析线程超时通过, 那么就定时处理链表残留的消息,
+			else
+			{
+				analysis_receive_list();
+			}
+		}
+	}
+
+	LOG(INFO) << " Communication_socket_base::analysis_data_thread end "<< this;
+	return;
+}
+
+//循环接受链表, 解析消息,
+Error_manager Communication_socket_base::analysis_receive_list()
+{
+	Error_manager t_error;
+	if ( m_receive_data_list.m_termination_flag )
+	{
+		return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+							 " Communication_socket_base::analysis_receive_list error ");
+	}
+	else
+	{
+		std::unique_lock<std::mutex> lk(m_receive_data_list.m_mutex);
+		for (auto iter = m_receive_data_list.m_data_list.begin(); iter != m_receive_data_list.m_data_list.end(); )
+		{
+			Communication_message* tp_msg = **iter;
+			if ( tp_msg == NULL )
+			{
+				iter = m_receive_data_list.m_data_list.erase(iter);
+				//注:erase 删除当前 iter 之后返回下一个节点,当前的 iter 无效化,
+			}
+			else
+			{
+				//检查消息是否可以被处理
+				t_error = check_executer(tp_msg);
+				if ( t_error == SUCCESS)
+				{
+					//处理消息
+					t_error = execute_msg(tp_msg);
+//				if ( t_error )
+//				{
+//					//执行结果不管
+//				}
+//				else
+//				{
+//					//执行结果不管
+//				}
+					delete(tp_msg);
+					tp_msg = NULL;
+					iter = m_receive_data_list.m_data_list.erase(iter);
+					//注:erase 删除当前 iter 之后返回下一个节点,当前的 iter 无效化,
+				}
+				else if( t_error == COMMUNICATION_EXCUTER_IS_BUSY)
+				{
+					//处理器正忙, 那就不做处理, 直接处理下一个
+					//注:这条消息就被保留了下来, wait_for_millisecond 超时通过之后, 会循环检查残留的消息.
+					iter++;
+				}
+				else //if( t_error == COMMUNICATION_ANALYSIS_TIME_OUT )
+				{
+					//超时了就直接删除
+					delete(tp_msg);
+					tp_msg = NULL;
+					iter = m_receive_data_list.m_data_list.erase(iter);
+					//注:erase 删除当前 iter 之后返回下一个节点,当前的 iter 无效化,
+
+					//注:消息删除之后, 不需要发送答复消息, 发送方也会有超时处理的,  只有 execute_msg 里面可以答复消息
+				}
+			}
+		}
+	}
+	return Error_code::SUCCESS;
+}
+
+
+
+//检查执行者的状态, 判断能否处理这条消息, 需要子类重载
+Error_manager Communication_socket_base::check_executer(Communication_message*  p_msg)
+{
+	//检查对应模块的状态, 判断是否可以处理这条消息
+	//同时也要判断是否超时, 超时返回 COMMUNICATION_ANALYSIS_TIME_OUT
+	//如果处理器正在忙别的, 那么返回 COMMUNICATION_EXCUTER_IS_BUSY
+
+	if ( p_msg->is_over_time() )
+	{
+		std::cout << "Communication_socket_base::check_msg  p_buf =  " << p_msg->get_message_buf() << std::endl;
+		std::cout << "Communication_socket_base::check_msg   size =  " << p_msg->get_message_buf().size() << std::endl;
+		std::cout << "COMMUNICATION_ANALYSIS_TIME_OUT , " << std::endl;
+		return Error_code::COMMUNICATION_ANALYSIS_TIME_OUT;
+	}
+	else
+	{
+		bool executer_is_ready = false;
+		//通过 p_msg->get_message_type() 和 p_msg->get_receiver() 找到处理模块的实例对象, 查询执行人是否可以处理这条消息
+		//这里子类重载时, 增加判断逻辑, 以后再写.
+		executer_is_ready = true;
+
+		std::cout << "Communication_socket_base::check_msg  p_buf =  " << p_msg->get_message_buf() << std::endl;
+		std::cout << "Communication_socket_base::check_msg   size =  " << p_msg->get_message_buf().size() << std::endl;
+
+		if ( executer_is_ready )
+		{
+			std::cout << "executer_is_ready , " << std::endl;
+			return Error_code::SUCCESS;
+		}
+		else
+		{
+			std::cout << "executer_is_busy , " << std::endl;
+			return Error_code::COMMUNICATION_EXCUTER_IS_BUSY;
+		}
+	}
+
+	return Error_code::SUCCESS;
+}
+
+//处理消息
+Error_manager Communication_socket_base::execute_msg(Communication_message*  p_msg)
+{
+	//先将 p_msg 转化为 对应的格式, 使用对应模块的protobuf来二次解析
+	// 不能一直使用 Communication_message*  p_msg, 这个是要销毁的
+	//然后处理这个消息, 就是调用对应模块的 execute 接口函数
+	//执行结果不管, 如果需要答复, 那么对应模块 在自己内部 封装一条消息发送即可.
+	//子类重载, 需要完全重写, 以后再写.
+
+	//注注注注注意了, 本模块只是用来做通信,
+	//在做处理消息的时候, 可能会调用执行者的接口函数,
+	//这里不应该长时间阻塞或者处理复杂的逻辑,
+	//请执行者另开线程来处理任务.
+
+	std::cout << "Communication_socket_base::excute_msg  p_buf =  " << p_msg->get_message_buf() << std::endl;
+	std::cout << "Communication_socket_base::excute_msg   size =  " << p_msg->get_message_buf().size() << std::endl;
+	return Error_code::SUCCESS;
+}
+
+//mp_send_data_thread 发送线程执行函数,
+//send_data_thread 内部线程负责发送消息
+void Communication_socket_base::send_data_thread()
+{
+	LOG(INFO) << " Communication_socket_base::send_data_thread start "<< this;
+
+	//通信发送线程, 负责巡检m_send_data_list, 并发送消息
+	while (m_send_data_condition.is_alive())
+	{
+		m_send_data_condition.wait();
+		if ( m_send_data_condition.is_alive() )
+		{
+			std::this_thread::yield();
+
+			Communication_message* tp_msg = NULL;
+			//这里 wait_and_pop 会使用链表内部的 m_data_cond 条件变量来控制等待,
+			//封装线程使用push的时候, 会唤醒线程并通过等待, 此时 m_send_data_condition 是一直通过的.
+			//如果需要退出, 那么就要 m_send_data_list.termination_list();	和 m_send_data_condition.kill_all();
+			bool is_pop = m_send_data_list.wait_and_pop(tp_msg);
+			if ( is_pop )
+			{
+				if ( tp_msg != NULL )
+				{
+					{//这个大括号表示只对 recv 和 send 加锁, 不要因为后面的复杂逻辑影响通信效率
+						std::unique_lock<std::mutex> lk(m_mutex);
+						m_socket.send(tp_msg->get_message_buf());
+					}
+					delete(tp_msg);
+					tp_msg = NULL;
+				}
+			}
+			else
+			{
+				//没有取出, 那么应该就是 m_termination_flag 结束了
+//				return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+//									 " Communication_socket_base::send_data_thread() error ");
+			}
+		}
+	}
+
+	LOG(INFO) << " Communication_socket_base::send_data_thread end "<< this;
+	return;
+}
+
+//mp_encapsulate_data_thread 封装线程执行函数,
+//encapsulate_data_thread 内部线程负责封装消息
+void Communication_socket_base::encapsulate_data_thread()
+{
+	LOG(INFO) << " Communication_socket_base::encapsulate_data_thread start "<< this;
+
+	//通信封装线程, 负责定时封装消息, 并存入 m_send_data_list
+	while (m_encapsulate_data_condition.is_alive())
+	{
+		bool t_pass_flag = m_encapsulate_data_condition.wait_for_millisecond(m_encapsulate_cycle_time);
+
+		if ( m_encapsulate_data_condition.is_alive() )
+		{
+			std::this_thread::yield();
+			//如果封装线程被主动唤醒, 那么就表示 需要主动发送消息,
+			if ( t_pass_flag )
+			{
+				//主动发送消息,
+			}
+				//如果封装线程超时通过, 那么就定时封装心跳和状态信息
+			else
+			{
+				encapsulate_send_data();
+			}
+		}
+	}
+
+	LOG(INFO) << " Communication_socket_base::encapsulate_data_thread end "<< this;
+	return;
+}
+
+
+//定时封装发送消息, 一般为心跳和状态信息, 需要子类重载
+Error_manager Communication_socket_base::encapsulate_send_data()
+{
+//	char buf[256] = {0};
+//	static unsigned int t_heartbeat = 0;
+//	sprintf(buf, "Communication_socket_base, heartbeat = %d\0\0\0, test\0", t_heartbeat);
+//	t_heartbeat++;
+    return SUCCESS;
+	message::Base_msg t_base_msg;
+	t_base_msg.mutable_base_info()->set_msg_type(message::Message_type::eBase_msg);
+	t_base_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_base_msg.mutable_base_info()->set_sender(message::Communicator::eMain);
+	t_base_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+
+	Communication_message* tp_msg = new Communication_message(t_base_msg.SerializeAsString());
+	bool is_push = m_send_data_list.push(tp_msg);
+	if ( is_push == false )
+	{
+		delete(tp_msg);
+		tp_msg = NULL;
+		return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+							 " Communication_socket_base::encapsulate_msg error ");
+	}
+	return Error_code::SUCCESS;
+}
+
+
+
+//封装消息, 需要子类重载
+Error_manager Communication_socket_base::encapsulate_msg(std::string message)
+{
+	Communication_message* tp_msg = new Communication_message(message);
+	bool is_push = m_send_data_list.push(tp_msg);
+	if ( is_push == false )
+	{
+		delete(tp_msg);
+		tp_msg = NULL;
+		return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+							 " Communication_socket_base::encapsulate_msg error ");
+	}
+	return Error_code::SUCCESS;
+}
+
+//封装消息, 需要子类重载
+Error_manager Communication_socket_base::encapsulate_msg(Communication_message* p_msg)
+{
+	Communication_message* tp_msg = new Communication_message(*p_msg);
+	bool is_push = m_send_data_list.push(tp_msg);
+	if ( is_push == false )
+	{
+		delete(tp_msg);
+		tp_msg = NULL;
+		return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+							 " Communication_socket_base::encapsulate_msg error ");
+	}
+	return Error_code::SUCCESS;
+}

+ 165 - 0
communication/communication_socket_base.h

@@ -0,0 +1,165 @@
+
+
+/*
+ * communication_socket_base 通信模块的基类,
+ * 用户从这个基类继承, 初始化之后, 便可以自动进行通信
+ * 重载解析消息和封装消息,
+ *
+ *Thread_safe_list<Binary_buf*> 使用 Binary_buf , 而不是string
+ * 主要是为了支持直接发送数字0
+ * 
+ * 
+ * */
+
+#ifndef __COMMUNICATION_SOCKET_BASE__HH__
+#define __COMMUNICATION_SOCKET_BASE__HH__
+
+
+#include <nnxx/message>
+#include <nnxx/socket.h>
+#include <nnxx/bus.h>
+
+#include <glog/logging.h>
+#include "../error_code/error_code.h"
+#include "../tool/binary_buf.h"
+#include "../tool/thread_safe_list.h"
+#include "../tool/thread_condition.h"
+
+#include "../communication/communication.pb.h"
+#include "../communication/communication_message.h"
+
+#include "../message/message_base.pb.h"
+#include "../message/measure_message.pb.h"
+
+
+
+#define COMMUNICATION_PARAMETER_PATH "../setting/communication.prototxt"
+
+class Communication_socket_base
+{
+	//通信状态
+	enum Communication_statu
+	{
+		COMMUNICATION_UNKNOW		=0,	        //通信状态 未知
+		COMMUNICATION_READY			=1,			//通信状态 正常
+
+		COMMUNICATION_FAULT			=3,         //通信状态 错误
+	};
+
+public:
+	Communication_socket_base();
+	Communication_socket_base(const Communication_socket_base& other)= delete;
+	Communication_socket_base& operator =(const Communication_socket_base& other)= delete;
+	~Communication_socket_base();
+public://API functions
+	//初始化 通信 模块。如下三选一
+	virtual Error_manager communication_init();
+	//初始化 通信 模块。从文件读取
+	Error_manager communication_init_from_protobuf(std::string prototxt_path);
+	//初始化 通信 模块。从protobuf读取
+	Error_manager communication_init_from_protobuf(Communication_proto::Communication_parameter_all& communication_parameter_all);
+
+	//初始化
+	virtual Error_manager communication_init(std::string bind_string, std::vector<std::string>& connect_string_vector);
+	//bind
+	virtual Error_manager communication_bind(std::string bind_string);
+	//connect
+	virtual Error_manager communication_connect(std::vector<std::string>& connect_string_vector);
+	//connect
+	virtual Error_manager communication_connect(std::string connect_string);
+	//启动通信, run thread
+	virtual Error_manager communication_run();
+
+	//反初始化 通信 模块。
+	virtual Error_manager communication_uninit();
+	
+	
+public://get or set member variable
+	void set_analysis_cycle_time(unsigned int analysis_cycle_time);
+	void set_encapsulate_cycle_time(unsigned int encapsulate_cycle_time);
+
+protected:
+	//mp_receive_data_thread 接受线程执行函数,
+	//receive_data_thread 内部线程负责接受消息
+	void receive_data_thread();
+
+	//检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的.
+	virtual Error_manager check_msg(Communication_message* p_msg);
+
+	//mp_analysis_data_thread 解析线程执行函数,
+	//analysis_data_thread 内部线程负责解析消息
+	void analysis_data_thread();
+
+	//遍历接受链表, 解析消息,
+	Error_manager analysis_receive_list();
+
+	//检查执行者的状态, 判断能否处理这条消息, 需要子类重载
+	virtual Error_manager check_executer(Communication_message* p_msg);
+
+	//处理消息, 需要子类重载
+	virtual Error_manager execute_msg(Communication_message* p_msg);
+
+	//mp_send_data_thread 发送线程执行函数,
+	//send_data_thread 内部线程负责发送消息
+	void send_data_thread();
+
+	//mp_encapsulate_data_thread 封装线程执行函数,
+	//encapsulate_data_thread 内部线程负责封装消息
+	void encapsulate_data_thread();
+
+	//定时封装发送消息, 一般为心跳和状态信息, 需要子类重载
+	virtual Error_manager encapsulate_send_data();
+
+public:
+	//封装消息, 需要子类重载
+	virtual Error_manager encapsulate_msg(std::string message);
+	//封装消息, 需要子类重载
+	virtual Error_manager encapsulate_msg(Communication_message* p_msg);
+
+protected://member variable
+
+	//通用的网络编程接口, 默认使用总线模式, (网状结构)
+	nnxx::socket 						m_socket { nnxx::SP, nnxx::BUS };
+	std::mutex 							m_mutex;				//m_socket的锁
+
+	//通信状态
+	Communication_statu 				m_communication_statu;			//通信状态
+
+	//接受模块,
+	Thread_safe_list<Communication_message*>		m_receive_data_list; 			//接受的list容器
+	std::thread*						mp_receive_data_thread;    		//接受的线程指针
+	Thread_condition					m_receive_condition;			//接受的条件变量
+	std::thread*						mp_analysis_data_thread;    	//解析的线程指针
+	Thread_condition					m_analysis_data_condition;		//解析的条件变量
+	unsigned int 						m_analysis_cycle_time;			//自动解析的时间周期
+
+	//发送模块,
+	Thread_safe_list<Communication_message*>		m_send_data_list;				//发送的list容器
+	std::thread*						mp_send_data_thread;    		//发送的线程指针
+	Thread_condition					m_send_data_condition;			//发送的条件变量
+	std::thread*						mp_encapsulate_data_thread;    	//封装的线程指针
+	Thread_condition					m_encapsulate_data_condition;	//封装的条件变量
+	unsigned int 						m_encapsulate_cycle_time;		//自动封装的时间周期
+
+
+
+private:
+
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif //__COMMUNICATION_SOCKET_BASE__HH__

+ 847 - 0
dispatch/carrier_base.cpp

@@ -0,0 +1,847 @@
+//
+// Created by huli on 2020/7/20.
+//
+
+#include "carrier_base.h"
+#include "dispatch_communication.h"
+
+Carrier_base::Carrier_base()
+{
+	m_carrier_status = E_UNKNOW;
+	m_carrier_id = 0;
+
+	m_parkspace_unit_id = 0;		//车位单元号(楚天项目为1~3)
+	m_parkspace_floor_id = 0;		//车位楼层号(楚天项目为1~14)
+	m_parkspace_room_id = 0;		//车位同层的房间号	(楚天项目一楼为1~4, 楼上为1~6)
+//	m_command_key = 0;				//任务唯一码
+	m_motion_direction = 0;			//调度方向, 根据停车取车选择出入口, 	1=入口,0=非入口
+	m_car_center_x = 0;				//汽车的中心坐标x
+	m_car_center_y = 0;				//汽车的中心坐标y
+	m_car_angle = 0;				//汽车的旋转角(角度-90~90)
+
+	m_carrier_coordinate_x = 0;				//搬运器坐标x轴, 中跑车控制横向移动
+	m_carrier_coordinate_y = 0;				//搬运器坐标y轴, (本模块默认为0, 由AGV模块去控制纵向移动)
+	m_carrier_coordinate_z = 0;				//搬运器坐标z轴, 电梯控制上下移动
+	m_respons_status = RESPONS_NORMAL;			//指令完成状态, 搬运器答复指令, 返回任务完成的情况
+
+	//硬件状态, 目前只做显示判断
+	m_carrier_device_status = E_UNKNOW;	//搬运器设备的状态, 楚天项目就是中跑车
+	memset(m_carrier_error_code, 0, 50);	//搬运器设备的报警信息位
+//	m_carrier_error_description = 0;//搬运器设备的报警状态描述
+	m_elevator_device_status = E_UNKNOW;	//升降机设备状态, 楚天项目就是电梯
+	memset(m_elevator_error_code, 0, 50);	//升降机设备的报警信息位
+//	m_elevator_error_description = 0;//升降机设备的报警状态描述
+
+	mp_execute_thread = NULL;
+
+}
+
+Carrier_base::~Carrier_base()
+{
+	carrier_base_uninit();
+}
+
+
+//搬运器 初始化
+Error_manager Carrier_base::carrier_base_init()
+{
+//	线程默认开启
+	m_execute_condition.reset(false, true, false);
+	mp_execute_thread = new std::thread(&Carrier_base::execute_thread_fun, this);
+
+	m_carrier_status = E_READY;
+	return Error_code::SUCCESS;
+}
+//搬运器 反初始化
+Error_manager Carrier_base::carrier_base_uninit()
+{
+	if (mp_execute_thread)
+	{
+		m_execute_condition.kill_all();
+	}
+	if (mp_execute_thread)
+	{
+		mp_execute_thread->join();
+		delete mp_execute_thread;
+		mp_execute_thread = NULL;
+	}
+
+	m_carrier_status = E_UNKNOW;
+
+	return Error_code::SUCCESS;
+}
+
+
+
+
+//处理一级任务, 普通任务
+Error_manager Carrier_base::execute_one_level_task(std::shared_ptr<Carrier_task> p_carrier_task)
+{
+	Error_manager t_error;
+	Error_manager t_result;
+
+	//检查指针
+	if (p_carrier_task == NULL) {
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 "Carrier_base::execute_one_level_task failed, POINTER_IS_NULL");
+	}
+	//检查任务类型,
+	if (p_carrier_task->get_task_type() != CARRIER_TASK)
+	{
+		return Error_manager(Error_code::CARRIER_TASK_TYPE_ERROR, Error_level::MINOR_ERROR,
+							 "Carrier_base::execute_one_level_task  get_task_type() != CARRIER_TASK ");
+	}
+
+	//检查接收方的状态
+	t_error = check_one_level_task();
+	if ( t_error != SUCCESS )
+	{
+		t_result.compare_and_cover_error(t_error);
+	}
+	else
+	{
+		//接受任务,并将任务的状态改为TASK_SIGNED已签收
+		mp_carrier_one_level_task = p_carrier_task;
+		mp_carrier_one_level_task->set_task_statu(TASK_SIGNED);
+
+		//这里不用检查任务内容, 直接下发给底层设备
+		//启动定位管理模块,的核心工作线程
+		m_carrier_status = E_ONE_LEVEL_WORK;
+		m_execute_condition.notify_all(true);
+		//通知 thread_work 子线程启动。
+
+		//将任务的状态改为 TASK_WORKING 处理中
+		mp_carrier_one_level_task->set_task_statu(TASK_WORKING);
+	}
+
+	if ( t_result != Error_code::SUCCESS )
+	{
+		return t_result;
+	}
+
+	return Error_code::SUCCESS;
+}
+//处理二级任务, 插队任务
+Error_manager Carrier_base::execute_two_level_task(std::shared_ptr<Carrier_task> p_carrier_task)
+{
+	Error_manager t_error;
+	Error_manager t_result;
+
+	//检查指针
+	if (p_carrier_task == NULL) {
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 "Carrier_base::execute_two_level_task failed, POINTER_IS_NULL");
+	}
+	//检查任务类型,
+	if (p_carrier_task->get_task_type() != CARRIER_TASK)
+	{
+		return Error_manager(Error_code::CARRIER_TASK_TYPE_ERROR, Error_level::MINOR_ERROR,
+							 "Carrier_base::execute_two_level_task  get_task_type() != CARRIER_TASK ");
+	}
+
+
+	//检查接收方的状态
+	t_error = check_two_level_task();
+	if ( t_error != SUCCESS )
+	{
+		t_result.compare_and_cover_error(t_error);
+	}
+	else
+	{
+		//接受任务,并将任务的状态改为TASK_SIGNED已签收
+		mp_carrier_two_level_task = p_carrier_task;
+		mp_carrier_two_level_task->set_task_statu(TASK_SIGNED);
+
+		//这里不用检查任务内容, 直接下发给底层设备
+		//启动定位管理模块,的核心工作线程
+		m_carrier_status = E_TWO_LEVEL_WORK;
+		m_execute_condition.notify_all(true);
+		//通知 thread_work 子线程启动。
+
+		//将任务的状态改为 TASK_WORKING 处理中
+		mp_carrier_two_level_task->set_task_statu(TASK_WORKING);
+	}
+
+	if ( t_result != Error_code::SUCCESS )
+	{
+		return t_result;
+	}
+
+	return Error_code::SUCCESS;
+}
+//处理三级任务, 核心任务
+Error_manager Carrier_base::execute_three_level_task(std::shared_ptr<Carrier_task> p_carrier_task)
+{
+	Error_manager t_error;
+	Error_manager t_result;
+
+	//检查指针
+	if (p_carrier_task == NULL) {
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 "Carrier_base::execute_three_level_task failed, POINTER_IS_NULL");
+	}
+	//检查任务类型,
+	if (p_carrier_task->get_task_type() != CARRIER_TASK)
+	{
+		return Error_manager(Error_code::CARRIER_TASK_TYPE_ERROR, Error_level::MINOR_ERROR,
+							 "Carrier_base::execute_three_level_task  get_task_type() != CARRIER_TASK ");
+	}
+
+
+	//检查接收方的状态
+	t_error = check_three_level_task();
+	if ( t_error != SUCCESS )
+	{
+		t_result.compare_and_cover_error(t_error);
+	}
+	else
+	{
+		//接受任务,并将任务的状态改为TASK_SIGNED已签收
+		mp_carrier_three_level_task = p_carrier_task;
+		mp_carrier_three_level_task->set_task_statu(TASK_SIGNED);
+
+		//这里不用检查任务内容, 直接下发给底层设备
+		//启动定位管理模块,的核心工作线程
+		m_carrier_status = E_THREE_LEVEL_WORK;
+		m_execute_condition.notify_all(true);
+		//通知 thread_work 子线程启动。
+
+		//将任务的状态改为 TASK_WORKING 处理中
+		mp_carrier_three_level_task->set_task_statu(TASK_WORKING);
+	}
+
+	if ( t_result != Error_code::SUCCESS )
+	{
+		return t_result;
+	}
+
+	return Error_code::SUCCESS;
+}
+
+//检查状态,是否正常运行
+Error_manager Carrier_base::check_status()
+{
+	if ( m_carrier_status == E_READY )
+	{
+		return Error_code::SUCCESS;
+	}
+	else if ( m_carrier_status >= E_BUSY && m_carrier_status <= E_THREE_LEVEL_OVER)
+	{
+		return Error_manager(Error_code::CARRIER_STATUS_BUSY, Error_level::NEGLIGIBLE_ERROR,
+							 " Carrier_base::check_status is busy ");
+	}
+	else
+	{
+		return Error_manager(Error_code::CARRIER_STATUS_ERROR, Error_level::MINOR_ERROR,
+							 " Carrier_base::check_status error ");
+	}
+	return Error_code::SUCCESS;
+}
+
+//判断能否执行一级任务
+Error_manager	Carrier_base::check_one_level_task()
+{
+	if ( m_carrier_status == E_READY )
+	{
+		return Error_code::SUCCESS;
+	}
+	else if ( m_carrier_status >= E_BUSY && m_carrier_status <= E_THREE_LEVEL_OVER)
+	{
+		return Error_manager(Error_code::CARRIER_STATUS_BUSY, Error_level::NEGLIGIBLE_ERROR,
+							 " Carrier_base::check_status is busy ");
+	}
+	else
+	{
+		return Error_manager(Error_code::CARRIER_STATUS_ERROR, Error_level::MINOR_ERROR,
+							 " Carrier_base::check_status error ");
+	}
+	return Error_code::SUCCESS;
+}
+//判断能否执行二级任务
+Error_manager	Carrier_base::check_two_level_task()
+{
+	if ( m_carrier_status == E_READY ||
+		 m_carrier_status == E_ONE_LEVEL_WORK ||
+		 m_carrier_status == E_ONE_LEVEL_OVER )
+	{
+		return Error_code::SUCCESS;
+	}
+	else if ( m_carrier_status >= E_TWO_LEVEL_WORK && m_carrier_status <= E_THREE_LEVEL_OVER)
+	{
+		return Error_manager(Error_code::CARRIER_STATUS_BUSY, Error_level::NEGLIGIBLE_ERROR,
+							 " Carrier_base::check_status is busy ");
+	}
+	else
+	{
+		return Error_manager(Error_code::CARRIER_STATUS_ERROR, Error_level::MINOR_ERROR,
+							 " Carrier_base::check_status error ");
+	}
+	return Error_code::SUCCESS;
+}
+//判断能否执行三级任务
+Error_manager	Carrier_base::check_three_level_task()
+{
+	if ( m_carrier_status == E_READY ||
+		 m_carrier_status == E_ONE_LEVEL_WORK ||
+		 m_carrier_status == E_ONE_LEVEL_OVER )
+	{
+		return Error_code::SUCCESS;
+	}
+	else if ( m_carrier_status >= E_TWO_LEVEL_WORK && m_carrier_status <= E_THREE_LEVEL_OVER)
+	{
+		return Error_manager(Error_code::CARRIER_STATUS_BUSY, Error_level::NEGLIGIBLE_ERROR,
+							 " Carrier_base::check_status is busy ");
+	}
+	else
+	{
+		return Error_manager(Error_code::CARRIER_STATUS_ERROR, Error_level::MINOR_ERROR,
+							 " Carrier_base::check_status error ");
+	}
+	return Error_code::SUCCESS;
+}
+
+//结束任务单,里面会根据任务的故障等级修正 任务单的状态
+Error_manager Carrier_base::end_task(std::shared_ptr<Carrier_task> carrier_task)
+{
+	LOG(INFO) << " ---Carrier_base::end_task run---"<< this;
+
+	carrier_task->m_respons_status = (Carrier_task::Respons_status)m_respons_status;
+
+	//注:这里只修改任务单的状态, 搬运器的状态不管
+	//在结束任务单时,将雷达任务状态改为 TASK_OVER 已结束
+	//判断任务单的错误等级,
+	if ( carrier_task->get_task_error_manager().get_error_level() < Error_level::MINOR_ERROR)
+	{
+		//强制改为TASK_OVER,不管它当前在做什么。
+		carrier_task->set_task_statu(TASK_OVER);
+	}
+	else
+	{
+		//强制改为 TASK_ERROR,不管它当前在做什么。
+		carrier_task->set_task_statu(TASK_ERROR);
+	}
+
+
+	return Error_code::SUCCESS;
+}
+
+//取消任务单,由发送方提前取消任务单
+Error_manager Carrier_base::cancel_task(std::shared_ptr<Carrier_task> carrier_task)
+{
+	//找到对应的任务单
+	if ( carrier_task->get_task_id() == mp_carrier_one_level_task->get_task_id() )
+	{
+		if ( m_carrier_status == E_ONE_LEVEL_WORK || m_carrier_status == E_ONE_LEVEL_OVER )
+		{
+			//如果正在执行一级任务, 那么取消当前指令, 然后降级
+			m_execute_condition.notify_all(false);
+			//确保内部线程已经停下
+			while (m_execute_condition.is_working())
+			{
+
+			}
+			cancel_command();
+			mp_carrier_one_level_task.reset();
+			m_carrier_status = E_READY;
+			m_execute_condition.notify_all(true);
+		}
+		else
+		{
+			//否则直接销毁任务单
+			mp_carrier_one_level_task.reset();
+		}
+	}
+	else if ( carrier_task->get_task_id() == mp_carrier_two_level_task->get_task_id() )
+	{
+		if ( m_carrier_status == E_TWO_LEVEL_WORK || m_carrier_status == E_TWO_LEVEL_OVER )
+		{
+			//如果正在执行二级任务, 那么取消当前指令, 然后降级
+			m_execute_condition.notify_all(false);
+			//确保内部线程已经停下
+			while (m_execute_condition.is_working())
+			{
+
+			}
+			cancel_command();
+			mp_carrier_two_level_task.reset();
+			m_carrier_status = E_ONE_LEVEL_WORK;
+			m_execute_condition.notify_all(true);
+		}
+		else
+		{
+			//否则直接销毁任务单
+			mp_carrier_two_level_task.reset();
+		}
+	}
+	else if ( carrier_task->get_task_id() == mp_carrier_three_level_task->get_task_id() )
+	{
+		if ( m_carrier_status == E_THREE_LEVEL_WORK || m_carrier_status == E_THREE_LEVEL_OVER )
+		{
+			//如果正在执行三级任务, 那么取消当前指令, 然后降级
+			m_execute_condition.notify_all(false);
+			//确保内部线程已经停下
+			while (m_execute_condition.is_working())
+			{
+
+			}
+			cancel_command();
+			mp_carrier_three_level_task.reset();
+			m_carrier_status = E_TWO_LEVEL_WORK;
+			m_execute_condition.notify_all(true);
+		}
+		else
+		{
+			//否则直接销毁任务单
+			mp_carrier_two_level_task.reset();
+		}
+	}
+	else
+	{
+		return Error_manager(Error_code::CARRIER_TASK_NOTHINGNESS, Error_level::MINOR_ERROR,
+							 " carrier_task->get_task_id() is nothingness ");
+	}
+
+	carrier_task->set_task_statu(TASK_DEAD);
+	return Error_code::SUCCESS;
+}
+
+
+//判断是否为待机,如果已经准备好,则可以执行任务。
+bool Carrier_base::is_ready()
+{
+	return (m_carrier_status == E_READY);
+}
+
+Carrier_base::Carrier_status Carrier_base::get_carrier_status()
+{
+	return m_carrier_status;
+}
+
+
+//执行外界任务的执行函数
+void Carrier_base::execute_thread_fun()
+{
+	LOG(INFO) << " execute_thread_fun start "<< this;
+
+//	while (1);
+
+	Error_manager t_error;
+
+	while (m_execute_condition.is_alive())
+	{
+		m_execute_condition.wait();
+		if ( m_execute_condition.is_alive() )
+		{
+			std::this_thread::sleep_for(std::chrono::microseconds(1));
+			std::this_thread::yield();
+
+			switch ( (Carrier_status)m_carrier_status )
+			{
+				//核心任务, (三级任务)
+				case E_THREE_LEVEL_WORK:
+				{
+					if ( mp_carrier_three_level_task.get() != NULL )
+					{
+						//执行三级任务
+						std::unique_lock<std::mutex> t_lock(mp_carrier_three_level_task->m_lock);
+						m_parkspace_unit_id = mp_carrier_three_level_task->m_parkspace_unit_id;
+						m_parkspace_floor_id = mp_carrier_three_level_task->m_parkspace_floor_id;
+						m_parkspace_room_id = mp_carrier_three_level_task->m_parkspace_room_id;
+						m_command_key = mp_carrier_three_level_task->m_command_key;
+						m_motion_direction = mp_carrier_three_level_task->m_motion_direction;
+						m_car_center_x = mp_carrier_three_level_task->m_car_center_x;
+						m_car_center_y = mp_carrier_three_level_task->m_car_center_y;
+						m_car_angle = mp_carrier_three_level_task->m_car_angle;
+
+						//更新通信
+						update_device_communication();
+
+						//检查设备的答复
+						if ( m_respons_status == RESPONS_OVER )
+						{
+							mp_carrier_three_level_task->m_respons_status = (Carrier_task::Respons_status)m_respons_status;
+							end_task(mp_carrier_three_level_task);
+							m_carrier_status = E_THREE_LEVEL_OVER;
+						}
+						else if ( m_respons_status == RESPONS_MINOR_ERROR || m_respons_status == RESPONS_CRITICAL_ERROR )
+						{
+							mp_carrier_three_level_task->m_respons_status = (Carrier_task::Respons_status)m_respons_status;
+							//添加错误码
+							Error_manager t_error(CARRIER_RESPONS_ERROR, MINOR_ERROR, "m_respons_status is error");
+							mp_carrier_three_level_task->set_task_error_manager(t_error);
+							end_task(mp_carrier_three_level_task);
+							m_carrier_status = E_THREE_LEVEL_OVER;
+						}
+						else
+						{
+							//设备正常运行
+							//延时1ms, snap7的通信效率偏慢, 不需要高频率检查
+							std::this_thread::sleep_for(std::chrono::milliseconds(1));
+						}
+					}
+					else
+					{
+						//直接降级
+						m_carrier_status = E_TWO_LEVEL_WORK;
+					}
+					break;
+				}
+				case E_THREE_LEVEL_OVER:
+				{
+					if ( mp_carrier_three_level_task.get() != NULL )
+					{
+						//检查任务状态,
+						//在 E_THREE_LEVEL_WORK 里面, 已经 设为 TASK_OVER 了.
+						//等待发送方的新指令, (发送方会把状态改为回收, 表示这个任务结束)
+						if ( mp_carrier_three_level_task->get_task_statu() == TASK_WITHDRAW )
+						{
+							//这里会通知任务已经释放, 然后销毁任务单,  并降级
+							mp_carrier_three_level_task->set_task_statu(TASK_FREE);
+							mp_carrier_three_level_task.reset();
+							m_carrier_status = E_TWO_LEVEL_WORK;
+						}
+						//else //保持不动, 直到发送方给定新的任务,
+					}
+					else
+					{
+						//直接降级
+						m_carrier_status = E_TWO_LEVEL_WORK;
+					}
+					break;
+				}
+				case E_TWO_LEVEL_WORK:
+				{
+					if ( mp_carrier_two_level_task.get() != NULL )
+					{
+						//执行三级任务
+						std::unique_lock<std::mutex> t_lock(mp_carrier_two_level_task->m_lock);
+						m_parkspace_unit_id = mp_carrier_two_level_task->m_parkspace_unit_id;
+						m_parkspace_floor_id = mp_carrier_two_level_task->m_parkspace_floor_id;
+						m_parkspace_room_id = mp_carrier_two_level_task->m_parkspace_room_id;
+						m_command_key = mp_carrier_two_level_task->m_command_key;
+						m_motion_direction = mp_carrier_two_level_task->m_motion_direction;
+						m_car_center_x = mp_carrier_two_level_task->m_car_center_x;
+						m_car_center_y = mp_carrier_two_level_task->m_car_center_y;
+						m_car_angle = mp_carrier_two_level_task->m_car_angle;
+
+						//更新通信
+						update_device_communication();
+
+						//检查设备的答复
+						if ( m_respons_status == RESPONS_OVER )
+						{
+							mp_carrier_two_level_task->m_respons_status = (Carrier_task::Respons_status)m_respons_status;
+							end_task(mp_carrier_two_level_task);
+							m_carrier_status = E_TWO_LEVEL_OVER;
+						}
+						else if ( m_respons_status == RESPONS_MINOR_ERROR || m_respons_status == RESPONS_CRITICAL_ERROR )
+						{
+							mp_carrier_two_level_task->m_respons_status = (Carrier_task::Respons_status)m_respons_status;
+							//添加错误码
+							Error_manager t_error(CARRIER_RESPONS_ERROR, MINOR_ERROR, "m_respons_status is error");
+							mp_carrier_two_level_task->set_task_error_manager(t_error);
+							end_task(mp_carrier_two_level_task);
+							m_carrier_status = E_TWO_LEVEL_OVER;
+						}
+						else
+						{
+							//设备正常运行
+							//延时1ms, snap7的通信效率偏慢, 不需要高频率检查
+							std::this_thread::sleep_for(std::chrono::milliseconds(1));
+						}
+					}
+					else
+					{
+						//直接降级
+						m_carrier_status = E_ONE_LEVEL_WORK;
+					}
+					break;
+				}
+				case E_TWO_LEVEL_OVER:
+				{
+					if ( mp_carrier_two_level_task.get() != NULL )
+					{
+						//检查任务状态,
+						//在 E_TWO_LEVEL_WORK 里面, 已经 设为 TASK_OVER 了.
+						//等待发送方的新指令, (发送方会把状态改为回收, 表示这个任务结束)
+						if ( mp_carrier_two_level_task->get_task_statu() == TASK_WITHDRAW )
+						{
+							//这里会通知任务已经释放, 然后销毁任务单,  并降级
+							mp_carrier_two_level_task->set_task_statu(TASK_FREE);
+							mp_carrier_two_level_task.reset();
+							m_carrier_status = E_ONE_LEVEL_WORK;
+						}
+						//else //保持不动, 直到发送方给定新的任务,
+					}
+					else
+					{
+						//直接降级
+						m_carrier_status = E_ONE_LEVEL_WORK;
+					}
+					break;
+				}
+				case E_ONE_LEVEL_WORK:
+				{
+					if ( mp_carrier_one_level_task.get() != NULL )
+					{
+						//执行三级任务
+						std::unique_lock<std::mutex> t_lock(mp_carrier_one_level_task->m_lock);
+						m_parkspace_unit_id = mp_carrier_one_level_task->m_parkspace_unit_id;
+						m_parkspace_floor_id = mp_carrier_one_level_task->m_parkspace_floor_id;
+						m_parkspace_room_id = mp_carrier_one_level_task->m_parkspace_room_id;
+						m_command_key = mp_carrier_one_level_task->m_command_key;
+						m_motion_direction = mp_carrier_one_level_task->m_motion_direction;
+						m_car_center_x = mp_carrier_one_level_task->m_car_center_x;
+						m_car_center_y = mp_carrier_one_level_task->m_car_center_y;
+						m_car_angle = mp_carrier_one_level_task->m_car_angle;
+
+						//更新通信
+						update_device_communication();
+
+						//检查设备的答复
+						if ( m_respons_status == RESPONS_OVER )
+						{
+							mp_carrier_one_level_task->m_respons_status = (Carrier_task::Respons_status)m_respons_status;
+							end_task(mp_carrier_one_level_task);
+							m_carrier_status = E_ONE_LEVEL_OVER;
+						}
+						else if ( m_respons_status == RESPONS_MINOR_ERROR || m_respons_status == RESPONS_CRITICAL_ERROR )
+						{
+							mp_carrier_one_level_task->m_respons_status = (Carrier_task::Respons_status)m_respons_status;
+							//添加错误码
+							Error_manager t_error(CARRIER_RESPONS_ERROR, MINOR_ERROR, "m_respons_status is error");
+							mp_carrier_one_level_task->set_task_error_manager(t_error);
+							end_task(mp_carrier_one_level_task);
+							m_carrier_status = E_ONE_LEVEL_OVER;
+						}
+						else if(m_carrier_status == E_ONE_LEVEL_WORK)
+						{
+							//设备正常运行
+							//延时1ms, snap7的通信效率偏慢, 不需要高频率检查
+							std::this_thread::sleep_for(std::chrono::milliseconds(1));
+						}
+					}
+					else
+					{
+						//直接降级
+						m_carrier_status = E_READY;
+					}
+					break;
+				}
+				case E_ONE_LEVEL_OVER:
+				{
+					if ( mp_carrier_one_level_task.get() != NULL )
+					{
+						//检查任务状态,
+						//在 E_ONE_LEVEL_WORK 里面, 已经 设为 TASK_OVER 了.
+						//等待发送方的新指令, (发送方会把状态改为回收, 表示这个任务结束)
+						if ( mp_carrier_one_level_task->get_task_statu() == TASK_WITHDRAW )
+						{
+							//这里会通知任务已经释放, 然后销毁任务单,  并降级
+							mp_carrier_one_level_task->set_task_statu(TASK_FREE);
+							mp_carrier_one_level_task.reset();
+							m_carrier_status = E_READY;
+						}
+						//else //保持不动, 直到发送方给定新的任务,
+					}
+					else
+					{
+						//直接降级
+						m_carrier_status = E_READY;
+					}
+					break;
+				}
+				case E_FAULT:
+				{
+					//更新通信
+					update_device_communication();
+
+					//所有任务报错, 并销毁任务.
+					if ( mp_carrier_one_level_task.get() != NULL )
+					{
+						//添加错误码
+						Error_manager t_error(CARRIER_STATUS_ERROR, MINOR_ERROR, "m_respons_status is error");
+						mp_carrier_one_level_task->set_task_error_manager(t_error);
+						end_task(mp_carrier_one_level_task);
+						mp_carrier_one_level_task.reset();
+					}
+					if ( mp_carrier_two_level_task.get() != NULL )
+					{
+						//添加错误码
+						Error_manager t_error(CARRIER_STATUS_ERROR, MINOR_ERROR, "m_respons_status is error");
+						mp_carrier_two_level_task->set_task_error_manager(t_error);
+						end_task(mp_carrier_two_level_task);
+						mp_carrier_two_level_task.reset();
+					}
+					if ( mp_carrier_three_level_task.get() != NULL )
+					{
+						//添加错误码
+						Error_manager t_error(CARRIER_STATUS_ERROR, MINOR_ERROR, "m_respons_status is error");
+						mp_carrier_three_level_task->set_task_error_manager(t_error);
+						end_task(mp_carrier_three_level_task);
+						mp_carrier_three_level_task.reset();
+					}
+
+
+					break;
+				}
+				case E_DISCONNECT:
+				{
+					//更新通信
+					update_device_communication();
+					//所有任务报错, 并销毁任务.
+					if ( mp_carrier_one_level_task.get() != NULL )
+					{
+						//添加错误码
+						Error_manager t_error(CARRIER_STATUS_DISCONNECT, MINOR_ERROR, "m_respons_status is error");
+						mp_carrier_one_level_task->set_task_error_manager(t_error);
+						end_task(mp_carrier_one_level_task);
+						mp_carrier_one_level_task.reset();
+					}
+					if ( mp_carrier_two_level_task.get() != NULL )
+					{
+						//添加错误码
+						Error_manager t_error(CARRIER_STATUS_DISCONNECT, MINOR_ERROR, "m_respons_status is error");
+						mp_carrier_two_level_task->set_task_error_manager(t_error);
+						end_task(mp_carrier_two_level_task);
+						mp_carrier_two_level_task.reset();
+					}
+					if ( mp_carrier_three_level_task.get() != NULL )
+					{
+						//添加错误码
+						Error_manager t_error(CARRIER_STATUS_DISCONNECT, MINOR_ERROR, "m_respons_status is error");
+						mp_carrier_three_level_task->set_task_error_manager(t_error);
+						end_task(mp_carrier_three_level_task);
+						mp_carrier_three_level_task.reset();
+					}
+
+
+					break;
+				}
+				case E_READY:
+				{
+					//更新通信
+					update_device_communication();
+					break;
+				}
+				default:
+				{
+
+					break;
+				}
+			}
+
+
+
+		}
+	}
+	LOG(INFO) << " execute_thread_fun end "<< this;
+	return;
+}
+
+
+//更新设备底层通信数据
+Error_manager Carrier_base::update_device_communication()
+{
+	//加锁
+	std::mutex * tp_data_lock = 	Dispatch_communication::get_instance_references().get_data_lock();
+	std::unique_lock<std::mutex> t_lock(*tp_data_lock);
+
+	//请求消息, 调度->plc
+	Dispatch_communication::Request_from_dispatch_to_plc * tp_request_from_dispatch_to_plc =
+	Dispatch_communication::get_instance_references().get_request_from_dispatch_to_plc();
+	tp_request_from_dispatch_to_plc->m_block_id = m_parkspace_unit_id;
+	tp_request_from_dispatch_to_plc->m_floor_id = m_parkspace_floor_id;
+	tp_request_from_dispatch_to_plc->m_parkspace_id = m_parkspace_room_id;
+	memcpy(tp_request_from_dispatch_to_plc->m_command_key, m_command_key.c_str(), m_command_key.size());
+	tp_request_from_dispatch_to_plc->m_is_entrance_flag = m_motion_direction;
+	tp_request_from_dispatch_to_plc->m_center_x = m_car_center_x;
+	tp_request_from_dispatch_to_plc->m_center_y = m_car_center_y;
+	tp_request_from_dispatch_to_plc->m_car_angle = m_car_angle;
+
+
+	//答复消息, plc->调度
+	Dispatch_communication::Response_from_plc_to_dispatch * tp_response_from_plc_to_dispatch =
+	Dispatch_communication::get_instance_references().get_response_from_plc_to_dispatch();
+	m_respons_key = (char*)(tp_response_from_plc_to_dispatch->m_command_key);
+	if ( m_respons_key == m_command_key )
+	{
+		if ( tp_response_from_plc_to_dispatch->m_task_status == 0 )
+		{
+			if ( tp_response_from_plc_to_dispatch->m_command_flag == 0 )
+			{
+				m_respons_status = RESPONS_NORMAL;
+			}
+			else
+			{
+				m_respons_status = RESPONS_OVER;
+			}
+		}
+		else if ( tp_response_from_plc_to_dispatch->m_task_status == 1 )
+		{
+			m_respons_status = RESPONS_MINOR_ERROR;
+		}
+		else
+		{
+			m_respons_status = RESPONS_CRITICAL_ERROR;
+		}
+	}
+	else
+	{
+		m_respons_status = RESPONS_NORMAL;
+	}
+
+	//状态消息, 调度->plc
+	Dispatch_communication::Status_from_dispatch_to_plc * tp_status_from_dispatch_to_plc =
+	Dispatch_communication::get_instance_references().get_status_from_dispatch_to_plc();
+	tp_status_from_dispatch_to_plc->m_heartbeat++;
+
+	//状态消息, plc->调度
+	Dispatch_communication::Status_from_plc_to_dispatch * tp_status_from_plc_to_dispatch =
+	Dispatch_communication::get_instance_references().get_status_from_plc_to_dispatch();
+	//通过心跳帧来判断通信是否正常
+	if ( m_last_heartbeat != tp_status_from_plc_to_dispatch->m_heartbeat )
+	{
+		m_last_heartbeat = tp_status_from_plc_to_dispatch->m_heartbeat;
+		m_status_updata_time = std::chrono::system_clock::now();
+
+		m_carrier_coordinate_x = tp_status_from_plc_to_dispatch->m_carrier_coordinates;
+		m_carrier_coordinate_z = tp_status_from_plc_to_dispatch->m_elevator_coordinates;
+		m_carrier_angle = tp_status_from_plc_to_dispatch->m_carrier_angle;
+
+		m_elevator_device_status = tp_status_from_plc_to_dispatch->m_elevator_information;
+		memcpy(m_elevator_error_code, tp_status_from_plc_to_dispatch->m_elevator_error_code, 50);
+		m_elevator_error_description = (char*)(tp_status_from_plc_to_dispatch->m_carrier_error_string);
+
+		m_carrier_device_status = tp_status_from_plc_to_dispatch->m_carrier_information;
+		memcpy(m_carrier_error_code, tp_status_from_plc_to_dispatch->m_carrier_error_code, 50);
+		m_carrier_error_description = (char*)(tp_status_from_plc_to_dispatch->m_carrier_error_string);
+
+		if ( m_carrier_status == E_DISCONNECT )
+		{
+			m_carrier_status = E_THREE_LEVEL_WORK;
+		}
+	}
+	else if(std::chrono::system_clock::now() - m_status_updata_time > std::chrono::milliseconds(CARRIER_COMMUNICATION_OVER_TIME_MS))
+	{
+		m_carrier_status = E_DISCONNECT;
+	}
+
+
+	return Error_code::SUCCESS;
+}
+
+//取消下发的指令
+Error_manager Carrier_base::cancel_command()
+{
+	//以后再写 need programe
+	//目前调度和plc的通信指令做的很简单,没有暂停和急停 复位等操作.
+	//这里先空着,以后再写.
+	//调度模块单方面销毁任务, 不管底层plc的执行情况, 也不去告知plc任务取消.
+
+	return Error_code::SUCCESS;
+}
+
+
+
+

+ 152 - 0
dispatch/carrier_base.h

@@ -0,0 +1,152 @@
+//
+// Created by huli on 2020/7/20.
+//
+
+#ifndef NNXX_TESTS_CARRIER_BASE_H
+#define NNXX_TESTS_CARRIER_BASE_H
+
+#include "../error_code/error_code.h"
+#include <glog/logging.h>
+#include <thread>
+#include <mutex>
+#include "../tool/thread_condition.h"
+#include "../dispatch/carrier_task.h"
+
+//搬运器的基类, 楚天项目就是电梯和中跑车的合并
+class Carrier_base
+{
+public:
+	//搬运器底层通信延时5000ms
+#define	CARRIER_COMMUNICATION_OVER_TIME_MS	5000
+
+	//搬运器状态,
+	enum Carrier_status
+	{
+		E_UNKNOW               	= 0,    //未知
+		E_READY               	= 1,    //准备,待机
+		E_BUSY					= 2, 	//工作正忙
+
+		E_ONE_LEVEL_WORK		= 3,	//一级工作状态, 就是普通的移动任务
+		E_ONE_LEVEL_OVER		= 4, 	//一级工作完成,
+		E_TWO_LEVEL_WORK		= 5,	//二级工作状态, 就是紧急避让, 插队任务(会在执行一级任务的过程中, 插队并优先执行二级任务)
+		E_TWO_LEVEL_OVER		= 6, 	//一级工作完成,
+		E_THREE_LEVEL_WORK		= 7,	//三级工作任务, 就是锁定硬件资源, 不让插队, (除非急停或者取消任务)
+		E_THREE_LEVEL_OVER		= 8, 	//一级工作完成,
+
+		E_FAULT					= 100,	//故障
+		E_DISCONNECT			= 101, 	//通信故障
+	};
+
+	//指令完成状态, 搬运器答复指令, 返回任务完成的情况
+	enum Respons_status
+	{
+		RESPONS_NORMAL             	= 0,    //正常
+		RESPONS_OVER               	= 1,    //任务完成
+		RESPONS_MINOR_ERROR			= 100,	//一般故障, 可恢复
+		RESPONS_CRITICAL_ERROR		= 101,	//致命故障,不可恢复
+	};
+
+public:
+	Carrier_base();
+	Carrier_base(const Carrier_base& other)= default;
+	Carrier_base& operator =(const Carrier_base& other)= default;
+	~Carrier_base();
+public://API functions
+	//搬运器 初始化
+	virtual Error_manager carrier_base_init();
+	//搬运器 反初始化
+	virtual Error_manager carrier_base_uninit();
+
+	//处理一级任务, 普通任务
+	virtual Error_manager execute_one_level_task(std::shared_ptr<Carrier_task> p_carrier_task);
+	//处理二级任务, 插队任务
+	virtual Error_manager execute_two_level_task(std::shared_ptr<Carrier_task> p_carrier_task);
+	//处理三级任务, 核心任务
+	virtual Error_manager execute_three_level_task(std::shared_ptr<Carrier_task> p_carrier_task);
+	//检查状态,是否正常运行
+	Error_manager check_status();
+
+	//注意了, 调度任务允许同时接受多个任务
+	//判断能否执行一级任务
+	Error_manager	check_one_level_task();
+	//判断能否执行二级任务
+	Error_manager	check_two_level_task();
+	//判断能否执行三级任务
+	Error_manager	check_three_level_task();
+
+	//结束任务单,里面会根据任务的故障等级修正 任务单的状态
+	Error_manager end_task(std::shared_ptr<Carrier_task> carrier_task);
+	//取消任务单,由发送方提前取消任务单
+	Error_manager cancel_task(std::shared_ptr<Carrier_task> carrier_task);
+
+	//判断是否为待机,如果已经准备好,则可以执行任务。
+	bool is_ready();
+public://get or set member variable
+	Carrier_status get_carrier_status();
+
+protected://member functions
+	//执行外界任务的执行函数
+	void execute_thread_fun();
+
+	//更新设备底层通信数据
+	virtual Error_manager update_device_communication();
+
+	//取消下发的指令
+	virtual Error_manager cancel_command();
+protected://member variable
+	std::atomic<Carrier_status>			m_carrier_status;			//搬运器总状态, 控制任务流程
+	int 								m_carrier_id;				//搬运器id, (楚天项目和单元号对应)
+	
+	//下发到硬件
+	//搬运器的目标车位
+	unsigned short 						m_parkspace_unit_id;		//车位单元号(楚天项目为1~3)
+	unsigned short 						m_parkspace_floor_id;		//车位楼层号(楚天项目为1~14)
+	unsigned short 						m_parkspace_room_id;		//车位同层的房间号	(楚天项目一楼为1~4, 楼上为1~6)
+	std::string							m_command_key;				//任务唯一码, 用作识别
+	unsigned char						m_motion_direction;			//调度方向, 根据停车取车选择出入口, 	1=入口,0=非入口
+	float 								m_car_center_x;				//汽车的中心坐标x
+	float 								m_car_center_y;				//汽车的中心坐标y
+	float 								m_car_angle;				//汽车的旋转角(角度-90~90)
+
+	//硬件反馈
+	//搬运器当前坐标
+	std::string							m_respons_key;				//应答的唯一码, 用作识别
+	Respons_status						m_respons_status;			//指令完成状态, 搬运器答复指令, 返回任务完成的情况
+
+
+
+	//硬件状态, 目前只做显示判断
+	std::chrono::system_clock::time_point	m_status_updata_time;	//状态更新时间点
+	unsigned char						m_last_heartbeat;			//上一次的心跳
+
+	//硬件坐标,
+	float 								m_carrier_coordinate_x;			//搬运器坐标x轴, 中跑车控制横向移动
+	float 								m_carrier_coordinate_y;			//搬运器坐标y轴, (本模块默认为0, 由AGV模块去控制纵向移动)
+	float 								m_carrier_coordinate_z;			//搬运器坐标z轴, 电梯控制上下移动
+	float 								m_carrier_angle;				//搬运器角度
+	//搬运器设备的状态(0bit为1:急停正常, 1bit为1:处于安全位置, 2bit为1:静止状态, 3bit为1:可执行新指令, 4bit为1:存在故障)
+	unsigned char						m_carrier_device_status;	//搬运器设备的状态, 楚天项目就是中跑车
+	unsigned char						m_carrier_error_code[50];	//搬运器设备的报警信息位
+	std::string							m_carrier_error_description;//搬运器设备的报警状态描述
+	//升降机设备的状态(0bit为1:急停正常, 1bit为1:处于安全位置, 2bit为1:静止状态, 3bit为1:可执行新指令, 4bit为1:存在故障)
+	unsigned char						m_elevator_device_status;	//升降机设备状态, 楚天项目就是电梯
+	unsigned char						m_elevator_error_code[50];	//升降机设备的报警信息位
+	std::string							m_elevator_error_description;//升降机设备的报警状态描述
+
+
+	//任务执行线程
+	std::thread*        				mp_execute_thread;   			//执行的线程指针,内存由本类管理
+	Thread_condition					m_execute_condition;			//执行的条件变量
+
+	std::shared_ptr<Carrier_task>		mp_carrier_one_level_task;		//搬运器的普通任务, (一般移动和等待指令, 允许被打断)
+	std::shared_ptr<Carrier_task>		mp_carrier_two_level_task;		//搬运器的优先任务, (紧急避让和插队指令, 允许打断普通任务)
+	std::shared_ptr<Carrier_task>		mp_carrier_three_level_task;	//搬运器的核心任务, (锁定位置进行抓车和放车, 最高任务, 不允许打断和被打断)
+
+
+
+private:
+
+};
+
+
+#endif //NNXX_TESTS_CARRIER_BASE_H

+ 82 - 0
dispatch/carrier_task.cpp

@@ -0,0 +1,82 @@
+//
+// Created by huli on 2020/10/20.
+//
+
+#include "carrier_task.h"
+
+Carrier_task::Carrier_task()
+{
+	//构造函数锁定任务类型为 LOCATE_MANGER_TASK,后续不允许更改
+	m_task_type = CARRIER_TASK;
+	m_task_statu = TASK_CREATED;
+	m_task_statu_information.clear();
+	m_task_error_manager.error_manager_clear_all();
+
+	m_parkspace_unit_id = 0;
+	m_parkspace_floor_id = 0;
+	m_parkspace_room_id = 0;
+//	m_command_key = "";
+	m_motion_direction = 0;
+	m_car_center_x = 0;
+	m_car_center_y = 0;
+	m_car_angle = 0;
+
+
+
+	unsigned short 						m_parkspace_floor_id;		//车位楼层号(楚天项目为1~14)
+	unsigned short 						m_parkspace_room_id;		//车位同层的房间号	(楚天项目一楼为1~4, 楼上为1~6)
+	std::string							m_command_key;				//任务唯一码
+	unsigned char						m_motion_direction;			//调度方向, 根据停车取车选择出入口, 	1=入口,0=非入口
+	float 								m_car_center_x;				//汽车的中心坐标x
+	float 								m_car_center_y;				//汽车的中心坐标y
+	float 								m_car_angle;				//汽车的旋转角(角度-90~90)
+
+	//任务执行结果
+	Respons_status						m_respons_status;			//指令完成状态, 搬运器答复指令, 返回任务完成的情况
+}
+
+Carrier_task::~Carrier_task()
+{
+
+}
+
+
+//初始化任务单,必须初始化之后才可以使用,(可选参数)
+//    input:tast_receiver 接受对象
+//    input:task_over_time 超时时间
+Error_manager Carrier_task::task_init(void* p_tast_receiver,
+						std::chrono::milliseconds task_over_time,
+						unsigned short parkspace_unit_id,
+						unsigned shortparkspace_floor_id,
+						unsigned shortparkspace_room_id,
+						std::string command_key,
+						unsigned char motion_direction,
+						float car_center_x,
+						float car_center_y,
+						float car_angle
+)
+{
+	m_task_statu = TASK_CREATED;
+	m_task_statu_information.clear();
+	m_task_error_manager.error_manager_clear_all();
+
+	m_parkspace_unit_id = parkspace_unit_id;
+	m_parkspace_floor_id = shortparkspace_floor_id;
+	m_parkspace_room_id = shortparkspace_room_id;
+	m_command_key = command_key;
+	m_motion_direction = motion_direction;
+	m_car_center_x = car_center_x;
+	m_car_center_y = car_center_y;
+	m_car_angle = car_angle;
+
+	m_respons_status = RESPONS_NORMAL;
+}
+
+
+
+
+
+
+
+
+

+ 72 - 0
dispatch/carrier_task.h

@@ -0,0 +1,72 @@
+//
+// Created by huli on 2020/10/20.
+//
+
+#ifndef NNXX_TESTS_CARRIER_TASK_H
+#define NNXX_TESTS_CARRIER_TASK_H
+
+#include "../error_code/error_code.h"
+#include "../task/task_command_manager.h"
+#include "../task/task_base.h"
+#include <mutex>
+
+
+class Carrier_task :public Task_Base
+{
+public:
+	//指令完成状态, 搬运器答复指令, 返回任务完成的情况
+	enum Respons_status
+	{
+		RESPONS_NORMAL             	= 0,    //正常
+		RESPONS_OVER               	= 1,    //任务完成
+		RESPONS_MINOR_ERROR			= 100,	//一般故障, 可恢复
+		RESPONS_CRITICAL_ERROR		= 101,	//致命故障,不可恢复
+	};
+public:
+	Carrier_task();
+	Carrier_task(const Carrier_task& other)= default;
+	Carrier_task& operator =(const Carrier_task& other)= default;
+	~Carrier_task();
+public://API functions
+
+	//初始化任务单,必须初始化之后才可以使用,(可选参数)
+	//    input:tast_receiver 接受对象
+	//    input:task_over_time 超时时间
+	Error_manager task_init(void* p_tast_receiver,
+							std::chrono::milliseconds task_over_time,
+							unsigned short parkspace_unit_id,
+							unsigned shortparkspace_floor_id,
+							unsigned shortparkspace_room_id,
+							std::string command_key,
+							unsigned char motion_direction = 0,
+							float car_center_x = 0,
+							float car_center_y = 0,
+							float car_angle = 0
+	);
+public://get or set member variable
+
+protected://member functions
+
+public://member variable
+
+	std::mutex							m_lock;	//锁
+
+	//搬运器的目标车位
+	unsigned short 						m_parkspace_unit_id;		//车位单元号(楚天项目为1~3)
+	unsigned short 						m_parkspace_floor_id;		//车位楼层号(楚天项目为1~14)
+	unsigned short 						m_parkspace_room_id;		//车位同层的房间号	(楚天项目一楼为1~4, 楼上为1~6)
+	std::string							m_command_key;				//任务唯一码
+	unsigned char						m_motion_direction;			//调度方向, 根据停车取车选择出入口, 	1=入口,0=非入口
+	float 								m_car_center_x;				//汽车的中心坐标x
+	float 								m_car_center_y;				//汽车的中心坐标y
+	float 								m_car_angle;				//汽车的旋转角(角度-90~90)
+
+	//任务执行结果
+	Respons_status						m_respons_status;			//指令完成状态, 搬运器答复指令, 返回任务完成的情况
+
+private:
+
+};
+
+
+#endif //NNXX_TESTS_CARRIER_TASK_H

+ 216 - 0
dispatch/dispatch_communication.cpp

@@ -0,0 +1,216 @@
+//
+// Created by huli on 2020/9/25.
+//
+
+#include "dispatch_communication.h"
+
+
+Dispatch_communication::Dispatch_communication()
+{
+
+}
+
+
+Dispatch_communication::~Dispatch_communication()
+{
+
+}
+
+
+//初始化 通信 模块。如下三选一
+Error_manager Dispatch_communication::communication_init()
+{
+	int t_index = 0;
+	std::vector<Snap7_buf::Variable_information>		t_variable_information_vector;
+
+	//往map通信缓存里面添加所需要的buf
+	std::unique_lock<std::mutex> t_lock1(m_receive_buf_lock);
+	std::unique_lock<std::mutex> t_lock2(m_send_buf_lock);
+
+	t_index = 0;
+	t_variable_information_vector.clear();
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved0", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_command_flag", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_task_status", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved3_11", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 9 });
+	t_index += sizeof(unsigned char)*9;
+
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_block_id", typeid(unsigned short).name(), t_index,sizeof(unsigned short), 1 });
+	t_index += sizeof(unsigned short)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_floor_id", typeid(unsigned short).name(), t_index,sizeof(unsigned short), 1 });
+	t_index += sizeof(unsigned short)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_parkspace_id", typeid(unsigned short).name(), t_index,sizeof(unsigned short), 1 });
+	t_index += sizeof(unsigned short)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_command_key", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 256 });
+	t_index += sizeof(unsigned char)*256;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_is_entrance_flag", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved275_289", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 15 });
+	t_index += sizeof(unsigned char)*15;
+
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_center_x", typeid(float).name(), t_index,sizeof(float), 1 });
+	t_index += sizeof(float)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_center_y", typeid(float).name(), t_index,sizeof(float), 1 });
+	t_index += sizeof(float)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_car_angle", typeid(float).name(), t_index,sizeof(float), 1 });
+	t_index += sizeof(float)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_car_length", typeid(float).name(), t_index,sizeof(float), 1 });
+	t_index += sizeof(float)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_car_width", typeid(float).name(), t_index,sizeof(float), 1 });
+	t_index += sizeof(float)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_car_height", typeid(float).name(), t_index,sizeof(float), 1 });
+	t_index += sizeof(float)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_wheel_base", typeid(float).name(), t_index,sizeof(float), 1 });
+	t_index += sizeof(float)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_wheel_width", typeid(float).name(), t_index,sizeof(float), 1 });
+	t_index += sizeof(float)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_voucher_number", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 256 });
+	t_index += sizeof(unsigned char)*256;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_plate_number", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 512 });
+	t_index += sizeof(unsigned char)*512;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_phone_number", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 256 });
+	t_index += sizeof(unsigned char)*256;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved1346_1377", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 32 });
+	t_index += sizeof(unsigned char)*32;
+	Snap7_buf t_response(RESPONSE_FROM_PLC_TO_DISPATCH_DBNUMBER, 0, sizeof(Response_from_plc_to_dispatch), t_variable_information_vector, Snap7_buf::LOOP_COMMUNICATION);
+	m_receive_buf_map[0] = t_response;
+
+	Snap7_buf t_request(REQUEST_FROM_DISPATCH_TO_PLC_DBNUMBER, 0, sizeof(Request_from_dispatch_to_plc), t_variable_information_vector,Snap7_buf::NO_COMMUNICATION);
+	m_send_buf_map[0] = t_request;
+
+
+	t_index = 0;
+	t_variable_information_vector.clear();
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_heartbeat", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_check_flag", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved2_9", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 8 });
+	t_index += sizeof(unsigned char)*8;
+
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_year", typeid(unsigned short).name(), t_index,sizeof(unsigned short), 1 });
+	t_index += sizeof(unsigned short)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_month", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_day", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_weekday", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_hour", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_minute", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_second", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_nanosecond", typeid(unsigned int).name(), t_index,sizeof(unsigned int), 1 });
+	t_index += sizeof(unsigned int)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved22_29", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 8 });
+	t_index += sizeof(unsigned char)*8;
+
+	Snap7_buf t_dispatch_status(STATUS_FROM_DISPATCH_TO_PLC_DBNUMBER, 0, sizeof(Status_from_dispatch_to_plc), t_variable_information_vector,Snap7_buf::NO_COMMUNICATION);
+	m_send_buf_map[1] = t_dispatch_status;
+
+
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_elevator_information", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved31", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_elevator_coordinates", typeid(double).name(), t_index,sizeof(double), 1 });
+	t_index += sizeof(double)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved40_73", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 34 });
+	t_index += sizeof(unsigned char)*34;
+
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_carrier_information", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved75", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 1 });
+	t_index += sizeof(unsigned char)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_carrier_coordinates", typeid(double).name(), t_index,sizeof(double), 1 });
+	t_index += sizeof(double)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_carrier_angle", typeid(double).name(), t_index,sizeof(double), 1 });
+	t_index += sizeof(double)*1;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_reserved92_125", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 34 });
+	t_index += sizeof(unsigned char)*34;
+
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_carrier_error_code", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 50 });
+	t_index += sizeof(unsigned char)*50;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_carrier_error_string", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 512 });
+	t_index += sizeof(unsigned char)*512;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_elevator_error_code", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 50 });
+	t_index += sizeof(unsigned char)*50;
+	t_variable_information_vector.push_back(Snap7_buf::Variable_information{"m_elevator_error_string", typeid(unsigned char).name(), t_index,sizeof(unsigned char), 512 });
+	t_index += sizeof(unsigned char)*512;
+
+	Snap7_buf t_plc_status(STATUS_FROM_PLC_TO_DISPATCH_DBNUMBER, 0, sizeof(Status_from_plc_to_dispatch), t_variable_information_vector,Snap7_buf::LOOP_COMMUNICATION);
+	m_receive_buf_map[1] = t_plc_status;
+
+	return Snap7_communication_base::communication_init();
+}
+
+//反初始化 通信 模块。
+Error_manager Dispatch_communication::communication_uninit()
+{
+	return Snap7_communication_base::communication_uninit();
+}
+
+std::mutex * Dispatch_communication::get_data_lock()
+{
+	return &m_data_lock;
+}
+Dispatch_communication::Request_from_dispatch_to_plc * Dispatch_communication::get_request_from_dispatch_to_plc()
+{
+	return &m_request_from_dispatch_to_plc;
+}
+Dispatch_communication::Response_from_plc_to_dispatch * Dispatch_communication::get_response_from_plc_to_dispatch()
+{
+	return &m_response_from_plc_to_dispatch;
+}
+Dispatch_communication::Status_from_dispatch_to_plc * Dispatch_communication::get_status_from_dispatch_to_plc()
+{
+	return &m_status_from_dispatch_to_plc;
+}
+Dispatch_communication::Status_from_plc_to_dispatch * Dispatch_communication::get_status_from_plc_to_dispatch()
+{
+	return &m_status_from_plc_to_dispatch;
+}
+
+
+//更新数据
+Error_manager Dispatch_communication::updata_receive_buf()
+{
+	std::unique_lock<std::mutex> t_lock1(m_receive_buf_lock);
+	std::unique_lock<std::mutex> t_lock2(m_data_lock);
+
+	memcpy(&m_response_from_plc_to_dispatch, m_receive_buf_map[0].mp_buf_obverse, m_receive_buf_map[0].m_size);
+	memcpy(&m_status_from_plc_to_dispatch, m_receive_buf_map[1].mp_buf_obverse, m_receive_buf_map[1].m_size);
+
+//	std::cout << " huli test :::: " << " m_status_from_plc_to_dispatch.m_heartbeat = " << (int)m_status_from_plc_to_dispatch.m_heartbeat << std::endl;
+//	std::cout << " huli test :::: " << " m_response_from_plc_to_dispatch.m_command_key = " << m_response_from_plc_to_dispatch.m_command_key << std::endl;
+//	std::cout << " huli test :::: " << " m_status_from_plc_to_dispatch.m_elevator_coordinates = " << m_status_from_plc_to_dispatch.m_elevator_coordinates << std::endl;
+//	std::cout << " huli test :::: " << " m_status_from_plc_to_dispatch.m_carrier_coordinates = " << m_status_from_plc_to_dispatch.m_carrier_coordinates << std::endl;
+
+	return Error_code::SUCCESS;
+}
+Error_manager Dispatch_communication::updata_send_buf()
+{
+	std::unique_lock<std::mutex> t_lock1(m_send_buf_lock);
+	std::unique_lock<std::mutex> t_lock2(m_data_lock);
+
+//	memcpy(m_request_from_dispatch_to_plc.m_command_key, "from_dispatch_to_plc_123", 20);
+//	m_status_from_dispatch_to_plc.m_year = (unsigned short)20;
+//	m_status_from_dispatch_to_plc.m_day = 20;
+//	m_status_from_dispatch_to_plc.m_heartbeat = 20;
+
+	memcpy(m_send_buf_map[0].mp_buf_obverse, &m_request_from_dispatch_to_plc, m_send_buf_map[0].m_size);
+	m_send_buf_map[0].set_communication_mode(Snap7_buf::ONCE_COMMUNICATION);
+	memcpy(m_send_buf_map[1].mp_buf_obverse, &m_status_from_dispatch_to_plc, m_send_buf_map[1].m_size);
+	m_send_buf_map[1].set_communication_mode(Snap7_buf::ONCE_COMMUNICATION);
+
+	return Error_code::SUCCESS;
+}
+
+
+
+

+ 185 - 0
dispatch/dispatch_communication.h

@@ -0,0 +1,185 @@
+//
+// Created by huli on 2020/9/25.
+//
+
+#ifndef NNXX_TESTS_DISPATCH_COMMUNICATION_H
+#define NNXX_TESTS_DISPATCH_COMMUNICATION_H
+
+#include "../tool/singleton.h"
+#include "../snap7_communication/snap7_communication_base.h"
+
+class Dispatch_communication:public Singleton<Dispatch_communication>, public Snap7_communication_base
+{
+public:
+#pragma pack(push, 1)	//struct按照1个byte对齐
+	//调度模块给plc发送请求消息的DB编号
+	#define REQUEST_FROM_DISPATCH_TO_PLC_DBNUMBER		100
+	//调度模块给plc发送请求消息的指令结构体
+	struct Request_from_dispatch_to_plc
+	{
+	    unsigned char 			m_reserved0 = 0;				//预留
+	    unsigned char			m_command_flag = 0;				//指令标志位, 0bit==1:流程开始, 1bit==1:校验无误
+		unsigned char			m_task_status = 0;				//流程状态, 0=正常,1=可恢复型故障,2=不可恢复故障
+		unsigned char			m_reserved3_11[9] = {0};		//预留
+
+	    //指令信息
+		unsigned short 			m_block_id = 0;					//单位编号(区域编号), 1~3
+		unsigned short 			m_floor_id = 0;					//楼层编号, 1~14
+		unsigned short 			m_parkspace_id = 0;				//同层的车位索引, 一楼为1~4, 楼上为1~6
+		unsigned char			m_command_key[256] = {0};		//指令key(任务唯一码), 作为通信标志位
+		unsigned char			m_is_entrance_flag = 0;			//是否为入口, 1=入口,0=非入口, (如果是入口, 中跑车需要按照汽车的旋转角进行偏移)
+		unsigned char			m_reserved275_289[15] = {0};	//预留
+
+		//汽车定位信息
+		float  					m_center_x = 0;					//整车的中心点x值, 四轮的中心
+		float  					m_center_y = 0;					//整车的中心点y值, 四轮的中心
+		float  					m_car_angle = 0;				//整车的车身旋转角,
+		float  					m_car_length = 0;				//整车的长度, 用于规避碰撞
+		float  					m_car_width = 0;				//整车的宽度, 用于规避碰撞
+		float  					m_car_height = 0;				//整车的高度, 用于规避碰撞
+		float  					m_wheel_base = 0;				//整车的轮距, 前后轮的距离, 用于机器人或agv的抓车
+		float  					m_wheel_width = 0;				//整车的轮距, 左右轮的距离, 用于机器人或agv的抓车
+		unsigned char			m_voucher_number[256] = {0};	//停取凭证号
+		unsigned char			m_plate_number[512] = {0};		//车牌号
+		unsigned char			m_phone_number[256] = {0};		//电话号码
+		unsigned char			m_reserved1346_1377[32] = {0};	//预留
+	};
+
+	//plc给调度模块发送答复消息的DB编号
+	#define RESPONSE_FROM_PLC_TO_DISPATCH_DBNUMBER		101
+	//plc给调度模块发送答复消息的指令结构体
+	struct Response_from_plc_to_dispatch
+	{
+		unsigned char			m_reserved0 = 0;				//预留
+		unsigned char			m_command_flag = 0;				//指令标志位, 0bit==1:流程结束
+		unsigned char			m_task_status = 0;				//流程状态, 0=正常,1=可恢复型故障,2=不可恢复故障
+		unsigned char			m_reserved3_11[9] = {0};		//预留
+
+		//指令信息
+		unsigned short 			m_block_id = 0;					//单位编号(区域编号), 1~3
+		unsigned short 			m_floor_id = 0;					//楼层编号, 1~14
+		unsigned short 			m_parkspace_id = 0;				//同层的车位索引, 一楼为1~4, 楼上为1~6
+		unsigned char			m_command_key[256] = {0};		//指令key(任务唯一码), 作为通信标志位
+		unsigned char			m_is_entrance_flag = 0;			//是否为入口, 1=入口,0=非入口, (如果是入口, 中跑车需要按照汽车的旋转角进行偏移)
+		unsigned char			m_reserved275_289[15] = {0};	//预留
+
+		//汽车定位信息
+		float  					m_center_x = 0;					//整车的中心点x值, 四轮的中心
+		float  					m_center_y = 0;					//整车的中心点y值, 四轮的中心
+		float  					m_car_angle = 0;				//整车的车身旋转角,
+		float  					m_car_length = 0;				//整车的长度, 用于规避碰撞
+		float  					m_car_width = 0;				//整车的宽度, 用于规避碰撞
+		float  					m_car_height = 0;				//整车的高度, 用于规避碰撞
+		float  					m_wheel_base = 0;				//整车的轮距, 前后轮的距离, 用于机器人或agv的抓车
+		float  					m_wheel_width = 0;				//整车的轮距, 左右轮的距离, 用于机器人或agv的抓车
+		unsigned char			m_voucher_number[256] = {0};	//停取凭证号
+		unsigned char			m_plate_number[512] = {0};		//车牌号
+		unsigned char			m_phone_number[256] = {0};		//电话号码
+		unsigned char			m_reserved1346_1377[32] = {0};	//预留
+	};
+
+	//调度模块给plc发送状态消息的DB编号
+	#define STATUS_FROM_DISPATCH_TO_PLC_DBNUMBER		110
+	//调度模块给plc发送状态消息的指令结构体
+	struct Status_from_dispatch_to_plc
+	{
+		unsigned char			m_heartbeat = 0;				//心跳位, 0-255循环
+		unsigned char			m_check_flag = 0;				//校验标志位
+		unsigned char			m_reserved2_9[8] = {0};			//预留
+
+		//时钟
+		unsigned short			m_year = 0;						//年
+		unsigned char			m_month = 0;					//月
+		unsigned char			m_day = 0;						//日
+		unsigned char			m_weekday = 0;					//周
+		unsigned char			m_hour = 0;						//时
+		unsigned char			m_minute = 0;					//分
+		unsigned char			m_second = 0;					//秒
+		unsigned int			m_nanosecond = 0;				//纳秒
+		unsigned char			m_reserved22_29[8] = {0};		//预留
+
+	};
+
+	//plc给调度模块发送状态消息的DB编号
+	#define STATUS_FROM_PLC_TO_DISPATCH_DBNUMBER		111
+	//plc给调度模块发送状态消息的指令结构体
+	struct Status_from_plc_to_dispatch
+	{
+		unsigned char			m_heartbeat = 0;				//心跳位, 0-255循环
+		unsigned char			m_check_flag = 0;				//校验标志位
+		unsigned char			m_reserved2_9[8] = {0};			//预留
+
+		//时钟
+		unsigned short			m_year = 0;						//年
+		unsigned char			m_month = 0;					//月
+		unsigned char			m_day = 0;						//日
+		unsigned char			m_weekday = 0;					//周
+		unsigned char			m_hour = 0;						//时
+		unsigned char			m_minute = 0;					//分
+		unsigned char			m_second = 0;					//秒
+		unsigned int			m_nanosecond = 0;				//纳秒
+		unsigned char			m_reserved22_29[8] = {0};		//预留
+
+		//升降机状态, (楚天项目代指电梯)
+		//升降机信息, 0bit==1:急停正常, 1bit==1:处于安全位置, 2bit==1:静止状态, 3bit==1:可执行新指令, 4bit==1:存在故障,
+		unsigned char			m_elevator_information = 0;		//升降机信息,
+		unsigned char			m_reserved31 = 0;				//预留
+		double 					m_elevator_coordinates = 0;		//升降机坐标
+		unsigned char			m_reserved40_73[34] = {0};		//预留
+
+		//搬运器状态, (楚天项目代指中跑车)
+		//搬运器信息, 0bit==1:急停正常, 1bit==1:处于安全位置, 2bit==1:静止状态, 3bit==1:可执行新指令, 4bit==1:存在故障,
+		unsigned char			m_carrier_information = 0;		//搬运器信息,
+		unsigned char			m_reserved75 = 0;				//预留
+		double 					m_carrier_coordinates = 0;		//搬运器坐标
+		double 					m_carrier_angle = 0;			//搬运器角度
+		unsigned char			m_reserved92_125[34] = {0};		//预留
+
+		//故障信息
+		unsigned char			m_carrier_error_code[50] = {0};		//搬运器错误码
+		unsigned char			m_carrier_error_string[512] = {0};	//搬运器错误描述
+		unsigned char			m_elevator_error_code[50] = {0};	//升降机错误码
+		unsigned char			m_elevator_error_string[512] = {0};	//升降机错误描述
+	};
+#pragma pack(pop)		//取消对齐
+
+// 子类必须把父类设定为友元函数,这样父类才能使用子类的私有构造函数。
+   friend class Singleton<Dispatch_communication>;
+private:
+ // 父类的构造函数必须保护,子类的构造函数必须私有。
+   Dispatch_communication();
+public:
+    //必须关闭拷贝构造和赋值构造,只能通过 get_instance 函数来进行操作唯一的实例。
+    Dispatch_communication(const Dispatch_communication& other) = delete;
+    Dispatch_communication& operator =(const Dispatch_communication& other) = delete;
+    ~Dispatch_communication();
+public://API functions
+	//初始化 通信 模块。如下三选一
+	virtual Error_manager communication_init();
+	//反初始化 通信 模块。
+	virtual Error_manager communication_uninit();
+public://get or set member variable
+	std::mutex * get_data_lock();
+	Request_from_dispatch_to_plc * get_request_from_dispatch_to_plc();
+	Response_from_plc_to_dispatch * get_response_from_plc_to_dispatch();
+	Status_from_dispatch_to_plc * get_status_from_dispatch_to_plc();
+	Status_from_plc_to_dispatch * get_status_from_plc_to_dispatch();
+protected://member functions
+	//更新数据
+	virtual Error_manager updata_receive_buf();
+	virtual Error_manager updata_send_buf();
+
+protected://member variable
+
+	std::mutex									m_data_lock;						//数据锁
+	Request_from_dispatch_to_plc				m_request_from_dispatch_to_plc;		//调度模块给plc发送请求消息的指令结构体
+	Response_from_plc_to_dispatch				m_response_from_plc_to_dispatch;	//plc给调度模块发送答复消息的指令结构体
+	Status_from_dispatch_to_plc					m_status_from_dispatch_to_plc;		//调度模块给plc发送状态消息的指令结构体
+	Status_from_plc_to_dispatch					m_status_from_plc_to_dispatch;		//plc给调度模块发送状态消息的指令结构体
+
+private:
+
+};
+
+
+#endif //NNXX_TESTS_DISPATCH_COMMUNICATION_H

+ 113 - 0
dispatch/dispatch_manager.cpp

@@ -0,0 +1,113 @@
+//
+// Created by huli on 2020/7/20.
+//
+
+#include "dispatch_manager.h"
+#include <cstdlib>
+
+Dispatch_manager::Dispatch_manager()
+{
+	m_dispatch_manager_status = E_DISPATCH_MANAGER_UNKNOW;
+//	m_carrier_number = 0;
+}
+
+Dispatch_manager::~Dispatch_manager()
+{
+	dispatch_manager_uninit();
+}
+
+
+
+//调度管理 初始化
+Error_manager Dispatch_manager::dispatch_manager_init(int dispatch_id)
+{
+	m_dispatch_manager_status = E_DISPATCH_MANAGER_READY;
+	m_dispatch_id = dispatch_id;
+//	m_carrier_number = size;
+//
+//	for (int i = 0; i < size; ++i)
+//	{
+//		Carrier_base * p_arrier_base = new Carrier_base;
+//		p_arrier_base->carrier_base_init();
+//		m_carrier_vector.push_back(p_arrier_base);
+//	}
+	return Error_code::SUCCESS;
+}
+//调度管理 反初始化
+Error_manager Dispatch_manager::dispatch_manager_uninit()
+{
+//	//回收搬运器的内存
+//	for (int i = 0; i < m_carrier_number; ++i)
+//	{
+//		m_carrier_vector[i]->carrier_base_uninit();
+//		delete(m_carrier_vector[i]);
+//	}
+
+	m_dispatch_manager_status = E_DISPATCH_MANAGER_UNKNOW;
+
+//	m_carrier_number = 0;
+//	m_carrier_vector.clear();
+	return Error_code::SUCCESS;
+}
+
+//对外的接口函数,负责接受并处理任务单,
+Error_manager Dispatch_manager::execute_task(Dispatch_manager::Dispatch_motion_direction dispatch_motion_direction)
+{
+return Error_code::SUCCESS;
+//	std::this_thread::sleep_for(std::chrono::seconds(rand()%3+3));
+
+	if ( dispatch_motion_direction == E_PICKUP_CAR )
+	{
+		return Error_code::SUCCESS;
+	}
+
+//	return Error_code::SUCCESS;
+
+//	srand(0);
+	unsigned int t_probability = rand();
+
+	if ( t_probability%100 >=20 )
+	{
+	    return Error_code::SUCCESS;
+	}
+	else
+	{
+	    return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+	    					" Dispatch_manager::execute_task() error ");
+	}
+}
+
+//检查状态
+Error_manager Dispatch_manager::check_status()
+{
+	if ( m_dispatch_manager_status == E_DISPATCH_MANAGER_READY )
+	{
+		return Error_code::SUCCESS;
+	}
+	else if ( m_dispatch_manager_status == E_DISPATCH_MANAGER_STORE || m_dispatch_manager_status == E_DISPATCH_MANAGER_STORE )
+	{
+		return Error_manager(Error_code::DISPATCH_MANAGER_STATUS_BUSY, Error_level::NEGLIGIBLE_ERROR,
+							 " Dispatch_manager::check_status() error ");
+	}
+	else
+	{
+		return Error_manager(Error_code::DISPATCH_MANAGER_STATUS_ERROR, Error_level::MINOR_ERROR,
+							 " Dispatch_manager::check_status() error ");
+	}
+	return Error_code::SUCCESS;
+}
+
+Dispatch_manager::Dispatch_manager_status Dispatch_manager::get_dispatch_manager_status()
+{
+	return m_dispatch_manager_status;
+}
+
+int Dispatch_manager::get_dispatch_id()
+{
+	return m_dispatch_id;
+}
+void Dispatch_manager::set_dispatch_id(int dispatch_id)
+{
+	m_dispatch_id = dispatch_id;
+}
+

+ 99 - 0
dispatch/dispatch_manager.h

@@ -0,0 +1,99 @@
+//
+// Created by huli on 2020/7/20.
+//
+
+#ifndef NNXX_TESTS_DISPATCH_MANAGER_H
+#define NNXX_TESTS_DISPATCH_MANAGER_H
+
+
+#include "../error_code/error_code.h"
+#include "../tool/singleton.h"
+#include "../tool/thread_condition.h"
+
+#include "../dispatch/carrier_base.h"
+#include <vector>
+#include <glog/logging.h>
+
+
+
+//lacate测量结果结构体, 整车的信息,
+typedef struct Locate_information
+{
+	float locate_x;				//整车的中心点x值, 四轮的中心
+	float locate_y;				//整车的中心点y值, 四轮的中心
+	float locate_angle;			//整车的旋转角, 四轮的旋转角
+	float locate_length;		//整车的长度, 用于规避碰撞
+	float locate_width;			//整车的宽度, 用于规避碰撞
+	float locate_height;		//整车的高度, 用于规避碰撞
+	float locate_wheel_base;	//整车的轮距, 前后轮的距离, 用于机器人或agv的抓车
+	float locate_wheel_width;	//整车的轮距, 左右轮的距离, 用于机器人或agv的抓车
+	bool locate_correct;		//整车的校准标记位
+	//注:理论上, 车宽和左右轮距应该是一样的, 但是实际上车宽比左右轮距略大,
+
+}Locate_information;
+
+//调度管理模块
+class Dispatch_manager:public Singleton<Dispatch_manager>
+{
+// 子类必须把父类设定为友元函数,这样父类才能使用子类的私有构造函数。
+   friend class Singleton<Dispatch_manager>;
+
+public:
+	//调度管理 的状态
+	enum Dispatch_manager_status
+	{
+		E_DISPATCH_MANAGER_UNKNOW               = 0,    //未知
+		E_DISPATCH_MANAGER_READY                = 1,    //准备,待机
+		E_DISPATCH_MANAGER_STORE                = 2,    //正在存车
+		E_DISPATCH_MANAGER_PICKUP               = 3,    //正在取车
+
+		E_DISPATCH_MANAGER_FAULT               = 10,    //故障
+	};
+
+	//调度方向, 停车取车
+	enum Dispatch_motion_direction
+	{
+		E_STORE_CAR             =0,         //停车, 出入口 -> 停车位
+		E_PICKUP_CAR            =1,         //取车, 停车位 -> 出入口
+	};
+private:
+ // 父类的构造函数必须保护,子类的构造函数必须私有。
+   Dispatch_manager();
+public:
+    //必须关闭拷贝构造和赋值构造,只能通过 get_instance 函数来进行操作唯一的实例。
+    Dispatch_manager(const Dispatch_manager& other) = delete;
+    Dispatch_manager& operator =(const Dispatch_manager& other) = delete;
+    ~Dispatch_manager();
+public://API functions
+	//调度管理 初始化
+	Error_manager dispatch_manager_init(int dispatch_id);
+	//调度管理 反初始化
+	Error_manager dispatch_manager_uninit();
+
+	//对外的接口函数,负责接受并处理任务单,
+	Error_manager execute_task(Dispatch_manager::Dispatch_motion_direction dispatch_motion_direction);
+
+	//检查状态
+	Error_manager check_status();
+public://get or set member variable
+	Dispatch_manager_status get_dispatch_manager_status();
+	int get_dispatch_id();
+	void set_dispatch_id(int dispatch_id);
+protected://member variable
+
+	Dispatch_manager_status						m_dispatch_manager_status;			//调度管理 的状态
+
+	int 										m_dispatch_id;						//调度模块的id, (楚天项目就是单元号, 0~2)
+
+	int 										m_carrier_number;					//搬运器的数量, 默认3个
+	std::vector<Carrier_base*>					m_carrier_vector;					//搬运器的对象实例,内存由本类管理
+
+
+
+
+private:
+
+};
+
+
+#endif //NNXX_TESTS_DISPATCH_MANAGER_H

+ 536 - 0
error_code/dispatch.error_code.h

@@ -0,0 +1,536 @@
+
+//Error_code是错误码的底层通用模块,
+//功能:用作故障分析和处理。
+
+//用法:所有的功能接口函数return错误管理类,
+//然后上层判断分析错误码,并进行故障处理。
+
+
+
+#ifndef TEST_ERROR_ERROR_CODE_H
+#define TEST_ERROR_ERROR_CODE_H
+
+#include <string>
+#include <string.h>
+#include<iostream>
+
+//错误管理类转化为字符串 的前缀,固定长度为58
+//这个是由显示格式来确定的,如果要修改格式或者 Error_code长度超过8位,Error_level长度超过2位,折需要重新计算
+#define ERROR_NAMAGER_TO_STRING_FRONT_LENGTH   58
+
+//进程加锁的状态,
+enum Lock_status
+{
+    UNLOCK      = 0,
+    LOCK        = 1,
+};
+
+//设备使能状态,
+enum Able_status
+{
+    UNABLE      = 0,
+    ENABLE      = 1,
+};
+
+//数据是否为空
+enum Empty_status
+{
+    NON_EMPTY   = 0,
+    EMPTY       = 1,
+};
+
+
+//错误码的枚举,用来做故障分析
+enum Error_code
+{
+    //成功,没有错误,默认值0
+    SUCCESS                         = 0x00000000,
+
+
+    //基本错误码,
+    ERROR                           = 0x00000001,//错误
+    PARTIAL_SUCCESS                 = 0x00000002,//部分成功
+    WARNING                         = 0x00000003,//警告
+    FAILED                          = 0x00000004,//失败
+
+    NODATA                          = 0x00000010,//没有数据,传入参数容器内部没有数据时,
+	INVALID_MESSAGE					= 0x00000011, //无效的消息,
+	PARSE_FAILED					= 0x00000012,//解析失败
+
+    TASK_TIMEOVER					= 0x00000020,//任务超时
+	RESPONSE_TIMEOUT                = 0x00000021,//答复超时
+
+    POINTER_IS_NULL                 = 0x00000101,//空指针
+    PARAMETER_ERROR                 = 0x00000102,//参数错误,传入参数不符合规范时,
+    POINTER_MALLOC_FAIL             = 0x00000103,//手动分配内存失败
+
+    CLASS_BASE_FUNCTION_CANNOT_USE  = 0x00000201,//基类函数不允许使用,必须使用子类的
+
+	CONTAINER_IS_TERMINATE			= 0x00000301,//容器被终止
+
+
+
+
+//    错误码的规范,
+//    错误码是int型,32位,十六进制。
+//    例如0x12345678
+//    12表示功能模块,例如:laser雷达模块               	框架制定
+//    34表示文件名称,例如:laser_livox.cpp             框架制定
+//    56表示具体的类,例如:class laser_livox           个人制定
+//    78表示类的函数,例如:laser_livox::start();       个人制定
+//    注:错误码的制定从1开始,不要从0开始,
+//        0用作错误码的基数,用来位运算,来判断错误码的范围。
+
+//    laser扫描模块
+    LASER_ERROR_BASE                = 0x01000000,
+
+//    laser_base基类
+	LASER_BASE_ERROR_BASE			= 0x01010000,
+    LASER_TASK_PARAMETER_ERROR      = 0x01010001,   //雷达基类模块, 任务输入参数错误
+    LASER_CONNECT_FAILED,							//雷达基类模块, 连接失败
+	LASER_START_FAILED,								//雷达基类模块, 开始扫描失败
+	LASER_CHECK_FAILED,								//雷达基类模块, 检查失败
+	LASER_STATUS_BUSY,								//雷达基类模块, 状态正忙
+	LASER_STATUS_ERROR,								//雷达基类模块, 状态错误
+	LASER_TASK_OVER_TIME,							//雷达基类模块, 任务超时
+	LASER_QUEUE_ERROR,								//雷达基类模块, 数据缓存错误
+
+
+//    laser_livox.cpp的错误码
+    LIVOX_ERROR_BASE                = 0x01020000,
+    LIVOX_START_FAILE,								//livox模块,开始扫描失败
+	LIVOX_TASK_TYPE_ERROR,							//livox模块,任务类型错误
+	lIVOX_CANNOT_PUSH_DATA,							//livox模块,不能添加扫描的数据
+	lIVOX_CHECK_FAILED,								//livox模块,检查失败
+	lIVOX_STATUS_BUSY,								//livox模块,状态正忙
+	lIVOX_STATUS_ERROR,								//livox模块,状态错误
+
+	//laser_manager 雷达管理模块
+	LASER_MANAGER_ERROR_BASE						= 0x01030000,
+	LASER_MANAGER_READ_PROTOBUF_ERROR,				//雷达管理模块,读取参数错误
+	LASER_MANAGER_STATUS_BUSY,						//雷达管理模块,状态正忙
+	LASER_MANAGER_STATUS_ERROR,						//雷达管理模块,状态错误
+	LASER_MANAGER_TASK_TYPE_ERROR,					//雷达管理模块,任务类型错误
+	LASER_MANAGER_IS_NOT_READY,						//雷达管理模块,不在准备状态
+	LASER_MANAGER_TASK_OVER_TIME,					//雷达管理模块,任务超时
+	LASER_MANAGER_LASER_INDEX_ERRPR,				//雷达管理模块,雷达索引错误,编号错误。
+	LASER_MANAGER_LASER_INDEX_REPEAT,				//雷达管理模块,需要扫描的雷达索引重复,可忽略的错误,提示作用
+
+//livox_driver 雷达livox驱动模块
+	LIVOX_DRIVER_ERROR_BASE							= 0x01040000,
+	LIVOX_DRIVER_SN_REPEAT,							//livox驱动模块, 雷达广播码重复
+	LIVOX_DRIVER_SN_ERROR,							//livox驱动模块, 雷达广播码错误
+	LIVOX_SKD_INIT_FAILED,							//livox驱动模块, livox_sdk初始化失败
+	LIVOX_DRIVER_NOT_READY,							//livox驱动模块, livox没有准备好.
+
+
+
+
+     //PLC error code  ...
+    PLC_ERROR_BASE                  = 0x02010000,
+    PLC_UNKNOWN_ERROR,
+    PLC_EMPTY_TASK,
+    PLC_IP_PORT_ERROR,
+    PLC_SLAVE_ID_ERROR,
+    PLC_CONNECTION_FAILED,
+    PLC_READ_FAILED,
+    PLC_WRITE_FAILED,
+    PLC_NOT_ENOUGH_DATA_ERROR,
+
+
+
+    //locate 定位模块,
+	LOCATER_ERROR_BASE                				= 0x03000000,
+
+	//LASER_MANAGER 定位管理模块
+	LOCATER_MANAGER_ERROR_BASE                		= 0x03010000,
+	LOCATER_MANAGER_READ_PROTOBUF_ERROR,				//定位管理模块,读取参数错误
+	LOCATER_MANAGER_STATUS_BUSY,						//定位管理模块,状态正忙
+	LOCATER_MANAGER_STATUS_ERROR,						//定位管理模块,状态错误
+	LOCATER_MANAGER_TASK_TYPE_ERROR,					//定位管理模块,任务类型错误
+	LOCATER_MANAGER_IS_NOT_READY,						//定位管理模块,不在准备状态
+	LOCATER_MANAGER_CLOUD_MAP_ERROR,					//定位管理模块,任务输入点云map的error
+	LOCATER_MANAGER_TASK_OVER_TIME,						//定位管理模块,任务超时
+
+
+	//Locater.cpp error from 0x0301000-0x030100FF
+	LOCATER_TASK_INIT_CLOUD_EMPTY ,
+    LOCATER_TASK_ERROR,
+    LOCATER_TASK_INPUT_CLOUD_UNINIT,
+    LOCATER_INPUT_CLOUD_EMPTY,
+    LOCATER_YOLO_UNINIT,
+    LOCATER_POINTSIFT_UNINIT,
+    LOCATER_3DCNN_UNINIT,
+    LOCATER_INPUT_YOLO_CLOUD_EMPTY,
+    LOCATER_Y_OUT_RANGE_BY_PLC,
+    LOCATER_MEASURE_HEIGHT_CLOUD_UNINIT,
+    LOCATER_MEASURE_HEIGHT_CLOUD_EMPTY,
+    LOCATER_INPUT_CLOUD_UNINIT,
+
+
+    //point sift from 0x03010100-0x030101FF
+    LOCATER_SIFT_INIT_FAILED=0x03010100,
+    LOCATER_SIFT_INPUT_CLOUD_UNINIT,
+	LOCATER_SIFT_INPUT_CLOUD_EMPTY,
+	LOCATER_SIFT_GRID_ERROR,
+	LOCATER_SIFT_SELECT_ERROR,
+	LOCATER_SIFT_CLOUD_VERY_LITTLE,
+	LOCATER_SIFT_CREATE_INPUT_DATA_FAILED,
+	LOCATER_SIFT_PREDICT_FAILED,
+	LOCATER_SIFT_PREDICT_TIMEOUT,
+	LOCATER_SIFT_PREDICT_NO_WHEEL_POINT,
+	LOCATER_SIFT_PREDICT_NO_CAR_POINT,
+
+    LOCATER_SIFT_FILTE_OBS_FAILED,
+    LOCATER_SIFT_INPUT_BOX_PARAMETER_FAILED,
+
+//    //yolo from 0x03010200-0x030102FF
+//        LOCATER_YOLO_DETECT_FAILED=0x03010200,
+//    LOCATER_YOLO_DETECT_NO_TARGET,
+//    LOCATER_YOLO_PARAMETER_INVALID,
+//    LOCATER_YOLO_INPUT_CLOUD_UNINIT,
+
+    //3dcnn from 0x03010300-0x030103FF
+    LOCATER_3DCNN_INIT_FAILED=0x03010300,
+    LOCATER_3DCNN_INPUT_CLOUD_UNINIT,
+	LOCATER_3DCNN_INPUT_CLOUD_EMPTY,
+	LOCATER_3DCNN_INPUT_CLOUD_MAP_ERROR,
+	LOCATER_3DCNN_PCA_OUT_ERROR,
+	LOCATER_3DCNN_EXTRACT_RECT_ERROR,
+	LOCATER_3DCNN_RECT_SIZE_ERROR,
+
+    LOCATER_3DCNN_PREDICT_FAILED,
+    LOCATER_3DCNN_VERIFY_RECT_FAILED_3,
+    LOCATER_3DCNN_VERIFY_RECT_FAILED_4,
+    LOCATER_3DCNN_KMEANS_FAILED,
+    LOCATER_3DCNN_IIU_FAILED,
+    LOCATER_3DCNN_PCA_OUT_CLOUD_EMPTY,
+
+    //System_manager error from 0x04010000-0x0401FFFF
+    SYSTEM_READ_PARAMETER_ERROR=0x04010100,
+    SYSTEM_PARAMETER_ERROR,
+    SYSTEM_INPUT_TERMINOR_NO_LASERS,
+
+    //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,
+
+
+
+    WANJI_LIDAR_DEVICE_ERROR_BASE=0x06080000,						//万集设备模块,错误基类
+	WANJI_LIDAR_DEVICE_STATUS_BUSY,									//万集设备模块,状态正忙
+	WANJI_LIDAR_DEVICE_STATUS_ERROR,								//万集设备模块,状态错误
+	WANJI_LIDAR_DEVICE_TASK_TYPE_ERROR,								//万集设备模块,任务类型错误
+	WANJI_LIDAR_DEVICE_TASK_OVER_TIME,								//万集设备模块,任务超时
+	WANJI_LIDAR_DEVICE_NO_CLOUD,									//万集设备模块,没有点云
+
+
+	//wj_lidar error from 0x06010000-0x0601FFFF
+	WJ_LIDAR_COMMUNICATION_ERROR_BASE=0x06010000,
+	WJ_LIDAR_COMMUNICATION_UNINITIALIZED,							//万集通信,未初始化
+	WJ_LIDAR_COMMUNICATION_DISCONNECT,								//万集通信,断连
+	WJ_LIDAR_COMMUNICATION_FAULT,									//万集通信,故障
+	WJ_LIDAR_CONNECT_FAILED,
+    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_STATUS_BUSY,										//万集解析, 状态正忙
+	WJ_PROTOCOL_STATUS_ERROR,										//系统执行模块, 状态错误
+    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_ERROR_BASE					= 0x06030000,
+	WJ_REGION_EMPTY_CLOUD,
+	WJ_REGION_EMPTY_NO_WHEEL_INFORMATION,
+    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_MANAGER_READ_PROTOBUF_ERROR,								//万集管理模块,读取参数错误
+	WJ_MANAGER_INIT_REPEAT,										//万集管理模块,重复初始化
+	WJ_MANAGER_TASK_TYPE_ERROR,									//万集管理模块,任务类型错误
+	WJ_MANAGER_STATUS_BUSY,										//万集管理模块,状态正忙
+	WJ_MANAGER_STATUS_ERROR,									//万集管理模块,状态错误
+	WJ_MANAGER_LASER_INDEX_ERRPR,								//万集管理模块,雷达索引错误,编号错误。
+	WJ_MANAGER_LASER_INDEX_REPEAT,								//万集管理模块,需要扫描的雷达索引重复,可忽略的错误,提示作用
+	WJ_MANAGER_TASK_OVER_TIME,									//万集管理模块,任务超时
+
+
+	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,
+
+
+
+    //task module, 任务模块  error from 0x10010000-0x1001FFFF
+	TASK_MODULE_ERROR_BASE 							= 0x10010000,
+	TASK_TYPE_IS_UNKNOW,
+	TASK_NO_RECEIVER,
+
+
+	//Communication module, 通信模块
+	COMMUNICATION_BASE_ERROR_BASE					= 0x11010000,
+	COMMUNICATION_READ_PROTOBUF_ERROR,				//模块,读取参数错误
+	COMMUNICATION_BIND_ERROR,
+	COMMUNICATION_CONNECT_ERROR,
+	COMMUNICATION_ANALYSIS_TIME_OUT,									//解析超时,
+	COMMUNICATION_EXCUTER_IS_BUSY,										//处理器正忙, 请稍等
+
+
+	//system module, 系统模块
+	SYSTEM_EXECUTOR_ERROR_BASE						= 0x12010000,		//系统执行模块,
+	SYSTEM_EXECUTOR_PARSE_ERROR,										//系统执行模块, 解析消息错误
+	SYSTEM_EXECUTOR_STATUS_BUSY,										//系统执行模块, 状态正忙
+	SYSTEM_EXECUTOR_STATUS_ERROR,										//系统执行模块, 状态错误
+	SYSTEM_EXECUTOR_CHECK_ERROR,										//系统执行模块, 检查错误
+
+	LOCATER_MSG_TABLE_NOT_EXIST ,
+    LOCATER_MSG_RESPONSE_TYPE_ERROR,
+    LOCATER_MSG_RESPONSE_INFO_ERROR,
+    LOCATER_MSG_REQUEST_INVALID,
+    LOCATER_MSG_RESPONSE_HAS_NO_REQUEST,
+
+	//Dispatch_manager 调度管理模块 错误码
+	DISPATCH_MANAGER_ERROR_BASE						= 0x13010000,
+	DISPATCH_MANAGER_READ_PROTOBUF_ERROR,				//调度管理模块,读取参数错误
+	DISPATCH_MANAGER_STATUS_BUSY,						//调度管理模块,状态正忙
+	DISPATCH_MANAGER_STATUS_ERROR,						//调度管理模块,状态错误
+	DISPATCH_MANAGER_TASK_TYPE_ERROR,					//调度管理模块,任务类型错误
+	DISPATCH_MANAGER_IS_NOT_READY,						//调度管理模块,不在准备状态
+
+	CARRIER_ERROR_BASE								= 0x13020000,
+	CARRIER_READ_PROTOBUF_ERROR,				//搬运器模块,读取参数错误
+	CARRIER_STATUS_BUSY,						//搬运器模块,状态正忙
+	CARRIER_STATUS_ERROR,						//搬运器模块,状态错误
+	CARRIER_STATUS_DISCONNECT,					//搬运器模块,状态断连
+	CARRIER_TASK_TYPE_ERROR,					//搬运器模块,任务类型错误
+	CARRIER_TASK_OVER_TIME,						//搬运器模块,任务超时
+	CARRIER_IS_NOT_READY,						//搬运器模块,不在准备状态
+	CARRIER_RESPONS_ERROR,						//搬运器模块,指令的执行失败
+	CARRIER_TASK_NOTHINGNESS,					//搬运器模块,任务不存在
+
+
+
+
+	//snap7 通信模块 错误码
+	SNAP7_ERROR_BASE								= 0x1401000,
+	SNAP7_READ_PROTOBUF_ERROR,							//snap7通信模块,读取参数错误
+	SNAP7_CONNECT_ERROR,								//snap7通信模块,连接错误
+	SNAP7_DISCONNECT_ERROR,								//snap7通信模块,断连错误
+	SNAP7_READ_ERROR,									//snap7通信模块,读取错误
+	SNAP7_WRITE_ERROR,									//snap7通信模块,写入错误
+	SNAP7_ANALYSIS_TIME_OUT,									//解析超时,
+	SNAP7_EXCUTER_IS_BUSY,										//处理器正忙, 请稍等
+};
+
+//错误等级,用来做故障处理
+enum Error_level
+{
+//    正常,没有错误,默认值0
+    NORMAL                = 0,
+
+
+//    轻微故障,可忽略的故障,NEGLIGIBLE_ERROR
+//    提示作用,不做任何处理,不影响代码的流程,
+//    用作一些不重要的事件,即使出错也不会影响到系统功能,
+//    例如:文件保存错误,等
+    NEGLIGIBLE_ERROR      = 1,
+
+
+//    一般故障,MINOR_ERROR
+//    用作底层功能函数的错误返回,表示该功能函数执行失败,
+//    返回给应用层之后,需要做故障分析和处理,
+//    例如:雷达数据传输失败,应用层就需要进行重新扫描,或者重连,或者重置参数等。
+    MINOR_ERROR           = 2,
+
+
+//    严重故障,MAJOR_ERROR
+//    用作应用层的任务事件的结果,表示该功能模块失败。
+//    通常是底层函数返回一般故障之后,应用层无法处理并解决故障,此时就要进行故障升级,
+//    从一般故障升级为严重故障,然后进行回退流程,回退已经执行的操作,最终回到故障待机状态。
+//    需要外部清除故障,并复位至正常待机状态,才能恢复功能的使用。
+//    例如:雷达扫描任务失败,且无法自动恢复。
+    MAJOR_ERROR           = 3,
+
+
+//    致命故障,CRITICAL_ERROR
+//    系统出现致命错误。导致系统无法正常运行,
+//    此时系统应该紧急停机,执行紧急流程,快速停机。
+//    此时不允许再执行任何函数和任务指令,防止系统故障更加严重。
+//    也不需要做任何错误处理了,快速执行紧急流程。
+//    例如:内存错误,进程挂死,关键设备失控,监控设备报警,等
+    CRITICAL_ERROR        = 4,
+};
+
+
+class Error_manager
+{
+public://外部接口函数
+    //构造函数
+    Error_manager();
+    //拷贝构造
+    Error_manager(const Error_manager & error_manager);
+    //赋值构造
+    Error_manager(Error_code error_code, Error_level error_level = NORMAL,
+                  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);
+    //析构函数
+    ~Error_manager();
+
+    //初始化
+    void error_manager_init();
+    //初始化
+    void error_manager_init(Error_code error_code, Error_level error_level = NORMAL,
+                            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,
+                             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);
+    //重置
+    void error_manager_reset(const Error_manager & error_manager);
+    //清除所有内容
+    void error_manager_clear_all();
+
+    //重载=
+    Error_manager& operator=(const Error_manager & error_manager);
+    //重载=,支持Error_manager和Error_code的直接转化,会清空错误等级和描述
+    Error_manager& operator=(Error_code error_code);
+    //重载==
+    bool operator==(const Error_manager & error_manager);
+    //重载==,支持Error_manager和Error_code的直接比较
+    bool operator==(Error_code error_code);
+    //重载!=
+    bool operator!=(const Error_manager & error_manager);
+    //重载!=,支持Error_manager和Error_code的直接比较
+    bool operator!=(Error_code error_code);
+	//重载<<,支持cout<<
+	friend std::ostream & operator<<(std::ostream &out, Error_manager &error_manager);
+
+
+    //获取错误码
+    Error_code get_error_code();
+    //获取错误等级
+    Error_level get_error_level();
+    //获取错误描述的指针,(浅拷贝)
+    char* get_error_description();
+
+	int get_description_length();
+
+    //复制错误描述,(深拷贝)
+    //output:p_error_description     错误描述的字符串指针,不可以为NULL,必须要有实际的内存
+    //output:description_length      错误描述的字符串长度,不可以为0,长度最好足够大,一般256即可。
+    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);
+
+    //设置错误码
+    void set_error_code(Error_code error_code);
+    //比较错误等级并升级,取高等级的结果
+    void set_error_level_up(Error_level error_level);
+    //比较错误等级并降级,取低等级的结果
+    void set_error_level_down(Error_level error_level);
+    //错误等级,设定到固定值
+    void set_error_level_location(Error_level error_level);
+    //设置错误描述
+    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(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(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);
+    //output:error_description_string     错误汇总的string
+    void translate_error_to_string(std::string & error_aggregate_string);
+    //错误码转字符串的简易版,可支持cout<<
+    //return     错误汇总的string
+    std::string to_string();
+
+
+
+protected:
+    Error_code              m_error_code;               //错误码
+    Error_level             m_error_level;              //错误等级
+    char*                   pm_error_description;       //错误描述
+    int                     m_description_length;       //错误描述的字符长度
+
+protected://内部功能函数
+public:
+    //释放错误描述的内存,
+    void free_description();
+
+    //重新分配错误描述的内存,并从外部拷贝新的(深拷贝)
+    //input:p_error_description     错误描述的字符串指针,可以为NULL,
+    //input:description_length      错误描述的字符串长度,如果为0,则从p_error_description里面获取有效的长度
+    void reallocate_memory_and_copy_string(const char* p_error_description, int description_length = 0);
+
+    //重新分配错误描述的内存,并从外部拷贝新的(深拷贝)
+    //input:error_aggregate_string     错误描述的string
+    void reallocate_memory_and_copy_string(std::string & error_aggregate_string);
+};
+
+
+
+
+#endif //TEST_ERROR_ERROR_CODE_H
+
+

+ 547 - 0
error_code/error_code.cpp

@@ -0,0 +1,547 @@
+
+//Error_code是错误码的底层通用模块,
+//功能:用作故障分析和处理。
+
+//用法:所有的功能接口函数return错误管理类,
+//然后上层判断分析错误码,并进行故障处理。
+
+
+
+#include "error_code.h"
+
+/////////////////////////////////////////////
+//构造函数
+Error_manager::Error_manager()
+{
+    m_error_code = SUCCESS;
+    m_error_level = NORMAL;
+    pm_error_description = 0;
+    m_description_length = 0;
+    return ;
+}
+//拷贝构造
+Error_manager::Error_manager(const Error_manager & error_manager)
+{
+    this->m_error_code = error_manager.m_error_code;
+    this->m_error_level = error_manager.m_error_level;
+    pm_error_description = NULL;
+    m_description_length = 0;
+    reallocate_memory_and_copy_string(error_manager.pm_error_description, error_manager.m_description_length);
+    return ;
+}
+//赋值构造
+Error_manager::Error_manager(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;
+    pm_error_description = NULL;
+    m_description_length = 0;
+    reallocate_memory_and_copy_string(p_error_description, description_length);
+    return ;
+}
+//赋值构造
+Error_manager::Error_manager(Error_code error_code, Error_level error_level , std::string & error_aggregate_string)
+{
+    m_error_code = error_code;
+    m_error_level = error_level;
+    pm_error_description = NULL;
+    m_description_length = 0;
+    reallocate_memory_and_copy_string(error_aggregate_string);
+    return ;
+}
+//析构函数
+Error_manager::~Error_manager()
+{
+    free_description();
+}
+
+//初始化
+void Error_manager::error_manager_init()
+{
+    error_manager_clear_all();
+    return;
+}
+//初始化
+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;
+    reallocate_memory_and_copy_string(p_error_description, description_length);
+    return ;
+}
+//初始化
+void Error_manager::error_manager_init(Error_code error_code, Error_level error_level , std::string & error_aggregate_string)
+{
+    m_error_code = error_code;
+    m_error_level = error_level;
+    reallocate_memory_and_copy_string(error_aggregate_string);
+    return ;
+}
+//重置
+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;
+    reallocate_memory_and_copy_string(p_error_description, description_length);
+    return ;
+}
+//重置
+void Error_manager::error_manager_reset(Error_code error_code, Error_level error_level , std::string & error_aggregate_string)
+{
+    m_error_code = error_code;
+    m_error_level = error_level;
+    reallocate_memory_and_copy_string(error_aggregate_string);
+    return ;
+}
+//重置
+void Error_manager::error_manager_reset(const Error_manager & error_manager)
+{
+    this->m_error_code = error_manager.m_error_code;
+    this->m_error_level = error_manager.m_error_level;
+    reallocate_memory_and_copy_string(error_manager.pm_error_description, error_manager.m_description_length);
+    return ;
+}
+//清除所有内容
+void Error_manager::error_manager_clear_all()
+{
+    m_error_code = SUCCESS;
+    m_error_level = NORMAL;
+    free_description();
+	return;
+}
+
+//重载=
+Error_manager& Error_manager::operator=(const Error_manager & error_manager)
+{
+    error_manager_reset(error_manager);
+	return *this;
+}
+//重载=,支持Error_manager和Error_code的直接转化,会清空错误等级和描述
+Error_manager& Error_manager::operator=(Error_code error_code)
+{
+    error_manager_clear_all();
+    set_error_code(error_code);
+	return *this;
+}
+//重载==
+bool Error_manager::operator==(const Error_manager & error_manager)
+{
+	return is_equal_error_manager(error_manager);
+}
+//重载==,支持Error_manager和Error_code的直接比较
+bool Error_manager::operator==(Error_code error_code)
+{
+    if(m_error_code == error_code)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+//重载!=
+bool Error_manager::operator!=(const Error_manager & error_manager)
+{
+	return (! is_equal_error_manager(error_manager));
+}
+//重载!=,支持Error_manager和Error_code的直接比较
+bool Error_manager::operator!=(Error_code error_code)
+{
+    if(m_error_code != error_code)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+//重载<<,支持cout<<
+std::ostream & operator<<(std::ostream &out, Error_manager &error_manager)
+{
+	out << error_manager.to_string();
+	return out;
+}
+
+//获取错误码
+Error_code Error_manager::get_error_code()
+{
+    return m_error_code;
+}
+//获取错误等级
+Error_level Error_manager::get_error_level()
+{
+    return m_error_level;
+}
+//获取错误描述的指针,(浅拷贝)
+char* Error_manager::get_error_description()
+{
+    return pm_error_description;
+}
+
+int Error_manager::get_description_length()
+{
+	return m_description_length;
+}
+
+//复制错误描述,(深拷贝)
+//output:p_error_description     错误描述的字符串指针,不可以为NULL,必须要有实际的内存
+//output:description_length      错误描述的字符串长度,不可以为0,长度最好足够大,一般256即可。
+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 = (char *)p_error_description;
+        char* pt_destination = pm_error_description;
+
+        int t_length_min = m_description_length;
+        if(m_description_length > description_length)
+        {
+            t_length_min = description_length;
+        }
+
+        for(int i=0;i<t_length_min; i++)
+        {
+            *pt_destination = *pt_source;
+            pt_destination++;
+            pt_source++;
+        }
+    }
+
+    return;
+}
+//复制错误描述,(深拷贝)
+//output:error_description_string     错误描述的string
+void Error_manager::copy_error_description(std::string & error_description_string)
+{
+    if( (!error_description_string.empty() ) && pm_error_description != NULL)
+    {
+        error_description_string = pm_error_description;
+    }
+    return;
+}
+
+//设置错误码
+void Error_manager::set_error_code(Error_code error_code)
+{
+    m_error_code = error_code;
+    return;
+}
+//比较错误等级并升级,取高等级的结果
+void Error_manager::set_error_level_up(Error_level error_level)
+{
+    if(m_error_level < error_level)
+    {
+        m_error_level = error_level;
+    }
+    return;
+}
+//比较错误等级并降级,取低等级的结果
+void Error_manager::set_error_level_down(Error_level error_level)
+{
+    if(m_error_level > error_level)
+    {
+        m_error_level = error_level;
+    }
+    return;
+}
+//错误等级,设定到固定值
+void Error_manager::set_error_level_location(Error_level error_level)
+{
+    m_error_level = error_level;
+    return;
+}
+//设置错误描述
+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 ;
+}
+//设置错误描述
+void Error_manager::set_error_description(std::string & error_description_string)
+{
+    reallocate_memory_and_copy_string(error_description_string);
+    return ;
+}
+
+//尾部追加错误描述
+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 = (char *)p_error_description;
+        int t_description_back_length = 0;
+
+        if(description_length == 0)
+        {
+            t_description_back_length = 0;
+            while (*pt_description_back != '\0')
+            {
+                t_description_back_length++;
+                pt_description_back++;
+            }
+            t_description_back_length++;
+            pt_description_back = (char *)p_error_description;
+        }
+        else
+        {
+            t_description_back_length = description_length;
+        }
+
+        int t_description_new_length = t_description_front_length + 5 + t_description_back_length - 1;
+        char* pt_description_new =  (char*) malloc(t_description_new_length );
+
+        sprintf(pt_description_new, "%s ### %s", pt_description_front, pt_description_back);
+        free_description();
+        pm_error_description = pt_description_new;
+        m_description_length = t_description_new_length;
+    }
+    return ;
+}
+//尾部追加错误描述
+void Error_manager::add_error_description(std::string & error_description_string)
+{
+    if( ! error_description_string.empty() )
+    {
+        std::string t_description_string = pm_error_description ;
+        t_description_string += (" ### "+ error_description_string);
+
+        reallocate_memory_and_copy_string(t_description_string);
+    }
+	return;
+}
+
+//比较错误是否相同,
+// 注:只比较错误码和等级
+bool Error_manager::is_equal_error_manager(const Error_manager & error_manager)
+{
+    if(this->m_error_code == error_manager.m_error_code
+       && this->m_error_level == error_manager.m_error_level)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+//比较并覆盖错误,讲低级错误转为字符串存放于描述中,
+//如果错误相同,则保留this的,将输入参数转入描述。
+void Error_manager::compare_and_cover_error(const Error_manager & error_manager)
+{
+    if(this->m_error_code == SUCCESS)
+    {
+        error_manager_reset(error_manager);
+    }
+    else if (error_manager.m_error_code == SUCCESS)
+    {
+		return;
+    }
+    else
+    {
+        Error_manager t_error_manager_new;
+        char* pt_string_inside = NULL;
+        int t_string_inside_length = 0;
+        if(this->m_error_level < 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(error_manager);
+            add_error_description(pt_string_inside,t_string_inside_length);
+        }
+        else
+        {
+            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 & )error_manager).translate_error_to_string(pt_string_inside, t_string_inside_length);
+
+            add_error_description(pt_string_inside,t_string_inside_length);
+        }
+    }
+	return;
+}
+//比较并覆盖错误,讲低级错误转为字符串存放于描述中,
+//如果错误相同,则保留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);
+		}
+	}
+	return;
+}
+
+//将所有的错误信息,格式化为字符串,用作日志打印。
+//output:p_error_description     错误汇总的字符串指针,不可以为NULL,必须要有实际的内存
+//output:description_length      错误汇总的字符串长度,不可以为0,长度最好足够大,一般256即可。
+void Error_manager::translate_error_to_string(char* p_error_aggregate, int aggregate_length )
+{
+    char t_string_array[ERROR_NAMAGER_TO_STRING_FRONT_LENGTH] = {0};
+    char* pt_index_front = t_string_array;
+    char* pt_index_back = pm_error_description;
+    char* pt_index = p_error_aggregate;
+
+    sprintf(t_string_array, "error_code:0x%08x, error_level:%02d, error_description:", m_error_code , m_error_level );
+
+    int t_length_min = m_description_length + ERROR_NAMAGER_TO_STRING_FRONT_LENGTH -1;
+    if(t_length_min > aggregate_length)
+    {
+        t_length_min = aggregate_length;
+    }
+
+    for(int i=0;i<t_length_min; i++)
+    {
+        if(i < ERROR_NAMAGER_TO_STRING_FRONT_LENGTH -1)
+        {
+            *pt_index = *pt_index_front;
+            pt_index++;
+            pt_index_front++;
+        }
+        else
+        {
+            *pt_index = *pt_index_back;
+            pt_index++;
+            pt_index_back++;
+        }
+    }
+	return;
+}
+//output:error_description_string     错误汇总的string
+void Error_manager::translate_error_to_string(std::string & error_aggregate_string)
+{
+    char t_string_array[ERROR_NAMAGER_TO_STRING_FRONT_LENGTH] = {0};
+    sprintf(t_string_array, "error_code:0x%08x, error_level:%02d, error_description:", m_error_code , m_error_level );
+
+    error_aggregate_string = t_string_array ;
+    if(pm_error_description != NULL)
+    {
+        error_aggregate_string += pm_error_description;
+    }
+    else
+    {
+        //error_aggregate_string += "NULL";
+    }
+	return;
+}
+//错误码转字符串的简易版,可支持cout<<
+//return     错误汇总的string
+std::string Error_manager::to_string()
+{
+    std::string t_string;
+    translate_error_to_string(t_string);
+    return t_string;
+}
+
+
+
+
+//释放错误描述的内存,
+void Error_manager::free_description()
+{
+    if(pm_error_description != NULL)
+    {
+        free (pm_error_description);
+        pm_error_description = NULL;
+    }
+    m_description_length = 0;
+	return;
+}
+
+//重新分配错误描述的内存,并从外部拷贝新的(深拷贝)
+//input:p_error_description     错误描述的字符串指针,可以为NULL,
+//input:description_length      错误描述的字符串长度,如果为0,则从p_error_description里面获取有效的长度
+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 = (char *)p_error_description;
+        char* pt_destination = NULL;
+
+        if(description_length == 0)
+        {
+            m_description_length = 0;
+            while (*pt_source != '\0')
+            {
+                m_description_length++;
+                pt_source++;
+            }
+            m_description_length++;
+            pt_source = (char *)p_error_description;
+        }
+        else
+        {
+            m_description_length = description_length;
+        }
+
+        pm_error_description =  (char*) malloc(m_description_length );
+        pt_destination = pm_error_description;
+
+        for(int i=0;i<m_description_length; i++)
+        {
+            *pt_destination = *pt_source;
+            pt_destination++;
+            pt_source++;
+        }
+    }
+
+    return;
+}
+
+
+//重新分配错误描述的内存,并从外部拷贝新的(深拷贝)
+//input:error_aggregate_string     错误描述的string
+void Error_manager::reallocate_memory_and_copy_string(std::string & error_aggregate_string)
+{
+    free_description();
+
+    if( ! error_aggregate_string.empty())
+    {
+        m_description_length = error_aggregate_string.length()+1;
+
+        pm_error_description =  (char*) malloc( m_description_length );
+
+        strcpy(pm_error_description ,   error_aggregate_string.c_str()  );
+    }
+	return;
+}
+
+
+
+
+

+ 542 - 0
error_code/error_code.h

@@ -0,0 +1,542 @@
+
+//Error_code是错误码的底层通用模块,
+//功能:用作故障分析和处理。
+
+//用法:所有的功能接口函数return错误管理类,
+//然后上层判断分析错误码,并进行故障处理。
+
+
+
+#ifndef TEST_ERROR_ERROR_CODE_H
+#define TEST_ERROR_ERROR_CODE_H
+
+#include <string>
+#include <string.h>
+#include<iostream>
+
+//错误管理类转化为字符串 的前缀,固定长度为58
+//这个是由显示格式来确定的,如果要修改格式或者 Error_code长度超过8位,Error_level长度超过2位,折需要重新计算
+#define ERROR_NAMAGER_TO_STRING_FRONT_LENGTH   58
+
+//进程加锁的状态,
+enum Lock_status
+{
+    UNLOCK      = 0,
+    LOCK        = 1,
+};
+
+//设备使能状态,
+enum Able_status
+{
+    UNABLE      = 0,
+    ENABLE      = 1,
+};
+
+//数据是否为空
+enum Empty_status
+{
+    NON_EMPTY   = 0,
+    EMPTY       = 1,
+};
+
+
+//错误码的枚举,用来做故障分析
+enum Error_code
+{
+    //成功,没有错误,默认值0
+    SUCCESS                         = 0x00000000,
+
+
+    //基本错误码,
+    ERROR                           = 0x00000001,//错误
+    PARTIAL_SUCCESS                 = 0x00000002,//部分成功
+    WARNING                         = 0x00000003,//警告
+    FAILED                          = 0x00000004,//失败
+
+    NODATA                          = 0x00000010,//没有数据,传入参数容器内部没有数据时,
+	INVALID_MESSAGE					= 0x00000011, //无效的消息,
+	PARSE_FAILED					= 0x00000012,//解析失败
+
+    TASK_TIMEOVER					= 0x00000020,//任务超时
+	RESPONSE_TIMEOUT                = 0x00000021,//答复超时
+
+    POINTER_IS_NULL                 = 0x00000101,//空指针
+    PARAMETER_ERROR                 = 0x00000102,//参数错误,传入参数不符合规范时,
+    POINTER_MALLOC_FAIL             = 0x00000103,//手动分配内存失败
+
+    CLASS_BASE_FUNCTION_CANNOT_USE  = 0x00000201,//基类函数不允许使用,必须使用子类的
+
+	CONTAINER_IS_TERMINATE			= 0x00000301,//容器被终止
+
+
+
+
+//    错误码的规范,
+//    错误码是int型,32位,十六进制。
+//    例如0x12345678
+//    12表示功能模块,例如:laser雷达模块               	框架制定
+//    34表示文件名称,例如:laser_livox.cpp             框架制定
+//    56表示具体的类,例如:class laser_livox           个人制定
+//    78表示类的函数,例如:laser_livox::start();       个人制定
+//    注:错误码的制定从1开始,不要从0开始,
+//        0用作错误码的基数,用来位运算,来判断错误码的范围。
+
+//    laser扫描模块
+    LASER_ERROR_BASE                = 0x01000000,
+
+//    laser_base基类
+	LASER_BASE_ERROR_BASE			= 0x01010000,
+    LASER_TASK_PARAMETER_ERROR      = 0x01010001,   //雷达基类模块, 任务输入参数错误
+    LASER_CONNECT_FAILED,							//雷达基类模块, 连接失败
+	LASER_START_FAILED,								//雷达基类模块, 开始扫描失败
+	LASER_CHECK_FAILED,								//雷达基类模块, 检查失败
+	LASER_STATUS_BUSY,								//雷达基类模块, 状态正忙
+	LASER_STATUS_ERROR,								//雷达基类模块, 状态错误
+	LASER_TASK_OVER_TIME,							//雷达基类模块, 任务超时
+	LASER_QUEUE_ERROR,								//雷达基类模块, 数据缓存错误
+
+//    laser_livox.cpp的错误码
+    LIVOX_ERROR_BASE                = 0x01020000,
+    LIVOX_START_FAILE,								//livox模块,开始扫描失败
+	LIVOX_TASK_TYPE_ERROR,							//livox模块,任务类型错误
+	lIVOX_CANNOT_PUSH_DATA,							//livox模块,不能添加扫描的数据
+	lIVOX_CHECK_FAILED,								//livox模块,检查失败
+	lIVOX_STATUS_BUSY,								//livox模块,状态正忙
+	lIVOX_STATUS_ERROR,								//livox模块,状态错误
+
+	//laser_manager 雷达管理模块
+	LASER_MANAGER_ERROR_BASE						= 0x01030000,
+	LASER_MANAGER_READ_PROTOBUF_ERROR,				//雷达管理模块,读取参数错误
+	LASER_MANAGER_STATUS_BUSY,						//雷达管理模块,状态正忙
+	LASER_MANAGER_STATUS_ERROR,						//雷达管理模块,状态错误
+	LASER_MANAGER_TASK_TYPE_ERROR,					//雷达管理模块,任务类型错误
+	LASER_MANAGER_IS_NOT_READY,						//雷达管理模块,不在准备状态
+	LASER_MANAGER_TASK_OVER_TIME,					//雷达管理模块,任务超时
+	LASER_MANAGER_LASER_INDEX_ERRPR,				//雷达管理模块,雷达索引错误,编号错误。
+	LASER_MANAGER_LASER_INDEX_REPEAT,				//雷达管理模块,需要扫描的雷达索引重复,可忽略的错误,提示作用
+
+//livox_driver 雷达livox驱动模块
+	LIVOX_DRIVER_ERROR_BASE							= 0x01040000,
+	LIVOX_DRIVER_SN_REPEAT,							//livox驱动模块, 雷达广播码重复
+	LIVOX_DRIVER_SN_ERROR,							//livox驱动模块, 雷达广播码错误
+	LIVOX_SKD_INIT_FAILED,							//livox驱动模块, livox_sdk初始化失败
+	LIVOX_DRIVER_NOT_READY,							//livox驱动模块, livox没有准备好.
+
+
+
+
+     //PLC error code  ...
+    PLC_ERROR_BASE                  				= 0x02010000,
+    PLC_UNKNOWN_ERROR,								//plc未知错误
+    PLC_EMPTY_TASK,									//plc任务为空
+    PLC_IP_PORT_ERROR,								//plc的ip端口错误
+    PLC_SLAVE_ID_ERROR,								//plc的身份id错误
+    PLC_CONNECTION_FAILED,							//PLC连接失败
+    PLC_READ_FAILED,								//plc读取失败
+    PLC_WRITE_FAILED,								//plc写入失败
+    PLC_NOT_ENOUGH_DATA_ERROR,						//PLC没有足够的数据错误
+
+
+
+    //locate 定位模块,
+	LOCATER_ERROR_BASE                				= 0x03000000,
+	//LASER_MANAGER 定位管理模块
+	LOCATER_MANAGER_ERROR_BASE                		= 0x03010000,
+	LOCATER_MANAGER_READ_PROTOBUF_ERROR,				//定位管理模块,读取参数错误
+	LOCATER_MANAGER_STATUS_BUSY,						//定位管理模块,状态正忙
+	LOCATER_MANAGER_STATUS_ERROR,						//定位管理模块,状态错误
+	LOCATER_MANAGER_TASK_TYPE_ERROR,					//定位管理模块,任务类型错误
+	LOCATER_MANAGER_IS_NOT_READY,						//定位管理模块,不在准备状态
+	LOCATER_MANAGER_CLOUD_MAP_ERROR,					//定位管理模块,任务输入点云map的error
+	LOCATER_MANAGER_TASK_OVER_TIME,						//定位管理模块,任务超时
+
+
+	//Locater.cpp error 
+	LOCATER_ALGORITHM_ERROR_BASE                	= 0x03020000,
+	LOCATER_TASK_INIT_CLOUD_EMPTY ,						//定位任务初始化点云为空
+    LOCATER_TASK_ERROR,									//定位任务错误
+    LOCATER_TASK_INPUT_CLOUD_UNINIT,					//定位任务输入点云为空
+    LOCATER_INPUT_CLOUD_EMPTY,							//定位输入点云为空
+    LOCATER_YOLO_UNINIT,								//定位yolo未初始化
+    LOCATER_POINTSIFT_UNINIT,							//定位POINTSIFT未初始化
+    LOCATER_3DCNN_UNINIT,								//定位3DCNN未初始化
+    LOCATER_INPUT_YOLO_CLOUD_EMPTY,						//定位输入yolo点云为空
+    LOCATER_Y_OUT_RANGE_BY_PLC,							//定位超出plc的限制范围
+    LOCATER_MEASURE_HEIGHT_CLOUD_UNINIT,				//定位测量高点云未初始化
+    LOCATER_MEASURE_HEIGHT_CLOUD_EMPTY,					//定位测量高点云为空
+    LOCATER_INPUT_CLOUD_UNINIT,							//定位输入点云未初始化
+
+
+    //point sift from 0x03010100-0x030101FF
+	LOCATER_SIFT_ERROR_BASE							=0x03020100,
+   	LOCATER_SIFT_INIT_FAILED,							//定位过滤模块,初始化失败
+    LOCATER_SIFT_INPUT_CLOUD_UNINIT,					//定位过滤模块,输入点云未初始化
+	LOCATER_SIFT_INPUT_CLOUD_EMPTY,						//定位过滤模块,输入点云为空
+	LOCATER_SIFT_GRID_ERROR,							//定位过滤模块,筛选网格错误
+	LOCATER_SIFT_SELECT_ERROR,							//定位过滤模块,筛选选择错误
+	LOCATER_SIFT_CLOUD_VERY_LITTLE,						//定位过滤模块,筛选点云很少
+	LOCATER_SIFT_CREATE_INPUT_DATA_FAILED,				//定位过滤模块,筛选创建输入数据失败
+	LOCATER_SIFT_PREDICT_FAILED,						//定位过滤模块,预测失败
+	LOCATER_SIFT_PREDICT_TIMEOUT,						//定位过滤模块,预测超时
+	LOCATER_SIFT_PREDICT_NO_WHEEL_POINT,				//定位过滤模块,预测结果没有车轮点云
+	LOCATER_SIFT_PREDICT_NO_CAR_POINT,					//定位过滤模块,预测结果没有车身点云
+
+    LOCATER_SIFT_FILTE_OBS_FAILED,						//定位过滤模块,过滤OBS失败
+    LOCATER_SIFT_INPUT_BOX_PARAMETER_FAILED,			//定位过滤模块,输入范围参数错误
+
+//    //yolo 
+//    LOCATER_YOLO_ERROR_BASE						=0x03020200,
+//    LOCATER_YOLO_DETECT_FAILED,
+//    LOCATER_YOLO_DETECT_NO_TARGET,
+//    LOCATER_YOLO_PARAMETER_INVALID,
+//    LOCATER_YOLO_INPUT_CLOUD_UNINIT,
+
+    //3dcnn from 0x03010300-0x030103FF
+    LOCATER_3DCNN_ERROR_BASE						=0x03020300,
+    LOCATER_3DCNN_INIT_FAILED,							//定位3DCNN模块,初始化失败
+    LOCATER_3DCNN_INPUT_CLOUD_UNINIT,					//定位3DCNN模块,输入点云未初始化
+	LOCATER_3DCNN_INPUT_CLOUD_EMPTY,					//定位3DCNN模块,输入点云为空
+	LOCATER_3DCNN_INPUT_CLOUD_MAP_ERROR,				//定位3DCNN模块,输入点云的map错误
+	LOCATER_3DCNN_PCA_OUT_ERROR,						//定位3DCNN模块,pca错误
+	LOCATER_3DCNN_EXTRACT_RECT_ERROR,					//定位3DCNN模块,提取矩形错误
+	LOCATER_3DCNN_RECT_SIZE_ERROR,						//定位3DCNN模块,矩形范围错误
+
+    LOCATER_3DCNN_PREDICT_FAILED,						//定位3DCNN模块,预测失败
+    LOCATER_3DCNN_VERIFY_RECT_FAILED_3,					//定位3DCNN模块,验证矩形失败3
+    LOCATER_3DCNN_VERIFY_RECT_FAILED_4,					//定位3DCNN模块,验证矩形失败4
+    LOCATER_3DCNN_KMEANS_FAILED,						//定位3DCNN模块,k均值失败
+    LOCATER_3DCNN_IIU_FAILED,							//定位3DCNN模块,IIU失败
+    LOCATER_3DCNN_PCA_OUT_CLOUD_EMPTY,					//定位3DCNN模块,pca输出点云为空
+
+    //System_manager error from 0x04010000-0x0401FFFF
+    SYSTEM_READ_PARAMETER_ERROR=0x04010100,
+    SYSTEM_PARAMETER_ERROR,
+    SYSTEM_INPUT_TERMINOR_NO_LASERS,
+
+    //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,
+
+
+
+    WANJI_LIDAR_DEVICE_ERROR_BASE=0x06080000,						//万集设备模块,错误基类
+	WANJI_LIDAR_DEVICE_STATUS_BUSY,									//万集设备模块,状态正忙
+	WANJI_LIDAR_DEVICE_STATUS_ERROR,								//万集设备模块,状态错误
+	WANJI_LIDAR_DEVICE_TASK_TYPE_ERROR,								//万集设备模块,任务类型错误
+	WANJI_LIDAR_DEVICE_TASK_OVER_TIME,								//万集设备模块,任务超时
+	WANJI_LIDAR_DEVICE_NO_CLOUD,									//万集设备模块,没有点云
+
+
+	//wj_lidar error from 0x06010000-0x0601FFFF
+	WJ_LIDAR_COMMUNICATION_ERROR_BASE=0x06010000,
+	WJ_LIDAR_COMMUNICATION_UNINITIALIZED,							//万集通信,未初始化
+	WJ_LIDAR_COMMUNICATION_DISCONNECT,								//万集通信,断连
+	WJ_LIDAR_COMMUNICATION_FAULT,									//万集通信,故障
+	WJ_LIDAR_CONNECT_FAILED,
+    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_STATUS_BUSY,										//万集解析, 状态正忙
+	WJ_PROTOCOL_STATUS_ERROR,										//系统执行模块, 状态错误
+    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_ERROR_BASE					= 0x06030000,
+	WJ_REGION_EMPTY_CLOUD,
+	WJ_REGION_EMPTY_NO_WHEEL_INFORMATION,
+    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_MANAGER_READ_PROTOBUF_ERROR,								//万集管理模块,读取参数错误
+	WJ_MANAGER_INIT_REPEAT,										//万集管理模块,重复初始化
+	WJ_MANAGER_TASK_TYPE_ERROR,									//万集管理模块,任务类型错误
+	WJ_MANAGER_STATUS_BUSY,										//万集管理模块,状态正忙
+	WJ_MANAGER_STATUS_ERROR,									//万集管理模块,状态错误
+	WJ_MANAGER_LASER_INDEX_ERRPR,								//万集管理模块,雷达索引错误,编号错误。
+	WJ_MANAGER_LASER_INDEX_REPEAT,								//万集管理模块,需要扫描的雷达索引重复,可忽略的错误,提示作用
+	WJ_MANAGER_TASK_OVER_TIME,									//万集管理模块,任务超时
+
+
+	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,
+
+
+
+    //task module, 任务模块  error from 0x10010000-0x1001FFFF
+	TASK_MODULE_ERROR_BASE 							= 0x10010000,
+	TASK_TYPE_IS_UNKNOW,
+	TASK_NO_RECEIVER,
+
+
+	//Communication module, 通信模块
+	COMMUNICATION_BASE_ERROR_BASE					= 0x11010000,
+	COMMUNICATION_READ_PROTOBUF_ERROR,				//模块,读取参数错误
+	COMMUNICATION_BIND_ERROR,
+	COMMUNICATION_CONNECT_ERROR,
+	COMMUNICATION_ANALYSIS_TIME_OUT,									//解析超时,
+	COMMUNICATION_EXCUTER_IS_BUSY,										//处理器正忙, 请稍等
+
+
+	//system module, 系统模块
+	SYSTEM_EXECUTOR_ERROR_BASE						= 0x12010000,		//系统执行模块,
+	SYSTEM_EXECUTOR_PARSE_ERROR,										//系统执行模块, 解析消息错误
+	SYSTEM_EXECUTOR_STATUS_BUSY,										//系统执行模块, 状态正忙
+	SYSTEM_EXECUTOR_STATUS_ERROR,										//系统执行模块, 状态错误
+	SYSTEM_EXECUTOR_CHECK_ERROR,										//系统执行模块, 检查错误
+
+	LOCATER_MSG_TABLE_NOT_EXIST ,
+    LOCATER_MSG_RESPONSE_TYPE_ERROR,
+    LOCATER_MSG_RESPONSE_INFO_ERROR,
+    LOCATER_MSG_REQUEST_INVALID,
+    LOCATER_MSG_RESPONSE_HAS_NO_REQUEST,
+
+
+	//Dispatch 调度 模块 错误码
+	DISPATCH_ERROR_BASE								= 0x13000000,
+
+	//Dispatch_manager 调度管理模块 错误码
+	DISPATCH_MANAGER_ERROR_BASE						= 0x13010000,
+	DISPATCH_MANAGER_READ_PROTOBUF_ERROR,				//调度管理模块,读取参数错误
+	DISPATCH_MANAGER_STATUS_BUSY,						//调度管理模块,状态正忙
+	DISPATCH_MANAGER_STATUS_ERROR,						//调度管理模块,状态错误
+	DISPATCH_MANAGER_TASK_TYPE_ERROR,					//调度管理模块,任务类型错误
+	DISPATCH_MANAGER_IS_NOT_READY,						//调度管理模块,不在准备状态
+
+	CARRIER_ERROR_BASE								= 0x13020000,
+	CARRIER_READ_PROTOBUF_ERROR,				//搬运器模块,读取参数错误
+	CARRIER_STATUS_BUSY,						//搬运器模块,状态正忙
+	CARRIER_STATUS_ERROR,						//搬运器模块,状态错误
+	CARRIER_STATUS_DISCONNECT,					//搬运器模块,状态断连
+	CARRIER_TASK_TYPE_ERROR,					//搬运器模块,任务类型错误
+	CARRIER_TASK_OVER_TIME,						//搬运器模块,任务超时
+	CARRIER_IS_NOT_READY,						//搬运器模块,不在准备状态
+	CARRIER_RESPONS_ERROR,						//搬运器模块,指令的执行失败
+	CARRIER_TASK_NOTHINGNESS,					//搬运器模块,任务不存在
+
+
+
+
+	//snap7 通信模块 错误码
+	SNAP7_ERROR_BASE								= 0x1401000,
+	SNAP7_READ_PROTOBUF_ERROR,							//snap7通信模块,读取参数错误
+	SNAP7_CONNECT_ERROR,								//snap7通信模块,连接错误
+	SNAP7_DISCONNECT_ERROR,								//snap7通信模块,断连错误
+	SNAP7_READ_ERROR,									//snap7通信模块,读取错误
+	SNAP7_WRITE_ERROR,									//snap7通信模块,写入错误
+	SNAP7_ANALYSIS_TIME_OUT,									//解析超时,
+	SNAP7_EXCUTER_IS_BUSY,										//处理器正忙, 请稍等
+};
+
+//错误等级,用来做故障处理
+enum Error_level
+{
+//    正常,没有错误,默认值0
+    NORMAL                = 0,
+
+
+//    轻微故障,可忽略的故障,NEGLIGIBLE_ERROR
+//    提示作用,不做任何处理,不影响代码的流程,
+//    用作一些不重要的事件,即使出错也不会影响到系统功能,
+//    例如:文件保存错误,等
+    NEGLIGIBLE_ERROR      = 1,
+
+
+//    一般故障,MINOR_ERROR
+//    用作底层功能函数的错误返回,表示该功能函数执行失败,
+//    返回给应用层之后,需要做故障分析和处理,
+//    例如:雷达数据传输失败,应用层就需要进行重新扫描,或者重连,或者重置参数等。
+    MINOR_ERROR           = 2,
+
+
+//    严重故障,MAJOR_ERROR
+//    用作应用层的任务事件的结果,表示该功能模块失败。
+//    通常是底层函数返回一般故障之后,应用层无法处理并解决故障,此时就要进行故障升级,
+//    从一般故障升级为严重故障,然后进行回退流程,回退已经执行的操作,最终回到故障待机状态。
+//    需要外部清除故障,并复位至正常待机状态,才能恢复功能的使用。
+//    例如:雷达扫描任务失败,且无法自动恢复。
+    MAJOR_ERROR           = 3,
+
+
+//    致命故障,CRITICAL_ERROR
+//    系统出现致命错误。导致系统无法正常运行,
+//    此时系统应该紧急停机,执行紧急流程,快速停机。
+//    此时不允许再执行任何函数和任务指令,防止系统故障更加严重。
+//    也不需要做任何错误处理了,快速执行紧急流程。
+//    例如:内存错误,进程挂死,关键设备失控,监控设备报警,等
+    CRITICAL_ERROR        = 4,
+};
+
+
+class Error_manager
+{
+public://外部接口函数
+    //构造函数
+    Error_manager();
+    //拷贝构造
+    Error_manager(const Error_manager & error_manager);
+    //赋值构造
+    Error_manager(Error_code error_code, Error_level error_level = NORMAL,
+                  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);
+    //析构函数
+    ~Error_manager();
+
+    //初始化
+    void error_manager_init();
+    //初始化
+    void error_manager_init(Error_code error_code, Error_level error_level = NORMAL,
+                            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,
+                             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);
+    //重置
+    void error_manager_reset(const Error_manager & error_manager);
+    //清除所有内容
+    void error_manager_clear_all();
+
+    //重载=
+    Error_manager& operator=(const Error_manager & error_manager);
+    //重载=,支持Error_manager和Error_code的直接转化,会清空错误等级和描述
+    Error_manager& operator=(Error_code error_code);
+    //重载==
+    bool operator==(const Error_manager & error_manager);
+    //重载==,支持Error_manager和Error_code的直接比较
+    bool operator==(Error_code error_code);
+    //重载!=
+    bool operator!=(const Error_manager & error_manager);
+    //重载!=,支持Error_manager和Error_code的直接比较
+    bool operator!=(Error_code error_code);
+	//重载<<,支持cout<<
+	friend std::ostream & operator<<(std::ostream &out, Error_manager &error_manager);
+
+
+    //获取错误码
+    Error_code get_error_code();
+    //获取错误等级
+    Error_level get_error_level();
+    //获取错误描述的指针,(浅拷贝)
+    char* get_error_description();
+
+	int get_description_length();
+
+    //复制错误描述,(深拷贝)
+    //output:p_error_description     错误描述的字符串指针,不可以为NULL,必须要有实际的内存
+    //output:description_length      错误描述的字符串长度,不可以为0,长度最好足够大,一般256即可。
+    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);
+
+    //设置错误码
+    void set_error_code(Error_code error_code);
+    //比较错误等级并升级,取高等级的结果
+    void set_error_level_up(Error_level error_level);
+    //比较错误等级并降级,取低等级的结果
+    void set_error_level_down(Error_level error_level);
+    //错误等级,设定到固定值
+    void set_error_level_location(Error_level error_level);
+    //设置错误描述
+    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(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(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);
+    //output:error_description_string     错误汇总的string
+    void translate_error_to_string(std::string & error_aggregate_string);
+    //错误码转字符串的简易版,可支持cout<<
+    //return     错误汇总的string
+    std::string to_string();
+
+
+
+protected:
+    Error_code              m_error_code;               //错误码
+    Error_level             m_error_level;              //错误等级
+    char*                   pm_error_description;       //错误描述
+    int                     m_description_length;       //错误描述的字符长度
+
+protected://内部功能函数
+public:
+    //释放错误描述的内存,
+    void free_description();
+
+    //重新分配错误描述的内存,并从外部拷贝新的(深拷贝)
+    //input:p_error_description     错误描述的字符串指针,可以为NULL,
+    //input:description_length      错误描述的字符串长度,如果为0,则从p_error_description里面获取有效的长度
+    void reallocate_memory_and_copy_string(const char* p_error_description, int description_length = 0);
+
+    //重新分配错误描述的内存,并从外部拷贝新的(深拷贝)
+    //input:error_aggregate_string     错误描述的string
+    void reallocate_memory_and_copy_string(std::string & error_aggregate_string);
+};
+
+
+
+
+#endif //TEST_ERROR_ERROR_CODE_H
+
+

+ 41 - 0
hulitest.sh

@@ -0,0 +1,41 @@
+#!/bin/bash
+ 
+
+{
+gnome-terminal -x bash -c "cd /home/huli/huli/Terminal_project/hl_dispatch/Terminal_process_CT_20200902/cmake-build-debug/&&./terminal 0; exec bash"
+}&
+ 
+{
+gnome-terminal -x bash -c "cd /home/huli/huli/Terminal_project/hl_dispatch/Terminal_process_CT_20200902/cmake-build-debug/&&./terminal 1; exec bash"
+}&
+
+{
+gnome-terminal -x bash -c "cd /home/huli/huli/Terminal_project/hl_dispatch/Terminal_process_CT_20200902/cmake-build-debug/&&./terminal 2; exec bash"
+}&
+
+
+
+
+{
+gnome-terminal -x bash -c "cd /home/huli/huli/Terminal_project/hl_measure/Terminal_process_CT20200820/cmake-build-debug/&&./terminal 0; exec bash"
+}&
+
+{
+gnome-terminal -x bash -c "cd /home/huli/huli/Terminal_project/hl_measure/Terminal_process_CT20200820/cmake-build-debug/&&./terminal 1; exec bash"
+}&
+
+{
+gnome-terminal -x bash -c "cd /home/huli/huli/Terminal_project/hl_measure/Terminal_process_CT20200820/cmake-build-debug/&&./terminal 2; exec bash"
+}&
+
+{
+gnome-terminal -x bash -c "cd /home/huli/huli/Terminal_project/hl_measure/Terminal_process_CT20200820/cmake-build-debug/&&./terminal 3; exec bash"
+}&
+
+{
+gnome-terminal -x bash -c "cd /home/huli/huli/Terminal_project/hl_measure/Terminal_process_CT20200820/cmake-build-debug/&&./terminal 4; exec bash"
+}&
+
+{
+gnome-terminal -x bash -c "cd /home/huli/huli/Terminal_project/hl_measure/Terminal_process_CT20200820/cmake-build-debug/&&./terminal 5; exec bash"
+}&

+ 152 - 0
main.cpp

@@ -0,0 +1,152 @@
+//
+// Created by zx on 2020/6/18.
+//
+
+#include <iostream>
+#include "./error_code/error_code.h"
+//#include "LogFiles.h"
+#include <glog/logging.h>
+
+#include "./communication/communication_socket_base.h"
+
+#include "./tool/thread_pool.h"
+#include "./system/system_communication.h"
+#include "./system/system_executor.h"
+
+#include "./dispatch/dispatch_manager.h"
+#include "./dispatch/dispatch_communication.h"
+
+#include <algorithm>    // std::for_each
+
+
+#define LIVOX_NUMBER	     2
+
+
+GOOGLE_GLOG_DLL_DECL void shut_down_logging(const char* data, int size)
+{
+	time_t tt;
+	time( &tt );
+	tt = tt + 8*3600;  // transform the time zone
+	tm* t= gmtime( &tt );
+	char buf[255]={0};
+	sprintf(buf,"./%d%02d%02d-%02d%02d%02d-dump.txt",
+			t->tm_year + 1900,
+			t->tm_mon + 1,
+			t->tm_mday,
+			t->tm_hour,
+			t->tm_min,
+			t->tm_sec);
+
+	FILE* tp_file=fopen(buf,"w");
+	fprintf(tp_file,data,strlen(data));
+	fclose(tp_file);
+
+}
+
+#include <chrono>
+using namespace std;
+
+void myfunction (int i) {  // function:
+	std::cout << ' ' << i;
+}
+
+
+int main(int argc,char* argv[])
+{
+
+
+
+	const char* logPath = "./";
+	google::InitGoogleLogging("LidarMeasurement");
+	google::SetStderrLogging(google::INFO);
+	google::SetLogDestination(0, logPath);
+	google::SetLogFilenameExtension("zxlog");
+	google::InstallFailureSignalHandler();
+	google::InstallFailureWriter(&shut_down_logging);
+	FLAGS_colorlogtostderr = true;        // Set log color
+	FLAGS_logbufsecs = 0;                // Set log output speed(s)
+	FLAGS_max_log_size = 1024;            // Set max log file size(GB)
+	FLAGS_stop_logging_if_full_disk = true;
+
+	
+	Error_manager t_error;
+
+	std::cout << " huli test :::: " << " sizeof(Dispatch_communication::Request_from_dispatch_to_plc) = " << sizeof(Dispatch_communication::Request_from_dispatch_to_plc) << std::endl;
+	std::cout << " huli test :::: " << " sizeof(Dispatch_communication::Response_from_plc_to_dispatch) = " << sizeof(Dispatch_communication::Response_from_plc_to_dispatch) << std::endl;
+	std::cout << " huli test :::: " << " sizeof(Dispatch_communication::Status_from_dispatch_to_plc) = " << sizeof(Dispatch_communication::Status_from_dispatch_to_plc) << std::endl;
+	std::cout << " huli test :::: " << " sizeof(Dispatch_communication::Status_from_plc_to_dispatch) = " << sizeof(Dispatch_communication::Status_from_plc_to_dispatch) << std::endl;
+
+
+	t_error = Dispatch_communication::get_instance_references().communication_init();
+	std::cout << " huli test :::: " << " t_error = " << t_error << std::endl;
+	std::cout << "Dispatch_communication = " << Dispatch_communication::get_instance_references().get_status() << std::endl;
+
+	Carrier_base t_carrier_base;
+	t_carrier_base.carrier_base_init();
+
+	std::shared_ptr<Carrier_task> tp_carrier_task(new Carrier_task);
+	tp_carrier_task->task_init(NULL,std::chrono::milliseconds(15000),
+	1,2,3,"asd",
+	0,10,20,30);
+
+
+	std::cout << " huli test :::: " << " tp_carrier_task->get_task_statu = " << tp_carrier_task->get_task_statu() << std::endl;
+	std::cout << " huli test :::: " << " tp_carrier_task->m_respons_status = " << tp_carrier_task->m_respons_status << std::endl;
+
+	std::cout << " huli test :::: " << " tp_carrier_task->m_respons_status = " << t_carrier_base.get_carrier_status() << std::endl;
+
+
+	std::cout << " ---------------------------------------------------" << std::endl;
+
+	t_error = t_carrier_base.execute_one_level_task(tp_carrier_task);
+	std::cout << " huli test :::: " << " t_error = " << t_error << std::endl;
+
+	while ( 1 )
+	{
+		std::cout << " huli test :::: " << " tp_carrier_task->get_task_statu = " << tp_carrier_task->get_task_statu() << std::endl;
+		std::cout << " huli test :::: " << " tp_carrier_task->m_respons_status = " << tp_carrier_task->m_respons_status << std::endl;
+
+		std::cout << " huli test :::: " << " t_carrier_base.get_carrier_status() = " << t_carrier_base.get_carrier_status() << std::endl;
+
+
+		std::cout << " ---------------------------------------------------" << std::endl;
+		std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+	}
+
+	char ch123 ;
+	std::cin >> ch123 ;
+
+
+	Dispatch_communication::get_instance_references().communication_uninit();
+	return 0;
+
+
+
+
+	int t_dispatch_id = 0;
+//	std::cin >> t_dispatch_id ;
+	if ( argc == 2 )
+	{
+		std::cout << " huli test :::: " << " argv[1] = " << argv[1] << std::endl;
+		t_dispatch_id = atoi(argv[1]);
+	}
+	std::cout << " huli test :::: " << " t_dispatch_id = " << t_dispatch_id << std::endl;
+
+	Dispatch_manager::get_instance_references().dispatch_manager_init(t_dispatch_id);
+	std::cout << "Dispatch_manager = " << Dispatch_manager::get_instance_references().get_dispatch_manager_status() << std::endl;
+
+	System_executor::get_instance_references().system_executor_init(8);
+	std::cout << "System_executor = " << System_executor::get_instance_references().get_system_executor_status() << std::endl;
+	System_communication::get_instance_references().communication_init();
+
+	char ch ;
+	std::cin >> ch ;
+
+	System_communication::get_instance_references().communication_uninit();
+	System_executor::get_instance_references().system_executor_uninit();
+	Dispatch_manager::get_instance_references().dispatch_manager_uninit();
+
+
+	return 0;
+}

File diff suppressed because it is too large
+ 2817 - 0
message/dispatch_message.pb.cc


File diff suppressed because it is too large
+ 1974 - 0
message/dispatch_message.pb.h


+ 135 - 0
message/dispatch_message.proto

@@ -0,0 +1,135 @@
+syntax = "proto2";
+package message;
+import "message_base.proto";
+
+//调度管理 的状态
+enum Dispatch_manager_status
+{
+    E_DISPATCH_MANAGER_UNKNOW               = 0;    //未知
+    E_DISPATCH_MANAGER_READY                = 1;    //准备,待机
+    E_DISPATCH_MANAGER_STORE                = 2;    //正在存车
+    E_DISPATCH_MANAGER_PICKUP               = 3;    //正在取车
+
+    E_DISPATCH_MANAGER_FAULT               = 10;    //故障
+}
+
+//抓车器状态, 楚天项目就是AGV系统
+enum Catcher_status
+{
+    E_CATCHER_UNKNOW               = 0;     //未知
+    E_CATCHER_READY                = 1;     //准备,待机
+    E_CATCHER_STORE                = 2;	    //正在存车
+    E_CATCHER_PICKUP               = 3;	    //正在取车
+
+    E_CATCHER_FAULT                = 10;     //故障
+}
+
+//搬运器状态, 楚天项目就是中跑车
+enum Carrier_status
+{
+    E_CARRIER_UNKNOW               = 0;     //未知
+    E_CARRIER_READY                = 1;     //准备,待机
+    E_CARRIER_STORE                = 2;	    //正在存车
+    E_CARRIER_PICKUP               = 3;	    //正在取车
+
+    E_CARRIER_FAULT                = 10;     //故障
+}
+
+//升降机状态, 楚天项目就是电梯
+enum Elevator_status
+{
+    E_ELEVATOR_UNKNOW               = 0;     //未知
+    E_ELEVATOR_READY                = 1;     //准备,待机
+    E_ELEVATOR_STORE                = 2;	    //正在存车
+    E_ELEVATOR_PICKUP               = 3;	    //正在取车
+
+    E_ELEVATOR_FAULT                = 10;     //故障
+}
+
+//通道口状态, 楚天项目就是一楼的出入口
+enum Passageway_status
+{
+    E_PASSAGEWAY_UNKNOW               = 0;     //未知
+    E_PASSAGEWAY_READY                = 1;     //准备,待机
+    E_PASSAGEWAY_STORE                = 2;	    //正在存车
+    E_PASSAGEWAY_PICKUP               = 3;	    //正在取车
+
+    E_PASSAGEWAY_FAULT                = 10;     //故障
+}
+
+//终端流程状态, 表示这个出入口到楼上停车位之间的所有设备总状态
+enum Terminal_status
+{
+    E_TERMINAL_UNKNOW               = 0;     //未知
+    E_TERMINAL_READY                = 1;     //准备,待机
+    E_TERMINAL_STORE                = 2;	    //正在存车
+    E_TERMINAL_PICKUP               = 3;	    //正在取车
+
+    E_TERMINAL_FAULT                = 10;     //故障
+}
+
+//通道口属性, 出入口的方向属性, 表示这个通道允许停车或者取车
+enum Passageway_direction
+{
+    E_INLET             =0;         //入口
+    E_OUTLET            =1;         //出口
+    E_BILATERAL         =2;         //双向口
+}
+
+//设备坐标
+message Device_position
+{
+    required float x=1;             //X轴坐标
+    required float y=2;             //Y轴坐标
+    required float z=3;             //Z轴坐标, 楚天AGV和电梯一一对应,所以Z轴就用电梯高度表示
+}
+
+//调度方向, 停车取车, 表示正在执行的动作
+enum Dispatch_motion_direction
+{
+    E_STORE_CAR             =0;         //停车, 出入口 -> 停车位
+    E_PICKUP_CAR            =1;         //取车, 停车位 -> 出入口
+}
+
+//调度管理总管理的状态
+message Dispatch_manager_status_msg
+{
+    required Base_info                  base_info=1;                    //消息类型
+    required int32                      dispatch_id=2;                  //调度管理模块 id
+    required Dispatch_manager_status    dispatch_manager_status = 3;    //调度管理模块 状态
+
+    repeated Catcher_status             catcher_status = 4;             //抓车器状态, 楚天项目就是AGV系统
+    repeated Carrier_status             carrier_status = 5;             //搬运器状态, 楚天项目就是中跑车
+    repeated Elevator_status            elevator_status = 6;            //升降机状态, 楚天项目就是电梯
+    repeated Passageway_status          passageway_status = 7;          //通道口状态, 楚天项目就是一楼的出入口
+}
+
+//调度模块终端出入口的状态
+message Dispatch_terminal_status_msg
+{
+    required Base_info                  base_info=1;                    //消息类型
+    required int32                      terminal_id=2;                  //终端id
+    required Terminal_status            terminal_status = 3;            //终端流程状态, 表示这个出入口到楼上停车位之间的所有设备总状态
+    required Passageway_direction       passageway_direction = 4;       //通道口属性, 出入口的方向属性, 表示这个通道允许停车或者取车
+}
+
+
+//执行搬运请求
+message Dispatch_request_msg
+{
+    required Base_info                  base_info=1;                            //消息类型
+    required string                     command_key=2;                   //指令唯一标识符id
+
+    required Dispatch_motion_direction  dispatch_motion_direction=3;            //调度方向, 停车取车
+    required int32                      terminal_id=4;                          //终端id, 出入口
+    required Parkspace_info             parkspace_info=5;                         //车位编号, 停车位
+    optional Locate_information         locate_information=6;                   //汽车测量信息, 只有停车时有数据, 取车时没有数据.
+}
+
+//搬运动作执行完成后反馈结果
+message Dispatch_response_msg
+{
+    required Base_info                  base_info=1;                    //消息类型
+    required string                     command_key=2;                   //指令唯一标识符id
+    required Error_manager              error_manager = 3;
+}

File diff suppressed because it is too large
+ 3815 - 0
message/measure_message.pb.cc


File diff suppressed because it is too large
+ 2658 - 0
message/measure_message.pb.h


+ 144 - 0
message/measure_message.proto

@@ -0,0 +1,144 @@
+syntax = "proto2";
+package message;
+import "message_base.proto";
+
+//雷达管理模块的工作状态
+enum Laser_manager_status
+{
+    LASER_MANAGER_UNKNOW               	= 0;    //未知
+    LASER_MANAGER_READY               	= 1;    //准备,待机
+	LASER_MANAGER_ISSUED_TASK			= 2;	//工作下发任务
+	LASER_MANAGER_WAIT_REPLY			= 3;	//工作等待答复
+	LASER_MANAGER_FAULT					= 4;	//故障
+}
+	
+//子雷达状态
+enum Laser_statu
+{
+	LASER_DISCONNECT	=0;	        //雷达断连
+	LASER_READY			=1;			//雷达正常待机,空闲
+	LASER_BUSY			=2;	        //雷达正在工作,正忙
+	LASER_FAULT			=3;         //雷达错误
+}
+
+//定位管理模块的工作状态
+enum Locate_manager_status
+{
+	LOCATE_MANAGER_UNKNOW               	= 0;    //未知
+	LOCATE_MANAGER_READY               		= 1;    //准备,待机
+	LOCATE_MANAGER_SIFT						= 2;	//sift点云筛选; 将车身和轮胎的点剥离出来
+	LOCATE_MANAGER_CAR						= 3;	//通过车身 计算汽车的定位信息.
+	LOCATE_MANAGER_WHEEL					= 4;	//通过车轮 计算汽车的定位信息.
+	LOCATE_MANAGER_FAULT					= 5;	//故障
+}
+	
+
+//雷达管理的状态
+enum Wanji_manager_status
+{
+	WANJI_MANAGER_UNKNOWN              	= 0;    //未知
+	WANJI_MANAGER_READY               	= 1;    //准备,待机
+	WANJI_MANAGER_BUSY					= 2; 	//工作正忙
+
+	WANJI_MANAGER_ISSUED_SCAN			= 3; 	//下发任务; 获取点云
+	WANJI_MANAGER_WAIT_SCAN				= 4;	//等待任务; 扫描点云
+
+	WANJI_MANAGER_ISSUED_DETECT			= 5; 	//下发任务; 算法预测
+	WANJI_MANAGER_WAIT_DETECT			= 6; 	//等待任务; 算法预测
+
+	WANJI_MANAGER_FAULT					= 10;	//故障
+}
+
+//万集设备身状态
+enum Wanji_lidar_device_status
+{
+	WANJI_LIDAR_DEVICE_UNKNOWN              	= 0;    //未知
+	WANJI_LIDAR_DEVICE_READY	             	= 1;    //正常待机
+	WANJI_LIDAR_DEVICE_DISCONNECT			= 2;	//断连
+
+	WANJI_LIDAR_DEVICE_BUSY					= 3; 	//工作正忙
+
+	WANJI_LIDAR_DEVICE_FAULT					=10;	//故障
+}
+
+//万集区域功能的状态
+enum Region_worker_status
+{
+	REGION_WORKER_UNKNOWN              	= 0;    //未知
+	REGION_WORKER_READY               	= 1;    //准备,待机
+	REGION_WORKER_BUSY					= 2; 	//工作正忙
+
+	REGION_WORKER_FAULT					= 10;	//故障
+}
+
+//定位模块状态
+message Measure_status_msg
+{
+    required Base_info                  base_info=1;                 //消息类型
+    required int32                      terminal_id=2;
+
+    required Laser_manager_status       laser_manager_status = 3;       //大疆管理状态
+    repeated Laser_statu                laser_statu_vector = 4;         //大疆雷达设备状态
+    required Locate_manager_status      locate_manager_status = 5;      //大疆定位算法状态
+
+    required Wanji_manager_status       wanji_manager_status = 6;       //万集管理状态
+    repeated Wanji_lidar_device_status  wanji_lidar_device_status = 7;  //万集设备身状态
+    repeated Region_worker_status       region_worker_status = 8;       //万集区域功能的状态
+    repeated Locate_information         locate_information_realtime = 9;//地面雷达的 实时定位信息
+
+    required Error_manager              error_manager = 10;
+}
+
+
+//定位请求消息
+message Measure_request_msg
+{
+    required Base_info                  base_info=1;        //消息类型
+    required string                     command_key=2;                   //指令唯一标识符id
+    required int32                      terminal_id=3;          //终端id
+}
+
+//定位测量返回消息
+message Measure_response_msg
+{
+    required Base_info                  base_info=1;                         //消息类型
+    required string                     command_key=2;                   //指令唯一标识符id
+    required int32                      terminal_id=3;
+
+    optional Locate_information         locate_information=4;
+    required Error_manager              error_manager = 5;
+}
+
+//点云坐标
+message Cloud_coordinate
+{
+    required float                      x=1;
+    required float                      y=2;
+    required float                      z=3;
+}
+//点云类型
+message Cloud_type
+{
+    required int32                      type=1;
+}
+
+//筛选点云; 请求消息
+message Locate_sift_request_msg
+{
+    required Base_info                  base_info=1;            //消息类型
+    required string                     command_key=2;          //指令唯一标识符id
+    required int32                      terminal_id=3;          //终端id
+    required int32                      lidar_id=4;             //雷达id
+    repeated Cloud_coordinate           cloud_coordinates=5;     //点云坐标
+}
+
+//筛选点云; 答复消息
+message Locate_sift_response_msg
+{
+    required Base_info                  base_info=1;            //消息类型
+    required string                     command_key=2;          //指令唯一标识符id
+    required int32                      terminal_id=3;          //终端id
+    required int32                      lidar_id=4;             //雷达id
+    repeated Cloud_type                 cloud_type=5;            //点云类型
+    required Error_manager              error_manager = 6;      //错误码
+}

File diff suppressed because it is too large
+ 3306 - 0
message/message_base.pb.cc


File diff suppressed because it is too large
+ 2411 - 0
message/message_base.pb.h


+ 210 - 0
message/message_base.proto

@@ -0,0 +1,210 @@
+syntax = "proto2";
+package message;
+
+//消息类型定义;每个在网络上传输的消息必须含有这个属性
+enum Message_type
+{
+    eBase_msg=0x00;
+    eCommand_msg=0x01;                      //指令消息
+
+
+    eLocate_status_msg=0x11;                //定位模块状态消息
+    eLocate_request_msg=0x12;               //定位请求消息
+    eLocate_response_msg=0x13;              //定位反馈消息
+
+    eLocate_sift_request_msg = 0x14;            //预测算法请求消息
+    eLocate_sift_response_msg = 0x15;           //预测算法反馈消息
+
+    eDispatch_status_msg=0x21;                //调度模块硬件状态消息
+    eDispatch_request_msg=0x22;              //请求调度消息
+    eDispatch_response_msg=0x23;             //调度结果反馈消息
+
+    eParkspace_allocation_status_msg=0x31;  //车位分配模块状态消息,包括车位信息
+    eParkspace_allocation_request_msg=0x32; //请求分配车位消息
+    eParkspace_allocation_response_msg=0x33;//分配车位结果反馈消息
+    eParkspace_search_request_msg = 0x34;		//查询车位请求消息
+    eParkspace_search_response_msg = 0x35;		//查询车位反馈消息
+    eParkspace_release_request_msg = 0x36;		//释放车位请求消息
+    eParkspace_release_response_msg = 0x37;		//释放车位反馈消息
+    eParkspace_force_update_request_msg = 0x38;	//手动修改车位消息
+    eParkspace_force_update_response_msg = 0x39;//手动修改车位反馈消息
+    eParkspace_confirm_alloc_request_msg = 0x3A;//确认分配车位请求消息
+    eParkspace_confirm_alloc_response_msg = 0x3B;//确认分配车位反馈消息
+
+
+    eStore_command_request_msg=0x41;        //终端停车请求消息
+    eStore_command_response_msg=0x42;       //停车请求反馈消息
+    ePickup_command_request_msg=0x43;       //取车请求消息
+    ePickup_command_response_msg=0x44;       //取车请求反馈消息
+
+
+
+    eStoring_process_statu_msg=0x90;        //停车指令进度条消息
+    ePicking_process_statu_msg=0x91;        //取车指令进度消息
+
+
+    eCentral_controller_statu_msg=0xa0;     //中控系统状态消息
+
+
+    eEntrance_manual_operation_msg=0xb0;            //针对出入口状态操作的手动消息
+    eProcess_manual_operation_msg=0xb1;             //针对流程的手动消息
+
+
+}
+
+//通讯单元
+enum Communicator
+{
+    eEmpty=0x0000;
+    eMain=0x0001;    //主流程
+
+    eTerminor=0x0100;
+    //车位表
+    eParkspace=0x0200;
+    //测量单元
+    eMeasurer=0x0300;
+    //测量单元
+    eMeasurer_sift_server=0x0301;
+    //调度机构
+    eDispatch=0x0400;
+    //...
+
+
+}
+////base message 用于解析未知类型的消息
+message Base_info
+{
+    required Message_type               msg_type=1;
+    optional int32                      timeout_ms=2;
+    required Communicator               sender=3;                       //发送者
+    required Communicator               receiver=4;                     //接收者
+}
+
+// 事件,停车或者取车
+enum Process_type
+{
+    eStoring=1;
+    ePicking=2;
+}
+
+
+message Base_msg
+{
+    required Base_info                  base_info=1;
+}
+
+//错误等级,用来做故障处理
+enum Error_level
+{
+    NORMAL                = 0;      //    正常,没有错误,默认值0
+
+    NEGLIGIBLE_ERROR      = 1;      //    轻微故障;可忽略的故障,NEGLIGIBLE_ERROR
+
+    MINOR_ERROR           = 2;      //    一般故障,MINOR_ERROR
+
+    MAJOR_ERROR           = 3;      //    严重故障,MAJOR_ERROR
+
+    CRITICAL_ERROR        = 4;      //    致命故障,CRITICAL_ERROR
+
+}
+
+message Error_manager
+{
+    required int32                      error_code = 1;
+    optional Error_level                error_level = 2;
+    optional string                     error_description = 3;
+}
+
+//测量结果结构体
+message Locate_information
+{
+    optional float locate_x = 1;				//整车的中心点x值; 四轮的中心
+    optional float locate_y = 2;				//整车的中心点y值; 四轮的中心
+    optional float locate_angle = 3;			//整车的旋转角; 四轮的旋转角
+    optional float locate_length = 4;		    //整车的长度; 用于规避碰撞
+    optional float locate_width = 5;			//整车的宽度; 用于规避碰撞
+    optional float locate_height = 6;		    //整车的高度; 用于规避碰撞
+    optional float locate_wheel_base = 7;	    //整车的轮距; 前后轮的距离; 用于机器人或agv的抓车
+    optional float locate_wheel_width = 8;	    //整车的轮距; 左右轮的距离; 用于机器人或agv的抓车
+    optional bool locate_correct = 9;		    //整车的校准标记位
+
+    optional float locate_front_theta = 10;	    //整车的前轮的旋转角
+}
+
+//车辆基本信息
+message Car_info
+{
+    optional float                      car_length=1;           //车长
+    optional float                      car_width=2;            //车宽
+    optional float                      car_height=3;           //车高
+    optional string                     license=4;              //车辆凭证号
+}
+
+//车位状态枚举
+enum Parkspace_status
+{
+    eParkspace_empty            = 0;         //空闲,可分配
+    eParkspace_occupied         = 1;         //被占用,不可分配
+    eParkspace_reserverd        = 2;         //被预约,预约车辆可分配
+    eParkspace_error            = 3;         //车位机械结构或硬件故障
+}
+
+enum Direction
+{
+    eForward = 1;
+    eBackward = 2;
+}
+
+//单个车位基本信息与状态信息,车位信息以及车位上的车辆信息
+message Parkspace_info
+{
+    optional int32              parkspace_id=1;         //车位编号
+    optional int32              index=2;                //同层编号
+    optional Direction          direction=3;            //前后
+    optional int32              floor=4;                //楼层
+    optional float              length=5;               //车位长
+    optional float              width=6;                //车位宽
+    optional float              height=7;               //车位高
+    optional Parkspace_status   parkspace_status=8;     //车位当前状态
+    optional Car_info           car_info=9;              //当前车位存入车辆的凭证号
+    optional string             entry_time=10;          //入场时间
+    optional string             leave_time=11;          //离场时间
+    optional int32              block_id=12;            //区块编号
+}
+
+/*
+*流程中的步骤类型, 例如:停车流程包含5个步骤 , 分配车位-测量-检验结果-搬运-更新车位表
+*/
+enum Step_type
+{
+    eAlloc_step=0;
+    eMeasure_step=1;
+    eCompare_step=2;
+    eDispatch_step=3;
+    eConfirm_step=4;
+
+    eSearch_step=5;        //查询数据库
+    eWait_step=6;             //等待车辆离开
+    eRelease_step=7;          //释放车位
+
+    eComplete=8;              //完成
+
+    eBackConfirm_step=9;
+    eBack_compare_step=10;
+    eBackMeasure_step=11;
+    eBackAlloc_step=12;
+
+    eBackWait_step=13;
+    eBackDispatch_step=14;
+    eBackSearch_step=15;
+
+    eBackComplete=16;
+}
+//步骤状态,每个步骤有四中可能状态 ,等待中-执行中-完成或者错误  四个状态
+enum Step_statu
+{
+    eWaiting=0;               //完成/空闲
+    eWorking=1;
+    eError=2;
+    eFinished=3;
+}

+ 12 - 0
proto.sh

@@ -0,0 +1,12 @@
+protoc -I=./message message_base.proto --cpp_out=./message
+protoc -I=./message measure_message.proto --cpp_out=./message
+
+protoc -I=./communication communication.proto --cpp_out=./communication
+protoc -I=./message dispatch_message.proto --cpp_out=./message
+protoc -I=./snap7_communication snap7_communication.proto --cpp_out=./snap7_communication
+
+
+
+
+
+

+ 26 - 0
setting/communication.prototxt

@@ -0,0 +1,26 @@
+
+
+communication_parameters
+{
+
+#   bind_string:"tcp://192.168.2.166:9000"
+ #  connect_string_vector:"tcp://192.168.2.166:9001"
+ # connect_string_vector:"tcp://192.168.2.166:9002"
+
+  # connect_string_vector:"tcp://192.168.2.125:9876"
+  # connect_string_vector:"tcp://192.168.2.166:1234"
+
+  # bind_string:"tcp://192.168.2.166:4444"
+  #      bind_string:"tcp://192.168.3.106:5555"
+
+#    bind_string:"tcp://192.168.2.192:30002"
+
+
+
+ #  bind_string:"tcp://192.168.2.167:30002"
+  # connect_string_vector:"tcp://192.168.2.183:30003"
+ #  connect_string_vector:"tcp://192.168.2.183:30000"
+    connect_string_vector:"tcp://192.168.2.127:30000"
+
+}
+

+ 86 - 0
setting/laser.prototxt

@@ -0,0 +1,86 @@
+#1号雷达
+#  0TFDFG700601881  0TFDFCE00502001 0TFDH5L00684HE1  0TFDH5R006RCJ91
+
+
+
+
+laser_parameters
+{
+	type:"Livox"
+	sn:"0TFDFG700601881"
+	frame_num:1000
+    mat_r00:1
+    mat_r01:0
+    mat_r02:0
+    mat_r03:0
+    mat_r10:0
+    mat_r11:1
+    mat_r12:0
+    mat_r13:0
+    mat_r20:0
+    mat_r21:0
+    mat_r22:1
+    mat_r23:0
+}
+
+
+laser_parameters
+{
+	type:"Livox"
+	sn:"0TFDFCE00502001"
+	frame_num:1000
+    mat_r00:1
+    mat_r01:0
+    mat_r02:0
+    mat_r03:0
+    mat_r10:0
+    mat_r11:1
+    mat_r12:0
+    mat_r13:0
+    mat_r20:0
+    mat_r21:0
+    mat_r22:1
+    mat_r23:0
+}
+
+
+
+laser_parameters
+{
+	type:"Livox"
+	sn:"0TFDH5L00684HE1"
+	frame_num:1000
+    mat_r00:1
+    mat_r01:0
+    mat_r02:0
+    mat_r03:0
+    mat_r10:0
+    mat_r11:1
+    mat_r12:0
+    mat_r13:0
+    mat_r20:0
+    mat_r21:0
+    mat_r22:1
+    mat_r23:0
+}
+
+
+
+laser_parameters
+{
+	type:"Livox"
+	sn:"0TFDH5R006RCJ91"
+	frame_num:1000
+    mat_r00:1
+    mat_r01:0
+    mat_r02:0
+    mat_r03:0
+    mat_r10:0
+    mat_r11:1
+    mat_r12:0
+    mat_r13:0
+    mat_r20:0
+    mat_r21:0
+    mat_r22:1
+    mat_r23:0
+}

+ 54 - 0
setting/locate.prototxt

@@ -0,0 +1,54 @@
+area{
+ #   x_min:-1227.5
+ #   x_max:1802.9
+ #   y_min:-2789.8
+ #   y_max:3777.19
+  #  z_min:0
+  #  z_max:1800
+
+        x_min:-1000000
+        x_max:1000000
+        y_min:-1000000
+        y_max:1000000
+        z_min:-1000000
+        z_max:1000000
+}
+
+net_3dcnn_parameter
+{
+    length:0.224
+    width:0.224
+    height:0.096
+    freq:0.025
+    nclass:3
+    weights_file:"./setting/3dcnn_model.pb"
+}
+
+seg_parameter
+{
+    point_size:8192
+    cls_num:2
+    freq:0.020
+    area
+    {
+        x_min:-100000.0
+    	x_max:100000.0
+    	y_min:-100000.0
+    	y_max:100000.0
+    	z_min:-100000.0
+    	z_max:100000.0
+    }
+    graph:"../model_param/seg_model_404500.ckpt.meta"
+    cpkt:"../model_param/seg_model_404500.ckpt"
+}
+
+yolo_parameter
+{
+    cfg:"./setting/yolov3-spot2.cfg"
+    weights:"./setting/yolov3-spot2_12000.weights"
+    min_x:-1227.5
+    max_x:10802.9
+    min_y:-2789.8
+    max_y:3777.19
+    freq:25.
+}

+ 10 - 0
setting/snap7_communication.prototxt

@@ -0,0 +1,10 @@
+
+snap7_communication_parameters
+{
+  #  ip_string:"192.168.0.1"
+ #   ip_string:"192.168.2.134"
+
+ ip_string:"192.168.0.6"
+
+}
+

+ 182 - 0
snap7_communication/plc_data.cpp

@@ -0,0 +1,182 @@
+//
+// Created by zx on 2019/12/9.
+//
+
+#include "plc_data.h"
+#include <string.h>
+Plc_data *Plc_data::g_ins = 0;
+std::mutex Plc_data::g_lock;
+
+/**
+ * 获取单例句柄
+ * */
+Plc_data *Plc_data::get_instance(std::string ip)
+{
+    if (g_ins == 0)
+    {
+        std::lock_guard<std::mutex> lock(g_lock);
+        if (g_ins == 0)
+        {
+            if (ip != "")
+            {
+                g_ins = new Plc_data(ip);
+                LOG(INFO) << "plc data, handle created";
+            }
+            else
+            {
+                return 0;
+            }
+        }
+    }
+    return g_ins;
+}
+
+// void Plc_data::Release()
+// {
+//     if (g_ins)
+//     {
+//         g_ins->m_cond_exit.Notify(true);
+//         LOG(INFO) << "plc data, try to exit plc send thread";
+//         g_lock.lock();
+//         if (g_ins->p_send_thread)
+//         {
+//             LOG(INFO) << "plc data, try to join plc send thread";
+//             // LOG(INFO) << g_ins->p_send_thread->joinable();
+//             if (g_ins->p_send_thread->joinable())
+//                 g_ins->p_send_thread->join();
+//             LOG(INFO) << "plc data, try to delete plc send thread";
+//             delete g_ins->p_send_thread;
+//             g_ins->p_send_thread = 0;
+//             LOG(INFO) << "plc data, delete data send thread";
+//         }
+//         g_lock.unlock();
+
+//         LOG(INFO) << "plc data, start to exit plc handle";
+//         // if(g_instance->p_plc){
+//         //     LOG(INFO)<<"plc data, try to delete plc handle";
+//         //     delete g_instance->p_plc;
+//         //     g_instance->p_plc = 0;
+//         // }
+//         // LOG(INFO)<<"plc data, delete plc handle";
+//         LOG(INFO) << "plc data, delete instance";
+//         // delete g_ins;
+//         // g_ins = 0;
+//         LOG(INFO) << "plc data, instance deleted";
+//     }
+//     else
+//     {
+//         LOG(WARNING) << "plc data, cannot find the instance";
+//     }
+// }
+
+/**
+ * 更新区域状态
+ * */
+void Plc_data::update_data(int state_code, int border_status, int id)
+{
+//     LOG(INFO) << "plc data 更新数据 id: "<<id<<", code: "<<state_code;
+    if(id<0 || id>=MAX_REGIONS)
+        return ;
+    std::lock_guard<std::mutex> lock(g_lock);
+    m_data[2 * id] = state_code;
+    m_data[2 * id + 1] = border_status;
+}
+
+/**
+ * plc更新线程,将区域状态写入plc
+ * */
+void Plc_data::plc_update_thread(Plc_data *p)
+{
+    if (p == 0)
+    {
+        LOG(ERROR) << "plc update thread null pointer";
+        return;
+    }
+    while (!p->m_cond_exit.wait_for_millisecond(1))
+    {
+
+        // 判断plc状态
+        if (p->m_plc.getConnection() && p->mb_is_ready)
+        {
+
+
+            for (int i = 0; i < ELE_FENCE_COUNT; ++i)
+            {
+
+                g_lock.lock();
+                p->mb_is_ready = p->m_plc.WriteShorts(ELE_FENCE_DB_NUM,
+                                                      ELE_FENCE_BOUNDARY_START_ADDR + i * ELE_FENCE_OFFSET,
+                                                      2,
+                                                      p->m_data + (i * 2));
+                memcpy(p->m_last_data + (i * 2), p->m_data + (i * 2), 2 * sizeof(short));
+
+                g_lock.unlock();
+                usleep(10 * 1000);
+            }
+
+        }
+        else
+        {
+            // 重连plc
+            LOG(WARNING) << "find plc connection error, trying to reconnect.";
+            g_lock.lock();
+            p->m_plc.disconnect();
+            // LOG(WARNING) << "find plc connection error, diconnect first.";
+            if (p->m_ip_str != "")
+            {
+                p->mb_is_ready = p->m_plc.connect(p->m_ip_str);
+                // LOG(WARNING) << "find plc connection error, trying to connect";
+                if (p->mb_is_ready)
+                {
+                    LOG(INFO) << "successfully reconnect.";
+                }
+                else
+                {
+                    LOG(WARNING) << "failed to connect plc.";
+                }
+            }
+            g_lock.unlock();
+            usleep(p->m_update_interval_milli * 5 * 1000);
+        }
+        usleep(p->m_update_interval_milli * 1000);
+    }
+}
+
+/**
+ * 有参构造
+ * */
+Plc_data::Plc_data(std::string ip) : mp_update_thread(0),
+                                     m_ip_str(""),
+                                     mb_is_ready(0)
+{
+    m_ip_str = ip;
+    memset(m_data, 0, MAX_REGIONS*2 * sizeof(short));
+    memset(m_last_data, 0, MAX_REGIONS*2 * sizeof(short));
+    // p_plc = new S7PLC();
+    if (m_ip_str != "")
+    {
+        if (m_plc.connect(m_ip_str))
+        {
+            mb_is_ready = true;
+        }
+        else
+        {
+            LOG(ERROR) << "Plc_data instance, connect failed";
+        }
+    }
+    else
+    {
+        LOG(ERROR) << "Plc_data instance, empty ip string.";
+    }
+    m_cond_exit.notify_all(false);
+    mp_update_thread = new std::thread(plc_update_thread, this);
+    mp_update_thread->detach();
+}
+
+/**
+ * 获取plc连接状态
+ * */
+bool Plc_data::get_plc_status()
+{
+    return mb_is_ready;
+}

+ 75 - 0
snap7_communication/plc_data.h

@@ -0,0 +1,75 @@
+//
+// Created by zx on 2019/12/9.
+//
+
+#ifndef PLC_DATA_H
+#define PLC_DATA_H
+#include <iostream>
+#include <string>
+#include <mutex>
+#include <atomic>
+#include "../tool/thread_condition.h"
+#include <thread>
+#include "../snap7_communication/s7_plc.h"
+#include "unistd.h"
+//#include "define.h"
+#include "glog/logging.h"
+
+#define MAX_REGIONS 6
+#define ELE_FENCE_BOUNDARY_START_ADDR 3
+#define ELE_FENCE_DB_NUM 95
+#define ELE_FENCE_OFFSET 7
+#define ELE_FENCE_COUNT 6
+
+#define CENTRAL_CONTROLLER_DB_NUM 41
+#define DOOR_STATUS_OFFSET 18
+
+
+class Plc_data
+{
+public:
+    // 获取plc通信类单例
+    static Plc_data *get_instance(std::string ip = "");
+    // static void Release();
+    // 更新区域状态数据
+    void update_data(int state_code, int border_status, int id);
+    // plc更新线程
+    static void plc_update_thread(Plc_data *p);
+    // 获取plc实时状态
+    bool get_plc_status();
+
+public:
+    std::atomic<bool> mb_is_ready; // 状态正常与否
+
+private:
+    static Plc_data *g_ins;   // 全局Plc_data实例
+    static std::mutex g_lock; // 全局Plc_data实例访问互斥锁
+
+    Thread_condition m_cond_exit;                // 系统关闭标志
+    std::thread *mp_update_thread;           // plc更新线程
+    S7PLC m_plc;                             // S7协议句柄
+    const int m_update_interval_milli = 100; // plc更新频率
+
+    // 有参构造函数
+    Plc_data(std::string ip);
+
+    // class CGarbo
+    // {
+    // public:
+    // 	~CGarbo() {
+    // 		if (g_ins)
+    // 		{
+    // 			delete g_ins;
+    // 			g_ins = 0;
+    // 		}
+    // 	}
+    // };
+    // static CGarbo Garbo;	//--->1
+
+protected:
+    short m_data[MAX_REGIONS*2];
+    short m_last_data[MAX_REGIONS*2];
+    std::string m_ip_str;
+};
+
+#endif //PLC_DATA_H

+ 85 - 0
snap7_communication/s7_plc.cpp

@@ -0,0 +1,85 @@
+#include "s7_plc.h"
+
+S7PLC::S7PLC():bConnected_(false)
+{
+}
+S7PLC::~S7PLC()
+{
+    disconnect();
+}
+
+bool S7PLC::getConnection(){
+    return bConnected_;
+}
+
+bool S7PLC::connect(std::string ip)    
+{
+    std::lock_guard<std::mutex> lck (mutex_);
+    int ret=client_.ConnectTo(ip.c_str(),0,1);
+    bConnected_=(ret==0);
+    return bConnected_;
+}
+
+bool S7PLC::ReadShorts(int DBNumber,int start,int size,short* pdata)
+{
+    short* plc_data= (short*)malloc(size*sizeof(short));
+    bool ret=read_dbs(DBNumber,start*sizeof(short),size*sizeof(short),pdata);
+    if(ret)
+    {
+        reverse_byte(pdata,size*sizeof(short),plc_data);
+        for(int i=0;i<size;++i)
+            pdata[i]=plc_data[size-i-1];
+    }
+    free(plc_data);
+    return ret;
+
+}
+    bool S7PLC::WriteShorts(int DBNumber,int start,int size,short* pdata)
+    {
+        short* plc_data=(short*)malloc(size*sizeof(short));
+        memcpy(plc_data,pdata,size*sizeof(short));
+        for(int i=0;i<size;++i)
+            plc_data[i]=HTON(plc_data[i]);
+
+        bool ret=write_dbs(DBNumber,start*sizeof(short),size*sizeof(short),plc_data);
+        free(plc_data);
+        return ret;
+    }
+
+ bool S7PLC::read_dbs(int DBNumber,int start,int size,void* pdata)
+ {
+     std::lock_guard<std::mutex> lck (mutex_);
+     usleep(1000* 50);
+     if(bConnected_==false)
+        return false;
+     
+     int ret=client_.AsDBRead(DBNumber,start,size,pdata);
+
+     return ret == 0;
+ }
+ bool S7PLC::write_dbs(int DBNumber, int start, int size, void *pdata)
+ {
+    std::lock_guard<std::mutex> lck(mutex_);
+    usleep(1000*50);
+     if(bConnected_==false)
+        return false;
+     
+     int ret = client_.AsDBWrite(DBNumber, start, size, pdata);
+
+     return ret == 0;
+ }
+ void S7PLC::disconnect()
+ {
+     std::lock_guard<std::mutex> lck(mutex_);
+     client_.Disconnect();
+ }
+
+ void S7PLC::reverse_byte(void* pdata,int num_byte,void* out)
+ {
+     char* pin=(char*)pdata;
+     char* pout=(char*)out;
+     for(int i=0;i<num_byte;++i)
+     {
+         pout[i]=pin[num_byte-i-1];
+     }
+ }

+ 32 - 0
snap7_communication/s7_plc.h

@@ -0,0 +1,32 @@
+#ifndef S7__PLC__H
+#define S7__PLC__H
+
+#include <s7_client.h>
+#include <mutex>
+#include <iostream>
+
+class S7PLC
+{
+public:
+#define HTON(T) ((T) << 8) | ((T) >> 8)
+protected:
+    bool        bConnected_;
+    std::mutex  mutex_;
+    TSnap7Client client_;
+public:
+    S7PLC();
+    ~S7PLC();
+
+    bool connect(std::string ip);
+    bool getConnection();
+    bool ReadShorts(int DBNumber,int start,int size,short* pdata);
+    bool WriteShorts(int DBNumber,int start,int size,short* pdata);
+    void disconnect();
+private:
+    bool read_dbs(int DBNumber,int start,int size,void* pdata);
+    bool write_dbs(int DBNumber,int start,int size,void* pdata);
+    void reverse_byte(void* pdata,int num_byte,void* out);
+
+};
+
+#endif // !S7__PLC__H

+ 161 - 0
snap7_communication/snap7_buf.cpp

@@ -0,0 +1,161 @@
+
+
+
+#include "snap7_buf.h"
+#include <string>
+#include <string.h>
+
+Snap7_buf::Snap7_buf()
+{
+	m_id = 0;
+	m_start_index = 0;
+	m_size = 0;
+	mp_buf_obverse = nullptr;
+	mp_buf_reverse = nullptr;
+	m_communication_mode = NO_COMMUNICATION;
+
+}
+Snap7_buf::Snap7_buf(const Snap7_buf& other)
+{
+	m_id = other.m_id;
+	m_start_index = other.m_start_index;
+	m_communication_mode = other.m_communication_mode;
+
+	if ( other.m_size > 0 && other.mp_buf_obverse != nullptr && other.mp_buf_reverse != nullptr)
+	{
+		mp_buf_obverse = (void*)malloc(other.m_size);
+		memcpy(mp_buf_obverse, other.mp_buf_obverse, other.m_size);
+		mp_buf_reverse = (void*)malloc(other.m_size);
+		memcpy(mp_buf_reverse, other.mp_buf_reverse, other.m_size);
+		m_size = other.m_size;
+	}
+}
+Snap7_buf& Snap7_buf::operator =(const Snap7_buf& other)
+{
+	m_id = other.m_id;
+	m_start_index = other.m_start_index;
+	m_communication_mode = other.m_communication_mode;
+
+	if ( other.m_size > 0 && other.mp_buf_obverse != nullptr && other.mp_buf_reverse != nullptr)
+	{
+		mp_buf_obverse = (void*)malloc(other.m_size);
+		memcpy(mp_buf_obverse, other.mp_buf_obverse, other.m_size);
+		mp_buf_reverse = (void*)malloc(other.m_size);
+		memcpy(mp_buf_reverse, other.mp_buf_reverse, other.m_size);
+		m_size = other.m_size;
+	}
+}
+Snap7_buf::~Snap7_buf()
+{
+	if ( mp_buf_obverse )
+	{
+		free(mp_buf_obverse);
+		mp_buf_obverse = NULL;
+	}
+	if ( mp_buf_reverse )
+	{
+		free(mp_buf_reverse);
+		mp_buf_reverse = NULL;
+	}
+}
+
+Snap7_buf::Snap7_buf(int id, int start_index, int size,
+					 std::vector<Snap7_buf::Variable_information>& variable_information_vector,Communication_mode communication_mode)
+{
+	m_id = id;
+	m_start_index = start_index;
+	m_communication_mode = communication_mode;
+
+	if ( size > 0)
+	{
+		mp_buf_obverse = (void*)malloc(size);
+		memset(mp_buf_obverse, 0, size);
+		mp_buf_reverse = (void*)malloc(size);
+		memset(mp_buf_reverse, 0, size);
+		m_size = size;
+		m_variable_information_vector=variable_information_vector;
+	}
+}
+Snap7_buf::Snap7_buf(int id, int start_index, int size, void* p_buf_obverse, void* p_buf_reverse,
+					 std::vector<Snap7_buf::Variable_information>& variable_information_vector, Communication_mode communication_mode)
+{
+	m_id = id;
+	m_start_index = start_index;
+	m_communication_mode = communication_mode;
+
+	if ( size > 0 && p_buf_obverse != nullptr && p_buf_reverse != nullptr)
+	{
+		mp_buf_obverse = (void*)malloc(size);
+		memcpy(mp_buf_obverse, p_buf_obverse, size);
+		mp_buf_reverse = (void*)malloc(size);
+		memcpy(mp_buf_reverse, p_buf_reverse, size);
+		m_size = size;
+		m_variable_information_vector=variable_information_vector;
+	}
+}
+
+//正序数据 转为 倒序数据
+void Snap7_buf::obverse_to_reverse()
+{
+	char *p_in=(char*)mp_buf_obverse;
+	char *p_out=(char*)mp_buf_reverse;
+
+	for ( auto &iter:m_variable_information_vector)
+	{
+		for (int i = 0; i < iter.m_variable_count; ++i)
+		{
+			for (int j = iter.m_variable_index*i; j < iter.m_variable_index*i+iter.m_variable_size ; ++j)
+			{
+				p_out[j] = p_in[iter.m_variable_index*i+iter.m_variable_size - j -1];
+			}
+		}
+	}
+}
+
+//倒序数据 转为 正序数据
+void Snap7_buf::reverse_to_obverse()
+{
+	char *p_in=(char*)mp_buf_reverse;
+	char *p_out=(char*)mp_buf_obverse;
+
+	for ( auto &iter:m_variable_information_vector)
+	{
+		for (int i = 0; i < iter.m_variable_count; ++i)
+		{
+			for (int j = iter.m_variable_index*i; j < iter.m_variable_index*i+iter.m_variable_size ; ++j)
+			{
+				p_out[j] = p_in[iter.m_variable_index*i+iter.m_variable_size - j -1];
+			}
+		}
+	}
+}
+
+int Snap7_buf::get_id()
+{
+	return m_id;
+}
+int Snap7_buf::get_start_index()
+{
+	return m_start_index;
+}
+int Snap7_buf::get_size()
+{
+	return m_size;
+}
+void* Snap7_buf::get_buf_obverse()
+{
+	return mp_buf_obverse;
+}
+void* Snap7_buf::get_buf_reverse()
+{
+	return mp_buf_reverse;
+}
+
+Snap7_buf::Communication_mode Snap7_buf::get_communication_mode()
+{
+	return m_communication_mode;
+}
+void Snap7_buf::set_communication_mode(Communication_mode communication_mode)
+{
+	m_communication_mode = communication_mode;
+}

+ 79 - 0
snap7_communication/snap7_buf.h

@@ -0,0 +1,79 @@
+
+
+
+#ifndef NNXX_TESTS_SNAP7_BUF_H
+#define NNXX_TESTS_SNAP7_BUF_H
+
+#include <string>
+#include <map>
+#include <vector>
+#include <iostream>
+
+//Snap7协议的数据结构
+class Snap7_buf
+{
+public:
+	//通信模式
+	enum Communication_mode
+	{
+	    NO_COMMUNICATION               		= 0,    //不通信
+	    ONCE_COMMUNICATION               	= 1,    //一次通信
+	    LOOP_COMMUNICATION					= 2,	//循环通信
+	};
+
+	//变量信息
+	struct Variable_information
+	{
+	    std::string		m_variable_name;		//变量名称
+	    std::string		m_variable_type;		//变量类型, 使用 typeid(a).name() 获取
+	    int 			m_variable_index;		//变量下标, 偏移量
+	    int 			m_variable_size;		//变量类型大小
+		int				m_variable_count;		//变量个数
+	};
+public:
+	Snap7_buf();
+	Snap7_buf(const Snap7_buf& other);
+	Snap7_buf& operator =(const Snap7_buf& other);
+	~Snap7_buf();
+public://API functions
+	Snap7_buf(int id, int start_index, int size,
+			  std::vector<Snap7_buf::Variable_information>& variable_information_vector,Communication_mode communication_mode = NO_COMMUNICATION);
+	Snap7_buf(int id, int start_index, int size, void* p_buf_obverse, void* p_buf_reverse,
+			  std::vector<Snap7_buf::Variable_information>& variable_information_vector, Communication_mode communication_mode = NO_COMMUNICATION);
+
+	//正序数据 转为 倒序数据
+	void obverse_to_reverse();
+	//倒序数据 转为 正序数据
+	void reverse_to_obverse();
+public://get or set member variable
+	int get_id();
+	int get_start_index();
+	int get_size();
+	void* get_buf_obverse();
+	void* get_buf_reverse();
+	Communication_mode get_communication_mode();
+	void set_communication_mode(Communication_mode communication_mode);
+protected://member functions
+
+public://member variable
+
+	int 		m_id;					//Snap7协议的数据块的编号
+	int 		m_start_index;			//Snap7协议的数据起始位下标
+	int			m_size;					//Snap7协议的数据字节大小
+	void*		mp_buf_obverse;			//Snap7协议的正序数据指针, 和数据结构体进行强转, 内存由本类管理
+	void*		mp_buf_reverse;			//Snap7协议的倒序数据指针, 用作s7通信, 内存由本类管理
+	//注:s7的通信的数据必须要倒序之后才能进行通信,
+
+//	std::map<std::string, Variable_information>			m_variable_information_map;
+	std::vector<Variable_information>		m_variable_information_vector;
+
+	Communication_mode 		m_communication_mode;	//Snap7协议的通信模式
+	//注:s7协议传输很慢, 防止相同的数据重复发送...
+
+
+private:
+
+};
+
+
+#endif //NNXX_TESTS_SNAP7_BUF_H

+ 686 - 0
snap7_communication/snap7_communication.pb.cc

@@ -0,0 +1,686 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: snap7_communication.proto
+
+#include "snap7_communication.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// This is a temporary google only hack
+#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+#include "third_party/protobuf/version.h"
+#endif
+// @@protoc_insertion_point(includes)
+namespace Snap7_communication_proto {
+class Snap7_communication_parameterDefaultTypeInternal {
+ public:
+  ::google::protobuf::internal::ExplicitlyConstructed<Snap7_communication_parameter>
+      _instance;
+} _Snap7_communication_parameter_default_instance_;
+class Snap7_communication_parameter_allDefaultTypeInternal {
+ public:
+  ::google::protobuf::internal::ExplicitlyConstructed<Snap7_communication_parameter_all>
+      _instance;
+} _Snap7_communication_parameter_all_default_instance_;
+}  // namespace Snap7_communication_proto
+namespace protobuf_snap7_5fcommunication_2eproto {
+void InitDefaultsSnap7_communication_parameterImpl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  ::google::protobuf::internal::InitProtobufDefaultsForceUnique();
+#else
+  ::google::protobuf::internal::InitProtobufDefaults();
+#endif  // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  ::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.DefaultConstruct();
+  *::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get_mutable() = ::std::string("192.168.0.1", 11);
+  ::google::protobuf::internal::OnShutdownDestroyString(
+      ::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get_mutable());
+  {
+    void* ptr = &::Snap7_communication_proto::_Snap7_communication_parameter_default_instance_;
+    new (ptr) ::Snap7_communication_proto::Snap7_communication_parameter();
+    ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
+  }
+  ::Snap7_communication_proto::Snap7_communication_parameter::InitAsDefaultInstance();
+}
+
+void InitDefaultsSnap7_communication_parameter() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsSnap7_communication_parameterImpl);
+}
+
+void InitDefaultsSnap7_communication_parameter_allImpl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  ::google::protobuf::internal::InitProtobufDefaultsForceUnique();
+#else
+  ::google::protobuf::internal::InitProtobufDefaults();
+#endif  // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  protobuf_snap7_5fcommunication_2eproto::InitDefaultsSnap7_communication_parameter();
+  {
+    void* ptr = &::Snap7_communication_proto::_Snap7_communication_parameter_all_default_instance_;
+    new (ptr) ::Snap7_communication_proto::Snap7_communication_parameter_all();
+    ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
+  }
+  ::Snap7_communication_proto::Snap7_communication_parameter_all::InitAsDefaultInstance();
+}
+
+void InitDefaultsSnap7_communication_parameter_all() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsSnap7_communication_parameter_allImpl);
+}
+
+::google::protobuf::Metadata file_level_metadata[2];
+
+const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Snap7_communication_proto::Snap7_communication_parameter, _has_bits_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Snap7_communication_proto::Snap7_communication_parameter, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Snap7_communication_proto::Snap7_communication_parameter, ip_string_),
+  0,
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Snap7_communication_proto::Snap7_communication_parameter_all, _has_bits_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Snap7_communication_proto::Snap7_communication_parameter_all, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Snap7_communication_proto::Snap7_communication_parameter_all, snap7_communication_parameters_),
+  0,
+};
+static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, 6, sizeof(::Snap7_communication_proto::Snap7_communication_parameter)},
+  { 7, 13, sizeof(::Snap7_communication_proto::Snap7_communication_parameter_all)},
+};
+
+static ::google::protobuf::Message const * const file_default_instances[] = {
+  reinterpret_cast<const ::google::protobuf::Message*>(&::Snap7_communication_proto::_Snap7_communication_parameter_default_instance_),
+  reinterpret_cast<const ::google::protobuf::Message*>(&::Snap7_communication_proto::_Snap7_communication_parameter_all_default_instance_),
+};
+
+void protobuf_AssignDescriptors() {
+  AddDescriptors();
+  ::google::protobuf::MessageFactory* factory = NULL;
+  AssignDescriptors(
+      "snap7_communication.proto", schemas, file_default_instances, TableStruct::offsets, factory,
+      file_level_metadata, NULL, NULL);
+}
+
+void protobuf_AssignDescriptorsOnce() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 2);
+}
+
+void AddDescriptorsImpl() {
+  InitDefaults();
+  static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+      "\n\031snap7_communication.proto\022\031Snap7_commu"
+      "nication_proto\"\?\n\035Snap7_communication_pa"
+      "rameter\022\036\n\tip_string\030\001 \002(\t:\013192.168.0.1\""
+      "\205\001\n!Snap7_communication_parameter_all\022`\n"
+      "\036snap7_communication_parameters\030\001 \002(\01328."
+      "Snap7_communication_proto.Snap7_communic"
+      "ation_parameter"
+  };
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+      descriptor, 255);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "snap7_communication.proto", &protobuf_RegisterTypes);
+}
+
+void AddDescriptors() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
+}
+// Force AddDescriptors() to be called at dynamic initialization time.
+struct StaticDescriptorInitializer {
+  StaticDescriptorInitializer() {
+    AddDescriptors();
+  }
+} static_descriptor_initializer;
+}  // namespace protobuf_snap7_5fcommunication_2eproto
+namespace Snap7_communication_proto {
+
+// ===================================================================
+
+void Snap7_communication_parameter::InitAsDefaultInstance() {
+}
+::google::protobuf::internal::ExplicitlyConstructed< ::std::string> Snap7_communication_parameter::_default_ip_string_;
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Snap7_communication_parameter::kIpStringFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Snap7_communication_parameter::Snap7_communication_parameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
+    ::protobuf_snap7_5fcommunication_2eproto::InitDefaultsSnap7_communication_parameter();
+  }
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:Snap7_communication_proto.Snap7_communication_parameter)
+}
+Snap7_communication_parameter::Snap7_communication_parameter(const Snap7_communication_parameter& from)
+  : ::google::protobuf::Message(),
+      _internal_metadata_(NULL),
+      _has_bits_(from._has_bits_),
+      _cached_size_(0) {
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  ip_string_.UnsafeSetDefault(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get());
+  if (from.has_ip_string()) {
+    ip_string_.AssignWithDefault(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get(), from.ip_string_);
+  }
+  // @@protoc_insertion_point(copy_constructor:Snap7_communication_proto.Snap7_communication_parameter)
+}
+
+void Snap7_communication_parameter::SharedCtor() {
+  _cached_size_ = 0;
+  ip_string_.UnsafeSetDefault(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get());
+}
+
+Snap7_communication_parameter::~Snap7_communication_parameter() {
+  // @@protoc_insertion_point(destructor:Snap7_communication_proto.Snap7_communication_parameter)
+  SharedDtor();
+}
+
+void Snap7_communication_parameter::SharedDtor() {
+  ip_string_.DestroyNoArena(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get());
+}
+
+void Snap7_communication_parameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Snap7_communication_parameter::descriptor() {
+  ::protobuf_snap7_5fcommunication_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_snap7_5fcommunication_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
+}
+
+const Snap7_communication_parameter& Snap7_communication_parameter::default_instance() {
+  ::protobuf_snap7_5fcommunication_2eproto::InitDefaultsSnap7_communication_parameter();
+  return *internal_default_instance();
+}
+
+Snap7_communication_parameter* Snap7_communication_parameter::New(::google::protobuf::Arena* arena) const {
+  Snap7_communication_parameter* n = new Snap7_communication_parameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Snap7_communication_parameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:Snap7_communication_proto.Snap7_communication_parameter)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    GOOGLE_DCHECK(!ip_string_.IsDefault(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get()));
+    (*ip_string_.UnsafeRawStringPointer())->assign(*&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get());
+  }
+  _has_bits_.Clear();
+  _internal_metadata_.Clear();
+}
+
+bool Snap7_communication_parameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:Snap7_communication_proto.Snap7_communication_parameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // required string ip_string = 1 [default = "192.168.0.1"];
+      case 1: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_ip_string()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->ip_string().data(), static_cast<int>(this->ip_string().length()),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "Snap7_communication_proto.Snap7_communication_parameter.ip_string");
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:Snap7_communication_proto.Snap7_communication_parameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:Snap7_communication_proto.Snap7_communication_parameter)
+  return false;
+#undef DO_
+}
+
+void Snap7_communication_parameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:Snap7_communication_proto.Snap7_communication_parameter)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  // required string ip_string = 1 [default = "192.168.0.1"];
+  if (cached_has_bits & 0x00000001u) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->ip_string().data(), static_cast<int>(this->ip_string().length()),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "Snap7_communication_proto.Snap7_communication_parameter.ip_string");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->ip_string(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        _internal_metadata_.unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:Snap7_communication_proto.Snap7_communication_parameter)
+}
+
+::google::protobuf::uint8* Snap7_communication_parameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:Snap7_communication_proto.Snap7_communication_parameter)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  // required string ip_string = 1 [default = "192.168.0.1"];
+  if (cached_has_bits & 0x00000001u) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->ip_string().data(), static_cast<int>(this->ip_string().length()),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "Snap7_communication_proto.Snap7_communication_parameter.ip_string");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->ip_string(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:Snap7_communication_proto.Snap7_communication_parameter)
+  return target;
+}
+
+size_t Snap7_communication_parameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:Snap7_communication_proto.Snap7_communication_parameter)
+  size_t total_size = 0;
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        _internal_metadata_.unknown_fields());
+  }
+  // required string ip_string = 1 [default = "192.168.0.1"];
+  if (has_ip_string()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->ip_string());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Snap7_communication_parameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:Snap7_communication_proto.Snap7_communication_parameter)
+  GOOGLE_DCHECK_NE(&from, this);
+  const Snap7_communication_parameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const Snap7_communication_parameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Snap7_communication_proto.Snap7_communication_parameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Snap7_communication_proto.Snap7_communication_parameter)
+    MergeFrom(*source);
+  }
+}
+
+void Snap7_communication_parameter::MergeFrom(const Snap7_communication_parameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:Snap7_communication_proto.Snap7_communication_parameter)
+  GOOGLE_DCHECK_NE(&from, this);
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from.has_ip_string()) {
+    set_has_ip_string();
+    ip_string_.AssignWithDefault(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get(), from.ip_string_);
+  }
+}
+
+void Snap7_communication_parameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Snap7_communication_proto.Snap7_communication_parameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Snap7_communication_parameter::CopyFrom(const Snap7_communication_parameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Snap7_communication_proto.Snap7_communication_parameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Snap7_communication_parameter::IsInitialized() const {
+  if ((_has_bits_[0] & 0x00000001) != 0x00000001) return false;
+  return true;
+}
+
+void Snap7_communication_parameter::Swap(Snap7_communication_parameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Snap7_communication_parameter::InternalSwap(Snap7_communication_parameter* other) {
+  using std::swap;
+  ip_string_.Swap(&other->ip_string_);
+  swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Snap7_communication_parameter::GetMetadata() const {
+  protobuf_snap7_5fcommunication_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_snap7_5fcommunication_2eproto::file_level_metadata[kIndexInFileMessages];
+}
+
+
+// ===================================================================
+
+void Snap7_communication_parameter_all::InitAsDefaultInstance() {
+  ::Snap7_communication_proto::_Snap7_communication_parameter_all_default_instance_._instance.get_mutable()->snap7_communication_parameters_ = const_cast< ::Snap7_communication_proto::Snap7_communication_parameter*>(
+      ::Snap7_communication_proto::Snap7_communication_parameter::internal_default_instance());
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Snap7_communication_parameter_all::kSnap7CommunicationParametersFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Snap7_communication_parameter_all::Snap7_communication_parameter_all()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
+    ::protobuf_snap7_5fcommunication_2eproto::InitDefaultsSnap7_communication_parameter_all();
+  }
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:Snap7_communication_proto.Snap7_communication_parameter_all)
+}
+Snap7_communication_parameter_all::Snap7_communication_parameter_all(const Snap7_communication_parameter_all& from)
+  : ::google::protobuf::Message(),
+      _internal_metadata_(NULL),
+      _has_bits_(from._has_bits_),
+      _cached_size_(0) {
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  if (from.has_snap7_communication_parameters()) {
+    snap7_communication_parameters_ = new ::Snap7_communication_proto::Snap7_communication_parameter(*from.snap7_communication_parameters_);
+  } else {
+    snap7_communication_parameters_ = NULL;
+  }
+  // @@protoc_insertion_point(copy_constructor:Snap7_communication_proto.Snap7_communication_parameter_all)
+}
+
+void Snap7_communication_parameter_all::SharedCtor() {
+  _cached_size_ = 0;
+  snap7_communication_parameters_ = NULL;
+}
+
+Snap7_communication_parameter_all::~Snap7_communication_parameter_all() {
+  // @@protoc_insertion_point(destructor:Snap7_communication_proto.Snap7_communication_parameter_all)
+  SharedDtor();
+}
+
+void Snap7_communication_parameter_all::SharedDtor() {
+  if (this != internal_default_instance()) delete snap7_communication_parameters_;
+}
+
+void Snap7_communication_parameter_all::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Snap7_communication_parameter_all::descriptor() {
+  ::protobuf_snap7_5fcommunication_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_snap7_5fcommunication_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
+}
+
+const Snap7_communication_parameter_all& Snap7_communication_parameter_all::default_instance() {
+  ::protobuf_snap7_5fcommunication_2eproto::InitDefaultsSnap7_communication_parameter_all();
+  return *internal_default_instance();
+}
+
+Snap7_communication_parameter_all* Snap7_communication_parameter_all::New(::google::protobuf::Arena* arena) const {
+  Snap7_communication_parameter_all* n = new Snap7_communication_parameter_all;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Snap7_communication_parameter_all::Clear() {
+// @@protoc_insertion_point(message_clear_start:Snap7_communication_proto.Snap7_communication_parameter_all)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  if (cached_has_bits & 0x00000001u) {
+    GOOGLE_DCHECK(snap7_communication_parameters_ != NULL);
+    snap7_communication_parameters_->Clear();
+  }
+  _has_bits_.Clear();
+  _internal_metadata_.Clear();
+}
+
+bool Snap7_communication_parameter_all::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:Snap7_communication_proto.Snap7_communication_parameter_all)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // required .Snap7_communication_proto.Snap7_communication_parameter snap7_communication_parameters = 1;
+      case 1: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
+               input, mutable_snap7_communication_parameters()));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:Snap7_communication_proto.Snap7_communication_parameter_all)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:Snap7_communication_proto.Snap7_communication_parameter_all)
+  return false;
+#undef DO_
+}
+
+void Snap7_communication_parameter_all::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:Snap7_communication_proto.Snap7_communication_parameter_all)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  // required .Snap7_communication_proto.Snap7_communication_parameter snap7_communication_parameters = 1;
+  if (cached_has_bits & 0x00000001u) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, *this->snap7_communication_parameters_, output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        _internal_metadata_.unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:Snap7_communication_proto.Snap7_communication_parameter_all)
+}
+
+::google::protobuf::uint8* Snap7_communication_parameter_all::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:Snap7_communication_proto.Snap7_communication_parameter_all)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  cached_has_bits = _has_bits_[0];
+  // required .Snap7_communication_proto.Snap7_communication_parameter snap7_communication_parameters = 1;
+  if (cached_has_bits & 0x00000001u) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageToArray(
+        1, *this->snap7_communication_parameters_, deterministic, target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:Snap7_communication_proto.Snap7_communication_parameter_all)
+  return target;
+}
+
+size_t Snap7_communication_parameter_all::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:Snap7_communication_proto.Snap7_communication_parameter_all)
+  size_t total_size = 0;
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        _internal_metadata_.unknown_fields());
+  }
+  // required .Snap7_communication_proto.Snap7_communication_parameter snap7_communication_parameters = 1;
+  if (has_snap7_communication_parameters()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSize(
+        *this->snap7_communication_parameters_);
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Snap7_communication_parameter_all::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:Snap7_communication_proto.Snap7_communication_parameter_all)
+  GOOGLE_DCHECK_NE(&from, this);
+  const Snap7_communication_parameter_all* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const Snap7_communication_parameter_all>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Snap7_communication_proto.Snap7_communication_parameter_all)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Snap7_communication_proto.Snap7_communication_parameter_all)
+    MergeFrom(*source);
+  }
+}
+
+void Snap7_communication_parameter_all::MergeFrom(const Snap7_communication_parameter_all& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:Snap7_communication_proto.Snap7_communication_parameter_all)
+  GOOGLE_DCHECK_NE(&from, this);
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  if (from.has_snap7_communication_parameters()) {
+    mutable_snap7_communication_parameters()->::Snap7_communication_proto::Snap7_communication_parameter::MergeFrom(from.snap7_communication_parameters());
+  }
+}
+
+void Snap7_communication_parameter_all::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Snap7_communication_proto.Snap7_communication_parameter_all)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Snap7_communication_parameter_all::CopyFrom(const Snap7_communication_parameter_all& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Snap7_communication_proto.Snap7_communication_parameter_all)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Snap7_communication_parameter_all::IsInitialized() const {
+  if ((_has_bits_[0] & 0x00000001) != 0x00000001) return false;
+  if (has_snap7_communication_parameters()) {
+    if (!this->snap7_communication_parameters_->IsInitialized()) return false;
+  }
+  return true;
+}
+
+void Snap7_communication_parameter_all::Swap(Snap7_communication_parameter_all* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Snap7_communication_parameter_all::InternalSwap(Snap7_communication_parameter_all* other) {
+  using std::swap;
+  swap(snap7_communication_parameters_, other->snap7_communication_parameters_);
+  swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Snap7_communication_parameter_all::GetMetadata() const {
+  protobuf_snap7_5fcommunication_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_snap7_5fcommunication_2eproto::file_level_metadata[kIndexInFileMessages];
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+}  // namespace Snap7_communication_proto
+
+// @@protoc_insertion_point(global_scope)

+ 439 - 0
snap7_communication/snap7_communication.pb.h

@@ -0,0 +1,439 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: snap7_communication.proto
+
+#ifndef PROTOBUF_snap7_5fcommunication_2eproto__INCLUDED
+#define PROTOBUF_snap7_5fcommunication_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3005000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_table_driven.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace protobuf_snap7_5fcommunication_2eproto {
+// Internal implementation detail -- do not use these members.
+struct TableStruct {
+  static const ::google::protobuf::internal::ParseTableField entries[];
+  static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
+  static const ::google::protobuf::internal::ParseTable schema[2];
+  static const ::google::protobuf::internal::FieldMetadata field_metadata[];
+  static const ::google::protobuf::internal::SerializationTable serialization_table[];
+  static const ::google::protobuf::uint32 offsets[];
+};
+void AddDescriptors();
+void InitDefaultsSnap7_communication_parameterImpl();
+void InitDefaultsSnap7_communication_parameter();
+void InitDefaultsSnap7_communication_parameter_allImpl();
+void InitDefaultsSnap7_communication_parameter_all();
+inline void InitDefaults() {
+  InitDefaultsSnap7_communication_parameter();
+  InitDefaultsSnap7_communication_parameter_all();
+}
+}  // namespace protobuf_snap7_5fcommunication_2eproto
+namespace Snap7_communication_proto {
+class Snap7_communication_parameter;
+class Snap7_communication_parameterDefaultTypeInternal;
+extern Snap7_communication_parameterDefaultTypeInternal _Snap7_communication_parameter_default_instance_;
+class Snap7_communication_parameter_all;
+class Snap7_communication_parameter_allDefaultTypeInternal;
+extern Snap7_communication_parameter_allDefaultTypeInternal _Snap7_communication_parameter_all_default_instance_;
+}  // namespace Snap7_communication_proto
+namespace Snap7_communication_proto {
+
+// ===================================================================
+
+class Snap7_communication_parameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Snap7_communication_proto.Snap7_communication_parameter) */ {
+ public:
+  Snap7_communication_parameter();
+  virtual ~Snap7_communication_parameter();
+
+  Snap7_communication_parameter(const Snap7_communication_parameter& from);
+
+  inline Snap7_communication_parameter& operator=(const Snap7_communication_parameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  #if LANG_CXX11
+  Snap7_communication_parameter(Snap7_communication_parameter&& from) noexcept
+    : Snap7_communication_parameter() {
+    *this = ::std::move(from);
+  }
+
+  inline Snap7_communication_parameter& operator=(Snap7_communication_parameter&& from) noexcept {
+    if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
+      if (this != &from) InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+  #endif
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Snap7_communication_parameter& default_instance();
+
+  static void InitAsDefaultInstance();  // FOR INTERNAL USE ONLY
+  static inline const Snap7_communication_parameter* internal_default_instance() {
+    return reinterpret_cast<const Snap7_communication_parameter*>(
+               &_Snap7_communication_parameter_default_instance_);
+  }
+  static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
+    0;
+
+  void Swap(Snap7_communication_parameter* other);
+  friend void swap(Snap7_communication_parameter& a, Snap7_communication_parameter& b) {
+    a.Swap(&b);
+  }
+
+  // implements Message ----------------------------------------------
+
+  inline Snap7_communication_parameter* New() const PROTOBUF_FINAL { return New(NULL); }
+
+  Snap7_communication_parameter* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CopyFrom(const Snap7_communication_parameter& from);
+  void MergeFrom(const Snap7_communication_parameter& from);
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
+
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void InternalSwap(Snap7_communication_parameter* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return NULL;
+  }
+  inline void* MaybeArenaPtr() const {
+    return NULL;
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // required string ip_string = 1 [default = "192.168.0.1"];
+  bool has_ip_string() const;
+  void clear_ip_string();
+  static const int kIpStringFieldNumber = 1;
+  const ::std::string& ip_string() const;
+  void set_ip_string(const ::std::string& value);
+  #if LANG_CXX11
+  void set_ip_string(::std::string&& value);
+  #endif
+  void set_ip_string(const char* value);
+  void set_ip_string(const char* value, size_t size);
+  ::std::string* mutable_ip_string();
+  ::std::string* release_ip_string();
+  void set_allocated_ip_string(::std::string* ip_string);
+
+  // @@protoc_insertion_point(class_scope:Snap7_communication_proto.Snap7_communication_parameter)
+ private:
+  void set_has_ip_string();
+  void clear_has_ip_string();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  static ::google::protobuf::internal::ExplicitlyConstructed< ::std::string> _default_ip_string_;
+  ::google::protobuf::internal::ArenaStringPtr ip_string_;
+  friend struct ::protobuf_snap7_5fcommunication_2eproto::TableStruct;
+  friend void ::protobuf_snap7_5fcommunication_2eproto::InitDefaultsSnap7_communication_parameterImpl();
+};
+// -------------------------------------------------------------------
+
+class Snap7_communication_parameter_all : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Snap7_communication_proto.Snap7_communication_parameter_all) */ {
+ public:
+  Snap7_communication_parameter_all();
+  virtual ~Snap7_communication_parameter_all();
+
+  Snap7_communication_parameter_all(const Snap7_communication_parameter_all& from);
+
+  inline Snap7_communication_parameter_all& operator=(const Snap7_communication_parameter_all& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  #if LANG_CXX11
+  Snap7_communication_parameter_all(Snap7_communication_parameter_all&& from) noexcept
+    : Snap7_communication_parameter_all() {
+    *this = ::std::move(from);
+  }
+
+  inline Snap7_communication_parameter_all& operator=(Snap7_communication_parameter_all&& from) noexcept {
+    if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
+      if (this != &from) InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+  #endif
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Snap7_communication_parameter_all& default_instance();
+
+  static void InitAsDefaultInstance();  // FOR INTERNAL USE ONLY
+  static inline const Snap7_communication_parameter_all* internal_default_instance() {
+    return reinterpret_cast<const Snap7_communication_parameter_all*>(
+               &_Snap7_communication_parameter_all_default_instance_);
+  }
+  static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
+    1;
+
+  void Swap(Snap7_communication_parameter_all* other);
+  friend void swap(Snap7_communication_parameter_all& a, Snap7_communication_parameter_all& b) {
+    a.Swap(&b);
+  }
+
+  // implements Message ----------------------------------------------
+
+  inline Snap7_communication_parameter_all* New() const PROTOBUF_FINAL { return New(NULL); }
+
+  Snap7_communication_parameter_all* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CopyFrom(const Snap7_communication_parameter_all& from);
+  void MergeFrom(const Snap7_communication_parameter_all& from);
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
+
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void InternalSwap(Snap7_communication_parameter_all* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return NULL;
+  }
+  inline void* MaybeArenaPtr() const {
+    return NULL;
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // required .Snap7_communication_proto.Snap7_communication_parameter snap7_communication_parameters = 1;
+  bool has_snap7_communication_parameters() const;
+  void clear_snap7_communication_parameters();
+  static const int kSnap7CommunicationParametersFieldNumber = 1;
+  const ::Snap7_communication_proto::Snap7_communication_parameter& snap7_communication_parameters() const;
+  ::Snap7_communication_proto::Snap7_communication_parameter* release_snap7_communication_parameters();
+  ::Snap7_communication_proto::Snap7_communication_parameter* mutable_snap7_communication_parameters();
+  void set_allocated_snap7_communication_parameters(::Snap7_communication_proto::Snap7_communication_parameter* snap7_communication_parameters);
+
+  // @@protoc_insertion_point(class_scope:Snap7_communication_proto.Snap7_communication_parameter_all)
+ private:
+  void set_has_snap7_communication_parameters();
+  void clear_has_snap7_communication_parameters();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::Snap7_communication_proto::Snap7_communication_parameter* snap7_communication_parameters_;
+  friend struct ::protobuf_snap7_5fcommunication_2eproto::TableStruct;
+  friend void ::protobuf_snap7_5fcommunication_2eproto::InitDefaultsSnap7_communication_parameter_allImpl();
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Snap7_communication_parameter
+
+// required string ip_string = 1 [default = "192.168.0.1"];
+inline bool Snap7_communication_parameter::has_ip_string() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Snap7_communication_parameter::set_has_ip_string() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void Snap7_communication_parameter::clear_has_ip_string() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void Snap7_communication_parameter::clear_ip_string() {
+  ip_string_.ClearToDefaultNoArena(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get());
+  clear_has_ip_string();
+}
+inline const ::std::string& Snap7_communication_parameter::ip_string() const {
+  // @@protoc_insertion_point(field_get:Snap7_communication_proto.Snap7_communication_parameter.ip_string)
+  return ip_string_.GetNoArena();
+}
+inline void Snap7_communication_parameter::set_ip_string(const ::std::string& value) {
+  set_has_ip_string();
+  ip_string_.SetNoArena(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get(), value);
+  // @@protoc_insertion_point(field_set:Snap7_communication_proto.Snap7_communication_parameter.ip_string)
+}
+#if LANG_CXX11
+inline void Snap7_communication_parameter::set_ip_string(::std::string&& value) {
+  set_has_ip_string();
+  ip_string_.SetNoArena(
+    &::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get(), ::std::move(value));
+  // @@protoc_insertion_point(field_set_rvalue:Snap7_communication_proto.Snap7_communication_parameter.ip_string)
+}
+#endif
+inline void Snap7_communication_parameter::set_ip_string(const char* value) {
+  GOOGLE_DCHECK(value != NULL);
+  set_has_ip_string();
+  ip_string_.SetNoArena(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:Snap7_communication_proto.Snap7_communication_parameter.ip_string)
+}
+inline void Snap7_communication_parameter::set_ip_string(const char* value, size_t size) {
+  set_has_ip_string();
+  ip_string_.SetNoArena(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:Snap7_communication_proto.Snap7_communication_parameter.ip_string)
+}
+inline ::std::string* Snap7_communication_parameter::mutable_ip_string() {
+  set_has_ip_string();
+  // @@protoc_insertion_point(field_mutable:Snap7_communication_proto.Snap7_communication_parameter.ip_string)
+  return ip_string_.MutableNoArena(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get());
+}
+inline ::std::string* Snap7_communication_parameter::release_ip_string() {
+  // @@protoc_insertion_point(field_release:Snap7_communication_proto.Snap7_communication_parameter.ip_string)
+  clear_has_ip_string();
+  return ip_string_.ReleaseNoArena(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get());
+}
+inline void Snap7_communication_parameter::set_allocated_ip_string(::std::string* ip_string) {
+  if (ip_string != NULL) {
+    set_has_ip_string();
+  } else {
+    clear_has_ip_string();
+  }
+  ip_string_.SetAllocatedNoArena(&::Snap7_communication_proto::Snap7_communication_parameter::_default_ip_string_.get(), ip_string);
+  // @@protoc_insertion_point(field_set_allocated:Snap7_communication_proto.Snap7_communication_parameter.ip_string)
+}
+
+// -------------------------------------------------------------------
+
+// Snap7_communication_parameter_all
+
+// required .Snap7_communication_proto.Snap7_communication_parameter snap7_communication_parameters = 1;
+inline bool Snap7_communication_parameter_all::has_snap7_communication_parameters() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Snap7_communication_parameter_all::set_has_snap7_communication_parameters() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void Snap7_communication_parameter_all::clear_has_snap7_communication_parameters() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void Snap7_communication_parameter_all::clear_snap7_communication_parameters() {
+  if (snap7_communication_parameters_ != NULL) snap7_communication_parameters_->Clear();
+  clear_has_snap7_communication_parameters();
+}
+inline const ::Snap7_communication_proto::Snap7_communication_parameter& Snap7_communication_parameter_all::snap7_communication_parameters() const {
+  const ::Snap7_communication_proto::Snap7_communication_parameter* p = snap7_communication_parameters_;
+  // @@protoc_insertion_point(field_get:Snap7_communication_proto.Snap7_communication_parameter_all.snap7_communication_parameters)
+  return p != NULL ? *p : *reinterpret_cast<const ::Snap7_communication_proto::Snap7_communication_parameter*>(
+      &::Snap7_communication_proto::_Snap7_communication_parameter_default_instance_);
+}
+inline ::Snap7_communication_proto::Snap7_communication_parameter* Snap7_communication_parameter_all::release_snap7_communication_parameters() {
+  // @@protoc_insertion_point(field_release:Snap7_communication_proto.Snap7_communication_parameter_all.snap7_communication_parameters)
+  clear_has_snap7_communication_parameters();
+  ::Snap7_communication_proto::Snap7_communication_parameter* temp = snap7_communication_parameters_;
+  snap7_communication_parameters_ = NULL;
+  return temp;
+}
+inline ::Snap7_communication_proto::Snap7_communication_parameter* Snap7_communication_parameter_all::mutable_snap7_communication_parameters() {
+  set_has_snap7_communication_parameters();
+  if (snap7_communication_parameters_ == NULL) {
+    snap7_communication_parameters_ = new ::Snap7_communication_proto::Snap7_communication_parameter;
+  }
+  // @@protoc_insertion_point(field_mutable:Snap7_communication_proto.Snap7_communication_parameter_all.snap7_communication_parameters)
+  return snap7_communication_parameters_;
+}
+inline void Snap7_communication_parameter_all::set_allocated_snap7_communication_parameters(::Snap7_communication_proto::Snap7_communication_parameter* snap7_communication_parameters) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete snap7_communication_parameters_;
+  }
+  if (snap7_communication_parameters) {
+    ::google::protobuf::Arena* submessage_arena = NULL;
+    if (message_arena != submessage_arena) {
+      snap7_communication_parameters = ::google::protobuf::internal::GetOwnedMessage(
+          message_arena, snap7_communication_parameters, submessage_arena);
+    }
+    set_has_snap7_communication_parameters();
+  } else {
+    clear_has_snap7_communication_parameters();
+  }
+  snap7_communication_parameters_ = snap7_communication_parameters;
+  // @@protoc_insertion_point(field_set_allocated:Snap7_communication_proto.Snap7_communication_parameter_all.snap7_communication_parameters)
+}
+
+#ifdef __GNUC__
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace Snap7_communication_proto
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_snap7_5fcommunication_2eproto__INCLUDED

+ 12 - 0
snap7_communication/snap7_communication.proto

@@ -0,0 +1,12 @@
+syntax = "proto2";
+package Snap7_communication_proto;
+
+message Snap7_communication_parameter
+{
+    required string ip_string = 1 [default="192.168.0.1"];
+}
+
+message Snap7_communication_parameter_all
+{
+    required Snap7_communication_parameter        snap7_communication_parameters=1;
+}

+ 326 - 0
snap7_communication/snap7_communication_base.cpp

@@ -0,0 +1,326 @@
+//
+// Created by huli on 2020/9/25.
+//
+
+#include "snap7_communication_base.h"
+#include "../tool/proto_tool.h"
+
+Snap7_communication_base::Snap7_communication_base()
+{
+	m_communication_status = E_UNKNOWN;
+	m_communication_delay_time_ms = SNAP7_COMMUNICATION_DELAY_TIME_MS;
+	mp_communication_thread = NULL;
+}
+
+Snap7_communication_base::~Snap7_communication_base()
+{
+	communication_uninit();
+}
+
+//初始化 通信 模块。如下三选一
+Error_manager Snap7_communication_base::communication_init()
+{
+	return  communication_init_from_protobuf(SNAP7_COMMUNICATION_PARAMETER_PATH);
+}
+//初始化 通信 模块。从文件读取
+Error_manager Snap7_communication_base::communication_init_from_protobuf(std::string prototxt_path)
+{
+	Snap7_communication_proto::Snap7_communication_parameter_all t_snap7_communication_parameter_all;
+	if(!  proto_tool::read_proto_param(prototxt_path,t_snap7_communication_parameter_all) )
+	{
+		return Error_manager(SNAP7_READ_PROTOBUF_ERROR,MINOR_ERROR,
+							 "Snap7_communication_base::communication_init_from_protobuf read_proto_param  failed");
+	}
+	return communication_init_from_protobuf(t_snap7_communication_parameter_all);
+}
+//初始化 通信 模块。从protobuf读取
+Error_manager Snap7_communication_base::communication_init_from_protobuf(Snap7_communication_proto::Snap7_communication_parameter_all& snap7_communication_parameter_all)
+{
+	LOG(INFO) << " ---Communication_socket_base::communication_init() --- "<< this;
+	Error_manager t_error;
+//	snap7_communication_parameter_all.DebugString();
+
+	if ( snap7_communication_parameter_all.snap7_communication_parameters().has_ip_string() )
+	{
+		m_ip_string = snap7_communication_parameter_all.snap7_communication_parameters().ip_string();
+		t_error = communication_connect(m_ip_string);
+		if ( t_error != Error_code::SUCCESS )
+		{
+			//连接失败, 不要直接返回, 而是改为断连, 后面继续启动线程, (线程内部有重连功能)
+			m_communication_status = E_DISCONNECT;
+		}
+		else
+		{
+			m_communication_status = E_READY;
+		}
+	}
+
+	//启动通信, run thread
+	communication_run();
+	return Error_code::SUCCESS;
+}
+
+
+//反初始化 通信 模块。
+Error_manager Snap7_communication_base::communication_uninit()
+{
+	//关闭线程并回收资源
+	if (mp_communication_thread)
+	{
+		m_communication_condition.kill_all();
+	}
+	if (mp_communication_thread)
+	{
+		mp_communication_thread->join();
+		delete mp_communication_thread;
+		mp_communication_thread = NULL;
+	}
+
+	//清空map
+	{
+		std::unique_lock<std::mutex> t_lock(m_receive_buf_lock);
+		m_receive_buf_map.clear();
+	}
+	{
+		std::unique_lock<std::mutex> t_lock(m_send_buf_lock);
+		m_send_buf_map.clear();
+	}
+
+	communication_disconnect();
+	m_communication_status = E_UNKNOWN;
+
+	return Error_code::SUCCESS;
+}
+
+Snap7_communication_base::Communication_statu Snap7_communication_base::get_status()
+{
+	return m_communication_status;
+}
+
+//通信连接
+Error_manager Snap7_communication_base::communication_connect(std::string ip_string)
+{
+	std::unique_lock<std::mutex> t_lock(m_communication_lock);
+	int result=m_snap7_client.ConnectTo(ip_string.c_str(),0,1);
+	std::this_thread::sleep_for(std::chrono::milliseconds(m_communication_delay_time_ms));
+	if (result==0)
+	{
+		return Error_code::SUCCESS;
+	}
+	else
+	{
+		return Error_manager(Error_code::SNAP7_CONNECT_ERROR, Error_level::MINOR_ERROR,
+							 " Snap7_communication_base::communication_connect error ");
+	}
+	return Error_code::SUCCESS;
+}
+//启动通信, run thread
+Error_manager Snap7_communication_base::communication_run()
+{
+	//启动4个线程。
+	//接受线程默认循环, 内部的nn_recv进行等待, 超时1ms
+	m_communication_condition.reset(false, false, false);
+	mp_communication_thread = new std::thread(&Snap7_communication_base::communication_thread, this);
+
+	return Error_code::SUCCESS;
+}
+//通信断连
+Error_manager Snap7_communication_base::communication_disconnect()
+{
+	std::unique_lock<std::mutex> t_lock(m_communication_lock);
+	int result=m_snap7_client.Disconnect();
+	std::this_thread::sleep_for(std::chrono::milliseconds(m_communication_delay_time_ms));
+	if (result==0)
+	{
+		return Error_code::SUCCESS;
+	}
+	else
+	{
+		return Error_manager(Error_code::SNAP7_DISCONNECT_ERROR, Error_level::MINOR_ERROR,
+							 " Snap7_communication_base::communication_disconnect error ");
+	}
+	return Error_code::SUCCESS;
+}
+//mp_communication_thread线程的执行函数, 负责进行s7的通信
+void Snap7_communication_base::communication_thread()
+{
+	LOG(INFO) << " ---Snap7_communication_base::communication_thread()--- "<< this;
+Error_manager t_error;
+	while (m_communication_condition.is_alive())
+	{
+		m_communication_condition.wait_for_ex(std::chrono::milliseconds(m_communication_delay_time_ms));
+
+		//s7的通信时间较长, 所以将发送和接受分开
+		//发送多个时, 必须加锁后一起发送, 不允许分段写入, 防止数据错误
+		if ( m_communication_condition.is_alive() )
+		{
+			std::this_thread::yield();
+			switch ( m_communication_status )
+			{
+			    case E_READY:
+				case E_RECEIVE:
+			    {
+					{
+						std::unique_lock<std::mutex> t_lock(m_receive_buf_lock);
+						for (auto iter = m_receive_buf_map.begin(); iter != m_receive_buf_map.end(); ++iter)
+						{
+							//接受数据, 读取DB块,
+							t_error = read_data_buf(iter->second);
+							if (t_error == Error_code::SNAP7_READ_ERROR)
+							{
+								m_communication_status = E_DISCONNECT;
+								std::cout << " huli test :::: " << " t_error = " << t_error << std::endl;
+								break;
+							}
+						}
+					}
+					//注:数据更新放在锁的外面, 防止重复加锁....
+					updata_receive_buf();
+					m_communication_status = E_SEND;
+			        break;
+			    }
+			    case E_SEND:
+			    {
+					//注:数据更新放在锁的外面, 防止重复加锁....
+					updata_send_buf();
+					{
+						std::unique_lock<std::mutex> t_lock(m_send_buf_lock);
+						for (auto iter = m_send_buf_map.begin(); iter != m_send_buf_map.end(); ++iter)
+						{
+							//发送数据, 写入DB块,
+							t_error = write_data_buf(iter->second);
+							if (t_error == Error_code::SNAP7_WRITE_ERROR)
+							{
+								m_communication_status = E_DISCONNECT;
+								std::cout << " huli test :::: " << " t_error = " << t_error << std::endl;
+								break;
+							}
+						}
+					}
+					m_communication_status = E_RECEIVE;
+			        break;
+			    }
+				case E_DISCONNECT:
+				{
+					//重连
+					LOG(WARNING) << "find plc connection error, trying to reconnect.";
+					communication_disconnect();
+					std::this_thread::sleep_for(std::chrono::milliseconds(m_communication_delay_time_ms));
+					t_error = communication_connect(m_ip_string);
+					if ( t_error != Error_code::SUCCESS )
+					{
+						//连接失败, 不要直接返回, 而是改为断连, 后面继续启动线程, (线程内部有重连功能)
+						m_communication_status = E_DISCONNECT;
+					}
+					else
+					{
+						m_communication_status = E_READY;
+					}
+					std::this_thread::sleep_for(std::chrono::milliseconds(m_communication_delay_time_ms));
+
+					break;
+				}
+			    default:
+			    {
+
+			        break;
+			    }
+			}
+		}
+	}
+
+	LOG(INFO) << " Communication_socket_base::send_data_thread end "<< this;
+	return;
+}
+
+//接受数据, 读取DB块,
+Error_manager Snap7_communication_base::read_data_buf(Snap7_buf& snap7_buf)
+{
+	Error_manager t_error;
+	if ( snap7_buf.m_communication_mode != Snap7_buf::NO_COMMUNICATION)
+	{
+		if ( snap7_buf.m_communication_mode == Snap7_buf::ONCE_COMMUNICATION )
+		{
+			snap7_buf.m_communication_mode = Snap7_buf::NO_COMMUNICATION;
+		}
+
+		std::unique_lock<std::mutex> lck(m_communication_lock);
+		int result = m_snap7_client.AsDBRead(snap7_buf.m_id, snap7_buf.m_start_index, snap7_buf.m_size, snap7_buf.mp_buf_reverse);
+		if ( result == 0 )
+		{
+			m_snap7_client.WaitAsCompletion(100);
+			//倒序数据 转为 正序数据
+			snap7_buf.reverse_to_obverse();
+		}
+		else
+		{
+			return Error_manager(Error_code::SNAP7_READ_ERROR, Error_level::MINOR_ERROR,
+								 " Snap7_communication_base::read_data_buf error ");
+		}
+	}
+
+	return Error_code::SUCCESS;
+}
+//发送数据, 写入DB块,
+Error_manager Snap7_communication_base::write_data_buf(Snap7_buf& snap7_buf)
+{
+	Error_manager t_error;
+	if ( snap7_buf.m_communication_mode != Snap7_buf::NO_COMMUNICATION)
+	{
+		if ( snap7_buf.m_communication_mode != Snap7_buf::ONCE_COMMUNICATION )
+		{
+			snap7_buf.m_communication_mode = Snap7_buf::NO_COMMUNICATION;
+		}
+
+		//正序数据 转为 倒序数据
+		snap7_buf.obverse_to_reverse();
+
+		std::unique_lock<std::mutex> lck(m_communication_lock);
+		int result = m_snap7_client.AsDBWrite(snap7_buf.m_id, snap7_buf.m_start_index, snap7_buf.m_size,
+											  snap7_buf.mp_buf_reverse);
+		if ( result == 0 )
+		{
+			m_snap7_client.WaitAsCompletion(100);
+		}
+		else
+		{
+			return Error_manager(Error_code::SNAP7_WRITE_ERROR, Error_level::MINOR_ERROR,
+								 " Snap7_communication_base::write_data_buf error ");
+		}
+	}
+	return Error_code::SUCCESS;
+}
+
+//数据颠倒
+Error_manager Snap7_communication_base::reverse_byte(void* p_buf_in, void* p_buf_out, int size)
+{
+	if ( p_buf_in == NULL || p_buf_out == NULL )
+	{
+	    return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+	    					"  POINTER IS NULL ");
+	}
+	char* tp_in=(char*)p_buf_in;
+	char* tp_out=(char*)p_buf_out;
+//	for(int i=0;i<size;++i)
+//	{
+//		tp_out[i]=tp_in[size-i-1];
+//	}
+	for(int i=0;i<size;++i)
+	{
+		tp_out[i]=tp_in[i];
+	}
+	return Error_code::SUCCESS;
+}
+
+//更新数据
+Error_manager Snap7_communication_base::updata_receive_buf()
+{
+	return Error_code::SUCCESS;
+}
+Error_manager Snap7_communication_base::updata_send_buf()
+{
+	return Error_code::SUCCESS;
+}
+
+
+

+ 102 - 0
snap7_communication/snap7_communication_base.h

@@ -0,0 +1,102 @@
+//
+// Created by huli on 2020/9/25.
+//
+
+#ifndef NNXX_TESTS_SNAP7_E_BASE_H
+#define NNXX_TESTS_SNAP7_E_BASE_H
+
+#include <s7_client.h>
+#include <mutex>
+#include <map>
+#include <glog/logging.h>
+
+#include "../error_code/error_code.h"
+#include "../tool/thread_condition.h"
+#include "../snap7_communication/snap7_buf.h"
+#include "../snap7_communication/s7_plc.h"
+#include "../snap7_communication/snap7_communication.pb.h"
+
+class Snap7_communication_base
+{
+public:
+	//snap7的通信延时, 默认50ms
+#define SNAP7_COMMUNICATION_DELAY_TIME_MS 	50
+//snap7的通信参数路径
+#define SNAP7_COMMUNICATION_PARAMETER_PATH	"../setting/snap7_communication.prototxt"
+	//通信状态
+	enum Communication_statu
+	{
+		E_UNKNOWN		=0,	        //通信状态 未知
+		E_READY			=1,			//通信状态 正常
+
+		E_RECEIVE		=2, 		//接受
+		E_SEND			=3, 		//发送
+		E_DISCONNECT	=4, 		//断连
+
+		E_FAULT			=10,         //通信状态 错误
+	};
+public:
+	Snap7_communication_base();
+	Snap7_communication_base(const Snap7_communication_base& other)= default;
+	Snap7_communication_base& operator =(const Snap7_communication_base& other)= default;
+	~Snap7_communication_base();
+public://API functions
+	//初始化 通信 模块。如下三选一
+	virtual Error_manager communication_init();
+	//初始化 通信 模块。从文件读取
+	virtual Error_manager communication_init_from_protobuf(std::string prototxt_path);
+	//初始化 通信 模块。从protobuf读取
+	virtual Error_manager communication_init_from_protobuf(Snap7_communication_proto::Snap7_communication_parameter_all& snap7_communication_parameter_all);
+	//反初始化 通信 模块。
+	virtual Error_manager communication_uninit();
+public://get or set member variable
+	Communication_statu get_status();
+protected://member functions
+	//通信连接
+	Error_manager communication_connect(std::string ip_string);
+	//启动通信, run thread
+	Error_manager communication_run();
+	//通信断连
+	Error_manager communication_disconnect();
+	//mp_communication_thread线程的执行函数, 负责进行s7的通信
+	void communication_thread();
+
+	//接受数据, 读取DB块,
+	Error_manager read_data_buf(Snap7_buf& snap7_buf);
+	//发送数据, 写入DB块,
+	Error_manager write_data_buf(Snap7_buf& snap7_buf);
+	//数据颠倒
+	Error_manager reverse_byte(void* p_buf_in, void* p_buf_out, int size);
+
+	//更新数据
+	virtual Error_manager updata_receive_buf();
+	virtual Error_manager updata_send_buf();
+protected://member variable
+
+	//状态
+	Communication_statu				m_communication_status;	//通信状态
+	std::string						m_ip_string;			//通信ip
+
+	//通信模块
+	std::mutex  					m_communication_lock;	//通信锁
+	TSnap7Client 					m_snap7_client;			//通信的客户端
+	int 							m_communication_delay_time_ms;//通信延时, 单位ms
+	//注:s7协议通信很不稳定, 在每次使用 TSnap7Client 之后, 都需要加延时
+
+	//数据
+	std::mutex  					m_receive_buf_lock;		//接受的锁
+	std::map<int, Snap7_buf>		m_receive_buf_map; 		//接受的map容器
+	std::mutex  					m_send_buf_lock;		//发送的锁
+	std::map<int, Snap7_buf>		m_send_buf_map; 		//发送的map容器
+
+	//线程, snap7的通信核心就是对 发送和接受内存的 周期性读写, 所以使用一个线程即可.
+	std::thread*					mp_communication_thread;    		//通信的线程指针
+	Thread_condition				m_communication_condition;			//通信的条件变量
+
+
+private:
+
+};
+
+
+#endif //NNXX_TESTS_SNAP7_E_BASE_H

+ 123 - 0
system/system_communication.cpp

@@ -0,0 +1,123 @@
+//
+// Created by huli on 2020/6/28.
+//
+
+#include "system_communication.h"
+//#include "../laser/laser_manager.h"
+//#include "../locate/locate_manager.h"
+#include "../system/system_executor.h"
+
+System_communication::System_communication()
+{
+
+}
+
+System_communication::~System_communication()
+{
+
+}
+
+
+//检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的.
+Error_manager System_communication::check_msg(Communication_message*  p_msg)
+{
+	return System_executor::get_instance_references().check_msg(p_msg);
+}
+
+//检查执行者的状态, 判断能否处理这条消息, 需要子类重载
+Error_manager System_communication::check_executer(Communication_message*  p_msg)
+{
+	//检查对应模块的状态, 判断是否可以处理这条消息
+	//同时也要判断是否超时, 超时返回 COMMUNICATION_ANALYSIS_TIME_OUT
+	//如果处理器正在忙别的, 那么返回 COMMUNICATION_EXCUTER_IS_BUSY
+//	std::cout << "Communication_socket_base::check_msg  p_buf =  " << p_msg->get_message_buf() << std::endl;
+//	std::cout << "Communication_socket_base::check_msg   size =  " << p_msg->get_message_buf().size() << std::endl;
+
+	Error_manager t_error;
+	if ( p_msg->is_over_time() )
+	{
+		std::cout << "COMMUNICATION_ANALYSIS_TIME_OUT , " << std::endl;
+		//超时:接收方不做处理,发送方会进行超时处理
+		return Error_code::COMMUNICATION_ANALYSIS_TIME_OUT;
+	}
+	else
+	{
+
+		return System_executor::get_instance_references().check_executer(p_msg);
+	}
+	return Error_code::SUCCESS;
+}
+
+//处理消息, 需要子类重载
+Error_manager System_communication::execute_msg(Communication_message* p_msg)
+{
+	return System_executor::get_instance_references().execute_msg(p_msg);
+}
+
+//定时封装发送消息, 一般为心跳和状态信息, 需要子类重载
+Error_manager System_communication::encapsulate_send_data()
+{
+	Error_manager t_error;
+	return System_executor::get_instance_references().encapsulate_send_status();
+/*
+	message::Measure_request_msg t_measure_request_msg;
+	t_measure_request_msg.mutable_base_info()->set_msg_type(message::Message_type::eLocate_request_msg);
+	t_measure_request_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_measure_request_msg.mutable_base_info()->set_sender(message::Communicator::eMain);
+	t_measure_request_msg.mutable_base_info()->set_receiver(message::Communicator::eMeasurer);
+	t_measure_request_msg.set_command_id(123);
+	t_measure_request_msg.set_terminal_id(1);
+	string t_msg = t_measure_request_msg.SerializeAsString();
+	System_communication::get_instance_references().encapsulate_msg(t_msg);
+ */
+
+
+/*
+	//创建一条状态消息
+	message::Measure_status_msg t_measure_status_msg;
+	t_measure_status_msg.mutable_base_info()->set_msg_type(message::Message_type::eLocate_status_msg);
+	t_measure_status_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_measure_status_msg.mutable_base_info()->set_sender(message::Communicator::eMeasurer);
+	t_measure_status_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+
+	Laser_manager::Laser_manager_status t_laser_manager_status = Laser_manager::get_instance_references().get_laser_manager_status();
+	t_measure_status_msg.set_laser_manager_status((message::Laser_manager_status)t_laser_manager_status);
+
+	std::vector<Laser_base*> & t_laser_vector = Laser_manager::get_instance_references().get_laser_vector();
+	for (auto iter = t_laser_vector.begin(); iter != t_laser_vector.end(); ++iter)
+	{
+		Laser_statu t_laser_statu = (*iter)->get_laser_statu();
+		t_measure_status_msg.add_laser_statu_vector((message::Laser_statu)t_laser_statu);
+	}
+
+	Locate_manager::Locate_manager_status t_locate_manager_status = Locate_manager::get_instance_references().get_locate_manager_status();
+	t_measure_status_msg.set_locate_manager_status((message::Locate_manager_status)t_locate_manager_status);
+
+	t_measure_status_msg.mutable_error_manager()->set_error_code(t_error.get_error_code());
+	t_measure_status_msg.mutable_error_manager()->set_error_level((message::Error_level)t_error.get_error_level());
+	t_measure_status_msg.mutable_error_manager()->set_error_description(t_error.get_error_description(), t_error.get_description_length());
+
+	t_measure_status_msg.mutable_locate_information_realtime()->set_locate_x(0);
+	t_measure_status_msg.mutable_locate_information_realtime()->set_locate_y(0);
+	t_measure_status_msg.mutable_locate_information_realtime()->set_locate_angle(0);
+	t_measure_status_msg.mutable_locate_information_realtime()->set_locate_length(0);
+	t_measure_status_msg.mutable_locate_information_realtime()->set_locate_width(0);
+	t_measure_status_msg.mutable_locate_information_realtime()->set_locate_height(0);
+	t_measure_status_msg.mutable_locate_information_realtime()->set_locate_wheel_base(0);
+	t_measure_status_msg.mutable_locate_information_realtime()->set_locate_wheel_width(0);
+	t_measure_status_msg.mutable_locate_information_realtime()->set_locate_correct(0);
+
+	string t_msg = t_measure_status_msg.SerializeAsString();
+	System_communication::get_instance_references().encapsulate_msg(t_msg);
+*/
+	return Error_code::SUCCESS;
+}
+
+
+
+
+
+
+
+
+

+ 46 - 0
system/system_communication.h

@@ -0,0 +1,46 @@
+//
+// Created by huli on 2020/6/28.
+//
+
+#ifndef NNXX_TESTS_SYSTEM_COMMUNICATION_H
+#define NNXX_TESTS_SYSTEM_COMMUNICATION_H
+
+#include "../tool/singleton.h"
+#include "../communication/communication_socket_base.h"
+
+class System_communication:public Singleton<System_communication>, public Communication_socket_base
+{
+
+// 子类必须把父类设定为友元函数,这样父类才能使用子类的私有构造函数。
+   friend class Singleton<System_communication>;
+private:
+ // 父类的构造函数必须保护,子类的构造函数必须私有。
+   System_communication();
+public:
+    //必须关闭拷贝构造和赋值构造,只能通过 get_instance 函数来进行操作唯一的实例。
+    System_communication(const System_communication& other) = delete;
+    System_communication& operator =(const System_communication& other) = delete;
+    ~System_communication();
+public://API functions
+	//检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的.
+	virtual Error_manager check_msg(Communication_message* p_msg);
+	//检查执行者的状态, 判断能否处理这条消息, 需要子类重载
+	virtual Error_manager check_executer(Communication_message* p_msg);
+	//处理消息, 需要子类重载
+	virtual Error_manager execute_msg(Communication_message* p_msg);
+
+	//定时封装发送消息, 一般为心跳和状态信息, 需要子类重载
+	virtual Error_manager encapsulate_send_data();
+
+public://get or set member variable
+
+    
+protected://member variable 
+
+    
+private:
+    
+};
+
+
+#endif //NNXX_TESTS_SYSTEM_COMMUNICATION_H

+ 415 - 0
system/system_executor.cpp

@@ -0,0 +1,415 @@
+//
+// Created by huli on 2020/7/2.
+//
+
+#include "system_executor.h"
+#include "../message/measure_message.pb.h"
+//#include "../laser/laser_manager.h"
+//#include "../locate/locate_manager.h"
+#include "../system/system_communication.h"
+#include "../message/dispatch_message.pb.h"
+#include "../dispatch/dispatch_manager.h"
+
+System_executor::System_executor()
+{
+
+}
+
+System_executor::~System_executor()
+{
+	system_executor_uninit();
+}
+
+//初始化
+Error_manager System_executor::system_executor_init(int threads_size)
+{
+	m_thread_pool.thread_pool_init(threads_size);
+	m_system_executor_status = SYSTEM_EXECUTOR_READY;
+	return Error_code::SUCCESS;
+}
+
+//反初始化
+Error_manager System_executor::system_executor_uninit()
+{
+	m_thread_pool.thread_pool_uninit();
+	m_system_executor_status = SYSTEM_EXECUTOR_UNKNOW;
+	return Error_code::SUCCESS;
+}
+
+//检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的.
+Error_manager System_executor::check_msg(Communication_message* p_msg)
+{
+	if ( p_msg == NULL )
+	{
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 "  POINTER IS NULL ");
+	}
+
+	//检查消息类型
+	switch ( p_msg->get_message_type() )
+	{
+		case Communication_message::Message_type::eDispatch_request_msg:
+		{
+			//检查接受人
+			if ( p_msg->get_receiver() == Communication_message::Communicator::eDispatch )
+			{
+				message::Dispatch_request_msg t_dispatch_request_msg;
+				//针对消息类型, 对消息进行二次解析
+				if (t_dispatch_request_msg.ParseFromString(p_msg->get_message_buf()))
+				{
+					int t_dispatch_id = Dispatch_manager::get_instance_references().get_dispatch_id();
+					//检查终端id
+					if ( t_dispatch_request_msg.terminal_id() == t_dispatch_id*2+0 || t_dispatch_request_msg.terminal_id() == t_dispatch_id*2+1)
+					{
+						return Error_code::SUCCESS;
+					}
+				}
+			}
+			break;
+		}
+		default :
+			;
+			break;
+	}
+
+
+	//无效的消息,
+	return Error_manager(Error_code::INVALID_MESSAGE, Error_level::NEGLIGIBLE_ERROR,
+						 " INVALID_MESSAGE error ");
+}
+//检查执行者的状态, 判断能否处理这条消息,
+Error_manager System_executor::check_executer(Communication_message* p_msg)
+{
+	if ( p_msg == NULL )
+	{
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 "  POINTER IS NULL ");
+	}
+
+	Error_manager t_error;
+	//通过 p_msg->get_message_type() 和 p_msg->get_receiver() 找到处理模块的实例对象, 查询执行人是否可以处理这条消息
+	switch ( p_msg->get_message_type() )
+	{
+
+		case Communication_message::Message_type::eDispatch_request_msg:
+		{
+			Error_manager t_dispatch_result = Dispatch_manager::get_instance_references().check_status();
+			Error_manager t_executor_result = System_executor::get_instance_references().check_status();
+			if (t_dispatch_result == SUCCESS
+				&& t_executor_result == SUCCESS)
+			{
+				return Error_code::SUCCESS;
+			}
+			else
+			{
+				//整合所有的错误码
+				t_error.compare_and_cover_error(t_dispatch_result);
+				t_error.compare_and_cover_error(t_executor_result);
+				if (t_error.get_error_level() == NEGLIGIBLE_ERROR)//一级故障,轻微故障,
+				{
+					std::cout << "executer_is_busy , " << std::endl;
+					//返回繁忙之后, 通信模块1秒后再次调用check
+					return Error_code::COMMUNICATION_EXCUTER_IS_BUSY;
+				}
+				else//返回二级故障,可以封装一条答复信息, 返回错误码
+				{
+					message::Dispatch_request_msg t_dispatch_request_msg;
+					//针对消息类型, 对消息进行二次解析
+					if (t_dispatch_request_msg.ParseFromString(p_msg->get_message_buf()))
+					{
+						//创建一条答复消息
+						message::Dispatch_response_msg t_dispatch_response_msg;
+						t_dispatch_response_msg.mutable_base_info()->set_msg_type(message::Message_type::eDispatch_response_msg);
+						t_dispatch_response_msg.mutable_base_info()->set_timeout_ms(5000);
+						t_dispatch_response_msg.mutable_base_info()->set_sender(message::Communicator::eDispatch);
+						t_dispatch_response_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+
+						t_dispatch_response_msg.set_command_key(t_dispatch_request_msg.command_key());
+						t_dispatch_response_msg.mutable_error_manager()->set_error_code(t_error.get_error_code());
+						t_dispatch_response_msg.mutable_error_manager()->set_error_level((message::Error_level)t_error.get_error_level());
+						t_dispatch_response_msg.mutable_error_manager()->set_error_description(t_error.get_error_description());
+
+						std::string t_msg = t_dispatch_response_msg.SerializeAsString();
+						System_communication::get_instance_references().encapsulate_msg(t_msg);
+						LOG(INFO) << " System_executor::check_executer executer status error "<< this;
+						return t_error;
+					}
+					else
+					{
+						LOG(INFO) << " System_executor::check_executer Second analysis ERROR "<< this;
+						return Error_manager(Error_code::SYSTEM_EXECUTOR_PARSE_ERROR, Error_level::MINOR_ERROR,
+											 " message::Measure_request_msg  ParseFromString error ");
+					}
+				}
+			}
+			break;
+		}
+		default :
+			;
+			break;
+	}
+
+
+	return t_error;
+}
+
+
+//处理消息的执行函数
+Error_manager System_executor::execute_msg(Communication_message* p_msg)
+{
+	if ( p_msg == NULL )
+	{
+		return Error_manager(Error_code::POINTER_IS_NULL, Error_level::MINOR_ERROR,
+							 "  POINTER IS NULL ");
+	}
+	switch ( p_msg->get_message_type() )
+	{
+		case Communication_message::Message_type::eLocate_request_msg:
+		{
+			message::Measure_request_msg t_measure_request_msg;
+			//针对消息类型, 对消息进行二次解析
+			if (t_measure_request_msg.ParseFromString(p_msg->get_message_buf()))
+			{
+				//往线程池添加执行任务, 之后会唤醒一个线程去执行他.
+				m_thread_pool.enqueue(&System_executor::execute_for_measure, this,
+									  t_measure_request_msg.command_key(), t_measure_request_msg.terminal_id());
+			}
+			else
+			{
+				return Error_manager(Error_code::SYSTEM_EXECUTOR_PARSE_ERROR, Error_level::MINOR_ERROR,
+									 " message::Measure_request_msg  ParseFromString error ");
+			}
+			break;
+		}
+		case Communication_message::Message_type::eDispatch_request_msg:
+		{
+			message::Dispatch_request_msg t_dispatch_request_msg;
+			//针对消息类型, 对消息进行二次解析
+			if (t_dispatch_request_msg.ParseFromString(p_msg->get_message_buf()))
+			{
+				Locate_information t_locate_information;
+
+				if ( t_dispatch_request_msg.dispatch_motion_direction() == message::Dispatch_motion_direction::E_STORE_CAR
+				&& t_dispatch_request_msg.has_locate_information())
+				{
+					t_locate_information.locate_x = t_dispatch_request_msg.locate_information().locate_x();
+					t_locate_information.locate_y = t_dispatch_request_msg.locate_information().locate_y();
+					t_locate_information.locate_angle = t_dispatch_request_msg.locate_information().locate_angle();
+					t_locate_information.locate_length = t_dispatch_request_msg.locate_information().locate_length();
+					t_locate_information.locate_width = t_dispatch_request_msg.locate_information().locate_width();
+					t_locate_information.locate_height = t_dispatch_request_msg.locate_information().locate_height();
+					t_locate_information.locate_wheel_base = t_dispatch_request_msg.locate_information().locate_wheel_base();
+					t_locate_information.locate_wheel_width = t_dispatch_request_msg.locate_information().locate_wheel_width();
+					t_locate_information.locate_correct = t_dispatch_request_msg.locate_information().locate_correct();
+				}
+				//往线程池添加执行任务, 之后会唤醒一个线程去执行他.
+				m_thread_pool.enqueue(&System_executor::execute_for_dispatch, this,
+									  t_dispatch_request_msg.command_key(),
+									  (Dispatch_manager::Dispatch_motion_direction)t_dispatch_request_msg.dispatch_motion_direction(),
+									  t_dispatch_request_msg.terminal_id(),
+									  t_dispatch_request_msg.parkspace_info().parkspace_id(),
+									  &t_locate_information		);
+			}
+			else
+			{
+				return Error_manager(Error_code::SYSTEM_EXECUTOR_PARSE_ERROR, Error_level::MINOR_ERROR,
+									 " message::Dispatch_request_msg  ParseFromString error ");
+			}
+			break;
+		}
+		default:
+			break;
+	}
+
+
+	return Error_code::SUCCESS;
+}
+
+//检查状态
+Error_manager System_executor::check_status()
+{
+	if ( m_system_executor_status == SYSTEM_EXECUTOR_READY )
+	{
+		if ( m_thread_pool.thread_is_full_load() == false )
+		{
+		    return Error_code::SUCCESS;
+		}
+		else
+		{
+		    return Error_manager(Error_code::SYSTEM_EXECUTOR_STATUS_BUSY, Error_level::NEGLIGIBLE_ERROR,
+		    					" System_executor::check_status error ");
+		}
+	}
+	else
+	{
+		return Error_manager(Error_code::SYSTEM_EXECUTOR_STATUS_ERROR, Error_level::MINOR_ERROR,
+							" System_executor::check_status error ");
+	}
+}
+
+//定时发送状态信息
+Error_manager System_executor::encapsulate_send_status()
+{
+	Error_manager t_error;
+
+	int t_dispatch_id = Dispatch_manager::get_instance_references().get_dispatch_id();
+	std::string t_msg;
+/*
+	//创建一条 调度管理总管理的状态
+	message::Dispatch_manager_status_msg t_dispatch_manager_status_msg;
+	t_dispatch_manager_status_msg.mutable_base_info()->set_msg_type(message::Message_type::eDispatch_manager_status_msg);
+	t_dispatch_manager_status_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_dispatch_manager_status_msg.mutable_base_info()->set_sender(message::Communicator::eDispatch);
+	t_dispatch_manager_status_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+
+	t_dispatch_manager_status_msg.set_dispatch_id(t_dispatch_id);
+
+	Dispatch_manager::Dispatch_manager_status t_dispatch_manager_status = Dispatch_manager::get_instance_references().get_dispatch_manager_status();
+	t_dispatch_manager_status_msg.set_dispatch_manager_status((message::Dispatch_manager_status)t_dispatch_manager_status);
+
+	t_msg = t_dispatch_manager_status_msg.SerializeAsString();
+	System_communication::get_instance_references().encapsulate_msg(t_msg);
+*/
+
+
+	//创建4条 调度模块终端出入口的状态
+	message::Dispatch_terminal_status_msg t_dispatch_terminal_status_msg;
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_msg_type(message::Message_type::eDispatch_status_msg);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_sender(message::Communicator::eDispatch);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+	t_dispatch_terminal_status_msg.set_terminal_id(t_dispatch_id*2+0);
+	t_dispatch_terminal_status_msg.set_terminal_status(message::Terminal_status::E_TERMINAL_READY);
+	t_dispatch_terminal_status_msg.set_passageway_direction(message::Passageway_direction::E_INLET);
+	t_msg = t_dispatch_terminal_status_msg.SerializeAsString();
+	System_communication::get_instance_references().encapsulate_msg(t_msg);
+
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_msg_type(message::Message_type::eDispatch_status_msg);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_sender(message::Communicator::eDispatch);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+	t_dispatch_terminal_status_msg.set_terminal_id(t_dispatch_id*2+0);
+	t_dispatch_terminal_status_msg.set_terminal_status(message::Terminal_status::E_TERMINAL_READY);
+	t_dispatch_terminal_status_msg.set_passageway_direction(message::Passageway_direction::E_OUTLET);
+	t_msg = t_dispatch_terminal_status_msg.SerializeAsString();
+	System_communication::get_instance_references().encapsulate_msg(t_msg);
+
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_msg_type(message::Message_type::eDispatch_status_msg);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_sender(message::Communicator::eDispatch);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+	t_dispatch_terminal_status_msg.set_terminal_id(t_dispatch_id*2+1);
+	t_dispatch_terminal_status_msg.set_terminal_status(message::Terminal_status::E_TERMINAL_READY);
+	t_dispatch_terminal_status_msg.set_passageway_direction(message::Passageway_direction::E_INLET);
+	t_msg = t_dispatch_terminal_status_msg.SerializeAsString();
+	System_communication::get_instance_references().encapsulate_msg(t_msg);
+
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_msg_type(message::Message_type::eDispatch_status_msg);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_sender(message::Communicator::eDispatch);
+	t_dispatch_terminal_status_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+	t_dispatch_terminal_status_msg.set_terminal_id(t_dispatch_id*2+1);
+	t_dispatch_terminal_status_msg.set_terminal_status(message::Terminal_status::E_TERMINAL_READY);
+	t_dispatch_terminal_status_msg.set_passageway_direction(message::Passageway_direction::E_OUTLET);
+	t_msg = t_dispatch_terminal_status_msg.SerializeAsString();
+	System_communication::get_instance_references().encapsulate_msg(t_msg);
+	return Error_code::SUCCESS;
+}
+
+//判断是否为待机,如果已经准备好,则可以执行任务。
+bool System_executor::is_ready()
+{
+	if ( m_system_executor_status == SYSTEM_EXECUTOR_READY && m_thread_pool.thread_is_full_load() == false )
+	{
+	    return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+System_executor::System_executor_status System_executor::get_system_executor_status()
+{
+	return m_system_executor_status;
+}
+
+
+
+
+//雷达感测定位 的处理函数
+//input::command_id, 消息指令id, 由主控制系统生成的唯一码
+//input::command_id, 终端id, 对应具体的某个车位
+//return::void, 没有返回, 执行结果直接生成一条答复消息, 然后通过通信返回
+void System_executor::execute_for_measure(std::string command_key, int terminal_id)
+{
+	Error_manager t_error;
+
+	LOG(INFO) << " System_executor::execute_for_measure run "<< this;
+	//这里要处理.......以后再写
+
+	//创建一条答复消息
+	message::Measure_response_msg t_measure_response_msg;
+	t_measure_response_msg.mutable_base_info()->set_msg_type(message::Message_type::eLocate_response_msg);
+	t_measure_response_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_measure_response_msg.mutable_base_info()->set_sender(message::Communicator::eMeasurer);
+	t_measure_response_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+
+	t_measure_response_msg.set_command_key(command_key);
+	t_measure_response_msg.set_terminal_id(terminal_id);
+	t_measure_response_msg.mutable_error_manager()->set_error_code(t_error.get_error_code());
+	t_measure_response_msg.mutable_error_manager()->set_error_level((message::Error_level)t_error.get_error_level());
+	t_measure_response_msg.mutable_error_manager()->set_error_description(t_error.get_error_description(), t_error.get_description_length());
+
+	t_measure_response_msg.mutable_locate_information()->set_locate_x(0);
+	t_measure_response_msg.mutable_locate_information()->set_locate_y(0);
+	t_measure_response_msg.mutable_locate_information()->set_locate_angle(0);
+	t_measure_response_msg.mutable_locate_information()->set_locate_length(0);
+	t_measure_response_msg.mutable_locate_information()->set_locate_width(0);
+	t_measure_response_msg.mutable_locate_information()->set_locate_height(0);
+	t_measure_response_msg.mutable_locate_information()->set_locate_wheel_base(0);
+	t_measure_response_msg.mutable_locate_information()->set_locate_wheel_width(0);
+	t_measure_response_msg.mutable_locate_information()->set_locate_correct(0);
+
+	std::string t_msg = t_measure_response_msg.SerializeAsString();
+	System_communication::get_instance_references().encapsulate_msg(t_msg);
+	LOG(INFO) << " System_executor::execute_for_measure end "<< this;
+
+	return ;
+}
+
+
+//调度模块的处理函数
+void System_executor::execute_for_dispatch(std::string command_key, Dispatch_manager::Dispatch_motion_direction dispatch_motion_direction,
+										   int terminal_id, int parkspace_id, Locate_information * p_locate_information)
+{
+	Error_manager t_error;
+
+	LOG(INFO) << " System_executor::execute_for_dispatch run "<< this;
+	//这里要处理.......以后再写
+
+	t_error = Dispatch_manager::get_instance_references().execute_task(dispatch_motion_direction);
+
+	//创建一条答复消息
+	message::Dispatch_response_msg t_dispatch_response_msg;
+	t_dispatch_response_msg.mutable_base_info()->set_msg_type(message::Message_type::eDispatch_response_msg);
+	t_dispatch_response_msg.mutable_base_info()->set_timeout_ms(5000);
+	t_dispatch_response_msg.mutable_base_info()->set_sender(message::Communicator::eDispatch);
+	t_dispatch_response_msg.mutable_base_info()->set_receiver(message::Communicator::eMain);
+
+	t_dispatch_response_msg.set_command_key(command_key);
+	t_dispatch_response_msg.mutable_error_manager()->set_error_code(t_error.get_error_code());
+	t_dispatch_response_msg.mutable_error_manager()->set_error_level((message::Error_level)t_error.get_error_level());
+	t_dispatch_response_msg.mutable_error_manager()->set_error_description(t_error.get_error_description(), t_error.get_description_length());
+
+	std::string t_msg = t_dispatch_response_msg.SerializeAsString();
+	System_communication::get_instance_references().encapsulate_msg(t_msg);
+
+	std::cout << "huli test dispatch_motion_direction = " << dispatch_motion_direction << std::endl;
+	std::cout << "huli test error = " << t_error << std::endl;
+
+
+	LOG(INFO) << " System_executor::execute_for_dispatch end "<< this;
+	return ;
+
+}

+ 85 - 0
system/system_executor.h

@@ -0,0 +1,85 @@
+//
+// Created by huli on 2020/7/2.
+//
+
+#ifndef NNXX_TESTS_SYSTEM_EXECUTOR_H
+#define NNXX_TESTS_SYSTEM_EXECUTOR_H
+
+#include "../tool/thread_pool.h"
+#include "../tool/singleton.h"
+#include "../error_code/error_code.h"
+#include "../communication/communication_message.h"
+#include "../dispatch/dispatch_manager.h"
+//#include "../locate/locate_manager.h"
+//#include "../locate/locate_manager_task.h"
+
+class System_executor:public Singleton<System_executor>
+{
+// 子类必须把父类设定为友元函数,这样父类才能使用子类的私有构造函数。
+   friend class Singleton<System_executor>;
+
+public:
+	//系统执行者的状态
+	enum System_executor_status
+	{//default SYSTEM_EXECUTOR_UNKNOW = 0
+	    SYSTEM_EXECUTOR_UNKNOW				= 0,    //
+		SYSTEM_EXECUTOR_READY				= 1,    //
+
+		SYSTEM_EXECUTOR_FAULT				= 10,    //
+
+	};
+   
+private:
+ // 父类的构造函数必须保护,子类的构造函数必须私有。
+   System_executor();
+public:
+    //必须关闭拷贝构造和赋值构造,只能通过 get_instance 函数来进行操作唯一的实例。
+    System_executor(const System_executor& other) = delete;
+    System_executor& operator =(const System_executor& other) = delete;
+    ~System_executor();
+public://API functions
+	//初始化
+	Error_manager system_executor_init(int threads_size);
+	//反初始化
+	Error_manager system_executor_uninit();
+
+	//检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的.
+	Error_manager check_msg(Communication_message* p_msg);
+	//检查执行者的状态, 判断能否处理这条消息,
+	Error_manager check_executer(Communication_message* p_msg);
+	//处理消息的执行函数
+	Error_manager execute_msg(Communication_message* p_msg);
+
+	//检查状态
+	Error_manager check_status();
+
+	//定时发送状态信息
+	Error_manager encapsulate_send_status();
+
+	//判断是否为待机,如果已经准备好,则可以执行任务。
+	bool is_ready();
+public://get or set member variable
+	System_executor_status get_system_executor_status();
+public:
+	//雷达感测定位 的处理函数
+//input::command_id, 消息指令id, 由主控制系统生成的唯一码
+//input::command_id, 终端id, 对应具体的某个车位
+//return::void, 没有返回, 执行结果直接生成一条答复消息, 然后通过通信返回
+	void execute_for_measure(std::string command_key, int terminal_id);
+
+	//调度模块的处理函数
+	void execute_for_dispatch(std::string command_key, Dispatch_manager::Dispatch_motion_direction dispatch_motion_direction,
+							  int terminal_id, int parkspace_id, Locate_information * p_locate_information);
+
+protected://member variable
+
+	System_executor_status		m_system_executor_status;		//系统执行者的状态
+	
+	Thread_pool 				m_thread_pool;					//执行多任务的线程池
+
+private:
+
+};
+
+
+#endif //NNXX_TESTS_SYSTEM_EXECUTOR_H

+ 161 - 0
task/task_base.cpp

@@ -0,0 +1,161 @@
+//
+// Created by zx on 2019/12/28.
+//
+
+#include "task_base.h"
+#include "../error_code/error_code.h"
+
+Task_Base::Task_Base()
+{
+	static unsigned int t_task_id = 0;
+	m_task_id = t_task_id;
+	t_task_id++;
+
+    m_task_type = UNKNOW_TASK;
+	m_task_statu = TASK_CREATED;
+	mp_tast_receiver = NULL;
+
+	m_task_start_time = std::chrono::system_clock::now();	//获取当前时间
+	m_task_over_time = std::chrono::milliseconds(TASK_OVER_TIME_DEFAULT); //默认10秒
+}
+Task_Base::~Task_Base()
+{
+	mp_tast_receiver = NULL;
+}
+
+//初始化任务单,必须初始化之后才可以使用,
+//    input:task_statu 任务状态
+//    input:task_statu_information 状态说明
+//    input:tast_receiver 接受对象
+//    input:task_over_time 超时时间
+Error_manager Task_Base::task_init(Task_statu task_statu,
+				   std::string task_statu_information,
+				   void* p_tast_receiver,
+				   std::chrono::milliseconds task_over_time)
+{
+	m_task_statu = task_statu;
+	m_task_statu_information = task_statu_information;
+	mp_tast_receiver = p_tast_receiver;
+	m_task_over_time = task_over_time;
+	m_task_error_manager.error_manager_clear_all();
+	return Error_code::SUCCESS;
+}
+
+//更新任务单
+//task_statu: 任务状态
+//statu_information:状态说明
+Error_manager Task_Base::update_statu(Task_statu task_statu,std::string statu_information)
+{
+    m_task_statu=task_statu;
+    m_task_statu_information=statu_information;
+    return SUCCESS;
+}
+
+//判断是否超时。返回true表示任务超时,返回false表示任务没有超时
+bool Task_Base::is_over_time()
+{
+	return (std::chrono::system_clock::now() - m_task_start_time) > m_task_over_time;
+}
+
+//判断是否结束, TASK_OVER  TASK_ERROR TASK_DEAD 都算结束
+bool Task_Base::is_task_end()
+{
+	if(m_task_statu == TASK_OVER || m_task_statu == TASK_ERROR || m_task_statu == TASK_DEAD)
+	{
+		return true;
+	}
+	else
+	{
+	    return false;
+	}
+}
+
+
+
+
+//获取 任务单id
+unsigned int  Task_Base::get_task_id()
+{
+	return m_task_id;
+}
+
+//获取任务类型
+Task_type Task_Base::get_task_type()
+{
+    return m_task_type;
+}
+//获取任务单状态
+Task_statu  Task_Base::get_task_statu()
+{
+    return m_task_statu;
+}
+//设置 任务单状态
+void  Task_Base::set_task_statu(Task_statu task_statu)
+{
+	m_task_statu = task_statu;
+}
+//获取状态说明
+std::string Task_Base::get_task_statu_information()
+{
+    return m_task_statu_information;
+}
+//设置 状态说明
+void Task_Base::set_task_statu_information(std::string task_statu_information)
+{
+	m_task_statu_information = 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;
+}
+//比较覆盖错误码
+void Task_Base::compare_and_cover_task_error_manager(Error_manager & error_manager)
+{
+	m_task_error_manager.compare_and_cover_error(error_manager);
+}
+
+
+
+
+
+//获取任务接收方
+void * Task_Base::get_tast_receiver()
+{
+	return mp_tast_receiver;
+}
+//设置任务接收方
+void Task_Base::set_tast_receiver(void * p_tast_receiver)
+{
+	mp_tast_receiver = p_tast_receiver;
+}
+
+
+//获取 任务创建的时间点
+std::chrono::system_clock::time_point Task_Base::get_task_start_time()
+{
+	return m_task_start_time;
+}
+//设置 任务创建的时间点
+void Task_Base::set_task_start_time(std::chrono::system_clock::time_point task_start_time)
+{
+	m_task_start_time = task_start_time;
+}
+//获取 任务超时的时限
+std::chrono::milliseconds	Task_Base::get_task_over_time()
+{
+	return m_task_over_time;
+}
+//设置 任务超时的时限
+void	Task_Base::set_task_over_time(std::chrono::milliseconds task_over_time)
+{
+	m_task_over_time = task_over_time;
+}
+
+
+

+ 142 - 0
task/task_base.h

@@ -0,0 +1,142 @@
+/*
+ * Task_Base 是任务基类,用作不同的模块之间的通信载体。
+ *	每一个模块创建一个任务子类,从Task_Base继承。
+ *	然后任务子类自定义一些数据和读写数据的接口函数。
+ *	然后在任务接受方实现 execute_task(Task_Base* p_laser_task)
+ * */
+
+#ifndef TASK_BASE_H
+#define TASK_BASE_H
+#include <string>
+#include "../error_code/error_code.h"
+#include <chrono>
+
+//任务超时时间默认值10000ms,10秒
+#define TASK_OVER_TIME_DEFAULT				10000
+
+//任务类型
+enum Task_type
+{
+	UNKNOW_TASK             =0,				//未知任务单//初始化,默认值
+	LASER_MANGER_SCAN_TASK  =1,             //雷达管理模块的扫描任务,
+	LASER_BASE_SCAN_TASK    =2,             //单个雷达的扫描任务,
+    LOCATE_MANGER_TASK		=3,             //测量任务
+    PLC_TASK                =4,             //上传PLC任务
+
+    WANJI_MANAGER_TASK,						//万集雷达管理任务
+	WANJI_LIDAR_SCAN,						//万集雷达扫描任务
+	WANJI_LIDAR_DETECT,						//万集雷达定位任务
+
+	DISPATCH_MANAGER_TASK,					//调度管理任务
+	CARRIER_TASK,							//搬运器任务
+    
+};
+//任务状态,如果任务故障,任务状态改为TASK_OVER,然后在m_task_error_manager 补充错误码。
+enum Task_statu
+{
+    TASK_CREATED            = 0,      		//任务创建, 发送方
+
+    TASK_ISSUE				= 1, 			//任务下发, 发送方
+    TASK_SIGNED             = 2,      		//已签收, 接收方
+    TASK_WORKING            = 3,      		//处理中, 接收方
+    TASK_OVER               = 4,   			//已结束, 接收方
+    TASK_STOP				= 5, 			//任务暂停, 接收方
+
+	TASK_ERROR              = 11,			//任务错误, 接收方
+
+	TASK_CANCEL				= 21,			//任务取消, 发送方
+	TASK_DEAD               = 22,           //任务死亡, 接收方
+
+	TASK_WITHDRAW			= 31, 			//任务收回, 发送方
+	TASK_FREE				= 32, 			//任务释放, 接收方
+
+};
+
+//任务单基类
+class Task_Base
+{
+protected:
+	//不允许构造基类,只允许子类构造,(多态)
+	Task_Base();
+public:
+    ~Task_Base();
+
+	//初始化任务单,必须初始化之后才可以使用,
+	//    input:task_statu 任务状态
+	//    input:task_statu_information 状态说明
+	//    input:tast_receiver 接受对象
+	//    input:task_over_time 超时时间
+	Error_manager task_init(Task_statu task_statu,
+					   std::string task_statu_information,
+					   void* p_tast_receiver,
+					   std::chrono::milliseconds task_over_time);
+
+	//更新任务单
+    //task_statu: 任务状态
+    //statu_information:状态说明
+    Error_manager update_statu(Task_statu task_statu,std::string statu_information="");
+
+    //判断是否超时。返回true表示任务超时,返回false表示任务没有超时
+    bool is_over_time();
+
+	//判断是否结束, TASK_OVER  TASK_ERROR TASK_DEAD 都算结束
+	bool is_task_end();
+
+public:
+
+	//获取 任务单id
+	unsigned int  get_task_id();
+	//设置 任务单id
+//	void  set_task_id(unsigned int task_id) = delete;
+
+    //获取 任务类型
+    Task_type   get_task_type();
+	//设置 任务类型
+//	void   set_task_type(Task_type task_type) = delete;
+    //获取 任务单状态
+    Task_statu  get_task_statu();
+	//设置 任务单状态
+	void  set_task_statu(Task_statu task_statu);
+    //获取 状态说明
+    std::string get_task_statu_information();
+	//设置 状态说明
+	void set_task_statu_information(std::string task_statu_information);
+	//获取 错误码,返回引用。
+	Error_manager& get_task_error_manager();
+	//设置 错误码
+	void set_task_error_manager(Error_manager & error_manager);
+	//比较覆盖错误码
+	void compare_and_cover_task_error_manager(Error_manager & error_manager);
+
+	//获取任务接收方
+	void * get_tast_receiver();
+	//设置任务接收方
+	void set_tast_receiver(void * p_tast_receiver);
+	//获取 任务创建的时间点
+	std::chrono::system_clock::time_point get_task_start_time();
+	//设置 任务创建的时间点
+	void set_task_start_time(std::chrono::system_clock::time_point task_start_time);
+	//获取 任务超时的时限
+	std::chrono::milliseconds	get_task_over_time();
+	//设置 任务超时的时限
+	void	set_task_over_time(std::chrono::milliseconds task_over_time);
+
+
+protected:
+	unsigned int				m_task_id;						//任务id, 每次新建任务, 自动+1, 用于多任务的管理
+    Task_type                   m_task_type;					//任务类型,不允许中途修改
+    Task_statu                  m_task_statu;					//任务状态
+    std::string					m_task_statu_information;		//任务状态说明
+    void*						mp_tast_receiver;				//任务接收方,Task_Base并不分配和释放内存。
+    //注:mp_tast_receiver是可选的,可以为NULL。如果为NULL,则需要task_command_manager去找到接收对象。
+
+	std::chrono::system_clock::time_point 	m_task_start_time;	//任务创建的时间点
+	std::chrono::milliseconds	m_task_over_time;				//任务超时的时限
+	//注:std::chrono::system_clock::now();	//获取当前时间
+
+	//错误码,任务故障信息,任务输出
+	Error_manager               m_task_error_manager;
+};
+
+#endif //TASK_BASE_H
+

+ 80 - 0
task/task_base.puml

@@ -0,0 +1,80 @@
+@startuml
+@startuml
+skinparam classAttributeIconSize 0
+
+
+title  Task_Base 任务单基类
+
+
+
+
+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

+ 56 - 0
task/task_command_manager.cpp

@@ -0,0 +1,56 @@
+
+
+
+#include "task_command_manager.h"
+
+
+//对外的接口函数,所有的任务发送方,都必须使用该函数。
+//execute_task在内部解析了Task_Base里面的Task_type,然后转发给具体某个模块的实例对象。
+//input:p_task_base 任务单,基类的指针,指向子类的实例,(多态)
+Error_manager Task_command_manager::execute_task(Task_Base* p_task_base)
+{
+	Error_manager t_error;
+	void * tp_tast_receiver = p_task_base->get_tast_receiver();
+	switch ( p_task_base->get_task_type() )
+	{
+	    case UNKNOW_TASK:
+			t_error.error_manager_reset(Error_code::TASK_TYPE_IS_UNKNOW, Error_level::MINOR_ERROR,
+								" p_task_base->get_task_type() is  UNKNOW_TASK ");
+	        break;
+		case LASER_MANGER_SCAN_TASK:
+			break;
+		case LASER_BASE_SCAN_TASK:
+	        break;
+		case LOCATE_MANGER_TASK:
+			break;
+		case PLC_TASK:
+			break;
+		case WANJI_MANAGER_TASK:
+			break;
+	    default:
+			t_error.error_manager_reset(Error_code::TASK_TYPE_IS_UNKNOW, Error_level::MINOR_ERROR,
+										" p_task_base->get_task_type() is  UNKNOW_TASK ");
+	        break;
+	}
+
+	return t_error;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 42 - 0
task/task_command_manager.h

@@ -0,0 +1,42 @@
+/*
+ * task_command_manager 是任务单的总管理,单例模式
+ * 负责管理任务单的派送和转发
+ * 所有的任务发送方都只需要调用 task_command_manager.get_instance_references().execute_task(p_task_base)
+ * 然后task_command_manager去找到对应的接受对象,来调用该对象的接口函数。 例如Laser_base::execute_task
+ * 这样发送方和接收方不直接绑定,双方完全独立。
+ * 没有在实例里面保存对方的回调函数或者对象指针
+ *
+ * */
+
+#ifndef TASK_COMAND_MANAGER_H
+#define TASK_COMAND_MANAGER_H
+#include <string>
+#include "../error_code/error_code.h"
+#include "../task/task_base.h"
+#include "../tool/singleton.h"
+
+
+class Task_command_manager:public Singleton<Task_command_manager>
+{
+// 子类必须把父类设定为友元函数,这样父类才能使用子类的私有构造函数。
+	friend class Singleton<Task_command_manager>;
+public:
+// 必须关闭拷贝构造和赋值构造,只能通过 get_instance 函数来进行操作唯一的实例。
+	Task_command_manager(const Task_command_manager&)=delete;
+	Task_command_manager& operator =(const Task_command_manager&)= delete;
+	~Task_command_manager()=default;
+private:
+// 父类的构造函数必须保护,子类的构造函数必须私有。
+	Task_command_manager()=default;
+
+public:
+	//对外的接口函数,所有的任务发送方,都必须使用该函数。
+	//execute_task在内部解析了Task_Base里面的Task_type,然后转发给具体某个模块的实例对象。
+	//input:p_task_base 任务单,基类的指针,指向子类的实例,(多态)
+	Error_manager execute_task(Task_Base* p_task_base);
+};
+
+
+
+#endif //TASK_COMAND_MANAGER_H
+

+ 12 - 0
task/task_command_manager.puml

@@ -0,0 +1,12 @@
+@startuml
+@startuml
+skinparam classAttributeIconSize 0
+
+
+title  task_command_manager 任务单管理类
+
+
+
+
+
+@enduml

+ 341 - 0
tool/binary_buf.cpp

@@ -0,0 +1,341 @@
+
+/*
+ * 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;
+
+//	std::cout << "Binary_buf::~Binary_buf()" << std::endl;
+}
+
+
+//使用参数构造,深拷贝,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;
+	}
+}
+
+
+//使用参数构造,深拷贝,len为0时,使用strlen(buf),不存储结束符'\0'
+Binary_buf::Binary_buf(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;
+}
+
+
+
+
+

+ 91 - 0
tool/binary_buf.h

@@ -0,0 +1,91 @@
+
+/*
+ * 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
+#include <iostream>
+
+
+//雷达消息的类型
+//在通信消息的前面一部分字符串,表示这条消息的类型。
+//在解析消息的时候,先解析前面的消息类型,来判断这条消息的功用
+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);
+	//使用参数构造,深拷贝,len为0时,使用strlen(buf),不存储结束符'\0'
+	Binary_buf(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

+ 41 - 0
tool/common_data.cpp

@@ -0,0 +1,41 @@
+//
+// Created by huli on 2020/9/8.
+//
+float center_x;				//整车的中心点x值, 四轮的中心
+float center_y;				//整车的中心点y值, 四轮的中心
+float car_angle;			//整车的车身旋转角,
+float car_length;			//整车的长度, 用于规避碰撞
+float car_width;			//整车的宽度, 用于规避碰撞
+float car_height;			//整车的高度, 用于规避碰撞
+float wheel_base;			//整车的轮距, 前后轮的距离, 用于机器人或agv的抓车
+float wheel_width;			//整车的轮距, 左右轮的距离, 用于机器人或agv的抓车
+float front_theta;			//整车的前轮的旋转角
+
+bool correctness;			//整车的校准标记位
+
+#include "common_data.h"
+
+void Common_data::copy_data(Car_measure_information& car_measure_information_in, Car_wheel_information& car_wheel_information_out)
+{
+	car_wheel_information_out.center_x = car_measure_information_in.center_x;
+	car_wheel_information_out.center_y = car_measure_information_in.center_y;
+	car_wheel_information_out.car_angle = car_measure_information_in.car_angle;
+
+	car_wheel_information_out.wheel_base = car_measure_information_in.wheel_base;
+	car_wheel_information_out.wheel_width = car_measure_information_in.wheel_width;
+	car_wheel_information_out.front_theta = car_measure_information_in.front_theta;
+	car_wheel_information_out.correctness = car_measure_information_in.correctness;
+}
+void Common_data::copy_data(Car_wheel_information& car_wheel_information_in, Car_measure_information& car_measure_information_out)
+{
+	car_measure_information_out.center_x = car_wheel_information_in.center_x;
+	car_measure_information_out.center_y = car_wheel_information_in.center_y;
+	car_measure_information_out.car_angle = car_wheel_information_in.car_angle;
+	car_measure_information_out.car_length = 0;
+	car_measure_information_out.car_width = 0;
+	car_measure_information_out.car_height = 0;
+	car_measure_information_out.wheel_base = car_wheel_information_in.wheel_base;
+	car_measure_information_out.wheel_width = car_wheel_information_in.wheel_width;
+	car_measure_information_out.front_theta = car_wheel_information_in.front_theta;
+	car_measure_information_out.correctness = car_wheel_information_in.correctness;
+}

+ 57 - 0
tool/common_data.h

@@ -0,0 +1,57 @@
+//
+// Created by huli on 2020/9/8.
+//
+
+#ifndef NNXX_TESTS_COMMON_DATA_H
+#define NNXX_TESTS_COMMON_DATA_H
+
+
+class Common_data
+{
+public:
+	//万集雷达扫描周期66ms, (频率15hz), 一般设置大一些
+#define WANJI_716_SCAN_CYCLE_MS 		70
+
+
+	//整车的测量信息
+	struct Car_measure_information
+	{
+		float center_x = 0;				//整车的中心点x值, 四轮的中心
+		float center_y = 0;				//整车的中心点y值, 四轮的中心
+		float car_angle = 0;			//整车的车身旋转角,
+		float car_length = 0;			//整车的长度, 用于规避碰撞
+		float car_width = 0;			//整车的宽度, 用于规避碰撞
+		float car_height = 0;			//整车的高度, 用于规避碰撞
+		float wheel_base = 0;			//整车的轮距, 前后轮的距离, 用于机器人或agv的抓车
+		float wheel_width = 0;			//整车的轮距, 左右轮的距离, 用于机器人或agv的抓车
+		float front_theta = 0;			//整车的前轮的旋转角
+
+		bool correctness = false;			//整车的校准标记位
+
+	};
+
+	//四轮的测量信息
+	struct Car_wheel_information
+	{
+		float center_x = 0;				//整车的中心点x值, 四轮的中心
+		float center_y = 0;				//整车的中心点y值, 四轮的中心
+		float car_angle = 0;			//整车的车身旋转角,
+
+		float wheel_base = 0;			//整车的轮距, 前后轮的距离, 用于机器人或agv的抓车
+		float wheel_width = 0;			//整车的轮距, 左右轮的距离, 用于机器人或agv的抓车
+		float front_theta = 0;			//整车的前轮的旋转角
+
+		bool correctness = false;			//整车的校准标记位
+
+	};
+
+
+	static void copy_data(Car_measure_information& car_measure_information_in, Car_wheel_information& car_wheel_information_out);
+	static void copy_data(Car_wheel_information& car_wheel_information_in, Car_measure_information& car_measure_information_out);
+
+
+
+};
+
+
+#endif //NNXX_TESTS_COMMON_DATA_H

+ 94 - 0
tool/pathcreator.cpp

@@ -0,0 +1,94 @@
+#include "pathcreator.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <stdint.h>
+#include <stdio.h>
+
+PathCreator::PathCreator()
+{
+
+}
+
+PathCreator::~PathCreator()
+{
+
+}
+
+std::string PathCreator::GetCurPath()
+{
+    return m_current_path;
+}
+bool PathCreator::Mkdir(std::string dirName)
+{
+    uint32_t beginCmpPath = 0;
+    uint32_t endCmpPath = 0;
+    std::string fullPath = "";
+
+    if('/' != dirName[0])
+    {
+        fullPath = getcwd(nullptr, 0);
+        beginCmpPath = fullPath.size();
+        fullPath = fullPath + "/" + dirName;
+    }
+    else
+    {
+        //Absolute path
+        fullPath = dirName;
+        beginCmpPath = 1;
+    }
+    if (fullPath[fullPath.size() - 1] != '/')
+    {
+        fullPath += "/";
+    }
+    endCmpPath = fullPath.size();
+
+    //create dirs;
+    for(uint32_t i = beginCmpPath; i < endCmpPath ; i++ )
+    {
+        if('/' == fullPath[i])
+        {
+            std::string curPath = fullPath.substr(0, i);
+            if(access(curPath.c_str(), F_OK) != 0)
+            {
+                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;
+                }
+            }
+        }
+    }
+    m_current_path=fullPath;
+    return true;
+
+}
+
+bool PathCreator::CreateDatePath(std::string root, bool add_time)
+{
+    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);
+    }
+    return Mkdir(buf);
+}

+ 18 - 0
tool/pathcreator.h

@@ -0,0 +1,18 @@
+#ifndef PATHCREATOR_H
+#define PATHCREATOR_H
+#include <string>
+
+class PathCreator
+{
+public:
+    PathCreator();
+    ~PathCreator();
+    std::string GetCurPath();
+    bool Mkdir(std::string dir);
+    bool CreateDatePath(std::string root, bool add_time = true);
+protected:
+    std::string m_current_path;
+};
+
+
+#endif // PATHCREATOR_H

+ 0 - 0
tool/pcl_cloud_with_lock.cpp


+ 30 - 0
tool/pcl_cloud_with_lock.h

@@ -0,0 +1,30 @@
+
+
+
+#ifndef PCL_CLOUD_WITH_LOCK_H
+#define PCL_CLOUD_WITH_LOCK_H
+
+
+class Pcl_cloud_with_lock
+{
+public:
+	Pcl_cloud_with_lock();
+	Pcl_cloud_with_lock(const Pcl_cloud_with_lock& other);
+	~Pcl_cloud_with_lock();
+public://API functions
+
+public://get or set member variable
+
+
+protected://member variable
+//	//三维点云的数据保护锁,
+//	std::mutex*                     mp_task_cloud_lock;
+//	//三维点云容器的智能指针,这里不直接分配内存,
+//	pcl::PointCloud<pcl::PointXYZ>::Ptr        mp_task_point_cloud;
+
+private:
+
+};
+
+
+#endif //PCL_CLOUD_WITH_LOCK_H

+ 139 - 0
tool/point2D_tool.cpp

@@ -0,0 +1,139 @@
+//
+// Created by huli on 2020/9/1.
+//
+
+#include "point2D_tool.h"
+
+//极坐标 -> 平面坐标
+bool Point2D_tool::Polar_coordinates_to_point2D(Point2D_tool::Polar_coordinates* p_polar_coordinates, Point2D_tool::Point2D* p_point2D)
+{
+	if ( p_polar_coordinates == NULL || p_point2D == NULL)
+	{
+		return false;
+	}
+	else
+	{
+		p_point2D->x = p_polar_coordinates->distance * cos(p_polar_coordinates->angle);
+		p_point2D->y = p_polar_coordinates->distance * sin(p_polar_coordinates->angle);
+		return true;
+	}
+	return true;
+}
+//平面坐标 -> 极坐标
+bool Point2D_tool::Point2D_to_polar_coordinates(Point2D_tool::Point2D* p_point2D, Point2D_tool::Polar_coordinates* p_polar_coordinates)
+{
+	if ( p_polar_coordinates == NULL || p_point2D == NULL)
+	{
+		return false;
+	}
+	else
+	{
+		p_polar_coordinates->distance = sqrt(p_point2D->x * p_point2D->x + p_point2D->y * p_point2D->y);
+		p_polar_coordinates->angle = atan(p_point2D->y / p_point2D->x);
+		return true;
+	}
+	return true;
+}
+
+//判断极坐标点是否在限制范围
+bool Point2D_tool::limit_with_polar_coordinates_box(float distance, float angle, Point2D_tool::Polar_coordinates_box* p_polar_coordinates_box)
+{
+	if ( p_polar_coordinates_box == NULL )
+	{
+		return false;
+	}
+	else
+	{
+		if ( angle >= p_polar_coordinates_box->angle_min &&
+			 angle <= p_polar_coordinates_box->angle_max &&
+			 distance >= p_polar_coordinates_box->distance_min &&
+			 distance <= p_polar_coordinates_box->distance_max )
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+//判断平面坐标点是否在限制范围
+bool Point2D_tool::limit_with_point2D_box(float x, float y, Point2D_tool::Point2D_box* p_point2D_box)
+{
+	if ( p_point2D_box == NULL )
+	{
+		return false;
+	}
+	else
+	{
+		if ( x >= p_point2D_box->x_min &&
+			 x <= p_point2D_box->x_max &&
+			 y >= p_point2D_box->y_min &&
+			 y <= p_point2D_box->y_max )
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+//平面坐标的转换, 可以进行旋转和平移, 不能缩放
+bool Point2D_tool::transform_with_translation_rotation(float* p_x_in, float* p_y_in, float* p_x_out, float* p_y_out,
+										 Point2D_tool::Point2D_transform* p_point2D_transform)
+{
+	if ( p_x_in == NULL || p_x_in == NULL || p_x_out == NULL || p_y_out == NULL || p_point2D_transform == NULL)
+	{
+		return false;
+	}
+	else
+	{
+		*p_x_out = *p_x_in * p_point2D_transform->m00 + *p_y_in * p_point2D_transform->m01 + p_point2D_transform->m02;
+		*p_y_out = *p_x_in * p_point2D_transform->m10 + *p_y_in * p_point2D_transform->m11 + p_point2D_transform->m12;
+		return true;
+	}
+	return true;
+}
+bool Point2D_tool::transform_with_translation_rotation(pcl::PointXYZ* p_point3D_in, pcl::PointXYZ* p_point3D_out,
+												Point2D_tool::Point2D_transform* p_point2D_transform)
+{
+	if (p_point3D_in == NULL || p_point3D_out == NULL || p_point2D_transform == NULL)
+	{
+		return false;
+	}
+	else
+	{
+		p_point3D_out->x = p_point3D_in->x * p_point2D_transform->m00 + p_point3D_in->y * p_point2D_transform->m01 +
+						   p_point2D_transform->m02;
+		p_point3D_out->y = p_point3D_in->x * p_point2D_transform->m10 + p_point3D_in->y * p_point2D_transform->m11 +
+						   p_point2D_transform->m12;
+		return true;
+	}
+	return true;
+}
+bool Point2D_tool::transform_with_translation_rotation(pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_in,
+												pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_out,
+												Point2D_tool::Point2D_transform* p_point2D_transform)
+{
+	if ( p_cloud_in.get() == NULL || p_cloud_out.get() == NULL || p_point2D_transform == NULL)
+	{
+	    return false;
+	}
+	else
+	{
+		pcl::PointXYZ point;
+		for (int i = 0; i < p_cloud_in->size(); ++i)
+		{
+			point.x = p_cloud_in->points[i].x * p_point2D_transform->m00 + p_cloud_in->points[i].y * p_point2D_transform->m01 + p_point2D_transform->m02;
+			point.y = p_cloud_in->points[i].x * p_point2D_transform->m10 + p_cloud_in->points[i].y * p_point2D_transform->m11 + p_point2D_transform->m12;
+			p_cloud_out->push_back(point);
+		}
+		return true;
+	}
+	return true;
+}

+ 81 - 0
tool/point2D_tool.h

@@ -0,0 +1,81 @@
+//
+// Created by huli on 2020/9/1.
+//
+
+#ifndef NNXX_TESTS_POINT2D_H
+#define NNXX_TESTS_POINT2D_H
+
+#include <pcl/point_types.h>
+#include <pcl/PCLPointCloud2.h>
+#include <pcl/conversions.h>
+#include <pcl/common/common.h>
+
+class Point2D_tool
+{
+public:
+	//极坐标
+	struct Polar_coordinates
+	{
+		float angle=0;				//弧度
+		float distance=0;				//距离
+	};
+
+	//极坐标的限定范围
+	struct Polar_coordinates_box
+	{
+		float angle_min=0;			//角度最小值
+		float angle_max=0;			//角度最大值
+		float distance_min=0;			//距离最小值
+		float distance_max=0;			//距离最大值
+	};
+
+	//平面坐标
+	struct Point2D
+	{
+		float x=0;				//x轴
+		float y=0;				//y轴
+	};
+
+	//平面坐标的限定范围
+	struct Point2D_box
+	{
+		float x_min=0;				//x轴最小值
+		float x_max=0;				//x轴最大值
+		float y_min=0;				//y轴最小值
+		float y_max=0;				//y轴最大值
+	};
+
+	//平面坐标的转换矩阵, 可以进行旋转和平移, 不能缩放
+	struct Point2D_transform
+	{
+		float m00=1;
+		float m01=0;
+		float m02=0;
+		float m10=0;
+		float m11=1;
+		float m12=0;
+	};
+
+	//极坐标 -> 平面坐标
+	static bool Polar_coordinates_to_point2D(Point2D_tool::Polar_coordinates* p_polar_coordinates, Point2D_tool::Point2D* p_point2D);
+	//平面坐标 -> 极坐标
+	static bool Point2D_to_polar_coordinates(Point2D_tool::Point2D* p_point2D, Point2D_tool::Polar_coordinates* p_polar_coordinates);
+
+
+	//判断极坐标点是否在限制范围
+	static bool limit_with_polar_coordinates_box(float distance, float angle, Point2D_tool::Polar_coordinates_box* p_polar_coordinates_box);
+	//判断平面坐标点是否在限制范围
+	static bool limit_with_point2D_box(float x, float y, Point2D_tool::Point2D_box* p_point2D_box);
+
+	//平面坐标的转换, 可以进行旋转和平移, 不能缩放
+	static bool transform_with_translation_rotation(float* p_x_in, float* p_y_in, float* p_x_out, float* p_y_out,
+													Point2D_tool::Point2D_transform* p_point2D_transform);
+	static bool transform_with_translation_rotation(pcl::PointXYZ* p_point3D_in, pcl::PointXYZ* p_point3D_out,
+													Point2D_tool::Point2D_transform* p_point2D_transform);
+	static bool transform_with_translation_rotation(pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_in,
+													pcl::PointCloud<pcl::PointXYZ>::Ptr p_cloud_out,
+													Point2D_tool::Point2D_transform* p_point2D_transform);
+};
+
+
+#endif //NNXX_TESTS_POINT2D_H

+ 42 - 0
tool/proto_tool.cpp

@@ -0,0 +1,42 @@
+
+
+
+#include "proto_tool.h"
+#include <fcntl.h>
+#include<unistd.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+using google::protobuf::io::FileInputStream;
+using google::protobuf::io::FileOutputStream;
+using google::protobuf::io::ZeroCopyInputStream;
+using google::protobuf::io::CodedInputStream;
+using google::protobuf::io::ZeroCopyOutputStream;
+using google::protobuf::io::CodedOutputStream;
+using google::protobuf::Message;
+
+
+//读取protobuf 配置文件,转化为protobuf参数形式
+//input:	prototxt_path :prototxt文件路径
+//ouput:	parameter: protobuf参数,这里是消息基类,实际调用时传入对应的子类即可。
+bool proto_tool::read_proto_param(std::string prototxt_path, ::google::protobuf::Message& protobuf_parameter)
+{
+	int fd = open(prototxt_path.c_str(), O_RDONLY);
+	if (fd == -1) return false;
+	FileInputStream* input = new FileInputStream(fd);
+	bool success = google::protobuf::TextFormat::Parse(input, &protobuf_parameter);
+	delete input;
+	close(fd);
+	return success;
+}
+
+
+
+
+
+
+
+
+
+
+
+

+ 56 - 0
tool/proto_tool.h

@@ -0,0 +1,56 @@
+
+
+
+
+
+#ifndef __PROTO_TOOL_H
+#define __PROTO_TOOL_H
+
+#include "../tool/singleton.h"
+#include <istream>
+#include <google/protobuf/message.h>
+
+class proto_tool:public Singleton<proto_tool>
+{
+	// 子类必须把父类设定为友元函数,这样父类才能使用子类的私有构造函数。
+	friend class Singleton<proto_tool>;
+public:
+	// 必须关闭拷贝构造和赋值构造,只能通过 get_instance 函数来进行操作唯一的实例。
+	proto_tool(const proto_tool&)=delete;
+	proto_tool& operator =(const proto_tool&)= delete;
+	~proto_tool()=default;
+private:
+	// 父类的构造函数必须保护,子类的构造函数必须私有。
+	proto_tool()=default;
+
+
+public:
+	//读取protobuf 配置文件,转化为protobuf参数形式
+	//input:	prototxt_path :prototxt文件路径
+	//ouput:	parameter: protobuf参数,这里是消息基类,实际调用时传入对应的子类即可。
+	static bool read_proto_param(std::string prototxt_path, ::google::protobuf::Message& protobuf_parameter);
+};
+
+
+
+
+#endif //__PROTO_TOOL_H
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 4 - 0
tool/singleton.cpp

@@ -0,0 +1,4 @@
+
+#include "singleton.h"
+
+

+ 81 - 0
tool/singleton.h

@@ -0,0 +1,81 @@
+
+/* Singleton 是单例类的模板。
+ * https://www.cnblogs.com/sunchaothu/p/10389842.html
+ * 单例 Singleton 是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一实例;
+ * 全局只有一个实例:static 特性,同时禁止用户自己声明并定义实例(把构造函数设为 private 或者 protected)
+ * Singleton 模板类对这种方法进行了一层封装。
+ * 单例类需要从Singleton继承。
+ * 子类需要将自己作为模板参数T 传递给 Singleton<T> 模板;
+ * 同时需要将基类声明为友元,这样Singleton才能调用子类的私有构造函数。
+// 子类必须把父类设定为友元函数,这样父类才能使用子类的私有构造函数。
+// 父类的构造函数必须保护,子类的构造函数必须私有。
+// 必须关闭拷贝构造和赋值构造,只能通过 get_instance 函数来操作 唯一的实例。
+ * */
+
+#ifndef __SINGLIETON_H
+#define __SINGLIETON_H
+
+//#include <iostream>
+
+template<typename T>
+class Singleton
+{
+public:
+	//获取单例的引用
+	static T& get_instance_references()
+	{
+		static T instance;
+		return instance;
+	}
+	//获取单例的指针
+	static T* get_instance_pointer()
+	{
+		return &(get_instance_references());
+	}
+
+	virtual ~Singleton()
+	{
+//		std::cout<<"destructor called!"<<std::endl;
+	}
+
+	Singleton(const Singleton&)=delete;					//关闭拷贝构造函数
+	Singleton& operator =(const Singleton&)=delete;		//关闭赋值函数
+
+protected:
+	//构造函数需要是 protected,这样子类才能继承;
+	Singleton()
+	{
+//		std::cout<<"constructor called!"<<std::endl;
+	}
+
+};
+
+/*
+// 如下是 使用样例:
+// 子类必须把父类设定为友元函数,这样父类才能使用子类的私有构造函数。
+// 父类的构造函数必须保护,子类的构造函数必须私有。
+// 必须关闭拷贝构造和赋值构造,只能通过 get_instance 函数来进行操作唯一的实例。
+
+class DerivedSingle:public Singleton<DerivedSingle>
+{
+ // 子类必须把父类设定为友元函数,这样父类才能使用子类的私有构造函数。
+	friend class Singleton<DerivedSingle>;
+public:
+ // 必须关闭拷贝构造和赋值构造,只能通过 get_instance 函数来进行操作唯一的实例。
+	DerivedSingle(const DerivedSingle&)=delete;
+	DerivedSingle& operator =(const DerivedSingle&)= delete;
+ 	~DerivedSingle()=default;
+private:
+ // 父类的构造函数必须保护,子类的构造函数必须私有。
+	DerivedSingle()=default;
+};
+
+int main(int argc, char* argv[]){
+	DerivedSingle& instance1 = DerivedSingle::get_instance_references();
+	DerivedSingle* p_instance2 = DerivedSingle::get_instance_pointer();
+	return 0;
+}
+
+ */
+
+#endif

+ 175 - 0
tool/thread_condition.cpp

@@ -0,0 +1,175 @@
+
+
+/* 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;
+	m_working_flag = 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;
+
+	//只要前面通过了, 那就进入工作状态
+	m_working_flag = true;
+
+	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;
+
+	//只要前面通过了, 那就进入工作状态 , 超时通过也算通过
+	m_working_flag = true;
+
+	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();
+}
+
+//判断是否存活,只有活着才能继续支持子线程从功能函数,否则需要强制退出函数并结束子线程
+bool Thread_condition::is_alive()
+{
+	return !m_kill_flag;
+}
+
+
+//判断是否等待, 外部线程通过这个函数来查询this线程的工作状态,
+bool Thread_condition::is_waiting()
+{
+	return !m_working_flag;
+}
+//判断是否工作, 外部线程通过这个函数来查询this线程的工作状态,
+bool Thread_condition::is_working()
+{
+	return m_working_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;
+	}
+
+	bool result = (other->m_kill_flag || other->m_pass_ever || other->m_pass_once);
+
+	//如果不能通过等待, 那么线程状态改为等待中,
+	if ( !result )
+	{
+		other->m_working_flag = false;
+	}
+
+
+	return result;
+}
+

+ 183 - 0
tool/thread_condition.h

@@ -0,0 +1,183 @@
+
+
+/* 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();
+
+	//判断是否存活,只有活着才能继续支持子线程从功能函数,否则需要强制退出函数并结束子线程
+	bool is_alive();
+
+	//判断是否等待, 外部线程通过这个函数来查询this线程的工作状态,
+	bool is_waiting();
+	//判断是否工作, 外部线程通过这个函数来查询this线程的工作状态,
+	bool is_working();
+
+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::atomic<bool> 		m_working_flag;			//线程是否进入工作的标志位, false:表示线程进行进入wait等待, true:表示线程仍然在运行中,
+
+	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
+
+
+
+
+
+/*
+//使用样例:
+std::thread*						mp_thread_receive;    		//接受缓存的线程指针
+Thread_condition					m_condition_receive;		//接受缓存的条件变量
+
+void thread_receive()
+{
+	while (m_condition_receive.is_alive())
+	{
+		m_condition_receive.wait();
+		if ( m_condition_receive.is_alive() )
+		{
+			//do everything
+
+		}
+	}
+
+	return;
+}
+
+//main函数的主线程
+int main(int argc,char* argv[])
+{
+ 	//线程创建之后, 默认等待
+	m_condition_receive.reset(false, false, false);
+	mp_thread_receive = new std::thread(& thread_receive );
+
+
+	//唤醒所有线程, 然后线程可以一直通过wait等待, 线程进入无限制的循环工作.
+	m_condition_receive.notify_all(true);
+
+	//暂停所有线程, 然后线程还是继续工作, 直到下一次循环, 进入wait等待
+	m_condition_receive.notify_all(false);
+
+	//如果线程单次循环运行时间较长, 需要等待线程完全停止, 才能读写公共的内存,
+	if ( m_condition_receive.is_waiting() )
+	{
+	    // 读写公共的内存,
+	}
+
+	//唤醒一个线程, 然后线程循环一次, 然后下次循环进入等待
+	m_condition_receive.notify_all(false, true);
+
+
+	//杀死线程,
+	m_condition_receive.kill_all();
+
+	//在线程join结束之后, 就可以可以回收线程内存资源
+	mp_thread_receive->join();
+	delete mp_thread_receive;
+	mp_thread_receive = NULL;
+}
+*/

+ 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

+ 262 - 0
tool/thread_pool.h

@@ -0,0 +1,262 @@
+/*
+ * Thread_pool 线程池,
+ *
+ * */
+
+
+
+//例如
+// Thread_pool thread_pool(4);
+// std::future<int> x =  thread_pool.enqueue( []{return 0;} );
+// std::cout << x.get() << std::endl;
+
+//例如
+/*
+Thread_pool pool(4);
+std::vector< std::future<int> > results;
+
+for(int i = 0; i < 8; ++i) {
+results.emplace_back(
+pool.enqueue([i] {
+std::cout << "hello " << i << std::endl;
+std::this_thread::sleep_for(std::chrono::seconds(1));
+std::cout << "world " << i << std::endl;
+return i*i;
+})
+);
+}
+
+for(auto && result: results)
+std::cout << result.get() << ' ';
+std::cout << std::endl;
+return 0;
+*/
+
+#ifndef THREAD_POOL_H
+#define THREAD_POOL_H
+
+#include <vector>
+#include <queue>
+#include <memory>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <future>
+#include <functional>
+#include <stdexcept>
+
+class Thread_pool {
+public:
+	//构造函数, 会自动初始化 threads_size 数量的线程
+    Thread_pool(size_t threads_size);
+
+	//构造函数,没有初始化的,后续需要调用init才能正常使用
+	Thread_pool();
+	//初始化,初始化 threads_size 数量的线程
+	void thread_pool_init(size_t threads_size);
+
+	//反初始化
+	void thread_pool_uninit();
+
+	//往线程池添加执行任务, 之后会唤醒一个线程去执行他.
+	//input: F&& f  			函数指针(函数名)
+	//input: Args&&... args		函数的参数, 自定义
+    template<class F, class... Args>
+    auto enqueue(F&& f, Args&&... args) 
+        -> std::future<typename std::result_of<F(Args...)>::type>;
+
+
+    ~Thread_pool();
+
+	//判断线程池是否超载
+    bool thread_is_full_load();
+
+private:
+    // 线程数组
+    std::vector< std::thread > workers;
+	//每个线程的工作状态, true:线程正在执行任务,  false:线程空闲等待
+	std::vector< bool > working_flag_vector;
+    // 任务函数 队列, 里面存入的是任务函数的指针
+    std::queue< std::function<void()> > tasks;
+    
+    // 线程锁和条件变量
+    std::mutex queue_mutex;
+    std::condition_variable condition;
+
+    //终止标志位
+    bool stop;
+};
+
+//构造函数, 会自动初始化 threads_size 数量的线程
+inline Thread_pool::Thread_pool(size_t threads_size)
+    :   stop(false)
+{
+	//每个线程的工作状态
+	for(size_t i = 0;i<threads_size;++i)
+	{
+		working_flag_vector.push_back(false);
+	}
+
+	//初始化 threads_size 数量的线程
+    for(size_t i = 0;i<threads_size;++i)
+        workers.emplace_back(
+            [i,this]   //每个线程的执行的基本函数,
+            {
+                for(;;)
+                {
+                    std::function<void()> task;
+
+					{
+						std::unique_lock<std::mutex> lock(this->queue_mutex);
+						this->working_flag_vector[i] = false;//线程等待
+						this->condition.wait(lock,
+											 [this]    //线程等待的判断函数
+											 { return this->stop || !this->tasks.empty(); });
+						if (this->stop )//&& this->tasks.empty()) //这里修改了, 不需要把任务池都执行完才退出, stop之后就可以退了.
+						{
+							return;//只有在终止标志位true, 那么就退出线程执行函数
+						}
+						this->working_flag_vector[i] = true;//线程工作
+						//从 任务池 里面取出 执行函数
+						task = std::move(this->tasks.front());
+						this->tasks.pop();
+					}
+
+					//运行执行函数
+                    task();
+                }
+            }
+        );
+}
+
+
+//构造函数,没有初始化的,后续需要调用init才能正常使用
+inline Thread_pool::Thread_pool()
+:   stop(false)
+{
+
+}
+//初始化,初始化 threads_size 数量的线程
+inline void Thread_pool::thread_pool_init(size_t threads_size)
+{
+	stop = false;
+
+	//每个线程的工作状态
+	for(size_t i = 0;i<threads_size;++i)
+	{
+		working_flag_vector.push_back(false);
+	}
+
+	//初始化 threads_size 数量的线程
+	for(size_t i = 0;i<threads_size;++i)
+		workers.emplace_back(
+		[i,this]   //每个线程的执行的基本函数,
+		{
+			for(;;)
+			{
+				std::function<void()> task;
+
+				{
+					std::unique_lock<std::mutex> lock(this->queue_mutex);
+					this->working_flag_vector[i] = false;//线程等待
+					this->condition.wait(lock,
+										 [this]    //线程等待的判断函数
+										 { return this->stop || !this->tasks.empty(); });
+					if (this->stop )//&& this->tasks.empty()) //这里修改了, 不需要把任务池都执行完才退出, stop之后就可以退了.
+					{
+						return;//只有在终止标志位true, 那么就退出线程执行函数
+					}
+					this->working_flag_vector[i] = true;//线程工作
+					//从 任务池 里面取出 执行函数
+					task = std::move(this->tasks.front());
+					this->tasks.pop();
+				}
+
+				//运行执行函数
+				task();
+			}
+		}
+		);
+}
+
+//反初始化
+inline void Thread_pool::thread_pool_uninit()
+{
+	{
+		std::unique_lock<std::mutex> lock(queue_mutex);
+		stop = true;
+	}
+	condition.notify_all();
+
+	for (auto iter = workers.begin(); iter != workers.end(); )
+	{
+		iter->join();
+		iter = workers.erase(iter);
+	}
+	working_flag_vector.clear();
+}
+
+
+//往线程池添加执行任务, 之后会唤醒一个线程去执行他.
+//input: F&& f  			函数指针(函数名)
+//input: Args&&... args		函数的参数, 自定义
+//注注注注注意了:::::  res是enqueue的返回值, 由于线程异步, 使用future, 可以返回未来的一个值,
+// 在子线程执行完成之后, 将结果返回给外部主线程
+// 外部主线程 调用时, 必须使用 std::future<return_type> 格式去接受
+template<class F, class... Args>
+auto Thread_pool::enqueue(F&& f, Args&&... args) 
+    -> std::future<typename std::result_of<F(Args...)>::type>
+{
+    using return_type = typename std::result_of<F(Args...)>::type;
+
+    auto task = std::make_shared< std::packaged_task<return_type()> >(
+            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
+        );
+
+
+    std::future<return_type> res = task->get_future();
+    {
+        std::unique_lock<std::mutex> lock(queue_mutex);
+
+        // don't allow enqueueing after stopping the pool
+        if(stop)
+            throw std::runtime_error("enqueue on stopped Thread_pool");
+
+        tasks.emplace([task](){ (*task)(); });
+    }
+    condition.notify_one();
+    return res;
+}
+
+// the destructor joins all threads
+inline Thread_pool::~Thread_pool()
+{
+    {
+        std::unique_lock<std::mutex> lock(queue_mutex);
+        stop = true;
+    }
+    condition.notify_all();
+    for(std::thread &worker: workers)
+	{  worker.join();}
+
+
+}
+
+//判断线程池是否超载
+inline bool Thread_pool::thread_is_full_load()
+{
+	//只要有一个线程wait, 那么就认为没有超载,
+	std::unique_lock<std::mutex> lock(queue_mutex);
+	bool result = true;
+	for(bool t_working_flag: working_flag_vector)
+	{
+		if ( !t_working_flag )
+		{
+			result = false;
+		}
+	}
+	return result;
+}
+
+
+#endif

+ 6 - 0
tool/thread_safe_list.cpp

@@ -0,0 +1,6 @@
+
+
+
+#include "thread_safe_queue.h"
+
+

+ 350 - 0
tool/thread_safe_list.h

@@ -0,0 +1,350 @@
+
+
+/*
+ * (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_list
+ 	// 在退出状态下,所有的功能函数不可用,返回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文件,但是这样不好。
+
+
+ thread_safe_queue  就是在 Thread_safe_queue 的基础上修改的,
+
+ * */
+
+#ifndef __THREAD_SAFE_LIST_H__
+#define __THREAD_SAFE_LIST_H__
+
+#include <list>
+
+#include <atomic>
+#include <mutex>
+#include <condition_variable>
+
+
+template<class T>
+class Thread_safe_list
+{
+public:
+	Thread_safe_list();
+	Thread_safe_list(const Thread_safe_list& other);
+	~Thread_safe_list();
+
+	//(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_list();
+	//唤醒队列,恢复所有的功能函数。wait_and_pop会继续阻塞。
+	void wake_list();
+	//获取退出状态
+	bool get_termination_flag();
+	//判断是否可以直接通过wait,  m_data_list不为空或者m_termination终止时都可以通过等待。
+	bool is_pass();
+
+public:
+	std::mutex 						m_mutex;				//队列的锁
+	std::list<std::shared_ptr<T>> 	m_data_list;			//队列数据,使用智能指针shared_ptr
+	std::condition_variable 		m_data_cond;			//条件变量
+	std::atomic<bool> 				m_termination_flag;		//终止标志位
+
+private:
+
+
+};
+
+
+
+
+
+
+
+
+template<class T>
+Thread_safe_list<T>::Thread_safe_list()
+{
+	m_termination_flag = false;
+}
+template<class T>
+Thread_safe_list<T>::Thread_safe_list(const Thread_safe_list& other)
+{
+	std::unique_lock<std::mutex> lock_this(m_mutex);
+	std::unique_lock<std::mutex> lock_other(other.m_mutex);
+	m_data_list = other.data_list;
+	m_termination_flag = other.m_termination_flag;
+}
+template<class T>
+Thread_safe_list<T>::~Thread_safe_list()
+{
+	//析构时,终止队列,让线程通过等待,方便线程推出。
+	termination_list();
+}
+
+//(1)没有调用termination时,每调用一次出队一个元素,直到队列为空本方法阻塞线程。
+//(2)在调用了termination后,本方法永不阻塞,如果原本已经处于阻塞状态,解除阻塞状态。
+//(3)返回true时,value值有效。返回false时,value值无效。调用了termination且队列为空时返回false.
+
+//等待并弹出数据,成功弹出则返回true
+// 队列为空则无限等待,termination终止队列,则返回false
+template<class T>
+bool Thread_safe_list<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_list.empty()) || m_termination_flag); });
+		if (m_termination_flag)
+		{
+			return false;
+		}
+		else
+		{
+			value = std::move(*m_data_list.front());
+		
+			m_data_list.pop_front();
+			return true;
+		}
+	}
+}
+//尝试弹出数据,成功弹出则返回true
+//队列为空 或者 termination终止队列,返回false
+template<class T>
+bool Thread_safe_list<T>::try_pop(T& value)
+{
+	if ( m_termination_flag )
+	{
+		return false;
+	}
+	else
+	{
+		std::unique_lock<std::mutex> lk(m_mutex);
+		if (m_data_list.empty())
+		{
+			return false;
+		}
+		else
+		{
+			value = std::move(*m_data_list.front());
+	
+			m_data_list.pop();
+			return true;
+		}
+	}
+}
+
+
+
+//等待并弹出数据,成功弹出则返回true
+// 队列为空则无限等待,termination终止队列,则返回false
+template<class T>
+std::shared_ptr<T> Thread_safe_list<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_list.empty()) || m_termination_flag); });
+		if (m_termination_flag)
+		{
+			return NULL;
+		}
+		else
+		{
+			std::shared_ptr<T> res = m_data_list.front();
+			m_data_list.pop();
+			return res;
+		}
+	}
+}
+//尝试弹出数据,成功弹出则返回true
+//队列为空 或者 termination终止队列,返回false
+template<class T>
+std::shared_ptr<T> Thread_safe_list<T>::try_pop()
+{
+	if ( m_termination_flag )
+	{
+		return NULL;
+	}
+	else
+	{
+		std::unique_lock<std::mutex> lk(m_mutex);
+		if (m_data_list.empty())
+		{
+			return NULL;
+		}
+		else
+		{
+			std::shared_ptr<T> res = m_data_list.front();
+			m_data_list.pop();
+			return res;
+		}
+	}
+}
+//插入一项,并唤醒一个线程,
+//如果成功插入,则返回true,  失败则返回false
+//注:只能唤醒一个线程,防止多线程误判empty()
+template<class T>
+bool Thread_safe_list<T>::push(T new_value)
+{
+	if (m_termination_flag)
+	{
+		return false;
+	}
+	else
+	{
+		std::shared_ptr<T> data(std::make_shared<T>(std::move(new_value)));
+		std::unique_lock<std::mutex> lk(m_mutex);
+		m_data_list.push_back(data);
+		m_data_cond.notify_one();
+		return true;
+	}
+}
+//清除队列,只是将队列的实例抛出。T是实例内存,系统自动回收的。
+template<class T>
+bool Thread_safe_list<T>::clear()
+{
+	std::unique_lock<std::mutex> lk(m_mutex);
+	while (!m_data_list.empty())
+	{
+		m_data_list.pop_front();
+	}
+	return true;
+
+}
+
+//清除队列,抛出之后还要delete指针。T是动态内存,需要手动回收的。
+template<class T>
+bool Thread_safe_list<T>::clear_and_delete()
+{
+
+	std::unique_lock<std::mutex> lk(m_mutex);
+	while (!m_data_list.empty())
+	{
+		T res = NULL;
+		res = std::move(*m_data_list.front());
+
+		m_data_list.pop_front();
+		if(res != NULL)
+		{
+			delete(res);
+
+		}
+	}
+	return true;
+}
+
+
+
+//判空
+template<class T>
+bool Thread_safe_list<T>::empty()
+{
+	std::unique_lock<std::mutex> lk(m_mutex);
+	return m_data_list.empty();
+}
+//获取队列大小
+template<class T>
+size_t Thread_safe_list<T>::size()
+{
+	std::unique_lock<std::mutex> lk(m_mutex);
+	return m_data_list.size();
+}
+//设置队列为退出状态。并唤醒所有的线程,使其通过wait
+// 在退出状态下,所有的功能函数不可用,必须直接返回false或者null。
+// wait_and_pop不会阻塞。让其直接通过,通过后直接return,不允许做其他的。
+template<class T>
+void Thread_safe_list<T>::termination_list()
+{
+	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_list<T>::wake_list()
+{
+	std::unique_lock<std::mutex> lk(m_mutex);
+	m_termination_flag = false;
+	m_data_cond.notify_all();
+}
+//获取退出状态
+template<class T>
+bool Thread_safe_list<T>::get_termination_flag()
+{
+	return m_termination_flag;
+}
+//判断是否可以直接通过wait,  m_data_list不为空或者m_termination终止时都可以通过等待。
+template<class T>
+bool Thread_safe_list<T>::is_pass()
+{
+	return (!m_data_list.empty() || m_termination_flag);
+}
+
+
+
+
+
+
+#endif //__THREAD_SAFE_LIST_H__

+ 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"
+
+

+ 338 - 0
tool/thread_safe_queue.h

@@ -0,0 +1,338 @@
+
+
+/*
+ * (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 = std::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 = std::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>(std::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 = std::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