197 lines
4.9 KiB
C
197 lines
4.9 KiB
C
|
||
#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
|
||
|
||
|