Merge pull request 'gull-parse-scenes' (#15) from gullradriel/ProtoPirate:gull-parse-scenes into main
All checks were successful
FAP Build / ufbt: Build for Momentum release (push) Successful in 39s
FAP Build / ufbt: Build for OFW dev channel (push) Successful in 40s
FAP Build / ufbt: Build for Momentum dev (push) Successful in 1m2s
FAP Build / ufbt: Build for OFW release channel (push) Successful in 37s
FAP Build / ufbt: Build for Unleashed dev (push) Successful in 46s
FAP Build / ufbt: Build for Unleashed release (push) Successful in 56s

Reviewed-on: http://protopirate.net/ProtoPirate/ProtoPirate/pulls/15
Reviewed-by: MMX <mmx@no-reply.protopirate.net>
This commit is contained in:
MMX
2026-02-11 05:21:12 -05:00
6 changed files with 132 additions and 44 deletions

View File

@@ -19,6 +19,7 @@ typedef struct {
SubGhzTransmitter* transmitter;
bool is_transmitting;
bool flag_stop_called;
Storage* storage;
} EmulateContext;
static EmulateContext* emulate_context = NULL;
@@ -77,6 +78,11 @@ static void emulate_context_free(void) {
emulate_context->protocol_name = NULL;
}
if(emulate_context->storage) {
furi_record_close(RECORD_STORAGE);
emulate_context->storage = NULL;
}
free(emulate_context);
emulate_context = NULL;
}
@@ -372,33 +378,46 @@ void protopirate_scene_emulate_on_enter(void* context) {
// Load the file
if(app->loaded_file_path) {
// Open storage once and keep track of it
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_file_alloc(storage);
if(!flipper_format_file_open_existing(ff, furi_string_get_cstr(app->loaded_file_path))) {
FURI_LOG_E(
TAG, "Failed to open file: %s", furi_string_get_cstr(app->loaded_file_path));
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
emulate_context->storage = furi_record_open(RECORD_STORAGE);
if(!emulate_context->storage) {
FURI_LOG_E(TAG, "Failed to open storage");
emulate_context_free();
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
}
emulate_context->flipper_format = ff;
emulate_context->flipper_format = flipper_format_file_alloc(emulate_context->storage);
if(!emulate_context->flipper_format) {
FURI_LOG_E(TAG, "Failed to allocate FlipperFormat");
emulate_context_free();
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
}
if(!flipper_format_file_open_existing(
emulate_context->flipper_format, furi_string_get_cstr(app->loaded_file_path))) {
FURI_LOG_E(
TAG, "Failed to open file: %s", furi_string_get_cstr(app->loaded_file_path));
emulate_context_free();
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
}
// Read frequency and preset from the saved file
uint32_t frequency = 433920000;
FuriString* preset_str = furi_string_alloc();
flipper_format_rewind(ff);
if(!flipper_format_read_uint32(ff, "Frequency", &frequency, 1)) {
flipper_format_rewind(emulate_context->flipper_format);
if(!flipper_format_read_uint32(
emulate_context->flipper_format, "Frequency", &frequency, 1)) {
FURI_LOG_W(TAG, "Failed to read frequency, using default 433.92MHz");
}
flipper_format_rewind(ff);
if(!flipper_format_read_string(ff, "Preset", preset_str)) {
flipper_format_rewind(emulate_context->flipper_format);
if(!flipper_format_read_string(emulate_context->flipper_format, "Preset", preset_str)) {
FURI_LOG_W(TAG, "Failed to read preset, using AM650");
furi_string_set(preset_str, "AM650");
}
@@ -415,29 +434,32 @@ void protopirate_scene_emulate_on_enter(void* context) {
furi_string_free(preset_str);
// Read protocol name
flipper_format_rewind(ff);
if(!flipper_format_read_string(ff, "Protocol", emulate_context->protocol_name)) {
flipper_format_rewind(emulate_context->flipper_format);
if(!flipper_format_read_string(
emulate_context->flipper_format, "Protocol", emulate_context->protocol_name)) {
FURI_LOG_E(TAG, "Failed to read protocol name");
furi_string_set(emulate_context->protocol_name, "Unknown");
}
// Read serial
flipper_format_rewind(ff);
if(!flipper_format_read_uint32(ff, "Serial", &emulate_context->serial, 1)) {
flipper_format_rewind(emulate_context->flipper_format);
if(!flipper_format_read_uint32(
emulate_context->flipper_format, "Serial", &emulate_context->serial, 1)) {
FURI_LOG_W(TAG, "Failed to read serial");
emulate_context->serial = 0;
}
// Read original button
flipper_format_rewind(ff);
flipper_format_rewind(emulate_context->flipper_format);
uint32_t btn_temp = 0;
if(flipper_format_read_uint32(ff, "Btn", &btn_temp, 1)) {
if(flipper_format_read_uint32(emulate_context->flipper_format, "Btn", &btn_temp, 1)) {
emulate_context->original_button = (uint8_t)btn_temp;
}
// Read counter
flipper_format_rewind(ff);
if(flipper_format_read_uint32(ff, "Cnt", &emulate_context->original_counter, 1)) {
flipper_format_rewind(emulate_context->flipper_format);
if(flipper_format_read_uint32(
emulate_context->flipper_format, "Cnt", &emulate_context->original_counter, 1)) {
emulate_context->current_counter = emulate_context->original_counter;
}
@@ -475,9 +497,9 @@ void protopirate_scene_emulate_on_enter(void* context) {
FURI_LOG_I(TAG, "Transmitter allocated successfully");
// Deserialize for transmission
flipper_format_rewind(ff);
SubGhzProtocolStatus status =
subghz_transmitter_deserialize(emulate_context->transmitter, ff);
flipper_format_rewind(emulate_context->flipper_format);
SubGhzProtocolStatus status = subghz_transmitter_deserialize(
emulate_context->transmitter, emulate_context->flipper_format);
if(status != SubGhzProtocolStatusOk) {
FURI_LOG_E(TAG, "Failed to deserialize transmitter, status: %d", status);
@@ -723,9 +745,6 @@ void protopirate_scene_emulate_on_exit(void* context) {
// Free emulate context and all its resources
emulate_context_free();
// Close storage record that was opened in on_enter
furi_record_close(RECORD_STORAGE);
// Delete temp file if we were using one
protopirate_storage_delete_temp();

View File

@@ -10,10 +10,27 @@
void protopirate_scene_receiver_view_callback(ProtoPirateCustomEvent event, void* context);
static void protopirate_scene_receiver_update_statusbar(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
FuriString* frequency_str = furi_string_alloc();
if(!frequency_str) {
FURI_LOG_E(TAG, "frequency_str allocation failed");
return;
}
FuriString* modulation_str = furi_string_alloc();
if(!modulation_str) {
FURI_LOG_E(TAG, "modulation_str allocation failed");
furi_string_free(frequency_str);
return;
}
FuriString* history_stat_str = furi_string_alloc();
if(!history_stat_str) {
FURI_LOG_E(TAG, "history_stat_str allocation failed");
furi_string_free(frequency_str);
furi_string_free(modulation_str);
return;
}
protopirate_get_frequency_modulation(app, frequency_str, modulation_str);
@@ -30,12 +47,6 @@ static void protopirate_scene_receiver_update_statusbar(void* context) {
"%u/%u",
protopirate_history_get_item(app->txrx->history),
PROTOPIRATE_DISPLAY_HISTORY_MAX);
} else {
furi_string_printf(
history_stat_str,
"%u/%u",
protopirate_history_get_item(app->txrx->history),
PROTOPIRATE_DISPLAY_HISTORY_MAX);
}
// Pass actual external radio status
@@ -56,12 +67,18 @@ static void protopirate_scene_receiver_callback(
SubGhzProtocolDecoderBase* decoder_base,
void* context) {
UNUSED(receiver);
furi_check(decoder_base);
furi_check(context);
ProtoPirateApp* app = context;
FURI_LOG_I(TAG, "=== SIGNAL DECODED ===");
FuriString* str_buff = furi_string_alloc();
if(!str_buff) {
FURI_LOG_E(TAG, "str_buff allocation failed");
return;
}
subghz_protocol_decoder_base_get_string(decoder_base, str_buff);
FURI_LOG_I(TAG, "%s", furi_string_get_cstr(str_buff));
@@ -75,6 +92,11 @@ static void protopirate_scene_receiver_callback(
protopirate_history_get_item(app->txrx->history));
FuriString* item_name = furi_string_alloc();
if(!item_name) {
FURI_LOG_E(TAG, "item_name allocation failed");
return;
}
protopirate_history_get_text_item_menu(
app->txrx->history, item_name, protopirate_history_get_item(app->txrx->history) - 1);
@@ -94,6 +116,12 @@ static void protopirate_scene_receiver_callback(
if(ff) {
FuriString* protocol = furi_string_alloc();
if(!protocol) {
FURI_LOG_E(TAG, "protocol allocation failed");
furi_string_free(str_buff);
return;
}
flipper_format_rewind(ff);
if(!flipper_format_read_string(ff, "Protocol", protocol)) {
furi_string_set_str(protocol, "Unknown");
@@ -104,6 +132,13 @@ static void protopirate_scene_receiver_callback(
furi_string_replace_all(protocol, " ", "_");
FuriString* saved_path = furi_string_alloc();
if(!protocol) {
FURI_LOG_E(TAG, "saved_path allocation failed");
furi_string_free(protocol);
furi_string_free(str_buff);
return;
}
if(protopirate_storage_save_capture(
ff, furi_string_get_cstr(protocol), saved_path)) {
FURI_LOG_I(TAG, "Auto-saved: %s", furi_string_get_cstr(saved_path));
@@ -133,6 +168,7 @@ static void protopirate_scene_receiver_callback(
}
void protopirate_scene_receiver_on_enter(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
FURI_LOG_I(TAG, "=== ENTERING RECEIVER SCENE ===");
@@ -141,7 +177,8 @@ void protopirate_scene_receiver_on_enter(void* context) {
#ifndef REMOVE_LOGS
bool is_external =
app->txrx->radio_device ? radio_device_loader_is_external(app->txrx->radio_device) : false;
const char* device_name = subghz_devices_get_name(app->txrx->radio_device);
const char* device_name =
app->txrx->radio_device ? subghz_devices_get_name(app->txrx->radio_device) : NULL;
FURI_LOG_I(TAG, "Radio device: %s", device_name ? device_name : "NULL");
FURI_LOG_I(TAG, "Is External: %s", is_external ? "YES" : "NO");
FURI_LOG_I(TAG, "Frequency: %lu Hz", app->txrx->preset->frequency);
@@ -221,6 +258,7 @@ void protopirate_scene_receiver_on_enter(void* context) {
}
bool protopirate_scene_receiver_on_event(void* context, SceneManagerEvent event) {
furi_check(context);
ProtoPirateApp* app = context;
bool consumed = false;
@@ -273,7 +311,8 @@ bool protopirate_scene_receiver_on_event(void* context, SceneManagerEvent event)
}
// Update RSSI from the correct radio device (only if initialized)
if(app->radio_initialized && app->txrx->txrx_state == ProtoPirateTxRxStateRx) {
if(app->radio_initialized && app->txrx->txrx_state == ProtoPirateTxRxStateRx &&
app->txrx->radio_device) {
float rssi = subghz_devices_get_rssi(app->txrx->radio_device);
protopirate_view_receiver_set_rssi(app->protopirate_receiver, rssi);
@@ -300,6 +339,7 @@ bool protopirate_scene_receiver_on_event(void* context, SceneManagerEvent event)
}
void protopirate_scene_receiver_on_exit(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
FURI_LOG_I(TAG, "=== EXITING RECEIVER SCENE ===");

View File

@@ -29,6 +29,9 @@ void protopirate_scene_receiver_info_on_enter(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
// Always reset per-enter to avoid stale static state
is_emu_off = false;
widget_reset(app->widget);
FuriString* text;

View File

@@ -28,12 +28,15 @@ static void protopirate_scene_saved_info_widget_callback(
notification_message(app->notifications, &sequence_semi_success);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventSavedInfoDelete);
break;
default:
break;
}
}
}
void protopirate_scene_saved_info_on_enter(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
Storage* storage = NULL;
FlipperFormat* ff = NULL;
@@ -104,7 +107,9 @@ void protopirate_scene_saved_info_on_enter(void* context) {
FURI_LOG_I(TAG, "File opened, reading...");
// Read fields
uint32_t temp_data;
uint32_t temp_data = 0;
// reset is_emu_off state before loading
is_emu_off = false;
flipper_format_rewind(ff);
if(flipper_format_read_string(ff, "Protocol", temp_str)) {
@@ -116,8 +121,6 @@ void protopirate_scene_saved_info_on_enter(void* context) {
is_emu_off = true;
} else if(furi_string_cmp_str(temp_str, "Kia V6") == 0) {
is_emu_off = true;
} else {
is_emu_off = false;
}
flipper_format_rewind(ff);

View File

@@ -378,8 +378,10 @@ static void close_file_handles(SubDecodeContext* ctx) {
flipper_format_free(ctx->ff);
ctx->ff = NULL;
}
furi_record_close(RECORD_STORAGE);
//ctx->storage = NULL;
if(ctx->storage) {
furi_record_close(RECORD_STORAGE);
ctx->storage = NULL;
}
}
// Receiver view callback for history navigation
@@ -425,6 +427,8 @@ void protopirate_scene_sub_decode_on_enter(void* context) {
app->txrx->history = protopirate_history_alloc();
if(!app->txrx->history) {
FURI_LOG_E(TAG, "Failed to allocate history!");
free(g_decode_ctx);
g_decode_ctx = NULL;
return;
}
}
@@ -714,7 +718,16 @@ bool protopirate_scene_sub_decode_on_event(void* context, SceneManagerEvent even
FURI_LOG_I(TAG, "StartingWorker: Reading file metadata");
Storage* storage = furi_record_open(RECORD_STORAGE);
if(!storage) {
FURI_LOG_E(TAG, "Failed to open storage");
break;
}
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
if(!fff_data_file) {
FURI_LOG_E(TAG, "Failed to allocate FlipperFormat");
break;
}
FuriString* temp_str = furi_string_alloc();
bool setup_ok = false;
@@ -803,9 +816,11 @@ bool protopirate_scene_sub_decode_on_event(void* context, SceneManagerEvent even
setup_ok = true;
} while(false);
flipper_format_free(fff_data_file);
if(fff_data_file) flipper_format_free(fff_data_file);
if(storage) furi_record_close(RECORD_STORAGE);
furi_string_free(temp_str);
furi_record_close(RECORD_STORAGE);
if(!setup_ok) {
furi_string_set(ctx->result, "Failed to read file metadata");

View File

@@ -607,11 +607,18 @@ static void timing_tuner_pair_callback(void* context, bool level, uint32_t durat
}
void protopirate_scene_timing_tuner_on_enter(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
FURI_LOG_I(TAG, "Entering Timing Tuner");
g_timing_ctx = malloc(sizeof(TimingTunerContext));
if(!g_timing_ctx) {
FURI_LOG_E(TAG, "Failed to allocate timing tuner context");
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
}
memset(g_timing_ctx, 0, sizeof(TimingTunerContext));
g_timing_ctx->is_receiving = false;
g_timing_ctx->has_match = false;
@@ -673,8 +680,9 @@ bool protopirate_scene_timing_tuner_on_event(void* context, SceneManagerEvent ev
}
} else if(event.type == SceneManagerEventTypeTick) {
if(g_timing_ctx && g_timing_ctx->is_receiving && !g_timing_ctx->has_match) {
g_timing_ctx->rssi = subghz_devices_get_rssi(app->txrx->radio_device);
if(app->txrx->radio_device) {
g_timing_ctx->rssi = subghz_devices_get_rssi(app->txrx->radio_device);
}
// Blink the light like the SubGHZ app
notification_message(app->notifications, &sequence_blink_cyan_10);
}