NESC手册.doc

上传人:laozhun 文档编号:3773802 上传时间:2023-03-21 格式:DOC 页数:23 大小:125.50KB
返回 下载 相关 举报
NESC手册.doc_第1页
第1页 / 共23页
NESC手册.doc_第2页
第2页 / 共23页
NESC手册.doc_第3页
第3页 / 共23页
NESC手册.doc_第4页
第4页 / 共23页
NESC手册.doc_第5页
第5页 / 共23页
点击查看更多>>
资源描述

《NESC手册.doc》由会员分享,可在线阅读,更多相关《NESC手册.doc(23页珍藏版)》请在三一办公上搜索。

1、nesC 1.1 语言参考手册 David Gay, Philip Levis, David Culler, Eric Brewer 20035 1 简介 nesC 是对 C 的扩展 2 ,它基于体现 TinyOS 的结构化概念和执行模型而设计 1 。 TinyOS 是为传感器网络节点而设计的一个事件驱动的操作系统,传感器网络节点拥有非常有限的资源 ( 举例来说., 8K 字节的程序储存器,512个字节的随机存取储存器) 。TinyOS 用 nesC 重新编写。本手册描述 nesC 的 1.1 版本, 在第 3 段中概述了它与1.0版的不同。 nesC 基本概念如下: l 结构和内容的分离:

2、程序有组件构成, 它们装配在一起 ( 配线 ) 构成完整程序. 组件定义两类域, 一类用于它们的描述 ( 包含它们的接口请求名称) ,另一类用于它们的补充。组件内部存在作业形式的协作。 控制线程可以通过它的接口进入一个组件。这些线程产生于一件作业或硬件中断。 l 根据接口的设置说明组件功能。 接口可以由组件提供或使用。被提供的接口表现它为使用者提供的功能,被使用的接口表现使用者完成它的作业所需要的功能。 l 接口有双向性: 它们叙述一组接口供给者 (指令)提供的函数和一组被接口的使用者(事件)实现的函数。这允许一个单一的接口能够表现组件之间复杂的交互作用 (举例来说.,当某一事件在一个回调之前

3、发生时,对一些事件的兴趣登记)。 这是危险的,因为 TinyOS 中所有的长指令 (举例来说. 发送包)是非中断的; 他们的完成由一个事件( 发送完成)标志。 通过叙述接口,一个组件不能调用发送指令除非它提供 sendDone 事件的实现。通常指令向下调用,比如, 从应用组件到那些比较靠近硬件的调用,而事件则向上调用。特定的原始事件与硬件中断是关联的 (这种关联是由系统决定的,因此在本参考手册中不作进一步描述)。 l 组件通过接口彼此静态地相连。 这增加运行时效率,支持 rubust 设计, 而且允许更好的程序静态分析。 l nesC基于由编译器生成完整程序代码的需求设计。这考虑到较好的代码重

4、用和分析。这方面的一例子是 nesC 的编译-时间数据竞争监视器。 l nesC 的协作模型基于一旦开始直至完成作业 , 并且中断远源可以彼此打断作业. nesC 编译器标记由中断源引起的潜在的数据竞争。 本文是 nesC 的一本参考手册并非个别指导。TinyOS tutorial1给出了对 nesC 的更亲切的介绍. 本文的其余部分构成如下: 第 2 节给出了本参考手册中使用的记号。. 第 3 节概述 nesC 1.1 的新特征。 第 4,5 节,6, 和 7介绍 nesC 接口和组件. 第 8 节给出 nesC的协作模型和数据竞争监视. 第 9 节解释 C文件, nesC 接口和组件是怎样

5、被装配成一个应用. 第 10 节包含 nesC 的保留的各种特征. 最后,附录A完全定义 nesC 的文法 (来自Kernighan and Ritchie (K&R) 2, pp234239附录A的对 C 文法述说的扩展),而附录 B 是本参考手册中所使用术语的专业词汇词典。 2 符号 打字机字体作为 nesC 代码和文件名,带任意下标的单个斜体字符用于表示 nesC 实体,举例来说., 组件 K 或 数值 v。nesC文法是ANSI C 文法的扩展. 我们选择来自 Kernighan and Ritchie (K&R) 的附录A的 ANSI C 文法2, pp234 239作为我们介绍的基

