[Tinyos-2-commits] CVS: tinyos-2.x/tos/chips/rf230 ActiveMessageConfig.nc, NONE, 1.1 ActiveMessageLayerC.nc, NONE, 1.1 CsmaConfig.nc, NONE, 1.1 CsmaLayerC.nc, NONE, 1.1 CsmaLayerP.nc, NONE, 1.1 DefaultMac.h, NONE, 1.1 DefaultMacC.nc, NONE, 1.1 DefaultMacP.nc, NONE, 1.1 DummyConfig.nc, NONE, 1.1 DummyLayerC.nc, NONE, 1.1 IEEE154Packet.h, NONE, 1.1 IEEE154Packet.nc, NONE, 1.1 IEEE154PacketC.nc, NONE, 1.1 IEEE154PacketP.nc, NONE, 1.1 MessageBufferLayerC.nc, NONE, 1.1 MessageBufferLayerP.nc, NONE, 1.1 Neighborhood.h, NONE, 1.1 Neighborhood.nc, NONE, 1.1 NeighborhoodC.nc, NONE, 1.1 NeighborhoodFlag.nc, NONE, 1.1 NeighborhoodFlagC.nc, NONE, 1.1 NeighborhoodP.nc, NONE, 1.1 PacketTimeStamp.nc, NONE, 1.1 PacketTimeSynch.nc, NONE, 1.1 RF230.h, NONE, 1.1 RF230Config.nc, NONE, 1.1 RF230LayerC.nc, NONE, 1.1 RF230LayerP.nc, NONE, 1.1 RadioAlarm.nc, NONE, 1.1 RadioAlarmC.nc, NONE, 1.1 RadioAlarmP.nc, NONE, 1.1 RadioAssert.h, NONE, 1.1 RadioCCA.nc, NONE, 1.1 RadioReceive.nc, NONE, 1.1 RadioSend.nc, NONE, 1.1 RadioState.nc, NONE, 1.1 RandomCollisionConfig.nc, NONE, 1.1 RandomCollisionLayerC.nc, NONE, 1.1 RandomCollisionLayerP.nc, NONE, 1.1 SlottedCollisionConfig.nc, NONE, 1.1 SlottedCollisionLayerC.nc, NONE, 1.1 SlottedCollisionLayerP.nc, NONE, 1.1 SoftwareAckConfig.nc, NONE, 1.1 SoftwareAckLayerC.nc, NONE, 1.1 SoftwareAckLayerP.nc, NONE, 1.1 Tasklet.h, NONE, 1.1 Tasklet.nc, NONE, 1.1 TaskletC.nc, NONE, 1.1 TrafficMonitorConfig.nc, NONE, 1.1 TrafficMonitorLayerC.nc, NONE, 1.1 TrafficMonitorLayerP.nc, NONE, 1.1 UniqueConfig.nc, NONE, 1.1 UniqueLayerC.nc, NONE, 1.1 UniqueLayerP.nc, NONE, 1.1 notes.txt, NONE, 1.1

Janos Sallai sallai at users.sourceforge.net
Mon Nov 5 12:37:04 PST 2007


Update of /cvsroot/tinyos/tinyos-2.x/tos/chips/rf230
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv27101/rf230

Added Files:
	ActiveMessageConfig.nc ActiveMessageLayerC.nc CsmaConfig.nc 
	CsmaLayerC.nc CsmaLayerP.nc DefaultMac.h DefaultMacC.nc 
	DefaultMacP.nc DummyConfig.nc DummyLayerC.nc IEEE154Packet.h 
	IEEE154Packet.nc IEEE154PacketC.nc IEEE154PacketP.nc 
	MessageBufferLayerC.nc MessageBufferLayerP.nc Neighborhood.h 
	Neighborhood.nc NeighborhoodC.nc NeighborhoodFlag.nc 
	NeighborhoodFlagC.nc NeighborhoodP.nc PacketTimeStamp.nc 
	PacketTimeSynch.nc RF230.h RF230Config.nc RF230LayerC.nc 
	RF230LayerP.nc RadioAlarm.nc RadioAlarmC.nc RadioAlarmP.nc 
	RadioAssert.h RadioCCA.nc RadioReceive.nc RadioSend.nc 
	RadioState.nc RandomCollisionConfig.nc 
	RandomCollisionLayerC.nc RandomCollisionLayerP.nc 
	SlottedCollisionConfig.nc SlottedCollisionLayerC.nc 
	SlottedCollisionLayerP.nc SoftwareAckConfig.nc 
	SoftwareAckLayerC.nc SoftwareAckLayerP.nc Tasklet.h Tasklet.nc 
	TaskletC.nc TrafficMonitorConfig.nc TrafficMonitorLayerC.nc 
	TrafficMonitorLayerP.nc UniqueConfig.nc UniqueLayerC.nc 
	UniqueLayerP.nc notes.txt 
Log Message:
platform support for the IRIS mote (atm1218 MCU and rf230 radio)

--- NEW FILE: ActiveMessageConfig.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
 */

interface ActiveMessageConfig
{
	/**
	 * This command is called when the message first enters the radio stack
	 * via the Send.send command. This should clear the packet if the user
	 * forgot to do so (or return EINVAL to be strict).
	 */
	command error_t checkPacket(message_t* msg);
}

--- NEW FILE: ActiveMessageLayerC.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
 */

module ActiveMessageLayerC
{
	provides
	{
		interface AMSend[am_id_t id];
		interface Receive[am_id_t id];
		interface Receive as Snoop[am_id_t id];	
	}
	uses
	{
		interface Send as SubSend;
		interface Receive as SubReceive;
		interface AMPacket;
		interface ActiveMessageConfig as Config;
	}
}

implementation
{
/*----------------- Send -----------------*/

	command error_t AMSend.send[am_id_t id](am_addr_t addr, message_t* msg, uint8_t len)
	{
		error_t error;

		error = call Config.checkPacket(msg);
		if( error != SUCCESS )
			return error;

		call AMPacket.setSource(msg, call AMPacket.address());
		call AMPacket.setGroup(msg, call AMPacket.localGroup());
		call AMPacket.setType(msg, id);
		call AMPacket.setDestination(msg, addr);

		return call SubSend.send(msg, len);
	}

	inline event void SubSend.sendDone(message_t* msg, error_t error)
	{
		signal AMSend.sendDone[call AMPacket.type(msg)](msg, error);
	}

	inline command error_t AMSend.cancel[am_id_t id](message_t* msg)
	{
		return call SubSend.cancel(msg);
	}

	default event void AMSend.sendDone[am_id_t id](message_t* msg, error_t error)
	{
	}

	inline command uint8_t AMSend.maxPayloadLength[am_id_t id]()
	{
		return call SubSend.maxPayloadLength();
	}

	inline command void* AMSend.getPayload[am_id_t id](message_t* msg, uint8_t len)
	{
		return call SubSend.getPayload(msg, len);
	}

/*----------------- Receive -----------------*/

	event message_t* SubReceive.receive(message_t* msg, void* payload, uint8_t len)
	{
		am_id_t type = call AMPacket.type(msg);

		msg = call AMPacket.isForMe(msg) 
			? signal Receive.receive[type](msg, payload, len)
			: signal Snoop.receive[type](msg, payload, len);

		return msg;
	}

	default event message_t* Receive.receive[am_id_t id](message_t* msg, void* payload, uint8_t len)
	{
		return msg;
	}

	default event message_t* Snoop.receive[am_id_t id](message_t* msg, void* payload, uint8_t len)
	{
		return msg;
	}
}

--- NEW FILE: CsmaConfig.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
 */

interface CsmaConfig
{
	/**
	 * This command is called when the message is transmitted to
	 * check if it needs software clear channel assesment.
	 */
	async command bool requiresSoftwareCCA(message_t* msg);
}

--- NEW FILE: CsmaLayerC.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
 */

configuration CsmaLayerC
{
	provides
	{
		interface RadioSend;
	}
	uses
	{
		interface RadioSend as SubSend;
		interface RadioCCA as SubCCA;

		interface CsmaConfig as Config;
	}
}

implementation
{
	components CsmaLayerP;

	RadioSend = CsmaLayerP;
	SubSend = CsmaLayerP;
	SubCCA = CsmaLayerP;
	Config = CsmaLayerP;
}

--- NEW FILE: CsmaLayerP.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 CsmaLayerP
{
	provides
	{
		interface RadioSend;
	}

	uses
	{
		interface CsmaConfig as Config;

		interface RadioSend as SubSend;
		interface RadioCCA as SubCCA;
	}
}

implementation
{
	tasklet_norace message_t *txMsg;

	tasklet_norace uint8_t state;
	enum
	{
		STATE_READY = 0,
		STATE_CCA_WAIT = 1,
		STATE_SEND = 2,
	};

	tasklet_async event void SubSend.ready()
	{
		if( state == STATE_READY )
			signal RadioSend.ready();
	}

	tasklet_async command error_t RadioSend.send(message_t* msg)
	{
		error_t error;

		if( state == STATE_READY )
		{
			if( call Config.requiresSoftwareCCA(msg) )
			{
				txMsg = msg;

				if( (error = call SubCCA.request()) == SUCCESS )
					state = STATE_CCA_WAIT;
			}
			else if( (error = call SubSend.send(msg)) == SUCCESS )
				state = STATE_SEND;
		}
		else
			error = EBUSY;

		return error;
	}

	tasklet_async event void SubCCA.done(error_t error)
	{
		ASSERT( state == STATE_CCA_WAIT );

		if( error == SUCCESS && (error = call SubSend.send(txMsg)) == SUCCESS )
			state = STATE_SEND;
		else
		{
			state = STATE_READY;
			signal RadioSend.sendDone(EBUSY);
		}
	}

	tasklet_async event void SubSend.sendDone(error_t error)
	{
		ASSERT( state == STATE_SEND );

		state = STATE_READY;
		signal RadioSend.sendDone(error);
	}
}

--- NEW FILE: DefaultMac.h ---
/*
 * 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
 */

#ifndef __DEFAULTMAC_H__
#define __DEFAULTMAC_H__

#include <IEEE154Packet.h>

typedef ieee154_header_t defaultmac_header_t;

typedef nx_struct defaultmac_metadata_t
{
	nx_uint8_t flags;
	nx_uint8_t lqi;
	nx_uint16_t timestamp;
} defaultmac_metadata_t;

enum defaultmac_metadata_flags
{
	DEFAULTMAC_WAS_ACKED = 0x01,
	DEFAULTMAC_SCHEDULED_TX = 0x02,
};

/* This is the default value of the TX_PWR field of the PHY_TX_PWR register. */
#ifndef RF230_DEF_RFPOWER
#define RF230_DEF_RFPOWER	0
#endif

/* This is the default value of the CHANNEL field of the PHY_CC_CCA register. */
#ifndef RF230_DEF_CHANNEL
#define RF230_DEF_CHANNEL	11
#endif

#endif//__DEFAULTMAC_H__

--- NEW FILE: DefaultMacC.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
 */

configuration DefaultMacC
{
	provides 
	{
		interface SplitControl;

		interface AMSend[am_id_t id];
		interface Receive[am_id_t id];
		interface Receive as Snoop[am_id_t id];

		interface Packet;
		interface AMPacket;
		interface PacketAcknowledgements;
	}
}

