1.重新编写Blink
我们将创建一个简单的应用,实现计数的增加,将计数的三个最低有效位在三个LED灯上显示,并通过无线方式将计数消息发出。
创建BlinkToRadio.nc文件,以下是其具体代码实现。
创建BlinkToRadio.h头文件,在文件中定义用到的常量和数据结构。
注释:BlinkToRadio.h是一个标准的头文件,但这里应注意两点:第一:注意ifndef、define和endif的使用,它们会确保每个头文件中的定义不被多次定义,因为编译器会对多次定义提出警告。
第二:使用enum定义了常量TIMER_PERIOD_MILLT。使用enum定义常量优于使用define,因为enum不会轻易地代替已定义的每个常量值。
接下来,要编写配置文件BlinkToRadioAppC.nc,将用到的组件导通:
另外还需一个Makefile文件:
2.Dissemination分发
分发是一种基本的传感器网络协议,主要用于实现基于共享变量的网络一致性。网络中的每一个节点都有该变量的一个备份,这种小数据分发服务会通知节点该变量值更改的时间,同时交换数据包以达到整个网络的一致性。在任意给定时段,也许会有两个节点不同意交换数据包,但是随着时间的流逝,不同意的节点数会越来越少,最终整个网络完全依赖于一个变量值(converge on a single value)。
网络的高度一致性能有效避免临时性的链接失效以及高丢包率。与泛洪协议(flooding protocals)不同,泛洪协议主要是离散性的工作(节点与节点之间不受某一变量值约束),它能够终止并且不再达成网络的一致性,小数据分发机制确保网络内部在有可靠连接的情况下能够达到基于单个变量值的一致性。
小数据分发协议会因为数据项(data item)的不同而不同:相比于分发两个字节的配置字到网络中,有效的分发几十个KB的二进制数据流时需要另外的协议。但是,深入研究一下,会发现二者其实还是有相同点的,两种协议并非完全不同。把小数据分发协议分成两个部分--分别是控制量部分(control traffic)和数据量部分(data traffic)。其中数据通信量(data traffic)协议依赖于数据项的大小,而控制通信量(control traffic)协议大致相同。例如,Deluge-这种二进制重编程服务以二进制形式分发metadata。当网络中的节点发现收到的metadata与自身的metadata不同时,他们就会意识到自身原来的二进制信息已经失效了,需要一个新的二进制信息。
Noverlty协议在小数据分发一致性模型上做了很周到的考虑,致力于让网络中的每一个节点都接纳分发到网络中的变量值的最新版本。按照这种方式,节点可以通过告诉网络变量值被更新从而促进网络达成一致。如果有好几个节点决定更新变量值,小数据分发协议就可以确保网络只需要一次更新便可以确保达成一致。
网络的这种一致性并不意味着每一个节点都能够接收到变量值,这种一致性仅仅表示网络最终会在哪个最新变量值这个问题上达成一致。如果有一个节点从网络中断开并且此后网络经过8次更新才得到共享变量,则当该节点重新加入网络后,它所接收到的变量值只会是最后一个更新所得到的变量值。
能够将小数据分发到整个网络中,这对于传感网应用而言是重要的组成部分。它允许管理员向网络中插入小段程序,命令以及配置字。比如,安装一小段程序到整个网络中就相当于建立网络一致性的问题,该一致性通过包含这段小程序的一个变量来建立。
小数据分发协议有两个接口:DisseminationValue和DisseminationUpdate。前者适用于分发数据的消费者,后者便适用于生产者。详细代码如下:(www.xing528.com)
1)
2)
这些接口假定在分发服务中分配空间来储存变量值。这样一来,多个组件都可以访问该变量并且还能共享分发服务建立网络一致性所基于的相同的变量。消费者能够通过DisseminationValue.get()指向的数据区域获取CONST类型的指针,但它不能存储这个指针,因为网络更新过程中可能会导致指针值的改变。另外,由于该指针可以很容易就被获取,这么做会浪费RAM,DisseminationValue.get()只要分发的变量值改变的时候就会触发change()事件,因此在这种情形下消费者需要执行一些运算或者采取相应的举措。
DisseminationValue接口有一个命令"set",该命令允许节点在不以建立网络一致性的情况下改变其当前的变量值,这个命令的存在可以使节点为变量分配一个初始值。节点不能在它已经处理了"changed"事件之后再调用"set"函数,否则整个网络就可能会变得不一致。如果一个节点已经收到了一个更新信息或者一个客户机已经调用了"change"函数,那么"set"命令不能用来设定新的变量值。
DisseminationUpdate有个单独的命令"change",该命令函数有一个参数,并且是指针类型。该指针不能被存起来,因为提供DisseminationUpdate接口的组件必须将接收到的信息存入自己分配的内存里。
小数据分发协议必须在整个网络中以最新的变量值为桥梁从而达成网络的一致性。间接调用change函数使得被传输的数据项得以更新,这样它就可以被分发给网络中的每一个节点。然而,这个change函数是局部的,对于一个过时的节点也调用了change函数的话,新的变量值可能不会被分发,因为其他的节点或许都有了一个更新的变量值。如果两个节点同时调用了change函数但是却在分发不同的变量值,在网络中节点变量值仍旧不同的情况下,整个网络也许可能会达成一致!但是小数据分发协议必须能有一种可以打破僵局的机制,以至每个节点最终都能有相同的变量值。
小数据分发服务必须提供一个组件,DisseminatorC,该组件的声明如下:
考虑到小数据分发协议所介绍的帧头格式,参数t必须能够适用于单个message_t格式。如果使用了一个更大容量的类型,在实现小数据分发过程中编译器是会报错的。
由于每一个DisseminatorC的实例都可能分配存储空间或者产生代码,如果有更多的组件希望共享一个分发的变量值时,那么他们应当在一个不通用但又能被共享的组件中对该变量值进行封装,代码示例如下:
两个DisseminiatorC的不同实例不能共用相同变量值的关键参数。
在使用上述接口的过程中会出现这样一个问题,即如何选择变量key的值。一方面,采用unique()很简单,但是这意味着对于同一个程序的两个不同的汇编的参数key所占用的空间可能有所不同,且没有办法支持一个以上的二进制网络。另一方面,组件在其内部声明自己的参数key意味着会碰到无法解决的参数key碰撞问题。因为在这期间,应用程序可以选择其他组件的参数key。
一般而言,小数据分发的变量参数key可独自产生或手动产生。这些定义好的参数key可以被应用程序特定的头文件所覆盖。单独的命名空间和静态命名空间被其最重要的二进制位所分隔。一个组件作者可能会写代码如下:
你可以在应用程序目录下的头文件disseminate_keys.h中看到:
即使仔细选择参数key,两个不兼容的参数key的二进制存储空间最终在同一个网络以碰撞的形式出现。如果发生这种情况,一个GUID,参数key独有的二进制可包括在该协议内。利用GUID可以使节点检测其他二进制版本,而不是储存它们。此GUID不会成为外部接口的一部分,但将在内部被使用。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。