]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/chips/rf230/LowPowerListeningLayerP.nc
Proper MSP_BSL_FLAGS for telosa and telosb based platforms using TMI modular tos...
[tinyos-2.x.git] / tos / chips / rf230 / LowPowerListeningLayerP.nc
index 532528437ad03121d7469aa8e76305d9ca691dc5..ef4bac568622da67001c384b7a0f47ca8256962b 100644 (file)
@@ -41,6 +41,8 @@ module LowPowerListeningLayerP
                interface Receive as SubReceive;
 
                interface PacketField<uint16_t> as PacketSleepInterval;
+               interface IEEE154Packet;
+               interface PacketAcknowledgements;
                interface Timer<TMilli>;
        }
 }
@@ -50,109 +52,152 @@ implementation
        enum
        {
                // minimum wakeup time to catch a transmission in milliseconds
-               LISTEN_WAKEUP = 6     // use xxxL if LISTEN_WAKEUP * 10000 > 65535
+               LISTEN_WAKEUP = 6U,     // use xxxL if LISTEN_WAKEUP * 10000 > 65535
 
                // extra wakeup time after receiving a message in milliseconds
-               AFTER_RECEIVE = 10,
+               AFTER_RECEIVE = 10U,
 
                // extra wakeup time after transmitting a message in milliseconds
-               AFTER_TRANSMIT = 10,
+               AFTER_TRANSMIT = 10U,
 
                MIN_SLEEP = 2,          // the minimum sleep interval in milliseconds
                MAX_SLEEP = 30000,      // the maximum sleep interval in milliseconds
                MIN_DUTY = 2,           // the minimum duty cycle
        };
 
-       uint16_t rxSleepInterval;
+       uint16_t sleepInterval;
+
+       message_t* txMsg;
+       uint8_t txLen;
+       error_t txError;
 
 /*----------------- state machine -----------------*/
 
        enum
        {
-               STATE_OFF = 0,          // timer off, radio off
-               STATE_SLEEP = 1,        // timer on, radio off
-               STATE_LISTEN = 2,       // timer on/off, radio on
-               STATE_SEND = 3,         // timer on/off, radio on
-
-               STATE_OFF_TO_LISTEN = 10,
-               STATE_SLEEP_TO_LISTEN = 11,
-               STATE_SLEEP_TO_SEND = 12,
-               STATE_SLEEP_TO_OFF = 13,
-               STATE_LISTEN_TO_SLEEP_1 = 14,   // we go back to listen if a message arrives in this state
-               STATE_LISTEN_TO_SLEEP_2 = 15,
-               STATE_LISTEN_TO_OFF = 16,
-               STATE_SEND_DONE = 17,
+               OFF = 0,                                        
+               OFF_SUBSTOP = 1,                        // must have consecutive indices
+               OFF_SUBSTOP_DONE = 2,           // must have consecutive indices
+               OFF_STOP_END = 3,                       // must have consecutive indices
+               OFF_START_END = 4,
+
+               LISTEN_SUBSTART = 5,            // must have consecutive indices
+               LISTEN_SUBSTART_DONE = 6,       // must have consecutive indices
+               LISTEN_TIMER = 7,                       // must have consecutive indices
+               LISTEN = 8,                                     // must have consecutive indices
+
+               SLEEP_SUBSTOP = 9,                      // must have consecutive indices
+               SLEEP_SUBSTOP_DONE = 10,        // must have consecutive indices
+               SLEEP_TIMER = 11,                       // must have consecutive indices
+               SLEEP = 12,                                     // must have consecutive indices
+
+               SEND_SUBSTART = 13,                     // must have consecutive indices
+               SEND_SUBSTART_DONE = 14,        // must have consecutive indices
+               SEND_TIMER = 15,                        // must have consecutive indices
+               SEND_SUBSEND= 16,
+               SEND_SUBSEND_DONE = 17,
+               SEND_SUBSEND_DONE_LAST = 18,
+               SEND_DONE = 19,
        };
 
        uint8_t state;
 
