CC26xx IEEE mode: more robust radio timer handling: do not crash the system in case the radio timer failed to start; allow the overflow checker to be called when the radio is off

This commit is contained in:
Atis Elsts 2017-03-14 18:41:05 +00:00
parent dbd9d32daf
commit 3b090d97c7

View File

@ -211,7 +211,7 @@ static uint64_t last_rat_timestamp64 = 0;
/* For RAT overflow handling */ /* For RAT overflow handling */
static struct ctimer rat_overflow_timer; static struct ctimer rat_overflow_timer;
static uint32_t rat_overflow_counter = 0; static volatile uint32_t rat_overflow_counter = 0;
static rtimer_clock_t last_rat_overflow = 0; static rtimer_clock_t last_rat_overflow = 0;
/* RAT has 32-bit register, overflows once 18 minutes */ /* RAT has 32-bit register, overflows once 18 minutes */
@ -759,20 +759,25 @@ static const rf_core_primary_mode_t mode_ieee = {
soft_on, soft_on,
}; };
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static uint8_t
check_rat_overflow(bool first_time) check_rat_overflow(bool first_time)
{ {
static uint32_t last_value; static uint32_t last_value;
uint32_t current_value; uint32_t current_value;
uint8_t interrupts_disabled; uint8_t interrupts_disabled;
/* Bail out if the RF is not on */
if(!rf_is_on()) {
return 0;
}
interrupts_disabled = ti_lib_int_master_disable(); interrupts_disabled = ti_lib_int_master_disable();
if(first_time) { if(first_time) {
last_value = HWREG(RFC_RAT_BASE + RATCNT); last_value = HWREG(RFC_RAT_BASE + RATCNT);
} else { } else {
current_value = HWREG(RFC_RAT_BASE + RATCNT); current_value = HWREG(RFC_RAT_BASE + RATCNT);
if(current_value + RAT_RANGE / 4 < last_value) { if(current_value + RAT_RANGE / 4 < last_value) {
/* overflow detected */ /* Overflow detected */
last_rat_overflow = RTIMER_NOW(); last_rat_overflow = RTIMER_NOW();
rat_overflow_counter++; rat_overflow_counter++;
} }
@ -781,31 +786,40 @@ check_rat_overflow(bool first_time)
if(!interrupts_disabled) { if(!interrupts_disabled) {
ti_lib_int_master_enable(); ti_lib_int_master_enable();
} }
return 1;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
handle_rat_overflow(void *unused) handle_rat_overflow(void *unused)
{ {
uint8_t success;
uint8_t was_off = 0; uint8_t was_off = 0;
if(!rf_is_on()) { if(!rf_is_on()) {
was_off = 1; was_off = 1;
if(on() != RF_CORE_CMD_OK) { if(on() != RF_CORE_CMD_OK) {
PRINTF("overflow: on() failed\n"); PRINTF("overflow: on() failed\n");
ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, ctimer_set(&rat_overflow_timer, CLOCK_SECOND,
handle_rat_overflow, NULL); handle_rat_overflow, NULL);
return; return;
} }
} }
check_rat_overflow(false); success = check_rat_overflow(false);
if(was_off) { if(was_off) {
off(); off();
} }
ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, if(success) {
handle_rat_overflow, NULL); /* Retry after half of the interval */
ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2,
handle_rat_overflow, NULL);
} else {
/* Retry sooner */
ctimer_set(&rat_overflow_timer, CLOCK_SECOND,
handle_rat_overflow, NULL);
}
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int static int
@ -995,7 +1009,22 @@ static uint32_t
calc_last_packet_timestamp(uint32_t rat_timestamp) calc_last_packet_timestamp(uint32_t rat_timestamp)
{ {
uint64_t rat_timestamp64; uint64_t rat_timestamp64;
uint32_t adjusted_overflow_counter = rat_overflow_counter; uint32_t adjusted_overflow_counter;
uint8_t was_off = 0;
if(!rf_is_on()) {
was_off = 1;
on();
}
if(rf_is_on()) {
check_rat_overflow(false);
if(was_off) {
off();
}
}
adjusted_overflow_counter = rat_overflow_counter;
/* if the timestamp is large and the last oveflow was recently, /* if the timestamp is large and the last oveflow was recently,
assume that the timestamp refers to the time before the overflow */ assume that the timestamp refers to the time before the overflow */
@ -1023,10 +1052,6 @@ read_frame(void *buf, unsigned short buf_len)
rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry;
uint32_t rat_timestamp; uint32_t rat_timestamp;
if(rf_is_on()) {
check_rat_overflow(false);
}
/* wait for entry to become finished */ /* wait for entry to become finished */
rtimer_clock_t t0 = RTIMER_NOW(); rtimer_clock_t t0 = RTIMER_NOW();
while(entry->status == DATA_ENTRY_STATUS_BUSY while(entry->status == DATA_ENTRY_STATUS_BUSY
@ -1498,9 +1523,9 @@ set_value(radio_param_t param, radio_value_t value)
/* Restart the radio timer (RAT). /* Restart the radio timer (RAT).
This causes resynchronization between RAT and RTC: useful for TSCH. */ This causes resynchronization between RAT and RTC: useful for TSCH. */
rf_core_restart_rat(); if(rf_core_restart_rat() == RF_CORE_CMD_OK) {
check_rat_overflow(false);
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");