messagebufferlayerp.nc
来自「tinyos-2.x.rar」· NC 代码 · 共 335 行
NC
335 行
/*
* Copyright (c) 2007, Vanderbilt University
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without written agreement is
* hereby granted, provided that the above copyright notice, the following
* two paragraphs and the author appear in all copies of this software.
*
* IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
* UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Author: Miklos Maroti
*/
#include <Tasklet.h>
#include <RadioAssert.h>
module MessageBufferLayerP
{
provides
{
interface SplitControl;
interface Init as SoftwareInit;
interface BareSend as Send;
interface BareReceive as Receive;
interface RadioChannel;
}
uses
{
interface RadioState;
interface Tasklet;
interface RadioSend;
interface RadioReceive;
}
}
implementation
{
/*----------------- State -----------------*/
norace uint8_t state; // written only from tasks
enum
{
STATE_READY = 0,
STATE_TX_PENDING = 1,
STATE_TX_SEND = 2,
STATE_TX_DONE = 3,
STATE_TURN_ON = 4,
STATE_TURN_OFF = 5,
STATE_CHANNEL = 6,
};
command error_t SplitControl.start()
{
error_t error;
call Tasklet.suspend();
if( state != STATE_READY )
error = EBUSY;
else
error = call RadioState.turnOn();
if( error == SUCCESS )
state = STATE_TURN_ON;
call Tasklet.resume();
return error;
}
command error_t SplitControl.stop()
{
error_t error;
call Tasklet.suspend();
if( state != STATE_READY )
error = EBUSY;
else
error = call RadioState.turnOff();
if( error == SUCCESS )
state = STATE_TURN_OFF;
call Tasklet.resume();
return error;
}
command error_t RadioChannel.setChannel(uint8_t channel)
{
error_t error;
call Tasklet.suspend();
if( state != STATE_READY )
error = EBUSY;
else
error = call RadioState.setChannel(channel);
if( error == SUCCESS )
state = STATE_CHANNEL;
call Tasklet.resume();
return error;
}
command uint8_t RadioChannel.getChannel()
{
return call RadioState.getChannel();
}
task void stateDoneTask()
{
uint8_t s;
s = state;
// change the state before so we can be reentered from the event
state = STATE_READY;
if( s == STATE_TURN_ON )
signal SplitControl.startDone(SUCCESS);
else if( s == STATE_TURN_OFF )
signal SplitControl.stopDone(SUCCESS);
else if( s == STATE_CHANNEL )
signal RadioChannel.setChannelDone();
else // not our event, ignore it
state = s;
}
tasklet_async event void RadioState.done()
{
post stateDoneTask();
}
default event void SplitControl.startDone(error_t error)
{
}
default event void SplitControl.stopDone(error_t error)
{
}
default event void RadioChannel.setChannelDone()
{
}
/*----------------- Send -----------------*/
message_t* txMsg;
error_t txError;
uint8_t retries;
// Many EBUSY replies from RadioSend are normal if the channel is cognested
enum { MAX_RETRIES = 5 };
task void sendTask()
{
error_t error;
ASSERT( state == STATE_TX_PENDING || state == STATE_TX_SEND );
atomic error = txError;
if( (state == STATE_TX_SEND && error == SUCCESS) || ++retries > MAX_RETRIES )
state = STATE_TX_DONE;
else
{
call Tasklet.suspend();
error = call RadioSend.send(txMsg);
if( error == SUCCESS )
state = STATE_TX_SEND;
else if( retries == MAX_RETRIES )
state = STATE_TX_DONE;
else
state = STATE_TX_PENDING;
call Tasklet.resume();
}
if( state == STATE_TX_DONE )
{
state = STATE_READY;
signal Send.sendDone(txMsg, error);
}
}
tasklet_async event void RadioSend.sendDone(error_t error)
{
ASSERT( state == STATE_TX_SEND );
atomic txError = error;
post sendTask();
}
command error_t Send.send(message_t* msg)
{
if( state != STATE_READY )
return EBUSY;
txMsg = msg;
state = STATE_TX_PENDING;
retries = 0;
post sendTask();
return SUCCESS;
}
tasklet_async event void RadioSend.ready()
{
if( state == STATE_TX_PENDING )
post sendTask();
}
tasklet_async event void Tasklet.run()
{
}
command error_t Send.cancel(message_t* msg)
{
if( state == STATE_TX_PENDING )
{
state = STATE_READY;
// TODO: check if sendDone can be called before cancel returns
signal Send.sendDone(msg, ECANCEL);
return SUCCESS;
}
else
return FAIL;
}
/*----------------- Receive -----------------*/
enum
{
RECEIVE_QUEUE_SIZE = 3,
};
message_t receiveQueueData[RECEIVE_QUEUE_SIZE];
message_t* receiveQueue[RECEIVE_QUEUE_SIZE];
uint8_t receiveQueueHead;
uint8_t receiveQueueSize;
command error_t SoftwareInit.init()
{
uint8_t i;
for(i = 0; i < RECEIVE_QUEUE_SIZE; ++i)
receiveQueue[i] = receiveQueueData + i;
return SUCCESS;
}
tasklet_async event bool RadioReceive.header(message_t* msg)
{
bool notFull;
// this prevents undeliverable messages to be acknowledged
atomic notFull = receiveQueueSize < RECEIVE_QUEUE_SIZE;
return notFull;
}
task void deliverTask()
{
// get rid of as many messages as possible without interveining tasks
for(;;)
{
message_t* msg;
atomic
{
if( receiveQueueSize == 0 )
return;
msg = receiveQueue[receiveQueueHead];
}
msg = signal Receive.receive(msg);
atomic
{
receiveQueue[receiveQueueHead] = msg;
if( ++receiveQueueHead >= RECEIVE_QUEUE_SIZE )
receiveQueueHead = 0;
--receiveQueueSize;
}
}
}
tasklet_async event message_t* RadioReceive.receive(message_t* msg)
{
message_t *m;
atomic
{
if( receiveQueueSize >= RECEIVE_QUEUE_SIZE )
m = msg;
else
{
uint8_t index = receiveQueueHead + receiveQueueSize;
if( index >= RECEIVE_QUEUE_SIZE )
index -= RECEIVE_QUEUE_SIZE;
m = receiveQueue[index];
receiveQueue[index] = msg;
++receiveQueueSize;
post deliverTask();
}
}
return m;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?