Overhaul | 2

This commit is contained in:
VerstreuteSeele
2022-12-30 09:01:44 +01:00
parent 64a81747c2
commit d5c0f4f3a3
26 changed files with 13 additions and 1266 deletions

View File

@@ -10,7 +10,6 @@ App(
"ibutton_loader", "ibutton_loader",
# "infrared", # "infrared",
"infrared_loader", "infrared_loader",
"infrared_rem_loader",
"lfrfid", "lfrfid",
# "lfrfid_loader", # "lfrfid_loader",
"nfc", "nfc",

View File

@@ -1,14 +0,0 @@
App(
appid="infrared_rem_loader",
name="IR Remote",
apptype=FlipperAppType.APP,
entry_point="infrared_rem_loader_app",
requires=[
"gui",
"dialogs",
],
stack_size=int(2 * 1024),
icon="A_Infrared_14",
order=41,
link="/ext/apps/Tools/IR_Remote.fap",
)

View File

@@ -1,9 +0,0 @@
#include <applications/services/loader/loader_i.h>
#define TAG "infrared_rem_loader_app"
int32_t infrared_rem_loader_app(void* p) {
UNUSED(p);
return 0;
}

View File

@@ -1,63 +0,0 @@
# Alternative Infrared Remote for Flipperzero
It is a plugin like [UniversalRF Remix](https://github.com/ESurge/flipperzero-firmware-unirfremix) but for infrared files. I do this plugin for convenience, because the main IR app need to navigate for different button abit troublesome (buttons like up,down,left,right,back). I found it useful for TV and TV box.
It supports short press and long press input for different ir remote buttons. Tested on the [unleashed firmware version unlshd-015](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/unlshd-015)
## How to install
1. Update unleashed firmware to the version unlshd-015, then download the `ir_remote.fap` from [releases](https://github.com/Hong5489/ir_remote/tags)
2. Put the `ir_remote.fap` file in your flipper's SD card, under `apps` folder
## How to use
1. Similar to UniRF app, put the path of the ir file and the ir button for each button on flipper (UP,DOWN,LEFT,RIGHT,BACK)
The format With `HOLD` one is long press, without is short press
Example of the configuration file:
```
REMOTE: /ext/infrared/Philips_32PFL4208T.ir
UP: Up
DOWN: Down
LEFT: Left
RIGHT: Right
OK:
BACK: Back
UPHOLD: VOL+
DOWNHOLD: VOL-
LEFTHOLD: Source
RIGHTHOLD: SmartTV
OKHOLD: POWER
```
Leave it empty for the button you don't need
2. Save it as `.txt` file, then create a new folder in your SD card `ir_remote`, put it inside the folder
3. Lastly, you can open the app, choose the configuration file, then you can try out the ir for each buttons
4. Long press back button to exit the app
## How to build
You can clone this repo and put it inside the `applications_user` folder, then build it with the command:
```
./fbt fap_ir_remote
```
Or you can build and run it on your flipper with the command:
```
./fbt launch_app APPSRC=applications_user/ir_remote
```
## Screenshots
Choose config file to map
![image](ir.png)
Show all button name in the config file (If empty will show N/A). Upper part short press, Lower part long press
![image2](ir2.png)

View File

@@ -1,14 +0,0 @@
App(
appid="IR_Remote",
name="IR Remote",
apptype=FlipperAppType.EXTERNAL,
entry_point="infrared_remote_app",
stack_size=3 * 1024,
requires=[
"gui",
"dialogs",
],
fap_category="Tools",
fap_icon="ir_10px.png",
fap_icon_assets="images",
)

View File

@@ -1,12 +0,0 @@
REMOTE: /ext/infrared/Philips_32PFL4208T.ir
UP: Up
DOWN: Down
LEFT: Left
RIGHT: Right
OK:
BACK: Back
UPHOLD: VOL+
DOWNHOLD: VOL-
LEFTHOLD: Source
RIGHTHOLD: SmartTV
OKHOLD: POWER

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 B

View File

@@ -1,188 +0,0 @@
#include "infrared_remote.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <m-array.h>
#include <toolbox/path.h>
#include <storage/storage.h>
#include <core/common_defines.h>
#define TAG "InfraredRemote"
ARRAY_DEF(InfraredButtonArray, InfraredRemoteButton*, M_PTR_OPLIST);
struct InfraredRemote {
InfraredButtonArray_t buttons;
FuriString* name;
FuriString* path;
};
static void infrared_remote_clear_buttons(InfraredRemote* remote) {
InfraredButtonArray_it_t it;
for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it);
InfraredButtonArray_next(it)) {
infrared_remote_button_free(*InfraredButtonArray_cref(it));
}
InfraredButtonArray_reset(remote->buttons);
}
InfraredRemote* infrared_remote_alloc() {
InfraredRemote* remote = malloc(sizeof(InfraredRemote));
InfraredButtonArray_init(remote->buttons);
remote->name = furi_string_alloc();
remote->path = furi_string_alloc();
return remote;
}
void infrared_remote_free(InfraredRemote* remote) {
infrared_remote_clear_buttons(remote);
InfraredButtonArray_clear(remote->buttons);
furi_string_free(remote->path);
furi_string_free(remote->name);
free(remote);
}
void infrared_remote_reset(InfraredRemote* remote) {
infrared_remote_clear_buttons(remote);
furi_string_reset(remote->name);
furi_string_reset(remote->path);
}
void infrared_remote_set_name(InfraredRemote* remote, const char* name) {
furi_string_set(remote->name, name);
}
const char* infrared_remote_get_name(InfraredRemote* remote) {
return furi_string_get_cstr(remote->name);
}
void infrared_remote_set_path(InfraredRemote* remote, const char* path) {
furi_string_set(remote->path, path);
}
const char* infrared_remote_get_path(InfraredRemote* remote) {
return furi_string_get_cstr(remote->path);
}
size_t infrared_remote_get_button_count(InfraredRemote* remote) {
return InfraredButtonArray_size(remote->buttons);
}
InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t index) {
furi_assert(index < InfraredButtonArray_size(remote->buttons));
return *InfraredButtonArray_get(remote->buttons, index);
}
bool infrared_remote_find_button_by_name(InfraredRemote* remote, const char* name, size_t* index) {
for(size_t i = 0; i < InfraredButtonArray_size(remote->buttons); i++) {
InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, i);
if(!strcmp(infrared_remote_button_get_name(button), name)) {
*index = i;
return true;
}
}
return false;
}
bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal) {
InfraredRemoteButton* button = infrared_remote_button_alloc();
infrared_remote_button_set_name(button, name);
infrared_remote_button_set_signal(button, signal);
InfraredButtonArray_push_back(remote->buttons, button);
return infrared_remote_store(remote);
}
bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index) {
furi_assert(index < InfraredButtonArray_size(remote->buttons));
InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, index);
infrared_remote_button_set_name(button, new_name);
return infrared_remote_store(remote);
}
bool infrared_remote_delete_button(InfraredRemote* remote, size_t index) {
furi_assert(index < InfraredButtonArray_size(remote->buttons));
InfraredRemoteButton* button;
InfraredButtonArray_pop_at(&button, remote->buttons, index);
infrared_remote_button_free(button);
return infrared_remote_store(remote);
}
bool infrared_remote_store(InfraredRemote* remote) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_file_alloc(storage);
const char* path = furi_string_get_cstr(remote->path);
FURI_LOG_I(TAG, "store file: \'%s\'", path);
bool success = flipper_format_file_open_always(ff, path) &&
flipper_format_write_header_cstr(ff, "IR signals file", 1);
if(success) {
InfraredButtonArray_it_t it;
for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it);
InfraredButtonArray_next(it)) {
InfraredRemoteButton* button = *InfraredButtonArray_cref(it);
success = infrared_signal_save(
infrared_remote_button_get_signal(button),
ff,
infrared_remote_button_get_name(button));
if(!success) {
break;
}
}
}
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
return success;
}
bool infrared_remote_load(InfraredRemote* remote, FuriString* path) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
FuriString* buf;
buf = furi_string_alloc();
FURI_LOG_I(TAG, "load file: \'%s\'", furi_string_get_cstr(path));
bool success = flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(path));
if(success) {
uint32_t version;
success = flipper_format_read_header(ff, buf, &version) &&
!furi_string_cmp(buf, "IR signals file") && (version == 1);
}
if(success) {
path_extract_filename(path, buf, true);
infrared_remote_clear_buttons(remote);
infrared_remote_set_name(remote, furi_string_get_cstr(buf));
infrared_remote_set_path(remote, furi_string_get_cstr(path));
for(bool can_read = true; can_read;) {
InfraredRemoteButton* button = infrared_remote_button_alloc();
can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf);
if(can_read) {
infrared_remote_button_set_name(button, furi_string_get_cstr(buf));
InfraredButtonArray_push_back(remote->buttons, button);
} else {
infrared_remote_button_free(button);
}
}
}
furi_string_free(buf);
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
return success;
}
bool infrared_remote_remove(InfraredRemote* remote) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FS_Error status = storage_common_remove(storage, furi_string_get_cstr(remote->path));
infrared_remote_reset(remote);
furi_record_close(RECORD_STORAGE);
return (status == FSE_OK || status == FSE_NOT_EXIST);
}

