前面的6部实验为基本的驱动外设实验,是学习使用基础,实验设备只需要一个cc2538cb节点;从这一部开始实验开始需要两个cc2538cb节点,开始zigbee的无线通信;
此次例程为TinyOS的核心协议栈BLIP,现在的版本是BLIP2.0;大家可以去TinyOS的官网搜索BLIP查看介绍;
如何理解BLIP呢?他的存在意义是什么?我们清楚zigbee到6lowpan的升级,zigbee芯片厂商并没有在硬件部分做6lowpan的压缩解压,这些的完成是纯软件实现的,也就需要一个zigbee(IEEE802.15.4)到6lowpan的转换桥梁,BLIP最重要的功能就是如此;
例程目录tinyos-main-release_tinyos_2_1_2\apps\cc2538_Test\blip\TestLinkLocal
例程为TinyOS的官方固件的代码,以后大家使用会发现我的这些例程基本不修改官方的例程,方便大家的兼容学习;
Makefile文件:
- COMPONENT=TestLinkLocalAppC
- CFLAGS += -DUSE_TIMER_HANDLER
- #CFLAGS += -DUSE_UART_HANDLER
- CFLAGS += -DUSE_RF_HANDLER
- CFLAGS += -DNOT_USE_PRINTFC_BUT_USE_PRINT
- PFLAGS += -DIN6_PREFIX=\"fec0::\"
-
- include $(MAKERULES)
- CFLAGS += -DIN6_NO_GLOBAL -DLIB6LOWPAN_HC_VERSION=-1
- CFLAGS += -DPRINTFUART_ENABLED
BLIP分为两种模式:短地址(16bit)和IEEE地址(8bytes/64bit)模式,默认采用短地址模式;注意如果后期的实验如边界路由,RPL,CoAP实验;通信都需要选择同一种模式;默认是短地址;大家在完成基本的通讯后可以修改Makefile,尝试IEEE地址模式;具体参考TinyOS官网BLIP文档;
TestLinkLocalAppC.nc文件:
- /** Test the link-local communication in the blip stack
- */
- configuration TestLinkLocalAppC {
-
- } implementation {
- components MainC, LedsC;
- components TestLinkLocalC;
- components IPStackC;
- components new TimerMilliC();
- components new UdpSocketC();
-
- TestLinkLocalC.Boot -> MainC;
- TestLinkLocalC.SplitControl -> IPStackC;
- TestLinkLocalC.Sock -> UdpSocketC;
- TestLinkLocalC.Timer -> TimerMilliC;
- TestLinkLocalC.Leds -> LedsC;
-
- components StaticIPAddressTosIdC; // Use TOS_NODE_ID in address
- //components StaticIPAddressC; // Use LocalIeee154 in address
- }
TestLinkLocalC.nc文件:
- /*******************************************************************
- *实验5----zigbee blip实验
- *节点需求数 >= 2
- *编译命令make cc2538cb blip id.xx (xx为1~65533)
- ********************************************************************/
- #include "blip_printf.h"
- #include <lib6lowpan/ip.h>
-
- module TestLinkLocalC {
- uses {
- interface Boot;
- interface SplitControl;
- interface UDP as Sock;
- interface Timer<TMilli>;
- interface Leds;
- }
- } implementation {
- nx_struct echo_state {
- nx_int8_t cmd;
- nx_uint32_t seqno;
- } m_data;
-
- enum {
- SVC_PORT = 10210,
- CMD_ECHO = 1,
- CMD_REPLY = 2,
- };
-
- /***************************************************
- *启动事件
- ****************************************************/
- event void Boot.booted() {
- call SplitControl.start();
- m_data.seqno = 0;
- }
-
- event void SplitControl.startDone(error_t e) {
- /**开启约2秒的周期性定时器(单位毫秒) Timer**/
- call Timer.startPeriodic(2048);
- /**端口绑定************************************/
- call Sock.bind(SVC_PORT);
- }
-
- event void SplitControl.stopDone(error_t e) {}
-
- /***************************************************
- *Timer定时时间到事件
- ****************************************************/
- event void Timer.fired() {
- struct sockaddr_in6 dest;
-
- inet_pton6("ff02::1", &dest.sin6_addr);
- dest.sin6_port = htons(SVC_PORT);
-
- m_data.cmd = CMD_ECHO;
- m_data.seqno ++;
- /***启动zigbee发送,可以自己修改发送内容和长度*****/
- call Sock.sendto(&dest, &m_data, sizeof(m_data));
- call Leds.led0Toggle();
- }
- /***************************************************
- *接收事件
- ****************************************************/
- event void Sock.recvfrom(struct sockaddr_in6 *src, void *payload,
- uint16_t len, struct ip6_metadata *meta) {
- nx_struct echo_state *cmd = payload;
- printf("TestLinkLocalC: recv from: ");
- printf_in6addr(&src->sin6_addr);
- printf("\n");
-
- if (cmd->cmd == CMD_ECHO) {
- cmd->cmd = CMD_REPLY;
- call Sock.sendto(src, payload, len);
- call Leds.led1Toggle();
- } else {
- printf("TestLinkLocalC: reply seqno: %li\n", cmd->seqno);
- call Leds.led2Toggle();
- }
- }
- }
如果大家对nesC语法还是不熟悉,可以先去看看前6部实验帖子;
nx_struct---等价于struct{}__attribute__ ((packed)) ;是为了兼容平台从8位单片机到32位arm的结构体对齐问题;常常使用的关键字;大家可以使用printf例程
测试一下一个struct里面有unsigned char/long成员后的sizeof打印和nx_struct的sizeof的区别;回忆2530的TinyOS代码,nesC编译成app.c后调用perl脚本对app.c进行转换,其中就必须注释掉了nx_struct生成的__attribute__ ((packed)) ;
call SplitControl.start();这句代码大家可以使用yeti2插件图形化组件去查看代码(见视频),手动的分析代码;或者生成的app.c去查看,完成了什么,BLIP的地址初始化;
这个例程有视频,没记错应该是第十四部视频;
SplitControl.startDone事件开启一个2.048秒的周期性定时器;绑定端口,看到这里大家肯定很熟悉了,Socket的写法
inet_pton6(...)函数,说明一下对于TinyOS我们清楚函数修饰是command,但是由于它支持C的所有特性,所以对于C函数的调用和C语言写法一样,不需要使用call关键字;
call Sock.sendto(&dest, &m_data, sizeof(m_data)); 核心发包部分,也是咱们可以去DIY的,可以DIY内容,接收方解析;比如LED控制,大家可以自己去写;或者和之前的例程结合一下咱们可以发送采集的片内温度,又或者将串口接收的数据发送,做一个聊天QQ;
例程本质在烧写两个节点完成通信,定义
CMD_ECHO = 1,
CMD_REPLY = 2,
发送方发送CMD_ECHO ,接收方解析后发送回CMD_REPLY ;例程简单,不做截图了;
需要注意编译命令从这一部开始因为是多节点的通信,我们需要make的时候添加options了,前六部的编译命令是make cc2538cb
这个例程编译命令为make cc2538cb blip id.xx
如两个节点 我们可以make cc2538cb blip id.1烧写
make cc2538cb blip id.2烧写完成实验;
blip的make选项是通知nesC编译器使用blip栈;