[FL-1472, FL-1596, FL-1673] IRDA: stability improvements (#655)

- Restrict with 31 bytes length for remote and signal name
- Don't stuck for 0 PWM cycle timings
- Support timings > 65535 PWM cycles
- Fix remote file open error
- Add IRDA TX debug redirect
- Add remote parse error print, improve parsing, support tabs
- Fix stucks with uncorrect RAW signal values, long strings in remote file, etc
- Fix HAL signals capturing (save previous read value)
- Fix leak in case of failed parsing
This commit is contained in:
Albert Kharisov
2021-08-19 03:18:42 +03:00
committed by GitHub
parent 9d38f28de7
commit 5f6aff2255
19 changed files with 347 additions and 177 deletions

View File

@@ -38,7 +38,6 @@ FuriHalIrdaTxGetDataState irda_get_raw_data_callback (void* context, uint32_t* d
void irda_send_raw_ext(const uint32_t timings[], uint32_t timings_cnt, bool start_from_mark, uint32_t frequency, float duty_cycle) {
furi_assert(timings);
furi_assert(timings_cnt > 1);
irda_tx_raw_start_from_mark = start_from_mark;
irda_tx_raw_timings_index = 0;
@@ -56,7 +55,7 @@ void irda_send_raw(const uint32_t timings[], uint32_t timings_cnt, bool start_fr
}
FuriHalIrdaTxGetDataState irda_get_data_callback (void* context, uint32_t* duration, bool* level) {
FuriHalIrdaTxGetDataState state = FuriHalIrdaTxGetDataStateError;
FuriHalIrdaTxGetDataState state = FuriHalIrdaTxGetDataStateLastDone;
IrdaEncoderHandler* handler = context;
IrdaStatus status = IrdaStatusError;
@@ -65,7 +64,9 @@ FuriHalIrdaTxGetDataState irda_get_data_callback (void* context, uint32_t* durat
}
if (status == IrdaStatusError) {
state = FuriHalIrdaTxGetDataStateError;
state = FuriHalIrdaTxGetDataStateLastDone;
*duration = 0;
*level = 0;
} else if (status == IrdaStatusOk) {
state = FuriHalIrdaTxGetDataStateOk;
} else if (status == IrdaStatusDone) {
@@ -74,8 +75,7 @@ FuriHalIrdaTxGetDataState irda_get_data_callback (void* context, uint32_t* durat
state = FuriHalIrdaTxGetDataStateLastDone;
}
} else {
furi_assert(0);
state = FuriHalIrdaTxGetDataStateError;
furi_check(0);
}
return state;
@@ -90,8 +90,11 @@ void irda_send(const IrdaMessage* message, int times) {
irda_reset_encoder(handler, message);
irda_tx_number_of_transmissions = times;
uint32_t frequency = irda_get_protocol_frequency(message->protocol);
float duty_cycle = irda_get_protocol_duty_cycle(message->protocol);
furi_hal_irda_async_tx_set_data_isr_callback(irda_get_data_callback, handler);
furi_hal_irda_async_tx_start(IRDA_COMMON_CARRIER_FREQUENCY, IRDA_COMMON_DUTY_CYCLE);
furi_hal_irda_async_tx_start(frequency, duty_cycle);
furi_hal_irda_async_tx_wait_termination();
irda_free_encoder(handler);

View File

@@ -44,8 +44,9 @@ struct IrdaWorkerSignal{
size_t timings_cnt;
union {
IrdaMessage message;
uint32_t timings[MAX_TIMINGS_AMOUNT];
} data;
/* +1 is for pause we add at the beginning */
uint32_t timings[MAX_TIMINGS_AMOUNT + 1];
};
};
struct IrdaWorker {
@@ -125,7 +126,7 @@ static void irda_worker_process_timeout(IrdaWorker* instance) {
static void irda_worker_process_timings(IrdaWorker* instance, uint32_t duration, bool level) {
const IrdaMessage* message_decoded = irda_decode(instance->irda_decoder, level, duration);
if (message_decoded) {
instance->signal.data.message = *message_decoded;
instance->signal.message = *message_decoded;
instance->signal.timings_cnt = 0;
instance->signal.decoded = true;
if (instance->rx.received_signal_callback)
@@ -137,7 +138,7 @@ static void irda_worker_process_timings(IrdaWorker* instance, uint32_t duration,
}
if (instance->signal.timings_cnt < MAX_TIMINGS_AMOUNT) {
instance->signal.data.timings[instance->signal.timings_cnt] = duration;
instance->signal.timings[instance->signal.timings_cnt] = duration;
++instance->signal.timings_cnt;
} else {
uint32_t flags_set = osEventFlagsSet(instance->events, IRDA_WORKER_OVERRUN);
@@ -211,7 +212,7 @@ IrdaWorker* irda_worker_alloc() {
furi_thread_set_stack_size(instance->thread, 2048);
furi_thread_set_context(instance->thread, instance);
size_t buffer_size = MAX(sizeof(IrdaWorkerTiming) * MAX_TIMINGS_AMOUNT, sizeof(LevelDuration) * MAX_TIMINGS_AMOUNT);
size_t buffer_size = MAX(sizeof(IrdaWorkerTiming) * (MAX_TIMINGS_AMOUNT + 1), sizeof(LevelDuration) * MAX_TIMINGS_AMOUNT);
instance->stream = xStreamBufferCreate(buffer_size, sizeof(IrdaWorkerTiming));
instance->irda_decoder = irda_alloc_decoder();
instance->irda_encoder = irda_alloc_encoder();
@@ -283,13 +284,13 @@ void irda_worker_get_raw_signal(const IrdaWorkerSignal* signal, const uint32_t**
furi_assert(timings);
furi_assert(timings_cnt);
*timings = signal->data.timings;
*timings = signal->timings;
*timings_cnt = signal->timings_cnt;
}
const IrdaMessage* irda_worker_get_decoded_signal(const IrdaWorkerSignal* signal) {
furi_assert(signal);
return &signal->data.message;
return &signal->message;
}
void irda_worker_rx_enable_blink_on_receiving(IrdaWorker* instance, bool enable) {
@@ -328,21 +329,24 @@ static FuriHalIrdaTxGetDataState irda_worker_furi_hal_data_isr_callback(void* co
furi_assert(level);
IrdaWorker* instance = context;
IrdaWorkerTiming timing = {.state = FuriHalIrdaTxGetDataStateError} ;
IrdaWorkerTiming timing;
FuriHalIrdaTxGetDataState state;
if (sizeof(IrdaWorkerTiming) == xStreamBufferReceiveFromISR(instance->stream, &timing, sizeof(IrdaWorkerTiming), 0)) {
*level = timing.level;
*duration = timing.duration;
furi_assert(timing.state != FuriHalIrdaTxGetDataStateError);
state = timing.state;
} else {
furi_assert(0);
timing.state = FuriHalIrdaTxGetDataStateError;
*level = 0;
*duration = 100;
state = FuriHalIrdaTxGetDataStateDone;
}
uint32_t flags_set = osEventFlagsSet(instance->events, IRDA_WORKER_TX_FILL_BUFFER);
furi_check(flags_set & IRDA_WORKER_TX_FILL_BUFFER);
return timing.state;
return state;
}
static bool irda_get_new_signal(IrdaWorker* instance) {
@@ -353,8 +357,8 @@ static bool irda_get_new_signal(IrdaWorker* instance) {
uint32_t new_tx_frequency = 0;
float new_tx_duty_cycle = 0;
if (instance->signal.decoded) {
new_tx_frequency = irda_get_protocol_frequency(instance->signal.data.message.protocol);
new_tx_duty_cycle = irda_get_protocol_duty_cycle(instance->signal.data.message.protocol);
new_tx_frequency = irda_get_protocol_frequency(instance->signal.message.protocol);
new_tx_duty_cycle = irda_get_protocol_duty_cycle(instance->signal.message.protocol);
} else {
furi_assert(instance->signal.timings_cnt > 1);
new_tx_frequency = IRDA_COMMON_CARRIER_FREQUENCY;
@@ -366,7 +370,7 @@ static bool irda_get_new_signal(IrdaWorker* instance) {
instance->tx.frequency = new_tx_frequency;
instance->tx.duty_cycle = new_tx_duty_cycle;
if (instance->signal.decoded) {
irda_reset_encoder(instance->irda_encoder, &instance->signal.data.message);
irda_reset_encoder(instance->irda_encoder, &instance->signal.message);
}
new_signal_obtained = true;
} else if (response == IrdaWorkerGetSignalResponseSame) {
@@ -390,8 +394,8 @@ static bool irda_worker_tx_fill_buffer(IrdaWorker* instance) {
if (instance->signal.decoded) {
status = irda_encode(instance->irda_encoder, &timing.duration, &timing.level);
} else {
timing.duration = instance->signal.data.timings[instance->tx.tx_raw_cnt];
/* raw always starts from Mark, but we fulfill it with space delay at start */
timing.duration = instance->signal.timings[instance->tx.tx_raw_cnt];
/* raw always starts from Mark, but we fill it with space delay at start */
timing.level = (instance->tx.tx_raw_cnt % 2);
++instance->tx.tx_raw_cnt;
if (instance->tx.tx_raw_cnt >= instance->signal.timings_cnt) {
@@ -532,16 +536,18 @@ void irda_worker_set_decoded_signal(IrdaWorker* instance, const IrdaMessage* mes
furi_assert(message);
instance->signal.decoded = true;
instance->signal.data.message = *message;
instance->signal.message = *message;
}
void irda_worker_set_raw_signal(IrdaWorker* instance, const uint32_t* timings, size_t timings_cnt) {
furi_assert(instance);
furi_assert(timings);
furi_assert(timings_cnt > 2);
furi_assert(timings_cnt > 0);
size_t max_copy_num = COUNT_OF(instance->signal.timings) - 1;
furi_check(timings_cnt <= max_copy_num);
instance->signal.data.timings[0] = IRDA_RAW_TX_TIMING_DELAY_US;
memcpy(&instance->signal.data.timings[1], timings, timings_cnt * sizeof(uint32_t));
instance->signal.timings[0] = IRDA_RAW_TX_TIMING_DELAY_US;
memcpy(&instance->signal.timings[1], timings, timings_cnt * sizeof(uint32_t));
instance->signal.decoded = false;
instance->signal.timings_cnt = timings_cnt + 1;
}