View File

@@ -1,29 +0,0 @@
#pragma once
#include <stdbool.h>
#include "infrared_remote_button.h"
typedef struct InfraredRemote InfraredRemote;
InfraredRemote* infrared_remote_alloc();
void infrared_remote_free(InfraredRemote* remote);
void infrared_remote_reset(InfraredRemote* remote);
void infrared_remote_set_name(InfraredRemote* remote, const char* name);
const char* infrared_remote_get_name(InfraredRemote* remote);
void infrared_remote_set_path(InfraredRemote* remote, const char* path);
const char* infrared_remote_get_path(InfraredRemote* remote);
size_t infrared_remote_get_button_count(InfraredRemote* remote);
InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t index);
bool infrared_remote_find_button_by_name(InfraredRemote* remote, const char* name, size_t* index);
bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal);
bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index);
bool infrared_remote_delete_button(InfraredRemote* remote, size_t index);
bool infrared_remote_store(InfraredRemote* remote);
bool infrared_remote_load(InfraredRemote* remote, FuriString* path);
bool infrared_remote_remove(InfraredRemote* remote);

View File

@@ -1,532 +0,0 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <dialogs/dialogs.h>
#include <IR_Remote_icons.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include "infrared_signal.h"
#include "infrared_remote.h"
#include "infrared_remote_button.h"
#define TAG "IR_Remote"
#include <flipper_format/flipper_format.h>
typedef struct {
int status;
ViewPort* view_port;
FuriString* up_button;
FuriString* down_button;
FuriString* left_button;
FuriString* right_button;
FuriString* ok_button;
FuriString* back_button;
FuriString* up_hold_button;
FuriString* down_hold_button;
FuriString* left_hold_button;
FuriString* right_hold_button;
FuriString* ok_hold_button;
} IRApp;
// Screen is 128x64 px
static void app_draw_callback(Canvas* canvas, void* ctx) {
// Show config is incorrect when cannot read the remote file
// Showing button string in the screen, upper part is short press, lower part is long press
IRApp* app = ctx;
if(app->status) {
canvas_clear(canvas);
view_port_set_orientation(app->view_port, ViewPortOrientationHorizontal);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 62, 5, AlignCenter, AlignTop, "Config is incorrect.");
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignTop, "Please configure map.");
canvas_draw_str_aligned(canvas, 62, 60, AlignCenter, AlignBottom, "Press Back to Exit.");
} else {
canvas_clear(canvas);
view_port_set_orientation(app->view_port, ViewPortOrientationVertical);
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_aligned(
canvas, 32, 8, AlignCenter, AlignCenter, furi_string_get_cstr(app->up_button));
canvas_draw_str_aligned(
canvas, 32, 18, AlignCenter, AlignCenter, furi_string_get_cstr(app->down_button));
canvas_draw_str_aligned(
canvas, 32, 28, AlignCenter, AlignCenter, furi_string_get_cstr(app->left_button));
canvas_draw_str_aligned(
canvas, 32, 38, AlignCenter, AlignCenter, furi_string_get_cstr(app->right_button));
canvas_draw_str_aligned(
canvas, 32, 48, AlignCenter, AlignCenter, furi_string_get_cstr(app->ok_button));
canvas_draw_str_aligned(
canvas, 32, 58, AlignCenter, AlignCenter, furi_string_get_cstr(app->back_button));
canvas_draw_line(canvas, 0, 65, 64, 65);
canvas_draw_icon(canvas, 1, 70, &I_ButtonUp_7x4);
canvas_draw_icon(canvas, 1, 80, &I_ButtonDown_7x4);
canvas_draw_icon(canvas, 2, 88, &I_ButtonLeft_4x7);
canvas_draw_icon(canvas, 2, 98, &I_ButtonRight_4x7);
canvas_draw_icon(canvas, 0, 107, &I_Ok_btn_9x9);
canvas_draw_icon(canvas, 0, 118, &I_back_10px);
canvas_draw_str_aligned(
canvas, 32, 73, AlignCenter, AlignCenter, furi_string_get_cstr(app->up_hold_button));
canvas_draw_str_aligned(
canvas, 32, 83, AlignCenter, AlignCenter, furi_string_get_cstr(app->down_hold_button));
canvas_draw_str_aligned(
canvas, 32, 93, AlignCenter, AlignCenter, furi_string_get_cstr(app->left_hold_button));
canvas_draw_str_aligned(
canvas,
32,
103,
AlignCenter,
AlignCenter,
furi_string_get_cstr(app->right_hold_button));
canvas_draw_str_aligned(
canvas, 32, 113, AlignCenter, AlignCenter, furi_string_get_cstr(app->ok_hold_button));
canvas_draw_str_aligned(canvas, 32, 123, AlignCenter, AlignCenter, "Exit App");
}
}
static void app_input_callback(InputEvent* input_event, void* ctx) {
furi_assert(ctx);
FuriMessageQueue* event_queue = ctx;
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
}
int32_t infrared_remote_app(void* p) {
UNUSED(p);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
// App button string
IRApp* app = malloc(sizeof(IRApp));
app->up_button = furi_string_alloc();
app->down_button = furi_string_alloc();
app->left_button = furi_string_alloc();
app->right_button = furi_string_alloc();
app->ok_button = furi_string_alloc();
app->back_button = furi_string_alloc();
app->up_hold_button = furi_string_alloc();
app->down_hold_button = furi_string_alloc();
app->left_hold_button = furi_string_alloc();
app->right_hold_button = furi_string_alloc();
app->ok_hold_button = furi_string_alloc();
app->view_port = view_port_alloc();
// Configure view port
view_port_draw_callback_set(app->view_port, app_draw_callback, app);
view_port_input_callback_set(app->view_port, app_input_callback, event_queue);
// Register view port in GUI
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, app->view_port, GuiLayerFullscreen);
InputEvent event;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_file_alloc(storage);
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, ".txt", &I_sub1_10px);
FuriString* map_file = furi_string_alloc();
furi_string_set(map_file, "/ext/infrared/ir_remote");
bool res = dialog_file_browser_show(dialogs, map_file, map_file, &browser_options);
furi_record_close(RECORD_DIALOGS);
// if user didn't choose anything, free everything and exit
if(!res) {
FURI_LOG_I(TAG, "exit");
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
furi_string_free(app->up_button);
furi_string_free(app->down_button);
furi_string_free(app->left_button);
furi_string_free(app->right_button);
furi_string_free(app->ok_button);
furi_string_free(app->back_button);
furi_string_free(app->up_hold_button);
furi_string_free(app->down_hold_button);
furi_string_free(app->left_hold_button);
furi_string_free(app->right_hold_button);
furi_string_free(app->ok_hold_button);
view_port_enabled_set(app->view_port, false);
gui_remove_view_port(gui, app->view_port);
view_port_free(app->view_port);
free(app);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_GUI);
return 255;
}
InfraredRemote* remote = infrared_remote_alloc();
FuriString* remote_path = furi_string_alloc();
InfraredSignal* up_signal = infrared_signal_alloc();
InfraredSignal* down_signal = infrared_signal_alloc();
InfraredSignal* left_signal = infrared_signal_alloc();
InfraredSignal* right_signal = infrared_signal_alloc();
InfraredSignal* ok_signal = infrared_signal_alloc();
InfraredSignal* back_signal = infrared_signal_alloc();
InfraredSignal* up_hold_signal = infrared_signal_alloc();
InfraredSignal* down_hold_signal = infrared_signal_alloc();
InfraredSignal* left_hold_signal = infrared_signal_alloc();
InfraredSignal* right_hold_signal = infrared_signal_alloc();
InfraredSignal* ok_hold_signal = infrared_signal_alloc();
bool up_enabled = false;
bool down_enabled = false;
bool left_enabled = false;
bool right_enabled = false;
bool ok_enabled = false;
bool back_enabled = false;
bool up_hold_enabled = false;
bool down_hold_enabled = false;
bool left_hold_enabled = false;
bool right_hold_enabled = false;
bool ok_hold_enabled = false;
if(!flipper_format_file_open_existing(ff, furi_string_get_cstr(map_file))) {
FURI_LOG_E(TAG, "Could not open MAP file %s", furi_string_get_cstr(map_file));
app->status = 1;
} else {
//Filename Assignment/Check Start
if(!flipper_format_read_string(ff, "REMOTE", remote_path)) {
FURI_LOG_E(TAG, "Could not read REMOTE string");
app->status = 1;
} else {
if(!infrared_remote_load(remote, remote_path)) {
FURI_LOG_E(TAG, "Could not load ir file: %s", furi_string_get_cstr(remote_path));
app->status = 1;
} else {
FURI_LOG_I(TAG, "Loaded REMOTE file: %s", furi_string_get_cstr(remote_path));
}
}
//assign variables to values within map file
//set missing filenames to N/A
//assign button signals
size_t index = 0;
if(!flipper_format_read_string(ff, "UP", app->up_button)) {
FURI_LOG_W(TAG, "Could not read UP string");
furi_string_set(app->up_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->up_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
up_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
up_enabled = true;
}
}
if(!flipper_format_read_string(ff, "DOWN", app->down_button)) {
FURI_LOG_W(TAG, "Could not read DOWN string");
furi_string_set(app->down_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->down_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
down_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
down_enabled = true;
}
}
if(!flipper_format_read_string(ff, "LEFT", app->left_button)) {
FURI_LOG_W(TAG, "Could not read LEFT string");
furi_string_set(app->left_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->left_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
left_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
left_enabled = true;
}
}
if(!flipper_format_read_string(ff, "RIGHT", app->right_button)) {
FURI_LOG_W(TAG, "Could not read RIGHT string");
furi_string_set(app->right_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->right_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
right_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
right_enabled = true;
}
}
if(!flipper_format_read_string(ff, "OK", app->ok_button)) {
FURI_LOG_W(TAG, "Could not read OK string");
furi_string_set(app->ok_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->ok_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
ok_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
ok_enabled = true;
}
}
if(!flipper_format_read_string(ff, "BACK", app->back_button)) {
FURI_LOG_W(TAG, "Could not read BACK string");
furi_string_set(app->back_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->back_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
back_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
back_enabled = true;
}
}
if(!flipper_format_read_string(ff, "UPHOLD", app->up_hold_button)) {
FURI_LOG_W(TAG, "Could not read UPHOLD string");
furi_string_set(app->up_hold_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->up_hold_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
up_hold_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
up_hold_enabled = true;
}
}
if(!flipper_format_read_string(ff, "DOWNHOLD", app->down_hold_button)) {
FURI_LOG_W(TAG, "Could not read DOWNHOLD string");
furi_string_set(app->down_hold_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->down_hold_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
down_hold_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
down_hold_enabled = true;
}
}
if(!flipper_format_read_string(ff, "LEFTHOLD", app->left_hold_button)) {
FURI_LOG_W(TAG, "Could not read LEFTHOLD string");
furi_string_set(app->left_hold_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->left_hold_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
left_hold_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
left_hold_enabled = true;
}
}
if(!flipper_format_read_string(ff, "RIGHTHOLD", app->right_hold_button)) {
FURI_LOG_W(TAG, "Could not read RIGHTHOLD string");
furi_string_set(app->right_hold_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->right_hold_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
right_hold_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
right_hold_enabled = true;
}
}
if(!flipper_format_read_string(ff, "OKHOLD", app->ok_hold_button)) {
FURI_LOG_W(TAG, "Could not read OKHOLD string");
furi_string_set(app->ok_hold_button, "N/A");
} else {
if(!infrared_remote_find_button_by_name(
remote, furi_string_get_cstr(app->ok_hold_button), &index)) {
FURI_LOG_W(TAG, "Error");
} else {
ok_hold_signal =
infrared_remote_button_get_signal(infrared_remote_get_button(remote, index));
ok_hold_enabled = true;
}
}
}
furi_string_free(remote_path);
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
bool running = true;
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
if(app->status) {
view_port_update(app->view_port);
while(running) {
if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
if(event.type == InputTypeShort) {
switch(event.key) {
case InputKeyBack:
running = false;
break;
default:
break;
}
}
}
}
} else {
view_port_update(app->view_port);
while(running) {
if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
// short press signal
if(event.type == InputTypeShort) {
switch(event.key) {
case InputKeyUp:
if(up_enabled) {
infrared_signal_transmit(up_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "up");
}
break;
case InputKeyDown:
if(down_enabled) {
infrared_signal_transmit(down_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "down");
}
break;
case InputKeyRight:
if(right_enabled) {
infrared_signal_transmit(right_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "right");
}
break;
case InputKeyLeft:
if(left_enabled) {
infrared_signal_transmit(left_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "left");
}
break;
case InputKeyOk:
if(ok_enabled) {
infrared_signal_transmit(ok_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "ok");
}
break;
case InputKeyBack:
if(back_enabled) {
infrared_signal_transmit(back_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "back");
}
break;
default:
running = false;
break;
}
// long press signal
} else if(event.type == InputTypeLong) {
switch(event.key) {
case InputKeyUp:
if(up_hold_enabled) {
infrared_signal_transmit(up_hold_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "up!");
}
break;
case InputKeyDown:
if(down_hold_enabled) {
infrared_signal_transmit(down_hold_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "down!");
}
break;
case InputKeyRight:
if(right_hold_enabled) {
infrared_signal_transmit(right_hold_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "right!");
}
break;
case InputKeyLeft:
if(left_hold_enabled) {
infrared_signal_transmit(left_hold_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "left!");
}
break;
case InputKeyOk:
if(ok_hold_enabled) {
infrared_signal_transmit(ok_hold_signal);
notification_message(notification, &sequence_blink_start_magenta);
FURI_LOG_I(TAG, "ok!");
}
break;
default:
running = false;
break;
}
} else if(event.type == InputTypeRelease) {
notification_message(notification, &sequence_blink_stop);
}
}
}
}
// Free all things
furi_string_free(app->up_button);
furi_string_free(app->down_button);
furi_string_free(app->left_button);
furi_string_free(app->right_button);
furi_string_free(app->ok_button);
furi_string_free(app->back_button);
furi_string_free(app->up_hold_button);
furi_string_free(app->down_hold_button);
furi_string_free(app->left_hold_button);
furi_string_free(app->right_hold_button);
furi_string_free(app->ok_hold_button);
infrared_remote_free(remote);
view_port_enabled_set(app->view_port, false);
gui_remove_view_port(gui, app->view_port);
view_port_free(app->view_port);
free(app);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_GUI);
return 0;
}

