FreeModbus_Slave-Master-RTT-STM32
FreeModbus_Slave-Master-RTT-STM32 copied to clipboard
STATE_TX_IDLE 状态更新不及时,可能导致协议栈触发断言
在mbrtu.c -> xMBRTUTransmitFSM 中 case STATE_TX_XMIT: /* check if we are finished. */ if( usSndBufferCount != 0 ) { xMBPortSerialPutByte( ( CHAR )pucSndBufferCur ); pucSndBufferCur++; / next byte in sendbuffer. / usSndBufferCount--; } else { xNeedPoll = xMBPortEventPost( EV_FRAME_SENT ); / Disable transmitter. This prevents another transmit buffer * empty interrupt. / vMBPortSerialEnable( TRUE, FALSE ); eSndState = STATE_TX_IDLE; } break; 应该改成: case STATE_TX_XMIT: / check if we are finished. */ if( usSndBufferCount != 0 ) { xMBPortSerialPutByte( ( CHAR )pucSndBufferCur ); pucSndBufferCur++; / next byte in sendbuffer. / usSndBufferCount--; } else { xNeedPoll = xMBPortEventPost( EV_FRAME_SENT ); / Disable transmitter. This prevents another transmit buffer * empty interrupt. */ eSndState = STATE_TX_IDLE; vMBPortSerialEnable( TRUE, FALSE ); //eSndState = STATE_TX_IDLE; } break;
否则会出现的现象为: 当vMBPortSerialEnable( TRUE, FALSE );使能接收中断的一瞬间,硬件出现接收中断,进入中断函数,而此时由于eSndState还未完全置为IDLE会造成,接收中断函数进入assert_failed;
在 modbus 协议中,从机回复响应报文完成后,主机方是需要等待 T3.5 超时后,才能开始处理该报文,处理完了,主机才能发送新的报文。这期间时间差不多是毫秒级,所以大家在使用的时候没有出现跟你同样的断言。
建议:
- 检查下自己的 T3.5 超时是否准确
- 上面的改法理论上我觉得好像没问题,但毕竟这个库已经经过很多产品的验证,不敢轻易动核心代码,除非你非常了解协议栈。所以也希望,你那边对这个改动先做下充分的验证。
我们做的就是暴力测试。 作为单独的一个库,首先得保证自身不会进入死循环。 如果不修改,移植该库的产品相当于存在一个造成死机的后门。
这个改动是经过验证的。
检查下自己的 T3.5 超时是否准确
这条检查了吗?
我做的测试就是测试从机设备的稳定性, 主机就是不按照modbus的时序规范去收发数据的。 但即使我这么操作测试,从设备也绝不应该进入死循环。
我认为 FreeModbus 从机协议栈的作者原意是想让整个状态机更加可靠,所以增加了一些检查,看似挺合情合理。只是这些非常规临界状态时,针对具体的移植代码,可能会状态紊乱。
先这样改,方便提交 pr 吗?