This commit is contained in:
gid9798 2023-05-19 21:06:03 +03:00
parent 43a7b50b74
commit 0b25cc5a5c
11 changed files with 92 additions and 484 deletions

View File

@ -1,16 +1,19 @@
App(
appid="subghz_remote_new",
name="SubRem new",
apptype=FlipperAppType.EXTERNAL,
appid="subrem_remote_fap",
name="Sub-GHz Remote",
apptype=FlipperAppType.APP,
entry_point="subghz_remote_app",
cdefines=[
"APP_SUBGHZREMOTE",
"SUBREM_LIGHT",
],
requires=[
"gui",
"dialogs",
],
cdefines=["SUBREM_LIGHT"],
icon="A_SubGHzRemote_14",
stack_size=4 * 1024,
order=12,
order=50,
fap_category="Debug",
fap_icon_assets="icons",
)

View File

@ -1,13 +1,9 @@
#pragma once
typedef enum {
// SubRemCustomEventManagerNoSet = 0,
// SubRemCustomEventManagerSet,
// SubRemCustomEventManagerSetRAW,
//SubmenuIndex
SubmenuIndexSubRemOpenMapFile,
SubmenuIndexSubRemRemoteView, // TODO: temp debug
SubmenuIndexSubRemRemoteView,
SubmenuIndexSubRemAbout,
//SubRemCustomEvent

View File

@ -3,6 +3,7 @@
#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"
@ -25,16 +26,7 @@ typedef enum {
} SubRemViewID;
typedef enum {
// Loadin State
SubRemSubKeyTypeNoData = 0,
// SubRemSubKeyTypeHaveFileName,
// Key Type
SubRemSubKeyTypeStaticKey = 100,
SubRemSubKeyTypeDynamicKey,
SubRemSubKeyTypeRawKey,
} SubRemSubKeyType; // TODO: depricated
// typedef enum {
//
// } SubRemLoadMapState;
SubRemLoadMapStateBack = 0,
SubRemLoadMapStateError,
SubRemLoadMapStateOK,
} SubRemLoadMapState;

View File

