車乾的ZigBee學習筆記九—設備間的第一次對話

一、功能要求

1:協調器組建PAN網絡
2:協調器組網成功後會週期性廣播“I am coordinator device ! ”(週期爲5S)
3: 終端設備節點加入該PAN網絡,加入網絡成功後週期性廣播字符串“I am endpoint device ! ”(週期爲 5S)

二、實現過程(下面的多個代碼塊代表不同的.c文件,用於對照自己的協議棧)

首先需要在電腦C盤,找到TI公司的文件夾,C:\Texas Instruments\ZStack-CC2530-2.3.0-1.4.0\Projects\zstack\Samples,將samples中的samples APP進行復制,進入samples文件夾,打開.eww文件。

**第一步:**因爲我們用到了串口和字符串,所以我們首先要加入兩個頭文件 #include “mt_uart.h” //串口 #include “string.h” //字符串

**第二步:**加入頭文件以後,我們需要做的就是設置我們的串口,既然要設置我們的串口,那麼我們必然就要調用我們的串口初始化函數MT_UartInit(); ,此函數定義於MT層的MT_UART.c文件

**第三步:**調用完我們的串口初始化函數,自然要進入此函數設置我們的波特率,以及確保流控爲關閉狀態。

**第四步:**串口初始化成功之後,我們在這裏通過串口打印一句話,
串口的打印接口 extern uint16 HalUARTWrite ( uint8 port, uint8 *pBuffer, uint16 length ); 是在HAL層的hal_uart.h頭文件內
uint8 port指的是串口號,uint8 *pBuffer指實際要發送的字符串,uint16 length指要發送字符串的長度

第五步:這裏我們先不做改動。瞭解一下void SampleApp_Init( uint8 task_id ) 這個函數中的幾個變量
SampleApp_TaskID = task_id; //任務優先級
SampleApp_NwkState = DEV_INIT; //當前設備在無線網絡中的網絡狀態 DEV_INIT;爲宏定義,初始狀態
SampleApp_TransID = 0; //發送數據包的一個序列號,現在初始化爲0,以後ZigBee每發送一個數據出去,這個序列號就會自動加一,可以根據這個序列號以及接收方真正接收到的數據的多少,計算丟包率

**第六步:**繼續往下,到了我們對地址的設置,我們設置爲廣播通信,地址爲0XFFFF
SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast; //地址模式,此處爲Broadcast,設置爲廣播模式
SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF; //設置廣播模式的地址 0XFFFF

**第七步:**設置完串口以及廣播相關的東西后,那麼我們就到了事件處理函數uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) 它們在這裏看一下它的具體運作過程:

	     首先呢,他是先通過 if ( events & SYS_EVENT_MSG )這條語句判斷是否真的產生了SYS_EVENT_MSG這一事件。
	 		這個事件是一個系統消息事件,同時又是一個強制事件。
		 意思就是隻要協議棧運行起來了,那麼這一個事件就會被觸發,所以會執行這個事件處理函數。
		 一般情況一個事件產生的同時,他會額外的附加產生一些事件和一些數據。
		 協議棧把這些附加的東西打包成一個消息結構體,並把這些消息結構體依次放到消息隊列裏去

		然後我們如何從消息隊列裏面去提取當前任務的消息結構體呢,用的就是 
		MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );   中的    osal_msg_receive函數

		再下面是常用的三個額外事件,具體內容見下面的sampleAPP.c代碼塊
		第一個,是否有按鍵按下
		第二個,是否有新的無線消息到達了
		第三個,是否當前設備的網絡狀態改變了
		在第三個事件這裏,不同網絡狀態的宏定義需要了解一下
		if ( (SampleApp_NwkState == DEV_ZB_COORD)//DEV_ZB_COORD代表協調器
		          || (SampleApp_NwkState == DEV_ROUTER)   //DEV_ROUTER代表路由器
  	 	         || (SampleApp_NwkState == DEV_END_DEVICE) )//DEV_END_DEVICE代表終端
	還需要注意的一點是,在第三個額外事件中,調用了一個定時器函數
	osal_start_timerEx( SampleApp_TaskID,
                          SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
                          SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
 隔一段時間後觸發一個SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件,並在後面對這個事件進行了一個判斷,並再次調用此函數,			       					配合發送消息的函數,構成了週期發送消息的效果 。

**第八步:**那麼具體是怎麼發送消息,請看void SampleApp_SendPeriodicMessage( void ),具體的函數說明,在sampleAPP.c代碼塊中做了註解

**第九步:**看完怎麼發送消息,接下來必然是到了接收消息的部分,請看發送函數上面的
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) 接收函數
從整體的流程來講,接收到了消息,最先進入的應該是事件處理函數,並且觸發額外事件二:接受到新的無線消息,然後由額外事件二中的接收函數的函數接口,進入接收函數MessageMSGCB( afIncomingMSGPacket_t *pkt )

