plc_communicator.cpp 20 KB

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