/* * Copyright (c) 2012, Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \addtogroup cc2538-rf * @{ * * \file * Implementation of the cc2538 RF driver */ #include "contiki.h" #include "dev/radio.h" #include "sys/clock.h" #include "sys/rtimer.h" #include "net/packetbuf.h" #include "net/rime/rimestats.h" #include "net/linkaddr.h" #include "net/netstack.h" #include "sys/energest.h" #include "dev/cc2538-rf.h" #include "dev/rfcore.h" #include "dev/sys-ctrl.h" #include "dev/udma.h" #include "reg.h" #include /*---------------------------------------------------------------------------*/ #define CHECKSUM_LEN 2 /* uDMA channel control persistent flags */ #define UDMA_TX_FLAGS (UDMA_CHCTL_ARBSIZE_128 | UDMA_CHCTL_XFERMODE_AUTO \ | UDMA_CHCTL_SRCSIZE_8 | UDMA_CHCTL_DSTSIZE_8 \ | UDMA_CHCTL_SRCINC_8 | UDMA_CHCTL_DSTINC_NONE) #define UDMA_RX_FLAGS (UDMA_CHCTL_ARBSIZE_128 | UDMA_CHCTL_XFERMODE_AUTO \ | UDMA_CHCTL_SRCSIZE_8 | UDMA_CHCTL_DSTSIZE_8 \ | UDMA_CHCTL_SRCINC_NONE | UDMA_CHCTL_DSTINC_8) /* * uDMA transfer threshold. DMA will only be used to read an incoming frame * if its size is above this threshold */ #define UDMA_RX_SIZE_THRESHOLD 3 /*---------------------------------------------------------------------------*/ #include #define DEBUG 0 #if DEBUG #define PRINTF(...) printf(__VA_ARGS__) #else #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ /* Local RF Flags */ #define RX_ACTIVE 0x80 #define RF_MUST_RESET 0x40 #define WAS_OFF 0x10 #define RF_ON 0x01 /* Bit Masks for the last byte in the RX FIFO */ #define CRC_BIT_MASK 0x80 #define LQI_BIT_MASK 0x7F /* RSSI Offset */ #define RSSI_OFFSET 73 /* 192 usec off -> on interval (RX Callib -> SFD Wait). We wait a bit more */ #define ONOFF_TIME RTIMER_ARCH_SECOND / 3125 /*---------------------------------------------------------------------------*/ /* Sniffer configuration */ #ifndef CC2538_RF_CONF_SNIFFER_USB #define CC2538_RF_CONF_SNIFFER_USB 0 #endif #if CC2538_RF_CONF_SNIFFER static const uint8_t magic[] = { 0x53, 0x6E, 0x69, 0x66 }; /** Snif */ #if CC2538_RF_CONF_SNIFFER_USB #include "usb/usb-serial.h" #define write_byte(b) usb_serial_writeb(b) #define flush() usb_serial_flush() #else #include "dev/uart.h" #define write_byte(b) uart_write_byte(b) #define flush() #endif #else /* CC2538_RF_CONF_SNIFFER */ #define write_byte(b) #define flush() #endif /* CC2538_RF_CONF_SNIFFER */ /*---------------------------------------------------------------------------*/ #ifdef CC2538_RF_CONF_AUTOACK #define CC2538_RF_AUTOACK CC2538_RF_CONF_AUTOACK #else #define CC2538_RF_AUTOACK 1 #endif /*---------------------------------------------------------------------------*/ static uint8_t rf_flags; static int on(void); static int off(void); /*---------------------------------------------------------------------------*/ PROCESS(cc2538_rf_process, "cc2538 RF driver"); /*---------------------------------------------------------------------------*/ uint8_t cc2538_rf_channel_get() { uint8_t chan = REG(RFCORE_XREG_FREQCTRL) & RFCORE_XREG_FREQCTRL_FREQ; return ((chan - CC2538_RF_CHANNEL_MIN) / CC2538_RF_CHANNEL_SPACING + CC2538_RF_CHANNEL_MIN); } /*---------------------------------------------------------------------------*/ int8_t cc2538_rf_channel_set(uint8_t channel) { PRINTF("RF: Set Channel\n"); if((channel < CC2538_RF_CHANNEL_MIN) || (channel > CC2538_RF_CHANNEL_MAX)) { return -1; } /* Changes to FREQCTRL take effect after the next recalibration */ off(); REG(RFCORE_XREG_FREQCTRL) = (CC2538_RF_CHANNEL_MIN + (channel - CC2538_RF_CHANNEL_MIN) * CC2538_RF_CHANNEL_SPACING); on(); return (int8_t) channel; } /*---------------------------------------------------------------------------*/ uint8_t cc2538_rf_power_set(uint8_t new_power) { PRINTF("RF: Set Power\n"); REG(RFCORE_XREG_TXPOWER) = new_power; return (REG(RFCORE_XREG_TXPOWER) & 0xFF); } /*---------------------------------------------------------------------------*/ /* ToDo: Check once we have info on the... infopage */ void cc2538_rf_set_addr(uint16_t pan) { #if LINKADDR_SIZE==8 /* EXT_ADDR[7:0] is ignored when using short addresses */ int i; for(i = (LINKADDR_SIZE - 1); i >= 0; --i) { ((uint32_t *)RFCORE_FFSM_EXT_ADDR0)[i] = linkaddr_node_addr.u8[LINKADDR_SIZE - 1 - i]; } #endif REG(RFCORE_FFSM_PAN_ID0) = pan & 0xFF; REG(RFCORE_FFSM_PAN_ID1) = pan >> 8; REG(RFCORE_FFSM_SHORT_ADDR0) = linkaddr_node_addr.u8[LINKADDR_SIZE - 1]; REG(RFCORE_FFSM_SHORT_ADDR1) = linkaddr_node_addr.u8[LINKADDR_SIZE - 2]; } /*---------------------------------------------------------------------------*/ int cc2538_rf_read_rssi(void) { int rssi; /* If we are off, turn on first */ if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) { rf_flags |= WAS_OFF; on(); } /* Wait on RSSI_VALID */ while((REG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0); rssi = ((int8_t)REG(RFCORE_XREG_RSSI)) - RSSI_OFFSET; /* If we were off, turn back off */ if((rf_flags & WAS_OFF) == WAS_OFF) { rf_flags &= ~WAS_OFF; off(); } return rssi; } /*---------------------------------------------------------------------------*/ /* Netstack API radio driver functions */ /*---------------------------------------------------------------------------*/ static int channel_clear(void) { int cca; PRINTF("RF: CCA\n"); /* If we are off, turn on first */ if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) { rf_flags |= WAS_OFF; on(); } /* Wait on RSSI_VALID */ while((REG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0); if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_CCA) { cca = CC2538_RF_CCA_CLEAR; } else { cca = CC2538_RF_CCA_BUSY; } /* If we were off, turn back off */ if((rf_flags & WAS_OFF) == WAS_OFF) { rf_flags &= ~WAS_OFF; off(); } return cca; } /*---------------------------------------------------------------------------*/ static int on(void) { PRINTF("RF: On\n"); if(!(rf_flags & RX_ACTIVE)) { CC2538_RF_CSP_ISFLUSHRX(); CC2538_RF_CSP_ISRXON(); rf_flags |= RX_ACTIVE; } ENERGEST_ON(ENERGEST_TYPE_LISTEN); return 1; } /*---------------------------------------------------------------------------*/ static int off(void) { PRINTF("RF: Off\n"); /* Wait for ongoing TX to complete (e.g. this could be an outgoing ACK) */ while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); CC2538_RF_CSP_ISFLUSHRX(); /* Don't turn off if we are off as this will trigger a Strobe Error */ if(REG(RFCORE_XREG_RXENABLE) != 0) { CC2538_RF_CSP_ISRFOFF(); } rf_flags &= ~RX_ACTIVE; ENERGEST_OFF(ENERGEST_TYPE_LISTEN); return 1; } /*---------------------------------------------------------------------------*/ static int init(void) { PRINTF("RF: Init\n"); if(rf_flags & RF_ON) { return 0; } /* Enable clock for the RF Core while Running, in Sleep and Deep Sleep */ REG(SYS_CTRL_RCGCRFC) = 1; REG(SYS_CTRL_SCGCRFC) = 1; REG(SYS_CTRL_DCGCRFC) = 1; REG(RFCORE_XREG_CCACTRL0) = CC2538_RF_CCA_THRES_USER_GUIDE; /* * Changes from default values * See User Guide, section "Register Settings Update" */ REG(RFCORE_XREG_TXFILTCFG) = 0x09; /** TX anti-aliasing filter bandwidth */ REG(RFCORE_XREG_AGCCTRL1) = 0x15; /** AGC target value */ REG(ANA_REGS_IVCTRL) = 0x0B; /** Bias currents */ /* * Defaults: * Auto CRC; Append RSSI, CRC-OK and Corr. Val.; CRC calculation; * RX and TX modes with FIFOs */ REG(RFCORE_XREG_FRMCTRL0) = RFCORE_XREG_FRMCTRL0_AUTOCRC; #if CC2538_RF_AUTOACK REG(RFCORE_XREG_FRMCTRL0) |= RFCORE_XREG_FRMCTRL0_AUTOACK; #endif /* If we are a sniffer, turn off frame filtering */ #if CC2538_RF_CONF_SNIFFER REG(RFCORE_XREG_FRMFILT0) &= ~RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN; #endif /* Disable source address matching and autopend */ REG(RFCORE_XREG_SRCMATCH) = 0; /* MAX FIFOP threshold */ REG(RFCORE_XREG_FIFOPCTRL) = CC2538_RF_MAX_PACKET_LEN; cc2538_rf_power_set(CC2538_RF_TX_POWER); cc2538_rf_channel_set(CC2538_RF_CHANNEL); /* Acknowledge RF interrupts, FIFOP only */ REG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_FIFOP; nvic_interrupt_enable(NVIC_INT_RF_RXTX); /* Acknowledge all RF Error interrupts */ REG(RFCORE_XREG_RFERRM) = RFCORE_XREG_RFERRM_RFERRM; nvic_interrupt_enable(NVIC_INT_RF_ERR); if(CC2538_RF_CONF_TX_USE_DMA) { /* Disable peripheral triggers for the channel */ udma_channel_mask_set(CC2538_RF_CONF_TX_DMA_CHAN); /* * Set the channel's DST. SRC can not be set yet since it will change for * each transfer */ udma_set_channel_dst(CC2538_RF_CONF_TX_DMA_CHAN, RFCORE_SFR_RFDATA); } if(CC2538_RF_CONF_RX_USE_DMA) { /* Disable peripheral triggers for the channel */ udma_channel_mask_set(CC2538_RF_CONF_RX_DMA_CHAN); /* * Set the channel's SRC. DST can not be set yet since it will change for * each transfer */ udma_set_channel_src(CC2538_RF_CONF_RX_DMA_CHAN, RFCORE_SFR_RFDATA); } process_start(&cc2538_rf_process, NULL); rf_flags |= RF_ON; ENERGEST_ON(ENERGEST_TYPE_LISTEN); return 1; } /*---------------------------------------------------------------------------*/ static int prepare(const void *payload, unsigned short payload_len) { uint8_t i; PRINTF("RF: Prepare 0x%02x bytes\n", payload_len + CHECKSUM_LEN); /* * When we transmit in very quick bursts, make sure previous transmission * is not still in progress before re-writing to the TX FIFO */ while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); if((rf_flags & RX_ACTIVE) == 0) { on(); } CC2538_RF_CSP_ISFLUSHTX(); PRINTF("RF: data = "); /* Send the phy length byte first */ REG(RFCORE_SFR_RFDATA) = payload_len + CHECKSUM_LEN; if(CC2538_RF_CONF_TX_USE_DMA) { PRINTF(""); /* Set the transfer source's end address */ udma_set_channel_src(CC2538_RF_CONF_TX_DMA_CHAN, (uint32_t)(payload) + payload_len - 1); /* Configure the control word */ udma_set_channel_control_word(CC2538_RF_CONF_TX_DMA_CHAN, UDMA_TX_FLAGS | udma_xfer_size(payload_len)); /* Enabled the RF TX uDMA channel */ udma_channel_enable(CC2538_RF_CONF_TX_DMA_CHAN); /* Trigger the uDMA transfer */ udma_channel_sw_request(CC2538_RF_CONF_TX_DMA_CHAN); /* * No need to wait for this to end. Even if transmit() gets called * immediately, the uDMA controller will stream the frame to the TX FIFO * faster than transmit() can empty it */ } else { for(i = 0; i < payload_len; i++) { REG(RFCORE_SFR_RFDATA) = ((unsigned char *)(payload))[i]; PRINTF("%02x", ((unsigned char *)(payload))[i]); } } PRINTF("\n"); return 0; } /*---------------------------------------------------------------------------*/ static int transmit(unsigned short transmit_len) { uint8_t counter; int ret = RADIO_TX_ERR; rtimer_clock_t t0; PRINTF("RF: Transmit\n"); if(!(rf_flags & RX_ACTIVE)) { t0 = RTIMER_NOW(); on(); rf_flags |= WAS_OFF; while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME)); } if(channel_clear() == CC2538_RF_CCA_BUSY) { RIMESTATS_ADD(contentiondrop); return RADIO_TX_COLLISION; } /* * prepare() double checked that TX_ACTIVE is low. If SFD is high we are * receiving. Abort transmission and bail out with RADIO_TX_COLLISION */ if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_SFD) { RIMESTATS_ADD(contentiondrop); return RADIO_TX_COLLISION; } /* Start the transmission */ ENERGEST_OFF(ENERGEST_TYPE_LISTEN); ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); CC2538_RF_CSP_ISTXON(); counter = 0; while(!((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)) && (counter++ < 3)) { clock_delay_usec(6); } if(!(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)) { PRINTF("RF: TX never active.\n"); CC2538_RF_CSP_ISFLUSHTX(); ret = RADIO_TX_ERR; } else { /* Wait for the transmission to finish */ while(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); ret = RADIO_TX_OK; } ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); ENERGEST_ON(ENERGEST_TYPE_LISTEN); if(rf_flags & WAS_OFF) { rf_flags &= ~WAS_OFF; off(); } RIMESTATS_ADD(lltx); return ret; } /*---------------------------------------------------------------------------*/ static int send(const void *payload, unsigned short payload_len) { prepare(payload, payload_len); return transmit(payload_len); } /*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short bufsize) { uint8_t i; uint8_t len; uint8_t crc_corr; int8_t rssi; PRINTF("RF: Read\n"); if((REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) == 0) { return 0; } /* Check the length */ len = REG(RFCORE_SFR_RFDATA); /* Check for validity */ if(len > CC2538_RF_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ PRINTF("RF: bad sync\n"); RIMESTATS_ADD(badsynch); CC2538_RF_CSP_ISFLUSHRX(); return 0; } if(len <= CC2538_RF_MIN_PACKET_LEN) { PRINTF("RF: too short\n"); RIMESTATS_ADD(tooshort); CC2538_RF_CSP_ISFLUSHRX(); return 0; } if(len - CHECKSUM_LEN > bufsize) { PRINTF("RF: too long\n"); RIMESTATS_ADD(toolong); CC2538_RF_CSP_ISFLUSHRX(); return 0; } /* If we reach here, chances are the FIFO is holding a valid frame */ PRINTF("RF: read (0x%02x bytes) = ", len); len -= CHECKSUM_LEN; /* Don't bother with uDMA for short frames (e.g. ACKs) */ if(CC2538_RF_CONF_RX_USE_DMA && len > UDMA_RX_SIZE_THRESHOLD) { PRINTF(""); /* Set the transfer destination's end address */ udma_set_channel_dst(CC2538_RF_CONF_RX_DMA_CHAN, (uint32_t)(buf) + len - 1); /* Configure the control word */ udma_set_channel_control_word(CC2538_RF_CONF_RX_DMA_CHAN, UDMA_RX_FLAGS | udma_xfer_size(len)); /* Enabled the RF RX uDMA channel */ udma_channel_enable(CC2538_RF_CONF_RX_DMA_CHAN); /* Trigger the uDMA transfer */ udma_channel_sw_request(CC2538_RF_CONF_RX_DMA_CHAN); /* Wait for the transfer to complete. */ while(udma_channel_get_mode(CC2538_RF_CONF_RX_DMA_CHAN)); } else { for(i = 0; i < len; ++i) { ((unsigned char *)(buf))[i] = REG(RFCORE_SFR_RFDATA); PRINTF("%02x", ((unsigned char *)(buf))[i]); } } /* Read the RSSI and CRC/Corr bytes */ rssi = ((int8_t)REG(RFCORE_SFR_RFDATA)) - RSSI_OFFSET; crc_corr = REG(RFCORE_SFR_RFDATA); PRINTF("%02x%02x\n", (uint8_t)rssi, crc_corr); /* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */ if(crc_corr & CRC_BIT_MASK) { packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK); RIMESTATS_ADD(llrx); } else { RIMESTATS_ADD(badcrc); PRINTF("RF: Bad CRC\n"); CC2538_RF_CSP_ISFLUSHRX(); return 0; } #if CC2538_RF_CONF_SNIFFER write_byte(magic[0]); write_byte(magic[1]); write_byte(magic[2]); write_byte(magic[3]); write_byte(len + 2); for(i = 0; i < len; ++i) { write_byte(((unsigned char *)(buf))[i]); } write_byte(rssi); write_byte(crc_corr); flush(); #endif /* If FIFOP==1 and FIFO==0 then we had a FIFO overflow at some point. */ if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) { if(REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFO) { process_poll(&cc2538_rf_process); } else { CC2538_RF_CSP_ISFLUSHRX(); } } return (len); } /*---------------------------------------------------------------------------*/ static int receiving_packet(void) { PRINTF("RF: Receiving\n"); /* * SFD high while transmitting and receiving. * TX_ACTIVE high only when transmitting * * FSMSTAT1 & (TX_ACTIVE | SFD) == SFD <=> receiving */ return ((REG(RFCORE_XREG_FSMSTAT1) & (RFCORE_XREG_FSMSTAT1_TX_ACTIVE | RFCORE_XREG_FSMSTAT1_SFD)) == RFCORE_XREG_FSMSTAT1_SFD); } /*---------------------------------------------------------------------------*/ static int pending_packet(void) { PRINTF("RF: Pending\n"); return (REG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP); } /*---------------------------------------------------------------------------*/ const struct radio_driver cc2538_rf_driver = { init, prepare, transmit, send, read, channel_clear, receiving_packet, pending_packet, on, off, }; /*---------------------------------------------------------------------------*/ /** * \brief Implementation of the cc2538 RF driver process * * This process is started by init(). It simply sits there waiting for * an event. Upon frame reception, the RX ISR will poll this process. * Subsequently, the contiki core will generate an event which will * call this process so that the received frame can be picked up from * the RF RX FIFO * */ PROCESS_THREAD(cc2538_rf_process, ev, data) { int len; PROCESS_BEGIN(); while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); packetbuf_clear(); len = read(packetbuf_dataptr(), PACKETBUF_SIZE); if(len > 0) { packetbuf_set_datalen(len); NETSTACK_RDC.input(); } /* If we were polled due to an RF error, reset the transceiver */ if(rf_flags & RF_MUST_RESET) { rf_flags = 0; off(); init(); } } PROCESS_END(); } /*---------------------------------------------------------------------------*/ /** * \brief The cc2538 RF RX/TX ISR * * This is the interrupt service routine for all RF interrupts relating * to RX and TX. Error conditions are handled by cc2538_rf_err_isr(). * Currently, we only acknowledge the FIFOP interrupt source. */ void cc2538_rf_rx_tx_isr(void) { ENERGEST_ON(ENERGEST_TYPE_IRQ); process_poll(&cc2538_rf_process); /* We only acknowledge FIFOP so we can safely wipe out the entire SFR */ REG(RFCORE_SFR_RFIRQF0) = 0; ENERGEST_OFF(ENERGEST_TYPE_IRQ); } /*---------------------------------------------------------------------------*/ /** * \brief The cc2538 RF Error ISR * * This is the interrupt service routine for all RF errors. We * acknowledge every error type and instead of trying to be smart and * act differently depending on error condition, we simply reset the * transceiver. RX FIFO overflow is an exception, we ignore this error * since read() handles it anyway. * * However, we don't want to reset within this ISR. If the error occurs * while we are reading a frame out of the FIFO, trashing the FIFO in * the middle of read(), would result in further errors (RX underflows). * * Instead, we set a flag and poll the driver process. The process will * reset the transceiver without any undesirable consequences. */ void cc2538_rf_err_isr(void) { ENERGEST_ON(ENERGEST_TYPE_IRQ); PRINTF("RF Error: 0x%08lx\n", REG(RFCORE_SFR_RFERRF)); /* If the error is not an RX FIFO overflow, set a flag */ if(REG(RFCORE_SFR_RFERRF) != RFCORE_SFR_RFERRF_RXOVERF) { rf_flags |= RF_MUST_RESET; } REG(RFCORE_SFR_RFERRF) = 0; process_poll(&cc2538_rf_process); ENERGEST_OFF(ENERGEST_TYPE_IRQ); } /*---------------------------------------------------------------------------*/ void cc2538_rf_set_promiscous_mode(char p) { if(p) { REG(RFCORE_XREG_FRMFILT0) &= ~RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN; } else { REG(RFCORE_XREG_FRMFILT0) |= RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN; } } /*---------------------------------------------------------------------------*/ /** @} */