**第十步:**進入接收函數以後,首先對命令號進行一個判斷,然後根據命令號進行相應的處理。確認命令號之後,我們首先需要調用串口打印函數,打印一下消息。那麼具體哪個是真正要的消息呢?我們進入結構體 afIncomingMSGPacket_t *pkt 中查看
*進入之後我們可以看到許多變量,而我們真正需要的只有 afMSGCommandFormat_t cmd; / Application Data */ *這一個變量,我們再進入afMSGCommandFormat這個結構體,看看這個變量都具體包含哪些東西

typedef struct
{
  byte   TransSeqNumber;   //傳送序列號
  uint16 DataLength;               // 數據長度
  byte  *Data;     //真正的數據
} afMSGCommandFormat_t;

**第十一步:**編譯我們的工程,將不需要的功能模塊前加x去掉
在這裏插入圖片描述
然後點擊編譯,下入硬件,就OK了

代碼塊一:sampleAPP.c

//sampleAPP.c
#include "OSAL.h"
#include "ZGlobals.h"
#include "AF.h"
#include "aps_groups.h"
#include "ZDApp.h"

#include "SampleApp.h"
#include "SampleAppHw.h"

#include "OnBoard.h"

/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"

#include "mt_uart.h"  //串口
#include "string.h" //字符串

// This list should be filled with Application specific Cluster IDs.
const cId_t SampleApp_ClusterList[SAMPLEAPP_MAX_CLUSTERS] =
{
  SAMPLEAPP_PERIODIC_CLUSTERID,
  SAMPLEAPP_FLASH_CLUSTERID
};

const SimpleDescriptionFormat_t SampleApp_SimpleDesc =
{
  SAMPLEAPP_ENDPOINT,              //  int Endpoint;
  SAMPLEAPP_PROFID,                //  uint16 AppProfId[2];
  SAMPLEAPP_DEVICEID,              //  uint16 AppDeviceId[2];
  SAMPLEAPP_DEVICE_VERSION,        //  int   AppDevVer:4;
  SAMPLEAPP_FLAGS,                 //  int   AppFlags:4;
  SAMPLEAPP_MAX_CLUSTERS,          //  uint8  AppNumInClusters;
  (cId_t *)SampleApp_ClusterList,  //  uint8 *pAppInClusterList;
  SAMPLEAPP_MAX_CLUSTERS,          //  uint8  AppNumInClusters;
  (cId_t *)SampleApp_ClusterList   //  uint8 *pAppInClusterList;
};


endPointDesc_t SampleApp_epDesc;


uint8 SampleApp_TaskID;   // Task ID for internal task/event processing
                          // This variable will be received when
                          // SampleApp_Init() is called.
devStates_t SampleApp_NwkState;

uint8 SampleApp_TransID;  // This is the unique message ID (counter)

afAddrType_t SampleApp_Periodic_DstAddr;
afAddrType_t SampleApp_Flash_DstAddr;

aps_Group_t SampleApp_Group;

uint8 SampleAppPeriodicCounter = 0;
uint8 SampleAppFlashCounter = 0;

/*********************************************************************
 * LOCAL FUNCTIONS
 */
void SampleApp_HandleKeys( uint8 shift, uint8 keys );
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void SampleApp_SendPeriodicMessage( void );
void SampleApp_SendFlashMessage( uint16 flashTime );


 */
