nes-proj/arch/cpu/simplelink-cc13xx-cc26xx/rf/prop-mode.c

727 lines
22 KiB
C
Raw Normal View History

2018-02-08 10:45:47 +00:00
/*
2018-02-15 11:48:02 +00:00
* Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
2018-02-08 10:45:47 +00:00
* 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.
*/
/**
2018-07-23 12:35:37 +00:00
* \addtogroup cc13xx-cc26xx-rf
* @{
*
* \defgroup cc13xx-cc26xx-rf-prop Prop-mode driver for CC13xx/CC26xx
*
2018-02-08 10:45:47 +00:00
* @{
*
* \file
2018-07-23 12:35:37 +00:00
* Implementation of the CC13xx/CC26xx prop-mode NETSTACK_RADIO driver.
* \author
* Edvard Pettersen <e.pettersen@ti.com>
2018-02-08 10:45:47 +00:00
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "net/packetbuf.h"
#include "net/netstack.h"
#include "sys/energest.h"
#include "sys/clock.h"
#include "sys/rtimer.h"
#include "sys/cc.h"
2018-02-09 11:50:55 +00:00
#include "dev/watchdog.h"
2018-02-08 10:45:47 +00:00
/*---------------------------------------------------------------------------*/
/* RF Core Mailbox API */
#include <ti/devices/DeviceFamily.h>
#include DeviceFamily_constructPath(driverlib/rf_mailbox.h)
#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h)
#include DeviceFamily_constructPath(driverlib/rf_data_entry.h)
#include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h)
#include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)
2018-02-08 10:45:47 +00:00
#include <ti/drivers/rf/RF.h>
2018-02-15 11:48:02 +00:00
/*---------------------------------------------------------------------------*/
/* Platform RF dev */
#include "rf/rf.h"
#include "rf/dot-15-4g.h"
#include "rf/sched.h"
#include "rf/data-queue.h"
#include "rf/tx-power.h"
#include "rf/settings.h"
2018-02-08 10:45:47 +00:00
/*---------------------------------------------------------------------------*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
2018-02-09 11:50:55 +00:00
#include <assert.h>
2018-02-08 10:45:47 +00:00
/*---------------------------------------------------------------------------*/
2018-07-12 08:44:14 +00:00
/* Log configuration */
#include "sys/log.h"
#define LOG_MODULE "Radio"
2018-07-12 08:44:14 +00:00
#define LOG_LEVEL LOG_LEVEL_NONE
/*---------------------------------------------------------------------------*/
#undef CLAMP
#define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin))
/*---------------------------------------------------------------------------*/
/* Configuration parameters */
2018-07-25 16:16:27 +00:00
#define PROP_MODE_DYN_WHITENER PROP_MODE_CONF_DW
#define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16
2018-07-25 16:16:27 +00:00
#define PROP_MODE_CENTER_FREQ PROP_MODE_CONF_CENTER_FREQ
#define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER
#define PROP_MODE_CCA_RSSI_THRESHOLD PROP_MODE_CONF_CCA_RSSI_THRESHOLD
2018-02-08 10:45:47 +00:00
/*---------------------------------------------------------------------------*/
2018-06-19 12:55:18 +00:00
/* Used for checking result of CCA_REQ command */
typedef enum {
2018-07-25 16:16:27 +00:00
CCA_STATE_IDLE = 0,
CCA_STATE_BUSY = 1,
CCA_STATE_INVALID = 2
} cca_state_t;
2018-02-08 10:45:47 +00:00
/*---------------------------------------------------------------------------*/
/* Defines and variables related to the .15.4g PHY HDR */
#define DOT_4G_MAX_FRAME_LEN 2047
#define DOT_4G_PHR_LEN 2
2018-02-08 10:45:47 +00:00
/* PHY HDR bits */
#define DOT_4G_PHR_CRC16 0x10
#define DOT_4G_PHR_DW 0x08
2018-02-08 10:45:47 +00:00
#if PROP_MODE_USE_CRC16
/* CRC16 */
#define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16
#define CRC_LEN 2
2018-02-08 10:45:47 +00:00
#else
/* CRC32 */
#define DOT_4G_PHR_CRC_BIT 0
#define CRC_LEN 4
2018-06-15 14:37:51 +00:00
#endif /* PROP_MODE_USE_CRC16 */
2018-02-08 10:45:47 +00:00
2018-07-25 16:16:27 +00:00
#if PROP_MODE_DYN_WHITENER
#define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW
2018-02-08 10:45:47 +00:00
#else
#define DOT_4G_PHR_DW_BIT 0
2018-02-08 10:45:47 +00:00
#endif
/*---------------------------------------------------------------------------*/
/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */
2018-07-09 18:13:01 +00:00
#define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10)
/* How long to wait for the rx read entry to become ready */
#define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250)
2018-02-08 10:45:47 +00:00
/*---------------------------------------------------------------------------*/
2018-06-15 14:37:51 +00:00
/* TX buf configuration */
#define TX_BUF_HDR_LEN 2
#define TX_BUF_PAYLOAD_LEN 180
#define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN)
2018-02-08 10:45:47 +00:00
/*---------------------------------------------------------------------------*/
2018-06-19 12:55:18 +00:00
/* Size of the Length field in Data Entry, two bytes in this case */
2018-07-25 16:16:27 +00:00
typedef uint16_t lensz_t;
#define FRAME_OFFSET sizeof(lensz_t)
#define FRAME_SHAVE 2 /**< RSSI (1) + Status (1) */
2018-06-15 14:37:51 +00:00
/*---------------------------------------------------------------------------*/
/* Constants used when calculating the LQI from the RSSI */
#define RX_SENSITIVITY_DBM -110
#define RX_SATURATION_DBM 10
#define ED_MIN_DBM_ABOVE_RX_SENSITIVITY 10
#define ED_MAX 0xFF
2018-02-08 10:45:47 +00:00
#define ED_RF_POWER_MIN_DBM (RX_SENSITIVITY_DBM + ED_MIN_DBM_ABOVE_RX_SENSITIVITY)
#define ED_RF_POWER_MAX_DBM RX_SATURATION_DBM
2018-06-15 14:37:51 +00:00
/*---------------------------------------------------------------------------*/
2018-06-19 12:55:18 +00:00
/* RF Core typedefs */
2018-07-25 16:16:27 +00:00
typedef rfc_propRxOutput_t rx_output_t;
2018-06-15 14:37:51 +00:00
typedef struct {
/* Outgoing frame buffer */
2018-07-25 16:16:27 +00:00
uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4);
2018-02-08 10:45:47 +00:00
2018-06-15 14:37:51 +00:00
/* RX Statistics struct */
rx_output_t rx_stats;
2018-02-08 10:45:47 +00:00
2018-06-15 14:37:51 +00:00
/* RSSI Threshold */
2018-07-25 16:16:27 +00:00
int8_t rssi_threshold;
uint16_t channel;
2018-06-15 14:37:51 +00:00
/* Indicates RF is supposed to be on or off */
2018-07-25 16:16:27 +00:00
uint8_t rf_is_on;
2018-02-08 10:45:47 +00:00
2018-06-15 14:37:51 +00:00
/* RF driver */
2018-07-25 16:16:27 +00:00
RF_Handle rf_handle;
2018-06-15 14:37:51 +00:00
} prop_radio_t;
static prop_radio_t prop_radio;
2018-02-08 10:45:47 +00:00
/*---------------------------------------------------------------------------*/
/* Convenience macros for volatile access with the RF commands */
2018-06-15 14:37:51 +00:00
#define cmd_radio_setup (*(volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&rf_cmd_prop_radio_div_setup)
#define cmd_fs (*(volatile rfc_CMD_FS_t *) &rf_cmd_prop_fs)
#define cmd_tx (*(volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv)
#define cmd_rx (*(volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv)
/*---------------------------------------------------------------------------*/
2018-07-24 10:16:53 +00:00
static inline bool
tx_is_active(void)
{
return cmd_tx.status == ACTIVE;
}
/*---------------------------------------------------------------------------*/
2018-07-24 10:16:53 +00:00
static inline bool
rx_is_active(void)
{
return cmd_rx.status == ACTIVE;
}
2018-02-09 08:13:12 +00:00
/*---------------------------------------------------------------------------*/
2018-06-15 14:37:51 +00:00
static int on(void);
static int off(void);
2018-02-09 11:50:55 +00:00
/*---------------------------------------------------------------------------*/
static void
2018-07-09 18:13:01 +00:00
init_rf_params(void)
2018-02-09 11:50:55 +00:00
{
cmd_radio_setup.config.frontEndMode = RF_SUB_1_GHZ_FRONT_END_MODE;
cmd_radio_setup.config.biasMode = RF_SUB_1_GHZ_BIAS_MODE;
2018-07-25 16:16:27 +00:00
cmd_radio_setup.centerFreq = PROP_MODE_CENTER_FREQ;
cmd_radio_setup.loDivider = PROP_MODE_LO_DIVIDER;
2018-07-17 16:02:38 +00:00
2018-07-12 08:44:14 +00:00
data_queue_t *data_queue = data_queue_init(sizeof(lensz_t));
2018-07-09 18:13:01 +00:00
cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset;
2018-07-25 16:16:27 +00:00
cmd_rx.pQueue = data_queue;
cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats;
2018-02-09 11:50:55 +00:00
}
/*---------------------------------------------------------------------------*/
2018-07-09 18:13:01 +00:00
static int8_t
2018-02-08 10:45:47 +00:00
get_rssi(void)
{
2018-07-09 18:13:01 +00:00
rf_result_t res;
bool stop_rx = false;
int8_t rssi = RF_GET_RSSI_ERROR_VAL;
2018-07-09 18:13:01 +00:00
/* RX is required to be running in order to do a RSSI measurement */
if(!rx_is_active()) {
/* If RX is not pending, i.e. soon to be running, schedule the RX command */
if(cmd_rx.status != PENDING) {
res = netstack_sched_rx(false);
if(res != RF_RESULT_OK) {
LOG_ERR("RSSI measurement failed to schedule RX\n");
return res;
}
/* We only stop RX if we had to schedule it */
stop_rx = true;
2018-07-09 18:13:01 +00:00
}
2018-02-09 08:13:12 +00:00
/* Make sure RX is running before we continue, unless we timeout and fail */
RTIMER_BUSYWAIT_UNTIL(!rx_is_active(), TIMEOUT_ENTER_RX_WAIT);
2018-07-09 18:13:01 +00:00
if(!rx_is_active()) {
LOG_ERR("RSSI measurement failed to turn on RX, RX status=0x%04X\n", cmd_rx.status);
return RF_RESULT_ERROR;
}
2018-06-15 14:37:51 +00:00
}
2018-02-09 08:13:12 +00:00
/* Perform the RSSI measurement */
rssi = RF_getRssi(prop_radio.rf_handle);
if(stop_rx) {
2018-07-09 18:13:01 +00:00
netstack_stop_rx();
2018-06-15 14:37:51 +00:00
}
2018-02-09 08:13:12 +00:00
2018-06-15 14:37:51 +00:00
return rssi;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static uint8_t
get_channel(void)
{
2018-06-15 14:37:51 +00:00
uint32_t freq_khz = cmd_fs.frequency * 1000;
2018-02-09 08:13:12 +00:00
/*
* For some channels, fractFreq * 1000 / 65536 will return 324.99xx.
* Casting the result to uint32_t will truncate decimals resulting in the
* function returning channel - 1 instead of channel. Thus, we do a quick
* positive integer round up.
*/
2018-06-15 14:37:51 +00:00
freq_khz += (((cmd_fs.fractFreq * 1000) + 65535) / 65536);
2018-02-09 08:13:12 +00:00
2018-07-13 12:34:08 +00:00
return (uint8_t)((freq_khz - DOT_15_4G_CHAN0_FREQ) / DOT_15_4G_FREQ_SPACING);
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
2018-07-09 18:13:01 +00:00
static rf_result_t
set_channel(uint16_t channel)
2018-02-08 10:45:47 +00:00
{
2018-07-09 18:13:01 +00:00
rf_result_t res;
2018-02-08 10:45:47 +00:00
2018-07-23 12:35:37 +00:00
if(!dot_15_4g_chan_in_range(channel)) {
2018-07-25 14:59:28 +00:00
LOG_WARN("Supplied hannel %d is illegal, defaults to %d\n",
(int)channel, DOT_15_4G_DEFAULT_CHAN);
2018-07-17 16:02:38 +00:00
channel = DOT_15_4G_DEFAULT_CHAN;
2018-06-15 14:37:51 +00:00
}
2018-07-23 12:35:37 +00:00
if(channel == prop_radio.channel) {
2018-07-09 18:13:01 +00:00
/* We are already calibrated to this channel */
return RF_RESULT_OK;
2018-06-15 14:37:51 +00:00
}
2018-02-09 08:13:12 +00:00
2018-07-17 16:02:38 +00:00
const uint32_t new_freq = dot_15_4g_freq(channel);
2018-07-09 18:13:01 +00:00
const uint16_t freq = (uint16_t)(new_freq / 1000);
const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000);
2018-06-19 12:55:18 +00:00
2018-07-25 14:59:28 +00:00
LOG_DBG("Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n",
2018-07-25 16:16:27 +00:00
(int)channel, freq, frac, new_freq);
2018-02-08 10:45:47 +00:00
2018-07-09 18:13:01 +00:00
cmd_fs.frequency = freq;
cmd_fs.fractFreq = frac;
res = netstack_sched_fs();
2018-07-23 12:35:37 +00:00
if(res != RF_RESULT_OK) {
2018-07-09 18:13:01 +00:00
return res;
}
prop_radio.channel = channel;
return RF_RESULT_OK;
2018-06-19 12:55:18 +00:00
}
/*---------------------------------------------------------------------------*/
2018-06-15 14:37:51 +00:00
static uint8_t
calculate_lqi(int8_t rssi)
{
/*
* Note : Currently the LQI value is simply the energy detect measurement.
2018-06-15 14:37:51 +00:00
* A more accurate value could be derived by using the correlation
* value along with the RSSI value.
*/
2018-06-15 14:37:51 +00:00
rssi = CLAMP(rssi, ED_RF_POWER_MIN_DBM, ED_RF_POWER_MAX_DBM);
/*
* Create energy detect measurement by normalizing and scaling RF power level.
2018-06-15 14:37:51 +00:00
* Note : The division operation below is designed for maximum accuracy and
* best granularity. This is done by grouping the math operations to
* compute the entire numerator before doing any division.
*/
return (ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM);
2018-06-15 14:37:51 +00:00
}
/*---------------------------------------------------------------------------*/
2018-02-08 10:45:47 +00:00
static int
prepare(const void *payload, unsigned short payload_len)
{
2018-07-09 18:13:01 +00:00
const size_t len = MIN((size_t)payload_len,
(size_t)TX_BUF_PAYLOAD_LEN);
2018-02-08 10:45:47 +00:00
2018-06-15 14:37:51 +00:00
memcpy(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload, len);
return 0;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static int
transmit(unsigned short transmit_len)
{
2018-07-09 18:13:01 +00:00
rf_result_t res;
2018-06-15 14:37:51 +00:00
2018-07-23 12:35:37 +00:00
if(tx_is_active()) {
2018-07-25 14:59:28 +00:00
LOG_ERR("A transmission is already active\n");
2018-06-15 14:37:51 +00:00
return RADIO_TX_ERR;
}
2018-06-15 14:37:51 +00:00
/* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */
2018-07-09 18:13:01 +00:00
const uint16_t total_length = transmit_len + CRC_LEN;
/*
* Prepare the .15.4g PHY header
* MS=0, Length MSBits=0, DW and CRC configurable
* Total length = transmit_len (payload) + CRC length
*
* The Radio will flip the bits around, so tx_buf[0] must have the length
2018-07-09 18:13:01 +00:00
* LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0]
*/
2018-07-12 08:44:14 +00:00
prop_radio.tx_buf[0] = ((total_length >> 0) & 0xFF);
prop_radio.tx_buf[1] = ((total_length >> 8) & 0xFF) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT;
2018-02-09 11:50:55 +00:00
/* pktLen: Total number of bytes in the TX buffer, including the header if
* one exists, but not including the CRC (which is not present in the buffer) */
2018-06-15 14:37:51 +00:00
cmd_tx.pktLen = transmit_len + DOT_4G_PHR_LEN;
cmd_tx.pPkt = prop_radio.tx_buf;
2018-07-12 08:44:14 +00:00
res = netstack_sched_prop_tx();
2018-02-08 10:45:47 +00:00
2018-07-09 18:13:01 +00:00
return (res == RF_RESULT_OK)
2018-07-24 10:16:53 +00:00
? RADIO_TX_OK
: RADIO_TX_ERR;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static int
send(const void *payload, unsigned short payload_len)
{
2018-06-15 14:37:51 +00:00
prepare(payload, payload_len);
return transmit(payload_len);
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static int
2018-06-15 14:37:51 +00:00
read(void *buf, unsigned short buf_len)
2018-02-08 10:45:47 +00:00
{
2018-07-12 08:44:14 +00:00
volatile data_entry_t *data_entry = data_queue_current_entry();
2018-02-08 10:45:47 +00:00
const rtimer_clock_t t0 = RTIMER_NOW();
2018-07-12 08:44:14 +00:00
/* Only wait if the Radio is accessing the entry */
2018-07-23 12:35:37 +00:00
while((data_entry->status == DATA_ENTRY_BUSY) &&
2018-07-24 10:16:53 +00:00
RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)) ;
2018-07-23 12:35:37 +00:00
if(data_entry->status != DATA_ENTRY_FINISHED) {
2018-06-19 12:55:18 +00:00
/* No available data */
2018-07-23 07:37:23 +00:00
return -1;
2018-06-15 14:37:51 +00:00
}
2018-07-12 08:44:14 +00:00
/*
2018-07-23 07:37:23 +00:00
* lensz bytes (2) in the data entry are the length of the received frame.
* Data frame is on the following format:
* Length (2) + Payload (N) + RSSI (1) + Status (1)
* Data frame DOES NOT contain the following:
* no Header/PHY bytes
* no appended Received CRC bytes
* no Timestamp bytes
2018-07-23 07:37:23 +00:00
* Visual representation of frame format:
*
* +---------+---------+--------+--------+
* | 2 bytes | N bytes | 1 byte | 1 byte |
* +---------+---------+--------+--------+
* | Length | Payload | RSSI | Status |
* +---------+---------+--------+--------+
*
* Length bytes equal total length of entire frame excluding itself,
2018-07-12 08:44:14 +00:00
* Length = N + RSSI (1) + Status (1)
* = N + 2
2018-07-12 08:44:14 +00:00
* N = Length - 2
*/
2018-07-25 16:16:27 +00:00
uint8_t *const frame_ptr = (uint8_t *)&data_entry->data;
const lensz_t frame_len = *(lensz_t *)frame_ptr;
/* Sanity check that Frame is at least Frame Shave bytes long */
2018-07-23 12:35:37 +00:00
if(frame_len < FRAME_SHAVE) {
2018-07-25 14:59:28 +00:00
LOG_ERR("Received rame is too short, len=%d\n", frame_len);
2018-07-12 08:44:14 +00:00
data_queue_release_entry();
return 0;
}
2018-06-15 14:37:51 +00:00
const uint8_t *payload_ptr = frame_ptr + sizeof(lensz_t);
const unsigned short payload_len = (unsigned short)(frame_len - FRAME_SHAVE);
2018-06-15 14:37:51 +00:00
/* Sanity check that Payload fits in Buffer */
2018-07-23 12:35:37 +00:00
if(payload_len > buf_len) {
2018-07-25 14:59:28 +00:00
LOG_ERR("Payload of received frame is too large for local buffer, len=%d buf_len=%d\n",
payload_len, buf_len);
2018-07-12 08:44:14 +00:00
data_queue_release_entry();
return 0;
2018-06-15 14:37:51 +00:00
}
memcpy(buf, payload_ptr, payload_len);
2018-06-15 14:37:51 +00:00
/* RSSI stored after payload */
const int8_t rssi = (int8_t)payload_ptr[payload_len];
/* LQI calculated from RSSI */
const uint8_t lqi = calculate_lqi(rssi);
2018-07-25 16:16:27 +00:00
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi);
packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)lqi);
2018-07-12 08:44:14 +00:00
data_queue_release_entry();
return (int)payload_len;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
2018-07-09 18:13:01 +00:00
static uint8_t
cca_request(void)
2018-02-08 10:45:47 +00:00
{
2018-07-09 18:13:01 +00:00
const int8_t rssi = get_rssi();
2018-02-08 10:45:47 +00:00
2018-07-23 12:35:37 +00:00
if(rssi == RF_GET_RSSI_ERROR_VAL) {
2018-07-09 18:13:01 +00:00
return CCA_STATE_INVALID;
2018-06-15 14:37:51 +00:00
}
2018-02-08 10:45:47 +00:00
2018-07-09 18:13:01 +00:00
return (rssi < prop_radio.rssi_threshold)
2018-07-24 10:16:53 +00:00
? CCA_STATE_IDLE
: CCA_STATE_BUSY;
2018-07-09 18:13:01 +00:00
}
/*---------------------------------------------------------------------------*/
static int
channel_clear(void)
{
2018-07-23 12:35:37 +00:00
if(tx_is_active()) {
2018-07-25 14:59:28 +00:00
LOG_ERR("Channel clear called while in TX\n");
2018-07-09 18:13:01 +00:00
return 0;
2018-06-15 14:37:51 +00:00
}
2018-02-08 10:45:47 +00:00
2018-07-09 18:13:01 +00:00
const uint8_t cca_state = cca_request();
2018-06-15 14:37:51 +00:00
2018-07-09 18:13:01 +00:00
/* Channel is clear if CCA state is IDLE */
2018-07-24 10:16:53 +00:00
return cca_state == CCA_STATE_IDLE;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static int
receiving_packet(void)
{
2018-07-23 12:35:37 +00:00
if(!rx_is_active()) {
return 0;
2018-06-15 14:37:51 +00:00
}
2018-02-08 10:45:47 +00:00
2018-07-09 18:13:01 +00:00
const uint8_t cca_state = cca_request();
2018-02-08 10:45:47 +00:00
2018-07-24 10:16:53 +00:00
return cca_state == CCA_STATE_BUSY;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static int
pending_packet(void)
{
2018-07-12 08:44:14 +00:00
const data_entry_t *const read_entry = data_queue_current_entry();
2018-06-19 12:55:18 +00:00
volatile const data_entry_t *curr_entry = read_entry;
2018-02-08 10:45:47 +00:00
2018-06-19 12:55:18 +00:00
int num_pending = 0;
2018-02-08 10:45:47 +00:00
2018-06-15 14:37:51 +00:00
/* Go through RX Circular buffer and check their status */
do {
2018-06-19 12:55:18 +00:00
const uint8_t status = curr_entry->status;
2018-07-23 12:35:37 +00:00
if((status == DATA_ENTRY_FINISHED) ||
2018-07-24 10:16:53 +00:00
(status == DATA_ENTRY_BUSY)) {
2018-06-19 12:55:18 +00:00
num_pending += 1;
2018-06-15 14:37:51 +00:00
}
2018-06-19 12:55:18 +00:00
/* Stop when we have looped the circular buffer */
curr_entry = (data_entry_t *)curr_entry->pNextEntry;
2018-07-23 12:35:37 +00:00
} while(curr_entry != read_entry);
2018-06-15 14:37:51 +00:00
2018-07-23 12:35:37 +00:00
if(num_pending > 0) {
process_poll(&rf_sched_process);
2018-06-15 14:37:51 +00:00
}
2018-02-08 10:45:47 +00:00
2018-06-15 14:37:51 +00:00
/* If we didn't find an entry at status finished, no frames are pending */
2018-06-19 12:55:18 +00:00
return num_pending;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static int
2018-06-15 14:37:51 +00:00
on(void)
2018-02-08 10:45:47 +00:00
{
2018-07-09 18:13:01 +00:00
rf_result_t res;
2018-07-23 12:35:37 +00:00
if(prop_radio.rf_is_on) {
2018-07-25 14:59:28 +00:00
LOG_WARN("Radio is already on\n");
2018-07-09 18:13:01 +00:00
return RF_RESULT_OK;
2018-06-15 14:37:51 +00:00
}
2018-07-12 08:44:14 +00:00
data_queue_reset();
2018-06-15 14:37:51 +00:00
2018-07-17 16:02:38 +00:00
res = netstack_sched_rx(true);
2018-06-15 14:37:51 +00:00
2018-07-23 12:35:37 +00:00
if(res != RF_RESULT_OK) {
2018-07-09 18:13:01 +00:00
return RF_RESULT_ERROR;
2018-06-15 14:37:51 +00:00
}
prop_radio.rf_is_on = true;
2018-07-09 18:13:01 +00:00
return RF_RESULT_OK;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static int
2018-06-15 14:37:51 +00:00
off(void)
2018-02-08 10:45:47 +00:00
{
2018-07-23 12:35:37 +00:00
if(!prop_radio.rf_is_on) {
2018-07-25 14:59:28 +00:00
LOG_WARN("Radio is already off\n");
2018-07-09 18:13:01 +00:00
return RF_RESULT_OK;
2018-06-15 14:37:51 +00:00
}
2018-02-08 10:45:47 +00:00
2018-07-09 18:13:01 +00:00
rf_yield();
2018-02-08 10:45:47 +00:00
2018-06-15 14:37:51 +00:00
prop_radio.rf_is_on = false;
2018-07-09 18:13:01 +00:00
return RF_RESULT_OK;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static radio_result_t
get_value(radio_param_t param, radio_value_t *value)
{
2018-07-09 18:13:01 +00:00
rf_result_t res;
2018-07-23 12:35:37 +00:00
if(!value) {
2018-02-08 10:45:47 +00:00
return RADIO_RESULT_INVALID_VALUE;
}
switch(param) {
2018-02-08 10:45:47 +00:00
case RADIO_PARAM_POWER_MODE:
/* On / off */
2018-06-15 14:37:51 +00:00
*value = (prop_radio.rf_is_on)
2018-07-24 10:16:53 +00:00
? RADIO_POWER_MODE_ON
: RADIO_POWER_MODE_OFF;
2018-06-15 14:37:51 +00:00
2018-02-08 10:45:47 +00:00
return RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
case RADIO_PARAM_CHANNEL:
*value = (radio_value_t)get_channel();
return RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
case RADIO_PARAM_TXPOWER:
2018-07-25 16:16:27 +00:00
res = rf_get_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t *)&value);
2018-07-09 18:13:01 +00:00
return ((res == RF_RESULT_OK) &&
(*value != RF_TxPowerTable_INVALID_DBM))
2018-07-24 10:16:53 +00:00
? RADIO_RESULT_OK
: RADIO_RESULT_ERROR;
2018-02-08 10:45:47 +00:00
case RADIO_PARAM_CCA_THRESHOLD:
2018-06-15 14:37:51 +00:00
*value = prop_radio.rssi_threshold;
2018-02-08 10:45:47 +00:00
return RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
case RADIO_PARAM_RSSI:
*value = get_rssi();
2018-06-15 14:37:51 +00:00
return (*value == RF_GET_RSSI_ERROR_VAL)
2018-07-24 10:16:53 +00:00
? RADIO_RESULT_ERROR
: RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
case RADIO_CONST_CHANNEL_MIN:
2018-07-13 12:34:08 +00:00
*value = DOT_15_4G_CHAN_MIN;
2018-02-08 10:45:47 +00:00
return RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
case RADIO_CONST_CHANNEL_MAX:
2018-07-13 12:34:08 +00:00
*value = DOT_15_4G_CHAN_MAX;
2018-02-08 10:45:47 +00:00
return RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
case RADIO_CONST_TXPOWER_MIN:
*value = (radio_value_t)tx_power_min(rf_tx_power_table);
2018-02-08 10:45:47 +00:00
return RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
case RADIO_CONST_TXPOWER_MAX:
*value = (radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size);
2018-02-08 10:45:47 +00:00
return RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
default:
return RADIO_RESULT_NOT_SUPPORTED;
}
}
/*---------------------------------------------------------------------------*/
static radio_result_t
set_value(radio_param_t param, radio_value_t value)
{
2018-07-09 18:13:01 +00:00
rf_result_t res;
2018-02-08 10:45:47 +00:00
switch(param) {
case RADIO_PARAM_POWER_MODE:
2018-07-09 18:13:01 +00:00
2018-02-08 10:45:47 +00:00
if(value == RADIO_POWER_MODE_ON) {
2018-07-09 18:13:01 +00:00
return (on() == RF_RESULT_OK)
2018-07-24 10:16:53 +00:00
? RADIO_RESULT_OK
: RADIO_RESULT_ERROR;
2018-07-09 18:13:01 +00:00
} else if(value == RADIO_POWER_MODE_OFF) {
2018-06-15 14:37:51 +00:00
off();
2018-02-08 10:45:47 +00:00
return RADIO_RESULT_OK;
}
2018-07-09 18:13:01 +00:00
2018-02-08 10:45:47 +00:00
return RADIO_RESULT_INVALID_VALUE;
2018-02-08 10:45:47 +00:00
case RADIO_PARAM_CHANNEL:
2018-07-09 18:13:01 +00:00
res = set_channel((uint16_t)value);
return (res == RF_RESULT_OK)
2018-07-24 10:16:53 +00:00
? RADIO_RESULT_OK
: RADIO_RESULT_ERROR;
2018-02-08 10:45:47 +00:00
case RADIO_PARAM_TXPOWER:
if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) {
2018-07-09 18:13:01 +00:00
return RADIO_RESULT_INVALID_VALUE;
}
res = rf_set_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t)value);
2018-07-09 18:13:01 +00:00
return (res == RF_RESULT_OK)
2018-07-24 10:16:53 +00:00
? RADIO_RESULT_OK
: RADIO_RESULT_ERROR;
2018-02-08 10:45:47 +00:00
case RADIO_PARAM_RX_MODE:
return RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
case RADIO_PARAM_CCA_THRESHOLD:
2018-06-15 14:37:51 +00:00
prop_radio.rssi_threshold = (int8_t)value;
2018-02-09 11:50:55 +00:00
return RADIO_RESULT_OK;
2018-02-08 10:45:47 +00:00
default:
return RADIO_RESULT_NOT_SUPPORTED;
}
}
/*---------------------------------------------------------------------------*/
static radio_result_t
get_object(radio_param_t param, void *dest, size_t size)
{
return RADIO_RESULT_NOT_SUPPORTED;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
static radio_result_t
set_object(radio_param_t param, const void *src, size_t size)
{
return RADIO_RESULT_NOT_SUPPORTED;
2018-02-08 10:45:47 +00:00
}
/*---------------------------------------------------------------------------*/
2018-02-09 11:50:55 +00:00
static int
2018-06-15 14:37:51 +00:00
init(void)
2018-02-09 11:50:55 +00:00
{
2018-07-23 12:35:37 +00:00
if(prop_radio.rf_handle) {
2018-07-25 14:59:28 +00:00
LOG_WARN("Radio is already initialized\n");
2018-07-09 18:13:01 +00:00
return RF_RESULT_OK;
2018-06-19 12:55:18 +00:00
}
2018-07-09 18:13:01 +00:00
/* RX is off */
prop_radio.rf_is_on = false;
2018-06-15 14:37:51 +00:00
/* Set configured RSSI threshold */
2018-07-25 14:59:28 +00:00
prop_radio.rssi_threshold = PROP_MODE_CCA_RSSI_THRESHOLD;
2018-06-15 14:37:51 +00:00
2018-07-09 18:13:01 +00:00
init_rf_params();
2018-06-15 14:37:51 +00:00
/* Init RF params and specify non-default params */
2018-07-25 16:16:27 +00:00
RF_Params rf_params;
2018-06-15 14:37:51 +00:00
RF_Params_init(&rf_params);
rf_params.nInactivityTimeout = RF_CONF_INACTIVITY_TIMEOUT;
2018-06-15 14:37:51 +00:00
/* Open RF Driver */
2018-07-09 18:13:01 +00:00
prop_radio.rf_handle = netstack_open(&rf_params);
2018-07-23 12:35:37 +00:00
if(prop_radio.rf_handle == NULL) {
2018-07-25 14:59:28 +00:00
LOG_ERR("Unable to open RF driver during initialization\n");
2018-07-09 18:13:01 +00:00
return RF_RESULT_ERROR;
2018-06-15 14:37:51 +00:00
}
2018-02-09 11:50:55 +00:00
2018-07-13 17:09:02 +00:00
set_channel(IEEE802154_DEFAULT_CHANNEL);
2018-02-09 11:50:55 +00:00
2018-06-15 14:37:51 +00:00
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
2018-02-09 11:50:55 +00:00
2018-06-15 14:37:51 +00:00
/* Start RF process */
process_start(&rf_sched_process, NULL);
2018-02-09 11:50:55 +00:00
2018-07-09 18:13:01 +00:00
return RF_RESULT_OK;
2018-02-09 11:50:55 +00:00
}
/*---------------------------------------------------------------------------*/
2018-02-08 10:45:47 +00:00
const struct radio_driver prop_mode_driver = {
2018-06-15 14:37:51 +00:00
init,
2018-02-08 10:45:47 +00:00
prepare,
transmit,
send,
2018-06-15 14:37:51 +00:00
read,
2018-02-08 10:45:47 +00:00
channel_clear,
receiving_packet,
pending_packet,
2018-06-15 14:37:51 +00:00
on,
off,
2018-02-08 10:45:47 +00:00
get_value,
set_value,
get_object,
set_object,
};
/*---------------------------------------------------------------------------*/
/**
2018-07-23 12:35:37 +00:00
* @}
2018-02-08 10:45:47 +00:00
* @}
*/