mirror of
https://protopirate.net/ProtoPirate/ProtoPirate.git
synced 2026-03-29 11:00:40 +00:00
239 lines
7.5 KiB
C
239 lines
7.5 KiB
C
// protopirate_history.c
|
|
#include "protopirate_history.h"
|
|
#include <lib/subghz/receiver.h>
|
|
#include <flipper_format/flipper_format_i.h>
|
|
|
|
#define TAG "ProtoPirateHistory"
|
|
|
|
typedef struct {
|
|
FuriString* item_str;
|
|
FlipperFormat* flipper_format;
|
|
uint8_t type;
|
|
SubGhzRadioPreset* preset;
|
|
} ProtoPirateHistoryItem;
|
|
|
|
ARRAY_DEF(ProtoPirateHistoryItemArray, ProtoPirateHistoryItem, M_POD_OPLIST)
|
|
|
|
struct ProtoPirateHistory {
|
|
ProtoPirateHistoryItemArray_t data;
|
|
uint16_t last_index;
|
|
uint32_t last_update_timestamp;
|
|
uint8_t code_last_hash_data;
|
|
};
|
|
|
|
ProtoPirateHistory* protopirate_history_alloc(void) {
|
|
ProtoPirateHistory* instance = malloc(sizeof(ProtoPirateHistory));
|
|
ProtoPirateHistoryItemArray_init(instance->data);
|
|
instance->last_index = 0;
|
|
return instance;
|
|
}
|
|
|
|
void protopirate_history_free(ProtoPirateHistory* instance) {
|
|
furi_assert(instance);
|
|
for(size_t i = 0; i < ProtoPirateHistoryItemArray_size(instance->data); i++) {
|
|
ProtoPirateHistoryItem* item = ProtoPirateHistoryItemArray_get(instance->data, i);
|
|
furi_string_free(item->item_str);
|
|
flipper_format_free(item->flipper_format);
|
|
if(item->preset) {
|
|
if(item->preset->name) {
|
|
furi_string_free(item->preset->name);
|
|
}
|
|
free(item->preset);
|
|
}
|
|
}
|
|
ProtoPirateHistoryItemArray_clear(instance->data);
|
|
free(instance);
|
|
}
|
|
|
|
void protopirate_history_reset(ProtoPirateHistory* instance) {
|
|
furi_assert(instance);
|
|
for(size_t i = 0; i < ProtoPirateHistoryItemArray_size(instance->data); i++) {
|
|
ProtoPirateHistoryItem* item = ProtoPirateHistoryItemArray_get(instance->data, i);
|
|
furi_string_free(item->item_str);
|
|
flipper_format_free(item->flipper_format);
|
|
if(item->preset) {
|
|
if(item->preset->name) {
|
|
furi_string_free(item->preset->name);
|
|
}
|
|
free(item->preset);
|
|
}
|
|
}
|
|
ProtoPirateHistoryItemArray_reset(instance->data);
|
|
instance->last_index = 0;
|
|
}
|
|
|
|
uint16_t protopirate_history_get_item(ProtoPirateHistory* instance) {
|
|
furi_assert(instance);
|
|
return ProtoPirateHistoryItemArray_size(instance->data);
|
|
}
|
|
|
|
uint16_t protopirate_history_get_last_index(ProtoPirateHistory* instance) {
|
|
furi_assert(instance);
|
|
return instance->last_index;
|
|
}
|
|
|
|
// Helper function to free a single history item's resources
|
|
static void protopirate_history_item_free(ProtoPirateHistoryItem* item) {
|
|
if(item->item_str) {
|
|
furi_string_free(item->item_str);
|
|
item->item_str = NULL;
|
|
}
|
|
if(item->flipper_format) {
|
|
flipper_format_free(item->flipper_format);
|
|
item->flipper_format = NULL;
|
|
}
|
|
if(item->preset) {
|
|
if(item->preset->name) {
|
|
furi_string_free(item->preset->name);
|
|
}
|
|
free(item->preset);
|
|
item->preset = NULL;
|
|
}
|
|
}
|
|
|
|
bool protopirate_history_add_to_history(
|
|
ProtoPirateHistory* instance,
|
|
void* context,
|
|
SubGhzRadioPreset* preset) {
|
|
furi_assert(instance);
|
|
furi_assert(context);
|
|
|
|
SubGhzProtocolDecoderBase* decoder_base = context;
|
|
|
|
// Check for duplicate (same hash within 500ms)
|
|
if((instance->code_last_hash_data ==
|
|
subghz_protocol_decoder_base_get_hash_data(decoder_base)) &&
|
|
((furi_get_tick() - instance->last_update_timestamp) < 500)) {
|
|
instance->last_update_timestamp = furi_get_tick();
|
|
return false;
|
|
}
|
|
|
|
// If history is full, remove the oldest entry
|
|
if(ProtoPirateHistoryItemArray_size(instance->data) >= KIA_HISTORY_MAX) {
|
|
ProtoPirateHistoryItem* oldest = ProtoPirateHistoryItemArray_get(instance->data, 0);
|
|
if(oldest) {
|
|
protopirate_history_item_free(oldest);
|
|
}
|
|
ProtoPirateHistoryItemArray_pop_at(NULL, instance->data, 0);
|
|
FURI_LOG_D(TAG, "History full, removed oldest entry");
|
|
}
|
|
|
|
instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base);
|
|
instance->last_update_timestamp = furi_get_tick();
|
|
|
|
// Create a new history item
|
|
ProtoPirateHistoryItem* item = ProtoPirateHistoryItemArray_push_raw(instance->data);
|
|
item->item_str = furi_string_alloc();
|
|
item->flipper_format = flipper_format_string_alloc();
|
|
item->type = 0;
|
|
|
|
// Copy preset
|
|
item->preset = malloc(sizeof(SubGhzRadioPreset));
|
|
item->preset->frequency = preset->frequency;
|
|
item->preset->name = furi_string_alloc();
|
|
furi_string_set(item->preset->name, preset->name);
|
|
item->preset->data = preset->data;
|
|
item->preset->data_size = preset->data_size;
|
|
|
|
// Get string representation
|
|
FuriString* text = furi_string_alloc();
|
|
subghz_protocol_decoder_base_get_string(decoder_base, text);
|
|
furi_string_set(item->item_str, text);
|
|
|
|
// Serialize to flipper format
|
|
subghz_protocol_decoder_base_serialize(decoder_base, item->flipper_format, preset);
|
|
|
|
// Debug: Log what we're adding to history
|
|
flipper_format_rewind(item->flipper_format);
|
|
uint32_t debug_bit_count;
|
|
FuriString* debug_protocol = furi_string_alloc();
|
|
if(flipper_format_read_string(item->flipper_format, "Protocol", debug_protocol)) {
|
|
FURI_LOG_I(TAG, "History add - Protocol: %s", furi_string_get_cstr(debug_protocol));
|
|
}
|
|
flipper_format_rewind(item->flipper_format);
|
|
if(flipper_format_read_uint32(item->flipper_format, "Bit", &debug_bit_count, 1)) {
|
|
FURI_LOG_I(TAG, "History add - Bit count: %lu", debug_bit_count);
|
|
}
|
|
furi_string_free(debug_protocol);
|
|
|
|
furi_string_free(text);
|
|
|
|
instance->last_index++;
|
|
|
|
FURI_LOG_I(
|
|
TAG,
|
|
"Added item %u to history (size: %zu)",
|
|
instance->last_index,
|
|
ProtoPirateHistoryItemArray_size(instance->data));
|
|
|
|
return true;
|
|
}
|
|
|
|
void protopirate_history_get_text_item_menu(
|
|
ProtoPirateHistory* instance,
|
|
FuriString* output,
|
|
uint16_t idx) {
|
|
furi_assert(instance);
|
|
furi_assert(output);
|
|
|
|
if(idx >= ProtoPirateHistoryItemArray_size(instance->data)) {
|
|
furi_string_set(output, "---");
|
|
return;
|
|
}
|
|
|
|
ProtoPirateHistoryItem* item = ProtoPirateHistoryItemArray_get(instance->data, idx);
|
|
|
|
// Get just the first line for the menu
|
|
const char* str = furi_string_get_cstr(item->item_str);
|
|
const char* newline = strchr(str, '\r');
|
|
size_t len = 0;
|
|
if(newline) {
|
|
len = newline - str;
|
|
} else {
|
|
newline = strchr(str, '\n');
|
|
if(newline) {
|
|
len = newline - str;
|
|
} else {
|
|
len = furi_string_size(item->item_str);
|
|
}
|
|
}
|
|
|
|
// Add index prefix
|
|
uint16_t display_idx = idx + 1;
|
|
furi_string_printf(output, "%u. %.*s", display_idx, (int)len, str);
|
|
}
|
|
|
|
void protopirate_history_get_text_item(
|
|
ProtoPirateHistory* instance,
|
|
FuriString* output,
|
|
uint16_t idx) {
|
|
furi_assert(instance);
|
|
furi_assert(output);
|
|
|
|
if(idx >= ProtoPirateHistoryItemArray_size(instance->data)) {
|
|
furi_string_set(output, "---");
|
|
return;
|
|
}
|
|
|
|
ProtoPirateHistoryItem* item = ProtoPirateHistoryItemArray_get(instance->data, idx);
|
|
furi_string_set(output, item->item_str);
|
|
}
|
|
|
|
SubGhzProtocolDecoderBase*
|
|
protopirate_history_get_decoder_base(ProtoPirateHistory* instance, uint16_t idx) {
|
|
UNUSED(instance);
|
|
UNUSED(idx);
|
|
return NULL;
|
|
}
|
|
|
|
FlipperFormat* protopirate_history_get_raw_data(ProtoPirateHistory* instance, uint16_t idx) {
|
|
furi_assert(instance);
|
|
|
|
if(idx >= ProtoPirateHistoryItemArray_size(instance->data)) {
|
|
return NULL;
|
|
}
|
|
|
|
ProtoPirateHistoryItem* item = ProtoPirateHistoryItemArray_get(instance->data, idx);
|
|
return item->flipper_format;
|
|
}
|