void SampleApp_Init( uint8 task_id )
{
  SampleApp_TaskID = task_id;    //任務優先級
  SampleApp_NwkState = DEV_INIT;   //當前設備在無線網絡中的網絡狀態   DEV_INIT;爲宏定義,初始狀態
  SampleApp_TransID = 0;		//發送數據包的一個序列號,現在初始化爲0,以後ZigBee每發送一個數據出去,這個序列號就會自動加一,可以根據這個序列號以及接收方真正接收到的數據的多少,計算丟包率
  
  MT_UartInit ();  //調用串口初始化函數,進行波特率設置,並關閉流控
  HalUARTWrite ( 0, "uart0 is ok\n",strlen("uart0 is ok\n"));  //在這裏我們 設置串口號爲0,發送的字符串爲uart0 is ok,然後計算字符串長度
 
 #if defined ( BUILD_ALL_DEVICES )
  if ( readCoordinatorJumper() )
    zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
  else
    zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES

#if defined ( HOLD_AUTO_START )
  ZDOInitDevice(0);
#endif
 //此處用於設置模式,以及模式地址
  SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;  //地址模式,此處爲Broadcast,設置爲廣播模式
  SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;  //設置廣播模式的地址 0XFFFF 
  
  //接下來是對設備的端口描述符進行成員的複製,一般情況下也不需要做改動
  SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_epDesc.task_id = &SampleApp_TaskID;
  SampleApp_epDesc.simpleDesc
            = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;
  SampleApp_epDesc.latencyReq = noLatencyReqs;
  
  

  // 向AF註冊端點描述
  afRegister( &SampleApp_epDesc );

  // Register for all key events - This app will handle all key events
  RegisterForKeys( SampleApp_TaskID );
  

#if defined ( LCD_SUPPORTED )
  HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );
#endif
}

//下面是當我們的協議棧運行起來之後一定會調用的一個事件處理函數,我們看一下他的具體運行過程

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  afIncomingMSGPacket_t *MSGpkt;
  (void)task_id;  
/*
  首先呢,他是先判斷是否真的產生了SYS_EVENT_MSG這一事件。
  這個事件是一個系統消息事件,同時又是一個強制事件。
  意思就是隻要協議棧運行起來了,那麼這一個事件就會被觸發,所以會執行這個事件處理函數。
  一般情況一個事件產生的同時,他會額外的附加產生一些事件和一些數據。
  協議棧把這些附加的東西打包成一個消息結構體,並把這些消息結構體依次放到消息隊列裏去
  
  */
  if ( events & SYS_EVENT_MSG )
  {
    //那麼如何從消息隊列裏面去提取當前任務的消息結構體呢,用的就是osal_msg_receive函數
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    while ( MSGpkt )
    {
      //常用的一些產生的額外事件有以下三個
      //然後再對提取的消息結構體進行拆包,可以看到 switch ( MSGpkt->hdr.event )他產生了一些額外的事件
      switch ( MSGpkt->hdr.event )
      {
        // 第一個,是否有按鍵按下
        case KEY_CHANGE:
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          break;

        // 第二個,是否有新的無線消息到達了
        case AF_INCOMING_MSG_CMD:
          SampleApp_MessageMSGCB( MSGpkt );
          break;

        // 第三個,是否當前設備的網絡狀態改變了
        case ZDO_STATE_CHANGE:
          SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
          //如果協調器創建網絡成功的時候,他的網絡狀態會由初始值變爲協調器狀態
          //所以說,如果我們使用協調器創建網絡的時候勢必會觸發此事件,那麼網絡狀態改變後會調用定時器osal_start_timerEx
          if ( (SampleApp_NwkState == DEV_ZB_COORD)//DEV_ZB_COORD代表協調器
              || (SampleApp_NwkState == DEV_ROUTER)   //DEV_ROUTER代表路由器
              || (SampleApp_NwkState == DEV_END_DEVICE) )//DEV_END_DEVICE代表終端
          {
            // Start sending the periodic message in a regular interval.
            //隔一段時間之後會觸發一個事件,那麼在下一次事件輪詢之前,觸發此事件後,協議棧將進行什麼操作呢?
            //下面看if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )這個函數
            osal_start_timerEx( SampleApp_TaskID,
                              SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
                              SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );//這個參數決定隔多長時間
          }
          else
          {
            // Device is no longer in the network
          }
          break;

        default:
          break;
      }

      // Release the memory
      osal_msg_deallocate( (uint8 *)MSGpkt );

      // Next - if one is available
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    }

    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }

  // Send a message out - This event is generated by a timer
  //  (setup in SampleApp_Init()).
  if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
  {
    //發送消息
    SampleApp_SendPeriodicMessage();  

    // 此處又調用定時器觸發事件,
    //在下次輪詢時又產生SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件
    //再次循環回來,5S一次,構成週期性發送消息,
    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
        (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );

    // return unprocessed events
    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
  }

  // Discard unknown events
  return 0;
}