implementation
{
	components DefaultMacP, IEEE154PacketC, RadioAlarmC;

#ifdef RF230_DEBUG
	components AssertC;
#endif

	DefaultMacP.IEEE154Packet -> IEEE154PacketC;
	DefaultMacP.RadioAlarm -> RadioAlarmC.RadioAlarm[unique("RadioAlarm")];

	components ActiveMessageLayerC;
	components MessageBufferLayerC;
	components UniqueLayerC;
	components TrafficMonitorLayerC;
	components RandomCollisionLayerC as CollisionAvoidanceLayerC;
//	components SlottedCollisionLayerC as CollisionAvoidanceLayerC;
	components SoftwareAckLayerC;
	components new DummyLayerC() as CsmaLayerC;
	components RF230LayerC;

	SplitControl = MessageBufferLayerC;
	AMSend = ActiveMessageLayerC;
	Receive = ActiveMessageLayerC.Receive;
	Snoop = ActiveMessageLayerC.Snoop;
	Packet = DefaultMacP;
	AMPacket = IEEE154PacketC;
	PacketAcknowledgements = DefaultMacP;

	ActiveMessageLayerC.Config -> DefaultMacP;
	ActiveMessageLayerC.AMPacket -> IEEE154PacketC;
	ActiveMessageLayerC.SubSend -> UniqueLayerC;
	ActiveMessageLayerC.SubReceive -> MessageBufferLayerC;

	UniqueLayerC.Config -> DefaultMacP;
	UniqueLayerC.SubSend -> MessageBufferLayerC;

	MessageBufferLayerC.Packet -> DefaultMacP;
	MessageBufferLayerC.RadioSend -> TrafficMonitorLayerC;
	MessageBufferLayerC.RadioReceive -> UniqueLayerC;
	MessageBufferLayerC.RadioState -> TrafficMonitorLayerC;

	UniqueLayerC.SubReceive -> TrafficMonitorLayerC;

	TrafficMonitorLayerC.Config -> DefaultMacP;
	TrafficMonitorLayerC.SubSend -> CollisionAvoidanceLayerC;
	TrafficMonitorLayerC.SubReceive -> CollisionAvoidanceLayerC;
	TrafficMonitorLayerC.SubState -> RF230LayerC;

	CollisionAvoidanceLayerC.Config -> DefaultMacP;
	CollisionAvoidanceLayerC.SubSend -> SoftwareAckLayerC;
	CollisionAvoidanceLayerC.SubReceive -> SoftwareAckLayerC;

	SoftwareAckLayerC.Config -> DefaultMacP;
	SoftwareAckLayerC.SubSend -> CsmaLayerC;
	SoftwareAckLayerC.SubReceive -> RF230LayerC;

	CsmaLayerC.Config -> DefaultMacP;
	CsmaLayerC.SubSend -> RF230LayerC;
	CsmaLayerC.SubCCA -> RF230LayerC;

	RF230LayerC.RF230Config -> DefaultMacP;
}

--- NEW FILE: DefaultMacP.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 <DefaultMac.h>
#include <HplRF230.h>
#include <Tasklet.h>

module DefaultMacP
{
	provides
	{
		interface RF230Config;
		interface SoftwareAckConfig;
		interface UniqueConfig;
		interface CsmaConfig;
		interface TrafficMonitorConfig;
		interface RandomCollisionConfig;
		interface SlottedCollisionConfig;
		interface ActiveMessageConfig;
		interface DummyConfig;

		interface PacketAcknowledgements;
		interface Packet;
	}

	uses
	{
		interface IEEE154Packet;
		interface RadioAlarm;
	}
}

implementation
{
/*----------------- Packet -----------------*/

	command void Packet.clear(message_t* msg) 
	{
		call IEEE154Packet.createDataFrame(msg);

#ifdef IEEE154_6LOWPAN
		call IEEE154Packet.set6LowPan(msg, TINYOS_6LOWPAN_NETWORK_ID);
#endif
	}
  
	command uint8_t Packet.payloadLength(message_t* msg) 
	{
		return call IEEE154Packet.getLength(msg) - sizeof(ieee154_header_t) + 1 - sizeof(ieee154_footer_t);
	}
  
	command void Packet.setPayloadLength(message_t* msg, uint8_t len) 
	{
		call IEEE154Packet.setLength(msg, len + sizeof(ieee154_header_t) - 1 + sizeof(ieee154_footer_t));
	}
  
	command uint8_t Packet.maxPayloadLength()
	{
		return TOSH_DATA_LENGTH;
	}
  
	command void* Packet.getPayload(message_t* msg, uint8_t len)
	{
		if( len > TOSH_DATA_LENGTH )
			return NULL;

		return msg->data;
	}

	command error_t ActiveMessageConfig.checkPacket(message_t* msg)
	{
		// the user forgot to call clear, we should return EINVAL
		if( ! call IEEE154Packet.isDataFrame(msg) )
			call Packet.clear(msg);

		return SUCCESS;
	}

/*----------------- RF230Config -----------------*/

	async command uint8_t RF230Config.getLength(message_t* msg)
	{
		return call IEEE154Packet.getLength(msg);
	}

	async command void RF230Config.setLength(message_t* msg, uint8_t len)
	{
		call IEEE154Packet.setLength(msg, len);
	}

	async command uint8_t* RF230Config.getPayload(message_t* msg)
	{
		return ((uint8_t*)(call IEEE154Packet.getHeader(msg))) + 1;
	}

	inline defaultmac_metadata_t* getMeta(message_t* msg)
	{
		return (defaultmac_metadata_t*)(msg->metadata);
	}

	async command void RF230Config.setTimestamp(message_t* msg, uint16_t time)
	{
		getMeta(msg)->timestamp = time;
	}

	async command void RF230Config.setLinkQuality(message_t* msg, uint8_t lqi)
	{
		getMeta(msg)->lqi = lqi;
	}

	async command uint8_t RF230Config.getHeaderLength()
	{
		// we need the fcf, dsn, destpan and dest
		return 7;
	}

	async command uint8_t RF230Config.getMaxLength()
	{
		// note, that the ieee154_footer_t is not stored, but we should include it here
		return sizeof(defaultmac_header_t) - 1 + TOSH_DATA_LENGTH + sizeof(ieee154_footer_t);
	}

	async command uint8_t RF230Config.getTransmitPower(message_t* msg)
	{
		return RF230_DEF_RFPOWER;
	}

	async command uint8_t RF230Config.getDefaultChannel()
	{
		return RF230_DEF_CHANNEL;
	}

	async command bool RF230Config.requiresRssiCca(message_t* msg)
	{
		return call IEEE154Packet.isDataFrame(msg);
	}

/*----------------- SoftwareAckConfig -----------------*/

	async command bool SoftwareAckConfig.requiresAckWait(message_t* msg)
	{
		return call IEEE154Packet.requiresAckWait(msg);
	}

	async command bool SoftwareAckConfig.isAckPacket(message_t* msg)
	{
		return call IEEE154Packet.isAckFrame(msg);
	}

	async command bool SoftwareAckConfig.verifyAckPacket(message_t* data, message_t* ack)
	{
		return call IEEE154Packet.verifyAckReply(data, ack);
	}

	async command bool SoftwareAckConfig.requiresAckReply(message_t* msg)
	{
		return call IEEE154Packet.requiresAckReply(msg);
	}

	async command void SoftwareAckConfig.createAckPacket(message_t* data, message_t* ack)
	{
		call IEEE154Packet.createAckReply(data, ack);
	}

	async command void SoftwareAckConfig.setAckReceived(message_t* msg, bool acked)
	{
		if( acked )
			getMeta(msg)->flags |= DEFAULTMAC_WAS_ACKED;
		else
			getMeta(msg)->flags &= ~DEFAULTMAC_WAS_ACKED;
	}

	async command uint16_t SoftwareAckConfig.getAckTimeout()
	{
		return (uint16_t)(800 * RF230_ALARM_MICROSEC);
	}

	tasklet_async command void SoftwareAckConfig.reportChannelError()
	{
		signal TrafficMonitorConfig.channelError();
	}

/*----------------- PacketAcknowledgements -----------------*/

	async command error_t PacketAcknowledgements.requestAck(message_t* msg)
	{
		call IEEE154Packet.setAckRequired(msg, TRUE);

		return SUCCESS;
	}

	async command error_t PacketAcknowledgements.noAck(message_t* msg)
	{
		call IEEE154Packet.setAckRequired(msg, FALSE);

		return SUCCESS;
	}

	async command bool PacketAcknowledgements.wasAcked(message_t* msg)
	{
		return getMeta(msg)->flags & DEFAULTMAC_WAS_ACKED;
	}

/*----------------- UniqueConfig -----------------*/

	async command uint8_t UniqueConfig.getSequenceNumber(message_t* msg)
	{
		return call IEEE154Packet.getDSN(msg);
	}

	async command void UniqueConfig.setSequenceNumber(message_t* msg, uint8_t dsn)
	{
		call IEEE154Packet.setDSN(msg, dsn);
	}

	async command am_addr_t UniqueConfig.getSender(message_t* msg)
	{
		return call IEEE154Packet.getSrcAddr(msg);
	}

	tasklet_async command void UniqueConfig.reportChannelError()
	{
		signal TrafficMonitorConfig.channelError();
	}

/*----------------- CsmaConfig -----------------*/

	async command bool CsmaConfig.requiresSoftwareCCA(message_t* msg)
	{
		return call IEEE154Packet.isDataFrame(msg);
	}

/*----------------- TrafficMonitorConfig -----------------*/

	enum
	{
		TRAFFIC_UPDATE_PERIOD = 100,	// in milliseconds
		TRAFFIC_MAX_BYTES = (uint16_t)(TRAFFIC_UPDATE_PERIOD * 1000.0 / 32),	// 3125
	};

	async command uint16_t TrafficMonitorConfig.getUpdatePeriod()
	{
		return TRAFFIC_UPDATE_PERIOD;
	}

	async command uint16_t TrafficMonitorConfig.getChannelTime(message_t* msg)
	{
		/* We count in bytes, one byte is 32 microsecond. We are conservative here.
		 *
		 * pure airtime: preable (4 bytes), SFD (1 byte), length (1 byte), payload + CRC (len bytes)
		 * frame separation: 5-10 bytes
		 * ack required: 8-16 byte separation, 11 bytes airtime, 5-10 bytes separation
		 */

		uint8_t len = call IEEE154Packet.getLength(msg);
		return call IEEE154Packet.getAckRequired(msg) ? len + 6 + 16 + 11 + 10 : len + 6 + 10;
	}

	async command am_addr_t TrafficMonitorConfig.getSender(message_t* msg)
	{
		return call IEEE154Packet.getSrcAddr(msg);
	}

	tasklet_async command void TrafficMonitorConfig.timerTick()
	{
		signal SlottedCollisionConfig.timerTick();
	}

/*----------------- RandomCollisionConfig -----------------*/

	/*
	 * We try to use the same values as in CC2420
	 *
	 * CC2420_MIN_BACKOFF = 10 jiffies = 320 microsec
	 * CC2420_BACKOFF_PERIOD = 10 jiffies
	 * initial backoff = 0x1F * CC2420_BACKOFF_PERIOD = 310 jiffies = 9920 microsec
	 * congestion backoff = 0x7 * CC2420_BACKOFF_PERIOD = 70 jiffies = 2240 microsec
	 */

	async command uint16_t RandomCollisionConfig.getMinimumBackoff()
	{
		return (uint16_t)(320 * RF230_ALARM_MICROSEC);
	}

	async command uint16_t RandomCollisionConfig.getInitialBackoff(message_t* msg)
	{
		return (uint16_t)(9920 * RF230_ALARM_MICROSEC);
	}

	async command uint16_t RandomCollisionConfig.getCongestionBackoff(message_t* msg)
	{
		return (uint16_t)(2240 * RF230_ALARM_MICROSEC);
	}

	async command uint16_t RandomCollisionConfig.getTransmitBarrier(message_t* msg)
	{
		uint16_t time;

		// TODO: maybe we should use the embedded timestamp of the message
		time = call RadioAlarm.getNow();

		// estimated response time (download the message, etc) is 5-8 bytes
		if( call IEEE154Packet.requiresAckReply(msg) )
			time += (uint16_t)(32 * (-5 + 16 + 11 + 5) * RF230_ALARM_MICROSEC);
		else
			time += (uint16_t)(32 * (-5 + 5) * RF230_ALARM_MICROSEC);

		return time;
	}

	tasklet_async event void RadioAlarm.fired()	{ }

/*----------------- SlottedCollisionConfig -----------------*/

	async command uint16_t SlottedCollisionConfig.getInitialDelay()
	{
		return 300;
	}

	async command uint8_t SlottedCollisionConfig.getScheduleExponent()
	{
		return 11;
	}

	async command uint16_t SlottedCollisionConfig.getTransmitTime(message_t* msg)
	{
		// TODO: check if the timestamp is correct
		return getMeta(msg)->timestamp;
	}

	async command uint16_t SlottedCollisionConfig.getCollisionWindowStart(message_t* msg)
	{
		// the preamble (4 bytes), SFD (1 byte), plus two extra for safety
		return getMeta(msg)->timestamp - (uint16_t)(7 * 32 * RF230_ALARM_MICROSEC);
	}

	async command uint16_t SlottedCollisionConfig.getCollisionWindowLength(message_t* msg)
	{
		return (uint16_t)(2 * 7 * 32 * RF230_ALARM_MICROSEC);
	}

	default tasklet_async event void SlottedCollisionConfig.timerTick() { }

/*----------------- Dummy -----------------*/

	async command void DummyConfig.nothing()
	{
	}

}