View File

@@ -1,37 +0,0 @@
#include "infrared_remote_button.h"
#include <stdlib.h>
struct InfraredRemoteButton {
FuriString* name;
InfraredSignal* signal;
};
InfraredRemoteButton* infrared_remote_button_alloc() {
InfraredRemoteButton* button = malloc(sizeof(InfraredRemoteButton));
button->name = furi_string_alloc();
button->signal = infrared_signal_alloc();
return button;
}
void infrared_remote_button_free(InfraredRemoteButton* button) {
furi_string_free(button->name);
infrared_signal_free(button->signal);
free(button);
}
void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name) {
furi_string_set(button->name, name);
}
const char* infrared_remote_button_get_name(InfraredRemoteButton* button) {
return furi_string_get_cstr(button->name);
}
void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal) {
infrared_signal_set_signal(button->signal, signal);
}
InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button) {
return button->signal;
}

View File

@@ -1,14 +0,0 @@
#pragma once
#include "infrared_signal.h"
typedef struct InfraredRemoteButton InfraredRemoteButton;
InfraredRemoteButton* infrared_remote_button_alloc();
void infrared_remote_button_free(InfraredRemoteButton* button);
void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name);
const char* infrared_remote_button_get_name(InfraredRemoteButton* button);
void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal);
InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button);

