nes-proj/arch/cpu/cc13xx-cc26xx/dev/rf-core.c

531 lines
15 KiB
C
Raw Normal View History

2018-07-09 18:13:01 +00:00
/*
* Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
* 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.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup simplelink
* @{
*
* \file
* Implementation of common CC13xx/CC26xx RF functionality
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "dev/watchdog.h"
#include "sys/cc.h"
#include "sys/process.h"
#include "sys/energest.h"
#include "net/netstack.h"
#include "net/packetbuf.h"
#include "net/mac/mac.h"
#include "rf-core.h"
/*---------------------------------------------------------------------------*/
#include <ti/devices/DeviceFamily.h>
#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h)
#include DeviceFamily_constructPath(driverlib/rf_mailbox.h)
#include <ti/drivers/rf/RF.h>
/*---------------------------------------------------------------------------*/
2018-07-12 08:44:14 +00:00
#include "rf-data-queue.h"
2018-07-09 18:13:01 +00:00
#include "netstack-settings.h"
/*---------------------------------------------------------------------------*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
2018-07-13 17:09:02 +00:00
#if 0
2018-07-09 18:13:01 +00:00
# define PRINTF(...)
#else
# define PRINTF(...) printf(__VA_ARGS__)
#endif
/*---------------------------------------------------------------------------*/
#define CMD_FS_RETRIES 3
#define RF_EVENTS_CMD_DONE (RF_EventCmdDone | RF_EventLastCmdDone | \
RF_EventFGCmdDone | RF_EventLastFGCmdDone)
#define CMD_STATUS(cmd) (CC_ACCESS_NOW(RF_Op, cmd).status)
#define CMD_HANDLE_OK(handle) (((handle) != RF_ALLOC_ERROR) && \
((handle) != RF_SCHEDULE_CMD_ERROR))
#define EVENTS_CMD_DONE(events) (((events) & RF_EVENTS_CMD_DONE) != 0)
/*---------------------------------------------------------------------------*/
static RF_Object rf_netstack;
static RF_Object rf_ble;
2018-07-12 08:44:14 +00:00
static RF_CmdHandle cmd_rx_handle;
2018-07-13 12:34:08 +00:00
static volatile bool rx_buf_full;
2018-07-12 08:44:14 +00:00
/*---------------------------------------------------------------------------*/
static void
cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events)
{
/* Unused arguments */
(void)client;
(void)command;
if (events & RF_EventRxEntryDone) {
process_poll(&rf_core_process);
}
if (events & RF_EventRxBufFull) {
2018-07-13 12:34:08 +00:00
rx_buf_full = true;
2018-07-09 18:13:01 +00:00
2018-07-12 08:44:14 +00:00
process_poll(&rf_core_process);
}
}
2018-07-09 18:13:01 +00:00
/*---------------------------------------------------------------------------*/
static inline bool
cmd_rx_is_active(void)
{
/*
* Active in this case means RX command is either running to be running,
* that is ACTIVE for running or PENDING for to be running.
*/
const uint16_t status = CMD_STATUS(netstack_cmd_rx);
return (status == ACTIVE) ||
(status == PENDING);
}
/*---------------------------------------------------------------------------*/
static uint_fast8_t
cmd_rx_disable(void)
{
const bool is_active = cmd_rx_is_active();
if (is_active) {
CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
2018-07-12 08:44:14 +00:00
RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
cmd_rx_handle = 0;
2018-07-09 18:13:01 +00:00
}
return (uint_fast8_t)is_active;
}
/*---------------------------------------------------------------------------*/
static rf_result_t
cmd_rx_restore(uint_fast8_t rx_key)
{
const bool was_active = (rx_key != 0) ? true : false;
if (!was_active) {
return RF_RESULT_OK;
}
RF_ScheduleCmdParams sched_params;
RF_ScheduleCmdParams_init(&sched_params);
sched_params.priority = RF_PriorityNormal;
sched_params.endTime = 0;
sched_params.allowDelay = RF_AllowDelayAny;
CMD_STATUS(netstack_cmd_rx) = PENDING;
2018-07-12 08:44:14 +00:00
cmd_rx_handle = RF_scheduleCmd(&rf_netstack,
2018-07-09 18:13:01 +00:00
(RF_Op*)&netstack_cmd_rx,
&sched_params,
2018-07-12 08:44:14 +00:00
cmd_rx_cb,
RF_EventRxEntryDone | RF_EventRxBufFull
2018-07-09 18:13:01 +00:00
);
2018-07-12 08:44:14 +00:00
if (!CMD_HANDLE_OK(cmd_rx_handle)) {
2018-07-09 18:13:01 +00:00
PRINTF("cmd_rx_restore: unable to schedule RX command handle=%d status=0x%04x",
2018-07-12 08:44:14 +00:00
cmd_rx_handle, CMD_STATUS(netstack_cmd_rx));
2018-07-09 18:13:01 +00:00
return RF_RESULT_ERROR;
}
return RF_RESULT_OK;
}
/*---------------------------------------------------------------------------*/
rf_result_t
rf_yield(void)
{
/* Force abort of any ongoing RF operation */
RF_flushCmd(&rf_netstack, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY);
2018-07-13 17:09:02 +00:00
#if RF_BLE_BEACON_ENABLE
2018-07-09 18:13:01 +00:00
RF_flushCmd(&rf_ble, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY);
2018-07-13 17:09:02 +00:00
#endif
2018-07-09 18:13:01 +00:00
/* Trigger a manual power-down */
RF_yield(&rf_netstack);
2018-07-13 17:09:02 +00:00
#if RF_BLE_BEACON_ENABLE
2018-07-09 18:13:01 +00:00
RF_yield(&rf_ble);
2018-07-13 17:09:02 +00:00
#endif
2018-07-09 18:13:01 +00:00
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
return RF_RESULT_OK;
}
/*---------------------------------------------------------------------------*/
rf_result_t
rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm)
{
const RF_Stat stat = RF_setTxPower(handle,
RF_TxPowerTable_findValue(table, dbm)
);
return (stat == RF_StatSuccess)
? RF_RESULT_OK
: RF_RESULT_ERROR;
}
/*---------------------------------------------------------------------------*/
rf_result_t
rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm)
{
*dbm = RF_TxPowerTable_findPowerLevel(table,
RF_getTxPower(handle)
);
return (*dbm != RF_TxPowerTable_INVALID_DBM)
? RF_RESULT_OK
: RF_RESULT_ERROR;
}
/*---------------------------------------------------------------------------*/
RF_Handle
netstack_open(RF_Params *params)
{
2018-07-12 08:44:14 +00:00
return RF_open(&rf_netstack,
&netstack_mode,
(RF_RadioSetup*)&netstack_cmd_radio_setup,
params
);
2018-07-09 18:13:01 +00:00
}
/*---------------------------------------------------------------------------*/
rf_result_t
netstack_sched_fs(void)
{
const uint_fast8_t rx_key = cmd_rx_disable();
/*
2018-07-13 12:34:08 +00:00
* For IEEE-mode, restarting CMD_IEEE_RX re-calibrates the synth by using the
* channel field in the CMD_IEEE_RX command. It is assumed this field is
* already configured before this function is called.
* However, if CMD_IEEE_RX wasn't active, manually calibrate the synth
2018-07-09 18:13:01 +00:00
* with CMD_FS.
*
* For Prop-mode, the synth is always manually calibrated with CMD_FS.
*/
#if (RF_CORE_CONF_MODE == RF_CORE_MODE_2_4_GHZ)
if (rx_key) {
cmd_rx_restore(rx_key);
return RF_RESULT_OK;
}
#endif /* RF_CORE_CONF_MODE == RF_CORE_MODE_2_4_GHZ */
RF_EventMask events;
bool synth_error = false;
uint8_t num_tries = 0;
do {
CMD_STATUS(netstack_cmd_fs) = PENDING;
events = RF_runCmd(&rf_netstack,
(RF_Op*)&netstack_cmd_fs,
RF_PriorityNormal,
NULL,
0
);
synth_error = (EVENTS_CMD_DONE(events))
&& (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG);
} while (synth_error && (num_tries++ < CMD_FS_RETRIES));
cmd_rx_restore(rx_key);
return (CMD_STATUS(netstack_cmd_fs) == DONE_OK)
? RF_RESULT_OK
: RF_RESULT_ERROR;
}
/*---------------------------------------------------------------------------*/
rf_result_t
2018-07-12 08:44:14 +00:00
netstack_sched_ieee_tx(bool recieve_ack)
2018-07-09 18:13:01 +00:00
{
2018-07-12 08:44:14 +00:00
rf_result_t res;
2018-07-09 18:13:01 +00:00
RF_ScheduleCmdParams sched_params;
RF_ScheduleCmdParams_init(&sched_params);
sched_params.priority = RF_PriorityNormal;
sched_params.endTime = 0;
sched_params.allowDelay = RF_AllowDelayAny;
2018-07-12 08:44:14 +00:00
const bool is_active = cmd_rx_is_active();
const bool rx_ack_required = (recieve_ack && !is_active);
/*
* If we expect ACK after transmission, RX must be running to be able to
* run the RX_ACK command. Therefore, turn on RX before starting the
* chained TX command.
*/
if (rx_ack_required) {
res = netstack_sched_rx();
if (res != RF_RESULT_OK) {
return res;
}
}
2018-07-09 18:13:01 +00:00
CMD_STATUS(netstack_cmd_tx) = PENDING;
RF_CmdHandle tx_handle = RF_scheduleCmd(&rf_netstack,
(RF_Op*)&netstack_cmd_tx,
&sched_params,
2018-07-12 08:44:14 +00:00
NULL,
0
);
if (!CMD_HANDLE_OK(tx_handle)) {
PRINTF("netstack_sched_tx: unable to schedule TX command handle=%d status=0x%04x\n",
tx_handle, CMD_STATUS(netstack_cmd_tx));
return RF_RESULT_ERROR;
}
if (is_active) {
ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
} else {
ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
}
/* Wait until TX operation finishes */
RF_EventMask tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
/* Stop RX if it was turned on only for ACK */
if (rx_ack_required) {
netstack_stop_rx();
}
if (is_active) {
ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
} else {
ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
}
if (!EVENTS_CMD_DONE(tx_events)) {
PRINTF("netstack_sched_tx: TX command pend error events=0x%08llx status=0x%04x\n",
tx_events, CMD_STATUS(netstack_cmd_tx));
return RF_RESULT_ERROR;
}
return RF_RESULT_OK;
}
/*---------------------------------------------------------------------------*/
rf_result_t
netstack_sched_prop_tx(void)
{
RF_ScheduleCmdParams sched_params;
RF_ScheduleCmdParams_init(&sched_params);
sched_params.priority = RF_PriorityNormal;
sched_params.endTime = 0;
sched_params.allowDelay = RF_AllowDelayAny;
CMD_STATUS(netstack_cmd_tx) = PENDING;
RF_CmdHandle tx_handle = RF_scheduleCmd(&rf_netstack,
(RF_Op*)&netstack_cmd_tx,
&sched_params,
NULL,
0
2018-07-09 18:13:01 +00:00
);
if (!CMD_HANDLE_OK(tx_handle)) {
PRINTF("netstack_sched_tx: unable to schedule TX command handle=%d status=0x%04x\n",
tx_handle, CMD_STATUS(netstack_cmd_tx));
return RF_RESULT_ERROR;
}
/*
2018-07-12 08:44:14 +00:00
* Prop TX requires any on-going RX operation to be stopped to be
* able to transmit. Therefore, disable RX if running.
2018-07-09 18:13:01 +00:00
*/
2018-07-12 08:44:14 +00:00
const bool rx_key = cmd_rx_disable();
2018-07-09 18:13:01 +00:00
if (rx_key) {
ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
} else {
ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
}
/* Wait until TX operation finishes */
RF_EventMask tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
2018-07-12 08:44:14 +00:00
cmd_rx_restore(rx_key);
2018-07-09 18:13:01 +00:00
if (rx_key) {
ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
} else {
ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
}
if (!EVENTS_CMD_DONE(tx_events)) {
PRINTF("netstack_sched_tx: TX command pend error events=0x%08llx status=0x%04x\n",
tx_events, CMD_STATUS(netstack_cmd_tx));
return RF_RESULT_ERROR;
}
return RF_RESULT_OK;
}
/*---------------------------------------------------------------------------*/
rf_result_t
2018-07-12 08:44:14 +00:00
netstack_sched_rx(void)
2018-07-09 18:13:01 +00:00
{
if (cmd_rx_is_active()) {
PRINTF("netstack_sched_rx: already in RX\n");
return RF_RESULT_OK;
}
RF_ScheduleCmdParams sched_params;
RF_ScheduleCmdParams_init(&sched_params);
sched_params.priority = RF_PriorityNormal;
sched_params.endTime = 0;
sched_params.allowDelay = RF_AllowDelayAny;
CMD_STATUS(netstack_cmd_rx) = PENDING;
2018-07-12 08:44:14 +00:00
cmd_rx_handle = RF_scheduleCmd(&rf_netstack,
2018-07-09 18:13:01 +00:00
(RF_Op*)&netstack_cmd_rx,
&sched_params,
2018-07-12 08:44:14 +00:00
cmd_rx_cb,
RF_EventRxEntryDone | RF_EventRxBufFull
2018-07-09 18:13:01 +00:00
);
2018-07-12 08:44:14 +00:00
if (!CMD_HANDLE_OK(cmd_rx_handle)) {
2018-07-09 18:13:01 +00:00
PRINTF("netstack_sched_rx: unable to schedule RX command handle=%d status=0x%04x\n",
2018-07-12 08:44:14 +00:00
cmd_rx_handle, CMD_STATUS(netstack_cmd_rx));
2018-07-09 18:13:01 +00:00
return RF_RESULT_ERROR;
}
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
return RF_RESULT_OK;
}
/*---------------------------------------------------------------------------*/
rf_result_t
netstack_stop_rx(void)
{
if (!cmd_rx_is_active()) {
PRINTF("netstack_stop_rx: RX not active\n");
return RF_RESULT_OK;
}
CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
2018-07-12 08:44:14 +00:00
const RF_Stat stat = RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
cmd_rx_handle = 0;
2018-07-09 18:13:01 +00:00
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
return (stat == RF_StatSuccess)
? RF_RESULT_OK
: RF_RESULT_ERROR;
}
/*---------------------------------------------------------------------------*/
RF_Handle
ble_open(RF_Params *params)
{
return RF_open(&rf_ble, &ble_mode, (RF_RadioSetup*)&ble_cmd_radio_setup, params);
}
/*---------------------------------------------------------------------------*/
rf_result_t
ble_sched_beacon(RF_Callback cb, RF_EventMask bm_event)
{
RF_ScheduleCmdParams sched_params;
RF_ScheduleCmdParams_init(&sched_params);
sched_params.priority = RF_PriorityNormal;
sched_params.endTime = 0;
sched_params.allowDelay = RF_AllowDelayAny;
CMD_STATUS(ble_cmd_beacon) = PENDING;
RF_CmdHandle beacon_handle = RF_scheduleCmd(&rf_ble,
(RF_Op*)&ble_cmd_beacon,
&sched_params,
cb,
bm_event
);
if (!CMD_HANDLE_OK(beacon_handle)) {
PRINTF("ble_sched_beacon: unable to schedule BLE Beacon command handle=%d status=0x%04x\n",
beacon_handle, CMD_STATUS(ble_cmd_beacon));
return RF_RESULT_ERROR;
}
const uint_fast8_t rx_key = cmd_rx_disable();
/* Wait until Beacon operation finishes */
RF_EventMask beacon_events = RF_pendCmd(&rf_ble, beacon_handle, 0);
if (!EVENTS_CMD_DONE(beacon_events)) {
PRINTF("ble_sched_beacon: Beacon command pend error events=0x%08llx status=0x%04x\n",
beacon_events, CMD_STATUS(ble_cmd_beacon));
cmd_rx_restore(rx_key);
return RF_RESULT_ERROR;
}
cmd_rx_restore(rx_key);
return RF_RESULT_OK;
}
/*---------------------------------------------------------------------------*/
PROCESS(rf_core_process, "RF Core Process");
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(rf_core_process, ev, data)
{
int len;
PROCESS_BEGIN();
while(1) {
PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
2018-07-13 12:34:08 +00:00
2018-07-09 18:13:01 +00:00
do {
//watchdog_periodic();
packetbuf_clear();
len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
2018-07-13 12:34:08 +00:00
if (rx_buf_full) {
PRINTF("rf_core: RX buf full, restart RX\n");
rx_buf_full = false;
/* Restart RX */
netstack_stop_rx();
2018-07-13 12:34:08 +00:00
netstack_sched_rx();
}
2018-07-09 18:13:01 +00:00
if(len > 0) {
packetbuf_set_datalen(len);
NETSTACK_MAC.input();
}
} while(len > 0);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/** @} */