From 14d0ef6c4d6de719d9952aac226e214e5ab974e8 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Wed, 26 Aug 2015 10:21:26 +0200 Subject: [PATCH 1/2] drivers: add cc110x driver --- Makefile.dep | 4 + drivers/cc110x/Makefile | 3 + drivers/cc110x/cc110x-defaultsettings.c | 100 ++++++ drivers/cc110x/cc110x-netdev2.c | 218 +++++++++++++ drivers/cc110x/cc110x-rxtx.c | 298 ++++++++++++++++++ drivers/cc110x/cc110x-spi.c | 179 +++++++++++ drivers/cc110x/cc110x.c | 281 +++++++++++++++++ drivers/cc110x/gnrc_cc110x/Makefile | 1 + .../cc110x/gnrc_cc110x/gnrc_netdev2_cc110x.c | 192 +++++++++++ drivers/include/cc110x.h | 132 ++++++++ .../include/cc110x/cc110x-defaultsettings.h | 46 +++ drivers/include/cc110x/cc110x-defines.h | 207 ++++++++++++ drivers/include/cc110x/cc110x-interface.h | 66 ++++ drivers/include/cc110x/cc110x-internal.h | 208 ++++++++++++ drivers/include/cc110x/cc110x-netdev2.h | 62 ++++ drivers/include/cc110x/cc110x-spi.h | 116 +++++++ drivers/include/cc110x/gnrc_netdev2_cc110x.h | 45 +++ sys/auto_init/auto_init.c | 5 + sys/auto_init/netif/auto_init_cc110x.c | 70 ++++ 19 files changed, 2233 insertions(+) create mode 100644 drivers/cc110x/Makefile create mode 100644 drivers/cc110x/cc110x-defaultsettings.c create mode 100644 drivers/cc110x/cc110x-netdev2.c create mode 100644 drivers/cc110x/cc110x-rxtx.c create mode 100644 drivers/cc110x/cc110x-spi.c create mode 100644 drivers/cc110x/cc110x.c create mode 100644 drivers/cc110x/gnrc_cc110x/Makefile create mode 100644 drivers/cc110x/gnrc_cc110x/gnrc_netdev2_cc110x.c create mode 100644 drivers/include/cc110x.h create mode 100644 drivers/include/cc110x/cc110x-defaultsettings.h create mode 100644 drivers/include/cc110x/cc110x-defines.h create mode 100644 drivers/include/cc110x/cc110x-interface.h create mode 100644 drivers/include/cc110x/cc110x-internal.h create mode 100644 drivers/include/cc110x/cc110x-netdev2.h create mode 100644 drivers/include/cc110x/cc110x-spi.h create mode 100644 drivers/include/cc110x/gnrc_netdev2_cc110x.h create mode 100644 sys/auto_init/netif/auto_init_cc110x.c diff --git a/Makefile.dep b/Makefile.dep index 0bdcebd297a4..8545ac3e3c19 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -36,6 +36,10 @@ ifneq (,$(filter at86rf2%,$(USEMODULE))) USEMODULE += netif endif +ifneq (,$(filter cc110x,$(USEMODULE))) + USEMODULE += ieee802154 +endif + ifneq (,$(filter kw2xrf,$(USEMODULE))) USEMODULE += ieee802154 USEMODULE += netif diff --git a/drivers/cc110x/Makefile b/drivers/cc110x/Makefile new file mode 100644 index 000000000000..a6588efa9cd4 --- /dev/null +++ b/drivers/cc110x/Makefile @@ -0,0 +1,3 @@ +DIRS += gnrc_cc110x + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/cc110x/cc110x-defaultsettings.c b/drivers/cc110x/cc110x-defaultsettings.c new file mode 100644 index 000000000000..aded9ece1f52 --- /dev/null +++ b/drivers/cc110x/cc110x-defaultsettings.c @@ -0,0 +1,100 @@ +/* + * 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-netdev2.c b/drivers/cc110x/cc110x-netdev2.c new file mode 100644 index 000000000000..96da07dc82c1 --- /dev/null +++ b/drivers/cc110x/cc110x-netdev2.c @@ -0,0 +1,218 @@ +/* + * 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 netdev2 interface for cc110x + * + * @author Fabian Nack + * @author Kaspar Schleiser + * @} + */ + +#include +#include +#include +#include + +#include "cc110x.h" +#include "cc110x/cc110x-netdev2.h" +#include "cc110x/cc110x-internal.h" +#include "cc110x/cc110x-interface.h" +#include "net/eui64.h" + +#include "periph/cpuid.h" +#include "periph/gpio.h" +#include "net/netdev2.h" +#include "net/gnrc/nettype.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static int _send(netdev2_t *dev, const struct iovec *vector, int count) +{ + DEBUG("%s:%u\n", __func__, __LINE__); + + netdev2_cc110x_t *netdev2_cc110x = (netdev2_cc110x_t*) dev; + cc110x_pkt_t *cc110x_pkt = vector[0].iov_base; + + return cc110x_send(&netdev2_cc110x->cc110x, cc110x_pkt); +} + +static int _recv(netdev2_t *dev, char* buf, int len) +{ + DEBUG("%s:%u\n", __func__, __LINE__); + + cc110x_t *cc110x = &((netdev2_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); + return cc110x_pkt->length; +} + +static inline int _get_iid(netdev2_t *netdev, eui64_t *value, size_t max_len) +{ + if (max_len < sizeof(eui64_t)) { + return -EOVERFLOW; + } + + uint8_t *eui64 = (uint8_t*) value; +#ifdef CPUID_ID_LEN + int n = (CPUID_ID_LEN < sizeof(eui64_t)) + ? CPUID_ID_LEN + : sizeof(eui64_t); + + char cpuid[CPUID_ID_LEN]; + cpuid_get(cpuid); + + memcpy(eui64 + 8 - n, cpuid, n); + +#else + for (int i = 0; i < 8; i++) { + eui64[i] = i; + } +#endif + + /* make sure we mark the address as non-multicast and not globally unique */ + eui64[0] &= ~(0x01); + eui64[0] |= 0x02; + + return sizeof(eui64_t); +} + +static int _get(netdev2_t *dev, netopt_t opt, void *value, size_t value_len) +{ + cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x; + + switch (opt) { + case NETOPT_DEVICE_TYPE: + assert(value_len == 2); + *((uint16_t *) value) = NETDEV2_TYPE_CC110X; + return 2; + case NETOPT_PROTO: + assert(value_len == sizeof(gnrc_nettype_t)); +#ifdef MODULE_GNRC_SIXLOWPAN + *((gnrc_nettype_t*)value) = GNRC_NETTYPE_SIXLOWPAN; +#else + *((gnrc_nettype_t*)value) = GNRC_NETTYPE_UNDEF; +#endif + return sizeof(gnrc_nettype_t); + case NETOPT_CHANNEL: + assert(value_len > 1); + *((uint16_t *)value) = (uint16_t)cc110x->radio_channel; + return 2; + case NETOPT_ADDRESS: + assert(value_len > 0); + *((uint8_t *)value) = cc110x->radio_address; + return 1; + case NETOPT_MAX_PACKET_SIZE: + assert(value_len > 0); + *((uint8_t *)value) = CC110X_PACKET_LENGTH; + return 1; + case NETOPT_IPV6_IID: + return _get_iid(dev, value, value_len); + default: + break; + } + + return -ENOTSUP; +} + +static int _set(netdev2_t *dev, netopt_t opt, void *value, size_t value_len) +{ + cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x; + + switch (opt) { + case NETOPT_CHANNEL: + { + uint8_t *arg = (uint8_t*)value; + uint8_t channel = arg[value_len-1]; + if ((channel < CC110X_MIN_CHANNR) || (channel > CC110X_MAX_CHANNR)) { + return -EINVAL; + } + if (cc110x_set_channel(cc110x, channel) == -1) { + return -EINVAL; + } + return 1; + } + case NETOPT_ADDRESS: + if (value_len < 1) { + return -EINVAL; + } + if (!cc110x_set_address(cc110x, *(uint8_t*)value)) { + return -EINVAL; + } + return 1; + default: + return -ENOTSUP; + } + + return 0; +} + +static void _netdev2_cc110x_isr(void *arg) +{ + netdev2_t *netdev2 = (netdev2_t*) arg; + netdev2->event_callback(netdev2, NETDEV2_EVENT_ISR, netdev2->isr_arg); +} + +static void _netdev2_cc110x_rx_callback(void *arg) +{ + netdev2_t *netdev2 = (netdev2_t*) arg; + cc110x_t *cc110x = &((netdev2_cc110x_t*) arg)->cc110x; + gpio_irq_disable(cc110x->params.gdo2); + netdev2->event_callback(netdev2, NETDEV2_EVENT_RX_COMPLETE, netdev2->isr_arg); +} + +static void _isr(netdev2_t *dev) +{ + cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x; + cc110x_isr_handler(cc110x, _netdev2_cc110x_rx_callback, (void*)dev); +} + +static int _init(netdev2_t *dev) +{ + DEBUG("%s:%u\n", __func__, __LINE__); + + cc110x_t *cc110x = &((netdev2_cc110x_t*) dev)->cc110x; + + gpio_init_int(cc110x->params.gdo2, GPIO_NOPULL, GPIO_BOTH, + &_netdev2_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 netdev2_driver_t netdev2_cc110x_driver = { + .send=_send, + .recv=_recv, + .init=_init, + .get=_get, + .set=_set, + .isr=_isr +}; + +int netdev2_cc110x_setup(netdev2_cc110x_t *netdev2_cc110x, const cc110x_params_t *params) +{ + DEBUG("netdev2_cc110x_setup()\n"); + netdev2_cc110x->netdev.driver = &netdev2_cc110x_driver; + + return cc110x_setup(&netdev2_cc110x->cc110x, params); +} diff --git a/drivers/cc110x/cc110x-rxtx.c b/drivers/cc110x/cc110x-rxtx.c new file mode 100644 index 000000000000..f2936db5f164 --- /dev/null +++ b/drivers/cc110x/cc110x-rxtx.c @@ -0,0 +1,298 @@ +/* + * 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/cc110x-spi.h" +#include "cc110x/cc110x-internal.h" +#include "cc110x/cc110x-interface.h" +#include "cc110x/cc110x-defines.h" + +#include "periph/gpio.h" +#include "irq.h" + +#include "kernel_types.h" +#include "msg.h" + +#include "cpu_conf.h" +#include "cpu.h" + +#include "log.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +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, 0x01); + 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 & 0x80) { + 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-3); + /* 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++; + _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 = 64 - cc110x_get_reg_robust(dev, 0xfa); + + if (fifo & 0x80) { + 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, 0x02); + } + else { + /* set GDO2 to 0x6 -> will deassert at packet end */ + cc110x_write_reg(dev, CC110X_IOCFG2, 0x06); + 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-3); + uint8_t 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, 0x02); + + /* 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 size; +} diff --git a/drivers/cc110x/cc110x-spi.c b/drivers/cc110x/cc110x-spi.c new file mode 100644 index 000000000000..9c8f0dbc7a55 --- /dev/null +++ b/drivers/cc110x/cc110x-spi.c @@ -0,0 +1,179 @@ +/* + * 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/cc110x-spi.h" +#include "cc110x/cc110x-internal.h" +#include "cc110x/cc110x-defines.h" + +#include "periph/gpio.h" +#include "periph/spi.h" + +#include "xtimer.h" +#include "irq.h" + +/********************************************************************** + * CC110x spi access + **********************************************************************/ + +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_DIR_IN, GPIO_NOPULL); +#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_conf_pins(dev->params.spi); +#endif +} + +void cc110x_writeburst_reg(cc110x_t *dev, uint8_t addr, const char *src, uint8_t count) +{ + unsigned int cpsr; + spi_acquire(dev->params.spi); + cpsr = disableIRQ(); + cc110x_cs(dev); + spi_transfer_regs(dev->params.spi, addr | CC110X_WRITE_BURST, (char *)src, 0, count); + gpio_set(dev->params.cs); + restoreIRQ(cpsr); + spi_release(dev->params.spi); +} + +void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t count) +{ + int i = 0; + unsigned int cpsr; + spi_acquire(dev->params.spi); + cpsr = disableIRQ(); + cc110x_cs(dev); + spi_transfer_byte(dev->params.spi, addr | CC110X_READ_BURST, 0); + while (i < count) { + spi_transfer_byte(dev->params.spi, CC110X_NOBYTE, &buffer[i]); + i++; + } + gpio_set(dev->params.cs); + restoreIRQ(cpsr); + spi_release(dev->params.spi); +} + +void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value) +{ + unsigned int cpsr; + spi_acquire(dev->params.spi); + cpsr = disableIRQ(); + cc110x_cs(dev); + spi_transfer_reg(dev->params.spi, addr, value, 0); + gpio_set(dev->params.cs); + restoreIRQ(cpsr); + spi_release(dev->params.spi); +} + +uint8_t cc110x_read_reg(cc110x_t *dev, uint8_t addr) +{ + char result; + unsigned int cpsr; + spi_acquire(dev->params.spi); + cpsr = disableIRQ(); + cc110x_cs(dev); + spi_transfer_reg(dev->params.spi, addr | CC110X_READ_SINGLE, CC110X_NOBYTE, &result); + gpio_set(dev->params.cs); + restoreIRQ(cpsr); + spi_release(dev->params.spi); + return (uint8_t) result; +} + +uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr) +{ + char result; + unsigned int cpsr; + spi_acquire(dev->params.spi); + cpsr = disableIRQ(); + cc110x_cs(dev); + spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result); + gpio_set(dev->params.cs); + restoreIRQ(cpsr); + spi_release(dev->params.spi); + return (uint8_t) result; +} + +uint8_t cc110x_get_reg_robust(cc110x_t *dev, uint8_t addr) +{ + char result, result2; + unsigned int cpsr; + spi_acquire(dev->params.spi); + cpsr = disableIRQ(); + cc110x_cs(dev); + do { + spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result); + spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result2); + } while (result != result2); + gpio_set(dev->params.cs); + restoreIRQ(cpsr); + spi_release(dev->params.spi); + return (uint8_t) result; +} + +uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c) +{ +#ifdef CC110X_DONT_RESET + if (c == CC110X_SRES) { + return 0; + } +#endif + + char result; + unsigned int cpsr; + spi_acquire(dev->params.spi); + cpsr = disableIRQ(); + cc110x_cs(dev); + spi_transfer_byte(dev->params.spi, c, &result); + gpio_set(dev->params.cs); + restoreIRQ(cpsr); + spi_release(dev->params.spi); + return (uint8_t) result; +} diff --git a/drivers/cc110x/cc110x.c b/drivers/cc110x/cc110x.c new file mode 100644 index 000000000000..bb965d4f3221 --- /dev/null +++ b/drivers/cc110x/cc110x.c @@ -0,0 +1,281 @@ +/* + * 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 "board.h" +#include "periph/cpuid.h" +#include "periph/gpio.h" +#include "periph/spi.h" +#include "xtimer.h" +#include "cpu.h" +#include "log.h" + +#include "cc110x.h" +#include "cc110x/cc110x-defaultsettings.h" +#include "cc110x/cc110x-defines.h" +#include "cc110x/cc110x-interface.h" +#include "cc110x/cc110x-internal.h" +#include "cc110x/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 */ + gpio_init(dev->params.cs, GPIO_DIR_OUT, GPIO_NOPULL); + gpio_set(dev->params.cs); + + /* Configure GDO1 */ + gpio_init(dev->params.gdo1, GPIO_DIR_IN, GPIO_NOPULL); + + /* Configure SPI */ + spi_acquire(dev->params.spi); + spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ); + spi_release(dev->params.spi); + +#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 */ +#ifdef CPUID_ID_LEN + if (CPUID_ID_LEN>0) { + char cpuid[CPUID_ID_LEN]; + cpuid_get(cpuid); + cc110x_set_address(dev, (uint8_t) cpuid[CPUID_ID_LEN-1]); + } +#endif + + 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) || (address > MAX_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, 0x6); + 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 new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/drivers/cc110x/gnrc_cc110x/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/cc110x/gnrc_cc110x/gnrc_netdev2_cc110x.c b/drivers/cc110x/gnrc_cc110x/gnrc_netdev2_cc110x.c new file mode 100644 index 000000000000..d8de98c55ca4 --- /dev/null +++ b/drivers/cc110x/gnrc_cc110x/gnrc_netdev2_cc110x.c @@ -0,0 +1,192 @@ +/* + * 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/netdev2.h" +#include "net/gnrc.h" +#include "cc110x.h" +#include "cc110x/cc110x-netdev2.h" +#include "net/gnrc/gnrc_netdev2.h" +#include "od.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static int _send(gnrc_netdev2_t *gnrc_netdev2, gnrc_pktsnip_t *pkt) +{ + cc110x_pkt_t cc110x_pkt; + netdev2_t *dev = gnrc_netdev2->dev; + netdev2_cc110x_t *netdev_cc110x = (netdev2_cc110x_t *) dev; + cc110x_t *cc110x = &netdev_cc110x->cc110x; + + assert(pkt != NULL); + assert(dev->driver == &netdev2_cc110x_driver); + + gnrc_netif_hdr_t *netif_hdr; + gnrc_pktsnip_t *payload; + + payload = pkt->next; + + if (pkt->type != GNRC_NETTYPE_NETIF) { + DEBUG("gnrc_netdev2_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; + } + + struct iovec vector; + vector.iov_base = (char*)&cc110x_pkt; + vector.iov_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_netdev2_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 iovec, we're done with it. */ + gnrc_pktbuf_release(pkt); + + cc110x_pkt.length = (uint8_t) payload_len + CC110X_HEADER_LENGTH; + + DEBUG("gnrc_netdev2_cc110x: sending packet from %u to %u with payload " + "length %u\n", + (unsigned)cc110x_pkt.phy_src, + (unsigned)cc110x_pkt.address, + (unsigned)cc110x_pkt.length); + + return dev->driver->send(dev, &vector, 1); +} + +static gnrc_pktsnip_t *_recv(gnrc_netdev2_t *gnrc_netdev2) +{ + netdev2_t *dev = gnrc_netdev2->dev; + cc110x_t *cc110x = &((netdev2_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("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_netdev2_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_t *)netif_hdr->data)->if_pid = thread_getpid(); + ((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_netdev2_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; +} + +int gnrc_netdev2_cc110x_init(gnrc_netdev2_t *gnrc_netdev2, netdev2_t *dev) +{ + gnrc_netdev2->send = _send; + gnrc_netdev2->recv = _recv; + gnrc_netdev2->dev = dev; + + return 0; +} diff --git a/drivers/include/cc110x.h b/drivers/include/cc110x.h new file mode 100644 index 000000000000..a5df225ed26e --- /dev/null +++ b/drivers/include/cc110x.h @@ -0,0 +1,132 @@ +/* + * 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 CC110x + * @ingroup drivers + * @brief TI CC110x + * @{ + * @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/cc110x-internal.h" + +/** + * @brief Struct for holding cc110x IO parameters + */ +typedef struct cc110x_params { + spi_t spi; /**< what */ + gpio_t cs; /**< does */ + gpio_t gdo0; /**< this */ + gpio_t gdo1; /**< look */ + gpio_t gdo2; /**< like */ +} 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 */ +}; + +/** + * @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/drivers/include/cc110x/cc110x-defaultsettings.h b/drivers/include/cc110x/cc110x-defaultsettings.h new file mode 100644 index 000000000000..7161c33e4b87 --- /dev/null +++ b/drivers/include/cc110x/cc110x-defaultsettings.h @@ -0,0 +1,46 @@ +/* + * 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 driver_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/include/cc110x/cc110x-defines.h b/drivers/include/cc110x/cc110x-defines.h new file mode 100644 index 000000000000..1c1966ef8322 --- /dev/null +++ b/drivers/include/cc110x/cc110x-defines.h @@ -0,0 +1,207 @@ +/* + * 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) + +/** + * @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) */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif diff --git a/drivers/include/cc110x/cc110x-interface.h b/drivers/include/cc110x/cc110x-interface.h new file mode 100644 index 000000000000..624696609970 --- /dev/null +++ b/drivers/include/cc110x/cc110x-interface.h @@ -0,0 +1,66 @@ +/* + * 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); +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/include/cc110x/cc110x-internal.h b/drivers/include/cc110x/cc110x-internal.h new file mode 100644 index 000000000000..5d51697dffc7 --- /dev/null +++ b/drivers/include/cc110x/cc110x-internal.h @@ -0,0 +1,208 @@ +/* + * 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_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_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 */ +#define CC110X_DEFAULT_CHANNEL (0) /**< The default channel number */ +#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/include/cc110x/cc110x-netdev2.h b/drivers/include/cc110x/cc110x-netdev2.h new file mode 100644 index 000000000000..742e3ef9a429 --- /dev/null +++ b/drivers/include/cc110x/cc110x-netdev2.h @@ -0,0 +1,62 @@ +/* + * 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 ng_netdev base 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/netdev2.h" +#include "cc110x.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Implementation of netdev2_driver_t for CC110X device + */ +extern const netdev2_driver_t netdev2_cc110x_driver; + +/** + * @brief cc110x netdev2 struct + */ +typedef struct netdev2_cc110x { + netdev2_t netdev; /**< writing obious */ + cc110x_t cc110x; /**< documentation here */ +} netdev2_cc110x_t; + + +/** + * @brief netdev2 <-> cc110x glue code initialization function + * + * @param[out] netdev2_cc110x ptr to netdev2_cc110x struct ti initialize + * @param[in] params cc110x IO parameter struct to use + * + * @return 0 on success + * @return -1 on error + */ +int netdev2_cc110x_setup(netdev2_cc110x_t *netdev2_cc110x, const cc110x_params_t *params); + +#ifdef __cplusplus +} +#endif + +#endif /* CC110X_NETDEV_H */ diff --git a/drivers/include/cc110x/cc110x-spi.h b/drivers/include/cc110x/cc110x-spi.h new file mode 100644 index 000000000000..e5422873b249 --- /dev/null +++ b/drivers/include/cc110x/cc110x-spi.h @@ -0,0 +1,116 @@ +/* + * 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/include/cc110x/gnrc_netdev2_cc110x.h b/drivers/include/cc110x/gnrc_netdev2_cc110x.h new file mode 100644 index 000000000000..3a6ccfafb610 --- /dev/null +++ b/drivers/include/cc110x/gnrc_netdev2_cc110x.h @@ -0,0 +1,45 @@ +/* + * 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 driver_cc110x + * @{ + * + * @file + * @brief cc110x gnrc glue code interface + * + * @author Kaspar Schleiser + */ + +#include "net/gnrc/gnrc_netdev2.h" +#include "cc110x/cc110x-netdev2.h" + +#ifndef GNRC_CC110X_H +#define GNRC_CC110X_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief initialize cc110x gnrc glue code + * + * @param[in] gnrc_netdev2 gnrc_netdev2 state structure to initialize + * @param[in] dev cc110x device structure to setup + * + * @return 1 on sucess + * @return <=0 on error + */ +int gnrc_netdev2_cc110x_init(gnrc_netdev2_t *gnrc_netdev2, netdev2_cc110x_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* GNRC_CC110X_H */ +/** @} */ diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index faaf8cde6c91..b7fe1305ba59 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -158,6 +158,11 @@ void auto_init(void) auto_init_slip(); #endif +#ifdef MODULE_CC110X + extern void auto_init_cc110x(void); + auto_init_cc110x(); +#endif + #ifdef MODULE_XBEE extern void auto_init_xbee(void); auto_init_xbee(); diff --git a/sys/auto_init/netif/auto_init_cc110x.c b/sys/auto_init/netif/auto_init_cc110x.c new file mode 100644 index 000000000000..291922f70307 --- /dev/null +++ b/sys/auto_init/netif/auto_init_cc110x.c @@ -0,0 +1,70 @@ +/* + * 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 auto_init_ng_netif + * @{ + * + * @file + * @brief Auto initialization for cc110x network interfaces + * + * @author Kaspar Schleiser + */ + +#ifdef MODULE_CC110X + +#include "board.h" +#include "net/gnrc/gnrc_netdev2.h" +#include "cc110x/gnrc_netdev2_cc110x.h" +#include "net/gnrc.h" + +#include "cc110x.h" +#include "cc110x_params.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief Define stack parameters for the MAC layer thread + * @{ + */ +#define CC110X_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE) +#define CC110X_MAC_PRIO (THREAD_PRIORITY_MAIN - 3) + +#define CC110X_NUM (sizeof(cc110x_params)/sizeof(cc110x_params[0])) + +static netdev2_cc110x_t cc110x_devs[CC110X_NUM]; +static char _stacks[CC110X_MAC_STACKSIZE][CC110X_NUM]; + +static gnrc_netdev2_t _gnrc_netdev2_devs[CC110X_NUM]; + +void auto_init_cc110x(void) +{ + for (int i = 0; i < CC110X_NUM; i++) { + const cc110x_params_t *p = &cc110x_params[i]; + DEBUG("Initializing CC110X radio at SPI_%i\n", p->spi); + int res = netdev2_cc110x_setup(&cc110x_devs[i], p); + if (res < 0) { + DEBUG("Error initializing CC110X radio device!"); + } + else { + gnrc_netdev2_cc110x_init(&_gnrc_netdev2_devs[i], &cc110x_devs[i]); + res = gnrc_netdev2_init(_stacks[i], CC110X_MAC_STACKSIZE, + CC110X_MAC_PRIO, "cc110x", &_gnrc_netdev2_devs[i]); + if (res < 0) { + DEBUG("Error starting gnrc_cc110x thread for CC110X!"); + } + } + } +} +#else +typedef int dont_be_pedantic; +#endif /* MODULE_CC110X */ + +/** @} */ From 63acf0bb19b6f251466b5eb04a5a675b1f6c5e93 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Wed, 26 Aug 2015 10:21:46 +0200 Subject: [PATCH 2/2] boards: msba2: add cc110x support --- boards/msba2/Makefile.include | 4 +++ boards/msba2/include/cc110x_params.h | 44 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 boards/msba2/include/cc110x_params.h diff --git a/boards/msba2/Makefile.include b/boards/msba2/Makefile.include index 214f4602c309..2a3412a209f0 100644 --- a/boards/msba2/Makefile.include +++ b/boards/msba2/Makefile.include @@ -1,3 +1,7 @@ export INCLUDES += -I$(RIOTBOARD)/msba2/include +ifneq (,$(filter gnrc_netif_default,$(USEMODULE))) + USEMODULE += cc110x gnrc_netdev2 gnrc_cc110x +endif + include $(RIOTBOARD)/msba2-common/Makefile.include diff --git a/boards/msba2/include/cc110x_params.h b/boards/msba2/include/cc110x_params.h new file mode 100644 index 000000000000..54236e2abebd --- /dev/null +++ b/boards/msba2/include/cc110x_params.h @@ -0,0 +1,44 @@ +/* + * 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 board_msba2 + * @{ + * + * @file + * @brief cc110x board specific configuration + * + * @author Kaspar Schleiser + */ + +#ifndef CC110X_PARAMS_H +#define CC110X_PARAMS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name CC110X configuration + */ +const cc110x_params_t cc110x_params[] = { + { + .spi = 0, + .cs = 53, + .gdo0 = 27, + .gdo1 = 55, + .gdo2 = 28 + }, +}; +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif /* CC110X_PARAMS_H */ +/** @} */