关于 z-Stack MT层的使用

MT层(也有叫MT包的)是Z-Stack自带的,TI公司提供的ZTOOL工具可以通过串口的方式来和模块通信,这个工具发送的数据具有一定的协议,MT层的函数就具有解析这些协议的功能,因此在使用MT层的函数的时候,必须要遵守TI公司提供的串口协议来发送和接收数据。协议如下:

 

0xFE:数据帧头 

DataLength:Datapayload的数据长度(不包括命令字节),以字节计,低字节在前;

CM0:命令低字节; 

CM1:命令高字节;(ZTOOL软件就是通过发送一系列命令给MT实现和协议栈交互) 

Data payload:数据帧具体的数据,这个长度是可变的,但是要和DataLength一致; 

FCS:校验和,从DataLength字节开始到Data payload最后一个字节所有字节的异或按字节操作;

 

在MT_UART.h中可以被外部调用的有这些函数:

extern void MT_UartInit (void);

extern uint8 MT_UartCalcFCS( uint8 *msg_ptr, uint8 length );

extern void MT_UartRegisterTaskID( uint8 taskID );

void MT_UartProcessZToolData ( uint8 port, uint8 taskId );

void MT_UartProcessZAppData ( uint8 port, uint8 event );

 


1、MT_UartInit 串口初始化函数:

void MT_UartInit ()

{

  halUARTCfg_t uartConfig;//定义串口配置参数的结构体,包括波特率、使能串口等等


  App_TaskID = 0;


  uartConfig.configured           = TRUE;

  uartConfig.baudRate             = MT_UART_DEFAULT_BAUDRATE;

  uartConfig.flowControl          = MT_UART_DEFAULT_OVERFLOW;

  uartConfig.flowControlThreshold = MT_UART_DEFAULT_THRESHOLD;

  uartConfig.rx.maxBufSize        = MT_UART_DEFAULT_MAX_RX_BUFF;

  uartConfig.tx.maxBufSize        = MT_UART_DEFAULT_MAX_TX_BUFF;

  uartConfig.idleTimeout          = MT_UART_DEFAULT_IDLE_TIMEOUT;

  uartConfig.intEnable            = TRUE;

/*预定义,作用是使用MT_UartProcessZToolData还是MT_UartProcessZAppData
 *MT_UartProcessZToolData为和官方的串口调试工具通信,
 *MT_UartProcessZAppData为传输app数据,这个需要做一些修改才可以使用*/

#if defined (ZTOOL_P1) || defined (ZTOOL_P2)

  uartConfig.callBackFunc         = MT_UartProcessZToolData;

#elif defined (ZAPP_P1) || defined (ZAPP_P2)

  uartConfig.callBackFunc         = MT_UartProcessZAppData;

#else

  uartConfig.callBackFunc         = NULL;//如果都不想用,那么就可以自己填一个串口处理回调函数

#endif



#if defined (MT_UART_DEFAULT_PORT)

  HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig);//串口初始化,调用上面的uartConfig作为参数,函数内还根据是否使用DMA来做不同的初始化

#else

  (void)uartConfig;

#endif



#if defined (ZAPP_P1) || defined (ZAPP_P2)//同样的预定义,先不管这两个参数作用

  MT_UartMaxZAppBufLen  = 1;

  MT_UartZAppRxStatus   = MT_UART_ZAPP_RX_READY;

#endif

}

这个函数主要就是完成了串口的初始化,以及串口DMA的配置,最后根据宏定义ZTOOL_P1、ZTOOL_P2来确定MT的回调函数,如果都没有定义的话那么就使用用户指定的函数。如果不想用官方提供的串口模块,可以参考MT的初始化来完成自己的串口初始化代码。下面为我写的串口初始化函数,写的不好,欢迎大佬指点。


static char Uart_RX[200];
static char Uart_TX[200];

static void FS_Uart_CallBack(uint8 port,uint8 event);


