mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-29 02:08:10 -07:00
Merge branch 'dev' of https://github.com/DarkFlippers/unleashed-firmware into xfw-dev
This commit is contained in:
+4
-1
@@ -3,7 +3,10 @@ App(
|
||||
name="Sub-GHz Remote",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="subghz_remote_app",
|
||||
cdefines=["APP_SUBGHZREMOTE"],
|
||||
cdefines=[
|
||||
"APP_SUBGHZREMOTE",
|
||||
"SUBREM_LIGHT",
|
||||
],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
//SubmenuIndex
|
||||
SubmenuIndexSubRemOpenMapFile,
|
||||
SubmenuIndexSubRemRemoteView,
|
||||
SubmenuIndexSubRemAbout,
|
||||
|
||||
//SubRemCustomEvent
|
||||
SubRemCustomEventViewRemoteStartUP = 100,
|
||||
SubRemCustomEventViewRemoteStartDOWN,
|
||||
SubRemCustomEventViewRemoteStartLEFT,
|
||||
SubRemCustomEventViewRemoteStartRIGHT,
|
||||
SubRemCustomEventViewRemoteStartOK,
|
||||
SubRemCustomEventViewRemoteBack,
|
||||
SubRemCustomEventViewRemoteStop,
|
||||
SubRemCustomEventViewRemoteForcedStop,
|
||||
} SubRemCustomEvent;
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
// TODO: File version/type logic
|
||||
// #define SUBREM_APP_APP_FILE_VERSION 1
|
||||
// #define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file"
|
||||
#define SUBREM_APP_EXTENSION ".txt"
|
||||
|
||||
typedef enum {
|
||||
SubRemSubKeyNameUp = (0U),
|
||||
SubRemSubKeyNameDown,
|
||||
SubRemSubKeyNameLeft,
|
||||
SubRemSubKeyNameRight,
|
||||
SubRemSubKeyNameOk,
|
||||
SubRemSubKeyNameMaxCount,
|
||||
} SubRemSubKeyName;
|
||||
|
||||
typedef enum {
|
||||
SubRemViewSubmenu,
|
||||
SubRemViewWidget,
|
||||
SubRemViewPopup,
|
||||
SubRemViewTextInput,
|
||||
SubRemViewIDRemote,
|
||||
} SubRemViewID;
|
||||
|
||||
typedef enum {
|
||||
SubRemLoadMapStateBack = 0,
|
||||
SubRemLoadMapStateError,
|
||||
SubRemLoadMapStateOK,
|
||||
} SubRemLoadMapState;
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const subrem_scene_on_enter_handlers[])(void*) = {
|
||||
#include "subrem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const subrem_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "subrem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const subrem_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "subrem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers subrem_scene_handlers = {
|
||||
.on_enter_handlers = subrem_scene_on_enter_handlers,
|
||||
.on_event_handlers = subrem_scene_on_event_handlers,
|
||||
.on_exit_handlers = subrem_scene_on_exit_handlers,
|
||||
.scene_num = SubRemSceneNum,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) SubRemScene##id,
|
||||
typedef enum {
|
||||
#include "subrem_scene_config.h"
|
||||
SubRemSceneNum,
|
||||
} SubRemScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers subrem_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "subrem_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "subrem_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "subrem_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -0,0 +1,3 @@
|
||||
ADD_SCENE(subrem, start, Start)
|
||||
ADD_SCENE(subrem, openmapfile, OpenMapFile)
|
||||
ADD_SCENE(subrem, remote, Remote)
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
void subrem_scene_openmapfile_on_enter(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
SubRemLoadMapState load_state = subrem_load_from_file(app);
|
||||
|
||||
if(load_state == SubRemLoadMapStateError) {
|
||||
#ifdef SUBREM_LIGHT
|
||||
dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file");
|
||||
#else
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
|
||||
dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter);
|
||||
dialog_message_set_text(message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_message_set_buttons(message, "Back", NULL, NULL);
|
||||
dialog_message_show(app->dialogs, message);
|
||||
|
||||
dialog_message_free(message);
|
||||
#endif
|
||||
}
|
||||
if(load_state == SubRemLoadMapStateOK) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneRemote);
|
||||
} else {
|
||||
// TODO: Map Preset Reset
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SubRemSceneStart)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool subrem_scene_openmapfile_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_openmapfile_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
#include "../views/remote.h"
|
||||
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
|
||||
#define TAG "SubRemScenRemote"
|
||||
|
||||
void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void subrem_scene_remote_raw_callback_end_tx(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewRemoteForcedStop);
|
||||
}
|
||||
|
||||
static uint8_t subrem_scene_remote_event_to_index(SubRemCustomEvent event_id) {
|
||||
uint8_t ret = 0;
|
||||
|
||||
if(event_id == SubRemCustomEventViewRemoteStartUP) {
|
||||
ret = SubRemSubKeyNameUp;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartDOWN) {
|
||||
ret = SubRemSubKeyNameDown;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartLEFT) {
|
||||
ret = SubRemSubKeyNameLeft;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartRIGHT) {
|
||||
ret = SubRemSubKeyNameRight;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartOK) {
|
||||
ret = SubRemSubKeyNameOk;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool subrem_scene_remote_update_data_show(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
bool ret = false;
|
||||
|
||||
subrem_view_remote_add_data_to_show(
|
||||
app->subrem_remote_view,
|
||||
furi_string_get_cstr(app->subs_preset[0]->label),
|
||||
furi_string_get_cstr(app->subs_preset[1]->label),
|
||||
furi_string_get_cstr(app->subs_preset[2]->label),
|
||||
furi_string_get_cstr(app->subs_preset[3]->label),
|
||||
furi_string_get_cstr(app->subs_preset[4]->label));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subrem_scene_remote_on_enter(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
subrem_scene_remote_update_data_show(app);
|
||||
|
||||
subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote);
|
||||
}
|
||||
|
||||
bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubRemCustomEventViewRemoteBack) {
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SubRemSceneOpenMapFile)) {
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SubRemSceneStart)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if(
|
||||
event.event == SubRemCustomEventViewRemoteStartUP ||
|
||||
event.event == SubRemCustomEventViewRemoteStartDOWN ||
|
||||
event.event == SubRemCustomEventViewRemoteStartLEFT ||
|
||||
event.event == SubRemCustomEventViewRemoteStartRIGHT ||
|
||||
event.event == SubRemCustomEventViewRemoteStartOK) {
|
||||
// Start sending sub
|
||||
subrem_tx_stop_sub(app, true);
|
||||
app->chusen_sub = subrem_scene_remote_event_to_index(event.event);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateLoading);
|
||||
if(subrem_tx_start_sub(
|
||||
app,
|
||||
app->subs_preset[app->chusen_sub],
|
||||
subrem_scene_remote_raw_callback_end_tx)) {
|
||||
subrem_view_remote_set_presed_btn(app->subrem_remote_view, app->chusen_sub);
|
||||
subrem_view_remote_set_state(
|
||||
app->subrem_remote_view, SubRemViewRemoteStateSending);
|
||||
notification_message(app->notifications, &sequence_blink_start_magenta);
|
||||
} else {
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle);
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventViewRemoteForcedStop) {
|
||||
subrem_tx_stop_sub(app, true);
|
||||
subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventViewRemoteStop) {
|
||||
if(subrem_tx_stop_sub(app, false)) {
|
||||
subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// } else if(event.type == SceneManagerEventTypeTick) {
|
||||
// }
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_remote_on_exit(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
subrem_tx_stop_sub(app, true);
|
||||
|
||||
subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
#include "../helpers/subrem_custom_event.h"
|
||||
|
||||
void subrem_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void subrem_scene_start_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Open Map File",
|
||||
SubmenuIndexSubRemOpenMapFile,
|
||||
subrem_scene_start_submenu_callback,
|
||||
app);
|
||||
#if FURI_DEBUG
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Remote_Debug",
|
||||
SubmenuIndexSubRemRemoteView,
|
||||
subrem_scene_start_submenu_callback,
|
||||
app);
|
||||
#endif
|
||||
// submenu_add_item(
|
||||
// submenu,
|
||||
// "About",
|
||||
// SubmenuIndexSubGhzRemoteAbout,
|
||||
// subrem_scene_start_submenu_callback,
|
||||
// app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu);
|
||||
}
|
||||
|
||||
bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexSubRemOpenMapFile) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile);
|
||||
consumed = true;
|
||||
}
|
||||
// } else if(event.event == SubmenuIndexSubRemAbout) {
|
||||
// scene_manager_next_scene(app->scene_manager, SubRemSceneAbout);
|
||||
// consumed = true;
|
||||
// }
|
||||
#if FURI_DEBUG
|
||||
else if(event.event == SubmenuIndexSubRemRemoteView) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneRemote);
|
||||
consumed = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subrem_scene_start_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
+109
-1047
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,448 @@
|
||||
#include "subghz_remote_app_i.h"
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
|
||||
// #include <lib/subghz/protocols/keeloq.h>
|
||||
// #include <lib/subghz/protocols/star_line.h>
|
||||
|
||||
#include <lib/subghz/blocks/custom_btn.h>
|
||||
|
||||
#define TAG "SubGhzRemote"
|
||||
|
||||
static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = {
|
||||
[SubRemSubKeyNameUp] = {"UP", "ULABEL"},
|
||||
[SubRemSubKeyNameDown] = {"DOWN", "DLABEL"},
|
||||
[SubRemSubKeyNameLeft] = {"LEFT", "LLABEL"},
|
||||
[SubRemSubKeyNameRight] = {"RIGHT", "RLABEL"},
|
||||
[SubRemSubKeyNameOk] = {"OK", "OKLABEL"},
|
||||
};
|
||||
|
||||
static bool
|
||||
subrem_set_preset_data(SubGhzSetting* setting, FreqPreset* freq_preset, const char* preset) {
|
||||
const char* preset_name = "";
|
||||
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
|
||||
preset_name = "AM270";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
|
||||
preset_name = "AM650";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
||||
preset_name = "FM238";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
||||
preset_name = "FM476";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
|
||||
// preset_name = "CUSTOM";
|
||||
return false;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown preset");
|
||||
return false;
|
||||
}
|
||||
size_t preset_index = subghz_setting_get_inx_preset_by_name(setting, preset_name);
|
||||
freq_preset->data = subghz_setting_get_preset_data(setting, preset_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
SubRemSubFilePreset* subrem_sub_file_preset_alloc() {
|
||||
SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset));
|
||||
|
||||
sub_preset->fff_data = flipper_format_string_alloc();
|
||||
sub_preset->file_path = furi_string_alloc();
|
||||
sub_preset->protocaol_name = furi_string_alloc();
|
||||
sub_preset->label = furi_string_alloc_set_str("N/A");
|
||||
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
|
||||
return sub_preset;
|
||||
}
|
||||
|
||||
void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) {
|
||||
furi_assert(sub_preset);
|
||||
|
||||
furi_string_free(sub_preset->label);
|
||||
furi_string_free(sub_preset->protocaol_name);
|
||||
furi_string_free(sub_preset->file_path);
|
||||
flipper_format_free(sub_preset->fff_data);
|
||||
|
||||
free(sub_preset);
|
||||
}
|
||||
|
||||
static void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) {
|
||||
furi_assert(sub_preset);
|
||||
|
||||
furi_string_set_str(sub_preset->label, "N/A");
|
||||
furi_string_reset(sub_preset->protocaol_name);
|
||||
furi_string_reset(sub_preset->file_path);
|
||||
|
||||
Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data);
|
||||
stream_clean(fff_data_stream);
|
||||
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
}
|
||||
|
||||
void subrem_map_preset_reset(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
subrem_sub_file_preset_reset(app->subs_preset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) {
|
||||
furi_assert(app);
|
||||
bool ret = false;
|
||||
SubRemSubFilePreset* sub_preset;
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
sub_preset = app->subs_preset[i];
|
||||
if(!flipper_format_read_string(
|
||||
fff_data_file, map_file_labels[i][0], sub_preset->file_path)) {
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]);
|
||||
#endif
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
} else if(!flipper_format_rewind(fff_data_file)) {
|
||||
// Rewind error
|
||||
} else if(!flipper_format_read_string(
|
||||
fff_data_file, map_file_labels[i][1], sub_preset->label)) {
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]);
|
||||
#endif
|
||||
path_extract_filename(sub_preset->file_path, sub_preset->label, true);
|
||||
} else {
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"%-5s: %s %s",
|
||||
map_file_labels[i][0],
|
||||
furi_string_get_cstr(sub_preset->label),
|
||||
furi_string_get_cstr(sub_preset->file_path));
|
||||
ret = true;
|
||||
}
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) {
|
||||
furi_assert(flipper_format);
|
||||
furi_assert(dev_file_name);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format);
|
||||
|
||||
bool saved = false;
|
||||
FuriString* file_dir = furi_string_alloc();
|
||||
|
||||
path_extract_dirname(dev_file_name, file_dir);
|
||||
do {
|
||||
//removing additional fields
|
||||
flipper_format_delete_key(flipper_format, "Repeat");
|
||||
//flipper_format_delete_key(flipper_format, "Manufacture");
|
||||
|
||||
if(!storage_simply_remove(storage, dev_file_name)) {
|
||||
break;
|
||||
}
|
||||
//ToDo check Write
|
||||
stream_seek(flipper_format_stream, 0, StreamOffsetFromStart);
|
||||
stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS);
|
||||
|
||||
saved = true;
|
||||
} while(0);
|
||||
furi_string_free(file_dir);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return saved;
|
||||
}
|
||||
|
||||
bool subrem_tx_start_sub(
|
||||
SubGhzRemoteApp* app,
|
||||
SubRemSubFilePreset* sub_preset,
|
||||
SubGhzProtocolEncoderRAWCallbackEnd callback) {
|
||||
furi_assert(app);
|
||||
furi_assert(sub_preset);
|
||||
bool ret = false;
|
||||
|
||||
subrem_tx_stop_sub(app, true);
|
||||
|
||||
if(sub_preset->type == SubGhzProtocolTypeUnknown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label));
|
||||
|
||||
subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK);
|
||||
keeloq_reset_original_btn();
|
||||
subghz_custom_btns_reset();
|
||||
|
||||
do {
|
||||
flipper_format_rewind(sub_preset->fff_data); //
|
||||
|
||||
app->transmitter = subghz_transmitter_alloc_init(
|
||||
app->environment, furi_string_get_cstr(sub_preset->protocaol_name));
|
||||
|
||||
if(app->transmitter) {
|
||||
if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) !=
|
||||
SubGhzProtocolStatusOk) {
|
||||
FURI_LOG_E(TAG, "Deserialize error!");
|
||||
break;
|
||||
}
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_idle();
|
||||
furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data);
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
furi_hal_subghz_idle();
|
||||
|
||||
furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency);
|
||||
furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false);
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
if(!furi_hal_subghz_tx()) {
|
||||
FURI_LOG_E(TAG, "Sending not allowed");
|
||||
break;
|
||||
}
|
||||
|
||||
if(sub_preset->type == SubGhzProtocolTypeRAW) {
|
||||
subghz_protocol_raw_file_encoder_worker_set_callback_end(
|
||||
(SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(
|
||||
app->transmitter),
|
||||
callback,
|
||||
app);
|
||||
}
|
||||
|
||||
furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter);
|
||||
|
||||
ret = true;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
app->tx_running = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void subghz_tx_stop(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
//Stop TX
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
|
||||
subghz_transmitter_stop(app->transmitter);
|
||||
subghz_transmitter_free(app->transmitter);
|
||||
furi_hal_subghz_idle();
|
||||
}
|
||||
|
||||
bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) {
|
||||
furi_assert(app);
|
||||
SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub];
|
||||
|
||||
if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) {
|
||||
// SubRemSubKeyTypeRawKey)) {
|
||||
if(app->tx_running) {
|
||||
subghz_tx_stop(app);
|
||||
|
||||
if(sub_preset->type == SubGhzProtocolTypeDynamic) {
|
||||
subrem_save_protocol_to_file(
|
||||
sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path));
|
||||
|
||||
keeloq_reset_mfname();
|
||||
keeloq_reset_kl_type();
|
||||
keeloq_reset_original_btn();
|
||||
subghz_custom_btns_reset();
|
||||
star_line_reset_mfname();
|
||||
star_line_reset_kl_type();
|
||||
}
|
||||
|
||||
app->tx_running = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) {
|
||||
furi_assert(app);
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
uint32_t temp_data32;
|
||||
bool ret = false;
|
||||
bool sub_preset_loaded = false;
|
||||
SubRemSubFilePreset* sub_preset;
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
sub_preset = app->subs_preset[i];
|
||||
sub_preset_loaded = false;
|
||||
if(furi_string_empty(sub_preset->file_path)) {
|
||||
// FURI_LOG_I(TAG, "Empty file path");
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(
|
||||
fff_data_file, furi_string_get_cstr(sub_preset->file_path))) {
|
||||
FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path));
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect header");
|
||||
break;
|
||||
}
|
||||
|
||||
if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) ||
|
||||
(!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) &&
|
||||
temp_data32 == SUBGHZ_KEY_FILE_VERSION) {
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Type or version mismatch");
|
||||
break;
|
||||
}
|
||||
|
||||
//Load frequency
|
||||
if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
|
||||
FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency");
|
||||
sub_preset->freq_preset.frequency =
|
||||
subghz_setting_get_default_frequency(app->setting);
|
||||
} else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) {
|
||||
FURI_LOG_E(TAG, "This frequency can only be used for RX");
|
||||
break;
|
||||
} else {
|
||||
sub_preset->freq_preset.frequency = temp_data32;
|
||||
}
|
||||
|
||||
//Load preset
|
||||
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing Preset");
|
||||
break;
|
||||
}
|
||||
|
||||
if(!subrem_set_preset_data(
|
||||
app->setting, &sub_preset->freq_preset, furi_string_get_cstr(temp_str))) {
|
||||
FURI_LOG_E(TAG, "Cannot load preset.");
|
||||
break;
|
||||
}
|
||||
|
||||
//Load protocol
|
||||
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing Protocol");
|
||||
break;
|
||||
}
|
||||
|
||||
FlipperFormat* fff_data = sub_preset->fff_data;
|
||||
if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
|
||||
//if RAW
|
||||
subghz_protocol_raw_gen_fff_data(
|
||||
fff_data, furi_string_get_cstr(sub_preset->file_path));
|
||||
} else {
|
||||
stream_copy_full(
|
||||
flipper_format_get_raw_stream(fff_data_file),
|
||||
flipper_format_get_raw_stream(fff_data));
|
||||
}
|
||||
|
||||
const SubGhzProtocolRegistry* protocol_registry_items =
|
||||
subghz_environment_get_protocol_registry(app->environment);
|
||||
|
||||
const SubGhzProtocol* protocol = subghz_protocol_registry_get_by_name(
|
||||
protocol_registry_items, furi_string_get_cstr(temp_str));
|
||||
|
||||
if(!protocol) {
|
||||
FURI_LOG_E(TAG, "Protocol not found");
|
||||
break;
|
||||
} else if(protocol->flag & SubGhzProtocolFlag_Send) {
|
||||
if((protocol->type == SubGhzProtocolTypeStatic) ||
|
||||
(protocol->type == SubGhzProtocolTypeDynamic) ||
|
||||
// (protocol->type == SubGhzProtocolTypeBinRAW) || // TODO: BINRAW
|
||||
(protocol->type == SubGhzProtocolTypeRAW)) {
|
||||
sub_preset->type = protocol->type;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unsuported Protocol");
|
||||
break;
|
||||
}
|
||||
|
||||
furi_string_set(sub_preset->protocaol_name, temp_str);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Protocol does not support transmission");
|
||||
}
|
||||
|
||||
sub_preset_loaded = true;
|
||||
ret |= true;
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label));
|
||||
#endif
|
||||
} while(false);
|
||||
|
||||
// TODO:
|
||||
// Load file state logic
|
||||
// Label depending on the state
|
||||
|
||||
if(!sub_preset_loaded) {
|
||||
furi_string_set_str(sub_preset->label, "N/A");
|
||||
}
|
||||
|
||||
flipper_format_file_close(fff_data_file);
|
||||
}
|
||||
furi_string_free(temp_str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) {
|
||||
furi_assert(app);
|
||||
furi_assert(file_path);
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Load Map File Start");
|
||||
#endif
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
bool ret = false;
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Open Map File..");
|
||||
#endif
|
||||
subrem_map_preset_reset(app);
|
||||
|
||||
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||
FURI_LOG_E(TAG, "Could not open MAP file %s", file_path);
|
||||
} else {
|
||||
if(!subrem_map_preset_load(app, fff_data_file)) {
|
||||
FURI_LOG_E(TAG, "Could no Sub file path in MAP file");
|
||||
// ret = // error for popup
|
||||
} else if(
|
||||
(flipper_format_file_close(fff_data_file)) &&
|
||||
(subrem_map_preset_check(app, fff_data_file))) {
|
||||
FURI_LOG_I(TAG, "Load Map File Seccesful");
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Popup for error or return error type
|
||||
if(!ret) {
|
||||
FURI_LOG_E(TAG, "Broken Map File");
|
||||
}
|
||||
|
||||
flipper_format_file_close(fff_data_file);
|
||||
flipper_format_free(fff_data_file);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
FuriString* file_path = furi_string_alloc();
|
||||
SubRemLoadMapState ret = SubRemLoadMapStateBack;
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_sub1_10px);
|
||||
browser_options.base_path = SUBREM_APP_FOLDER;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
if(!dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options)) {
|
||||
} else if(subrem_map_file_load(app, furi_string_get_cstr(app->file_path))) {
|
||||
ret = SubRemLoadMapStateOK;
|
||||
} else {
|
||||
ret = SubRemLoadMapStateError;
|
||||
}
|
||||
|
||||
furi_string_free(file_path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/subrem_types.h"
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include "views/remote.h"
|
||||
|
||||
#include "scenes/subrem_scene.h"
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <storage/storage.h>
|
||||
#include <gui/modules/popup.h>
|
||||
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
|
||||
#include <lib/subghz/subghz_setting.h>
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/transmitter.h>
|
||||
|
||||
#define SUBREM_APP_FOLDER EXT_PATH("subghz/remote")
|
||||
#define SUBREM_MAX_LEN_NAME 64
|
||||
|
||||
typedef struct {
|
||||
uint32_t frequency;
|
||||
uint8_t* data;
|
||||
} FreqPreset;
|
||||
|
||||
// Sub File preset
|
||||
typedef struct {
|
||||
FlipperFormat* fff_data;
|
||||
FreqPreset freq_preset;
|
||||
FuriString* file_path;
|
||||
FuriString* protocaol_name;
|
||||
FuriString* label;
|
||||
SubGhzProtocolType type;
|
||||
} SubRemSubFilePreset;
|
||||
|
||||
SubRemSubFilePreset* subrem_sub_file_preset_alloc();
|
||||
|
||||
void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset);
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
DialogsApp* dialogs;
|
||||
Submenu* submenu;
|
||||
FuriString* file_path;
|
||||
char file_name_tmp[SUBREM_MAX_LEN_NAME];
|
||||
|
||||
SubRemViewRemote* subrem_remote_view;
|
||||
|
||||
SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount];
|
||||
|
||||
SubGhzSetting* setting;
|
||||
SubGhzEnvironment* environment;
|
||||
SubGhzReceiver* receiver;
|
||||
SubGhzTransmitter* transmitter;
|
||||
|
||||
bool tx_running;
|
||||
|
||||
uint8_t chusen_sub;
|
||||
|
||||
// TODO: LoadFileError
|
||||
} SubGhzRemoteApp;
|
||||
|
||||
SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app);
|
||||
|
||||
bool subrem_tx_start_sub(
|
||||
SubGhzRemoteApp* app,
|
||||
SubRemSubFilePreset* sub_preset,
|
||||
SubGhzProtocolEncoderRAWCallbackEnd callback);
|
||||
|
||||
bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced);
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
#include "remote.h"
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 16
|
||||
|
||||
struct SubRemViewRemote {
|
||||
View* view;
|
||||
SubRemViewRemoteCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
// TODO: model
|
||||
typedef struct {
|
||||
// FuriString* up_label;
|
||||
// FuriString* down_label;
|
||||
// FuriString* left_label;
|
||||
// FuriString* right_label;
|
||||
// FuriString* ok_label;
|
||||
|
||||
char* up_label;
|
||||
char* down_label;
|
||||
char* left_label;
|
||||
char* right_label;
|
||||
char* ok_label;
|
||||
|
||||
SubRemViewRemoteState state;
|
||||
|
||||
uint8_t pressed_btn;
|
||||
} SubRemViewRemoteModel;
|
||||
|
||||
void subrem_view_remote_set_callback(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteCallback callback,
|
||||
void* context) {
|
||||
furi_assert(subrem_view_remote);
|
||||
|
||||
subrem_view_remote->callback = callback;
|
||||
subrem_view_remote->context = context;
|
||||
}
|
||||
|
||||
void subrem_view_remote_add_data_to_show(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
const char* up_label,
|
||||
const char* down_label,
|
||||
const char* left_label,
|
||||
const char* right_label,
|
||||
const char* ok_label) {
|
||||
furi_assert(subrem_view_remote);
|
||||
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
strncpy(model->up_label, up_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
strncpy(model->down_label, down_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
strncpy(model->left_label, left_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
strncpy(model->right_label, right_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
strncpy(model->ok_label, ok_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
|
||||
// furi_string_set(model->up_label, up_label);
|
||||
// furi_string_set(model->down_label, down_label);
|
||||
// furi_string_set(model->left_label, left_label);
|
||||
// furi_string_set(model->right_label, right_label);
|
||||
// furi_string_set(model->ok_label, ok_label);
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn) {
|
||||
furi_assert(subrem_view_remote);
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{ model->pressed_btn = presed_btn; },
|
||||
true);
|
||||
}
|
||||
|
||||
void subrem_view_remote_set_state(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteState state) {
|
||||
furi_assert(subrem_view_remote);
|
||||
with_view_model(
|
||||
subrem_view_remote->view, SubRemViewRemoteModel * model, { model->state = state; }, true);
|
||||
}
|
||||
|
||||
void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
//Icons for Labels
|
||||
//canvas_draw_icon(canvas, 0, 0, &I_SubGHzRemote_LeftAlignedButtons_9x64);
|
||||
canvas_draw_icon(canvas, 1, 5, &I_ButtonUp_7x4);
|
||||
canvas_draw_icon(canvas, 1, 15, &I_ButtonDown_7x4);
|
||||
canvas_draw_icon(canvas, 2, 23, &I_ButtonLeft_4x7);
|
||||
canvas_draw_icon(canvas, 2, 33, &I_ButtonRight_4x7);
|
||||
canvas_draw_icon(canvas, 0, 42, &I_Ok_btn_9x9);
|
||||
canvas_draw_icon(canvas, 0, 53, &I_back_10px);
|
||||
|
||||
//Labels
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 10, 10, model->up_label);
|
||||
canvas_draw_str(canvas, 10, 20, model->down_label);
|
||||
canvas_draw_str(canvas, 10, 30, model->left_label);
|
||||
canvas_draw_str(canvas, 10, 40, model->right_label);
|
||||
canvas_draw_str(canvas, 10, 50, model->ok_label);
|
||||
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
|
||||
canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit.");
|
||||
|
||||
//Status text and indicator
|
||||
canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13);
|
||||
|
||||
if(model->state == SubRemViewRemoteStateIdle) {
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle");
|
||||
} else {
|
||||
switch(model->state) {
|
||||
case SubRemViewRemoteStateSending:
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Send");
|
||||
break;
|
||||
case SubRemViewRemoteStateLoading:
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Load");
|
||||
break;
|
||||
default:
|
||||
#if FURI_DEBUG
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Wrong_state");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
switch(model->pressed_btn) {
|
||||
case SubRemSubKeyNameUp:
|
||||
canvas_draw_icon(canvas, 116, 17, &I_Pin_arrow_up_7x9);
|
||||
break;
|
||||
case SubRemSubKeyNameDown:
|
||||
canvas_draw_icon_ex(canvas, 116, 17, &I_Pin_arrow_up_7x9, IconRotation180);
|
||||
break;
|
||||
case SubRemSubKeyNameLeft:
|
||||
canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270);
|
||||
break;
|
||||
case SubRemSubKeyNameRight:
|
||||
canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90);
|
||||
break;
|
||||
case SubRemSubKeyNameOk:
|
||||
canvas_draw_icon(canvas, 116, 18, &I_Pin_star_7x7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Repeat indicator
|
||||
//canvas_draw_str_aligned(canvas, 125, 40, AlignRight, AlignBottom, "Repeat:");
|
||||
//canvas_draw_icon(canvas, 115, 39, &I_SubGHzRemote_Repeat_12x14);
|
||||
//canvas_draw_str_aligned(canvas, 125, 62, AlignRight, AlignBottom, int_to_char(app->repeat));
|
||||
}
|
||||
|
||||
bool subrem_view_remote_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubRemViewRemote* subrem_view_remote = context;
|
||||
|
||||
if(event->key == InputKeyBack && event->type == InputTypeLong) {
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
strcpy(model->up_label, "N/A");
|
||||
strcpy(model->down_label, "N/A");
|
||||
strcpy(model->left_label, "N/A");
|
||||
strcpy(model->right_label, "N/A");
|
||||
strcpy(model->ok_label, "N/A");
|
||||
},
|
||||
false);
|
||||
subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{ model->pressed_btn = 0; },
|
||||
true);
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteForcedStop, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
return true;
|
||||
}
|
||||
// BACK button processing end
|
||||
|
||||
if(event->key == InputKeyUp && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyDown && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartDOWN, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyLeft && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartLEFT, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyRight && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartRIGHT, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartOK, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
subrem_view_remote->callback(SubRemCustomEventViewRemoteStop, subrem_view_remote->context);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void subrem_view_remote_enter(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
void subrem_view_remote_exit(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
SubRemViewRemote* subrem_view_remote_alloc() {
|
||||
SubRemViewRemote* subrem_view_remote = malloc(sizeof(SubRemViewRemote));
|
||||
|
||||
// View allocation and configuration
|
||||
subrem_view_remote->view = view_alloc();
|
||||
view_allocate_model(
|
||||
subrem_view_remote->view, ViewModelTypeLocking, sizeof(SubRemViewRemoteModel));
|
||||
view_set_context(subrem_view_remote->view, subrem_view_remote);
|
||||
view_set_draw_callback(subrem_view_remote->view, (ViewDrawCallback)subrem_view_remote_draw);
|
||||
view_set_input_callback(subrem_view_remote->view, subrem_view_remote_input);
|
||||
view_set_enter_callback(subrem_view_remote->view, subrem_view_remote_enter);
|
||||
view_set_exit_callback(subrem_view_remote->view, subrem_view_remote_exit);
|
||||
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
model->state = SubRemViewRemoteStateIdle;
|
||||
|
||||
model->up_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
model->down_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
model->left_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
model->right_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
model->ok_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
|
||||
strcpy(model->up_label, "N/A");
|
||||
strcpy(model->down_label, "N/A");
|
||||
strcpy(model->left_label, "N/A");
|
||||
strcpy(model->right_label, "N/A");
|
||||
strcpy(model->ok_label, "N/A");
|
||||
|
||||
// model->up_label = furi_string_alloc_set_str("N/A");
|
||||
// model->down_label = furi_string_alloc_set_str("N/A");
|
||||
// model->left_label = furi_string_alloc_set_str("N/A");
|
||||
// model->right_label = furi_string_alloc_set_str("N/A");
|
||||
// model->ok_label = furi_string_alloc_set_str("N/A");
|
||||
|
||||
model->pressed_btn = 0;
|
||||
},
|
||||
true);
|
||||
return subrem_view_remote;
|
||||
}
|
||||
|
||||
void subrem_view_remote_free(SubRemViewRemote* subghz_remote) {
|
||||
furi_assert(subghz_remote);
|
||||
|
||||
with_view_model(
|
||||
subghz_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
free(model->up_label);
|
||||
free(model->down_label);
|
||||
free(model->left_label);
|
||||
free(model->right_label);
|
||||
free(model->ok_label);
|
||||
|
||||
// furi_string_free(model->up_label);
|
||||
// furi_string_free(model->down_label);
|
||||
// furi_string_free(model->left_label);
|
||||
// furi_string_free(model->right_label);
|
||||
// furi_string_free(model->ok_label);
|
||||
},
|
||||
true);
|
||||
view_free(subghz_remote->view);
|
||||
free(subghz_remote);
|
||||
}
|
||||
|
||||
View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote) {
|
||||
furi_assert(subrem_view_remote);
|
||||
return subrem_view_remote->view;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/subrem_custom_event.h"
|
||||
|
||||
typedef enum {
|
||||
SubRemViewRemoteStateIdle,
|
||||
SubRemViewRemoteStateLoading,
|
||||
SubRemViewRemoteStateSending,
|
||||
} SubRemViewRemoteState;
|
||||
|
||||
typedef struct SubRemViewRemote SubRemViewRemote;
|
||||
|
||||
typedef void (*SubRemViewRemoteCallback)(SubRemCustomEvent event, void* context);
|
||||
|
||||
void subrem_view_remote_set_callback(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteCallback callback,
|
||||
void* context);
|
||||
|
||||
SubRemViewRemote* subrem_view_remote_alloc();
|
||||
|
||||
void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote);
|
||||
|
||||
View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote);
|
||||
|
||||
void subrem_view_remote_add_data_to_show(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
const char* up_label,
|
||||
const char* down_label,
|
||||
const char* left_label,
|
||||
const char* right_label,
|
||||
const char* ok_label);
|
||||
|
||||
void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn);
|
||||
void subrem_view_remote_set_state(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteState state);
|
||||
+5
-12
@@ -97,20 +97,13 @@ const WifiMarauderItem items[NUM_MENU_ITEMS] = {
|
||||
NO_ARGS,
|
||||
FOCUS_CONSOLE_END,
|
||||
SHOW_STOPSCAN_TIP},
|
||||
{"Sniff PMKID on channel",
|
||||
{""},
|
||||
1,
|
||||
{"sniffpmkid -c"},
|
||||
INPUT_ARGS,
|
||||
{"Sniff PMKID",
|
||||
{"ap", "channel"},
|
||||
2,
|
||||
{"sniffpmkid -d -l", "sniffpmkid -c"},
|
||||
TOGGLE_ARGS,
|
||||
FOCUS_CONSOLE_END,
|
||||
SHOW_STOPSCAN_TIP},
|
||||
{"Sniff pmkid on selected aps",
|
||||
{""},
|
||||
1,
|
||||
{"sniffpmkid -d -l"},
|
||||
NO_ARGS,
|
||||
FOCUS_CONSOLE_END,
|
||||
NO_TIP},
|
||||
{"Channel",
|
||||
{"get", "set"},
|
||||
2,
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
|
||||
#define NUM_MENU_ITEMS (19)
|
||||
#define NUM_MENU_ITEMS (18)
|
||||
|
||||
#define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096)
|
||||
#define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512)
|
||||
|
||||
@@ -187,11 +187,16 @@ int32_t lfrfid_app(char* args) {
|
||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
||||
} else {
|
||||
furi_string_set(app->file_path, args);
|
||||
lfrfid_load_key_data(app, app->file_path, true);
|
||||
view_dispatcher_attach_to_gui(
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
||||
if(lfrfid_load_key_data(app, app->file_path, true)) {
|
||||
view_dispatcher_attach_to_gui(
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
||||
} else {
|
||||
// TODO: exit properly
|
||||
lfrfid_free(app);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -296,6 +296,7 @@ int32_t nfc_app(char* p) {
|
||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
|
||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||
|
||||
@@ -204,7 +204,6 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
||||
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
|
||||
break;
|
||||
}
|
||||
// Set tag general data
|
||||
} else if(type == FuriHalNfcTypeF) {
|
||||
// Set NFC-F data
|
||||
furi_string_cat_printf(temp_str, "ISO 18092 (NFC-F)\n");
|
||||
@@ -260,7 +259,8 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
||||
for(size_t i = 0; i < sizeof(nfc_data->f_data.pmm); i++) {
|
||||
furi_string_cat_printf(temp_str, " %02X", nfc_data->f_data.pmm[i]);
|
||||
}
|
||||
} else { // FuriHalNfcTypeA
|
||||
} else {
|
||||
// Set tag general data
|
||||
char iso_type = FURI_BIT(nfc_data->a_data.sak, 5) ? '4' : '3';
|
||||
furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type);
|
||||
furi_string_cat_printf(temp_str, "UID:");
|
||||
|
||||
@@ -10,7 +10,10 @@ App(
|
||||
"cli",
|
||||
"dialogs",
|
||||
],
|
||||
provides=["subghz_start"],
|
||||
provides=[
|
||||
"subghz_start",
|
||||
"subghz_load_extended_settings",
|
||||
],
|
||||
icon="A_Sub1ghz_14",
|
||||
stack_size=3 * 1024,
|
||||
order=10,
|
||||
@@ -23,3 +26,11 @@ App(
|
||||
requires=["subghz"],
|
||||
order=40,
|
||||
)
|
||||
|
||||
App(
|
||||
appid="subghz_load_extended_settings",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="subghz_extended_freq",
|
||||
requires=["storage", "subghz"],
|
||||
order=650,
|
||||
)
|
||||
|
||||
@@ -36,6 +36,8 @@ typedef enum {
|
||||
SubmenuIndexCAME24bit868,
|
||||
SubmenuIndexCAMETwee,
|
||||
SubmenuIndexCAMESpace,
|
||||
SubmenuIndexCameAtomo433,
|
||||
SubmenuIndexCameAtomo868,
|
||||
SubmenuIndexPricenton433,
|
||||
SubmenuIndexPricenton315,
|
||||
SubmenuIndexBETT_433,
|
||||
|
||||
@@ -266,6 +266,34 @@ bool subghz_txrx_gen_alutech_at_4n_protocol(
|
||||
return res;
|
||||
}
|
||||
|
||||
bool subghz_txrx_gen_came_atomo_protocol(
|
||||
void* context,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint32_t serial,
|
||||
uint16_t cnt) {
|
||||
SubGhzTxRx* txrx = context;
|
||||
|
||||
bool res = false;
|
||||
|
||||
txrx->transmitter =
|
||||
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_CAME_ATOMO_NAME);
|
||||
subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0);
|
||||
|
||||
if(txrx->transmitter && subghz_protocol_came_atomo_create_data(
|
||||
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
||||
txrx->fff_data,
|
||||
serial,
|
||||
cnt,
|
||||
txrx->preset)) {
|
||||
res = true;
|
||||
}
|
||||
|
||||
subghz_transmitter_free(txrx->transmitter);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool subghz_txrx_gen_somfy_telis_protocol(
|
||||
void* context,
|
||||
const char* preset_name,
|
||||
|
||||
@@ -108,6 +108,13 @@ bool subghz_txrx_gen_somfy_telis_protocol(
|
||||
uint8_t btn,
|
||||
uint16_t cnt);
|
||||
|
||||
bool subghz_txrx_gen_came_atomo_protocol(
|
||||
void* context,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint32_t serial,
|
||||
uint16_t cnt);
|
||||
|
||||
/**
|
||||
* Generate data SecPlus v2 protocol
|
||||
*
|
||||
|
||||
@@ -25,11 +25,14 @@ const char* const debug_pin_text[DEBUG_P_COUNT] = {
|
||||
"17(1W)",
|
||||
};
|
||||
|
||||
#define DEBUG_COUNTER_COUNT 3
|
||||
#define DEBUG_COUNTER_COUNT 6
|
||||
const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = {
|
||||
"+1",
|
||||
"+2",
|
||||
"+3",
|
||||
"+4",
|
||||
"+5",
|
||||
"+10",
|
||||
};
|
||||
|
||||
static void subghz_scene_ext_module_changed(VariableItem* item) {
|
||||
@@ -71,6 +74,15 @@ static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) {
|
||||
case 2:
|
||||
furi_hal_subghz_set_rolling_counter_mult(3);
|
||||
break;
|
||||
case 3:
|
||||
furi_hal_subghz_set_rolling_counter_mult(4);
|
||||
break;
|
||||
case 4:
|
||||
furi_hal_subghz_set_rolling_counter_mult(5);
|
||||
break;
|
||||
case 5:
|
||||
furi_hal_subghz_set_rolling_counter_mult(10);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -140,24 +152,58 @@ void subghz_scene_radio_settings_on_enter(void* context) {
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, timestamp_names_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Counter incr.",
|
||||
DEBUG_COUNTER_COUNT,
|
||||
subghz_scene_receiver_config_set_debug_counter,
|
||||
subghz);
|
||||
switch(furi_hal_subghz_get_rolling_counter_mult()) {
|
||||
case 1:
|
||||
value_index = 0;
|
||||
break;
|
||||
case 2:
|
||||
value_index = 1;
|
||||
break;
|
||||
case 3:
|
||||
value_index = 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Counter incr.",
|
||||
DEBUG_COUNTER_COUNT,
|
||||
subghz_scene_receiver_config_set_debug_counter,
|
||||
subghz);
|
||||
switch(furi_hal_subghz_get_rolling_counter_mult()) {
|
||||
case 1:
|
||||
value_index = 0;
|
||||
break;
|
||||
case 2:
|
||||
value_index = 1;
|
||||
break;
|
||||
case 3:
|
||||
value_index = 2;
|
||||
break;
|
||||
case 4:
|
||||
value_index = 3;
|
||||
break;
|
||||
case 5:
|
||||
value_index = 4;
|
||||
break;
|
||||
case 10:
|
||||
value_index = 5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Counter incr.",
|
||||
3,
|
||||
subghz_scene_receiver_config_set_debug_counter,
|
||||
subghz);
|
||||
switch(furi_hal_subghz_get_rolling_counter_mult()) {
|
||||
case 1:
|
||||
value_index = 0;
|
||||
break;
|
||||
case 2:
|
||||
value_index = 1;
|
||||
break;
|
||||
case 3:
|
||||
value_index = 2;
|
||||
break;
|
||||
default:
|
||||
// Reset to default value
|
||||
value_index = 0;
|
||||
furi_hal_subghz_set_rolling_counter_mult(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, debug_counter_text[value_index]);
|
||||
|
||||
@@ -227,12 +227,20 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
break;
|
||||
case SubGhzCustomEventViewReceiverDeleteItem:
|
||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||
subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||
|
||||
subghz_view_receiver_disable_draw_callback(subghz->subghz_receiver);
|
||||
|
||||
subghz_history_delete_item(subghz->history, subghz->idx_menu_chosen);
|
||||
subghz_view_receiver_delete_element_callback(subghz->subghz_receiver);
|
||||
|
||||
subghz_view_receiver_enable_draw_callback(subghz->subghz_receiver);
|
||||
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
if(subghz_history_get_last_index(subghz->history) == 0) {
|
||||
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case SubGhzCustomEventViewReceiverConfig:
|
||||
|
||||
@@ -199,6 +199,18 @@ void subghz_scene_set_type_on_enter(void* context) {
|
||||
SubmenuIndexCAMETwee,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"CAME Atomo 433MHz",
|
||||
SubmenuIndexCameAtomo433,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"CAME Atomo 868MHz",
|
||||
SubmenuIndexCameAtomo868,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"KL: CAME Space 433MHz",
|
||||
@@ -534,6 +546,14 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
break;
|
||||
case SubmenuIndexCameAtomo433:
|
||||
generated_protocol = subghz_txrx_gen_came_atomo_protocol(
|
||||
subghz->txrx, "AM650", 433920000, (key & 0x0FFFFFFF) | 0x10000000, 0x0003);
|
||||
break;
|
||||
case SubmenuIndexCameAtomo868:
|
||||
generated_protocol = subghz_txrx_gen_came_atomo_protocol(
|
||||
subghz->txrx, "AM650", 868350000, (key & 0x0FFFFFFF) | 0x10000000, 0x0003);
|
||||
break;
|
||||
case SubmenuIndexBFTMitto:
|
||||
generated_protocol = subghz_txrx_gen_keeloq_bft_protocol(
|
||||
subghz->txrx,
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_subghz_i.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
void subghz_extended_freq() {
|
||||
bool is_extended_i = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
|
||||
if(flipper_format_file_open_existing(file, "/ext/subghz/assets/extend_range.txt")) {
|
||||
flipper_format_read_bool(file, "use_ext_range_at_own_risk", &is_extended_i, 1);
|
||||
}
|
||||
|
||||
furi_hal_subghz_set_extended_frequency(is_extended_i);
|
||||
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
@@ -73,6 +73,7 @@ typedef struct {
|
||||
SubGhzViewReceiverMode mode;
|
||||
uint8_t u_rssi;
|
||||
size_t scroll_counter;
|
||||
bool nodraw;
|
||||
} SubGhzViewReceiverModel;
|
||||
|
||||
void subghz_view_receiver_set_mode(
|
||||
@@ -243,40 +244,48 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
|
||||
bool scrollbar = model->history_item > 4;
|
||||
FuriString* str_buff = furi_string_alloc();
|
||||
|
||||
SubGhzReceiverMenuItem* item_menu;
|
||||
if(!model->nodraw) {
|
||||
SubGhzReceiverMenuItem* item_menu;
|
||||
|
||||
for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
|
||||
size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0);
|
||||
item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx);
|
||||
furi_string_set(str_buff, item_menu->item_str);
|
||||
size_t scroll_counter = model->scroll_counter;
|
||||
if(model->idx == idx) {
|
||||
subghz_view_receiver_draw_frame(canvas, i, scrollbar);
|
||||
if(scroll_counter < SCROLL_DELAY) {
|
||||
// Show time of signal one moment
|
||||
furi_string_set(str_buff, item_menu->time);
|
||||
scroll_counter = 0;
|
||||
} else {
|
||||
scroll_counter -= SCROLL_DELAY;
|
||||
for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
|
||||
size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0);
|
||||
item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx);
|
||||
if(item_menu == NULL) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
scroll_counter = 0;
|
||||
if(item_menu->type == 0) {
|
||||
break;
|
||||
}
|
||||
furi_string_set(str_buff, item_menu->item_str);
|
||||
size_t scroll_counter = model->scroll_counter;
|
||||
if(model->idx == idx) {
|
||||
subghz_view_receiver_draw_frame(canvas, i, scrollbar);
|
||||
if(scroll_counter < SCROLL_DELAY) {
|
||||
// Show time of signal one moment
|
||||
furi_string_set(str_buff, item_menu->time);
|
||||
scroll_counter = 0;
|
||||
} else {
|
||||
scroll_counter -= SCROLL_DELAY;
|
||||
}
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
scroll_counter = 0;
|
||||
}
|
||||
canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]);
|
||||
elements_scrollable_text_line(
|
||||
canvas,
|
||||
15,
|
||||
9 + i * FRAME_HEIGHT,
|
||||
(scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX),
|
||||
str_buff,
|
||||
scroll_counter,
|
||||
(model->idx != idx),
|
||||
false);
|
||||
furi_string_reset(str_buff);
|
||||
}
|
||||
if(scrollbar) {
|
||||
elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
|
||||
}
|
||||
canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]);
|
||||
elements_scrollable_text_line(
|
||||
canvas,
|
||||
15,
|
||||
9 + i * FRAME_HEIGHT,
|
||||
(scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX),
|
||||
str_buff,
|
||||
scroll_counter,
|
||||
(model->idx != idx),
|
||||
false);
|
||||
furi_string_reset(str_buff);
|
||||
}
|
||||
if(scrollbar) {
|
||||
elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
|
||||
}
|
||||
furi_string_free(str_buff);
|
||||
|
||||
@@ -469,29 +478,12 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
|
||||
SubGhzViewReceiverModel * model,
|
||||
{
|
||||
if(model->history_item != 0) {
|
||||
SubGhzReceiverMenuItemArray_it_t it;
|
||||
// SubGhzReceiverMenuItem* target_item =
|
||||
// SubGhzReceiverMenuItemArray_get(model->history->data, model->idx);
|
||||
SubGhzReceiverMenuItemArray_it_last(it, model->history->data);
|
||||
while(!SubGhzReceiverMenuItemArray_end_p(it)) {
|
||||
SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it);
|
||||
|
||||
if(it->index == (size_t)(model->idx)) {
|
||||
furi_string_free(item->item_str);
|
||||
furi_string_free(item->time);
|
||||
item->type = 0;
|
||||
SubGhzReceiverMenuItemArray_remove(model->history->data, it);
|
||||
}
|
||||
|
||||
SubGhzReceiverMenuItemArray_previous(it);
|
||||
}
|
||||
|
||||
// Callback
|
||||
subghz_receiver->callback(
|
||||
SubGhzCustomEventViewReceiverDeleteItem, subghz_receiver->context);
|
||||
}
|
||||
},
|
||||
true);
|
||||
false);
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
subghz_receiver->view,
|
||||
@@ -542,6 +534,7 @@ void subghz_view_receiver_exit(void* context) {
|
||||
model->idx = 0;
|
||||
model->list_offset = 0;
|
||||
model->history_item = 0;
|
||||
model->nodraw = false;
|
||||
},
|
||||
false);
|
||||
furi_timer_stop(subghz_receiver->timer);
|
||||
@@ -576,6 +569,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
|
||||
model->history_stat_str = furi_string_alloc();
|
||||
model->progress_str = furi_string_alloc();
|
||||
model->bar_show = SubGhzViewReceiverBarShowDefault;
|
||||
model->nodraw = false;
|
||||
model->history = malloc(sizeof(SubGhzReceiverHistory));
|
||||
SubGhzReceiverMenuItemArray_init(model->history->data);
|
||||
},
|
||||
@@ -633,6 +627,23 @@ void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_rec
|
||||
subghz_receiver->view,
|
||||
SubGhzViewReceiverModel * model,
|
||||
{
|
||||
SubGhzReceiverMenuItemArray_it_t it;
|
||||
// SubGhzReceiverMenuItem* target_item =
|
||||
// SubGhzReceiverMenuItemArray_get(model->history->data, model->idx);
|
||||
SubGhzReceiverMenuItemArray_it_last(it, model->history->data);
|
||||
while(!SubGhzReceiverMenuItemArray_end_p(it)) {
|
||||
SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it);
|
||||
|
||||
if(it->index == (size_t)(model->idx)) {
|
||||
furi_string_free(item->item_str);
|
||||
furi_string_free(item->time);
|
||||
item->type = 0;
|
||||
SubGhzReceiverMenuItemArray_remove(model->history->data, it);
|
||||
}
|
||||
|
||||
SubGhzReceiverMenuItemArray_previous(it);
|
||||
}
|
||||
|
||||
if(model->history_item == 5) {
|
||||
if(model->idx >= 2) {
|
||||
model->idx = model->history_item - 1;
|
||||
@@ -645,7 +656,20 @@ void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_rec
|
||||
}
|
||||
},
|
||||
true);
|
||||
furi_delay_ms(200);
|
||||
}
|
||||
|
||||
void subghz_view_receiver_enable_draw_callback(SubGhzViewReceiver* subghz_receiver) {
|
||||
furi_assert(subghz_receiver);
|
||||
|
||||
with_view_model(
|
||||
subghz_receiver->view, SubGhzViewReceiverModel * model, { model->nodraw = false; }, true);
|
||||
}
|
||||
|
||||
void subghz_view_receiver_disable_draw_callback(SubGhzViewReceiver* subghz_receiver) {
|
||||
furi_assert(subghz_receiver);
|
||||
|
||||
with_view_model(
|
||||
subghz_receiver->view, SubGhzViewReceiverModel * model, { model->nodraw = true; }, true);
|
||||
}
|
||||
|
||||
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) {
|
||||
|
||||
@@ -49,4 +49,8 @@ void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint
|
||||
|
||||
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver);
|
||||
|
||||
void subghz_view_receiver_enable_draw_callback(SubGhzViewReceiver* subghz_receiver);
|
||||
|
||||
void subghz_view_receiver_disable_draw_callback(SubGhzViewReceiver* subghz_receiver);
|
||||
|
||||
void subghz_view_receiver_exit(void* context);
|
||||
|
||||
@@ -64,7 +64,19 @@ bool xtreme_app_apply(XtremeApp* app) {
|
||||
}
|
||||
|
||||
if(app->save_subghz) {
|
||||
furi_hal_subghz_set_is_extended(app->subghz_extend);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
do {
|
||||
if(!flipper_format_file_open_always(file, "/ext/subghz/assets/extend_range.txt"))
|
||||
break;
|
||||
if(!flipper_format_write_header_cstr(file, "Flipper SubGhz Setting File", 1)) break;
|
||||
if(!flipper_format_write_comment_cstr(
|
||||
file, "Whether to allow extended ranges that can break your flipper"))
|
||||
break;
|
||||
if(!flipper_format_write_bool(
|
||||
file, "use_ext_range_at_own_risk", &app->subghz_extend, 1))
|
||||
break;
|
||||
} while(0);
|
||||
flipper_format_free(file);
|
||||
}
|
||||
|
||||
if(app->save_name) {
|
||||
@@ -249,11 +261,13 @@ XtremeApp* xtreme_app_alloc() {
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
|
||||
if(flipper_format_file_open_existing(file, "/ext/subghz/assets/extend_range.txt")) {
|
||||
flipper_format_read_bool(file, "use_ext_range_at_own_risk", &app->subghz_extend, 1);
|
||||
}
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
app->subghz_extend = furi_hal_subghz_get_is_extended();
|
||||
|
||||
strlcpy(app->device_name, furi_hal_version_get_name_ptr(), FURI_HAL_VERSION_ARRAY_NAME_LENGTH);
|
||||
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
|
||||
Reference in New Issue
Block a user