[net2-wg] Default LPL implementation
Razvan Musaloiu-E.
razvanm at cs.jhu.edu
Tue Jan 6 17:19:32 PST 2009
Hi!
I have ready an implementation of a Default LPL. A git head with it
is "default-lpl" from here:
http://hinrg.cs.jhu.edu/git/?p=razvanm/tinyos-2.x.git (web)
git://hinrg.cs.jhu.edu/git/razvanm/tinyos-2.x.git
I also attached a patch against the latest CVS tree.
Some notes:
* In tests/TestNetworkLpl there is a version of the TestNetwork that is
using the default lpl. The tweaking of the LPL is done using 3 defines:
LPL_DEF_LOCAL_SLEEP
LPL_DEF_RX_SLEEP
DELAY_AFTER_RECEIVE
In the Wyman Park Testbed (47 nodes + one on desk + a basestation) with
0.5s of sleeping and 20ms of delay after receive I got 98%-99% delivery
ratio with a 5% duty-cycle. The test was a little longer than 14h and
each SEND_INTERVAL was 60s.
* Both the basestation and clients are reporting their stats using
printf. In the TestNetworkLpl there is a tos-dump.py script that
properly displays the data from both basestation and clients.
* The stats are maintain using some global functions constucted using
some macros. The code for this is in 3 files: Globals.h, GlobalsC.nc
and GlobalsP.nc.
* The LowPowerListening interface is strip downed to only provide the
functions that provide sleepInterval values.
* The LowPowerListeningControl is not yet implemented in LPL (but it is
used by the LPP which is also almost ready).
If somebody (Om?) have time to give it a try and/or give some feedback
would be great. :-)
--
Razvan ME
-------------- next part --------------
diff --git a/apps/tests/TestNetwork/TestNetworkC.nc b/apps/tests/TestNetwork/TestNetworkC.nc
index 28e248f..cb46243 100644
--- a/apps/tests/TestNetwork/TestNetworkC.nc
+++ b/apps/tests/TestNetwork/TestNetworkC.nc
@@ -49,7 +49,8 @@ implementation {
bool firstTimer = TRUE;
uint16_t seqno;
enum {
- SEND_INTERVAL = 8192
+// SEND_INTERVAL = 8192
+ SEND_INTERVAL = 60*1024U
};
event void ReadSensor.readDone(error_t err, uint16_t val) { }
@@ -113,10 +114,10 @@ implementation {
event void Timer.fired() {
- uint16_t nextInt;
+ uint32_t nextInt;
call Leds.led0Toggle();
dbg("TestNetworkC", "TestNetworkC: Timer fired.\n");
- nextInt = call Random.rand16() % SEND_INTERVAL;
+ nextInt = call Random.rand32() % SEND_INTERVAL;
nextInt += SEND_INTERVAL >> 1;
call Timer.startOneShot(nextInt);
if (!sendBusy)
diff --git a/apps/tests/TestNetworkLpl/CtpP.nc b/apps/tests/TestNetworkLpl/CtpP.nc
new file mode 100644
index 0000000..add5412
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/CtpP.nc
@@ -0,0 +1,208 @@
+/*
+ * "Copyright (c) 2005 The Regents of the University of California.
+ * 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 UNIVERSITY OF CALIFORNIA 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 UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA 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 UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * Copyright (c) 2006 Stanford University.
+ * 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 Stanford University 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 STANFORD
+ * UNIVERSITY 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.
+ */
+
+#include "Ctp.h"
+
+/**
+ * A data collection service that uses a tree routing protocol
+ * to deliver data to collection roots, following TEP 119.
+ *
+ * @author Rodrigo Fonseca
+ * @author Omprakash Gnawali
+ * @author Kyle Jamieson
+ * @author Philip Levis
+ */
+
+
+configuration CtpP {
+ provides {
+ interface StdControl;
+ interface Send[uint8_t client];
+ interface Receive[collection_id_t id];
+ interface Receive as Snoop[collection_id_t];
+ interface Intercept[collection_id_t id];
+
+ interface Packet;
+ interface CollectionPacket;
+ interface CtpPacket;
+
+ interface CtpInfo;
+ interface LinkEstimator;
+ interface CtpCongestion;
+ interface RootControl;
+ }
+
+ uses {
+ interface CollectionId[uint8_t client];
+ interface CollectionDebug;
+ }
+}
+
+implementation {
+ enum {
+ CLIENT_COUNT = uniqueCount(UQ_CTP_CLIENT),
+ FORWARD_COUNT = 12,
+ TREE_ROUTING_TABLE_SIZE = 10,
+ QUEUE_SIZE = CLIENT_COUNT + FORWARD_COUNT,
+ CACHE_SIZE = 4,
+ };
+
+ components ActiveMessageC;
+ components new CtpForwardingEngineP() as Forwarder;
+ components MainC, LedsC;
+
+ Send = Forwarder;
+ StdControl = Forwarder;
+ Receive = Forwarder.Receive;
+ Snoop = Forwarder.Snoop;
+ Intercept = Forwarder;
+ Packet = Forwarder;
+ CollectionId = Forwarder;
+ CollectionPacket = Forwarder;
+ CtpPacket = Forwarder;
+ CtpCongestion = Forwarder;
+
+ components new PoolC(message_t, FORWARD_COUNT) as MessagePoolP;
+ components new PoolC(fe_queue_entry_t, FORWARD_COUNT) as QEntryPoolP;
+ Forwarder.QEntryPool -> QEntryPoolP;
+ Forwarder.MessagePool -> MessagePoolP;
+
+ components new QueueC(fe_queue_entry_t*, QUEUE_SIZE) as SendQueueP;
+ Forwarder.SendQueue -> SendQueueP;
+
+ components new LruCtpMsgCacheC(CACHE_SIZE) as SentCacheP;
+ Forwarder.SentCache -> SentCacheP;
+
+ components new TimerMilliC() as RoutingBeaconTimer;
+ components new TimerMilliC() as RouteUpdateTimer;
+ components LinkEstimatorP as Estimator;
+ Forwarder.LinkEstimator -> Estimator;
+
+ components new LplAMSenderC(AM_CTP_DATA) as AMSenderC;
+ components new AMReceiverC(AM_CTP_DATA);
+ components new AMSnooperC(AM_CTP_DATA);
+
+ components new CtpRoutingEngineP(TREE_ROUTING_TABLE_SIZE, 128, 512000) as Router;
+
+ StdControl = Router;
+ StdControl = Estimator;
+ RootControl = Router;
+ MainC.SoftwareInit -> Router;
+ Router.BeaconSend -> Estimator.Send;
+ Router.BeaconReceive -> Estimator.Receive;
+ Router.LinkEstimator -> Estimator.LinkEstimator;
+
+ Router.CompareBit -> Estimator.CompareBit;
+
+ Router.AMPacket -> ActiveMessageC;
+ Router.RadioControl -> ActiveMessageC;
+ Router.BeaconTimer -> RoutingBeaconTimer;
+ Router.RouteTimer -> RouteUpdateTimer;
+ Router.CollectionDebug = CollectionDebug;
+ Forwarder.CollectionDebug = CollectionDebug;
+ Forwarder.CtpInfo -> Router;
+ Router.CtpCongestion -> Forwarder;
+ CtpInfo = Router;
+
+
+ components new TimerMilliC() as RetxmitTimer;
+ Forwarder.RetxmitTimer -> RetxmitTimer;
+
+ components RandomC;
+ Router.Random -> RandomC;
+ Forwarder.Random -> RandomC;
+
+ MainC.SoftwareInit -> Forwarder;
+ Forwarder.SubSend -> AMSenderC;
+ Forwarder.SubReceive -> AMReceiverC;
+ Forwarder.SubSnoop -> AMSnooperC;
+ Forwarder.SubPacket -> AMSenderC;
+ Forwarder.RootControl -> Router;
+ Forwarder.UnicastNameFreeRouting -> Router.Routing;
+ Forwarder.RadioControl -> ActiveMessageC;
+ Forwarder.PacketAcknowledgements -> AMSenderC.Acks;
+ Forwarder.AMPacket -> AMSenderC;
+ Forwarder.Leds -> LedsC;
+
+ components new LplAMSenderC(AM_CTP_ROUTING) as SendControl;
+ components new AMReceiverC(AM_CTP_ROUTING) as ReceiveControl;
+
+ LinkEstimator = Estimator;
+
+ Estimator.Random -> RandomC;
+
+ Estimator.AMSend -> SendControl;
+ Estimator.SubReceive -> ReceiveControl;
+ Estimator.SubPacket -> SendControl;
+ Estimator.SubAMPacket -> SendControl;
+
+#if defined(PLATFORM_TELOSB) || defined(PLATFORM_MICAZ)
+#ifndef TOSSIM
+ components CC2420ActiveMessageC as PlatformActiveMessageC;
+#else
+ components DummyActiveMessageP as PlatformActiveMessageC;
+#endif
+#elif defined (PLATFORM_MICA2) || defined (PLATFORM_MICA2DOT)
+ components CC1000ActiveMessageC as PlatformActiveMessageC;
+#elif defined(PLATFORM_EYESIFXV1) || defined(PLATFORM_EYESIFXV2)
+ components WhiteBitAccessorC as PlatformActiveMessageC;
+#else
+ components DummyActiveMessageP as PlatformActiveMessageC;
+#endif
+
+ Estimator.LinkPacketMetadata -> PlatformActiveMessageC;
+
+ // eventually
+ // Estimator.LinkPacketMetadata -> ActiveMessageC;
+
+ MainC.SoftwareInit -> Estimator;
+}
diff --git a/apps/tests/TestNetworkLpl/DefaultLplP.nc b/apps/tests/TestNetworkLpl/DefaultLplP.nc
new file mode 100644
index 0000000..cc92737
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/DefaultLplP.nc
@@ -0,0 +1,423 @@
+/*
+ * 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"
+#include "Globals.h"
+
+module DefaultLplP {
+ provides {
+ interface Init;
+ interface LowPowerListening;
+ interface Send;
+ interface Receive;
+ }
+
+ uses {
+ interface Send as SubSend;
+ interface CC2420Transmit as Resend;
+ interface RadioBackoff;
+ 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 Power State
+ */
+ enum {
+ S_OFF, // off by default
+ S_TURNING_ON,
+ S_ON,
+ S_TURNING_OFF,
+ };
+
+ /**
+ * 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();
+ }
+
+ /**
+ * 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;
+ }
+
+ /***************** 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 EBUSY;
+ }
+
+ 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, uint8_t len) {
+ return call SubSend.getPayload(msg, len);
+ }
+
+
+ /***************** RadioBackoff Events ****************/
+ async event void RadioBackoff.requestInitialBackoff(message_t *msg) {
+ if((call CC2420PacketBody.getMetadata(msg))->rxInterval
+ > ONE_MESSAGE) {
+ call RadioBackoff.setInitialBackoff( call Random.rand16()
+ % (0x4 * CC2420_BACKOFF_PERIOD) + CC2420_MIN_BACKOFF);
+ }
+ }
+
+ async event void RadioBackoff.requestCongestionBackoff(message_t *msg) {
+ if((call CC2420PacketBody.getMetadata(msg))->rxInterval
+ > ONE_MESSAGE) {
+ call RadioBackoff.setCongestionBackoff( call Random.rand16()
+ % (0x3 * CC2420_BACKOFF_PERIOD) + CC2420_MIN_BACKOFF);
+ }
+ }
+
+ async event void RadioBackoff.requestCca(message_t *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.
+
+ startOffTimer();
+ }
+
+
+ /***************** SubControl Events ***************/
+ event void SubControl.startDone(error_t error) {
+ if(!error) {
+ setRadioOnStart(getLocalTime());
+ 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) {
+ addRadioOn(getLocalTime() - getRadioOnStart());
+ 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) {
+ incRecvPackets();
+ 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_OFF
+ && 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() {
+ incSentPackets();
+ if(call SubSend.send(currentSendMsg, currentSendLen) != SUCCESS) {
+ post send();
+ }
+ }
+
+ task void resend() {
+ incSentPackets();
+ 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);
+ }
+
+}
+
diff --git a/apps/tests/TestNetworkLpl/Globals.h b/apps/tests/TestNetworkLpl/Globals.h
new file mode 100644
index 0000000..b6352d8
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/Globals.h
@@ -0,0 +1,41 @@
+#ifndef GLOBALS_H
+#define GLOBALS_H
+
+nx_struct Globals {
+ nx_uint32_t RadioOn;
+ nx_uint32_t RadioOnStart;
+ nx_uint32_t Wakeups;
+ nx_uint32_t CcaChecks;
+ nx_uint32_t SentPackets;
+ nx_uint32_t RecvPackets;
+};
+
+ nx_struct Globals __g;
+
+ uint16_t getGlobalsSize() { return sizeof(__g); }
+ void *getGlobals() { return (void*)&__g; }
+ uint32_t getLocalTime();
+
+#define GLOBALS_GET(name) typeof(__g.name) get##name() { return __g.name; }
+#define GLOBALS_SET(name) void set##name(typeof(__g.name) val) { __g.name = val; }
+#define GLOBALS_INC(name) void inc##name() { __g.name++; }
+#define GLOBALS_ADD(name) void add##name(typeof(__g.name) val) { __g.name += val; }
+
+ GLOBALS_GET(RadioOn);
+ GLOBALS_ADD(RadioOn);
+
+ GLOBALS_GET(RadioOnStart);
+ GLOBALS_SET(RadioOnStart);
+
+ GLOBALS_GET(Wakeups);
+ GLOBALS_INC(Wakeups);
+
+ GLOBALS_GET(CcaChecks);
+ GLOBALS_INC(CcaChecks);
+
+ GLOBALS_GET(SentPackets);
+ GLOBALS_INC(SentPackets);
+
+ GLOBALS_GET(RecvPackets);
+ GLOBALS_INC(RecvPackets);
+#endif
diff --git a/apps/tests/TestNetworkLpl/GlobalsC.nc b/apps/tests/TestNetworkLpl/GlobalsC.nc
new file mode 100644
index 0000000..911ec22
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/GlobalsC.nc
@@ -0,0 +1,13 @@
+configuration GlobalsC { }
+
+implementation
+{
+ components GlobalsP;
+ components new CounterToLocalTimeC(T32khz);
+ components new TransformCounterC(T32khz, uint32_t, T32khz, uint16_t, 0, uint32_t) as Transform;
+ components Msp430Counter32khzC;
+
+ CounterToLocalTimeC.Counter -> Transform;
+ Transform.CounterFrom -> Msp430Counter32khzC;
+ GlobalsP.LocalTime -> CounterToLocalTimeC;
+}
diff --git a/apps/tests/TestNetworkLpl/GlobalsP.nc b/apps/tests/TestNetworkLpl/GlobalsP.nc
new file mode 100644
index 0000000..1512175
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/GlobalsP.nc
@@ -0,0 +1,11 @@
+#include "Globals.h"
+
+module GlobalsP
+{
+ uses interface LocalTime<T32khz> as LocalTime;
+}
+
+implementation
+{
+ uint32_t getLocalTime() @C() { return call LocalTime.get(); }
+}
diff --git a/apps/tests/TestNetworkLpl/GlobalsPrintfC.nc b/apps/tests/TestNetworkLpl/GlobalsPrintfC.nc
new file mode 100644
index 0000000..e39f75d
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/GlobalsPrintfC.nc
@@ -0,0 +1,12 @@
+configuration GlobalsPrintfC { }
+
+implementation
+{
+ components GlobalsPrintfP;
+ components new TimerMilliC();
+ components MainC, LedsC, NoLedsC;
+
+ GlobalsPrintfP.Boot -> MainC;
+ GlobalsPrintfP.Timer -> TimerMilliC;
+ GlobalsPrintfP.Leds -> NoLedsC;
+}
diff --git a/apps/tests/TestNetworkLpl/GlobalsPrintfP.nc b/apps/tests/TestNetworkLpl/GlobalsPrintfP.nc
new file mode 100644
index 0000000..88333c0
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/GlobalsPrintfP.nc
@@ -0,0 +1,30 @@
+module GlobalsPrintfP
+{
+ uses {
+ interface Boot;
+ interface Timer<TMilli>;
+ interface Leds;
+ }
+}
+
+implementation
+{
+ event void Boot.booted()
+ {
+ call Timer.startPeriodic(1024);
+ call Leds.led2On();
+ }
+
+ event void Timer.fired()
+ {
+#ifdef LOW_POWER_LISTENING
+ call Leds.led2Toggle();
+ printf("g: %ld r %ld w %ld c %ld tx %ld rx %ld\n", getLocalTime(), getRadioOn(), getWakeups(), getCcaChecks(), getSentPackets(), getRecvPackets());
+ printfflush();
+#elif LOW_POWER_PROBING
+ call Leds.led2Toggle();
+ printf("g: %ld r %ld w %ld tx %ld rx %ld\n", getLocalTime(), getRadioOn(), getWakeups(), getSentPackets(), getRecvPackets());
+ printfflush();
+#endif
+ }
+}
diff --git a/apps/tests/TestNetworkLpl/Makefile b/apps/tests/TestNetworkLpl/Makefile
new file mode 100644
index 0000000..171df63
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/Makefile
@@ -0,0 +1,82 @@
+COMPONENT=TestNetworkAppC
+
+CFLAGS += -DLOW_POWER_LISTENING
+CFLAGS += -DLPL_DEF_LOCAL_SLEEP=512
+CFLAGS += -DLPL_DEF_RX_SLEEP=512
+CFLAGS += -DDELAY_AFTER_RECEIVE=20
+
+#CFLAGS += -I$(TOSDIR)/lib/lpp
+#CFLAGS += -DLOW_POWER_PROBING
+#CFLAGS += -DLPL_DEF_LOCAL_SLEEP=2048
+#CFLAGS += -DLPL_DEF_RX_SLEEP=2048
+#CFLAGS += -DDELAY_AFTER_RECEIVE=100
+
+CFLAGS += -DCC2420_DEF_CHANNEL=12
+CFLAGS += -I.
+CFLAGS += -I$(TOSDIR)/lib/printf
+CFLAGS += -I../TestNetwork
+CFLAGS += -DTOSH_DATA_LENGTH=114
+CFLAGS += -DPRINTF_MSG_LENGTH=70
+
+CFLAGS += -I$(TOSDIR)/lib/net \
+ -I$(TOSDIR)/lib/net/drip \
+ -I$(TOSDIR)/lib/net/4bitle \
+ -I$(TOSDIR)/lib/net/ctp -DNO_DEBUG
+
+TFLAGS += -I$(TOSDIR)/../apps/tests/TestDissemination \
+ -I$(TOSDIR)/../support/sdk/c \
+ -I$(TOSDIR)/types \
+ -I.
+
+LIBMOTE = $(TOSDIR)/../support/sdk/c/libmote.a
+#BUILD_EXTRA_DEPS += tn-injector #tn-listener
+LISTEN_OBJS = collection_msg.o test_network_msg.o tn-listener.o $(LIBMOTE)
+INJECT_OBJS = set_rate_msg.o tn-injector.o collection_debug_msg.o $(LIBMOTE)
+
+# arguments: output filename stem, input filename, struct name
+define mig_templ
+MIGFILES += $(1).c $(1).h $(1).java $(1).o
+$(1).c:
+ mig -o $(1).h c -target=$$(PLATFORM) $$(CFLAGS) $$(TFLAGS) $(2) $(3)
+$(1).java:
+ mig -o $(1).java java -target=$$(PLATFORM) $$(CFLAGS) $$(TFLAGS) $(2) $(3)
+endef
+
+$(eval $(call mig_templ,test_network_msg,TestNetwork.h,TestNetworkMsg))
+$(eval $(call mig_templ,set_rate_msg,$(TOSDIR)/lib/net/DisseminationEngine.h,dissemination_message))
+$(eval $(call mig_templ,collection_debug_msg,$(TOSDIR)/lib/net/collection/CollectionDebugMsg.h,CollectionDebugMsg))
+
+%.o: %.c
+ gcc -v $(TFLAGS) $(CFLAGS) -c -o $@ $<
+
+tn-listener: $(LISTEN_OBJS)
+ gcc -v $(TFLAGS) $(CFLAGS) -o $@ $(LISTEN_OBJS)
+
+tn-injector: $(INJECT_OBJS)
+ gcc -v $(TFLAGS) $(CFLAGS) -o $@ $(INJECT_OBJS)
+
+#tn-listener.o: tn-listener.c
+# gcc $(TFLAGS) $(CFLAGS) -c -o $@ $<
+
+tn-injector.o: tn-injector.c test_network_msg.c
+ gcc $(TFLAGS) $(CFLAGS) -c -o $@ $<
+
+#test_network_msg.c:
+# mig -o test_network_msg.h c -target=$(PLATFORM) $(CFLAGS) $(TFLAGS) TestNetwork.h TestNetworkMsg
+
+#set_rate_msg.c:
+# mig -o set_rate_msg.h c -target=$(PLATFORM) $(CFLAGS) $(TFLAGS) $(TOSDIR)/lib/net/DisseminationEngine.h dissemination_message
+
+#set_rate_msg.o: set_rate_msg.c
+# gcc $(CFLAGS) $(TFLAGS) -c -o $@ $<
+
+#test_network_msg.o: test_network_msg.c
+# gcc $(CFLAGS) $(TFLAGS) -c -o $@ $<
+
+#collection_msg.c:
+# mig -o collection_msg.h c -target=$(PLATFORM) $(CFLAGS) $(TFLAGS) $(TOSDIR)/lib/net/collection/ForwardingEngine.h collection_header
+
+include $(MAKERULES)
+
+migclean:
+ rm -rf $(MIGFILES)
diff --git a/apps/tests/TestNetworkLpl/PowerCycleP.nc b/apps/tests/TestNetworkLpl/PowerCycleP.nc
new file mode 100644
index 0000000..bb376dd
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/PowerCycleP.nc
@@ -0,0 +1,317 @@
+/*
+ * 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
+ */
+
+#include "DefaultLpl.h"
+#include "Globals.h"
+
+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 = LPL_DEF_LOCAL_SLEEP;
+
+ /** 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);
+
+ printf("start: sleepInterval %d\n", sleepInterval);
+ 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()) {
+ incWakeups();
+ 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++) {
+ incCcaChecks();
+ 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) {
+ }
+}
+
+
diff --git a/apps/tests/TestNetworkLpl/TestNetworkAppC.nc b/apps/tests/TestNetworkLpl/TestNetworkAppC.nc
new file mode 100644
index 0000000..cac615b
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/TestNetworkAppC.nc
@@ -0,0 +1,71 @@
+/**
+ * TestNetworkC exercises the basic networking layers, collection and
+ * dissemination. The application samples DemoSensorC at a basic rate
+ * and sends packets up a collection tree. The rate is configurable
+ * through dissemination.
+ *
+ * See TEP118: Dissemination, TEP 119: Collection, and TEP 123: The
+ * Collection Tree Protocol for details.
+ *
+ * @author Philip Levis
+ * @version $Revision$ $Date$
+ */
+#include "TestNetwork.h"
+#include "Ctp.h"
+
+configuration TestNetworkAppC {}
+implementation {
+ components TestNetworkC, MainC, LedsC, ActiveMessageC;
+ components DisseminationC;
+ components new DisseminatorC(uint16_t, SAMPLE_RATE_KEY) as Object16C;
+ components CollectionC as Collector;
+ components new CollectionSenderC(CL_TEST);
+ components new TimerMilliC();
+ components new DemoSensorC();
+ components new SerialAMSenderC(CL_TEST);
+ components SerialActiveMessageC;
+#ifndef NO_DEBUG
+ components new SerialAMSenderC(AM_COLLECTION_DEBUG) as UARTSender;
+ components UARTDebugSenderP as DebugSender;
+#endif
+ components RandomC;
+ components new QueueC(message_t*, 12);
+ components new PoolC(message_t, 12);
+
+ TestNetworkC.Boot -> MainC;
+ TestNetworkC.RadioControl -> ActiveMessageC;
+ TestNetworkC.SerialControl -> SerialActiveMessageC;
+ TestNetworkC.RoutingControl -> Collector;
+ TestNetworkC.DisseminationControl -> DisseminationC;
+ TestNetworkC.Leds -> LedsC;
+ TestNetworkC.Timer -> TimerMilliC;
+ TestNetworkC.DisseminationPeriod -> Object16C;
+ TestNetworkC.Send -> CollectionSenderC;
+ TestNetworkC.ReadSensor -> DemoSensorC;
+ TestNetworkC.RootControl -> Collector;
+ TestNetworkC.Receive -> Collector.Receive[CL_TEST];
+ TestNetworkC.UARTSend -> SerialAMSenderC.AMSend;
+ TestNetworkC.CollectionPacket -> Collector;
+ TestNetworkC.CtpInfo -> Collector;
+ TestNetworkC.CtpCongestion -> Collector;
+ TestNetworkC.Random -> RandomC;
+ TestNetworkC.Pool -> PoolC;
+ TestNetworkC.Queue -> QueueC;
+ TestNetworkC.RadioPacket -> ActiveMessageC;
+ TestNetworkC.Lpl -> ActiveMessageC;
+
+#ifndef NO_DEBUG
+ components new PoolC(message_t, 10) as DebugMessagePool;
+ components new QueueC(message_t*, 10) as DebugSendQueue;
+ DebugSender.Boot -> MainC;
+ DebugSender.UARTSend -> UARTSender;
+ DebugSender.MessagePool -> DebugMessagePool;
+ DebugSender.SendQueue -> DebugSendQueue;
+ Collector.CollectionDebug -> DebugSender;
+ TestNetworkC.CollectionDebug -> DebugSender;
+#endif
+ TestNetworkC.AMPacket -> ActiveMessageC;
+
+ components GlobalsC;
+ components GlobalsPrintfC;
+}
diff --git a/apps/tests/TestNetworkLpl/TestNetworkC.nc b/apps/tests/TestNetworkLpl/TestNetworkC.nc
new file mode 100644
index 0000000..6bb407e
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/TestNetworkC.nc
@@ -0,0 +1,214 @@
+/**
+ * TestNetworkC exercises the basic networking layers, collection and
+ * dissemination. The application samples DemoSensorC at a basic rate
+ * and sends packets up a collection tree. The rate is configurable
+ * through dissemination. The default send rate is every 10s.
+ *
+ * See TEP118: Dissemination and TEP 119: Collection for details.
+ *
+ * @author Philip Levis
+ * @version $Revision$ $Date$
+ */
+
+#include <Timer.h>
+#include "TestNetwork.h"
+#include "CtpDebugMsg.h"
+
+module TestNetworkC {
+ uses interface Boot;
+ uses interface SplitControl as RadioControl;
+ uses interface SplitControl as SerialControl;
+ uses interface StdControl as RoutingControl;
+ uses interface StdControl as DisseminationControl;
+ uses interface DisseminationValue<uint16_t> as DisseminationPeriod;
+ uses interface Send;
+ uses interface Leds;
+ uses interface Read<uint16_t> as ReadSensor;
+ uses interface Timer<TMilli>;
+ uses interface RootControl;
+ uses interface Receive;
+ uses interface AMSend as UARTSend;
+ uses interface CollectionPacket;
+ uses interface CtpInfo;
+ uses interface CtpCongestion;
+ uses interface Random;
+ uses interface Queue<message_t*>;
+ uses interface Pool<message_t>;
+ uses interface CollectionDebug;
+ uses interface AMPacket;
+ uses interface Packet as RadioPacket;
+ uses interface LowPowerListening as Lpl;
+}
+implementation {
+ task void uartEchoTask();
+ message_t packet;
+ message_t uartpacket;
+ message_t* recvPtr = &uartpacket;
+ uint8_t msglen;
+ bool sendBusy = FALSE;
+ bool uartbusy = FALSE;
+ bool firstTimer = TRUE;
+ uint16_t seqno;
+ enum {
+ SEND_INTERVAL = 60*1024U
+ };
+
+ event void ReadSensor.readDone(error_t err, uint16_t val) { }
+
+ event void Boot.booted() {
+ call SerialControl.start();
+ }
+ event void SerialControl.startDone(error_t err) {
+ if (TOS_NODE_ID % 500 == 0) {
+ call Lpl.setLocalSleepInterval(0);
+ }
+ call RadioControl.start();
+ }
+ event void RadioControl.startDone(error_t err) {
+ if (err != SUCCESS) {
+ call RadioControl.start();
+ }
+ else {
+ //call DisseminationControl.start();
+ call RoutingControl.start();
+ if (TOS_NODE_ID % 500 == 0) {
+ call RootControl.setRoot();
+ }
+ seqno = 0;
+ call Timer.startOneShot(call Random.rand32() % SEND_INTERVAL);
+ }
+ }
+
+ event void RadioControl.stopDone(error_t err) {}
+ event void SerialControl.stopDone(error_t err) {}
+
+ void failedSend() {
+ dbg("App", "%s: Send failed.\n", __FUNCTION__);
+ call CollectionDebug.logEvent(NET_C_DBG_1);
+ }
+
+
+ void sendMessage() {
+ TestNetworkMsg* msg = (TestNetworkMsg*)call Send.getPayload(&packet, sizeof(TestNetworkMsg));
+ uint16_t metric;
+ am_addr_t parent;
+
+ call CtpInfo.getParent(&parent);
+ call CtpInfo.getEtx(&metric);
+
+ msg->source = TOS_NODE_ID;
+ msg->seqno = seqno;
+ msg->data = 0xCAFE;
+ msg->parent = parent;
+ msg->hopcount = 0;
+ msg->metric = metric;
+
+ if (call Send.send(&packet, sizeof(TestNetworkMsg)) != SUCCESS) {
+ failedSend();
+ call Leds.led0On();
+ dbg("TestNetworkC", "%s: Transmission failed.\n", __FUNCTION__);
+ }
+ else {
+ sendBusy = TRUE;
+ seqno++;
+ dbg("TestNetworkC", "%s: Transmission succeeded.\n", __FUNCTION__);
+ }
+ }
+
+
+ event void Timer.fired() {
+ uint32_t nextInt;
+ call Leds.led0Toggle();
+ dbg("TestNetworkC", "TestNetworkC: Timer fired.\n");
+ nextInt = call Random.rand32() % SEND_INTERVAL;
+ nextInt += SEND_INTERVAL >> 1;
+ call Timer.startOneShot(nextInt);
+ if (!sendBusy)
+ sendMessage();
+ }
+
+ event void Send.sendDone(message_t* m, error_t err) {
+ if (err != SUCCESS) {
+ // call Leds.led0On();
+ }
+ sendBusy = FALSE;
+ dbg("TestNetworkC", "Send completed.\n");
+ }
+
+ event void DisseminationPeriod.changed() {
+ const uint16_t* newVal = call DisseminationPeriod.get();
+ call Timer.stop();
+ call Timer.startPeriodic(*newVal);
+ }
+
+ event message_t*
+ Receive.receive(message_t* msg, void* payload, uint8_t len) {
+ dbg("TestNetworkC", "Received packet at %s from node %hhu.\n", sim_time_string(), call CollectionPacket.getOrigin(msg));
+ call Leds.led1Toggle();
+ if (!call Pool.size() <= (TEST_NETWORK_QUEUE_SIZE < 4)? 1:3) {
+ // call CtpCongestion.setClientCongested(TRUE);
+ }
+ if (!call Pool.empty() && call Queue.size() < call Queue.maxSize()) {
+ message_t* tmp = call Pool.get();
+ call Queue.enqueue(msg);
+ if (!uartbusy) {
+ post uartEchoTask();
+ }
+ return tmp;
+ }
+ return msg;
+ }
+
+ task void uartEchoTask() {
+ dbg("Traffic", "Sending packet to UART.\n");
+ if (call Queue.empty()) {
+ return;
+ }
+ else if (!uartbusy) {
+ message_t* msg = call Queue.dequeue();
+ dbg("Traffic", "Sending packet to UART.\n");
+ if (call UARTSend.send(0xffff, msg, call RadioPacket.payloadLength(msg)) == SUCCESS) {
+ uartbusy = TRUE;
+ }
+ else {
+ call CollectionDebug.logEventMsg(NET_C_DBG_2,
+ call CollectionPacket.getSequenceNumber(msg),
+ call CollectionPacket.getOrigin(msg),
+ call AMPacket.destination(msg));
+ }
+ }
+ }
+
+ event void UARTSend.sendDone(message_t *msg, error_t error) {
+ dbg("Traffic", "UART send done.\n");
+ uartbusy = FALSE;
+ call Pool.put(msg);
+ if (!call Queue.empty()) {
+ post uartEchoTask();
+ }
+ else {
+ // call CtpCongestion.setClientCongested(FALSE);
+ }
+ }
+
+ /* Default implementations for CollectionDebug calls.
+ * These allow CollectionDebug not to be wired to anything if debugging
+ * is not desired. */
+
+ default command error_t CollectionDebug.logEvent(uint8_t type) {
+ return SUCCESS;
+ }
+ default command error_t CollectionDebug.logEventSimple(uint8_t type, uint16_t arg) {
+ return SUCCESS;
+ }
+ default command error_t CollectionDebug.logEventDbg(uint8_t type, uint16_t arg1, uint16_t arg2, uint16_t arg3) {
+ return SUCCESS;
+ }
+ default command error_t CollectionDebug.logEventMsg(uint8_t type, uint16_t msg, am_addr_t origin, am_addr_t node) {
+ return SUCCESS;
+ }
+ default command error_t CollectionDebug.logEventRoute(uint8_t type, am_addr_t parent, uint8_t hopcount, uint16_t metric) {
+ return SUCCESS;
+ }
+
+}
diff --git a/apps/tests/TestNetworkLpl/tos-dump.py b/apps/tests/TestNetworkLpl/tos-dump.py
new file mode 100755
index 0000000..6fdef40
--- /dev/null
+++ b/apps/tests/TestNetworkLpl/tos-dump.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+import sys, time
+import tos
+
+class Test(tos.Packet):
+ def __init__(self, payload = None):
+ tos.Packet.__init__(self,
+ [('source', 'int', 2),
+ ('seqno', 'int', 2),
+ ('parent', 'int', 2),
+ ('metric', 'int', 2),
+ ('data', 'int', 2),
+ ('hopcount', 'int', 1),
+ ('sendCount','int', 2),
+ ('sendSuccessCount','int', 2)],
+ payload)
+
+class CtpData(tos.Packet):
+ def __init__(self, payload = None):
+ tos.Packet.__init__(self,
+ [('options', 'int', 1),
+ ('thl', 'int', 1),
+ ('etx', 'int', 2),
+ ('origin', 'int', 2),
+ ('originSeqNo', 'int', 1),
+ ('collectionId','int', 1),
+ ('data', 'blob', None)],
+ payload)
+
+if len(sys.argv) < 2:
+ print "Usage:", sys.argv[0], "serial@/dev/ttyUSB0:57600"
+ sys.exit()
+
+#s = tos.Serial(sys.argv[1], int(sys.argv[2]), debug=False)
+am = tos.AM()
+
+while True:
+ p = am.read()
+ if p:
+ if p.type == 238:
+ ts = "%.4f" % time.time()
+ ctp = CtpData(p.data)
+ test = Test(ctp.data)
+ print ts, '\t', ctp
+ print ts, '\t', test
+ else:
+ print p
+
diff --git a/support/sdk/python/tos.py b/support/sdk/python/tos.py
index 83c08ad..280d1ce 100644
--- a/support/sdk/python/tos.py
+++ b/support/sdk/python/tos.py
@@ -406,8 +406,9 @@ def printfHook(packet):
if packet.type == 100:
s = "".join([chr(i) for i in packet.data]).strip('\0')
lines = s.split('\n')
+ ts = time.time()
for line in lines:
- if line: print "PRINTF:", line
+ if line: print "%.4f PRINTF: %s" % (ts, line)
packet = None # No further processing for the printf packet
return packet
diff --git a/tos/chips/cc2420/CC2420.h b/tos/chips/cc2420/CC2420.h
index 798107f..4beba0b 100644
--- a/tos/chips/cc2420/CC2420.h
+++ b/tos/chips/cc2420/CC2420.h
@@ -166,6 +166,17 @@ typedef nx_struct cc2420_packet_t {
#endif
+/**
+ * The LPL defaults to stay-on.
+ */
+#ifndef LPL_DEF_LOCAL_SLEEP
+#define LPL_DEF_LOCAL_SLEEP 0
+#endif
+
+#ifndef LPL_DEF_RX_SLEEP
+#define LPL_DEF_RX_SLEEP 0
+#endif
+
enum {
// size of the header not including the length byte
MAC_HEADER_SIZE = sizeof( cc2420_header_t ) - 1,
diff --git a/tos/chips/cc2420/lowpan/CC2420TinyosNetworkP.nc b/tos/chips/cc2420/lowpan/CC2420TinyosNetworkP.nc
index e490f37..00c9db6 100644
--- a/tos/chips/cc2420/lowpan/CC2420TinyosNetworkP.nc
+++ b/tos/chips/cc2420/lowpan/CC2420TinyosNetworkP.nc
@@ -39,6 +39,7 @@
*/
#include "CC2420.h"
+#include "Globals.h"
module CC2420TinyosNetworkP @safe() {
provides {
@@ -77,11 +78,13 @@ implementation {
/***************** SubSend Events *****************/
event void SubSend.sendDone(message_t* msg, error_t error) {
+ incSentPackets();
signal Send.sendDone(msg, error);
}
/***************** SubReceive Events ***************/
event message_t *SubReceive.receive(message_t *msg, void *payload, uint8_t len) {
+ incRecvPackets();
if((call CC2420PacketBody.getHeader(msg))->network == TINYOS_6LOWPAN_NETWORK_ID) {
return signal Receive.receive(msg, payload, len);
diff --git a/tos/chips/cc2420/lpl/DefaultLplP.nc b/tos/chips/cc2420/lpl/DefaultLplP.nc
index 3ada9db..bb99ebd 100644
--- a/tos/chips/cc2420/lpl/DefaultLplP.nc
+++ b/tos/chips/cc2420/lpl/DefaultLplP.nc
@@ -112,7 +112,6 @@ implementation {
void initializeSend();
void startOffTimer();
- uint16_t getActualDutyCycle(uint16_t dutyCycle);
/***************** Init Commands ***************/
command error_t Init.init() {
@@ -144,36 +143,6 @@ implementation {
}
/**
- * 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
@@ -191,65 +160,6 @@ implementation {
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 ((uint32_t)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(((uint32_t)DUTY_ON_TIME * 10000)
- / (sleepInterval + DUTY_ON_TIME));
- }
-
-
/***************** Send Commands ***************/
/**
* Each call to this send command gives the message a single
@@ -503,18 +413,5 @@ implementation {
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;
- }
}
diff --git a/tos/chips/cc2420/lpl/DummyLplP.nc b/tos/chips/cc2420/lpl/DummyLplP.nc
index dbc6bb5..defce61 100644
--- a/tos/chips/cc2420/lpl/DummyLplP.nc
+++ b/tos/chips/cc2420/lpl/DummyLplP.nc
@@ -51,13 +51,6 @@ implementation {
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) {
}
@@ -65,20 +58,5 @@ implementation {
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;
- }
-
}
diff --git a/tos/chips/cc2420/lpl/PowerCycleP.nc b/tos/chips/cc2420/lpl/PowerCycleP.nc
index 3409924..f86c7b5 100644
--- a/tos/chips/cc2420/lpl/PowerCycleP.nc
+++ b/tos/chips/cc2420/lpl/PowerCycleP.nc
@@ -75,7 +75,7 @@ module PowerCycleP {
implementation {
/** The current period of the duty cycle, equivalent of wakeup interval */
- uint16_t sleepInterval = 0;
+ uint16_t sleepInterval = LPL_DEF_LOCAL_SLEEP;
/** The number of times the CCA has been sampled in this wakeup period */
uint16_t ccaChecks;
@@ -106,6 +106,7 @@ implementation {
* @param sleepIntervalMs the sleep interval in [ms]
*/
command void PowerCycle.setSleepInterval(uint16_t sleepIntervalMs) {
+ printf("set: sleepInterval %d\n", sleepIntervalMs);
if (!sleepInterval && sleepIntervalMs) {
// We were always on, now lets duty cycle
post stopRadio(); // Might want to delay turning off the radio
diff --git a/tos/interfaces/LowPowerListening.nc b/tos/interfaces/LowPowerListening.nc
index b5225c4..60b49fc 100644
--- a/tos/interfaces/LowPowerListening.nc
+++ b/tos/interfaces/LowPowerListening.nc
@@ -35,18 +35,17 @@
* @author Jonathan Hui
* @author David Moss
*/
-
+
#include "message.h"
-
-interface LowPowerListening {
+interface LowPowerListening {
/**
- * 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.
+ * Set this this node's radio sleep interval, in milliseconds. After
+ * each interval, the node will wakeup and check for radio activity.
*
- * This is the equivalent of setting the local duty cycle rate.
+ * Note: The sleep interval can be set to 0 to indicate that the radio
+ * should stay on all the time but in order to get a startDone this
+ * should only be done when the duty-cycling is off (after a stopDone).
*
* @param sleepIntervalMs the length of this node's Rx check interval, in [ms]
*/
@@ -56,31 +55,7 @@ interface LowPowerListening {
* @return the local node's sleep interval, in [ms]
*/
command uint16_t getLocalSleepInterval();
-
- /**
- * 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 setLocalDutyCycle(uint16_t dutyCycle);
-
- /**
- * @return this node's radio duty cycle rate, in units of [percentage*100]
- */
- command uint16_t getLocalDutyCycle();
-
-
+
/**
* Configure this outgoing message so it can be transmitted to a neighbor mote
* with the specified Rx sleep interval.
@@ -88,45 +63,10 @@ interface LowPowerListening {
* @param sleepInterval The receiving node's sleep interval, in [ms]
*/
command void setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs);
-
+
/**
* @param 'message_t* ONE msg'
* @return the destination node's sleep interval configured in this message
*/
command uint16_t getRxSleepInterval(message_t *msg);
-
- /**
- * 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 'message_t* ONE 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 setRxDutyCycle(message_t *msg, uint16_t dutyCycle);
-
- /**
- * @param 'message_t* ONE msg'
- * @return the destination node's duty cycle configured in this message
- * in units of [percentage*100]
- */
- command uint16_t getRxDutyCycle(message_t *msg);
-
- /**
- * 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 dutyCycleToSleepInterval(uint16_t 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 sleepIntervalToDutyCycle(uint16_t sleepInterval);
-
}
diff --git a/tos/interfaces/LowPowerListeningControl.nc b/tos/interfaces/LowPowerListeningControl.nc
new file mode 100644
index 0000000..18b3e6d
--- /dev/null
+++ b/tos/interfaces/LowPowerListeningControl.nc
@@ -0,0 +1,42 @@
+#include "AM.h"
+
+/**
+ * Low Power Listening Control interface
+ */
+
+interface LowPowerListeningControl
+{
+ /**
+ * Start the duty-cycling of the radio. Once every sleep interval, the node
+ * will turn the radio on check for activity. Setting the sleep interval to 0
+ * (default value) will keep the radio always on.
+ *
+ * @param sleepIntervalMs the length of this node's Rx check interval, in [ms]
+ */
+ command void sleep(uint16_t sleepIntervalMs);
+
+ /**
+ * Resume the duty-cycling of the radio.
+ */
+ command void resumeSleep();
+
+ /**
+ * Terminate the duty-cycling and turn the radio on. The awake signal will
+ * indicate when the operation is completed.
+ */
+ command void wakeup();
+
+ /**
+ * The upper layers can use this to manage what to do when the LPL detects
+ * network activity. The default implementation for non-zero sleep intervals
+ * is to go to sleep immediately.
+ */
+ event void awake();
+
+ event void probeFrom(am_addr_t addr);
+
+ command void incUsers();
+ command void decUsers();
+ command bool isIdle();
+ command bool isAwake();
+}
diff --git a/tos/lib/net/ctp/CtpForwardingEngineP.nc b/tos/lib/net/ctp/CtpForwardingEngineP.nc
index 538fb64..ff77b95 100644
--- a/tos/lib/net/ctp/CtpForwardingEngineP.nc
+++ b/tos/lib/net/ctp/CtpForwardingEngineP.nc
@@ -416,6 +416,7 @@ implementation {
dbg("Forwarder", "%s: no route, don't send, try again in %i.\n", __FUNCTION__, NO_ROUTE_RETRY);
call RetxmitTimer.startOneShot(NO_ROUTE_RETRY);
call CollectionDebug.logEvent(NET_C_FE_NO_ROUTE);
+ printf("ctp: no route\n");
return;
}
else {
diff --git a/tos/lib/net/ctp/CtpRoutingEngineP.nc b/tos/lib/net/ctp/CtpRoutingEngineP.nc
index ec0d0ac..b00389c 100644
--- a/tos/lib/net/ctp/CtpRoutingEngineP.nc
+++ b/tos/lib/net/ctp/CtpRoutingEngineP.nc
@@ -344,6 +344,7 @@ implementation {
dbg("TreeRouting","Changed parent. from %d to %d\n", routeInfo.parent, best->neighbor);
call CollectionDebug.logEventDbg(NET_C_TREE_NEW_PARENT, best->neighbor, best->info.etx, minEtx);
+ printf("ctp: %u -> %u (%lu)\n", routeInfo.parent, best->neighbor, parentChanges);
call LinkEstimator.unpinNeighbor(routeInfo.parent);
call LinkEstimator.pinNeighbor(best->neighbor);
call LinkEstimator.clearDLQ(best->neighbor);
@@ -409,6 +410,7 @@ implementation {
beaconMsg->parent,
beaconMsg->etx);
call CollectionDebug.logEventRoute(NET_C_TREE_SENT_BEACON, beaconMsg->parent, 0, beaconMsg->etx);
+ printf("ctp: ping %u etx %u\n", beaconMsg->parent, beaconMsg->etx);
eval = call BeaconSend.send(AM_BROADCAST_ADDR,
&beaconMsgBuffer,
@@ -510,6 +512,7 @@ implementation {
event void LinkEstimator.evicted(am_addr_t neighbor) {
routingTableEvict(neighbor);
dbg("TreeRouting","%s\n",__FUNCTION__);
+ printf("ctp: %u evicted\n", neighbor);
if (routeInfo.parent == neighbor) {
routeInfoInit(&routeInfo);
justEvicted = TRUE;
diff --git a/tos/platforms/telosa/ActiveMessageC.nc b/tos/platforms/telosa/ActiveMessageC.nc
index 0e65149..aaf2bff 100644
--- a/tos/platforms/telosa/ActiveMessageC.nc
+++ b/tos/platforms/telosa/ActiveMessageC.nc
@@ -58,6 +58,7 @@ configuration ActiveMessageC {
interface PacketAcknowledgements;
interface PacketTimeStamp<T32khz, uint32_t> as PacketTimeStamp32khz;
interface PacketTimeStamp<TMilli, uint32_t> as PacketTimeStampMilli;
+ interface LowPowerListening;
}
}
implementation {
@@ -71,6 +72,7 @@ implementation {
Packet = AM;
AMPacket = AM;
PacketAcknowledgements = AM;
+ LowPowerListening = AM;
components CC2420PacketC;
PacketTimeStamp32khz = CC2420PacketC;
diff --git a/tos/platforms/telosa/GlobalsC.nc b/tos/platforms/telosa/GlobalsC.nc
new file mode 100644
index 0000000..911ec22
--- /dev/null
+++ b/tos/platforms/telosa/GlobalsC.nc
@@ -0,0 +1,13 @@
+configuration GlobalsC { }
+
+implementation
+{
+ components GlobalsP;
+ components new CounterToLocalTimeC(T32khz);
+ components new TransformCounterC(T32khz, uint32_t, T32khz, uint16_t, 0, uint32_t) as Transform;
+ components Msp430Counter32khzC;
+
+ CounterToLocalTimeC.Counter -> Transform;
+ Transform.CounterFrom -> Msp430Counter32khzC;
+ GlobalsP.LocalTime -> CounterToLocalTimeC;
+}
diff --git a/tos/platforms/telosa/GlobalsP.nc b/tos/platforms/telosa/GlobalsP.nc
new file mode 100644
index 0000000..1512175
--- /dev/null
+++ b/tos/platforms/telosa/GlobalsP.nc
@@ -0,0 +1,11 @@
+#include "Globals.h"
+
+module GlobalsP
+{
+ uses interface LocalTime<T32khz> as LocalTime;
+}
+
+implementation
+{
+ uint32_t getLocalTime() @C() { return call LocalTime.get(); }
+}
diff --git a/tos/system/AMQueueImplP.nc b/tos/system/AMQueueImplP.nc
index a4c4eaf..9f79d93 100644
--- a/tos/system/AMQueueImplP.nc
+++ b/tos/system/AMQueueImplP.nc
@@ -35,8 +35,11 @@
#include "AM.h"
generic module AMQueueImplP(int numClients) @safe() {
- provides interface Send[uint8_t client];
- uses{
+ provides {
+ interface Send[uint8_t client];
+ command uint8_t getNumClients();
+ }
+ uses {
interface AMSend[am_id_t id];
interface AMPacket;
interface Packet;
@@ -52,6 +55,8 @@ implementation {
queue_entry_t queue[numClients];
uint8_t cancelMask[numClients/8 + 1];
+ command uint8_t getNumClients() { return current == numClients ? 0 : current; }
+
void tryToSend();
void nextPacket() {
diff --git a/tos/system/AMQueueP.nc b/tos/system/AMQueueP.nc
index 415168e..2094057 100644
--- a/tos/system/AMQueueP.nc
+++ b/tos/system/AMQueueP.nc
@@ -32,7 +32,10 @@
#include "AM.h"
configuration AMQueueP {
- provides interface Send[uint8_t client];
+ provides {
+ interface Send[uint8_t client];
+ command uint8_t getNumClients();
+ }
}
implementation {
@@ -43,6 +46,7 @@ implementation {
components new AMQueueImplP(NUM_CLIENTS), ActiveMessageC;
Send = AMQueueImplP;
+ getNumClients = AMQueueImplP;
AMQueueImplP.AMSend -> ActiveMessageC;
AMQueueImplP.AMPacket -> ActiveMessageC;
AMQueueImplP.Packet -> ActiveMessageC;
diff --git a/tos/system/AMSenderC.nc b/tos/system/AMSenderC.nc
index eba1753..182151a 100644
--- a/tos/system/AMSenderC.nc
+++ b/tos/system/AMSenderC.nc
@@ -46,14 +46,15 @@ generic configuration AMSenderC(am_id_t AMId) {
}
implementation {
- components new AMQueueEntryP(AMId) as AMQueueEntryP;
- components AMQueueP, ActiveMessageC;
- AMQueueEntryP.Send -> AMQueueP.Send[unique(UQ_AMQUEUE_SEND)];
- AMQueueEntryP.AMPacket -> ActiveMessageC;
-
- AMSend = AMQueueEntryP;
- Packet = ActiveMessageC;
- AMPacket = ActiveMessageC;
- Acks = ActiveMessageC;
+#if defined(LOW_POWER_LISTENING) || defined(LOW_POWER_PROBING)
+ components new LplAMSenderC(AMId) as SenderC;
+#else
+ components new DirectAMSenderC(AMId) as SenderC;
+#endif
+
+ AMSend = SenderC;
+ Packet = SenderC;
+ AMPacket = SenderC;
+ Acks = SenderC;
}
diff --git a/tos/system/DirectAMSenderC.nc b/tos/system/DirectAMSenderC.nc
new file mode 100644
index 0000000..cb4fe07
--- /dev/null
+++ b/tos/system/DirectAMSenderC.nc
@@ -0,0 +1,59 @@
+// $Id$
+/*
+ * "Copyright (c) 2006 Stanford 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 STANFORD 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 STANFORD UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * STANFORD 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 STANFORD UNIVERSITY
+ * HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ * ENHANCEMENTS, OR MODIFICATIONS."
+ */
+
+/**
+ * The virtualized active message send abstraction. Each instantiation
+ * of AMSenderC has its own queue of depth one. Therefore, it does not
+ * have to contend with other AMSenderC instantiations for queue space.
+ * The underlying implementation schedules the packets in these queues
+ * using some form of fair-share queueing.
+ *
+ * @author Philip Levis
+ * @date Jan 16 2006
+ * @see TEP 116: Packet Protocols
+ */
+
+#include "AM.h"
+
+generic configuration DirectAMSenderC(am_id_t AMId) {
+ provides {
+ interface AMSend;
+ interface Packet;
+ interface AMPacket;
+ interface PacketAcknowledgements as Acks;
+ }
+}
+
+implementation {
+ components new AMQueueEntryP(AMId) as AMQueueEntryP;
+ components AMQueueP, ActiveMessageC;
+
+ AMQueueEntryP.Send -> AMQueueP.Send[unique(UQ_AMQUEUE_SEND)];
+ AMQueueEntryP.AMPacket -> ActiveMessageC;
+
+ AMSend = AMQueueEntryP;
+ Packet = ActiveMessageC;
+ AMPacket = ActiveMessageC;
+ Acks = ActiveMessageC;
+}
diff --git a/tos/system/LplAMSenderC.nc b/tos/system/LplAMSenderC.nc
new file mode 100644
index 0000000..52be108
--- /dev/null
+++ b/tos/system/LplAMSenderC.nc
@@ -0,0 +1,26 @@
+#include "AM.h"
+
+generic configuration LplAMSenderC(am_id_t AMId)
+{
+ provides {
+ interface AMSend;
+ interface Packet;
+ interface AMPacket;
+ interface PacketAcknowledgements as Acks;
+ }
+}
+
+implementation
+{
+ components new DirectAMSenderC(AMId);
+ components new LplAMSenderP();
+ components ActiveMessageC;
+
+ AMSend = LplAMSenderP;
+ Packet = DirectAMSenderC;
+ AMPacket = DirectAMSenderC;
+ Acks = DirectAMSenderC;
+
+ LplAMSenderP.SubAMSend -> DirectAMSenderC;
+ LplAMSenderP.Lpl -> ActiveMessageC;
+}
diff --git a/tos/system/LplAMSenderP.nc b/tos/system/LplAMSenderP.nc
new file mode 100644
index 0000000..d493241
--- /dev/null
+++ b/tos/system/LplAMSenderP.nc
@@ -0,0 +1,22 @@
+generic module LplAMSenderP()
+{
+ provides interface AMSend;
+ uses {
+ interface AMSend as SubAMSend;
+ interface LowPowerListening as Lpl;
+ }
+}
+
+implementation
+{
+ event void SubAMSend.sendDone(message_t* msg, error_t error)
+ {
+ call Lpl.setRxSleepInterval(msg, LPL_DEF_RX_SLEEP);
+ signal AMSend.sendDone(msg, error);
+ }
+
+ command error_t AMSend.send(am_addr_t addr, message_t* msg, uint8_t len) { return call SubAMSend.send(addr, msg, len); }
+ command error_t AMSend.cancel(message_t* msg) { return call SubAMSend.cancel(msg); }
+ command uint8_t AMSend.maxPayloadLength() { return call SubAMSend.maxPayloadLength(); }
+ command void* AMSend.getPayload(message_t* msg, uint8_t len) { return call SubAMSend.getPayload(msg, len); }
+}
diff --git a/tos/types/Globals.h b/tos/types/Globals.h
new file mode 100644
index 0000000..4bfc972
--- /dev/null
+++ b/tos/types/Globals.h
@@ -0,0 +1,25 @@
+#ifndef GLOBALS_H
+#define GLOBALS_H
+
+nx_struct Globals {
+ nx_uint32_t SentPackets;
+ nx_uint32_t RecvPackets;
+};
+
+ nx_struct Globals __g;
+
+ uint16_t getGlobalsSize() { return sizeof(__g); }
+ void *getGlobals() { return (void*)&__g; }
+ uint32_t getLocalTime();
+
+#define GLOBALS_GET(name) typeof(__g.name) get##name() { return __g.name; }
+#define GLOBALS_SET(name) void set##name(typeof(__g.name) val) { __g.name = val; }
+#define GLOBALS_INC(name) void inc##name() { __g.name++; }
+#define GLOBALS_ADD(name) void add##name(typeof(__g.name) val) { __g.name += val; }
+
+ GLOBALS_GET(SentPackets);
+ GLOBALS_INC(SentPackets);
+
+ GLOBALS_GET(RecvPackets);
+ GLOBALS_INC(RecvPackets);
+#endif
More information about the net2-wg
mailing list