--- NEW FILE: DummyConfig.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
 */

interface DummyConfig
{
	/**
	 * We need to put something here, but this is not going to get called
	 */
	async command void nothing();
}

--- NEW FILE: DummyLayerC.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
 */

generic configuration DummyLayerC()
{
	provides
	{
		interface RadioState;
		interface RadioSend;
		interface RadioReceive;
		interface RadioCCA;

		interface DummyConfig as UnconnectedConfig;
	}

	uses 
	{
		interface RadioState as SubState;
		interface RadioSend as SubSend;
		interface RadioReceive as SubReceive;
		interface RadioCCA as SubCCA;

		interface DummyConfig as Config;
	}
}

implementation
{
	RadioState = SubState;
	RadioSend = SubSend;
	RadioReceive = SubReceive;
	RadioCCA = SubCCA;
	Config = UnconnectedConfig;
}

--- NEW FILE: IEEE154Packet.h ---
/*
 * 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
 */

#ifndef __IEEE154PACKET_H__
#define __IEEE154PACKET_H__

typedef nx_struct ieee154_header_t
{
	nxle_uint8_t length;
	nxle_uint16_t fcf;
	nxle_uint8_t dsn;
	nxle_uint16_t destpan;
	nxle_uint16_t dest;
	nxle_uint16_t src;

// I-Frame 6LowPAN interoperability byte
#ifdef IEEE154_6LOWPAN	
	nxle_uint8_t network;
#endif

	nxle_uint8_t type;
} ieee154_header_t;

// the actual radio driver might not use this
typedef nx_struct ieee154_footer_t
{ 
	nxle_uint16_t crc;
} ieee154_footer_t;

enum ieee154_fcf_enums {
	IEEE154_FCF_FRAME_TYPE = 0,
	IEEE154_FCF_SECURITY_ENABLED = 3,
	IEEE154_FCF_FRAME_PENDING = 4,
	IEEE154_FCF_ACK_REQ = 5,
	IEEE154_FCF_INTRAPAN = 6,
	IEEE154_FCF_DEST_ADDR_MODE = 10,
	IEEE154_FCF_SRC_ADDR_MODE = 14,
};

enum ieee154_fcf_type_enums {
	IEEE154_TYPE_BEACON = 0,
	IEEE154_TYPE_DATA = 1,
	IEEE154_TYPE_ACK = 2,
	IEEE154_TYPE_MAC_CMD = 3,
	IEEE154_TYPE_MASK = 7,
};

enum iee154_fcf_addr_mode_enums {
	IEEE154_ADDR_NONE = 0,
	IEEE154_ADDR_SHORT = 2,
	IEEE154_ADDR_EXT = 3,
	IEEE154_ADDR_MASK = 3,
};

#endif//__IEEE154PACKET_H__

--- NEW FILE: IEEE154Packet.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 <IEEE154Packet.h>
#include <message.h>

/**
 * This interface encapsulates IEEE 802.15.4 intrapan data frames with 
 * 16-bit destination pan, source and destination addresses. It also 
 * supports 6LowPan interoperability mode, and acknowledgement frames.
 * Note, that this interface does not support the CRC-16 value, which
 * should be verified before the data can be trusted.
 */
interface IEEE154Packet
{
	/**
	 * Returns the IEEE 802.15.4 header including the length field.
	 */
	async command ieee154_header_t* getHeader(message_t* msg);

	/**
	 * Returns the raw value (unadjusted) of the length field
	 */
	async command uint8_t getLength(message_t* msg);

	/**
	 * Sets the length field
	 */
	async command void setLength(message_t* msg, uint8_t length);

	/**
	 * Returns the frame control field. This method should not be used, 
	 * isDataFrame and isAckFrame should be used instead.
	 */
	async command uint16_t getFCF(message_t* msg);

	/**
	 * Sets the frame control field. This method should not be used, 
	 * createDataFrame and createAckFrame should be used instead.
	 */
	async command void setFCF(message_t* msg, uint16_t fcf);

	/**
	 * Returns TRUE if the message is a data frame supported by 
	 * this interface (based on the value of the FCF).
	 */
	async command bool isDataFrame(message_t* msg);

	/**
	 * Sets the FCF to create a data frame supported by this interface.
	 * You may call setAckRequired and setFramePending commands after this.
	 */
	async command void createDataFrame(message_t* msg);

	/**
	 * Returns TRUE if the message is an acknowledgement frame supported
	 * by this interface (based on the value of the FCF).
	 */
	async command bool isAckFrame(message_t* msg);

	/**
	 * Sets the FCF to create an acknowledgement frame supported by
	 * this interface. You may call setFramePending after this.
	 */
	async command void createAckFrame(message_t* msg);

	/**
	 * Creates an acknowledgement packet for the given data packet.
	 * This also sets the DSN value. The data message must be a 
	 * data frame, the ack message will be overwritten.
	 */
	async command void createAckReply(message_t* data, message_t* ack);

	/**
	 * Returns TRUE if the acknowledgement packet corresponds to the
	 * data packet. The data message must be a data packet.
	 */
	async command bool verifyAckReply(message_t* data, message_t* ack);

	/**
	 * Returns TRUE if the ACK required field is set in the FCF.
	 */
	async command bool getAckRequired(message_t* msg);

	/**
	 * Sets the ACK required field in the FCF, should never be set
	 * for acknowledgement frames.
	 */
	async command void setAckRequired(message_t* msg, bool ack);

	/**
	 * Returns TRUE if the frame pending field is set in the FCF.
	 */
	async command bool getFramePending(message_t* msg);

	/**
	 * Sets the frame pending field in the FCF.
	 */
	async command void setFramePending(message_t* msg, bool pending);

	/**
	 * Returns the data sequence number
	 */
	async command uint8_t getDSN(message_t* msg);

	/**
	 * Sets the data sequence number
	 */
	async command void setDSN(message_t* msg, uint8_t dsn);

	/**
	 * returns the destination PAN id, values <= 255 are tinyos groups,
	 * valid only for data frames
	 */
	async command uint16_t getDestPan(message_t* msg);

	/**
	 * Sets the destination PAN id, valid only for data frames
	 */
	async command void setDestPan(message_t* msg, uint16_t pan);

	/**
	 * Returns the destination address, valid only for data frames
	 */
	async command uint16_t getDestAddr(message_t* msg);

	/**
	 * Sets the destination address, valid only for data frames
	 */
	async command void setDestAddr(message_t* msg, uint16_t addr);

	/**
	 * Returns the source address, valid only for data frames
	 */
	async command uint16_t getSrcAddr(message_t* msg);

	/**
	 * Sets the source address, valid only for data frames
	 */
	async command void setSrcAddr(message_t* msg, uint16_t addr);

#ifdef IEEE154_6LOWPAN

	/**
	 * Returns the value of the 6LowPan network field.
	 */
	async command uint8_t get6LowPan(message_t* msg);

	/**
	 * Sets the value of the 6LowPan network field.
	 */
	async command void set6LowPan(message_t* msg, uint8_t network);

#endif

	/**
	 * Returns the active message type of the message
	 */
	async command am_id_t getType(message_t* msg);

	/**
	 * Sets the active message type
	 */
	async command void setType(message_t* msg, am_id_t type);

	/**
	 * Returns TRUE if the packet is a data packet, the ACK_REQ field
	 * is set and the destination address is not the broadcast address.
	 */
	async command bool requiresAckWait(message_t* msg);

	/**
	 * Returns TRUE if the packet is a data packet, the ACK_REQ field
	 * is set and the destionation address is this node.
	 */
	async command bool requiresAckReply(message_t* msg);
}

--- NEW FILE: IEEE154PacketC.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
 */

configuration IEEE154PacketC
{
	provides
	{
		interface IEEE154Packet;
		interface AMPacket;
	}
}

implementation
{
	components IEEE154PacketP, ActiveMessageAddressC;
	IEEE154PacketP.ActiveMessageAddress -> ActiveMessageAddressC;

	IEEE154Packet = IEEE154PacketP;
	AMPacket = IEEE154PacketP;
}

--- NEW FILE: IEEE154PacketP.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 <IEEE154Packet.h>

module IEEE154PacketP
{
	provides 
	{
		interface IEEE154Packet;
		interface AMPacket;
	}

	uses interface ActiveMessageAddress;
}

