⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 slottedcollisionlayerp.nc

📁 tinyos-2.x.rar
💻 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 RADIO_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 ----- */

	void printStats();

	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 + (1<<ERROR_DECAY) - 1) >> ERROR_DECAY;
		if( isBetween(exponent, schedule1, start, length) )
			error1 += ERROR_COLLISION; 

		error2 -= (error1 + (1<<ERROR_DECAY) - 1) >> 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();
		}

		printStats();

		return signal RadioReceive.receive(msg);
	}

/* ------ 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;

		printStats();

		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 RADIO_DEBUG
	tasklet_norace uint8_t count;
	void printStats()
	{
		if( ++count > 50 && 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 + -