TinoyOs和nesC语言

nesC语言编程基础

 

1.接口

NesC程序主要由各式组件(component)构成,组件和组件之间通过特定的接口(interface)互相沟通。一个接口内声明了提供相关服务的方法(C语言函数)。例如数据读取接口(Read)内就包含了读取(read)、读取结束(readDone)函数。接口只是制定了组件之间交流的规范,也就是通过某一个接口,只能通过该接口提供的方法实现两个组件之间的交流。但是接口终归只是接口,只是一组函数的声明,并为包含对接口的实现。

 1 interface Read<val_t> {
 2   command error_t read();
 3   event void readDone( error_t result, val_t val );
 4 }

2.组件

NesC程序由组件构成。组件内主要是包含了对各类接口的使用(uses)和提供(provides)。例如组件A提供了Read接口,那A就需要负责实现Read接口内的read命令,也就是read命令的函数体,即“具体这个值是如何读取出来的”。因为命令(command)是由接口的提供者(provider)负责实现的。如果组件B使用了A提供的Read接口,那在读取数据结束以后,系统会返回给B一个“读取结束”的事件,而B则需要负责处理这个事件,即“数据读取完毕以后,我用这个数据干什么”,将值返回给计算机,或者是通过无线发送给其他传感器等等,所以事件(event)是由接口的使用者(user)来负责实现的。

组件分为两类。分别是模块(module)和配置(configuration)。模块内包含了程序的主干,也就是对各类命令和事件的实现,是NesC程序的可执行代码的主体。而配置则是负责将各个模块,通过特定的接口连接起来,其本身并不负责实现任何特定的命令或者事件。

以TinyOS附带的Blink(闪烁发光二极管)程序为例:

 
// BlinkC.nc
 #include "Timer.h"
 ​
 module BlinkC @safe()
 {
   uses interface Timer<TMilli> as Timer0;
   uses interface Timer<TMilli> as Timer1;
   uses interface Timer<TMilli> as Timer2;
   uses =interface Leds;
   uses interface Boot;
 }
 implementation
 {
   event void Boot.booted()
   {
     call Timer0.startPeriodic( 250 );
     call Timer1.startPeriodic( 500 );
     call Timer2.startPeriodic( 1000 );
   }
 ​
   event void Timer0.fired()
   {
     dbg("BlinkC", "Timer 0 fired @ %s.\n", sim_time_string());
     call Leds.led0Toggle();
   }
 ​
   event void Timer1.fired()
   {
     dbg("BlinkC", "Timer 1 fired @ %s \n", sim_time_string());
     call Leds.led1Toggle();
   }
 ​
   event void Timer2.fired()
   {
     dbg("BlinkC", "Timer 2 fired @ %s.\n", sim_time_string());
     call Leds.led2Toggle();
   }
 }
 
//BlinkAppC.nc
 configuration BlinkAppC
 {
 }
 implementation
 {
 components MainC, BlinkC, LedsC;
 components new TimerMilliC() as Timer0;
 components new TimerMilliC() as Timer1;
 components new TimerMilliC() as Timer2;
 ​
 ​
 BlinkC -> MainC.Boot;
 ​
 BlinkC.Timer0 -> Timer0;
 BlinkC.Timer1 -> Timer1;
 BlinkC.Timer2 -> Timer2;
 BlinkC.Leds -> LedsC;
 }

Blink程序由两个组件构成。BlinkC.nc为模块,BlinkAppC.nc为配置。

2.1 调用命令和事件信号

一个简单commanda可以使用call a()来调用,一个简单的event可以使用signal a()来触发。

若带参数的命令a有n个接口,类型为T1,...Tn由接口参数表达式e1...en调用如下:call ae1,...en;相应的可以用signal ae1,...en来触发事件。

2.2 任务

任务是一个独立的控制实体,由返回类型为void且无参数的函数定义。一个任务可以预先声明。例如:task void myTask(); 任务通过前缀post来提交,例如:post myTask().

2.3 原子

