1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/mrf24j40/mrf24j40_radio_hal.c
Marian Buschsieweke c10b8838f1
drivers/mrf24j40: cleanup function
`_set_csma_params()` spends some time to prepare a value in
`uint8_t tmp`, which then is never used. Likely this is a leftover
of moving code to `mrf24j40_set_csma_max_retries()`. This drops the
leftover code.
2023-05-20 16:59:25 +02:00

368 lines
11 KiB
C

#include "mrf24j40.h"
#include "mrf24j40_params.h"
#include "mrf24j40_internal.h"
#include "mrf24j40_registers.h"
#include "net/ieee802154/radio.h"
#define ENABLE_DEBUG 0
#include "debug.h"
static const ieee802154_radio_ops_t mrf24j40_ops;
void mrf24j40_radio_irq_handler(void *ctx)
{
ieee802154_dev_t *hal = ctx;
mrf24j40_t *dev = hal->priv;
/* update pending bits */
mrf24j40_update_tasks(dev);
DEBUG("[mrf24j40] INTERRUPT (pending: %x),\n", dev->pending);
/* Transmit interrupt occurred */
if (dev->pending & MRF24J40_TASK_TX_READY) {
hal->cb(hal, IEEE802154_RADIO_CONFIRM_TX_DONE);
}
/* Receive interrupt occurred */
if (dev->pending & MRF24J40_TASK_RX_READY) {
DEBUG("[mrf24j40] EVT - RX_END\n");
dev->pending &= ~(MRF24J40_TASK_RX_READY);
/* Prevent race condition if there is an ongoing transmission */
if (dev->tx_pending) {
mrf24j40_flush_rx(dev);
}
else {
hal->cb(hal, IEEE802154_RADIO_INDICATION_RX_DONE);
}
}
DEBUG("[mrf24j40] END IRQ\n");
}
static int _write(ieee802154_dev_t *hal, const iolist_t *iolist)
{
uint8_t len = 0;
mrf24j40_t *dev = hal->priv;
/* load packet data into FIFO */
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
/* Check if there is data to copy, prevents assertion failure in the
* SPI peripheral if there is no data to copy */
if (iol->iol_len) {
/* current packet data + FCS too long */
len = mrf24j40_tx_load(dev, iol->iol_base, iol->iol_len, len);
}
/* only on first iteration: */
if (iol == iolist) {
/* Grab the FCF bits from the frame header */
dev->fcf_low = *(uint8_t*)(iol->iol_base);
}
}
/* write frame length field in FIFO */
mrf24j40_tx_normal_fifo_write(dev, MRF24J40_TX_NORMAL_FIFO + 1, &len, 1);
return 0;
}
int mrf24j40_init(mrf24j40_t *dev, const mrf24j40_params_t *params, ieee802154_dev_t *hal,
gpio_cb_t cb, void *ctx)
{
hal->driver = &mrf24j40_ops;
hal->priv = dev;
dev->params = params;
/* initialize GPIOs */
spi_init_cs(dev->params->spi, dev->params->cs_pin);
gpio_init(dev->params->reset_pin, GPIO_OUT);
gpio_set(dev->params->reset_pin);
gpio_init_int(dev->params->int_pin, GPIO_IN, GPIO_RISING, cb, ctx);
/* reset device to default values */
if (mrf24j40_reset(dev)) {
return -ENODEV;
}
/* Set device to SLEEP */
mrf24j40_sleep(dev);
return 0;
}
static int _read(ieee802154_dev_t *hal, void *buf, size_t size, ieee802154_rx_info_t *info)
{
uint8_t phr;
size_t pkt_len;
int res = -ENOBUFS;
mrf24j40_t *dev = hal->priv;
phr = mrf24j40_reg_read_long(dev, MRF24J40_RX_FIFO);
pkt_len = (phr & 0x7f) - IEEE802154_FCS_LEN;
if (buf) {
if (pkt_len > size) {
mrf24j40_flush_rx(dev);
return -ENOBUFS;
}
mrf24j40_rx_fifo_read(dev, 1, (uint8_t *)buf, pkt_len);
if (info != NULL) {
uint8_t rssi_scalar = 0;
/* Read LQI and RSSI values from the RX fifo */
mrf24j40_rx_fifo_read(dev, phr + 1, &(info->lqi), 1);
mrf24j40_rx_fifo_read(dev, phr + 2, &(rssi_scalar), 1);
info->rssi = mrf24j40_dbm_from_reg(rssi_scalar);
}
res = pkt_len;
}
else {
mrf24j40_flush_rx(dev);
}
/* Return -ENOBUFS if a too small buffer is supplied. Return packet size
* otherwise */
return res;
}
static int _len(ieee802154_dev_t *hal)
{
mrf24j40_t *dev = hal->priv;
return (mrf24j40_reg_read_long(dev, MRF24J40_RX_FIFO) & 0x7f) - IEEE802154_FCS_LEN;
}
static int _off(ieee802154_dev_t *hal)
{
mrf24j40_t *dev = hal->priv;
mrf24j40_sleep(dev);
return -ENOTSUP;
}
static int _request_on(ieee802154_dev_t *hal)
{
mrf24j40_t *dev = hal->priv;
mrf24j40_wake_up(dev);
return 0;
}
static int _confirm_on(ieee802154_dev_t *hal)
{
(void) hal;
/* Nothing to do here */
return 0;
}
static int _request_op(ieee802154_dev_t *hal, ieee802154_hal_op_t op, void *ctx)
{
int res = -EBUSY;
mrf24j40_t *dev = hal->priv;
(void) ctx;
switch (op) {
case IEEE802154_HAL_OP_TRANSMIT:
if (dev->fcf_low & IEEE802154_FCF_ACK_REQ) {
mrf24j40_reg_write_short(dev, MRF24J40_REG_TXNCON, MRF24J40_TXNCON_TXNACKREQ | MRF24J40_TXNCON_TXNTRIG);
mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG1, 0x00);
}
else {
mrf24j40_reg_write_short(dev, MRF24J40_REG_TXNCON, MRF24J40_TXNCON_TXNTRIG);
}
dev->tx_pending = true;
res = 0;
break;
case IEEE802154_HAL_OP_SET_RX:
mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG1, 0x00);
res = 0;
mrf24j40_reg_write_short(dev, MRF24J40_REG_INTCON, ~(MRF24J40_INTCON_RXIE));
break;
case IEEE802154_HAL_OP_SET_IDLE:
mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG1, MRF24J40_BBREG1_RXDECINV );
mrf24j40_reg_write_short(dev, MRF24J40_REG_INTCON, ~(MRF24J40_INTCON_TXNIE));
res = 0;
break;
case IEEE802154_HAL_OP_CCA:
mrf24j40_enable_lna(dev);
mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG6, MRF24J40_BBREG6_RSSIMODE1);
mrf24j40_reg_write_short(dev, MRF24J40_REG_INTCON, 0xFF);
res = 0;
break;
}
return res;
}
static int _confirm_op(ieee802154_dev_t *hal, ieee802154_hal_op_t op, void *ctx)
{
int res = -EAGAIN;
mrf24j40_t *dev = hal->priv;
uint8_t tmp_ccaedth;
uint8_t tmp_rssi;
switch (op) {
case IEEE802154_HAL_OP_TRANSMIT:
if (dev->pending & MRF24J40_TASK_TX_READY) {
dev->pending &= ~(MRF24J40_TASK_TX_READY);
if (ctx) {
uint8_t txstat = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXSTAT);
ieee802154_tx_info_t *info = ctx;
if (txstat & MRF24J40_TXSTAT_TXNSTAT) {
info->status = (txstat & MRF24J40_TXSTAT_CCAFAIL)
? TX_STATUS_MEDIUM_BUSY
: TX_STATUS_NO_ACK;
}
else {
info->status = TX_STATUS_SUCCESS;
}
info->retrans = txstat >> MRF24J40_TXSTAT_MAX_FRAME_RETRIES_SHIFT;
}
mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG1, MRF24J40_BBREG1_RXDECINV);
dev->tx_pending = false;
return 0;
}
break;
case IEEE802154_HAL_OP_SET_RX:
case IEEE802154_HAL_OP_SET_IDLE:
res = 0;
break;
case IEEE802154_HAL_OP_CCA:
if ((mrf24j40_reg_read_short(dev, MRF24J40_REG_BBREG6) & MRF24J40_BBREG2_RSSIRDY)) {
tmp_ccaedth = mrf24j40_reg_read_short(dev, MRF24J40_REG_CCAEDTH); /* Energy detection threshold */
tmp_rssi = mrf24j40_reg_read_long(dev, MRF24J40_REG_RSSI);
mrf24j40_enable_auto_pa_lna(dev);
*((bool*) ctx) = (tmp_rssi < tmp_ccaedth) ? true : false;
res = 0;
}
break;
}
return res;
}
static int _set_cca_threshold(ieee802154_dev_t *hal, int8_t threshold)
{
mrf24j40_t *dev = hal->priv;
mrf24j40_set_cca_threshold(dev, threshold);
return 0;
}
static int _set_cca_mode(ieee802154_dev_t *dev, ieee802154_cca_mode_t mode)
{
(void) dev;
(void) mode;
if (mode != IEEE802154_CCA_MODE_ED_THRESHOLD) {
return -ENOTSUP;
}
return 0;
}
static int _config_phy(ieee802154_dev_t *hal, const ieee802154_phy_conf_t *conf)
{
mrf24j40_t *dev = hal->priv;
int8_t pow = conf->pow;
uint8_t channel = conf->channel;
if (pow < MRF24J40_MIN_TXPOWER && pow > MRF24J40_MAX_TXPOWER) {
return -EINVAL;
}
mrf24j40_set_txpower(dev, pow);
mrf24j40_set_chan(dev, channel);
return 0;
}
static int _set_csma_params(ieee802154_dev_t *hal, const ieee802154_csma_be_t *bd, int8_t retries)
{
mrf24j40_t *dev = hal->priv;
if (bd->min > MRF24J40_MAX_MINBE) {
return -EINVAL;
}
/* This radio ignores max_be */
mrf24j40_set_csma_max_retries(dev, retries);
return 0;
}
static int _config_addr_filter(ieee802154_dev_t *hal, ieee802154_af_cmd_t cmd, const void *value)
{
mrf24j40_t *dev = hal->priv;
switch (cmd) {
case IEEE802154_AF_SHORT_ADDR:
mrf24j40_set_addr_short(dev, *((const uint16_t *)value));
break;
case IEEE802154_AF_EXT_ADDR:
mrf24j40_set_addr_long(dev, value);
break;
case IEEE802154_AF_PANID:
mrf24j40_set_pan(dev, *((const uint16_t *)value));
break;
case IEEE802154_AF_PAN_COORD:
return -ENOTSUP;
}
return 0;
}
static int _config_src_addr_match(ieee802154_dev_t *hal, ieee802154_src_match_t cmd, const void *value)
{
mrf24j40_t *dev = hal->priv;
uint8_t tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_ACKTMOUT) & ~MRF24J40_ACKTMOUT_DRPACK;
bool en;
switch (cmd) {
case IEEE802154_SRC_MATCH_EN:
en = *((bool*) value);
tmp = en ? tmp | MRF24J40_ACKTMOUT_DRPACK : tmp;
mrf24j40_reg_write_short(dev, MRF24J40_REG_ACKTMOUT, tmp);
return 0;
default:
return -ENOTSUP;
}
}
static int _set_frame_filter_mode(ieee802154_dev_t *hal, ieee802154_filter_mode_t mode)
{
mrf24j40_t *dev = hal->priv;
switch (mode) {
case IEEE802154_FILTER_ACCEPT:
mrf24j40_set_option(dev, MRF24J40_OPT_PROMISCUOUS, false);
break;
case IEEE802154_FILTER_PROMISC:
mrf24j40_set_option(dev, MRF24J40_OPT_PROMISCUOUS, true);
break;
case IEEE802154_FILTER_ACK_ONLY:
default:
return -ENOTSUP;
}
return 0;
}
int _set_frame_retrans(ieee802154_dev_t *hal, uint8_t retrans)
{
(void) hal;
(void) retrans;
/* This radio does not allow to set the number of retransmission, but this
* must still be defined because this radio declares
* IEEE802154_CAP_FRAME_RETRANS */
return -ENOTSUP;
}
static const ieee802154_radio_ops_t mrf24j40_ops = {
.caps = IEEE802154_CAP_24_GHZ
| IEEE802154_CAP_IRQ_TX_DONE
| IEEE802154_CAP_FRAME_RETRANS
| IEEE802154_CAP_FRAME_RETRANS_INFO
| IEEE802154_CAP_PHY_OQPSK
| IEEE802154_CAP_REG_RETENTION,
.write = _write,
.read = _read,
.request_on = _request_on,
.confirm_on = _confirm_on,
.len = _len,
.off = _off,
.request_op = _request_op,
.confirm_op = _confirm_op,
.set_cca_threshold = _set_cca_threshold,
.set_cca_mode = _set_cca_mode,
.config_phy = _config_phy,
.set_csma_params = _set_csma_params,
.config_addr_filter = _config_addr_filter,
.config_src_addr_match = _config_src_addr_match,
.set_frame_filter_mode = _set_frame_filter_mode,
.set_frame_retrans = _set_frame_retrans,
};