|
@@ -0,0 +1,240 @@
|
|
|
+#include "plc_communicator.h"
|
|
|
+
|
|
|
+// ××××××××××× 构造与析构 ×××××××××××
|
|
|
+Plc_Communicator::Plc_Communicator(const char *ip, int port, int slave_id) : b_plc_initialized(false),
|
|
|
+ b_plc_is_connected(false),
|
|
|
+ b_plc_is_updating(false),
|
|
|
+ p_plc_owner(0),
|
|
|
+ m_plc_thread(0)
|
|
|
+{
|
|
|
+ m_plc_ip = ip;
|
|
|
+ m_plc_port = port;
|
|
|
+ m_plc_slave_id = slave_id;
|
|
|
+ m_plc_current_error = ERROR_CODE::SUCCESS;
|
|
|
+ m_plc_status_update_timeout = 10000;
|
|
|
+ for (size_t i = 0; i < PLC_REGION_NUM; i++)
|
|
|
+ {
|
|
|
+ m_plc_current_status[i].last_time_point = std::chrono::steady_clock::now();
|
|
|
+ m_plc_current_status[i].current_status = 255;
|
|
|
+ m_plc_current_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);
|
|
|
+ b_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;
|
|
|
+ }
|
|
|
+ disconnect();
|
|
|
+}
|
|
|
+
|
|
|
+// ××××××××××× getters setters ×××××××××××
|
|
|
+bool Plc_Communicator::get_connection()
|
|
|
+{
|
|
|
+ return b_plc_is_connected;
|
|
|
+}
|
|
|
+
|
|
|
+bool Plc_Communicator::get_initialize_status()
|
|
|
+{
|
|
|
+ return b_plc_initialized;
|
|
|
+}
|
|
|
+
|
|
|
+ERROR_CODE Plc_Communicator::set_plc_callback(Command_Callback callback, void *p_owner)
|
|
|
+{
|
|
|
+ if (callback == 0 || p_owner == 0)
|
|
|
+ return ERROR_CODE::PLC_SET_CALLBACK_ERROR;
|
|
|
+ m_plc_callback = callback;
|
|
|
+ p_plc_owner = p_owner;
|
|
|
+ return ERROR_CODE::SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+ERROR_CODE Plc_Communicator::set_status_update_timeout(int millisecond){
|
|
|
+ m_plc_status_update_timeout = millisecond;
|
|
|
+ return ERROR_CODE::SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+// ××××××××××× 内部调用连接与重连 ×××××××××××
|
|
|
+ERROR_CODE Plc_Communicator::connect()
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> lck(m_plc_mutex);
|
|
|
+ int rc = m_plc_wrapper.initialize(m_plc_ip.c_str(), m_plc_port, m_plc_slave_id);
|
|
|
+ switch (rc)
|
|
|
+ {
|
|
|
+ case 0:
|
|
|
+ b_plc_is_connected = true;
|
|
|
+ return ERROR_CODE::SUCCESS;
|
|
|
+ case -1:
|
|
|
+ b_plc_is_connected = false;
|
|
|
+ return ERROR_CODE::PLC_CONNECTION_FAILED;
|
|
|
+ case -2:
|
|
|
+ b_plc_is_connected = false;
|
|
|
+ return ERROR_CODE::PLC_SLAVE_ID_ERROR;
|
|
|
+ case -3:
|
|
|
+ b_plc_is_connected = false;
|
|
|
+ return ERROR_CODE::PLC_IP_PORT_ERROR;
|
|
|
+ default:
|
|
|
+ b_plc_is_connected = false;
|
|
|
+ return ERROR_CODE::PLC_UNKNOWN_ERROR;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+ERROR_CODE Plc_Communicator::disconnect()
|
|
|
+{
|
|
|
+ std::lock_guard<std::mutex> lck(m_plc_mutex);
|
|
|
+ m_plc_wrapper.deinitialize();
|
|
|
+ b_plc_is_connected = false;
|
|
|
+}
|
|
|
+
|
|
|
+// ××××××××××× 外部调用执行任务单 ×××××××××××
|
|
|
+ERROR_CODE Plc_Communicator::execute_task(Task_Base *task)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+// ××××××××××× 外部调用获取数据, 终端id[1-6] ×××××××××××
|
|
|
+ERROR_CODE 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_CODE::SUCCESS;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return ERROR_CODE::PLC_NOT_ENOUGH_DATA_ERROR;
|
|
|
+}
|
|
|
+
|
|
|
+// ××××××××××× 更新线程静态函数 ×××××××××××
|
|
|
+void Plc_Communicator::plc_update_thread(Plc_Communicator *plc_communicator)
|
|
|
+{
|
|
|
+ if (plc_communicator == 0)
|
|
|
+ return;
|
|
|
+ while (!plc_communicator->m_plc_cond_exit.WaitFor(1))
|
|
|
+ {
|
|
|
+ plc_communicator->m_plc_mutex.lock();
|
|
|
+ plc_communicator->b_plc_is_connected = plc_communicator->m_plc_wrapper.is_connected();
|
|
|
+ plc_communicator->m_plc_mutex.unlock();
|
|
|
+ // 判断是否初始化完成
|
|
|
+ if (!plc_communicator->b_plc_initialized)
|
|
|
+ continue;
|
|
|
+ // 断线重连
|
|
|
+ if (!plc_communicator->b_plc_is_connected)
|
|
|
+ {
|
|
|
+ plc_communicator->connect();
|
|
|
+ usleep(1000 * PLC_SLEEP_IN_MILLISECONDS * 10);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 读取所有数据并更新本地
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ plc_communicator->m_plc_mutex.lock();
|
|
|
+ for (size_t i = 0; i < plc_length_temp; i++)
|
|
|
+ {
|
|
|
+ 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_current_status[i].cmd){
|
|
|
+ plc_communicator->m_plc_current_status[i].cmd = plc_data_temp[i];
|
|
|
+ if(plc_data_temp[i] == 1){
|
|
|
+ if(plc_communicator->m_plc_callback!=0 && plc_communicator->p_plc_owner!=0){
|
|
|
+ plc_communicator->m_plc_callback(i/PLC_SIGNAL_NUM_PER_REGION + 1, plc_communicator->p_plc_owner);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ plc_communicator->m_plc_current_error = ERROR_CODE::PLC_READ_FAILED;
|
|
|
+ }
|
|
|
+ plc_communicator->m_plc_mutex.unlock();
|
|
|
+
|
|
|
+ // 写入心跳或当前运行状态
|
|
|
+ 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_current_status[i].last_time_point).count();
|
|
|
+ // 判断超时且非心跳,则转回心跳
|
|
|
+ bool modified = false;
|
|
|
+ if (time_interval > plc_communicator->m_plc_status_update_timeout && plc_communicator->m_plc_current_status[i].current_status < 6)
|
|
|
+ {
|
|
|
+ plc_communicator->m_plc_current_status[i].current_status = 255;
|
|
|
+ modified = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 状态切换后写入plc
|
|
|
+ switch (plc_communicator->m_plc_current_status[i].current_status)
|
|
|
+ {
|
|
|
+ case 254:
|
|
|
+ plc_communicator->m_plc_current_status[i].current_status = 255;
|
|
|
+ modified = true;
|
|
|
+ break;
|
|
|
+ case 255:
|
|
|
+ plc_communicator->m_plc_current_status[i].current_status = 254;
|
|
|
+ modified = true;
|
|
|
+ break;
|
|
|
+ case 0:
|
|
|
+ plc_communicator->m_plc_current_status[i].current_status = 254;
|
|
|
+ modified = true;
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ plc_communicator->m_plc_current_status[i].current_status = 2;
|
|
|
+ modified = true;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ if(time_interval > 3000)
|
|
|
+ {
|
|
|
+ plc_communicator->m_plc_current_status[i].current_status = 254;
|
|
|
+ modified = true;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ break;
|
|
|
+ case 5:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(modified && plc_communicator->b_plc_is_connected){
|
|
|
+ plc_communicator->m_plc_mutex.lock();
|
|
|
+ // 更新时间
|
|
|
+ plc_communicator->m_plc_current_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_current_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_CODE::PLC_WRITE_FAILED;
|
|
|
+ plc_communicator->m_plc_mutex.unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ usleep(1000 * PLC_SLEEP_IN_MILLISECONDS);
|
|
|
+ }
|
|
|
+}
|