void SampleApp_HandleKeys( uint8 shift, uint8 keys )
{
  (void)shift;  // Intentionally unreferenced parameter
  
  if ( keys & HAL_KEY_SW_1 )
  {
    /* This key sends the Flash Command is sent to Group 1.
     * This device will not receive the Flash Command from this
     * device (even if it belongs to group 1).
     */
    SampleApp_SendFlashMessage( SAMPLEAPP_FLASH_DURATION );
  }

  if ( keys & HAL_KEY_SW_2 )
  {
    /* The Flashr Command is sent to Group 1.
     * This key toggles this device in and out of group 1.
     * If this device doesn't belong to group 1, this application
     * will not receive the Flash command sent to group 1.
     */
    aps_Group_t *grp;
    grp = aps_FindGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );
    if ( grp )
    {
      // Remove from the group
      aps_RemoveGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );
    }
    else
    {
      // Add to the flash group
      aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
    }
  }
}

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
  uint16 flashTime;

  switch ( pkt->clusterId )//首先對發送的命令號進行判斷
  {
    case SAMPLEAPP_PERIODIC_CLUSTERID: //發送的也是這個命令號
      //確認後,打印消息,同上面的串口打印函數
      HalUARTWrite ( 0, (pkt->cmd).Data,(pkt->cmd). DataLength);  
      //進入上面的afIncomingMSGPacket_t *pkt結構體,找一下哪一個真正存放着數據
      break;

    case SAMPLEAPP_FLASH_CLUSTERID:
      flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );
      HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );
      break;
  }
}

void SampleApp_SendPeriodicMessage( void )
{
  uint *buff=NULL;  //首先定義一個緩存區
  //通過全局變量來判斷是協調器還是終端
  /*協議棧第190行左右的 
  if ( readCoordinatorJumper() )
    zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
  else
    zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;這個判斷中
    zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;全局變量可以代表ZigBee設備的邏輯類型
  */
  if(zgDeviceLogicalType == ZG_DEVICETYPE_COORDINATOR;)//ZG_DEVICETYPE_COORDINATOR  這個宏定義代表協調器
  													//goto 一下這個宏定義可以看到其他邏輯類型的宏定義名稱
  {
    buff="I am coordinator device\n";
  }
  else if(zgDeviceLogicalType == ZG_DEVICETYPE_ENDDEVICE )//ZG_DEVICETYPE_ENDDEVICE代表終端
  {
    buff="I am endpoint device";
  }
  //它的第一個參數,代表發送目的地地址,作用:找到網絡中的設備
  //第二個參數,端口描述符,作用:選中該設備上的某個端口
  //第三個參數,發送一個命令號,涉及到ZigBee裏的一個簇的概念
  //第四個參數,發送數據的長度
  //第五個參數,真正發送的數據
  //第五個參數,一個指針,代表發送數據包的序列號,用來計算丟包率的一個變量
  //後兩個參數不需要改動,做傳參就可以
  if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_PERIODIC_CLUSTERID,
                       strlen(buff),//此處用strlen計算數據包長度
                       buff,//發送實際數據,到這裏發送數據設置完畢,下面看接收數據,回到剛纔三個常用事件中的收到無線消息
                       &SampleApp_TransID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
  }
  else
  {
    // Error occurred in request to send.
  }
}

