nes-proj/arch/dev/cc1200/cc1200.c

2555 lines
69 KiB
C

/*
* Copyright (c) 2015, Weptech elektronik GmbH Germany
* http://www.weptech.de
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
#include "cc1200-const.h"
#include "cc1200-conf.h"
#include "cc1200-arch.h"
#include "cc1200-rf-cfg.h"
#include "net/netstack.h"
#include "net/packetbuf.h"
#include "dev/watchdog.h"
#include "sys/energest.h"
#include "dev/leds.h"
#include <string.h>
#include <stdio.h>
static int16_t rssi;
static rtimer_clock_t sfd_timestamp = 0;
/*---------------------------------------------------------------------------*/
/* Various implementation specific defines */
/*---------------------------------------------------------------------------*/
/*
* The debug level to use
* - 0: No output at all
* - 1: Print errors (unrecoverable)
* - 2: Print errors + warnings (recoverable errors)
* - 3: Print errors + warnings + information (what's going on...)
*/
#define DEBUG_LEVEL 0
/*
* RF test mode. Blocks inside "configure()".
* - Set this parameter to 1 in order to produce an modulated carrier (PN9)
* - Set this parameter to 2 in order to produce an unmodulated carrier
* - Set this parameter to 3 in order to switch to rx synchronous mode
* The channel is set according to CC1200_DEFAULT_CHANNEL
*/
#ifndef CC1200_RF_TESTMODE
#define CC1200_RF_TESTMODE 0
#endif
#if CC1200_RF_TESTMODE
#undef CC1200_RF_CFG
#if CC1200_RF_TESTMODE == 1
#define CC1200_RF_CFG cc1200_802154g_863_870_fsk_50kbps
#elif CC1200_RF_TESTMODE == 2
#define CC1200_RF_CFG cc1200_802154g_863_870_fsk_50kbps
#elif CC1200_RF_TESTMODE == 3
#define CC1200_RF_CFG cc1200_802154g_863_870_fsk_50kbps
#endif
#endif
/*
* When set, a software buffer is used to store outgoing packets before copying
* to Tx FIFO. This enabled sending packets larger than the FIFO. When unset,
* no buffer is used; instead, the payload is copied directly to the Tx FIFO.
* This is requried by TSCH, for shorter and more predictable delay in the Tx
* chain. This, however, restircts the payload length to the Tx FIFO size.
*/
#define CC1200_WITH_TX_BUF (!MAC_CONF_WITH_TSCH)
/*
* Set this parameter to 1 in order to use the MARC_STATE register when
* polling the chips's status. Else use the status byte returned when sending
* a NOP strobe.
*
* TODO: Option to be removed upon approval of the driver
*/
#define STATE_USES_MARC_STATE 0
/*
* Set this parameter to 1 in order to speed up transmission by
* sending a FSTXON strobe before filling the FIFO.
*
* TODO: Option to be removed upon approval of the driver
*/
#if MAC_CONF_WITH_TSCH
#define USE_SFSTXON 0
#else /* MAC_CONF_WITH_TSCH */
#define USE_SFSTXON 1
#endif /* MAC_CONF_WITH_TSCH */
/*---------------------------------------------------------------------------*/
/* Phy header length */
#if CC1200_802154G
/* Phy header = 2 byte */
#define PHR_LEN 2
#else
/* Phy header = length byte = 1 byte */
#define PHR_LEN 1
#endif /* #if CC1200_802154G */
/*---------------------------------------------------------------------------*/
/* Size of appendix (rssi + lqi) appended to the rx pkt */
#define APPENDIX_LEN 2
/*---------------------------------------------------------------------------*/
/* Verify payload length */
/*---------------------------------------------------------------------------*/
#if CC1200_802154G
#if CC1200_USE_GPIO2
#if CC1200_MAX_PAYLOAD_LEN > (2048 - PHR_LEN)
#error Payload length not supported by this driver
#endif
#else
#if CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)
/* PHR_LEN = 2 -> we can only place 126 payload bytes bytes in the FIFO */
#error Payload length not supported without GPIO2
#endif
#endif /* #if CC1200_USE_GPIO2 */
#else /* #if CC1200_802154G */
#if CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)
/* PHR_LEN = 1 -> we can only place 127 payload bytes bytes in the FIFO */
#error Payload length not supported without enabling 802.15.4g mode
#endif
#endif /* #if CC1200_802154G */
/*---------------------------------------------------------------------------*/
/* Main driver configurations settings. Don't touch! */
/*---------------------------------------------------------------------------*/
#if CC1200_USE_GPIO2
/* Use GPIO2 as RX / TX FIFO threshold indicator pin */
#define GPIO2_IOCFG CC1200_IOCFG_RXFIFO_THR
/* This is the FIFO threshold we use */
#if MAC_CONF_WITH_TSCH
#if CC1200_802154G
#define FIFO_THRESHOLD 1
#else
#define FIFO_THRESHOLD 0
#endif
#else /* MAC_CONF_WITH_TSCH */
#define FIFO_THRESHOLD 32
#endif /* MAC_CONF_WITH_TSCH */
/* Turn on RX after packet reception */
#define RXOFF_MODE_RX 1
/* Let the CC1200 append RSSI + LQI */
#define APPEND_STATUS 1
#else
/* Arbitrary configuration for GPIO2 */
#define GPIO2_IOCFG CC1200_IOCFG_MARC_2PIN_STATUS_0
#if (CC1200_MAX_PAYLOAD_LEN <= (CC1200_FIFO_SIZE - PHR_LEN - APPENDIX_LEN))
/*
* Read out RX FIFO at the end of the packet (GPIO0 falling edge). RX restarts
* automatically
*/
#define RXOFF_MODE_RX 1
/* Let the CC1200 append RSSI + LQI */
#define APPEND_STATUS 1
#else
/*
* Read out RX FIFO at the end of the packet (GPIO0 falling edge). RX has
* to be started manually in this case
*/
#define RXOFF_MODE_RX 0
/* No space for appendix in the RX FIFO. Read it out by hand */
#define APPEND_STATUS 0
#endif /* #if CC1200_MAX_PAYLOAD_LEN <= 125 */
#endif /* #if CC1200_USE_GPIO2 */
/* Read out packet on falling edge of GPIO0 */
#define GPIO0_IOCFG CC1200_IOCFG_PKT_SYNC_RXTX
/* Arbitrary configuration for GPIO3 */
#define GPIO3_IOCFG CC1200_IOCFG_MARC_2PIN_STATUS_0
/* Turn on RX automatically after TX */
#define TXOFF_MODE_RX 1
#if APPEND_STATUS
/* CC1200 places two bytes in the RX FIFO */
#define CC_APPENDIX_LEN 2
#else
/* CC1200 doesn't add appendix to RX FIFO */
#define CC_APPENDIX_LEN 0
#endif /* #if APPEND_STATUS */
/*---------------------------------------------------------------------------*/
/* RF configuration */
/*---------------------------------------------------------------------------*/
/* Import the rf configuration set by CC1200_RF_CFG */
extern const cc1200_rf_cfg_t CC1200_RF_CFG;
/*---------------------------------------------------------------------------*/
/* This defines the way we calculate the frequency registers */
/*---------------------------------------------------------------------------*/
/* XTAL frequency in kHz */
#define XTAL_FREQ_KHZ 40000
/*
* Divider + multiplier for calculation of FREQ registers
* f * 2^16 * 4 / 40000 = f * 2^12 / 625 (no overflow up to frequencies of
* 1048.576 MHz using uint32_t)
*/
#define LO_DIVIDER 4
#if (XTAL_FREQ_KHZ == 40000) && (LO_DIVIDER == 4)
#define FREQ_DIVIDER 625
#define FREQ_MULTIPLIER 4096
#else
#error Invalid settings for frequency calculation
#endif
/*---------------------------------------------------------------------------*/
#if STATE_USES_MARC_STATE
/* We use the MARC_STATE register to poll the chip's status */
#define STATE_IDLE CC1200_MARC_STATE_IDLE
#define STATE_RX CC1200_MARC_STATE_RX
#define STATE_TX CC1200_MARC_STATE_TX
#define STATE_RX_FIFO_ERROR CC1200_MARC_STATE_RX_FIFO_ERR
#define STATE_TX_FIFO_ERROR CC1200_MARC_STATE_TX_FIFO_ERR
#else
/* We use the status byte read out using a NOP strobe */
#define STATE_IDLE CC1200_STATUS_BYTE_IDLE
#define STATE_RX CC1200_STATUS_BYTE_RX
#define STATE_TX CC1200_STATUS_BYTE_TX
#define STATE_FSTXON CC1200_STATUS_BYTE_FSTXON
#define STATE_CALIBRATE CC1200_STATUS_BYTE_CALIBRATE
#define STATE_SETTLING CC1200_STATUS_BYTE_SETTLING
#define STATE_RX_FIFO_ERR CC1200_STATUS_BYTE_RX_FIFO_ERR
#define STATE_TX_FIFO_ERR CC1200_STATUS_BYTE_TX_FIFO_ERR
#endif /* #if STATE_USES_MARC_STATE */
/*---------------------------------------------------------------------------*/
/* Return values for addr_check_auto_ack() */
/*---------------------------------------------------------------------------*/
/* Frame cannot be parsed / is to short */
#define INVALID_FRAME 0
/* Address check failed */
#define ADDR_CHECK_FAILED 1
/* Address check succeeded */
#define ADDR_CHECK_OK 2
/* Address check succeeded and ACK was send */
#define ADDR_CHECK_OK_ACK_SEND 3
/*---------------------------------------------------------------------------*/
/* Return values for set_channel() */
/*---------------------------------------------------------------------------*/
/* Channel update was performed */
#define CHANNEL_UPDATE_SUCCEEDED 0
/* Busy, channel update postponed */
#define CHANNEL_UPDATE_POSTPONED 1
/* Invalid channel */
#define CHANNEL_OUT_OF_LIMITS 2
/*---------------------------------------------------------------------------*/
/* Various flags indicating the operating state of the radio. See rf_flags */
/*---------------------------------------------------------------------------*/
/* Radio was initialized (= init() was called) */
#define RF_INITIALIZED 0x01
/* The radio is on (= not in standby) */
#define RF_ON 0x02
/* An incoming packet was detected (at least payload length was received */
#define RF_RX_PROCESSING_PKT 0x04
/* TX is ongoing */
#define RF_TX_ACTIVE 0x08
/* Channel update required */
#define RF_UPDATE_CHANNEL 0x10
/* SPI was locked when calling RX interrupt, let the pollhandler do the job */
#define RF_POLL_RX_INTERRUPT 0x20
/* Ongoing reception */
#define RF_RX_ONGOING 0x40
/* Force calibration in case we don't use CC1200 AUTOCAL + timeout */
#if !CC1200_AUTOCAL
#if CC1200_CAL_TIMEOUT_SECONDS
#define RF_FORCE_CALIBRATION 0x40
#endif
#endif
/*---------------------------------------------------------------------------*/
/* Length of 802.15.4 ACK. We discard packets with a smaller size */
#define ACK_LEN 3
/*---------------------------------------------------------------------------*/
/* This is the way we handle the LEDs */
/*---------------------------------------------------------------------------*/
#ifdef CC1200_TX_LEDS
#define TX_LEDS_ON() leds_on(CC1200_TX_LEDS)
#define TX_LEDS_OFF() leds_off(CC1200_TX_LEDS)
#else
#define TX_LEDS_ON()
#define TX_LEDS_OFF()
#endif /* #ifdef CC1200_TX_LEDS */
#ifdef CC1200_RX_LEDS
#define RX_LEDS_ON() leds_on(CC1200_RX_LEDS)
#define RX_LEDS_OFF() leds_off(CC1200_RX_LEDS)
#else
#define RX_LEDS_ON()
#define RX_LEDS_OFF()
#endif /* #ifdef CC1200_RX_LEDS */
/*---------------------------------------------------------------------------*/
/*
* We have to prevent duplicate SPI access.
* We therefore LOCK SPI in order to prevent the rx interrupt to
* interfere.
*/
#define LOCK_SPI() do { spi_locked++; } while(0)
#define SPI_IS_LOCKED() (spi_locked != 0)
#define RELEASE_SPI() do { spi_locked--; } while(0)
/*---------------------------------------------------------------------------*/
#if CC1200_USE_GPIO2
/* Configure GPIO interrupts. GPIO0: falling, GPIO2: rising edge */
#define SETUP_GPIO_INTERRUPTS() \
do { \
cc1200_arch_gpio0_setup_irq(0); \
cc1200_arch_gpio2_setup_irq(1); \
} while(0)
#define ENABLE_GPIO_INTERRUPTS() \
do { \
cc1200_arch_gpio0_enable_irq(); \
cc1200_arch_gpio2_enable_irq(); \
} while(0)
#define DISABLE_GPIO_INTERRUPTS() \
do { \
cc1200_arch_gpio0_disable_irq(); \
cc1200_arch_gpio2_disable_irq(); \
} while(0)
#else
#define SETUP_GPIO_INTERRUPTS() cc1200_arch_gpio0_setup_irq(0)
#define ENABLE_GPIO_INTERRUPTS() cc1200_arch_gpio0_enable_irq()
#define DISABLE_GPIO_INTERRUPTS() cc1200_arch_gpio0_disable_irq()
#endif /* #if CC1200_USE_GPIO2 */
/*---------------------------------------------------------------------------*/
/* Debug macros */
/*---------------------------------------------------------------------------*/
#if DEBUG_LEVEL > 0
/* Show all kind of errors e.g. when passing invalid payload length */
#define ERROR(...) printf(__VA_ARGS__)
#else
#define ERROR(...)
#endif
#if DEBUG_LEVEL > 0
/* This macro is used to check if the radio is in a valid state */
#define RF_ASSERT(condition) \
do { \
if(!(condition)) { \
printf("RF: Assertion failed in line %d\n", __LINE__); \
} \
} while(0)
#else
#define RF_ASSERT(condition)
#endif
#if DEBUG_LEVEL > 1
/* Show warnings e.g. for FIFO errors */
#define WARNING(...) printf(__VA_ARGS__)
#else
#define WARNING(...)
#endif
#if DEBUG_LEVEL > 2
/* We just print out what's going on */
#define INFO(...) printf(__VA_ARGS__)
#else
#define INFO(...)
#endif
/* Busy-wait (time-bounded) until the radio reaches a given state */
#define RTIMER_BUSYWAIT_UNTIL_STATE(s, t) RTIMER_BUSYWAIT_UNTIL(state() == (s), t)
/*---------------------------------------------------------------------------*/
/* Variables */
/*---------------------------------------------------------------------------*/
/* Flag indicating whether non-interrupt routines are using SPI */
static volatile uint8_t spi_locked = 0;
#if CC1200_WITH_TX_BUF
/* Packet buffer for transmission, filled within prepare() */
static uint8_t tx_pkt[CC1200_MAX_PAYLOAD_LEN];
#endif /* CC1200_WITH_TX_BUF */
/* The number of bytes waiting in tx_pkt */
static uint16_t tx_pkt_len;
/* Number of bytes from tx_pkt left to write to FIFO */
uint16_t bytes_left_to_write;
/* Packet buffer for reception */
static uint8_t rx_pkt[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN];
/* The number of bytes placed in rx_pkt */
static volatile uint16_t rx_pkt_len = 0;
/*
* The current channel in the range CC1200_RF_CHANNEL_MIN
* to CC1200_RF_CHANNEL_MAX
*/
static uint8_t rf_channel;
/* The next channel requested */
static uint8_t new_rf_channel;
/* RADIO_PARAM_RX_MODE. Initialized in init() */
static radio_value_t rx_mode_value;
/* RADIO_PARAM_RX_MODE. Initialized in init() */
static radio_value_t tx_mode_value;
/* RADIO_PARAM_TXPOWER in dBm. Initialized in init() */
static int8_t txpower;
static int8_t new_txpower;
/* RADIO_PARAM_CCA_THRESHOLD. Initialized in init() */
static int8_t cca_threshold;
static int8_t new_cca_threshold;
/* The radio drivers state */
static uint8_t rf_flags = 0;
#if !CC1200_AUTOCAL && CC1200_CAL_TIMEOUT_SECONDS
/* Use a timeout to decide when to calibrate */
static unsigned long cal_timer;
#endif
#if CC1200_USE_RX_WATCHDOG
/* Timer used for RX watchdog */
static struct etimer et;
#endif /* #if CC1200_USE_RX_WATCHDOG */
/*---------------------------------------------------------------------------*/
/* Prototypes for Netstack API radio driver functions */
/*---------------------------------------------------------------------------*/
/* Init the radio. */
static int
init(void);
/* Prepare and copy PHY header to Tx FIFO */
static int
copy_header_to_tx_fifo(unsigned short payload_len);
/* Prepare the radio with a packet to be sent. */
static int
prepare(const void *payload, unsigned short payload_len);
/* Send the packet that has previously been prepared. */
static int
transmit(unsigned short payload_len);
/* Prepare & transmit a packet. */
static int
send(const void *payload, unsigned short payload_len);
/* Read a received packet into a buffer. */
static int
read(void *buf, unsigned short bufsize);
/*
* Perform a Clear-Channel Assessment (CCA) to find out if there is
* a packet in the air or not.
*/
static int
channel_clear(void);
/* Check if the radio driver is currently receiving a packet. */
static int
receiving_packet(void);
/* Check if the radio driver has just received a packet. */
static int
pending_packet(void);
/* Turn the radio on. */
static int
on(void);
/* Turn the radio off. */
static int
off(void);
/* Get a radio parameter value. */
static radio_result_t
get_value(radio_param_t param, radio_value_t *value);
/* Set a radio parameter value. */
static radio_result_t
set_value(radio_param_t param, radio_value_t value);
/* Get a radio parameter object. */
static radio_result_t
get_object(radio_param_t param, void *dest, size_t size);
/* Set a radio parameter object. */
static radio_result_t
set_object(radio_param_t param, const void *src, size_t size);
/*---------------------------------------------------------------------------*/
/* The radio driver exported to contiki */
/*---------------------------------------------------------------------------*/
const struct radio_driver cc1200_driver = {
init,
prepare,
transmit,
send,
read,
channel_clear,
receiving_packet,
pending_packet,
on,
off,
get_value,
set_value,
get_object,
set_object
};
/*---------------------------------------------------------------------------*/
/* Prototypes for CC1200 low level function. All of these functions are
called by the radio driver functions or the rx interrupt,
so there is no need to lock SPI within these functions */
/*---------------------------------------------------------------------------*/
/* Send a command strobe. */
static uint8_t
strobe(uint8_t strobe);
/* Reset CC1200. */
static void
reset(void);
/* Write a single byte to the specified address. */
static uint8_t
single_write(uint16_t addr, uint8_t value);
/* Read a single byte from the specified address. */
static uint8_t
single_read(uint16_t addr);
/* Write a burst of bytes starting at the specified address. */
static void
burst_write(uint16_t addr, const uint8_t *data, uint8_t data_len);
/* Read a burst of bytes starting at the specified address. */
static void
burst_read(uint16_t addr, uint8_t *data, uint8_t data_len);
/* Write a list of register settings. */
static void
write_reg_settings(const registerSetting_t *reg_settings,
uint16_t sizeof_reg_settings);
/* Configure the radio (write basic configuration). */
static void
configure(void);
/* Return the radio's state. */
static uint8_t
state(void);
#if !CC1200_AUTOCAL
/* Perform manual calibration. */
static void
calibrate(void);
#endif
/* Enter IDLE state. */
static void
idle(void);
/* Enter RX state. */
static void
idle_calibrate_rx(void);
/* Restart RX from within RX interrupt. */
static void
rx_rx(void);
/* Fill TX FIFO (if not already done), start TX and wait for TX to complete (blocking!). */
static int
idle_tx_rx(const uint8_t *payload, uint16_t payload_len);
/* Update TX power */
static void
update_txpower(int8_t txpower_dbm);
/* Update CCA threshold */
static void
update_cca_threshold(int8_t threshold_dbm);
/* Calculate FREQ register from channel */
static uint32_t
calculate_freq(uint8_t channel);
/* Update rf channel if possible, else postpone it (-> pollhandler). */
static int
set_channel(uint8_t channel);
/* Validate address and send ACK if requested. */
static int
addr_check_auto_ack(uint8_t *frame, uint16_t frame_len);
/*---------------------------------------------------------------------------*/
/* Handle tasks left over from rx interrupt or because SPI was locked */
static void pollhandler(void);
/*---------------------------------------------------------------------------*/
PROCESS(cc1200_process, "CC1200 driver");
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(cc1200_process, ev, data)
{
PROCESS_POLLHANDLER(pollhandler());
PROCESS_BEGIN();
#if CC1200_USE_RX_WATCHDOG
while(1) {
if((rf_flags & (RF_ON | RF_TX_ACTIVE)) == RF_ON) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
etimer_reset(&et);
/*
* We are on and not in TX. As every function of this driver
* assures that we are in RX mode
* (using RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, ...) construct) in
* either rx_rx(), idle_calibrate_rx() or transmit(),
* something probably went wrong in the rx interrupt handler
* if we are not in RX at this point.
*/
if(cc1200_arch_gpio0_read_pin() == 0) {
/*
* GPIO de-asserts as soon as we leave RX for what reason ever. No
* reason to check RX as long as it is asserted (we are receiving a
* packet). We should never interfere with the rx interrupt if we
* check GPIO0 in advance...
*/
LOCK_SPI();
if(state() != STATE_RX) {
WARNING("RF: RX watchdog triggered!\n");
rx_rx();
}
RELEASE_SPI();
}
} else {
PROCESS_YIELD();
}
}
#endif /* #if CC1200_USE_RX_WATCHDOG */
PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_EXIT);
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/* Handle tasks left over from rx interrupt or because SPI was locked */
static void
pollhandler(void)
{
if((rf_flags & (RF_ON + RF_POLL_RX_INTERRUPT)) ==
(RF_ON + RF_POLL_RX_INTERRUPT)) {
cc1200_rx_interrupt();
}
if(rf_flags & RF_UPDATE_CHANNEL) {
/* We couldn't set the channel because we were busy. Try again now. */
set_channel(new_rf_channel);
}
if((rx_mode_value & RADIO_RX_MODE_POLL_MODE) == 0 && rx_pkt_len > 0) {
int len;
/*
* We received a valid packet. CRC was checked before,
* address filtering was performed (if configured)
* and ACK was send (if configured)
*/
packetbuf_clear();
len = read(packetbuf_dataptr(), PACKETBUF_SIZE);
if(len > 0) {
packetbuf_set_datalen(len);
NETSTACK_MAC.input();
}
}
}
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*
* Netstack API radio driver functions
*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Initialize radio. */
static int
init(void)
{
INFO("RF: Init (%s)\n", CC1200_RF_CFG.cfg_descriptor);
if(!(rf_flags & RF_INITIALIZED)) {
LOCK_SPI();
/* Perform low level initialization */
cc1200_arch_init();
/* Configure GPIO interrupts */
SETUP_GPIO_INTERRUPTS();
/* Write initial configuration */
configure();
/* Enable address filtering + auto ack */
rx_mode_value = (RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_ADDRESS_FILTER);
/* Enable CCA */
tx_mode_value = (RADIO_TX_MODE_SEND_ON_CCA);
/* Set output power */
new_txpower = CC1200_RF_CFG.max_txpower;
update_txpower(new_txpower);
/* Adjust CAA threshold */
new_cca_threshold = CC1200_RF_CFG.cca_threshold;
update_cca_threshold(new_cca_threshold);
process_start(&cc1200_process, NULL);
/* We are on + initialized at this point */
rf_flags |= (RF_INITIALIZED + RF_ON);
RELEASE_SPI();
/* Set default channel. This will also force initial calibration! */
set_channel(CC1200_DEFAULT_CHANNEL);
/*
* We have to call off() before on() because on() relies on the
* configuration of the GPIO0 pin
*/
off();
}
return 1;
}
/*---------------------------------------------------------------------------*/
/* Prepare the radio with a packet to be sent. */
static int
prepare(const void *payload, unsigned short payload_len)
{
INFO("RF: Prepare (%d)\n", payload_len);
if((payload_len < ACK_LEN) ||
(payload_len > CC1200_MAX_PAYLOAD_LEN)) {
ERROR("RF: Invalid payload length!\n");
return RADIO_TX_ERR;
}
tx_pkt_len = payload_len;
#if CC1200_WITH_TX_BUF
/* Copy payload to buffer, will be sent later */
memcpy(tx_pkt, payload, tx_pkt_len);
#else /* CC1200_WITH_TX_BUF */
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
#error CC1200 max payload too large
#else
/* Copy header and payload directly to Radio Tx FIFO (127 bytes max) */
copy_header_to_tx_fifo(payload_len);
burst_write(CC1200_TXFIFO, payload, payload_len);
#endif
#endif /* CC1200_WITH_TX_BUF */
return RADIO_TX_OK;
}
/*---------------------------------------------------------------------------*/
/* Prepare the radio with a packet to be sent. */
static int
copy_header_to_tx_fifo(unsigned short payload_len)
{
#if CC1200_802154G
/* Prepare PHR for 802.15.4g frames */
struct {
uint8_t phra;
uint8_t phrb;
} phr;
#if CC1200_802154G_CRC16
payload_len += 2;
#else
payload_len += 4;
#endif
/* Frame length */
phr.phrb = (uint8_t)(payload_len & 0x00FF);
phr.phra = (uint8_t)((payload_len >> 8) & 0x0007);
#if CC1200_802154G_WHITENING
/* Enable Whitening */
phr.phra |= (1 << 3);
#endif /* #if CC1200_802154G_WHITENING */
#if CC1200_802154G_CRC16
/* FCS type 1, 2 Byte CRC */
phr.phra |= (1 << 4);
#endif /* #if CC1200_802154G_CRC16 */
#endif /* #if CC1200_802154G */
idle();
rf_flags &= ~RF_RX_PROCESSING_PKT;
strobe(CC1200_SFRX);
/* Flush TX FIFO */
strobe(CC1200_SFTX);
#if CC1200_802154G
/* Write PHR */
burst_write(CC1200_TXFIFO, (uint8_t *)&phr, PHR_LEN);
#else
/* Write length byte */
burst_write(CC1200_TXFIFO, (uint8_t *)&payload_len, PHR_LEN);
#endif /* #if CC1200_802154G */
return 0;
}
/*---------------------------------------------------------------------------*/
/* Send the packet that has previously been prepared. */
static int
transmit(unsigned short transmit_len)
{
uint8_t was_off = 0;
int ret = RADIO_TX_OK;
int txret;
INFO("RF: Transmit (%d)\n", transmit_len);
if(transmit_len != tx_pkt_len) {
ERROR("RF: TX length mismatch!\n");
return RADIO_TX_ERR;
}
/* TX ongoing. Inhibit channel update & ACK as soon as possible */
rf_flags |= RF_TX_ACTIVE;
if(!(rf_flags & RF_ON)) {
/* Radio is off - turn it on */
was_off = 1;
on();
/* Radio is in RX now (and calibrated...) */
}
if(tx_mode_value & RADIO_TX_MODE_SEND_ON_CCA) {
/* Perform clear channel assessment */
if(!channel_clear()) {
/* Channel occupied */
if(was_off) {
off();
}
rf_flags &= ~RF_TX_ACTIVE;
return RADIO_TX_COLLISION;
}
}
/*
* Lock SPI here because "on()" and "channel_clear()"
* won't work if SPI is locked!
*/
LOCK_SPI();
/*
* Make sure we start from a sane state. idle() also disables
* the GPIO interrupt(s).
*/
idle();
/* Update output power */
if(new_txpower != txpower) {
update_txpower(new_txpower);
}
#if !CC1200_AUTOCAL
/* Perform manual calibration unless just turned on */
if(!was_off) {
calibrate();
}
#endif
/* Send data using TX FIFO */
#if CC1200_WITH_TX_BUF
txret = idle_tx_rx(tx_pkt, tx_pkt_len);
#else /* CC1200_WITH_TX_BUF */
txret = idle_tx_rx(NULL, tx_pkt_len);
#endif /* CC1200_WITH_TX_BUF */
if(txret == RADIO_TX_OK) {
/*
* TXOFF_MODE is set to RX,
* let's wait until we are in RX and turn on the GPIO IRQs
* again as they were turned off in idle()
*/
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX,
CC1200_RF_CFG.tx_rx_turnaround);
ENABLE_GPIO_INTERRUPTS();
} else {
/*
* Something went wrong during TX, idle_tx_rx() returns in IDLE
* state in this case.
* Turn on RX again unless we turn off anyway
*/
ret = RADIO_TX_ERR;
if(!was_off) {
#ifdef RF_FORCE_CALIBRATION
rf_flags |= RF_FORCE_CALIBRATION;
#endif
idle_calibrate_rx();
}
}
/* Release SPI here because "off()" won't work if SPI is locked! */
RELEASE_SPI();
if(was_off) {
off();
}
/* TX completed */
rf_flags &= ~RF_TX_ACTIVE;
return ret;
}
/*---------------------------------------------------------------------------*/
/* Prepare & transmit a packet. */
static int
send(const void *payload, unsigned short payload_len)
{
int ret;
INFO("RF: Send (%d)\n", payload_len);
/* payload_len checked within prepare() */
if((ret = prepare(payload, payload_len)) == RADIO_TX_OK) {
ret = transmit(payload_len);
}
return ret;
}
/*---------------------------------------------------------------------------*/
/* Read a received packet into a buffer. */
static int
read(void *buf, unsigned short buf_len)
{
int len = 0;
if(rx_pkt_len > 0) {
rssi = (int8_t)rx_pkt[rx_pkt_len - 2] + (int)CC1200_RF_CFG.rssi_offset;
/* CRC is already checked */
uint8_t crc_lqi = rx_pkt[rx_pkt_len - 1];
len = rx_pkt_len - APPENDIX_LEN;
if(len > buf_len) {
ERROR("RF: Failed to read packet (too big)!\n");
} else {
INFO("RF: Read (%d bytes, %d dBm)\n", len, rssi);
memcpy((void *)buf, (const void *)rx_pkt, len);
/* Release rx_pkt */
rx_pkt_len = 0;
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
/* Mask out CRC bit */
packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY,
crc_lqi & ~(1 << 7));
}
}
return len;
}
/*---------------------------------------------------------------------------*/
/*
* Perform a Clear-Channel Assessment (CCA) to find out if there is a
* packet in the air or not.
*/
static int
channel_clear(void)
{
uint8_t cca, was_off = 0;
if(SPI_IS_LOCKED()) {
/* Probably locked in rx interrupt. Return "channel occupied" */
return 0;
}
if(!(rf_flags & RF_ON)) {
/* We are off */
was_off = 1;
on();
}
LOCK_SPI();
RF_ASSERT(state() == STATE_RX);
/*
* At this point we should be in RX. If GPIO0 is set, we are currently
* receiving a packet, no need to check the RSSI. Or is there any situation
* when we want access the channel even if we are currently receiving a
* packet???
*/
if(cc1200_arch_gpio0_read_pin() == 1) {
/* Channel occupied */
INFO("RF: CCA (0)\n");
cca = 0;
} else {
uint8_t rssi0;
/* Update CCA threshold */
if(new_cca_threshold != cca_threshold) {
update_cca_threshold(new_cca_threshold);
}
/* Wait for CARRIER_SENSE_VALID signal */
RTIMER_BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0))
& CC1200_CARRIER_SENSE_VALID),
RTIMER_SECOND / 100);
RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID);
if(rssi0 & CC1200_CARRIER_SENSE) {
/* Channel occupied */
INFO("RF: CCA (0)\n");
cca = 0;
} else {
/* Channel clear */
INFO("RF: CCA (1)\n");
cca = 1;
}
}
RELEASE_SPI();
if(was_off) {
off();
}
return cca;
}
/*---------------------------------------------------------------------------*/
/*
* Check if the radio driver is currently receiving a packet.
*
* CSMA uses this function
* - to detect a collision before transmit()
* - to detect an incoming ACK
*/
static int
receiving_packet(void)
{
int ret = 0;
if((rf_flags & (RF_ON | RF_TX_ACTIVE)) == RF_ON) {
/* We are on and not in TX */
if((cc1200_arch_gpio0_read_pin() == 1) || (rx_pkt_len != 0)) {
/*
* SYNC word found or packet just received. Changing the criteria
* for this event might make it necessary to review the MAC timing
* parameters! Instead of (or in addition to) using GPIO0 we could also
* read out MODEM_STATUS1 (e.g. PQT reached), but this would not change
* the situation at least for CSMA as it uses two "blocking" timers
* (does not perform polling...). Therefore the overall timing
* of the ACK handling wouldn't change. It would just allow to detect an
* incoming packet a little bit earlier and help us with respect to
* collision avoidance (why not use channel_clear()
* at this point?).
*/
ret = 1;
}
}
INFO("RF: Receiving (%d)\n", ret);
return ret;
}
/*---------------------------------------------------------------------------*/
/* Check if the radio driver has just received a packet. */
static int
pending_packet(void)
{
int ret;
ret = ((rx_pkt_len != 0) ? 1 : 0);
if(ret == 0 && !SPI_IS_LOCKED()) {
LOCK_SPI();
ret = (single_read(CC1200_NUM_RXBYTES) > 0);
RELEASE_SPI();
}
INFO("RF: Pending (%d)\n", ret);
return ret;
}
/*---------------------------------------------------------------------------*/
/* Turn the radio on. */
static int
on(void)
{
INFO("RF: On\n");
/* Don't turn on if we are on already */
if(!(rf_flags & RF_ON)) {
if(SPI_IS_LOCKED()) {
return 0;
}
LOCK_SPI();
/* Wake-up procedure. Wait for GPIO0 to de-assert (CHIP_RDYn) */
cc1200_arch_spi_select();
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
RTIMER_SECOND / 100);
RF_ASSERT((cc1200_arch_gpio0_read_pin() == 0));
cc1200_arch_spi_deselect();
rf_flags = RF_INITIALIZED;
rf_flags |= RF_ON;
/* Radio is IDLE now, re-configure GPIO0 (modified inside off()) */
single_write(CC1200_IOCFG0, GPIO0_IOCFG);
/* Turn on RX */
idle_calibrate_rx();
RELEASE_SPI();
#if CC1200_USE_RX_WATCHDOG
PROCESS_CONTEXT_BEGIN(&cc1200_process);
etimer_set(&et, CLOCK_SECOND);
PROCESS_CONTEXT_END(&cc1200_process);
#endif /* #if CC1200_USE_RX_WATCHDOG */
} else {
INFO("RF: Already on\n");
}
return 1;
}
/*---------------------------------------------------------------------------*/
/* Turn the radio off. */
static int
off(void)
{
INFO("RF: Off\n");
/* Don't turn off if we are off already */
if(rf_flags & RF_ON) {
if(SPI_IS_LOCKED()) {
return 0;
}
LOCK_SPI();
idle();
if(single_read(CC1200_NUM_RXBYTES) > 0) {
RELEASE_SPI();
/* In case there is something in the Rx FIFO, read it */
cc1200_rx_interrupt();
if(SPI_IS_LOCKED()) {
return 0;
}
LOCK_SPI();
}
/*
* As we use GPIO as CHIP_RDYn signal on wake-up / on(),
* we re-configure it for CHIP_RDYn.
*/
single_write(CC1200_IOCFG0, CC1200_IOCFG_RXFIFO_CHIP_RDY_N);
/* Say goodbye ... */
strobe(CC1200_SPWD);
/* Clear all but the initialized flag */
rf_flags = RF_INITIALIZED;
RELEASE_SPI();
#if CC1200_USE_RX_WATCHDOG
etimer_stop(&et);
#endif /* #if CC1200_USE_RX_WATCHDOG */
} else {
INFO("RF: Already off\n");
}
return 1;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Reads the current signal strength (RSSI)
* \return The current RSSI in dBm
*
* This function reads the current RSSI on the currently configured
* channel.
*/
static int16_t
get_rssi(void)
{
int16_t rssi0, rssi1;
uint8_t was_off = 0;
/* If we are off, turn on first */
if(!(rf_flags & RF_ON)) {
was_off = 1;
on();
}
/* Wait for CARRIER_SENSE_VALID signal */
RTIMER_BUSYWAIT_UNTIL(((rssi0 = single_read(CC1200_RSSI0))
& CC1200_CARRIER_SENSE_VALID),
RTIMER_SECOND / 100);
RF_ASSERT(rssi0 & CC1200_CARRIER_SENSE_VALID);
rssi1 = (int8_t)single_read(CC1200_RSSI1) + (int)CC1200_RF_CFG.rssi_offset;
/* If we were off, turn back off */
if(was_off) {
off();
}
return rssi1;
}
/*---------------------------------------------------------------------------*/
/* Get a radio parameter value. */
static radio_result_t
get_value(radio_param_t param, radio_value_t *value)
{
if(!value) {
return RADIO_RESULT_INVALID_VALUE;
}
switch(param) {
case RADIO_PARAM_POWER_MODE:
if(rf_flags & RF_ON) {
*value = (radio_value_t)RADIO_POWER_MODE_ON;
} else {
*value = (radio_value_t)RADIO_POWER_MODE_OFF;
}
return RADIO_RESULT_OK;
case RADIO_PARAM_CHANNEL:
*value = (radio_value_t)rf_channel;
return RADIO_RESULT_OK;
case RADIO_PARAM_PAN_ID:
case RADIO_PARAM_16BIT_ADDR:
return RADIO_RESULT_NOT_SUPPORTED;
case RADIO_PARAM_RX_MODE:
*value = (radio_value_t)rx_mode_value;
return RADIO_RESULT_OK;
case RADIO_PARAM_TX_MODE:
*value = (radio_value_t)tx_mode_value;
return RADIO_RESULT_OK;
case RADIO_PARAM_TXPOWER:
*value = (radio_value_t)txpower;
return RADIO_RESULT_OK;
case RADIO_PARAM_CCA_THRESHOLD:
*value = (radio_value_t)cca_threshold;
return RADIO_RESULT_OK;
case RADIO_PARAM_RSSI:
*value = get_rssi();
return RADIO_RESULT_OK;
case RADIO_PARAM_LAST_RSSI:
*value = (radio_value_t)rssi;
return RADIO_RESULT_OK;
case RADIO_PARAM_64BIT_ADDR:
return RADIO_RESULT_NOT_SUPPORTED;
case RADIO_CONST_CHANNEL_MIN:
*value = (radio_value_t)CC1200_RF_CFG.min_channel;
return RADIO_RESULT_OK;
case RADIO_CONST_CHANNEL_MAX:
*value = (radio_value_t)CC1200_RF_CFG.max_channel;
return RADIO_RESULT_OK;
case RADIO_CONST_TXPOWER_MIN:
*value = (radio_value_t)CC1200_CONST_TX_POWER_MIN;
return RADIO_RESULT_OK;
case RADIO_CONST_TXPOWER_MAX:
*value = (radio_value_t)CC1200_RF_CFG.max_txpower;
return RADIO_RESULT_OK;
case RADIO_CONST_PHY_OVERHEAD:
#if CC1200_802154G
#if CC1200_802154G_CRC16
*value = (radio_value_t)4; /* 2 bytes PHR, 2 bytes CRC */
#else
*value = (radio_value_t)6; /* 2 bytes PHR, 4 bytes CRC */
#endif
#else
*value = (radio_value_t)3; /* 1 len byte, 2 bytes CRC */
#endif
return RADIO_RESULT_OK;
case RADIO_CONST_BYTE_AIR_TIME:
*value = (radio_value_t)8*1000*1000 / CC1200_RF_CFG.bitrate;
return RADIO_RESULT_OK;
case RADIO_CONST_DELAY_BEFORE_TX:
*value = (radio_value_t)CC1200_RF_CFG.delay_before_tx;
return RADIO_RESULT_OK;
case RADIO_CONST_DELAY_BEFORE_RX:
*value = (radio_value_t)CC1200_RF_CFG.delay_before_rx;
return RADIO_RESULT_OK;
case RADIO_CONST_DELAY_BEFORE_DETECT:
*value = (radio_value_t)CC1200_RF_CFG.delay_before_detect;
return RADIO_RESULT_OK;
default:
return RADIO_RESULT_NOT_SUPPORTED;
}
}
/*---------------------------------------------------------------------------*/
/* Set a radio parameter value. */
static radio_result_t
set_value(radio_param_t param, radio_value_t value)
{
switch(param) {
case RADIO_PARAM_POWER_MODE:
if(value == RADIO_POWER_MODE_ON) {
on();
return RADIO_RESULT_OK;
}
if(value == RADIO_POWER_MODE_OFF) {
off();
return RADIO_RESULT_OK;
}
return RADIO_RESULT_INVALID_VALUE;
case RADIO_PARAM_CHANNEL:
if(set_channel(value) == CHANNEL_OUT_OF_LIMITS) {
return RADIO_RESULT_INVALID_VALUE;
}
/*
* We always return OK here even if the channel update was
* postponed. rf_channel is NOT updated in this case until
* the channel update was performed. So reading back
* the channel using get_value() might return the "old" channel
* until the channel was actually changed
*/
return RADIO_RESULT_OK;
case RADIO_PARAM_PAN_ID:
case RADIO_PARAM_16BIT_ADDR:
return RADIO_RESULT_NOT_SUPPORTED;
case RADIO_PARAM_RX_MODE:
rx_mode_value = value;
return RADIO_RESULT_OK;
case RADIO_PARAM_TX_MODE:
tx_mode_value = value;
return RADIO_RESULT_OK;
case RADIO_PARAM_TXPOWER:
if(value > (radio_value_t)CC1200_RF_CFG.max_txpower) {
value = (radio_value_t)CC1200_RF_CFG.max_txpower;
}
if(value < (radio_value_t)CC1200_CONST_TX_POWER_MIN) {
value = (radio_value_t)CC1200_CONST_TX_POWER_MIN;
}
/* We update the output power as soon as we transmit the next packet */
new_txpower = (int8_t)value;
return RADIO_RESULT_OK;
case RADIO_PARAM_CCA_THRESHOLD:
if(value > (radio_value_t)CC1200_CONST_CCA_THRESHOLD_MAX) {
value = (radio_value_t)CC1200_CONST_CCA_THRESHOLD_MAX;
}
if(value < (radio_value_t)CC1200_CONST_CCA_THRESHOLD_MIN) {
value = (radio_value_t)CC1200_CONST_CCA_THRESHOLD_MIN;
}
/* When to update the threshold? Let's do it in channel_clear() ... */
new_cca_threshold = (int8_t)value;
return RADIO_RESULT_OK;
case RADIO_PARAM_RSSI:
case RADIO_PARAM_64BIT_ADDR:
default:
return RADIO_RESULT_NOT_SUPPORTED;
}
}
/*---------------------------------------------------------------------------*/
/* Get a radio parameter object. */
static radio_result_t
get_object(radio_param_t param, void *dest, size_t size)
{
if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
if(size != sizeof(rtimer_clock_t) || !dest) {
return RADIO_RESULT_INVALID_VALUE;
}
*(rtimer_clock_t *)dest = sfd_timestamp;
return RADIO_RESULT_OK;
}
#if MAC_CONF_WITH_TSCH
if(param == RADIO_CONST_TSCH_TIMING) {
if(size != sizeof(uint16_t *) || !dest) {
return RADIO_RESULT_INVALID_VALUE;
}
*(const uint16_t **)dest = CC1200_RF_CFG.tsch_timing;
return RADIO_RESULT_OK;
}
#endif /* MAC_CONF_WITH_TSCH */
return RADIO_RESULT_NOT_SUPPORTED;
}
/*---------------------------------------------------------------------------*/
/* Set a radio parameter object. */
static radio_result_t
set_object(radio_param_t param, const void *src, size_t size)
{
return RADIO_RESULT_NOT_SUPPORTED;
}
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*
* CC1200 low level functions
*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Send a command strobe. */
static uint8_t
strobe(uint8_t strobe)
{
uint8_t ret;
cc1200_arch_spi_select();
ret = cc1200_arch_spi_rw_byte(strobe);
cc1200_arch_spi_deselect();
return ret;
}
/*---------------------------------------------------------------------------*/
/* Reset CC1200. */
static void
reset(void)
{
cc1200_arch_spi_select();
cc1200_arch_spi_rw_byte(CC1200_SRES);
/*
* Here we should wait for SO to go low again.
* As we don't have access to this pin we just wait for 100µs.
*/
clock_delay(100);
cc1200_arch_spi_deselect();
}
/*---------------------------------------------------------------------------*/
/* Write a single byte to the specified address. */
static uint8_t
single_write(uint16_t addr, uint8_t val)
{
uint8_t ret;
cc1200_arch_spi_select();
if(CC1200_IS_EXTENDED_ADDR(addr)) {
cc1200_arch_spi_rw_byte(CC1200_EXTENDED_WRITE_CMD);
cc1200_arch_spi_rw_byte((uint8_t)addr);
} else {
cc1200_arch_spi_rw_byte(addr | CC1200_WRITE_BIT);
}
ret = cc1200_arch_spi_rw_byte(val);
cc1200_arch_spi_deselect();
return ret;
}
/*---------------------------------------------------------------------------*/
/* Read a single byte from the specified address. */
static uint8_t
single_read(uint16_t addr)
{
uint8_t ret;
cc1200_arch_spi_select();
if(CC1200_IS_EXTENDED_ADDR(addr)) {
cc1200_arch_spi_rw_byte(CC1200_EXTENDED_READ_CMD);
cc1200_arch_spi_rw_byte((uint8_t)addr);
} else {
cc1200_arch_spi_rw_byte(addr | CC1200_READ_BIT);
}
ret = cc1200_arch_spi_rw_byte(0);
cc1200_arch_spi_deselect();
return ret;
}
/*---------------------------------------------------------------------------*/
/* Write a burst of bytes starting at the specified address. */
static void
burst_write(uint16_t addr, const uint8_t *data, uint8_t data_len)
{
cc1200_arch_spi_select();
if(CC1200_IS_EXTENDED_ADDR(addr)) {
cc1200_arch_spi_rw_byte(CC1200_EXTENDED_BURST_WRITE_CMD);
cc1200_arch_spi_rw_byte((uint8_t)addr);
} else {
cc1200_arch_spi_rw_byte(addr | CC1200_WRITE_BIT | CC1200_BURST_BIT);
}
cc1200_arch_spi_rw(NULL, data, data_len);
cc1200_arch_spi_deselect();
}
/*---------------------------------------------------------------------------*/
/* Read a burst of bytes starting at the specified address. */
static void
burst_read(uint16_t addr, uint8_t *data, uint8_t data_len)
{
cc1200_arch_spi_select();
if(CC1200_IS_EXTENDED_ADDR(addr)) {
cc1200_arch_spi_rw_byte(CC1200_EXTENDED_BURST_READ_CMD);
cc1200_arch_spi_rw_byte((uint8_t)addr);
} else {
cc1200_arch_spi_rw_byte(addr | CC1200_READ_BIT | CC1200_BURST_BIT);
}
cc1200_arch_spi_rw(data, NULL, data_len);
cc1200_arch_spi_deselect();
}
/*---------------------------------------------------------------------------*/
/* Write a list of register settings. */
static void
write_reg_settings(const registerSetting_t *reg_settings,
uint16_t sizeof_reg_settings)
{
int i = sizeof_reg_settings / sizeof(registerSetting_t);
if(reg_settings != NULL) {
while(i--) {
single_write(reg_settings->addr,
reg_settings->val);
reg_settings++;
}
}
}
/*---------------------------------------------------------------------------*/
/* Configure the radio (write basic configuration). */
static void
configure(void)
{
uint8_t reg;
#if CC1200_RF_TESTMODE
uint32_t freq;
#endif
/*
* As we only write registers which are different from the chip's reset
* state, let's assure that the chip is in a clean state
*/
reset();
/* Write the configuration as exported from SmartRF Studio */
write_reg_settings(CC1200_RF_CFG.register_settings,
CC1200_RF_CFG.size_of_register_settings);
/* Write frequency offset */
#if CC1200_FREQ_OFFSET
/* MSB */
single_write(CC1200_FREQOFF1, (uint8_t)(CC1200_FREQ_OFFSET >> 8));
/* LSB */
single_write(CC1200_FREQOFF0, (uint8_t)(CC1200_FREQ_OFFSET));
#endif
/* RSSI offset */
single_write(CC1200_AGC_GAIN_ADJUST, (int8_t)CC1200_RF_CFG.rssi_offset);
/***************************************************************************
* RF test modes needed during hardware development
**************************************************************************/
#if (CC1200_RF_TESTMODE == 1) || (CC1200_RF_TESTMODE == 2)
strobe(CC1200_SFTX);
single_write(CC1200_TXFIRST, 0);
single_write(CC1200_TXLAST, 0xFF);
update_txpower(CC1200_CONST_TX_POWER_MAX);
single_write(CC1200_PKT_CFG2, 0x02);
freq = calculate_freq(CC1200_DEFAULT_CHANNEL - CC1200_RF_CFG.min_channel);
single_write(CC1200_FREQ0, ((uint8_t *)&freq)[0]);
single_write(CC1200_FREQ1, ((uint8_t *)&freq)[1]);
single_write(CC1200_FREQ2, ((uint8_t *)&freq)[2]);
printf("RF: Freq0 0x%02x\n", ((uint8_t *)&freq)[0]);
printf("RF: Freq1 0x%02x\n", ((uint8_t *)&freq)[1]);
printf("RF: Freq2 0x%02x\n", ((uint8_t *)&freq)[2]);
#if (CC1200_RF_TESTMODE == 1)
single_write(CC1200_SYNC_CFG1, 0xE8);
single_write(CC1200_PREAMBLE_CFG1, 0x00);
single_write(CC1200_MDMCFG1, 0x46);
single_write(CC1200_PKT_CFG0, 0x40);
single_write(CC1200_FS_DIG1, 0x07);
single_write(CC1200_FS_DIG0, 0xAA);
single_write(CC1200_FS_DVC1, 0xFF);
single_write(CC1200_FS_DVC0, 0x17);
#endif
#if (CC1200_RF_TESTMODE == 2)
single_write(CC1200_SYNC_CFG1, 0xE8);
single_write(CC1200_PREAMBLE_CFG1, 0x00);
single_write(CC1200_MDMCFG1, 0x06);
single_write(CC1200_PA_CFG1, 0x3F);
single_write(CC1200_MDMCFG2, 0x03);
single_write(CC1200_FS_DIG1, 0x07);
single_write(CC1200_FS_DIG0, 0xAA);
single_write(CC1200_FS_DVC0, 0x17);
single_write(CC1200_SERIAL_STATUS, 0x08);
#endif
strobe(CC1200_STX);
while(1) {
#if (CC1200_RF_TESTMODE == 1)
watchdog_periodic();
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_YELLOW);
leds_on(LEDS_RED);
watchdog_periodic();
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_RED);
leds_on(LEDS_YELLOW);
#else
watchdog_periodic();
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_GREEN);
leds_on(LEDS_RED);
watchdog_periodic();
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_RED);
leds_on(LEDS_GREEN);
#endif
}
#elif (CC1200_RF_TESTMODE == 3)
/* CS on GPIO3 */
single_write(CC1200_IOCFG3, CC1200_IOCFG_CARRIER_SENSE);
single_write(CC1200_IOCFG2, CC1200_IOCFG_SERIAL_CLK);
single_write(CC1200_IOCFG0, CC1200_IOCFG_SERIAL_RX);
update_cca_threshold(CC1200_RF_CFG.cca_threshold);
freq = calculate_freq(CC1200_DEFAULT_CHANNEL - CC1200_RF_CFG.min_channel);
single_write(CC1200_FREQ0, ((uint8_t *)&freq)[0]);
single_write(CC1200_FREQ1, ((uint8_t *)&freq)[1]);
single_write(CC1200_FREQ2, ((uint8_t *)&freq)[2]);
strobe(CC1200_SRX);
while(1) {
watchdog_periodic();
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_GREEN);
leds_on(LEDS_YELLOW);
watchdog_periodic();
RTIMER_BUSYWAIT(RTIMER_SECOND / 10);
leds_off(LEDS_YELLOW);
leds_on(LEDS_GREEN);
clock_delay_usec(1000);
/* CS on GPIO3 */
if(cc1200_arch_gpio3_read_pin() == 1) {
leds_on(LEDS_RED);
} else {
leds_off(LEDS_RED);
}
}
#endif /* #if CC1200_RF_TESTMODE == ... */
/***************************************************************************
* Set the stuff we need for this driver to work. Don't touch!
**************************************************************************/
/* GPIOx configuration */
single_write(CC1200_IOCFG3, GPIO3_IOCFG);
single_write(CC1200_IOCFG2, GPIO2_IOCFG);
single_write(CC1200_IOCFG0, GPIO0_IOCFG);
reg = single_read(CC1200_SETTLING_CFG);
/*
* Turn of auto calibration. This gives us better control
* over the timing (RX/TX & TX /RX turnaround!). We calibrate manually:
* - Upon wake-up (on())
* - Before going to TX (transmit())
* - When setting an new channel (set_channel())
*/
reg &= ~(3 << 3);
#if CC1200_AUTOCAL
/* We calibrate when going from idle to RX or TX */
reg |= (1 << 3);
#endif
single_write(CC1200_SETTLING_CFG, reg);
/* Configure RXOFF_MODE */
reg = single_read(CC1200_RFEND_CFG1);
reg &= ~(3 << 4); /* RXOFF_MODE = IDLE */
#if RXOFF_MODE_RX
reg |= (3 << 4); /* RXOFF_MODE = RX */
#endif
reg |= 0x0F; /* Disable RX timeout */
single_write(CC1200_RFEND_CFG1, reg);
/* Configure TXOFF_MODE */
reg = single_read(CC1200_RFEND_CFG0);
reg &= ~(3 << 4); /* TXOFF_MODE = IDLE */
#if TXOFF_MODE_RX
reg |= (3 << 4); /* TXOFF_MODE = RX */
#endif
single_write(CC1200_RFEND_CFG0, reg);
/*
* CCA Mode 0: Always give clear channel indication.
* CCA is done "by hand". Keep in mind: automatic CCA would also
* affect the transmission of the ACK and is not implemented yet!
*/
#if CC1200_802154G
single_write(CC1200_PKT_CFG2, (1 << 5));
#else
single_write(CC1200_PKT_CFG2, 0x00);
#endif
/* Configure appendix */
reg = single_read(CC1200_PKT_CFG1);
#if APPEND_STATUS
reg |= (1 << 0);
#else
reg &= ~(1 << 0);
#endif
single_write(CC1200_PKT_CFG1, reg);
/* Variable packet length mode */
reg = single_read(CC1200_PKT_CFG0);
reg &= ~(3 << 5);
reg |= (1 << 5);
single_write(CC1200_PKT_CFG0, reg);
#ifdef FIFO_THRESHOLD
/* FIFO threshold */
single_write(CC1200_FIFO_CFG, FIFO_THRESHOLD);
#endif
}
/*---------------------------------------------------------------------------*/
/* Return the radio's state. */
static uint8_t
state(void)
{
#if STATE_USES_MARC_STATE
return single_read(CC1200_MARCSTATE) & 0x1f;
#else
return strobe(CC1200_SNOP) & 0x70;
#endif
}
/*---------------------------------------------------------------------------*/
#if !CC1200_AUTOCAL
/* Perform manual calibration. */
static void
calibrate(void)
{
#ifdef RF_FORCE_CALIBRATION
if (!(rf_flags & RF_FORCE_CALIBRATION)
&& ((clock_seconds() - cal_timer) < CC1200_CAL_TIMEOUT_SECONDS)) {
/* Timeout not reached, defer calibration... */
return;
}
rf_flags &= ~RF_FORCE_CALIBRATION;
#endif
INFO("RF: Calibrate\n");
strobe(CC1200_SCAL);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_CALIBRATE, RTIMER_SECOND / 100);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
#if CC1200_CAL_TIMEOUT_SECONDS
cal_timer = clock_seconds();
#endif
}
#endif
/*---------------------------------------------------------------------------*/
/* Enter IDLE state. */
static void
idle(void)
{
uint8_t s;
DISABLE_GPIO_INTERRUPTS();
TX_LEDS_OFF();
RX_LEDS_OFF();
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
s = state();
if(s == STATE_IDLE) {
return;
} else if(s == STATE_RX_FIFO_ERR) {
WARNING("RF: RX FIFO error!\n");
strobe(CC1200_SFRX);
} else if(s == STATE_TX_FIFO_ERR) {
WARNING("RF: TX FIFO error!\n");
strobe(CC1200_SFTX);
}
strobe(CC1200_SIDLE);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE, RTIMER_SECOND / 100);
} /* idle(), 21.05.2015 */
/*---------------------------------------------------------------------------*/
/* Enter RX state. */
static void
idle_calibrate_rx(void)
{
RF_ASSERT(state() == STATE_IDLE);
#if !CC1200_AUTOCAL
calibrate();
#endif
rf_flags &= ~RF_RX_PROCESSING_PKT;
strobe(CC1200_SFRX);
strobe(CC1200_SRX);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
ENABLE_GPIO_INTERRUPTS();
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
}
/*---------------------------------------------------------------------------*/
/* Restart RX from within RX interrupt. */
static void
rx_rx(void)
{
uint8_t s = state();
if(s == STATE_IDLE) {
/* Proceed to rx */
} else if(s == STATE_RX_FIFO_ERR) {
WARNING("RF: RX FIFO error!\n");
strobe(CC1200_SFRX);
} else if(s == STATE_TX_FIFO_ERR) {
WARNING("RF: TX FIFO error!\n");
strobe(CC1200_SFTX);
} else {
strobe(CC1200_SIDLE);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_IDLE,
RTIMER_SECOND / 100);
}
RX_LEDS_OFF();
rf_flags &= ~RF_RX_PROCESSING_PKT;
/* Clear pending GPIO interrupts */
ENABLE_GPIO_INTERRUPTS();
strobe(CC1200_SFRX);
strobe(CC1200_SRX);
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_RX, RTIMER_SECOND / 100);
}
/*---------------------------------------------------------------------------*/
/* Fill TX FIFO (if not already done), start TX and wait for TX to complete (blocking!). */
static int
idle_tx_rx(const uint8_t *payload, uint16_t payload_len)
{
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
uint8_t to_write;
const uint8_t *p;
#endif
/* Prepare for RX */
rf_flags &= ~RF_RX_PROCESSING_PKT;
strobe(CC1200_SFRX);
/* Configure GPIO0 to detect TX state */
single_write(CC1200_IOCFG0, CC1200_IOCFG_MARC_2PIN_STATUS_0);
#if CC1200_WITH_TX_BUF
/* Prepare and write header */
copy_header_to_tx_fifo(payload_len);
/*
* Fill FIFO with data. If SPI is slow it might make sense
* to divide this process into several chunks.
* The best solution would be to perform TX FIFO refill
* using an interrupt, but we are blocking here (= in TX) anyway...
*/
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
to_write = MIN(payload_len, (CC1200_FIFO_SIZE - PHR_LEN));
burst_write(CC1200_TXFIFO, payload, to_write);
bytes_left_to_write = payload_len - to_write;
p = payload + to_write;
#else
burst_write(CC1200_TXFIFO, payload, payload_len);
#endif
#endif /* CC1200_WITH_TX_BUF */
#if USE_SFSTXON
/* Wait for synthesizer to be ready */
RTIMER_BUSYWAIT_UNTIL_STATE(STATE_FSTXON, RTIMER_SECOND / 100);
#endif
/* Start TX */
strobe(CC1200_STX);
/* Wait for TX to start. */
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 1), RTIMER_SECOND / 100);
/* Turned off at the latest in idle() */
TX_LEDS_ON();
/* Turned off at the latest in idle() */
ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
if((cc1200_arch_gpio0_read_pin() == 0) &&
(single_read(CC1200_NUM_TXBYTES) != 0)) {
/*
* TX didn't start in time. We also check NUM_TXBYES
* in case we missed the rising edge of the GPIO signal
*/
ERROR("RF: TX doesn't start!\n");
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
single_write(CC1200_IOCFG2, GPIO2_IOCFG);
#endif
idle();
/* Re-configure GPIO0 */
single_write(CC1200_IOCFG0, GPIO0_IOCFG);
return RADIO_TX_ERR;
}
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN)) && CC1200_WITH_TX_BUF
if(bytes_left_to_write != 0) {
rtimer_clock_t t0;
uint8_t s;
t0 = RTIMER_NOW();
do {
if((bytes_left_to_write != 0) &&
(cc1200_arch_gpio2_read_pin() == 0)) {
/* TX TIFO is drained below FIFO_THRESHOLD. Re-fill... */
to_write = MIN(bytes_left_to_write, FIFO_THRESHOLD);
burst_write(CC1200_TXFIFO, p, to_write);
bytes_left_to_write -= to_write;
p += to_write;
t0 += CC1200_RF_CFG.tx_pkt_lifetime;
}
} while((cc1200_arch_gpio0_read_pin() == 1) &&
RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CC1200_RF_CFG.tx_pkt_lifetime));
/*
* At this point we either left TX or a timeout occurred. If all went
* well, we are in RX (or at least settling) now.
* If we didn't manage to refill the TX FIFO, an underflow might
* have occur-ed - the radio might be still in TX here!
*/
s = state();
if((s != STATE_RX) && (s != STATE_SETTLING)) {
/*
* Something bad happened. Wait for radio to enter a
* stable state (in case of an error we are in TX here)
*/
INFO("RF: TX failure!\n");
RTIMER_BUSYWAIT_UNTIL((state() != STATE_TX), RTIMER_SECOND / 100);
/* Re-configure GPIO2 */
single_write(CC1200_IOCFG2, GPIO2_IOCFG);
idle();
/* Re-configure GPIO0 */
single_write(CC1200_IOCFG0, GPIO0_IOCFG);
return RADIO_TX_ERR;
}
} else {
/* Wait for TX to complete */
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
CC1200_RF_CFG.tx_pkt_lifetime);
}
#else
/* Wait for TX to complete */
RTIMER_BUSYWAIT_UNTIL((cc1200_arch_gpio0_read_pin() == 0),
CC1200_RF_CFG.tx_pkt_lifetime);
#endif
if(cc1200_arch_gpio0_read_pin() == 1) {
/* TX takes to long - abort */
ERROR("RF: TX takes to long!\n");
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
/* Re-configure GPIO2 */
single_write(CC1200_IOCFG2, GPIO2_IOCFG);
#endif
idle();
/* Re-configure GPIO0 */
single_write(CC1200_IOCFG0, GPIO0_IOCFG);
return RADIO_TX_ERR;
}
#if (CC1200_MAX_PAYLOAD_LEN > (CC1200_FIFO_SIZE - PHR_LEN))
/* Re-configure GPIO2 */
single_write(CC1200_IOCFG2, GPIO2_IOCFG);
#endif
/* Re-configure GPIO0 */
single_write(CC1200_IOCFG0, GPIO0_IOCFG);
TX_LEDS_OFF();
ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
return RADIO_TX_OK;
}
/*---------------------------------------------------------------------------*/
/* Update TX power */
static void
update_txpower(int8_t txpower_dbm)
{
uint8_t reg = single_read(CC1200_PA_CFG1);
reg &= ~0x3F;
/* Up to now we don't handle the special power levels PA_POWER_RAMP < 3 */
reg |= ((((txpower_dbm + 18) * 2) - 1) & 0x3F);
single_write(CC1200_PA_CFG1, reg);
txpower = txpower_dbm;
}
/*---------------------------------------------------------------------------*/
/* Update CCA threshold */
static void
update_cca_threshold(int8_t threshold_dbm)
{
single_write(CC1200_AGC_CS_THR, (uint8_t)threshold_dbm);
cca_threshold = threshold_dbm;
}
/*---------------------------------------------------------------------------*/
/* Calculate FREQ register from channel */
static uint32_t
calculate_freq(uint8_t channel)
{
uint32_t freq;
freq = CC1200_RF_CFG.chan_center_freq0 + (channel * CC1200_RF_CFG.chan_spacing) / 1000 /* /1000 because chan_spacing is in Hz */;
freq *= FREQ_MULTIPLIER;
freq /= FREQ_DIVIDER;
return freq;
}
/*---------------------------------------------------------------------------*/
/* Update rf channel if possible, else postpone it (->pollhandler) */
static int
set_channel(uint8_t channel)
{
uint8_t was_off = 0;
uint32_t freq;
channel %= (CC1200_RF_CFG.max_channel - CC1200_RF_CFG.min_channel + 1);
channel += CC1200_RF_CFG.min_channel;
#if 0
/*
* We explicitly allow a channel update even if the channel does not change.
* This feature can be used to manually force a calibration.
*/
if(channel == rf_channel) {
return rf_channel;
}
#endif
if(channel < CC1200_RF_CFG.min_channel ||
channel > CC1200_RF_CFG.max_channel) {
/* Invalid channel */
return CHANNEL_OUT_OF_LIMITS;
}
if(SPI_IS_LOCKED() || (rf_flags & RF_TX_ACTIVE) || receiving_packet()) {
/* We are busy, postpone channel update */
new_rf_channel = channel;
rf_flags |= RF_UPDATE_CHANNEL;
process_poll(&cc1200_process);
INFO("RF: Channel update postponed\n");
return CHANNEL_UPDATE_POSTPONED;
}
rf_flags &= ~RF_UPDATE_CHANNEL;
INFO("RF: Channel update (%d)\n", channel);
if(!(rf_flags & RF_ON)) {
was_off = 1;
on();
}
LOCK_SPI();
idle();
freq = calculate_freq(channel - CC1200_RF_CFG.min_channel);
single_write(CC1200_FREQ0, ((uint8_t *)&freq)[0]);
single_write(CC1200_FREQ1, ((uint8_t *)&freq)[1]);
single_write(CC1200_FREQ2, ((uint8_t *)&freq)[2]);
rf_channel = channel;
/* Turn on RX again unless we turn off anyway */
if(!was_off) {
#ifdef RF_FORCE_CALIBRATION
rf_flags |= RF_FORCE_CALIBRATION;
#endif
idle_calibrate_rx();
}
RELEASE_SPI();
if(was_off) {
off();
}
return CHANNEL_UPDATE_SUCCEEDED;
}
/*---------------------------------------------------------------------------*/
/* Check broadcast address. */
static int
is_broadcast_addr(uint8_t mode, uint8_t *addr)
{
int i = mode == FRAME802154_SHORTADDRMODE ? 2 : 8;
while(i-- > 0) {
if(addr[i] != 0xff) {
return 0;
}
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int
addr_check_auto_ack(uint8_t *frame, uint16_t frame_len)
{
frame802154_t info154;
if(frame802154_parse(frame, frame_len, &info154) != 0) {
/* We received a valid 802.15.4 frame */
if(!(rx_mode_value & RADIO_RX_MODE_ADDRESS_FILTER) ||
info154.fcf.frame_type == FRAME802154_ACKFRAME ||
is_broadcast_addr(info154.fcf.dest_addr_mode,
(uint8_t *)&info154.dest_addr) ||
linkaddr_cmp((linkaddr_t *)&info154.dest_addr,
&linkaddr_node_addr)) {
/*
* Address check succeeded or address filter disabled.
* We send an ACK in case a corresponding data frame
* is received even in promiscuous mode (if auto-ack is
* enabled)!
*/
if((rx_mode_value & RADIO_RX_MODE_AUTOACK) &&
info154.fcf.frame_type == FRAME802154_DATAFRAME &&
info154.fcf.ack_required != 0 &&
(!(rx_mode_value & RADIO_RX_MODE_ADDRESS_FILTER) ||
linkaddr_cmp((linkaddr_t *)&info154.dest_addr,
&linkaddr_node_addr))) {
/*
* Data frame destined for us & ACK request bit set -> send ACK.
* Make sure the preamble length is configured accordingly as
* MAC timing parameters rely on this!
*/
uint8_t ack[ACK_LEN] = { FRAME802154_ACKFRAME, 0, info154.seq };
#if (RXOFF_MODE_RX == 1)
/*
* This turns off GPIOx interrupts. Make sure they are turned on
* in rx_rx() later on!
*/
idle();
#endif
prepare((const uint8_t *)ack, ACK_LEN);
idle_tx_rx((const uint8_t *)ack, ACK_LEN);
/* rx_rx() will follow */
return ADDR_CHECK_OK_ACK_SEND;
}
return ADDR_CHECK_OK;
} else {
return ADDR_CHECK_FAILED;
}
}
return INVALID_FRAME;
}
/*---------------------------------------------------------------------------*/
/*
* The CC1200 interrupt handler: called by the hardware interrupt
* handler, which is defined as part of the cc1200-arch interface.
*/
int
cc1200_rx_interrupt(void)
{
/* The radio's state */
uint8_t s;
/* The number of bytes in the RX FIFO waiting for read-out */
uint8_t num_rxbytes;
/* The payload length read as the first byte from the RX FIFO */
static uint16_t payload_len;
/*
* The number of bytes already read out and placed in the
* intermediate buffer
*/
static uint16_t bytes_read;
/*
* We use an intermediate buffer for the packet before
* we pass it to the next upper layer. We also place RSSI +
* LQI in this buffer
*/
static uint8_t buf[CC1200_MAX_PAYLOAD_LEN + APPENDIX_LEN];
/*
* If CC1200_USE_GPIO2 is enabled, we come here either once RX FIFO
* threshold is reached (GPIO2 rising edge)
* or at the end of the packet (GPIO0 falling edge).
*/
#if CC1200_USE_GPIO2
int gpio2 = cc1200_arch_gpio2_read_pin();
int gpio0 = cc1200_arch_gpio0_read_pin();
if((rf_flags & RF_RX_ONGOING) == 0 && gpio2 > 0) {
rf_flags |= RF_RX_ONGOING;
sfd_timestamp = RTIMER_NOW();
}
if(gpio0 == 0) {
rf_flags &= ~RF_RX_ONGOING;
}
#endif
if(SPI_IS_LOCKED()) {
/*
* SPI is in use. Exit and make sure this
* function is called from the poll handler as soon
* as SPI is available again
*/
rf_flags |= RF_POLL_RX_INTERRUPT;
process_poll(&cc1200_process);
return 1;
}
rf_flags &= ~RF_POLL_RX_INTERRUPT;
LOCK_SPI();
/*
* If CC1200_USE_GPIO2 is enabled, we come here either once RX FIFO
* threshold is reached (GPIO2 rising edge)
* or at the end of the packet (GPIO0 falling edge).
*/
/* Make sure we are in a sane state. Sane means: either RX or IDLE */
s = state();
if((s == STATE_RX_FIFO_ERR) || (s == STATE_TX_FIFO_ERR)) {
rx_rx();
RELEASE_SPI();
return 0;
}
num_rxbytes = single_read(CC1200_NUM_RXBYTES);
if(num_rxbytes == 0) {
/*
* This might happen from time to time because
* this function is also called by the pollhandler and / or
* from TWO interrupts which can occur at the same time.
*/
INFO("RF: RX FIFO empty!\n");
RELEASE_SPI();
return 0;
}
if(!(rf_flags & RF_RX_PROCESSING_PKT)) {
#if CC1200_802154G
struct {
uint8_t phra;
uint8_t phrb;
}
phr;
if(num_rxbytes < PHR_LEN) {
WARNING("RF: PHR incomplete!\n");
rx_rx();
RELEASE_SPI();
return 0;
}
burst_read(CC1200_RXFIFO,
&phr,
PHR_LEN);
payload_len = (phr.phra & 0x07);
payload_len <<= 8;
payload_len += phr.phrb;
if(phr.phra & (1 << 4)) {
/* CRC16, payload_len += 2 */
payload_len -= 2;
} else {
/* CRC16, payload_len += 4 */
payload_len -= 4;
}
#else
/* Read first byte in RX FIFO (payload length) */
burst_read(CC1200_RXFIFO,
(uint8_t *)&payload_len,
PHR_LEN);
#endif
if(payload_len < ACK_LEN) {
/* Packet to short. Discard it */
WARNING("RF: Packet too short!\n");
rx_rx();
RELEASE_SPI();
return 0;
}
if(payload_len > CC1200_MAX_PAYLOAD_LEN) {
/* Packet to long. Discard it */
WARNING("RF: Packet to long!\n");
rx_rx();
RELEASE_SPI();
return 0;
}
RX_LEDS_ON();
bytes_read = 0;
num_rxbytes -= PHR_LEN;
rf_flags |= RF_RX_PROCESSING_PKT;
/* Fall through... */
}
if(rf_flags & RF_RX_PROCESSING_PKT) {
/*
* Read out remaining bytes unless FIFO is empty.
* We have at least num_rxbytes in the FIFO to be read out.
*/
if((num_rxbytes + bytes_read) > (payload_len + CC_APPENDIX_LEN)) {
/*
* We have a mismatch between the number of bytes in the RX FIFO
* and the payload_len. This would lead to an buffer overflow,
* so we catch this error here.
*/
WARNING("RF: RX length mismatch %d %d %d!\n", num_rxbytes,
bytes_read,
payload_len);
rx_rx();
RELEASE_SPI();
return 0;
}
burst_read(CC1200_RXFIFO,
&buf[bytes_read],
num_rxbytes);
bytes_read += num_rxbytes;
num_rxbytes = 0;
if(bytes_read == (payload_len + CC_APPENDIX_LEN)) {
/*
* End of packet. Read appendix (if available), check CRC
* and copy the data from temporary buffer to rx_pkt
* RSSI offset already set using AGC_GAIN_ADJUST.GAIN_ADJUSTMENT
*/
#if APPEND_STATUS
uint8_t crc_lqi = buf[bytes_read - 1];
#else
int8_t rssi = single_read(CC1200_RSSI1);
uint8_t crc_lqi = single_read(CC1200_LQI_VAL);
#endif
if(!(crc_lqi & (1 << 7))) {
/* CRC error. Drop the packet */
INFO("RF: CRC error!\n");
} else if(rx_pkt_len != 0) {
/* An old packet is pending. Drop the packet */
WARNING("RF: Packet pending!\n");
} else {
int ret = addr_check_auto_ack(buf, bytes_read);
if((ret == ADDR_CHECK_OK) ||
(ret == ADDR_CHECK_OK_ACK_SEND)) {
#if APPEND_STATUS
/* RSSI + LQI already read out and placed into buf */
#else
buf[bytes_read++] = (uint8_t)rssi;
buf[bytes_read++] = crc_lqi;
#endif
rx_pkt_len = bytes_read;
memcpy((void *)rx_pkt, buf, rx_pkt_len);
rx_rx();
process_poll(&cc1200_process);
RELEASE_SPI();
return 1;
} else {
/* Invalid address. Drop the packet */
}
}
/* Buffer full, address or CRC check failed */
rx_rx();
RELEASE_SPI();
return 0;
} /* if (bytes_read == payload_len) */
}
RELEASE_SPI();
return 0;
}
/*---------------------------------------------------------------------------*/