wifi test
Dependencies: X_NUCLEO_IKS01A2 mbed-http
easy-connect/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp
- Committer:
- JMF
- Date:
- 2018-09-05
- Revision:
- 0:24d3eb812fd4
File content as of revision 0:24d3eb812fd4:
/* * Copyright (c) 2014-2015 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <string.h> #ifdef MBED_CONF_NANOSTACK_CONFIGURATION #include "platform/arm_hal_interrupt.h" #include "nanostack/platform/arm_hal_phy.h" #include "ns_types.h" #include "NanostackRfPhyAtmel.h" #include "randLIB.h" #include "AT86RFReg.h" #include "nanostack/platform/arm_hal_phy.h" #include "mbed_trace.h" #include "mbed_toolchain.h" #define TRACE_GROUP "AtRF" /*Worst case sensitivity*/ #define RF_DEFAULT_SENSITIVITY -88 /*Run calibration every 5 minutes*/ #define RF_CALIBRATION_INTERVAL 6000000 /*Wait ACK for 2.5ms*/ #define RF_ACK_WAIT_DEFAULT_TIMEOUT 50 /*Base CCA backoff (50us units) - substitutes for Inter-Frame Spacing*/ #define RF_CCA_BASE_BACKOFF 13 /* 650us */ /*CCA random backoff (50us units)*/ #define RF_CCA_RANDOM_BACKOFF 51 /* 2550us */ #define RF_MTU 127 #define RF_PHY_MODE OQPSK_SIN_250 /*Radio RX and TX state definitions*/ #define RFF_ON 0x01 #define RFF_RX 0x02 #define RFF_TX 0x04 #define RFF_CCA 0x08 typedef enum { RF_MODE_NORMAL = 0, RF_MODE_SNIFFER = 1, RF_MODE_ED = 2 }rf_mode_t; /*Atmel RF Part Type*/ typedef enum { ATMEL_UNKNOW_DEV = 0, ATMEL_AT86RF212, ATMEL_AT86RF231, // No longer supported (doesn't give ED+status on frame read) ATMEL_AT86RF233 }rf_trx_part_e; /*Atmel RF states*/ typedef enum { NOP = 0x00, BUSY_RX = 0x01, BUSY_TX = 0x02, RF_TX_START = 0x02, FORCE_TRX_OFF = 0x03, FORCE_PLL_ON = 0x04, RX_ON = 0x06, TRX_OFF = 0x08, PLL_ON = 0x09, BUSY_RX_AACK = 0x11, SLEEP = 0x0F, RX_AACK_ON = 0x16, TX_ARET_ON = 0x19, STATE_TRANSITION_IN_PROGRESS = 0x1F }rf_trx_states_t; static const uint8_t *rf_tx_data; // Points to Nanostack's buffer static uint8_t rf_tx_length; /*ACK wait duration changes depending on data rate*/ static uint16_t rf_ack_wait_duration = RF_ACK_WAIT_DEFAULT_TIMEOUT; static int8_t rf_sensitivity = RF_DEFAULT_SENSITIVITY; static rf_mode_t rf_mode = RF_MODE_NORMAL; static uint8_t radio_tx_power = 0x00; // Default to +4dBm static uint8_t rf_phy_channel = 12; static uint8_t rf_tuned = 1; static uint8_t rf_use_antenna_diversity = 0; static int16_t expected_ack_sequence = -1; static uint8_t rf_rx_mode = 0; static uint8_t rf_flags = 0; static int8_t rf_radio_driver_id = -1; static phy_device_driver_s device_driver; static uint8_t mac_tx_handle = 0; static uint8_t xah_ctrl_1; /* Channel configurations for 2.4 and sub-GHz */ static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK}; static const phy_rf_channel_configuration_s phy_subghz = {868300000U, 2000000U, 250000U, 11U, M_OQPSK}; static const phy_device_channel_page_s phy_channel_pages[] = { { CHANNEL_PAGE_0, &phy_24ghz}, { CHANNEL_PAGE_2, &phy_subghz}, { CHANNEL_PAGE_0, NULL} }; /** * RF output power write * * \brief TX power has to be set before network start. * * \param power * AT86RF233 * 0 = 4 dBm * 1 = 3.7 dBm * 2 = 3.4 dBm * 3 = 3 dBm * 4 = 2.5 dBm * 5 = 2 dBm * 6 = 1 dBm * 7 = 0 dBm * 8 = -1 dBm * 9 = -2 dBm * 10 = -3 dBm * 11 = -4 dBm * 12 = -6 dBm * 13 = -8 dBm * 14 = -12 dBm * 15 = -17 dBm * * AT86RF212B * See datasheet for TX power settings * * \return 0, Supported Value * \return -1, Not Supported Value */ static rf_trx_part_e rf_radio_type_read(void); static void rf_ack_wait_timer_start(uint16_t slots); static void rf_handle_cca_ed_done(uint8_t full_trx_status); static void rf_handle_tx_end(rf_trx_states_t trx_status); static void rf_handle_rx_end(rf_trx_states_t trx_status); static void rf_on(void); static void rf_give_up_on_ack(void); static void rf_receive(rf_trx_states_t trx_status = STATE_TRANSITION_IN_PROGRESS); static rf_trx_states_t rf_poll_trx_state_change(rf_trx_states_t trx_state); static void rf_init(void); static int8_t rf_device_register(const uint8_t *mac_addr); static void rf_device_unregister(void); static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ); static void rf_cca_abort(void); static void rf_calibration_cb(void); static void rf_init_phy_mode(void); static void rf_ack_wait_timer_interrupt(void); static void rf_calibration_timer_interrupt(void); static void rf_calibration_timer_start(uint32_t slots); static void rf_cca_timer_interrupt(void); static void rf_cca_timer_start(uint32_t slots); static uint8_t rf_scale_lqi(int8_t rssi); static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel); static int8_t rf_extension(phy_extension_type_e extension_type,uint8_t *data_ptr); static int8_t rf_address_write(phy_address_type_e address_type,uint8_t *address_ptr); static void rf_if_cca_timer_start(uint32_t slots); static void rf_if_enable_promiscuous_mode(void); static void rf_if_lock(void); static void rf_if_unlock(void); static uint8_t rf_if_read_rnd(void); static void rf_if_calibration_timer_start(uint32_t slots); static void rf_if_interrupt_handler(void); static void rf_if_ack_wait_timer_start(uint16_t slots); static void rf_if_ack_wait_timer_stop(void); static void rf_if_ack_pending_ctrl(uint8_t state); static void rf_if_calibration(void); static uint8_t rf_if_read_register(uint8_t addr); static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask); static void rf_if_clear_bit(uint8_t addr, uint8_t bit); static void rf_if_write_register(uint8_t addr, uint8_t data); static void rf_if_reset_radio(void); static void rf_if_enable_ant_div(void); static void rf_if_disable_ant_div(void); static void rf_if_enable_slptr(void); static void rf_if_disable_slptr(void); static void rf_if_write_antenna_diversity_settings(void); static void rf_if_write_set_tx_power_register(uint8_t value); static void rf_if_write_rf_settings(void); static rf_trx_states_t rf_if_read_trx_state(void); static uint16_t rf_if_read_packet(uint8_t data[RF_MTU], uint8_t *lqi_out, uint8_t *ed_out, bool *crc_good); static void rf_if_write_short_addr_registers(uint8_t *short_address); static uint8_t rf_if_last_acked_pending(void); static void rf_if_write_pan_id_registers(uint8_t *pan_id); static void rf_if_write_ieee_addr_registers(uint8_t *address); static void rf_if_write_frame_buffer(const uint8_t *ptr, uint8_t length); static rf_trx_states_t rf_if_change_trx_state(rf_trx_states_t trx_state); static void rf_if_start_cca_process(void); static int8_t rf_if_scale_rssi(uint8_t ed_level); static void rf_if_set_channel_register(uint8_t channel); static void rf_if_enable_promiscuous_mode(void); static void rf_if_disable_promiscuous_mode(void); static uint8_t rf_if_read_part_num(void); static void rf_if_enable_irq(void); static void rf_if_disable_irq(void); static void rf_if_spi_exchange_n(const void *tx, size_t tx_len, void *rx, size_t rx_len); static inline rf_trx_states_t rf_if_trx_status_from_full(uint8_t full_trx_status) { return (rf_trx_states_t) (full_trx_status & 0x1F); } #ifdef MBED_CONF_RTOS_PRESENT #include "mbed.h" #include "rtos.h" static void rf_if_irq_task_process_irq(); #define SIG_RADIO 1 #define SIG_TIMER_ACK 2 #define SIG_TIMER_CAL 4 #define SIG_TIMER_CCA 8 #define SIG_TIMERS (SIG_TIMER_ACK|SIG_TIMER_CAL|SIG_TIMER_CCA) #define SIG_ALL (SIG_RADIO|SIG_TIMERS) #endif // HW pins to RF chip class UnlockedSPI : public SPI { public: UnlockedSPI(PinName mosi, PinName miso, PinName sclk) : SPI(mosi, miso, sclk) { } virtual void lock() { } virtual void unlock() { } }; class RFBits { public: RFBits(PinName spi_mosi, PinName spi_miso, PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq); UnlockedSPI spi; DigitalOut CS; DigitalOut RST; DigitalOut SLP_TR; InterruptIn IRQ; Timeout ack_timer; Timeout cal_timer; Timeout cca_timer; #ifdef MBED_CONF_RTOS_PRESENT Thread irq_thread; Mutex mutex; void rf_if_irq_task(); #endif }; RFBits::RFBits(PinName spi_mosi, PinName spi_miso, PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq) : spi(spi_mosi, spi_miso, spi_sclk), CS(spi_cs), RST(spi_rst), SLP_TR(spi_slp), IRQ(spi_irq) #ifdef MBED_CONF_RTOS_PRESENT ,irq_thread(osPriorityRealtime, 1024) #endif { #ifdef MBED_CONF_RTOS_PRESENT irq_thread.start(mbed::callback(this, &RFBits::rf_if_irq_task)); #endif } static RFBits *rf; static uint8_t rf_part_num = 0; /*TODO: RSSI Base value setting*/ static int8_t rf_rssi_base_val = -91; static void rf_if_lock(void) { platform_enter_critical(); } static void rf_if_unlock(void) { platform_exit_critical(); } #ifdef MBED_CONF_RTOS_PRESENT static void rf_if_cca_timer_signal(void) { rf->irq_thread.signal_set(SIG_TIMER_CCA); } static void rf_if_cal_timer_signal(void) { rf->irq_thread.signal_set(SIG_TIMER_CAL); } static void rf_if_ack_timer_signal(void) { rf->irq_thread.signal_set(SIG_TIMER_ACK); } #endif /* Delay functions for RF Chip SPI access */ #ifdef __CC_ARM __asm static void delay_loop(uint32_t count) { 1 SUBS a1, a1, #1 BCS %BT1 BX lr } #elif defined (__ICCARM__) static void delay_loop(uint32_t count) { __asm volatile( "loop: \n" " SUBS %0, %0, #1 \n" " BCS.n loop\n" : "+r" (count) : : "cc" ); } #else // GCC static void delay_loop(uint32_t count) { __asm__ volatile ( "%=:\n\t" #if defined(__thumb__) && !defined(__thumb2__) "SUB %0, #1\n\t" #else "SUBS %0, %0, #1\n\t" #endif "BCS %=b\n\t" : "+l" (count) : : "cc" ); } #endif static void delay_ns(uint32_t ns) { uint32_t cycles_per_us = SystemCoreClock / 1000000; // Cortex-M0 takes 4 cycles per loop (SUB=1, BCS=3) // Cortex-M3 and M4 takes 3 cycles per loop (SUB=1, BCS=2) // Cortex-M7 - who knows? // Cortex M3-M7 have "CYCCNT" - would be better than a software loop, but M0 doesn't // Assume 3 cycles per loop for now - will be 33% slow on M0. No biggie, // as original version of code was 300% slow on M4. // [Note that this very calculation, plus call overhead, will take multiple // cycles. Could well be 100ns on its own... So round down here, startup is // worth at least one loop iteration.] uint32_t count = (cycles_per_us * ns) / 3000; delay_loop(count); } // t1 = 180ns, SEL falling edge to MISO active [SPI setup assumed slow enough to not need manual delay] #define CS_SELECT() {rf->CS = 0; /* delay_ns(180); */} // t9 = 250ns, last clock to SEL rising edge, t8 = 250ns, SPI idle time between consecutive access #define CS_RELEASE() {delay_ns(250); rf->CS = 1; delay_ns(250);} /* * \brief Read connected radio part. * * This function only return valid information when rf_init() is called * * \return */ static rf_trx_part_e rf_radio_type_read(void) { rf_trx_part_e ret_val = ATMEL_UNKNOW_DEV; switch (rf_part_num) { case PART_AT86RF212: ret_val = ATMEL_AT86RF212; break; case PART_AT86RF233: ret_val = ATMEL_AT86RF233; break; default: break; } return ret_val; } /* * \brief Function starts the ACK wait timeout. * * \param slots Given slots, resolution 50us * * \return none */ static void rf_if_ack_wait_timer_start(uint16_t slots) { #ifdef MBED_CONF_RTOS_PRESENT rf->ack_timer.attach_us(rf_if_ack_timer_signal, slots*50); #else rf->ack_timer.attach_us(rf_ack_wait_timer_interrupt, slots*50); #endif } /* * \brief Function starts the calibration interval. * * \param slots Given slots, resolution 50us * * \return none */ static void rf_if_calibration_timer_start(uint32_t slots) { #ifdef MBED_CONF_RTOS_PRESENT rf->cal_timer.attach_us(rf_if_cal_timer_signal, slots*50); #else rf->cal_timer.attach_us(rf_calibration_timer_interrupt, slots*50); #endif } /* * \brief Function starts the CCA interval. * * \param slots Given slots, resolution 50us * * \return none */ static void rf_if_cca_timer_start(uint32_t slots) { #ifdef MBED_CONF_RTOS_PRESENT rf->cca_timer.attach_us(rf_if_cca_timer_signal, slots*50); #else rf->cca_timer.attach_us(rf_cca_timer_interrupt, slots*50); #endif } /* * \brief Function stops the CCA interval. * * \return none */ static void rf_if_cca_timer_stop(void) { rf->cca_timer.detach(); } /* * \brief Function stops the ACK wait timeout. * * \param none * * \return none */ static void rf_if_ack_wait_timer_stop(void) { rf->ack_timer.detach(); } /* * \brief Function sets bit(s) in given RF register. * * \param addr Address of the register to set * \param bit Bit(s) to set * \param bit_mask Masks the field inside the register * * \return none */ static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask) { uint8_t reg = rf_if_read_register(addr); reg &= ~bit_mask; reg |= bit; rf_if_write_register(addr, reg); } /* * \brief Function clears bit(s) in given RF register. * * \param addr Address of the register to clear * \param bit Bit(s) to clear * * \return none */ static void rf_if_clear_bit(uint8_t addr, uint8_t bit) { rf_if_set_bit(addr, 0, bit); } /* * \brief Function writes register in RF. * * \param addr Address on the RF * \param data Written data * * \return none */ static void rf_if_write_register(uint8_t addr, uint8_t data) { const uint8_t tx[2] = { static_cast<uint8_t>(0xC0 | addr), data }; uint8_t rx[2]; CS_SELECT(); rf_if_spi_exchange_n(tx, 2, rx, 2); CS_RELEASE(); } /* * \brief Function reads RF register, and also outputs PHY_STATUS * * \param addr Address on the RF * \param[out] status_out Pointer to store PHY_STATUS * * \return Read register data */ static uint8_t rf_if_read_register_with_status(uint8_t addr, uint8_t *status_out) { const uint8_t tx[1] = { static_cast<uint8_t>(0x80 | addr) }; uint8_t rx[2]; CS_SELECT(); rf_if_spi_exchange_n(tx, 1, rx, 2); CS_RELEASE(); if (status_out) { *status_out = rx[0]; } return rx[1]; } /* * \brief Function reads RF register. * * \param addr Address on the RF * * \return Read register data */ static uint8_t rf_if_read_register(uint8_t addr) { return rf_if_read_register_with_status(addr, NULL); } /* * \brief Function resets the RF. * * \param none * * \return none */ static void rf_if_reset_radio(void) { #if MBED_CONF_ATMEL_RF_USE_SPI_SPACING_API rf->spi.frequency(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED); int spacing = rf->spi.write_spacing(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED_BYTE_SPACING); if (spacing < MBED_CONF_ATMEL_RF_FULL_SPI_SPEED_BYTE_SPACING) { rf->spi.frequency(MBED_CONF_ATMEL_RF_LOW_SPI_SPEED); rf->spi.write_spacing(0); } #elif MBED_CONF_ATMEL_RF_ASSUME_SPACED_SPI rf->spi.frequency(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED); #else rf->spi.frequency(MBED_CONF_ATMEL_RF_LOW_SPI_SPEED); #endif rf->IRQ.rise(0); rf->RST = 1; wait_ms(1); rf->RST = 0; wait_ms(10); CS_RELEASE(); rf->SLP_TR = 0; wait_ms(10); rf->RST = 1; wait_ms(10); rf->IRQ.rise(&rf_if_interrupt_handler); } /* * \brief Function enables the promiscuous mode. * * \param none * * \return none */ static void rf_if_enable_promiscuous_mode(void) { if (!(xah_ctrl_1 & AACK_PROM_MODE)) { /*Set AACK_PROM_MODE to enable the promiscuous mode*/ rf_if_write_register(XAH_CTRL_1, xah_ctrl_1 |= AACK_PROM_MODE); } } /* * \brief Function disable the promiscuous mode. * * \param none * * \return none */ static void rf_if_disable_promiscuous_mode(void) { if (xah_ctrl_1 & AACK_PROM_MODE) { /*Clear AACK_PROM_MODE to disable the promiscuous mode*/ rf_if_write_register(XAH_CTRL_1, xah_ctrl_1 &= ~AACK_PROM_MODE); } } /* * \brief Function enables the Antenna diversity usage. * * \param none * * \return none */ static void rf_if_enable_ant_div(void) { /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/ rf_if_set_bit(ANT_DIV, ANT_EXT_SW_EN, ANT_EXT_SW_EN); } /* * \brief Function disables the Antenna diversity usage. * * \param none * * \return none */ static void rf_if_disable_ant_div(void) { rf_if_clear_bit(ANT_DIV, ANT_EXT_SW_EN); } /* * \brief Function sets the SLP TR pin. * * \param none * * \return none */ static void rf_if_enable_slptr(void) { rf->SLP_TR = 1; } /* * \brief Function clears the SLP TR pin. * * \param none * * \return none */ static void rf_if_disable_slptr(void) { rf->SLP_TR = 0; } /* * \brief Function writes the antenna diversity settings. * * \param none * * \return none */ static void rf_if_write_antenna_diversity_settings(void) { /*Recommended setting of PDT_THRES is 3 when antenna diversity is used*/ rf_if_set_bit(RX_CTRL, 0x03, 0x0f); rf_if_write_register(ANT_DIV, ANT_DIV_EN | ANT_EXT_SW_EN | ANT_CTRL_DEFAULT); } /* * \brief Function writes the TX output power register. * * \param value Given register value * * \return none */ static void rf_if_write_set_tx_power_register(uint8_t value) { rf_if_write_register(PHY_TX_PWR, value); } /* * \brief Function returns the RF part number. * * \param none * * \return part number */ static uint8_t rf_if_read_part_num(void) { return rf_if_read_register(PART_NUM); } /* * \brief Function writes the RF settings and initialises SPI interface. * * \param none * * \return none */ static void rf_if_write_rf_settings(void) { /*Reset RF module*/ rf_if_reset_radio(); rf_part_num = rf_if_read_part_num(); rf_if_write_register(XAH_CTRL_0,0); /* Auto CRC on, IRQ status shows unmasked only, TRX_STATUS output on all accesses */ rf_if_write_register(TRX_CTRL_1, TX_AUTO_CRC_ON | SPI_CMD_MODE_TRX_STATUS); rf_if_write_register(IRQ_MASK, CCA_ED_DONE | TRX_END | TRX_UR); xah_ctrl_1 = rf_if_read_register(XAH_CTRL_1); /*Read transceiver PART_NUM*/ rf_part_num = rf_if_read_register(PART_NUM); /*Sub-GHz RF settings*/ if(rf_part_num == PART_AT86RF212) { /*GC_TX_OFFS mode-dependent setting - OQPSK*/ rf_if_write_register(RF_CTRL_0, 0x32); if(rf_if_read_register(VERSION_NUM) == VERSION_AT86RF212B) { /*TX Output Power setting - 0 dBm North American Band*/ rf_if_write_register(PHY_TX_PWR, 0x03); } else { /*TX Output Power setting - 0 dBm North American Band*/ rf_if_write_register(PHY_TX_PWR, 0x24); } /*PHY Mode: IEEE 802.15.4-2006/2011 - OQPSK-SIN-250*/ rf_if_write_register(TRX_CTRL_2, RX_SAFE_MODE | RF_PHY_MODE); /*Based on receiver Characteristics. See AT86RF212B Datasheet where RSSI BASE VALUE in range -97 - -100 dBm*/ rf_rssi_base_val = -98; } /*2.4GHz RF settings*/ else { #if 0 /* Disable power saving functions for now - can only impact reliability, * and don't have any users demanding it. */ /*Set RPC register*/ rf_if_write_register(TRX_RPC, RX_RPC_CTRL|RX_RPC_EN|PLL_RPC_EN|XAH_TX_RPC_EN|IPAN_RPC_EN|TRX_RPC_RSVD_1); #endif /*PHY Mode: IEEE 802.15.4 - Data Rate 250 kb/s*/ rf_if_write_register(TRX_CTRL_2, RX_SAFE_MODE); rf_rssi_base_val = -91; } } /* * \brief Function returns the RF state * * \param none * * \return RF state */ static rf_trx_states_t rf_if_read_trx_state(void) { return rf_if_trx_status_from_full(rf_if_read_register(TRX_STATUS)); } /* * \brief Function reads packet buffer. * * \param data_out Output buffer * \param lqi_out LQI output * \param ed_out ED output * \param crc_good CRC good indication * * \return PSDU length [0..RF_MTU] */ static uint16_t rf_if_read_packet(uint8_t data_out[RF_MTU], uint8_t *lqi_out, uint8_t *ed_out, bool *crc_good) { CS_SELECT(); const uint8_t tx[1] = { 0x20 }; uint8_t rx[3]; rf_if_spi_exchange_n(tx, 1, rx, 2); uint8_t len = rx[1] & 0x7F; rf_if_spi_exchange_n(NULL, 0, data_out, len); rf_if_spi_exchange_n(NULL, 0, rx, 3); *lqi_out = rx[0]; *ed_out = rx[1]; *crc_good = rx[2] & 0x80; CS_RELEASE(); return len; } /* * \brief Function writes RF short address registers * * \param short_address Given short address * * \return none */ static void rf_if_write_short_addr_registers(uint8_t *short_address) { rf_if_write_register(SHORT_ADDR_1, *short_address++); rf_if_write_register(SHORT_ADDR_0, *short_address); } /* * \brief Function sets the frame pending in ACK message * * \param state Given frame pending state * * \return none */ static void rf_if_ack_pending_ctrl(uint8_t state) { rf_if_lock(); if(state) { rf_if_set_bit(CSMA_SEED_1, (1 << AACK_SET_PD), (1 << AACK_SET_PD)); } else { rf_if_clear_bit(CSMA_SEED_1, (1 << AACK_SET_PD)); } rf_if_unlock(); } /* * \brief Function returns the state of frame pending control * * \param none * * \return Frame pending state */ static uint8_t rf_if_last_acked_pending(void) { uint8_t last_acked_data_pending; rf_if_lock(); if(rf_if_read_register(CSMA_SEED_1) & (1 << AACK_SET_PD)) last_acked_data_pending = 1; else last_acked_data_pending = 0; rf_if_unlock(); return last_acked_data_pending; } /* * \brief Function calibrates the RF part. * * \param none * * \return none */ static void rf_if_calibration(void) { rf_if_set_bit(FTN_CTRL, FTN_START, FTN_START); /*Wait while calibration is running*/ while(rf_if_read_register(FTN_CTRL) & FTN_START); } /* * \brief Function writes RF PAN Id registers * * \param pan_id Given PAN Id * * \return none */ static void rf_if_write_pan_id_registers(uint8_t *pan_id) { rf_if_write_register(PAN_ID_1, *pan_id++); rf_if_write_register(PAN_ID_0, *pan_id); } /* * \brief Function writes RF IEEE Address registers * * \param address Given IEEE Address * * \return none */ static void rf_if_write_ieee_addr_registers(uint8_t *address) { uint8_t i; uint8_t temp = IEEE_ADDR_0; for(i=0; i<8; i++) rf_if_write_register(temp++, address[7-i]); } /* * \brief Function writes data in RF frame buffer. * * \param ptr Pointer to data (PSDU, except FCS) * \param length Pointer to length (PSDU length, minus 2 for FCS) * * \return none */ static void rf_if_write_frame_buffer(const uint8_t *ptr, uint8_t length) { const uint8_t cmd[2] = { 0x60, static_cast<uint8_t>(length + 2) }; CS_SELECT(); rf_if_spi_exchange_n(cmd, 2, NULL, 0); rf_if_spi_exchange_n(ptr, length, NULL, 0); CS_RELEASE(); } /* * \brief Function returns 8-bit random value. * * \param none * * \return random value */ static uint8_t rf_if_read_rnd(void) { uint8_t temp; uint8_t tmp_rpc_val = 0; /*RPC must be disabled while reading the random number*/ if(rf_part_num == PART_AT86RF233) { tmp_rpc_val = rf_if_read_register(TRX_RPC); rf_if_write_register(TRX_RPC, RX_RPC_CTRL|TRX_RPC_RSVD_1); } wait_ms(1); temp = ((rf_if_read_register(PHY_RSSI)>>5) << 6); wait_ms(1); temp |= ((rf_if_read_register(PHY_RSSI)>>5) << 4); wait_ms(1); temp |= ((rf_if_read_register(PHY_RSSI)>>5) << 2); wait_ms(1); temp |= ((rf_if_read_register(PHY_RSSI)>>5)); wait_ms(1); if(rf_part_num == PART_AT86RF233) rf_if_write_register(TRX_RPC, tmp_rpc_val); return temp; } /* * \brief Function changes the state of the RF. * * \param trx_state Given RF state * * \return none */ static rf_trx_states_t rf_if_change_trx_state(rf_trx_states_t trx_state) { rf_if_write_register(TRX_STATE, trx_state); /*Wait while not in desired state*/ return rf_poll_trx_state_change(trx_state); } /* * \brief Function starts the CCA process * * \param none * * \return none */ static void rf_if_start_cca_process(void) { rf_if_write_register(PHY_CC_CCA, CCA_REQUEST | CCA_MODE_3A | rf_phy_channel); } /* * \brief Function scales RSSI * * \param ed_level ED level read from chip * * \return appropriately scaled RSSI dBm */ static int8_t rf_if_scale_rssi(uint8_t ed_level) { if (rf_part_num == PART_AT86RF212) { /* Data sheet says to multiply by 1.03 - this is 1.03125, rounding down */ ed_level += ed_level >> 5; } return rf_rssi_base_val + ed_level; } /* * \brief Function sets the RF channel field * * \param Given channel * * \return none */ static void rf_if_set_channel_register(uint8_t channel) { rf_if_set_bit(PHY_CC_CCA, channel, CCA_CHANNEL_MASK); } /* * \brief Function enables RF irq pin interrupts in RF interface. * * \param none * * \return none */ static void rf_if_enable_irq(void) { rf->IRQ.enable_irq(); } /* * \brief Function disables RF irq pin interrupts in RF interface. * * \param none * * \return none */ static void rf_if_disable_irq(void) { rf->IRQ.disable_irq(); } #ifdef MBED_CONF_RTOS_PRESENT static void rf_if_interrupt_handler(void) { rf->irq_thread.signal_set(SIG_RADIO); } // Started during construction of rf, so variable // rf isn't set at the start. Uses 'this' instead. void RFBits::rf_if_irq_task(void) { for (;;) { osEvent event = irq_thread.signal_wait(0); if (event.status != osEventSignal) { continue; } rf_if_lock(); if (event.value.signals & SIG_RADIO) { rf_if_irq_task_process_irq(); } if (event.value.signals & SIG_TIMER_ACK) { rf_ack_wait_timer_interrupt(); } if (event.value.signals & SIG_TIMER_CCA) { rf_cca_timer_interrupt(); } if (event.value.signals & SIG_TIMER_CAL) { rf_calibration_timer_interrupt(); } rf_if_unlock(); } } static void rf_if_irq_task_process_irq(void) #else /* * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt. * * \param none * * \return none */ static void rf_if_interrupt_handler(void) #endif { static uint8_t last_is, last_ts; uint8_t irq_status, full_trx_status; uint8_t orig_xah_ctrl_1 = xah_ctrl_1; /*Read and clear interrupt flag, and pick up trx_status*/ irq_status = rf_if_read_register_with_status(IRQ_STATUS, &full_trx_status); uint8_t orig_flags = rf_flags; /*Frame end interrupt (RX and TX)*/ if(irq_status & TRX_END) { /*TX done interrupt*/ rf_trx_states_t trx_status = rf_if_trx_status_from_full(full_trx_status); if(trx_status == PLL_ON || trx_status == TX_ARET_ON) { rf_handle_tx_end(trx_status); } /*Frame received interrupt*/ else { rf_handle_rx_end(trx_status); } } if(irq_status & CCA_ED_DONE) { rf_handle_cca_ed_done(full_trx_status); } if (irq_status & TRX_UR) { tr_error("Radio underrun is %x->%x ts %x->%x fl %x->%x x1 %x", last_is, irq_status, last_ts, full_trx_status, orig_flags, rf_flags, orig_xah_ctrl_1); } last_is = irq_status; last_ts = full_trx_status; } /* * \brief Function writes/read data in SPI interface */ static void rf_if_spi_exchange_n(const void *tx, size_t tx_len, void *rx, size_t rx_len) { #if 1 rf->spi.write(static_cast<const char *>(tx), tx_len, static_cast<char *>(rx), rx_len); #else const uint8_t *txb = static_cast<const uint8_t *>(tx); uint8_t *rxb = static_cast<uint8_t *>(rx); while (tx_len > 0 || rx_len > 0) { uint8_t b; if (tx_len) { tx_len--; b = *txb++; } else { b = 0xFF; } b = rf->spi.write(b); if (rx_len) { rx_len--; *rxb++ = b; } } #endif } /* * \brief Function sets given RF flag on. * * \param x Given RF flag * * \return none */ static void rf_flags_set(uint8_t x) { rf_flags |= x; } /* * \brief Function clears given RF flag on. * * \param x Given RF flag * * \return none */ static void rf_flags_clear(uint8_t x) { rf_flags &= ~x; } /* * \brief Function checks if given RF flag is on. * * \param x Given RF flag * * \return states of the given flags */ static uint8_t rf_flags_check(uint8_t x) { return (rf_flags & x); } /* * \brief Function clears all RF flags. * * \param none * * \return none */ static void rf_flags_reset(void) { rf_flags = 0; } /* * \brief Function initialises and registers the RF driver. * * \param none * * \return rf_radio_driver_id Driver ID given by NET library */ static int8_t rf_device_register(const uint8_t *mac_addr) { rf_trx_part_e radio_type; rf_init(); radio_type = rf_radio_type_read(); if(radio_type != ATMEL_UNKNOW_DEV) { /*Set pointer to MAC address*/ device_driver.PHY_MAC = (uint8_t *)mac_addr; device_driver.driver_description = (char*)"ATMEL_MAC"; //Create setup Used Radio chips if(radio_type == ATMEL_AT86RF212) { device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE; } else { device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; } device_driver.phy_channel_pages = phy_channel_pages; /*Maximum size of payload is 127*/ device_driver.phy_MTU = 127; /*No header in PHY*/ device_driver.phy_header_length = 0; /*No tail in PHY*/ device_driver.phy_tail_length = 0; /*Set address write function*/ device_driver.address_write = &rf_address_write; /*Set RF extension function*/ device_driver.extension = &rf_extension; /*Set RF state control function*/ device_driver.state_control = &rf_interface_state_control; /*Set transmit function*/ device_driver.tx = &rf_start_cca; /*NULLIFY rx and tx_done callbacks*/ device_driver.phy_rx_cb = NULL; device_driver.phy_tx_done_cb = NULL; /*Register device driver*/ rf_radio_driver_id = arm_net_phy_register(&device_driver); } else { rf_if_disable_irq(); } return rf_radio_driver_id; } /* * \brief Function unregisters the RF driver. * * \param none * * \return none */ static void rf_device_unregister() { if (rf_radio_driver_id >= 0) { arm_net_phy_unregister(rf_radio_driver_id); rf_radio_driver_id = -1; } } /* * \brief Function is a call back for ACK wait timeout. * * \param none * * \return none */ static void rf_ack_wait_timer_interrupt(void) { rf_if_lock(); rf_give_up_on_ack(); rf_if_unlock(); } /* * \brief Function is a call back for calibration interval timer. * * \param none * * \return none */ static void rf_calibration_timer_interrupt(void) { /*Calibrate RF*/ rf_calibration_cb(); /*Start new calibration timeout*/ rf_calibration_timer_start(RF_CALIBRATION_INTERVAL); } /* * \brief Function is a call back for cca interval timer. * * \param none * * \return none */ static void rf_cca_timer_interrupt(void) { rf_flags_set(RFF_CCA); /*Start CCA process*/ rf_if_start_cca_process(); } /* * \brief Function starts the ACK wait timeout. * * \param slots Given slots, resolution 50us * * \return none */ static void rf_ack_wait_timer_start(uint16_t slots) { rf_if_ack_wait_timer_start(slots); } /* * \brief Function starts the calibration interval. * * \param slots Given slots, resolution 50us * * \return none */ static void rf_calibration_timer_start(uint32_t slots) { rf_if_calibration_timer_start(slots); } /* * \brief Function starts the CCA backoff. * * \param slots Given slots, resolution 50us * * \return none */ static void rf_cca_timer_start(uint32_t slots) { rf_if_cca_timer_start(slots); } /* * \brief Function stops the CCA backoff. * * \return none */ static void rf_cca_timer_stop(void) { rf_if_cca_timer_stop(); } /* * \brief Function writes various RF settings in startup. * * \param none * * \return none */ static void rf_write_settings(void) { rf_if_lock(); rf_if_write_rf_settings(); /*Set output power*/ rf_if_write_set_tx_power_register(radio_tx_power); /*Initialise Antenna Diversity*/ if(rf_use_antenna_diversity) rf_if_write_antenna_diversity_settings(); rf_if_unlock(); } /* * \brief Function writes 16-bit address in RF address filter. * * \param short_address Given short address * * \return none */ static void rf_set_short_adr(uint8_t * short_address) { rf_if_lock(); /*Wake up RF if sleeping*/ if(rf_flags_check(RFF_ON) == 0) { rf_if_disable_slptr(); rf_poll_trx_state_change(TRX_OFF); } /*Write address filter registers*/ rf_if_write_short_addr_registers(short_address); /*RF back to sleep*/ if(rf_flags_check(RFF_ON) == 0) { rf_if_enable_slptr(); } rf_if_unlock(); } /* * \brief Function writes PAN Id in RF PAN Id filter. * * \param pan_id Given PAN Id * * \return none */ static void rf_set_pan_id(uint8_t *pan_id) { rf_if_lock(); /*Wake up RF if sleeping*/ if(rf_flags_check(RFF_ON) == 0) { rf_if_disable_slptr(); rf_poll_trx_state_change(TRX_OFF); } /*Write address filter registers*/ rf_if_write_pan_id_registers(pan_id); /*RF back to sleep*/ if(rf_flags_check(RFF_ON) == 0) { rf_if_enable_slptr(); } rf_if_unlock(); } /* * \brief Function writes 64-bit address in RF address filter. * * \param address Given 64-bit address * * \return none */ static void rf_set_address(uint8_t *address) { rf_if_lock(); /*Wake up RF if sleeping*/ if(rf_flags_check(RFF_ON) == 0) { rf_if_disable_slptr(); rf_poll_trx_state_change(TRX_OFF); } /*Write address filter registers*/ rf_if_write_ieee_addr_registers(address); /*RF back to sleep*/ if(rf_flags_check(RFF_ON) == 0) { rf_if_enable_slptr(); } rf_if_unlock(); } /* * \brief Function sets the RF channel. * * \param ch New channel * * \return none */ static void rf_channel_set(uint8_t ch) { rf_if_lock(); rf_phy_channel = ch; if(ch < 0x1f) rf_if_set_channel_register(ch); rf_if_unlock(); } /* * \brief Function initialises the radio driver and resets the radio. * * \param none * * \return none */ static void rf_init(void) { rf_if_lock(); /*Write RF settings*/ rf_write_settings(); /*Initialise PHY mode*/ rf_init_phy_mode(); /*Clear RF flags*/ rf_flags_reset(); /*Set RF in TRX OFF state*/ rf_if_change_trx_state(TRX_OFF); /*Set RF in PLL_ON state*/ rf_trx_states_t trx_status = rf_if_change_trx_state(PLL_ON); /*Start receiver*/ rf_receive(trx_status); /*Read randomness, and add to seed*/ randLIB_add_seed(rf_if_read_rnd()); /*Start RF calibration timer*/ rf_calibration_timer_start(RF_CALIBRATION_INTERVAL); rf_if_unlock(); } /** * \brief Function gets called when MAC is setting radio off. * * \param none * * \return none */ static void rf_off(void) { if(rf_flags_check(RFF_ON)) { rf_if_lock(); rf_cca_abort(); uint16_t while_counter = 0; /*Wait while receiving*/ while(rf_if_read_trx_state() == BUSY_RX_AACK) { while_counter++; if(while_counter == 0xffff) break; } /*RF state change: RX_AACK_ON->PLL_ON->TRX_OFF->SLEEP*/ if(rf_if_read_trx_state() == RX_AACK_ON) { rf_if_change_trx_state(PLL_ON); } rf_if_change_trx_state(TRX_OFF); rf_if_enable_slptr(); /*Disable Antenna Diversity*/ if(rf_use_antenna_diversity) rf_if_disable_ant_div(); rf_if_unlock(); } /*Clears all flags*/ rf_flags_reset(); } /* * \brief Function polls the RF state until it has changed to desired state. * * \param trx_state RF state * * \return none */ static rf_trx_states_t rf_poll_trx_state_change(rf_trx_states_t trx_state) { uint16_t while_counter = 0; if(trx_state == FORCE_PLL_ON) trx_state = PLL_ON; else if(trx_state == FORCE_TRX_OFF) trx_state = TRX_OFF; rf_trx_states_t state_out; while((state_out = rf_if_read_trx_state()) != trx_state) { while_counter++; if(while_counter == 0x1ff) break; } return state_out; } /* * \brief Function polls the RF state until it is no longer transitioning. * * \param trx_state RF state * * \return none */ static rf_trx_states_t rf_poll_for_state(void) { rf_trx_states_t state_out; while((state_out = rf_if_read_trx_state()) == STATE_TRANSITION_IN_PROGRESS) { } return state_out; } /* * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO. * * \param data_ptr Pointer to TX data (excluding FCS) * \param data_length Length of the TX data (excluding FCS) * \param tx_handle Handle to transmission * \return 0 Success * \return -1 Busy */ static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ) { (void)data_protocol; rf_if_lock(); /*Check if transmitter is busy*/ rf_trx_states_t trx_state = rf_if_read_trx_state(); if(trx_state == BUSY_RX || trx_state == BUSY_RX_AACK || data_length > RF_MTU - 2) { rf_if_unlock(); /*Return busy*/ return -1; } else { rf_give_up_on_ack(); /*Nanostack has a static TX buffer, which will remain valid until we*/ /*generate a callback, so we just note the pointer for reading later.*/ rf_tx_data = data_ptr; rf_tx_length = data_length; /*Start CCA timeout*/ rf_cca_timer_start(RF_CCA_BASE_BACKOFF + randLIB_get_random_in_range(0, RF_CCA_RANDOM_BACKOFF)); /*Store TX handle*/ mac_tx_handle = tx_handle; rf_if_unlock(); } /*Return success*/ return 0; } /* * \brief Function aborts CCA process. * * \param none * * \return none */ static void rf_cca_abort(void) { rf_cca_timer_stop(); rf_flags_clear(RFF_CCA); } /* * \brief Function starts the transmission of the frame. * * \param none * * \return none */ static bool rf_start_tx() { /* Attempt change to PLL_ON */ rf_if_write_register(TRX_STATE, PLL_ON); // It appears that if radio is busy, rather than ignoring the state change, // the state change happens when it stops being busy - eg // after address match fail or finishing reception. If this happens, we do // not want to transmit - our channel clear check is stale (either someone is // still transmitting, or it's a long time since we checked). So wait for the // PLL_ON change and then go to receive mode without trying to transmit. rf_trx_states_t state = rf_poll_for_state(); int poll_count = 0; while (state != PLL_ON) { /* Change didn't work (yet) - must be busy - assume it will eventually change */ state = rf_poll_for_state(); poll_count++; } rf_flags_clear(RFF_RX); // Check whether we saw any delay in the PLL_ON transition. if (poll_count > 0) { tr_warning("PLL_ON delayed, retry count: %d", poll_count); // let's get back to the receiving state. rf_receive(state); return false; } rf_flags_set(RFF_TX); /*RF state change: SLP_TR pulse triggers PLL_ON->BUSY_TX*/ rf_if_enable_slptr(); /*Chip permits us to write frame buffer while it is transmitting*/ /*As long as first byte of data is in within 176us of TX start, we're good */ rf_if_write_frame_buffer(rf_tx_data, rf_tx_length); rf_if_disable_slptr(); return true; } /* * \brief Function sets the RF in RX state. * * \param none * * \return none */ static void rf_receive(rf_trx_states_t trx_status) { uint16_t while_counter = 0; if(rf_flags_check(RFF_ON) == 0) { rf_on(); rf_channel_set(rf_phy_channel); trx_status = TRX_OFF; } /*If not yet in RX state set it*/ if(rf_flags_check(RFF_RX) == 0) { /*Wait while receiving data. Just making sure, usually this shouldn't happen. */ while(trx_status == BUSY_RX || trx_status == BUSY_RX_AACK || trx_status == STATE_TRANSITION_IN_PROGRESS) { while_counter++; if(while_counter == 0xffff) { break; } trx_status = rf_if_read_trx_state(); } if((rf_mode == RF_MODE_SNIFFER) || (rf_mode == RF_MODE_ED)) { if (trx_status != RX_ON) { trx_status = rf_if_change_trx_state(RX_ON); } } else { /*ACK is always received in promiscuous mode to bypass address filters*/ if(rf_rx_mode) { rf_rx_mode = 0; rf_if_enable_promiscuous_mode(); } else { rf_if_disable_promiscuous_mode(); } if (trx_status != RX_AACK_ON) { trx_status = rf_if_change_trx_state(RX_AACK_ON); } } /*If calibration timer was unable to calibrate the RF, run calibration now*/ if(!rf_tuned) { /*Start calibration. This can be done in states TRX_OFF, PLL_ON or in any receive state*/ rf_if_calibration(); /*RF is tuned now*/ rf_tuned = 1; } rf_flags_set(RFF_RX); } } /* * \brief Function calibrates the radio. * * \param none * * \return none */ static void rf_calibration_cb(void) { /*clear tuned flag to start tuning in rf_receive*/ rf_tuned = 0; /*If RF is in default receive state, start calibration*/ if(rf_if_read_trx_state() == RX_AACK_ON) { rf_if_lock(); /*Set RF in PLL_ON state*/ rf_if_change_trx_state(PLL_ON); /*Set RF in TRX_OFF state to start PLL tuning*/ rf_if_change_trx_state(TRX_OFF); /*Set RF in RX_ON state to calibrate*/ rf_trx_states_t trx_status = rf_if_change_trx_state(RX_ON); /*Calibrate FTN*/ rf_if_calibration(); /*RF is tuned now*/ rf_tuned = 1; /*Back to default receive state*/ rf_flags_clear(RFF_RX); rf_receive(trx_status); rf_if_unlock(); } } /* * \brief Function sets RF_ON flag when radio is powered. * * \param none * * \return none */ static void rf_on(void) { /*Set RFF_ON flag*/ if(rf_flags_check(RFF_ON) == 0) { rf_if_lock(); rf_flags_set(RFF_ON); /*Enable Antenna diversity*/ if(rf_use_antenna_diversity) /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/ rf_if_enable_ant_div(); /*Wake up from sleep state*/ rf_if_disable_slptr(); rf_poll_trx_state_change(TRX_OFF); rf_if_unlock(); } } /* * \brief Abandon waiting for an ack frame * \return none */ static void rf_give_up_on_ack(void) { if (expected_ack_sequence == -1) { return; } rf_if_disable_promiscuous_mode(); rf_if_ack_wait_timer_stop(); expected_ack_sequence = -1; if(device_driver.phy_tx_done_cb){ device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_FAIL, 0, 0); } } /* * \brief Function handles the received ACK frame. * * \param seq_number Sequence number of received ACK * \param data_pending Pending bit state in received ACK * * \return none */ static void rf_handle_ack(uint8_t seq_number, uint8_t data_pending) { phy_link_tx_status_e phy_status; /*Received ACK sequence must be equal with transmitted packet sequence*/ if(expected_ack_sequence == seq_number) { rf_if_disable_promiscuous_mode(); rf_if_ack_wait_timer_stop(); expected_ack_sequence = -1; /*When data pending bit in ACK frame is set, inform NET library*/ if(data_pending) phy_status = PHY_LINK_TX_DONE_PENDING; else phy_status = PHY_LINK_TX_DONE; /*Call PHY TX Done API*/ if(device_driver.phy_tx_done_cb){ device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle,phy_status, 0, 0); } } else { rf_give_up_on_ack(); } } /* * \brief Function is a call back for RX end interrupt. * * \param none * * \return none */ static void rf_handle_rx_end(rf_trx_states_t trx_status) { /*Frame received interrupt*/ if(!rf_flags_check(RFF_RX)) { return; } static uint8_t rf_buffer[RF_MTU]; uint8_t rf_lqi, rf_ed; int8_t rf_rssi; bool crc_good; /*Read received packet*/ uint8_t len = rf_if_read_packet(rf_buffer, &rf_lqi, &rf_ed, &crc_good); if (len < 5 || !crc_good) { rf_give_up_on_ack(); return; } /* Convert raw ED to dBm value (chip-dependent) */ rf_rssi = rf_if_scale_rssi(rf_ed); /* Create a virtual LQI using received RSSI, forgetting actual HW LQI */ /* (should be done through PHY_EXTENSION_CONVERT_SIGNAL_INFO) */ rf_lqi = rf_scale_lqi(rf_rssi); /*Handle received ACK*/ if((rf_buffer[0] & 0x07) == 0x02 && rf_mode != RF_MODE_SNIFFER) { /*Check if data is pending*/ bool pending = (rf_buffer[0] & 0x10); /*Send sequence number in ACK handler*/ rf_handle_ack(rf_buffer[2], pending); } else { rf_give_up_on_ack(); if( device_driver.phy_rx_cb ){ device_driver.phy_rx_cb(rf_buffer, len - 2, rf_lqi, rf_rssi, rf_radio_driver_id); } } } /* * \brief Function is called when MAC is shutting down the radio. * * \param none * * \return none */ static void rf_shutdown(void) { /*Call RF OFF*/ rf_off(); } /* * \brief Function is a call back for TX end interrupt. * * \param none * * \return none */ static void rf_handle_tx_end(rf_trx_states_t trx_status) { rf_rx_mode = 0; /*If ACK is needed for this transmission*/ if((rf_tx_data[0] & 0x20) && rf_flags_check(RFF_TX)) { expected_ack_sequence = rf_tx_data[2]; rf_ack_wait_timer_start(rf_ack_wait_duration); rf_rx_mode = 1; } rf_flags_clear(RFF_TX); /*Start receiver*/ rf_receive(trx_status); /*Call PHY TX Done API*/ if(device_driver.phy_tx_done_cb){ device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 0, 0); } } /* * \brief Function is a call back for CCA ED done interrupt. * * \param none * * \return none */ static void rf_handle_cca_ed_done(uint8_t full_trx_status) { if (!rf_flags_check(RFF_CCA)) { return; } rf_flags_clear(RFF_CCA); bool success = false; /*Check the result of CCA process*/ if((full_trx_status & CCA_STATUS) && rf_if_trx_status_from_full(full_trx_status) == RX_AACK_ON) { success = rf_start_tx(); } if (!success) { /*Send CCA fail notification*/ if(device_driver.phy_tx_done_cb){ device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); } } } /* * \brief Function gives the control of RF states to MAC. * * \param new_state RF state * \param rf_channel RF channel * * \return 0 Success */ static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel) { int8_t ret_val = 0; switch (new_state) { /*Reset PHY driver and set to idle*/ case PHY_INTERFACE_RESET: break; /*Disable PHY Interface driver*/ case PHY_INTERFACE_DOWN: rf_shutdown(); break; /*Enable PHY Interface driver*/ case PHY_INTERFACE_UP: rf_if_lock(); rf_mode = RF_MODE_NORMAL; rf_channel_set(rf_channel); rf_receive(); rf_if_enable_irq(); rf_if_unlock(); break; /*Enable wireless interface ED scan mode*/ case PHY_INTERFACE_RX_ENERGY_STATE: rf_mode = RF_MODE_ED; rf_channel_set(rf_channel); rf_receive(); rf_if_disable_irq(); // Read status to clear pending flags. rf_if_read_register(IRQ_STATUS); // ED can be initiated by writing arbitrary value to PHY_ED_LEVEL rf_if_write_register(PHY_ED_LEVEL, 0xff); break; case PHY_INTERFACE_SNIFFER_STATE: /**< Enable Sniffer state */ rf_mode = RF_MODE_SNIFFER; rf_channel_set(rf_channel); rf_flags_clear(RFF_RX); rf_receive(); rf_if_enable_irq(); break; } return ret_val; } /* * \brief Function controls the ACK pending, channel setting and energy detection. * * \param extension_type Type of control * \param data_ptr Data from NET library * * \return 0 Success */ static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr) { switch (extension_type) { /*Control MAC pending bit for Indirect data transmission*/ case PHY_EXTENSION_CTRL_PENDING_BIT: if(*data_ptr) { rf_if_ack_pending_ctrl(1); } else { rf_if_ack_pending_ctrl(0); } break; /*Return frame pending status*/ case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: *data_ptr = rf_if_last_acked_pending(); break; /*Set channel*/ case PHY_EXTENSION_SET_CHANNEL: break; /*Read energy on the channel*/ case PHY_EXTENSION_READ_CHANNEL_ENERGY: // End of the ED measurement is indicated by CCA_ED_DONE while (!(rf_if_read_register(IRQ_STATUS) & CCA_ED_DONE)); // RF input power: RSSI base level + 1[db] * PHY_ED_LEVEL *data_ptr = rf_sensitivity + rf_if_read_register(PHY_ED_LEVEL); // Read status to clear pending flags. rf_if_read_register(IRQ_STATUS); // Next ED measurement is started, next PHY_EXTENSION_READ_CHANNEL_ENERGY call will return the result. rf_if_write_register(PHY_ED_LEVEL, 0xff); break; /*Read status of the link*/ case PHY_EXTENSION_READ_LINK_STATUS: break; default: break; } return 0; } /* * \brief Function sets the addresses to RF address filters. * * \param address_type Type of address * \param address_ptr Pointer to given address * * \return 0 Success */ static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr) { int8_t ret_val = 0; switch (address_type) { /*Set 48-bit address*/ case PHY_MAC_48BIT: break; /*Set 64-bit address*/ case PHY_MAC_64BIT: rf_set_address(address_ptr); break; /*Set 16-bit address*/ case PHY_MAC_16BIT: rf_set_short_adr(address_ptr); break; /*Set PAN Id*/ case PHY_MAC_PANID: rf_set_pan_id(address_ptr); break; } return ret_val; } /* * \brief Function initialises the ACK wait time and returns the used PHY mode. * * \param none * * \return tmp Used PHY mode */ static void rf_init_phy_mode(void) { uint8_t tmp = 0; uint8_t part = rf_if_read_part_num(); /*Read used PHY Mode*/ tmp = rf_if_read_register(TRX_CTRL_2); /*Set ACK wait time for used data rate*/ if(part == PART_AT86RF212) { if((tmp & 0x1f) == 0x00) { rf_sensitivity = -110; rf_ack_wait_duration = 938; tmp = BPSK_20; } else if((tmp & 0x1f) == 0x04) { rf_sensitivity = -108; rf_ack_wait_duration = 469; tmp = BPSK_40; } else if((tmp & 0x1f) == 0x14) { rf_sensitivity = -108; rf_ack_wait_duration = 469; tmp = BPSK_40_ALT; } else if((tmp & 0x1f) == 0x08) { rf_sensitivity = -101; rf_ack_wait_duration = 50; tmp = OQPSK_SIN_RC_100; } else if((tmp & 0x1f) == 0x09) { rf_sensitivity = -99; rf_ack_wait_duration = 30; tmp = OQPSK_SIN_RC_200; } else if((tmp & 0x1f) == 0x18) { rf_sensitivity = -102; rf_ack_wait_duration = 50; tmp = OQPSK_RC_100; } else if((tmp & 0x1f) == 0x19) { rf_sensitivity = -100; rf_ack_wait_duration = 30; tmp = OQPSK_RC_200; } else if((tmp & 0x1f) == 0x0c) { rf_sensitivity = -100; rf_ack_wait_duration = 20; tmp = OQPSK_SIN_250; } else if((tmp & 0x1f) == 0x0d) { rf_sensitivity = -98; rf_ack_wait_duration = 25; tmp = OQPSK_SIN_500; } else if((tmp & 0x1f) == 0x0f) { rf_sensitivity = -98; rf_ack_wait_duration = 25; tmp = OQPSK_SIN_500_ALT; } else if((tmp & 0x1f) == 0x1c) { rf_sensitivity = -101; rf_ack_wait_duration = 20; tmp = OQPSK_RC_250; } else if((tmp & 0x1f) == 0x1d) { rf_sensitivity = -99; rf_ack_wait_duration = 25; tmp = OQPSK_RC_500; } else if((tmp & 0x1f) == 0x1f) { rf_sensitivity = -99; rf_ack_wait_duration = 25; tmp = OQPSK_RC_500_ALT; } else if((tmp & 0x3f) == 0x2A) { rf_sensitivity = -91; rf_ack_wait_duration = 25; tmp = OQPSK_SIN_RC_400_SCR_ON; } else if((tmp & 0x3f) == 0x0A) { rf_sensitivity = -91; rf_ack_wait_duration = 25; tmp = OQPSK_SIN_RC_400_SCR_OFF; } else if((tmp & 0x3f) == 0x3A) { rf_sensitivity = -97; rf_ack_wait_duration = 25; tmp = OQPSK_RC_400_SCR_ON; } else if((tmp & 0x3f) == 0x1A) { rf_sensitivity = -97; rf_ack_wait_duration = 25; tmp = OQPSK_RC_400_SCR_OFF; } else if((tmp & 0x3f) == 0x2E) { rf_sensitivity = -93; rf_ack_wait_duration = 13; tmp = OQPSK_SIN_1000_SCR_ON; } else if((tmp & 0x3f) == 0x0E) { rf_sensitivity = -93; rf_ack_wait_duration = 13; tmp = OQPSK_SIN_1000_SCR_OFF; } else if((tmp & 0x3f) == 0x3E) { rf_sensitivity = -95; rf_ack_wait_duration = 13; tmp = OQPSK_RC_1000_SCR_ON; } else if((tmp & 0x3f) == 0x1E) { rf_sensitivity = -95; rf_ack_wait_duration = 13; tmp = OQPSK_RC_1000_SCR_OFF; } } else { rf_sensitivity = -101; rf_ack_wait_duration = 20; } /*Board design might reduces the sensitivity*/ //rf_sensitivity += RF_SENSITIVITY_CALIBRATION; } static uint8_t rf_scale_lqi(int8_t rssi) { uint8_t scaled_lqi; /*rssi < RF sensitivity*/ if(rssi < rf_sensitivity) scaled_lqi=0; /*-91 dBm < rssi < -81 dBm (AT86RF233 XPro)*/ /*-90 dBm < rssi < -80 dBm (AT86RF212B XPro)*/ else if(rssi < (rf_sensitivity + 10)) scaled_lqi=31; /*-81 dBm < rssi < -71 dBm (AT86RF233 XPro)*/ /*-80 dBm < rssi < -70 dBm (AT86RF212B XPro)*/ else if(rssi < (rf_sensitivity + 20)) scaled_lqi=207; /*-71 dBm < rssi < -61 dBm (AT86RF233 XPro)*/ /*-70 dBm < rssi < -60 dBm (AT86RF212B XPro)*/ else if(rssi < (rf_sensitivity + 30)) scaled_lqi=255; /*-61 dBm < rssi < -51 dBm (AT86RF233 XPro)*/ /*-60 dBm < rssi < -50 dBm (AT86RF212B XPro)*/ else if(rssi < (rf_sensitivity + 40)) scaled_lqi=255; /*-51 dBm < rssi < -41 dBm (AT86RF233 XPro)*/ /*-50 dBm < rssi < -40 dBm (AT86RF212B XPro)*/ else if(rssi < (rf_sensitivity + 50)) scaled_lqi=255; /*-41 dBm < rssi < -31 dBm (AT86RF233 XPro)*/ /*-40 dBm < rssi < -30 dBm (AT86RF212B XPro)*/ else if(rssi < (rf_sensitivity + 60)) scaled_lqi=255; /*-31 dBm < rssi < -21 dBm (AT86RF233 XPro)*/ /*-30 dBm < rssi < -20 dBm (AT86RF212B XPro)*/ else if(rssi < (rf_sensitivity + 70)) scaled_lqi=255; /*rssi > RF saturation*/ else if(rssi > (rf_sensitivity + 80)) scaled_lqi=111; /*-21 dBm < rssi < -11 dBm (AT86RF233 XPro)*/ /*-20 dBm < rssi < -10 dBm (AT86RF212B XPro)*/ else scaled_lqi=255; return scaled_lqi; } NanostackRfPhyAtmel::NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso, PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq, PinName i2c_sda, PinName i2c_scl) : _mac(i2c_sda, i2c_scl), _mac_addr(), _rf(NULL), _mac_set(false), _spi_mosi(spi_mosi), _spi_miso(spi_miso), _spi_sclk(spi_sclk), _spi_cs(spi_cs), _spi_rst(spi_rst), _spi_slp(spi_slp), _spi_irq(spi_irq) { _rf = new RFBits(_spi_mosi, _spi_miso, _spi_sclk, _spi_cs, _spi_rst, _spi_slp, _spi_irq); } NanostackRfPhyAtmel::~NanostackRfPhyAtmel() { delete _rf; } int8_t NanostackRfPhyAtmel::rf_register() { if (NULL == _rf) { return -1; } rf_if_lock(); if (rf != NULL) { rf_if_unlock(); error("Multiple registrations of NanostackRfPhyAtmel not supported"); return -1; } // Read the mac address if it hasn't been set by a user rf = _rf; if (!_mac_set) { int ret = _mac.read_eui64((void*)_mac_addr); if (ret < 0) { rf = NULL; rf_if_unlock(); return -1; } } int8_t radio_id = rf_device_register(_mac_addr); if (radio_id < 0) { rf = NULL; } rf_if_unlock(); return radio_id; } void NanostackRfPhyAtmel::rf_unregister() { rf_if_lock(); if (NULL == rf) { rf_if_unlock(); return; } rf_device_unregister(); rf = NULL; rf_if_unlock(); } void NanostackRfPhyAtmel::get_mac_address(uint8_t *mac) { rf_if_lock(); if (NULL == rf) { error("NanostackRfPhyAtmel Must be registered to read mac address"); rf_if_unlock(); return; } memcpy((void*)mac, (void*)_mac_addr, sizeof(_mac_addr)); rf_if_unlock(); } void NanostackRfPhyAtmel::set_mac_address(uint8_t *mac) { rf_if_lock(); if (NULL != rf) { error("NanostackRfPhyAtmel cannot change mac address when running"); rf_if_unlock(); return; } memcpy((void*)_mac_addr, (void*)mac, sizeof(_mac_addr)); _mac_set = true; rf_if_unlock(); } #if MBED_CONF_ATMEL_RF_PROVIDE_DEFAULT NanostackRfPhy &NanostackRfPhy::get_default_instance() { static NanostackRfPhyAtmel rf_phy(ATMEL_SPI_MOSI, ATMEL_SPI_MISO, ATMEL_SPI_SCLK, ATMEL_SPI_CS, ATMEL_SPI_RST, ATMEL_SPI_SLP, ATMEL_SPI_IRQ, ATMEL_I2C_SDA, ATMEL_I2C_SCL); return rf_phy; } #endif // MBED_CONF_ATMEL_RF_PROVIDE_DEFAULT #endif // MBED_CONF_NANOSTACK_CONFIGURATION