IoT开发实战:CoAP卷【3.0】

10.3.2 native入门示例

下面我们在Instant Contiki中实现一个最为简单的“hello world”示例,该示例位于examples/hello-world目录中,通过cd指令进入该目录后运行“make TARGET=native”便可生成可执行文件,具体操作步骤如下:

# 进入hello-world目录cd ~/contiki/exapmples/hello-world # 使用native平台

make TARGET=native

TARGET参数用于指定平台,native平台是Contiki所支持的平台中较为特殊的平台,native平台一般特指Linux平台,该平台在Linux系统内仿真Contiki系统所需的运行环境。此时经make编译获得的可执行文件为hello-world.native,该文件可在Linux系统中直接运行。在控制台中输入“./hello-world.native”可获得类似输出。

# 运行可执行文件./hello-world.native
./hello-world.native
# contiki-main.c中输出
Contiki-3.x-2906-g14bfaff started with IPV6, RPL
Rime started with address 1.2.3.4.5.6.7.8
MAC nullmac RDC nullrdc NETWORK sicslowpan
Tentative link-local IPv6 address fe80:0000:0000:0000:0302:0304:0506:0708
# hello world.c中输出
Hello, world
# 使用Ctrl+c 退出

控制台中除了输出“Hello,world”之外,还给出了很多提示信息,这些提示信息由native平台下的contiki-main.c中输出,而hello-world.c中仅输出“Hello,world”。下面我们再来分析helloworld.c文件,hello-world.c的具体实现如下:

代码清单10-1 native hello-world.c

#include "contiki.h"
#include <stdio.h>
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
printf("Hello, world
");
PROCESS_END();
}

虽然hello-world.c示例非常简单,但已经包括了protothread机制涉及的常用宏定义——PROCESS(…)、PROCESS_THREAD(…)、PROCESS_BEGIN()、PROCESS_END()和AUTOSTART_PROCESSES(…)。

·PROCESS(hello_world_process,”Hello world process”):PROCESS宏用于任务声明,此处声明一个hello_world_process任务。

·AUTOSTART_PROCESSES(&hello_world_process):AUTOSTART_PROCESSES宏用于设置“自启动”任务,hello_world_process任务加入到自启动任务列表中,Contiki操作系统完成初始化工作之后便会启动该任务。

·PROCESS_THREAD(hello_world_process,ev,data){}:在任务主体中,任务主体总是以PROCESS_BEGIN()开始并以PROCESS_END()结束,此处hello_world_process任务中并没有while(1)循环结构,所以任务运行一次。

10.3.3 安装交叉工具链

一个入门级别的“Hello World”示例虽然并没有太多的使用价值,但是该示例却展现了使用protothread的基本方法,现在我们可以把native的成功经验迁移到CC2538dk/SensorTag平台中。SensorTag平台和native平台不同,SensorTag平台的开发依赖于gcc-arm-embedded交叉工具链。gcc-arm-embedded交叉工具链的更多信息请参考:https://launchpad.net/gcc-arm-embedded。下面介绍gcc-arm-embedded工具链安装的两种方法:Ubuntu PPA方法和软件包直接安装法。

1.Ubuntu PPA方法

如果使用Ubuntu发行版,可通过Ubuntu PPA服务安装较新版本的gcc-arm-embedded交叉工具链,在控制台中依次输入以下指令:

# Instant Contiki中已经预装了gcc-arm-embedded工具链
# 可使用apt-get remove指令卸载该旧工具链
sudo apt-get remove gcc-arm-none-eabi
# 增加gcc-arm-embedded软件源仓库
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
# 更新软件源
sudo apt-get update
# 安装gcc-arm-embedded
sudo apt-get install gcc-arm-embedded

2.软件包直接安装法

其他Linux发行版也可以通过下载软件包的方式安装gcc-arm-embedded交叉工具链。下面以gcc-arm-none-eabi 5.4版本为例说明安装gcc-arm-embedded的具体方法。

# 获取gcc-arm-embedded软件安装包
wget https://launchpadlibrarian.net/287101520/gcc-arm-none-eabi-5_4-2016q3-20160926-
linux.tar.bz2
# 复制安装包到/usr/local目录
sudo cp gcc-arm-none-eabi-5_4-2016q3-20160926-linux.tar.bz2 /usr/local
# 在/usr/local目录下解压软件安装包
cd /usr/local
sudo tar -jxvf gcc-arm-none-eabi-5_4-2016q3-20160926-linux.tar.bz2

把gcc-arm-none-eabi-5_4解压至/usr/local之后,并不能立即使用gcc-arm-embedded工具链,还需要把交叉工具链的具体路径加入到用户环境变量中。
 

# 使用nano打开bashrc
sudo nano ~/.bashrc
# 在bashrc文件的最后一行增加
PATH=$PATH:/usr/local/gcc-arm-none-eabi-5_4-2016q3/bin
# 退出nano
# 立即更新环境变量
source ~/.bashr

3.安装验证

完成交叉工具链安装之后,在控制台中输入“arm-none-eabi-gcc-v”便可查看该工具是否安装成功,若交叉工具链安装成功可在控制台中看到如图10-8所示内容。

