plc_communicator.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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_mutex.lock();
  191. plc_write_return_code = m_plc_wrapper.write_registers(offset, result_length, result_info_temp);
  192. m_plc_mutex.unlock();
  193. if(plc_write_return_code<0)
  194. continue;
  195. usleep(1000* 100);
  196. // 写入状态
  197. if(result.correctness)
  198. {
  199. result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(3);
  200. result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(1);
  201. }else
  202. {
  203. result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(4);
  204. result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(0);
  205. }
  206. m_plc_mutex.lock();
  207. plc_write_return_code = m_plc_wrapper.write_registers(offset, result_length, result_info_temp);
  208. m_plc_mutex.unlock();
  209. usleep(1000* 100);
  210. // std::cout<<" write result end "<<rc<<std::endl;
  211. }
  212. if(retry_times <=0 || plc_write_return_code != 0)
  213. return Error_manager(Error_code::PLC_WRITE_FAILED);
  214. else
  215. return Error_manager(Error_code::SUCCESS);
  216. }
  217. }
  218. /*
  219. *
  220. */
  221. void Plc_Communicator::plc_publish_message(Plc_Communicator* plc)
  222. {
  223. if(plc==0)
  224. {
  225. LOG(ERROR)<<"";
  226. }
  227. while(plc->m_plc_cond_exit.WaitFor(100)==false) {
  228. plc_message::plcMsg msg;
  229. for(int i=0;i<PLC_SIGNAL_BEGIN_OFFSET;++i)
  230. {
  231. msg.add_plc_values(0);
  232. }
  233. for (int i = 0; i < plc->m_plc_data.size(); ++i) {
  234. msg.add_plc_values(plc->m_plc_data[i]);
  235. }
  236. plc_message::plcStatus status;
  237. if (plc->mb_plc_is_connected)
  238. status = plc_message::ePLCConnected;
  239. else
  240. status = plc_message::ePLCDisconnected;
  241. msg.set_plc_status(status);
  242. MeasureTopicPublisher::GetInstance()->Publish(msg.SerializeAsString());
  243. }
  244. }
  245. // ××××××××××× 更新线程静态函数 ×××××××××××
  246. void Plc_Communicator::plc_update_thread(Plc_Communicator *plc_communicator)
  247. {
  248. if (plc_communicator == 0)
  249. return;
  250. while (!plc_communicator->m_plc_cond_exit.WaitFor(100))
  251. {
  252. // std::cout<<" thread 000 "<<std::endl;
  253. // 断线重连
  254. if (!plc_communicator->mb_plc_is_connected)
  255. {
  256. Error_manager code=plc_communicator->connect();
  257. if(code!=SUCCESS)
  258. {
  259. LOG(ERROR)<<code.to_string();
  260. }
  261. usleep(1000 * 200);
  262. }
  263. else
  264. {
  265. // std::cout<<" thread 111 "<<std::endl;
  266. // 读取所有数据,更新本地并发布消息到UI
  267. int plc_length_temp = PLC_REGION_NUM * PLC_SIGNAL_NUM_PER_REGION;
  268. uint16_t plc_data_temp[plc_length_temp];
  269. int rc = plc_communicator->m_plc_wrapper.read_registers(PLC_SIGNAL_BEGIN_OFFSET, plc_length_temp, plc_data_temp);
  270. if(rc <0)
  271. {
  272. std::cout<<"find plc disconnected while read. try to reconnect."<<std::endl;
  273. plc_communicator->mb_plc_is_connected = false;
  274. continue;
  275. }
  276. else if (rc == 0)
  277. {
  278. plc_communicator->m_plc_mutex.lock();
  279. int terminal_id_temp = 0;
  280. for (size_t i = 0; i < plc_length_temp; i++)
  281. {
  282. terminal_id_temp = i / PLC_SIGNAL_NUM_PER_REGION;
  283. plc_communicator->m_plc_data[i] = plc_data_temp[i];
  284. // 读取后检查是否存在差异, 存在则赋值。调用回调函数启动外部扫描
  285. 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)
  286. {
  287. plc_communicator->m_plc_region_status[terminal_id_temp].cmd = plc_data_temp[i];
  288. bool modified = false;
  289. // 判断指令存在
  290. // std::cout<<" thread 222 "<<std::endl;
  291. if (plc_data_temp[i] == 1)
  292. {
  293. // 判空
  294. if (plc_communicator->m_plc_callback != 0 && plc_communicator->mp_plc_owner != 0)
  295. {
  296. Error_manager ec = plc_communicator->m_plc_callback(terminal_id_temp + 1, plc_communicator->mp_plc_owner);
  297. if (ec.is_equal_error_manager(Error_manager(Error_code::SUCCESS)))
  298. {
  299. plc_communicator->m_plc_region_status[terminal_id_temp].current_status = 1;
  300. // 更新时间
  301. plc_communicator->m_plc_region_status[terminal_id_temp].last_time_point = std::chrono::steady_clock::now();
  302. modified = true;
  303. }
  304. else{
  305. LOG(ERROR)<<ec.to_string();
  306. }
  307. }
  308. }
  309. // 指令清空,暂不恢复心跳
  310. else if (plc_data_temp[i] == 0)
  311. {
  312. // int status_temp = plc_communicator->m_plc_region_status[terminal_id_temp].current_status;
  313. // if (status_temp != 254 && status_temp != 255)
  314. // {
  315. // plc_communicator->m_plc_region_status[terminal_id_temp].current_status = 255;
  316. // // 更新时间
  317. // plc_communicator->m_plc_region_status[terminal_id_temp].last_time_point = std::chrono::steady_clock::now();
  318. // modified = true;
  319. // }
  320. }
  321. // 写入plc
  322. if (modified)
  323. {
  324. int address_temp = PLC_SIGNAL_BEGIN_OFFSET + PLC_SIGNAL_NUM_PER_REGION * terminal_id_temp + PLC_LASER_STATUS_ADDR;
  325. uint16_t value_temp = plc_communicator->m_plc_region_status[terminal_id_temp].current_status;
  326. int rc = plc_communicator->m_plc_wrapper.write_registers(address_temp, 1, &value_temp);
  327. if (rc != 0)
  328. plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_WRITE_FAILED, Error_level::MINOR_ERROR, "写入状态1失败");
  329. }
  330. }
  331. }
  332. plc_communicator->m_plc_mutex.unlock();
  333. }
  334. else
  335. {
  336. plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_READ_FAILED, Error_level::MINOR_ERROR, "循环读plc失败");
  337. }
  338. // std::cout<<" thread 333 "<<std::endl;
  339. // 写入心跳或当前运行状态
  340. for (size_t i = 0; i < PLC_REGION_NUM; i++)
  341. {
  342. 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();
  343. // 判断超时且非心跳,则转回心跳
  344. bool modified = false;
  345. if (time_interval > plc_communicator->m_plc_status_update_timeout && plc_communicator->m_plc_region_status[i].current_status < 5)
  346. {
  347. plc_communicator->m_plc_region_status[i].current_status = 255;
  348. modified = true;
  349. }
  350. else
  351. {
  352. // 状态切换后写入plc
  353. switch (plc_communicator->m_plc_region_status[i].current_status)
  354. {
  355. case 254:
  356. if (time_interval > 1000)
  357. {
  358. plc_communicator->m_plc_region_status[i].current_status = 255;
  359. modified = true;
  360. }
  361. break;
  362. case 255:
  363. if (time_interval > 1000)
  364. {
  365. plc_communicator->m_plc_region_status[i].current_status = 254;
  366. modified = true;
  367. }
  368. break;
  369. case 0:
  370. plc_communicator->m_plc_region_status[i].current_status = 254;
  371. modified = true;
  372. break;
  373. case 1:
  374. if (time_interval > 1000)
  375. {
  376. plc_communicator->m_plc_region_status[i].current_status = 2;
  377. modified = true;
  378. }
  379. break;
  380. case 2:
  381. break;
  382. case 3:
  383. if (time_interval > 3000)
  384. {
  385. plc_communicator->m_plc_region_status[i].current_status = 254;
  386. modified = true;
  387. }
  388. break;
  389. case 4:
  390. if (time_interval > 8000)
  391. {
  392. plc_communicator->m_plc_region_status[i].current_status = 254;
  393. modified = true;
  394. }
  395. break;
  396. case 5:
  397. break;
  398. default:
  399. break;
  400. }
  401. }
  402. if (modified && plc_communicator->mb_plc_is_connected)
  403. {
  404. plc_communicator->m_plc_mutex.lock();
  405. // std::cout<<" thread 444 "<<std::endl;
  406. // 更新时间
  407. plc_communicator->m_plc_region_status[i].last_time_point = std::chrono::steady_clock::now();
  408. // 写入plc
  409. int address_temp = PLC_SIGNAL_BEGIN_OFFSET + PLC_SIGNAL_NUM_PER_REGION * i + PLC_LASER_STATUS_ADDR;
  410. uint16_t value_temp = plc_communicator->m_plc_region_status[i].current_status;
  411. int rc = plc_communicator->m_plc_wrapper.write_registers(address_temp, 1, &value_temp);
  412. if (rc != 0)
  413. plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_WRITE_FAILED, Error_level::MINOR_ERROR, "写入当前状态失败");
  414. plc_communicator->m_plc_mutex.unlock();
  415. // std::cout<<" thread 555 "<<std::endl;
  416. }
  417. }
  418. }
  419. usleep(1000 * PLC_SLEEP_IN_MILLISECONDS);
  420. }
  421. }