+++ /dev/null
-/*\r
- * Copyright (c) 2005-2006 Arch Rock Corporation\r
- * All rights reserved.\r
- *\r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions\r
- * are met:\r
- * - Redistributions of source code must retain the above copyright\r
- * notice, this list of conditions and the following disclaimer.\r
- * - Redistributions in binary form must reproduce the above copyright\r
- * notice, this list of conditions and the following disclaimer in the\r
- * documentation and/or other materials provided with the\r
- * distribution.\r
- * - Neither the name of the Arch Rock Corporation nor the names of\r
- * its contributors may be used to endorse or promote products derived\r
- * from this software without specific prior written permission.\r
- *\r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
- * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\r
- * OF THE POSSIBILITY OF SUCH DAMAGE\r
- */\r
-\r
-/**\r
- * @author Jonathan Hui <jhui@archrock.com>\r
- * @version $Revision$ $Date$\r
- */\r
- \r
-#include "IEEE802154.h"\r
-\r
-module CC2420TransmitP {\r
-\r
- provides interface Init;\r
- provides interface AsyncStdControl;\r
- provides interface CC2420Transmit as Send;\r
- provides interface CsmaBackoff;\r
- provides interface RadioTimeStamping as TimeStamp;\r
- provides interface CC2420Cca;\r
- \r
- uses interface Alarm<T32khz,uint32_t> as BackoffTimer;\r
-\r
-#ifdef PLATFORM_MICAZ\r
- uses interface Timer<TMilli> as WatchdogTimer;\r
-#endif\r
-\r
- uses interface GpioCapture as CaptureSFD;\r
- uses interface GeneralIO as CCA;\r
- uses interface GeneralIO as CSN;\r
- uses interface GeneralIO as SFD;\r
-\r
- uses interface Resource as SpiResource;\r
- uses interface CC2420Fifo as TXFIFO;\r
- uses interface CC2420Ram as TXFIFO_RAM;\r
- uses interface CC2420Register as TXCTRL;\r
- uses interface CC2420Strobe as SNOP;\r
- uses interface CC2420Strobe as STXON;\r
- uses interface CC2420Strobe as STXONCCA;\r
- uses interface CC2420Strobe as SFLUSHTX;\r
-\r
- uses interface CC2420Receive;\r
- uses interface Leds;\r
-\r
-}\r
-\r
-implementation {\r
-\r
- typedef enum {\r
- S_STOPPED,\r
- S_STARTED,\r
- S_LOAD,\r
- S_SAMPLE_CCA,\r
- S_SAMPLE_CCA_ONLY,\r
- S_BEGIN_TRANSMIT,\r
- S_SFD,\r
- S_EFD,\r
- S_ACK_WAIT,\r
- S_CANCEL,\r
- } cc2420_transmit_state_t;\r
-\r
- // This specifies how many jiffies the stack should wait after a\r
- // TXACTIVE to receive an SFD interrupt before assuming something is\r
- // wrong and aborting the send. There seems to be a condition\r
- // on the micaZ where the SFD interrupt is never handled.\r
- enum {\r
- CC2420_ABORT_PERIOD = 320\r
- };\r
- \r
- norace message_t* m_msg;\r
- \r
- norace bool m_cca;\r
- \r
- norace uint8_t m_tx_power;\r
- \r
- cc2420_transmit_state_t m_state = S_STOPPED;\r
- \r
- bool m_receiving = FALSE;\r
- \r
- uint16_t m_prev_time;\r
-\r
-\r
- /***************** Prototypes ****************/\r
- void loadTXFIFO();\r
- void attemptSend();\r
- cc2420_header_t* getHeader( message_t* msg );\r
- cc2420_metadata_t* getMetadata( message_t* msg );\r
- void startBackoffTimer(uint16_t time);\r
- void stopBackoffTimer();\r
- error_t acquireSpiResource();\r
- void releaseSpiResource();\r
- void signalDone(error_t err);\r
- void congestionBackoff();\r
- error_t send( message_t* p_msg, bool cca );\r
- error_t resend( bool cca );\r
- \r
-#ifdef PLATFORM_MICAZ\r
- task void startWatchdogTimer();\r
- task void stopWatchdogTimer();\r
-#endif\r
-\r
-\r
- /***************** Init Commands ****************/\r
- command error_t Init.init() {\r
- call CCA.makeInput();\r
- call CSN.makeOutput();\r
- call SFD.makeInput();\r
- return SUCCESS;\r
- }\r
-\r
- /***************** AsyncStdControl Commands ****************/\r
- async command error_t AsyncStdControl.start() {\r
- atomic {\r
- call CaptureSFD.captureRisingEdge();\r
- m_state = S_STARTED;\r
- m_receiving = FALSE;\r
- m_tx_power = 0;\r
- }\r
- return SUCCESS;\r
- }\r
-\r
- async command error_t AsyncStdControl.stop() {\r
- atomic {\r
- m_state = S_STOPPED;\r
- stopBackoffTimer();\r
- call CaptureSFD.disable();\r
- }\r
- return SUCCESS;\r
- }\r
-\r
- /***************** Send Commands ****************/\r
- async command error_t Send.sendCCA( message_t* p_msg ) {\r
- return send( p_msg, TRUE );\r
- }\r
-\r
- async command error_t Send.send( message_t* p_msg ) {\r
- return send( p_msg, FALSE );\r
- }\r
-\r
- async command error_t Send.resendCCA() {\r
- return resend( TRUE );\r
- }\r
-\r
- async command error_t Send.resend() {\r
- return resend( FALSE );\r
- }\r
-\r
- async command error_t Send.cancel() {\r
- stopBackoffTimer();\r
-\r
- atomic {\r
- switch( m_state ) {\r
- case S_LOAD:\r
- m_state = S_CANCEL;\r
- break;\r
- \r
- case S_SAMPLE_CCA: \r
- case S_BEGIN_TRANSMIT:\r
- m_state = S_STARTED;\r
- break;\r
- \r
- default:\r
- // cancel not allowed while radio is busy transmitting\r
- return FAIL;\r
- }\r
- }\r
-\r
- return SUCCESS;\r
- }\r
-\r
- async command error_t Send.modify( uint8_t offset, uint8_t* buf, \r
- uint8_t len ) {\r
- call CSN.clr();\r
- call TXFIFO_RAM.write( offset, buf, len );\r
- call CSN.set();\r
- return SUCCESS;\r
- }\r
-\r
- /***************** CC2420Cca Commands ****************/\r
- /**\r
- * @return TRUE if the CCA pin shows a clear channel\r
- */\r
- command bool CC2420Cca.isChannelClear() {\r
- return call CCA.get();\r
- }\r
- \r
- /***************** CaptureSFD Events ****************/\r
- async event void CaptureSFD.captured( uint16_t time ) {\r
-\r
- atomic {\r
- switch( m_state ) {\r
- \r
- case S_SFD:\r
- call CaptureSFD.captureFallingEdge();\r
- signal TimeStamp.transmittedSFD( time, m_msg );\r
- releaseSpiResource();\r
- stopBackoffTimer();\r
- m_state = S_EFD;\r
- if ( ( ( getHeader( m_msg )->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7 ) == \r
- IEEE154_TYPE_DATA )\r
- getMetadata( m_msg )->time = time;\r
- if ( call SFD.get() )\r
- break;\r
- \r
- case S_EFD:\r
- call CaptureSFD.captureRisingEdge();\r
- if ( getHeader( m_msg )->fcf & ( 1 << IEEE154_FCF_ACK_REQ ) ) {\r
- m_state = S_ACK_WAIT;\r
- startBackoffTimer( CC2420_ACK_WAIT_DELAY );\r
- }\r
- else {\r
- signalDone(SUCCESS);\r
- }\r
- if ( !call SFD.get() )\r
- break;\r
- \r
- default:\r
- if ( !m_receiving ) {\r
- call CaptureSFD.captureFallingEdge();\r
- signal TimeStamp.receivedSFD( time );\r
- call CC2420Receive.sfd( time );\r
- m_receiving = TRUE;\r
- m_prev_time = time;\r
- if ( call SFD.get() )\r
- return;\r
- }\r
- if ( m_receiving ) {\r
- call CaptureSFD.captureRisingEdge();\r
- m_receiving = FALSE;\r
- if ( time - m_prev_time < 10 )\r
- call CC2420Receive.sfd_dropped();\r
- }\r
- break;\r
- \r
- }\r
- }\r
- }\r
-\r
- /***************** CC2420Receive Events ****************/\r
- async event void CC2420Receive.receive( uint8_t type, message_t* ack_msg ) {\r
-\r
- if ( type == IEEE154_TYPE_ACK ) {\r
- cc2420_header_t* ack_header = getHeader( ack_msg );\r
- cc2420_header_t* msg_header = getHeader( m_msg );\r
- cc2420_metadata_t* msg_metadata = getMetadata( m_msg );\r
- uint8_t* ack_buf = (uint8_t*)ack_header;\r
- uint8_t length = ack_header->length;\r
- \r
- if ( m_state == S_ACK_WAIT &&\r
- msg_header->dsn == ack_header->dsn ) {\r
- stopBackoffTimer();\r
- msg_metadata->ack = TRUE;\r
- msg_metadata->rssi = ack_buf[ length - 1 ];\r
- msg_metadata->lqi = ack_buf[ length ] & 0x7f;\r
- signalDone(SUCCESS);\r
- }\r
- }\r
- }\r
-\r
- /***************** SpiResource Events ****************/\r
- event void SpiResource.granted() {\r
- uint8_t cur_state;\r
-\r
- atomic {\r
- cur_state = m_state;\r
- }\r
-\r
- switch( cur_state ) {\r
- case S_LOAD: \r
- loadTXFIFO(); \r
- break;\r
- \r
- case S_BEGIN_TRANSMIT: \r
- attemptSend(); \r
- break;\r
- \r
- default: \r
- releaseSpiResource(); \r
- break;\r
- }\r
- }\r
-\r
- /***************** TXFIFO Events ****************/\r
- async event void TXFIFO.readDone( uint8_t* tx_buf, uint8_t tx_len, \r
- error_t error ) {\r
- }\r
-\r
-\r
- async event void TXFIFO.writeDone( uint8_t* tx_buf, uint8_t tx_len,\r
- error_t error ) {\r
- call CSN.set();\r
-\r
- if ( m_state == S_CANCEL ) {\r
- m_state = S_STARTED;\r
- }\r
- else if ( !m_cca ) {\r
- m_state = S_BEGIN_TRANSMIT;\r
- attemptSend();\r
- }\r
- else {\r
- releaseSpiResource();\r
- m_state = S_SAMPLE_CCA;\r
- startBackoffTimer( signal CsmaBackoff.initial( m_msg ) + 1);\r
- }\r
- }\r
- \r
- /***************** Timer Events ****************/\r
- async event void BackoffTimer.fired() {\r
-\r
- atomic {\r
- switch( m_state ) { \r
- case S_SAMPLE_CCA :\r
- // sample CCA and wait a little longer if free, just in case we\r
- // sampled during the ack turn-around window\r
- if ( call CCA.get() ) {\r
- m_state = S_BEGIN_TRANSMIT;\r
- startBackoffTimer( CC2420_TIME_ACK_TURNAROUND );\r
- }\r
- else {\r
- congestionBackoff();\r
- }\r
- break;\r
- \r
- case S_BEGIN_TRANSMIT :\r
- if ( acquireSpiResource() == SUCCESS )\r
- attemptSend();\r
- break;\r
- \r
- case S_ACK_WAIT :\r
- signalDone( SUCCESS );\r
- break;\r
- \r
-#ifdef PLATFORM_MICAZ\r
- case S_SFD:\r
- // We didn't receive an SFD interrupt within CC2420_ABORT_PERIOD\r
- // jiffies. Assume something is wrong.\r
- call SFLUSHTX.strobe();\r
- call CaptureSFD.disable();\r
- call CaptureSFD.captureRisingEdge();\r
- signalDone( ERETRY );\r
- break;\r
-#endif\r
- default:\r
- break;\r
- }\r
- }\r
- }\r
- \r
- \r
-#ifdef PLATFORM_MICAZ\r
- event void WatchdogTimer.fired() {\r
- atomic m_state = S_STARTED;\r
- releaseSpiResource();\r
- signalDone(ERETRY);\r
- }\r
-#endif\r
- \r
- \r
- /***************** Functions ****************/\r
- /**\r
- * Send a message with or without CCA\r
- */\r
- error_t send( message_t* p_msg, bool cca ) {\r
- atomic {\r
- if ( m_state != S_STARTED ) {\r
- return FAIL;\r
- }\r
- \r
- m_state = S_LOAD;\r
- m_cca = cca;\r
- m_msg = p_msg;\r
- }\r
-\r
-#ifdef PLATFORM_MICAZ\r
- post startWatchdogTimer();\r
-#endif\r
-\r
- if ( acquireSpiResource() == SUCCESS ) {\r
- loadTXFIFO();\r
- }\r
- // Else, we wait for the SpiResource.granted event..\r
- \r
- return SUCCESS;\r
- }\r
- \r
- /**\r
- * Resend a message with or without CCA\r
- */\r
- error_t resend( bool cca ) {\r
- atomic {\r
- if ( m_state != S_STARTED )\r
- return FAIL;\r
- m_cca = cca;\r
- m_state = cca ? S_SAMPLE_CCA : S_BEGIN_TRANSMIT;\r
- }\r
-\r
-#ifdef PLATFORM_MICAZ\r
- post startWatchdogTimer();\r
-#endif\r
-\r
- if ( m_cca ) {\r
- startBackoffTimer( signal CsmaBackoff.initial( m_msg ) );\r
- }\r
- else if ( acquireSpiResource() == SUCCESS ) {\r
- attemptSend();\r
- }\r
- \r
- return SUCCESS;\r
- }\r
- \r
- /**\r
- * Attempt to send a message\r
- */\r
- void attemptSend() {\r
- uint8_t status;\r
- bool congestion = TRUE;\r
-\r
- call CSN.clr();\r
-\r
- status = m_cca ? call STXONCCA.strobe() : call STXON.strobe();\r
- if ( !( status & CC2420_STATUS_TX_ACTIVE ) ) {\r
- status = call SNOP.strobe();\r
- if ( status & CC2420_STATUS_TX_ACTIVE )\r
- congestion = FALSE;\r
- }\r
- atomic m_state = congestion ? S_SAMPLE_CCA : S_SFD;\r
- \r
- call CSN.set();\r
-\r
- if ( congestion ) {\r
- releaseSpiResource();\r
- congestionBackoff();\r
- }\r
-#ifdef PLATFORM_MICAZ\r
- else {\r
- startBackoffTimer(CC2420_ABORT_PERIOD);\r
- }\r
-#endif\r
- }\r
- \r
- \r
- /**\r
- * Get the CC2420 message header\r
- */\r
- cc2420_header_t* getHeader( message_t* msg ) {\r
- return (cc2420_header_t*)( msg->data - sizeof( cc2420_header_t ) );\r
- }\r
-\r
- /**\r
- * Get the CC2420 message metadata\r
- */\r
- cc2420_metadata_t* getMetadata( message_t* msg ) {\r
- return (cc2420_metadata_t*)msg->metadata;\r
- }\r
- \r
-#ifdef PLATFORM_MICAZ\r
- /**\r
- * Start the watchdog timer\r
- */\r
- task void startWatchdogTimer() {\r
- call WatchdogTimer.startOneShot(50);\r
- }\r
- \r
- /**\r
- * Stop the watchdog timer\r
- */\r
- task void stopWatchdogTimer() {\r
- call WatchdogTimer.stop();\r
- }\r
-#endif\r
- \r
- /**\r
- * Start the backoff timer\r
- */\r
- void startBackoffTimer(uint16_t time) {\r
- call BackoffTimer.start(time);\r
- }\r
-\r
- /** \r
- * Stop the backoff timer\r
- */\r
- void stopBackoffTimer() {\r
- call BackoffTimer.stop();\r
- }\r
-\r
- /**\r
- * Acquire the SPI bus resource immediately, or defer it till later\r
- */\r
- error_t acquireSpiResource() {\r
- error_t error = call SpiResource.immediateRequest();\r
- if ( error != SUCCESS ) {\r
- call SpiResource.request();\r
- }\r
- return error;\r
- }\r
-\r
- /**\r
- * Release the SPI resource\r
- */\r
- void releaseSpiResource() {\r
- call SpiResource.release();\r
- }\r
-\r
- /**\r
- * Signal done\r
- */\r
- void signalDone( error_t err ) {\r
- atomic m_state = S_STARTED;\r
-\r
-#ifdef PLATFORM_MICAZ\r
- post stopWatchdogTimer();\r
-#endif\r
-\r
- signal Send.sendDone( m_msg, err );\r
- }\r
-\r
- /** \r
- * Congestion Backoff\r
- */\r
- void congestionBackoff() {\r
- atomic {\r
- startBackoffTimer(signal CsmaBackoff.congestion( m_msg ) + 1);\r
- }\r
- }\r
- \r
- /**\r
- * Load TX FIFO\r
- */\r
- void loadTXFIFO() {\r
- cc2420_header_t* header = getHeader( m_msg );\r
- uint8_t tx_power = getMetadata( m_msg )->tx_power;\r
- \r
- if ( !tx_power )\r
- tx_power = CC2420_DEF_RFPOWER;\r
- call CSN.clr();\r
- if ( m_tx_power != tx_power )\r
- call TXCTRL.write( ( 2 << CC2420_TXCTRL_TXMIXBUF_CUR ) |\r
- ( 3 << CC2420_TXCTRL_PA_CURRENT ) |\r
- ( 1 << CC2420_TXCTRL_RESERVED ) |\r
- ( tx_power << CC2420_TXCTRL_PA_LEVEL ) );\r
- m_tx_power = tx_power;\r
- call TXFIFO.write( (uint8_t*)header, header->length - 1 );\r
- }\r
- \r
- /***************** Defaults ****************/\r
- default async event void TimeStamp.transmittedSFD( uint16_t time, message_t* p_msg ) {}\r
- default async event void TimeStamp.receivedSFD( uint16_t time ) {}\r
-\r
-}\r