*/
/**
- * An async version of the SplitControl interface.
+ * This interface is a mixture of a SplitControl/AsyncStdControl interface.
* @author Jan Hauer <hauer@tkn.tu-berlin.de>
*/
interface CC2420AsyncSplitControl
{
/**
- * Start this component and all of its subcomponents. Return
- * values of SUCCESS will always result in a <code>startDone()</code>
- * event being signalled.
+ * Start this component and all of its subcomponents.
*
- * @return SUCCESS if the device is already in the process of
- * starting or the device was off and the device is now ready to turn
- * on. After receiving this return value, you should expect a
- * <code>startDone</code> event in the near future.<br>
- * EBUSY if the component is in the middle of powering down
- * i.e. a <code>stop()</code> command has been called,
- * and a <code>stopDone()</code> event is pending<br>
- * EALREADY if the device is already on <br>
+ * @return SUCCESS if the component was started successfully.<br>
* FAIL Otherwise
*/
async command error_t start();
- /**
- * Notify caller that the component has been started and is ready to
- * receive other commands.
- *
- * @param <b>error</b> -- SUCCESS if the component was successfully
- * turned on, FAIL otherwise
- */
- async event void startDone(error_t error);
-
/**
- * Start this component and all of its subcomponents. Return
- * values of SUCCESS will always result in a <code>startDone()</code>
- * event being signalled.
+ * Stop this component and all of its subcomponents - iff this command
+ * succeeds then <tt>stopDone</tt> will signal the result of the stop
+ * operation.
*
- * @return SUCCESS if the device is already in the process of
- * stopping or the device was on and the device is now ready to turn
- * off. After receiving this return value, you should expect a
- * <code>stopDone</code> event in the near future.<br>
- * EBUSY if the component is in the middle of powering up
- * i.e. a <code>start()</code> command has been called,
- * and a <code>startDone()</code> event is pending<br>
- * EALREADY if the device is already off <br>
- * FAIL Otherwise
+ * @return SUCCESS Stop operation was started, <tt>stopDone</tt> will be signalled
+ * FAIL Otherwise (<tt>stopDone</tt> will not be signalled)
*/
async command error_t stop();
/**
- * Notify caller that the component has been stopped.
+ * Notify caller that the component has been stopped. This event
+ * completes the <tt>stop()</tt> operation.
*
* @param <b>error</b> -- SUCCESS if the component was successfully
* turned off, FAIL otherwise
* @author Jonathan Hui <jhui@archrock.com>
* @author David Moss
* @author Urs Hunkeler (ReadRssi implementation)
- * @author Jan Hauer <hauer@tkn.tu-berlin.de> (support for promiscuous mode)
+ * @author Jan Hauer <hauer@tkn.tu-berlin.de>
* @version $Revision$ $Date$
*/
uses interface GeneralIO as RSTN;
uses interface GeneralIO as VREN;
uses interface GpioInterrupt as InterruptCCA;
+ uses interface GeneralIO as FIFO;
uses interface CC2420Ram as IEEEADR;
uses interface CC2420Register as FSCTRL;
uses interface CC2420Register as MDMCTRL1;
uses interface CC2420Register as RXCTRL1;
uses interface CC2420Register as RSSI;
+ uses interface CC2420Register as RXFIFO_REGISTER;
+ uses interface CC2420Strobe as SNOP;
uses interface CC2420Strobe as SRXON;
uses interface CC2420Strobe as SRFOFF;
uses interface CC2420Strobe as SXOSCOFF;
uses interface CC2420Strobe as SXOSCON;
- uses interface CC2420Strobe as SACKPEND; // JH: ACKs must have pending flag set
+ uses interface CC2420Strobe as SACKPEND;
+ uses interface CC2420Strobe as SFLUSHRX;
uses interface CC2420Register as TXCTRL;
uses interface AMPacket;
}
/***************** Resource Commands ****************/
+ /* This module never actively requests the SPI resource,
+ * instead the caller MUST request the SPI through this module
+ * before it calls any of the provided commands and it must
+ * release it afterwards (the caller can call multiple
+ * commands in this module before it releases the SPI, though).
+ */
async command error_t Resource.immediateRequest() {
error_t error = call SpiResource.immediateRequest();
if ( error == SUCCESS ) {
}
}
+ event void SpiResource.granted() {
+/* call CSN.clr();*/
+ signal Resource.granted();
+ }
+
void switchToUnbufferedMode()
{
uint16_t mdmctrol1;
m_state = S_VREG_STARTING;
}
call VREN.set();
- call StartupAlarm.start( CC2420_TIME_VREN * 2 ); // JH: a 15.4 symbol is about two 32khz ticks
+ call StartupAlarm.start( CC2420_TIME_VREN * 2 ); // JH: changed from 32khz jiffies
return SUCCESS;
}
async command error_t CC2420Power.rxOn() {
atomic {
- if ( m_state != S_XOSC_STARTED ) {
+ if ( !call SpiResource.isOwner() )
return FAIL;
- }
call CSN.set();
call CSN.clr();
call SRXON.strobe();
- call SACKPEND.strobe(); // JH: ACKs have the pending bit set
+ call SACKPEND.strobe(); // JH: ACKs need the pending bit set
call CSN.set();
}
return SUCCESS;
}
async command error_t CC2420Power.rfOff() {
- atomic {
- if ( m_state != S_XOSC_STARTED ) {
+ atomic {
+ if ( !call SpiResource.isOwner() )
return FAIL;
- }
call CSN.set();
call CSN.clr();
- call SACKPEND.strobe(); // JH: ACKs have the pending bit set
call SRFOFF.strobe();
call CSN.set();
}
return SUCCESS;
}
+ async command error_t CC2420Power.flushRxFifo()
+ {
+ uint16_t dummy;
+ atomic {
+ if ( !call SpiResource.isOwner() )
+ return FAIL;
+ if ( call FIFO.get() ){ // check if there is something in the RXFIFO
+ // SFLUSHRX: "Flush the RX FIFO buffer and reset the demodulator.
+ // Always read at least one byte from the RXFIFO before
+ // issuing the SFLUSHRX command strobe" (CC2420 Datasheet)
+ call CSN.clr();
+ call RXFIFO_REGISTER.read(&dummy); // reading 1 byte would be enough...
+ call CSN.set();
+ call CSN.clr();
+ // "SFLUSHRX command strobe should be issued twice to ensure
+ // that the SFD pin goes back to its idle state." (CC2420 Datasheet)
+ call SFLUSHRX.strobe();
+ call SFLUSHRX.strobe();
+ call CSN.set();
+ }
+ }
+ return SUCCESS;
+ }
/***************** CC2420Config Commands ****************/
command uint8_t CC2420Config.getChannel() {
* Sync must be called to commit software parameters configured on
* the microcontroller (through the CC2420Config interface) to the
* CC2420 radio chip.
- * ASSUMPTION: caller owns the SPI, radio will be switched off !
*/
async command error_t CC2420Config.sync() {
atomic {
- if ( m_state != S_XOSC_STARTED ) {
+ if ( !call SpiResource.isOwner() )
return FAIL;
- }
if (m_needsSync){
call CSN.set();
call CSN.clr();
/***************** ReadRssi Commands ****************/
async command error_t CC2420Power.rssi(int8_t *rssi) {
- // we are owner of the Spi !
uint16_t data;
cc2420_status_t status;
- call CSN.clr();
- status = call RSSI.read(&data);
- call CSN.set();
- if ((status & 0x02)){
- *rssi = (data & 0x00FF);
- return SUCCESS;
- } else
- return FAIL;
- }
-
- event void SpiResource.granted() {
-/* call CSN.clr();*/
- signal Resource.granted();
+ atomic {
+ if ( !call SpiResource.isOwner() )
+ return FAIL;
+ call CSN.set();
+ call CSN.clr();
+ status = call RSSI.read(&data);
+ call CSN.set();
+ if ((status & 0x02)){
+ *rssi = (data & 0x00FF);
+ return SUCCESS;
+ } else
+ return FAIL;
+ }
}
-
-
/***************** StartupAlarm Events ****************/
async event void StartupAlarm.fired() {
if ( m_state == S_VREG_STARTING ) {
+ cc2420_status_t status;
+ do {
+ status = call SNOP.strobe();
+ } while (!(status & CC2420_STATUS_XOSC16M_STABLE));
m_state = S_VREG_STARTED;
call RSTN.clr();
call RSTN.set();
CC2420ControlP.CSN -> Pins.CSN;
CC2420ControlP.RSTN -> Pins.RSTN;
CC2420ControlP.VREN -> Pins.VREN;
+ CC2420ControlP.FIFO -> Pins.FIFO;
components HplCC2420InterruptsC as Interrupts;
CC2420ControlP.InterruptCCA -> Interrupts.InterruptCCA;
CC2420ControlP.TXCTRL -> Spi.TXCTRL;
CC2420ControlP.IEEEADR -> Spi.IEEEADR;
CC2420ControlP.RXCTRL1 -> Spi.RXCTRL1;
+ CC2420ControlP.SFLUSHRX-> Spi.SFLUSHRX;
CC2420ControlP.RSSI -> Spi.RSSI;
+ CC2420ControlP.RXFIFO_REGISTER -> Spi.RXFIFO_REGISTER;
+ CC2420ControlP.SNOP -> Spi.SNOP;
// CC2420TransmitC
components CC2420TransmitP;
* @return SUCCESS if RSSI was read successfulyy, FAIL otherwise.
*/
async command error_t rssi(int8_t *rssi);
+
+ /**
+ * Flush the RXFIFO if it is not empty.
+ * Radio SHOULD be disabled (off) when calling this command.
+ *
+ * @return SUCCESS if fifo was flushed (or it was empty), FAIL otherwise.
+ */
+ async command error_t flushRxFifo();
}
provides interface CC2420AsyncSplitControl as AsyncSplitControl;
provides interface CC2420Receive;
provides interface CC2420Rx;
-/* provides interface ReceiveIndicator as PacketIndicator;*/
uses interface GeneralIO as CSN;
uses interface GeneralIO as FIFO;
uses interface CC2420Strobe as SACK;
uses interface CC2420Strobe as SFLUSHRX;
uses interface CC2420Strobe as SRXON;
- uses interface CC2420Strobe as SACKPEND; // JH: ACKs must have pending flag set
+ uses interface CC2420Strobe as SACKPEND;
uses interface CC2420Register as MDMCTRL1;
uses interface ReferenceTime;
uses interface FrameUtility;
uses interface CC2420Config;
-/* uses interface CC2420Packet;*/
-/* uses interface CC2420PacketBody;*/
+ uses interface CC2420Ram as RXFIFO_RAM;
uses interface Leds;
}
typedef enum {
S_STOPPED,
S_STARTING,
- S_STARTING_FLUSHRX,
S_STARTED,
S_RX_LENGTH,
S_RX_FCF,
void flush();
void switchToUnbufferedMode();
void switchToBufferedMode();
- void startingSpiReserved();
void continueStart();
void continueStop();
task void stopContinueTask();
return SUCCESS;
}
- /***************** AsyncSplitControl ****************
- * IMPORTANT: when AsyncSplitControl.start is called,
- * the radio MUST be off !
+ /***************** AsyncSplitControl ****************/
+ /* NOTE: AsyncSplitControl does not switch the state of the radio
+ * hardware (i.e. it does not put the radio in Rx mode, this has to
+ * be done by the caller through a separate interface/component).
+ */
+
+ /**
+ * AsyncSplitControl.start should be called before radio
+ * is switched to Rx mode (or at least early enough before
+ * a packet has been received, i.e. before FIFOP changes)
*/
async command error_t AsyncSplitControl.start()
{
atomic {
+ if ( !call FIFO.get() && !call FIFOP.get() ){
+ // RXFIFO has some data (remember: FIFOP is inverted)
+ // the problem is that this messses up the timestamping
+ // so why don't we flush here ourselves?
+ // because we don't own the SPI...
+ return FAIL;
+ }
if (m_state != S_STOPPED){
call Leds.led0On();
return FAIL;
- } else {
- m_state = S_STARTING;
- if (call SpiResource.isOwner()){
- call Leds.led0On(); // internal error (debug) !
- startingSpiReserved();
- }
- if (call SpiResource.immediateRequest() == SUCCESS)
- startingSpiReserved();
- else
- call SpiResource.request();
}
- }
- return SUCCESS;
- }
-
- void startingSpiReserved()
- {
- atomic {
- if (!call FIFOP.get() || call FIFO.get()){ // FIFOP is inverted
- // there is something in RXFIFO: flush it out
- // the datasheet says at least one byte should
- // be read before flushing
- m_state = S_STARTING_FLUSHRX;
- call CSN.set();
- call CSN.clr();
- call RXFIFO.beginRead( &m_dummy, 1 ); // will continue in continueFlushStart()
- return;
- }
- }
- continueStart();
- }
-
-
- void continueFlushStart()
- {
- atomic {
- call CSN.set();
- call CSN.clr();
- call SFLUSHRX.strobe();
- call SFLUSHRX.strobe();
- call CSN.set();
- }
- continueStart();
- }
-
- void continueStart()
- {
- // RXFIFO is empty
- if (!call FIFOP.get() || call FIFO.get()){
- call Leds.led0On();
- }
- atomic {
reset_state();
m_state = S_STARTED;
+ call InterruptFIFOP.enableFallingEdge(); // ready!
}
- call SpiResource.release();
- call InterruptFIFOP.enableFallingEdge();
- signal AsyncSplitControl.startDone(SUCCESS);
+ return SUCCESS;
}
- /***************** AsyncSplitControl ****************
+ /* AsyncSplitControl.stop:
+ *
* IMPORTANT: when AsyncSplitControl.stop is called,
- * the radio MUST NOT be off !
+ * then either
+ * 1) the radio MUST still be in RxMode
+ * 2) it was never put in RxMode after
+ * AsyncSplitControl.start() was called
+ *
+ * => The radio may be switched off only *after* the
+ * stopDone() event was signalled.
*/
async command error_t AsyncSplitControl.stop()
{
m_stop = TRUE;
call InterruptFIFOP.disable();
if (!receivingPacket)
- continueStop();
- // else stopContinueTask will be posted after
- // current Rx operation is finished, because m_stop is set
+ continueStop(); // it is safe to stop now
+ // else continueStop will be called after
+ // current Rx operation is finished
}
}
return SUCCESS;
void continueStop()
{
atomic {
+ if (!m_stop){
+ return;
+ }
m_stop = FALSE;
m_state = S_STOPPED;
}
task void stopContinueTask()
{
- if (receivingPacket){
+ if (receivingPacket)
call Leds.led0On();
- }
call SpiResource.release(); // may fail
atomic m_state = S_STOPPED;
signal AsyncSplitControl.stopDone(SUCCESS);
atomic {
switch (m_state)
{
- case S_STARTING: startingSpiReserved(); break;
- case S_STARTING_FLUSHRX: // fall through
- case S_STOPPED: call Leds.led0On();
- call SpiResource.release(); break;
+ case S_STOPPED: // this should never happen!
+ call Leds.led0On();
+ call SpiResource.release();
+ break;
default: receive();
}
}
waitForNextPacket();
break;
- case S_STARTING_FLUSHRX: continueFlushStart(); break;
-
default:
atomic receivingPacket = FALSE;
call CSN.set();
*/
void beginReceive() {
atomic {
- if ( m_state == S_STOPPED){
- call Leds.led0On();
+ if (m_state == S_STOPPED || m_stop){
return;
}
m_state = S_RX_LENGTH;
*/
void waitForNextPacket() {
atomic {
- receivingPacket = FALSE;
if ( m_state == S_STOPPED) {
call SpiResource.release();
return;
}
+ receivingPacket = FALSE;
if (m_stop){
continueStop();
return;
--- /dev/null
+/*
+ * Copyright (c) 2005-2006 Arch Rock 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 Arch Rock 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
+ * ARCHED ROCK 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
+ */
+
+/**
+ * Implementation of basic SPI primitives for the ChipCon CC2420 radio.
+ *
+ * Jan Hauer: this component currently shadows
+ * tinyos-2.x/tos/chips/cc2420/spi/CC2420SpiC.nc because the latter
+ * does not (yet) provide access to the RXFIFO via the CC2420Register
+ * interface. As soon as it does, this file should be removed.
+ *
+ * @author Jonathan Hui <jhui@archrock.com>
+ * @version $Revision$ $Date$
+ */
+
+generic configuration CC2420SpiC() {
+
+ provides interface Resource;
+ provides interface ChipSpiResource;
+
+ // commands
+ provides interface CC2420Strobe as SNOP;
+ provides interface CC2420Strobe as SXOSCON;
+ provides interface CC2420Strobe as STXCAL;
+ provides interface CC2420Strobe as SRXON;
+ provides interface CC2420Strobe as STXON;
+ provides interface CC2420Strobe as STXONCCA;
+ provides interface CC2420Strobe as SRFOFF;
+ provides interface CC2420Strobe as SXOSCOFF;
+ provides interface CC2420Strobe as SFLUSHRX;
+ provides interface CC2420Strobe as SFLUSHTX;
+ provides interface CC2420Strobe as SACK;
+ provides interface CC2420Strobe as SACKPEND;
+ provides interface CC2420Strobe as SRXDEC;
+ provides interface CC2420Strobe as STXENC;
+ provides interface CC2420Strobe as SAES;
+
+ // registers
+ provides interface CC2420Register as MAIN;
+ provides interface CC2420Register as MDMCTRL0;
+ provides interface CC2420Register as MDMCTRL1;
+ provides interface CC2420Register as RSSI;
+ provides interface CC2420Register as SYNCWORD;
+ provides interface CC2420Register as TXCTRL;
+ provides interface CC2420Register as RXCTRL0;
+ provides interface CC2420Register as RXCTRL1;
+ provides interface CC2420Register as FSCTRL;
+ provides interface CC2420Register as SECCTRL0;
+ provides interface CC2420Register as SECCTRL1;
+ provides interface CC2420Register as BATTMON;
+ provides interface CC2420Register as IOCFG0;
+ provides interface CC2420Register as IOCFG1;
+ provides interface CC2420Register as MANFIDL;
+ provides interface CC2420Register as MANFIDH;
+ provides interface CC2420Register as FSMTC;
+ provides interface CC2420Register as MANAND;
+ provides interface CC2420Register as MANOR;
+ provides interface CC2420Register as AGCCTRL;
+ provides interface CC2420Register as RXFIFO_REGISTER;
+
+ // ram
+ provides interface CC2420Ram as IEEEADR;
+ provides interface CC2420Ram as PANID;
+ provides interface CC2420Ram as SHORTADR;
+ provides interface CC2420Ram as TXFIFO_RAM;
+
+ // fifos
+ provides interface CC2420Fifo as RXFIFO;
+ provides interface CC2420Fifo as TXFIFO;
+
+}
+
+implementation {
+
+ enum {
+ CLIENT_ID = unique( "CC2420Spi.Resource" ),
+ };
+
+ components HplCC2420PinsC as Pins;
+ components CC2420SpiWireC as Spi;
+
+ ChipSpiResource = Spi.ChipSpiResource;
+ Resource = Spi.Resource[ CLIENT_ID ];
+
+ // commands
+ SNOP = Spi.Strobe[ CC2420_SNOP ];
+ SXOSCON = Spi.Strobe[ CC2420_SXOSCON ];
+ STXCAL = Spi.Strobe[ CC2420_STXCAL ];
+ SRXON = Spi.Strobe[ CC2420_SRXON ];
+ STXON = Spi.Strobe[ CC2420_STXON ];
+ STXONCCA = Spi.Strobe[ CC2420_STXONCCA ];
+ SRFOFF = Spi.Strobe[ CC2420_SRFOFF ];
+ SXOSCOFF = Spi.Strobe[ CC2420_SXOSCOFF ];
+ SFLUSHRX = Spi.Strobe[ CC2420_SFLUSHRX ];
+ SFLUSHTX = Spi.Strobe[ CC2420_SFLUSHTX ];
+ SACK = Spi.Strobe[ CC2420_SACK ];
+ SACKPEND = Spi.Strobe[ CC2420_SACKPEND ];
+ SRXDEC = Spi.Strobe[ CC2420_SRXDEC ];
+ STXENC = Spi.Strobe[ CC2420_STXENC ];
+ SAES = Spi.Strobe[ CC2420_SAES ];
+
+ // registers
+ MAIN = Spi.Reg[ CC2420_MAIN ];
+ MDMCTRL0 = Spi.Reg[ CC2420_MDMCTRL0 ];
+ MDMCTRL1 = Spi.Reg[ CC2420_MDMCTRL1 ];
+ RSSI = Spi.Reg[ CC2420_RSSI ];
+ SYNCWORD = Spi.Reg[ CC2420_SYNCWORD ];
+ TXCTRL = Spi.Reg[ CC2420_TXCTRL ];
+ RXCTRL0 = Spi.Reg[ CC2420_RXCTRL0 ];
+ RXCTRL1 = Spi.Reg[ CC2420_RXCTRL1 ];
+ FSCTRL = Spi.Reg[ CC2420_FSCTRL ];
+ SECCTRL0 = Spi.Reg[ CC2420_SECCTRL0 ];
+ SECCTRL1 = Spi.Reg[ CC2420_SECCTRL1 ];
+ BATTMON = Spi.Reg[ CC2420_BATTMON ];
+ IOCFG0 = Spi.Reg[ CC2420_IOCFG0 ];
+ IOCFG1 = Spi.Reg[ CC2420_IOCFG1 ];
+ MANFIDL = Spi.Reg[ CC2420_MANFIDL ];
+ MANFIDH = Spi.Reg[ CC2420_MANFIDH ];
+ FSMTC = Spi.Reg[ CC2420_FSMTC ];
+ MANAND = Spi.Reg[ CC2420_MANAND ];
+ MANOR = Spi.Reg[ CC2420_MANOR ];
+ AGCCTRL = Spi.Reg[ CC2420_AGCCTRL ];
+ RXFIFO_REGISTER = Spi.Reg[ CC2420_RXFIFO ];
+
+ // ram
+ IEEEADR = Spi.Ram[ CC2420_RAM_IEEEADR ];
+ PANID = Spi.Ram[ CC2420_RAM_PANID ];
+ SHORTADR = Spi.Ram[ CC2420_RAM_SHORTADR ];
+ TXFIFO_RAM = Spi.Ram[ CC2420_RAM_TXFIFO ];
+
+ // fifos
+ RXFIFO = Spi.Fifo[ CC2420_RXFIFO ];
+ TXFIFO = Spi.Fifo[ CC2420_TXFIFO ];
+
+}
+
S_RESERVE_RX_SPI,
S_RX_PREPARED,
+ S_RX_WAIT,
S_RECEIVING,
S_OFF_PENDING,
S_LOAD_TXFIFO,
S_TX_LOADED,
+ S_TX_WAIT,
S_TX_ACTIVE,
S_TX_CANCEL,
S_TX_DONE,
} m_state_t;
norace m_state_t m_state = S_STOPPED;
- norace ieee154_txframe_t *m_txdata;
+ norace ieee154_txframe_t *m_txframe;
norace error_t m_txError;
norace ieee154_reftime_t m_txReferenceTime;
norace bool m_ackFramePending;
uint32_t m_edDuration;
bool m_pibUpdated;
- uint8_t m_numCCA;
+ norace uint8_t m_numCCA;
ieee154_reftime_t *m_t0Tx;
- uint32_t m_dtTx;
+ uint32_t m_dtMax;
+ uint32_t m_dt;
+ norace ieee154_csma_t *m_csmaParams;
norace uint8_t m_txLockOnCCAFail;
norace bool m_rxAfterTx = FALSE;
void rxSpiReserved();
void txSpiReserved();
void txDoneSpiReserved();
- void signalTxDone();
void finishTx();
void stopContinue();
void offSpiReserved();
void offStopRxDone();
- void continueTxPrepare();
+ uint16_t generateRandomBackoff(uint8_t BE);
+ void randomDelayUnslottedCsmaCa();
+ void randomDelaySlottedCsmaCa(bool resume, uint16_t remainingBackoff);
+ void sendDone(ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error);
- /******************************/
- /* StdControl Operations */
- /******************************/
-
- /****************************************/
- /* TelosB Pin connection (debug) */
- /* */
- /* R1 = P6.6 = ADC6, R2 = P6.7 = ADC7 */
- /* S1 = P2.3 = GIO2, S2 = P2.6 = GIO3 */
- /* R1 is at 6pin-expansion pin 1, */
- /* R2 is at 6pin-expansion pin 2, */
- /****************************************/
+/* ----------------------- StdControl Operations ----------------------- */
command error_t SplitControl.start()
{
- // debug
- //P6SEL &= ~0xC0; // debug PIN: 6.6, 6.7, set to I/O function
- //P6DIR |= 0xC0; // output
- //P6OUT &= ~0xC0; // low
-
atomic {
if (m_state == S_RADIO_OFF)
return EALREADY;
{
// default configuration (addresses, etc) has been written
call CC2420Power.rfOff();
+ call CC2420Power.flushRxFifo();
call CC2420Tx.unlockChipSpi();
post startDoneTask();
}
m_state = S_STOPPING;
}
if (m_state != S_STOPPING)
- post stopTask(); // this will not happen, because the caller has switched radio off
+ post stopTask(); // spin - this should not happen, because the caller has switched radio off
else
- if (call RxControl.stop() == EALREADY)
- stopContinue();
+ stopContinue();
}
void stopContinue()
// we own the SPI bus
atomic {
call CC2420Power.rfOff();
- call CC2420Tx.unlockChipSpi();
- call TxControl.stop();
+ call CC2420Power.flushRxFifo();
call CC2420Power.stopOscillator();
call CC2420Power.stopVReg();
+ call CC2420Tx.unlockChipSpi();
call SpiResource.release();
m_state = S_STOPPED;
signal SplitControl.stopDone(SUCCESS);
}
}
- /*********************************/
- /* PIB Updates */
- /*********************************/
+ uint16_t generateRandomBackoff(uint8_t BE)
+ {
+ // return random number from [0,(2^BE) - 1] (uniform distr.)
+ uint16_t res = call Random.rand16();
+ uint16_t mask = 0xFFFF;
+ mask <<= BE;
+ mask = ~mask;
+ res &= mask;
+ return res;
+ }
+
+/* ----------------------- PIB Updates ----------------------- */
// input: power in dBm, output: PA_LEVEL parameter for cc2420 TXCTRL register
uint8_t dBmToPA_LEVEL(int dBm)
call CC2420Config.setPromiscuousMode(val);
}
- /*********************************/
- /* Energy Detection */
- /*********************************/
+/* ----------------------- Energy Detection ----------------------- */
command error_t EnergyDetection.start(uint32_t duration)
{
call CC2420Power.rxOn();
// reading an RSSI value over SPI will usually almost
// take as much time as 8 symbols, i.e. there's
- // no point using an Alarm here (but maybe a BusyWait?)
+ // no point using an Alarm here (but maybe a busy wait?)
while (!call TimeCalc.hasExpired(start, m_edDuration)){
if (call CC2420Power.rssi(&value) != SUCCESS)
continue;
if (maxEnergy > -128)
maxEnergy -= 45;
call CC2420Power.rfOff();
+ call CC2420Power.flushRxFifo();
m_state = S_RADIO_OFF;
call SpiResource.release();
signal EnergyDetection.done(SUCCESS, maxEnergy);
}
- /****************************************/
- /* Transceiver Off */
- /****************************************/
+/* ----------------------- Transceiver Off ----------------------- */
+
+ task void spinOffTask()
+ {
+ uint8_t i;
+ call Leds.led2On(); call Leds.led1On();
+ for (i=0; i<65500U; i++) ;
+ call Leds.led2Off(); call Leds.led1Off();
+ for (i=0; i<65500U; i++) ;
+ call RadioOff.off();
+ }
async command error_t RadioOff.off()
{
atomic {
if (m_state == S_RADIO_OFF)
return EALREADY;
- else if (m_state != S_RECEIVING && m_state != S_TX_LOADED && m_state != S_RX_PREPARED)
+ if (m_state == S_RX_WAIT || m_state == S_TX_WAIT){
+ post spinOffTask();
+ return SUCCESS;
+ } else if (m_state != S_RECEIVING && m_state != S_TX_LOADED && m_state != S_RX_PREPARED)
return FAIL;
m_state = S_OFF_PENDING;
}
{
call TxControl.stop();
call CC2420Power.rfOff();
- call CC2420Config.sync(); // put any PIB updates into operation
+ call CC2420Power.flushRxFifo();
call CC2420Tx.unlockChipSpi();
call SpiResource.release();
m_state = S_RADIO_OFF;
return m_state == S_RADIO_OFF;
}
- /****************************************/
- /* Receive Operations */
- /****************************************/
+/* ----------------------- Receive Operations ----------------------- */
async command error_t RadioRx.prepare()
{
return FAIL;
m_state = S_RESERVE_RX_SPI;
}
- if (call RxControl.start() != SUCCESS){ // will trigger rxStartRxDone()
+ if (call RxControl.start() != SUCCESS){
m_state = S_RADIO_OFF;
call Leds.led0On();
return FAIL;
+ } else {
+ if (call SpiResource.immediateRequest() == SUCCESS) // will trigger rxSpiReserved()
+ rxSpiReserved();
+ else
+ call SpiResource.request();
}
return SUCCESS;
}
- void rxStartRxDone()
- {
- if (call SpiResource.immediateRequest() == SUCCESS) // will trigger rxSpiReserved()
- rxSpiReserved();
- else
- call SpiResource.request();
- }
-
void rxSpiReserved()
{
call CC2420Config.sync(); // put PIB changes into operation
- call TxControl.start(); // for timestamping
+ call TxControl.stop();
+ call TxControl.start(); // for timestamping (SFD interrupt)
m_state = S_RX_PREPARED;
signal RadioRx.prepareDone(); // keep owning the SPI
}
call Leds.led0On();
return FAIL;
}
- if (t0 != NULL && dt)
- call ReliableWait.waitRx(t0, dt);
+ m_state = S_RX_WAIT;
+ if (t0 != NULL)
+ call ReliableWait.waitRx(t0, dt); // will signal waitRxDone() in time
else
signal ReliableWait.waitRxDone();
}
call SpiResource.release();
}
- event message_t* CC2420Rx.received(message_t *data, ieee154_reftime_t *timestamp)
+ event message_t* CC2420Rx.received(message_t *frame, ieee154_reftime_t *timestamp)
{
if (m_state == S_RECEIVING)
- return signal RadioRx.received(data, timestamp);
+ return signal RadioRx.received(frame, timestamp);
else
- return data;
+ return frame;
}
async command bool RadioRx.isReceiving()
return m_state == S_RECEIVING;
}
- /******************************/
- /* Transmit Operations */
- /******************************/
+/* ----------------------- Transmit Operations ----------------------- */
async command error_t RadioTx.load(ieee154_txframe_t *frame)
{
- bool startRxControl;
atomic {
if (m_state != S_RADIO_OFF && m_state != S_TX_LOADED)
return FAIL;
- startRxControl = (m_state == S_RADIO_OFF);
- m_txdata = frame;
+ m_txframe = frame;
m_state = S_LOAD_TXFIFO;
}
- if (!startRxControl)
- continueTxPrepare();
- else if (call RxControl.start() != SUCCESS) // will trigger continueTxPrepare()
- call Leds.led0On();
- return SUCCESS;
- }
-
- void continueTxPrepare()
- {
- if (call SpiResource.immediateRequest() == SUCCESS)
+ if (call SpiResource.isOwner() || call SpiResource.immediateRequest() == SUCCESS)
txSpiReserved();
else
call SpiResource.request(); // will trigger txSpiReserved()
+ return SUCCESS;
}
void txSpiReserved()
{
call CC2420Config.sync();
call TxControl.start();
- if (call CC2420Tx.loadTXFIFO(m_txdata) != SUCCESS)
+ if (call CC2420Tx.loadTXFIFO(m_txframe) != SUCCESS)
call Leds.led0On();
}
async command ieee154_txframe_t* RadioTx.getLoadedFrame()
{
if (m_state == S_TX_LOADED)
- return m_txdata;
+ return m_txframe;
else
return NULL;
}
- async command error_t RadioTx.transmit(ieee154_reftime_t *t0, uint32_t dt, uint8_t numCCA, bool ackRequest)
+ async command error_t RadioTx.transmit(ieee154_reftime_t *t0, uint32_t dt)
+ {
+ // transmit without CCA
+ atomic {
+ if (m_state != S_TX_LOADED)
+ return FAIL;
+ m_numCCA = 0;
+ m_state = S_TX_WAIT;
+ if (t0 != NULL)
+ call ReliableWait.waitTx(t0, dt); // will signal waitTxDone() in time
+ else
+ signal ReliableWait.waitTxDone();
+ }
+ return SUCCESS;
+ }
+
+ void checkEnableRxForACK()
+ {
+ // the packet is currently being transmitted, check if we need the receive logic ready
+ bool ackRequest = (m_txframe->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST) ? TRUE : FALSE;
+ if (ackRequest){
+ // ATTENTION: here the SpiResource is released if ACK is expected
+ // (so Rx part of the driver can take over)
+ call SpiResource.release();
+ if (call RxControl.start() != SUCCESS)
+ call Leds.led0On();
+ }
+ }
+
+ async event void ReliableWait.waitTxDone()
{
+ atomic {
+ m_state = S_TX_ACTIVE;
+ if (call CC2420Tx.send(FALSE) == SUCCESS) // transmit without CCA, this must succeed
+ checkEnableRxForACK();
+ else
+ call Leds.led0On();
+ }
+ }
+
+ async command error_t RadioTx.transmitUnslottedCsmaCa(ieee154_csma_t *csmaParams)
+ {
+ // transmit with single CCA
atomic {
if (m_state != S_TX_LOADED)
return FAIL;
- m_numCCA = numCCA;
- m_t0Tx = t0;
- m_dtTx = dt;
- if (numCCA){
- // for CCA we need to be in Rx mode
- call CC2420Power.rxOn();
- call ReliableWait.busyWait(20); // turnaround + CCA valid time
- if (numCCA == 2){
- // first CCA is done in software (8 symbols after backoff boundary)
- if (t0 != NULL){
- call ReliableWait.waitCCA(t0, dt-IEEE154_aUnitBackoffPeriod-12);
- return SUCCESS;
- }
+ m_csmaParams = csmaParams;
+ m_numCCA = 1;
+ randomDelayUnslottedCsmaCa();
+ }
+ return SUCCESS;
+ }
+
+ void randomDelayUnslottedCsmaCa()
+ {
+ // wait random delay (unslotted CSMA-CA)
+ uint16_t dtTx = generateRandomBackoff(m_csmaParams->BE) * 20;
+ call ReferenceTime.getNow(m_t0Tx, 0);
+ m_state = S_TX_WAIT;
+ call ReliableWait.waitBackoff(m_t0Tx, dtTx);
+ }
+
+ void waitBackoffUnslottedCsmaCaDone()
+ {
+ int8_t dummy;
+ atomic {
+ // CC2420 needs to be in an Rx state for STXONCCA strobe
+ // note: the receive logic of the CC2420 driver is not yet started,
+ // i.e. we will not (yet) receive any packets
+ call CC2420Power.rxOn();
+ m_state = S_TX_ACTIVE;
+ // wait for CC2420 Rx to calibrate + CCA valid time
+ while (call CC2420Power.rssi(&dummy) != SUCCESS)
+ ;
+ // call ReliableWait.busyWait(40);
+ // transmit with single CCA (STXONCCA strobe)
+ if (call CC2420Tx.send(TRUE) == SUCCESS){
+ checkEnableRxForACK();
+ } else {
+ // channel is busy
+ call CC2420Power.rfOff();
+ call CC2420Power.flushRxFifo(); // we might have (accidentally) caught something during CCA
+ m_state = S_TX_LOADED;
+ m_csmaParams->NB += 1;
+ if (m_csmaParams->NB > m_csmaParams->macMaxCsmaBackoffs){
+ // CSMA-CA failure, note: we keep owning the SPI,
+ // our state is back to S_TX_LOADED, the MAC may try to retransmit
+ signal RadioTx.transmitUnslottedCsmaCaDone(m_txframe, FALSE, m_csmaParams, FAIL);
+ } else {
+ // next iteration of unslotted CSMA-CA
+ m_csmaParams->BE += 1;
+ if (m_csmaParams->BE > m_csmaParams->macMaxBE)
+ m_csmaParams->BE = m_csmaParams->macMaxBE;
+ randomDelayUnslottedCsmaCa();
}
}
- signal ReliableWait.waitCCADone();
+ }
+ }
+
+ async command error_t RadioTx.transmitSlottedCsmaCa(ieee154_reftime_t *slot0Time, uint32_t dtMax,
+ bool resume, uint16_t remainingBackoff, ieee154_csma_t *csmaParams)
+ {
+ // slotted CSMA-CA requires very exact timing (transmission on
+ // 320 us backoff boundary), even if we have a sufficiently precise and
+ // accurate clock the CC2420 is not the right radio for
+ // this task because it is accessed over SPI. The code below relies on
+ // platform-specific busy-wait functions that must be adjusted
+ // (through measurements) such that they meet the timing constraints
+ atomic {
+ if (m_state != S_TX_LOADED)
+ return FAIL;
+ m_csmaParams = csmaParams;
+ m_numCCA = 2;
+ m_t0Tx = slot0Time;
+ m_dtMax = dtMax;
+ randomDelaySlottedCsmaCa(resume, remainingBackoff);
}
return SUCCESS;
}
- async event void ReliableWait.waitCCADone()
+ void randomDelaySlottedCsmaCa(bool resume, uint16_t remainingBackoff)
{
- bool cca = call CC2420Tx.cca();
- if (m_numCCA == 2 && !cca){
- // channel is busy
- ieee154_reftime_t now;
- call ReferenceTime.getNow(&now, IEEE154_aUnitBackoffPeriod+12);
- memcpy(&m_txReferenceTime, &now, sizeof(ieee154_reftime_t));
- m_ackFramePending = FALSE;
- m_txError = EBUSY;
- signalTxDone();
- return;
- } else {
- // the second CCA (or first CCA if there's only one) is done in hardware...
- uint16_t offset = 0;
- if (m_numCCA)
- offset = 12;
- if (m_t0Tx)
- call ReliableWait.waitTx(m_t0Tx, m_dtTx-offset);
+ uint16_t dtTx;
+ atomic {
+ dtTx = call TimeCalc.timeElapsed(call ReferenceTime.toLocalTime(m_t0Tx), call LocalTime.get());
+ dtTx += (20 - (dtTx % 20)); // round to backoff boundary
+ if (resume)
+ dtTx += remainingBackoff;
else
- signal ReliableWait.waitTxDone();
+ dtTx = dtTx + (generateRandomBackoff(m_csmaParams->BE) * 20);
+ dtTx += 40; // two backoff periods for the two CCA, the actual tx is scheduled for = m_t0Tx + dtTx
+ if (dtTx > m_dtMax){
+ uint16_t remaining = dtTx - m_dtMax;
+ if (remaining >= 40)
+ remaining -= 40; // substract the two CCA (they don't count for the backoff)
+ else
+ remaining = 0;
+ signal RadioTx.transmitSlottedCsmaCaDone(m_txframe, NULL, FALSE, remaining, m_csmaParams, ERETRY);
+ } else {
+ m_state = S_TX_WAIT;
+ call ReliableWait.waitBackoff(m_t0Tx, dtTx);
+ }
}
}
- async event void ReliableWait.waitTxDone()
+ void waitBackoffSlottedCsmaCaDone()
+ {
+ bool cca;
+ uint16_t dtTx=0;
+ int8_t dummy;
+ atomic {
+ // CC2420 needs to be in an Rx state for STXONCCA strobe
+ // note: the receive logic of the CC2420 driver is not yet started,
+ // i.e. we will not (yet) receive any packets
+ call CC2420Power.rxOn();
+ m_state = S_TX_ACTIVE;
+ // wait for CC2420 Rx to calibrate + CCA valid time
+ while (call CC2420Power.rssi(&dummy) != SUCCESS)
+ ;
+ // perform CCA on slot boundary (or rather 8 symbols after)
+ call ReliableWait.busyWaitSlotBoundaryCCA(m_t0Tx, &dtTx); // platform-specific implementation
+ cca = call CC2420Tx.cca();
+ if (cca && dtTx <= m_dtMax){
+ // Tx in following slot (STXONCCA)
+ call ReliableWait.busyWaitSlotBoundaryTx(m_t0Tx, dtTx+20); // platform-specific implementation
+ if (call CC2420Tx.send(TRUE) == SUCCESS){
+ checkEnableRxForACK();
+ return;
+ } else
+ cca = FALSE;
+ }
+ // did not transmit the frame
+ call CC2420Power.rfOff();
+ call CC2420Power.flushRxFifo(); // we might have (accidentally) caught something
+ m_state = S_TX_LOADED;
+ if (dtTx > m_dtMax)
+ // frame didn't fit into remaining CAP, this can only
+ // be because we couldn't meet the time-constraints
+ // (in principle the frame should have fitted)
+ signal RadioTx.transmitSlottedCsmaCaDone(m_txframe, NULL, FALSE, 0, m_csmaParams, ERETRY);
+ else {
+ // CCA failed
+ m_csmaParams->NB += 1;
+ if (m_csmaParams->NB > m_csmaParams->macMaxCsmaBackoffs){
+ // CSMA-CA failure, note: we keep owning the SPI
+ signal RadioTx.transmitSlottedCsmaCaDone(m_txframe, NULL, FALSE, 0, m_csmaParams, FAIL);
+ } else {
+ // next iteration of slotted CSMA-CA
+ m_csmaParams->BE += 1;
+ if (m_csmaParams->BE > m_csmaParams->macMaxBE)
+ m_csmaParams->BE = m_csmaParams->macMaxBE;
+ randomDelaySlottedCsmaCa(FALSE, 0);
+ }
+ }
+ }
+ }
+
+ async event void ReliableWait.waitBackoffDone()
{
- m_state = S_TX_ACTIVE;
- call CC2420Tx.send(m_numCCA>0); // go (with or without CCA) !
+ if (m_numCCA == 1)
+ waitBackoffUnslottedCsmaCaDone();
+ else
+ waitBackoffSlottedCsmaCaDone();
}
- async event void CC2420Tx.transmissionStarted( ieee154_txframe_t *data )
+ async event void CC2420Tx.transmissionStarted( ieee154_txframe_t *frame )
{
- uint8_t frameType = data->header->mhr[0] & FC1_FRAMETYPE_MASK;
- uint8_t token = data->headerLen;
- signal Timestamp.transmissionStarted(frameType, data->handle, data->payload, token);
+ uint8_t frameType = frame->header->mhr[0] & FC1_FRAMETYPE_MASK;
+ uint8_t token = frame->headerLen;
+ signal Timestamp.transmissionStarted(frameType, frame->handle, frame->payload, token);
}
- async event void CC2420Tx.transmittedSFD(uint32_t time, ieee154_txframe_t *data)
+ async event void CC2420Tx.transmittedSFD(uint32_t time, ieee154_txframe_t *frame)
{
- uint8_t frameType = data->header->mhr[0] & FC1_FRAMETYPE_MASK;
- uint8_t token = data->headerLen;
- signal Timestamp.transmittedSFD(time, frameType, data->handle, data->payload, token);
- // ATTENTION: here we release the SPI, so we can receive a possible ACK
- call SpiResource.release();
+ uint8_t frameType = frame->header->mhr[0] & FC1_FRAMETYPE_MASK;
+ uint8_t token = frame->headerLen;
+ signal Timestamp.transmittedSFD(time, frameType, frame->handle, frame->payload, token);
}
async command void Timestamp.modifyMACPayload(uint8_t token, uint8_t offset, uint8_t* buf, uint8_t len )
async event void CC2420Tx.sendDone(ieee154_txframe_t *frame, ieee154_reftime_t *referenceTime,
bool ackPendingFlag, error_t error)
{
- memcpy(&m_txReferenceTime, referenceTime, sizeof(ieee154_reftime_t));
- m_ackFramePending = ackPendingFlag;
- m_txError = error;
- if (error == EBUSY) // CCA failure, i.e. didn't transmit
- signalTxDone();
- else
- // reset radio
+ if (!call SpiResource.isOwner()){
+ // this can only happen if an ack was requested and we gave up the SPI
+ bool wasAckRequested = (frame->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST) ? TRUE : FALSE;
+ if (!wasAckRequested)
+ call Leds.led0On(); // internal error!
+ memcpy(&m_txReferenceTime, referenceTime, sizeof(ieee154_reftime_t));
+ m_ackFramePending = ackPendingFlag;
+ m_txError = error;
if (call RxControl.stop() != SUCCESS) // will trigger txDoneRxControlStopped()
call Leds.led0On();
+ } else
+ sendDone(referenceTime, ackPendingFlag, error);
}
void txDoneRxControlStopped()
void txDoneSpiReserved()
{
- // switch radio off
- call CC2420Power.rfOff();
- call TxControl.stop();
- call SpiResource.release(); // for RxControl.start to succeed
- if (m_txError == SUCCESS)
- signalTxDone();
- else {
- call TxControl.start();
- call RxControl.start(); // will trigger txDoneRxControlStarted()
- }
+ sendDone(&m_txReferenceTime, m_ackFramePending, m_txError);
}
- void txDoneRxControlStarted()
+ void sendDone(ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error)
{
- m_state = S_TX_DONE;
- call SpiResource.request(); // will trigger signalTxDone()
- }
-
- void signalTxDone()
- {
- // radio is off, Rx component is started, radio is loaded, we own the SPI
- if (m_txError == SUCCESS)
+ uint8_t numCCA = m_numCCA;
+ // transmission complete, we're owning the SPI, Rx logic is disabled
+ call CC2420Power.rfOff();
+ call CC2420Power.flushRxFifo();
+ switch (error)
+ {
+ case SUCCESS:
+ m_state = S_RADIO_OFF;
+ break;
+ case ENOACK:
+ m_state = S_TX_LOADED;
+ break;
+ default:
+ call Leds.led0On(); // internal error!
+ break;
+ }
+ if (error == SUCCESS){
+ call CC2420Tx.unlockChipSpi();
+ call TxControl.stop();
+ call SpiResource.release();
m_state = S_RADIO_OFF;
- else
+ } else
m_state = S_TX_LOADED;
- signal RadioTx.transmitDone(m_txdata, &m_txReferenceTime, m_ackFramePending, m_txError);
+ if (numCCA == 0)
+ signal RadioTx.transmitDone(m_txframe, referenceTime);
+ else if (numCCA == 1)
+ signal RadioTx.transmitUnslottedCsmaCaDone(m_txframe, ackPendingFlag, m_csmaParams, error);
+ else
+ signal RadioTx.transmitSlottedCsmaCaDone(m_txframe, referenceTime, ackPendingFlag, 0, m_csmaParams, error);
}
- /*************/
- /* RxControl */
- /*************/
+/* ----------------------- RxControl ----------------------- */
async event void RxControl.stopDone(error_t error)
{
switch (m_state)
{
case S_OFF_PENDING: offStopRxDone(); break;
- case S_RX_PREPARED: rxStartRxDone(); break;
case S_TX_ACTIVE: txDoneRxControlStopped(); break;
case S_STOPPING: stopContinue(); break;
default: // huh ?
}
}
- async event void RxControl.startDone(error_t error)
- {
- switch (m_state)
- {
- case S_RESERVE_RX_SPI: rxStartRxDone(); break;
- case S_LOAD_TXFIFO: continueTxPrepare(); break;
- case S_TX_ACTIVE: txDoneRxControlStarted(); break;
- default: // huh ?
- call Leds.led0On(); break;
- }
- }
-
- /***********************/
- /* SPI Bus Arbitration */
- /***********************/
+/* ----------------------- SPI Bus Arbitration ----------------------- */
event void SpiResource.granted()
{
case S_LOAD_TXFIFO: txSpiReserved(); break;
case S_TX_ACTIVE: txDoneSpiReserved(); break;
case S_STOPPING: stopReserved(); break;
- case S_TX_DONE: signalTxDone(); break;
case S_OFF_PENDING: offSpiReserved(); break;
default: // huh ?
call Leds.led0On(); break;
* @author David Moss
* @author Jung Il Choi Initial SACK implementation
* @author Jan Hauer <hauer@tkn.tu-berlin.de>
+ *
+ * IMPORTANT: this module does not use the SPI Resource interface,
+ * instead the caller must take care of the resource arbitration
+ * (i.e. the caller must own the resource before calling commands
+ * like CC2420Tx.loadTXFIFO())
+ * Note: on TelosB there seems to be a problem if BackoffAlarm
+ * is virtualized - i.e. BackoffAlarm should be a dedicated Alarm.
+ *
* @version $Revision$ $Date$
*/
provides interface Init;
provides interface AsyncStdControl;
-/* interface CC2420Transmit;*/
provides interface CC2420Tx;
-/* provides interface RadioBackoff;*/
-/* provides interface RadioTimeStamping as TimeStamp;*/
-/* provides interface ReceiveIndicator as EnergyIndicator;*/
-/* provides interface ReceiveIndicator as ByteIndicator;*/
-
-/* uses interface Alarm<T32khz,uint32_t> as BackoffAlarm;*/
uses interface Alarm<T62500hz,uint32_t> as BackoffAlarm;
uses interface GpioCapture as CaptureSFD;
uses interface GeneralIO as CCA;
uses interface GeneralIO as CSN;
uses interface GeneralIO as SFD;
-/* uses interface Resource as SpiResource;*/
uses interface ChipSpiResource;
uses interface CC2420Fifo as TXFIFO;
uses interface CC2420Ram as TXFIFO_RAM;
uses interface CC2420Strobe as SRXON;
uses interface CC2420Strobe as SRFOFF;
uses interface CC2420Strobe as SFLUSHRX;
- uses interface CC2420Strobe as SACKPEND; // JH: ACKs must have pending flag set
+ uses interface CC2420Strobe as SACKPEND;
uses interface CC2420Register as MDMCTRL1;
uses interface CaptureTime;
uses interface ReferenceTime;
S_STOPPED,
S_STARTED,
S_LOAD,
- S_SAMPLE_CCA,
- S_BEGIN_TRANSMIT,
+ S_READY_TX,
S_SFD,
S_EFD,
S_ACK_WAIT,
- S_CANCEL,
} cc2420_transmit_state_t;
- // This specifies how many jiffies the stack should wait after a
+ // This specifies how many symbols the stack should wait after a
// TXACTIVE to receive an SFD interrupt before assuming something is
// wrong and aborting the send. There seems to be a condition
// on the micaZ where the SFD interrupt is never handled.
enum {
- CC2420_ABORT_PERIOD = 320
+ CC2420_ABORT_PERIOD = 320*3,
};
-/* norace message_t *m_msg;*/
- norace ieee154_txframe_t *m_data;
- norace uint8_t m_txFrameLen;
+ norace ieee154_txframe_t *m_frame;
ieee154_reftime_t m_timestamp;
cc2420_transmit_state_t m_state = S_STOPPED;
/** Let the CC2420 driver keep a lock on the SPI while waiting for an ack */
norace bool abortSpiRelease;
- /** Total CCA checks that showed no activity before the NoAck LPL send */
- norace int8_t totalCcaChecks;
-
/** The initial backoff period */
norace uint16_t myInitialBackoff;
/** The congestion backoff period */
norace uint16_t myCongestionBackoff;
+ norace uint32_t alarmStartTime;
/***************** Prototypes ****************/
- error_t load( ieee154_txframe_t *data );
- error_t resend( bool cca );
- void loadTXFIFO();
- void attemptSend(bool cca);
- void congestionBackoff();
- error_t acquireSpiResource();
- error_t releaseSpiResource();
-/* void signalDone( error_t err );*/
void signalDone( bool ackFramePending, error_t err );
-/* void cancelTx();*/
/***************** Init Commands *****************/
command error_t Init.init() {
m_state = S_STOPPED;
call BackoffAlarm.stop();
call CaptureSFD.disable();
-/* call SpiResource.release(); // REMOVE*/
call CSN.set();
}
return SUCCESS;
}
- /**************** Send Commands ****************/
+ /**************** Load/Send Commands ****************/
-/* async command error_t Send.send( message_t* p_msg, bool useCca ) {*/
- async command error_t CC2420Tx.loadTXFIFO(ieee154_txframe_t *data) {
- return load( data);
- }
-
- async command void CC2420Tx.send(bool cca)
+ async command error_t CC2420Tx.loadTXFIFO(ieee154_txframe_t *data)
{
- attemptSend(cca);
- }
-
- async command bool CC2420Tx.cca()
- {
- return call CCA.get();
- }
-
- async command error_t CC2420Tx.modify( uint8_t offset, uint8_t* buf,
- uint8_t len ) {
- call CSN.set();
- call CSN.clr();
- call TXFIFO_RAM.write( offset, buf, len );
- call CSN.set();
+ atomic {
+ if ( m_state != S_STARTED )
+ return FAIL;
+ m_state = S_LOAD;
+ m_frame = data;
+ m_frame->header->length = m_frame->headerLen + m_frame->payloadLen + 2; // 2 for CRC
+ call CSN.set();
+ call CSN.clr();
+ call SFLUSHTX.strobe(); // flush out anything that was in TXFIFO
+ call CSN.set();
+ call CSN.clr();
+ call TXFIFO.write( &(m_frame->header->length), 1 );
+ }
return SUCCESS;
- }
-
- async command void CC2420Tx.lockChipSpi()
+ }
+
+ async event void TXFIFO.writeDone( uint8_t* tx_buf, uint8_t tx_len, error_t error)
{
- abortSpiRelease = TRUE;
+ atomic {
+ call CSN.set();
+ if (tx_buf == &(m_frame->header->length)){
+ call CSN.clr();
+ call TXFIFO.write( m_frame->header->mhr, m_frame->headerLen );
+ return;
+ } else if (tx_buf == m_frame->header->mhr) {
+ call CSN.clr();
+ call TXFIFO.write( m_frame->payload, m_frame->payloadLen );
+ return;
+ }
+ }
+ m_state = S_READY_TX;
+ signal CC2420Tx.loadTXFIFODone(m_frame, error);
}
- async command void CC2420Tx.unlockChipSpi()
+
+ async command error_t CC2420Tx.send(bool cca)
{
- abortSpiRelease = FALSE;
- }
+ cc2420_status_t status;
+ bool congestion = TRUE;
- /***************** Indicator Commands ****************/
-/* command bool EnergyIndicator.isReceiving() {*/
-/* return !(call CCA.get());*/
-/* }*/
-/* */
-/* command bool ByteIndicator.isReceiving() {*/
-/* bool high;*/
-/* atomic high = sfdHigh;*/
-/* return high;*/
-/* }*/
-
+ atomic {
+ if (m_state != S_READY_TX)
+ return EOFF;
+ call CSN.set();
+ call CSN.clr();
- /***************** RadioBackoff Commands ****************/
- /**
- * Must be called within a requestInitialBackoff event
- * @param backoffTime the amount of time in some unspecified units to backoff
- */
-/* async command void RadioBackoff.setInitialBackoff(uint16_t backoffTime) {*/
-/* myInitialBackoff = backoffTime + 1;*/
-/* }*/
-
- /**
- * Must be called within a requestCongestionBackoff event
- * @param backoffTime the amount of time in some unspecified units to backoff
- */
-/* async command void RadioBackoff.setCongestionBackoff(uint16_t backoffTime) {*/
-/* myCongestionBackoff = backoffTime + 1;*/
-/* }*/
-
-/* async command void RadioBackoff.setCca(bool useCca) {*/
-/* }*/
-
-
+ // DEBUG
+ //P2OUT |= 0x40; // P2.6 high
+ status = cca ? call STXONCCA.strobe() : call STXON.strobe();
+ //status = call STXON.strobe();
+ //U0TXBUF = 0x04; // strobe STXON
+ //while (!(IFG1 & URXIFG0));
+ //status = U0RXBUF;
+ //call CSN.set();
+
+ if ( !( status & CC2420_STATUS_TX_ACTIVE ) ) {
+ status = call SNOP.strobe();
+ if ( status & CC2420_STATUS_TX_ACTIVE ) {
+ congestion = FALSE;
+ }
+ }
+
+ call CSN.set();
+ // DEBUG: on telosb SFD is connected to Pin P4.1
+ //if (!congestion) {while (!(P4IN & 0x02)) ; P6OUT &= ~0x80;}
+
+ if (congestion){
+ return FAIL; // channel busy
+ } else {
+ m_state = S_SFD;
+ call BackoffAlarm.start(CC2420_ABORT_PERIOD);
+ return SUCCESS;
+ }
+ }
+ }
/**
* The CaptureSFD event is actually an interrupt from the capture pin
* would have picked up and executed had our microcontroller been fast enough.
*/
async event void CaptureSFD.captured( uint16_t time ) {
- // "time" is from TimerB capture, which is sourced by SMCLK (1MHz)
//P2OUT &= ~0x40; // debug: P2.6 low
- uint32_t localTime;
atomic {
switch( m_state ) {
case S_SFD:
m_state = S_EFD;
sfdHigh = TRUE;
- call CaptureTime.convert(time, &m_timestamp, -8); // -8 for the preamble
call CaptureSFD.captureFallingEdge();
-/* signal TimeStamp.transmittedSFD( time, m_msg );*/
- localTime = call ReferenceTime.toLocalTime(&m_timestamp);
- signal CC2420Tx.transmittedSFD(localTime, m_data );
- //if ( (call CC2420PacketBody.getHeader( m_msg ))->fcf & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
- //if ( (m_data->header)[0] & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
- // This is an ack packet, don't release the chip's SPI bus lock.
- //}
- releaseSpiResource();
+ // timestamp denotes time of first bit (chip) of PPDU on the channel
+ call CaptureTime.convert(time, &m_timestamp, -10); // offset: -10 for 5 bytes (preamble+SFD)
+ m_frame->metadata->timestamp = call ReferenceTime.toLocalTime(&m_timestamp);
call BackoffAlarm.stop();
- m_data->metadata->timestamp = localTime;
-
-
-/* if ( ( ( (call CC2420PacketBody.getHeader( m_msg ))->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7 ) == IEEE154_TYPE_DATA ) {*/
-/* (call CC2420PacketBody.getMetadata( m_msg ))->time = time;*/
-/* }*/
-
if ( call SFD.get() ) {
break;
}
case S_EFD:
sfdHigh = FALSE;
call CaptureSFD.captureRisingEdge();
-
-/* if ( (call CC2420PacketBody.getHeader( m_msg ))->fcf & ( 1 << IEEE154_FCF_ACK_REQ ) ) {*/
- if ( (m_data->header->mhr)[0] & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
+ signal CC2420Tx.transmissionStarted(m_frame);
+ if ( (m_frame->header->mhr)[0] & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
+ // wait for the ACK
m_state = S_ACK_WAIT;
- call BackoffAlarm.start( 200 ); // we need to have *completely* received the ACK
+ alarmStartTime = call BackoffAlarm.getNow();
+ // we need to have *completely* received the ACK, 32+22 symbols
+ // should theroretically be enough, but there can be delays in
+ // servicing the FIFOP interrupt, so we use 100 symbols here
+ call BackoffAlarm.start( 100 );
} else {
signalDone(FALSE, SUCCESS);
}
if ( !m_receiving ) {
sfdHigh = TRUE;
call CaptureSFD.captureFallingEdge();
-/* signal TimeStamp.receivedSFD( time );*/
- call CaptureTime.convert(time, &m_timestamp, -8);
+ call CaptureTime.convert(time, &m_timestamp, -10);
call CC2420Receive.sfd( &m_timestamp );
m_receiving = TRUE;
m_prev_time = time;
// wait for the next interrupt before moving on
return;
}
+ // if we move on, then the timestamp will be invalid!
}
sfdHigh = FALSE;
call CaptureSFD.captureRisingEdge();
m_receiving = FALSE;
-/* if ( time - m_prev_time < 10 ) {*/
-#ifdef PIERCEBOARD_ENABLED
+#ifdef TKN154_PIERCEBOARD
if ( time - m_prev_time < 10*30 ) {
#else
if ( time - m_prev_time < 10 ) {
}
}
}
+
+ async command bool CC2420Tx.cca()
+ {
+ return call CCA.get();
+ }
+
+ async command error_t CC2420Tx.modify( uint8_t offset, uint8_t* buf, uint8_t len )
+ {
+ call CSN.set();
+ call CSN.clr();
+ call TXFIFO_RAM.write( offset, buf, len );
+ call CSN.set();
+ return SUCCESS;
+ }
+
+ async command void CC2420Tx.lockChipSpi()
+ {
+ abortSpiRelease = TRUE;
+ }
+
+ async command void CC2420Tx.unlockChipSpi()
+ {
+ abortSpiRelease = FALSE;
+ }
- /***************** ChipSpiResource Events ****************/
async event void ChipSpiResource.releasing() {
if(abortSpiRelease) {
call ChipSpiResource.abortRelease();
* our send is complete.
*/
async event void CC2420Receive.receive( uint8_t type, message_t *ackFrame ){
-/* async event void CC2420Receive.receive( uint8_t type, message_t* ack_msg ) {*/
-/* cc2420_header_t* ack_header;*/
-/* cc2420_header_t* msg_header;*/
-/* cc2420_metadata_t* msg_metadata;*/
-/* uint8_t* ack_buf;*/
-/* uint8_t length;*/
-
atomic {
if ( type == IEEE154_TYPE_ACK ) {
-
- /* ack_header = call CC2420PacketBody.getHeader( ack_msg );*/
- /* msg_header = call CC2420PacketBody.getHeader( m_msg );*/
-
- /* if ( m_state == S_ACK_WAIT && msg_header->dsn == ack_header->dsn ) {*/
if ( m_state == S_ACK_WAIT &&
- m_data->header->mhr[2] == ((ieee154_header_t*) ackFrame->header)->mhr[2] ) { // compare seqno
+ m_frame->header->mhr[2] == ((ieee154_header_t*) ackFrame->header)->mhr[2] ) { // compare seqno
call BackoffAlarm.stop();
-
- /* msg_metadata = call CC2420PacketBody.getMetadata( m_msg );*/
- /* ack_buf = (uint8_t *) ack_header;*/
- /* length = ack_header->length;*/
- /* */
- /* msg_metadata->ack = TRUE;*/
- /* msg_metadata->rssi = ack_buf[ length - 1 ];*/
- /* msg_metadata->lqi = ack_buf[ length ] & 0x7f;*/
signalDone(( ((ieee154_header_t*) ackFrame->header)->mhr[0] & 0x10) ? TRUE: FALSE, SUCCESS);
}
}
}
}
-
- /***************** SpiResource Events ****************/
- /*
- event void SpiResource.granted() {
- uint8_t cur_state;
-
- atomic {
- cur_state = m_state;
- }
-
- switch( cur_state ) {
- case S_LOAD:
- loadTXFIFO();
- break;
-
- case S_BEGIN_TRANSMIT:
- attemptSend();
- break;
-
- case S_CANCEL:
- cancelTx();
- break;
-
- default:
- releaseSpiResource();
- break;
- }
- }
- */
- /***************** TXFIFO Events ****************/
- /**
- * The TXFIFO is used to load packets into the transmit buffer on the
- * chip
- */
- async event void TXFIFO.writeDone( uint8_t* tx_buf, uint8_t tx_len,
- error_t error ) {
-
- call CSN.set();
-
- if (tx_buf == &m_txFrameLen){
- // until here: 1.65 ms
- call CSN.clr();
- call TXFIFO.write( m_data->header->mhr, m_data->headerLen );
- return;
- } else if (tx_buf == m_data->header->mhr) {
- // until here: 2.2 ms
- call CSN.clr();
- call TXFIFO.write( m_data->payload, m_data->payloadLen );
- return;
- }
- // until here: 4.6 ms (no DMA on USART0)
- // until here: 3.3 ms (with DMA on USART0)
- // P2OUT &= ~0x40; // P2.1 low
-
-/* if ( m_state == S_CANCEL ) {*/
-/* atomic {*/
-/* call CSN.clr();*/
-/* call SFLUSHTX.strobe();*/
-/* call CSN.set();*/
-/* }*/
-/* releaseSpiResource();*/
-/* m_state = S_STARTED;*/
-
-/* } else if ( !m_cca ) {*/
-/* } else {*/
- m_state = S_BEGIN_TRANSMIT;
- releaseSpiResource();
- signal CC2420Tx.loadTXFIFODone(m_data, error);
-/* attemptSend();*/
-/* }*/
-
-/* } else {*/
-/* releaseSpiResource();*/
-/* atomic {*/
-/* if (m_state == S_LOAD_CANCEL) {*/
-/* m_state = S_CCA_CANCEL;*/
-/* } else {*/
-/* m_state = S_SAMPLE_CCA;*/
-/* }*/
-/* }*/
-/* signal CC2420Tx.loadTXFIFODone(m_data, error);*/
-
-/* signal RadioBackoff.requestInitialBackoff(m_msg);*/
-/* call BackoffAlarm.start(myInitialBackoff);*/
-/* }*/
- }
-
-
- async event void TXFIFO.readDone( uint8_t* tx_buf, uint8_t tx_len,
- error_t error ) {
- }
-
-
- /***************** Timer Events ****************/
- /**
- * The backoff timer is mainly used to wait for a moment before trying
- * to send a packet again. But we also use it to timeout the wait for
- * an acknowledgement, and timeout the wait for an SFD interrupt when
- * we should have gotten one.
- */
async event void BackoffAlarm.fired() {
atomic {
switch( m_state ) {
-
- case S_SAMPLE_CCA :
- // sample CCA and wait a little longer if free, just in case we
- // sampled during the ack turn-around window
- if ( call CCA.get() ) {
- m_state = S_BEGIN_TRANSMIT;
- call BackoffAlarm.start( CC2420_TIME_ACK_TURNAROUND );
-
- } else {
- congestionBackoff();
- }
- break;
-
- case S_BEGIN_TRANSMIT:
- case S_CANCEL:
- // should never happen
- call Leds.led0On();
-/* if ( acquireSpiResource() == SUCCESS ) {*/
-/* attemptSend();*/
-/* }*/
- break;
-
- case S_ACK_WAIT:
-/* signalDone( SUCCESS );*/
- signalDone( FALSE, FAIL );
- break;
-
- case S_SFD:
- // We didn't receive an SFD interrupt within CC2420_ABORT_PERIOD
- // jiffies. Assume something is wrong.
- atomic {
- call CSN.set();
- call CSN.clr();
- call SFLUSHTX.strobe();
- call CSN.set();
- }
- signalDone( FALSE, ERETRY );
- releaseSpiResource();
- //call CaptureSFD.captureRisingEdge();
- break;
-
- default:
- break;
- }
- }
- }
-
- /***************** Functions ****************/
- /**
- * Set up a message to be sent. First load it into the outbound tx buffer
- * on the chip, then attempt to send it.
- * @param *p_msg Pointer to the message that needs to be sent
- * @param cca TRUE if this transmit should use clear channel assessment
- */
- error_t load( ieee154_txframe_t *data) {
- atomic {
- if (m_state == S_CANCEL) {
- return ECANCEL;
- }
-
- if ( m_state != S_STARTED ) {
- return FAIL;
- }
-
- m_state = S_LOAD;
-/* m_msg = p_msg;*/
- m_data = data;
- totalCcaChecks = 0;
- }
-
- if ( acquireSpiResource() == SUCCESS ) {
- loadTXFIFO();
- }
-
- return SUCCESS;
- }
-
- /**
- * Resend a packet that already exists in the outbound tx buffer on the
- * chip
- * @param cca TRUE if this transmit should use clear channel assessment
- */
-/* error_t resend( bool cca ) {*/
-
-/* atomic {*/
-/* if (m_state == S_LOAD_CANCEL*/
-/* || m_state == S_CCA_CANCEL*/
-/* || m_state == S_TX_CANCEL) {*/
-/* return ECANCEL;*/
-/* }*/
-/* */
-/* if ( m_state != S_STARTED ) {*/
-/* return FAIL;*/
-/* }*/
-/* */
-/* m_cca = cca;*/
-/* m_state = cca ? S_SAMPLE_CCA : S_BEGIN_TRANSMIT;*/
-/* totalCcaChecks = 0;*/
-/* }*/
-/* */
-/* if(m_cca) {*/
-/* signal RadioBackoff.requestInitialBackoff(m_msg);*/
-/* call BackoffAlarm.start( myInitialBackoff );*/
-/* */
-/* } else if ( acquireSpiResource() == SUCCESS ) {*/
-/* attemptSend();*/
-/* }*/
-/* */
-/* return SUCCESS;*/
-/* }*/
-
- /**
- * Attempt to send the packet we have loaded into the tx buffer on
- * the radio chip. The STXONCCA will send the packet immediately if
- * the channel is clear. If we're not concerned about whether or not
- * the channel is clear (i.e. m_cca == FALSE), then STXON will send the
- * packet without checking for a clear channel.
- *
- * If the packet didn't get sent, then congestion == TRUE. In that case,
- * we reset the backoff timer and try again in a moment.
- *
- * If the packet got sent, we should expect an SFD interrupt to take
- * over, signifying the packet is getting sent.
- */
- void attemptSend(bool cca) {
- uint8_t status;
- bool congestion = TRUE;
- atomic {
- call CSN.set();
- call CSN.clr();
+ case S_SFD:
+ case S_EFD: // fall through
+ // We didn't receive an SFD interrupt within CC2420_ABORT_PERIOD
+ // jiffies. Assume something is wrong.
+ atomic {
+ call CSN.set();
+ call CSN.clr();
+ call SFLUSHTX.strobe();
+ call CSN.set();
+ }
+ signalDone( FALSE, ERETRY );
+ break;
- // STXONCCA costs about ? symbols, i.e. attemptSend should be called
- // ? symbols, before the actual CCA
- //P2OUT |= 0x40; // P2.6 high
- status = cca ? call STXONCCA.strobe() : call STXON.strobe();
- //status = call STXON.strobe();
- //U0TXBUF = 0x04; // strobe STXON
- //while (!(IFG1 & URXIFG0));
- //status = U0RXBUF;
- //call CSN.set();
+ case S_ACK_WAIT:
+ /* signalDone( SUCCESS );*/
+ signalDone( FALSE, ENOACK );
+ break;
- if ( !( status & CC2420_STATUS_TX_ACTIVE ) ) {
- status = call SNOP.strobe();
- if ( status & CC2420_STATUS_TX_ACTIVE ) {
- congestion = FALSE;
- }
- }
-
- call CSN.set();
- // debug: on telosb SFD is connected to Pin P4.1
- if (!congestion) {while (!(P4IN & 0x02)) ; P6OUT &= ~0x80;}
- if (congestion){
- call ReferenceTime.getNow(&m_timestamp, 0);
- m_state = S_BEGIN_TRANSMIT; // don't use a state S_SAMPLE_CCA
- releaseSpiResource();
- signal CC2420Tx.sendDone(m_data, &m_timestamp, FALSE, EBUSY); // waiting for the next send()
- } else {
- m_state = S_SFD; // wait for an ACK
- signal CC2420Tx.transmissionStarted(m_data);
- call BackoffAlarm.start(CC2420_ABORT_PERIOD*3);
+ default:
+ break;
}
- return; // we still own the SPI, either we wait for an ACK or resend is going to be called soon
}
-
-/* if ( congestion ) {*/
-/* totalCcaChecks = 0;*/
-/* releaseSpiResource();*/
-/* congestionBackoff();*/
-/* } else {*/
-/* call BackoffAlarm.start(CC2420_ABORT_PERIOD);*/
-/* }*/
}
-
- /**
- * Congestion Backoff
- */
- void congestionBackoff() {
- atomic {
-/* signal RadioBackoff.requestCongestionBackoff(m_msg);*/
- call BackoffAlarm.start(myCongestionBackoff);
- }
- }
-
- error_t acquireSpiResource() {
- return SUCCESS;
- /*
- error_t error = call SpiResource.immediateRequest();
- if ( error != SUCCESS ) {
- call SpiResource.request();
- }
- return error;
- */
- }
-
- error_t releaseSpiResource() {
- //call SpiResource.release();
- return SUCCESS;
- }
-
-
- /**
- * Setup the packet transmission power and load the tx fifo buffer on
- * the chip with our outbound packet.
- *
- * Warning: the tx_power metadata might not be initialized and
- * could be a value other than 0 on boot. Verification is needed here
- * to make sure the value won't overstep its bounds in the TXCTRL register
- * and is transmitting at max power by default.
- *
- * It should be possible to manually calculate the packet's CRC here and
- * tack it onto the end of the header + payload when loading into the TXFIFO,
- * so the continuous modulation low power listening strategy will continually
- * deliver valid packets. This would increase receive reliability for
- * mobile nodes and lossy connections. The crcByte() function should use
- * the same CRC polynomial as the CC2420's AUTOCRC functionality.
- */
- void loadTXFIFO() {
-/* cc2420_header_t* header = call CC2420PacketBody.getHeader( m_msg );*/
-/* uint8_t tx_power = (call CC2420PacketBody.getMetadata( m_msg ))->tx_power;*/
- m_txFrameLen = m_data->headerLen + m_data->payloadLen + 2;
-/* if ( !tx_power ) {*/
-/* tx_power = CC2420_DEF_RFPOWER;*/
-/* }*/
- call CSN.set();
- call CSN.clr();
- call SFLUSHTX.strobe(); // flush out anything that was in there
- call CSN.set();
- call CSN.clr();
-
-/* call TXFIFO.write( (uint8_t*)header, header->length - 1);*/
- call TXFIFO.write( &m_txFrameLen, 1 );
-
- }
-
void signalDone( bool ackFramePending, error_t err ) {
atomic m_state = S_STARTED;
- signal CC2420Tx.sendDone( m_data, &m_timestamp, ackFramePending, err );
+ signal CC2420Tx.sendDone( m_frame, &m_timestamp, ackFramePending, err );
call ChipSpiResource.attemptRelease();
-/* signal Send.sendDone( m_msg, err );*/
}
-
- /***************** Tasks ****************/
-
- /***************** Defaults ****************/
-/* default async event void TimeStamp.transmittedSFD( uint16_t time, message_t* p_msg ) {*/
-/* }*/
-
-/* default async event void TimeStamp.receivedSFD( uint16_t time ) {*/
-/* }*/
+ async event void TXFIFO.readDone( uint8_t* tx_buf, uint8_t tx_len,
+ error_t error ) {
+ }
}
async command error_t loadTXFIFO(ieee154_txframe_t *data);
async event void loadTXFIFODone(ieee154_txframe_t *data, error_t error );
- async command void send(bool cca);
+ async command error_t send(bool cca);
async event void sendDone(ieee154_txframe_t *frame, ieee154_reftime_t *referenceTime,
bool ackPendingFlag, error_t error);
*/
interface ReliableWait
{
-
async command void busyWait(uint16_t dt);
-
- /*
- * The following command/event pairs are platform-specific
- * busy-waits.
- */
-
async command void waitRx(ieee154_reftime_t *t0, uint16_t dt);
async event void waitRxDone();
- async command void waitCCA(ieee154_reftime_t *t0, uint16_t dt);
- async event void waitCCADone();
async command void waitTx(ieee154_reftime_t *t0, uint16_t dt);
async event void waitTxDone();
+ async command void waitBackoff(ieee154_reftime_t *t0, uint16_t dt);
+ async event void waitBackoffDone();
+
+ async command void busyWaitSlotBoundaryCCA(ieee154_reftime_t *t0, uint16_t *dt);
+ async command void busyWaitSlotBoundaryTx(ieee154_reftime_t *t0, uint16_t dt);
}
call TxControlPool.put(txControl);
}
}
- call Debug.log(LEVEL_INFO, AssociateP_REQUEST, status, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, AssociateP_REQUEST, status, 0, 0);
return status;
}
signal MLME_ASSOCIATE.confirm(0xFFFF, status, 0);
} else {
call ResponseTimeout.startOneShot(call MLME_GET.macResponseWaitTime()*IEEE154_aBaseSuperframeDuration);
- call Debug.log(LEVEL_INFO, AssociateP_SETTIMER,
+ call Debug.log(DEBUG_LEVEL_INFO, AssociateP_SETTIMER,
call MLME_GET.macResponseWaitTime()*IEEE154_aBaseSuperframeDuration, 0, 0);
}
- call Debug.log(LEVEL_INFO, AssociateP_TXDONE, status, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, AssociateP_TXDONE, status, 0, 0);
}
event void ResponseTimeout.fired()
event void DataRequest.pollDone()
{
if (m_associationOngoing){
- call Debug.log(LEVEL_INFO, AssociateP_POLL_DONE, m_payloadAssocRequest[0], m_assocRespStatus, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, AssociateP_POLL_DONE, m_payloadAssocRequest[0], m_assocRespStatus, 0);
call ResponseTimeout.stop();
m_associationOngoing = FALSE;
signal MLME_ASSOCIATE.confirm(m_shortAddress, m_assocRespStatus, 0);
bool m_internalRequest = FALSE;
norace uint8_t m_numBeaconsLost;
- uint8_t m_coordAddress[8];
message_t m_beaconBuffer;
norace message_t *m_beaconBufferPtr = &m_beaconBuffer;
norace bool m_beaconSwapBufferReady = TRUE;
(channelPage != IEEE154_SUPPORTED_CHANNELPAGE) || !call IsBeaconEnabledPAN.getNow())
return IEEE154_INVALID_PARAMETER;
- call Debug.log(LEVEL_INFO,SyncP_REQUEST, logicalChannel, channelPage, trackBeacon);
+ call Debug.log(DEBUG_LEVEL_INFO,0, logicalChannel, channelPage, trackBeacon);
if (!trackBeacon && m_tracking){
// stop tracking after next received beacon
m_stopTracking = TRUE;
m_updateTrackBeacon = trackBeacon;
m_internalRequest = FALSE;
m_updatePending = TRUE;
- call Debug.log(LEVEL_INFO,SyncP_RESOURCE_REQUEST, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO,1, 0, 0, 0);
atomic {
// if we are tracking then we'll get the Token automatically,
// otherwise request it now
event void FindBeacon.notify( bool val )
{
- if (!m_tracking && !m_updatePending){
+ call Debug.log(DEBUG_LEVEL_IMPORTANT,20, m_tracking, m_updatePending, 0);
+ if (!m_tracking && !m_updatePending && !call Token.isOwner()){
// find a single beacon now (treat this like a user request)
m_updateLogicalChannel = call MLME_GET.phyCurrentChannel();
m_updateTrackBeacon = FALSE;
event void Token.granted()
{
- call Debug.log(LEVEL_INFO,SyncP_GOT_RESOURCE, m_lastBeaconRxTime+m_beaconInterval,
+ call Debug.log(DEBUG_LEVEL_INFO,2, m_lastBeaconRxTime+m_beaconInterval,
m_beaconInterval, (m_updatePending<<1)+m_tracking);
if (m_updatePending){
m_state = S_FIRST_SCAN;
m_beaconInterval = ((uint32_t) 1 << m_beaconOrder) * (uint32_t) IEEE154_aBaseSuperframeDuration;
m_dt = m_beaconInterval;
m_numBeaconsLost = IEEE154_aMaxLostBeacons; // will be reset when beacon is received
- call Debug.log(LEVEL_INFO,SyncP_UPDATING, call MLME_GET.macCoordShortAddress(),
+ call Debug.log(DEBUG_LEVEL_INFO,3, call MLME_GET.macCoordShortAddress(),
call MLME_GET.macPANId(), m_updateLogicalChannel);
}
getNextBeacon();
m_state = S_PREPARE;
if (!m_tracking){
// nothing to do, just give up the token
- call Debug.log(LEVEL_INFO,SyncP_RELEASE_RESOURCE, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO,4, 0, 0, 0);
call Token.release();
return;
}
while (call TimeCalc.hasExpired(m_lastBeaconRxTime, m_dt)){ // missed a beacon!
missed = TRUE;
- call Debug.log(LEVEL_INFO,SyncP_BEACON_MISSED_1, m_lastBeaconRxTime, m_dt, missed);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT,5, m_lastBeaconRxTime, m_dt, missed);
m_dt += m_beaconInterval;
m_numBeaconsLost++;
}
if (m_numBeaconsLost >= IEEE154_aMaxLostBeacons){
+ call Debug.log(DEBUG_LEVEL_IMPORTANT,19, m_numBeaconsLost, m_dt, missed);
post processBeaconTask();
return;
}
if (missed){
call Token.request();
- call Debug.log(LEVEL_INFO,SyncP_RELEASE_RESOURCE, m_lastBeaconRxTime, m_dt, missed);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT,6, m_lastBeaconRxTime, m_dt, missed);
call Token.release();
return;
}
async event void TrackAlarm.fired()
{
- call Debug.log(LEVEL_IMPORTANT,SyncP_TRACK_ALARM, m_state,m_lastBeaconRxTime,m_dt);
- atomic {
- switch (m_state)
- {
- case S_PREPARE:
- call BeaconRx.prepare();
- break;
- case S_RADIO_OFF:
- call RadioOff.off();
- break;
- }
+ call Debug.log(DEBUG_LEVEL_INFO,7, m_state,m_lastBeaconRxTime,m_dt);
+ switch (m_state)
+ {
+ case S_PREPARE:
+ call BeaconRx.prepare();
+ break;
+ case S_RADIO_OFF:
+ call RadioOff.off();
+ break;
}
}
} else {
m_state = S_RADIO_OFF;
result = call BeaconRx.receive(&m_lastBeaconRxRefTime, m_dt-RX_LAG);
- call Debug.log(LEVEL_IMPORTANT,SyncP_RX_ON, m_lastBeaconRxTime, call TrackAlarm.getNow(), m_dt+RX_DURATION);
+ //__nesc_enable_interrupt();
+ call Debug.log(DEBUG_LEVEL_INFO,8, m_lastBeaconRxTime, 0,(m_lastBeaconRxTime+m_dt) - call TrackAlarm.getNow());
if (result != SUCCESS)
- call Debug.log(LEVEL_IMPORTANT,SyncP_RADIO_BUSY, result, 0, 0);
+ call Debug.log(DEBUG_LEVEL_CRITICAL,9, result, 0, 0);
call TrackAlarm.startAt(m_lastBeaconRxTime, m_dt + RX_DURATION);
}
}
event message_t* BeaconRx.received(message_t *frame, ieee154_reftime_t *timestamp)
{
uint8_t *mhr = MHR(frame);
- call Debug.log(LEVEL_INFO,SyncP_RX_PACKET,*((nxle_uint32_t*) &mhr[MHR_INDEX_ADDRESS]),
+ call Debug.log(DEBUG_LEVEL_INFO,10,*((nxle_uint32_t*) &mhr[MHR_INDEX_ADDRESS]),
mhr[MHR_INDEX_FC1] & FC1_FRAMETYPE_MASK,mhr[MHR_INDEX_SEQNO]);
if (!m_beaconSwapBufferReady || !call FrameUtility.isBeaconFromCoord(frame))
{
- call Debug.log(LEVEL_IMPORTANT,SyncP_RX_GARBAGE, m_beaconSwapBufferReady, 0, 0);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT,11, m_beaconSwapBufferReady, 0, 0);
return frame;
} else {
+ error_t resultOff;
message_t *tmp = m_beaconBufferPtr;
call TrackAlarm.stop();
m_beaconSwapBufferReady = FALSE;
m_beaconBufferPtr = frame;
- if (timestamp != NULL)
+ resultOff = call RadioOff.off();
+ if (timestamp != NULL){
memcpy(&m_lastBeaconRxRefTime, timestamp, sizeof(ieee154_reftime_t));
- call RadioOff.off();
+ call Debug.log(DEBUG_LEVEL_INFO,23,0, 0, resultOff);
+ }
return tmp;
}
}
{
if (m_state == S_FIRST_SCAN)
call BeaconRx.prepare();
- else if (m_state == S_PREPARE)
- call TrackAlarm.startAt(m_lastBeaconRxTime, m_dt - IEEE154_RADIO_RX_PREPARE_DELAY);
- else
+ else if (m_state == S_PREPARE){
+ if (!call TimeCalc.hasExpired(m_lastBeaconRxTime, m_dt - IEEE154_RADIO_RX_PREPARE_DELAY))
+ call TrackAlarm.startAt(m_lastBeaconRxTime, m_dt - IEEE154_RADIO_RX_PREPARE_DELAY);
+ else
+ signal TrackAlarm.fired();
+ } else {
post processBeaconTask();
+ }
}
task void processBeaconTask()
// valid beacon timestamp is pre-condition for slotted CSMA-CA
if (m_beaconSwapBufferReady || !call Frame.isTimestampValid(m_beaconBufferPtr)){
// missed a beacon!
+ if (!m_beaconSwapBufferReady)
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 21,m_numBeaconsLost,m_beaconSwapBufferReady,m_lastBeaconRxTime);
+ else
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 12,m_numBeaconsLost,m_beaconSwapBufferReady,m_lastBeaconRxTime);
m_sfSlotDuration = 0; // CAP len will be 0
m_numBeaconsLost++;
m_dt += m_beaconInterval;
- call Debug.log(LEVEL_IMPORTANT, SyncP_BEACON_MISSED_3,m_numBeaconsLost,0,m_lastBeaconRxTime);
+ m_beaconSwapBufferReady = TRUE;
if (m_numBeaconsLost >= IEEE154_aMaxLostBeacons){
m_tracking = FALSE;
- call Debug.log(LEVEL_IMPORTANT, SyncP_LOST_SYNC,0,0,0);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 13,m_internalRequest,0,0);
call Leds.led2Off();
- if (m_internalRequest)
+ if (m_internalRequest){
call TokenToCap.transfer();
- else
+ return;
+ } else
signal MLME_SYNC_LOSS.indication(
IEEE154_BEACON_LOSS,
call MLME_GET.macPANId(),
);
} else
call Token.request(); // make another request again (before giving the token up)
- call Debug.log(LEVEL_INFO,SyncP_RELEASE_RESOURCE, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO,14, 0, 0, 0);
call Token.release();
} else {
// got the beacon!
uint8_t gtsFieldLength;
uint32_t timestamp = call Frame.getTimestamp(m_beaconBufferPtr);
- call Debug.log(LEVEL_INFO, SyncP_BEACON_RX, m_lastBeaconRxTime, timestamp, mhr[2]);
+ call Debug.log(DEBUG_LEVEL_INFO, 15, m_lastBeaconRxTime, timestamp, mhr[2]);
m_numGtsSlots = (payload[2] & 7);
gtsFieldLength = 1 + ((m_numGtsSlots > 0) ? 1 + m_numGtsSlots * 3: 0);
m_lastBeaconRxTime = timestamp;
m_BLELen += call MLME_GET.macMinLIFSPeriod();
else
m_BLELen += call MLME_GET.macMinSIFSPeriod();
- m_BLELen += call MLME_GET.macBattLifeExtPeriods();
+ m_BLELen = m_BLELen + call MLME_GET.macBattLifeExtPeriods() * 20;
} else
m_BLELen = 0;
m_broadcastPending = mhr[MHR_INDEX_FC1] & FC1_FRAME_PENDING ? TRUE : FALSE;
m_dt = m_beaconInterval = ((uint32_t) 1 << coordBeaconOrder) * (uint32_t) IEEE154_aBaseSuperframeDuration;
if (m_stopTracking){
m_tracking = FALSE;
- call Debug.log(LEVEL_INFO,SyncP_RELEASE_RESOURCE, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO,16, 0, 0, 0);
if (m_updatePending) // there is already a new request pending...
call Token.request();
call Token.release();
} else {
- call Debug.log(LEVEL_INFO,SyncP_TRANSFER_RESOURCE, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO,17, 0, 0, 0);
call TokenToCap.transfer(); // borrow Token to CAP/CFP module, we'll get it back afterwards
}
call DataRequest.poll(CoordAddrMode, CoordPANId, CoordAddress, SrcAddrMode);
}
// Beacon Tracking: update state
- call Debug.log(LEVEL_INFO, SyncP_NEXT_RX_TIME, 0, timestamp, m_beaconInterval);
+ call Debug.log(DEBUG_LEVEL_INFO, 18, m_lastBeaconRxTime, m_beaconInterval, 0);
m_numBeaconsLost = 0;
// TODO: check PAN ID conflict here?
if (!autoRequest || beaconPayloadSize)
status = IEEE154_SUCCESS;
if (panCoordinator)
startTime = 0; // start immediately
- call Debug.log(LEVEL_INFO, StartP_REQUEST, logicalChannel, beaconOrder, superframeOrder);
+ call Debug.log(DEBUG_LEVEL_INFO, 0, logicalChannel, beaconOrder, superframeOrder);
if (beaconOrder == 15){
// beaconless PAN
superframeOrder = 15;
event void Token.granted()
{
call Debug.flush();
- call Debug.log(LEVEL_INFO, StartP_GOT_RESOURCE, m_lastBeaconTxTime, m_beaconInterval, m_requests);
+ call Debug.log(DEBUG_LEVEL_INFO, 1, m_lastBeaconTxTime, m_beaconInterval, m_requests);
if (m_requests & REQUEST_REALIGNMENT_DONE_PENDING){
// unlikely to occur: we have not yet received a done()
// event after sending out a realignment frame
if (m_requests & REQUEST_UPDATE_SF){
m_requests &= ~REQUEST_UPDATE_SF;
continueStartRequest();
- call Debug.log(LEVEL_INFO, StartP_UPDATE_STATE, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, 2, 0, 0, 0);
}
if (call RadioOff.isOff())
prepareNextBeaconTransmission();
if (m_txState == S_TX_LOCKED){
// have not had time to finish processing the last sent beacon
post grantedTask();
- call Debug.log(LEVEL_CRITICAL, StartP_OWNER_TOO_FAST, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 3, 0, 0, 0);
return;
} else if (m_beaconOrder == 15){
call Token.release();
// the usual case: next beacon tx time = last time + BI
m_dt = m_beaconInterval;
}
- while (call TimeCalc.hasExpired(m_lastBeaconTxTime, m_dt)){ // missed sending a beacon
- call Debug.log(LEVEL_INFO, StartP_SKIPPED_BEACON, m_lastBeaconTxTime, m_dt, 0);
+ while (call TimeCalc.hasExpired(m_lastBeaconTxTime, m_dt)){ // skipped a beacon
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 4, m_lastBeaconTxTime, m_dt, 0);
m_dt += m_beaconInterval;
}
if (m_dt < IEEE154_RADIO_TX_PREPARE_DELAY)
else
m_beaconFrame.header->mhr[MHR_INDEX_FC1] &= ~FC1_FRAME_PENDING;
m_beaconFrame.header->mhr[MHR_INDEX_SEQNO] = m_bsn; // update beacon seqno
- call Debug.log(LEVEL_INFO, StartP_PREPARE_TX, 0, m_lastBeaconTxTime, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, 5, 0, m_lastBeaconTxTime, 0);
call BeaconTx.load(&m_beaconFrame);
break;
case S_TX_LOCKED:
- call Debug.log(LEVEL_INFO, StartP_TRANSMIT, m_lastBeaconTxTime, m_dt, ((uint32_t)m_lastBeaconTxRefTime));
- call BeaconTx.transmit(&m_lastBeaconTxRefTime, m_dt, 0, FALSE);
+ call Debug.log(DEBUG_LEVEL_INFO, 6, m_lastBeaconTxTime, m_dt, 0);
+ call BeaconTx.transmit(&m_lastBeaconTxRefTime, m_dt);
break;
}
}
async event void BeaconTx.loadDone()
{
atomic {
- call Debug.log(LEVEL_INFO, StartP_PREPARE_TXDONE, 0, m_lastBeaconTxTime, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, 7, 0, m_lastBeaconTxTime, 0);
if (m_txOneBeaconImmediately){
m_txOneBeaconImmediately = FALSE;
- call BeaconTx.transmit(0, 0, 0, FALSE); // now!
+ call BeaconTx.transmit(NULL, 0); // now!
} else
call BeaconTxAlarm.startAt(m_lastBeaconTxTime, m_dt - IEEE154_RADIO_TX_SEND_DELAY);
}
}
-
- async event void BeaconTx.transmitDone(ieee154_txframe_t *frame,
- ieee154_reftime_t *referenceTime, bool pendingFlag, error_t error)
+ async event void BeaconTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime)
{
// Coord CAP has just started...
uint8_t gtsFieldLength;
// Sec. 7.5.1.1: "start of slot 0 is defined as the point at which
// the first symbol of the beacon PPDU is transmitted"
- call Debug.log(LEVEL_INFO, StartP_BEACON_TRANSMITTED, frame->metadata->timestamp, m_lastBeaconTxTime, m_dt);
+ call Debug.log(DEBUG_LEVEL_INFO, 8, frame->metadata->timestamp, m_lastBeaconTxTime, m_dt);
m_lastBeaconTxTime = frame->metadata->timestamp;
- memcpy(&m_lastBeaconTxRefTime, referenceTime, sizeof(ieee154_reftime_t));
+ memcpy(&m_lastBeaconTxRefTime, txTime, sizeof(ieee154_reftime_t));
m_numGtsSlots = (frame->payload[2] & 0x07);
gtsFieldLength = 1 + ((m_numGtsSlots > 0) ? 1 + m_numGtsSlots * 3: 0);
m_finalCAPSlot = (frame->payload[1] & 0x0F);
if (frame->payload[1] & 0x10){
// BLE is active; calculate the time offset from slot0
m_BLELen = IEEE154_SHR_DURATION +
- (frame->headerLen + frame->payloadLen) * IEEE154_SYMBOLS_PER_OCTET;
- if (frame->headerLen + frame->payloadLen > IEEE154_aMaxSIFSFrameSize)
+ (frame->headerLen + frame->payloadLen + 2) * IEEE154_SYMBOLS_PER_OCTET;
+ if (frame->headerLen + frame->payloadLen + 2 > IEEE154_aMaxSIFSFrameSize)
m_BLELen += IEEE154_MIN_LIFS_PERIOD;
else
m_BLELen += IEEE154_MIN_SIFS_PERIOD;
- m_BLELen += m_battLifeExtPeriods;
+ m_BLELen = m_BLELen + m_battLifeExtPeriods * 20;
} else
m_BLELen = 0;
call TokenToBroadcast.transfer(); // borrow Token to Broadcast/CAP/CFP module, we'll get it back afterwards
atomic {
if (m_txState == S_TX_LOCKED)
{
- call Debug.log(LEVEL_INFO, StartP_BEACON_UPDATE, 0, 0, m_txState);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 10, 0, 0, m_txState);
return; // too late !
}
if (m_payloadState & MODIFIED_PENDING_ADDR_FIELD){
atomic {
if (m_txState == S_TX_LOCKED)
{
- call Debug.log(LEVEL_INFO, StartP_BEACON_UPDATE_2, 0, 0, m_txState);
+ call Debug.log(DEBUG_LEVEL_INFO, 11, 0, 0, m_txState);
return; // too late !
}
if (m_payloadState & MODIFIED_BEACON_PAYLOAD){
async command uint32_t SfSlotDuration.getNow() { return m_sfSlotDuration; }
async command uint8_t FinalCapSlot.getNow() { return m_finalCAPSlot; }
async command uint8_t NumGtsSlots.getNow() { return m_numGtsSlots; }
+ async event void BeaconTx.transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result){}
+ async event void BeaconTx.transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParams, error_t result){}
+
default event void MLME_START.confirm (
ieee154_status_t status
+++ /dev/null
-/*
- * Copyright (c) 2008, Technische Universitaet Berlin
- * 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 Technische Universitaet Berlin 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 COPYRIGHT
- * OWNER OR 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.
- *
- * - Revision -------------------------------------------------------------
- * $Revision$
- * $Date$
- * @author Jan Hauer <hauer@tkn.tu-berlin.de>
- * ========================================================================
- */
-
-#include "TKN154_PHY.h"
-#include "TKN154_MAC.h"
-
-/**
- * This module implements the slotted and unslotted CSMA-CA algorithm.
- * Unslotted CSMA-CA is used in nonbeacon-enabled PANs, slotted CSMA-CA is used
- * in beacon-enabled PANs. In a beacon-enabled PAN this module is responsible
- * for channel access during the contention access period (CAP). It does
- * slightly different things depending on whether it is the CAP for an outgoing
- * superframe (superframeDirection = OUTGOING_SUPERFRAME), i.e. the CAP from
- * the perspective of a coordinator after it has transmitted its own beacon; or
- * for an incoming superframe (superframeDirection = INCOMING_SUPERFRAME), i.e.
- * the CAP from the perspective of a device after it has received a beacon from
- * its coordinator; for example, in the CAP a coordinator will usually listen for
- * incoming frames from the devices, and a device will usually switch the radio
- * off unless it has a frame to transmit. In nonbeacon-enabled PANs the
- * superframeDirection parameter is ignored.
- */
-
-generic module CsmaP(uint8_t superframeDirection)
-{
- provides
- {
- interface Init as Reset;
- interface FrameTx as FrameTx;
- interface FrameRx as FrameRx[uint8_t frameType];
- interface FrameExtracted as FrameExtracted[uint8_t frameType];
- interface FrameTxNow as BroadcastTx;
- interface Notify<bool> as WasRxEnabled;
- interface Notify<bool> as FindBeacon;
- }
- uses
- {
- interface Random;
- interface Alarm<TSymbolIEEE802154,uint32_t> as CapEndAlarm;
- interface Alarm<TSymbolIEEE802154,uint32_t> as BLEAlarm;
- interface Alarm<TSymbolIEEE802154,uint32_t> as IndirectTxWaitAlarm;
- interface Alarm<TSymbolIEEE802154,uint32_t> as BroadcastAlarm;
- interface Resource as Token;
- interface GetNow<bool> as IsTokenRequested;
- interface ResourceTransfer as TokenToCfp;
- interface ResourceTransferred as TokenTransferred;
- interface GetNow<uint32_t> as CapStart;
- interface GetNow<ieee154_reftime_t*> as CapStartRefTime;
- interface GetNow<uint32_t> as CapLen;
- interface GetNow<bool> as IsBLEActive;
- interface GetNow<uint16_t> as BLELen;
- interface GetNow<bool> as IsRxBroadcastPending;
- interface GetNow<bool> as IsRxEnableActive;
- interface Notify<bool> as RxEnableStateChange;
- interface GetNow<bool> as IsTrackingBeacons;
- interface FrameUtility;
- interface RadioTx;
- interface RadioRx;
- interface RadioOff;
- interface GetNow<bool> as IsBeaconEnabledPAN;
- interface MLME_GET;
- interface MLME_SET;
- interface Ieee802154Debug as Debug;
- interface TimeCalc;
- interface Leds;
- interface SetNow<ieee154_cap_frame_backup_t*> as FrameBackup;
- interface GetNow<ieee154_cap_frame_backup_t*> as FrameRestore;
- }
-}
-implementation
-{
- typedef enum {
- SWITCH_OFF,
- LOAD_TX,
- PREPARE_RX,
- DO_NOTHING,
- WAIT_FOR_TXDONE,
- } next_state_t;
-
- typedef enum {
- INDIRECT_TX_ALARM,
- BROADCAST_ALARM,
- NO_ALARM,
- } rx_alarm_t;
-
- enum {
- COORD_ROLE = (superframeDirection == OUTGOING_SUPERFRAME),
- DEVICE_ROLE = !COORD_ROLE,
- };
-
- norace bool m_lock;
- norace ieee154_txframe_t *m_currentFrame;
- norace ieee154_txframe_t *m_bcastFrame;
- norace ieee154_txframe_t *m_lastFrame;
- norace ieee154_macMaxBE_t m_BE;
- norace ieee154_macMaxBE_t m_NB;
- norace ieee154_macMaxBE_t m_numCCA;
- norace ieee154_macMaxCSMABackoffs_t m_macMaxCSMABackoffs;
- norace ieee154_macMaxFrameRetries_t m_macMaxFrameRetries;
- norace ieee154_macMaxBE_t m_macMaxBE;
- norace ieee154_macMinBE_t m_macMinBE;
- norace uint16_t m_backoff;
- norace uint16_t m_backoffElapsed;
- norace ieee154_status_t m_result;
- norace uint32_t m_transactionTime;
- norace bool m_indirectTxPending = FALSE;
- norace bool m_broadcastRxPending;
- norace ieee154_macMaxFrameTotalWaitTime_t m_macMaxFrameTotalWaitTime;
-
- uint16_t generateRandomBackoff(uint8_t BE);
- void stopAllAlarms();
- next_state_t tryReceive(rx_alarm_t alarmType);
- next_state_t tryTransmit();
- next_state_t trySwitchOff();
- void backupCurrentFrame();
- void restoreFrameFromBackup();
- void updateState();
- void setCurrentFrame(ieee154_txframe_t *frame);
- void signalTxBroadcastDone(ieee154_txframe_t *frame, ieee154_status_t error);
- task void signalTxDoneTask();
- task void setupTxBroadcastTask();
- task void wasRxEnabledTask();
-
- command error_t Reset.init()
- {
- if (m_currentFrame)
- signal FrameTx.transmitDone(m_currentFrame, IEEE154_TRANSACTION_OVERFLOW);
- if (m_lastFrame)
- signal FrameTx.transmitDone(m_lastFrame, IEEE154_TRANSACTION_OVERFLOW);
- if (m_bcastFrame)
- signalTxBroadcastDone(m_bcastFrame, IEEE154_TRANSACTION_OVERFLOW);
- m_currentFrame = m_lastFrame = m_bcastFrame = NULL;
- stopAllAlarms();
- return SUCCESS;
- }
-
- async event void TokenTransferred.transferred()
- {
- // we got the token, i.e. CAP has just started
- uint32_t actualCapLen = call CapLen.getNow();
- if (!call IsBeaconEnabledPAN.getNow()){
- call Leds.led0On(); // internal error!
- call TokenToCfp.transfer();
- call Debug.log(LEVEL_IMPORTANT, CapP_INTERNAL_ERROR, 0,0,0);
- } else if (DEVICE_ROLE && actualCapLen == 0){
- // very rare case:
- // this can only happen, if we're on a beacon-enabled PAN, not tracking beacons,
- // and searched but didn't find a beacon for aBaseSuperframeDuration*(2n+1) symbols
- // -> transmit current frame using unslotted CSMA-CA
- m_numCCA = 1;
- updateState();
- return;
- } else if (actualCapLen < IEEE154_RADIO_GUARD_TIME){
- call Debug.log(LEVEL_IMPORTANT, CapP_TOO_SHORT, superframeDirection, actualCapLen, IEEE154_RADIO_GUARD_TIME);
- call TokenToCfp.transfer();
- return;
- } else {
- actualCapLen -= IEEE154_RADIO_GUARD_TIME;
- if (DEVICE_ROLE)
- m_broadcastRxPending = call IsRxBroadcastPending.getNow();
- else {
- // COORD_ROLE
- if (m_bcastFrame != NULL) {
- // we have to transmit a broadcast frame immediately; this
- // (possibly) requires a backup of the previously active frame
- // and a reinitializing the CSMA parameters -> will do it
- // in task context and then continue
- m_lock = TRUE;
- post setupTxBroadcastTask();
- }
- }
- call CapEndAlarm.startAt(call CapStart.getNow(), actualCapLen);
- if (call IsBLEActive.getNow())
- call BLEAlarm.startAt(call CapStart.getNow(), call BLELen.getNow());
- call Debug.log(LEVEL_IMPORTANT, CapP_SET_CAP_END, call CapStart.getNow(),
- actualCapLen, call CapStart.getNow()+ actualCapLen);
- }
- updateState();
- }
-
- command ieee154_status_t FrameTx.transmit(ieee154_txframe_t *frame)
- {
- if (m_currentFrame != NULL)
- return IEEE154_TRANSACTION_OVERFLOW;
- else {
- setCurrentFrame(frame);
- if (!call IsBeaconEnabledPAN.getNow()){
- call Token.request(); // prepare for unslotted CSMA-CA
- } else {
- // a beacon must be found before transmitting in a beacon-enabled PAN
- if (DEVICE_ROLE && !call IsTrackingBeacons.getNow()){
- signal FindBeacon.notify(TRUE);
- // we'll receive the Token at latest after aBaseSuperframeDuration*(2n+1) symbols;
- // if the beacon was not found, then we'll send the frame using unslotted CSMA-CA
- }
- updateState();
- }
- return IEEE154_SUCCESS;
- }
- }
-
- task void setupTxBroadcastTask()
- {
- ieee154_macDSN_t tmp;
- ieee154_txframe_t *oldFrame = m_currentFrame;
- if (COORD_ROLE){
- if (m_bcastFrame != NULL){
- // broadcasts should be transmitted *immediately* after the beacon,
- // which may interrupt a pending transmit operation from the previous
- // CAP; back up the last active frame configuration (may be none)
- // and restore it after the broadcast frame has been transmitted;
- // do this through interfaces and don't wire them for DEVICE_ROLE,
- // so we don't waste the RAM of devices
- backupCurrentFrame();
- setCurrentFrame(m_bcastFrame);
- if (oldFrame){
- // now the sequence number are out of order... swap them back
- tmp = m_bcastFrame->header->mhr[MHR_INDEX_SEQNO];
- m_bcastFrame->header->mhr[MHR_INDEX_SEQNO] =
- oldFrame->header->mhr[MHR_INDEX_SEQNO];
- oldFrame->header->mhr[MHR_INDEX_SEQNO] = tmp;
- }
- }
- }
- m_lock = FALSE;
- updateState();
- }
-
- void setCurrentFrame(ieee154_txframe_t *frame)
- {
- ieee154_macDSN_t dsn = call MLME_GET.macDSN();
- frame->header->mhr[MHR_INDEX_SEQNO] = dsn++;
- call MLME_SET.macDSN(dsn);
- m_macMaxCSMABackoffs = call MLME_GET.macMaxCSMABackoffs();
- m_macMaxFrameRetries = call MLME_GET.macMaxFrameRetries();
- m_macMaxBE = call MLME_GET.macMaxBE();
- m_macMinBE = call MLME_GET.macMinBE();
- if (call MLME_GET.macBattLifeExt() && m_macMinBE > 2)
- m_macMinBE = 2;
- m_BE = m_macMinBE;
- if (call IsBeaconEnabledPAN.getNow())
- m_numCCA = 2;
- else
- m_numCCA = 1;
- m_NB = 0;
- m_transactionTime = IEEE154_SHR_DURATION +
- (frame->headerLen + frame->payloadLen) * IEEE154_SYMBOLS_PER_OCTET;
- if (frame->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST)
- m_transactionTime += (IEEE154_aTurnaroundTime + IEEE154_aUnitBackoffPeriod +
- 11 * IEEE154_SYMBOLS_PER_OCTET);
- if (frame->headerLen + frame->payloadLen > IEEE154_aMaxSIFSFrameSize)
- m_transactionTime += call MLME_GET.macMinLIFSPeriod();
- else
- m_transactionTime += call MLME_GET.macMinSIFSPeriod();
- m_backoff = generateRandomBackoff(m_BE) * IEEE154_aUnitBackoffPeriod; // initial backoff
- m_macMaxFrameTotalWaitTime = call MLME_GET.macMaxFrameTotalWaitTime();
- m_backoffElapsed = 0;
- m_currentFrame = frame;
- }
-
- uint16_t generateRandomBackoff(uint8_t BE)
- {
- // return random number from [0,(2^BE) - 1] (uniform distr.)
- uint16_t res = call Random.rand16();
- uint16_t mask = 0xFFFF;
- mask <<= BE;
- mask = ~mask;
- res &= mask;
- return res;
- }
-
- void stopAllAlarms()
- {
- call CapEndAlarm.stop();
- if (DEVICE_ROLE){
- call IndirectTxWaitAlarm.stop();
- call BroadcastAlarm.stop();
- }
- call BLEAlarm.stop();
- }
-
- /**
- * The updateState() function is called whenever some event happened that
- * might require a state change; it implements a lock mechanism (m_lock) to
- * prevent race conditions. Whenever the lock is set a "done"-event (from a
- * RadioTx/RadioRx/RadioOff interface) is pending and will "soon" unset the
- * lock (and then updateState() will called again). The updateState()
- * function decides about the next state by checking a list of possible
- * current states ordered by priority, e.g. it first always checks whether
- * the CAP is still active. Calling this function more than necessary can do
- * no harm, but it SHOULD be called whenever an event happened that might
- * lead to a state change.
- */
-
- void updateState()
- {
- error_t result = SUCCESS;
- next_state_t next;
- atomic {
- // long atomics are bad... but in this block, once the
- // current state has been determined only one branch will
- // be taken (no loops, etc.)
- if (m_lock || !call Token.isOwner())
- return;
- m_lock = TRUE; // lock
-
- // Check 1: for beacon-enabled PANs, has the CAP finished?
- if (call IsBeaconEnabledPAN.getNow()
- && (COORD_ROLE || call IsTrackingBeacons.getNow()) // FALSE only if device could't find a beacon
- && (call TimeCalc.hasExpired(call CapStart.getNow(), call CapLen.getNow()-IEEE154_RADIO_GUARD_TIME) ||
- !call CapEndAlarm.isRunning())){
- if (call RadioOff.isOff()) {
- stopAllAlarms(); // may still fire, locked through isOwner()
- if (DEVICE_ROLE && m_indirectTxPending)
- signal IndirectTxWaitAlarm.fired();
- m_broadcastRxPending = FALSE;
- if (COORD_ROLE && m_bcastFrame){
- // didn't manage to transmit a broadcast
- restoreFrameFromBackup();
- signalTxBroadcastDone(m_bcastFrame, IEEE154_CHANNEL_ACCESS_FAILURE);
- m_bcastFrame = NULL;
- }
- m_lock = FALSE; // unlock
- call TokenToCfp.transfer();
- return;
- } else
- next = SWITCH_OFF;
- }
-
- // Check 2: should a broadcast frame be received/transmitted immediately
- // at the start of CAP?
- else if (DEVICE_ROLE && m_broadcastRxPending){
- // receive a broadcast from coordinator
- next = tryReceive(BROADCAST_ALARM);
- } else if (COORD_ROLE && m_bcastFrame){
- next = tryTransmit();
- }
-
- // Check 3: was an indirect transmission successfully started
- // and are we now waiting for a frame from the coordinator?
- else if (DEVICE_ROLE && m_indirectTxPending) {
- next = tryReceive(INDIRECT_TX_ALARM);
- }
-
- // Check 4: is some other operation (like MLME-SCAN or MLME-RESET) pending?
- else if (call IsTokenRequested.getNow() && call IsBeaconEnabledPAN.getNow()) {
- if (call RadioOff.isOff()) {
- stopAllAlarms(); // may still fire, but is locked through isOwner()
- // nothing more to do... just release the Token
- m_lock = FALSE; // unlock
- call TokenToCfp.transfer();
- return;
- } else
- next = SWITCH_OFF;
- }
-
- // Check 5: is battery life extension (BLE) active and
- // has the BLE period expired?
- else if (call IsBLEActive.getNow() &&
- call TimeCalc.hasExpired(call CapStart.getNow(), call BLELen.getNow()) &&
- !call IsRxEnableActive.getNow()) {
- next = trySwitchOff();
- }
-
- // Check 6: is there a frame ready to transmit?
- else if (m_currentFrame != NULL) {
- next = tryTransmit();
- }
-
- // Check 7: should we be in receive mode?
- else if (COORD_ROLE || call IsRxEnableActive.getNow()) {
- next = tryReceive(NO_ALARM);
- if (next == DO_NOTHING && call IsRxEnableActive.getNow()){
- // this means there is an active MLME_RX_ENABLE.request
- // and the radio was just switched to Rx mode - signal
- // a notify event to inform the next higher layer
- post wasRxEnabledTask();
- }
- }
-
- // Check 8: just make sure the radio is switched off
- else {
- next = trySwitchOff();
- if (next == DO_NOTHING &&
- (!call IsBeaconEnabledPAN.getNow() || (DEVICE_ROLE && call CapLen.getNow() == 0))){
- // nothing more to do... just release the Token
- stopAllAlarms(); // may still fire, but is locked through isOwner()
- m_lock = FALSE; // unlock
- call Token.release();
- return;
- }
- }
-
- // if there is nothing to do, then we must clear the lock
- if (next == DO_NOTHING)
- m_lock = FALSE;
- } // atomic
- // put next state in operation (possibly keeping the lock)
- switch (next)
- {
- case SWITCH_OFF: result = call RadioOff.off(); break;
- case LOAD_TX: result = call RadioTx.load(m_currentFrame); break;
- case PREPARE_RX: result = call RadioRx.prepare(); break;
- case WAIT_FOR_TXDONE: break;
- case DO_NOTHING: break;
- }
- if (result != SUCCESS)
- call Leds.led0On(); // internal error: could not update state !!!
- }
-
- next_state_t tryTransmit()
- {
- // tries to transmit m_currentFrame using the configuration stored
- // in other module variables (m_backoff, etc.)
- next_state_t next;
- if (call RadioTx.getLoadedFrame() == m_currentFrame){
- // the frame is already loaded -> transmit it now
- if (m_numCCA == 1){
- // unslotted CSMA-CA
- call RadioTx.transmit(NULL, m_backoff, m_numCCA, m_currentFrame->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST ? TRUE : FALSE);
- next = WAIT_FOR_TXDONE; // this will NOT clear the lock
- } else {
- // slotted CSMA-CA
- uint32_t capLen = call CapLen.getNow(), capStart = call CapStart.getNow();
- uint32_t elapsed, totalTime;
- totalTime = IEEE154_RADIO_TX_SEND_DELAY +
- m_backoff - m_backoffElapsed + m_transactionTime + IEEE154_RADIO_GUARD_TIME;
- if (totalTime > capLen)
- totalTime = capLen; // CAP is too short
- elapsed = call TimeCalc.timeElapsed(capStart, call CapEndAlarm.getNow());
- elapsed += (20 - (elapsed % 20)); // round to backoff boundary
- if (!call TimeCalc.hasExpired(capStart, capLen - totalTime)){
- call RadioTx.transmit(call CapStartRefTime.getNow(),
- elapsed + IEEE154_RADIO_TX_SEND_DELAY + m_backoff - m_backoffElapsed,
- m_numCCA,
- m_currentFrame->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST ? TRUE : FALSE);
- next = WAIT_FOR_TXDONE; // this will NOT clear the lock
- } else {
- // frame does not fit in remaing portion of the CAP
- if (elapsed < call CapLen.getNow()){
- m_backoffElapsed += call CapLen.getNow() - elapsed;
- if (m_backoffElapsed > m_backoff)
- m_backoffElapsed = m_backoff;
- }
- next = SWITCH_OFF;
- }
- }
- } else {
- // the frame to transmit has not yet been loaded -> load it now
- if (!call RadioOff.isOff())
- next = SWITCH_OFF;
- else {
- if (m_lastFrame){
- // the done event for the previous frame has not yet been
- // signalled to the upper layer -> wait
- next = DO_NOTHING;
- } else
- next = LOAD_TX;
- }
- }
- return next;
- }
-
- next_state_t tryReceive(rx_alarm_t alarmType)
- {
- next_state_t next;
- if (call RadioRx.isReceiving()){
- next = DO_NOTHING;
- } else if (call RadioRx.isPrepared()){
- call RadioRx.receive(NULL, 0);
- switch (alarmType)
- {
- case INDIRECT_TX_ALARM: call IndirectTxWaitAlarm.start(m_macMaxFrameTotalWaitTime); break;
- case BROADCAST_ALARM: call BroadcastAlarm.start(m_macMaxFrameTotalWaitTime); break;
- case NO_ALARM: break;
- }
- next = DO_NOTHING;
- } else if (call RadioOff.isOff())
- next = PREPARE_RX;
- else
- next = SWITCH_OFF;
- return next;
- }
-
- next_state_t trySwitchOff()
- {
- next_state_t next;
- if (call RadioOff.isOff())
- next = DO_NOTHING;
- else
- next = SWITCH_OFF;
- return next;
- }
-
- async event void RadioTx.loadDone(){ m_lock = FALSE; updateState();}
- async event void RadioOff.offDone(){ m_lock = FALSE; updateState();}
- async event void RadioRx.prepareDone(){ m_lock = FALSE; updateState();}
-
- async event void CapEndAlarm.fired(){
- call Debug.log(LEVEL_IMPORTANT, CapP_CAP_END_FIRED, superframeDirection, 0, 0);
- updateState();
- }
- async event void BLEAlarm.fired(){ updateState();}
- event void RxEnableStateChange.notify(bool whatever){ updateState();}
- async event void BroadcastAlarm.fired(){ m_broadcastRxPending = FALSE; updateState();}
-
- async event void IndirectTxWaitAlarm.fired()
- {
- atomic {
- if (m_indirectTxPending){
- m_indirectTxPending = FALSE;
- post signalTxDoneTask();
- }
- }
- }
-
- async event void RadioTx.transmitDone(ieee154_txframe_t *frame,
- ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error)
- {
- bool retry = FALSE;
- switch (error)
- {
- case SUCCESS:
- m_result = IEEE154_SUCCESS;
- if (DEVICE_ROLE && frame->payload[0] == CMD_FRAME_DATA_REQUEST &&
- ((frame->header->mhr[MHR_INDEX_FC1]) & FC1_FRAMETYPE_MASK) == FC1_FRAMETYPE_CMD){
- // just transmitted a data request frame
- m_result = IEEE154_NO_DATA; // pessimistic
- if (ackPendingFlag){
- // the coordinator has data for us; switch to Rx
- // to complete the indirect transmission
- m_indirectTxPending = TRUE;
- m_lastFrame = m_currentFrame;
- m_currentFrame = NULL;
- if (call RadioRx.prepare() != SUCCESS) // SHOULD succeed
- call RadioOff.off();
- return;
- }
- }
- break;
- case EBUSY:
- // we're following the SDL Spec in IEEE 802.15.4-2003 Annex D
- m_result = IEEE154_CHANNEL_ACCESS_FAILURE;
- m_NB += 1;
- if (m_NB < m_macMaxCSMABackoffs){
- m_BE += 1;
- if (m_BE > m_macMaxBE)
- m_BE = m_macMaxBE;
- retry = TRUE;
- }
- break;
- case ENOACK:
- // we're following the SDL Spec in IEEE 802.15.4-2003 Annex D
- m_result = IEEE154_NO_ACK;
- m_NB += 1;
- // shouldn't the next check be (m_NB-1 < m_macMaxFrameRetries)? but
- // on the other hand, NB is used for CHANNEL_ACCESS_FAILURE and NO_ACK,
- // i.e. m_NB does not tell us much about past retransmissions anyway...
- if (m_NB < m_macMaxFrameRetries){
- m_BE = m_macMinBE;
- retry = TRUE;
- }
- break;
- default: break;
- }
- if (retry){
- m_backoff = generateRandomBackoff(m_BE) * IEEE154_aUnitBackoffPeriod; // next backoff
- m_backoffElapsed = 0;
- } else if (COORD_ROLE && frame == m_bcastFrame){
- // signal result of broadcast transmissions immediately
- restoreFrameFromBackup();
- signalTxBroadcastDone(m_bcastFrame, m_result);
- m_bcastFrame = NULL;
- } else {
- m_lastFrame = m_currentFrame;
- m_currentFrame = NULL;
- post signalTxDoneTask();
- }
- m_lock = FALSE;
- updateState();
- }
-
- task void signalTxDoneTask()
- {
- ieee154_txframe_t *lastFrame = m_lastFrame;
- m_lastFrame = NULL; // only now can a next transmission begin
- m_indirectTxPending = FALSE;
- if (lastFrame)
- signal FrameTx.transmitDone(lastFrame, m_result);
- updateState();
- }
-
- event message_t* RadioRx.received(message_t* frame, ieee154_reftime_t *timestamp)
- {
- // received a frame during CAP - find out frame type and
- // signal it to corresponding client component
- uint8_t *payload = (uint8_t *) frame->data;
- uint8_t *mhr = MHR(frame);
- uint8_t frameType = mhr[MHR_INDEX_FC1] & FC1_FRAMETYPE_MASK;
- if (frameType == FC1_FRAMETYPE_CMD)
- frameType += payload[0];
- atomic {
- if (DEVICE_ROLE && m_indirectTxPending){
- message_t* frameBuf;
- call IndirectTxWaitAlarm.stop();
- // TODO: check!
- //if (frame->payloadLen)
- // is this frame from our coordinator? hmm... we cannot say
- // with certainty, because we might only know either the
- // coordinator extended or short address (and the frame could
- // have been sent with the other addressing mode) ??
- m_result = IEEE154_SUCCESS;
- frameBuf = signal FrameExtracted.received[frameType](frame, m_lastFrame);
- signal IndirectTxWaitAlarm.fired();
- return frameBuf;
- } else
- return signal FrameRx.received[frameType](frame);
- }
- }
-
- void backupCurrentFrame()
- {
- ieee154_cap_frame_backup_t backup = {m_currentFrame, m_BE, m_macMaxCSMABackoffs,
- m_macMaxBE, m_macMinBE, m_NB, m_backoff, m_backoffElapsed, m_transactionTime};
- call FrameBackup.setNow(&backup);
- }
-
- void restoreFrameFromBackup()
- {
- ieee154_cap_frame_backup_t *backup = call FrameRestore.getNow();
- if (backup != NULL){
- m_currentFrame = backup->frame;
- m_BE = backup->BE;
- m_macMaxCSMABackoffs = backup->allowedBackoffs;
- m_macMaxBE = backup->macMaxBE;
- m_macMinBE = backup->macMinBE;
- m_NB = backup->NB;
- m_backoff = backup->backoff;
- m_backoffElapsed = backup->backoffElapsed;
- m_transactionTime = backup->transactionTime;
- }
- }
-
- async command ieee154_status_t BroadcastTx.transmitNow(ieee154_txframe_t *frame)
- {
- // if this command is called then it is (MUST be) called
- // only just before the token is transferred to this component
- // and it is then be called only once per CAP (max. one broadcast
- // is allowed after a beacon transmission)
- atomic {
- if (!call Token.isOwner() && m_bcastFrame == NULL){
- m_bcastFrame = frame;
- return IEEE154_SUCCESS;
- } else {
- call Leds.led0On();
- return IEEE154_TRANSACTION_OVERFLOW;
- }
- }
- }
-
- void signalTxBroadcastDone(ieee154_txframe_t *frame, ieee154_status_t error)
- {
- signal BroadcastTx.transmitNowDone(frame, error);
- }
-
- task void wasRxEnabledTask()
- {
- signal WasRxEnabled.notify(TRUE);
- }
-
- bool isUnslottedCSMA_CA()
- {
- return (m_numCCA == 1);
- }
-
- event void Token.granted()
- {
- // the current frame should be transmitted using unslotted CSMA-CA
- updateState();
- }
-
- default event void FrameTx.transmitDone(ieee154_txframe_t *data, ieee154_status_t status){}
- default event message_t* FrameRx.received[uint8_t client](message_t* data){return data;}
- default async command bool IsRxEnableActive.getNow(){return FALSE;}
-
- default async command void IndirectTxWaitAlarm.start(uint32_t dt){call Leds.led0On();}
- default async command void IndirectTxWaitAlarm.stop(){call Leds.led0On();}
- default async command void IndirectTxWaitAlarm.startAt(uint32_t t0, uint32_t dt){call Leds.led0On();}
-
- default async command void BroadcastAlarm.start(uint32_t dt){call Leds.led0On();}
- default async command void BroadcastAlarm.stop(){call Leds.led0On();}
- default async command void BroadcastAlarm.startAt(uint32_t t0, uint32_t dt){call Leds.led0On();}
-
- default async command bool IsRxBroadcastPending.getNow(){ return FALSE;}
- default async event void BroadcastTx.transmitNowDone(ieee154_txframe_t *frame, ieee154_status_t status){}
- default event message_t* FrameExtracted.received[uint8_t client](message_t* msg, ieee154_txframe_t *txFrame){return msg;}
- default async command error_t FrameBackup.setNow(ieee154_cap_frame_backup_t* val ){return FAIL;}
- default async command ieee154_cap_frame_backup_t* FrameRestore.getNow(){return NULL;}
-
- command error_t WasRxEnabled.enable(){return FAIL;}
- command error_t WasRxEnabled.disable(){return FAIL;}
- command error_t FindBeacon.enable(){return FAIL;}
- command error_t FindBeacon.disable(){return FAIL;}
-}
+++ /dev/null
-/*
- * Copyright (c) 2008, Technische Universitaet Berlin
- * 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 Technische Universitaet Berlin 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 COPYRIGHT
- * OWNER OR 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.
- *
- * - Revision -------------------------------------------------------------
- * $Revision$
- * $Date$
- * @author Jan Hauer <hauer@tkn.tu-berlin.de>
- * ========================================================================
- */
-#include "TKN154_MAC.h"
-generic module CsmaQueueP() {
- provides
- {
- interface Init as Reset;
- interface FrameTx[uint8_t client];
- interface FrameRx as FrameExtracted[uint8_t client];
- interface Purge;
- } uses {
- interface Queue<ieee154_txframe_t*>;
- interface FrameTx as FrameTxCsma;
- interface FrameRx as SubFrameExtracted;
- }
-}
-implementation
-{
- task void txTask();
- bool m_busy;
- uint8_t m_client;
-
- command error_t Reset.init()
- {
- while (call Queue.size()){
- ieee154_txframe_t *txFrame = call Queue.dequeue();
- signal FrameTx.transmitDone[txFrame->client](txFrame, IEEE154_TRANSACTION_OVERFLOW);
- }
- m_busy = FALSE;
- return SUCCESS;
- }
-
- command ieee154_status_t FrameTx.transmit[uint8_t client](ieee154_txframe_t *txFrame)
- {
- txFrame->client = client;
- if (call Queue.enqueue(txFrame) != SUCCESS)
- return IEEE154_TRANSACTION_OVERFLOW;
- else {
- post txTask();
- return IEEE154_SUCCESS;
- }
- }
-
- task void txTask()
- {
- if (!m_busy && call Queue.size()){
- ieee154_txframe_t *txFrame = call Queue.head();
- if (txFrame->headerLen == 0){
- // was purged
- call Queue.dequeue();
- signal Purge.purgeDone(txFrame, IEEE154_SUCCESS);
- post txTask();
- }
- m_client = txFrame->client;
- if (call FrameTxCsma.transmit(txFrame) == IEEE154_SUCCESS){
- m_busy = TRUE;
- }
- }
- }
-
- event void FrameTxCsma.transmitDone(ieee154_txframe_t *txFrame, ieee154_status_t status)
- {
- call Queue.dequeue();
- m_busy = FALSE;
- signal FrameTx.transmitDone[txFrame->client](txFrame, status);
- post txTask();
- }
-
- event message_t* SubFrameExtracted.received(message_t* frame)
- {
- // this event is signalled when a frame has been received
- // in response to a data request command frame. The transmitDone
- // event will be signalled later
- return signal FrameExtracted.received[m_client](frame);
- }
-
- default event void FrameTx.transmitDone[uint8_t client](ieee154_txframe_t *txFrame, ieee154_status_t status){}
-
- command ieee154_status_t Purge.purge(uint8_t msduHandle)
- {
- uint8_t qSize = call Queue.size(), i;
- if (qSize > 1){
- for (i=0; i<qSize-1; i++){
- ieee154_txframe_t *txFrame = call Queue.element(i);
- if (((txFrame->header->mhr[MHR_INDEX_FC1] & FC1_FRAMETYPE_MASK) == FC1_FRAMETYPE_DATA) &&
- txFrame->handle == msduHandle){
- txFrame->headerLen = 0; // mark as invalid
- return IEEE154_SUCCESS;
- }
- }
- }
- return IEEE154_INVALID_HANDLE;
- }
-
- default event void Purge.purgeDone(ieee154_txframe_t *txFrame, ieee154_status_t status){}
-}
call TxControlPool.put(txControl);
}
}
- call Debug.log(LEVEL_INFO, DISSASSOCIATE_REQUEST, status, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, DISSASSOCIATE_REQUEST, status, 0, 0);
return status;
}
call FrameUtility.convertToNative(&DeviceAddress.extendedAddress, &mhr[srcAddrOffset]);
call TxControlPool.put((ieee154_txcontrol_t*) ((uint8_t*) data->header - offsetof(ieee154_txcontrol_t, header)));
call TxFramePool.put(data);
- call Debug.log(LEVEL_INFO, DISSASSOCIATE_TXDONE, status, 2, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, DISSASSOCIATE_TXDONE, status, 2, 0);
m_disAssociationOngoing = FALSE;
signal MLME_DISASSOCIATE.confirm(status, DeviceAddrMode, DevicePANID, DeviceAddress);
}
uint16_t DevicePANID = *((nxle_uint16_t*) (&(mhr[MHR_INDEX_ADDRESS])));
ieee154_address_t DeviceAddress;
call FrameUtility.convertToNative(&DeviceAddress.extendedAddress, &mhr[dstAddrOffset]);
- call Debug.log(LEVEL_INFO, DISSASSOCIATE_TXDONE, status, 1, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, DISSASSOCIATE_TXDONE, status, 1, 0);
call TxControlPool.put((ieee154_txcontrol_t*) ((uint8_t*) data->header - offsetof(ieee154_txcontrol_t, header)));
call TxFramePool.put(data);
- call Debug.log(LEVEL_INFO, DISSASSOCIATE_TXDONE, status, 2, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, DISSASSOCIATE_TXDONE, status, 2, 0);
m_disAssociationOngoing = FALSE;
signal MLME_DISASSOCIATE.confirm(status, DeviceAddrMode, DevicePANID, DeviceAddress);
}
{
// received a disassociation notification from the device
ieee154_address_t address;
- call Debug.log(LEVEL_INFO, DISSASSOCIATE_RX, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, DISSASSOCIATE_RX, 0, 0, 0);
if (call Frame.getSrcAddrMode(frame) == ADDR_MODE_EXTENDED_ADDRESS &&
call Frame.getSrcAddr(frame, &address) == SUCCESS)
signal MLME_DISASSOCIATE.indication(address.extendedAddress, frame->data[1], NULL);
--- /dev/null
+/*
+ * Copyright (c) 2008, Technische Universitaet Berlin
+ * 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 Technische Universitaet Berlin 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 COPYRIGHT
+ * OWNER OR 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.
+ *
+ * - Revision -------------------------------------------------------------
+ * $Revision$
+ * $Date$
+ * @author Jan Hauer <hauer@tkn.tu-berlin.de>
+ * ========================================================================
+ */
+
+#include "TKN154_PHY.h"
+#include "TKN154_MAC.h"
+
+
+/**
+ * This module is responsible for preparing the transmission/reception of DATA
+ * and COMMAND frames in the contention access period (CAP, slotted CSMA-CA) or
+ * in a nonbeacon-enabled PAN (unslotted CSMA-CA). It prepares the relevant
+ * parameters of the CSMA-CA algorithm (NB, BE, etc.), but it does not implement
+ * the CSMA-CA algorithm (the CSMA-CA algorithm is implemented in the radio
+ * driver).
+ *
+ * In a beacon-enabled this module does slightly different things depending on
+ * whether it is the CAP for an outgoing superframe (superframeDirection =
+ * OUTGOING_SUPERFRAME), i.e. the CAP from the perspective of a coordinator
+ * after it has transmitted its own beacon; or for an incoming superframe
+ * (superframeDirection = INCOMING_SUPERFRAME), i.e. the CAP from the
+ * perspective of a device after it has received a beacon from its coordinator.
+ * For example, in the CAP a coordinator will usually listen for incoming
+ * frames from the devices, and a device will usually switch the radio off
+ * unless it has a frame to transmit. In nonbeacon-enabled PANs the
+ * superframeDirection parameter is ignored.
+ */
+
+generic module FrameDispatchP(uint8_t superframeDirection)
+{
+ provides
+ {
+ interface Init as Reset;
+ interface FrameTx as FrameTx;
+ interface FrameRx as FrameRx[uint8_t frameType];
+ interface FrameExtracted as FrameExtracted[uint8_t frameType];
+ interface FrameTxNow as BroadcastTx;
+ interface Notify<bool> as WasRxEnabled;
+ interface Notify<bool> as FindBeacon;
+ }
+ uses
+ {
+ interface Alarm<TSymbolIEEE802154,uint32_t> as CapEndAlarm;
+ interface Alarm<TSymbolIEEE802154,uint32_t> as BLEAlarm;
+ interface Alarm<TSymbolIEEE802154,uint32_t> as IndirectTxWaitAlarm;
+ interface Alarm<TSymbolIEEE802154,uint32_t> as BroadcastAlarm;
+ interface Resource as Token;
+ interface GetNow<bool> as IsTokenRequested;
+ interface ResourceTransfer as TokenToCfp;
+ interface ResourceTransferred as TokenTransferred;
+ interface GetNow<uint32_t> as CapStart;
+ interface GetNow<ieee154_reftime_t*> as CapStartRefTime;
+ interface GetNow<uint32_t> as CapLen;
+ interface GetNow<bool> as IsBLEActive;
+ interface GetNow<uint16_t> as BLELen;
+ interface GetNow<bool> as IsRxBroadcastPending;
+ interface GetNow<bool> as IsRxEnableActive;
+ interface Get<ieee154_txframe_t*> as GetIndirectTxFrame;
+ interface Notify<bool> as RxEnableStateChange;
+ interface GetNow<bool> as IsTrackingBeacons;
+ interface FrameUtility;
+ interface RadioTx;
+ interface RadioRx;
+ interface RadioOff;
+ interface GetNow<bool> as IsBeaconEnabledPAN;
+ interface MLME_GET;
+ interface MLME_SET;
+ interface Ieee802154Debug as Debug;
+ interface TimeCalc;
+ interface Leds;
+ interface SetNow<ieee154_cap_frame_backup_t*> as FrameBackup;
+ interface GetNow<ieee154_cap_frame_backup_t*> as FrameRestore;
+ }
+}
+implementation
+{
+ typedef enum {
+ SWITCH_OFF,
+ LOAD_TX,
+ PREPARE_RX,
+ DO_NOTHING,
+ WAIT_FOR_TXDONE,
+ } next_state_t;
+
+ typedef enum {
+ INDIRECT_TX_ALARM,
+ BROADCAST_ALARM,
+ NO_ALARM,
+ } rx_alarm_t;
+
+ enum {
+ COORD_ROLE = (superframeDirection == OUTGOING_SUPERFRAME),
+ DEVICE_ROLE = !COORD_ROLE,
+ };
+
+ norace bool m_lock;
+ norace ieee154_txframe_t *m_currentFrame;
+ norace ieee154_txframe_t *m_bcastFrame;
+ norace ieee154_txframe_t *m_lastFrame;
+
+ norace ieee154_csma_t m_csmaParams;
+ norace bool m_resume;
+ norace uint16_t m_remainingBackoff;
+ norace ieee154_macMaxBE_t m_BE;
+ norace ieee154_macMaxCSMABackoffs_t m_macMaxCSMABackoffs;
+ norace ieee154_macMaxBE_t m_macMaxBE;
+ norace bool m_slottedCsma;
+ norace ieee154_macMaxFrameRetries_t m_macMaxFrameRetries;
+ norace ieee154_status_t m_result;
+ norace uint32_t m_transactionTime;
+ norace bool m_indirectTxPending = FALSE;
+ norace bool m_broadcastRxPending;
+ norace ieee154_macMaxFrameTotalWaitTime_t m_macMaxFrameTotalWaitTime;
+
+
+#ifdef TKN154_SERIAL_DEBUG
+#define DEBUG_NEXT_BUFFER_SIZE 12
+ norace uint8_t dbgHistory[DEBUG_NEXT_BUFFER_SIZE];
+ norace uint8_t dbgHistoryIndex;
+ void dbgHistoryReset(){dbgHistoryIndex=0; memset(dbgHistory, 0xFF, DEBUG_NEXT_BUFFER_SIZE);}
+ void dbgHistoryAdd(uint8_t nextState)
+ {
+ dbgHistory[dbgHistoryIndex] = nextState;
+ dbgHistoryIndex = (dbgHistoryIndex+1) % DEBUG_NEXT_BUFFER_SIZE;
+ }
+ void dbgHistoryFlush()
+ {
+ uint8_t i,k=dbgHistoryIndex;
+ uint32_t s1=0xFFFFFFFF,s2=0xFFFFFFFF,s3=0xFFFFFFFF;
+ for (i=0; i<4; i++){ s1 = s1 << 8; s1 |= dbgHistory[k]; k = (k+1) % DEBUG_NEXT_BUFFER_SIZE;}
+ for (i=0; i<4; i++){ s2 = s2 << 8; s2 |= dbgHistory[k]; k = (k+1) % DEBUG_NEXT_BUFFER_SIZE;}
+ for (i=0; i<4; i++){ s3 = s3 << 8; s3 |= dbgHistory[k]; k = (k+1) % DEBUG_NEXT_BUFFER_SIZE;}
+ call Debug.log(DEBUG_LEVEL_INFO, 12, s1,s2,s3);
+ }
+#else
+ void dbgHistoryReset(){}
+ void dbgHistoryAdd(uint8_t nextState){}
+ void dbgHistoryFlush(){}
+#endif
+
+ void stopAllAlarms();
+ next_state_t tryReceive(rx_alarm_t alarmType);
+ next_state_t tryTransmit();
+ next_state_t trySwitchOff();
+ void backupCurrentFrame();
+ void restoreFrameFromBackup();
+ void updateState();
+ void setCurrentFrame(ieee154_txframe_t *frame);
+ void signalTxBroadcastDone(ieee154_txframe_t *frame, ieee154_status_t error);
+ void transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result);
+ task void signalTxDoneTask();
+ task void setupTxBroadcastTask();
+ task void wasRxEnabledTask();
+
+ command error_t Reset.init()
+ {
+ if (m_currentFrame)
+ signal FrameTx.transmitDone(m_currentFrame, IEEE154_TRANSACTION_OVERFLOW);
+ if (m_lastFrame)
+ signal FrameTx.transmitDone(m_lastFrame, IEEE154_TRANSACTION_OVERFLOW);
+ if (m_bcastFrame)
+ signalTxBroadcastDone(m_bcastFrame, IEEE154_TRANSACTION_OVERFLOW);
+ m_currentFrame = m_lastFrame = m_bcastFrame = NULL;
+ stopAllAlarms();
+ return SUCCESS;
+ }
+
+ async event void TokenTransferred.transferred()
+ {
+ // we got the token, i.e. CAP has just started
+ uint32_t actualCapLen = call CapLen.getNow();
+ dbgHistoryReset();
+ if (!call IsBeaconEnabledPAN.getNow()){
+ call Leds.led0On(); // internal error!
+ call TokenToCfp.transfer();
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 0, 0,0,0);
+ } else if (DEVICE_ROLE && actualCapLen == 0){
+ // very rare case:
+ // this can only happen, if we're on a beacon-enabled PAN, not tracking beacons,
+ // and searched but didn't find a beacon for aBaseSuperframeDuration*(2n+1) symbols
+ // -> transmit current frame using unslotted CSMA-CA
+ m_slottedCsma = FALSE;
+ updateState();
+ return;
+ } else if (actualCapLen < IEEE154_ACTIVE_PERIOD_GUARD_TIME){
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 1, superframeDirection, actualCapLen, IEEE154_ACTIVE_PERIOD_GUARD_TIME);
+ call TokenToCfp.transfer();
+ return;
+ } else {
+ actualCapLen -= IEEE154_ACTIVE_PERIOD_GUARD_TIME;
+ if (DEVICE_ROLE)
+ m_broadcastRxPending = call IsRxBroadcastPending.getNow();
+ else {
+ // COORD_ROLE
+ if (m_bcastFrame != NULL) {
+ // we have to transmit a broadcast frame immediately; this
+ // (possibly) requires a backup of the previously active frame
+ // and a reinitializing the CSMA parameters -> will do it
+ // in task context and then continue
+ m_lock = TRUE;
+ post setupTxBroadcastTask();
+ call Debug.log(DEBUG_LEVEL_INFO, 7, 0,0,0);
+ }
+ }
+ call CapEndAlarm.startAt(call CapStart.getNow(), actualCapLen);
+ if (call IsBLEActive.getNow())
+ call BLEAlarm.startAt(call CapStart.getNow(), call BLELen.getNow());
+ call Debug.log(DEBUG_LEVEL_INFO, 2, call CapStart.getNow(),
+ actualCapLen, call CapStart.getNow()+ actualCapLen);
+ }
+ updateState();
+ }
+
+ command ieee154_status_t FrameTx.transmit(ieee154_txframe_t *frame)
+ {
+ //call Debug.log(DEBUG_LEVEL_INFO, 4, m_lock, call Token.isOwner(), m_currentFrame == NULL);
+ if (m_currentFrame != NULL){
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 5, 0,0,0);
+ return IEEE154_TRANSACTION_OVERFLOW;
+ } else {
+ setCurrentFrame(frame);
+ if (!call IsBeaconEnabledPAN.getNow()){
+ call Token.request(); // prepare for unslotted CSMA-CA
+ } else {
+ // a beacon must be found before transmitting in a beacon-enabled PAN
+ if (DEVICE_ROLE && !call IsTrackingBeacons.getNow()){
+ signal FindBeacon.notify(TRUE);
+ // we'll receive the Token at latest after aBaseSuperframeDuration*(2n+1) symbols;
+ // if the beacon was not found, then we'll send the frame using unslotted CSMA-CA
+ }
+ updateState();
+ }
+ return IEEE154_SUCCESS;
+ }
+ }
+
+ task void setupTxBroadcastTask()
+ {
+ ieee154_macDSN_t tmp;
+ ieee154_txframe_t *oldFrame = m_currentFrame;
+ if (COORD_ROLE){
+ if (m_bcastFrame != NULL){
+ // broadcasts should be transmitted *immediately* after the beacon,
+ // which may interrupt a pending transmit operation from the previous
+ // CAP; back up the last active frame configuration (may be none)
+ // and restore it after the broadcast frame has been transmitted;
+ // do this through interfaces and don't wire them for DEVICE_ROLE,
+ // so we don't waste the RAM of devices
+ backupCurrentFrame();
+ setCurrentFrame(m_bcastFrame);
+ if (oldFrame){
+ // now the sequence number are out of order... swap them back
+ tmp = m_bcastFrame->header->mhr[MHR_INDEX_SEQNO];
+ m_bcastFrame->header->mhr[MHR_INDEX_SEQNO] =
+ oldFrame->header->mhr[MHR_INDEX_SEQNO];
+ oldFrame->header->mhr[MHR_INDEX_SEQNO] = tmp;
+ }
+ }
+ }
+ m_lock = FALSE;
+ updateState();
+ }
+
+ void setCurrentFrame(ieee154_txframe_t *frame)
+ {
+ ieee154_macDSN_t dsn = call MLME_GET.macDSN();
+ frame->header->mhr[MHR_INDEX_SEQNO] = dsn++;
+ call MLME_SET.macDSN(dsn);
+ m_csmaParams.NB = 0;
+ m_csmaParams.macMaxCsmaBackoffs = m_macMaxCSMABackoffs = call MLME_GET.macMaxCSMABackoffs();
+ m_csmaParams.macMaxBE = m_macMaxBE = call MLME_GET.macMaxBE();
+ m_csmaParams.BE = call MLME_GET.macMinBE();
+ if (call MLME_GET.macBattLifeExt() && m_csmaParams.BE > 2)
+ m_csmaParams.BE = 2;
+ m_BE = m_csmaParams.BE;
+ if (COORD_ROLE && call GetIndirectTxFrame.get() == frame)
+ m_macMaxFrameRetries = 0; // this is an indirect transmissions (never retransmit)
+ else
+ m_macMaxFrameRetries = call MLME_GET.macMaxFrameRetries();
+ m_slottedCsma = call IsBeaconEnabledPAN.getNow();
+ m_transactionTime = IEEE154_SHR_DURATION +
+ (frame->headerLen + frame->payloadLen + 2) * IEEE154_SYMBOLS_PER_OCTET; // extra 2 for CRC
+ if (frame->header->mhr[MHR_INDEX_FC1] & FC1_ACK_REQUEST)
+ m_transactionTime += (IEEE154_aTurnaroundTime + IEEE154_aUnitBackoffPeriod +
+ 11 * IEEE154_SYMBOLS_PER_OCTET); // 11 byte for the ACK PPDU
+ //if (frame->headerLen + frame->payloadLen > IEEE154_aMaxSIFSFrameSize)
+ // m_transactionTime += call MLME_GET.macMinLIFSPeriod();
+ //else
+ // m_transactionTime += call MLME_GET.macMinSIFSPeriod();
+ m_macMaxFrameTotalWaitTime = call MLME_GET.macMaxFrameTotalWaitTime();
+ m_currentFrame = frame;
+ }
+
+ void stopAllAlarms()
+ {
+ call CapEndAlarm.stop();
+ if (DEVICE_ROLE){
+ call IndirectTxWaitAlarm.stop();
+ call BroadcastAlarm.stop();
+ }
+ call BLEAlarm.stop();
+ }
+
+ /**
+ * The updateState() function is called whenever some event happened that
+ * might require a state change; it implements a lock mechanism (m_lock) to
+ * prevent race conditions. Whenever the lock is set a "done"-event (from a
+ * RadioTx/RadioRx/RadioOff interface) is pending and will "soon" unset the
+ * lock (and then updateState() will called again). The updateState()
+ * function decides about the next state by checking a list of possible
+ * current states ordered by priority, e.g. it first always checks whether
+ * the CAP is still active. Calling this function more than necessary can do
+ * no harm, but it SHOULD be called whenever an event happened that might
+ * lead to a state change.
+ */
+
+ void updateState()
+ {
+ error_t result = SUCCESS;
+ next_state_t next;
+ atomic {
+ // long atomics are bad... but in this block, once the
+ // current state has been determined only one branch will
+ // be taken (no loops, etc.)
+ if (m_lock || !call Token.isOwner())
+ return;
+ m_lock = TRUE; // lock
+
+ // Check 1: for beacon-enabled PANs, has the CAP finished?
+ if (call IsBeaconEnabledPAN.getNow()
+ && (COORD_ROLE || call IsTrackingBeacons.getNow()) // FALSE only if device could't find a beacon
+ && (call TimeCalc.hasExpired(call CapStart.getNow(), call CapLen.getNow()-IEEE154_ACTIVE_PERIOD_GUARD_TIME) ||
+ !call CapEndAlarm.isRunning())){
+ if (call RadioOff.isOff()) {
+ stopAllAlarms(); // may still fire, locked through isOwner()
+ if (DEVICE_ROLE && m_indirectTxPending)
+ signal IndirectTxWaitAlarm.fired();
+ m_broadcastRxPending = FALSE;
+ if (COORD_ROLE && m_bcastFrame){
+ // didn't manage to transmit a broadcast
+ restoreFrameFromBackup();
+ signalTxBroadcastDone(m_bcastFrame, IEEE154_CHANNEL_ACCESS_FAILURE);
+ m_bcastFrame = NULL;
+ }
+ m_lock = FALSE; // unlock
+ call TokenToCfp.transfer();
+ call Debug.log(DEBUG_LEVEL_INFO, 8, 0,0,0);
+ dbgHistoryFlush();
+ return;
+ } else
+ next = SWITCH_OFF;
+ }
+
+ // Check 2: should a broadcast frame be received/transmitted immediately
+ // at the start of CAP?
+ else if (DEVICE_ROLE && m_broadcastRxPending){
+ // receive a broadcast from coordinator
+ next = tryReceive(BROADCAST_ALARM);
+ } else if (COORD_ROLE && m_bcastFrame){
+ next = tryTransmit();
+ }
+
+ // Check 3: was an indirect transmission successfully started
+ // and are we now waiting for a frame from the coordinator?
+ else if (DEVICE_ROLE && m_indirectTxPending) {
+ next = tryReceive(INDIRECT_TX_ALARM);
+ }
+
+ // Check 4: is some other operation (like MLME-SCAN or MLME-RESET) pending?
+ else if (call IsTokenRequested.getNow() && call IsBeaconEnabledPAN.getNow()) {
+ if (call RadioOff.isOff()) {
+ stopAllAlarms(); // may still fire, but is locked through isOwner()
+ // nothing more to do... just release the Token
+ m_lock = FALSE; // unlock
+ call TokenToCfp.transfer();
+ call Debug.log(DEBUG_LEVEL_INFO, 9, call IsTokenRequested.getNow(),0,0);
+ dbgHistoryFlush();
+ return;
+ } else
+ next = SWITCH_OFF;
+ }
+
+ // Check 5: is battery life extension (BLE) active and
+ // has the BLE period expired?
+ else if (call IsBLEActive.getNow() &&
+ call TimeCalc.hasExpired(call CapStart.getNow(), call BLELen.getNow()) &&
+ !call IsRxEnableActive.getNow()) {
+ next = trySwitchOff();
+ }
+
+ // Check 6: is there a frame ready to transmit?
+ else if (m_currentFrame != NULL) {
+ next = tryTransmit();
+ }
+
+ // Check 7: should we be in receive mode?
+ else if (COORD_ROLE || call IsRxEnableActive.getNow()) {
+ next = tryReceive(NO_ALARM);
+ if (next == DO_NOTHING && call IsRxEnableActive.getNow()){
+ // this means there is an active MLME_RX_ENABLE.request
+ // and the radio was just switched to Rx mode - signal
+ // a notify event to inform the next higher layer
+ post wasRxEnabledTask();
+ }
+ }
+
+ // Check 8: just make sure the radio is switched off
+ else {
+ next = trySwitchOff();
+ if (next == DO_NOTHING &&
+ (!call IsBeaconEnabledPAN.getNow() || (DEVICE_ROLE && call CapLen.getNow() == 0))){
+ // nothing more to do... just release the Token
+ stopAllAlarms(); // may still fire, but is locked through isOwner()
+ m_lock = FALSE; // unlock
+ call Debug.log(DEBUG_LEVEL_INFO, 10, 0,0,0);
+ dbgHistoryFlush();
+ call Token.release();
+ return;
+ }
+ }
+
+ // if there is nothing to do, then we must clear the lock
+ if (next == DO_NOTHING)
+ m_lock = FALSE;
+ } // atomic
+ dbgHistoryAdd(next);
+ // put next state in operation (possibly keeping the lock)
+ switch (next)
+ {
+ case SWITCH_OFF: result = call RadioOff.off(); break;
+ case LOAD_TX: result = call RadioTx.load(m_currentFrame); break;
+ case PREPARE_RX: result = call RadioRx.prepare(); break;
+ case WAIT_FOR_TXDONE: break;
+ case DO_NOTHING: break;
+ }
+ if (result != SUCCESS)
+ call Leds.led0On(); // internal error: could not update state !!!
+ }
+
+ next_state_t tryTransmit()
+ {
+ // tries to transmit m_currentFrame using the either slotted or unslotted csma-ca
+ next_state_t next;
+ if (call RadioTx.getLoadedFrame() == m_currentFrame){
+ // the frame is already loaded -> transmit it now
+ if (!m_slottedCsma){
+ // unslotted CSMA-CA
+ call RadioTx.transmitUnslottedCsmaCa(&m_csmaParams);
+ next = WAIT_FOR_TXDONE; // this will NOT clear the lock
+ } else {
+ // slotted CSMA-CA
+ uint32_t dtMax = call CapLen.getNow() - m_transactionTime - IEEE154_ACTIVE_PERIOD_GUARD_TIME;
+ if (dtMax > call CapLen.getNow())
+ dtMax = 0;
+ if (call IsBLEActive.getNow()){
+ // battery life extension
+ uint16_t bleLen = call BLELen.getNow();
+ if (bleLen < dtMax)
+ dtMax = bleLen;
+ }
+ if (call TimeCalc.hasExpired(call CapStart.getNow() - 60, dtMax)) // 60 is for enabling Rx + 2 CCA
+ next = SWITCH_OFF; // frame doesn't possibly fit in the remaining CAP
+ else {
+ call RadioTx.transmitSlottedCsmaCa(call CapStartRefTime.getNow(),
+ dtMax, m_resume, m_remainingBackoff, &m_csmaParams);
+ //call Debug.log(DEBUG_LEVEL_INFO, 13, call CapStart.getNow(), dtMax, m_resume);
+ next = WAIT_FOR_TXDONE; // this will NOT clear the lock
+ }
+ }
+ } else {
+ // the frame to transmit has not yet been loaded -> load it now
+ if (!call RadioOff.isOff())
+ next = SWITCH_OFF;
+ else {
+ if (m_lastFrame){
+ // the done event for the previous frame has not yet been
+ // signalled to the upper layer -> wait
+ next = DO_NOTHING;
+ } else
+ next = LOAD_TX;
+ }
+ }
+ return next;
+ }
+
+ next_state_t tryReceive(rx_alarm_t alarmType)
+ {
+ next_state_t next;
+ if (call RadioRx.isReceiving()){
+ next = DO_NOTHING;
+ } else if (call RadioRx.isPrepared()){
+ call RadioRx.receive(NULL, 0);
+ switch (alarmType)
+ {
+ case INDIRECT_TX_ALARM: call IndirectTxWaitAlarm.start(m_macMaxFrameTotalWaitTime); break;
+ case BROADCAST_ALARM: call BroadcastAlarm.start(m_macMaxFrameTotalWaitTime); break;
+ case NO_ALARM: break;
+ }
+ next = DO_NOTHING;
+ } else if (call RadioOff.isOff())
+ next = PREPARE_RX;
+ else
+ next = SWITCH_OFF;
+ return next;
+ }
+
+ next_state_t trySwitchOff()
+ {
+ next_state_t next;
+ if (call RadioOff.isOff())
+ next = DO_NOTHING;
+ else
+ next = SWITCH_OFF;
+ return next;
+ }
+
+ async event void RadioTx.loadDone(){ m_lock = FALSE; updateState();}
+ async event void RadioOff.offDone(){ m_lock = FALSE; updateState();}
+ async event void RadioRx.prepareDone(){ m_lock = FALSE; updateState();}
+
+ async event void CapEndAlarm.fired(){
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 3, superframeDirection, 0, 0);
+ updateState();
+ }
+ async event void BLEAlarm.fired(){ updateState();}
+ event void RxEnableStateChange.notify(bool whatever){ updateState();}
+ async event void BroadcastAlarm.fired(){ m_broadcastRxPending = FALSE; updateState();}
+
+ async event void IndirectTxWaitAlarm.fired()
+ {
+ atomic {
+ if (m_indirectTxPending){
+ m_indirectTxPending = FALSE;
+ post signalTxDoneTask();
+ }
+ }
+ }
+
+ async event void RadioTx.transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result)
+ {
+ transmitDone(frame, NULL, ackPendingFlag, csmaParams, result);
+ }
+
+ async event void RadioTx.transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParams, error_t result)
+ {
+ if (result == ERETRY){
+ m_resume = TRUE;
+ m_remainingBackoff = remainingBackoff;
+ } else
+ m_resume = FALSE;
+ transmitDone(frame, txTime, ackPendingFlag, csmaParams, result);
+ }
+
+ void transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result)
+ {
+ bool done = TRUE;
+ //call Debug.log(DEBUG_LEVEL_INFO, 11, result,0,0);
+ switch (result)
+ {
+ case SUCCESS:
+ // frame was successfully transmitted, if ACK was requested
+ // then a matching ACK was successfully received also
+ m_result = IEEE154_SUCCESS;
+ if (DEVICE_ROLE && frame->payload[0] == CMD_FRAME_DATA_REQUEST &&
+ ((frame->header->mhr[MHR_INDEX_FC1]) & FC1_FRAMETYPE_MASK) == FC1_FRAMETYPE_CMD){
+ // this was a data request frame
+ m_result = IEEE154_NO_DATA; // pessimistic
+ if (ackPendingFlag){
+ // the coordinator has data for us; switch to Rx
+ // to complete the indirect transmission
+ m_indirectTxPending = TRUE;
+ m_lastFrame = m_currentFrame;
+ m_currentFrame = NULL;
+ if (call RadioRx.prepare() != SUCCESS) // SHOULD succeed
+ call RadioOff.off();
+ return;
+ }
+ }
+ break;
+ case FAIL:
+ // CSMA-CA algorithm failed: frame was not transmitted,
+ // because channel was never idle (including backoff attempts)
+ m_result = IEEE154_CHANNEL_ACCESS_FAILURE;
+ break;
+ case ENOACK:
+ // frame was transmitted, but we didn't receive an ACK (and
+ // the AckRequest flag was set in the frame header)
+ // note: coordinator never retransmits an indirect transmission (see above)
+ if (m_macMaxFrameRetries > 0) {
+ // retransmit: reinitialize CSMA-CA parameters
+ done = FALSE;
+ m_csmaParams.NB = 0;
+ m_csmaParams.macMaxCsmaBackoffs = m_macMaxCSMABackoffs;
+ m_csmaParams.macMaxBE = m_macMaxBE;
+ m_csmaParams.BE = m_BE;
+ m_macMaxFrameRetries -= 1;
+ } else
+ m_result = IEEE154_NO_ACK;
+ break;
+ case ERETRY:
+ // frame was not transmitted, because the transaction does not
+ // fit in the remaining CAP (in beacon-enabled PANs only)
+ done = FALSE;
+ break;
+ default:
+ break;
+ }
+ if (COORD_ROLE && frame == m_bcastFrame){
+ // always signal result of broadcast transmissions immediately
+ restoreFrameFromBackup();
+ signalTxBroadcastDone(m_bcastFrame, (!done) ? IEEE154_CHANNEL_ACCESS_FAILURE : m_result);
+ m_bcastFrame = NULL;
+ } else if (done) {
+ m_lastFrame = m_currentFrame;
+ m_currentFrame = NULL;
+ post signalTxDoneTask();
+ }
+ m_lock = FALSE;
+ updateState();
+ }
+
+ task void signalTxDoneTask()
+ {
+ ieee154_txframe_t *lastFrame = m_lastFrame;
+ m_lastFrame = NULL; // only now can a next transmission begin
+ m_indirectTxPending = FALSE;
+ if (lastFrame)
+ signal FrameTx.transmitDone(lastFrame, m_result);
+ updateState();
+ }
+
+ event message_t* RadioRx.received(message_t* frame, ieee154_reftime_t *timestamp)
+ {
+ // received a frame during CAP - find out frame type and
+ // signal it to corresponding client component
+ uint8_t *payload = (uint8_t *) frame->data;
+ uint8_t *mhr = MHR(frame);
+ uint8_t frameType = mhr[MHR_INDEX_FC1] & FC1_FRAMETYPE_MASK;
+ if (frameType == FC1_FRAMETYPE_CMD)
+ frameType += payload[0];
+ atomic {
+ if (DEVICE_ROLE && m_indirectTxPending){
+ message_t* frameBuf;
+ call IndirectTxWaitAlarm.stop();
+ // TODO: check!
+ //if (frame->payloadLen)
+ // is this frame from our coordinator? hmm... we cannot say
+ // with certainty, because we might only know either the
+ // coordinator extended or short address (and the frame could
+ // have been sent with the other addressing mode) ??
+ m_result = IEEE154_SUCCESS;
+ frameBuf = signal FrameExtracted.received[frameType](frame, m_lastFrame);
+ signal IndirectTxWaitAlarm.fired();
+ return frameBuf;
+ } else
+ return signal FrameRx.received[frameType](frame);
+ }
+ }
+
+ void backupCurrentFrame()
+ {
+ ieee154_cap_frame_backup_t backup = {m_currentFrame, m_csmaParams, m_transactionTime};
+ call FrameBackup.setNow(&backup);
+ }
+
+ void restoreFrameFromBackup()
+ {
+ ieee154_cap_frame_backup_t *backup = call FrameRestore.getNow();
+ if (backup != NULL){
+ m_currentFrame = backup->frame;
+ memcpy(&m_csmaParams, &backup->csmaParams, sizeof(ieee154_csma_t));
+ m_transactionTime = backup->transactionTime;
+ }
+ }
+
+ async command ieee154_status_t BroadcastTx.transmitNow(ieee154_txframe_t *frame)
+ {
+ // if this command is called then it is (MUST be) called
+ // only just before the token is transferred to this component
+ // and it is then be called only once per CAP (max. one broadcast
+ // is allowed after a beacon transmission)
+ atomic {
+ if (!call Token.isOwner() && m_bcastFrame == NULL){
+ m_bcastFrame = frame;
+ return IEEE154_SUCCESS;
+ } else {
+ call Leds.led0On();
+ return IEEE154_TRANSACTION_OVERFLOW;
+ }
+ }
+ }
+
+ void signalTxBroadcastDone(ieee154_txframe_t *frame, ieee154_status_t error)
+ {
+ signal BroadcastTx.transmitNowDone(frame, error);
+ }
+
+ task void wasRxEnabledTask()
+ {
+ signal WasRxEnabled.notify(TRUE);
+ }
+
+ event void Token.granted()
+ {
+ // the current frame should be transmitted using unslotted CSMA-CA
+ dbgHistoryReset();
+ call Debug.log(DEBUG_LEVEL_INFO, 6, 0,0,0);
+ updateState();
+ }
+
+ async event void RadioTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime){}
+
+ default event void FrameTx.transmitDone(ieee154_txframe_t *data, ieee154_status_t status){}
+ default event message_t* FrameRx.received[uint8_t client](message_t* data){return data;}
+ default async command bool IsRxEnableActive.getNow(){return FALSE;}
+
+ default async command void IndirectTxWaitAlarm.start(uint32_t dt){call Leds.led0On();}
+ default async command void IndirectTxWaitAlarm.stop(){call Leds.led0On();}
+ default async command void IndirectTxWaitAlarm.startAt(uint32_t t0, uint32_t dt){call Leds.led0On();}
+
+ default async command void BroadcastAlarm.start(uint32_t dt){call Leds.led0On();}
+ default async command void BroadcastAlarm.stop(){call Leds.led0On();}
+ default async command void BroadcastAlarm.startAt(uint32_t t0, uint32_t dt){call Leds.led0On();}
+
+ default async command bool IsRxBroadcastPending.getNow(){ return FALSE;}
+ default async event void BroadcastTx.transmitNowDone(ieee154_txframe_t *frame, ieee154_status_t status){}
+ default event message_t* FrameExtracted.received[uint8_t client](message_t* msg, ieee154_txframe_t *txFrame){return msg;}
+ default async command error_t FrameBackup.setNow(ieee154_cap_frame_backup_t* val ){return FAIL;}
+ default async command ieee154_cap_frame_backup_t* FrameRestore.getNow(){return NULL;}
+
+ command error_t WasRxEnabled.enable(){return FAIL;}
+ command error_t WasRxEnabled.disable(){return FAIL;}
+ command error_t FindBeacon.enable(){return FAIL;}
+ command error_t FindBeacon.disable(){return FAIL;}
+}
--- /dev/null
+/*
+ * Copyright (c) 2008, Technische Universitaet Berlin
+ * 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 Technische Universitaet Berlin 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 COPYRIGHT
+ * OWNER OR 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.
+ *
+ * - Revision -------------------------------------------------------------
+ * $Revision$
+ * $Date$
+ * @author Jan Hauer <hauer@tkn.tu-berlin.de>
+ * ========================================================================
+ */
+#include "TKN154_MAC.h"
+generic module FrameDispatchQueueP() {
+ provides
+ {
+ interface Init as Reset;
+ interface FrameTx[uint8_t client];
+ interface FrameRx as FrameExtracted[uint8_t client];
+ interface Purge;
+ } uses {
+ interface Queue<ieee154_txframe_t*>;
+ interface FrameTx as FrameTxCsma;
+ interface FrameRx as SubFrameExtracted;
+ }
+}
+implementation
+{
+ task void txTask();
+ bool m_busy;
+ uint8_t m_client;
+
+ command error_t Reset.init()
+ {
+ while (call Queue.size()){
+ ieee154_txframe_t *txFrame = call Queue.dequeue();
+ signal FrameTx.transmitDone[txFrame->client](txFrame, IEEE154_TRANSACTION_OVERFLOW);
+ }
+ m_busy = FALSE;
+ return SUCCESS;
+ }
+
+ command ieee154_status_t FrameTx.transmit[uint8_t client](ieee154_txframe_t *txFrame)
+ {
+ txFrame->client = client;
+ if (call Queue.enqueue(txFrame) != SUCCESS)
+ return IEEE154_TRANSACTION_OVERFLOW;
+ else {
+ post txTask();
+ return IEEE154_SUCCESS;
+ }
+ }
+
+ task void txTask()
+ {
+ if (!m_busy && call Queue.size()){
+ ieee154_txframe_t *txFrame = call Queue.head();
+ if (txFrame->headerLen == 0){
+ // was purged
+ call Queue.dequeue();
+ signal Purge.purgeDone(txFrame, IEEE154_SUCCESS);
+ post txTask();
+ }
+ m_client = txFrame->client;
+ if (call FrameTxCsma.transmit(txFrame) == IEEE154_SUCCESS){
+ m_busy = TRUE;
+ }
+ }
+ }
+
+ event void FrameTxCsma.transmitDone(ieee154_txframe_t *txFrame, ieee154_status_t status)
+ {
+ call Queue.dequeue();
+ m_busy = FALSE;
+ signal FrameTx.transmitDone[txFrame->client](txFrame, status);
+ post txTask();
+ }
+
+ event message_t* SubFrameExtracted.received(message_t* frame)
+ {
+ // this event is signalled when a frame has been received
+ // in response to a data request command frame. The transmitDone
+ // event will be signalled later
+ return signal FrameExtracted.received[m_client](frame);
+ }
+
+ default event void FrameTx.transmitDone[uint8_t client](ieee154_txframe_t *txFrame, ieee154_status_t status){}
+
+ command ieee154_status_t Purge.purge(uint8_t msduHandle)
+ {
+ uint8_t qSize = call Queue.size(), i;
+ if (qSize > 1){
+ for (i=0; i<qSize-1; i++){
+ ieee154_txframe_t *txFrame = call Queue.element(i);
+ if (((txFrame->header->mhr[MHR_INDEX_FC1] & FC1_FRAMETYPE_MASK) == FC1_FRAMETYPE_DATA) &&
+ txFrame->handle == msduHandle){
+ txFrame->headerLen = 0; // mark as invalid
+ return IEEE154_SUCCESS;
+ }
+ }
+ }
+ return IEEE154_INVALID_HANDLE;
+ }
+
+ default event void Purge.purgeDone(ieee154_txframe_t *txFrame, ieee154_status_t status){}
+}
interface FrameTx[uint8_t client];
interface WriteBeaconField as PendingAddrWrite;
interface Notify<bool> as PendingAddrSpecUpdated;
+ interface Get<ieee154_txframe_t*> as GetIndirectTxFrame;
interface Purge;
}
uses
for (j=0; j<8; j++)
pendingAddrField[1 + 2*m_numShortPending + i*8 + j] = longAdrPtr[i][j];
pendingAddrField[0] = m_numShortPending | (m_numExtPending << 4);
- call Debug.log(LEVEL_INFO, IndirectTxP_BEACON_ASSEMBLY, len,0,0);
+ call Debug.log(DEBUG_LEVEL_INFO, IndirectTxP_BEACON_ASSEMBLY, len,0,0);
return len;
}
// send a frame through indirect transmission
uint8_t i;
if (m_numTableEntries >= NUM_MAX_PENDING){
- call Debug.log(LEVEL_IMPORTANT, IndirectTxP_OVERFLOW, 0,0,0);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, IndirectTxP_OVERFLOW, 0,0,0);
return IEEE154_TRANSACTION_OVERFLOW;
}
txFrame->client = client;
m_numExtPending++;
if (!call IndirectTxTimeout.isRunning())
call IndirectTxTimeout.startOneShot(getPersistenceTime());
- call Debug.log(LEVEL_INFO, IndirectTxP_NOTIFIED, 0,0,0);
+ call Debug.log(DEBUG_LEVEL_INFO, IndirectTxP_NOTIFIED, 0,0,0);
signal PendingAddrSpecUpdated.notify(TRUE);
return IEEE154_SUCCESS;
}
}
}
}
- call Debug.log(LEVEL_INFO, IndirectTxP_REQUESTED, NUM_MAX_PENDING-i,i,*src);
+ call Debug.log(DEBUG_LEVEL_INFO, IndirectTxP_REQUESTED, NUM_MAX_PENDING-i,i,*src);
if (i != NUM_MAX_PENDING){
// found a matching frame, mark it for transmission
m_txFrameTable[i]->client |= SEND_THIS_FRAME;
// iterate over the queued frames and transmit them in the CAP
// (if they are marked for transmission)
uint8_t i;
- if (!m_pendingTxFrame && m_numTableEntries){
+ if (m_pendingTxFrame == NULL && m_numTableEntries){
for (i=0; i<NUM_MAX_PENDING; i++)
if (m_txFrameTable[i] && (m_txFrameTable[i]->client & SEND_THIS_FRAME)){
// TODO: set frame pending bit, if there's more data for this destination
m_pendingTxFrame = m_txFrameTable[i];
m_client = m_txFrameTable[i]->client;
if (call CoordCapTx.transmit(m_txFrameTable[i]) == IEEE154_SUCCESS){
- call Debug.log(LEVEL_INFO, IndirectTxP_SEND_NOW, 0,0,0);
+ call Debug.log(DEBUG_LEVEL_INFO, IndirectTxP_SEND_NOW, 0,0,0);
} else {
- m_pendingTxFrame = 0;
+ m_pendingTxFrame = NULL;
post tryCoordCapTxTask();
}
return; // done - wait for txDone
event void CoordCapTx.transmitDone(ieee154_txframe_t *txFrame, ieee154_status_t status)
{
uint8_t i;
- // TODO: if CSMA-CA algorithm failed, then frame shall remain in transaction queue
+ // TODO: if CSMA-CA algorithm failed, then frame shall still remain in transaction queue
for (i=0; i<NUM_MAX_PENDING; i++)
if (m_txFrameTable[i] == txFrame){
m_txFrameTable[i] = NULL; // slot is now empty
m_numExtPending--;
signal FrameTx.transmitDone[txFrame->client](txFrame, status);
post tryCoordCapTxTask();
- call Debug.log(LEVEL_INFO, IndirectTxP_SEND_DONE, status,m_numTableEntries,0);
+ call Debug.log(DEBUG_LEVEL_INFO, IndirectTxP_SEND_DONE, status,m_numTableEntries,0);
}
+ command ieee154_txframe_t* GetIndirectTxFrame.get(){ return m_pendingTxFrame;}
command error_t PendingAddrSpecUpdated.enable(){return FAIL;}
command error_t PendingAddrSpecUpdated.disable(){return FAIL;}
default event void FrameTx.transmitDone[uint8_t client](ieee154_txframe_t *txFrame, ieee154_status_t status){}
if ((txStatus = call PollTx.transmit(txFrame)) != IEEE154_SUCCESS){
call TxFramePool.put(txFrame);
call TxControlPool.put(txControl);
- call Debug.log(LEVEL_IMPORTANT, PollP_ALLOC_FAIL1, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, PollP_ALLOC_FAIL1, 0, 0, 0);
} else
m_numPending++;
}
ieee154_txframe_t *txFrame;
ieee154_txcontrol_t *txControl;
ieee154_status_t status = IEEE154_TRANSACTION_OVERFLOW;
- call Debug.log(LEVEL_INFO, PollP_INTERNAL_POLL, CoordAddrMode, client, m_numPending);
- if (client == SYNC_CLIENT && m_numPending != 0){
+ call Debug.log(DEBUG_LEVEL_INFO, PollP_INTERNAL_POLL, CoordAddrMode, client, m_numPending);
+ if (client == SYNC_POLL_CLIENT && m_numPending != 0){
// no point in auto-requesting if user request is pending
signal DataRequest.pollDone[client]();
return IEEE154_SUCCESS;
if ((status = call PollTx.transmit(txFrame)) != IEEE154_SUCCESS){
call TxControlPool.put(txControl);
call TxFramePool.put(txFrame);
- call Debug.log(LEVEL_IMPORTANT, PollP_ALLOC_FAIL2, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, PollP_ALLOC_FAIL2, 0, 0, 0);
} else
m_numPending++;
}
event message_t* DataExtracted.received(message_t* frame, ieee154_txframe_t *txFrame)
{
if (!txFrame){
- call Debug.log(LEVEL_CRITICAL, PollP_INTERNAL_ERROR, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_CRITICAL, PollP_INTERNAL_ERROR, 0, 0, 0);
return frame;
} else
- call Debug.log(LEVEL_INFO, PollP_SUCCESS, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, PollP_SUCCESS, 0, 0, 0);
if (txFrame->handle == HANDLE_MLME_POLL_REQUEST)
signal MLME_POLL.confirm(IEEE154_SUCCESS);
else
signal DataRequest.pollDone[txFrame->handle]();
txFrame->handle = HANDLE_MLME_POLL_SUCCESS; // mark as processed
// TODO: check if pending bit is set (then initiate another POLL)
- call Debug.log(LEVEL_IMPORTANT, PollP_RX, txFrame->handle, 0, 0);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, PollP_RX, txFrame->handle, 0, 0);
return signal DataRx.received(frame);
}
event void PollTx.transmitDone(ieee154_txframe_t *txFrame, ieee154_status_t status)
{
- call Debug.log(LEVEL_IMPORTANT, PollP_TXDONE, status, txFrame->handle, 0);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, PollP_TXDONE, status, txFrame->handle, 0);
m_numPending--;
if (txFrame->handle != HANDLE_MLME_POLL_SUCCESS){
// didn't receive a DATA frame from the coordinator
return FAIL;
m_promiscuousState = S_STARTING;
call Token.request();
- call Debug.log(LEVEL_INFO, EnableRxP_PROMISCUOUS_REQUEST, m_promiscuousState, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, EnableRxP_PROMISCUOUS_REQUEST, m_promiscuousState, 0, 0);
call Debug.flush();
return SUCCESS;
}
if (call PromiscuousRx.prepare() != IEEE154_SUCCESS){
m_promiscuousState = S_IDLE;
call Token.release();
- call Debug.log(LEVEL_IMPORTANT, EnableRxP_RADIORX_ERROR, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, EnableRxP_RADIORX_ERROR, 0, 0, 0);
signal PromiscuousMode.startDone(FAIL);
}
}
m_promiscuousState = S_STARTED;
call PromiscuousRx.receive(NULL, 0);
signal PromiscuousMode.startDone(SUCCESS);
- call Debug.log(LEVEL_INFO, EnableRxP_PROMISCUOUS_ON, m_promiscuousState, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, EnableRxP_PROMISCUOUS_ON, m_promiscuousState, 0, 0);
}
event message_t* PromiscuousRx.received(message_t *frame, ieee154_reftime_t *timestamp)
call RadioPromiscuousMode.set(FALSE);
call Token.release();
signal PromiscuousMode.stopDone(SUCCESS);
- call Debug.log(LEVEL_INFO, EnableRxP_PROMISCUOUS_OFF, m_promiscuousState, 0, 0);
+ call Debug.log(DEBUG_LEVEL_INFO, EnableRxP_PROMISCUOUS_OFF, m_promiscuousState, 0, 0);
}
default event void PromiscuousMode.startDone(error_t error){}
}
}
+ async command error_t MacTx.transmit[uint8_t client](ieee154_reftime_t *t0, uint32_t dt)
+ {
+ if (client == call ArbiterInfo.userId())
+ return call PhyTx.transmit(t0, dt);
+ else {
+ call Leds.led0On();
+ return IEEE154_TRANSACTION_OVERFLOW;
+ }
+ }
+
+ async event void PhyTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime)
+ {
+ signal MacTx.transmitDone[call ArbiterInfo.userId()](frame, txTime);
+ }
- async command error_t MacTx.transmit[uint8_t client](ieee154_reftime_t *referenceTime,
- uint32_t timeOffset, uint8_t numCCA, bool ackRequest)
+ async command error_t MacTx.transmitUnslottedCsmaCa[uint8_t client](ieee154_csma_t *csmaParams)
{
if (client == call ArbiterInfo.userId())
- return call PhyTx.transmit(referenceTime, timeOffset, numCCA, ackRequest);
+ return call PhyTx.transmitUnslottedCsmaCa(csmaParams);
else {
call Leds.led0On();
return IEEE154_TRANSACTION_OVERFLOW;
}
}
- async event void PhyTx.transmitDone(ieee154_txframe_t *frame,
- ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error)
+ async event void PhyTx.transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result)
{
- signal MacTx.transmitDone[call ArbiterInfo.userId()](frame, referenceTime, ackPendingFlag, error);
+ signal MacTx.transmitUnslottedCsmaCaDone[call ArbiterInfo.userId()](
+ frame, ackPendingFlag, csmaParams, result);
+ }
+
+ async command error_t MacTx.transmitSlottedCsmaCa[uint8_t client](ieee154_reftime_t *slot0Time, uint32_t dtMax,
+ bool resume, uint16_t remainingBackoff, ieee154_csma_t *csmaParams)
+ {
+ if (client == call ArbiterInfo.userId())
+ return call PhyTx.transmitSlottedCsmaCa(slot0Time, dtMax, resume, remainingBackoff, csmaParams);
+ else {
+ call Leds.led0On();
+ return IEEE154_TRANSACTION_OVERFLOW;
+ }
+ }
+
+ async event void PhyTx.transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParams, error_t result)
+ {
+ signal MacTx.transmitSlottedCsmaCaDone[call ArbiterInfo.userId()](
+ frame, txTime, ackPendingFlag, remainingBackoff, csmaParams, result);
}
/* ----------------------- RadioOff ----------------------- */
default async event void MacTx.loadDone[uint8_t client]()
{
- call Debug.log(LEVEL_CRITICAL, RadioRxTxP_DEFAULT_PREPARE_TX_DONE, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_CRITICAL, 0, 0, 0, 0);
}
- default async event void MacTx.transmitDone[uint8_t client](ieee154_txframe_t *frame,
- ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error)
+ default async event void MacTx.transmitDone[uint8_t client](ieee154_txframe_t *frame, ieee154_reftime_t *txTime)
{
- call Debug.log(LEVEL_CRITICAL, RadioRxTxP_DEFAULT_TX_DONE, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_CRITICAL, 1, 0, 0, 0);
}
default async event void MacRx.prepareDone[uint8_t client]()
{
- call Debug.log(LEVEL_CRITICAL, RadioRxTxP_DEFAULT_PREPARE_RX_DONE, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_CRITICAL, 2, 0, 0, 0);
}
default event message_t* MacRx.received[uint8_t client](message_t *frame, ieee154_reftime_t *timestamp)
{
- call Debug.log(LEVEL_INFO, RadioRxTxP_DEFAULT_RECEIVED, client, call ArbiterInfo.userId(), 0xff);
+ call Debug.log(DEBUG_LEVEL_IMPORTANT, 3, client, call ArbiterInfo.userId(), 0xff);
return frame;
}
default async event void MacRadioOff.offDone[uint8_t client]()
{
- call Debug.log(LEVEL_CRITICAL, RadioRxTxP_DEFAULT_OFFDONE, 0, 0, 0);
+ call Debug.log(DEBUG_LEVEL_CRITICAL, 4, 0, 0, 0);
+ }
+ default async event void MacTx.transmitUnslottedCsmaCaDone[uint8_t client](ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result)
+ {
+ call Debug.log(DEBUG_LEVEL_CRITICAL, 5, 0, 0, 0);
+ }
+ default async event void MacTx.transmitSlottedCsmaCaDone[uint8_t client](ieee154_txframe_t *frame,
+ ieee154_reftime_t *txTime, bool ackPendingFlag, uint16_t remainingBackoff,
+ ieee154_csma_t *csmaParams, error_t result)
+ {
+ call Debug.log(DEBUG_LEVEL_CRITICAL, 6, 0, 0, 0);
}
}
async event void RadioTx.loadDone()
{
- call RadioTx.transmit(0, 0, 0, FALSE);
+ call RadioTx.transmit(NULL, 0); // transmit immediately
}
- async event void RadioTx.transmitDone(ieee154_txframe_t *frame,
- ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error)
+ async event void RadioTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime)
{
if (call RadioRx.prepare() != SUCCESS) // must succeed
call Leds.led0On();
nextIteration();
}
+ async event void RadioTx.transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result){}
+
+ async event void RadioTx.transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParams, error_t result){}
+
default event message_t* MLME_BEACON_NOTIFY.indication ( message_t *beaconFrame ){return beaconFrame;}
default event void MLME_SCAN.confirm (
ieee154_status_t status,
#ifndef IEEE154_BEACON_SYNC_DISABLED
BeaconSynchronizeP,
- new CsmaQueueP() as DeviceCapQueue,
- new CsmaP(INCOMING_SUPERFRAME) as DeviceCap,
+ new FrameDispatchQueueP() as DeviceCapQueue,
+ new FrameDispatchP(INCOMING_SUPERFRAME) as DeviceCap,
#else
NoBeaconSynchronizeP as BeaconSynchronizeP,
- new NoCsmaQueueP() as DeviceCapQueue,
- new NoCsmaP() as DeviceCap,
+ new NoFrameDispatchQueueP() as DeviceCapQueue,
+ new NoFrameDispatchP(INCOMING_SUPERFRAME) as DeviceCap,
#endif
NoDeviceCfpP as DeviceCfp,
#ifndef IEEE154_BEACON_TX_DISABLED
BeaconTransmitP,
- new CsmaQueueP() as CoordCapQueue,
- new CsmaP(OUTGOING_SUPERFRAME) as CoordCap,
+ new FrameDispatchQueueP() as CoordCapQueue,
+ new FrameDispatchP(OUTGOING_SUPERFRAME) as CoordCap,
#else
NoBeaconTransmitP as BeaconTransmitP,
- new NoCsmaQueueP() as CoordCapQueue,
- new NoCsmaP() as CoordCap,
+ new NoFrameDispatchQueueP() as CoordCapQueue,
+ new NoFrameDispatchP(OUTGOING_SUPERFRAME) as CoordCap,
#endif
NoCoordCfpP as CoordCfp,
BeaconTransmitP.IsBroadcastReady -> CoordBroadcastP.IsBroadcastReady;
BeaconTransmitP.TimeCalc -> PibP;
BeaconTransmitP.Leds = Leds;
- BeaconTransmitP.Debug = Ieee802154Debug[START_CLIENT];
+ BeaconTransmitP.Debug = Ieee802154Debug[DEBUG_BEACON_TRANSMIT_ID];
BeaconTxRadioClient.TransferTo -> CoordBroadcastRadioClient.TransferFrom;
/* ------------------ Beacon Tracking (MLME-SYNC) ------------------ */
BeaconSynchronizeP.BeaconRx -> SyncRadioClient;
BeaconSynchronizeP.RadioOff -> SyncRadioClient;
BeaconSynchronizeP.IsBeaconEnabledPAN -> PibP.IsBeaconEnabledPAN;
- BeaconSynchronizeP.DataRequest -> PollP.DataRequest[SYNC_CLIENT];
+ BeaconSynchronizeP.DataRequest -> PollP.DataRequest[SYNC_POLL_CLIENT];
BeaconSynchronizeP.Token -> SyncRadioClient;
BeaconSynchronizeP.IsTokenRequested -> SyncRadioClient;
BeaconSynchronizeP.TokenTransferred -> SyncRadioClient;
BeaconSynchronizeP.TimeCalc -> PibP;
BeaconSynchronizeP.CoordRealignmentRx -> DeviceCap.FrameRx[FC1_FRAMETYPE_CMD + CMD_FRAME_COORDINATOR_REALIGNMENT];
BeaconSynchronizeP.Leds = Leds;
- BeaconSynchronizeP.Debug = Ieee802154Debug[SYNC_CLIENT];
+ BeaconSynchronizeP.Debug = Ieee802154Debug[DEBUG_BEACON_SYNCHRONIZE_ID];
SyncRadioClient.TransferTo -> DeviceCapRadioClient.TransferFrom;
/* -------------------- Association (MLME-ASSOCIATE) -------------------- */
AssociateP.AssociationRequestTx -> DeviceCapQueue.FrameTx[unique(CAP_TX_CLIENT)];
AssociateP.AssociationResponseExtracted -> DeviceCap.FrameExtracted[FC1_FRAMETYPE_CMD + CMD_FRAME_ASSOCIATION_RESPONSE];
AssociateP.AssociationResponseTx -> IndirectTxP.FrameTx[unique(INDIRECT_TX_CLIENT)];
- AssociateP.DataRequest -> PollP.DataRequest[ASSOCIATE_CLIENT];
+ AssociateP.DataRequest -> PollP.DataRequest[ASSOCIATE_POLL_CLIENT];
AssociateP.ResponseTimeout = Timer3;
AssociateP.TxFramePool -> TxFramePoolP;
AssociateP.TxControlPool -> TxControlPoolP;
AssociateP.FrameUtility -> PibP;
AssociateP.Frame -> PibP;
AssociateP.LocalExtendedAddress -> PibP.GetLocalExtendedAddress;
- AssociateP.Debug = Ieee802154Debug[ASSOCIATE_CLIENT];
+ AssociateP.Debug = Ieee802154Debug[DEBUG_ASSOCIATE_ID];
/* --------------- Disassociation (MLME-DISASSOCIATE) --------------- */
DisassociateP.FrameUtility -> PibP;
DisassociateP.Frame -> PibP;
DisassociateP.LocalExtendedAddress -> PibP.GetLocalExtendedAddress;
- DisassociateP.Debug = Ieee802154Debug[DISASSOCIATE_CLIENT];
+ DisassociateP.Debug = Ieee802154Debug[DEBUG_DISASSOCIATE_ID];
/* ------------------ Data Transmission (MCPS-DATA) ------------------- */
PollP.FrameUtility -> PibP;
PollP.TxFramePool -> TxFramePoolP;
PollP.TxControlPool -> TxControlPoolP;
- PollP.Debug = Ieee802154Debug[POLL_CLIENT];
+ PollP.Debug = Ieee802154Debug[DEBUG_POLL_ID];
PollP.MLME_GET -> PibP;
PollP.LocalExtendedAddress -> PibP.GetLocalExtendedAddress;
IndirectTxP.IndirectTxTimeout = Timer4;
IndirectTxP.TimeCalc -> PibP;
IndirectTxP.Leds = Leds;
- IndirectTxP.Debug = Ieee802154Debug[INDIRECTTX_DEBUG_CLIENT];
+ IndirectTxP.Debug = Ieee802154Debug[DEBUG_INDIRECTTX_ID];
/* ---------------------------- Realignment --------------------------- */
components new RadioClientC() as DeviceCapRadioClient;
PibP.CapReset -> DeviceCap;
- DeviceCap.Random = Random;
DeviceCap.CapEndAlarm = Alarm3;
DeviceCap.BLEAlarm = Alarm4;
DeviceCap.IndirectTxWaitAlarm = Alarm5;
DeviceCap.BLELen -> BeaconSynchronizeP.BLELen;
DeviceCap.IsRxBroadcastPending -> BeaconSynchronizeP.IsRxBroadcastPending;
DeviceCap.IsRxEnableActive -> RxEnableP.IsRxEnableActive;
+ DeviceCap.GetIndirectTxFrame -> IndirectTxP;
DeviceCap.RxEnableStateChange -> RxEnableP.RxEnableStateChange;
DeviceCap.IsTrackingBeacons -> BeaconSynchronizeP.IsTrackingBeacons;
DeviceCap.FrameUtility -> PibP;
DeviceCap.IsBeaconEnabledPAN -> PibP.IsBeaconEnabledPAN;
DeviceCap.MLME_GET -> PibP;
DeviceCap.MLME_SET -> PibP.MLME_SET;
- DeviceCap.Debug = Ieee802154Debug[DEVICE_CAP_CLIENT];
+ DeviceCap.Debug = Ieee802154Debug[DEBUG_FRAME_DISPATCH_DEVICE_ID];
DeviceCap.TimeCalc -> PibP;
DeviceCap.Leds = Leds;
DeviceCapRadioClient.TransferTo -> DeviceCfpRadioClient.TransferFrom;
components new RadioClientC() as CoordCapRadioClient,
new BackupP(ieee154_cap_frame_backup_t);
PibP.CapReset -> CoordCap;
- CoordCap.Random = Random;
CoordCap.CapEndAlarm = Alarm7;
CoordCap.BLEAlarm = Alarm8;
CoordCap.Token -> CoordCapRadioClient;
CoordCap.IsBLEActive -> BeaconTransmitP.IsBLEActive;
CoordCap.BLELen -> BeaconTransmitP.BLELen;
CoordCap.IsRxEnableActive -> RxEnableP.IsRxEnableActive;
+ CoordCap.GetIndirectTxFrame -> IndirectTxP;
CoordCap.RxEnableStateChange -> RxEnableP.RxEnableStateChange;
CoordCap.IsTrackingBeacons -> BeaconSynchronizeP.IsTrackingBeacons;
CoordCap.FrameUtility -> PibP;
CoordCap.IsBeaconEnabledPAN -> PibP.IsBeaconEnabledPAN;
CoordCap.MLME_GET -> PibP;
CoordCap.MLME_SET -> PibP.MLME_SET;
- CoordCap.Debug = Ieee802154Debug[COORD_CAP_CLIENT];
+ CoordCap.Debug = Ieee802154Debug[DEBUG_FRAME_DISPATCH_COORD_ID];
CoordCap.TimeCalc -> PibP;
CoordCap.Leds = Leds;
CoordCapRadioClient.TransferTo -> CoordCfpRadioClient.TransferFrom;
PromiscuousModeP.PromiscuousRx -> PromiscuousModeRadioClient;
PromiscuousModeP.RadioOff -> PromiscuousModeRadioClient;
PromiscuousModeP.RadioPromiscuousMode = RadioPromiscuousMode;
- PromiscuousModeP.Debug = Ieee802154Debug[PROMISCUOUS_MODE_CLIENT];
+ PromiscuousModeP.Debug = Ieee802154Debug[DEBUG_PROMISCUOUSMODE_ID];
/* --------------------------- MLME-RX-ENABLE ------------------------ */
RxEnableP.WasRxEnabled -> DeviceCap.WasRxEnabled;
RxEnableP.WasRxEnabled -> CoordCap.WasRxEnabled;
RxEnableP.RxEnableTimer = Timer5;
- RxEnableP.Debug = Ieee802154Debug[RXENABLE_CLIENT];
+ RxEnableP.Debug = Ieee802154Debug[DEBUG_RXENABLE_ID];
/* ------------------------------- PIB -------------------------------- */
RadioControlP.PhyRadioOff = RadioOff;
RadioControlP.RadioPromiscuousMode -> PromiscuousModeP;
RadioControlP.Leds = Leds;
- RadioControlP.Debug = Ieee802154Debug[RADIORXTX_CLIENT];
+ RadioControlP.Debug = Ieee802154Debug[DEBUG_RADIOCONTROL_ID];
}
#ifndef __TKN154_DEBUG_H
#define __TKN154_DEBUG_H
-#define LEVEL_INFO 0
-#define LEVEL_IMPORTANT 50
-#define LEVEL_CRITICAL 100
-
-#define RadioRxTxP_ACQUIRED 0
-#define RadioRxTxP_NOT_ACQUIRED 1
-#define RadioRxTxP_TRANSFERRED 2
-#define RadioRxTxP_NOT_TRANSFERRED 3
-#define RadioRxTxP_RELEASED 4
-#define RadioRxTxP_NOT_RELEASED 5
-#define RadioRxTxP_TRANSFER_REQUEST 6
-#define RadioRxTxP_DEFAULT_PREPARE_TX_DONE 7
-#define RadioRxTxP_DEFAULT_TX_DONE 8
-#define RadioRxTxP_DEFAULT_PREPARE_RX_DONE 9
-#define RadioRxTxP_DEFAULT_RECEIVED 10
-#define RadioRxTxP_DEFAULT_OFFDONE 11
-#define RadioRxTxP_DEFAULT_TRANSFERRED 12
-#define RadioRxTxP_DEFAULT_TRANSFERREQUEST 13
-#define RadioRxTxP_ASK_ISOWNER 14
-#define RadioRxTxP_RX_NOOWNER 15
-#define RadioRxTxP_DEFAULT_CANCEL_TX_DONE 16
-#define RadioRxTxP_DEFAULT_CANCEL_RX_DONE 17
-
-#define SyncP_BEACON_MISSED_1 0
-#define SyncP_BEACON_MISSED_2 1
-#define SyncP_BEACON_MISSED_3 2
-#define SyncP_TRACK_ALARM 3
-#define SyncP_INVALID_PARAM 4
-#define SyncP_RX_ON 5
-#define SyncP_INTERNAL_ERROR 6
-#define SyncP_BEACON_RX 7
-#define SyncP_RADIO_BUSY 8
-#define SyncP_LOST_SYNC 9
-#define SyncP_RX_PACKET 10
-#define SyncP_NEXT_RX_TIME 11
-#define SyncP_SWITCHOFF 12
-#define SyncP_RX_GARBAGE 13
-#define SyncP_GOT_RESOURCE 14
-#define SyncP_RELEASE_RESOURCE 15
-#define SyncP_RESOURCE_REQUEST 16
-#define SyncP_TRANSFER_RESOURCE 17
-#define SyncP_PREPARE_RX 18
-#define SyncP_REQUEST 19
-#define SyncP_UPDATING 20
-#define SyncP_PREPARE_RX_DONE 21
-#define SyncP_INVALID_TIMESTAMP 22
-#define SyncP_RX_BEACON SyncP_RX_PACKET
-
-#define StartP_BEACON_TRANSMITTED 0
-#define StartP_UPDATE_STATE 1
-#define StartP_REQUEST 2
-#define StartP_OWNER_TOO_FAST 3
-#define StartP_BEACON_UPDATE 4
-#define StartP_BEACON_UPDATE_2 5
-#define StartP_PREPARE_TX 6
-#define StartP_PREPARE_TXDONE 7
-#define StartP_SKIPPED_BEACON 8
-#define StartP_GOT_RESOURCE 9
-#define StartP_TRANSMIT 10
-
#define PollP_ALLOC_FAIL1 0
#define PollP_ALLOC_FAIL2 1
#define PollP_INTERNAL_POLL 2
#define CoordCapTransmitP_FINISH_TX 5
#define CoordCapTransmitP_RADIO_RX 6
-#define Phy_RX_CANCEL 0
-#define Phy_RX_NOW 1
-#define Phy_LOAD_TX_FIFO 2
-#define Phy_LOAD_TX_FIFO_DONE 3
-#define Phy_LOAD_TX_CANCEL 4
-#define Phy_LOAD_TX_NOW 5
-#define Phy_LOAD_TX_RX_NOW 6
-#define Phy_SEND_DONE 7
-#define Phy_SPI_GRANTED 8
-#define Phy_RADIO_OFF 9
-#define Phy_RADIO_OFF_DONE 10
-#define Phy_RADIO_PREPARE_RX 11
-#define Phy_RADIO_PREPARE_TX 12
-#define Phy_RADIO_TX_DONE 13
-#define Phy_RADIO_RECEIVED 14
#define PhyRx_START 0
#define PhyRx_STOP 1
#define PhyRx_FIFOP 2
#define PhyRx_RXON 3
+
enum {
+ DEBUG_LEVEL_INFO = 0,
+ DEBUG_LEVEL_IMPORTANT = 1,
+ DEBUG_LEVEL_CRITICAL = 2,
+
// IDs assigned for debugging
- START_CLIENT = 0,
- COORD_CAP_CLIENT = 1,
- COORD_CFP_CLIENT = 2,
-
- SYNC_CLIENT = 3,
- DEVICE_CAP_CLIENT = 4,
- DEVICE_CFP_CLIENT = 5,
-
- SCAN_CLIENT = 6,
-
- RADIORXTX_CLIENT = 7,
- PIBDATABASE_CLIENT = 8,
- ASSOCIATE_CLIENT = 9,
- DISASSOCIATE_CLIENT = 10,
- DEVICECAPQUEUE_CLIENT = 11,
- INDIRECTTX_DEBUG_CLIENT = 12,
- DATA_CLIENT = 13,
- POLL_CLIENT = 14,
- RXENABLE_CLIENT = 15,
- PROMISCUOUS_MODE_CLIENT = 16,
-
- PHY_CLIENT = 17,
- PHY_TXCLIENT = 18,
- PHY_RXCLIENT = 19,
+ DEBUG_BEACON_TRANSMIT_ID = 0,
+ DEBUG_FRAME_DISPATCH_COORD_ID = 1,
+ DEBUG_COORD_CFP_ID = 2,
+
+ DEBUG_BEACON_SYNCHRONIZE_ID = 3,
+ DEBUG_FRAME_DISPATCH_DEVICE_ID = 4,
+ DEBUG_DEVICE_CFP_ID = 5,
+
+ DEBUG_SCAN_ID = 6,
+
+ DEBUG_RADIOCONTROL_ID = 7,
+ DEBUG_PIB_ID = 8,
+ DEBUG_ASSOCIATE_ID = 9,
+ DEBUG_DISASSOCIATE_ID = 10,
+ DEBUG_FRAMEDISPATCHQUEUE_ID = 11,
+ DEBUG_INDIRECTTX_ID = 12,
+ DEBUG_DATA_ID = 13,
+ DEBUG_POLL_ID = 14,
+ DEBUG_RXENABLE_ID = 15,
+ DEBUG_PROMISCUOUSMODE_ID = 16,
+ DEBUG_RADIO_DRIVER_ID = 17,
+
};
typedef nx_struct serial_debug_msg {
} serial_debug_msg_t;
#ifndef SERIAL_DBG_MSGBUF_SIZE
-#define SERIAL_DBG_MSGBUF_SIZE 25
+#define SERIAL_DBG_MSGBUF_SIZE 150
#endif
enum {
FC2_FRAME_VERSION_MASK = 0x30,
};
+#define SYNC_POLL_CLIENT unique("PollP.client")
+#define ASSOCIATE_POLL_CLIENT unique("PollP.client")
#define CAP_TX_CLIENT "CapQueueP.FrameTx.client"
#define INDIRECT_TX_CLIENT "IndirectTx.client"
#define IEEE802154_RADIO_RESOURCE "RadioRxTxP.resource"
ieee154_header_t header;
ieee154_metadata_t metadata;
} ieee154_txcontrol_t;
+
+typedef struct ieee154_csma {
+ uint8_t BE; // initial backoff exponent
+ uint8_t macMaxBE; // maximum backoff exponent
+ uint8_t macMaxCsmaBackoffs; // maximum number of allowed backoffs
+ uint8_t NB; // number of backoff during current transmission
+} ieee154_csma_t;
typedef struct {
ieee154_txframe_t *frame;
- ieee154_macMaxBE_t BE;
- ieee154_macMaxCSMABackoffs_t allowedBackoffs;
- ieee154_macMaxBE_t macMaxBE;
- ieee154_macMinBE_t macMinBE;
- uint8_t NB;
- uint16_t backoff;
- uint16_t backoffElapsed;
+ ieee154_csma_t csmaParams;
uint32_t transactionTime;
} ieee154_cap_frame_backup_t;
async event void BeaconTx.loadDone() {}
- async event void BeaconTx.transmitDone(ieee154_txframe_t *frame,
- ieee154_reftime_t *referenceTime, bool pendingFlag, error_t error) { }
+ async event void BeaconTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime){}
+
+ async event void BeaconTx.transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParameters, error_t result){}
+
+ async event void BeaconTx.transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParameters, error_t result){}
command error_t IEEE154TxBeaconPayload.setBeaconPayload(void *beaconPayload, uint8_t length) { return ESIZE; }
}
async event void RadioTx.loadDone(){}
- async event void RadioTx.transmitDone(ieee154_txframe_t *frame,
- ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error){}
+ async event void RadioTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime){}
async event void RadioRx.prepareDone(){}
event message_t* RadioRx.received(message_t *frame, ieee154_reftime_t *timestamp){return frame;}
}
async event void TokenRequested.immediateRequested(){ }
+ async event void RadioTx.transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result){}
+ async event void RadioTx.transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParams, error_t result){}
}
+++ /dev/null
-/*
- * Copyright (c) 2008, Technische Universitaet Berlin
- * 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 Technische Universitaet Berlin 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 COPYRIGHT
- * OWNER OR 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.
- *
- * - Revision -------------------------------------------------------------
- * $Revision$
- * $Date$
- * @author Jan Hauer <hauer@tkn.tu-berlin.de>
- * ========================================================================
- */
-
-#include "TKN154_PHY.h"
-#include "TKN154_MAC.h"
-
-generic module NoCsmaP()
-{
- provides
- {
- interface Init as Reset;
- interface FrameTx as FrameTx;
- interface FrameRx as FrameRx[uint8_t frameType];
- interface FrameExtracted as FrameExtracted[uint8_t frameType];
- interface FrameTxNow as BroadcastTx;
- interface Notify<bool> as WasRxEnabled;
- interface Notify<bool> as FindBeacon;
- }
- uses
- {
- interface Random;
- interface Alarm<TSymbolIEEE802154,uint32_t> as CapEndAlarm;
- interface Alarm<TSymbolIEEE802154,uint32_t> as BLEAlarm;
- interface Alarm<TSymbolIEEE802154,uint32_t> as IndirectTxWaitAlarm;
- interface Alarm<TSymbolIEEE802154,uint32_t> as BroadcastAlarm;
- interface Resource as Token;
- interface ResourceTransfer as TokenToCfp;
- interface ResourceTransferred as TokenTransferred;
- interface ResourceRequested as TokenRequested;
- interface GetNow<bool> as IsTokenRequested;
- interface GetNow<uint32_t> as CapStart;
- interface GetNow<ieee154_reftime_t*> as CapStartRefTime;
- interface GetNow<uint32_t> as CapLen;
- interface GetNow<bool> as IsBLEActive;
- interface GetNow<uint16_t> as BLELen;
- interface GetNow<bool> as IsRxEnableActive;
- interface GetNow<bool> as IsRxBroadcastPending;
- interface Notify<bool> as RxEnableStateChange;
- interface GetNow<bool> as IsTrackingBeacons;
- interface FrameUtility;
- interface RadioTx;
- interface RadioRx;
- interface RadioOff;
- interface GetNow<bool> as IsBeaconEnabledPAN;
- interface MLME_GET;
- interface MLME_SET;
- interface Ieee802154Debug as Debug;
- interface TimeCalc;
- interface Leds;
- interface SetNow<ieee154_cap_frame_backup_t*> as FrameBackup;
- interface GetNow<ieee154_cap_frame_backup_t*> as FrameRestore;
- }
-}
-implementation
-{
- command error_t Reset.init()
- {
- return SUCCESS;
- }
-
- async event void TokenTransferred.transferred()
- {
- call TokenToCfp.transfer();
- }
-
- command ieee154_status_t FrameTx.transmit(ieee154_txframe_t *frame)
- {
- return IEEE154_TRANSACTION_OVERFLOW;
- }
-
- async event void RadioTx.loadDone(){ }
- async event void RadioOff.offDone(){ }
- async event void RadioRx.prepareDone(){ }
-
- async event void CapEndAlarm.fired(){ }
- async event void BLEAlarm.fired(){ }
- event void RxEnableStateChange.notify(bool x){ }
- async event void BroadcastAlarm.fired(){ }
-
- async event void IndirectTxWaitAlarm.fired() { }
-
- async event void RadioTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t
- *referenceTime, bool ackPendingFlag, error_t error) { }
-
- event message_t* RadioRx.received(message_t* frame, ieee154_reftime_t* referenceTime) { return frame; }
- async command ieee154_status_t BroadcastTx.transmitNow(ieee154_txframe_t *frame){ return IEEE154_TRANSACTION_OVERFLOW; }
-
- async event void TokenRequested.requested() {}
- async event void TokenRequested.immediateRequested() {}
- event void Token.granted(){}
- command error_t WasRxEnabled.enable(){return FAIL;}
- command error_t WasRxEnabled.disable(){return FAIL;}
- command error_t FindBeacon.enable(){return FAIL;}
- command error_t FindBeacon.disable(){return FAIL;}
-}
+++ /dev/null
-/*
- * Copyright (c) 2008, Technische Universitaet Berlin
- * 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 Technische Universitaet Berlin 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 COPYRIGHT
- * OWNER OR 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.
- *
- * - Revision -------------------------------------------------------------
- * $Revision$
- * $Date$
- * @author Jan Hauer <hauer@tkn.tu-berlin.de>
- * ========================================================================
- */
-#include "TKN154_MAC.h"
-generic module NoCsmaQueueP()
-{
- provides
- {
- interface Init;
- interface FrameTx[uint8_t client];
- interface FrameRx as FrameExtracted[uint8_t client];
- interface Purge;
- }
- uses
- {
- interface Queue<ieee154_txframe_t*>;
- interface FrameTx as FrameTxCsma;
- interface FrameRx as SubFrameExtracted;
- }
-}
-implementation
-{
- command error_t Init.init()
- {
- return SUCCESS;
- }
-
- command ieee154_status_t FrameTx.transmit[uint8_t client](ieee154_txframe_t *data)
- {
- return IEEE154_TRANSACTION_OVERFLOW;
- }
-
- event void FrameTxCsma.transmitDone(ieee154_txframe_t *data, ieee154_status_t status) { }
-
- event message_t* SubFrameExtracted.received(message_t* frame) { return frame; }
-
- command ieee154_status_t Purge.purge(uint8_t msduHandle) { return IEEE154_INVALID_HANDLE; }
-}
+++ /dev/null
-/*
- * Copyright (c) 2008, Technische Universitaet Berlin
- * 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 Technische Universitaet Berlin 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 COPYRIGHT
- * OWNER OR 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.
- *
- * - Revision -------------------------------------------------------------
- * $Revision$
- * $Date$
- * @author Jan Hauer <hauer@tkn.tu-berlin.de>
- * ========================================================================
- */
-#include "TKN154_MAC.h"
-module NoDeviceCapQueueP
-{
- provides
- {
- interface Init;
- interface FrameTx[uint8_t client];
- interface FrameRx as FrameExtracted[uint8_t client];
- interface Purge;
- }
- uses
- {
- interface Queue<ieee154_txframe_t*>;
- interface FrameTx as DeviceCapTx;
- interface FrameRx as SubFrameExtracted;
- }
-}
-implementation
-{
- command error_t Init.init() { return SUCCESS; }
-
- command ieee154_status_t FrameTx.tx[uint8_t client](ieee154_txframe_t *data) { return TRANSACTION_OVERFLOW; }
-
- event void DeviceCapTx.transmitDone(ieee154_txframe_t *data, ieee154_status_t status) { }
-
- event message_t* SubFrameExtracted.received(message_t* data) { return data; }
-
- command ieee154_status_t Purge.purge(uint8_t msduHandle) { return INVALID_HANDLE; }
-}
async event void RadioOff.offDone() {}
async event void RadioTx.loadDone(){}
- async event void RadioTx.transmitDone(ieee154_txframe_t *frame,
- ieee154_reftime_t *referenceTime, bool ackPendingFlag, error_t error){}
+ async event void RadioTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime){}
async event void RadioRx.prepareDone(){}
event message_t* RadioRx.received(message_t *frame, ieee154_reftime_t *timestamp){return frame;}
}
async event void TokenRequested.immediateRequested(){ }
+
+ async event void RadioTx.transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result){}
+ async event void RadioTx.transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParams, error_t result){}
}
--- /dev/null
+/*
+ * Copyright (c) 2008, Technische Universitaet Berlin
+ * 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 Technische Universitaet Berlin 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 COPYRIGHT
+ * OWNER OR 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.
+ *
+ * - Revision -------------------------------------------------------------
+ * $Revision$
+ * $Date$
+ * @author Jan Hauer <hauer@tkn.tu-berlin.de>
+ * ========================================================================
+ */
+
+#include "TKN154_PHY.h"
+#include "TKN154_MAC.h"
+
+generic module NoFrameDispatchP(uint8_t superframeDirection)
+{
+ provides
+ {
+ interface Init as Reset;
+ interface FrameTx as FrameTx;
+ interface FrameRx as FrameRx[uint8_t frameType];
+ interface FrameExtracted as FrameExtracted[uint8_t frameType];
+ interface FrameTxNow as BroadcastTx;
+ interface Notify<bool> as WasRxEnabled;
+ interface Notify<bool> as FindBeacon;
+ }
+ uses
+ {
+ interface Alarm<TSymbolIEEE802154,uint32_t> as CapEndAlarm;
+ interface Alarm<TSymbolIEEE802154,uint32_t> as BLEAlarm;
+ interface Alarm<TSymbolIEEE802154,uint32_t> as IndirectTxWaitAlarm;
+ interface Alarm<TSymbolIEEE802154,uint32_t> as BroadcastAlarm;
+ interface Resource as Token;
+ interface GetNow<bool> as IsTokenRequested;
+ interface ResourceTransfer as TokenToCfp;
+ interface ResourceTransferred as TokenTransferred;
+ interface GetNow<uint32_t> as CapStart;
+ interface GetNow<ieee154_reftime_t*> as CapStartRefTime;
+ interface GetNow<uint32_t> as CapLen;
+ interface GetNow<bool> as IsBLEActive;
+ interface GetNow<uint16_t> as BLELen;
+ interface GetNow<bool> as IsRxBroadcastPending;
+ interface GetNow<bool> as IsRxEnableActive;
+ interface Get<ieee154_txframe_t*> as GetIndirectTxFrame;
+ interface Notify<bool> as RxEnableStateChange;
+ interface GetNow<bool> as IsTrackingBeacons;
+ interface FrameUtility;
+ interface RadioTx;
+ interface RadioRx;
+ interface RadioOff;
+ interface GetNow<bool> as IsBeaconEnabledPAN;
+ interface MLME_GET;
+ interface MLME_SET;
+ interface Ieee802154Debug as Debug;
+ interface TimeCalc;
+ interface Leds;
+ interface SetNow<ieee154_cap_frame_backup_t*> as FrameBackup;
+ interface GetNow<ieee154_cap_frame_backup_t*> as FrameRestore;
+ }
+}
+implementation
+{
+ command error_t Reset.init()
+ {
+ return SUCCESS;
+ }
+
+ async event void TokenTransferred.transferred()
+ {
+ call TokenToCfp.transfer();
+ }
+
+ command ieee154_status_t FrameTx.transmit(ieee154_txframe_t *frame)
+ {
+ return IEEE154_TRANSACTION_OVERFLOW;
+ }
+
+ async event void RadioTx.loadDone(){ }
+ async event void RadioOff.offDone(){ }
+ async event void RadioRx.prepareDone(){ }
+
+ async event void CapEndAlarm.fired(){ }
+ async event void BLEAlarm.fired(){ }
+ event void RxEnableStateChange.notify(bool whatever){ }
+ async event void BroadcastAlarm.fired(){ }
+
+ async event void IndirectTxWaitAlarm.fired() { }
+
+ async event void RadioTx.transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result)
+ {
+ }
+
+ async event void RadioTx.transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParams, error_t result)
+ {
+ }
+
+ void transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, ieee154_csma_t *csmaParams, error_t result)
+ {
+ }
+
+ event message_t* RadioRx.received(message_t* frame, ieee154_reftime_t *timestamp)
+ {
+ return frame;
+ }
+
+ async command ieee154_status_t BroadcastTx.transmitNow(ieee154_txframe_t *frame)
+ {
+ return IEEE154_TRANSACTION_OVERFLOW;
+ }
+
+ event void Token.granted()
+ {
+ }
+
+ async event void RadioTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime){}
+
+ default event void FrameTx.transmitDone(ieee154_txframe_t *data, ieee154_status_t status){}
+ default event message_t* FrameRx.received[uint8_t client](message_t* data){return data;}
+ default async command bool IsRxEnableActive.getNow(){return FALSE;}
+
+ default async command void IndirectTxWaitAlarm.start(uint32_t dt){call Leds.led0On();}
+ default async command void IndirectTxWaitAlarm.stop(){call Leds.led0On();}
+ default async command void IndirectTxWaitAlarm.startAt(uint32_t t0, uint32_t dt){call Leds.led0On();}
+
+ default async command void BroadcastAlarm.start(uint32_t dt){call Leds.led0On();}
+ default async command void BroadcastAlarm.stop(){call Leds.led0On();}
+ default async command void BroadcastAlarm.startAt(uint32_t t0, uint32_t dt){call Leds.led0On();}
+
+ default async command bool IsRxBroadcastPending.getNow(){ return FALSE;}
+ default async event void BroadcastTx.transmitNowDone(ieee154_txframe_t *frame, ieee154_status_t status){}
+ default event message_t* FrameExtracted.received[uint8_t client](message_t* msg, ieee154_txframe_t *txFrame){return msg;}
+ default async command error_t FrameBackup.setNow(ieee154_cap_frame_backup_t* val ){return FAIL;}
+ default async command ieee154_cap_frame_backup_t* FrameRestore.getNow(){return NULL;}
+
+ command error_t WasRxEnabled.enable(){return FAIL;}
+ command error_t WasRxEnabled.disable(){return FAIL;}
+ command error_t FindBeacon.enable(){return FAIL;}
+ command error_t FindBeacon.disable(){return FAIL;}
+}
--- /dev/null
+/*
+ * Copyright (c) 2008, Technische Universitaet Berlin
+ * 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 Technische Universitaet Berlin 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 COPYRIGHT
+ * OWNER OR 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.
+ *
+ * - Revision -------------------------------------------------------------
+ * $Revision$
+ * $Date$
+ * @author Jan Hauer <hauer@tkn.tu-berlin.de>
+ * ========================================================================
+ */
+#include "TKN154_MAC.h"
+generic module NoFrameDispatchQueueP() {
+ provides
+ {
+ interface Init as Reset;
+ interface FrameTx[uint8_t client];
+ interface FrameRx as FrameExtracted[uint8_t client];
+ interface Purge;
+ } uses {
+ interface Queue<ieee154_txframe_t*>;
+ interface FrameTx as FrameTxCsma;
+ interface FrameRx as SubFrameExtracted;
+ }
+}
+implementation
+{
+ command error_t Reset.init() { return SUCCESS; }
+
+ command ieee154_status_t FrameTx.transmit[uint8_t client](ieee154_txframe_t *txFrame)
+ {
+ return IEEE154_TRANSACTION_OVERFLOW;
+ }
+
+ event void FrameTxCsma.transmitDone(ieee154_txframe_t *txFrame, ieee154_status_t status) { }
+
+ event message_t* SubFrameExtracted.received(message_t* frame) { return frame; }
+
+ default event void FrameTx.transmitDone[uint8_t client](ieee154_txframe_t *txFrame, ieee154_status_t status){}
+
+ command ieee154_status_t Purge.purge(uint8_t msduHandle)
+ {
+ return IEEE154_INVALID_HANDLE;
+ }
+
+ default event void Purge.purgeDone(ieee154_txframe_t *txFrame, ieee154_status_t status){}
+}
}
async event void RadioTx.loadDone() { }
-
- async event void RadioTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *t0,
- bool ackPendingFlag, error_t error){}
+
+ async event void RadioTx.transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime){}
+
+ async event void RadioTx.transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParameters, error_t result){}
+
+ async event void RadioTx.transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParameters, error_t result){}
event void ScanTimer.fired() { }
* SPDU (i.e., MSDU) from a local SSCS entity to a single peer SSCS
* entity." (IEEE 802.15.4-2006, Sec. 7.1.1.1)
*
- * The MSDU is the payload portion of a message_t (<code>frame<\code>
- * parameter) and can be accessed through the <code>IEEE154Frame<\code>
+ * The MSDU is the payload portion of a message_t (<tt>frame</tt>
+ * parameter) and can be accessed through the <tt>IEEE154Frame</tt>
* interface. In contrast to the standard interface definition address
* information is not passed as separate parameters; instead, the
- * address information is already part of the <code>frame<\code>,
- * i.e. it must have been set (through the <code>IEEE154Frame<\code>
+ * address information is already part of the <tt>frame</tt>,
+ * i.e. it must have been set (through the <tt>IEEE154Frame</tt>
* interface) before this command is called.
*
* If this command returns IEEE154_SUCCESS, then the confirm event
/**
* Indicates the arrival of a frame. Address information can be accessed
- * through the <code>IEEE154Frame<\code> interface.
+ * through the <tt>IEEE154Frame</tt> interface.
*
* @return A frame buffer for the stack to use for the next received frame
*/
* beacon payload is not empty.
*
* The beacon parameters can be accessed through the
- * <code>IEEE154BeaconFrame<\code> interface. The
- * <code>IEEE154Frame<\code> interface can be used to
+ * <tt>IEEE154BeaconFrame<\tt> interface. The
+ * <tt>IEEE154Frame<\tt> interface can be used to
* inspect the addressing fields in the MAC header.
*
* @param beacon The beacon frame
* command per attribute (and there are no confirm events).
*
* NOTE: for the attributes macBeaconPayload (0x45) and
- * macBeaconPayloadLength (0x46) use the <code>IEEE154TxBeaconPayload <\code>
+ * macBeaconPayloadLength (0x46) use the <tt>IEEE154TxBeaconPayload <\tt>
* interface; for promiscuous mode there is a separate (SplitControl)
* interface.
**/
command ieee154_macBattLifeExtPeriods_t macBattLifeExtPeriods();
/* macBeaconPayload (0x45) and macBeaconPayloadLength (0x46) are read
- * through the <code>IEEE154TxBeaconPayload<\code> interface. */
+ * through the <tt>IEEE154TxBeaconPayload<\tt> interface. */
/** @return PIB attribute macBeaconOrder (0x47) */
command ieee154_macBeaconOrder_t macBeaconOrder();
* command per attribute (and there are no confirm events).
*
* NOTE: for the attributes macBeaconPayload (0x45) and
- * macBeaconPayloadLength (0x46) use the <code>IEEE154TxBeaconPayload <\code>
+ * macBeaconPayloadLength (0x46) use the <tt>IEEE154TxBeaconPayload <\tt>
* interface; for promiscuous mode there is a separate (SplitControl)
* interface.
**/
command ieee154_status_t macBattLifeExtPeriods(ieee154_macBattLifeExtPeriods_t value);
/* macBeaconPayload (0x45) and macBeaconPayloadLength (0x46) are set
- * through the <code>IEEE154TxBeaconPayload<\code> interface. */
+ * through the <tt>IEEE154TxBeaconPayload<\tt> interface. */
/** @param value new PIB attribute value for macBeaconOrder (0x47)
* @returns IEEE154_SUCCESS if PIB attribute was updated, INVALID_PARAMETER if
command ieee154_status_t macPANId(ieee154_macPANId_t value);
/* macPromiscuousMode (0x51) is (re-)set through the
- * <code>PromiscuousMode<\code> (SplitControl) interface. */
+ * <tt>PromiscuousMode<\tt> (SplitControl) interface. */
/** @param value new PIB attribute value for macRxOnWhenIdle (0x52)
* @returns IEEE154_SUCCESS if PIB attribute was updated, INVALID_PARAMETER if
{
/**
* Requests to measure the energy level on the current channel; the
- * measurement should last for <code>duration<\code> symbols and the
- * maximum energy level is signalled through the <code>done<\code>
+ * measurement should last for <tt>duration</tt> symbols and the
+ * maximum energy level is signalled through the <tt>done</tt>
* event.
*
* @param duration Duration of the energy detection measurement
* (in symbol time)
* @return SUCCESS if the request was accepted and only then
- * the <code>done<\code> event will be signalled, FAIL otherwise
+ * the <tt>done</tt> event will be signalled, FAIL otherwise
**/
command error_t start(uint32_t duration);
/**
- * Signalled in response to a call to <code>start<\code>;
+ * Signalled in response to a call to <tt>start<\tt>;
* returns the maximum energy measured on the channel over the
* specified period of time.
*
* @param status SUCCESS if the measurement succeeded
- * and only then <code>EnergyLevel<\code> is valid, FAIL
+ * and only then <tt>EnergyLevel<\tt> is valid, FAIL
* otherwise
* @param EnergyLevel The maximum energy on the channel
**/
*
* @param txFrame the frame to transmit
* @return IEEE154_SUCCESS if the request was accepted and
- * only then <code>transmitDone()</code> will be signalled
+ * only then <tt>transmitDone()</tt> will be signalled
*/
command ieee154_status_t transmit(ieee154_txframe_t *txFrame);
*
* @param txFrame the frame to transmit
* @return IEEE154_SUCCESS if the request was accepted and
- * only then <code>transmitDone()</code> will be signalled
+ * only then <tt>transmitDone()</tt> will be signalled
*/
async command ieee154_status_t transmitNow(ieee154_txframe_t *frame);
{
/**
- * Switches the radio off and changes the radio state to RADIO_OFF. This
+ * Disables the transceiver and changes the radio state to RADIO_OFF. This
* command will succeed only if the current state of the radio is either
* TX_LOADED, RX_PREPARED or RECEIVING.
*
- * @return EALREADY if radio is already switched off <br> FAIL if radio the
- * current radio state is neither TX_LOADED, RX_PREPARED nor RECEIVING <br>
- * SUCCESS if the command was accepted and the <tt>offDone()</tt> event will
- * be signalled.
+ * @return SUCCESS if the command was accepted and the <tt>offDone()</tt>
+ * event will be signalled; EALREADY if radio is already switched off; FAIL
+ * if the current radio state is neither TX_LOADED, RX_PREPARED nor
+ * RECEIVING.
*/
async command error_t off();
**/
async event void offDone();
- /** @return TRUE if the radio is in the state RADIO_OFF, FALSE otherwise */
- async command bool isOff();
+ /**
+ * Tells whether the radio is in state RADIO_OFF.
+ * @return TRUE if the radio is in the state RADIO_OFF, FALSE otherwise
+ */
+ async command bool isOff();
}
#include "TKN154_platform.h"
interface RadioRx
{
-
/**
* Prepares the radio for receive mode. This command will fail, if the radio
* is not in the state RADIO_OFF. The actual receive operation will be
**/
async event void prepareDone();
- /** @return TRUE if the radio is in the state RX_PREPARED, FALSE otherwise */
+ /**
+ * Tells whether the radio is in state RX_PREPARED.
+ * @return TRUE if the radio is in the state RX_PREPARED, FALSE otherwise
+ */
async command bool isPrepared();
/**
* Switches the radio to receive mode at time <tt>t0 + dt</tt>. If
- * <tt>t0</tt> is NULL, then the callee interprets <tt>t0</tt> as the current
- * time.
+ * <tt>t0</tt> is NULL, then the callee interprets <tt>t0</tt> as now.
*
* @param t0 Reference time for receive operation (NULL means now)
*
*/
async command error_t receive(ieee154_reftime_t *t0, uint32_t dt);
- /** @return TRUE if the radio is in the state RECEIVING, FALSE otherwise */
+ /**
+ * Tells whether the radio is in state RECEIVING.
+ * @return TRUE if the radio is in the state RECEIVING, FALSE otherwise
+ */
async command bool isReceiving();
/**
* The frame will be loaded (and the radio will stay in the state
* TX_LOADED) until either the transmission was successful, i.e.
* <tt>transmitDone()</tt> was signalled with a status IEEE154_SUCCESS, or
- * the radio is explicitly switched off through the <tt>RadioOff</tt>
+ * the radio is switched off through the <tt>RadioOff</tt>
* interface. Until then the callee might have to reserve certain resources
* (e.g. the bus connected to the radio), so the caller should keep the time
* while a frame is loaded as short as possible.
/**
* Transmits the frame whose transmission has previously been prepared
- * through a call to <tt>load()</tt>. The actual time of transmission -- the
- * point in time when the first symbol of the PPDU is transmitted -- is
- * defined by: <tt>t0 + dt</tt>. The data type of the <tt>t0</tt> parameter
- * is platform-specific (symbol precision or better) while <tt>dt</tt> is
- * expressed in 802.15.4 symbols. If <tt>t0</tt> is NULL, then the callee
- * interprets <tt>t0</tt> as the current time. The caller guarantees (through
+ * through a call to <tt>load()</tt> at time <tt>t0+dt</tt> or immediately if
+ * <tt>t0</tt> is NULL. In the first case the caller has to guarantee (through
* platform-specific guard times and by calling <tt>transmit</tt> in an
- * atomic block) that the callee can start the transmission on time, taking
- * any prior clear channel assesment(s) into consideration.
- *
- * A transmission may require 0, 1 or 2 prior clear channel assesments
- * (<tt>numCCA</tt> parameter) to be performed 0, 20 or 40 symbols,
- * respectively, before the actual transmission. If a CCA determines a busy
- * channel, then the frame will not be transmitted.
- *
- * A successful transmission may also require an acknowledgement from the
- * destination (indicated through the <tt>ackRequest</tt> parameter); then,
- * the callee has to perform the necessary steps for receiving that
- * acknowledgement (switching the radio to Rx mode immediately after
- * transmission, etc.; for details see IEEE 802.15.4-2006).
- *
- * The <tt>transmit()</tt> command will succeed iff the radio is in state
- * TX_LOADED. The <tt>transmitDone()</tt> event will then signal the result
+ * atomic block) that the callee can start the transmission on time.
+ * The frame is transmitted without carrier sense (without CCA).
+ * The <tt>transmitDone()</tt> event will signal the result
* of the transmission.
*
* @param t0 Reference time for transmission (NULL means now)
- *
* @param dt A positive offset relative to <tt>t0</tt>.
*
- * @param numCCA Number of clear channel assesments.
- *
- * @param ackRequest TRUE means an acknowledgement is required, FALSE means
- * no acknowledgement is not required
- *
* @return SUCCESS if the transmission was triggered successfully and only
* then <tt>transmitDone()</tt> will be signalled; FAIL, if the transmission
* was not triggered because no frame was loaded.
- */
- async command error_t transmit(ieee154_reftime_t *t0, uint32_t dt,
- uint8_t numCCA, bool ackRequest);
+ */
+ async command error_t transmit(ieee154_reftime_t *t0, uint32_t dt);
/**
- * Signalled in response to a call to <tt>transmit()</tt>. Depending on the
- * <tt>error</tt> parameter the radio is now in state RADIO_OFF
- * (<tt>error</tt> == IEEE154_SUCCESS) or still in state TX_LOADED
- * (<tt>error</tt> != IEEE154_SUCCESS). If the transmission succeeded then
- * the time of transmission -- the point in time when the first symbol of the
- * PPDU was transmitted -- will be stored in the metadata field of the frame.
- * In addition, the <tt>t0</tt> parameter will hold a platform-specific
- * representation of the same point in time (possibly with higher precision)
- * to be used as future reference time in a <tt>transmit()</tt> command. If
- * the transmission did not succeed no timestamp will be stored in the
- * metadata portion, but <tt>t0</tt> will still represent the hypothetical
- * transmission time.
- *
- * If <tt>error</tt> has a value other than IEEE154_SUCCESS the frame will
- * stay loaded and a subsequent call to <tt>transmit</tt> will (re-)transmit
- * the same <tt>frame</tt> again. If <tt>error</tt> has a value of
- * IEEE154_SUCCESS then the frame was automatically un-loaded and a new frame
- * has to be loaded before the <tt>transmit()</tt> command will succeed.
- *
- * When the <tt>transmit()</tt> command was called with an
- * <tt>ackRequest</tt> parameter with value TRUE, and <tt>error</tt> has a
- * value of IEEE154_SUCCESS, then this means that a corresponding
- * acknowledgement was successfully received. In this case, the
- * <tt>ackPendingFlag</tt> represents the "pending" flag in the header of the
- * acknowledgement frame (TRUE means set, FALSE means reset).
+ * Signalled in response to a call to <tt>transmit()</tt> and completing the transmission. Depending on the
+ * <tt>error</tt> parameter the radio is now in the state RADIO_OFF
+ * (<tt>error == IEEE154_SUCCESS</tt>) or back in state TX_LOADED
+ * (<tt>error != IEEE154_SUCCESS</tt>).
*
* @param frame The frame that was transmitted.
+ * @param txTime The time of transmission of the first symbol of the PPDU or NULL if the transmission failed.
+ */
+ async event void transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime);
+
+
+ /**
+ * Transmits the frame whose transmission has previously been prepared
+ * through a call to <tt>load()</tt> using the unslotted CSMA-CA
+ * algorithm as specified in the IEEE 802.15.4-2006 standard Sect. 7.5.1.4. The initial
+ * CSMA-CA parameters are passed as a parameter, the algorithm should start immediately.
+ * The <tt>transmitUnslottedCsmaCaDone()</tt> event will signal the result
+ * of the transmission.
+ * A successful transmission may include an acknowledgement from the
+ * destination if the ACK_REQUESTED flag is set in the loaded frame's header; then,
+ * the callee also has to perform the necessary steps for receiving the
+ * acknowledgement (switching the radio to Rx mode immediately after
+ * transmission, etc., as specified in IEEE 802.15.4-2006 Sect. 7.5.6.4).
+ *
+ * @param csmaParameters parameters for the unslotted CSMA-CA algorithm.
*
- * @param t0 The (hypothetical) transmission time; the pointer is only valid
- * until the eventhandler returns.
+ * @return SUCCESS if the unslotted CSMA-CA was triggered successfully,
+ * FAIL otherwise.
+ */
+ async command error_t transmitUnslottedCsmaCa(ieee154_csma_t *csmaParameters);
+
+ /**
+ * Signalled in response to a call to <tt>transmitUnslottedCsmaCa()</tt>.
+ * Depending on the
+ * <tt>error</tt> parameter the radio is now in the state RADIO_OFF
+ * (<tt>error == IEEE154_SUCCESS</tt>) or still in state TX_LOADED
+ * (<tt>error != IEEE154_SUCCESS</tt>). If the transmission succeeded then
+ * the time of the transmission -- the point in time when the first symbol of the
+ * PPDU was transmitted -- will be stored in the metadata field of the frame.
*
+ * @param frame The frame that was transmitted.
+ * @param csmaParameters csmaParameters parameters for the unslotted CSMA-CA algorithm
* @param ackPendingFlag TRUE if an acknowledgement was received and the
* "pending" flag is set in the header of the ACK frame, FALSE otherwise
+ * @param result SUCCESS if the the frame was transmitted (and a matching
+ * acknowledgement was received, if requested); FAIL if the CSMA-CA algorithm failed
+ * because NB > macMaxCsmaBackoffs.
+ *
+ * unslotted CSMA-CA was triggered successfully,
+ * FAIL otherwiseThe time of transmission or NULL if the transmission failed.
+ */
+ async event void transmitUnslottedCsmaCaDone(ieee154_txframe_t *frame,
+ bool ackPendingFlag, ieee154_csma_t *csmaParameters, error_t result);
+
+
+ /**
+ * Transmits the frame whose transmission has previously been prepared
+ * through a call to <tt>load()</tt> using the slotted CSMA-CA
+ * algorithm as specified in the IEEE 802.15.4-2006 standard Sect. 7.5.1.4. The initial
+ * CSMA-CA parameters are passed as a parameter, the algorithm should start immediately,
+ * but the frame transmission should start no later than <tt>slot0Time+dtMax</tt>. The backoff slot boundaries
+ * are defined relative to <tt>slot0Time</tt>, if the <tt>resume</tt>
+ * then the initial backoff (in symbols) is passed as the <tt>initialBackoff</tt> parameter.
+ *
+ * The <tt>transmitSlottedCsmaCaDone()</tt> event will signal the result
+ * of the transmission.
+ * A successful transmission may include an acknowledgement from the
+ * destination if the ACK_REQUESTED flag is set in the loaded frame's header; then,
+ * the callee also has to perform the necessary steps for receiving the
+ * acknowledgement (switching the radio to Rx mode immediately after
+ * transmission, etc., as specified in IEEE 802.15.4-2006 Sect. 7.5.6.4).
+ *
+ * @param slot0Time Reference time (last beacon)
+ * @param dtMax <tt>slot0Time+dtMax</tt> is the last time the frame may be transmitted.
+ * @param resume TRUE means that the initial backoff is defined by the
+ * <tt>initialBackoff</tt> parameter, FALSE means the <tt>initialBackoff</tt>
+ * should be ignored.
+ * @param initialBackoff initial backoff.
+ * @param csmaParameters parameters for the slotted CSMA-CA algorithm.
+ *
+ * @return SUCCESS if the slotted CSMA-CA was triggered successfully,
+ * FAIL otherwise.
+ */
+ async command error_t transmitSlottedCsmaCa(ieee154_reftime_t *slot0Time, uint32_t dtMax,
+ bool resume, uint16_t initialBackoff, ieee154_csma_t *csmaParameters);
+
+ /**
+ * Signalled in response to a call to <tt>transmitSlottedCsmaCa()</tt>.
+ * Depending on the
+ * <tt>error</tt> parameter the radio is now in the state RADIO_OFF
+ * (<tt>error == IEEE154_SUCCESS</tt>) or still in state TX_LOADED
+ * (<tt>error != IEEE154_SUCCESS</tt>). If the transmission succeeded then
+ * the time of the transmission -- the point in time when the first symbol of the
+ * PPDU was transmitted -- will be stored in the metadata field of the frame.
+ * It will also passed (possibly with higher precision) through the
+ * <tt>txTime</tt> parameter.
*
- * @param error SUCCESS if the transmission succeeded (including successful
- * CCA and acknowledgement reception, if requested); EBUSY if CCA was
- * unsuccessful (frame was not transmitted); ENOACK if frame was transmitted
- * but no matching acknowledgement was received.
- **/
- async event void transmitDone(ieee154_txframe_t *frame, ieee154_reftime_t *t0,
- bool ackPendingFlag, error_t error);
+ * @param frame The frame that was transmitted.
+ * @param txTime The time of transmission of the first symbol of the PPDU or NULL if the transmission failed.
+ * @param ackPendingFlag TRUE if an acknowledgement was received and the
+ * "pending" flag is set in the header of the ACK frame, FALSE otherwise
+ * @param remainingBackoff only valid if <tt>error == ERETRY</tt>, i.e.
+ * when the frame could not be transmitted because transmission would have
+ * started later than <tt>slot0Time+dtMax</tt>; then it
+ * specifies the remaining offset (in symbols) relative to <tt>slot0Time+dtMax</tt>,
+ * when the frame would have been transmitted
+ * @param csmaParameters csmaParameters parameters for the unslotted CSMA-CA algorithm
+ *
+ * @result result SUCCESS if the the frame was transmitted (and a matching
+ * acknowledgement was received, if requested); FAIL if the CSMA-CA algorithm failed
+ * because NB > macMaxCsmaBackoffs; ERETRY if the frame could not be transmitted because transmission would have
+ * started later than <tt>slot0Time+dtMax</tt>
+ */
+ async event void transmitSlottedCsmaCaDone(ieee154_txframe_t *frame, ieee154_reftime_t *txTime,
+ bool ackPendingFlag, uint16_t remainingBackoff, ieee154_csma_t *csmaParameters, error_t result);
}
/**
* Sets the addressing fields in the MAC header of a frame. The source
* PAN identifier and the source address will be set automatically, their
- * values depend on the <code>SrcAddrMode</code> parameter: if
- * <code>SrcAddrMode</code> is a short or extended address, then
- * the current PIB attributes <code>macShortAddress</code> or
- * <code>aExtendedAddress</code> and <code>macPANId</code> are used.
+ * values depend on the <tt>SrcAddrMode</tt> parameter: if
+ * <tt>SrcAddrMode</tt> is a short or extended address, then
+ * the current PIB attributes <tt>macShortAddress</tt> or
+ * <tt>aExtendedAddress</tt> and <tt>macPANId</tt> are used.
*
* @param frame the frame
* @param srcAddrMode the source addressing mode
/**
* Returns the point in time when the frame was received. If
- * <code>isTimestampValid()<\code> returns FALSE then the
+ * <tt>isTimestampValid()<\tt> returns FALSE then the
* timestamp is not valid and must be ignored.
*
* @param frame the frame
* Returns the type of the frame
* BEACON=0, DATA=1, ACK=2, COMMAND=3.
*
- * Note: For beacon frames one can use the <code>IEEE154BeaconFrame<\code>
+ * Note: For beacon frames one can use the <tt>IEEE154BeaconFrame<\tt>
* interface to inspect additional fields of the frame.
*
* @param frame the frame
* received while in promiscuous mode, because then no filtering
* (except CRC check) was applied. Note: if this command returns
* FALSE, then all other commands in this interface (except
- * <code>wasPromiscuousModeEnabled()</code>) and the
- * <code>IEEE154BeaconFrame</code> interface return undefined values!
+ * <tt>wasPromiscuousModeEnabled()</tt>) and the
+ * <tt>IEEE154BeaconFrame</tt> interface return undefined values!
*
* @param frame the frame
* @return TRUE if frame has a standard compliant header,
* Sets the beacon payload portion for all subsequently transmitted beacons.
* This command replaces the MLME-SET command for the PIB attribute values
* 0x45 (macBeaconPayload) and 0x46 (macBeaconPayloadLength). The
- * <code>setBeaconPayloadDone()<\code> event will be signalled when the
- * beacon payload has been set -- until then <code>beaconPayload<\code> must
+ * <tt>setBeaconPayloadDone()<\tt> event will be signalled when the
+ * beacon payload has been set -- until then <tt>beaconPayload<\tt> must
* not be modified.
*
* @param beaconPayload the new beacon payload
* @param length the length of the new beacon payload (in byte)
*
* @return EBUSY if another transaction is pending, ESIZE if length is too big,
- * SUCCESS otherwise (and only then the <code>setBeaconPayloadDone<\code> event
+ * SUCCESS otherwise (and only then the <tt>setBeaconPayloadDone<\tt> event
* will be signalled)
*/
command error_t setBeaconPayload(void *beaconPayload, uint8_t length);
/**
- * Signalled in response to a <code>setBeaconPayload()<\code> request.
+ * Signalled in response to a <tt>setBeaconPayload()<\tt> request.
* Indicates that the beacon payload has been copied and returns the
* ownership of the buffer to the next higher layer.
*
- * @param beaconPayload the <code>beaconPayload<\code> passed in the
- * <code>setBeaconPayload()<\code> command
- * @param length the <code>length<\code> passed in the
- * <code>setBeaconPayload()<\code> command
+ * @param beaconPayload the <tt>beaconPayload<\tt> passed in the
+ * <tt>setBeaconPayload()<\tt> command
+ * @param length the <tt>length<\tt> passed in the
+ * <tt>setBeaconPayload()<\tt> command
*/
event void setBeaconPayloadDone(void *beaconPayload, uint8_t length);
/**
* Replaces (overwrites) a portion of the current beacon payload. Whenever
* possible, to minimize overhead, the next higher layer should prefer this
- * command over the <code>setBeaconPayload()<\code> command. The
- * <code>modifyBeaconPayloadDone()<\code> event will be signalled when the
- * beacon payload has been updated -- until then <code>buffer<\code> must
+ * command over the <tt>setBeaconPayload()<\tt> command. The
+ * <tt>modifyBeaconPayloadDone()<\tt> event will be signalled when the
+ * beacon payload has been updated -- until then <tt>buffer<\tt> must
* not be modified.
*
* @param offset offset into the current beacon payload
* @param length the length of the buffer
*
* @return EBUSY if another transaction is pending, ESIZE if offset+length is too big,
- * SUCCESS otherwise (and only then the <code>modifyBeaconPayloadDone<\code> event
+ * SUCCESS otherwise (and only then the <tt>modifyBeaconPayloadDone<\tt> event
* will be signalled)
*/
command error_t modifyBeaconPayload(uint8_t offset, void *buffer, uint8_t bufferLength);
/**
- * Signalled in response to a <code>modifyBeaconPayload()<\code> request.
+ * Signalled in response to a <tt>modifyBeaconPayload()<\tt> request.
* Indicates that the beacon payload has been updated.
*
- * @param offset the <code>offset<\code> passed in the
- * <code>modifyBeaconPayload()<\code> command
- * @param buffer the <code>buffer<\code> passed in the
- * <code>modifyBeaconPayload()<\code> command
- * @param bufferLength the <code>bufferLength<\code> passed in the
- * <code>modifyBeaconPayload()<\code> command
+ * @param offset the <tt>offset<\tt> passed in the
+ * <tt>modifyBeaconPayload()<\tt> command
+ * @param buffer the <tt>buffer<\tt> passed in the
+ * <tt>modifyBeaconPayload()<\tt> command
+ * @param bufferLength the <tt>bufferLength<\tt> passed in the
+ * <tt>modifyBeaconPayload()<\tt> command
*/
event void modifyBeaconPayloadDone(uint8_t offset, void *buffer, uint8_t bufferLength);
* time to update the beacon payload (if desired).
*
* The usual policy is that (1) this event is signalled before every beacon
- * transmission, and (2) that a subsequent call to <code>setPayload<\code>
+ * transmission, and (2) that a subsequent call to <tt>setPayload<\tt>
* will update the beacon payload portion of this beacon. However,
* because of tight timing constraints in beacon-enabled mode neither can be
* guaranteed!
/**
* Indicates that a beacon frame has been transmitted (the
- * <code>getBeaconPayload<\code> command can be used to inspect the
+ * <tt>getBeaconPayload<\tt> command can be used to inspect the
* beacon payload).
*/
event void beaconTransmitted();
Packet = MAC;
components CC2420TKN154C as PHY,
- new Alarm62500hz32VirtualizedC() as PHYAlarm1,
+ new Alarm62500hz32C() as PHYAlarm1,
new Alarm62500hz32VirtualizedC() as PHYAlarm2,
+ new Alarm62500hz32C() as TKN154TimingPAlarm,
LocalTime62500hzC, TKN154TimingP;
// wire PHY to the PIB
PHY.TimeCalc -> MAC;
PHY.Leds -> LedsC;
TKN154TimingP.TimeCalc -> MAC;
- TKN154TimingP.LocalTime -> LocalTime62500hzC;
+ TKN154TimingP.Leds -> LedsC;
+ TKN154TimingP.SymbolAlarm -> TKN154TimingPAlarm;
components new Alarm62500hz32VirtualizedC() as MACAlarm1,
new Alarm62500hz32VirtualizedC() as MACAlarm2,
components RandomC, LedsC, NoLedsC;
MAC.Random -> RandomC;
MAC.Leds -> LedsC;
+ PHY.Random -> RandomC;
#ifdef TKN154_SERIAL_DEBUG
components SerialDebugC as Debug;
+ifdef TKN154_PIERCEBOARD
+CFLAGS += -I$(TOSDIR)/platforms/telosb/mac/tkn154/timer/pierceboard
+endif
+
CFLAGS += -I$(TOSDIR)/platforms/telosb/mac/tkn154 \
-I$(TOSDIR)/platforms/telosb/mac/tkn154/timer \
-I$(TOSDIR)/chips/cc2420_tkn154
*/
/**
- * NOTE:
* In slotted CSMA-CA frames must be sent on backoff boundaries (slot width:
- * 320 us). On TelosB the only clock source with sufficient accuracy is the
- * external quartz, unfortunately it is not precise enough (32.768 Hz).
- * Therefore, currently the following code is not even trying to achieve
- * accurate timing.
+ * 320 us). The TelosB platform lacks a clock with sufficient precision/
+ * accuracy, i.e. for slotted CSMA-CA the timing is *not* standard compliant.
*/
#include "TKN154_platform.h"
provides interface ReliableWait;
provides interface ReferenceTime;
uses interface TimeCalc;
- uses interface LocalTime<T62500hz>;
+ uses interface Alarm<T62500hz,uint32_t> as SymbolAlarm;
+ uses interface Leds;
}
implementation
{
-
-#define UWAIT1 nop();nop();nop();nop()
-#define UWAIT2 UWAIT1;UWAIT1
-#define UWAIT4 UWAIT2;UWAIT2
-#define UWAIT8 UWAIT4;UWAIT4
+ enum {
+ S_WAIT_OFF,
+ S_WAIT_RX,
+ S_WAIT_TX,
+ S_WAIT_BACKOFF,
+ };
+ uint8_t m_state = S_WAIT_OFF;
async command void CaptureTime.convert(uint16_t time, ieee154_reftime_t *localTime, int16_t offset)
{
// we now need to convert the capture "time" into ieee154_reftime_t.
// With the 32768Hz quartz we don't have enough precision anyway,
// so the code below generates a timestamp that is not accurate
- // (deviating about +-50 microseconds; this could probably
+ // (deviating about +-50 microseconds, which could probably
// improved if we don't go through LocalTime)
uint16_t tbr1, tbr2, delta;
uint32_t now;
tbr1 = TBR;
tbr2 = TBR;
} while (tbr1 != tbr2); // majority vote required (see msp430 manual)
- now = call LocalTime.get();
+ now = call SymbolAlarm.getNow();
}
if (time < tbr1)
delta = tbr1 - time;
async command void ReliableWait.busyWait(uint16_t dt)
{
- uint32_t start = call LocalTime.get();
- while (!call TimeCalc.hasExpired(start, dt))
- ;
+ uint16_t tbr1, tbr2, tbrVal;
+ atomic {
+ do {
+ tbr1 = TBR;
+ tbr2 = TBR;
+ } while (tbr1 != tbr2); // majority vote required (see msp430 manual)
+ }
+ tbrVal = tbr1 + dt;
+ atomic {
+ do {
+ tbr1 = TBR;
+ tbr2 = TBR;
+ } while (tbr1 != tbr2 || tbr1 != tbrVal); // majority vote required (see msp430 manual)
+ }
}
- async command void ReliableWait.waitCCA(ieee154_reftime_t *t0, uint16_t dt)
+ async command void ReliableWait.waitRx(ieee154_reftime_t *t0, uint16_t dt)
{
- while (!call TimeCalc.hasExpired(*t0, dt))
- ;
- signal ReliableWait.waitCCADone();
+ if (m_state != S_WAIT_OFF){
+ call Leds.led0On();
+ return;
+ }
+ m_state = S_WAIT_RX;
+ call SymbolAlarm.startAt(*t0 - 12, dt); // subtract 12 symbols required for Rx calibration
+ //signal SymbolAlarm.fired();
}
async command void ReliableWait.waitTx(ieee154_reftime_t *t0, uint16_t dt)
{
- while (!call TimeCalc.hasExpired(*t0, dt))
- ;
- signal ReliableWait.waitTxDone();
+ if (m_state != S_WAIT_OFF){
+ call Leds.led0On();
+ return;
+ }
+ m_state = S_WAIT_TX;
+ call SymbolAlarm.startAt(*t0 - 12, dt); // subtract 12 symbols required for Tx calibration
+ }
+
+ async command void ReliableWait.waitBackoff(ieee154_reftime_t *t0, uint16_t dt)
+ {
+ if (m_state != S_WAIT_OFF){
+ call Leds.led0On();
+ return;
+ }
+ m_state = S_WAIT_BACKOFF;
+ call SymbolAlarm.startAt(*t0, dt);
+ //signal SymbolAlarm.fired();
}
- async command void ReliableWait.waitRx(ieee154_reftime_t *t0, uint16_t dt)
+ async event void SymbolAlarm.fired()
{
- while (!call TimeCalc.hasExpired(*t0, dt))
- ;
- signal ReliableWait.waitRxDone();
+ switch (m_state)
+ {
+ case S_WAIT_RX: m_state = S_WAIT_OFF; signal ReliableWait.waitRxDone(); break;
+ case S_WAIT_TX: m_state = S_WAIT_OFF; signal ReliableWait.waitTxDone(); break;
+ case S_WAIT_BACKOFF: m_state = S_WAIT_OFF; signal ReliableWait.waitBackoffDone(); break;
+ default: call Leds.led0On(); break;
+ }
}
-
+
+ async command void ReliableWait.busyWaitSlotBoundaryCCA(ieee154_reftime_t *t0, uint16_t *dt) { }
+ async command void ReliableWait.busyWaitSlotBoundaryTx(ieee154_reftime_t *t0, uint16_t dt)
+ {
+ // we cannot meet the timing constraints, but there should at least roughly
+ // be 20 symbols between the first and the seconds CCA
+ call ReliableWait.busyWait(20);
+ }
+
async command void ReferenceTime.getNow(ieee154_reftime_t* reftime, uint16_t dt)
{
- *reftime = call LocalTime.get();
+ *reftime = call SymbolAlarm.getNow() + dt;
}
async command uint32_t ReferenceTime.toLocalTime(ieee154_reftime_t* refTime)
enum {
// guard time to give up the token before actual end of CAP/CFP
- IEEE154_RADIO_GUARD_TIME = 1000,
+ IEEE154_ACTIVE_PERIOD_GUARD_TIME = 300,
// the expected time for a RadioTx.prepare() operation to execute (return)
IEEE154_RADIO_TX_PREPARE_DELAY = 220,
implementation
{
/**
- * This is the place where we cheat: since we don't have a clock source
- * running at 62500 Hz, we cast 2 symbols to 1 tick of the 32768
- * clock, which introduces a small (5%) error.
-*/
+ * TelosB lacks a clock with the precision and accuracy
+ * required by the 802.15.4 standard (62500 Hz, 40 ppm).
+ * As a workaround, we cast one tick of the 32768 Hz clock to
+ * two 802.15.4 symbols, which introduces a small (5%) error.
+ * Thus the channel access in particular in beacon-enabled PANs
+ * (slotted CSMA-CA) is not be standard-compliant!
+ */
#warning "Warning: MAC timing is not standard compliant (the symbol clock is based on the 32768 Hz oscillator)!"
async command void Alarm.start[ uint8_t num ](uint32_t dt){ call AlarmFrom.start[num](dt >> 1);}
async command void Alarm.startAt[ uint8_t num ](uint32_t t0, uint32_t dt){
// t0 occured before "now"
- uint32_t now = call Alarm.getNow[num](), elapsed;
- if (t0 <= now)
- elapsed = now - t0;
- else
- elapsed = ~(t0 - now) + 1;
- if (elapsed > dt)
- elapsed = dt;
- dt -= elapsed;
- call AlarmFrom.start[num](dt >> 1);
+ atomic {
+ uint32_t now = call Alarm.getNow[num](), elapsed;
+ if (t0 < now)
+ elapsed = now - t0;
+ else
+ elapsed = ~(t0 - now) + 1;
+ if (elapsed > dt)
+ dt = elapsed;
+ dt -= elapsed;
+ call Alarm.start[num](dt);
+ }
}
/******************** Defaults ****************************/
--- /dev/null
+#include "Timer62500hz.h"
+generic configuration Alarm62500hz32C()
+{
+ provides interface Alarm<T62500hz,uint32_t> as Alarm;
+}
+implementation
+{
+ components new Alarm32khz32C(), MainC;
+ components new Alarm62500hz32P();
+
+ Alarm = Alarm62500hz32P;
+
+ MainC -> Alarm32khz32C.Init;
+ Alarm62500hz32P.AlarmFrom -> Alarm32khz32C;
+}
--- /dev/null
+/*
+ * Copyright (c) 2008, Technische Universitaet Berlin
+ * 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 Technische Universitaet Berlin 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 COPYRIGHT
+ * OWNER OR 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.
+ *
+ * - Revision -------------------------------------------------------------
+ * $Date$
+ * @author Jan Hauer <hauer@tkn.tu-berlin.de>
+ * ========================================================================
+ */
+
+generic module Alarm62500hz32P()
+
+{
+ provides interface Alarm<T62500hz,uint32_t> as Alarm;
+ uses interface Alarm<T32khz,uint32_t> as AlarmFrom;
+}
+implementation
+{
+/**
+ * TelosB lacks a clock with the precision and accuracy
+ * required by the 802.15.4 standard (62500 Hz, 40 ppm).
+ * As a workaround, we cast one tick of the 32768 Hz clock to
+ * two 802.15.4 symbols, which introduces a small (5%) error.
+ * Thus the channel access in particular in beacon-enabled PANs
+ * (slotted CSMA-CA) is not be standard-compliant!
+ */
+
+ async command void Alarm.start(uint32_t dt){ call AlarmFrom.start(dt >> 1);}
+ async command void Alarm.stop(){ call AlarmFrom.stop();}
+ async event void AlarmFrom.fired(){ signal Alarm.fired();}
+ async command bool Alarm.isRunning(){ return call AlarmFrom.isRunning();}
+ async command uint32_t Alarm.getAlarm(){ return call AlarmFrom.getAlarm() << 1;}
+
+ async command uint32_t Alarm.getNow(){
+ // this might shift out the most significant bit
+ // that's why Alarm.startAt() is converted to a Alarm.start()
+ return call AlarmFrom.getNow() << 1;
+ }
+
+ async command void Alarm.startAt(uint32_t t0, uint32_t dt){
+ // t0 occured before "now"
+ atomic {
+ uint32_t now = call Alarm.getNow(), elapsed;
+ if (t0 < now)
+ elapsed = now - t0;
+ else
+ elapsed = ~(t0 - now) + 1;
+ if (elapsed > dt)
+ dt = elapsed;
+ dt -= elapsed;
+ call Alarm.start(dt);
+ }
+ }
+
+ /******************** Defaults ****************************/
+
+ default async command void AlarmFrom.start(uint32_t dt){ }
+ default async command void AlarmFrom.stop(){ }
+ default async command bool AlarmFrom.isRunning(){ return FALSE;}
+ default async event void Alarm.fired(){}
+ default async command void AlarmFrom.startAt(uint32_t t0, uint32_t dt){ }
+ default async command uint32_t AlarmFrom.getNow(){ return 0;}
+ default async command uint32_t AlarmFrom.getAlarm(){ return 0;}
+}