diff --git a/drivers/cc2420/cc2420.c b/drivers/cc2420/cc2420.c index 61dc539246..8bfb5f1ba2 100644 --- a/drivers/cc2420/cc2420.c +++ b/drivers/cc2420/cc2420.c @@ -1,11 +1,14 @@ /** * cc2420.c - Implementation of cc2420 functions. * Copyright (C) 2013 Milan Babel + * Copyright (C) 2014 Kévin Roussel * - * This source code is licensed under the GNU Lesser General Public License, - * Version 2. See the file LICENSE for more details. + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. */ +#include "crash.h" #include "cc2420.h" #include "cc2420_spi.h" #include "cc2420_settings.h" @@ -15,28 +18,38 @@ #define ENABLE_DEBUG (0) #include "debug.h" -/* Radio driver API */ -void cc2420_init(int tpid) +/* number of attempts to turn on transceiver at startup, before panicking */ +#define CC2420_STARTUP_ATTEMPTS 3 + +/* startup timeout (2 ms) in 16MHz-clock cycles */ +#define CC2420_STARTUP_TIMEOUT 32000U + + +/* implementation of driver's functions */ + +void cc2420_initialize(void) { - uint16_t reg; - transceiver_pid = tpid; - cc2420_spi_init(); hwtimer_wait(CC2420_WAIT_TIME); cc2420_reset(); - cc2420_strobe(CC2420_STROBE_XOSCON); //enable crystal - - while ((cc2420_strobe(NOBYTE) & 0x40) == 0); //wait for crystal to be stable + bool ok = false; + for (int i = 0; i < CC2420_STARTUP_ATTEMPTS; i++) { + ok = cc2420_on(); + if (ok) break; + } + if (!ok) { + core_panic(0x2420, "Could not start CC2420 radio transceiver"); + } hwtimer_wait(CC2420_WAIT_TIME); - reg = cc2420_read_reg(CC2420_REG_MDMCTRL0); - reg |= CC2420_ADR_DECODE; //enable adr decode - reg |= CC2420_AUTOACK; //enable auto ack - reg |= CC2420_AUTOCRC; //enable auto crc - reg &= ~(CC2420_RES_FRM_MODE); //disable reserved frames + uint16_t reg = cc2420_read_reg(CC2420_REG_MDMCTRL0); + reg |= CC2420_ADR_DECODE; /* enable auto adress decoding */ + reg |= CC2420_AUTOACK; /* enable auto ACK */ + reg |= CC2420_AUTOCRC; /* enable auto CRC */ + reg &= ~(CC2420_RES_FRM_MODE); /* disable reserved frames */ cc2420_write_reg(CC2420_REG_MDMCTRL0, reg); /* Change default values as recomended in the data sheet, */ @@ -53,15 +66,53 @@ void cc2420_init(int tpid) reg &= ~CC2420_RXFIFO_PROTECTION; cc2420_write_reg(CC2420_REG_SECCTRL0, reg); - /* set output power to 0dbm */ - cc2420_write_reg(CC2420_REG_TXCTRL, 0xA0FF); - + cc2420_set_tx_power(0); cc2420_set_channel(CC2420_DEFAULT_CHANNR); cc2420_set_pan(0x1111); DEBUG("CC2420 initialized and set to channel %i and pan 0x1111\n", CC2420_DEFAULT_CHANNR); cc2420_init_interrupts(); cc2420_switch_to_rx(); +} +void cc2420_init(int tpid) +{ + transceiver_pid = tpid; + cc2420_initialize(); +} + +bool cc2420_on(void) +{ + /* enable transceiver's crystal oscillator */ + cc2420_strobe(CC2420_STROBE_XOSCON); + /* wait for the oscillator to be stable */ + unsigned int delay_on = 0; + do { + delay_on++; + if (delay_on >= CC2420_STARTUP_TIMEOUT) { + /* could not start up radio transceiver! */ + return false; + } + } while ((cc2420_status_byte() & CC2420_STATUS_XOSC16M_STABLE) == 0); + hwtimer_wait(CC2420_WAIT_TIME); + /* discard any potential garbage in TX buffer */ + cc2420_strobe(CC2420_STROBE_FLUSHTX); + /* switch to RX mode */ + cc2420_switch_to_rx(); + /* OK, radio is on */ + return true; +} + +void cc2420_off(void) +{ + /* halt any pending communication... */ + cc2420_strobe(CC2420_STROBE_RFOFF); + /* ... and put the transceiver in power-down mode */ + cc2420_strobe(CC2420_STROBE_XOSCOFF); +} + +bool cc2420_is_on(void) +{ + return ((cc2420_status_byte() & CC2420_STATUS_XOSC16M_STABLE) != 0); } void cc2420_switch_to_rx(void) @@ -75,7 +126,7 @@ void cc2420_switch_to_rx(void) void cc2420_rxoverflow_irq(void) { cc2420_strobe(CC2420_STROBE_FLUSHRX); - //Datasheets says do this twice... + /* CC2420 datasheet says to do this twice... */ cc2420_strobe(CC2420_STROBE_FLUSHRX); } @@ -84,45 +135,44 @@ void cc2420_rx_irq(void) cc2420_rx_handler(); } -void cc2420_set_monitor(uint8_t mode) +void cc2420_set_monitor(bool mode) { - uint16_t reg; - reg = cc2420_read_reg(CC2420_REG_MDMCTRL0); - + uint16_t reg = cc2420_read_reg(CC2420_REG_MDMCTRL0); if (mode) { reg &= ~CC2420_ADR_DECODE; - } - else { + } else { reg |= CC2420_ADR_DECODE; } - cc2420_write_reg(CC2420_REG_MDMCTRL0, reg); } -int16_t cc2420_set_channel(uint16_t chan) +bool cc2420_get_monitor(void) { - uint16_t freq; + uint16_t reg = cc2420_read_reg(CC2420_REG_MDMCTRL0); + return ((reg & CC2420_ADR_DECODE) == 0); +} +int cc2420_set_channel(unsigned int chan) +{ if (chan < 11 || chan > 26) { DEBUG("Invalid channel %i set. Valid channels are 11 through 26\n", chan); return -1; } - /* * calculation from http://www.ti.com/lit/ds/symlink/cc2420.pdf p.50 */ - freq = 357 + (5 * (chan - 11)); + uint16_t freq = 357 + (5 * (chan - 11)); cc2420_write_reg(CC2420_REG_FSCTRL, freq); - return (int32_t)chan; + return ((unsigned int) chan); } -uint16_t cc2420_get_channel(void) +unsigned int cc2420_get_channel(void) { /* undo calculation from cc2420_set_channel() */ return ((cc2420_read_reg(CC2420_REG_FSCTRL) - 357) / 5) + 11; } -radio_address_t cc2420_set_address(radio_address_t addr) +uint16_t cc2420_set_address(uint16_t addr) { uint8_t buf[2]; buf[0] = (uint8_t)(addr & 0xFF); @@ -147,9 +197,9 @@ uint64_t cc2420_set_address_long(uint64_t addr) return addr; } -radio_address_t cc2420_get_address(void) +uint16_t cc2420_get_address(void) { - radio_address_t addr; + uint16_t addr; cc2420_read_ram(CC2420_RAM_SHORTADR, (uint8_t *)&addr, sizeof(addr)); return addr; } @@ -177,7 +227,69 @@ uint16_t cc2420_get_pan(void) return pan; } -inline bool channel_clear(void) +static const uint8_t DBM_TO_LEVEL[32] = { + 31, 27, 25, 23, 21, 19, 17, 15, 13, 12, 11, 10, 9, 8, 7, 7, + 6, 6, 5, 5, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3 +}; + +int cc2420_set_tx_power(int pow) +{ + uint16_t txctrl_reg = cc2420_read_reg(CC2420_REG_TXCTRL); + /* reset PA_LEVEL bits */ + txctrl_reg &= 0xFFE0; + /* constrain power in transceiver's acceptable set of values */ + if (pow > 0) pow = 0; + if (pow < -25) pow = -25; + /* determine TX level from power in dBm */ + uint8_t level = DBM_TO_LEVEL[-pow]; + /* put wanted value in PA_LEVEL bits, and write back register */ + txctrl_reg |= level; + cc2420_write_reg(CC2420_REG_TXCTRL, txctrl_reg); + return pow; +} + +static const int LEVEL_TO_DBM[32] = { + -25, -25, -25, -24, -21, -19, -17, -15, -13, -12, -11, -10, -9, -8, -7, -7, + -6, -6, -5, -5, -4, -4, -3, -3, -2, -2, -1, -1, 0, 0, 0, 0 +}; + +int cc2420_get_tx_power(void) +{ + uint16_t txctrl_reg = cc2420_read_reg(CC2420_REG_TXCTRL); + /* PA_LEVEL is in the 5 least-significant bits of TXCTRL register */ + uint8_t level = txctrl_reg & 0x001F; + /* determine output power in dBm from TX level */ + int pow = LEVEL_TO_DBM[level]; + return pow; +} + +inline bool cc2420_channel_clear(void) { return (cc2420_get_cca() != 0); } + +/* CC2420 low-level radio driver definition */ +const ieee802154_radio_driver_t cc2420_radio_driver = { + .init = cc2420_initialize, + .on = cc2420_on, + .off = cc2420_off, + .is_on = cc2420_is_on, + .load_tx = cc2420_load_tx_buf, + .transmit = cc2420_transmit_tx_buf, + .send = cc2420_do_send, + .set_receive_callback = cc2420_set_recv_callback, + .switch_to_rx = cc2420_switch_to_rx, + .set_channel = do_set_channel, + .get_channel = cc2420_get_channel, + .set_address = do_set_address, + .get_address = cc2420_get_address, + .set_long_address = do_set_long_address, + .get_long_address = cc2420_get_address_long, + .set_pan_id = do_set_pan_id, + .get_pan_id = cc2420_get_pan, + .set_tx_power = do_set_tx_power, + .get_tx_power = cc2420_get_tx_power, + .channel_is_clear = cc2420_channel_clear, + .set_promiscuous_mode = cc2420_set_monitor, + .in_promiscuous_mode = cc2420_get_monitor +}; diff --git a/drivers/cc2420/cc2420_rx.c b/drivers/cc2420/cc2420_rx.c index d8172956bd..2f4ba0a810 100644 --- a/drivers/cc2420/cc2420_rx.c +++ b/drivers/cc2420/cc2420_rx.c @@ -1,9 +1,11 @@ /** * cc2420_rx.c - Implementation of receiving cc2420 functions. * Copyright (C) 2013 Milan Babel + * Copyright (C) 2014 Kévin Roussel * - * This source code is licensed under the GNU Lesser General Public License, - * Version 2. See the file LICENSE for more details. + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. */ #include @@ -18,37 +20,57 @@ #include "msg.h" #include "debug.h" +/* circular buffer for incoming 802.15.4 packets */ cc2420_packet_t cc2420_rx_buffer[CC2420_RX_BUF_SIZE]; -volatile uint8_t rx_buffer_next; +volatile uint8_t rx_buffer_next; /* index of next free cell in RX buffer */ + +/* pointer to the callback low-level function for packet reception */ +static receive_802154_packet_callback_t recv_func = NULL; + + +void cc2420_set_recv_callback(receive_802154_packet_callback_t recv_cb) +{ + recv_func = recv_cb; +} void cc2420_rx_handler(void) { - uint8_t rssi_crc_lqi[2]; + uint8_t pkt_len, pkt_lqi; + int8_t pkt_rssi; + bool crc_ok; /* read length */ - cc2420_read_fifo(&cc2420_rx_buffer[rx_buffer_next].length, 1); + cc2420_read_fifo(&pkt_len, 1); - /* read packet without rssi, crc and lqi */ - uint8_t buf[cc2420_rx_buffer[rx_buffer_next].length - 2]; - cc2420_read_fifo(buf, cc2420_rx_buffer[rx_buffer_next].length - 2); + /* read packet's raw payload */ + uint8_t buf[pkt_len - 2]; + cc2420_read_fifo(buf, pkt_len - 2); /* read rssi, lqi and crc */ - cc2420_read_fifo(rssi_crc_lqi, 2); - - /* build package */ - cc2420_rx_buffer[rx_buffer_next].rssi = (int8_t)(rssi_crc_lqi[0]); - cc2420_rx_buffer[rx_buffer_next].lqi = (uint8_t)(rssi_crc_lqi[1] & 0x7F); - cc2420_rx_buffer[rx_buffer_next].crc = (uint8_t)((rssi_crc_lqi[1] & 0x80) >> 7); - - if (cc2420_rx_buffer[rx_buffer_next].crc == 0) { + cc2420_read_fifo((uint8_t *) &pkt_rssi, 1); + cc2420_read_fifo(&pkt_lqi, 1); + crc_ok = ((pkt_lqi & 0x80) != 0); + pkt_lqi &= 0x7F; + if (!crc_ok) { DEBUG("Got packet with invalid crc.\n"); return; } + /* low-level reception mechanism (for MAC layer, among others) */ + if (recv_func != NULL) { + recv_func(buf, pkt_len - 2, pkt_rssi, pkt_lqi, crc_ok); + } + + /* decode received packet */ + cc2420_rx_buffer[rx_buffer_next].length = pkt_len; + cc2420_rx_buffer[rx_buffer_next].rssi = pkt_rssi; + cc2420_rx_buffer[rx_buffer_next].lqi = pkt_lqi; + cc2420_rx_buffer[rx_buffer_next].crc = (crc_ok ? 1 : 0); ieee802154_frame_read(buf, &cc2420_rx_buffer[rx_buffer_next].frame, cc2420_rx_buffer[rx_buffer_next].length); + /* follow-up to transceiver module if adequate */ if (cc2420_rx_buffer[rx_buffer_next].frame.fcf.frame_type != 2) { #ifdef DEBUG ieee802154_frame_print_fcf_frame(&cc2420_rx_buffer[rx_buffer_next].frame); diff --git a/drivers/cc2420/cc2420_spi.c b/drivers/cc2420/cc2420_spi.c index 72f2d63f57..6c31afe292 100644 --- a/drivers/cc2420/cc2420_spi.c +++ b/drivers/cc2420/cc2420_spi.c @@ -2,8 +2,9 @@ * cc2420_spi.c - Implementation of SPI cc2420 functions. * Copyright (C) 2013 Milan Babel * - * This source code is licensed under the GNU Lesser General Public License, - * Version 2. See the file LICENSE for more details. + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. */ #include "cc2420_spi.h" diff --git a/drivers/cc2420/cc2420_tx.c b/drivers/cc2420/cc2420_tx.c index ce1c088d3c..d6b7d751d0 100644 --- a/drivers/cc2420/cc2420_tx.c +++ b/drivers/cc2420/cc2420_tx.c @@ -2,8 +2,9 @@ * cc2420_rx.c - Implementation of transmitting cc2420 functions. * Copyright (C) 2013 Milan Babel * - * This source code is licensed under the GNU Lesser General Public License, - * Version 2. See the file LICENSE for more details. + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. */ #include @@ -15,13 +16,202 @@ #include "ieee802154_frame.h" #include "irq.h" +#include "hwtimer.h" #define ENABLE_DEBUG (0) #include "debug.h" static void cc2420_gen_pkt(uint8_t *buf, cc2420_packet_t *packet); - static uint8_t sequenz_nr; +static bool wait_for_ack; + +radio_tx_status_t cc2420_load_tx_buf(ieee802154_packet_kind_t kind, + ieee802154_node_addr_t dest, + bool use_long_addr, + bool wants_ack, + void *buf, + unsigned int len) +{ + uint8_t hdr[24]; + + /* FCS : frame version 0, we don't manage security, + nor batchs of packets */ + switch (kind) { + case PACKET_KIND_BEACON: + hdr[0] = 0x00; + break; + case PACKET_KIND_DATA: + hdr[0] = 0x01; + break; + case PACKET_KIND_ACK: + hdr[0] = 0x02; + break; + default: + return RADIO_TX_INVALID_PARAM; + } + + if (wants_ack) { + hdr[0] |= 0x20; + } + wait_for_ack = wants_ack; + + uint16_t src_pan = cc2420_get_pan(); + bool compress_pan = false; + + if (use_long_addr) { + hdr[1] = 0xcc; + } else { + hdr[1] = 0x88; + /* short address mode, use PAN ID compression + for intra-PAN communication */ + if (dest.pan.id == src_pan) { + compress_pan = true; + hdr[0] |= 0x40; + } + } + + /* sequence number */ + hdr[2] = sequenz_nr++; + + /* variable-length fields */ + int idx = 3; + + if (use_long_addr) { + /* dest long addr */ + hdr[idx++] = (uint8_t)(dest.long_addr & 0xFF); + hdr[idx++] = (uint8_t)(dest.long_addr >> 8); + hdr[idx++] = (uint8_t)(dest.long_addr >> 16); + hdr[idx++] = (uint8_t)(dest.long_addr >> 24); + hdr[idx++] = (uint8_t)(dest.long_addr >> 32); + hdr[idx++] = (uint8_t)(dest.long_addr >> 40); + hdr[idx++] = (uint8_t)(dest.long_addr >> 48); + hdr[idx++] = (uint8_t)(dest.long_addr >> 56); + /* src long addr */ + uint64_t src_long_addr = cc2420_get_address_long(); + hdr[idx++] = (uint8_t)(src_long_addr & 0xFF); + hdr[idx++] = (uint8_t)(src_long_addr >> 8); + hdr[idx++] = (uint8_t)(src_long_addr >> 16); + hdr[idx++] = (uint8_t)(src_long_addr >> 24); + hdr[idx++] = (uint8_t)(src_long_addr >> 32); + hdr[idx++] = (uint8_t)(src_long_addr >> 40); + hdr[idx++] = (uint8_t)(src_long_addr >> 48); + hdr[idx++] = (uint8_t)(src_long_addr >> 56); + } else { + /* dest PAN ID */ + hdr[idx++] = (uint8_t)(dest.pan.id & 0xFF); + hdr[idx++] = (uint8_t)(dest.pan.id >> 8); + /* dest short addr */ + hdr[idx++] = (uint8_t)(dest.pan.addr & 0xFF); + hdr[idx++] = (uint8_t)(dest.pan.addr >> 8); + /* src PAN ID */ + if (!compress_pan) { + uint16_t src_pan = cc2420_get_pan(); + hdr[idx++] = (uint8_t)(src_pan & 0xFF); + hdr[idx++] = (uint8_t)(src_pan >> 8); + } + /* src short addr */ + uint16_t src_addr = cc2420_get_address(); + hdr[idx++] = (uint8_t)(src_addr & 0xFF); + hdr[idx++] = (uint8_t)(src_addr >> 8); + } + + /* total frame size */ + uint8_t size = idx + len + 2; + if (size > CC2420_MAX_PKT_LENGTH) { + return RADIO_TX_PACKET_TOO_LONG; + } + + /* flush TX buffer */ + cc2420_strobe(CC2420_STROBE_FLUSHTX); + + /* write length, header and payload to TX FIFO */ + cc2420_write_fifo(&size, 1); + cc2420_write_fifo(hdr, idx); + cc2420_write_fifo(buf, len); + + return RADIO_TX_OK; +} + +#define CC2420_ACK_WAIT_DELAY_uS 1000 +#define ACK_LENGTH 5 + +radio_tx_status_t cc2420_transmit_tx_buf(void) +{ + /* check if channel clear */ + if (!cc2420_channel_clear()) { + return RADIO_TX_MEDIUM_BUSY; + } + + /* put tranceiver in idle mode */ + cc2420_strobe(CC2420_STROBE_RFOFF); + + /* begin transmission: wait for preamble to be sent */ + unsigned int cpsr = disableIRQ(); + cc2420_strobe(CC2420_STROBE_TXON); + + int abort_count = 0; + while (cc2420_get_sfd() == 0) { + /* Wait for SFD signal to be set -> sync word transmitted */ + abort_count++; + + if (abort_count > CC2420_SYNC_WORD_TX_TIME) { + /* Abort waiting. CC2420 maybe in wrong mode + e.g. sending preambles for always */ + puts("[CC2420 TX] fatal error: could not send packet\n"); + return RADIO_TX_ERROR; + } + } + + restoreIRQ(cpsr); + + /* wait for packet to be sent, i.e.: SFD to go down */ + uint8_t st; + do { + st = cc2420_status_byte(); + } while (cc2420_get_sfd() != 0); + cc2420_switch_to_rx(); + + /* check for underflow error flag */ + if (st & 0x20) { + return RADIO_TX_UNDERFLOW; + } + + /* wait for ACK only if needed */ + if (!wait_for_ack) { + return RADIO_TX_OK; + } + + /* delay for the peer to answer our packet */ + //TODO design a more robust method? + hwtimer_wait(HWTIMER_TICKS(CC2420_ACK_WAIT_DELAY_uS)); + /* try to read a returning ACK packet */ + if (cc2420_get_fifop()) { + uint8_t ackbuf[ACK_LENGTH]; + /* a packet has arrived, read the arrived data */ + cc2420_read_fifo(ackbuf, ACK_LENGTH); + if (ackbuf[0] == 0x02 /* ack packet in buffer */ + && (ackbuf[2] == sequenz_nr - 1)) /* correct sequence number */ + return RADIO_TX_OK; + } + return RADIO_TX_NOACK; +} + +radio_tx_status_t cc2420_do_send(ieee802154_packet_kind_t kind, + ieee802154_node_addr_t dest, + bool use_long_addr, + bool wants_ack, + void *buf, + unsigned int len) +{ + bool ok = cc2420_load_tx_buf(kind, dest, + use_long_addr, + wants_ack, + buf, len); + if (!ok) { + return RADIO_TX_ERROR; + } + return cc2420_transmit_tx_buf(); +} int16_t cc2420_send(cc2420_packet_t *packet) { diff --git a/drivers/cc2420/include/cc2420_arch.h b/drivers/cc2420/include/cc2420_arch.h index dd2435f10a..2b7e6a5d53 100644 --- a/drivers/cc2420/include/cc2420_arch.h +++ b/drivers/cc2420/include/cc2420_arch.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright 2013, Freie Universitaet Berlin (FUB). All rights reserved. + * Copyright 2014, Freie Universitaet Berlin (FUB). All rights reserved. * * These sources were developed at the Freie Universitaet Berlin, Computer Systems and Telematics group (http://cst.mi.fu-berlin.de). @@ -20,9 +20,7 @@ and Telematics group (http://cst.mi.fu-berlin.de). * @author Freie Universität Berlin, Computer Systems & Telematics * @author Heiko Will * @author Milan Babel - * @version $Revision: 1775 $ - * - * @note $Id: arch_cc110x.h 1775 2010-01-26 09:37:03Z hillebra $ + * @author Kévin Roussel */ #include @@ -38,23 +36,31 @@ and Telematics group (http://cst.mi.fu-berlin.de). uint8_t cc2420_txrx(uint8_t c); /** - * @brief Gets the status of the sfd pin. + * @brief Gets the status of the FIFOP pin. * - * @return Status of the sfd pin. + * @return Status of the FIFOP pin. + * + */ +uint8_t cc2420_get_fifop(void); + +/** + * @brief Gets the status of the SFD pin. + * + * @return Status of the SFD pin. * */ uint8_t cc2420_get_sfd(void); /** - * @brief Gets the status of the cca pin + * @brief Gets the status of the CCA pin * - * @return Status of the cca pin. + * @return Status of the CCA pin. * */ uint8_t cc2420_get_cca(void); /** - * @brief Does a hardware reset of the cc2420. + * @brief Does a hardware reset of the CC2420. * */ void cc2420_reset(void); @@ -66,13 +72,13 @@ void cc2420_reset(void); void cc2420_spi_init(void); /** - * @brief Selects the cc2420 on the spi bus. + * @brief Selects the CC2420 on the spi bus. * */ void cc2420_spi_select(void); /** - * @brief Unselects the cc2420 on the spi bus. + * @brief Unselects the CC2420 on the spi bus. * */ void cc2420_spi_unselect(void); diff --git a/drivers/include/cc2420.h b/drivers/include/cc2420.h index 18d48e1195..35c995aa10 100644 --- a/drivers/include/cc2420.h +++ b/drivers/include/cc2420.h @@ -1,9 +1,11 @@ /** * cc2420.h - Definitions for CC2420 functions. * Copyright (C) 2013 Milan Babel + * Copyright (C) 2014 Kévin Roussel * - * This source code is licensed under the GNU Lesser General Public License, - * Version 2. See the file LICENSE for more details. + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. */ @@ -81,7 +83,7 @@ Frame type value: #include "ieee802154_frame.h" #include "cc2420_settings.h" -#include "radio/types.h" +#include "radio_driver.h" #define CC2420_MAX_PKT_LENGTH 127 #define CC2420_MAX_DATA_LENGTH (118) @@ -99,15 +101,20 @@ typedef struct __attribute__ ((packed)) { uint8_t length; /** < the length of the frame of the frame including fcs*/ ieee802154_frame_t frame; /** < the ieee802154 frame */ int8_t rssi; /** < the rssi value */ - uint8_t crc; /** < 1 if crc was successfull, 0 otherwise */ uint8_t lqi; /** < the link quality indicator */ + bool crc; /** < 1 if crc was successfull, 0 otherwise */ /* @} */ } cc2420_packet_t; extern int transceiver_pid; /** - * @brief Init the cc2420. + * @brief Initialize the CC2420 transceiver. + */ +void cc2420_initialize(void); + +/** + * @brief Init the CC2420 for use with RIOT's transceiver module. * * @param[in] tpid The PID of the transceiver thread. */ @@ -115,53 +122,80 @@ extern int transceiver_pid; void cc2420_init(int tpid); /** - * @brief Turns monitor mode on off. + * @brief Turn CC2420 on. * - * @param[in] mode The desired mode, 1 for on; 0 for off. + * @return true if the radio was correctly turned on; false otherwise. */ -void cc2420_set_monitor(uint8_t mode); +bool cc2420_on(void); /** - * @brief Switchs the cc2420 into receive mode. + * @brief Turn CC2420 off. + */ +void cc2420_off(void); + +/** + * @brief Indicate if the CC2420 is on. * + * @return true if the radio transceiver is on (active); false otherwise. + */ +bool cc2420_is_on(void); + +/** + * @brief Switches the CC2420 into receive mode. */ void cc2420_switch_to_rx(void); /** - * @brief Set the channel of the cc2420. + * @brief Turns monitor (promiscuous) mode on or off. + * + * @param[in] mode The desired mode: + * true for monitor (promiscuous) mode; + * false for normal (auto address-decoding) mode. + */ +void cc2420_set_monitor(bool mode); + +/** + * @brief Indicate if the CC2420 is in monitor (promiscuous) mode. + * + * @return true if the transceiver is in monitor (promiscuous) mode; + * false if it is in normal (auto address-decoding) mode. + */ +bool cc2420_get_monitor(void); + +/** + * @brief Set the channel of the CC2420. * * @param[in] chan The desired channel, valid channels are from 11 to 26. * * @return The tuned channel after calling, or -1 on error. */ -int16_t cc2420_set_channel(uint16_t chan); +int cc2420_set_channel(unsigned int chan); /** - * @brief Get the channel of the cc2420. + * @brief Get the channel of the CC2420. * * @return The tuned channel. */ -uint16_t cc2420_get_channel(void); +unsigned int cc2420_get_channel(void); /** - * @brief Sets the short address of the cc2420. + * @brief Sets the short address of the CC2420. * * @param[in] addr The desired address. * * @return The set address after calling. */ -radio_address_t cc2420_set_address(radio_address_t addr); +uint16_t cc2420_set_address(uint16_t addr); /** - * @brief Gets the current short address of the cc2420. + * @brief Gets the current short address of the CC2420. * * @return The current short address. - * */ -radio_address_t cc2420_get_address(void); +uint16_t cc2420_get_address(void); /** - * @brief Sets the IEEE long address of the cc2420. + * @brief Sets the IEEE long address of the CC2420. * * @param[in] addr The desired address. * @@ -170,15 +204,14 @@ radio_address_t cc2420_get_address(void); uint64_t cc2420_set_address_long(uint64_t addr); /** - * @brief Gets the current IEEE long address of the cc2420. + * @brief Gets the current IEEE long address of the CC2420. * * @return The current IEEE long address. - * */ uint64_t cc2420_get_address_long(void); /** - * @brief Sets the pan ID of the cc2420. + * @brief Sets the pan ID of the CC2420. * * @param[in] pan The desired pan ID. * @@ -187,13 +220,39 @@ uint64_t cc2420_get_address_long(void); uint16_t cc2420_set_pan(uint16_t pan); /** - * @brief Gets the current IEEE long address of the cc2420. + * @brief Gets the current IEEE long address of the CC2420. * * @return The current IEEE long address. - * */ uint16_t cc2420_get_pan(void); +/** + * @brief Sets the output (TX) power of the CC2420. + * + * @param[in] pow The desired TX (output) power in dBm, + * valid values are -25 to 0; other values + * will be "saturated" into this range. + * + * @return The set TX (output) power after calling. + */ +int cc2420_set_tx_power(int pow); + +/** + * @brief Gets the current output (TX) power of the CC2420. + * + * @return The current TX (output) power. + */ +int cc2420_get_tx_power(void); + +/** + * @brief Checks if the radio medium is available/clear to send + * ("Clear Channel Assessment" a.k.a. CCA). + * + * @return a `true` value if radio medium is clear (available), + * a `false` value otherwise. + * + */ +bool cc2420_channel_clear(void); /** * @brief Interrupt handler, gets fired when a RX overflow happens. @@ -207,6 +266,14 @@ void cc2420_rxoverflow_irq(void); */ void cc2420_rx_irq(void); +/** + * @brief Sets the function called back when a packet is received. + * (Low-level mechanism, parallel to the `transceiver` module). + * + * @param[in] recv_cb callback function for 802.15.4 packet arrival; + * pass `NULL` to deactivate packet reception. + */ +void cc2420_set_recv_callback(receive_802154_packet_callback_t recv_cb); /** * @brief RX handler, process data from the RX FIFO. @@ -214,6 +281,74 @@ void cc2420_rx_irq(void); */ void cc2420_rx_handler(void); +/** + * @brief Prepare the CC2420 TX buffer to send with the given packet. + * + * @param[in] kind Kind of packet to transmit. + * @param[in] dest Address of the node to which the packet is sent. + * @param[in] use_long_addr `true` to use the 64-bit address mode + * with `dest` param; `false` to use + * "short" PAN-centric mode. + * @param[in] wants_ack `true` to request an acknowledgement + * from the receiving node for this packet; + * `false` otherwise. + * @param[in] buf Pointer to the buffer containing the payload + * of the 802.15.4 packet to transmit. + * The frame header (i.e.: FCS, sequence number, + * src and dest PAN and addresses) is inserted + * using values in accord with `kind` parameter + * and transceiver configuration. + * @param[in] len Length (in bytes) of the outgoing packet payload. + * + * @return `true` if the transceiver TX buffer was loaded correctly; + * `false` otherwise (transceiver error). + */ +radio_tx_status_t cc2420_load_tx_buf(ieee802154_packet_kind_t kind, + ieee802154_node_addr_t dest, + bool use_long_addr, + bool wants_ack, + void *buf, + unsigned int len); + +/** + * @brief Transmit the data loaded into the CC2420 TX buffer. + * + * @return The outcome of this packet's transmission. + * @see radio_tx_status_t + */ +radio_tx_status_t cc2420_transmit_tx_buf(void); + +/** + * @brief Transmit the given IEEE 802.15.4 packet, + * by calling successively functions`load_tx()` + * and `transmit()`. + * + * @param[in] kind Kind of packet to transmit. + * @param[in] dest Address of the node to which the packet is sent. + * @param[in] use_long_addr `true` to use the 64-bit address mode + * with `dest` param; `false` to use + * "short" PAN-centric mode. + * @param[in] wants_ack `true` to request an acknowledgement + * from the receiving node for this packet; + * `false` otherwise. + * @param[in] buf Pointer to the buffer containing the payload + * of the 802.15.4 packet to transmit. + * The frame header (i.e.: FCS, sequence number, + * src and dest PAN and addresses) is inserted + * using values in accord with `kind` parameter + * and transceiver configuration. + * @param[in] len Length (in bytes) of the outgoing packet payload. + * + * @return The outcome of this packet's transmission. + * @see radio_tx_status_t + */ +radio_tx_status_t cc2420_do_send(ieee802154_packet_kind_t kind, + ieee802154_node_addr_t dest, + bool use_long_addr, + bool wants_ack, + void *buf, + unsigned int len); + /** * @brief Send function, sends a cc2420_packet_t over the air. * @@ -224,16 +359,6 @@ void cc2420_rx_handler(void); */ int16_t cc2420_send(cc2420_packet_t *packet); -/** - * @brief Checks if the radio medium is available/clear to send - * ("Clear Channel Assessment" a.k.a. CCA). - * - * @return a @c true value if radio medium is clear (available), - * a @c false value otherwise. - * - */ -bool channel_clear(void); - /** * The PID of the transceiver thread. */ @@ -245,4 +370,37 @@ extern int transceiver_pid; extern cc2420_packet_t cc2420_rx_buffer[CC2420_RX_BUF_SIZE]; +/** Utility macro: get CC2420's status byte */ +#define cc2420_status_byte() cc2420_strobe(NOBYTE) + + +/* setter functions wrappers, to maintain compatibility with both + ieee802154_radio_driver_t and transceiver module */ + +static inline void do_set_channel(unsigned int chan) { + cc2420_set_channel(chan); +} + +static inline void do_set_address(uint16_t addr) { + cc2420_set_address(addr); +} + +static inline void do_set_long_address(uint64_t addr) { + cc2420_set_address_long(addr); +} + +static inline void do_set_pan_id(uint16_t pan) { + cc2420_set_pan(pan); +} + +static inline void do_set_tx_power(int pow) { + cc2420_set_tx_power(pow); +} + +/** + * CC2420 low-level radio driver definition. + */ +extern const ieee802154_radio_driver_t cc2420_radio_driver; + + #endif