nesC中文手册.docx

上传人:b****5 文档编号:5901825 上传时间:2023-01-02 格式:DOCX 页数:27 大小:37.01KB
下载 相关 举报
nesC中文手册.docx_第1页
第1页 / 共27页
nesC中文手册.docx_第2页
第2页 / 共27页
nesC中文手册.docx_第3页
第3页 / 共27页
nesC中文手册.docx_第4页
第4页 / 共27页
nesC中文手册.docx_第5页
第5页 / 共27页
点击查看更多>>
下载资源
资源描述

nesC中文手册.docx

《nesC中文手册.docx》由会员分享,可在线阅读,更多相关《nesC中文手册.docx(27页珍藏版)》请在冰豆网上搜索。

nesC中文手册.docx

nesC中文手册

nesC1.1语言参考手册

DavidGay,PhilipLevis,DavidCuller,EricBrewer

2003.5

1简介

nesC是对C的扩展[2],它基于体现TinyOS的结构化概念和执行模型而设计[1]。

TinyOS是为传感器网络节点而设计的一个事件驱动的操作系统,传感器网络节点拥有非常有限的资源(举例来说.,8K字节的程序储存器,512个字节的随机存取储存器)。

TinyOS用nesC重新编写。

本手册描述nesC的1.1版本,在第3段中概述了它与1.0版的不同。

nesC基本概念如下:

􀁺结构和内容的分离:

程序有组件构成,它们装配在一起("配线")构成完整程序.组件定义两类域,一类用于它们的描述(包含它们的接口请求名称),另一类用于它们的补充。

组件内部存在作业形式的协作。

控制线程可以通过它的接口进入一个组件。

这些线程产生于一件作业或硬件中断。

􀁺根据接口的设置说明组件功能。

接口可以由组件提供或使用。

被提供的接口表现它为使用者提供的功能,被使用的接口表现使用者完成它的作业所需要的功能。

􀁺接口有双向性:

它们叙述一组接口供给者(指令)提供的函数和一组被接口的使用者(事件)实现的函数。

这允许一个单一的接口能够表现组件之间复杂的交互作用(举例来说.,当某一事件在一个回调之前发生时,对一些事件的兴趣登记)。

这是危险的,因为TinyOS中所有的长指令(举例来说.发送包)是非中断的;他们的完成由一个事件(发送完成)标志。

通过叙述接口,一个组件不能调用发送指令除非它提供sendDone事件的实现。

通常指令向下调用,比如,从应用组件到那些比较靠近硬件的调用,而事件则向上调用。

特定的原始事件与硬件中断是关联的(这种关联是由系统决定的,因此在本参考手册中不作进一步描述)。

􀁺组件通过接口彼此静态地相连。

这增加运行时效率,支持rubust设计,而且允许更好的程序静态分析。

􀁺nesC基于由编译器生成完整程序代码的需求设计。

这考虑到较好的代码重用和分析。

这方面的一例子是nesC的编译-时间数据竞争监视器。

􀁺nesC的协作模型基于一旦开始直至完成作业,并且中断源可以彼此打断作业.nesC编译器标记由中断源引起的潜在的数据竞争。

本文是nesC的一本参考手册并非个别指导。

TinyOStutorial1给出了对nesC的更亲切的介绍.

本文的其余部分构成如下:

第2节给出了本参考手册中使用的记号。

.第3节概述nesC1.1的新特征。

第4,5节,6,和7介绍nesC接口和组件.第8节给出nesC的协作模型和数据竞争监视.第9节解释C文件,nesC接口和组件是怎样被装配成一个应用.第10节包含nesC的保留的各种特征.最后,附录A完全定义nesC的文法(来自KernighanandRitchie(K&R)[2,pp234–239]附录A的对C文法述说的扩展),而附录B是本参考手册中所使用术语的专业词汇词典。

2符号

打字机字体作为nesC代码和文件名,带任意下标的单个斜体字符用于表示nesC实体,举例来说.,"组件K"或"数值v"。

nesC文法是ANSIC文法的扩展.我们选择来自KernighanandRitchie(K&R)的附录A的ANSIC文法[2,pp234–239]作为我们介绍的基础。

在这里我们将不重复ANSIC文法。

.斜体字是非终端机和非文字的终端机,打字机字体和符号是文字的终端机。

下标opt表示可选择的终端机或非终端机。

在一些情形中,我们改变一些ANSIC文法规则.我们用下面的方式表示:

