#include "modbustcp.h" #include "deviceproxy.h" ModbusTCP* ModbusTCP::uniqueInstance = nullptr; ModbusTCP* ModbusTCP::instance() { if (!uniqueInstance) { uniqueInstance = new ModbusTCP(); } return uniqueInstance; } ModbusTCP::ModbusTCP() { sockfd = INVALID_SOCKET; sockfd_fl = INVALID_SOCKET; sockfd_record = INVALID_SOCKET; port = 502; ipAddr = ""; ipAddr_fl = ""; ipAddr_record = ""; ipAddr_electric_resistance = ""; _seq_modbus = 0; _seq_modbus_fl = 0; stopFlag = false; memset(RFID,0,50); PLCSts[0] = -1; PLCSts[1] = -1; TransferPLCCmd.cmdAddr = 0; TransferPLCCmd.cmdDelay = 0; TransferPLCCmd.cmdWriteFlag = false; SeparatePLCCmd.cmdAddr = 0; SeparatePLCCmd.cmdDelay = 0; SeparatePLCCmd.cmdWriteFlag = false; WORD sockVersion = MAKEWORD(2, 2); WSADATA data; WSAStartup(sockVersion, &data); InitializeCriticalSection(&mCsRead); InitializeCriticalSection(&mCsRead_fl); } ModbusTCP::~ModbusTCP(void) { if (sockfd != INVALID_SOCKET) { CloseConn(); } if (sockfd_fl != INVALID_SOCKET) { CloseConn_fl(); } if (sockfd_record != INVALID_SOCKET) { CloseConn_record(); } sockfd = INVALID_SOCKET; sockfd_fl = INVALID_SOCKET; sockfd_record = INVALID_SOCKET; WSACleanup(); } bool ModbusTCP::ConnPLC() { struct sockaddr_in server_addr; char* ip; QByteArray ba = ipAddr.toLatin1(); // must ip=ba.data(); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == INVALID_SOCKET) { //printf("Failed to create socket: %s\n", strerror(errno)); return false; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); //inet_pton(AF_INET, "server_ip", &server_addr.sin_addr.s_addr); server_addr.sin_addr.s_addr = inet_addr(ip); if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { //printf("Failed to connect to server: %s\n", strerror(errno)); closesocket(sockfd); return false; } return true; } bool ModbusTCP::ConnPLC_fl() { struct sockaddr_in server_addr; char* ip; QByteArray ba = ipAddr_fl.toLatin1(); // must ip=ba.data(); sockfd_fl = socket(AF_INET, SOCK_STREAM, 0); if (sockfd_fl == INVALID_SOCKET) { //printf("Failed to create socket: %s\n", strerror(errno)); return false; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); //inet_pton(AF_INET, "server_ip", &server_addr.sin_addr.s_addr); server_addr.sin_addr.s_addr = inet_addr(ip); if (connect(sockfd_fl, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { //printf("Failed to connect to server: %s\n", strerror(errno)); closesocket(sockfd_fl); return false; } return true; } bool ModbusTCP::ConnPLC_force() { struct sockaddr_in server_addr; char* ip; QByteArray ba = ipAddr_record.toLatin1(); // must ip=ba.data(); sockfd_record = socket(AF_INET, SOCK_STREAM, 0); if (sockfd_record == INVALID_SOCKET) { //printf("Failed to create socket: %s\n", strerror(errno)); return false; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(6000); //inet_pton(AF_INET, "server_ip", &server_addr.sin_addr.s_addr); server_addr.sin_addr.s_addr = inet_addr(ip); if (connect(sockfd_record, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { //printf("Failed to connect to server: %s\n", strerror(errno)); closesocket(sockfd_record); return false; } return true; } bool ModbusTCP::ConnPLC_electric_resistance() { struct sockaddr_in server_addr; char* ip; //ipAddr_electric_resistance = "192.168.30.6"; QByteArray ba = ipAddr_electric_resistance.toLatin1(); // must AF_LOCAL ip=ba.data(); sockfd_electric_resistance = socket(AF_INET, SOCK_STREAM, 0); if (sockfd_electric_resistance == INVALID_SOCKET) { //printf("Failed to create socket: %s\n", strerror(errno)); return false; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(6677); //inet_pton(AF_INET, "server_ip", &server_addr.sin_addr.s_addr); server_addr.sin_addr.s_addr = inet_addr(ip); if (connect(sockfd_electric_resistance, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { //printf("Failed to connect to server: %s\n", strerror(errno)); closesocket(sockfd_electric_resistance); return false; } return true; } bool ModbusTCP::CloseConn() { bool ret = true; if (sockfd != INVALID_SOCKET) closesocket(sockfd); sockfd = INVALID_SOCKET; return ret; } bool ModbusTCP::CloseConn_fl() { bool ret = true; if (sockfd_fl != INVALID_SOCKET) closesocket(sockfd_fl); sockfd_fl = INVALID_SOCKET; return ret; } bool ModbusTCP::CloseConn_record() { bool ret = true; if (sockfd_record != INVALID_SOCKET) closesocket(sockfd_record); sockfd_record = INVALID_SOCKET; return ret; } bool ModbusTCP::CloseConn_electric_resistance() { bool ret = true; if (sockfd_electric_resistance != INVALID_SOCKET) closesocket(sockfd_electric_resistance); sockfd_electric_resistance = INVALID_SOCKET; return ret; } int ModbusTCP::SendCmdRead(unsigned int sockfd,char *data, unsigned short data_len) { //可能存在问题。 //1、接收按照数据长度接收,然后校验接收长度是否正确 //2、返回的数据,是否正确,是否要进行判断? char rev_buf[4096]; int RevDataLen = 0; //发送modbus请求 if (send(sockfd, data, data_len, 0) == -1) { closesocket(sockfd); return -1; } //printf("Sent request successfully.\n"); //接收modbus请求 RevDataLen = recv(sockfd, rev_buf, 4096, 0); if (RevDataLen == -1) { //printf("Failed to receive response: %s\n", strerror(errno)); closesocket(sockfd); return -1; } int ret = DataDecode(rev_buf, RevDataLen); return ret; } int ModbusTCP::SendCmdWrite(unsigned int sockfd,char *data, unsigned short data_len) { //可能存在问题。 //1、接收按照数据长度接收,然后校验接收长度是否正确 //2、返回的数据,是否正确,是否要进行判断? char rev_buf[4096]; int RevDataLen = 0; //发送modbus请求 if (send(sockfd, data, data_len, 0) == -1) { closesocket(sockfd); return -1; } //printf("Sent request successfully.\n"); //接收modbus请求 RevDataLen = recv(sockfd, rev_buf, 4096, 0); if (RevDataLen == -1) { //printf("Failed to receive response: %s\n", strerror(errno)); closesocket(sockfd); return -1; } //int ret = Com_decode(rev_buf, RevDataLen); return 0; } int ModbusTCP::SendCmdRead_fl(unsigned int sockfd,char *data, unsigned short data_len) { //可能存在问题。 //1、接收按照数据长度接收,然后校验接收长度是否正确 //2、返回的数据,是否正确,是否要进行判断? char rev_buf[4096]; int RevDataLen = 0; //发送modbus请求 if (send(sockfd, data, data_len, 0) == -1) { closesocket(sockfd); return -1; } //printf("Sent request successfully.\n"); //接收modbus请求 RevDataLen = recv(sockfd, rev_buf, 4096, 0); if (RevDataLen == -1) { //printf("Failed to receive response: %s\n", strerror(errno)); closesocket(sockfd); return -1; } int ret = DataDecode(rev_buf, RevDataLen); return ret; } int ModbusTCP::SendCmdWrite_fl(unsigned int sockfd,char *data, unsigned short data_len) { //可能存在问题。 //1、接收按照数据长度接收,然后校验接收长度是否正确 //2、返回的数据,是否正确,是否要进行判断? char rev_buf[4096]; int RevDataLen = 0; //发送modbus请求 if (send(sockfd, data, data_len, 0) == -1) { closesocket(sockfd); return -1; } //printf("Sent request successfully.\n"); //接收modbus请求 RevDataLen = recv(sockfd, rev_buf, 4096, 0); if (RevDataLen == -1) { //printf("Failed to receive response: %s\n", strerror(errno)); closesocket(sockfd); return -1; } //int ret = Com_decode(rev_buf, RevDataLen); return 0; } int ModbusTCP::DataDecode(char *data, int len) { if ((len >= 10) && (len <= 11)) { return data[len-1]; } else if (len > 11) { memset(MODBUSTCP->RFID,0,50); memcpy(RFID,&data[9],len-9); } return 0; } int ModbusTCP::ModbusWrite(unsigned char cmd,unsigned short addr, unsigned short data) { int ret; unsigned char sendBuf[50];//发送缓存 unsigned short temps = _seq_modbus++;//类似于TCP的seq序列号,让其自增即可 unsigned char* temp = reinterpret_cast(&temps); //协议头 sendBuf[0] = *(temp + 1);//前两位为事务处理标识,2个字节的序列号 sendBuf[1] = *(temp); sendBuf[2] = 0;//协议标识,两个字节,0000即为Modbus TCP协议 sendBuf[3] = 0; sendBuf[4] = 0;//长度字段(前半部分字节) sendBuf[5] = 6;//随后字节数 sendBuf[6] = 1;//单元标志,定义连接目的节点的其他设备(这个设备是1号,所以是0x01) //以上是Modbus协议头部分 //协议体 sendBuf[7] = cmd;//Modbus功能码 ,这里是 写多个保持寄存器 操作 temps = addr; sendBuf[8] = *(temp + 1); //写寄存器起始地址高字节 sendBuf[9] = *(temp); //写寄存器起始地址低字节(所以这里是往0x0100地址写寄存器) //sendBuf[10] = 0x00; //写寄存器数量高字节 //sendBuf[11] = 0x01; //写寄存器数量低字节 //sendBuf[12] = 0x01; //数据长度 //写1个值到报文中 temps = data; //sendBuf[10] = data; sendBuf[10] = *(temp + 1); sendBuf[11] = *(temp); bool ret_conn = true; ::EnterCriticalSection(&mCsRead); ret_conn = ConnPLC(); if (ret_conn) ret = SendCmdWrite(sockfd,reinterpret_cast(sendBuf), 12); else { CloseConn(); ::LeaveCriticalSection(&mCsRead); return -1; } CloseConn(); ::LeaveCriticalSection(&mCsRead); return ret; } int ModbusTCP::ModbusWrite_fl(unsigned char cmd,unsigned short addr, unsigned short data) { int ret; unsigned char sendBuf[50];//发送缓存 unsigned short temps = _seq_modbus_fl++;//类似于TCP的seq序列号,让其自增即可 unsigned char* temp = reinterpret_cast(&temps); //协议头 sendBuf[0] = *(temp + 1);//前两位为事务处理标识,2个字节的序列号 sendBuf[1] = *(temp); sendBuf[2] = 0;//协议标识,两个字节,0000即为Modbus TCP协议 sendBuf[3] = 0; sendBuf[4] = 0;//长度字段(前半部分字节) sendBuf[5] = 6;//随后字节数 sendBuf[6] = 1;//单元标志,定义连接目的节点的其他设备(这个设备是1号,所以是0x01) //以上是Modbus协议头部分 //协议体 sendBuf[7] = cmd;//Modbus功能码 ,这里是 写多个保持寄存器 操作 temps = addr; sendBuf[8] = *(temp + 1); //写寄存器起始地址高字节 sendBuf[9] = *(temp); //写寄存器起始地址低字节(所以这里是往0x0100地址写寄存器) //sendBuf[10] = 0x00; //写寄存器数量高字节 //sendBuf[11] = 0x01; //写寄存器数量低字节 //sendBuf[12] = 0x01; //数据长度 //写1个值到报文中 temps = data; //sendBuf[10] = data; sendBuf[10] = *(temp + 1); sendBuf[11] = *(temp); bool ret_conn = true; ::EnterCriticalSection(&mCsRead_fl); ret_conn = ConnPLC_fl(); if (ret_conn) ret = SendCmdWrite_fl(sockfd_fl,reinterpret_cast(sendBuf), 12); else { CloseConn_fl(); ::LeaveCriticalSection(&mCsRead_fl); return -1; } CloseConn_fl(); ::LeaveCriticalSection(&mCsRead_fl); return ret; } int ModbusTCP::ModbusWrite_force(char * data, int len) { bool ret_conn = true; //::EnterCriticalSection(&mCsRead_fl); ret_conn = ConnPLC_force(); if (ret_conn) { if (send(sockfd_record, data, len, 0) == -1) { CloseConn_record(); qDebug()<< "result1: "<(&temps); //协议头 sendBuf[0] = *(temp + 1);//前两位为事务处理标识,2个字节的序列号 sendBuf[1] = *(temp); sendBuf[2] = 0;//协议标识,两个字节,0000即为Modbus TCP协议 sendBuf[3] = 0; sendBuf[4] = 0;//长度字段(前半部分字节) sendBuf[5] = 6;//随后字节数 sendBuf[6] = 0x01;//单元标志,定义连接目的节点的其他设备(这个设备是1号,所以是0x01) //以上是Modbus协议头部分 //协议体 sendBuf[7] = 0x03;//Modbus功能码 ,这里是读 temps = addr; sendBuf[8] = *(temp + 1); //写寄存器起始地址高字节 sendBuf[9] = *(temp); //写寄存器起始地址低字节(所以这里是往0x0100地址写寄存器) sendBuf[10] = 0x00; //长度 sendBuf[11] = dataLen; //写寄存器数量低字节 bool ret_conn = true; ::EnterCriticalSection(&mCsRead); ret_conn = ConnPLC(); if (ret_conn) ret = SendCmdRead(sockfd,reinterpret_cast(sendBuf), 12); else { CloseConn(); ::LeaveCriticalSection(&mCsRead); return -1; } CloseConn(); ::LeaveCriticalSection(&mCsRead); return ret; } int ModbusTCP::ModbusRead_fl(unsigned short addr,int dataLen) { int ret; unsigned char sendBuf[50];//发送缓存 unsigned short temps = _seq_modbus_fl++;//类似于TCP的seq序列号,让其自增即可 unsigned char* temp = reinterpret_cast(&temps); //协议头 sendBuf[0] = *(temp + 1);//前两位为事务处理标识,2个字节的序列号 sendBuf[1] = *(temp); sendBuf[2] = 0;//协议标识,两个字节,0000即为Modbus TCP协议 sendBuf[3] = 0; sendBuf[4] = 0;//长度字段(前半部分字节) sendBuf[5] = 6;//随后字节数 sendBuf[6] = 0x01;//单元标志,定义连接目的节点的其他设备(这个设备是1号,所以是0x01) //以上是Modbus协议头部分 //协议体 sendBuf[7] = 0x03;//Modbus功能码 ,这里是读 temps = addr; sendBuf[8] = *(temp + 1); //写寄存器起始地址高字节 sendBuf[9] = *(temp); //写寄存器起始地址低字节(所以这里是往0x0100地址写寄存器) sendBuf[10] = 0x00; //长度 sendBuf[11] = dataLen; //写寄存器数量低字节 bool ret_conn = true; ::EnterCriticalSection(&mCsRead_fl); ret_conn = ConnPLC_fl(); if (ret_conn) ret = SendCmdRead_fl(sockfd_fl,reinterpret_cast(sendBuf), 12); else { CloseConn_fl(); ::LeaveCriticalSection(&mCsRead_fl); return -1; } CloseConn_fl(); ::LeaveCriticalSection(&mCsRead_fl); return ret; } int ModbusTCP::TransferPLCRun(unsigned short addr,int delay) { if ((addr == 0) || (delay <= 0)) return -1; if (TransferPLCCmd.cmdAddr != 0) { return -1; } else { TransferPLCCmd.cmdAddr = addr; TransferPLCCmd.cmdDelay = delay; TransferPLCCmd.cmdWriteFlag = false; return 0; } } int ModbusTCP::SeparatePLCRun(unsigned short addr,int delay) { if ((addr == 0) || (delay <= 0)) return -1; if (SeparatePLCCmd.cmdAddr != 0) { return -1; } else { SeparatePLCCmd.cmdAddr = addr; SeparatePLCCmd.cmdDelay = delay; SeparatePLCCmd.cmdWriteFlag = false; return 0; } } int ModbusTCP::getModbusPara(QString DevName) { QSettings *settings;//申明一个QSetting类函数 settings = new QSettings ("SerialDevSet.ini", QSettings::IniFormat);//构建函数 QString strKey; strKey = "/"+DevName+"/ipAddr"; ipAddr = settings->value(strKey).toString(); strKey = "/"+DevName+"/ipAddr_fl"; ipAddr_fl = settings->value(strKey).toString(); strKey = "/"+DevName+"/ipAddr_record"; ipAddr_record = settings->value(strKey).toString(); strKey = "/"+DevName+"/ipAddr_electric_resistance"; ipAddr_electric_resistance = settings->value(strKey).toString(); strKey = "/"+DevName+"/shangReadAddr"; shangReadAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/shangWriteAddr"; shangWriteAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/shangReadRFIDAddr"; shangReadRFIDAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/shangReadVacuumAddr"; shangReadVacuumAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/shangWriteHeartbeatAddr"; shangWriteHeartbeatAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/shangWriteVacuumAddr"; shangWriteVacuumAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/xiaReadAddr"; xiaReadAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/xiaWriteAddr"; xiaWriteAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/xiaReadStsAddr"; xiaReadStsAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/ReadTransferPLCStsAddr"; ReadTransferPLCStsAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/xiaWriteVacuumAddr"; xiaWriteVacuumAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/InitAddr"; InitAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/RunAddr"; RunAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/StopAddr"; StopAddr = static_cast(settings->value(strKey).toInt()); strKey = "/"+DevName+"/ClearAlarmAddr"; ClearAlarmAddr = static_cast(settings->value(strKey).toInt()); return 0; } int ModbusTCP::Heartbeat(void) { int internal_read = 0; int internal_write = 0; int internal_sts = 0; int ret_modbus; int count = 0; bool readFlag = false; int fail_count[2] = {0}; int internal_TransferPLCCmd_sts = 0; while (1) { internal_read++; internal_write++; internal_sts++; if ((internal_read >= 240) && (readFlag)) { ret_modbus = MODBUSTCP->ModbusRead(MODBUSTCP->shangWriteHeartbeatAddr, 1); if (ret_modbus != 0) { count++; } else { count = 0; MODBUSTCP->connFlag = true; } if (count >= 3) { MODBUSTCP->connFlag = false; } readFlag = false; internal_write = 0; } if ((internal_write >= 20) && (!readFlag)) { ret_modbus = MODBUSTCP->ModbusWrite(0x06,MODBUSTCP->shangWriteHeartbeatAddr, 1); internal_read = 0; readFlag = true; } if (internal_sts >= 20) { ret_modbus = MODBUSTCP->ModbusRead(MODBUSTCP->xiaReadStsAddr, 1); if (ret_modbus == -1) { fail_count[0]++; if (fail_count[0] >= 3) { PLCSts[0] = -1; } } else { fail_count[0] = 0; PLCSts[0] = ret_modbus; } ret_modbus = MODBUSTCP->ModbusRead(MODBUSTCP->ReadTransferPLCStsAddr, 1); TransferPLCSts = ret_modbus; emit DEV->TransferPLCSGL(PLCSts[0]); internal_sts = 0; } if (TransferPLCCmd.cmdAddr != 0) { if (TransferPLCCmd.cmdWriteFlag == false) { //发送写命令 ret_modbus = MODBUSTCP->ModbusWrite(0x05,TransferPLCCmd.cmdAddr, 0xff00); TransferPLCCmd.cmdWriteFlag = true; } internal_TransferPLCCmd_sts++; if ((internal_TransferPLCCmd_sts * 5) >= TransferPLCCmd.cmdDelay) { //发送清除命令 ret_modbus = MODBUSTCP->ModbusWrite(0x05,TransferPLCCmd.cmdAddr, 0); TransferPLCCmd.cmdWriteFlag = false; TransferPLCCmd.cmdAddr = 0; TransferPLCCmd.cmdDelay = 0; internal_TransferPLCCmd_sts = 0; } } Sleep(5); } } int ModbusTCP::Heartbeat_fl(void) { int internal_sts = 0; int ret_modbus; int fail_count[2] = {0}; int internal_SeparatePLCCmd_sts = 0; while (1) { internal_sts++; if (internal_sts >= 20) { ret_modbus = MODBUSTCP->ModbusRead_fl(MODBUSTCP->xiaReadStsAddr, 1); if (ret_modbus == -1) { fail_count[1]++; if (fail_count[1] >= 3) { PLCSts[1] = -1; } } else { fail_count[1] = 0; PLCSts[1] = ret_modbus; } emit DEV->SeparatePLCSGL(PLCSts[1]); internal_sts = 0; } if (SeparatePLCCmd.cmdAddr != 0) { if (SeparatePLCCmd.cmdWriteFlag == false) { ret_modbus = MODBUSTCP->ModbusWrite_fl(0x05,SeparatePLCCmd.cmdAddr, 0xff00); SeparatePLCCmd.cmdWriteFlag = true; } internal_SeparatePLCCmd_sts++; if ((internal_SeparatePLCCmd_sts * 5) >= SeparatePLCCmd.cmdDelay) { //发送清除命令 ret_modbus = MODBUSTCP->ModbusWrite_fl(0x05,SeparatePLCCmd.cmdAddr, 0); SeparatePLCCmd.cmdWriteFlag = false; SeparatePLCCmd.cmdAddr = 0; SeparatePLCCmd.cmdDelay = 0; internal_SeparatePLCCmd_sts = 0; } } Sleep(5); } } /* * 1、正常自动加工时,在工作线程跑上下料 * 2、在测试界面,使用线程(CreateThread),有运行标记 */