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 的一本参考手册并非个别指导。TinyOS tutorial1给出了对 nesC 的更贴切的介绍.
本文的其余部分构成如下: 第 2 节给出了本参考手册中使用的记号。. 第 3 节概述 nesC 1.1 的新特征。 第 4,5 节,6, 和 7介绍 nesC 接口和组件. 第 8 节给出 nesC的协作模型和数据竞争监视. 第 9 节解释 C文件, nesC 接口和组件是怎样被装配成一个应用. 第 10 节包含 nesC 的保留的各种特征. 最后,附录A完全定义 nesC 的文法 (来自Kernighan and Ritchie (K&R) [2, pp234–239]附录A的对 C 文法述说的扩展),而附录 B 是本参考手册中所使用术语的专业词汇词典。
2 符号
打字机字体作为 nesC 代码和文件名,带任意下标的单个斜体字符用于表示 nesC 实体,举例来说., " 组件 K" 或 " 数值 v"。nesC文法是ANSI C 文法的扩展. 我们选择来自 Kernighan and Ritchie (K&R) 的附录A的 ANSI C 文法[2, pp234 –239]作为我们介绍的基础。在这里我们将不重复ANSI C文法。. 斜体字是非终端机和非文字的终端机,打字机字体和符号是文字的终端机。 下标 opt 表示可选择的终端机或非终端机。在一些情形中,我们改变一些 ANSI C 文法规则. 我们用下面的方式表示:also 为现存的非终端机指出新增的内容,replaced by表示替换一现有的非终点的.nesC 的结构解释给出对应的文法片段。在这些片段中,我们有时使用 . . . 表现省略( 与当前不相关的解释). 附录A给出完整的 nesC 文法.一些例子使用来自 C99 标准 inttypes.h 文件的 uint8 t 和 uint16 t 类型.
3 变化
nesC 1.0版本同1.1版本的变化如下:
1. 原子的陈述. 这些单一化协同数据结构的实现,能够被新的编译- 时间数据竞争监视器识别。
2. 编译- 时间数据竞争监视为可能的协同的二个中断操作者 , 或一个中断操作者和一件作业同时存取变量提出警告
3. 指令和事件必须明确地标出存储类型说明才能安全地被中断操作者执行。
4. 对指令或"扇出"事件的调用返回结果自动地被新的类型- 特性的组合器执行联合。
5. uniqueCount 是一个新的 " 常数功能 ", 具有独特的作用.
6. NESC 预处理程序符号指出语言版本. 对于 nesC 1.1版本它是 110 。
4 接口
nesC 的接口有双向性: 它们在两个组件之间建立了一个由多个函数组成的接口的通道,分为provider(供给)和use(使用)。接口声明了一组函数,分为两种,一种函数叫做commands, 由接口的供给者实现。另一种叫做events,留给接口的使用者实现。
本节解释接口如何被说明, 第 5 节解释组件如何描述它们提供和使用的接口, 第 6 节解释在 C代码中指令和事件如何被调用和实现,而第 7 节解释组件接口如何被一起联编.
接口被接口类型指定,如下:
nesC-file:
includes-listopt interface
interface:
interface identifier { declaration-list }
storage-class-specifier: also one of
command event async
这声明接口类型标识符. 这一标识符有全局的作用范围并且属于分开的命名空间,组件和接口类型命名空间。 如此所有接口类型都有清楚的名字以区别于其它接口和所有组件, 同时能不和一般的 C的声明发生任何冲突。
声明列表中,每个接口类型都有一个分开的声明范围。声明列表必须由有指令或事件存储类型的功能描述组成( 否则, 会发生编译-时间错误). 可选的 async 关键字指出指令或事件能在一个中断处理者中被运行。
通过包含列表,一个接口能可选择地包括 C 文件 (见第9节)。
一个简单的接口如下:
interface SendMsg {
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 事件.
注:纯粹的接口其实就是一组函数声明的集合。其本身没有实现任何功能。它的函数功能的实现是在module中去实现的。
5 组件说明
一个 nesC 组件或是一个模块 (第 6 节) 或一个结构 (第 7 节):
nesC-file:
includes-listopt module
includes-listopt configuration
module:
module identifier specification module-implementation
configuration:
configuration identifier specification configuration-implementation
组件的名字由标识符指定. 这一标识符有全局的作用范围并且属于组件和接口类型命名空间. 一个组件介入两个分组件的作用域::一个规格作用域,属于 C 中全局的作用域,和一个实现作用域属于规格作用域。
通过包含列表,一个组件能可选择地包括 C 文件 (见第9节).
组件规格列出该组件提供或使用的规格元素 (接口请求,指令或事件)。就如我们在第 4 节中见到的,一个组件必须实现它提供接口的指令和它的使用的接口事件。另外,它必须实现它提供的指令和事件。
典型地,指令向下调用硬件组件,而事件向上调用应用组件 (这表现为nesC应用如一个应用组件处于顶端的组件曲线图)。 一个控制线程只有通过它的规格元素越过组件。
每种规格元素有一个名字 (接口实例名,命令名或事件名).这些名字属于总组件-规格作用域的变量命名空间。
specification:
{ uses-provides-list }
uses-provides-list:
uses-provides
uses-provides-list uses-provides
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}中而组合在一个指令中。举例来说,下面两个说明是一样的:
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 ]
接口实例声明的完整语法是 interface X as Y,明确地指明Y作为接口的名字。interface X是interface X as X.的一个速记.
如果接口没有参数, 那么interface X as Y 声明一个简单的接口实例,对应这一组件的一个单一接口。 如果一个带参数的接口 (如: interface SendMsg[uint8 t id]) ,那么这就是一个带参量接口的实例声明。对应这一组件的多个接口, 每个接口对应不同参数值(因此interface SendMsg[uint8 t id]声明了最多256个SendMsg类型接口)。参数的类型必须是整数类型 (这里enums 是不允许的)。
commands或event事件能够作为一个特殊的元素,被使用command或event关键字的标准C语言函数声明,包含到类声明中来:
specification-element:
declaration
storage-class-specifier: also one of
command event async
如果该函数声明没有command或event关键字,那么就会产生“编译—时间”错误。在接口中,async (异步)表示command或event事件允许中断发生并执行此中断程序。
作为接口实例, 如果没有指定接口参数,指令 (事件)就是简单的command (简单的event)。
如果接口参数是已经被指定,就是参数化的指令command (参数事件event)。接口参数被放置在一般的函数参数列表之前,举例来说,
command void send[uint8 t id](int x):
direct-declarator: also
direct-declarator interface-parameters ( parameter-type-list )
注意接口参数只在组件说明里面的指令或事件上被允许, 而不允许在接口类型里面.
这儿有一个完整的规格例子:
configuration GenericComm
{
     provides {
               interface StdControl as Control;// 该接口以当前消息序号作参数
               interface SendMsg[uint8_t id];
               interface ReceiveMsg[uint8_t id];
               }
     uses {
             //发送完成之后为组件作标记
             //重试失败的发送
            event result_t sendDone();
 
           }
} ...
在这个例子中,一般:
      提供简单的接口实例类型 StdControl 的控制.
      提供接口类型 SendMsg 和 ReceiveMsg 的参数实例; 参数实例分别地叫做 SendMsg 和 ReceiveMsg.
      使用事件 sendDone.
