mirror of
https://github.com/oliverschmidt/contiki.git
synced 2024-09-11 06:54:32 +00:00
Merge pull request #1709 from atiselsts/cc26xx_tsch_port
TSCH port for CC26xx
This commit is contained in:
commit
5fe95fc425
@ -38,6 +38,7 @@ It has been tested on the following platforms:
|
|||||||
* Zolertia Z1 (`z1`, tested in cooja only)
|
* Zolertia Z1 (`z1`, tested in cooja only)
|
||||||
* CC2538DK (`cc2538dk`, tested on hardware)
|
* CC2538DK (`cc2538dk`, tested on hardware)
|
||||||
* Zolertia Zoul (`zoul`, tested on hardware)
|
* Zolertia Zoul (`zoul`, tested on hardware)
|
||||||
|
* CC2650 (`srf06-cc26xx`, tested on hardware)
|
||||||
|
|
||||||
This implementation was present at the ETSI Plugtest
|
This implementation was present at the ETSI Plugtest
|
||||||
event in Prague in July 2015, and did successfully inter-operate with all
|
event in Prague in July 2015, and did successfully inter-operate with all
|
||||||
@ -78,7 +79,7 @@ Orchestra is implemented in:
|
|||||||
|
|
||||||
A simple TSCH+RPL example is included under `examples/ipv6/rpl-tsch`.
|
A simple TSCH+RPL example is included under `examples/ipv6/rpl-tsch`.
|
||||||
To use TSCH, first make sure your platform supports it.
|
To use TSCH, first make sure your platform supports it.
|
||||||
Currently, `jn516x`, `sky`, `z1`, `cc2538dk` and `zoul` are the supported platforms.
|
Currently, `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul` and `srf06-cc26xx` are the supported platforms.
|
||||||
To add your own, we refer the reader to the next section.
|
To add your own, we refer the reader to the next section.
|
||||||
|
|
||||||
To add TSCH to your application, first include the TSCH module from your makefile with:
|
To add TSCH to your application, first include the TSCH module from your makefile with:
|
||||||
@ -164,7 +165,7 @@ Finally, one can also implement his own scheduler, centralized or distributed, b
|
|||||||
## Porting TSCH to a new platform
|
## Porting TSCH to a new platform
|
||||||
|
|
||||||
Porting TSCH to a new platform requires a few new features in the radio driver, a number of timing-related configuration paramters.
|
Porting TSCH to a new platform requires a few new features in the radio driver, a number of timing-related configuration paramters.
|
||||||
The easiest is probably to start from one of the existing port: `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul`.
|
The easiest is probably to start from one of the existing port: `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul`, `srf06-cc26xx`.
|
||||||
|
|
||||||
### Radio features required for TSCH
|
### Radio features required for TSCH
|
||||||
|
|
||||||
|
@ -118,6 +118,9 @@ clock_init(void)
|
|||||||
/* GPT0 / Timer B: One shot, PWM interrupt enable */
|
/* GPT0 / Timer B: One shot, PWM interrupt enable */
|
||||||
HWREG(GPT0_BASE + GPT_O_TBMR) =
|
HWREG(GPT0_BASE + GPT_O_TBMR) =
|
||||||
((TIMER_CFG_B_ONE_SHOT >> 8) & 0xFF) | GPT_TBMR_TBPWMIE;
|
((TIMER_CFG_B_ONE_SHOT >> 8) & 0xFF) | GPT_TBMR_TBPWMIE;
|
||||||
|
|
||||||
|
/* enable sync with radio timer */
|
||||||
|
HWREGBITW(AON_RTC_BASE + AON_RTC_O_CTL, AON_RTC_CTL_RTC_UPD_EN_BITN) = 1;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
|
@ -81,11 +81,13 @@ soc_rtc_init(void)
|
|||||||
|
|
||||||
ti_lib_aon_rtc_event_clear(AON_RTC_CH0);
|
ti_lib_aon_rtc_event_clear(AON_RTC_CH0);
|
||||||
ti_lib_aon_rtc_event_clear(AON_RTC_CH1);
|
ti_lib_aon_rtc_event_clear(AON_RTC_CH1);
|
||||||
|
ti_lib_aon_rtc_event_clear(AON_RTC_CH2);
|
||||||
|
|
||||||
/* Setup the wakeup event */
|
/* Setup the wakeup event */
|
||||||
ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU0, AON_EVENT_RTC_CH0);
|
ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU0, AON_EVENT_RTC_CH0);
|
||||||
ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU1, AON_EVENT_RTC_CH1);
|
ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU1, AON_EVENT_RTC_CH1);
|
||||||
ti_lib_aon_rtc_combined_event_config(AON_RTC_CH0 | AON_RTC_CH1);
|
ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU2, AON_EVENT_RTC_CH2);
|
||||||
|
ti_lib_aon_rtc_combined_event_config(AON_RTC_CH0 | AON_RTC_CH1 | AON_RTC_CH2);
|
||||||
|
|
||||||
HWREG(AON_RTC_BASE + AON_RTC_O_SEC) = SOC_RTC_START_TICK_COUNT;
|
HWREG(AON_RTC_BASE + AON_RTC_O_SEC) = SOC_RTC_START_TICK_COUNT;
|
||||||
|
|
||||||
@ -123,7 +125,7 @@ soc_rtc_get_next_trigger()
|
|||||||
void
|
void
|
||||||
soc_rtc_schedule_one_shot(uint32_t channel, uint32_t ticks)
|
soc_rtc_schedule_one_shot(uint32_t channel, uint32_t ticks)
|
||||||
{
|
{
|
||||||
if((channel != AON_RTC_CH0) && (channel != AON_RTC_CH1)) {
|
if((channel != AON_RTC_CH0) && (channel != AON_RTC_CH1) && (channel != AON_RTC_CH2)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,6 +172,12 @@ soc_rtc_isr(void)
|
|||||||
rtimer_run_next();
|
rtimer_run_next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ti_lib_aon_rtc_event_get(AON_RTC_CH2)) {
|
||||||
|
/* after sleep; since a rtimer is already scheduled, do nothing */
|
||||||
|
ti_lib_aon_rtc_channel_disable(AON_RTC_CH2);
|
||||||
|
HWREG(AON_RTC_BASE + AON_RTC_O_EVFLAGS) = AON_RTC_EVFLAGS_CH2;
|
||||||
|
}
|
||||||
|
|
||||||
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
|
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -77,12 +77,13 @@ LIST(modules_list);
|
|||||||
* Don't consider standby mode if the next AON RTC event is scheduled to fire
|
* Don't consider standby mode if the next AON RTC event is scheduled to fire
|
||||||
* in less than STANDBY_MIN_DURATION rtimer ticks
|
* in less than STANDBY_MIN_DURATION rtimer ticks
|
||||||
*/
|
*/
|
||||||
#define STANDBY_MIN_DURATION (RTIMER_SECOND >> 11)
|
#define STANDBY_MIN_DURATION (RTIMER_SECOND / 100) /* 10.0 ms */
|
||||||
#define MINIMAL_SAFE_SCHEDUAL 8u
|
|
||||||
|
/* Wake up this much time earlier before the next rtimer */
|
||||||
|
#define SLEEP_GUARD_TIME (RTIMER_SECOND / 1000) /* 1.0 ms */
|
||||||
|
|
||||||
#define MAX_SLEEP_TIME RTIMER_SECOND
|
#define MAX_SLEEP_TIME RTIMER_SECOND
|
||||||
#define DEFAULT_SLEEP_TIME RTIMER_SECOND
|
#define MINIMAL_SAFE_SCHEDULE 8u
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#define CLK_TO_RT(c) ((c) * (RTIMER_SECOND / CLOCK_SECOND))
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Prototype of a function in clock.c. Called every time we come out of DS */
|
/* Prototype of a function in clock.c. Called every time we come out of DS */
|
||||||
void clock_update(void);
|
void clock_update(void);
|
||||||
@ -241,14 +242,124 @@ wake_up(void)
|
|||||||
module->wakeup();
|
module->wakeup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CC2650_FAST_RADIO_STARTUP
|
||||||
|
/*
|
||||||
|
* Trigger a switch to the XOSC, so that we can subsequently use the RF FS
|
||||||
|
*/
|
||||||
|
oscillators_request_hf_xosc();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
setup_sleep_mode(rtimer_clock_t *next_timer)
|
||||||
|
{
|
||||||
|
lpm_registered_module_t *module;
|
||||||
|
uint8_t max_pm = LPM_MODE_MAX_SUPPORTED;
|
||||||
|
|
||||||
|
rtimer_clock_t now = RTIMER_NOW();
|
||||||
|
const rtimer_clock_t max_sleep = now + MAX_SLEEP_TIME;
|
||||||
|
|
||||||
|
/* next_timer will hold the time of the next system wakeup due to a timer*/
|
||||||
|
*next_timer = max_sleep;
|
||||||
|
|
||||||
|
/* Check if any events fired before we turned interrupts off. If so, abort */
|
||||||
|
if(LPM_MODE_MAX_SUPPORTED == LPM_MODE_AWAKE || process_nevents()) {
|
||||||
|
return LPM_MODE_AWAKE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ti_lib_aon_rtc_channel_active(AON_RTC_CH0)) {
|
||||||
|
rtimer_clock_t next_rtimer;
|
||||||
|
/* find out the timer of the next rtimer interrupt */
|
||||||
|
next_rtimer = ti_lib_aon_rtc_compare_value_get(AON_RTC_CH0);
|
||||||
|
if(RTIMER_CLOCK_LT(next_rtimer, now + 2)) {
|
||||||
|
return LPM_MODE_AWAKE;
|
||||||
|
}
|
||||||
|
if(RTIMER_CLOCK_LT(next_rtimer, now + STANDBY_MIN_DURATION)) {
|
||||||
|
return LPM_MODE_SLEEP;
|
||||||
|
}
|
||||||
|
*next_timer = next_rtimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* also find out the timer of the next etimer */
|
||||||
|
if(etimer_pending()) {
|
||||||
|
int32_t until_next_etimer;
|
||||||
|
rtimer_clock_t next_etimer;
|
||||||
|
|
||||||
|
until_next_etimer = (int32_t)etimer_next_expiration_time() - (int32_t)clock_time();
|
||||||
|
if(until_next_etimer < 1) {
|
||||||
|
return LPM_MODE_AWAKE;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_etimer = soc_rtc_last_isr_time() + (until_next_etimer * (RTIMER_SECOND / CLOCK_SECOND));
|
||||||
|
if(RTIMER_CLOCK_LT(next_etimer, now + STANDBY_MIN_DURATION)) {
|
||||||
|
/* ensure that we schedule sleep a minimal number of ticks into the
|
||||||
|
future */
|
||||||
|
soc_rtc_schedule_one_shot(AON_RTC_CH1, now + MINIMAL_SAFE_SCHEDULE);
|
||||||
|
return LPM_MODE_SLEEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RTIMER_CLOCK_LT(max_sleep, next_etimer)) {
|
||||||
|
/* if max_pm is LPM_MODE_SLEEP, we could trigger the watchdog if we slept
|
||||||
|
for too long. */
|
||||||
|
if(RTIMER_CLOCK_LT(max_sleep, *next_timer)) {
|
||||||
|
soc_rtc_schedule_one_shot(AON_RTC_CH1, max_sleep);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Reschedule AON RTC CH1 to fire just in time for the next etimer event */
|
||||||
|
soc_rtc_schedule_one_shot(AON_RTC_CH1, next_etimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RTIMER_CLOCK_LT(next_etimer, *next_timer)) {
|
||||||
|
/* set `next_timer` to the time the first etimer fires */
|
||||||
|
*next_timer = next_etimer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Collect max allowed PM permission from interested modules */
|
||||||
|
for(module = list_head(modules_list); module != NULL;
|
||||||
|
module = module->next) {
|
||||||
|
if(module->request_max_pm) {
|
||||||
|
uint8_t module_pm = module->request_max_pm();
|
||||||
|
if(module_pm < max_pm) {
|
||||||
|
max_pm = module_pm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_pm;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
lpm_sleep(void)
|
||||||
|
{
|
||||||
|
ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM);
|
||||||
|
|
||||||
|
/* We are only interested in IRQ energest while idle or in LPM */
|
||||||
|
ENERGEST_IRQ_RESTORE(irq_energest);
|
||||||
|
|
||||||
|
/* Just to be on the safe side, explicitly disable Deep Sleep */
|
||||||
|
HWREG(NVIC_SYS_CTRL) &= ~(NVIC_SYS_CTRL_SLEEPDEEP);
|
||||||
|
|
||||||
|
ti_lib_prcm_sleep();
|
||||||
|
|
||||||
|
/* Remember IRQ energest for next pass */
|
||||||
|
ENERGEST_IRQ_SAVE(irq_energest);
|
||||||
|
|
||||||
|
ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
deep_sleep(void)
|
deep_sleep(rtimer_clock_t next_timer)
|
||||||
{
|
{
|
||||||
uint32_t domains = LOCKABLE_DOMAINS;
|
uint32_t domains = LOCKABLE_DOMAINS;
|
||||||
lpm_registered_module_t *module;
|
lpm_registered_module_t *module;
|
||||||
|
|
||||||
|
#if CC2650_FAST_RADIO_STARTUP
|
||||||
|
/* schedule a wakeup briefly before the next etimer/rtimer to wake up the system */
|
||||||
|
soc_rtc_schedule_one_shot(AON_RTC_CH2, next_timer - SLEEP_GUARD_TIME);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notify all registered modules that we are dropping to mode X. We do not
|
* Notify all registered modules that we are dropping to mode X. We do not
|
||||||
* need to do this for simple sleep.
|
* need to do this for simple sleep.
|
||||||
@ -304,7 +415,8 @@ deep_sleep(void)
|
|||||||
* turn back off.
|
* turn back off.
|
||||||
*
|
*
|
||||||
* If the radio is on, we won't even reach here, and if it's off the HF
|
* If the radio is on, we won't even reach here, and if it's off the HF
|
||||||
* clock source should already be the HF RC.
|
* clock source should already be the HF RC, unless CC2650_FAST_RADIO_STARTUP
|
||||||
|
* is defined.
|
||||||
*
|
*
|
||||||
* Nevertheless, request the switch to the HF RC explicitly here.
|
* Nevertheless, request the switch to the HF RC explicitly here.
|
||||||
*/
|
*/
|
||||||
@ -370,131 +482,32 @@ deep_sleep(void)
|
|||||||
* unpending events so the handlers can fire
|
* unpending events so the handlers can fire
|
||||||
*/
|
*/
|
||||||
wake_up();
|
wake_up();
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
static void
|
|
||||||
safe_schedule_rtimer(rtimer_clock_t time, rtimer_clock_t now, int pm)
|
|
||||||
{
|
|
||||||
rtimer_clock_t min_sleep;
|
|
||||||
rtimer_clock_t max_sleep;
|
|
||||||
|
|
||||||
min_sleep = now + MINIMAL_SAFE_SCHEDUAL;
|
ti_lib_int_master_enable();
|
||||||
max_sleep = now + MAX_SLEEP_TIME;
|
|
||||||
|
|
||||||
if(RTIMER_CLOCK_LT(time, min_sleep)) {
|
|
||||||
/* ensure that we schedule sleep a minimal number of ticks into the
|
|
||||||
future */
|
|
||||||
soc_rtc_schedule_one_shot(AON_RTC_CH1, min_sleep);
|
|
||||||
} else if((pm == LPM_MODE_SLEEP) && RTIMER_CLOCK_LT(max_sleep, time)) {
|
|
||||||
/* if max_pm is LPM_MODE_SLEEP, we could trigger the watchdog if we slept
|
|
||||||
for too long. */
|
|
||||||
soc_rtc_schedule_one_shot(AON_RTC_CH1, max_sleep);
|
|
||||||
} else {
|
|
||||||
soc_rtc_schedule_one_shot(AON_RTC_CH1, time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
static int
|
|
||||||
setup_sleep_mode(void)
|
|
||||||
{
|
|
||||||
rtimer_clock_t et_distance = 0;
|
|
||||||
|
|
||||||
lpm_registered_module_t *module;
|
|
||||||
int max_pm;
|
|
||||||
int module_pm;
|
|
||||||
int etimer_is_pending;
|
|
||||||
rtimer_clock_t now;
|
|
||||||
rtimer_clock_t et_time;
|
|
||||||
rtimer_clock_t next_trig;
|
|
||||||
|
|
||||||
max_pm = LPM_MODE_MAX_SUPPORTED;
|
|
||||||
now = RTIMER_NOW();
|
|
||||||
|
|
||||||
if((LPM_MODE_MAX_SUPPORTED == LPM_MODE_AWAKE) || process_nevents()) {
|
|
||||||
return LPM_MODE_AWAKE;
|
|
||||||
}
|
|
||||||
|
|
||||||
etimer_is_pending = etimer_pending();
|
|
||||||
|
|
||||||
if(etimer_is_pending) {
|
|
||||||
et_distance = CLK_TO_RT(etimer_next_expiration_time() - clock_time());
|
|
||||||
|
|
||||||
if(RTIMER_CLOCK_LT(et_distance, 1)) {
|
|
||||||
/* there is an etimer which is already expired; we shouldn't go to
|
|
||||||
sleep at all */
|
|
||||||
return LPM_MODE_AWAKE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next_trig = soc_rtc_get_next_trigger();
|
|
||||||
if(RTIMER_CLOCK_LT(next_trig, now + STANDBY_MIN_DURATION)) {
|
|
||||||
return LPM_MODE_SLEEP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Collect max allowed PM permission from interested modules */
|
|
||||||
for(module = list_head(modules_list); module != NULL;
|
|
||||||
module = module->next) {
|
|
||||||
if(module->request_max_pm) {
|
|
||||||
module_pm = module->request_max_pm();
|
|
||||||
if(module_pm < max_pm) {
|
|
||||||
max_pm = module_pm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reschedule AON RTC CH1 to fire just in time for the next etimer event */
|
|
||||||
if(etimer_is_pending) {
|
|
||||||
et_time = soc_rtc_last_isr_time() + et_distance;
|
|
||||||
|
|
||||||
safe_schedule_rtimer(et_time, now, max_pm);
|
|
||||||
} else {
|
|
||||||
/* set a maximal sleep period if no etimers are queued */
|
|
||||||
soc_rtc_schedule_one_shot(AON_RTC_CH1, now + DEFAULT_SLEEP_TIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
return max_pm;
|
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
lpm_drop()
|
lpm_drop()
|
||||||
{
|
{
|
||||||
uint8_t max_pm;
|
uint8_t max_pm;
|
||||||
|
rtimer_clock_t next_timer;
|
||||||
|
|
||||||
/* Critical. Don't get interrupted! */
|
/* Critical. Don't get interrupted! */
|
||||||
ti_lib_int_master_disable();
|
ti_lib_int_master_disable();
|
||||||
|
|
||||||
max_pm = setup_sleep_mode();
|
max_pm = setup_sleep_mode(&next_timer);
|
||||||
|
|
||||||
/* Drop */
|
/* Drop */
|
||||||
if(max_pm == LPM_MODE_SLEEP) {
|
if(max_pm == LPM_MODE_SLEEP) {
|
||||||
lpm_sleep();
|
lpm_sleep();
|
||||||
} else if(max_pm == LPM_MODE_DEEP_SLEEP) {
|
} else if(max_pm == LPM_MODE_DEEP_SLEEP) {
|
||||||
deep_sleep();
|
deep_sleep(next_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ti_lib_int_master_enable();
|
ti_lib_int_master_enable();
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
lpm_sleep(void)
|
|
||||||
{
|
|
||||||
ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM);
|
|
||||||
|
|
||||||
/* We are only interested in IRQ energest while idle or in LPM */
|
|
||||||
ENERGEST_IRQ_RESTORE(irq_energest);
|
|
||||||
|
|
||||||
/* Just to be on the safe side, explicitly disable Deep Sleep */
|
|
||||||
HWREG(NVIC_SYS_CTRL) &= ~(NVIC_SYS_CTRL_SLEEPDEEP);
|
|
||||||
|
|
||||||
ti_lib_prcm_sleep();
|
|
||||||
|
|
||||||
/* Remember IRQ energest for next pass */
|
|
||||||
ENERGEST_IRQ_SAVE(irq_energest);
|
|
||||||
|
|
||||||
ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU);
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
void
|
|
||||||
lpm_register_module(lpm_registered_module_t *module)
|
lpm_register_module(lpm_registered_module_t *module)
|
||||||
{
|
{
|
||||||
list_add(modules_list, module);
|
list_add(modules_list, module);
|
||||||
@ -512,7 +525,7 @@ lpm_init()
|
|||||||
list_init(modules_list);
|
list_init(modules_list);
|
||||||
|
|
||||||
/* Always wake up on any DIO edge detection */
|
/* Always wake up on any DIO edge detection */
|
||||||
ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU2, AON_EVENT_IO);
|
ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU3, AON_EVENT_IO);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "sys/energest.h"
|
#include "sys/energest.h"
|
||||||
#include "sys/clock.h"
|
#include "sys/clock.h"
|
||||||
#include "sys/rtimer.h"
|
#include "sys/rtimer.h"
|
||||||
|
#include "sys/ctimer.h"
|
||||||
#include "sys/cc.h"
|
#include "sys/cc.h"
|
||||||
#include "lpm.h"
|
#include "lpm.h"
|
||||||
#include "ti-lib.h"
|
#include "ti-lib.h"
|
||||||
@ -102,6 +103,9 @@
|
|||||||
#define IEEE_MODE_RSSI_THRESHOLD 0xA6
|
#define IEEE_MODE_RSSI_THRESHOLD 0xA6
|
||||||
#endif /* IEEE_MODE_CONF_RSSI_THRESHOLD */
|
#endif /* IEEE_MODE_CONF_RSSI_THRESHOLD */
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#define STATUS_CRC_OK 0x80
|
||||||
|
#define STATUS_CORRELATION 0x7f
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Data entry status field constants */
|
/* Data entry status field constants */
|
||||||
#define DATA_ENTRY_STATUS_PENDING 0x00 /* Not in use by the Radio CPU */
|
#define DATA_ENTRY_STATUS_PENDING 0x00 /* Not in use by the Radio CPU */
|
||||||
#define DATA_ENTRY_STATUS_ACTIVE 0x01 /* Open for r/w by the radio CPU */
|
#define DATA_ENTRY_STATUS_ACTIVE 0x01 /* Open for r/w by the radio CPU */
|
||||||
@ -142,6 +146,13 @@ static uint8_t rf_stats[16] = { 0 };
|
|||||||
#define RF_CMD_CCA_REQ_CCA_STATE_IDLE 0 /* 00 */
|
#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_BUSY 1 /* 01 */
|
||||||
#define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */
|
#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_MIN 11
|
||||||
#define IEEE_MODE_CHANNEL_MAX 26
|
#define IEEE_MODE_CHANNEL_MAX 26
|
||||||
@ -186,6 +197,35 @@ static const output_config_t output_power[] = {
|
|||||||
/* Default TX Power - position in output_power[] */
|
/* Default TX Power - position in output_power[] */
|
||||||
const output_config_t *tx_power_current = &output_power[0];
|
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 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;
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
* Buffers used to send commands to the RF core (generic and IEEE commands).
|
* Buffers used to send commands to the RF core (generic and IEEE commands).
|
||||||
* Some of those buffers are re-usable, some are not.
|
* Some of those buffers are re-usable, some are not.
|
||||||
@ -202,7 +242,7 @@ static uint8_t cmd_ieee_rx_buf[RF_CMD_BUFFER_SIZE] CC_ALIGN(4);
|
|||||||
#define DATA_ENTRY_LENSZ_BYTE 1
|
#define DATA_ENTRY_LENSZ_BYTE 1
|
||||||
#define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */
|
#define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */
|
||||||
|
|
||||||
#define RX_BUF_SIZE 140
|
#define RX_BUF_SIZE 144
|
||||||
/* Four receive buffers entries with room for 1 IEEE802.15.4 frame in each */
|
/* 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_0[RX_BUF_SIZE] CC_ALIGN(4);
|
||||||
static uint8_t rx_buf_1[RX_BUF_SIZE] CC_ALIGN(4);
|
static uint8_t rx_buf_1[RX_BUF_SIZE] CC_ALIGN(4);
|
||||||
@ -544,7 +584,7 @@ init_rf_params(void)
|
|||||||
cmd->rxConfig.bAppendRssi = 1;
|
cmd->rxConfig.bAppendRssi = 1;
|
||||||
cmd->rxConfig.bAppendCorrCrc = 1;
|
cmd->rxConfig.bAppendCorrCrc = 1;
|
||||||
cmd->rxConfig.bAppendSrcInd = 0;
|
cmd->rxConfig.bAppendSrcInd = 0;
|
||||||
cmd->rxConfig.bAppendTimestamp = 0;
|
cmd->rxConfig.bAppendTimestamp = 1;
|
||||||
|
|
||||||
cmd->pRxQ = &rx_data_queue;
|
cmd->pRxQ = &rx_data_queue;
|
||||||
cmd->pOutput = (rfc_ieeeRxOutput_t *)rf_stats;
|
cmd->pOutput = (rfc_ieeeRxOutput_t *)rf_stats;
|
||||||
@ -568,7 +608,7 @@ init_rf_params(void)
|
|||||||
cmd->frameFiltOpt.defaultPend = 0;
|
cmd->frameFiltOpt.defaultPend = 0;
|
||||||
cmd->frameFiltOpt.bPendDataReqOnly = 0;
|
cmd->frameFiltOpt.bPendDataReqOnly = 0;
|
||||||
cmd->frameFiltOpt.bPanCoord = 0;
|
cmd->frameFiltOpt.bPanCoord = 0;
|
||||||
cmd->frameFiltOpt.maxFrameVersion = 1;
|
cmd->frameFiltOpt.maxFrameVersion = 2;
|
||||||
cmd->frameFiltOpt.bStrictLenFilter = 0;
|
cmd->frameFiltOpt.bStrictLenFilter = 0;
|
||||||
|
|
||||||
/* Receive all frame types */
|
/* Receive all frame types */
|
||||||
@ -584,9 +624,9 @@ init_rf_params(void)
|
|||||||
/* Configure CCA settings */
|
/* Configure CCA settings */
|
||||||
cmd->ccaOpt.ccaEnEnergy = 1;
|
cmd->ccaOpt.ccaEnEnergy = 1;
|
||||||
cmd->ccaOpt.ccaEnCorr = 1;
|
cmd->ccaOpt.ccaEnCorr = 1;
|
||||||
cmd->ccaOpt.ccaEnSync = 0;
|
cmd->ccaOpt.ccaEnSync = 1;
|
||||||
cmd->ccaOpt.ccaCorrOp = 1;
|
cmd->ccaOpt.ccaCorrOp = 1;
|
||||||
cmd->ccaOpt.ccaSyncOp = 1;
|
cmd->ccaOpt.ccaSyncOp = 0;
|
||||||
cmd->ccaOpt.ccaCorrThr = 3;
|
cmd->ccaOpt.ccaCorrThr = 3;
|
||||||
|
|
||||||
cmd->ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD;
|
cmd->ccaRssiThr = IEEE_MODE_RSSI_THRESHOLD;
|
||||||
@ -598,6 +638,11 @@ init_rf_params(void)
|
|||||||
|
|
||||||
cmd->endTrigger.triggerType = TRIG_NEVER;
|
cmd->endTrigger.triggerType = TRIG_NEVER;
|
||||||
cmd->endTime = 0x00000000;
|
cmd->endTime = 0x00000000;
|
||||||
|
|
||||||
|
/* set address filter command */
|
||||||
|
filter_cmd.commandNo = CMD_IEEE_MOD_FILT;
|
||||||
|
memcpy(&filter_cmd.newFrameFiltOpt, &cmd->frameFiltOpt, sizeof(cmd->frameFiltOpt));
|
||||||
|
memcpy(&filter_cmd.newFrameTypes, &cmd->frameTypes, sizeof(cmd->frameTypes));
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static int
|
static int
|
||||||
@ -647,13 +692,14 @@ rx_off(void)
|
|||||||
if(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_STOPPED ||
|
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) {
|
RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_ABORT) {
|
||||||
/* Stopped gracefully */
|
/* Stopped gracefully */
|
||||||
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
|
|
||||||
ret = RF_CORE_CMD_OK;
|
ret = RF_CORE_CMD_OK;
|
||||||
} else {
|
} else {
|
||||||
PRINTF("RX off: BG status=0x%04x\n", RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf));
|
PRINTF("RX off: BG status=0x%04x\n", RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf));
|
||||||
ret = RF_CORE_CMD_ERROR;
|
ret = RF_CORE_CMD_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@ -712,6 +758,55 @@ static const rf_core_primary_mode_t mode_ieee = {
|
|||||||
soft_on,
|
soft_on,
|
||||||
};
|
};
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
check_rat_overflow(bool first_time)
|
||||||
|
{
|
||||||
|
static uint32_t last_value;
|
||||||
|
uint32_t current_value;
|
||||||
|
uint8_t interrupts_enabled;
|
||||||
|
|
||||||
|
interrupts_enabled = 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_enabled) {
|
||||||
|
ti_lib_int_master_enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
handle_rat_overflow(void *unused)
|
||||||
|
{
|
||||||
|
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, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2,
|
||||||
|
handle_rat_overflow, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check_rat_overflow(false);
|
||||||
|
|
||||||
|
if(was_off) {
|
||||||
|
off();
|
||||||
|
}
|
||||||
|
|
||||||
|
ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2,
|
||||||
|
handle_rat_overflow, NULL);
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
static int
|
static int
|
||||||
init(void)
|
init(void)
|
||||||
{
|
{
|
||||||
@ -745,6 +840,10 @@ init(void)
|
|||||||
|
|
||||||
rf_core_primary_mode_register(&mode_ieee);
|
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);
|
||||||
|
|
||||||
process_start(&rf_core_process, NULL);
|
process_start(&rf_core_process, NULL);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -755,7 +854,7 @@ prepare(const void *payload, unsigned short payload_len)
|
|||||||
int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN);
|
int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN);
|
||||||
|
|
||||||
memcpy(&tx_buf[TX_BUF_HDR_LEN], payload, len);
|
memcpy(&tx_buf[TX_BUF_HDR_LEN], payload, len);
|
||||||
return RF_CORE_CMD_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static int
|
static int
|
||||||
@ -768,6 +867,7 @@ transmit(unsigned short transmit_len)
|
|||||||
uint8_t tx_active = 0;
|
uint8_t tx_active = 0;
|
||||||
rtimer_clock_t t0;
|
rtimer_clock_t t0;
|
||||||
volatile rfc_CMD_IEEE_TX_t cmd;
|
volatile rfc_CMD_IEEE_TX_t cmd;
|
||||||
|
uint8_t interrupts_enabled;
|
||||||
|
|
||||||
if(!rf_is_on()) {
|
if(!rf_is_on()) {
|
||||||
was_off = 1;
|
was_off = 1;
|
||||||
@ -805,8 +905,19 @@ transmit(unsigned short transmit_len)
|
|||||||
cmd.payloadLen = transmit_len;
|
cmd.payloadLen = transmit_len;
|
||||||
cmd.pPayload = &tx_buf[TX_BUF_HDR_LEN];
|
cmd.pPayload = &tx_buf[TX_BUF_HDR_LEN];
|
||||||
|
|
||||||
|
cmd.startTime = 0;
|
||||||
|
cmd.startTrigger.triggerType = TRIG_NOW;
|
||||||
|
|
||||||
|
/* XXX: there seems to be no function that gets interrupt state w/o changing it */
|
||||||
|
interrupts_enabled = ti_lib_int_master_disable();
|
||||||
|
if(interrupts_enabled) {
|
||||||
|
ti_lib_int_master_enable();
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable the LAST_FG_COMMAND_DONE interrupt, which will wake us up */
|
/* Enable the LAST_FG_COMMAND_DONE interrupt, which will wake us up */
|
||||||
rf_core_cmd_done_en(true);
|
if(interrupts_enabled) {
|
||||||
|
rf_core_cmd_done_en(true, poll_mode);
|
||||||
|
}
|
||||||
|
|
||||||
ret = rf_core_send_cmd((uint32_t)&cmd, &cmd_status);
|
ret = rf_core_send_cmd((uint32_t)&cmd, &cmd_status);
|
||||||
|
|
||||||
@ -818,7 +929,14 @@ transmit(unsigned short transmit_len)
|
|||||||
/* Idle away while the command is running */
|
/* Idle away while the command is running */
|
||||||
while((cmd.status & RF_CORE_RADIO_OP_MASKED_STATUS)
|
while((cmd.status & RF_CORE_RADIO_OP_MASKED_STATUS)
|
||||||
== RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING) {
|
== 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(interrupts_enabled) {
|
||||||
|
lpm_sleep();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stat = cmd.status;
|
stat = cmd.status;
|
||||||
@ -848,12 +966,13 @@ transmit(unsigned short transmit_len)
|
|||||||
ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
|
ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
|
||||||
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
|
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
|
||||||
|
|
||||||
/*
|
if(interrupts_enabled) {
|
||||||
* Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it
|
/*
|
||||||
* except when we are transmitting
|
* Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it
|
||||||
*/
|
* except when we are transmitting
|
||||||
rf_core_cmd_done_dis();
|
*/
|
||||||
|
rf_core_cmd_done_dis(poll_mode);
|
||||||
|
}
|
||||||
|
|
||||||
if(was_off) {
|
if(was_off) {
|
||||||
off();
|
off();
|
||||||
@ -880,13 +999,48 @@ release_data_entry(void)
|
|||||||
/* Set status to 0 "Pending" in element */
|
/* Set status to 0 "Pending" in element */
|
||||||
entry->status = DATA_ENTRY_STATUS_PENDING;
|
entry->status = DATA_ENTRY_STATUS_PENDING;
|
||||||
rx_read_entry = entry->pNextEntry;
|
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 = 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
|
static int
|
||||||
read_frame(void *buf, unsigned short buf_len)
|
read_frame(void *buf, unsigned short buf_len)
|
||||||
{
|
{
|
||||||
int8_t rssi;
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry;
|
rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry;
|
||||||
|
uint32_t rat_timestamp;
|
||||||
|
|
||||||
|
if(rf_is_on()) {
|
||||||
|
check_rat_overflow(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 / 250)));
|
||||||
|
|
||||||
if(entry->status != DATA_ENTRY_STATUS_FINISHED) {
|
if(entry->status != DATA_ENTRY_STATUS_FINISHED) {
|
||||||
/* No available data */
|
/* No available data */
|
||||||
@ -901,7 +1055,7 @@ read_frame(void *buf, unsigned short buf_len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = rx_read_entry[8] - 4;
|
len = rx_read_entry[8] - 8;
|
||||||
|
|
||||||
if(len > buf_len) {
|
if(len > buf_len) {
|
||||||
PRINTF("RF: too long\n");
|
PRINTF("RF: too long\n");
|
||||||
@ -913,9 +1067,21 @@ read_frame(void *buf, unsigned short buf_len)
|
|||||||
|
|
||||||
memcpy(buf, (char *)&rx_read_entry[9], len);
|
memcpy(buf, (char *)&rx_read_entry[9], len);
|
||||||
|
|
||||||
rssi = (int8_t)rx_read_entry[9 + len + 2];
|
last_rssi = (int8_t)rx_read_entry[9 + len + 2];
|
||||||
|
last_corr_lqi = (uint8_t)rx_read_entry[9 + len + 2] & STATUS_CORRELATION;
|
||||||
|
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
|
/* get the timestamp */
|
||||||
|
memcpy(&rat_timestamp, (char *)rx_read_entry + 9 + len + 4, 4);
|
||||||
|
|
||||||
|
last_packet_timestamp = calc_last_packet_timestamp(rat_timestamp);
|
||||||
|
|
||||||
|
if(!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);
|
||||||
|
}
|
||||||
RIMESTATS_ADD(llrx);
|
RIMESTATS_ADD(llrx);
|
||||||
|
|
||||||
release_data_entry();
|
release_data_entry();
|
||||||
@ -983,9 +1149,7 @@ channel_clear(void)
|
|||||||
static int
|
static int
|
||||||
receiving_packet(void)
|
receiving_packet(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
|
||||||
uint8_t cca_info;
|
uint8_t cca_info;
|
||||||
uint8_t was_off = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are in the middle of a BLE operation, we got called by ContikiMAC
|
* If we are in the middle of a BLE operation, we got called by ContikiMAC
|
||||||
@ -1010,19 +1174,17 @@ receiving_packet(void)
|
|||||||
|
|
||||||
cca_info = get_cca_info();
|
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_GET_CCA_INFO_ERROR) {
|
||||||
/* If we can't read CCA info, return "not receiving" */
|
return 0;
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
/* Return 1 (receiving) if ccaState is busy */
|
|
||||||
ret = (cca_info & 0x03) == RF_CMD_CCA_REQ_CCA_STATE_BUSY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(was_off) {
|
/* If sync has been seen, return 1 (receiving) */
|
||||||
off();
|
if(cca_info & RF_CMD_CCA_REQ_CCA_SYNC_BUSY) {
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static int
|
static int
|
||||||
@ -1033,9 +1195,12 @@ pending_packet(void)
|
|||||||
|
|
||||||
/* Go through all RX buffers and check their status */
|
/* Go through all RX buffers and check their status */
|
||||||
do {
|
do {
|
||||||
if(entry->status == DATA_ENTRY_STATUS_FINISHED) {
|
if(entry->status == DATA_ENTRY_STATUS_FINISHED
|
||||||
|
|| entry->status == DATA_ENTRY_STATUS_BUSY) {
|
||||||
rv = 1;
|
rv = 1;
|
||||||
process_poll(&rf_core_process);
|
if(!poll_mode) {
|
||||||
|
process_poll(&rf_core_process);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = (rfc_dataEntry_t *)entry->pNextEntry;
|
entry = (rfc_dataEntry_t *)entry->pNextEntry;
|
||||||
@ -1057,11 +1222,13 @@ on(void)
|
|||||||
return RF_CORE_CMD_OK;
|
return RF_CORE_CMD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !CC2650_FAST_RADIO_STARTUP
|
||||||
/*
|
/*
|
||||||
* Request the HF XOSC as the source for the HF clock. Needed before we can
|
* 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.
|
* use the FS. This will only request, it will _not_ perform the switch.
|
||||||
*/
|
*/
|
||||||
oscillators_request_hf_xosc();
|
oscillators_request_hf_xosc();
|
||||||
|
#endif
|
||||||
|
|
||||||
if(rf_is_on()) {
|
if(rf_is_on()) {
|
||||||
PRINTF("on: We were on. PD=%u, RX=0x%04x \n", rf_core_is_accessible(),
|
PRINTF("on: We were on. PD=%u, RX=0x%04x \n", rf_core_is_accessible(),
|
||||||
@ -1069,21 +1236,22 @@ on(void)
|
|||||||
return RF_CORE_CMD_OK;
|
return RF_CORE_CMD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init_rx_buffers();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trigger a switch to the XOSC, so that we can subsequently use the RF FS
|
||||||
|
* This will block until the XOSC is actually ready, but give how we
|
||||||
|
* requested it early on, this won't be too long a wait.
|
||||||
|
* This should be done before starting the RAT.
|
||||||
|
*/
|
||||||
|
oscillators_switch_to_hf_xosc();
|
||||||
|
|
||||||
if(rf_core_boot() != RF_CORE_CMD_OK) {
|
if(rf_core_boot() != RF_CORE_CMD_OK) {
|
||||||
PRINTF("on: rf_core_boot() failed\n");
|
PRINTF("on: rf_core_boot() failed\n");
|
||||||
return RF_CORE_CMD_ERROR;
|
return RF_CORE_CMD_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_rx_buffers();
|
rf_core_setup_interrupts(poll_mode);
|
||||||
|
|
||||||
rf_core_setup_interrupts();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Trigger a switch to the XOSC, so that we can subsequently use the RF FS
|
|
||||||
* This will block until the XOSC is actually ready, but give how we
|
|
||||||
* requested it early on, this won't be too long a wait/
|
|
||||||
*/
|
|
||||||
oscillators_switch_to_hf_xosc();
|
|
||||||
|
|
||||||
if(rf_radio_setup() != RF_CORE_CMD_OK) {
|
if(rf_radio_setup() != RF_CORE_CMD_OK) {
|
||||||
PRINTF("on: radio_setup() failed\n");
|
PRINTF("on: radio_setup() failed\n");
|
||||||
@ -1113,8 +1281,12 @@ off(void)
|
|||||||
|
|
||||||
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
|
ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
|
||||||
|
|
||||||
/* Switch HF clock source to the RCOSC to preserve power */
|
#if !CC2650_FAST_RADIO_STARTUP
|
||||||
|
/* Switch HF clock source to the RCOSC to preserve power.
|
||||||
|
* This must be done after stopping RAT.
|
||||||
|
*/
|
||||||
oscillators_switch_to_hf_rc();
|
oscillators_switch_to_hf_rc();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* We pulled the plug, so we need to restore the status manually */
|
/* We pulled the plug, so we need to restore the status manually */
|
||||||
((rfc_CMD_IEEE_RX_t *)cmd_ieee_rx_buf)->status = RF_CORE_RADIO_OP_STATUS_IDLE;
|
((rfc_CMD_IEEE_RX_t *)cmd_ieee_rx_buf)->status = RF_CORE_RADIO_OP_STATUS_IDLE;
|
||||||
@ -1123,14 +1295,33 @@ off(void)
|
|||||||
* Just in case there was an ongoing RX (which started after we begun the
|
* 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
|
* shutdown sequence), we don't want to leave the buffer in state == ongoing
|
||||||
*/
|
*/
|
||||||
((rfc_dataEntry_t *)rx_buf_0)->status = DATA_ENTRY_STATUS_PENDING;
|
if(((rfc_dataEntry_t *)rx_buf_0)->status == DATA_ENTRY_STATUS_BUSY) {
|
||||||
((rfc_dataEntry_t *)rx_buf_1)->status = DATA_ENTRY_STATUS_PENDING;
|
((rfc_dataEntry_t *)rx_buf_0)->status = DATA_ENTRY_STATUS_PENDING;
|
||||||
((rfc_dataEntry_t *)rx_buf_2)->status = DATA_ENTRY_STATUS_PENDING;
|
}
|
||||||
((rfc_dataEntry_t *)rx_buf_3)->status = DATA_ENTRY_STATUS_PENDING;
|
if(((rfc_dataEntry_t *)rx_buf_1)->status == DATA_ENTRY_STATUS_BUSY) {
|
||||||
|
((rfc_dataEntry_t *)rx_buf_1)->status = DATA_ENTRY_STATUS_PENDING;
|
||||||
|
}
|
||||||
|
if(((rfc_dataEntry_t *)rx_buf_2)->status == DATA_ENTRY_STATUS_BUSY) {
|
||||||
|
((rfc_dataEntry_t *)rx_buf_2)->status = DATA_ENTRY_STATUS_PENDING;
|
||||||
|
}
|
||||||
|
if(((rfc_dataEntry_t *)rx_buf_3)->status == DATA_ENTRY_STATUS_BUSY) {
|
||||||
|
((rfc_dataEntry_t *)rx_buf_3)->status = DATA_ENTRY_STATUS_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
return RF_CORE_CMD_OK;
|
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
|
static radio_result_t
|
||||||
get_value(radio_param_t param, radio_value_t *value)
|
get_value(radio_param_t param, radio_value_t *value)
|
||||||
{
|
{
|
||||||
@ -1162,7 +1353,13 @@ get_value(radio_param_t param, radio_value_t *value)
|
|||||||
if(cmd->frameFiltOpt.autoAckEn) {
|
if(cmd->frameFiltOpt.autoAckEn) {
|
||||||
*value |= RADIO_RX_MODE_AUTOACK;
|
*value |= RADIO_RX_MODE_AUTOACK;
|
||||||
}
|
}
|
||||||
|
if(poll_mode) {
|
||||||
|
*value |= RADIO_RX_MODE_POLL_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
|
case RADIO_PARAM_TX_MODE:
|
||||||
|
*value = 0;
|
||||||
return RADIO_RESULT_OK;
|
return RADIO_RESULT_OK;
|
||||||
case RADIO_PARAM_TXPOWER:
|
case RADIO_PARAM_TXPOWER:
|
||||||
*value = get_tx_power();
|
*value = get_tx_power();
|
||||||
@ -1190,6 +1387,12 @@ get_value(radio_param_t param, radio_value_t *value)
|
|||||||
case RADIO_CONST_TXPOWER_MAX:
|
case RADIO_CONST_TXPOWER_MAX:
|
||||||
*value = OUTPUT_POWER_MAX;
|
*value = OUTPUT_POWER_MAX;
|
||||||
return RADIO_RESULT_OK;
|
return RADIO_RESULT_OK;
|
||||||
|
case RADIO_PARAM_LAST_RSSI:
|
||||||
|
*value = last_rssi;
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
|
case RADIO_PARAM_LAST_LINK_QUALITY:
|
||||||
|
*value = last_corr_lqi;
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
default:
|
default:
|
||||||
return RADIO_RESULT_NOT_SUPPORTED;
|
return RADIO_RESULT_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
@ -1198,9 +1401,9 @@ get_value(radio_param_t param, radio_value_t *value)
|
|||||||
static radio_result_t
|
static radio_result_t
|
||||||
set_value(radio_param_t param, radio_value_t value)
|
set_value(radio_param_t param, radio_value_t value)
|
||||||
{
|
{
|
||||||
uint8_t was_off = 0;
|
|
||||||
radio_result_t rv = RADIO_RESULT_OK;
|
radio_result_t rv = RADIO_RESULT_OK;
|
||||||
rfc_CMD_IEEE_RX_t *cmd = (rfc_CMD_IEEE_RX_t *)cmd_ieee_rx_buf;
|
rfc_CMD_IEEE_RX_t *cmd = (rfc_CMD_IEEE_RX_t *)cmd_ieee_rx_buf;
|
||||||
|
uint8_t old_poll_mode;
|
||||||
|
|
||||||
switch(param) {
|
switch(param) {
|
||||||
case RADIO_PARAM_POWER_MODE:
|
case RADIO_PARAM_POWER_MODE:
|
||||||
@ -1222,6 +1425,7 @@ set_value(radio_param_t param, radio_value_t value)
|
|||||||
return RADIO_RESULT_INVALID_VALUE;
|
return RADIO_RESULT_INVALID_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note: this return may lead to long periods when RAT and RTC are not resynchronized */
|
||||||
if(cmd->channel == (uint8_t)value) {
|
if(cmd->channel == (uint8_t)value) {
|
||||||
/* We already have that very same channel configured.
|
/* We already have that very same channel configured.
|
||||||
* Nothing to do here. */
|
* Nothing to do here. */
|
||||||
@ -1239,7 +1443,7 @@ set_value(radio_param_t param, radio_value_t value)
|
|||||||
case RADIO_PARAM_RX_MODE:
|
case RADIO_PARAM_RX_MODE:
|
||||||
{
|
{
|
||||||
if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
|
if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER |
|
||||||
RADIO_RX_MODE_AUTOACK)) {
|
RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) {
|
||||||
return RADIO_RESULT_INVALID_VALUE;
|
return RADIO_RESULT_INVALID_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1252,8 +1456,30 @@ set_value(radio_param_t param, radio_value_t value)
|
|||||||
cmd->frameFiltOpt.bPendDataReqOnly = 0;
|
cmd->frameFiltOpt.bPendDataReqOnly = 0;
|
||||||
cmd->frameFiltOpt.bPanCoord = 0;
|
cmd->frameFiltOpt.bPanCoord = 0;
|
||||||
cmd->frameFiltOpt.bStrictLenFilter = 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) {
|
||||||
|
uint32_t cmd_status;
|
||||||
|
|
||||||
|
/* do not turn the radio on and off, just send an update command */
|
||||||
|
memcpy(&filter_cmd.newFrameFiltOpt, &cmd->frameFiltOpt, sizeof(cmd->frameFiltOpt));
|
||||||
|
|
||||||
|
if(rf_core_send_cmd((uint32_t)&filter_cmd, &cmd_status) == RF_CORE_CMD_ERROR) {
|
||||||
|
PRINTF("setting address filter failed: CMDSTA=0x%08lx\n", cmd_status);
|
||||||
|
return RADIO_RESULT_ERROR;
|
||||||
|
}
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
|
}
|
||||||
break;
|
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:
|
case RADIO_PARAM_TXPOWER:
|
||||||
if(value < OUTPUT_POWER_MIN || value > OUTPUT_POWER_MAX) {
|
if(value < OUTPUT_POWER_MIN || value > OUTPUT_POWER_MAX) {
|
||||||
return RADIO_RESULT_INVALID_VALUE;
|
return RADIO_RESULT_INVALID_VALUE;
|
||||||
@ -1262,37 +1488,37 @@ set_value(radio_param_t param, radio_value_t value)
|
|||||||
set_tx_power(value);
|
set_tx_power(value);
|
||||||
|
|
||||||
return RADIO_RESULT_OK;
|
return RADIO_RESULT_OK;
|
||||||
|
|
||||||
case RADIO_PARAM_CCA_THRESHOLD:
|
case RADIO_PARAM_CCA_THRESHOLD:
|
||||||
cmd->ccaRssiThr = (int8_t)value;
|
cmd->ccaRssiThr = (int8_t)value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return RADIO_RESULT_NOT_SUPPORTED;
|
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()) {
|
if(!rf_is_on()) {
|
||||||
was_off = 1;
|
return RADIO_RESULT_OK;
|
||||||
if(on() != RF_CORE_CMD_OK) {
|
|
||||||
PRINTF("set_value: on() failed (2)\n");
|
|
||||||
return RADIO_RESULT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we reach here we had no errors. Apply new settings */
|
||||||
if(rx_off() != RF_CORE_CMD_OK) {
|
if(rx_off() != RF_CORE_CMD_OK) {
|
||||||
PRINTF("set_value: rx_off() failed\n");
|
PRINTF("set_value: rx_off() failed\n");
|
||||||
rv = RADIO_RESULT_ERROR;
|
rv = RADIO_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Restart the radio timer (RAT).
|
||||||
|
This causes resynchronization between RAT and RTC: useful for TSCH. */
|
||||||
|
rf_core_restart_rat();
|
||||||
|
|
||||||
|
check_rat_overflow(false);
|
||||||
|
|
||||||
if(rx_on() != RF_CORE_CMD_OK) {
|
if(rx_on() != RF_CORE_CMD_OK) {
|
||||||
PRINTF("set_value: rx_on() failed\n");
|
PRINTF("set_value: rx_on() failed\n");
|
||||||
rv = RADIO_RESULT_ERROR;
|
rv = RADIO_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we were off, turn back off */
|
|
||||||
if(was_off) {
|
|
||||||
off();
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@ -1318,13 +1544,22 @@ get_object(radio_param_t param, void *dest, size_t size)
|
|||||||
|
|
||||||
return RADIO_RESULT_OK;
|
return RADIO_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(param == RADIO_PARAM_LAST_PACKET_TIMESTAMP) {
|
||||||
|
if(size != sizeof(rtimer_clock_t) || !dest) {
|
||||||
|
return RADIO_RESULT_INVALID_VALUE;
|
||||||
|
}
|
||||||
|
*(rtimer_clock_t *)dest = last_packet_timestamp;
|
||||||
|
|
||||||
|
return RADIO_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
return RADIO_RESULT_NOT_SUPPORTED;
|
return RADIO_RESULT_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static radio_result_t
|
static radio_result_t
|
||||||
set_object(radio_param_t param, const void *src, size_t size)
|
set_object(radio_param_t param, const void *src, size_t size)
|
||||||
{
|
{
|
||||||
uint8_t was_off = 0;
|
|
||||||
radio_result_t rv;
|
radio_result_t rv;
|
||||||
int i;
|
int i;
|
||||||
uint8_t *dst;
|
uint8_t *dst;
|
||||||
@ -1341,12 +1576,9 @@ set_object(radio_param_t param, const void *src, size_t size)
|
|||||||
dst[i] = ((uint8_t *)src)[7 - i];
|
dst[i] = ((uint8_t *)src)[7 - i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If off, the new configuration will be applied the next time radio is started */
|
||||||
if(!rf_is_on()) {
|
if(!rf_is_on()) {
|
||||||
was_off = 1;
|
return RADIO_RESULT_OK;
|
||||||
if(on() != RF_CORE_CMD_OK) {
|
|
||||||
PRINTF("set_object: on() failed\n");
|
|
||||||
return RADIO_RESULT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rx_off() != RF_CORE_CMD_OK) {
|
if(rx_off() != RF_CORE_CMD_OK) {
|
||||||
@ -1359,11 +1591,6 @@ set_object(radio_param_t param, const void *src, size_t size)
|
|||||||
rv = RADIO_RESULT_ERROR;
|
rv = RADIO_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we were off, turn back off */
|
|
||||||
if(was_off) {
|
|
||||||
off();
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
return RADIO_RESULT_NOT_SUPPORTED;
|
return RADIO_RESULT_NOT_SUPPORTED;
|
||||||
|
@ -634,7 +634,7 @@ prepare(const void *payload, unsigned short payload_len)
|
|||||||
int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN);
|
int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN);
|
||||||
|
|
||||||
memcpy(&tx_buf[TX_BUF_HDR_LEN], payload, len);
|
memcpy(&tx_buf[TX_BUF_HDR_LEN], payload, len);
|
||||||
return RF_CORE_CMD_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static int
|
static int
|
||||||
@ -683,7 +683,7 @@ transmit(unsigned short transmit_len)
|
|||||||
rx_off_prop();
|
rx_off_prop();
|
||||||
|
|
||||||
/* Enable the LAST_COMMAND_DONE interrupt to wake us up */
|
/* Enable the LAST_COMMAND_DONE interrupt to wake us up */
|
||||||
rf_core_cmd_done_en(false);
|
rf_core_cmd_done_en(false, false);
|
||||||
|
|
||||||
ret = rf_core_send_cmd((uint32_t)cmd_tx_adv, &cmd_status);
|
ret = rf_core_send_cmd((uint32_t)cmd_tx_adv, &cmd_status);
|
||||||
|
|
||||||
@ -728,7 +728,7 @@ transmit(unsigned short transmit_len)
|
|||||||
* Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it
|
* Disable LAST_FG_COMMAND_DONE interrupt. We don't really care about it
|
||||||
* except when we are transmitting
|
* except when we are transmitting
|
||||||
*/
|
*/
|
||||||
rf_core_cmd_done_dis();
|
rf_core_cmd_done_dis(false);
|
||||||
|
|
||||||
/* Workaround. Set status to IDLE */
|
/* Workaround. Set status to IDLE */
|
||||||
cmd_tx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE;
|
cmd_tx_adv->status = RF_CORE_RADIO_OP_STATUS_IDLE;
|
||||||
@ -933,7 +933,7 @@ on(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rf_core_setup_interrupts();
|
rf_core_setup_interrupts(false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trigger a switch to the XOSC, so that we can subsequently use the RF FS
|
* Trigger a switch to the XOSC, so that we can subsequently use the RF FS
|
||||||
|
@ -92,6 +92,8 @@
|
|||||||
#define ENABLED_IRQS (RX_FRAME_IRQ | ERROR_IRQ)
|
#define ENABLED_IRQS (RX_FRAME_IRQ | ERROR_IRQ)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ENABLED_IRQS_POLL_MODE (ENABLED_IRQS & ~(RX_FRAME_IRQ | ERROR_IRQ))
|
||||||
|
|
||||||
#define cc26xx_rf_cpe0_isr RFCCPE0IntHandler
|
#define cc26xx_rf_cpe0_isr RFCCPE0IntHandler
|
||||||
#define cc26xx_rf_cpe1_isr RFCCPE1IntHandler
|
#define cc26xx_rf_cpe1_isr RFCCPE1IntHandler
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@ -101,6 +103,10 @@ static rfc_radioOp_t *last_radio_op = NULL;
|
|||||||
/* A struct holding pointers to the primary mode's abort() and restore() */
|
/* A struct holding pointers to the primary mode's abort() and restore() */
|
||||||
static const rf_core_primary_mode_t *primary_mode = NULL;
|
static const rf_core_primary_mode_t *primary_mode = NULL;
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Radio timer (RAT) offset as compared to the rtimer counter (RTC) */
|
||||||
|
int32_t rat_offset = 0;
|
||||||
|
static bool rat_offset_known = false;
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
PROCESS(rf_core_process, "CC13xx / CC26xx RF driver");
|
PROCESS(rf_core_process, "CC13xx / CC26xx RF driver");
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
#define RF_CORE_CLOCKS_MASK (RFC_PWR_PWMCLKEN_RFC_M | RFC_PWR_PWMCLKEN_CPE_M \
|
#define RF_CORE_CLOCKS_MASK (RFC_PWR_PWMCLKEN_RFC_M | RFC_PWR_PWMCLKEN_CPE_M \
|
||||||
@ -265,6 +271,66 @@ rf_core_power_up()
|
|||||||
return RF_CORE_CMD_OK;
|
return RF_CORE_CMD_OK;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
uint8_t
|
||||||
|
rf_core_start_rat(void)
|
||||||
|
{
|
||||||
|
uint32_t cmd_status;
|
||||||
|
rfc_CMD_SYNC_START_RAT_t cmd_start;
|
||||||
|
|
||||||
|
/* Start radio timer (RAT) */
|
||||||
|
rf_core_init_radio_op((rfc_radioOp_t *)&cmd_start, sizeof(cmd_start), CMD_SYNC_START_RAT);
|
||||||
|
|
||||||
|
/* copy the value and send back */
|
||||||
|
cmd_start.rat0 = rat_offset;
|
||||||
|
|
||||||
|
if(rf_core_send_cmd((uint32_t)&cmd_start, &cmd_status) != RF_CORE_CMD_OK) {
|
||||||
|
PRINTF("rf_core_get_rat_rtc_offset: SYNC_START_RAT fail, CMDSTA=0x%08lx\n",
|
||||||
|
cmd_status);
|
||||||
|
return RF_CORE_CMD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until done (?) */
|
||||||
|
if(rf_core_wait_cmd_done(&cmd_start) != RF_CORE_CMD_OK) {
|
||||||
|
PRINTF("rf_core_cmd_ok: SYNC_START_RAT wait, CMDSTA=0x%08lx, status=0x%04x\n",
|
||||||
|
cmd_status, cmd_start.status);
|
||||||
|
return RF_CORE_CMD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RF_CORE_CMD_OK;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
uint8_t
|
||||||
|
rf_core_stop_rat(void)
|
||||||
|
{
|
||||||
|
rfc_CMD_SYNC_STOP_RAT_t cmd_stop;
|
||||||
|
uint32_t cmd_status;
|
||||||
|
|
||||||
|
rf_core_init_radio_op((rfc_radioOp_t *)&cmd_stop, sizeof(cmd_stop), CMD_SYNC_STOP_RAT);
|
||||||
|
|
||||||
|
int ret = rf_core_send_cmd((uint32_t)&cmd_stop, &cmd_status);
|
||||||
|
if(ret != RF_CORE_CMD_OK) {
|
||||||
|
PRINTF("rf_core_get_rat_rtc_offset: SYNC_STOP_RAT fail, ret %d CMDSTA=0x%08lx\n",
|
||||||
|
ret, cmd_status);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until done */
|
||||||
|
ret = rf_core_wait_cmd_done(&cmd_stop);
|
||||||
|
if(ret != RF_CORE_CMD_OK) {
|
||||||
|
PRINTF("rf_core_cmd_ok: SYNC_STOP_RAT wait, CMDSTA=0x%08lx, status=0x%04x\n",
|
||||||
|
cmd_status, cmd_stop.status);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!rat_offset_known) {
|
||||||
|
/* save the offset, but only if this is the first time */
|
||||||
|
rat_offset_known = true;
|
||||||
|
rat_offset = cmd_stop.rat0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RF_CORE_CMD_OK;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
rf_core_power_down()
|
rf_core_power_down()
|
||||||
{
|
{
|
||||||
@ -280,6 +346,8 @@ rf_core_power_down()
|
|||||||
fs_powerdown();
|
fs_powerdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rf_core_stop_rat();
|
||||||
|
|
||||||
/* Shut down the RFCORE clock domain in the MCU VD */
|
/* Shut down the RFCORE clock domain in the MCU VD */
|
||||||
ti_lib_prcm_domain_disable(PRCM_DOMAIN_RFCORE);
|
ti_lib_prcm_domain_disable(PRCM_DOMAIN_RFCORE);
|
||||||
ti_lib_prcm_load_set();
|
ti_lib_prcm_load_set();
|
||||||
@ -329,22 +397,6 @@ rf_core_set_modesel()
|
|||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
uint8_t
|
uint8_t
|
||||||
rf_core_start_rat()
|
|
||||||
{
|
|
||||||
uint32_t cmd_status;
|
|
||||||
|
|
||||||
/* Start radio timer (RAT) */
|
|
||||||
if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_START_RAT), &cmd_status)
|
|
||||||
!= RF_CORE_CMD_OK) {
|
|
||||||
PRINTF("rf_core_apply_patches: START_RAT fail, CMDSTA=0x%08lx\n",
|
|
||||||
cmd_status);
|
|
||||||
return RF_CORE_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RF_CORE_CMD_OK;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
uint8_t
|
|
||||||
rf_core_boot()
|
rf_core_boot()
|
||||||
{
|
{
|
||||||
if(rf_core_power_up() != RF_CORE_CMD_OK) {
|
if(rf_core_power_up() != RF_CORE_CMD_OK) {
|
||||||
@ -366,10 +418,31 @@ rf_core_boot()
|
|||||||
return RF_CORE_CMD_OK;
|
return RF_CORE_CMD_OK;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
uint8_t
|
||||||
|
rf_core_restart_rat(void)
|
||||||
|
{
|
||||||
|
if(rf_core_stop_rat() != RF_CORE_CMD_OK) {
|
||||||
|
PRINTF("rf_core_restart_rat: rf_core_stop_rat() failed\n");
|
||||||
|
|
||||||
|
return RF_CORE_CMD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rf_core_start_rat() != RF_CORE_CMD_OK) {
|
||||||
|
PRINTF("rf_core_restart_rat: rf_core_start_rat() failed\n");
|
||||||
|
|
||||||
|
rf_core_power_down();
|
||||||
|
|
||||||
|
return RF_CORE_CMD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RF_CORE_CMD_OK;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
rf_core_setup_interrupts()
|
rf_core_setup_interrupts(bool poll_mode)
|
||||||
{
|
{
|
||||||
bool interrupts_disabled;
|
bool interrupts_disabled;
|
||||||
|
const uint32_t enabled_irqs = poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS;
|
||||||
|
|
||||||
/* We are already turned on by the caller, so this should not happen */
|
/* We are already turned on by the caller, so this should not happen */
|
||||||
if(!rf_core_is_accessible()) {
|
if(!rf_core_is_accessible()) {
|
||||||
@ -384,7 +457,7 @@ rf_core_setup_interrupts()
|
|||||||
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEISL) = ERROR_IRQ;
|
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEISL) = ERROR_IRQ;
|
||||||
|
|
||||||
/* Acknowledge configured interrupts */
|
/* Acknowledge configured interrupts */
|
||||||
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = ENABLED_IRQS;
|
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = enabled_irqs;
|
||||||
|
|
||||||
/* Clear interrupt flags, active low clear(?) */
|
/* Clear interrupt flags, active low clear(?) */
|
||||||
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0x0;
|
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0x0;
|
||||||
@ -400,18 +473,20 @@ rf_core_setup_interrupts()
|
|||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
rf_core_cmd_done_en(bool fg)
|
rf_core_cmd_done_en(bool fg, bool poll_mode)
|
||||||
{
|
{
|
||||||
uint32_t irq = fg ? IRQ_LAST_FG_COMMAND_DONE : IRQ_LAST_COMMAND_DONE;
|
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;
|
||||||
|
|
||||||
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 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;
|
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = enabled_irqs | irq;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
rf_core_cmd_done_dis()
|
rf_core_cmd_done_dis(bool poll_mode)
|
||||||
{
|
{
|
||||||
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = ENABLED_IRQS;
|
const uint32_t enabled_irqs = poll_mode ? ENABLED_IRQS_POLL_MODE : ENABLED_IRQS;
|
||||||
|
HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = enabled_irqs;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
rfc_radioOp_t *
|
rfc_radioOp_t *
|
||||||
|
@ -228,6 +228,9 @@ typedef struct rf_core_primary_mode_s {
|
|||||||
#define RF_CORE_COMMAND_PROTOCOL_IEEE 0x2000
|
#define RF_CORE_COMMAND_PROTOCOL_IEEE 0x2000
|
||||||
#define RF_CORE_COMMAND_PROTOCOL_PROP 0x3000
|
#define RF_CORE_COMMAND_PROTOCOL_PROP 0x3000
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Radio timer register */
|
||||||
|
#define RATCNT 0x00000004
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Make the main driver process visible to mode drivers */
|
/* Make the main driver process visible to mode drivers */
|
||||||
PROCESS_NAME(rf_core_process);
|
PROCESS_NAME(rf_core_process);
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@ -310,6 +313,24 @@ uint8_t rf_core_set_modesel(void);
|
|||||||
*/
|
*/
|
||||||
uint8_t rf_core_start_rat(void);
|
uint8_t rf_core_start_rat(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Stop the CM0 RAT synchronously
|
||||||
|
* \return RF_CORE_CMD_OK or RF_CORE_CMD_ERROR
|
||||||
|
*
|
||||||
|
* This function is not strictly necessary, but through calling it it's possibly
|
||||||
|
* to learn the RAT / RTC offset, which useful to get accurate radio timestamps.
|
||||||
|
*/
|
||||||
|
uint8_t rf_core_stop_rat(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Restart the CM0 RAT
|
||||||
|
* \return RF_CORE_CMD_OK or RF_CORE_CMD_ERROR
|
||||||
|
*
|
||||||
|
* This function restarts the CM0 RAT and therefore resynchornizes it with RTC.
|
||||||
|
* To achieve good timing accuracy, it should be called periodically.
|
||||||
|
*/
|
||||||
|
uint8_t rf_core_restart_rat(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Boot the RF Core
|
* \brief Boot the RF Core
|
||||||
* \return RF_CORE_CMD_OK or RF_CORE_CMD_ERROR
|
* \return RF_CORE_CMD_OK or RF_CORE_CMD_ERROR
|
||||||
@ -327,19 +348,20 @@ uint8_t rf_core_boot(void);
|
|||||||
/**
|
/**
|
||||||
* \brief Setup RF core interrupts
|
* \brief Setup RF core interrupts
|
||||||
*/
|
*/
|
||||||
void rf_core_setup_interrupts(void);
|
void rf_core_setup_interrupts(bool poll_mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Enable interrupt on command done.
|
* \brief Enable interrupt on command done.
|
||||||
* \param fg set true to enable irq on foreground command done and false for
|
* \param fg set true to enable irq on foreground command done and false for
|
||||||
* background commands or if not in ieee mode.
|
* 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
|
* This is used within TX routines in order to be able to sleep the CM3 and
|
||||||
* wake up after TX has finished
|
* wake up after TX has finished
|
||||||
*
|
*
|
||||||
* \sa rf_core_cmd_done_dis()
|
* \sa rf_core_cmd_done_dis()
|
||||||
*/
|
*/
|
||||||
void rf_core_cmd_done_en(bool fg);
|
void rf_core_cmd_done_en(bool fg, bool poll_mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Disable the LAST_CMD_DONE and LAST_FG_CMD_DONE interrupts.
|
* \brief Disable the LAST_CMD_DONE and LAST_FG_CMD_DONE interrupts.
|
||||||
@ -348,7 +370,7 @@ void rf_core_cmd_done_en(bool fg);
|
|||||||
*
|
*
|
||||||
* \sa rf_core_cmd_done_en()
|
* \sa rf_core_cmd_done_en()
|
||||||
*/
|
*/
|
||||||
void rf_core_cmd_done_dis(void);
|
void rf_core_cmd_done_dis(bool poll_mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Returns a pointer to the most recent proto-dependent Radio Op
|
* \brief Returns a pointer to the most recent proto-dependent Radio Op
|
||||||
|
@ -50,6 +50,21 @@
|
|||||||
#define RTIMER_ARCH_SECOND 65536
|
#define RTIMER_ARCH_SECOND 65536
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
rtimer_clock_t rtimer_arch_now(void);
|
rtimer_clock_t rtimer_arch_now(void);
|
||||||
|
|
||||||
|
/* HW oscillator frequency is 32 kHz, not 64 kHz and RTIMER_NOW() never returns
|
||||||
|
* an odd value; so US_TO_RTIMERTICKS always rounds to the nearest even number.
|
||||||
|
*/
|
||||||
|
#define US_TO_RTIMERTICKS(US) (2 * ((US) >= 0 ? \
|
||||||
|
(((int32_t)(US) * (RTIMER_ARCH_SECOND / 2) + 500000) / 1000000L) : \
|
||||||
|
((int32_t)(US) * (RTIMER_ARCH_SECOND / 2) - 500000) / 1000000L))
|
||||||
|
|
||||||
|
#define RTIMERTICKS_TO_US(T) ((T) >= 0 ? \
|
||||||
|
(((int32_t)(T) * 1000000L + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)) : \
|
||||||
|
((int32_t)(T) * 1000000L - ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND))
|
||||||
|
|
||||||
|
/* A 64-bit version because the 32-bit one cannot handle T >= 4295 ticks.
|
||||||
|
Intended only for positive values of T. */
|
||||||
|
#define RTIMERTICKS_TO_US_64(T) ((uint32_t)(((uint64_t)(T) * 1000000 + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)))
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
#endif /* RTIMER_ARCH_H_ */
|
#endif /* RTIMER_ARCH_H_ */
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -329,6 +329,55 @@ typedef uint32_t uip_stats_t;
|
|||||||
*/
|
*/
|
||||||
typedef uint32_t rtimer_clock_t;
|
typedef uint32_t rtimer_clock_t;
|
||||||
#define RTIMER_CLOCK_DIFF(a, b) ((int32_t)((a) - (b)))
|
#define RTIMER_CLOCK_DIFF(a, b) ((int32_t)((a) - (b)))
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
/* TSCH related defines */
|
||||||
|
|
||||||
|
/* Delay between GO signal and SFD */
|
||||||
|
#define RADIO_DELAY_BEFORE_TX ((unsigned)US_TO_RTIMERTICKS(81))
|
||||||
|
/* 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))
|
||||||
|
/* Delay between the SFD finishes arriving and it is detected in software.
|
||||||
|
* Not important on this platform as it uses hardware timestamps for SFD */
|
||||||
|
#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(0))
|
||||||
|
|
||||||
|
/* Timer conversion; radio is running at 4 MHz */
|
||||||
|
#define RADIO_TIMER_SECOND 4000000u
|
||||||
|
#if (RTIMER_SECOND % 256) || (RADIO_TIMER_SECOND % 256)
|
||||||
|
#error RADIO_TO_RTIMER macro must be fixed!
|
||||||
|
#endif
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* Disable TSCH frame filtering */
|
||||||
|
#define TSCH_CONF_HW_FRAME_FILTERING 0
|
||||||
|
|
||||||
|
/* Disable turning off HF oscillator when radio is off;
|
||||||
|
enable this for TSCH, disable to save more energy. */
|
||||||
|
#ifndef CC2650_FAST_RADIO_STARTUP
|
||||||
|
#define CC2650_FAST_RADIO_STARTUP 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Use hardware timestamps */
|
||||||
|
#ifndef TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS
|
||||||
|
#define TSCH_CONF_RESYNC_WITH_SFD_TIMESTAMPS 1
|
||||||
|
#define TSCH_CONF_TIMESYNC_REMOVE_JITTER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The drift compared to "true" 10ms slots.
|
||||||
|
Enable adaptive sync to enable compensation for this. */
|
||||||
|
#define TSCH_CONF_BASE_DRIFT_PPM -977
|
||||||
|
|
||||||
|
/* 10 times per second */
|
||||||
|
#define TSCH_CONF_ASSOCIATION_CHANNEL_SWITCH_FREQUENCY 10
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* board.h assumes that basic configuration is done */
|
/* board.h assumes that basic configuration is done */
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "sys/clock.h"
|
#include "sys/clock.h"
|
||||||
#include "sys/rtimer.h"
|
#include "sys/rtimer.h"
|
||||||
|
#include "sys/node-id.h"
|
||||||
#include "lib/sensors.h"
|
#include "lib/sensors.h"
|
||||||
#include "button-sensor.h"
|
#include "button-sensor.h"
|
||||||
#include "dev/serial-line.h"
|
#include "dev/serial-line.h"
|
||||||
@ -68,6 +69,8 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
unsigned short node_id = 0;
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
/** \brief Board specific iniatialisation */
|
/** \brief Board specific iniatialisation */
|
||||||
void board_init(void);
|
void board_init(void);
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@ -123,6 +126,10 @@ set_rf_params(void)
|
|||||||
printf("%02x\n", linkaddr_node_addr.u8[i]);
|
printf("%02x\n", linkaddr_node_addr.u8[i]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* also set the global node id */
|
||||||
|
node_id = short_addr;
|
||||||
|
printf(" Node ID: %d\n", node_id);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
@ -142,6 +149,11 @@ main(void)
|
|||||||
/* Set the LF XOSC as the LF system clock source */
|
/* Set the LF XOSC as the LF system clock source */
|
||||||
oscillators_select_lf_xosc();
|
oscillators_select_lf_xosc();
|
||||||
|
|
||||||
|
#if CC2650_FAST_RADIO_STARTUP
|
||||||
|
/* Also request HF XOSC to start up */
|
||||||
|
oscillators_request_hf_xosc();
|
||||||
|
#endif
|
||||||
|
|
||||||
lpm_init();
|
lpm_init();
|
||||||
|
|
||||||
board_init();
|
board_init();
|
||||||
|
Loading…
Reference in New Issue
Block a user