#include "plc_communicator.h" #include // ××××××××××× 构造与析构 ××××××××××× Plc_Communicator::Plc_Communicator(plc_module::plc_connection_params connection_params) : mb_plc_initialized(false), mb_plc_is_connected(false), mb_plc_is_updating(false), mp_plc_owner(0), m_plc_thread(0), m_plc_message_thread(0) { m_plc_ip_str = connection_params.ip(); m_plc_port = connection_params.port(); m_plc_slave_id = connection_params.slave_id(); m_plc_current_error = Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "初始状态正常"); m_plc_status_update_timeout = 10000; for (size_t i = 0; i < PLC_REGION_NUM; i++) { m_plc_region_status[i].last_time_point = std::chrono::steady_clock::now(); m_plc_region_status[i].current_status = 255; m_plc_region_status[i].cmd = 0; } m_plc_data.resize(PLC_REGION_NUM * PLC_SIGNAL_NUM_PER_REGION); m_plc_current_error = connect(); m_plc_cond_exit.Notify(false); m_plc_thread = new std::thread(plc_update_thread, this); m_plc_message_thread=new std::thread(plc_publish_message, this); mb_plc_initialized = true; } Plc_Communicator::~Plc_Communicator() { m_plc_cond_exit.Notify(true); if (m_plc_thread) { if (m_plc_thread->joinable()) m_plc_thread->join(); delete m_plc_thread; m_plc_thread = 0; } if (m_plc_message_thread) { if (m_plc_message_thread->joinable()) m_plc_message_thread->join(); delete m_plc_message_thread; m_plc_message_thread = 0; } disconnect(); } // ××××××××××× getters setters ××××××××××× bool Plc_Communicator::get_connection() { return mb_plc_is_connected; } Error_manager Plc_Communicator::get_error(){ if(mb_plc_is_connected){ return Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "连接正常"); }else{ return Error_manager(Error_code::PLC_CONNECTION_FAILED, Error_level::NEGLIGIBLE_ERROR, "连接失败"); } } bool Plc_Communicator::get_initialize_status() { return mb_plc_initialized; } Error_manager Plc_Communicator::set_plc_callback(Command_Callback callback, void *p_owner) { if (callback == 0 || p_owner == 0) return Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR, "回调设置参数错误"); m_plc_callback = callback; mp_plc_owner = p_owner; return Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "回调设置参数正确"); } Error_manager Plc_Communicator::set_status_update_timeout(int millisecond) { m_plc_status_update_timeout = millisecond; return Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "设置状态更新超时时间成功"); } // ××××××××××× 内部调用连接与重连 ××××××××××× Error_manager Plc_Communicator::connect() { m_plc_mutex.lock(); int rc = m_plc_wrapper.initialize(m_plc_ip_str.c_str(), m_plc_port, m_plc_slave_id); m_plc_mutex.unlock(); switch (rc) { case 0: mb_plc_is_connected = true; return Error_manager(Error_code::SUCCESS, Error_level::NORMAL, "plc连接成功"); case -1: mb_plc_is_connected = false; return Error_manager(Error_code::PLC_CONNECTION_FAILED, Error_level::MINOR_ERROR, "plc掉线"); case -2: mb_plc_is_connected = false; return Error_manager(Error_code::PLC_SLAVE_ID_ERROR, Error_level::MINOR_ERROR, "plc的从站id错误"); case -3: mb_plc_is_connected = false; return Error_manager(Error_code::PLC_IP_PORT_ERROR, Error_level::MINOR_ERROR, "plc的ip或端口设置错误"); default: mb_plc_is_connected = false; return Error_manager(Error_code::PLC_UNKNOWN_ERROR, Error_level::MINOR_ERROR, "plc连接时出现未知返回值"); } } Error_manager Plc_Communicator::disconnect() { m_plc_mutex.lock(); m_plc_wrapper.deinitialize(); mb_plc_is_connected = false; m_plc_mutex.unlock(); return Error_manager(Error_code::SUCCESS); } // ××××××××××× 外部调用执行任务单 ××××××××××× Error_manager Plc_Communicator::execute_task(Task_Base *task) { if (task == 0) return Error_manager(Error_code::PARAMETER_ERROR, Error_level::NEGLIGIBLE_ERROR, "传入空任务"); if (task->get_task_type() != Task_type::PLC_TASK) { return Error_manager(Error_code::PARAMETER_ERROR, Error_level::NEGLIGIBLE_ERROR, "传入非plc任务"); } Plc_Task *plc_task_temp = (Plc_Task *)task; plc_task_temp->update_statu(Task_statu::TASK_SIGNED, "received by plc_communicator."); struct measure_result measure_result_temp; Error_manager err = plc_task_temp->get_result(measure_result_temp); if (err.is_equal_error_manager(Error_manager(Error_code::SUCCESS))) { Error_manager write_err = write_result_to_plc(measure_result_temp); // // added by yct, 检查为何2号位测量88度,发送86.9到plc // char description[480] = {0}; // sprintf(description, "to plc, id %d center(%.1f, %.1f) size:(%.1f, %.1f) angle:%.2f", // 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); // LOG(INFO) << description; plc_task_temp->update_statu(Task_statu::TASK_OVER, "executed by plc_communicator."); return write_err; } else { return err; } } // ××××××××××× 外部调用获取数据, 终端id[1-6], -1则获取所有数据 ××××××××××× Error_manager Plc_Communicator::get_plc_data(std::vector &plc_data, int terminal_id) { std::lock_guard lck(m_plc_mutex); plc_data.clear(); if (terminal_id == -1) { plc_data.operator=(m_plc_data); } else if (terminal_id <= PLC_REGION_NUM && terminal_id * PLC_SIGNAL_NUM_PER_REGION <= m_plc_data.size()) { for (size_t i = (terminal_id - 1) * PLC_SIGNAL_NUM_PER_REGION; i < terminal_id * PLC_SIGNAL_NUM_PER_REGION; i++) { plc_data.push_back(m_plc_data[i]); } return Error_manager(Error_code::SUCCESS); } else return Error_manager(Error_code::PLC_NOT_ENOUGH_DATA_ERROR); } Error_manager Plc_Communicator::write_result_to_plc(struct measure_result result){ // std::cout<<" write result 000 "<PLC_REGION_NUM){ Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR, "写plc传入参数错误"); } // std::cout<<" write result 111 "<0 && plc_write_return_code<0) { // 更新时间 m_plc_region_status[result.terminal_id - 1].last_time_point = std::chrono::steady_clock::now(); // 写入数据 m_plc_mutex.lock(); plc_write_return_code = m_plc_wrapper.write_registers(offset, result_length, result_info_temp); m_plc_mutex.unlock(); if(plc_write_return_code<0) continue; usleep(1000* 100); // 写入状态 if(result.correctness) { result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(3); result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(1); }else { result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(4); result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(0); } m_plc_mutex.lock(); plc_write_return_code = m_plc_wrapper.write_registers(offset, result_length, result_info_temp); m_plc_mutex.unlock(); usleep(1000* 100); // std::cout<<" write result end "<m_plc_cond_exit.WaitFor(100)==false) { plc_message::plcMsg msg; for(int i=0;im_plc_data.size(); ++i) { msg.add_plc_values(plc->m_plc_data[i]); } plc_message::plcStatus status; if (plc->mb_plc_is_connected) status = plc_message::ePLCConnected; else status = plc_message::ePLCDisconnected; msg.set_plc_status(status); MeasureTopicPublisher::GetInstance()->Publish(msg.SerializeAsString()); } } // ××××××××××× 更新线程静态函数 ××××××××××× void Plc_Communicator::plc_update_thread(Plc_Communicator *plc_communicator) { if (plc_communicator == 0) return; while (!plc_communicator->m_plc_cond_exit.WaitFor(100)) { // std::cout<<" thread 000 "<mb_plc_is_connected) { Error_manager code=plc_communicator->connect(); if(code!=SUCCESS) { LOG(ERROR)<m_plc_wrapper.read_registers(PLC_SIGNAL_BEGIN_OFFSET, plc_length_temp, plc_data_temp); if(rc <0) { std::cout<<"find plc disconnected while read. try to reconnect."<mb_plc_is_connected = false; continue; } else if (rc == 0) { plc_communicator->m_plc_mutex.lock(); int terminal_id_temp = 0; for (size_t i = 0; i < plc_length_temp; i++) { terminal_id_temp = i / PLC_SIGNAL_NUM_PER_REGION; plc_communicator->m_plc_data[i] = plc_data_temp[i]; // 读取后检查是否存在差异, 存在则赋值。调用回调函数启动外部扫描 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) { plc_communicator->m_plc_region_status[terminal_id_temp].cmd = plc_data_temp[i]; bool modified = false; // 判断指令存在 // std::cout<<" thread 222 "<m_plc_callback != 0 && plc_communicator->mp_plc_owner != 0) { Error_manager ec = plc_communicator->m_plc_callback(terminal_id_temp + 1, plc_communicator->mp_plc_owner); if (ec.is_equal_error_manager(Error_manager(Error_code::SUCCESS))) { plc_communicator->m_plc_region_status[terminal_id_temp].current_status = 1; // 更新时间 plc_communicator->m_plc_region_status[terminal_id_temp].last_time_point = std::chrono::steady_clock::now(); modified = true; } else{ LOG(ERROR)<m_plc_region_status[terminal_id_temp].current_status; // if (status_temp != 254 && status_temp != 255) // { // plc_communicator->m_plc_region_status[terminal_id_temp].current_status = 255; // // 更新时间 // plc_communicator->m_plc_region_status[terminal_id_temp].last_time_point = std::chrono::steady_clock::now(); // modified = true; // } } // 写入plc if (modified) { int address_temp = PLC_SIGNAL_BEGIN_OFFSET + PLC_SIGNAL_NUM_PER_REGION * terminal_id_temp + PLC_LASER_STATUS_ADDR; uint16_t value_temp = plc_communicator->m_plc_region_status[terminal_id_temp].current_status; int rc = plc_communicator->m_plc_wrapper.write_registers(address_temp, 1, &value_temp); if (rc != 0) plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_WRITE_FAILED, Error_level::MINOR_ERROR, "写入状态1失败"); } } } plc_communicator->m_plc_mutex.unlock(); } else { plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_READ_FAILED, Error_level::MINOR_ERROR, "循环读plc失败"); } // std::cout<<" thread 333 "<(std::chrono::steady_clock::now() - plc_communicator->m_plc_region_status[i].last_time_point).count(); // 判断超时且非心跳,则转回心跳 bool modified = false; if (time_interval > plc_communicator->m_plc_status_update_timeout && plc_communicator->m_plc_region_status[i].current_status < 5) { plc_communicator->m_plc_region_status[i].current_status = 255; modified = true; } else { // 状态切换后写入plc switch (plc_communicator->m_plc_region_status[i].current_status) { case 254: if (time_interval > 1000) { plc_communicator->m_plc_region_status[i].current_status = 255; modified = true; } break; case 255: if (time_interval > 1000) { plc_communicator->m_plc_region_status[i].current_status = 254; modified = true; } break; case 0: plc_communicator->m_plc_region_status[i].current_status = 254; modified = true; break; case 1: if (time_interval > 1000) { plc_communicator->m_plc_region_status[i].current_status = 2; modified = true; } break; case 2: break; case 3: if (time_interval > 3000) { plc_communicator->m_plc_region_status[i].current_status = 254; modified = true; } break; case 4: if (time_interval > 8000) { plc_communicator->m_plc_region_status[i].current_status = 254; modified = true; } break; case 5: break; default: break; } } if (modified && plc_communicator->mb_plc_is_connected) { plc_communicator->m_plc_mutex.lock(); // std::cout<<" thread 444 "<m_plc_region_status[i].last_time_point = std::chrono::steady_clock::now(); // 写入plc int address_temp = PLC_SIGNAL_BEGIN_OFFSET + PLC_SIGNAL_NUM_PER_REGION * i + PLC_LASER_STATUS_ADDR; uint16_t value_temp = plc_communicator->m_plc_region_status[i].current_status; int rc = plc_communicator->m_plc_wrapper.write_registers(address_temp, 1, &value_temp); if (rc != 0) plc_communicator->m_plc_current_error = Error_manager(Error_code::PLC_WRITE_FAILED, Error_level::MINOR_ERROR, "写入当前状态失败"); plc_communicator->m_plc_mutex.unlock(); // std::cout<<" thread 555 "<