]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/chips/rf230/TrafficMonitorLayerP.nc
platform support for the IRIS mote (atm1218 MCU and rf230 radio)
[tinyos-2.x.git] / tos / chips / rf230 / TrafficMonitorLayerP.nc
diff --git a/tos/chips/rf230/TrafficMonitorLayerP.nc b/tos/chips/rf230/TrafficMonitorLayerP.nc
new file mode 100644 (file)
index 0000000..75328ac
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, reportS, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+#include <Tasklet.h>
+
+/*
+ * You have to make sure that the maximum channel time in one report
+ * period times (1 << TRAFFIC_MONITOR_DECAY) is less than 65535.
+ */
+#ifndef TRAFFIC_MONITOR_DECAY
+#define TRAFFIC_MONITOR_DECAY  3
+#endif
+
+module TrafficMonitorLayerP
+{
+       provides
+       {
+               interface RadioSend;
+               interface RadioReceive;
+               interface RadioState;
+       }
+
+       uses
+       {
+               interface TrafficMonitorConfig;
+               interface RadioSend as SubSend;
+               interface RadioReceive as SubReceive;
+               interface RadioState as SubState;
+               interface Timer<TMilli> as Timer;
+               interface Neighborhood;
+               interface NeighborhoodFlag;
+               interface Tasklet;
+#ifdef RF230_DEBUG
+               interface DiagMsg;
+#endif
+       }
+}
+
+implementation
+{
+       tasklet_norace message_t *txMsg;
+       tasklet_norace uint8_t neighborCount;
+
+       tasklet_norace uint16_t txAverage;
+       tasklet_norace uint16_t rxAverage;
+       tasklet_norace uint8_t neighborAverage;
+       tasklet_norace uint8_t errorAverage;
+
+       enum
+       {
+               // the maximum average value
+               TRAFFIC_MONITOR_UINT8_MAX = 1 << (7-TRAFFIC_MONITOR_DECAY),
+
+               // the unsignificant bits of the averaged values
+               TRAFFIC_MONITOR_MASK = (1 << TRAFFIC_MONITOR_DECAY) - 1,
+
+               // to get the ceiling integer value
+               TRAFFIC_MONITOR_ROUND_UP = (1 << TRAFFIC_MONITOR_DECAY) - 1,
+       };
+
+       tasklet_async event void SubSend.ready()
+       {
+               signal RadioSend.ready();
+       }
+
+       tasklet_async command error_t RadioSend.send(message_t* msg)
+       {
+               txMsg = msg;
+               return call SubSend.send(msg);
+       }
+
+       tasklet_async event void SubSend.sendDone(error_t error)
+       {
+               if( error == SUCCESS )
+                       txAverage += call TrafficMonitorConfig.getChannelTime(txMsg);
+
+               signal RadioSend.sendDone(error);
+       }
+
+       tasklet_async event bool SubReceive.header(message_t* msg)
+       {
+               return signal RadioReceive.header(msg);
+       }
+
+       tasklet_async event message_t* SubReceive.receive(message_t* msg)
+       {
+               uint8_t index;
+
+               rxAverage += call TrafficMonitorConfig.getChannelTime(msg);
+
+               index = call Neighborhood.insertNode(call TrafficMonitorConfig.getSender(msg));
+               if( ! call NeighborhoodFlag.get(index) )
+               {
+                       if( neighborCount < TRAFFIC_MONITOR_UINT8_MAX )
+                       {
+                               ++neighborCount;
+                               call NeighborhoodFlag.set(index);
+                       }
+               }
+
+               return signal RadioReceive.receive(msg);
+       }
+
+       tasklet_async event void TrafficMonitorConfig.channelError()
+       {
+               if( errorAverage < 255 )
+                       ++errorAverage;
+       }
+
+       uint8_t debugCounter;
+
+       event void Timer.fired()
+       {
+               uint8_t fraction;
+
+               call Tasklet.suspend();
+
+               txAverage -= (txAverage >> TRAFFIC_MONITOR_DECAY);
+               rxAverage -= (rxAverage >> TRAFFIC_MONITOR_DECAY);
+               errorAverage -= (errorAverage >> TRAFFIC_MONITOR_DECAY);
+
+               // we could get stuck in the [1,7] range with no neighbors, so be more precise
+               fraction = neighborAverage >> TRAFFIC_MONITOR_DECAY;
+               if( fraction == neighborCount && (neighborAverage & TRAFFIC_MONITOR_MASK) != 0 )
+                       --neighborAverage;
+               else
+                       neighborAverage += neighborCount - fraction;
+
+               call NeighborhoodFlag.clearAll();
+               neighborCount = 0;
+
+               call TrafficMonitorConfig.timerTick();
+
+               call Tasklet.resume();
+
+#ifdef RF230_DEBUG
+               if( ++debugCounter >= 10 && call DiagMsg.record() )
+               {
+                       debugCounter = 0;
+
+                       call DiagMsg.str("traffic");
+                       call DiagMsg.uint16(signal TrafficMonitorConfig.getTransmitAverage());
+                       call DiagMsg.uint16(signal TrafficMonitorConfig.getReceiveAverage());
+                       call DiagMsg.uint8(signal TrafficMonitorConfig.getNeighborAverage());
+                       call DiagMsg.uint8(signal TrafficMonitorConfig.getErrorAverage());
+                       call DiagMsg.send();
+               }
+#endif
+       }
+
+       tasklet_async event void Tasklet.run()
+       {
+       }
+
+       tasklet_async event uint16_t TrafficMonitorConfig.getTransmitAverage()
+       {
+               return txAverage >> TRAFFIC_MONITOR_DECAY;
+       }
+
+       tasklet_async event uint16_t TrafficMonitorConfig.getReceiveAverage()
+       {
+               return rxAverage >> TRAFFIC_MONITOR_DECAY;
+       }
+
+       tasklet_async event uint8_t TrafficMonitorConfig.getNeighborAverage()
+       {
+               return (neighborAverage + TRAFFIC_MONITOR_ROUND_UP) >> TRAFFIC_MONITOR_DECAY;
+       }
+
+       tasklet_async event uint8_t TrafficMonitorConfig.getErrorAverage()
+       {
+               return errorAverage >> TRAFFIC_MONITOR_DECAY;
+       }
+
+       tasklet_async event void Neighborhood.evicted(uint8_t index) { }
+
+       enum
+       {
+               RADIO_CMD_NONE = 0,
+               RADIO_CMD_TURNON = 1,
+               RADIO_CMD_TURNOFF = 2,
+       };
+       tasklet_norace uint8_t radioCmd;
+
+       tasklet_async command error_t RadioState.turnOff()
+       {
+               radioCmd = RADIO_CMD_TURNOFF;
+               return call SubState.turnOff();
+       }
+
+       tasklet_async command error_t RadioState.standby()
+       {
+               radioCmd = RADIO_CMD_TURNOFF;
+               return call SubState.standby();
+       }
+
+       tasklet_async command error_t RadioState.turnOn()
+       {
+               radioCmd = RADIO_CMD_TURNON;
+               return call SubState.turnOn();
+       }
+
+       tasklet_async command error_t RadioState.setChannel(uint8_t channel)
+       {
+               radioCmd = RADIO_CMD_NONE;
+               return call SubState.setChannel(channel);
+       }
+
+       task void startStopTimer()
+       {
+               if( radioCmd == RADIO_CMD_TURNON )
+                       call Timer.startPeriodic(call TrafficMonitorConfig.getUpdatePeriod());
+               else if( radioCmd == RADIO_CMD_TURNOFF )
+                       call Timer.stop();
+       }
+
+       tasklet_async event void SubState.done()
+       {
+               post startStopTimer();
+               signal RadioState.done();
+       }
+}