6、础。在这里我们将不重复ANSI C文法。. 斜体字是非终端机和非文字的终端机,打字机字体和符号是文字的终端机。 下标 opt 表示可选择的终端机或非终端机。在一些情形中,我们改变一些 ANSI C 文法规则. 我们用下面的方式表示:also 为现存的非终端机指出新增的内容,replaced by表示替换一现有的非终点的.nesC 的结构解释给出对应的文法片段。在这些片段中,我们有时使用 . . . 表现省略( 与当前不相关的解释). 附录A给出完整的 nesC 文法.一些例子使用来自 C99 标准 inttypes.h 文件的 uint8 t 和 uint16 t 类型. 3 变化 nesC

7、1.0版本同1.1版本的变化如下: 1. 原子的陈述. 这些单一化协同数据结构的实现,能够被新的编译- 时间数据竞争监视器识别。 2. 编译- 时间数据竞争监视为可能的协同的二个中断操作者 , 或一个中断操作者和一件作业同时存取变量提出警告 3. 指令和事件必须明确地标出存储类型说明才能安全地被中断操作者执行。 4. 对指令或扇出事件的调用返回结果自动地被新的类型- 特性的组合器执行联合。 5. uniqueCount 是一个新的 常数功能 , 具有独特的作用. 6. NESC 预处理程序符号指出语言版本. 对于 nesC 1.1版本它是 110 。 4 接口 nesC 的接口有双向性: 它们

8、描述一个多功能的两组件(供给者和使用者)之间的交互渠道.。 接口叙述一组叫做指令的, 被接口的供给者实现的,被命名的功能和一组叫做事件的, 被接口的使用者实现.的,被命名的功能。 本节解释接口如何被指定, 第 5 节解释组件如何描述它们提供和使用的接口, 第 6 节解释在 C代码中指令和事件如何被调用和实现,而第 7 节解释组件接口如何被一起联编. 接口被接口类型指定,如下: nesC-file: includes-listopt interface . . . interface: interface identifier declaration-list storage-class-spe

9、cifier: also one of command event async 这声明接口类型标识符. 这一标识符有全局的作用范围并且属于分开的命名空间,组件和接口类型命名空间。 如此所有接口类型都有清楚的名字以区别于其它接口和所有组件, 同时能不和一般的 C的声明发生任何冲突。 声明列表中,每个接口类型都有一个分开的声明范围。声明列表必须由有指令或事件存储类型的功能描述组成( 否则, 会发生编译-时间错误). 可选的 async 关键字指出指令或事件能在一个中断处理者中被运行。 通过包含列表,一个接口能可选择地包括 C 文件 (见第9节)。 一个简单的接口如下: interface Send

10、Msg command result_t send(uint16_t address, uint8_t length, TOS_MsgPtr msg); event result_t sendDone(TOS_MsgPtr msg, result_t success); SendMsg 接口类型提供者必须实现发送指令, 而使用者必须实现 sendDone 事件. 5 组件说明 一个 nesC 组件或是一个模块 (第 6 节) 或一个结构 (第 7 节): nesC-file: includes-listopt module includes-listopt configuration . .

11、. module: module identifier specification module-implementation configuration: configuration identifier specification configuration-implementation 组件的名字由标识符指定. 这一标识符有全局的作用范围并且属于组件和接口类型命名空间. 一个组件介入两个分组件的作用域::一个规格作用域,属于 C 中全局的作用域,和一个实现作用域属于规格作用域。 通过包含列表,一个组件能可选择地包括 C 文件 (见第9节). 组件规格列出该组件提供或使用的规格元素 (接口

12、请求,指令或事件)。 就如我们在第 4 节中见到的,一个组件必须实现它提供接口的指令和它的使用的接口事件。另外,它必须实现它提供的指令和事件。 典型地,指令向下调用硬件组件,而事件向上调用应用组件 (这表现为nesC应用如一个应用组件处于顶端的组件曲线图)。 一个控制线程只有通过它的规格元素越过组件。 每种规格元素有一个名字 (接口实例名,命令名或事件名).这些名字属于总组件-规格作用域的变量命名空间。 specification: uses-provides-list uses-provides-list: uses-provides uses-provides-list uses-prov

