/* This file has been prepared for Doxygen automatic documentation generation.*/ /*! \file ********************************************************************* * * \brief This files implements a wireless IEEE 802.15.4 serial communication * link between two nodes. * * \section wireless_uart_extended The Extended Wireless Uart Example * This particular example implements a more advanced wireless serial * communication link. This implementation follows the IEEE 802.15.4 standard * and uses some of the more advanced features in the AT86RF230 radio * transceiver. Data is sent as IEEE 802.15.4 data frames, and each frame is * acknowledged as specified in the standard by using the extended operating * modes of the radio transceiver (TX_ARET and RX_AACK). * * \par Application note: * AVR2001: Transceiver Access Toolbox for the AT86RF230 * * \par Documentation * For comprehensive code documentation, supported compilers, compiler * settings and supported devices see readme.html * * \author * Atmel Corporation: http://www.atmel.com \n * Support email: avr@atmel.com * * $Name$ * $Revision: 613 $ * $RCSfile$ * $Date: 2006-04-07 14:40:07 +0200 (fr, 07 apr 2006) $ \n * * Copyright (c) 2006, Atmel 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: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. 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. * * 3. The name of ATMEL may not be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY ATMEL ``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 EXPRESSLY AND * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. ******************************************************************************/ /*============================ INCLDUE =======================================*/ #include #include #include "config_uart_extended.h" // See this file for all project options. #include "compiler.h" #include "at86rf230_registermap.h" #include "hal.h" #include "tat.h" #define UART_EXTENDED #include "com.h" /*============================ MACROS ========================================*/ /*============================ TYPEDEFS ======================================*/ /*============================ VARIABLES =====================================*/ static uint8_t tx_frame[ 127 ]; //!< Buffer used to build TX frames. (Size must be max PSDU length.) static hal_rx_frame_t rx_pool[ RX_POOL_SIZE ]; //!< Pool of hal_rx_frame_t's. static hal_rx_frame_t *rx_pool_start; //!< Pointer to start of pool. static hal_rx_frame_t *rx_pool_end; //!< Pointer to end of pool. static hal_rx_frame_t *rx_pool_head; //!< Pointer to next hal_rx_frame_t it is possible to write. static hal_rx_frame_t *rx_pool_tail; //!< Pointer to next hal_rx_frame_t that can be read from the pool. static uint8_t rx_pool_items_free; //!< Number of free items (hal_rx_frame_t) in the pool. static uint8_t rx_pool_items_used; // !< Number of used items. static bool rx_pool_overflow_flag; //!< Flag that is used to signal a pool overflow. static bool rx_flag; //!< Flag used to mask between the two possible TRX_END events. static uint8_t debug_pll_transition[] = "State transition failed\r\n"; //!< Debug Text. static uint8_t debug_type_message[] = "\r<---Type Message:\r\n"; //!< Debug Text. static uint8_t debug_data_sent[] = "<---TX OK.\r\n"; //!< Debug Text. static uint8_t debug_data_received[] = "\r--->Rx:\r"; //!< Debug Text. static uint8_t debug_lqi[] = "LQI: "; //!< Debug Text. static uint8_t debug_rx_pool_overflow[] = "RX Buffer Overflow!\r\n"; //!< Debug Text. static uint8_t debug_transmission_failed[] = "TX Failed!\r\n"; //!< Debug Text. static uint8_t debug_transmission_length[] = "Typed Message too long!!\r\n"; //!< Debug Text. static uint8_t debug_fatal_error[] = "A fatal error. System must be reset.\r\n"; //!< Debug Text. /*============================ PROTOTYPES ====================================*/ static bool trx_init( void ); static void avr_init( void ); static void trx_end_handler( uint32_t time_stamp ); static void rx_pool_init( void ); /*! \brief This function is used to initialize the TRX. * * The TAT will be set up to run on the chosen operating channel, with CLKM diabled, * and then configure the RX_AACK and TX_ARET modes. * * \retval true if the TRX was successfully configured. * \retval false if the TRX was not configured properly. */ static bool trx_init( void ){ static bool status; if (tat_init( ) != TAT_SUCCESS) { status = false; } else if (tat_set_operating_channel( OPERATING_CHANNEL ) != TAT_SUCCESS) { status = false; } else if (tat_set_clock_speed( true, CLKM_DISABLED ) != TAT_SUCCESS) { status = false; } else{ /*Set up the extended modes:*/ //RX_AACK: tat_set_short_address( SHORT_ADDRESS ); //Short Address. tat_set_pan_id( PAN_ID ); //PAN ID. tat_set_device_role( false ); // No Coordintor support is necessary. //TX_ARET: tat_configure_csma( 234, 0xE2 ); // Default CSMA_SEED_0, MIN_BE = 3, MAX_CSMA_RETRIES = , and CSMA_SEED_1 = //Both Modes: tat_use_auto_tx_crc( true ); //Automatic CRC must be enabled. hal_set_trx_end_event_handler( trx_end_handler ); // Event handler for TRX_END events. status = true; } // end: if (tat_init( ) != TAT_SUCCESS) ... return status; } /*! \brief This function configure the necessary IO modules on the AVR. */ static void avr_init( void ){ com_init( BR_38400 ); } /*! \brief This function initialize the rx_pool. The rx_pool is in essence a FIFO. */ static void rx_pool_init( void ){ rx_pool_start = rx_pool; rx_pool_end = &rx_pool[ RX_POOL_SIZE - 1 ]; rx_pool_head = rx_pool_start; rx_pool_tail = rx_pool_end; rx_pool_items_free = RX_POOL_SIZE; rx_pool_items_used = 0; rx_pool_overflow_flag = false; } /*! \brief This function is the TRX_END event handler that is called from the * TRX isr if assigned. * * \param[in] time_stamp Interrupt timestamp in IEEE 802.15.4 symbols. */ static void trx_end_handler( uint32_t time_stamp ){ if (rx_flag == true) { //Check if these is space left in the rx_pool. if (rx_pool_items_free == 0) { rx_pool_overflow_flag = true; } else { //Space left, so upload the received frame. hal_frame_read( rx_pool_head ); //Then check the CRC. Will not store frames with invalid CRC. if (rx_pool_head->crc == true) { //Handle wrapping of rx_pool. if (rx_pool_head == rx_pool_end) { rx_pool_head = rx_pool_start; } else { ++rx_pool_head; } // end: if (rx_pool_head == rx_pool_end) ... --rx_pool_items_free; ++rx_pool_items_used; } // end: if (rx_pool_head->crc == true) ... } // end: if (rx_pool_items_free == 0) ... } // end: if (rx_flag == true) ... } int main( void ){ static uint8_t length_of_received_data = 0; static uint8_t frame_sequence_number = 0; rx_flag = true; /*Pre Build Header of IEEE 802.15.4 Data frame.*/ tx_frame[ 0 ] = 0x61; //FCF. tx_frame[ 1 ] = 0x88; //FCF. //Sequence number set during frame transmission. tx_frame[ 3 ] = PAN_ID & 0xFF; //Dest. PANID. tx_frame[ 4 ] = (PAN_ID >> 8 ) & 0xFF; //Dest. PANID. tx_frame[ 5 ] = DEST_ADDRESS & 0xFF; //Dest. Addr. tx_frame[ 6 ] = (DEST_ADDRESS >> 8 ) & 0xFF; //Dest. Addr. tx_frame[ 7 ] = SHORT_ADDRESS & 0xFF; //Source Addr. tx_frame[ 8 ] = (SHORT_ADDRESS >> 8 ) & 0xFF; //Source Addr. rx_pool_init( ); avr_init( ); trx_init( ); //Set system state to RX_AACK_ON if (tat_set_trx_state( RX_AACK_ON ) != TAT_SUCCESS) { com_send_string( debug_fatal_error, sizeof( debug_fatal_error ) ); } // end: if (tat_set_trx_state( RX_AACK_ON ) != TAT_SUCCESS) ... sei( ); //Give the user an indication that the system is ready. com_send_string( debug_type_message, sizeof( debug_type_message ) ); /*Enter Normal Program Flow: - Check for newly received frames. Print them if something is received. - Notify on rx_pool overflow. - Try to send data on air interface, if something is received on UART/USB. - Notify if the typed message was too long. */ while (true) { //Check if we have received something on the air interface. if (rx_pool_items_used != 0) { //Handle wrapping of rx_pool. if (rx_pool_tail == rx_pool_end) { rx_pool_tail = rx_pool_start; } else { ++rx_pool_tail; } // end: if (rx_pool_tail == rx_pool_end) ... //Turn interrupts off for a short while to protect when status //information about the rx_pool is updated. cli( ); ++rx_pool_items_free; --rx_pool_items_used; sei( ); //Send the frame to the user: com_send_string( debug_data_received, sizeof( debug_data_received ) ); com_send_string( &(rx_pool_tail->data[ 9 ]), ((rx_pool_tail->length) - 9 - 2 ) ); com_send_string( debug_lqi, sizeof( debug_lqi ) ); com_send_hex( rx_pool_tail->lqi ); com_send_string( debug_type_message, sizeof( debug_type_message ) ); } // end: if (rx_pool_items_used != 0) ... //Check for rx_pool overflow. if (rx_pool_overflow_flag == true) { cli(); rx_pool_init( ); com_send_string( debug_rx_pool_overflow, sizeof( debug_rx_pool_overflow ) ); sei(); } // end: if (rx_pool_overflow_flag == true) ... //Check for new data on the serial interface. //Check if data is ready to be sent. length_of_received_data = com_get_number_of_received_bytes( ); if (length_of_received_data == 1) { //length_of_received_data == 1 indicates a buffer overflow. Received data too long. com_send_string( debug_transmission_length, sizeof( debug_transmission_length ) ); com_reset_receiver( ); } else { if ((length_of_received_data >= 3) && (length_of_received_data <= COM_RX_BUFFER_SIZE)) { //Change state to TX_ARET_ON and send data if the state transition was successful. if (tat_set_trx_state( TX_ARET_ON ) == TAT_SUCCESS) { uint8_t *rx_frame = com_get_received_data( ); uint8_t tx_frame_length = 9; // Length of prebuilt frame header. tx_frame[ 2 ] = frame_sequence_number++; //Sequence Number. //Copy data into the TX frame buffer. do { tx_frame[ tx_frame_length++ ] = *rx_frame++; } while (--length_of_received_data > 0); rx_flag = false; // Set the flag false, so that the TRX_END event is not misinterpreted. if (tat_send_data_with_retry( tx_frame_length, tx_frame, 1 ) == TAT_SUCCESS) { com_send_string( debug_data_sent, sizeof( debug_data_sent ) ); } else { com_send_string( debug_transmission_failed, sizeof( debug_transmission_failed ) ); } // end: if (tat_send_data_with_retry( tx_frame_length, tx_frame, 1 ) ... } else { com_send_string( debug_pll_transition, sizeof( debug_pll_transition ) ); } // end: if (tat_set_trx_state( TX_ARET_ON ) == TAT_SUCCESS) ... if (tat_set_trx_state( RX_AACK_ON ) != TAT_SUCCESS) { com_send_string( debug_fatal_error, sizeof( debug_fatal_error ) ); } // end: if (tat_set_trx_state( RX_AACK_ON ) != TAT_SUCCESS) ... rx_flag = true; // Set the flag back again. Only used to protec the frame transmission. com_reset_receiver( ); com_send_string( debug_type_message, sizeof( debug_type_message ) ); } // end: } // end: if (length_of_received_data == 1) ... } // emd: while (true) ... } /*EOF*/