From 615e25f31900378505f687e7840a6a107ffb0893 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Sat, 6 Oct 2018 17:24:59 +0200 Subject: [PATCH 1/7] drivers: Removed driver for CC110x transceivers - Removed cc110x driver - Updated all makefiles - Kept both board specific configurations and support for it in RIOT's upper layers, so re-implementations don't need to start from zero --- boards/msba2/Makefile.dep | 4 - boards/msbiot/Makefile.dep | 4 - drivers/Makefile.dep | 12 - drivers/Makefile.include | 4 - drivers/cc110x/Makefile | 3 - drivers/cc110x/cc110x-defaultsettings.c | 100 ------ drivers/cc110x/cc110x-netdev.c | 239 ------------- drivers/cc110x/cc110x-rxtx.c | 327 ------------------ drivers/cc110x/cc110x-spi.c | 172 --------- drivers/cc110x/cc110x.c | 271 --------------- drivers/cc110x/gnrc_cc110x/Makefile | 1 - drivers/cc110x/gnrc_cc110x/gnrc_cc110x.c | 200 ----------- .../cc110x/include/cc110x-defaultsettings.h | 46 --- drivers/cc110x/include/cc110x-defines.h | 252 -------------- drivers/cc110x/include/cc110x-interface.h | 66 ---- drivers/cc110x/include/cc110x-internal.h | 212 ------------ drivers/cc110x/include/cc110x-netdev.h | 67 ---- drivers/cc110x/include/cc110x-spi.h | 116 ------- drivers/cc110x/include/cc110x_params.h | 79 ----- drivers/cc110x/include/gnrc_netif_cc110x.h | 35 -- drivers/include/cc110x.h | 136 -------- examples/default/Makefile | 17 +- examples/gnrc_border_router/Makefile | 17 +- examples/gnrc_minimal/Makefile | 17 +- examples/gnrc_networking/Makefile | 17 +- examples/nanocoap_server/Makefile | 17 +- sys/auto_init/auto_init.c | 5 - tests/gnrc_udp/Makefile | 17 +- 28 files changed, 36 insertions(+), 2417 deletions(-) delete mode 100644 drivers/cc110x/Makefile delete mode 100644 drivers/cc110x/cc110x-defaultsettings.c delete mode 100644 drivers/cc110x/cc110x-netdev.c delete mode 100644 drivers/cc110x/cc110x-rxtx.c delete mode 100644 drivers/cc110x/cc110x-spi.c delete mode 100644 drivers/cc110x/cc110x.c delete mode 100644 drivers/cc110x/gnrc_cc110x/Makefile delete mode 100644 drivers/cc110x/gnrc_cc110x/gnrc_cc110x.c delete mode 100644 drivers/cc110x/include/cc110x-defaultsettings.h delete mode 100644 drivers/cc110x/include/cc110x-defines.h delete mode 100644 drivers/cc110x/include/cc110x-interface.h delete mode 100644 drivers/cc110x/include/cc110x-internal.h delete mode 100644 drivers/cc110x/include/cc110x-netdev.h delete mode 100644 drivers/cc110x/include/cc110x-spi.h delete mode 100644 drivers/cc110x/include/cc110x_params.h delete mode 100644 drivers/cc110x/include/gnrc_netif_cc110x.h delete mode 100644 drivers/include/cc110x.h diff --git a/boards/msba2/Makefile.dep b/boards/msba2/Makefile.dep index 04ee7ff3eaa8..629c28a5432c 100644 --- a/boards/msba2/Makefile.dep +++ b/boards/msba2/Makefile.dep @@ -1,9 +1,5 @@ include $(RIOTBOARD)/common/msba2/Makefile.dep -ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE))) - USEMODULE += cc110x -endif - ifneq (,$(filter saul_default,$(USEMODULE))) USEMODULE += ltc4150 USEMODULE += sht11 diff --git a/boards/msbiot/Makefile.dep b/boards/msbiot/Makefile.dep index be08a394e325..ab057998f197 100644 --- a/boards/msbiot/Makefile.dep +++ b/boards/msbiot/Makefile.dep @@ -1,7 +1,3 @@ -# add driver for CC1101 sub-gigahertz transceiver as default netdev -ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE))) - USEMODULE += cc110x -endif # add support for LEDs and buttons as default saul devices ifneq (,$(filter saul_default,$(USEMODULE))) USEMODULE += saul_gpio diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 3d893f6017e1..25c3a8db8570 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -81,18 +81,6 @@ ifneq (,$(filter bm%280,$(USEMODULE))) USEMODULE += bmx280 endif -ifneq (,$(filter cc110x,$(USEMODULE))) - USEMODULE += ieee802154 - USEMODULE += luid - USEMODULE += xtimer - ifneq (,$(filter gnrc_netdev_default,$(USEMODULE))) - USEMODULE += gnrc_cc110x - endif - FEATURES_REQUIRED += periph_gpio - FEATURES_REQUIRED += periph_gpio_irq - FEATURES_REQUIRED += periph_spi -endif - ifneq (,$(filter cc2420,$(USEMODULE))) USEMODULE += xtimer USEMODULE += luid diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 6a6f9d5e45c2..27723b0e0925 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -42,10 +42,6 @@ ifneq (,$(filter bmx280,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bmx280/include endif -ifneq (,$(filter cc110x,$(USEMODULE))) - USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cc110x/include -endif - ifneq (,$(filter cc2420,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cc2420/include endif diff --git a/drivers/cc110x/Makefile b/drivers/cc110x/Makefile deleted file mode 100644 index a6588efa9cd4..000000000000 --- a/drivers/cc110x/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -DIRS += gnrc_cc110x - -include $(RIOTBASE)/Makefile.base diff --git a/drivers/cc110x/cc110x-defaultsettings.c b/drivers/cc110x/cc110x-defaultsettings.c deleted file mode 100644 index aded9ece1f52..000000000000 --- a/drivers/cc110x/cc110x-defaultsettings.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2013 INRIA - * 2015 Kaspar Schleiser - * - * 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_cc110x - * @{ - * - * @file - * @brief TI Chipcon CC110x default settings - * - * @author Thomas Hillebrandt - * @author Heiko Will - * @author Oliver Hahm - * @author Kaspar Schleiser - * @} - */ - -#include "board.h" -#include "cc110x.h" - -/** - * @brief PATABLE with available output powers - * @note If changed in size, adjust MAX_OUTPUT_POWER definition - * in CC110x interface -*/ -const char cc110x_default_pa_table[8] = { - 0x00, /*< -52 dBm */ - 0x0D, /*< -20 dBm */ - 0x34, /*< -10 dBm */ - 0x57, /*< - 5 dBm */ - 0x8E, /*< 0 dBm */ - 0x85, /*< + 5 dBm */ - 0xCC, /*< + 7 dBm */ - 0xC3 /*< +10 dBm */ -}; - -const char cc110x_default_base_freq[3] = { 0x21, 0x71, 0x7F }; - -/** - * @brief cc110x default settings - */ -const char cc110x_default_conf[] = { - 0x06, /* IOCFG2 */ - 0x2E, /* IOCFG1 */ - /* some boards use cc110x' GDO0 as clock source, so for those, we allow - * overriding of the corresponding setting, e.g., in board.h */ -#ifdef CC110X_IOCONF0_VAL - CC110X_IOCONF0_VAL, -#else - 0x0E, /* IOCFG0 */ -#endif - 0x07, /* FIFOTHR */ - 0x9B, /* SYNC1 */ - 0xAD, /* SYNC0 */ - 0xFF, /* PKTLEN */ - 0x06, /* PKTCTRL1 */ - 0x45, /* PKTCTRL0 (variable packet length) */ - 0xFF, /* ADDR */ - 0x00, /* CHANNR */ - 0x0F, /* FSCTRL1 */ - 0x00, /* FSCTRL0 */ - 0x21, /* FREQ2 */ - 0x71, /* FREQ1 */ - 0x7A, /* FREQ0 */ - 0x7C, /* MDMCFG4 */ - 0x7A, /* MDMCFG3 */ - 0x06, /* MDMCFG2 */ - 0xC0, /* MDMCFG1 */ - 0xF8, /* MDMCFG0 */ - 0x44, /* DEVIATN */ - 0x07, /* MCSM2 */ - 0x03, /* MCSM1 */ - 0x18, /* MCSM0 */ - 0x16, /* FOCCFG */ - 0x6C, /* BSCFG */ - 0x45, /* AGCCTRL2 */ - 0x40, /* AGCCTRL1 */ - 0x91, /* AGCCTRL0 */ - 0x87, /* WOREVT1 */ - 0x6B, /* WOREVT0 */ - 0xF8, /* WORCTRL */ - 0x56, /* FREND1 */ - 0x17, /* FREND0 */ - 0xEA, /* FSCAL3 */ - 0x2A, /* FSCAL2 */ - 0x00, /* FSCAL1 */ - 0x1F, /* FSCAL0 */ - 0x00 /* padding to 4 bytes */ -}; - -/** - * @brief The size of the configuration array for CC110X in bytes - * */ -const uint8_t cc110x_default_conf_size = sizeof(cc110x_default_conf); diff --git a/drivers/cc110x/cc110x-netdev.c b/drivers/cc110x/cc110x-netdev.c deleted file mode 100644 index b840389e22f8..000000000000 --- a/drivers/cc110x/cc110x-netdev.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * 2015 Kaspar Schleiser - * - * 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_cc110x - * @{ - * @file - * @brief Implementation of netdev interface for cc110x - * - * @author Fabian Nack - * @author Kaspar Schleiser - * @} - */ - -#include -#include -#include -#include - -#include "cc110x.h" -#include "cc110x-netdev.h" -#include "cc110x-internal.h" -#include "cc110x-interface.h" -#include "cc110x-defines.h" -#include "net/eui64.h" - -#include "periph/gpio.h" -#include "net/netdev.h" -#include "net/gnrc/nettype.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -static int _send(netdev_t *dev, const iolist_t *iolist) -{ - DEBUG("%s:%u\n", __func__, __LINE__); - - netdev_cc110x_t *netdev_cc110x = (netdev_cc110x_t *)dev; - cc110x_pkt_t *cc110x_pkt = iolist->iol_base; - - return cc110x_send(&netdev_cc110x->cc110x, cc110x_pkt); -} - -static int _recv(netdev_t *dev, void *buf, size_t len, void *info) -{ - DEBUG("%s:%u\n", __func__, __LINE__); - - cc110x_t *cc110x = &((netdev_cc110x_t*) dev)->cc110x; - - cc110x_pkt_t *cc110x_pkt = &cc110x->pkt_buf.packet; - if (cc110x_pkt->length > len) { - return -ENOSPC; - } - - memcpy(buf, (void*)cc110x_pkt, cc110x_pkt->length); - if (info != NULL) { - netdev_cc110x_rx_info_t *cc110x_info = info; - - cc110x_info->rssi = (int16_t)cc110x->pkt_buf.rssi/2 - CC110X_RSSI_OFFSET; - cc110x_info->lqi = cc110x->pkt_buf.lqi; - } - return cc110x_pkt->length; -} - -static inline int _get_iid(netdev_t *netdev, eui64_t *value, size_t max_len) -{ - cc110x_t *cc110x = &((netdev_cc110x_t*) netdev)->cc110x; - uint8_t *eui64 = (uint8_t*) value; - - if (max_len < sizeof(eui64_t)) { - return -EOVERFLOW; - } - - /* make address compatible to https://tools.ietf.org/html/rfc6282#section-3.2.2*/ - memset(eui64, 0, sizeof(eui64_t)); - eui64[3] = 0xff; - eui64[4] = 0xfe; - eui64[7] = cc110x->radio_address; - - return sizeof(eui64_t); -} - -static int _get(netdev_t *dev, netopt_t opt, void *value, size_t value_len) -{ - cc110x_t *cc110x = &((netdev_cc110x_t*) dev)->cc110x; - - switch (opt) { - case NETOPT_DEVICE_TYPE: - assert(value_len == 2); - *((uint16_t *) value) = NETDEV_TYPE_CC110X; - return 2; -#ifdef MODULE_GNRC_NETIF - case NETOPT_PROTO: - assert(value_len == sizeof(gnrc_nettype_t)); - *((gnrc_nettype_t *)value) = cc110x->proto; - return sizeof(gnrc_nettype_t); -#endif - case NETOPT_CHANNEL: - assert(value_len > 1); - *((uint16_t *)value) = (uint16_t)cc110x->radio_channel; - return sizeof(uint16_t); - case NETOPT_ADDRESS: - assert(value_len > 0); - *((uint8_t *)value) = cc110x->radio_address; - return sizeof(uint8_t); - case NETOPT_MAX_PDU_SIZE: - assert(value_len > 0); - *((uint16_t *)value) = CC110X_PACKET_LENGTH - CC110X_L2_HDR_SIZE; - return sizeof(uint16_t); - case NETOPT_IPV6_IID: - return _get_iid(dev, value, value_len); - case NETOPT_ADDR_LEN: - case NETOPT_SRC_LEN: - *((uint16_t *)value) = sizeof(cc110x->radio_address); - return sizeof(uint16_t); - default: - break; - } - - return -ENOTSUP; -} - -static int _set(netdev_t *dev, netopt_t opt, const void *value, size_t value_len) -{ - cc110x_t *cc110x = &((netdev_cc110x_t*) dev)->cc110x; - - switch (opt) { - case NETOPT_CHANNEL: - { - const uint16_t *arg = value; - uint8_t channel = (uint8_t)(*arg); - #if CC110X_MIN_CHANNR - if (channel < CC110X_MIN_CHANNR) { - return -EINVAL; - } - #endif /* CC110X_MIN_CHANNR */ - if (channel > CC110X_MAX_CHANNR) { - return -EINVAL; - } - if (cc110x_set_channel(cc110x, channel) == -1) { - return -EINVAL; - } - return sizeof(uint16_t); - } - case NETOPT_ADDRESS: - if (value_len < 1) { - return -EINVAL; - } - if (!cc110x_set_address(cc110x, *(const uint8_t*)value)) { - return -EINVAL; - } - return sizeof(uint8_t); -#ifdef MODULE_GNRC_NETIF - case NETOPT_PROTO: - if (value_len != sizeof(gnrc_nettype_t)) { - return -EINVAL; - } - else { - cc110x->proto = (gnrc_nettype_t) value; - return sizeof(gnrc_nettype_t); - } - break; -#endif - default: - return -ENOTSUP; - } - - return 0; -} - -static void _netdev_cc110x_isr(void *arg) -{ - netdev_t *netdev = (netdev_t*) arg; - netdev->event_callback(netdev, NETDEV_EVENT_ISR); -} - -static void _netdev_cc110x_rx_callback(void *arg) -{ - netdev_t *netdev = (netdev_t*) arg; - cc110x_t *cc110x = &((netdev_cc110x_t*) arg)->cc110x; - gpio_irq_disable(cc110x->params.gdo2); - netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE); -} - -static void _isr(netdev_t *dev) -{ - cc110x_t *cc110x = &((netdev_cc110x_t*) dev)->cc110x; - cc110x_isr_handler(cc110x, _netdev_cc110x_rx_callback, (void*)dev); -} - -static int _init(netdev_t *dev) -{ - DEBUG("%s:%u\n", __func__, __LINE__); - - cc110x_t *cc110x = &((netdev_cc110x_t*) dev)->cc110x; - - gpio_init_int(cc110x->params.gdo2, GPIO_IN, GPIO_BOTH, - &_netdev_cc110x_isr, (void*)dev); - - gpio_set(cc110x->params.gdo2); - gpio_irq_disable(cc110x->params.gdo2); - - /* Switch to RX mode */ - cc110x_rd_set_mode(cc110x, RADIO_MODE_ON); - - return 0; -} - -const netdev_driver_t netdev_cc110x_driver = { - .send=_send, - .recv=_recv, - .init=_init, - .get=_get, - .set=_set, - .isr=_isr -}; - -int netdev_cc110x_setup(netdev_cc110x_t *netdev_cc110x, const cc110x_params_t *params) -{ - DEBUG("netdev_cc110x_setup()\n"); - netdev_cc110x->netdev.driver = &netdev_cc110x_driver; - - /* set default protocol */ -#ifdef MODULE_GNRC_NETIF -# ifdef MODULE_GNRC_SIXLOWPAN - netdev_cc110x->cc110x.proto = GNRC_NETTYPE_SIXLOWPAN; -# else - netdev_cc110x->cc110x.proto = GNRC_NETTYPE_UNDEF; -# endif -#endif - - return cc110x_setup(&netdev_cc110x->cc110x, params); -} diff --git a/drivers/cc110x/cc110x-rxtx.c b/drivers/cc110x/cc110x-rxtx.c deleted file mode 100644 index 04cc8df5c461..000000000000 --- a/drivers/cc110x/cc110x-rxtx.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2013 INRIA - * - * 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_cc110x - * @{ - * @file - * @brief Functions for packet reception and transmission on cc110x devices - * - * @author Oliver Hahm - * @author Fabian Nack - * @author Kaspar Schleiser - * @} - */ - -#include -#include -#include - -#include "cc110x.h" -#include "cc110x-spi.h" -#include "cc110x-internal.h" -#include "cc110x-interface.h" -#include "cc110x-defines.h" - -#include "periph/gpio.h" -#include "irq.h" - -#include "kernel_types.h" -#include "msg.h" - -#include "cpu_conf.h" -#include "cpu.h" - -#ifdef MODULE_OD -#include "od.h" -#endif - -#include "log.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -const char *cc110x_state_to_text(uint8_t state) -{ - switch (state){ - case RADIO_IDLE: - return "idle"; - case RADIO_TX_BUSY: - return "tx busy"; - case RADIO_RX: - return "rx"; - case RADIO_RX_BUSY: - return "rx busy"; - case RADIO_PWD: - return "pwd"; - case RADIO_UNKNOWN: - return "unknown"; - } - return "invalid"; -} - -static void _rx_abort(cc110x_t *dev) -{ - gpio_irq_disable(dev->params.gdo2); - - cc110x_strobe(dev, CC110X_SIDLE); /* Switch to IDLE (should already be)... */ - cc110x_strobe(dev, CC110X_SFRX); /* ...for flushing the RX FIFO */ - - cc110x_switch_to_rx(dev); -} - -static void _rx_start(cc110x_t *dev) -{ - dev->radio_state = RADIO_RX_BUSY; - - cc110x_pkt_buf_t *pkt_buf = &dev->pkt_buf; - pkt_buf->pos = 0; - - gpio_irq_disable(dev->params.gdo2); - cc110x_write_reg(dev, CC110X_IOCFG2, - CC110X_GDO_HIGH_ON_RX_FIFO_FILLED_OR_PKT_END); - gpio_irq_enable(dev->params.gdo2); -} - -static void _rx_read_data(cc110x_t *dev, void(*callback)(void*), void*arg) -{ - int fifo = cc110x_get_reg_robust(dev, 0xfb); - - if (fifo & RXFIFO_OVERFLOW) { - DEBUG("%s:%s:%u rx overflow\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - _rx_abort(dev); - return; - } - - if (!fifo) { - gpio_irq_enable(dev->params.gdo2); - return; - } - - cc110x_pkt_buf_t *pkt_buf = &dev->pkt_buf; - if (!pkt_buf->pos) { - pkt_buf->pos = 1; - pkt_buf->packet.length = cc110x_read_reg(dev, CC110X_RXFIFO); - - /* Possible packet received, RX -> IDLE (0.1 us) */ - dev->cc110x_statistic.packets_in++; - } - - int left = pkt_buf->packet.length+1 - pkt_buf->pos; - - /* if the fifo doesn't contain the rest of the packet, - * leav at least one byte as per spec sheet. */ - int to_read = (fifo < left) ? (fifo-1) : fifo; - if (to_read > left) { - to_read = left; - } - - if (to_read) { - cc110x_readburst_reg(dev, CC110X_RXFIFO, - ((char *)&pkt_buf->packet)+pkt_buf->pos, to_read); - pkt_buf->pos += to_read; - } - - if (to_read == left) { - uint8_t status[2]; - /* full packet received. */ - /* Read the 2 appended status bytes (status[0] = RSSI, status[1] = LQI) */ - cc110x_readburst_reg(dev, CC110X_RXFIFO, (char *)status, 2); - - /* Store RSSI value of packet */ - pkt_buf->rssi = status[I_RSSI]; - - /* Bit 0-6 of LQI indicates the link quality (LQI) */ - pkt_buf->lqi = status[I_LQI] & LQI_EST; - - /* MSB of LQI is the CRC_OK bit */ - int crc_ok = (status[I_LQI] & CRC_OK) >> 7; - - if (crc_ok) { - LOG_DEBUG("cc110x: received packet from=%u to=%u payload len=%u\n", - (unsigned)pkt_buf->packet.phy_src, - (unsigned)pkt_buf->packet.address, - pkt_buf->packet.length - CC110X_L2_HDR_SIZE); - /* let someone know that we've got a packet */ - callback(arg); - - cc110x_switch_to_rx(dev); - } - else { - DEBUG("%s:%s:%u crc-error\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - dev->cc110x_statistic.packets_in_crc_fail++; -#if defined(MODULE_OD) && ENABLE_DEBUG - od_hex_dump(pkt_buf->packet.data, - pkt_buf->packet.length - CC110X_L2_HDR_SIZE, - OD_WIDTH_DEFAULT); -#endif - _rx_abort(dev); - } - } -} - -static void _rx_continue(cc110x_t *dev, void(*callback)(void*), void*arg) -{ - if (dev->radio_state != RADIO_RX_BUSY) { - DEBUG("%s:%s:%u _rx_continue in invalid state\n", RIOT_FILE_RELATIVE, - __func__, __LINE__); - _rx_abort(dev); - return; - } - - gpio_irq_disable(dev->params.gdo2); - - do { - _rx_read_data(dev, callback, arg); - } while (gpio_read(dev->params.gdo2)); -} - -static void _tx_abort(cc110x_t *dev) -{ - cc110x_switch_to_rx(dev); -} - -static void _tx_continue(cc110x_t *dev) -{ - gpio_irq_disable(dev->params.gdo2); - - cc110x_pkt_t *pkt = &dev->pkt_buf.packet; - int size = pkt->length + 1; - int left = size - dev->pkt_buf.pos; - - if (!left) { - dev->cc110x_statistic.raw_packets_out++; - - LOG_DEBUG("cc110x: packet successfully sent.\n"); - - cc110x_switch_to_rx(dev); - return; - } - - int fifo = CC110X_FIFO_LENGTH - cc110x_get_reg_robust(dev, 0xfa); - - if (fifo & TXFIFO_UNDERFLOW) { - DEBUG("%s:%s:%u tx underflow!\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - _tx_abort(dev); - return; - } - - if (!fifo) { - DEBUG("%s:%s:%u fifo full!?\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - _tx_abort(dev); - return; - } - - int to_send = left > fifo ? fifo : left; - - /* Write packet into TX FIFO */ - cc110x_writeburst_reg(dev, CC110X_TXFIFO, ((char *)pkt)+dev->pkt_buf.pos, to_send); - dev->pkt_buf.pos += to_send; - - if (left == size) { - /* Switch to TX mode */ - cc110x_strobe(dev, CC110X_STX); - } - - if (to_send < left) { - /* set GDO2 to 0x2 -> will deassert at TX FIFO below threshold */ - gpio_irq_enable(dev->params.gdo2); - cc110x_write_reg(dev, CC110X_IOCFG2, - CC110X_GDO_LOW_ON_TX_FIFO_BELOW_THRESHOLD); - } - else { - /* set GDO2 to 0x6 -> will deassert at packet end */ - cc110x_write_reg(dev, CC110X_IOCFG2, CC110X_GDO_HIGH_ON_SYNC_WORD); - gpio_irq_enable(dev->params.gdo2); - } -} - -void cc110x_isr_handler(cc110x_t *dev, void(*callback)(void*), void*arg) -{ - switch (dev->radio_state) { - case RADIO_RX: - if (gpio_read(dev->params.gdo2)) { - _rx_start(dev); - } - else { - DEBUG("cc110x_isr_handler((): isr handled too slow?\n"); - _rx_abort(dev); - } - break; - case RADIO_RX_BUSY: - _rx_continue(dev, callback, arg); - break; - case RADIO_TX_BUSY: - if (!gpio_read(dev->params.gdo2)) { - _tx_continue(dev); - } - else { - DEBUG("cc110x_isr_handler() RADIO_TX_BUSY + GDO2\n"); - } - break; - default: - DEBUG("%s:%s:%u: unhandled mode\n", RIOT_FILE_RELATIVE, - __func__, __LINE__); - } -} - -int cc110x_send(cc110x_t *dev, cc110x_pkt_t *packet) -{ - DEBUG("cc110x: snd pkt to %u payload_length=%u\n", - (unsigned)packet->address, - (unsigned)packet->length - CC110X_L2_HDR_SIZE); - unsigned size; - - switch (dev->radio_state) { - case RADIO_RX_BUSY: - case RADIO_TX_BUSY: - DEBUG("cc110x: invalid state for sending: %s\n", - cc110x_state_to_text(dev->radio_state)); - return -EAGAIN; - } - - /* - * Number of bytes to send is: - * length of phy payload (packet->length) - * + size of length field (1 byte) - */ - size = packet->length + 1; - - if (size > CC110X_PACKET_LENGTH) { - DEBUG("%s:%s:%u trying to send oversized packet\n", - RIOT_FILE_RELATIVE, __func__, __LINE__); - return -ENOSPC; - } - - /* set source address */ - packet->phy_src = dev->radio_address; - - /* Disable RX interrupt */ - gpio_irq_disable(dev->params.gdo2); - dev->radio_state = RADIO_TX_BUSY; - -#ifdef MODULE_CC110X_HOOKS - cc110x_hook_tx(); -#endif - - cc110x_write_reg(dev, CC110X_IOCFG2, - CC110X_GDO_LOW_ON_TX_FIFO_BELOW_THRESHOLD); - - /* Put CC110x in IDLE mode to flush the FIFO */ - cc110x_strobe(dev, CC110X_SIDLE); - /* Flush TX FIFO to be sure it is empty */ - cc110x_strobe(dev, CC110X_SFTX); - - memcpy((char*)&dev->pkt_buf.packet, packet, size); - dev->pkt_buf.pos = 0; - - _tx_continue(dev); - - return (int)size; -} diff --git a/drivers/cc110x/cc110x-spi.c b/drivers/cc110x/cc110x-spi.c deleted file mode 100644 index abb1920f12db..000000000000 --- a/drivers/cc110x/cc110x-spi.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2015 Kaspar Schleiser - * - * 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_cc110x - * @{ - * - * @file - * @brief TI Chipcon CC110x spi driver - * - * @author Thomas Hillebrandt - * @author Heiko Will - * @author Fabian Nack - * @author Joakim Gebart - * @author Kaspar Schleiser - * @} - */ - -#include - -#include "cc110x.h" -#include "cc110x-spi.h" -#include "cc110x-internal.h" -#include "cc110x-defines.h" - -#include "periph/gpio.h" -#include "periph/spi.h" - -#include "xtimer.h" - -#define SPI_CLK SPI_CLK_5MHZ -#define SPI_MODE SPI_MODE_0 - -/********************************************************************** - * CC110x spi access - **********************************************************************/ - -static inline void lock(cc110x_t *dev) -{ - spi_acquire(dev->params.spi, dev->params.cs, SPI_MODE, SPI_CLK); -} - -void cc110x_cs(cc110x_t *dev) -{ - volatile int retry_count = 0; - /* Switch MISO/GDO1 to GPIO input mode */ -#ifndef GPIO_READS_SPI_PINS - gpio_init(dev->params.gdo1, GPIO_IN); -#endif - /* CS to low */ - gpio_clear(dev->params.cs); - /* Wait for SO to go low (voltage regulator - * has stabilized and the crystal is running) */ - while (gpio_read(dev->params.gdo1)) { - /* Wait ~500us and try again */ - xtimer_usleep(CS_SO_WAIT_TIME); - - if (gpio_read(dev->params.gdo1)) { - retry_count++; - - if (retry_count > CC110X_GDO1_LOW_RETRY) { - puts("[CC110X spi] fatal error\n"); - break; - } - - gpio_set(dev->params.cs); - gpio_clear(dev->params.cs); - } - } - /* Switch MISO/GDO1 to spi mode */ -#ifndef GPIO_READS_SPI_PINS - spi_init_pins(dev->params.spi); -#endif -} - -void cc110x_writeburst_reg(cc110x_t *dev, uint8_t addr, const char *src, uint8_t count) -{ - lock(dev); - cc110x_cs(dev); - spi_transfer_regs(dev->params.spi, SPI_CS_UNDEF, - (addr | CC110X_WRITE_BURST), src, NULL, count); - gpio_set(dev->params.cs); - spi_release(dev->params.spi); -} - -void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t count) -{ - int i = 0; - lock(dev); - cc110x_cs(dev); - spi_transfer_byte(dev->params.spi, SPI_CS_UNDEF, false, - (addr | CC110X_READ_BURST)); - while (i < count) { - buffer[i] = (char)spi_transfer_byte(dev->params.spi, SPI_CS_UNDEF, - false, CC110X_NOBYTE); - i++; - } - gpio_set(dev->params.cs); - spi_release(dev->params.spi); -} - -void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value) -{ - lock(dev); - cc110x_cs(dev); - spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, addr, value); - gpio_set(dev->params.cs); - spi_release(dev->params.spi); -} - -uint8_t cc110x_read_reg(cc110x_t *dev, uint8_t addr) -{ - uint8_t result; - lock(dev); - cc110x_cs(dev); - result = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, - (addr | CC110X_READ_SINGLE), CC110X_NOBYTE); - gpio_set(dev->params.cs); - spi_release(dev->params.spi); - return result; -} - -uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr) -{ - uint8_t result; - lock(dev); - cc110x_cs(dev); - result = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, - (addr | CC110X_READ_BURST), CC110X_NOBYTE); - gpio_set(dev->params.cs); - spi_release(dev->params.spi); - return (uint8_t) result; -} - -uint8_t cc110x_get_reg_robust(cc110x_t *dev, uint8_t addr) -{ - uint8_t res1, res2; - lock(dev); - cc110x_cs(dev); - do { - res1 = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, - (addr | CC110X_READ_BURST), CC110X_NOBYTE); - res2 = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, - (addr | CC110X_READ_BURST), CC110X_NOBYTE); - } while (res1 != res2); - gpio_set(dev->params.cs); - spi_release(dev->params.spi); - return res1; -} - -uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c) -{ -#ifdef CC110X_DONT_RESET - if (c == CC110X_SRES) { - return 0; - } -#endif - - uint8_t result; - lock(dev); - cc110x_cs(dev); - result = spi_transfer_byte(dev->params.spi, SPI_CS_UNDEF, false, c); - gpio_set(dev->params.cs); - spi_release(dev->params.spi); - return result; -} diff --git a/drivers/cc110x/cc110x.c b/drivers/cc110x/cc110x.c deleted file mode 100644 index 8230f948734b..000000000000 --- a/drivers/cc110x/cc110x.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2013 INRIA - * Copyright (C) 2015 Kaspar Schleiser - * - * 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_cc110x - * @{ - * @file - * @brief Basic functionality of cc110x driver - * - * @author Oliver Hahm - * @author Fabian Nack - * @author Kaspar Schleiser - * @} - */ - -#include "luid.h" -#include "board.h" -#include "periph/gpio.h" -#include "periph/spi.h" -#include "xtimer.h" -#include "cpu.h" -#include "log.h" - -#include "cc110x.h" -#include "cc110x-defaultsettings.h" -#include "cc110x-defines.h" -#include "cc110x-interface.h" -#include "cc110x-internal.h" -#include "cc110x-spi.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -/* Internal function prototypes */ -#ifndef CC110X_DONT_RESET -static void _reset(cc110x_t *dev); -static void _power_up_reset(cc110x_t *dev); -#endif - -int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params) -{ - DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - -#ifdef MODULE_CC110X_HOOKS - cc110x_hooks_init(); -#endif - - dev->params = *params; - - /* Configure chip-select */ - spi_init_cs(dev->params.spi, dev->params.cs); - - /* Configure GDO1 */ - gpio_init(dev->params.gdo1, GPIO_IN); - -#ifndef CC110X_DONT_RESET - /* reset device*/ - _power_up_reset(dev); -#endif - - /* set default state */ - dev->radio_state = RADIO_IDLE; - - /* Write configuration to configuration registers */ - cc110x_writeburst_reg(dev, 0x00, cc110x_default_conf, cc110x_default_conf_size); - - /* Write PATABLE (power settings) */ - cc110x_writeburst_reg(dev, CC110X_PATABLE, CC110X_DEFAULT_PATABLE, 8); - - /* set base frequency */ - cc110x_set_base_freq_raw(dev, CC110X_DEFAULT_FREQ); - - /* Set default channel number */ - cc110x_set_channel(dev, CC110X_DEFAULT_CHANNEL); - - /* set default node id */ - uint8_t addr; - luid_get(&addr, 1); - cc110x_set_address(dev, addr); - - LOG_INFO("cc110x: initialized with address=%u and channel=%i\n", - (unsigned)dev->radio_address, - dev->radio_channel); - - return 0; -} - -uint8_t cc110x_set_address(cc110x_t *dev, uint8_t address) -{ - DEBUG("%s:%s:%u setting address %u\n", RIOT_FILE_RELATIVE, __func__, - __LINE__, (unsigned)address); - if (!(address < MIN_UID)) { - if (dev->radio_state != RADIO_UNKNOWN) { - cc110x_write_register(dev, CC110X_ADDR, address); - dev->radio_address = address; - return address; - } - } - - return 0; -} - -void cc110x_set_base_freq_raw(cc110x_t *dev, const char* freq_array) -{ -#if ENABLE_DEBUG == 1 - uint8_t _tmp[] = { freq_array[2], freq_array[1], freq_array[0], 0x00}; - uint32_t *FREQ = (uint32_t*) _tmp; - - DEBUG("cc110x_set_base_freq_raw(): setting base frequency to %uHz\n", - (26000000>>16) * (unsigned)(*FREQ)); -#endif - cc110x_writeburst_reg(dev, CC110X_FREQ2, freq_array, 3); -} - -void cc110x_set_monitor(cc110x_t *dev, uint8_t mode) -{ - DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - - cc110x_write_register(dev, CC110X_PKTCTRL1, mode ? 0x04 : 0x06); -} - -void cc110x_setup_rx_mode(cc110x_t *dev) -{ - DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - - /* Stay in RX mode until end of packet */ - cc110x_write_reg(dev, CC110X_MCSM2, 0x07); - cc110x_switch_to_rx(dev); -} - -void cc110x_switch_to_rx(cc110x_t *dev) -{ - DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - -#ifdef MODULE_CC110X_HOOKS - cc110x_hook_rx(); -#endif - - gpio_irq_disable(dev->params.gdo2); - - /* flush RX fifo */ - cc110x_strobe(dev, CC110X_SIDLE); - cc110x_strobe(dev, CC110X_SFRX); - - dev->radio_state = RADIO_RX; - - cc110x_write_reg(dev, CC110X_IOCFG2, CC110X_GDO_HIGH_ON_SYNC_WORD); - cc110x_strobe(dev, CC110X_SRX); - - gpio_irq_enable(dev->params.gdo2); -} - -void cc110x_wakeup_from_rx(cc110x_t *dev) -{ - if (dev->radio_state != RADIO_RX) { - return; - } - - LOG_DEBUG("cc110x: switching to idle mode\n"); - - cc110x_strobe(dev, CC110X_SIDLE); - dev->radio_state = RADIO_IDLE; -} - -void cc110x_switch_to_pwd(cc110x_t *dev) -{ - LOG_DEBUG("cc110x: switching to powerdown mode\n"); - cc110x_wakeup_from_rx(dev); - cc110x_strobe(dev, CC110X_SPWD); - dev->radio_state = RADIO_PWD; - -#ifdef MODULE_CC110X_HOOKS - cc110x_hook_off(); -#endif -} - -#ifndef MODULE_CC110X_HOOKS -int16_t cc110x_set_channel(cc110x_t *dev, uint8_t channr) -{ - DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - - if (channr > MAX_CHANNR) { - return -1; - } - - cc110x_write_register(dev, CC110X_CHANNR, channr * 10); - dev->radio_channel = channr; - - return channr; -} -#endif - -#ifndef CC110X_DONT_RESET -static void _reset(cc110x_t *dev) -{ - DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - cc110x_wakeup_from_rx(dev); - cc110x_cs(dev); - cc110x_strobe(dev, CC110X_SRES); - xtimer_usleep(100); -} - -static void _power_up_reset(cc110x_t *dev) -{ - DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - gpio_set(dev->params.cs); - gpio_clear(dev->params.cs); - gpio_set(dev->params.cs); - xtimer_usleep(RESET_WAIT_TIME); - _reset(dev); -} -#endif - -void cc110x_write_register(cc110x_t *dev, uint8_t r, uint8_t value) -{ - /* Save old radio state */ - uint8_t old_state = dev->radio_state; - - /* Wake up from RX (no effect if in other mode) */ - cc110x_wakeup_from_rx(dev); - cc110x_write_reg(dev, r, value); - - /* Have to put radio back to RX if old radio state - * was RX, otherwise no action is necessary */ - if (old_state == RADIO_RX) { - cc110x_switch_to_rx(dev); - } -} - -int cc110x_rd_set_mode(cc110x_t *dev, int mode) -{ - DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__); - - int result; - - /* Get current radio mode */ - if ((dev->radio_state == RADIO_UNKNOWN) || (dev->radio_state == RADIO_PWD)) { - result = RADIO_MODE_OFF; - } - else { - result = RADIO_MODE_ON; - } - - switch(mode) { - case RADIO_MODE_ON: - LOG_DEBUG("cc110x: switching to RX mode\n"); - cc110x_setup_rx_mode(dev); /* Set chip to desired mode */ - break; - - case RADIO_MODE_OFF: - gpio_irq_disable(dev->params.gdo2); /* Disable interrupts */ - cc110x_switch_to_pwd(dev); /* Set chip to power down mode */ - break; - - case RADIO_MODE_GET: - /* do nothing, just return current mode */ - default: - /* do nothing */ - break; - } - - /* Return previous mode */ - return result; -} diff --git a/drivers/cc110x/gnrc_cc110x/Makefile b/drivers/cc110x/gnrc_cc110x/Makefile deleted file mode 100644 index 48422e909a47..000000000000 --- a/drivers/cc110x/gnrc_cc110x/Makefile +++ /dev/null @@ -1 +0,0 @@ -include $(RIOTBASE)/Makefile.base diff --git a/drivers/cc110x/gnrc_cc110x/gnrc_cc110x.c b/drivers/cc110x/gnrc_cc110x/gnrc_cc110x.c deleted file mode 100644 index 38e786583e9b..000000000000 --- a/drivers/cc110x/gnrc_cc110x/gnrc_cc110x.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2015 Kaspar Schleiser - * - * 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. - */ - -#include - -#include - -#include "net/netdev.h" -#include "net/gnrc.h" -#include "cc110x.h" -#include "cc110x-netdev.h" -#include "net/gnrc/netif.h" -#include "od.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) -{ - cc110x_pkt_t cc110x_pkt; - netdev_t *dev = netif->dev; - netdev_cc110x_t *netdev_cc110x = (netdev_cc110x_t *) dev; - cc110x_t *cc110x = &netdev_cc110x->cc110x; - - assert(pkt != NULL); - assert(dev->driver == &netdev_cc110x_driver); - - gnrc_netif_hdr_t *netif_hdr; - gnrc_pktsnip_t *payload; - - payload = pkt->next; - - if (pkt->type != GNRC_NETTYPE_NETIF) { - DEBUG("gnrc_cc110x: First header was not generic netif header\n"); - gnrc_pktbuf_release(pkt); - return -EBADMSG; - } - - netif_hdr = (gnrc_netif_hdr_t *) pkt->data; - - /* set up header */ - if (netif_hdr->src_l2addr_len == 1) { - uint8_t *_src_addr = gnrc_netif_hdr_get_src_addr(netif_hdr); - cc110x_pkt.phy_src = *_src_addr; - } - else { - cc110x_pkt.phy_src = cc110x->radio_address; - } - - if (netif_hdr->flags & (GNRC_NETIF_HDR_FLAGS_BROADCAST | - GNRC_NETIF_HDR_FLAGS_MULTICAST)) { - cc110x_pkt.address = 0; - } - else { - uint8_t *_dst_addr = gnrc_netif_hdr_get_dst_addr(netif_hdr); - cc110x_pkt.address = _dst_addr[netif_hdr->dst_l2addr_len-1]; - } - - switch (payload->type) { -#ifdef MODULE_GNRC_SIXLOWPAN - case GNRC_NETTYPE_SIXLOWPAN: - cc110x_pkt.flags = 1; - break; -#endif - default: - cc110x_pkt.flags = 0; - } - - iolist_t iolist = { - .iol_base = (char *)&cc110x_pkt, - .iol_len = sizeof(cc110x_pkt_t) - }; - - unsigned payload_len = 0; - uint8_t *pos = cc110x_pkt.data; - - while (payload) { - payload_len += payload->size; - - if (payload_len > CC110X_MAX_DATA_LENGTH) { - DEBUG("gnrc_cc110x: payload length exceeds maximum" - "(%u>%u)\n", payload_len, CC110X_MAX_DATA_LENGTH); - gnrc_pktbuf_release(pkt); - return -EBADMSG; - } - - memcpy(pos, payload->data, payload->size); - pos += payload->size; - payload = payload->next; - } - - /* pkt has been copied into cc110x_pkt, we're done with it. */ - gnrc_pktbuf_release(pkt); - - cc110x_pkt.length = (uint8_t) payload_len + CC110X_HEADER_LENGTH; - - DEBUG("gnrc_cc110x: sending packet from %02x to %02x with payload " - "length %u\n", - (unsigned)cc110x_pkt.phy_src, - (unsigned)cc110x_pkt.address, - (unsigned)payload_len); -#if defined(MODULE_OD) && ENABLE_DEBUG - od_hex_dump(cc110x_pkt.data, payload_len, OD_WIDTH_DEFAULT); -#endif - - return dev->driver->send(dev, &iolist); -} - -static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif) -{ - netdev_t *dev = netif->dev; - cc110x_t *cc110x = &((netdev_cc110x_t*) dev)->cc110x; - - cc110x_pkt_t *cc110x_pkt = &cc110x->pkt_buf.packet; - - int payload_length = cc110x_pkt->length - CC110X_HEADER_LENGTH; - - int nettype; - - int addr_len; - switch (cc110x_pkt->flags) { -#ifdef MODULE_GNRC_SIXLOWPAN - case 1: - addr_len = 8; - nettype = GNRC_NETTYPE_SIXLOWPAN; - break; -#endif - default: - addr_len = 1; - nettype = GNRC_NETTYPE_UNDEF; - } - - /* copy packet payload into pktbuf */ - gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, cc110x_pkt->data, - payload_length, nettype); - - if(!pkt) { - DEBUG("gnrc_cc110x: _recv: cannot allocate pktsnip.\n"); - return NULL; - } - - - gnrc_pktsnip_t *netif_hdr; - netif_hdr = gnrc_pktbuf_add(NULL, NULL, - sizeof(gnrc_netif_hdr_t) + 2*addr_len, - GNRC_NETTYPE_NETIF); - - if (netif_hdr == NULL) { - DEBUG("gnrc_cc110x: no space left in packet buffer\n"); - gnrc_pktbuf_release(pkt); - return NULL; - } - - gnrc_netif_hdr_init(netif_hdr->data, addr_len, addr_len); - if (addr_len == 8) { - uint64_t src_addr = cc110x_pkt->phy_src; - uint64_t dst_addr = cc110x_pkt->address; - gnrc_netif_hdr_set_src_addr(netif_hdr->data, (uint8_t*)&src_addr, addr_len); - gnrc_netif_hdr_set_dst_addr(netif_hdr->data, (uint8_t*)&dst_addr, addr_len); - } - else { - gnrc_netif_hdr_set_src_addr(netif_hdr->data, (uint8_t*)&cc110x_pkt->phy_src, addr_len); - gnrc_netif_hdr_set_dst_addr(netif_hdr->data, (uint8_t*)&cc110x_pkt->address, addr_len); - } - - gnrc_netif_hdr_set_netif(netif_hdr->data, netif); - ((gnrc_netif_hdr_t *)netif_hdr->data)->lqi = cc110x->pkt_buf.lqi; - ((gnrc_netif_hdr_t *)netif_hdr->data)->rssi = cc110x->pkt_buf.rssi; - - DEBUG("gnrc_cc110x: received packet from %02x of length %u\n", - (unsigned)cc110x_pkt->phy_src, - (unsigned)cc110x_pkt->length-CC110X_HEADER_LENGTH); -#if defined(MODULE_OD) && ENABLE_DEBUG - od_hex_dump(cc110x_pkt->data, payload_length, OD_WIDTH_DEFAULT); -#endif - - - pkt->next = netif_hdr; - - return pkt; -} - -static const gnrc_netif_ops_t _cc110x_ops = { - .send = _send, - .recv = _recv, - .get = gnrc_netif_get_from_netdev, - .set = gnrc_netif_set_from_netdev, -}; - -gnrc_netif_t *gnrc_netif_cc110x_create(char *stack, int stacksize, char priority, - char *name, netdev_t *dev) -{ - return gnrc_netif_create(stack, stacksize, priority, name, dev, - &_cc110x_ops); -} diff --git a/drivers/cc110x/include/cc110x-defaultsettings.h b/drivers/cc110x/include/cc110x-defaultsettings.h deleted file mode 100644 index 1c9764d051e7..000000000000 --- a/drivers/cc110x/include/cc110x-defaultsettings.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2015 Kaspar Schleiser - * - * 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_cc110x - * @{ - * - * @file - * @brief cc110x default settings override - * - * By setting either CC110X_DEFAULT_PATABLE or CC110X_DEFAULT_FREQ in board.h, - * it is possible to override the default pa table or base frequency registers - * on a per-device basis. - * - * @author Kaspar Schleiser - */ -#ifndef CC110X_DEFAULTSETTINGS_H -#define CC110X_DEFAULTSETTINGS_H - -#include "board.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef CC110X_DEFAULT_PATABLE -#define CC110X_DEFAULT_PATABLE cc110x_default_pa_table -extern const char cc110x_default_pa_table[8]; -#endif - -#ifndef CC110X_DEFAULT_FREQ -#define CC110X_DEFAULT_FREQ cc110x_default_base_freq -extern const char cc110x_default_base_freq[3]; -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* CC110X_DEFAULTSETTINGS_H */ -/** @} */ diff --git a/drivers/cc110x/include/cc110x-defines.h b/drivers/cc110x/include/cc110x-defines.h deleted file mode 100644 index 6eac9fafb264..000000000000 --- a/drivers/cc110x/include/cc110x-defines.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (C) 2008 Freie Universität Berlin - * Copyright (C) 2013 INRIA - * - * 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_cc110x - * @{ - * - * @file - * @brief Driver internal constants for CC110x chip configuration - * - * @author Thomas Hillebrandt - * @author Heiko Will - * @author Oliver Hahm - */ - -#ifndef CC110X_DEFINES_H -#define CC110X_DEFINES_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Variable packet length PKTCTRL0 bit configuration - * - * If variable packet length is configured in PKTCTRL0 the - * first byte after the synch word determines the packet length. - */ -#define VARIABLE_PKTLEN (0x01) - -/** - * @brief RSSI calculation offset. - * - * The cc1101 has 74 as a RSSI offset. The CC1100E has a - * slightly larger offset of 75 to 79 (not implemented here). - * With those devices we thus get a slightly optimistic result. - */ -#define CC110X_RSSI_OFFSET (74) - -/** - * @name Bitmasks for reading out status register values - * @{ - */ - -/** - * @brief Bitmask (=10000000) for reading CRC_OK. - * - * If CRC_OK == 1: CRC for received data OK (or CRC disabled). - * If CRC_OK == 0: CRC error in received data. - */ -#define CRC_OK (0x80) -/** - * @brief Bitmask (=01111111) for reading LQI_EST. - * - * The Link Quality Indicator estimates how easily a received signal can be demodulated. - */ -#define LQI_EST (0x7F) -#define I_RSSI (0x00) /**< Index 0 contains RSSI information (from optionally appended packet status bytes). */ -#define I_LQI (0x01) /**< Index 1 contains LQI & CRC_OK information (from optionally appended packet status bytes). */ -#define MARC_STATE (0x1F) /**< Bitmask (=00011111) for reading MARC_STATE in MARCSTATE status register. */ -#define PKTSTATUS_CS (0x40) /**< Bitmask (=01000000) for reading CS (Carrier Sense) in PKTSTATUS status register. */ -#define PKTSTATUS_PQT_REACHED (0x20) /**< Bitmask (=00100000) for reading PQT_REACHED (Preamble Quality reached) in PKTSTATUS status register. */ -#define PKTSTATUS_CCA (0x10) /**< Bitmask (=00010000) for reading CCA (clear channel assessment) in PKTSTATUS status register. */ -#define PKTSTATUS_SFD (0x08) /**< Bitmask (=00001000) for reading SFD (Sync word found) in PKTSTATUS status register. */ -#define PKTSTATUS_GDO2 (0x04) /**< Bitmask (=00000100) for reading GDO2 (current value on GDO2 pin) in PKTSTATUS status register. */ -#define PKTSTATUS_GDO1 (0x02) /**< Bitmask (=00000010) for reading GDO1 (current value on GDO1 pin) in PKTSTATUS status register. */ -#define PKTSTATUS_GDO0 (0x01) /**< Bitmask (=00000001) for reading GDO0 (current value on GDO0 pin) in PKTSTATUS status register. */ -#define TXFIFO_UNDERFLOW (0x80) /**< Bitmask (=10000000) for reading TXFIFO_UNDERFLOW in TXBYTES status register. */ -#define BYTES_IN_TXFIFO (0x7F) /**< Bitmask (=01111111) for reading NUM_TXBYTES in TXBYTES status register. */ -#define RXFIFO_OVERFLOW (0x80) /**< Bitmask (=10000000) for reading RXFIFO_OVERFLOW in RXBYTES status register. */ -#define BYTES_IN_RXFIFO (0x7F) /**< Bitmask (=01111111) for reading NUM_RXBYTES in RXBYTES status register. */ -/** @} */ - -/** - * @name Bitmasks for reading out configuration register values - * @{ - */ -#define PKT_LENGTH_CONFIG (0x03) /**< Bitmask (=00000011) for reading LENGTH_CONFIG in PKTCTRL0 configuration register. */ -/** @} */ - -/** - * @name Definitions to support burst/single access - * @{ - */ -#define CC110X_WRITE_BURST (0x40) /**< Offset for burst write. */ -#define CC110X_READ_SINGLE (0x80) /**< Offset for read single byte. */ -#define CC110X_READ_BURST (0xC0) /**< Offset for read burst. */ -#define CC110X_NOBYTE (0xFF) /**< No command (for reading). */ -/** @} */ - -/** - * @name Configuration Registers (47x) - * @{ - */ -#define CC110X_IOCFG2 (0x00) /**< GDO2 output pin configuration */ -#define CC110X_IOCFG1 (0x01) /**< GDO1 output pin configuration */ -#define CC110X_IOCFG0 (0x02) /**< GDO0 output pin configuration */ -#define CC110X_FIFOTHR (0x03) /**< RX FIFO and TX FIFO thresholds */ -#define CC110X_SYNC1 (0x04) /**< Sync word, high byte */ -#define CC110X_SYNC0 (0x05) /**< Sync word, low byte */ -#define CC110X_PKTLEN (0x06) /**< Packet length */ -#define CC110X_PKTCTRL1 (0x07) /**< Packet automation control */ -#define CC110X_PKTCTRL0 (0x08) /**< Packet automation control */ -#define CC110X_ADDR (0x09) /**< Device address */ -#define CC110X_CHANNR (0x0A) /**< Channel number */ -#define CC110X_FSCTRL1 (0x0B) /**< Frequency synthesizer control */ -#define CC110X_FSCTRL0 (0x0C) /**< Frequency synthesizer control */ -#define CC110X_FREQ2 (0x0D) /**< Frequency control word, high byte */ -#define CC110X_FREQ1 (0x0E) /**< Frequency control word, middle byte */ -#define CC110X_FREQ0 (0x0F) /**< Frequency control word, low byte */ -#define CC110X_MDMCFG4 (0x10) /**< Modem configuration */ -#define CC110X_MDMCFG3 (0x11) /**< Modem configuration */ -#define CC110X_MDMCFG2 (0x12) /**< Modem configuration */ -#define CC110X_MDMCFG1 (0x13) /**< Modem configuration */ -#define CC110X_MDMCFG0 (0x14) /**< Modem configuration */ -#define CC110X_DEVIATN (0x15) /**< Modem deviation setting */ -#define CC110X_MCSM2 (0x16) /**< Main Radio Control State Machine configuration */ -#define CC110X_MCSM1 (0x17) /**< Main Radio Control State Machine configuration */ -#define CC110X_MCSM0 (0x18) /**< Main Radio Control State Machine configuration */ -#define CC110X_FOCCFG (0x19) /**< Frequency Offset Compensation configuration */ -#define CC110X_BSCFG (0x1A) /**< Bit Synchronization configuration */ -#define CC110X_AGCCTRL2 (0x1B) /**< AGC control */ -#define CC110X_AGCCTRL1 (0x1C) /**< AGC control */ -#define CC110X_AGCCTRL0 (0x1D) /**< AGC control */ -#define CC110X_WOREVT1 (0x1E) /**< High byte Event 0 timeout */ -#define CC110X_WOREVT0 (0x1F) /**< Low byte Event 0 timeout */ -#define CC110X_WORCTRL (0x20) /**< Wake On Radio control */ -#define CC110X_FREND1 (0x21) /**< Front end RX configuration */ -#define CC110X_FREND0 (0x22) /**< Front end TX configuration */ -#define CC110X_FSCAL3 (0x23) /**< Frequency synthesizer calibration */ -#define CC110X_FSCAL2 (0x24) /**< Frequency synthesizer calibration */ -#define CC110X_FSCAL1 (0x25) /**< Frequency synthesizer calibration */ -#define CC110X_FSCAL0 (0x26) /**< Frequency synthesizer calibration */ -#define CC110X_RCCTRL1 (0x27) /**< RC oscillator configuration */ -#define CC110X_RCCTRL0 (0x28) /**< RC oscillator configuration */ -#define CC110X_FSTEST (0x29) /**< Frequency synthesizer calibration control */ -#define CC110X_PTEST (0x2A) /**< Production test */ -#define CC110X_AGCTEST (0x2B) /**< AGC test */ -#define CC110X_TEST2 (0x2C) /**< Various test settings */ -#define CC110X_TEST1 (0x2D) /**< Various test settings */ -#define CC110X_TEST0 (0x2E) /**< Various test settings */ -/** @} */ - -/** - * @name Strobe commands (14x) - * @{ - */ -#define CC110X_SRES (0x30) /**< Reset chip. */ -/** - * @brief Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). - * - * If in RX/TX: Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround). - */ -#define CC110X_SFSTXON (0x31) -#define CC110X_SXOFF (0x32) /**< Turn off crystal oscillator. */ -#define CC110X_SCAL (0x33) /**< Calibrate frequency synthesizer and turn it off (enables quick start). */ -#define CC110X_SRX (0x34) /**< Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1. */ -/** - * In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1. - * If in RX state and CCA is enabled: Only go to TX if channel is clear. - */ -#define CC110X_STX (0x35) -#define CC110X_SIDLE (0x36) /**< Exit RX / TX, turn off frequency synthesizer and exit WOR mode if applicable. */ -#define CC110X_SAFC (0x37) /**< Perform AFC adjustment of the frequency synthesizer */ -#define CC110X_SWOR (0x38) /**< Start automatic RX polling sequence (Wake-on-Radio) */ -#define CC110X_SPWD (0x39) /**< Enter power down mode when CSn goes high. */ -#define CC110X_SFRX (0x3A) /**< Flush the RX FIFO buffer (CC110X should be in IDLE state). */ -#define CC110X_SFTX (0x3B) /**< Flush the TX FIFO buffer (CC110X should be in IDLE state). */ -#define CC110X_SWORRST (0x3C) /**< Reset real time clock. */ -#define CC110X_SNOP (0x3D) /**< No operation. May be used to pad strobe commands to two bytes for simpler software. */ -/** @} */ - -/** - * @name Status registers (12x) - * @{ - */ -#define CC110X_PARTNUM (0x30) /**< Part number of CC110X. */ -#define CC110X_VERSION (0x31) /**< Current version number. */ -#define CC110X_FREQEST (0x32) /**< Frequency Offset Estimate. */ -#define CC110X_LQI (0x33) /**< Demodulator estimate for Link Quality. */ -#define CC110X_RSSI (0x34) /**< Received signal strength indication. */ -#define CC110X_MARCSTATE (0x35) /**< Control state machine state. */ -#define CC110X_WORTIME1 (0x36) /**< High byte of WOR timer. */ -#define CC110X_WORTIME0 (0x37) /**< Low byte of WOR timer. */ -#define CC110X_PKTSTATUS (0x38) /**< Current GDOx status and packet status. */ -#define CC110X_VCO_VC_DAC (0x39) /**< Current setting from PLL calibration module. */ -#define CC110X_TXBYTES (0x3A) /**< Underflow and number of bytes in the TX FIFO. */ -#define CC110X_RXBYTES (0x3B) /**< Overflow and number of bytes in the RX FIFO. */ -/** @} */ - -/** - * @name Multi byte registers - * @{ - */ -/** - * @brief Register for eight user selected output power settings. - * - * 3-bit FREND0.PA_POWER value selects the PATABLE entry to use. - */ -#define CC110X_PATABLE (0x3E) -#define CC110X_TXFIFO (0x3F) /**< TX FIFO: Write operations write to the TX FIFO (SB: +0x00; BURST: +0x40) */ -#define CC110X_RXFIFO (0x3F) /**< RX FIFO: Read operations read from the RX FIFO (SB: +0x80; BURST: +0xC0) */ -/** @} */ - - -/** - * @name GDO configuration values - * - * Values that can be written to the GDO0, GDO1 and GDO2 configuration registers - * @{ - */ - -/** @brief GDO goes high when RX FIFO is filled at or above threshold */ -#define CC110X_GDO_HIGH_ON_RX_FIFO_ABOVE_THRESHOLD (0x00) -/** - * @brief GDO goes high when RX FIFO is filled at or above threshold or when - * packet is fully received - */ -#define CC110X_GDO_HIGH_ON_RX_FIFO_FILLED_OR_PKT_END (0x01) -/** @brief GDO goes low when TX FIFO is filled less than threshold */ -#define CC110X_GDO_LOW_ON_TX_FIFO_BELOW_THRESHOLD (0x02) -/** @brief GDO goes low when TX FIFO becomes empty */ -#define CC110X_GDO_LOW_ON_TX_FIFO_EMPTY (0x03) -/** @brief GDO goes high when RX FIFO overflows */ -#define CC110X_GDO_HIGH_ON_RX_FIFO_OVERFLOW (0x04) -/** @brief GDO goes high when TX FIFO underflows */ -#define CC110X_GDO_HIGH_ON_TX_FIFO_UNDERFLOW (0x05) -/** - * @brief GDO goes high when sync word was just received until the packet is - * fully received, or when sync word has been send until packet is fully - * send - */ -#define CC110X_GDO_HIGH_ON_SYNC_WORD (0x06) -/** - * @brief GDO goes high when a packet is received and CRC is correct. - * Goes back to low when first byte of RX fifo has been read - */ -#define CC110X_GDO_HIGH_ON_PACKET_RECEIVED (0x07) -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* CC110X_DEFINES_H */ -/** @} */ diff --git a/drivers/cc110x/include/cc110x-interface.h b/drivers/cc110x/include/cc110x-interface.h deleted file mode 100644 index 4e77b9478992..000000000000 --- a/drivers/cc110x/include/cc110x-interface.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2015 Kaspar Schleiser - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2013 INRIA - * - * 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_cc110x - * @{ - * - * @file - * @brief internal declarations for cc110x driver - * - * @author Oliver Hahm - * @author Kaspar Schleiser - */ - -#ifndef CC110X_INTERFACE_H -#define CC110X_INTERFACE_H - -#include -#include "cc110x.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @name cc110x raw low-level interface - * @internal - * @{ - */ -char *cc110x_get_marc_state(cc110x_t *dev); -const char *cc110x_state_to_text(uint8_t state); -int cc110x_rd_set_mode(cc110x_t *dev, int mode); -uint8_t cc110x_get_buffer_pos(cc110x_t *dev); -void cc110x_isr_handler(cc110x_t *dev, void(*callback)(void*), void*arg); -void cc110x_set_base_freq_raw(cc110x_t *dev, const char* freq_array); -void cc110x_setup_rx_mode(cc110x_t *dev); -void cc110x_switch_to_pwd(cc110x_t *dev); -void cc110x_switch_to_rx(cc110x_t *dev); -void cc110x_wakeup_from_rx(cc110x_t *dev); -void cc110x_write_register(cc110x_t *dev, uint8_t r, uint8_t value); - -extern const char cc110x_default_conf[]; -extern const uint8_t cc110x_default_conf_size; -extern const uint8_t cc110x_pa_table[]; - -#ifdef MODULE_CC110X_HOOKS -void cc110x_hooks_init(void); -void cc110x_hook_rx(void); -void cc110x_hook_tx(void); -void cc110x_hook_off(void); -#endif -/* @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* CC110X_INTERFACE_H */ -/** @} */ diff --git a/drivers/cc110x/include/cc110x-internal.h b/drivers/cc110x/include/cc110x-internal.h deleted file mode 100644 index 1c5cc5ba6a00..000000000000 --- a/drivers/cc110x/include/cc110x-internal.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2015 Kaspar Schleiser - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2013 INRIA - * - * 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_cc110x - * @{ - * - * @file - * @brief Data structures and variables for the cc110x driver interface - * - * @author Oliver Hahm - * @author Kaspar Schleiser - */ - -#ifndef CC110X_INTERNAL_H -#define CC110X_INTERNAL_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CC110X_RXBUF_SIZE (2) -#define CC110X_FIFO_LENGTH (64) -#define CC110X_MAX_DATA_LENGTH (58+64) - -#define CC110X_HEADER_LENGTH (3) /**< Header covers SRC, DST and - FLAGS */ -#define CC110X_BROADCAST_ADDRESS (0x00) /**< CC110X broadcast address */ - -#define MIN_UID (0x01) /**< Minimum UID of a node is - 1 */ -#define MAX_UID (0xFF) /**< Maximum UID of a node is - 255 */ - -#define MIN_CHANNR (0) /**< Minimum channel number */ -#define MAX_CHANNR (24) /**< Maximum channel number */ - -#define CC110X_PACKET_LENGTH (0xFF) /**< max packet length = 255b */ -#define CC110X_L2_HDR_SIZE (3) /**< Layer 2 header size */ -#define CC110X_SYNC_WORD_TX_TIME (90000) /**< loop count (max. timeout ~15ms) - to wait for sync word to be - transmitted (GDO2 from low to - high) */ - -#define RESET_WAIT_TIME (610) /**< Reset wait time (in reset - procedure) */ -#define IDLE_TO_RX_TIME (122) /**< Time chip needs to go to RX */ -#define CS_SO_WAIT_TIME (488) /**< Time to wait for SO to go low - after CS */ -#define CC110X_GDO1_LOW_RETRY (100) /**< Max. retries for SO to go low - after CS */ -#ifndef CC110X_DEFAULT_CHANNEL -#define CC110X_DEFAULT_CHANNEL (0) /**< The default channel number */ -#endif -#define CC110X_MIN_CHANNR (0) /**< lowest possible channel number */ -#define CC110X_MAX_CHANNR (0) /**< highest possible channel number */ - -/** - * @name State values for state machine - * @{ - */ -enum { - RADIO_UNKNOWN, - RADIO_IDLE, - RADIO_TX_BUSY, - RADIO_RX, - RADIO_RX_BUSY, - RADIO_PWD, -}; -/** @} */ - -/** - * @brief array holding cc110x register values - */ -extern char cc110x_conf[]; - -/** - * @brief CC110X layer 0 protocol - * - *
----------------------------------------------------
-|        |         |         |       |            |
-| Length | Address | PhySrc  | Flags |    Data    |
-|        |         |         |       |            |
----------------------------------------------------
-  1 byte   1 byte    1 byte   1 byte   <= 251 bytes
-
-Flags:
-        Bit | Meaning
-        --------------------
-        7:4 | -
-        3:1 | Protocol
-          0 | Identification
-
-Notes: -\li length & address are given by CC110X -\li Identification is increased is used to scan duplicates. It must be increased - for each new packet and kept for packet retransmissions. - */ -typedef struct __attribute__((packed)) -{ - uint8_t length; /**< Length of the packet (without length byte) */ - uint8_t address; /**< Destination address */ - uint8_t phy_src; /**< Source address (physical source) */ - uint8_t flags; /**< Flags */ - uint8_t data[CC110X_MAX_DATA_LENGTH]; /**< Data (high layer protocol) */ -} cc110x_pkt_t; - -/** - * @brief struct holding cc110x packet + metadata - */ -typedef struct { - uint8_t rssi; /**< RSSI value */ - uint8_t lqi; /**< link quality indicator */ - uint8_t pos; /**< I have no clue. */ - cc110x_pkt_t packet; /**< whole packet */ -} cc110x_pkt_buf_t; - -/** - * @brief enum for holding cc110x radio on/off state */ -enum cc110x_radio_mode { - RADIO_MODE_GET = -1, /**< leave mode unchanged */ - RADIO_MODE_OFF = 0, /**< turn radio off */ - RADIO_MODE_ON = 1 /**< turn radio on */ -}; - -/** - * @brief CC110x register configuration - */ -typedef struct { - uint8_t _IOCFG2; /**< GDO2 output pin configuration */ - uint8_t _IOCFG1; /**< GDO1 output pin configuration */ - uint8_t _IOCFG0; /**< GDO0 output pin configuration */ - uint8_t _FIFOTHR; /**< RX FIFO and TX FIFO thresholds */ - uint8_t _SYNC1; /**< Sync word, high byte */ - uint8_t _SYNC0; /**< Sync word, low byte */ - uint8_t _PKTLEN; /**< Packet length */ - uint8_t _PKTCTRL1; /**< Packet automation control */ - uint8_t _PKTCTRL0; /**< Packet automation control */ - uint8_t _ADDR; /**< Device address */ - uint8_t _CHANNR; /**< Channel number */ - uint8_t _FSCTRL1; /**< Frequency synthesizer control */ - uint8_t _FSCTRL0; /**< Frequency synthesizer control */ - uint8_t _FREQ2; /**< Frequency control word, high byte */ - uint8_t _FREQ1; /**< Frequency control word, middle byte */ - uint8_t _FREQ0; /**< Frequency control word, low byte */ - uint8_t _MDMCFG4; /**< Modem configuration */ - uint8_t _MDMCFG3; /**< Modem configuration */ - uint8_t _MDMCFG2; /**< Modem configuration */ - uint8_t _MDMCFG1; /**< Modem configuration */ - uint8_t _MDMCFG0; /**< Modem configuration */ - uint8_t _DEVIATN; /**< Modem deviation setting */ - uint8_t _MCSM2; /**< Main Radio Control State Machine configuration */ - uint8_t _MCSM1; /**< Main Radio Control State Machine configuration */ - uint8_t _MCSM0; /**< Main Radio Control State Machine configuration */ - uint8_t _FOCCFG; /**< Frequency Offset Compensation configuration */ - uint8_t _BSCFG; /**< Bit Synchronization configuration */ - uint8_t _AGCCTRL2; /**< AGC control */ - uint8_t _AGCCTRL1; /**< AGC control */ - uint8_t _AGCCTRL0; /**< AGC control */ - uint8_t _WOREVT1; /**< High byte Event 0 timeout */ - uint8_t _WOREVT0; /**< Low byte Event 0 timeout */ - uint8_t _WORCTRL; /**< Wake On Radio control */ - uint8_t _FREND1; /**< Front end RX configuration */ - uint8_t _FREND0; /**< Front end TX configuration */ - uint8_t _FSCAL3; /**< Frequency synthesizer calibration */ - uint8_t _FSCAL2; /**< Frequency synthesizer calibration */ - uint8_t _FSCAL1; /**< Frequency synthesizer calibration */ - uint8_t _FSCAL0; /**< Frequency synthesizer calibration */ -} cc110x_reg_t; - -/** - * @brief CC110x radio configuration - */ -typedef struct { - cc110x_reg_t reg_cfg; /**< CC110X register configuration */ - uint8_t pa_power; /**< Output power setting */ -} cc110x_cfg_t; - -/** - * @brief Radio Control Flags - */ -typedef struct { - uint8_t _RSSI; /**< The RSSI value of last received packet */ - uint8_t _LQI; /**< The LQI value of the last received packet */ -} cc110x_flags_t; - -/** - * @brief Statistic interface for debugging - */ -typedef struct cc110x_statistic { - uint32_t packets_in; /**< total nr of packets received */ - uint32_t packets_in_crc_fail; /**< dropped because of invalid crc */ - uint32_t packets_in_while_tx; /**< receive while tx */ - uint32_t raw_packets_out; /**< packets sent */ -} cc110x_statistic_t; - -#ifdef __cplusplus -} -#endif - -#endif /* CC110X_INTERNAL_H */ -/** @} */ diff --git a/drivers/cc110x/include/cc110x-netdev.h b/drivers/cc110x/include/cc110x-netdev.h deleted file mode 100644 index 2292662b83ba..000000000000 --- a/drivers/cc110x/include/cc110x-netdev.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * 2015 Kaspar Schleiser - * - * 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_cc110x - * @{ - * - * @file - * @brief Variables for the cc110x netdev interface - * - * @author Fabian Nack - * @author Kaspar Schleiser - */ - -#ifndef CC110X_NETDEV_H -#define CC110X_NETDEV_H - -#include "periph/gpio.h" -#include "periph/spi.h" -#include "net/netdev.h" -#include "cc110x.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Implementation of netdev_driver_t for CC110X device - */ -extern const netdev_driver_t netdev_cc110x_driver; - -/** - * @brief cc110x netdev struct - */ -typedef struct netdev_cc110x { - netdev_t netdev; /**< writing obious */ - cc110x_t cc110x; /**< documentation here */ -} netdev_cc110x_t; - -/** - * @brief Received packet status information for cc110x radios - */ -typedef struct netdev_radio_rx_info netdev_cc110x_rx_info_t; - -/** - * @brief netdev <-> cc110x glue code initialization function - * - * @param[out] netdev_cc110x ptr to netdev_cc110x struct ti initialize - * @param[in] params cc110x IO parameter struct to use - * - * @return 0 on success - * @return -1 on error - */ -int netdev_cc110x_setup(netdev_cc110x_t *netdev_cc110x, const cc110x_params_t *params); - -#ifdef __cplusplus -} -#endif - -#endif /* CC110X_NETDEV_H */ -/** @} */ diff --git a/drivers/cc110x/include/cc110x-spi.h b/drivers/cc110x/include/cc110x-spi.h deleted file mode 100644 index 0b39c89c9132..000000000000 --- a/drivers/cc110x/include/cc110x-spi.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2013 INRIA - * Copyright (C) 2015 Kaspar Schleiser - * - * 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_cc110x - * @{ - * - * @file - * @brief CC110X SPI functions - * - * @author Oliver Hahm - * @author Fabian Nack - * @author Kaspar Schleiser - */ - -#ifndef CC110X_SPI_H -#define CC110X_SPI_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Write a set of bytes using burst mode (if available) - * - * @param dev Device to work on - * @param addr Destination register - * @param buffer Data to be written - * @param count Size of data - */ -void cc110x_writeburst_reg(cc110x_t *dev, uint8_t addr, const char *buffer, uint8_t count); - -/** - * @brief Read a set of bytes using burst mode (if available) - * - * @param dev Device to work on - * @param addr Source register - * @param buffer Buffer to store read data - * @param count Size of data to be read - */ -void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t count); - -/** - * @brief Write one byte to a register - * - * @param dev Device to work on - * @param addr Destinatoin register - * @param value New value - */ -void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value); - -/** - * @brief Read a byte from register - * - * @param dev Device to work on - * @param addr Source register - * - * @return Read state and value of register - */ -uint8_t cc110x_read_reg(cc110x_t *dev, uint8_t addr); - -/** - * @brief Read a byte from register, robust version - * - * Datasheet states some registered should be read twice until - * it returns the same value. - * - * @param dev Device to work on - * @param addr Source register - * - * @return Read state and value of register - */ -uint8_t cc110x_get_reg_robust(cc110x_t *dev, uint8_t addr); - -/** - * @brief Read state of a register - * - * @param dev Device to work on - * @param addr Source register - * - * @return State of register - */ -uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr); - -/** - * @brief Sends a command strobe - * - * @param dev Device to work on - * @param c Command code - * - * @return Command response - */ -uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c); - -/** - * @brief Pull CS to low and wait for CC110x stabilization - * - * @param dev Device to work on - */ -void cc110x_cs(cc110x_t *dev); - -#ifdef __cplusplus -} -#endif - -#endif /* CC110X_SPI_H */ -/** @} */ diff --git a/drivers/cc110x/include/cc110x_params.h b/drivers/cc110x/include/cc110x_params.h deleted file mode 100644 index e9f0130c2a92..000000000000 --- a/drivers/cc110x/include/cc110x_params.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2017 Marian Buschsieweke - * - * 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_cc110x - * @{ - * - * @file - * @brief cc110x board specific configuration - * - * @author Marian Buschsieweke - */ - -#ifndef CC110X_PARAMS_H -#define CC110X_PARAMS_H - -#include "board.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @name Default parameters for the cc110x driver - * - * These values are based on the msba2 board - * @{ - */ -#ifndef CC110X_PARAM_SPI -#define CC110X_PARAM_SPI SPI_DEV(0) -#endif - -#ifndef CC110X_PARAM_CS -#define CC110X_PARAM_CS GPIO_PIN(1, 21) -#endif - -#ifndef CC110X_PARAM_GDO0 -#define CC110X_PARAM_GDO0 GPIO_PIN(0, 27) -#endif - -#ifndef CC110X_PARAM_GDO1 -#define CC110X_PARAM_GDO1 GPIO_PIN(1, 23) -#endif - -#ifndef CC110X_PARAM_GDO2 -#define CC110X_PARAM_GDO2 GPIO_PIN(0, 28) -#endif - -#ifndef CC110X_PARAMS -#define CC110X_PARAMS { \ - .spi = CC110X_PARAM_SPI, \ - .cs = CC110X_PARAM_CS, \ - .gdo0 = CC110X_PARAM_GDO0, \ - .gdo1 = CC110X_PARAM_GDO1, \ - .gdo2 = CC110X_PARAM_GDO2, \ - } - -#endif -/** @} */ - - -/** - * @name CC110X configuration - * @brief Specifies the SPI bus and GPIOs connected to the CC110X transceiver - */ -const cc110x_params_t cc110x_params[] = { - CC110X_PARAMS -}; - -#ifdef __cplusplus -} -#endif -#endif /* CC110X_PARAMS_H */ -/** @} */ diff --git a/drivers/cc110x/include/gnrc_netif_cc110x.h b/drivers/cc110x/include/gnrc_netif_cc110x.h deleted file mode 100644 index dc1d43c2110c..000000000000 --- a/drivers/cc110x/include/gnrc_netif_cc110x.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2017 Freie Universität Berlin - * - * 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 net_gnrc_netif - * @{ - * - * @file - * @brief CC110x adaption for @ref net_gnrc_netif - * - * @author Martine Lenders - */ -#ifndef GNRC_NETIF_CC110X_H -#define GNRC_NETIF_CC110X_H - -#include "net/gnrc/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -gnrc_netif_t *gnrc_netif_cc110x_create(char *stack, int stacksize, char priority, - char *name, netdev_t *dev); - -#ifdef __cplusplus -} -#endif - -#endif /* GNRC_NETIF_CC110X_H */ -/** @} */ diff --git a/drivers/include/cc110x.h b/drivers/include/cc110x.h deleted file mode 100644 index f915f8bfc0de..000000000000 --- a/drivers/include/cc110x.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * 2015 Kaspar Schleiser - * - * 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_cc110x CC1100/CC1101 radio driver - * @ingroup drivers_netdev - * @brief Driver for TI CC1100/CC1101 radios - * @{ - * @file - * @brief Public interface for cc110x driver - * @author Kaspar Schleiser - */ - -#ifndef CC110X_H -#define CC110X_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "periph/spi.h" -#include "periph/gpio.h" -#include "cc110x-internal.h" -#include "net/gnrc/nettype.h" - -/** - * @brief Struct for holding cc110x IO parameters - */ -typedef struct cc110x_params { - spi_t spi; /**< SPI bus the CC110x is connected to */ - gpio_t cs; /**< GPIO connected to the chip select pin of the CC110x */ - gpio_t gdo0; /**< GPIO connected to the GDO0 pin of the CC110x */ - gpio_t gdo1; /**< GPIO connected to the GDO1 pin of the CC110x */ - gpio_t gdo2; /**< GPIO connected to the GDO2 pin of the CC110x */ -} cc110x_params_t; - -/** - * @brief Forward declaration - */ -typedef struct cc110x cc110x_t; - -/** - * @brief Struct for holding cc110x device state - */ -struct cc110x { - cc110x_params_t params; /**< cc110x IO configuration */ - - cc110x_statistic_t cc110x_statistic; /**< Statistic values for - debugging */ - - uint8_t radio_state; /**< Radio state */ - uint8_t radio_channel; /**< current Radio channel */ - uint8_t radio_address; /**< current Radio address */ - - cc110x_pkt_buf_t pkt_buf; /**< RX/TX buffer */ - void (*isr_cb)(cc110x_t *dev, void* arg); /**< isr callback */ - void *isr_cb_arg; /**< isr callback argument */ -#ifdef MODULE_GNRC_NETIF - gnrc_nettype_t proto; /**< protocol the radio expects */ -#endif -}; - -/** - * @brief Setup cc110x device parameters - * - * @param[in] dev device struct to set up - * @param[in] params struct holding parameters - * - * @return always succeeds - */ -int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params); - -/** - * @brief Set cc110x channel number - * - * @param[in] dev device to work on - * @param[in] channr guess what - * - * @return nr of set channel on success - * @return -1 on error - */ -int16_t cc110x_set_channel(cc110x_t *dev, uint8_t channr); - - -/** - * @brief Send raw cc110x packet - * - * @param[in] dev Device to send on - * @param[in] packet ptr to packet to be sent - * - * @return size of packet on success - * @return <0 on error - */ -int cc110x_send(cc110x_t *dev, cc110x_pkt_t *packet); - -/** - * @brief Set cc110x radio address - * - * @param[in] dev device to query - * - * @return nr of currently set address - */ -uint8_t cc110x_get_address(cc110x_t *dev); - -/** - * @brief Set cc110x radio address - * - * @param[in] dev device to work on - * @param[in] address new address - * - * @return address set on success - * @return 0 on error - */ -uint8_t cc110x_set_address(cc110x_t *dev, uint8_t address); - - -/** - * @brief Set cc110x monitor mode setting - * - * @param[in] dev device to work on - * @param[in] mode mode to set (0 or 1) - */ -void cc110x_set_monitor(cc110x_t *dev, uint8_t mode); - -#ifdef __cplusplus -} -#endif - -#endif /* CC110X_H */ -/** @} */ diff --git a/examples/default/Makefile b/examples/default/Makefile index 87bca54625f8..64a4112b27e6 100644 --- a/examples/default/Makefile +++ b/examples/default/Makefile @@ -71,15 +71,10 @@ endif include $(RIOTBASE)/Makefile.include # Set a custom channel if needed -ifneq (,$(filter cc110x,$(USEMODULE))) # radio is cc110x sub-GHz - DEFAULT_CHANNEL ?= 0 - CFLAGS += -DCC110X_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) -else - ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz - DEFAULT_CHANNEL ?= 5 - CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) - else # radio is IEEE 802.15.4 2.4 GHz - DEFAULT_CHANNEL ?= 26 - CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) - endif +ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz + DEFAULT_CHANNEL ?= 5 + CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) +else # radio is IEEE 802.15.4 2.4 GHz + DEFAULT_CHANNEL ?= 26 + CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) endif diff --git a/examples/gnrc_border_router/Makefile b/examples/gnrc_border_router/Makefile index ff06c25ed728..3d0c46d9529b 100644 --- a/examples/gnrc_border_router/Makefile +++ b/examples/gnrc_border_router/Makefile @@ -116,15 +116,10 @@ host-tools: $(Q)env -u CC -u CFLAGS make -C $(RIOTTOOLS) # Set a custom channel if needed -ifneq (,$(filter cc110x,$(USEMODULE))) # radio is cc110x sub-GHz - DEFAULT_CHANNEL ?= 0 - CFLAGS += -DCC110X_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) -else - ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz - DEFAULT_CHANNEL ?= 5 - CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) - else # radio is IEEE 802.15.4 2.4 GHz - DEFAULT_CHANNEL ?= 26 - CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) - endif +ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz + DEFAULT_CHANNEL ?= 5 + CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) +else # radio is IEEE 802.15.4 2.4 GHz + DEFAULT_CHANNEL ?= 26 + CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) endif diff --git a/examples/gnrc_minimal/Makefile b/examples/gnrc_minimal/Makefile index 18d8ddc40ceb..7d7a1cf80518 100644 --- a/examples/gnrc_minimal/Makefile +++ b/examples/gnrc_minimal/Makefile @@ -36,15 +36,10 @@ QUIET ?= 1 include $(RIOTBASE)/Makefile.include # Set a custom channel if needed -ifneq (,$(filter cc110x,$(USEMODULE))) # radio is cc110x sub-GHz - DEFAULT_CHANNEL ?= 0 - CFLAGS += -DCC110X_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) -else - ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz - DEFAULT_CHANNEL ?= 5 - CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) - else # radio is IEEE 802.15.4 2.4 GHz - DEFAULT_CHANNEL ?= 26 - CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) - endif +ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz + DEFAULT_CHANNEL ?= 5 + CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) +else # radio is IEEE 802.15.4 2.4 GHz + DEFAULT_CHANNEL ?= 26 + CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) endif diff --git a/examples/gnrc_networking/Makefile b/examples/gnrc_networking/Makefile index 25c2dc858d19..57ca39821a6f 100644 --- a/examples/gnrc_networking/Makefile +++ b/examples/gnrc_networking/Makefile @@ -65,15 +65,10 @@ QUIET ?= 1 include $(RIOTBASE)/Makefile.include # Set a custom channel if needed -ifneq (,$(filter cc110x,$(USEMODULE))) # radio is cc110x sub-GHz - DEFAULT_CHANNEL ?= 0 - CFLAGS += -DCC110X_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) -else - ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz - DEFAULT_CHANNEL ?= 5 - CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) - else # radio is IEEE 802.15.4 2.4 GHz - DEFAULT_CHANNEL ?= 26 - CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) - endif +ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz + DEFAULT_CHANNEL ?= 5 + CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) +else # radio is IEEE 802.15.4 2.4 GHz + DEFAULT_CHANNEL ?= 26 + CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) endif diff --git a/examples/nanocoap_server/Makefile b/examples/nanocoap_server/Makefile index 511f3b65beda..8b908cb32b90 100644 --- a/examples/nanocoap_server/Makefile +++ b/examples/nanocoap_server/Makefile @@ -61,15 +61,10 @@ QUIET ?= 1 include $(RIOTBASE)/Makefile.include # Set a custom channel if needed -ifneq (,$(filter cc110x,$(USEMODULE))) # radio is cc110x sub-GHz - DEFAULT_CHANNEL ?= 0 - CFLAGS += -DCC110X_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) -else - ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz - DEFAULT_CHANNEL ?= 5 - CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) - else # radio is IEEE 802.15.4 2.4 GHz - DEFAULT_CHANNEL ?= 26 - CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) - endif +ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz + DEFAULT_CHANNEL ?= 5 + CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) +else # radio is IEEE 802.15.4 2.4 GHz + DEFAULT_CHANNEL ?= 26 + CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) endif diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 874ce21a8e55..ac123db8443e 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -248,11 +248,6 @@ void auto_init(void) auto_init_slipdev(); #endif -#ifdef MODULE_CC110X - extern void auto_init_cc110x(void); - auto_init_cc110x(); -#endif - #ifdef MODULE_CC2538_RF extern void auto_init_cc2538_rf(void); auto_init_cc2538_rf(); diff --git a/tests/gnrc_udp/Makefile b/tests/gnrc_udp/Makefile index 16d201ced299..b4d10df9b2b4 100644 --- a/tests/gnrc_udp/Makefile +++ b/tests/gnrc_udp/Makefile @@ -31,15 +31,10 @@ USEMODULE += netstats_ipv6 include $(RIOTBASE)/Makefile.include # Set a custom channel if needed -ifneq (,$(filter cc110x,$(USEMODULE))) # radio is cc110x sub-GHz - DEFAULT_CHANNEL ?= 0 - CFLAGS += -DCC110X_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) -else - ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz - DEFAULT_CHANNEL ?= 5 - CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) - else # radio is IEEE 802.15.4 2.4 GHz - DEFAULT_CHANNEL ?= 26 - CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) - endif +ifneq (,$(filter at86rf212b,$(USEMODULE))) # radio is IEEE 802.15.4 sub-GHz + DEFAULT_CHANNEL ?= 5 + CFLAGS += -DIEEE802154_DEFAULT_SUBGHZ_CHANNEL=$(DEFAULT_CHANNEL) +else # radio is IEEE 802.15.4 2.4 GHz + DEFAULT_CHANNEL ?= 26 + CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL) endif From 972367432a732868932db8c22e13b9ddc9774395 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Thu, 8 Nov 2018 17:37:07 +0100 Subject: [PATCH 2/7] drivers/cc110x: Rewrite of the cc110x driver The cc110x driver has been re-written from scratch to overcome the limitations of the old driver. The main motivation of the rewrite was to achieve better maintainability by a detailed documentation, reduce the complexity and the overhead of the SPI communication with the device, and to allow to simultaneously use transceivers with different configuration regarding the used base band, the channel bandwidth, the modulation rate, and the channel map. Features of this driver include: - Support for the CC1100, CC1101, and the CC1100e sub-gigahertz transceivers. - Detailed documentation of every aspect of this driver. - An easy to use configuration API that allows setting the transceiver configuration (modulation rate, channel bandwidth, base frequency) and the channel map. - Fast channel hopping by pre-calibration of the channels during device configuration (so that no calibration is needed during hopping). - Simplified SPI communication: Only during start-up the MCU has to wait for the transceiver to be ready (for the power regulators and the crystal to stabilize). The old driver did this for every SPI transfer, which resulted in complex communication code. This driver will wait on start up for the transceiver to power up and then use RIOT's SPI API like every other driver. (Not only the data sheet states that this is fine, it also proved to be reliable in practise.) - Greatly reduced latency: The RTT on the old driver (@150 kbps data rate) was about 16ms, the new driver (@250 kbps data rate) has as RTT of ~3ms (depending on SPI clock and on CPU performance) (measured with ping6). - Increased reliability: The preamble size and the sync word size have been doubled compared to the old driver (preamble: 8 bytes instead of 4, sync word: 4 byte instead of 2). The new values are the once recommended by the data sheet for reliable communication. - Basic diagnostic during driver initialization to detect common issues as SPI communication issues and GDO pin configuration/wiring issues. - TX power configuration with netdev_driver_t::set() API-integration - Calls to netdev_driver_t::send() block until the transmission has completed to ease the use of the API (implemented without busy waiting, so that the MCU can enter lower power states or other threads can be executed). --- Makefile.dep | 2 +- drivers/Makefile.dep | 14 + drivers/Makefile.include | 4 + drivers/cc110x/Makefile | 1 + drivers/cc110x/cc110x.c | 173 +++++ drivers/cc110x/cc110x_calibration.c | 141 ++++ drivers/cc110x/cc110x_chanmaps.c | 74 ++ drivers/cc110x/cc110x_communication.c | 115 ++++ drivers/cc110x/cc110x_configs.c | 65 ++ drivers/cc110x/cc110x_netdev.c | 623 +++++++++++++++++ drivers/cc110x/cc110x_patables.c | 67 ++ drivers/cc110x/cc110x_rx_tx.c | 326 +++++++++ drivers/cc110x/cc110x_settings.c | 330 +++++++++ drivers/cc110x/include/cc110x_calibration.h | 49 ++ drivers/cc110x/include/cc110x_communication.h | 213 ++++++ drivers/cc110x/include/cc110x_constants.h | 522 +++++++++++++++ drivers/cc110x/include/cc110x_internal.h | 83 +++ drivers/cc110x/include/cc110x_netdev.h | 47 ++ drivers/cc110x/include/cc110x_params.h | 99 +++ drivers/cc110x/include/cc110x_rx_tx.h | 47 ++ drivers/cc110x/include/cc110x_settings.h | 170 +++++ drivers/include/cc110x.h | 633 ++++++++++++++++++ makefiles/pseudomodules.inc.mk | 5 + sys/auto_init/auto_init.c | 5 + sys/auto_init/netif/auto_init_cc110x.c | 60 +- 25 files changed, 3838 insertions(+), 30 deletions(-) create mode 100644 drivers/cc110x/Makefile create mode 100644 drivers/cc110x/cc110x.c create mode 100644 drivers/cc110x/cc110x_calibration.c create mode 100644 drivers/cc110x/cc110x_chanmaps.c create mode 100644 drivers/cc110x/cc110x_communication.c create mode 100644 drivers/cc110x/cc110x_configs.c create mode 100644 drivers/cc110x/cc110x_netdev.c create mode 100644 drivers/cc110x/cc110x_patables.c create mode 100644 drivers/cc110x/cc110x_rx_tx.c create mode 100644 drivers/cc110x/cc110x_settings.c create mode 100644 drivers/cc110x/include/cc110x_calibration.h create mode 100644 drivers/cc110x/include/cc110x_communication.h create mode 100644 drivers/cc110x/include/cc110x_constants.h create mode 100644 drivers/cc110x/include/cc110x_internal.h create mode 100644 drivers/cc110x/include/cc110x_netdev.h create mode 100644 drivers/cc110x/include/cc110x_params.h create mode 100644 drivers/cc110x/include/cc110x_rx_tx.h create mode 100644 drivers/cc110x/include/cc110x_settings.h create mode 100644 drivers/include/cc110x.h diff --git a/Makefile.dep b/Makefile.dep index c4d9b80450bf..afc3d5d61b26 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -164,7 +164,7 @@ ifneq (,$(filter gnrc_netif,$(USEMODULE))) endif endif -ifneq (,$(filter ieee802154 nrfmin esp_now gnrc_sixloenc,$(USEMODULE))) +ifneq (,$(filter ieee802154 nrfmin esp_now cc110x gnrc_sixloenc,$(USEMODULE))) ifneq (,$(filter gnrc_ipv6, $(USEMODULE))) USEMODULE += gnrc_sixlowpan endif diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 25c3a8db8570..a04ba5f49144 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -81,6 +81,20 @@ ifneq (,$(filter bm%280,$(USEMODULE))) USEMODULE += bmx280 endif +ifneq (,$(filter cc110%,$(USEMODULE))) + USEMODULE += cc110x + USEMODULE += cc1xxx_common + USEMODULE += luid + USEMODULE += netif + USEMODULE += xtimer + FEATURES_REQUIRED += periph_gpio + FEATURES_REQUIRED += periph_gpio_irq + FEATURES_REQUIRED += periph_spi + ifneq (,$(filter gnrc_ipv6,$(USEMODULE))) + USEMODULE += gnrc_sixlowpan + endif +endif + ifneq (,$(filter cc2420,$(USEMODULE))) USEMODULE += xtimer USEMODULE += luid diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 27723b0e0925..6a6f9d5e45c2 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -42,6 +42,10 @@ ifneq (,$(filter bmx280,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bmx280/include endif +ifneq (,$(filter cc110x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cc110x/include +endif + ifneq (,$(filter cc2420,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cc2420/include endif diff --git a/drivers/cc110x/Makefile b/drivers/cc110x/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/drivers/cc110x/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/cc110x/cc110x.c b/drivers/cc110x/cc110x.c new file mode 100644 index 000000000000..a60323aaaa3a --- /dev/null +++ b/drivers/cc110x/cc110x.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Implementation for the "public" API of the CC1100/CC1101 driver + * + * @author Marian Buschsieweke + * @} + */ + +#include +#include + +#include "cc110x.h" +#include "cc110x_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params) +{ + if (!dev || !params) { + return -EINVAL; + } + + /* Zero out everything but RIOT's driver interface, which should be + * managed by RIOT + */ + memset((char *)dev + sizeof(netdev_t), 0x00, + sizeof(cc110x_t) - sizeof(netdev_t)); + dev->params = *params; + dev->netdev.driver = &cc110x_driver; + dev->state = CC110X_STATE_OFF; + return 0; +} + +int cc110x_apply_config(cc110x_t *dev, const cc110x_config_t *conf, + const cc110x_chanmap_t *chanmap) +{ + DEBUG("[cc110x] Applying new configuration\n"); + if (!dev || !chanmap) { + return -EINVAL; + } + + if (cc110x_acquire(dev) != SPI_OK) { + return -EIO; + } + + gpio_irq_disable(dev->params.gdo0); + gpio_irq_disable(dev->params.gdo2); + + /* Go to IDLE state to allow reconfiguration */ + cc110x_cmd(dev, CC110X_STROBE_IDLE); + dev->state = CC110X_STATE_IDLE; + + if (conf != NULL) { + /* Write all three base frequency configuration bytes in one burst */ + cc110x_burst_write(dev, CC110X_REG_FREQ2, &conf->base_freq, 3); + + cc110x_write(dev, CC110X_REG_FSCTRL1, conf->fsctrl1); + cc110x_write(dev, CC110X_REG_MDMCFG4, conf->mdmcfg4); + cc110x_write(dev, CC110X_REG_MDMCFG3, conf->mdmcfg3); + cc110x_write(dev, CC110X_REG_DEVIATN, conf->deviatn); + } + + /* Set current channel to zero, as the new map might not support the current + * virtual channel number. cc110x_full_calibration() will tune in that + * channel after calibration. + */ + dev->channel = 0; + dev->channels = chanmap; + cc110x_release(dev); + + /* prepare hopping will call cc110x_enter_rx_mode(), which restores the IRQs */ + return cc110x_full_calibration(dev); +} + +int cc110x_set_tx_power(cc110x_t *dev, cc110x_tx_power_t power) +{ + DEBUG("[cc110x] Applying TX power setting at index %u\n", (unsigned)power); + if (!dev) { + return -EINVAL; + } + + if ((unsigned)power >= CC110X_TX_POWER_NUMOF) { + return -ERANGE; + } + + if (cc110x_acquire(dev) != SPI_OK) { + return -EIO; + } + + switch (dev->state) { + case CC110X_STATE_IDLE: + /* falls through */ + case CC110X_STATE_RX_MODE: + break; + default: + cc110x_release(dev); + return -EAGAIN; + } + + uint8_t frend0 = 0x10 | (uint8_t)power; + cc110x_write(dev, CC110X_REG_FREND0, frend0); + dev->tx_power = power; + cc110x_release(dev); + return 0; +} + +int cc110x_set_channel(cc110x_t *dev, uint8_t channel) +{ + DEBUG("[cc110x] Hopping to channel %i\n", (int)channel); + if (!dev) { + return -EINVAL; + } + + if (cc110x_acquire(dev) != SPI_OK) { + return -EIO; + } + + if ((channel >= CC110X_MAX_CHANNELS) || (dev->channels->map[channel] == 0xff)) { + /* Channel out of range or not supported in current channel map */ + cc110x_release(dev); + return -ERANGE; + } + + switch (dev->state) { + case CC110X_STATE_IDLE: + /* falls through */ + case CC110X_STATE_RX_MODE: + /* falls through */ + case CC110X_STATE_FSTXON: + /* Above states are fine for hopping */ + break; + default: + /* All other states do not allow hopping right now */ + cc110x_release(dev); + return -EAGAIN; + } + + /* Disable IRQs, as e.g. PLL indicator will go LOW in IDLE state */ + gpio_irq_disable(dev->params.gdo0); + gpio_irq_disable(dev->params.gdo2); + + /* Go to IDLE state to disable frequency synchronizer */ + cc110x_cmd(dev, CC110X_STROBE_IDLE); + + /* Upload new channel and corresponding calibration data */ + cc110x_write(dev, CC110X_REG_CHANNR, dev->channels->map[channel]); + + uint8_t caldata[] = { + dev->fscal.fscal3, dev->fscal.fscal2, dev->fscal.fscal1[channel] + }; + cc110x_burst_write(dev, CC110X_REG_FSCAL3, caldata, sizeof(caldata)); + + /* Start listening on the new channel (restores IRQs) */ + cc110x_enter_rx_mode(dev); + + dev->channel = channel; + cc110x_release(dev); + + dev->netdev.event_callback(&dev->netdev, NETDEV_EVENT_FHSS_CHANGE_CHANNEL); + return 0; +} diff --git a/drivers/cc110x/cc110x_calibration.c b/drivers/cc110x/cc110x_calibration.c new file mode 100644 index 000000000000..f530a067c6d2 --- /dev/null +++ b/drivers/cc110x/cc110x_calibration.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Implementation of the manual calibration facility of the + * CC1100/CC1101 driver + * + * @author Marian Buschsieweke + * @} + */ + +#include +#include + +#include "periph/gpio.h" +#include "xtimer.h" + +#include "cc110x.h" +#include "cc110x_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief Read the calibration data from the transceiver and store it + * + * @param dev Device descriptor of the transceiver + * + * @pre @p dev is acquired using @p cc110x_acquire + */ +static inline void get_calibration_data(cc110x_t *dev) +{ + char caldata[3]; + + cc110x_burst_read(dev, CC110X_REG_FSCAL3, caldata, sizeof(caldata)); + dev->fscal.fscal3 = caldata[0]; + dev->fscal.fscal2 = caldata[1]; + dev->fscal.fscal1[dev->channel] = caldata[2]; +} + +int cc110x_recalibrate(cc110x_t *dev) +{ + /* Sadly we cannot use GDO0 to check for calibration, as it only + * provides output in RX/TX state. But after successful manual + * calibration, the device returns to IDLE state. Thus, we keep + * calibrating until IDLE state is reached + */ + do { + /* Start calibration */ + cc110x_cmd(dev, CC110X_STROBE_CALIBRATE); + /* Release SPI interface to give other threads a chance to use it */ + cc110x_release(dev); + /* Manual calibration take 735 micro seconds (see Table 34 on page + * 54 in the date sheet). We'll wait 750 to be sure + */ + xtimer_usleep(750); + + /* Re-acquire SPI interface in order to check if calibration + * succeeded + */ + if (cc110x_acquire(dev) != SPI_OK) { + return -EIO; + } + } while (cc110x_state_from_status(cc110x_status(dev)) != CC110X_STATE_IDLE); + + get_calibration_data(dev); + + return 0; +} + +int cc110x_full_calibration(cc110x_t *dev) +{ + DEBUG("[cc110x] Obtaining calibration data for fast channel hopping\n"); + if (!dev) { + return -EINVAL; + } + + if (cc110x_acquire(dev) != SPI_OK) { + return -EIO; + } + + switch (dev->state) { + case CC110X_STATE_IDLE: + /* falls through */ + case CC110X_STATE_RX_MODE: + /* falls through */ + case CC110X_STATE_FSTXON: + /* Current state is fine for deliberate calibration */ + break; + default: + /* Current state prevents deliberate calibration */ + cc110x_release(dev); + return -EAGAIN; + } + + uint8_t old_channel = dev->channel; + + /* Disable interrupts on GDO pins */ + gpio_irq_disable(dev->params.gdo0); + gpio_irq_disable(dev->params.gdo2); + + /* While waiting for calibration to be done, another thread could + * be scheduled. Setting the state should prevent other threads from + * messing around with the driver + */ + dev->state = CC110X_STATE_CALIBRATE; + + /* Go to IDLE to allow setting the channel */ + cc110x_cmd(dev, CC110X_STROBE_IDLE); + + for (dev->channel = 0; dev->channel < CC110X_MAX_CHANNELS; dev->channel++) { + uint8_t phy_chan = dev->channels->map[dev->channel]; + if (phy_chan == 0xff) { + /* Channel not supported by channel map */ + continue; + } + /* Set the channel to calibrate for fast hopping */ + cc110x_write(dev, CC110X_REG_CHANNR, phy_chan); + + if (cc110x_recalibrate(dev)) { + /* cc110x_recalibrate() release device on error */ + return -EIO; + } + } + + /* Update device to reflect current transceiver state */ + dev->state = CC110X_STATE_IDLE; + cc110x_release(dev); + + /* Hop back to old channel, IRQs are restored by cc110x_set_channel */ + return cc110x_set_channel(dev, old_channel); +} diff --git a/drivers/cc110x/cc110x_chanmaps.c b/drivers/cc110x/cc110x_chanmaps.c new file mode 100644 index 000000000000..49c82bb3ae88 --- /dev/null +++ b/drivers/cc110x/cc110x_chanmaps.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Channel maps that translate "virtual" channels to "physical" + * channels. + * + * @author Marian Buschsieweke + * @} + */ + +#include "cc110x.h" +#include "cc110x_internal.h" + +const cc110x_chanmap_t cc110x_chanmap_433mhz_300khz = { + .map = { + 0, /*< base + 0.000MHz = 433.225 MHz (up to 350 kHz wide channel) */ + 7, /*< base + 0.350MHz = 433.575 MHz (up to 350 kHz wide channel) */ + 14, /*< base + 0.700MHz = 433.925 MHz (up to 350 kHz wide channel) */ + 21, /*< base + 1.050MHz = 434.275 MHz (up to 350 kHz wide channel) */ + 28, /*< base + 1.400MHz = 434.625 MHz (only up to *330* kHz wide) */ + 255, /*< License free range (433.05 MHz - 434.79 MHz) exhausted :-( */ + 255, /*< License free range (433.05 MHz - 434.79 MHz) exhausted :-( */ + 255, /*< License free range (433.05 MHz - 434.79 MHz) exhausted :-( */ + } +}; + +const cc110x_chanmap_t cc110x_chanmap_433mhz_50khz = { + .map = { + 0, /*< base + 0.000MHz = 433.100 MHz (LDP433 Channel 2) */ + 4, /*< base + 0.200MHz = 433.300 MHz (LDP433 Channel 10)*/ + 8, /*< base + 0.400MHz = 433.500 MHz (LDP433 Channel 18) */ + 12, /*< base + 0.600MHz = 433.700 MHz (LDP433 Channel 26) */ + 16, /*< base + 0.800MHz = 433.900 MHz (LDP433 Channel 34) */ + 20, /*< base + 1.000MHz = 434.100 MHz (LDP433 Channel 42) */ + 24, /*< base + 1.200MHz = 434.300 MHz (LDP433 Channel 50) */ + 28, /*< base + 1.400MHz = 434.500 MHz (LDP433 Channel 58) */ + } +}; + +const cc110x_chanmap_t cc110x_chanmap_433mhz_50khz_alt = { + .map = { + 2, /*< base + 0.100MHz = 433.200 MHz (LDP433 Channel 6) */ + 6, /*< base + 0.300MHz = 433.400 MHz (LDP433 Channel 14)*/ + 10, /*< base + 0.500MHz = 433.600 MHz (LDP433 Channel 22) */ + 14, /*< base + 0.700MHz = 433.800 MHz (LDP433 Channel 30) */ + 18, /*< base + 0.900MHz = 434.000 MHz (LDP433 Channel 38) */ + 22, /*< base + 1.100MHz = 434.200 MHz (LDP433 Channel 46) */ + 26, /*< base + 1.300MHz = 434.400 MHz (LDP433 Channel 54) */ + 30, /*< base + 1.500MHz = 434.600 MHz (LDP433 Channel 62) */ + } +}; + +const cc110x_chanmap_t cc110x_chanmap_868mhz_lora = { + .map = { + 0, /*< base + 0.000MHz = 865.20 MHz = LoRa868 Channel 10 */ + 6, /*< base + 0.300MHz = 865.50 MHz = LoRa868 Channel 11 */ + 12, /*< base + 0.600MHz = 865.80 MHz = LoRa868 Channel 12 */ + 18, /*< base + 0.900MHz = 866.10 MHz = LoRa868 Channel 13 */ + 24, /*< base + 1.200MHz = 866.40 MHz = LoRa868 Channel 14 */ + 30, /*< base + 1.500MHz = 866.70 MHz = LoRa868 Channel 15 */ + 36, /*< base + 1.800MHz = 867.00 MHz = LoRa868 Channel 16 */ + 56, /*< base + 2.800MHz = 868.00 MHz = LoRa868 Channel 17 */ + } +}; diff --git a/drivers/cc110x/cc110x_communication.c b/drivers/cc110x/cc110x_communication.c new file mode 100644 index 000000000000..a6f3134504a9 --- /dev/null +++ b/drivers/cc110x/cc110x_communication.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Functions to communicate with the CC1100/CC1101 transceiver + * + * @author Marian Buschsieweke + * @} + */ + +#include +#include "periph/gpio.h" +#include "periph/spi.h" +#include "xtimer.h" +#include "cc110x.h" +#include "cc110x_constants.h" + +int cc110x_power_on(cc110x_t *dev) +{ + gpio_t cs = dev->params.cs; + + if (gpio_init(cs, GPIO_OUT)) { + return -EIO; + } + gpio_clear(cs); + xtimer_usleep(150); + gpio_set(cs); + spi_init_cs(dev->params.spi, dev->params.cs); + return 0; +} + +uint8_t cc110x_read(cc110x_t *dev, uint8_t addr, uint8_t *dest) +{ + uint8_t status; + + addr |= CC110X_SINGLE_BYTE_READ; + spi_transfer_bytes(dev->params.spi, dev->params.cs, true, + &addr, &status, 1); + spi_transfer_bytes(dev->params.spi, dev->params.cs, false, NULL, dest, 1); + return status; +} + +uint8_t cc110x_read_reliable(cc110x_t *dev, uint8_t addr, uint8_t *dest) +{ + uint8_t status, tmp; + + do { + cc110x_read(dev, addr, &tmp); + status = cc110x_read(dev, addr, dest); + } while (*dest != tmp); + + return status; +} + +uint8_t cc110x_write(cc110x_t *dev, uint8_t addr, uint8_t data) +{ + uint8_t status; + + addr |= CC110X_SINGLE_BYTE_WRITE; + spi_transfer_bytes(dev->params.spi, dev->params.cs, true, + &addr, &status, 1); + spi_transfer_bytes(dev->params.spi, dev->params.cs, false, &data, NULL, 1); + return status; +} + +uint8_t cc110x_burst_read(cc110x_t *dev, uint8_t addr, void *dest, size_t len) +{ + uint8_t status; + + addr |= CC110X_BURST_READ; + spi_transfer_bytes(dev->params.spi, dev->params.cs, true, + &addr, &status, 1); + spi_transfer_bytes(dev->params.spi, dev->params.cs, false, NULL, dest, len); + return status; +} + +uint8_t cc110x_burst_write(cc110x_t *dev, uint8_t addr, + const void *src, size_t len) +{ + uint8_t status; + + addr |= CC110X_BURST_WRITE; + spi_transfer_bytes(dev->params.spi, dev->params.cs, true, + &addr, &status, 1); + spi_transfer_bytes(dev->params.spi, dev->params.cs, false, src, NULL, len); + return status; +} + +uint8_t cc110x_cmd(cc110x_t *dev, uint8_t cmd_strobe) +{ + uint8_t status; + + spi_transfer_bytes(dev->params.spi, dev->params.cs, false, + &cmd_strobe, &status, 1); + return status; +} + +uint8_t cc110x_status(cc110x_t *dev) +{ + uint8_t status; + + do { + status = cc110x_cmd(dev, CC110X_STROBE_STATUS); + } while (status != cc110x_cmd(dev, CC110X_STROBE_STATUS)); + return status; +} diff --git a/drivers/cc110x/cc110x_configs.c b/drivers/cc110x/cc110x_configs.c new file mode 100644 index 000000000000..540806e018b9 --- /dev/null +++ b/drivers/cc110x/cc110x_configs.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Transceiver configuration for different base bands, modulation + * rate and channel bandwidth. + * + * @author Marian Buschsieweke + * @} + */ + +#include "cc110x.h" +#include "cc110x_internal.h" + +const cc110x_config_t cc110x_config_433mhz_250kbps_300khz = { + /* 0x10A99A * 26MHz / 65536 = 433.2252 MHz (LPD433 Channel 7) + * + * This is 175 kHz above lower end of the license free range, thus up to 5 + * 350 kHz wide channels can be used (see @ref cc110x_conf_t::deviatn). + */ + .base_freq = { 0x10, 0xA9, 0x9A }, + /* Intermediate frequency: 0x0C * 26MHz / 1024 = 304.7kHz */ + .fsctrl1 = 0x0C, + /* 541.67 kHz channel filter bandwidth */ + .mdmcfg4 = 0x2D, + /* 250 kBaud symbol rate ==> 250 kbps data rate with GFSK */ + .mdmcfg3 = 0x3B, + /* Deviation of +- 126.953 kHz ==> channel bandwidth about 300 kHz */ + .deviatn = 0x62, +}; + +const cc110x_config_t cc110x_config_433mhz_38kbps_50khz = { + /* 0x10A85F * 26MHz / 65536 = 433.1002 MHz (LPD433 Channel 2) */ + .base_freq = { 0x10, 0xA8, 0x5F }, + /* Intermediate frequency: 0x06 * 26000kHz / 1024 = 152.3kHz */ + .fsctrl1 = 0x06, + /* 101.5625 kHz channel filter bandwidth */ + .mdmcfg4 = 0xCA, + /* 38.38 kBaud symbol rate ==> 38.38 kbps data rate with GFSK */ + .mdmcfg3 = 0x83, + /* Deviation of +- 20.63 kHz ==> channel bandwidth about 50 kHz */ + .deviatn = 0x35, +}; + +const cc110x_config_t cc110x_config_868mhz_250kbps_300khz = { + /* 0x2146e4 * 26MHz / 65536 = 865.1998 MHz (LoRa 868 Channel 10) */ + .base_freq = { 0x21, 0x46, 0xE4 }, + /* Intermediate frequency: 0x0C * 26MHz / 1024 = 304.7kHz */ + .fsctrl1 = 0x0C, + /* 541.67 kHz channel filter bandwidth */ + .mdmcfg4 = 0x2D, + /* 250 kBaud symbol rate ==> 250 kbps data rate with GFSK */ + .mdmcfg3 = 0x3B, + /* Deviation of +- 126.953 kHz ==> channel bandwidth about 300 kHz */ + .deviatn = 0x62, +}; diff --git a/drivers/cc110x/cc110x_netdev.c b/drivers/cc110x/cc110x_netdev.c new file mode 100644 index 000000000000..1f34ce9dac87 --- /dev/null +++ b/drivers/cc110x/cc110x_netdev.c @@ -0,0 +1,623 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Implementation of RIOT's netdev_driver API for the CC1100/CC1101 + * transceiver + * + * @author Marian Buschsieweke + * @} + */ + +#include +#include + +#include "assert.h" +#include "iolist.h" +#include "irq.h" +#include "luid.h" +#include "mutex.h" +#include "net/eui64.h" +#include "net/netdev.h" +#include "xtimer.h" + +#include "cc110x.h" +#include "cc110x_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static int cc110x_init(netdev_t *netdev); +static int cc110x_recv(netdev_t *netdev, void *buf, size_t len, void *info); +static int cc110x_send(netdev_t *netdev, const iolist_t *iolist); +static int cc110x_get(netdev_t *netdev, netopt_t opt, + void *val, size_t max_len); +static int cc110x_set(netdev_t *netdev, netopt_t opt, + const void *val, size_t len); + +/** + * @brief A lookup table to convert from dBm value to the best matching + * @ref cc110x_tx_power_t value + */ +static const int8_t tx_power_from_dbm[] = { + [CC110X_TX_POWER_MINUS_30_DBM] = -25, + [CC110X_TX_POWER_MINUS_20_DBM] = -17, + [CC110X_TX_POWER_MINUS_15_DBM] = -12, + [CC110X_TX_POWER_MINUS_10_DBM] = -5, + [CC110X_TX_POWER_0_DBM] = 3, + [CC110X_TX_POWER_PLUS_5_DBM] = 6, + [CC110X_TX_POWER_PLUS_7_DBM] = 9, +}; + +/** + * @brief A lookup table to convert an @ref cc110x_tx_power_t value to dBm + */ +static const int8_t dbm_from_tx_power[] = { + [CC110X_TX_POWER_MINUS_30_DBM] = -30, + [CC110X_TX_POWER_MINUS_20_DBM] = -20, + [CC110X_TX_POWER_MINUS_15_DBM] = -15, + [CC110X_TX_POWER_MINUS_10_DBM] = -10, + [CC110X_TX_POWER_0_DBM] = 0, + [CC110X_TX_POWER_PLUS_5_DBM] = 5, + [CC110X_TX_POWER_PLUS_7_DBM] = 7, + [CC110X_TX_POWER_PLUS_10_DBM] = 10, +}; + +const netdev_driver_t cc110x_driver = { + .init = cc110x_init, + .recv = cc110x_recv, + .send = cc110x_send, + .isr = cc110x_isr, + .get = cc110x_get, + .set = cc110x_set, +}; + +void cc110x_on_gdo(void *_dev) +{ + cc110x_t *dev = _dev; + if ((dev->state & 0x07) == CC110X_STATE_TX_MODE) { + /* Unlock mutex to unblock netdev thread */ + mutex_unlock(&dev->isr_signal); + } + else { + dev->netdev.event_callback(&dev->netdev, NETDEV_EVENT_ISR); + } +} + +static int identify_device(cc110x_t *dev) +{ + uint8_t partnum, version, status; + int is_ready; + cc110x_state_t state; + + cc110x_read(dev, CC110X_REG_VERSION, &version); + /* Retrieving the status is reliable for non-transient status */ + status = cc110x_read(dev, CC110X_REG_PARTNUM, &partnum); + state = cc110x_state_from_status(status); + /* Most significant bit should be zero, otherwise chip is not ready */ + is_ready = cc110x_is_ready_from_status(status); + + DEBUG("[cc110x] PARTNUM = %i, VERSION = %i, STATUS = 0x%02x, READY = %i\n", + (int)partnum, (int)version, (int)status, is_ready); + + if ((state != CC110X_STATE_IDLE) || (!is_ready)) { + DEBUG("[cc110x] IC not ready or in invalid state\n"); + return -1; + } + + /* Source: https://e2e.ti.com/support/wireless-connectivity/other-wireless/f/667/t/370643 */ + if (partnum != 0) { + DEBUG("[cc110x] Device not a CC110x transceiver\n"); + return -1; + } + + switch (version) { + case 3: + DEBUG("[cc110x] Detected CC1100 transceiver\n"); + /* RSSI offset is 78dBm @ 868MHz & 250kBaud. + * Depends on the symbol rate and base band and ranges from + * 74dBm to 79dBm. + */ + dev->rssi_offset = 78; + return 0; + case 5: + DEBUG("[cc110x] Detected CC1100E transceiver\n"); + /* RSSI offset is 79 dBm @ 250kbps & 250 kbps. + * Depends on base band and symbol rate and ranges from + * 75dBm to 79dBm + */ + dev->rssi_offset = 79; + return 0; + case 4: + /* falls through */ + case 14: + /* falls through */ + case 20: + /* RSSI offset for the CC1101 is independent of symbol rate and + * base 74 dBm + */ + dev->rssi_offset = 74; + DEBUG("[cc110x] Detected CC1101 transceiver\n"); + return 0; + default: + DEBUG("[cc110x] Device not a CC110x transceiver\n"); + return -1; + } +} + +static int check_config(cc110x_t *dev) +{ + char buf[CC110X_CONF_SIZE]; + + /* Verify content of main config registers */ + cc110x_burst_read(dev, CC110X_CONF_START, buf, sizeof(buf)); + if (memcmp(buf, cc110x_conf, sizeof(buf))) { + DEBUG("[cc110x] ERROR: Verification of main config registers failed\n" + " Check SPI wiring or reduce SPI clock\n"); + return -1; + } + + /* Verify content of "magic number" config registers */ + cc110x_burst_read(dev, CC110X_REG_TEST2, buf, + sizeof(cc110x_magic_registers)); + if (memcmp(buf, cc110x_magic_registers, sizeof(cc110x_magic_registers))) { + DEBUG("[cc110x] ERROR: Verification of \"magic\" registers failed\n" + " Check SPI wiring or reduce SPI clock\n"); + return -1; + } + + /* Verify content of PA_TABLE */ + cc110x_burst_read(dev, CC110X_MULTIREG_PATABLE, buf, CC110X_PATABLE_LEN); + if (memcmp(buf, dev->params.patable->data, CC110X_PATABLE_LEN)) { + DEBUG("[cc110x] ERROR: Verification of PA_TABLE failed\n" + " Check SPI wiring or reduce SPI clock\n"); + return -1; + } + + DEBUG("[cc110x] Content of configuration registers verified\n"); + return 0; +} + +static int check_gdo_pins(cc110x_t *dev) +{ + /* GPIOs connected to GDOs are not yet configured, so we do this now. + * This configuration is just temporarily for testing, as gpio_init_int() + * will reconfigure them later again. We do not want to set up the + * interrupts before validating the transceiver, so we effectively configure + * the GPIOs twice. + */ + if (gpio_init(dev->params.gdo2, GPIO_IN)) { + DEBUG("[cc110x] Configuring GDO2 failed"); + return -1; + } + + if (gpio_init(dev->params.gdo0, GPIO_IN)) { + DEBUG("[cc110x] Configuring GDO0 failed"); + return -1; + } + + /* Validate that GDO2 responds to configuration updates */ + cc110x_write(dev, CC110X_REG_IOCFG2, CC110X_GDO_CONSTANT_HIGH); + if (!gpio_read(dev->params.gdo2)) { + DEBUG("[cc110x] GDO2 does not respond (check wiring!)\n"); + return -1; + } + + cc110x_write(dev, CC110X_REG_IOCFG2, CC110X_GDO_CONSTANT_LOW); + if (gpio_read(dev->params.gdo2)) { + DEBUG("[cc110x] GDO2 does not respond (check wiring!)\n"); + return -1; + } + + /* Validate that GDO0 responds to configuration updates */ + cc110x_write(dev, CC110X_REG_IOCFG0, CC110X_GDO_CONSTANT_HIGH); + if (!gpio_read(dev->params.gdo0)) { + DEBUG("[cc110x] GDO0 does not respond (check wiring!)\n"); + return -1; + } + + cc110x_write(dev, CC110X_REG_IOCFG0, CC110X_GDO_CONSTANT_LOW); + if (gpio_read(dev->params.gdo0)) { + DEBUG("[cc110x] GDO0 does not respond (check wiring!)\n"); + return -1; + } + + /* Restore default GDO2 & GDO0 config */ + cc110x_write(dev, CC110X_REG_IOCFG2, cc110x_conf[CC110X_REG_IOCFG2]); + cc110x_write(dev, CC110X_REG_IOCFG0, cc110x_conf[CC110X_REG_IOCFG0]); + + return 0; +} + +static int cc110x_init(netdev_t *netdev) +{ + cc110x_t *dev = (cc110x_t *)netdev; + /* Use locked mutex to block thread on TX and un-block from ISR */ + mutex_init(&dev->isr_signal); + mutex_lock(&dev->isr_signal); + + /* Make sure the crystal is stable and the chip ready. This is needed as + * the reset is done via an SPI command, but the SPI interface must not be + * used unless the chip is ready according to the data sheet. After the + * reset, a second call to cc110x_power_on() is needed to finally have + * the transceiver in a known state and ready for SPI communication. + */ + if (cc110x_power_on(dev)) { + DEBUG("[cc110x] netdev_driver_t::init(): Failed to pull CS pin low\n"); + return -EIO; + } + + if (cc110x_acquire(dev) != SPI_OK) { + DEBUG("[cc110x] netdev_driver_t::init(): Failed to setup/acquire SPI " + "interface\n"); + return -EIO; + } + + /* Performing a reset of the transceiver to get it in a known state */ + cc110x_cmd(dev, CC110X_STROBE_RESET); + cc110x_release(dev); + + /* Again, make sure the crystal is stable and the chip ready */ + if (cc110x_power_on(dev)) { + DEBUG("[cc110x] netdev_driver_t::init(): Failed to pull CS pin low " + "after reset\n"); + return -EIO; + } + + if (cc110x_acquire(dev) != SPI_OK) { + DEBUG("[cc110x] netdev_driver_t::init(): Failed to setup/acquire SPI " + "interface after reset\n"); + return -EIO; + } + + if (identify_device(dev)) { + DEBUG("[cc110x] netdev_driver_t::init(): Device identification failed\n"); + cc110x_release(dev); + return -ENOTSUP; + } + + /* Upload the main configuration */ + cc110x_burst_write(dev, CC110X_CONF_START, cc110x_conf, CC110X_CONF_SIZE); + /* Set TX power to match uploaded configuration */ + dev->tx_power = CC110X_TX_POWER_0_DBM; + + /* Upload the poorly documented magic numbers obtained via SmartRF Studio */ + cc110x_burst_write(dev, CC110X_REG_TEST2, cc110x_magic_registers, + sizeof(cc110x_magic_registers)); + + /* Setup the selected PA_TABLE */ + cc110x_burst_write(dev, CC110X_MULTIREG_PATABLE, + dev->params.patable->data, CC110X_PATABLE_LEN); + + /* Verify main config, magic numbers and PA_TABLE correctly uploaded */ + if (check_config(dev)) { + cc110x_release(dev); + return -EIO; + } + + /* Verify that pins GDO2 and GDO0 are correctly connected */ + if (check_gdo_pins(dev)) { + cc110x_release(dev); + return -EIO; + } + + /* Setup the layer 2 address, but do not accept CC110X_L2ADDR_AUTO (which + * has the value 0x00 and is used for broadcast) + */ + dev->addr = dev->params.l2addr; + while (dev->addr == CC110X_L2ADDR_AUTO) { + luid_get(&dev->addr, 1); + } + cc110x_write(dev, CC110X_REG_ADDR, dev->addr); + + /* Setup interrupt on GDO0 */ + if (gpio_init_int(dev->params.gdo0, GPIO_IN, GPIO_BOTH, + cc110x_on_gdo, dev)) { + cc110x_release(dev); + DEBUG("[cc110x] netdev_driver_t::init(): Failed to setup interrupt on " + "GDO0 pin\n"); + return -EIO; + } + + /* Setup interrupt on GDO2 */ + if (gpio_init_int(dev->params.gdo2, GPIO_IN, GPIO_BOTH, + cc110x_on_gdo, dev)) { + gpio_irq_disable(dev->params.gdo0); + cc110x_release(dev); + DEBUG("[cc110x] netdev_driver_t::init(): Failed to setup interrupt on " + "GDO2 pin\n"); + return -EIO; + } + + /* Update the state of the driver/transceiver */ + dev->state = CC110X_STATE_IDLE; + cc110x_release(dev); + + + int retval; /*< Store return value to be able to pass through error code */ + /* Apply configuration (if non-NULL) and channel map, which also calls + * cc110x_full_calibration + */ + retval = cc110x_apply_config(dev, dev->params.config, dev->params.channels); + if (retval) { + gpio_irq_disable(dev->params.gdo0); + gpio_irq_disable(dev->params.gdo2); + DEBUG("[cc110x] netdev_driver_t::init(): cc110x_apply_config() " + "failed\n"); + /* Pass through received error code */ + return retval; + } + else { + DEBUG("[cc110x] netdev_driver_t::init(): Success\n"); + } + + return 0; +} + +static int cc110x_recv(netdev_t *netdev, void *buf, size_t len, void *info) +{ + cc110x_t *dev = (cc110x_t *)netdev; + + /* Call to cc110x_enter_rx_mode() will clear dev->buf.len, so back up it first */ + int size = dev->buf.len; + + if (cc110x_acquire(dev) != SPI_OK) { + DEBUG("[cc110x] netdev_driver_t::recv(): cc110x_acquire() " + "failed\n"); + return -EIO; + } + + /* Copy RX info on last frame (if requested) */ + if (info != NULL) { + *((cc1xxx_rx_info_t *)info) = dev->rx_info; + } + + if (!buf) { + /* Get the size of the frame; if len > 0 then also drop the frame */ + if (len > 0) { + /* Drop frame requested */ + cc110x_enter_rx_mode(dev); + } + cc110x_release(dev); + return size; + } + + if (len < (size_t)size) { + /* Drop frame and return -ENOBUFS */ + cc110x_enter_rx_mode(dev); + cc110x_release(dev); + return -ENOBUFS; + } + + memcpy(buf, dev->buf.data, (size_t)size); + + cc110x_enter_rx_mode(dev); + cc110x_release(dev); + return size; +} + +static int cc110x_send(netdev_t *netdev, const iolist_t *iolist) +{ + cc110x_t *dev = (cc110x_t *)netdev; + + /* assert that cc110x_send was called with valid parameters */ + assert(netdev && iolist && (iolist->iol_len == sizeof(cc1xxx_l2hdr_t))); + + if (cc110x_acquire(dev) != SPI_OK) { + DEBUG("[cc110x] netdev_driver_t::send(): cc110x_acquire() failed\n"); + return -1; + } + + switch (dev->state) { + case CC110X_STATE_FSTXON: + /* falls through */ + case CC110X_STATE_RX_MODE: + break; + case CC110X_STATE_RECEIVING: + cc110x_release(dev); + DEBUG("[cc110x] netdev_driver_t::send(): Refusing to send while " + "receiving a frame\n"); + return -EBUSY; + default: + cc110x_release(dev); + DEBUG("[cc110x] netdev_driver_t::send(): Driver state %i prevents " + "sending\n", (int)dev->state); + return -1; + } + + /* Copy data to send into frame buffer */ + size_t size = sizeof(cc1xxx_l2hdr_t); + memcpy(dev->buf.data, iolist->iol_base, sizeof(cc1xxx_l2hdr_t)); + + for (const iolist_t *iol = iolist->iol_next; iol; iol = iol->iol_next) { + if (iol->iol_len) { + if (size + iol->iol_len > CC110X_MAX_FRAME_SIZE) { + cc110x_release(dev); + DEBUG("[cc110x] netdev_driver_t::send(): Frame size of %uB " + "exceeds maximum supported size of %uB\n", + (unsigned)(size + iol->iol_len), + (unsigned)CC110X_MAX_FRAME_SIZE); + return -1; + } + memcpy(dev->buf.data + size, iol->iol_base, iol->iol_len); + size += iol->iol_len; + } + } + + dev->buf.len = (uint8_t)size; + + /* Disable IRQs, as GDO configuration will be changed now */ + gpio_irq_disable(dev->params.gdo0); + gpio_irq_disable(dev->params.gdo2); + + /* Fill the TX FIFO: First write the length, then the frame */ + dev->buf.pos = (size > CC110X_FIFO_SIZE - 1) ? CC110X_FIFO_SIZE - 1 : size; + /* cc110x_framebuf_t has the same memory layout as the device expects */ + cc110x_burst_write(dev, CC110X_MULTIREG_FIFO, + &dev->buf, dev->buf.pos + 1); + + /* Go to TX */ + cc110x_cmd(dev, CC110X_STROBE_TX); + + /* Configure GDO2 and update state */ + if (dev->buf.pos < dev->buf.len) { + /* We need to keep feeding TX FIFO */ + cc110x_write(dev, CC110X_REG_IOCFG2, CC110X_GDO_ON_TX_DATA); + dev->state = CC110X_STATE_TX_MODE; + } + else { + /* All data in TX FIFO, just waiting for transceiver to finish */ + cc110x_write(dev, CC110X_REG_IOCFG2, CC110X_GDO_CONSTANT_LOW); + dev->state = CC110X_STATE_TX_COMPLETING; + } + + cc110x_release(dev); + + /* Restore IRQs */ + gpio_irq_enable(dev->params.gdo0); + gpio_irq_enable(dev->params.gdo2); + + while ((dev->state & 0x07) == CC110X_STATE_TX_MODE) { + /* Block until mutex is unlocked from ISR */ + mutex_lock(&dev->isr_signal); + cc110x_isr(&dev->netdev); + } + + return (int)size; +} + +/** + * @brief Generate an IPv6 interface identifier for a CC110X transceiver + * + * @param dev Transceiver to create the IPv6 interface identifier (IID) + * @param iid Store the generated IID here + * + * @return Returns the size of @ref eui64_t to confirm with the API + * in @ref netdev_driver_t::get + */ +static int cc110x_get_iid(cc110x_t *dev, eui64_t *iid) +{ + static const eui64_t empty_iid = { + .uint8 = { 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00 } + }; + + *iid = empty_iid; + iid->uint8[7] = dev->addr; + return sizeof(eui64_t); +} + +static int cc110x_get(netdev_t *netdev, netopt_t opt, + void *val, size_t max_len) +{ + cc110x_t *dev = (cc110x_t *)netdev; + + switch (opt) { + case NETOPT_DEVICE_TYPE: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = NETDEV_TYPE_CC110X; + return sizeof(uint16_t); + case NETOPT_PROTO: + assert(max_len == sizeof(gnrc_nettype_t)); + *((gnrc_nettype_t *)val) = CC110X_DEFAULT_PROTOCOL; + return sizeof(gnrc_nettype_t); + case NETOPT_MAX_PACKET_SIZE: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = CC110X_MAX_FRAME_SIZE - sizeof(cc1xxx_l2hdr_t); + return sizeof(uint16_t); + case NETOPT_ADDR_LEN: + /* falls through */ + case NETOPT_SRC_LEN: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = CC1XXX_ADDR_SIZE; + return sizeof(uint16_t); + case NETOPT_ADDRESS: + assert(max_len >= CC1XXX_ADDR_SIZE); + *((uint8_t *)val) = dev->addr; + return CC1XXX_ADDR_SIZE; + case NETOPT_IPV6_IID: + if (max_len < sizeof(eui64_t)) { + return -EOVERFLOW; + } + return cc110x_get_iid(dev, val); + case NETOPT_CHANNEL: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = dev->channel; + return sizeof(uint16_t); + case NETOPT_TX_POWER: + assert(max_len == sizeof(uint16_t)); + *((uint16_t *)val) = dbm_from_tx_power[dev->tx_power]; + return sizeof(uint16_t); + default: + return -ENOTSUP; + } +} + +/** + * @brief Set the given address as the device's layer 2 address + * + * @param dev Device descripter of the transceiver + * @param addr Address to set + */ +static int cc110x_set_addr(cc110x_t *dev, uint8_t addr) +{ + if (cc110x_acquire(dev) != SPI_OK) { + return -EIO; + } + + dev->addr = addr; + cc110x_write(dev, CC110X_REG_ADDR, addr); + cc110x_release(dev); + return 1; +} + +static int cc110x_set(netdev_t *netdev, netopt_t opt, + const void *val, size_t len) +{ + (void)len; + cc110x_t *dev = (cc110x_t *)netdev; + + switch (opt) { + case NETOPT_ADDRESS: + assert(len == CC1XXX_ADDR_SIZE); + return cc110x_set_addr(dev, *((uint8_t *)val)); + case NETOPT_CHANNEL: + { + assert(len == sizeof(uint16_t)); + int retval; + uint16_t channel = *((uint16_t *)val); + if (channel >= CC110X_MAX_CHANNELS) { + return -EINVAL; + } + if ((retval = cc110x_set_channel(dev, (uint8_t)channel))) { + return retval; + } + } + return sizeof(uint16_t); + case NETOPT_TX_POWER: + { + assert(len == sizeof(int16_t)); + int16_t dbm = *((int16_t *)val); + cc110x_tx_power_t power = CC110X_TX_POWER_MINUS_30_DBM; + for ( ; power < CC110X_TX_POWER_PLUS_10_DBM; power++) { + if ((int16_t)tx_power_from_dbm[power] >= dbm) { + break; + } + } + if (cc110x_set_tx_power(dev, power)) { + return -EINVAL; + } + } + return sizeof(uint16_t); + default: + return -ENOTSUP; + } +} diff --git a/drivers/cc110x/cc110x_patables.c b/drivers/cc110x/cc110x_patables.c new file mode 100644 index 000000000000..8d1863b1c8a9 --- /dev/null +++ b/drivers/cc110x/cc110x_patables.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Default configuration of the transceiver output power for the + * different frequency bands + * + * See Section "24 Output Power Programming" on page 59 in the data sheet for + * details. + * + * @author Marian Buschsieweke + * @} + */ + +#include "cc110x.h" +#include "cc110x_internal.h" + +const cc110x_patable_t cc110x_patable_433mhz = { + .data = { + /* Settings for 433 MHz */ + 0x12, /*< -30 dBm */ + 0x0E, /*< -20 dBm */ + 0x1D, /*< -15 dBm */ + 0x34, /*< -10 dBm */ + 0x60, /*< 0 dBm */ + 0x84, /*< 5 dBm */ + 0xC8, /*< 7 dBm */ + 0xC0, /*< 10 dBm */ + } +}; + +const cc110x_patable_t cc110x_patable_868mhz = { + .data = { + /* Settings for 868 MHz */ + 0x03, /*< -30 dBm */ + 0x0F, /*< -20 dBm */ + 0x1E, /*< -15 dBm */ + 0x27, /*< -10 dBm */ + 0x50, /*< 0 dBm */ + 0x81, /*< 5 dBm */ + 0xCB, /*< 7 dBm */ + 0xC2, /*< 10 dBm */ + } +}; + +const cc110x_patable_t cc110x_patable_915mhz = { + .data = { + /* Settings for 915 MHz */ + 0x03, /*< -30 dBm */ + 0x0E, /*< -20 dBm */ + 0x1E, /*< -15 dBm */ + 0x27, /*< -10 dBm */ + 0x8E, /*< 0 dBm */ + 0xCD, /*< 5 dBm */ + 0xC7, /*< 7 dBm */ + 0xC0, /*< 10 dBm */ + } +}; diff --git a/drivers/cc110x/cc110x_rx_tx.c b/drivers/cc110x/cc110x_rx_tx.c new file mode 100644 index 000000000000..523bb882d156 --- /dev/null +++ b/drivers/cc110x/cc110x_rx_tx.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Functions to manage sending/receiving frames with the CC110x + * + * @author Marian Buschsieweke + * @} + */ + +#include "xtimer.h" +#include "cc110x.h" +#include "cc110x_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Use NETDEV_EVENT_ISR to indicate that no event needs to be passed to upper + * layer at end of ISR, as ISR will never need this event + */ +#define NETDEV_NO_EVENT NETDEV_EVENT_ISR + +void cc110x_enter_rx_mode(cc110x_t *dev) +{ + DEBUG("[cc110x] Going to RX\n"); + /* bring device to IDLE state and flush FIFOs (just in case) */ + gpio_irq_disable(dev->params.gdo0); + gpio_irq_disable(dev->params.gdo2); + cc110x_cmd(dev, CC110X_STROBE_IDLE); + cc110x_cmd(dev, CC110X_STROBE_FLUSH_RX); + cc110x_cmd(dev, CC110X_STROBE_FLUSH_TX); + dev->buf.pos = dev->buf.len = 0; + /* Apply GDO2 config and go to RX */ + cc110x_write(dev, CC110X_REG_IOCFG2, CC110X_GDO_ON_RX_DATA); + cc110x_write(dev, CC110X_REG_IOCFG0, CC110X_GDO_ON_TRANSMISSION); + cc110x_cmd(dev, CC110X_STROBE_RX); + dev->state = CC110X_STATE_RX_MODE; + gpio_irq_enable(dev->params.gdo2); + gpio_irq_enable(dev->params.gdo0); +} + +/** + * @brief Function to run when frame is fully received + * + * @param dev Device descriptor of the transceiver + * + * Intended to be called from @ref cc110x_rx_continue + */ +static netdev_event_t cc110x_rx_done(cc110x_t *dev) +{ + uint8_t lqi_crc; + int8_t rssi; + + cc110x_read(dev, CC110X_REG_LQI, &lqi_crc); + cc110x_read(dev, CC110X_REG_RSSI, (uint8_t *)&rssi); + + /* CRC_OK bit is most significant bit, see page 92 in the data sheet */ + if (!(lqi_crc & 0x80)) { + DEBUG("[cc110x] ISR: CRC error, dropping frame\n"); + /* Drop frame and go back to RX */ + cc110x_enter_rx_mode(dev); + return NETDEV_EVENT_CRC_ERROR; + } + + /* Copy all but the CRC_OK bit */ + dev->rx_info.lqi = (uint8_t)lqi_crc & 0x7f; + + /* Use the formula in section 17.3 on page 44 in the data sheet to obtain + * the correct RSSI value in dBm. + */ + dev->rx_info.rssi = (int16_t)(rssi / 2) - (int16_t)dev->rssi_offset; + + /* Transceiver has automatically gone to IDLE. We keep it in IDLE until + * upper layer fetched the frame + */ + dev->state = CC110X_STATE_FRAME_READY; + return NETDEV_EVENT_RX_COMPLETE; +} + +/** + * @brief Read a chunk of data from the RX-FIFO + * + * @param dev Device descriptor of the transceiver + * + * This function should be called from the ISR when data in the RX-FIFO is + * available or the last byte of the frame was received + */ +static netdev_event_t cc110x_rx_continue(cc110x_t *dev) +{ + uint8_t in_fifo; + netdev_event_t retval = NETDEV_NO_EVENT; + + while (gpio_read(dev->params.gdo2)) { + cc110x_read_reliable(dev, CC110X_REG_RXBYTES, &in_fifo); + + if (in_fifo & 0x80) { + /* RXFIFO_OVERFLOW bit is set (see RXBYTES on page 94) */ + DEBUG("[cc110x] ISR: RX-FIFO overflown, ISR too slow\n"); + /* Drop frame and go to RX */ + cc110x_enter_rx_mode(dev); + return NETDEV_EVENT_RX_TIMEOUT; + } + + if (!in_fifo) { + /* GDO2 will be high when data is present *or* at end of packet */ + break; + } + + /* Handle first read from RX FIFO differently from subsequent reads, as + * in first reads the Length Field is read as well + */ + if (!dev->buf.len) { + if (in_fifo < sizeof(cc1xxx_l2hdr_t) + 1) { + /* At least a frame header + Length Field (1B) is expected */ + DEBUG("[cc110x] ISR: Incoming frame smaller than header " + "--> drop\n"); + cc110x_enter_rx_mode(dev); + /* Not exactly CRC, but incorrect CRC indicates a broken frame*/ + return NETDEV_EVENT_CRC_ERROR; + } + cc110x_burst_read(dev, CC110X_MULTIREG_FIFO, &dev->buf, + in_fifo - 1); + /* Update read position in payload, that is number of bytes read + * minus the Length Filed and minus the byte left in the FIFO to not + * trigger a silicon bug + */ + dev->buf.pos = in_fifo - 2; + retval = NETDEV_EVENT_RX_STARTED; + } + else { + /* Prevent overflow of buffer */ + if (dev->buf.pos + in_fifo > CC110X_MAX_FRAME_SIZE) { + DEBUG("[cc110x] ISR: Incoming frame exceeds maximum size\n"); + cc110x_enter_rx_mode(dev); + /* Not exactly CRC, but incorrect CRC indicates a broken frame */ + return NETDEV_EVENT_CRC_ERROR; + } + + if (dev->buf.pos + in_fifo < dev->buf.len) { + /* Frame not fully received yet, keeping one byte in RX FIFO + * to prevent triggering a silicon bug + */ + in_fifo--; + } + + /* Continue reading data */ + cc110x_burst_read(dev, CC110X_MULTIREG_FIFO, + dev->buf.data + dev->buf.pos, in_fifo); + dev->buf.pos += in_fifo; + + } + } + + if (dev->buf.pos > dev->buf.len) { + DEBUG("[cc110x] ISR: Incoming frame larger than Length Field " + "--> drop\n"); + cc110x_enter_rx_mode(dev); + /* Not exactly CRC, but incorrect CRC indicates a broken frame */ + return NETDEV_EVENT_CRC_ERROR; + } + + if (!gpio_read(dev->params.gdo0)) { + /* GDO0 is low when transmission is over ==> RX complete or corrupt + frame */ + if (dev->buf.pos == dev->buf.len) { + return cc110x_rx_done(dev); + } + else { + DEBUG("[cc110x] ISR: Incoming frame smaller than Length Field " + "--> drop\n"); + cc110x_enter_rx_mode(dev); + /* Not exactly CRC, but incorrect CRC indicates a broken frame */ + return NETDEV_EVENT_CRC_ERROR; + } + } + + return retval; +} + +/** + * @brief Function to run when frame is fully send + * + * @param dev Device descriptor of the transceiver + */ +static netdev_event_t cc110x_tx_done(cc110x_t *dev) +{ + uint8_t status = cc110x_status(dev); + cc110x_state_t state = cc110x_state_from_status(status); + switch (state){ + case CC110X_STATE_SETTLING: + case CC110X_STATE_CALIBRATE: + case CC110X_STATE_TX_MODE: + /* TX still in progress, or hasn't even started yet */ + return NETDEV_NO_EVENT; + case CC110X_STATE_IDLE: + cc110x_enter_rx_mode(dev); + return NETDEV_EVENT_TX_COMPLETE; + case CC110X_STATE_TXFIFO_UNDERFLOW: + DEBUG("[cc110x] ISR: TX FIFO underflown.\n"); + break; + default: + DEBUG("[cc110x] ISR: Unknown state during TX.\n"); + break; + } + + cc110x_enter_rx_mode(dev); + /* TX timeout is the only TX-related error event known to RIOT */ + return NETDEV_EVENT_TX_TIMEOUT; +} + +/** + * @brief Refill the TX-FIFO + * + * @param dev Device descriptor of the transceiver + */ +static netdev_event_t cc110x_tx_continue(cc110x_t *dev) +{ + uint8_t in_fifo; + + cc110x_read_reliable(dev, CC110X_REG_TXBYTES, &in_fifo); + + /* most significant bit indicates TXFIFO underflow, see page 94 in the + * data sheet + */ + if (in_fifo & 0x80) { + DEBUG("[cc110x] ISR: ERROR: TX-FIFO underflown, ISR too slow\n"); + /* Abort: Flush TX and go back to RX */ + cc110x_cmd(dev, CC110X_STROBE_IDLE); + cc110x_cmd(dev, CC110X_STROBE_FLUSH_TX); + cc110x_enter_rx_mode(dev); + return NETDEV_EVENT_TX_TIMEOUT; + } + + uint8_t to_write = CC110X_FIFO_SIZE - in_fifo; + + if (to_write == 0) { + /* ISR came to early, nothing to do yet */ + return NETDEV_NO_EVENT; + } + + uint8_t left = dev->buf.len - dev->buf.pos; + to_write = (left < to_write) ? left : to_write; + + cc110x_burst_write(dev, CC110X_MULTIREG_FIFO, + dev->buf.data + dev->buf.pos, to_write); + dev->buf.pos += to_write; + + if (dev->buf.pos == dev->buf.len) { + /* All data send to the transceiver, now waiting for transceiver to + * complete transmission + */ + dev->state = CC110X_STATE_TX_COMPLETING; + /* Disable GDO2, as we do not need to further feed TX FIFO */ + cc110x_write(dev, CC110X_REG_IOCFG2, CC110X_GDO_CONSTANT_LOW); + } + + return NETDEV_NO_EVENT; +} + +void cc110x_isr(netdev_t *netdev) +{ + cc110x_t *dev = (cc110x_t *)netdev; + /* We don't want to create events while device descriptor is acquired, to + * prevent a dead lock. (Currently e.g. on NETDEV_EVENT_RX_COMPLETE the + * upper layer will immediately call netdev_driver_t::recv(), which in + * turn wants to operate on the device descriptor. We could rely on this + * behaviour by skipping cc110x_acquire() there, but the driver would break + * when upper layer behaviour is changed. By moving the event notification + * at the end of the ISR (end after cc110x_release()), the driver becomes + * agnostic to which behaviour the upper layer implements.) + */ + netdev_event_t post_isr_event = NETDEV_NO_EVENT; + + if (cc110x_acquire(dev) != SPI_OK) { + DEBUG("[cc110x] ISR: CRITICAL ERROR: Couldn't acquire device\n"); + return; + } + + /* Disable IRQs in a coarse manner, instead of doing so any time the + * IOCFGx configuration registers are changed. (This should be less + * bug prone.) + */ + gpio_irq_disable(dev->params.gdo0); + gpio_irq_disable(dev->params.gdo2); + + switch (dev->state) { + case CC110X_STATE_RX_MODE: + if (gpio_read(dev->params.gdo0) || gpio_read(dev->params.gdo2)) { + dev->state = CC110X_STATE_RECEIVING; + dev->buf.pos = dev->buf.len = 0; + } + break; + case CC110X_STATE_RECEIVING: + post_isr_event = cc110x_rx_continue(dev); + break; + case CC110X_STATE_TX_MODE: + post_isr_event = cc110x_tx_continue(dev); + break; + case CC110X_STATE_TX_COMPLETING: + post_isr_event = cc110x_tx_done(dev); + break; + default: + DEBUG("[cc110x] ISR: CRITICAL ERROR: No interrupt expected " + "for current state\n"); + /* Go back to RX and pray that solved the problem */ + cc110x_enter_rx_mode(dev); + } + + /* Re-enable IRQs again, unless device state */ + gpio_irq_enable(dev->params.gdo0); + gpio_irq_enable(dev->params.gdo2); + cc110x_release(dev); + /* Pass event to uper layer, if needed */ + if (post_isr_event != NETDEV_NO_EVENT) { + dev->netdev.event_callback(&dev->netdev, post_isr_event); + } +} diff --git a/drivers/cc110x/cc110x_settings.c b/drivers/cc110x/cc110x_settings.c new file mode 100644 index 000000000000..715fd68ec792 --- /dev/null +++ b/drivers/cc110x/cc110x_settings.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief On-chip settings for the TI CC1100/CC1101 transceiver + * + * @author Marian Buschsieweke + * @} + */ + +#include "cc110x.h" +#include "cc110x_internal.h" + +const char cc110x_conf[CC110X_CONF_SIZE] = { + /* + * IOCFG2; default: 0x29 (CHIP_RDYn) + * Invert GDO2: off, + * GDO2: Go high when RX data should be read + * + * Why not default? + * GDO2 will be used to be notified about FIFO events (e.g. refilling TX + * FIFO is needed during transmission, reading from RX FIFO is needed + * during reception) + */ + CC110X_GDO_ON_RX_DATA, + /* + * IOCFG1; default: 0x2E (3-state) + * Invert GDO1: off, + * GDO1: 3-state (required when SPI interface is shared with other devices) + */ + 0x2E, + /* + * IOCFG0; default: 0x3F (CLK_XOSC/192) + * Invert GDO0: off, + * GDO0: Go high on PLL in lock + * + * Why not default? + * GDO0 will be used to be notified when a packet is coming while in RX + * mode (will go high during transmission) and when sending is completed + * while in TX (remains high during transmission and will go back low when + * done). + */ + CC110X_GDO_ON_TRANSMISSION, + /* + * FIFOTHR; default: 0x07 + * TEST1 = 0x31 and TEST2 = 0x88 when waking up from SLEEP, + * 0dB RX attenuation, + * threshold for FIFOs: TX FIFO = 33, RX FIFO = 32 + */ + 0x07, + /* + * SYNC1, SYNC0; defaults: 0xD3, 0x91 + * Use 0xD3,0x91 as sync word + */ + 0xD3, /*< SYNC1 */ + 0x91, /*< SYNC0 */ + /* + * PKTLEN; default: 0xFF + * Packet length in bytes in fixed length mode, else maximum length + */ + 0xff, + /* + * PKTCTRL1; default: 0x04 + * PQT: Accept all sync words, regardless of preamble quality + * CRC_AUTOFLUSH: Do not auto-flush RX FIFO on incorrect CRC + * APPEND_STATUS: Do not add 2 bytes of status information in RX FIFO + * ADDR_CHK: Filter incoming frames in hardware by address: Only frames + * with destination address 0x00 (broadcast) or with with the + * layer-2 address of the transceiver are accepted. + * + * Why not default? + * - The RSSI, LQI and CRC info are also available via status registers. + * Thus, it is not worth to sacrifice two bytes of RX FIFO for it. + * - Hardware address filtering could reduce the number IRQs generated + * (e.g. a huge frame is dropped before it fully received) which reduces + * the system's load. Thus, it is enabled. + */ + 0x02, + /* + * PKTCTRL0; default: 0x45 + * Data whitening enabled, use RX/TX FIFOs, CRC enabled, + * variable packet length + */ + 0x45, + /* + * ADDR; default: 0x00 + * Address will overwritten later + * + * Why not default? + * 0x00 is used as broadcast address. Using it would increase chance to + * receive message during device initialization and thus power consumption. + */ + 0xFF, + /* + * CHANNR; default: 0x00 + * Channel number 0 by default + */ + 0x00, + /* + * FSCTRL1; default: 0x0C + * Intermediate frequency: 0x0C * 26MHz / 1024 = 304.7kHz + * + * Why not defaults? + * See MDMCFG4, MDMCFG3 + */ + 0x0C, + /* + * FSCTRL0; default: 0x00 + * Frequency offset to base frequency: 0kHz + */ + 0x00, + /* + * FREQ2, FREQ1, FREQ0; defaults: 0x1E, 0xC4, 0xEC + * 0x2146E4 * 26MHz / 65536 = 865.1998 MHz (LoRa Channel 10) + * + * Why not defaults? + * Default is 800.000 MHz, which is not in a license free frequency band. + * Using LoRa channel 10 instead. + */ + 0x21, /*< FREQ2 */ + 0x46, /*< FREQ1 */ + 0xE4, /*< FREQ0 */ + /* + * MDMCFG4, MDMCFG3; defaults: 0x8C, 0x22 + * 541.67 kHz channel filter bandwidth, + * 249.94 kBaud symbol rate + * + * Why not defaults? + * Using 250 kBaud (==> 250kBit/s when 2-FSK/GFSK/ASK) to compete with + * 802.15.4 in data rate. + * Using settings listed in Table 7 (pages 12ff in the data sheet): + * - 250 kBaud + * - GFSK modulation + * - 304 kHz IF frequency + * - 540 kHz channel filter bandwidth + * - 127 kHz deviation + */ + 0x2D, /*< MDMCFG4 */ + 0x3B, /*< MDMCFG3 */ + /* + * MDMCFG2; default: 0x02 + * DC blocking filter on, + * GFSK modulation, + * no manchester code, + * Enable RX when 30 bits of the 32 bits sync word are received correctly + * + * Why not default? + * Default expects all 16 bits of a two byte sync word to be correctly + * received. The data sheet recommends to expect 30 bits of a four byte + * sync word to be correctly received instead (see section 15 on page 37), + * so we go for this. + * + * Using GFSK instead of 2-FSK reduces the modulated spectrum width and is + * suggested in Table 7 of the datasheet, see MDMCFG4, MDMCFG3 + */ + 0x13, + /* + * MDMCFG1, MDMCFG0; defaults: 0x22, 0xF8 + * FEC disabled, + * 4 preamble bytes, + * 49.99 kHz distance between channel centre frequencies (closest to 50kHz) + * + * Why not defaults? + * This driver uses an translation layer between physical channels (with + * 50 kHz distance) and "virtual" channel numbers as seen outside of the + * driver. This allows to set the frequency in a range of 12.75 MHz with + * a resolution of 50kHz - this seems to allow to configure all desired + * channel layouts. + */ + 0x20, /*< MDMCFG1 */ + 0xF8, /*< MDMCFG0 */ + /* + * DEVIATN; default: 0x47 + * Deviation of frequency to encode data: +- 126.953kHz in 2-FSK/4-FSK/GFSK + * + * Why not default? + * Higher deviation required for reliable operation at 250 kbps data rate. + */ + 0x62, + /* + * MCSM2; default: 0x07 + * No direct RX termination on RSSI measurement (only for ASK/OOK), + * on RX timeout check for sync word and ignore PQI, + * no RX timeout + */ + 0x07, + /* + * MCSM1; default: 0x30 + * CCA: Enter TX even when channel is detected busy + * go to idle after packet received, + * go to idle after packet sent + * + * Why not default? + * By default the transceiver refuses to enter TX when the channel is + * detected busy. While this is desired, checking if TX was successfully + * entered is too slow and generated interrupts on the GDO2 pin are easily + * missed. However, reading the carrier sense value in the PKTSTATUS + * registers allows to implement this feature in software in a faster + * way. In addition to not missing GDO2 interrupts, this allows the send + * function to give feedback right away when the channel is busy. + */ + 0x00, + /* + * MCSM0; default: 0x04 + * Auto calibration: Disabled, driver has to manage + * delay to allow supply voltage to stabilize: 149-155 microseconds + * pin radio control option is off, + * oscillator is off in sleep state + * + * Why not default? + * Using 149µs-155µs instead of the default 37µs-39µs as PO_TIMEOUT is + * encouraged by the data sheet for robust operation + */ + 0x08, + /* + * FOCCFG; default: 0x36 + * Freeze frequency offset compensation etc until CS high: yes + * frequency compensation loop gain before sync word: 3K + * frequency compensation loop gain after sync word: K/2 + * saturation point for frequency offset compensation: 25% channel bandwidth + * (incompatible with ASK/OOK) + */ + 0x36, + /* + * BSCFG; default: 0x6C + * Clock recovery feedback loop integral gain before sync word: 2K_i, + * clock recovery feedback loop proportional gain before sync word: 3K_p, + * clock recovery feedback loop integral gain after sync word: K_i/2 + * clock recovery feedback loop proportional gain after sync word: K_p, + * data rate offset compensation: Disabled + */ + 0x6C, + /* + * AGCCTRL2; default: 0x03 + * Maximum allowable DVGA gain: No limitation, maximum DVGA gain can be used + * Maximum allowable LNA + LNA2 gain: No limitation + * target amplitude from channel filter: 33 dB (default) + */ + 0x03, + /* + * AGCCTRL1; default: 0x40 + * LNA priority: Decrease LNA gain first, start decreasing LNA2 gain when + * LNA gain reached minimum + * Relative carrier sense threshold: Disabled + * Absolute carrier sense threshold: At MAGN_TARGET + */ + 0x40, + /* + * AGCCTRL0; default: 0x91 + * HYST_LEVEL: Medium hysteresis, medium asymmetric dead zone, medium gain + * Adjust gain after how many channel filter samples: After 16 samples + * Freeze AGC gain: Never; perform gain adjustments as required + * FILTER_LENGTH: + * - 16 channel filter samples when 2-FSK, 4-FSK, or MSK is used + * - 8 dB decision baundry when OOK/ASK is used + */ + 0x91, + /* + * WOREVT1, WOREVT0, WORCTRL; defaults: 0x87, 0x6B, 0xF8 + * Event0 Timeout: 1.000 seconds + * RC_PD: 1 (The datasheet is quite cryptic regarding this setting) + * Event1 Timeout: 1.333ms - 1.385ms (depending on crystal frequency) + * RC oscillator calibration: Enabled + * WOR_RES: 0 (Relevant for Event0 resolution and maximum timeout) + */ + 0x87, /*< WOREVT1 */ + 0x6B, /*< WOREVT0 */ + 0xF8, /*< WORCTRL */ + /* + * FREND1; default: 0x56 + * LNA_CURRENT: 0b01 + * LNA2MIX_CURRENT: 0b01 + * LODIV_BUF_CURRENT_RW: 0b01 + * MIX_CURRENT: 0b10 + */ + 0x56, + /* + * FREND0; default: 0x10 + * LODIV_BUF_CURRENT_TX: 0b01 + * Index in PA_POWER table (in 0..7, default is 0): 4 (0dBm) + * + * Why not default: + * Use a reasonable TX power level instead of the lowest. + */ + 0x14, + /* + * FSCAL3, FSCAL2, FSCAL1, FSCAL0; defaults: 0xA9, 0x0A, 0x20, 0x0d + * These values store calibration date of the CC1100/CC1101 transceiver. + * Once the transceiver performs a calibration, those registers are updated + * with the new calibration data. In a "stable" environment (e.g. constant + * channel/frequency, stable humidity, temperature, supply voltage etc.) + * the obtained values could be written to the transceiver and calibration + * could be turned off completely. + * + * Fast channel hopping could be performed by obtaining the FSCAL1 + * calibration data for each channel and storing it in the MCU's RAM. + * The other calibration values is frequency independent according to the + * data sheet, but depends on temperature etc. + * + * Once the FSCAL1 values for each channel are stored, the calibration can + * be disabled and the stored FSCAL1 data can be uploaded for each channel + * hop. A re-calibration from time to time is suggested to cope with changes + * in the environment, e.g. in temperature or supply voltage. + * + * Why not defaults? + * Using "magic" values obtained with SmartRF Studio software for 868 MHz + * band. + */ + 0xEA, /*< FSCAL3: charge pump current calibration, frequency independent */ + 0x2A, /*< FSCAL2: VCO current calibration, frequency independent */ + 0x00, /*< FSCAL1: VCO capacitance calibration, frequency dependent */ + 0x1F, /*< FSCAL0: "Magic number", use SmartRF Studio to obtain */ + /* + * RCCTRL1, RCCTRL0; defaults: 0x41, 0x00 + * RC oscillator configuration, no explanation given in data sheet. + */ + 0x41, /*< RCCTRL1 */ + 0x00, /*< RCCTRL0 */ +}; + +const char cc110x_magic_registers[3] = { 0x88, 0x31, 0x09 }; diff --git a/drivers/cc110x/include/cc110x_calibration.h b/drivers/cc110x/include/cc110x_calibration.h new file mode 100644 index 000000000000..250e47f826c9 --- /dev/null +++ b/drivers/cc110x/include/cc110x_calibration.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Calibration related functions of the CC110x transceiver driver + * + * @author Marian Buschsieweke + * @} + */ + +#ifndef CC110X_CALIBRATION_H +#define CC110X_CALIBRATION_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Perform a recalibration of the transceiver + * + * @param dev The device descriptor of the transceiver + * + * @retval 0 Success + * @retval -EIO Failed + * + * @pre @p dev has been acquired using @ref cc110x_acquire + * @pre Transceiver is in IDLE state + * @post On success @p dev is still acquired, the caller has to release + * it. On failure the SPI bus is **already** **released** + * @post Transceiver is again in IDLE state, calibration has been + * performed and calibration data has been backed up on MCU. + */ +int cc110x_recalibrate(cc110x_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* CC110X_CALIBRATION_H */ +/** @} */ diff --git a/drivers/cc110x/include/cc110x_communication.h b/drivers/cc110x/include/cc110x_communication.h new file mode 100644 index 000000000000..40e5e1cc2793 --- /dev/null +++ b/drivers/cc110x/include/cc110x_communication.h @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Functions to communicate with the CC1100/CC1101 transceiver + * + * @author Marian Buschsieweke + * @} + */ + +#ifndef CC110X_COMMUNICATION_H +#define CC110X_COMMUNICATION_H + +#include "periph/gpio.h" +#include "periph/spi.h" +#include "cc110x.h" +#include "cc110x_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Acquire the SPI interface of the transceiver and configure it + * + * @retval SPI_OK Success + * @retval SPI_NOMODE SPI mode 0 not supported by MCU + * @retval SPI_NOCLK SPI clock given in @ref cc110x_params_t is not supported + * + * @pre @ref cc110x_power_on has be called before calling this function. + * (Only needed *once* when the driver initializes.) + */ +static inline int cc110x_acquire(cc110x_t *dev) +{ + return spi_acquire(dev->params.spi, dev->params.cs, SPI_MODE_0, + dev->params.spi_clk); +} + +/** + * @brief Release the SPI interface of the transceiver + */ +static inline void cc110x_release(cc110x_t *dev) +{ + spi_release(dev->params.spi); +} + +/** + * @brief Read a single configuration/status register from the transceiver + * + * @param dev Device descriptor of the transceiver to read the register from + * @param addr Address of the register to read + * @param dest Where to store the received register content + * + * @return The received status byte + * + * @pre @p dest points to one byte of writeable memory + * @warning Race condition: SPI access to status registers can occur while + * their content is changed, resulting in corrupted data being + * retrieved. @ref cc110x_read_reliable provides reliable access + * to status registers and should be used to read the TXBYTES, + * RXBYTES, MARCSTATE, LQI, RSSI, WORTIME1 and WORTIME0 status + * registers. (See Silicon Errata from 2015 at pages 4ff.) + * (In IDLE state LQI and RSSI can be read safely using this + * function.) + * @warning The received status byte is occasionally corrupted. (See + * Silicon Errata from 2015 at pages 4ff.) Use @ref cc110x_status + * To get the status byte in a reliable way. + */ +uint8_t cc110x_read(cc110x_t *dev, uint8_t addr, uint8_t *dest); + +/** + * @brief Read a single status register from the transceiver reliable + * + * This function has more overhead than @ref cc110x_read, but it is the only + * reliable way to access frequently updated status registers. + * + * @param dev Device descriptor of the transceiver to read the register from + * @param addr Address of the register to read + * @param dest Where to store the received register content + * + * @return The received status byte + * + * @pre @p dest points to one byte of writeable memory + * @warning The received status byte is occasionally corrupted. (See + * Silicon Errata from 2015 at pages 4ff.) Use @ref cc110x_status + * To get the status byte in a reliable way. + */ +uint8_t cc110x_read_reliable(cc110x_t *dev, uint8_t addr, uint8_t *dest); + +/** + * @brief Write to a single configuration register on the transceiver + * + * @param dev Device descriptor of the transceiver to write byte to + * @param addr Address of the register to write to + * @param data Data to write + * + * @return The received status byte + * + * @pre @p addr <= 0x2e (@ref CC110X_REG_TEST0) + * @warning Writing to status registers is impossible (==> precondition) + * @warning The received status byte is occasionally corrupted. (See + * Silicon Errata from 2015 at pages 4ff.) Use @ref cc110x_status + * To get the status byte in a reliable way. + */ +uint8_t cc110x_write(cc110x_t *dev, uint8_t addr, uint8_t data); + +/** + * @brief Burst-read a bunch of configuration registers from the transceiver + * + * @param dev Device descriptor of the transceiver to read from + * @param addr Address to start reading from + * @param dest Destination buffer to store the received data to + * @param len Number of bytes to read starting from @p addr + * + * @return The received status byte + * + * @pre @p dest points to a pre-allocated buffer of >= @p len bytes + * @pre @p addr + @p len <= 0x2e (@ref CC110X_REG_TEST0) + * @warning Burst read access from status registers is impossible + * (==> second precondition) + * @warning The received status byte is occasionally corrupted. (See + * Silicon Errata from 2015 at pages 4ff.) Use @ref cc110x_status + * To get the status byte in a reliable way. + */ +uint8_t cc110x_burst_read(cc110x_t *dev, uint8_t addr, void *dest, size_t len); + +/** + * @brief Burst-write to a bunch of configuration registers on the transceiver + * + * @param dev Device descriptor of the transceiver to write + * @param addr Address to start writing to + * @param src Buffer holding the configuration to write + * @param len Number of registers to write to + * + * @return The received status byte + * + * @pre @p src points to @p len bytes of readable memory + * @pre @p addr + @p len <= 0x2e (@ref CC110X_REG_TEST0) + * @warning Writes to status registers is impossible + * (==> second precondition) + * @warning The received status byte is occasionally corrupted. (See + * Silicon Errata from 2015 at pages 4ff.) Use @ref cc110x_status + * to get the status byte in a reliable way. + */ +uint8_t cc110x_burst_write(cc110x_t *dev, uint8_t addr, + const void *src, size_t len); + +/** + * @brief Send a command to the transceiver + * + * @param dev Device descriptor of the transceiver to send the command to + * @param cmd_strobe Command to send + * + * @return The received status byte + * + * @warning The received status byte is occasionally corrupted. (See + * Silicon Errata from 2015 at pages 4ff.) Use + * @ref cc110x_status to get the status byte in a reliable + * way. + */ +uint8_t cc110x_cmd(cc110x_t *dev, uint8_t cmd_strobe); + +/** + * @brief Get the transceivers status byte in a reliable way + * + * @param dev Device descriptor of the transceiver to get the status from + * + * @return The received status byte + */ +uint8_t cc110x_status(cc110x_t *dev); + +/** + * @brief Wakes up the transceiver from "Sleep" or "Crystal oscillator off" + * state and waits until the crystal has stabilized + * + * Thus function clears the CS pin, which triggers a transition from the "Sleep" + * or "Crystal oscillator off" states (see Figure 13 on page 28 in the data + * sheet). + * + * If the crystal was off (only in above mentioned states), the MCU must wait + * for the transceiver to become ready *before* any SPI transfer is initiated. + * In all other states, CS pin can be pulled low and SPI transfer can start + * right away (see section 10 on page 29 in the data sheet). This driver will + * never disable the transceivers crystal, so this function has to be called + * only once when the transceiver is powered on. + * + * The transceiver will signal that it is available by pulling the MISO pin + * low (section 10 on page 29 in the data sheet), which does not take longer + * than 150 microseconds (see Table 22 on page 30 in the data sheet). Instead + * of messing with the SPI interface, this driver simply waits for this upper + * bound, as suggested in the note below Table 22 on page 30 in the data sheet. + * + * @retval 0 Success + * @retval -EIO Couldn't pull the CS pin down (@ref cc110x_params_t::cs) + */ +int cc110x_power_on(cc110x_t *dev); + + +#ifdef __cplusplus +} +#endif + +#endif /* CC110X_COMMUNICATION_H */ +/** @} */ diff --git a/drivers/cc110x/include/cc110x_constants.h b/drivers/cc110x/include/cc110x_constants.h new file mode 100644 index 000000000000..2fbecc938223 --- /dev/null +++ b/drivers/cc110x/include/cc110x_constants.h @@ -0,0 +1,522 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Constants for the CC1100/CC1101 driver + * + * @author Marian Buschsieweke + * @} + */ + +#ifndef CC110X_CONSTANTS_H +#define CC110X_CONSTANTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Command strobes of the CC1100/CC1101 transceiver + * + * See Table 42 on page 67 in the data sheet. Only values relevant to the + * driver are listed. + * + * @{ + */ + +/** + * @brief Reset chip (SRES) + */ +#define CC110X_STROBE_RESET 0x30 + +/** + * @brief Calibrate frequency synthesizer and turn it off (SCAL) + */ +#define CC110X_STROBE_CALIBRATE 0x33 + +/** + * @brief Go to RX state (SRX) + * + * Requires frequency calibration first + */ +#define CC110X_STROBE_RX 0x34 + +/** + * @brief Go to TX state (STX) + * + * Requires frequency calibration first + */ +#define CC110X_STROBE_TX 0x35 + +/** + * @brief Go to IDLE state (SIDLE) + */ +#define CC110X_STROBE_IDLE 0x36 + +/** + * @brief Go to power down state once CS goes high (SPWD) + */ +#define CC110X_STROBE_OFF 0x39 + +/** + * @brief Flush RX fifo (SFRX) + * + * Only valid in IDLE or in RXFIO_OVERFLOW states + */ +#define CC110X_STROBE_FLUSH_RX 0x3A + +/** + * @brief Flush TX fifo (SFTX) + * + * Only valid in IDLE or in TXFIO_OVERFLOW states + */ +#define CC110X_STROBE_FLUSH_TX 0x3B + +/** + * @brief Get the status byte (SNOP) + */ +#define CC110X_STROBE_STATUS 0x3D + +/** @} */ + +/** + * @name Access modifies for accessing configuration/status registers + * + * See Table 45 on pages 69ff in the data sheet. These modifies need to be + * xor'ed with the address of the register. + * + * @{ + */ + +/** + * @brief Access modifier to write a single byte to a configuration register + * + * | read bit (`0x80`) | burst access bit (`0x40`) | + * |-------------------|---------------------------| + * | `0` (= write) | `0` (= no burst access) | + */ +#define CC110X_SINGLE_BYTE_WRITE 0x00 + +/** + * @brief Access modifier to write multiple bytes at once to configuration + * registers + * + * | read bit (`0x80`) | burst access bit (`0x40`) | + * |-------------------|---------------------------| + * | `0` (= write) | `1` (= burst access) | + */ +#define CC110X_BURST_WRITE 0x40 + +/** + * @brief Access modifier to read a single byte from a configuration register + * + * | read bit (`0x80`) | burst access bit (`0x40`) | + * |-------------------|---------------------------| + * | `1` (= read) | `0` (= no burst access) | + */ +#define CC110X_SINGLE_BYTE_READ 0x80 + +/** + * @brief Access modifier to read multiple bytes at once from configuration + * registers + * + * | read bit (`0x80`) | burst access bit (`0x40`) | + * |-------------------|---------------------------| + * | `1` (= read) | `1` (= burst access) | + */ +#define CC110X_BURST_READ 0xC0 + +/** @} */ + +/** + * @name "Multi byte registers" of the CC1100/CC1101 transceiver + * + * See Table 45 on pages 69ff in the data sheet. These multi byte registers + * have a special semantics, which is documented for each multi byte register + * + * @{ + */ + +/** + * @brief Access to the PATABLE as multi byte register + * + * It is most convenient to read/write the whole 8 bytes of the PATABLE using a + * burst access. The first single byte access after the CS pin is pulled low + * will read from / write to the first byte, the second access the second byte, + * and so on. As @ref cc110x_read and @ref cc110x_write pull the CS pin high + * after the access, all but the first byte are only accessible using burst + * access in this driver. + */ +#define CC110X_MULTIREG_PATABLE 0x3E + +/** + * @brief Access to the TX and RX FIFO as multi byte register + * + * A single byte read using @ref cc110x_read from the FIFO multi byte register + * will retrieve and remove the next byte from the RX FIFO. A burst of *n* bytes + * using @ref cc110x_burst_read will retrieve and remove the next *n* bytes. + * + * A single byte write using @ref cc110x_write will push one byte of data into + * the TX FIFO. A multi byte write of *n* byte using @ref cc110x_burst_write + * will push *n* bytes into the TX FIFO. + * + * @warning Reading the last byte from the RX-FIFO results in data corruption, + * unless the whole frame was received. Thus, read all but the last + * byte from the FIFO until the whole frame was received. + */ +#define CC110X_MULTIREG_FIFO 0x3F + +/** @} */ + +/** + * @name Configuration registers of the CC1100/CC1101 transceiver + * + * See Table 43 on pages 68ff in the data sheet. Only values relevant to the + * driver are listed. + * + * @{ + */ + +/** + * @brief First configuration register on the transceiver, used for burst + * access to the whole configuration + */ +#define CC110X_CONF_START 0x00 + +/** + * @brief GDO2 output pin configuration + */ +#define CC110X_REG_IOCFG2 0x00 + +/** + * @brief GDO1 output pin configuration + */ +#define CC110X_REG_IOCFG1 0x01 + +/** + * @brief GDO0 output pin configuration + */ +#define CC110X_REG_IOCFG0 0x02 + +/** + * @brief Device address + */ +#define CC110X_REG_ADDR 0x09 + +/** + * @brief Channel number + */ +#define CC110X_REG_CHANNR 0x0A + +/** + * @brief Intermediate frequency to use + */ +#define CC110X_REG_FSCTRL1 0x0B + +/** + * @brief Frequency control word, high byte + */ +#define CC110X_REG_FREQ2 0x0D + +/** + * @brief Frequency control word, middle byte + */ +#define CC110X_REG_FREQ1 0x0E + +/** + * @brief Frequency control word, low byte + */ +#define CC110X_REG_FREQ0 0x0F + +/** + * @brief Modem configuration (channel filter bandwidth and data rate) + */ +#define CC110X_REG_MDMCFG4 0x10 + +/** + * @brief Modem configuration (data rate) + */ +#define CC110X_REG_MDMCFG3 0x11 + +/** + * @brief Modem deviation setting + */ +#define CC110X_REG_DEVIATN 0x15 + +/** + * @brief Front End TX Configuration + * + * Least three significant bits contain the current PA power setting. + */ +#define CC110X_REG_FREND0 0x22 + +/** + * @brief Charge pump current calibration + * + * This value depends on the environment (e.g. temperature, supply voltage, + * etc.), but not on the frequency. Thus, this value does not become obsolete + * when changing the channel. + */ +#define CC110X_REG_FSCAL3 0x23 + +/** + * @brief VCO current calibration + * + * This value depends on the environment (e.g. temperature, supply voltage, + * etc.), but not on the frequency. Thus, this value does not become obsolete + * when changing the channel. + */ +#define CC110X_REG_FSCAL2 0x24 + +/** + * @brief VCO capacitance calibration + * + * This value is frequency depended. Thus, for fast channel hopping it has to + * be obtained for each channel (by performing a calibration on that channel + * and reading it out). Than the stored calibration data can be written to the + * register when changing the channel. + */ +#define CC110X_REG_FSCAL1 0x25 + +/** + * @brief Undocumented frequency calibration value + * + * For fast channel hopping this value can be ignored (see page 64ff in the + * data sheet) - so it has to be frequency independent. + */ +#define CC110X_REG_FSCAL0 0x26 + +/** + * @brief Unlock the temperature sensor by writing 0xBF to it + * + * Intended for production test, but who would complain about getting an + * temperature sensor for free :-) + * + * @see @ref CC110X_GDO0_ANALOG_TEMPERATURE for details + */ +#define CC110X_REG_PTEST 0x2A + +/** + * @brief Magic value obtained with SmartRF Studio software + */ +#define CC110X_REG_TEST2 0x2C + +/** + * @brief Magic value obtained with SmartRF Studio software + */ +#define CC110X_REG_TEST1 0x2D + +/** + * @brief Magic value obtained with SmartRF Studio software + */ +#define CC110X_REG_TEST0 0x2E + +/** @} */ + +/** + * @name Status registers of the CC1100/CC1101 transceiver + * + * See Table 43 on pages 68ff in the data sheet. Only values relevant to the + * driver are listed. + * + * @warning The burst access bit of these registers has to be set to distinguish + * between command strobes and status registers. Thus, no burst access + * to status registers is possible. + * + * @{ + */ + +/** + * @brief Part number + * + * @warning Not accessible using burst reads + */ +#define CC110X_REG_PARTNUM (0x30 | 0x40) + +/** + * @brief Version + * + * @warning Not accessible using burst reads + */ +#define CC110X_REG_VERSION (0x31 | 0x40) + +/** + * @brief Estimated link quality + * + * @warning Not accessible using burst reads + */ +#define CC110X_REG_LQI (0x33 | 0x40) + +/** + * @brief Received signal strength indication + * + * @warning Not accessible using burst reads + */ +#define CC110X_REG_RSSI (0x34 | 0x40) + +/** + * @brief Packet status, GDOx status + * + * @warning Not accessible using burst reads + */ +#define CC110X_REG_PKTSTATUS (0x38 | 0x40) + +/** + * @brief Number of bytes in the TX FIFO + * + * @warning Not accessible using burst reads + * @warning The received value could be corrupted when reading it while it is + * updated. Reading it out twice until both reads return the same + * value is the suggested workaround for this hardware bug. + */ +#define CC110X_REG_TXBYTES (0x3A | 0x40) + +/** + * @brief Number of bytes available in the RX FIFO + * + * @warning Not accessible using burst reads + * @warning The received value could be corrupted when reading it while it is + * updated. Reading it out twice until both reads return the same + * value is the suggested workaround for this hardware bug. + */ +#define CC110X_REG_RXBYTES (0x3B | 0x40) + +/** @} */ + +/** + * @name Possible values for the IOCFG2, IOCFG1, and IOCFG0 configuration registers + * + * See Table 41 on page 62 in the data sheet. Only values relevant to the + * driver are listed. + * + * @{ + */ + +/** + * @brief GDOx goes HIGH when data has to be read from RX FIFO or when a packet + * is fully received + * + * Depends on the threshold set for the RX-FIFO in the FIFOTHR configuration + * register + */ +#define CC110X_GDO_ON_RX_DATA 0x01 + +/** + * @brief GDOx goes LOW when data should be written to the TX FIFO + * + * Depends on the threshold set for the TX-FIFO in the FIFOTHR configuration + * register + */ +#define CC110X_GDO_ON_TX_DATA 0x02 + +/** + * @brief GDOx goes HIGH when a packet is received/send and back LOW when the + * transmission is completed/aborted (e.g. wrong destination address) + */ +#define CC110X_GDO_ON_TRANSMISSION 0x06 + +/** + * @brief GDOx goes HIGH when channel is clear for sending + * + * Depends on the CCA_MODE setting in the MCSM1 configuration register + */ +#define CC110X_GDO_ON_CHANNEL_CLEAR 0x09 + +/** + * @brief GDOx goes HIGH when PLL is in lock + * + */ +#define CC110X_GDO_ON_PLL_IN_LOCK 0x0A + + +/** + * @brief GDOx remains constantly LOW + */ +#define CC110X_GDO_CONSTANT_LOW 0x2F + +/** + * @brief GDOx remains constantly HIGH + */ +#define CC110X_GDO_CONSTANT_HIGH 0x6F + +/** + * @brief Repurpose GDO0 as analog temperature sensor in IDLE state + * + * This only works with GDO0 and only in IDLE state! Additionally, 0xBF has + * to be written to configuration register PTEST when in IDLE state. Before + * leaving IDLE state, PTEST should be restored to 0x7F. + */ +#define CC110X_GDO0_ANALOG_TEMPERATURE 0x80 + +/** @} */ + +/** + * @name Bitmasks to access entries in the PKTSTATUS status register + * + * See page 94 in the data sheet. + * + * @{ + */ +/** + * @brief Bitmask to get the GDO0 state from the PKTSTATUS status register value + */ +#define CC110X_PKTSTATUS_GDO0 0x01 +/** + * @brief Bitmask to get the GDO2 state from the PKTSTATUS status register value + */ +#define CC110X_PKTSTATUS_GDO2 0x04 +/** + * @brief Bitmask to get the SFD bit from the PKTSTATUS status register value + * which is set while receiving a frame + */ +#define CC110X_PKTSTATUS_RECEIVING 0x08 +/** + * @brief Bitmask to get the CCA bit from the PKTSTATUS status register value + */ +#define CC110X_PKTSTATUS_CCA 0x10 +/** + * @brief Bitmask to get the Carrier Sense bit from the PKTSTATUS status + * register value + */ +#define CC110X_PKTSTATUS_CS 0x40 +/** @} */ + +/** + * @name Values to write into the PTEST configuration register + * + * See page 91 in the data sheet. Only the two documented values are specified. + * + * @{ + */ +/** + * @brief Default value of the PTEST configuration register. + */ +#define CC110X_PTEST_DEFAULT 0x7F +/** + * @brief Value to write in PTEST when reading the temperature. + * + * @see CC110X_GDO0_ANALOG_TEMPERATURE + */ +#define CC110X_PTEST_TEMPERATURE 0xBF +/** @} */ + +/** + * @brief Size of the RX and TX FIFO + */ +#define CC110X_FIFO_SIZE 64 + +#ifdef __cplusplus +} +#endif + +#endif /* CC110X_CONSTANTS_H */ +/** @} */ diff --git a/drivers/cc110x/include/cc110x_internal.h b/drivers/cc110x/include/cc110x_internal.h new file mode 100644 index 000000000000..ca11d9b42afa --- /dev/null +++ b/drivers/cc110x/include/cc110x_internal.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Internal functions of the CC110x transceiver driver + * + * @author Marian Buschsieweke + * @} + */ + +#ifndef CC110X_INTERNAL_H +#define CC110X_INTERNAL_H + +#include "cc110x_calibration.h" +#include "cc110x_communication.h" +#include "cc110x_constants.h" +#include "cc110x_netdev.h" +#include "cc110x_rx_tx.h" +#include "cc110x_settings.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Extract the device state from the status register value + * + * @param status Contents of the CC110x's status register + * @return The state encoded in @p status + * + * The status register contains the device state at the bits 1 - 3 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Format of the status byte + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |R|STATE| FIFO | + * +-+-+-+-+-+-+-+-+ + * + * R = Chip Ready bit (0 = ready, 1 = power and crystal are not yet stable) + * STATE = The device state + * FIFO = Number of bytes available in RX FIFO or (in TX mode) number of free + * bytes + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Note: The FIFO has a size of 64 bytes. If more than 15 bytes are available + * for reading in the FIFO (or more than 15 bytes can be written in TX), the + * value will still show 15. This driver never uses this information, but + * accesses a dedicated register for that. + */ +static inline cc110x_state_t cc110x_state_from_status(uint8_t status) +{ + return (cc110x_state_t)((status >> 4) & 0x7); +} + +/** + * @brief Figure out of the transceiver is ready or still powering up + * @param status Contents of the CC110x's status register + * @retval 1 Transceiver is ready + * @retval 0 *NOT* ready, still powering up + * + * @see cc110x_state_from_status + */ +static inline int cc110x_is_ready_from_status(uint8_t status) +{ + return (status & 0x80) ? 0: 1; +} + +#ifdef __cplusplus +} +#endif + +#endif /* CC110X_INTERNAL_H */ +/** @} */ diff --git a/drivers/cc110x/include/cc110x_netdev.h b/drivers/cc110x/include/cc110x_netdev.h new file mode 100644 index 000000000000..88d8bb0de1e7 --- /dev/null +++ b/drivers/cc110x/include/cc110x_netdev.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Functions related to the netdev interface of the CC110x driver + * + * @author Marian Buschsieweke + * @} + */ + +#ifndef CC110X_NETDEV_H +#define CC110X_NETDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief RIOT's API to interact with the CC1100/CC1101 driver + */ +extern const netdev_driver_t cc110x_driver; + +/** + * @brief Interrupt handler to call on both edges of the GDO0 and GDO2 pins + * + * @param dev The device descriptor of the transceiver + * + * This interrupt handler requests that the cc110x ISR is called in thread + * context + */ +void cc110x_on_gdo(void *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* CC110X_NETDEV_H */ +/** @} */ diff --git a/drivers/cc110x/include/cc110x_params.h b/drivers/cc110x/include/cc110x_params.h new file mode 100644 index 000000000000..bcead87fb70f --- /dev/null +++ b/drivers/cc110x/include/cc110x_params.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief cc110x board specific configuration + * + * @author Marian Buschsieweke + */ + +#ifndef CC110X_PARAMS_H +#define CC110X_PARAMS_H + +#include "board.h" +#include "cc110x_settings.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Default parameters for the cc110x driver + * + * These values are based on the msba2 board + * @{ + */ +#ifndef CC110X_PARAM_SPI +#define CC110X_PARAM_SPI SPI_DEV(0) +#endif + +#ifndef CC110X_PARAM_CS +#define CC110X_PARAM_CS GPIO_PIN(1, 21) +#endif + +#ifndef CC110X_PARAM_GDO0 +#define CC110X_PARAM_GDO0 GPIO_PIN(0, 27) +#endif + +#ifndef CC110X_PARAM_GDO2 +#define CC110X_PARAM_GDO2 GPIO_PIN(0, 28) +#endif + +#ifndef CC110X_PARAM_SPI_CLOCK +#define CC110X_PARAM_SPI_CLOCK SPI_CLK_5MHZ +#endif + +#ifndef CC110X_PARAM_L2ADDR +#define CC110X_PARAM_L2ADDR CC110X_L2ADDR_AUTO +#endif + +#ifndef CC110X_PARAM_PATABLE +#define CC110X_PARAM_PATABLE (&cc110x_patable_868mhz) +#endif + +#ifndef CC110X_PARAM_CONFIG +#define CC110X_PARAM_CONFIG NULL +#endif + +#ifndef CC110X_PARAM_CHANNELS +#define CC110X_PARAM_CHANNELS (&cc110x_chanmap_868mhz_lora) +#endif + +#ifndef CC110X_PARAMS +#define CC110X_PARAMS { \ + .spi = CC110X_PARAM_SPI, \ + .spi_clk = CC110X_PARAM_SPI_CLOCK, \ + .cs = CC110X_PARAM_CS, \ + .gdo0 = CC110X_PARAM_GDO0, \ + .gdo2 = CC110X_PARAM_GDO2, \ + .l2addr = CC110X_PARAM_L2ADDR, \ + .patable = CC110X_PARAM_PATABLE, \ + .config = CC110X_PARAM_CONFIG, \ + .channels = CC110X_PARAM_CHANNELS, \ +} + +#endif +/** @} */ + +/** + * @name CC110X configuration + * @brief Specifies the SPI bus and GPIOs connected to the CC110X transceiver + */ +static const cc110x_params_t cc110x_params[] = { + CC110X_PARAMS +}; + +#ifdef __cplusplus +} +#endif +#endif /* CC110X_PARAMS_H */ +/** @} */ diff --git a/drivers/cc110x/include/cc110x_rx_tx.h b/drivers/cc110x/include/cc110x_rx_tx.h new file mode 100644 index 000000000000..554af05f502a --- /dev/null +++ b/drivers/cc110x/include/cc110x_rx_tx.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Functions to related to RX/TX of the CC110x transceiver driver + * + * @author Marian Buschsieweke + * @} + */ + +#ifndef CC110X_RX_TX_H +#define CC110X_RX_TX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ISR to be called via @ref netdev_driver_t::isr + */ +void cc110x_isr(netdev_t *dev); + +/** + * @brief Bring transceiver into RX mode + * + * @param dev The device descriptor of the transceiver + * + * @pre @p dev has been acquired using @ref cc110x_acquire + * @post @p dev is still acquired, the caller has to release it + */ +void cc110x_enter_rx_mode(cc110x_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* CC110X_RX_TX_H */ +/** @} */ diff --git a/drivers/cc110x/include/cc110x_settings.h b/drivers/cc110x/include/cc110x_settings.h new file mode 100644 index 000000000000..29238a1a43b0 --- /dev/null +++ b/drivers/cc110x/include/cc110x_settings.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_cc110x + * @{ + * + * @file + * @brief Default settings of the TI CC1100/CC1101 transceiver + * + * @author Marian Buschsieweke + * @} + */ + +#ifndef CC110X_SETTINGS_H +#define CC110X_SETTINGS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The size of the configuration array for CC110X in bytes + */ +#define CC110X_CONF_SIZE 41 + +/** + * @brief Length of the PATABLE + */ +#define CC110X_PATABLE_LEN 8 + +/** + * @brief Configuration register values for CC1100/CC1101 transceivers + */ +extern const char cc110x_conf[CC110X_CONF_SIZE]; + +/** + * @brief Magic numbers to write to the TEST2, TEST1 and TEST0 configuration + * registers + * + * Those registers are poorly documented. The data sheet refers to SmartRF + * Studio to obtain the correct magic numbers. Those values were identical + * for the 433MHz, 868MHz and 915MHz band at GFSK, 250kBaud and 127kHz + * deviation. Maybe by luck? So when adding a new base band or adjusting the + * transceiver configuration, those numbers should be checked again with the + * SmartRF Studio + */ +extern const char cc110x_magic_registers[3]; + +/** + * @name Configuration data that specify the 8 available output power levels + * + * Source: Table 39 in the data sheet on page 60. + * + * | Output Power [dBm] | Setting 433 MHz | Setting 868 MHz | Setting 915 MHz | + * |--------------------|-----------------|-----------------|-----------------| + * | -30 | 0x12 | 0x03 | 0x03 | + * | -20 | 0x0E | 0x0F | 0x0E | + * | -15 | 0x1D | 0x1E | 0x1E | + * | -10 | 0x34 | 0x27 | 0x27 | + * | 0 | 0x60 | 0x50 | 0x8E | + * | 5 | 0x84 | 0x81 | 0xCD | + * | 7 | 0xC8 | 0xCB | 0xC7 | + * | 10 | 0xC0 | 0xC2 | 0xC0 | + * + * @{ + */ +/** + * @brief PATABLE values for the 433 MHz band + * + * Source: Table 39 in the data sheet on page 60. + */ +extern const cc110x_patable_t cc110x_patable_433mhz; +/** + * @brief PATABLE values for the 868 MHz band + * + * @note This is the default PATABLE. There is no need to upload this table + * unless switching between different PATABLEs is required. + * + * Source: Table 39 in the data sheet on page 60. + */ +extern const cc110x_patable_t cc110x_patable_868mhz; +/** + * @brief PATABLE values for the 915 MHz band + * + * Source: Table 39 in the data sheet on page 60. + */ +extern const cc110x_patable_t cc110x_patable_915mhz; +/** @} */ + + +/** + * @name Channel mappings for CC110x transceivers + * + * @{ + */ +/** + * @brief Channel map for 50 kHz channels with a distance of 200 kHz in the + * 433 MHz band + * + * This channel mapping assumes @ref cc110x_config_433mhz_38kbps_50khz is + * used as configuration. @ref cc110x_chanmap_433mhz_50khz_alt is an alternative + * channel map that does not overlap with this map. (This means devices with + * the alternative channel map cannot communicate with devices using this one, + * but also no interference is expected.) + */ +extern const cc110x_chanmap_t cc110x_chanmap_433mhz_50khz; +/** + * @brief Alternative channel map for 50 kHz channels with a distance of 200 kHz + * in the 433 MHz band + * @see cc110x_chanmap_433mhz_50khz + * + * This channel mapping assumes @ref cc110x_config_433mhz_38kbps_50khz is + * used as configuration. + */ +extern const cc110x_chanmap_t cc110x_chanmap_433mhz_50khz_alt; +/** + * @brief Channel map for 5 non-overlapping 300 kHz channels in the 433 MHz band + * + * This channel mapping assumes @ref cc110x_config_433mhz_250kbps_300khz is + * used as configuration. (Note: The distance between channels is in fact + * 350 kHz instead of 300. This increased distance allows to cover the full + * license free range and reduce the possibility of interference of adjacent + * channels. Reducing the distance to 300kHz would still allow only 5 channels.) + */ +extern const cc110x_chanmap_t cc110x_chanmap_433mhz_300khz; +/** + * @brief Channel map for LoRa 868MHz channels 10 to 17 (available as 0 to 7). + * + * This channel mapping assumes @ref cc110x_config_868mhz_250kbps_300khz is used + * as configuration. + */ +extern const cc110x_chanmap_t cc110x_chanmap_868mhz_lora; +/** @} */ + +/** + * @name Base frequency, channel bandwidth and data rate configurations for CC110x transceivers + * + * @{ + */ +/** + * @brief CC110x configuration: 433MHz band, 38.4kbps data rate, 50 kHz channel + * width + */ +extern const cc110x_config_t cc110x_config_433mhz_38kbps_50khz; +/** + * @brief CC110x configuration: 433MHz band, 250kbps data rate, 300 kHz channel + * width + */ +extern const cc110x_config_t cc110x_config_433mhz_250kbps_300khz; +/** + * @brief CC110x configuration: 868MHz band, 250kbps data rate, 300 kHz channel + * width + */ +extern const cc110x_config_t cc110x_config_868mhz_250kbps_300khz; +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* CC110X_SETTINGS_H */ +/** @} */ diff --git a/drivers/include/cc110x.h b/drivers/include/cc110x.h new file mode 100644 index 000000000000..261f6306cf2c --- /dev/null +++ b/drivers/include/cc110x.h @@ -0,0 +1,633 @@ +/* + * Copyright (C) 2013 INRIA + * 2014 Freie Universität Berlin + * 2015 Kaspar Schleiser + * 2018,2019 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @defgroup drivers_cc110x CC1100/CC1100e/CC1101 Sub-GHz transceiver driver + * @ingroup drivers_netdev + * + * This module contains the driver for the TI CC1100/CC110e/CC1101 Sub-GHz + * transceivers. + * + * @warning How the CC1100/CC1101 operate can be configured quite sophistically. + * This has the drawback, that configurations breaking laws and rules + * are complete possible. Please make sure that the configured output + * power, duty cycle, frequency range, etc. conform to the rules, + * standards and laws that apply in your use case. + * + * + * Supported Hardware and how to obtain + * ==================================== + * + * This driver has been developed for the CC1101 and the older CC1100 + * transceiver and tested for both. However, it should work with the CC1100e + * as well - but this has *NOT* been tested at all. + * + * It is suggested to go for the CC1101 when considering to buy one of the + * supported transceivers. The easiest way is to obtain CC1101 break out boards + * with a complete antenna circuit & antenna that can be connected via jumper + * wires using an 8 pin DIP pin header. These are sold in various flavours start + * from less than 2€ at quantity one at your favourite Far East store. Beware + * that while the CC1101 chip can operate a various base frequencies, the + * antenna circuit will only work for a single frequency band. Most break out + * boards will operate at 433 MHz, which is license free in many countries (but + * verify that for your country before buying!). EU citizens might prefer the + * 868 MHz band over the 433 MHz, as more license free bandwidth is available + * in the 868 MHz band in the EU. (But when deploying only a few dozens of + * devices, the 433 MHz band is also fine for EU citizens.) US citizens should + * go for the 900 MHz band (as 868 MHz is not license free in the USA), which + * even contains more bandwidth than the 868 MHz band. (However, the 900 MHz + * band has not been tested, as using it would be illegal in the EU.) + * + * + * Packet Format + * ============= + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Preamble (4 bytes, handled by hardware, see MDMCFG1) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Sync Word (4 bytes, handled by hardware, see MDMCFG2) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Length Field | Destination | Source | Payload... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ... (see Length Field) | CRC (handled by hardware) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * | Field | Description | + * |--------------|------------------------------------------------------------| + * | Preamble | 4 bytes, handled by hardware | + * | Sync Word | 4 bytes, handled by hardware | + * | Length Field | Handled by software & hardware, length of payload + 2 | + * | Destination | Handled by software & hardware, destination MAC address | + * | Source | Handled by software only, source MAC address | + * | Payload | Handled by software only, the payload to send | + * | CRC | 2 bytes, handled by hardware | + * + * The Length Field contains the length of the driver supplied data in bytes, + * not counting the Length Field. Thus, it contains the length of the payload + * plus the length of the Destination and Source address. + * + * + * Layer-2 Addresses + * ----------------- + * + * The layer 2 addresses of the CC110x transceivers is a single byte long and + * the special value `0x00` for the destination address is used in broadcast + * transmissions. The transceiver is configured by this driver to ignore all + * packets unless the destination address matches the address of the transceiver + * or the destination address is `0x00`. + * + * Please note that the layer 2 address by default is derived from the CPU ID. + * Due to the birthday paradox with only 20 devices the probability of a + * collision is already bigger than 50%. Thus, manual address assignment is + * supported by defining `C110X_PARAM_L2ADDR`. + * + * + * Base Band, Data Rate, Channel Bandwidth and Channel Map Configuration + * ===================================================================== + * + * This driver allows to configure the base band, the data rate and the channel + * bandwidth using an @ref cc110x_config_t data structure. Default + * configurations are supplied and name using the following scheme: + * `cc110x_config___`. (E.g. + * @ref cc110x_config_868mhz_250kbps_300khz is the default configuration used by + * the MSB-A2 and the MSB-IoT boards.) + * + * Using the @ref cc110x_chanmap_t data structure the channel layout can be + * defined. This map contains 8 entries, each defines the offset from the base + * frequency defined in the @ref cc110x_config_t data structure for each + * channel in steps of 50kHz. E.g. @ref cc110x_chanmap_868mhz_lora provides + * the LoRa channels 10 to 17 in the 868MHz band. (The RIOT channel numbers + * will always start from 0, and currently only up to eight channels are + * supported. A special value of 255 as offset from the base frequency in the + * channel map is used mark the channel as disabled. This can be used if less + * than 8 non-overlapping channels are possible in the license free band.) + * + * Please note that the channel map (@ref cc110x_chanmap_t) must match the + * base configuration (@ref cc110x_config_t), as the channel map is relative + * to the configured base frequency. Also, the distance between the channels + * in the channel map should match the channel bandwidth of the configuration, + * as otherwise channels could overlap. + * + * Both configuration and matching channel map can be applied using + * @ref cc110x_apply_config. Please consider this as a slow operation, as the + * transceiver needs to be calibrated for each channel in the channel map. + * + * + * Calibration of the Frequency Generator + * ====================================== + * + * The CC110x transceivers use a voltage controlled oscillator (VCO) and a + * phase locked loop (PLL) for frequency generation. However, they need to be + * calibrated to work correctly with the given supply voltage and the current + * temperature. The driver will perform this calibration during startup, but + * when the supply voltage or the temperature is not stable, a recalibration is + * required whenever the supply voltage of temperature has changed too much since + * the last calibration. This can be done by calling + * @ref cc110x_full_calibration. It is left to the application developer to + * perform this calibration when needed. During a test of about 2 hours of + * operation in an in-door environment with a stable temperature the CC1101 has + * worked reliable without any calibration at all (except for the automatic + * calibration at start up). So there are use cases which do not require any + * recalibration at all. + * + * + * Troubleshooting + * =============== + * + * The Driver Does Not Initialize Properly + * --------------------------------------- + * Set `ENABLE_DEBUG` in `cc110x_netdev.c` to `1` to get debug output, which + * will likely tell you what is going wrong. There are basically two things + * that can fail: + * + * Upon initialization the driver will read out the part number and version of + * the transceiver. If those do not match the ones expected for the CC1100, + * CC1100E, or the CC1101 the driver will refuse to initialize. If this fails, + * most likely incorrect values are read out and the SPI communication does not + * work correctly. However, future revisions of the CC110X transceivers might + * be produced and might have different values for the part number or version. + * If this should happen and they remain compatible with the driver, their + * part number & revision needs to be added to the driver. + * + * After uploading the configuration, the driver will read back the + * configuration to verify it. If the SPI communication is not reliable (e.g. + * sporadically bits flip), this will fail from time to time. E.g. on the + * MSB-IoT boards this is the case when the SPI interface operates at a clock of + * 5MHz, but it becomes reliable when clocked at 1MHz. + * + * The Driver Initializes, but Communication Is Impossible + * ------------------------------------------------------- + * If two transceivers are too close to each other and TX power is at maximum, + * the signal is just too strong to be received correctly. Reducing TX power + * or increasing the distance (about half a meter should be fine) will solve + * this issue. + * + * While the chips can operate at any base frequency offered by the driver, + * the circuit the chip is connected to and the antenna are build for a single + * base band. Check if your configuration matches the frequency range the + * board is build for. E.g. most break out boards operate at 433MHz, but there + * are also boards for 868MHz. + * + * @{ + * + * @file + * @brief Interface definition for the CC1100/CC1101 driver + * + * @author Marian Buschsieweke + * @author Oliver Hahm + * @author Fabian Nack + * @author Kaspar Schleiser + */ + +#ifndef CC110X_H +#define CC110X_H + +#include + +#include "cc1xxx_common.h" +#include "mutex.h" +#include "net/gnrc/nettype.h" +#include "net/netdev.h" +#include "periph/adc.h" +#include "periph/gpio.h" +#include "periph/spi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Length of a layer 2 frame + * + * This does not include the preamble, sync word, CRC field, and length field. + */ +#define CC110X_MAX_FRAME_SIZE 0xFF + +/** + * @brief Maximum (layer 2) payload size supported by the driver + */ +#define CC110X_MAX_PAYLOAD_SIZE (CC110X_MAX_FRAME_SIZE - CC1XXX_HEADER_SIZE) + +/** + * @brief Maximum number of channels supported by the driver + */ +#define CC110X_MAX_CHANNELS 8 + +/** + * @brief Special value to indicate that layer 2 address should be derived + * from the CPU-ID + */ +#define CC110X_L2ADDR_AUTO 0x00 + +/** + * @brief Default protocol for data that is coming in + */ +#ifdef MODULE_GNRC_SIXLOWPAN +#define CC110X_DEFAULT_PROTOCOL (GNRC_NETTYPE_SIXLOWPAN) +#else +#define CC110X_DEFAULT_PROTOCOL (GNRC_NETTYPE_UNDEF) +#endif + +/** + * @brief The state of the CC1100/CC1101 transceiver + * + * The three least significant bytes match the representation of the matching + * transceiver state given in the status byte of the hardware. See Table 32 on + * page 31 in the data sheet for the possible states in the status byte. + */ +typedef enum { + CC110X_STATE_IDLE = 0b00000000, /**< IDLE state */ + /** + * @brief Frame received, waiting for upper layer to retrieve it + * + * Transceiver is in IDLE state. + */ + CC110X_STATE_FRAME_READY = 0b00001000, + /** + * @brief Frame received, waiting for upper layer to retrieve it + * + * Transceiver is in SLEEP state. There is no matching representation in the + * status byte, as reading the status byte will power up the transceiver in + * bring it in the IDLE state. Thus, we set the three least significant bits + * to the IDLE state + */ + CC110X_STATE_OFF = 0b00010000, + CC110X_STATE_RX_MODE = 0b00000001, /**< Listening for frames */ + /** + * @brief Receiving a frame just now + * + * Transceiver is in RX state. + */ + CC110X_STATE_RECEIVING = 0b00001001, + CC110X_STATE_TX_MODE = 0b00000010, /**< Transmit mode */ + /** + * @brief Waiting for transceiver to complete outgoing transmission + * + * Transceiver is in TX state + */ + CC110X_STATE_TX_COMPLETING = 0b00001010, + CC110X_STATE_FSTXON = 0b00000011, /**< Fast TX ready */ + CC110X_STATE_CALIBRATE = 0b00000100, /**< Device is calibrating */ + CC110X_STATE_SETTLING = 0b00000101, /**< PLL is settling */ + CC110X_STATE_RXFIFO_OVERFLOW = 0b00000110, /**< RX FIFO overflown */ + CC110X_STATE_TXFIFO_UNDERFLOW = 0b00000111, /**< TX FIFO underflown */ +} cc110x_state_t; + +/** + * @brief Enumeration over the possible TX power settings the driver offers + */ +typedef enum { + CC110X_TX_POWER_MINUS_30_DBM, /**< -30 dBm */ + CC110X_TX_POWER_MINUS_20_DBM, /**< -20 dBm */ + CC110X_TX_POWER_MINUS_15_DBM, /**< -15 dBm */ + CC110X_TX_POWER_MINUS_10_DBM, /**< -10 dBm */ + CC110X_TX_POWER_0_DBM, /**< 0 dBm */ + CC110X_TX_POWER_PLUS_5_DBM, /**< 5 dBm */ + CC110X_TX_POWER_PLUS_7_DBM, /**< 7 dBm */ + CC110X_TX_POWER_PLUS_10_DBM, /**< 1 dBm */ + CC110X_TX_POWER_NUMOF, /**< Number of TX power options */ +} cc110x_tx_power_t; + +/** + * @brief Structure that holds the PATABLE, which allows to configure the + * 8 available output power levels using a magic number for each level. + * + * See Section "24 Output Power Programming" on page 59ff in the data sheet. + * The values suggested in Table 39 on page 60 in the data sheet are already + * available by this driver, but will only be linked in (8 bytes of ROM size) + * when they are referenced. + * + * @see cc110x_patable_433mhz + * @see cc110x_patable_868mhz + * @see cc110x_patable_915mhz + */ +typedef struct { + uint8_t data[8]; /**< Magic number to store in the configuration register */ +} cc110x_patable_t; + + +/** + * @brief Configuration of the transceiver to use + * + * @warning Two transceivers with different configurations will be unable + * to communicate. + * + * The data uploaded into configuration registers are stored in + * @ref cc110x_conf. Most of them cannot be changed, as the driver relies on + * their values. However, the base frequency, the symbol rate (which equals + * the bit rate for the chosen modulation and error correction) and the + * channel bandwidth can be configured using this data structure. + * + * Please note that while the CC1100/CC1101 chip is compatible with a huge + * frequency range (300 MHz - 928 MHz), the complete circuit is optimized to + * a narrow frequency band. So make sure the configured base frequency is within + * that frequency band that is compatible with that circuit. (Most break out + * board will operate at the 433 MHz band. In the EU the 868 MHz band would be + * more interesting, but 433 MHz is license free as well. In the USA the 915 MHz + * band is license free. + * + * Please verify that the driver is configured in a way that allows legal + * operation according to rules and laws that apply for you. + */ +typedef struct { + uint8_t base_freq[3]; /**< Base frequency to use */ + /** + * @brief FSCTRL1 configuration register value that affects the + * intermediate frequency of the transceiver to use + * @note The 4 most significant bits have to be 0. + * + * Assuming a 26 MHz crystal the IF is calculated as follows (in kHz): + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * double intermediate_frequency = 26000 / 1024 * fsctrl1; + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + uint8_t fsctrl1; + /** + * @brief MDMCFG4 configuration register value that affects channel filter + * bandwidth and the data rate + * + * See page 76 in the data sheet. + * + * Assuming a 26 MHz crystal the channel filter bandwidth is calculated + * as follows (in kHz): + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * uint8_t exponent = mdmcfg4 >> 6; + * uint8_t mantissa = (mdmcfg4 >> 4) & 0x03; + * double bandwidth = 26000.0 / (8 * (4 + mantissa) * (1L << exponent)); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + uint8_t mdmcfg4; + /** + * @brief MDMCFG3 configuration register value that affects the data rate + * + * @see cc110x_config_t::mdmcfg4 + * + * See page 76 in the data sheet. + * + * Assuming a 26 MHz crystal the symbol rate of the transceiver is calculated + * as fallows (in kBaud): + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * uint8_t exponent = mdmcfg4 & 0x0f; + * int32_t mantissa = mdmcfg3; + * double baudrate = (256 + mantissa) * 26000.0 / (1L << (28 - exponent)); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + uint8_t mdmcfg3; + /** + * @brief DEVIANT configuration register that affects the amount by which + * the radio frequency is shifted in FSK/GFSK modulation + * + * @see cc110x_config_t::mdmcfg4 + * + * See page 79 in the data sheet. + * + * In an ideal world the channel bandwidth would be twice the channel + * deviation. In the real world the used channel bandwidth is higher. + * Assuming a 26 MHz crystal and GFSK modulation (the driver will configure + * the transceiver to use GFSK) the deviation + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * uint8_t exponent = (deviatn >> 4) & 0x07; + * int32_t mantissa = deviatn & 0x07; + * double deviation = (8 + mantissa) * 26000.0 / (1L << (17 - exponent)); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * For reliable operation at high symbol rates, the deviation has to be + * increased as well. + */ + uint8_t deviatn; +} cc110x_config_t; + +/** + * @brief Structure to hold mapping between virtual and physical channel numbers + * + * This driver will provide "virtual" channel numbers 0 to 7, which will be + * translated to "physical" channel numbers before being send to the + * transceiver. This is used to overcome the following limitations: + * + * - The transceiver does not support channel maps with varying distance between + * channels. However, e.g. the LoRa channels 10 - 16 in the 868 MHz band have + * a distance of 300 kHz, but channel 16 and 17 have a distance of 1 MHz. + * - The transceiver does not supports channel distances higher than 405.46 kHz. + * + * This mapping overcomes both limitations be using 50kHz physical channel + * spacing and use the map to translate to the correct physical channel. This + * also allows to keep the same MDMCFG1 and MDMCFG0 configuration register + * values for all channel layouts. Finally, different channel sets can be + * used by different groups of IoT device in the same environment to limit + * collisions between those groups - assuming that enough non-overlapping + * channels are available. + * + * The "virtual" channel (the channel number presented to RIOT) will be used + * as index in @ref cc110x_chanmap_t::map, the value in there will give the + * corresponding "physical" channel number, or 255 if this virtual channel + * number is not available. + */ +typedef struct { + uint8_t map[CC110X_MAX_CHANNELS]; /**< "Physical" channel numbers */ +} cc110x_chanmap_t; + +/** + * @brief Structure holding all parameter for driver initialization + */ +typedef struct { + const cc110x_patable_t *patable; /**< Pointer to the PATABLE to use */ + /** + * @brief Pointer to the configuration of the base frequency, data rate and + * channel bandwidth; or `NULL` to keep the default. + */ + const cc110x_config_t *config; + const cc110x_chanmap_t *channels; /**< Pointer to the default channel map */ + spi_t spi; /**< SPI bus connected to the device */ + spi_clk_t spi_clk; /**< SPI clock to use (max 6.5 MHz) */ + spi_cs_t cs; /**< GPIO pin connected to chip select */ + gpio_t gdo0; /**< GPIO pin connected to GDO0 */ + gpio_t gdo2; /**< GPIO pin connected to GDO2 */ + /** + * @brief Layer-2 address to use or `CC110X_L2ADDR_AUTO` to derive it from + * the CPU ID + */ + uint8_t l2addr; +} cc110x_params_t; + +/** + * @brief Structure holding the calibration data of the frequency synthesizer + */ +typedef struct { + /** + * @brief VCO capacitance calibration, which depends on the frequency and, + * thus, has to be stored for each channel + */ + char fscal1[CC110X_MAX_CHANNELS]; + char fscal2; /**< VCO current calibration, independent of channel */ + char fscal3; /**< charge pump current calibration, independent of channel */ +} cc110x_fs_calibration_t; + +/** + * @brief Buffer to temporary store incoming/outgoing packet + * + * The CC1100/CC1101 transceiver's FIFO sadly is only 64 bytes in size. To + * support frames bigger than that, chunks of the frame have to be + * transferred between the MCU and the CC1100/CC1101 transceiver while the + * frame is in transit. + */ +typedef struct __attribute__((packed)) { + uint8_t len; /**< Length of the frame in bytes */ + /** + * @brief The payload data of the frame + */ + uint8_t data[CC110X_MAX_FRAME_SIZE]; + /** + * @brief Index of the next @ref cc110x_framebuf_t::data element to transfer + * + * In RX mode: Index of the next @ref cc110x_framebuf_t::data element to store + * data read from the RX-FIFO into. + * + * In TX mode: Index of the next @ref cc110x_framebuf_t::data element to write + * to the TX-FIFO. + */ + uint8_t pos; +} cc110x_framebuf_t; + +/** + * @brief Device descriptor for CC1100/CC1101 transceivers + */ +typedef struct { + netdev_t netdev; /**< RIOT's interface to this driver */ + uint8_t addr; /**< Layer 2 address of this device */ + /* Keep above in sync with cc1xx_t members, as they must overlap! */ + cc110x_state_t state; /**< State of the transceiver */ + cc110x_tx_power_t tx_power; /**< TX power of the receiver */ + uint8_t channel; /**< Currently tuned (virtual) channel */ + /* Struct packing: addr, state, tx_power and channel add up to 32 bit */ + const cc110x_chanmap_t *channels; /**< Pointer to the channel map to use. */ + cc110x_params_t params; /**< Configuration of the driver */ + cc110x_framebuf_t buf; /**< Temporary frame buffer */ + /** + * @brief RSSI and LQI of the last received frame + */ + cc1xxx_rx_info_t rx_info; + /** + * @brief Frequency synthesizer calibration data + */ + cc110x_fs_calibration_t fscal; + /** + * @brief Use mutex to block during TX and unblock from ISR when ISR + * needs to be handled from thread-context + * + * Blocking during TX within the driver prevents the upper layers from + * calling @ref netdev_driver_t::send while already transmitting a frame. + */ + mutex_t isr_signal; + uint8_t rssi_offset; /**< dBm to subtract from raw RSSI data */ +} cc110x_t; + +/** + * @brief Setup the CC1100/CC1101 driver, but perform no initialization + * + * @ref netdev_driver_t::init can be used after this call to initialize the + * transceiver. + * + * @param dev Device descriptor to use + * @param params Parameter of the device to setup + * + * @retval 0 Device successfully set up + * @retval -EINVAL @p dev or @p params is `NULL`, or @p params is invalid + */ +int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params); + +/** + * @brief Apply the given configuration and the given channel map and performs + * a recalibration + * + * @param dev Device descriptor of the transceiver + * @param conf Configuration to apply or `NULL` to only change channel map + * @param chanmap Channel map to apply (must be compatible with @p conf) + * + * @retval 0 Success + * @retval -EINVAL Called with invalid argument + * @retval -EIO Communication with the transceiver failed + * + * @pre The application developer checked in the documentation that the channel + * map in @p chanmap is compatible with the configuration in @p conf + * + * Because the configuration (potentially) changes the channel bandwidth, the + * old channel map is rendered invalid. This API therefore asks for both to make + * sure an application developer does not forget to update the channel map. + * Because the old calibration data is also rendered invalid, + * @ref cc110x_full_calibration is called to update it. + */ +int cc110x_apply_config(cc110x_t *dev, const cc110x_config_t *conf, + const cc110x_chanmap_t *chanmap); + +/** + * @brief Perform a calibration of the frequency generator for each supported + * channel + * + * @param dev Device descriptor of the transceiver + * + * @retval 0 Success + * @retval -EINVAL Called with invalid argument + * @retval -EAGAIN Current state prevents deliberate calibration + * @retval -EIO Communication with the transceiver failed + * + * Tunes in each supported channel and calibrates the transceiver. The + * calibration data is stored so that @ref cc110x_set_channel can skip the + * calibration phase and use the stored calibration data instead. + */ +int cc110x_full_calibration(cc110x_t *dev); + +/** + * @brief Hops to the specified channel + * + * @param dev Device descriptor of the transceiver + * @param channel Channel to hop to + * + * @retval 0 Success + * @retval -EINVAL Called with `NULL` as @p dev + * @retval -ERANGE Channel out of range or not supported by channel map + * @retval -EAGAIN Currently in a state that does not allow hopping, e.g. + * sending/receiving a packet, calibrating or handling + * transmission errors + * @retval -EIO Communication with the transceiver failed + * + * This function implements the fact channel hopping approach outlined in + * section 28.2 on page 64 in the data sheet, which skips the calibration phase + * by storing the calibration date for each channel in the driver. + */ +int cc110x_set_channel(cc110x_t *dev, uint8_t channel); + +/** + * @brief Set the TX power to the specified value + * + * @param dev Device descriptor of the transceiver + * @param power Output power to apply + * + * @retval 0 Success + * @retval -EINVAL Called with `NULL` as @p dev + * @retval -ERANGE Called with an invalid value for @p power + * @retval -EAGAIN Changing the TX power is in the current state not possible + * @retval -EIO Communication with the transceiver failed + */ +int cc110x_set_tx_power(cc110x_t *dev, cc110x_tx_power_t power); + +#ifdef __cplusplus +} +#endif + +#endif /* CC110X_H */ +/** @} */ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 47ee91cff6cc..72542fb28f6c 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -97,6 +97,11 @@ PSEUDOMODULES += adc121c # full featured version of CCS811 driver as pseudo module PSEUDOMODULES += ccs811_full +# include variants of CC110X drivers as pseudo modules +PSEUDOMODULES += cc1100 +PSEUDOMODULES += cc1100e +PSEUDOMODULES += cc1101 + # include variants of SX127X drivers as pseudo modules PSEUDOMODULES += sx1272 PSEUDOMODULES += sx1276 diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index ac123db8443e..9585445687dd 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -206,6 +206,11 @@ void auto_init(void) auto_init_mrf24j40(); #endif +#ifdef MODULE_CC110X + extern void auto_init_cc110x(void); + auto_init_cc110x(); +#endif + #ifdef MODULE_CC2420 extern void auto_init_cc2420(void); auto_init_cc2420(); diff --git a/sys/auto_init/netif/auto_init_cc110x.c b/sys/auto_init/netif/auto_init_cc110x.c index 7a0e9df67eb5..1403c5f7c684 100644 --- a/sys/auto_init/netif/auto_init_cc110x.c +++ b/sys/auto_init/netif/auto_init_cc110x.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Kaspar Schleiser + * 2016 Freie Universität Berlin * * 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 @@ -7,62 +8,63 @@ * */ -/* - * @ingroup sys_auto_init_gnrc_netif +/** + * @ingroup sys_auto_init_gnrc_netif * @{ * * @file - * @brief Auto initialization for cc110x network interfaces + * @brief Auto initialization for cc110x network interfaces * - * @author Kaspar Schleiser + * @author Kaspar Schleiser + * @author Hauke Petersen */ #ifdef MODULE_CC110X #include "log.h" -#include "debug.h" -#include "board.h" -#include "gnrc_netif_cc110x.h" -#include "cc110x-netdev.h" -#include "net/gnrc.h" - #include "cc110x.h" +#include "cc1xxx_common.h" #include "cc110x_params.h" +#define ENABLE_DEBUG (0) +#include "debug.h" /** - * @brief Define stack parameters for the MAC layer thread - * @{ + * @brief Calculate the stack size for the MAC layer thread(s) */ -#define CC110X_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE) +#define CC110X_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE) #ifndef CC110X_MAC_PRIO -#define CC110X_MAC_PRIO (GNRC_NETIF_PRIO) +/** + * @brief The priority of the MAC layer thread + */ +#define CC110X_MAC_PRIO (GNRC_NETIF_PRIO) #endif -#define CC110X_NUM ARRAY_SIZE(cc110x_params) +/** + * @brief Calculate the number of configured CC1100/CC1101 transceivers + */ +#define CC110X_NUM ARRAY_SIZE(cc110x_params) -static netdev_cc110x_t cc110x_devs[CC110X_NUM]; -static char _stacks[CC110X_NUM][CC110X_MAC_STACKSIZE]; +/** + * @brief Statically allocate memory for device descriptors + */ +cc110x_t _cc110x_devs[CC110X_NUM]; +/** + * @brief Statically allocate memory for the MAC layer thread(s) + */ +static char stacks[CC110X_NUM][CC110X_MAC_STACKSIZE]; void auto_init_cc110x(void) { for (unsigned i = 0; i < CC110X_NUM; i++) { - const cc110x_params_t *p = &cc110x_params[i]; - LOG_DEBUG("[auto_init_netif] initializing cc110x #%u\n", i); - int res = netdev_cc110x_setup(&cc110x_devs[i], p); - if (res < 0) { - LOG_ERROR("[auto_init_netif] error initializing cc110x #%u\n", i); - } - else { - gnrc_netif_cc110x_create(_stacks[i], CC110X_MAC_STACKSIZE, - CC110X_MAC_PRIO, "cc110x", - (netdev_t *)&cc110x_devs[i]); - } + cc110x_setup(&_cc110x_devs[i], &cc110x_params[i]); + gnrc_netif_cc1xxx_create(stacks[i], CC110X_MAC_STACKSIZE, CC110X_MAC_PRIO, + "cc110x", (netdev_t *)&_cc110x_devs[i]); } } + #else typedef int dont_be_pedantic; #endif /* MODULE_CC110X */ - /** @} */ From 88cf6cb46fd89a357568a90f364da2f80142cf12 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 11 Jun 2019 11:32:49 +0200 Subject: [PATCH 3/7] sys/auto_init/netif: Increased cc110x stack size With the increase of the message queue size from 8 to 16 in 946b06e4f0ea2faf8b63f427dab3720e48790f76, the default stack became too small. This changes the stack size to grow with the message queue size. --- sys/auto_init/netif/auto_init_cc110x.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/sys/auto_init/netif/auto_init_cc110x.c b/sys/auto_init/netif/auto_init_cc110x.c index 1403c5f7c684..42645c6c8458 100644 --- a/sys/auto_init/netif/auto_init_cc110x.c +++ b/sys/auto_init/netif/auto_init_cc110x.c @@ -21,22 +21,37 @@ #ifdef MODULE_CC110X -#include "log.h" #include "cc110x.h" #include "cc1xxx_common.h" #include "cc110x_params.h" +#include "log.h" +#include "msg.h" +#include "net/gnrc/netif/conf.h" /* <- GNRC_NETIF_MSG_QUEUE_SIZE */ #define ENABLE_DEBUG (0) #include "debug.h" +#ifndef CC110X_EXTRA_STACKSIZE +/** + * @brief Additional stack size required by the driver + * + * With increasing of GNRC_NETIF_MSG_QUEUE_SIZE the required stack size + * increases as well. A queue size of 8 messages works with default stack size, + * so we increase the stack by `sizeof(msg_t)` for each additional element + */ +#define CC110X_EXTRA_STACKSIZE ((GNRC_NETIF_MSG_QUEUE_SIZE - 8) * sizeof(msg_t)) +#endif + /** * @brief Calculate the stack size for the MAC layer thread(s) */ -#define CC110X_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE) +#define CC110X_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + \ + CC110X_EXTRA_STACKSIZE + \ + DEBUG_EXTRA_STACKSIZE) #ifndef CC110X_MAC_PRIO /** * @brief The priority of the MAC layer thread */ -#define CC110X_MAC_PRIO (GNRC_NETIF_PRIO) +#define CC110X_MAC_PRIO (GNRC_NETIF_PRIO) #endif /** From 137c2c0adfd9aad88c3917b97bce85e9ada0c225 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Fri, 21 Dec 2018 10:36:01 +0100 Subject: [PATCH 4/7] boards: Added cc110x params for MSB-A2 & MSB-IoT --- boards/msba2/Makefile.dep | 4 ++++ boards/msbiot/Makefile.dep | 4 ++++ boards/msbiot/include/board.h | 10 +++++----- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/boards/msba2/Makefile.dep b/boards/msba2/Makefile.dep index 629c28a5432c..b0ec516ac260 100644 --- a/boards/msba2/Makefile.dep +++ b/boards/msba2/Makefile.dep @@ -1,5 +1,9 @@ include $(RIOTBOARD)/common/msba2/Makefile.dep +ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE))) + USEMODULE += cc1100 +endif + ifneq (,$(filter saul_default,$(USEMODULE))) USEMODULE += ltc4150 USEMODULE += sht11 diff --git a/boards/msbiot/Makefile.dep b/boards/msbiot/Makefile.dep index ab057998f197..c1c23ead6996 100644 --- a/boards/msbiot/Makefile.dep +++ b/boards/msbiot/Makefile.dep @@ -1,3 +1,7 @@ +ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE))) + USEMODULE += cc1101 +endif + # add support for LEDs and buttons as default saul devices ifneq (,$(filter saul_default,$(USEMODULE))) USEMODULE += saul_gpio diff --git a/boards/msbiot/include/board.h b/boards/msbiot/include/board.h index 4af33f6f32af..55d08dcec1fb 100644 --- a/boards/msbiot/include/board.h +++ b/boards/msbiot/include/board.h @@ -30,11 +30,11 @@ extern "C" { * @name Configure connected CC1101 (radio) device * @{ */ -#define CC110X_PARAM_SPI SPI_DEV(0) /**< SPI interface CC1101 is connected to */ -#define CC110X_PARAM_CS GPIO_PIN(PORT_B, 12) /**< CS pin of CC1101 */ -#define CC110X_PARAM_GDO0 GPIO_PIN(PORT_C, 4) /**< GDO0 pin of CC1101 */ -#define CC110X_PARAM_GDO1 GPIO_PIN(PORT_A, 6) /**< GDO1 pin of CC1101 */ -#define CC110X_PARAM_GDO2 GPIO_PIN(PORT_C, 5) /**< GDO2 pin of CC1101 */ +#define CC110X_PARAM_SPI SPI_DEV(0) /**< SPI interface CC1101 is connected to */ +#define CC110X_PARAM_CS GPIO_PIN(PORT_B, 12) /**< CS pin of CC1101 */ +#define CC110X_PARAM_GDO0 GPIO_PIN(PORT_C, 4) /**< GDO0 pin of CC1101 */ +#define CC110X_PARAM_GDO2 GPIO_PIN(PORT_C, 5) /**< GDO2 pin of CC1101 */ +#define CC110X_PARAM_SPI_CLOCK SPI_CLK_1MHZ /**< SPI clock (reduced to work around hw bug) */ /** @} */ /** From ccf713c5adc6be059c66b585050f5905667e7ad6 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 19 Jun 2019 14:50:31 +0200 Subject: [PATCH 5/7] drivers/cc1xxx_common: L2 netstats & cleanups - Added required logic to provide correct L2 netstats when the module netstats_l2 is used. - Refactored code to use gnrc_netif_hdr_set_netif() over manually setting the pid to ease future refactoring. --- drivers/cc1xxx_common/gnrc_netif_cc1xxx.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c b/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c index 2c55bc11b643..0c4498427ec9 100644 --- a/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c +++ b/drivers/cc1xxx_common/gnrc_netif_cc1xxx.c @@ -86,7 +86,7 @@ static gnrc_pktsnip_t *cc1xxx_adpt_recv(gnrc_netif_t *netif) return NULL; } netif_hdr = (gnrc_netif_hdr_t *)hdr->data; - netif_hdr->if_pid = netif->pid; + gnrc_netif_hdr_set_netif(netif_hdr, netif); netif_hdr->rssi = rx_info.rssi; netif_hdr->lqi = rx_info.lqi; if (l2hdr.dest_addr == CC1XXX_BCAST_ADDR) { @@ -98,6 +98,11 @@ static gnrc_pktsnip_t *cc1xxx_adpt_recv(gnrc_netif_t *netif) /* and append the netif header */ LL_APPEND(payload, hdr); +#ifdef MODULE_NETSTATS_L2 + netif->stats.rx_count++; + netif->stats.rx_bytes += pktlen; +#endif + return payload; } @@ -122,6 +127,9 @@ static int cc1xxx_adpt_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) if (netif_hdr->flags & BCAST) { l2hdr.dest_addr = CC1XXX_BCAST_ADDR; DEBUG("[cc1xxx-gnrc] send: preparing to send broadcast\n"); +#ifdef MODULE_NETSTATS_L2 + netif->stats.tx_mcast_count++; +#endif } else { /* check that destination address is valid */ @@ -130,6 +138,9 @@ static int cc1xxx_adpt_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) l2hdr.dest_addr = addr[0]; DEBUG("[cc1xxx-gnrc] send: preparing to send unicast %02x --> %02x\n", (int)l2hdr.src_addr, (int)l2hdr.dest_addr); +#ifdef MODULE_NETSTATS_L2 + netif->stats.tx_unicast_count++; +#endif } /* now let's send out the stuff */ From f33b963ef4d95caff94c311568ea9997b412f2d9 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 19 Jun 2019 17:27:06 +0200 Subject: [PATCH 6/7] tests: Added test for the cc110x driver The test application provides: - RIOT's basic network utilities such as `ping6` - A custom `cc110x` shell command that can be used print the low level device and driver state. This is mostly useful for debugging. --- tests/driver_cc110x/Makefile | 57 +++++++++ tests/driver_cc110x/main.c | 134 ++++++++++++++++++++ tests/driver_cc110x/sc_cc110x.c | 208 ++++++++++++++++++++++++++++++++ 3 files changed, 399 insertions(+) create mode 100644 tests/driver_cc110x/Makefile create mode 100644 tests/driver_cc110x/main.c create mode 100644 tests/driver_cc110x/sc_cc110x.c diff --git a/tests/driver_cc110x/Makefile b/tests/driver_cc110x/Makefile new file mode 100644 index 000000000000..d2f9afbc7101 --- /dev/null +++ b/tests/driver_cc110x/Makefile @@ -0,0 +1,57 @@ +BOARD ?= msba2 +include ../Makefile.tests_common + +DEVICE ?= cc1100 # The MSB-A2 uses the CC1100. New boards use CC1101 + +BOARD_INSUFFICIENT_MEMORY += arduino-duemilanove +BOARD_INSUFFICIENT_MEMORY += arduino-leonardo +BOARD_INSUFFICIENT_MEMORY += arduino-mega2560 +BOARD_INSUFFICIENT_MEMORY += arduino-nano +BOARD_INSUFFICIENT_MEMORY += arduino-uno +BOARD_INSUFFICIENT_MEMORY += blackpill +BOARD_INSUFFICIENT_MEMORY += bluepill +BOARD_INSUFFICIENT_MEMORY += i-nucleo-lrwan1 +BOARD_INSUFFICIENT_MEMORY += mega-xplained +BOARD_INSUFFICIENT_MEMORY += nucleo-f031k6 +BOARD_INSUFFICIENT_MEMORY += nucleo-f042k6 +BOARD_INSUFFICIENT_MEMORY += nucleo-f072rb +BOARD_INSUFFICIENT_MEMORY += nucleo-f302r8 +BOARD_INSUFFICIENT_MEMORY += nucleo-f303k8 +BOARD_INSUFFICIENT_MEMORY += nucleo-f334r8 +BOARD_INSUFFICIENT_MEMORY += nucleo-l031k6 +BOARD_INSUFFICIENT_MEMORY += nucleo-l053r8 +BOARD_INSUFFICIENT_MEMORY += saml10-xpro +BOARD_INSUFFICIENT_MEMORY += saml11-xpro +BOARD_INSUFFICIENT_MEMORY += stm32f0discovery +BOARD_INSUFFICIENT_MEMORY += stm32l0538-disco +BOARD_INSUFFICIENT_MEMORY += waspmote-pro + +# stdlib.h for msp430 does not provide EXIT_FAILURE and EXIT_SUCCESS +BOARD_BLACKLIST += msb-430 msb-430h telosb wsn430-v1_3b wsn430-v1_4 z1 + +# This test will rely on a human interacting with the shell, so we better add +# the shell and some commands +USEMODULE += shell +USEMODULE += shell_commands +# Add the device driver +USEMODULE += $(DEVICE) +# Add a network stack and auto init of the network devices +USEMODULE += gnrc +USEMODULE += auto_init_gnrc_netif +USEMODULE += gnrc_ipv6_router_default +# checking current state of network threads can be useful for testing/debuggig +USEMODULE += ps +# txtsnd can be useful to test lower layers +USEMODULE += gnrc_txtsnd +USEMODULE += auto_init_gnrc_netif +# Activate ICMPv6 error messages +USEMODULE += gnrc_icmpv6_error +# This application dumps received packets to STDIO using the pktdump module +USEMODULE += gnrc_pktdump +# Additional networking modules that can be dropped if not needed +USEMODULE += gnrc_icmpv6_echo +# Some statistics could also be helpful +USEMODULE += netstats_l2 +USEMODULE += netstats_ipv6 + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_cc110x/main.c b/tests/driver_cc110x/main.c new file mode 100644 index 000000000000..5e3ff85d6288 --- /dev/null +++ b/tests/driver_cc110x/main.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application for the CC110x driver + * + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include + +#include "shell.h" +#include "shell_commands.h" + +#include "net/gnrc/pktdump.h" +#include "net/gnrc.h" + +#define MAIN_QUEUE_SIZE (8) + +static int sc_dump(int argc, char **argv); +int sc_cc110x(int argc, char **argv); + +static const shell_command_t shell_commands[] = { + { "dump", "Enable/disable dumping of frames", sc_dump }, + { "cc110x", "Print the low level state of an CC110x device", sc_cc110x }, + { NULL, NULL, NULL } +}; + +static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; +static gnrc_netreg_entry_t dump; + +static int sc_dump(int argc, char **argv) +{ + static int is_enabled = 0; + if (argc == 1) { + if (is_enabled) { + puts("Currently dumping packets"); + } + else { + puts("Currently NOT dumping packets"); + } + return 0; + } + else if (argc == 2) { + int new_state = 0; + if (!strcmp("y", argv[1])) { + new_state = 1; + } + else if (!strcmp("n", argv[1])) { + new_state = 0; + } + else { + printf("Usage: %s [y/n]\n", argv[0]); + return 0; + } + if (new_state == is_enabled) { + // Nothing to do; + return 0; + } + + if (new_state) { + if (gnrc_netreg_register(GNRC_NETTYPE_SIXLOWPAN, &dump)) { + puts("Failed to register packet dumping"); + } + } + else { + gnrc_netreg_unregister(GNRC_NETTYPE_SIXLOWPAN, &dump); + } + + is_enabled = new_state; + return 0; + } + + printf("Usage: %s [y/n]\n", argv[0]); + return 0; +} + +int main(void) +{ + /* we need a message queue for the thread running the shell in order to + * receive potentially fast incoming networking packets */ + msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE); + + gnrc_netreg_entry_init_pid(&dump, GNRC_NETREG_DEMUX_CTX_ALL, + gnrc_pktdump_pid); + + puts("cc110x driver test application\n" + "==============================\n" + "\n" + "Use the shell and two boards equipped with an CC1100/CC1101\n" + "transceiver to test the driver. Common testing tasks:\n" + "\n" + "- Using \"ifconfig\":\n" + " - Check the information stated for plausibility/correctness\n" + " - Try to get/set parameters like TX power, channel, address, ...\n" + " - BEWARE: With short communication distances (<=1m) for boards\n" + " with high gain antennas a high TX power may result in packet\n" + " loss: The incoming signal can only be demodulated when the\n" + " input signal is at most +10 dBm on the CC1101.\n" + " - Check the statistics for correctness/plausibility (after\n" + " sending frames using \"txtsnd\" or \"ping6\")\n" + "- Using \"ping6\":\n" + " - Does the other device respond to the ping?\n" + " - Does the measured RSSI increase when the nodes are closer\n" + " together?\n" + " - Try to increase the size of the pings, so that the TX/RX FIFO\n" + " needs to be filled/drain more than once per frame. The TX/RX\n" + " FIFO can hold 64 bytes\n" + " - Try to increase the size of the pings in order to trigger L2\n" + " fragmentation. The driver supports frames of up to 255 bytes\n" + "- Using \"txtsnd\":\n" + " - Turn on packet dumping using the command \"dump y\" on node A\n" + " - Send both unicast and broadcast frame from node B to A\n" + "- Using \"cc110x\":\n" + " - This tool will print low level details for all CC110x devices\n" + " attached\n" + " - This will be mostly useful for debugging, not for testing\n"); + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +} diff --git a/tests/driver_cc110x/sc_cc110x.c b/tests/driver_cc110x/sc_cc110x.c new file mode 100644 index 000000000000..5cf55d652fc4 --- /dev/null +++ b/tests/driver_cc110x/sc_cc110x.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include +#include +#include +#include +#include "cc110x.h" +#include "cc110x_internal.h" +#include "cc110x_params.h" + +#define CC110X_NUM (sizeof(cc110x_params) / sizeof(cc110x_params[0])) + +extern cc110x_t _cc110x_devs[CC110X_NUM]; + +static const char *pa_settings[] = { + "-30", + "-20", + "-15", + "-10", + "0", + "+5", + "+7", + "+10", +}; + +static const char *state2s(cc110x_state_t state) +{ + switch (state) { + case CC110X_STATE_IDLE: + return "IDLE"; + case CC110X_STATE_FRAME_READY: + return "Frame ready"; + case CC110X_STATE_OFF: + return "Off"; + case CC110X_STATE_RX_MODE: + return "RX mode"; + case CC110X_STATE_RECEIVING: + return "RX mode and currently receiving frame"; + case CC110X_STATE_TX_MODE: + return "TX"; + case CC110X_STATE_TX_COMPLETING: + return "TX completing"; + case CC110X_STATE_FSTXON: + return "Fast TX on"; + case CC110X_STATE_CALIBRATE: + return "Calibrating"; + case CC110X_STATE_SETTLING: + return "Settling"; + case CC110X_STATE_RXFIFO_OVERFLOW: + return "RX FIFO overflow"; + case CC110X_STATE_TXFIFO_UNDERFLOW: + return "TX FIFO underflow"; + } + return "Unknown"; +} + +static const char *gdoconf2s(uint8_t conf) +{ + switch (conf) { + case CC110X_GDO_ON_RX_DATA: + return "High when frame received or RX FIFO needs draining"; + case CC110X_GDO_ON_TX_DATA: + return "Low when TX FIFO needs refilling"; + case CC110X_GDO_ON_TRANSMISSION: + return "High while frame is incoming / outgoing"; + case CC110X_GDO_ON_CHANNEL_CLEAR: + return "High when channel is clear"; + case CC110X_GDO_ON_PLL_IN_LOCK: + return "High when frequency generator is on and PLL is in lock"; + case CC110X_GDO_CONSTANT_LOW: + return "Constant low"; + case CC110X_GDO_CONSTANT_HIGH: + return "Constant high"; + case CC110X_GDO0_ANALOG_TEMPERATURE: + return "Analog output of the temperature sensor (GDO0 only)"; + } + + return "Unknown"; +} + +static inline const char *b2s(int boolean) +{ + return (boolean) ? "1" : "0"; +} + +static void print_state(cc110x_t *dev) +{ + uint8_t status; + uint8_t pktstatus; + int8_t rssi_raw; + uint8_t iocfg2; + uint8_t iocfg0; + uint8_t txbytes; + uint8_t rxbytes; + uint8_t hwaddr; + uint8_t frend0; + uint8_t physical_channel; + uint8_t virtual_channel; + + /* Get all required data and release device */ + if (cc110x_acquire(dev) != SPI_OK) { + puts("Failed to acquire CC1100/CC1101 transceiver"); + return; + } + + /* Reading out the RSSI changes it, as SPI communication seems to generate + * some noise. Reading the RSSI out first yields up to 20 dBm lower + * values... (E.g. about -100dBm instead of about -80dBm with no + * other sources of Sub-GHz RF) + */ + status = cc110x_read_reliable(dev, CC110X_REG_RSSI, (uint8_t *)&rssi_raw); + cc110x_read_reliable(dev, CC110X_REG_PKTSTATUS, &pktstatus); + cc110x_read(dev, CC110X_REG_IOCFG2, &iocfg2); + cc110x_read(dev, CC110X_REG_IOCFG0, &iocfg0); + cc110x_read(dev, CC110X_REG_ADDR, &hwaddr); + cc110x_read(dev, CC110X_REG_FREND0, &frend0); + cc110x_read(dev, CC110X_REG_CHANNR, &physical_channel); + virtual_channel = dev->channel; + cc110x_read_reliable(dev, CC110X_REG_TXBYTES, &txbytes); + cc110x_read_reliable(dev, CC110X_REG_RXBYTES, &rxbytes); + cc110x_state_t sw_state = dev->state; + cc110x_release(dev); + + /* Parse obtained raw data */ + cc110x_state_t hw_state = (status >> 4) & 0x03; + int ready = !(status & 0x80); + int rssi = ((int)rssi_raw / 2) - (int)dev->rssi_offset; + int gdo0 = pktstatus & CC110X_PKTSTATUS_GDO0; + int gdo2 = pktstatus & CC110X_PKTSTATUS_GDO2; + int recv = pktstatus & CC110X_PKTSTATUS_RECEIVING; + int cca = pktstatus & CC110X_PKTSTATUS_CCA; + int cs = pktstatus & CC110X_PKTSTATUS_CS; + const char *pa = pa_settings[frend0 & 0x07]; + + /* Print all information */ + if (!ready) { + puts(" CRITICAL: Crystal has not stabilized yet!"); + } + printf(" GDO0: %s (%s)\n", b2s(gdo0), gdoconf2s(iocfg0)); + printf(" GDO2: %s (%s)\n", b2s(gdo2), gdoconf2s(iocfg2)); + printf(" Receiving: %s, CCA: %s, CS: %s\n", b2s(recv), b2s(cca), b2s(cs)); + printf(" RSSI: %i.%sdBm, TX power: %sdBm\n", + rssi, (rssi_raw & 1) ? "5" : "0", pa); + printf(" L2 addr: %02x, physical channel: %u, virtual channel: %u\n", + (int)hwaddr, (unsigned)physical_channel, (unsigned)virtual_channel); + if (dev->channels->map[virtual_channel] != physical_channel) { + puts(" WARNING: Physical channel does not match channel map"); + } + printf(" Driver state: %s, transceiver state: %s\n", + state2s(sw_state), state2s(hw_state)); + if (hw_state != (sw_state & 0x07)) { + puts(" WARNING: Transceiver and device state don't match!"); + } + if (0x80 & txbytes) { + puts(" TX FIFO: Underflown!"); + } + else { + printf(" TX FIFO: %iB\n", (int)txbytes); + } + if (0x80 & rxbytes) { + puts(" RX FIFO: Overflown!"); + } + else { + printf(" RX FIFO: %iB\n", (int)rxbytes); + } +} + +int sc_cc110x(int argc, char **argv) +{ + switch (argc) { + case 1: + for (unsigned i = 0; i < CC110X_NUM; i++){ + printf("CC110x #%u:\n", i); + print_state(&_cc110x_devs[i]); + } + break; + case 2: + if ((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help"))) { + printf("Usage: %s [NUM]\n" + "\n" + "Prints the status of the CC1100/CC1101 transceiver " + "identified by NUM, or of\n" + "all available CC110x transceivers if no argument is " + "given\n", argv[0]); + } + else { + unsigned pos = atoi(argv[1]); + if (pos >= CC110X_NUM) { + puts("No such transceiver"); + return EXIT_FAILURE; + } + printf("CC110x #%u:\n", pos); + print_state(&_cc110x_devs[pos]); + } + break; + default: + printf("Usage: %s [NUM]\n", argv[0]); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} From a84de4225dcc90927a9b38d72db28c701b78a9c5 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 20 Aug 2019 17:05:09 +0200 Subject: [PATCH 7/7] examples,tests: Add msba2 to BOARD_PROVIDES_NETIF --- examples/default/Makefile | 8 ++++---- tests/netstats_l2/Makefile | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/default/Makefile b/examples/default/Makefile index 64a4112b27e6..79e53da8ebf3 100644 --- a/examples/default/Makefile +++ b/examples/default/Makefile @@ -38,10 +38,10 @@ USEMODULE += ps USEMODULE += saul_default BOARD_PROVIDES_NETIF := acd52832 airfy-beacon b-l072z-lrwan1 cc2538dk fox \ - iotlab-m3 iotlab-a8-m3 lobaro-lorabox lsn50 mulle microbit native nrf51dk \ - nrf51dongle nrf52dk nrf52840dk nrf52840-mdk nrf6310 nucleo-f767zi \ - openmote-cc2538 pba-d-01-kw2x remote-pa remote-reva samr21-xpro \ - spark-core telosb yunjia-nrf51822 z1 + iotlab-m3 iotlab-a8-m3 lobaro-lorabox lsn50 mulle microbit msba2 \ + native nrf51dk nrf51dongle nrf52dk nrf52840dk nrf52840-mdk nrf6310 \ + nucleo-f767zi openmote-cc2538 pba-d-01-kw2x remote-pa remote-reva \ + samr21-xpro spark-core telosb yunjia-nrf51822 z1 ifneq (,$(filter $(BOARD),$(BOARD_PROVIDES_NETIF))) # Use modules for networking diff --git a/tests/netstats_l2/Makefile b/tests/netstats_l2/Makefile index 1f31841b632f..627fa54d2923 100644 --- a/tests/netstats_l2/Makefile +++ b/tests/netstats_l2/Makefile @@ -2,7 +2,7 @@ include ../Makefile.tests_common BOARD_PROVIDES_NETIF := airfy-beacon fox iotlab-m3 mulle native nrf51dk nrf51dongle \ nrf6310 pba-d-01-kw2x samd21-xpro saml21-xpro samr21-xpro spark-core \ - yunjia-nrf51822 \ + yunjia-nrf51822 msba2 \ esp32-mh-et-live-minikit esp32-olimex-evb \ esp32-wemos-lolin-d32-pro esp32-wroom-32 esp32-wrover-kit