also为现存的非终端机指出新增的内容,replacedby表示替换一现有的非终点的.nesC的结构解释给出对应的文法片段。

在这些片段中,我们有时使用...表现省略(与当前不相关的解释).附录A给出完整的nesC文法.一些例子使用来自C99标准inttypes.h文件的uint8t和uint16t类型.

3变化

nesC1.0版本同1.1版本的变化如下:

1.原子的陈述.这些单一化协同数据结构的实现,能够被新的编译-时间数据竞争监视器识别。

2.编译-时间数据竞争监视为可能的协同的二个中断操作者,或一个中断操作者和一件作业同时存取变量提出警告

3.指令和事件必须明确地标出存储类型说明才能安全地被中断操作者执行。

4.对指令或"扇出"事件的调用返回结果自动地被新的类型-特性的组合器执行联合。

5.uniqueCount是一个新的"常数功能",具有独特的作用.

6.NESC预处理程序符号指出语言版本.对于nesC1.1版本它是110。

4接口

nesC的接口有双向性:

它们描述一个多功能的两组件(供给者和使用者)之间的交互渠道.。

接口叙述一组叫做指令的,被接口的供给者实现的,被命名的功能和一组叫做事件的,被接口的使用者实现.的,被命名的功能。

本节解释接口如何被指定,第5节解释组件如何描述它们提供和使用的接口,第6节解释在C代码中指令和事件如何被调用和实现,而第7节解释组件接口如何被一起联编.

接口被接口类型指定,如下:

nesC-file:

includes-listoptinterface

...

interface:

interfaceidentifier{declaration-list}

storage-class-specifier:

alsooneof

commandeventasync

这声明接口类型标识符.这一标识符有全局的作用范围并且属于分开的命名空间,组件和接口类型命名空间。

如此所有接口类型都有清楚的名字以区别于其它接口和所有组件,同时能不和一般的C的声明发生任何冲突。

声明列表中,每个接口类型都有一个分开的声明范围。

声明列表必须由有指令或事件存储类型的功能描述组成(否则,会发生编译-时间错误).可选的async关键字指出指令或事件能在一个中断处理者中被运行。

通过包含列表,一个接口能可选择地包括C文件(见第9节)。

一个简单的接口如下:

interfaceSendMsg{

commandresult_tsend(uint16_taddress,uint8_tlength,TOS_MsgPtrmsg);

eventresult_tsendDone(TOS_MsgPtrmsg,result_tsuccess);

}

SendMsg接口类型提供者必须实现发送指令,而使用者必须实现sendDone事件.

5组件说明

一个nesC组件或是一个模块(第6节)或一个结构(第7节):

nesC-file:

includes-listoptmodule

includes-listoptconfiguration

...

module:

moduleidentifierspecificationmodule-implementation

configuration:

configurationidentifierspecificationconfiguration-implementation

组件的名字由标识符指定.这一标识符有全局的作用范围并且属于组件和接口类型命名空间.一个组件介入两个分组件的作用域:

一个规格作用域,属于C中全局的作用域,和一个实现作用域属于规格作用域。

通过包含列表,一个组件能可选择地包括C文件(见第9节).

组件规格列出该组件提供或使用的规格元素(接口请求,指令或事件)。

就如我们在第4节中见到的,一个组件必须实现它提供接口的指令和它的使用的接口事件。

另外,它必须实现它提供的指令和事件。

典型地,指令向下调用硬件组件,而事件向上调用应用组件(这表现为nesC应用如一个应用组件处于顶端的组件曲线图)。

一个控制线程只有通过它的规格元素越过组件。

每种规格元素有一个名字(接口实例名,命令名或事件名).这些名字属于总组件-规格作用域的变量命名空间。

specification:

{uses-provides-list}

uses-provides-list:

uses-provides

uses-provides-listuses-provides

uses-provides:

usesspecification-element-list

providesspecification-element-list

specification-element-list:

specification-element

{specification-elements}

specification-elements:

specification-element

specification-elementsspecification-element

一个组件说明中可以有多个使用和提供指令。

多个使用和提供规格元素可以通过包含在{and}中而组合在一个指令中。

举例来说,下面两个说明是一样的:

moduleA1{moduleA1{

usesinterfaceX;uses{

usesinterfaceY;interfaceX;

}...interfaceY;

}

}...

一个接口实例描述如下:

specification-element:

interfacerenamed-identifierparametersopt

...

renamed-identifier:

identifier

identifierasidentifier

interface-parameters:

[parameter-type-list]

接口实例声明的完整语法是interfaceXasY,明确地指明Y作为接口的名字。

