Simpliciti協議棧移植筆記一

第一次寫博客,覺得應該把學習的心得體會記下來!長期更新。希望能幫助到新手少走彎路,也希望能提出問題,大家一起討論,一起進步。轉載請標明出處。謝 謝 http://blog.csdn.net/libin55/article/details/51203727

簡要說明:

SimpliciTI 是TI針對簡單低射頻網絡的低功耗射頻協議。
支持兩種網絡拓撲結構,小型星型網絡與點對點通信,星型網絡最大支持30個節點,相對Zigbee協議棧而言,該協議棧資源小,僅需8KFlash左右,(本人大概佔用10K)移植也很簡單。可以很好的兼容小數據低功耗應用場合。
本章主要講解SimpliciTI星型網絡應用部分。

一、協議棧組網原理

現科普一下星型組網的原理吧!
首先,射頻模塊之間能進行正常的數據收發。我們規定在網絡中只允許存在一箇中心節點,他可以與網絡中任一子節點通信,這樣便實現了對網絡的監控與管理!
子節點與子節點是不能直接通信的,必須通過中心節點才能實現通信。下圖爲星型網絡拓撲結構圖,看圖就比較好理解了


二、星型網絡結構

星型網絡由三部分組成。
中心節點(AP):星型網絡的管理節點,是長供電的設備。單個網絡僅可允許存在一個AP,協議棧中不同網絡是通過宏定義JoinToken進行區分。
傳感節點(ED):傳感設備子節點,可進入睡眠模式(主要電池供電方式)。
範圍擴展(RE):擴展網絡的無線距離(路由功能),實際就是在轉發數據幀,以擴展發送者的有效距離。目前網絡最大支持4個RE,也屬於長供電設備。

二、協議棧移植

協議棧源碼可以到TI官網下載,可能官網下載比較慢,這裏就我直接上傳了。
安裝後會在根目錄生成Texas Instruments文件夾,裏面有對應的例程源碼與英文文檔。裏面對應的是IARfor8051與IARforMPS430的工程。這裏我就以8051的工程進行解讀把。


 


針對IAR上面的目錄文件講解一下吧
bsp:板級支持包,主要是板載的一些外圍器件的初始化與MCU寄存器的配置。
mrfi:射頻驅動的代碼,CC2530是嵌入射頻部分,內核是8051的。該文件內核心代碼爲mrfi_radio.c,關於射頻的配置接口都在這裏面。
nwk:網絡層底層數據發送與接收的接口,主要爲協議層部分。
nwk applications:網絡層上層應用代碼,實際開發中使用的接口。
我們如果需要移植其他平臺的話,其實只需要修改bsp與mrfi裏面的部分代碼,而網絡協議層是不需要進行修改的。

三、協議棧應用部分

