Simpliciti协议栈移植笔记一

来源:互联网 发布:如何开淘宝店详细步骤 编辑:程序博客网 时间:2024/06/05 10:01

第一次写博客,觉得应该把学习的心得体会记下来!长期更新。希望能帮助到新手少走弯路,也希望能提出问题,大家一起讨论,一起进步。转载请标明出处。谢 谢 http://blog.csdn.net/libin55/article/details/51203727

简要说明:

SimpliciTI 是TI针对简单低射频网络的低功耗射频协议。
支持两种网络拓扑结构,小型星型网络与点对点通信,星型网络最大支持30个节点,相对Zigbee协议栈而言,该协议栈资源小,仅需8KFlash左右,(本人大概占用10K)移植也很简单。可以很好的兼容小数据低功耗应用场合。
本章主要讲解SimpliciTI星型网络应用部分。

一、协议栈组网原理

现科普一下星型组网的原理吧!
首先,射频模块之间能进行正常的数据收发。我们规定在网络中只允许存在一个中心节点,他可以与网络中任一子节点通信,这样便实现了对网络的监控与管理!
子节点与子节点是不能直接通信的,必须通过中心节点才能实现通信。下图为星型网络拓扑结构图,看图就比较好理解了


二、星型网络结构

星型网络由三部分组成。
中心节点(AP):星型网络的管理节点,是长供电的设备。单个网络仅可允许存在一个AP,协议栈中不同网络是通过宏定义JoinToken进行区分。
传感节点(ED):传感设备子节点,可进入睡眠模式(主要电池供电方式)。
范围扩展(RE):扩展网络的无线距离(路由功能),实际就是在转发数据帧,以扩展发送者的有效距离。目前网络最大支持4个RE,也属于长供电设备。

二、协议栈移植

协议栈源码可以到TI官网下载,可能官网下载比较慢,这里就我直接上传了。
下载地址http://download.csdn.net/detail/libin55/9499966  
安装后会在根目录生成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


2 0
原创粉丝点击