原子通常是最小的运行单元,其主要目的是其运行时,没有其他运算同时发生。一般用于更新并发性的互斥变量。例如:atomic{flag = 1;};

2.4 绑定

1)赋值绑定:endpoint1 = endpoint2;设S1是endpoint1的规范元素,S2是endpoint2的规范元素,则必须满足一下条件之一:

S1是内部的,S2是外部的(反之亦然),而且S1和S2都是被提供或被使用。

S1和S2都是外部的,一个被提供,一个被使用。

2)联编绑定:endpoint2->endpoint2,S1和S2都为内部的。

3.编程注意事项

3.1 所有的中断处理程序都是异步的,因此它们不能调用同步的函数。在中断处理程序中,执行同步函数唯一的方式是通过发布任务。任务的发布时一个异步过程,但任务本身的运行却是同步的操作。

3.2 TinyOS应用程序编写应当尽量采用同步代码。

3.3 atomic语句块能保证变量的读取具有原子性。注意:这并不意味着atomic语句块不会被抢占。即使是atomic语句块,倘若两个代码块使用不同得变量,也可以相互抢占。从理论上讲,funC可以抢占funA不可冒犯的原子性,但funA不能抢占它自身,funC也一样,即包含共同变量的atomic代码块不能相互抢占执行。

3.4 如果某个函数没有包含在一个atomic代码块里,但它总是在atomic代码块里被调用,那么编译器就不会发出警告。

3.5 atomic代码块会浪费cpu资源,应该尽量简短,从而使中断的延迟减少。

3.6 组件间的指针传递

组件调用send命令或者产生sendDone事件,就会放弃消息缓冲区的所有权,例如:组件A使用组件B提供的send接口,如果A调用了send传递参数message_t x,那么x的所有权就传给了B。在B可能访问x期间A不能再访问x。当B产生以x作为参数的sengDone事件后,x的所有权又归还给了A。

如果一个传递参数的接口有error_t类型的返回值,那么所有权只有在返回值为SUCCESS得时候才传递。

TinoyOs和nesC语言

nesC语言编程基础

1.接口

NesC程序主要由各式组件(component)构成,组件和组件之间通过特定的接口(interface)互相沟通。一个接口内声明了提供相关服务的方法(C语言函数)。例如数据读取接口(Read)内就包含了读取(read)、读取结束(readDone)函数。接口只是制定了组件之间交流的规范,也就是通过某一个接口,只能通过该接口提供的方法实现两个组件之间的交流。但是接口终归只是接口,只是一组函数的声明,并为包含对接口的实现。

 1 interface Read<val_t> {
 2   command error_t read();
 3   event void readDone( error_t result, val_t val );
 4 }

2.组件

NesC程序由组件构成。组件内主要是包含了对各类接口的使用(uses)和提供(provides)。例如组件A提供了Read接口,那A就需要负责实现Read接口内的read命令,也就是read命令的函数体,即“具体这个值是如何读取出来的”。因为命令(command)是由接口的提供者(provider)负责实现的。如果组件B使用了A提供的Read接口,那在读取数据结束以后,系统会返回给B一个“读取结束”的事件,而B则需要负责处理这个事件,即“数据读取完毕以后,我用这个数据干什么”,将值返回给计算机,或者是通过无线发送给其他传感器等等,所以事件(event)是由接口的使用者(user)来负责实现的。

组件分为两类。分别是模块(module)和配置(configuration)。模块内包含了程序的主干,也就是对各类命令和事件的实现,是NesC程序的可执行代码的主体。而配置则是负责将各个模块,通过特定的接口连接起来,其本身并不负责实现任何特定的命令或者事件。

