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得时候才传递。
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得时候才传递。
文章浏览阅读51次。免费领取项目源码,请关注赞收藏并私信博主,谢谢-本课题研究的疫情返乡人员管理系统,主要功能模块包括:防疫须知、疫情用品、返乡报备、用户反馈管理等,主要是主要采取Mysql作为后台数据的主要存储单元,运用软件工程原理和开发方法,采用Python的Django技术构建的,实现了系统的全部功能。本次报告,首先分析了研究的背景、作用、意义,为研究工作的合理性打下了基础。
文章浏览阅读1.1k次。首先我这篇博客的内容是我不知道oracle里的 cache 是什么,结果越查越多。。。“序列的cache通常为 20,但在需要依据序列值判断创建的先后顺序时必须是 NOCACHE”,关于这句话,是公司的数据库规范里提到的一句话,但是我感觉nocache会导致的问题好像还不少,所以我很纠结,但是除了根据序列值判断创建的先后顺序外,还有其他的靠谱的方式来判断先后顺序吗?难道入库时间不可以吗..._数据库中的nocache是什么意思
文章浏览阅读193次。一、字符串多行书写有时为了书写阅读方便,需要将一大串的字符串写成多行举例源码 MyUart_Printf("moduleConfigParams=>\r\n"\ "\tuartBaudrate:%s\r\n"\ "\tuartStopbit:%s\r\n"\ "\tparityType:%s\r\n"\ "\trfC..._c语言编辑多行源代码中的字符串
文章浏览阅读1.2k次。随着人工智能技术的普及,越来越多的前端程序员开始关注相关技术。Python 作为人工智能领域最常用的语言,与前端程序员日常使用的语言 JavaScript 同属脚本语言,且在两者发展过程中,社区也多有相互借鉴之处,因此有很多相似。一个熟悉 JavaScript 语言的前端程序员,通过掌握了他们之间的不同之处,可以快速上手 Python 。以下是我学习过程中记录的 Python 不同于 JavaSc..._js python 语法 区别
文章浏览阅读744次。《德系VS日系》比较客观的文章作者:颜宇鹏,新车评网创办人之一、总编辑、首席车评人、视频版主持人。从业超过十年,曾任专业汽车杂志试车总监、主编。阅车无数,对全球车型发展、中国汽车市场、试车驾驶技术有深厚积累,其见解独到的车评备受读者喜爱和业界推崇。在讨论“德系VS日系”这个话题时,我想先确立以下几点基础原则。..._2019新君威的前后防碰梁
文章浏览阅读448次。首先简单了解一下 FormData,点击链接:https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/Using_FormData_ObjectsIE浏览器版本最好为:IE10+,因为 FormData 兼容性问题然后查看示例,代码如下↓html 代码:<!DOCTYPE html><html lan..._ajajx提交文件到php
文章浏览阅读249次,点赞4次,收藏4次。openGauss提供向量化引擎,通常用在OLAP数据仓库类系统。主要是因为分析型系统通常是数据处理密集型,基本上都是采用顺序方式来访问表中大部分的数据,然后再进行计算,最后将计算结果输出给用户。
文章浏览阅读639次。相信很多站长在使用宝塔面板的同时也会安装云锁用于加固服务器安全性,不过有时因为Nginx版本过高等问题导致安装云锁时无法自动安装Web防护模块,所以还需要我们在Linux系统下额外将云锁Web防护模块编译进Nginx才可以。之前也转载过一篇一、上传云锁Web防护模块压缩包并解压Ps:其实宝塔添加模块功能里可以通过配置shell脚本实现这些前置准备,但我还是喜欢用手动的方式上传,这样使步骤看起来更直..._宝塔 云锁自编译 测试
文章浏览阅读8.4k次。原文作者:雪飘碧鸳 在github上导入项目,或其他地方导入Android Studio,出现Error:A problem occurred configuring project ‘:app’.的错误。其实这种错误有很多种原因,需要对每种情况进行不同的处理才行,这里说的一种情况是JNI的情况,即该项目使用到C/C++库,此时需要引入NDK才行,先看下错误提示Gradle ‘trunk’ ..._error:a problem occurred configuring project ':app'.
文章浏览阅读603次。groupby一个索引的比较简单,这里主要讲两个索引的:这里先设dataframe为下图然后根据第0列和第1列来进行分组,再对第二列进行数量统计,这里用了nunique函数来进行数量统计上图中最上面的2表示是根据原表的第3列即序号2的那一列使用的agg函数得到的结果。unstack是把一维表转换成二维表,即把(0,1)这对分组条件分别写成表的行列索引,一一对应agg函数得到的结果,如下图:stack是把二维表转换成一维表,类似花括号形式(就像是思维导图一层一层括出去),第一列写上原本的行索引_group by unstack
文章浏览阅读2.2k次。宝塔新建网站:假设文件夹根目录为/home/nextcloud创建FTP,数据集。并且选择php版本。删除文件夹根目录/home/nextcloud下的两个html文件。下载nextcloud文件:官网链接可以使用wget:wget https://download.nextcloud.com/server/releases/nextcloud-20.0.0.zip,或者本地端下载后拖过去。多线程下载:sudo apt install axel axel -n 20 ht.._宝塔做nas
文章浏览阅读41次。Scala 用val定义常量,用var定义变量。常量重新赋值就会报错。变量没有问题。注意:我们不需要给出值或者变量的类型,scala初始化表达式会自己推断出来。当然我们也可以指定类型。多个值和变量可以一起声明:Scala 类型:Byte, Char, Short, Int, Long, Float, Double, BooleanScala不区分基...