MT_UartProcessZToolData ( uint8 port, uint8 event )函数解析

来源:互联网 发布:薛之谦 淘宝 店铺名称 编辑:程序博客网 时间:2024/05/02 01:53

UART函数:MT_UART.c >> void MT_UartProcessZToolData ( uint8 port, uint8 event )
该函数是串口MT协议解析函数,解析接收到的串口数据,并确定是程序启动函数,还是简单的串口数据,然后发送数据到正确的地方(MT或APP)。Ti的协议栈中的MT的指令结构比较简单(一般还会在校验后面加帧尾,有的还会在数据里与帧头相同的数据后面加转义字符),如下图:帧头、数据、校验和。

 ,但是MT CMD里面有包含了不少没什么用的数据,内容就比较复杂了。不过他的整个处理还是非常好的。
开始先检测缓冲区内是否有数据,然后从DMA中将数据读出,虽然是一个一个数据读取的,可能有人觉得比较麻烦,但是仔细往下看就不会有这种感觉了。这样做的目的只是在接下来使用状态机的方式把数据解析出来,这样方便简单单,又能检测数据的正确性。下面对整个结构有详细的注解,大家交流交流啊!

原函数:(函数来源于:Z-Stack Lighting 1.0.1)
/***************************************************************************************************
 * @fn      MT_UartProcessZToolData
 *
 * @brief   | SOP | Data Length  |   CMD   |   Data   |  FCS  |
 *         |  1  |     1      |    2     |  0-Len   |   1   |
 *
 *          Parses the data and determine either is SPI or just simply serial data
 *          then send the data to correct place (MT or APP)
 *          
 * @param   port     - UART port
 *          event    - Event that causes the callback
 *
 *
 * @return  None
 ***************************************************************************************************/
void MT_UartProcessZToolData ( uint8 port, uint8 event )
{
  uint8  ch;
  uint8  bytesInRxBuffer;
  (void)event;  // Intentionally unreferenced parameter
  while (Hal_UART_RxBufLen(port))  //循环接收数据
  {
    HalUARTRead (port, &ch, 1);


    switch (state)   //串口接收状态机
    {
      case SOP_STATE:   //SOF位
        if (ch == MT_UART_SOF)
          state = LEN_STATE;  //确认后跳转状态
        break;


      case LEN_STATE:   //数据长度位
        LEN_Token = ch;


        tempDataLen = 0;


        /* Allocate memory for the data *///建立一个存储空间
        pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) +
                                                        MT_RPC_FRAME_HDR_SZ + LEN_Token );


        if (pMsg)
        {
          /* Fill up what we can */
          pMsg->hdr.event = CMD_SERIAL_MSG;
          pMsg->msg = (uint8*)(pMsg+1);
          pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;
          state = CMD_STATE1;       //正确后跳转至CMD0
        }
        else
        {
          state = SOP_STATE;
          return;
        }
        break;


      case CMD_STATE1:    // CMD_STATE1
        pMsg->msg[MT_RPC_POS_CMD0] = ch;
        state = CMD_STATE2;       //跳转至CMD_STATE2
        break;


      case CMD_STATE2:    // CMD_STATE2
        pMsg->msg[MT_RPC_POS_CMD1] = ch;
        /* If there is no data, skip to FCS state */
        if (LEN_Token)
        {
          state = DATA_STATE;//跳转至数据接收状态
        }
        else
        {
          state = FCS_STATE;  //没有数据跳转只校验和
        }
        break;


      case DATA_STATE:  //接收数据


        /* Fill in the buffer the first byte of the data */
        pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen++] = ch;


        /* Check number of bytes left in the Rx buffer */
        bytesInRxBuffer = Hal_UART_RxBufLen(port);


        /* If the remain of the data is there, read them all, otherwise, just read enough */
        if (bytesInRxBuffer <= LEN_Token - tempDataLen)
        {
          HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], bytesInRxBuffer);
          tempDataLen += bytesInRxBuffer;
        }
        else
        {
          HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], LEN_Token - tempDataLen);
          tempDataLen += (LEN_Token - tempDataLen);
        }


        /* If number of bytes read is equal to data length, time to move on to FCS */
        if ( tempDataLen == LEN_Token )  //数据位接收完成,跳转校验
            state = FCS_STATE;   //数据接收完成跳转至数据校验


        break;


      case FCS_STATE:   //校验和--按位异或


        FSC_Token = ch;


        /* Make sure it's correct */   //如果信息接受正确
        if ((MT_UartCalcFCS ((uint8*)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ + LEN_Token) == FSC_Token))
        {
          osal_msg_send( App_TaskID, (byte *)pMsg );
        }
        else
        {
          /* deallocate the msg */
          osal_msg_deallocate ( (uint8 *)pMsg );
        }


        /* Reset the state, send or discard the buffers at this point */
        state = SOP_STATE;  //重新回到初始状态,检测帧头


        break;


      default:
       break;
    }
#if TEST  //自己加的,接收到的数据在发送回串口助手
    //For test UART
    HalUARTWrite(HAL_UART_PORT_0,(uint8*)&pMsg->msg[0],MT_RPC_FRAME_HDR_SZ + LEN_Token);
#endif   //end TEST
  }
}
注:
1.状态机:是通信里经常会有到的一种协议解析方式。
2.这个只是UART接收时的数据处理相当于底层的解析,还有更多指令解析在  zllInitiator_event_loop ( uint8 task_id, uint16 events )和zllSampleRemote_event_loop ( uint8 task_id, uint16 events ) 这两个函数中还有解析,改天继续写!

0 0
原创粉丝点击