Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
380 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,367 @@ | ||
#include <errno.h> | ||
#include <stdio.h> | ||
|
||
#include "net/gnrc.h" | ||
|
||
#include "cc2538_rf.h" | ||
#include "cc2538_rf_internal.h" | ||
|
||
#include "net/ieee802154/radio.h" | ||
|
||
#if IS_USED(MODULE_IEEE802154_RADIO_HAL) | ||
static const ieee802154_radio_ops_t cc2538_rf_ops; | ||
|
||
ieee802154_dev_t cc2538_rf_dev = { | ||
.driver = &cc2538_rf_ops, | ||
}; | ||
|
||
static int _write(ieee802154_dev_t *dev, iolist_t *iolist) | ||
{ | ||
(void) dev; | ||
int pkt_len = 0; | ||
RFCORE_SFR_RFST = ISFLUSHTX; | ||
rfcore_write_byte(0); | ||
|
||
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) { | ||
if (iol->iol_len) { | ||
pkt_len += iol->iol_len; | ||
rfcore_write_fifo(iol->iol_base, iol->iol_len); | ||
} | ||
} | ||
|
||
/* Set first byte of TX FIFO to the packet length */ | ||
rfcore_poke_tx_fifo(0, pkt_len + CC2538_AUTOCRC_LEN); | ||
return 0; | ||
} | ||
|
||
static int _confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info) | ||
{ | ||
(void) dev; | ||
(void) info; | ||
if (RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE != 0) { | ||
return -EAGAIN; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int _request_transmit(ieee802154_dev_t *dev, uint8_t flags) | ||
{ | ||
(void) dev; | ||
if (flags & TX_MODE_AUTO) { | ||
return -ENOTSUP; | ||
} | ||
|
||
if (flags & TX_MODE_TXRX) { | ||
RFCORE_SFR_RFST = ISRXMASKBITSET; | ||
} | ||
else { | ||
RFCORE_SFR_RFST = ISRXMASKBITCLR; | ||
} | ||
|
||
RFCORE_SFR_RFST = ISTXON; | ||
return 0; | ||
} | ||
|
||
static int _len(ieee802154_dev_t *dev) | ||
{ | ||
(void) dev; | ||
return rfcore_peek_rx_fifo(0); | ||
} | ||
|
||
static int _indication_rx(ieee802154_dev_t *dev, void *buf, size_t size, ieee802154_rx_info_t *info) | ||
{ | ||
(void) dev; | ||
int res; | ||
size_t pkt_len = rfcore_read_byte(); | ||
|
||
pkt_len -= IEEE802154_FCS_LEN; | ||
|
||
if (pkt_len > size) { | ||
RFCORE_SFR_RFST = ISFLUSHRX; | ||
return -ENOBUFS; | ||
} | ||
|
||
if (buf != NULL) { | ||
rfcore_read_fifo(buf, pkt_len); | ||
res = pkt_len; | ||
if (info != NULL) { | ||
uint8_t corr_val; | ||
int8_t rssi_val; | ||
rssi_val = rfcore_read_byte() + CC2538_RSSI_OFFSET; | ||
|
||
RFCORE_ASSERT(rssi_val > CC2538_RF_SENSITIVITY); | ||
|
||
/* The number of dB above maximum sensitivity detected for the | ||
* received packet */ | ||
info->rssi = -CC2538_RF_SENSITIVITY + rssi_val; | ||
|
||
corr_val = rfcore_read_byte() & CC2538_CORR_VAL_MASK; | ||
|
||
if (corr_val < CC2538_CORR_VAL_MIN) { | ||
corr_val = CC2538_CORR_VAL_MIN; | ||
} | ||
else if (corr_val > CC2538_CORR_VAL_MAX) { | ||
corr_val = CC2538_CORR_VAL_MAX; | ||
} | ||
|
||
/* Interpolate the correlation value between 0 - 255 | ||
* to provide an LQI value */ | ||
info->lqi = 255 * (corr_val - CC2538_CORR_VAL_MIN) / | ||
(CC2538_CORR_VAL_MAX - CC2538_CORR_VAL_MIN); | ||
} | ||
} | ||
else { | ||
res = 0; | ||
} | ||
|
||
RFCORE_SFR_RFST = ISFLUSHRX; | ||
|
||
return res; | ||
} | ||
|
||
static int _confirm_cca(ieee802154_dev_t *dev) | ||
{ | ||
(void) dev; | ||
/* We use the register Z to indicate there's a pending CCA */ | ||
if (RFCORE_XREG_CSPZ) { | ||
return -EAGAIN; | ||
} | ||
|
||
return RFCORE_XREG_CSPX; | ||
} | ||
|
||
static int _request_cca(ieee802154_dev_t *dev) | ||
{ | ||
(void) dev; | ||
/* Ignore baseband processing */ | ||
RFCORE_XREG_RFIRQM0 &= ~RXPKTDONE; | ||
|
||
/* Clear last program */ | ||
RFCORE_SFR_RFST = ISCLEAR; | ||
|
||
/* CCA requires RX-ON */ | ||
RFCORE_SFR_RFST = ISRXON; | ||
|
||
/* If the RSSI is not yet valid, busy loop */ | ||
RFCORE_SFR_RFST = SKIP_S_C | | ||
CC2538_CSP_SKIP_N_MASK | | ||
CC2538_CSP_SKIP_COND_RSSI; | ||
|
||
/* If CCA is not valid, skip the next instruction */ | ||
RFCORE_SFR_RFST = SKIP_S_C | | ||
(1<<CC2538_CSP_SKIP_INST_POS) | | ||
CC2538_CSP_SKIP_COND_CCA; | ||
|
||
/* If the strobe processor execute this function, | ||
* it means the CCA was valid. We use the | ||
* register X to indicate so */ | ||
RFCORE_SFR_RFST = INCX; | ||
|
||
/* Decrement the register Z (used to indicate | ||
* there's a pending CCA request */ | ||
RFCORE_SFR_RFST = DECZ; | ||
|
||
/* Stop the program */ | ||
RFCORE_SFR_RFST = STOP; | ||
|
||
RFCORE_XREG_CSPX = 0; | ||
RFCORE_XREG_CSPZ = 1; | ||
|
||
/* Execute the last program */ | ||
RFCORE_SFR_RFST = ISSTART; | ||
return 0; | ||
} | ||
|
||
static int _set_cca_threshold(ieee802154_dev_t *dev, int8_t threshold) | ||
{ | ||
(void) dev; | ||
(void) threshold; | ||
|
||
if (threshold < CC2538_RF_SENSITIVITY) { | ||
return -EINVAL; | ||
} | ||
|
||
|
||
RFCORE_XREG_CCACTRL0 &= ~CC2538_CCA_THR_MASK; | ||
RFCORE_XREG_CCACTRL0 |= (threshold - CC2538_RSSI_OFFSET) & CC2538_CCA_THR_MASK; | ||
|
||
return 0; | ||
} | ||
|
||
static int _config_phy(ieee802154_dev_t *dev, ieee802154_phy_conf_t *conf) | ||
{ | ||
(void) dev; | ||
cc2538_set_freq(IEEE802154_CHAN2FREQ(conf->channel)); | ||
cc2538_set_tx_power(conf->pow); | ||
|
||
return 0; | ||
} | ||
|
||
static int _confirm_set_trx_state(ieee802154_dev_t *dev) | ||
{ | ||
(void) dev; | ||
if (RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE == FSM_STATE_RX_CALIBRATION) { | ||
return -EAGAIN; | ||
} | ||
return 0; | ||
} | ||
|
||
static int _request_set_trx_state(ieee802154_dev_t *dev, ieee802154_trx_state_t state) | ||
{ | ||
|
||
(void) dev; | ||
bool wait_sfd = RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE > 0x2 && RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE < 0x7; | ||
if ((RFCORE->XREG_FSMSTAT1bits.RX_ACTIVE && !wait_sfd) || | ||
RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE) { | ||
return -EBUSY; | ||
} | ||
|
||
switch(state) { | ||
case IEEE802154_TRX_STATE_TRX_OFF: | ||
case IEEE802154_TRX_STATE_TX_ON: | ||
if (RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE != FSM_STATE_IDLE) { | ||
RFCORE_SFR_RFST = ISRFOFF; | ||
} | ||
break; | ||
case IEEE802154_TRX_STATE_RX_ON: | ||
RFCORE_XREG_RFIRQM0 |= RXPKTDONE; | ||
RFCORE_SFR_RFST = ISRXON; | ||
break; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
void _irq_handler(void) | ||
{ | ||
uint_fast8_t flags_f0 = RFCORE_SFR_RFIRQF0; | ||
uint_fast8_t flags_f1 = RFCORE_SFR_RFIRQF1; | ||
|
||
RFCORE_SFR_RFIRQF0 = 0; | ||
RFCORE_SFR_RFIRQF1 = 0; | ||
|
||
if (flags_f1 & TXDONE) { | ||
cc2538_rf_dev.cb(&cc2538_rf_dev, IEEE802154_RADIO_CONFIRM_TX_DONE); | ||
} | ||
|
||
if (flags_f0 & RXPKTDONE) { | ||
/* CRC check */ | ||
uint8_t pkt_len = rfcore_peek_rx_fifo(0); | ||
if (rfcore_peek_rx_fifo(pkt_len) & CC2538_CRC_BIT_MASK) { | ||
cc2538_rf_dev.cb(&cc2538_rf_dev, IEEE802154_RADIO_INDICATION_RX_DONE); | ||
} | ||
else { | ||
/* CRC failed; discard packet */ | ||
RFCORE_SFR_RFST = ISFLUSHRX; | ||
} | ||
|
||
} | ||
|
||
if (flags_f1 & CSP_STOP) { | ||
cc2538_rf_dev.cb(&cc2538_rf_dev, IEEE802154_RADIO_CONFIRM_CCA); | ||
} | ||
} | ||
|
||
static int _off(ieee802154_dev_t *dev) | ||
{ | ||
(void) dev; | ||
return -ENOTSUP; | ||
} | ||
|
||
static bool _get_cap(ieee802154_dev_t *dev, ieee802154_rf_caps_t cap) | ||
{ | ||
(void) dev; | ||
switch(cap) { | ||
case IEEE802154_CAP_AUTO_ACK: | ||
case IEEE802154_CAP_24_GHZ: | ||
case IEEE802154_CAP_TXRX: | ||
case IEEE802154_CAP_IRQ_TX_DONE: | ||
case IEEE802154_CAP_IRQ_CCA_DONE: | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
static int _set_hw_addr_filter(ieee802154_dev_t *dev, uint8_t *short_addr, uint8_t *ext_addr, uint16_t pan_id) | ||
{ | ||
(void) dev; | ||
RFCORE_FFSM_SHORT_ADDR0 = short_addr[1]; | ||
RFCORE_FFSM_SHORT_ADDR1 = short_addr[0]; | ||
|
||
RFCORE_FFSM_EXT_ADDR0 = ext_addr[7]; | ||
RFCORE_FFSM_EXT_ADDR1 = ext_addr[6]; | ||
RFCORE_FFSM_EXT_ADDR2 = ext_addr[5]; | ||
RFCORE_FFSM_EXT_ADDR3 = ext_addr[4]; | ||
RFCORE_FFSM_EXT_ADDR4 = ext_addr[3]; | ||
RFCORE_FFSM_EXT_ADDR5 = ext_addr[2]; | ||
RFCORE_FFSM_EXT_ADDR6 = ext_addr[1]; | ||
RFCORE_FFSM_EXT_ADDR7 = ext_addr[0]; | ||
|
||
RFCORE_FFSM_PAN_ID0 = pan_id; | ||
RFCORE_FFSM_PAN_ID1 = pan_id >> 8; | ||
return 0; | ||
} | ||
|
||
static int _set_promiscuous(ieee802154_dev_t *dev, bool enable) | ||
{ | ||
(void) dev; | ||
cc2538_set_monitor(enable); | ||
return 0; | ||
} | ||
|
||
static int _confirm_on(ieee802154_dev_t *dev) | ||
{ | ||
(void) dev; | ||
/* TODO */ | ||
return 0; | ||
} | ||
|
||
static int _request_on(ieee802154_dev_t *dev) | ||
{ | ||
(void) dev; | ||
/* TODO */ | ||
return 0; | ||
} | ||
|
||
static int _set_cca_mode(ieee802154_dev_t *dev, ieee802154_cca_mode_t mode) | ||
{ | ||
(void) dev; | ||
(void) mode; | ||
/* TODO */ | ||
return 0; | ||
} | ||
|
||
static int _set_aack(ieee802154_dev_t *dev, ieee802154_aack_conf_t conf) | ||
{ | ||
(void) dev; | ||
(void) conf; | ||
/* TODO */ | ||
return 0; | ||
} | ||
|
||
static const ieee802154_radio_ops_t cc2538_rf_ops = { | ||
.write = _write, | ||
.request_transmit = _request_transmit, | ||
.confirm_transmit = _confirm_transmit, | ||
.len = _len, | ||
.indication_rx = _indication_rx, | ||
.off = _off, | ||
.request_on = _request_on, | ||
.confirm_on = _confirm_on, | ||
.request_set_trx_state = _request_set_trx_state, | ||
.confirm_set_trx_state = _confirm_set_trx_state, | ||
.request_cca = _request_cca, | ||
.confirm_cca = _confirm_cca, | ||
.get_cap = _get_cap, | ||
.set_cca_threshold = _set_cca_threshold, | ||
.set_cca_mode = _set_cca_mode, | ||
.config_phy = _config_phy, | ||
.set_promiscuous = _set_promiscuous, | ||
.set_hw_addr_filter = _set_hw_addr_filter, | ||
.set_aack = _set_aack | ||
}; | ||
#else | ||
int dont_be_pedantic; | ||
#endif |