diff --git a/boards/telosb/Makefile.dep b/boards/telosb/Makefile.dep new file mode 100644 index 0000000000..9c00f92efc --- /dev/null +++ b/boards/telosb/Makefile.dep @@ -0,0 +1,3 @@ +ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE))) + USEMODULE += cc2420 +endif diff --git a/boards/telosb/Makefile.features b/boards/telosb/Makefile.features index be3115c5de..57c25ac5c4 100644 --- a/boards/telosb/Makefile.features +++ b/boards/telosb/Makefile.features @@ -1,5 +1,6 @@ # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_gpio +FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart diff --git a/boards/telosb/Makefile.include b/boards/telosb/Makefile.include index c84cacd0bd..71e7292ed9 100644 --- a/boards/telosb/Makefile.include +++ b/boards/telosb/Makefile.include @@ -9,6 +9,9 @@ PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbserial-MXV*))) export BAUD ?= 9600 include $(RIOTBOARD)/Makefile.include.serial +# setup the boards dependencies +include $(RIOTBOARD)/$(BOARD)/Makefile.dep + # flash tool configuration export OFLAGS = -O ihex export FLASHER = $(RIOTBASE)/dist/tools/goodfet/goodfet.bsl diff --git a/boards/z1/Makefile.dep b/boards/z1/Makefile.dep new file mode 100644 index 0000000000..9c00f92efc --- /dev/null +++ b/boards/z1/Makefile.dep @@ -0,0 +1,3 @@ +ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE))) + USEMODULE += cc2420 +endif diff --git a/boards/z1/Makefile.include b/boards/z1/Makefile.include index fa3dea543c..4cfb447176 100644 --- a/boards/z1/Makefile.include +++ b/boards/z1/Makefile.include @@ -8,6 +8,9 @@ PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.SLAB_USBtoUART*))) # setup serial terminal include $(RIOTBOARD)/Makefile.include.serial +# setup the boards dependencies +include $(RIOTBOARD)/$(BOARD)/Makefile.dep + # setup flash tool export OFLAGS = -O ihex export FLASHER = $(RIOTBASE)/dist/tools/goodfet/goodfet.bsl diff --git a/boards/z1/include/board.h b/boards/z1/include/board.h index 4698181e04..fef9bad859 100644 --- a/boards/z1/include/board.h +++ b/boards/z1/include/board.h @@ -116,6 +116,19 @@ extern "C" { #define USER_BTN_RELEASED ((USER_BTN_PxIN & USER_BTN_MASK) != 0) /** @} */ +/** + * @brief Definition of the interface to the CC2420 radio + */ +#define CC2420_PARAMS_BOARD {.spi = SPI_0, \ + .spi_clk = SPI_SPEED_1MHZ, \ + .pin_cs = GPIO_PIN(P3, 0), \ + .pin_fifo = GPIO_PIN(P1, 3), \ + .pin_fifop = GPIO_PIN(P1, 2), \ + .pin_cca = GPIO_PIN(P1, 4), \ + .pin_sfd = GPIO_PIN(P4, 1), \ + .pin_vrefen = GPIO_PIN(P4, 5), \ + .pin_reset = GPIO_PIN(P4, 6)} + #ifdef __cplusplus } #endif diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 1f7fb49575..127169145c 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -32,6 +32,20 @@ ifneq (,$(filter cc110x,$(USEMODULE))) endif endif +ifneq (,$(filter cc2420,$(USEMODULE))) + USEMODULE += xtimer + USEMODULE += netif + USEMODULE += ieee802154 + USEMODULE += netdev2_ieee802154 + ifneq (,$(filter gnrc_netdev_default,$(USEMODULE))) + # XXX: this can be modelled as a dependency for gnrc_netdev_default as soon + # as all drivers are ported to netdev2 + USEMODULE += gnrc_netdev2 + endif + FEATURES_REQUIRED += periph_gpio + FEATURES_REQUIRED += periph_spi +endif + ifneq (,$(filter dht,$(USEMODULE))) USEMODULE += xtimer FEATURES_REQUIRED += periph_gpio diff --git a/drivers/Makefile.include b/drivers/Makefile.include index c216f626fe..2328776d0b 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -61,3 +61,6 @@ endif ifneq (,$(filter bmp180,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bmp180/include endif +ifneq (,$(filter cc2420,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cc2420/include +endif diff --git a/drivers/cc2420/Makefile b/drivers/cc2420/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/cc2420/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/cc2420/cc2420.c b/drivers/cc2420/cc2420.c new file mode 100644 index 0000000000..12678f0dec --- /dev/null +++ b/drivers/cc2420/cc2420.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2015-2016 Freie Universität Berlin + * 2016 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_cc2420 + * @{ + * + * @file + * @brief Implementation of public functions for cc2420 driver + * + * @author Thomas Eichinger + * @author Hauke Petersen + * + * @} + */ + +#include "periph/cpuid.h" +#include "byteorder.h" +#include "net/ieee802154.h" +#include "net/gnrc.h" + +#include "cc2420_internal.h" +#include "cc2420_netdev.h" +#include "cc2420_registers.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @todo Move this function to a global module + */ +#if CPUID_ID_LEN +static void addr_from_cpuid(uint8_t *addr) +{ + /* option 1: generate addresses from CPUID */ + uint8_t cpuid[CPUID_ID_LEN]; + + cpuid_get(cpuid); + memcpy(addr, cpuid, 8); + +#if CPUID_ID_LEN < 8 + /* in case CPUID_ID_LEN < 8, fill missing bytes with zeros */ + for (int i = CPUID_ID_LEN; i < 8; i++) { + addr_long[i] = 0; + } +#else + /* in case CPUID_ID_LEN > 8, XOR those bytes on top of the first 8 */ + for (int i = 8; i < CPUID_ID_LEN; i++) { + addr_long[i & 0x07] ^= cpuid[i]; + } +#endif + + /* make sure we mark the address as non-multicast and not globally unique */ + addr_long[0] &= ~(0x01); + addr_long[0] |= 0x02; +} +#endif + + +void cc2420_setup(cc2420_t * dev, const cc2420_params_t *params) +{ + /* set pointer to the devices netdev functions */ + dev->netdev.netdev.driver = &cc2420_driver; + /* pull in device configuration parameters */ + memcpy(&dev->params, params, sizeof(cc2420_params_t)); + dev->state = CC2420_STATE_IDLE; + /* reset device descriptor fields */ + dev->options = 0; + spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, dev->params.spi_clk); +} + +int cc2420_init(cc2420_t *dev) +{ + uint16_t reg; + uint8_t addr[8] = CC2420_ADDR_FALLBACK; + + /* reset options and sequence number */ + dev->netdev.seq = 0; + dev->netdev.flags = 0; + + /* set default address, channel, PAN ID, and TX power */ +#if CPUID_ID_LEN + addr_from_cpuid(addr); +#endif + cc2420_set_addr_short(dev, &addr[6]); + cc2420_set_addr_long(dev, addr); + cc2420_set_pan(dev, CC2420_PANID_DEFAULT); + cc2420_set_chan(dev, CC2420_CHAN_DEFAULT); + cc2420_set_txpower(dev, CC2420_TXPOWER_DEFAULT); + + + /* set default options */ + cc2420_set_option(dev, CC2420_OPT_AUTOACK, true); + cc2420_set_option(dev, CC2420_OPT_CSMA, true); + cc2420_set_option(dev, CC2420_OPT_TELL_TX_START, true); + cc2420_set_option(dev, CC2420_OPT_TELL_RX_END, true); + +#ifdef MODULE_NETSTATS_L2 + cc2420_set_option(dev, CC2420_OPT_TELL_RX_END, true); +#endif + /* set default protocol*/ +#ifdef MODULE_GNRC_SIXLOWPAN + dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN; +#elif MODULE_GNRC + dev->netdev.proto = GNRC_NETTYPE_UNDEF; +#endif + + /* change default RX bandpass filter to 1.3uA (as recommended) */ + reg = cc2420_reg_read(dev, CC2420_REG_RXCTRL1); + reg |= CC2420_RXCTRL1_RXBPF_LOCUR; + cc2420_reg_write(dev, CC2420_REG_RXCTRL1, reg); + + /* set the FIFOP threshold to maximum. */ + cc2420_reg_write(dev, CC2420_REG_IOCFG0, CC2420_PKT_MAXLEN); + + /* turn off "Security enable" (page 33). */ + reg = cc2420_reg_read(dev, CC2420_REG_SECCTRL0); + reg &= ~CC2420_SECCTRL0_RXFIFO_PROT; + cc2420_reg_write(dev, CC2420_REG_SECCTRL0, reg); + + /* go into RX state */ + cc2420_set_state(dev, CC2420_GOTO_RX); + + /* set preamble length to 3 leading zero byte */ + reg = cc2420_reg_read(dev, CC2420_REG_MDMCTRL0); + reg &= ~(CC2420_MDMCTRL0_PREAMBLE_M); + reg |= CC2420_MDMCTRL0_PREAMBLE_3B; + cc2420_reg_write(dev, CC2420_REG_MDMCTRL0, reg); + + return 0; +} + + +bool cc2420_cca(cc2420_t *dev) +{ + while (!(cc2420_status(dev) & CC2420_STATUS_RSSI_VALID)) {} + return gpio_read(dev->params.pin_cca); +} + +size_t cc2420_send(cc2420_t *dev, const struct iovec *data, int count) +{ + size_t n = cc2420_tx_prepare(dev, data, count); + + if ((n > 0) && !(dev->options & CC2420_OPT_PRELOADING)) { + cc2420_tx_exec(dev); + } + + return n; +} + +size_t cc2420_tx_prepare(cc2420_t *dev, const struct iovec *data, int count) +{ + size_t pkt_len = 2; /* include the FCS (frame check sequence) */ + + /* wait for any ongoing transmissions to be finished */ + while (cc2420_get_state(dev) & NETOPT_STATE_TX) {} + + /* get and check the length of the packet */ + for (int i = 0; i < count; i++) { + pkt_len += data[i].iov_len; + } + if (pkt_len >= CC2420_PKT_MAXLEN) { + DEBUG("cc2420: tx_prep: unable to send, pkt too large\n"); + return 0; + } + + /* flush TX FIFO and write new packet to it */ + cc2420_strobe(dev, CC2420_STROBE_FLUSHTX); + /* push packet length to TX FIFO */ + cc2420_fifo_write(dev, (uint8_t *)&pkt_len, 1); + /* push packet to TX FIFO */ + for (int i = 0; i < count; i++) { + cc2420_fifo_write(dev, (uint8_t *)data[i].iov_base, data[i].iov_len); + } + DEBUG("cc2420: tx_prep: loaded %i byte into the TX FIFO\n", (int)pkt_len); + + return pkt_len; +} + +void cc2420_tx_exec(cc2420_t *dev) +{ + /* make sure, any ongoing transmission is finished */ + DEBUG("cc2420: tx_exec: waiting for any ongoing transmission\n"); + while (cc2420_get_state(dev) & NETOPT_STATE_TX) {} + /* trigger the transmission */ + if (dev->options & CC2420_OPT_TELL_TX_START) { + dev->netdev.netdev.event_callback(&dev->netdev.netdev, + NETDEV2_EVENT_TX_STARTED); + } + DEBUG("cc2420: tx_exec: TX_START\n"); + if (dev->options & CC2420_OPT_CSMA) { + DEBUG("cc2420: tx_exec: triggering TX with CCA\n"); + cc2420_strobe(dev, CC2420_STROBE_TXONCCA); + } + else { + DEBUG("cc2420: tx_exec: triggering TX without CCA\n"); + cc2420_strobe(dev, CC2420_STROBE_TXON); + } + + while (gpio_read(dev->params.pin_sfd)) { + puts("\t...ongoing}"); + } + if (dev->options & CC2420_OPT_TELL_TX_END) { + dev->netdev.netdev.event_callback(&dev->netdev.netdev, + NETDEV2_EVENT_TX_COMPLETE); + } + DEBUG("cc2420: tx_exec: TX_DONE\n"); +} + +int cc2420_rx(cc2420_t *dev, uint8_t *buf, size_t max_len, void *info) +{ + uint8_t len; + + /* get the packet length (without dropping it) (first byte in RX FIFO */ + cc2420_ram_read(dev, CC2420_RAM_RXFIFO, &len, 1); + len -= 2; /* subtract RSSI and FCF */ + + if (!buf) { + DEBUG("cc2420: recv: packet of length %i in RX FIFO\n", (int)len); + } + + /* if a buffer is given, read (and drop) the packet */ + if (buf) { + len = (len > max_len) ? max_len : len; + + /* drop length byte */ + cc2420_fifo_read(dev, NULL, 1); + /* read fifo contents */ + DEBUG("cc2420: recv: reading %i byte of the packet\n", (int)len); + cc2420_fifo_read(dev, buf, len); + + uint8_t rssi; + cc2420_fifo_read(dev, &rssi, 1); + DEBUG("cc2420: recv: RSSI is %i\n", (int)rssi); + /* finally flush the FIFO */ + cc2420_strobe(dev, CC2420_STROBE_FLUSHRX); + cc2420_strobe(dev, CC2420_STROBE_FLUSHRX); + } + + return (int)len; +} diff --git a/drivers/cc2420/cc2420_getset.c b/drivers/cc2420/cc2420_getset.c new file mode 100644 index 0000000000..bd5d749468 --- /dev/null +++ b/drivers/cc2420/cc2420_getset.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * 2016 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_cc2420 + * @{ + * + * @file + * @brief Getter and setter functions for the cc2420 driver + * + * @author Hauke Petersen + * @author Francisco Acosta + * + * @} + */ + +#include + +#include "cc2420.h" +#include "cc2420_internal.h" +#include "cc2420_registers.h" +#include "periph/spi.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief Translation from dBm to PA level + * + * Entry 0 in the array corresponds to -25dBm (min), entry 25 to 0dBm (max), so + * `PA_level = power_dbm_to_pa[DBM + 25]`. We use only the 3 MSB of the 5-bit + * level, leading to 8 distinct power settings (the 8 settings listed in the + * datasheet in section 28, page 51). + */ +static const uint8_t power_dbm_to_pa[26] = { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, + 7, 7, 11, 11, 11, 15, 15, 19, 19, 23, 23, 27, 31 +}; + +/** + * @brief Translate PA level to dBm + * + * As we use only the 3 MSB of the PA level value, we have 8 distinct settings. + * We get the dBm value with `DBM = power_pa_to_dbm(PA >> 2). + */ +static const int8_t power_pa_to_dbm[8] = { + -25, -15, -10, -7, -5, -3, -1, 0 +}; + +void cc2420_get_addr_short(cc2420_t *dev, uint8_t *addr) +{ + uint8_t tmp[2]; + + cc2420_ram_read(dev, CC2420_RAM_SHORTADR, tmp, 2); + + addr[0] = tmp[1]; + addr[1] = tmp[0]; +} + +void cc2420_set_addr_short(cc2420_t *dev, uint8_t *addr) +{ + uint8_t tmp[2]; + tmp[0] = addr[1]; + tmp[1] = addr[0]; + + memcpy(dev->netdev.short_addr, addr, 2); + +#ifdef MODULE_SIXLOWPAN + /* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to + * 0 for unicast addresses */ + dev->netdev.short_addr[0] &= 0x7F; +#endif + + cc2420_ram_write(dev, CC2420_RAM_SHORTADR, tmp, 2); +} + +void cc2420_get_addr_long(cc2420_t *dev, uint8_t *addr) +{ + cc2420_ram_read(dev, CC2420_RAM_IEEEADR, addr, 8); + + uint8_t *ap = (uint8_t *)(&addr); + for (int i = 0; i < 8; i++) { + ap[i] = dev->netdev.long_addr[i]; + } +} + +void cc2420_set_addr_long(cc2420_t *dev, uint8_t *addr) +{ + int i, j; + uint8_t tmp[8]; + + for (i = 0, j = 7; i < 8; i++, j--) { + dev->netdev.long_addr[i] = addr[i]; + tmp[j] = addr[i]; + } + + cc2420_ram_write(dev, CC2420_RAM_IEEEADR, tmp, 8); +} + +uint16_t cc2420_get_pan(cc2420_t *dev) +{ + le_uint16_t pan; + + cc2420_ram_read(dev, CC2420_RAM_PANID, pan.u8, 2); + return pan.u16; +} + +void cc2420_set_pan(cc2420_t *dev, uint16_t pan) +{ + dev->netdev.pan = pan; + cc2420_ram_write(dev, CC2420_RAM_PANID, (uint8_t *)&pan, 2); +} + +uint16_t cc2420_get_chan(cc2420_t *dev) +{ + uint16_t chan; + uint16_t freq = cc2420_reg_read(dev, CC2420_REG_FSCTRL); + + chan = (((freq & CC2420_FSCTRL_FREQ_MASK) - 357) / 5) + 11; + return chan; +} + +int cc2420_set_chan(cc2420_t *dev, uint16_t chan) +{ + if ((chan < CC2420_CHAN_MIN) || (chan > CC2420_CHAN_MAX)) { + DEBUG("cc2420: set channel: given channel invalid\n"); + return -ENOTSUP; + } + + /* calculation from http://www.ti.com/lit/ds/symlink/cc2420.pdf p.50 */ + uint16_t freq = cc2420_reg_read(dev, CC2420_REG_FSCTRL); + freq &= ~CC2420_FSCTRL_FREQ_MASK; + freq |= (357 + (5 * (chan - 11))); + cc2420_reg_write(dev, CC2420_REG_FSCTRL, freq); + + dev->netdev.chan = chan; + + return CC2420_RET_CHAN_OK; +} + +int16_t cc2420_get_txpower(cc2420_t *dev) +{ + uint16_t txctrl = cc2420_reg_read(dev, CC2420_REG_TXCTRL); + return (int16_t)power_pa_to_dbm[(txctrl & CC2420_TXCTRL_PA_MASK) >> 2]; +} + +void cc2420_set_txpower(cc2420_t *dev, int16_t txpower) +{ + if (txpower > CC2420_TXPOWER_MAX) { + txpower = CC2420_TXPOWER_MAX; + } + else if (txpower < CC2420_TXPOWER_MIN) { + txpower = CC2420_TXPOWER_MIN; + } + + uint16_t txctrl = cc2420_reg_read(dev, CC2420_REG_TXCTRL); + txctrl &= ~(CC2420_TXCTRL_PA_MASK); + txctrl |= power_dbm_to_pa[txpower + 25]; + cc2420_reg_write(dev, CC2420_REG_TXCTRL, txctrl); +} + +int cc2420_set_option(cc2420_t *dev, uint16_t option, bool state) +{ + uint16_t reg; + + /* set option field */ + if (state) { + dev->options |= option; + /* trigger option specific actions */ + switch (option) { + case CC2420_OPT_AUTOACK: + DEBUG("cc2420: set_opt: CC2420_OPT_AUTOACK\n"); + reg = cc2420_reg_read(dev, CC2420_REG_MDMCTRL0); + reg |= CC2420_MDMCTRL0_AUTOACK; + cc2420_reg_write(dev, CC2420_REG_MDMCTRL0, reg); + break; + + case CC2420_OPT_CSMA: + DEBUG("cc2420: set_opt: CC2420_OPT_CSMA\n"); + /* TODO: en/disable csma */ + break; + + case CC2420_OPT_PROMISCUOUS: + DEBUG("cc2420: set_opt: CC2420_OPT_PROMISCUOUS\n"); + /* in promisc mode, AUTO ACKs are should be disabled */ + reg = cc2420_reg_read(dev, CC2420_REG_MDMCTRL0); + reg &= ~(CC2420_MDMCTRL0_AUTOACK); + reg &= ~(CC2420_MDMCTRL0_ADR_DECODE); + cc2420_reg_write(dev, CC2420_REG_MDMCTRL0, reg); + break; + + case CC2420_OPT_PRELOADING: + DEBUG("cc2420: set_opt: CC2420_OPT_PRELOADING\n"); + break; + + case CC2420_OPT_TELL_TX_START: + case CC2420_OPT_TELL_TX_END: + case CC2420_OPT_TELL_RX_START: + case CC2420_OPT_TELL_RX_END: + DEBUG("cc2420: set_opt: TX/RX START/END\n"); + /* TODO */ + break; + + default: + return -ENOTSUP; + } + } + else { + dev->options &= ~(option); + /* trigger option specific actions */ + switch (option) { + case CC2420_OPT_AUTOACK: + DEBUG("cc2420: clr_opt: CC2420_OPT_AUTOACK\n"); + reg = cc2420_reg_read(dev, CC2420_REG_MDMCTRL0); + reg &= ~(CC2420_MDMCTRL0_AUTOACK); + cc2420_reg_write(dev, CC2420_REG_MDMCTRL0, reg); + break; + + case CC2420_OPT_CSMA: + DEBUG("cc2420: clr_opt: CC2420_OPT_CSMA\n"); + /* TODO: en/disable csma */ + break; + + case CC2420_OPT_PROMISCUOUS: + DEBUG("cc2420: clr_opt: CC2420_OPT_PROMISCUOUS\n"); + reg = cc2420_reg_read(dev, CC2420_REG_MDMCTRL0); + reg |= CC2420_MDMCTRL0_ADR_DECODE; + /* re-enable AUTOACK only if the option was set */ + if (dev->options & CC2420_OPT_AUTOACK) { + reg |= CC2420_MDMCTRL0_AUTOACK; + } + cc2420_reg_write(dev, CC2420_REG_MDMCTRL0, reg); + break; + + case CC2420_OPT_PRELOADING: + DEBUG("cc2420: clr_opt: CC2420_OPT_PRELOADING\n"); + break; + + case CC2420_OPT_TELL_TX_START: + case CC2420_OPT_TELL_TX_END: + case CC2420_OPT_TELL_RX_START: + case CC2420_OPT_TELL_RX_END: + DEBUG("cc2420: clr_opt: TX/RX START/END\n"); + /* TODO */ + break; + + default: + return -ENOTSUP; + } + } + return sizeof(netopt_enable_t); +} + +int cc2420_set_state(cc2420_t *dev, netopt_state_t cmd) +{ + if ((cc2420_get_state(dev) == NETOPT_STATE_OFF) && + (cmd != NETOPT_STATE_OFF)) { + cc2420_en_xosc(dev); + } + switch (cmd) { + case NETOPT_STATE_OFF: + cc2420_strobe(dev, CC2420_STROBE_XOSCOFF); + while (cc2420_state(dev) != CC2420_STATE_PD) {} + break; + case NETOPT_STATE_SLEEP: + cc2420_strobe(dev, CC2420_STROBE_RFOFF); + while (cc2420_state(dev) != CC2420_STATE_IDLE) {} + break; + case NETOPT_STATE_IDLE: + cc2420_strobe(dev, CC2420_STROBE_FLUSHRX); + cc2420_strobe(dev, CC2420_STROBE_RXON); + break; + case NETOPT_STATE_TX: + cc2420_tx_exec(dev); + break; + case NETOPT_STATE_RESET: + cc2420_init(dev); + break; + case NETOPT_STATE_RX: + default: + DEBUG("cc2420: set_state: called with invalid target state\n"); + return -ENOTSUP; + } + return sizeof(netopt_state_t); +} + +netopt_state_t cc2420_get_state(cc2420_t *dev) +{ + uint8_t cur_state = cc2420_state(dev); + + if (cur_state == 0) { + return NETOPT_STATE_OFF; + } + else if (cur_state == 1) { + return NETOPT_STATE_SLEEP; + } + else if (((cur_state >= 32) && (cur_state <=39)) || (cur_state == 56)) { + return NETOPT_STATE_TX; + } + else if ((cur_state >= 3) && (cur_state <= 6)) { + return NETOPT_STATE_IDLE; + } + else { + return NETOPT_STATE_RX; + } +} diff --git a/drivers/cc2420/cc2420_internal.c b/drivers/cc2420/cc2420_internal.c new file mode 100644 index 0000000000..01ab024f29 --- /dev/null +++ b/drivers/cc2420/cc2420_internal.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2015-2016 Freie Universität Berlin + * 2016 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_cc2420 + * @{ + * + * @file + * @brief Implementation of driver internal functions + * + * @author Hauke Petersen + * @author Francisco Acosta + * + * @} + */ + +#include "periph/spi.h" +#include "periph/gpio.h" +#include "xtimer.h" + +#include "cc2420_internal.h" +#include "cc2420_registers.h" + +uint8_t cc2420_strobe(const cc2420_t *dev, const uint8_t command) +{ + char res; + + spi_acquire(dev->params.spi); + gpio_clear(dev->params.pin_cs); + spi_transfer_byte(dev->params.spi, (char)command, (char *)&res); + gpio_set(dev->params.pin_cs); + spi_release(dev->params.spi); + + return res; +} + +void cc2420_reg_write(const cc2420_t *dev, + const uint8_t addr, + const uint16_t value) +{ + uint16_t tmp = byteorder_htons(value).u16; + + spi_acquire(dev->params.spi); + gpio_clear(dev->params.pin_cs); + spi_transfer_regs(dev->params.spi, CC2420_REG_WRITE | addr, + (char *)&tmp, NULL, 2); + gpio_set(dev->params.pin_cs); + spi_release(dev->params.spi); +} + +uint16_t cc2420_reg_read(const cc2420_t *dev, const uint8_t addr) +{ + network_uint16_t tmp; + + spi_acquire(dev->params.spi); + gpio_clear(dev->params.pin_cs); + spi_transfer_regs(dev->params.spi, CC2420_REG_READ | addr, + NULL, (char *)&tmp, 2); + gpio_set(dev->params.pin_cs); + spi_release(dev->params.spi); + + return byteorder_ntohs(tmp); +} + +void cc2420_ram_read(const cc2420_t *dev, const uint16_t addr, + uint8_t *data, const size_t len) +{ + char tmp[] = { (CC2420_RAM | (addr & 0x7f)), + (CC2420_RAM_READ | ((addr >> 1) & 0xc0)) }; + + spi_acquire(dev->params.spi); + gpio_clear(dev->params.pin_cs); + spi_transfer_bytes(dev->params.spi, tmp, NULL, 2); + spi_transfer_bytes(dev->params.spi, NULL, (char*)data, len); + gpio_set(dev->params.pin_cs); + spi_release(dev->params.spi); +} + +void cc2420_ram_write(const cc2420_t *dev, const uint16_t addr, + const uint8_t *data, const size_t len) +{ + char tmp[] = { (CC2420_RAM | (addr & 0x7f)), + (CC2420_RAM_WRITE | ((addr >> 1) & 0xc0)) }; + + spi_acquire(dev->params.spi); + gpio_clear(dev->params.pin_cs); + spi_transfer_bytes(dev->params.spi, tmp, NULL, 2); + spi_transfer_bytes(dev->params.spi, (char*)data, NULL, len); + gpio_set(dev->params.pin_cs); + spi_release(dev->params.spi); +} + +void cc2420_fifo_read(const cc2420_t *dev, uint8_t *data, const size_t len) +{ + spi_acquire(dev->params.spi); + gpio_clear(dev->params.pin_cs); + spi_transfer_regs(dev->params.spi, CC2420_FIFO_READ, + NULL, (char *)data, len); + gpio_set(dev->params.pin_cs); + spi_release(dev->params.spi); +} + +void cc2420_fifo_write(const cc2420_t *dev, uint8_t *data, const size_t len) +{ + spi_acquire(dev->params.spi); + gpio_clear(dev->params.pin_cs); + spi_transfer_regs(dev->params.spi, CC2420_FIFO_WRITE, + (char *)data, NULL, len); + gpio_set(dev->params.pin_cs); + spi_release(dev->params.spi); +} + +uint8_t cc2420_status(cc2420_t *dev) +{ + return cc2420_strobe(dev, CC2420_STROBE_NOP); +} + +uint8_t cc2420_state(cc2420_t *dev) +{ + return (uint8_t)cc2420_reg_read(dev, CC2420_REG_FSMSTATE); +} + +void cc2420_en_xosc(cc2420_t *dev) +{ + cc2420_strobe(dev, CC2420_STROBE_XOSCON); + xtimer_usleep(CC2420_XOSCON_DELAY); +} diff --git a/drivers/cc2420/cc2420_netdev.c b/drivers/cc2420/cc2420_netdev.c new file mode 100644 index 0000000000..41cfd8e153 --- /dev/null +++ b/drivers/cc2420/cc2420_netdev.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * 2016 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_cc2420 + * @{ + * + * @file + * @brief Netdev adaption for the cc2420 driver + * + * @author Hauke Petersen + * @author Francisco Acosta + * + * @} + */ + +#include +#include +#include + +#include "net/eui64.h" +#include "net/ieee802154.h" +#include "net/netdev2.h" +#include "net/netdev2/ieee802154.h" +#include "xtimer.h" + +#include "cc2420.h" +#include "cc2420_netdev.h" +#include "cc2420_internal.h" +#include "cc2420_registers.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + + +static int _send(netdev2_t *netdev, const struct iovec *vector, int count); +static int _recv(netdev2_t *netdev, char *buf, int len, void *info); +static int _init(netdev2_t *netdev); +static void _isr(netdev2_t *netdev); +static int _get(netdev2_t *netdev, netopt_t opt, void *val, size_t max_len); +static int _set(netdev2_t *netdev, netopt_t opt, void *val, size_t len); + +const netdev2_driver_t cc2420_driver = { + .send = _send, + .recv = _recv, + .init = _init, + .isr = _isr, + .get = _get, + .set = _set, +}; + +static void _irq_handler(void *arg) +{ + netdev2_t *dev = (netdev2_t *)arg; + + if(dev->event_callback) { + dev->event_callback(dev, NETDEV2_EVENT_ISR); + } +} + +static inline uint16_t to_u16(void *buf) +{ + return *((uint16_t *)buf); +} + +static inline int16_t to_i16(void *buf) +{ + return *((int16_t *)buf); +} + +static inline bool to_bool(void *buf) +{ + return *((bool *)buf); +} + +static inline int w_u16(void *buf, uint16_t val) +{ + memcpy(buf, &val, sizeof(uint16_t)); + return sizeof(uint16_t); +} + +static inline int w_i16(void *buf, int16_t val) +{ + memcpy(buf, &val, sizeof(int16_t)); + return sizeof(int16_t); +} + +static inline int opt_state(void *buf, bool cond) +{ + *((netopt_enable_t *)buf) = !!(cond); + return sizeof(netopt_enable_t); +} + +static int _init(netdev2_t *netdev) +{ + cc2420_t *dev = (cc2420_t *)netdev; + + uint16_t reg; + + /* initialize power and reset pins -> put the device into reset state */ + gpio_init(dev->params.pin_reset, GPIO_OUT); + gpio_set(dev->params.pin_reset); + gpio_init(dev->params.pin_vrefen, GPIO_OUT); + gpio_clear(dev->params.pin_vrefen); + + /* initialize the input lines */ + gpio_init(dev->params.pin_cca, GPIO_IN); + gpio_init(dev->params.pin_sfd, GPIO_IN); + gpio_init(dev->params.pin_fifo, GPIO_IN); + gpio_init_int(dev->params.pin_fifop, GPIO_IN, GPIO_RISING, _irq_handler, dev); + + /* initialize the chip select line and the SPI bus */ + gpio_init(dev->params.pin_cs, GPIO_OUT); + gpio_set(dev->params.pin_cs); + + /* power on and toggle reset */ + gpio_set(dev->params.pin_vrefen); + gpio_clear(dev->params.pin_reset); + xtimer_usleep(CC2420_RESET_DELAY); + gpio_set(dev->params.pin_reset); + + /* test the connection to the device by reading MANFIDL register */ + reg = cc2420_reg_read(dev, CC2420_REG_MANFIDL); + if (reg != CC2420_MANFIDL_VAL) { + DEBUG("cc2420: init: unable to communicate with device\n"); + return -1; + } + + /* turn on the oscillator and wait for it to be stable */ + cc2420_en_xosc(dev); + if (!(cc2420_status(dev) & CC2420_STATUS_XOSC_STABLE)) { + DEBUG("cc2420: init: oscillator did not stabilize\n"); + return -1; + } + +#ifdef MODULE_NETSTATS_L2 + memset(&netdev->stats, 0, sizeof(netstats_t)); +#endif + + return cc2420_init((cc2420_t *)dev); +} + +static void _isr(netdev2_t *netdev) +{ + netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE); +} + +static int _send(netdev2_t *netdev, const struct iovec *vector, int count) +{ + cc2420_t *dev = (cc2420_t *)netdev; + return (int)cc2420_send(dev, vector, count); +} + +static int _recv(netdev2_t *netdev, char *buf, int len, void *info) +{ + cc2420_t *dev = (cc2420_t *)netdev; + return (int)cc2420_rx(dev, (uint8_t *)buf, len, info); +} + +static int _get(netdev2_t *netdev, netopt_t opt, void *val, size_t max_len) +{ + if (netdev == NULL) { + return -ENODEV; + } + + cc2420_t *dev = (cc2420_t *)netdev; + + int ext = netdev2_ieee802154_get(&dev->netdev, opt, val, max_len); + if (ext > 0) { + return ext; + } + + switch (opt) { + + case NETOPT_ADDRESS: + assert(max_len >= sizeof(uint16_t)); + cc2420_get_addr_short(dev, val); + return sizeof(uint16_t); + + case NETOPT_ADDRESS_LONG: + assert(max_len >= 8); + cc2420_get_addr_long(dev, val); + return 8; + + case NETOPT_NID: + assert(max_len >= sizeof(uint16_t)); + return w_u16(val, cc2420_get_pan(dev)); + + case NETOPT_CHANNEL: + assert(max_len >= sizeof(uint16_t)); + return w_u16(val, cc2420_get_chan(dev)); + + case NETOPT_TX_POWER: + assert(max_len >= sizeof(int16_t)); + return w_i16(val, cc2420_get_txpower(dev)); + + case NETOPT_STATE: + assert(max_len >= sizeof(netopt_state_t)); + *((netopt_state_t *)val) = cc2420_get_state(dev); + return sizeof(netopt_state_t); + + case NETOPT_IS_CHANNEL_CLR: + return opt_state(val, cc2420_cca(dev)); + + case NETOPT_AUTOACK: + return opt_state(val, (dev->options & CC2420_OPT_AUTOACK)); + + case NETOPT_CSMA: + return opt_state(val, (dev->options & CC2420_OPT_CSMA)); + + case NETOPT_PRELOADING: + return opt_state(val, (dev->options & CC2420_OPT_PRELOADING)); + + case NETOPT_PROMISCUOUSMODE: + return opt_state(val, (dev->options & CC2420_OPT_PROMISCUOUS)); + + case NETOPT_RX_START_IRQ: + return opt_state(val, (dev->options & CC2420_OPT_TELL_RX_START)); + + case NETOPT_RX_END_IRQ: + return opt_state(val, (dev->options & CC2420_OPT_TELL_TX_END)); + + case NETOPT_TX_START_IRQ: + return opt_state(val, (dev->options & CC2420_OPT_TELL_RX_START)); + + case NETOPT_TX_END_IRQ: + return opt_state(val, (dev->options & CC2420_OPT_TELL_RX_END)); + + default: + return -ENOTSUP; + } +} + +static int _set(netdev2_t *netdev, netopt_t opt, void *val, size_t val_len) +{ + if (netdev == NULL) { + return -ENODEV; + } + + cc2420_t *dev = (cc2420_t *)netdev; + + int ext = netdev2_ieee802154_set(&dev->netdev, opt, val, val_len); + + switch (opt) { + case NETOPT_ADDRESS: + assert(val_len == 2); + cc2420_set_addr_short(dev, (uint8_t *)val); + return 2; + + case NETOPT_ADDRESS_LONG: + assert(val_len == 8); + cc2420_set_addr_long(dev, (uint8_t *)val); + return 8; + + case NETOPT_NID: + assert(val_len == sizeof(uint16_t)); + cc2420_set_pan(dev, to_u16(val)); + return sizeof(uint16_t); + + case NETOPT_CHANNEL: + assert(val_len == sizeof(uint16_t)); + return cc2420_set_chan(dev, to_u16(val)); + + case NETOPT_TX_POWER: + assert(val_len == sizeof(int16_t)); + cc2420_set_txpower(dev, to_i16(val)); + return sizeof(int16_t); + + case NETOPT_STATE: + assert(val_len == sizeof(netopt_state_t)); + return cc2420_set_state(dev, *((netopt_state_t *)val)); + + case NETOPT_AUTOACK: + return cc2420_set_option(dev, CC2420_OPT_AUTOACK, to_bool(val)); + + case NETOPT_CSMA: + return cc2420_set_option(dev, CC2420_OPT_CSMA, to_bool(val)); + + case NETOPT_PRELOADING: + return cc2420_set_option(dev, CC2420_OPT_PRELOADING, to_bool(val)); + + case NETOPT_PROMISCUOUSMODE: + return cc2420_set_option(dev, CC2420_OPT_PROMISCUOUS, to_bool(val)); + + case NETOPT_RX_START_IRQ: + return cc2420_set_option(dev, CC2420_OPT_TELL_RX_START, to_bool(val)); + + case NETOPT_RX_END_IRQ: + return cc2420_set_option(dev, CC2420_OPT_TELL_RX_END, to_bool(val)); + + case NETOPT_TX_START_IRQ: + return cc2420_set_option(dev, CC2420_OPT_TELL_TX_START, to_bool(val)); + + case NETOPT_TX_END_IRQ: + return cc2420_set_option(dev, CC2420_OPT_TELL_TX_END, to_bool(val)); + + default: + return ext; + } + + return 0; +} diff --git a/drivers/cc2420/include/cc2420_internal.h b/drivers/cc2420/include/cc2420_internal.h new file mode 100644 index 0000000000..ebb7a4eb50 --- /dev/null +++ b/drivers/cc2420/include/cc2420_internal.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2014 Milan Babel and INRIA + * 2015-2016 Freie Universität Berlin + * 2016 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_cc2420 + * @{ + * + * @file + * @brief Definitions and settings for the cc2420 + * + * @author Milan Babel + * @author Kévin Roussel + * @author Thomas Eichinger + * @author Hauke Petersen + * @author Francisco Acosta + * + */ +#ifndef CC2420_INTERNAL_H +#define CC2420_INTERNAL_H + +#include + +#include "cc2420.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Delays for resetting and turning on the device + */ +#define CC2420_RESET_DELAY (500U) +#define CC2420_XOSCON_DELAY (2000U) + + +uint8_t cc2420_strobe(const cc2420_t *dev, const uint8_t command); + + +/** + * @brief Read from a register at address `addr` from device `dev`. + * + * @param[in] dev device to read from + * @param[in] addr address of the register to read + * + * @return the value of the specified register + */ +uint16_t cc2420_reg_read(const cc2420_t *dev, const uint8_t addr); + +/** + * @brief Write to a register at address `addr` from device `dev`. + * + * @param[in] dev device to write to + * @param[in] addr address of the register to write + * @param[in] value value to write to the given register + */ +void cc2420_reg_write(const cc2420_t *dev, const uint8_t addr, + const uint16_t value); + +/** + * @brief Read a chunk of data from the SRAM of the given device + * + * @param[in] dev device to read from + * @param[in] addr starting address to read from [valid 0x00-0x16B] + * @param[out] data buffer to read data into + * @param[in] len number of bytes to read from SRAM + */ +void cc2420_ram_read(const cc2420_t *dev, const uint16_t addr, + uint8_t *data, const size_t len); + +/** + * @brief Write a chunk of data into the SRAM of the given device + * + * @param[in] dev device to write to + * @param[in] addr address in the SRAM to write to [valid 0x00-0x16B] + * @param[in] data data to copy into SRAM + * @param[in] len number of bytes to write to SRAM + */ +void cc2420_ram_write(const cc2420_t *dev, const uint16_t addr, + const uint8_t *data, const size_t len); + +/** + * @brief Reads FIFO buffer from RAM at address 0x080 + * + * @param[in] dev device to write to + * @param[in] data data to copy into SRAM + * @param[in] len number of bytes to write to SRAM + */ +void cc2420_fifo_read(const cc2420_t *dev, uint8_t *data, const size_t len); + +/** + * @brief Writes FIFO buffer to RAM at address 0x000 + * + * @param[in] dev device to write to + * @param[in] data data to copy into SRAM + * @param[in] len number of bytes to write to SRAM + */ +void cc2420_fifo_write(const cc2420_t *dev, uint8_t *data, const size_t len); + +/** + * @brief Get the device's status byte + */ +uint8_t cc2420_status(cc2420_t *dev); + +/** + * @brief Get the device's current state + */ +uint8_t cc2420_state(cc2420_t *dev); + +/** + * @brief Enable on-board oscillator + */ +void cc2420_en_xosc(cc2420_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* CC2420_INTERNAL_H_ */ +/** @} */ diff --git a/drivers/cc2420/include/cc2420_netdev.h b/drivers/cc2420/include/cc2420_netdev.h new file mode 100644 index 0000000000..2b260938ed --- /dev/null +++ b/drivers/cc2420/include/cc2420_netdev.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 Inria + * 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 + * directory for more details. + */ + +/** + * @ingroup drivers_cc2420 + * @{ + * + * @file + * @brief Netdev interface for the CC2420 + * + * @author Francisco Acosta + * @author Hauke Petersen + * + */ + +#ifndef CC2420_NETDEV_H_ +#define CC2420_NETDEV_H_ + +#include "net/netdev2.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Reference to the netdev device driver struct + */ +extern const netdev2_driver_t cc2420_driver; + +#ifdef __cplusplus +} +#endif + +#endif /* CC2420_NETDEV_H_ */ +/** @} */ diff --git a/drivers/cc2420/include/cc2420_params.h b/drivers/cc2420/include/cc2420_params.h new file mode 100644 index 0000000000..77d901aa5a --- /dev/null +++ b/drivers/cc2420/include/cc2420_params.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 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 + * directory for more details. + */ + +/** + * @ingroup drivers_cc2420 + * + * @{ + * @file + * @brief Default configuration for the CC2420 driver + * + * @author Hauke Petersen + */ + +#ifndef CC2420_PARAMS_H +#define CC2420_PARAMS_H + +#include "board.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set default configuration parameters for the CC2420 driver + * @{ + */ +#ifndef CC2420_PARAM_SPI +#define CC2420_PARAM_SPI (SPI_0) +#endif +#ifndef CC2420_PARAM_SPI_CLK +#define CC2420_PARAM_SPI_CLK (SPI_SPEED_5MHZ) +#endif +#ifndef CC2420_PARAM_CS +#define CC2420_PARAM_CS (GPIO_PIN(0, 0)) +#endif +#ifndef CC2420_PARAM_FIFO +#define CC2420_PARAM_FIFO (GPIO_PIN(0, 1)) +#endif +#ifndef CC2420_PARAM_FIFOP +#define CC2420_PARAM_FIFOP (GPIO_PIN(0, 2)) +#endif +#ifndef CC2420_PARAM_CCA +#define CC2420_PARAM_CCA (GPIO_PIN(0, 3)) +#endif +#ifndef CC2420_PARAM_SFD +#define CC2420_PARAM_SFD (GPIO_PIN(0, 3)) +#endif +#ifndef CC2420_PARAM_VREFEN +#define CC2420_PARAM_VREFEN (GPIO_PIN(0, 3)) +#endif +#ifndef CC2420_PARAM_RESET +#define CC2420_PARAM_RESET (GPIO_PIN(0, 3)) +#endif + +#define CC2420_PARAMS_DEFAULT {.spi = CC2420_PARAM_SPI, \ + .spi_clk = CC2420_PARAM_SPI_CLK, \ + .pin_cs = CC2420_PARAM_CS, \ + .pin_fifo = CC2420_PARAM_FIFO, \ + .pin_fifop = CC2420_PARAM_FIFOP, \ + .pin_cca = CC2420_PARAM_CCA, \ + .pin_sfd = CC2420_PARAM_SFD, \ + .pin_vrefen = CC2420_PARAM_VREFEN, \ + .pin_reset = CC2420_PARAM_RESET} +/**@}*/ + +/** + * @brief CC2420 configuration + */ +static const cc2420_params_t cc2420_params[] = +{ +#ifdef CC2420_PARAMS_BOARD + CC2420_PARAMS_BOARD, +#else + CC2420_PARAMS_DEFAULT, +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif /* CC2420_PARAMS_H */ +/** @} */ diff --git a/drivers/cc2420/include/cc2420_registers.h b/drivers/cc2420/include/cc2420_registers.h new file mode 100644 index 0000000000..c4a318c593 --- /dev/null +++ b/drivers/cc2420/include/cc2420_registers.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * 2016 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_cc2420 + * @{ + * + * @file + * @brief Register and command definitions for CC2420 + * + * @author Hauke Petersen + * @author Francisco Acosta + */ + +#ifndef CC2420_REGISTERS_H_ +#define CC2420_REGISTERS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Internal device option flags + * @{ + */ +#define CC2420_OPT_AUTOACK (0x0001) /**< auto ACKs active */ +#define CC2420_OPT_CSMA (0x0002) /**< CSMA active */ +#define CC2420_OPT_PROMISCUOUS (0x0004) /**< promiscuous mode + * active */ +#define CC2420_OPT_PRELOADING (0x0008) /**< preloading enabled */ +#define CC2420_OPT_TELL_TX_START (0x0010) /**< notify MAC layer on TX + * start */ +#define CC2420_OPT_TELL_TX_END (0x0020) /**< notify MAC layer on TX + * finished */ +#define CC2420_OPT_TELL_RX_START (0x0040) /**< notify MAC layer on RX + * start */ +#define CC2420_OPT_TELL_RX_END (0x0080) /**< notify MAC layer on RX + * finished */ +/** @} */ + +/** + * @brief Possible device state change commands + * @{ + */ +enum { + CC2420_GOTO_PD, /**< power down */ + CC2420_GOTO_IDLE, /**< idle */ + CC2420_GOTO_RX, /**< receive state */ + CC2420_GOTO_TXON, /**< transmit packet without CCA */ + CC2420_GOTO_TXONCCA /**< transmit packet using CCA */ +}; + +/** + * @brief (Selected) device states + */ +enum { + CC2420_STATE_PD = 0, /**< power down */ + CC2420_STATE_IDLE = 1, /**< idle state */ + CC2420_STATE_TX_PRE = 34, /**< transmitting preamble */ + CC2420_STATE_RX_SEARCH = 6, /**< receive SFD search */ + CC2420_STATE_RX_OVERFLOW = 17 /**< receive buffer overflow */ +}; + +/** + * @brief CC2420 SPI commands + * @{ + */ +#define CC2420_REG_WRITE (0x00) /**< read register value */ +#define CC2420_REG_READ (0x40) /**< write register value */ +#define CC2420_RAM (0x80) /**< access the internal RAM */ +#define CC2420_RAM_WRITE (0x00) /**< write to RAM */ +#define CC2420_RAM_READ (0x20) /**< read from RAM */ +#define CC2420_FIFO_READ (CC2420_REG_RXFIFO | CC2420_REG_READ) +#define CC2420_FIFO_WRITE (CC2420_REG_TXFIFO | CC2420_REG_WRITE) +/** @} */ + + +/** + * @brief CC2420 strobe commands + * @see Datasheet section 37, pages 61--62 + * @{ + */ +#define CC2420_STROBE_NOP (0x00) /**< no operation */ +#define CC2420_STROBE_XOSCON (0x01) /**< turn transceiver on */ +#define CC2420_STROBE_TXCAL (0x02) /**< calibrate TX freq and wait */ +#define CC2420_STROBE_RXON (0x03) /**< switch to RX mode */ +#define CC2420_STROBE_TXON (0x04) /**< switch to TX mode */ +#define CC2420_STROBE_TXONCCA (0x05) /**< switch to TX after CCA*/ +#define CC2420_STROBE_RFOFF (0x06) /**< switch to IDLE mode */ +#define CC2420_STROBE_XOSCOFF (0x07) /**< power down */ +#define CC2420_STROBE_FLUSHRX (0x08) /**< flush RX FIFO */ +#define CC2420_STROBE_FLUSHTX (0x09) /**< flush TX FIFO */ +#define CC2420_STROBE_ACK (0x0A) /**< send ACK with pending cleared */ +#define CC2420_STROBE_ACKPEND (0x0B) /**< send ACK with pending set */ +#define CC2420_STROBE_RXDEC (0x0C) /**< start RX FIFO decrypt/verify */ +#define CC2420_STROBE_TXENC (0x0D) /**< start TX FIFO encrypt/auth */ +#define CC2420_STROBE_AES (0x0E) /**< start AES encryption */ +/** @} */ + +/** + * @brief CC2420 configuration registers + * @see Datasheet section 37, pages 61 to 80 + * @{ + */ +#define CC2420_REG_MAIN (0x10) /**< main control */ +#define CC2420_REG_MDMCTRL0 (0x11) /**< modem control 0 */ +#define CC2420_REG_MDMCTRL1 (0x12) /**< modem control 1 */ +#define CC2420_REG_RSSI (0x13) /**< RSSI and CCA control */ +#define CC2420_REG_SYNCWORD (0x14) /**< synchronization word control */ +#define CC2420_REG_TXCTRL (0x15) /**< transmit control */ +#define CC2420_REG_RXCTRL0 (0x16) /**< receive control 0 */ +#define CC2420_REG_RXCTRL1 (0x17) /**< receive control 1 */ +#define CC2420_REG_FSCTRL (0x18) /**< freq synthesizer control */ +#define CC2420_REG_SECCTRL0 (0x19) /**< security control 0 */ +#define CC2420_REG_SECCTRL1 (0x1A) /**< security control 1 */ +#define CC2420_REG_BATTMON (0x1B) /**< battery monitor control */ +#define CC2420_REG_IOCFG0 (0x1C) /**< I/O control 0 */ +#define CC2420_REG_IOCFG1 (0x1D) /**< I/O control 1 */ +#define CC2420_REG_MANFIDL (0x1e) /**< manufacturer ID low */ +#define CC2420_REG_MANFIDH (0x1F) /**< manufacturer ID high */ +#define CC2420_REG_FSMTC (0x20) /**< FSM timer constants */ +#define CC2420_REG_MANAND (0x21) /**< manual signal AND override */ +#define CC2420_REG_MANOR (0x22) /**< manual signal OR override */ +#define CC2420_REG_AGCCTRL (0x23) /**< AGC control */ +#define CC2420_REG_AGCTST0 (0x24) /**< AGC test 0 */ +#define CC2420_REG_AGCTST1 (0x25) /**< AGC test 1 */ +#define CC2420_REG_AGCTST2 (0x26) /**< AGC test 2 */ +#define CC2420_REG_FSTST0 (0x27) /**< freq synthesizer test 0 */ +#define CC2420_REG_FSTST1 (0x28) /**< freq synthesizer test 1 */ +#define CC2420_REG_FSTST2 (0x29) /**< freq synthesizer test 2 */ +#define CC2420_REG_FSTST3 (0x2A) /**< freq synthesizer test 3 */ +#define CC2420_REG_RXBPFTST (0x2B) /**< RX bandpass filter test */ +#define CC2420_REG_FSMSTATE (0x2C) /**< FSM status */ +#define CC2420_REG_ADCTST (0x2D) /**< ADC test */ +#define CC2420_REG_DACTST (0x2E) /**< DAC test */ +#define CC2420_REG_TOPTST (0x2F) /**< top level test */ +#define CC2420_REG_TXFIFO (0x3E) /**< TX FIFO byte */ +#define CC2420_REG_RXFIFO (0x3F) /**< RX FIFO byte */ +/** @} */ + +/** + * @brief CC2420 section address in RAM + * @see Datasheet section 13.5 page 31. + * @{ + */ +#define CC2420_RAM_TXFIFO (0x0000) +#define CC2420_RAM_RXFIFO (0x0080) +#define CC2420_RAM_KEY0 (0x0100) +#define CC2420_RAM_RXNONCE (0x0110) +#define CC2420_RAM_RXCTR (0x0110) +#define CC2420_RAM_SABUF (0x0120) +#define CC2420_RAM_KEY1 (0x0130) +#define CC2420_RAM_TXNONCE (0x0140) +#define CC2420_RAM_TXCTR (0x0140) +#define CC2420_RAM_CBCSTATE (0x0150) +#define CC2420_RAM_IEEEADR (0x0160) +#define CC2420_RAM_PANID (0x0168) +#define CC2420_RAM_SHORTADR (0x016A) +/** @} */ + +/** + * @brief Status byte bit fields + * @see Datasheet section 13.3, page 29 + * @{ + */ +#define CC2420_STATUS_XOSC_STABLE (0x40) +#define CC2420_STATUS_TX_UNDERFLOW (0x20) +#define CC2420_STATUS_ENC_BUSY (0x10) +#define CC2420_STATUS_TX_ACTIVE (0x08) +#define CC2420_STATUS_PLL_LOCK (0x04) +#define CC2420_STATUS_RSSI_VALID (0x02) +/** @} */ + +/** + * @brief Modem control 0 register bitfields + * @{ + */ +#define CC2420_MDMCTRL0_RES_FRM (0x2000 +#define CC2420_MDMCTRL0_ADR_DECODE (0x0800) +#define CC2420_MDMCTRL0_PAN_COORD (0x1000) +#define CC2420_MDMCTRL0_AUTOCRC (0x0020) +#define CC2420_MDMCTRL0_AUTOACK (0x0010) +#define CC2420_MDMCTRL0_PREAMBLE_M (0x000f) +#define CC2420_MDMCTRL0_PREAMBLE_3B (0x0002) +/** @} */ + +/** + * @brief Transmit control register bitfields + * @{ + */ +#define CC2420_TXCTRL_PA_MASK (0x001f) +/** @} */ + +/** + * @brief Receive control register 1 bitfields + * @{ + */ +#define CC2420_RXCTRL1_RXBPF_LOCUR (0x2000) +/** @} */ + +/** + * @brief Frequency synthesizer control and status register bitfields + * @{ + */ +#define CC2420_FSCTRL_LOCK_THR_MASK (0xc000) +#define CC2420_FSCTRL_CAL_DONE (0x2000) +#define CC2420_FSCTRL_CAL_RUNNING (0x1000) +#define CC2420_FSCTRL_LOCK_LENGTH (0x0800) +#define CC2420_FSCTRL_LOCK_STATUS (0x0400) +#define CC2420_FSCTRL_FREQ_MASK (0x03ff) +/** @} */ + +/** + * @brief Security control register 0 bitfields + * @{ + */ +#define CC2420_SECCTRL0_RXFIFO_PROT (0x0200) +/** @} */ + +/** + * @brief Manufacturer ID low register value + */ +#define CC2420_MANFIDL_VAL (0x233d) + +/** + * @brief Manufacturer ID high register value + */ +#define CC2420_MANFIDH_VAL (0x3000) + + +#ifdef __cplusplus +} +#endif + +#endif /* CC2420_REGISTERS_H_ */ diff --git a/drivers/include/cc2420.h b/drivers/include/cc2420.h new file mode 100644 index 0000000000..8fe23ad979 --- /dev/null +++ b/drivers/include/cc2420.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2015 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. + */ + +/** + * @defgroup drivers_cc2420 CC2420 driver + * @ingroup drivers_netdev_netdev2 + * @{ + * + * @file + * @brief Interface definition for the CC2420 driver + * + * @author Thomas Eichinger + * @author Hauke Petersen + */ + +#ifndef CC2420_H +#define CC2420_H + +#include + +#include "periph/spi.h" +#include "periph/gpio.h" + +#include "net/netdev2.h" +#include "net/netdev2/ieee802154.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Maximum possible packet size in byte + */ +#define CC2420_PKT_MAXLEN (127U) + +/** + * @brief Default addresses used if the CPUID module is not present + * + * In case this address is used, that short address will be created by using the + * last two bytes of the long address. + */ +#define CC2420_ADDR_FALLBACK {0x12, 0x22, 0x33, 0x44, 0x55, 0x66, 0x08, 0x15} + +/** + * @brief PAN ID configuration + */ +#define CC2420_PANID_DEFAULT (0x0023) + +/** + * @brief Channel configuration + * @{ + */ +#define CC2420_CHAN_MIN (11U) +#define CC2420_CHAN_MAX (26U) +#define CC2420_CHAN_DEFAULT (26U) +/** @} */ + +/** + * @brief Default TX power configuration [in dBm] + * @{ + */ +#define CC2420_TXPOWER_MIN (-25) +#define CC2420_TXPOWER_MAX (0) +#define CC2420_TXPOWER_DEFAULT (0) +/** @} */ + +/** + * @brief A couple of return values used in this driver + */ +enum { + CC2420_RET_CHAN_OK = 2, +}; + +/** + * @brief Struct holding all parameters needed for device initialization + * @{ + */ +typedef struct cc2420_params { + spi_t spi; /**< SPI bus the device is connected to */ + spi_speed_t spi_clk; /**< SPI speed to use */ + gpio_t pin_cs; /**< pin connected to chip select */ + gpio_t pin_fifo; /**< pin connected to the FIFO interrupt pin */ + gpio_t pin_fifop; /**< pin connected to the FIFOP interrupt pin */ + gpio_t pin_cca; /**< pin connected to CCA */ + gpio_t pin_sfd; /**< pin connected to 'start of frame delimiter' */ + gpio_t pin_vrefen; /**< pin connected to the Vref enable pin */ + gpio_t pin_reset; /**< pin connected to the reset pin */ +} cc2420_params_t; +/** @} */ + +/** + * @brief Device descriptor for CC2420 radio devices + * @{ + */ +typedef struct { + /* netdev fields */ + netdev2_ieee802154_t netdev; /**< netdev2 parent struct */ + /* device specific fields */ + cc2420_params_t params; /**< hardware interface configuration */ + /* device state fields */ + uint8_t state; /**< current state of the radio */ + uint16_t options; /**< state of used options */ +} cc2420_t; +/** @} */ + +/** + * @brief Setup the device descriptor for the given device + * + * @param[out] dev device descriptor + * @param[in] params device parameters + * + * @return 0 on success + * @return -1 on error + */ +void cc2420_setup(cc2420_t *dev, const cc2420_params_t *params); + +/** + * @brief Initialize a given CC2420 device + * + * @param[out] dev device descriptor + * + * @return 0 on success + * @return <0 on error + */ +int cc2420_init(cc2420_t *dev); + +/** + * @brief Trigger a hardware reset and configure radio with default values + * + * @param[in] dev device to reset + * + * @return TODO + */ +int cc2420_reset(cc2420_t *dev); + +/** + * @brief Trigger a clear channel assessment + * + * @param[in] dev device to use + * + * @return true if channel is clear + * @return false if channel is busy + */ +bool cc2420_cca(cc2420_t *dev); + +/** + * @brief Get the short address of the given device + * + * @param[in] dev device to read from + * @param[out] addr memory to write the 2 byte address into + */ +void cc2420_get_addr_short(cc2420_t *dev, uint8_t *addr); + +/** + * @brief Set the short address of the given device + * + * @param[in] dev device to write to + * @param[in] addr (2-byte) short address to set + */ +void cc2420_set_addr_short(cc2420_t *dev, uint8_t *addr); + +/** + * @brief Get the configured long address of the given device + * + * @param[in] dev device to read from + * @param[out] addr_long buffer to save the read address + * + * @return the currently set (8-byte) long address + */ +void cc2420_get_addr_long(cc2420_t *dev, uint8_t *addr_long); + +/** + * @brief Set the long address of the given device + * + * @param[in] dev device to write to + * @param[in] addr_long (8-byte) long address to set + */ +void cc2420_set_addr_long(cc2420_t *dev, uint8_t *addr_long); + +/** + * @brief Get the configured PAN ID of the given device + * + * @param[in] dev device to read from + * + * @return the currently set PAN ID + */ +uint16_t cc2420_get_pan(cc2420_t *dev); + +/** + * @brief Set the PAN ID of the given device + * + * @param[in] dev device to write to + * @param[in] pan PAN ID to set + */ +void cc2420_set_pan(cc2420_t *dev, uint16_t pan); + +/** + * @brief Get the configured channel of the given device + * + * @param[in] dev device to read from + * + * @return the currently set channel + */ +uint16_t cc2420_get_chan(cc2420_t *dev); + +/** + * @brief Set the channel of the given device + * + * @param[in] dev device to write to + * @param[in] chan channel to set + */ +int cc2420_set_chan(cc2420_t *dev, uint16_t chan); + +/** + * @brief Get the configured transmission power of the given device [in dBm] + * + * @param[in] dev device to read from + * + * @return configured transmission power in dBm + */ +int16_t cc2420_get_txpower(cc2420_t *dev); + +/** + * @brief Set the transmission power of the given device [in dBm] + * + * If the device does not support the exact dBm value given, it will set a value + * as close as possible to the given value. If the given value is larger or + * lower then the maximal or minimal possible value, the min or max value is + * set, respectively. + * + * @param[in] dev device to write to + * @param[in] txpower transmission power in dBm + */ +void cc2420_set_txpower(cc2420_t *dev, int16_t txpower); + +/** + * @brief Enable or disable driver specific options + * + * @param[in] dev device to set/clear option flag for + * @param[in] option option to enable/disable + * @param[in] state true for enable, false for disable + */ +int cc2420_set_option(cc2420_t *dev, uint16_t option, bool state); + +/** + * @brief Set the state of the given device (trigger a state change) + * + * @param[in] dev device to change state of + * @param[in] state the targeted new state + */ +int cc2420_set_state(cc2420_t *dev, netopt_state_t state); + +/** + * @brief Get the state of the given device + * + * @param[in] dev device to change state of + * + * @return the device's current state + */ +netopt_state_t cc2420_get_state(cc2420_t *dev); + +/** + * @brief Convenience function for simply sending data + * + * @note This function ignores the PRELOADING option + * + * @param[in] dev device to use for sending + * @param[in] data data to send (must include IEEE802.15.4 header) + * @param[in] count length of @p data + * + * @return number of bytes that were actually send + * @return 0 on error + */ +size_t cc2420_send(cc2420_t *dev, const struct iovec *data, int count); + +/** + * @brief Prepare for sending of data + * + * This function puts the given device into the TX state, so no receiving of + * data is possible after it was called. + * + * @param[in] dev device to prepare for sending + * @param[in] data data to prepare (must include IEEE802.15.4 header) + * @param[in] count length of @p data + */ +size_t cc2420_tx_prepare(cc2420_t *dev, const struct iovec *data, int count); + +/** + * @brief Trigger sending of data previously loaded into transmit buffer + * + * @param[in] dev device to trigger + */ +void cc2420_tx_exec(cc2420_t *dev); + +/** + * @brief Read a chunk of data from the receive buffer of the given device + * + * @param[in] dev device to read from + * @param[out] buf buffer to write data to + * @param[in] max_len number of bytes to read from device + * @param[in] info to be removed + */ +int cc2420_rx(cc2420_t *dev, uint8_t *buf, size_t max_len, void *info); + +#ifdef __cplusplus +} +#endif + +#endif /* CC2420_H */ +/** @} */ diff --git a/examples/default/Makefile b/examples/default/Makefile index ec34ee23ca..266a5d0ab9 100644 --- a/examples/default/Makefile +++ b/examples/default/Makefile @@ -39,7 +39,7 @@ USEMODULE += auto_init_saul BOARD_PROVIDES_NETIF := airfy-beacon fox iotlab-m3 iotlab-a8-m3 mulle native nrf51dongle \ nrf6310 pba-d-01-kw2x pca10000 pca10005 saml21-xpro samr21-xpro spark-core \ - yunjia-nrf51822 + telosb yunjia-nrf51822 z1 ifneq (,$(filter $(BOARD),$(BOARD_PROVIDES_NETIF))) # Use modules for networking diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 5d50ff14f1..b5da2796ee 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -175,6 +175,11 @@ void auto_init(void) auto_init_at86rf2xx(); #endif +#ifdef MODULE_CC2420 + extern void auto_init_cc2420(void); + auto_init_cc2420(); +#endif + #ifdef MODULE_ENCX24J600 extern void auto_init_encx24j600(void); auto_init_encx24j600(); diff --git a/sys/auto_init/netif/auto_init_cc2420.c b/sys/auto_init/netif/auto_init_cc2420.c new file mode 100644 index 0000000000..78f8de3878 --- /dev/null +++ b/sys/auto_init/netif/auto_init_cc2420.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * 2016 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 auto_init_gnrc_netif + * @{ + * + * @file + * @brief Auto initialization for CC2420 network devices + * + * @author Hauke Petersen + * @author Francisco Acosta + */ + +#ifdef MODULE_CC2420 + +#include "board.h" +#include "net/gnrc/netdev2.h" +#include "net/gnrc/netdev2/ieee802154.h" +#include "net/gnrc.h" + +#include "cc2420.h" +#include "cc2420_params.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief MAC layer stack parameters + * @{ + */ +#define CC2420_MAC_STACKSIZE (THREAD_STACKSIZE_MAIN) +#define CC2420_MAC_PRIO (THREAD_PRIORITY_MAIN - 4) +/** @} */ + +/** + * @brief Get the number of configured CC2420 devices + */ +#define CC2420_NUMOF (sizeof(cc2420_params) / sizeof(cc2420_params[0])) + +/** + * @brief Allocate memory for dev descriptors, stacks, and 802.15.4 adaption + * @{ + */ +static cc2420_t cc2420_devs[CC2420_NUMOF]; +static gnrc_netdev2_t gnrc_adpt[CC2420_NUMOF]; +static char _cc2420_stacks[CC2420_NUMOF][CC2420_MAC_STACKSIZE]; +/** @} */ + +void auto_init_cc2420(void) +{ + for (unsigned i = 0; i < CC2420_NUMOF; i++) { + DEBUG("Initializing CC2420 radios #%u\n", i); + + cc2420_setup(&cc2420_devs[i], &cc2420_params[i]); + int res = gnrc_netdev2_ieee802154_init(&gnrc_adpt[i], + (netdev2_ieee802154_t *)&cc2420_devs[i]); + + if (res < 0) { + DEBUG("Error initializing CC2420 radio device!\n"); + } + else { + gnrc_netdev2_init(_cc2420_stacks[i], + CC2420_MAC_STACKSIZE, + CC2420_MAC_PRIO, + "cc2420", &gnrc_adpt[i]); + } + } +} + +#else +typedef int dont_be_pedantic; +#endif /* MODULE_CC2420 */ + +/** @} */ diff --git a/tests/driver_enc28j60/Makefile b/tests/driver_enc28j60/Makefile index c324d3c047..b879374800 100644 --- a/tests/driver_enc28j60/Makefile +++ b/tests/driver_enc28j60/Makefile @@ -3,7 +3,8 @@ include ../Makefile.tests_common FEATURES_REQUIRED = periph_spi periph_gpio -BOARD_INSUFFICIENT_MEMORY := msb-430h nucleo-f334 stm32f0discovery weio z1 +BOARD_INSUFFICIENT_MEMORY := msb-430h nucleo-f334 stm32f0discovery telosb \ + weio z1 USEMODULE += gnrc_netdev2 USEMODULE += gnrc_netdev_default diff --git a/tests/driver_encx24j600/Makefile b/tests/driver_encx24j600/Makefile index b770b94fa7..8b6b8ea2b8 100644 --- a/tests/driver_encx24j600/Makefile +++ b/tests/driver_encx24j600/Makefile @@ -3,7 +3,7 @@ include ../Makefile.tests_common FEATURES_REQUIRED = periph_spi periph_gpio -BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery weio z1 +BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery telosb weio z1 USEMODULE += gnrc_netdev2 USEMODULE += gnrc_netdev_default diff --git a/tests/emb6/Makefile b/tests/emb6/Makefile index 874ed139e1..df1e286881 100644 --- a/tests/emb6/Makefile +++ b/tests/emb6/Makefile @@ -6,7 +6,7 @@ BOARD ?= samr21-xpro RIOTBASE ?= $(CURDIR)/../.. -BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery weio z1 +BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery telosb weio z1 USEMODULE += emb6_router USEMODULE += emb6_conn_udp diff --git a/tests/lwip/Makefile b/tests/lwip/Makefile index f9fdcf2cb2..c004c6202f 100644 --- a/tests/lwip/Makefile +++ b/tests/lwip/Makefile @@ -4,10 +4,10 @@ BOARD ?= iotlab-m3 RIOTBASE ?= $(CURDIR)/../.. -BOARD_BLACKLIST := arduino-mega2560 msb-430h z1 waspmote-pro +BOARD_BLACKLIST := arduino-mega2560 msb-430h telosb waspmote-pro z1 BOARD_INSUFFICIENT_MEMORY := airfy-beacon arduino-mega2560 msb-430h nrf6310 \ - nucleo-f334 pca10005 stm32f0discovery weio \ - yunjia-nrf51822 z1 + nucleo-f334 pca10005 stm32f0discovery telosb \ + weio yunjia-nrf51822 z1 # including lwip_ipv6_mld would currently break this test on at86rf2xx radios USEMODULE += lwip lwip_ipv6_autoconfig lwip_conn_ip lwip_netdev2