第一次正儿八经移植程序,整理了2天,终于梳理清楚。
过程曲折&愉快
RTU客端代码梳理
源代码很多,提炼核心,了解程序跳转流程
把握整体框架
modbus-rtu 03数据结构
Slave Address | Function Code | RegAdd | RegNum | CRC |
---|
根据数据结构,就分了3个处理层级
- 地址 eMBPoll
- 功能码 eMBFunc…
- 寄存器 eMBRegHoldingCB
1. 总入口-eMBPoll–<1 设备地址> <mb.c>
层级1 :<设备地址>
主要流程:
- 接收事件状态机:case EV_FRAME_RECEIVED / EV_EXECUTE
- 提取+判断:设备地址ucRcvAddress
- 功能跳转:功能码ucFunctionCode
- 回复内容:ucMBFrame
核心代码:
- 事件状态机:xMBPortEventGet( &eEvent ) +switch ( eEvent )
- 地址提取:peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength )
地址判断 if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) ) - 功能码跳转关联处理函数:xFuncHandlers[i].pxHandler( ucMBFrame, &usLength )
- 回复数据 peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
源代码
eMBErrorCode eMBPoll( void )
{
static UCHAR *ucMBFrame;
static UCHAR ucRcvAddress;
static UCHAR ucFunctionCode;
static USHORT usLength;
static eMBException eException;
int i;
eMBErrorCode eStatus = MB_ENOERR;
eMBEventType eEvent;
/* Check if the protocol stack is ready. */
if( eMBState != STATE_ENABLED )
{
return MB_EILLSTATE;
}
/* Check if there is a event available. If not return control to caller.
* Otherwise we will handle the event. */
if( xMBPortEventGet( &eEvent ) == TRUE )
{
switch ( eEvent )
{
case EV_READY:
break;
case EV_FRAME_RECEIVED:
eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
if( eStatus == MB_ENOERR )
{
/* Check if the frame is for us. If not ignore the frame. */
if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )
{
( void )xMBPortEventPost( EV_EXECUTE );
}
}
break;
case EV_EXECUTE:
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
eException = MB_EX_ILLEGAL_FUNCTION;
for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
{
/* No more function handlers registered. Abort. */
if( xFuncHandlers[i].ucFunctionCode == 0 )
{
break;
}
else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
{
eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
break;
}
}
/* If the request was not sent to the broadcast address we
* return a reply. */
if( ucRcvAddress != MB_ADDRESS_BROADCAST )
{
if( eException != MB_EX_NONE )
{
/* An exception occured. Build an error frame. */
usLength = 0;
ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
ucMBFrame[usLength++] = eException;
}
eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
}
break;
case EV_FRAME_SENT:
break;
}
}
return MB_ENOERR;
}
2. 功能码关联函数-eMBFunc-<2 功能码> <mbfuncholding.c>
层级2: <功能码>
提取:寄存器地址usRegAddress+寄存器数量usRegCount
以eMBFuncReadHoldingRegister为例
主要流程:
- 提取:寄存器地址usRegAddress
- 提取:寄存器数量usRegCount
- 调用寄存器处理函数
核心代码:
- 提取寄存器地址+数量
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
usRegAddress++;
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
- 调用寄存器处理函数
eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ );
源代码
eMBException
eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{
USHORT usRegAddress;
USHORT usRegCount;
UCHAR *pucFrameCur;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
usRegAddress++;
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
*/
if( ( usRegCount >= 1 ) && ( usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX ) )
{
/* Set the current PDU data pointer to the beginning. */
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
*usLen = MB_PDU_FUNC_OFF;
/* First byte contains the function code. */
*pucFrameCur++ = MB_FUNC_READ_HOLDING_REGISTER;
*usLen += 1;
/* Second byte in the response contain the number of bytes. */
*pucFrameCur++ = ( UCHAR ) ( usRegCount * 2 );
*usLen += 1;
/* Make callback to fill the buffer. */
eRegStatus = eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
else
{
*usLen += usRegCount * 2;
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid request because the length is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
3. 寄存器处理回调函数-eMBRegHoldingCB- < 3 寄存器> <user_mb_app.c>
层级3:<寄存器>
回调函数在demo的port->user_mb_app.c
移植时可以参考着修改
主要流程:
- 读写判断:eMode
- 寄存器地址&数量:usAddress + usNRegs
核心代码:
- 读写判断
switch (eMode)
{
case MB_REG_READ:
...
case MB_REG_WRITE:
...
}
- 操作寄存器
读
while (usNRegs > 0)
{
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
iRegIndex++;
usNRegs--;
}
写
while (usNRegs > 0)
{
pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
源代码
eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex;
USHORT * pusRegHoldingBuf;
USHORT REG_HOLDING_START;
USHORT REG_HOLDING_NREGS;
USHORT usRegHoldStart;
pusRegHoldingBuf = usSRegHoldBuf;
REG_HOLDING_START = S_REG_HOLDING_START;
REG_HOLDING_NREGS = S_REG_HOLDING_NREGS;
usRegHoldStart = usSRegHoldStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= REG_HOLDING_START)
&& (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS))
{
iRegIndex = usAddress - usRegHoldStart;
switch (eMode)
{
/* read current register values from the protocol stack. */
case MB_REG_READ:
while (usNRegs > 0)
{
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
iRegIndex++;
usNRegs--;
}
break;
/* write current register values with new values from the protocol stack. */
case MB_REG_WRITE:
while (usNRegs > 0)
{
pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
功能码关联函数清单
static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
17 {MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
4 {MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister},
3 {MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister},
16 {MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister},
6 {MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister},
23 {MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister},
1 {MB_FUNC_READ_COILS, eMBFuncReadCoils},
5 {MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil},
15 {MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils},
2 {MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs},};
寄存器回调函数清单(用户)
//读字
eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
//读写字
eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)
//读写bit
eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNCoils, eMBRegisterMode eMode)
//读bit
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
位操作:01 eMBRegCoilsCB 砍掉写功能=> 02 eMBRegDiscreteCB
字操作:03eMBRegHoldingCB 砍掉写功能=> 04 eMBRegInputCB