implementation
{
/*----------------- IEEE154Packet -----------------*/

	enum
	{
		IEEE154_DATA_FRAME_MASK = (IEEE154_TYPE_MASK << IEEE154_FCF_FRAME_TYPE) 
			| (1 << IEEE154_FCF_INTRAPAN) 
			| (IEEE154_ADDR_MASK << IEEE154_FCF_DEST_ADDR_MODE) 
			| (IEEE154_ADDR_MASK << IEEE154_FCF_SRC_ADDR_MODE),

		IEEE154_DATA_FRAME_VALUE = (IEEE154_TYPE_DATA << IEEE154_FCF_FRAME_TYPE) 
			| (1 << IEEE154_FCF_INTRAPAN) 
			| (IEEE154_ADDR_SHORT << IEEE154_FCF_DEST_ADDR_MODE) 
			| (IEEE154_ADDR_SHORT << IEEE154_FCF_SRC_ADDR_MODE),

		IEEE154_ACK_FRAME_LENGTH = 5,	// includes the FCF, DSN and FCS
		IEEE154_ACK_FRAME_MASK = (IEEE154_TYPE_MASK << IEEE154_FCF_FRAME_TYPE), 
		IEEE154_ACK_FRAME_VALUE = (IEEE154_TYPE_ACK << IEEE154_FCF_FRAME_TYPE),
	};

	inline ieee154_header_t* getHeader(message_t* msg)
	{
		return (ieee154_header_t*)(msg->data - sizeof(ieee154_header_t));
	}

	inline async command ieee154_header_t* IEEE154Packet.getHeader(message_t* msg)
	{
		return getHeader(msg);
	}

	inline async command uint8_t IEEE154Packet.getLength(message_t* msg)
	{
		return getHeader(msg)->length;
	}

	inline async command void IEEE154Packet.setLength(message_t* msg, uint8_t length)
	{
		getHeader(msg)->length = length;
	}

	inline async command uint16_t IEEE154Packet.getFCF(message_t* msg)
	{
		return getHeader(msg)->fcf;
	}

	inline async command void IEEE154Packet.setFCF(message_t* msg, uint16_t fcf)
	{
		getHeader(msg)->fcf = fcf;
	}

	inline async command bool IEEE154Packet.isDataFrame(message_t* msg)
	{
		return (getHeader(msg)->fcf & IEEE154_DATA_FRAME_MASK) == IEEE154_DATA_FRAME_VALUE;
	}

	inline async command void IEEE154Packet.createDataFrame(message_t* msg)
	{
		getHeader(msg)->fcf = IEEE154_DATA_FRAME_VALUE;
	}

	inline async command bool IEEE154Packet.isAckFrame(message_t* msg)
	{
		return (getHeader(msg)->fcf & IEEE154_ACK_FRAME_MASK) == IEEE154_ACK_FRAME_VALUE;
	}

	inline async command void IEEE154Packet.createAckFrame(message_t* msg)
	{
		ieee154_header_t* header = getHeader(msg);

		header->length = IEEE154_ACK_FRAME_LENGTH;
		header->fcf = IEEE154_ACK_FRAME_VALUE;
	}

	inline async command void IEEE154Packet.createAckReply(message_t* data, message_t* ack)
	{
		ieee154_header_t* header = getHeader(ack);

		header->length = IEEE154_ACK_FRAME_LENGTH;
		header->fcf = IEEE154_ACK_FRAME_VALUE;
		header->dsn = getHeader(data)->dsn;
	}

	inline async command bool IEEE154Packet.verifyAckReply(message_t* data, message_t* ack)
	{
		ieee154_header_t* header = getHeader(ack);

		return header->dsn == getHeader(data)->dsn
			&& (header->fcf & IEEE154_ACK_FRAME_MASK) == IEEE154_ACK_FRAME_VALUE;
	}

	inline async command bool IEEE154Packet.getAckRequired(message_t* msg)
	{
		return getHeader(msg)->fcf & (1 << IEEE154_FCF_ACK_REQ);
	}

	inline async command void IEEE154Packet.setAckRequired(message_t* msg, bool ack)
	{
		if( ack )
			getHeader(msg)->fcf |= (1 << IEEE154_FCF_ACK_REQ);
		else
			getHeader(msg)->fcf &= ~(uint16_t)(1 << IEEE154_FCF_ACK_REQ);
	}

	inline async command bool IEEE154Packet.getFramePending(message_t* msg)
	{
		return getHeader(msg)->fcf & (1 << IEEE154_FCF_FRAME_PENDING);
	}

	inline async command void IEEE154Packet.setFramePending(message_t* msg, bool pending)
	{
		if( pending )
			getHeader(msg)->fcf |= (1 << IEEE154_FCF_FRAME_PENDING);
		else
			getHeader(msg)->fcf &= ~(uint16_t)(1 << IEEE154_FCF_FRAME_PENDING);
	}

	inline async command uint8_t IEEE154Packet.getDSN(message_t* msg)
	{
		return getHeader(msg)->dsn;
	}

	inline async command void IEEE154Packet.setDSN(message_t* msg, uint8_t dsn)
	{
		getHeader(msg)->dsn = dsn;
	}

	inline async command uint16_t IEEE154Packet.getDestPan(message_t* msg)
	{
		return getHeader(msg)->destpan;
	}

	inline async command void IEEE154Packet.setDestPan(message_t* msg, uint16_t pan)
	{
		getHeader(msg)->destpan = pan;
	}

	inline async command uint16_t IEEE154Packet.getDestAddr(message_t* msg)
	{
		return getHeader(msg)->dest;
	}

	inline async command void IEEE154Packet.setDestAddr(message_t* msg, uint16_t addr)
	{
		getHeader(msg)->dest = addr;
	}

	inline async command uint16_t IEEE154Packet.getSrcAddr(message_t* msg)
	{
		return getHeader(msg)->src;
	}

	inline async command void IEEE154Packet.setSrcAddr(message_t* msg, uint16_t addr)
	{
		getHeader(msg)->src = addr;
	}

#ifdef IEEE154_6LOWPAN

	inline async command uint8_t IEEE154Packet.get6LowPan(message_t* msg)
	{
		return getHeader(msg)->network;
	}

	inline async command void IEEE154Packet.set6LowPan(message_t* msg, uint8_t network)
	{
		getHeader(msg)->network = network;
	}

#endif

	inline async command am_id_t IEEE154Packet.getType(message_t* msg)
	{
		return getHeader(msg)->type;
	}

	inline async command void IEEE154Packet.setType(message_t* msg, am_id_t type)
	{
		getHeader(msg)->type = type;
	}

	async command bool IEEE154Packet.requiresAckWait(message_t* msg)
	{
		return call IEEE154Packet.getAckRequired(msg)
			&& call IEEE154Packet.isDataFrame(msg)
			&& call IEEE154Packet.getDestAddr(msg) != 0xFFFF;
	}

	async command bool IEEE154Packet.requiresAckReply(message_t* msg)
	{
		return call IEEE154Packet.getAckRequired(msg)
			&& call IEEE154Packet.isDataFrame(msg)
			&& call IEEE154Packet.getDestAddr(msg) == call ActiveMessageAddress.amAddress();
	}

	inline async event void ActiveMessageAddress.changed()
	{
	}

/*----------------- AMPacket -----------------*/

	inline command am_addr_t AMPacket.address()
	{
		return call ActiveMessageAddress.amAddress();
	}
 
	inline command am_group_t AMPacket.localGroup()
	{
		// TODO: check if this is correct
		return call ActiveMessageAddress.amGroup();
	}

	inline command am_addr_t AMPacket.destination(message_t* msg)
	{
		return call IEEE154Packet.getDestAddr(msg);
	}
 
	inline command am_addr_t AMPacket.source(message_t* msg)
	{
		return call IEEE154Packet.getSrcAddr(msg);
	}

	inline command void AMPacket.setDestination(message_t* msg, am_addr_t addr)
	{
		call IEEE154Packet.setDestAddr(msg, addr);
	}

	inline command void AMPacket.setSource(message_t* msg, am_addr_t addr)
	{
		call IEEE154Packet.setSrcAddr(msg, addr);
	}

	inline command bool AMPacket.isForMe(message_t* msg)
	{
		am_addr_t addr = call AMPacket.destination(msg);
		return addr == call AMPacket.address() || addr == AM_BROADCAST_ADDR;
	}

	inline command am_id_t AMPacket.type(message_t* msg)
	{
		return call IEEE154Packet.getType(msg);
	}

	inline command void AMPacket.setType(message_t* msg, am_id_t type)
	{
		call IEEE154Packet.setType(msg, type);
	}
  
	inline command am_group_t AMPacket.group(message_t* msg) 
	{
		return call IEEE154Packet.getDestPan(msg);
	}

	inline command void AMPacket.setGroup(message_t* msg, am_group_t grp)
	{
		call IEEE154Packet.setDestPan(msg, grp);
	}
}

--- NEW FILE: MessageBufferLayerC.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
 */

configuration MessageBufferLayerC
{
	provides
	{
		interface SplitControl;
		interface Send;
		interface Receive;
	}
	uses
	{
		interface RadioState;
		interface RadioSend;
		interface RadioReceive;

		interface Packet;
	}
}

implementation
{
	components MessageBufferLayerP, MainC, TaskletC;

	MainC.SoftwareInit -> MessageBufferLayerP;

	SplitControl = MessageBufferLayerP;
	Send = MessageBufferLayerP;
	Receive = MessageBufferLayerP.Receive;

	RadioState = MessageBufferLayerP;
	MessageBufferLayerP.Tasklet -> TaskletC;
	RadioSend = MessageBufferLayerP;
	RadioReceive = MessageBufferLayerP;

	Packet = MessageBufferLayerP;
}

--- NEW FILE: MessageBufferLayerP.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 MessageBufferLayerP
{
	provides
	{
		interface SplitControl;
		interface Init as SoftwareInit;

		interface Send;
		interface Receive;
	}
	uses
	{
		interface RadioState;
		interface Tasklet;
		interface RadioSend;
		interface RadioReceive;

		interface Packet;
	}
}

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,
	};

	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;
	}

	task void stateDoneTask()
	{
		uint8_t s;
		
		s = state;

		if( s == STATE_TURN_ON || s == STATE_TURN_OFF )
			state = STATE_READY;

		if( s == STATE_TURN_ON )
			signal SplitControl.startDone(SUCCESS);
		else
			signal SplitControl.stopDone(SUCCESS);
	}

	tasklet_async event void RadioState.done()
	{
		post stateDoneTask();
	}

	default event void SplitControl.startDone(error_t error)
	{
	}

	default event void SplitControl.stopDone(error_t error)
	{
	}

/*----------------- 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, uint8_t len)
	{
		if( len > call Packet.maxPayloadLength() )
			return EINVAL;
		else if( state != STATE_READY )
			return EBUSY;

		call Packet.setPayloadLength(msg, len);

		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;
	}

	default event void Send.sendDone(message_t* msg, error_t error)
	{
	}

	inline command uint8_t Send.maxPayloadLength()
	{
		return call Packet.maxPayloadLength();
	}

	inline command void* Send.getPayload(message_t* msg, uint8_t len)
	{
		return call Packet.getPayload(msg, len);
	}

/*----------------- 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 undelivered 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, 
				call Packet.getPayload(msg, call Packet.maxPayloadLength()), 
				call Packet.payloadLength(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;
	}

	default event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len)
	{
		return msg;
	}
}

--- NEW FILE: Neighborhood.h ---
/*
 * 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
 */

#ifndef __NEIGHBORHOOD_H__
#define __NEIGHBORHOOD_H__

#ifndef NEIGHBORHOOD_SIZE
#define NEIGHBORHOOD_SIZE	5
#endif

#endif//__NEIGHBORHOOD_H__

--- NEW FILE: Neighborhood.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>

/**
 * Every component maintains its own neighborhood data. The Neighboorhood
 * component maintains only the nodeids and ages of the neighbors, and
 * evicts old entries from the table when necessary.
 */
interface Neighborhood
{
	/**
	 * Returns the index of the neighbor in the table. If the node was not 
	 * found in the table, then the value NEIGHBORHOOD is  returned, 
	 * otherwise an index in the range [0, NEIGHBORHOOD-1] is returned.
	 */
	tasklet_async command uint8_t getIndex(am_addr_t id);

	/**
	 * Returns the age of the given entry. The age is incremented by one
	 * every time a new node is inserted into the neighborhood table that
	 * is not already at the very end. If the age would get too large to
	 * fit into a byte, then it is periodically reset to a large value.
	 */
	tasklet_async command uint8_t getAge(uint8_t index);

	/**
	 * Returns the node address for the given entry.
	 */
	tasklet_async command am_addr_t getNode(uint8_t index);

	/**
	 * Adds a new node into the neighborhood table. If this node was already
	 * in the table, then it is just brought to the front (its age is reset
	 * to zero). If the node was not in the table, then the oldest is evicted
	 * and its entry is replaced with this node. The index of the entry
	 * is returned in the range [0, NEIGHBORHOOD-1]. 
	 */
	tasklet_async command uint8_t insertNode(am_addr_t id);

	/**
	 * This event is fired when the oldest entry is replaced with a new
	 * node. The same interface is used by many users, so all of them
	 * will receive this event and can clear the corresponding entry.
	 * After this event is fired, all flags for this entry are cleared
	 * (see the NeighborhoodFlag interface)
	 */
	tasklet_async event void evicted(uint8_t index);
}

--- NEW FILE: NeighborhoodC.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
 */

configuration NeighborhoodC
{
	provides interface Neighborhood;
}

