瓦特芯 worldsing https://bbs.21ic.com/?564608 [收藏] [复制] [RSS] worldsing.cnblogs.com

日志

FreeModbus Slave 改进的eMbPoll()【worldsing 笔记】

热度 3已有 4483 次阅读2013-8-14 12:35 |个人分类:Modbus|系统分类:单片机| 通信, 主机

eMbPoll()的作用是FreeMod协议通信过程中不断查询事件对列有无完速数据桢,并进行地址和CRD验证,最后运行和回复主机。

为了减小代码尺寸对eMbPoll进行改进:

原版:

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:

            //接收报文函数,传入参数从机地址,报文指针,长度

            //实际上调用了eMBRTUReceive 位于mbrtu.c

            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;

                }

                if( ( eMBCurrentMode == MB_ASCII ) && MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS )

                {

                    vMBPortTimersDelay( MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS );

                }                

                eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );

            }

            break;


        case EV_FRAME_SENT:

            break;

        }

    }

    return MB_ENOERR;

}


改进后的eMbPoll():

void eMBPoll( void ){
  
  static UCHAR   *ucMBFrame;
  static UCHAR    ucFunctionCode;
  static USHORT   usLength;
  static eMBException eException;
  eMBEventType    eEvent;
  UCHAR i;
  USHORT usCRC16;
  if(xMBPortEventGet( &eEvent) == TRUE ){                             //桢事件判断
    if(eEvent == EV_FRAME_RECEIVED){    
      if(usRcvBufferPos < MB_SER_PDU_SIZE_MIN)                        //最小桢判断
        return;
      if(usMBCRC16((UCHAR *)ucRTUBuf, usRcvBufferPos ) != 0)          //CRC判断
        return;
      if(IS_VALID_ADD){                                               //地址       
        ucMBFrame = (UCHAR *) &ucRTUBuf[MB_SER_PDU_PDU_OFF];       
        usLength = (USHORT)( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC);
        ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
        eException = MB_EX_ILLEGAL_FUNCTION;
        for(i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ){                  //执行功能码
          if( xFuncHandlers[i].ucFunctionCode == 0 ){
            return;
          }
          else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode ){
            eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
            break;                               
          }
      }
      if(IS_NOT_BROADCAST){                                        //回复主机
        if( eException != MB_EX_NONE ){                            //错误码         
          usLength = 0;
          ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
          ucMBFrame[usLength++] = eException;
        } 
        if(eRcvState == STATE_RX_IDLE){                            //发送
          pucSndBufferCur = ( UCHAR * ) ucMBFrame - 1;
          pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucMBAddress;
          usSndBufferCount = usLength + 1;      
          usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
          ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF );
          ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 );    
          eSndState = STATE_TX_XMIT;
          vMBPortSerialEnable( FALSE, TRUE );
          }//发送结束
        }//回复结束
      }//地址判断
    }//桢事件判断
  }
}

 

改进说明:

1、eMbPoll()调用一次即可运行功能码和回复主机;

2、省去独立的接收函数peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength ); 而直接操作,(其实里面对算出数据桢的启始位置、和长度);

3、省去发送函数peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength ); 而直接操作;

4、省去返回值,因为调用处没有使用;

5、对功能的遍历i改成unsigned char类型,省去ucRcvAddress和eMBErrorCode    eStatus = MB_ENOERR; 变量,

6、功能兼容原版本。

 

eMbPoll的经典之处在于功能的运行,——》函数指针,这部分在其它笔记中记录。


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)