Implement extended RF API for the CC2538
This commit is contained in:
parent
132b8dde3b
commit
0ec1eda75e
2 changed files with 297 additions and 75 deletions
|
@ -126,10 +126,39 @@ static uint8_t rf_flags;
|
|||
static int on(void);
|
||||
static int off(void);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* TX Power dBm lookup table. Values from SmartRF Studio v1.16.0 */
|
||||
typedef struct output_config {
|
||||
radio_value_t power;
|
||||
uint8_t txpower_val;
|
||||
} output_config_t;
|
||||
|
||||
static const output_config_t output_power[] = {
|
||||
{ 7, 0xFF },
|
||||
{ 5, 0xED },
|
||||
{ 3, 0xD5 },
|
||||
{ 1, 0xC5 },
|
||||
{ 0, 0xB6 },
|
||||
{ -1, 0xB0 },
|
||||
{ -3, 0xA1 },
|
||||
{ -5, 0x91 },
|
||||
{ -7, 0x88 },
|
||||
{ -9, 0x72 },
|
||||
{-11, 0x62 },
|
||||
{-13, 0x58 },
|
||||
{-15, 0x42 },
|
||||
{-24, 0x00 },
|
||||
};
|
||||
|
||||
#define OUTPUT_CONFIG_COUNT (sizeof(output_power) / sizeof(output_config_t))
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(cc2538_rf_process, "cc2538 RF driver");
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
cc2538_rf_channel_get()
|
||||
/**
|
||||
* \brief Get the current operating channel
|
||||
* \return Returns a value in [11,26] representing the current channel
|
||||
*/
|
||||
static uint8_t
|
||||
get_channel()
|
||||
{
|
||||
uint8_t chan = REG(RFCORE_XREG_FREQCTRL) & RFCORE_XREG_FREQCTRL_FREQ;
|
||||
|
||||
|
@ -137,13 +166,19 @@ cc2538_rf_channel_get()
|
|||
+ CC2538_RF_CHANNEL_MIN);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int8_t
|
||||
cc2538_rf_channel_set(uint8_t channel)
|
||||
/**
|
||||
* \brief Set the current operating channel
|
||||
* \param channel The desired channel as a value in [11,26]
|
||||
* \return Returns a value in [11,26] representing the current channel
|
||||
* or a negative value if \e channel was out of bounds
|
||||
*/
|
||||
static int8_t
|
||||
set_channel(uint8_t channel)
|
||||
{
|
||||
PRINTF("RF: Set Channel\n");
|
||||
|
||||
if((channel < CC2538_RF_CHANNEL_MIN) || (channel > CC2538_RF_CHANNEL_MAX)) {
|
||||
return -1;
|
||||
return CC2538_RF_CHANNEL_SET_ERROR;
|
||||
}
|
||||
|
||||
/* Changes to FREQCTRL take effect after the next recalibration */
|
||||
|
@ -155,41 +190,43 @@ cc2538_rf_channel_set(uint8_t channel)
|
|||
return (int8_t) channel;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
cc2538_rf_power_set(uint8_t new_power)
|
||||
static radio_value_t
|
||||
get_pan_id(void)
|
||||
{
|
||||
PRINTF("RF: Set Power\n");
|
||||
|
||||
REG(RFCORE_XREG_TXPOWER) = new_power;
|
||||
|
||||
return (REG(RFCORE_XREG_TXPOWER) & 0xFF);
|
||||
return (radio_value_t)(REG(RFCORE_FFSM_PAN_ID1) << 8 | REG(RFCORE_FFSM_PAN_ID0));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* ToDo: Check once we have info on the... infopage */
|
||||
void
|
||||
cc2538_rf_set_addr(uint16_t pan)
|
||||
static void
|
||||
set_pan_id(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)
|
||||
static radio_value_t
|
||||
get_short_addr(void)
|
||||
{
|
||||
int rssi;
|
||||
return (radio_value_t)(REG(RFCORE_FFSM_SHORT_ADDR1) << 8 | REG(RFCORE_FFSM_SHORT_ADDR0));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
set_short_addr(uint16_t addr)
|
||||
{
|
||||
REG(RFCORE_FFSM_SHORT_ADDR0) = addr & 0xFF;
|
||||
REG(RFCORE_FFSM_SHORT_ADDR1) = addr >> 8;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Reads the current signal strength (RSSI)
|
||||
* \return The current RSSI in dBm
|
||||
*
|
||||
* This function reads the current RSSI on the currently configured
|
||||
* channel.
|
||||
*/
|
||||
static radio_value_t
|
||||
get_rssi(void)
|
||||
{
|
||||
int8_t rssi;
|
||||
|
||||
/* If we are off, turn on first */
|
||||
if((REG(RFCORE_XREG_FSMSTAT0) & RFCORE_XREG_FSMSTAT0_FSM_FFCTRL_STATE) == 0) {
|
||||
|
@ -200,7 +237,7 @@ cc2538_rf_read_rssi(void)
|
|||
/* Wait on RSSI_VALID */
|
||||
while((REG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0);
|
||||
|
||||
rssi = ((int8_t)REG(RFCORE_XREG_RSSI)) - RSSI_OFFSET;
|
||||
rssi = (int8_t)(REG(RFCORE_XREG_RSSI) & RFCORE_XREG_RSSI_RSSI_VAL) - RSSI_OFFSET;
|
||||
|
||||
/* If we were off, turn back off */
|
||||
if((rf_flags & WAS_OFF) == WAS_OFF) {
|
||||
|
@ -211,6 +248,80 @@ cc2538_rf_read_rssi(void)
|
|||
return rssi;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Returns the current CCA threshold in dBm */
|
||||
static radio_value_t
|
||||
get_cca_threshold(void)
|
||||
{
|
||||
return (int8_t)(REG(RFCORE_XREG_CCACTRL0) & RFCORE_XREG_CCACTRL0_CCA_THR) - RSSI_OFFSET;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Sets the CCA threshold in dBm */
|
||||
static void
|
||||
set_cca_threshold(radio_value_t value)
|
||||
{
|
||||
REG(RFCORE_XREG_CCACTRL0) = (value & 0xFF) + RSSI_OFFSET;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Returns the current TX power in dBm */
|
||||
static radio_value_t
|
||||
get_tx_power(void)
|
||||
{
|
||||
int i;
|
||||
uint8_t reg_val = REG(RFCORE_XREG_TXPOWER) & 0xFF;
|
||||
|
||||
/*
|
||||
* Find the TXPOWER value in the lookup table
|
||||
* If the value has been written with set_tx_power, we should be able to
|
||||
* find the exact value. However, in case the register has been written in
|
||||
* a different fashion, we return the immediately lower value of the lookup
|
||||
*/
|
||||
for(i = 0; i < OUTPUT_CONFIG_COUNT; i++) {
|
||||
if(reg_val >= output_power[i].txpower_val) {
|
||||
return output_power[i].power;
|
||||
}
|
||||
}
|
||||
return CC2538_RF_TX_POWER_MIN;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Set TX power to 'at least' power dBm
|
||||
* This works with a lookup table. If the value of 'power' does not exist in
|
||||
* the lookup table, TXPOWER will be set to the immediately higher available
|
||||
* value
|
||||
*/
|
||||
static void
|
||||
set_tx_power(radio_value_t power)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = OUTPUT_CONFIG_COUNT - 1; i >= 0; --i) {
|
||||
if(power <= output_power[i].power) {
|
||||
REG(RFCORE_XREG_TXPOWER) = output_power[i].txpower_val;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
set_frame_filtering(uint8_t enable)
|
||||
{
|
||||
if(enable) {
|
||||
REG(RFCORE_XREG_FRMFILT0) |= RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN;
|
||||
} else {
|
||||
REG(RFCORE_XREG_FRMFILT0) &= ~RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
set_auto_ack(uint8_t enable)
|
||||
{
|
||||
if(enable) {
|
||||
REG(RFCORE_XREG_FRMCTRL0) |= RFCORE_XREG_FRMCTRL0_AUTOACK;
|
||||
} else {
|
||||
REG(RFCORE_XREG_FRMCTRL0) &= ~RFCORE_XREG_FRMCTRL0_AUTOACK;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Netstack API radio driver functions */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
|
@ -327,8 +438,10 @@ init(void)
|
|||
/* 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);
|
||||
/* Set TX Power */
|
||||
REG(RFCORE_XREG_TXPOWER) = CC2538_RF_TX_POWER;
|
||||
|
||||
set_channel(CC2538_RF_CHANNEL);
|
||||
|
||||
/* Acknowledge RF interrupts, FIFOP only */
|
||||
REG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_FIFOP;
|
||||
|
@ -641,24 +754,150 @@ pending_packet(void)
|
|||
static radio_result_t
|
||||
get_value(radio_param_t param, radio_value_t *value)
|
||||
{
|
||||
if(!value) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
|
||||
switch(param) {
|
||||
case RADIO_PARAM_POWER_MODE:
|
||||
*value = (REG(RFCORE_XREG_RXENABLE) && RFCORE_XREG_RXENABLE_RXENMASK) == 0
|
||||
? RADIO_POWER_MODE_OFF : RADIO_POWER_MODE_ON;
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_CHANNEL:
|
||||
*value = (radio_value_t)get_channel();
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_PAN_ID:
|
||||
*value = get_pan_id();
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_16BIT_ADDR:
|
||||
*value = get_short_addr();
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_RX_MODE:
|
||||
*value = 0;
|
||||
if(REG(RFCORE_XREG_FRMFILT0) & RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN) {
|
||||
*value |= RADIO_RX_MODE_ADDRESS_FILTER;
|
||||
}
|
||||
if(REG(RFCORE_XREG_FRMCTRL0) & RFCORE_XREG_FRMCTRL0_AUTOACK) {
|
||||
*value |= RADIO_RX_MODE_AUTOACK;
|
||||
}
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_TXPOWER:
|
||||
*value = get_tx_power();
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_CCA_THRESHOLD:
|
||||
*value = get_cca_threshold();
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_RSSI:
|
||||
*value = get_rssi();
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_CONST_CHANNEL_MIN:
|
||||
*value = CC2538_RF_CHANNEL_MIN;
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_CONST_CHANNEL_MAX:
|
||||
*value = CC2538_RF_CHANNEL_MAX;
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_CONST_TXPOWER_MIN:
|
||||
*value = CC2538_RF_TX_POWER_MIN;
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_CONST_TXPOWER_MAX:
|
||||
*value = CC2538_RF_TX_POWER_MAX;
|
||||
return RADIO_RESULT_OK;
|
||||
default:
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static radio_result_t
|
||||
set_value(radio_param_t param, radio_value_t value)
|
||||
{
|
||||
switch(param) {
|
||||
case RADIO_PARAM_POWER_MODE:
|
||||
if(value == RADIO_POWER_MODE_ON) {
|
||||
on();
|
||||
return RADIO_RESULT_OK;
|
||||
}
|
||||
if(value == RADIO_POWER_MODE_OFF) {
|
||||
off();
|
||||
return RADIO_RESULT_OK;
|
||||
}
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
case RADIO_PARAM_CHANNEL:
|
||||
if(value < CC2538_RF_CHANNEL_MIN ||
|
||||
value > CC2538_RF_CHANNEL_MAX) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
if(set_channel(value) == CC2538_RF_CHANNEL_SET_ERROR) {
|
||||
return RADIO_RESULT_ERROR;
|
||||
}
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_PAN_ID:
|
||||
set_pan_id(value & 0xffff);
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_16BIT_ADDR:
|
||||
set_short_addr(value & 0xffff);
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_RX_MODE:
|
||||
if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
|
||||
RADIO_RX_MODE_AUTOACK)) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
|
||||
set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0);
|
||||
set_auto_ack((value & RADIO_RX_MODE_AUTOACK) != 0);
|
||||
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_TXPOWER:
|
||||
if(value < CC2538_RF_TX_POWER_MIN || value > CC2538_RF_TX_POWER_MAX) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
|
||||
set_tx_power(value);
|
||||
return RADIO_RESULT_OK;
|
||||
case RADIO_PARAM_CCA_THRESHOLD:
|
||||
set_cca_threshold(value);
|
||||
return RADIO_RESULT_OK;
|
||||
default:
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static radio_result_t
|
||||
get_object(radio_param_t param, void *dest, size_t size)
|
||||
{
|
||||
uint8_t *target;
|
||||
int i;
|
||||
|
||||
if(param == RADIO_PARAM_64BIT_ADDR) {
|
||||
if(size < 8 || !dest || LINKADDR_SIZE != 8) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
|
||||
target = dest;
|
||||
for(i = 0; i < size; i++) {
|
||||
target[size - 1 - i] = ((uint32_t *)RFCORE_FFSM_EXT_ADDR0)[i] & 0xFF;
|
||||
}
|
||||
|
||||
return RADIO_RESULT_OK;
|
||||
}
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static radio_result_t
|
||||
set_object(radio_param_t param, const void *src, size_t size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(param == RADIO_PARAM_64BIT_ADDR) {
|
||||
if(size < 8 || !src || LINKADDR_SIZE != 8) {
|
||||
return RADIO_RESULT_INVALID_VALUE;
|
||||
}
|
||||
|
||||
for(i = 0; i < size; i++) {
|
||||
((uint32_t *)RFCORE_FFSM_EXT_ADDR0)[i] = ((uint8_t *)src)[size - 1 - i];
|
||||
}
|
||||
|
||||
return RADIO_RESULT_OK;
|
||||
}
|
||||
return RADIO_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -776,11 +1015,26 @@ cc2538_rf_err_isr(void)
|
|||
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;
|
||||
set_frame_filtering(p);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
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
|
||||
|
||||
set_pan_id(pan);
|
||||
|
||||
REG(RFCORE_FFSM_SHORT_ADDR0) = linkaddr_node_addr.u8[LINKADDR_SIZE - 1];
|
||||
REG(RFCORE_FFSM_SHORT_ADDR1) = linkaddr_node_addr.u8[LINKADDR_SIZE - 2];
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
||||
|
|
|
@ -56,10 +56,13 @@
|
|||
#define CC2538_RF_CHANNEL_MIN 11
|
||||
#define CC2538_RF_CHANNEL_MAX 26
|
||||
#define CC2538_RF_CHANNEL_SPACING 5
|
||||
#define CC2538_RF_CHANNEL_SET_ERROR -1
|
||||
#define CC2538_RF_MAX_PACKET_LEN 127
|
||||
#define CC2538_RF_MIN_PACKET_LEN 4
|
||||
#define CC2538_RF_CCA_CLEAR 1
|
||||
#define CC2538_RF_CCA_BUSY 0
|
||||
#define CC2538_RF_TX_POWER_MIN -24
|
||||
#define CC2538_RF_TX_POWER_MAX 7
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifdef CC2538_RF_CONF_TX_POWER
|
||||
#define CC2538_RF_TX_POWER CC2538_RF_CONF_TX_POWER
|
||||
|
@ -132,31 +135,6 @@
|
|||
/** The NETSTACK data structure for the cc2538 RF driver */
|
||||
extern const struct radio_driver cc2538_rf_driver;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Set the current operating channel
|
||||
* \param channel The desired channel as a value in [11,26]
|
||||
* \return Returns a value in [11,26] representing the current channel
|
||||
* or a negative value if \e channel was out of bounds
|
||||
*/
|
||||
int8_t cc2538_rf_channel_set(uint8_t channel);
|
||||
|
||||
/**
|
||||
* \brief Get the current operating channel
|
||||
* \return Returns a value in [11,26] representing the current channel
|
||||
*/
|
||||
uint8_t cc2538_rf_channel_get(void);
|
||||
|
||||
/**
|
||||
* \brief Sets RF TX power
|
||||
* \param new_power The desired power level
|
||||
* \return The power level in use after the adjustment
|
||||
*
|
||||
* The value specified in \e new_power will be written directly to the
|
||||
* RFCORE_XREG_TXPOWER register. See the datasheet for more details on
|
||||
* possible values.
|
||||
*/
|
||||
uint8_t cc2538_rf_power_set(uint8_t new_power);
|
||||
|
||||
/**
|
||||
* \brief Sets addresses and PAN identifier to the relevant RF hardware
|
||||
* registers
|
||||
|
@ -168,15 +146,6 @@ uint8_t cc2538_rf_power_set(uint8_t new_power);
|
|||
*/
|
||||
void cc2538_rf_set_addr(uint16_t pan);
|
||||
|
||||
/**
|
||||
* \brief Reads the current signal strength (RSSI)
|
||||
* \return The current RSSI
|
||||
*
|
||||
* This function reads the current RSSI on the currently configured
|
||||
* channel.
|
||||
*/
|
||||
int cc2538_rf_read_rssi(void);
|
||||
|
||||
/**
|
||||
* \brief Turn promiscous mode on or off
|
||||
* \param p If promiscous mode should be on (1) or off (0)
|
||||
|
@ -187,7 +156,6 @@ int cc2538_rf_read_rssi(void);
|
|||
* address as the receive address are returned from the RF core.
|
||||
*/
|
||||
void cc2538_rf_set_promiscous_mode(char p);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* CC2538_RF_H__ */
|
||||
|
||||
|
|
Loading…
Reference in a new issue