interfaceX是interfaceXasX.的一个速记.

如果接口-叁数被省略,那么interfaceXasY声明一个简单的接口实例,对应这一组件的一个单一接口。

如果接口-叁数是给出的(举例来说.,interfaceSendMsgS[uint8tid]),那么就是一个参量接口实例声明,对应这一组件的多个接口,每个接口对应不同参数值(因此interfaceSendMsgS[uint8tid]声明SendMsg类型的256个接口).叁数的类型必须是完整的类型(这里enums是不允许的).指令或事件能通过包括一个声明了指令或事件及存储类型的标准的C函数而作为规格元素直接地被包含:

specification-element:

declaration

...

storage-class-specifier:

alsooneof

commandeventasync

如果该声明不是带有指令或事件存储类型的函数声明就会产生一编译-时间错误。

在接口中,文法指出指令或事件能被一中断操纵者运行。

作为接口实例,如果没有指定接口叁数,指令(事件)就是简单的指令(简单的事件),如果接口叁数是指定的,就是参数化指令(参数事件)。

接口叁数被放置在一般的函数叁数列表之前,举例来说.,

commandvoidsend[uint8tid](intx):

direct-declarator:

also

direct-declaratorinterface-parameters(parameter-type-list)

...

注意接口叁数只在组件说明里面指令或事件上被允许,而不允许在接口类型里面.

这儿有一个完整的规格例子:

configurationGenericComm{

provides{

interfaceStdControlasControl;

//该接口以当前消息序号作参数

interfaceSendMsg[uint8_tid];

interfaceReceiveMsg[uint8_tid];

}

uses{

//发送完成之后为组件作标记

//重试失败的发送

eventresult_tsendDone();

}

}...

在这个例子中,一般:

􀁺提供简单的接口实例类型StdControl的控制.

􀁺提供接口类型SendMsg和ReceiveMsg的参数实例;参数实例分别地叫做SendMsg和ReceiveMsg.

􀁺使用事件sendDone.

我们说,在组件K的规格中提供的一个指令(事件)F是K的提供指令(事件)F;同样地,一个被用于组件K的规格的指令(事件)是K的使用指令(事件)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}

这里编译基本单位是一连串的C声明和定义(见K&R[2,pp234–239])。

模块编译基本单位的顶层声明属于模块的组件说明域。

这些声明的范围是模糊的而且可以是:

任意的标准C声明或定义,一种作业声明或定义,指令或事件实现.

6.1实现模块的说明

编译基本单位必须实现模块的所有的提供指令(事件)a(例如.,所有的直接提供指令和事件,以及提供接口的所有指令和使用接口的所有事件).一个模块能调用它的任一指令和它的任一事件的信号.

这些指令和事件的实现由如下的C语法扩展指定:

storage-class-specifier:

alsooneof

commandeventasync

declaration-specifiers:

also

defaultdeclaration-specifiers

direct-declarator:

also

identifier.identifier

direct-declaratorinterface-parameters(parameter-type-list)

简单指令或事件a由带有存储类型指令或事件的C函数定义的语法实现(注意允许在函数名中直接定义的扩展)。

另外,语法关键字必须被包含如果它被包含在a的声明中。

举例来说,在SendMsg类型的提供接口Send的模块中:

commandresult_tSend.send(uint16_taddress,uint8_tlength,TOS_MsgPtrmsg){

...

returnSUCCESS;

}

带有接口参数P的参数指令或事件a,由带有存储类型指令或事件的函数定义的C文法实现,这时,函数的普通参数列表要以P作为前缀,并带上方括号(这与组件说明中声明参数化指令或事件是相同的文法)。

这些接口叁数声明P属于a的函数叁数作用域而且和普通的函数参数有相同的作用域。

举例来说,在SendMsg类型提供接口Send[uint8tid]的模块中:

commandresult_tSend.send[uint8_tid](uint16_taddress,uint8_tlength,

TOS_MsgPtrmsg){

...

returnSUCCESS;

}

以下情况将报告编译-时间错误:

􀁺提供指令或事件没有实现。

􀁺类型标志,可选择的接口叁数和指令或事件语法关键字的存在或缺失,或与模块说明不匹配

6.2调用命令和事件信号

对C语法的下列扩展用于调用事件和向指令发出信号:

postfix-expression:

postfix-expression[argument-expression-list]

call-kindoptprimary(argument-expression-listopt)

...

call-kind:

oneof

callsignalpost

