123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- #include "plc_communicator.h"
- #include <glog/logging.h>
- // ××××××××××× 构造与析构 ×××××××××××
- 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<uint16_t> &plc_data, int terminal_id)
- {
- std::lock_guard<std::mutex> 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 "<<result.terminal_id<<std::endl;
- if(result.terminal_id<=0 || result.terminal_id>PLC_REGION_NUM){
- Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR, "写plc传入参数错误");
- }
- // std::cout<<" write result 111 "<<std::endl;
- int offset = PLC_SIGNAL_BEGIN_OFFSET + PLC_LASER_STATUS_ADDR + (result.terminal_id-1) * PLC_SIGNAL_NUM_PER_REGION;
- int result_length = PLC_LASER_WHEELBASE_ADDR - PLC_LASER_STATUS_ADDR + 1;
- uint16_t result_info_temp[result_length];
- memset(result_info_temp, 0, result_length * sizeof(uint16_t));
- // 之后设置正确位,先将数据写入,状态写2
- if(result.correctness){
- m_plc_region_status[result.terminal_id - 1].current_status = 3;
- result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(2);
- result_info_temp[PLC_LASER_X_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.x + 0.5f);
- result_info_temp[PLC_LASER_Y_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.y + 0.5f);
- result_info_temp[PLC_LASER_ANGLE_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.angle * 100);
- result_info_temp[PLC_LASER_LENGTH_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.length + 0.5f);
- result_info_temp[PLC_LASER_WIDTH_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.width + 0.5f);
- result_info_temp[PLC_LASER_HEIGHT_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.height + 0.5f);
- result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(0);
- result_info_temp[PLC_LASER_WHEELBASE_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(result.wheel_base + 0.5f);
- }else{
- m_plc_region_status[result.terminal_id-1].current_status = 4;
- result_info_temp[PLC_LASER_STATUS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(2);
- result_info_temp[PLC_LASER_CORRECTNESS_ADDR - PLC_LASER_STATUS_ADDR] = uint16_t(0);
- }
- if(!m_plc_wrapper.is_connected()){
- return Error_manager(Error_code::PLC_CONNECTION_FAILED);
- }
- else{
- // std::cout<<" write result start "<<std::endl;
- int retry_times = 3;
- int plc_write_return_code = -1;
- while(retry_times-->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 "<<rc<<std::endl;
- }
- if(retry_times <=0 || plc_write_return_code != 0)
- return Error_manager(Error_code::PLC_WRITE_FAILED);
- else
- return Error_manager(Error_code::SUCCESS);
- }
- }
- /*
- *
- */
- void Plc_Communicator::plc_publish_message(Plc_Communicator* plc)
- {
- if(plc==0)
- {
- LOG(ERROR)<<"";
- }
- while(plc->m_plc_cond_exit.WaitFor(100)==false) {
- plc_message::plcMsg msg;
- for(int i=0;i<PLC_SIGNAL_BEGIN_OFFSET;++i)
- {
- msg.add_plc_values(0);
- }
- for (int i = 0; i < plc->m_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 "<<std::endl;
- // 断线重连
- if (!plc_communicator->mb_plc_is_connected)
- {
- Error_manager code=plc_communicator->connect();
- if(code!=SUCCESS)
- {
- LOG(ERROR)<<code.to_string();
- }
- usleep(1000 * 200);
- }
- else
- {
- // std::cout<<" thread 111 "<<std::endl;
- // 读取所有数据,更新本地并发布消息到UI
- int plc_length_temp = PLC_REGION_NUM * PLC_SIGNAL_NUM_PER_REGION;
- uint16_t plc_data_temp[plc_length_temp];
- int rc = plc_communicator->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."<<std::endl;
- plc_communicator->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 "<<std::endl;
- if (plc_data_temp[i] == 1)
- {
- // 判空
- if (plc_communicator->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)<<ec.to_string();
- }
- }
- }
- // 指令清空,暂不恢复心跳
- else if (plc_data_temp[i] == 0)
- {
- // int status_temp = plc_communicator->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::endl;
- // 写入心跳或当前运行状态
- for (size_t i = 0; i < PLC_REGION_NUM; i++)
- {
- 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();
- // 判断超时且非心跳,则转回心跳
- 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 "<<std::endl;
- // 更新时间
- plc_communicator->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 "<<std::endl;
- }
- }
- }
- usleep(1000 * PLC_SLEEP_IN_MILLISECONDS);
- }
- }
|