@ -2,15 +2,12 @@
void subrem_scene_openmapfile_on_enter(void* context) {
SubGhzRemoteApp* app = context;
SubRemLoadMapState load_state = subrem_load_from_file(app);
if(subrem_load_from_file(app)) {
scene_manager_next_scene(app->scene_manager, SubRemSceneRemote);
} else {
// TODO: Map Preset Reset
// #if SUBREM_LIGHT
// dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file");
// #else
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);
@ -19,8 +16,12 @@ void subrem_scene_openmapfile_on_enter(void* context) {
dialog_message_show(app->dialogs, message);
dialog_message_free(message);
// #endif
#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 File

@ -5,12 +5,6 @@
#define TAG "SubRemScenRemote"
// TODO:
// #include <lib/subghz/protocols/keeloq.h>
// #include <lib/subghz/protocols/star_line.h>
// #include <lib/subghz/blocks/custom_btn.h>
void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) {
furi_assert(context);
SubGhzRemoteApp* app = context;
@ -59,16 +53,10 @@ static bool subrem_scene_remote_update_data_show(void* context) {
void subrem_scene_remote_on_enter(void* context) {
SubGhzRemoteApp* app = context;
// TODO: init view data
subrem_scene_remote_update_data_show(app);
if(!subrem_scene_remote_update_data_show(app)) {
// view_dispatcher_send_custom_event(
// app->view_dispatcher, SubGhzCustomEventViewTransmitterError);
}
subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app);
// TODO: notifications
// app->state_notifications = SubGhzNotificationStateIDLE;
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote);
}
@ -92,10 +80,10 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) {
event.event == SubRemCustomEventViewRemoteStartRIGHT ||
event.event == SubRemCustomEventViewRemoteStartOK) {
// Start sending sub
subghz_tx_stop_sub(app, true);
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(subghz_tx_start_sub(
if(subrem_tx_start_sub(
app,
app->subs_preset[app->chusen_sub],
subrem_scene_remote_raw_callback_end_tx)) {
@ -105,17 +93,18 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) {
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) {
subghz_tx_stop_sub(app, true);
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(subghz_tx_stop_sub(app, false)) {
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);
@ -132,19 +121,10 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) {
void subrem_scene_remote_on_exit(void* context) {
SubGhzRemoteApp* app = context;
subghz_tx_stop_sub(app, true);
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);
// TODO: notifications and reset KL
// keeloq_reset_mfname();
// keeloq_reset_kl_type();
// keeloq_reset_original_btn();
// subghz_custom_btns_reset();
// star_line_reset_mfname();
// star_line_reset_kl_type();
}

View File

@ -48,7 +48,6 @@ bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSubRemOpenMapFile) {
//scene_manager_set_scene_state(app->scene_manager, SubRemSceneStart, event.event);
scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile);
consumed = true;
}

View File

@ -34,16 +34,8 @@ SubGhzRemoteApp* subghz_remote_app_alloc() {
furi_hal_power_suppress_charge_enter();
// // Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering
// uint8_t attempts = 0;
// while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
// furi_hal_power_enable_otg();
// furi_delay_ms(10);
// }
app->file_path = furi_string_alloc();
furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
//app->error = SubGhzRemoteErrorNoError;
furi_string_set(app->file_path, SUBREM_APP_FOLDER);
// GUI
app->gui = furi_record_open(RECORD_GUI);
@ -71,19 +63,6 @@ SubGhzRemoteApp* subghz_remote_app_alloc() {
view_dispatcher_add_view(
app->view_dispatcher, SubRemViewSubmenu, submenu_get_view(app->submenu));
// Widget
app->widget = widget_alloc();
view_dispatcher_add_view(app->view_dispatcher, SubRemViewWidget, widget_get_view(app->widget));
// Text Input
app->text_input = text_input_alloc();
view_dispatcher_add_view(
app->view_dispatcher, SubRemViewTextInput, text_input_get_view(app->text_input));
// Popup
app->popup = popup_alloc();
view_dispatcher_add_view(app->view_dispatcher, SubRemViewPopup, popup_get_view(app->popup));
//Dialog
app->dialogs = furi_record_open(RECORD_DIALOGS);
@ -118,7 +97,11 @@ SubGhzRemoteApp* subghz_remote_app_alloc() {
app->tx_running = false;
#ifdef SUBREM_LIGHT
scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile);
#else
scene_manager_next_scene(app->scene_manager, SubRemSceneStart);
#endif
return app;
}
@ -137,18 +120,6 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewSubmenu);
submenu_free(app->submenu);
// Widget
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewWidget);
widget_free(app->widget);
// TextInput
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewTextInput);
text_input_free(app->text_input);
// Popup
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewPopup);
popup_free(app->popup);
//Dialog
furi_record_close(RECORD_DIALOGS);

View File

