Full dpad emulation on receiver scene not need to save the signal to use all the buttons

This commit is contained in:
d4rks1d33
2026-07-13 22:14:08 -03:00
parent f7b04f1382
commit f1422cb701
3 changed files with 44 additions and 26 deletions
@@ -15,6 +15,7 @@ typedef enum {
SubGhzCustomEventSceneReceiverInfoTxStart,
SubGhzCustomEventSceneReceiverInfoTxStop,
SubGhzCustomEventSceneReceiverInfoSave,
SubGhzCustomEventSceneReceiverInfoTxFullDpad,
SubGhzCustomEventSceneSaveName,
SubGhzCustomEventSceneSignalSettings,
SubGhzCustomEventSceneSaveSuccess,
@@ -1,6 +1,7 @@
#include "../subghz_i.h"
#include <lib/subghz/blocks/custom_btn.h>
#include <flipper_format/flipper_format_i.h>
#include "applications/main/subghz/helpers/subghz_txrx_i.h"
#include <lib/subghz/blocks/generic.h>
@@ -20,6 +21,9 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v
} else if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoSave);
} else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoTxFullDpad);
}
}
@@ -29,7 +33,6 @@ static bool subghz_scene_receiver_info_update_parser(void* context) {
if(subghz_txrx_load_decoder_by_name_protocol(
subghz->txrx,
subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) {
// we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal
subghz_protocol_decoder_base_deserialize(
subghz_txrx_get_decoder(subghz->txrx),
subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen));
@@ -37,7 +40,6 @@ static bool subghz_scene_receiver_info_update_parser(void* context) {
SubGhzRadioPreset* preset =
subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen);
//Edit TX power, if necessary.
subghz_txrx_set_tx_power(preset->data, preset->data_size, subghz->tx_power);
subghz_txrx_set_preset(
@@ -93,7 +95,7 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) {
subghz_scene_receiver_info_callback,
subghz);
}
// Removed static check
if(subghz_txrx_protocol_is_transmittable(subghz->txrx, false)) {
widget_add_button_element(
subghz->widget,
@@ -101,9 +103,14 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) {
"Send",
subghz_scene_receiver_info_callback,
subghz);
widget_add_button_element(
subghz->widget,
GuiButtonTypeLeft,
"Full",
subghz_scene_receiver_info_callback,
subghz);
}
} else {
// [NO_DOLPHIN] widget_add_icon_element(subghz->widget, 83, 22, &I_WarningDolphinFlip_45x42);
widget_add_string_element(
subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse.");
}
@@ -131,12 +138,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
if(!subghz_scene_receiver_info_update_parser(subghz)) {
return false;
}
//CC1101 Stop RX -> Start TX
subghz_txrx_hopper_pause(subghz->txrx);
// key concept: we start endless TX until user release OK button, and after this we send last
// protocols repeats - this guarantee that one press OK will
// be guarantee send the required minimum protocol data packets
// for all of this we use subghz_block_generic_global.endless_tx in protocols _yield function.
subghz->state_notifications = SubGhzNotificationStateTx;
subghz_block_generic_global.endless_tx = true;
if(!subghz_tx_start(
@@ -146,37 +148,51 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
subghz_txrx_hopper_unpause(subghz->txrx);
subghz->state_notifications = SubGhzNotificationStateRx;
subghz_block_generic_global.endless_tx = false;
return true;
}
return true;
} else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) {
//CC1101 Stop Tx -> next tick event Start RX
// user release OK
// we switch off endless_tx - that mean protocols yield finish endless transmission,
// send upload "repeat=xx" times, and after will be stoped by the tick event down in this code
subghz->state_notifications = SubGhzNotificationStateTxWait;
subghz_block_generic_global.endless_tx = false;
return true;
} else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) {
//CC1101 Stop RX -> Save
subghz->state_notifications = SubGhzNotificationStateIDLE;
subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
subghz_txrx_stop(subghz->txrx);
if(!subghz_scene_receiver_info_update_parser(subghz)) {
return false;
}
if(subghz_txrx_protocol_is_serializable(subghz->txrx)) {
subghz_file_name_clear(subghz);
subghz->save_datetime =
subghz_history_get_datetime(subghz->history, subghz->idx_menu_chosen);
subghz->save_datetime_set = true;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
}
return true;
} else if(event.event == SubGhzCustomEventSceneReceiverInfoTxFullDpad) {
if(!subghz_scene_receiver_info_update_parser(subghz)) {
return false;
}
FlipperFormat* fff_history =
subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen);
FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx);
Stream* src = flipper_format_get_raw_stream(fff_history);
Stream* dst = flipper_format_get_raw_stream(fff_data);
stream_seek(src, 0, StreamOffsetFromStart);
stream_clean(dst);
stream_copy_full(src, dst);
stream_seek(dst, 0, StreamOffsetFromStart);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter);
return true;
}
} else if(event.type == SceneManagerEventTypeTick) {
if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) {
subghz_txrx_hopper_update(subghz->txrx, subghz->last_settings->hopping_threshold);
@@ -193,18 +209,15 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
subghz->state_notifications = SubGhzNotificationStateRx;
break;
case SubGhzNotificationStateTxWait:
// we wait until hardware TX finished and after stop TX and start RX, else just blink led
if(!subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) {
notification_message(subghz->notifications, &sequence_blink_magenta_10);
} else {
subghz_txrx_stop(subghz->txrx);
// update screen
widget_reset(subghz->widget);
subghz_scene_receiver_info_draw_widget(subghz);
subghz->state_notifications = SubGhzNotificationStateIDLE;
if(!scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneDecodeRAW)) {
if(!scene_manager_has_previous_scene(
subghz->scene_manager, SubGhzSceneDecodeRAW)) {
subghz_txrx_rx_start(subghz->txrx);
subghz_txrx_hopper_unpause(subghz->txrx);
if(!subghz_history_get_text_space_left(subghz->history, NULL)) {
@@ -222,7 +235,6 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
void subghz_scene_receiver_info_on_exit(void* context) {
SubGhz* subghz = context;
widget_reset(subghz->widget);
subghz_txrx_reset_dynamic_and_custom_btns(subghz->txrx);
}
+6 -1
View File
@@ -3,6 +3,7 @@ import hashlib
import os
import struct
import subprocess
import shutil
import tempfile
import time
from collections import defaultdict
@@ -26,6 +27,10 @@ def replace_file_with_retry(source: str, target: str, attempts: int = 50) -> Non
if attempt == attempts - 1:
raise
time.sleep(0.1)
except OSError:
shutil.copy2(source, target)
os.remove(source)
return
@dataclass
@@ -147,7 +152,7 @@ class Main(App):
RelSection(section_name, section.name, unique_relocations)
)
with tempfile.TemporaryDirectory() as temp_dir:
with tempfile.TemporaryDirectory(dir=os.path.dirname(os.path.abspath(fap_path))) as temp_dir:
current_fap_path = fap_path
for section_index, section in enumerate(sections):