plc_communicator.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. #include "plc_communicator.h"
  2. #include <glog/logging.h>
  3. // ××××××××××× 构造与析构 ×××××××××××
  4. Plc_Communicator::Plc_Communicator(plc_module::plc_connection_params connection_params) : mb_plc_initialized(false),
  5. mb_plc_is_connected(false),
  6. mb_plc_is_updating(false),
  7. mp_plc_owner(0),
  8. m_plc_thread(0),
  9. m_plc_message_thread(0)
  10. {
  11. m_plc_ip_str = connection_params.ip();
  12. m_plc_port = connection_params.port();
  13. m_plc_slave_id = connection_params.slave_id();
  14. m_plc_current_error = Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "初始状态正常");
  15. m_plc_status_update_timeout = 10000;
  16. for (size_t i = 0; i < PLC_REGION_NUM; i++)
  17. {
  18. m_plc_region_status[i].last_time_point = std::chrono::steady_clock::now();
  19. m_plc_region_status[i].current_status = 255;
  20. m_plc_region_status[i].cmd = 0;
  21. }
  22. m_plc_data.resize(PLC_REGION_NUM * PLC_SIGNAL_NUM_PER_REGION);
  23. m_plc_current_error = connect();
  24. m_plc_cond_exit.Notify(false);
  25. m_plc_thread = new std::thread(plc_update_thread, this);
  26. m_plc_message_thread=new std::thread(plc_publish_message, this);
  27. mb_plc_initialized = true;
  28. }
  29. Plc_Communicator::~Plc_Communicator()
  30. {
  31. m_plc_cond_exit.Notify(true);
  32. if (m_plc_thread)
  33. {
  34. if (m_plc_thread->joinable())
  35. m_plc_thread->join();
  36. delete m_plc_thread;
  37. m_plc_thread = 0;
  38. }
  39. if (m_plc_message_thread)
  40. {
  41. if (m_plc_message_thread->joinable())
  42. m_plc_message_thread->join();
  43. delete m_plc_message_thread;
  44. m_plc_message_thread = 0;
  45. }
  46. disconnect();
  47. }
  48. // ××××××××××× getters setters ×××××××××××
  49. bool Plc_Communicator::get_connection()
  50. {
  51. return mb_plc_is_connected;
  52. }
  53. Error_manager Plc_Communicator::get_error(){
  54. if(mb_plc_is_connected){
  55. return Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "连接正常");
  56. }else{
  57. return Error_manager(Error_code::PLC_CONNECTION_FAILED, Error_level::NEGLIGIBLE_ERROR, "连接失败");
  58. }
  59. }
  60. bool Plc_Communicator::get_initialize_status()
  61. {
  62. return mb_plc_initialized;
  63. }
  64. Error_manager Plc_Communicator::set_plc_callback(Command_Callback callback, void *p_owner)
  65. {
  66. if (callback == 0 || p_owner == 0)
  67. return Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR, "回调设置参数错误");
  68. m_plc_callback = callback;
  69. mp_plc_owner = p_owner;
  70. return Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "回调设置参数正确");
  71. }
  72. Error_manager Plc_Communicator::set_status_update_timeout(int millisecond)
  73. {
  74. m_plc_status_update_timeout = millisecond;
  75. return Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "设置状态更新超时时间成功");
  76. }
  77. // ××××××××××× 内部调用连接与重连 ×××××××××××
  78. Error_manager Plc_Communicator::connect()
  79. {
  80. m_plc_mutex.lock();
  81. int rc = m_plc_wrapper.initialize(m_plc_ip_str.c_str(), m_plc_port, m_plc_slave_id);
  82. m_plc_mutex.unlock();
  83. switch (rc)
  84. {
  85. case 0:
  86. mb_plc_is_connected = true;
  87. return Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "plc连接成功");
  88. case -1:
  89. mb_plc_is_connected = false;
  90. return Error_manager(Error_code::PLC_CONNECTION_FAILED, Error_level::MINOR_ERROR, "plc掉线");
  91. case -2:
  92. mb_plc_is_connected = false;
  93. return Error_manager(Error_code::PLC_SLAVE_ID_ERROR, Error_level::MINOR_ERROR, "plc的从站id错误");
  94. case -3:
  95. mb_plc_is_connected = false;
  96. return Error_manager(Error_code::PLC_IP_PORT_ERROR, Error_level::MINOR_ERROR, "plc的ip或端口设置错误");
  97. default:
  98. mb_plc_is_connected = false;
  99. return Error_manager(Error_code::PLC_UNKNOWN_ERROR, Error_level::MINOR_ERROR, "plc连接时出现未知返回值");
  100. }
  101. }
  102. Error_manager Plc_Communicator::disconnect()
  103. {
  104. m_plc_mutex.lock();
  105. m_plc_wrapper.deinitialize();
  106. mb_plc_is_connected = false;
  107. m_plc_mutex.unlock();
  108. return Error_manager(Error_code::SUCCESS);
  109. }
  110. // ××××××××××× 外部调用执行任务单 ×××××××××××
  111. Error_manager Plc_Communicator::execute_task(Task_Base *task)
  112. {
  113. if (task == 0)
  114. return Error_manager(Error_code::PARAMETER_ERROR, Error_level::NEGLIGIBLE_ERROR, "传入空任务");
  115. if (task->get_task_type() != Task_type::PLC_TASK)
  116. {
  117. return Error_manager(Error_code::PARAMETER_ERROR, Error_level::NEGLIGIBLE_ERROR, "传入非plc任务");
  118. }
  119. Plc_Task *plc_task_temp = (Plc_Task *)task;
  120. plc_task_temp->update_statu(Task_statu::TASK_SIGNED, "received by plc_communicator.");
  121. std::cout << " execute task, update status " << std::endl;
  122. struct measure_result measure_result_temp;
  123. Error_manager err = plc_task_temp->get_result(measure_result_temp);
  124. std::cout << " execute task, get result " << std::endl;
  125. if (err.is_equal_error_manager(Error_manager(Error_code::SUCCESS)))
  126. {
  127. Error_manager write_err = write_result_to_plc(measure_result_temp);
  128. plc_task_temp->update_statu(Task_statu::TASK_OVER, "executed by plc_communicator.");
  129. return write_err;
  130. }
  131. else
  132. {
  133. return err;
  134. }
  135. }
  136. // ××××××××××× 外部调用获取数据, 终端id[1-6], -1则获取所有数据 ×××××××××××
  137. Error_manager Plc_Communicator::get_plc_data(std::vector<uint16_t> &plc_data, int terminal_id)
  138. {
  139. std::lock_guard<std::mutex> lck(m_plc_mutex);
  140. plc_data.clear();
  141. if (terminal_id == -1)
  142. {
  143. plc_data.operator=(m_plc_data);
  144. }
  145. else if (terminal_id <= PLC_REGION_NUM && terminal_id * PLC_SIGNAL_NUM_PER_REGION <= m_plc_data.size())
  146. {
  147. for (size_t i = (terminal_id - 1) * PLC_SIGNAL_NUM_PER_REGION; i < terminal_id * PLC_SIGNAL_NUM_PER_REGION; i++)
  148. {
  149. plc_data.push_back(m_plc_data[i]);
  150. }
  151. return Error_manager(Error_code::SUCCESS);
  152. }
  153. else
  154. return Error_manager(Error_code::PLC_NOT_ENOUGH_DATA_ERROR);
  155. }
  156. Error_manager Plc_Communicator::write_result_to_plc(struct measure_result result){
  157. // std::cout<<" write result 000 "<<result.terminal_id<<std::endl;
  158. if(result.terminal_id<=0 || result.terminal_id>PLC_REGION_NUM){
  159. Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR, "写plc传入参数错误");
  160. }
  161. // std::cout<<" write result 111 "<<std::endl;
  162. int offset = PLC_SIGNAL_BEGIN_OFFSET + PLC_LASER_STATUS_ADDR + (result.terminal_id-1) * PLC_SIGNAL_NUM_PER_REGION;
  163. int result_length = PLC_LASER_WHEELBASE_ADDR - PLC_LASER_STATUS_ADDR + 1;
  164. uint16_t result_info_temp[result_length];
  165. memset(result_info_temp, 0, result_length * sizeof(uint16_t));
  166. // std::cout<<" write result 222 "<<std::endl;
  167. if(result.correctness){
  168. m_plc_region_status[result.terminal_id - 1].current_status = 3;
  169. result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(3);
  170. result_info_temp[PLC_LASER_X_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.x + 0.5f);
  171. result_info_temp[PLC_LASER_Y_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.y + 0.5f);
  172. result_info_temp[PLC_LASER_ANGLE_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.angle * 100);
  173. result_info_temp[PLC_LASER_LENGTH_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.length + 0.5f);
  174. result_info_temp[PLC_LASER_WIDTH_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.width + 0.5f);
  175. result_info_temp[PLC_LASER_HEIGHT_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.height + 0.5f);
  176. result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(1);
  177. result_info_temp[PLC_LASER_WHEELBASE_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.wheel_base + 0.5f);
  178. }else{
  179. m_plc_region_status[result.terminal_id-1].current_status = 4;
  180. result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(4);
  181. result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(0);
  182. }
  183. if(!m_plc_wrapper.is_connected()){
  184. return Error_manager(Error_code::PLC_CONNECTION_FAILED);
  185. }
  186. else{
  187. // std::cout<<" write result start "<<std::endl;
  188. m_plc_mutex.lock();
  189. int rc = m_plc_wrapper.write_registers(offset, result_length, result_info_temp);
  190. m_plc_mutex.unlock();
  191. // std::cout<<" write result end "<<rc<<std::endl;
  192. if(rc != 0)
  193. return Error_manager(Error_code::PLC_WRITE_FAILED);
  194. else
  195. return Error_manager(Error_code::SUCCESS);
  196. }
  197. }
  198. /*
  199. *
  200. */
  201. void Plc_Communicator::plc_publish_message(Plc_Communicator* plc)
  202. {
  203. if(plc==0)
  204. {
  205. LOG(ERROR)<<"";
  206. }
  207. while(plc->m_plc_cond_exit.WaitFor(100)==false) {
  208. plc_message::plcMsg msg;
  209. for(int i=0;i<PLC_SIGNAL_BEGIN_OFFSET;++i)
  210. {
  211. msg.add_plc_values(0);
  212. }
  213. for (int i = 0; i < plc->m_plc_data.size(); ++i) {
  214. msg.add_plc_values(plc->m_plc_data[i]);
  215. }
  216. plc_message::plcStatus status;
  217. if (plc->mb_plc_is_connected)
  218. status = plc_message::ePLCConnected;
  219. else
  220. status = plc_message::ePLCDisconnected;
  221. msg.set_plc_status(status);
  222. MeasureTopicPublisher::GetInstance()->Publish(msg.SerializeAsString());
  223. }
  224. }
  225. // ××××××××××× 更新线程静态函数 ×××××××××××
  226. void Plc_Communicator::plc_update_thread(Plc_Communicator *plc_communicator)
  227. {
  228. if (plc_communicator == 0)
  229. return;
  230. while (!plc_communicator->m_plc_cond_exit.WaitFor(100))
  231. {
  232. // std::cout<<" thread 000 "<<std::endl;
  233. // 断线重连
  234. if (!plc_communicator->mb_plc_is_connected)
  235. {
  236. Error_manager code=plc_communicator->connect();
  237. if(code!=SUCCESS)
  238. {
  239. LOG(ERROR)<<code.to_string();
  240. }
  241. usleep(1000 * 200);
  242. }
  243. else
  244. {
  245. // std::cout<<" thread 111 "<<std::endl;
  246. // 读取所有数据,更新本地并发布消息到UI
  247. int plc_length_temp = PLC_REGION_NUM * PLC_SIGNAL_NUM_PER_REGION;
  248. uint16_t plc_data_temp[plc_length_temp];
  249. int rc = plc_communicator->m_plc_wrapper.read_registers(PLC_SIGNAL_BEGIN_OFFSET, plc_length_temp, plc_data_temp);
  250. if(rc <0)
  251. {
  252. std::cout<<"find plc disconnected while read. try to reconnect."<<std::endl;
  253. plc_communicator->mb_plc_is_connected = false;
  254. continue;
  255. }
  256. else if (rc == 0)
  257. {
  258. plc_communicator->m_plc_mutex.lock();
  259. int terminal_id_temp = 0;
  260. for (size_t i = 0; i < plc_length_temp; i++)
  261. {
  262. terminal_id_temp = i / PLC_SIGNAL_NUM_PER_REGION;
  263. plc_communicator->m_plc_data[i] = plc_data_temp[i];
  264. // 读取后检查是否存在差异, 存在则赋值。调用回调函数启动外部扫描
  265. if (i % PLC_SIGNAL_NUM_PER_REGION == PLC_LASER_START_ADDR && plc_data_temp[i] != plc_communicator->m_plc_region_status[terminal_id_temp].cmd)
  266. {
  267. plc_communicator->m_plc_region_status[terminal_id_temp].cmd = plc_data_temp[i];
  268. bool modified = false;
  269. // 判断指令存在
  270. // std::cout<<" thread 222 "<<std::endl;
  271. if (plc_data_temp[i] == 1)
  272. {
  273. // 判空
  274. if (plc_communicator->m_plc_callback != 0 && plc_communicator->mp_plc_owner != 0)
  275. {
  276. Error_manager ec = plc_communicator->m_plc_callback(terminal_id_temp + 1, plc_communicator->mp_plc_owner);
  277. if (ec.is_equal_error_manager(Error_manager(Error_code::SUCCESS)))
  278. {
  279. plc_communicator->m_plc_region_status[terminal_id_temp].current_status = 1;
  280. // 更新时间
  281. plc_communicator->m_plc_region_status[terminal_id_temp].last_time_point = std::chrono::steady_clock::now();
  282. modified = true;
  283. }
  284. else{
  285. LOG(ERROR)<<ec.to_string();
  286. }
  287. }
  288. }
  289. // 指令清空,暂不恢复心跳
  290. else if (plc_data_temp[i] == 0)
  291. {
  292. // int status_temp = plc_communicator->m_plc_region_status[terminal_id_temp].current_status;
  293. // if (status_temp != 254 && status_temp != 255)
  294. // {
  295. // plc_communicator->m_plc_region_status[terminal_id_temp].current_status = 255;
  296. // // 更新时间
  297. // plc_communicator->m_plc_region_status[terminal_id_temp].last_time_point = std::chrono::steady_clock::now();
  298. // modified = true;
  299. // }
  300. }
  301. // 写入plc
  302. if (modified)
  303. {
  304. int address_temp = PLC_SIGNAL_BEGIN_OFFSET + PLC_SIGNAL_NUM_PER_REGION * terminal_id_temp + PLC_LASER_STATUS_ADDR;
  305. uint16_t value_temp = plc_communicator->m_plc_region_status[terminal_id_temp].current_status;
  306. int rc = plc_communicator->m_plc_wrapper.write_registers(address_temp, 1, &value_temp);
  307. if (rc != 0)
  308. plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_WRITE_FAILED, Error_level::MINOR_ERROR, "写入状态1失败");
  309. }
  310. }
  311. }
  312. plc_communicator->m_plc_mutex.unlock();
  313. }
  314. else
  315. {
  316. plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_READ_FAILED, Error_level::MINOR_ERROR, "循环读plc失败");
  317. }
  318. // std::cout<<" thread 333 "<<std::endl;
  319. // 写入心跳或当前运行状态
  320. for (size_t i = 0; i < PLC_REGION_NUM; i++)
  321. {
  322. int time_interval = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - plc_communicator->m_plc_region_status[i].last_time_point).count();
  323. // 判断超时且非心跳,则转回心跳
  324. bool modified = false;
  325. if (time_interval > plc_communicator->m_plc_status_update_timeout && plc_communicator->m_plc_region_status[i].current_status < 5)
  326. {
  327. plc_communicator->m_plc_region_status[i].current_status = 255;
  328. modified = true;
  329. }
  330. else
  331. {
  332. // 状态切换后写入plc
  333. switch (plc_communicator->m_plc_region_status[i].current_status)
  334. {
  335. case 254:
  336. if (time_interval > 1000)
  337. {
  338. plc_communicator->m_plc_region_status[i].current_status = 255;
  339. modified = true;
  340. }
  341. break;
  342. case 255:
  343. if (time_interval > 1000)
  344. {
  345. plc_communicator->m_plc_region_status[i].current_status = 254;
  346. modified = true;
  347. }
  348. break;
  349. case 0:
  350. plc_communicator->m_plc_region_status[i].current_status = 254;
  351. modified = true;
  352. break;
  353. case 1:
  354. if (time_interval > 1000)
  355. {
  356. plc_communicator->m_plc_region_status[i].current_status = 2;
  357. modified = true;
  358. }
  359. break;
  360. case 2:
  361. break;
  362. case 3:
  363. if (time_interval > 3000)
  364. {
  365. plc_communicator->m_plc_region_status[i].current_status = 254;
  366. modified = true;
  367. }
  368. break;
  369. case 4:
  370. if (time_interval > 8000)
  371. {
  372. plc_communicator->m_plc_region_status[i].current_status = 254;
  373. modified = true;
  374. }
  375. break;
  376. case 5:
  377. break;
  378. default:
  379. break;
  380. }
  381. }
  382. if (modified && plc_communicator->mb_plc_is_connected)
  383. {
  384. plc_communicator->m_plc_mutex.lock();
  385. // std::cout<<" thread 444 "<<std::endl;
  386. // 更新时间
  387. plc_communicator->m_plc_region_status[i].last_time_point = std::chrono::steady_clock::now();
  388. // 写入plc
  389. int address_temp = PLC_SIGNAL_BEGIN_OFFSET + PLC_SIGNAL_NUM_PER_REGION * i + PLC_LASER_STATUS_ADDR;
  390. uint16_t value_temp = plc_communicator->m_plc_region_status[i].current_status;
  391. int rc = plc_communicator->m_plc_wrapper.write_registers(address_temp, 1, &value_temp);
  392. if (rc != 0)
  393. plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_WRITE_FAILED, Error_level::MINOR_ERROR, "写入当前状态失败");
  394. plc_communicator->m_plc_mutex.unlock();
  395. // std::cout<<" thread 555 "<<std::endl;
  396. }
  397. }
  398. }
  399. usleep(1000 * PLC_SLEEP_IN_MILLISECONDS);
  400. }
  401. }