implementation
{
	components NeighborhoodP, MainC;

	Neighborhood = NeighborhoodP;
	MainC.SoftwareInit -> NeighborhoodP;
}

--- NEW FILE: NeighborhoodFlag.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>

/**
 * This interface provides one bit storage for each neighbor in a very
 * fast and conveint way (without using shifts for example). 
 */
interface NeighborhoodFlag
{
	/**
	 * Returns the value of the flag for the given index
	 */
	tasklet_async command bool get(uint8_t index);
	
	/**
	 * Sets the flag for the given index
	 */
	tasklet_async command void set(uint8_t index);

	/**
	 * Clears the flag for the given index. The flag is automatically
	 * cleared after the Neighborhood.evicted event is fired.
	 */
	tasklet_async command void clear(uint8_t index);

	/**
	 * Clears the flag for all indices
	 */
	tasklet_async command void clearAll();
}

--- NEW FILE: NeighborhoodFlagC.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
 */

generic configuration NeighborhoodFlagC()
{
	provides interface NeighborhoodFlag;
}

implementation
{
	components NeighborhoodP;

	// TODO: make sure that no more than 8 flags are used at a time
	NeighborhoodFlag = NeighborhoodP.NeighborhoodFlag[unique("NeighborhoodFlag")];
}

--- NEW FILE: NeighborhoodP.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 <Neighborhood.h>

module NeighborhoodP
{
	provides
	{
		interface Init;
		interface Neighborhood;
		interface NeighborhoodFlag[uint8_t bit];
	}
}

implementation
{
	tasklet_norace am_addr_t nodes[NEIGHBORHOOD_SIZE];
	tasklet_norace uint8_t ages[NEIGHBORHOOD_SIZE];
	tasklet_norace uint8_t flags[NEIGHBORHOOD_SIZE];
	tasklet_norace uint8_t time;
	tasklet_norace uint8_t last;

	command error_t Init.init()
	{
		uint8_t i;

		for(i = 0; i < NEIGHBORHOOD_SIZE; ++i)
			nodes[i] = AM_BROADCAST_ADDR;
	
		return SUCCESS;
	}

	inline tasklet_async command am_addr_t Neighborhood.getNode(uint8_t index)
	{
		return nodes[index];
	}

	inline tasklet_async command uint8_t Neighborhood.getAge(uint8_t index)
	{
		return time - ages[index];
	}

	tasklet_async uint8_t command Neighborhood.getIndex(am_addr_t node)
	{
		uint8_t i;

		if( nodes[last] == node )
			return last;

		for(i = 0; i < NEIGHBORHOOD_SIZE; ++i)
		{
			if( nodes[i] == node )
			{
				last = i;
				break;
			}
		}

		return i;
	}

	tasklet_async uint8_t command Neighborhood.insertNode(am_addr_t node)
	{
		uint8_t i;
		uint8_t maxAge;

		if( nodes[last] == node )
		{
			if( ages[last] == time )
				return last;

			ages[last] = ++time;
			maxAge = 0x80;
		}
		else
		{
			uint8_t oldest = 0;
			maxAge = 0;

			for(i = 0; i < NEIGHBORHOOD_SIZE; ++i)
			{
				uint8_t age;

				if( nodes[i] == node )
				{
					last = i;
					if( ages[i] == time )
						return i;

					ages[i] = ++time;
					maxAge = 0x80;
					break;
				}

				age = time - ages[i];
				if( age > maxAge )
				{
					maxAge = age;
					oldest = i;
				}
			}

			if( i == NEIGHBORHOOD_SIZE )
			{
				signal Neighborhood.evicted(oldest);

				last = oldest;
				nodes[oldest] = node;
				ages[oldest] = ++time;
				flags[oldest] = 0;
			}
		}

		if( (time & 0x7F) == 0x7F && maxAge >= 0x7F )
		{
			for(i = 0; i < NEIGHBORHOOD_SIZE; ++i)
			{
				if( (ages[i] | 0x7F) != time )
					ages[i] = time & 0x80;
			}
		}

		return last;
	}

	inline tasklet_async command bool NeighborhoodFlag.get[uint8_t bit](uint8_t index)
	{
		return flags[index] & (1 << bit);
	}

	inline tasklet_async command void NeighborhoodFlag.set[uint8_t bit](uint8_t index)
	{
		flags[index] |= (1 << bit);
	}

	inline tasklet_async command void NeighborhoodFlag.clear[uint8_t bit](uint8_t index)
	{
		flags[index] &= ~(1 << bit);
	}

	tasklet_async command void NeighborhoodFlag.clearAll[uint8_t bit]()
	{
		uint8_t i;

		bit = ~(1 << bit);

		for(i = 0; i < NEIGHBORHOOD_SIZE; ++i)
			flags[i] &= bit;
	}
}

--- NEW FILE: PacketTimeStamp.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
 */

interface PacketTimeStamp<precision_tag, size_type>
{
	/**
	 * Returns TRUE if the time stamp stored in the message is valid. Under
	 * special circumstances the radio chip might not be able to correctly
	 * assign a precise time value to an incoming packet (e.g. under very 
	 * heavy traffic multiple interrupts can occur before they could be 
	 * serviced, and even if capture registers are used, it is not possible 
	 * to get the time stamp for the first or last unserviced event), in
	 * which case the time stamp value should not be used.
	 */
	async command bool isSet(message_t* msg);

	/**
	 * Return the time stamp for the given message. Please check with the 
	 * isSet command if this value can be relied upon. If this command is
	 * called after transmission, then the transmit time of the packet
	 * is returned (the time when the frame synchronization byte was 
	 * transmitted). If this command is called after the message is received,
	 * the tne receive time of the message is returned.
	 */
	async command size_type get(message_t* msg);

	/**
	 * Sets the isSet flag to FALSE.
	 */
	async command void clear(message_t* msg);

	/**
	 * Sets the isSet false to TRUE and the time stamp value to the 
	 * specified value.
	 */
	async command void set(message_t* msg, size_type value);
}

--- NEW FILE: PacketTimeSynch.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
 */

interface PacketTimeSynch<precision_tag, size_type>
{
	/**
	 * This command should be called by the sender on packets used for sender- 
	 * receiver time synchronization. The eventTime parameter should be as 
	 * close to the current time as possible (precision and size of the stamp 
	 * permitting) to avoid large time synchronization errors resulting from
	 * the time skew between the clocks of the sender and receiver. The
	 * time difference between the sending time and eventTime is stored in 
	 * the message just before it is transmitted over the air.
	 */
	async command void set(message_t* msg, size_type eventTime);

	/**
	 * The recveive should call this method to ensure that the received time
	 * stamp is correct (for the same reason as for PacketTimeStamp.isSet).
	 * If this method returns TRUE, then the eventTime returned by the get
	 * command is correct.
	 */
	async command bool isSet(message_t* msg);

	/**
	 * This command should be called by the receiver. The time stamp of the
	 * received message is added to the embedded time difference to get the
	 * eventTime as measured by the clock of the receiver. The caller should
	 * call the isSet command before to make sure that the returned time is
	 * correct.
	 */
	async command size_type get(message_t* msg);
}

--- NEW FILE: RF230.h ---
/*
 * 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
 */

#ifndef __RF230_H__
#define __RF230_H__

enum rf230_registers_enum
{
	RF230_TRX_STATUS = 0x01,
	RF230_TRX_STATE = 0x02,
	RF230_TRX_CTRL_0 = 0x03,
	RF230_PHY_TX_PWR = 0x05,
	RF230_PHY_RSSI = 0x06,
	RF230_PHY_ED_LEVEL = 0x07,
	RF230_PHY_CC_CCA = 0x08,
	RF230_CCA_THRES = 0x09,
	RF230_IRQ_MASK = 0x0E,
	RF230_IRQ_STATUS = 0x0F,
	RF230_VREG_CTRL = 0x10,
	RF230_BATMON = 0x11,
	RF230_XOSC_CTRL = 0x12,
	RF230_PLL_CF = 0x1A,
	RF230_PLL_DCU = 0x1B,
	RF230_PART_NUM = 0x1C,
	RF230_VERSION_NUM = 0x1D,
	RF230_MAN_ID_0 = 0x1E,
	RF230_MAN_ID_1 = 0x1F,
	RF230_SHORT_ADDR_0 = 0x20,
	RF230_SHORT_ADDR_1 = 0x21,
	RF230_PAN_ID_0 = 0x22,
	RF230_PAN_ID_1 = 0x23,
	RF230_IEEE_ADDR_0 = 0x24,
	RF230_IEEE_ADDR_1 = 0x25,
	RF230_IEEE_ADDR_2 = 0x26,
	RF230_IEEE_ADDR_3 = 0x27,
	RF230_IEEE_ADDR_4 = 0x28,
	RF230_IEEE_ADDR_5 = 0x29,
	RF230_IEEE_ADDR_6 = 0x2A,
	RF230_IEEE_ADDR_7 = 0x2B,
	RF230_XAH_CTRL = 0x2C,
	RF230_CSMA_SEED_0 = 0x2D,
	RF230_CSMA_SEED_1 = 0x2E,
};

enum rf230_trx_register_enums
{
	RF230_CCA_DONE = 1 << 7,
	RF230_CCA_STATUS = 1 << 6,
	RF230_TRX_STATUS_MASK = 0x1F,
	RF230_P_ON = 0,
	RF230_BUSY_RX = 1,
	RF230_BUSY_TX = 2,
	RF230_RX_ON = 6,
	RF230_TRX_OFF = 8,
	RF230_PLL_ON = 9,
	RF230_SLEEP = 15,
	RF230_BUSY_RX_AACK = 16,
	RF230_BUSR_TX_ARET = 17,
	RF230_RX_AACK_ON = 22,
	RF230_TX_ARET_ON = 25,
	RF230_RX_ON_NOCLK = 28,
	RF230_AACK_ON_NOCLK = 29,
	RF230_BUSY_RX_AACK_NOCLK = 30,
	RF230_STATE_TRANSITION_IN_PROGRESS = 31,
	RF230_TRAC_STATUS_MASK = 0xE0,
	RF230_TRAC_SUCCESS = 0,
	RF230_TRAC_CHANNEL_ACCESS_FAILURE = 3 << 5,
	RF230_TRAC_NO_ACK = 5 << 5,
	RF230_TRX_CMD_MASK = 0x1F,
	RF230_NOP = 0,
	RF230_TX_START = 2,
	RF230_FORCE_TRX_OFF = 3,
};

enum rf230_phy_register_enums
{
	RF230_TX_AUTO_CRC_ON = 1 << 7,
	RF230_TX_PWR_MASK = 0x0F,
	RF230_TX_PWR_DEFAULT = 0,
	RF230_RSSI_MASK = 0x1F,
	RF230_CCA_REQUEST = 1 << 7,
	RF230_CCA_MODE_0 = 0 << 5,
	RF230_CCA_MODE_1 = 1 << 5,
	RF230_CCA_MODE_2 = 2 << 5,
	RF230_CCA_MODE_3 = 3 << 5,
	RF230_CHANNEL_DEFAULT = 11,
	RF230_CHANNEL_MASK = 0x1F,
	RF230_CCA_CS_THRES_SHIFT = 4,
	RF230_CCA_ED_THRES_SHIFT = 0,
};

enum rf230_irq_register_enums
{
	RF230_IRQ_BAT_LOW = 1 << 7,
	RF230_IRQ_TRX_UR = 1 << 6,
	RF230_IRQ_TRX_END = 1 << 3,
	RF230_IRQ_RX_START = 1 << 2,
	RF230_IRQ_PLL_UNLOCK = 1 << 1,
	RF230_IRQ_PLL_LOCK = 1 << 0,
};

