From cf32ff7f194134fbcbfe1e3151e5be1435049bc7 Mon Sep 17 00:00:00 2001 From: Johann Fischer <j.fischer@phytec.de> Date: Fri, 20 May 2016 17:13:31 +0200 Subject: [PATCH] drivers/kw2xrf: adapt for the netdev2 interface Adapt the kw2xrf driver for the netdev2 interface. This patch also adds overwrites.h, the header provides overwrite values for the kw2xrf PHY. --- drivers/Makefile.dep | 5 +- drivers/include/kw2xrf.h | 140 +-- drivers/kw2xrf/include/kw2xrf_getset.h | 70 ++ drivers/kw2xrf/include/kw2xrf_intern.h | 129 +++ drivers/kw2xrf/include/kw2xrf_netdev.h | 31 + drivers/kw2xrf/include/kw2xrf_reg.h | 216 +++- drivers/kw2xrf/include/kw2xrf_spi.h | 50 +- drivers/kw2xrf/include/kw2xrf_tm.h | 47 + drivers/kw2xrf/include/overwrites.h | 308 ++++++ drivers/kw2xrf/kw2xrf.c | 1311 ++---------------------- drivers/kw2xrf/kw2xrf_getset.c | 516 ++++++++++ drivers/kw2xrf/kw2xrf_intern.c | 230 +++++ drivers/kw2xrf/kw2xrf_netdev.c | 765 ++++++++++++++ drivers/kw2xrf/kw2xrf_spi.c | 112 +- drivers/kw2xrf/kw2xrf_tm.c | 181 ++++ sys/auto_init/netif/auto_init_kw2xrf.c | 24 +- 16 files changed, 2783 insertions(+), 1352 deletions(-) create mode 100644 drivers/kw2xrf/include/kw2xrf_getset.h create mode 100644 drivers/kw2xrf/include/kw2xrf_intern.h create mode 100644 drivers/kw2xrf/include/kw2xrf_netdev.h create mode 100644 drivers/kw2xrf/include/kw2xrf_tm.h create mode 100644 drivers/kw2xrf/include/overwrites.h create mode 100644 drivers/kw2xrf/kw2xrf_getset.c create mode 100644 drivers/kw2xrf/kw2xrf_intern.c create mode 100644 drivers/kw2xrf/kw2xrf_netdev.c create mode 100644 drivers/kw2xrf/kw2xrf_tm.c diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 8bcb374a09..350907e237 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -116,8 +116,11 @@ endif ifneq (,$(filter kw2xrf,$(USEMODULE))) USEMODULE += ieee802154 USEMODULE += netif + USEMODULE += netdev2_ieee802154 ifneq (,$(filter gnrc_netdev_default,$(USEMODULE))) - USEMODULE += gnrc_nomac + # XXX: this can be modelled as a dependency for gnrc_netdev_default as soon + # as all drivers are ported to netdev2 + USEMODULE += gnrc_netdev2 endif endif diff --git a/drivers/include/kw2xrf.h b/drivers/include/kw2xrf.h index c7682ba1b7..1e328ad464 100644 --- a/drivers/include/kw2xrf.h +++ b/drivers/include/kw2xrf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Phytec Messtechnik GmbH + * Copyright (C) 2016 Phytec Messtechnik GmbH * * 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 @@ -8,12 +8,12 @@ /** * @defgroup drivers_kw2xrf kw2x radio-driver - * @ingroup drivers_netdev - * @brief Device driver for the Freescale KW2xD radio + * @ingroup drivers_netdev_netdev2 + * @brief Device driver for the NXP CR20A and KW2xD radios * @{ * * @file - * @brief Interface definition for the KW2xD device driver + * @brief Interface definition for the kw2xrf driver * * @author Johann Fischer <j.fischer@phytec.de> * @author Jonas Remmert <j.remmert@phytec.de> @@ -27,8 +27,9 @@ #include "board.h" #include "periph/spi.h" #include "periph/gpio.h" -#include "net/gnrc/netdev.h" -#include "net/ieee802154.h" +#include "net/netdev2.h" +#include "net/netdev2/ieee802154.h" +#include "net/gnrc/nettype.h" #ifdef __cplusplus extern "C" { @@ -39,24 +40,15 @@ extern "C" { */ #define KW2XRF_MAX_PKT_LENGTH (IEEE802154_FRAME_LEN_MAX) -/** - * @brief Default protocol for data that is coming in - */ -#ifdef MODULE_GNRC_SIXLOWPAN -#define KW2XRF_DEFAULT_PROTOCOL GNRC_NETTYPE_SIXLOWPAN -#else -#define KW2XRF_DEFAULT_PROTOCOL GNRC_NETTYPE_UNDEF -#endif - /** * @brief Default short address used after initialization */ -#define KW2XRF_DEFAULT_SHORT_ADDR (0x0002) +#define KW2XRF_DEFAULT_SHORT_ADDR (0x0042) /** * @brief Default short address used after initialization */ -#define KW2XRF_DEFAULT_ADDR_LONG (0x0000000000000000) +#define KW2XRF_DEFAULT_ADDR_LONG (0x0000000DEADCAB1E) /** * @brief Default PAN ID used after initialization @@ -72,6 +64,8 @@ extern "C" { #ifndef KW2XRF_DEFAULT_CHANNEL #define KW2XRF_DEFAULT_CHANNEL (IEEE802154_DEFAULT_CHANNEL) #endif +#define KW2XRF_MIN_CHANNEL (11U) +#define KW2XRF_MAX_CHANNEL (26U) /** * @brief Default TX_POWER in dbm used after initialization @@ -81,79 +75,99 @@ extern "C" { /** * @brief Maximum output power of the kw2x device in dBm */ -#define MKW2XDRF_OUTPUT_POWER_MAX (8) +#define MKW2XDRF_OUTPUT_POWER_MAX (8) /** * @brief Minimum output power of the kw2x device in dBm */ -#define MKW2XDRF_OUTPUT_POWER_MIN (-35) +#define MKW2XDRF_OUTPUT_POWER_MIN (-35) /** * @brief Internal device option flags + * + * `0x00ff` is reserved for general IEEE 802.15.4 flags + * (see @ref netdev2_ieee802154_t) + * * @{ */ -#define KW2XRF_OPT_AUTOACK (0x0001) /**< auto ACKs active */ -#define KW2XRF_OPT_CSMA (0x0002) /**< CSMA active */ -#define KW2XRF_OPT_PROMISCUOUS (0x0004) /**< promiscuous mode active */ -#define KW2XRF_OPT_PRELOADING (0x0008) /**< preloading enabled */ -#define KW2XRF_OPT_TELL_TX_START (0x0010) /**< notify MAC layer on TX start */ -#define KW2XRF_OPT_TELL_TX_END (0x0020) /**< notify MAC layer on TX finished */ -#define KW2XRF_OPT_TELL_RX_START (0x0040) /**< notify MAC layer on RX start */ -#define KW2XRF_OPT_TELL_RX_END (0x0080) /**< notify MAC layer on RX finished */ -#define KW2XRF_OPT_RAWDUMP (0x0100) /**< pass RAW frame data to upper layer */ -#define KW2XRF_OPT_SRC_ADDR_LONG (0x0200) /**< send data using long source address */ -#define KW2XRF_OPT_USE_SRC_PAN (0x0400) /**< do not compress source PAN ID */ +#define KW2XRF_OPT_SRC_ADDR_LONG (NETDEV2_IEEE802154_SRC_MODE_LONG) /**< legacy define */ +#define KW2XRF_OPT_RAWDUMP (NETDEV2_IEEE802154_RAW) /**< legacy define */ +#define KW2XRF_OPT_ACK_REQ (NETDEV2_IEEE802154_ACK_REQ) /**< legacy define */ + +#define KW2XRF_OPT_AUTOCCA (0x0100) /**< CCA befor TX active */ +#define KW2XRF_OPT_PROMISCUOUS (0x0200) /**< promiscuous mode + * active */ +#define KW2XRF_OPT_PRELOADING (0x0400) /**< preloading enabled */ +#define KW2XRF_OPT_TELL_TX_START (0x0800) /**< notify MAC layer on TX + * start */ +#define KW2XRF_OPT_TELL_TX_END (0x1000) /**< notify MAC layer on TX + * finished */ +#define KW2XRF_OPT_TELL_RX_START (0x2000) /**< notify MAC layer on RX + * start */ +#define KW2XRF_OPT_TELL_RX_END (0x4000) /**< notify MAC layer on RX + * finished */ +#define KW2XRF_OPT_AUTOACK (0x8000) /**< enable automatically ACK + * for incommint packet */ /** @} */ /** - * @brief kw2xrf device descriptor + * @brief struct holding all params needed for device initialization + */ +typedef struct kw2xrf_params { + spi_t spi; /**< SPI bus the device is connected to */ + spi_speed_t spi_speed; /**< SPI speed to use */ + gpio_t cs_pin; /**< GPIO pin connected to chip select */ + gpio_t int_pin; /**< GPIO pin connected to the interrupt pin */ +} kw2xrf_params_t; + +/** + * @brief Device descriptor for KW2XRF radio devices + * + * @extends netdev2_ieee802154_t */ typedef struct { - /* netdev fields */ - gnrc_netdev_driver_t const *driver; /**< Pointer to the devices interface */ - gnrc_netdev_event_cb_t event_cb; /**< Netdev event callback */ - kernel_pid_t mac_pid; /**< The driver's thread's PID */ - /* driver specific fields */ - uint8_t buf[KW2XRF_MAX_PKT_LENGTH]; /**< Buffer for incoming or outgoing packets */ - netopt_state_t state; /**< Variable to keep radio driver's state */ - uint8_t seq_nr; /**< Next packets sequence number */ - uint16_t radio_pan; /**< The PAN the radio device is using */ - uint8_t radio_channel; /**< The channel the radio device is using */ - uint8_t addr_short[2]; /**< The short address the radio device is using */ - uint8_t addr_long[8]; /**< The long address the radio device is using */ - uint16_t option; /**< Bit field to save enable/disable options */ - int8_t tx_power; /**< The current tx-power setting of the device */ - gnrc_nettype_t proto; /**< Protocol the interface speaks */ + netdev2_ieee802154_t netdev; /**< netdev2 parent struct */ + /** + * @brief device specific fields + * @{ + */ + kw2xrf_params_t params; /**< parameters for initialization */ + uint8_t buf[KW2XRF_MAX_PKT_LENGTH]; /**< Buffer for incoming or outgoing packets */ + uint8_t state; /**< current state of the radio */ + uint8_t tx_frame_len; /**< length of the current TX frame */ + uint8_t idle_state; /**< state to return to after sending */ + uint8_t pending_tx; /**< keep track of pending TX calls + this is required to know when to + return to @ref kw2xrf_t::idle_state */ + int16_t tx_power; /**< The current tx-power setting of the device */ + /** @} */ } kw2xrf_t; +/** + * @brief Setup an KW2XRF based device state + * + * @param[out] dev device descriptor + * @param[in] params parameters for device initialization + */ +void kw2xrf_setup(kw2xrf_t *dev, const kw2xrf_params_t *params); + /** * @brief Initialize the given KW2XRF device * @param[out] dev device descriptor - * @param[in] spi SPI bus the device is connected to - * @param[in] spi_clk SPI bus clock speed to use - * @param[in] cs_pin GPIO pin connected to chip select - * @param[in] int_pin GPIO pin connected to the interrupt pin + * @param[in] cb irq callback * * @return 0 on success * @return <0 on error */ -int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_clk_t spi_clk, - gpio_t cs_pin, gpio_t int_pin); +int kw2xrf_init(kw2xrf_t *dev, gpio_cb_t cb); /** - * @brief struct holding all params needed for device initialization + * @brief Configure radio with default values + * + * @param[in] dev device to reset */ -typedef struct kw2xrf_params { - spi_t spi; /**< SPI bus the device is connected to */ - spi_clk_t spi_speed; /**< SPI speed to use */ - gpio_t cs_pin; /**< GPIO pin connected to chip select */ - gpio_t int_pin; /**< GPIO pin connected to the interrupt pin */ -} kw2xrf_params_t; +void kw2xrf_reset_phy(kw2xrf_t *dev); -/** - * @brief Reference to the KW2XRF driver interface - */ -extern const gnrc_netdev_driver_t kw2xrf_driver; #ifdef __cplusplus } diff --git a/drivers/kw2xrf/include/kw2xrf_getset.h b/drivers/kw2xrf/include/kw2xrf_getset.h new file mode 100644 index 0000000000..fbc219b368 --- /dev/null +++ b/drivers/kw2xrf/include/kw2xrf_getset.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 Phytec Messtechnik GmbH + * + * 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 + * @{ + * + * @file + * @brief get/set interfaces for kw2xrf driver + * + * @author Johann Fischer <j.fischer@phytec.de> + */ + +#include "kw2xrf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void kw2xrf_set_tx_power(kw2xrf_t *dev, int16_t txpower); + +uint16_t kw2xrf_get_txpower(kw2xrf_t *dev); + +uint8_t kw2xrf_get_channel(kw2xrf_t *dev); + +int kw2xrf_set_channel(kw2xrf_t *dev, uint8_t val); + +void kw2xrf_abort_sequence(kw2xrf_t *dev); + +void kw2xrf_set_idle_sequence(kw2xrf_t *dev); + +void kw2xrf_set_sequence(kw2xrf_t *dev, kw2xrf_physeq_t seq); + +void kw2xrf_set_pan(kw2xrf_t *dev, uint16_t pan); + +void kw2xrf_set_addr_short(kw2xrf_t *dev, uint16_t addr); + +void kw2xrf_set_addr_long(kw2xrf_t *dev, uint64_t addr); + +uint16_t kw2xrf_get_addr_short(kw2xrf_t *dev); + +uint64_t kw2xrf_get_addr_long(kw2xrf_t *dev); + +int8_t kw2xrf_get_cca_threshold(kw2xrf_t *dev); + +void kw2xrf_set_cca_threshold(kw2xrf_t *dev, int8_t value); + +void kw2xrf_set_cca_mode(kw2xrf_t *dev, uint8_t mode); + +uint8_t kw2xrf_get_cca_mode(kw2xrf_t *dev); + +uint32_t kw2xrf_get_rssi(uint32_t value); + +netopt_state_t kw2xrf_get_status(kw2xrf_t *dev); + +int kw2xrf_cca(kw2xrf_t *dev); + +void kw2xrf_set_rx_watermark(kw2xrf_t *dev, uint8_t value); + +void kw2xrf_set_option(kw2xrf_t *dev, uint16_t option, bool state); + +#ifdef __cplusplus +} +#endif +/** @} */ diff --git a/drivers/kw2xrf/include/kw2xrf_intern.h b/drivers/kw2xrf/include/kw2xrf_intern.h new file mode 100644 index 0000000000..600d37d5d0 --- /dev/null +++ b/drivers/kw2xrf/include/kw2xrf_intern.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2016 Phytec Messtechnik GmbH + * + * 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 + * @{ + * + * @file + * @brief Internal function interfaces for kw2xrf driver + * + * @author Johann Fischer <j.fischer@phytec.de> + */ + +#include <stdint.h> +#include "kw2xrf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Power Modes */ +typedef enum { + KW2XRF_HIBERNATE = 0, + KW2XRF_DOZE, + KW2XRF_IDLE, + KW2XRF_AUTODOZE, +} kw2xrf_powermode_t; + +inline void kw2xrf_set_dreg_bit(kw2xrf_t *dev, uint8_t reg, uint8_t bit) +{ + uint8_t tmp = kw2xrf_read_dreg(dev, reg); + tmp |= bit; + kw2xrf_write_dreg(dev, reg, tmp); +} + +inline void kw2xrf_clear_dreg_bit(kw2xrf_t *dev, uint8_t reg, uint8_t bit) +{ + uint8_t tmp = kw2xrf_read_dreg(dev, reg); + tmp &= ~bit; + kw2xrf_write_dreg(dev, reg, tmp); +} + +/** Enable any transceiver interrupt to assert IRQ_B */ +inline void kw2xrf_enable_irq_b(kw2xrf_t *dev) +{ + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TRCV_MSK); +} + +/** Mask all transceiver interrupts to assert IRQ_B */ +inline void kw2xrf_mask_irq_b(kw2xrf_t *dev) +{ + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TRCV_MSK); +} + +void kw2xrf_disable_interrupts(kw2xrf_t *dev); + +void kw2xrf_update_overwrites(kw2xrf_t *dev); + +void kw2xrf_set_out_clk(kw2xrf_t *dev); + +void kw2xrf_set_power_mode(kw2xrf_t *dev, kw2xrf_powermode_t pm); + +int kw2xrf_can_switch_to_idle(kw2xrf_t *dev); + +typedef enum kw2xrf_timer_timebase { + KW2XRF_TIMEBASE_500000HZ = 2, + KW2XRF_TIMEBASE_250000HZ, + KW2XRF_TIMEBASE_125000HZ, + KW2XRF_TIMEBASE_62500HZ, + KW2XRF_TIMEBASE_31250HZ, + KW2XRF_TIMEBASE_15625HZ, +} kw2xrf_timer_timebase_t; + +/** + * Initialize the Event Timer Block (up counter) + * The Event Timer Block provides: + * - Abort an RX and CCA sequence at pre-determined time + * - Latches "timestamp" value during packet reception + * - Initiates timer-triggered sequences + */ +void kw2xrf_timer_init(kw2xrf_t *dev, kw2xrf_timer_timebase_t tb); + +void kw2xrf_timer2_seq_start_on(kw2xrf_t *dev); + +void kw2xrf_timer2_seq_start_off(kw2xrf_t *dev); + +void kw2xrf_timer3_seq_abort_on(kw2xrf_t *dev); + +void kw2xrf_timer3_seq_abort_off(kw2xrf_t *dev); + +/** + * Use T2CMP or T2PRIMECMP to Trigger Transceiver Operations + */ +void kw2xrf_trigger_tx_ops_enable(kw2xrf_t *dev, uint32_t timeout); + +/** + * Disable Trigger for Transceiver Operations + * + */ +void kw2xrf_trigger_tx_ops_disable(kw2xrf_t *dev); + +/** + * Use T3CMP to Abort an RX operation + */ +void kw2xrf_abort_rx_ops_enable(kw2xrf_t *dev, uint32_t timeout); + +/** + * Disable Trigger to Abort an RX operation + */ +void kw2xrf_abort_rx_ops_disable(kw2xrf_t *dev); + +void kw2xrf_seq_timeout_on(kw2xrf_t *dev, uint32_t timeout); + +void kw2xrf_seq_timeout_off(kw2xrf_t *dev); + +/** + * Returns Timestamp of the actual received packet + */ +uint32_t kw2xrf_get_timestamp(kw2xrf_t *dev); + +#ifdef __cplusplus +} +#endif +/** @} */ diff --git a/drivers/kw2xrf/include/kw2xrf_netdev.h b/drivers/kw2xrf/include/kw2xrf_netdev.h new file mode 100644 index 0000000000..ebe42fd0dc --- /dev/null +++ b/drivers/kw2xrf/include/kw2xrf_netdev.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 Phytec Messtechnik GmbH + * + * 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 + * @{ + * + * @file + * @brief Netdev interface for kw2xrf driver + * + * @author Johann Fischer <j.fischer@phytec.de> + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Reference to the netdev device driver struct + */ +extern const netdev2_driver_t kw2xrf_driver; + +#ifdef __cplusplus +} +#endif +/** @} */ diff --git a/drivers/kw2xrf/include/kw2xrf_reg.h b/drivers/kw2xrf/include/kw2xrf_reg.h index 3fa1b0f7b4..1e572c8482 100644 --- a/drivers/kw2xrf/include/kw2xrf_reg.h +++ b/drivers/kw2xrf/include/kw2xrf_reg.h @@ -1,9 +1,43 @@ /* - * Copyright (C) 2015 Phytec Messtechnik GmbH + * Copyright (C) 2016 Phytec Messtechnik GmbH * * 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. + * + * The description of the registers was extracted from the + * Reference Manual MKW2xDxxxRM.pdf. After the release of MCR20A Device, + * it was extended by the undocumented registers from the file MCR20reg.h. + * + * Portions of this file are derived from material that is + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ /** @@ -92,6 +126,24 @@ enum mkw2xdrf_dregister { MKW2XDM_SEQ_STATE = 0x24, /**< Sequence Manager State */ MKW2XDM_LQI_VALUE = 0x25, /**< Link Quality Indicator */ MKW2XDM_RSSI_CCA_CNT = 0x26, /**< RSSI CCA CNT */ + MKW2XDM_ASM_CTRL1 = 0x28, + MKW2XDM_ASM_CTRL2 = 0x29, + MKW2XDM_ASM_DATA_0 = 0x2A, + MKW2XDM_ASM_DATA_1 = 0x2B, + MKW2XDM_ASM_DATA_2 = 0x2C, + MKW2XDM_ASM_DATA_3 = 0x2D, + MKW2XDM_ASM_DATA_4 = 0x2E, + MKW2XDM_ASM_DATA_5 = 0x2F, + MKW2XDM_ASM_DATA_6 = 0x30, + MKW2XDM_ASM_DATA_7 = 0x31, + MKW2XDM_ASM_DATA_8 = 0x32, + MKW2XDM_ASM_DATA_9 = 0x33, + MKW2XDM_ASM_DATA_A = 0x34, + MKW2XDM_ASM_DATA_B = 0x35, + MKW2XDM_ASM_DATA_C = 0x36, + MKW2XDM_ASM_DATA_D = 0x37, + MKW2XDM_ASM_DATA_E = 0x38, + MKW2XDM_ASM_DATA_F = 0x39, MKW2XDM_OVERWRITE_VER = 0x3b, /**< Overwrite Version Number */ MKW2XDM_CLK_OUT_CTRL = 0x3c, /**< CLK_OUT Control */ MKW2XDM_PWR_MODES = 0x3d, /**< Power Modes */ @@ -124,13 +176,16 @@ enum mkw2xdrf_dregister { #define MKW2XDM_IRQSTS3_TMR3IRQ (1 << 2) #define MKW2XDM_IRQSTS3_TMR2IRQ (1 << 1) #define MKW2XDM_IRQSTS3_TMR1IRQ (1 << 0) +#define MKW2XDM_IRQSTS3_TMR_IRQ_MASK 0xfu +#define MKW2XDM_IRQSTS3_TMR_IRQ_SHIFT 0x0u +#define MKW2XDM_IRQSTS3_TMR_IRQ(x) (((uint8_t)(((uint8_t)(x))<<MKW2XDM_IRQSTS3_TMR_IRQ_SHIFT))&MKW2XDM_IRQSTS3_TMR_IRQ_MASK) #define MKW2XDM_PHY_CTRL1_TMRTRIGEN (1 << 7) #define MKW2XDM_PHY_CTRL1_SLOTTED (1 << 6) #define MKW2XDM_PHY_CTRL1_CCABFRTX (1 << 5) #define MKW2XDM_PHY_CTRL1_RXACKRQD (1 << 4) #define MKW2XDM_PHY_CTRL1_AUTOACK (1 << 3) -#define MKW2XDM_PHY_CTRL1_XCVSEQ_MASK 0x03u +#define MKW2XDM_PHY_CTRL1_XCVSEQ_MASK 0x07u #define MKW2XDM_PHY_CTRL1_XCVSEQ(x) (((uint8_t)(((uint8_t)(x))<<0))&MKW2XDM_PHY_CTRL1_XCVSEQ_MASK) #define MKW2XDM_PHY_CTRL2_CRC_MSK (1 << 7) @@ -227,6 +282,7 @@ enum mkw2xdrf_iregister { MKW2XDMI_CCA_CTRL = 0x25, /**< CCA Control */ MKW2XDMI_CCA2_CORR_PEAKS = 0x26, /**< Clear Channel Assessment 2 Threshold Peak Compare */ MKW2XDMI_CCA2_THRESH = 0x27, /**< Clear Channel Assessment 2 Threshold */ + MKW2XDMI_TMR_PRESCALE = 0x28, /**< Event Timer Time Base */ MKW2XDMI_GPIO_DATA = 0x2a, /**< GPIO Data */ MKW2XDMI_GPIO_DIR = 0x2b, /**< GPIO Direction Control */ MKW2XDMI_GPIO_PUL_EN = 0x2c, /**< GPIO Pullup Enable */ @@ -234,8 +290,110 @@ enum mkw2xdrf_iregister { MKW2XDMI_GPIO_DS = 0x2e, /**< GPIO Drive Strength */ MKW2XDMI_ANT_PAD_CTRL = 0x30, /**< Antenna Control */ MKW2XDMI_MISC_PAD_CTRL = 0x31, /**< Miscellaneous Pad Control */ + MKW2XDMI_BSM_CTRL = 0x32, + MKW2XDMI__RNG = 0x34, + MKW2XDMI_RX_BYTE_COUNT = 0x35, + MKW2XDMI_RX_WTR_MARK = 0x36, + MKW2XDMI_SOFT_RESET = 0x37, + MKW2XDMI_TXDELAY = 0x38, + MKW2XDMI_ACKDELAY = 0x39, + MKW2XDMI_SEQ_MGR_CTRL = 0x3A, + MKW2XDMI_SEQ_MGR_STS = 0x3B, + MKW2XDMI_SEQ_T_STS = 0x3C, + MKW2XDMI_ABORT_STS = 0x3D, + MKW2XDMI_CCCA_BUSY_CNT = 0x3E, + MKW2XDMI_SRC_ADDR_CHECKSUM1 = 0x3F, + MKW2XDMI_SRC_ADDR_CHECKSUM2 = 0x40, + MKW2XDMI_SRC_TBL_VALID1 = 0x41, + MKW2XDMI_SRC_TBL_VALID2 = 0x42, + MKW2XDMI_FILTERFAIL_CODE1 = 0x43, + MKW2XDMI_FILTERFAIL_CODE2 = 0x44, + MKW2XDMI_SLOT_PRELOAD = 0x45, + MKW2XDMI_CORR_VT = 0x47, + MKW2XDMI_SYNC_CTRL = 0x48, + MKW2XDMI_PN_LSB_0 = 0x49, + MKW2XDMI_PN_LSB_1 = 0x4A, + MKW2XDMI_PN_MSB_0 = 0x4B, + MKW2XDMI_PN_MSB_1 = 0x4C, + MKW2XDMI_CORR_NVAL = 0x4D, + MKW2XDMI_TX_MODE_CTRL = 0x4E, + MKW2XDMI_SNF_THR = 0x4F, + MKW2XDMI_FAD_THR = 0x50, MKW2XDMI_ANT_AGC_CTRL = 0x51, /**< Antenna AGC and FAD Control */ + MKW2XDMI_AGC_THR1 = 0x52, + MKW2XDMI_AGC_THR2 = 0x53, + MKW2XDMI_AGC_HYS = 0x54, + MKW2XDMI_AFC = 0x55, MKW2XDMI_LPPS_CTRL = 0x56, /**< LPPS_CTRL */ + MKW2XDMI_PHY_STS = 0x58, + MKW2XDMI_RX_MAX_CORR = 0x59, + MKW2XDMI_RX_MAX_PREAMBLE = 0x5A, + MKW2XDMI_RSSI = 0x5B, + MKW2XDMI_PLL_DIG_CTRL = 0x5E, + MKW2XDMI_VCO_CAL = 0x5F, + MKW2XDMI_VCO_BEST_DIFF = 0x60, + MKW2XDMI_VCO_BIAS = 0x61, + MKW2XDMI_KMOD_CTRL = 0x62, + MKW2XDMI_KMOD_CAL = 0x63, + MKW2XDMI_PA_CAL = 0x64, + MKW2XDMI_PA_PWRCAL = 0x65, + MKW2XDMI_ATT_RSSI1 = 0x66, + MKW2XDMI_ATT_RSSI2 = 0x67, + MKW2XDMI_RSSI_OFFSET = 0x68, + MKW2XDMI_RSSI_SLOPE = 0x69, + MKW2XDMI_RSSI_CAL1 = 0x6A, + MKW2XDMI_RSSI_CAL2 = 0x6B, + MKW2XDMI_XTAL_CTRL = 0x6E, + MKW2XDMI_XTAL_COMP_MIN = 0x6F, + MKW2XDMI_XTAL_COMP_MAX = 0x70, + MKW2XDMI_XTAL_GM = 0x71, + MKW2XDMI_LNA_TUNE = 0x74, + MKW2XDMI_LNA_AGCGAIN = 0x75, + MKW2XDMI_CHF_PMA_GAIN = 0x78, + MKW2XDMI_CHF_IBUF = 0x79, + MKW2XDMI_CHF_QBUF = 0x7A, + MKW2XDMI_CHF_IRIN = 0x7B, + MKW2XDMI_CHF_QRIN = 0x7C, + MKW2XDMI_CHF_IL = 0x7D, + MKW2XDMI_CHF_QL = 0x7E, + MKW2XDMI_CHF_CC1 = 0x7F, + MKW2XDMI_CHF_CCL = 0x80, + MKW2XDMI_CHF_CC2 = 0x81, + MKW2XDMI_CHF_IROUT = 0x82, + MKW2XDMI_CHF_QROUT = 0x83, + MKW2XDMI_RSSI_CTRL = 0x86, + MKW2XDMI_PA_BIAS = 0x89, + MKW2XDMI_PA_TUNING = 0x8A, + MKW2XDMI_PMC_HP_TRIM = 0x8D, + MKW2XDMI_VREGA_TRIM = 0x8E, + MKW2XDMI_VCO_CTRL1 = 0x91, + MKW2XDMI_VCO_CTRL2 = 0x92, + MKW2XDMI_ANA_SPARE_OUT1 = 0x95, + MKW2XDMI_ANA_SPARE_OUT2 = 0x96, + MKW2XDMI_ANA_SPARE_IN = 0x97, + MKW2XDMI_MISCELLANEOUS = 0x98, + MKW2XDMI_SEQ_MGR_OVRD0 = 0x9A, + MKW2XDMI_SEQ_MGR_OVRD1 = 0x9B, + MKW2XDMI_SEQ_MGR_OVRD2 = 0x9C, + MKW2XDMI_SEQ_MGR_OVRD3 = 0x9D, + MKW2XDMI_SEQ_MGR_OVRD4 = 0x9E, + MKW2XDMI_SEQ_MGR_OVRD5 = 0x9F, + MKW2XDMI_SEQ_MGR_OVRD6 = 0xA0, + MKW2XDMI_SEQ_MGR_OVRD7 = 0xA1, + MKW2XDMI_TESTMODE_CTRL = 0xA3, + MKW2XDMI_DTM_CTRL1= 0xA4, + MKW2XDMI_DTM_CTRL2= 0xA5, + MKW2XDMI_ATM_CTRL1= 0xA6, + MKW2XDMI_ATM_CTRL2= 0xA7, + MKW2XDMI_ATM_CTRL3= 0xA8, + MKW2XDMI_LIM_FE_TEST_CTRL = 0xAA, + MKW2XDMI_CHF_TEST_CTRL = 0xAB, + MKW2XDMI_VCO_TEST_CTRL = 0xAC, + MKW2XDMI_PLL_TEST_CTRL = 0xAD, + MKW2XDMI_PA_TEST_CTRL = 0xAE, + MKW2XDMI_PMC_TEST_CTRL = 0xAF, + MKW2XDMI_SCAN_DTM_PROTECT_1 = 0xFE, + MKW2XDMI_SCAN_DTM_PROTECT_0 = 0xFF, }; #define MKW2XDMI_PART_ID_MANUF_ID_MASK 0x60u @@ -279,6 +437,10 @@ enum mkw2xdrf_iregister { #define MKW2XDMI_CCA2_CORR_PEAKS_CCA2_MIN_NUM_CORR_TH(x) (((uint8_t)(((uint8_t)(x))<<MKW2XDMI_CCA2_CORR_PEAKS_CCA2_MIN_NUM_CORR_TH_SHIFT))&MKW2XDMI_CCA2_CORR_PEAKS_CCA2_MIN_NUM_CORR_TH_MASK) #define MKW2XDMI_CCA2_CORR_PEAKS_CCA2_NUM_CORR_PEAKS_MASK 0x0Fu +#define MKW2XDMI_TMR_PRESCALE_MASK 0x7u +#define MKW2XDMI_TMR_PRESCALE_SHIFT 0x0u +#define MKW2XDMI_TMR_PRESCALE_SET(x) (((uint8_t)(((uint8_t)(x))<<MKW2XDMI_TMR_PRESCALE_SHIFT))&MKW2XDMI_TMR_PRESCALE_MASK) + #define MKW2XDMI_GPIO_DATA8 (1 << 7) #define MKW2XDMI_GPIO_DATA7 (1 << 6) #define MKW2XDMI_GPIO_DATA6 (1 << 5) @@ -348,6 +510,56 @@ enum mkw2xdrf_iregister { #define MKW2XDMI_LPPS_CTRL_LPPS_EN (1 << 0) +#define MKW2XDMI_SOFT_RESET_SOG_RST (1 << 7) +#define MKW2XDMI_SOFT_RESET_REGS_RST (1 << 4) +#define MKW2XDMI_SOFT_RESET_PLL_RST (1 << 3) +#define MKW2XDMI_SOFT_RESET_TX_RST (1 << 2) +#define MKW2XDMI_SOFT_RESET_RX_RST (1 << 1) +#define MKW2XDMI_SOFT_RESET_SEQ_MGR_RST (1 << 0) + +#define MKW2XDMI_SEQ_MGR_CTRL_SEQ_STATE_CTRL_MASK 0x3 +#define MKW2XDMI_SEQ_MGR_CTRL_SEQ_STATE_CTRL_SHIFT 6 +#define MKW2XDMI_SEQ_MGR_CTRL_NO_RX_RECYCLE (1 << 5) +#define MKW2XDMI_SEQ_MGR_CTRL_LATCH_PREAMBLE (1 << 4) +#define MKW2XDMI_SEQ_MGR_CTRL_EVENT_TMR_DO_NOT_LATCH (1 << 3) +#define MKW2XDMI_SEQ_MGR_CTRL_CLR_NEW_SEQ_INHIBIT (1 << 2) +#define MKW2XDMI_SEQ_MGR_CTRL_PSM_LOCK_DIS (1 << 1) +#define MKW2XDMI_SEQ_MGR_CTRL_PLL_ABORT_OVRD (1 << 0) + +#define MKW2XDMI_SEQ_MGR_STS_TMR2_SEQ_TRIG_ARMED (1 << 7) +#define MKW2XDMI_SEQ_MGR_STS_RX_MODE (1 << 6) +#define MKW2XDMI_SEQ_MGR_STS_RX_TIMEOUT_PENDING (1 << 5) +#define MKW2XDMI_SEQ_MGR_STS_NEW_SEQ_INHIBIT (1 << 4) +#define MKW2XDMI_SEQ_MGR_STS_SEQ_IDLE (1 << 3) +#define MKW2XDMI_SEQ_MGR_STS_XCVSEQ_ACTUAL_MASK 7 + +#define MKW2XDMI_ABORT_STS_PLL_ABORTED (1 << 2) +#define MKW2XDMI_ABORT_STS_TC3_ABORTED (1 << 1) +#define MKW2XDMI_ABORT_STS_SW_ABORTED (1 << 0) + +#define MKW2XDMI_TESTMODE_CTRL_HOT_ANT (1 << 4) +#define MKW2XDMI_TESTMODE_CTRL_IDEAL_RSSI_EN (1 << 3) +#define MKW2XDMI_TESTMODE_CTRL_IDEAL_PFC_EN (1 << 2) +#define MKW2XDMI_TESTMODE_CTRL_CONTINUOUS_EN (1 << 1) +#define MKW2XDMI_TESTMODE_CTRL_FPGA_EN (1 << 0) + +#define MKW2XDMI_DTM_CTRL1_ATM_LOCKED (1 << 7) +#define MKW2XDMI_DTM_CTRL1_DTM_EN (1 << 6) +#define MKW2XDMI_DTM_CTRL1_PAGE5 (1 << 5) +#define MKW2XDMI_DTM_CTRL1_PAGE4 (1 << 4) +#define MKW2XDMI_DTM_CTRL1_PAGE3 (1 << 3) +#define MKW2XDMI_DTM_CTRL1_PAGE2 (1 << 2) +#define MKW2XDMI_DTM_CTRL1_PAGE1 (1 << 1) +#define MKW2XDMI_DTM_CTRL1_PAGE0 (1 << 0) + +#define MKW2XDMI_TX_MODE_CTRL_TX_INV (1 << 4) +#define MKW2XDMI_TX_MODE_CTRL_BT_EN (1 << 3) +#define MKW2XDMI_TX_MODE_CTRL_DTS2 (1 << 2) +#define MKW2XDMI_TX_MODE_CTRL_DTS1 (1 << 1) +#define MKW2XDMI_TX_MODE_CTRL_DTS0 (1 << 0) +#define MKW2XDMI_TX_MODE_CTRL_DTS_MASK 7 + + #ifdef __cplusplus } #endif diff --git a/drivers/kw2xrf/include/kw2xrf_spi.h b/drivers/kw2xrf/include/kw2xrf_spi.h index a973a5510f..3cddd14723 100644 --- a/drivers/kw2xrf/include/kw2xrf_spi.h +++ b/drivers/kw2xrf/include/kw2xrf_spi.h @@ -29,85 +29,111 @@ extern "C" { /** * @brief SPI interface initialization - * @param[in] spi SPI bus the device is connected to - * @param[in] spi_clk SPI clock speed to use - * @param[in] cs_pin GPIO pin connected to chip select + * @param[in] dev device descriptor * * @return 0 on success * @return -1 on error */ -int kw2xrf_spi_init(spi_t spi, spi_clk_t spi_clk, spi_cs_t cs_pin); +int kw2xrf_spi_init(kw2xrf_t *dev); /** * @brief Writes a byte to the kw2xrf register. * + * @param[in] dev device descriptor * @param[in] addr Address of the register to write. * @param[in] value The value to write in the register. */ -void kw2xrf_write_dreg(uint8_t addr, uint8_t value); +void kw2xrf_write_dreg(kw2xrf_t *dev, uint8_t addr, uint8_t value); /** * @brief Reads a byte from the kw2xrf register. * + * @param[in] dev device descriptor * @param[in] addr Address of the register to read. * @return Value of the register. */ -uint8_t kw2xrf_read_dreg(uint8_t addr); +uint8_t kw2xrf_read_dreg(kw2xrf_t *dev, uint8_t addr); + +/** + * @brief Writes to kw2xrf direct registers. + * + * @param[in] dev device descriptor + * @param[in] addr Address of the register to write into. + * @param[in] buf Value that shall be written. + * @param[in] length Length of the register. + */ +size_t kw2xrf_write_dregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length); + +/** + * @brief Reads a byte from the kw2xrf indirect register. + * + * @param[in] dev device descriptor + * @param[in] addr Address of the register to read. + * @param[in] buf Buffer, where the content of the reg shall be written to. + * @param[in] length Length of the register. + */ +size_t kw2xrf_read_dregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length); /** * @brief Writes to a byte from the kw2xrf indirect register. * + * @param[in] dev device descriptor * @param[in] addr Address of the register to write into. * @param[in] value Value that shall be written. */ -void kw2xrf_write_ireg(uint8_t addr, uint8_t value); +void kw2xrf_write_ireg(kw2xrf_t *dev, uint8_t addr, uint8_t value); /** * @brief Reads a byte from the kw2xrf indirect register. * + * @param[in] dev device descriptor * @param[in] addr Address of the register to read. * * @return value in the register */ -uint8_t kw2xrf_read_ireg(uint8_t addr); +uint8_t kw2xrf_read_ireg(kw2xrf_t *dev, uint8_t addr); /** * @brief Writes to kw2xrf indirect registers. * + * @param[in] dev device descriptor * @param[in] addr Address of the register to write into. * @param[in] buf Value that shall be written. * @param[in] length Length of the register. */ -void kw2xrf_write_iregs(uint8_t addr, uint8_t *buf, uint8_t length); +void kw2xrf_write_iregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length); /** * @brief Reads a byte from the kw2xrf indirect register. * + * @param[in] dev device descriptor * @param[in] addr Address of the register to read. * @param[in] buf Buffer, where the content of the reg shall be written to. * @param[in] length Length of the register. */ -void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length); +void kw2xrf_read_iregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length); /** * @brief Writes multiple bytes to the kw2xrf fifo. * + * @param[in] dev device descriptor * @param[in] data A buffer with the value to write to the fifo. * @param[in] data_length The count of bytes which should be written. * * @return number of bytes written. */ -void kw2xrf_write_fifo(uint8_t *data, uint8_t data_length); +void kw2xrf_write_fifo(kw2xrf_t *dev, uint8_t *data, uint8_t data_length); /** * @brief Reads multiple bytes from the kw2xrf fifo. * + * @param[in] dev device descriptor * @param[out] data A buffer to store the value of the fifo. * @param[in] data_length The count of bytes which should be read. * * @return number of bytes read. */ -void kw2xrf_read_fifo(uint8_t *data, uint8_t data_length); +void kw2xrf_read_fifo(kw2xrf_t *dev, uint8_t *data, uint8_t data_length); #ifdef __cplusplus } diff --git a/drivers/kw2xrf/include/kw2xrf_tm.h b/drivers/kw2xrf/include/kw2xrf_tm.h new file mode 100644 index 0000000000..63cfb14e67 --- /dev/null +++ b/drivers/kw2xrf/include/kw2xrf_tm.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 Phytec Messtechnik GmbH + * + * 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 tests_kw2xrf + * @{ + * + * @file + * @brief Testing interfaces for kw2xrf driver + * + * @author Johann Fischer <j.fischer@phytec.de> + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef KW2XRF_TESTMODE + +#include "kw2xrf.h" +#include "kw2xrf_reg.h" +#include "kw2xrf_getset.h" +#include "net/netopt.h" + +enum mkw2xrf_testmode { + KW2XRF_TM_CTX_PREAMBLE = NETOPT_RF_TESTMODE_CTX_PRBS9 + 1, + KW2XRF_TM_CTX_2MHZ, + KW2XRF_TM_CTX_200KHZ, + KW2XRF_TM_CTX_1MBPS_PRBS9, + KW2XRF_TM_CTX_EXT, + KW2XRF_TM_CTX_NM0, + KW2XRF_TM_CTX_NM1, +}; + +int kw2xrf_set_test_mode(kw2xrf_t *dev, uint8_t mode); + +#endif + +#ifdef __cplusplus +} +#endif +/** @} */ diff --git a/drivers/kw2xrf/include/overwrites.h b/drivers/kw2xrf/include/overwrites.h new file mode 100644 index 0000000000..26d7d5305b --- /dev/null +++ b/drivers/kw2xrf/include/overwrites.h @@ -0,0 +1,308 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file MCR20Overwrites.h +* Description: Overwrites header file for MCR20 Register values +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OVERWRITES_H_ +#define OVERWRITES_H_ + +typedef struct overwrites_tag { + char address; + char data; +} overwrites_t; + + +/*****************************************************************************************************************/ +// This file is created exclusively for use with the transceiver 2.0 silicon +// and is provided for the world to use. It contains a list of all +// known overwrite values. Overwrite values are non-default register +// values that configure the transceiver device to a more optimally performing +// posture. It is expected that low level software (i.e. PHY) will +// consume this file as a #include, and transfer the contents to the +// the indicated addresses in the transceiver's memory space. This file has +// at least one required entry, that being its own version current version +// number, to be stored at transceiver's location 0x3B the +// OVERWRITES_VERSION_NUMBER register. The RAM register is provided in +// the transceiver address space to assist in future debug efforts. The +// analyst may read this location (once device has been booted with +// mysterious software) and have a good indication of what register +// overwrites were performed (with all versions of the overwrites.h file +// being archived forever at the Compass location shown above. +// +// The transceiver has an indirect register (IAR) space. Write access to this space +// requires 3 or more writes: +// 1st) the first write is an index value to the indirect (write Bit7=0, register access Bit 6=0) + 0x3E +// 2nd) IAR Register #0x00 - 0xFF. +// 3rd) The data to write +// nth) Burst mode additional data if required. +// +// Write access to direct space requires only a single address, data pair. + +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x0C}, //version 0C: new value for ACKDELAY targeting 198us (23 May, 2013, Larry Roshak) +{0x23, 0x17} //PA_PWR new default Power Step is "23" +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x55}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03}, //CHF_PMAGAIN +{0x22, 0x50}, //CCA1_THRESH +{0x4D, 0x13}, //CORR_NVAL moved from 0x14 to 0x13 for 0.5 dB improved Rx Sensitivity +{0x39, 0x3D} //ACKDELAY new value targeting a delay of 198us (23 May, 2013, Larry Roshak) +}; + + +/* begin of deprecated versions + +==VERSION 1== +(version 1 is empty) + +==VERSION 2== +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02} //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +}; + +==VERSION 3== +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +}; + +==VERSION 4== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x04} //version 04 is the current version: update PA_COILTUNING default +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71} //PA_TUNING: override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +}; + +==VERSION 5== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x05} //version 05: updates Channel Filter Register set (21 Dec 2012, on behalf of S. Soca) +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71} //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F} //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F} //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24} //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24} //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24} //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24} //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24} //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24} //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32} //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D} //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D} //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +}; + +==VERSION 6== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x06} //version 06: disable PA calibration +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71} //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F} //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F} //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24} //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24} //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24} //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24} //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24} //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24} //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32} //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D} //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D} //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28} //PA_CAL_DIS=1 Disabled PA calibration +}; + +==VERSION 7== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x07} //version 07: updated registers for ED/RSSI +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x73}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x60}, //RSSI_OFFSET +{0x69, 0x65} //RSSI_SLOPE +}; + + +==VERSION 8== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x08} //version 08: updated registers for ED/RSSI +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x73}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x69, 0x65} //RSSI_SLOPE +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03} //CHF_PMAGAIN +}; + + +==VERSION 9== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x09} //version 09: updated registers for ED/RSSI and PowerStep +{0x23, 0x17} //PA_PWR new default value +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x55}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03} //CHF_PMAGAIN +}; + +==VERSION A== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x0A} //version 0A: updated registers for CCA +{0x23, 0x17} //PA_PWR new default Power Step is "23" +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x55}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03} //CHF_PMAGAIN +{0x22, 0x50} //CCA1_THRESH +}; + +end of deprecated versions */ + + +#endif //OVERWRITES_H_ diff --git a/drivers/kw2xrf/kw2xrf.c b/drivers/kw2xrf/kw2xrf.c index fd2b41d9b7..b4fdbb859d 100644 --- a/drivers/kw2xrf/kw2xrf.c +++ b/drivers/kw2xrf/kw2xrf.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 PHYTEC Messtechnik GmbH + * Copyright (C) 2016 PHYTEC Messtechnik GmbH * * 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 @@ -7,7 +7,7 @@ */ /** - * @ingroup kw2xrf + * @ingroup drivers_kw2xrf * @{ * @file * @brief Basic functionality of kw2xrf driver @@ -17,10 +17,9 @@ * @author Oliver Hahm <oliver.hahm@inria.fr> * @} */ -#include "panic.h" -#include "kw2xrf.h" -#include "kw2xrf_spi.h" -#include "kw2xrf_reg.h" +#include <stdint.h> +#include <string.h> + #include "mutex.h" #include "msg.h" #include "periph/gpio.h" @@ -28,1262 +27,136 @@ #include "net/gnrc.h" #include "net/ieee802154.h" +#include "kw2xrf.h" +#include "kw2xrf_spi.h" +#include "kw2xrf_reg.h" +#include "kw2xrf_netdev.h" +#include "kw2xrf_getset.h" +#include "kw2xrf_intern.h" + #define ENABLE_DEBUG (0) #include "debug.h" -/** - * @brief Internal driver event type in case of an unexpected interrupt - */ -#define ISR_EVENT_UNKNOWN (0x0020) - -/* Modem_PA_PWR Register (PA Power Control) has a valid range from 3-31 */ -#define MKW2XDRF_PA_RANGE_MAX 31 /**< Maximum value of PA Power Control Register */ -#define MKW2XDRF_PA_RANGE_MIN 3 /**< Minimum value of PA Power Control Register */ - -#define _MAX_MHR_OVERHEAD (25) - -/* PLL integer lookup table */ -static const uint8_t pll_int_lt[16] = { - 11, 11, 11, 11, - 11, 11, 12, 12, - 12, 12, 12, 12, - 13, 13, 13, 13 -}; - -/* PLL frequency fractional lookup table */ -static const uint16_t pll_frac_lt[16] = { - 10240, 20480, 30720, 40960, - 51200, 61440, 6144, 16384, - 26624, 36864, 47104, 57344, - 2048, 12288, 22528, 32768 -}; - -static const uint8_t pow_lt[44] = { - 3, 4, 4, 5, - 6, 6, 7, 7, - 8, 9, 9, 10, - 11, 11, 12, 13, - 13, 14, 14, 15, - 16, 16, 17, 18, - 18, 19, 20, 20, - 21, 21, 22, 23, - 23, 24, 25, 25, - 26, 27, 27, 28, - 28, 29, 30, 31 -}; - -/* TODO: Implement this -static const int level_lt[29] = { - -35, -34, -32, -31, - -29, -28, -26, -25, - -23, -22, -20, -19, - -17, -16, -14, -13, - -11, -10, -8, -7, - -5, -4, -2, -1, - 1, 2, 4, 5, - 7 -}; -*/ - -static gpio_t kw2xrf_gpio_int; - -void kw2xrf_set_option(kw2xrf_t *dev, uint16_t option, bool state); - -int kw2xrf_set_tx_power(kw2xrf_t *dev, int8_t *val, size_t len) -{ - uint8_t level = pow_lt[val[0] - MKW2XDRF_OUTPUT_POWER_MIN]; - kw2xrf_write_dreg(MKW2XDM_PA_PWR, MKW2XDM_PA_PWR(level)); - return 2; -} - -int kw2xrf_get_channel(kw2xrf_t *dev, uint8_t *val, size_t max) -{ - if (max < 2) { - return -EOVERFLOW; - } - - uint8_t pll_int = kw2xrf_read_dreg(MKW2XDM_PLL_INT0); - uint16_t pll_frac = kw2xrf_read_dreg(MKW2XDM_PLL_FRAC0_LSB); - pll_frac |= ((uint16_t)kw2xrf_read_dreg(MKW2XDM_PLL_FRAC0_MSB) << 8); - - for (int i = 0; i < 16; i++) { - if ((pll_frac_lt[i] == pll_frac) && (pll_int_lt[i] == pll_int)) { - val[0] = i + 11; - val[1] = 0; - return 2; - } - } - - return -EINVAL; -} - -int kw2xrf_get_sequence(void) -{ - int reg = 0; - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - reg &= MKW2XDM_PHY_CTRL1_XCVSEQ_MASK; - return reg; -} - -void kw2xrf_set_sequence(kw2xrf_t *dev, kw2xrf_physeq_t seq) -{ - uint8_t reg = 0; - - /* Only interrupt interruptable states */ - uint8_t curr_seq = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - curr_seq &= (MKW2XDM_PHY_CTRL1_XCVSEQ_MASK); - - if ((curr_seq == XCVSEQ_RECEIVE) || (curr_seq == XCVSEQ_CONTINUOUS_CCA)) { - /* Clear all pending interrupts */ - gpio_irq_disable(kw2xrf_gpio_int); - - /* abort any ongoing sequence */ - DEBUG("kw2xrf_tx: abort SEQ_STATE: %x\n", kw2xrf_read_dreg(MKW2XDM_SEQ_STATE)); - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - reg &= ~(MKW2XDM_PHY_CTRL1_XCVSEQ_MASK); - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL1, reg); - - /* Mask all possible interrupts */ - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL3); - reg |= MKW2XDM_PHY_CTRL3_WAKE_MSK; - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL3, reg); - - kw2xrf_write_dreg(MKW2XDM_IRQSTS1, 0x7f); - kw2xrf_write_dreg(MKW2XDM_IRQSTS2, 0x03); - kw2xrf_write_dreg(MKW2XDM_IRQSTS3, 0xff); - - gpio_irq_enable(kw2xrf_gpio_int); - } - -#ifdef DEVELHELP - uint16_t max_tries = 0; -#endif - - /* Wait for all other states finish */ - while (kw2xrf_read_dreg(MKW2XDM_SEQ_STATE)) { -#ifdef DEVELHELP - max_tries++; - - /* At 10MHz SPI-Clock, 40000 should be in the magnitue of 0.1s */ - if (max_tries == 40000) { - DEBUG("kw2xrf_error: device does not finish sequence\n"); - core_panic(PANIC_GENERAL_ERROR, "kw2xrf_error: device does not finish sequence"); - } - -#endif - } - - /* For all sequences only enable SEQ-irq will be set when sequence completed */ - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL2); - reg &= ~(MKW2XDM_PHY_CTRL2_SEQMSK); - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL2, reg); - - /* Progrmm new sequence */ - switch (seq) { - case XCVSEQ_IDLE: - dev->state = NETOPT_STATE_SLEEP; - break; - - case XCVSEQ_RECEIVE: - dev->state = NETOPT_STATE_RX; - break; - - case XCVSEQ_TRANSMIT: - dev->state = NETOPT_STATE_TX; - break; - - case XCVSEQ_CCA: - dev->state = NETOPT_STATE_TX; - break; - - case XCVSEQ_TX_RX: - dev->state = NETOPT_STATE_TX; - break; - - case XCVSEQ_CONTINUOUS_CCA: - dev->state = NETOPT_STATE_TX; - break; - - default: - DEBUG("kw2xrf: undefined state assigned to phy\n"); - dev->state = NETOPT_STATE_IDLE; - } - - /* Mapping of TX-sequences depending on AUTOACK flag */ - /* TODO: This should only used in combination with - * an CSMA-MAC layer. Currently not working - */ - /*if ((seq == XCVSEQ_TRANSMIT) || (seq == XCVSEQ_TX_RX)) { - if ((dev->option) & KW2XRF_OPT_AUTOACK) { - seq = XCVSEQ_TX_RX; - } - else { - seq = XCVSEQ_TRANSMIT; - } - }*/ - - DEBUG("kw2xrf: Set sequence to %i\n", seq); - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - reg &= ~(MKW2XDM_PHY_CTRL1_XCVSEQ_MASK); - reg |= MKW2XDM_PHY_CTRL1_XCVSEQ(seq); - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL1, reg); -} - -int kw2xrf_set_channel(kw2xrf_t *dev, uint8_t *val, size_t len) -{ - /* Save old sequence to restore this state later */ - uint8_t old_seq = kw2xrf_get_sequence(); - - if (old_seq) { - kw2xrf_set_sequence(dev, XCVSEQ_IDLE); - } - - if ((val[0] < 11) || (val[0] > 26)) { - DEBUG("kw2xrf: Invalid channel %i set. Valid channels are 11 through 26\n", val[0]); - return -ENOTSUP; - } - - if ((len != 2) || (val[1] != 0)) { - DEBUG("kw2xrf: set channel failed, len: %u, val[0]:%u\n", len, val[0]); - return -EINVAL; - } - - /* - * Fc = 2405 + 5(k - 11) , k = 11,12,...,26 - * - * Equation for PLL frequency, MKW2xD Reference Manual, p.255 : - * F = ((PLL_INT0 + 64) + (PLL_FRAC0/65536))32MHz - * - */ - uint8_t tmp = val[0] - 11; - kw2xrf_write_dreg(MKW2XDM_PLL_INT0, MKW2XDM_PLL_INT0_VAL(pll_int_lt[tmp])); - kw2xrf_write_dreg(MKW2XDM_PLL_FRAC0_LSB, (uint8_t)pll_frac_lt[tmp]); - kw2xrf_write_dreg(MKW2XDM_PLL_FRAC0_MSB, (uint8_t)(pll_frac_lt[tmp] >> 8)); - - DEBUG("kw2xrf: set channel to %u\n", val[0]); - - if (old_seq) { - kw2xrf_set_sequence(dev, old_seq); - } - - return 2; -} - -void kw2xrf_irq_handler(void *args) -{ - msg_t msg; - kw2xrf_t *dev = (kw2xrf_t *)args; - - /* notify driver thread about the interrupt */ - msg.type = GNRC_NETDEV_MSG_TYPE_EVENT; - msg_send_int(&msg, dev->mac_pid); -} - -/* Set up interrupt sources, triggered by the radio-module */ -void kw2xrf_init_interrupts(kw2xrf_t *dev, gpio_t int_pin) -{ - /* Clear all pending interrupts */ - kw2xrf_write_dreg(MKW2XDM_IRQSTS1, 0x7f); - kw2xrf_write_dreg(MKW2XDM_IRQSTS2, 0x03); - kw2xrf_write_dreg(MKW2XDM_IRQSTS3, 0xff); - - /* Disable all interrups: - * Selectively enable only one interrupt source selectively in sequence manager. - * After reset state all interrupts are disabled, except WAKE_IRQ. - */ - int reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL3); - reg |= MKW2XDM_PHY_CTRL3_WAKE_MSK; - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL3, reg); - - /* set up GPIO-pin used for IRQ */ - gpio_init_int(int_pin, GPIO_IN, GPIO_FALLING, &kw2xrf_irq_handler, dev); -} - -int kw2xrf_set_pan(kw2xrf_t *dev, uint16_t pan) -{ - dev->radio_pan = pan; - - uint8_t val_ar[2]; - val_ar[1] = (pan >> 8); - val_ar[0] = (uint8_t)pan; - kw2xrf_write_iregs(MKW2XDMI_MACPANID0_LSB, val_ar, 2); - return 2; -} - -int kw2xrf_get_proto(kw2xrf_t *dev, uint8_t *val, size_t max) -{ - if (max < sizeof(gnrc_nettype_t)) { - return -EOVERFLOW; - } - - memcpy(val, &(dev->proto), sizeof(gnrc_nettype_t)); - return sizeof(gnrc_nettype_t); -} - -int kw2xrf_set_proto(kw2xrf_t *dev, uint8_t *val, size_t len) -{ - if (len != sizeof(gnrc_nettype_t)) { - return -EINVAL; - } - - memcpy(&(dev->proto), val, sizeof(gnrc_nettype_t)); - return sizeof(gnrc_nettype_t); -} - -int kw2xrf_on(kw2xrf_t *dev) -{ - uint8_t tmp; - /* check modem's crystal oscillator, CLK_OUT shall be 4MHz */ - tmp = kw2xrf_read_dreg(MKW2XDM_CLK_OUT_CTRL); - - if (tmp != 0x8Bu) { - return -1; - } - - DEBUG("SEQ_STATE: %x\n", kw2xrf_read_dreg(MKW2XDM_SEQ_STATE)); - - /* enable RFon mode */ - kw2xrf_write_dreg(MKW2XDM_PWR_MODES, - (MKW2XDM_PWR_MODES_XTALEN | MKW2XDM_PWR_MODES_PMC_MODE)); - - /* abort any ongoing sequence */ - kw2xrf_set_sequence(dev, XCVSEQ_IDLE); - - dev->state = NETOPT_STATE_SLEEP; - return 0; -} - -int kw2xrf_set_addr(kw2xrf_t *dev, uint16_t addr) -{ - uint8_t val_ar[2]; - val_ar[0] = (addr >> 8); - val_ar[1] = (uint8_t)addr; - dev->addr_short[0] = val_ar[0]; - dev->addr_short[1] = val_ar[1]; -#ifdef MODULE_SIXLOWPAN - /* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to - * 0 for unicast addresses */ - dev->addr_short[1] &= 0x7F; -#endif - kw2xrf_write_iregs(MKW2XDMI_MACSHORTADDRS0_LSB, val_ar, - IEEE802154_SHORT_ADDRESS_LEN); - - return sizeof(uint16_t); -} - -int kw2xrf_set_addr_long(kw2xrf_t *dev, uint64_t addr) -{ - for (int i = 0; i < IEEE802154_LONG_ADDRESS_LEN; i++) { - dev->addr_long[i] = (addr >> ((IEEE802154_LONG_ADDRESS_LEN - 1 - i) * 8)); - } - - kw2xrf_write_iregs(MKW2XDMI_MACLONGADDRS0_0, (dev->addr_long), - IEEE802154_LONG_ADDRESS_LEN); - - return sizeof(uint64_t); -} - -int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_clk_t spi_clk, - gpio_t cs_pin, gpio_t int_pin) -{ - uint8_t reg = 0; - uint8_t tmp[2]; - kw2xrf_gpio_int = int_pin; #if CPUID_LEN /* make sure that the buffer is always big enough to store a 64bit value */ -# if CPUID_LEN < IEEE802154_LONG_ADDRESS_LEN - uint8_t cpuid[IEEE802154_LONG_ADDRESS_LEN]; -# else - uint8_t cpuid[CPUID_LEN]; -#endif - uint16_t addr_short = 0; - eui64_t addr_long; -#endif - - /* check device parameters */ - if (dev == NULL) { - return -ENODEV; - } - - kw2xrf_spi_init(spi, spi_clk, cs_pin); - - if (kw2xrf_on(dev) != 0) { - core_panic(PANIC_GENERAL_ERROR, "Could not start MKW2XD radio transceiver"); - } - - /* General initialization of interrupt sources. - * sets radio to idle mode with all interrupt masked - */ - kw2xrf_init_interrupts(dev, kw2xrf_gpio_int); - - /* set device driver */ - dev->driver = &kw2xrf_driver; - /* set default option */ - dev->proto = KW2XRF_DEFAULT_PROTOCOL; - dev->option = 0; - -#if CPUID_LEN - /* in case CPUID_LEN < 8, fill missing bytes with zeros */ - memset(cpuid, 0, CPUID_LEN); - - cpuid_get(cpuid); - - /* generate short hardware address if CPUID_LEN > 0 */ - for (int i = 0; i < CPUID_LEN; i++) { - /* XOR each even byte of the CPUID with LSB of short address - and each odd byte with MSB */ - addr_short ^= (uint16_t)(cpuid[i] << ((i & 0x01) * 8)); - } -#if CPUID_LEN > IEEE802154_LONG_ADDRESS_LEN - for (int i = IEEE802154_LONG_ADDRESS_LEN; i < CPUID_LEN; i++) { - cpuid[i & 0x07] ^= cpuid[i]; - } -#endif - /* make sure we mark the address as non-multicast and not globally unique */ - cpuid[0] &= ~(0x01); - cpuid[0] |= 0x02; - /* copy and set long address */ - memcpy(&addr_long, cpuid, IEEE802154_LONG_ADDRESS_LEN); - kw2xrf_set_addr_long(dev, NTOHLL(addr_long.uint64.u64)); - kw2xrf_set_addr(dev, addr_short); +#if CPUID_LEN < IEEE802154_LONG_ADDRESS_LEN +#define KW2XRF_ID_LEN IEEE802154_LONG_ADDRESS_LEN #else - kw2xrf_set_addr_long(dev, KW2XRF_DEFAULT_SHORT_ADDR); - kw2xrf_set_addr(dev, KW2XRF_DEFAULT_ADDR_LONG); +#define KW2XRF_ID_LEN CPUID_LEN +#endif #endif - /* set default TX-Power */ - dev->tx_power = KW2XRF_DEFAULT_TX_POWER; - kw2xrf_set_tx_power(dev, &(dev->tx_power), sizeof(dev->tx_power)); - - /* set default channel */ - dev->radio_channel = KW2XRF_DEFAULT_CHANNEL; - tmp[0] = dev->radio_channel; - tmp[1] = 0; - kw2xrf_set_channel(dev, tmp, 2); - /* set default PAN ID */ - kw2xrf_set_pan(dev, KW2XRF_DEFAULT_PANID); - - /* CCA Setup */ - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL4); - /* Set up CCA mode 1 (RSSI threshold) */ - reg |= MKW2XDM_PHY_CTRL4_CCATYPE(1); - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL4, reg); - DEBUG("kw2xrf: Initialized and set to channel %i and pan %i.\n", - KW2XRF_DEFAULT_CHANNEL, KW2XRF_DEFAULT_PANID); - - kw2xrf_set_option(dev, KW2XRF_OPT_AUTOACK, true); - kw2xrf_set_option(dev, KW2XRF_OPT_CSMA, true); - - /* Switch to Receive state per default after initialization */ - kw2xrf_set_sequence(dev, XCVSEQ_RECEIVE); - return 0; -} - -int kw2xrf_add_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb) -{ - if (dev == NULL) { - return -ENODEV; - } - - if (dev->event_cb != NULL) { - return -ENOBUFS; - } - - dev->event_cb = cb; - return 0; -} - -int kw2xrf_rem_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb) -{ - if (dev == NULL) { - return -ENODEV; - } - - if (dev->event_cb != cb) { - return -ENOENT; - } - - dev->event_cb = NULL; - return 0; -} - -uint16_t kw2xrf_get_addr_short(kw2xrf_t *dev) -{ - return (dev->addr_short[0] << 8) | dev->addr_short[1]; -} - -uint64_t kw2xrf_get_addr_long(kw2xrf_t *dev) -{ - uint64_t addr; - uint8_t *ap = (uint8_t *)(&addr); - - for (int i = 0; i < IEEE802154_LONG_ADDRESS_LEN; i++) { - ap[i] = dev->addr_long[IEEE802154_LONG_ADDRESS_LEN - 1 - i]; - } - - return addr; -} - -int8_t kw2xrf_get_cca_threshold(kw2xrf_t *dev) -{ - uint8_t tmp; - kw2xrf_read_iregs(MKW2XDMI_CCA1_THRESH, &tmp, 1); - /* KW2x register value represents absolute value in dBm - * default value: -75 dBm - */ - return (-tmp); -} - -void kw2xrf_set_cca_threshold(kw2xrf_t *dev, int8_t value) -{ - /* normalize to absolute value */ - if (value < 0) { - value = -value; - } - kw2xrf_write_iregs(MKW2XDMI_CCA1_THRESH, (uint8_t*)&value, 1); -} - -int kw2xrf_get(gnrc_netdev_t *netdev, netopt_t opt, void *value, size_t max_len) -{ - kw2xrf_t *dev = (kw2xrf_t *)netdev; - - if (dev == NULL) { - return -ENODEV; - } - - switch (opt) { - case NETOPT_ADDRESS: - if (max_len < sizeof(uint16_t)) { - return -EOVERFLOW; - } - - *((uint16_t *)value) = kw2xrf_get_addr_short(dev); - return sizeof(uint16_t); - - case NETOPT_ADDRESS_LONG: - if (max_len < sizeof(uint64_t)) { - return -EOVERFLOW; - } - - *((uint64_t *)value) = kw2xrf_get_addr_long(dev); - return sizeof(uint64_t); - - case NETOPT_ADDR_LEN: - if (max_len < sizeof(uint16_t)) { - return -EOVERFLOW; - } - - *((uint16_t *)value) = 2; - return sizeof(uint16_t); - - case NETOPT_SRC_LEN: - if (max_len < sizeof(uint16_t)) { - return -EOVERFLOW; - } - - if (dev->option & KW2XRF_OPT_SRC_ADDR_LONG) { - *((uint16_t *)value) = IEEE802154_LONG_ADDRESS_LEN; - } - else { - *((uint16_t *)value) = IEEE802154_SHORT_ADDRESS_LEN; - } - - return sizeof(uint16_t); - - case NETOPT_NID: - if (max_len < sizeof(uint16_t)) { - return -EOVERFLOW; - } - - *((uint16_t *)value) = dev->radio_pan; - return sizeof(uint16_t); - - case NETOPT_IPV6_IID: - if (max_len < sizeof(eui64_t)) { - return -EOVERFLOW; - } - if (dev->option & KW2XRF_OPT_SRC_ADDR_LONG) { - uint64_t addr = kw2xrf_get_addr_long(dev); - ieee802154_get_iid(value, (uint8_t *)&addr, IEEE802154_LONG_ADDRESS_LEN); - } - else { - uint16_t addr = kw2xrf_get_addr_short(dev); - ieee802154_get_iid(value, (uint8_t *)&addr, IEEE802154_SHORT_ADDRESS_LEN); - } - return sizeof(eui64_t); - - case NETOPT_CHANNEL: - return kw2xrf_get_channel(dev, (uint8_t *)value, max_len); - - case NETOPT_PROTO: - return kw2xrf_get_proto(dev, (uint8_t *)value, max_len); - - case NETOPT_STATE: - if (max_len < sizeof(netopt_state_t)) { - return -EOVERFLOW; - } - - *(netopt_state_t *)value = *(netopt_state_t *) & (dev->state); - return 0; - - case NETOPT_TX_POWER: - if (max_len < 1) { - return -EOVERFLOW; - } - - *(int16_t *)value = dev->tx_power; - return 0; - - case NETOPT_CCA_THRESHOLD: - if (max_len < sizeof(uint8_t)) { - return -EOVERFLOW; - } else { - *(int8_t *)value = kw2xrf_get_cca_threshold(dev); - } - return 0; - - case NETOPT_MAX_PACKET_SIZE: - if (max_len < sizeof(int16_t)) { - return -EOVERFLOW; - } - - *((uint16_t *)value) = KW2XRF_MAX_PKT_LENGTH - _MAX_MHR_OVERHEAD; - return sizeof(uint16_t); - - case NETOPT_PRELOADING: - *((netopt_enable_t *)value) = !!(dev->option & KW2XRF_OPT_PRELOADING); - return sizeof(netopt_enable_t); - - case NETOPT_AUTOACK: - *((netopt_enable_t *)value) = !!(dev->option & KW2XRF_OPT_AUTOACK); - return sizeof(netopt_enable_t); - - case NETOPT_PROMISCUOUSMODE: - *((netopt_enable_t *)value) = !!(dev->option & KW2XRF_OPT_PROMISCUOUS); - return sizeof(netopt_enable_t); - - case NETOPT_RAWMODE: - *((netopt_enable_t *)value) = !!(dev->option & KW2XRF_OPT_RAWDUMP); - return sizeof(netopt_enable_t); - - default: - return -ENOTSUP; - } -} - -void kw2xrf_set_option(kw2xrf_t *dev, uint16_t option, bool state) -{ - uint8_t reg; - - DEBUG("set option %i to %i\n", option, state); - - /* set option field */ - if (state) { - dev->option |= option; - - /* trigger option specific actions */ - switch (option) { - case KW2XRF_OPT_CSMA: - DEBUG("[kw2xrf] opt: enabling CSMA mode\n"); - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - reg |= MKW2XDM_PHY_CTRL1_CCABFRTX; - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL1, reg); - break; - - case KW2XRF_OPT_PROMISCUOUS: - DEBUG("[kw2xrf] opt: enabling PROMISCUOUS mode\n"); - /* disable auto ACKs in promiscuous mode */ - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - reg &= ~(MKW2XDM_PHY_CTRL1_AUTOACK); - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL1, reg); - /* enable promiscuous mode */ - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL4); - reg |= MKW2XDM_PHY_CTRL4_PROMISCUOUS; - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL4, reg); - break; - - case KW2XRF_OPT_AUTOACK: - DEBUG("[kw2xrf] opt: enabling auto ACKs\n"); - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - reg |= MKW2XDM_PHY_CTRL1_AUTOACK; - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL1, reg); - break; - - default: - /* do nothing */ - break; - } - } - else { - dev->option &= ~(option); - - /* trigger option specific actions */ - switch (option) { - case KW2XRF_OPT_CSMA: - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - reg &= ~(MKW2XDM_PHY_CTRL1_CCABFRTX); - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL1, reg); - break; - - case KW2XRF_OPT_PROMISCUOUS: - /* disable promiscuous mode */ - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL4); - reg &= ~(MKW2XDM_PHY_CTRL4_PROMISCUOUS); - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL4, reg); - - /* re-enable AUTOACK only if the option is set */ - if (dev->option & KW2XRF_OPT_AUTOACK) { - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - reg |= MKW2XDM_PHY_CTRL1_AUTOACK; - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL1, reg); - } - - break; - - case KW2XRF_OPT_AUTOACK: - reg = kw2xrf_read_dreg(MKW2XDM_PHY_CTRL1); - reg &= ~(MKW2XDM_PHY_CTRL1_AUTOACK); - kw2xrf_write_dreg(MKW2XDM_PHY_CTRL1, reg); - break; - - default: - /* do nothing */ - break; - } - } -} - -int kw2xrf_set(gnrc_netdev_t *netdev, netopt_t opt, void *value, size_t value_len) -{ - kw2xrf_t *dev = (kw2xrf_t *)netdev; - - if (dev == NULL) { - return -ENODEV; - } - - switch (opt) { - case NETOPT_CHANNEL: - return kw2xrf_set_channel(dev, (uint8_t *)value, value_len); - - case NETOPT_ADDRESS: - if (value_len > sizeof(uint16_t)) { - return -EOVERFLOW; - } - - return kw2xrf_set_addr(dev, *((uint16_t *)value)); - - case NETOPT_ADDRESS_LONG: - if (value_len > sizeof(uint64_t)) { - return -EOVERFLOW; - } - - return kw2xrf_set_addr_long(dev, *((uint64_t *)value)); - - case NETOPT_SRC_LEN: - if (value_len > sizeof(uint16_t)) { - return -EOVERFLOW; - } - - if (*((uint16_t *)value) == IEEE802154_SHORT_ADDRESS_LEN) { - kw2xrf_set_option(dev, KW2XRF_OPT_SRC_ADDR_LONG, - false); - } - else if (*((uint16_t *)value) == IEEE802154_LONG_ADDRESS_LEN) { - kw2xrf_set_option(dev, KW2XRF_OPT_SRC_ADDR_LONG, - true); - } - else { - return -ENOTSUP; - } - - return sizeof(uint16_t); - - case NETOPT_NID: - if (value_len > sizeof(uint16_t)) { - return -EOVERFLOW; - } - - return kw2xrf_set_pan(dev, *((uint16_t *)value)); - - case NETOPT_TX_POWER: - if (value_len < sizeof(uint16_t)) { - return -EOVERFLOW; - } - /* correct value if out of valid range */ - if (*(int16_t *)value > MKW2XDRF_OUTPUT_POWER_MAX) { - *(int16_t *)value = MKW2XDRF_OUTPUT_POWER_MAX; - } - else if (*(int16_t *)value < MKW2XDRF_OUTPUT_POWER_MIN) { - *(int16_t *)value = MKW2XDRF_OUTPUT_POWER_MIN; - } - kw2xrf_set_tx_power(dev, (int8_t *)value, value_len); - dev->tx_power = *((uint16_t *)value); - return sizeof(uint16_t); - - case NETOPT_CCA_THRESHOLD: - if (value_len < sizeof(uint8_t)) { - return -EOVERFLOW; - } else { - kw2xrf_set_cca_threshold(dev, *((int8_t*)value)); - } - return sizeof(uint8_t); - - case NETOPT_PROTO: - return kw2xrf_set_proto(dev, (uint8_t *)value, value_len); - - case NETOPT_AUTOACK: - /* Set up HW generated automatic ACK after Receive */ - kw2xrf_set_option(dev, KW2XRF_OPT_AUTOACK, - ((bool *)value)[0]); - return sizeof(netopt_enable_t); - - case NETOPT_PROMISCUOUSMODE: - kw2xrf_set_option(dev, KW2XRF_OPT_PROMISCUOUS, - ((bool *)value)[0]); - return sizeof(netopt_enable_t); - - case NETOPT_RAWMODE: - kw2xrf_set_option(dev, KW2XRF_OPT_RAWDUMP, - ((bool *)value)[0]); - return sizeof(netopt_enable_t); - - case NETOPT_PRELOADING: - kw2xrf_set_option(dev, KW2XRF_OPT_PRELOADING, - ((bool *)value)[0]); - return sizeof(netopt_enable_t); - - case NETOPT_AUTOCCA: - kw2xrf_set_option(dev, KW2XRF_OPT_CSMA, - ((bool *)value)[0]); - return sizeof(netopt_enable_t); - - case NETOPT_STATE: - if (*((netopt_state_t *)value) == NETOPT_STATE_TX) { - DEBUG("kw2xrf: Sending now.\n"); - kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); - return sizeof(netopt_state_t); - } - else if (*((netopt_state_t *)value) == NETOPT_STATE_SLEEP) { - kw2xrf_set_sequence(dev, XCVSEQ_IDLE); - return sizeof(netopt_state_t); - } - else if (*((netopt_state_t *)value) == NETOPT_STATE_IDLE) { - kw2xrf_set_sequence(dev, XCVSEQ_RECEIVE); - return sizeof(netopt_state_t); - } - - /* TODO: Implement Off state here, when LPM functions are implemented */ - - default: - return -ENOTSUP; - } -} - -/* TODO: generalize and move to ieee802154 */ -/* TODO: include security header implications */ -static size_t _get_frame_hdr_len(uint8_t *mhr) -{ - uint8_t tmp; - size_t len = 3; - - /* figure out address sizes */ - tmp = (mhr[1] & IEEE802154_FCF_DST_ADDR_MASK); - - if (tmp == IEEE802154_FCF_DST_ADDR_SHORT) { - len += 4; - } - else if (tmp == IEEE802154_FCF_DST_ADDR_LONG) { - len += 10; - } - else if (tmp != IEEE802154_FCF_DST_ADDR_VOID) { - return 0; - } - - tmp = (mhr[1] & IEEE802154_FCF_SRC_ADDR_MASK); - - if (tmp == IEEE802154_FCF_SRC_ADDR_VOID) { - return len; - } - else { - if (!(mhr[0] & IEEE802154_FCF_PAN_COMP)) { - len += 2; - } - - if (tmp == IEEE802154_FCF_SRC_ADDR_SHORT) { - return (len + IEEE802154_SHORT_ADDRESS_LEN); - } - else if (tmp == IEEE802154_FCF_SRC_ADDR_LONG) { - return (len + IEEE802154_LONG_ADDRESS_LEN); - } - } - - return 0; -} - -/* TODO: generalize and move to (gnrc_)ieee802154 */ -static gnrc_pktsnip_t *_make_netif_hdr(uint8_t *mhr) +static void kw2xrf_set_address(kw2xrf_t *dev) { - uint8_t tmp; - uint8_t *addr; - uint8_t src_len, dst_len; - gnrc_pktsnip_t *snip; - gnrc_netif_hdr_t *hdr; - - /* figure out address sizes */ - tmp = mhr[1] & IEEE802154_FCF_SRC_ADDR_MASK; - - if (tmp == IEEE802154_FCF_SRC_ADDR_SHORT) { - src_len = IEEE802154_SHORT_ADDRESS_LEN; - } - else if (tmp == IEEE802154_FCF_SRC_ADDR_LONG) { - src_len = IEEE802154_LONG_ADDRESS_LEN; - } - else if (tmp == 0) { - src_len = 0; - } - else { - return NULL; - } - - tmp = mhr[1] & IEEE802154_FCF_DST_ADDR_MASK; - - if (tmp == IEEE802154_FCF_DST_ADDR_SHORT) { - dst_len = IEEE802154_SHORT_ADDRESS_LEN; - } - else if (tmp == IEEE802154_FCF_DST_ADDR_LONG) { - dst_len = IEEE802154_LONG_ADDRESS_LEN; - } - else if (tmp == 0) { - dst_len = 0; - } - else { - return NULL; - } - - /* allocate space for header */ - snip = gnrc_pktbuf_add(NULL, NULL, sizeof(gnrc_netif_hdr_t) + src_len + dst_len, - GNRC_NETTYPE_NETIF); - - if (snip == NULL) { - return NULL; - } - - /* fill header */ - hdr = (gnrc_netif_hdr_t *)snip->data; - gnrc_netif_hdr_init(hdr, src_len, dst_len); - - if (dst_len > 0) { - tmp = 5 + dst_len; - addr = gnrc_netif_hdr_get_dst_addr(hdr); - - for (int i = 0; i < dst_len; i++) { - addr[i] = mhr[5 + (dst_len - i) - 1]; - } - } - else { - tmp = 3; - } + eui64_t addr_long; + addr_long.uint64.u64 = KW2XRF_DEFAULT_ADDR_LONG; + uint16_t addr_short = KW2XRF_DEFAULT_SHORT_ADDR; - if (!(mhr[0] & IEEE802154_FCF_PAN_COMP)) { - tmp += 2; - } +#if CPUID_LEN + if (CPUID_LEN) { + uint8_t cpuid[KW2XRF_ID_LEN]; + /* in case CPUID_LEN < 8, fill missing bytes with zeros */ + memset(cpuid, 0, CPUID_LEN); - if (src_len > 0) { - addr = gnrc_netif_hdr_get_src_addr(hdr); + cpuid_get(cpuid); - for (int i = 0; i < src_len; i++) { - addr[i] = mhr[tmp + (src_len - i) - 1]; + /* generate short hardware address if CPUID_LEN > 0 */ + for (int i = 0; i < CPUID_LEN; i++) { + /* XOR each even byte of the CPUID with LSB of short address + and each odd byte with MSB */ + addr_short ^= (uint16_t)(cpuid[i] << ((i & 0x01) * 8)); } - } - - return snip; -} - -void _receive_data(kw2xrf_t *dev) -{ - size_t pkt_len, hdr_len; - gnrc_pktsnip_t *hdr, *payload = NULL; - gnrc_netif_hdr_t *netif; - - /* get size of the received packet */ - pkt_len = kw2xrf_read_dreg(MKW2XDM_RX_FRM_LEN); - - /* read PSDU */ - kw2xrf_read_fifo(dev->buf, pkt_len + 1); - - /* abort here already if no event callback is registered */ - if (!dev->event_cb) { - return; - } - /* If RAW-mode is selected directly forward pkt, MAC does the rest */ - if (dev->option & KW2XRF_OPT_RAWDUMP) { - payload = gnrc_pktbuf_add(NULL, NULL, pkt_len, GNRC_NETTYPE_UNDEF); - - if (payload == NULL) { - DEBUG("kw2xf: error: unable to allocate RAW data\n"); - return; + for (int i = IEEE802154_LONG_ADDRESS_LEN; i < CPUID_LEN; i++) { + cpuid[i & 0x07] ^= cpuid[i]; } - payload->data = dev->buf; - dev->event_cb(NETDEV_EVENT_RX_COMPLETE, payload); - return; - } - - /* get FCF field and compute 802.15.4 header length */ - hdr_len = _get_frame_hdr_len(dev->buf); - - if (hdr_len == 0) { - DEBUG("kw2xrf error: unable parse incoming frame header\n"); - return; - } - - /* read the rest of the header and parse the netif header from it */ - hdr = _make_netif_hdr(dev->buf); - - if (hdr == NULL) { - DEBUG("kw2xrf error: unable to allocate netif header\n"); - return; - } - - /* fill missing fields in netif header */ - netif = (gnrc_netif_hdr_t *)hdr->data; - netif->if_pid = thread_getpid(); - netif->lqi = dev->buf[pkt_len]; - /* lqi and rssi are directly related to each other in the kw2x-device. - * The rssi-unit is dBm and in this case always negative, nevertheless a - * positive value is reported. - */ - netif->rssi = -((netif->lqi) - 286.6) / 2.69333; - - payload = gnrc_pktbuf_add(hdr, (void *) & (dev->buf[hdr_len]), - pkt_len - hdr_len - 2, dev->proto); - - if (payload == NULL) { - DEBUG("kw2xrf: ERROR allocating payload in packet buffer on RX\n"); - gnrc_pktbuf_release(hdr); - return; + /* make sure we mark the address as non-multicast and not globally unique */ + cpuid[0] &= ~(0x01); + cpuid[0] |= 0x02; + /* copy and set long address */ + memcpy(&addr_long, cpuid, IEEE802154_LONG_ADDRESS_LEN); } +#endif - dev->event_cb(NETDEV_EVENT_RX_COMPLETE, payload); + kw2xrf_set_addr_long(dev, addr_long.uint64.u64); + kw2xrf_set_addr_short(dev, addr_short); } -void kw2xrf_isr_event(gnrc_netdev_t *netdev, uint32_t event_type) +void kw2xrf_setup(kw2xrf_t *dev, const kw2xrf_params_t *params) { - kw2xrf_t *dev = (kw2xrf_t *)netdev; - uint8_t irqst1 = kw2xrf_read_dreg(MKW2XDM_IRQSTS1); - uint8_t irqst2 = kw2xrf_read_dreg(MKW2XDM_IRQSTS2); + netdev2_t *netdev = (netdev2_t *)dev; - if ((irqst1 & MKW2XDM_IRQSTS1_RXIRQ) && (irqst1 & MKW2XDM_IRQSTS1_SEQIRQ)) { - /* RX */ - DEBUG("kw2xrf: RX Int\n"); - _receive_data(dev); - kw2xrf_set_sequence(dev, XCVSEQ_RECEIVE); - kw2xrf_write_dreg(MKW2XDM_IRQSTS1, MKW2XDM_IRQSTS1_RXIRQ | MKW2XDM_IRQSTS1_SEQIRQ); - } - else if ((irqst1 & MKW2XDM_IRQSTS1_TXIRQ) && (irqst1 & MKW2XDM_IRQSTS1_SEQIRQ)) { - /* TX_Complete */ - /* Device is automatically in Radio-idle state when TX is done */ - kw2xrf_set_sequence(dev, XCVSEQ_RECEIVE); - DEBUG("kw2xrf: TX Complete\n"); - kw2xrf_write_dreg(MKW2XDM_IRQSTS1, MKW2XDM_IRQSTS1_TXIRQ | MKW2XDM_IRQSTS1_SEQIRQ); - } - else if ((irqst1 & MKW2XDM_IRQSTS1_CCAIRQ) && (irqst1 & MKW2XDM_IRQSTS1_SEQIRQ)) { - /* TX_Started (CCA_done) */ - if (irqst2 & MKW2XDM_IRQSTS2_CCA) { - DEBUG("kw2xrf: CCA done -> Channel busy\n"); - } - else { - DEBUG("kw2xrf: CCA done -> Channel idle\n"); - } + netdev->driver = &kw2xrf_driver; + /* initialize device descriptor */ + memcpy(&dev->params, params, sizeof(kw2xrf_params_t)); + dev->idle_state = XCVSEQ_RECEIVE; + dev->state = 0; + dev->pending_tx = 0; - kw2xrf_write_dreg(MKW2XDM_IRQSTS1, MKW2XDM_IRQSTS1_CCAIRQ | MKW2XDM_IRQSTS1_SEQIRQ); - kw2xrf_set_sequence(dev, XCVSEQ_RECEIVE); - } - else { - /* Unknown event */ - /* Clear all interrupts to prevent ISR-loop */ - kw2xrf_write_dreg(MKW2XDM_IRQSTS1, 0x7f); - kw2xrf_write_dreg(MKW2XDM_IRQSTS2, 0x03); - kw2xrf_write_dreg(MKW2XDM_IRQSTS3, 0xff); - DEBUG("kw2xrf_isr_event: unknown Interrupt\n"); - kw2xrf_set_sequence(dev, XCVSEQ_RECEIVE); - return; - } + kw2xrf_spi_init(dev); + kw2xrf_set_power_mode(dev, KW2XRF_IDLE); + DEBUG("[kw2xrf]: setup finished\n"); } -/* TODO: Move to gnrc_ieee802.15.4 as soon as ready */ -int _assemble_tx_buf(kw2xrf_t *dev, gnrc_pktsnip_t *pkt) +int kw2xrf_init(kw2xrf_t *dev, gpio_cb_t cb) { - gnrc_netif_hdr_t *hdr; - int index = 4; - if (dev == NULL) { - return 0; - } - - /* get netif header check address length */ - hdr = (gnrc_netif_hdr_t *)pkt->data; - - /* we are building a data frame here */ - dev->buf[1] = IEEE802154_FCF_TYPE_DATA; - dev->buf[2] = IEEE802154_FCF_VERS_V0; - - /* if AUTOACK is enabled, then we also expect ACKs for this packet */ - if (!(hdr->flags & GNRC_NETIF_HDR_FLAGS_BROADCAST) && - !(hdr->flags & GNRC_NETIF_HDR_FLAGS_MULTICAST) && - (dev->option & KW2XRF_OPT_AUTOACK)) { - dev->buf[1] |= IEEE802154_FCF_ACK_REQ; - } - - /* set destination pan_id */ - dev->buf[index++] = (uint8_t)((dev->radio_pan) & 0xff); - dev->buf[index++] = (uint8_t)((dev->radio_pan) >> 8); - - /* fill in destination address */ - if (hdr->flags & - (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) { - dev->buf[2] |= IEEE802154_FCF_DST_ADDR_SHORT; - dev->buf[index++] = 0xff; - dev->buf[index++] = 0xff; - } - else if (hdr->dst_l2addr_len == IEEE802154_SHORT_ADDRESS_LEN) { - /* set to short addressing mode */ - dev->buf[2] |= IEEE802154_FCF_DST_ADDR_SHORT; - /* set destination address, byte order is inverted */ - uint8_t *dst_addr = gnrc_netif_hdr_get_dst_addr(hdr); - dev->buf[index++] = dst_addr[1]; - dev->buf[index++] = dst_addr[0]; - } - else if (hdr->dst_l2addr_len == IEEE802154_LONG_ADDRESS_LEN) { - /* default to use long address mode for src and dst */ - dev->buf[2] |= IEEE802154_FCF_DST_ADDR_LONG; - /* set destination address located directly after gnrc_ifhrd_t in memory */ - uint8_t *dst_addr = gnrc_netif_hdr_get_dst_addr(hdr); - for (int i = IEEE802154_LONG_ADDRESS_LEN - 1; i >= 0; i--) { - dev->buf[index++] = dst_addr[i]; - } - } - else { - return 0; + return -ENODEV; } - /* fill in source PAN ID (if applicable */ - if (dev->option & KW2XRF_OPT_USE_SRC_PAN) { - dev->buf[index++] = (uint8_t)((dev->radio_pan) & 0xff); - dev->buf[index++] = (uint8_t)((dev->radio_pan) >> 8); - } - else { - dev->buf[1] |= IEEE802154_FCF_PAN_COMP; - } + kw2xrf_set_out_clk(dev); + kw2xrf_disable_interrupts(dev); + /* set up GPIO-pin used for IRQ */ + gpio_init_int(dev->params.int_pin, GPIO_IN, GPIO_FALLING, cb, dev); - /* insert source address according to length */ - if (hdr->src_l2addr_len == IEEE802154_SHORT_ADDRESS_LEN) { - dev->buf[2] |= IEEE802154_FCF_SRC_ADDR_SHORT; - dev->buf[index++] = (uint8_t)(dev->addr_short[0]); - dev->buf[index++] = (uint8_t)(dev->addr_short[1]); - } - else { - dev->buf[2] |= IEEE802154_FCF_SRC_ADDR_LONG; - memcpy(&(dev->buf[index]), dev->addr_long, IEEE802154_LONG_ADDRESS_LEN); - index += IEEE802154_LONG_ADDRESS_LEN; - } - /* set sequence number */ - dev->buf[3] = dev->seq_nr++; + kw2xrf_abort_sequence(dev); + kw2xrf_update_overwrites(dev); + kw2xrf_timer_init(dev, KW2XRF_TIMEBASE_62500HZ); + DEBUG("[kw2xrf]: init finished\n"); - /* return header size */ - return index; + return 0; } -int kw2xrf_send(gnrc_netdev_t *netdev, gnrc_pktsnip_t *pkt) +void kw2xrf_reset_phy(kw2xrf_t *dev) { - int index = 0; - kw2xrf_t *dev = (kw2xrf_t *) netdev; - - if ((dev->option & KW2XRF_OPT_PRELOADING) == NETOPT_DISABLE) { - kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); - } - - if (pkt == NULL) { - return -ENOMSG; - } - - gnrc_pktsnip_t *payload = pkt->next; + /* reset options and sequence number */ + dev->netdev.seq = 0; + dev->netdev.flags = 0; - if (netdev == NULL) { - gnrc_pktbuf_release(pkt); - return -ENODEV; - } - - if (pkt->type == GNRC_NETTYPE_NETIF) { - /* Build header and fills this already into the tx-buf */ - index = _assemble_tx_buf(dev, pkt); - if (index == 0) { - DEBUG("Unable to create 802.15.4 header\n"); - gnrc_pktbuf_release(pkt); - return -ENOMSG; - } - DEBUG("Assembled header for GNRC_NETTYPE_UNDEF to tx-buf, index: %i\n", index); - } - else if (pkt->type == GNRC_NETTYPE_UNDEF) { - /* IEEE packet is already included in the header, - * no need to build the header manually */ - DEBUG("Incoming packet of type GNRC_NETTYPE_802154: %i\n", index); - DEBUG("size of pktsnip: %i\n", pkt->size); + /* set default protocol */ +#ifdef MODULE_GNRC_SIXLOWPAN + dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN; +#elif MODULE_GNRC + dev->netdev.proto = GNRC_NETTYPE_UNDEF; +#endif - for (int i = 0; i < pkt->size; i++) { - uint8_t *tmp = pkt->data; - dev->buf[index + i + 1] = tmp[i]; - } + dev->tx_power = KW2XRF_DEFAULT_TX_POWER; + kw2xrf_set_tx_power(dev, dev->tx_power); - /* count bytes */ - index += pkt->size; - } - else { - DEBUG("Driver does not support this type of packet\n"); - return -ENOTSUP; - } + kw2xrf_set_channel(dev, KW2XRF_DEFAULT_CHANNEL); - while (payload) { - /* check we don't exceed FIFO size */ - if (index + 2 + payload->size > KW2XRF_MAX_PKT_LENGTH) { - gnrc_pktbuf_release(pkt); - DEBUG("Packet exceeded FIFO size.\n"); - return -ENOBUFS; - } + kw2xrf_set_pan(dev, KW2XRF_DEFAULT_PANID); + kw2xrf_set_address(dev); - for (int i = 0; i < payload->size; i++) { - uint8_t *tmp = payload->data; - dev->buf[index + i] = tmp[i]; - } + kw2xrf_set_cca_mode(dev, 1); - /* count bytes */ - index += payload->size; + kw2xrf_set_rx_watermark(dev, 1); - /* next snip */ - payload = payload->next; - } + kw2xrf_set_option(dev, KW2XRF_OPT_AUTOACK, true); + kw2xrf_set_option(dev, KW2XRF_OPT_ACK_REQ, true); + kw2xrf_set_option(dev, KW2XRF_OPT_AUTOCCA, true); - dev->buf[0] = index + 1; /* set packet size */ + kw2xrf_set_power_mode(dev, KW2XRF_AUTODOZE); + kw2xrf_set_sequence(dev, dev->idle_state); - gnrc_pktbuf_release(pkt); - DEBUG("kw2xrf: packet with size %i loaded to tx_buf\n", dev->buf[0]); - kw2xrf_write_fifo(dev->buf, dev->buf[0]); + kw2xrf_set_option(dev, KW2XRF_OPT_TELL_RX_START, true); + kw2xrf_set_option(dev, KW2XRF_OPT_TELL_RX_END, true); + kw2xrf_set_option(dev, KW2XRF_OPT_TELL_TX_END, true); + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL2, MKW2XDM_PHY_CTRL2_SEQMSK); - if ((dev->option & KW2XRF_OPT_PRELOADING) == NETOPT_DISABLE) { - DEBUG("kw2xrf: Sending now.\n"); - kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); - } + kw2xrf_enable_irq_b(dev); - return index; + DEBUG("[kw2xrf]: Initialized and set to channel %d and pan %d.\n", + KW2XRF_DEFAULT_CHANNEL, KW2XRF_DEFAULT_PANID); } - -/* implementation of the netdev interface */ -const gnrc_netdev_driver_t kw2xrf_driver = { - .send_data = kw2xrf_send, - .add_event_callback = kw2xrf_add_cb, - .rem_event_callback = kw2xrf_rem_cb, - .get = kw2xrf_get, - .set = kw2xrf_set, - .isr_event = kw2xrf_isr_event, -}; diff --git a/drivers/kw2xrf/kw2xrf_getset.c b/drivers/kw2xrf/kw2xrf_getset.c new file mode 100644 index 0000000000..5f64b80eb8 --- /dev/null +++ b/drivers/kw2xrf/kw2xrf_getset.c @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2016 PHYTEC Messtechnik GmbH + * + * 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_kw2xrf + * @{ + * @file + * @brief get/set functionality of kw2xrf driver + * + * @author Johann Fischer <j.fischer@phytec.de> + * @author Jonas Remmert <j.remmert@phytec.de> + * @author Oliver Hahm <oliver.hahm@inria.fr> + * @} + */ + +#include "kw2xrf.h" +#include "kw2xrf_spi.h" +#include "kw2xrf_reg.h" +#include "kw2xrf_getset.h" +#include "kw2xrf_intern.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define KW2XRF_LQI_HW_MAX 230 /**< LQI Saturation Level */ + +/* Modem_PA_PWR Register (PA Power Control) has a valid range from 3-31 */ +#define MKW2XDRF_PA_RANGE_MAX 31 /**< Maximum value of PA Power Control Register */ +#define MKW2XDRF_PA_RANGE_MIN 3 /**< Minimum value of PA Power Control Register */ + +/* PLL integer and fractional lookup tables + * + * Fc = 2405 + 5(k - 11) , k = 11,12,...,26 + * + * Equation for PLL frequency, MKW2xD Reference Manual, p.255 : + * F = ((PLL_INT0 + 64) + (PLL_FRAC0/65536))32MHz + * + */ +static const uint8_t pll_int_lt[16] = { + 11, 11, 11, 11, + 11, 11, 12, 12, + 12, 12, 12, 12, + 13, 13, 13, 13 +}; + +static const uint16_t pll_frac_lt[16] = { + 10240, 20480, 30720, 40960, + 51200, 61440, 6144, 16384, + 26624, 36864, 47104, 57344, + 2048, 12288, 22528, 32768 +}; + +static const uint8_t pow_lt[44] = { + 3, 4, 4, 5, + 6, 6, 7, 7, + 8, 9, 9, 10, + 11, 11, 12, 13, + 13, 14, 14, 15, + 16, 16, 17, 18, + 18, 19, 20, 20, + 21, 21, 22, 23, + 23, 24, 25, 25, + 26, 27, 27, 28, + 28, 29, 30, 31 +}; + +void kw2xrf_set_tx_power(kw2xrf_t *dev, int16_t txpower) +{ + if (txpower > MKW2XDRF_OUTPUT_POWER_MAX) { + txpower = MKW2XDRF_OUTPUT_POWER_MAX; + } + + if (txpower < MKW2XDRF_OUTPUT_POWER_MIN) { + txpower = MKW2XDRF_OUTPUT_POWER_MIN; + } + + uint8_t level = pow_lt[txpower - MKW2XDRF_OUTPUT_POWER_MIN]; + kw2xrf_write_dreg(dev, MKW2XDM_PA_PWR, MKW2XDM_PA_PWR(level)); + dev->tx_power = txpower; +} + +uint16_t kw2xrf_get_txpower(kw2xrf_t *dev) +{ + return dev->tx_power; +} + +uint8_t kw2xrf_get_channel(kw2xrf_t *dev) +{ + uint8_t pll_int = kw2xrf_read_dreg(dev, MKW2XDM_PLL_INT0); + uint16_t pll_frac = kw2xrf_read_dreg(dev, MKW2XDM_PLL_FRAC0_LSB); + pll_frac |= ((uint16_t)kw2xrf_read_dreg(dev, MKW2XDM_PLL_FRAC0_MSB) << 8); + + for (int i = 0; i < 16; i++) { + if ((pll_frac_lt[i] == pll_frac) && (pll_int_lt[i] == pll_int)) { + return i + 11; + } + } + return 0; +} + +static int kw2xrf_get_sequence(kw2xrf_t *dev) +{ + int reg = 0; + reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1); + reg &= MKW2XDM_PHY_CTRL1_XCVSEQ_MASK; + return reg; +} + +int kw2xrf_set_channel(kw2xrf_t *dev, uint8_t channel) +{ + /* Save old sequence to restore this state later */ + uint8_t old_seq = kw2xrf_get_sequence(dev); + + if (channel < KW2XRF_MIN_CHANNEL || channel > KW2XRF_MAX_CHANNEL) { + DEBUG("[kw2xrf]: Invalid channel %i set\n", channel); + return -1; + } + + if (old_seq) { + kw2xrf_abort_sequence(dev); + } + + uint8_t tmp = channel - 11; + kw2xrf_write_dreg(dev, MKW2XDM_PLL_INT0, MKW2XDM_PLL_INT0_VAL(pll_int_lt[tmp])); + kw2xrf_write_dreg(dev, MKW2XDM_PLL_FRAC0_LSB, (uint8_t)pll_frac_lt[tmp]); + kw2xrf_write_dreg(dev, MKW2XDM_PLL_FRAC0_MSB, (uint8_t)(pll_frac_lt[tmp] >> 8)); + + dev->netdev.chan = channel; + + if (old_seq) { + kw2xrf_set_sequence(dev, old_seq); + } + + DEBUG("[kw2xrf]: set channel to %u\n", channel); + return 0; +} + +void kw2xrf_abort_sequence(kw2xrf_t *dev) +{ + uint8_t regs[MKW2XDM_PHY_CTRL4 + 1]; + + kw2xrf_mask_irq_b(dev); + kw2xrf_read_dregs(dev, MKW2XDM_IRQSTS1, regs, (MKW2XDM_PHY_CTRL4 + 1)); + + if ((regs[MKW2XDM_PHY_CTRL1] & MKW2XDM_PHY_CTRL1_XCVSEQ_MASK) != XCVSEQ_IDLE) { + /* abort any ongoing sequence */ + regs[MKW2XDM_PHY_CTRL1] &= ~(MKW2XDM_PHY_CTRL1_XCVSEQ_MASK); + kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL1, regs[MKW2XDM_PHY_CTRL1]); + } + + uint8_t state; + do { + state = kw2xrf_read_dreg(dev, MKW2XDM_SEQ_STATE); + DEBUG("[kw2xrf]: abort SEQ_STATE: %x\n", state); + } while ((state & 0x1F) != 0); + + /* clear all IRQ bits */ + regs[MKW2XDM_IRQSTS1] = 0x7f; + regs[MKW2XDM_IRQSTS2] = 0x03; + regs[MKW2XDM_IRQSTS3] |= 0x0f; + kw2xrf_write_dregs(dev, MKW2XDM_IRQSTS1, regs, 3); + + kw2xrf_enable_irq_b(dev); +} + +/* + * Simplified version for irq handling where the state of + * the sequenz manager is known. + */ +void kw2xrf_set_idle_sequence(kw2xrf_t *dev) +{ + kw2xrf_mask_irq_b(dev); + uint8_t reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1); + + /* reset sequenz manager */ + reg &= ~(MKW2XDM_PHY_CTRL1_XCVSEQ_MASK); + kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL1, reg); + + if (dev->pending_tx) { + DEBUG("[kw2xrf]: pending tx, cannot set idle sequenz\n"); + return; + } + + /* start new sequenz */ + reg |= MKW2XDM_PHY_CTRL1_XCVSEQ(dev->idle_state); + kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL1, reg); + + switch (dev->idle_state) { + case XCVSEQ_IDLE: + /* for inexplicable reasons, the receive mode is also idle mode */ + case XCVSEQ_RECEIVE: + dev->state = NETOPT_STATE_IDLE; + break; + + case XCVSEQ_CONTINUOUS_CCA: + case XCVSEQ_CCA: + dev->state = NETOPT_STATE_RX; + break; + + case XCVSEQ_TRANSMIT: + case XCVSEQ_TX_RX: + dev->state = NETOPT_STATE_TX; + break; + + default: + dev->state = NETOPT_STATE_IDLE; + } + + kw2xrf_enable_irq_b(dev); +} + +void kw2xrf_set_sequence(kw2xrf_t *dev, kw2xrf_physeq_t seq) +{ + uint8_t reg = 0; + + kw2xrf_abort_sequence(dev); + + switch (seq) { + case XCVSEQ_IDLE: + /* for inexplicable reasons, the receive mode is also idle mode */ + case XCVSEQ_RECEIVE: + dev->state = NETOPT_STATE_IDLE; + break; + + case XCVSEQ_CONTINUOUS_CCA: + case XCVSEQ_CCA: + dev->state = NETOPT_STATE_RX; + break; + + case XCVSEQ_TRANSMIT: + case XCVSEQ_TX_RX: + dev->state = NETOPT_STATE_TX; + break; + + default: + DEBUG("[kw2xrf]: undefined state assigned to phy\n"); + dev->state = NETOPT_STATE_IDLE; + } + + DEBUG("[kw2xrf]: set sequence to %i\n", seq); + reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1); + reg &= ~(MKW2XDM_PHY_CTRL1_XCVSEQ_MASK); + reg |= MKW2XDM_PHY_CTRL1_XCVSEQ(seq); + kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL1, reg); +} + +void kw2xrf_set_pan(kw2xrf_t *dev, uint16_t pan) +{ + dev->netdev.pan = pan; + + uint8_t val_ar[2]; + val_ar[1] = (pan >> 8); + val_ar[0] = (uint8_t)pan; + kw2xrf_write_iregs(dev, MKW2XDMI_MACPANID0_LSB, val_ar, 2); + dev->netdev.pan = pan; +} + +void kw2xrf_set_addr_short(kw2xrf_t *dev, uint16_t addr) +{ + uint8_t val_ar[2]; + val_ar[0] = (addr >> 8); + val_ar[1] = (uint8_t)addr; + dev->netdev.short_addr[0] = val_ar[1]; + dev->netdev.short_addr[1] = val_ar[0]; +#ifdef MODULE_SIXLOWPAN + /* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to + * 0 for unicast addresses */ + dev->netdev.short_addr[1] &= 0x7F; +#endif + kw2xrf_write_iregs(dev, MKW2XDMI_MACSHORTADDRS0_LSB, val_ar, + IEEE802154_SHORT_ADDRESS_LEN); +} + +void kw2xrf_set_addr_long(kw2xrf_t *dev, uint64_t addr) +{ + uint64_t tmp; + uint8_t *ap = (uint8_t *)(&tmp); + + for (int i = 0; i < IEEE802154_LONG_ADDRESS_LEN; i++) { + dev->netdev.long_addr[i] = (uint8_t)(addr >> (i * 8)); + ap[i] = (addr >> ((IEEE802154_LONG_ADDRESS_LEN - 1 - i) * 8)); + } + + kw2xrf_write_iregs(dev, MKW2XDMI_MACLONGADDRS0_0, ap, + IEEE802154_LONG_ADDRESS_LEN); +} + +uint16_t kw2xrf_get_addr_short(kw2xrf_t *dev) +{ + return (dev->netdev.short_addr[0] << 8) | dev->netdev.short_addr[1]; +} + +uint64_t kw2xrf_get_addr_long(kw2xrf_t *dev) +{ + uint64_t addr; + uint8_t *ap = (uint8_t *)(&addr); + + kw2xrf_read_iregs(dev, MKW2XDMI_MACLONGADDRS0_0, ap, + IEEE802154_LONG_ADDRESS_LEN); + + return addr; +} + +int8_t kw2xrf_get_cca_threshold(kw2xrf_t *dev) +{ + uint8_t tmp; + kw2xrf_read_iregs(dev, MKW2XDMI_CCA1_THRESH, &tmp, 1); + /* KW2x register value represents absolute value in dBm + * default value: -75 dBm + */ + return (-tmp); +} + +void kw2xrf_set_cca_threshold(kw2xrf_t *dev, int8_t value) +{ + /* normalize to absolute value */ + if (value < 0) { + value = -value; + } + kw2xrf_write_iregs(dev, MKW2XDMI_CCA1_THRESH, (uint8_t*)&value, 1); +} + +void kw2xrf_set_cca_mode(kw2xrf_t *dev, uint8_t mode) +{ + uint8_t tmp; + tmp = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL4); + tmp &= ~MKW2XDM_PHY_CTRL4_CCATYPE_MASK; + tmp |= MKW2XDM_PHY_CTRL4_CCATYPE(mode); + kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL4, tmp); +} + +uint8_t kw2xrf_get_cca_mode(kw2xrf_t *dev) +{ + uint8_t tmp; + tmp = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL4); + return (tmp & MKW2XDM_PHY_CTRL4_CCATYPE_MASK) >> MKW2XDM_PHY_CTRL4_CCATYPE_SHIFT; +} + +uint32_t kw2xrf_get_rssi(uint32_t value) +{ + /* Get rssi (Received Signal Strength Indicator, unit is dBm) + * from lqi (Link Quality Indicator) value. + * There are two different equations for RSSI: + * RF = (LQI – 286.6) / 2.69333 (MKW2xD Reference Manual) + * RF = (LQI – 295.4) / 2.84 (MCR20A Reference Manual) + * The last appears more to match the graphic (Figure 3-10). + * Since RSSI value is always positive and we want to + * avoid the floating point computation: + * -RF * 65536 = (LQI / 2.84 - 295.4 / 2.84) * 65536 + * RF * 65536 = (295.4 * 65536 / 2.84) - (LQI * 65536 / 2.84) + */ + uint32_t a = (uint32_t)(295.4 * 65536 / 2.84); + uint32_t b = (uint32_t)(65536 / 2.84); + return (a - (b * value)) >> 16; +} + +void kw2xrf_set_option(kw2xrf_t *dev, uint16_t option, bool state) +{ + DEBUG("[kw2xrf]: set option %i to %i\n", option, state); + + /* set option field */ + if (state) { + dev->netdev.flags |= option; + + /* trigger option specific actions */ + switch (option) { + case KW2XRF_OPT_AUTOCCA: + DEBUG("[kw2xrf] opt: enabling CCA before TX mode\n"); + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1, + MKW2XDM_PHY_CTRL1_CCABFRTX); + break; + + case KW2XRF_OPT_PROMISCUOUS: + DEBUG("[kw2xrf] opt: enabling PROMISCUOUS mode\n"); + /* disable auto ACKs in promiscuous mode */ + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1, + MKW2XDM_PHY_CTRL1_AUTOACK | MKW2XDM_PHY_CTRL1_RXACKRQD); + /* enable promiscuous mode */ + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL4, + MKW2XDM_PHY_CTRL4_PROMISCUOUS); + break; + + case KW2XRF_OPT_AUTOACK: + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1, + MKW2XDM_PHY_CTRL1_AUTOACK); + break; + + case KW2XRF_OPT_ACK_REQ: + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1, + MKW2XDM_PHY_CTRL1_RXACKRQD); + break; + + case KW2XRF_OPT_TELL_RX_START: + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL2, + MKW2XDM_PHY_CTRL2_RX_WMRK_MSK); + break; + + case KW2XRF_OPT_TELL_RX_END: + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL2, + MKW2XDM_PHY_CTRL2_RXMSK); + break; + + case KW2XRF_OPT_TELL_TX_END: + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL2, + MKW2XDM_PHY_CTRL2_TXMSK); + break; + + case KW2XRF_OPT_TELL_TX_START: + default: + /* do nothing */ + break; + } + } + else { + dev->netdev.flags &= ~(option); + /* trigger option specific actions */ + switch (option) { + case KW2XRF_OPT_AUTOCCA: + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1, + MKW2XDM_PHY_CTRL1_CCABFRTX); + break; + + case KW2XRF_OPT_PROMISCUOUS: + /* disable promiscuous mode */ + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL4, + MKW2XDM_PHY_CTRL4_PROMISCUOUS); + /* re-enable AUTOACK only if the option is set */ + if (dev->netdev.flags & KW2XRF_OPT_AUTOACK) { + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1, + MKW2XDM_PHY_CTRL1_AUTOACK); + } + if (dev->netdev.flags & KW2XRF_OPT_ACK_REQ) { + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1, + MKW2XDM_PHY_CTRL1_RXACKRQD); + } + break; + + case KW2XRF_OPT_AUTOACK: + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1, + MKW2XDM_PHY_CTRL1_AUTOACK); + break; + + case KW2XRF_OPT_ACK_REQ: + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1, + MKW2XDM_PHY_CTRL1_RXACKRQD); + break; + + case KW2XRF_OPT_TELL_RX_START: + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL2, + MKW2XDM_PHY_CTRL2_RX_WMRK_MSK); + break; + + case KW2XRF_OPT_TELL_RX_END: + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL2, + MKW2XDM_PHY_CTRL2_RXMSK); + break; + + case KW2XRF_OPT_TELL_TX_END: + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL2, + MKW2XDM_PHY_CTRL2_TXMSK); + break; + + + case KW2XRF_OPT_TELL_TX_START: + default: + /* do nothing */ + break; + } + } +} + +netopt_state_t kw2xrf_get_status(kw2xrf_t *dev) +{ + uint8_t reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1); + + switch (reg & MKW2XDM_PHY_CTRL1_XCVSEQ_MASK) { + case XCVSEQ_RECEIVE: + return NETOPT_STATE_RX; + + case XCVSEQ_TRANSMIT: + return NETOPT_STATE_TX; + + case XCVSEQ_CCA: + return NETOPT_STATE_RX; + + case XCVSEQ_TX_RX: + return NETOPT_STATE_TX; + + case XCVSEQ_CONTINUOUS_CCA: + return NETOPT_STATE_RX; + + case XCVSEQ_IDLE: + return NETOPT_STATE_IDLE; + default: + break; + } + return NETOPT_STATE_IDLE; +} + +int kw2xrf_cca(kw2xrf_t *dev) +{ + /* TODO: add Standalone CCA here */ + kw2xrf_seq_timeout_on(dev, 0x3ffff); + kw2xrf_set_sequence(dev, XCVSEQ_CONTINUOUS_CCA); + return 0; +} + +void kw2xrf_set_rx_watermark(kw2xrf_t *dev, uint8_t value) +{ + kw2xrf_write_iregs(dev, MKW2XDMI_RX_WTR_MARK, &value, 1); +} diff --git a/drivers/kw2xrf/kw2xrf_intern.c b/drivers/kw2xrf/kw2xrf_intern.c new file mode 100644 index 0000000000..5ef49177d3 --- /dev/null +++ b/drivers/kw2xrf/kw2xrf_intern.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2016 PHYTEC Messtechnik GmbH + * + * 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_kw2xrf + * @{ + * @file + * @brief Internal function of kw2xrf driver + * + * @author Johann Fischer <j.fischer@phytec.de> + * @} + */ + +#include "panic.h" +#include "kw2xrf.h" +#include "kw2xrf_spi.h" +#include "kw2xrf_reg.h" +#include "kw2xrf_getset.h" +#include "kw2xrf_intern.h" +#include "overwrites.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +void kw2xrf_disable_interrupts(kw2xrf_t *dev) +{ + /* Clear and disable all interrupts */ + kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL2, 0xff); + int reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL3); + reg |= MKW2XDM_PHY_CTRL3_WAKE_MSK | MKW2XDM_PHY_CTRL3_PB_ERR_MSK; + kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL3, reg); + + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, 0x7f); + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS2, 0x03); + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, 0xff); +} + +/* update overwrites register */ +void kw2xrf_update_overwrites(kw2xrf_t *dev) +{ + kw2xrf_write_dreg(dev, MKW2XDM_OVERWRITE_VER, overwrites_direct[0].data); + for (uint8_t i = 0; i < sizeof(overwrites_indirect)/sizeof(overwrites_t); i++) { + kw2xrf_write_iregs(dev, overwrites_indirect[i].address, + (uint8_t *)&(overwrites_indirect[i].data), 1); + } +} + +void kw2xrf_set_out_clk(kw2xrf_t *dev) +{ + /* TODO: add clock select */ + /* check modem's crystal oscillator, CLK_OUT shall be 4MHz */ + uint8_t tmp = kw2xrf_read_dreg(dev, MKW2XDM_CLK_OUT_CTRL); + if (tmp != 0x8Bu) { + core_panic(PANIC_GENERAL_ERROR, "Could not start MKW2XD radio transceiver"); + } +} + +void kw2xrf_set_power_mode(kw2xrf_t *dev, kw2xrf_powermode_t pm) +{ + uint8_t reg = 0; + switch (pm) { + case KW2XRF_HIBERNATE: + /* VREG off, XTAL off, Timer off, Current cons. < 1uA */ + reg = 0; + dev->state = NETOPT_STATE_SLEEP; + break; + + case KW2XRF_DOZE: + /* VREG off, XTAL on, Timer on/off, Current cons. 600uA */ + reg = MKW2XDM_PWR_MODES_XTALEN; + dev->state = NETOPT_STATE_SLEEP; + break; + + case KW2XRF_IDLE: + /* VREG on, XTAL on, Timer on, Current cons. 700uA */ + reg = MKW2XDM_PWR_MODES_XTALEN | MKW2XDM_PWR_MODES_PMC_MODE; + dev->state = NETOPT_STATE_IDLE; + break; + + case KW2XRF_AUTODOZE: + reg = MKW2XDM_PWR_MODES_XTALEN | MKW2XDM_PWR_MODES_AUTODOZE; + dev->state = NETOPT_STATE_IDLE; + break; + } + + kw2xrf_write_dreg(dev, MKW2XDM_PWR_MODES, reg); +} + +int kw2xrf_can_switch_to_idle(kw2xrf_t *dev) +{ + uint8_t state = kw2xrf_read_dreg(dev, MKW2XDM_SEQ_STATE); + uint8_t seq = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1) & MKW2XDM_PHY_CTRL1_XCVSEQ_MASK; + DEBUG("[kw2xrf]: state 0x%0x, seq 0x%0x\n", state, seq); + + if ((seq != XCVSEQ_TRANSMIT) && (seq != XCVSEQ_TX_RX)) { + return 1; + } + + if (state != 0) { + return 0; + } + + return 0; +} + +/** Load the timer value (Setting Current Time) */ +static void kw2xrf_timer_load(kw2xrf_t *dev, uint32_t value) +{ + kw2xrf_write_dregs(dev, MKW2XDM_T1CMP_LSB, (uint8_t *)&value, sizeof(value)); + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TMRLOAD); +} + +static uint32_t kw2xrf_timer_get(kw2xrf_t *dev) +{ + uint32_t tmp; + kw2xrf_read_dregs(dev, MKW2XDM_EVENT_TIMER_LSB, (uint8_t*)&tmp, sizeof(tmp)); + return tmp; +} + +/** Set an absolute timeout value for the given compare register of the Event Timer */ +static void kw2xrf_timer_set_absolute(kw2xrf_t *dev, uint8_t cmp_reg, uint32_t value) +{ + kw2xrf_write_dregs(dev, cmp_reg, (uint8_t *)&value, 3); +} + +/** Set an timeout value for the given compare register of the Event Timer */ +static void kw2xrf_timer_set(kw2xrf_t *dev, uint8_t cmp_reg, uint32_t timeout) +{ + uint32_t now = kw2xrf_timer_get(dev); + + DEBUG("[kw2xrf] timer now: %" PRIx32 ", set %" PRIx32 "\n", now, now + timeout); + kw2xrf_timer_set_absolute(dev, cmp_reg, now + timeout); +} + +void kw2xrf_timer_init(kw2xrf_t *dev, kw2xrf_timer_timebase_t tb) +{ + uint8_t tmp = MKW2XDMI_TMR_PRESCALE_SET(tb); + + kw2xrf_write_iregs(dev, MKW2XDMI_TMR_PRESCALE, &tmp, 1); + kw2xrf_timer_load(dev, 0); +} + +void kw2xrf_timer2_seq_start_on(kw2xrf_t *dev) +{ + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1, MKW2XDM_PHY_CTRL1_TMRTRIGEN); +} + +void kw2xrf_timer2_seq_start_off(kw2xrf_t *dev) +{ + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1, MKW2XDM_PHY_CTRL1_TMRTRIGEN); +} + +void kw2xrf_timer3_seq_abort_on(kw2xrf_t *dev) +{ + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TC3TMOUT); +} + +void kw2xrf_timer3_seq_abort_off(kw2xrf_t *dev) +{ + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TC3TMOUT); +} + +void kw2xrf_trigger_tx_ops_enable(kw2xrf_t *dev, uint32_t timeout) +{ + kw2xrf_timer_set(dev, MKW2XDM_T2CMP_LSB, timeout); + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR2CMP_EN); +} + +void kw2xrf_trigger_tx_ops_disable(kw2xrf_t *dev) +{ + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR2CMP_EN); + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, MKW2XDM_IRQSTS3_TMR2IRQ); + if (ENABLE_DEBUG) { + uint32_t now = kw2xrf_timer_get(dev); + printf("[kw2xrf] now: %" PRIx32 "\n", now); + } +} + +void kw2xrf_abort_rx_ops_enable(kw2xrf_t *dev, uint32_t timeout) +{ + kw2xrf_timer_set(dev, MKW2XDM_T3CMP_LSB, timeout); + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR3CMP_EN); +} + +void kw2xrf_abort_rx_ops_disable(kw2xrf_t *dev) +{ + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR3CMP_EN); + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, MKW2XDM_IRQSTS3_TMR3IRQ); + if (ENABLE_DEBUG) { + uint32_t now = kw2xrf_timer_get(dev); + printf("[kw2xrf] now: %" PRIx32 "\n", now); + } +} + +void kw2xrf_seq_timeout_on(kw2xrf_t *dev, uint32_t timeout) +{ + kw2xrf_mask_irq_b(dev); + kw2xrf_timer_set(dev, MKW2XDM_T4CMP_LSB, timeout); + + /* enable and clear irq for timer 3 */ + uint8_t irqsts3 = kw2xrf_read_dreg(dev, MKW2XDM_IRQSTS3) & 0xf0; + irqsts3 &= ~MKW2XDM_IRQSTS3_TMR4MSK; + irqsts3 |= MKW2XDM_IRQSTS3_TMR4IRQ; + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, irqsts3); + + kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR4CMP_EN); + kw2xrf_enable_irq_b(dev); +} + +void kw2xrf_seq_timeout_off(kw2xrf_t *dev) +{ + kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR4CMP_EN); + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, MKW2XDM_IRQSTS3_TMR4IRQ); + if (ENABLE_DEBUG) { + uint32_t now = kw2xrf_timer_get(dev); + printf("[kw2xrf] now: %" PRIx32 "\n", now); + } +} + +uint32_t kw2xrf_get_timestamp(kw2xrf_t *dev) +{ + uint32_t tmp; + kw2xrf_read_dregs(dev, MKW2XDM_TIMESTAMP_LSB, (uint8_t*)&tmp, sizeof(tmp)); + return tmp; +} diff --git a/drivers/kw2xrf/kw2xrf_netdev.c b/drivers/kw2xrf/kw2xrf_netdev.c new file mode 100644 index 0000000000..ccdd2c7ba7 --- /dev/null +++ b/drivers/kw2xrf/kw2xrf_netdev.c @@ -0,0 +1,765 @@ +/* + * Copyright (C) 2016 Phytec Messtechnik GmbH + * + * 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_kw2xrf + * @{ + * + * @file + * @brief Netdev interface for kw2xrf drivers + * + * @author Johann Fischer <j.fischer@phytec.de> + */ + +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include "net/eui64.h" +#include "net/ieee802154.h" +#include "net/netdev2.h" +#include "net/netdev2/ieee802154.h" + +#include "kw2xrf.h" +#include "kw2xrf_spi.h" +#include "kw2xrf_reg.h" +#include "kw2xrf_netdev.h" +#include "kw2xrf_getset.h" +#include "kw2xrf_tm.h" +#include "kw2xrf_intern.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define _MAX_MHR_OVERHEAD (25) + +#define _MACACKWAITDURATION (864 / 16) /* 864us * 62500Hz */ + +static uint8_t _send_last_fcf; + +static void _irq_handler(void *arg) +{ + netdev2_t *dev = (netdev2_t *) arg; + + if (dev->event_callback) { + dev->event_callback(dev, NETDEV2_EVENT_ISR); + } +} + +static int _init(netdev2_t *netdev) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + + /* initialise SPI and GPIOs */ + if (kw2xrf_init(dev, &_irq_handler)) { + DEBUG("[kw2xrf]: error: unable to initialize device\n"); + return -1; + } + +#ifdef MODULE_NETSTATS_L2 + memset(&netdev->stats, 0, sizeof(netstats_t)); +#endif + + /* reset device to default values and put it into RX state */ + kw2xrf_reset_phy(dev); + + return 0; +} + +static size_t kw2xrf_tx_load(uint8_t *pkt_buf, uint8_t *buf, size_t len, size_t offset) +{ + for (int i = 0; i < len; i++) { + pkt_buf[i + offset] = buf[i]; + } + return offset + len; +} + +static void kw2xrf_tx_exec(kw2xrf_t *dev) +{ + if ((dev->netdev.flags & KW2XRF_OPT_AUTOACK) && + (_send_last_fcf & IEEE802154_FCF_ACK_REQ)) { + kw2xrf_set_sequence(dev, XCVSEQ_TX_RX); + } + else { + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + } +} + +static int _send(netdev2_t *netdev, const struct iovec *vector, unsigned count) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + const struct iovec *ptr = vector; + uint8_t *pkt_buf = &(dev->buf[1]); + size_t len = 0; + + /* load packet data into buffer */ + for (unsigned i = 0; i < count; i++, ptr++) { + /* current packet data + FCS too long */ + if ((len + ptr->iov_len + IEEE802154_FCS_LEN) > KW2XRF_MAX_PKT_LENGTH) { + DEBUG("[kw2xrf]: error: packet too large (%u byte) to be send\n", + (unsigned)len + IEEE802154_FCS_LEN); + return -EOVERFLOW; + } + len = kw2xrf_tx_load(pkt_buf, ptr->iov_base, ptr->iov_len, len); + } + + /* make sure ongoing t or tr sequenz are finished */ + if (kw2xrf_can_switch_to_idle(dev)) { + kw2xrf_set_sequence(dev, XCVSEQ_IDLE); + dev->pending_tx++; + } + else { + /* do not wait, this can lead to a dead lock */ + return 0; + } + + /* + * Nbytes = FRAME_LEN - 2 -> FRAME_LEN = Nbytes + 2 + * MKW2xD Reference Manual, P.192 + */ + dev->buf[0] = len + IEEE802154_FCS_LEN; + + /* Help for decision to use T or TR sequenz */ + _send_last_fcf = dev->buf[1]; + + kw2xrf_write_fifo(dev, dev->buf, dev->buf[0]); +#ifdef MODULE_NETSTATS_L2 + netdev->stats.tx_bytes += len; +#endif + + /* send data out directly if pre-loading id disabled */ + if (!(dev->netdev.flags & KW2XRF_OPT_PRELOADING)) { + kw2xrf_tx_exec(dev); + } + + return (int)len; +} + +static int _recv(netdev2_t *netdev, void *buf, size_t len, void *info) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + size_t pkt_len = 0; + + /* get size of the received packet */ + pkt_len = kw2xrf_read_dreg(dev, MKW2XDM_RX_FRM_LEN); + + /* just return length when buf == NULL */ + if (buf == NULL) { + return pkt_len + 1; + } + +#ifdef MODULE_NETSTATS_L2 + netdev->stats.rx_count++; + netdev->stats.rx_bytes += pkt_len; +#endif + + if (pkt_len > len) { + /* not enough space in buf */ + return -ENOBUFS; + } + + kw2xrf_read_fifo(dev, (uint8_t *)buf, pkt_len + 1); + + if (info != NULL) { + netdev2_ieee802154_rx_info_t *radio_info = info; + radio_info->lqi = ((uint8_t*)buf)[pkt_len]; + radio_info->rssi = (uint8_t)kw2xrf_get_rssi(radio_info->lqi); + } + + /* skip FCS and LQI */ + return pkt_len - 2; +} + +static int _set_state(kw2xrf_t *dev, netopt_state_t state) +{ + switch (state) { + case NETOPT_STATE_SLEEP: + kw2xrf_set_power_mode(dev, KW2XRF_DOZE); + break; + case NETOPT_STATE_IDLE: + kw2xrf_set_power_mode(dev, KW2XRF_AUTODOZE); + kw2xrf_set_sequence(dev, dev->idle_state); + break; + case NETOPT_STATE_TX: + if (dev->netdev.flags & KW2XRF_OPT_PRELOADING) { + kw2xrf_tx_exec(dev); + } + break; + case NETOPT_STATE_RESET: + kw2xrf_reset_phy(dev); + break; + case NETOPT_STATE_OFF: + /* TODO: Replace with powerdown (set reset input low) */ + kw2xrf_set_power_mode(dev, KW2XRF_HIBERNATE); + default: + return -ENOTSUP; + } + return sizeof(netopt_state_t); +} + +static netopt_state_t _get_state(kw2xrf_t *dev) +{ + return dev->state; +} + +int _get(netdev2_t *netdev, netopt_t opt, void *value, size_t len) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + + if (dev == NULL) { + return -ENODEV; + } + + switch (opt) { + case NETOPT_MAX_PACKET_SIZE: + if (len < sizeof(int16_t)) { + return -EOVERFLOW; + } + + *((uint16_t *)value) = KW2XRF_MAX_PKT_LENGTH - _MAX_MHR_OVERHEAD; + return sizeof(uint16_t); + + case NETOPT_STATE: + if (len < sizeof(netopt_state_t)) { + return -EOVERFLOW; + } + *((netopt_state_t *)value) = _get_state(dev); + return sizeof(netopt_state_t); + + case NETOPT_PRELOADING: + if (dev->netdev.flags & KW2XRF_OPT_PRELOADING) { + *((netopt_enable_t *)value) = NETOPT_ENABLE; + } + else { + *((netopt_enable_t *)value) = NETOPT_DISABLE; + } + return sizeof(netopt_enable_t); + + case NETOPT_PROMISCUOUSMODE: + if (dev->netdev.flags & KW2XRF_OPT_PROMISCUOUS) { + *((netopt_enable_t *)value) = NETOPT_ENABLE; + } + else { + *((netopt_enable_t *)value) = NETOPT_DISABLE; + } + return sizeof(netopt_enable_t); + + case NETOPT_RX_START_IRQ: + *((netopt_enable_t *)value) = + !!(dev->netdev.flags & KW2XRF_OPT_TELL_RX_START); + return sizeof(netopt_enable_t); + + case NETOPT_RX_END_IRQ: + *((netopt_enable_t *)value) = + !!(dev->netdev.flags & KW2XRF_OPT_TELL_RX_END); + return sizeof(netopt_enable_t); + + case NETOPT_TX_START_IRQ: + *((netopt_enable_t *)value) = + !!(dev->netdev.flags & KW2XRF_OPT_TELL_TX_START); + return sizeof(netopt_enable_t); + + case NETOPT_TX_END_IRQ: + *((netopt_enable_t *)value) = + !!(dev->netdev.flags & KW2XRF_OPT_TELL_TX_END); + return sizeof(netopt_enable_t); + + case NETOPT_AUTOCCA: + *((netopt_enable_t *)value) = + !!(dev->netdev.flags & KW2XRF_OPT_AUTOCCA); + return sizeof(netopt_enable_t); + + case NETOPT_TX_POWER: + if (len < sizeof(int16_t)) { + return -EOVERFLOW; + } + *((uint16_t *)value) = kw2xrf_get_txpower(dev); + return sizeof(uint16_t); + + case NETOPT_IS_CHANNEL_CLR: + if (kw2xrf_cca(dev)) { + *((netopt_enable_t *)value) = NETOPT_ENABLE; + } + else { + *((netopt_enable_t *)value) = NETOPT_DISABLE; + } + return sizeof(netopt_enable_t); + + case NETOPT_CCA_THRESHOLD: + if (len < sizeof(uint8_t)) { + return -EOVERFLOW; + } + else { + *(int8_t *)value = kw2xrf_get_cca_threshold(dev); + } + return sizeof(int8_t); + + case NETOPT_CCA_MODE: + if (len < sizeof(uint8_t)) { + return -EOVERFLOW; + } + else { + *(uint8_t *)value = kw2xrf_get_cca_mode(dev); + switch (*((int8_t *)value)) { + case NETDEV2_IEEE802154_CCA_MODE_1: + case NETDEV2_IEEE802154_CCA_MODE_2: + case NETDEV2_IEEE802154_CCA_MODE_3: + return sizeof(uint8_t); + default: + break; + } + return -EOVERFLOW; + } + break; + + case NETOPT_CHANNEL_PAGE: + default: + break; + } + + return netdev2_ieee802154_get((netdev2_ieee802154_t *)netdev, opt, value, len); +} + +static int _set(netdev2_t *netdev, netopt_t opt, void *value, size_t len) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + int res = -ENOTSUP; + + if (dev == NULL) { + return -ENODEV; + } + + switch (opt) { + case NETOPT_ADDRESS: + if (len > sizeof(uint16_t)) { + res = -EOVERFLOW; + } + else { + kw2xrf_set_addr_short(dev, *((uint16_t *)value)); + /* don't set res to set netdev2_ieee802154_t::short_addr */ + } + break; + + case NETOPT_ADDRESS_LONG: + if (len > sizeof(uint64_t)) { + return -EOVERFLOW; + } + else { + kw2xrf_set_addr_long(dev, *((uint64_t *)value)); + /* don't set res to set netdev2_ieee802154_t::short_addr */ + } + break; + + case NETOPT_NID: + if (len > sizeof(uint16_t)) { + return -EOVERFLOW; + } + + else { + kw2xrf_set_pan(dev, *((uint16_t *)value)); + /* don't set res to set netdev2_ieee802154_t::pan */ + } + break; + + case NETOPT_CHANNEL: + if (len != sizeof(uint16_t)) { + res = -EINVAL; + } + else { + uint8_t chan = ((uint8_t *)value)[0]; + if (kw2xrf_set_channel(dev, chan)) { + res = -EINVAL; + break; + } + dev->netdev.chan = chan; + /* don't set res to set netdev2_ieee802154_t::chan */ + } + break; + + case NETOPT_CHANNEL_PAGE: + res = -EINVAL; + break; + + case NETOPT_TX_POWER: + if (len < sizeof(uint16_t)) { + res = -EOVERFLOW; + } + else { + kw2xrf_set_tx_power(dev, *(int16_t *)value); + res = sizeof(uint16_t); + } + break; + + case NETOPT_STATE: + if (len > sizeof(netopt_state_t)) { + res = -EOVERFLOW; + } + else { + res = _set_state(dev, *((netopt_state_t *)value)); + } + break; + + case NETOPT_AUTOACK: + /* Set up HW generated automatic ACK after Receive */ + kw2xrf_set_option(dev, KW2XRF_OPT_AUTOACK, + ((bool *)value)[0]); + break; + + case NETOPT_ACK_REQ: + kw2xrf_set_option(dev, KW2XRF_OPT_ACK_REQ, + ((bool *)value)[0]); + break; + + case NETOPT_PRELOADING: + kw2xrf_set_option(dev, KW2XRF_OPT_PRELOADING, + ((bool *)value)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_PROMISCUOUSMODE: + kw2xrf_set_option(dev, KW2XRF_OPT_PROMISCUOUS, + ((bool *)value)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_RX_START_IRQ: + kw2xrf_set_option(dev, KW2XRF_OPT_TELL_RX_START, + ((bool *)value)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_RX_END_IRQ: + kw2xrf_set_option(dev, KW2XRF_OPT_TELL_RX_END, + ((bool *)value)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_TX_START_IRQ: + kw2xrf_set_option(dev, KW2XRF_OPT_TELL_TX_START, + ((bool *)value)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_TX_END_IRQ: + kw2xrf_set_option(dev, KW2XRF_OPT_TELL_TX_END, + ((bool *)value)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_AUTOCCA: + kw2xrf_set_option(dev, KW2XRF_OPT_AUTOCCA, + ((bool *)value)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_CCA_THRESHOLD: + if (len < sizeof(uint8_t)) { + res = -EOVERFLOW; + } + else { + kw2xrf_set_cca_threshold(dev, *((int8_t*)value)); + res = sizeof(uint8_t); + } + break; + + case NETOPT_CCA_MODE: + if (len < sizeof(uint8_t)) { + res = -EOVERFLOW; + } + else { + switch (*((int8_t*)value)) { + case NETDEV2_IEEE802154_CCA_MODE_1: + case NETDEV2_IEEE802154_CCA_MODE_2: + case NETDEV2_IEEE802154_CCA_MODE_3: + kw2xrf_set_cca_mode(dev, *((int8_t*)value)); + res = sizeof(uint8_t); + break; + case NETDEV2_IEEE802154_CCA_MODE_4: + case NETDEV2_IEEE802154_CCA_MODE_5: + case NETDEV2_IEEE802154_CCA_MODE_6: + default: + break; + } + } + break; + + case NETOPT_RF_TESTMODE: +#ifdef KW2XRF_TESTMODE + if (len < sizeof(uint8_t)) { + res = -EOVERFLOW; + } + else { + kw2xrf_set_test_mode(dev, *((uint8_t *)value)); + res = sizeof(uint8_t); + } +#endif + break; + + default: + break; + } + + if (res == -ENOTSUP) { + res = netdev2_ieee802154_set((netdev2_ieee802154_t *)netdev, opt, + value, len); + } + + return res; +} + +static void _isr_event_seq_r(netdev2_t *netdev, uint8_t *dregs) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + uint8_t irqsts1 = 0; + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_RXWTRMRKIRQ) { + DEBUG("[kw2xrf]: got RXWTRMRKIRQ\n"); + irqsts1 |= MKW2XDM_IRQSTS1_RXWTRMRKIRQ; + netdev->event_callback(netdev, NETDEV2_EVENT_RX_STARTED); + } + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_RXIRQ) { + DEBUG("[kw2xrf]: finished RXSEQ\n"); + dev->state = NETOPT_STATE_RX; + irqsts1 |= MKW2XDM_IRQSTS1_RXIRQ; + netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE); + if (dregs[MKW2XDM_PHY_CTRL1] & MKW2XDM_PHY_CTRL1_AUTOACK) { + DEBUG("[kw2xrf]: perform TX ACK\n"); + } + } + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_TXIRQ) { + DEBUG("[kw2xrf]: finished (ACK) TXSEQ\n"); + irqsts1 |= MKW2XDM_IRQSTS1_TXIRQ; + } + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ) { + DEBUG("[kw2xrf]: SEQIRQ\n"); + irqsts1 |= MKW2XDM_IRQSTS1_SEQIRQ; + kw2xrf_set_idle_sequence(dev); + } + + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1); + dregs[MKW2XDM_IRQSTS1] &= ~irqsts1; +} + +static void _isr_event_seq_t(netdev2_t *netdev, uint8_t *dregs) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + uint8_t irqsts1 = 0; + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_TXIRQ) { + DEBUG("[kw2xrf]: finished TXSEQ\n"); + irqsts1 |= MKW2XDM_IRQSTS1_TXIRQ; + } + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ) { + DEBUG("[kw2xrf]: SEQIRQ\n"); + irqsts1 |= MKW2XDM_IRQSTS1_SEQIRQ; + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) { + irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ; + if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_CCA) { + DEBUG("[kw2xrf]: CCA CH busy\n"); + netdev->event_callback(netdev, NETDEV2_EVENT_TX_MEDIUM_BUSY); + } + else { + netdev->event_callback(netdev, NETDEV2_EVENT_TX_COMPLETE); + } + } + + assert(dev->pending_tx != 0); + dev->pending_tx--; + kw2xrf_set_idle_sequence(dev); + } + + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1); + dregs[MKW2XDM_IRQSTS1] &= ~irqsts1; +} + +/* Standalone CCA */ +static void _isr_event_seq_cca(netdev2_t *netdev, uint8_t *dregs) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + uint8_t irqsts1 = 0; + + if ((dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) && + (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ)) { + irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ | MKW2XDM_IRQSTS1_SEQIRQ; + if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_CCA) { + DEBUG("[kw2xrf]: SEQIRQ, CCA CH busy\n"); + } + else { + DEBUG("[kw2xrf]: SEQIRQ, CCA CH idle\n"); + } + kw2xrf_set_idle_sequence(dev); + } + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1); + dregs[MKW2XDM_IRQSTS1] &= ~irqsts1; +} + +static void _isr_event_seq_tr(netdev2_t *netdev, uint8_t *dregs) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + uint8_t irqsts1 = 0; + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_TXIRQ) { + DEBUG("[kw2xrf]: finished TXSEQ\n"); + irqsts1 |= MKW2XDM_IRQSTS1_TXIRQ; + if (dregs[MKW2XDM_PHY_CTRL1] & MKW2XDM_PHY_CTRL1_RXACKRQD) { + DEBUG("[kw2xrf]: wait for RX ACK\n"); + kw2xrf_seq_timeout_on(dev, _MACACKWAITDURATION); + } + } + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_RXWTRMRKIRQ) { + DEBUG("[kw2xrf]: got RXWTRMRKIRQ\n"); + irqsts1 |= MKW2XDM_IRQSTS1_RXWTRMRKIRQ; + } + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_FILTERFAIL_IRQ) { + DEBUG("[kw2xrf]: got FILTERFAILIRQ\n"); + irqsts1 |= MKW2XDM_IRQSTS1_FILTERFAIL_IRQ; + } + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_RXIRQ) { + DEBUG("[kw2xrf]: got RX ACK\n"); + irqsts1 |= MKW2XDM_IRQSTS1_RXIRQ; + } + + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ) { + if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) { + irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ; + if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_CCA) { + DEBUG("[kw2xrf]: CCA CH busy\n"); + netdev->event_callback(netdev, NETDEV2_EVENT_TX_MEDIUM_BUSY); + } + } + + DEBUG("[kw2xrf]: SEQIRQ\n"); + irqsts1 |= MKW2XDM_IRQSTS1_SEQIRQ; + assert(dev->pending_tx != 0); + dev->pending_tx--; + netdev->event_callback(netdev, NETDEV2_EVENT_TX_COMPLETE); + kw2xrf_seq_timeout_off(dev); + kw2xrf_set_idle_sequence(dev); + } + else if (dregs[MKW2XDM_IRQSTS3] & MKW2XDM_IRQSTS3_TMR4IRQ) { + DEBUG("[kw2xrf]: TC4TMOUT, no SEQIRQ, TX failed\n"); + assert(dev->pending_tx != 0); + dev->pending_tx--; + netdev->event_callback(netdev, NETDEV2_EVENT_TX_NOACK); + kw2xrf_seq_timeout_off(dev); + kw2xrf_set_sequence(dev, dev->idle_state); + } + + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1); + dregs[MKW2XDM_IRQSTS1] &= ~irqsts1; +} + +static void _isr_event_seq_ccca(netdev2_t *netdev, uint8_t *dregs) +{ + kw2xrf_t *dev = (kw2xrf_t *)netdev; + uint8_t irqsts1 = 0; + + if ((dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) && + (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ)) { + irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ | MKW2XDM_IRQSTS1_SEQIRQ; + DEBUG("[kw2xrf]: CCCA CH idle\n"); + kw2xrf_seq_timeout_off(dev); + kw2xrf_set_sequence(dev, dev->idle_state); + } + else if (dregs[MKW2XDM_IRQSTS3] & MKW2XDM_IRQSTS3_TMR4IRQ) { + irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ | MKW2XDM_IRQSTS1_SEQIRQ; + DEBUG("[kw2xrf]: CCCA timeout\n"); + kw2xrf_seq_timeout_off(dev); + kw2xrf_set_sequence(dev, dev->idle_state); + } + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1); + dregs[MKW2XDM_IRQSTS1] &= ~irqsts1; +} + +static void _isr(netdev2_t *netdev) +{ + uint8_t dregs[MKW2XDM_PHY_CTRL4 + 1]; + kw2xrf_t *dev = (kw2xrf_t *)netdev; + + kw2xrf_read_dregs(dev, MKW2XDM_IRQSTS1, dregs, MKW2XDM_PHY_CTRL4 + 1); + kw2xrf_mask_irq_b(dev); + + DEBUG("[kw2xrf]: CTRL1 %0x, IRQSTS1 %0x, IRQSTS2 %0x\n", + dregs[MKW2XDM_PHY_CTRL1], dregs[MKW2XDM_IRQSTS1], dregs[MKW2XDM_IRQSTS2]); + + switch (dregs[MKW2XDM_PHY_CTRL1] & MKW2XDM_PHY_CTRL1_XCVSEQ_MASK) { + case XCVSEQ_RECEIVE: + _isr_event_seq_r(netdev, dregs); + break; + + case XCVSEQ_TRANSMIT: + _isr_event_seq_t(netdev, dregs); + break; + + case XCVSEQ_CCA: + _isr_event_seq_cca(netdev, dregs); + break; + + case XCVSEQ_TX_RX: + _isr_event_seq_tr(netdev, dregs); + break; + + case XCVSEQ_CONTINUOUS_CCA: + _isr_event_seq_ccca(netdev, dregs); + break; + + case XCVSEQ_IDLE: + default: + DEBUG("[kw2xrf]: undefined seq state in isr\n"); + break; + } + + uint8_t irqsts2 = 0; + if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_PB_ERR_IRQ) { + DEBUG("[kw2xrf]: untreated PB_ERR_IRQ\n"); + irqsts2 |= MKW2XDM_IRQSTS2_PB_ERR_IRQ; + } + if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_WAKE_IRQ) { + DEBUG("[kw2xrf]: untreated WAKE_IRQ\n"); + irqsts2 |= MKW2XDM_IRQSTS2_WAKE_IRQ; + } + kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS2, irqsts2); + + if (ENABLE_DEBUG) { + /* for debugging only */ + kw2xrf_read_dregs(dev, MKW2XDM_IRQSTS1, dregs, MKW2XDM_IRQSTS1 + 3); + if (dregs[MKW2XDM_IRQSTS1] & 0x7f) { + DEBUG("[kw2xrf]: IRQSTS1 contains untreated IRQs: 0x%02x\n", + dregs[MKW2XDM_IRQSTS1]); + } + if (dregs[MKW2XDM_IRQSTS2] & 0x02) { + DEBUG("[kw2xrf]: IRQSTS2 contains untreated IRQs: 0x%02x\n", + dregs[MKW2XDM_IRQSTS2]); + } + if (dregs[MKW2XDM_IRQSTS3] & 0x0f) { + DEBUG("[kw2xrf]: IRQSTS3 contains untreated IRQs: 0x%02x\n", + dregs[MKW2XDM_IRQSTS3]); + } + } + + kw2xrf_enable_irq_b(dev); +} + +const netdev2_driver_t kw2xrf_driver = { + .init = _init, + .send = _send, + .recv = _recv, + .get = _get, + .set = _set, + .isr = _isr, +}; + +/** @} */ diff --git a/drivers/kw2xrf/kw2xrf_spi.c b/drivers/kw2xrf/kw2xrf_spi.c index f129925dcc..ba59ca5139 100644 --- a/drivers/kw2xrf/kw2xrf_spi.c +++ b/drivers/kw2xrf/kw2xrf_spi.c @@ -32,31 +32,39 @@ static uint8_t ibuf[KW2XRF_IBUF_LENGTH]; -/** Set up in kw2xrf_spi_init during initialization */ -static spi_t kw2xrf_spi; -static spi_clk_t kw2xrf_clk; -static spi_cs_t kw2xrf_cs_pin; - -static inline void kw2xrf_spi_transfer_head(void) +void kw2xrf_spi_transfer_head(kw2xrf_t *dev) { - spi_acquire(kw2xrf_spi, kw2xrf_cs_pin, SPI_MODE, kw2xrf_clk); +#if KW2XRF_SHARED_SPI + spi_acquire(dev->params.spi); + gpio_clear(dev->params.cs_pin); +#endif } -static inline void kw2xrf_spi_transfer_tail(void) +void kw2xrf_spi_transfer_tail(kw2xrf_t *dev) { - spi_release(kw2xrf_spi); +#if KW2XRF_SHARED_SPI + gpio_set(dev->params.cs_pin); + spi_release(dev->params.spi); +#endif } -int kw2xrf_spi_init(spi_t spi, spi_clk_t spi_clk, spi_cs_t cs_pin) +int kw2xrf_spi_init(kw2xrf_t *dev) { int res; - kw2xrf_spi = spi; - kw2xrf_clk = spi_clk; - kw2xrf_cs_pin = cs_pin; /**< for later reference */ - res = spi_init_cs(kw2xrf_spi, kw2xrf_cs_pin); - if (res != SPI_OK) { - DEBUG("kw2xrf_spi_init: error initializing SPI_DEV(%i) (code %i)\n", +#if KW2XRF_SHARED_SPI + spi_acquire(dev->params.spi); +#endif + res = spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, dev->params.spi_speed); +#if KW2XRF_SHARED_SPI + spi_release(dev->params.spi); + + gpio_init(dev->params.cs_pin, GPIO_OUT); + gpio_set(dev->params.cs_pin); +#endif + + if (res < 0) { + DEBUG("[kw2xrf]: error initializing SPI_%i device (code %i)\n", kw2xrf_spi, res); return -1; } @@ -64,25 +72,43 @@ int kw2xrf_spi_init(spi_t spi, spi_clk_t spi_clk, spi_cs_t cs_pin) return 0; } -void kw2xrf_write_dreg(uint8_t addr, uint8_t value) +void kw2xrf_write_dreg(kw2xrf_t *dev, uint8_t addr, uint8_t value) { - kw2xrf_spi_transfer_head(); - spi_transfer_reg(kw2xrf_spi, kw2xrf_cs_pin, addr, value); - kw2xrf_spi_transfer_tail(); + kw2xrf_spi_transfer_head(dev); + spi_transfer_reg(dev->params.spi, dev->params.cs_pin, addr, value); + kw2xrf_spi_transfer_tail(dev); return; } -uint8_t kw2xrf_read_dreg(uint8_t addr) +uint8_t kw2xrf_read_dreg(kw2xrf_t *dev, uint8_t addr) { uint8_t value; - kw2xrf_spi_transfer_head(); - value = spi_transfer_reg(kw2xrf_spi, kw2xrf_cs_pin, + kw2xrf_spi_transfer_head(dev); + value = spi_transfer_reg(dev->params.spi, dev->params.cs_pin, (addr | MKW2XDRF_REG_READ), 0x0); - kw2xrf_spi_transfer_tail(); + kw2xrf_spi_transfer_tail(dev); return value; } -void kw2xrf_write_iregs(uint8_t addr, uint8_t *buf, uint8_t length) +size_t kw2xrf_write_dregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length) +{ + kw2xrf_spi_transfer_head(dev); + size_t i = spi_transfer_regs(dev->params.spi, addr, (char *)buf, NULL, length); + kw2xrf_spi_transfer_tail(dev); + return i; +} + +size_t kw2xrf_read_dregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length) +{ + kw2xrf_spi_transfer_head(dev); + size_t i = spi_transfer_regs(dev->params.spi, (addr | MKW2XDRF_REG_READ), + NULL, (char *)buf, length); + kw2xrf_spi_transfer_tail(dev); + return i; +} + + +void kw2xrf_write_iregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length) { if (length > (KW2XRF_IBUF_LENGTH - 1)) { length = KW2XRF_IBUF_LENGTH - 1; @@ -94,15 +120,15 @@ void kw2xrf_write_iregs(uint8_t addr, uint8_t *buf, uint8_t length) ibuf[i + 1] = buf[i]; } - kw2xrf_spi_transfer_head(); - spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDM_IAR_INDEX, + kw2xrf_spi_transfer_head(dev); + spi_transfer_regs(dev->params.spi, dev->params.cs_pin, MKW2XDM_IAR_INDEX, ibuf, NULL, length + 1); - kw2xrf_spi_transfer_tail(); + kw2xrf_spi_transfer_tail(dev); return; } -void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length) +void kw2xrf_read_iregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length) { if (length > (KW2XRF_IBUF_LENGTH - 1)) { length = KW2XRF_IBUF_LENGTH - 1; @@ -110,11 +136,11 @@ void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length) ibuf[0] = addr; - kw2xrf_spi_transfer_head(); - spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, - MKW2XDM_IAR_INDEX | MKW2XDRF_REG_READ, + kw2xrf_spi_transfer_head(dev); + spi_transfer_regs(dev->params.spi, dev->params.cs_pin, + (MKW2XDM_IAR_INDEX | MKW2XDRF_REG_READ), ibuf, ibuf, length + 1); - kw2xrf_spi_transfer_tail(); + kw2xrf_spi_transfer_tail(dev); for (uint8_t i = 0; i < length; i++) { buf[i] = ibuf[i + 1]; @@ -123,18 +149,18 @@ void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length) return; } -void kw2xrf_write_fifo(uint8_t *data, uint8_t length) +void kw2xrf_write_fifo(kw2xrf_t *dev, uint8_t *data, uint8_t length) { - kw2xrf_spi_transfer_head(); - spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDRF_BUF_WRITE, - data, NULL, length); - kw2xrf_spi_transfer_tail(); + kw2xrf_spi_transfer_head(dev); + spi_transfer_regs(dev->params.spi, dev->params.cs_pin, + MKW2XDRF_BUF_WRITE, data, NULL, length); + kw2xrf_spi_transfer_tail(dev); } -void kw2xrf_read_fifo(uint8_t *data, uint8_t length) +void kw2xrf_read_fifo(kw2xrf_t *dev, uint8_t *data, uint8_t length) { - kw2xrf_spi_transfer_head(); - spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDRF_BUF_READ, - NULL, data, length); - kw2xrf_spi_transfer_tail(); + kw2xrf_spi_transfer_head(dev); + spi_transfer_regs(dev->params.spi, dev->params.cs_pin, + MKW2XDRF_BUF_READ, NULL, data, length); + kw2xrf_spi_transfer_tail(dev); } diff --git a/drivers/kw2xrf/kw2xrf_tm.c b/drivers/kw2xrf/kw2xrf_tm.c new file mode 100644 index 0000000000..576459597d --- /dev/null +++ b/drivers/kw2xrf/kw2xrf_tm.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2016 Phytec Messtechnik GmbH + * + * 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_kw2xrf + * @{ + * + * @file + * @brief Testing function of kw2xrf driver + * + * @author Johann Fischer <j.fischer@phytec.de> + */ + +#include "kw2xrf.h" +#include "kw2xrf_spi.h" +#include "kw2xrf_reg.h" +#include "kw2xrf_tm.h" + +#ifdef KW2XRF_TESTMODE + +inline static void enable_xcvr_test_mode(kw2xrf_t *dev) +{ + uint8_t reg; + + kw2xrf_read_iregs(dev, MKW2XDMI_DTM_CTRL1, ®, 1); + reg |= MKW2XDMI_DTM_CTRL1_DTM_EN; + kw2xrf_write_iregs(dev, MKW2XDMI_DTM_CTRL1, ®, 1); + + kw2xrf_read_iregs(dev, MKW2XDMI_TESTMODE_CTRL, ®, 1); + reg |= MKW2XDMI_TESTMODE_CTRL_CONTINUOUS_EN | MKW2XDMI_TESTMODE_CTRL_IDEAL_PFC_EN; + kw2xrf_write_iregs(dev, MKW2XDMI_TESTMODE_CTRL, ®, 1); +} + +inline static void disable_xcvr_test_mode(kw2xrf_t *dev) +{ + uint8_t reg; + + kw2xrf_read_iregs(dev, MKW2XDMI_DTM_CTRL1, ®, 1); + reg &= MKW2XDMI_DTM_CTRL1_DTM_EN; + kw2xrf_write_iregs(dev, MKW2XDMI_DTM_CTRL1, ®, 1); + + kw2xrf_read_iregs(dev, MKW2XDMI_TESTMODE_CTRL, ®, 1); + reg &= ~(MKW2XDMI_TESTMODE_CTRL_CONTINUOUS_EN | MKW2XDMI_TESTMODE_CTRL_IDEAL_PFC_EN); + kw2xrf_write_iregs(dev, MKW2XDMI_TESTMODE_CTRL, ®, 1); +} + +int kw2xrf_set_test_mode(kw2xrf_t *dev, uint8_t mode) +{ + uint8_t reg = 0; + uint8_t buf[2]; + + kw2xrf_abort_sequence(dev); + disable_xcvr_test_mode(dev); + kw2xrf_set_channel(dev, dev->netdev.chan); + + switch(mode) { + case NETOPT_RF_TESTMODE_IDLE: + reg = 0; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + + kw2xrf_set_sequence(dev, XCVSEQ_IDLE); + break; + + case NETOPT_RF_TESTMODE_CRX: + /* set continuous RX mode */ + reg = 0; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + /* set data length */ + reg = 127; + kw2xrf_write_iregs(dev, MKW2XDMI_DUAL_PAN_DWELL, ®, 1); + + kw2xrf_set_sequence(dev, XCVSEQ_RECEIVE); + break; + + case KW2XRF_TM_CTX_PREAMBLE: + /* set continuous TX mode, transmit 10101010 pattern */ + reg = 0; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + buf[0] = 1; + buf[1] = 0xaa; + kw2xrf_write_fifo(dev, buf, buf[0] + 1); + + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + break; + + case NETOPT_RF_TESTMODE_CTX_CW: + /* set continuous TX mode, transmit unmodulated carrier */ + reg = MKW2XDMI_TX_MODE_CTRL_DTS0; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + /* fix pll frequency for cw mode */ + uint16_t pll_frac = kw2xrf_read_dreg(dev, MKW2XDM_PLL_FRAC0_LSB); + pll_frac |= ((uint16_t)kw2xrf_read_dreg(dev, MKW2XDM_PLL_FRAC0_MSB) << 8); + pll_frac -= 0x400; + + kw2xrf_write_dreg(dev, MKW2XDM_PLL_FRAC0_LSB, (uint8_t)pll_frac); + kw2xrf_write_dreg(dev, MKW2XDM_PLL_FRAC0_MSB, (uint8_t)(pll_frac >> 8)); + + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + break; + + case KW2XRF_TM_CTX_NM1: + /* set continuous TX mode */ + reg = MKW2XDMI_TX_MODE_CTRL_DTS0; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + break; + + case KW2XRF_TM_CTX_NM0: + /* set continuous TX mode */ + reg = MKW2XDMI_TX_MODE_CTRL_DTS1; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + break; + + case KW2XRF_TM_CTX_2MHZ: + /* set continuous TX mode */ + reg = MKW2XDMI_TX_MODE_CTRL_DTS1 | MKW2XDMI_TX_MODE_CTRL_DTS0; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + break; + + case KW2XRF_TM_CTX_200KHZ: + /* set continuous TX mode */ + reg = MKW2XDMI_TX_MODE_CTRL_DTS2; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + break; + + case KW2XRF_TM_CTX_1MBPS_PRBS9: + /* set continuous TX mode, transmit PRBS9 pattern */ + reg = MKW2XDMI_TX_MODE_CTRL_DTS2 | MKW2XDMI_TX_MODE_CTRL_DTS0; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + break; + + case KW2XRF_TM_CTX_EXT: + /* set continuous TX mode */ + reg = MKW2XDMI_TX_MODE_CTRL_DTS2 | MKW2XDMI_TX_MODE_CTRL_DTS1; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + break; + + case NETOPT_RF_TESTMODE_CTX_PRBS9: + /* set continuous TX mode, transmit PRBS9 pattern */ + reg = MKW2XDMI_TX_MODE_CTRL_DTS2 | MKW2XDMI_TX_MODE_CTRL_DTS1 + | MKW2XDMI_TX_MODE_CTRL_DTS0; + kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, ®, 1); + enable_xcvr_test_mode(dev); + + kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT); + break; + + } + return 1; +} + +#endif +/** @} */ diff --git a/sys/auto_init/netif/auto_init_kw2xrf.c b/sys/auto_init/netif/auto_init_kw2xrf.c index 25410443f1..2ac62261be 100644 --- a/sys/auto_init/netif/auto_init_kw2xrf.c +++ b/sys/auto_init/netif/auto_init_kw2xrf.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de> - * Copyright (C) 2015 PHYTEC Messtechnik GmbH + * Copyright (C) 2016 PHYTEC Messtechnik GmbH * * 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 @@ -24,7 +24,7 @@ #include "log.h" #include "board.h" #include "net/gnrc/netdev2.h" -#include "net/gnrc/nomac.h" +#include "net/gnrc/netdev2/ieee802154.h" #include "net/gnrc.h" #include "kw2xrf.h" @@ -42,7 +42,8 @@ #define KW2XRF_NUM (sizeof(kw2xrf_params)/sizeof(kw2xrf_params[0])) static kw2xrf_t kw2xrf_devs[KW2XRF_NUM]; -static char _nomac_stacks[KW2XRF_NUM][KW2XRF_MAC_STACKSIZE]; +static gnrc_netdev2_t gnrc_adpt[KW2XRF_NUM]; +static char _nomac_stacks[KW2XRF_MAC_STACKSIZE][KW2XRF_NUM]; void auto_init_kw2xrf(void) { @@ -51,19 +52,18 @@ void auto_init_kw2xrf(void) LOG_DEBUG("[auto_init_netif] initializing kw2xrf #%u\n", i); - int res = kw2xrf_init(&kw2xrf_devs[i], - p->spi, - p->spi_speed, - p->cs_pin, - p->int_pin); - + kw2xrf_setup(&kw2xrf_devs[i], (kw2xrf_params_t*) p); + int res = gnrc_netdev2_ieee802154_init(&gnrc_adpt[i], + (netdev2_ieee802154_t *)&kw2xrf_devs[i]); if (res < 0) { LOG_ERROR("[auto_init_netif] initializing kw2xrf #%u\n", i); } else { - gnrc_nomac_init(_nomac_stacks[i], - KW2XRF_MAC_STACKSIZE, KW2XRF_MAC_PRIO, - "kw2xrf", (gnrc_netdev_t *)&kw2xrf_devs[i]); + gnrc_netdev2_init(_nomac_stacks[i], + KW2XRF_MAC_STACKSIZE, + KW2XRF_MAC_PRIO, + "kw2xrf", + &gnrc_adpt[i]); } } } -- GitLab