diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx index ac050efe8..5ea92e30c 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc13xx @@ -1,6 +1,6 @@ TI_XXWARE_PATH = lib/cc13xxware -CONTIKI_CPU_SOURCEFILES += smartrf-settings.c prop-mode.c prop-mode-tx-power.c +CONTIKI_CPU_SOURCEFILES += smartrf-settings.c prop-mode.c prop-mode-tx-power.c cc13xx-50kbps-tsch.c CFLAGS += -DCPU_FAMILY_CC13X0=1 -DCPU_FAMILY_CC13XX=1 diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h index 47dbc4eb5..97b188e15 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-def.h @@ -36,12 +36,43 @@ /*---------------------------------------------------------------------------*/ /* TSCH related defines */ +/* 2 bytes header, 4 bytes CRC */ +#define CC13XX_RADIO_PHY_OVERHEAD 6 +/* 3 bytes preamble, 3 bytes sync */ +#define CC13XX_RADIO_PHY_HEADER_LEN 6 +/* The default data rate is 50 kbps */ +#define CC13XX_RADIO_BIT_RATE 50000 + /* 1 len byte, 2 bytes CRC */ -#define RADIO_PHY_OVERHEAD 3 -/* 250kbps data rate. One byte = 32us */ -#define RADIO_BYTE_AIR_TIME 32 +#define CC26XX_RADIO_PHY_OVERHEAD 3 +/* 4 bytes preamble, 1 byte sync */ +#define CC26XX_RADIO_PHY_HEADER_LEN 5 +/* The fixed data rate is 250 kbps */ +#define CC26XX_RADIO_BIT_RATE 250000 + +#if CPU_FAMILY_CC13XX +#define RADIO_PHY_HEADER_LEN CC13XX_RADIO_PHY_HEADER_LEN +#define RADIO_PHY_OVERHEAD CC13XX_RADIO_PHY_OVERHEAD +#define RADIO_BIT_RATE CC13XX_RADIO_BIT_RATE + +/* The TSCH default slot length of 10ms is too short, use custom one instead */ +#ifndef TSCH_CONF_DEFAULT_TIMESLOT_TIMING +#define TSCH_CONF_DEFAULT_TIMESLOT_TIMING tsch_timing_cc13xx_50kbps +#endif /* TSCH_CONF_DEFAULT_TIMESLOT_TIMING */ + +/* Symbol for the custom TSCH timeslot timing template */ +#define TSCH_CONF_ARCH_HDR_PATH "rf-core/cc13xx-50kbps-tsch.h" + +#else +#define RADIO_PHY_HEADER_LEN CC26XX_RADIO_PHY_HEADER_LEN +#define RADIO_PHY_OVERHEAD CC26XX_RADIO_PHY_OVERHEAD +#define RADIO_BIT_RATE CC26XX_RADIO_BIT_RATE +#endif + +#define RADIO_BYTE_AIR_TIME (1000000 / (RADIO_BIT_RATE / 8)) + /* Delay between GO signal and SFD */ -#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81)) +#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(RADIO_PHY_HEADER_LEN * RADIO_BYTE_AIR_TIME)) /* Delay between GO signal and start listening. * This value is so small because the radio is constantly on within each timeslot. */ #define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(15)) @@ -56,9 +87,6 @@ #define RADIO_TO_RTIMER(X) ((uint32_t)(((uint64_t)(X) * (RTIMER_SECOND / 256)) / (RADIO_TIMER_SECOND / 256))) #define USEC_TO_RADIO(X) ((X) * 4) -/* The PHY header (preamble + SFD, 4+1 bytes) duration is equivalent to 10 symbols */ -#define RADIO_IEEE_802154_PHY_HEADER_DURATION_USEC 160 - /* Do not turn off TSCH within a timeslot: not enough time */ #define TSCH_CONF_RADIO_ON_DURING_TIMESLOT 1 diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c index a9b949d93..3245b9c4f 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ble-hal/ble-hal-cc26xx.c @@ -386,7 +386,7 @@ on(void) rf_core_power_down(); return RF_CORE_CMD_ERROR; } - rf_core_setup_interrupts(0); + rf_core_setup_interrupts(); oscillators_switch_to_hf_xosc(); if(rf_ble_cmd_setup_ble_mode() != RF_BLE_CMD_OK) { diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.c b/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.c new file mode 100644 index 000000000..af76d63e3 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018, University of Bristol - http://www.bristol.ac.uk/ + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + * + */ + +/** + * \file + * IEEE 802.15.4 TSCH timeslot timings for CC13xx chips at 50kbps datarate + * \author + * Atis Elsts + * + */ + +#include "contiki.h" +#include "net/mac/tsch/tsch.h" + +#define CC13XX_TSCH_DEFAULT_TS_CCA_OFFSET 1800 +#define CC13XX_TSCH_DEFAULT_TS_CCA 128 +#define CC13XX_TSCH_DEFAULT_TS_TX_OFFSET 2500 +#define CC13XX_TSCH_DEFAULT_TS_RX_OFFSET (CC13XX_TSCH_DEFAULT_TS_TX_OFFSET - (TSCH_CONF_RX_WAIT / 2)) +#define CC13XX_TSCH_DEFAULT_TS_RX_ACK_DELAY 2000 +#define CC13XX_TSCH_DEFAULT_TS_TX_ACK_DELAY 3000 +#define CC13XX_TSCH_DEFAULT_TS_RX_WAIT TSCH_CONF_RX_WAIT +#define CC13XX_TSCH_DEFAULT_TS_ACK_WAIT 3000 +#define CC13XX_TSCH_DEFAULT_TS_RX_TX 192 +#define CC13XX_TSCH_DEFAULT_TS_MAX_ACK 10000 +#define CC13XX_TSCH_DEFAULT_TS_MAX_TX 21600 + +/* Timeslot length: 40000 usec */ +#define CC13XX_TSCH_DEFAULT_TS_TIMESLOT_LENGTH 40000 + +/* TSCH timeslot timing (microseconds) */ +const uint16_t tsch_timing_cc13xx_50kbps[tsch_ts_elements_count] = { + CC13XX_TSCH_DEFAULT_TS_CCA_OFFSET, + CC13XX_TSCH_DEFAULT_TS_CCA, + CC13XX_TSCH_DEFAULT_TS_TX_OFFSET, + CC13XX_TSCH_DEFAULT_TS_RX_OFFSET, + CC13XX_TSCH_DEFAULT_TS_RX_ACK_DELAY, + CC13XX_TSCH_DEFAULT_TS_TX_ACK_DELAY, + CC13XX_TSCH_DEFAULT_TS_RX_WAIT, + CC13XX_TSCH_DEFAULT_TS_ACK_WAIT, + CC13XX_TSCH_DEFAULT_TS_RX_TX, + CC13XX_TSCH_DEFAULT_TS_MAX_ACK, + CC13XX_TSCH_DEFAULT_TS_MAX_TX, + CC13XX_TSCH_DEFAULT_TS_TIMESLOT_LENGTH, +}; diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.h b/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.h new file mode 100644 index 000000000..5d4fdb376 --- /dev/null +++ b/arch/cpu/cc26xx-cc13xx/rf-core/cc13xx-50kbps-tsch.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018, University of Bristol - http://www.bristol.ac.uk/ + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + * + */ + +#ifndef CC13XX_50KBPS_TSCH_H_ +#define CC13XX_50KBPS_TSCH_H_ + +#include "contiki.h" + +/* TSCH timeslot timing (microseconds) */ +extern const uint16_t tsch_timing_cc13xx_50kbps[]; + +#endif /* CC13XX_50KBPS_TSCH_H_ */ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c b/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c index 3516147b5..9f4021d21 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c @@ -120,6 +120,8 @@ static uint8_t rf_stats[16] = { 0 }; /* The size of the RF commands buffer */ #define RF_CMD_BUFFER_SIZE 128 /*---------------------------------------------------------------------------*/ +#define RAT_TIMESTAMP_OFFSET_2_4_GHZ 0 +/*---------------------------------------------------------------------------*/ /** * \brief Returns the current status of a running Radio Op command * \param a A pointer with the buffer used to initiate the command @@ -130,55 +132,9 @@ static uint8_t rf_stats[16] = { 0 }; */ #define RF_RADIO_OP_GET_STATUS(a) (((rfc_radioOp_t *)a)->status) /*---------------------------------------------------------------------------*/ -/* Special value returned by CMD_IEEE_CCA_REQ when an RSSI is not available */ -#define RF_CMD_CCA_REQ_RSSI_UNKNOWN -128 - -/* Used for the return value of channel_clear */ -#define RF_CCA_CLEAR 1 -#define RF_CCA_BUSY 0 - -/* Used as an error return value for get_cca_info */ -#define RF_GET_CCA_INFO_ERROR 0xFF - -/* - * Values of the individual bits of the ccaInfo field in CMD_IEEE_CCA_REQ's - * status struct - */ -#define RF_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 00 */ -#define RF_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 01 */ -#define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ - -#define RF_CMD_CCA_REQ_CCA_CORR_IDLE (0 << 4) -#define RF_CMD_CCA_REQ_CCA_CORR_BUSY (1 << 4) -#define RF_CMD_CCA_REQ_CCA_CORR_INVALID (3 << 4) -#define RF_CMD_CCA_REQ_CCA_CORR_MASK (3 << 4) - -#define RF_CMD_CCA_REQ_CCA_SYNC_BUSY (1 << 6) -/*---------------------------------------------------------------------------*/ #define IEEE_MODE_CHANNEL_MIN 11 #define IEEE_MODE_CHANNEL_MAX 26 /*---------------------------------------------------------------------------*/ -/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ -#define TX_WAIT_TIMEOUT (RTIMER_SECOND >> 11) - -/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ -#define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) - -/* How long to wait for the RF to react on CMD_ABORT: around 1 msec */ -#define RF_TURN_OFF_WAIT_TIMEOUT (RTIMER_SECOND >> 10) - -/* How long to wait for the RF to finish TX of a packet or an ACK */ -#define TX_FINISH_WAIT_TIMEOUT (RTIMER_SECOND >> 7) - -#define LIMITED_BUSYWAIT(cond, timeout) do { \ - rtimer_clock_t end_time = RTIMER_NOW() + timeout; \ - while(cond) { \ - if(!RTIMER_CLOCK_LT(RTIMER_NOW(), end_time)) { \ - break; \ - } \ - } \ - } while(0) -/*---------------------------------------------------------------------------*/ /* TX Power dBm lookup table - values from SmartRF Studio */ typedef struct output_config { radio_value_t dbm; @@ -211,33 +167,6 @@ static const output_config_t output_power[] = { /* Default TX Power - position in output_power[] */ static const output_config_t *tx_power_current = &output_power[0]; /*---------------------------------------------------------------------------*/ -static volatile int8_t last_rssi = 0; -static volatile uint8_t last_corr_lqi = 0; - -extern int32_t rat_offset; - -/*---------------------------------------------------------------------------*/ -/* SFD timestamp in RTIMER ticks */ -static volatile uint32_t last_packet_timestamp = 0; -/* SFD timestamp in RAT ticks (but 64 bits) */ -static uint64_t last_rat_timestamp64 = 0; - -/* For RAT overflow handling */ -static struct ctimer rat_overflow_timer; -static volatile uint32_t rat_overflow_counter = 0; -static rtimer_clock_t last_rat_overflow = 0; - -/* RAT has 32-bit register, overflows once 18 minutes */ -#define RAT_RANGE 4294967296ull -/* approximate value */ -#define RAT_OVERFLOW_PERIOD_SECONDS (60 * 18) - -/* XXX: don't know what exactly is this, looks like the time to Tx 3 octets */ -#define TIMESTAMP_OFFSET -(USEC_TO_RADIO(32 * 3) - 1) /* -95.75 usec */ -/*---------------------------------------------------------------------------*/ -/* Are we currently in poll mode? */ -static uint8_t poll_mode = 0; - static rfc_CMD_IEEE_MOD_FILT_t filter_cmd; /*---------------------------------------------------------------------------*/ /* @@ -256,27 +185,28 @@ static uint8_t cmd_ieee_rx_buf[RF_CMD_BUFFER_SIZE] CC_ALIGN(4); #define DATA_ENTRY_LENSZ_BYTE 1 #define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ -#define RX_BUF_SIZE 144 -/* Four receive buffers entries with room for 1 IEEE802.15.4 frame in each */ -static uint8_t rx_buf_0[RX_BUF_SIZE] CC_ALIGN(4); -static uint8_t rx_buf_1[RX_BUF_SIZE] CC_ALIGN(4); -static uint8_t rx_buf_2[RX_BUF_SIZE] CC_ALIGN(4); -static uint8_t rx_buf_3[RX_BUF_SIZE] CC_ALIGN(4); - -#define RX_BUF_INCLUDE_CRC 1 -#define RX_BUF_INCLUDE_RSSI 1 -#define RX_BUF_INCLUDE_CORR 1 -#define RX_BUF_INCLUDE_TIMESTAMP 1 - /* The size of the metadata (excluding the packet length field) */ #define RX_BUF_METADATA_SIZE \ - (2 * RX_BUF_INCLUDE_CRC + RX_BUF_INCLUDE_RSSI + RX_BUF_INCLUDE_CORR + 4 * RX_BUF_INCLUDE_TIMESTAMP) + (2 * RF_CORE_RX_BUF_INCLUDE_CRC \ + + RF_CORE_RX_BUF_INCLUDE_RSSI \ + + RF_CORE_RX_BUF_INCLUDE_CORR \ + + 4 * RF_CORE_RX_BUF_INCLUDE_TIMESTAMP) /* The offset of the packet length in a rx buffer */ #define RX_BUF_LENGTH_OFFSET sizeof(rfc_dataEntry_t) /* The offset of the packet data in a rx buffer */ #define RX_BUF_DATA_OFFSET (RX_BUF_LENGTH_OFFSET + 1) +#define RX_BUF_SIZE (RX_BUF_DATA_OFFSET \ + + NETSTACK_RADIO_MAX_PAYLOAD_LEN \ + + RX_BUF_METADATA_SIZE) + +/* Four receive buffers entries with room for 1 IEEE802.15.4 frame in each */ +static uint8_t rx_buf_0[RX_BUF_SIZE] CC_ALIGN(4); +static uint8_t rx_buf_1[RX_BUF_SIZE] CC_ALIGN(4); +static uint8_t rx_buf_2[RX_BUF_SIZE] CC_ALIGN(4); +static uint8_t rx_buf_3[RX_BUF_SIZE] CC_ALIGN(4); + /* The RX Data Queue */ static dataQueue_t rx_data_queue = { 0 }; @@ -358,8 +288,8 @@ transmitting(void) return 0; } - if((cmd.currentRssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN) && - (cmd.ccaInfo.ccaEnergy == RF_CMD_CCA_REQ_CCA_STATE_BUSY)) { + if((cmd.currentRssi == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN) && + (cmd.ccaInfo.ccaEnergy == RF_CORE_CMD_CCA_REQ_CCA_STATE_BUSY)) { return 1; } @@ -368,12 +298,12 @@ transmitting(void) /*---------------------------------------------------------------------------*/ /** * \brief Returns CCA information - * \return RF_GET_CCA_INFO_ERROR if the RF was not on + * \return RF_CORE_GET_CCA_INFO_ERROR if the RF was not on * \return On success, the return value is formatted as per the ccaInfo field * of CMD_IEEE_CCA_REQ * * It is the caller's responsibility to make sure the RF is on. This function - * will return RF_GET_CCA_INFO_ERROR if the RF is off + * will return RF_CORE_GET_CCA_INFO_ERROR if the RF is off * * This function will in fact wait for a valid CCA state */ @@ -385,20 +315,20 @@ get_cca_info(void) if(!rf_is_on()) { PRINTF("get_cca_info: Not on\n"); - return RF_GET_CCA_INFO_ERROR; + return RF_CORE_GET_CCA_INFO_ERROR; } memset(&cmd, 0x00, sizeof(cmd)); - cmd.ccaInfo.ccaState = RF_CMD_CCA_REQ_CCA_STATE_INVALID; + cmd.ccaInfo.ccaState = RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID; - while(cmd.ccaInfo.ccaState == RF_CMD_CCA_REQ_CCA_STATE_INVALID) { + while(cmd.ccaInfo.ccaState == RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID) { memset(&cmd, 0x00, sizeof(cmd)); cmd.commandNo = CMD_IEEE_CCA_REQ; if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) { PRINTF("get_cca_info: CMDSTA=0x%08lx\n", cmd_status); - return RF_GET_CCA_INFO_ERROR; + return RF_CORE_GET_CCA_INFO_ERROR; } } @@ -425,14 +355,14 @@ get_rssi(void) was_off = 1; if(on() != RF_CORE_CMD_OK) { PRINTF("get_rssi: on() failed\n"); - return RF_CMD_CCA_REQ_RSSI_UNKNOWN; + return RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; } } memset(&cmd, 0x00, sizeof(cmd)); - cmd.ccaInfo.ccaEnergy = RF_CMD_CCA_REQ_CCA_STATE_INVALID; + cmd.ccaInfo.ccaEnergy = RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID; - while(cmd.ccaInfo.ccaEnergy == RF_CMD_CCA_REQ_CCA_STATE_INVALID) { + while(cmd.ccaInfo.ccaEnergy == RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID) { memset(&cmd, 0x00, sizeof(cmd)); cmd.commandNo = CMD_IEEE_CCA_REQ; @@ -440,7 +370,7 @@ get_rssi(void) PRINTF("get_rssi: CMDSTA=0x%08lx\n", cmd_status); /* Make sure to return RSSI unknown */ - cmd.currentRssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; + cmd.currentRssi = RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; break; } } @@ -558,8 +488,8 @@ rf_cmd_ieee_rx() return RF_CORE_CMD_ERROR; } - LIMITED_BUSYWAIT(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) != RF_CORE_RADIO_OP_STATUS_ACTIVE, - ENTER_RX_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == RF_CORE_RADIO_OP_STATUS_ACTIVE, + RF_CORE_ENTER_RX_TIMEOUT); /* Wait to enter RX */ if(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) != RF_CORE_RADIO_OP_STATUS_ACTIVE) { @@ -615,11 +545,11 @@ init_rf_params(void) cmd->rxConfig.bAutoFlushCrc = 1; cmd->rxConfig.bAutoFlushIgn = 0; cmd->rxConfig.bIncludePhyHdr = 0; - cmd->rxConfig.bIncludeCrc = RX_BUF_INCLUDE_CRC; - cmd->rxConfig.bAppendRssi = RX_BUF_INCLUDE_RSSI; - cmd->rxConfig.bAppendCorrCrc = RX_BUF_INCLUDE_CORR; + cmd->rxConfig.bIncludeCrc = RF_CORE_RX_BUF_INCLUDE_CRC; + cmd->rxConfig.bAppendRssi = RF_CORE_RX_BUF_INCLUDE_RSSI; + cmd->rxConfig.bAppendCorrCrc = RF_CORE_RX_BUF_INCLUDE_CORR; cmd->rxConfig.bAppendSrcInd = 0; - cmd->rxConfig.bAppendTimestamp = RX_BUF_INCLUDE_TIMESTAMP; + cmd->rxConfig.bAppendTimestamp = RF_CORE_RX_BUF_INCLUDE_TIMESTAMP; cmd->pRxQ = &rx_data_queue; cmd->pOutput = (rfc_ieeeRxOutput_t *)rf_stats; @@ -714,7 +644,7 @@ rx_off(void) } /* Wait for ongoing ACK TX to finish */ - LIMITED_BUSYWAIT(transmitting(), TX_FINISH_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(!transmitting(), RF_CORE_TX_FINISH_TIMEOUT); /* Send a CMD_ABORT command to RF Core */ if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_ABORT), &cmd_status) != RF_CORE_CMD_OK) { @@ -722,7 +652,7 @@ rx_off(void) /* Continue nonetheless */ } - LIMITED_BUSYWAIT(rf_is_on(), RF_TURN_OFF_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(!rf_is_on(), RF_CORE_TURN_OFF_TIMEOUT); if(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_STOPPED || RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_ABORT) { @@ -773,8 +703,8 @@ soft_off(void) return; } - LIMITED_BUSYWAIT((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) == - RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING, RF_TURN_OFF_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) != + RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING, RF_CORE_TURN_OFF_TIMEOUT); } /*---------------------------------------------------------------------------*/ static uint8_t @@ -791,71 +721,10 @@ soft_on(void) static const rf_core_primary_mode_t mode_ieee = { soft_off, soft_on, + rf_is_on, + RAT_TIMESTAMP_OFFSET_2_4_GHZ }; /*---------------------------------------------------------------------------*/ -static uint8_t -check_rat_overflow(bool first_time) -{ - static uint32_t last_value; - uint32_t current_value; - uint8_t interrupts_disabled; - - /* Bail out if the RF is not on */ - if(!rf_is_on()) { - return 0; - } - - interrupts_disabled = ti_lib_int_master_disable(); - if(first_time) { - last_value = HWREG(RFC_RAT_BASE + RATCNT); - } else { - current_value = HWREG(RFC_RAT_BASE + RATCNT); - if(current_value + RAT_RANGE / 4 < last_value) { - /* Overflow detected */ - last_rat_overflow = RTIMER_NOW(); - rat_overflow_counter++; - } - last_value = current_value; - } - if(!interrupts_disabled) { - ti_lib_int_master_enable(); - } - return 1; -} -/*---------------------------------------------------------------------------*/ -static void -handle_rat_overflow(void *unused) -{ - uint8_t success; - uint8_t was_off = 0; - - if(!rf_is_on()) { - was_off = 1; - if(on() != RF_CORE_CMD_OK) { - PRINTF("overflow: on() failed\n"); - ctimer_set(&rat_overflow_timer, CLOCK_SECOND, - handle_rat_overflow, NULL); - return; - } - } - - success = check_rat_overflow(false); - - if(was_off) { - off(); - } - - if(success) { - /* Retry after half of the interval */ - ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, - handle_rat_overflow, NULL); - } else { - /* Retry sooner */ - ctimer_set(&rat_overflow_timer, CLOCK_SECOND, - handle_rat_overflow, NULL); - } -} -/*---------------------------------------------------------------------------*/ static int init(void) { @@ -889,9 +758,7 @@ init(void) rf_core_primary_mode_register(&mode_ieee); - check_rat_overflow(true); - ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, - handle_rat_overflow, NULL); + rf_core_rat_init(); process_start(&rf_core_process, NULL); return 1; @@ -935,7 +802,7 @@ transmit(unsigned short transmit_len) do { tx_active = transmitting(); } while(tx_active == 1 && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TX_WAIT_TIMEOUT))); + (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + RF_CORE_TX_TIMEOUT))); if(tx_active) { PRINTF("transmit: Already TXing and wait timed out\n"); @@ -957,7 +824,7 @@ transmit(unsigned short transmit_len) cmd.startTrigger.triggerType = TRIG_NOW; /* Enable the LAST_FG_COMMAND_DONE interrupt, which will wake us up */ - rf_core_cmd_done_en(true, poll_mode); + rf_core_cmd_done_en(true); ret = rf_core_send_cmd((uint32_t)&cmd, &cmd_status); @@ -973,7 +840,7 @@ transmit(unsigned short transmit_len) * 1) make the `lpm_sleep()` call here unconditional; * 2) change the radio ISR priority to allow radio ISR to interrupt rtimer ISR. */ - if(!poll_mode) { + if(!rf_core_poll_mode) { lpm_sleep(); } } @@ -1007,7 +874,7 @@ transmit(unsigned short transmit_len) * Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it * except when we are transmitting */ - rf_core_cmd_done_dis(poll_mode); + rf_core_cmd_done_dis(); if(was_off) { off(); @@ -1036,46 +903,6 @@ release_data_entry(void) rx_read_entry = entry->pNextEntry; } /*---------------------------------------------------------------------------*/ -static uint32_t -calc_last_packet_timestamp(uint32_t rat_timestamp) -{ - uint64_t rat_timestamp64; - uint32_t adjusted_overflow_counter; - uint8_t was_off = 0; - - if(!rf_is_on()) { - was_off = 1; - on(); - } - - if(rf_is_on()) { - check_rat_overflow(false); - if(was_off) { - off(); - } - } - - adjusted_overflow_counter = rat_overflow_counter; - - /* if the timestamp is large and the last oveflow was recently, - assume that the timestamp refers to the time before the overflow */ - if(rat_timestamp > (uint32_t)(RAT_RANGE * 3 / 4)) { - if(RTIMER_CLOCK_LT(RTIMER_NOW(), - last_rat_overflow + RAT_OVERFLOW_PERIOD_SECONDS * RTIMER_SECOND / 4)) { - adjusted_overflow_counter--; - } - } - - /* add the overflowed time to the timestamp */ - rat_timestamp64 = rat_timestamp + RAT_RANGE * adjusted_overflow_counter; - /* correct timestamp so that it refers to the end of the SFD */ - rat_timestamp64 += TIMESTAMP_OFFSET; - - last_rat_timestamp64 = rat_timestamp64 - rat_offset; - - return RADIO_TO_RTIMER(rat_timestamp64 - rat_offset); -} -/*---------------------------------------------------------------------------*/ static int read_frame(void *buf, unsigned short buf_len) { @@ -1111,20 +938,20 @@ read_frame(void *buf, unsigned short buf_len) memcpy(buf, (uint8_t *)rx_read_entry + RX_BUF_DATA_OFFSET, len); - last_rssi = (int8_t)rx_read_entry[RX_BUF_DATA_OFFSET + len + 2]; - last_corr_lqi = (uint8_t)rx_read_entry[RX_BUF_DATA_OFFSET + len + 3] & STATUS_CORRELATION; + rf_core_last_rssi = (int8_t)rx_read_entry[RX_BUF_DATA_OFFSET + len]; + rf_core_last_corr_lqi = (uint8_t)rx_read_entry[RX_BUF_DATA_OFFSET + len + 1] & STATUS_CORRELATION; /* get the timestamp */ - memcpy(&rat_timestamp, (uint8_t *)rx_read_entry + RX_BUF_DATA_OFFSET + len + 4, 4); + memcpy(&rat_timestamp, (uint8_t *)rx_read_entry + RX_BUF_DATA_OFFSET + len + 2, 4); - last_packet_timestamp = calc_last_packet_timestamp(rat_timestamp); + rf_core_last_packet_timestamp = rf_core_convert_rat_to_rtimer(rat_timestamp); - if(!poll_mode) { + if(!rf_core_poll_mode) { /* Not in poll mode: packetbuf should not be accessed in interrupt context. * In poll mode, the last packet RSSI and link quality can be obtained through * RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY */ - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, last_rssi); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, last_corr_lqi); + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rf_core_last_rssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, rf_core_last_corr_lqi); } release_data_entry(); @@ -1137,7 +964,7 @@ channel_clear(void) { uint8_t was_off = 0; uint8_t cca_info; - int ret = RF_CCA_CLEAR; + int ret = RF_CORE_CCA_CLEAR; /* * If we are in the middle of a BLE operation, we got called by ContikiMAC @@ -1145,7 +972,7 @@ channel_clear(void) */ if(rf_ble_is_active() == RF_BLE_ACTIVE) { PRINTF("channel_clear: Interrupt context but BLE in progress\n"); - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } if(rf_is_on()) { @@ -1157,7 +984,7 @@ channel_clear(void) * * We could probably even simply return that the channel is clear */ - LIMITED_BUSYWAIT(transmitting(), TX_FINISH_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(!transmitting(), RF_CORE_TX_FINISH_TIMEOUT); } else { was_off = 1; if(on() != RF_CORE_CMD_OK) { @@ -1165,21 +992,21 @@ channel_clear(void) if(was_off) { off(); } - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } } cca_info = get_cca_info(); - if(cca_info == RF_GET_CCA_INFO_ERROR) { + if(cca_info == RF_CORE_GET_CCA_INFO_ERROR) { PRINTF("channel_clear: CCA error\n"); - ret = RF_CCA_CLEAR; + ret = RF_CORE_CCA_CLEAR; } else { /* * cca_info bits 1:0 - ccaStatus * Return 1 (clear) if idle or invalid. */ - ret = (cca_info & 0x03) != RF_CMD_CCA_REQ_CCA_STATE_BUSY; + ret = (cca_info & 0x03) != RF_CORE_CMD_CCA_REQ_CCA_STATE_BUSY; } if(was_off) { @@ -1218,12 +1045,12 @@ receiving_packet(void) cca_info = get_cca_info(); /* If we can't read CCA info, return "not receiving" */ - if(cca_info == RF_GET_CCA_INFO_ERROR) { + if(cca_info == RF_CORE_GET_CCA_INFO_ERROR) { return 0; } /* If sync has been seen, return 1 (receiving) */ - if(cca_info & RF_CMD_CCA_REQ_CCA_SYNC_BUSY) { + if(cca_info & RF_CORE_CMD_CCA_REQ_CCA_SYNC_BUSY) { return 1; } @@ -1241,7 +1068,7 @@ pending_packet(void) if(entry->status == DATA_ENTRY_STATUS_FINISHED || entry->status == DATA_ENTRY_STATUS_BUSY) { rv = 1; - if(!poll_mode) { + if(!rf_core_poll_mode) { process_poll(&rf_core_process); } } @@ -1292,7 +1119,7 @@ on(void) return RF_CORE_CMD_ERROR; } - rf_core_setup_interrupts(poll_mode); + rf_core_setup_interrupts(); if(rf_radio_setup() != RF_CORE_CMD_OK) { PRINTF("on: radio_setup() failed\n"); @@ -1314,7 +1141,7 @@ off(void) return RF_CORE_CMD_OK; } - LIMITED_BUSYWAIT(transmitting(), TX_FINISH_WAIT_TIMEOUT); + RTIMER_BUSYWAIT_UNTIL(!transmitting(), RF_CORE_TX_FINISH_TIMEOUT); /* stopping the rx explicitly results in lower sleep-mode power usage */ rx_off(); @@ -1394,7 +1221,7 @@ get_value(radio_param_t param, radio_value_t *value) if(cmd->frameFiltOpt.autoAckEn) { *value |= RADIO_RX_MODE_AUTOACK; } - if(poll_mode) { + if(rf_core_poll_mode) { *value |= RADIO_RX_MODE_POLL_MODE; } @@ -1411,7 +1238,7 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_RSSI: *value = get_rssi(); - if(*value == RF_CMD_CCA_REQ_RSSI_UNKNOWN) { + if(*value == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN) { return RADIO_RESULT_ERROR; } else { return RADIO_RESULT_OK; @@ -1429,10 +1256,25 @@ get_value(radio_param_t param, radio_value_t *value) *value = OUTPUT_POWER_MAX; return RADIO_RESULT_OK; case RADIO_PARAM_LAST_RSSI: - *value = last_rssi; + *value = rf_core_last_rssi; return RADIO_RESULT_OK; case RADIO_PARAM_LAST_LINK_QUALITY: - *value = last_corr_lqi; + *value = rf_core_last_corr_lqi; + return RADIO_RESULT_OK; + case RADIO_CONST_PHY_OVERHEAD: + *value = (radio_value_t)RADIO_PHY_OVERHEAD; + return RADIO_RESULT_OK; + case RADIO_CONST_BYTE_AIR_TIME: + *value = (radio_value_t)RADIO_BYTE_AIR_TIME; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_TX: + *value = (radio_value_t)RADIO_DELAY_BEFORE_TX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_RX: + *value = (radio_value_t)RADIO_DELAY_BEFORE_RX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_DETECT: + *value = (radio_value_t)RADIO_DELAY_BEFORE_DETECT; return RADIO_RESULT_OK; default: return RADIO_RESULT_NOT_SUPPORTED; @@ -1498,9 +1340,9 @@ set_value(radio_param_t param, radio_value_t value) cmd->frameFiltOpt.bPanCoord = 0; cmd->frameFiltOpt.bStrictLenFilter = 0; - old_poll_mode = poll_mode; - poll_mode = (value & RADIO_RX_MODE_POLL_MODE) != 0; - if(poll_mode == old_poll_mode) { + old_poll_mode = rf_core_poll_mode; + rf_core_poll_mode = (value & RADIO_RX_MODE_POLL_MODE) != 0; + if(rf_core_poll_mode == old_poll_mode) { uint32_t cmd_status; /* do not turn the radio on and off, just send an update command */ @@ -1552,7 +1394,7 @@ set_value(radio_param_t param, radio_value_t value) /* Restart the radio timer (RAT). This causes resynchronization between RAT and RTC: useful for TSCH. */ if(rf_core_restart_rat() == RF_CORE_CMD_OK) { - check_rat_overflow(false); + rf_core_check_rat_overflow(); } if(rx_on() != RF_CORE_CMD_OK) { @@ -1590,7 +1432,7 @@ get_object(radio_param_t param, void *dest, size_t size) if(size != sizeof(rtimer_clock_t) || !dest) { return RADIO_RESULT_INVALID_VALUE; } - *(rtimer_clock_t *)dest = last_packet_timestamp; + *(rtimer_clock_t *)dest = rf_core_last_packet_timestamp; return RADIO_RESULT_OK; } diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c b/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c index 66b4a4370..0ce6de5dd 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c @@ -115,24 +115,6 @@ */ #define RF_RADIO_OP_GET_STATUS(a) GET_FIELD_V(a, radioOp, status) /*---------------------------------------------------------------------------*/ -/* Special value returned by CMD_IEEE_CCA_REQ when an RSSI is not available */ -#define RF_CMD_CCA_REQ_RSSI_UNKNOWN -128 - -/* Used for the return value of channel_clear */ -#define RF_CCA_CLEAR 1 -#define RF_CCA_BUSY 0 - -/* Used as an error return value for get_cca_info */ -#define RF_GET_CCA_INFO_ERROR 0xFF - -/* - * Values of the individual bits of the ccaInfo field in CMD_IEEE_CCA_REQ's - * status struct - */ -#define RF_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 00 */ -#define RF_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 01 */ -#define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ - #ifdef PROP_MODE_CONF_RSSI_THRESHOLD #define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD #else @@ -141,6 +123,8 @@ static int8_t rssi_threshold = PROP_MODE_RSSI_THRESHOLD; /*---------------------------------------------------------------------------*/ +static volatile uint8_t is_receiving_packet; +/*---------------------------------------------------------------------------*/ static int on(void); static int off(void); @@ -170,12 +154,6 @@ static rfc_propRxOutput_t rx_stats; #define DOT_4G_PHR_DW_BIT 0 #endif /*---------------------------------------------------------------------------*/ -/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ -#define TX_WAIT_TIMEOUT (RTIMER_SECOND >> 11) - -/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ -#define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) -/*---------------------------------------------------------------------------*/ /* TX power table for the 431-527MHz band */ #ifdef PROP_MODE_CONF_TX_POWER_431_527 #define PROP_MODE_TX_POWER_431_527 PROP_MODE_CONF_TX_POWER_431_527 @@ -222,12 +200,29 @@ static const prop_mode_tx_power_config_t *tx_power_current = &TX_POWER_DRIVER[1] #define DATA_ENTRY_LENSZ_BYTE 1 #define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ +/* The size of the metadata (excluding the packet length field) */ +#define RX_BUF_METADATA_SIZE \ + (CRC_LEN * RF_CORE_RX_BUF_INCLUDE_CRC \ + + RF_CORE_RX_BUF_INCLUDE_RSSI \ + + RF_CORE_RX_BUF_INCLUDE_CORR \ + + 4 * RF_CORE_RX_BUF_INCLUDE_TIMESTAMP) + +/* The offset of the packet length in a rx buffer */ +#define RX_BUF_LENGTH_OFFSET sizeof(rfc_dataEntry_t) +/* The offset of the packet data in a rx buffer */ +#define RX_BUF_DATA_OFFSET (RX_BUF_LENGTH_OFFSET + DOT_4G_PHR_LEN) + +#define ALIGN_TO_4(size) (((size) + 3) & ~3) + +#define RX_BUF_SIZE ALIGN_TO_4(RX_BUF_DATA_OFFSET \ + + NETSTACK_RADIO_MAX_PAYLOAD_LEN \ + + RX_BUF_METADATA_SIZE) + /* * RX buffers. * PROP_MODE_RX_BUF_CNT buffers of RX_BUF_SIZE bytes each. The start of each * buffer must be 4-byte aligned, therefore RX_BUF_SIZE must divide by 4 */ -#define RX_BUF_SIZE 140 static uint8_t rx_buf[PROP_MODE_RX_BUF_CNT][RX_BUF_SIZE] CC_ALIGN(4); /* The RX Data Queue */ @@ -236,6 +231,12 @@ static dataQueue_t rx_data_queue = { 0 }; /* Receive entry pointer to keep track of read items */ volatile static uint8_t *rx_read_entry; /*---------------------------------------------------------------------------*/ +/* + * Increasing this number causes unicast Tx immediately after broadcast Rx to have + * negative synchronization errors ("dr" in TSCH logs); decreasing it: the opposite. + */ +#define RAT_TIMESTAMP_OFFSET_SUB_GHZ USEC_TO_RADIO(160 * 6 - 240) +/*---------------------------------------------------------------------------*/ /* The outgoing frame buffer */ #define TX_BUF_PAYLOAD_LEN 180 #define TX_BUF_HDR_LEN 2 @@ -272,13 +273,13 @@ get_rssi(void) was_off = 1; if(on() != RF_CORE_CMD_OK) { PRINTF("get_rssi: on() failed\n"); - return RF_CMD_CCA_REQ_RSSI_UNKNOWN; + return RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; } } - rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; + rssi = RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; - while((rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) && ++attempts < 10) { + while((rssi == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) && ++attempts < 10) { memset(&cmd, 0x00, sizeof(cmd)); cmd.commandNo = CMD_GET_RSSI; @@ -420,13 +421,17 @@ static uint8_t rf_cmd_prop_rx() { uint32_t cmd_status; - rtimer_clock_t t0; volatile rfc_CMD_PROP_RX_ADV_t *cmd_rx_adv; int ret; cmd_rx_adv = (rfc_CMD_PROP_RX_ADV_t *)&smartrf_settings_cmd_prop_rx_adv; cmd_rx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; + cmd_rx_adv->rxConf.bIncludeCrc = RF_CORE_RX_BUF_INCLUDE_CRC; + cmd_rx_adv->rxConf.bAppendRssi = RF_CORE_RX_BUF_INCLUDE_RSSI; + cmd_rx_adv->rxConf.bAppendTimestamp = RF_CORE_RX_BUF_INCLUDE_TIMESTAMP; + cmd_rx_adv->rxConf.bAppendStatus = RF_CORE_RX_BUF_INCLUDE_CORR; + /* * Set the max Packet length. This is for the payload only, therefore * 2047 - length offset @@ -441,10 +446,8 @@ rf_cmd_prop_rx() return RF_CORE_CMD_ERROR; } - t0 = RTIMER_NOW(); - - while(cmd_rx_adv->status != RF_CORE_RADIO_OP_STATUS_ACTIVE && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); + RTIMER_BUSYWAIT_UNTIL(cmd_rx_adv->status == RF_CORE_RADIO_OP_STATUS_ACTIVE, + RF_CORE_ENTER_RX_TIMEOUT); /* Wait to enter RX */ if(cmd_rx_adv->status != RF_CORE_RADIO_OP_STATUS_ACTIVE) { @@ -506,13 +509,16 @@ rx_off_prop(void) return RF_CORE_CMD_OK; } + /* Wait for ongoing ACK TX to finish */ + RTIMER_BUSYWAIT_UNTIL(!transmitting(), RF_CORE_TX_FINISH_TIMEOUT); + /* Send a CMD_ABORT command to RF Core */ if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_ABORT), &cmd_status) != RF_CORE_CMD_OK) { PRINTF("rx_off_prop: CMD_ABORT status=0x%08lx\n", cmd_status); /* Continue nonetheless */ } - while(rf_is_on()); + RTIMER_BUSYWAIT_UNTIL(!rf_is_on(), RF_CORE_TURN_OFF_TIMEOUT); if(smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_STOPPED || smartrf_settings_cmd_prop_rx_adv.status == PROP_DONE_ABORT) { @@ -583,8 +589,8 @@ soft_off_prop(void) return; } - while((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) == - RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING); + RTIMER_BUSYWAIT_UNTIL((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) != + RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING, RF_CORE_TURN_OFF_TIMEOUT); } /*---------------------------------------------------------------------------*/ static uint8_t @@ -606,6 +612,8 @@ soft_on_prop(void) static const rf_core_primary_mode_t mode_prop = { soft_off_prop, soft_on_prop, + rf_is_on, + RAT_TIMESTAMP_OFFSET_SUB_GHZ }; /*---------------------------------------------------------------------------*/ static int @@ -637,10 +645,15 @@ init(void) return RF_CORE_CMD_ERROR; } + /* Enable the "sync word seen" interrupt */ + ti_lib_rfc_hw_int_enable(RFC_DBELL_RFHWIEN_MDMSOFT); + ENERGEST_ON(ENERGEST_TYPE_LISTEN); rf_core_primary_mode_register(&mode_prop); + rf_core_rat_init(); + process_start(&rf_core_process, NULL); return 1; @@ -701,7 +714,7 @@ transmit(unsigned short transmit_len) rx_off_prop(); /* Enable the LAST_COMMAND_DONE interrupt to wake us up */ - rf_core_cmd_done_en(false, false); + rf_core_cmd_done_en(false); ret = rf_core_send_cmd((uint32_t)cmd_tx_adv, &cmd_status); @@ -714,7 +727,14 @@ transmit(unsigned short transmit_len) /* Idle away while the command is running */ while((cmd_tx_adv->status & RF_CORE_RADIO_OP_MASKED_STATUS) == RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING) { - lpm_sleep(); + /* Note: for now sleeping while Tx'ing in polling mode is disabled. + * To enable it: + * 1) make the `lpm_sleep()` call here unconditional; + * 2) change the radio ISR priority to allow radio ISR to interrupt rtimer ISR. + */ + if(!rf_core_poll_mode) { + lpm_sleep(); + } } if(cmd_tx_adv->status == RF_CORE_RADIO_OP_STATUS_PROP_DONE_OK) { @@ -743,7 +763,7 @@ transmit(unsigned short transmit_len) * Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it * except when we are transmitting */ - rf_core_cmd_done_dis(false); + rf_core_cmd_done_dis(); /* Workaround. Set status to IDLE */ cmd_tx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE; @@ -764,47 +784,98 @@ send(const void *payload, unsigned short payload_len) return transmit(payload_len); } /*---------------------------------------------------------------------------*/ -static int -read_frame(void *buf, unsigned short buf_len) +static void +release_data_entry(void) { - int_master_status_t status; rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; uint8_t *data_ptr = &entry->data; - int len = 0; + int_master_status_t interrupt_status; - if(entry->status == DATA_ENTRY_STATUS_FINISHED) { + /* Clear the length field (2 bytes) */ + data_ptr[0] = 0; + data_ptr[1] = 0; - /* - * First 2 bytes in the data entry are the length. - * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) - * This length includes all of those. - */ - len = (*(uint16_t *)data_ptr); - data_ptr += 2; - len -= 2; + /* Set status to 0 "Pending" in element */ + entry->status = DATA_ENTRY_STATUS_PENDING; + rx_read_entry = entry->pNextEntry; - if(len > 0) { - if(len <= buf_len) { - memcpy(buf, data_ptr, len); - } - - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (int8_t)data_ptr[len]); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, 0x7F); - } - - /* Move read entry pointer to next entry */ - rx_read_entry = entry->pNextEntry; - entry->status = DATA_ENTRY_STATUS_PENDING; - } - - status = critical_enter(); - if(rx_is_full) { - rx_is_full = false; + interrupt_status = critical_enter(); + if(rf_core_rx_is_full) { + rf_core_rx_is_full = false; PRINTF("RXQ was full, re-enabling radio!\n"); rx_on_prop(); } - critical_exit(status); - + critical_exit(interrupt_status); + +} +/*---------------------------------------------------------------------------*/ +static int +read_frame(void *buf, unsigned short buf_len) +{ + rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; + uint8_t *data_ptr = &entry->data; + int len = 0; + uint32_t rat_timestamp; + + /* wait for entry to become finished */ + rtimer_clock_t t0 = RTIMER_NOW(); + while(entry->status == DATA_ENTRY_STATUS_BUSY + && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (RTIMER_SECOND / 50))); + + /* Make sure the flag is reset */ + is_receiving_packet = 0; + + if(entry->status != DATA_ENTRY_STATUS_FINISHED) { + /* No available data */ + return 0; + } + + /* + * First 2 bytes in the data entry are the length. + * Our data entry consists of: + * Payload + RSSI (1 byte) + Timestamp (4 bytes) + Status (1 byte) + * This length includes all of those. + */ + len = (*(uint16_t *)data_ptr); + + if(len <= RX_BUF_METADATA_SIZE) { + PRINTF("RF: too short!"); + + release_data_entry(); + return 0; + } + + data_ptr += 2; + len -= RX_BUF_METADATA_SIZE; + + if(len > buf_len) { + PRINTF("RF: too long\n"); + + release_data_entry(); + return 0; + } + + memcpy(buf, data_ptr, len); + + /* get the RSSI and status */ + rf_core_last_rssi = (int8_t)data_ptr[len]; + rf_core_last_corr_lqi = data_ptr[len + 5]; + + /* get the timestamp */ + memcpy(&rat_timestamp, data_ptr + len + 1, 4); + + rf_core_last_packet_timestamp = rf_core_convert_rat_to_rtimer(rat_timestamp); + + if(!rf_core_poll_mode) { + /* Not in poll mode: packetbuf should not be accessed in interrupt context. + * In poll mode, the last packet RSSI and link quality can be obtained through + * RADIO_PARAM_LAST_RSSI and RADIO_PARAM_LAST_LINK_QUALITY */ + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rf_core_last_rssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, rf_core_last_corr_lqi); + } + + release_data_entry(); + return len; } /*---------------------------------------------------------------------------*/ @@ -813,14 +884,14 @@ channel_clear(void) { uint8_t was_off = 0; uint32_t cmd_status; - int8_t rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; + int8_t rssi = RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; /* * If we are in the middle of a BLE operation, we got called by ContikiMAC * from within an interrupt context. Indicate a clear channel */ if(rf_ble_is_active() == RF_BLE_ACTIVE) { - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } if(!rf_core_is_accessible()) { @@ -830,16 +901,16 @@ channel_clear(void) if(was_off) { off(); } - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } } else { if(transmitting()) { PRINTF("channel_clear: called while in TX\n"); - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } } - while(rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { + while(rssi == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_GET_RSSI), &cmd_status) != RF_CORE_CMD_OK) { break; @@ -853,10 +924,10 @@ channel_clear(void) } if(rssi >= rssi_threshold) { - return RF_CCA_BUSY; + return RF_CORE_CCA_BUSY; } - return RF_CCA_CLEAR; + return RF_CORE_CCA_CLEAR; } /*---------------------------------------------------------------------------*/ static int @@ -866,11 +937,23 @@ receiving_packet(void) return 0; } - if(channel_clear() == RF_CCA_CLEAR) { - return 0; + if(!is_receiving_packet) { + /* Look for the modem synchronization word detection interrupt flag. + * This flag is raised when the synchronization word is received. + */ + if(HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFHWIFG) & RFC_DBELL_RFHWIFG_MDMSOFT) { + is_receiving_packet = 1; + } + } else { + /* After the start of the packet: reset the Rx flag once the channel gets clear */ + is_receiving_packet = (channel_clear() == RF_CORE_CCA_BUSY); + if(!is_receiving_packet) { + /* Clear the modem sync flag */ + ti_lib_rfc_hw_int_clear(RFC_DBELL_RFHWIFG_MDMSOFT); + } } - return 1; + return is_receiving_packet; } /*---------------------------------------------------------------------------*/ static int @@ -881,9 +964,12 @@ pending_packet(void) /* Go through all RX buffers and check their status */ do { - if(entry->status == DATA_ENTRY_STATUS_FINISHED) { - rv += 1; - process_poll(&rf_core_process); + if(entry->status == DATA_ENTRY_STATUS_FINISHED + || entry->status == DATA_ENTRY_STATUS_BUSY) { + rv = 1; + if(!rf_core_poll_mode) { + process_poll(&rf_core_process); + } } entry = (rfc_dataEntry_t *)entry->pNextEntry; @@ -904,18 +990,18 @@ on(void) return RF_CORE_CMD_OK; } - /* - * Request the HF XOSC as the source for the HF clock. Needed before we can - * use the FS. This will only request, it will _not_ perform the switch. - */ - oscillators_request_hf_xosc(); - if(rf_is_on()) { PRINTF("on: We were on. PD=%u, RX=0x%04x \n", rf_core_is_accessible(), smartrf_settings_cmd_prop_rx_adv.status); return RF_CORE_CMD_OK; } + /* + * Request the HF XOSC as the source for the HF clock. Needed before we can + * use the FS. This will only request, it will _not_ perform the switch. + */ + oscillators_request_hf_xosc(); + if(!rf_core_is_accessible()) { if(rf_core_power_up() != RF_CORE_CMD_OK) { PRINTF("on: rf_core_power_up() failed\n"); @@ -958,7 +1044,7 @@ on(void) } } - rf_core_setup_interrupts(false); + rf_core_setup_interrupts(); init_rx_buffers(); @@ -985,6 +1071,9 @@ on(void) static int off(void) { + int i; + rfc_dataEntry_t *entry; + /* * If we are in the middle of a BLE operation, we got called by ContikiMAC * from within an interrupt context. Abort, but pretend everything is OK. @@ -998,15 +1087,39 @@ off(void) ENERGEST_OFF(ENERGEST_TYPE_LISTEN); +#if !CC2650_FAST_RADIO_STARTUP /* Switch HF clock source to the RCOSC to preserve power */ oscillators_switch_to_hf_rc(); +#endif /* We pulled the plug, so we need to restore the status manually */ smartrf_settings_cmd_prop_rx_adv.status = RF_CORE_RADIO_OP_STATUS_IDLE; + /* + * Just in case there was an ongoing RX (which started after we begun the + * shutdown sequence), we don't want to leave the buffer in state == ongoing + */ + for(i = 0; i < PROP_MODE_RX_BUF_CNT; i++) { + entry = (rfc_dataEntry_t *)rx_buf[i]; + if(entry->status == DATA_ENTRY_STATUS_BUSY) { + entry->status = DATA_ENTRY_STATUS_PENDING; + } + } + return RF_CORE_CMD_OK; } /*---------------------------------------------------------------------------*/ +/* Enable or disable CCA before sending */ +static radio_result_t +set_send_on_cca(uint8_t enable) +{ + if(enable) { + /* this driver does not have support for CCA on Tx */ + return RADIO_RESULT_NOT_SUPPORTED; + } + return RADIO_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ static radio_result_t get_value(radio_param_t param, radio_value_t *value) { @@ -1022,6 +1135,15 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_CHANNEL: *value = (radio_value_t)get_channel(); return RADIO_RESULT_OK; + case RADIO_PARAM_RX_MODE: + *value = 0; + if(rf_core_poll_mode) { + *value |= RADIO_RX_MODE_POLL_MODE; + } + return RADIO_RESULT_OK; + case RADIO_PARAM_TX_MODE: + *value = 0; + return RADIO_RESULT_OK; case RADIO_PARAM_TXPOWER: *value = get_tx_power(); return RADIO_RESULT_OK; @@ -1031,7 +1153,7 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_RSSI: *value = get_rssi(); - if(*value == RF_CMD_CCA_REQ_RSSI_UNKNOWN) { + if(*value == RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN) { return RADIO_RESULT_ERROR; } else { return RADIO_RESULT_OK; @@ -1048,6 +1170,28 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_CONST_TXPOWER_MAX: *value = OUTPUT_POWER_MAX; return RADIO_RESULT_OK; + case RADIO_PARAM_LAST_RSSI: + *value = rf_core_last_rssi; + return RADIO_RESULT_OK; + case RADIO_PARAM_LAST_LINK_QUALITY: + *value = rf_core_last_corr_lqi; + return RADIO_RESULT_OK; + case RADIO_CONST_PHY_OVERHEAD: + /* 2 header bytes, 2 or 4 bytes CRC */ + *value = (radio_value_t)(DOT_4G_PHR_LEN + CRC_LEN); + return RADIO_RESULT_OK; + case RADIO_CONST_BYTE_AIR_TIME: + *value = (radio_value_t)RADIO_BYTE_AIR_TIME; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_TX: + *value = (radio_value_t)RADIO_DELAY_BEFORE_TX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_RX: + *value = (radio_value_t)RADIO_DELAY_BEFORE_RX; + return RADIO_RESULT_OK; + case RADIO_CONST_DELAY_BEFORE_DETECT: + *value = (radio_value_t)RADIO_DELAY_BEFORE_DETECT; + return RADIO_RESULT_OK; default: return RADIO_RESULT_NOT_SUPPORTED; } @@ -1056,8 +1200,8 @@ get_value(radio_param_t param, radio_value_t *value) static radio_result_t set_value(radio_param_t param, radio_value_t value) { - uint8_t was_off = 0; radio_result_t rv = RADIO_RESULT_OK; + uint8_t old_poll_mode; switch(param) { case RADIO_PARAM_POWER_MODE: @@ -1087,6 +1231,25 @@ set_value(radio_param_t param, radio_value_t value) set_channel((uint8_t)value); break; + + case RADIO_PARAM_RX_MODE: + if(value & ~(RADIO_RX_MODE_POLL_MODE)) { + return RADIO_RESULT_INVALID_VALUE; + } + + old_poll_mode = rf_core_poll_mode; + rf_core_poll_mode = (value & RADIO_RX_MODE_POLL_MODE) != 0; + if(rf_core_poll_mode == old_poll_mode) { + return RADIO_RESULT_OK; + } + break; + + case RADIO_PARAM_TX_MODE: + if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) { + return RADIO_RESULT_INVALID_VALUE; + } + return set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0); + case RADIO_PARAM_TXPOWER: if(value < TX_POWER_DRIVER[get_tx_power_array_last_element()].dbm || value > OUTPUT_POWER_MAX) { @@ -1103,8 +1266,7 @@ set_value(radio_param_t param, radio_value_t value) } return RADIO_RESULT_OK; - case RADIO_PARAM_RX_MODE: - return RADIO_RESULT_OK; + case RADIO_PARAM_CCA_THRESHOLD: rssi_threshold = (int8_t)value; break; @@ -1112,28 +1274,29 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_NOT_SUPPORTED; } - /* If we reach here we had no errors. Apply new settings */ + /* If off, the new configuration will be applied the next time radio is started */ if(!rf_is_on()) { - was_off = 1; - if(on() != RF_CORE_CMD_OK) { - PRINTF("set_value: on() failed (2)\n"); - return RADIO_RESULT_ERROR; - } + return RADIO_RESULT_OK; } + /* If we reach here we had no errors. Apply new settings */ if(rx_off_prop() != RF_CORE_CMD_OK) { PRINTF("set_value: rx_off_prop() failed\n"); rv = RADIO_RESULT_ERROR; } - if(soft_on_prop() != RF_CORE_CMD_OK) { - PRINTF("set_value: rx_on_prop() failed\n"); - rv = RADIO_RESULT_ERROR; + /* Restart the radio timer (RAT). + This causes resynchronization between RAT and RTC: useful for TSCH. */ + if(rf_core_restart_rat() != RF_CORE_CMD_OK) { + PRINTF("set_value: rf_core_restart_rat() failed\n"); + /* do not set the error */ + } else { + rf_core_check_rat_overflow(); } - /* If we were off, turn back off */ - if(was_off) { - off(); + if(soft_on_prop() != RF_CORE_CMD_OK) { + PRINTF("set_value: soft_on_prop() failed\n"); + rv = RADIO_RESULT_ERROR; } return rv; @@ -1142,6 +1305,15 @@ set_value(radio_param_t param, radio_value_t value) 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 = rf_core_last_packet_timestamp; + + return RADIO_RESULT_OK; + } + return RADIO_RESULT_NOT_SUPPORTED; } /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c index faa8f808b..db3c6adb3 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.c @@ -99,12 +99,37 @@ static rfc_radioOp_t *last_radio_op = NULL; /* A struct holding pointers to the primary mode's abort() and restore() */ static const rf_core_primary_mode_t *primary_mode = NULL; /*---------------------------------------------------------------------------*/ +/* RAT has 32-bit register, overflows once 18 minutes */ +#define RAT_RANGE 4294967296ull +/* approximate value */ +#define RAT_OVERFLOW_PERIOD_SECONDS (60 * 18) + +/* how often to check for the overflow, as a minimum */ +#define RAT_OVERFLOW_TIMER_INTERVAL (CLOCK_SECOND * RAT_OVERFLOW_PERIOD_SECONDS / 3) + /* Radio timer (RAT) offset as compared to the rtimer counter (RTC) */ -int32_t rat_offset = 0; -static bool rat_offset_known = false; +static int32_t rat_offset; +static bool rat_offset_known; + +/* Value during the last read of the RAT register */ +static uint32_t rat_last_value; + +/* For RAT overflow handling */ +static struct ctimer rat_overflow_timer; +static volatile uint32_t rat_overflow_counter; +static rtimer_clock_t rat_last_overflow; + +static void rat_overflow_check_timer_cb(void *); +/*---------------------------------------------------------------------------*/ +volatile int8_t rf_core_last_rssi = RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN; +volatile uint8_t rf_core_last_corr_lqi = 0; +volatile uint32_t rf_core_last_packet_timestamp = 0; +/*---------------------------------------------------------------------------*/ +/* Are we currently in poll mode? */ +uint8_t rf_core_poll_mode = 0; /*---------------------------------------------------------------------------*/ /* Buffer full flag */ -volatile bool rx_is_full = false; +volatile bool rf_core_rx_is_full = false; /*---------------------------------------------------------------------------*/ PROCESS(rf_core_process, "CC13xx / CC26xx RF driver"); /*---------------------------------------------------------------------------*/ @@ -451,10 +476,10 @@ rf_core_restart_rat(void) } /*---------------------------------------------------------------------------*/ void -rf_core_setup_interrupts(bool poll_mode) +rf_core_setup_interrupts(void) { bool interrupts_disabled; - const uint32_t enabled_irqs = poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; + const uint32_t enabled_irqs = rf_core_poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; /* We are already turned on by the caller, so this should not happen */ if(!rf_core_is_accessible()) { @@ -485,19 +510,19 @@ rf_core_setup_interrupts(bool poll_mode) } /*---------------------------------------------------------------------------*/ void -rf_core_cmd_done_en(bool fg, bool poll_mode) +rf_core_cmd_done_en(bool fg) { uint32_t irq = fg ? IRQ_LAST_FG_COMMAND_DONE : IRQ_LAST_COMMAND_DONE; - const uint32_t enabled_irqs = poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; + const uint32_t enabled_irqs = rf_core_poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = enabled_irqs; HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = enabled_irqs | irq; } /*---------------------------------------------------------------------------*/ void -rf_core_cmd_done_dis(bool poll_mode) +rf_core_cmd_done_dis(void) { - const uint32_t enabled_irqs = poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; + const uint32_t enabled_irqs = rf_core_poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS; HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = enabled_irqs; } /*---------------------------------------------------------------------------*/ @@ -544,6 +569,123 @@ rf_core_primary_mode_restore() return RF_CORE_CMD_ERROR; } /*---------------------------------------------------------------------------*/ +uint8_t +rf_core_rat_init(void) +{ + rat_last_value = HWREG(RFC_RAT_BASE + RATCNT); + + ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_TIMER_INTERVAL, + rat_overflow_check_timer_cb, NULL); + + return 1; +} +/*---------------------------------------------------------------------------*/ +uint8_t +rf_core_check_rat_overflow(void) +{ + uint32_t rat_current_value; + uint8_t interrupts_disabled; + + /* Bail out if the RF is not on */ + if(primary_mode == NULL || !primary_mode->is_on()) { + return 0; + } + + interrupts_disabled = ti_lib_int_master_disable(); + + rat_current_value = HWREG(RFC_RAT_BASE + RATCNT); + if(rat_current_value + RAT_RANGE / 4 < rat_last_value) { + /* Overflow detected */ + rat_last_overflow = RTIMER_NOW(); + rat_overflow_counter++; + } + rat_last_value = rat_current_value; + + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static void +rat_overflow_check_timer_cb(void *unused) +{ + uint8_t success = 0; + uint8_t was_off = 0; + + if(primary_mode != NULL) { + + if(!primary_mode->is_on()) { + was_off = 1; + if(NETSTACK_RADIO.on() != RF_CORE_CMD_OK) { + PRINTF("overflow: on() failed\n"); + ctimer_set(&rat_overflow_timer, CLOCK_SECOND, + rat_overflow_check_timer_cb, NULL); + return; + } + } + + success = rf_core_check_rat_overflow(); + + if(was_off) { + NETSTACK_RADIO.off(); + } + } + + if(success) { + /* Retry after half of the interval */ + ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_TIMER_INTERVAL, + rat_overflow_check_timer_cb, NULL); + } else { + /* Retry sooner */ + ctimer_set(&rat_overflow_timer, CLOCK_SECOND, + rat_overflow_check_timer_cb, NULL); + } +} +/*---------------------------------------------------------------------------*/ +uint32_t +rf_core_convert_rat_to_rtimer(uint32_t rat_timestamp) +{ + uint64_t rat_timestamp64; + uint32_t adjusted_overflow_counter; + uint8_t was_off = 0; + + if(primary_mode == NULL) { + PRINTF("rf_core_convert_rat_to_rtimer: not initialized\n"); + return 0; + } + + if(!primary_mode->is_on()) { + was_off = 1; + NETSTACK_RADIO.on(); + } + + rf_core_check_rat_overflow(); + + if(was_off) { + NETSTACK_RADIO.off(); + } + + adjusted_overflow_counter = rat_overflow_counter; + + /* if the timestamp is large and the last oveflow was recently, + assume that the timestamp refers to the time before the overflow */ + if(rat_timestamp > (uint32_t)(RAT_RANGE * 3 / 4)) { + if(RTIMER_CLOCK_LT(RTIMER_NOW(), + rat_last_overflow + RAT_OVERFLOW_PERIOD_SECONDS * RTIMER_SECOND / 4)) { + adjusted_overflow_counter--; + } + } + + /* add the overflowed time to the timestamp */ + rat_timestamp64 = rat_timestamp + RAT_RANGE * adjusted_overflow_counter; + /* correct timestamp so that it refers to the end of the SFD */ + rat_timestamp64 += primary_mode->sfd_timestamp_offset; + + return RADIO_TO_RTIMER(rat_timestamp64 - rat_offset); +} +/*---------------------------------------------------------------------------*/ PROCESS_THREAD(rf_core_process, ev, data) { int len; @@ -582,11 +724,11 @@ cc26xx_rf_cpe1_isr(void) return; } } - + if(HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & IRQ_RX_BUF_FULL) { PRINTF("\nRF: BUF_FULL\n\n"); /* set a flag that the buffer is full*/ - rx_is_full = true; + rf_core_rx_is_full = true; /* make sure read_frame() will be called to make space in RX buffer */ process_poll(&rf_core_process); /* Clear the IRQ_RX_BUF_FULL interrupt flag by writing zero to bit */ diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h index c97ab0f8a..6cb65672d 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h @@ -133,6 +133,17 @@ typedef struct rf_core_primary_mode_s { * \return RF_CORE_CMD_OK or RF_CORE_CMD_ERROR */ uint8_t (*restore)(void); + + /** + * \brief A pointer to a function that checks if the radio is on + * \return 1 or 0 + */ + uint8_t (*is_on)(void); + + /** + * \brief Offset of the end of SFD when compared to the radio HW-generated timestamp + */ + int16_t sfd_timestamp_offset; } rf_core_primary_mode_t; /*---------------------------------------------------------------------------*/ /* RF Command status constants - Correspond to values in the CMDSTA register */ @@ -263,12 +274,65 @@ typedef struct rf_core_primary_mode_s { /* Radio timer register */ #define RATCNT 0x00000004 /*---------------------------------------------------------------------------*/ -/* Buffer full flag */ -extern volatile bool rx_is_full; +/* Special value returned by CMD_IEEE_CCA_REQ when an RSSI is not available */ +#define RF_CORE_CMD_CCA_REQ_RSSI_UNKNOWN -128 + +/* Used for the return value of channel_clear */ +#define RF_CORE_CCA_CLEAR 1 +#define RF_CORE_CCA_BUSY 0 + +/* Used as an error return value for get_cca_info */ +#define RF_CORE_GET_CCA_INFO_ERROR 0xFF + +/* + * Values of the individual bits of the ccaInfo field in CMD_IEEE_CCA_REQ's + * status struct + */ +#define RF_CORE_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 00 */ +#define RF_CORE_CMD_CCA_REQ_CCA_STATE_BUSY 1 /* 01 */ +#define RF_CORE_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ + +#define RF_CORE_CMD_CCA_REQ_CCA_CORR_IDLE (0 << 4) +#define RF_CORE_CMD_CCA_REQ_CCA_CORR_BUSY (1 << 4) +#define RF_CORE_CMD_CCA_REQ_CCA_CORR_INVALID (3 << 4) +#define RF_CORE_CMD_CCA_REQ_CCA_CORR_MASK (3 << 4) + +#define RF_CORE_CMD_CCA_REQ_CCA_SYNC_BUSY (1 << 6) +/*---------------------------------------------------------------------------*/ +#define RF_CORE_RX_BUF_INCLUDE_CRC 0 +#define RF_CORE_RX_BUF_INCLUDE_RSSI 1 +#define RF_CORE_RX_BUF_INCLUDE_CORR 1 +#define RF_CORE_RX_BUF_INCLUDE_TIMESTAMP 1 +/*---------------------------------------------------------------------------*/ +/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ +#define RF_CORE_TX_TIMEOUT (RTIMER_SECOND >> 11) + +/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ +#define RF_CORE_ENTER_RX_TIMEOUT (RTIMER_SECOND >> 10) + +/* How long to wait for the RF to react on CMD_ABORT: around 1 msec */ +#define RF_CORE_TURN_OFF_TIMEOUT (RTIMER_SECOND >> 10) + +/* How long to wait for the RF to finish TX of a packet or an ACK */ +#define RF_CORE_TX_FINISH_TIMEOUT (RTIMER_SECOND >> 7) + /*---------------------------------------------------------------------------*/ /* Make the main driver process visible to mode drivers */ PROCESS_NAME(rf_core_process); /*---------------------------------------------------------------------------*/ +/* Buffer full flag */ +extern volatile bool rf_core_rx_is_full; +/*---------------------------------------------------------------------------*/ +/* RSSI of the last read frame */ +extern volatile int8_t rf_core_last_rssi; +/* Correlation/LQI of the last read frame */ +extern volatile uint8_t rf_core_last_corr_lqi; +/* SFD timestamp of the last read frame, in rtimer ticks */ +extern volatile uint32_t rf_core_last_packet_timestamp; +/*---------------------------------------------------------------------------*/ +/* Are we currently in poll mode? */ +extern uint8_t rf_core_poll_mode; +/*---------------------------------------------------------------------------*/ /** * \brief Check whether the RF core is accessible * \retval RF_CORE_ACCESSIBLE The core is powered and ready for access @@ -383,20 +447,19 @@ uint8_t rf_core_boot(void); /** * \brief Setup RF core interrupts */ -void rf_core_setup_interrupts(bool poll_mode); +void rf_core_setup_interrupts(void); /** * \brief Enable interrupt on command done. * \param fg set true to enable irq on foreground command done and false for * background commands or if not in ieee mode. - * \param poll_mode true if the driver is in poll mode * * This is used within TX routines in order to be able to sleep the CM3 and * wake up after TX has finished * * \sa rf_core_cmd_done_dis() */ -void rf_core_cmd_done_en(bool fg, bool poll_mode); +void rf_core_cmd_done_en(bool fg); /** * \brief Disable the LAST_CMD_DONE and LAST_FG_CMD_DONE interrupts. @@ -405,7 +468,7 @@ void rf_core_cmd_done_en(bool fg, bool poll_mode); * * \sa rf_core_cmd_done_en() */ -void rf_core_cmd_done_dis(bool poll_mode); +void rf_core_cmd_done_dis(void); /** * \brief Returns a pointer to the most recent proto-dependent Radio Op @@ -467,6 +530,22 @@ void rf_core_primary_mode_abort(void); * \brief Abort the currently running primary radio op */ uint8_t rf_core_primary_mode_restore(void); + +/** + * \brief Initialize the RAT to RTC conversion machinery + */ +uint8_t rf_core_rat_init(void); + +/** + * \brief Check if RAT overflow has occured and increment the overflow counter if so + */ +uint8_t rf_core_check_rat_overflow(void); + +/** + * \brief Convert from RAT timestamp to rtimer ticks + */ +uint32_t rf_core_convert_rat_to_rtimer(uint32_t rat_timestamp); + /*---------------------------------------------------------------------------*/ #endif /* RF_CORE_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index edc989378..d158c802c 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -77,9 +77,7 @@ /* The approximate number of slots per second */ #define TSCH_SLOTS_PER_SECOND (1000000 / tsch_timing_us[tsch_ts_timeslot_length]) -/* Calculate packet tx/rx duration in rtimer ticks based on sent - * packet len in bytes with 802.15.4 250kbps data rate. - * One byte = 32us. Add two bytes for CRC and one for len field */ +/* Calculate packet tx/rx duration in rtimer ticks based on packet length in bytes. */ #define TSCH_PACKET_DURATION(len) US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * ((len) + RADIO_PHY_OVERHEAD)) /* Convert rtimer ticks to clock and vice versa */