一个简单的指令a使用call_(...)调用,一件简单的事件使用signala(...)发送讯号。

举例来说,在一个模块中使用SendMsg类型接口Send:

callSend.send(1,sizeof(Message),&msg1)。

一个参数指令a(个别地,一件事件)有n个接口叁数,类型为t1,...,tn由接口参数表达式e1,...,en调用如下:

call_[e1,...,en](...)(个别地,signal_[e1,...,en](...))。

接口叁数表达式ei必须分配类型ti;实际的接口叁数值是ei影射到ti.举例来说,在一个组件中使用类型SendMsg的接口Send[uint8tid]:

intx=...;

callSend.send[x+1](1,sizeof(Message),&msg1);

指令和事件的执行是立即的,也就是,调用和发送信号行为和函数调用是同样地。

实际的指令或事件是由调用还是信号表达运行取决于程序结构联系说明。

这些联系说明可能指定0,1或更多的实现将被运行。

当超过1个实现被运行,我们说模块的指令或事件为"扇出"。

一个模块能为一使用指令或事件a指定默认的调用或信号实现。

提供指令或事件的默认实现会引起编译-时间错误。

如果a未与任何指令或事件实现联系,默认的实现将被执行。

默认的指令或事件由带有默认关键字的指令或事件实现前缀定义:

declaration-specifiers:

also

defaultdeclaration-specifiers

举例来说,在一个类型SendMsg使用接口Send的模块中:

defaultcommandresult_tSend.send(uint16_taddress,uint8_tlength,

TOS_MsgPtrmsg){

returnSUCCESS;

}

/*允许调用即使接口发送未连接*/

...callSend.send(1,sizeof(Message),&msg1)...

第7.4节叙述实际上什么指令或事件实现被运行以及调用和信号表达返回什么结果.

6.3作业

作业是一个独立的控制点,由一个返回空存储类型的无二义性地函数定义:

taskvoidmyTask(){...}。

作业也能预先声明,举例来说.,taskvoidmyTask();

作业通过前缀post调用通知,举例来说.,postmyTask()。

通知返回迅速;如果独立执行通知成功则返回1,否则返回0。

通知表达式的类型是unsignedchar。

storage-class-specifier:

alsooneof

task

call-kind:

alsooneof

post

nesC的协作模型,包括作业,在第8节中详细陈述。

6.4原子的陈述

原子的陈述:

atomic-stmt:

atomicstatement

确保陈述被运行"好像"没有其它的运算同时发生。

它用于更新并发的数据结构的互斥变量,等等。

一简单的例子是:

boolbusy;//全局

voidf(){

boolavailable;

atomic{

available=!

busy;

busy=TRUE;

}

if(available)do_something;

atomicbusy=FALSE;

}

原子的区段应该很短,虽然这常常并不是必须的。

控制只能"正常地"流入或流出原子的陈述:

任何的goto,break或continue,跳转入或出一原子陈述都是错误的。

返回陈述决不允许进入原子陈述。

第8节讨论原子和nesC协作模型和数据竞争监视器之间的关系。

7结构

结构通过连接,或配线,集合其他组件实现一个组件说明:

configuration-implementation:

implementation{component-listoptconnection-list}

组件列表列出用来建立这一个结构的组件,连接列表指明各组件之间,以及与结构说明之间是怎样装配在一起的。

在这一节的其余部分中,我们调用来自结构的外部的规格元素,和来自结构的内在的成份之一的规格元素。

7.1包含组件

组件列表列出用来建立这一个结构的组件。

在结构里面这些组件可随意的重命名,使用共同外形规格元素,或简单的改变组件结构从而避免名称冲突。

(以避免必须改变配线)为组件选择的名字属于成份的实现域。

component-list:

components

component-listcomponents

components:

componentscomponent-line;

component-line:

renamed-identifier

component-line,renamed-identifier

renamed-identifier:

identifier

identifierasidentifier

如果二个组件使用as给出相同的名字,则会发生编译时间错误(举例来说.,componentsX,YasX)。

只有一个个别的例子:

如果组件K被用于二不同的结构(或甚至两次用于相同的结构里面),在程序中仍然只有K(及它的变量)的唯一实例。

7.2配线

配线用于连接规格元素(接口,指令,事件)。

本节和下一节(第7.3节)定义配线的语法和编译-时间规则。

第7.4节详细说明程序配线声明是如何指出在每个调用和信号表达中哪个函数被调用。

connection-list:

connection

connection-listconnection

connection:

endpoint=endpoint

e

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

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1