/* * Copyright (C) 2016 MUTEX NZ Ltd. * Copyright (C) 2015 Loci Controls Inc. * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. * */ /** * @ingroup cpu_cc2538 * @{ * * @file * @brief Getter and setter functions for the cc2538_rf driver * * @author Aaron Sowry * @author Ian Martin * * @} */ #include "cc2538_rf.h" #define ENABLE_DEBUG (0) #include "debug.h" /* static const __flash uint8_t? */ static const uint8_t power_lut[NUM_POWER_LEVELS] = { 0, /**< -24 dBm */ 7, /**< -23 dBm */ 15, /**< -22 dBm */ 22, /**< -21 dBm */ 29, /**< -20 dBm */ 37, /**< -19 dBm */ 44, /**< -18 dBm */ 51, /**< -17 dBm */ 59, /**< -16 dBm */ 66, /**< -15 dBm */ 77, /**< -14 dBm */ 88, /**< -13 dBm */ 93, /**< -12 dBm */ 98, /**< -11 dBm */ 106, /**< -10 dBm */ 114, /**< -9 dBm */ 125, /**< -8 dBm */ 136, /**< -7 dBm */ 141, /**< -6 dBm */ 145, /**< -5 dBm */ 153, /**< -4 dBm */ 161, /**< -3 dBm */ 169, /**< -2 dBm */ 176, /**< -1 dBm */ 182, /**< 0 dBm */ 197, /**< 1 dBm */ 205, /**< 2 dBm */ 213, /**< 3 dBm */ 225, /**< 4 dBm */ 237, /**< 5 dBm */ 246, /**< 6 dBm */ 255, /**< 7 dBm */ }; uint64_t cc2538_get_addr_long(void) { uint64_t addr = RFCORE_FFSM_EXT_ADDR0; addr <<= 8; addr |= RFCORE_FFSM_EXT_ADDR1; addr <<= 8; addr |= RFCORE_FFSM_EXT_ADDR2; addr <<= 8; addr |= RFCORE_FFSM_EXT_ADDR3; addr <<= 8; addr |= RFCORE_FFSM_EXT_ADDR4; addr <<= 8; addr |= RFCORE_FFSM_EXT_ADDR5; addr <<= 8; addr |= RFCORE_FFSM_EXT_ADDR6; addr <<= 8; addr |= RFCORE_FFSM_EXT_ADDR7; return addr; } uint16_t cc2538_get_addr_short(void) { return (RFCORE_FFSM_SHORT_ADDR0 << 8) | RFCORE_FFSM_SHORT_ADDR1; } unsigned int cc2538_get_chan(void) { return IEEE802154_FREQ2CHAN(CC2538_MIN_FREQ + RFCORE_XREG_FREQCTRL); } uint64_t cc2538_get_eui64_primary(void) { /* * The primary EUI-64 seems to be written to memory in a non-sequential * byte order, with both 4-byte halves of the address flipped. */ uint64_t eui64 = ((uint8_t*)CC2538_EUI64_LOCATION_PRI)[4]; eui64 <<= 8; eui64 |= ((uint8_t*)CC2538_EUI64_LOCATION_PRI)[5]; eui64 <<= 8; eui64 |= ((uint8_t*)CC2538_EUI64_LOCATION_PRI)[6]; eui64 <<= 8; eui64 |= ((uint8_t*)CC2538_EUI64_LOCATION_PRI)[7]; eui64 <<= 8; eui64 |= ((uint8_t*)CC2538_EUI64_LOCATION_PRI)[0]; eui64 <<= 8; eui64 |= ((uint8_t*)CC2538_EUI64_LOCATION_PRI)[1]; eui64 <<= 8; eui64 |= ((uint8_t*)CC2538_EUI64_LOCATION_PRI)[2]; eui64 <<= 8; eui64 |= ((uint8_t*)CC2538_EUI64_LOCATION_PRI)[3]; return eui64; } bool cc2538_get_monitor(void) { return NOT(RFCORE->XREG_FRMFILT0bits.FRAME_FILTER_EN); } uint16_t cc2538_get_pan(void) { return (RFCORE_FFSM_PAN_ID1 << 8) | RFCORE_FFSM_PAN_ID0; } int cc2538_get_tx_power(void) { int index; int best_index = 0; int best_delta = INT_MAX; int txpower; txpower = RFCORE_XREG_TXPOWER & 0xff; for (index = 0; index < NUM_POWER_LEVELS; index++) { int delta = ABS_DIFF(power_lut[index], txpower); if (delta < best_delta) { best_delta = delta; best_index = index; } } return OUTPUT_POWER_MIN + best_index; } void cc2538_set_addr_long(uint64_t addr) { RFCORE_FFSM_EXT_ADDR0 = addr >> (7 * 8); RFCORE_FFSM_EXT_ADDR1 = addr >> (6 * 8); RFCORE_FFSM_EXT_ADDR2 = addr >> (5 * 8); RFCORE_FFSM_EXT_ADDR3 = addr >> (4 * 8); RFCORE_FFSM_EXT_ADDR4 = addr >> (3 * 8); RFCORE_FFSM_EXT_ADDR5 = addr >> (2 * 8); RFCORE_FFSM_EXT_ADDR6 = addr >> (1 * 8); RFCORE_FFSM_EXT_ADDR7 = addr >> (0 * 8); } void cc2538_set_addr_short(uint16_t addr) { RFCORE_FFSM_SHORT_ADDR1 = addr; RFCORE_FFSM_SHORT_ADDR0 = addr >> 8; } void cc2538_set_chan(unsigned int chan) { DEBUG("%s(%u): Setting channel to ", __FUNCTION__, chan); if (chan < IEEE802154_CHANNEL_MIN) { chan = IEEE802154_CHANNEL_MIN; } else if (chan > IEEE802154_CHANNEL_MAX) { chan = IEEE802154_CHANNEL_MAX; } DEBUG("%i (range %i-%i)\n", chan, IEEE802154_CHANNEL_MIN, IEEE802154_CHANNEL_MAX); cc2538_set_freq(IEEE802154_CHAN2FREQ(chan)); } void cc2538_set_freq(unsigned int MHz) { DEBUG("%s(%u): Setting frequency to ", __FUNCTION__, MHz); if (MHz < IEEE802154_MIN_FREQ) { MHz = IEEE802154_MIN_FREQ; } else if (MHz > IEEE802154_MAX_FREQ) { MHz = IEEE802154_MAX_FREQ; } DEBUG("%i (range %i-%i)\n", MHz, IEEE802154_MIN_FREQ, IEEE802154_MAX_FREQ); RFCORE_XREG_FREQCTRL = MHz - CC2538_MIN_FREQ; } void cc2538_set_monitor(bool mode) { RFCORE->XREG_FRMFILT0bits.FRAME_FILTER_EN = NOT(mode); } void cc2538_set_state(cc2538_rf_t *dev, netopt_state_t state) { switch (state) { case NETOPT_STATE_OFF: case NETOPT_STATE_SLEEP: cc2538_off(); dev->state = state; break; case NETOPT_STATE_RX: case NETOPT_STATE_IDLE: if (!cc2538_is_on()) { cc2538_on(); RFCORE_WAIT_UNTIL(RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE > FSM_STATE_RX_CALIBRATION); } dev->state = state; break; case NETOPT_STATE_TX: dev->state = NETOPT_STATE_IDLE; break; case NETOPT_STATE_RESET: cc2538_off(); cc2538_on(); RFCORE_WAIT_UNTIL(RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE > FSM_STATE_RX_CALIBRATION); dev->state = NETOPT_STATE_IDLE; break; } } void cc2538_set_pan(uint16_t pan) { RFCORE_FFSM_PAN_ID0 = pan; RFCORE_FFSM_PAN_ID1 = pan >> 8; } void cc2538_set_tx_power(int dBm) { DEBUG("%s(%i): Setting TX power to ", __FUNCTION__, dBm); if (dBm < OUTPUT_POWER_MIN) { dBm = OUTPUT_POWER_MIN; } else if (dBm > OUTPUT_POWER_MAX) { dBm = OUTPUT_POWER_MAX; } DEBUG("%idBm (range %i-%i dBm)\n", dBm, OUTPUT_POWER_MIN, OUTPUT_POWER_MAX); RFCORE_XREG_TXPOWER = power_lut[dBm - OUTPUT_POWER_MIN]; }