/**
* @author Jonathan Hui <jhui@archrock.com>
+ * @author David Moss
+ * @author Jung Il Choi
* @version $Revision$ $Date$
*/
+#include "CC2420.h"
+#include "crc.h"
+
module CC2420TransmitP {
provides interface Init;
- provides interface AsyncStdControl;
+ provides interface StdControl;
provides interface CC2420Transmit as Send;
- provides interface CsmaBackoff;
+ provides interface RadioBackoff;
provides interface RadioTimeStamping as TimeStamp;
-
+ provides interface CC2420Cca;
+
uses interface Alarm<T32khz,uint32_t> as BackoffTimer;
+ uses interface CC2420Packet;
uses interface GpioCapture as CaptureSFD;
uses interface GeneralIO as CCA;
uses interface GeneralIO as CSN;
uses interface CC2420Strobe as STXON;
uses interface CC2420Strobe as STXONCCA;
uses interface CC2420Strobe as SFLUSHTX;
+ uses interface CC2420Register as MDMCTRL1;
+ uses interface Timer<TMilli> as LplDisableTimer;
uses interface CC2420Receive;
uses interface Leds;
-
}
implementation {
S_SFD,
S_EFD,
S_ACK_WAIT,
- S_CANCEL,
+ S_LOAD_CANCEL,
+ S_TX_CANCEL,
+ S_CCA_CANCEL,
} cc2420_transmit_state_t;
// This specifies how many jiffies the stack should wait after a
CC2420_ABORT_PERIOD = 320
};
- norace message_t* m_msg;
+ norace message_t *m_msg;
+
norace bool m_cca;
+
norace uint8_t m_tx_power;
+
cc2420_transmit_state_t m_state = S_STOPPED;
+
bool m_receiving = FALSE;
+
uint16_t m_prev_time;
+
+ bool signalSendDone;
+
+ /** TRUE if the current lpl tx is taking place with continuous modulation */
+ norace bool continuousModulation;
+
+ /** 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;
+
+ /** The low power listening backoff period */
+ norace uint16_t myLplBackoff;
+
+ /***************** Prototypes ****************/
+ error_t send( message_t *p_msg, bool cca );
+ error_t resend( bool cca );
void loadTXFIFO();
void attemptSend();
-
- cc2420_header_t* getHeader( message_t* msg ) {
- return (cc2420_header_t*)( msg->data - sizeof( cc2420_header_t ) );
- }
-
- cc2420_metadata_t* getMetadata( message_t* msg ) {
- return (cc2420_metadata_t*)msg->metadata;
- }
-
- void startBackoffTimer(uint16_t time) {
- call BackoffTimer.start(time);
- }
-
- void stopBackoffTimer() {
- call BackoffTimer.stop();
- }
-
- error_t acquireSpiResource() {
- error_t error = call SpiResource.immediateRequest();
- if ( error != SUCCESS )
- call SpiResource.request();
- return error;
- }
-
- error_t releaseSpiResource() {
- return call SpiResource.release();
- }
-
- void signalDone( error_t err ) {
- atomic m_state = S_STARTED;
- signal Send.sendDone( m_msg, err );
- }
-
+ void congestionBackoff();
+ error_t acquireSpiResource();
+ error_t releaseSpiResource();
+ void signalDone( error_t err );
+
+ task void startLplTimer();
+
+ /***************** Init Commands *****************/
command error_t Init.init() {
call CCA.makeInput();
call CSN.makeOutput();
return SUCCESS;
}
- async command error_t AsyncStdControl.start() {
+ /***************** StdControl Commands ****************/
+ command error_t StdControl.start() {
atomic {
call CaptureSFD.captureRisingEdge();
m_state = S_STARTED;
return SUCCESS;
}
- async command error_t AsyncStdControl.stop() {
+ command error_t StdControl.stop() {
atomic {
m_state = S_STOPPED;
- stopBackoffTimer();
+ call BackoffTimer.stop();
call CaptureSFD.disable();
+ call SpiResource.release();
}
return SUCCESS;
}
- error_t send( message_t* p_msg, bool cca ) {
+ /**************** Send Commands ****************/
+ async command error_t Send.send( message_t* p_msg, bool useCca ) {
+ return send( p_msg, useCca );
+ }
+
+ async command error_t Send.resend(bool useCca) {
+ return resend( useCca );
+ }
+
+ async command error_t Send.cancel() {
atomic {
- if ( m_state != S_STARTED )
- return FAIL;
- m_state = S_LOAD;
- m_cca = cca;
- m_msg = p_msg;
+ signalSendDone = FALSE;
+ switch( m_state ) {
+ case S_LOAD:
+ m_state = S_LOAD_CANCEL;
+ break;
+
+ case S_SAMPLE_CCA:
+ m_state = S_CCA_CANCEL;
+ break;
+
+ case S_BEGIN_TRANSMIT:
+ m_state = S_TX_CANCEL;
+ break;
+
+ default:
+ // cancel not allowed while radio is busy transmitting
+ return FAIL;
+ }
}
- if ( acquireSpiResource() == SUCCESS )
- loadTXFIFO();
-
return SUCCESS;
-
}
- async command error_t Send.sendCCA( message_t* p_msg ) {
- return send( p_msg, TRUE );
+ async command error_t Send.modify( uint8_t offset, uint8_t* buf,
+ uint8_t len ) {
+ call CSN.clr();
+ call TXFIFO_RAM.write( offset, buf, len );
+ call CSN.set();
+ return SUCCESS;
}
- async command error_t Send.send( message_t* p_msg ) {
- return send( p_msg, FALSE );
+ /***************** 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;
}
-
- error_t resend( bool cca ) {
-
- atomic {
- if ( m_state != S_STARTED )
- return FAIL;
- m_cca = cca;
- m_state = cca ? S_SAMPLE_CCA : S_BEGIN_TRANSMIT;
- }
-
- if ( m_cca ) {
- startBackoffTimer( signal CsmaBackoff.initial( m_msg ) *
- CC2420_BACKOFF_PERIOD );
- }
- else if ( acquireSpiResource() == SUCCESS ) {
- attemptSend();
- }
-
- return SUCCESS;
+ /**
+ * 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 error_t Send.resendCCA() {
- return resend( TRUE );
+ /**
+ * Must be called within a requestLplBackoff event
+ * @param backoffTime the amount of time in some unspecified units to backoff
+ */
+ async command void RadioBackoff.setLplBackoff(uint16_t backoffTime) {
+ myLplBackoff = backoffTime + 1;
}
-
- async command error_t Send.resend() {
- return resend( FALSE );
+
+ async command void RadioBackoff.setCca(bool useCca) {
}
+
+
+
+ /***************** CC2420Cca Commands ****************/
+ /**
+ * @return TRUE if the CCA pin shows a clear channel
+ */
+ command bool CC2420Cca.isChannelClear() {
+ return call CCA.get();
+ }
+
- async command error_t Send.cancel() {
-
- stopBackoffTimer();
-
+ /**
+ * The CaptureSFD event is actually an interrupt from the capture pin
+ * which is connected to timing circuitry and timer modules. This
+ * type of interrupt allows us to see what time (being some relative value)
+ * the event occurred, and lets us accurately timestamp our packets. This
+ * allows higher levels in our system to synchronize with other nodes.
+ *
+ * Because the SFD events can occur so quickly, and the interrupts go
+ * in both directions, we set up the interrupt but check the SFD pin to
+ * determine if that interrupt condition has already been met - meaning,
+ * we should fall through and continue executing code where that interrupt
+ * would have picked up and executed had our microcontroller been fast enough.
+ */
+ async event void CaptureSFD.captured( uint16_t time ) {
atomic {
switch( m_state ) {
- case S_LOAD:
- m_state = S_CANCEL;
- break;
- case S_SAMPLE_CCA: case S_BEGIN_TRANSMIT:
- m_state = S_STARTED;
- break;
+
+ case S_SFD:
+ call CaptureSFD.captureFallingEdge();
+ signal TimeStamp.transmittedSFD( time, m_msg );
+ releaseSpiResource();
+ call BackoffTimer.stop();
+ m_state = S_EFD;
+ if ( ( ( (call CC2420Packet.getHeader( m_msg ))->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7 ) == IEEE154_TYPE_DATA ) {
+ (call CC2420Packet.getMetadata( m_msg ))->time = time;
+ }
+
+ if ( call SFD.get() ) {
+ break;
+ }
+ /** Fall Through because the next interrupt was already received */
+
+ case S_EFD:
+ call CaptureSFD.captureRisingEdge();
+ if ( (call CC2420Packet.getHeader( m_msg ))->fcf & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
+ m_state = S_ACK_WAIT;
+ call BackoffTimer.start( CC2420_ACK_WAIT_DELAY );
+ } else {
+
+#ifdef NOACK_LOW_POWER_LISTENING
+ if(continuousModulation) {
+ // Wait for the LplDisableTimer to fire before running signalDone()
+ return;
+ }
+#endif
+ signalDone(SUCCESS);
+ }
+
+ if ( !call SFD.get() ) {
+ break;
+ }
+ /** Fall Through because the next interrupt was already received */
+
default:
- // cancel not allowed while radio is busy transmitting
- return FAIL;
+ if ( !m_receiving ) {
+ call CaptureSFD.captureFallingEdge();
+ signal TimeStamp.receivedSFD( time );
+ call CC2420Receive.sfd( time );
+ m_receiving = TRUE;
+ m_prev_time = time;
+ if ( call SFD.get() ) {
+ // wait for the next interrupt before moving on
+ return;
+ }
+ }
+
+ call CaptureSFD.captureRisingEdge();
+ m_receiving = FALSE;
+ if ( time - m_prev_time < 10 ) {
+ call CC2420Receive.sfd_dropped();
+ }
+ break;
+
}
}
+ }
- return SUCCESS;
+ /***************** CC2420Receive Events ****************/
+ /**
+ * If the packet we just received was an ack that we were expecting,
+ * our send is complete.
+ */
+ 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;
+ if ( type == IEEE154_TYPE_ACK ) {
+ ack_header = call CC2420Packet.getHeader( ack_msg );
+ msg_header = call CC2420Packet.getHeader( m_msg );
+ msg_metadata = call CC2420Packet.getMetadata( m_msg );
+ ack_buf = (uint8_t *) ack_header;
+ length = ack_header->length;
+
+ if ( m_state == S_ACK_WAIT &&
+ msg_header->dsn == ack_header->dsn ) {
+ call BackoffTimer.stop();
+ msg_metadata->ack = TRUE;
+ msg_metadata->rssi = ack_buf[ length - 1 ];
+ msg_metadata->lqi = ack_buf[ length ] & 0x7f;
+ signalDone(SUCCESS);
+ }
+ }
}
- void loadTXFIFO() {
- cc2420_header_t* header = getHeader( m_msg );
- uint8_t tx_power = getMetadata( m_msg )->tx_power;
- if ( !tx_power )
- tx_power = CC2420_DEF_RFPOWER;
- call CSN.clr();
- if ( m_tx_power != tx_power )
- call TXCTRL.write( ( 2 << CC2420_TXCTRL_TXMIXBUF_CUR ) |
- ( 3 << CC2420_TXCTRL_PA_CURRENT ) |
- ( 1 << CC2420_TXCTRL_RESERVED ) |
- ( tx_power << CC2420_TXCTRL_PA_LEVEL ) );
- m_tx_power = tx_power;
- call TXFIFO.write( (uint8_t*)header, header->length - 1 );
+ /***************** 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_LOAD_CANCEL:
+ case S_CCA_CANCEL:
+ case S_TX_CANCEL:
+ call CSN.clr();
+ call SFLUSHTX.strobe();
+ call CSN.set();
+ releaseSpiResource();
+ atomic {
+ if (signalSendDone) {
+ signalDone(ECANCEL);
+ } else {
+ m_state = S_STARTED;
+ }
+ }
+ 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 ) {
+ error_t error ) {
call CSN.set();
-
- if ( m_state == S_CANCEL ) {
- m_state = S_STARTED;
- }
- else if ( !m_cca ) {
- m_state = S_BEGIN_TRANSMIT;
+ if ( m_state == S_LOAD_CANCEL ) {
+ atomic {
+ call CSN.clr();
+ call SFLUSHTX.strobe();
+ call CSN.set();
+ }
+ releaseSpiResource();
+ if (signalSendDone) {
+ signalDone(ECANCEL);
+ } else {
+ m_state = S_STARTED;
+ }
+
+ } else if ( !m_cca ) {
+ atomic {
+ if (m_state == S_LOAD_CANCEL) {
+ m_state = S_TX_CANCEL;
+ } else {
+ m_state = S_BEGIN_TRANSMIT;
+ }
+ }
attemptSend();
- }
- else {
+
+ } else {
releaseSpiResource();
- m_state = S_SAMPLE_CCA;
- startBackoffTimer( signal CsmaBackoff.initial( m_msg ) *
- CC2420_BACKOFF_PERIOD );
+ atomic {
+ if (m_state == S_LOAD_CANCEL) {
+ m_state = S_CCA_CANCEL;
+ } else {
+ m_state = S_SAMPLE_CCA;
+ }
+ }
+
+ signal RadioBackoff.requestInitialBackoff(m_msg);
+ call BackoffTimer.start(myInitialBackoff);
}
-
}
- void congestionBackoff() {
- atomic {
- uint16_t time = signal CsmaBackoff.congestion( m_msg );
- if ( time )
- startBackoffTimer( time * CC2420_BACKOFF_PERIOD );
- else
- m_state = S_STARTED;
- }
+
+ 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 BackoffTimer.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;
- startBackoffTimer( CC2420_TIME_ACK_TURNAROUND );
- }
- else {
- congestionBackoff();
- }
- break;
-
- case S_BEGIN_TRANSMIT :
- if ( acquireSpiResource() == SUCCESS )
- attemptSend();
- break;
-
- case S_ACK_WAIT :
- signalDone( SUCCESS );
- break;
-
-#ifdef PLATFORM_MICAZ
+
+ 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 BackoffTimer.start( CC2420_TIME_ACK_TURNAROUND );
+
+ } else {
+ congestionBackoff();
+ }
+ break;
+
+ case S_CCA_CANCEL:
+ m_state = S_TX_CANCEL;
+ /** Fall Through */
+
+ case S_BEGIN_TRANSMIT:
+ case S_TX_CANCEL:
+ if ( acquireSpiResource() == SUCCESS ) {
+ attemptSend();
+ }
+ break;
+
+ case S_ACK_WAIT:
+ signalDone( SUCCESS );
+ break;
+
case S_SFD:
- // We didn't receive an SFD interrupt within CC2420_ABORT_PERIOD
- // jiffies. Assume something is wrong.
- call SFLUSHTX.strobe();
- call CaptureSFD.disable();
- call CaptureSFD.captureRisingEdge();
- signalDone( ERETRY );
- break;
-#endif
+ // We didn't receive an SFD interrupt within CC2420_ABORT_PERIOD
+ // jiffies. Assume something is wrong.
+ call SFLUSHTX.strobe();
+ call CaptureSFD.captureRisingEdge();
+ releaseSpiResource();
+ signalDone( ERETRY );
+ break;
+
default:
- break;
+ break;
+ }
+ }
+ }
+
+ event void LplDisableTimer.fired() {
+ call MDMCTRL1.write(0 << CC2420_MDMCTRL1_TX_MODE);
+ signalDone( SUCCESS );
+ }
+
+ /***************** 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 send( message_t* p_msg, 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_state = S_LOAD;
+ m_cca = cca;
+ m_msg = p_msg;
+ totalCcaChecks = 0;
+ }
+
+ if ( acquireSpiResource() == SUCCESS ) {
+ loadTXFIFO();
}
+ return SUCCESS;
}
- void attemptSend() {
+ /**
+ * 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) {
+ if((call CC2420Packet.getMetadata( m_msg ))->rxInterval > 0) {
+ signal RadioBackoff.requestLplBackoff(m_msg);
+ call BackoffTimer.start( myLplBackoff );
+
+ } else {
+ signal RadioBackoff.requestInitialBackoff(m_msg);
+ call BackoffTimer.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() {
uint8_t status;
bool congestion = TRUE;
+
+ continuousModulation = FALSE;
+
+#ifdef NOACK_LOW_POWER_LISTENING
+ // When the message is being sent with LPL, CCA implies this is the first
+ // message. Send it using the continuous modulation delivery
+ continuousModulation = m_cca
+ && (call CC2420Packet.getMetadata( m_msg ))->rxInterval > 0;
+#endif
- call CSN.clr();
+ atomic {
+ if (m_state == S_TX_CANCEL) {
+ call SFLUSHTX.strobe();
+ releaseSpiResource();
+ call CSN.set();
+ if (signalSendDone) {
+ signalDone(ECANCEL);
+ } else {
+ m_state = S_STARTED;
+ }
+ return;
+ }
+
+
+ call CSN.clr();
+
+ if(continuousModulation) {
+ /*
+ * We do a complex backoff like this because the last message of a
+ * continuous modulation delivery is currently reloaded into the
+ * SPI bus and sent off without CCA. This leaves a small quiet gap
+ * between the continuous modulation and its last message that other
+ * transmitters are guaranteed to hit.
+ *
+ * In the future, when the CRC is built into the continuous delivery
+ * message, this complex backoff may not be needed. Alternatively,
+ * directly accessing the TXFIFO RAM and adjusting the FCF to
+ * request an acknowledgement, and then resend without CCA will
+ * decrease the quiet gap.
+ */
+ if(totalCcaChecks < 20) {
+ if(call CCA.get()) {
+ // Extended backoff
+ totalCcaChecks++;
+ } else {
+ // Saw another transmitter, start over
+ totalCcaChecks = 0;
+ }
+
+ call CSN.set();
+ releaseSpiResource();
+ signal RadioBackoff.requestInitialBackoff(m_msg);
+ call BackoffTimer.start( myInitialBackoff );
+ return;
+ }
+
+ call MDMCTRL1.write(2 << CC2420_MDMCTRL1_TX_MODE);
+ } else {
+ call MDMCTRL1.write(0 << CC2420_MDMCTRL1_TX_MODE);
+ }
- status = m_cca ? call STXONCCA.strobe() : call STXON.strobe();
- if ( !( status & CC2420_STATUS_TX_ACTIVE ) ) {
- status = call SNOP.strobe();
- if ( status & CC2420_STATUS_TX_ACTIVE )
- congestion = FALSE;
+ status = m_cca ? call STXONCCA.strobe() : call STXON.strobe();
+ if ( !( status & CC2420_STATUS_TX_ACTIVE ) ) {
+ status = call SNOP.strobe();
+ if ( status & CC2420_STATUS_TX_ACTIVE ) {
+ congestion = FALSE;
+
+ if(continuousModulation) {
+ post startLplTimer();
+ }
+ }
+ }
+
+ m_state = congestion ? S_SAMPLE_CCA : S_SFD;
+ call CSN.set();
}
- atomic m_state = congestion ? S_SAMPLE_CCA : S_SFD;
- call CSN.set();
-
if ( congestion ) {
+ totalCcaChecks = 0;
releaseSpiResource();
congestionBackoff();
+ } else {
+ call BackoffTimer.start(CC2420_ABORT_PERIOD);
}
-#ifdef PLATFORM_MICAZ
- else {
- startBackoffTimer(CC2420_ABORT_PERIOD);
- }
-#endif
-
}
-
- async command error_t Send.modify( uint8_t offset, uint8_t* buf,
- uint8_t len ) {
- call CSN.clr();
- call TXFIFO_RAM.write( offset, buf, len );
- call CSN.set();
- return SUCCESS;
- }
-
- async event void CaptureSFD.captured( uint16_t time ) {
-
+
+
+ /**
+ * Congestion Backoff
+ */
+ void congestionBackoff() {
atomic {
- switch( m_state ) {
-
- case S_SFD:
- call CaptureSFD.captureFallingEdge();
- signal TimeStamp.transmittedSFD( time, m_msg );
- releaseSpiResource();
- stopBackoffTimer();
- m_state = S_EFD;
- if ( ( ( getHeader( m_msg )->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7 ) ==
- IEEE154_TYPE_DATA )
- getMetadata( m_msg )->time = time;
- if ( call SFD.get() )
- break;
-
- case S_EFD:
- call CaptureSFD.captureRisingEdge();
- if ( getHeader( m_msg )->fcf & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
- m_state = S_ACK_WAIT;
- startBackoffTimer( CC2420_ACK_WAIT_DELAY );
- }
- else {
- signalDone(SUCCESS);
- }
- if ( !call SFD.get() )
- break;
-
- default:
- if ( !m_receiving ) {
- call CaptureSFD.captureFallingEdge();
- signal TimeStamp.receivedSFD( time );
- call CC2420Receive.sfd( time );
- m_receiving = TRUE;
- m_prev_time = time;
- if ( call SFD.get() )
- return;
- }
- if ( m_receiving ) {
- call CaptureSFD.captureRisingEdge();
- m_receiving = FALSE;
- if ( time - m_prev_time < 10 )
- call CC2420Receive.sfd_dropped();
- }
- break;
-
+ if((call CC2420Packet.getMetadata(m_msg))->rxInterval > 0) {
+ signal RadioBackoff.requestLplBackoff(m_msg);
+ call BackoffTimer.start(myLplBackoff);
+
+ } else {
+ signal RadioBackoff.requestCongestionBackoff(m_msg);
+ call BackoffTimer.start(myCongestionBackoff);
}
}
}
-
- async event void CC2420Receive.receive( uint8_t type, message_t* ack_msg ) {
-
- if ( type == IEEE154_TYPE_ACK ) {
- cc2420_header_t* ack_header = getHeader( ack_msg );
- cc2420_header_t* msg_header = getHeader( m_msg );
- cc2420_metadata_t* msg_metadata = getMetadata( m_msg );
- uint8_t* ack_buf = (uint8_t*)ack_header;
- uint8_t length = ack_header->length;
-
- if ( m_state == S_ACK_WAIT &&
- msg_header->dsn == ack_header->dsn ) {
- stopBackoffTimer();
- msg_metadata->ack = TRUE;
- msg_metadata->rssi = ack_buf[ length - 1 ];
- msg_metadata->lqi = ack_buf[ length ] & 0x7f;
- signalDone(SUCCESS);
- }
+
+ error_t acquireSpiResource() {
+ error_t error = call SpiResource.immediateRequest();
+ if ( error != SUCCESS ) {
+ call SpiResource.request();
}
-
+ return error;
}
- event void SpiResource.granted() {
+ error_t releaseSpiResource() {
+ call SpiResource.release();
+ return SUCCESS;
+ }
- uint8_t cur_state;
- atomic {
- cur_state = m_state;
+ /**
+ * 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 CC2420Packet.getHeader( m_msg );
+ uint8_t tx_power = (call CC2420Packet.getMetadata( m_msg ))->tx_power;
+
+ if ( !tx_power ) {
+ // If our packet's tx_power wasn't configured to anything but 0,
+ // send it using the default RF power. This assumes the
+ // packet's metadata is all set to 0's on boot.
+
+ tx_power = CC2420_DEF_RFPOWER;
}
-
- switch( cur_state ) {
- case S_LOAD: loadTXFIFO(); break;
- case S_BEGIN_TRANSMIT: attemptSend(); break;
- default: releaseSpiResource(); break;
+
+ call CSN.clr();
+
+ if ( m_tx_power != tx_power ) {
+ call TXCTRL.write( ( 2 << CC2420_TXCTRL_TXMIXBUF_CUR ) |
+ ( 3 << CC2420_TXCTRL_PA_CURRENT ) |
+ ( 1 << CC2420_TXCTRL_RESERVED ) |
+ ( (tx_power & 0x1F) << CC2420_TXCTRL_PA_LEVEL ) );
}
-
+
+ m_tx_power = tx_power;
+
+ call TXFIFO.write( (uint8_t*)header, header->length - 1 );
+ }
+
+ void signalDone( error_t err ) {
+ atomic m_state = S_STARTED;
+ signal Send.sendDone( m_msg, err );
+ }
+
+
+
+ /***************** Tasks ****************/
+ task void startLplTimer() {
+ call LplDisableTimer.startOneShot((call CC2420Packet.getMetadata( m_msg ))->rxInterval + 10);
}
- async event void TXFIFO.readDone( uint8_t* tx_buf, uint8_t tx_len, error_t error ) {}
-
- default async event void TimeStamp.transmittedSFD( uint16_t time, message_t* p_msg ) {}
- default async event void TimeStamp.receivedSFD( uint16_t time ) {}
+ /***************** Defaults ****************/
+ default async event void TimeStamp.transmittedSFD( uint16_t time, message_t* p_msg ) {
+ }
+
+ default async event void TimeStamp.receivedSFD( uint16_t time ) {
+ }
}
+