13、ides uses-provides: uses specification-element-list provides specification-element-list specification-element-list: specification-element specification-elements specification-elements: specification-element specification-elements specification-element 一个组件说明中可以有多个使用和提供指令。多个使用和提供规格元素可以通过包含在 and中而组合在一

14、个指令中。举例来说,下面两个说明是一样的: module A1 module A1 uses interface X; uses uses interface Y; interface X; . interface Y; . 一个接口实例描述如下: specification-element: interface renamed-identifier parametersopt . . . renamed-identifier: identifier identifier as identifier interface-parameters: parameter-type-list 接口实例声

15、明的完整语法是 interface X as Y,明确地指明Y作为接口的名字。interface X是interface X as X.的一个速记. 如果接口-叁数被省略, 那么interface X as Y声明一个简单的接口实例,对应这一组件的一个单一接口。 如果接口-叁数是给出的 (举例来说., interface SendMsg Suint8 t id) ,那么就是一个参量接口实例声明,对应这一组件的多个接口, 每个接口对应不同参数值(因此interface SendMsg Suint8 t id声明SendMsg类型的 256个接口). 叁数的类型必须是完整的类型 (这里enums

16、是不允许的).指令或事件能通过包括一个声明了指令或事件及存储类型的标准的 C函数而作为规格元素直接地被包含: specification-element: declaration . . . storage-class-specifier: also one of command event async 如果该声明不是带有指令或事件存储类型的函数声明就会产生一编译- 时间错误。在接口中, 文法指出指令或事件能被一中断操纵者运行。 作为接口实例, 如果没有指定接口叁数,指令 (事件)就是简单的指令 (简单的事件),如果接口叁数是指定的,就是参数化指令 (参数事件)。接口叁数被放置在一般的函数叁数

17、列表之前,举例来说., command void senduint8 t id(int x): direct-declarator: also direct-declarator interface-parameters ( parameter-type-list ) . . . 注意接口叁数只在组件说明里面指令或事件上被允许, 而不允许在接口类型里面. 这儿有一个完整的规格例子: configuration GenericComm provides interface StdControl as Control; / 该接口以当前消息序号作参数 interface SendMsguint8_

18、t id; interface ReceiveMsguint8_t id; uses /发送完成之后为组件作标记 /重试失败的发送 event result_t sendDone(); . 在这个例子中,一般: l 提供简单的接口实例类型 StdControl 的控制. l 提供接口类型 SendMsg 和 ReceiveMsg 的参数实例; 参数实例分别地叫做 SendMsg 和 ReceiveMsg. l 使用事件 sendDone. 我们说,在组件 K 的规格中提供的一个指令 (事件) F 是K的提供指令(事件) F; 同样地,一个被用于组件 K 的规格的指令 (事件) 是K 的使用指令

19、 (事件) F。 组件K的提供接口实例X的指令F是K的提供指令X.F;组件K的使用接口实例X的指令F是K的使用指令X.F 。K的提供接口实例X中的事件F是K的使用事件X.F; K的使用接口实例X中的事件F是K的提供事件X.F ( 注意事件的使用和提供根据接口双向属性的颠倒)。 当使用/提供区别关系不大时,我们常常只简单的提到 K的指令或事件a。K的指令或事件a可能是参数化的或简单的, 取决于其通信的规格元素的参数化或简单状态. 6 模块 模块用C代码实现组件说明: module-implementation: implementation translation-unit 这里编译基本单位是一

20、连串的 C 声明和定义 ( 见K& R2 , pp234 239)。 模块编译基本单位的顶层声明属于模块的组件说明域。这些声明的范围是模糊的而且可以是: 任意的标准 C声明或定义,一种作业声明或定义,指令或事件实现. 6.1 实现模块的说明 编译基本单位必须实现模块的所有的提供指令 (事件)a (例如., 所有的直接提供指令和事件, 以及提供接口的所有指令和使用接口的所有事件). 一个模块能调用它的任一指令和它的任一事件的信号. 这些指令和事件的实现由如下的 C 语法扩展指定: storage-class-specifier: also one of command event async d

