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


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