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

404 lines
12 KiB
C

/*
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
*
* 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_nrf24l01p_ng
* @{
*
* @file
* @brief Implementation of the public NRF24L01+ (NG) device interface
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
* @}
*/
#include <errno.h>
#include <string.h>
#define ENABLE_DEBUG 0
#include "debug.h"
#include "kernel_defines.h"
#include "nrf24l01p_ng_netdev.h"
#include "nrf24l01p_ng_constants.h"
#include "nrf24l01p_ng_communication.h"
#include "nrf24l01p_ng_registers.h"
#include "nrf24l01p_ng_states.h"
#if IS_USED(MODULE_NRF24L01P_NG_DIAGNOSTICS)
#include "nrf24l01p_ng_diagnostics.h"
#endif
#define NRF24L01P_NG_REG_RX_ADDR_PX(x) (NRF24L01P_NG_REG_RX_ADDR_P0 + (x))
#define NRF24L01P_NG_REG_RX_PW_PX(x) (NRF24L01P_NG_REG_RX_PW_P0 + (x))
int nrf24l01p_ng_setup(nrf24l01p_ng_t *dev,
const nrf24l01p_ng_params_t *params,
uint8_t index)
{
assert(dev);
assert(params);
memset((char *)dev + sizeof(netdev_t), 0x00,
sizeof(nrf24l01p_ng_t) - sizeof(netdev_t));
dev->state = NRF24L01P_NG_STATE_UNDEFINED;
dev->idle_state = NRF24L01P_NG_STATE_RX_MODE;
dev->params = *params;
dev->netdev.driver = &nrf24l01p_ng_driver;
netdev_register(&dev->netdev, NETDEV_NRF24L01P_NG, index);
return 0;
}
int nrf24l01p_ng_set_enable_pipe(nrf24l01p_ng_t *dev, nrf24l01p_ng_pipe_t pipe,
bool enable)
{
assert(dev);
if (pipe >= NRF24L01P_NG_PX_NUM_OF) {
return -EINVAL;
}
uint8_t en_aa = (1 << pipe);
uint8_t dynpd = (1 << pipe);
uint8_t en_rx_addr = (1 << pipe);
nrf24l01p_ng_acquire(dev);
if (enable) {
nrf24l01p_ng_reg8_set(dev, NRF24L01P_NG_REG_EN_AA, &en_aa);
nrf24l01p_ng_reg8_set(dev, NRF24L01P_NG_REG_DYNPD, &dynpd);
nrf24l01p_ng_reg8_set(dev, NRF24L01P_NG_REG_EN_RXADDR, &en_rx_addr);
}
else {
nrf24l01p_ng_reg8_clear(dev, NRF24L01P_NG_REG_EN_AA, &en_aa);
nrf24l01p_ng_reg8_clear(dev, NRF24L01P_NG_REG_DYNPD, &dynpd);
nrf24l01p_ng_reg8_clear(dev, NRF24L01P_NG_REG_EN_RXADDR, &en_rx_addr);
}
nrf24l01p_ng_release(dev);
return 0;
}
int nrf24l01p_ng_get_enable_pipe(nrf24l01p_ng_t *dev, nrf24l01p_ng_pipe_t pipe,
bool* enable)
{
assert(dev);
if (pipe >= NRF24L01P_NG_PX_NUM_OF) {
return -EINVAL;
}
uint8_t en_rx_addr;
nrf24l01p_ng_acquire(dev);
nrf24l01p_ng_read_reg(dev, NRF24L01P_NG_REG_EN_RXADDR, &en_rx_addr, 1);
nrf24l01p_ng_release(dev);
*enable = !!(en_rx_addr & (1 << pipe));
return 0;
}
int nrf24l01p_ng_set_air_data_rate(nrf24l01p_ng_t *dev,
nrf24l01p_ng_rfdr_t data_rate)
{
assert(dev);
if (data_rate >= NRF24L01P_NG_RF_DR_NUM_OF) {
return -EINVAL;
}
switch (dev->state) {
case NRF24L01P_NG_STATE_POWER_DOWN:
case NRF24L01P_NG_STATE_STANDBY_1:
case NRF24L01P_NG_STATE_RX_MODE:
break;
default:
return -EAGAIN;
}
uint8_t rf_setup = NRF24L01P_NG_FLG_RF_DR(data_rate);
nrf24l01p_ng_acquire(dev);
nrf24l01p_ng_reg8_mod(dev, NRF24L01P_NG_REG_RF_SETUP,
NRF24L01P_NG_MSK_RF_DR, &rf_setup);
nrf24l01p_ng_release(dev);
dev->params.config.cfg_data_rate = data_rate;
return 0;
}
uint16_t nrf24l01p_ng_get_air_data_rate(const nrf24l01p_ng_t *dev,
nrf24l01p_ng_rfdr_t *data_rate)
{
assert(dev);
if (data_rate) {
*data_rate = dev->params.config.cfg_data_rate;
}
return nrf24l01p_ng_etoval_rfdr(dev->params.config.cfg_data_rate);
}
int nrf24l01p_ng_set_crc(nrf24l01p_ng_t *dev, nrf24l01p_ng_crc_t crc)
{
assert(dev);
if (crc > NRF24L01P_NG_CRC_2BYTE) {
return -EINVAL;
}
if (crc == NRF24L01P_NG_CRC_0BYTE) {
return -ENOTSUP;
}
switch (dev->state) {
case NRF24L01P_NG_STATE_POWER_DOWN:
case NRF24L01P_NG_STATE_STANDBY_1:
case NRF24L01P_NG_STATE_RX_MODE:
break;
default:
return -EAGAIN;
}
uint8_t config = NRF24L01P_NG_FLG_CRCO(crc);
nrf24l01p_ng_acquire(dev);
nrf24l01p_ng_reg8_mod(dev, NRF24L01P_NG_REG_CONFIG, NRF24L01P_NG_MSK_CRC,
&config);
nrf24l01p_ng_release(dev);
dev->params.config.cfg_crc = crc;
return 0;
}
uint8_t nrf24l01p_ng_get_crc(const nrf24l01p_ng_t *dev,
nrf24l01p_ng_crc_t *crc)
{
assert(dev);
if (crc) {
*crc = dev->params.config.cfg_crc;
}
return nrf24l01p_ng_etoval_crc(dev->params.config.cfg_crc);
}
int nrf24l01p_ng_set_tx_power(nrf24l01p_ng_t *dev,
nrf24l01p_ng_tx_power_t power)
{
assert(dev);
if (power >= NRF24L01P_NG_TX_POWER_NUM_OF) {
return -EINVAL;
}
switch (dev->state) {
case NRF24L01P_NG_STATE_POWER_DOWN:
case NRF24L01P_NG_STATE_STANDBY_1:
case NRF24L01P_NG_STATE_RX_MODE:
break;
default:
return -EAGAIN;
}
uint8_t rf_setup = NRF24L01P_NG_FLG_RF_PWR(power);
nrf24l01p_ng_acquire(dev);
nrf24l01p_ng_reg8_mod(dev, NRF24L01P_NG_REG_RF_SETUP,
NRF24L01P_NG_MSK_RF_PWR, &rf_setup);
nrf24l01p_ng_release(dev);
dev->params.config.cfg_tx_power = power;
return 0;
}
int8_t nrf24l01p_ng_get_tx_power(const nrf24l01p_ng_t *dev,
nrf24l01p_ng_tx_power_t *power)
{
assert(dev);
if (power) {
*power = dev->params.config.cfg_tx_power;
}
return nrf24l01p_ng_etoval_tx_power(dev->params.config.cfg_tx_power);
}
int nrf24l01p_ng_set_channel(nrf24l01p_ng_t *dev, uint8_t channel)
{
assert(dev);
if (channel >= NRF24L01P_NG_NUM_CHANNELS) {
return -EINVAL;
}
switch (dev->state) {
case NRF24L01P_NG_STATE_POWER_DOWN:
case NRF24L01P_NG_STATE_STANDBY_1:
case NRF24L01P_NG_STATE_RX_MODE:
break;
default:
return -EAGAIN;
}
uint8_t rf_ch = NRF24L01P_NG_FLG_RF_CH(channel);
nrf24l01p_ng_acquire(dev);
nrf24l01p_ng_reg8_mod(dev, NRF24L01P_NG_REG_RF_CH,
NRF24L01P_NG_MSK_RF_CH, &rf_ch);
nrf24l01p_ng_release(dev);
dev->params.config.cfg_channel = channel;
return 0;
}
uint8_t nrf24l01p_ng_get_channel(const nrf24l01p_ng_t *dev)
{
assert(dev);
return dev->params.config.cfg_channel;
}
int nrf24l01p_ng_set_rx_address(nrf24l01p_ng_t *dev, const uint8_t *addr,
nrf24l01p_ng_pipe_t pipe)
{
assert(dev);
assert(addr);
if (pipe >= NRF24L01P_NG_PX_NUM_OF) {
return -EINVAL;
}
switch (dev->state) {
case NRF24L01P_NG_STATE_POWER_DOWN:
case NRF24L01P_NG_STATE_STANDBY_1:
case NRF24L01P_NG_STATE_RX_MODE:
break;
default:
return -EAGAIN;
}
nrf24l01p_ng_acquire(dev);
if (pipe == NRF24L01P_NG_P0) {
nrf24l01p_ng_write_reg(dev, NRF24L01P_NG_REG_RX_ADDR_PX(pipe),
addr, NRF24L01P_NG_ADDR_WIDTH);
memcpy(NRF24L01P_NG_ADDR_P0(dev), addr, NRF24L01P_NG_ADDR_WIDTH);
}
else if (pipe == NRF24L01P_NG_P1) {
nrf24l01p_ng_write_reg(dev, NRF24L01P_NG_REG_RX_ADDR_PX(pipe),
addr, NRF24L01P_NG_ADDR_WIDTH);
memcpy(NRF24L01P_NG_ADDR_P1(dev), addr, NRF24L01P_NG_ADDR_WIDTH);
}
else {
nrf24l01p_ng_write_reg(dev, NRF24L01P_NG_REG_RX_ADDR_PX(pipe),
addr, 1);
NRF24L01P_NG_ADDR_PX_LSB(dev, pipe) = *addr;
}
nrf24l01p_ng_release(dev);
return 0;
}
int nrf24l01p_ng_get_rx_address(const nrf24l01p_ng_t *dev, uint8_t *addr,
nrf24l01p_ng_pipe_t pipe)
{
assert(dev);
assert(addr);
if (pipe >= NRF24L01P_NG_PX_NUM_OF) {
return -EINVAL;
}
if (pipe == NRF24L01P_NG_P0) {
memcpy(addr, NRF24L01P_NG_ADDR_P0(dev), NRF24L01P_NG_ADDR_WIDTH);
}
else {
memcpy(addr, NRF24L01P_NG_ADDR_P1(dev), NRF24L01P_NG_ADDR_WIDTH);
if (pipe > NRF24L01P_NG_P1) {
addr[NRF24L01P_NG_ADDR_WIDTH - 1] =
NRF24L01P_NG_ADDR_PX_LSB(dev, pipe);
}
}
return NRF24L01P_NG_ADDR_WIDTH;
}
int nrf24l01p_ng_set_max_retransm(nrf24l01p_ng_t *dev, uint8_t max_rt)
{
assert(dev);
if (max_rt > NRF24L01P_NG_MAX_RETRANSMISSIONS) {
return -EINVAL;
}
switch (dev->state) {
case NRF24L01P_NG_STATE_POWER_DOWN:
case NRF24L01P_NG_STATE_STANDBY_1:
case NRF24L01P_NG_STATE_RX_MODE:
break;
default:
return -EAGAIN;
}
uint8_t setup_retr = NRF24L01P_NG_FLG_ARC(max_rt);
nrf24l01p_ng_acquire(dev);
nrf24l01p_ng_reg8_mod(dev, NRF24L01P_NG_REG_SETUP_RETR,
NRF24L01P_NG_MSK_ARC, &setup_retr);
nrf24l01p_ng_release(dev);
dev->params.config.cfg_max_retr = max_rt;
return 0;
}
uint8_t nrf24l01p_ng_get_max_retransm(const nrf24l01p_ng_t *dev)
{
assert(dev);
return dev->params.config.cfg_max_retr;
}
int nrf24l01p_ng_set_retransm_delay(nrf24l01p_ng_t *dev,
nrf24l01p_ng_ard_t rt_delay)
{
assert(dev);
if (rt_delay >= NRF24L01P_NG_ARD_NUM_OF) {
return -EINVAL;
}
switch (dev->state) {
case NRF24L01P_NG_STATE_POWER_DOWN:
case NRF24L01P_NG_STATE_STANDBY_1:
case NRF24L01P_NG_STATE_RX_MODE:
break;
default:
return -EAGAIN;
}
uint8_t setup_retr = NRF24L01P_NG_FLG_ARD(rt_delay);
nrf24l01p_ng_acquire(dev);
nrf24l01p_ng_reg8_mod(dev, NRF24L01P_NG_REG_SETUP_RETR,
NRF24L01P_NG_MSK_ARD, &setup_retr);
nrf24l01p_ng_release(dev);
dev->params.config.cfg_retr_delay = rt_delay;
return 0;
}
uint16_t nrf24l01p_ng_get_retransm_delay(const nrf24l01p_ng_t *dev,
nrf24l01p_ng_ard_t *rt_delay)
{
assert(dev);
if (rt_delay) {
*rt_delay = dev->params.config.cfg_retr_delay;
}
return nrf24l01p_ng_etoval_ard(dev->params.config.cfg_retr_delay);
}
int nrf24l01p_ng_set_state(nrf24l01p_ng_t *dev, nrf24l01p_ng_state_t state)
{
switch (dev->state) {
case NRF24L01P_NG_STATE_POWER_DOWN:
case NRF24L01P_NG_STATE_STANDBY_1:
case NRF24L01P_NG_STATE_RX_MODE:
break;
default:
return -EAGAIN;
}
nrf24l01p_ng_state_t old = dev->state;
nrf24l01p_ng_acquire(dev);
if (state == NRF24L01P_NG_STATE_POWER_DOWN) {
if (dev->state != NRF24L01P_NG_STATE_POWER_DOWN) {
nrf24l01p_ng_transition_to_power_down(dev);
}
}
else if (state == NRF24L01P_NG_STATE_STANDBY_1) {
if (dev->state != NRF24L01P_NG_STATE_STANDBY_1) {
nrf24l01p_ng_transition_to_standby_1(dev);
}
}
else if (state == NRF24L01P_NG_STATE_RX_MODE) {
if (dev->state != NRF24L01P_NG_STATE_RX_MODE) {
if (state != NRF24L01P_NG_STATE_STANDBY_1) {
nrf24l01p_ng_transition_to_standby_1(dev);
}
nrf24l01p_ng_transition_to_rx_mode(dev);
}
}
else {
nrf24l01p_ng_release(dev);
return -ENOTSUP;
}
nrf24l01p_ng_release(dev);
return (int)old;
}
nrf24l01p_ng_state_t nrf24l01p_ng_get_state(const nrf24l01p_ng_t *dev)
{
assert(dev);
return dev->state;
}
#if IS_USED(MODULE_NRF24L01P_NG_DIAGNOSTICS)
void nrf24l01p_ng_print_all_regs(nrf24l01p_ng_t *dev)
{
nrf24l01p_ng_acquire(dev);
nrf24l01p_ng_diagnostics_print_all_regs(dev);
nrf24l01p_ng_release(dev);
}
void nrf24l01p_ng_print_dev_info(const nrf24l01p_ng_t *dev)
{
nrf24l01p_ng_diagnostics_print_dev_info(dev);
}
#endif