View File

@@ -1,300 +0,0 @@
#include "infrared_signal.h"
#include <stdlib.h>
#include <string.h>
#include <core/check.h>
#include <lib/infrared/worker/infrared_transmit.h>
#include <lib/infrared/worker/infrared_worker.h>
#define TAG "InfraredSignal"
struct InfraredSignal {
bool is_raw;
union {
InfraredMessage message;
InfraredRawSignal raw;
} payload;
};
static void infrared_signal_clear_timings(InfraredSignal* signal) {
if(signal->is_raw) {
free(signal->payload.raw.timings);
signal->payload.raw.timings_size = 0;
signal->payload.raw.timings = NULL;
}
}
static bool infrared_signal_is_message_valid(InfraredMessage* message) {
if(!infrared_is_protocol_valid(message->protocol)) {
FURI_LOG_E(TAG, "Unknown protocol");
return false;
}
uint32_t address_length = infrared_get_protocol_address_length(message->protocol);
uint32_t address_mask = (1UL << address_length) - 1;
if(message->address != (message->address & address_mask)) {
FURI_LOG_E(
TAG,
"Address is out of range (mask 0x%08lX): 0x%lX\r\n",
address_mask,
message->address);
return false;
}
uint32_t command_length = infrared_get_protocol_command_length(message->protocol);
uint32_t command_mask = (1UL << command_length) - 1;
if(message->command != (message->command & command_mask)) {
FURI_LOG_E(
TAG,
"Command is out of range (mask 0x%08lX): 0x%lX\r\n",
command_mask,
message->command);
return false;
}
return true;
}
static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) {
if((raw->frequency > INFRARED_MAX_FREQUENCY) || (raw->frequency < INFRARED_MIN_FREQUENCY)) {
FURI_LOG_E(
TAG,
"Frequency is out of range (%X - %X): %lX",
INFRARED_MIN_FREQUENCY,
INFRARED_MAX_FREQUENCY,
raw->frequency);
return false;
} else if((raw->duty_cycle <= 0) || (raw->duty_cycle > 1)) {
FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", (double)raw->duty_cycle);
return false;
} else if((raw->timings_size <= 0) || (raw->timings_size > MAX_TIMINGS_AMOUNT)) {
FURI_LOG_E(
TAG,
"Timings amount is out of range (0 - %X): %X",
MAX_TIMINGS_AMOUNT,
raw->timings_size);
return false;
}
return true;
}
static inline bool infrared_signal_save_message(InfraredMessage* message, FlipperFormat* ff) {
const char* protocol_name = infrared_get_protocol_name(message->protocol);
return flipper_format_write_string_cstr(ff, "type", "parsed") &&
flipper_format_write_string_cstr(ff, "protocol", protocol_name) &&
flipper_format_write_hex(ff, "address", (uint8_t*)&message->address, 4) &&
flipper_format_write_hex(ff, "command", (uint8_t*)&message->command, 4);
}
static inline bool infrared_signal_save_raw(InfraredRawSignal* raw, FlipperFormat* ff) {
furi_assert(raw->timings_size <= MAX_TIMINGS_AMOUNT);
return flipper_format_write_string_cstr(ff, "type", "raw") &&
flipper_format_write_uint32(ff, "frequency", &raw->frequency, 1) &&
flipper_format_write_float(ff, "duty_cycle", &raw->duty_cycle, 1) &&
flipper_format_write_uint32(ff, "data", raw->timings, raw->timings_size);
}
static inline bool infrared_signal_read_message(InfraredSignal* signal, FlipperFormat* ff) {
FuriString* buf;
buf = furi_string_alloc();
bool success = false;
do {
if(!flipper_format_read_string(ff, "protocol", buf)) break;
InfraredMessage message;
message.protocol = infrared_get_protocol_by_name(furi_string_get_cstr(buf));
success = flipper_format_read_hex(ff, "address", (uint8_t*)&message.address, 4) &&
flipper_format_read_hex(ff, "command", (uint8_t*)&message.command, 4) &&
infrared_signal_is_message_valid(&message);
if(!success) break;
infrared_signal_set_message(signal, &message);
} while(0);
furi_string_free(buf);
return success;
}
static inline bool infrared_signal_read_raw(InfraredSignal* signal, FlipperFormat* ff) {
uint32_t timings_size, frequency;
float duty_cycle;
bool success = flipper_format_read_uint32(ff, "frequency", &frequency, 1) &&
flipper_format_read_float(ff, "duty_cycle", &duty_cycle, 1) &&
flipper_format_get_value_count(ff, "data", &timings_size);
if(!success || timings_size > MAX_TIMINGS_AMOUNT) {
return false;
}
uint32_t* timings = malloc(sizeof(uint32_t) * timings_size);
success = flipper_format_read_uint32(ff, "data", timings, timings_size);
if(success) {
infrared_signal_set_raw_signal(signal, timings, timings_size, frequency, duty_cycle);
}
free(timings);
return success;
}
static bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff) {
FuriString* tmp = furi_string_alloc();
bool success = false;
do {
if(!flipper_format_read_string(ff, "type", tmp)) break;
if(furi_string_equal(tmp, "raw")) {
success = infrared_signal_read_raw(signal, ff);
} else if(furi_string_equal(tmp, "parsed")) {
success = infrared_signal_read_message(signal, ff);
} else {
FURI_LOG_E(TAG, "Unknown signal type");
}
} while(false);
furi_string_free(tmp);
return success;
}
InfraredSignal* infrared_signal_alloc() {
InfraredSignal* signal = malloc(sizeof(InfraredSignal));
signal->is_raw = false;
signal->payload.message.protocol = InfraredProtocolUnknown;
return signal;
}
void infrared_signal_free(InfraredSignal* signal) {
infrared_signal_clear_timings(signal);
free(signal);
}
bool infrared_signal_is_raw(InfraredSignal* signal) {
return signal->is_raw;
}
bool infrared_signal_is_valid(InfraredSignal* signal) {
return signal->is_raw ? infrared_signal_is_raw_valid(&signal->payload.raw) :
infrared_signal_is_message_valid(&signal->payload.message);
}
void infrared_signal_set_signal(InfraredSignal* signal, const InfraredSignal* other) {
if(other->is_raw) {
const InfraredRawSignal* raw = &other->payload.raw;
infrared_signal_set_raw_signal(
signal, raw->timings, raw->timings_size, raw->frequency, raw->duty_cycle);
} else {
const InfraredMessage* message = &other->payload.message;
infrared_signal_set_message(signal, message);
}
}
void infrared_signal_set_raw_signal(
InfraredSignal* signal,
const uint32_t* timings,
size_t timings_size,
uint32_t frequency,
float duty_cycle) {
infrared_signal_clear_timings(signal);
signal->is_raw = true;
signal->payload.raw.timings_size = timings_size;
signal->payload.raw.frequency = frequency;
signal->payload.raw.duty_cycle = duty_cycle;
signal->payload.raw.timings = malloc(timings_size * sizeof(uint32_t));
memcpy(signal->payload.raw.timings, timings, timings_size * sizeof(uint32_t));
}
InfraredRawSignal* infrared_signal_get_raw_signal(InfraredSignal* signal) {
furi_assert(signal->is_raw);
return &signal->payload.raw;
}
void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* message) {
infrared_signal_clear_timings(signal);
signal->is_raw = false;
signal->payload.message = *message;
}
InfraredMessage* infrared_signal_get_message(InfraredSignal* signal) {
furi_assert(!signal->is_raw);
return &signal->payload.message;
}
bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name) {
if(!flipper_format_write_comment_cstr(ff, "") ||
!flipper_format_write_string_cstr(ff, "name", name)) {
return false;
} else if(signal->is_raw) {
return infrared_signal_save_raw(&signal->payload.raw, ff);
} else {
return infrared_signal_save_message(&signal->payload.message, ff);
}
}
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name) {
FuriString* tmp = furi_string_alloc();
bool success = false;
do {
if(!flipper_format_read_string(ff, "name", tmp)) break;
furi_string_set(name, tmp);
if(!infrared_signal_read_body(signal, ff)) break;
success = true;
} while(0);
furi_string_free(tmp);
return success;
}
bool infrared_signal_search_and_read(
InfraredSignal* signal,
FlipperFormat* ff,
const FuriString* name) {
bool success = false;
FuriString* tmp = furi_string_alloc();
do {
bool is_name_found = false;
while(flipper_format_read_string(ff, "name", tmp)) {
is_name_found = furi_string_equal(name, tmp);
if(is_name_found) break;
}
if(!is_name_found) break;
if(!infrared_signal_read_body(signal, ff)) break;
success = true;
} while(false);
furi_string_free(tmp);
return success;
}
void infrared_signal_transmit(InfraredSignal* signal) {
if(signal->is_raw) {
InfraredRawSignal* raw_signal = &signal->payload.raw;
infrared_send_raw_ext(
raw_signal->timings,
raw_signal->timings_size,
true,
raw_signal->frequency,
raw_signal->duty_cycle);
} else {
InfraredMessage* message = &signal->payload.message;
infrared_send(message, 1);
}
}