我们说,在组件component K 的规范中提供的一个command (event) F 是component K的provides  command(event)F; 同样地,一个被组件 K 的规范中使用的command (event) 是K 的uses command (event) F。
如果组件K中有接口实例X, command F是接口X的一个函数称之为 X.F,我们是可说X.F属于K;
6 模块
模块用C代码实现组件说明:
module-implementation:
implementation { translation-unit }
这里编译基本单位是一连串的 C 声明和定义 ( 见K& R[2 , pp234 –239])。
模块编译基本单位的顶层声明属于模块的组件说明域。这些声明的范围是模糊的而且可以是: 任意的标准 C声明或定义,一种作业声明或定义,指令或事件实现.
6.1 实现模块的说明
编译基本单位必须实现模块的所有的提供指令 (事件)a (例如., 所有的直接提供指令和事件, 以及提供接口的所有指令和使用接口的所有事件). 一个模块能调用它的任一指令和它的任一事件的信号.
这些指令和事件的实现由如下的 C 语法扩展指定:
storage-class-specifier: also one of
command event async
declaration-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.send(uint16_t address, uint8_t length, TOS_MsgPtr msg) {
return SUCCESS;
}
带有接口参数P的参数指令或事件a,由带有存储类型指令或事件的函数定义的C文法实现,这时,函数的普通参数列表要以P作为前缀,并带上方括号 ( 这与组件说明中声明参数化指令或事件是相同的文法)。这些接口叁数声明P 属于a的函数叁数作用域而且和普通的函数参数有相同的作用域。举例来说,在SendMsg类型提供接口Send[uint8 tid]的模块中:
command result_t Send.send[uint8_t id](uint16_t address, uint8_t length,
TOS_MsgPtr msg) {
return SUCCESS;
}
以下情况将报告编译- 时间错误:
提供指令或事件没有实现。
类型标志,可选择的接口叁数和指令或事件语法关键字的存在或缺失,或与模块说明不匹配
6.2 调用命令和事件信号
对 C 语法的下列扩展用于调用事件和向指令发出信号:
postfix-expression:
postfix-expression [ argument-expression-list ]
call-kindopt primary ( argument-expression-listopt )
call-kind: one of
call signal post
命令函数的command a ,使用call a(...)调用, 事件函数使用signal a(...)发送讯号。例如:在一个模块中使用SendMsg类型接口Send:call Send.send(1,sizeof(Message), &msg1)。
如果是带有n个参数的command a(或者是一个事件event),参数的类型为t1,t2....tn,参数的值是e1...en.那么调用的方式如下:call a[e1...en](...) (特别地,signal a[e1...en](...))。接口参数值表达式 ei 的类型为ti; 实际的接口参数值ei影射到ti。 例如, 在一个组件中使用类型 SendMsg 的接口Send[uint8 t id]:
int x = ...;
call Send.send[x + 1](1, sizeof(Message), &msg1);
commands和events的执行是立即的,也就是,call和signal调用行为是立即的。实际的command或event事件是由调用还是信号表达运行取决于程序结构联系说明。这些联系说明可能指定0,1 或更多的实现将被运行。当超过 1个实现被运行, 我们说模块的指令或事件为"扇出"。
一个模块能为一使用指令或事件a指定默认的调用或信号实现。提供指令或事件的默认实现会引起编译-时间错误。如果a未与任何指令或事件实现联系,默认的实现将被执行。默认的指令或事件由带有默认关键字的指令或事件实现前缀定义:
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) ...
第 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
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;
}
原子的区段应该很短, 虽然这常常并不是必须的。控制只能" 正常地 " 流入或流出原子的陈述: 任何的 goto, break或continue,跳转入或出一原子陈述都是错误的。返回陈述决不允许进入原子陈述。
第 8 节讨论原子和 nesC协作模型和数据竞争监视器之间的关系。