void SampleApp_SendFlashMessage( uint16 flashTime )
{
  uint8 buffer[3];
  buffer[0] = (uint8)(SampleAppFlashCounter++);
  buffer[1] = LO_UINT16( flashTime );
  buffer[2] = HI_UINT16( flashTime );

  if ( AF_DataRequest( &SampleApp_Flash_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_FLASH_CLUSTERID,
                       3,
                       buffer,
                       &SampleApp_TransID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
  }
  else
  {
    // Error occurred in request to send.
  }
}


代碼塊二:MT_uart.c

#include "ZComDef.h"
#include "OSAL.h"
#include "hal_uart.h"
#include "MT.h"
#include "MT_UART.h"
#include "OSAL_Memory.h"


/***************************************************************************************************
 * MACROS
 ***************************************************************************************************/

/***************************************************************************************************
 * CONSTANTS
 ***************************************************************************************************/
/* State values for ZTool protocal */
#define SOP_STATE      0x00
#define CMD_STATE1     0x01
#define CMD_STATE2     0x02
#define LEN_STATE      0x03
#define DATA_STATE     0x04
#define FCS_STATE      0x05

/***************************************************************************************************
 *                                         GLOBAL VARIABLES
 ***************************************************************************************************/
/* Used to indentify the application ID for osal task */
byte App_TaskID;

/* ZTool protocal parameters */
uint8 state;
uint8  CMD_Token[2];
uint8  LEN_Token;
uint8  FSC_Token;
mtOSALSerialData_t  *pMsg;
uint8  tempDataLen;

#if defined (ZAPP_P1) || defined (ZAPP_P2)
uint16  MT_UartMaxZAppBufLen;
bool    MT_UartZAppRxStatus;
#endif

void MT_UartInit ()
{
  halUARTCfg_t uartConfig;

  /* Initialize APP ID */
  App_TaskID = 0;

  /* UART Configuration */
  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;
#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

  /* Start UART */
#if defined (MT_UART_DEFAULT_PORT)
  HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig);
#else
  /* Silence IAR compiler warning */
  (void)uartConfig;
#endif

  /* Initialize for ZApp */
#if defined (ZAPP_P1) || defined (ZAPP_P2)
  /* Default max bytes that ZAPP can take */
  MT_UartMaxZAppBufLen  = 1;
  MT_UartZAppRxStatus   = MT_UART_ZAPP_RX_READY;
#endif

}

void MT_UartRegisterTaskID( byte taskID )
{
  App_TaskID = taskID;
}

byte MT_UartCalcFCS( uint8 *msg_ptr, uint8 len )
{
  byte x;
  byte xorResult;

  xorResult = 0;

  for ( x = 0; x < len; x++, msg_ptr++ )
    xorResult = xorResult ^ *msg_ptr;

  return ( xorResult );
}


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:
        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;
        }
        else
        {
          state = SOP_STATE;
          return;
        }
        break;

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

      case 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 defined (ZAPP_P1) || defined (ZAPP_P2)

void MT_UartProcessZAppData ( uint8 port, uint8 event )
{

  osal_event_hdr_t  *msg_ptr;
  uint16 length = 0;
  uint16 rxBufLen  = Hal_UART_RxBufLen(MT_UART_DEFAULT_PORT);

  /*
     If maxZAppBufferLength is 0 or larger than current length
     the entire length of the current buffer is returned.
  */
  if ((MT_UartMaxZAppBufLen != 0) && (MT_UartMaxZAppBufLen <= rxBufLen))
  {
    length = MT_UartMaxZAppBufLen;
  }
  else
  {
    length = rxBufLen;
  }

  /* Verify events */
  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))
  {
    if ( App_TaskID )
    {
      /*
         If Application is ready to receive and there is something
         in the Rx buffer then send it up
      */
      if ((MT_UartZAppRxStatus == MT_UART_ZAPP_RX_READY ) && (length != 0))
      {
        /* Disable App flow control until it processes the current data */
         MT_UartAppFlowControl (MT_UART_ZAPP_RX_NOT_READY);

        /* 2 more bytes are added, 1 for CMD type, other for length */
        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;

          /* Read the data of Rx buffer */
          HalUARTRead( MT_UART_DEFAULT_PORT, (uint8 *)(msg_ptr + 1), length );

          /* Send the raw data to application...or where ever */
          osal_msg_send( App_TaskID, (uint8 *)msg_ptr );
        }
      }
    }
  }
}

void MT_UartZAppBufferLengthRegister ( uint16 maxLen )
{
  /* If the maxLen is larger than the RX buff, something is not right */
  if (maxLen <= MT_UART_DEFAULT_MAX_RX_BUFF)
    MT_UartMaxZAppBufLen = maxLen;
  else
    MT_UartMaxZAppBufLen = 1; /* default is 1 byte */
}


void MT_UartAppFlowControl ( bool status )
{

  /* Make sure only update if needed */
  if (status != MT_UartZAppRxStatus )
  {
    MT_UartZAppRxStatus = status;
  }

  /* App is ready to read again, ProcessZAppData have to be triggered too */
  if (status == MT_UART_ZAPP_RX_READY)
  {
    MT_UartProcessZAppData (MT_UART_DEFAULT_PORT, HAL_UART_RX_TIMEOUT );
  }

}

#endif //ZAPP

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章