以TinyOS附带的Blink(闪烁发光二极管)程序为例:

 // BlinkC.nc
 #include "Timer.h"
 ​
 module BlinkC @safe()
 {
   uses interface Timer<TMilli> as Timer0;
   uses interface Timer<TMilli> as Timer1;
   uses interface Timer<TMilli> as Timer2;
   uses =interface Leds;
   uses interface Boot;
 }
 implementation
 {
   event void Boot.booted()
   {
     call Timer0.startPeriodic( 250 );
     call Timer1.startPeriodic( 500 );
     call Timer2.startPeriodic( 1000 );
   }
 ​
   event void Timer0.fired()
   {
     dbg("BlinkC", "Timer 0 fired @ %s.\n", sim_time_string());
     call Leds.led0Toggle();
   }
 ​
   event void Timer1.fired()
   {
     dbg("BlinkC", "Timer 1 fired @ %s \n", sim_time_string());
     call Leds.led1Toggle();
   }
 ​
   event void Timer2.fired()
   {
     dbg("BlinkC", "Timer 2 fired @ %s.\n", sim_time_string());
     call Leds.led2Toggle();
   }
 }
 //BlinkAppC.nc
 configuration BlinkAppC
 {
 }
 implementation
 {
 components MainC, BlinkC, LedsC;
 components new TimerMilliC() as Timer0;
 components new TimerMilliC() as Timer1;
 components new TimerMilliC() as Timer2;
 ​
 ​
 BlinkC -> MainC.Boot;
 ​
 BlinkC.Timer0 -> Timer0;
 BlinkC.Timer1 -> Timer1;
 BlinkC.Timer2 -> Timer2;
 BlinkC.Leds -> LedsC;
 }

Blink程序由两个组件构成。BlinkC.nc为模块,BlinkAppC.nc为配置。

2.1 调用命令和事件信号

一个简单commanda可以使用call a()来调用,一个简单的event可以使用signal a()来触发。

若带参数的命令a有n个接口,类型为T1,...Tn由接口参数表达式e1...en调用如下:call ae1,...en;相应的可以用signal ae1,...en来触发事件。

2.2 任务

任务是一个独立的控制实体,由返回类型为void且无参数的函数定义。一个任务可以预先声明。例如:task void myTask(); 任务通过前缀post来提交,例如:post myTask().

2.3 原子

原子通常是最小的运行单元,其主要目的是其运行时,没有其他运算同时发生。一般用于更新并发性的互斥变量。例如:atomic{flag = 1;};

2.4 绑定

1)赋值绑定:endpoint1 = endpoint2;设S1是endpoint1的规范元素,S2是endpoint2的规范元素,则必须满足一下条件之一:

S1是内部的,S2是外部的(反之亦然),而且S1和S2都是被提供或被使用。

S1和S2都是外部的,一个被提供,一个被使用。

2)联编绑定:endpoint2->endpoint2,S1和S2都为内部的。

3.编程注意事项

3.1 所有的中断处理程序都是异步的,因此它们不能调用同步的函数。在中断处理程序中,执行同步函数唯一的方式是通过发布任务。任务的发布时一个异步过程,但任务本身的运行却是同步的操作。

3.2 TinyOS应用程序编写应当尽量采用同步代码。

3.3 atomic语句块能保证变量的读取具有原子性。注意:这并不意味着atomic语句块不会被抢占。即使是atomic语句块,倘若两个代码块使用不同得变量,也可以相互抢占。从理论上讲,funC可以抢占funA不可冒犯的原子性,但funA不能抢占它自身,funC也一样,即包含共同变量的atomic代码块不能相互抢占执行。

3.4 如果某个函数没有包含在一个atomic代码块里,但它总是在atomic代码块里被调用,那么编译器就不会发出警告。

3.5 atomic代码块会浪费cpu资源,应该尽量简短,从而使中断的延迟减少。

3.6 组件间的指针传递

组件调用send命令或者产生sendDone事件,就会放弃消息缓冲区的所有权,例如:组件A使用组件B提供的send接口,如果A调用了send传递参数message_t x,那么x的所有权就传给了B。在B可能访问x期间A不能再访问x。当B产生以x作为参数的sengDone事件后,x的所有权又归还给了A。

如果一个传递参数的接口有error_t类型的返回值,那么所有权只有在返回值为SUCCESS得时候才传递。

TinoyOs和nesC语言

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值