enum rf230_control_register_enums
{
	RF230_AVREG_EXT = 1 << 7,
	RF230_AVDD_OK = 1 << 6,
	RF230_DVREG_EXT = 1 << 3,
	RF230_DVDD_OK = 1 << 2,
	RF230_BATMON_OK = 1 << 5,
	RF230_BATMON_VHR = 1 << 4,
	RF230_BATMON_VTH_MASK = 0x0F,
	RF230_XTAL_MODE_OFF = 0 << 4,
	RF230_XTAL_MODE_EXTERNAL = 4 << 4,
	RF230_XTAL_MODE_INTERNAL = 15 << 4,
};

enum rf230_pll_register_enums
{
	RF230_PLL_CF_START = 1 << 7,
	RF230_PLL_DCU_START = 1 << 7,
};

enum rf230_spi_command_enums
{
	RF230_CMD_REGISTER_READ = 0x80,
	RF230_CMD_REGISTER_WRITE = 0xC0,
	RF230_CMD_REGISTER_MASK = 0x3F,
	RF230_CMD_FRAME_READ = 0x20,
	RF230_CMD_FRAME_WRITE = 0x60,
	RF230_CMD_SRAM_READ = 0x00,
	RF230_CMD_SRAM_WRITE = 0x40,
};

#endif//__RF230_H__

--- NEW FILE: RF230Config.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
 */

/**
 * This interface needs to be implemented by the MAC to control the behaviour 
 * of the RF230LayerC component.
 */
interface RF230Config
{
	/**
	 * Returns the length of the PHY payload (including the FCF field).
	 * This value must be in the range [3, 127].
	 */
	async command uint8_t getLength(message_t* msg);

	/**
	 * Sets the length of the PHY payload.
	 */
	async command void setLength(message_t* msg, uint8_t len);

	/**
	 * Returns a pointer to the start of the PHY payload that contains 
	 * getLength()-2 number of bytes. The FCF field (CRC-16) is not stored,
	 * but automatically appended / verified.
	 */
	async command uint8_t* getPayload(message_t* msg);

	/**
	 * Sets the timestamp (when the message was sent or received)
	 */
	async command void setTimestamp(message_t* msg, uint16_t time);

	/**
	 * Sets the link quality indicator field for the received message
	 */
	async command void setLinkQuality(message_t* msg, uint8_t lqi);

	/**
	 * Gets the number of bytes we should read before the RadioReceive.header
	 * event is fired. If the length of the packet is less than this amount, 
	 * then that event is fired earlier.
	 */
	async command uint8_t getHeaderLength();

	/**
	 * Returns the maximum PHY length that can be set via the setLength command
	 */
	async command uint8_t getMaxLength();

	/**
	 * Returns the transmit power for the given message, this must be a value 
	 * in the range [0, 15] which will be stored in the PHY_TX_PWR register.
	 */
	async command uint8_t getTransmitPower(message_t* msg);

	/**
	 * This command is used at power up to set the default channel.
	 * The default CC2420 channel is 26.
	 */
	async command uint8_t getDefaultChannel();

	/**
	 * Returns TRUE if before sending this message we should make sure that
	 * the channel is clear via a very basic (and quick) RSSI check.
	 */
	async command bool requiresRssiCca(message_t* msg);
}

--- NEW FILE: RF230LayerC.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
 */

configuration RF230LayerC
{
	provides
	{
		interface Init as PlatformInit @exactlyonce();

		interface RadioState;
		interface RadioSend;
		interface RadioReceive;
		interface RadioCCA;
	}

	uses 
	{
		interface RF230Config;
	}
}

implementation
{
	components RF230LayerP, HplRF230C, BusyWaitMicroC, TaskletC, MainC, RadioAlarmC;

	PlatformInit = RF230LayerP.PlatformInit;

	RadioState = RF230LayerP;
	RadioSend = RF230LayerP;
	RadioReceive = RF230LayerP;
	RadioCCA = RF230LayerP;

	RF230Config = RF230LayerP;

	RF230LayerP.RadioAlarm -> RadioAlarmC.RadioAlarm[unique("RadioAlarm")];
	RadioAlarmC.Alarm -> HplRF230C.Alarm;

	RF230LayerP.SELN -> HplRF230C.SELN;
	RF230LayerP.SpiResource -> HplRF230C.SpiResource;
	RF230LayerP.SpiByte -> HplRF230C;
	RF230LayerP.HplRF230 -> HplRF230C;

	RF230LayerP.SLP_TR -> HplRF230C.SLP_TR;
	RF230LayerP.RSTN -> HplRF230C.RSTN;

	RF230LayerP.IRQ -> HplRF230C.IRQ;
	RF230LayerP.Tasklet -> TaskletC;
	RF230LayerP.BusyWait -> BusyWaitMicroC;

#ifdef RF230_DEBUG
	components DiagMsgC;
	RF230LayerP.DiagMsg -> DiagMsgC;
#endif

	MainC.SoftwareInit -> RF230LayerP.SoftwareInit;
}

--- NEW FILE: RF230LayerP.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 <RF230.h>
#include <HplRF230.h>
#include <Tasklet.h>
#include <RadioAssert.h>

module RF230LayerP
{
	provides
	{
		interface Init as PlatformInit @exactlyonce();
		interface Init as SoftwareInit @exactlyonce();

		interface RadioState;
		interface RadioSend;
		interface RadioReceive;
		interface RadioCCA;
	}

	uses
	{
		interface GeneralIO as SELN;
		interface Resource as SpiResource;

		interface SpiByte;
		interface HplRF230;

		interface GeneralIO as SLP_TR;
		interface GeneralIO as RSTN;

		interface GpioCapture as IRQ;

		interface BusyWait<TMicro, uint16_t>;

		interface RF230Config;
		interface Tasklet;

#ifdef RF230_DEBUG
		interface DiagMsg;
#endif

		interface RadioAlarm;
	}
}