nesC 1.1 语言参考手册 (1)相关推荐

  1. 『TinyOS』 nesC 1.1 语言参考手册

    8 nesC 的协作 nesC 采用由一旦运行直至完成作业(代表性的实时运算)和硬件异步触发中断控制构成的运行模型.编译器依靠用户提供的事件句柄和原语特征来识别中断源 (见10.3节).nesC调度程 ...

  2. nesC 1.1 语言参考手册(2)

    7 配置 配置是通过连接.配线,建立与其他组件的连接: configuration-implementation: implementation { component-listopt connect ...

  3. c语言初始化字符串 函数 manment,nesC语言参考手册.doc

    nesC语言参考手册 1 简介 nesC 是对 C 的扩展 ,它基于体现 TinyOS 的结构化概念和执行模型而设计. TinyOS 是为传感器网络节点而设计的一个事件驱动的操作系统,传感器网络节点拥 ...

  4. cc++语言参考手册_C ++值类别快速参考:第2部分

    c&c++语言参考手册 ← Go to Part 1 ← 转到第1部分 将参数传递给函数 (Passing parameters to a function) When passing par ...

  5. Python语言参考手册

    Python语言参考手册 3 数据模型 3.3 特殊的方法名称 3.3.2 自定义属性获取 3 数据模型 3.3 特殊的方法名称 3.3.2 自定义属性获取 可以通过定义下列方法来自定义(使用.分配或 ...

  6. python - references 之 python语言参考手册目录

    python 语言参考手册 官方文档link: https://docs.python.org/zh-cn/3/reference/index.html 目录 1. 概述 1.1. 其他实现 1.2. ...

  7. nesC 语言参考手册

    1 简介 nesC 是对 C 的扩展 ,它基于体现 TinyOS 的结构化概念和执行模型而设计. TinyOS 是为传感器网络节点而设计的一个事件驱动的操作系统,传感器网络节点拥有非常有限的资源 ( ...

  8. 金仓数据库 KingbaseES SQL 语言参考手册 (11. SQL语句:ABORT 到 ALTER INDEX)

    11. SQL语句:ABORT 到 ALTER INDEX 本章描述各种类型的SQL语句,由于类型较多,将按字母顺序排列分组.这是第一组SQL语句. 包含以下章节: SQL语句类型 SQL语句各章节是 ...

  9. 金仓数据库 KingbaseES SQL 语言参考手册 (13. SQL语句:ALTER SYNONYM 到 COMMENT)

    13. SQL语句:ALTER SYNONYM 到 COMMENT 本章包含以下SQL语句: ALTER SYNONYM ALTER SYSTEM ALTER TABLE ALTER TABLESPA ...

最新文章

  1. 高并发-【抢红包案例】之二:使用悲观锁方式修复红包超发的bug
  2. [转载]AngularJS之Factory vs Service vs Provider
  3. 通过分区在Kafka中实现订单保证人
  4. matlab 计算 工程,matlab工程计算.doc
  5. python基础整理——ASCII码、Unicode、utf-8、gbk
  6. UI设计新趋势|拟物风格UI设计素材模板
  7. es6语法在ios低版本的支持性
  8. mysql数据库日志太多_数据库Log太多如何清理但是不影响mysql原本的表数据。
  9. #436. 子串的最大差(单调栈)
  10. python拍3游戏_用Python实现小3传奇小游戏(源代码)
  11. 如何对一个普通的Java项目进行打包,打成jar包,idea操作
  12. GB35114—⑤、附 录C
  13. 论一只爬虫的自我修养11:Scrapy框架之初窥门径
  14. FreeSSL + ACME自动化续期域名SSL证书(支持泛域名)
  15. 斑马打印机设置成网络打印机步骤
  16. VNC远程控制软件,VNC远程控制软件如何实现批量管理服务器
  17. ConstraintLayout实现左中右布局
  18. ES2015 解构 Destructuring
  19. 汽车嵌入式软件自动化测试的方法及推荐工具
  20. 大学生的秘密,全都藏在快递里

热门文章

  1. EXCEL密码VBA解决
  2. Python实现批量图像文字识别并指定部分提取
  3. C++软件工程师面试题汇总
  4. 磁盘清理工具:DaisyDisk for Mac 4.20.3
  5. 用matlab打造的摩斯电码加解码器音频版,支持包括中文在内的任意字符
  6. S32 Design Studio licence missing
  7. yolov7训练BDD100k自动驾驶环境感知2D框检测模型
  8. 联发科p60和骁龙710哪个好_一文读懂骁龙710/骁龙660/骁龙845/Helio P60的区别,联发科有苦说不出?-控制器/处理器-与非网...
  9. Picasso实现下载圆形头像以及圆角图片
  10. android 老人机模式,老人模式简单至上_小米 红米_手机Android频道-中关村在线