Vergil Cola
/
MQTTGatewayK64
Fork of my MQTTGateway
easy-connect/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp
- Committer:
- vpcola
- Date:
- 2017-04-08
- Revision:
- 0:f1d3878b8dd9
File content as of revision 0:f1d3878b8dd9:
/* * 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 "NanostackRfPhyMcr20a.h" #include "ns_types.h" #include "platform/arm_hal_interrupt.h" #include "nanostack/platform/arm_hal_phy.h" #include "toolchain.h" #include <string.h> /* Freescale headers which are for C files */ extern "C" { #include "MCR20Drv.h" #include "MCR20Reg.h" #include "MCR20Overwrites.h" } #define RF_BUFFER_SIZE 128 /*Radio RX and TX state definitions*/ #define RFF_ON 0x01 #define RFF_RX 0x02 #define RFF_TX 0x04 #define RFF_CCA 0x08 #define RF_MODE_NORMAL 0 #define RF_MODE_SNIFFER 1 #define RF_CCA_THRESHOLD 75 /* -75 dBm */ #define RF_TX_POWER_MAX 0 /* PHY constants in symbols */ #define gPhyWarmUpTime_c 9 #define gPhySHRDuration_c 10 #define gPhySymbolsPerOctet_c 2 #define gPhyAckWaitDuration_c 54 #define gCcaED_c 0 #define gCcaCCA_MODE1_c 1 #define gXcvrRunState_d gXcvrPwrAutodoze_c #define gXcvrLowPowerState_d gXcvrPwrHibernate_c /* MCR20A XCVR states */ typedef enum xcvrState_tag{ gIdle_c, gRX_c, gTX_c, gCCA_c, gTR_c, gCCCA_c, }xcvrState_t; /* MCR20A XCVR low power states */ typedef enum xcvrPwrMode_tag{ gXcvrPwrIdle_c, gXcvrPwrAutodoze_c, gXcvrPwrDoze_c, gXcvrPwrHibernate_c }xcvrPwrMode_t; /*RF Part Type*/ typedef enum { FREESCALE_UNKNOW_DEV = 0, FREESCALE_MCR20A }rf_trx_part_e; /*Atmel RF states*/ typedef enum { NOP = 0x00, BUSY_RX = 0x01, 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 }rf_trx_states_t; /*RF receive buffer*/ static uint8_t rf_buffer[RF_BUFFER_SIZE]; /* TX info */ static uint8_t radio_tx_power = 0x17; /* 0 dBm */ static uint8_t mac_tx_handle = 0; static uint8_t need_ack = 0; static uint16_t tx_len = 0; /* RF driver data */ static xcvrState_t mPhySeqState; static xcvrPwrMode_t mPwrState; static phy_device_driver_s device_driver; static uint8_t mStatusAndControlRegs[8]; static uint8_t rf_rnd = 0; static int8_t rf_radio_driver_id = -1; static uint8_t MAC_address[8] = {1, 2, 3, 4, 5, 6, 7, 8}; /* Driver instance handle and hardware */ static NanostackRfPhyMcr20a *rf = NULL; static SPI *spi = NULL; static DigitalOut *cs = NULL; static DigitalOut *rst = NULL; static InterruptIn *irq = NULL; static DigitalIn *irq_pin = NULL; /* Channel info */ /* 2405 2410 2415 2420 2425 2430 2435 2440 2445 2450 2455 2460 2465 2470 2475 2480 */ static const uint8_t pll_int[16] = {0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D}; static const uint16_t pll_frac[16] = {0x2800, 0x5000, 0x7800, 0xA000, 0xC800, 0xF000, 0x1800, 0x4000, 0x6800, 0x9000, 0xB800, 0xE000, 0x0800, 0x3000, 0x5800, 0x8000}; static uint8_t rf_phy_channel = 0; /* Channel configurations for 2.4 */ static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK}; static const phy_device_channel_page_s phy_channel_pages[] = { { CHANNEL_PAGE_0, &phy_24ghz}, { CHANNEL_PAGE_0, NULL} }; static rf_trx_part_e rf_radio_type_read(void); MBED_UNUSED static void rf_ack_wait_timer_start(uint16_t slots); MBED_UNUSED static void rf_ack_wait_timer_stop(void); MBED_UNUSED static void rf_handle_cca_ed_done(void); MBED_UNUSED static void rf_handle_tx_end(void); MBED_UNUSED static void rf_handle_rx_end(void); MBED_UNUSED static void rf_on(void); MBED_UNUSED static void rf_receive(void); MBED_UNUSED static void rf_poll_trx_state_change(rf_trx_states_t trx_state); MBED_UNUSED static void rf_init(void); MBED_UNUSED static void rf_set_mac_address(const uint8_t *ptr); MBED_UNUSED static int8_t rf_device_register(void); MBED_UNUSED static void rf_device_unregister(void); MBED_UNUSED static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ); MBED_UNUSED static void rf_cca_abort(void); MBED_UNUSED static void rf_read_mac_address(uint8_t *ptr); MBED_UNUSED static int8_t rf_read_random(void); MBED_UNUSED static void rf_calibration_cb(void); MBED_UNUSED static void rf_init_phy_mode(void); MBED_UNUSED static void rf_ack_wait_timer_interrupt(void); MBED_UNUSED static void rf_calibration_timer_interrupt(void); MBED_UNUSED static void rf_calibration_timer_start(uint32_t slots); MBED_UNUSED static void rf_cca_timer_interrupt(void); MBED_UNUSED static void rf_cca_timer_start(uint32_t slots); MBED_UNUSED static uint16_t rf_get_phy_mtu_size(void); MBED_UNUSED static uint8_t rf_scale_lqi(int8_t rssi); /** * RF output power write * * \brief TX power has to be set before network start. * * \param power * See datasheet for TX power settings * * \return 0, Supported Value * \return -1, Not Supported Value */ MBED_UNUSED static int8_t rf_tx_power_set(uint8_t power); MBED_UNUSED static uint8_t rf_tx_power_get(void); MBED_UNUSED static int8_t rf_enable_antenna_diversity(void); /* Private functions */ MBED_UNUSED static void rf_abort(void); MBED_UNUSED static void rf_promiscuous(uint8_t mode); MBED_UNUSED static void rf_get_timestamp(uint32_t *pRetClk); MBED_UNUSED static void rf_set_timeout(uint32_t *pEndTime); MBED_UNUSED static void rf_set_power_state(xcvrPwrMode_t newState); MBED_UNUSED static uint8_t rf_if_read_rnd(void); MBED_UNUSED static uint8_t rf_convert_LQI(uint8_t hwLqi); MBED_UNUSED static uint8_t rf_get_channel_energy(void); MBED_UNUSED static uint8_t rf_convert_energy_level(uint8_t energyLevel); MBED_UNUSED static int8_t rf_convert_LQI_to_RSSI(uint8_t lqi); MBED_UNUSED static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel); MBED_UNUSED static int8_t rf_extension(phy_extension_type_e extension_type,uint8_t *data_ptr); MBED_UNUSED static int8_t rf_address_write(phy_address_type_e address_type,uint8_t *address_ptr); MBED_UNUSED static void rf_mac64_read(uint8_t *address); /* * \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) { return FREESCALE_MCR20A; } /* * \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(void) { rf_trx_part_e radio_type; rf_init(); radio_type = rf_radio_type_read(); if(radio_type == FREESCALE_MCR20A) { /*Set pointer to MAC address*/ device_driver.PHY_MAC = MAC_address; device_driver.driver_description = (char*)"FREESCALE_MAC"; //Create setup Used Radio chips /*Type of RF PHY is SubGHz*/ 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; /*Upper layer callbacks init to NULL*/ device_driver.phy_rx_cb = NULL; device_driver.phy_tx_done_cb = NULL; /*Virtual upper data callback init to NULL*/ device_driver.arm_net_virtual_rx_cb = NULL; device_driver.arm_net_virtual_tx_cb = NULL; /*Register device driver*/ rf_radio_driver_id = arm_net_phy_register(&device_driver); } return rf_radio_driver_id; } /* * \brief Function unregisters the RF driver. * * \param none * * \return none */ static void rf_device_unregister(void) { arm_net_phy_unregister(rf_radio_driver_id); } /* * \brief Function returns the generated 8-bit random value for seeding Pseudo-random generator. * * \param none * * \return random value */ static int8_t rf_read_random(void) { return rf_rnd; } /* * \brief Function is a call back for ACK wait timeout. * * \param none * * \return none */ static void rf_ack_wait_timer_interrupt(void) { /* The packet was transmitted successfully, but no ACK was received */ if (device_driver.phy_tx_done_cb) { device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1); } rf_receive(); } /* * \brief Function is a call back for calibration interval timer. * * \param none * * \return none */ static void rf_calibration_timer_interrupt(void) { } /* * \brief Function is a call back for cca interval timer. * * \param none * * \return none */ static void rf_cca_timer_interrupt(void) { /* CCA time-out handled by Hardware */ } /* * \brief Function starts the ACK wait time-out. * * \param slots The ACK wait time-out in [symbols] * * \return none */ static void rf_ack_wait_timer_start(uint16_t time) { uint32_t timeout; rf_get_timestamp(&timeout); timeout += time; rf_set_timeout(&timeout); } /* * \brief Function starts the calibration interval. * * \param slots Given slots, resolution 50us * * \return none */ static void rf_calibration_timer_start(uint32_t slots) { (void)slots; } /* * \brief Function starts the CCA timout. * * \param slots Given slots, resolution 50us * * \return none */ static void rf_cca_timer_start(uint32_t slots) { (void)slots; } /* * \brief Function stops the ACK wait timeout. * * \param none * * \return none */ static void rf_ack_wait_timer_stop(void) { } /* * \brief Function reads the MAC address array. * * \param ptr Pointer to read array * * \return none */ static void rf_read_mac_address(uint8_t *ptr) { memcpy(ptr, MAC_address, 8); } /* * \brief Function sets the MAC address array. * * \param ptr Pointer to given MAC address array * * \return none */ static void rf_set_mac_address(const uint8_t *ptr) { memcpy(MAC_address, ptr, 8); } static uint16_t rf_get_phy_mtu_size(void) { return device_driver.phy_MTU; } /* * \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) { /* Write one register at a time to be accessible from hibernate mode */ MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_MSB, short_address[0]); MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_LSB, short_address[1]); } /* * \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) { /* Write one register at a time to be accessible from hibernate mode */ MCR20Drv_IndirectAccessSPIWrite(MACPANID0_MSB, pan_id[0]); MCR20Drv_IndirectAccessSPIWrite(MACPANID0_LSB, pan_id[1]); } /* * \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) { /* Write one register at a time to be accessible from hibernate mode */ MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_0, address[7]); MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_8, address[6]); MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_16, address[5]); MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_24, address[4]); MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_32, address[3]); MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_40, address[2]); MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_48, address[1]); MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_56, address[0]); } /* * \brief Function sets the RF channel. * * \param ch New channel * * \return none */ static void rf_channel_set(uint8_t channel) { rf_phy_channel = channel; MCR20Drv_DirectAccessSPIWrite(PLL_INT0, pll_int[channel - 11]); MCR20Drv_DirectAccessSPIMultiByteWrite(PLL_FRAC0_LSB, (uint8_t *) &pll_frac[channel - 11], 2); } /* * \brief Function initialises the radio driver and resets the radio. * * \param none * * \return none */ static void rf_init(void) { uint32_t index; mPhySeqState = gIdle_c; mPwrState = gXcvrPwrIdle_c; /*Reset RF module*/ MCR20Drv_RESET(); /* Initialize the transceiver SPI driver */ MCR20Drv_Init(); /* Disable Tristate on MISO for SPI reads */ MCR20Drv_IndirectAccessSPIWrite(MISC_PAD_CTRL, 0x02); /* Set XCVR clock output settings */ MCR20Drv_Set_CLK_OUT_Freq(gMCR20_ClkOutFreq_d); /* Set default XCVR power state */ rf_set_power_state(gXcvrRunState_d); /* PHY_CTRL1 default HW settings + AUTOACK enabled */ mStatusAndControlRegs[PHY_CTRL1] = cPHY_CTRL1_AUTOACK; /* PHY_CTRL2 : mask all PP interrupts */ mStatusAndControlRegs[PHY_CTRL2] = cPHY_CTRL2_CRC_MSK | \ cPHY_CTRL2_PLL_UNLOCK_MSK | \ /*cPHY_CTRL2_FILTERFAIL_MSK | */ \ cPHY_CTRL2_RX_WMRK_MSK | \ cPHY_CTRL2_CCAMSK | \ cPHY_CTRL2_RXMSK | \ cPHY_CTRL2_TXMSK | \ cPHY_CTRL2_SEQMSK; /* PHY_CTRL3 : enable timer 3 and disable remaining interrupts */ mStatusAndControlRegs[PHY_CTRL3] = cPHY_CTRL3_ASM_MSK | \ cPHY_CTRL3_PB_ERR_MSK | \ cPHY_CTRL3_WAKE_MSK | \ cPHY_CTRL3_TMR3CMP_EN; /* PHY_CTRL4 unmask global TRX interrupts, enable 16 bit mode for TC2 - TC2 prime EN */ mStatusAndControlRegs[PHY_CTRL4] = cPHY_CTRL4_TC2PRIME_EN | (gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c); /* Clear all PP IRQ bits to avoid unexpected interrupts immediately after initialization */ mStatusAndControlRegs[IRQSTS1] = cIRQSTS1_PLL_UNLOCK_IRQ | \ cIRQSTS1_FILTERFAIL_IRQ | \ cIRQSTS1_RXWTRMRKIRQ | \ cIRQSTS1_CCAIRQ | \ cIRQSTS1_RXIRQ | \ cIRQSTS1_TXIRQ | \ cIRQSTS1_SEQIRQ; mStatusAndControlRegs[IRQSTS2] = cIRQSTS2_ASM_IRQ | cIRQSTS2_PB_ERR_IRQ | cIRQSTS2_WAKE_IRQ; /* Mask and clear all TMR IRQs */ mStatusAndControlRegs[IRQSTS3] = cIRQSTS3_TMR4MSK | cIRQSTS3_TMR3MSK | cIRQSTS3_TMR2MSK | cIRQSTS3_TMR1MSK | \ cIRQSTS3_TMR4IRQ | cIRQSTS3_TMR3IRQ | cIRQSTS3_TMR2IRQ | cIRQSTS3_TMR1IRQ; /* Write settings to XCVR */ MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 5); /* Clear all interrupts */ MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, &mStatusAndControlRegs[IRQSTS1], 3); /* RX_FRAME_FILTER. Accept FrameVersion 0 and 1 packets, reject all others */ MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, (cRX_FRAME_FLT_FRM_VER | \ cRX_FRAME_FLT_BEACON_FT | \ cRX_FRAME_FLT_DATA_FT | \ cRX_FRAME_FLT_CMD_FT )); /* Direct register overwrites */ for (index = 0; index < sizeof(overwrites_direct)/sizeof(overwrites_t); index++) MCR20Drv_DirectAccessSPIWrite(overwrites_direct[index].address, overwrites_direct[index].data); /* Indirect register overwrites */ for (index = 0; index < sizeof(overwrites_indirect)/sizeof(overwrites_t); index++) MCR20Drv_IndirectAccessSPIWrite(overwrites_indirect[index].address, overwrites_indirect[index].data); /* Set the CCA energy threshold value */ MCR20Drv_IndirectAccessSPIWrite(CCA1_THRESH, RF_CCA_THRESHOLD); /* Set prescaller to obtain 1 symbol (16us) timebase */ MCR20Drv_IndirectAccessSPIWrite(TMR_PRESCALE, 0x05); MCR20Drv_IRQ_Enable(); /*Read random variable. This will be used when seeding pseudo-random generator*/ rf_rnd = rf_if_read_rnd(); /*Read eui64*/ rf_mac64_read(MAC_address); /*set default channel to 11*/ rf_channel_set(11); /*Start receiver*/ rf_receive(); } /** * \brief Function gets called when MAC is setting radio off. * * \param none * * \return none */ static void rf_off(void) { /* Abort any ongoing sequences */ rf_abort(); /* Set XCVR in a low power state */ rf_set_power_state(gXcvrLowPowerState_d); } /* * \brief Function polls the RF state until it has changed to desired state. * * \param trx_state RF state * * \return none */ static void rf_poll_trx_state_change(rf_trx_states_t trx_state) { (void)trx_state; } /* * \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 * \param data_length Length of the TX data * \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 ) { uint8_t ccaMode; /* Parameter validation */ if( !data_ptr || (data_length > 125) || (PHY_LAYER_PAYLOAD != data_protocol) ) { return -1; } if( mPhySeqState == gRX_c ) { uint8_t phyReg = MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F; /* Check for an Rx in progress. */ if((phyReg <= 0x06) || (phyReg == 0x15) || (phyReg == 0x16)) { if (device_driver.phy_tx_done_cb) { device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1); } return -1; } rf_abort(); } /*Check if transmitter is busy*/ if( mPhySeqState != gIdle_c ) { /*Return busy*/ return -1; } /*Store TX handle*/ mac_tx_handle = tx_handle; /*Check if transmitted data needs to be acked*/ need_ack = (*data_ptr & 0x20) == 0x20; /* Set XCVR power state in run mode */ rf_set_power_state(gXcvrRunState_d); /* Load data into XCVR */ tx_len = data_length + 2; MCR20Drv_PB_SPIBurstWrite(data_ptr - 1, data_length + 1); MCR20Drv_PB_SPIByteWrite(0,tx_len); /* Set CCA mode 1 */ ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE; if( ccaMode != gCcaCCA_MODE1_c ) { mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c); mStatusAndControlRegs[PHY_CTRL4] |= gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c; MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]); } /* Read XCVR registers */ mStatusAndControlRegs[0] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[1], 4); mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c; mPhySeqState = gCCA_c; /* Ensure that no spurious interrupts are raised */ mStatusAndControlRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */ mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ); MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3); /* Write XCVR settings */ MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); /* Unmask SEQ interrupt */ mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK); MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]); /*Return success*/ return 0; } /* * \brief Function aborts CCA process. * * \param none * * \return none */ static void rf_cca_abort(void) { rf_abort(); } /* * \brief Function starts the transmission of the frame. Called from ISR context! * * \param none * * \return none */ static void rf_start_tx(void) { /* Perform TxRxAck sequence if required by phyTxMode */ if( need_ack ) { mStatusAndControlRegs[PHY_CTRL1] |= cPHY_CTRL1_RXACKRQD; mPhySeqState = gTR_c; } else { mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_RXACKRQD); mPhySeqState = gTX_c; } mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); mStatusAndControlRegs[PHY_CTRL1] |= mPhySeqState; /* Unmask SEQ interrupt */ mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK); /* Start the sequence immediately */ MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 2); if( need_ack ) { rf_ack_wait_timer_start(gPhyWarmUpTime_c + gPhySHRDuration_c + tx_len * gPhySymbolsPerOctet_c + gPhyAckWaitDuration_c); } } /* * \brief Function sets the RF in RX state. Called from ISR context! * * \param none * * \return none */ static void rf_receive(void) { uint8_t phyRegs[5]; /* RX can start only from Idle state */ if( mPhySeqState != gIdle_c ) { return; } /* Set XCVR power state in run mode */ rf_set_power_state(gXcvrRunState_d); /* read XVCR settings */ phyRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &phyRegs[IRQSTS2], 4); /* unmask SEQ interrupt */ phyRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK); /* set XcvrSeq to RX */ phyRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); phyRegs[PHY_CTRL1] |= gRX_c; mPhySeqState = gRX_c; /* Ensure that no spurious interrupts are raised */ phyRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */ phyRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ; /* sync settings with XCVR */ MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, phyRegs, 5); } /* * \brief Function calibrates the radio. * * \param none * * \return none */ static void rf_calibration_cb(void) { } /* * \brief Function sets RF_ON flag when radio is powered. * * \param none * * \return none */ static void rf_on(void) { } /* * \brief Function is a call back for RX end interrupt. * * \param none * * \return none */ static void rf_handle_rx_end(void) { uint8_t rf_lqi = MCR20Drv_DirectAccessSPIRead(LQI_VALUE); int8_t rf_rssi = 0; uint8_t len = mStatusAndControlRegs[RX_FRM_LEN] - 2; /*Start receiver*/ rf_receive(); /*Check the length is valid*/ if(len > 1 && len < RF_BUFFER_SIZE) { rf_lqi = rf_convert_LQI(rf_lqi); rf_rssi = rf_convert_LQI_to_RSSI(rf_lqi); /*gcararu: Scale LQI using received RSSI, to match the LQI reported by the ATMEL radio */ rf_lqi = rf_scale_lqi(rf_rssi); /*Read received packet*/ MCR20Drv_PB_SPIBurstRead(rf_buffer, len); if (device_driver.phy_rx_cb) { device_driver.phy_rx_cb(rf_buffer, len, 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(void) { uint8_t rx_frame_pending = mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_RX_FRM_PEND; /*Start receiver*/ rf_receive(); if (!device_driver.phy_tx_done_cb) { return; } /*Call PHY TX Done API*/ if( need_ack ) { if( rx_frame_pending ) { device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE_PENDING, 1, 1); } else { // arm_net_phy_tx_done(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1); device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE, 1, 1); } } else { device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1); } } /* * \brief Function is a call back for CCA ED done interrupt. * * \param none * * \return none */ static void rf_handle_cca_ed_done(void) { /*Check the result of CCA process*/ if( !(mStatusAndControlRegs[IRQSTS2] & cIRQSTS2_CCA) ) { rf_start_tx(); } else if (device_driver.phy_tx_done_cb) { /*Send CCA fail notification*/ device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1); } } /* * \brief Function sets the TX power variable. * * \param power TX power setting * * \return 0 Success * \return -1 Fail */ static int8_t rf_tx_power_set(uint8_t power) { /* gcapraru: Map MCR20A Tx power levels over ATMEL values */ static uint8_t pwrLevelMapping[16] = {25,25,25,24,24,24,23,23,22,22,21,20,19,18,17,14}; if( power > 15 ) { return -1; } radio_tx_power = power; MCR20Drv_DirectAccessSPIWrite(PA_PWR, pwrLevelMapping[power]); return 0; } /* * \brief Function returns the TX power variable. * * \param none * * \return radio_tx_power TX power variable */ static uint8_t rf_tx_power_get(void) { return radio_tx_power; } /* * \brief Function enables the usage of Antenna diversity. * * \param none * * \return 0 Success */ static int8_t rf_enable_antenna_diversity(void) { uint8_t phyReg; phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_AGC_CTRL); phyReg |= cANT_AGC_CTRL_FAD_EN_Mask_c; MCR20Drv_IndirectAccessSPIWrite(ANT_AGC_CTRL, phyReg); phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_PAD_CTRL); phyReg |= 0x02; MCR20Drv_IndirectAccessSPIWrite(ANT_PAD_CTRL, phyReg); return 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_channel_set(rf_channel); rf_receive(); break; /*Enable wireless interface ED scan mode*/ case PHY_INTERFACE_RX_ENERGY_STATE: rf_abort(); rf_channel_set(rf_channel); break; case PHY_INTERFACE_SNIFFER_STATE: /**< Enable Sniffer state */ rf_promiscuous(1); rf_channel_set(rf_channel); rf_receive(); 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: { uint8_t reg = MCR20Drv_DirectAccessSPIRead(SRC_CTRL); if(*data_ptr) { reg |= cSRC_CTRL_ACK_FRM_PND; } else { reg &= ~cSRC_CTRL_ACK_FRM_PND; } MCR20Drv_DirectAccessSPIWrite(SRC_CTRL, reg); break; } /*Return frame pending status*/ case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: *data_ptr = MCR20Drv_DirectAccessSPIRead(IRQSTS1 & cIRQSTS1_RX_FRM_PEND); break; /*Set channel*/ case PHY_EXTENSION_SET_CHANNEL: break; /*Read energy on the channel*/ case PHY_EXTENSION_READ_CHANNEL_ENERGY: *data_ptr = rf_get_channel_energy(); break; /*Read status of the link*/ case PHY_EXTENSION_READ_LINK_STATUS: break; case PHY_EXTENSION_CONVERT_SIGNAL_INFO: 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; } static void rf_mac64_read(uint8_t *address) { /* Write one register at a time to be accessible from hibernate mode */ address[7] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_0); address[6] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_8); address[5] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_16); address[4] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_24); address[3] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_32); address[2] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_40); address[1] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_48); address[0] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_56); } /* * \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) { } /* * \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 PHY_InterruptHandler(void) { uint8_t xcvseqCopy; /* Disable and clear transceiver(IRQ_B) interrupt */ MCR20Drv_IRQ_Disable(); //MCR20Drv_IRQ_Clear(); /* Read transceiver interrupt status and control registers */ mStatusAndControlRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 7); xcvseqCopy = mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ; /* Flter Fail IRQ */ if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_FILTERFAIL_IRQ) && !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_FILTERFAIL_MSK) ) { if( xcvseqCopy == gRX_c ) { /* Abort current SEQ */ mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); /* Wait for Sequence Idle */ while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0); /* Clear IRQ flags: */ MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ); /* Restart Rx asap */ mStatusAndControlRegs[PHY_CTRL1] |= gRX_c; MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); } } /* TMR3 IRQ: ACK wait time-out */ if( (mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3IRQ) && !(mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3MSK) ) { /* Disable TMR3 IRQ */ mStatusAndControlRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK; if( xcvseqCopy == gTR_c ) { /* Set XCVR to Idle */ mPhySeqState = gIdle_c; mStatusAndControlRegs[PHY_CTRL1] &= ~( cPHY_CTRL1_XCVSEQ ); /* Mask interrupts */ mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK; /* Sync settings with XCVR */ MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5); rf_ack_wait_timer_interrupt(); MCR20Drv_IRQ_Enable(); return; } } /* Sequencer interrupt, the autosequence has completed */ if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_SEQIRQ) && !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_SEQMSK) ) { /* Set XCVR to Idle */ mPhySeqState = gIdle_c; mStatusAndControlRegs[PHY_CTRL1] &= ~( cPHY_CTRL1_XCVSEQ ); /* Mask interrupts */ mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK; /* Sync settings with XCVR */ MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5); /* PLL unlock, the autosequence has been aborted due to PLL unlock */ if( mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_PLL_UNLOCK_IRQ ) { if(xcvseqCopy == gRX_c) { rf_receive(); } MCR20Drv_IRQ_Enable(); return; } switch(xcvseqCopy) { case gTX_c: case gTR_c: rf_handle_tx_end(); break; case gRX_c: rf_handle_rx_end(); break; case gCCA_c: rf_handle_cca_ed_done(); break; default: break; } MCR20Drv_IRQ_Enable(); return; } /* Other IRQ. Clear XCVR interrupt flags */ MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3); MCR20Drv_IRQ_Enable(); } /* * \brief Function forces the XCVR to Idle state. * * \param none * * \return none */ static void rf_abort(void) { /* Mask XCVR irq */ MCR20Drv_IRQ_Disable(); mPhySeqState = gIdle_c; mStatusAndControlRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 5); /* Mask SEQ interrupt */ mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_SEQMSK; MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]); if( (mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ) != gIdle_c ) { /* Abort current SEQ */ mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); /* Wait for Sequence Idle (if not already) */ while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0); //while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ)); mStatusAndControlRegs[IRQSTS1] |= cIRQSTS1_SEQIRQ; } /* Clear all PP IRQ bits to avoid unexpected interrupts and mask TMR3 interrupt. Do not change TMR IRQ status. */ mStatusAndControlRegs[IRQSTS3] &= 0xF0; mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ); MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3); /* Unmask XCVR irq */ MCR20Drv_IRQ_Enable(); } /* * \brief Function reads a time-stamp value from XCVR [symbols] * * \param pEndTime pointer to location where time-stamp will be stored * * \return none */ static void rf_get_timestamp(uint32_t *pRetClk) { if(NULL == pRetClk) { return; } platform_enter_critical(); *pRetClk = 0; MCR20Drv_DirectAccessSPIMultiByteRead(EVENT_TMR_LSB, (uint8_t *) pRetClk, 3); platform_exit_critical(); } /* * \brief Function set a time-out to an XCVR sequence. * * \param pEndTime pointer to the sequence time-out value [symbols] * * \return none */ static void rf_set_timeout(uint32_t *pEndTime) { uint8_t phyReg; if(NULL == pEndTime) { return; } platform_enter_critical(); phyReg = MCR20Drv_DirectAccessSPIRead(IRQSTS3); phyReg &= 0xF0; /* do not change IRQ status */ phyReg |= (cIRQSTS3_TMR3MSK); /* mask TMR3 interrupt */ MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg); MCR20Drv_DirectAccessSPIMultiByteWrite(T3CMP_LSB, (uint8_t *) pEndTime, 3); phyReg &= ~(cIRQSTS3_TMR3MSK); /* unmask TMR3 interrupt */ phyReg |= (cIRQSTS3_TMR3IRQ); /* aknowledge TMR3 IRQ */ MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg); platform_exit_critical(); } /* * \brief Function reads a random number from RF. * * \param none * * \return 8-bit random number */ static uint8_t rf_if_read_rnd(void) { uint8_t phyReg; MCR20Drv_IRQ_Disable(); /* Check if XCVR is idle */ phyReg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL1); if( (phyReg & cPHY_CTRL1_XCVSEQ) == gIdle_c ) { /* Program a new sequence */ MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, phyReg | gCCA_c); /* Wait for sequence to finish */ while( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ) ); /* Clear interrupt flag */ MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ); } MCR20Drv_IRQ_Enable(); return MCR20Drv_IndirectAccessSPIRead(_RNG); } /* * \brief Function converts LQI into RSSI. * * \param LQI * * \return RSSI */ static int8_t rf_convert_LQI_to_RSSI(uint8_t lqi) { int32_t rssi = (50*lqi - 16820) / 163; return (int8_t)rssi; } /* * \brief Function scale the LQI value reported by RF into a 0-255 value. * * \param hwLqi - the LQI value reported by RF * * \return scaled LQI */ static uint8_t rf_convert_LQI(uint8_t hwLqi) { uint32_t tmpLQI; /* LQI Saturation Level */ if (hwLqi >= 230) { return 0xFF; } else if (hwLqi <= 9) { return 0; } else { /* Rescale the LQI values from min to saturation to the 0x00 - 0xFF range */ /* The LQI value mst be multiplied by ~1.1087 */ /* tmpLQI = hwLqi * 7123 ~= hwLqi * 65536 * 0.1087 = hwLqi * 2^16 * 0.1087*/ tmpLQI = ((uint32_t)hwLqi * (uint32_t)7123 ); /* tmpLQI = (tmpLQI / 2^16) + hwLqi */ tmpLQI = (uint32_t)(tmpLQI >> 16) + (uint32_t)hwLqi; return (uint8_t)tmpLQI; } } /* * \brief Function enables/disables Rx promiscuous mode. * * \param state of XCVR promiscuous mode * * \return none */ static void rf_promiscuous(uint8_t state) { uint8_t rxFrameFltReg, phyCtrl4Reg; rxFrameFltReg = MCR20Drv_IndirectAccessSPIRead(RX_FRAME_FILTER); phyCtrl4Reg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL4); if( state ) { /* FRM_VER[1:0] = b00. 00: Any FrameVersion accepted (0,1,2 & 3) */ /* All frame types accepted*/ phyCtrl4Reg |= cPHY_CTRL4_PROMISCUOUS; rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER); rxFrameFltReg |= (cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT); } else { phyCtrl4Reg &= ~cPHY_CTRL4_PROMISCUOUS; /* FRM_VER[1:0] = b11. Accept FrameVersion 0 and 1 packets, reject all others */ /* Beacon, Data and MAC command frame types accepted */ rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER); rxFrameFltReg |= (0x03 << cRX_FRAME_FLT_FRM_VER_Shift_c); rxFrameFltReg &= ~(cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT); } MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, rxFrameFltReg); MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, phyCtrl4Reg); } /* * \brief Function used to switch XCVR power state. * * \param state The XCVR power mode * * \return none */ static void rf_set_power_state(xcvrPwrMode_t newState) { uint8_t pwrMode; uint8_t xtalState; if( mPwrState == newState ) { return; } /* Read power settings from RF */ pwrMode = MCR20Drv_DirectAccessSPIRead(PWR_MODES); xtalState = pwrMode & cPWR_MODES_XTALEN; switch( newState ) { case gXcvrPwrIdle_c: pwrMode &= ~(cPWR_MODES_AUTODOZE); pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_PMC_MODE); break; case gXcvrPwrAutodoze_c: pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE); break; case gXcvrPwrDoze_c: pwrMode &= ~(cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE); pwrMode |= cPWR_MODES_XTALEN; break; case gXcvrPwrHibernate_c: pwrMode &= ~(cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE); break; default: return; } mPwrState = newState; MCR20Drv_DirectAccessSPIWrite(PWR_MODES, pwrMode); if( !xtalState && (pwrMode & cPWR_MODES_XTALEN)) { /* wait for crystal oscillator to complet its warmup */ while( ( MCR20Drv_DirectAccessSPIRead(PWR_MODES) & cPWR_MODES_XTAL_READY ) != cPWR_MODES_XTAL_READY); /* wait for radio wakeup from hibernate interrupt */ while( ( MCR20Drv_DirectAccessSPIRead(IRQSTS2) & (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) ) != (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) ); MCR20Drv_DirectAccessSPIWrite(IRQSTS2, cIRQSTS2_WAKE_IRQ); } } /* * \brief Function reads the energy level on the preselected channel. * * \return energy level */ static uint8_t rf_get_channel_energy(void) { uint8_t ccaMode; MCR20Drv_IRQ_Disable(); /* RX can start only from Idle state */ if( mPhySeqState != gIdle_c ) { MCR20Drv_IRQ_Enable(); return 0; } /* Set XCVR power state in run mode */ rf_set_power_state(gXcvrRunState_d); /* Switch to ED mode */ ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE; if( ccaMode != gCcaED_c ) { mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c); mStatusAndControlRegs[PHY_CTRL4] |= gCcaED_c << cPHY_CTRL4_CCATYPE_Shift_c; MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]); } /* Start ED sequence */ mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c; MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ); MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); /* Wait for sequence to finish */ while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ)); /* Set XCVR to Idle */ mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ); MCR20Drv_IRQ_Enable(); return rf_convert_energy_level(MCR20Drv_DirectAccessSPIRead(CCA1_ED_FNL)); } /* * \brief Function converts the energy level from dBm to a 0-255 value. * * \param energyLevel in dBm * * \return energy level (0-255) */ static uint8_t rf_convert_energy_level(uint8_t energyLevel) { if(energyLevel >= 90) { /* ED value is below minimum. Return 0x00. */ energyLevel = 0x00; } else if(energyLevel <= 26) { /* ED value is above maximum. Return 0xFF. */ energyLevel = 0xFF; } else { /* Energy level (-90 dBm to -26 dBm ) --> varies form 0 to 64 */ energyLevel = (90 - energyLevel); /* Rescale the energy level values to the 0x00-0xff range (0 to 64 translates in 0 to 255) */ /* energyLevel * 3.9844 ~= 4 */ /* Multiply with 4=2^2 by shifting left. The multiplication will not overflow beacause energyLevel has values between 0 and 63 */ energyLevel <<= 2; } return energyLevel; } static uint8_t rf_scale_lqi(int8_t rssi) { uint8_t scaled_lqi; /*Worst case sensitivity*/ const int8_t rf_sensitivity = -98; /*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; } /*****************************************************************************/ /* Layer porting to the Freescale driver */ /*****************************************************************************/ extern "C" void xcvr_spi_init(uint32_t instance) { (void)instance; } extern "C" void RF_IRQ_Init(void) { MBED_ASSERT(irq != NULL); irq->mode(PullUp); irq->fall(&PHY_InterruptHandler); } extern "C" void RF_IRQ_Enable(void) { MBED_ASSERT(irq != NULL); irq->enable_irq(); } extern "C" void RF_IRQ_Disable(void) { MBED_ASSERT(irq != NULL); irq->disable_irq(); } extern "C" uint8_t RF_isIRQ_Pending(void) { MBED_ASSERT(rf != NULL); return !irq_pin->read(); } extern "C" void RF_RST_Set(int state) { MBED_ASSERT(rst != NULL); *rst = state; } extern "C" void gXcvrAssertCS_d(void) { MBED_ASSERT(cs != NULL); *cs = 0; } extern "C" void gXcvrDeassertCS_d(void) { MBED_ASSERT(cs != NULL); *cs = 1; } extern "C" void xcvr_spi_configure_speed(uint32_t instance, uint32_t freq) { MBED_ASSERT(spi != NULL); (void)instance; spi->frequency(freq); } extern "C" void xcvr_spi_transfer(uint32_t instance, uint8_t * sendBuffer, uint8_t * receiveBuffer, size_t transferByteCount) { MBED_ASSERT(spi != NULL); (void)instance; volatile uint8_t dummy; if( !transferByteCount ) return; if( !sendBuffer && !receiveBuffer ) return; while( transferByteCount-- ) { if( sendBuffer ) { dummy = *sendBuffer; sendBuffer++; } else { dummy = 0xFF; } dummy = spi->write(dummy); if( receiveBuffer ) { *receiveBuffer = dummy; receiveBuffer++; } } } /*****************************************************************************/ /*****************************************************************************/ static void rf_if_lock(void) { platform_enter_critical(); } static void rf_if_unlock(void) { platform_exit_critical(); } NanostackRfPhyMcr20a::NanostackRfPhyMcr20a(PinName spi_mosi, PinName spi_miso, PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_irq) : _spi(spi_mosi, spi_miso, spi_sclk), _rf_cs(spi_cs), _rf_rst(spi_rst), _rf_irq(spi_irq), _rf_irq_pin(spi_irq) { // Do nothing } NanostackRfPhyMcr20a::~NanostackRfPhyMcr20a() { // Do nothing } int8_t NanostackRfPhyMcr20a::rf_register() { rf_if_lock(); if (rf != NULL) { rf_if_unlock(); error("Multiple registrations of NanostackRfPhyMcr20a not supported"); return -1; } _pins_set(); int8_t radio_id = rf_device_register(); if (radio_id < 0) { _pins_clear(); rf = NULL; } rf_if_unlock(); return radio_id; } void NanostackRfPhyMcr20a::rf_unregister() { rf_if_lock(); if (rf != this) { rf_if_unlock(); return; } rf_device_unregister(); rf = NULL; _pins_clear(); rf_if_unlock(); } void NanostackRfPhyMcr20a::get_mac_address(uint8_t *mac) { rf_if_lock(); memcpy((void*)mac, (void*)MAC_address, sizeof(MAC_address)); rf_if_unlock(); } void NanostackRfPhyMcr20a::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_address, (void*)mac, sizeof(MAC_address)); rf_if_unlock(); } void NanostackRfPhyMcr20a::_pins_set() { spi = &_spi; cs = &_rf_cs; rst = &_rf_rst; irq = &_rf_irq; irq_pin = &_rf_irq_pin; } void NanostackRfPhyMcr20a::_pins_clear() { spi = NULL; cs = NULL; rst = NULL; irq = NULL; irq_pin = NULL; }