@ -2,9 +2,13 @@
#include <lib/toolbox/path.h>
#include <flipper_format/flipper_format_i.h>
#include <lib/subghz/protocols/raw.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] = {
@ -91,7 +95,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data
sub_preset = app->subs_preset[i];
if(!flipper_format_read_string(
fff_data_file, map_file_labels[i][0], sub_preset->file_path)) {
#if FURO_LOG
#if FURI_DEBUG
FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]);
#endif
sub_preset->type = SubGhzProtocolTypeUnknown;
@ -99,11 +103,10 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data
// Rewind error
} else if(!flipper_format_read_string(
fff_data_file, map_file_labels[i][1], sub_preset->label)) {
#if FURO_LOG
#if FURI_DEBUG
FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]);
#endif
furi_string_set_str(sub_preset->label,
"N/A"); // TODO: Standart name or part of name
path_extract_filename(sub_preset->file_path, sub_preset->label, true);
} else {
FURI_LOG_I(
TAG,
@ -118,8 +121,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data
return ret;
}
bool subghz_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) {
// furi_assert(subghz);
bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) {
furi_assert(flipper_format);
furi_assert(dev_file_name);
@ -135,12 +137,6 @@ bool subghz_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev
flipper_format_delete_key(flipper_format, "Repeat");
//flipper_format_delete_key(flipper_format, "Manufacture");
// Create subghz folder directory if necessary
// if(!storage_simply_mkdir(storage, furi_string_get_cstr(file_dir))) {
// dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder");
// break;
// }
if(!storage_simply_remove(storage, dev_file_name)) {
break;
}
@ -155,7 +151,7 @@ bool subghz_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev
return saved;
}
bool subghz_tx_start_sub(
bool subrem_tx_start_sub(
SubGhzRemoteApp* app,
SubRemSubFilePreset* sub_preset,
SubGhzProtocolEncoderRAWCallbackEnd callback) {
@ -163,7 +159,7 @@ bool subghz_tx_start_sub(
furi_assert(sub_preset);
bool ret = false;
subghz_tx_stop_sub(app, true);
subrem_tx_stop_sub(app, true);
if(sub_preset->type == SubGhzProtocolTypeUnknown) {
return false;
@ -171,8 +167,12 @@ bool subghz_tx_start_sub(
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); // FIXME:
flipper_format_rewind(sub_preset->fff_data); //
app->transmitter = subghz_transmitter_alloc_init(
app->environment, furi_string_get_cstr(sub_preset->protocaol_name));
@ -215,7 +215,7 @@ bool subghz_tx_start_sub(
}
} while(false);
app->tx_running = ret; // TODO:
app->tx_running = ret;
return ret;
}
@ -231,7 +231,7 @@ static void subghz_tx_stop(SubGhzRemoteApp* app) {
furi_hal_subghz_idle();
}
bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced) {
bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) {
furi_assert(app);
SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub];
@ -241,8 +241,15 @@ bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced) {
subghz_tx_stop(app);
if(sub_preset->type == SubGhzProtocolTypeDynamic) {
subghz_save_protocol_to_file(
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;
@ -251,10 +258,6 @@ bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced) {
}
return false;
// SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub];
// TODO: need saving logic
}
static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) {
@ -408,7 +411,7 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) {
}
}
// TODO: Pop for error or return error type
// TODO: Popup for error or return error type
if(!ret) {
FURI_LOG_E(TAG, "Broken Map File");
}
@ -421,24 +424,25 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) {
return ret;
}
bool subrem_load_from_file(SubGhzRemoteApp* app) {
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
bool res =
dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options);
if(res) {
res = subrem_map_file_load(app, furi_string_get_cstr(app->file_path));
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 res;
return ret;
}

View File

@ -1,7 +1,9 @@
#pragma once
#include "helpers/subrem_types.h"
#include <subghz_remote_new_icons.h> // TODO:
#include <subrem_remote_fap_icons.h>
// #include <assets_icons.h>
#include "views/remote.h"
@ -18,16 +20,16 @@
#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>
#include <flipper_format/flipper_format_i.h> // FIXME:
#define SUBREM_APP_FOLDER ANY_PATH("subghz_remote")
#define SUBGHZ_REMOTE_MAX_LEN_NAME 64
#define SUBREM_APP_FOLDER EXT_PATH("subghz_remote")
#define SUBREM_MAX_LEN_NAME 64
typedef struct {
uint32_t frequency;
@ -54,12 +56,9 @@ typedef struct {
SceneManager* scene_manager;
NotificationApp* notifications;
DialogsApp* dialogs;
Popup* popup;
Submenu* submenu;
Widget* widget;
TextInput* text_input;
FuriString* file_path;
char file_name_tmp[SUBGHZ_REMOTE_MAX_LEN_NAME];
char file_name_tmp[SUBREM_MAX_LEN_NAME];
SubRemViewRemote* subrem_remote_view;
@ -77,11 +76,11 @@ typedef struct {
// TODO: LoadFileError
} SubGhzRemoteApp;
bool subrem_load_from_file(SubGhzRemoteApp* app);
SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app);
bool subghz_tx_start_sub(
bool subrem_tx_start_sub(
SubGhzRemoteApp* app,
SubRemSubFilePreset* sub_preset,
SubGhzProtocolEncoderRAWCallbackEnd callback);
bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced);
bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced);

View File

