Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subghz Remote configurator #487

Merged
merged 27 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
App(
appid="subrem_configurator",
name="Remote Maker",
apptype=FlipperAppType.EXTERNAL,
entry_point="subghz_remote_config_app",
requires=[
"gui",
"dialogs",
],
stack_size=2 * 1024,
order=50,
fap_description="File Editor for the SubGhz Remote app",
fap_category="Sub-Ghz",
fap_icon_assets="icons",
fap_icon="icons/subrem_10px.png",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

typedef enum {
SubRemEditMenuStateUP = 0,
SubRemEditMenuStateDOWN,
SubRemEditMenuStateLEFT,
SubRemEditMenuStateRIGHT,
SubRemEditMenuStateOK,
} SubRemEditMenuState;

typedef enum {
// SubmenuIndex
SubmenuIndexSubRemEditMapFile = 0,
SubmenuIndexSubRemNewMapFile,
SubmenuIndexSubRemRemoteView,
SubmenuIndexSubRemAbout,

// EditSubmenuIndex
EditSubmenuIndexEditLabel,
EditSubmenuIndexEditFile,

// SubRemCustomEvent
SubRemCustomEventViewRemoteStartUP = 100,
SubRemCustomEventViewRemoteStartDOWN,
SubRemCustomEventViewRemoteStartLEFT,
SubRemCustomEventViewRemoteStartRIGHT,
SubRemCustomEventViewRemoteStartOK,
SubRemCustomEventViewRemoteBack,
SubRemCustomEventViewRemoteStop,
SubRemCustomEventViewRemoteForcedStop,

SubRemCustomEventViewEditMenuBack,
SubRemCustomEventViewEditMenuUP,
SubRemCustomEventViewEditMenuDOWN,
SubRemCustomEventViewEditMenuEdit,
SubRemCustomEventViewEditMenuSave,

SubRemCustomEventSceneEditsubmenu,
SubRemCustomEventSceneEditLabelInputDone,
SubRemCustomEventSceneEditLabelWidgetAcces,
SubRemCustomEventSceneEditLabelWidgetBack,

SubRemCustomEventSceneEditOpenSubErrorPopup,

SubRemCustomEventSceneEditPreviewSaved,

SubRemCustomEventSceneNewName,

// // SceneStates
// SubRemSceneOpenMapFileStateOpen,
// SubRemSceneOpenMapFileStateEdit,
} SubRemCustomEvent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#include "subrem_presets.h"

#define TAG "SubRemPresets"

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();

sub_preset->freq_preset.name = furi_string_alloc();

sub_preset->type = SubGhzProtocolTypeUnknown;
sub_preset->load_state = SubRemLoadSubStateNotSet;

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);

furi_string_free(sub_preset->freq_preset.name);

free(sub_preset);
}

void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) {
furi_assert(sub_preset);

furi_string_set_str(sub_preset->label, "");
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;
sub_preset->load_state = SubRemLoadSubStateNotSet;
}

SubRemLoadSubState subrem_sub_preset_load(
SubRemSubFilePreset* sub_preset,
SubGhzTxRx* txrx,
FlipperFormat* fff_data_file) {
furi_assert(sub_preset);
furi_assert(txrx);
furi_assert(fff_data_file);

Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data);

SubRemLoadSubState ret;
FuriString* temp_str = furi_string_alloc();
uint32_t temp_data32;
uint32_t repeat = 200;

ret = SubRemLoadSubStateError;

do {
stream_clean(fff_data_stream);
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;
}

SubGhzSetting* setting = subghz_txrx_get_setting(txrx);

//Load frequency or using default from settings
ret = SubRemLoadSubStateErrorFreq;
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(setting);
} else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) {
FURI_LOG_E(TAG, "This frequency can only be used for RX");
break;
}
sub_preset->freq_preset.frequency = temp_data32;

//Load preset
ret = SubRemLoadSubStateErrorMod;
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
FURI_LOG_E(TAG, "Missing Preset");
break;
}

furi_string_set_str(
temp_str, subghz_txrx_get_preset_name(txrx, furi_string_get_cstr(temp_str)));
if(!strcmp(furi_string_get_cstr(temp_str), "")) {
break;
}

