Merge pull request #14791 from jia200x/pr/cc2538_radio_hal
cc2538_rf: implement Radio HAL
This commit is contained in:
commit
6fcf60c0b0
@ -68,9 +68,41 @@ extern "C" {
|
||||
|
||||
#define CC2538_CRC_BIT_MASK (0x80)
|
||||
|
||||
#define CC2538_CCA_THR_MASK (0x000000FF) /**< CCA Threshold mask */
|
||||
|
||||
#define CC2538_CCA_MODE_MASK (0x18) /**< CCA Mode mask */
|
||||
#define CC2538_CCA_MODE_POS (3U) /**< CCA Mode pos */
|
||||
|
||||
#define CC2538_CSP_SKIP_INST_MASK (0x70) /**< CSP Skip instruction mask */
|
||||
#define CC2538_CSP_SKIP_INST_POS (4U) /**< CSP Skip instruction pos */
|
||||
|
||||
#define CC2538_CSP_SKIP_N_MASK (0x08) /**< CSP Skip condition negation mask */
|
||||
|
||||
#define CC2538_CSP_SKIP_COND_CCA (0x00) /**< CSP Skip condition is valid CCA */
|
||||
#define CC2538_CSP_SKIP_COND_CSPZ (0x06) /**< CSP Skip condition is CSPZ is 0 */
|
||||
#define CC2538_CSP_SKIP_COND_RSSI (0x07) /**< CSP Skip condition is valid RSSI */
|
||||
|
||||
#define CC2538_SFR_MTMSEL_MASK (0x7) /**< MAC Timer selection mask */
|
||||
#define CC2538_SFR_MTMSEL_TIMER_P (0x2) /**< Selects Timer period */
|
||||
#define CC2538_MCTRL_SYNC_MASK (0x2) /**< Sync MAC Timer to external clock */
|
||||
#define CC2538_MCTRL_RUN_MASK (0x1) /**< Run MAC Timer */
|
||||
|
||||
#define CC2538_CSP_MCU_CTRL_MASK (0x1) /**< MCU Ctrl mask */
|
||||
|
||||
#define CC2538_CSP_INCMAXY_MAX_MASK (0x7) /**< CSP INCMAXY instruction (increment Register CSPX
|
||||
without exceeding CSPY) */
|
||||
|
||||
#define CC2538_RXENABLE_RXON_MASK (0x80) /**< RX on mask */
|
||||
|
||||
#define CC2538_RSSI_OFFSET (-73) /**< Signal strength offset value */
|
||||
#define CC2538_RF_SENSITIVITY (-97) /**< dBm typical, normal conditions */
|
||||
|
||||
#define CC2538_ACCEPT_FT_2_ACK (1 << 5) /**< enable or disable the ACK filter */
|
||||
#define CC2538_STATE_SFD_WAIT_RANGE_MIN (0x03U) /**< min range value of SFD wait state */
|
||||
#define CC2538_STATE_SFD_WAIT_RANGE_MAX (0x06U) /**< max range value of SFD wait state */
|
||||
#define CC2538_FRMCTRL1_PENDING_OR_MASK (0x04) /**< mask for enabling or disabling the
|
||||
frame pending bit */
|
||||
|
||||
#define RFCORE_ASSERT(expr) (void)( (expr) || RFCORE_ASSERT_failure(#expr, __FUNCTION__, __LINE__) )
|
||||
|
||||
#if DEVELHELP
|
||||
@ -134,6 +166,18 @@ enum {
|
||||
RXMASKZERO = BIT(7),
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief RFCORE_XREG_RFIRQM1 / RFCORE_XREG_RFIRQF1 bits
|
||||
*/
|
||||
enum {
|
||||
TXACKDONE = BIT(0),
|
||||
TXDONE = BIT(1),
|
||||
RF_IDLE = BIT(2),
|
||||
CSP_MANINT = BIT(3),
|
||||
CSP_STOP = BIT(4),
|
||||
CSP_WAIT = BIT(5),
|
||||
};
|
||||
|
||||
/* Values for use with CCTEST_OBSSELx registers: */
|
||||
#define OBSSEL_EN BIT(7)
|
||||
enum {
|
||||
|
||||
@ -28,7 +28,15 @@
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#define CC2538_ACCEPT_FT_2_ACK (1 << 5)
|
||||
/*
|
||||
* @brief MAC timer period
|
||||
*
|
||||
* The period is set to the CSMA-CA Backoff Period Unit (20 symbols, 320 us).
|
||||
* The system clock runs at 32 MHz. Thus, the timeout period is
|
||||
* 320us * 32MHz = ~10738 (0x29F2)
|
||||
*/
|
||||
#define TIMER_PERIOD_LSB (0xF2)
|
||||
#define TIMER_PERIOD_MSB (0x29)
|
||||
|
||||
typedef struct {
|
||||
cc2538_reg_t *reg_addr;
|
||||
@ -58,6 +66,9 @@ static const init_pair_t init_table[] = {
|
||||
{&RFCORE_XREG_SRCMATCH, 0x00 },
|
||||
{&RFCORE_XREG_FIFOPCTRL, CC2538_RF_MAX_DATA_LEN },
|
||||
{&RFCORE_XREG_RFIRQM0, FIFOP | RXPKTDONE },
|
||||
#if IS_USED(MODULE_IEEE802154_RADIO_HAL)
|
||||
{&RFCORE_XREG_RFIRQM1, TXDONE | CSP_STOP },
|
||||
#endif
|
||||
{&RFCORE_XREG_RFERRM, STROBE_ERR | TXUNDERF | TXOVERF | RXUNDERF | RXOVERF | NLOCK},
|
||||
{NULL, 0},
|
||||
};
|
||||
@ -86,10 +97,6 @@ void cc2538_init(void)
|
||||
*pair->reg_addr = pair->value;
|
||||
}
|
||||
|
||||
cc2538_set_tx_power(CC2538_RF_POWER_DEFAULT);
|
||||
cc2538_set_chan(CC2538_RF_CHANNEL_DEFAULT);
|
||||
cc2538_set_addr_long(cc2538_get_eui64_primary());
|
||||
|
||||
/* Select the observable signals (maximum of three) */
|
||||
RFCORE_XREG_RFC_OBS_CTRL0 = tx_active;
|
||||
RFCORE_XREG_RFC_OBS_CTRL1 = rx_active;
|
||||
@ -123,6 +130,9 @@ void cc2538_init(void)
|
||||
|
||||
NVIC_SetPriority(RF_ERR_ALT_IRQn, RADIO_IRQ_PRIO);
|
||||
NVIC_EnableIRQ(RF_ERR_ALT_IRQn);
|
||||
|
||||
NVIC_SetPriority(MAC_TIMER_ALT_IRQn, RADIO_IRQ_PRIO);
|
||||
NVIC_EnableIRQ(MAC_TIMER_ALT_IRQn);
|
||||
}
|
||||
else {
|
||||
NVIC_SetPriority(RF_RXTX_IRQn, RADIO_IRQ_PRIO);
|
||||
@ -130,14 +140,25 @@ void cc2538_init(void)
|
||||
|
||||
NVIC_SetPriority(RF_ERR_IRQn, RADIO_IRQ_PRIO);
|
||||
NVIC_EnableIRQ(RF_ERR_IRQn);
|
||||
|
||||
NVIC_SetPriority(MACTIMER_IRQn, RADIO_IRQ_PRIO);
|
||||
NVIC_EnableIRQ(MACTIMER_IRQn);
|
||||
}
|
||||
|
||||
RFCORE_SFR_MTMSEL &= ~CC2538_SFR_MTMSEL_MASK;
|
||||
/* Select timer period */
|
||||
RFCORE_SFR_MTMSEL |= CC2538_SFR_MTMSEL_TIMER_P;
|
||||
|
||||
/* Fix timer to Backoff period */
|
||||
RFCORE_SFR_MTM0 |= TIMER_PERIOD_LSB;
|
||||
RFCORE_SFR_MTM1 |= TIMER_PERIOD_MSB;
|
||||
|
||||
RFCORE_SFR_MTMSEL &= ~CC2538_SFR_MTMSEL_MASK;
|
||||
RFCORE_SFR_MTCTRL |= CC2538_MCTRL_SYNC_MASK | CC2538_MCTRL_RUN_MASK;
|
||||
|
||||
/* Flush the receive and transmit FIFOs */
|
||||
RFCORE_SFR_RFST = ISFLUSHTX;
|
||||
RFCORE_SFR_RFST = ISFLUSHRX;
|
||||
/* Disable/filter l2 Acks */
|
||||
RFCORE_XREG_FRMFILT1 &= ~CC2538_ACCEPT_FT_2_ACK;
|
||||
cc2538_on();
|
||||
}
|
||||
|
||||
bool cc2538_is_on(void)
|
||||
@ -177,4 +198,9 @@ void cc2538_setup(cc2538_rf_t *dev)
|
||||
netdev->driver = &cc2538_rf_driver;
|
||||
|
||||
cc2538_init();
|
||||
cc2538_set_tx_power(CC2538_RF_POWER_DEFAULT);
|
||||
cc2538_set_chan(CC2538_RF_CHANNEL_DEFAULT);
|
||||
cc2538_set_addr_long(cc2538_get_eui64_primary());
|
||||
|
||||
cc2538_on();
|
||||
}
|
||||
|
||||
@ -64,9 +64,6 @@ void isr_rfcoreerr(void)
|
||||
|
||||
void isr_rfcorerxtx(void)
|
||||
{
|
||||
RFCORE_SFR_RFIRQF0 = 0;
|
||||
RFCORE_SFR_RFIRQF1 = 0;
|
||||
|
||||
_irq_handler();
|
||||
|
||||
cortexm_isr_end();
|
||||
|
||||
@ -31,11 +31,16 @@
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#if !IS_USED(MODULE_IEEE802154_RADIO_HAL)
|
||||
|
||||
/* Reference pointer for the IRQ handler */
|
||||
static netdev_t *_dev;
|
||||
|
||||
void _irq_handler(void)
|
||||
{
|
||||
RFCORE_SFR_RFIRQF0 = 0;
|
||||
RFCORE_SFR_RFIRQF1 = 0;
|
||||
|
||||
netdev_trigger_event_isr(_dev);
|
||||
}
|
||||
|
||||
@ -417,3 +422,6 @@ const netdev_driver_t cc2538_rf_driver = {
|
||||
.isr = _isr,
|
||||
.init = _init,
|
||||
};
|
||||
#else
|
||||
int dont_be_pedantic;
|
||||
#endif /* MODULE_IEEE802154_RADIO_HAL */
|
||||
|
||||
492
cpu/cc2538/radio/cc2538_rf_radio_ops.c
Normal file
492
cpu/cc2538/radio/cc2538_rf_radio_ops.c
Normal file
@ -0,0 +1,492 @@
|
||||
#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 uint8_t cc2538_min_be = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MIN_BE;
|
||||
static uint8_t cc2538_max_be = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MAX_BE;
|
||||
static int cc2538_csma_ca_retries = CONFIG_IEEE802154_DEFAULT_CSMA_CA_RETRIES;
|
||||
|
||||
static bool cc2538_cca_status; /**< status of the last CCA request */
|
||||
static bool cc2538_cca; /**< used to check wether the last CCA result
|
||||
corresponds to a CCA request or send with
|
||||
CSMA-CA */
|
||||
|
||||
static int _write(ieee802154_dev_t *dev, const 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;
|
||||
|
||||
if (RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE != 0 || !(RFCORE_XREG_CSPCTRL & CC2538_CSP_MCU_CTRL_MASK)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (info) {
|
||||
if (cc2538_csma_ca_retries >= 0 && RFCORE_XREG_CSPZ == 0) {
|
||||
info->status = TX_STATUS_MEDIUM_BUSY;
|
||||
}
|
||||
else {
|
||||
info->status = TX_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _request_transmit(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
|
||||
if (cc2538_csma_ca_retries < 0) {
|
||||
RFCORE_SFR_RFST = ISTXON;
|
||||
}
|
||||
else {
|
||||
cc2538_cca = false;
|
||||
|
||||
RFCORE_SFR_RFST = ISRXON;
|
||||
/* Clear last program */
|
||||
RFCORE_SFR_RFST = ISCLEAR;
|
||||
|
||||
/* If the RSSI is not yet valid, skip 0 instructions. This creates
|
||||
* a busy loop until the RSSI is valid. */
|
||||
RFCORE_SFR_RFST = SKIP_S_C
|
||||
| CC2538_CSP_SKIP_N_MASK
|
||||
| CC2538_CSP_SKIP_COND_RSSI;
|
||||
|
||||
/* Set a label right before the backoff */
|
||||
RFCORE_SFR_RFST = LABEL;
|
||||
|
||||
/* Load a random number with "register Y" LSBs into register X.
|
||||
* This is equivalent to choosing a random number between
|
||||
* (0, 2^(Y+1)).
|
||||
* Then, wait "register X" number of backoff units */
|
||||
RFCORE_SFR_RFST = RANDXY;
|
||||
RFCORE_SFR_RFST = WAITX;
|
||||
|
||||
/* If CCA is not valid, skip the next stop instruction. In such case
|
||||
* the CSP_STOP interrupt will trigger the transmission since the
|
||||
* channel is clear */
|
||||
RFCORE_SFR_RFST = SKIP_S_C
|
||||
| (1 << CC2538_CSP_SKIP_INST_POS)
|
||||
| CC2538_CSP_SKIP_N_MASK
|
||||
| CC2538_CSP_SKIP_COND_CCA;
|
||||
|
||||
RFCORE_SFR_RFST = STOP;
|
||||
|
||||
/* If we are here, the channel was not clear. Decrement the register Z
|
||||
* (remaining attempts) */
|
||||
RFCORE_SFR_RFST = DECZ;
|
||||
|
||||
/* Update the backoff exponent */
|
||||
RFCORE_SFR_RFST = INCMAXY | (cc2538_max_be & CC2538_CSP_INCMAXY_MAX_MASK);
|
||||
|
||||
/* If the are CSMA-CA retries left, go back to the defined label */
|
||||
RFCORE_SFR_RFST = RPT_C
|
||||
| CC2538_CSP_SKIP_N_MASK
|
||||
| CC2538_CSP_SKIP_COND_CSPZ;
|
||||
|
||||
/* Stop the program. The CSP_STOP interrupt will trigger the routine
|
||||
* to inform the upper layer that CSMA-CA failed. */
|
||||
RFCORE_SFR_RFST = STOP;
|
||||
|
||||
RFCORE_XREG_CSPX = 0; /* Holds timer value */
|
||||
RFCORE_XREG_CSPY = cc2538_min_be; /* Holds MinBE */
|
||||
|
||||
assert(cc2538_csma_ca_retries >= 0);
|
||||
RFCORE_XREG_CSPZ = cc2538_csma_ca_retries + 1; /* Holds CSMA-CA attempts (retries + 1) */
|
||||
|
||||
RFCORE_XREG_CSPCTRL &= ~CC2538_CSP_MCU_CTRL_MASK;
|
||||
|
||||
/* Execute the program */
|
||||
RFCORE_SFR_RFST = ISSTART;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _len(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
return rfcore_peek_rx_fifo(0) - IEEE802154_FCS_LEN;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
/* The number of dB above maximum sensitivity detected for the
|
||||
* received packet */
|
||||
info->rssi = -CC2538_RSSI_OFFSET + rssi_val + IEEE802154_RADIO_RSSI_OFFSET;
|
||||
|
||||
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;
|
||||
|
||||
RFCORE_XREG_RFIRQM0 |= RXPKTDONE;
|
||||
|
||||
return cc2538_cca_status;
|
||||
}
|
||||
|
||||
static int _request_cca(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
if (!RFCORE->XREG_FSMSTAT1bits.RX_ACTIVE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Ignore baseband processing */
|
||||
RFCORE_XREG_RFIRQM0 &= ~RXPKTDONE;
|
||||
|
||||
cc2538_cca = true;
|
||||
RFCORE_SFR_RFST = ISCLEAR;
|
||||
RFCORE_SFR_RFST = STOP;
|
||||
RFCORE_XREG_CSPCTRL &= ~CC2538_CSP_MCU_CTRL_MASK;
|
||||
|
||||
/* 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;
|
||||
int8_t pow = conf->pow;
|
||||
if (pow < OUTPUT_POWER_MIN || pow > OUTPUT_POWER_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint8_t channel = conf->channel;
|
||||
cc2538_set_freq(IEEE802154_CHAN2FREQ(channel));
|
||||
cc2538_set_tx_power(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 >= CC2538_STATE_SFD_WAIT_RANGE_MIN
|
||||
&& RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE <= CC2538_STATE_SFD_WAIT_RANGE_MAX;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Check if the interrupt was triggered because the CSP finished its routine
|
||||
* (CSMA-CA or CCA request)
|
||||
*/
|
||||
if (flags_f1 & CSP_STOP) {
|
||||
RFCORE_XREG_CSPCTRL |= CC2538_CSP_MCU_CTRL_MASK;
|
||||
if (!cc2538_cca) {
|
||||
if (RFCORE_XREG_CSPZ > 0) {
|
||||
RFCORE_XREG_RXMASKCLR = CC2538_RXENABLE_RXON_MASK;
|
||||
RFCORE_SFR_RFST = ISTXON;
|
||||
}
|
||||
else {
|
||||
cc2538_rf_dev.cb(&cc2538_rf_dev, IEEE802154_RADIO_CONFIRM_TX_DONE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
cc2538_cca_status = BOOLEAN(RFCORE->XREG_FSMSTAT1bits.CCA) && RFCORE->XREG_RSSISTATbits.RSSI_VALID;
|
||||
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_24_GHZ:
|
||||
case IEEE802154_CAP_IRQ_TX_DONE:
|
||||
case IEEE802154_CAP_IRQ_CCA_DONE:
|
||||
case IEEE802154_CAP_AUTO_CSMA:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int _set_hw_addr_filter(ieee802154_dev_t *dev, const network_uint16_t *short_addr,
|
||||
const eui64_t *ext_addr, const uint16_t *pan_id)
|
||||
{
|
||||
(void) dev;
|
||||
if (short_addr) {
|
||||
RFCORE_FFSM_SHORT_ADDR0 = short_addr->u8[1];
|
||||
RFCORE_FFSM_SHORT_ADDR1 = short_addr->u8[0];
|
||||
}
|
||||
|
||||
if (ext_addr) {
|
||||
RFCORE_FFSM_EXT_ADDR0 = ext_addr->uint8[7];
|
||||
RFCORE_FFSM_EXT_ADDR1 = ext_addr->uint8[6];
|
||||
RFCORE_FFSM_EXT_ADDR2 = ext_addr->uint8[5];
|
||||
RFCORE_FFSM_EXT_ADDR3 = ext_addr->uint8[4];
|
||||
RFCORE_FFSM_EXT_ADDR4 = ext_addr->uint8[3];
|
||||
RFCORE_FFSM_EXT_ADDR5 = ext_addr->uint8[2];
|
||||
RFCORE_FFSM_EXT_ADDR6 = ext_addr->uint8[1];
|
||||
RFCORE_FFSM_EXT_ADDR7 = ext_addr->uint8[0];
|
||||
}
|
||||
|
||||
if (pan_id) {
|
||||
RFCORE_FFSM_PAN_ID0 = *pan_id;
|
||||
RFCORE_FFSM_PAN_ID1 = (*pan_id) >> 8;
|
||||
}
|
||||
|
||||
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;
|
||||
uint8_t tmp = 0;
|
||||
switch (mode) {
|
||||
case IEEE802154_CCA_MODE_ED_THRESHOLD:
|
||||
tmp = 1;
|
||||
break;
|
||||
case IEEE802154_CCA_MODE_CARRIER_SENSING:
|
||||
tmp = 2;
|
||||
break;
|
||||
case IEEE802154_CCA_MODE_ED_THRESH_AND_CS:
|
||||
tmp = 3;
|
||||
break;
|
||||
case IEEE802154_CCA_MODE_ED_THRESH_OR_CS:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
RFCORE_XREG_CCACTRL1 &= CC2538_CCA_MODE_MASK;
|
||||
RFCORE_XREG_CCACTRL1 |= (tmp << CC2538_CCA_MODE_POS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_rx_mode(ieee802154_dev_t *dev, ieee802154_rx_mode_t mode)
|
||||
{
|
||||
(void) dev;
|
||||
|
||||
bool promisc = false;
|
||||
bool ack_filter = true;
|
||||
switch (mode) {
|
||||
case IEEE802154_RX_AACK_DISABLED:
|
||||
RFCORE->XREG_FRMCTRL0bits.AUTOACK = 0;
|
||||
break;
|
||||
case IEEE802154_RX_AACK_ENABLED:
|
||||
RFCORE->XREG_FRMCTRL0bits.AUTOACK = 1;
|
||||
RFCORE_XREG_FRMCTRL1 &= ~CC2538_FRMCTRL1_PENDING_OR_MASK;
|
||||
break;
|
||||
case IEEE802154_RX_AACK_FRAME_PENDING:
|
||||
RFCORE->XREG_FRMCTRL0bits.AUTOACK = 1;
|
||||
RFCORE_XREG_FRMCTRL1 |= CC2538_FRMCTRL1_PENDING_OR_MASK;
|
||||
break;
|
||||
case IEEE802154_RX_PROMISC:
|
||||
promisc = true;
|
||||
break;
|
||||
case IEEE802154_RX_WAIT_FOR_ACK:
|
||||
ack_filter = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ack_filter) {
|
||||
RFCORE_XREG_FRMFILT1 &= ~CC2538_ACCEPT_FT_2_ACK;
|
||||
}
|
||||
else {
|
||||
RFCORE_XREG_FRMFILT1 |= CC2538_ACCEPT_FT_2_ACK;
|
||||
}
|
||||
|
||||
cc2538_set_monitor(promisc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_csma_params(ieee802154_dev_t *dev, ieee802154_csma_be_t *bd, int8_t retries)
|
||||
{
|
||||
(void) dev;
|
||||
if (bd) {
|
||||
cc2538_min_be = bd->min;
|
||||
cc2538_max_be = bd->max;
|
||||
}
|
||||
|
||||
cc2538_csma_ca_retries = retries;
|
||||
|
||||
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_hw_addr_filter = _set_hw_addr_filter,
|
||||
.set_csma_params = _set_csma_params,
|
||||
.set_rx_mode = _set_rx_mode,
|
||||
};
|
||||
#else
|
||||
int dont_be_pedantic;
|
||||
#endif
|
||||
@ -59,6 +59,7 @@ PSEUDOMODULES += gnrc_sock_check_reuse
|
||||
PSEUDOMODULES += gnrc_txtsnd
|
||||
PSEUDOMODULES += heap_cmd
|
||||
PSEUDOMODULES += i2c_scan
|
||||
PSEUDOMODULES += ieee802154_radio_hal
|
||||
PSEUDOMODULES += ina3221_alerts
|
||||
PSEUDOMODULES += l2filter_blacklist
|
||||
PSEUDOMODULES += l2filter_whitelist
|
||||
|
||||
@ -98,6 +98,13 @@ extern "C" {
|
||||
#define IEEE802154G_FRAME_LEN_MAX (2047U) /**< maximum 802.15.4g-2012 frame length */
|
||||
#define IEEE802154_ACK_FRAME_LEN (5U) /**< ACK frame length */
|
||||
|
||||
/**
|
||||
* @brief value of measured power when RSSI is zero.
|
||||
*
|
||||
* This value is defined in the IEEE 802.15.4 standard
|
||||
*/
|
||||
#define IEEE802154_RADIO_RSSI_OFFSET (-174)
|
||||
|
||||
/**
|
||||
* For the SUN PHYs, the value is 1 ms expressed in symbol periods, rounded
|
||||
* up to the next integer number of symbol periods using the ceiling() function.
|
||||
@ -196,6 +203,27 @@ extern const uint8_t ieee802154_addr_bcast[IEEE802154_ADDR_BCAST_LEN];
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief IEEE802.15.4 default value for minimum backoff exponent
|
||||
*/
|
||||
#ifndef CONFIG_IEEE802154_DEFAULT_CSMA_CA_MIN_BE
|
||||
#define CONFIG_IEEE802154_DEFAULT_CSMA_CA_MIN_BE (3U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief IEEE802.15.4 default value for maximum number of CSMA-CA retries.
|
||||
*/
|
||||
#ifndef CONFIG_IEEE802154_DEFAULT_CSMA_CA_RETRIES
|
||||
#define CONFIG_IEEE802154_DEFAULT_CSMA_CA_RETRIES (4U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief IEEE802.15.4 default value for maximum backoff exponent
|
||||
*/
|
||||
#ifndef CONFIG_IEEE802154_DEFAULT_CSMA_CA_MAX_BE
|
||||
#define CONFIG_IEEE802154_DEFAULT_CSMA_CA_MAX_BE (5U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initializes an IEEE 802.15.4 MAC frame header in @p buf.
|
||||
*
|
||||
|
||||
@ -33,4 +33,16 @@ if KCONFIG_USEMODULE_IEEE802154
|
||||
int "IEEE802.15.4 default TX power (in dBm)"
|
||||
default 0
|
||||
|
||||
config IEEE802154_DEFAULT_CSMA_CA_MIN
|
||||
int "IEEE802.15.4 default CSMA-CA minimum backoff exponent"
|
||||
default 3
|
||||
|
||||
config IEEE802154_DEFAULT_CSMA_CA_RETRIES
|
||||
int "IEEE802.15.4 default CSMA-CA maximum number of retries"
|
||||
default 4
|
||||
|
||||
config IEEE802154_DEFAULT_CSMA_CA_MAX
|
||||
int "IEEE802.15.4 default CSMA-CA maximum backoff exponent"
|
||||
default 5
|
||||
|
||||
endif # KCONFIG_USEMODULE_IEEE802154
|
||||
|
||||
31
tests/ieee802154_hal/Makefile
Normal file
31
tests/ieee802154_hal/Makefile
Normal file
@ -0,0 +1,31 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
BOARD_WHITELIST := cc2538dk \
|
||||
omote \
|
||||
openmote-b \
|
||||
openmote-cc2538 \
|
||||
remote-pa \
|
||||
remote-reva \
|
||||
remote-revb
|
||||
|
||||
DISABLE_MODULE += auto_init_at86rf2xx auto_init_nrf802154
|
||||
|
||||
USEMODULE += od
|
||||
USEMODULE += luid
|
||||
USEMODULE += ieee802154
|
||||
USEMODULE += shell
|
||||
USEMODULE += ps
|
||||
USEMODULE += event_thread_highest
|
||||
USEMODULE += event_callback
|
||||
USEMODULE += xtimer
|
||||
USEMODULE += ieee802154_radio_hal
|
||||
|
||||
CFLAGS += -DEVENT_THREAD_HIGHEST_STACKSIZE=1024
|
||||
|
||||
# define the driver to be used for selected boards
|
||||
DRIVER := cc2538_rf
|
||||
|
||||
# include the selected driver
|
||||
USEMODULE += $(DRIVER)
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
43
tests/ieee802154_hal/common.h
Normal file
43
tests/ieee802154_hal/common.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2020 HAW Hamburg
|
||||
*
|
||||
* 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 tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Common header for ieee802154_hal tests.
|
||||
*
|
||||
* @author José I. Alamos <jose.alamos@haw-hamburg.de>
|
||||
*/
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include "net/ieee802154/radio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Application-internal functions and variables for ieee802154_hal tests
|
||||
* @internal
|
||||
* @{
|
||||
*/
|
||||
void ieee802154_hal_test_init_devs(void);
|
||||
ieee802154_dev_t *ieee802154_hal_test_get_dev(int id);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COMMON_H */
|
||||
/** @} */
|
||||
68
tests/ieee802154_hal/init_devs.c
Normal file
68
tests/ieee802154_hal/init_devs.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2020 HAW Hamburg
|
||||
*
|
||||
* 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 tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Test application for ieee802154_hal
|
||||
*
|
||||
* @author José I. Alamos <jose.alamos@haw-hamburg.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "assert.h"
|
||||
#include "kernel_defines.h"
|
||||
#include "net/ieee802154/radio.h"
|
||||
|
||||
#ifdef MODULE_CC2538_RF
|
||||
#include "cc2538_rf.h"
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_CC2538_RF
|
||||
extern ieee802154_dev_t cc2538_rf_dev;
|
||||
#endif
|
||||
|
||||
#define RADIOS_NUMOF IS_USED(MODULE_CC2538_RF)
|
||||
|
||||
#if RADIOS_NUMOF == 0
|
||||
#error "Radio is not supported"
|
||||
#endif
|
||||
|
||||
static ieee802154_dev_t *_radios[RADIOS_NUMOF];
|
||||
|
||||
static void _register_radios(void)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
#ifdef MODULE_CC2538_RF
|
||||
_radios[i++] = &cc2538_rf_dev;
|
||||
#endif
|
||||
|
||||
assert(i == RADIOS_NUMOF);
|
||||
}
|
||||
|
||||
void ieee802154_hal_test_init_devs(void)
|
||||
{
|
||||
/* Register all radios */
|
||||
_register_radios();
|
||||
|
||||
/* Call the init function of the device (this should be handled by
|
||||
* `auto_init`) */
|
||||
#ifdef MODULE_CC2538_RF
|
||||
cc2538_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
ieee802154_dev_t *ieee802154_hal_test_get_dev(int id)
|
||||
{
|
||||
assert(id < RADIOS_NUMOF);
|
||||
return _radios[id];
|
||||
}
|
||||
656
tests/ieee802154_hal/main.c
Normal file
656
tests/ieee802154_hal/main.c
Normal file
@ -0,0 +1,656 @@
|
||||
/*
|
||||
* Copyright (C) 2020 HAW Hamburg
|
||||
*
|
||||
* 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 tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Test application for IEEE 802.15.4 Radio HAL
|
||||
*
|
||||
* @author José I. Alamos <jose.alamos@haw-hamburg.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "errno.h"
|
||||
#include "event/thread.h"
|
||||
#include "luid.h"
|
||||
|
||||
#include "net/ieee802154.h"
|
||||
#include "net/ieee802154/radio.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "shell_commands.h"
|
||||
|
||||
#include "xtimer.h"
|
||||
|
||||
#define SYMBOL_TIME (16U) /**< 16 us */
|
||||
|
||||
#define ACK_TIMEOUT_TIME (40 * SYMBOL_TIME)
|
||||
|
||||
#define RADIO_DEFAULT_ID (0U)
|
||||
|
||||
static inline void _set_trx_state(int state, bool verbose);
|
||||
|
||||
static uint8_t buffer[127];
|
||||
static xtimer_t timer_ack;
|
||||
static mutex_t lock;
|
||||
|
||||
static const char *str_states[3]= {"TRX_OFF", "RX", "TX"};
|
||||
static ieee802154_rx_mode_t current_rx_mode;
|
||||
static eui64_t ext_addr;
|
||||
static network_uint16_t short_addr;
|
||||
static uint8_t seq;
|
||||
|
||||
static void _print_packet(size_t size, uint8_t lqi, int16_t rssi)
|
||||
{
|
||||
if (buffer[0] & IEEE802154_FCF_TYPE_ACK && ((seq-1) == buffer[2])) {
|
||||
printf("Received valid ACK with sqn %i\n", buffer[2]);
|
||||
}
|
||||
else {
|
||||
puts("Packet received:");
|
||||
for (unsigned i=0;i<size;i++) {
|
||||
printf("%02x ", buffer[i]);
|
||||
}
|
||||
}
|
||||
puts("");
|
||||
printf("LQI: %i, RSSI: %i\n", (int) lqi, (int) rssi);
|
||||
puts("");
|
||||
}
|
||||
|
||||
static int print_addr(int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
uint8_t *_p = (uint8_t*) &ext_addr;
|
||||
for(int i=0;i<8;i++) {
|
||||
printf("%02x", *_p++);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _ack_timeout(event_t *event)
|
||||
{
|
||||
(void) event;
|
||||
ieee802154_dev_t *dev = ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID);
|
||||
|
||||
ieee802154_radio_set_rx_mode(dev, current_rx_mode);
|
||||
}
|
||||
|
||||
static event_t _ack_timeout_ev = {
|
||||
.handler = _ack_timeout,
|
||||
};
|
||||
|
||||
void _timer_ack_handler(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
event_post(EVENT_PRIO_HIGHEST, &_ack_timeout_ev);
|
||||
}
|
||||
|
||||
static xtimer_t timer_ack = {
|
||||
.callback = _timer_ack_handler,
|
||||
};
|
||||
|
||||
void _rx_done_handler(event_t *event)
|
||||
{
|
||||
(void) event;
|
||||
ieee802154_rx_info_t info;
|
||||
|
||||
/* Read packet from internal framebuffer
|
||||
*
|
||||
* NOTE: It's possible to call `ieee802154_radio_len` to retrieve the packet
|
||||
* length. Since the buffer is fixed in this test, we don't use it
|
||||
*/
|
||||
int size = ieee802154_radio_indication_rx(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), buffer, 127, &info);
|
||||
if (size > 0) {
|
||||
/* Print packet while we wait for the state transition */
|
||||
_print_packet(size, info.lqi, info.rssi);
|
||||
}
|
||||
}
|
||||
|
||||
static event_t _rx_done_event = {
|
||||
.handler = _rx_done_handler,
|
||||
};
|
||||
|
||||
/* Event Notification callback */
|
||||
static void _hal_radio_cb(ieee802154_dev_t *dev, ieee802154_trx_ev_t status)
|
||||
{
|
||||
(void) dev;
|
||||
switch(status) {
|
||||
case IEEE802154_RADIO_CONFIRM_TX_DONE:
|
||||
case IEEE802154_RADIO_CONFIRM_CCA:
|
||||
mutex_unlock(&lock);
|
||||
break;
|
||||
case IEEE802154_RADIO_INDICATION_RX_DONE:
|
||||
event_post(EVENT_PRIO_HIGHEST, &_rx_done_event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _tx_finish_handler(event_t *event)
|
||||
{
|
||||
ieee802154_tx_info_t tx_info;
|
||||
|
||||
(void) event;
|
||||
/* The TX_DONE event indicates it's safe to call the confirm counterpart */
|
||||
assert(ieee802154_radio_confirm_transmit(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), &tx_info) >= 0);
|
||||
|
||||
if (!ieee802154_radio_has_irq_ack_timeout(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID)) && !ieee802154_radio_has_frame_retrans(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
/* This is just to show how the MAC layer would handle ACKs... */
|
||||
_set_trx_state(IEEE802154_TRX_STATE_RX_ON, false);
|
||||
xtimer_set(&timer_ack, ACK_TIMEOUT_TIME);
|
||||
}
|
||||
|
||||
switch (tx_info.status) {
|
||||
case TX_STATUS_SUCCESS:
|
||||
puts("Transmission succeeded");
|
||||
break;
|
||||
case TX_STATUS_FRAME_PENDING:
|
||||
puts("Transmission succeeded and there's pending data");
|
||||
break;
|
||||
case TX_STATUS_MEDIUM_BUSY:
|
||||
puts("Medium busy");
|
||||
break;
|
||||
case TX_STATUS_NO_ACK:
|
||||
puts("No ACK");
|
||||
break;
|
||||
}
|
||||
|
||||
puts("");
|
||||
|
||||
if (ieee802154_radio_has_frame_retrans_info(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
printf("Retransmission attempts: %i\n", tx_info.retrans);
|
||||
}
|
||||
|
||||
puts("");
|
||||
}
|
||||
|
||||
static event_t _tx_finish_ev = {
|
||||
.handler = _tx_finish_handler,
|
||||
};
|
||||
|
||||
static void _send(iolist_t *pkt)
|
||||
{
|
||||
/* Request a state change to RX_ON */
|
||||
ieee802154_radio_request_set_trx_state(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), IEEE802154_TRX_STATE_TX_ON);
|
||||
|
||||
/* Write the packet to the radio */
|
||||
ieee802154_radio_write(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), pkt);
|
||||
|
||||
/* Block until the radio confirms the state change */
|
||||
while(ieee802154_radio_confirm_set_trx_state(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID)) == -EAGAIN);
|
||||
|
||||
/* Trigger the transmit and wait for the mutex unlock (TX_DONE event) */
|
||||
ieee802154_radio_request_transmit(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID));
|
||||
ieee802154_radio_set_rx_mode(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), IEEE802154_RX_WAIT_FOR_ACK);
|
||||
mutex_lock(&lock);
|
||||
|
||||
event_post(EVENT_PRIO_HIGHEST, &_tx_finish_ev);
|
||||
}
|
||||
|
||||
static int _init(void)
|
||||
{
|
||||
ieee802154_hal_test_init_devs();
|
||||
|
||||
/* Set the Event Notification */
|
||||
((ieee802154_dev_t*) ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))->cb = _hal_radio_cb;
|
||||
|
||||
/* Note that addresses are not kept in the radio. This assumes MAC layers
|
||||
* already have a copy of the address */
|
||||
luid_get_eui64(&ext_addr);
|
||||
luid_get_short(&short_addr);
|
||||
|
||||
/* Since the device was already initialized, turn on the radio.
|
||||
* The transceiver state will be "TRX_OFF" */
|
||||
ieee802154_radio_request_on(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID));
|
||||
while(ieee802154_radio_confirm_on(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID)) == -EAGAIN) {}
|
||||
|
||||
current_rx_mode = IEEE802154_RX_AACK_ENABLED;
|
||||
ieee802154_radio_set_rx_mode(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), current_rx_mode);
|
||||
|
||||
uint16_t panid = CONFIG_IEEE802154_DEFAULT_PANID;
|
||||
/* Set all IEEE addresses */
|
||||
ieee802154_radio_set_hw_addr_filter(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), &short_addr, &ext_addr, &panid);
|
||||
|
||||
/* Set PHY configuration */
|
||||
ieee802154_phy_conf_t conf = {.channel=CONFIG_IEEE802154_DEFAULT_CHANNEL, .page=CONFIG_IEEE802154_DEFAULT_SUBGHZ_PAGE, .pow=CONFIG_IEEE802154_DEFAULT_TXPOWER};
|
||||
|
||||
ieee802154_radio_config_phy(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), &conf);
|
||||
|
||||
/* Set the transceiver state to RX_ON in order to receive packets */
|
||||
_set_trx_state(IEEE802154_TRX_STATE_RX_ON, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t payload[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ornare lacinia mi elementum interdum ligula.";
|
||||
|
||||
static int send(uint8_t *dst, size_t dst_len,
|
||||
size_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
uint8_t mhr[IEEE802154_MAX_HDR_LEN];
|
||||
int mhr_len;
|
||||
|
||||
le_uint16_t src_pan, dst_pan;
|
||||
iolist_t iol_data = {
|
||||
.iol_base = payload,
|
||||
.iol_len = len,
|
||||
.iol_next = NULL,
|
||||
};
|
||||
|
||||
flags = IEEE802154_FCF_TYPE_DATA | IEEE802154_FCF_ACK_REQ;
|
||||
|
||||
src_pan = byteorder_btols(byteorder_htons(CONFIG_IEEE802154_DEFAULT_PANID));
|
||||
dst_pan = byteorder_btols(byteorder_htons(CONFIG_IEEE802154_DEFAULT_PANID));
|
||||
uint8_t src_len = IEEE802154_LONG_ADDRESS_LEN;
|
||||
void *src = &ext_addr;
|
||||
|
||||
/* fill MAC header, seq should be set by device */
|
||||
if ((mhr_len = ieee802154_set_frame_hdr(mhr, src, src_len,
|
||||
dst, dst_len,
|
||||
src_pan, dst_pan,
|
||||
flags, seq++)) < 0) {
|
||||
puts("txtsnd: Error preperaring frame");
|
||||
return 1;
|
||||
}
|
||||
|
||||
iolist_t iol_hdr = {
|
||||
.iol_next = &iol_data,
|
||||
.iol_base = mhr,
|
||||
.iol_len = mhr_len,
|
||||
};
|
||||
|
||||
_send(&iol_hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int _dehex(char c, int default_)
|
||||
{
|
||||
if ('0' <= c && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
else if ('A' <= c && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
else if ('a' <= c && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
else {
|
||||
return default_;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t _parse_addr(uint8_t *out, size_t out_len, const char *in)
|
||||
{
|
||||
const char *end_str = in;
|
||||
uint8_t *out_end = out;
|
||||
size_t count = 0;
|
||||
int assert_cell = 1;
|
||||
|
||||
if (!in || !*in) {
|
||||
return 0;
|
||||
}
|
||||
while (end_str[1]) {
|
||||
++end_str;
|
||||
}
|
||||
|
||||
while (end_str >= in) {
|
||||
int a = 0, b = _dehex(*end_str--, -1);
|
||||
if (b < 0) {
|
||||
if (assert_cell) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
assert_cell = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
assert_cell = 0;
|
||||
|
||||
if (end_str >= in) {
|
||||
a = _dehex(*end_str--, 0);
|
||||
}
|
||||
|
||||
if (++count > out_len) {
|
||||
return 0;
|
||||
}
|
||||
*out_end++ = (a << 4) | b;
|
||||
}
|
||||
if (assert_cell) {
|
||||
return 0;
|
||||
}
|
||||
/* out is reversed */
|
||||
|
||||
while (out < --out_end) {
|
||||
uint8_t tmp = *out_end;
|
||||
*out_end = *out;
|
||||
*out++ = tmp;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int _cca(int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
ieee802154_radio_request_cca(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID));
|
||||
mutex_lock(&lock);
|
||||
int res = ieee802154_radio_confirm_cca(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID));
|
||||
assert(res >= 0);
|
||||
|
||||
if (res > 0) {
|
||||
puts("CLEAR");
|
||||
}
|
||||
else {
|
||||
puts("BUSY");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void _set_trx_state(int state, bool verbose)
|
||||
{
|
||||
xtimer_ticks32_t a;
|
||||
int res = ieee802154_radio_request_set_trx_state(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), state);
|
||||
if (verbose) {
|
||||
a = xtimer_now();
|
||||
if(res != 0) {
|
||||
printf("%i != 0 \n", res);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
while ((res = ieee802154_radio_confirm_set_trx_state(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) == -EAGAIN) {}
|
||||
if (verbose) {
|
||||
if (res != 0) {
|
||||
printf("%i != 0 \n", res);
|
||||
assert(false);
|
||||
}
|
||||
uint32_t secs = xtimer_usec_from_ticks(xtimer_diff(xtimer_now(), a));
|
||||
printf("\tTransition took %" PRIu32 " usecs\n", secs);
|
||||
}
|
||||
}
|
||||
|
||||
int _test_states(int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
for (int i=0; i<3;i++) {
|
||||
printf("Setting state to: %s\n", str_states[i]);
|
||||
_set_trx_state(i, true);
|
||||
for (int j=0; j<3; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
printf("%s-> %s\n", str_states[i], str_states[j]);
|
||||
_set_trx_state(j, true);
|
||||
printf("%s-> %s\n", str_states[j], str_states[i]);
|
||||
_set_trx_state(i, true);
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
_set_trx_state(IEEE802154_TRX_STATE_RX_ON, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int txtsnd(int argc, char **argv)
|
||||
{
|
||||
uint8_t addr[IEEE802154_LONG_ADDRESS_LEN];
|
||||
size_t len;
|
||||
size_t res;
|
||||
|
||||
if (argc != 3) {
|
||||
puts("Usage: txtsnd <long_addr> <len>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = _parse_addr(addr, sizeof(addr), argv[1]);
|
||||
if (res == 0) {
|
||||
puts("Usage: txtsnd <long_addr> <len>");
|
||||
return 1;
|
||||
}
|
||||
len = atoi(argv[2]);
|
||||
return send(addr, res, len);
|
||||
}
|
||||
|
||||
static int rx_mode_cmd(int argc, char **argv)
|
||||
{
|
||||
ieee802154_rx_mode_t conf;
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <on|off|pend|promisc>", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "pend") == 0) {
|
||||
conf = IEEE802154_RX_AACK_FRAME_PENDING;
|
||||
puts("ACK enabled with Frame Pending");
|
||||
}
|
||||
else if (strcmp(argv[1], "off") == 0) {
|
||||
conf = IEEE802154_RX_AACK_DISABLED;
|
||||
puts("ACK disabled");
|
||||
}
|
||||
else if (strcmp(argv[1], "promisc") == 0) {
|
||||
conf = IEEE802154_RX_PROMISC;
|
||||
puts("Promiscuous mode enabled");
|
||||
}
|
||||
else {
|
||||
conf = IEEE802154_RX_AACK_ENABLED;
|
||||
puts("ACK enabled");
|
||||
}
|
||||
|
||||
current_rx_mode = conf;
|
||||
ieee802154_radio_set_rx_mode(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID), conf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_phy(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
puts("Usage: config_phy <channel> <tx_pow>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t channel = atoi(argv[1]);
|
||||
int8_t tx_pow = atoi(argv[2]);
|
||||
|
||||
if (channel < 11 || channel > 26) {
|
||||
puts("Wrong channel configuration (11 <= channel <= 26).");
|
||||
return 1;
|
||||
}
|
||||
ieee802154_dev_t *dev = ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID);
|
||||
ieee802154_phy_conf_t conf = {.channel=channel, .page=0, .pow=tx_pow};
|
||||
if (ieee802154_radio_config_phy(dev, &conf) < 0) {
|
||||
puts("Channel or TX power settings not supported");
|
||||
}
|
||||
else {
|
||||
puts("Success!");
|
||||
}
|
||||
|
||||
/* Set the transceiver state to RX_ON in order to receive packets */
|
||||
_set_trx_state(IEEE802154_TRX_STATE_RX_ON, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int txmode_cmd(int argc, char **argv)
|
||||
{
|
||||
ieee802154_dev_t *dev = ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID);
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <csma_ca|cca|direct>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ieee802154_csma_be_t csma_conf = {.min = 3, .max = 5};
|
||||
|
||||
int retries;
|
||||
if (strcmp(argv[1], "direct") == 0) {
|
||||
retries = -1;
|
||||
}
|
||||
else if (strcmp(argv[1], "cca") == 0) {
|
||||
retries = 0;
|
||||
}
|
||||
else {
|
||||
retries = 4;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_set_csma_params(dev, &csma_conf, retries) < 0) {
|
||||
puts("Not supported");
|
||||
}
|
||||
else {
|
||||
puts("Ok");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _config_cca_cmd(int argc, char **argv)
|
||||
{
|
||||
ieee802154_dev_t *dev = ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID);
|
||||
ieee802154_cca_mode_t mode;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <ed|cs|or|and> [ED threshold]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "ed") == 0) {
|
||||
mode = IEEE802154_CCA_MODE_ED_THRESHOLD;
|
||||
}
|
||||
else if (strcmp(argv[1], "cs") == 0) {
|
||||
mode = IEEE802154_CCA_MODE_CARRIER_SENSING;
|
||||
}
|
||||
else if (strcmp(argv[1], "or") == 0) {
|
||||
mode = IEEE802154_CCA_MODE_ED_THRESH_OR_CS;
|
||||
}
|
||||
else {
|
||||
mode = IEEE802154_CCA_MODE_ED_THRESH_AND_CS;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_set_cca_mode(dev, mode) == -ENOTSUP) {
|
||||
puts("CCA mode not supported.");
|
||||
return 1;
|
||||
}
|
||||
puts("CCA mode set.");
|
||||
|
||||
if (argc > 2) {
|
||||
int8_t thresh = atoi(argv[2]);
|
||||
if (ieee802154_radio_set_cca_threshold(dev, thresh) < 0) {
|
||||
puts("Error setting the threshold");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("Set threshold to %i\n", thresh);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _caps_cmd(int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
bool has_frame_retrans = false;
|
||||
bool has_auto_csma = false;
|
||||
bool has_24_ghz = false;
|
||||
bool has_sub_ghz = false;
|
||||
bool has_irq_tx_done = false;
|
||||
bool has_irq_rx_start = false;
|
||||
bool has_irq_ack_timeout = false;
|
||||
bool has_irq_cca_done = false;
|
||||
bool has_frame_retrans_info = false;
|
||||
|
||||
if (ieee802154_radio_has_frame_retrans(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
has_frame_retrans = true;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_has_auto_csma(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
has_auto_csma = true;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_has_24_ghz(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
has_24_ghz = true;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_has_sub_ghz(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
has_sub_ghz = true;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_has_irq_tx_done(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
has_irq_tx_done = true;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_has_irq_rx_start(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
has_irq_rx_start = true;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_has_irq_ack_timeout(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
has_irq_ack_timeout = true;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_has_irq_cca_done(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
has_irq_cca_done = true;
|
||||
}
|
||||
|
||||
if (ieee802154_radio_has_frame_retrans_info(ieee802154_hal_test_get_dev(RADIO_DEFAULT_ID))) {
|
||||
has_frame_retrans_info = true;
|
||||
}
|
||||
|
||||
puts(" CAPS ");
|
||||
puts("=================================");
|
||||
printf("- Frame Retransmissions: %s\n", has_frame_retrans ? "y" : "n");
|
||||
printf(" * Info retries: %s\n", has_frame_retrans_info ? "y" : "n");
|
||||
printf("- Auto CSMA-CA: %s\n", has_auto_csma ? "y" : "n");
|
||||
printf("- 2.4 GHz band: %s\n", has_24_ghz ? "y" : "n");
|
||||
printf("- SubGHz band: %s\n", has_sub_ghz ? "y" : "n");
|
||||
printf("- TX DONE indication: %s\n", has_irq_tx_done ? "y" : "n");
|
||||
printf(" * ACK Timeout indication: %s\n", has_irq_ack_timeout ? "y" : "n");
|
||||
printf("- RX_START indication: %s\n", has_irq_rx_start ? "y" : "n");
|
||||
printf("- CCA Done indication: %s\n", has_irq_cca_done ? "y" : "n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "config_phy", "Set channel and TX power", config_phy},
|
||||
{ "print_addr", "Print IEEE802.15.4 addresses", print_addr},
|
||||
{ "txtsnd", "Send IEEE 802.15.4 packet", txtsnd },
|
||||
{ "test_states", "Test state changes", _test_states },
|
||||
{ "cca", "Perform CCA", _cca },
|
||||
{ "config_cca", "Config CCA parameters", _config_cca_cmd },
|
||||
{ "rx_mode", "Enable/Disable AACK or set Frame Pending bit or set promiscuos mode", rx_mode_cmd },
|
||||
{ "tx_mode", "Enable CSMA-CA, CCA or direct transmission", txmode_cmd },
|
||||
{ "caps", "Get a list of caps supported by the device", _caps_cmd },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mutex_init(&lock);
|
||||
mutex_lock(&lock);
|
||||
_init();
|
||||
|
||||
/* start the shell */
|
||||
puts("Initialization successful - starting the shell now");
|
||||
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user