[FL-3949] Universal IR signal selection (#4085)

* feat: universal ir signal selection
* fix: f18, format specifiers
* update labels with suggestions from the ui team

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Anna Antonenko
2025-02-20 03:58:55 +04:00
committed by GitHub
parent 93b0277938
commit 0f240c4dbc
17 changed files with 376 additions and 108 deletions

View File

@@ -2,26 +2,61 @@
#include <stdlib.h>
#include <m-dict.h>
#include <m-array.h>
#include <flipper_format/flipper_format.h>
#include "infrared_signal.h"
ARRAY_DEF(SignalPositionArray, size_t, M_DEFAULT_OPLIST);
typedef struct {
uint32_t index;
uint32_t count;
size_t index;
SignalPositionArray_t signals;
} InfraredBruteForceRecord;
static inline void ir_bf_record_init(InfraredBruteForceRecord* record) {
record->index = 0;
SignalPositionArray_init(record->signals);
}
#define IR_BF_RECORD_INIT(r) (ir_bf_record_init(&(r)))
static inline void
ir_bf_record_init_set(InfraredBruteForceRecord* dest, const InfraredBruteForceRecord* src) {
dest->index = src->index;
SignalPositionArray_init_set(dest->signals, src->signals);
}
#define IR_BF_RECORD_INIT_SET(d, s) (ir_bf_record_init_set(&(d), &(s)))
static inline void
ir_bf_record_set(InfraredBruteForceRecord* dest, const InfraredBruteForceRecord* src) {
dest->index = src->index;
SignalPositionArray_set(dest->signals, src->signals);
}
#define IR_BF_RECORD_SET(d, s) (ir_bf_record_set(&(d), &(s)))
static inline void ir_bf_record_clear(InfraredBruteForceRecord* record) {
SignalPositionArray_clear(record->signals);
}
#define IR_BF_RECORD_CLEAR(r) (ir_bf_record_clear(&(r)))
#define IR_BF_RECORD_OPLIST \
(INIT(IR_BF_RECORD_INIT), \
INIT_SET(IR_BF_RECORD_INIT_SET), \
SET(IR_BF_RECORD_SET), \
CLEAR(IR_BF_RECORD_CLEAR))
DICT_DEF2(
InfraredBruteForceRecordDict,
FuriString*,
FURI_STRING_OPLIST,
InfraredBruteForceRecord,
M_POD_OPLIST);
IR_BF_RECORD_OPLIST);
struct InfraredBruteForce {
FlipperFormat* ff;
const char* db_filename;
FuriString* current_record_name;
InfraredBruteForceRecord current_record;
InfraredSignal* current_signal;
InfraredBruteForceRecordDict_t records;
bool is_started;
@@ -39,6 +74,7 @@ InfraredBruteForce* infrared_brute_force_alloc(void) {
}
void infrared_brute_force_free(InfraredBruteForce* brute_force) {
furi_check(brute_force);
furi_assert(!brute_force->is_started);
InfraredBruteForceRecordDict_clear(brute_force->records);
furi_string_free(brute_force->current_record_name);
@@ -46,11 +82,13 @@ void infrared_brute_force_free(InfraredBruteForce* brute_force) {
}
void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename) {
furi_check(brute_force);
furi_assert(!brute_force->is_started);
brute_force->db_filename = db_filename;
}
InfraredErrorCode infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
furi_check(brute_force);
furi_assert(!brute_force->is_started);
furi_assert(brute_force->db_filename);
InfraredErrorCode error = InfraredErrorCodeNone;
@@ -66,19 +104,19 @@ InfraredErrorCode infrared_brute_force_calculate_messages(InfraredBruteForce* br
break;
}
bool signals_valid = false;
size_t signal_start = flipper_format_tell(ff);
bool signal_valid = false;
while(infrared_signal_read_name(ff, signal_name) == InfraredErrorCodeNone) {
error = infrared_signal_read_body(signal, ff);
signals_valid = (!INFRARED_ERROR_PRESENT(error)) && infrared_signal_is_valid(signal);
if(!signals_valid) break;
signal_valid = (!INFRARED_ERROR_PRESENT(error)) && infrared_signal_is_valid(signal);
if(!signal_valid) break;
InfraredBruteForceRecord* record =
InfraredBruteForceRecordDict_get(brute_force->records, signal_name);
if(record) { //-V547
++(record->count);
}
furi_assert(record);
SignalPositionArray_push_back(record->signals, signal_start);
}
if(!signals_valid) break;
if(!signal_valid) break;
} while(false);
infrared_signal_free(signal);
@@ -93,6 +131,7 @@ bool infrared_brute_force_start(
InfraredBruteForce* brute_force,
uint32_t index,
uint32_t* record_count) {
furi_check(brute_force);
furi_assert(!brute_force->is_started);
bool success = false;
*record_count = 0;
@@ -103,9 +142,10 @@ bool infrared_brute_force_start(
InfraredBruteForceRecordDict_next(it)) {
const InfraredBruteForceRecordDict_itref_t* record = InfraredBruteForceRecordDict_cref(it);
if(record->value.index == index) {
*record_count = record->value.count;
*record_count = SignalPositionArray_size(record->value.signals);
if(*record_count) {
furi_string_set(brute_force->current_record_name, record->key);
brute_force->current_record = record->value;
}
break;
}
@@ -124,10 +164,12 @@ bool infrared_brute_force_start(
}
bool infrared_brute_force_is_started(const InfraredBruteForce* brute_force) {
furi_check(brute_force);
return brute_force->is_started;
}
void infrared_brute_force_stop(InfraredBruteForce* brute_force) {
furi_check(brute_force);
furi_assert(brute_force->is_started);
furi_string_reset(brute_force->current_record_name);
infrared_signal_free(brute_force->current_signal);
@@ -138,25 +180,32 @@ void infrared_brute_force_stop(InfraredBruteForce* brute_force) {
furi_record_close(RECORD_STORAGE);
}
bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) {
bool infrared_brute_force_send(InfraredBruteForce* brute_force, uint32_t signal_index) {
furi_check(brute_force);
furi_assert(brute_force->is_started);
const bool success = infrared_signal_search_by_name_and_read(
brute_force->current_signal,
brute_force->ff,
furi_string_get_cstr(brute_force->current_record_name)) ==
InfraredErrorCodeNone;
if(success) {
infrared_signal_transmit(brute_force->current_signal);
}
return success;
if(signal_index >= SignalPositionArray_size(brute_force->current_record.signals)) return false;
size_t signal_start =
*SignalPositionArray_cget(brute_force->current_record.signals, signal_index);
if(!flipper_format_seek(brute_force->ff, signal_start, FlipperFormatOffsetFromStart))
return false;
if(INFRARED_ERROR_PRESENT(
infrared_signal_read_body(brute_force->current_signal, brute_force->ff)))
return false;
infrared_signal_transmit(brute_force->current_signal);
return true;
}
void infrared_brute_force_add_record(
InfraredBruteForce* brute_force,
uint32_t index,
const char* name) {
InfraredBruteForceRecord value = {.index = index, .count = 0};
InfraredBruteForceRecord value;
ir_bf_record_init(&value);
value.index = index;
FuriString* key;
key = furi_string_alloc_set(name);
InfraredBruteForceRecordDict_set_at(brute_force->records, key, value);