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

309 lines
9.3 KiB
C

/*
* Copyright (C) 2017 SKF AB
*
* 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_kw41zrf
* @{
* @file
* @brief get/set functionality of kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @}
*/
#include <errno.h>
#include <string.h>
#include "log.h"
#include "cpu.h"
#include "byteorder.h"
#include "kw41zrf.h"
#include "kw41zrf_intern.h"
#include "kw41zrf_getset.h"
#include "vendor/MKW41Z4.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define KW41ZRF_NUM_CHANNEL (KW41ZRF_MAX_CHANNEL - KW41ZRF_MIN_CHANNEL + 1)
/* Lookup table for PA_PWR register */
/* Source: KW41Z data sheet, 5.3 Transmit and PLL Feature Summary,
* Table 8. Transmit Output Power as a function of PA_POWER[5:0] */
static const uint8_t tx_power_dbm_to_pa_pwr[29] = {
4, 4, 4, 4, /* -19:-16 dBm */
6, 6, /* -15:-14 dBm */
8, 8, /* -13:-12 dBm */
10, 10, /* -11:-10 dBm */
12, /* -9 dBm */
14, /* -8 dBm */
16, /* -7 dBm */
18, /* -6 dBm */
20, /* -5 dBm */
22, /* -4 dBm */
26, /* -3 dBm */
28, /* -2 dBm */
34, /* -1 dBm */
38, /* 0 dBm */
42, /* 1 dBm */
48, /* 2 dBm */
56, /* 3 dBm */
62, /* 4 dBm */
};
void kw41zrf_set_tx_power(kw41zrf_t *dev, int16_t txpower_dbm)
{
if (txpower_dbm < KW41ZRF_OUTPUT_POWER_MIN) {
txpower_dbm = KW41ZRF_OUTPUT_POWER_MIN;
}
else if (txpower_dbm > KW41ZRF_OUTPUT_POWER_MAX) {
txpower_dbm = KW41ZRF_OUTPUT_POWER_MAX;
}
ZLL->PA_PWR = tx_power_dbm_to_pa_pwr[txpower_dbm - KW41ZRF_OUTPUT_POWER_MIN];
DEBUG("[kw41zrf] set txpower to: %d\n", txpower_dbm);
dev->tx_power = txpower_dbm;
}
int16_t kw41zrf_get_txpower(kw41zrf_t *dev)
{
return dev->tx_power;
}
uint8_t kw41zrf_get_channel(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->CHANNEL_NUM0 & ZLL_CHANNEL_NUM0_CHANNEL_NUM0_MASK)
>> ZLL_CHANNEL_NUM0_CHANNEL_NUM0_SHIFT;
}
uint16_t kw41zrf_get_pan(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->MACSHORTADDRS0 & ZLL_MACSHORTADDRS0_MACPANID0_MASK)
>> ZLL_MACSHORTADDRS0_MACPANID0_SHIFT;
}
int kw41zrf_set_channel(kw41zrf_t *dev, uint8_t channel)
{
(void) dev;
if (channel < KW41ZRF_MIN_CHANNEL || channel > KW41ZRF_MAX_CHANNEL) {
LOG_ERROR("[kw41zrf] Invalid channel %u\n", channel);
return -EINVAL;
}
ZLL->CHANNEL_NUM0 = channel;
DEBUG("[kw41zrf] set channel to %u\n", channel);
return 0;
}
void kw41zrf_set_pan(kw41zrf_t *dev, uint16_t pan)
{
(void) dev;
ZLL->MACSHORTADDRS0 = (ZLL->MACSHORTADDRS0
& ~ZLL_MACSHORTADDRS0_MACPANID0_MASK) |
ZLL_MACSHORTADDRS0_MACPANID0(pan);
DEBUG("[kw41zrf] set pan to: 0x%x\n", pan);
}
void kw41zrf_set_addr_short(kw41zrf_t *dev, const network_uint16_t *addr)
{
(void) dev;
/* radio hardware stores this in little endian */
ZLL->MACSHORTADDRS0 = (ZLL->MACSHORTADDRS0
& ~ZLL_MACSHORTADDRS0_MACSHORTADDRS0_MASK) |
ZLL_MACSHORTADDRS0_MACSHORTADDRS0(byteorder_swaps(
addr->u16));
}
void kw41zrf_set_addr_long(kw41zrf_t *dev, const eui64_t *addr)
{
(void) dev;
ZLL->MACLONGADDRS0_LSB = addr->uint32[0].u32;
ZLL->MACLONGADDRS0_MSB = addr->uint32[1].u32;
}
void kw41zrf_get_addr_short(kw41zrf_t *dev, network_uint16_t *addr)
{
(void) dev;
addr->u16 = (ZLL->MACSHORTADDRS0 & ZLL_MACSHORTADDRS0_MACSHORTADDRS0_MASK) >>
ZLL_MACSHORTADDRS0_MACSHORTADDRS0_SHIFT;
/* radio hardware stores this in little endian */
addr->u16 = byteorder_swaps(addr->u16);
}
void kw41zrf_get_addr_long(kw41zrf_t *dev, eui64_t *addr)
{
(void) dev;
addr->uint32[0] = (network_uint32_t)ZLL->MACLONGADDRS0_LSB;
addr->uint32[1] = (network_uint32_t)ZLL->MACLONGADDRS0_MSB;
}
int8_t kw41zrf_get_cca_threshold(kw41zrf_t *dev)
{
(void) dev;
uint8_t tmp = (ZLL->CCA_LQI_CTRL & ZLL_CCA_LQI_CTRL_CCA1_THRESH_MASK) >>
ZLL_CCA_LQI_CTRL_CCA1_THRESH_SHIFT;
return (int8_t)tmp;
}
void kw41zrf_set_cca_threshold(kw41zrf_t *dev, int8_t value)
{
(void) dev;
ZLL->CCA_LQI_CTRL = (ZLL->CCA_LQI_CTRL & ~ZLL_CCA_LQI_CTRL_CCA1_THRESH_MASK) |
ZLL_CCA_LQI_CTRL_CCA1_THRESH(value);
}
void kw41zrf_set_cca_mode(kw41zrf_t *dev, uint8_t mode)
{
(void) dev;
ZLL->PHY_CTRL = (ZLL->PHY_CTRL & ~ZLL_PHY_CTRL_CCATYPE_MASK) |
ZLL_PHY_CTRL_CCATYPE(mode);
}
uint8_t kw41zrf_get_cca_mode(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->PHY_CTRL & ZLL_PHY_CTRL_CCATYPE_MASK) >> ZLL_PHY_CTRL_CCATYPE_SHIFT;
}
int8_t kw41zrf_get_ed_level(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->LQI_AND_RSSI & ZLL_LQI_AND_RSSI_CCA1_ED_FNL_MASK)
>> ZLL_LQI_AND_RSSI_CCA1_ED_FNL_SHIFT;
}
void kw41zrf_set_option(kw41zrf_t *dev, uint8_t option, uint8_t state)
{
DEBUG("[kw41zrf] set option 0x%04x to %x\n", option, state);
if (kw41zrf_is_dsm()) {
/* Transceiver is sleeping */
switch (option) {
/* Modifying these options require that the transceiver is not in
* deep sleep mode */
case KW41ZRF_OPT_CSMA:
case KW41ZRF_OPT_PROMISCUOUS:
case KW41ZRF_OPT_AUTOACK:
case KW41ZRF_OPT_ACK_PENDING:
case KW41ZRF_OPT_TELL_RX_START:
LOG_ERROR("[kw41zrf] Attempt to modify option %04x while radio is sleeping\n",
(unsigned) option);
assert(0);
return;
default:
break;
}
}
/* set option field */
if (state) {
dev->flags |= option;
/* trigger option specific actions */
switch (option) {
case KW41ZRF_OPT_CSMA:
DEBUG("[kw41zrf] enable: CSMA\n");
bit_set32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_CCABFRTX_SHIFT);
break;
case KW41ZRF_OPT_PROMISCUOUS:
DEBUG("[kw41zrf] enable: PROMISCUOUS\n");
/* enable promiscuous mode */
bit_set32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_PROMISCUOUS_SHIFT);
/* auto ACK is always disabled in promiscuous mode by the hardware */
break;
case KW41ZRF_OPT_AUTOACK:
DEBUG("[kw41zrf] enable: AUTOACK\n");
bit_set32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_AUTOACK_SHIFT);
break;
case KW41ZRF_OPT_ACK_PENDING:
DEBUG("[kw41zrf] enable: PENDING_BIT\n");
bit_set32(&ZLL->SAM_TABLE, ZLL_SAM_TABLE_ACK_FRM_PND_SHIFT);
break;
case KW41ZRF_OPT_TELL_RX_START:
DEBUG("[kw41zrf] enable: TELL_RX_START\n");
bit_clear32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_RX_WMRK_MSK_SHIFT);
break;
case KW41ZRF_OPT_TELL_RX_END:
DEBUG("[kw41zrf] enable: TELL_RX_END\n");
break;
case KW41ZRF_OPT_TELL_TX_END:
DEBUG("[kw41zrf] enable: TELL_TX_END\n");
break;
case KW41ZRF_OPT_TELL_TX_START:
DEBUG("[kw41zrf] enable: TELL_TX_START (ignored)\n");
default:
/* do nothing */
break;
}
}
else {
dev->flags &= ~(option);
/* trigger option specific actions */
switch (option) {
case KW41ZRF_OPT_CSMA:
DEBUG("[kw41zrf] disable: CSMA\n");
bit_clear32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_CCABFRTX_SHIFT);
break;
case KW41ZRF_OPT_PROMISCUOUS:
DEBUG("[kw41zrf] disable: PROMISCUOUS\n");
/* disable promiscuous mode */
bit_clear32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_PROMISCUOUS_SHIFT);
break;
case KW41ZRF_OPT_AUTOACK:
DEBUG("[kw41zrf] disable: AUTOACK\n");
bit_clear32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_AUTOACK_SHIFT);
break;
case KW41ZRF_OPT_ACK_PENDING:
DEBUG("[kw41zrf] disable: PENDING_BIT\n");
bit_clear32(&ZLL->SAM_TABLE, ZLL_SAM_TABLE_ACK_FRM_PND_SHIFT);
break;
case KW41ZRF_OPT_TELL_RX_START:
DEBUG("[kw41zrf] disable: TELL_RX_START\n");
bit_set32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_RX_WMRK_MSK_SHIFT);
break;
case KW41ZRF_OPT_TELL_RX_END:
DEBUG("[kw41zrf] disable: TELL_RX_END\n");
break;
case KW41ZRF_OPT_TELL_TX_END:
DEBUG("[kw41zrf] disable: TELL_TX_END\n");
break;
case KW41ZRF_OPT_TELL_TX_START:
DEBUG("[kw41zrf] disable: TELL_TX_START (ignored)\n");
default:
/* do nothing */
break;
}
}
}
void kw41zrf_set_rx_watermark(kw41zrf_t *dev, uint8_t value)
{
(void) dev;
ZLL->RX_WTR_MARK = ZLL_RX_WTR_MARK_RX_WTR_MARK(value);
}