本文内容来源为contiki英文介绍,自己为了学习,将其大致翻译成中文,以便了解。
欢迎转载,转载请注明来源,如果有什么翻译不合适的地方,请留言指出,相互交流学习。
介绍
Contiki是一个开放源码、多任务事件驱动的嵌入式网络专用操作系统,轻量级的资源占用使得它很适合存储资源紧张的微控制器。
Contiki由几个独立的模块组成,包括一个类似线程的多任务事件驱动protothread库,uIP TCP/IP(v4 and v6)协议栈,无线传感网络协议栈Rime。
Contiki是为了网络应用而设计,但也可以基于它的内核开发其他应用。这时它的官方网站。official website
事件
contiki内核是基于事件驱动的,这意味着每个正在执行的应用都对于的一个事件的响应。整个应用包括kernel、libraries、user code可能包含若干个正在执行的进程。
不同的进程通常指执行特定的时间,然后等待事件的发生。在等待期间,进程处于阻塞状态。当事件发生时,内核将传递关于事件发生的消息,并且激活那些等待事件发生的进程。时间可以分为以下三类。
时间事件
一个进程可以设定一个定时器,在指定的时间后产生一个事件,它自己会阻塞,直到时间期满后,继续运行。这对于一些周期性的操作或者网络协议,例如同步相关的问题是,很有帮助。
外部事件
通过微控制器的具有中断功能的IO口连接的外部设备,当触发条件满足时,可以产生事件。例如,一个按钮、接收射频数据、加速度检测计都是可以外部中断源。进程会依据与这些事件来响应。
内部事件
任何进程都有可能处理其他进程的事件,或者发向自己的事件,这对于进程间通讯很有帮助。一个进程可以通知另一个进程,相关数据已经准备好。
事件一般是被发送的,一个中断服务程序执行时,可能向其他进程发起一个事件。一个事件通常具有以下几个信息:
process:事件将要发向的进程,可以发向某一个进程,也可以发向所有登记过的进程。
event type:事件类型,用户可以针对进程,自定义事件类型,以便于进程区分。例如发送和接收包时的事件
data:可选项,一些数据可能需要随同事件一起发向进程
进程
进程在Contiki是任务的同义词。进程机制使用protothread库。一个进程是一个C函数,很有可能包含一个无限循环和一些阻塞的宏调用。由于Contiki的事件驱动内核不是可抢占的,每个进程在执行时,会独享处理器,直到它由于等待事件而阻塞。不同的阻塞类型由不同的宏来定义实现。这允许编程状态机作为一个顺序控制流。下面给出的是一个contiki官方网站给出的一般进程结构:
#include "contiki.h" /* The PROCESS() statement defines the process' name. */ PROCESS(my_example_process, "My example process"); /* The AUTOSTART_PROCESS() statement selects what process(es) to start when the module is loaded. */ AUTOSTART_PROCESSES(&my_example_process); /* The PROCESS_THREAD() contains the code of the process. */ PROCESS_THREAD(my_example_process, ev, data) { /* Do not put code before the PROCESS_BEGIN() statement - such code is executed every time the process is invoked. */ PROCESS_BEGIN(); /* Initialize stuff here. */ while(1) { PROCESS_WAIT_EVENT(); /* Do the rest of the stuff here. */ } /* The PROCESS_END() statement must come at the end of the PROCESS_THREAD(). */ PROCESS_END(); }
这段代码没做任何事情,仅仅是一个进程的框架结构。重复性的等待事件发生,然后执行,然后再等待….
当使用protothread来编程时,有以下几点要注意:
1. 本地变量是不保存的。
当一个进程调用一个阻塞宏时,实际上发生的是进程函数已经返回了,控制权交给内核去调度其他进程。当事件发生时,内核会调用相同的进程函数,它会调到发生等待事件,阻塞的地方继续执行。因此,如果进程的本地变量(非static变量)在阻塞前被赋值,那么,当阻塞后返回时,这些变量保存的值将失效。一个好的解决方法是使用static变量。
2. 不要使用switch语句
protothreads使用本地local continuations去恢复阻塞退出后的堆栈状态。这是通过switch来实现的。如果case表达式可以放置在任何位置(在if里面或者while段里面),它不能再和其他switch语句混合使用了。因此,在进程函数里面,最好不要使用switch语句。
uIP TCP/IP stack
contiki包含一个轻量级的TCP/IP协议栈,名为uIP。它实现了RFC兼容的IPv4、IPv6、TCP和UDP。后两者兼容IPv4和IPv6.uIP非常精简,仅实现最为重要的功能。例如,整个协议栈只有一个buffer,用来接受和发送数据包。
应用API
基于uIP协议栈,有两种方式来编程。
raw API:uIP raw API适合实现简单应用。例如一个简单的能够监听一些TCP端口的简单回显服务器。随着不断的发展,它也可以编写功能复杂的网络程序。
protosocket API:protosocket API利用protothread库来实现更加灵活的TCP/IP应用程序。它提供类似于标准BSN socket的接口,允许在进程中编写应用。
Lower Layers
拥有TCP/IP功能的协议栈和一些应用程序很好,但是它还可以做的更好。uIP要求一个更低层去和附近节点通讯。有两种节点。
nodes:在nodes之间通讯需要无线连接。uIP支持无线收发数据包。基于uIP的版本配置,Contiki遵循不同的方向。
1. 当传输的为IPv6数据包时,Contiki选择route-over配置。因此,uIP6使用一个成为sicslowmac的MAC层来处理无线数据包。头部压缩技术由6lowpan模块提供,它可以转发数据包。
2. 针对IPv4通讯,Contiki选择mesh-under配置。这由Rime通讯协议栈来负责。Rime提供mesh路由和路由发现,因此,uIP通过它,可以转发网络数据包。从IP的角度来看,需要本地网络的所有传感器节点、甚至是多跳中继节点是需要的。
gateways:为了与无线传感器网络之外的网络通讯,网关是必须的。它是连接传感器网络和其他网络的桥梁。在大多数情况下,网关由PC来担当,当然,它也可以是嵌入式设备。PC和节点通过串口连接,IP数据包使用SLIP在两者之间传输。在PC端,必须允许转换程序,来转换串行线路和网络接口之间的数据转换。基于uIP的版本,功能有所不同。
1. uIPv6,一个将数据包在射频数据转和串行数据之间进行相互转换的程序是很有必要的,它不需要做任何的地址比较功能,除了IPv6的头压缩和解压机制外(6lowapn),它没有任何的其他的IP栈。从PC的角度出发,这个节点充当一个以太网的接口,因此,PC可以做任何工作。
2. uIPv4,它的工作机制就完全不同了。连接到PC的节点充当网关的角色,带有所有的IP栈。它发送的每个数据包,都会检测它的IP地址。如果数据无线传感器网络的范围,则会通过射频通道来发送。否则,会通过串行链路发给PC。PC上运行的程序将构建一个IP网络接口。
Rime stack
Rime stack提供一个层次分明的无线网络协议栈集合,从一个简单的匿名广播到复杂的网状路由.实现这一些列复杂协议肯定需要分层、分模块来进行的。复杂模块的实现基于简单模块的实现。下图是Rime协议的概览。
Rime每个模块的简要描述:
1. abc: 异步广播模块,它仅仅通过射频通道发送数据包,从射频通道接收所有的数据包,并且传递给高层协议,属于Rime中最底层的模块。
2. broadcast:指定广播。它向输出数据包中添加了源地址,并且将数据包传递给abc模块。
3. unicast:往数据包中增加目的地址,并传递给broadcast模块。在接收端,如果接受包的目的地址和节点地址不匹配,则丢弃该包。
4. stunicast:stubborn的单播,当需要向节点发送数据包时,它以一个给定的时间周期,反复的发送数据包,直到被暂停。该模块不单独使用,通常由高层来调用。
5. runicast:可靠的单播。它通过调用stunicast来发送数据包,并且等待ACK响应。当接收到ACK响应时,它停止持续的发送数据包。此时,为了避免无限制的发送数据包,需要制定一个最大重传次数。
6. polite和ipolite:这两个模块几乎是相同的。当一个数据包需要在指定帧中被传送,这个模块会等待一半的时间,然后检查它是否收到了准备要发送的数据包。如果收到了,该数据包不会发送。否则,他会发送数据包。这在避免不必要的重传中有用处。
7.multihop:这个模块需要一个路由表功能,当它要发送数据包时,它查找路由表寻找下一跳地址,通过unicast向其发送数据包。当它接收到一个数据包时,如果节点是接收数据包的目标地址,该数据包被传往上层,否则,它会查找路由表,确定下一跳地址并且转发它。
MAC layer
正如我们所看到的,uIPv6协议栈使用一个简单的MAC层协议,成为sicslomac,没有其他选项。然而,IPv4栈使用Rime作为它的底层协议实现,可以选择特定的MAC层。
在Contiki中,以下的MAC层已经实现了。
1. nullmac: 正如它名字一样,它不做其他事情,仅仅是在上层应用和射频驱动之前转发数据包。
2. xmac协议:前导采样协议,节点周期性的监听射频通道。
3. lpp协议:probing协议,节点周期性地发送一小段信息,说他们正在监听,监听一段时间后,他们转入休眠状态。
目前为止的工作情况
在WSN430平台上已经移植并且测试了如下几点。
1. kernel:基本的contiki工作没有问题,包括进城处理,不同的时间管理等等。此外,Contiki要求的所有驱动都在WSN430开发包中提供,在Contiki旧的开发包中,这些是系统的一部分,考虑到可维护因素,他们被分离了。
2. uIP:uIP在IPv4和IPv6下工作都没有问题,TCP和UDP都是可用的。需要注意的一点是,UDP的最大段长度,通常需要设置为128个字节。节点之间的通讯,可以直接通过射频,或者使用PC连接的gateway。
3. Rime:无线传感器协议栈部分已经被测试了,一些简单的模块能够正常工作了,例如abc, broadcast, unicast, ipolite, stunicast, runicast, multihop。使用mesh的全部的通讯协议栈已经证实可以在同样的信道和其他节点协同工作。多跳和路由暂时没有测试。
4. MAC层:之前提到的四个MAC层协议已经针对WSN430平台配置好了。nullmac, xmac, lpp and sicslomac.
例子
下载
Here is the archives, the Contiki OS ported for the WSN430, along with the examples:
-
-
updated to Contiki_2.4
-
added wsn430v14 support, with cc2420 radio chip
-
added tools to run SLIP from Senslab Virtual Machines
-
网址原文链接:http://senstools.gforge.inria.fr/doku.php?id=os:contiki