@ -29,9 +29,6 @@ typedef struct {
SubRemViewRemoteState state;
uint8_t pressed_btn;
// bool show_button;
// FuriString* temp_button_id;
// bool draw_temp_button;
} SubRemViewRemoteModel;
void subrem_view_remote_set_callback(
@ -93,18 +90,8 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
//map found, draw all the things
canvas_clear(canvas);
//canvas_set_font(canvas, FontPrimary);
//canvas_draw_str(canvas, 0, 10, "U: ");
//canvas_draw_str(canvas, 0, 20, "L: ");
//canvas_draw_str(canvas, 0, 30, "R: ");
//canvas_draw_str(canvas, 0, 40, "D: ");
//canvas_draw_str(canvas, 0, 50, "Ok: ");
//PNGs are located in assets/icons/SubGHzRemote before compilation
//Icons for Labels
//canvas_draw_icon(canvas, 0, 0, &I_SubGHzRemote_LeftAlignedButtons_9x64);
canvas_draw_icon(canvas, 1, 5, &I_ButtonUp_7x4);
@ -121,6 +108,7 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) {
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));
@ -130,9 +118,6 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) {
canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit.");
//Status text and indicator
//canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, model->state);
canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13);
if(model->state == SubRemViewRemoteStateIdle) {
@ -146,7 +131,9 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) {
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Load");
break;
default:
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle");
#if FURI_DEBUG
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Wrong_state");
#endif
break;
}
@ -179,7 +166,6 @@ bool subrem_view_remote_input(InputEvent* event, void* context) {
SubRemViewRemote* subrem_view_remote = context;
if(event->key == InputKeyBack && event->type == InputTypeLong) {
// TODO: remove reset Debug
with_view_model(
subrem_view_remote->view,
SubRemViewRemoteModel * model,
@ -189,12 +175,6 @@ bool subrem_view_remote_input(InputEvent* event, void* context) {
strcpy(model->left_label, "N/A");
strcpy(model->right_label, "N/A");
strcpy(model->ok_label, "N/A");
// furi_string_reset(model->up_label);
// furi_string_reset(model->down_label);
// furi_string_reset(model->left_label);
// furi_string_reset(model->right_label);
// furi_string_reset(model->ok_label);
},
false);
subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context);
@ -280,11 +260,11 @@ SubRemViewRemote* subrem_view_remote_alloc() {
strcpy(model->right_label, "N/A");
strcpy(model->ok_label, "N/A");
// model->up_label = furi_string_alloc();
// model->down_label = furi_string_alloc();
// model->left_label = furi_string_alloc();
// model->right_label = furi_string_alloc();
// model->ok_label = furi_string_alloc();
// 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;
},

View File

@ -1,317 +0,0 @@
#include "transmitter.h"
#include "../subghz_remote_app_i.h"
#include <input/input.h>
#include <gui/elements.h>
#include <lib/subghz/blocks/custom_btn.h>
struct SubGhzRemoteViewRemote {
View* view;
SubGhzRemoteViewRemoteCallback callback;
void* context;
};
typedef struct {
FuriString* frequency_str;
FuriString* preset_str;
FuriString* key_str;
// bool show_button;
// FuriString* temp_button_id;
// bool draw_temp_button;
} SubGhzRemoteViewRemoteModel;
void subghz_view_transmitter_set_callback(
SubGhzRemoteViewRemote* subghz_transmitter,
SubGhzRemoteViewRemoteCallback callback,
void* context) {
furi_assert(subghz_transmitter);
subghz_transmitter->callback = callback;
subghz_transmitter->context = context;
}
void subghz_view_transmitter_add_data_to_show(
SubGhzRemoteViewRemote* subghz_transmitter,
const char* key_str,
const char* frequency_str,
const char* preset_str,
bool show_button) {
furi_assert(subghz_transmitter);
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
furi_string_set(model->key_str, key_str);
furi_string_set(model->frequency_str, frequency_str);
furi_string_set(model->preset_str, preset_str);
model->show_button = show_button;
},
true);
}
static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) {
const uint8_t button_height = 12;
const uint8_t vertical_offset = 3;
const uint8_t horizontal_offset = 1;
const uint8_t string_width = canvas_string_width(canvas, str);
const Icon* icon = &I_ButtonCenter_7x7;
const uint8_t icon_offset = 3;
const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_offset;
const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40;
const uint8_t y = canvas_height(canvas);
canvas_draw_box(canvas, x, y - button_height, button_width, button_height);
canvas_draw_line(canvas, x - 1, y, x - 1, y - button_height + 0);
canvas_draw_line(canvas, x - 2, y, x - 2, y - button_height + 1);
canvas_draw_line(canvas, x - 3, y, x - 3, y - button_height + 2);
canvas_draw_line(canvas, x + button_width + 0, y, x + button_width + 0, y - button_height + 0);
canvas_draw_line(canvas, x + button_width + 1, y, x + button_width + 1, y - button_height + 1);
canvas_draw_line(canvas, x + button_width + 2, y, x + button_width + 2, y - button_height + 2);
canvas_invert_color(canvas);
canvas_draw_icon(
canvas,
x + horizontal_offset,
y - button_height + vertical_offset - 1,
&I_ButtonCenter_7x7);
canvas_draw_str(
canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str);
canvas_invert_color(canvas);
}
void subghz_view_transmitter_draw(Canvas* canvas, SubGhzRemoteViewRemoteModel* model) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
elements_multiline_text_aligned(
canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(model->key_str));
canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str));
// if(model->draw_temp_button) {
// canvas_set_font(canvas, FontBatteryPercent);
// canvas_draw_str(canvas, 117, 40, furi_string_get_cstr(model->temp_button_id));
// canvas_set_font(canvas, FontSecondary);
// }
// if(model->show_button) {
// canvas_draw_str(canvas, 58, 62, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int");
// subghz_view_transmitter_button_right(canvas, "Send");
// }
}
bool subghz_view_transmitter_input(InputEvent* event, void* context) {
furi_assert(context);
SubGhzRemoteViewRemote* subghz_transmitter = context;
bool can_be_sent = false;
if(event->key == InputKeyBack && event->type == InputTypeShort) {
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
furi_string_reset(model->frequency_str);
furi_string_reset(model->preset_str);
furi_string_reset(model->key_str);
furi_string_reset(model->temp_button_id);
model->show_button = false;
model->draw_temp_button = false;
},
false);
return false;
}
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
if(model->show_button) {
can_be_sent = true;
}
},
true);
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
subghz_custom_btn_set(0);
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
furi_string_reset(model->temp_button_id);
model->draw_temp_button = false;
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Temp Buttons (UP)
if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) {
subghz_custom_btn_set(1);
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 1) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyUp && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Down
if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) {
subghz_custom_btn_set(2);
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 2) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyDown && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Left
if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) {
subghz_custom_btn_set(3);
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 3) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Right
if(can_be_sent && event->key == InputKeyRight && event->type == InputTypePress) {
subghz_custom_btn_set(4);
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 4) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyRight && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
return true;
}
void subghz_view_transmitter_enter(void* context) {
furi_assert(context);
}
void subghz_view_transmitter_exit(void* context) {
furi_assert(context);
}
SubGhzRemoteViewRemote* subghz_view_transmitter_alloc() {
SubGhzRemoteViewRemote* subghz_transmitter = malloc(sizeof(SubGhzRemoteViewRemote));
// View allocation and configuration
subghz_transmitter->view = view_alloc();
view_allocate_model(
subghz_transmitter->view, ViewModelTypeLocking, sizeof(SubGhzRemoteViewRemoteModel));
view_set_context(subghz_transmitter->view, subghz_transmitter);
view_set_draw_callback(
subghz_transmitter->view, (ViewDrawCallback)subghz_view_transmitter_draw);
view_set_input_callback(subghz_transmitter->view, subghz_view_transmitter_input);
view_set_enter_callback(subghz_transmitter->view, subghz_view_transmitter_enter);
view_set_exit_callback(subghz_transmitter->view, subghz_view_transmitter_exit);
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
model->frequency_str = furi_string_alloc();
model->preset_str = furi_string_alloc();
model->key_str = furi_string_alloc();
model->temp_button_id = furi_string_alloc();
},
true);
return subghz_transmitter;
}
void subghz_view_transmitter_free(SubGhzRemoteViewRemote* subghz_transmitter) {
furi_assert(subghz_transmitter);
with_view_model(
subghz_transmitter->view,
SubGhzRemoteViewRemoteModel * model,
{
furi_string_free(model->frequency_str);
furi_string_free(model->preset_str);
furi_string_free(model->key_str);
furi_string_free(model->temp_button_id);
},
true);
view_free(subghz_transmitter->view);
free(subghz_transmitter);
}
View* subghz_view_transmitter_get_view(SubGhzRemoteViewRemote* subghz_transmitter) {
furi_assert(subghz_transmitter);
return subghz_transmitter->view;
}