if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) {
FURI_LOG_E(TAG, "CUSTOM preset is not supported");
break;
// TODO Custom preset loading logic if need
// sub_preset->freq_preset.preset_index =
// subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str));
}

furi_string_set(sub_preset->freq_preset.name, temp_str);

// Load protocol
ret = SubRemLoadSubStateErrorProtocol;
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));
}

if(subghz_txrx_load_decoder_by_name_protocol(txrx, furi_string_get_cstr(temp_str))) {
SubGhzProtocolStatus status =
subghz_protocol_decoder_base_deserialize(subghz_txrx_get_decoder(txrx), fff_data);
if(status != SubGhzProtocolStatusOk) {
break;
}
} else {
FURI_LOG_E(TAG, "Protocol not found");
break;
}

const SubGhzProtocol* protocol = subghz_txrx_get_decoder(txrx)->protocol;

if(protocol->flag & SubGhzProtocolFlag_Send) {
if((protocol->type == SubGhzProtocolTypeStatic) ||
(protocol->type == SubGhzProtocolTypeDynamic) ||
// TODO: BINRAW It probably works, but checks are needed.
// (protocol->type == SubGhzProtocolTypeBinRAW) ||
(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");
break;
}

if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) {
FURI_LOG_E(TAG, "Unable Repeat");
break;
}

ret = SubRemLoadSubStateOK;

#if FURI_DEBUG
FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label));
#endif
} while(false);

furi_string_free(temp_str);
sub_preset->load_state = ret;
return ret;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once

#include "subrem_types.h"
#include "txrx/subghz_txrx.h"

#include <flipper_format/flipper_format_i.h>
#include <lib/subghz/types.h>

typedef struct {
FuriString* name;
uint32_t frequency;
// size_t preset_index; // Need for custom preset
} FreqPreset;

// Sub File preset
typedef struct {
FlipperFormat* fff_data;
FreqPreset freq_preset;
FuriString* file_path;
FuriString* protocaol_name;
FuriString* label;
SubGhzProtocolType type;
SubRemLoadSubState load_state;
} SubRemSubFilePreset;

typedef struct {
SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount];
} SubRemMapPreset;

SubRemSubFilePreset* subrem_sub_file_preset_alloc();

void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset);

void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset);

SubRemLoadSubState subrem_sub_preset_load(
SubRemSubFilePreset* sub_preset,
SubGhzTxRx* txrx,
FlipperFormat* fff_data_file);
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#include <furi.h>
#include <furi_hal.h>

#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 {
SubRemViewIDSubmenu,
SubRemViewIDWidget,
SubRemViewIDPopup,
SubRemViewIDTextInput,
SubRemViewIDRemote,
SubRemViewIDEditMenu,
} SubRemViewID;

typedef enum {
SubRemLoadSubStateNotSet = 0,
SubRemLoadSubStatePreloaded,
SubRemLoadSubStateError,
SubRemLoadSubStateErrorIncorectPath,
SubRemLoadSubStateErrorNoFile,
SubRemLoadSubStateErrorFreq,
SubRemLoadSubStateErrorMod,
SubRemLoadSubStateErrorProtocol,
SubRemLoadSubStateOK,
} SubRemLoadSubState;

typedef enum {
SubRemLoadMapStateBack = 0,
SubRemLoadMapStateError,
SubRemLoadMapStateErrorOpenError,
SubRemLoadMapStateErrorStorage,
SubRemLoadMapStateErrorBrokenFile,
SubRemLoadMapStateNotAllOK,
SubRemLoadMapStateOK,
} SubRemLoadMapState;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This is part of the official `SubGhz` app from [flipperzero-firmware](https://github.com/flipperdevices/flipperzero-firmware/tree/3217f286f03da119398586daf94c0723d28b872a/applications/main/subghz)

With changes from [unleashed-firmware
](https://github.com/DarkFlippers/unleashed-firmware/tree/3eac6ccd48a3851cf5d63bf7899b387a293e5319/applications/main/subghz)
Loading