1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/mrf24j40/mrf24j40_getset.c

424 lines
16 KiB
C

/*
* Copyright (C) 2017 Neo Nenaco <neo@nenaco.de>
* Copyright (C) 2016 Koen Zandberg <koen@bergzand.net>
*
* 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 drivers_mrf24j40
* @{
*
* @file
* @brief Getter and setter functions for the MRF24J40 drivers
*
* @author Koen Zandberg <koen@bergzand.net>
* @author Neo Nenaco <neo@nenaco.de>
*
* @}
*/
#include "byteorder.h"
#include "mrf24j40.h"
#include "mrf24j40_internal.h"
#include "mrf24j40_registers.h"
#include "ztimer.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/* Values of RFCON3 - Address: 0x203
* 0b00000000 -> 0dB -> 0
* 0b00001000 -> -0.5dB -> 0
* 0b00010000 -> -1.2dB -> -1
* 0b00011000 -> -1.9dB -> -2
* 0b00100000 -> -2.8dB -> -3
* 0b00101000 -> -3.7dB -> -4
* 0b00110000 -> -4.9dB -> -5
* 0b00111000 -> -6.3dB -> -6
* 0b01000000 -> -10dB -> -10
* 0b01001000 -> -10.5dB-> -10
* 0b01010000 -> -11.2dB-> -11
* 0b01011000 -> -11.9dB-> -12
* 0b01100000 -> -12.8dB-> -13
* 0b01101000 -> -13.7dB-> -14
* 0b01110000 -> -14.9dB-> -15
* 0b01111000 -> -16.3dB-> -16
* 0b10000000 -> -20dB -> -20
* 0b10001000 -> -20.5dB-> -20
* 0b10010000 -> -21.2dB-> -21
* 0b10011000 -> -21.9dB-> -22
* 0b10100000 -> -22.8dB-> -23
* 0b10101000 -> -23.7dB-> -24
* 0b10110000 -> -24.9dB-> -25
* 0b10111000 -> -26.3dB-> -26
* 0b11000000 -> -30dB -> -30
* 0b11001000 -> -30.5dB-> -30
* 0b11010000 -> -31.2dB-> -31
* 0b11011000 -> -31.9dB-> -32
* 0b11100000 -> -32.8dB-> -33
* 0b11101000 -> -33.7dB-> -34
* 0b11110000 -> -34.9dB-> -35
* 0b11111000 -> -36.3dB-> -36
*/
static const uint8_t dbm_to_tx_pow[] = { 0x00, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x38, 0x38, 0x40,
0x40, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x78, 0x78, 0x80,
0x80, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xb8, 0xb8, 0xc0,
0xc0, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8 };
/* take a look onto datasheet table 3-8 */
static const int8_t dBm_value[] = { -90, -89, -88, -88, -87, -87, -87, -87, \
-86, -86, -86, -86, -85, -85, -85, -85, \
-84, -84, -84, -84, -84, -84, -83, -83, \
-83, -83, -82, -82, -82, -82, -81, -81, \
-81, -81, -81, -80, -80, -80, -80, -80, \
-80, -79, -79, -79, -79, -79, -78, -78, \
-78, -78, -78, -77, -77, -77, -77, -77, \
-76, -76, -76, -76, -76, -75, -75, -75, \
-75, -75, -75, -74, -74, -74, -74, -73, \
-73, -73, -73, -73, -72, -72, -72, -72, \
-72, -71, -71, -71, -71, -71, -70, -70, \
-70, -70, -70, -70, -70, -69, -69, -69, \
-69, -69, -68, -68, -68, -68, -68, -68, \
-68, -67, -67, -67, -67, -66, -66, -66, \
-66, -66, -66, -65, -65, -65, -65, -65, \
-64, -64, -64, -64, -63, -63, -63, -63, \
-62, -62, -62, -62, -61, -61, -61, -61, \
-60, -60, -60, -60, -60, -59, -59, -59, \
-59, -59, -58, -58, -58, -58, -58, -57, \
-57, -57, -57, -57, -57, -56, -56, -56, \
-56, -56, -56, -56, -55, -55, -55, -55, \
-54, -54, -54, -54, -54, -54, -53, -53, \
-53, -53, -53, -53, -53, -52, -52, -52, \
-52, -52, -52, -51, -51, -51, -51, -51, \
-50, -50, -50, -50, -50, -49, -49, -49, \
-49, -49, -48, -48, -48, -48, -47, -47, \
-47, -47, -47, -46, -46, -46, -46, -45, \
-45, -45, -45, -44, -44, -44, -44, -44, \
-43, -43, -43, -42, -42, -42, -42, -41, \
-41, -41, -41, -41, -41, -40, -40, -40, \
-40, -40, -39, -39, -39, -39, -39, -38, \
-38, -38, -38, -37, -37, -37, -36, -35 };
/* take a look onto datasheet table 3-8 */
static const uint8_t RSSI_value[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfa, 0xf5, \
0xef, 0xe9, 0xe4, 0xe1, 0xdd, 0xd8, 0xd4, 0xcf, 0xcb, 0xc6, \
0xc1, 0xbc, 0xb7, 0xb0, 0xaa, 0xa5, 0x9f, 0x99, 0x94, 0x8f, \
0x8a, 0x85, 0x81, 0x7d, 0x79, 0x75, 0x6f, 0x6b, 0x64, 0x5f, \
0x59, 0x53, 0x4e, 0x49, 0x44, 0x3f, 0x3a, 0x35, 0x30, 0x2b, \
0x25, 0x20, 0x1b, 0x17, 0x12, 0x0d, 0x09, 0x05, 0x02, 0x01, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static void mrf24j40_baseband_reset(mrf24j40_t *dev)
{
uint8_t softrst;
mrf24j40_reg_write_short(dev, MRF24J40_REG_SOFTRST, MRF24J40_SOFTRST_RSTBB);
do {
softrst = mrf24j40_reg_read_short(dev, MRF24J40_REG_SOFTRST);
} while (softrst != 0); /* wait until soft-reset has finished */
}
void mrf24j40_set_addr_short(mrf24j40_t *dev, uint16_t addr)
{
network_uint16_t naddr;
naddr.u16 = addr;
#ifdef MODULE_SIXLOWPAN
/* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to
* 0 for unicast addresses */
naddr.u8[0] &= 0x7F;
#endif
mrf24j40_reg_write_short(dev, MRF24J40_REG_SADRL,
naddr.u8[1]);
mrf24j40_reg_write_short(dev, MRF24J40_REG_SADRH,
naddr.u8[0]);
}
void mrf24j40_set_addr_long(mrf24j40_t *dev, const uint8_t *addr)
{
for (int i = 0; i < 8; i++) {
mrf24j40_reg_write_short(dev, MRF24J40_REG_EADR0 + i, addr[7 - i]);
}
}
void mrf24j40_set_chan(mrf24j40_t *dev, uint8_t channel)
{
uint8_t channel_value;
if ((channel < IEEE802154_CHANNEL_MIN) ||
(channel > IEEE802154_CHANNEL_MAX)) {
return;
}
/* Channel settings
* 11 -> Value = 0x03
* 12 -> Value = 0x13
* 13 -> Value = 0x23
* 14 -> Value = 0x33
* 15 -> Value = 0x43
* 16 -> Value = 0x53
* 17 -> Value = 0x63
* 18 -> Value = 0x73
* 19 -> Value = 0x83
* 20 -> Value = 0x93
* 21 -> Value = 0xA3
* 22 -> Value = 0xB3
* 23 -> Value = 0xC3
* 24 -> Value = 0xD3
* 25 -> Value = 0xE3
* 26 -> Value = 0xF3
*/
/* not using an array here because it's not starting at zero */
switch (channel) {
case 11: channel_value = 0x03;
break;
case 12: channel_value = 0x13;
break;
case 13: channel_value = 0x23;
break;
case 14: channel_value = 0x33;
break;
case 15: channel_value = 0x43;
break;
case 16: channel_value = 0x53;
break;
case 17: channel_value = 0x63;
break;
case 18: channel_value = 0x73;
break;
case 19: channel_value = 0x83;
break;
case 20: channel_value = 0x93;
break;
case 21: channel_value = 0xa3;
break;
case 22: channel_value = 0xb3;
break;
case 23: channel_value = 0xc3;
break;
case 24: channel_value = 0xd3;
break;
case 25: channel_value = 0xe3;
break;
case 26: channel_value = 0xf3;
break;
default:
return;
}
mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON0, channel_value);
/*
* Note: Perform an RF State Machine Reset (see Section 3.1 Reset)
* after a channel frequency change. Then, delay at least 192 us after
* the RF State Machine Reset, to allow the RF circuitry to calibrate.
*/
mrf24j40_reset_state_machine(dev);
}
void mrf24j40_set_pan(mrf24j40_t *dev, uint16_t pan)
{
le_uint16_t le_pan = byteorder_htols(pan);
DEBUG("pan0: %u, pan1: %u\n", le_pan.u8[0], le_pan.u8[1]);
mrf24j40_reg_write_short(dev, MRF24J40_REG_PANIDL, le_pan.u8[0]);
mrf24j40_reg_write_short(dev, MRF24J40_REG_PANIDH, le_pan.u8[1]);
}
void mrf24j40_set_txpower(mrf24j40_t *dev, int16_t txpower)
{
uint8_t txpower_reg_value;
/* positive values are better with a conversion array */
txpower = (txpower < 0) ? -1 * txpower : txpower;
txpower = (txpower > 36) ? 36 : txpower;
txpower_reg_value = dbm_to_tx_pow[txpower];
mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON3, txpower_reg_value);
}
void mrf24j40_set_csma_max_retries(mrf24j40_t *dev, int8_t retries)
{
uint8_t tmp;
/* get current register settings */
tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR);
/* clear csma bits */
tmp &= ~(MRF24J40_TXMCR_CSMA_BACKOFF_MASK);
/* apply new settings */
tmp |= (retries & MRF24J40_TXMCR_CSMA_BACKOFF_MASK);
mrf24j40_reg_write_short(dev, MRF24J40_REG_TXMCR, tmp);
}
void mrf24j40_set_cca_threshold(mrf24j40_t *dev, int8_t value)
{
/* ensure the given value is negative, since a CCA threshold > 0 is
just impossible: thus, any positive value given is considered
to be the absolute value of the actually wanted threshold */
if (value < 0) {
value = -value;
}
mrf24j40_reg_write_short(dev, MRF24J40_REG_CCAEDTH, RSSI_value[value]);
}
void mrf24j40_set_turbo(mrf24j40_t *dev, bool on)
{
uint8_t tmp;
static const uint8_t cfg[2][2] = {
{0xD0, 0x80}, /* IEEE mode */
{0x30, 0x40} /* Turbo mode */
};
mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG0, on);
/* Set Preamble Search Energy Valid Threshold */
tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_BBREG3) & 0xF;
mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG3, tmp | cfg[on][0]);
/* Set Carrier Sense Threshold */
tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_BBREG4) & 0x1F;
mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG4, tmp | cfg[on][1]);
mrf24j40_baseband_reset(dev);
}
void mrf24j40_set_option(mrf24j40_t *dev, uint16_t option, bool state)
{
uint8_t tmp;
DEBUG("set option %i to %i\n", option, state);
/* set option field */
if (state) {
/* trigger option specific actions */
switch (option) {
case MRF24J40_OPT_CSMA:
DEBUG("[mrf24j40] opt: enabling CSMA mode (4 retries, macMinBE: 3 max BE: 5)\n");
/* Initialize CSMA seed with hardware address */
tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR);
tmp &= ~MRF24J40_TXMCR_NOCSMA;
mrf24j40_reg_write_short(dev, MRF24J40_REG_TXMCR, tmp);
break;
case MRF24J40_OPT_PROMISCUOUS:
DEBUG("[mrf24j40] opt: enabling PROMISCUOUS mode\n");
/* disable auto ACKs in promiscuous mode */
tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_RXMCR);
tmp |= MRF24J40_RXMCR_NOACKRSP;
/* enable promiscuous mode */
tmp |= MRF24J40_RXMCR_PROMI;
tmp &= ~MRF24J40_RXMCR_ERRPKT;
mrf24j40_reg_write_short(dev, MRF24J40_REG_RXMCR, tmp);
break;
case NETDEV_IEEE802154_ACK_REQ:
DEBUG("[mrf24j40] opt: enabling auto ACKs\n");
tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_RXMCR);
tmp &= ~MRF24J40_RXMCR_NOACKRSP;
mrf24j40_reg_write_short(dev, MRF24J40_REG_RXMCR, tmp);
break;
default:
/* do nothing */
break;
}
}
/* clear option field */
else {
/* trigger option specific actions */
switch (option) {
case MRF24J40_OPT_CSMA:
DEBUG("[mrf24j40] opt: disabling CSMA mode\n");
tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR);
tmp |= MRF24J40_TXMCR_NOCSMA;
/* MACMINBE<1:0>: The minimum value of the backoff exponent
* in the CSMA-CA algorithm. Note that if this value is set
* to 0, collision avoidance is disabled. */
mrf24j40_reg_write_short(dev, MRF24J40_REG_TXMCR, tmp);
break;
case MRF24J40_OPT_PROMISCUOUS:
DEBUG("[mrf24j40] opt: disabling PROMISCUOUS mode\n");
/* disable promiscuous mode */
tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_RXMCR);
tmp &= ~MRF24J40_RXMCR_PROMI;
tmp &= ~MRF24J40_RXMCR_ERRPKT;
/* re-enable AUTOACK only if the option is set */
tmp &= ~(MRF24J40_RXMCR_NOACKRSP);
mrf24j40_reg_write_short(dev, MRF24J40_REG_RXMCR, tmp);
break;
case NETDEV_IEEE802154_ACK_REQ:
DEBUG("[mrf24j40] opt: disabling auto ACKs\n");
tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_RXMCR);
tmp |= MRF24J40_RXMCR_NOACKRSP;
mrf24j40_reg_write_short(dev, MRF24J40_REG_RXMCR, tmp);
break;
default:
/* do nothing */
break;
}
}
}
void mrf24j40_sleep(mrf24j40_t *dev)
{
DEBUG("[mrf24j40] Putting into sleep mode\n");
/* disable the PA & LNA */
mrf24j40_disable_auto_pa_lna(dev);
/* Datasheet chapter 3.15.2 IMMEDIATE SLEEP AND WAKE-UP MODE */
/* First force a Power Management Reset */
mrf24j40_reg_write_short(dev, MRF24J40_REG_SOFTRST, MRF24J40_SOFTRST_RSTPWR);
/* Go to SLEEP mode */
mrf24j40_reg_write_short(dev, MRF24J40_REG_SLPACK, MRF24J40_SLPACK_SLPACK);
}
void mrf24j40_wake_up(mrf24j40_t *dev)
{
DEBUG("[mrf24j40] Waking up from sleep mode\n");
/* Wake mrf up */
mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE | MRF24J40_WAKECON_REGWAKE);
/* undocumented delay, needed for stable wakeup */
ztimer_sleep(ZTIMER_USEC, MRF24J40_DELAY_SLEEP_TOGGLE);
mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE);
/* reset state machine */
mrf24j40_reg_write_short(dev, MRF24J40_REG_RFCTL, MRF24J40_RFCTL_RFRST);
mrf24j40_reg_write_short(dev, MRF24J40_REG_RFCTL, 0x00);
/* After wake-up, delay at least 2 ms to allow 20 MHz main
* oscillator time to stabilize before transmitting or receiving.
*/
ztimer_sleep(ZTIMER_USEC, MRF24J40_WAKEUP_DELAY);
/* reset interrupts */
mrf24j40_reg_read_short(dev, MRF24J40_REG_INTSTAT);
mrf24j40_enable_auto_pa_lna(dev);
}
void mrf24j40_reset_state_machine(mrf24j40_t *dev)
{
mrf24j40_reg_write_short(dev, MRF24J40_REG_RFCTL, MRF24J40_RFCTL_RFRST);
mrf24j40_reg_write_short(dev, MRF24J40_REG_RFCTL, 0x00);
ztimer_sleep(ZTIMER_USEC, MRF24J40_STATE_RESET_DELAY); /* Delay at least 192us */
}
void mrf24j40_software_reset(mrf24j40_t *dev)
{
uint8_t softrst;
mrf24j40_reg_write_short(dev, MRF24J40_REG_SOFTRST, MRF24J40_SOFTRST_RSTPWR |
MRF24J40_SOFTRST_RSTBB |
MRF24J40_SOFTRST_RSTMAC );
do {
softrst = mrf24j40_reg_read_short(dev, MRF24J40_REG_SOFTRST);
} while (softrst != 0); /* wait until soft-reset has finished */
}
int8_t mrf24j40_dbm_from_reg(uint8_t value)
{
return dBm_value[value];
}