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..22258e0e3d --- /dev/null +++ b/drivers/cc2420/cc2420.c @@ -0,0 +1,877 @@ +/* + * Copyright (C) 2015-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 Implementation of public functions for CC2420 driver + * + * @author Thomas Eichinger + * @author Hauke Petersen + * + * @} + */ + +#include "board.h" +#include "xtimer.h" +#include "periph/cpuid.h" +#include "byteorder.h" +#include "panic.h" +#include "net/ieee802154.h" +#include "net/gnrc.h" + +#include "cc2420.h" +#include "cc2420_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief Some constant hardware configuration values + */ +#define SPI_MODE (SPI_CONF_FIRST_RISING) + +extern const netdev2_driver_t cc2420_driver; + +/** + * @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 +}; + + +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 uint8_t 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; +} + +static void 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); +} + +static uint16_t 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); +} + +static void 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); +} + +static void 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); +} + +static void 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); +} + +static void 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); +} + +/** + * @brief Get the device's status byte + */ +static inline uint8_t status(cc2420_t *dev) +{ + return strobe(dev, CC2420_STROBE_NOP); +} + +/** + * @brief Get the device's current state + */ +static inline uint8_t state(cc2420_t *dev) +{ + return (uint8_t)reg_read(dev, CC2420_REG_FSMSTATE); +} + +static inline void en_xosc(cc2420_t *dev) +{ + strobe(dev, CC2420_STROBE_XOSCON); + xtimer_usleep(CC2420_XOSCON_DELAY); +} + +static void fifop_evt(void *arg) +{ + netdev2_t *dev = (netdev2_t *)arg; + dev->event_callback(dev, NETDEV2_EVENT_ISR, NULL); +} + +/** + * @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; + /* TODO: remove once the netdev2/802154 shit is cleaned up */ + dev->netdev.seq = 0; + dev->netdev.flags = NETDEV2_IEEE802154_PAN_COMP; + /* pull in device configuration parameters */ + memcpy(&dev->params, params, sizeof(cc2420_params_t)); + /* reset device descriptor fields */ + dev->options = 0; +} + +int cc2420_init(cc2420_t *dev) +{ + uint16_t reg; + uint8_t addr[8] = CC2420_ADDR_FALLBACK; + + /* 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, fifop_evt, dev); + + /* initialize the chip select line and the SPI bus */ + gpio_init(dev->params.pin_cs, GPIO_OUT); + gpio_set(dev->params.pin_cs); + spi_init_master(dev->params.spi, SPI_MODE, dev->params.spi_clk); + + /* 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 = 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 */ + en_xosc(dev); + if (!(status(dev) & CC2420_STATUS_XOSC_STABLE)) { + DEBUG("[cc2420] init: oscillator did not stabilize\n"); + return -1; + } + + /* 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); + + /* change default RX bandpass filter to 1.3uA (as recommended) */ + reg = reg_read(dev, CC2420_REG_RXCTRL1); + reg |= CC2420_RXCTRL1_RXBPF_LOCUR; + reg_write(dev, CC2420_REG_RXCTRL1, reg); + + /* set the FIFOP threshold to maximum. */ + reg_write(dev, CC2420_REG_IOCFG0, CC2420_PKT_MAXLEN); + + /* turn off "Security enable" (page 33). */ + reg = reg_read(dev, CC2420_REG_SECCTRL0); + reg &= ~CC2420_SECCTRL0_RXFIFO_PROT; + 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 = reg_read(dev, CC2420_REG_MDMCTRL0); + reg &= ~(CC2420_MDMCTRL0_PREAMBLE_M); + reg |= CC2420_MDMCTRL0_PREAMBLE_3B; + reg_write(dev, CC2420_REG_MDMCTRL0, reg); + + return 0; +} + +void cc2420_get_addr_short(cc2420_t *dev, uint8_t *addr) +{ + uint8_t tmp[2]; + + 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]; + + ram_write(dev, CC2420_RAM_SHORTADR, tmp, 2); + + /* TODO: remove after 802.15.4 / netdev2 cleanup */ + memcpy(dev->netdev.short_addr, addr, 2); +} + +void cc2420_get_addr_long(cc2420_t *dev, uint8_t *addr) +{ + ram_read(dev, CC2420_RAM_IEEEADR, addr, 8); +} + +void cc2420_set_addr_long(cc2420_t *dev, uint8_t *addr) +{ + ram_write(dev, CC2420_RAM_IEEEADR, addr, 8); + + /* TODO: remove after 802.15.4 / netdev2 cleanup */ + memcpy(dev->netdev.long_addr, addr, 8); +} + +uint16_t cc2420_get_pan(cc2420_t *dev) +{ + le_uint16_t pan; + + ram_read(dev, CC2420_RAM_PANID, pan.u8, 2); + return pan.u16; +} + +void cc2420_set_pan(cc2420_t *dev, uint16_t pan) +{ + ram_write(dev, CC2420_RAM_PANID, (uint8_t *)&pan, 2); + + /* TODO: remove after 802.15.4 / netdev2 cleanup */ + dev->netdev.pan = pan; +} + +uint16_t cc2420_get_chan(cc2420_t *dev) +{ + uint16_t chan; + uint16_t freq = 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 = reg_read(dev, CC2420_REG_FSCTRL); + freq &= ~CC2420_FSCTRL_FREQ_MASK; + freq |= (357 + (5 * (chan - 11))); + reg_write(dev, CC2420_REG_FSCTRL, freq); + + /* TODO: remove after 802.15.4 / netdev2 cleanup */ + dev->netdev.chan = chan; + + return CC2420_RET_CHAN_OK; +} + +int16_t cc2420_get_txpower(cc2420_t *dev) +{ + uint16_t txctrl = 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 = reg_read(dev, CC2420_REG_TXCTRL); + txctrl &= ~(CC2420_TXCTRL_PA_MASK); + txctrl |= power_dbm_to_pa[txpower + 25]; + 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 = reg_read(dev, CC2420_REG_MDMCTRL0); + reg |= CC2420_MDMCTRL0_AUTOACK; + reg_write(dev, CC2420_REG_MDMCTRL0, reg); + /* TODO: remove after netdev2 cleanup */ + dev->netdev.flags |= NETDEV2_IEEE802154_ACK_REQ; + 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 = reg_read(dev, CC2420_REG_MDMCTRL0); + reg &= ~(CC2420_MDMCTRL0_AUTOACK); + reg &= ~(CC2420_MDMCTRL0_ADR_DECODE); + 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"); + 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 = reg_read(dev, CC2420_REG_MDMCTRL0); + reg &= ~(CC2420_MDMCTRL0_AUTOACK); + reg_write(dev, CC2420_REG_MDMCTRL0, reg); + /* TODO: remove after netdev cleanup */ + dev->netdev.flags &= ~(NETDEV2_IEEE802154_ACK_REQ); + 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 = 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; + } + 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)) { + en_xosc(dev); + } + switch (cmd) { + case NETOPT_STATE_OFF: + strobe(dev, CC2420_STROBE_XOSCOFF); + while (state(dev) != CC2420_STATE_PD) {} + break; + case NETOPT_STATE_SLEEP: + strobe(dev, CC2420_STROBE_RFOFF); + while (state(dev) != CC2420_STATE_IDLE) {} + break; + case NETOPT_STATE_IDLE: + strobe(dev, CC2420_STROBE_FLUSHRX); + 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 = 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; + } +} + +bool cc2420_cca(cc2420_t *dev) +{ + while (!(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 */ + strobe(dev, CC2420_STROBE_FLUSHTX); + /* push packet length to TX FIFO */ + fifo_write(dev, (uint8_t *)&pkt_len, 1); + /* push packet to TX FIFO */ + for (int i = 0; i < count; i++) { + 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, dev); + } + DEBUG("[cc2420] tx_exec: TX_START\n"); + if (dev->options & CC2420_OPT_CSMA) { + DEBUG("[cc2420] tx_exec: triggering TX with CCA\n"); + strobe(dev, CC2420_STROBE_TXONCCA); + } + else { + DEBUG("[cc2420] tx_exec: triggering TX without CCA\n"); + 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, dev); + } + 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 */ + 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 */ + fifo_read(dev, NULL, 1); + /* read fifo contents */ + DEBUG("[cc2420] recv: reading %i byte of the packet\n", (int)len); + fifo_read(dev, buf, len); + + uint8_t rssi; + fifo_read(dev, &rssi, 1); + DEBUG("[cc2420] recv: RSSI is %i\n", (int)rssi); + /* finally flush the FIFO */ + strobe(dev, CC2420_STROBE_FLUSHRX); + strobe(dev, CC2420_STROBE_FLUSHRX); + } + + return (int)len; +} + +static int init(netdev2_t *dev) +{ + return cc2420_init((cc2420_t *)dev); +} + +static void isr(netdev2_t *netdev) +{ + netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE, NULL); +} + +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; +} + +const netdev2_driver_t cc2420_driver = { + .send = send, + .recv = recv, + .init = init, + .isr = isr, + .get = get, + .set = set, +}; diff --git a/drivers/cc2420/include/cc2420_internal.h b/drivers/cc2420/include/cc2420_internal.h new file mode 100644 index 0000000000..d6bb5a53bd --- /dev/null +++ b/drivers/cc2420/include/cc2420_internal.h @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2014 Milan Babel and INRIA + * Copyright (C) 2015-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 Definitions and settings for the CC2420 + * + * @author Milan Babel + * @author Kévin Roussel + * @author Thomas Eichinger + * @author Hauke Petersen + * + */ +#ifndef CC2420_REGISTERS_H +#define CC2420_REGISTERS_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) +/** @} */ + +/** + * @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 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/include/cc2420.h b/drivers/include/cc2420.h new file mode 100644 index 0000000000..1baac59598 --- /dev/null +++ b/drivers/include/cc2420.h @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2015-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. + */ + +/** + * @defgroup drivers_cc2420 CC2420 driver + * @ingroup drivers + * @brief Implementation of the CC2420 radio driver + * @{ + * + * @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; + /* 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 + * + * @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 (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] len 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 + */ +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] data buffer to write data to + * @param[in] len number of bytes to read from device + * @param[in] offset offset in the receive buffer + */ +int cc2420_rx(cc2420_t *dev, uint8_t *buf, size_t max_len, void *info); + +#ifdef __cplusplus +} +#endif + +#endif /* CC2420_H */ +/** @} */