implementation
{
/*----------------- STATE -----------------*/

	tasklet_norace uint8_t state;
	enum
	{
		STATE_P_ON = 0,
		STATE_SLEEP = 1,
		STATE_SLEEP_2_TRX_OFF = 2,
		STATE_TRX_OFF = 3,
		STATE_TRX_OFF_2_RX_ON = 4,
		STATE_RX_ON = 5,
		STATE_BUSY_TX_2_RX_ON = 6,
		STATE_PLL_ON_2_RX_ON = 7,
	};

	tasklet_norace uint8_t cmd;
	enum
	{
		CMD_NONE = 0,			// the state machine has stopped
		CMD_TURNOFF = 1,		// goto SLEEP state
		CMD_STANDBY = 2,		// goto TRX_OFF state
		CMD_TURNON = 3,			// goto RX_ON state
		CMD_TRANSMIT = 4,		// currently transmitting a message
		CMD_RECEIVE = 5,		// currently receiving a message
		CMD_CCA = 6,			// performing clear chanel assesment
		CMD_CHANNEL = 7,		// changing the channel
		CMD_SIGNAL_DONE = 8,	// signal the end of the state transition
		CMD_DOWNLOAD = 9,		// download the received message
	};

	norace bool radioIrq;

	tasklet_norace uint8_t txPower;
	tasklet_norace uint8_t channel;

	tasklet_norace message_t* rxMsg;
	message_t rxMsgBuffer;

	uint16_t capturedTime;	// the current time when the last interrupt has occured

	tasklet_norace uint8_t rssiClear;
	tasklet_norace uint8_t rssiBusy;

/*----------------- REGISTER -----------------*/

	inline void writeRegister(uint8_t reg, uint8_t value)
	{
		ASSERT( call SpiResource.isOwner() );
		ASSERT( reg == (reg & RF230_CMD_REGISTER_MASK) );

		call SELN.clr();
		call HplRF230.spiSplitWrite(RF230_CMD_REGISTER_WRITE | reg);
		call HplRF230.spiSplitReadWrite(value);
		call HplRF230.spiSplitRead();
		call SELN.set();
	}

	inline uint8_t readRegister(uint8_t reg)
	{
		ASSERT( call SpiResource.isOwner() );
		ASSERT( reg == (reg & RF230_CMD_REGISTER_MASK) );

		call SELN.clr();
		call HplRF230.spiSplitWrite(RF230_CMD_REGISTER_READ | reg);
		call HplRF230.spiSplitReadWrite(0);
		reg = call HplRF230.spiSplitRead();
		call SELN.set();

		return reg;
	}

/*----------------- ALARM -----------------*/

	enum
	{
		SLEEP_WAKEUP_TIME = (uint16_t)(880 * RF230_ALARM_MICROSEC),
		CCA_REQUEST_TIME = (uint16_t)(140 * RF230_ALARM_MICROSEC),

		TX_SFD_DELAY = (uint16_t)(176 * RF230_ALARM_MICROSEC),
		RX_SFD_DELAY = (uint16_t)(8 * RF230_ALARM_MICROSEC),
	};

	tasklet_async event void RadioAlarm.fired()
	{
		if( state == STATE_SLEEP_2_TRX_OFF )
		{
			state = STATE_TRX_OFF;
		}
		else if( cmd == CMD_CCA )
		{
			uint8_t cca;

			ASSERT( state == STATE_RX_ON );

			cmd = CMD_NONE;
			cca = readRegister(RF230_TRX_STATUS);

			ASSERT( (cca & RF230_TRX_STATUS_MASK) == RF230_RX_ON );

			signal RadioCCA.done( (cca & RF230_CCA_DONE) ? ((cca & RF230_CCA_STATUS) ? SUCCESS : EBUSY) : FAIL );
		}
		else
			ASSERT(FALSE);

		// make sure the rest of the command processing is called
		call Tasklet.schedule();
	}

/*----------------- INIT -----------------*/

	command error_t PlatformInit.init()
	{
		call SELN.makeOutput();
		call SELN.set();
		call SLP_TR.makeOutput();
		call SLP_TR.clr();
		call RSTN.makeOutput();
		call RSTN.set();

		rxMsg = &rxMsgBuffer;

		// these are just good approximates
		rssiClear = 0;
		rssiBusy = 90;

		return SUCCESS;
	}

	command error_t SoftwareInit.init()
	{
		// for powering up the radio
		return call SpiResource.request();
	}

	void initRadio()
	{
		call BusyWait.wait(510);

		call RSTN.clr();
		call SLP_TR.clr();
		call BusyWait.wait(6);
		call RSTN.set();

		writeRegister(RF230_TRX_CTRL_0, RF230_TRX_CTRL_0_VALUE);
		writeRegister(RF230_TRX_STATE, RF230_TRX_OFF);

		call BusyWait.wait(510);

		writeRegister(RF230_IRQ_MASK, RF230_IRQ_TRX_UR | RF230_IRQ_PLL_UNLOCK | RF230_IRQ_PLL_LOCK | RF230_IRQ_TRX_END | RF230_IRQ_RX_START);
		writeRegister(RF230_CCA_THRES, RF230_CCA_THRES_VALUE);
		writeRegister(RF230_PHY_TX_PWR, RF230_TX_AUTO_CRC_ON | RF230_TX_PWR_DEFAULT);

		txPower = RF230_TX_PWR_DEFAULT;
		channel = call RF230Config.getDefaultChannel() & RF230_CHANNEL_MASK;
		writeRegister(RF230_PHY_CC_CCA, RF230_CCA_MODE_VALUE | channel);

		call SLP_TR.set();
		state = STATE_SLEEP;
	}

/*----------------- SPI -----------------*/

	event void SpiResource.granted()
	{
		// TODO: this should not be here, see my comment in HplRF230C.nc
		call SELN.set();

		if( state == STATE_P_ON )
		{
			initRadio();
			call SpiResource.release();
		}
		else
			call Tasklet.schedule();
	}

	bool isSpiAcquired()
	{
		if( call SpiResource.isOwner() )
			return TRUE;

		if( call SpiResource.immediateRequest() == SUCCESS )
		{
			// TODO: this should not be here, see my comment in HplRF230C.nc
			call SELN.set();

			return TRUE;
		}

		call SpiResource.request();
		return FALSE;
	}

/*----------------- CHANNEL -----------------*/

	tasklet_async command error_t RadioState.setChannel(uint8_t c)
	{
		c &= RF230_CHANNEL_MASK;

		if( cmd != CMD_NONE )
			return EBUSY;
		else if( channel == c )
			return EALREADY;

		channel = c;
		cmd = CMD_CHANNEL;
		call Tasklet.schedule();

		return SUCCESS;
	}

	inline void changeChannel()
	{
		ASSERT( cmd == CMD_CHANNEL );
		ASSERT( state == STATE_SLEEP || state == STATE_TRX_OFF || state == STATE_RX_ON );

		if( isSpiAcquired() )
		{
			writeRegister(RF230_PHY_CC_CCA, RF230_CCA_MODE_VALUE | channel);

			if( state == STATE_RX_ON )
				state = STATE_TRX_OFF_2_RX_ON;
			else
				cmd = CMD_SIGNAL_DONE;
		}
	}

/*----------------- TURN ON/OFF -----------------*/

	inline void changeState()
	{
		if( (cmd == CMD_STANDBY || cmd == CMD_TURNON)
			&& state == STATE_SLEEP && call RadioAlarm.isFree() )
		{
			call SLP_TR.clr();

			call RadioAlarm.wait(SLEEP_WAKEUP_TIME);
			state = STATE_SLEEP_2_TRX_OFF;
		}
		else if( cmd == CMD_TURNON && state == STATE_TRX_OFF && isSpiAcquired() )
		{
			call IRQ.captureRisingEdge();
			writeRegister(RF230_TRX_STATE, RF230_RX_ON);
			state = STATE_TRX_OFF_2_RX_ON;
		}
		else if( (cmd == CMD_TURNOFF || cmd == CMD_STANDBY) 
			&& state == STATE_RX_ON && isSpiAcquired() )
		{
			call IRQ.disable();
			writeRegister(RF230_TRX_STATE, RF230_FORCE_TRX_OFF);
			state = STATE_TRX_OFF;
		}

		if( cmd == CMD_TURNOFF && state == STATE_TRX_OFF )
		{
			call SLP_TR.set();
			state = STATE_SLEEP;
			cmd = CMD_SIGNAL_DONE;
		}
		else if( cmd == CMD_STANDBY && state == STATE_TRX_OFF )
			cmd = CMD_SIGNAL_DONE;
	}

	tasklet_async command error_t RadioState.turnOff()
	{
		if( cmd != CMD_NONE )
			return EBUSY;
		else if( state == STATE_SLEEP )
			return EALREADY;

		cmd = CMD_TURNOFF;
		call Tasklet.schedule();

		return SUCCESS;
	}
	
	tasklet_async command error_t RadioState.standby()
	{
		if( cmd != CMD_NONE || (state == STATE_SLEEP && ! call RadioAlarm.isFree()) )
			return EBUSY;
		else if( state == STATE_TRX_OFF )
			return EALREADY;

		cmd = CMD_STANDBY;
		call Tasklet.schedule();

		return SUCCESS;
	}

	tasklet_async command error_t RadioState.turnOn()
	{
		if( cmd != CMD_NONE || (state == STATE_SLEEP && ! call RadioAlarm.isFree()) )
			return EBUSY;
		else if( state == STATE_RX_ON )
			return EALREADY;

		cmd = CMD_TURNON;
		call Tasklet.schedule();

		return SUCCESS;
	}

	default tasklet_async event void RadioState.done() { }

/*----------------- TRANSMIT -----------------*/

	tasklet_async command error_t RadioSend.send(message_t* msg)
	{
		uint16_t time;
		uint8_t length;
		uint8_t* data;

		if( cmd != CMD_NONE || state != STATE_RX_ON || ! isSpiAcquired() || radioIrq )
			return EBUSY;

		if( call RF230Config.requiresRssiCca(msg) 
				&& readRegister(RF230_PHY_RSSI) > ((rssiClear + rssiBusy) >> 3) )
			return EBUSY;

		writeRegister(RF230_TRX_STATE, RF230_PLL_ON);

		// do something useful, just to wait a little
		length = call RF230Config.getTransmitPower(msg) & RF230_TX_PWR_MASK;
		if( length != txPower )
		{
			txPower = length;
			writeRegister(RF230_PHY_TX_PWR, RF230_TX_AUTO_CRC_ON | txPower);
		}

		// we have missed an incoming message in this short amount of time
		if( (readRegister(RF230_TRX_STATUS) & RF230_TRX_STATUS_MASK) != RF230_PLL_ON )
		{
			ASSERT( (readRegister(RF230_TRX_STATUS) & RF230_TRX_STATUS_MASK) == RF230_BUSY_RX );

			state = STATE_PLL_ON_2_RX_ON;
			return EBUSY;
		}

		atomic
		{
			call SLP_TR.set();
			time = call RadioAlarm.getNow();
		}
		call SLP_TR.clr();

		ASSERT( ! radioIrq );

		call SELN.clr();
		call HplRF230.spiSplitWrite(RF230_CMD_FRAME_WRITE);

		length = call RF230Config.getLength(msg);
		data = call RF230Config.getPayload(msg);

		// length | data[0] ... data[length-3] | automatically generated FCS
		call HplRF230.spiSplitReadWrite(length);

		// the FCS is atomatically generated
		length -= 2;

		do {
			call HplRF230.spiSplitReadWrite(*(data++));
		}
		while( --length != 0 );

		// wait for the SPI transfer to finish
		call HplRF230.spiSplitRead();
		call SELN.set();

		length = readRegister(RF230_TRX_STATUS); 

		// go back to RX_ON state when finished
		writeRegister(RF230_TRX_STATE, RF230_RX_ON);

		/*
		 * There is a very small window (~1 microsecond) when the RF230 went 
		 * into PLL_ON state but was somehow not properly initialized because 
		 * of an incoming message and could not go into BUSY_TX. 
		 */
		if( (length & RF230_TRX_STATUS_MASK) != RF230_BUSY_TX )
		{
#ifdef RF230_DEBUG
			if( call DiagMsg.record() )
			{
				call DiagMsg.str("assert tx");
				call DiagMsg.uint16(call RadioAlarm.getNow());
				call DiagMsg.hex8(readRegister(RF230_TRX_STATUS));
				call DiagMsg.hex8(readRegister(RF230_TRX_STATE));
				call DiagMsg.hex8(radioIrq);
				call DiagMsg.uint8(state);
				call DiagMsg.uint8(cmd);
				call DiagMsg.send();
			}
#endif
			ASSERT( (length & RF230_TRX_STATUS_MASK) == RF230_PLL_ON );
			return FAIL;
		}

		time += TX_SFD_DELAY;
		call RF230Config.setTimestamp(msg, time);

		// wait for the TRX_END interrupt
		state = STATE_BUSY_TX_2_RX_ON;
		cmd = CMD_TRANSMIT;

		return SUCCESS;
	}

	default tasklet_async event void RadioSend.sendDone(error_t error) { }

/*----------------- CCA -----------------*/

	tasklet_async command error_t RadioCCA.request()
	{
		if( cmd != CMD_NONE || state != STATE_RX_ON || ! isSpiAcquired() || ! call RadioAlarm.isFree() )
			return EBUSY;

		// see Errata B7 of the datasheet
		// writeRegister(RF230_TRX_STATE, RF230_PLL_ON);
		// writeRegister(RF230_TRX_STATE, RF230_RX_ON);

		writeRegister(RF230_PHY_CC_CCA, RF230_CCA_REQUEST | RF230_CCA_MODE_VALUE | channel);
		call RadioAlarm.wait(CCA_REQUEST_TIME);
		cmd = CMD_CCA;
		
		return SUCCESS;
	}

	default tasklet_async event void RadioCCA.done(error_t error) { }

/*----------------- RECEIVE -----------------*/

	inline void downloadMessage()
	{
		uint8_t length;
		uint16_t crc;

		call SELN.clr();
		call HplRF230.spiWrite(RF230_CMD_FRAME_READ);

		// read the length byte
		length = call HplRF230.spiWrite(0);

		// if correct length
		if( length >= 3 && length <= call RF230Config.getMaxLength() )
		{
			uint8_t read;
			uint8_t* data;

			// initiate the reading
			call HplRF230.spiSplitWrite(0);

			call RF230Config.setLength(rxMsg, length);
			data = call RF230Config.getPayload(rxMsg);
			crc = 0;

			// we do not store the CRC field
			length -= 2;

			read = call RF230Config.getHeaderLength();
			if( length < read )
				read = length;

			length -= read;

			while( read-- != 0 )
				crc = call HplRF230.crcByte(crc, *(data++) = call HplRF230.spiSplitReadWrite(0));

			if( signal RadioReceive.header(rxMsg) )
			{
				while( length-- != 0 )
					crc = call HplRF230.crcByte(crc, *(data++) = call HplRF230.spiSplitReadWrite(0));

				crc = call HplRF230.crcByte(crc, call HplRF230.spiSplitReadWrite(0));
				crc = call HplRF230.crcByte(crc, call HplRF230.spiSplitReadWrite(0));

				call RF230Config.setLinkQuality(rxMsg, call HplRF230.spiSplitRead());
			}
			else
				crc = 1;
		}
		else
			crc = 1;

		call SELN.set();
		state = STATE_RX_ON;
		cmd = CMD_NONE;

		// signal only if it has passed the CRC check
		if( crc == 0 )
			rxMsg = signal RadioReceive.receive(rxMsg);
	}

/*----------------- IRQ -----------------*/

	async event void IRQ.captured(uint16_t time)
	{
		ASSERT( ! radioIrq );

		atomic
		{
			capturedTime = time;
			radioIrq = TRUE;
		}

		call Tasklet.schedule();
	}

	void serviceRadio()
	{
		if( isSpiAcquired() )
		{
			uint16_t time;
			uint8_t irq;
			
			atomic time = capturedTime;
			radioIrq = FALSE;
			irq = readRegister(RF230_IRQ_STATUS);

#ifdef RF230_DEBUG
			// TODO: handle this interrupt
//			ASSERT( ! (irq & RF230_IRQ_TRX_UR) );
			if( irq & RF230_IRQ_TRX_UR )
			{
				if( call DiagMsg.record() )
				{
					call DiagMsg.str("assert ur");
					call DiagMsg.uint16(call RadioAlarm.getNow());
					call DiagMsg.hex8(readRegister(RF230_TRX_STATUS));
					call DiagMsg.hex8(readRegister(RF230_TRX_STATE));
					call DiagMsg.hex8(irq);
					call DiagMsg.uint8(state);
					call DiagMsg.uint8(cmd);
					call DiagMsg.send();
				}
			}
#endif

			// TODO: handle this interrupt
			ASSERT( ! (irq & RF230_IRQ_PLL_UNLOCK) );

			if( irq & RF230_IRQ_PLL_LOCK )
			{
				if( cmd == CMD_TURNON || cmd == CMD_CHANNEL )
				{
					ASSERT( state == STATE_TRX_OFF_2_RX_ON );

					state = STATE_RX_ON;
					cmd = CMD_SIGNAL_DONE;
				}
				else if( cmd == CMD_TRANSMIT )
				{
					ASSERT( state == STATE_BUSY_TX_2_RX_ON );
				}
				else
					ASSERT(FALSE);
			}

			if( irq & RF230_IRQ_RX_START )
			{
				if( cmd == CMD_CCA )
				{
					signal RadioCCA.done(FAIL);
					cmd = CMD_NONE;
				}

				if( cmd == CMD_NONE )
				{
					ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );

					// the most likely place for busy channel
					rssiBusy += readRegister(RF230_PHY_RSSI) - (rssiBusy >> 2);

					/*
					 * The timestamp corresponds to the first event which could not
					 * have been a PLL_LOCK because then cmd != CMD_NONE, so we must
					 * have received a message (and could also have received the 
					 * TRX_END interrupt in the mean time, but that is fine. Also,
					 * we could not be after a transmission, because then cmd = 
					 * CMD_TRANSMIT.
					 */
					call RF230Config.setTimestamp(rxMsg, time - RX_SFD_DELAY);
					cmd = CMD_RECEIVE;
				}
				else
				{
#ifdef RF230_DEBUG
					if( call DiagMsg.record() )
					{
						call DiagMsg.str("assert irq");
						call DiagMsg.uint16(call RadioAlarm.getNow());
						call DiagMsg.hex8(readRegister(RF230_TRX_STATUS));
						call DiagMsg.hex8(readRegister(RF230_TRX_STATE));
						call DiagMsg.hex8(irq);
						call DiagMsg.uint8(state);
						call DiagMsg.uint8(cmd);
						call DiagMsg.send();
					}
#endif
				}
			}

			if( irq & RF230_IRQ_TRX_END )
			{
				if( cmd == CMD_TRANSMIT )
				{
					ASSERT( state == STATE_BUSY_TX_2_RX_ON );

					state = STATE_RX_ON;
					cmd = CMD_NONE;
					signal RadioSend.sendDone(SUCCESS);

					// TODO: we could have missed a received message
					ASSERT( ! (irq & RF230_IRQ_RX_START) );
				}
				else if( cmd == CMD_RECEIVE )
				{
					ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );

					if( state == STATE_PLL_ON_2_RX_ON )
					{
						ASSERT( (readRegister(RF230_TRX_STATUS) & RF230_TRX_STATUS_MASK) == RF230_PLL_ON );

						writeRegister(RF230_TRX_STATE, RF230_RX_ON);
						state = STATE_RX_ON;
					}
					else
					{
						// the most likely place for clear channel (hope to avoid acks)
						rssiClear += readRegister(RF230_PHY_RSSI) - (rssiClear >> 2);
					}

					cmd = CMD_DOWNLOAD;
				}
				else
					ASSERT(FALSE);
			}
		}
	}

	default tasklet_async event bool RadioReceive.header(message_t* msg)
	{
		return TRUE;
	}

	default tasklet_async event message_t* RadioReceive.receive(message_t* msg)
	{
		return msg;
	}

