文章目录
一、基础知识
1.1 AMSenderC组件接口:AMPacket
活动消息访问器,提供AM本地地址和用于查询(querying)数据包的功能。 活动消息是单跳通信协议。 因此,诸如源和目标的字段表示单跳源和目标。 多跳源和目标由相应的(corresponding)多跳协议(如果有)定义。 另请参阅数据包接口。
command am_addr_t address() 不清楚
command am_addr_t address()
返回与此AM堆栈关联的节点的活动消息地址。
am_addr_t destination(message_t *amsg) 返回AM数据包的AM目标地址
command am_addr_t destination(message_t *amsg)
返回AM数据包的AM目标地址。
message_t* msg = xxx;
am_addr_t addr ;
addr = call AMPacket.destination(msg);
command am_addr_t source(message_t *amsg) 返回AM数据包的AM源地址
command am_addr_t source(message_t *amsg)
返回AM数据包的AM源地址。
message_t* msg = xxx;
am_addr_t source;
source = call AMPacket.source(msg);
am_id_t type(message_t *amsg) 返回AM数据包的AM种类
command am_id_t type(message_t *amsg)
返回AM数据包的AM种类。
message_t* msg = xxx;
am_id_t id;
id = call AMPacket.type(msg);
setSource(message_t *amsg, am_addr_t addr) 设置AM数据包的源地址。
command void setSource(message_t *amsg, am_addr_t addr)
设置AM数据包的源地址。
setDestination(message_t *amsg, am_addr_t addr) 设置AM数据包的目标地址。
command void setDestination(message_t *amsg, am_addr_t addr)
设置AM数据包的目标地址。
1.3 AMSenderC组件接口:Packet
clear(message_t *msg) 清除这个数据包
command void clear(message_t *msg)
清除这个数据包
payloadLength(message_t *msg) 返回消息的有效载荷的长度
command uint8_t payloadLength(message_t *msg)
Return the length of the payload of msg.返回消息的有效载荷的长度。
1.3 AMSenderC组件接口:AMSend
send(am_addr_t addr, message_t *msg, uint8_t len) 无线发送数据包
command error_t send(am_addr_t addr, message_t *msg, uint8_t len)
message_t* msg = xxx;
len = call Packet.payloadLength(msg);
addr = call AMPacket.destination(msg);
source = call AMPacket.source(msg);
id = call AMPacket.type(msg);
call Packet.clear(msg);
call AMPacket.setSource(msg, source);
if (call RadioSend.send[id](addr, msg, len) == SUCCESS)
{
//。。。
}
1.2 TinyOS中的任务
TinyOS中关键字 async 声明了可被硬件事件句柄执行的命令或事件,这意味着它们可在任何时候执行(可能抢占其他代码的执行),因此 async 命令和事件所做的工作应该尽可能地少而且应快速。
任务 task 用来执行更长时间的处理操作,如背景数据处理等,同时,任务可以被硬件事件句柄所抢占。
任务的声明:
task void taskname() { … }
其中
taskname()是程序员任意指定的任务名称标识。
任务的返回值类型必须是 void,而且不可以带参数。
例如:
SenseTaskM.nc, continued
task void processData() {
int16_t i, sum=0;
atomic {
for (i=0; i < size; i++)
sum += (rdata[i] >> 7);
}
display(sum >> log2size);
}
在任务 processData()中使用了关键字 atomic ,这样的语句在 nesC 中被称为“原子语句(atomic statement)。
代码中 atomic 的含义是其后花括号内的代码段在执行过程中不可以被抢占。
注意:原子语句会推迟中断处理,从而使得系统的反应看起来不迅速。
任务的调用:
post taskname();
可以从一个命令、事件、甚至是另外一个任务内部“布置(post)”任务。
布置操作将任务放入一个以先进先出(FIFO)方式处理的内部任务队列。当某个任务执行时,它会一直运行直至结束,然后下一个任务开始执行。因此,任务不应该被挂起或阻塞太长时间。虽然任务之间不能够相互抢占,但任务可能被硬件事件句柄所抢占。如果要运行一系列较长的操作,应该为每个操作分配一个任务,而不是使用一个过大的任务。
SenseTaskM.nc
// ADC data ready event handler
async event result_t ADC.dataReady(uint16_t data) {
putdata(data); //将新的样本数据插入到缓冲区中
post processData(); //启动任务 processData()进行数据的处理
return SUCCESS;
}
二、源码分析
点源码
BlinkToRadioC.nc
发送流程:
- 上电后开启无线通信的组件
- 开启无线通信组件成功后,开启定时器并且设置周期250ms
- 定时器周期达到后,发送数据包(包含自身节点标识TOS_NODE_ID,counter数值),锁定发送,发送成功后解锁。
接收流程:
- 开启无线通信
- 过滤长度不符合的数据
- 给数据起别名,并且转化数据类型
- 根据rcm->counter ,执行相应的灯操作。
#include <Timer.h>
#include "BlinkToRadio.h"
configuration BlinkToRadioAppC {
}
implementation {
components MainC;
components LedsC;
components BlinkToRadioC as App;
components new TimerMilliC() as Timer0;
components ActiveMessageC;
components new AMSenderC(AM_BLINKTORADIO);
components new AMReceiverC(AM_BLINKTORADIO);
App.Boot -> MainC;
App.Leds -> LedsC;
App.Timer0 -> Timer0;
App.Packet -> AMSenderC;
App.AMPacket -> AMSenderC;
App.AMControl -> ActiveMessageC;
App.AMSend -> AMSenderC;
App.Receive -> AMReceiverC;
}
#include <Timer.h>
#include "BlinkToRadio.h"
module BlinkToRadioC {
uses interface Boot;
uses interface Leds;
uses interface Timer<TMilli> as Timer0;
uses interface Packet;
uses interface AMPacket;
uses interface AMSend;
uses interface Receive;
uses interface SplitControl as AMControl;
}
implementation {
uint16_t counter;
message_t pkt;
bool busy = FALSE;
void setLeds(uint16_t val) {
if (val & 0x01)
call Leds.led0On();
else
call Leds.led0Off();
if (val & 0x02)
call Leds.led1On();
else
call Leds.led1Off();
if (val & 0x04)
call Leds.led2On();
else
call Leds.led2Off();
}
event void Boot.booted() {
call AMControl.start();
}
event void AMControl.startDone(error_t err) {
if (err == SUCCESS) {
call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
}
else {
call AMControl.start();
}
}
event void AMControl.stopDone(error_t err) {
}
event void Timer0.fired() {
counter++;
if (!busy) {
BlinkToRadioMsg* btrpkt =
(BlinkToRadioMsg*)(call Packet.getPayload(&pkt, sizeof(BlinkToRadioMsg)));
if (btrpkt == NULL) {
return;
}
btrpkt->nodeid = TOS_NODE_ID;
btrpkt->counter = counter;
if (call AMSend.send(AM_BROADCAST_ADDR,
&pkt, sizeof(BlinkToRadioMsg)) == SUCCESS) {
busy = TRUE;
}
}
}
event void AMSend.sendDone(message_t* msg, error_t err) {
if (&pkt == msg) {
busy = FALSE;
}
}
event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len){
if (len == sizeof(BlinkToRadioMsg)) {
BlinkToRadioMsg* btrpkt = (BlinkToRadioMsg*)payload;
setLeds(btrpkt->counter);
}
return msg;
}
}
基站源码:
Makefile
CFLAGS += -DCC2420_NO_ACKNOWLEDGEMENTS //不回复ack
CFLAGS += -DCC2420_NO_ADDRESS_RECOGNITION //不开启地址识别
表示开始混杂模式。
COMPONENT=BaseStationC
CFLAGS += -DCC2420_NO_ACKNOWLEDGEMENTS
CFLAGS += -DCC2420_NO_ADDRESS_RECOGNITION
CFLAGS += -DTASKLET_IS_TASK
CFLAGS += -DCC2420_DEF_CHANNEL=14
include $(MAKERULES)
BaseStationC.nc
ActiveMessageC 组件也有AMSend,Receive,Packet,AMPacket接口。
以后可以直接使用ActiveMessageC组件,抛弃AMSenderC,AMReceiverC组件。
configuration BaseStationC {
}
implementation {
components MainC, BaseStationP, LedsC;
components ActiveMessageC as Radio, SerialActiveMessageC as Serial;
MainC.Boot <- BaseStationP;
BaseStationP.RadioControl -> Radio;
BaseStationP.SerialControl -> Serial;
BaseStationP.UartSend -> Serial;
BaseStationP.UartReceive -> Serial.Receive;
BaseStationP.UartPacket -> Serial;
BaseStationP.UartAMPacket -> Serial;
BaseStationP.RadioSend -> Radio;
BaseStationP.RadioReceive -> Radio.Receive;
BaseStationP.RadioSnoop -> Radio.Snoop;
BaseStationP.RadioPacket -> Radio;
BaseStationP.RadioAMPacket -> Radio;
BaseStationP.Leds -> LedsC;
}
BaseStationP.nc
流程:
- 上电后,初始化数据数组,然后打开无线通信,串口通信。
- 等待无线接收数据事件被触发。(正常接收到的包,窃听接收到的包)
#include "AM.h"
#include "Serial.h"
module BaseStationP @safe() {
uses {
interface Boot;
interface SplitControl as SerialControl;
interface SplitControl as RadioControl;
interface AMSend as UartSend[am_id_t id];
interface Receive as UartReceive[am_id_t id];
interface Packet as UartPacket;
interface AMPacket as UartAMPacket;
interface AMSend as RadioSend[am_id_t id];
interface Receive as RadioReceive[am_id_t id];
interface Receive as RadioSnoop[am_id_t id];
interface Packet as RadioPacket;
interface AMPacket as RadioAMPacket;
interface Leds;
}
}
implementation
{
enum {
UART_QUEUE_LEN = 12,
RADIO_QUEUE_LEN = 12,
};
message_t uartQueueBufs[UART_QUEUE_LEN];
message_t * ONE_NOK uartQueue[UART_QUEUE_LEN];
uint8_t uartIn, uartOut;
bool uartBusy, uartFull;
message_t radioQueueBufs[RADIO_QUEUE_LEN];
message_t * ONE_NOK radioQueue[RADIO_QUEUE_LEN];
uint8_t radioIn, radioOut;
bool radioBusy, radioFull;
task void uartSendTask();
task void radioSendTask();
void dropBlink() {
call Leds.led2Toggle();
}
void failBlink() {
call Leds.led2Toggle();
}
event void Boot.booted() {
uint8_t i;
for (i = 0; i < UART_QUEUE_LEN; i++)
uartQueue[i] = &uartQueueBufs[i];
uartIn = uartOut = 0;
uartBusy = FALSE;
uartFull = TRUE;
for (i = 0; i < RADIO_QUEUE_LEN; i++)
radioQueue[i] = &radioQueueBufs[i];
radioIn = radioOut = 0;
radioBusy = FALSE;
radioFull = TRUE;
call RadioControl.start();
call SerialControl.start();
}
event void RadioControl.startDone(error_t error) {
if (error == SUCCESS) {
radioFull = FALSE;
}
}
event void SerialControl.startDone(error_t error) {
if (error == SUCCESS) {
uartFull = FALSE;
}
}
event void SerialControl.stopDone(error_t error) {}
event void RadioControl.stopDone(error_t error) {}
uint8_t count = 0;
message_t* ONE receive(message_t* ONE msg, void* payload, uint8_t len);
event message_t *RadioSnoop.receive[am_id_t id](message_t *msg,
void *payload,
uint8_t len) {
return receive(msg, payload, len);
}
event message_t *RadioReceive.receive[am_id_t id](message_t *msg,
void *payload,
uint8_t len) {
return receive(msg, payload, len);
}
message_t* receive(message_t *msg, void *payload, uint8_t len) {
message_t *ret = msg;
atomic
{
if (!uartFull)//串口接收缓冲区没有满
{
ret = uartQueue[uartIn];//?????
uartQueue[uartIn] = msg;//msg存入队列输入缓冲区
uartIn = (uartIn + 1) % UART_QUEUE_LEN;//uartIn 增1,为下才存储作准备,并取余防止溢出
if (uartIn == uartOut)
uartFull = TRUE;
if (!uartBusy)
{
post uartSendTask();//调用发送到串口的任务
uartBusy = TRUE;
}
}
else
dropBlink();
}
return ret;
}
uint8_t tmpLen;
task void uartSendTask() {
uint8_t len;
am_id_t id;
am_addr_t addr, src;
message_t* msg;
atomic
//看不懂
if (uartIn == uartOut && !uartFull)
{
uartBusy = FALSE;
return;
}
msg = uartQueue[uartOut];
tmpLen = len = call RadioPacket.payloadLength(msg);
id = call RadioAMPacket.type(msg);
addr = call RadioAMPacket.destination(msg);
src = call RadioAMPacket.source(msg);
call UartPacket.clear(msg);
call UartAMPacket.setSource(msg, src);
//串口发送数据
if (call UartSend.send[id](addr, uartQueue[uartOut], len) == SUCCESS)
call Leds.led1Toggle();
else
{
failBlink();
post uartSendTask();
}
}
event void UartSend.sendDone[am_id_t id](message_t* msg, error_t error) {
if (error != SUCCESS)
failBlink();
else
atomic
if (msg == uartQueue[uartOut])//确认串口发送的数据是否正确
{
if (++uartOut >= UART_QUEUE_LEN)//uartOut 队列下标+1,并作溢出复原处理
uartOut = 0;
//串口非满
if (uartFull)
uartFull = FALSE;
}
post uartSendTask();//调用串口发送任务
}
event message_t *UartReceive.receive[am_id_t id](message_t *msg,
void *payload,
uint8_t len) {
message_t *ret = msg;
bool reflectToken = FALSE;
atomic
if (!radioFull)
{
reflectToken = TRUE;
ret = radioQueue[radioIn];
radioQueue[radioIn] = msg;
if (++radioIn >= RADIO_QUEUE_LEN)
radioIn = 0;
if (radioIn == radioOut)
radioFull = TRUE;
if (!radioBusy)
{
post radioSendTask();
radioBusy = TRUE;
}
}
else
dropBlink();
if (reflectToken) {
//call UartTokenReceive.ReflectToken(Token);
}
return ret;
}
task void radioSendTask() {
uint8_t len;
am_id_t id;
am_addr_t addr,source;
message_t* msg;
atomic
if (radioIn == radioOut && !radioFull)
{
radioBusy = FALSE;
return;
}
msg = radioQueue[radioOut];
len = call UartPacket.payloadLength(msg);
addr = call UartAMPacket.destination(msg);
source = call UartAMPacket.source(msg);
id = call UartAMPacket.type(msg);
call RadioPacket.clear(msg);
call RadioAMPacket.setSource(msg, source);
if (call RadioSend.send[id](addr, msg, len) == SUCCESS)
call Leds.led0Toggle();
else
{
failBlink();
post radioSendTask();
}
}
event void RadioSend.sendDone[am_id_t id](message_t* msg, error_t error) {
if (error != SUCCESS)
failBlink();
else
atomic
if (msg == radioQueue[radioOut])
{
if (++radioOut >= RADIO_QUEUE_LEN)
radioOut = 0;
if (radioFull)
radioFull = FALSE;
}
post radioSendTask();
}
}