📄 slottedcollisionlayerp.nc
字号:
/* * 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 SlottedCollisionLayerP{ provides { interface RadioSend; interface RadioReceive; interface Init; } uses { interface RadioSend as SubSend; interface RadioReceive as SubReceive; interface RadioAlarm; interface Random; interface SlottedCollisionConfig as Config;#ifdef RF230_DEBUG interface DiagMsg;#endif }}implementation{/* ----- random ----- */ uint16_t nextRandom; task void calcNextRandom() { uint16_t a = call Random.rand16(); atomic nextRandom = a; } uint16_t getNextRandom() { uint16_t a; atomic { a = nextRandom; nextRandom += 273; } post calcNextRandom(); return a; }/* ----- schedule selection ----- */ tasklet_async event bool SubReceive.header(message_t* msg) { return signal RadioReceive.header(msg); } // WARNING!!! Do not change these values, the error values can overflow enum { ERROR_DECAY = 3, ERROR_SWITCH = 30, // should be a multiple of (1 << decay) ERROR_COLLISION = 20, // must be less than (255 - switch) >> decay ERROR_BUSY = 1, // must be less than collision ERROR_INITIAL = 80, // must be less than giveup ERROR_GIVEUP = 120, // must be less than collision * (1 << decay) ERROR_REPRESS = 40, // must be more than switch ERROR_MAX = 255, }; /** * Returns TRUE if time is between start and start + window * modulo the schedule size of (1 << exponent) */ inline bool isBetween(uint8_t exponent, uint16_t time, uint16_t start, uint16_t length) { return (uint16_t)((time - start) & ((1 << exponent) - 1)) < length; } tasklet_norace uint16_t schedule1; tasklet_norace uint16_t schedule2; tasklet_norace uint8_t error1; tasklet_norace uint8_t error2; tasklet_async event message_t* SubReceive.receive(message_t* msg) { uint8_t exponent = call Config.getScheduleExponent(); uint16_t start = call Config.getCollisionWindowStart(msg); uint16_t length = call Config.getCollisionWindowLength(msg); error1 -= error1 >> ERROR_DECAY; if( isBetween(exponent, schedule1, start, length) ) error1 += ERROR_COLLISION; error2 -= error2 >> ERROR_DECAY; if( isBetween(exponent, schedule2, start, length) ) error2 += ERROR_COLLISION; if( error2 + ERROR_SWITCH <= error1 ) { error1 = error2; schedule1 = schedule2; error2 = ERROR_GIVEUP; } if( error2 >= ERROR_GIVEUP ) { error2 = ERROR_INITIAL; schedule2 = getNextRandom(); } return signal RadioReceive.receive(msg); } void printStats(); tasklet_async event void Config.timerTick() { if( error1 >= (1 << ERROR_DECAY) ) error1 -= error1 >> ERROR_DECAY; else if( error1 > 0 ) --error1; if( error2 >= (1 << ERROR_DECAY) ) error2 -= error2 >> ERROR_DECAY; else if( error2 > 0 ) --error2; printStats(); }/* ------ transmit ------ */ tasklet_norace uint8_t state; enum { STATE_READY = 0, STATE_PENDING = 1, STATE_SENDING = 2, }; enum { DELAY_DECAY = 2 }; tasklet_norace message_t *txMsg; tasklet_norace uint16_t txDelay; // the averaged delay between schedule and timestamp tasklet_norace uint16_t txTime; // the schedule time of transmission tasklet_async event void SubSend.ready() { if( state == STATE_READY && call RadioAlarm.isFree() ) signal RadioSend.ready(); } tasklet_async command error_t RadioSend.send(message_t* msg) { uint16_t backoff; uint16_t time; // TODO: we could supress transmission while error is large if( state != STATE_READY || ! call RadioAlarm.isFree() || error1 >= ERROR_REPRESS ) return EBUSY; txMsg = msg; state = STATE_PENDING; time = call RadioAlarm.getNow(); backoff = 1 + ((schedule1 - time - (txDelay >> DELAY_DECAY)) & ((1 << call Config.getScheduleExponent()) - 1)); backoff += getNextRandom() & (3 << call Config.getScheduleExponent()); call RadioAlarm.wait(backoff); txTime = time + backoff; return SUCCESS; } tasklet_async event void RadioAlarm.fired() { error_t error; ASSERT( state == STATE_PENDING ); error = call SubSend.send(txMsg); if( error == SUCCESS ) state = STATE_SENDING; else { if( error2 + ERROR_SWITCH <= error1 ) { error1 = error2; schedule1 = schedule2; error2 = ERROR_INITIAL; schedule2 = getNextRandom(); } else if( error1 < ERROR_MAX - ERROR_BUSY ) error1 = error1 + ERROR_BUSY; state = STATE_READY; signal RadioSend.sendDone(error); } } tasklet_async event void SubSend.sendDone(error_t error) { ASSERT( state == STATE_SENDING ); if( error == SUCCESS ) { txDelay += (call Config.getTransmitTime(txMsg) - txTime) - (txDelay >> DELAY_DECAY); ASSERT( (txDelay >> DELAY_DECAY) < (1 << call Config.getScheduleExponent()) ); } state = STATE_READY; signal RadioSend.sendDone(error); }/* ------ init ------ */ command error_t Init.init() { // do not use Random here because it might not be initialized schedule1 = (uint16_t)(TOS_NODE_ID * 1973); schedule2 = schedule1 + 0117; txDelay = call Config.getInitialDelay() << DELAY_DECAY; return SUCCESS; }#ifdef RF230_DEBUG tasklet_norace uint8_t count; void printStats() { if( ++count > 10 && call DiagMsg.record() ) { count = 0; call DiagMsg.str("slotted"); call DiagMsg.uint16(txDelay >> DELAY_DECAY); call DiagMsg.uint16(schedule1); call DiagMsg.uint8(error1); call DiagMsg.uint16(schedule2); call DiagMsg.uint8(error2); call DiagMsg.send(); } }#else void printStats() { }#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -