diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index e511c53a5b31..2a70c0e17171 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -19,6 +19,19 @@ ifneq (,$(filter at86rf2%,$(USEMODULE))) endif endif +ifneq (,$(filter mrf24j40,$(USEMODULE))) + USEMODULE += xtimer + USEMODULE += uuid + USEMODULE += netif + USEMODULE += ieee802154 + USEMODULE += netdev2_ieee802154 + ifneq (,$(filter gnrc_netdev_default,$(USEMODULE))) + # 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 + ifneq (,$(filter bh1750fvi,$(USEMODULE))) USEMODULE += xtimer FEATURES_REQUIRED += periph_i2c diff --git a/drivers/Makefile.include b/drivers/Makefile.include index d1ba0fb1eb46..f0e9712f620c 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -4,6 +4,9 @@ endif ifneq (,$(filter at86rf2xx,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at86rf2xx/include endif +ifneq (,$(filter mrf24j40,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mrf24j40/include +endif ifneq (,$(filter cc110x,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cc110x/include endif diff --git a/drivers/include/mrf24j40.h b/drivers/include/mrf24j40.h new file mode 100644 index 000000000000..6a3281a301cd --- /dev/null +++ b/drivers/include/mrf24j40.h @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * Copyright (C) 2017 Koen Zandberg + * + * 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. + */ + +/** + * @defgroup drivers_mrf24j40 MRF24J40 based drivers + * @ingroup drivers_netdev_netdev2 + * + * This module contains drivers for radio devices in Microchip MRF24J40 series. + * The driver is aimed to work with all devices of this series. + * + * @{ + * + * @file + * @brief Interface definition for MRF24J40 based drivers + * + * @author Neo Nenaco + * @author Koen Zandberg + */ + +#ifndef MRF24J40_H +#define MRF24J40_H + +#include + +#include "board.h" +#include "periph/spi.h" +#include "periph/gpio.h" +#include "net/netdev2.h" +#include "net/netdev2/ieee802154.h" +#include "net/gnrc/nettype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Default TX power (0dBm) + * 0 -> -36dB + * 1 -> -35dB + * 2 -> -34dB + * 3 -> -33dB + * 4 -> -32dB + * 5 -> -31dB + * 6 -> -30dB + * 7 -> -30dB + * 8 -> -26dB + * 9 -> -25dB + * 10 -> -24dB + * 11 -> -23dB + * 12 -> -22dB + * 13 -> -21dB + * 14 -> -20dB + * 15 -> -20dB + * 16 -> -16dB + * 17 -> -15dB + * 18 -> -14dB + * 19 -> -13dB + * 20 -> -12dB + * 21 -> -11dB + * 22 -> -10dB + * 23 -> -10dB + * 24 -> -6dB + * 25 -> -5dB + * 26 -> -4dB + * 27 -> -3dB + * 28 -> -2dB + * 29 -> -1dB + * 30 -> -0dB + * 31 -> -0dB + */ + +/** + * @brief Base (minimal) RSSI value in dBm + */ +#define RSSI_BASE_VAL (-91) + +/** + * @brief Flags for PSEUDO DEVICE INTERNAL STATES + * @{ + */ +#define MRF24J40_PSEUDO_STATE_IDLE (0x01) /**< Idle, ready to transmit or receive */ +#define MRF24J40_PSEUDO_STATE_SLEEP (0x02) /**< sleep mode, registers functional, but no RF */ +#define MRF24J40_PSEUDO_STATE_RESET (0x04) /**< Reset device, next state is idle */ +/** @} */ + +/** + * @brief Internal device option flags + * + * `0x00ff` is reserved for general IEEE 802.15.4 flags + * (see @ref netdev2_ieee802154_t) + * + * @{ + */ +#define MRF24J40_OPT_CSMA (0x0100) /**< CSMA active */ +#define MRF24J40_OPT_PROMISCUOUS (0x0200) /**< promiscuous mode + * active */ +#define MRF24J40_OPT_PRELOADING (0x0400) /**< preloading enabled */ +#define MRF24J40_OPT_TELL_TX_START (0x0800) /**< notify MAC layer on TX + * start */ +#define MRF24J40_OPT_TELL_TX_END (0x1000) /**< notify MAC layer on TX + * finished */ +#define MRF24J40_OPT_TELL_RX_START (0x2000) /**< notify MAC layer on RX + * start */ +#define MRF24J40_OPT_TELL_RX_END (0x4000) /**< notify MAC layer on RX + * finished */ +#define MRF24J40_OPT_REQ_AUTO_ACK (0x8000) /**< notify MAC layer on RX + * finished */ +/** @} */ + + +#define MRF24J40_TASK_TX_DONE (0x01) /**< TX operation is done */ +#define MRF24J40_TASK_TX_READY (0x02) /**< TX operation results ready for processing */ +#define MRF24J40_TASK_RX_READY (0x04) /**< RX processing needed */ + +#define MRF24J40_MAX_FRAME_RETRIES (3U) /**< Number of frame retries (fixed) */ + +/** + * @brief struct holding all params needed for device initialization + */ +typedef struct mrf24j40_params { + spi_t spi; /**< SPI bus the device is connected to */ + spi_clk_t spi_clk; /**< SPI speed to use */ + spi_cs_t cs_pin; /**< GPIO pin connected to chip select */ + gpio_t int_pin; /**< GPIO pin connected to the interrupt pin */ + gpio_t reset_pin; /**< GPIO pin connected to the reset pin */ +} mrf24j40_params_t; + +/** + * @brief Device descriptor for MRF24J40 radio devices + */ +typedef struct { + netdev2_ieee802154_t netdev; /**< netdev2 parent struct */ + /** + * @brief device specific fields + * @{ + */ + mrf24j40_params_t params; /**< parameters for initialization */ + uint8_t state; /**< current state of the radio */ + uint8_t idle_state; /**< state to return to after sending */ + uint8_t tx_frame_len; /**< length of the current TX frame */ + uint8_t header_len; + uint8_t pending; /**< Flags for pending tasks */ + uint8_t irq_flag; +} mrf24j40_t; + +/** + * @brief Setup an MRF24J40 based device state + * + * @param[out] dev device descriptor + * @param[in] params parameters for device initialization + */ +void mrf24j40_setup(mrf24j40_t *dev, const mrf24j40_params_t *params); + +/** + * @brief Trigger a hardware reset and configure radio with default values + * + * @param[in] dev device to reset + */ +void mrf24j40_reset(mrf24j40_t *dev); + +/** + * @brief Trigger a clear channel assessment + * + * @param[in] dev device to use + * + * @return true if channel is clear + * @return false if channel is busy + */ +bool mrf24j40_cca(mrf24j40_t *dev); + +/** + * @brief Get the short address of the given device + * + * @param[in] dev device to read from + * + * @return the currently set (2-byte) short address + */ +uint16_t mrf24j40_get_addr_short(mrf24j40_t *dev); + +/** + * @brief Set the short address of the given device + * + * @param[in] dev device to write to + * @param[in] addr (2-byte) short address to set + */ +void mrf24j40_set_addr_short(mrf24j40_t *dev, uint16_t addr); + +/** + * @brief Get the configured long address of the given device + * + * @param[in] dev device to read from + * + * @return the currently set (8-byte) long address + */ +uint64_t mrf24j40_get_addr_long(mrf24j40_t *dev); + +/** + * @brief Set the long address of the given device + * + * @param[in] dev device to write to + * @param[in] addr (8-byte) long address to set + */ +void mrf24j40_set_addr_long(mrf24j40_t *dev, uint64_t addr); + +/** + * @brief Get the configured channel number of the given device + * + * @param[in] dev device to read from + * + * @return the currently set channel number + */ +uint8_t mrf24j40_get_chan(mrf24j40_t *dev); + +/** + * @brief Set the channel number of the given device + * + * @param[in] dev device to write to + * @param[in] chan channel number to set + */ +void mrf24j40_set_chan(mrf24j40_t *dev, uint8_t chan); + +/** + * @brief Get the configured PAN ID of the given device + * + * @param[in] dev device to read from + * + * @return the currently set PAN ID + */ +uint16_t mrf24j40_get_pan(mrf24j40_t *dev); + +/** + * @brief Set the PAN ID of the given device + * + * @param[in] dev device to write to + * @param[in] pan PAN ID to set + */ +void mrf24j40_set_pan(mrf24j40_t *dev, uint16_t pan); + +/** + * @brief Get the configured transmission power of the given device [in dBm] + * + * @param[in] dev device to read from + * + * @return configured transmission power in dBm + */ +int16_t mrf24j40_get_txpower(mrf24j40_t *dev); + +/** + * @brief Set the transmission power of the given device [in dBm] + * + * If the device does not support the exact dBm value given, it will set a value + * as close as possible to the given value. If the given value is larger or + * lower then the maximal or minimal possible value, the min or max value is + * set, respectively. + * + * @param[in] dev device to write to + * @param[in] txpower transmission power in dBm + */ +void mrf24j40_set_txpower(mrf24j40_t *dev, int16_t txpower); + +/** + * @brief Get the maximum number of channel access attempts per frame (CSMA) + * + * @param[in] dev device to read from + * + * @return configured number of retries + */ +uint8_t mrf24j40_get_csma_max_retries(mrf24j40_t *dev); + +/** + * @brief Set the maximum number of channel access attempts per frame (CSMA) + * + * This setting specifies the number of attempts to access the channel to + * transmit a frame. If the channel is busy @p retries times, then frame + * transmission fails. + * Valid values: 0 to 5, -1 means CSMA disabled + * + * @param[in] dev device to write to + * @param[in] retries the maximum number of retries + */ +void mrf24j40_set_csma_max_retries(mrf24j40_t *dev, int8_t retries); + +/** + * @brief Set the min and max backoff exponent for CSMA/CA + * + * - Maximum BE: 0 - 8 + * - Minimum BE: 0 - [max] + * + * @param[in] dev device to write to + * @param[in] min the minimum BE + * @param[in] max the maximum BE + */ +void mrf24j40_set_csma_backoff_exp(mrf24j40_t *dev, uint8_t min, uint8_t max); + +/** + * @brief Get the CCA threshold value + * + * @param[in] dev device to read value from + * + * @return the current CCA threshold value + */ +int8_t mrf24j40_get_cca_threshold(mrf24j40_t *dev); + +/** + * @brief Set the CCA threshold value + * + * @param[in] dev device to write to + * @param[in] value the new CCA threshold value + */ +void mrf24j40_set_cca_threshold(mrf24j40_t *dev, int8_t value); + +/** + * @brief Enable or disable driver specific options + * + * @param[in] dev device to set/clear option flag for + * @param[in] option option to enable/disable + * @param[in] state true for enable, false for disable + */ +void mrf24j40_set_option(mrf24j40_t *dev, uint16_t option, bool state); + +/** + * @brief Set the state of the given device (trigger a state change) + * + * @param[in] dev device to change state of + * @param[in] state the targeted new state + */ +void mrf24j40_set_state(mrf24j40_t *dev, uint8_t state); + +/** + * @brief Put in sleep mode + * + * @param[in] dev device to put to sleep + */ +void mrf24j40_sleep(mrf24j40_t *dev); + +/** + * @brief Put in sleep mode if idle_state is sleep + * + * @param[in] dev device to put to sleep + */ +void mrf24j40_assert_sleep(mrf24j40_t *dev); + +/** + * @brief Wake up from sleep mode + * + * @param[in] dev device to eventually wake up + */ +void mrf24j40_assert_awake(mrf24j40_t *dev); + +/** + * @brief Reset the internal state machine to TRX_OFF mode. + * + * This will force a transition to TRX_OFF regardless of whether the transceiver + * is currently busy sending or receiving. This function is used to get back to + * a known state during driver initialization. + * + * @param[in] dev device to operate on + */ +void mrf24j40_reset_state_machine(mrf24j40_t *dev); + +/** + * @brief Software Reset. + * + * This will force the power management circuitry, the baseband circuitry and the MAC circuitry + * to be reset + * + * @param[in] dev device to operate on + */ +void mrf24j40_software_reset(mrf24j40_t *dev); + +/** + * @brief Prepare for sending of data + * + * This function puts the given device into the TX state, so no receiving of + * data is possible after it was called. + * + * @param[in] dev device to prepare for sending + */ +void mrf24j40_tx_prepare(mrf24j40_t *dev); + +/** + * @brief Load chunks of data into the transmit buffer of the given device + * + * @param[in] dev device to write data to + * @param[in] data buffer containing the data to load + * @param[in] len number of bytes in @p buffer + * @param[in] offset offset used when writing data to internal buffer + * + * @return offset + number of bytes written + */ +size_t mrf24j40_tx_load(mrf24j40_t *dev, uint8_t *data, size_t len, + size_t offset); + +/** + * @brief Trigger sending of data previously loaded into transmit buffer + * + * @param[in] dev device to trigger + */ +void mrf24j40_tx_exec(mrf24j40_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* MRF24J40_H */ +/** @} */ diff --git a/drivers/mrf24j40/Makefile b/drivers/mrf24j40/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/drivers/mrf24j40/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/mrf24j40/include/mrf24j40_internal.h b/drivers/mrf24j40/include/mrf24j40_internal.h new file mode 100644 index 000000000000..3254e0b8c7b5 --- /dev/null +++ b/drivers/mrf24j40/include/mrf24j40_internal.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * Copyright (C) 2017 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_mrf24j40 + * @{ + * + * @file + * @brief Internal interfaces for MRF24J40 drivers + * + * @author Neo Nenaco + * @author Koen Zandberg + */ + +#ifndef MRF24J40_INTERNAL_H +#define MRF24J40_INTERNAL_H + +#include + +#include "mrf24j40.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @brief initialization as decribed in datasheet + */ +void mrf24j40_init(mrf24j40_t *dev); + +/** + * @brief Read from a register with a at address `addr` from device `dev`. Register with 8bit address + * + * @param[in] dev device to read from + * @param[in] addr address of the register to read + * + * @return the value of the specified register + */ +uint8_t mrf24j40_reg_read_short(mrf24j40_t *dev, const uint8_t addr); + +/** + * @brief Write to a register at address `addr` from device `dev`. Register with 8bit address + * + * @param[in] dev device to write to + * @param[in] addr address of the register to write + * @param[in] value value to write to the given register + */ +void mrf24j40_reg_write_short(mrf24j40_t *dev, const uint8_t addr, const uint8_t value); + +/** + * @brief Read from a register with a at address `addr` from device `dev`. Register with 10bit address + * + * @param[in] dev device to read from + * @param[in] addr address of the register to read + * + * @return the value of the specified register + */ +uint8_t mrf24j40_reg_read_long(mrf24j40_t *dev, const uint16_t addr); + +/** + * @brief Write to a register at address `addr` from device `dev`. Register with 10bit address + * + * @param[in] dev device to write to + * @param[in] addr address of the register to write + * @param[in] value value to write to the given register + */ +void mrf24j40_reg_write_long(mrf24j40_t *dev, const uint16_t addr, const uint8_t value); + +/** + * @brief Read a chunk of data from the TX Normal FIFO area of the given device + * + * @param[in] dev device to read from + * @param[in] offset starting address to read from [valid 0x00-0x1ff] + * @param[out] data buffer to read data into + * @param[in] len number of bytes to read from FIFO + */ +void mrf24j40_tx_normal_fifo_read(mrf24j40_t *dev, const uint16_t offset, uint8_t *data, const size_t len); + +/** + * @brief Write a chunk of data into the TX Normal FIFO area of the given device + * + * @param[in] dev device to write to + * @param[in] offset address in the TX Normal FIFO to write to [valid 0x00-0x1ff] + * @param[in] data data to copy into FIFO + * @param[in] len number of bytes to write to FIFO + */ +void mrf24j40_tx_normal_fifo_write(mrf24j40_t *dev, const uint16_t offset, const uint8_t *data, const size_t len); + +/** + * @brief Read a chunk of data from the RX_FIFO area of the given device + * + * @param[in] dev device to read from + * @param[in] offset starting address to read from [valid 0x00-0x1ff] + * @param[out] data buffer to read data into + * @param[in] len number of bytes to read from FIFO + */ +void mrf24j40_rx_fifo_read(mrf24j40_t *dev, const uint16_t offset, uint8_t *data, const size_t len); + +/** + * @brief Write a chunk of data into the RX_FIFO area of the given device + * + * @param[in] dev device to write to + * @param[in] offset address in the RX FIFO to write to [valid 0x00-0x1ff] + * @param[in] data data to copy into FIFO + * @param[in] len number of bytes to write to FIFO + */ +void mrf24j40_rx_fifo_write(mrf24j40_t *dev, const uint16_t offset, const uint8_t *data, const size_t len); + +/** + * @brief Reset the pending task list of a device + * + * @param[in] dev device to reset tasks of + */ +void mrf24j40_reset_tasks(mrf24j40_t *dev); + +/** + * @brief Check for pending interrupts and update task list + * + * @param[in] dev device to read + */ +void mrf24j40_update_tasks(mrf24j40_t *dev); + +/** + * @brief Trigger a hardware reset + * + * @param[in] dev device to reset + */ +void mrf24j40_hardware_reset(mrf24j40_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* MRF24J40_INTERNAL_H */ +/** @} */ diff --git a/drivers/mrf24j40/include/mrf24j40_netdev.h b/drivers/mrf24j40/include/mrf24j40_netdev.h new file mode 100644 index 000000000000..eb95d20cd274 --- /dev/null +++ b/drivers/mrf24j40/include/mrf24j40_netdev.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * Copyright (C) 2017 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_mrf24j40 + * @{ + * + * @file + * @brief Netdev interface to MRF24J40 drivers + * + * @author Neo Nenaco + * @author Koen Zandberg + */ + +#ifndef MRF24J40_NETDEV_H +#define MRF24J40_NETDEV_H + +#include "net/netdev2.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Reference to the netdev device driver struct + */ +extern const netdev2_driver_t mrf24j40_driver; + + +#ifdef __cplusplus +} +#endif + +#endif /* MRF24J40_NETDEV_H */ +/** @} */ diff --git a/drivers/mrf24j40/include/mrf24j40_params.h b/drivers/mrf24j40/include/mrf24j40_params.h new file mode 100644 index 000000000000..01a715d9f5e4 --- /dev/null +++ b/drivers/mrf24j40/include/mrf24j40_params.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * Copyright (C) 2017 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_mrf24j40 + * + * @{ + * @file + * @brief Default configuration for the MRF24J40 driver + * + * @author Neo Nenaco + * @author Koen Zandberg + */ + +#ifndef MRF24J40_PARAMS_H +#define MRF24J40_PARAMS_H + +#include "board.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set default configuration parameters for the MRF24J40 driver + * @{ + */ +#ifndef MRF24J40_PARAM_SPI +#define MRF24J40_PARAM_SPI (SPI_DEV(0)) +#endif +#ifndef MRF24J40_PARAM_SPI_CLK +#define MRF24J40_PARAM_SPI_CLK (SPI_CLK_5MHZ) +#endif +#ifndef MRF24J40_PARAM_CS +#define MRF24J40_PARAM_CS (GPIO_PIN(0, 0)) +#endif +#ifndef MRF24J40_PARAM_INT +#define MRF24J40_PARAM_INT (GPIO_PIN(0, 1)) +#endif +#ifndef MRF24J40_PARAM_RESET +#define MRF24J40_PARAM_RESET (GPIO_PIN(0, 3)) +#endif + +#define MRF24J40_PARAMS_DEFAULT { .spi = MRF24J40_PARAM_SPI, \ + .spi_clk = MRF24J40_PARAM_SPI_CLK, \ + .cs_pin = MRF24J40_PARAM_CS, \ + .int_pin = MRF24J40_PARAM_INT, \ + .reset_pin = MRF24J40_PARAM_RESET } +/**@}*/ + +/** + * @brief MRF24J40 configuration + */ +static const mrf24j40_params_t mrf24j40_params[] = +{ +#ifdef MRF24J40_PARAMS_BOARD + MRF24J40_PARAMS_BOARD, +#else + MRF24J40_PARAMS_DEFAULT, +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif /* MRF24J40_PARAMS_H */ +/** @} */ diff --git a/drivers/mrf24j40/include/mrf24j40_registers.h b/drivers/mrf24j40/include/mrf24j40_registers.h new file mode 100644 index 000000000000..6aea886166d3 --- /dev/null +++ b/drivers/mrf24j40/include/mrf24j40_registers.h @@ -0,0 +1,454 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * Copyright (C) 2017 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_mrf24j40 + * @{ + * + * @file + * @brief Register and command definitions for MRF24J40 devices + * + * @author Neo Nenaco + * @author Koen Zandberg + */ + +#ifndef MRF24J40_REGISTERS_H +#define MRF24J40_REGISTERS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @brief SPI access specifiers + * @{ + */ +#define MRF24J40_SHORT_ADDR_TRANS (0x00) +#define MRF24J40_LONG_ADDR_TRANS (0x80) +#define MRF24J40_ACCESS_READ (0x00) +#define MRF24J40_ACCESS_WRITE (0x01) +#define MRF24J40_ACCESS_WRITE_LNG (0x10) +#define MRF24J40_ADDR_OFFSET (0x01) +/** @} */ + +/** + * @brief FIFO-Address-Map + ****@{ + */ +#define MRF24J40_TX_NORMAL_FIFO (0x000) +#define MRF24J40_TX_BEACON_FIFO (0x080) +#define MRF24J40_TX_GTS1_FIFO (0x100) +#define MRF24J40_TX_GTS2_FIFO (0x180) +#define MRF24J40_RX_FIFO (0x300) +/** @} */ + +/** + * @brief Short-Register addresses + * @{ + */ +#define MRF24J40_REG_RXMCR (0x00) +#define MRF24J40_REG_PANIDL (0x01) +#define MRF24J40_REG_PANIDH (0x02) +#define MRF24J40_REG_SADRL (0x03) +#define MRF24J40_REG_SADRH (0x04) +#define MRF24J40_REG_EADR0 (0x05) +#define MRF24J40_REG_EADR1 (0x06) +#define MRF24J40_REG_EADR2 (0x07) +#define MRF24J40_REG_EADR3 (0x08) +#define MRF24J40_REG_EADR4 (0x09) +#define MRF24J40_REG_EADR5 (0x0A) +#define MRF24J40_REG_EADR6 (0x0B) +#define MRF24J40_REG_EADR7 (0x0C) +#define MRF24J40_REG_RXFLUSH (0x0D) +#define MRF24J40_REG_ORDER (0x10) +#define MRF24J40_REG_TXMCR (0x11) +#define MRF24J40_REG_ACKTMOUT (0x12) +#define MRF24J40_REG_ESLOTG1 (0x13) +#define MRF24J40_REG_SYMTICKL (0x14) +#define MRF24J40_REG_SYMTICKH (0x15) +#define MRF24J40_REG_PACON0 (0x16) +#define MRF24J40_REG_PACON1 (0x17) +#define MRF24J40_REG_PACON2 (0x18) +#define MRF24J40_REG_TXBCON0 (0x1A) +#define MRF24J40_REG_TXNCON (0x1B) +#define MRF24J40_REG_TXG1CON (0x1C) +#define MRF24J40_REG_TXG2CON (0x1D) +#define MRF24J40_REG_ESLOTG23 (0x1E) +#define MRF24J40_REG_ESLOTG45 (0x1F) +#define MRF24J40_REG_ESLOTG67 (0x20) +#define MRF24J40_REG_TXPEND (0x21) +#define MRF24J40_REG_WAKECON (0x22) +#define MRF24J40_REG_FRMOFFSET (0x23) +#define MRF24J40_REG_TXSTAT (0x24) +#define MRF24J40_REG_TXBCON1 (0x25) +#define MRF24J40_REG_GATECLK (0x26) +#define MRF24J40_REG_TXTIME (0x27) +#define MRF24J40_REG_HSYMTMRL (0x28) +#define MRF24J40_REG_HSYMTMRH (0x29) +#define MRF24J40_REG_SOFTRST (0x2A) +#define MRF24J40_REG_SECCON0 (0x2C) +#define MRF24J40_REG_SECCON1 (0x2D) +#define MRF24J40_REG_TXSTBL (0x2E) +#define MRF24J40_REG_RXSR (0x30) +#define MRF24J40_REG_INTSTAT (0x31) +#define MRF24J40_REG_INTCON (0x32) +#define MRF24J40_REG_GPIO (0x33) +#define MRF24J40_REG_TRISGPIO (0x34) +#define MRF24J40_REG_SLPACK (0x35) +#define MRF24J40_REG_RFCTL (0x36) +#define MRF24J40_REG_SECCR2 (0x37) +#define MRF24J40_REG_BBREG0 (0x38) +#define MRF24J40_REG_BBREG1 (0x39) +#define MRF24J40_REG_BBREG2 (0x3A) +#define MRF24J40_REG_BBREG3 (0x3B) +#define MRF24J40_REG_BBREG4 (0x3C) +#define MRF24J40_REG_BBREG6 (0x3E) +#define MRF24J40_REG_CCAEDTH (0x3F) +/** @} */ + +/** + * @brief Long-Register addresses + * @{ + */ +#define MRF24J40_REG_RFCON0 (0x200) +#define MRF24J40_REG_RFCON1 (0x201) +#define MRF24J40_REG_RFCON2 (0x202) +#define MRF24J40_REG_RFCON3 (0x203) +#define MRF24J40_REG_RFCON5 (0x205) +#define MRF24J40_REG_RFCON6 (0x206) +#define MRF24J40_REG_RFCON7 (0x207) +#define MRF24J40_REG_RFCON8 (0x208) +#define MRF24J40_REG_SLPCAL0 (0x209) +#define MRF24J40_REG_SLPCAL1 (0x20A) +#define MRF24J40_REG_SLPCAL2 (0x20B) +#define MRF24J40_REG_RFSTATE (0x20F) +#define MRF24J40_REG_RSSI (0x210) +#define MRF24J40_REG_SLPCON0 (0x211) +#define MRF24J40_REG_SLPCON1 (0x220) +#define MRF24J40_REG_WAKETIMEL (0x222) +#define MRF24J40_REG_WAKETIMEH (0x223) +#define MRF24J40_REG_REMCNTL (0x224) +#define MRF24J40_REG_REMCNTH (0x225) +#define MRF24J40_REG_MAINCNT0 (0x226) +#define MRF24J40_REG_MAINCNT1 (0x227) +#define MRF24J40_REG_MAINCNT2 (0x228) +#define MRF24J40_REG_MAINCNT3 (0x229) +#define MRF24J40_REG_TESTMODE (0x22F) +#define MRF24J40_REG_ASSOEADR0 (0x230) +#define MRF24J40_REG_ASSOEADR1 (0x231) +#define MRF24J40_REG_ASSOEADR2 (0x232) +#define MRF24J40_REG_ASSOEADR3 (0x233) +#define MRF24J40_REG_ASSOEADR4 (0x234) +#define MRF24J40_REG_ASSOEADR5 (0x235) +#define MRF24J40_REG_ASSOEADR6 (0x236) +#define MRF24J40_REG_ASSOEADR7 (0x237) +#define MRF24J40_REG_ASSOSADR0 (0x238) +#define MRF24J40_REG_ASSOSADR1 (0x239) +#define MRF24J40_REG_UPNONCE0 (0x240) +#define MRF24J40_REG_UPNONCE1 (0x241) +#define MRF24J40_REG_UPNONCE2 (0x242) +#define MRF24J40_REG_UPNONCE3 (0x243) +#define MRF24J40_REG_UPNONCE4 (0x244) +#define MRF24J40_REG_UPNONCE5 (0x245) +#define MRF24J40_REG_UPNONCE6 (0x246) +#define MRF24J40_REG_UPNONCE7 (0x247) +#define MRF24J40_REG_UPNONCE8 (0x248) +#define MRF24J40_REG_UPNONCE9 (0x249) +#define MRF24J40_REG_UPNONCE10 (0x24A) +#define MRF24J40_REG_UPNONCE11 (0x24B) +#define MRF24J40_REG_UPNONCE12 (0x24C) +/** @} */ + +/** + * @brief Timing definition for the mrf24j40. + * @{ + */ +#define MRF24J40_RESET_DELAY (2000U) /* Datasheet MRF24J40 ~2ms */ +#define MRF24J40_RESET_PULSE_WIDTH (20000U) /* 20ms (estimated */ + +#define MRF24J40_WAKEUP_DELAY (2000U) +/** Undocumented delay. Probably needed because the bit has to be sampled by the low speed sleep clock */ +#define MRF24J40_DELAY_SLEEP_TOGGLE (50U) +#define MRF24J40_STATE_RESET_DELAY (200U) +/** @} */ + +/** + * @brief Bitfield definitions for the RXMCR register (0x00) + * @{ + */ +#define MRF24J40_RXMCR_NOACKRSP (0b00100000) +#define MRF24J40_RXMCR_PANCOORD (0b00001000) +#define MRF24J40_RXMCR_COORD (0b00000100) +#define MRF24J40_RXMCR_ERRPKT (0b00000010) +#define MRF24J40_RXMCR_PROMI (0b00000001) +/** @} */ + +/** + * @brief Bitfield definitions for the RXFLUSH register (0x0D) + * @{ + */ +#define MRF24J40_RXFLUSH_WAKEPOL (0b01000000) +#define MRF24J40_RXFLUSH_WAKEPAD (0b00100000) +#define MRF24J40_RXFLUSH_CMDONLY (0b00001000) +#define MRF24J40_RXFLUSH_DATAONLY (0b00000100) +#define MRF24J40_RXFLUSH_BCNONLY (0b00000010) +#define MRF24J40_RXFLUSH_RXFLUSH (0b00000001) +/** @} */ + +/** + * @brief Bitfield definitions for the TXMCR register (0x11) + * @{ + */ +#define MRF24J40_TXMCR_CSMA_BACKOFF_MASK (0x07) + +#define MRF24J40_TXMCR_MACMINBE (0b00011000) +#define MRF24J40_TXMCR_NOCSMA (0b10000000) +#define MRF24J40_TXMCR_BATLIFEXT (0b01000000) +#define MRF24J40_TXMCR_SLOTTED (0b00100000) +#define MRF24J40_TXMCR_MACMINBE1 (0b00010000) +#define MRF24J40_TXMCR_MACMINBE0 (0b00001000) +#define MRF24J40_TXMCR_CSMABF2 (0b00000100) +#define MRF24J40_TXMCR_CSMABF1 (0b00000010) +#define MRF24J40_TXMCR_CSMABF0 (0b00000001) + +/** @} */ + +/** + * @brief Bitfield definitions for the PACON2 register (0x18) + * @{ + */ +#define MRF24J40_PACON2_FIFOEN (0b10000000) +#define MRF24J40_PACON2_TXONTS3 (0b00100000) +#define MRF24J40_PACON2_TXONTS2 (0b00010000) +#define MRF24J40_PACON2_TXONTS1 (0b00001000) +#define MRF24J40_PACON2_TXONTS0 (0b00000100) +#define MRF24J40_PACON2_TXONT8 (0b00000010) +#define MRF24J40_PACON2_TXONT7 (0b00000001) +/** @} */ + +/** + * @brief Bitfield definitions for the TXNCON register (0x1B) + * @{ + */ +#define MRF24J40_TXNCON_FPSTAT (0x10) +#define MRF24J40_TXNCON_INDIRECT (0x08) +#define MRF24J40_TXNCON_TXNACKREQ (0x04) +#define MRF24J40_TXNCON_TXNSECEN (0x02) +#define MRF24J40_TXNCON_TXNTRIG (0x01) +/** @} */ + +/** + * @brief Bitfield definitions for the WAKECON register (0x22) + * @{ + */ +#define MRF24J40_WAKECON_IMMWAKE (0b10000000) +#define MRF24J40_WAKECON_REGWAKE (0b01000000) +/** @} */ + +/** + * @brief Bitfield definitions for the TXSTAT register (0x24) + * @{ + */ +#define MRF24J40_TXSTAT_MAX_FRAME_RETRIES (0b11000000) +#define MRF24J40_TXSTAT_TXNRETRY1 (0b10000000) +#define MRF24J40_TXSTAT_TXNRETRY0 (0b01000000) +#define MRF24J40_TXSTAT_CCAFAIL (0b00100000) +#define MRF24J40_TXSTAT_TXG2FNT (0b00010000) +#define MRF24J40_TXSTAT_TXG1FNT (0b00001000) +#define MRF24J40_TXSTAT_TXG2STAT (0b00000100) +#define MRF24J40_TXSTAT_TXG1STAT (0b00000010) +#define MRF24J40_TXSTAT_TXNSTAT (0b00000001) +/** @} */ + +/** + * @brief Bitfield definitions for the SOFTRST register (0x2A) + * @{ + */ +#define MRF24J40_SOFTRST_RSTPWR (0b00000100) +#define MRF24J40_SOFTRST_RSTBB (0b00000010) +#define MRF24J40_SOFTRST_RSTMAC (0b00000001) +/** @} */ + +/** + * @brief Bitfield definitions for the TXSTBL register (0x2E) + * @{ + */ +#define MRF24J40_TXSTBL_RFSTBL3 (0x80) +#define MRF24J40_TXSTBL_RFSTBL2 (0x40) +#define MRF24J40_TXSTBL_RFSTBL1 (0x20) +#define MRF24J40_TXSTBL_RFSTBL0 (0x10) +#define MRF24J40_TXSTBL_MSIFS3 (0x08) +#define MRF24J40_TXSTBL_MSIFS2 (0x04) +#define MRF24J40_TXSTBL_MSIFS1 (0x02) +#define MRF24J40_TXSTBL_MSIFS0 (0x01) +/** @} */ + +/** + * @brief Bitfield definitions for the INTSTAT register (0x31) + * @{ + */ +#define MRF24J40_INTSTAT_SLPIF (0x80) +#define MRF24J40_INTSTAT_WAKEIF (0x40) +#define MRF24J40_INTSTAT_HSYMTMRIF (0x20) +#define MRF24J40_INTSTAT_SECIF (0x10) +#define MRF24J40_INTSTAT_RXIF (0x08) +#define MRF24J40_INTSTAT_TXG2IF (0x04) +#define MRF24J40_INTSTAT_TXG1IF (0x02) +#define MRF24J40_INTSTAT_TXNIF (0x01) +/** @} */ + +/** + * @brief Bitfield definitions for the INTCON register (0x32) + * @{ + */ +#define MRF24J40_INTCON_SLPIE (0x80) +#define MRF24J40_INTCON_WAKEIE (0x40) +#define MRF24J40_INTCON_HSYMTMRIE (0x20) +#define MRF24J40_INTCON_SECIE (0x10) +#define MRF24J40_INTCON_RXIE (0x08) +#define MRF24J40_INTCON_TXG2IE (0x04) +#define MRF24J40_INTCON_TXG1IE (0x02) +#define MRF24J40_INTCON_TXNIE (0x01) +/** @} */ + +/** + * @brief Bitfield definitions for the SLPACK register (0x35) + * @{ + */ +#define MRF24J40_SLPACK_SLPACK (0b10000000) +/** @} */ + +/** + * @brief Bitfield definitions for the RFCTL register (0x36) + * @{ + */ +#define MRF24J40_RFCTL_WAKECNT8 (0x10) +#define MRF24J40_RFCTL_WAKECNT7 (0x08) +#define MRF24J40_RFCTL_RFRST (0x04) +#define MRF24J40_RFCTL_RFTXMODE (0x02) +#define MRF24J40_RFCTL_RFRXMODE (0x01) +/** @} */ + +/** + * @brief Bitfield definitions for the BBREG1 register (0x39) + * @{ + */ +#define MRF24J40_BBREG1_RXDECINV (0b00000100) +/** @} */ + +/** + * @brief Bitfield definitions for the BBREG2 register (0x3A) + * @{ + */ +#define MRF24J40_BBREG2_CCAMODE3 (0b11000000) +#define MRF25J40_BBREG2_CCAMODE1 (0b10000000) +#define MRF24J40_BBREG2_CCAMODE2 (0b01000000) + +#define MRF24J40_BBREG2_CCACSTH (0b00111100) +/** @} */ + +/** + * @brief Bitfield definitions for the BBREG6 register (0x3E) + * @{ + */ +#define MRF24J40_BBREG6_RSSIMODE1 (0b10000000) +#define MRF24J40_BBREG6_RSSIMODE2 (0b01000000) +#define MRF24J40_BBREG2_RSSIRDY (0b00000001) + +#define MRF24J40_BBREG2_CCACSTH (0b00111100) +/** @} */ + +/** + * @brief Bitfield definitions for the RFCON1 register (0x201) + * @{ + */ +#define MRF24J40_RFCON1_VCOOPT7 (0x80) +#define MRF24J40_RFCON1_VCOOPT6 (0x40) +#define MRF24J40_RFCON1_VCOOPT5 (0x20) +#define MRF24J40_RFCON1_VCOOPT4 (0x10) +#define MRF24J40_RFCON1_VCOOPT3 (0x08) +#define MRF24J40_RFCON1_VCOOPT2 (0x04) +#define MRF24J40_RFCON1_VCOOPT1 (0x02) +#define MRF24J40_RFCON1_VCOOPT0 (0x01) +/** @} */ + +/** + * @brief Bitfield definitions for the RFCON2 register (0x202) + * @{ + */ +#define MRF24J40_RFCON2_PLLEN (0x80) +/** @} */ + +/** + * @brief Bitfield definitions for the RFCON6 register (0x206) + * @{ + */ +#define MRF24J40_RFCON6_TXFIL (0x80) +#define MRF24J40_RFCON6_20MRECVR (0x10) +#define MRF24J40_RFCON6_BATEN (0x08) +/** @} */ + +/** + * @brief Bitfield definitions for the RFCON7 register (0x207) + * @{ + */ +#define MRF24J40_RFCON7_SLPCLKSEL1 (0x80) +#define MRF24J40_RFCON7_SLPCLKSEL2 (0x40) +/** @} */ + +/** + * @brief Bitfield definitions for the RFCON8 register (0x208) + * @{ + */ +#define MRF24J40_RFCON8_RFVCO (0x10) +/** @} */ + +/** + * @brief Bitfield definitions for the RFSTATE register (0x20F) + * @{ + */ +#define MRF24J40_RFSTATE_MASK (0xA0) +#define MRF24J40_RFSTATE_RTSEL2 (0xE0) +#define MRF24J40_RFSTATE_RTSEL1 (0xC0) +#define MRF24J40_RFSTATE_RX (0xA0) +#define MRF24J40_RFSTATE_TX (0x80) +#define MRF24J40_RFSTATE_CALVCO (0x60) +#define MRF24J40_RFSTATE_SLEEP (0x40) +#define MRF24J40_RFSTATE_CALFIL (0x20) +#define MRF24J40_RFSTATE_RESET (0x00) +/** @} */ + +/** + * @brief Bitfield definitions for the SLPCON1 register (0x211) + * @{ + */ +#define MRF24J40_SLPCON0_INTEDGE (0x02) +#define MRF24J40_SLPCON0_SLPCLKEN (0x01) +/** @} */ + +/** + * @brief Bitfield definitions for the SLPCON1 register (0x212) + * @{ + */ +#define MRF24J40_SLPCON1_CLKOUTEN (0x20) +#define MRF24J40_SLPCON1_SLPCLKDIV4 (0x10) +#define MRF24J40_SLPCON1_SLPCLKDIV3 (0x08) +#define MRF24J40_SLPCON1_SLPCLKDIV2 (0x04) +#define MRF24J40_SLPCON1_SLPCLKDIV1 (0x02) +#define MRF24J40_SLPCON1_SLPCLKDIV0 (0x01) +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif /* MRF24J40_REGISTERS_H */ +/** @} */ diff --git a/drivers/mrf24j40/mrf24j40.c b/drivers/mrf24j40/mrf24j40.c new file mode 100644 index 000000000000..8a26a02ab979 --- /dev/null +++ b/drivers/mrf24j40/mrf24j40.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * Copyright (C) 2017 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_mrf24j40 + * @{ + * + * @file + * @brief Implementation of public functions for MRF24J40 drivers + * + * @author Koen Zandberg + * @author Neo Nenaco + * + * @} + */ + +#include "uuid.h" +#include "byteorder.h" +#include "net/gnrc.h" +#include "mrf24j40_registers.h" +#include "mrf24j40_internal.h" +#include "mrf24j40_netdev.h" +#include "xtimer.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +void mrf24j40_setup(mrf24j40_t *dev, const mrf24j40_params_t *params) +{ + netdev2_t *netdev = (netdev2_t *)dev; + + netdev->driver = &mrf24j40_driver; + /* initialize device descriptor */ + memcpy(&dev->params, params, sizeof(mrf24j40_params_t)); +} + +void mrf24j40_reset(mrf24j40_t *dev) +{ + eui64_t addr_long; + + mrf24j40_init(dev); + + /* reset options and sequence number */ + dev->netdev.seq = 0; + dev->netdev.flags = 0; + + /* get an 8-byte unique ID to use as hardware address */ + uuid_get(addr_long.uint8, IEEE802154_LONG_ADDRESS_LEN); + addr_long.uint8[0] &= ~(0x01); + addr_long.uint8[0] |= (0x02); + /* set short and long address */ + mrf24j40_set_addr_long(dev, NTOHLL(addr_long.uint64.u64)); + mrf24j40_set_addr_short(dev, NTOHS(addr_long.uint16[0].u16)); + + /* set default PAN id */ + mrf24j40_set_pan(dev, IEEE802154_DEFAULT_PANID); + mrf24j40_set_chan(dev, IEEE802154_DEFAULT_CHANNEL); + + /* configure Immediate Sleep and Wake-Up mode */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE); + + /* set default options */ + mrf24j40_set_option(dev, IEEE802154_FCF_PAN_COMP, true); + mrf24j40_set_option(dev, NETDEV2_IEEE802154_SRC_MODE_LONG, true); + mrf24j40_set_option(dev, NETDEV2_IEEE802154_ACK_REQ, true); + mrf24j40_set_option(dev, MRF24J40_OPT_CSMA, true); + mrf24j40_set_option(dev, MRF24J40_OPT_TELL_RX_START, false); + mrf24j40_set_option(dev, MRF24J40_OPT_TELL_RX_END, true); +#ifdef MODULE_NETSTATS_L2 + mrf24j40_set_option(dev, MRF24J40_OPT_TELL_TX_END, true); +#endif + + /* set default protocol */ +#ifdef MODULE_GNRC_SIXLOWPAN + dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN; +#elif MODULE_GNRC + dev->netdev.proto = GNRC_NETTYPE_UNDEF; +#endif + + /* go into RX state */ + mrf24j40_reset_tasks(dev); + dev->state = 0; + mrf24j40_set_state(dev, MRF24J40_PSEUDO_STATE_IDLE); + DEBUG("mrf24j40_reset(): reset complete.\n"); +} + +bool mrf24j40_cca(mrf24j40_t *dev) +{ + uint8_t tmp_ccaedth; + uint8_t status; + uint8_t tmp_rssi; + + mrf24j40_assert_awake(dev); + + /* trigger CCA measurment */ + /* take a look onto datasheet chapter 3.6.1 */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG6, MRF24J40_BBREG6_RSSIMODE1); + /* wait for result to be ready */ + do { + status = mrf24j40_reg_read_short(dev, MRF24J40_REG_BBREG6); + } while (!(status & MRF24J40_BBREG2_RSSIRDY)); + mrf24j40_assert_sleep(dev); + /* return according to measurement */ + tmp_ccaedth = mrf24j40_reg_read_short(dev, MRF24J40_REG_CCAEDTH); /* Energy detection threshold */ + tmp_rssi = mrf24j40_reg_read_long(dev, MRF24J40_REG_RSSI); + if (tmp_rssi < tmp_ccaedth) { + /* channel is clear */ + return true; /* idle */ + } + else { + /* channel is busy */ + return false; + } +} + +void mrf24j40_tx_prepare(mrf24j40_t *dev) +{ + DEBUG("[mrf24j40] TX_Prepare, Current state: %x\n", dev->state); + do { + mrf24j40_update_tasks(dev); + } while (!(dev->pending & MRF24J40_TASK_TX_DONE)); + mrf24j40_assert_awake(dev); + dev->pending &= ~(MRF24J40_TASK_TX_DONE); + dev->tx_frame_len = IEEE802154_FCS_LEN; +} + +size_t mrf24j40_tx_load(mrf24j40_t *dev, uint8_t *data, size_t len, size_t offset) +{ + + DEBUG("[mrf24j40] TX_load, Current state: %x\n", dev->state); + dev->tx_frame_len += (uint8_t)len; + + mrf24j40_tx_normal_fifo_write(dev, MRF24J40_TX_NORMAL_FIFO + offset + 2, data, len); + return offset + len; +} + +void mrf24j40_tx_exec(mrf24j40_t *dev) +{ + netdev2_t *netdev = (netdev2_t *)dev; + + + dev->tx_frame_len = dev->tx_frame_len - IEEE802154_FCS_LEN; + /* write frame length field in FIFO */ + mrf24j40_tx_normal_fifo_write(dev, MRF24J40_TX_NORMAL_FIFO + 1, &(dev->tx_frame_len), 1); + + /* write header length to FIFO address 0x00 */ + /* from figure 3-11 datasheet: header length = 2 Bytes Frame Control + * + 1 Byte Seq. No. + * + 4 to 20 Bytes Addressing Fields + */ + mrf24j40_reg_write_long(dev, MRF24J40_TX_NORMAL_FIFO, dev->header_len); + + if (dev->netdev.flags & NETDEV2_IEEE802154_ACK_REQ) { + mrf24j40_reg_write_short(dev, MRF24J40_REG_TXNCON, MRF24J40_TXNCON_TXNACKREQ | MRF24J40_TXNCON_TXNTRIG); + } + else { + mrf24j40_reg_write_short(dev, MRF24J40_REG_TXNCON, MRF24J40_TXNCON_TXNTRIG); + } + if (netdev->event_callback && (dev->netdev.flags & MRF24J40_OPT_TELL_TX_START)) { + netdev->event_callback(netdev, NETDEV2_EVENT_TX_STARTED); + } +} diff --git a/drivers/mrf24j40/mrf24j40_getset.c b/drivers/mrf24j40/mrf24j40_getset.c new file mode 100644 index 000000000000..9da3b8fd6771 --- /dev/null +++ b/drivers/mrf24j40/mrf24j40_getset.c @@ -0,0 +1,490 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * Copyright (C) 2016 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_mrf24j40 + * @{ + * + * @file + * @brief Getter and setter functions for the MRF24J40 drivers + * + * @author Koen Zandberg + * @author Neo Nenaco + * + * @} + */ + +#include "mrf24j40.h" +#include "mrf24j40_internal.h" +#include "mrf24j40_registers.h" +#include "xtimer.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Values of RFCON3 - Address: 0x203 + * 0b00000000 -> 0dB -> 0 + * 0b00001000 -> -0.5dB -> 0 + * 0b00010000 -> -1.2dB -> -1 + * 0b00011000 -> -1.9dB -> -2 + * 0b00100000 -> -2.8dB -> -3 + * 0b00101000 -> -3.7dB -> -4 + * 0b00110000 -> -4.9dB -> -5 + * 0b00111000 -> -6.3dB -> -6 + * 0b01000000 -> -10dB -> -10 + * 0b01001000 -> -10.5dB-> -10 + * 0b01010000 -> -11.2dB-> -11 + * 0b01011000 -> -11.9dB-> -12 + * 0b01100000 -> -12.8dB-> -13 + * 0b01101000 -> -13.7dB-> -14 + * 0b01110000 -> -14.9dB-> -15 + * 0b01111000 -> -16.3dB-> -16 + * 0b10000000 -> -20dB -> -20 + * 0b10001000 -> -20.5dB-> -20 + * 0b10010000 -> -21.2dB-> -21 + * 0b10011000 -> -21.9dB-> -22 + * 0b10100000 -> -22.8dB-> -23 + * 0b10101000 -> -23.7dB-> -24 + * 0b10110000 -> -24.9dB-> -25 + * 0b10111000 -> -26.3dB-> -26 + * 0b11000000 -> -30dB -> -30 + * 0b11001000 -> -30.5dB-> -30 + * 0b11010000 -> -31.2dB-> -31 + * 0b11011000 -> -31.9dB-> -32 + * 0b11100000 -> -32.8dB-> -33 + * 0b11101000 -> -33.7dB-> -34 + * 0b11110000 -> -34.9dB-> -35 + * 0b11111000 -> -36.3dB-> -36 + */ + +static const int16_t tx_pow_to_dbm[] = { 0, 0, -1, -2, -3, -4, -5, -6, + -10, -10, -11, -12, -13, -14, -15, -16, + -20, -20, -21, -22, -23, -24, -25, -26, + -30, -30, -31, -32, -33, -34, -35, -36 }; + +static const uint8_t dbm_to_tx_pow[] = { 0x00, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x38, 0x38, 0x40, + 0x40, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x78, 0x78, 0x80, + 0x80, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xb8, 0xb8, 0xc0, + 0xc0, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8 }; + +/* take a look onto datasheet table 3-8 */ +static const int8_t dBm_value[] = { 95, 89, 88, 88, 87, 87, 87, 87, \ + 86, 86, 86, 86, 85, 85, 85, 85, \ + 84, 84, 84, 84, 84, 84, 83, 83, \ + 83, 83, 82, 82, 82, 82, 81, 81, \ + 81, 81, 81, 80, 80, 80, 80, 80, \ + 80, 79, 79, 79, 79, 79, 78, 78, \ + 78, 78, 78, 77, 77, 77, 77, 77, \ + 76, 76, 76, 76, 76, 75, 75, 75, \ + 75, 75, 75, 74, 74, 74, 74, 73, \ + 73, 73, 73, 73, 72, 72, 72, 72, \ + 72, 71, 71, 71, 71, 71, 70, 70, \ + 70, 70, 70, 70, 70, 69, 69, 69, \ + 69, 69, 68, 68, 68, 68, 68, 68, \ + 68, 67, 67, 67, 67, 66, 66, 66, \ + 66, 66, 66, 65, 65, 65, 65, 65, \ + 64, 64, 64, 64, 63, 63, 63, 63, \ + 62, 62, 62, 62, 61, 61, 61, 61, \ + 60, 60, 60, 60, 60, 59, 59, 59, \ + 59, 59, 58, 58, 58, 58, 58, 57, \ + 57, 57, 57, 57, 57, 56, 56, 56, \ + 56, 56, 56, 56, 55, 55, 55, 55, \ + 54, 54, 54, 54, 54, 54, 53, 53, \ + 53, 53, 53, 53, 53, 52, 52, 52, \ + 52, 52, 52, 51, 51, 51, 51, 51, \ + 50, 50, 50, 50, 50, 49, 49, 49, \ + 49, 49, 48, 48, 48, 48, 47, 47, \ + 47, 47, 47, 46, 46, 46, 46, 45, \ + 45, 45, 45, 44, 44, 44, 44, 44, \ + 43, 43, 43, 42, 42, 42, 42, 41, \ + 41, 41, 41, 41, 41, 40, 40, 40, \ + 40, 40, 39, 39, 39, 39, 39, 38, \ + 38, 38, 38, 37, 37, 37, 36, 30 }; + +/* take a look onto datasheet table 3-8 */ +static const uint8_t RSSI_value[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfa, 0xf5, \ + 0xef, 0xe9, 0xe4, 0xe1, 0xdd, 0xd8, 0xd4, 0xcf, 0xcb, 0xc6, \ + 0xc1, 0xbc, 0xb7, 0xb0, 0xaa, 0xa5, 0x9f, 0x99, 0x94, 0x8f, \ + 0x8a, 0x85, 0x81, 0x7d, 0x79, 0x75, 0x6f, 0x6b, 0x64, 0x5f, \ + 0x59, 0x53, 0x4e, 0x49, 0x44, 0x3f, 0x3a, 0x35, 0x30, 0x2b, \ + 0x25, 0x20, 0x1b, 0x17, 0x12, 0x0d, 0x09, 0x05, 0x02, 0x01, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + +uint16_t mrf24j40_get_addr_short(mrf24j40_t *dev) +{ + return (dev->netdev.short_addr[0] << 8) | dev->netdev.short_addr[1]; +} + +void mrf24j40_set_addr_short(mrf24j40_t *dev, uint16_t addr) +{ +#ifdef MODULE_SIXLOWPAN + /* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to + * 0 for unicast addresses */ + dev->netdev.short_addr[0] &= 0x7F; +#endif + dev->netdev.short_addr[0] = (uint8_t)(addr); + dev->netdev.short_addr[1] = (uint8_t)(addr >> 8); + mrf24j40_reg_write_short(dev, MRF24J40_REG_SADRL, + dev->netdev.short_addr[1]); + mrf24j40_reg_write_short(dev, MRF24J40_REG_SADRH, + dev->netdev.short_addr[0]); +} + +uint64_t mrf24j40_get_addr_long(mrf24j40_t *dev) +{ + uint64_t addr; + + uint8_t *ap = (uint8_t *)(&addr); + + for (int i = 0; i < 8; i++) { + ap[i] = dev->netdev.long_addr[i]; + } + return addr; +} + +void mrf24j40_set_addr_long(mrf24j40_t *dev, uint64_t addr) +{ + for (int i = 0; i < 8; i++) { + dev->netdev.long_addr[i] = (uint8_t)(addr >> (i * 8)); + mrf24j40_reg_write_short(dev, (MRF24J40_REG_EADR0 + i), + (addr >> ((7 - i) * 8))); + } +} + +uint8_t mrf24j40_get_chan(mrf24j40_t *dev) +{ + return dev->netdev.chan; +} + + +void mrf24j40_set_chan(mrf24j40_t *dev, uint8_t channel) +{ + uint8_t channel_value; + + if ((channel < IEEE802154_CHANNEL_MIN) || + (channel > IEEE802154_CHANNEL_MAX)) { + return; + } + + dev->netdev.chan = channel; + + /* Channel settings + * 11 -> Value = 0x03 + * 12 -> Value = 0x13 + * 13 -> Value = 0x23 + * 14 -> Value = 0x33 + * 15 -> Value = 0x43 + * 16 -> Value = 0x53 + * 17 -> Value = 0x63 + * 18 -> Value = 0x73 + * 19 -> Value = 0x83 + * 20 -> Value = 0x93 + * 21 -> Value = 0xA3 + * 22 -> Value = 0xB3 + * 23 -> Value = 0xC3 + * 24 -> Value = 0xD3 + * 25 -> Value = 0xE3 + * 26 -> Value = 0xF3 + */ + /* not using an array here because it's not starting at zero */ + switch (channel) { + case 11: channel_value = 0x03; + break; + case 12: channel_value = 0x13; + break; + case 13: channel_value = 0x23; + break; + case 14: channel_value = 0x33; + break; + case 15: channel_value = 0x43; + break; + case 16: channel_value = 0x53; + break; + case 17: channel_value = 0x63; + break; + case 18: channel_value = 0x73; + break; + case 19: channel_value = 0x83; + break; + case 20: channel_value = 0x93; + break; + case 21: channel_value = 0xa3; + break; + case 22: channel_value = 0xb3; + break; + case 23: channel_value = 0xc3; + break; + case 24: channel_value = 0xd3; + break; + case 25: channel_value = 0xe3; + break; + case 26: channel_value = 0xf3; + break; + default: + return; + } + + mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON0, channel_value); + /* + * Note:Perform an RF State Machine Reset (see Section 3.1 “Reset”) + * after a channel frequency change. Then, delay at least 192 us after + * the RF State Machine Reset, to allow the RF circuitry to calibrate. + */ + mrf24j40_reset_state_machine(dev); +} + +uint16_t mrf24j40_get_pan(mrf24j40_t *dev) +{ + return dev->netdev.pan; +} + +void mrf24j40_set_pan(mrf24j40_t *dev, uint16_t pan) +{ + le_uint16_t le_pan = byteorder_btols(byteorder_htons(pan)); + + dev->netdev.pan = pan; + DEBUG("pan0: %u, pan1: %u\n", le_pan.u8[0], le_pan.u8[1]); + mrf24j40_reg_write_short(dev, MRF24J40_REG_PANIDL, le_pan.u8[0]); + mrf24j40_reg_write_short(dev, MRF24J40_REG_PANIDH, le_pan.u8[1]); +} + + +int16_t mrf24j40_get_txpower(mrf24j40_t *dev) +{ + uint8_t txpower; + + txpower = (mrf24j40_reg_read_long(dev, MRF24J40_REG_RFCON3) >> 3) & 0x1F; + return tx_pow_to_dbm[txpower]; +} + +void mrf24j40_set_txpower(mrf24j40_t *dev, int16_t txpower) +{ + uint8_t txpower_reg_value; + + /* positive values are better with a conversion array */ + txpower = (txpower < 0) ? -1 * txpower : txpower; + txpower = (txpower > 36) ? 36 : txpower; + txpower_reg_value = dbm_to_tx_pow[txpower]; + + mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON3, txpower_reg_value); + +} + +uint8_t mrf24j40_get_csma_max_retries(mrf24j40_t *dev) +{ + uint8_t tmp; + + tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR); + tmp &= MRF24J40_TXMCR_CSMA_BACKOFF_MASK; + return tmp; +} + +void mrf24j40_set_csma_max_retries(mrf24j40_t *dev, int8_t retries) +{ + uint8_t tmp; + + /* get current register settings */ + tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR); + /* clear csma bits */ + tmp &= ~(MRF24J40_TXMCR_CSMA_BACKOFF_MASK); + /* apply new settings */ + tmp |= (retries & MRF24J40_TXMCR_CSMA_BACKOFF_MASK); + mrf24j40_reg_write_short(dev, MRF24J40_REG_TXMCR, tmp); +} + +int8_t mrf24j40_get_cca_threshold(mrf24j40_t *dev) +{ + int8_t tmp; + + tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_CCAEDTH); /* Energy detection threshold */ + + return(dBm_value[tmp]); /* in dBm */ +} + +void mrf24j40_set_cca_threshold(mrf24j40_t *dev, int8_t value) +{ + /* ensure the given value is negative, since a CCA threshold > 0 is + just impossible: thus, any positive value given is considered + to be the absolute value of the actually wanted threshold */ + if (value < 0) { + value = -value; + } + + mrf24j40_reg_write_short(dev, MRF24J40_REG_CCAEDTH, RSSI_value[value]); +} + +void mrf24j40_set_option(mrf24j40_t *dev, uint16_t option, bool state) +{ + uint8_t tmp; + + DEBUG("set option %i to %i\n", option, state); + + /* set option field */ + if (state) { + dev->netdev.flags |= option; + /* trigger option specific actions */ + switch (option) { + case MRF24J40_OPT_CSMA: + DEBUG("[mrf24j40] opt: enabling CSMA mode (4 retries, macMinBE: 3 max BE: 5)\n"); + /* Initialize CSMA seed with hardware address */ + tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR); + tmp &= ~MRF24J40_TXMCR_NOCSMA; + mrf24j40_reg_write_short(dev, MRF24J40_REG_TXMCR, tmp); + break; + case MRF24J40_OPT_PROMISCUOUS: + DEBUG("[mrf24j40] opt: enabling PROMISCUOUS mode\n"); + /* disable auto ACKs in promiscuous mode */ + tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_RXMCR); + tmp |= MRF24J40_RXMCR_NOACKRSP; + /* enable promiscuous mode */ + tmp |= MRF24J40_RXMCR_PROMI; + tmp &= ~MRF24J40_RXMCR_ERRPKT; + mrf24j40_reg_write_short(dev, MRF24J40_REG_RXMCR, tmp); + break; + case NETDEV2_IEEE802154_ACK_REQ: + DEBUG("[mrf24j40] opt: enabling auto ACKs\n"); + tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_RXMCR); + tmp &= ~MRF24J40_RXMCR_NOACKRSP; + mrf24j40_reg_write_short(dev, MRF24J40_REG_RXMCR, tmp); + break; + default: + /* do nothing */ + break; + } + } + /* clear option field */ + else { + dev->netdev.flags &= ~(option); + /* trigger option specific actions */ + switch (option) { + case MRF24J40_OPT_CSMA: + DEBUG("[mrf24j40] opt: disabling CSMA mode\n"); + tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR); + tmp |= MRF24J40_TXMCR_NOCSMA; + /* MACMINBE<1:0>: The minimum value of the backoff exponent + * in the CSMA-CA algorithm. Note that if this value is set + * to ‘0’, collision avoidance is disabled. */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_TXMCR, tmp); + break; + case MRF24J40_OPT_PROMISCUOUS: + DEBUG("[mrf24j40] opt: disabling PROMISCUOUS mode\n"); + /* disable promiscuous mode */ + tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_RXMCR); + tmp &= ~MRF24J40_RXMCR_PROMI; + tmp &= ~MRF24J40_RXMCR_ERRPKT; + /* re-enable AUTOACK only if the option is set */ + if (dev->netdev.flags & NETDEV2_IEEE802154_ACK_REQ) { + tmp &= ~(MRF24J40_RXMCR_NOACKRSP); + mrf24j40_reg_write_short(dev, MRF24J40_REG_RXMCR, tmp); + } + break; + case NETDEV2_IEEE802154_ACK_REQ: + DEBUG("[mrf24j40] opt: disabling auto ACKs\n"); + tmp = mrf24j40_reg_read_short(dev, MRF24J40_REG_RXMCR); + tmp |= MRF24J40_RXMCR_NOACKRSP; + mrf24j40_reg_write_short(dev, MRF24J40_REG_RXMCR, tmp); + break; + default: + /* do nothing */ + break; + } + } +} + + +void mrf24j40_set_state(mrf24j40_t *dev, uint8_t state) +{ + uint8_t old_state; + + old_state = dev->state; + + + if (state == old_state) { + return; + } + /* check if asked to wake up from sleep mode */ + if (old_state == MRF24J40_PSEUDO_STATE_SLEEP) { + mrf24j40_assert_awake(dev); + } + if (state == MRF24J40_PSEUDO_STATE_SLEEP) { + mrf24j40_sleep(dev); + } + if (state == MRF24J40_PSEUDO_STATE_IDLE) { + dev->state = state; + } + dev->idle_state = state; +} + +void mrf24j40_sleep(mrf24j40_t *dev) +{ + DEBUG("[mrf24j40] Putting into sleep mode\n"); + /* Datasheet chapter 3.15.2 IMMEDIATE SLEEP AND WAKE-UP MODE */ + /* First force a Power Management Reset */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_SOFTRST, MRF24J40_SOFTRST_RSTPWR); + /* Go to SLEEP mode */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_SLPACK, MRF24J40_SLPACK_SLPACK); + dev->state = MRF24J40_PSEUDO_STATE_SLEEP; +} + +void mrf24j40_assert_sleep(mrf24j40_t *dev) +{ + if (dev->idle_state == MRF24J40_PSEUDO_STATE_SLEEP) { + mrf24j40_sleep(dev); + } +} + +void mrf24j40_assert_awake(mrf24j40_t *dev) +{ + if (dev->state == MRF24J40_PSEUDO_STATE_SLEEP) { + DEBUG("[mrf24j40] Waking up from sleep mode\n"); + /* Wake mrf up */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE | MRF24J40_WAKECON_REGWAKE); + /* undocumented delay, needed for stable wakeup */ + xtimer_usleep(MRF24J40_DELAY_SLEEP_TOGGLE); + mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE); + /* reset state machine */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_RFCTL, MRF24J40_RFCTL_RFRST); + mrf24j40_reg_write_short(dev, MRF24J40_REG_RFCTL, 0x00); + /* After wake-up, delay at least 2 ms to allow 20 MHz main + * oscillator time to stabilize before transmitting or receiving. + */ + xtimer_usleep(MRF24J40_WAKEUP_DELAY); + /* reset interrupts */ + mrf24j40_reg_read_short(dev, MRF24J40_REG_INTSTAT); + dev->state = MRF24J40_PSEUDO_STATE_IDLE; + } +} + +void mrf24j40_reset_state_machine(mrf24j40_t *dev) +{ + uint8_t rfstate; + + mrf24j40_reg_write_short(dev, MRF24J40_REG_RFCTL, MRF24J40_RFCTL_RFRST); + mrf24j40_reg_write_short(dev, MRF24J40_REG_RFCTL, 0x00); + xtimer_usleep(MRF24J40_STATE_RESET_DELAY); /* Delay at least 192us */ + do { + rfstate = mrf24j40_reg_read_long(dev, MRF24J40_REG_RFSTATE); + } while ((rfstate & MRF24J40_RFSTATE_MASK) != MRF24J40_RFSTATE_RX); +} + +void mrf24j40_software_reset(mrf24j40_t *dev) +{ + uint8_t softrst; + + mrf24j40_reg_write_short(dev, MRF24J40_REG_SOFTRST, MRF24J40_SOFTRST_RSTPWR | + MRF24J40_SOFTRST_RSTBB | + MRF24J40_SOFTRST_RSTMAC ); + do { + softrst = mrf24j40_reg_read_short(dev, MRF24J40_REG_SOFTRST); + } while (softrst != 0); /* wait until soft-reset has finished */ +} diff --git a/drivers/mrf24j40/mrf24j40_internal.c b/drivers/mrf24j40/mrf24j40_internal.c new file mode 100644 index 000000000000..2e540123a686 --- /dev/null +++ b/drivers/mrf24j40/mrf24j40_internal.c @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * Copyright (C) 2017 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_mrf24j40 + * @{ + * + * @file + * @brief Implementation of driver internal functions + * + * @author Koen Zandberg + * @author Neo Nenaco + * + * @} + */ +#include "periph/spi.h" +#include "periph/gpio.h" +#include "xtimer.h" +#include "mrf24j40_internal.h" +#include "mrf24j40_registers.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define SPIDEV (dev->params.spi) +#define CSPIN (dev->params.cs_pin) + +static inline void getbus(mrf24j40_t *dev) +{ + spi_acquire(SPIDEV, CSPIN, SPI_MODE_0, dev->params.spi_clk); +} + +void mrf24j40_init(mrf24j40_t *dev) +{ + + mrf24j40_hardware_reset(dev); + +#if ENABLE_DEBUG + /* Check if MRF24J40 is available */ + uint8_t txmcr = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR); + if ((txmcr == 0xFF) || (txmcr == 0x00)) { + /* Write default value to TXMCR register */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_TXMCR, MRF24J40_TXMCR_MACMINBE1 | + MRF24J40_TXMCR_MACMINBE0 | + MRF24J40_TXMCR_CSMABF2); + txmcr = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR); + if (txmcr != (MRF24J40_TXMCR_MACMINBE1 | + MRF24J40_TXMCR_MACMINBE0 | + MRF24J40_TXMCR_CSMABF2)) { + DEBUG("[mrf24j40] Initialization failure, SPI interface communication failed\n"); + /* Return to prevents hangup later in the initialization */ + return; + } + } +#endif + + /* do a soft reset */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_SOFTRST, MRF24J40_SOFTRST_RSTPWR | + MRF24J40_SOFTRST_RSTBB | + MRF24J40_SOFTRST_RSTMAC ); + + /* flush RX FIFO */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_RXFLUSH, MRF24J40_RXFLUSH_RXFLUSH); + + /* Here starts init-process as described on MRF24J40 Manual Chap. 3.2 */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_PACON2, (MRF24J40_PACON2_TXONTS2 | + MRF24J40_PACON2_TXONTS1 | + MRF24J40_PACON2_FIFOEN)); + mrf24j40_reg_write_short(dev, MRF24J40_REG_TXSTBL, (MRF24J40_TXSTBL_RFSTBL3 | + MRF24J40_TXSTBL_RFSTBL0 | + MRF24J40_TXSTBL_MSIFS2 | + MRF24J40_TXSTBL_MSIFS0)); + mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON1, MRF24J40_RFCON1_VCOOPT1); + mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON2, MRF24J40_RFCON2_PLLEN); + mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON6, (MRF24J40_RFCON6_TXFIL | + MRF24J40_RFCON6_20MRECVR)); + mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON7, MRF24J40_RFCON7_SLPCLKSEL1 ); + mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON8, MRF24J40_RFCON8_RFVCO ); + mrf24j40_reg_write_long(dev, MRF24J40_REG_SLPCON1, (MRF24J40_SLPCON1_CLKOUTEN | + MRF24J40_SLPCON1_SLPCLKDIV0)); + mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG2, MRF25J40_BBREG2_CCAMODE1 ); + mrf24j40_reg_write_short(dev, MRF24J40_REG_CCAEDTH, 0x60); + mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG6, MRF24J40_BBREG6_RSSIMODE2 ); + + /* Enable immediate sleep mode */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE); + + /* set interrupt pin polarity, rising edge */ + mrf24j40_reg_write_long(dev, MRF24J40_REG_SLPCON0, MRF24J40_SLPCON0_INTEDGE ); + /* reset RF state machine */ + mrf24j40_reset_state_machine(dev); + + /* clear interrupts */ + mrf24j40_reg_read_short(dev, MRF24J40_REG_INTSTAT); + + /* mrf24j40_set_interrupts */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_INTCON, ~(MRF24J40_INTCON_RXIE | MRF24J40_INTCON_TXNIE)); +} + +uint8_t mrf24j40_reg_read_short(mrf24j40_t *dev, const uint8_t addr) +{ + char value; + + getbus(dev); + value = spi_transfer_reg(SPIDEV, CSPIN, MRF24J40_SHORT_ADDR_TRANS | + (addr << MRF24J40_ADDR_OFFSET) | + MRF24J40_ACCESS_READ, 0); + spi_release(SPIDEV); + return (uint8_t)value; +} + +void mrf24j40_reg_write_short(mrf24j40_t *dev, const uint8_t addr, const uint8_t value) +{ + getbus(dev); + spi_transfer_reg(SPIDEV, CSPIN , MRF24J40_SHORT_ADDR_TRANS | + (addr << MRF24J40_ADDR_OFFSET) | + MRF24J40_ACCESS_WRITE, value); + spi_release(SPIDEV); +} + +uint8_t mrf24j40_reg_read_long(mrf24j40_t *dev, const uint16_t addr) +{ + uint8_t reg1, reg2; + + reg1 = MRF24J40_LONG_ADDR_TRANS | (addr >> 3); + reg2 = (addr << 5) | MRF24J40_ACCESS_READ; + char value; + getbus(dev); + spi_transfer_byte(SPIDEV, CSPIN, true, reg1); + spi_transfer_byte(SPIDEV, CSPIN, true, reg2); + value = spi_transfer_byte(SPIDEV, CSPIN, false, 0); + spi_release(SPIDEV); + + return (uint8_t)value; +} + +void mrf24j40_reg_write_long(mrf24j40_t *dev, const uint16_t addr, const uint8_t value) +{ + uint8_t reg1, reg2; + + reg1 = MRF24J40_LONG_ADDR_TRANS | (addr >> 3); + reg2 = (addr << 5) | MRF24J40_ACCESS_WRITE_LNG; + getbus(dev); + spi_transfer_byte(SPIDEV, CSPIN, true, reg1); + spi_transfer_byte(SPIDEV, CSPIN, true, reg2); + spi_transfer_byte(SPIDEV, CSPIN, false, value); + spi_release(SPIDEV); +} + +void mrf24j40_tx_normal_fifo_read(mrf24j40_t *dev, const uint16_t offset, uint8_t *data, const size_t len) +{ + uint8_t reg1, reg2; + + reg1 = MRF24J40_LONG_ADDR_TRANS | (offset >> 3); + reg2 = (offset << 5) | MRF24J40_ACCESS_READ; + getbus(dev); + spi_transfer_byte(SPIDEV, CSPIN, true, reg1); + spi_transfer_byte(SPIDEV, CSPIN, true, reg2); + spi_transfer_bytes(SPIDEV, CSPIN, false, NULL, (char *)data, len); + spi_release(SPIDEV); +} + +void mrf24j40_tx_normal_fifo_write(mrf24j40_t *dev, + const uint16_t offset, + const uint8_t *data, + const size_t len) +{ + uint16_t addr; + uint8_t reg1; + uint8_t reg2; + + addr = offset; + + reg1 = MRF24J40_LONG_ADDR_TRANS | (addr >> 3); + reg2 = (addr << 5) | MRF24J40_ACCESS_WRITE_LNG; + + getbus(dev); + spi_transfer_byte(SPIDEV, CSPIN, true, reg1); + spi_transfer_byte(SPIDEV, CSPIN, true, reg2); + spi_transfer_bytes(SPIDEV, CSPIN, false, (char *)data, NULL, len); + spi_release(SPIDEV); +} + +void mrf24j40_rx_fifo_read(mrf24j40_t *dev, const uint16_t offset, uint8_t *data, const size_t len) +{ + uint16_t rx_addr; + + rx_addr = MRF24J40_RX_FIFO + offset; + + uint8_t reg1, reg2; + reg1 = MRF24J40_LONG_ADDR_TRANS | (rx_addr >> 3); + reg2 = (rx_addr << 5) | MRF24J40_ACCESS_READ; + getbus(dev); + spi_transfer_byte(SPIDEV, CSPIN, true, reg1); + spi_transfer_byte(SPIDEV, CSPIN, true, reg2); + spi_transfer_bytes(SPIDEV, CSPIN, false, NULL, (char *)data, len); + spi_release(SPIDEV); +} + +void mrf24j40_rx_fifo_write(mrf24j40_t *dev, const uint16_t offset, const uint8_t *data, const size_t len) +{ + uint16_t i; + + for (i = 0; i < len; i++) { + mrf24j40_reg_write_long(dev, i, data[i]); + } +} + +void mrf24j40_reset_tasks(mrf24j40_t *dev) +{ + dev->pending = MRF24J40_TASK_TX_DONE; +} + +void mrf24j40_update_tasks(mrf24j40_t *dev) +{ + if (dev->irq_flag) { + uint8_t newpending = 0; + uint8_t instat = 0; + + dev->irq_flag = 0; + instat = mrf24j40_reg_read_short(dev, MRF24J40_REG_INTSTAT); + /* check if TX done */ + if (instat & MRF24J40_INTSTAT_TXNIF) { + newpending |= MRF24J40_TASK_TX_DONE | MRF24J40_TASK_TX_READY; + /* transmit done, returning to configured idle state */ + mrf24j40_assert_sleep(dev); + } + if (instat & MRF24J40_INTSTAT_RXIF) { + newpending |= MRF24J40_TASK_RX_READY; + } + /* check if RX pending */ + dev->pending |= newpending; + } +} + + +void mrf24j40_hardware_reset(mrf24j40_t *dev) +{ + /* wake up from sleep in case radio is sleeping */ + mrf24j40_assert_awake(dev); + + /* trigger hardware reset */ + gpio_clear(dev->params.reset_pin); + /* Datasheet - Not specified */ + xtimer_usleep(MRF24J40_RESET_PULSE_WIDTH); + gpio_set(dev->params.reset_pin); + /* Datasheet - MRF24J40 ~2ms */ + xtimer_usleep(MRF24J40_RESET_DELAY); +} diff --git a/drivers/mrf24j40/mrf24j40_netdev.c b/drivers/mrf24j40/mrf24j40_netdev.c new file mode 100644 index 000000000000..7573950cc629 --- /dev/null +++ b/drivers/mrf24j40/mrf24j40_netdev.c @@ -0,0 +1,569 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * Copyright (C) 2017 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_mrf24j40 + * @{ + * + * @file + * @brief Netdev adaption for the MRF24J40 drivers + * + * @author Koen Zandberg + * @author Neo Nenaco + * + * @} + */ + +#include +#include +#include + +#include "net/eui64.h" +#include "net/ieee802154.h" +#include "net/netdev2.h" +#include "net/netdev2/ieee802154.h" + +#include "mrf24j40.h" +#include "mrf24j40_netdev.h" +#include "mrf24j40_internal.h" +#include "mrf24j40_registers.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define _MAX_MHR_OVERHEAD (25) + +static int _send(netdev2_t *netdev, const struct iovec *vector, unsigned count); +static int _recv(netdev2_t *netdev, void *buf, size_t len, void *info); +static int _init(netdev2_t *netdev); +static void _isr(netdev2_t *netdev); +static int _get(netdev2_t *netdev, netopt_t opt, void *val, size_t max_len); +static int _set(netdev2_t *netdev, netopt_t opt, void *val, size_t len); + +const netdev2_driver_t mrf24j40_driver = { + .send = _send, + .recv = _recv, + .init = _init, + .isr = _isr, + .get = _get, + .set = _set, +}; + +static void _irq_handler(void *arg) +{ + netdev2_t *dev = (netdev2_t *) arg; + + if (dev->event_callback) { + dev->event_callback(dev, NETDEV2_EVENT_ISR); + } + ((mrf24j40_t *)arg)->irq_flag = 1; +} + +static int _init(netdev2_t *netdev) +{ + mrf24j40_t *dev = (mrf24j40_t *)netdev; + + /* initialise GPIOs */ + spi_init_cs(dev->params.spi, dev->params.cs_pin); + gpio_init(dev->params.reset_pin, GPIO_OUT); + gpio_set(dev->params.reset_pin); + gpio_init_int(dev->params.int_pin, GPIO_IN, GPIO_RISING, _irq_handler, dev); + +#ifdef MODULE_NETSTATS_L2 + memset(&netdev->stats, 0, sizeof(netstats_t)); +#endif + /* reset device to default values and put it into RX state */ + mrf24j40_reset(dev); + return 0; +} + +static int _send(netdev2_t *netdev, const struct iovec *vector, unsigned count) +{ + mrf24j40_t *dev = (mrf24j40_t *)netdev; + const struct iovec *ptr = vector; + size_t len = 0; + + mrf24j40_tx_prepare(dev); + + /* load packet data into FIFO */ + for (int i = 0; i < count; i++, ptr++) { + /* current packet data + FCS too long */ + if ((len + ptr->iov_len + 2) > IEEE802154_FRAME_LEN_MAX) { + DEBUG("[mrf24j40] error: packet too large (%u byte) to be send\n", + (unsigned)len + 2); + return -EOVERFLOW; + } + +#ifdef MODULE_NETSTATS_L2 + netdev->stats.tx_bytes += len; +#endif + len = mrf24j40_tx_load(dev, ptr->iov_base, ptr->iov_len, len); + if (i == 0) { + dev->header_len = len; + } + + } + + /* send data out directly if pre-loading is disabled */ + if (!(dev->netdev.flags & MRF24J40_OPT_PRELOADING)) { + mrf24j40_tx_exec(dev); + } + /* return the number of bytes that were actually send out */ + return (int)len; + +} + +static int _recv(netdev2_t *netdev, void *buf, size_t len, void *info) +{ + mrf24j40_t *dev = (mrf24j40_t *)netdev; + uint8_t phr; + size_t pkt_len; + + /* Disable receiving while reading the RX fifo (datasheet sec. 3.11.4) */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG1, MRF24J40_BBREG1_RXDECINV ); + + /* get the size of the received packet */ + phr = mrf24j40_reg_read_long(dev, MRF24J40_RX_FIFO); + + pkt_len = (phr & 0x7f) - 2; + + /* just return length when buf == NULL */ + if (buf == NULL) { + return pkt_len; + } +#ifdef MODULE_NETSTATS_L2 + netdev->stats.rx_count++; + netdev->stats.rx_bytes += pkt_len; +#endif + /* not enough space in buf */ + if (pkt_len > len) { + DEBUG("[mrf24j40] No space in receive buffers\n"); + mrf24j40_reg_write_short(dev, MRF24J40_REG_RXFLUSH, MRF24J40_RXFLUSH_RXFLUSH); + /* Turn on reception of packets off the air */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG1, 0x00); + return -ENOBUFS; + } + /* copy payload */ + mrf24j40_rx_fifo_read(dev, 1, (uint8_t *)buf, pkt_len); + + if (info != NULL) { + netdev2_ieee802154_rx_info_t *radio_info = info; + /* Read LQI and RSSI values from the RX fifo */ + mrf24j40_rx_fifo_read(dev, phr + 1, &(radio_info->lqi), 1); + mrf24j40_rx_fifo_read(dev, phr + 2, &(radio_info->rssi), 1); + } + + /* Turn on reception of packets off the air */ + mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG1, 0x00); + return pkt_len; +} + +static netopt_state_t _get_state(mrf24j40_t *dev) +{ + if (!(dev->pending & MRF24J40_TASK_TX_DONE)) { + return NETOPT_STATE_TX; + } + if (dev->pending & MRF24J40_TASK_RX_READY) { + return NETOPT_STATE_RX; + } + switch (dev->state) { + case MRF24J40_PSEUDO_STATE_SLEEP: + return NETOPT_STATE_SLEEP; + } + return NETOPT_STATE_IDLE; +} + +static int _get(netdev2_t *netdev, netopt_t opt, void *val, size_t max_len) +{ + mrf24j40_t *dev = (mrf24j40_t *) netdev; + + if (netdev == NULL) { + return -ENODEV; + } + + int res; + switch (opt) { + case NETOPT_CHANNEL_PAGE: + if (max_len < sizeof(uint16_t)) { + res = -EOVERFLOW; + } + else { + ((uint8_t *)val)[1] = 0; + ((uint8_t *)val)[0] = 0; + res = sizeof(uint16_t); + } + break; + + case NETOPT_MAX_PACKET_SIZE: + if (max_len < sizeof(int16_t)) { + res = -EOVERFLOW; + } + else { + *((uint16_t *)val) = IEEE802154_FRAME_LEN_MAX - _MAX_MHR_OVERHEAD; + res = sizeof(uint16_t); + } + break; + + case NETOPT_STATE: + if (max_len < sizeof(netopt_state_t)) { + res = -EOVERFLOW; + } + else { + *((netopt_state_t *)val) = _get_state(dev); + res = sizeof(netopt_state_t); + } + break; + + case NETOPT_PRELOADING: + if (dev->netdev.flags & MRF24J40_OPT_PRELOADING) { + *((netopt_enable_t *)val) = NETOPT_ENABLE; + } + else { + *((netopt_enable_t *)val) = NETOPT_DISABLE; + } + res = sizeof(netopt_enable_t); + break; + + case NETOPT_PROMISCUOUSMODE: + if (dev->netdev.flags & MRF24J40_OPT_PROMISCUOUS) { + *((netopt_enable_t *)val) = NETOPT_ENABLE; + } + else { + *((netopt_enable_t *)val) = NETOPT_DISABLE; + } + res = sizeof(netopt_enable_t); + break; + + case NETOPT_RX_START_IRQ: + *((netopt_enable_t *)val) = + !!(dev->netdev.flags & MRF24J40_OPT_TELL_RX_START); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_RX_END_IRQ: + *((netopt_enable_t *)val) = + !!(dev->netdev.flags & MRF24J40_OPT_TELL_RX_END); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_TX_START_IRQ: + *((netopt_enable_t *)val) = + !!(dev->netdev.flags & MRF24J40_OPT_TELL_TX_START); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_TX_END_IRQ: + *((netopt_enable_t *)val) = + !!(dev->netdev.flags & MRF24J40_OPT_TELL_TX_END); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_CSMA: + *((netopt_enable_t *)val) = + !!(dev->netdev.flags & MRF24J40_OPT_CSMA); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_TX_POWER: + if (max_len < sizeof(int16_t)) { + res = -EOVERFLOW; + } + else { + *((uint16_t *)val) = mrf24j40_get_txpower(dev); + res = sizeof(uint16_t); + } + break; + + case NETOPT_RETRANS: + if (max_len < sizeof(uint8_t)) { + res = -EOVERFLOW; + } + else { + *((uint8_t *)val) = MRF24J40_MAX_FRAME_RETRIES; + res = sizeof(uint8_t); + } + break; + + case NETOPT_IS_CHANNEL_CLR: + if (mrf24j40_cca(dev)) { + *((netopt_enable_t *)val) = NETOPT_ENABLE; + } + else { + *((netopt_enable_t *)val) = NETOPT_DISABLE; + } + res = sizeof(netopt_enable_t); + break; + + case NETOPT_CSMA_RETRIES: + if (max_len < sizeof(uint8_t)) { + res = -EOVERFLOW; + } + else { + *((uint8_t *)val) = mrf24j40_get_csma_max_retries(dev); + res = sizeof(uint8_t); + } + break; + + case NETOPT_CCA_THRESHOLD: + if (max_len < sizeof(int8_t)) { + res = -EOVERFLOW; + } + else { + *((int8_t *)val) = mrf24j40_get_cca_threshold(dev); + res = sizeof(int8_t); + } + break; + + default: + /* try netdev2 settings */ + res = netdev2_ieee802154_get((netdev2_ieee802154_t *)netdev, opt, + val, max_len); + } + return res; +} + +static int _set_state(mrf24j40_t *dev, netopt_state_t state) +{ + switch (state) { + case NETOPT_STATE_SLEEP: + mrf24j40_set_state(dev, MRF24J40_PSEUDO_STATE_SLEEP); + break; + case NETOPT_STATE_IDLE: + mrf24j40_set_state(dev, MRF24J40_PSEUDO_STATE_IDLE); + break; + case NETOPT_STATE_TX: + if (dev->netdev.flags & MRF24J40_OPT_PRELOADING) { + mrf24j40_tx_exec(dev); + } + break; + case NETOPT_STATE_RESET: + mrf24j40_reset(dev); + break; + default: + return -ENOTSUP; + } + return sizeof(netopt_state_t); +} + +static int _set(netdev2_t *netdev, netopt_t opt, void *val, size_t len) +{ + mrf24j40_t *dev = (mrf24j40_t *) netdev; + int res = -ENOTSUP; + + if (dev == NULL) { + return -ENODEV; + } + + switch (opt) { + case NETOPT_ADDRESS: + if (len > sizeof(uint16_t)) { + res = -EOVERFLOW; + } + else { + mrf24j40_set_addr_short(dev, *((uint16_t *)val)); + /* don't set res to set netdev2_ieee802154_t::short_addr */ + } + break; + + case NETOPT_ADDRESS_LONG: + if (len > sizeof(uint64_t)) { + res = -EOVERFLOW; + } + else { + mrf24j40_set_addr_long(dev, *((uint64_t *)val)); + /* don't set res to set netdev2_ieee802154_t::long_addr */ + } + break; + + case NETOPT_NID: + if (len > sizeof(uint16_t)) { + res = -EOVERFLOW; + } + else { + mrf24j40_set_pan(dev, *((uint16_t *)val)); + /* 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 *)val)[0]; + if (chan < IEEE802154_CHANNEL_MIN || + chan > IEEE802154_CHANNEL_MAX || + dev->netdev.chan == chan) { + res = -EINVAL; + break; + } + mrf24j40_set_chan(dev, chan); + /* don't set res to set netdev2_ieee802154_t::chan */ + } + break; + + case NETOPT_CHANNEL_PAGE: + if (len != sizeof(uint16_t)) { + res = -EINVAL; + } + else { + uint8_t page = ((uint8_t *)val)[0]; + + /* mrf24j40 only supports page 0, no need to configure anything in the driver. */ + if (page != 0) { + res = -EINVAL; + } + else { + res = sizeof(uint16_t); + } + } + break; + + case NETOPT_TX_POWER: + if (len > sizeof(int16_t)) { + res = -EOVERFLOW; + } + else { + mrf24j40_set_txpower(dev, *((int16_t *)val)); + res = sizeof(uint16_t); + } + break; + + case NETOPT_STATE: + if (len > sizeof(netopt_state_t)) { + res = -EOVERFLOW; + } + else { + res = _set_state(dev, *((netopt_state_t *)val)); + } + break; + + case NETOPT_AUTOACK: + mrf24j40_set_option(dev, NETDEV2_IEEE802154_ACK_REQ, + ((bool *)val)[0]); + /* don't set res to set netdev2_ieee802154_t::flags */ + break; + + case NETOPT_PRELOADING: + mrf24j40_set_option(dev, MRF24J40_OPT_PRELOADING, + ((bool *)val)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_PROMISCUOUSMODE: + mrf24j40_set_option(dev, MRF24J40_OPT_PROMISCUOUS, + ((bool *)val)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_RX_START_IRQ: + mrf24j40_set_option(dev, MRF24J40_OPT_TELL_RX_START, + ((bool *)val)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_RX_END_IRQ: + mrf24j40_set_option(dev, MRF24J40_OPT_TELL_RX_END, + ((bool *)val)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_TX_START_IRQ: + mrf24j40_set_option(dev, MRF24J40_OPT_TELL_TX_START, + ((bool *)val)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_TX_END_IRQ: + mrf24j40_set_option(dev, MRF24J40_OPT_TELL_TX_END, + ((bool *)val)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_CSMA: + mrf24j40_set_option(dev, MRF24J40_OPT_CSMA, + ((bool *)val)[0]); + res = sizeof(netopt_enable_t); + break; + + case NETOPT_CSMA_RETRIES: + if ((len > sizeof(uint8_t)) || + (*((uint8_t *)val) > 5)) { + res = -EOVERFLOW; + } + else if (dev->netdev.flags & MRF24J40_OPT_CSMA) { + /* only set if CSMA is enabled */ + mrf24j40_set_csma_max_retries(dev, *((uint8_t *)val)); + res = sizeof(uint8_t); + } + break; + + case NETOPT_CCA_THRESHOLD: + if (len > sizeof(int8_t)) { + res = -EOVERFLOW; + } + else { + mrf24j40_set_cca_threshold(dev, *((int8_t *)val)); + res = sizeof(int8_t); + } + break; + + default: + break; + } + /* try netdev2 building flags */ + if (res == -ENOTSUP) { + res = netdev2_ieee802154_set((netdev2_ieee802154_t *)netdev, opt, + val, len); + } + return res; +} + +static void _isr(netdev2_t *netdev) +{ + mrf24j40_t *dev = (mrf24j40_t *) netdev; + /* update pending bits */ + mrf24j40_update_tasks(dev); + DEBUG("[mrf24j40] INTERRUPT (pending: %x),\n", dev->pending); + /* Transmit interrupt occured */ + if (dev->pending & MRF24J40_TASK_TX_READY) { + dev->pending &= ~(MRF24J40_TASK_TX_READY); + DEBUG("[mrf24j40] EVT - TX_END\n"); +#ifdef MODULE_NETSTATS_L2 + if (netdev->event_callback && (dev->netdev.flags & MRF24J40_OPT_TELL_TX_END)) { + uint8_t txstat = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXSTAT); + /* transmision failed */ + if (txstat & MRF24J40_TXSTAT_TXNSTAT) { + /* TX_NOACK - CCAFAIL */ + if (txstat & MRF24J40_TXSTAT_CCAFAIL) { + netdev->event_callback(netdev, NETDEV2_EVENT_TX_MEDIUM_BUSY); + DEBUG("[mrf24j40] TX_CHANNEL_ACCESS_FAILURE\n"); + } + /* check max retries */ + else if (txstat & MRF24J40_TXSTAT_MAX_FRAME_RETRIES) { + netdev->event_callback(netdev, NETDEV2_EVENT_TX_NOACK); + DEBUG("[mrf24j40] TX NO_ACK\n"); + } + } + else { + netdev->event_callback(netdev, NETDEV2_EVENT_TX_COMPLETE); + } + } +#endif + } + /* Receive interrupt occured */ + if (dev->pending & MRF24J40_TASK_RX_READY) { + DEBUG("[mrf24j40] EVT - RX_END\n"); + if ((dev->netdev.flags & MRF24J40_OPT_TELL_RX_END)) { + netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE); + } + dev->pending &= ~(MRF24J40_TASK_RX_READY); + } + DEBUG("[mrf24j40] END IRQ\n"); +} diff --git a/pkg/lwip/contrib/lwip.c b/pkg/lwip/contrib/lwip.c index aa45c1eb5089..88584c00eb36 100644 --- a/pkg/lwip/contrib/lwip.c +++ b/pkg/lwip/contrib/lwip.c @@ -28,6 +28,11 @@ #include "at86rf2xx_params.h" #endif +#ifdef MODULE_MRF24J40 +#include "mrf24j40.h" +#include "mrf24j40_params.h" +#endif + #include "lwip.h" #define ENABLE_DEBUG (0) @@ -41,6 +46,10 @@ #define LWIP_NETIF_NUMOF (sizeof(at86rf2xx_params) / sizeof(at86rf2xx_params[0])) #endif +#ifdef MODULE_MRF24J40 /* is mutual exclusive with above ifdef */ +#define LWIP_NETIF_NUMOF (sizeof(mrf24j40_params) / sizeof(mrf24j40_params[0])) +#endif + #ifdef LWIP_NETIF_NUMOF static struct netif netif[LWIP_NETIF_NUMOF]; #endif @@ -53,6 +62,10 @@ static netdev2_tap_t netdev2_taps[LWIP_NETIF_NUMOF]; static at86rf2xx_t at86rf2xx_devs[LWIP_NETIF_NUMOF]; #endif +#ifdef MODULE_MRF24J40 +static mrf24j40_t mrf24j40_devs[LWIP_NETIF_NUMOF]; +#endif + void lwip_bootstrap(void) { /* TODO: do for every eligable netdev2 */ @@ -66,6 +79,15 @@ void lwip_bootstrap(void) return; } } +#elif defined(MODULE_MRF24J40) + for (int i = 0; i < LWIP_NETIF_NUMOF; i++) { + mrf24j40_setup(&mrf24j40_devs[i], &mrf24j40_params[i]); + if (netif_add(&netif[i], &mrf24j40_devs[i], lwip_netdev2_init, + tcpip_6lowpan_input) == NULL) { + DEBUG("Could not add mrf24j40 device\n"); + return; + } + } #elif defined(MODULE_AT86RF2XX) for (int i = 0; i < LWIP_NETIF_NUMOF; i++) { at86rf2xx_setup(&at86rf2xx_devs[i], &at86rf2xx_params[i]); diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index dccd57f5d5b1..f09d7192edb5 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -182,6 +182,11 @@ void auto_init(void) auto_init_at86rf2xx(); #endif +#ifdef MODULE_MRF24J40 + extern void auto_init_mrf24j40(void); + auto_init_mrf24j40(); +#endif + #ifdef MODULE_CC2420 extern void auto_init_cc2420(void); auto_init_cc2420(); diff --git a/sys/auto_init/netif/auto_init_mrf24j40.c b/sys/auto_init/netif/auto_init_mrf24j40.c new file mode 100644 index 000000000000..4b1db6c39a6a --- /dev/null +++ b/sys/auto_init/netif/auto_init_mrf24j40.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2017 Neo Nenaco + * + * 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 auto_init_gnrc_netif + * @{ + * + * @file + * @brief Auto initialization for mrf24j40 network interfaces + * + * @author Neo Nenaco + */ + +#ifdef MODULE_MRF24J40 + +#include "board.h" +#include "net/gnrc/netdev2.h" +#include "net/gnrc/netdev2/ieee802154.h" +#include "net/gnrc.h" + +#include "mrf24j40.h" +#include "mrf24j40_params.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief Define stack parameters for the MAC layer thread + * @{ + */ +#define MRF24J40_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#ifndef MRF24J40_MAC_PRIO +#define MRF24J40_MAC_PRIO (GNRC_NETDEV2_MAC_PRIO) +#endif + +#define MRF24J40_NUM (sizeof(mrf24j40_params) / sizeof(mrf24j40_params[0])) + +static mrf24j40_t mrf24j40_devs[MRF24J40_NUM]; +static gnrc_netdev2_t gnrc_adpt[MRF24J40_NUM]; +static char _mrf24j40_stacks[MRF24J40_NUM][MRF24J40_MAC_STACKSIZE]; + +void auto_init_mrf24j40(void) +{ + for (unsigned i = 0; i < MRF24J40_NUM; i++) { + const mrf24j40_params_t *p = &mrf24j40_params[i]; + int res; + + DEBUG("Initializing MRF24J40 radio at SPI_%i\n", p->spi); + mrf24j40_setup(&mrf24j40_devs[i], (mrf24j40_params_t *) p); + res = gnrc_netdev2_ieee802154_init(&gnrc_adpt[i], + (netdev2_ieee802154_t *)&mrf24j40_devs[i]); + + if (res < 0) { + DEBUG("Error initializing MRF24J40 radio device!\n"); + } + else { + gnrc_netdev2_init(_mrf24j40_stacks[i], + MRF24J40_MAC_STACKSIZE, + MRF24J40_MAC_PRIO, + "mrf24j40", + &gnrc_adpt[i]); + } + } +} +#else +typedef int dont_be_pedantic; +#endif /* MODULE_MRF24J40 */ + +/** @} */