[Tinyos-2-commits] CVS: tinyos-2.x/tos/chips/cc2420/lpl
DefaultLpl.h, NONE, 1.1 DefaultLplC.nc, NONE,
1.1 DefaultLplP.nc, NONE, 1.1 DummyLplC.nc, NONE,
1.1 DummyLplP.nc, NONE, 1.1 PowerCycleC.nc, NONE,
1.1 PowerCycleP.nc, NONE, 1.1 readme.txt, NONE, 1.1
dmm
rincon at users.sourceforge.net
Tue Jul 3 17:37:17 PDT 2007
Update of /cvsroot/tinyos/tinyos-2.x/tos/chips/cc2420/lpl
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv30635/lpl
Added Files:
DefaultLpl.h DefaultLplC.nc DefaultLplP.nc DummyLplC.nc
DummyLplP.nc PowerCycleC.nc PowerCycleP.nc readme.txt
Log Message:
New CC2420 architecture in place for 2.0.2 release. See the README.txt file for changes. Test results from TUnit testing are included.
--- NEW FILE: DefaultLpl.h ---
/*
* Copyright (c) 2005-2006 Rincon Research Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the Rincon Research Corporation nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* RINCON RESEARCH OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE
*/
/**
* @author David Moss
*/
#ifndef DEFAULTLPL_H
#define DEFAULTLPL_H
/**
* Low Power Listening Send States
*/
typedef enum {
S_LPL_NOT_SENDING, // DEFAULT
S_LPL_FIRST_MESSAGE, // 1. Sending the first message
S_LPL_SENDING, // 2. Sending all other messages
S_LPL_CLEAN_UP, // 3. Clean up the transmission
} lpl_sendstate_t;
/**
* Amount of time, in milliseconds, to keep the radio on after
* a successful receive addressed to this node
*/
#ifndef DELAY_AFTER_RECEIVE
#define DELAY_AFTER_RECEIVE 100
#endif
/**
* This is a measured value of the time in ms the radio is actually on
* We round this up to err on the side of better performance ratios
*/
#ifndef DUTY_ON_TIME
#define DUTY_ON_TIME 5
#endif
/**
* The maximum number of CCA checks performed on each wakeup.
* If there are too few, the receiver may wake up between messages
* and not detect the transmitter.
*
* The on-time had to increase from the original version to allow multiple
* transmitters to co-exist. This is due to using ack's, which then requires us
* to extend the backoff period. In networks that transmit frequently, possibly
* with multiple transmitters, this power scheme makes sense.
*
* In networks that transmit very infrequently or without multiple transmitters,
* it makes more sense to go with no acks and no backoffs and make the
* receive check as short as possible.
*/
#ifndef MAX_LPL_CCA_CHECKS
#if defined(PLATFORM_TELOSB) || defined(PLATFORM_TMOTE)
#define MAX_LPL_CCA_CHECKS 400
#else
#define MAX_LPL_CCA_CHECKS 400
#endif
#endif
/**
* The minimum number of samples that must be taken in CC2420DutyCycleP
* that show the channel is not clear before a detection event is issued
*/
#ifndef MIN_SAMPLES_BEFORE_DETECT
#define MIN_SAMPLES_BEFORE_DETECT 3
#endif
#endif
--- NEW FILE: DefaultLplC.nc ---
/*
* Copyright (c) 2005-2006 Rincon Research Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the Rincon Research Corporation nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* RINCON RESEARCH OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE
*/
/**
* Low Power Listening for the CC2420
* @author David Moss
*/
#include "DefaultLpl.h"
#warning "*** USING DEFAULT POWER LISTENING LAYER"
configuration DefaultLplC {
provides {
interface LowPowerListening;
interface Send;
interface Receive;
interface SplitControl;
interface State as SendState;
}
uses {
interface Send as SubSend;
interface Receive as SubReceive;
interface SplitControl as SubControl;
}
}
implementation {
components MainC,
DefaultLplP,
PowerCycleC,
CC2420ActiveMessageC,
CC2420CsmaC,
CC2420TransmitC,
CC2420PacketC,
RandomC,
new StateC() as SendStateC,
new TimerMilliC() as OffTimerC,
new TimerMilliC() as SendDoneTimerC,
LedsC;
LowPowerListening = DefaultLplP;
Send = DefaultLplP;
Receive = DefaultLplP;
SplitControl = PowerCycleC;
SendState = SendStateC;
SubControl = DefaultLplP.SubControl;
SubReceive = DefaultLplP.SubReceive;
SubSend = DefaultLplP.SubSend;
MainC.SoftwareInit -> DefaultLplP;
DefaultLplP.SplitControlState -> PowerCycleC.SplitControlState;
DefaultLplP.RadioPowerState -> PowerCycleC.RadioPowerState;
DefaultLplP.SendState -> SendStateC;
DefaultLplP.OffTimer -> OffTimerC;
DefaultLplP.SendDoneTimer -> SendDoneTimerC;
DefaultLplP.PowerCycle -> PowerCycleC;
DefaultLplP.Resend -> CC2420TransmitC;
DefaultLplP.PacketAcknowledgements -> CC2420ActiveMessageC;
DefaultLplP.AMPacket -> CC2420ActiveMessageC;
DefaultLplP.CC2420PacketBody -> CC2420PacketC;
DefaultLplP.RadioBackoff -> CC2420CsmaC;
DefaultLplP.Random -> RandomC;
DefaultLplP.Leds -> LedsC;
}
--- NEW FILE: DefaultLplP.nc ---
/*
* Copyright (c) 2005-2006 Rincon Research Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the Rincon Research Corporation nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* RINCON RESEARCH OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE
*/
/**
* Low Power Listening for the CC2420. This component is responsible for
* delivery of an LPL packet, and for turning off the radio when the radio
* has run out of tasks.
*
* The PowerCycle component is responsible for duty cycling the radio
* and performing receive detections.
*
* @author David Moss
*/
#include "DefaultLpl.h"
#include "AM.h"
module DefaultLplP {
provides {
interface Init;
interface LowPowerListening;
interface Send;
interface Receive;
}
uses {
interface Send as SubSend;
interface CC2420Transmit as Resend;
interface RadioBackoff[am_id_t amId];
interface Receive as SubReceive;
interface AMPacket;
interface SplitControl as SubControl;
interface PowerCycle;
interface CC2420PacketBody;
interface PacketAcknowledgements;
interface State as SendState;
interface State as RadioPowerState;
interface State as SplitControlState;
interface Timer<TMilli> as OffTimer;
interface Timer<TMilli> as SendDoneTimer;
interface Random;
interface Leds;
}
}
implementation {
/** The message currently being sent */
norace message_t *currentSendMsg;
/** The length of the current send message */
uint8_t currentSendLen;
/** TRUE if the radio is duty cycling and not always on */
bool dutyCycling;
/**
* Radio State
*/
enum {
S_OFF,
S_ON,
};
/**
* Send States
*/
enum {
S_IDLE,
S_SENDING,
};
enum {
ONE_MESSAGE = 0,
};
/***************** Prototypes ***************/
task void send();
task void resend();
task void startRadio();
task void stopRadio();
void initializeSend();
void startOffTimer();
uint16_t getActualDutyCycle(uint16_t dutyCycle);
/***************** Init Commands ***************/
command error_t Init.init() {
dutyCycling = FALSE;
return SUCCESS;
}
/***************** LowPowerListening Commands ***************/
/**
* Set this this node's radio sleep interval, in milliseconds.
* Once every interval, the node will sleep and perform an Rx check
* on the radio. Setting the sleep interval to 0 will keep the radio
* always on.
*
* This is the equivalent of setting the local duty cycle rate.
*
* @param sleepIntervalMs the length of this node's Rx check interval, in [ms]
*/
command void LowPowerListening.setLocalSleepInterval(
uint16_t sleepIntervalMs) {
call PowerCycle.setSleepInterval(sleepIntervalMs);
}
/**
* @return the local node's sleep interval, in [ms]
*/
command uint16_t LowPowerListening.getLocalSleepInterval() {
return call PowerCycle.getSleepInterval();
}
/**
* Set this node's radio duty cycle rate, in units of [percentage*100].
* For example, to get a 0.05% duty cycle,
* <code>
* call LowPowerListening.setDutyCycle(5);
* </code>
*
* For a 100% duty cycle (always on),
* <code>
* call LowPowerListening.setDutyCycle(10000);
* </code>
*
* This is the equivalent of setting the local sleep interval explicitly.
*
* @param dutyCycle The duty cycle percentage, in units of [percentage*100]
*/
command void LowPowerListening.setLocalDutyCycle(uint16_t dutyCycle) {
call PowerCycle.setSleepInterval(
call LowPowerListening.dutyCycleToSleepInterval(dutyCycle));
}
/**
* @return this node's radio duty cycle rate, in units of [percentage*100]
*/
command uint16_t LowPowerListening.getLocalDutyCycle() {
return call LowPowerListening.sleepIntervalToDutyCycle(
call PowerCycle.getSleepInterval());
}
/**
* Configure this outgoing message so it can be transmitted to a neighbor mote
* with the specified Rx sleep interval.
* @param msg Pointer to the message that will be sent
* @param sleepInterval The receiving node's sleep interval, in [ms]
*/
command void LowPowerListening.setRxSleepInterval(message_t *msg,
uint16_t sleepIntervalMs) {
(call CC2420PacketBody.getMetadata(msg))->rxInterval = sleepIntervalMs;
}
/**
* @return the destination node's sleep interval configured in this message
*/
command uint16_t LowPowerListening.getRxSleepInterval(message_t *msg) {
return (call CC2420PacketBody.getMetadata(msg))->rxInterval;
}
/**
* Configure this outgoing message so it can be transmitted to a neighbor mote
* with the specified Rx duty cycle rate.
* Duty cycle is in units of [percentage*100], i.e. 0.25% duty cycle = 25.
*
* @param msg Pointer to the message that will be sent
* @param dutyCycle The duty cycle of the receiving mote, in units of
* [percentage*100]
*/
command void LowPowerListening.setRxDutyCycle(message_t *msg,
uint16_t dutyCycle) {
(call CC2420PacketBody.getMetadata(msg))->rxInterval =
call LowPowerListening.dutyCycleToSleepInterval(dutyCycle);
}
/**
* @return the destination node's duty cycle configured in this message
* in units of [percentage*100]
*/
command uint16_t LowPowerListening.getRxDutyCycle(message_t *msg) {
return call LowPowerListening.sleepIntervalToDutyCycle(
(call CC2420PacketBody.getMetadata(msg))->rxInterval);
}
/**
* Convert a duty cycle, in units of [percentage*100], to
* the sleep interval of the mote in milliseconds
* @param dutyCycle The duty cycle in units of [percentage*100]
* @return The equivalent sleep interval, in units of [ms]
*/
command uint16_t LowPowerListening.dutyCycleToSleepInterval(
uint16_t dutyCycle) {
dutyCycle = getActualDutyCycle(dutyCycle);
if(dutyCycle == 10000) {
return 0;
}
return (DUTY_ON_TIME * (10000 - dutyCycle)) / dutyCycle;
}
/**
* Convert a sleep interval, in units of [ms], to a duty cycle
* in units of [percentage*100]
* @param sleepInterval The sleep interval in units of [ms]
* @return The duty cycle in units of [percentage*100]
*/
command uint16_t LowPowerListening.sleepIntervalToDutyCycle(
uint16_t sleepInterval) {
if(sleepInterval == 0) {
return 10000;
}
return getActualDutyCycle((DUTY_ON_TIME * 10000)
/ (sleepInterval + DUTY_ON_TIME));
}
/***************** Send Commands ***************/
/**
* Each call to this send command gives the message a single
* DSN that does not change for every copy of the message
* sent out. For messages that are not acknowledged, such as
* a broadcast address message, the receiving end does not
* signal receive() more than once for that message.
*/
command error_t Send.send(message_t *msg, uint8_t len) {
if(call SplitControlState.getState() == S_OFF) {
// Everything is off right now, start SplitControl and try again
return EOFF;
}
if(call SendState.requestState(S_LPL_SENDING) == SUCCESS) {
currentSendMsg = msg;
currentSendLen = len;
// In case our off timer is running...
call OffTimer.stop();
call SendDoneTimer.stop();
if(call RadioPowerState.getState() == S_ON) {
initializeSend();
return SUCCESS;
} else {
post startRadio();
}
return SUCCESS;
}
return FAIL;
}
command error_t Send.cancel(message_t *msg) {
if(currentSendMsg == msg) {
call SendState.toIdle();
call SendDoneTimer.stop();
startOffTimer();
return call SubSend.cancel(msg);
}
return FAIL;
}
command uint8_t Send.maxPayloadLength() {
return call SubSend.maxPayloadLength();
}
command void *Send.getPayload(message_t* msg) {
return call SubSend.getPayload(msg);
}
/***************** RadioBackoff Events ****************/
async event void RadioBackoff.requestInitialBackoff[am_id_t amId](message_t *msg) {
if((call CC2420PacketBody.getMetadata(msg))->rxInterval
> ONE_MESSAGE) {
call RadioBackoff.setInitialBackoff[amId]( call Random.rand16()
% (0x4 * CC2420_BACKOFF_PERIOD) + CC2420_MIN_BACKOFF);
}
}
async event void RadioBackoff.requestCongestionBackoff[am_id_t amId](message_t *msg) {
if((call CC2420PacketBody.getMetadata(msg))->rxInterval
> ONE_MESSAGE) {
call RadioBackoff.setCongestionBackoff[amId]( call Random.rand16()
% (0x3 * CC2420_BACKOFF_PERIOD) + CC2420_MIN_BACKOFF);
}
}
async event void RadioBackoff.requestCca[am_id_t amId](message_t *msg) {
}
/***************** Receive Commands ***************/
command void *Receive.getPayload(message_t* msg, uint8_t* len) {
return call SubReceive.getPayload(msg, len);
}
command uint8_t Receive.payloadLength(message_t* msg) {
return call SubReceive.payloadLength(msg);
}
/***************** DutyCycle Events ***************/
/**
* A transmitter was detected. You must now take action to
* turn the radio off when the transaction is complete.
*/
event void PowerCycle.detected() {
// At this point, the duty cycling has been disabled temporary
// and it will be this component's job to turn the radio back off
// Wait long enough to see if we actually receive a packet, which is
// just a little longer in case there is more than one lpl transmitter on
// the channel.
if(call SendState.isIdle()) {
startOffTimer();
}
}
/***************** SubControl Events ***************/
event void SubControl.startDone(error_t error) {
if(!error) {
call RadioPowerState.forceState(S_ON);
if(call SendState.getState() == S_LPL_FIRST_MESSAGE
|| call SendState.getState() == S_LPL_SENDING) {
initializeSend();
}
}
}
event void SubControl.stopDone(error_t error) {
if(!error) {
if(call SendState.getState() == S_LPL_FIRST_MESSAGE
|| call SendState.getState() == S_LPL_SENDING) {
// We're in the middle of sending a message; start the radio back up
post startRadio();
} else {
call OffTimer.stop();
call SendDoneTimer.stop();
}
}
}
/***************** SubSend Events ***************/
event void SubSend.sendDone(message_t* msg, error_t error) {
switch(call SendState.getState()) {
case S_LPL_SENDING:
if(call SendDoneTimer.isRunning()) {
if(!call PacketAcknowledgements.wasAcked(msg)) {
post resend();
return;
}
}
break;
case S_LPL_CLEAN_UP:
/**
* We include this state so upper layers can't send a different message
* before the last message gets done sending
*/
break;
default:
break;
}
call SendState.toIdle();
call SendDoneTimer.stop();
startOffTimer();
signal Send.sendDone(msg, error);
}
/***************** SubReceive Events ***************/
/**
* If the received message is new, we signal the receive event and
* start the off timer. If the last message we received had the same
* DSN as this message, then the chances are pretty good
* that this message should be ignored, especially if the destination address
* as the broadcast address
*/
event message_t *SubReceive.receive(message_t* msg, void* payload,
uint8_t len) {
startOffTimer();
return signal Receive.receive(msg, payload, len);
}
/***************** Timer Events ****************/
event void OffTimer.fired() {
/*
* Only stop the radio if the radio is supposed to be off permanently
* or if the duty cycle is on and our sleep interval is not 0
*/
if(call SplitControlState.getState() == S_OFF
|| (call PowerCycle.getSleepInterval() > 0
&& call SplitControlState.getState() == S_ON
&& call SendState.getState() == S_LPL_NOT_SENDING)) {
post stopRadio();
}
}
/**
* When this timer is running, that means we're sending repeating messages
* to a node that is receive check duty cycling.
*/
event void SendDoneTimer.fired() {
if(call SendState.getState() == S_LPL_SENDING) {
// The next time SubSend.sendDone is signaled, send is complete.
call SendState.forceState(S_LPL_CLEAN_UP);
}
}
/***************** Resend Events ****************/
/**
* Signal that a message has been sent
*
* @param p_msg message to send.
* @param error notifaction of how the operation went.
*/
async event void Resend.sendDone( message_t* p_msg, error_t error ) {
// This is actually caught by SubSend.sendDone
}
/***************** Tasks ***************/
task void send() {
if(call SubSend.send(currentSendMsg, currentSendLen) != SUCCESS) {
post send();
}
}
task void resend() {
if(call Resend.resend(TRUE) != SUCCESS) {
post resend();
}
}
task void startRadio() {
if(call SubControl.start() != SUCCESS) {
post startRadio();
}
}
task void stopRadio() {
if(call SendState.getState() == S_LPL_NOT_SENDING) {
if(call SubControl.stop() != SUCCESS) {
post stopRadio();
}
}
}
/***************** Functions ***************/
void initializeSend() {
if(call LowPowerListening.getRxSleepInterval(currentSendMsg)
> ONE_MESSAGE) {
if(call AMPacket.destination(currentSendMsg) == AM_BROADCAST_ADDR) {
call PacketAcknowledgements.noAck(currentSendMsg);
} else {
// Send it repetitively within our transmit window
call PacketAcknowledgements.requestAck(currentSendMsg);
}
call SendDoneTimer.startOneShot(
call LowPowerListening.getRxSleepInterval(currentSendMsg) + 20);
}
post send();
}
void startOffTimer() {
call OffTimer.startOneShot(DELAY_AFTER_RECEIVE);
}
/**
* Check the bounds on a given duty cycle
* We're never over 100%, and we're never at 0%
*/
uint16_t getActualDutyCycle(uint16_t dutyCycle) {
if(dutyCycle > 10000) {
return 10000;
} else if(dutyCycle == 0) {
return 1;
}
return dutyCycle;
}
}
--- NEW FILE: DummyLplC.nc ---
/*
* Copyright (c) 2005-2006 Rincon Research Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the Rincon Research Corporation nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* RINCON RESEARCH OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE
*/
/**
* Dummy low power listening interface used when LowPowerListening is not
* compiled in with the application.
* Sleep interval is always 0, and duty cycle is always 100%
* @author David Moss
*/
configuration DummyLplC {
provides {
interface Send;
interface Receive;
interface LowPowerListening;
interface SplitControl;
interface State as SendState;
}
uses {
interface Send as SubSend;
interface Receive as SubReceive;
interface SplitControl as SubControl;
}
}
implementation {
components DummyLplP;
components new StateC();
Send = SubSend;
Receive = SubReceive;
SplitControl = SubControl;
LowPowerListening = DummyLplP;
SendState = StateC;
}
--- NEW FILE: DummyLplP.nc ---
/*
* Copyright (c) 2005-2006 Rincon Research Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the Rincon Research Corporation nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* RINCON RESEARCH OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE
*/
/**
* Dummy low power listening interface used when LowPowerListening is not
* compiled in with the application.
* Sleep interval is always 0, and duty cycle is always 100%
* @author David Moss
*/
module DummyLplP {
provides {
interface LowPowerListening;
}
}
implementation {
command void LowPowerListening.setLocalSleepInterval(uint16_t sleepIntervalMs) {
}
command uint16_t LowPowerListening.getLocalSleepInterval() {
return 0;
}
command void LowPowerListening.setLocalDutyCycle(uint16_t dutyCycle) {
}
command uint16_t LowPowerListening.getLocalDutyCycle() {
return 10000;
}
command void LowPowerListening.setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs) {
}
command uint16_t LowPowerListening.getRxSleepInterval(message_t *msg) {
return 0;
}
command void LowPowerListening.setRxDutyCycle(message_t *msg, uint16_t dutyCycle) {
}
command uint16_t LowPowerListening.getRxDutyCycle(message_t *msg) {
return 10000;
}
command uint16_t LowPowerListening.dutyCycleToSleepInterval(uint16_t dutyCycle) {
return 0;
}
command uint16_t LowPowerListening.sleepIntervalToDutyCycle(uint16_t sleepInterval) {
return 10000;
}
}
--- NEW FILE: PowerCycleC.nc ---
/*
* Copyright (c) 2005-2006 Rincon Research Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the Rincon Research Corporation nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* RINCON RESEARCH OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE
*/
/**
* Use this component to duty cycle the radio. When a message is heard,
* disable DutyCycling.
*
* @author David Moss dmm at rincon.com
*/
configuration PowerCycleC {
provides {
interface PowerCycle;
interface SplitControl;
interface State as SplitControlState;
interface State as RadioPowerState;
}
}
implementation {
components PowerCycleP,
CC2420TransmitC,
CC2420ReceiveC,
CC2420CsmaC,
LedsC,
new StateC() as RadioPowerStateC,
new StateC() as SplitControlStateC,
new TimerMilliC() as OnTimerC,
new TimerMilliC() as CheckTimerC;
#if defined(LOW_POWER_LISTENING) || defined(ACK_LOW_POWER_LISTENING)
components DefaultLplC as LplC;
#else
components DummyLplC as LplC;
#endif
PowerCycle = PowerCycleP;
SplitControl = PowerCycleP;
SplitControlState = SplitControlStateC;
RadioPowerState = RadioPowerStateC;
PowerCycleP.EnergyIndicator -> CC2420TransmitC.EnergyIndicator;
PowerCycleP.ByteIndicator -> CC2420TransmitC.ByteIndicator;
PowerCycleP.PacketIndicator -> CC2420ReceiveC.PacketIndicator;
PowerCycleP.SubControl -> CC2420CsmaC;
PowerCycleP.SendState -> LplC;
PowerCycleP.RadioPowerState -> RadioPowerStateC;
PowerCycleP.SplitControlState -> SplitControlStateC;
PowerCycleP.OnTimer -> OnTimerC;
PowerCycleP.Leds -> LedsC;
}
--- NEW FILE: PowerCycleP.nc ---
/*
* Copyright (c) 2005-2006 Rincon Research Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the Rincon Research Corporation nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* RINCON RESEARCH OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE
*/
/**
* Module to duty cycle the radio on and off, performing CCA receive checks.
* When a carrier is sensed, this will leave the radio on. It is then up
* to higher layers to turn the radio off again. Once the radio is turned
* off, this module will automatically continue duty cycling and looking for
* a modulated signal.
*
* Suggested TODO's:
* > TransmitC and ReceiveC provide Energy, Byte, and Packet indicators.
* Tap into those to add more detection levels and granularity. Only let
* the radio turn off when we're not actively receiving bytes. Right now
* the packet indicator is a little backwards.
* > Let one component be in charge of maintaining State information about
* the power of the radio, probably lower in the stack.
* > Wire SplitControl, Send, and Receive through this component. Make it
* responsible for packet-level detections and being completely responsible
* for controlling the power of the radio without the use of upper layers
* > Remove unnecessary State components and Timers.
*
* @author David Moss
*/
module PowerCycleP {
provides {
interface PowerCycle;
interface SplitControl;
}
uses {
interface Timer<TMilli> as OnTimer;
interface SplitControl as SubControl;
interface State as RadioPowerState;
interface State as SplitControlState;
interface State as SendState;
interface Leds;
interface ReceiveIndicator as EnergyIndicator;
interface ReceiveIndicator as ByteIndicator;
interface ReceiveIndicator as PacketIndicator;
}
}
implementation {
/** The current period of the duty cycle, equivalent of wakeup interval */
uint16_t sleepInterval = 0;
/** The number of times the CCA has been sampled in this wakeup period */
uint16_t ccaChecks;
/**
* Radio Power, Check State, and Duty Cycling State
*/
enum {
S_OFF, // off by default
S_TURNING_ON,
S_ON,
S_TURNING_OFF,
};
/***************** Prototypes ****************/
task void stopRadio();
task void startRadio();
task void getCca();
bool finishSplitControlRequests();
bool isDutyCycling();
/***************** PowerCycle Commands ****************/
/**
* Set the sleep interval, in binary milliseconds
* @param sleepIntervalMs the sleep interval in [ms]
*/
command void PowerCycle.setSleepInterval(uint16_t sleepIntervalMs) {
if (!sleepInterval && sleepIntervalMs) {
// We were always on, now lets duty cycle
post stopRadio(); // Might want to delay turning off the radio
}
sleepInterval = sleepIntervalMs;
if(sleepInterval == 0 && call SplitControlState.isState(S_ON)) {
/*
* Leave the radio on permanently if sleepInterval == 0 and the radio is
* supposed to be enabled
*/
if(call RadioPowerState.getState() == S_OFF) {
call SubControl.start();
}
}
}
/**
* @return the sleep interval in [ms]
*/
command uint16_t PowerCycle.getSleepInterval() {
return sleepInterval;
}
/***************** SplitControl Commands ****************/
command error_t SplitControl.start() {
if(call SplitControlState.isState(S_ON)) {
return EALREADY;
} else if(call SplitControlState.isState(S_TURNING_ON)) {
return SUCCESS;
} else if(!call SplitControlState.isState(S_OFF)) {
return EBUSY;
}
// Radio was off, now has been told to turn on or duty cycle.
call SplitControlState.forceState(S_TURNING_ON);
if(sleepInterval > 0) {
// Begin duty cycling
post stopRadio();
return SUCCESS;
} else {
post startRadio();
return SUCCESS;
}
}
command error_t SplitControl.stop() {
if(call SplitControlState.isState(S_OFF)) {
return EALREADY;
} else if(call SplitControlState.isState(S_TURNING_OFF)) {
return SUCCESS;
} else if(!call SplitControlState.isState(S_ON)) {
return EBUSY;
}
call SplitControlState.forceState(S_TURNING_OFF);
post stopRadio();
return SUCCESS;
}
/***************** Timer Events ****************/
event void OnTimer.fired() {
if(isDutyCycling()) {
if(call RadioPowerState.getState() == S_OFF) {
ccaChecks = 0;
/*
* Turn on the radio only after the uC is fully awake. ATmega128's
* have this issue when running on an external crystal.
*/
post getCca();
} else {
// Someone else turned on the radio, try again in awhile
call OnTimer.startOneShot(sleepInterval);
}
}
}
/***************** SubControl Events ****************/
event void SubControl.startDone(error_t error) {
call RadioPowerState.forceState(S_ON);
//call Leds.led2On();
if(finishSplitControlRequests()) {
return;
} else if(isDutyCycling()) {
post getCca();
}
}
event void SubControl.stopDone(error_t error) {
call RadioPowerState.forceState(S_OFF);
//call Leds.led2Off();
if(finishSplitControlRequests()) {
return;
} else if(isDutyCycling()) {
call OnTimer.startOneShot(sleepInterval);
}
}
/***************** Tasks ****************/
task void stopRadio() {
error_t error = call SubControl.stop();
if(error != SUCCESS) {
// Already stopped?
finishSplitControlRequests();
call OnTimer.startOneShot(sleepInterval);
}
}
task void startRadio() {
if(call SubControl.start() != SUCCESS) {
post startRadio();
}
}
task void getCca() {
uint8_t detects = 0;
if(isDutyCycling()) {
ccaChecks++;
if(ccaChecks == 1) {
// Microcontroller is ready, turn on the radio and sample a few times
post startRadio();
return;
}
atomic {
for( ; ccaChecks < MAX_LPL_CCA_CHECKS && call SendState.isIdle(); ccaChecks++) {
if(call PacketIndicator.isReceiving()) {
signal PowerCycle.detected();
return;
}
if(call EnergyIndicator.isReceiving()) {
detects++;
if(detects > MIN_SAMPLES_BEFORE_DETECT) {
signal PowerCycle.detected();
return;
}
// Leave the radio on for upper layers to perform some transaction
}
}
}
if(call SendState.isIdle()) {
post stopRadio();
}
}
}
/**
* @return TRUE if the radio should be actively duty cycling
*/
bool isDutyCycling() {
return sleepInterval > 0 && call SplitControlState.isState(S_ON);
}
/**
* @return TRUE if we successfully handled a SplitControl request
*/
bool finishSplitControlRequests() {
if(call SplitControlState.isState(S_TURNING_OFF)) {
call SplitControlState.forceState(S_OFF);
signal SplitControl.stopDone(SUCCESS);
return TRUE;
} else if(call SplitControlState.isState(S_TURNING_ON)) {
// Starting while we're duty cycling first turns off the radio
call SplitControlState.forceState(S_ON);
signal SplitControl.startDone(SUCCESS);
return TRUE;
}
return FALSE;
}
/**************** Defaults ****************/
default event void PowerCycle.detected() {
}
default event void SplitControl.startDone(error_t error) {
}
default event void SplitControl.stopDone(error_t error) {
}
}
--- NEW FILE: readme.txt ---
ARCHITECTURE
=======================================================
The default LPL implementation uses a packet train with acknowledgements
enabled, shortened backoffs, and a spinning energy checking loop.
The default strategy can be improved by implementing a different architecture.
Right now the architecture looks like this:
+----------------------------------+
| DefaultLplP | -> To lower level Send
| Responsible for retransmissions | -> To lower level SplitControl
| and turning the radio off when | <- From lower level Receive
| done, or on when starting to |
| transmit |
+----------------------------------+
| PowerCycleP |
| Responsible for performing | -> To lower level SplitControl
| receive checks and leaving the |
| radio on |
+----------------------------------+
I think the architecture should be changed. If you're interested in doing work
in this area, there's lots of development and research to be done.
First, take a look at tinyos-2.x-contrib/wustl/upma. The architecture of the
CC2420 stack there is implemented to define a low-level abstraction layer
which separates radio-specific functionality from radio-independent
functionality. This is nice. By providing certain interfaces from the
radio-dependant functionality, it makes it easier to maintain MAC layer
stuff independent of the radio. And that includes LPL.
One of the things that radio stack uses is an Alarm instead of a spinning
task/while loop. Whereas the implementation here uses a static number of
loops to detect if energy is on the channel, we would be better able
to achieve the smallest radio asynchronous receive check on-time by using an
alarm. After all, the radio only has to be on to span the quiet gaps in a
transmitter's transmission, and we know approximately the duration of those
quiet gaps based on the backoff period, which the stack defines.
I recommend we redo some of the LPL architecture to look more like this:
+----------------------------------+
| DefaultLplP |
| Responsible for retransmissions |
+----------------------------------+
| | | (Send, Receive, SplitControl goes through PowerCycle)
+----------------------------------+
| PowerCycleP |
| Responsible for managing radio | -> To lower level Send
| on/off power, and telling | -> To lower level SplitControl
| PacketDetectP when to start/stop | <- From lower level Receive
| its job |
+----------------------------------+
| PacketDetectP |
| Responsible for detecting | <- EnergyIndicator
| energy, bytes, and/or packets. | <- ByteIndicator
| Notify PowerCycle when packets | <- PacketIndicator
| are detected |
+----------------------------------+
This is pretty radio independent.
OTHER LOW POWER LISTENING STRATEGIES
=============================================================
Other low power listening layers can be implemented as well:
* Continuous modulation / No Acknowledgements:
> Allows the receiver to achieve the lowest possible receive check
on time. It's shown to be several times more efficient on the receive
check than the default. This is a radio-dependent LPL strategy
and the CC2420 can acheive it by putting some transmit register into
test mode where it continually retransmits the contents of the TXFIFO.
The CRC of the packet must be uploaded into the TXFIFO because it won't
be calculated by the CC2420. Not sure if the preamble and sync bytes
need to be uploaded as well. The transmitter takes a hit because it
cannot receive acks in the middle of its packet train. But since
the receiver's energy consumption is so low, it's possible to increase
the number of receive checks in order to lower the duration of the
transmission.
> This strategy would be a good match for networks that must get data
through quickly when there is data, but doesn't see too many
transmissions in any given geographical area of the network. Also
a good strategy where your transmitters have more power.
* 802.15.4/ZigBee End Node:
> Queue up packets to Send to a particular destination until that node
checks in at some random time. Use fields in the ack frame to let the
node know that packets are available. Good match for networks where one
node has access to line power and other nodes are on batteries.
* Low throughput acknowledgement LPL:
> Just like the default, only it uses the ByteIndicator to turn off
the radio as soon as it stops receiving bytes and no packet was
received. Able to get a much shorter receive check at the expense
of decreased probability that you'll receive messages in a congested
network.
More information about the Tinyos-2-commits
mailing list