View File

@@ -1,45 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <lib/infrared/encoder_decoder/infrared.h>
#include <flipper_format/flipper_format.h>
typedef struct InfraredSignal InfraredSignal;
typedef struct {
size_t timings_size;
uint32_t* timings;
uint32_t frequency;
float duty_cycle;
} InfraredRawSignal;
InfraredSignal* infrared_signal_alloc();
void infrared_signal_free(InfraredSignal* signal);
bool infrared_signal_is_raw(InfraredSignal* signal);
bool infrared_signal_is_valid(InfraredSignal* signal);
void infrared_signal_set_signal(InfraredSignal* signal, const InfraredSignal* other);
void infrared_signal_set_raw_signal(
InfraredSignal* signal,
const uint32_t* timings,
size_t timings_size,
uint32_t frequency,
float duty_cycle);
InfraredRawSignal* infrared_signal_get_raw_signal(InfraredSignal* signal);
void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* message);
InfraredMessage* infrared_signal_get_message(InfraredSignal* signal);
bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name);
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name);
bool infrared_signal_search_and_read(
InfraredSignal* signal,
FlipperFormat* ff,
const FuriString* name);
void infrared_signal_transmit(InfraredSignal* signal);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 B

View File

@@ -455,7 +455,7 @@ static void
} while(false); } while(false);
furi_string_free(remote_path); furi_string_free(remote_path);
//infrared_brute_force_reset(brute_force); infrared_brute_force_reset(brute_force);
infrared_brute_force_free(brute_force); infrared_brute_force_free(brute_force);
} }

View File

@@ -48,13 +48,18 @@ static void loader_menu_callback(void* _ctx, uint32_t index) {
furi_assert(application->app); furi_assert(application->app);
furi_assert(application->name); furi_assert(application->name);
furi_assert(application->link);
if(!loader_lock(loader_instance)) { if(strcmp(application->link, "NULL") != 0) {
FURI_LOG_E(TAG, "Loader is locked"); LoaderStatus status = loader_start(NULL, "Applications", application->link);
return; } else {
if(!loader_lock(loader_instance)) {
FURI_LOG_E(TAG, "Loader is locked");
return;
}
loader_start_application(application, NULL);
} }
loader_start_application(application, NULL);
} }
static void loader_submenu_callback(void* context, uint32_t index) { static void loader_submenu_callback(void* context, uint32_t index) {
@@ -526,4 +531,4 @@ int32_t loader_srv(void* p) {
FuriPubSub* loader_get_pubsub(Loader* instance) { FuriPubSub* loader_get_pubsub(Loader* instance) {
return instance->pubsub; return instance->pubsub;
} }

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,v,14.2,, Version,v,15.0,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,
1 entry status name type params
2 Version v 14.2 15.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h