optical/NxFuncs/modbus/modbus_tcp.c
2025-09-04 09:45:08 +08:00

197 lines
4.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 协议标识符为0x000x00
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至0x007B123
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