/*
*串口初始化函数
*UARTx:要操作的是串口几
*baud:串口波特率
*/
void usart_init(uint8 UARTx,uint8 baud)
{
  halUARTCfg_t uartConfig;
  
  assert(ASSERT_UART_BAUD(baud));
  assert(ASSERT_UARTX(UARTx));
  
  uartConfig.configured           = TRUE;              // 2x30 don't care - see uart driver.
  uartConfig.baudRate             = baud;
  uartConfig.flowControl          = FALSE;
  uartConfig.flowControlThreshold = 32; // 2x30 don't care - see uart driver.
  uartConfig.rx.maxBufSize        = 32;  // 2x30 don't care - see uart driver.
  uartConfig.tx.maxBufSize        = 32;  // 2x30 don't care - see uart driver.
  uartConfig.idleTimeout          = 6;   // 2x30 don't care - see uart driver.
  uartConfig.intEnable            = TRUE;              // 2x30 don't care - see uart driver.
  uartConfig.callBackFunc         = FS_Uart_CallBack;  //指定串口回调函数
  HalUARTOpen (UARTx, &uartConfig);
}

/*串口回调函数*/
static void FS_Uart_CallBack(uint8 port,uint8 event)
{
  if(( event & ( HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT ) ) ) 
  {   
    if(port == HAL_UART_PORT_0)
    {         
      uint16 len = Hal_UART_RxBufLen(HAL_UART_PORT_0); //取出本次接收到的字符长度              
      HalUARTRead(HAL_UART_PORT_0, Uart_RX, len); 
      if ( len > 0 )
      {
        //成功接收到数据,对数据进行处理
        osal_printf("%s",Uart_RX);
      }
    }
    else//port == HAL_UART_PORT_1
    {
        
    }
  }
}


//串口printf 函数
//确保一次发送数据不超过Uart_TX_LEN字节
void osal_printf(char* fmt,...)  
{  
  uint16 i,j; 
  va_list ap; 
  va_start(ap,fmt);
  vsprintf((char*)Uart_TX,fmt,ap);
  va_end(ap);
  i=strlen((const char*)Uart_TX);		//此次发送数据的长度
  for(j=0;j<i;j++)			//循环发送数据
  {
    HalUARTWrite(HAL_UART_PORT_0, &Uart_TX[j], 1); 
  } 
}

2、void MT_UartRegisterTaskID( uint8 taskID );

void MT_UartRegisterTaskID( byte taskID )//注册串口任务,在应用层中的任务注册

{

  App_TaskID = taskID;

}

3、void MT_UartProcessZToolData ( uint8 port, uint8 taskId );

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);//从RX缓冲区中读取一个字节



    switch (state)

    {

//state开始的值肯定是0x00(猜的),判断数据第一个字节是不是0xFE,如果是那么state = 0x03,以此类推,下面的也是这个意思

      case SOP_STATE:                      //SOP_STATE =  0x00

        if (ch == MT_UART_SOF)      //MT_UART_SOF = 0xFE

          state = LEN_STATE;            //LEN_STATE = 0x03

        break;



      case LEN_STATE:                    //LEN_STATE = 0x03

        LEN_Token = ch;



        tempDataLen = 0;





//这里的C语言语法有点难懂(对我来说),给pMsg分配内存空间,大小等于sizeof ( mtOSALSerialData_t )结构体大小+1个表示数据长度的标识符占用的空间+两个CMD占用的空间+数据占用的空间,注意这里最后强制转换成mtOSALSerialData_t这个结构体的指针,也就是pMsg指向了该分配内存的首地址,而且pMsg是mtOSALSerialData_t类型的。pMsg+1 等于pMsg+sizeof ( mtOSALSerialData_t )的大小,此时指向了数据的长度标识符。而且此时的协议第二个字节表示的数据的长度,ch = dataLength

        pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) +

                                                        MT_RPC_FRAME_HDR_SZ + LEN_Token );

        if (pMsg)

        {

          pMsg->hdr.event = CMD_SERIAL_MSG;

          pMsg->msg = (uint8*)(pMsg+1);

          pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;   //发送CMD_SERIAL_MSG

          state = CMD_STATE1;              //CMD_STATE1 = 0x01

        }

        else

        {

          state = SOP_STATE;

          return;

        }

        break;