10.3.4 SensorTag入门示例

完成了交叉工具链的安装之后,我们立马着手SensorTag平台上的“Hello World”示例。SensorTag的“Hello World”示例比native的“Hello World”示例更复杂一些。

1.修改makefile.user.include

与设备相关的代码均位于本书代码仓库the_beginning_of_coap/microsystem_device目录中,该目录下有一个名为makefile.user.include的文件,该文件用于指定Contiki源代码的具体位置,在前面的小节中Contiki源代码被复制至user用户根目录中,那么Contiki源代码的绝对位置为/home/user/contiki。请根据实际情况修改Contiki源代码的具体位置,否则将导致SensorTag入门示例和其他所有示例编译失败。makefile.user.include的具体内容如下:

APPDIRS+=$(USER_FOLDER)/apps
TARGETDIRS+=$(USER_FOLDER)/platform
#指定contiki源代码目录位置
# 请务必根据实际情况修改
CONTIKI=/home/user/contiki
include $(CONTIKI)/Makefile.include

图10-8 验证arm-none-eabi-gcc工具链

2.hello-world.c

SensorTag入门示例位于/examples/sensortag/hello-world目录中,该文件夹中包括:hello-world.c、project-conf.h、Makefile.target和Makefile四个文件,其中hello-world.c文件的具体内容如下:

代码清单10-2 SensorTag hello-world.c

