先看一下初始化函数,参数只有端口。
/* modbus协议栈初始化 */
eMBErrorCode eMBTCPInit(USHORT ucTCPPort);
在网络通信过程中,502端口是专门为modbus保留的,其它应用不得占用该端口。在缺省配置的情况下,强制使用502端口。
modbus协议栈的初始化,主要工作为tcp初始化,注册一些接口,设置节点号。
特别要注意节点号问题,由于网络中通过IP地址寻址,因此节点号对于本机来说就没什么用了,本机必须使用0xFF。
但是对于专门用于通过以太网TCP-IP网络和MODBUS串行链路之间的网关对MODBUS或MODBUS+串行链路从站的通信来说。网关转发数据包给串行链路时,节点号被用来寻址从节点。
modbus tcp端口初始化,主要就是创建modbus tcp服务器,监听端口,等待客户端连接。
/* modbus tcp端口初始化 */
BOOL xMBTCPPortInit(USHORT usTCPPort)
{
struct tcp_pcb *pxPCBListenNew, *pxPCBListenOld;
BOOL bOkay = FALSE;
USHORT usPort;
/* 默认端口502 */
if(usTCPPort == 0)
{
usPort = MB_TCP_DEFAULT_PORT;
}
else
{
usPort = (USHORT)usTCPPort;
}
/* 创建tcp控制块 */
if((pxPCBListenNew = pxPCBListenOld = tcp_new()) == NULL)
{
bOkay = FALSE;
}
/* 绑定端口 */
else if(tcp_bind(pxPCBListenNew, IP_ADDR_ANY, (u16_t)usPort) != ERR_OK)
{
(void)tcp_close(pxPCBListenOld);
bOkay = FALSE;
}
/* 监听端口 */
else if((pxPCBListenNew = tcp_listen(pxPCBListenNew)) == NULL)
{
(void)tcp_close(pxPCBListenOld);
bOkay = FALSE;
}
/* 注册连接回调函数 */
else
{
tcp_accept(pxPCBListenNew, prvxMBTCPPortAccept);
pxPCBListen = pxPCBListenNew;
#ifdef MB_TCP_DEBUG
vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" );
#endif
}
bOkay = TRUE;
return bOkay;
}
modbus tcp服务器同时只能接受一个客户端的连接。
/* 客户端连接回调函数 */
err_t prvxMBTCPPortAccept(void *pvArg, struct tcp_pcb *pxPCB, err_t xErr)
{
err_t error;
if(xErr != ERR_OK)
{
return xErr;
}
/* 之前没有客户端连接 */
if(pxPCBClient == NULL)
{
pxPCBClient = pxPCB;
/* 注册接收回调函数 */
tcp_recv(pxPCB, prvxMBTCPPortReceive);
/* 注册错误回调函数 */
tcp_err(pxPCB, prvvMBTCPPortError);
/* 回调函数参数 */
tcp_arg(pxPCB, pxPCB);
/* 接收字节数置0 */
usTCPBufPos = 0;
#ifdef MB_TCP_DEBUG
vMBPortLog(MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n",
ip4_addr1(&(pxPCB->remote_ip)), ip4_addr2(&(pxPCB->remote_ip)),
ip4_addr3(&(pxPCB->remote_ip)), ip4_addr4(&(pxPCB->remote_ip)));
#endif
error = ERR_OK;
}
/* 已经有客户端连接,不允许第二个客户端连接 */
else
{
prvvMBPortReleaseClient(pxPCB);
error = ERR_OK;
}
return error;
}