#include "modbus_tcp.h" #include "trigger.h" #if (MAX_MODBUS_TCP_NODE > 0) #include "ethernet.h" //------------------------------ // 控制数据结构 typedef struct { SocketCtrl * pSocket; // 控制控制 int transing; // 0, 空闲; 1, 发送请求,等待回包 u16 transId; // 发送的事务控制(从零开始自增) u32 begtime; // 发送的时刻 int expectAnswerPduLen; // 期望的PDU长度 // 发送命令的记录 ModbusTcpADU request; // 请求命令 ModbusTcpADU answer; // 应答命令 }ModbusTcpCtrl; //------------------------------ #define MODBUSTCP_SIDX TCP_CLIENT_SN_BEG ModbusTcpCtrl g_modbusTcpCtrl[MAX_MODBUS_TCP_NODE]; //------------------------------ // 发送数据 #define ModbusTcpSendData EthernetSendData // 接收数据 #define ModbusTcpGetData EthernetGetData // 已接收数据长度 #define ModbusTcpGetRsLen EthernetGetRsLen // 得到发送缓冲区空闲长度 #define ModbusTcpGetSdFreeLen EthernetGetSdFreeLen //------------------------------ void InitModbusTcp() { int i; memset(&g_modbusTcpCtrl, 0, sizeof(ModbusTcpCtrl)*MAX_MODBUS_TCP_NODE); for (i = 0; i < MAX_MODBUS_TCP_NODE; i++) { g_modbusTcpCtrl[i].pSocket = GetCtrlFromSocketIdx(MODBUSTCP_SIDX+i); } } // 异步功能,发送或接收modbustcp数据,完成通讯 void ModbusTcpServerRun(void) { int i; int rslt; ModbusTcpADU * pRequestAdu; ModbusTcpADU * pAnswerAdu; for (i = 0; i < MAX_MODBUS_TCP_NODE; i++) { if (g_modbusTcpCtrl[i].transing == 1) // 正在发送,等待回包 { pRequestAdu = &(g_modbusTcpCtrl[i].request); pAnswerAdu = &(g_modbusTcpCtrl[i].answer); rslt = ModbusTcpGetRsLen(g_modbusTcpCtrl[i].pSocket); if (rslt >= g_modbusTcpCtrl[i].expectAnswerPduLen) { rslt = ModbusTcpGetData(g_modbusTcpCtrl[i].pSocket, pAnswerAdu->datbuff, g_modbusTcpCtrl[i].expectAnswerPduLen); if (rslt == g_modbusTcpCtrl[i].expectAnswerPduLen) { if ( pRequestAdu->normal.transId == pAnswerAdu->normal.transId && pRequestAdu->normal.cmd == pAnswerAdu->normal.cmd && // 其他检验 1 ) { // 收到正确回复 printf("get ModbusTcp %d ACK\r\n", i); } } g_modbusTcpCtrl[i].transing = 0; } else if (rslt == LEN_ERR_ANSWER) // 接收数据 { rslt = ModbusTcpGetData(g_modbusTcpCtrl[i].pSocket, pAnswerAdu->datbuff, LEN_ERR_ANSWER); if (rslt == LEN_ERR_ANSWER) { if ( pRequestAdu->normal.transId == pAnswerAdu->normal.transId && pRequestAdu->normal.cmd == (pAnswerAdu->normal.cmd | 0x80) && // 其他检验 1 ) { // 收到错误回复 printf("get ModbusTcp %d NAK\r\n", i); } } g_modbusTcpCtrl[i].transing = 0; } else if (rslt > 0) { printf("get ModbusTcp %d dat err len = %d\r\n", i, rslt); // 长度不对 g_modbusTcpCtrl[i].transing = 0; } else { u32 time; time = GetMsSoftTimer(); if (time - g_modbusTcpCtrl[i].begtime > 100) { printf("wait ModbusTcp %d answer timout\r\n", i); // 超时 g_modbusTcpCtrl[i].transing = 0; } // 等待中 } } } } u16 SwapHighLow(u16 data) { u16 temp; temp = LOBYTE(data); // DATA_L temp <<= 8; temp += HIBYTE(data); // DATA_H; return temp; } // 功能: 写入多个寄存器 int ModbusTcpWriteRegs(int nidx, u16 addr, u16 * regAry, u16 nums) { int i, pdulen; ModbusTcpADU * pRequestAdu; // ModbusTcpADU * pAnswerAdu; if (nidx < 0 || nidx > MAX_MODBUS_TCP_NODE || nums < 1 || regAry == NULL) { printf("ModbusTcpWriteRegs trans para err, nidx=%d, nums=%d\r\n", nidx, nums); return -1; } if (g_modbusTcpCtrl[nidx].transing != 0) { printf("ModbusTcpWriteRegs trans at %d is busy\r\n", nidx); return -1; } if (nums > MAX_WR_REG_NUMS) { nums = MAX_WR_REG_NUMS; } pdulen = 6 + nums*2; pRequestAdu = &(g_modbusTcpCtrl[nidx].request); // pAnswerAdu = &(g_modbusTcpCtrl[nidx].answer); //-------- // MBAP pRequestAdu->writeRegArrayRequest.transId = SwapHighLow(g_modbusTcpCtrl[nidx].transId); // 事务元标识符。从0开始自增 pRequestAdu->writeRegArrayRequest.protId = SwapHighLow(0); // 协议标识符。MODBUS 协议标识符为0x00,0x00 pRequestAdu->writeRegArrayRequest.len = SwapHighLow(pdulen + 1); // 帧长度。 pRequestAdu->writeRegArrayRequest.unitId = 0x01; // 单元标识符。 //-------- // MODBUS PDU pRequestAdu->writeRegArrayRequest.cmd = WRITE_MULTIPLE_REGISTER; // 写多个寄存器 pRequestAdu->writeRegArrayRequest.regBegAddr = SwapHighLow(addr); // 寄存器起始位地址 0x0000至0xFFFF pRequestAdu->writeRegArrayRequest.regsNum = SwapHighLow(nums); // 寄存器的数量 0x0001至0x007B(123) pRequestAdu->writeRegArrayRequest.bytes = nums * 2; // 字节数 N = 寄存器数量 * 2 for (i = 0; i < nums; i++) { pRequestAdu->writeRegArrayRequest.regsArray[i] = SwapHighLow(regAry[i]); // 寄存器的值,MSB } //-------- // 记录当前发送命令 g_modbusTcpCtrl[nidx].transing = 1; // 开始发送 g_modbusTcpCtrl[nidx].begtime = GetMsSoftTimer(); // 记录开始发送的时间点 g_modbusTcpCtrl[nidx].expectAnswerPduLen = 5; g_modbusTcpCtrl[nidx].transId++; //-------- // 发送数据 ModbusTcpSendData(g_modbusTcpCtrl[nidx].pSocket, pRequestAdu->datbuff, LEN_MBAP+pdulen); return 0; } #endif