#include "contiki.h"
#include "dev/leds.h"
#include "net/ipv6/uip-ds6.h"
#include <stdio.h>
PROCESS(hello_world_process, "hello world process");
PROCESS(simple_process, "simple process");
AUTOSTART_PROCESSES(&hello_world_process);
PROCESS_THREAD(hello_world_process, ev, data)
{
static struct etimer et_red;
PROCESS_BEGIN();
etimer_set(&et_red, CLOCK_SECOND / 8);
printf("hello world!
");
while(1) {
PROCESS_YIELD();
if(ev == PROCESS_EVENT_TIMER && etimer_expired(&et_red)) {
if(uip_ds6_get_global(ADDR_PREFERRED) != NULL) {
leds_off(LEDS_RED);
printf("device has joined the net
");
process_start(&simple_process, NULL);
} else {
leds_toggle(LEDS_RED);
etimer_set(&et_red, CLOCK_SECOND / 8);
}
}
} P
ROCESS_END();
}P
ROCESS_THREAD(simple_process, ev, data)
{
static struct etimer et_green;
PROCESS_BEGIN();
printf("simple process
");
etimer_set(&et_green, CLOCK_SECOND / 4);
while(1) {
PROCESS_YIELD();
if(ev == PROCESS_EVENT_TIMER && etimer_expired(&et_green)) {
leds_toggle(LEDS_GREEN);
etimer_set(&et_green, CLOCK_SECOND / 4);
}
}P
ROCESS_END();
}

ello-world.c中包含两个任务:hello_world_process和simple_process。hello_world_process任务周期性查看设备是否已经获得IPv6网络前缀,如果暂未分配到网络前缀,则令红色LED不停闪烁;如果已经分配到网络前缀,那么关闭红色LED并启动simple_process任务。
 

·PROCESS(hello_world_process,"hello world process"):声明hello_world_process任务,并把该任务设置为自启动。
·PROCESS(simple_process,"simple process"):声明simple_process任务。·static struct etimer et_red;etimer_set(&et_red,CLOCK_SECOND/8):在hello_world_process任务中增加一个etimer定时器,该定时器为Contiki中的一个默认组件,定时器的溢出时间为
CLOCK_SECOND/8也就是125ms。
·PROCESS_YIELD():任务挂起等待系统时间。
·if(ev==PROCESS_EVENT_TIMER&&etimer_expired(&et_red)):任务获得一个定时器事件,且定时器etimer为在该任务中创建的et_red定时器。Contiki中通过etimer实现任务的周期性运行。
·uip_ds6_get_global(ADDR_PREFERRED)!=NULL:获取全局IPv6网络前缀,该前缀由边界路由分配。如果该设备未分配到IPv6网络前缀,再次启动et_red定时器,超时依然为
CLOCK_SECOND/8。
·process_start(&simple_process,NULL):如果分配到IPv6网络前缀,则启动simple任务。
simple_process任务是典型的周期性处理任务,但是该任务并不会开机自动,该任务是否启动取决于设备是否已经获取IPv6网络前缀。

3.生成hello-world.hex

下面我们尝试生成HEX格式固件,在控制台中输入:

# 进入hello-world示例目录cd examples/sensortag/hello-world # 生成固件

make BOARD=sensortag/cc2650

在hello-world目录下将生成hello-world.hex文件,该文件便是hello-world示例的最终固件。若在Instant Contiki 3.0中生成固件,可以在Instant Contiki 3.0中复制hello-world.hex,切换至Windows操作系统后直接粘贴到合适的目录即可;若使用其他Linux发行版需要在虚拟机中安装VMware Tools工具,该工具可实现Linux虚拟机和Windows主机之间的复制与粘贴操作。Linux虚拟机和Windows主机之间传输的文件的方法还包括FTP和共享文件夹等方法。

4.下载hello-world.hex

SensorTag/CC2650的固件下载操作需要借助XDS110下载工具(见图10-9)和Flash Programmer2下载软件。相关软件与工具的详细介绍和使用方法请参考德州仪器官方网站。

·XDS110:http://processors.wiki.ti.com/index.php/Debug_DevPack_User_Guide

·Flash Programmer2:http://www.ti.com.cn/tool/cn/flash-programmer

图10-9 SensorTag和XDS110下载器

为了顺利下载固件首先需要拆除SensorTag的保护外壳,把SensorTag底板与XDS110下载器相连,然后通过USB连接线与Windows主机相连。打开Flash Programmer2下载软件把hello-world.hex文件下载至SensorTag中,具体操作过程如图10-10所示。HEX文件下载完成之后SensorTag将自动重启。

图10-10 下载hello-world.hex

5.运行hello-world.hex

固件下载完成之后,SensorTag将进入正常运行模式,XDS110下载工具将在Windows主机中虚拟一个串口设备,利用该串口设备可以观察SensorTag的运行情况,通过串口调试工具可以观察到以下类似输出信息:

# contiki-main.c中输出
Starting Contiki-3.x-2906-g14bfaff
With DriverLib v0.46593
TI CC2650 SensorTag
Starting Contiki-3.x-2906-g14bfaff
With DriverLib v0.46593
TI CC2650 SensorTag
Net: sicslowpan
MAC: CSMA
RDC: ContikiMAC, Channel Check Interval: 16 ticks
RF: Channel 25
Link layer addr: 00:12:4b:00:07:c9:4b:03
Node ID: 19203
# hello-world.c中输出
hello world!

SensorTag的串口输出信息大致可分为两部分:一部分为contiki-main.c输出内容,另一部分为hello-world.c输出内容。contiki-main.c中输出了当前Contiki的版本编号,CC2650相关driverlib的版本编号、Platform名称、MAC层和RDC层选用组件情况、射频部分工作信号、CC2650链路层MAC地址等基本信息。hello-world.c中的输出信息则相对简单,仅包括“hello world!”。

此时SensorTag的红色LED将会不停地闪烁,由于并没有边界路由设备,所以Sensor Tag始终无法加入网络,也无法获得全局网络前缀。SensorTag与外部网络建立联系必须要依赖于边界路由。

10.4 搭建边界路由

在WiFi组成的无线局域网中一般存在两种角色:WiFi AP和WiFi Station,WiFi AP即俗称的无线路由器,而手机或者个人笔记本则扮演WiFi Station角色。在Contiki所支持的IEEE 802.15.4无线局域网中,SensorTag扮演终端设备,这和WiFi无线局域网中的手机和个人笔记本所扮演的角色相似。边界路由则扮演与无线路由器相似的角色,它把无线数据“翻译”为有线数据,可以说边界路由是低功耗无线网络与传统互联网之间的桥梁。

在多数情况下,WiFi无线路由器仅需传递IPv4报文,但在此处的无线网络中边界路由需要做更多的工作,它需要把经过6LoWPAN技术压缩的IPv6报文还原为完整的IPv6报文。由于具体网络的限制,边界路由还需要把IPv6报文转化为合适的IPv4报文。

Contiki中有多种创建边界路由的方法,本小节将介绍Slip-Radio+Native-Border-Router方法。本小节中CC2538用于实现Slip-Radio,而树莓派用于实现Native-Border-Router,本节的主要工作如图10-11所示。

10.4.1 创建Slip-Radio

Slip是串行线路接口协议的简称,它是一种点对点网络解决方案,Slip协议是一种非常古老的串行线路接口协议,该协议提供了一种非常简单的封装IP数据包的方法。Slip协议定义一个称为slip end的界定符,该值为192(0xC0),该界定符被追加到IP数据包的末尾,利用该界定符判断IP数据包是否完整。在IP数据包中也会出现其他的0xC0,为了解决这种冲突,Slip协议又定义了一个slip esc界定符,该值为219(0xDB)。当IP发送数据包中包含0xC0时,它被自动替换为0xDB 0xDC两个字符,这样可以避免与结尾界定符0xC0产生冲突。

图10-11 搭建边界路由主要工作

Slip-Radio把无线传感网中的IPv6数据转化为使用串行接口的slip数据,那么Native-Border-Router便可使用诸如ttyUSB0这样的串行设备接收slip分包数据,并把这些分包数据注入到Linux网络层中。Slip-Radio的相关实现代码位于本书代码仓库microsystem_deviceexamplesipv6slip-radio目录中。

1.生成Slip-Radio固件

本节示例使用CC2538DK平台生成Slip-Radio固件,具体操作如下:

# 进入Slip-Radio目录cd examples/ipv6/slip-radio # 在CC2538平台下生成固件make TARGET=cc2538dk

2.下载Slip-Radio固件

CC2538的固件烧写方式和SensorTag/CC2650相似,借助Flash Programmer2和XDS100/XDS110下载工具便可完成操作。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容