/* * 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 * @} */ #include #include #include #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: 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; 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; 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); }