//和下面的两个case都表示了CMD

      case CMD_STATE1:                       //CMD_STATE1 = 0x01

        pMsg->msg[MT_RPC_POS_CMD0] = ch;

        state = CMD_STATE2;                //CMD_STATE2 = 0x02

        break;

      case CMD_STATE2:

        pMsg->msg[MT_RPC_POS_CMD1] = ch;

        if (LEN_Token)

        {

          state = DATA_STATE;           //DATA_STATE = 0x04

        }

        else

        {

          state = FCS_STATE;                //FCS_STATE = 0x05

        }

        break;

//下面的case里就是处理数据的部分

      case DATA_STATE:

//对于刚刚接手的这个字节ch的处理

        pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen++] = ch;

//然后通过Hal_UART_RxBufLen这个函数看看Rx缓冲区还有多少个字节

        bytesInRxBuffer = Hal_UART_RxBufLen(port);

//如果Rx缓冲区的字节数<=(总长度 - 已读出的长度),那么一次性将缓冲区的数据读出来,否则就将(总长度 - 已读出的长度 )的数据读出来,这里很好理解,其实我认为这里数据处理在上面的 case CMD_STATE2:来完成就好了,就免去了读取第一个字节的数据这步了,可能为了更直观吧。

        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);

        }

//读完后,不要忘了把读取的数量更新下,全部读完后, state = FCS_STATE来看看是不是都读正确了

        if ( tempDataLen == LEN_Token )

            state = FCS_STATE;

        break;

      case FCS_STATE:           //FCS_STATE = 0x05

        FSC_Token = ch;

//通过校验位,来判断数据是否有错误

        if ((MT_UartCalcFCS ((uint8*)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ + LEN_Token) == FSC_Token))

        {

//如果正确,那么发送消息到应用层,这个消息是上面case LEN_STATE:中的

pMsg->hdr.event = CMD_SERIAL_MSG;

          osal_msg_send( App_TaskID, (byte *)pMsg );

        }

        else

        {

          osal_msg_deallocate ( (uint8 *)pMsg );

        }



        state = SOP_STATE;

        break;

      default:

       break;

    }

  }

}

4、void MT_UartProcessZAppData ( uint8 port, uint8 event );

这个函数就比较简单了,没有去分析那么多协议的东西

下面两个参数都是标志位,感觉没有特别大的用处。。。。

// MT_UartMaxZAppBufLen  = 1;

//  MT_UartZAppRxStatus   = MT_UART_ZAPP_RX_READY;

void MT_UartProcessZAppData ( uint8 port, uint8 event )

{



  osal_event_hdr_t  *msg_ptr;

  uint16 length = 0;

//确定Rx缓冲区数据长度

  uint16 rxBufLen  = Hal_UART_RxBufLen(MT_UART_DEFAULT_PORT);





//MT_UartMaxZAppBufLen一次最大处理数据的长度,查看缓冲区长度是否大于这个长度

  if ((MT_UartMaxZAppBufLen != 0) && (MT_UartMaxZAppBufLen <= rxBufLen))

  {

    length = MT_UartMaxZAppBufLen;

  }

  else

  {

    length = rxBufLen;

  }





  if (event == HAL_UART_TX_FULL)

  {

    // Do something when TX if full

    return;

  }

//一堆宏定义,没有深究到底有何作用,都是满足条件的

  if (event & ( HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT))

  {

//App_TaskID = taskID;初始化函数后,任务ID就已经不为0了

    if ( App_TaskID )

    {



//在初始化函数中串口状态标识符,且有数据

      if ((MT_UartZAppRxStatus == MT_UART_ZAPP_RX_READY ) && (length != 0))

      {



//关闭流控

         MT_UartAppFlowControl (MT_UART_ZAPP_RX_NOT_READY);





//分配内存,大小=数据长度+消息头长度

        msg_ptr = (osal_event_hdr_t *)osal_msg_allocate( length + sizeof(osal_event_hdr_t) );

        if ( msg_ptr )

        {

          msg_ptr->event = SPI_INCOMING_ZAPP_DATA;

          msg_ptr->status = length;





          HalUARTRead( MT_UART_DEFAULT_PORT, (uint8 *)(msg_ptr + 1), length );

//发送消息到应用层



          osal_msg_send( App_TaskID, (uint8 *)msg_ptr );

        }

      }

    }

  }

}

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值