interface Receive as SubReceive;
interface PacketField<uint16_t> as PacketSleepInterval;
+ interface IEEE154Packet;
+ interface PacketAcknowledgements;
interface Timer<TMilli>;
}
}
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;
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;
}
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);
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()
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)
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));
}
}