21、eclaration-specifiers: also default declaration-specifiers direct-declarator: also identifier . identifier direct-declarator interface-parameters ( parameter-type-list ) 简单指令或事件a由带有存储类型指令或事件的C 函数定义的语法实现 (注意允许在函数名中直接定义的扩展)。另外,语法关键字必须被包含如果它被包含在a的声明中。举例来说,在SendMsg类型的提供接口Send的模块中: command result_t Send.

22、send(uint16_t address, uint8_t length, TOS_MsgPtr msg) . return SUCCESS; 带有接口参数P的参数指令或事件a,由带有存储类型指令或事件的函数定义的C文法实现,这时,函数的普通参数列表要以P作为前缀,并带上方括号 ( 这与组件说明中声明参数化指令或事件是相同的文法)。这些接口叁数声明P 属于a的函数叁数作用域而且和普通的函数参数有相同的作用域。举例来说,在SendMsg类型提供接口Senduint8 tid的模块中: command result_t Send.senduint8_t id(uint16_t address,

23、uint8_t length, TOS_MsgPtr msg) . return SUCCESS; 以下情况将报告编译- 时间错误: l 提供指令或事件没有实现。 l 类型标志,可选择的接口叁数和指令或事件语法关键字的存在或缺失,或与模块说明不匹配 6.2 调用命令和事件信号 对 C 语法的下列扩展用于调用事件和向指令发出信号: postfix-expression: postfix-expression argument-expression-list call-kindopt primary ( argument-expression-listopt ) . . . call-kind:

