plc_communicator.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. struct measure_result measure_result_temp;
  122. Error_manager err = plc_task_temp->get_result(measure_result_temp);
  123. if (err.is_equal_error_manager(Error_manager(Error_code::SUCCESS)))
  124. {
  125. Error_manager write_err = write_result_to_plc(measure_result_temp);
  126. plc_task_temp->update_statu(Task_statu::TASK_OVER, "executed by plc_communicator.");
  127. return write_err;
  128. }
  129. else
  130. {
  131. return err;
  132. }
  133. }
  134. // ××××××××××× 外部调用获取数据, 终端id[1-6], -1则获取所有数据 ×××××××××××
  135. Error_manager Plc_Communicator::get_plc_data(std::vector<uint16_t> &plc_data, int terminal_id)
  136. {
  137. std::lock_guard<std::mutex> lck(m_plc_mutex);
  138. plc_data.clear();
  139. if (terminal_id == -1)
  140. {
  141. plc_data.operator=(m_plc_data);
  142. }
  143. else if (terminal_id <= PLC_REGION_NUM && terminal_id * PLC_SIGNAL_NUM_PER_REGION <= m_plc_data.size())
  144. {
  145. for (size_t i = (terminal_id - 1) * PLC_SIGNAL_NUM_PER_REGION; i < terminal_id * PLC_SIGNAL_NUM_PER_REGION; i++)
  146. {
  147. plc_data.push_back(m_plc_data[i]);
  148. }
  149. return Error_manager(Error_code::SUCCESS);
  150. }
  151. else
  152. return Error_manager(Error_code::PLC_NOT_ENOUGH_DATA_ERROR);
  153. }
  154. Error_manager Plc_Communicator::write_result_to_plc(struct measure_result result){
  155. // std::cout<<" write result 000 "<<result.terminal_id<<std::endl;
  156. if(result.terminal_id<=0 || result.terminal_id>PLC_REGION_NUM){
  157. Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR, "写plc传入参数错误");
  158. }
  159. // std::cout<<" write result 111 "<<std::endl;
  160. int offset = PLC_SIGNAL_BEGIN_OFFSET + PLC_LASER_STATUS_ADDR + (result.terminal_id-1) * PLC_SIGNAL_NUM_PER_REGION;
  161. int result_length = PLC_LASER_WHEELBASE_ADDR - PLC_LASER_STATUS_ADDR + 1;
  162. uint16_t result_info_temp[result_length];
  163. memset(result_info_temp, 0, result_length * sizeof(uint16_t));
  164. // 之后设置正确位,先将数据写入,状态写2
  165. if(result.correctness){
  166. m_plc_region_status[result.terminal_id - 1].current_status = 3;
  167. result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(2);
  168. result_info_temp[PLC_LASER_X_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.x + 0.5f);
  169. result_info_temp[PLC_LASER_Y_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.y + 0.5f);
  170. result_info_temp[PLC_LASER_ANGLE_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.angle * 100);
  171. result_info_temp[PLC_LASER_LENGTH_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.length + 0.5f);
  172. result_info_temp[PLC_LASER_WIDTH_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.width + 0.5f);
  173. result_info_temp[PLC_LASER_HEIGHT_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.height + 0.5f);
  174. result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(0);
  175. result_info_temp[PLC_LASER_WHEELBASE_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.wheel_base + 0.5f);
  176. }else{
  177. m_plc_region_status[result.terminal_id-1].current_status = 4;
  178. result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(2);
  179. result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(0);
  180. }
  181. if(!m_plc_wrapper.is_connected()){
  182. return Error_manager(Error_code::PLC_CONNECTION_FAILED);
  183. }
  184. else{
  185. // std::cout<<" write result start "<<std::endl;
  186. int retry_times = 3;
  187. int plc_write_return_code = -1;
  188. while(retry_times-->0 && plc_write_return_code<0) {
  189. // 更新时间
  190. m_plc_region_status[result.terminal_id - 1].last_time_point = std::chrono::steady_clock::now();
  191. // 写入数据
  192. m_plc_mutex.lock();
  193. plc_write_return_code = m_plc_wrapper.write_registers(offset, result_length, result_info_temp);
  194. m_plc_mutex.unlock();
  195. if(plc_write_return_code<0)
  196. continue;
  197. usleep(1000* 100);
  198. // 写入状态
  199. if(result.correctness)
  200. {
  201. result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(3);
  202. result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(1);
  203. }else
  204. {
  205. result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(4);
  206. result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(0);
  207. }
  208. m_plc_mutex.lock();
  209. plc_write_return_code = m_plc_wrapper.write_registers(offset, result_length, result_info_temp);
  210. m_plc_mutex.unlock();
  211. usleep(1000* 100);
  212. // std::cout<<" write result end "<<rc<<std::endl;
  213. }
  214. if(retry_times <=0 || plc_write_return_code != 0)
  215. return Error_manager(Error_code::PLC_WRITE_FAILED);
  216. else
  217. return Error_manager(Error_code::SUCCESS);
  218. }
  219. }
  220. /*
  221. *
  222. */
  223. void Plc_Communicator::plc_publish_message(Plc_Communicator* plc)
  224. {
  225. if(plc==0)
  226. {
  227. LOG(ERROR)<<"";
  228. }
  229. while(plc->m_plc_cond_exit.WaitFor(100)==false) {
  230. plc_message::plcMsg msg;
  231. for(int i=0;i<PLC_SIGNAL_BEGIN_OFFSET;++i)
  232. {
  233. msg.add_plc_values(0);
  234. }
  235. for (int i = 0; i < plc->m_plc_data.size(); ++i) {
  236. msg.add_plc_values(plc->m_plc_data[i]);
  237. }
  238. plc_message::plcStatus status;
  239. if (plc->mb_plc_is_connected)
  240. status = plc_message::ePLCConnected;
  241. else
  242. status = plc_message::ePLCDisconnected;
  243. msg.set_plc_status(status);
  244. MeasureTopicPublisher::GetInstance()->Publish(msg.SerializeAsString());
  245. }
  246. }
  247. // ××××××××××× 更新线程静态函数 ×××××××××××
  248. void Plc_Communicator::plc_update_thread(Plc_Communicator *plc_communicator)
  249. {
  250. if (plc_communicator == 0)
  251. return;
  252. while (!plc_communicator->m_plc_cond_exit.WaitFor(100))
  253. {
  254. // std::cout<<" thread 000 "<<std::endl;
  255. // 断线重连
  256. if (!plc_communicator->mb_plc_is_connected)
  257. {
  258. Error_manager code=plc_communicator->connect();
  259. if(code!=SUCCESS)
  260. {
  261. LOG(ERROR)<<code.to_string();
  262. }
  263. usleep(1000 * 200);
  264. }
  265. else
  266. {
  267. // std::cout<<" thread 111 "<<std::endl;
  268. // 读取所有数据,更新本地并发布消息到UI
  269. int plc_length_temp = PLC_REGION_NUM * PLC_SIGNAL_NUM_PER_REGION;
  270. uint16_t plc_data_temp[plc_length_temp];
  271. int rc = plc_communicator->m_plc_wrapper.read_registers(PLC_SIGNAL_BEGIN_OFFSET, plc_length_temp, plc_data_temp);
  272. if(rc <0)
  273. {
  274. std::cout<<"find plc disconnected while read. try to reconnect."<<std::endl;
  275. plc_communicator->mb_plc_is_connected = false;
  276. continue;
  277. }
  278. else if (rc == 0)
  279. {
  280. plc_communicator->m_plc_mutex.lock();
  281. int terminal_id_temp = 0;
  282. for (size_t i = 0; i < plc_length_temp; i++)
  283. {
  284. terminal_id_temp = i / PLC_SIGNAL_NUM_PER_REGION;
  285. plc_communicator->m_plc_data[i] = plc_data_temp[i];
  286. // 读取后检查是否存在差异, 存在则赋值。调用回调函数启动外部扫描
  287. 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)
  288. {
  289. plc_communicator->m_plc_region_status[terminal_id_temp].cmd = plc_data_temp[i];
  290. bool modified = false;
  291. // 判断指令存在
  292. // std::cout<<" thread 222 "<<std::endl;
  293. if (plc_data_temp[i] == 1)
  294. {
  295. // 判空
  296. if (plc_communicator->m_plc_callback != 0 && plc_communicator->mp_plc_owner != 0)
  297. {
  298. Error_manager ec = plc_communicator->m_plc_callback(terminal_id_temp + 1, plc_communicator->mp_plc_owner);
  299. if (ec.is_equal_error_manager(Error_manager(Error_code::SUCCESS)))
  300. {
  301. plc_communicator->m_plc_region_status[terminal_id_temp].current_status = 1;
  302. // 更新时间
  303. plc_communicator->m_plc_region_status[terminal_id_temp].last_time_point = std::chrono::steady_clock::now();
  304. modified = true;
  305. }
  306. else{
  307. LOG(ERROR)<<ec.to_string();
  308. }
  309. }
  310. }
  311. // 指令清空,暂不恢复心跳
  312. else if (plc_data_temp[i] == 0)
  313. {
  314. // int status_temp = plc_communicator->m_plc_region_status[terminal_id_temp].current_status;
  315. // if (status_temp != 254 && status_temp != 255)
  316. // {
  317. // plc_communicator->m_plc_region_status[terminal_id_temp].current_status = 255;
  318. // // 更新时间
  319. // plc_communicator->m_plc_region_status[terminal_id_temp].last_time_point = std::chrono::steady_clock::now();
  320. // modified = true;
  321. // }
  322. }
  323. // 写入plc
  324. if (modified)
  325. {
  326. int address_temp = PLC_SIGNAL_BEGIN_OFFSET + PLC_SIGNAL_NUM_PER_REGION * terminal_id_temp + PLC_LASER_STATUS_ADDR;
  327. uint16_t value_temp = plc_communicator->m_plc_region_status[terminal_id_temp].current_status;
  328. int rc = plc_communicator->m_plc_wrapper.write_registers(address_temp, 1, &value_temp);
  329. if (rc != 0)
  330. plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_WRITE_FAILED, Error_level::MINOR_ERROR, "写入状态1失败");
  331. }
  332. }
  333. }
  334. plc_communicator->m_plc_mutex.unlock();
  335. }
  336. else
  337. {
  338. plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_READ_FAILED, Error_level::MINOR_ERROR, "循环读plc失败");
  339. }
  340. // std::cout<<" thread 333 "<<std::endl;
  341. // 写入心跳或当前运行状态
  342. for (size_t i = 0; i < PLC_REGION_NUM; i++)
  343. {
  344. 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();
  345. // 判断超时且非心跳,则转回心跳
  346. bool modified = false;
  347. if (time_interval > plc_communicator->m_plc_status_update_timeout && plc_communicator->m_plc_region_status[i].current_status < 5)
  348. {
  349. plc_communicator->m_plc_region_status[i].current_status = 255;
  350. modified = true;
  351. }
  352. else
  353. {
  354. // 状态切换后写入plc
  355. switch (plc_communicator->m_plc_region_status[i].current_status)
  356. {
  357. case 254:
  358. if (time_interval > 1000)
  359. {
  360. plc_communicator->m_plc_region_status[i].current_status = 255;
  361. modified = true;
  362. }
  363. break;
  364. case 255:
  365. if (time_interval > 1000)
  366. {
  367. plc_communicator->m_plc_region_status[i].current_status = 254;
  368. modified = true;
  369. }
  370. break;
  371. case 0:
  372. plc_communicator->m_plc_region_status[i].current_status = 254;
  373. modified = true;
  374. break;
  375. case 1:
  376. if (time_interval > 1000)
  377. {
  378. plc_communicator->m_plc_region_status[i].current_status = 2;
  379. modified = true;
  380. }
  381. break;
  382. case 2:
  383. break;
  384. case 3:
  385. if (time_interval > 3000)
  386. {
  387. plc_communicator->m_plc_region_status[i].current_status = 254;
  388. modified = true;
  389. }
  390. break;
  391. case 4:
  392. if (time_interval > 8000)
  393. {
  394. plc_communicator->m_plc_region_status[i].current_status = 254;
  395. modified = true;
  396. }
  397. break;
  398. case 5:
  399. break;
  400. default:
  401. break;
  402. }
  403. }
  404. if (modified && plc_communicator->mb_plc_is_connected)
  405. {
  406. plc_communicator->m_plc_mutex.lock();
  407. // std::cout<<" thread 444 "<<std::endl;
  408. // 更新时间
  409. plc_communicator->m_plc_region_status[i].last_time_point = std::chrono::steady_clock::now();
  410. // 写入plc
  411. int address_temp = PLC_SIGNAL_BEGIN_OFFSET + PLC_SIGNAL_NUM_PER_REGION * i + PLC_LASER_STATUS_ADDR;
  412. uint16_t value_temp = plc_communicator->m_plc_region_status[i].current_status;
  413. int rc = plc_communicator->m_plc_wrapper.write_registers(address_temp, 1, &value_temp);
  414. if (rc != 0)
  415. plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_WRITE_FAILED, Error_level::MINOR_ERROR, "写入当前状态失败");
  416. plc_communicator->m_plc_mutex.unlock();
  417. // std::cout<<" thread 555 "<<std::endl;
  418. }
  419. }
  420. }
  421. usleep(1000 * PLC_SLEEP_IN_MILLISECONDS);
  422. }
  423. }