TIMER_PERIOD_MILLI = 250
};
习惯上,这些指令的常量通常是文件名的全大写版本,这样这些常量可以在任何情况下成为重点关注的对象。另一个需要关注的是用来定义常量TIMER_PERIOD_MILLI的“列举型”(enum)申明的使用。这里优先选择使用“列举型”来定义常量而不是单纯的“定义”是因为列举型不能够对已经定义的常量的每一次使用进行任意的修改,无论这些常量出现在代码的任何部分。因此,列举型提供了一个更好的作用范围。
我们已经使用了上面的方法,即仅用一个单独的timer组件和counter变量来重新实现了打印,现在我们可以将注意力转移到为发送的数据定义报文格式上来。通过通信模块,报文可以发送出包括节点ID号以及counter值在内的信息。我们并不直接读写message_t缓冲区内载荷区域中存有的这些数据(包括节点ID以及counter值),而是使用一个结构来存储它们并通过结构赋值将数据复制到载荷区域中。使用一个结构允许更便捷地读写报文载荷,尤其是当报文有多个数据类型域 (如 uint16_t 或者 uint32_t) 时,因为通过使用结构你能避免通过使用索引来读写字节,因此容易修改和增添(例如:uint16_t x = data[0] << 8 + data[1])。即便是对于仅有单个域的报文,你也应当习惯于使用结构,因为只要你曾经为报文增添过域或者移动过某些域,在没有使用结构的情况下如果你以字节形式读写载荷都需要人工的更新所有的载荷位置索引,所以使用结构将非常简单直接。为了定义在载荷中的无符号16位整型( uint16_t)的节点id以及无符号16位整型的counter值的报文结构,PrintToRadio.h文件中在endif指令之前需要添加如下的代码:
typedef nx_struct PrintToRadioMsg {nx_uint16_t nodeid;
nx_uint16_t counter;
} PrintToRadioMsg;
nx前缀只针对于nesC语言且能够表示结构和 uint16_t都是外部类型。编程提示15:当定义报文格式时,使用与平台无关的数据类型(来自于Phil Levis’的TinyOS Programming )编程提示16:如果你需要在独立类型的平台上进行重要的运算或者需要成百上千次的访问,那么可以暂时的将其复制为本地特有类型。外部类型能够在任何平台上使用,nesC编译器产生的代码能够记录对nx_data类型数据的透明访问并且不再需要手工处理数据字节顺序及排列格式(在某些平台上上结构中的多余填充部分)问题。但什么是字节顺序呢?
不同的处理器在内存中数据表示的方式也不尽相同。有些处理器使用“big endian”的方式来表示,这种方法将一个多字节数据(16- or 32-bit)中的最高有效字节放在低地址,而对于“little endian”的表现方式,它与“big endian”完全相反,即将最低有效字节放置在低地址。但是当数据以串行的形式通过网络进行发送时会出现新的问题,因为不同的处理器将以不同的方式(基于其不同的字节顺序)来处理相同的一组字节集。字节顺序所带来的问题主要体现在需要一些额外的操作来重新安排字节顺序以使其与特定的网络协议或者处理器结构相匹配,这事实上是一个非常麻烦且易出错的处理过程。使用套接字API的htons,htol,ntohs以及ntohl调用就是一种在特定平台下调用的范例,这些调用均能够在网络和主机之间进行字节顺序的转换,但麻烦的是你必须记得它们。而nesC编程语言则采取了一种完全不同的方法来解决这个问题,并且定义了避免让编程者重新安排字节顺序的外部类型。特别的是nx前缀在一种类型里则表明该域以big endian格式被串行化。相反的,nxle前缀则表明域以little endian格式被串行化。