24、one of call signal post 一个简单的指令a使用call _(.)调用, 一件简单的事件使用signal a(.)发送讯号。举例来说,在一个模块中使用SendMsg类型接口Send:call Send.send(1,sizeof(Message), &msg1)。 一个参数指令a(个别地,一件事件)有 n个接口叁数,类型为t1 , . . . , t n由接口参数表达式e1 , . . . ,en调用如下:call _e1, . . . , en(.) (个别地,signal _e1, . . . , en(.)。接口叁数表达式 ei 必须分配类型t i; 实际的接口叁数值

25、是ei影射到t i. 举例来说, 在一个组件中使用类型 SendMsg 的接口Senduint8 t id: int x = .; call Send.sendx + 1(1, sizeof(Message), &msg1); 指令和事件的执行是立即的,也就是,调用和发送信号行为和函数调用是同样地。实际的指令或事件是由调用还是信号表达运行取决于程序结构联系说明。 这些联系说明可能指定0,1 或更多的实现将被运行。当超过 1个实现被运行, 我们说模块的指令或事件为扇出。 一个模块能为一使用指令或事件a指定默认的调用或信号实现。提供指令或事件的默认实现会引起编译-时间错误。如果a未与任何指令或事件

26、实现联系,默认的实现将被执行。默认的指令或事件由带有默认关键字的指令或事件实现前缀定义: declaration-specifiers: also default declaration-specifiers 举例来说, 在一个类型 SendMsg使用接口Send的模块中: default command result_t Send.send(uint16_t address, uint8_t length, TOS_MsgPtr msg) return SUCCESS; /* 允许调用即使接口发送未连接*/ . call Send.send(1, sizeof(Message), &msg1

27、) . 第 7.4 节叙述实际上什么指令或事件实现被运行以及调用和信号表达返回什么结果. 6.3 作业 作业是一个独立的控制点,由一个返回空存储类型的无二义性地函数定义:task void myTask() . 。作业也能预先声明,举例来说., task void myTask(); 作业通过前缀post调用通知,举例来说., post myTask()。通知返回迅速;如果独立执行通知成功则返回1,否则返回0。通知表达式的类型是unsigned char。 storage-class-specifier: also one of task call-kind: also one of post

28、 nesC的协作模型,包括作业,在第8节中详细陈述。 6.4 原子的陈述 原子的陈述: atomic-stmt: atomic statement 确保陈述被运行 好像 没有其它的运算同时发生。它用于更新并发的数据结构的互斥变量,等等。 一简单的例子是: bool busy; /全局 void f() bool available; atomic available = !busy; busy = TRUE; if (available) do_something; atomic busy = FALSE; 原子的区段应该很短, 虽然这常常并不是必须的。控制只能 正常地 流入或流出原子的陈述:

29、 任何的 goto, break或continue,跳转入或出一原子陈述都是错误的。返回陈述决不允许进入原子陈述。 第 8 节讨论原子和 nesC协作模型和数据竞争监视器之间的关系。 7 结构 结构通过连接,或配线,集合其他组件实现一个组件说明: configuration-implementation: implementation component-listopt connection-list 组件列表列出用来建立这一个结构的组件,连接列表指明各组件之间,以及与结构说明之间是怎样装配在一起的。在这一节的其余部分中,我们调用来自结构的外部的规格元素 , 和来自结构的内在的成份之一的规格元

30、素。 7.1 包含组件 组件列表列出用来建立这一个结构的组件。在结构里面这些组件可随意的重命名,使用共同外形规格元素,或简单的改变组件结构从而避免名称冲突。(以避免必须改变配线)为组件选择的名字属于成份的实现域。 component-list: components component-list components components: components component-line ; component-line: renamed-identifier component-line , renamed-identifier renamed-identifier: identifie

31、r identifier as identifier 如果二个组件使用as给出相同的名字,则会发生编译时间错误(举例来说., components X, Y as X)。 只有一个个别的例子:如果组件 K 被用于二不同的结构 ( 或甚至两次用于相同的结构里面), 在程序中仍然只有 K(及它的变量) 的唯一实例。 7.2 配线 配线用于连接规格元素 (接口,指令,事件)。本节和下一节(第 7.3 节) 定义配线的语法和编译-时间规则。第 7.4 节详细说明程序配线声明是如何指出在每个调用和信号表达中哪个函数被调用。 connection-list: connection connection-l

32、ist connection connection: endpoint = endpoint endpoint - endpoint endpoint endpoint2:( 联编配线) 一个连接包括二种内在的规格元素。.联编配线总是连结一由endpoint1指定的使用规格元素到一endpoint2指定的提供规格元素。如果这两个条件不能满足, 就会发生编译-时间错误.。 l endpoint1 endpoint1是等价的。 在配线的所有三种类型中,两被指定的规格元素必须是一致的,就是说., 它们必须都是指令,或都是事件, 或都是接口实例. 同时, 如果它们是指令(或事件),则它们必须有相同的函

33、数名 如果他们是接口实例,它们必须有相同的接口类型。他们一定是有相同的接口类型的. 如果这些条件不能满足, 就会发生编译-时间错误.。 如果一个端点是参数化的,则另一个必须也是而且必须有相同的叁数类型;否则就会发生编译-时间错误.。 相同的规格元素可以被多次连接,举例来说.,: configuration C provides interface X; implementation components C1, C2; X = C1.X; X = C2.X; 在这个例子中,当接口X中的命令被调用时,多次的配线将会导致接口X的事件的多重信号 (扇入),以及多个函数的执行(扇-出)。注意,当二个结

34、构独立地联结相同接口的时候,多重配线也能发生,举例来说.: configuration C configuration D implementation implementation components C1, C2; components C3, C2; C1.Y - C2.Y; C3.Y - C2.Y; 所有的外部规格元素必须配线,否则发生编译-时间错误. 可是,内部的规格元素可以不连接 (它们可能在另外一个结构中配线,或者如果模块有适当的默认事件或指令实现,他们可以不配线). 7.3 隐含连接 隐含连接可以写成K1 - K2.X 或K1.X 是等价的). 该用法通过规格元素K1 (不妨

35、K2)来引用规格元素 Y,因此K1.Y - K2.X (不妨 K1.X M.P; h2 = M.h; 图 1: 简单的配线例子 components M1, M2; M2.SC - M1; M2.SC - M1 这一行与M2.SC - M1.StdControl. 是等价的。 7.4 配线语义 我们首先撇开参数化接口讨论配线语义. 7.4.1 节将讨论参数化接口。最后,第 7.4.2 节叙述整体上而言,程序配线声明上的要求。我们将会用到图1中的简单程序作为我们运行的例子。 我们根据中间函数定义配线的意义。每个组件的每个指令或事件都有中间函数. 举例来说,在图 1 中,模块M 有中间函数 IM.

36、P.f , IM.P.g , IM.U.f , IM.U.g , IM.h. 在例子中,我们以其组件,任意接口实例名,及函数名为基础命名中间函数。中间函数不是使用就是提供。每个中间函数接受与组件说明中相应指令或事件相同的自变量。中间函数体I是调用(执行系列)其它中间函数的列表。I 通过程序配线说明连接到其它中间函数 。I接受的自变量不变的经过被调用的中间函数.I 返回结果列表,(列表元素类型是相应指令或事件返回给I的结果类型),列表通过连接调用中间函数返回结果构成。返回空值的中间函数适合不相 连接的指令或事件;返回两个或以上值的中间函数适合“扇出”。 - nesC允许在没有直接中间函数的情况下

37、编译,所以本节中描述的行为没有运行开销,实际的函数调用需要参数化的指令或事件。 - 中间函数和结构 一个结构的配线说明指定中间函数体。我们首先扩展配线说明到中间函数而不限于规格元素,并取消配线说明中= 和-的区别。我们用 I1 I2 表示中间函数I1 和I2之间的连结。举例来说,图 1中的结构C 叙述了下列中间函数连接: IC.X.f IM.P.f IM.U.f IM.P.f IC.h2IM.h IC.X.g IM.P.g IM.U.gIM.P.g 在结构 C 的连接I1 I2中,二个中间函数之一是被调用的,另一个是调用者。如果下列任一条件成立(我们使用内部或外部的用辞作规格说明并不妨碍结构

38、C包含连接),则I1(同样地,I2)是被调用的: l 如果 I1 符合一件被提供指令或事件的内部规格元素. l 如果 I1 符合一件被使用指令或事件的外部规格元素. l 如果 I1 符合一个接口实例X 的指令,而X是内部的且被提供或外部的且被使用的规格元素. l 如果 I1 符合一个接口实例X 的事件,而X是外部的且被提供或内部的且被使用的规格元素. 如果这些情况没有一个成立,则I1 调用者。7.2 节的配线规则确保一个连接 I1I2 不会同时连接二个调用者或二个被调用者。图1的结构 C 中,IC.X.f , IC.h2 , IM.P.g,IM.U.f 是调用者而 IC.X.g , IM.P.

39、f , IM.U.g,IM.h 是被调用者。如此C的连接说明IC.X.f 调用IM.P.f,IM.P.g调用IC.X.g,等等。 中间函数和模块 模块中的C代码调用中间函数,或被中间函数调用。 模块M中提供指令或事件a的中间函数I 包含一个单独调用以运行M中的a。其结果是 一个单独的调用返回列表。表达式call a(e1, . . . , en)性质如下: l 自变量e1, . . . , en 被赋值为v1, . . . , vn.。 l a对应的中间函数被以自变量v1, . . . , vn调用,返回结果列表L. l 如果 L=(w)( 一个独立列表),调用的返回结果就是 w. 如果 L=

40、(w1,w2, . . . ,wm) (二或更多的元素),调用的结果仰赖于a的返回类型t。如果t=void,则结果是void。否则,t 一定有一联合函数c( 第 10.3节演示联合函数是如何联合类型的),否则发生编译-时间错误。联合函数接受类型t 的两个值并且返回一个类型t的结果。该调用的结果是c(w1, c(w2, . . . , c(wm1,wm) ( 注意L中元素次序是任意的). list of int IM.P.f() list of void IM.P.g(int x) return list(M.P.f(); list of int r1 = IC.X.g(x); list of int r1

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 办公文档 > 其他范文


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号