/*----------------- TASKLET -----------------*/

	tasklet_async event void Tasklet.run()
	{
		if( radioIrq )
			serviceRadio();

		if( cmd != CMD_NONE )
		{
			if( cmd == CMD_DOWNLOAD )
				downloadMessage();
			else if( cmd <= CMD_TURNON && CMD_TURNOFF <= cmd )
				changeState();
			else if( cmd == CMD_CHANNEL )
				changeChannel();
			
			if( cmd == CMD_SIGNAL_DONE )
			{
				cmd = CMD_NONE;
				signal RadioState.done();
			}
		}

		if( cmd == CMD_NONE && state == STATE_RX_ON && ! radioIrq )
			signal RadioSend.ready();

		if( cmd == CMD_NONE )
			call SpiResource.release();
	}
}

--- NEW FILE: RadioAlarm.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>

interface RadioAlarm
{
	/**
	 * Returns TRUE if the alarm is free and ready to be used. Once the alarm
	 * is free, it cannot become nonfree in the same tasklet block. Note,
	 * if the alarm is currently set (even if for ourselves) then it is not free.
	 */
	tasklet_async command bool isFree();

	/**
	 * Waits till the specified timeout period expires. The alarm must be free.
	 */
	tasklet_async command void wait(uint16_t timeout);

	/**
	 * Cancels the running alarm. The alarm must be pending.
	 */
	tasklet_async command void cancel();

	/**
	 * This event is fired when the specified timeout period expires.
	 */
	tasklet_async event void fired();

	/**
	 * Returns the current time as measured by the radio stack.
	 */
	async command uint16_t getNow();
}

--- NEW FILE: RadioAlarmC.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
 */

configuration RadioAlarmC
{
	provides
	{
		interface RadioAlarm[uint8_t id]; // use unique("RadioAlarm")
	}

	uses
	{
		interface Alarm<TRF230, uint16_t> @exactlyonce();
	}
}

implementation
{
	components RadioAlarmP, TaskletC;

	RadioAlarm = RadioAlarmP;
	Alarm = RadioAlarmP;
	RadioAlarmP.Tasklet -> TaskletC;
}

--- NEW FILE: RadioAlarmP.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 RadioAlarmP
{
	provides
	{
		interface RadioAlarm[uint8_t id];
	}

	uses
	{
		interface Alarm<TRF230, uint16_t>;
		interface Tasklet;
	}
}

implementation
{
	norace uint8_t state;
	enum
	{
		STATE_READY = 0,
		STATE_WAIT = 1,
		STATE_FIRED = 2,
	};

	tasklet_norace uint8_t alarm;

	async event void Alarm.fired()
	{
		atomic
		{
			if( state == STATE_WAIT )
				state = STATE_FIRED;
		}

		call Tasklet.schedule();
	}

	inline async command uint16_t RadioAlarm.getNow[uint8_t id]()
	{
		return call Alarm.getNow();
	}

	tasklet_async event void Tasklet.run()
	{
		if( state == STATE_FIRED )
		{
			state = STATE_READY;
			signal RadioAlarm.fired[alarm]();
		}
	}

	default tasklet_async event void RadioAlarm.fired[uint8_t id]()
	{
	}

	inline tasklet_async command bool RadioAlarm.isFree[uint8_t id]()
	{
		return state == STATE_READY;
	}

	tasklet_async command void RadioAlarm.wait[uint8_t id](uint16_t timeout)
	{
		ASSERT( state == STATE_READY );

		alarm = id;
		state = STATE_WAIT;
		call Alarm.start(timeout);
	}

	tasklet_async command void RadioAlarm.cancel[uint8_t id]()
	{
		ASSERT( alarm == id );
		ASSERT( state != STATE_READY );

		call Alarm.stop();
		state = STATE_READY;
	}
}

--- NEW FILE: RadioAssert.h ---
/*
 * 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
 */

#ifndef __RADIOASSERT_H__
#define __RADIOASSERT_H__

#ifdef RF230_DEBUG

	void assert(bool condition, const char* file, uint16_t line);
	#define ASSERT(COND) assert(COND, __FILE__, __LINE__)

#else

	#define ASSERT(COND) for(;0;)

#endif

#endif//__RADIOASSERT_H__

--- NEW FILE: RadioCCA.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>

interface RadioCCA
{
	/**
	 * Starts the clear channel assesment procedure. Returns EBUSY if the radio
	 * is currently servicing a clear channel assesment, and SUCCESS otherwise.
	 * The check will be performed only in the RX_READY state.
	 */
	tasklet_async command error_t request();

	/**
	 * Signals the completion of the clear channel assesment send command.
	 * SUCCESS means the channel is clear, EBUSY means the channel is not
	 * clear, and FAIL means that the clear channel assesment could not
	 * be finished or the operation was cancelled.
	 */
	tasklet_async event void done(error_t error);
}

--- NEW FILE: RadioReceive.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>

interface RadioReceive
{
	/**
	 * This event is fired when the header is received/downloaded and the 
	 * higher layers are consulted whether it needs to be downloaded and 
	 * further processed. Return FALSE if the message should be discarded.
	 * In particular, the message buffer layer returns FALSE if there is
	 * no space for a new message, so this message will not get acknowledged.
	 */
	tasklet_async event bool header(message_t* msg);

	/**
	 * Signals the reception of a message, but only for those messages for
	 * which SUCCESS was returned in the header event. The usual owner rules 
	 * apply to the message pointers.
	 */
	tasklet_async event message_t* receive(message_t* msg);
}

--- NEW FILE: RadioSend.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>

interface RadioSend
{
	/**
	 * Starts the transmission of the given message. This command must not
	 * be called while another send is in progress (so one must wait for the
	 * sendDone event). Returns EBUSY if a reception is in progress or for
	 * some other reason the request cannot be temporarily satisfied (e.g.
	 * the SPI bus access could not be acquired). In this case the send 
	 * command could be retried from a tasklet. Returns SUCCESS if the 
	 * transmission could be started. In this case sendDone will be fired.
	 */
	tasklet_async command error_t send(message_t* msg);
	
	/**
	 * Signals the completion of the send command, exactly once for each 
	 * successfull send command. If the returned error code is SUCCESS, then 
	 * the message was sent (may not have been acknowledged), otherwise 
	 * the message was not transmitted over the air.
	 */
	tasklet_async event void sendDone(error_t error);

	/**
	 * This event is fired when the component is most likely able to accept 
	 * a send request. If the send command has returned with a failure, then
	 * this event will be called at least once in the near future.
	 */
	tasklet_async event void ready();
}

--- NEW FILE: RadioState.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>

interface RadioState
{
	/**
	 * Moves to radio into sleep state with the lowest power consumption but 
	 * highest wakeup time. The radio cannot send or receive in this state 
	 * and releases all access to shared resources (e.g. SPI bus). 
	 */
	tasklet_async command error_t turnOff();

	/**
	 * The same as the turnOff command, except it is not as deep sleep, and
	 * it is quicker to recover from this state.
	 */
	tasklet_async command error_t standby();

	/**
	 * Goes into receive state. The radio continuously receive messages 
	 * and able to transmit.
	 */
	tasklet_async command error_t turnOn();

	/**
	 * Sets the current channel. Returns EBUSY if the stack is unable
	 * to change the channel this time (some other operation is in progress)
	 * SUCCESS otherwise.
	 */
	tasklet_async command error_t setChannel(uint8_t channel);

	/**
	 * This event is signaled exactly once for each sucessfully posted state 
	 * transition and setChannel command when it is completed.
	 */
	tasklet_async event void done();
}

--- NEW FILE: RandomCollisionConfig.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
 */

interface RandomCollisionConfig
{
	/**
	 * Returns the initial amount of maximum backoff for this message.
	 */
	async command uint16_t getInitialBackoff(message_t* msg);

	/**
	 * Returns the amount of maximum backoff when there is congestion
	 * (the channel was busy for the first try)
	 */
	async command uint16_t getCongestionBackoff(message_t* msg);

	/**
	 * Returns the minimum ticks before the message could be sent.
	 */
	async command uint16_t getMinimumBackoff();

	/**
	 * The provided message was just received, and this command should return 
	 * the time till no transmission should be initiated.
	 */
	async command uint16_t getTransmitBarrier(message_t* msg);
}

--- NEW FILE: RandomCollisionLayerC.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
 */

configuration RandomCollisionLayerC
{
	provides
	{
		interface RadioSend;
		interface RadioReceive;
	}
	uses
	{
		interface RadioSend as SubSend;
		interface RadioReceive as SubReceive;
		interface RandomCollisionConfig as Config;
	}
}

implementation
{
	components RandomCollisionLayerP, RadioAlarmC, RandomC;

	RadioSend = RandomCollisionLayerP;
	SubSend = RandomCollisionLayerP;
	Config = RandomCollisionLayerP;
	RadioReceive = RandomCollisionLayerP;
	SubReceive = RandomCollisionLayerP;

	RandomCollisionLayerP.RadioAlarm -> RadioAlarmC.RadioAlarm[unique("RadioAlarm")];
	RandomCollisionLayerP.Random -> RandomC;
}

--- NEW FILE: RandomCollisionLayerP.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 co