好了,開始講應用部分!直接進入main函數,這段針對代碼講解。
void main (void)
{
  bspIState_t intState;


#ifdef FREQUENCY_AGILITY
  memset(sSample, 0x0, sizeof(sSample));
#endif
  
  BSP_Init();

  /* If an on-the-fly device address is generated it must be done before the
   * call to SMPL_Init(). If the address is set here the ROM value will not
   * be used. If SMPL_Init() runs before this IOCTL is used the IOCTL call
   * will not take effect. One shot only. The IOCTL call below is conformal.
   */
#ifdef I_WANT_TO_CHANGE_DEFAULT_ROM_DEVICE_ADDRESS_PSEUDO_CODE
  {
    addr_t lAddr;


    createRandomAddress(&lAddr);
    SMPL_Ioctl(IOCTL_OBJ_ADDR, IOCTL_ACT_SET, &lAddr);
  }
#endif /* I_WANT_TO_CHANGE_DEFAULT_ROM_DEVICE_ADDRESS_PSEUDO_CODE */


  SMPL_Init(sCB); //初始化通信系統和simpliciti的協議棧


  /* green and red LEDs on solid to indicate waiting for a Join. */
  if (!BSP_LED2_IS_ON())
  {
    toggleLED(2);
  }
  if (!BSP_LED1_IS_ON())
  {
    toggleLED(1);
  }


  /* main work loop */
  while (1)
  {
    /* manage FHSS schedule if FHSS is active */
    FHSS_ACTIVE( nwk_pllBackgrounder( false ) );
    
    /* Wait for the Join semaphore to be set by the receipt of a Join frame from a
     * device that supports an End Device.
     *
     * An external method could be used as well. A button press could be connected
     * to an ISR and the ISR could set a semaphore that is checked by a function
     * call here, or a command shell running in support of a serial connection
     * could set a semaphore that is checked by a function call.
     */
    if (sJoinSem && (sNumCurrentPeers < NUM_CONNECTIONS))
    {
      /* listen for a new connection */
      while (1)
      {
        if (SMPL_SUCCESS == SMPL_LinkListen(&sLID[sNumCurrentPeers]))
        {
          break;
        }
        /* Implement fail-to-link policy here. otherwise, listen again. */
      }


      sNumCurrentPeers++;


      BSP_ENTER_CRITICAL_SECTION(intState);
      sJoinSem--;
      BSP_EXIT_CRITICAL_SECTION(intState);
    }


    /* Have we received a frame on one of the ED connections?
     * No critical section -- it doesn't really matter much if we miss a poll
     */
    if (sPeerFrameSem)
    {
      uint8_t     msg[MAX_APP_PAYLOAD], len, i;


      /* process all frames waiting */
      for (i=0; i<sNumCurrentPeers; ++i)
      {
        if (SMPL_SUCCESS == SMPL_Receive(sLID[i], msg, &len))
        {
          processMessage(sLID[i], msg, len);


          BSP_ENTER_CRITICAL_SECTION(intState);
          sPeerFrameSem--;
          BSP_EXIT_CRITICAL_SECTION(intState);
        }
      }
    }
    if (BSP_BUTTON1())
    {
      SPIN_ABOUT_A_QUARTER_SECOND;  /* debounce */
      changeChannel();
    }
    else
    {
      checkChangeChannel();
    }
    BSP_ENTER_CRITICAL_SECTION(intState);
    if (sBlinky)
    {
      if (++sBlinky >= 0xF)
      {
        sBlinky = 1;
        toggleLED(1);
        toggleLED(2);
      }
    }
    BSP_EXIT_CRITICAL_SECTION(intState);
  }
}

main函數最開始是初始化板級支持包Bsp_Init();

接着初始化協議棧SMPL_Init(sCB);

這裏sCB對應的是回調函數,針對AP來說這個是必須加的,因爲AP(協調器)是肯定要接收ED(節點)的數據的。而對於只上報的節點設備,sCB就可以忽略。

整個程序的核心在接收中斷裏,很龐大,簡單解說就是通過數據幀剝離出端口,後面調用回調函數sCB,嚮應用層提示本幀數據是Join幀還是通用的數據幀。在main.c裏面定義了兩個全局變量。

static volatile uint8_t sPeerFrameSem = 0;  /*  數據幀標識,每接收到一楨新數據就會通過回調加一,然後主循環查詢進行數據的讀取 
static volatile uint8_t sJoinSem = 0;         /* Join幀標識變量,ED請求加入時會通過回調加一,主循環查詢後進行LINK的監聽*/
static uint8_t sCB(linkID_t lid)
{
  if (lid)
  {
    sPeerFrameSem++;
    sBlinky = 0;
  }
  else
  {
    sJoinSem++;
  }

  /* leave frame to be read by application. */
  return 0;
}

所以在mian函數裏面,一直輪詢sPeerFrameSem和sJoinSem兩個變量。
smplStatus_t SMPL_Receive(linkID_t lid, uint8_t *msg, uint8_t *len) 
讀取數據幀接口函數,lid針對ED而已是唯一的,AP的話是根據ED申請LINK時按順序分配的。*msg與*len就是接收數據的緩存與長度了
發送其實是一樣的意思
smplStatus_t SMPL_Send(linkID_t lid, uint8_t *msg, uint8_t len)
從上面的代碼來看,sCB函數內確實是這樣做的!其實TI代碼分層,程序模塊化寫的很好(很有借鑑意義),對於只關心應用的用戶來說,不需要關心具體底層的實現方法。主函數代碼可讀性比較高!降低代碼之間耦合性。
最後我們只需要根據變量標識去讀寫數據就可以了。

實際API接口比較多,下章我會細講接收中斷與協議棧本身的代碼。先上傳分中英文的API文檔把~英文不好的小夥伴們可以下載看看http://download.csdn.net/detail/libin55/9500682


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