-       message_t* txMsg;
-       uint8_t txLen;
-
        task void transition()
        {
                error_t error;
+               uint16_t transmitInterval;
 
-               if( state == STATE_OFF_TO_LISTEN || state == STATE_SLEEP_TO_LISTEN || state == STATE_SLEEP_TO_SEND )
+               if( state == LISTEN_SUBSTART || state == SEND_SUBSTART )
                {
                        error = call SubControl.start();
                        ASSERT( error == SUCCESS || error == EBUSY );
 
-                       if( error != SUCCESS )
+                       if( error == SUCCESS )
+                               ++state;
+                       else
                                post transition();
                }
-               else if( state == STATE_LISTEN_TO_OFF || state == STATE_LISTEN_TO_SLEEP_1 )
+               else if( state == SLEEP_SUBSTOP || state == OFF_SUBSTOP )
                {
                        error = call SubControl.stop();
                        ASSERT( error == SUCCESS || error == EBUSY );
 
-                       if( error != SUCCESS )
+                       if( error == SUCCESS )
+                               ++state;
+                       else
                                post transition();
-                       else if( state == STATE_LISTEN_TO_SLEEP_1 )
-                               state = STATE_LISTEN_TO_SLEEP_2;
                }
-               else if( state == STATE_SLEEP_TO_OFF )
+               else if( state == OFF_START_END )
                {
-                       state = STATE_OFF;
+                       state = LISTEN_SUBSTART;
+                       post transition();
+
+                       signal SplitControl.startDone(SUCCESS);
+               }
+               else if( state == OFF_STOP_END )
+               {
+                       state = OFF;
                        signal SplitControl.stopDone(SUCCESS);
                }
-               else if( state == STATE_SEND )
+               else if( state == LISTEN_TIMER )
                {
-                       error = call SubSend.send(txMsg, txLen);
-                       if( error == SUCCESS )
-                               state = STATE_SEND_DONE;
+                       state = LISTEN;
+                       if( sleepInterval > 0 )
+                               call Timer.startOneShot(LISTEN_WAKEUP);
+               }
+               else if( state == SLEEP_TIMER )
+               {
+                       if( sleepInterval > 0 )
+                       {
+                               state = SLEEP;
+                               call Timer.startOneShot(sleepInterval);
+                       }
                        else
                        {
-                               state = STATE_LISTEN;
-                               if( rxSleepInterval > 0 )
-                                       call Timer.startOneShot(AFTER_TRANSMIT);
-
-                               signal Send.sendDone(txMsg, error);
+                               state = LISTEN_SUBSTART;
+                               post transition();
                        }
                }
-               else if( state == STATE_LISTEN )
+               else if( state == SEND_TIMER )
                {
-                       if( rxSleepInterval > 0 )
-                               call Timer.startOneShot(LISTEN_WAKEUP);
+                       transmitInterval = call LowPowerListening.getRxSleepInterval(txMsg);
+
+                       if( transmitInterval > 0 )
+                               call Timer.startOneShot(transmitInterval);
+
+                       state = SEND_SUBSEND;
+                       post transition();
                }
-               else if( state == STATE_SLEEP )
+               else if( state == SEND_SUBSEND)
                {
-                       if( rxSleepInterval > 0 )
-                               call Timer.startOneShot(rxSleepInterval);
+                       txError = call SubSend.send(txMsg, txLen);
+
+                       if( txError == SUCCESS )
+                               state = SEND_SUBSEND_DONE;
                        else
                        {
-                               state = STATE_SLEEP_TO_LISTEN;
+                               state = SEND_DONE;
                                post transition();
                        }
                }
+               else if( state == SEND_DONE )
+               {
+                       state = LISTEN;
+                       if( sleepInterval > 0 )
+                               call Timer.startOneShot(AFTER_TRANSMIT);
+
+                       signal Send.sendDone(txMsg, txError);
+               }
        }
 
        command error_t SplitControl.start()
        {
-               if( state != STATE_OFF )
+               if( state == OFF_START_END )
+                       return EBUSY;
+               else if( state != OFF )
                        return EALREADY;
 
-               state = STATE_OFF_TO_LISTEN;
+               state = OFF_START_END;
                post transition();
 
                return SUCCESS;
@@ -161,35 +206,34 @@ implementation
        event void SubControl.startDone(error_t error)
        {
                ASSERT( error == SUCCESS || error == EBUSY );
-               ASSERT( state == STATE_OFF_TO_LISTEN || state == STATE_SLEEP_TO_LISTEN || state == STATE_SLEEP_TO_SEND );
+               ASSERT( state == LISTEN_SUBSTART_DONE || state == SEND_SUBSTART_DONE );
 
                if( error == SUCCESS )
-               {
-                       if( state == STATE_OFF_TO_LISTEN )
-                               signal SplitControl.startDone(SUCCESS);
-                       else if( state == STATE_SLEEP_TO_SEND )
-                               state = STATE_SEND;
-                       else
-                               state = STATE_LISTEN;
-               }
+                       ++state;
+               else
+                       --state;
 
                post transition();
        }
 
        command error_t SplitControl.stop()
        {
-               if( state == STATE_OFF )
-                       return EALREADY;
-               else if( state != STATE_LISTEN || state != STATE_SLEEP )
-                       return EBUSY;
+               if( state == SLEEP || state == LISTEN )
+               {
+                       call Timer.stop();
+                       post transition();
+               }
 
-               call Timer.stop();
-               if( state == STATE_SLEEP )
-                       state = STATE_SLEEP_TO_OFF;
+               if( state == LISTEN_TIMER || state == LISTEN || state == SLEEP_SUBSTOP )
+                       state = OFF_SUBSTOP;
+               else if( state == SLEEP_SUBSTOP_DONE )
+                       state = OFF_SUBSTOP_DONE;
+               else if( state == LISTEN_SUBSTART || state == SLEEP_TIMER || state == SLEEP )
+                       state = OFF_STOP_END;
+               else if( state == OFF )
+                       return EALREADY;
                else
-                       state = STATE_LISTEN_TO_OFF;
-
-               post transition();
+                       return EBUSY;
 
                return SUCCESS;
        }
@@ -197,49 +241,38 @@ implementation
        event void SubControl.stopDone(error_t error)
        {
                ASSERT( error == SUCCESS || error == EBUSY );
-               ASSERT( state == STATE_LISTEN_TO_SLEEP_2 || state == STATE_LISTEN_TO_OFF );
+               ASSERT( state == SLEEP_SUBSTOP_DONE || state == OFF_SUBSTOP_DONE );
 
                if( error == SUCCESS )
-               {
-                       if( state == STATE_LISTEN_TO_OFF )
-                               state = STATE_SLEEP_TO_OFF;
-                       else
-                               state = STATE_SLEEP;
-               }
+                       ++state;
+               else
+                       --state;
 
                post transition();
        }
 
        event void Timer.fired()
        {
-               ASSERT( state == STATE_LISTEN || state == STATE_SLEEP );
-
-               if( state == STATE_LISTEN )
-                       state = STATE_LISTEN_TO_SLEEP_1;
-               else
-                       state = STATE_SLEEP_TO_LISTEN;
-
-               post transition();
-       }
+               ASSERT( state == LISTEN || state == SLEEP || state == SEND_SUBSEND || state == SEND_SUBSEND_DONE );
 
-       void rxSleepIntervalChanged()
-       {
-               if( rxSleepInterval == 0 )
-               {
-                       call Timer.stop();
-                       if( state == STATE_SLEEP )
-                               state = STATE_SLEEP_TO_LISTEN;
-               }
+               if( state == LISTEN )
+                       state = SLEEP_SUBSTOP;
+               else if( state == SLEEP )
+                       state = LISTEN_SUBSTART;
+               else if( state == SEND_SUBSEND_DONE )
+                       state = SEND_SUBSEND_DONE_LAST;
+               else if( state == SEND_SUBSEND)
+                       state = SEND_DONE;
 
                post transition();
        }
 
        event message_t* SubReceive.receive(message_t* msg, void* payload, uint8_t len)
        {
-               if( state == STATE_LISTEN_TO_SLEEP_1 )
-                       state = STATE_LISTEN;
+               if( state == SLEEP_SUBSTOP )
+                       state = LISTEN;
 
-               if( state == STATE_LISTEN && rxSleepInterval > 0 )
+               if( state == LISTEN && sleepInterval > 0 )
                        call Timer.startOneShot(AFTER_RECEIVE);
 
                return signal Receive.receive(msg, payload, len);
@@ -247,42 +280,70 @@ implementation
 
        command error_t Send.send(message_t* msg, uint8_t len)
        {
-               if( state == STATE_LISTEN || state == STATE_SLEEP )
-                       call Timer.stop();
-
-               if( state == STATE_LISTEN || state == STATE_LISTEN_TO_SLEEP_1 )
-               {
-                       state = STATE_SEND;
-                       post transition();
-               }
-               else if( state == STATE_SLEEP )
+               if( state == LISTEN || state == SLEEP )
                {
-                       state = STATE_SLEEP_TO_SEND;
+                       call Timer.stop();
                        post transition();
                }
-               else if( state == STATE_SLEEP_TO_LISTEN )
-                       state = STATE_SLEEP_TO_SEND;
+
+               if( state == LISTEN_SUBSTART || state == SLEEP_TIMER || state == SLEEP )
+                       state = SEND_SUBSTART;
+               else if( state == LISTEN_SUBSTART_DONE )
+                       state = SEND_SUBSTART_DONE;
+               else if( state == LISTEN_TIMER || state == SLEEP_SUBSTOP || state == LISTEN )
+                       state = SEND_TIMER;
                else
                        return EBUSY;
 
                txMsg = msg;
                txLen = len;
+               txError = FAIL;
+
+               return SUCCESS;
        }
 
        command error_t Send.cancel(message_t* msg)
        {
-               return call SubSend.cancel(msg);
+               if( state == SEND_SUBSEND )
+               {
+                       call Timer.stop();
+                       state = SEND_DONE;
+                       txError = ECANCEL;
+                       post transition();
+
+                       return SUCCESS;
+               }
+               else if( state == SEND_SUBSEND_DONE )
+               {
+                       // we stop sending the message even if SubSend.cancel was not succesfull
+                       state = SEND_SUBSEND_DONE_LAST;
+
+                       return call SubSend.cancel(txMsg);
+               }
+               else
+                       return FAIL;
        }
 
        event void SubSend.sendDone(message_t* msg, error_t error)
        {
-               ASSERT( state == STATE_SEND_DONE );
+               ASSERT( state == SEND_SUBSEND_DONE || state == SEND_SUBSEND_DONE_LAST );
+               ASSERT( msg == txMsg );
+
+               txError = error;
 
-               state = STATE_LISTEN;
-               if( rxSleepInterval > 0 )
-                       call Timer.startOneShot(AFTER_TRANSMIT);
+               // TODO: extend the PacketAcknowledgements interface with getAckRequired
+               if( error != SUCCESS
+                       || call LowPowerListening.getRxSleepInterval(msg) == 0
+                       || state == SEND_SUBSEND_DONE_LAST
+                       || (call IEEE154Packet.getAckRequired(msg) && call PacketAcknowledgements.wasAcked(msg)) )
+               {
+                       call Timer.stop();
+                       state = SEND_DONE;
+               }
+               else
+                       state = SEND_SUBSEND;
 
-               signal Send.sendDone(msg, error);
+               post transition();
        }
 
        command uint8_t Send.maxPayloadLength()
@@ -304,33 +365,39 @@ implementation
                else if( dutyCycle <= MIN_DUTY  )
                        return MAX_SLEEP;
 
-               return ((10000 * LISTEN_WAKEUP) / dutyCycle) - LISTEN_WAKEUP;
+               return ((10000U * LISTEN_WAKEUP) / dutyCycle) - LISTEN_WAKEUP;
        }
 
-       command uint16_t LowPowerListening.sleepIntervalToDutyCycle(uint16_t sleepInterval)
+       command uint16_t LowPowerListening.sleepIntervalToDutyCycle(uint16_t interval)
        {
-               if( sleepInterval < MIN_SLEEP )
+               if( interval < MIN_SLEEP )
                        return 10000;
-               else if( sleepInterval >= MAX_SLEEP )
+               else if( interval >= MAX_SLEEP )
                        return MIN_DUTY;
 
-               return (10000 * LISTEN_WAKEUP) / (LISTEN_WAKEUP + sleepInterval);
+               return (10000U * LISTEN_WAKEUP) / (LISTEN_WAKEUP + interval);
        }
 
-       command void LowPowerListening.setLocalSleepInterval(uint16_t sleepInterval)
+       command void LowPowerListening.setLocalSleepInterval(uint16_t interval)
     {
-               if( sleepInterval < MIN_SLEEP )
-                       sleepInterval = 0;
-               else if( sleepInterval > MAX_SLEEP )
-                       sleepInterval = MAX_SLEEP;
+               if( interval < MIN_SLEEP )
+                       interval = 0;
+               else if( interval > MAX_SLEEP )
+                       interval = MAX_SLEEP;
+
+               sleepInterval = interval;
 
-               rxSleepInterval = sleepInterval;
-               rxSleepIntervalChanged();
+               if( (state == LISTEN && sleepInterval == 0) || state == SLEEP )
+               {
+                       call Timer.stop();
+                       --state;
+                       post transition();
+               }
        }
 
        command uint16_t LowPowerListening.getLocalSleepInterval()
     {  
-               return rxSleepInterval;
+               return sleepInterval;
        }
 
        command void LowPowerListening.setLocalDutyCycle(uint16_t dutyCycle)
@@ -341,39 +408,36 @@ implementation
 
        command uint16_t LowPowerListening.getLocalDutyCycle()
        {
-               return call LowPowerListening.sleepIntervalToDutyCycle(rxSleepInterval);
+               return call LowPowerListening.sleepIntervalToDutyCycle(sleepInterval);
        }
 
-       command void LowPowerListening.setRxSleepInterval(message_t *msg, uint16_t sleepInterval)
+       command void LowPowerListening.setRxSleepInterval(message_t *msg, uint16_t interval)
        {
-               if( sleepInterval < MIN_SLEEP )
-                       sleepInterval = 0;
-               else if( sleepInterval > MAX_SLEEP )
-                       sleepInterval = MAX_SLEEP;
+               if( interval < MIN_SLEEP )
+                       interval = 0;
+               else if( interval > MAX_SLEEP )
+                       interval = MAX_SLEEP;
 
-               call PacketSleepInterval.set(msg, sleepInterval);
+               call PacketSleepInterval.set(msg, interval);
        }
 
        command uint16_t LowPowerListening.getRxSleepInterval(message_t *msg)
     {
                if( ! call PacketSleepInterval.isSet(msg) )
-                       return 0;
+                       return sleepInterval;
 
                return call PacketSleepInterval.get(msg);
        }
 
        command void LowPowerListening.setRxDutyCycle(message_t *msg, uint16_t dutyCycle)
     {
-               call PacketSleepInterval.set(msg, 
+               call LowPowerListening.setRxSleepInterval(msg, 
                        call LowPowerListening.dutyCycleToSleepInterval(dutyCycle));
        }
 
        command uint16_t LowPowerListening.getRxDutyCycle(message_t *msg)
     {
-               if( ! call PacketSleepInterval.isSet(msg) )
-                       return 10000;
-
                return call LowPowerListening.sleepIntervalToDutyCycle(
-                       call PacketSleepInterval.get(msg));
+                       call LowPowerListening.getRxSleepInterval(msg));
        }
 }