例程学习之SampleApp--SPIMgr.c(MT层) SPIMgr_ProcessZToolData()

来源:互联网 发布:php utf8转换为gbk 编辑:程序博客网 时间:2024/06/05 02:28
学习协议栈的一个重要原因就是要通过协议栈和pc进行通信,而要完成通信过程需要对协议栈的MT层有一定的了解。MT层的SPIMgr.c文件主要处理串口相关的应用。串口这个概念之前听到过很多次,现在终于对它有了一些了解,欣慰啊~但是做出实物才是硬道理,程序只是看明白还是不够滴,修改成功才是王道~废话不多说,下面来看程序。

首先是串口的初始化函数:
void SPIMgr_Init ()
{
  halUARTCfg_t uartConfig;/halUARTCfg_t应该是一个关于串口的结构体,可以查查具体是怎么定义的

 
  App_TaskID = 0;

   配置串口相关的参数,包括波特率、流控制、接收缓存区、发送缓存区等
  uartConfig.configured           = TRUE;
  uartConfig.baudRate             = SPI_MGR_DEFAULT_BAUDRATE;
  uartConfig.flowControl          = SPI_MGR_DEFAULT_OVERFLOW;
  uartConfig.flowControlThreshold = SPI_MGR_DEFAULT_THRESHOLD;
  uartConfig.rx.maxBufSize        = SPI_MGR_DEFAULT_MAX_RX_BUFF;
  uartConfig.tx.maxBufSize        = SPI_MGR_DEFAULT_MAX_TX_BUFF;
  uartConfig.idleTimeout          = SPI_MGR_DEFAULT_IDLE_TIMEOUT;
  uartConfig.intEnable            = TRUE;
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)/如果设置了ZTOOL,就将数据发往MT层处理
  uartConfig.callBackFunc         = SPIMgr_ProcessZToolData;
#elif defined (ZAPP_P1) || defined (ZAPP_P2)/把数据送往应用任务App_TaskID
  uartConfig.callBackFunc         = SPIMgr_ProcessZAppData;
#else
  uartConfig.callBackFunc         = NULL;
#endif

SPIMgr_ProcessZToolData以及SPIMgr_ProcessZAppData这两个回调函数十分重要,在接下来的程序中就是在这两个函数中完成串口数据收发的工作。其中SPIMgr_ProcessZToolData中接收数据部分还完成了对接收到的数据进行打包并发送至MT层的任务(这部分占据了整个文档将近1/3的篇幅,重要性可见一斑哦~)。先在这里提个醒,具体内容在碰到程序时具体分析咯~

  打开串口
#if defined (SPI_MGR_DEFAULT_PORT)
  HalUARTOpen (SPI_MGR_DEFAULT_PORT, &uartConfig);/突然发现在串口收发过程中起关键作用的还是HalUARTXXXX系列,例如HalUARTRead、HalUARTWrite以及这里的HalUARTOpen
#else
 
  (void)uartConfig;
#endif

 
#if defined (ZAPP_P1) || defined (ZAPP_P2)
 
  SPIMgr_MaxZAppBufLen  = 1;
  SPIMgr_ZAppRxStatus   = SPI_MGR_ZAPP_RX_READY;
#endif
}

接下来上场的就是刚刚强调过的uart回调函数之一:SPIMgr_ProcessZToolRxData ~\(≧▽≦)/~
在下面的函数brief里面介绍了数据包的构造:一个字节的SOP(数据包起始字节),两个字节的命令标记,一个字节的数据长度(这个之后是具体数据,但是没有标记出来)以及一个字节的奇偶校验位。
void SPIMgr_ProcessZToolData ( uint8 port, uint8 event )
{
  uint8  ch;/设置一个字节的变量,从串口读入的数据首先放入这个变量中

 
  if (event == HAL_UART_TX_FULL)/这里就是传说中串口写数据的地方了,我之前以为会有一个专门 /的函数处理发送数据,没想到在协议栈里居然是个空~函~数~ 泪奔~o(>_<)o ~~ 自定义串口发送数据的 /时候应该自行添加HalUARTWrite()函数,具体我还没有尝试
  {
    // Do something when TX if full
    return;
  }

  if (event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT))/接收数据
  {
    while (Hal_UART_RxBufLen(SPI_MGR_DEFAULT_PORT))
    {
      HalUARTRead (SPI_MGR_DEFAULT_PORT, &ch, 1);/用HalUARTRead()函数将串口的数据一个字节一个字节的读入变量ch中
     
下面的state参数当初让我纠结了好久,在研究了半天程序之后自以为得到了一个差不多合理的解释,现在记录下来,如果有理解不正确的地方希望能早日更正~
state参数的值包括:
#define SOP_STATE      0x00
#define CMD_STATE1     0x01
#define CMD_STATE2     0x02
#define LEN_STATE      0x03
#define DATA_STATE     0x04
#define FCS_STATE      0x05
之后在程序的开始部分定义了state:
uint8 state;
个人的理解是,初始化后之后默认state的值为0,即上述的 
SOP_STATE
 
,所以下面的switch()函数一开始就进入
 case SOP_STATE,在判断读入的字节为数据包起始字节(SOP)之后,让state变为 
 CMD_STATE1
 
并跳出函数,接着判断下一个字节。
       switch (state)
      {
        case SOP_STATE:
          if (ch == SOP_VALUE)
            state = CMD_STATE1;
          break;

        case CMD_STATE1:
          CMD_Token[0] = ch;
          state = CMD_STATE2;
          break;

        case CMD_STATE2:
          CMD_Token[1] = ch;
          state = LEN_STATE;
          break;

        case LEN_STATE:
          LEN_Token = ch;
          if (ch == 0)
            state = FCS_STATE;
          else
            state = DATA_STATE;

          tempDataLen = 0;

在此处抛一个链接,小峰博主对于SPI_Msg及一下的程序有很精辟的解释,在此感谢博主~
http://wjf88223.blog.163.com/blog/static/35168001201052772511674/
         
          SPI_Msg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) + 2+1+LEN_Token );
          if (SPI_Msg)
          {
            构造数据包
            SPI_Msg->hdr.event = CMD_SERIAL_MSG;
            SPI_Msg->msg = (uint8*)(SPI_Msg+1);
            SPI_Msg->msg[0] = CMD_Token[0];
            SPI_Msg->msg[1] = CMD_Token[1];
            SPI_Msg->msg[2] = LEN_Token;
          }
          else
          {
            state = SOP_STATE;
            return;
          }

          break;

        case DATA_STATE:
            SPI_Msg->msg[3 + tempDataLen++] = ch;
            if ( tempDataLen == LEN_Token )
              state = FCS_STATE;
          break;

归纳:msg[0]和msg[1]是两字节命令标记;msg[2]是数据长度标记;msg[3]是EP号;msg[4]开始就是长度为msg[2]-1的具体数据了。

        case FCS_STATE:

          FSC_Token = ch;

         
          if ((SPIMgr_CalcFCS ((uint8*)&SPI_Msg->msg[0], 2 + 1 + LEN_Token) == FSC_Token))
          {
            osal_msg_send( MT_TaskID, (byte *)SPI_Msg );/将数据发送至MT层
          }
          else
          {
           
            osal_msg_deallocate ( (uint8 *)SPI_Msg);
          }

         
          state = SOP_STATE;

          break;

        default:
         break;
      }


    }
  }
}
#endif //ZTOOL

SPIMgr_ProcessZToolData函数就介绍完了,接下来是SPIMgr_ProcessZAppData()函数。因为目前没有用到这部分,所以下次再具体学习了。

0 0
原创粉丝点击