Merge branch 'dev' into release-candidate
This commit is contained in:
commit
dc6da827fa
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -14,7 +14,7 @@ applications/gui/** @skotopes @DrZlo13
|
||||
applications/gui-test/** @skotopes @DrZlo13
|
||||
applications/ibutton/** @skotopes @DrZlo13
|
||||
applications/input/** @skotopes @DrZlo13
|
||||
applications/irda/** @skotopes @DrZlo13 @albkharisov
|
||||
applications/infrared/** @skotopes @DrZlo13
|
||||
applications/lf-rfid/** @skotopes @DrZlo13
|
||||
applications/menu/** @skotopes @DrZlo13
|
||||
applications/music-player/** @skotopes @DrZlo13
|
||||
|
||||
@ -58,7 +58,7 @@ Examples:
|
||||
|
||||
FuriHalUsb
|
||||
Gui
|
||||
SubghzKeystore
|
||||
SubGhzKeystore
|
||||
|
||||
|
||||
### Functions are snake_case
|
||||
@ -73,8 +73,8 @@ This rule makes easier to locate types, functions and sources.
|
||||
|
||||
For example:
|
||||
|
||||
We have abstraction that we call `Subghz Keystore`, so there will be:
|
||||
file `subghz_keystore.h` we have type `SubghzKeystore` and function `subghz_keystore_read`.
|
||||
We have abstraction that we call `SubGhz Keystore`, so there will be:
|
||||
file `subghz_keystore.h` we have type `SubGhzKeystore` and function `subghz_keystore_read`.
|
||||
|
||||
### File names
|
||||
|
||||
|
||||
7
Makefile
7
Makefile
@ -13,7 +13,7 @@ PROJECT_SOURCE_DIRECTORIES := \
|
||||
$(PROJECT_ROOT)/lib/cyfral \
|
||||
$(PROJECT_ROOT)/lib/drivers \
|
||||
$(PROJECT_ROOT)/lib/flipper_file \
|
||||
$(PROJECT_ROOT)/lib/irda \
|
||||
$(PROJECT_ROOT)/lib/infrared \
|
||||
$(PROJECT_ROOT)/lib/nfc_protocols \
|
||||
$(PROJECT_ROOT)/lib/ST25RFAL002 \
|
||||
$(PROJECT_ROOT)/lib/onewire \
|
||||
@ -121,3 +121,8 @@ lint:
|
||||
format:
|
||||
@echo "Reformating sources code"
|
||||
@$(PROJECT_ROOT)/scripts/lint.py format $(PROJECT_SOURCE_DIRECTORIES)
|
||||
|
||||
.PHONY: guruguru
|
||||
guruguru:
|
||||
@echo "ぐるぐる回る"
|
||||
@$(PROJECT_ROOT)/scripts/guruguru.py $(PROJECT_ROOT)
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
- `gui` - GUI service and API
|
||||
- `ibutton` - iButton application, onewire keys and more
|
||||
- `input` - Input service
|
||||
- `irda` - Irda application, controls your IR devices
|
||||
- `irda_monitor` - Irda debug tool
|
||||
- `infrared` - Infrared application, controls your IR devices
|
||||
- `infrared_monitor` - Infrared debug tool
|
||||
- `lfrfid` - LF RFID application
|
||||
- `lfrfid_debug` - LF RFID debug tool
|
||||
- `loader` - Application loader service
|
||||
@ -30,7 +30,7 @@
|
||||
- `snake_game` - Snake game application
|
||||
- `storage` - Storage service, internal + sdcard
|
||||
- `storage_settings` - Storage settings app
|
||||
- `subghz` - Subghz application, 433 fobs and etc
|
||||
- `subghz` - SubGhz application, 433 fobs and etc
|
||||
- `system` - System settings, tools and API
|
||||
- `tests` - Unit tests and etc
|
||||
- `u2f` - U2F Application
|
||||
|
||||
@ -27,8 +27,8 @@ extern int32_t delay_test_app(void* p);
|
||||
extern int32_t display_test_app(void* p);
|
||||
extern int32_t gpio_app(void* p);
|
||||
extern int32_t ibutton_app(void* p);
|
||||
extern int32_t irda_app(void* p);
|
||||
extern int32_t irda_monitor_app(void* p);
|
||||
extern int32_t infrared_app(void* p);
|
||||
extern int32_t infrared_monitor_app(void* p);
|
||||
extern int32_t keypad_test_app(void* p);
|
||||
extern int32_t lfrfid_app(void* p);
|
||||
extern int32_t lfrfid_debug_app(void* p);
|
||||
@ -51,7 +51,7 @@ extern int32_t snake_game_app(void* p);
|
||||
extern void bt_on_system_start();
|
||||
extern void crypto_on_system_start();
|
||||
extern void ibutton_on_system_start();
|
||||
extern void irda_on_system_start();
|
||||
extern void infrared_on_system_start();
|
||||
extern void lfrfid_on_system_start();
|
||||
extern void nfc_on_system_start();
|
||||
extern void storage_on_system_start();
|
||||
@ -136,8 +136,8 @@ const FlipperApplication FLIPPER_APPS[] = {
|
||||
{.app = nfc_app, .name = "NFC", .stack_size = 4096, .icon = &A_NFC_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_IRDA
|
||||
{.app = irda_app, .name = "Infrared", .stack_size = 1024 * 3, .icon = &A_Infrared_14},
|
||||
#ifdef APP_INFRARED
|
||||
{.app = infrared_app, .name = "Infrared", .stack_size = 1024 * 3, .icon = &A_Infrared_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_GPIO
|
||||
@ -164,8 +164,8 @@ const size_t FLIPPER_APPS_COUNT = sizeof(FLIPPER_APPS) / sizeof(FlipperApplicati
|
||||
const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[] = {
|
||||
crypto_on_system_start,
|
||||
|
||||
#ifdef APP_IRDA
|
||||
irda_on_system_start,
|
||||
#ifdef APP_INFRARED
|
||||
infrared_on_system_start,
|
||||
#endif
|
||||
|
||||
#ifdef APP_NFC
|
||||
@ -251,8 +251,8 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
|
||||
{.app = uart_echo_app, .name = "Uart Echo", .stack_size = 2048, .icon = NULL},
|
||||
#endif
|
||||
|
||||
#ifdef APP_IRDA_MONITOR
|
||||
{.app = irda_monitor_app, .name = "Irda Monitor", .stack_size = 1024, .icon = NULL},
|
||||
#ifdef APP_INFRARED_MONITOR
|
||||
{.app = infrared_monitor_app, .name = "Infrared Monitor", .stack_size = 1024, .icon = NULL},
|
||||
#endif
|
||||
|
||||
#ifdef APP_SCENED
|
||||
|
||||
@ -26,7 +26,7 @@ SRV_DESKTOP = 1
|
||||
APP_ARCHIVE = 1
|
||||
APP_GPIO = 1
|
||||
APP_IBUTTON = 1
|
||||
APP_IRDA = 1
|
||||
APP_INFRARED = 1
|
||||
APP_LF_RFID = 1
|
||||
APP_NFC = 1
|
||||
APP_SUBGHZ = 1
|
||||
@ -40,7 +40,7 @@ APP_SNAKE_GAME = 1
|
||||
# Debug
|
||||
APP_ACCESSOR = 1
|
||||
APP_BLINK = 1
|
||||
APP_IRDA_MONITOR = 1
|
||||
APP_INFRARED_MONITOR = 1
|
||||
APP_KEYPAD_TEST = 1
|
||||
APP_SD_TEST = 1
|
||||
APP_VIBRO_TEST = 1
|
||||
@ -59,9 +59,9 @@ endif
|
||||
# Prefix with APP_*
|
||||
|
||||
|
||||
APP_IRDA_MONITOR ?= 0
|
||||
ifeq ($(APP_IRDA_MONITOR), 1)
|
||||
CFLAGS += -DAPP_IRDA_MONITOR
|
||||
APP_INFRARED_MONITOR ?= 0
|
||||
ifeq ($(APP_INFRARED_MONITOR), 1)
|
||||
CFLAGS += -DAPP_INFRARED_MONITOR
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
@ -122,9 +122,9 @@ SRV_GUI = 1
|
||||
endif
|
||||
|
||||
|
||||
APP_IRDA ?= 0
|
||||
ifeq ($(APP_IRDA), 1)
|
||||
CFLAGS += -DAPP_IRDA
|
||||
APP_INFRARED ?= 0
|
||||
ifeq ($(APP_INFRARED), 1)
|
||||
CFLAGS += -DAPP_INFRARED
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ static const char* tab_default_paths[] = {
|
||||
[ArchiveTabNFC] = "/any/nfc",
|
||||
[ArchiveTabSubGhz] = "/any/subghz",
|
||||
[ArchiveTabLFRFID] = "/any/lfrfid",
|
||||
[ArchiveTabIrda] = "/any/irda",
|
||||
[ArchiveTabInfrared] = "/any/infrared",
|
||||
[ArchiveTabBadUsb] = "/any/badusb",
|
||||
[ArchiveTabU2f] = "/app:u2f",
|
||||
[ArchiveTabBrowser] = "/any",
|
||||
@ -21,7 +21,7 @@ static const char* known_ext[] = {
|
||||
[ArchiveFileTypeNFC] = ".nfc",
|
||||
[ArchiveFileTypeSubGhz] = ".sub",
|
||||
[ArchiveFileTypeLFRFID] = ".rfid",
|
||||
[ArchiveFileTypeIrda] = ".ir",
|
||||
[ArchiveFileTypeInfrared] = ".ir",
|
||||
[ArchiveFileTypeBadUsb] = ".txt",
|
||||
[ArchiveFileTypeU2f] = "?",
|
||||
[ArchiveFileTypeFolder] = "?",
|
||||
@ -34,7 +34,7 @@ static const ArchiveFileTypeEnum known_type[] = {
|
||||
[ArchiveTabNFC] = ArchiveFileTypeNFC,
|
||||
[ArchiveTabSubGhz] = ArchiveFileTypeSubGhz,
|
||||
[ArchiveTabLFRFID] = ArchiveFileTypeLFRFID,
|
||||
[ArchiveTabIrda] = ArchiveFileTypeIrda,
|
||||
[ArchiveTabInfrared] = ArchiveFileTypeInfrared,
|
||||
[ArchiveTabBadUsb] = ArchiveFileTypeBadUsb,
|
||||
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
||||
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
||||
|
||||
@ -8,7 +8,7 @@ typedef enum {
|
||||
ArchiveFileTypeNFC,
|
||||
ArchiveFileTypeSubGhz,
|
||||
ArchiveFileTypeLFRFID,
|
||||
ArchiveFileTypeIrda,
|
||||
ArchiveFileTypeInfrared,
|
||||
ArchiveFileTypeBadUsb,
|
||||
ArchiveFileTypeU2f,
|
||||
ArchiveFileTypeFolder,
|
||||
|
||||
@ -12,7 +12,7 @@ static const char* flipper_app_name[] = {
|
||||
[ArchiveFileTypeNFC] = "NFC",
|
||||
[ArchiveFileTypeSubGhz] = "Sub-GHz",
|
||||
[ArchiveFileTypeLFRFID] = "125 kHz RFID",
|
||||
[ArchiveFileTypeIrda] = "Infrared",
|
||||
[ArchiveFileTypeInfrared] = "Infrared",
|
||||
[ArchiveFileTypeBadUsb] = "Bad USB",
|
||||
[ArchiveFileTypeU2f] = "U2F",
|
||||
};
|
||||
|
||||
@ -9,7 +9,7 @@ static const char* ArchiveTabNames[] = {
|
||||
[ArchiveTabNFC] = "NFC",
|
||||
[ArchiveTabSubGhz] = "Sub-GHz",
|
||||
[ArchiveTabLFRFID] = "RFID LF",
|
||||
[ArchiveTabIrda] = "Infrared",
|
||||
[ArchiveTabInfrared] = "Infrared",
|
||||
[ArchiveTabBadUsb] = "Bad USB",
|
||||
[ArchiveTabU2f] = "U2F",
|
||||
[ArchiveTabBrowser] = "Browser"};
|
||||
@ -19,7 +19,7 @@ static const Icon* ArchiveItemIcons[] = {
|
||||
[ArchiveFileTypeNFC] = &I_Nfc_10px,
|
||||
[ArchiveFileTypeSubGhz] = &I_sub1_10px,
|
||||
[ArchiveFileTypeLFRFID] = &I_125_10px,
|
||||
[ArchiveFileTypeIrda] = &I_ir_10px,
|
||||
[ArchiveFileTypeInfrared] = &I_ir_10px,
|
||||
[ArchiveFileTypeBadUsb] = &I_badusb_10px,
|
||||
[ArchiveFileTypeU2f] = &I_u2f_10px,
|
||||
[ArchiveFileTypeFolder] = &I_dir_10px,
|
||||
|
||||
@ -22,7 +22,7 @@ typedef enum {
|
||||
ArchiveTabSubGhz,
|
||||
ArchiveTabLFRFID,
|
||||
ArchiveTabNFC,
|
||||
ArchiveTabIrda,
|
||||
ArchiveTabInfrared,
|
||||
ArchiveTabIButton,
|
||||
ArchiveTabBadUsb,
|
||||
ArchiveTabU2f,
|
||||
|
||||
@ -12,12 +12,15 @@
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
#define FILE_BUFFER_LEN 16
|
||||
|
||||
#define SCRIPT_STATE_ERROR (-1)
|
||||
#define SCRIPT_STATE_END (-2)
|
||||
#define SCRIPT_STATE_NEXT_LINE (-3)
|
||||
|
||||
typedef enum {
|
||||
WorkerEvtReserved = (1 << 0),
|
||||
WorkerEvtToggle = (1 << 1),
|
||||
WorkerEvtEnd = (1 << 2),
|
||||
WorkerEvtConnect = (1 << 3),
|
||||
WorkerEvtDisconnect = (1 << 4),
|
||||
WorkerEvtToggle = (1 << 0),
|
||||
WorkerEvtEnd = (1 << 1),
|
||||
WorkerEvtConnect = (1 << 2),
|
||||
WorkerEvtDisconnect = (1 << 3),
|
||||
} WorkerEvtFlags;
|
||||
|
||||
struct BadUsbScript {
|
||||
@ -138,6 +141,10 @@ static uint32_t ducky_get_command_len(const char* line) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ducky_is_line_end(const char chr) {
|
||||
return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n'));
|
||||
}
|
||||
|
||||
static void ducky_numlock_on() {
|
||||
if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
|
||||
furi_hal_hid_kb_press(KEY_NUM_LOCK);
|
||||
@ -163,7 +170,7 @@ static bool ducky_altchar(const char* charcode) {
|
||||
|
||||
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
|
||||
|
||||
while((charcode[i] != ' ') && (charcode[i] != '\n') && (charcode[i] != '\0')) {
|
||||
while(!ducky_is_line_end(charcode[i])) {
|
||||
state = ducky_numpad_press(charcode[i]);
|
||||
if(state == false) break;
|
||||
i++;
|
||||
@ -196,8 +203,11 @@ static bool ducky_altstring(const char* param) {
|
||||
static bool ducky_string(const char* param) {
|
||||
uint32_t i = 0;
|
||||
while(param[i] != '\0') {
|
||||
furi_hal_hid_kb_press(HID_ASCII_TO_KEY(param[i]));
|
||||
furi_hal_hid_kb_release(HID_ASCII_TO_KEY(param[i]));
|
||||
uint16_t keycode = HID_ASCII_TO_KEY(param[i]);
|
||||
if(keycode != KEY_NONE) {
|
||||
furi_hal_hid_kb_press(keycode);
|
||||
furi_hal_hid_kb_release(keycode);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
@ -207,8 +217,7 @@ static uint16_t ducky_get_keycode(const char* param, bool accept_chars) {
|
||||
for(uint8_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) {
|
||||
uint8_t key_cmd_len = strlen(ducky_keys[i].name);
|
||||
if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) &&
|
||||
((param[key_cmd_len] == ' ') || (param[key_cmd_len] == '\n') ||
|
||||
(param[key_cmd_len] == '\0'))) {
|
||||
(ducky_is_line_end(param[key_cmd_len]))) {
|
||||
return ducky_keys[i].keycode;
|
||||
}
|
||||
}
|
||||
@ -228,7 +237,7 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
|
||||
line_tmp = &line_tmp[i];
|
||||
break; // Skip spaces and tabs
|
||||
}
|
||||
if(i == line_len - 1) return 0; // Skip empty lines
|
||||
if(i == line_len - 1) return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
|
||||
}
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "line:%s", line_tmp);
|
||||
@ -245,25 +254,25 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
|
||||
if((state) && (delay_val > 0)) {
|
||||
return (int32_t)delay_val;
|
||||
}
|
||||
return (-1);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
} else if(
|
||||
(strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) ||
|
||||
(strncmp(line_tmp, ducky_cmd_defdelay_2, strlen(ducky_cmd_defdelay_2)) == 0)) {
|
||||
// DEFAULT_DELAY
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_get_number(line_tmp, &bad_usb->defdelay);
|
||||
return (state) ? (0) : (-1);
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
|
||||
// STRING
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_string(line_tmp);
|
||||
return (state) ? (0) : (-1);
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) {
|
||||
// ALTCHAR
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
ducky_numlock_on();
|
||||
state = ducky_altchar(line_tmp);
|
||||
return (state) ? (0) : (-1);
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else if(
|
||||
(strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) ||
|
||||
(strncmp(line_tmp, ducky_cmd_altstr_2, strlen(ducky_cmd_altstr_2)) == 0)) {
|
||||
@ -271,16 +280,16 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
ducky_numlock_on();
|
||||
state = ducky_altstring(line_tmp);
|
||||
return (state) ? (0) : (-1);
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) {
|
||||
// REPEAT
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt);
|
||||
return (state) ? (0) : (-1);
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else {
|
||||
// Special keys + modifiers
|
||||
uint16_t key = ducky_get_keycode(line_tmp, false);
|
||||
if(key == KEY_NONE) return (-1);
|
||||
if(key == KEY_NONE) return SCRIPT_STATE_ERROR;
|
||||
if((key & 0xFF00) != 0) {
|
||||
// It's a modifier key
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
@ -290,7 +299,7 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
|
||||
furi_hal_hid_kb_release(key);
|
||||
return (0);
|
||||
}
|
||||
return (-1);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
|
||||
@ -326,10 +335,12 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
|
||||
if(bad_usb->repeat_cnt > 0) {
|
||||
bad_usb->repeat_cnt--;
|
||||
delay_val = ducky_parse_line(bad_usb, bad_usb->line_prev);
|
||||
if(delay_val < 0) {
|
||||
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
|
||||
return 0;
|
||||
} else if(delay_val < 0) { // Script error
|
||||
bad_usb->st.error_line = bad_usb->st.line_cur - 1;
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur - 1);
|
||||
return (-1);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
} else {
|
||||
return (delay_val + bad_usb->defdelay);
|
||||
}
|
||||
@ -350,7 +361,7 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
|
||||
}
|
||||
|
||||
bad_usb->buf_start = 0;
|
||||
if(bad_usb->buf_len == 0) return (-2);
|
||||
if(bad_usb->buf_len == 0) return SCRIPT_STATE_END;
|
||||
}
|
||||
for(uint8_t i = bad_usb->buf_start; i < (bad_usb->buf_start + bad_usb->buf_len); i++) {
|
||||
if(bad_usb->file_buf[i] == '\n' && string_size(bad_usb->line) > 0) {
|
||||
@ -361,7 +372,7 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
|
||||
if(delay_val < 0) {
|
||||
bad_usb->st.error_line = bad_usb->st.line_cur;
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur);
|
||||
return (-1);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
} else {
|
||||
return (delay_val + bad_usb->defdelay);
|
||||
}
|
||||
@ -370,7 +381,7 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
|
||||
}
|
||||
}
|
||||
bad_usb->buf_len = 0;
|
||||
if(bad_usb->file_end) return (-2);
|
||||
if(bad_usb->file_end) return SCRIPT_STATE_END;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -479,11 +490,11 @@ static int32_t bad_usb_worker(void* context) {
|
||||
}
|
||||
bad_usb->st.state = BadUsbStateRunning;
|
||||
delay_val = ducky_script_execute_next(bad_usb, script_file);
|
||||
if(delay_val == -1) { // Script error
|
||||
if(delay_val == SCRIPT_STATE_ERROR) { // Script error
|
||||
delay_val = 0;
|
||||
worker_state = BadUsbStateScriptError;
|
||||
bad_usb->st.state = worker_state;
|
||||
} else if(delay_val == -2) { // End of script
|
||||
} else if(delay_val == SCRIPT_STATE_END) { // End of script
|
||||
delay_val = 0;
|
||||
worker_state = BadUsbStateIdle;
|
||||
bad_usb->st.state = BadUsbStateDone;
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <task_control_block.h>
|
||||
#include <time.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <loader/loader.h>
|
||||
|
||||
// Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'`
|
||||
#define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d"
|
||||
@ -146,6 +147,20 @@ void cli_command_vibro(Cli* cli, string_t args, void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
void cli_command_debug(Cli* cli, string_t args, void* context) {
|
||||
if(!string_cmp(args, "0")) {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
|
||||
loader_update_menu();
|
||||
printf("Debug disabled.");
|
||||
} else if(!string_cmp(args, "1")) {
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagDebug);
|
||||
loader_update_menu();
|
||||
printf("Debug enabled.");
|
||||
} else {
|
||||
cli_print_usage("debug", "<1|0>", string_get_cstr(args));
|
||||
}
|
||||
}
|
||||
|
||||
void cli_command_led(Cli* cli, string_t args, void* context) {
|
||||
// Get first word as light name
|
||||
NotificationMessage notification_led_message;
|
||||
@ -348,6 +363,7 @@ void cli_commands_init(Cli* cli) {
|
||||
|
||||
cli_add_command(cli, "date", CliCommandFlagParallelSafe, cli_command_date, NULL);
|
||||
cli_add_command(cli, "log", CliCommandFlagParallelSafe, cli_command_log, NULL);
|
||||
cli_add_command(cli, "debug", CliCommandFlagDefault, cli_command_debug, NULL);
|
||||
cli_add_command(cli, "ps", CliCommandFlagParallelSafe, cli_command_ps, NULL);
|
||||
cli_add_command(cli, "free", CliCommandFlagParallelSafe, cli_command_free, NULL);
|
||||
cli_add_command(cli, "free_blocks", CliCommandFlagParallelSafe, cli_command_free_blocks, NULL);
|
||||
|
||||
@ -211,12 +211,11 @@ void gui_redraw(Gui* gui) {
|
||||
}
|
||||
|
||||
canvas_commit(gui->canvas);
|
||||
if(gui->canvas_callback) {
|
||||
gui->canvas_callback(
|
||||
canvas_get_buffer(gui->canvas),
|
||||
canvas_get_buffer_size(gui->canvas),
|
||||
gui->canvas_callback_context);
|
||||
}
|
||||
for
|
||||
M_EACH(p, gui->canvas_callback_pair, CanvasCallbackPairArray_t) {
|
||||
p->callback(
|
||||
canvas_get_buffer(gui->canvas), canvas_get_buffer_size(gui->canvas), p->context);
|
||||
}
|
||||
gui_unlock(gui);
|
||||
}
|
||||
|
||||
@ -396,16 +395,36 @@ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) {
|
||||
gui_unlock(gui);
|
||||
}
|
||||
|
||||
void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) {
|
||||
void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) {
|
||||
furi_assert(gui);
|
||||
gui_lock(gui);
|
||||
gui->canvas_callback = callback;
|
||||
gui->canvas_callback_context = context;
|
||||
gui_unlock(gui);
|
||||
|
||||
if(callback != NULL) {
|
||||
gui_update(gui);
|
||||
}
|
||||
const CanvasCallbackPair p = {callback, context};
|
||||
|
||||
gui_lock(gui);
|
||||
|
||||
furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 0);
|
||||
CanvasCallbackPairArray_push_back(gui->canvas_callback_pair, p);
|
||||
|
||||
gui_unlock(gui);
|
||||
gui_update(gui);
|
||||
}
|
||||
|
||||
void gui_remove_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) {
|
||||
furi_assert(gui);
|
||||
|
||||
const CanvasCallbackPair p = {callback, context};
|
||||
|
||||
gui_lock(gui);
|
||||
|
||||
furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 1);
|
||||
CanvasCallbackPairArray_remove_val(gui->canvas_callback_pair, p);
|
||||
|
||||
gui_unlock(gui);
|
||||
}
|
||||
|
||||
size_t gui_get_framebuffer_size(Gui* gui) {
|
||||
furi_assert(gui);
|
||||
return canvas_get_buffer_size(gui->canvas);
|
||||
}
|
||||
|
||||
void gui_set_lockdown(Gui* gui, bool lockdown) {
|
||||
@ -429,9 +448,12 @@ Gui* gui_alloc() {
|
||||
}
|
||||
// Drawing canvas
|
||||
gui->canvas = canvas_init();
|
||||
CanvasCallbackPairArray_init(gui->canvas_callback_pair);
|
||||
|
||||
// Input
|
||||
gui->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL);
|
||||
gui->input_events = furi_record_open("input_events");
|
||||
|
||||
furi_check(gui->input_events);
|
||||
furi_pubsub_subscribe(gui->input_events, gui_input_events_callback, gui);
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port);
|
||||
*/
|
||||
void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port);
|
||||
|
||||
/** Set gui canvas commit callback
|
||||
/** Add gui canvas commit callback
|
||||
*
|
||||
* This callback will be called upon Canvas commit Callback dispatched from GUI
|
||||
* thread and is time critical
|
||||
@ -77,7 +77,22 @@ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port);
|
||||
* @param callback GuiCanvasCommitCallback
|
||||
* @param context GuiCanvasCommitCallback context
|
||||
*/
|
||||
void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context);
|
||||
void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context);
|
||||
|
||||
/** Remove gui canvas commit callback
|
||||
*
|
||||
* @param gui Gui instance
|
||||
* @param callback GuiCanvasCommitCallback
|
||||
* @param context GuiCanvasCommitCallback context
|
||||
*/
|
||||
void gui_remove_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context);
|
||||
|
||||
/** Get gui canvas frame buffer size
|
||||
* *
|
||||
* @param gui Gui instance
|
||||
* @return size_t size of frame buffer in bytes
|
||||
*/
|
||||
size_t gui_get_framebuffer_size(Gui* gui);
|
||||
|
||||
/** Set lockdown mode
|
||||
*
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
#include <furi.h>
|
||||
#include <m-array.h>
|
||||
#include <m-algo.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "canvas.h"
|
||||
@ -42,6 +43,17 @@
|
||||
|
||||
ARRAY_DEF(ViewPortArray, ViewPort*, M_PTR_OPLIST);
|
||||
|
||||
typedef struct {
|
||||
GuiCanvasCommitCallback callback;
|
||||
void* context;
|
||||
} CanvasCallbackPair;
|
||||
|
||||
ARRAY_DEF(CanvasCallbackPairArray, CanvasCallbackPair, M_POD_OPLIST);
|
||||
|
||||
#define M_OPL_CanvasCallbackPairArray_t() ARRAY_OPLIST(CanvasCallbackPairArray, M_POD_OPLIST)
|
||||
|
||||
ALGO_DEF(CanvasCallbackPairArray, CanvasCallbackPairArray_t);
|
||||
|
||||
/** Gui structure */
|
||||
struct Gui {
|
||||
// Thread and lock
|
||||
@ -52,8 +64,7 @@ struct Gui {
|
||||
bool lockdown;
|
||||
ViewPortArray_t layers[GuiLayerMAX];
|
||||
Canvas* canvas;
|
||||
GuiCanvasCommitCallback canvas_callback;
|
||||
void* canvas_callback_context;
|
||||
CanvasCallbackPairArray_t canvas_callback_pair;
|
||||
|
||||
// Input
|
||||
osMessageQueueId_t input_queue;
|
||||
|
||||
@ -108,11 +108,11 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
ButtonMenuItemArray_it_t it;
|
||||
|
||||
if(active_screen > 0) {
|
||||
canvas_draw_icon(canvas, 28, 1, &I_IrdaArrowUp_4x8);
|
||||
canvas_draw_icon(canvas, 28, 1, &I_InfraredArrowUp_4x8);
|
||||
}
|
||||
|
||||
if(max_screen > active_screen) {
|
||||
canvas_draw_icon(canvas, 28, 123, &I_IrdaArrowDown_4x8);
|
||||
canvas_draw_icon(canvas, 28, 123, &I_InfraredArrowDown_4x8);
|
||||
}
|
||||
|
||||
if(model->header) {
|
||||
|
||||
@ -1,52 +1,52 @@
|
||||
#include <furi_hal_delay.h>
|
||||
#include <irda.h>
|
||||
#include <infrared.h>
|
||||
#include <app_template.h>
|
||||
#include <cli/cli.h>
|
||||
#include <cmsis_os2.h>
|
||||
#include <irda_worker.h>
|
||||
#include <infrared_worker.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal_irda.h>
|
||||
#include <furi_hal_infrared.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <m-string.h>
|
||||
#include <irda_transmit.h>
|
||||
#include <infrared_transmit.h>
|
||||
#include <sys/types.h>
|
||||
#include "../helpers/irda_parser.h"
|
||||
#include "../helpers/infrared_parser.h"
|
||||
|
||||
static void irda_cli_start_ir_rx(Cli* cli, string_t args);
|
||||
static void irda_cli_start_ir_tx(Cli* cli, string_t args);
|
||||
static void infrared_cli_start_ir_rx(Cli* cli, string_t args);
|
||||
static void infrared_cli_start_ir_tx(Cli* cli, string_t args);
|
||||
|
||||
static const struct {
|
||||
const char* cmd;
|
||||
void (*process_function)(Cli* cli, string_t args);
|
||||
} irda_cli_commands[] = {
|
||||
{.cmd = "rx", .process_function = irda_cli_start_ir_rx},
|
||||
{.cmd = "tx", .process_function = irda_cli_start_ir_tx},
|
||||
} infrared_cli_commands[] = {
|
||||
{.cmd = "rx", .process_function = infrared_cli_start_ir_rx},
|
||||
{.cmd = "tx", .process_function = infrared_cli_start_ir_tx},
|
||||
};
|
||||
|
||||
static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) {
|
||||
static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) {
|
||||
furi_assert(received_signal);
|
||||
char buf[100];
|
||||
size_t buf_cnt;
|
||||
Cli* cli = (Cli*)context;
|
||||
|
||||
if(irda_worker_signal_is_decoded(received_signal)) {
|
||||
const IrdaMessage* message = irda_worker_get_decoded_signal(received_signal);
|
||||
if(infrared_worker_signal_is_decoded(received_signal)) {
|
||||
const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal);
|
||||
buf_cnt = sniprintf(
|
||||
buf,
|
||||
sizeof(buf),
|
||||
"%s, A:0x%0*lX, C:0x%0*lX%s\r\n",
|
||||
irda_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4),
|
||||
infrared_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4),
|
||||
message->address,
|
||||
ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4),
|
||||
ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4),
|
||||
message->command,
|
||||
message->repeat ? " R" : "");
|
||||
cli_write(cli, (uint8_t*)buf, buf_cnt);
|
||||
} else {
|
||||
const uint32_t* timings;
|
||||
size_t timings_cnt;
|
||||
irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||
infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||
|
||||
buf_cnt = sniprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt);
|
||||
cli_write(cli, (uint8_t*)buf, buf_cnt);
|
||||
@ -59,39 +59,39 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s
|
||||
}
|
||||
}
|
||||
|
||||
static void irda_cli_start_ir_rx(Cli* cli, string_t args) {
|
||||
IrdaWorker* worker = irda_worker_alloc();
|
||||
irda_worker_rx_start(worker);
|
||||
irda_worker_rx_set_received_signal_callback(worker, signal_received_callback, cli);
|
||||
static void infrared_cli_start_ir_rx(Cli* cli, string_t args) {
|
||||
InfraredWorker* worker = infrared_worker_alloc();
|
||||
infrared_worker_rx_start(worker);
|
||||
infrared_worker_rx_set_received_signal_callback(worker, signal_received_callback, cli);
|
||||
|
||||
printf("Receiving IRDA...\r\nPress Ctrl+C to abort\r\n");
|
||||
printf("Receiving INFRARED...\r\nPress Ctrl+C to abort\r\n");
|
||||
while(!cli_cmd_interrupt_received(cli)) {
|
||||
delay(50);
|
||||
}
|
||||
|
||||
irda_worker_rx_stop(worker);
|
||||
irda_worker_free(worker);
|
||||
infrared_worker_rx_stop(worker);
|
||||
infrared_worker_free(worker);
|
||||
}
|
||||
|
||||
static void irda_cli_print_usage(void) {
|
||||
static void infrared_cli_print_usage(void) {
|
||||
printf("Usage:\r\n");
|
||||
printf("\tir rx\r\n");
|
||||
printf("\tir tx <protocol> <address> <command>\r\n");
|
||||
printf("\t<command> and <address> are hex-formatted\r\n");
|
||||
printf("\tAvailable protocols:");
|
||||
for(int i = 0; irda_is_protocol_valid((IrdaProtocol)i); ++i) {
|
||||
printf(" %s", irda_get_protocol_name((IrdaProtocol)i));
|
||||
for(int i = 0; infrared_is_protocol_valid((InfraredProtocol)i); ++i) {
|
||||
printf(" %s", infrared_get_protocol_name((InfraredProtocol)i));
|
||||
}
|
||||
printf("\r\n");
|
||||
printf("\tRaw format:\r\n");
|
||||
printf("\tir_tx RAW F:<frequency> DC:<duty_cycle> <sample0> <sample1>...\r\n");
|
||||
printf(
|
||||
"\tFrequency (%d - %d), Duty cycle (0 - 100), max 512 samples\r\n",
|
||||
IRDA_MIN_FREQUENCY,
|
||||
IRDA_MAX_FREQUENCY);
|
||||
INFRARED_MIN_FREQUENCY,
|
||||
INFRARED_MAX_FREQUENCY);
|
||||
}
|
||||
|
||||
static bool parse_message(const char* str, IrdaMessage* message) {
|
||||
static bool parse_message(const char* str, InfraredMessage* message) {
|
||||
char protocol_name[32];
|
||||
int parsed = sscanf(str, "%31s %lX %lX", protocol_name, &message->address, &message->command);
|
||||
|
||||
@ -99,10 +99,10 @@ static bool parse_message(const char* str, IrdaMessage* message) {
|
||||
return false;
|
||||
}
|
||||
|
||||
message->protocol = irda_get_protocol_by_name(protocol_name);
|
||||
message->protocol = infrared_get_protocol_by_name(protocol_name);
|
||||
message->repeat = false;
|
||||
|
||||
return irda_parser_is_parsed_signal_valid(message);
|
||||
return infrared_parser_is_parsed_signal_valid(message);
|
||||
}
|
||||
|
||||
static bool parse_signal_raw(
|
||||
@ -136,11 +136,11 @@ static bool parse_signal_raw(
|
||||
++*timings_cnt;
|
||||
}
|
||||
|
||||
return irda_parser_is_raw_signal_valid(*frequency, *duty_cycle, *timings_cnt);
|
||||
return infrared_parser_is_raw_signal_valid(*frequency, *duty_cycle, *timings_cnt);
|
||||
}
|
||||
|
||||
static void irda_cli_start_ir_tx(Cli* cli, string_t args) {
|
||||
IrdaMessage message;
|
||||
static void infrared_cli_start_ir_tx(Cli* cli, string_t args) {
|
||||
InfraredMessage message;
|
||||
const char* str = string_get_cstr(args);
|
||||
uint32_t frequency;
|
||||
float duty_cycle;
|
||||
@ -148,27 +148,27 @@ static void irda_cli_start_ir_tx(Cli* cli, string_t args) {
|
||||
uint32_t* timings = (uint32_t*)malloc(sizeof(uint32_t) * timings_cnt);
|
||||
|
||||
if(parse_message(str, &message)) {
|
||||
irda_send(&message, 1);
|
||||
infrared_send(&message, 1);
|
||||
} else if(parse_signal_raw(str, timings, &timings_cnt, &duty_cycle, &frequency)) {
|
||||
irda_send_raw_ext(timings, timings_cnt, true, frequency, duty_cycle);
|
||||
infrared_send_raw_ext(timings, timings_cnt, true, frequency, duty_cycle);
|
||||
} else {
|
||||
printf("Wrong arguments.\r\n");
|
||||
irda_cli_print_usage();
|
||||
infrared_cli_print_usage();
|
||||
}
|
||||
|
||||
free(timings);
|
||||
}
|
||||
|
||||
static void irda_cli_start_ir(Cli* cli, string_t args, void* context) {
|
||||
if(furi_hal_irda_is_busy()) {
|
||||
printf("IRDA is busy. Exit.");
|
||||
static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) {
|
||||
if(furi_hal_infrared_is_busy()) {
|
||||
printf("INFRARED is busy. Exit.");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for(; i < COUNT_OF(irda_cli_commands); ++i) {
|
||||
size_t size = strlen(irda_cli_commands[i].cmd);
|
||||
bool cmd_found = !strncmp(string_get_cstr(args), irda_cli_commands[i].cmd, size);
|
||||
for(; i < COUNT_OF(infrared_cli_commands); ++i) {
|
||||
size_t size = strlen(infrared_cli_commands[i].cmd);
|
||||
bool cmd_found = !strncmp(string_get_cstr(args), infrared_cli_commands[i].cmd, size);
|
||||
if(cmd_found) {
|
||||
if(string_size(args) == size) {
|
||||
break;
|
||||
@ -180,17 +180,17 @@ static void irda_cli_start_ir(Cli* cli, string_t args, void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
if(i < COUNT_OF(irda_cli_commands)) {
|
||||
irda_cli_commands[i].process_function(cli, args);
|
||||
if(i < COUNT_OF(infrared_cli_commands)) {
|
||||
infrared_cli_commands[i].process_function(cli, args);
|
||||
} else {
|
||||
irda_cli_print_usage();
|
||||
infrared_cli_print_usage();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void irda_on_system_start() {
|
||||
extern "C" void infrared_on_system_start() {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = (Cli*)furi_record_open("cli");
|
||||
cli_add_command(cli, "ir", CliCommandFlagDefault, irda_cli_start_ir, NULL);
|
||||
cli_add_command(cli, "ir", CliCommandFlagDefault, infrared_cli_start_ir, NULL);
|
||||
furi_record_close("cli");
|
||||
#endif
|
||||
}
|
||||
@ -1,19 +1,19 @@
|
||||
|
||||
#include "../irda_app_signal.h"
|
||||
#include "irda.h"
|
||||
#include "irda/helpers/irda_parser.h"
|
||||
#include "irda_worker.h"
|
||||
#include "../infrared_app_signal.h"
|
||||
#include "infrared.h"
|
||||
#include "infrared/helpers/infrared_parser.h"
|
||||
#include "infrared_worker.h"
|
||||
#include "m-string.h"
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <furi_hal_irda.h>
|
||||
#include <furi_hal_infrared.h>
|
||||
|
||||
#define TAG "IrdaParser"
|
||||
#define TAG "InfraredParser"
|
||||
|
||||
bool irda_parser_save_signal(
|
||||
bool infrared_parser_save_signal(
|
||||
FlipperFormat* ff,
|
||||
const IrdaAppSignal& signal,
|
||||
const InfraredAppSignal& signal,
|
||||
const std::string& name) {
|
||||
furi_assert(ff);
|
||||
furi_assert(!name.empty());
|
||||
@ -33,7 +33,7 @@ bool irda_parser_save_signal(
|
||||
break;
|
||||
} else {
|
||||
auto parsed_signal = signal.get_message();
|
||||
const char* protocol_name = irda_get_protocol_name(parsed_signal.protocol);
|
||||
const char* protocol_name = infrared_get_protocol_name(parsed_signal.protocol);
|
||||
if(!flipper_format_write_string_cstr(ff, "type", "parsed")) break;
|
||||
if(!flipper_format_write_string_cstr(ff, "protocol", protocol_name)) break;
|
||||
if(!flipper_format_write_hex(ff, "address", (uint8_t*)&parsed_signal.address, 4))
|
||||
@ -47,7 +47,7 @@ bool irda_parser_save_signal(
|
||||
return result;
|
||||
}
|
||||
|
||||
bool irda_parser_read_signal(FlipperFormat* ff, IrdaAppSignal& signal, std::string& name) {
|
||||
bool infrared_parser_read_signal(FlipperFormat* ff, InfraredAppSignal& signal, std::string& name) {
|
||||
furi_assert(ff);
|
||||
|
||||
bool result = false;
|
||||
@ -75,12 +75,12 @@ bool irda_parser_read_signal(FlipperFormat* ff, IrdaAppSignal& signal, std::stri
|
||||
}
|
||||
free(timings);
|
||||
} else if(!string_cmp_str(read_string, "parsed")) {
|
||||
IrdaMessage parsed_signal;
|
||||
InfraredMessage parsed_signal;
|
||||
if(!flipper_format_read_string(ff, "protocol", read_string)) break;
|
||||
parsed_signal.protocol = irda_get_protocol_by_name(string_get_cstr(read_string));
|
||||
parsed_signal.protocol = infrared_get_protocol_by_name(string_get_cstr(read_string));
|
||||
if(!flipper_format_read_hex(ff, "address", (uint8_t*)&parsed_signal.address, 4)) break;
|
||||
if(!flipper_format_read_hex(ff, "command", (uint8_t*)&parsed_signal.command, 4)) break;
|
||||
if(!irda_parser_is_parsed_signal_valid(&parsed_signal)) break;
|
||||
if(!infrared_parser_is_parsed_signal_valid(&parsed_signal)) break;
|
||||
signal.set_message(&parsed_signal);
|
||||
result = true;
|
||||
} else {
|
||||
@ -92,17 +92,17 @@ bool irda_parser_read_signal(FlipperFormat* ff, IrdaAppSignal& signal, std::stri
|
||||
return result;
|
||||
}
|
||||
|
||||
bool irda_parser_is_parsed_signal_valid(const IrdaMessage* signal) {
|
||||
bool infrared_parser_is_parsed_signal_valid(const InfraredMessage* signal) {
|
||||
furi_assert(signal);
|
||||
bool result = true;
|
||||
|
||||
if(!irda_is_protocol_valid(signal->protocol)) {
|
||||
if(!infrared_is_protocol_valid(signal->protocol)) {
|
||||
FURI_LOG_E(TAG, "Unknown protocol");
|
||||
result = false;
|
||||
}
|
||||
|
||||
if(result) {
|
||||
uint32_t address_length = irda_get_protocol_address_length(signal->protocol);
|
||||
uint32_t address_length = infrared_get_protocol_address_length(signal->protocol);
|
||||
uint32_t address_mask = (1LU << address_length) - 1;
|
||||
if(signal->address != (signal->address & address_mask)) {
|
||||
FURI_LOG_E(
|
||||
@ -115,7 +115,7 @@ bool irda_parser_is_parsed_signal_valid(const IrdaMessage* signal) {
|
||||
}
|
||||
|
||||
if(result) {
|
||||
uint32_t command_length = irda_get_protocol_command_length(signal->protocol);
|
||||
uint32_t command_length = infrared_get_protocol_command_length(signal->protocol);
|
||||
uint32_t command_mask = (1LU << command_length) - 1;
|
||||
if(signal->command != (signal->command & command_mask)) {
|
||||
FURI_LOG_E(
|
||||
@ -130,15 +130,18 @@ bool irda_parser_is_parsed_signal_valid(const IrdaMessage* signal) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool irda_parser_is_raw_signal_valid(uint32_t frequency, float duty_cycle, uint32_t timings_cnt) {
|
||||
bool infrared_parser_is_raw_signal_valid(
|
||||
uint32_t frequency,
|
||||
float duty_cycle,
|
||||
uint32_t timings_cnt) {
|
||||
bool result = true;
|
||||
|
||||
if((frequency > IRDA_MAX_FREQUENCY) || (frequency < IRDA_MIN_FREQUENCY)) {
|
||||
if((frequency > INFRARED_MAX_FREQUENCY) || (frequency < INFRARED_MIN_FREQUENCY)) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"Frequency is out of range (%lX - %lX): %lX",
|
||||
IRDA_MIN_FREQUENCY,
|
||||
IRDA_MAX_FREQUENCY,
|
||||
INFRARED_MIN_FREQUENCY,
|
||||
INFRARED_MAX_FREQUENCY,
|
||||
frequency);
|
||||
result = false;
|
||||
} else if((duty_cycle <= 0) || (duty_cycle > 1)) {
|
||||
48
applications/infrared/helpers/infrared_parser.h
Normal file
48
applications/infrared/helpers/infrared_parser.h
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file infrared_parser.h
|
||||
* Infrared: Helper file for conversion Flipper File Format
|
||||
* to Infrared signal class, and backwards
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../infrared_app_signal.h"
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <string>
|
||||
|
||||
/** Save Infrared signal into file
|
||||
*
|
||||
* @param ff - Flipper File Format instance
|
||||
* @param signal - Infrared signal to save
|
||||
* @param name - name for saved signal. Every
|
||||
* signal on disk has name.
|
||||
*/
|
||||
bool infrared_parser_save_signal(
|
||||
FlipperFormat* ff,
|
||||
const InfraredAppSignal& signal,
|
||||
const std::string& name);
|
||||
|
||||
/** Read Infrared signal from file
|
||||
*
|
||||
* @param ff - Flipper File Format instance
|
||||
* @param signal - Infrared signal to read to
|
||||
* @param name - name for saved signal. Every
|
||||
* signal in file has name.
|
||||
*/
|
||||
bool infrared_parser_read_signal(FlipperFormat* ff, InfraredAppSignal& signal, std::string& name);
|
||||
|
||||
/** Validate parsed signal
|
||||
*
|
||||
* @signal - signal to validate
|
||||
* @retval true if valid, false otherwise
|
||||
*/
|
||||
bool infrared_parser_is_parsed_signal_valid(const InfraredMessage* signal);
|
||||
|
||||
/** Validate raw signal
|
||||
*
|
||||
* @signal - signal to validate
|
||||
* @retval true if valid, false otherwise
|
||||
*/
|
||||
bool infrared_parser_is_raw_signal_valid(
|
||||
uint32_t frequency,
|
||||
float duty_cycle,
|
||||
uint32_t timings_cnt);
|
||||
@ -1,13 +1,13 @@
|
||||
#include "irda_app.h"
|
||||
#include <irda_worker.h>
|
||||
#include "infrared_app.h"
|
||||
#include <infrared_worker.h>
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdio.h>
|
||||
#include <callback-connector.h>
|
||||
|
||||
int32_t IrdaApp::run(void* args) {
|
||||
IrdaAppEvent event;
|
||||
int32_t InfraredApp::run(void* args) {
|
||||
InfraredAppEvent event;
|
||||
bool consumed;
|
||||
bool exit = false;
|
||||
|
||||
@ -17,7 +17,7 @@ int32_t IrdaApp::run(void* args) {
|
||||
remote_name.erase(remote_name.find_last_of('.'));
|
||||
bool result = remote_manager.load(remote_name);
|
||||
if(result) {
|
||||
current_scene = IrdaApp::Scene::Remote;
|
||||
current_scene = InfraredApp::Scene::Remote;
|
||||
} else {
|
||||
printf("Failed to load remote \'%s\'\r\n", remote_name.c_str());
|
||||
return -1;
|
||||
@ -29,12 +29,12 @@ int32_t IrdaApp::run(void* args) {
|
||||
while(!exit) {
|
||||
view_manager.receive_event(&event);
|
||||
|
||||
if(event.type == IrdaAppEvent::Type::Exit) break;
|
||||
if(event.type == InfraredAppEvent::Type::Exit) break;
|
||||
|
||||
consumed = scenes[current_scene]->on_event(this, &event);
|
||||
|
||||
if(!consumed) {
|
||||
if(event.type == IrdaAppEvent::Type::Back) {
|
||||
if(event.type == InfraredAppEvent::Type::Back) {
|
||||
exit = switch_to_previous_scene();
|
||||
}
|
||||
}
|
||||
@ -45,36 +45,36 @@ int32_t IrdaApp::run(void* args) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
IrdaApp::IrdaApp() {
|
||||
furi_check(IrdaAppRemoteManager::max_button_name_length < get_text_store_size());
|
||||
InfraredApp::InfraredApp() {
|
||||
furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size());
|
||||
notification = static_cast<NotificationApp*>(furi_record_open("notification"));
|
||||
irda_worker = irda_worker_alloc();
|
||||
infrared_worker = infrared_worker_alloc();
|
||||
}
|
||||
|
||||
IrdaApp::~IrdaApp() {
|
||||
irda_worker_free(irda_worker);
|
||||
InfraredApp::~InfraredApp() {
|
||||
infrared_worker_free(infrared_worker);
|
||||
furi_record_close("notification");
|
||||
for(auto& [key, scene] : scenes) delete scene;
|
||||
}
|
||||
|
||||
IrdaAppViewManager* IrdaApp::get_view_manager() {
|
||||
InfraredAppViewManager* InfraredApp::get_view_manager() {
|
||||
return &view_manager;
|
||||
}
|
||||
|
||||
void IrdaApp::set_learn_new_remote(bool value) {
|
||||
void InfraredApp::set_learn_new_remote(bool value) {
|
||||
learn_new_remote = value;
|
||||
}
|
||||
|
||||
bool IrdaApp::get_learn_new_remote() {
|
||||
bool InfraredApp::get_learn_new_remote() {
|
||||
return learn_new_remote;
|
||||
}
|
||||
|
||||
void IrdaApp::switch_to_next_scene(Scene next_scene) {
|
||||
void InfraredApp::switch_to_next_scene(Scene next_scene) {
|
||||
previous_scenes_list.push_front(current_scene);
|
||||
switch_to_next_scene_without_saving(next_scene);
|
||||
}
|
||||
|
||||
void IrdaApp::switch_to_next_scene_without_saving(Scene next_scene) {
|
||||
void InfraredApp::switch_to_next_scene_without_saving(Scene next_scene) {
|
||||
if(next_scene != Scene::Exit) {
|
||||
scenes[current_scene]->on_exit(this);
|
||||
current_scene = next_scene;
|
||||
@ -83,7 +83,8 @@ void IrdaApp::switch_to_next_scene_without_saving(Scene next_scene) {
|
||||
}
|
||||
}
|
||||
|
||||
void IrdaApp::search_and_switch_to_previous_scene(const std::initializer_list<Scene>& scenes_list) {
|
||||
void InfraredApp::search_and_switch_to_previous_scene(
|
||||
const std::initializer_list<Scene>& scenes_list) {
|
||||
Scene previous_scene = Scene::Start;
|
||||
bool scene_found = false;
|
||||
|
||||
@ -101,8 +102,8 @@ void IrdaApp::search_and_switch_to_previous_scene(const std::initializer_list<Sc
|
||||
}
|
||||
|
||||
if(previous_scene == Scene::Exit) {
|
||||
IrdaAppEvent event;
|
||||
event.type = IrdaAppEvent::Type::Exit;
|
||||
InfraredAppEvent event;
|
||||
event.type = InfraredAppEvent::Type::Exit;
|
||||
view_manager.send_event(&event);
|
||||
} else {
|
||||
scenes[current_scene]->on_exit(this);
|
||||
@ -112,7 +113,7 @@ void IrdaApp::search_and_switch_to_previous_scene(const std::initializer_list<Sc
|
||||
}
|
||||
}
|
||||
|
||||
bool IrdaApp::switch_to_previous_scene(uint8_t count) {
|
||||
bool InfraredApp::switch_to_previous_scene(uint8_t count) {
|
||||
Scene previous_scene = Scene::Start;
|
||||
|
||||
for(uint8_t i = 0; i < count; i++) previous_scene = get_previous_scene();
|
||||
@ -126,7 +127,7 @@ bool IrdaApp::switch_to_previous_scene(uint8_t count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IrdaApp::Scene IrdaApp::get_previous_scene() {
|
||||
InfraredApp::Scene InfraredApp::get_previous_scene() {
|
||||
Scene scene = Scene::Exit;
|
||||
|
||||
if(!previous_scenes_list.empty()) {
|
||||
@ -137,11 +138,11 @@ IrdaApp::Scene IrdaApp::get_previous_scene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
IrdaAppRemoteManager* IrdaApp::get_remote_manager() {
|
||||
InfraredAppRemoteManager* InfraredApp::get_remote_manager() {
|
||||
return &remote_manager;
|
||||
}
|
||||
|
||||
void IrdaApp::set_text_store(uint8_t index, const char* text...) {
|
||||
void InfraredApp::set_text_store(uint8_t index, const char* text...) {
|
||||
furi_check(index < text_store_max);
|
||||
|
||||
va_list args;
|
||||
@ -152,77 +153,63 @@ void IrdaApp::set_text_store(uint8_t index, const char* text...) {
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
char* IrdaApp::get_text_store(uint8_t index) {
|
||||
char* InfraredApp::get_text_store(uint8_t index) {
|
||||
furi_check(index < text_store_max);
|
||||
|
||||
return text_store[index];
|
||||
}
|
||||
|
||||
uint8_t IrdaApp::get_text_store_size() {
|
||||
uint8_t InfraredApp::get_text_store_size() {
|
||||
return text_store_size;
|
||||
}
|
||||
|
||||
void IrdaApp::text_input_callback(void* context) {
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
event.type = IrdaAppEvent::Type::TextEditDone;
|
||||
void InfraredApp::text_input_callback(void* context) {
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
event.type = InfraredAppEvent::Type::TextEditDone;
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaApp::popup_callback(void* context) {
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
event.type = IrdaAppEvent::Type::PopupTimer;
|
||||
void InfraredApp::popup_callback(void* context) {
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
event.type = InfraredAppEvent::Type::PopupTimer;
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaApp::set_edit_element(IrdaApp::EditElement value) {
|
||||
void InfraredApp::set_edit_element(InfraredApp::EditElement value) {
|
||||
element = value;
|
||||
}
|
||||
|
||||
IrdaApp::EditElement IrdaApp::get_edit_element(void) {
|
||||
InfraredApp::EditElement InfraredApp::get_edit_element(void) {
|
||||
return element;
|
||||
}
|
||||
|
||||
void IrdaApp::set_edit_action(IrdaApp::EditAction value) {
|
||||
void InfraredApp::set_edit_action(InfraredApp::EditAction value) {
|
||||
action = value;
|
||||
}
|
||||
|
||||
IrdaApp::EditAction IrdaApp::get_edit_action(void) {
|
||||
InfraredApp::EditAction InfraredApp::get_edit_action(void) {
|
||||
return action;
|
||||
}
|
||||
|
||||
void IrdaApp::set_current_button(int value) {
|
||||
void InfraredApp::set_current_button(int value) {
|
||||
current_button = value;
|
||||
}
|
||||
|
||||
int IrdaApp::get_current_button() {
|
||||
int InfraredApp::get_current_button() {
|
||||
return current_button;
|
||||
}
|
||||
|
||||
void IrdaApp::notify_success() {
|
||||
void InfraredApp::notify_success() {
|
||||
notification_message(notification, &sequence_success);
|
||||
}
|
||||
|
||||
void IrdaApp::notify_red_blink() {
|
||||
void InfraredApp::notify_red_blink() {
|
||||
notification_message(notification, &sequence_blink_red_10);
|
||||
}
|
||||
|
||||
void IrdaApp::notify_sent_just_learnt() {
|
||||
static const NotificationSequence sequence = {
|
||||
&message_green_0,
|
||||
&message_vibro_on,
|
||||
&message_delay_50,
|
||||
&message_vibro_off,
|
||||
&message_green_255,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
notification_message_block(notification, &sequence);
|
||||
}
|
||||
|
||||
void IrdaApp::notify_click() {
|
||||
void InfraredApp::notify_click() {
|
||||
static const NotificationSequence sequence = {
|
||||
&message_click,
|
||||
&message_delay_1,
|
||||
@ -233,7 +220,7 @@ void IrdaApp::notify_click() {
|
||||
notification_message_block(notification, &sequence);
|
||||
}
|
||||
|
||||
void IrdaApp::notify_click_and_green_blink() {
|
||||
void InfraredApp::notify_click_and_green_blink() {
|
||||
static const NotificationSequence sequence = {
|
||||
&message_click,
|
||||
&message_delay_1,
|
||||
@ -248,7 +235,7 @@ void IrdaApp::notify_click_and_green_blink() {
|
||||
notification_message_block(notification, &sequence);
|
||||
}
|
||||
|
||||
void IrdaApp::notify_blink_green() {
|
||||
void InfraredApp::notify_blink_green() {
|
||||
static const NotificationSequence sequence = {
|
||||
&message_green_255,
|
||||
&message_delay_10,
|
||||
@ -260,27 +247,27 @@ void IrdaApp::notify_blink_green() {
|
||||
notification_message(notification, &sequence);
|
||||
}
|
||||
|
||||
void IrdaApp::notify_green_on() {
|
||||
void InfraredApp::notify_green_on() {
|
||||
notification_message(notification, &sequence_set_only_green_255);
|
||||
}
|
||||
|
||||
void IrdaApp::notify_green_off() {
|
||||
void InfraredApp::notify_green_off() {
|
||||
notification_message(notification, &sequence_reset_green);
|
||||
}
|
||||
|
||||
IrdaWorker* IrdaApp::get_irda_worker() {
|
||||
return irda_worker;
|
||||
InfraredWorker* InfraredApp::get_infrared_worker() {
|
||||
return infrared_worker;
|
||||
}
|
||||
|
||||
const IrdaAppSignal& IrdaApp::get_received_signal() const {
|
||||
const InfraredAppSignal& InfraredApp::get_received_signal() const {
|
||||
return received_signal;
|
||||
}
|
||||
|
||||
void IrdaApp::set_received_signal(const IrdaAppSignal& signal) {
|
||||
void InfraredApp::set_received_signal(const InfraredAppSignal& signal) {
|
||||
received_signal = signal;
|
||||
}
|
||||
|
||||
void IrdaApp::signal_sent_callback(void* context) {
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
void InfraredApp::signal_sent_callback(void* context) {
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
app->notify_blink_green();
|
||||
}
|
||||
322
applications/infrared/infrared_app.h
Normal file
322
applications/infrared/infrared_app.h
Normal file
@ -0,0 +1,322 @@
|
||||
/**
|
||||
* @file infrared_app.h
|
||||
* Infrared: Main infrared application class
|
||||
*/
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <infrared.h>
|
||||
#include <furi.h>
|
||||
#include <forward_list>
|
||||
#include <stdint.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <infrared_worker.h>
|
||||
|
||||
#include "scene/infrared_app_scene.h"
|
||||
#include "scene/infrared_app_scene.h"
|
||||
#include "infrared_app_view_manager.h"
|
||||
#include "infrared_app_remote_manager.h"
|
||||
#include "infrared_app_view_manager.h"
|
||||
|
||||
/** Main Infrared application class */
|
||||
class InfraredApp {
|
||||
public:
|
||||
/** Enum to save scene state: edit element */
|
||||
enum class EditElement : uint8_t {
|
||||
Button,
|
||||
Remote,
|
||||
};
|
||||
/** Enum to save scene state: edit action */
|
||||
enum class EditAction : uint8_t {
|
||||
Rename,
|
||||
Delete,
|
||||
};
|
||||
/** List of scenes for Infrared application */
|
||||
enum class Scene : uint8_t {
|
||||
Exit,
|
||||
Start,
|
||||
Universal,
|
||||
UniversalTV,
|
||||
UniversalAudio,
|
||||
UniversalAirConditioner,
|
||||
Learn,
|
||||
LearnSuccess,
|
||||
LearnEnterName,
|
||||
LearnDone,
|
||||
AskBack,
|
||||
Remote,
|
||||
RemoteList,
|
||||
Edit,
|
||||
EditKeySelect,
|
||||
EditRename,
|
||||
EditDelete,
|
||||
EditRenameDone,
|
||||
EditDeleteDone,
|
||||
};
|
||||
|
||||
/** Start application
|
||||
*
|
||||
* @param args - application arguments.
|
||||
* Allowed argument is path to remote file.
|
||||
* @retval 0 on success, error code otherwise
|
||||
*/
|
||||
int32_t run(void* args);
|
||||
|
||||
/** Switch to next scene. Put current scene number on stack.
|
||||
* Doesn't save scene state.
|
||||
*
|
||||
* @param index - next scene index
|
||||
*/
|
||||
void switch_to_next_scene(Scene index);
|
||||
|
||||
/** Switch to next scene, but don't put current scene on
|
||||
* stack. Thus calling switch_to_previous_scene() doesn't return
|
||||
* to current scene.
|
||||
*
|
||||
* @param index - next scene index
|
||||
*/
|
||||
void switch_to_next_scene_without_saving(Scene index);
|
||||
|
||||
/** Switch to previous scene. Pop scenes from stack and switch to last one.
|
||||
*
|
||||
* @param count - how many scenes should be popped
|
||||
* @retval false on failed, true on success
|
||||
*/
|
||||
bool switch_to_previous_scene(uint8_t count = 1);
|
||||
|
||||
/** Get previous scene in scene stack
|
||||
*
|
||||
* @retval previous scene
|
||||
*/
|
||||
Scene get_previous_scene();
|
||||
|
||||
/** Get view manager instance
|
||||
*
|
||||
* @retval view manager instance
|
||||
*/
|
||||
InfraredAppViewManager* get_view_manager();
|
||||
|
||||
/** Set one of text stores
|
||||
*
|
||||
* @param index - index of text store
|
||||
* @param text - text to set
|
||||
*/
|
||||
void set_text_store(uint8_t index, const char* text...);
|
||||
|
||||
/** Get value in text store
|
||||
*
|
||||
* @param index - index of text store
|
||||
* @retval value in text_store
|
||||
*/
|
||||
char* get_text_store(uint8_t index);
|
||||
|
||||
/** Get text store size
|
||||
*
|
||||
* @retval size of text store
|
||||
*/
|
||||
uint8_t get_text_store_size();
|
||||
|
||||
/** Get remote manager instance
|
||||
*
|
||||
* @retval remote manager instance
|
||||
*/
|
||||
InfraredAppRemoteManager* get_remote_manager();
|
||||
|
||||
/** Get infrared worker instance
|
||||
*
|
||||
* @retval infrared worker instance
|
||||
*/
|
||||
InfraredWorker* get_infrared_worker();
|
||||
|
||||
/** Get signal, previously got on Learn scene
|
||||
*
|
||||
* @retval received signal
|
||||
*/
|
||||
const InfraredAppSignal& get_received_signal() const;
|
||||
|
||||
/** Set received signal
|
||||
*
|
||||
* @param signal - signal
|
||||
*/
|
||||
void set_received_signal(const InfraredAppSignal& signal);
|
||||
|
||||
/** Switch to previous scene in one of provided in list.
|
||||
* Pop scene stack, and find first scene from list.
|
||||
*
|
||||
* @param scenes_list - list of scenes
|
||||
*/
|
||||
void search_and_switch_to_previous_scene(const std::initializer_list<Scene>& scenes_list);
|
||||
|
||||
/** Set edit element value. It is used on edit scene to determine
|
||||
* what should be deleted - remote or button.
|
||||
*
|
||||
* @param value - value to set
|
||||
*/
|
||||
void set_edit_element(EditElement value);
|
||||
|
||||
/** Get edit element
|
||||
*
|
||||
* @retval edit element value
|
||||
*/
|
||||
EditElement get_edit_element(void);
|
||||
|
||||
/** Set edit action value. It is used on edit scene to determine
|
||||
* what action to perform - deletion or renaming.
|
||||
*
|
||||
* @param value - value to set
|
||||
*/
|
||||
void set_edit_action(EditAction value);
|
||||
|
||||
/** Get edit action
|
||||
*
|
||||
* @retval edit action value
|
||||
*/
|
||||
EditAction get_edit_action(void);
|
||||
|
||||
/** Get state of learning new signal.
|
||||
* Adding new remote with 1 button from start scene and
|
||||
* learning 1 additional button to remote have very similar
|
||||
* flow, so they are joined. Difference in flow is handled
|
||||
* by this boolean flag.
|
||||
*
|
||||
* @retval false if flow is in learning new remote, true if
|
||||
* adding signal to created remote
|
||||
*
|
||||
*/
|
||||
bool get_learn_new_remote();
|
||||
|
||||
/** Set state of learning new signal.
|
||||
* Adding new remote with 1 button from start scene and
|
||||
* learning 1 additional button to remote have very similar
|
||||
* flow, so they are joined. Difference in flow is handled
|
||||
* by this boolean flag.
|
||||
*
|
||||
* @param value - false if flow is in learning new remote, true if
|
||||
* adding signal to created remote
|
||||
*/
|
||||
void set_learn_new_remote(bool value);
|
||||
|
||||
/** Button is not assigned value
|
||||
*/
|
||||
enum : int {
|
||||
ButtonNA = -1,
|
||||
};
|
||||
|
||||
/** Get current button index
|
||||
*
|
||||
* @retval current button index
|
||||
*/
|
||||
int get_current_button();
|
||||
|
||||
/** Set current button index
|
||||
*
|
||||
* @param current button index
|
||||
*/
|
||||
void set_current_button(int value);
|
||||
|
||||
/** Play success notification */
|
||||
void notify_success();
|
||||
/** Play red blink notification */
|
||||
void notify_red_blink();
|
||||
/** Light green */
|
||||
void notify_green_on();
|
||||
/** Disable green light */
|
||||
void notify_green_off();
|
||||
/** Play click sound */
|
||||
void notify_click();
|
||||
/** Play click and green notification */
|
||||
void notify_click_and_green_blink();
|
||||
/** Blink green light */
|
||||
void notify_blink_green();
|
||||
|
||||
/** Text input callback
|
||||
*
|
||||
* @param context - context to pass to callback
|
||||
*/
|
||||
static void text_input_callback(void* context);
|
||||
|
||||
/** Popup callback
|
||||
*
|
||||
* @param context - context to pass to callback
|
||||
*/
|
||||
static void popup_callback(void* context);
|
||||
|
||||
/** Signal sent callback
|
||||
*
|
||||
* @param context - context to pass to callback
|
||||
*/
|
||||
static void signal_sent_callback(void* context);
|
||||
|
||||
/** Main class constructor, initializes all critical objects */
|
||||
InfraredApp();
|
||||
/** Main class destructor, deinitializes all critical objects */
|
||||
~InfraredApp();
|
||||
|
||||
/** Path to Infrared directory */
|
||||
static constexpr const char* infrared_directory = "/any/infrared";
|
||||
/** Infrared files extension (remote files and universal databases) */
|
||||
static constexpr const char* infrared_extension = ".ir";
|
||||
/** Max Raw timings in signal */
|
||||
static constexpr const uint32_t max_raw_timings_in_signal = 512;
|
||||
/** Max line length in Infrared file */
|
||||
static constexpr const uint32_t max_line_length =
|
||||
(9 + 1) * InfraredApp::max_raw_timings_in_signal + 100;
|
||||
|
||||
private:
|
||||
/** Text store size */
|
||||
static constexpr const uint8_t text_store_size = 128;
|
||||
/** Amount of text stores */
|
||||
static constexpr const uint8_t text_store_max = 2;
|
||||
/** Store text here, for some views, because they doesn't
|
||||
* hold ownership of text */
|
||||
char text_store[text_store_max][text_store_size + 1];
|
||||
/**
|
||||
* Flag to control adding new signal flow.
|
||||
* Adding new remote with 1 button from start scene and
|
||||
* learning 1 additional button to remote have very similar
|
||||
* flow, so they are joined. Difference in flow is handled
|
||||
* by this boolean flag.
|
||||
*/
|
||||
bool learn_new_remote;
|
||||
/** Value to control edit scene */
|
||||
EditElement element;
|
||||
/** Value to control edit scene */
|
||||
EditAction action;
|
||||
/** Selected button index */
|
||||
uint32_t current_button;
|
||||
|
||||
/** Notification instance */
|
||||
NotificationApp* notification;
|
||||
/** View manager instance */
|
||||
InfraredAppViewManager view_manager;
|
||||
/** Remote manager instance */
|
||||
InfraredAppRemoteManager remote_manager;
|
||||
/** Infrared worker instance */
|
||||
InfraredWorker* infrared_worker;
|
||||
/** Signal received on Learn scene */
|
||||
InfraredAppSignal received_signal;
|
||||
|
||||
/** Stack of previous scenes */
|
||||
std::forward_list<Scene> previous_scenes_list;
|
||||
/** Now acting scene */
|
||||
Scene current_scene = Scene::Start;
|
||||
|
||||
/** Map of index/scene objects */
|
||||
std::map<Scene, InfraredAppScene*> scenes = {
|
||||
{Scene::Start, new InfraredAppSceneStart()},
|
||||
{Scene::Universal, new InfraredAppSceneUniversal()},
|
||||
{Scene::UniversalTV, new InfraredAppSceneUniversalTV()},
|
||||
{Scene::Learn, new InfraredAppSceneLearn()},
|
||||
{Scene::LearnSuccess, new InfraredAppSceneLearnSuccess()},
|
||||
{Scene::LearnEnterName, new InfraredAppSceneLearnEnterName()},
|
||||
{Scene::LearnDone, new InfraredAppSceneLearnDone()},
|
||||
{Scene::AskBack, new InfraredAppSceneAskBack()},
|
||||
{Scene::Remote, new InfraredAppSceneRemote()},
|
||||
{Scene::RemoteList, new InfraredAppSceneRemoteList()},
|
||||
{Scene::Edit, new InfraredAppSceneEdit()},
|
||||
{Scene::EditKeySelect, new InfraredAppSceneEditKeySelect()},
|
||||
{Scene::EditRename, new InfraredAppSceneEditRename()},
|
||||
{Scene::EditDelete, new InfraredAppSceneEditDelete()},
|
||||
{Scene::EditRenameDone, new InfraredAppSceneEditRenameDone()},
|
||||
{Scene::EditDeleteDone, new InfraredAppSceneEditDeleteDone()},
|
||||
};
|
||||
};
|
||||
@ -1,18 +1,18 @@
|
||||
|
||||
#include "helpers/irda_parser.h"
|
||||
#include "irda_app_brute_force.h"
|
||||
#include "irda_app_signal.h"
|
||||
#include "helpers/infrared_parser.h"
|
||||
#include "infrared_app_brute_force.h"
|
||||
#include "infrared_app_signal.h"
|
||||
#include <memory>
|
||||
#include <m-string.h>
|
||||
#include <furi.h>
|
||||
#include <file_worker_cpp.h>
|
||||
|
||||
void IrdaAppBruteForce::add_record(int index, const char* name) {
|
||||
void InfraredAppBruteForce::add_record(int index, const char* name) {
|
||||
records[name].index = index;
|
||||
records[name].amount = 0;
|
||||
}
|
||||
|
||||
bool IrdaAppBruteForce::calculate_messages() {
|
||||
bool InfraredAppBruteForce::calculate_messages() {
|
||||
bool result = false;
|
||||
|
||||
Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
|
||||
@ -20,7 +20,7 @@ bool IrdaAppBruteForce::calculate_messages() {
|
||||
result = flipper_format_file_open_existing(ff, universal_db_filename);
|
||||
|
||||
if(result) {
|
||||
IrdaAppSignal signal;
|
||||
InfraredAppSignal signal;
|
||||
|
||||
string_t signal_name;
|
||||
string_init(signal_name);
|
||||
@ -38,7 +38,7 @@ bool IrdaAppBruteForce::calculate_messages() {
|
||||
return result;
|
||||
}
|
||||
|
||||
void IrdaAppBruteForce::stop_bruteforce() {
|
||||
void InfraredAppBruteForce::stop_bruteforce() {
|
||||
furi_assert((current_record.size()));
|
||||
|
||||
if(current_record.size()) {
|
||||
@ -49,15 +49,15 @@ void IrdaAppBruteForce::stop_bruteforce() {
|
||||
}
|
||||
}
|
||||
|
||||
bool IrdaAppBruteForce::send_next_bruteforce(void) {
|
||||
bool InfraredAppBruteForce::send_next_bruteforce(void) {
|
||||
furi_assert(current_record.size());
|
||||
furi_assert(ff);
|
||||
|
||||
IrdaAppSignal signal;
|
||||
InfraredAppSignal signal;
|
||||
std::string signal_name;
|
||||
bool result = false;
|
||||
do {
|
||||
result = irda_parser_read_signal(ff, signal, signal_name);
|
||||
result = infrared_parser_read_signal(ff, signal, signal_name);
|
||||
} while(result && current_record.compare(signal_name));
|
||||
|
||||
if(result) {
|
||||
@ -66,7 +66,7 @@ bool IrdaAppBruteForce::send_next_bruteforce(void) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IrdaAppBruteForce::start_bruteforce(int index, int& record_amount) {
|
||||
bool InfraredAppBruteForce::start_bruteforce(int index, int& record_amount) {
|
||||
bool result = false;
|
||||
record_amount = 0;
|
||||
|
||||
67
applications/infrared/infrared_app_brute_force.h
Normal file
67
applications/infrared/infrared_app_brute_force.h
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @file infrared_app_brute_force.h
|
||||
* Infrared: Brute Force class description
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
|
||||
/** Class handles brute force mechanic */
|
||||
class InfraredAppBruteForce {
|
||||
/** Universal database filename */
|
||||
const char* universal_db_filename;
|
||||
|
||||
/** Current record name (POWER, MUTE, VOL+, etc).
|
||||
* This is the name of signal to brute force. */
|
||||
std::string current_record;
|
||||
|
||||
/** Flipper File Format instance */
|
||||
FlipperFormat* ff;
|
||||
|
||||
/** Data about every record - index in button panel view
|
||||
* and amount of signals, which is need for correct
|
||||
* progress bar displaying. */
|
||||
typedef struct {
|
||||
/** Index of record in button panel view model */
|
||||
int index;
|
||||
/** Amount of signals of that type (POWER, MUTE, etc) */
|
||||
int amount;
|
||||
} Record;
|
||||
|
||||
/** Container to hold Record info.
|
||||
* 'key' is record name, because we have to search by both, index and name,
|
||||
* but index search has place once per button press, and should not be
|
||||
* noticed, but name search should occur during entering universal menu,
|
||||
* and will go through container for every record in file, that's why
|
||||
* more critical to have faster search by record name.
|
||||
*/
|
||||
std::unordered_map<std::string, Record> records;
|
||||
|
||||
public:
|
||||
/** Calculate messages. Walk through the file ('universal_db_name')
|
||||
* and calculate amount of records of certain type. */
|
||||
bool calculate_messages();
|
||||
|
||||
/** Start brute force */
|
||||
bool start_bruteforce(int index, int& record_amount);
|
||||
|
||||
/** Stop brute force */
|
||||
void stop_bruteforce();
|
||||
|
||||
/** Send next signal during brute force */
|
||||
bool send_next_bruteforce();
|
||||
|
||||
/** Add record to container of records */
|
||||
void add_record(int index, const char* name);
|
||||
|
||||
/** Initialize class, set db file */
|
||||
InfraredAppBruteForce(const char* filename)
|
||||
: universal_db_filename(filename) {
|
||||
}
|
||||
|
||||
/** Deinitialize class */
|
||||
~InfraredAppBruteForce() {
|
||||
}
|
||||
};
|
||||
47
applications/infrared/infrared_app_event.h
Normal file
47
applications/infrared/infrared_app_event.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file infrared_app_event.h
|
||||
* Infrared: Scene events description
|
||||
*/
|
||||
#pragma once
|
||||
#include <infrared.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
|
||||
/** Infrared events class */
|
||||
class InfraredAppEvent {
|
||||
public:
|
||||
/** Type of event enum */
|
||||
enum class Type : uint8_t {
|
||||
/** Tick event come after no other events came in 100 ms */
|
||||
Tick,
|
||||
/** Exit application event */
|
||||
Exit,
|
||||
/** Back event */
|
||||
Back,
|
||||
/** Menu selected event type. Provided with payload value. */
|
||||
MenuSelected,
|
||||
/** Button press event. Need for continuous signal sending. */
|
||||
MenuSelectedPress,
|
||||
/** Button release event. Need for continuous signal sending. */
|
||||
MenuSelectedRelease,
|
||||
/** Events from DialogEx view module */
|
||||
DialogExSelected,
|
||||
/** Infrared signal received event */
|
||||
InfraredMessageReceived,
|
||||
/** Text edit done event */
|
||||
TextEditDone,
|
||||
/** Popup timer finished event */
|
||||
PopupTimer,
|
||||
/** Button panel pressed event */
|
||||
ButtonPanelPressed,
|
||||
};
|
||||
|
||||
union {
|
||||
/** Menu selected event type payload. Selected index. */
|
||||
int32_t menu_index;
|
||||
/** DialogEx view module event type payload */
|
||||
DialogExResult dialog_ex_result;
|
||||
} payload;
|
||||
|
||||
/** Type of event */
|
||||
Type type;
|
||||
};
|
||||
@ -1,25 +1,26 @@
|
||||
#include <file_worker_cpp.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include "irda_app_remote_manager.h"
|
||||
#include "irda/helpers/irda_parser.h"
|
||||
#include "irda/irda_app_signal.h"
|
||||
#include "infrared_app_remote_manager.h"
|
||||
#include "infrared/helpers/infrared_parser.h"
|
||||
#include "infrared/infrared_app_signal.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <irda.h>
|
||||
#include <infrared.h>
|
||||
#include <cstdio>
|
||||
#include <furi.h>
|
||||
#include <gui/modules/button_menu.h>
|
||||
#include <storage/storage.h>
|
||||
#include "irda_app.h"
|
||||
#include "infrared_app.h"
|
||||
|
||||
static const std::string default_remote_name = "remote";
|
||||
|
||||
std::string IrdaAppRemoteManager::make_full_name(const std::string& remote_name) const {
|
||||
return std::string("") + IrdaApp::irda_directory + "/" + remote_name + IrdaApp::irda_extension;
|
||||
std::string InfraredAppRemoteManager::make_full_name(const std::string& remote_name) const {
|
||||
return std::string("") + InfraredApp::infrared_directory + "/" + remote_name +
|
||||
InfraredApp::infrared_extension;
|
||||
}
|
||||
|
||||
std::string IrdaAppRemoteManager::find_vacant_remote_name(const std::string& name) {
|
||||
std::string InfraredAppRemoteManager::find_vacant_remote_name(const std::string& name) {
|
||||
bool exist = true;
|
||||
FileWorkerCpp file_worker;
|
||||
|
||||
@ -41,14 +42,14 @@ std::string IrdaAppRemoteManager::find_vacant_remote_name(const std::string& nam
|
||||
return !exist ? name + std::to_string(i) : std::string();
|
||||
}
|
||||
|
||||
bool IrdaAppRemoteManager::add_button(const char* button_name, const IrdaAppSignal& signal) {
|
||||
bool InfraredAppRemoteManager::add_button(const char* button_name, const InfraredAppSignal& signal) {
|
||||
remote->buttons.emplace_back(button_name, signal);
|
||||
return store();
|
||||
}
|
||||
|
||||
bool IrdaAppRemoteManager::add_remote_with_button(
|
||||
bool InfraredAppRemoteManager::add_remote_with_button(
|
||||
const char* button_name,
|
||||
const IrdaAppSignal& signal) {
|
||||
const InfraredAppSignal& signal) {
|
||||
furi_check(button_name != nullptr);
|
||||
|
||||
auto new_name = find_vacant_remote_name(default_remote_name);
|
||||
@ -56,11 +57,11 @@ bool IrdaAppRemoteManager::add_remote_with_button(
|
||||
return false;
|
||||
}
|
||||
|
||||
remote = std::make_unique<IrdaAppRemote>(new_name);
|
||||
remote = std::make_unique<InfraredAppRemote>(new_name);
|
||||
return add_button(button_name, signal);
|
||||
}
|
||||
|
||||
std::vector<std::string> IrdaAppRemoteManager::get_button_list(void) const {
|
||||
std::vector<std::string> InfraredAppRemoteManager::get_button_list(void) const {
|
||||
std::vector<std::string> name_vector;
|
||||
name_vector.reserve(remote->buttons.size());
|
||||
|
||||
@ -72,7 +73,7 @@ std::vector<std::string> IrdaAppRemoteManager::get_button_list(void) const {
|
||||
return name_vector;
|
||||
}
|
||||
|
||||
const IrdaAppSignal& IrdaAppRemoteManager::get_button_data(size_t index) const {
|
||||
const InfraredAppSignal& InfraredAppRemoteManager::get_button_data(size_t index) const {
|
||||
furi_check(remote.get() != nullptr);
|
||||
auto& buttons = remote->buttons;
|
||||
furi_check(index < buttons.size());
|
||||
@ -80,7 +81,7 @@ const IrdaAppSignal& IrdaAppRemoteManager::get_button_data(size_t index) const {
|
||||
return buttons.at(index).signal;
|
||||
}
|
||||
|
||||
bool IrdaAppRemoteManager::delete_remote() {
|
||||
bool InfraredAppRemoteManager::delete_remote() {
|
||||
bool result;
|
||||
FileWorkerCpp file_worker;
|
||||
result = file_worker.remove(make_full_name(remote->name).c_str());
|
||||
@ -89,11 +90,11 @@ bool IrdaAppRemoteManager::delete_remote() {
|
||||
return result;
|
||||
}
|
||||
|
||||
void IrdaAppRemoteManager::reset_remote() {
|
||||
void InfraredAppRemoteManager::reset_remote() {
|
||||
remote.reset();
|
||||
}
|
||||
|
||||
bool IrdaAppRemoteManager::delete_button(uint32_t index) {
|
||||
bool InfraredAppRemoteManager::delete_button(uint32_t index) {
|
||||
furi_check(remote.get() != nullptr);
|
||||
auto& buttons = remote->buttons;
|
||||
furi_check(index < buttons.size());
|
||||
@ -102,30 +103,18 @@ bool IrdaAppRemoteManager::delete_button(uint32_t index) {
|
||||
return store();
|
||||
}
|
||||
|
||||
std::string IrdaAppRemoteManager::get_button_name(uint32_t index) {
|
||||
std::string InfraredAppRemoteManager::get_button_name(uint32_t index) {
|
||||
furi_check(remote.get() != nullptr);
|
||||
auto& buttons = remote->buttons;
|
||||
furi_check(index < buttons.size());
|
||||
return buttons[index].name.c_str();
|
||||
}
|
||||
|
||||
std::string IrdaAppRemoteManager::get_remote_name() {
|
||||
std::string InfraredAppRemoteManager::get_remote_name() {
|
||||
return remote.get() ? remote->name : std::string();
|
||||
}
|
||||
|
||||
int IrdaAppRemoteManager::find_remote_name(const std::vector<std::string>& strings) {
|
||||
furi_assert(remote.get() != nullptr);
|
||||
int i = 0;
|
||||
for(const auto& str : strings) {
|
||||
if(!str.compare(remote->name)) {
|
||||
return i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IrdaAppRemoteManager::rename_remote(const char* str) {
|
||||
bool InfraredAppRemoteManager::rename_remote(const char* str) {
|
||||
furi_check(str != nullptr);
|
||||
furi_check(remote.get() != nullptr);
|
||||
|
||||
@ -148,7 +137,7 @@ bool IrdaAppRemoteManager::rename_remote(const char* str) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IrdaAppRemoteManager::rename_button(uint32_t index, const char* str) {
|
||||
bool InfraredAppRemoteManager::rename_button(uint32_t index, const char* str) {
|
||||
furi_check(remote.get() != nullptr);
|
||||
auto& buttons = remote->buttons;
|
||||
furi_check(index < buttons.size());
|
||||
@ -157,16 +146,16 @@ bool IrdaAppRemoteManager::rename_button(uint32_t index, const char* str) {
|
||||
return store();
|
||||
}
|
||||
|
||||
size_t IrdaAppRemoteManager::get_number_of_buttons() {
|
||||
size_t InfraredAppRemoteManager::get_number_of_buttons() {
|
||||
furi_check(remote.get() != nullptr);
|
||||
return remote->buttons.size();
|
||||
}
|
||||
|
||||
bool IrdaAppRemoteManager::store(void) {
|
||||
bool InfraredAppRemoteManager::store(void) {
|
||||
bool result = false;
|
||||
FileWorkerCpp file_worker;
|
||||
|
||||
if(!file_worker.mkdir(IrdaApp::irda_directory)) return false;
|
||||
if(!file_worker.mkdir(InfraredApp::infrared_directory)) return false;
|
||||
|
||||
Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
|
||||
FlipperFormat* ff = flipper_format_file_alloc(storage);
|
||||
@ -178,7 +167,7 @@ bool IrdaAppRemoteManager::store(void) {
|
||||
}
|
||||
if(result) {
|
||||
for(const auto& button : remote->buttons) {
|
||||
result = irda_parser_save_signal(ff, button.signal, button.name.c_str());
|
||||
result = infrared_parser_save_signal(ff, button.signal, button.name.c_str());
|
||||
if(!result) {
|
||||
break;
|
||||
}
|
||||
@ -190,7 +179,7 @@ bool IrdaAppRemoteManager::store(void) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IrdaAppRemoteManager::load(const std::string& remote_name) {
|
||||
bool InfraredAppRemoteManager::load(const std::string& remote_name) {
|
||||
bool result = false;
|
||||
Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
|
||||
FlipperFormat* ff = flipper_format_file_alloc(storage);
|
||||
@ -208,10 +197,10 @@ bool IrdaAppRemoteManager::load(const std::string& remote_name) {
|
||||
string_clear(header);
|
||||
}
|
||||
if(result) {
|
||||
remote = std::make_unique<IrdaAppRemote>(remote_name);
|
||||
IrdaAppSignal signal;
|
||||
remote = std::make_unique<InfraredAppRemote>(remote_name);
|
||||
InfraredAppSignal signal;
|
||||
std::string signal_name;
|
||||
while(irda_parser_read_signal(ff, signal, signal_name)) {
|
||||
while(infrared_parser_read_signal(ff, signal, signal_name)) {
|
||||
remote->buttons.emplace_back(signal_name.c_str(), std::move(signal));
|
||||
}
|
||||
}
|
||||
188
applications/infrared/infrared_app_remote_manager.h
Normal file
188
applications/infrared/infrared_app_remote_manager.h
Normal file
@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @file infrared_app_remote_manager.h
|
||||
* Infrared: Remote manager class.
|
||||
* It holds remote, can load/save/rename remote,
|
||||
* add/remove/rename buttons.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "infrared_app_signal.h"
|
||||
|
||||
#include <infrared_worker.h>
|
||||
#include <infrared.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
/** Class to handle remote button */
|
||||
class InfraredAppRemoteButton {
|
||||
/** Allow field access */
|
||||
friend class InfraredAppRemoteManager;
|
||||
/** Name of signal */
|
||||
std::string name;
|
||||
/** Signal data */
|
||||
InfraredAppSignal signal;
|
||||
|
||||
public:
|
||||
/** Initialize remote button
|
||||
*
|
||||
* @param name - button name
|
||||
* @param signal - signal to copy for remote button
|
||||
*/
|
||||
InfraredAppRemoteButton(const char* name, const InfraredAppSignal& signal)
|
||||
: name(name)
|
||||
, signal(signal) {
|
||||
}
|
||||
|
||||
/** Initialize remote button
|
||||
*
|
||||
* @param name - button name
|
||||
* @param signal - signal to move for remote button
|
||||
*/
|
||||
InfraredAppRemoteButton(const char* name, InfraredAppSignal&& signal)
|
||||
: name(name)
|
||||
, signal(std::move(signal)) {
|
||||
}
|
||||
|
||||
/** Deinitialize remote button */
|
||||
~InfraredAppRemoteButton() {
|
||||
}
|
||||
};
|
||||
|
||||
/** Class to handle remote */
|
||||
class InfraredAppRemote {
|
||||
/** Allow field access */
|
||||
friend class InfraredAppRemoteManager;
|
||||
/** Button container */
|
||||
std::vector<InfraredAppRemoteButton> buttons;
|
||||
/** Name of remote */
|
||||
std::string name;
|
||||
|
||||
public:
|
||||
/** Initialize new remote
|
||||
*
|
||||
* @param name - new remote name
|
||||
*/
|
||||
InfraredAppRemote(const std::string& name)
|
||||
: name(name) {
|
||||
}
|
||||
};
|
||||
|
||||
/** Class to handle remote manager */
|
||||
class InfraredAppRemoteManager {
|
||||
/** Remote instance. There can be 1 remote loaded at a time. */
|
||||
std::unique_ptr<InfraredAppRemote> remote;
|
||||
/** Make full name from remote name
|
||||
*
|
||||
* @param remote_name name of remote
|
||||
* @retval full name of remote on disk
|
||||
*/
|
||||
std::string make_full_name(const std::string& remote_name) const;
|
||||
|
||||
public:
|
||||
/** Restriction to button name length. Buttons larger are ignored. */
|
||||
static constexpr const uint32_t max_button_name_length = 22;
|
||||
|
||||
/** Restriction to remote name length. Remotes larger are ignored. */
|
||||
static constexpr const uint32_t max_remote_name_length = 22;
|
||||
|
||||
/** Construct button from signal, and create remote
|
||||
*
|
||||
* @param button_name - name of button to create
|
||||
* @param signal - signal to create button from
|
||||
* @retval true for success, false otherwise
|
||||
* */
|
||||
bool add_remote_with_button(const char* button_name, const InfraredAppSignal& signal);
|
||||
|
||||
/** Add button to current remote
|
||||
*
|
||||
* @param button_name - name of button to create
|
||||
* @param signal - signal to create button from
|
||||
* @retval true for success, false otherwise
|
||||
* */
|
||||
bool add_button(const char* button_name, const InfraredAppSignal& signal);
|
||||
|
||||
/** Rename button in current remote
|
||||
*
|
||||
* @param index - index of button to rename
|
||||
* @param str - new button name
|
||||
*/
|
||||
bool rename_button(uint32_t index, const char* str);
|
||||
|
||||
/** Rename current remote
|
||||
*
|
||||
* @param str - new remote name
|
||||
*/
|
||||
bool rename_remote(const char* str);
|
||||
|
||||
/** Find vacant remote name. If suggested name is occupied,
|
||||
* incremented digit(2,3,4,etc) added to name and check repeated.
|
||||
*
|
||||
* @param name - suggested remote name
|
||||
* @retval garanteed free remote name, prefixed with suggested
|
||||
*/
|
||||
std::string find_vacant_remote_name(const std::string& name);
|
||||
|
||||
/** Get button list
|
||||
*
|
||||
* @retval container of button names
|
||||
*/
|
||||
std::vector<std::string> get_button_list() const;
|
||||
|
||||
/** Get button name by index
|
||||
*
|
||||
* @param index - index of button to get name from
|
||||
* @retval button name
|
||||
*/
|
||||
std::string get_button_name(uint32_t index);
|
||||
|
||||
/** Get remote name
|
||||
*
|
||||
* @retval remote name
|
||||
*/
|
||||
std::string get_remote_name();
|
||||
|
||||
/** Get number of buttons
|
||||
*
|
||||
* @retval number of buttons
|
||||
*/
|
||||
size_t get_number_of_buttons();
|
||||
|
||||
/** Get button's signal
|
||||
*
|
||||
* @param index - index of interested button
|
||||
* @retval signal
|
||||
*/
|
||||
const InfraredAppSignal& get_button_data(size_t index) const;
|
||||
|
||||
/** Delete button
|
||||
*
|
||||
* @param index - index of interested button
|
||||
* @retval true if success, false otherwise
|
||||
*/
|
||||
bool delete_button(uint32_t index);
|
||||
|
||||
/** Delete remote
|
||||
*
|
||||
* @retval true if success, false otherwise
|
||||
*/
|
||||
bool delete_remote();
|
||||
|
||||
/** Clean all loaded info in current remote */
|
||||
void reset_remote();
|
||||
|
||||
/** Store current remote data on disk
|
||||
*
|
||||
* @retval true if success, false otherwise
|
||||
*/
|
||||
bool store();
|
||||
|
||||
/** Load data from disk into current remote
|
||||
*
|
||||
* @param name - name of remote to load
|
||||
* @retval true if success, false otherwise
|
||||
*/
|
||||
bool load(const std::string& name);
|
||||
};
|
||||
@ -1,7 +1,7 @@
|
||||
#include "irda_app_signal.h"
|
||||
#include <irda_transmit.h>
|
||||
#include "infrared_app_signal.h"
|
||||
#include <infrared_transmit.h>
|
||||
|
||||
void IrdaAppSignal::copy_raw_signal(
|
||||
void InfraredAppSignal::copy_raw_signal(
|
||||
const uint32_t* timings,
|
||||
size_t size,
|
||||
uint32_t frequency,
|
||||
@ -18,7 +18,7 @@ void IrdaAppSignal::copy_raw_signal(
|
||||
}
|
||||
}
|
||||
|
||||
void IrdaAppSignal::clear_timings() {
|
||||
void InfraredAppSignal::clear_timings() {
|
||||
if(raw_signal) {
|
||||
delete[] payload.raw.timings;
|
||||
payload.raw.timings_cnt = 0;
|
||||
@ -26,7 +26,7 @@ void IrdaAppSignal::clear_timings() {
|
||||
}
|
||||
}
|
||||
|
||||
IrdaAppSignal::IrdaAppSignal(
|
||||
InfraredAppSignal::InfraredAppSignal(
|
||||
const uint32_t* timings,
|
||||
size_t timings_cnt,
|
||||
uint32_t frequency,
|
||||
@ -35,12 +35,12 @@ IrdaAppSignal::IrdaAppSignal(
|
||||
copy_raw_signal(timings, timings_cnt, frequency, duty_cycle);
|
||||
}
|
||||
|
||||
IrdaAppSignal::IrdaAppSignal(const IrdaMessage* irda_message) {
|
||||
InfraredAppSignal::InfraredAppSignal(const InfraredMessage* infrared_message) {
|
||||
raw_signal = false;
|
||||
payload.message = *irda_message;
|
||||
payload.message = *infrared_message;
|
||||
}
|
||||
|
||||
IrdaAppSignal& IrdaAppSignal::operator=(const IrdaAppSignal& other) {
|
||||
InfraredAppSignal& InfraredAppSignal::operator=(const InfraredAppSignal& other) {
|
||||
clear_timings();
|
||||
raw_signal = other.raw_signal;
|
||||
if(!raw_signal) {
|
||||
@ -56,7 +56,7 @@ IrdaAppSignal& IrdaAppSignal::operator=(const IrdaAppSignal& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
IrdaAppSignal::IrdaAppSignal(const IrdaAppSignal& other) {
|
||||
InfraredAppSignal::InfraredAppSignal(const InfraredAppSignal& other) {
|
||||
raw_signal = other.raw_signal;
|
||||
if(!raw_signal) {
|
||||
payload.message = other.payload.message;
|
||||
@ -69,7 +69,7 @@ IrdaAppSignal::IrdaAppSignal(const IrdaAppSignal& other) {
|
||||
}
|
||||
}
|
||||
|
||||
IrdaAppSignal::IrdaAppSignal(IrdaAppSignal&& other) {
|
||||
InfraredAppSignal::InfraredAppSignal(InfraredAppSignal&& other) {
|
||||
raw_signal = other.raw_signal;
|
||||
if(!raw_signal) {
|
||||
payload.message = other.payload.message;
|
||||
@ -86,13 +86,13 @@ IrdaAppSignal::IrdaAppSignal(IrdaAppSignal&& other) {
|
||||
}
|
||||
}
|
||||
|
||||
void IrdaAppSignal::set_message(const IrdaMessage* irda_message) {
|
||||
void InfraredAppSignal::set_message(const InfraredMessage* infrared_message) {
|
||||
clear_timings();
|
||||
raw_signal = false;
|
||||
payload.message = *irda_message;
|
||||
payload.message = *infrared_message;
|
||||
}
|
||||
|
||||
void IrdaAppSignal::set_raw_signal(
|
||||
void InfraredAppSignal::set_raw_signal(
|
||||
uint32_t* timings,
|
||||
size_t timings_cnt,
|
||||
uint32_t frequency,
|
||||
@ -102,11 +102,11 @@ void IrdaAppSignal::set_raw_signal(
|
||||
copy_raw_signal(timings, timings_cnt, frequency, duty_cycle);
|
||||
}
|
||||
|
||||
void IrdaAppSignal::transmit() const {
|
||||
void InfraredAppSignal::transmit() const {
|
||||
if(!raw_signal) {
|
||||
irda_send(&payload.message, 1);
|
||||
infrared_send(&payload.message, 1);
|
||||
} else {
|
||||
irda_send_raw_ext(
|
||||
infrared_send_raw_ext(
|
||||
payload.raw.timings,
|
||||
payload.raw.timings_cnt,
|
||||
true,
|
||||
134
applications/infrared/infrared_app_signal.h
Normal file
134
applications/infrared/infrared_app_signal.h
Normal file
@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @file infrared_app_signal.h
|
||||
* Infrared: Signal class
|
||||
*/
|
||||
#pragma once
|
||||
#include <infrared_worker.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <infrared.h>
|
||||
|
||||
/** Infrared application signal class */
|
||||
class InfraredAppSignal {
|
||||
public:
|
||||
/** Raw signal structure */
|
||||
typedef struct {
|
||||
/** Timings amount */
|
||||
size_t timings_cnt;
|
||||
/** Samples of raw signal in ms */
|
||||
uint32_t* timings;
|
||||
/** PWM Frequency of raw signal */
|
||||
uint32_t frequency;
|
||||
/** PWM Duty cycle of raw signal */
|
||||
float duty_cycle;
|
||||
} RawSignal;
|
||||
|
||||
private:
|
||||
/** if true - signal is raw, if false - signal is parsed */
|
||||
bool raw_signal;
|
||||
/** signal data, either raw or parsed */
|
||||
union {
|
||||
/** signal data for parsed signal */
|
||||
InfraredMessage message;
|
||||
/** raw signal data */
|
||||
RawSignal raw;
|
||||
} payload;
|
||||
|
||||
/** Copy raw signal into object
|
||||
*
|
||||
* @param timings - timings (samples) of raw signal
|
||||
* @param size - number of timings
|
||||
* @frequency - PWM frequency of raw signal
|
||||
* @duty_cycle - PWM duty cycle
|
||||
*/
|
||||
void
|
||||
copy_raw_signal(const uint32_t* timings, size_t size, uint32_t frequency, float duty_cycle);
|
||||
/** Clear and free timings data */
|
||||
void clear_timings();
|
||||
|
||||
public:
|
||||
/** Construct Infrared signal class */
|
||||
InfraredAppSignal() {
|
||||
raw_signal = false;
|
||||
payload.message.protocol = InfraredProtocolUnknown;
|
||||
}
|
||||
|
||||
/** Destruct signal class and free all allocated data */
|
||||
~InfraredAppSignal() {
|
||||
clear_timings();
|
||||
}
|
||||
|
||||
/** Construct object with raw signal
|
||||
*
|
||||
* @param timings - timings (samples) of raw signal
|
||||
* @param size - number of timings
|
||||
* @frequency - PWM frequency of raw signal
|
||||
* @duty_cycle - PWM duty cycle
|
||||
*/
|
||||
InfraredAppSignal(
|
||||
const uint32_t* timings,
|
||||
size_t timings_cnt,
|
||||
uint32_t frequency,
|
||||
float duty_cycle);
|
||||
|
||||
/** Construct object with parsed signal
|
||||
*
|
||||
* @param infrared_message - parsed_signal to construct from
|
||||
*/
|
||||
InfraredAppSignal(const InfraredMessage* infrared_message);
|
||||
|
||||
/** Copy constructor */
|
||||
InfraredAppSignal(const InfraredAppSignal& other);
|
||||
/** Move constructor */
|
||||
InfraredAppSignal(InfraredAppSignal&& other);
|
||||
|
||||
/** Assignment operator */
|
||||
InfraredAppSignal& operator=(const InfraredAppSignal& signal);
|
||||
|
||||
/** Set object to parsed signal
|
||||
*
|
||||
* @param infrared_message - parsed_signal to construct from
|
||||
*/
|
||||
void set_message(const InfraredMessage* infrared_message);
|
||||
|
||||
/** Set object to raw signal
|
||||
*
|
||||
* @param timings - timings (samples) of raw signal
|
||||
* @param size - number of timings
|
||||
* @frequency - PWM frequency of raw signal
|
||||
* @duty_cycle - PWM duty cycle
|
||||
*/
|
||||
void
|
||||
set_raw_signal(uint32_t* timings, size_t timings_cnt, uint32_t frequency, float duty_cycle);
|
||||
|
||||
/** Transmit held signal (???) */
|
||||
void transmit() const;
|
||||
|
||||
/** Show is held signal raw
|
||||
*
|
||||
* @retval true if signal is raw, false if signal is parsed
|
||||
*/
|
||||
bool is_raw(void) const {
|
||||
return raw_signal;
|
||||
}
|
||||
|
||||
/** Get parsed signal.
|
||||
* User must check is_raw() signal before calling this function.
|
||||
*
|
||||
* @retval parsed signal pointer
|
||||
*/
|
||||
const InfraredMessage& get_message(void) const {
|
||||
furi_assert(!raw_signal);
|
||||
return payload.message;
|
||||
}
|
||||
|
||||
/** Get raw signal.
|
||||
* User must check is_raw() signal before calling this function.
|
||||
*
|
||||
* @retval raw signal
|
||||
*/
|
||||
const RawSignal& get_raw_signal(void) const {
|
||||
furi_assert(raw_signal);
|
||||
return payload.raw;
|
||||
}
|
||||
};
|
||||
@ -6,16 +6,16 @@
|
||||
#include <furi.h>
|
||||
#include <callback-connector.h>
|
||||
|
||||
#include "irda/irda_app_view_manager.h"
|
||||
#include "irda/view/irda_progress_view.h"
|
||||
#include "irda_app.h"
|
||||
#include "irda/irda_app_event.h"
|
||||
#include "infrared/infrared_app_view_manager.h"
|
||||
#include "infrared/view/infrared_progress_view.h"
|
||||
#include "infrared_app.h"
|
||||
#include "infrared/infrared_app_event.h"
|
||||
|
||||
IrdaAppViewManager::IrdaAppViewManager() {
|
||||
event_queue = osMessageQueueNew(10, sizeof(IrdaAppEvent), NULL);
|
||||
InfraredAppViewManager::InfraredAppViewManager() {
|
||||
event_queue = osMessageQueueNew(10, sizeof(InfraredAppEvent), NULL);
|
||||
|
||||
view_dispatcher = view_dispatcher_alloc();
|
||||
auto callback = cbc::obtain_connector(this, &IrdaAppViewManager::previous_view_callback);
|
||||
auto callback = cbc::obtain_connector(this, &InfraredAppViewManager::previous_view_callback);
|
||||
|
||||
gui = static_cast<Gui*>(furi_record_open("gui"));
|
||||
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
@ -26,18 +26,18 @@ IrdaAppViewManager::IrdaAppViewManager() {
|
||||
dialog_ex = dialog_ex_alloc();
|
||||
text_input = text_input_alloc();
|
||||
button_panel = button_panel_alloc();
|
||||
progress_view = irda_progress_view_alloc();
|
||||
progress_view = infrared_progress_view_alloc();
|
||||
loading_view = loading_alloc();
|
||||
universal_view_stack = view_stack_alloc();
|
||||
view_stack_add_view(universal_view_stack, button_panel_get_view(button_panel));
|
||||
view_set_orientation(view_stack_get_view(universal_view_stack), ViewOrientationVertical);
|
||||
|
||||
add_view(ViewType::UniversalRemote, view_stack_get_view(universal_view_stack));
|
||||
add_view(ViewType::ButtonMenu, button_menu_get_view(button_menu));
|
||||
add_view(ViewType::Submenu, submenu_get_view(submenu));
|
||||
add_view(ViewType::Popup, popup_get_view(popup));
|
||||
add_view(ViewType::DialogEx, dialog_ex_get_view(dialog_ex));
|
||||
add_view(ViewType::TextInput, text_input_get_view(text_input));
|
||||
add_view(ViewId::UniversalRemote, view_stack_get_view(universal_view_stack));
|
||||
add_view(ViewId::ButtonMenu, button_menu_get_view(button_menu));
|
||||
add_view(ViewId::Submenu, submenu_get_view(submenu));
|
||||
add_view(ViewId::Popup, popup_get_view(popup));
|
||||
add_view(ViewId::DialogEx, dialog_ex_get_view(dialog_ex));
|
||||
add_view(ViewId::TextInput, text_input_get_view(text_input));
|
||||
|
||||
view_set_previous_callback(view_stack_get_view(universal_view_stack), callback);
|
||||
view_set_previous_callback(button_menu_get_view(button_menu), callback);
|
||||
@ -47,19 +47,19 @@ IrdaAppViewManager::IrdaAppViewManager() {
|
||||
view_set_previous_callback(text_input_get_view(text_input), callback);
|
||||
}
|
||||
|
||||
IrdaAppViewManager::~IrdaAppViewManager() {
|
||||
InfraredAppViewManager::~InfraredAppViewManager() {
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(IrdaAppViewManager::ViewType::UniversalRemote));
|
||||
view_dispatcher, static_cast<uint32_t>(InfraredAppViewManager::ViewId::UniversalRemote));
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(IrdaAppViewManager::ViewType::ButtonMenu));
|
||||
view_dispatcher, static_cast<uint32_t>(InfraredAppViewManager::ViewId::ButtonMenu));
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(IrdaAppViewManager::ViewType::TextInput));
|
||||
view_dispatcher, static_cast<uint32_t>(InfraredAppViewManager::ViewId::TextInput));
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(IrdaAppViewManager::ViewType::DialogEx));
|
||||
view_dispatcher, static_cast<uint32_t>(InfraredAppViewManager::ViewId::DialogEx));
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(IrdaAppViewManager::ViewType::Submenu));
|
||||
view_dispatcher, static_cast<uint32_t>(InfraredAppViewManager::ViewId::Submenu));
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(IrdaAppViewManager::ViewType::Popup));
|
||||
view_dispatcher, static_cast<uint32_t>(InfraredAppViewManager::ViewId::Popup));
|
||||
|
||||
view_stack_remove_view(universal_view_stack, button_panel_get_view(button_panel));
|
||||
view_stack_free(universal_view_stack);
|
||||
@ -69,7 +69,7 @@ IrdaAppViewManager::~IrdaAppViewManager() {
|
||||
button_menu_free(button_menu);
|
||||
dialog_ex_free(dialog_ex);
|
||||
text_input_free(text_input);
|
||||
irda_progress_view_free(progress_view);
|
||||
infrared_progress_view_free(progress_view);
|
||||
loading_free(loading_view);
|
||||
|
||||
view_dispatcher_free(view_dispatcher);
|
||||
@ -77,70 +77,70 @@ IrdaAppViewManager::~IrdaAppViewManager() {
|
||||
osMessageQueueDelete(event_queue);
|
||||
}
|
||||
|
||||
void IrdaAppViewManager::switch_to(ViewType type) {
|
||||
void InfraredAppViewManager::switch_to(ViewId type) {
|
||||
view_dispatcher_switch_to_view(view_dispatcher, static_cast<uint32_t>(type));
|
||||
}
|
||||
|
||||
TextInput* IrdaAppViewManager::get_text_input() {
|
||||
TextInput* InfraredAppViewManager::get_text_input() {
|
||||
return text_input;
|
||||
}
|
||||
|
||||
DialogEx* IrdaAppViewManager::get_dialog_ex() {
|
||||
DialogEx* InfraredAppViewManager::get_dialog_ex() {
|
||||
return dialog_ex;
|
||||
}
|
||||
|
||||
Submenu* IrdaAppViewManager::get_submenu() {
|
||||
Submenu* InfraredAppViewManager::get_submenu() {
|
||||
return submenu;
|
||||
}
|
||||
|
||||
Popup* IrdaAppViewManager::get_popup() {
|
||||
Popup* InfraredAppViewManager::get_popup() {
|
||||
return popup;
|
||||
}
|
||||
|
||||
ButtonMenu* IrdaAppViewManager::get_button_menu() {
|
||||
ButtonMenu* InfraredAppViewManager::get_button_menu() {
|
||||
return button_menu;
|
||||
}
|
||||
|
||||
ButtonPanel* IrdaAppViewManager::get_button_panel() {
|
||||
ButtonPanel* InfraredAppViewManager::get_button_panel() {
|
||||
return button_panel;
|
||||
}
|
||||
|
||||
IrdaProgressView* IrdaAppViewManager::get_progress() {
|
||||
InfraredProgressView* InfraredAppViewManager::get_progress() {
|
||||
return progress_view;
|
||||
}
|
||||
|
||||
Loading* IrdaAppViewManager::get_loading() {
|
||||
Loading* InfraredAppViewManager::get_loading() {
|
||||
return loading_view;
|
||||
}
|
||||
|
||||
ViewStack* IrdaAppViewManager::get_universal_view_stack() {
|
||||
ViewStack* InfraredAppViewManager::get_universal_view_stack() {
|
||||
return universal_view_stack;
|
||||
}
|
||||
|
||||
osMessageQueueId_t IrdaAppViewManager::get_event_queue() {
|
||||
osMessageQueueId_t InfraredAppViewManager::get_event_queue() {
|
||||
return event_queue;
|
||||
}
|
||||
|
||||
void IrdaAppViewManager::clear_events() {
|
||||
IrdaAppEvent event;
|
||||
void InfraredAppViewManager::clear_events() {
|
||||
InfraredAppEvent event;
|
||||
while(osMessageQueueGet(event_queue, &event, NULL, 0) == osOK)
|
||||
;
|
||||
}
|
||||
|
||||
void IrdaAppViewManager::receive_event(IrdaAppEvent* event) {
|
||||
void InfraredAppViewManager::receive_event(InfraredAppEvent* event) {
|
||||
if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) {
|
||||
event->type = IrdaAppEvent::Type::Tick;
|
||||
event->type = InfraredAppEvent::Type::Tick;
|
||||
}
|
||||
}
|
||||
|
||||
void IrdaAppViewManager::send_event(IrdaAppEvent* event) {
|
||||
void InfraredAppViewManager::send_event(InfraredAppEvent* event) {
|
||||
uint32_t timeout = 0;
|
||||
/* Rapid button hammering on signal send scenes causes queue overflow - ignore it,
|
||||
* but try to keep button release event - it switches off IRDA DMA sending. */
|
||||
if(event->type == IrdaAppEvent::Type::MenuSelectedRelease) {
|
||||
* but try to keep button release event - it switches off INFRARED DMA sending. */
|
||||
if(event->type == InfraredAppEvent::Type::MenuSelectedRelease) {
|
||||
timeout = 200;
|
||||
}
|
||||
if((event->type == IrdaAppEvent::Type::DialogExSelected) &&
|
||||
if((event->type == InfraredAppEvent::Type::DialogExSelected) &&
|
||||
(event->payload.dialog_ex_result == DialogExReleaseCenter)) {
|
||||
timeout = 200;
|
||||
}
|
||||
@ -148,16 +148,16 @@ void IrdaAppViewManager::send_event(IrdaAppEvent* event) {
|
||||
osMessageQueuePut(event_queue, event, 0, timeout);
|
||||
}
|
||||
|
||||
uint32_t IrdaAppViewManager::previous_view_callback(void* context) {
|
||||
uint32_t InfraredAppViewManager::previous_view_callback(void* context) {
|
||||
if(event_queue != NULL) {
|
||||
IrdaAppEvent event;
|
||||
event.type = IrdaAppEvent::Type::Back;
|
||||
InfraredAppEvent event;
|
||||
event.type = InfraredAppEvent::Type::Back;
|
||||
send_event(&event);
|
||||
}
|
||||
|
||||
return VIEW_IGNORE;
|
||||
}
|
||||
|
||||
void IrdaAppViewManager::add_view(ViewType view_type, View* view) {
|
||||
void InfraredAppViewManager::add_view(ViewId view_type, View* view) {
|
||||
view_dispatcher_add_view(view_dispatcher, static_cast<uint32_t>(view_type), view);
|
||||
}
|
||||
164
applications/infrared/infrared_app_view_manager.h
Normal file
164
applications/infrared/infrared_app_view_manager.h
Normal file
@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @file infrared_app_view_manager.h
|
||||
* Infrared: Scene events description
|
||||
*/
|
||||
#pragma once
|
||||
#include <gui/modules/button_menu.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/view_stack.h>
|
||||
#include <gui/modules/button_panel.h>
|
||||
#include <furi.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/modules/loading.h>
|
||||
|
||||
#include "infrared_app_event.h"
|
||||
#include "view/infrared_progress_view.h"
|
||||
|
||||
/** Infrared View manager class */
|
||||
class InfraredAppViewManager {
|
||||
public:
|
||||
/** Infrared View Id enum, it is used
|
||||
* to identify added views */
|
||||
enum class ViewId : uint8_t {
|
||||
DialogEx,
|
||||
TextInput,
|
||||
Submenu,
|
||||
ButtonMenu,
|
||||
UniversalRemote,
|
||||
Popup,
|
||||
};
|
||||
|
||||
/** Class constructor */
|
||||
InfraredAppViewManager();
|
||||
/** Class destructor */
|
||||
~InfraredAppViewManager();
|
||||
|
||||
/** Switch to another view
|
||||
*
|
||||
* @param id - view id to switch to
|
||||
*/
|
||||
void switch_to(ViewId id);
|
||||
|
||||
/** Receive event from queue
|
||||
*
|
||||
* @param event - received event
|
||||
*/
|
||||
void receive_event(InfraredAppEvent* event);
|
||||
|
||||
/** Send event to queue
|
||||
*
|
||||
* @param event - event to send
|
||||
*/
|
||||
void send_event(InfraredAppEvent* event);
|
||||
|
||||
/** Clear events that already in queue
|
||||
*
|
||||
* @param event - event to send
|
||||
*/
|
||||
void clear_events();
|
||||
|
||||
/** Get dialog_ex view module
|
||||
*
|
||||
* @retval dialog_ex view module
|
||||
*/
|
||||
DialogEx* get_dialog_ex();
|
||||
|
||||
/** Get submenu view module
|
||||
*
|
||||
* @retval submenu view module
|
||||
*/
|
||||
Submenu* get_submenu();
|
||||
|
||||
/** Get popup view module
|
||||
*
|
||||
* @retval popup view module
|
||||
*/
|
||||
Popup* get_popup();
|
||||
|
||||
/** Get text_input view module
|
||||
*
|
||||
* @retval text_input view module
|
||||
*/
|
||||
TextInput* get_text_input();
|
||||
|
||||
/** Get button_menu view module
|
||||
*
|
||||
* @retval button_menu view module
|
||||
*/
|
||||
ButtonMenu* get_button_menu();
|
||||
|
||||
/** Get button_panel view module
|
||||
*
|
||||
* @retval button_panel view module
|
||||
*/
|
||||
ButtonPanel* get_button_panel();
|
||||
|
||||
/** Get view_stack view module used in universal remote
|
||||
*
|
||||
* @retval view_stack view module
|
||||
*/
|
||||
ViewStack* get_universal_view_stack();
|
||||
|
||||
/** Get progress view module
|
||||
*
|
||||
* @retval progress view module
|
||||
*/
|
||||
InfraredProgressView* get_progress();
|
||||
|
||||
/** Get loading view module
|
||||
*
|
||||
* @retval loading view module
|
||||
*/
|
||||
Loading* get_loading();
|
||||
|
||||
/** Get event queue
|
||||
*
|
||||
* @retval event queue
|
||||
*/
|
||||
osMessageQueueId_t get_event_queue();
|
||||
|
||||
/** Callback to handle back button
|
||||
*
|
||||
* @param context - context to pass to callback
|
||||
* @retval always returns VIEW_IGNORE
|
||||
*/
|
||||
uint32_t previous_view_callback(void* context);
|
||||
|
||||
private:
|
||||
/** View Dispatcher instance.
|
||||
* It handles view switching */
|
||||
ViewDispatcher* view_dispatcher;
|
||||
/** Gui instance */
|
||||
Gui* gui;
|
||||
/** Text input view module instance */
|
||||
TextInput* text_input;
|
||||
/** DialogEx view module instance */
|
||||
DialogEx* dialog_ex;
|
||||
/** Submenu view module instance */
|
||||
Submenu* submenu;
|
||||
/** Popup view module instance */
|
||||
Popup* popup;
|
||||
/** ButtonMenu view module instance */
|
||||
ButtonMenu* button_menu;
|
||||
/** ButtonPanel view module instance */
|
||||
ButtonPanel* button_panel;
|
||||
/** ViewStack view module instance */
|
||||
ViewStack* universal_view_stack;
|
||||
/** ProgressView view module instance */
|
||||
InfraredProgressView* progress_view;
|
||||
/** Loading view module instance */
|
||||
Loading* loading_view;
|
||||
|
||||
/** Queue to handle events, which are processed in scenes */
|
||||
osMessageQueueId_t event_queue;
|
||||
|
||||
/** Add View to pull of views
|
||||
*
|
||||
* @param view_id - id to identify view
|
||||
* @param view - view to add
|
||||
*/
|
||||
void add_view(ViewId view_id, View* view);
|
||||
};
|
||||
9
applications/infrared/infrared_runner.cpp
Normal file
9
applications/infrared/infrared_runner.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "infrared_app.h"
|
||||
|
||||
extern "C" int32_t infrared_app(void* p) {
|
||||
InfraredApp* app = new InfraredApp();
|
||||
int32_t result = app->run(p);
|
||||
delete app;
|
||||
|
||||
return result;
|
||||
}
|
||||
305
applications/infrared/scene/infrared_app_scene.h
Normal file
305
applications/infrared/scene/infrared_app_scene.h
Normal file
@ -0,0 +1,305 @@
|
||||
/**
|
||||
* @file infrared_app_scene.h
|
||||
* Infrared: Application scenes
|
||||
*/
|
||||
#pragma once
|
||||
#include "../infrared_app_event.h"
|
||||
#include <furi_hal_infrared.h>
|
||||
#include "infrared.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../infrared_app_brute_force.h"
|
||||
|
||||
/** Anonymous class */
|
||||
class InfraredApp;
|
||||
|
||||
/** Base Scene class */
|
||||
class InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
virtual void on_enter(InfraredApp* app) = 0;
|
||||
/** Events handler callback */
|
||||
virtual bool on_event(InfraredApp* app, InfraredAppEvent* event) = 0;
|
||||
/** Called when exit scene */
|
||||
virtual void on_exit(InfraredApp* app) = 0;
|
||||
/** Virtual destructor of base class */
|
||||
virtual ~InfraredAppScene(){};
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
/** Start scene
|
||||
* Main Infrared application menu
|
||||
*/
|
||||
class InfraredAppSceneStart : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
|
||||
private:
|
||||
/** Save previously selected submenu index
|
||||
* to highlight it when get back */
|
||||
uint32_t submenu_item_selected = 0;
|
||||
};
|
||||
|
||||
/** Universal menu scene
|
||||
* Scene to select universal remote
|
||||
*/
|
||||
class InfraredAppSceneUniversal : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
|
||||
private:
|
||||
/** Save previously selected submenu index
|
||||
* to highlight it when get back */
|
||||
uint32_t submenu_item_selected = 0;
|
||||
};
|
||||
|
||||
/** Learn new signal scene
|
||||
* On this scene catching new IR signal performed.
|
||||
*/
|
||||
class InfraredAppSceneLearn : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
};
|
||||
|
||||
/** New signal learn succeeded scene
|
||||
*/
|
||||
class InfraredAppSceneLearnSuccess : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
bool button_pressed = false;
|
||||
};
|
||||
|
||||
/** Scene to enter name for new button in remote
|
||||
*/
|
||||
class InfraredAppSceneLearnEnterName : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
};
|
||||
|
||||
/** Scene where signal is learnt
|
||||
*/
|
||||
class InfraredAppSceneLearnDone : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
};
|
||||
|
||||
/** Remote interface scene
|
||||
* On this scene you can send IR signals from selected remote
|
||||
*/
|
||||
class InfraredAppSceneRemote : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
|
||||
private:
|
||||
/** container of button names in current remote. */
|
||||
std::vector<std::string> buttons_names;
|
||||
/** Save previously selected index
|
||||
* to highlight it when get back */
|
||||
uint32_t buttonmenu_item_selected = 0;
|
||||
/** state flag to show button is pressed.
|
||||
* As long as send-signal button pressed no other button
|
||||
* events are handled. */
|
||||
bool button_pressed = false;
|
||||
};
|
||||
|
||||
/** List of remotes scene
|
||||
* Every remote is a file, located on internal/external storage.
|
||||
* Every file has same format, and same extension.
|
||||
* Files are parsed as you enter 'Remote scene' and showed
|
||||
* as a buttons.
|
||||
*/
|
||||
class InfraredAppSceneRemoteList : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
|
||||
private:
|
||||
/** Save previously selected index
|
||||
* to highlight it when get back */
|
||||
uint32_t submenu_item_selected = 0;
|
||||
/** Remote names to show them in submenu */
|
||||
std::vector<std::string> remote_names;
|
||||
};
|
||||
|
||||
class InfraredAppSceneAskBack : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
};
|
||||
|
||||
class InfraredAppSceneEdit : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
|
||||
private:
|
||||
/** Save previously selected index
|
||||
* to highlight it when get back */
|
||||
uint32_t submenu_item_selected = 0;
|
||||
};
|
||||
|
||||
class InfraredAppSceneEditKeySelect : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
|
||||
private:
|
||||
/** Button names to show them in submenu */
|
||||
std::vector<std::string> buttons_names;
|
||||
};
|
||||
|
||||
class InfraredAppSceneEditRename : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
};
|
||||
|
||||
class InfraredAppSceneEditDelete : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
};
|
||||
|
||||
class InfraredAppSceneEditRenameDone : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
};
|
||||
|
||||
class InfraredAppSceneEditDeleteDone : public InfraredAppScene {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
};
|
||||
|
||||
class InfraredAppSceneUniversalCommon : public InfraredAppScene {
|
||||
/** Brute force started flag */
|
||||
bool brute_force_started = false;
|
||||
|
||||
protected:
|
||||
/** Events handler callback */
|
||||
bool on_event(InfraredApp* app, InfraredAppEvent* event) final;
|
||||
/** Called when exit scene */
|
||||
void on_exit(InfraredApp* app) final;
|
||||
|
||||
/** Show popup window
|
||||
*
|
||||
* @param app - application instance
|
||||
*/
|
||||
void show_popup(InfraredApp* app, int record_amount);
|
||||
|
||||
/** Hide popup window
|
||||
*
|
||||
* @param app - application instance
|
||||
*/
|
||||
void hide_popup(InfraredApp* app);
|
||||
|
||||
/** Propagate progress in popup window
|
||||
*
|
||||
* @param app - application instance
|
||||
*/
|
||||
bool progress_popup(InfraredApp* app);
|
||||
|
||||
/** Item selected callback
|
||||
*
|
||||
* @param context - context
|
||||
* @param index - selected item index
|
||||
*/
|
||||
static void infrared_app_item_callback(void* context, uint32_t index);
|
||||
|
||||
/** Brute Force instance */
|
||||
InfraredAppBruteForce brute_force;
|
||||
|
||||
/** Constructor */
|
||||
InfraredAppSceneUniversalCommon(const char* filename)
|
||||
: brute_force(filename) {
|
||||
}
|
||||
|
||||
/** Destructor */
|
||||
~InfraredAppSceneUniversalCommon() {
|
||||
}
|
||||
};
|
||||
|
||||
class InfraredAppSceneUniversalTV : public InfraredAppSceneUniversalCommon {
|
||||
public:
|
||||
/** Called when enter scene */
|
||||
void on_enter(InfraredApp* app) final;
|
||||
|
||||
/** Constructor
|
||||
* Specifies path to brute force db library */
|
||||
InfraredAppSceneUniversalTV()
|
||||
: InfraredAppSceneUniversalCommon("/ext/infrared/assets/tv.ir") {
|
||||
}
|
||||
|
||||
/** Destructor */
|
||||
~InfraredAppSceneUniversalTV() {
|
||||
}
|
||||
};
|
||||
@ -1,21 +1,21 @@
|
||||
#include "../irda_app.h"
|
||||
#include "../infrared_app.h"
|
||||
#include "gui/modules/dialog_ex.h"
|
||||
#include "irda.h"
|
||||
#include "irda/scene/irda_app_scene.h"
|
||||
#include "infrared.h"
|
||||
#include "infrared/scene/infrared_app_scene.h"
|
||||
#include <string>
|
||||
|
||||
static void dialog_result_callback(DialogExResult result, void* context) {
|
||||
auto app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
auto app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
|
||||
event.type = IrdaAppEvent::Type::DialogExSelected;
|
||||
event.type = InfraredAppEvent::Type::DialogExSelected;
|
||||
event.payload.dialog_ex_result = result;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneAskBack::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneAskBack::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
DialogEx* dialog_ex = view_manager->get_dialog_ex();
|
||||
|
||||
if(app->get_learn_new_remote()) {
|
||||
@ -33,21 +33,21 @@ void IrdaAppSceneAskBack::on_enter(IrdaApp* app) {
|
||||
dialog_ex_set_result_callback(dialog_ex, dialog_result_callback);
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::DialogEx);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::DialogEx);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneAskBack::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneAskBack::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::DialogExSelected) {
|
||||
if(event->type == InfraredAppEvent::Type::DialogExSelected) {
|
||||
switch(event->payload.dialog_ex_result) {
|
||||
case DialogExResultLeft:
|
||||
consumed = true;
|
||||
if(app->get_learn_new_remote()) {
|
||||
app->search_and_switch_to_previous_scene({IrdaApp::Scene::Start});
|
||||
app->search_and_switch_to_previous_scene({InfraredApp::Scene::Start});
|
||||
} else {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{IrdaApp::Scene::Edit, IrdaApp::Scene::Remote});
|
||||
{InfraredApp::Scene::Edit, InfraredApp::Scene::Remote});
|
||||
}
|
||||
break;
|
||||
case DialogExResultCenter:
|
||||
@ -62,12 +62,12 @@ bool IrdaAppSceneAskBack::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
}
|
||||
}
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::Back) {
|
||||
if(event->type == InfraredAppEvent::Type::Back) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneAskBack::on_exit(IrdaApp* app) {
|
||||
void InfraredAppSceneAskBack::on_exit(InfraredApp* app) {
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
#include "../irda_app.h"
|
||||
#include "../infrared_app.h"
|
||||
#include "gui/modules/submenu.h"
|
||||
|
||||
typedef enum {
|
||||
@ -10,17 +10,17 @@ typedef enum {
|
||||
} SubmenuIndex;
|
||||
|
||||
static void submenu_callback(void* context, uint32_t index) {
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
|
||||
event.type = IrdaAppEvent::Type::MenuSelected;
|
||||
event.type = InfraredAppEvent::Type::MenuSelected;
|
||||
event.payload.menu_index = index;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneEdit::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneEdit::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_add_item(submenu, "Add key", SubmenuIndexAddKey, submenu_callback, app);
|
||||
@ -31,38 +31,38 @@ void IrdaAppSceneEdit::on_enter(IrdaApp* app) {
|
||||
submenu_set_selected_item(submenu, submenu_item_selected);
|
||||
submenu_item_selected = 0;
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::Submenu);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneEdit::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneEdit::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::MenuSelected) {
|
||||
if(event->type == InfraredAppEvent::Type::MenuSelected) {
|
||||
submenu_item_selected = event->payload.menu_index;
|
||||
switch(event->payload.menu_index) {
|
||||
case SubmenuIndexAddKey:
|
||||
app->set_learn_new_remote(false);
|
||||
app->switch_to_next_scene(IrdaApp::Scene::Learn);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::Learn);
|
||||
break;
|
||||
case SubmenuIndexRenameKey:
|
||||
app->set_edit_action(IrdaApp::EditAction::Rename);
|
||||
app->set_edit_element(IrdaApp::EditElement::Button);
|
||||
app->switch_to_next_scene(IrdaApp::Scene::EditKeySelect);
|
||||
app->set_edit_action(InfraredApp::EditAction::Rename);
|
||||
app->set_edit_element(InfraredApp::EditElement::Button);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::EditKeySelect);
|
||||
break;
|
||||
case SubmenuIndexDeleteKey:
|
||||
app->set_edit_action(IrdaApp::EditAction::Delete);
|
||||
app->set_edit_element(IrdaApp::EditElement::Button);
|
||||
app->switch_to_next_scene(IrdaApp::Scene::EditKeySelect);
|
||||
app->set_edit_action(InfraredApp::EditAction::Delete);
|
||||
app->set_edit_element(InfraredApp::EditElement::Button);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::EditKeySelect);
|
||||
break;
|
||||
case SubmenuIndexRenameRemote:
|
||||
app->set_edit_action(IrdaApp::EditAction::Rename);
|
||||
app->set_edit_element(IrdaApp::EditElement::Remote);
|
||||
app->switch_to_next_scene(IrdaApp::Scene::EditRename);
|
||||
app->set_edit_action(InfraredApp::EditAction::Rename);
|
||||
app->set_edit_element(InfraredApp::EditElement::Remote);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::EditRename);
|
||||
break;
|
||||
case SubmenuIndexDeleteRemote:
|
||||
app->set_edit_action(IrdaApp::EditAction::Delete);
|
||||
app->set_edit_element(IrdaApp::EditElement::Remote);
|
||||
app->switch_to_next_scene(IrdaApp::Scene::EditDelete);
|
||||
app->set_edit_action(InfraredApp::EditAction::Delete);
|
||||
app->set_edit_element(InfraredApp::EditElement::Remote);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::EditDelete);
|
||||
break;
|
||||
}
|
||||
consumed = true;
|
||||
@ -71,8 +71,8 @@ bool IrdaAppSceneEdit::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneEdit::on_exit(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneEdit::on_exit(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_reset(submenu);
|
||||
@ -1,25 +1,25 @@
|
||||
#include "../irda_app.h"
|
||||
#include "irda.h"
|
||||
#include "irda/scene/irda_app_scene.h"
|
||||
#include "../infrared_app.h"
|
||||
#include "infrared.h"
|
||||
#include "infrared/scene/infrared_app_scene.h"
|
||||
#include <string>
|
||||
|
||||
static void dialog_result_callback(DialogExResult result, void* context) {
|
||||
auto app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
auto app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
|
||||
event.type = IrdaAppEvent::Type::DialogExSelected;
|
||||
event.type = InfraredAppEvent::Type::DialogExSelected;
|
||||
event.payload.dialog_ex_result = result;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneEditDelete::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
DialogEx* dialog_ex = view_manager->get_dialog_ex();
|
||||
|
||||
auto remote_manager = app->get_remote_manager();
|
||||
|
||||
if(app->get_edit_element() == IrdaApp::EditElement::Button) {
|
||||
if(app->get_edit_element() == InfraredApp::EditElement::Button) {
|
||||
auto signal = remote_manager->get_button_data(app->get_current_button());
|
||||
dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop);
|
||||
if(!signal.is_raw()) {
|
||||
@ -28,10 +28,10 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) {
|
||||
0,
|
||||
"%s\n%s\nA=0x%0*lX C=0x%0*lX",
|
||||
remote_manager->get_button_name(app->get_current_button()).c_str(),
|
||||
irda_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4),
|
||||
infrared_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4),
|
||||
message->address,
|
||||
ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4),
|
||||
ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4),
|
||||
message->command);
|
||||
} else {
|
||||
app->set_text_store(
|
||||
@ -56,13 +56,13 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) {
|
||||
dialog_ex_set_result_callback(dialog_ex, dialog_result_callback);
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::DialogEx);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::DialogEx);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneEditDelete::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneEditDelete::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::DialogExSelected) {
|
||||
if(event->type == InfraredAppEvent::Type::DialogExSelected) {
|
||||
switch(event->payload.dialog_ex_result) {
|
||||
case DialogExResultLeft:
|
||||
app->switch_to_previous_scene();
|
||||
@ -73,18 +73,18 @@ bool IrdaAppSceneEditDelete::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
case DialogExResultRight: {
|
||||
auto remote_manager = app->get_remote_manager();
|
||||
bool result = false;
|
||||
if(app->get_edit_element() == IrdaApp::EditElement::Remote) {
|
||||
if(app->get_edit_element() == InfraredApp::EditElement::Remote) {
|
||||
result = remote_manager->delete_remote();
|
||||
} else {
|
||||
result = remote_manager->delete_button(app->get_current_button());
|
||||
app->set_current_button(IrdaApp::ButtonNA);
|
||||
app->set_current_button(InfraredApp::ButtonNA);
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{IrdaApp::Scene::RemoteList, IrdaApp::Scene::Start});
|
||||
{InfraredApp::Scene::RemoteList, InfraredApp::Scene::Start});
|
||||
} else {
|
||||
app->switch_to_next_scene(IrdaApp::Scene::EditDeleteDone);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::EditDeleteDone);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -96,5 +96,5 @@ bool IrdaAppSceneEditDelete::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneEditDelete::on_exit(IrdaApp* app) {
|
||||
void InfraredAppSceneEditDelete::on_exit(InfraredApp* app) {
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
#include "../infrared_app.h"
|
||||
|
||||
void InfraredAppSceneEditDeleteDone::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Popup* popup = view_manager->get_popup();
|
||||
|
||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
|
||||
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
|
||||
popup_set_callback(popup, InfraredApp::popup_callback);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::Popup);
|
||||
}
|
||||
|
||||
bool InfraredAppSceneEditDeleteDone::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InfraredAppEvent::Type::PopupTimer) {
|
||||
if(app->get_edit_element() == InfraredApp::EditElement::Remote) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList});
|
||||
} else {
|
||||
app->search_and_switch_to_previous_scene({InfraredApp::Scene::Remote});
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void InfraredAppSceneEditDeleteDone::on_exit(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Popup* popup = view_manager->get_popup();
|
||||
popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop);
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
#include "../infrared_app.h"
|
||||
#include "gui/modules/submenu.h"
|
||||
|
||||
static void submenu_callback(void* context, uint32_t index) {
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
|
||||
event.type = InfraredAppEvent::Type::MenuSelected;
|
||||
event.payload.menu_index = index;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void InfraredAppSceneEditKeySelect::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
int item_number = 0;
|
||||
|
||||
const char* header =
|
||||
app->get_edit_action() == InfraredApp::EditAction::Rename ? "Rename key:" : "Delete key:";
|
||||
submenu_set_header(submenu, header);
|
||||
|
||||
auto remote_manager = app->get_remote_manager();
|
||||
buttons_names = remote_manager->get_button_list();
|
||||
for(const auto& it : buttons_names) {
|
||||
submenu_add_item(submenu, it.c_str(), item_number++, submenu_callback, app);
|
||||
}
|
||||
if((item_number > 0) && (app->get_current_button() != InfraredApp::ButtonNA)) {
|
||||
submenu_set_selected_item(submenu, app->get_current_button());
|
||||
app->set_current_button(InfraredApp::ButtonNA);
|
||||
}
|
||||
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu);
|
||||
}
|
||||
|
||||
bool InfraredAppSceneEditKeySelect::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InfraredAppEvent::Type::MenuSelected) {
|
||||
app->set_current_button(event->payload.menu_index);
|
||||
consumed = true;
|
||||
if(app->get_edit_action() == InfraredApp::EditAction::Rename) {
|
||||
app->switch_to_next_scene(InfraredApp::Scene::EditRename);
|
||||
} else {
|
||||
app->switch_to_next_scene(InfraredApp::Scene::EditDelete);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void InfraredAppSceneEditKeySelect::on_exit(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_reset(submenu);
|
||||
}
|
||||
@ -1,16 +1,16 @@
|
||||
#include "../irda_app.h"
|
||||
#include "../infrared_app.h"
|
||||
|
||||
void IrdaAppSceneEditRename::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneEditRename::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
TextInput* text_input = view_manager->get_text_input();
|
||||
size_t enter_name_length = 0;
|
||||
|
||||
auto remote_manager = app->get_remote_manager();
|
||||
if(app->get_edit_element() == IrdaApp::EditElement::Button) {
|
||||
furi_assert(app->get_current_button() != IrdaApp::ButtonNA);
|
||||
if(app->get_edit_element() == InfraredApp::EditElement::Button) {
|
||||
furi_assert(app->get_current_button() != InfraredApp::ButtonNA);
|
||||
auto button_name = remote_manager->get_button_name(app->get_current_button());
|
||||
char* buffer_str = app->get_text_store(0);
|
||||
size_t max_len = IrdaAppRemoteManager::max_button_name_length;
|
||||
size_t max_len = InfraredAppRemoteManager::max_button_name_length;
|
||||
strncpy(buffer_str, button_name.c_str(), max_len);
|
||||
buffer_str[max_len + 1] = 0;
|
||||
enter_name_length = max_len;
|
||||
@ -18,43 +18,43 @@ void IrdaAppSceneEditRename::on_enter(IrdaApp* app) {
|
||||
} else {
|
||||
auto remote_name = remote_manager->get_remote_name();
|
||||
strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size());
|
||||
enter_name_length = IrdaAppRemoteManager::max_remote_name_length;
|
||||
enter_name_length = InfraredAppRemoteManager::max_remote_name_length;
|
||||
text_input_set_header_text(text_input, "Name the remote");
|
||||
|
||||
ValidatorIsFile* validator_is_file =
|
||||
validator_is_file_alloc_init(app->irda_directory, app->irda_extension);
|
||||
validator_is_file_alloc_init(app->infrared_directory, app->infrared_extension);
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
}
|
||||
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
IrdaApp::text_input_callback,
|
||||
InfraredApp::text_input_callback,
|
||||
app,
|
||||
app->get_text_store(0),
|
||||
enter_name_length,
|
||||
false);
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::TextInput);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneEditRename::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneEditRename::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::TextEditDone) {
|
||||
if(event->type == InfraredAppEvent::Type::TextEditDone) {
|
||||
auto remote_manager = app->get_remote_manager();
|
||||
bool result = false;
|
||||
if(app->get_edit_element() == IrdaApp::EditElement::Button) {
|
||||
if(app->get_edit_element() == InfraredApp::EditElement::Button) {
|
||||
result =
|
||||
remote_manager->rename_button(app->get_current_button(), app->get_text_store(0));
|
||||
app->set_current_button(IrdaApp::ButtonNA);
|
||||
app->set_current_button(InfraredApp::ButtonNA);
|
||||
} else {
|
||||
result = remote_manager->rename_remote(app->get_text_store(0));
|
||||
}
|
||||
if(!result) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{IrdaApp::Scene::Start, IrdaApp::Scene::RemoteList});
|
||||
{InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList});
|
||||
} else {
|
||||
app->switch_to_next_scene_without_saving(IrdaApp::Scene::EditRenameDone);
|
||||
app->switch_to_next_scene_without_saving(InfraredApp::Scene::EditRenameDone);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
@ -62,7 +62,7 @@ bool IrdaAppSceneEditRename::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneEditRename::on_exit(IrdaApp* app) {
|
||||
void InfraredAppSceneEditRename::on_exit(InfraredApp* app) {
|
||||
TextInput* text_input = app->get_view_manager()->get_text_input();
|
||||
|
||||
void* validator_context = text_input_get_validator_callback_context(text_input);
|
||||
@ -0,0 +1,31 @@
|
||||
#include "../infrared_app.h"
|
||||
|
||||
void InfraredAppSceneEditRenameDone::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Popup* popup = view_manager->get_popup();
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
|
||||
popup_set_callback(popup, InfraredApp::popup_callback);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::Popup);
|
||||
}
|
||||
|
||||
bool InfraredAppSceneEditRenameDone::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InfraredAppEvent::Type::PopupTimer) {
|
||||
app->switch_to_next_scene(InfraredApp::Scene::Remote);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void InfraredAppSceneEditRenameDone::on_exit(InfraredApp* app) {
|
||||
}
|
||||
75
applications/infrared/scene/infrared_app_scene_learn.cpp
Normal file
75
applications/infrared/scene/infrared_app_scene_learn.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include "../infrared_app.h"
|
||||
#include "../infrared_app_event.h"
|
||||
#include "infrared.h"
|
||||
#include <infrared_worker.h>
|
||||
|
||||
static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) {
|
||||
furi_assert(context);
|
||||
furi_assert(received_signal);
|
||||
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
|
||||
if(infrared_worker_signal_is_decoded(received_signal)) {
|
||||
InfraredAppSignal signal(infrared_worker_get_decoded_signal(received_signal));
|
||||
app->set_received_signal(signal);
|
||||
} else {
|
||||
const uint32_t* timings;
|
||||
size_t timings_cnt;
|
||||
infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||
InfraredAppSignal signal(
|
||||
timings, timings_cnt, INFRARED_COMMON_CARRIER_FREQUENCY, INFRARED_COMMON_DUTY_CYCLE);
|
||||
app->set_received_signal(signal);
|
||||
}
|
||||
|
||||
infrared_worker_rx_set_received_signal_callback(app->get_infrared_worker(), NULL, NULL);
|
||||
InfraredAppEvent event;
|
||||
event.type = InfraredAppEvent::Type::InfraredMessageReceived;
|
||||
auto view_manager = app->get_view_manager();
|
||||
view_manager->send_event(&event);
|
||||
}
|
||||
|
||||
void InfraredAppSceneLearn::on_enter(InfraredApp* app) {
|
||||
auto view_manager = app->get_view_manager();
|
||||
auto popup = view_manager->get_popup();
|
||||
|
||||
auto worker = app->get_infrared_worker();
|
||||
infrared_worker_rx_set_received_signal_callback(worker, signal_received_callback, app);
|
||||
infrared_worker_rx_start(worker);
|
||||
|
||||
popup_set_icon(popup, 0, 32, &I_InfraredLearnShort_128x31);
|
||||
popup_set_text(
|
||||
popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter);
|
||||
popup_set_callback(popup, NULL);
|
||||
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::Popup);
|
||||
}
|
||||
|
||||
bool InfraredAppSceneLearn::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
switch(event->type) {
|
||||
case InfraredAppEvent::Type::Tick:
|
||||
consumed = true;
|
||||
app->notify_red_blink();
|
||||
break;
|
||||
case InfraredAppEvent::Type::InfraredMessageReceived:
|
||||
app->notify_success();
|
||||
app->switch_to_next_scene_without_saving(InfraredApp::Scene::LearnSuccess);
|
||||
break;
|
||||
case InfraredAppEvent::Type::Back:
|
||||
consumed = true;
|
||||
app->switch_to_previous_scene();
|
||||
break;
|
||||
default:
|
||||
furi_assert(0);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void InfraredAppSceneLearn::on_exit(InfraredApp* app) {
|
||||
infrared_worker_rx_stop(app->get_infrared_worker());
|
||||
auto view_manager = app->get_view_manager();
|
||||
auto popup = view_manager->get_popup();
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
#include "../irda_app.h"
|
||||
#include "../infrared_app.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneLearnDone::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Popup* popup = view_manager->get_popup();
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
@ -14,28 +14,28 @@ void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) {
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
}
|
||||
|
||||
popup_set_callback(popup, IrdaApp::popup_callback);
|
||||
popup_set_callback(popup, InfraredApp::popup_callback);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::Popup);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::Popup);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneLearnDone::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneLearnDone::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::PopupTimer) {
|
||||
app->switch_to_next_scene(IrdaApp::Scene::Remote);
|
||||
if(event->type == InfraredAppEvent::Type::PopupTimer) {
|
||||
app->switch_to_next_scene(InfraredApp::Scene::Remote);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneLearnDone::on_exit(IrdaApp* app) {
|
||||
void InfraredAppSceneLearnDone::on_exit(InfraredApp* app) {
|
||||
app->set_learn_new_remote(false);
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Popup* popup = view_manager->get_popup();
|
||||
popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop);
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
#include "../irda_app.h"
|
||||
#include "../infrared_app.h"
|
||||
#include "gui/modules/text_input.h"
|
||||
|
||||
void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneLearnEnterName::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
TextInput* text_input = view_manager->get_text_input();
|
||||
|
||||
auto signal = app->get_received_signal();
|
||||
@ -12,8 +12,8 @@ void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) {
|
||||
app->set_text_store(
|
||||
0,
|
||||
"%.4s_%0*lX",
|
||||
irda_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4),
|
||||
infrared_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4),
|
||||
message->command);
|
||||
} else {
|
||||
auto raw_signal = signal.get_raw_signal();
|
||||
@ -23,19 +23,19 @@ void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) {
|
||||
text_input_set_header_text(text_input, "Name the key");
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
IrdaApp::text_input_callback,
|
||||
InfraredApp::text_input_callback,
|
||||
app,
|
||||
app->get_text_store(0),
|
||||
IrdaAppRemoteManager::max_button_name_length,
|
||||
InfraredAppRemoteManager::max_button_name_length,
|
||||
true);
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::TextInput);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneLearnEnterName::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneLearnEnterName::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::TextEditDone) {
|
||||
if(event->type == InfraredAppEvent::Type::TextEditDone) {
|
||||
auto remote_manager = app->get_remote_manager();
|
||||
bool result = false;
|
||||
if(app->get_learn_new_remote()) {
|
||||
@ -48,13 +48,13 @@ bool IrdaAppSceneLearnEnterName::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
|
||||
if(!result) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{IrdaApp::Scene::Start, IrdaApp::Scene::RemoteList});
|
||||
{InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList});
|
||||
} else {
|
||||
app->switch_to_next_scene_without_saving(IrdaApp::Scene::LearnDone);
|
||||
app->switch_to_next_scene_without_saving(InfraredApp::Scene::LearnDone);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneLearnEnterName::on_exit(IrdaApp* app) {
|
||||
void InfraredAppSceneLearnEnterName::on_exit(InfraredApp* app) {
|
||||
}
|
||||
@ -3,42 +3,44 @@
|
||||
#include <memory>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "../irda_app.h"
|
||||
#include "irda.h"
|
||||
#include "../infrared_app.h"
|
||||
#include "infrared.h"
|
||||
|
||||
static void dialog_result_callback(DialogExResult result, void* context) {
|
||||
auto app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
auto app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
|
||||
event.type = IrdaAppEvent::Type::DialogExSelected;
|
||||
event.type = InfraredAppEvent::Type::DialogExSelected;
|
||||
event.payload.dialog_ex_result = result;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneLearnSuccess::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
DialogEx* dialog_ex = view_manager->get_dialog_ex();
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedIrLearnSuccess);
|
||||
app->notify_green_on();
|
||||
|
||||
irda_worker_tx_set_get_signal_callback(
|
||||
app->get_irda_worker(), irda_worker_tx_get_signal_steady_callback, app);
|
||||
irda_worker_tx_set_signal_sent_callback(
|
||||
app->get_irda_worker(), IrdaApp::signal_sent_callback, app);
|
||||
infrared_worker_tx_set_get_signal_callback(
|
||||
app->get_infrared_worker(), infrared_worker_tx_get_signal_steady_callback, app);
|
||||
infrared_worker_tx_set_signal_sent_callback(
|
||||
app->get_infrared_worker(), InfraredApp::signal_sent_callback, app);
|
||||
|
||||
auto signal = app->get_received_signal();
|
||||
|
||||
if(!signal.is_raw()) {
|
||||
auto message = &signal.get_message();
|
||||
uint8_t adr_digits = ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4);
|
||||
uint8_t cmd_digits = ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4);
|
||||
uint8_t adr_digits =
|
||||
ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4);
|
||||
uint8_t cmd_digits =
|
||||
ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4);
|
||||
uint8_t max_digits = MAX(adr_digits, cmd_digits);
|
||||
max_digits = MIN(max_digits, 7);
|
||||
size_t label_x_offset = 63 + (7 - max_digits) * 3;
|
||||
|
||||
app->set_text_store(0, "%s", irda_get_protocol_name(message->protocol));
|
||||
app->set_text_store(0, "%s", infrared_get_protocol_name(message->protocol));
|
||||
app->set_text_store(
|
||||
1,
|
||||
"A: 0x%0*lX\nC: 0x%0*lX\n",
|
||||
@ -64,24 +66,24 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) {
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_enable_extended_events(dialog_ex);
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::DialogEx);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::DialogEx);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneLearnSuccess::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
if(event->type == IrdaAppEvent::Type::Tick) {
|
||||
if(event->type == InfraredAppEvent::Type::Tick) {
|
||||
/* Send event every tick to suppress any switching off green light */
|
||||
if(!button_pressed) {
|
||||
app->notify_green_on();
|
||||
}
|
||||
}
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::DialogExSelected) {
|
||||
if(event->type == InfraredAppEvent::Type::DialogExSelected) {
|
||||
switch(event->payload.dialog_ex_result) {
|
||||
case DialogExResultLeft:
|
||||
consumed = true;
|
||||
if(!button_pressed) {
|
||||
app->switch_to_next_scene_without_saving(IrdaApp::Scene::Learn);
|
||||
app->switch_to_next_scene_without_saving(InfraredApp::Scene::Learn);
|
||||
}
|
||||
break;
|
||||
case DialogExResultRight: {
|
||||
@ -89,7 +91,7 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
FileWorkerCpp file_worker;
|
||||
if(!button_pressed) {
|
||||
if(file_worker.check_errors()) {
|
||||
app->switch_to_next_scene(IrdaApp::Scene::LearnEnterName);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName);
|
||||
} else {
|
||||
app->switch_to_previous_scene();
|
||||
}
|
||||
@ -103,21 +105,22 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
|
||||
auto signal = app->get_received_signal();
|
||||
if(signal.is_raw()) {
|
||||
irda_worker_set_raw_signal(
|
||||
app->get_irda_worker(),
|
||||
infrared_worker_set_raw_signal(
|
||||
app->get_infrared_worker(),
|
||||
signal.get_raw_signal().timings,
|
||||
signal.get_raw_signal().timings_cnt);
|
||||
} else {
|
||||
irda_worker_set_decoded_signal(app->get_irda_worker(), &signal.get_message());
|
||||
infrared_worker_set_decoded_signal(
|
||||
app->get_infrared_worker(), &signal.get_message());
|
||||
}
|
||||
|
||||
irda_worker_tx_start(app->get_irda_worker());
|
||||
infrared_worker_tx_start(app->get_infrared_worker());
|
||||
}
|
||||
break;
|
||||
case DialogExReleaseCenter:
|
||||
if(button_pressed) {
|
||||
button_pressed = false;
|
||||
irda_worker_tx_stop(app->get_irda_worker());
|
||||
infrared_worker_tx_stop(app->get_infrared_worker());
|
||||
app->notify_green_off();
|
||||
}
|
||||
break;
|
||||
@ -126,9 +129,9 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
}
|
||||
}
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::Back) {
|
||||
if(event->type == InfraredAppEvent::Type::Back) {
|
||||
if(!button_pressed) {
|
||||
app->switch_to_next_scene(IrdaApp::Scene::AskBack);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::AskBack);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
@ -136,11 +139,11 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneLearnSuccess::on_exit(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneLearnSuccess::on_exit(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
DialogEx* dialog_ex = view_manager->get_dialog_ex();
|
||||
dialog_ex_reset(dialog_ex);
|
||||
app->notify_green_off();
|
||||
irda_worker_tx_set_get_signal_callback(app->get_irda_worker(), nullptr, nullptr);
|
||||
irda_worker_tx_set_signal_sent_callback(app->get_irda_worker(), nullptr, nullptr);
|
||||
infrared_worker_tx_set_get_signal_callback(app->get_infrared_worker(), nullptr, nullptr);
|
||||
infrared_worker_tx_set_signal_sent_callback(app->get_infrared_worker(), nullptr, nullptr);
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
#include <gui/modules/button_menu.h>
|
||||
#include <input/input.h>
|
||||
#include <irda_worker.h>
|
||||
#include <infrared_worker.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include "../irda_app.h"
|
||||
#include "../irda_app_view_manager.h"
|
||||
#include "../infrared_app.h"
|
||||
#include "../infrared_app_view_manager.h"
|
||||
|
||||
typedef enum {
|
||||
ButtonIndexPlus = -2,
|
||||
@ -12,15 +12,15 @@ typedef enum {
|
||||
} ButtonIndex;
|
||||
|
||||
static void button_menu_callback(void* context, int32_t index, InputType type) {
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
|
||||
if(type == InputTypePress) {
|
||||
event.type = IrdaAppEvent::Type::MenuSelectedPress;
|
||||
event.type = InfraredAppEvent::Type::MenuSelectedPress;
|
||||
} else if(type == InputTypeRelease) {
|
||||
event.type = IrdaAppEvent::Type::MenuSelectedRelease;
|
||||
event.type = InfraredAppEvent::Type::MenuSelectedRelease;
|
||||
} else if(type == InputTypeShort) {
|
||||
event.type = IrdaAppEvent::Type::MenuSelected;
|
||||
event.type = InfraredAppEvent::Type::MenuSelected;
|
||||
} else {
|
||||
furi_assert(0);
|
||||
}
|
||||
@ -30,17 +30,17 @@ static void button_menu_callback(void* context, int32_t index, InputType type) {
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneRemote::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneRemote::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
ButtonMenu* button_menu = view_manager->get_button_menu();
|
||||
auto remote_manager = app->get_remote_manager();
|
||||
int i = 0;
|
||||
button_pressed = false;
|
||||
|
||||
irda_worker_tx_set_get_signal_callback(
|
||||
app->get_irda_worker(), irda_worker_tx_get_signal_steady_callback, app);
|
||||
irda_worker_tx_set_signal_sent_callback(
|
||||
app->get_irda_worker(), IrdaApp::signal_sent_callback, app);
|
||||
infrared_worker_tx_set_get_signal_callback(
|
||||
app->get_infrared_worker(), infrared_worker_tx_get_signal_steady_callback, app);
|
||||
infrared_worker_tx_set_signal_sent_callback(
|
||||
app->get_infrared_worker(), InfraredApp::signal_sent_callback, app);
|
||||
buttons_names = remote_manager->get_button_list();
|
||||
|
||||
i = 0;
|
||||
@ -60,32 +60,32 @@ void IrdaAppSceneRemote::on_enter(IrdaApp* app) {
|
||||
button_menu_set_selected_item(button_menu, buttonmenu_item_selected);
|
||||
buttonmenu_item_selected = ButtonIndexNA;
|
||||
}
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::ButtonMenu);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneRemote::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = true;
|
||||
|
||||
if((event->type == IrdaAppEvent::Type::MenuSelected) ||
|
||||
(event->type == IrdaAppEvent::Type::MenuSelectedPress) ||
|
||||
(event->type == IrdaAppEvent::Type::MenuSelectedRelease)) {
|
||||
if((event->type == InfraredAppEvent::Type::MenuSelected) ||
|
||||
(event->type == InfraredAppEvent::Type::MenuSelectedPress) ||
|
||||
(event->type == InfraredAppEvent::Type::MenuSelectedRelease)) {
|
||||
switch(event->payload.menu_index) {
|
||||
case ButtonIndexPlus:
|
||||
furi_assert(event->type == IrdaAppEvent::Type::MenuSelected);
|
||||
furi_assert(event->type == InfraredAppEvent::Type::MenuSelected);
|
||||
app->notify_click();
|
||||
buttonmenu_item_selected = event->payload.menu_index;
|
||||
app->set_learn_new_remote(false);
|
||||
app->switch_to_next_scene(IrdaApp::Scene::Learn);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::Learn);
|
||||
break;
|
||||
case ButtonIndexEdit:
|
||||
furi_assert(event->type == IrdaAppEvent::Type::MenuSelected);
|
||||
furi_assert(event->type == InfraredAppEvent::Type::MenuSelected);
|
||||
app->notify_click();
|
||||
buttonmenu_item_selected = event->payload.menu_index;
|
||||
app->switch_to_next_scene(IrdaApp::Scene::Edit);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::Edit);
|
||||
break;
|
||||
default:
|
||||
furi_assert(event->type != IrdaAppEvent::Type::MenuSelected);
|
||||
bool pressed = (event->type == IrdaAppEvent::Type::MenuSelectedPress);
|
||||
furi_assert(event->type != InfraredAppEvent::Type::MenuSelected);
|
||||
bool pressed = (event->type == InfraredAppEvent::Type::MenuSelectedPress);
|
||||
|
||||
if(pressed && !button_pressed) {
|
||||
button_pressed = true;
|
||||
@ -94,28 +94,28 @@ bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
auto button_signal =
|
||||
app->get_remote_manager()->get_button_data(event->payload.menu_index);
|
||||
if(button_signal.is_raw()) {
|
||||
irda_worker_set_raw_signal(
|
||||
app->get_irda_worker(),
|
||||
infrared_worker_set_raw_signal(
|
||||
app->get_infrared_worker(),
|
||||
button_signal.get_raw_signal().timings,
|
||||
button_signal.get_raw_signal().timings_cnt);
|
||||
} else {
|
||||
irda_worker_set_decoded_signal(
|
||||
app->get_irda_worker(), &button_signal.get_message());
|
||||
infrared_worker_set_decoded_signal(
|
||||
app->get_infrared_worker(), &button_signal.get_message());
|
||||
}
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedIrSend);
|
||||
irda_worker_tx_start(app->get_irda_worker());
|
||||
infrared_worker_tx_start(app->get_infrared_worker());
|
||||
} else if(!pressed && button_pressed) {
|
||||
button_pressed = false;
|
||||
irda_worker_tx_stop(app->get_irda_worker());
|
||||
infrared_worker_tx_stop(app->get_infrared_worker());
|
||||
app->notify_green_off();
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if(event->type == IrdaAppEvent::Type::Back) {
|
||||
} else if(event->type == InfraredAppEvent::Type::Back) {
|
||||
if(!button_pressed) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{IrdaApp::Scene::Start, IrdaApp::Scene::RemoteList});
|
||||
{InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList});
|
||||
}
|
||||
} else {
|
||||
consumed = false;
|
||||
@ -124,10 +124,10 @@ bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneRemote::on_exit(IrdaApp* app) {
|
||||
irda_worker_tx_set_get_signal_callback(app->get_irda_worker(), nullptr, nullptr);
|
||||
irda_worker_tx_set_signal_sent_callback(app->get_irda_worker(), nullptr, nullptr);
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneRemote::on_exit(InfraredApp* app) {
|
||||
infrared_worker_tx_set_get_signal_callback(app->get_infrared_worker(), nullptr, nullptr);
|
||||
infrared_worker_tx_set_signal_sent_callback(app->get_infrared_worker(), nullptr, nullptr);
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
ButtonMenu* button_menu = view_manager->get_button_menu();
|
||||
|
||||
button_menu_reset(button_menu);
|
||||
@ -1,9 +1,9 @@
|
||||
#include "../irda_app.h"
|
||||
#include "irda/irda_app_event.h"
|
||||
#include "../infrared_app.h"
|
||||
#include "infrared/infrared_app_event.h"
|
||||
#include <text_store.h>
|
||||
#include <file_worker_cpp.h>
|
||||
|
||||
void IrdaAppSceneRemoteList::on_enter(IrdaApp* app) {
|
||||
void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
FileWorkerCpp file_worker;
|
||||
@ -13,23 +13,24 @@ void IrdaAppSceneRemoteList::on_enter(IrdaApp* app) {
|
||||
auto last_selected_remote = remote_manager->get_remote_name();
|
||||
const char* last_selected_remote_name =
|
||||
last_selected_remote.size() ? last_selected_remote.c_str() : nullptr;
|
||||
auto filename_ts = std::make_unique<TextStore>(IrdaAppRemoteManager::max_remote_name_length);
|
||||
auto filename_ts =
|
||||
std::make_unique<TextStore>(InfraredAppRemoteManager::max_remote_name_length);
|
||||
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
ButtonMenu* button_menu = view_manager->get_button_menu();
|
||||
button_menu_reset(button_menu);
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::ButtonMenu);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu);
|
||||
|
||||
file_select_result = file_worker.file_select(
|
||||
IrdaApp::irda_directory,
|
||||
IrdaApp::irda_extension,
|
||||
InfraredApp::infrared_directory,
|
||||
InfraredApp::infrared_extension,
|
||||
filename_ts->text,
|
||||
filename_ts->text_size,
|
||||
last_selected_remote_name);
|
||||
|
||||
if(file_select_result) {
|
||||
if(remote_manager->load(std::string(filename_ts->text))) {
|
||||
app->switch_to_next_scene(IrdaApp::Scene::Remote);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::Remote);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
@ -39,11 +40,11 @@ void IrdaAppSceneRemoteList::on_enter(IrdaApp* app) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IrdaAppSceneRemoteList::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneRemoteList::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneRemoteList::on_exit(IrdaApp* app) {
|
||||
void InfraredAppSceneRemoteList::on_exit(InfraredApp* app) {
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
#include "../irda_app.h"
|
||||
#include "../infrared_app.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexUniversalLibrary,
|
||||
@ -7,17 +7,17 @@ typedef enum {
|
||||
} SubmenuIndex;
|
||||
|
||||
static void submenu_callback(void* context, uint32_t index) {
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
|
||||
event.type = IrdaAppEvent::Type::MenuSelected;
|
||||
event.type = InfraredAppEvent::Type::MenuSelected;
|
||||
event.payload.menu_index = index;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneStart::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneStart::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_add_item(
|
||||
@ -28,24 +28,24 @@ void IrdaAppSceneStart::on_enter(IrdaApp* app) {
|
||||
submenu_set_selected_item(submenu, submenu_item_selected);
|
||||
submenu_item_selected = 0;
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::Submenu);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneStart::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneStart::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::MenuSelected) {
|
||||
if(event->type == InfraredAppEvent::Type::MenuSelected) {
|
||||
submenu_item_selected = event->payload.menu_index;
|
||||
switch(event->payload.menu_index) {
|
||||
case SubmenuIndexUniversalLibrary:
|
||||
app->switch_to_next_scene(IrdaApp::Scene::Universal);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::Universal);
|
||||
break;
|
||||
case SubmenuIndexLearnNewRemote:
|
||||
app->set_learn_new_remote(true);
|
||||
app->switch_to_next_scene(IrdaApp::Scene::Learn);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::Learn);
|
||||
break;
|
||||
case SubmenuIndexSavedRemotes:
|
||||
app->switch_to_next_scene(IrdaApp::Scene::RemoteList);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::RemoteList);
|
||||
break;
|
||||
default:
|
||||
furi_assert(0);
|
||||
@ -57,8 +57,8 @@ bool IrdaAppSceneStart::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneStart::on_exit(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneStart::on_exit(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
app->get_remote_manager()->reset_remote();
|
||||
@ -1,4 +1,4 @@
|
||||
#include "../irda_app.h"
|
||||
#include "../infrared_app.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexUniversalTV,
|
||||
@ -7,40 +7,40 @@ typedef enum {
|
||||
} SubmenuIndex;
|
||||
|
||||
static void submenu_callback(void* context, uint32_t index) {
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
|
||||
event.type = IrdaAppEvent::Type::MenuSelected;
|
||||
event.type = InfraredAppEvent::Type::MenuSelected;
|
||||
event.payload.menu_index = index;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneUniversal::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneUniversal::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_add_item(submenu, "TV's", SubmenuIndexUniversalTV, submenu_callback, app);
|
||||
submenu_set_selected_item(submenu, submenu_item_selected);
|
||||
submenu_item_selected = 0;
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::Submenu);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneUniversal::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool InfraredAppSceneUniversal::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::MenuSelected) {
|
||||
if(event->type == InfraredAppEvent::Type::MenuSelected) {
|
||||
submenu_item_selected = event->payload.menu_index;
|
||||
switch(event->payload.menu_index) {
|
||||
case SubmenuIndexUniversalTV:
|
||||
app->switch_to_next_scene(IrdaApp::Scene::UniversalTV);
|
||||
app->switch_to_next_scene(InfraredApp::Scene::UniversalTV);
|
||||
break;
|
||||
case SubmenuIndexUniversalAudio:
|
||||
// app->switch_to_next_scene(IrdaApp::Scene::UniversalAudio);
|
||||
// app->switch_to_next_scene(InfraredApp::Scene::UniversalAudio);
|
||||
break;
|
||||
case SubmenuIndexUniversalAirConditioner:
|
||||
// app->switch_to_next_scene(IrdaApp::Scene::UniversalAirConditioner);
|
||||
// app->switch_to_next_scene(InfraredApp::Scene::UniversalAirConditioner);
|
||||
break;
|
||||
}
|
||||
consumed = true;
|
||||
@ -49,8 +49,8 @@ bool IrdaAppSceneUniversal::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneUniversal::on_exit(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneUniversal::on_exit(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_reset(submenu);
|
||||
@ -0,0 +1,101 @@
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <gui/modules/button_menu.h>
|
||||
#include <gui/modules/button_panel.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_stack.h>
|
||||
|
||||
#include "../infrared_app.h"
|
||||
#include "infrared/infrared_app_event.h"
|
||||
#include "infrared/infrared_app_view_manager.h"
|
||||
#include "infrared/scene/infrared_app_scene.h"
|
||||
#include "../view/infrared_progress_view.h"
|
||||
|
||||
void InfraredAppSceneUniversalCommon::infrared_app_item_callback(void* context, uint32_t index) {
|
||||
InfraredApp* app = static_cast<InfraredApp*>(context);
|
||||
InfraredAppEvent event;
|
||||
|
||||
event.type = InfraredAppEvent::Type::ButtonPanelPressed;
|
||||
event.payload.menu_index = index;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
static void infrared_progress_back_callback(void* context) {
|
||||
furi_assert(context);
|
||||
auto app = static_cast<InfraredApp*>(context);
|
||||
|
||||
InfraredAppEvent infrared_event = {
|
||||
.type = InfraredAppEvent::Type::Back,
|
||||
};
|
||||
app->get_view_manager()->clear_events();
|
||||
app->get_view_manager()->send_event(&infrared_event);
|
||||
}
|
||||
|
||||
void InfraredAppSceneUniversalCommon::hide_popup(InfraredApp* app) {
|
||||
auto stack_view = app->get_view_manager()->get_universal_view_stack();
|
||||
auto progress_view = app->get_view_manager()->get_progress();
|
||||
view_stack_remove_view(stack_view, infrared_progress_view_get_view(progress_view));
|
||||
}
|
||||
|
||||
void InfraredAppSceneUniversalCommon::show_popup(InfraredApp* app, int record_amount) {
|
||||
auto stack_view = app->get_view_manager()->get_universal_view_stack();
|
||||
auto progress_view = app->get_view_manager()->get_progress();
|
||||
infrared_progress_view_set_progress_total(progress_view, record_amount);
|
||||
infrared_progress_view_set_back_callback(progress_view, infrared_progress_back_callback, app);
|
||||
view_stack_add_view(stack_view, infrared_progress_view_get_view(progress_view));
|
||||
}
|
||||
|
||||
bool InfraredAppSceneUniversalCommon::progress_popup(InfraredApp* app) {
|
||||
auto progress_view = app->get_view_manager()->get_progress();
|
||||
return infrared_progress_view_increase_progress(progress_view);
|
||||
}
|
||||
|
||||
bool InfraredAppSceneUniversalCommon::on_event(InfraredApp* app, InfraredAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(brute_force_started) {
|
||||
if(event->type == InfraredAppEvent::Type::Tick) {
|
||||
auto view_manager = app->get_view_manager();
|
||||
InfraredAppEvent tick_event = {.type = InfraredAppEvent::Type::Tick};
|
||||
view_manager->send_event(&tick_event);
|
||||
bool result = brute_force.send_next_bruteforce();
|
||||
if(result) {
|
||||
result = progress_popup(app);
|
||||
}
|
||||
if(!result) {
|
||||
brute_force.stop_bruteforce();
|
||||
brute_force_started = false;
|
||||
hide_popup(app);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InfraredAppEvent::Type::Back) {
|
||||
brute_force_started = false;
|
||||
brute_force.stop_bruteforce();
|
||||
hide_popup(app);
|
||||
consumed = true;
|
||||
}
|
||||
} else {
|
||||
if(event->type == InfraredAppEvent::Type::ButtonPanelPressed) {
|
||||
int record_amount = 0;
|
||||
if(brute_force.start_bruteforce(event->payload.menu_index, record_amount)) {
|
||||
DOLPHIN_DEED(DolphinDeedIrBruteForce);
|
||||
brute_force_started = true;
|
||||
show_popup(app, record_amount);
|
||||
} else {
|
||||
app->switch_to_previous_scene();
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InfraredAppEvent::Type::Back) {
|
||||
app->switch_to_previous_scene();
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void InfraredAppSceneUniversalCommon::on_exit(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
ButtonPanel* button_panel = view_manager->get_button_panel();
|
||||
button_panel_reset(button_panel);
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
#include <stdint.h>
|
||||
#include <gui/modules/loading.h>
|
||||
#include <gui/view_stack.h>
|
||||
#include "irda/scene/irda_app_scene.h"
|
||||
#include "irda/irda_app.h"
|
||||
#include "infrared/scene/infrared_app_scene.h"
|
||||
#include "infrared/infrared_app.h"
|
||||
|
||||
void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
void InfraredAppSceneUniversalTV::on_enter(InfraredApp* app) {
|
||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||
ButtonPanel* button_panel = view_manager->get_button_panel();
|
||||
button_panel_reserve(button_panel, 2, 3);
|
||||
|
||||
@ -19,7 +19,7 @@ void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) {
|
||||
19,
|
||||
&I_Power_25x27,
|
||||
&I_Power_hvr_25x27,
|
||||
irda_app_item_callback,
|
||||
infrared_app_item_callback,
|
||||
app);
|
||||
brute_force.add_record(i, "POWER");
|
||||
++i;
|
||||
@ -32,7 +32,7 @@ void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) {
|
||||
19,
|
||||
&I_Mute_25x27,
|
||||
&I_Mute_hvr_25x27,
|
||||
irda_app_item_callback,
|
||||
infrared_app_item_callback,
|
||||
app);
|
||||
brute_force.add_record(i, "MUTE");
|
||||
++i;
|
||||
@ -45,12 +45,21 @@ void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) {
|
||||
66,
|
||||
&I_Vol_up_25x27,
|
||||
&I_Vol_up_hvr_25x27,
|
||||
irda_app_item_callback,
|
||||
infrared_app_item_callback,
|
||||
app);
|
||||
brute_force.add_record(i, "VOL+");
|
||||
++i;
|
||||
button_panel_add_item(
|
||||
button_panel, i, 1, 1, 36, 66, &I_Up_25x27, &I_Up_hvr_25x27, irda_app_item_callback, app);
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
1,
|
||||
36,
|
||||
66,
|
||||
&I_Up_25x27,
|
||||
&I_Up_hvr_25x27,
|
||||
infrared_app_item_callback,
|
||||
app);
|
||||
brute_force.add_record(i, "CH+");
|
||||
++i;
|
||||
button_panel_add_item(
|
||||
@ -62,7 +71,7 @@ void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) {
|
||||
98,
|
||||
&I_Vol_down_25x27,
|
||||
&I_Vol_down_hvr_25x27,
|
||||
irda_app_item_callback,
|
||||
infrared_app_item_callback,
|
||||
app);
|
||||
brute_force.add_record(i, "VOL-");
|
||||
++i;
|
||||
@ -75,7 +84,7 @@ void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) {
|
||||
98,
|
||||
&I_Down_25x27,
|
||||
&I_Down_hvr_25x27,
|
||||
irda_app_item_callback,
|
||||
infrared_app_item_callback,
|
||||
app);
|
||||
brute_force.add_record(i, "CH-");
|
||||
|
||||
@ -83,7 +92,7 @@ void IrdaAppSceneUniversalTV::on_enter(IrdaApp* app) {
|
||||
button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol");
|
||||
button_panel_add_label(button_panel, 43, 64, FontSecondary, "Ch");
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::UniversalRemote);
|
||||
view_manager->switch_to(InfraredAppViewManager::ViewId::UniversalRemote);
|
||||
|
||||
auto stack_view = app->get_view_manager()->get_universal_view_stack();
|
||||
auto loading_view = app->get_view_manager()->get_loading();
|
||||
@ -7,26 +7,26 @@
|
||||
#include "m-string.h"
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
#include "irda_progress_view.h"
|
||||
#include "infrared_progress_view.h"
|
||||
#include "gui/modules/button_panel.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct IrdaProgressView {
|
||||
struct InfraredProgressView {
|
||||
View* view;
|
||||
IrdaProgressViewBackCallback back_callback;
|
||||
InfraredProgressViewBackCallback back_callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
size_t progress;
|
||||
size_t progress_total;
|
||||
} IrdaProgressViewModel;
|
||||
} InfraredProgressViewModel;
|
||||
|
||||
bool irda_progress_view_increase_progress(IrdaProgressView* progress) {
|
||||
bool infrared_progress_view_increase_progress(InfraredProgressView* progress) {
|
||||
furi_assert(progress);
|
||||
bool result = false;
|
||||
|
||||
IrdaProgressViewModel* model = view_get_model(progress->view);
|
||||
InfraredProgressViewModel* model = view_get_model(progress->view);
|
||||
if(model->progress < model->progress_total) {
|
||||
++model->progress;
|
||||
result = model->progress < model->progress_total;
|
||||
@ -36,8 +36,8 @@ bool irda_progress_view_increase_progress(IrdaProgressView* progress) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static void irda_progress_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
IrdaProgressViewModel* model = (IrdaProgressViewModel*)_model;
|
||||
static void infrared_progress_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
InfraredProgressViewModel* model = (InfraredProgressViewModel*)_model;
|
||||
|
||||
uint8_t x = 0;
|
||||
uint8_t y = 36;
|
||||
@ -63,16 +63,18 @@ static void irda_progress_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_draw_str(canvas, x + 30, y + height - 6, "= stop");
|
||||
}
|
||||
|
||||
void irda_progress_view_set_progress_total(IrdaProgressView* progress, uint16_t progress_total) {
|
||||
void infrared_progress_view_set_progress_total(
|
||||
InfraredProgressView* progress,
|
||||
uint16_t progress_total) {
|
||||
furi_assert(progress);
|
||||
IrdaProgressViewModel* model = view_get_model(progress->view);
|
||||
InfraredProgressViewModel* model = view_get_model(progress->view);
|
||||
model->progress = 0;
|
||||
model->progress_total = progress_total;
|
||||
view_commit_model(progress->view, false);
|
||||
}
|
||||
|
||||
bool irda_progress_view_input_callback(InputEvent* event, void* context) {
|
||||
IrdaProgressView* instance = context;
|
||||
bool infrared_progress_view_input_callback(InputEvent* event, void* context) {
|
||||
InfraredProgressView* instance = context;
|
||||
|
||||
if((event->type == InputTypeShort) && (event->key == InputKeyBack)) {
|
||||
if(instance->back_callback) {
|
||||
@ -83,36 +85,36 @@ bool irda_progress_view_input_callback(InputEvent* event, void* context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
IrdaProgressView* irda_progress_view_alloc(void) {
|
||||
IrdaProgressView* instance = malloc(sizeof(IrdaProgressView));
|
||||
InfraredProgressView* infrared_progress_view_alloc(void) {
|
||||
InfraredProgressView* instance = malloc(sizeof(InfraredProgressView));
|
||||
instance->view = view_alloc();
|
||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(IrdaProgressViewModel));
|
||||
IrdaProgressViewModel* model = view_get_model(instance->view);
|
||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(InfraredProgressViewModel));
|
||||
InfraredProgressViewModel* model = view_get_model(instance->view);
|
||||
model->progress = 0;
|
||||
model->progress_total = 0;
|
||||
view_commit_model(instance->view, false);
|
||||
view_set_draw_callback(instance->view, irda_progress_view_draw_callback);
|
||||
view_set_input_callback(instance->view, irda_progress_view_input_callback);
|
||||
view_set_draw_callback(instance->view, infrared_progress_view_draw_callback);
|
||||
view_set_input_callback(instance->view, infrared_progress_view_input_callback);
|
||||
view_set_context(instance->view, instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void irda_progress_view_free(IrdaProgressView* progress) {
|
||||
void infrared_progress_view_free(InfraredProgressView* progress) {
|
||||
view_free(progress->view);
|
||||
free(progress);
|
||||
}
|
||||
|
||||
void irda_progress_view_set_back_callback(
|
||||
IrdaProgressView* instance,
|
||||
IrdaProgressViewBackCallback callback,
|
||||
void infrared_progress_view_set_back_callback(
|
||||
InfraredProgressView* instance,
|
||||
InfraredProgressViewBackCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
instance->back_callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
View* irda_progress_view_get_view(IrdaProgressView* instance) {
|
||||
View* infrared_progress_view_get_view(InfraredProgressView* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->view);
|
||||
return instance->view;
|
||||
68
applications/infrared/view/infrared_progress_view.h
Normal file
68
applications/infrared/view/infrared_progress_view.h
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @file infrared_progress_view.h
|
||||
* Infrared: Custom Infrared view module.
|
||||
* It shows popup progress bar during brute force.
|
||||
*/
|
||||
#pragma once
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Anonumous instance */
|
||||
typedef struct InfraredProgressView InfraredProgressView;
|
||||
|
||||
/** Callback for back button handling */
|
||||
typedef void (*InfraredProgressViewBackCallback)(void*);
|
||||
|
||||
/** Allocate and initialize Infrared view
|
||||
*
|
||||
* @retval new allocated instance
|
||||
*/
|
||||
InfraredProgressView* infrared_progress_view_alloc();
|
||||
|
||||
/** Free previously allocated Progress view module instance
|
||||
*
|
||||
* @param instance to free
|
||||
*/
|
||||
void infrared_progress_view_free(InfraredProgressView* instance);
|
||||
|
||||
/** Get progress view module view
|
||||
*
|
||||
* @param instance view module
|
||||
* @retval view
|
||||
*/
|
||||
View* infrared_progress_view_get_view(InfraredProgressView* instance);
|
||||
|
||||
/** Increase progress on progress view module
|
||||
*
|
||||
* @param instance view module
|
||||
* @retval true - value is incremented and maximum is reached,
|
||||
* false - value is incremented and maximum is not reached
|
||||
*/
|
||||
bool infrared_progress_view_increase_progress(InfraredProgressView* instance);
|
||||
|
||||
/** Set maximum progress value
|
||||
*
|
||||
* @param instance - view module
|
||||
* @param progress_max - maximum value of progress
|
||||
*/
|
||||
void infrared_progress_view_set_progress_total(
|
||||
InfraredProgressView* instance,
|
||||
uint16_t progress_max);
|
||||
|
||||
/** Set back button callback
|
||||
*
|
||||
* @param instance - view module
|
||||
* @param callback - callback to call for back button
|
||||
* @param context - context to pass to callback
|
||||
*/
|
||||
void infrared_progress_view_set_back_callback(
|
||||
InfraredProgressView* instance,
|
||||
InfraredProgressViewBackCallback callback,
|
||||
void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
140
applications/infrared_monitor/infrared_monitor.c
Normal file
140
applications/infrared_monitor/infrared_monitor.c
Normal file
@ -0,0 +1,140 @@
|
||||
#include <gui/canvas.h>
|
||||
#include <input/input.h>
|
||||
#include <infrared.h>
|
||||
#include <infrared_worker.h>
|
||||
#include <stdio.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal_infrared.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/view_port.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#define INFRARED_TIMINGS_SIZE 700
|
||||
|
||||
typedef struct {
|
||||
uint32_t timing_cnt;
|
||||
struct {
|
||||
uint8_t level;
|
||||
uint32_t duration;
|
||||
} timing[INFRARED_TIMINGS_SIZE];
|
||||
} InfraredDelaysArray;
|
||||
|
||||
typedef struct {
|
||||
char display_text[64];
|
||||
osMessageQueueId_t event_queue;
|
||||
InfraredDelaysArray delays;
|
||||
InfraredWorker* worker;
|
||||
ViewPort* view_port;
|
||||
} InfraredMonitor;
|
||||
|
||||
void infrared_monitor_input_callback(InputEvent* input_event, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
InfraredMonitor* infrared_monitor = (InfraredMonitor*)ctx;
|
||||
|
||||
if((input_event->type == InputTypeShort) && (input_event->key == InputKeyBack)) {
|
||||
osMessageQueuePut(infrared_monitor->event_queue, input_event, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void infrared_monitor_draw_callback(Canvas* canvas, void* ctx) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(ctx);
|
||||
InfraredMonitor* infrared_monitor = (InfraredMonitor*)ctx;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "INFRARED monitor\n");
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
if(strlen(infrared_monitor->display_text)) {
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 64, 43, AlignCenter, AlignCenter, infrared_monitor->display_text);
|
||||
}
|
||||
}
|
||||
|
||||
static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) {
|
||||
furi_assert(context);
|
||||
furi_assert(received_signal);
|
||||
InfraredMonitor* infrared_monitor = context;
|
||||
|
||||
if(infrared_worker_signal_is_decoded(received_signal)) {
|
||||
const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal);
|
||||
snprintf(
|
||||
infrared_monitor->display_text,
|
||||
sizeof(infrared_monitor->display_text),
|
||||
"%s\nA:0x%0*lX\nC:0x%0*lX\n%s\n",
|
||||
infrared_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4),
|
||||
message->address,
|
||||
ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4),
|
||||
message->command,
|
||||
message->repeat ? " R" : "");
|
||||
view_port_update(infrared_monitor->view_port);
|
||||
printf(
|
||||
"== %s, A:0x%0*lX, C:0x%0*lX%s ==\r\n",
|
||||
infrared_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4),
|
||||
message->address,
|
||||
ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4),
|
||||
message->command,
|
||||
message->repeat ? " R" : "");
|
||||
} else {
|
||||
const uint32_t* timings;
|
||||
size_t timings_cnt;
|
||||
infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||
snprintf(
|
||||
infrared_monitor->display_text,
|
||||
sizeof(infrared_monitor->display_text),
|
||||
"RAW\n%d samples\n",
|
||||
timings_cnt);
|
||||
view_port_update(infrared_monitor->view_port);
|
||||
printf("RAW, %d samples:\r\n", timings_cnt);
|
||||
for(size_t i = 0; i < timings_cnt; ++i) {
|
||||
printf("%lu ", timings[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t infrared_monitor_app(void* p) {
|
||||
(void)p;
|
||||
|
||||
InfraredMonitor* infrared_monitor = malloc(sizeof(InfraredMonitor));
|
||||
infrared_monitor->display_text[0] = 0;
|
||||
infrared_monitor->event_queue = osMessageQueueNew(1, sizeof(InputEvent), NULL);
|
||||
infrared_monitor->view_port = view_port_alloc();
|
||||
Gui* gui = furi_record_open("gui");
|
||||
|
||||
view_port_draw_callback_set(
|
||||
infrared_monitor->view_port, infrared_monitor_draw_callback, infrared_monitor);
|
||||
view_port_input_callback_set(
|
||||
infrared_monitor->view_port, infrared_monitor_input_callback, infrared_monitor);
|
||||
|
||||
gui_add_view_port(gui, infrared_monitor->view_port, GuiLayerFullscreen);
|
||||
|
||||
infrared_monitor->worker = infrared_worker_alloc();
|
||||
infrared_worker_rx_start(infrared_monitor->worker);
|
||||
infrared_worker_rx_set_received_signal_callback(
|
||||
infrared_monitor->worker, signal_received_callback, infrared_monitor);
|
||||
infrared_worker_rx_enable_blink_on_receiving(infrared_monitor->worker, true);
|
||||
|
||||
while(1) {
|
||||
InputEvent event;
|
||||
if(osOK == osMessageQueueGet(infrared_monitor->event_queue, &event, NULL, 50)) {
|
||||
if((event.type == InputTypeShort) && (event.key == InputKeyBack)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
infrared_worker_rx_stop(infrared_monitor->worker);
|
||||
infrared_worker_free(infrared_monitor->worker);
|
||||
osMessageQueueDelete(infrared_monitor->event_queue);
|
||||
view_port_enabled_set(infrared_monitor->view_port, false);
|
||||
gui_remove_view_port(gui, infrared_monitor->view_port);
|
||||
view_port_free(infrared_monitor->view_port);
|
||||
furi_record_close("gui");
|
||||
free(infrared_monitor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../irda_app_signal.h"
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <string>
|
||||
|
||||
bool irda_parser_save_signal(
|
||||
FlipperFormat* ff,
|
||||
const IrdaAppSignal& signal,
|
||||
const std::string& name);
|
||||
bool irda_parser_read_signal(FlipperFormat* ff, IrdaAppSignal& signal, std::string& name);
|
||||
bool irda_parser_is_parsed_signal_valid(const IrdaMessage* signal);
|
||||
bool irda_parser_is_raw_signal_valid(uint32_t frequency, float duty_cycle, uint32_t timings_cnt);
|
||||
@ -1,138 +0,0 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <irda.h>
|
||||
#include <furi.h>
|
||||
#include "scene/irda_app_scene.h"
|
||||
#include "scene/irda_app_scene.h"
|
||||
#include "irda_app_view_manager.h"
|
||||
#include "irda_app_remote_manager.h"
|
||||
#include <forward_list>
|
||||
#include <stdint.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <irda_worker.h>
|
||||
#include "irda_app_view_manager.h"
|
||||
|
||||
class IrdaApp {
|
||||
public:
|
||||
enum class EditElement : uint8_t {
|
||||
Button,
|
||||
Remote,
|
||||
};
|
||||
enum class EditAction : uint8_t {
|
||||
Rename,
|
||||
Delete,
|
||||
};
|
||||
enum class Scene : uint8_t {
|
||||
Exit,
|
||||
Start,
|
||||
Universal,
|
||||
UniversalTV,
|
||||
UniversalAudio,
|
||||
UniversalAirConditioner,
|
||||
Learn,
|
||||
LearnSuccess,
|
||||
LearnEnterName,
|
||||
LearnDone,
|
||||
AskBack,
|
||||
Remote,
|
||||
RemoteList,
|
||||
Edit,
|
||||
EditKeySelect,
|
||||
EditRename,
|
||||
EditDelete,
|
||||
EditRenameDone,
|
||||
EditDeleteDone,
|
||||
};
|
||||
|
||||
int32_t run(void* args);
|
||||
void switch_to_next_scene(Scene index);
|
||||
void switch_to_next_scene_without_saving(Scene index);
|
||||
bool switch_to_previous_scene(uint8_t count = 1);
|
||||
Scene get_previous_scene();
|
||||
IrdaAppViewManager* get_view_manager();
|
||||
void set_text_store(uint8_t index, const char* text...);
|
||||
char* get_text_store(uint8_t index);
|
||||
uint8_t get_text_store_size();
|
||||
IrdaAppRemoteManager* get_remote_manager();
|
||||
|
||||
IrdaWorker* get_irda_worker();
|
||||
const IrdaAppSignal& get_received_signal() const;
|
||||
void set_received_signal(const IrdaAppSignal& signal);
|
||||
|
||||
void search_and_switch_to_previous_scene(const std::initializer_list<Scene>& scenes_list);
|
||||
|
||||
void set_edit_element(EditElement value);
|
||||
EditElement get_edit_element(void);
|
||||
|
||||
void set_edit_action(EditAction value);
|
||||
EditAction get_edit_action(void);
|
||||
|
||||
bool get_learn_new_remote();
|
||||
void set_learn_new_remote(bool value);
|
||||
|
||||
enum : int {
|
||||
ButtonNA = -1,
|
||||
};
|
||||
int get_current_button();
|
||||
void set_current_button(int value);
|
||||
|
||||
void notify_success();
|
||||
void notify_red_blink();
|
||||
void notify_sent_just_learnt();
|
||||
void notify_green_on();
|
||||
void notify_green_off();
|
||||
void notify_click();
|
||||
void notify_click_and_green_blink();
|
||||
void notify_blink_green();
|
||||
|
||||
static void text_input_callback(void* context);
|
||||
static void popup_callback(void* context);
|
||||
static void signal_sent_callback(void* context);
|
||||
|
||||
IrdaApp();
|
||||
~IrdaApp();
|
||||
|
||||
static constexpr const char* irda_directory = "/any/irda";
|
||||
static constexpr const char* irda_extension = ".ir";
|
||||
static constexpr const uint32_t max_raw_timings_in_signal = 512;
|
||||
static constexpr const uint32_t max_line_length =
|
||||
(9 + 1) * IrdaApp::max_raw_timings_in_signal + 100;
|
||||
|
||||
private:
|
||||
static constexpr const uint8_t text_store_size = 128;
|
||||
static constexpr const uint8_t text_store_max = 2;
|
||||
char text_store[text_store_max][text_store_size + 1];
|
||||
bool learn_new_remote;
|
||||
EditElement element;
|
||||
EditAction action;
|
||||
uint32_t current_button;
|
||||
|
||||
NotificationApp* notification;
|
||||
IrdaAppViewManager view_manager;
|
||||
IrdaAppRemoteManager remote_manager;
|
||||
IrdaWorker* irda_worker;
|
||||
IrdaAppSignal received_signal;
|
||||
|
||||
std::forward_list<Scene> previous_scenes_list;
|
||||
Scene current_scene = Scene::Start;
|
||||
|
||||
std::map<Scene, IrdaAppScene*> scenes = {
|
||||
{Scene::Start, new IrdaAppSceneStart()},
|
||||
{Scene::Universal, new IrdaAppSceneUniversal()},
|
||||
{Scene::UniversalTV, new IrdaAppSceneUniversalTV()},
|
||||
// {Scene::UniversalAudio, new IrdaAppSceneUniversalAudio()},
|
||||
{Scene::Learn, new IrdaAppSceneLearn()},
|
||||
{Scene::LearnSuccess, new IrdaAppSceneLearnSuccess()},
|
||||
{Scene::LearnEnterName, new IrdaAppSceneLearnEnterName()},
|
||||
{Scene::LearnDone, new IrdaAppSceneLearnDone()},
|
||||
{Scene::AskBack, new IrdaAppSceneAskBack()},
|
||||
{Scene::Remote, new IrdaAppSceneRemote()},
|
||||
{Scene::RemoteList, new IrdaAppSceneRemoteList()},
|
||||
{Scene::Edit, new IrdaAppSceneEdit()},
|
||||
{Scene::EditKeySelect, new IrdaAppSceneEditKeySelect()},
|
||||
{Scene::EditRename, new IrdaAppSceneEditRename()},
|
||||
{Scene::EditDelete, new IrdaAppSceneEditDelete()},
|
||||
{Scene::EditRenameDone, new IrdaAppSceneEditRenameDone()},
|
||||
{Scene::EditDeleteDone, new IrdaAppSceneEditDeleteDone()},
|
||||
};
|
||||
};
|
||||
@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
|
||||
class IrdaAppBruteForce {
|
||||
const char* universal_db_filename;
|
||||
std::string current_record;
|
||||
FlipperFormat* ff;
|
||||
|
||||
typedef struct {
|
||||
int index;
|
||||
int amount;
|
||||
} Record;
|
||||
|
||||
// 'key' is record name, because we have to search by both, index and name,
|
||||
// but index search has place once per button press, and should not be
|
||||
// noticed, but name search should occur during entering universal menu,
|
||||
// and will go through container for every record in file, that's why
|
||||
// more critical to have faster search by record name.
|
||||
std::unordered_map<std::string, Record> records;
|
||||
|
||||
public:
|
||||
bool calculate_messages();
|
||||
void stop_bruteforce();
|
||||
bool send_next_bruteforce();
|
||||
bool start_bruteforce(int index, int& record_amount);
|
||||
void add_record(int index, const char* name);
|
||||
|
||||
IrdaAppBruteForce(const char* filename)
|
||||
: universal_db_filename(filename) {
|
||||
}
|
||||
~IrdaAppBruteForce() {
|
||||
}
|
||||
};
|
||||
@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
#include <irda.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
|
||||
class IrdaAppEvent {
|
||||
public:
|
||||
enum class Type : uint8_t {
|
||||
Tick,
|
||||
Exit,
|
||||
Back,
|
||||
MenuSelected,
|
||||
MenuSelectedPress,
|
||||
MenuSelectedRelease,
|
||||
DialogExSelected,
|
||||
NextScene,
|
||||
IrdaMessageReceived,
|
||||
TextEditDone,
|
||||
PopupTimer,
|
||||
ButtonPanelPressed,
|
||||
};
|
||||
|
||||
union {
|
||||
int32_t menu_index;
|
||||
DialogExResult dialog_ex_result;
|
||||
} payload;
|
||||
|
||||
Type type;
|
||||
};
|
||||
@ -1,76 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "irda_app_signal.h"
|
||||
|
||||
#include <irda_worker.h>
|
||||
#include <irda.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class IrdaAppRemoteButton {
|
||||
friend class IrdaAppRemoteManager;
|
||||
std::string name;
|
||||
IrdaAppSignal signal;
|
||||
|
||||
public:
|
||||
IrdaAppRemoteButton(const char* name, const IrdaAppSignal& signal)
|
||||
: name(name)
|
||||
, signal(signal) {
|
||||
}
|
||||
|
||||
IrdaAppRemoteButton(const char* name, IrdaAppSignal&& signal)
|
||||
: name(name)
|
||||
, signal(std::move(signal)) {
|
||||
}
|
||||
~IrdaAppRemoteButton() {
|
||||
}
|
||||
};
|
||||
|
||||
class IrdaAppRemote {
|
||||
friend class IrdaAppRemoteManager;
|
||||
std::vector<IrdaAppRemoteButton> buttons;
|
||||
std::string name;
|
||||
|
||||
public:
|
||||
IrdaAppRemote(const std::string& name)
|
||||
: name(name) {
|
||||
}
|
||||
|
||||
IrdaAppRemote& operator=(std::string& new_name) noexcept {
|
||||
name = new_name;
|
||||
buttons.clear();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class IrdaAppRemoteManager {
|
||||
std::unique_ptr<IrdaAppRemote> remote;
|
||||
std::string make_full_name(const std::string& remote_name) const;
|
||||
std::string make_remote_name(const std::string& full_name) const;
|
||||
|
||||
public:
|
||||
static constexpr const uint32_t max_button_name_length = 22;
|
||||
static constexpr const uint32_t max_remote_name_length = 22;
|
||||
bool add_remote_with_button(const char* button_name, const IrdaAppSignal& signal);
|
||||
bool add_button(const char* button_name, const IrdaAppSignal& signal);
|
||||
|
||||
int find_remote_name(const std::vector<std::string>& strings);
|
||||
bool rename_button(uint32_t index, const char* str);
|
||||
bool rename_remote(const char* str);
|
||||
std::string find_vacant_remote_name(const std::string& name);
|
||||
|
||||
std::vector<std::string> get_button_list() const;
|
||||
std::string get_button_name(uint32_t index);
|
||||
std::string get_remote_name();
|
||||
size_t get_number_of_buttons();
|
||||
const IrdaAppSignal& get_button_data(size_t index) const;
|
||||
bool delete_button(uint32_t index);
|
||||
bool delete_remote();
|
||||
void reset_remote();
|
||||
|
||||
bool store();
|
||||
bool load(const std::string& name);
|
||||
};
|
||||
@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
#include <irda_worker.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <irda.h>
|
||||
|
||||
class IrdaAppSignal {
|
||||
public:
|
||||
typedef struct {
|
||||
size_t timings_cnt;
|
||||
uint32_t* timings;
|
||||
uint32_t frequency;
|
||||
float duty_cycle;
|
||||
} RawSignal;
|
||||
|
||||
private:
|
||||
bool raw_signal;
|
||||
union {
|
||||
IrdaMessage message;
|
||||
RawSignal raw;
|
||||
} payload;
|
||||
|
||||
void
|
||||
copy_raw_signal(const uint32_t* timings, size_t size, uint32_t frequency, float duty_cycle);
|
||||
void clear_timings();
|
||||
|
||||
public:
|
||||
IrdaAppSignal() {
|
||||
raw_signal = false;
|
||||
payload.message.protocol = IrdaProtocolUnknown;
|
||||
}
|
||||
|
||||
~IrdaAppSignal() {
|
||||
clear_timings();
|
||||
}
|
||||
|
||||
IrdaAppSignal(
|
||||
const uint32_t* timings,
|
||||
size_t timings_cnt,
|
||||
uint32_t frequency,
|
||||
float duty_cycle);
|
||||
IrdaAppSignal(const IrdaMessage* irda_message);
|
||||
|
||||
IrdaAppSignal(const IrdaAppSignal& other);
|
||||
IrdaAppSignal(IrdaAppSignal&& other);
|
||||
|
||||
IrdaAppSignal& operator=(const IrdaAppSignal& signal);
|
||||
|
||||
void set_message(const IrdaMessage* irda_message);
|
||||
void
|
||||
set_raw_signal(uint32_t* timings, size_t timings_cnt, uint32_t frequency, float duty_cycle);
|
||||
|
||||
void transmit() const;
|
||||
|
||||
bool is_raw(void) const {
|
||||
return raw_signal;
|
||||
}
|
||||
|
||||
const IrdaMessage& get_message(void) const {
|
||||
furi_assert(!raw_signal);
|
||||
return payload.message;
|
||||
}
|
||||
|
||||
const RawSignal& get_raw_signal(void) const {
|
||||
furi_assert(raw_signal);
|
||||
return payload.raw;
|
||||
}
|
||||
};
|
||||
@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
#include <gui/modules/button_menu.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/view_stack.h>
|
||||
#include <gui/modules/button_panel.h>
|
||||
#include <furi.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/modules/loading.h>
|
||||
|
||||
#include "irda_app_event.h"
|
||||
#include "view/irda_progress_view.h"
|
||||
|
||||
class IrdaAppViewManager {
|
||||
public:
|
||||
enum class ViewType : uint8_t {
|
||||
DialogEx,
|
||||
TextInput,
|
||||
Submenu,
|
||||
ButtonMenu,
|
||||
UniversalRemote,
|
||||
Popup,
|
||||
};
|
||||
|
||||
IrdaAppViewManager();
|
||||
~IrdaAppViewManager();
|
||||
|
||||
void switch_to(ViewType type);
|
||||
|
||||
void receive_event(IrdaAppEvent* event);
|
||||
void send_event(IrdaAppEvent* event);
|
||||
void clear_events();
|
||||
|
||||
DialogEx* get_dialog_ex();
|
||||
Submenu* get_submenu();
|
||||
Popup* get_popup();
|
||||
TextInput* get_text_input();
|
||||
ButtonMenu* get_button_menu();
|
||||
ButtonPanel* get_button_panel();
|
||||
ViewStack* get_universal_view_stack();
|
||||
IrdaProgressView* get_progress();
|
||||
Loading* get_loading();
|
||||
|
||||
osMessageQueueId_t get_event_queue();
|
||||
|
||||
uint32_t previous_view_callback(void* context);
|
||||
|
||||
private:
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Gui* gui;
|
||||
TextInput* text_input;
|
||||
DialogEx* dialog_ex;
|
||||
Submenu* submenu;
|
||||
Popup* popup;
|
||||
ButtonMenu* button_menu;
|
||||
ButtonPanel* button_panel;
|
||||
ViewStack* universal_view_stack;
|
||||
IrdaProgressView* progress_view;
|
||||
Loading* loading_view;
|
||||
|
||||
osMessageQueueId_t event_queue;
|
||||
|
||||
void add_view(ViewType view_type, View* view);
|
||||
};
|
||||
@ -1,9 +0,0 @@
|
||||
#include "irda_app.h"
|
||||
|
||||
extern "C" int32_t irda_app(void* p) {
|
||||
IrdaApp* app = new IrdaApp();
|
||||
int32_t result = app->run(p);
|
||||
delete app;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1,184 +0,0 @@
|
||||
#pragma once
|
||||
#include "../irda_app_event.h"
|
||||
#include <furi_hal_irda.h>
|
||||
#include "irda.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../irda_app_brute_force.h"
|
||||
|
||||
class IrdaApp;
|
||||
|
||||
class IrdaAppScene {
|
||||
public:
|
||||
virtual void on_enter(IrdaApp* app) = 0;
|
||||
virtual bool on_event(IrdaApp* app, IrdaAppEvent* event) = 0;
|
||||
virtual void on_exit(IrdaApp* app) = 0;
|
||||
virtual ~IrdaAppScene(){};
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class IrdaAppSceneStart : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
|
||||
private:
|
||||
uint32_t submenu_item_selected = 0;
|
||||
};
|
||||
|
||||
class IrdaAppSceneUniversal : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
|
||||
private:
|
||||
uint32_t submenu_item_selected = 0;
|
||||
};
|
||||
|
||||
class IrdaAppSceneLearn : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
};
|
||||
|
||||
class IrdaAppSceneLearnSuccess : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
bool button_pressed = false;
|
||||
};
|
||||
|
||||
class IrdaAppSceneLearnEnterName : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
};
|
||||
|
||||
class IrdaAppSceneLearnDone : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
};
|
||||
|
||||
class IrdaAppSceneRemote : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
|
||||
private:
|
||||
std::vector<std::string> buttons_names;
|
||||
uint32_t buttonmenu_item_selected = 0;
|
||||
bool button_pressed = false;
|
||||
};
|
||||
|
||||
class IrdaAppSceneRemoteList : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
|
||||
private:
|
||||
uint32_t submenu_item_selected = 0;
|
||||
std::vector<std::string> remote_names;
|
||||
};
|
||||
|
||||
class IrdaAppSceneAskBack : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
};
|
||||
|
||||
class IrdaAppSceneEdit : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
|
||||
private:
|
||||
uint32_t submenu_item_selected = 0;
|
||||
};
|
||||
|
||||
class IrdaAppSceneEditKeySelect : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
|
||||
private:
|
||||
std::vector<std::string> buttons_names;
|
||||
};
|
||||
|
||||
class IrdaAppSceneEditRename : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
};
|
||||
|
||||
class IrdaAppSceneEditDelete : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
};
|
||||
|
||||
class IrdaAppSceneEditRenameDone : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
};
|
||||
|
||||
class IrdaAppSceneEditDeleteDone : public IrdaAppScene {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
};
|
||||
|
||||
class IrdaAppSceneUniversalCommon : public IrdaAppScene {
|
||||
bool brute_force_started = false;
|
||||
|
||||
protected:
|
||||
bool on_event(IrdaApp* app, IrdaAppEvent* event) final;
|
||||
void on_exit(IrdaApp* app) final;
|
||||
IrdaAppBruteForce brute_force;
|
||||
void remove_popup(IrdaApp* app);
|
||||
void show_popup(IrdaApp* app, int record_amount);
|
||||
bool progress_popup(IrdaApp* app);
|
||||
static void irda_app_item_callback(void* context, uint32_t index);
|
||||
IrdaAppSceneUniversalCommon(const char* filename)
|
||||
: brute_force(filename) {
|
||||
}
|
||||
~IrdaAppSceneUniversalCommon() {
|
||||
}
|
||||
};
|
||||
|
||||
class IrdaAppSceneUniversalTV : public IrdaAppSceneUniversalCommon {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
IrdaAppSceneUniversalTV()
|
||||
: IrdaAppSceneUniversalCommon("/ext/irda/assets/tv.ir") {
|
||||
}
|
||||
~IrdaAppSceneUniversalTV() {
|
||||
}
|
||||
};
|
||||
|
||||
class IrdaAppSceneUniversalAudio : public IrdaAppSceneUniversalCommon {
|
||||
public:
|
||||
void on_enter(IrdaApp* app) final;
|
||||
IrdaAppSceneUniversalAudio()
|
||||
: IrdaAppSceneUniversalCommon("/ext/irda/assets/audio.ir") {
|
||||
}
|
||||
~IrdaAppSceneUniversalAudio() {
|
||||
}
|
||||
};
|
||||
@ -1,38 +0,0 @@
|
||||
#include "../irda_app.h"
|
||||
|
||||
void IrdaAppSceneEditDeleteDone::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
Popup* popup = view_manager->get_popup();
|
||||
|
||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
|
||||
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
|
||||
popup_set_callback(popup, IrdaApp::popup_callback);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::Popup);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneEditDeleteDone::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::PopupTimer) {
|
||||
if(app->get_edit_element() == IrdaApp::EditElement::Remote) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{IrdaApp::Scene::Start, IrdaApp::Scene::RemoteList});
|
||||
} else {
|
||||
app->search_and_switch_to_previous_scene({IrdaApp::Scene::Remote});
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneEditDeleteDone::on_exit(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
Popup* popup = view_manager->get_popup();
|
||||
popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop);
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
#include "../irda_app.h"
|
||||
#include "gui/modules/submenu.h"
|
||||
|
||||
static void submenu_callback(void* context, uint32_t index) {
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
|
||||
event.type = IrdaAppEvent::Type::MenuSelected;
|
||||
event.payload.menu_index = index;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneEditKeySelect::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
int item_number = 0;
|
||||
|
||||
const char* header = app->get_edit_action() == IrdaApp::EditAction::Rename ? "Rename key:" :
|
||||
"Delete key:";
|
||||
submenu_set_header(submenu, header);
|
||||
|
||||
auto remote_manager = app->get_remote_manager();
|
||||
buttons_names = remote_manager->get_button_list();
|
||||
for(const auto& it : buttons_names) {
|
||||
submenu_add_item(submenu, it.c_str(), item_number++, submenu_callback, app);
|
||||
}
|
||||
if((item_number > 0) && (app->get_current_button() != IrdaApp::ButtonNA)) {
|
||||
submenu_set_selected_item(submenu, app->get_current_button());
|
||||
app->set_current_button(IrdaApp::ButtonNA);
|
||||
}
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::Submenu);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneEditKeySelect::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::MenuSelected) {
|
||||
app->set_current_button(event->payload.menu_index);
|
||||
consumed = true;
|
||||
if(app->get_edit_action() == IrdaApp::EditAction::Rename) {
|
||||
app->switch_to_next_scene(IrdaApp::Scene::EditRename);
|
||||
} else {
|
||||
app->switch_to_next_scene(IrdaApp::Scene::EditDelete);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneEditKeySelect::on_exit(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_reset(submenu);
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
#include "../irda_app.h"
|
||||
|
||||
void IrdaAppSceneEditRenameDone::on_enter(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
Popup* popup = view_manager->get_popup();
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
|
||||
popup_set_callback(popup, IrdaApp::popup_callback);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::Popup);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneEditRenameDone::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == IrdaAppEvent::Type::PopupTimer) {
|
||||
app->switch_to_next_scene(IrdaApp::Scene::Remote);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneEditRenameDone::on_exit(IrdaApp* app) {
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
#include "../irda_app.h"
|
||||
#include "../irda_app_event.h"
|
||||
#include "irda.h"
|
||||
#include <irda_worker.h>
|
||||
|
||||
static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) {
|
||||
furi_assert(context);
|
||||
furi_assert(received_signal);
|
||||
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
|
||||
if(irda_worker_signal_is_decoded(received_signal)) {
|
||||
IrdaAppSignal signal(irda_worker_get_decoded_signal(received_signal));
|
||||
app->set_received_signal(signal);
|
||||
} else {
|
||||
const uint32_t* timings;
|
||||
size_t timings_cnt;
|
||||
irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||
IrdaAppSignal signal(
|
||||
timings, timings_cnt, IRDA_COMMON_CARRIER_FREQUENCY, IRDA_COMMON_DUTY_CYCLE);
|
||||
app->set_received_signal(signal);
|
||||
}
|
||||
|
||||
irda_worker_rx_set_received_signal_callback(app->get_irda_worker(), NULL, NULL);
|
||||
IrdaAppEvent event;
|
||||
event.type = IrdaAppEvent::Type::IrdaMessageReceived;
|
||||
auto view_manager = app->get_view_manager();
|
||||
view_manager->send_event(&event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneLearn::on_enter(IrdaApp* app) {
|
||||
auto view_manager = app->get_view_manager();
|
||||
auto popup = view_manager->get_popup();
|
||||
|
||||
auto worker = app->get_irda_worker();
|
||||
irda_worker_rx_set_received_signal_callback(worker, signal_received_callback, app);
|
||||
irda_worker_rx_start(worker);
|
||||
|
||||
popup_set_icon(popup, 0, 32, &I_IrdaLearnShort_128x31);
|
||||
popup_set_text(
|
||||
popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter);
|
||||
popup_set_callback(popup, NULL);
|
||||
|
||||
view_manager->switch_to(IrdaAppViewManager::ViewType::Popup);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
switch(event->type) {
|
||||
case IrdaAppEvent::Type::Tick:
|
||||
consumed = true;
|
||||
app->notify_red_blink();
|
||||
break;
|
||||
case IrdaAppEvent::Type::IrdaMessageReceived:
|
||||
app->notify_success();
|
||||
app->switch_to_next_scene_without_saving(IrdaApp::Scene::LearnSuccess);
|
||||
break;
|
||||
case IrdaAppEvent::Type::Back:
|
||||
consumed = true;
|
||||
app->switch_to_previous_scene();
|
||||
break;
|
||||
default:
|
||||
furi_assert(0);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneLearn::on_exit(IrdaApp* app) {
|
||||
irda_worker_rx_stop(app->get_irda_worker());
|
||||
auto view_manager = app->get_view_manager();
|
||||
auto popup = view_manager->get_popup();
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <gui/modules/button_menu.h>
|
||||
#include <gui/modules/button_panel.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_stack.h>
|
||||
|
||||
#include "../irda_app.h"
|
||||
#include "irda/irda_app_event.h"
|
||||
#include "irda/irda_app_view_manager.h"
|
||||
#include "irda/scene/irda_app_scene.h"
|
||||
#include "../view/irda_progress_view.h"
|
||||
|
||||
void IrdaAppSceneUniversalCommon::irda_app_item_callback(void* context, uint32_t index) {
|
||||
IrdaApp* app = static_cast<IrdaApp*>(context);
|
||||
IrdaAppEvent event;
|
||||
|
||||
event.type = IrdaAppEvent::Type::ButtonPanelPressed;
|
||||
event.payload.menu_index = index;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
||||
|
||||
static void irda_progress_back_callback(void* context) {
|
||||
furi_assert(context);
|
||||
auto app = static_cast<IrdaApp*>(context);
|
||||
|
||||
IrdaAppEvent irda_event = {
|
||||
.type = IrdaAppEvent::Type::Back,
|
||||
};
|
||||
app->get_view_manager()->clear_events();
|
||||
app->get_view_manager()->send_event(&irda_event);
|
||||
}
|
||||
|
||||
void IrdaAppSceneUniversalCommon::remove_popup(IrdaApp* app) {
|
||||
auto stack_view = app->get_view_manager()->get_universal_view_stack();
|
||||
auto progress_view = app->get_view_manager()->get_progress();
|
||||
view_stack_remove_view(stack_view, irda_progress_view_get_view(progress_view));
|
||||
}
|
||||
|
||||
void IrdaAppSceneUniversalCommon::show_popup(IrdaApp* app, int record_amount) {
|
||||
auto stack_view = app->get_view_manager()->get_universal_view_stack();
|
||||
auto progress_view = app->get_view_manager()->get_progress();
|
||||
irda_progress_view_set_progress_total(progress_view, record_amount);
|
||||
irda_progress_view_set_back_callback(progress_view, irda_progress_back_callback, app);
|
||||
view_stack_add_view(stack_view, irda_progress_view_get_view(progress_view));
|
||||
}
|
||||
|
||||
bool IrdaAppSceneUniversalCommon::progress_popup(IrdaApp* app) {
|
||||
auto progress_view = app->get_view_manager()->get_progress();
|
||||
return irda_progress_view_increase_progress(progress_view);
|
||||
}
|
||||
|
||||
bool IrdaAppSceneUniversalCommon::on_event(IrdaApp* app, IrdaAppEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(brute_force_started) {
|
||||
if(event->type == IrdaAppEvent::Type::Tick) {
|
||||
auto view_manager = app->get_view_manager();
|
||||
IrdaAppEvent tick_event = {.type = IrdaAppEvent::Type::Tick};
|
||||
view_manager->send_event(&tick_event);
|
||||
bool result = brute_force.send_next_bruteforce();
|
||||
if(result) {
|
||||
result = progress_popup(app);
|
||||
}
|
||||
if(!result) {
|
||||
brute_force.stop_bruteforce();
|
||||
brute_force_started = false;
|
||||
remove_popup(app);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == IrdaAppEvent::Type::Back) {
|
||||
brute_force_started = false;
|
||||
brute_force.stop_bruteforce();
|
||||
remove_popup(app);
|
||||
consumed = true;
|
||||
}
|
||||
} else {
|
||||
if(event->type == IrdaAppEvent::Type::ButtonPanelPressed) {
|
||||
int record_amount = 0;
|
||||
if(brute_force.start_bruteforce(event->payload.menu_index, record_amount)) {
|
||||
DOLPHIN_DEED(DolphinDeedIrBruteForce);
|
||||
brute_force_started = true;
|
||||
show_popup(app, record_amount);
|
||||
} else {
|
||||
app->switch_to_previous_scene();
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == IrdaAppEvent::Type::Back) {
|
||||
app->switch_to_previous_scene();
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void IrdaAppSceneUniversalCommon::on_exit(IrdaApp* app) {
|
||||
IrdaAppViewManager* view_manager = app->get_view_manager();
|
||||
ButtonPanel* button_panel = view_manager->get_button_panel();
|
||||
button_panel_reset(button_panel);
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct IrdaProgressView IrdaProgressView;
|
||||
|
||||
typedef void (*IrdaProgressViewBackCallback)(void*);
|
||||
|
||||
IrdaProgressView* irda_progress_view_alloc();
|
||||
void irda_progress_view_free(IrdaProgressView* progress);
|
||||
View* irda_progress_view_get_view(IrdaProgressView* progress);
|
||||
|
||||
bool irda_progress_view_increase_progress(IrdaProgressView* progress);
|
||||
void irda_progress_view_set_progress_total(IrdaProgressView* progress, uint16_t progress_max);
|
||||
void irda_progress_view_set_back_callback(
|
||||
IrdaProgressView* instance,
|
||||
IrdaProgressViewBackCallback callback,
|
||||
void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,139 +0,0 @@
|
||||
#include <gui/canvas.h>
|
||||
#include <input/input.h>
|
||||
#include <irda.h>
|
||||
#include <irda_worker.h>
|
||||
#include <stdio.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal_irda.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/view_port.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#define IRDA_TIMINGS_SIZE 700
|
||||
|
||||
typedef struct {
|
||||
uint32_t timing_cnt;
|
||||
struct {
|
||||
uint8_t level;
|
||||
uint32_t duration;
|
||||
} timing[IRDA_TIMINGS_SIZE];
|
||||
} IrdaDelaysArray;
|
||||
|
||||
typedef struct {
|
||||
char display_text[64];
|
||||
osMessageQueueId_t event_queue;
|
||||
IrdaDelaysArray delays;
|
||||
IrdaWorker* worker;
|
||||
ViewPort* view_port;
|
||||
} IrdaMonitor;
|
||||
|
||||
void irda_monitor_input_callback(InputEvent* input_event, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
IrdaMonitor* irda_monitor = (IrdaMonitor*)ctx;
|
||||
|
||||
if((input_event->type == InputTypeShort) && (input_event->key == InputKeyBack)) {
|
||||
osMessageQueuePut(irda_monitor->event_queue, input_event, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void irda_monitor_draw_callback(Canvas* canvas, void* ctx) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(ctx);
|
||||
IrdaMonitor* irda_monitor = (IrdaMonitor*)ctx;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "IRDA monitor\n");
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
if(strlen(irda_monitor->display_text)) {
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 64, 43, AlignCenter, AlignCenter, irda_monitor->display_text);
|
||||
}
|
||||
}
|
||||
|
||||
static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) {
|
||||
furi_assert(context);
|
||||
furi_assert(received_signal);
|
||||
IrdaMonitor* irda_monitor = context;
|
||||
|
||||
if(irda_worker_signal_is_decoded(received_signal)) {
|
||||
const IrdaMessage* message = irda_worker_get_decoded_signal(received_signal);
|
||||
snprintf(
|
||||
irda_monitor->display_text,
|
||||
sizeof(irda_monitor->display_text),
|
||||
"%s\nA:0x%0*lX\nC:0x%0*lX\n%s\n",
|
||||
irda_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4),
|
||||
message->address,
|
||||
ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4),
|
||||
message->command,
|
||||
message->repeat ? " R" : "");
|
||||
view_port_update(irda_monitor->view_port);
|
||||
printf(
|
||||
"== %s, A:0x%0*lX, C:0x%0*lX%s ==\r\n",
|
||||
irda_get_protocol_name(message->protocol),
|
||||
ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4),
|
||||
message->address,
|
||||
ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4),
|
||||
message->command,
|
||||
message->repeat ? " R" : "");
|
||||
} else {
|
||||
const uint32_t* timings;
|
||||
size_t timings_cnt;
|
||||
irda_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
|
||||
snprintf(
|
||||
irda_monitor->display_text,
|
||||
sizeof(irda_monitor->display_text),
|
||||
"RAW\n%d samples\n",
|
||||
timings_cnt);
|
||||
view_port_update(irda_monitor->view_port);
|
||||
printf("RAW, %d samples:\r\n", timings_cnt);
|
||||
for(size_t i = 0; i < timings_cnt; ++i) {
|
||||
printf("%lu ", timings[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t irda_monitor_app(void* p) {
|
||||
(void)p;
|
||||
|
||||
IrdaMonitor* irda_monitor = malloc(sizeof(IrdaMonitor));
|
||||
irda_monitor->display_text[0] = 0;
|
||||
irda_monitor->event_queue = osMessageQueueNew(1, sizeof(InputEvent), NULL);
|
||||
irda_monitor->view_port = view_port_alloc();
|
||||
Gui* gui = furi_record_open("gui");
|
||||
|
||||
view_port_draw_callback_set(irda_monitor->view_port, irda_monitor_draw_callback, irda_monitor);
|
||||
view_port_input_callback_set(
|
||||
irda_monitor->view_port, irda_monitor_input_callback, irda_monitor);
|
||||
|
||||
gui_add_view_port(gui, irda_monitor->view_port, GuiLayerFullscreen);
|
||||
|
||||
irda_monitor->worker = irda_worker_alloc();
|
||||
irda_worker_rx_start(irda_monitor->worker);
|
||||
irda_worker_rx_set_received_signal_callback(
|
||||
irda_monitor->worker, signal_received_callback, irda_monitor);
|
||||
irda_worker_rx_enable_blink_on_receiving(irda_monitor->worker, true);
|
||||
|
||||
while(1) {
|
||||
InputEvent event;
|
||||
if(osOK == osMessageQueueGet(irda_monitor->event_queue, &event, NULL, 50)) {
|
||||
if((event.type == InputTypeShort) && (event.key == InputKeyBack)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
irda_worker_rx_stop(irda_monitor->worker);
|
||||
irda_worker_free(irda_monitor->worker);
|
||||
osMessageQueueDelete(irda_monitor->event_queue);
|
||||
view_port_enabled_set(irda_monitor->view_port, false);
|
||||
gui_remove_view_port(gui, irda_monitor->view_port);
|
||||
view_port_free(irda_monitor->view_port);
|
||||
furi_record_close("gui");
|
||||
free(irda_monitor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -11,6 +11,9 @@ static void nfc_cli_print_usage() {
|
||||
printf("Cmd list:\r\n");
|
||||
printf("\tdetect\t - detect nfc device\r\n");
|
||||
printf("\temulate\t - emulate predefined nfca card\r\n");
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
printf("\tfield\t - turn field on\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_cli_detect(Cli* cli, string_t args) {
|
||||
@ -76,6 +79,27 @@ void nfc_cli_emulate(Cli* cli, string_t args) {
|
||||
furi_hal_nfc_deactivate();
|
||||
}
|
||||
|
||||
void nfc_cli_field(Cli* cli, string_t args) {
|
||||
// Check if nfc worker is not busy
|
||||
if(furi_hal_nfc_is_busy()) {
|
||||
printf("Nfc is busy\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
furi_hal_nfc_exit_sleep();
|
||||
furi_hal_nfc_field_on();
|
||||
|
||||
printf("Field is on. Don't leave device in this mode for too long.\r\n");
|
||||
printf("Press Ctrl+C to abort\r\n");
|
||||
|
||||
while(!cli_cmd_interrupt_received(cli)) {
|
||||
osDelay(50);
|
||||
}
|
||||
|
||||
furi_hal_nfc_field_off();
|
||||
furi_hal_nfc_deactivate();
|
||||
}
|
||||
|
||||
static void nfc_cli(Cli* cli, string_t args, void* context) {
|
||||
string_t cmd;
|
||||
string_init(cmd);
|
||||
@ -94,6 +118,13 @@ static void nfc_cli(Cli* cli, string_t args, void* context) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
if(string_cmp_str(cmd, "field") == 0) {
|
||||
nfc_cli_field(cli, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nfc_cli_print_usage();
|
||||
} while(false);
|
||||
|
||||
|
||||
@ -27,3 +27,5 @@ ADD_SCENE(nfc, read_emv_data, ReadEmvData)
|
||||
ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess)
|
||||
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
|
||||
ADD_SCENE(nfc, restore_original, RestoreOriginal)
|
||||
ADD_SCENE(nfc, debug, Debug)
|
||||
ADD_SCENE(nfc, field, Field)
|
||||
|
||||
54
applications/nfc/scenes/nfc_scene_debug.c
Normal file
54
applications/nfc/scenes/nfc_scene_debug.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
enum SubmenuDebugIndex {
|
||||
SubmenuDebugIndexField,
|
||||
SubmenuDebugIndexApdu,
|
||||
};
|
||||
|
||||
void nfc_scene_debug_submenu_callback(void* context, uint32_t index) {
|
||||
Nfc* nfc = (Nfc*)context;
|
||||
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_debug_on_enter(void* context) {
|
||||
Nfc* nfc = (Nfc*)context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "Field", SubmenuDebugIndexField, nfc_scene_debug_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu, "Apdu", SubmenuDebugIndexApdu, nfc_scene_debug_submenu_callback, nfc);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDebug));
|
||||
|
||||
nfc_device_clear(nfc->dev);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
|
||||
bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = (Nfc*)context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuDebugIndexField) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneDebug, SubmenuDebugIndexField);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneField);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuDebugIndexApdu) {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneDebug, SubmenuDebugIndexApdu);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateApduSequence);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_debug_on_exit(void* context) {
|
||||
Nfc* nfc = (Nfc*)context;
|
||||
|
||||
submenu_reset(nfc->submenu);
|
||||
}
|
||||
@ -32,7 +32,5 @@ void nfc_scene_emulate_apdu_sequence_on_exit(void* context) {
|
||||
|
||||
// Clear view
|
||||
Popup* popup = nfc->popup;
|
||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 0, NULL);
|
||||
popup_reset(popup);
|
||||
}
|
||||
|
||||
34
applications/nfc/scenes/nfc_scene_field.c
Normal file
34
applications/nfc/scenes/nfc_scene_field.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
void nfc_scene_field_on_enter(void* context) {
|
||||
Nfc* nfc = (Nfc*)context;
|
||||
|
||||
furi_hal_nfc_field_on();
|
||||
|
||||
Popup* popup = nfc->popup;
|
||||
popup_set_header(
|
||||
popup,
|
||||
"Field is on\nDon't leave device\nin this mode for too long.",
|
||||
64,
|
||||
11,
|
||||
AlignCenter,
|
||||
AlignTop);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
|
||||
notification_internal_message(nfc->notifications, &sequence_set_blue_255);
|
||||
}
|
||||
|
||||
bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void nfc_scene_field_on_exit(void* context) {
|
||||
Nfc* nfc = (Nfc*)context;
|
||||
|
||||
notification_internal_message(nfc->notifications, &sequence_reset_blue);
|
||||
|
||||
Popup* popup = nfc->popup;
|
||||
popup_reset(popup);
|
||||
|
||||
furi_hal_nfc_field_off();
|
||||
}
|
||||
@ -17,7 +17,7 @@ void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
|
||||
dialog_ex_set_header(dialog_ex, "Run EMV app?", 64, 8, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex,
|
||||
"It will try to run card's app\nand detect unencrypred\ndata",
|
||||
"It will try to run card's app\nand detect unencrypted\ndata",
|
||||
64,
|
||||
18,
|
||||
AlignCenter,
|
||||
|
||||
@ -68,7 +68,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexDebug) {
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateApduSequence);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +54,9 @@ static void power_cli_command_print_usage() {
|
||||
printf("\treboot2dfu\t - reboot to dfu bootloader\r\n");
|
||||
printf("\tdebug\t - show debug information\r\n");
|
||||
printf("\t5v <0 or 1>\t - enable or disable 5v ext\r\n");
|
||||
printf("\t3v3 <0 or 1>\t - enable or disable 3v3 ext\r\n");
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
printf("\t3v3 <0 or 1>\t - enable or disable 3v3 ext\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void power_cli(Cli* cli, string_t args, void* context) {
|
||||
@ -92,9 +94,11 @@ void power_cli(Cli* cli, string_t args, void* context) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "3v3") == 0) {
|
||||
power_cli_3v3(cli, args);
|
||||
break;
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
if(string_cmp_str(cmd, "3v3") == 0) {
|
||||
power_cli_3v3(cli, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
power_cli_command_print_usage();
|
||||
|
||||
@ -19,9 +19,12 @@
|
||||
|
||||
#define TAG "RpcSrv"
|
||||
|
||||
#define RPC_EVENT_NEW_DATA (1 << 0)
|
||||
#define RPC_EVENT_DISCONNECT (1 << 1)
|
||||
#define RPC_EVENTS_ALL (RPC_EVENT_DISCONNECT | RPC_EVENT_NEW_DATA)
|
||||
typedef enum {
|
||||
RpcEvtNewData = (1 << 0),
|
||||
RpcEvtDisconnect = (1 << 1),
|
||||
} RpcEvtFlags;
|
||||
|
||||
#define RPC_ALL_EVENTS (RpcEvtNewData | RpcEvtDisconnect)
|
||||
|
||||
DICT_DEF2(RpcHandlerDict, pb_size_t, M_DEFAULT_OPLIST, RpcHandler, M_POD_OPLIST)
|
||||
|
||||
@ -51,44 +54,45 @@ static RpcSystemCallbacks rpc_systems[] = {
|
||||
};
|
||||
|
||||
struct RpcSession {
|
||||
Rpc* rpc;
|
||||
|
||||
FuriThread* thread;
|
||||
|
||||
RpcHandlerDict_t handlers;
|
||||
StreamBufferHandle_t stream;
|
||||
PB_Main* decoded_message;
|
||||
bool terminate;
|
||||
void** system_contexts;
|
||||
bool decode_error;
|
||||
|
||||
osMutexId_t callbacks_mutex;
|
||||
RpcSendBytesCallback send_bytes_callback;
|
||||
RpcBufferIsEmptyCallback buffer_is_empty_callback;
|
||||
RpcSessionClosedCallback closed_callback;
|
||||
RpcSessionTerminatedCallback terminated_callback;
|
||||
void* context;
|
||||
osMutexId_t callbacks_mutex;
|
||||
Rpc* rpc;
|
||||
bool terminate;
|
||||
void** system_contexts;
|
||||
bool decode_error;
|
||||
};
|
||||
|
||||
struct Rpc {
|
||||
bool busy;
|
||||
osMutexId_t busy_mutex;
|
||||
RpcSession session;
|
||||
osEventFlagsId_t events;
|
||||
StreamBufferHandle_t stream;
|
||||
RpcHandlerDict_t handlers;
|
||||
PB_Main* decoded_message;
|
||||
};
|
||||
|
||||
static bool content_callback(pb_istream_t* stream, const pb_field_t* field, void** arg);
|
||||
|
||||
static void rpc_close_session_process(const PB_Main* msg_request, void* context) {
|
||||
furi_assert(msg_request);
|
||||
furi_assert(context);
|
||||
static void rpc_close_session_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
|
||||
Rpc* rpc = context;
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
rpc_send_and_release_empty(rpc, msg_request->command_id, PB_CommandStatus_OK);
|
||||
osMutexAcquire(rpc->session.callbacks_mutex, osWaitForever);
|
||||
if(rpc->session.closed_callback) {
|
||||
rpc->session.closed_callback(rpc->session.context);
|
||||
rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK);
|
||||
osMutexAcquire(session->callbacks_mutex, osWaitForever);
|
||||
if(session->closed_callback) {
|
||||
session->closed_callback(session->context);
|
||||
} else {
|
||||
FURI_LOG_W(TAG, "Session stop doesn't processed by transport layer");
|
||||
FURI_LOG_W(TAG, "Session stop isn't processed by transport layer");
|
||||
}
|
||||
osMutexRelease(rpc->session.callbacks_mutex);
|
||||
osMutexRelease(session->callbacks_mutex);
|
||||
}
|
||||
|
||||
static size_t rpc_sprintf_msg_file(
|
||||
@ -349,94 +353,8 @@ void rpc_print_message(const PB_Main* message) {
|
||||
string_clear(str);
|
||||
}
|
||||
|
||||
static Rpc* rpc_alloc(void) {
|
||||
Rpc* rpc = malloc(sizeof(Rpc));
|
||||
rpc->busy_mutex = osMutexNew(NULL);
|
||||
rpc->busy = false;
|
||||
rpc->events = osEventFlagsNew(NULL);
|
||||
rpc->stream = xStreamBufferCreate(RPC_BUFFER_SIZE, 1);
|
||||
|
||||
rpc->decoded_message = malloc(sizeof(PB_Main));
|
||||
rpc->decoded_message->cb_content.funcs.decode = content_callback;
|
||||
rpc->decoded_message->cb_content.arg = rpc;
|
||||
|
||||
RpcHandlerDict_init(rpc->handlers);
|
||||
|
||||
return rpc;
|
||||
}
|
||||
|
||||
RpcSession* rpc_session_open(Rpc* rpc) {
|
||||
furi_assert(rpc);
|
||||
bool result = false;
|
||||
furi_check(osMutexAcquire(rpc->busy_mutex, osWaitForever) == osOK);
|
||||
if(rpc->busy) {
|
||||
result = false;
|
||||
} else {
|
||||
rpc->busy = true;
|
||||
result = true;
|
||||
}
|
||||
furi_check(osMutexRelease(rpc->busy_mutex) == osOK);
|
||||
|
||||
if(result) {
|
||||
RpcSession* session = &rpc->session;
|
||||
session->callbacks_mutex = osMutexNew(NULL);
|
||||
session->rpc = rpc;
|
||||
session->terminate = false;
|
||||
session->decode_error = false;
|
||||
xStreamBufferReset(rpc->stream);
|
||||
|
||||
session->system_contexts = malloc(COUNT_OF(rpc_systems) * sizeof(void*));
|
||||
for(int i = 0; i < COUNT_OF(rpc_systems); ++i) {
|
||||
session->system_contexts[i] = rpc_systems[i].alloc(rpc);
|
||||
}
|
||||
|
||||
RpcHandler rpc_handler = {
|
||||
.message_handler = rpc_close_session_process,
|
||||
.decode_submessage = NULL,
|
||||
.context = rpc,
|
||||
};
|
||||
rpc_add_handler(rpc, PB_Main_stop_session_tag, &rpc_handler);
|
||||
|
||||
FURI_LOG_D(TAG, "Session started");
|
||||
}
|
||||
|
||||
return result ? &rpc->session : NULL; /* support 1 open session for now */
|
||||
}
|
||||
|
||||
void rpc_session_close(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
furi_assert(session->rpc);
|
||||
furi_assert(session->rpc->busy);
|
||||
|
||||
rpc_session_set_send_bytes_callback(session, NULL);
|
||||
rpc_session_set_close_callback(session, NULL);
|
||||
rpc_session_set_buffer_is_empty_callback(session, NULL);
|
||||
osEventFlagsSet(session->rpc->events, RPC_EVENT_DISCONNECT);
|
||||
}
|
||||
|
||||
static void rpc_free_session(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
|
||||
for(int i = 0; i < COUNT_OF(rpc_systems); ++i) {
|
||||
if(rpc_systems[i].free) {
|
||||
rpc_systems[i].free(session->system_contexts[i]);
|
||||
}
|
||||
}
|
||||
free(session->system_contexts);
|
||||
osMutexDelete(session->callbacks_mutex);
|
||||
RpcHandlerDict_reset(session->rpc->handlers);
|
||||
|
||||
session->context = NULL;
|
||||
session->closed_callback = NULL;
|
||||
session->send_bytes_callback = NULL;
|
||||
session->buffer_is_empty_callback = NULL;
|
||||
session->terminated_callback = NULL;
|
||||
}
|
||||
|
||||
void rpc_session_set_context(RpcSession* session, void* context) {
|
||||
furi_assert(session);
|
||||
furi_assert(session->rpc);
|
||||
furi_assert(session->rpc->busy);
|
||||
|
||||
osMutexAcquire(session->callbacks_mutex, osWaitForever);
|
||||
session->context = context;
|
||||
@ -445,8 +363,6 @@ void rpc_session_set_context(RpcSession* session, void* context) {
|
||||
|
||||
void rpc_session_set_close_callback(RpcSession* session, RpcSessionClosedCallback callback) {
|
||||
furi_assert(session);
|
||||
furi_assert(session->rpc);
|
||||
furi_assert(session->rpc->busy);
|
||||
|
||||
osMutexAcquire(session->callbacks_mutex, osWaitForever);
|
||||
session->closed_callback = callback;
|
||||
@ -455,8 +371,6 @@ void rpc_session_set_close_callback(RpcSession* session, RpcSessionClosedCallbac
|
||||
|
||||
void rpc_session_set_send_bytes_callback(RpcSession* session, RpcSendBytesCallback callback) {
|
||||
furi_assert(session);
|
||||
furi_assert(session->rpc);
|
||||
furi_assert(session->rpc->busy);
|
||||
|
||||
osMutexAcquire(session->callbacks_mutex, osWaitForever);
|
||||
session->send_bytes_callback = callback;
|
||||
@ -467,7 +381,6 @@ void rpc_session_set_buffer_is_empty_callback(
|
||||
RpcSession* session,
|
||||
RpcBufferIsEmptyCallback callback) {
|
||||
furi_assert(session);
|
||||
furi_assert(session->rpc->busy);
|
||||
|
||||
osMutexAcquire(session->callbacks_mutex, osWaitForever);
|
||||
session->buffer_is_empty_callback = callback;
|
||||
@ -478,8 +391,6 @@ void rpc_session_set_terminated_callback(
|
||||
RpcSession* session,
|
||||
RpcSessionTerminatedCallback callback) {
|
||||
furi_assert(session);
|
||||
furi_assert(session->rpc);
|
||||
furi_assert(session->rpc->busy);
|
||||
|
||||
osMutexAcquire(session->callbacks_mutex, osWaitForever);
|
||||
session->terminated_callback = callback;
|
||||
@ -495,54 +406,54 @@ void rpc_session_set_terminated_callback(
|
||||
size_t
|
||||
rpc_session_feed(RpcSession* session, uint8_t* encoded_bytes, size_t size, TickType_t timeout) {
|
||||
furi_assert(session);
|
||||
Rpc* rpc = session->rpc;
|
||||
furi_assert(rpc->busy);
|
||||
size_t bytes_sent = xStreamBufferSend(session->stream, encoded_bytes, size, timeout);
|
||||
|
||||
size_t bytes_sent = xStreamBufferSend(rpc->stream, encoded_bytes, size, timeout);
|
||||
osEventFlagsSet(rpc->events, RPC_EVENT_NEW_DATA);
|
||||
osThreadFlagsSet(furi_thread_get_thread_id(session->thread), RpcEvtNewData);
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
size_t rpc_session_get_available_size(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
Rpc* rpc = session->rpc;
|
||||
return xStreamBufferSpacesAvailable(rpc->stream);
|
||||
return xStreamBufferSpacesAvailable(session->stream);
|
||||
}
|
||||
|
||||
bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
|
||||
Rpc* rpc = istream->state;
|
||||
RpcSession* session = istream->state;
|
||||
furi_assert(session);
|
||||
furi_assert(istream->bytes_left);
|
||||
|
||||
uint32_t flags = 0;
|
||||
size_t bytes_received = 0;
|
||||
|
||||
furi_assert(istream->bytes_left);
|
||||
|
||||
while(1) {
|
||||
bytes_received +=
|
||||
xStreamBufferReceive(rpc->stream, buf + bytes_received, count - bytes_received, 0);
|
||||
if(xStreamBufferIsEmpty(rpc->stream)) {
|
||||
if(rpc->session.buffer_is_empty_callback) {
|
||||
rpc->session.buffer_is_empty_callback(rpc->session.context);
|
||||
xStreamBufferReceive(session->stream, buf + bytes_received, count - bytes_received, 0);
|
||||
if(xStreamBufferIsEmpty(session->stream)) {
|
||||
if(session->buffer_is_empty_callback) {
|
||||
session->buffer_is_empty_callback(session->context);
|
||||
}
|
||||
}
|
||||
if(rpc->session.decode_error) {
|
||||
if(session->decode_error) {
|
||||
/* never go out till RPC_EVENT_DISCONNECT come */
|
||||
bytes_received = 0;
|
||||
}
|
||||
if(count == bytes_received) {
|
||||
break;
|
||||
} else {
|
||||
flags = osEventFlagsWait(rpc->events, RPC_EVENTS_ALL, 0, osWaitForever);
|
||||
if(flags & RPC_EVENT_DISCONNECT) {
|
||||
if(xStreamBufferIsEmpty(rpc->stream)) {
|
||||
rpc->session.terminate = true;
|
||||
flags = osThreadFlagsWait(RPC_ALL_EVENTS, osFlagsWaitAny, osWaitForever);
|
||||
if(flags & RpcEvtDisconnect) {
|
||||
if(xStreamBufferIsEmpty(session->stream)) {
|
||||
session->terminate = true;
|
||||
istream->bytes_left = 0;
|
||||
bytes_received = 0;
|
||||
break;
|
||||
} else {
|
||||
/* Save disconnect flag and continue reading buffer */
|
||||
osEventFlagsSet(rpc->events, RPC_EVENT_DISCONNECT);
|
||||
osThreadFlagsSet(furi_thread_get_thread_id(session->thread), RpcEvtDisconnect);
|
||||
}
|
||||
} else if(flags & RpcEvtNewData) {
|
||||
// Just wake thread up
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -554,10 +465,211 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
|
||||
return (count == bytes_received);
|
||||
}
|
||||
|
||||
void rpc_send_and_release(Rpc* rpc, PB_Main* message) {
|
||||
static bool content_callback(pb_istream_t* stream, const pb_field_t* field, void** arg) {
|
||||
furi_assert(stream);
|
||||
RpcSession* session = stream->state;
|
||||
furi_assert(session);
|
||||
|
||||
RpcHandler* handler = RpcHandlerDict_get(session->handlers, field->tag);
|
||||
|
||||
if(handler && handler->decode_submessage) {
|
||||
handler->decode_submessage(stream, field, arg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int32_t rpc_session_worker(void* context) {
|
||||
furi_assert(context);
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
Rpc* rpc = session->rpc;
|
||||
|
||||
FURI_LOG_D(TAG, "Session started");
|
||||
|
||||
while(1) {
|
||||
pb_istream_t istream = {
|
||||
.callback = rpc_pb_stream_read,
|
||||
.state = session,
|
||||
.errmsg = NULL,
|
||||
.bytes_left = RPC_MAX_MESSAGE_SIZE, /* max incoming message size */
|
||||
};
|
||||
|
||||
bool message_decode_failed = false;
|
||||
|
||||
if(pb_decode_ex(&istream, &PB_Main_msg, session->decoded_message, PB_DECODE_DELIMITED)) {
|
||||
#if SRV_RPC_DEBUG
|
||||
FURI_LOG_I(TAG, "INPUT:");
|
||||
rpc_print_message(session->decoded_message);
|
||||
#endif
|
||||
RpcHandler* handler =
|
||||
RpcHandlerDict_get(session->handlers, session->decoded_message->which_content);
|
||||
|
||||
if(handler && handler->message_handler) {
|
||||
furi_check(osMutexAcquire(rpc->busy_mutex, osWaitForever) == osOK);
|
||||
handler->message_handler(session->decoded_message, handler->context);
|
||||
furi_check(osMutexRelease(rpc->busy_mutex) == osOK);
|
||||
} else if(session->decoded_message->which_content == 0) {
|
||||
/* Receiving zeroes means message is 0-length, which
|
||||
* is valid for proto3: all fields are filled with default values.
|
||||
* 0 - is default value for which_content field.
|
||||
* Mark it as decode error, because there is no content message
|
||||
* in Main message with tag 0.
|
||||
*/
|
||||
message_decode_failed = true;
|
||||
} else if(!handler && !session->terminate) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"Message(%d) decoded, but not implemented",
|
||||
session->decoded_message->which_content);
|
||||
rpc_send_and_release_empty(
|
||||
session,
|
||||
session->decoded_message->command_id,
|
||||
PB_CommandStatus_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
} else {
|
||||
message_decode_failed = true;
|
||||
}
|
||||
|
||||
if(message_decode_failed) {
|
||||
xStreamBufferReset(session->stream);
|
||||
if(!session->terminate) {
|
||||
/* Protobuf can't determine start and end of message.
|
||||
* Handle this by adding varint at beginning
|
||||
* of a message (PB_ENCODE_DELIMITED). But decoding fail
|
||||
* means we can't be sure next bytes are varint for next
|
||||
* message, so the only way to close session.
|
||||
* RPC itself can't make decision to close session. It has
|
||||
* to notify:
|
||||
* 1) down layer (transport)
|
||||
* 2) other side (companion app)
|
||||
* Who are responsible to handle RPC session lifecycle.
|
||||
* Companion receives 2 messages: ERROR_DECODE and session_closed.
|
||||
*/
|
||||
FURI_LOG_E(TAG, "Decode failed, error: \'%.128s\'", PB_GET_ERROR(&istream));
|
||||
session->decode_error = true;
|
||||
rpc_send_and_release_empty(session, 0, PB_CommandStatus_ERROR_DECODE);
|
||||
osMutexAcquire(session->callbacks_mutex, osWaitForever);
|
||||
if(session->closed_callback) {
|
||||
session->closed_callback(session->context);
|
||||
}
|
||||
osMutexRelease(session->callbacks_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
pb_release(&PB_Main_msg, session->decoded_message);
|
||||
|
||||
if(session->terminate) {
|
||||
FURI_LOG_D(TAG, "Session terminated");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rpc_session_free_callback(FuriThreadState thread_state, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
|
||||
if(thread_state == FuriThreadStateStopped) {
|
||||
for(int i = 0; i < COUNT_OF(rpc_systems); ++i) {
|
||||
if(rpc_systems[i].free) {
|
||||
rpc_systems[i].free(session->system_contexts[i]);
|
||||
}
|
||||
}
|
||||
free(session->system_contexts);
|
||||
free(session->decoded_message);
|
||||
RpcHandlerDict_clear(session->handlers);
|
||||
vStreamBufferDelete(session->stream);
|
||||
|
||||
osMutexAcquire(session->callbacks_mutex, osWaitForever);
|
||||
if(session->terminated_callback) {
|
||||
session->terminated_callback(session->context);
|
||||
}
|
||||
osMutexRelease(session->callbacks_mutex);
|
||||
|
||||
osMutexDelete(session->callbacks_mutex);
|
||||
furi_thread_free(session->thread);
|
||||
free(session);
|
||||
}
|
||||
}
|
||||
|
||||
RpcSession* rpc_session_open(Rpc* rpc) {
|
||||
furi_assert(rpc);
|
||||
|
||||
RpcSession* session = malloc(sizeof(RpcSession));
|
||||
session->callbacks_mutex = osMutexNew(NULL);
|
||||
session->stream = xStreamBufferCreate(RPC_BUFFER_SIZE, 1);
|
||||
session->rpc = rpc;
|
||||
session->terminate = false;
|
||||
session->decode_error = false;
|
||||
RpcHandlerDict_init(session->handlers);
|
||||
|
||||
session->decoded_message = malloc(sizeof(PB_Main));
|
||||
session->decoded_message->cb_content.funcs.decode = content_callback;
|
||||
session->decoded_message->cb_content.arg = session;
|
||||
|
||||
session->system_contexts = malloc(COUNT_OF(rpc_systems) * sizeof(void*));
|
||||
for(int i = 0; i < COUNT_OF(rpc_systems); ++i) {
|
||||
session->system_contexts[i] = rpc_systems[i].alloc(session);
|
||||
}
|
||||
|
||||
RpcHandler rpc_handler = {
|
||||
.message_handler = rpc_close_session_process,
|
||||
.decode_submessage = NULL,
|
||||
.context = session,
|
||||
};
|
||||
rpc_add_handler(session, PB_Main_stop_session_tag, &rpc_handler);
|
||||
|
||||
session->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(session->thread, "RpcSessionWorker");
|
||||
furi_thread_set_stack_size(session->thread, 2048);
|
||||
furi_thread_set_context(session->thread, session);
|
||||
furi_thread_set_callback(session->thread, rpc_session_worker);
|
||||
|
||||
furi_thread_set_state_context(session->thread, session);
|
||||
furi_thread_set_state_callback(session->thread, rpc_session_free_callback);
|
||||
|
||||
furi_thread_start(session->thread);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
void rpc_session_close(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
furi_assert(session->rpc);
|
||||
|
||||
rpc_session_set_send_bytes_callback(session, NULL);
|
||||
rpc_session_set_close_callback(session, NULL);
|
||||
rpc_session_set_buffer_is_empty_callback(session, NULL);
|
||||
osThreadFlagsSet(furi_thread_get_thread_id(session->thread), RpcEvtDisconnect);
|
||||
}
|
||||
|
||||
int32_t rpc_srv(void* p) {
|
||||
Rpc* rpc = malloc(sizeof(Rpc));
|
||||
|
||||
rpc->busy_mutex = osMutexNew(NULL);
|
||||
|
||||
Cli* cli = furi_record_open("cli");
|
||||
cli_add_command(
|
||||
cli, "start_rpc_session", CliCommandFlagParallelSafe, rpc_cli_command_start_session, rpc);
|
||||
|
||||
furi_record_create("rpc", rpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rpc_add_handler(RpcSession* session, pb_size_t message_tag, RpcHandler* handler) {
|
||||
furi_assert(RpcHandlerDict_get(session->handlers, message_tag) == NULL);
|
||||
|
||||
RpcHandlerDict_set_at(session->handlers, message_tag, *handler);
|
||||
}
|
||||
|
||||
void rpc_send(RpcSession* session, PB_Main* message) {
|
||||
furi_assert(session);
|
||||
furi_assert(message);
|
||||
RpcSession* session = &rpc->session;
|
||||
|
||||
pb_ostream_t ostream = PB_OSTREAM_SIZING;
|
||||
|
||||
#if SRV_RPC_DEBUG
|
||||
@ -584,127 +696,20 @@ void rpc_send_and_release(Rpc* rpc, PB_Main* message) {
|
||||
osMutexRelease(session->callbacks_mutex);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void rpc_send_and_release(RpcSession* session, PB_Main* message) {
|
||||
rpc_send(session, message);
|
||||
pb_release(&PB_Main_msg, message);
|
||||
}
|
||||
|
||||
static bool content_callback(pb_istream_t* stream, const pb_field_t* field, void** arg) {
|
||||
furi_assert(stream);
|
||||
Rpc* rpc = *arg;
|
||||
|
||||
RpcHandler* handler = RpcHandlerDict_get(rpc->handlers, field->tag);
|
||||
|
||||
if(handler && handler->decode_submessage) {
|
||||
handler->decode_submessage(stream, field, arg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t rpc_srv(void* p) {
|
||||
Rpc* rpc = rpc_alloc();
|
||||
furi_record_create("rpc", rpc);
|
||||
|
||||
Cli* cli = furi_record_open("cli");
|
||||
|
||||
cli_add_command(
|
||||
cli, "start_rpc_session", CliCommandFlagParallelSafe, rpc_cli_command_start_session, rpc);
|
||||
|
||||
while(1) {
|
||||
pb_istream_t istream = {
|
||||
.callback = rpc_pb_stream_read,
|
||||
.state = rpc,
|
||||
.errmsg = NULL,
|
||||
.bytes_left = RPC_MAX_MESSAGE_SIZE, /* max incoming message size */
|
||||
};
|
||||
|
||||
bool message_decode_failed = false;
|
||||
|
||||
if(pb_decode_ex(&istream, &PB_Main_msg, rpc->decoded_message, PB_DECODE_DELIMITED)) {
|
||||
#if SRV_RPC_DEBUG
|
||||
FURI_LOG_I(TAG, "INPUT:");
|
||||
rpc_print_message(rpc->decoded_message);
|
||||
#endif
|
||||
RpcHandler* handler =
|
||||
RpcHandlerDict_get(rpc->handlers, rpc->decoded_message->which_content);
|
||||
|
||||
if(handler && handler->message_handler) {
|
||||
handler->message_handler(rpc->decoded_message, handler->context);
|
||||
} else if(rpc->decoded_message->which_content == 0) {
|
||||
/* Receiving zeroes means message is 0-length, which
|
||||
* is valid for proto3: all fields are filled with default values.
|
||||
* 0 - is default value for which_content field.
|
||||
* Mark it as decode error, because there is no content message
|
||||
* in Main message with tag 0.
|
||||
*/
|
||||
message_decode_failed = true;
|
||||
} else if(!handler && !rpc->session.terminate) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"Message(%d) decoded, but not implemented",
|
||||
rpc->decoded_message->which_content);
|
||||
rpc_send_and_release_empty(
|
||||
rpc, rpc->decoded_message->command_id, PB_CommandStatus_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
} else {
|
||||
message_decode_failed = true;
|
||||
}
|
||||
|
||||
if(message_decode_failed) {
|
||||
xStreamBufferReset(rpc->stream);
|
||||
if(!rpc->session.terminate) {
|
||||
/* Protobuf can't determine start and end of message.
|
||||
* Handle this by adding varint at beginning
|
||||
* of a message (PB_ENCODE_DELIMITED). But decoding fail
|
||||
* means we can't be sure next bytes are varint for next
|
||||
* message, so the only way to close session.
|
||||
* RPC itself can't make decision to close session. It has
|
||||
* to notify:
|
||||
* 1) down layer (transport)
|
||||
* 2) other side (companion app)
|
||||
* Who are responsible to handle RPC session lifecycle.
|
||||
* Companion receives 2 messages: ERROR_DECODE and session_closed.
|
||||
*/
|
||||
FURI_LOG_E(TAG, "Decode failed, error: \'%.128s\'", PB_GET_ERROR(&istream));
|
||||
rpc->session.decode_error = true;
|
||||
rpc_send_and_release_empty(rpc, 0, PB_CommandStatus_ERROR_DECODE);
|
||||
osMutexAcquire(rpc->session.callbacks_mutex, osWaitForever);
|
||||
if(rpc->session.closed_callback) {
|
||||
rpc->session.closed_callback(rpc->session.context);
|
||||
}
|
||||
osMutexRelease(rpc->session.callbacks_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
pb_release(&PB_Main_msg, rpc->decoded_message);
|
||||
|
||||
if(rpc->session.terminate) {
|
||||
FURI_LOG_D(TAG, "Session terminated");
|
||||
osMutexAcquire(rpc->session.callbacks_mutex, osWaitForever);
|
||||
if(rpc->session.terminated_callback) {
|
||||
rpc->session.terminated_callback(rpc->session.context);
|
||||
}
|
||||
osMutexRelease(rpc->session.callbacks_mutex);
|
||||
osEventFlagsClear(rpc->events, RPC_EVENTS_ALL);
|
||||
rpc_free_session(&rpc->session);
|
||||
rpc->busy = false;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rpc_add_handler(Rpc* rpc, pb_size_t message_tag, RpcHandler* handler) {
|
||||
furi_assert(RpcHandlerDict_get(rpc->handlers, message_tag) == NULL);
|
||||
|
||||
RpcHandlerDict_set_at(rpc->handlers, message_tag, *handler);
|
||||
}
|
||||
|
||||
void rpc_send_and_release_empty(Rpc* rpc, uint32_t command_id, PB_CommandStatus status) {
|
||||
void rpc_send_and_release_empty(RpcSession* session, uint32_t command_id, PB_CommandStatus status) {
|
||||
PB_Main message = {
|
||||
.command_id = command_id,
|
||||
.command_status = status,
|
||||
.has_next = false,
|
||||
.which_content = PB_Main_empty_tag,
|
||||
};
|
||||
rpc_send_and_release(rpc, &message);
|
||||
rpc_send_and_release(session, &message);
|
||||
pb_release(&PB_Main_msg, &message);
|
||||
}
|
||||
|
||||
@ -5,10 +5,11 @@
|
||||
#include <loader/loader.h>
|
||||
|
||||
static void rpc_system_app_start_process(const PB_Main* request, void* context) {
|
||||
Rpc* rpc = context;
|
||||
furi_assert(rpc);
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_app_start_request_tag);
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
PB_CommandStatus result = PB_CommandStatus_ERROR_APP_CANT_START;
|
||||
|
||||
Loader* loader = furi_record_open("loader");
|
||||
@ -33,14 +34,14 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context)
|
||||
|
||||
furi_record_close("loader");
|
||||
|
||||
rpc_send_and_release_empty(rpc, request->command_id, result);
|
||||
rpc_send_and_release_empty(session, request->command_id, result);
|
||||
}
|
||||
|
||||
static void rpc_system_app_lock_status_process(const PB_Main* request, void* context) {
|
||||
Rpc* rpc = context;
|
||||
furi_assert(rpc);
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_app_lock_status_request_tag);
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
Loader* loader = furi_record_open("loader");
|
||||
|
||||
@ -55,24 +56,24 @@ static void rpc_system_app_lock_status_process(const PB_Main* request, void* con
|
||||
|
||||
furi_record_close("loader");
|
||||
|
||||
rpc_send_and_release(rpc, &response);
|
||||
rpc_send_and_release(session, &response);
|
||||
pb_release(&PB_Main_msg, &response);
|
||||
}
|
||||
|
||||
void* rpc_system_app_alloc(Rpc* rpc) {
|
||||
furi_assert(rpc);
|
||||
void* rpc_system_app_alloc(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
|
||||
RpcHandler rpc_handler = {
|
||||
.message_handler = NULL,
|
||||
.decode_submessage = NULL,
|
||||
.context = rpc,
|
||||
.context = session,
|
||||
};
|
||||
|
||||
rpc_handler.message_handler = rpc_system_app_start_process;
|
||||
rpc_add_handler(rpc, PB_Main_app_start_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_app_start_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_app_lock_status_process;
|
||||
rpc_add_handler(rpc, PB_Main_app_lock_status_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_app_lock_status_request_tag, &rpc_handler);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ void rpc_cli_command_start_session(Cli* cli, string_t args, void* context) {
|
||||
|
||||
RpcSession* rpc_session = rpc_session_open(rpc);
|
||||
if(rpc_session == NULL) {
|
||||
printf("Another session is in progress\r\n");
|
||||
printf("Session start error\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -5,35 +5,61 @@
|
||||
|
||||
#define TAG "RpcGui"
|
||||
|
||||
typedef enum {
|
||||
RpcGuiWorkerFlagTransmit = (1 << 0),
|
||||
RpcGuiWorkerFlagExit = (1 << 1),
|
||||
} RpcGuiWorkerFlag;
|
||||
|
||||
#define RpcGuiWorkerFlagAny (RpcGuiWorkerFlagTransmit | RpcGuiWorkerFlagExit)
|
||||
|
||||
typedef struct {
|
||||
Rpc* rpc;
|
||||
RpcSession* session;
|
||||
Gui* gui;
|
||||
|
||||
// Receive part
|
||||
ViewPort* virtual_display_view_port;
|
||||
uint8_t* virtual_display_buffer;
|
||||
|
||||
// Transmit
|
||||
PB_Main* transmit_frame;
|
||||
FuriThread* transmit_thread;
|
||||
|
||||
bool virtual_display_not_empty;
|
||||
bool is_streaming;
|
||||
} RpcGuiSystem;
|
||||
|
||||
static void
|
||||
rpc_system_gui_screen_stream_frame_callback(uint8_t* data, size_t size, void* context) {
|
||||
furi_assert(data);
|
||||
furi_assert(size == 1024);
|
||||
furi_assert(context);
|
||||
|
||||
RpcGuiSystem* rpc_gui = context;
|
||||
RpcGuiSystem* rpc_gui = (RpcGuiSystem*)context;
|
||||
uint8_t* buffer = rpc_gui->transmit_frame->content.gui_screen_frame.data->bytes;
|
||||
|
||||
PB_Main* frame = malloc(sizeof(PB_Main));
|
||||
furi_assert(size == rpc_gui->transmit_frame->content.gui_screen_frame.data->size);
|
||||
|
||||
frame->which_content = PB_Main_gui_screen_frame_tag;
|
||||
frame->command_status = PB_CommandStatus_OK;
|
||||
frame->content.gui_screen_frame.data = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size));
|
||||
uint8_t* buffer = frame->content.gui_screen_frame.data->bytes;
|
||||
uint16_t* frame_size_msg = &frame->content.gui_screen_frame.data->size;
|
||||
*frame_size_msg = size;
|
||||
memcpy(buffer, data, size);
|
||||
|
||||
rpc_send_and_release(rpc_gui->rpc, frame);
|
||||
osThreadFlagsSet(
|
||||
furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagTransmit);
|
||||
}
|
||||
|
||||
free(frame);
|
||||
static int32_t rpc_system_gui_screen_stream_frame_transmit_thread(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
RpcGuiSystem* rpc_gui = (RpcGuiSystem*)context;
|
||||
|
||||
while(true) {
|
||||
uint32_t flags = osThreadFlagsWait(RpcGuiWorkerFlagAny, osFlagsWaitAny, osWaitForever);
|
||||
if(flags & RpcGuiWorkerFlagTransmit) {
|
||||
rpc_send(rpc_gui->session, rpc_gui->transmit_frame);
|
||||
}
|
||||
if(flags & RpcGuiWorkerFlagExit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rpc_system_gui_start_screen_stream_process(const PB_Main* request, void* context) {
|
||||
@ -41,20 +67,59 @@ static void rpc_system_gui_start_screen_stream_process(const PB_Main* request, v
|
||||
furi_assert(context);
|
||||
RpcGuiSystem* rpc_gui = context;
|
||||
|
||||
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
|
||||
RpcSession* session = rpc_gui->session;
|
||||
furi_assert(session);
|
||||
furi_assert(!rpc_gui->is_streaming);
|
||||
|
||||
gui_set_framebuffer_callback(
|
||||
rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK);
|
||||
|
||||
rpc_gui->is_streaming = true;
|
||||
size_t framebuffer_size = gui_get_framebuffer_size(rpc_gui->gui);
|
||||
// Reusable Frame
|
||||
rpc_gui->transmit_frame = malloc(sizeof(PB_Main));
|
||||
rpc_gui->transmit_frame->which_content = PB_Main_gui_screen_frame_tag;
|
||||
rpc_gui->transmit_frame->command_status = PB_CommandStatus_OK;
|
||||
rpc_gui->transmit_frame->content.gui_screen_frame.data =
|
||||
malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(framebuffer_size));
|
||||
rpc_gui->transmit_frame->content.gui_screen_frame.data->size = framebuffer_size;
|
||||
// Transmission thread for async TX
|
||||
rpc_gui->transmit_thread = furi_thread_alloc();
|
||||
furi_thread_set_name(rpc_gui->transmit_thread, "GuiRpcWorker");
|
||||
furi_thread_set_callback(
|
||||
rpc_gui->transmit_thread, rpc_system_gui_screen_stream_frame_transmit_thread);
|
||||
furi_thread_set_context(rpc_gui->transmit_thread, rpc_gui);
|
||||
furi_thread_set_stack_size(rpc_gui->transmit_thread, 1024);
|
||||
furi_thread_start(rpc_gui->transmit_thread);
|
||||
// GUI framebuffer callback
|
||||
gui_add_framebuffer_callback(
|
||||
rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context);
|
||||
}
|
||||
|
||||
static void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(context);
|
||||
|
||||
RpcGuiSystem* rpc_gui = context;
|
||||
RpcSession* session = rpc_gui->session;
|
||||
furi_assert(session);
|
||||
|
||||
gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL);
|
||||
if(rpc_gui->is_streaming) {
|
||||
rpc_gui->is_streaming = false;
|
||||
// Remove GUI framebuffer callback
|
||||
gui_remove_framebuffer_callback(
|
||||
rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context);
|
||||
// Stop and release worker thread
|
||||
osThreadFlagsSet(
|
||||
furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit);
|
||||
furi_thread_join(rpc_gui->transmit_thread);
|
||||
furi_thread_free(rpc_gui->transmit_thread);
|
||||
// Release frame
|
||||
pb_release(&PB_Main_msg, rpc_gui->transmit_frame);
|
||||
free(rpc_gui->transmit_frame);
|
||||
rpc_gui->transmit_frame = NULL;
|
||||
}
|
||||
|
||||
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
|
||||
rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -62,7 +127,10 @@ static void
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_gui_send_input_event_request_tag);
|
||||
furi_assert(context);
|
||||
|
||||
RpcGuiSystem* rpc_gui = context;
|
||||
RpcSession* session = rpc_gui->session;
|
||||
furi_assert(session);
|
||||
|
||||
InputEvent event;
|
||||
|
||||
@ -117,7 +185,7 @@ static void
|
||||
|
||||
if(invalid) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_gui->rpc, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
session, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -125,12 +193,13 @@ static void
|
||||
furi_check(input_events);
|
||||
furi_pubsub_publish(input_events, &event);
|
||||
furi_record_close("input_events");
|
||||
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
|
||||
rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK);
|
||||
}
|
||||
|
||||
static void rpc_system_gui_virtual_display_render_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(context);
|
||||
|
||||
RpcGuiSystem* rpc_gui = context;
|
||||
|
||||
if(!rpc_gui->virtual_display_not_empty) {
|
||||
@ -146,13 +215,14 @@ static void rpc_system_gui_virtual_display_render_callback(Canvas* canvas, void*
|
||||
static void rpc_system_gui_start_virtual_display_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(context);
|
||||
|
||||
RpcGuiSystem* rpc_gui = context;
|
||||
RpcSession* session = rpc_gui->session;
|
||||
furi_assert(session);
|
||||
|
||||
if(rpc_gui->virtual_display_view_port) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_gui->rpc,
|
||||
request->command_id,
|
||||
PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_ALREADY_STARTED);
|
||||
session, request->command_id, PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_ALREADY_STARTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -178,17 +248,20 @@ static void rpc_system_gui_start_virtual_display_process(const PB_Main* request,
|
||||
rpc_gui);
|
||||
gui_add_view_port(rpc_gui->gui, rpc_gui->virtual_display_view_port, GuiLayerFullscreen);
|
||||
|
||||
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
|
||||
rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK);
|
||||
}
|
||||
|
||||
static void rpc_system_gui_stop_virtual_display_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(context);
|
||||
|
||||
RpcGuiSystem* rpc_gui = context;
|
||||
RpcSession* session = rpc_gui->session;
|
||||
furi_assert(session);
|
||||
|
||||
if(!rpc_gui->virtual_display_view_port) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_gui->rpc, request->command_id, PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED);
|
||||
session, request->command_id, PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -198,13 +271,16 @@ static void rpc_system_gui_stop_virtual_display_process(const PB_Main* request,
|
||||
rpc_gui->virtual_display_view_port = NULL;
|
||||
rpc_gui->virtual_display_not_empty = false;
|
||||
|
||||
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
|
||||
rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK);
|
||||
}
|
||||
|
||||
static void rpc_system_gui_virtual_display_frame_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(context);
|
||||
|
||||
RpcGuiSystem* rpc_gui = context;
|
||||
RpcSession* session = rpc_gui->session;
|
||||
furi_assert(session);
|
||||
|
||||
if(!rpc_gui->virtual_display_view_port) {
|
||||
FURI_LOG_W(TAG, "Virtual display is not started, ignoring incoming frame packet");
|
||||
@ -218,14 +294,16 @@ static void rpc_system_gui_virtual_display_frame_process(const PB_Main* request,
|
||||
buffer_size);
|
||||
rpc_gui->virtual_display_not_empty = true;
|
||||
view_port_update(rpc_gui->virtual_display_view_port);
|
||||
|
||||
(void)session;
|
||||
}
|
||||
|
||||
void* rpc_system_gui_alloc(Rpc* rpc) {
|
||||
furi_assert(rpc);
|
||||
void* rpc_system_gui_alloc(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
|
||||
RpcGuiSystem* rpc_gui = malloc(sizeof(RpcGuiSystem));
|
||||
rpc_gui->gui = furi_record_open("gui");
|
||||
rpc_gui->rpc = rpc;
|
||||
rpc_gui->session = session;
|
||||
|
||||
RpcHandler rpc_handler = {
|
||||
.message_handler = NULL,
|
||||
@ -234,29 +312,29 @@ void* rpc_system_gui_alloc(Rpc* rpc) {
|
||||
};
|
||||
|
||||
rpc_handler.message_handler = rpc_system_gui_start_screen_stream_process;
|
||||
rpc_add_handler(rpc, PB_Main_gui_start_screen_stream_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_gui_start_screen_stream_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_gui_stop_screen_stream_process;
|
||||
rpc_add_handler(rpc, PB_Main_gui_stop_screen_stream_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_gui_stop_screen_stream_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_gui_send_input_event_request_process;
|
||||
rpc_add_handler(rpc, PB_Main_gui_send_input_event_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_gui_send_input_event_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_gui_start_virtual_display_process;
|
||||
rpc_add_handler(rpc, PB_Main_gui_start_virtual_display_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_gui_start_virtual_display_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_gui_stop_virtual_display_process;
|
||||
rpc_add_handler(rpc, PB_Main_gui_stop_virtual_display_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_gui_stop_virtual_display_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_gui_virtual_display_frame_process;
|
||||
rpc_add_handler(rpc, PB_Main_gui_screen_frame_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_gui_screen_frame_tag, &rpc_handler);
|
||||
|
||||
return rpc_gui;
|
||||
}
|
||||
|
||||
void rpc_system_gui_free(void* ctx) {
|
||||
furi_assert(ctx);
|
||||
RpcGuiSystem* rpc_gui = ctx;
|
||||
void rpc_system_gui_free(void* context) {
|
||||
furi_assert(context);
|
||||
RpcGuiSystem* rpc_gui = context;
|
||||
furi_assert(rpc_gui->gui);
|
||||
|
||||
if(rpc_gui->virtual_display_view_port) {
|
||||
@ -267,7 +345,10 @@ void rpc_system_gui_free(void* ctx) {
|
||||
rpc_gui->virtual_display_not_empty = false;
|
||||
}
|
||||
|
||||
gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL);
|
||||
if(rpc_gui->is_streaming) {
|
||||
gui_remove_framebuffer_callback(
|
||||
rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context);
|
||||
}
|
||||
furi_record_close("gui");
|
||||
free(rpc_gui);
|
||||
}
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
#include <flipper.pb.h>
|
||||
#include <cli/cli.h>
|
||||
|
||||
typedef void* (*RpcSystemAlloc)(Rpc*);
|
||||
typedef void (*RpcSystemFree)(void*);
|
||||
typedef void* (*RpcSystemAlloc)(RpcSession* session);
|
||||
typedef void (*RpcSystemFree)(void* context);
|
||||
typedef void (*PBMessageHandler)(const PB_Main* msg_request, void* context);
|
||||
|
||||
typedef struct {
|
||||
@ -17,15 +17,19 @@ typedef struct {
|
||||
void* context;
|
||||
} RpcHandler;
|
||||
|
||||
void rpc_send_and_release(Rpc* rpc, PB_Main* main_message);
|
||||
void rpc_send_and_release_empty(Rpc* rpc, uint32_t command_id, PB_CommandStatus status);
|
||||
void rpc_add_handler(Rpc* rpc, pb_size_t message_tag, RpcHandler* handler);
|
||||
void rpc_send(RpcSession* session, PB_Main* main_message);
|
||||
|
||||
void* rpc_system_system_alloc(Rpc* rpc);
|
||||
void* rpc_system_storage_alloc(Rpc* rpc);
|
||||
void rpc_send_and_release(RpcSession* session, PB_Main* main_message);
|
||||
|
||||
void rpc_send_and_release_empty(RpcSession* session, uint32_t command_id, PB_CommandStatus status);
|
||||
|
||||
void rpc_add_handler(RpcSession* session, pb_size_t message_tag, RpcHandler* handler);
|
||||
|
||||
void* rpc_system_system_alloc(RpcSession* session);
|
||||
void* rpc_system_storage_alloc(RpcSession* session);
|
||||
void rpc_system_storage_free(void* ctx);
|
||||
void* rpc_system_app_alloc(Rpc* rpc);
|
||||
void* rpc_system_gui_alloc(Rpc* rpc);
|
||||
void* rpc_system_app_alloc(RpcSession* session);
|
||||
void* rpc_system_gui_alloc(RpcSession* session);
|
||||
void rpc_system_gui_free(void* ctx);
|
||||
|
||||
void rpc_print_message(const PB_Main* message);
|
||||
|
||||
@ -21,7 +21,7 @@ typedef enum {
|
||||
} RpcStorageState;
|
||||
|
||||
typedef struct {
|
||||
Rpc* rpc;
|
||||
RpcSession* session;
|
||||
Storage* api;
|
||||
File* file;
|
||||
RpcStorageState state;
|
||||
@ -30,13 +30,16 @@ typedef struct {
|
||||
|
||||
void rpc_print_message(const PB_Main* message);
|
||||
|
||||
static void rpc_system_storage_reset_state(RpcStorageSystem* rpc_storage, bool send_error) {
|
||||
static void rpc_system_storage_reset_state(
|
||||
RpcStorageSystem* rpc_storage,
|
||||
RpcSession* session,
|
||||
bool send_error) {
|
||||
furi_assert(rpc_storage);
|
||||
|
||||
if(rpc_storage->state != RpcStorageStateIdle) {
|
||||
if(send_error) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_storage->rpc,
|
||||
session,
|
||||
rpc_storage->current_command_id,
|
||||
PB_CommandStatus_ERROR_CONTINUOUS_COMMAND_INTERRUPTED);
|
||||
}
|
||||
@ -102,7 +105,10 @@ static void rpc_system_storage_info_process(const PB_Main* request, void* contex
|
||||
furi_assert(request->which_content == PB_Main_storage_info_request_tag);
|
||||
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
rpc_system_storage_reset_state(rpc_storage, true);
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
rpc_system_storage_reset_state(rpc_storage, session, true);
|
||||
|
||||
PB_Main* response = malloc(sizeof(PB_Main));
|
||||
response->command_id = request->command_id;
|
||||
@ -122,7 +128,7 @@ static void rpc_system_storage_info_process(const PB_Main* request, void* contex
|
||||
response->which_content = PB_Main_empty_tag;
|
||||
}
|
||||
|
||||
rpc_send_and_release(rpc_storage->rpc, response);
|
||||
rpc_send_and_release(session, response);
|
||||
free(response);
|
||||
furi_record_close("storage");
|
||||
}
|
||||
@ -133,7 +139,10 @@ static void rpc_system_storage_stat_process(const PB_Main* request, void* contex
|
||||
furi_assert(request->which_content == PB_Main_storage_stat_request_tag);
|
||||
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
rpc_system_storage_reset_state(rpc_storage, true);
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
rpc_system_storage_reset_state(rpc_storage, session, true);
|
||||
|
||||
PB_Main* response = malloc(sizeof(PB_Main));
|
||||
response->command_id = request->command_id;
|
||||
@ -156,13 +165,16 @@ static void rpc_system_storage_stat_process(const PB_Main* request, void* contex
|
||||
response->content.storage_stat_response.file.size = fileinfo.size;
|
||||
}
|
||||
|
||||
rpc_send_and_release(rpc_storage->rpc, response);
|
||||
rpc_send_and_release(session, response);
|
||||
free(response);
|
||||
furi_record_close("storage");
|
||||
}
|
||||
|
||||
static void rpc_system_storage_list_root(const PB_Main* request, void* context) {
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
const char* hard_coded_dirs[] = {"any", "int", "ext"};
|
||||
|
||||
PB_Main response = {
|
||||
@ -183,7 +195,7 @@ static void rpc_system_storage_list_root(const PB_Main* request, void* context)
|
||||
response.content.storage_list_response.file[i].name = str;
|
||||
}
|
||||
|
||||
rpc_send_and_release(rpc_storage->rpc, &response);
|
||||
rpc_send_and_release(session, &response);
|
||||
}
|
||||
|
||||
static void rpc_system_storage_list_process(const PB_Main* request, void* context) {
|
||||
@ -192,7 +204,10 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex
|
||||
furi_assert(request->which_content == PB_Main_storage_list_request_tag);
|
||||
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
rpc_system_storage_reset_state(rpc_storage, true);
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
rpc_system_storage_reset_state(rpc_storage, session, true);
|
||||
|
||||
if(!strcmp(request->content.storage_list_request.path, "/")) {
|
||||
rpc_system_storage_list_root(request, context);
|
||||
@ -226,7 +241,7 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex
|
||||
if(i == COUNT_OF(list->file)) {
|
||||
list->file_count = i;
|
||||
response.has_next = true;
|
||||
rpc_send_and_release(rpc_storage->rpc, &response);
|
||||
rpc_send_and_release(session, &response);
|
||||
i = 0;
|
||||
}
|
||||
list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? PB_Storage_File_FileType_DIR :
|
||||
@ -243,7 +258,7 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex
|
||||
}
|
||||
|
||||
response.has_next = false;
|
||||
rpc_send_and_release(rpc_storage->rpc, &response);
|
||||
rpc_send_and_release(session, &response);
|
||||
|
||||
storage_dir_close(dir);
|
||||
storage_file_free(dir);
|
||||
@ -253,10 +268,14 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex
|
||||
|
||||
static void rpc_system_storage_read_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(context);
|
||||
furi_assert(request->which_content == PB_Main_storage_read_request_tag);
|
||||
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
rpc_system_storage_reset_state(rpc_storage, true);
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
rpc_system_storage_reset_state(rpc_storage, session, true);
|
||||
|
||||
/* use same message memory to send reponse */
|
||||
PB_Main* response = malloc(sizeof(PB_Main));
|
||||
@ -284,17 +303,17 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex
|
||||
|
||||
if(result) {
|
||||
response->has_next = (size_left > 0);
|
||||
rpc_send_and_release(rpc_storage->rpc, response);
|
||||
rpc_send_and_release(session, response);
|
||||
}
|
||||
} while((size_left != 0) && result);
|
||||
|
||||
if(!result) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_storage->rpc, request->command_id, rpc_system_storage_get_file_error(file));
|
||||
session, request->command_id, rpc_system_storage_get_file_error(file));
|
||||
}
|
||||
} else {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_storage->rpc, request->command_id, rpc_system_storage_get_file_error(file));
|
||||
session, request->command_id, rpc_system_storage_get_file_error(file));
|
||||
}
|
||||
|
||||
free(response);
|
||||
@ -306,14 +325,18 @@ static void rpc_system_storage_read_process(const PB_Main* request, void* contex
|
||||
|
||||
static void rpc_system_storage_write_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(context);
|
||||
furi_assert(request->which_content == PB_Main_storage_write_request_tag);
|
||||
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
bool result = true;
|
||||
|
||||
if((request->command_id != rpc_storage->current_command_id) &&
|
||||
(rpc_storage->state == RpcStorageStateWriting)) {
|
||||
rpc_system_storage_reset_state(rpc_storage, true);
|
||||
rpc_system_storage_reset_state(rpc_storage, session, true);
|
||||
}
|
||||
|
||||
if(rpc_storage->state != RpcStorageStateWriting) {
|
||||
@ -336,17 +359,15 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte
|
||||
|
||||
if(result && !request->has_next) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_storage->rpc, rpc_storage->current_command_id, PB_CommandStatus_OK);
|
||||
rpc_system_storage_reset_state(rpc_storage, false);
|
||||
session, rpc_storage->current_command_id, PB_CommandStatus_OK);
|
||||
rpc_system_storage_reset_state(rpc_storage, session, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_storage->rpc,
|
||||
rpc_storage->current_command_id,
|
||||
rpc_system_storage_get_file_error(file));
|
||||
rpc_system_storage_reset_state(rpc_storage, false);
|
||||
session, rpc_storage->current_command_id, rpc_system_storage_get_file_error(file));
|
||||
rpc_system_storage_reset_state(rpc_storage, session, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,8 +394,11 @@ static void rpc_system_storage_delete_process(const PB_Main* request, void* cont
|
||||
furi_assert(request->which_content == PB_Main_storage_delete_request_tag);
|
||||
furi_assert(context);
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
PB_CommandStatus status = PB_CommandStatus_ERROR;
|
||||
rpc_system_storage_reset_state(rpc_storage, true);
|
||||
rpc_system_storage_reset_state(rpc_storage, session, true);
|
||||
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
|
||||
@ -400,7 +424,7 @@ static void rpc_system_storage_delete_process(const PB_Main* request, void* cont
|
||||
}
|
||||
|
||||
furi_record_close("storage");
|
||||
rpc_send_and_release_empty(rpc_storage->rpc, request->command_id, status);
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
static void rpc_system_storage_mkdir_process(const PB_Main* request, void* context) {
|
||||
@ -408,8 +432,11 @@ static void rpc_system_storage_mkdir_process(const PB_Main* request, void* conte
|
||||
furi_assert(request->which_content == PB_Main_storage_mkdir_request_tag);
|
||||
furi_assert(context);
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
PB_CommandStatus status;
|
||||
rpc_system_storage_reset_state(rpc_storage, true);
|
||||
rpc_system_storage_reset_state(rpc_storage, session, true);
|
||||
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
char* path = request->content.storage_mkdir_request.path;
|
||||
@ -420,7 +447,7 @@ static void rpc_system_storage_mkdir_process(const PB_Main* request, void* conte
|
||||
status = PB_CommandStatus_ERROR_INVALID_PARAMETERS;
|
||||
}
|
||||
furi_record_close("storage");
|
||||
rpc_send_and_release_empty(rpc_storage->rpc, request->command_id, status);
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
static void rpc_system_storage_md5sum_process(const PB_Main* request, void* context) {
|
||||
@ -428,12 +455,15 @@ static void rpc_system_storage_md5sum_process(const PB_Main* request, void* cont
|
||||
furi_assert(request->which_content == PB_Main_storage_md5sum_request_tag);
|
||||
furi_assert(context);
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
rpc_system_storage_reset_state(rpc_storage, true);
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
rpc_system_storage_reset_state(rpc_storage, session, true);
|
||||
|
||||
const char* filename = request->content.storage_md5sum_request.path;
|
||||
if(!filename) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_storage->rpc, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
session, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -474,10 +504,10 @@ static void rpc_system_storage_md5sum_process(const PB_Main* request, void* cont
|
||||
free(hash);
|
||||
free(data);
|
||||
storage_file_close(file);
|
||||
rpc_send_and_release(rpc_storage->rpc, &response);
|
||||
rpc_send_and_release(session, &response);
|
||||
} else {
|
||||
rpc_send_and_release_empty(
|
||||
rpc_storage->rpc, request->command_id, rpc_system_storage_get_file_error(file));
|
||||
session, request->command_id, rpc_system_storage_get_file_error(file));
|
||||
}
|
||||
|
||||
storage_file_free(file);
|
||||
@ -490,8 +520,11 @@ static void rpc_system_storage_rename_process(const PB_Main* request, void* cont
|
||||
furi_assert(request->which_content == PB_Main_storage_rename_request_tag);
|
||||
furi_assert(context);
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
PB_CommandStatus status;
|
||||
rpc_system_storage_reset_state(rpc_storage, true);
|
||||
rpc_system_storage_reset_state(rpc_storage, session, true);
|
||||
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
|
||||
@ -502,15 +535,15 @@ static void rpc_system_storage_rename_process(const PB_Main* request, void* cont
|
||||
status = rpc_system_storage_get_error(error);
|
||||
|
||||
furi_record_close("storage");
|
||||
rpc_send_and_release_empty(rpc_storage->rpc, request->command_id, status);
|
||||
rpc_send_and_release_empty(session, request->command_id, status);
|
||||
}
|
||||
|
||||
void* rpc_system_storage_alloc(Rpc* rpc) {
|
||||
furi_assert(rpc);
|
||||
void* rpc_system_storage_alloc(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
|
||||
RpcStorageSystem* rpc_storage = malloc(sizeof(RpcStorageSystem));
|
||||
rpc_storage->api = furi_record_open("storage");
|
||||
rpc_storage->rpc = rpc;
|
||||
rpc_storage->session = session;
|
||||
rpc_storage->state = RpcStorageStateIdle;
|
||||
|
||||
RpcHandler rpc_handler = {
|
||||
@ -520,37 +553,40 @@ void* rpc_system_storage_alloc(Rpc* rpc) {
|
||||
};
|
||||
|
||||
rpc_handler.message_handler = rpc_system_storage_info_process;
|
||||
rpc_add_handler(rpc, PB_Main_storage_info_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_storage_info_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_storage_stat_process;
|
||||
rpc_add_handler(rpc, PB_Main_storage_stat_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_storage_stat_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_storage_list_process;
|
||||
rpc_add_handler(rpc, PB_Main_storage_list_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_storage_list_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_storage_read_process;
|
||||
rpc_add_handler(rpc, PB_Main_storage_read_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_storage_read_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_storage_write_process;
|
||||
rpc_add_handler(rpc, PB_Main_storage_write_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_storage_write_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_storage_delete_process;
|
||||
rpc_add_handler(rpc, PB_Main_storage_delete_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_storage_delete_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_storage_mkdir_process;
|
||||
rpc_add_handler(rpc, PB_Main_storage_mkdir_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_storage_mkdir_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_storage_md5sum_process;
|
||||
rpc_add_handler(rpc, PB_Main_storage_md5sum_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_storage_md5sum_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_storage_rename_process;
|
||||
rpc_add_handler(rpc, PB_Main_storage_rename_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_storage_rename_request_tag, &rpc_handler);
|
||||
|
||||
return rpc_storage;
|
||||
}
|
||||
|
||||
void rpc_system_storage_free(void* ctx) {
|
||||
RpcStorageSystem* rpc_storage = ctx;
|
||||
rpc_system_storage_reset_state(rpc_storage, false);
|
||||
void rpc_system_storage_free(void* context) {
|
||||
RpcStorageSystem* rpc_storage = context;
|
||||
RpcSession* session = rpc_storage->session;
|
||||
furi_assert(session);
|
||||
|
||||
rpc_system_storage_reset_state(rpc_storage, session, false);
|
||||
free(rpc_storage);
|
||||
}
|
||||
|
||||
@ -6,40 +6,42 @@
|
||||
|
||||
#include "rpc_i.h"
|
||||
|
||||
static void rpc_system_system_ping_process(const PB_Main* msg_request, void* context) {
|
||||
furi_assert(msg_request);
|
||||
furi_assert(msg_request->which_content == PB_Main_system_ping_request_tag);
|
||||
furi_assert(context);
|
||||
Rpc* rpc = context;
|
||||
static void rpc_system_system_ping_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_system_ping_request_tag);
|
||||
|
||||
if(msg_request->has_next) {
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
if(request->has_next) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc, msg_request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
session, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
return;
|
||||
}
|
||||
|
||||
PB_Main msg_response = PB_Main_init_default;
|
||||
msg_response.has_next = false;
|
||||
msg_response.command_status = PB_CommandStatus_OK;
|
||||
msg_response.command_id = msg_request->command_id;
|
||||
msg_response.which_content = PB_Main_system_ping_response_tag;
|
||||
PB_Main response = PB_Main_init_default;
|
||||
response.has_next = false;
|
||||
response.command_status = PB_CommandStatus_OK;
|
||||
response.command_id = request->command_id;
|
||||
response.which_content = PB_Main_system_ping_response_tag;
|
||||
|
||||
const PB_System_PingRequest* request = &msg_request->content.system_ping_request;
|
||||
PB_System_PingResponse* response = &msg_response.content.system_ping_response;
|
||||
if(request->data && (request->data->size > 0)) {
|
||||
response->data = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(request->data->size));
|
||||
memcpy(response->data->bytes, request->data->bytes, request->data->size);
|
||||
response->data->size = request->data->size;
|
||||
const PB_System_PingRequest* ping_request = &request->content.system_ping_request;
|
||||
PB_System_PingResponse* ping_response = &response.content.system_ping_response;
|
||||
if(ping_request->data && (ping_request->data->size > 0)) {
|
||||
ping_response->data = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(ping_request->data->size));
|
||||
memcpy(ping_response->data->bytes, ping_request->data->bytes, ping_request->data->size);
|
||||
ping_response->data->size = ping_request->data->size;
|
||||
}
|
||||
|
||||
rpc_send_and_release(rpc, &msg_response);
|
||||
rpc_send_and_release(session, &response);
|
||||
}
|
||||
|
||||
static void rpc_system_system_reboot_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_system_reboot_request_tag);
|
||||
furi_assert(context);
|
||||
Rpc* rpc = context;
|
||||
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
const int mode = request->content.system_reboot_request.mode;
|
||||
|
||||
@ -49,12 +51,12 @@ static void rpc_system_system_reboot_process(const PB_Main* request, void* conte
|
||||
power_reboot(PowerBootModeDfu);
|
||||
} else {
|
||||
rpc_send_and_release_empty(
|
||||
rpc, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
session, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Rpc* rpc;
|
||||
RpcSession* session;
|
||||
PB_Main* response;
|
||||
} RpcSystemSystemDeviceInfoContext;
|
||||
|
||||
@ -65,7 +67,6 @@ static void rpc_system_system_device_info_callback(
|
||||
void* context) {
|
||||
furi_assert(key);
|
||||
furi_assert(value);
|
||||
furi_assert(context);
|
||||
RpcSystemSystemDeviceInfoContext* ctx = context;
|
||||
|
||||
char* str_key = strdup(key);
|
||||
@ -75,14 +76,15 @@ static void rpc_system_system_device_info_callback(
|
||||
ctx->response->content.system_device_info_response.key = str_key;
|
||||
ctx->response->content.system_device_info_response.value = str_value;
|
||||
|
||||
rpc_send_and_release(ctx->rpc, ctx->response);
|
||||
rpc_send_and_release(ctx->session, ctx->response);
|
||||
}
|
||||
|
||||
static void rpc_system_system_device_info_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_system_device_info_request_tag);
|
||||
furi_assert(context);
|
||||
Rpc* rpc = context;
|
||||
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
PB_Main* response = malloc(sizeof(PB_Main));
|
||||
response->command_id = request->command_id;
|
||||
@ -90,10 +92,9 @@ static void rpc_system_system_device_info_process(const PB_Main* request, void*
|
||||
response->command_status = PB_CommandStatus_OK;
|
||||
|
||||
RpcSystemSystemDeviceInfoContext device_info_context = {
|
||||
.rpc = rpc,
|
||||
.session = session,
|
||||
.response = response,
|
||||
};
|
||||
|
||||
furi_hal_info_get(rpc_system_system_device_info_callback, &device_info_context);
|
||||
|
||||
free(response);
|
||||
@ -102,8 +103,9 @@ static void rpc_system_system_device_info_process(const PB_Main* request, void*
|
||||
static void rpc_system_system_get_datetime_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_system_get_datetime_request_tag);
|
||||
furi_assert(context);
|
||||
Rpc* rpc = context;
|
||||
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
FuriHalRtcDateTime datetime;
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
@ -121,19 +123,20 @@ static void rpc_system_system_get_datetime_process(const PB_Main* request, void*
|
||||
response->content.system_get_datetime_response.datetime.year = datetime.year;
|
||||
response->content.system_get_datetime_response.datetime.weekday = datetime.weekday;
|
||||
|
||||
rpc_send_and_release(rpc, response);
|
||||
rpc_send_and_release(session, response);
|
||||
free(response);
|
||||
}
|
||||
|
||||
static void rpc_system_system_set_datetime_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_system_set_datetime_request_tag);
|
||||
furi_assert(context);
|
||||
Rpc* rpc = context;
|
||||
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
if(!request->content.system_set_datetime_request.has_datetime) {
|
||||
rpc_send_and_release_empty(
|
||||
rpc, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
session, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -147,38 +150,43 @@ static void rpc_system_system_set_datetime_process(const PB_Main* request, void*
|
||||
datetime.weekday = request->content.system_set_datetime_request.datetime.weekday;
|
||||
furi_hal_rtc_set_datetime(&datetime);
|
||||
|
||||
rpc_send_and_release_empty(rpc, request->command_id, PB_CommandStatus_OK);
|
||||
rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK);
|
||||
}
|
||||
|
||||
static void rpc_system_system_factory_reset_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_system_factory_reset_request_tag);
|
||||
furi_assert(context);
|
||||
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset);
|
||||
power_reboot(PowerBootModeNormal);
|
||||
|
||||
(void)session;
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_system_system_play_audiovisual_alert_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_system_play_audiovisual_alert_request_tag);
|
||||
furi_assert(context);
|
||||
Rpc* rpc = context;
|
||||
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &sequence_audiovisual_alert);
|
||||
furi_record_close("notification");
|
||||
|
||||
rpc_send_and_release_empty(rpc, request->command_id, PB_CommandStatus_OK);
|
||||
rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK);
|
||||
}
|
||||
|
||||
static void rpc_system_system_protobuf_version_process(const PB_Main* request, void* context) {
|
||||
furi_assert(request);
|
||||
furi_assert(request->which_content == PB_Main_system_protobuf_version_request_tag);
|
||||
furi_assert(context);
|
||||
|
||||
Rpc* rpc = context;
|
||||
RpcSession* session = (RpcSession*)context;
|
||||
furi_assert(session);
|
||||
|
||||
PB_Main* response = malloc(sizeof(PB_Main));
|
||||
response->command_id = request->command_id;
|
||||
@ -190,40 +198,40 @@ static void rpc_system_system_protobuf_version_process(const PB_Main* request, v
|
||||
response->content.system_protobuf_version_response.major = PROTOBUF_MAJOR_VERSION;
|
||||
response->content.system_protobuf_version_response.minor = PROTOBUF_MINOR_VERSION;
|
||||
|
||||
rpc_send_and_release(rpc, response);
|
||||
rpc_send_and_release(session, response);
|
||||
free(response);
|
||||
}
|
||||
|
||||
void* rpc_system_system_alloc(Rpc* rpc) {
|
||||
void* rpc_system_system_alloc(RpcSession* session) {
|
||||
RpcHandler rpc_handler = {
|
||||
.message_handler = NULL,
|
||||
.decode_submessage = NULL,
|
||||
.context = rpc,
|
||||
.context = session,
|
||||
};
|
||||
|
||||
rpc_handler.message_handler = rpc_system_system_ping_process;
|
||||
rpc_add_handler(rpc, PB_Main_system_ping_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_system_ping_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_system_reboot_process;
|
||||
rpc_add_handler(rpc, PB_Main_system_reboot_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_system_reboot_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_system_device_info_process;
|
||||
rpc_add_handler(rpc, PB_Main_system_device_info_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_system_device_info_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_system_factory_reset_process;
|
||||
rpc_add_handler(rpc, PB_Main_system_factory_reset_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_system_factory_reset_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_system_get_datetime_process;
|
||||
rpc_add_handler(rpc, PB_Main_system_get_datetime_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_system_get_datetime_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_system_set_datetime_process;
|
||||
rpc_add_handler(rpc, PB_Main_system_set_datetime_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_system_set_datetime_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_system_play_audiovisual_alert_process;
|
||||
rpc_add_handler(rpc, PB_Main_system_play_audiovisual_alert_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_system_play_audiovisual_alert_request_tag, &rpc_handler);
|
||||
|
||||
rpc_handler.message_handler = rpc_system_system_protobuf_version_process;
|
||||
rpc_add_handler(rpc, PB_Main_system_protobuf_version_request_tag, &rpc_handler);
|
||||
rpc_add_handler(session, PB_Main_system_protobuf_version_request_tag, &rpc_handler);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -23,12 +23,12 @@ static int32_t subghz_chat_worker_thread(void* context) {
|
||||
SubGhzChatWorker* instance = context;
|
||||
FURI_LOG_I(TAG, "Worker start");
|
||||
char c;
|
||||
SubghzChatEvent event;
|
||||
event.event = SubghzChatEventUserEntrance;
|
||||
SubGhzChatEvent event;
|
||||
event.event = SubGhzChatEventUserEntrance;
|
||||
osMessageQueuePut(instance->event_queue, &event, 0, 0);
|
||||
while(instance->worker_running) {
|
||||
if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 1000) == 1) {
|
||||
event.event = SubghzChatEventInputData;
|
||||
event.event = SubGhzChatEventInputData;
|
||||
event.c = c;
|
||||
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
@ -41,13 +41,13 @@ static int32_t subghz_chat_worker_thread(void* context) {
|
||||
static void subghz_chat_worker_update_rx_event_chat(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzChatWorker* instance = context;
|
||||
SubghzChatEvent event;
|
||||
SubGhzChatEvent event;
|
||||
if((millis() - instance->last_time_rx_data) > SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES) {
|
||||
event.event = SubghzChatEventNewMessage;
|
||||
event.event = SubGhzChatEventNewMessage;
|
||||
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
instance->last_time_rx_data = millis();
|
||||
event.event = SubghzChatEventRXData;
|
||||
event.event = SubGhzChatEventRXData;
|
||||
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
@ -55,12 +55,12 @@ SubGhzChatWorker* subghz_chat_worker_alloc() {
|
||||
SubGhzChatWorker* instance = malloc(sizeof(SubGhzChatWorker));
|
||||
|
||||
instance->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(instance->thread, "SubghzChat");
|
||||
furi_thread_set_name(instance->thread, "SubGhzChat");
|
||||
furi_thread_set_stack_size(instance->thread, 2048);
|
||||
furi_thread_set_context(instance->thread, instance);
|
||||
furi_thread_set_callback(instance->thread, subghz_chat_worker_thread);
|
||||
instance->subghz_txrx = subghz_tx_rx_worker_alloc();
|
||||
instance->event_queue = osMessageQueueNew(80, sizeof(SubghzChatEvent), NULL);
|
||||
instance->event_queue = osMessageQueueNew(80, sizeof(SubGhzChatEvent), NULL);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@ -109,18 +109,18 @@ bool subghz_chat_worker_is_running(SubGhzChatWorker* instance) {
|
||||
return instance->worker_running;
|
||||
}
|
||||
|
||||
SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance) {
|
||||
SubGhzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance) {
|
||||
furi_assert(instance);
|
||||
SubghzChatEvent event;
|
||||
SubGhzChatEvent event;
|
||||
if(osMessageQueueGet(instance->event_queue, &event, NULL, osWaitForever) == osOK) {
|
||||
return event;
|
||||
} else {
|
||||
event.event = SubghzChatEventNoEvent;
|
||||
event.event = SubGhzChatEventNoEvent;
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event) {
|
||||
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubGhzChatEvent* event) {
|
||||
furi_assert(instance);
|
||||
osMessageQueuePut(instance->event_queue, event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
@ -4,26 +4,26 @@
|
||||
typedef struct SubGhzChatWorker SubGhzChatWorker;
|
||||
|
||||
typedef enum {
|
||||
SubghzChatEventNoEvent,
|
||||
SubghzChatEventUserEntrance,
|
||||
SubghzChatEventUserExit,
|
||||
SubghzChatEventInputData,
|
||||
SubghzChatEventRXData,
|
||||
SubghzChatEventNewMessage,
|
||||
} SubghzChatEventType;
|
||||
SubGhzChatEventNoEvent,
|
||||
SubGhzChatEventUserEntrance,
|
||||
SubGhzChatEventUserExit,
|
||||
SubGhzChatEventInputData,
|
||||
SubGhzChatEventRXData,
|
||||
SubGhzChatEventNewMessage,
|
||||
} SubGhzChatEventType;
|
||||
|
||||
typedef struct {
|
||||
SubghzChatEventType event;
|
||||
SubGhzChatEventType event;
|
||||
char c;
|
||||
} SubghzChatEvent;
|
||||
} SubGhzChatEvent;
|
||||
|
||||
SubGhzChatWorker* subghz_chat_worker_alloc();
|
||||
void subghz_chat_worker_free(SubGhzChatWorker* instance);
|
||||
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency);
|
||||
void subghz_chat_worker_stop(SubGhzChatWorker* instance);
|
||||
bool subghz_chat_worker_is_running(SubGhzChatWorker* instance);
|
||||
SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance);
|
||||
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event);
|
||||
SubGhzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance);
|
||||
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubGhzChatEvent* event);
|
||||
size_t subghz_chat_worker_available(SubGhzChatWorker* instance);
|
||||
size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size);
|
||||
bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size);
|
||||
|
||||
@ -1,46 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
SubghzCustomEventManagerNoSet = 0,
|
||||
SubghzCustomEventManagerSet,
|
||||
SubghzCustomEventManagerSetRAW,
|
||||
SubGhzCustomEventManagerNoSet = 0,
|
||||
SubGhzCustomEventManagerSet,
|
||||
SubGhzCustomEventManagerSetRAW,
|
||||
|
||||
SubghzCustomEventSceneDeleteSuccess = 100,
|
||||
SubghzCustomEventSceneDelete,
|
||||
SubghzCustomEventSceneDeleteRAW,
|
||||
SubghzCustomEventSceneDeleteRAWBack,
|
||||
SubGhzCustomEventSceneDeleteSuccess = 100,
|
||||
SubGhzCustomEventSceneDelete,
|
||||
SubGhzCustomEventSceneDeleteRAW,
|
||||
SubGhzCustomEventSceneDeleteRAWBack,
|
||||
|
||||
SubghzCustomEventSceneReceiverInfoTxStart,
|
||||
SubghzCustomEventSceneReceiverInfoTxStop,
|
||||
SubghzCustomEventSceneReceiverInfoSave,
|
||||
SubghzCustomEventSceneSaveName,
|
||||
SubghzCustomEventSceneSaveSuccess,
|
||||
SubghzCustomEventSceneShowErrorBack,
|
||||
SubghzCustomEventSceneShowErrorOk,
|
||||
SubghzCustomEventSceneShowErrorSub,
|
||||
SubghzCustomEventSceneShowOnlyRX,
|
||||
SubGhzCustomEventSceneReceiverInfoTxStart,
|
||||
SubGhzCustomEventSceneReceiverInfoTxStop,
|
||||
SubGhzCustomEventSceneReceiverInfoSave,
|
||||
SubGhzCustomEventSceneSaveName,
|
||||
SubGhzCustomEventSceneSaveSuccess,
|
||||
SubGhzCustomEventSceneShowErrorBack,
|
||||
SubGhzCustomEventSceneShowErrorOk,
|
||||
SubGhzCustomEventSceneShowErrorSub,
|
||||
SubGhzCustomEventSceneShowOnlyRX,
|
||||
|
||||
SubghzCustomEventSceneExit,
|
||||
SubghzCustomEventSceneStay,
|
||||
SubGhzCustomEventSceneExit,
|
||||
SubGhzCustomEventSceneStay,
|
||||
|
||||
SubghzCustomEventViewReceverOK,
|
||||
SubghzCustomEventViewReceverConfig,
|
||||
SubghzCustomEventViewReceverBack,
|
||||
SubGhzCustomEventViewReceverOK,
|
||||
SubGhzCustomEventViewReceverConfig,
|
||||
SubGhzCustomEventViewReceverBack,
|
||||
|
||||
SubghzCustomEventViewReadRAWBack,
|
||||
SubghzCustomEventViewReadRAWIDLE,
|
||||
SubghzCustomEventViewReadRAWREC,
|
||||
SubghzCustomEventViewReadRAWConfig,
|
||||
SubghzCustomEventViewReadRAWErase,
|
||||
SubghzCustomEventViewReadRAWSendStart,
|
||||
SubghzCustomEventViewReadRAWSendStop,
|
||||
SubghzCustomEventViewReadRAWSave,
|
||||
SubghzCustomEventViewReadRAWVibro,
|
||||
SubghzCustomEventViewReadRAWTXRXStop,
|
||||
SubghzCustomEventViewReadRAWMore,
|
||||
SubGhzCustomEventViewReadRAWBack,
|
||||
SubGhzCustomEventViewReadRAWIDLE,
|
||||
SubGhzCustomEventViewReadRAWREC,
|
||||
SubGhzCustomEventViewReadRAWConfig,
|
||||
SubGhzCustomEventViewReadRAWErase,
|
||||
SubGhzCustomEventViewReadRAWSendStart,
|
||||
SubGhzCustomEventViewReadRAWSendStop,
|
||||
SubGhzCustomEventViewReadRAWSave,
|
||||
SubGhzCustomEventViewReadRAWVibro,
|
||||
SubGhzCustomEventViewReadRAWTXRXStop,
|
||||
SubGhzCustomEventViewReadRAWMore,
|
||||
|
||||
SubghzCustomEventViewTransmitterBack,
|
||||
SubghzCustomEventViewTransmitterSendStart,
|
||||
SubghzCustomEventViewTransmitterSendStop,
|
||||
SubghzCustomEventViewTransmitterError,
|
||||
} SubghzCustomEvent;
|
||||
SubGhzCustomEventViewTransmitterBack,
|
||||
SubGhzCustomEventViewTransmitterSendStart,
|
||||
SubGhzCustomEventViewTransmitterSendStop,
|
||||
SubGhzCustomEventViewTransmitterError,
|
||||
} SubGhzCustomEvent;
|
||||
|
||||
@ -145,7 +145,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc() {
|
||||
SubGhzFrequencyAnalyzerWorker* instance = malloc(sizeof(SubGhzFrequencyAnalyzerWorker));
|
||||
|
||||
instance->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(instance->thread, "SubghzFAWorker");
|
||||
furi_thread_set_name(instance->thread, "SubGhzFAWorker");
|
||||
furi_thread_set_stack_size(instance->thread, 2048);
|
||||
furi_thread_set_context(instance->thread, instance);
|
||||
furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread);
|
||||
|
||||
@ -5,7 +5,7 @@ void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* co
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneDelete);
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneDelete);
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,8 +31,7 @@ void subghz_scene_delete_on_enter(void* context) {
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
string_get_cstr(modulation_str));
|
||||
|
||||
subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text);
|
||||
subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
|
||||
widget_add_string_multiline_element(
|
||||
subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text));
|
||||
|
||||
@ -43,13 +42,13 @@ void subghz_scene_delete_on_enter(void* context) {
|
||||
widget_add_button_element(
|
||||
subghz->widget, GuiButtonTypeRight, "Delete", subghz_scene_delete_callback, subghz);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
|
||||
}
|
||||
|
||||
bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubghzCustomEventSceneDelete) {
|
||||
if(event.event == SubGhzCustomEventSceneDelete) {
|
||||
strcpy(subghz->file_name_tmp, subghz->file_name);
|
||||
if(subghz_delete_file(subghz)) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess);
|
||||
|
||||
@ -6,10 +6,10 @@ void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void
|
||||
SubGhz* subghz = context;
|
||||
if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(
|
||||
subghz->view_dispatcher, SubghzCustomEventSceneDeleteRAW);
|
||||
subghz->view_dispatcher, SubGhzCustomEventSceneDeleteRAW);
|
||||
} else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(
|
||||
subghz->view_dispatcher, SubghzCustomEventSceneDeleteRAWBack);
|
||||
subghz->view_dispatcher, SubGhzCustomEventSceneDeleteRAWBack);
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,13 +49,13 @@ void subghz_scene_delete_raw_on_enter(void* context) {
|
||||
widget_add_button_element(
|
||||
subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_delete_raw_callback, subghz);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
|
||||
}
|
||||
|
||||
bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubghzCustomEventSceneDeleteRAW) {
|
||||
if(event.event == SubGhzCustomEventSceneDeleteRAW) {
|
||||
strcpy(subghz->file_name_tmp, subghz->file_name);
|
||||
if(subghz_delete_file(subghz)) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess);
|
||||
@ -64,7 +64,7 @@ bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->scene_manager, SubGhzSceneStart);
|
||||
}
|
||||
return true;
|
||||
} else if(event.event == SubghzCustomEventSceneDeleteRAWBack) {
|
||||
} else if(event.event == SubGhzCustomEventSceneDeleteRAWBack) {
|
||||
return scene_manager_previous_scene(subghz->scene_manager);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
void subghz_scene_delete_success_popup_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(
|
||||
subghz->view_dispatcher, SubghzCustomEventSceneDeleteSuccess);
|
||||
subghz->view_dispatcher, SubGhzCustomEventSceneDeleteSuccess);
|
||||
}
|
||||
|
||||
void subghz_scene_delete_success_on_enter(void* context) {
|
||||
@ -18,14 +18,14 @@ void subghz_scene_delete_success_on_enter(void* context) {
|
||||
popup_set_context(popup, subghz);
|
||||
popup_set_callback(popup, subghz_scene_delete_success_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup);
|
||||
}
|
||||
|
||||
bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubghzCustomEventSceneDeleteSuccess) {
|
||||
if(event.event == SubGhzCustomEventSceneDeleteSuccess) {
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneSaved)) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#include "../views/subghz_frequency_analyzer.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
void subghz_scene_frequency_analyzer_callback(SubghzCustomEvent event, void* context) {
|
||||
void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
|
||||
@ -13,7 +13,7 @@ void subghz_scene_frequency_analyzer_on_enter(void* context) {
|
||||
DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer);
|
||||
subghz_frequency_analyzer_set_callback(
|
||||
subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewFrequencyAnalyzer);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdFrequencyAnalyzer);
|
||||
}
|
||||
|
||||
bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@ -30,7 +30,7 @@ void subghz_scene_more_raw_on_enter(void* context) {
|
||||
submenu_set_selected_item(
|
||||
subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneMoreRAW));
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu);
|
||||
}
|
||||
|
||||
bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
@ -39,7 +39,7 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexDelete) {
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW);
|
||||
|
||||
@ -6,9 +6,9 @@ void subghz_scene_need_saving_callback(GuiButtonType result, InputType type, voi
|
||||
SubGhz* subghz = context;
|
||||
|
||||
if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneStay);
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneStay);
|
||||
} else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneExit);
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ void subghz_scene_need_saving_on_enter(void* context) {
|
||||
widget_add_button_element(
|
||||
subghz->widget, GuiButtonTypeLeft, "Exit", subghz_scene_need_saving_callback, subghz);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
|
||||
}
|
||||
|
||||
bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
|
||||
@ -41,11 +41,11 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_previous_scene(subghz->scene_manager);
|
||||
return true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubghzCustomEventSceneStay) {
|
||||
if(event.event == SubGhzCustomEventSceneStay) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
||||
scene_manager_previous_scene(subghz->scene_manager);
|
||||
return true;
|
||||
} else if(event.event == SubghzCustomEventSceneExit) {
|
||||
} else if(event.event == SubGhzCustomEventSceneExit) {
|
||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
#include "../subghz_i.h"
|
||||
#include "../views/subghz_read_raw.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <lib/subghz/protocols/subghz_protocol_raw.h>
|
||||
#include <lib/subghz/subghz_parser.h>
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
#define RAW_FILE_NAME "Raw_signal_"
|
||||
#define TAG "SubGhzSceneReadRAW"
|
||||
|
||||
bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
|
||||
bool ret = false;
|
||||
//set the path to read the file
|
||||
if(strcmp(
|
||||
subghz_protocol_raw_get_last_file_name(
|
||||
(SubGhzProtocolRAW*)subghz->txrx->protocol_result),
|
||||
"")) {
|
||||
string_t temp_str;
|
||||
string_init_printf(
|
||||
temp_str,
|
||||
"%s",
|
||||
subghz_protocol_raw_get_last_file_name(
|
||||
(SubGhzProtocolRAW*)subghz->txrx->protocol_result));
|
||||
string_t temp_str;
|
||||
string_init(temp_str);
|
||||
do {
|
||||
if(!flipper_format_rewind(subghz->txrx->fff_data)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing File_name");
|
||||
break;
|
||||
}
|
||||
|
||||
path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str);
|
||||
strcpy(subghz->file_name, string_get_cstr(temp_str));
|
||||
string_printf(
|
||||
temp_str, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION);
|
||||
|
||||
subghz_protocol_raw_set_last_file_name(
|
||||
(SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str));
|
||||
string_clear(temp_str);
|
||||
ret = true;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
string_clear(temp_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ static void subghz_scene_read_raw_update_statusbar(void* context) {
|
||||
string_clear(modulation_str);
|
||||
}
|
||||
|
||||
void subghz_scene_read_raw_callback(SubghzCustomEvent event, void* context) {
|
||||
void subghz_scene_read_raw_callback(SubGhzCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
|
||||
@ -61,7 +61,7 @@ void subghz_scene_read_raw_callback_end_tx(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(
|
||||
subghz->view_dispatcher, SubghzCustomEventViewReadRAWSendStop);
|
||||
subghz->view_dispatcher, SubGhzCustomEventViewReadRAWSendStop);
|
||||
}
|
||||
|
||||
void subghz_scene_read_raw_on_enter(void* context) {
|
||||
@ -69,46 +69,43 @@ void subghz_scene_read_raw_on_enter(void* context) {
|
||||
|
||||
switch(subghz->txrx->rx_key_state) {
|
||||
case SubGhzRxKeyStateBack:
|
||||
subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusIDLE, "");
|
||||
subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "");
|
||||
break;
|
||||
case SubGhzRxKeyStateRAWLoad:
|
||||
subghz_read_raw_set_status(
|
||||
subghz->subghz_read_raw, SubghzReadRAWStatusLoadKeyTX, subghz->file_name);
|
||||
subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, subghz->file_name);
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
break;
|
||||
case SubGhzRxKeyStateRAWSave:
|
||||
subghz_read_raw_set_status(
|
||||
subghz->subghz_read_raw, SubghzReadRAWStatusSaveKey, subghz->file_name);
|
||||
subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, subghz->file_name);
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
break;
|
||||
default:
|
||||
subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusStart, "");
|
||||
subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "");
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
subghz_scene_read_raw_update_statusbar(subghz);
|
||||
|
||||
//set callback view raw
|
||||
subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz);
|
||||
|
||||
subghz->txrx->protocol_result = subghz_parser_get_by_name(subghz->txrx->parser, "RAW");
|
||||
furi_assert(subghz->txrx->protocol_result);
|
||||
subghz->txrx->decoder_result =
|
||||
subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "RAW");
|
||||
furi_assert(subghz->txrx->decoder_result);
|
||||
|
||||
subghz_worker_set_pair_callback(
|
||||
subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_raw_parse);
|
||||
|
||||
subghz_protocol_raw_file_encoder_worker_set_callback_end(
|
||||
(SubGhzProtocolRAW*)subghz->txrx->protocol_result,
|
||||
subghz_scene_read_raw_callback_end_tx,
|
||||
subghz);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReadRAW);
|
||||
//set filter RAW feed
|
||||
subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
|
||||
}
|
||||
|
||||
bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SubghzCustomEventViewReadRAWBack:
|
||||
case SubGhzCustomEventViewReadRAWBack:
|
||||
//Stop TX
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
||||
subghz_tx_stop(subghz);
|
||||
@ -121,7 +118,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
};
|
||||
//Stop save file
|
||||
subghz_protocol_raw_save_to_file_stop(
|
||||
(SubGhzProtocolRAW*)subghz->txrx->protocol_result);
|
||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
//needed save?
|
||||
if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) ||
|
||||
@ -144,7 +141,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
return true;
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWTXRXStop:
|
||||
case SubGhzCustomEventViewReadRAWTXRXStop:
|
||||
//Stop TX
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
||||
subghz_tx_stop(subghz);
|
||||
@ -159,27 +156,27 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
return true;
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWConfig:
|
||||
case SubGhzCustomEventViewReadRAWConfig:
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet);
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
|
||||
return true;
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWErase:
|
||||
case SubGhzCustomEventViewReadRAWErase:
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
return true;
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWVibro:
|
||||
case SubGhzCustomEventViewReadRAWVibro:
|
||||
notification_message(subghz->notifications, &sequence_single_vibro);
|
||||
return true;
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWMore:
|
||||
case SubGhzCustomEventViewReadRAWMore:
|
||||
if(subghz_scene_read_raw_update_filename(subghz)) {
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet);
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
|
||||
return true;
|
||||
@ -188,7 +185,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWSendStart:
|
||||
case SubGhzCustomEventViewReadRAWSendStart:
|
||||
|
||||
if(subghz_scene_read_raw_update_filename(subghz)) {
|
||||
//start send
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
@ -197,10 +195,17 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||
if(!subghz_tx_start(subghz)) {
|
||||
//ToDo FIX
|
||||
|
||||
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||
} else {
|
||||
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
||||
// set callback end tx
|
||||
subghz_protocol_raw_file_encoder_worker_set_callback_end(
|
||||
(SubGhzProtocolEncoderRAW*)subghz->txrx->transmitter->protocol_instance,
|
||||
subghz_scene_read_raw_callback_end_tx,
|
||||
subghz);
|
||||
subghz->state_notifications = SubGhzNotificationStateTX;
|
||||
}
|
||||
}
|
||||
@ -208,7 +213,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
return true;
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWSendStop:
|
||||
case SubGhzCustomEventViewReadRAWSendStop:
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
||||
subghz_tx_stop(subghz);
|
||||
@ -218,13 +223,14 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
return true;
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWIDLE:
|
||||
case SubGhzCustomEventViewReadRAWIDLE:
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
||||
subghz_rx_end(subghz);
|
||||
subghz_sleep(subghz);
|
||||
};
|
||||
subghz_protocol_raw_save_to_file_stop(
|
||||
(SubGhzProtocolRAW*)subghz->txrx->protocol_result);
|
||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
|
||||
subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, RAW_FILE_NAME);
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
||||
@ -232,16 +238,16 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
return true;
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWREC:
|
||||
case SubGhzCustomEventViewReadRAWREC:
|
||||
if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||
} else {
|
||||
subghz_get_preset_name(subghz, subghz->error_str);
|
||||
//subghz_get_preset_name(subghz, subghz->error_str);
|
||||
if(subghz_protocol_raw_save_to_file_init(
|
||||
(SubGhzProtocolRAW*)subghz->txrx->protocol_result,
|
||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result,
|
||||
RAW_FILE_NAME,
|
||||
subghz->txrx->frequency,
|
||||
string_get_cstr(subghz->error_str))) {
|
||||
subghz->txrx->preset)) {
|
||||
DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
|
||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||
@ -258,10 +264,10 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
return true;
|
||||
break;
|
||||
|
||||
case SubghzCustomEventViewReadRAWSave:
|
||||
case SubGhzCustomEventViewReadRAWSave:
|
||||
if(subghz_scene_read_raw_update_filename(subghz)) {
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSetRAW);
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||
}
|
||||
@ -278,7 +284,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz_read_raw_update_sample_write(
|
||||
subghz->subghz_read_raw,
|
||||
subghz_protocol_raw_get_sample_write(
|
||||
(SubGhzProtocolRAW*)subghz->txrx->protocol_result));
|
||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result));
|
||||
subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, furi_hal_subghz_get_rssi());
|
||||
break;
|
||||
case SubGhzNotificationStateTX:
|
||||
@ -302,7 +308,6 @@ void subghz_scene_read_raw_on_exit(void* context) {
|
||||
};
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
|
||||
//Сallback restoration
|
||||
subghz_worker_set_pair_callback(
|
||||
subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_parse);
|
||||
//filter restoration
|
||||
subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#include "../subghz_i.h"
|
||||
#include "../views/subghz_receiver.h"
|
||||
#include "../views/receiver.h"
|
||||
|
||||
static void subghz_scene_receiver_update_statusbar(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
@ -14,7 +14,7 @@ static void subghz_scene_receiver_update_statusbar(void* context) {
|
||||
|
||||
subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
|
||||
|
||||
subghz_receiver_add_data_statusbar(
|
||||
subghz_view_receiver_add_data_statusbar(
|
||||
subghz->subghz_receiver,
|
||||
string_get_cstr(frequency_str),
|
||||
string_get_cstr(modulation_str),
|
||||
@ -23,36 +23,41 @@ static void subghz_scene_receiver_update_statusbar(void* context) {
|
||||
string_clear(frequency_str);
|
||||
string_clear(modulation_str);
|
||||
} else {
|
||||
subghz_receiver_add_data_statusbar(
|
||||
subghz_view_receiver_add_data_statusbar(
|
||||
subghz->subghz_receiver, string_get_cstr(history_stat_str), "", "");
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
}
|
||||
string_clear(history_stat_str);
|
||||
}
|
||||
|
||||
void subghz_scene_receiver_callback(SubghzCustomEvent event, void* context) {
|
||||
void subghz_scene_receiver_callback(SubGhzCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void subghz_scene_add_to_history_callback(SubGhzProtocolCommon* parser, void* context) {
|
||||
static void subghz_scene_add_to_history_callback(
|
||||
SubGhzReceiver* receiver,
|
||||
SubGhzProtocolDecoderBase* decoder_base,
|
||||
void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
string_t str_buff;
|
||||
string_init(str_buff);
|
||||
|
||||
if(subghz_history_add_to_history(
|
||||
subghz->txrx->history, parser, subghz->txrx->frequency, subghz->txrx->preset)) {
|
||||
subghz_parser_reset(subghz->txrx->parser);
|
||||
subghz->txrx->history, decoder_base, subghz->txrx->frequency, subghz->txrx->preset)) {
|
||||
subghz_receiver_reset(receiver);
|
||||
string_reset(str_buff);
|
||||
|
||||
subghz_history_get_text_item_menu(
|
||||
subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
|
||||
subghz_receiver_add_item_to_menu(
|
||||
subghz_view_receiver_add_item_to_menu(
|
||||
subghz->subghz_receiver,
|
||||
string_get_cstr(str_buff),
|
||||
subghz_history_get_type_protocol(
|
||||
subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1));
|
||||
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
}
|
||||
string_clear(str_buff);
|
||||
@ -70,11 +75,11 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
}
|
||||
|
||||
//Load history to receiver
|
||||
subghz_receiver_exit(subghz->subghz_receiver);
|
||||
subghz_view_receiver_exit(subghz->subghz_receiver);
|
||||
for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
|
||||
string_reset(str_buff);
|
||||
subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
|
||||
subghz_receiver_add_item_to_menu(
|
||||
subghz_view_receiver_add_item_to_menu(
|
||||
subghz->subghz_receiver,
|
||||
string_get_cstr(str_buff),
|
||||
subghz_history_get_type_protocol(subghz->txrx->history, i));
|
||||
@ -82,8 +87,10 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
}
|
||||
string_clear(str_buff);
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
subghz_receiver_set_callback(subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
|
||||
subghz_parser_enable_dump(subghz->txrx->parser, subghz_scene_add_to_history_callback, subghz);
|
||||
subghz_view_receiver_set_callback(
|
||||
subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
|
||||
subghz_receiver_set_rx_callback(
|
||||
subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz);
|
||||
|
||||
subghz->state_notifications = SubGhzNotificationStateRX;
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
||||
@ -94,9 +101,9 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
subghz_begin(subghz, subghz->txrx->preset);
|
||||
subghz_rx(subghz, subghz->txrx->frequency);
|
||||
}
|
||||
subghz_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
|
||||
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
|
||||
}
|
||||
|
||||
bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
@ -104,7 +111,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SubghzCustomEventViewReceverBack:
|
||||
case SubGhzCustomEventViewReceverBack:
|
||||
|
||||
// Stop CC1101 Rx
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
@ -116,7 +123,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
|
||||
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
|
||||
subghz->txrx->idx_menu_chosen = 0;
|
||||
subghz_parser_enable_dump(subghz->txrx->parser, NULL, subghz);
|
||||
subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
|
||||
|
||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
|
||||
@ -127,14 +134,16 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
case SubghzCustomEventViewReceverOK:
|
||||
subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||
case SubGhzCustomEventViewReceverOK:
|
||||
subghz->txrx->idx_menu_chosen =
|
||||
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
|
||||
return true;
|
||||
break;
|
||||
case SubghzCustomEventViewReceverConfig:
|
||||
case SubGhzCustomEventViewReceverConfig:
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||
subghz->txrx->idx_menu_chosen =
|
||||
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
|
||||
return true;
|
||||
break;
|
||||
|
||||
@ -127,7 +127,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]);
|
||||
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
SubghzCustomEventManagerSet) {
|
||||
SubGhzCustomEventManagerSet) {
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Hopping:",
|
||||
@ -151,7 +151,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, preset_text[value_index]);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewVariableItemList);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
|
||||
}
|
||||
|
||||
bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent event) {
|
||||
@ -163,5 +163,5 @@ void subghz_scene_receiver_config_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
variable_item_list_reset(subghz->variable_item_list);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
||||
}
|
||||
|
||||
@ -8,25 +8,24 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v
|
||||
|
||||
if((result == GuiButtonTypeCenter) && (type == InputTypePress)) {
|
||||
view_dispatcher_send_custom_event(
|
||||
subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoTxStart);
|
||||
subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoTxStart);
|
||||
} else if((result == GuiButtonTypeCenter) && (type == InputTypeRelease)) {
|
||||
view_dispatcher_send_custom_event(
|
||||
subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoTxStop);
|
||||
subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoTxStop);
|
||||
} else if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(
|
||||
subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoSave);
|
||||
subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoSave);
|
||||
}
|
||||
}
|
||||
|
||||
static bool subghz_scene_receiver_info_update_parser(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
subghz->txrx->protocol_result = subghz_parser_get_by_name(
|
||||
subghz->txrx->parser,
|
||||
subghz_history_get_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
|
||||
|
||||
if(subghz->txrx->protocol_result->to_load_protocol != NULL) {
|
||||
subghz->txrx->protocol_result->to_load_protocol(
|
||||
subghz->txrx->protocol_result,
|
||||
subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
|
||||
subghz->txrx->receiver,
|
||||
subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
|
||||
if(subghz->txrx->decoder_result) {
|
||||
subghz_protocol_decoder_base_deserialize(
|
||||
subghz->txrx->decoder_result,
|
||||
subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
|
||||
subghz->txrx->frequency =
|
||||
subghz_history_get_frequency(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
|
||||
@ -68,8 +67,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
string_get_cstr(modulation_str));
|
||||
|
||||
subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text);
|
||||
subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
|
||||
widget_add_string_multiline_element(
|
||||
subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text));
|
||||
|
||||
@ -77,14 +75,19 @@ void subghz_scene_receiver_info_on_enter(void* context) {
|
||||
string_clear(modulation_str);
|
||||
string_clear(text);
|
||||
|
||||
if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_file &&
|
||||
strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) {
|
||||
if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
|
||||
SubGhzProtocolFlag_Save) {
|
||||
widget_add_button_element(
|
||||
subghz->widget,
|
||||
GuiButtonTypeRight,
|
||||
"Save",
|
||||
subghz_scene_receiver_info_callback,
|
||||
subghz);
|
||||
}
|
||||
if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
|
||||
SubGhzProtocolFlag_Send) &&
|
||||
subghz->txrx->decoder_result->protocol->encoder->deserialize &&
|
||||
subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic) {
|
||||
widget_add_button_element(
|
||||
subghz->widget,
|
||||
GuiButtonTypeCenter,
|
||||
@ -92,20 +95,19 @@ void subghz_scene_receiver_info_on_enter(void* context) {
|
||||
subghz_scene_receiver_info_callback,
|
||||
subghz);
|
||||
}
|
||||
|
||||
} else {
|
||||
widget_add_icon_element(subghz->widget, 32, 12, &I_DolphinFirstStart7_61x51);
|
||||
widget_add_string_element(
|
||||
subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse.");
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
|
||||
}
|
||||
|
||||
bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubghzCustomEventSceneReceiverInfoTxStart) {
|
||||
if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) {
|
||||
//CC1101 Stop RX -> Start TX
|
||||
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
|
||||
subghz->txrx->hopper_state = SubGhzHopperStatePause;
|
||||
@ -118,14 +120,17 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
|
||||
}
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE ||
|
||||
subghz->txrx->txrx_state == SubGhzTxRxStateSleep) {
|
||||
if(!subghz_tx_start(subghz)) {
|
||||
if(!subghz_tx_start(
|
||||
subghz,
|
||||
subghz_history_get_raw_data(
|
||||
subghz->txrx->history, subghz->txrx->idx_menu_chosen))) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||
} else {
|
||||
subghz->state_notifications = SubGhzNotificationStateTX;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if(event.event == SubghzCustomEventSceneReceiverInfoTxStop) {
|
||||
} else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) {
|
||||
//CC1101 Stop Tx -> Start RX
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
||||
@ -140,7 +145,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
|
||||
}
|
||||
subghz->state_notifications = SubGhzNotificationStateRX;
|
||||
return true;
|
||||
} else if(event.event == SubghzCustomEventSceneReceiverInfoSave) {
|
||||
} else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) {
|
||||
//CC1101 Stop RX -> Save
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
|
||||
@ -153,8 +158,9 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
|
||||
if(!subghz_scene_receiver_info_update_parser(subghz)) {
|
||||
return false;
|
||||
}
|
||||
if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_file &&
|
||||
strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) {
|
||||
|
||||
if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
|
||||
SubGhzProtocolFlag_Save) {
|
||||
subghz_file_name_clear(subghz);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
#include "../subghz_i.h"
|
||||
#include <lib/toolbox/random_name.h>
|
||||
#include "../helpers/subghz_custom_event.h"
|
||||
#include <lib/subghz/protocols/subghz_protocol_raw.h>
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
#include <gui/modules/validators.h>
|
||||
|
||||
void subghz_scene_save_name_text_input_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveName);
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneSaveName);
|
||||
}
|
||||
|
||||
void subghz_scene_save_name_on_enter(void* context) {
|
||||
@ -24,10 +24,10 @@ void subghz_scene_save_name_on_enter(void* context) {
|
||||
} else {
|
||||
strcpy(subghz->file_name_tmp, subghz->file_name);
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
SubghzCustomEventManagerNoSet) {
|
||||
SubGhzCustomEventManagerNoSet) {
|
||||
subghz_get_next_name_file(subghz);
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) ==
|
||||
SubghzCustomEventManagerSetRAW) {
|
||||
SubGhzCustomEventManagerSetRAW) {
|
||||
dev_name_empty = true;
|
||||
}
|
||||
}
|
||||
@ -46,7 +46,7 @@ void subghz_scene_save_name_on_enter(void* context) {
|
||||
validator_is_file_alloc_init(SUBGHZ_APP_FOLDER, SUBGHZ_APP_EXTENSION);
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTextInput);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTextInput);
|
||||
}
|
||||
|
||||
bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
||||
@ -56,22 +56,35 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_previous_scene(subghz->scene_manager);
|
||||
return true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubghzCustomEventSceneSaveName) {
|
||||
if(event.event == SubGhzCustomEventSceneSaveName) {
|
||||
if(strcmp(subghz->file_name, "")) {
|
||||
if(strcmp(subghz->file_name_tmp, "")) {
|
||||
if(!subghz_rename_file(subghz)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
subghz_save_protocol_to_file(subghz, subghz->file_name);
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType) !=
|
||||
SubGhzCustomEventManagerNoSet) {
|
||||
subghz_save_protocol_to_file(
|
||||
subghz, subghz->txrx->fff_data, subghz->file_name);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager,
|
||||
SubGhzSceneSetType,
|
||||
SubGhzCustomEventManagerNoSet);
|
||||
} else {
|
||||
subghz_save_protocol_to_file(
|
||||
subghz,
|
||||
subghz_history_get_raw_data(
|
||||
subghz->txrx->history, subghz->txrx->idx_menu_chosen),
|
||||
subghz->file_name);
|
||||
}
|
||||
}
|
||||
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||
SubghzCustomEventManagerNoSet) {
|
||||
subghz_protocol_raw_set_last_file_name(
|
||||
(SubGhzProtocolRAW*)subghz->txrx->protocol_result, subghz->file_name);
|
||||
SubGhzCustomEventManagerNoSet) {
|
||||
subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, subghz->file_name);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
||||
} else {
|
||||
subghz_file_name_clear(subghz);
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
void subghz_scene_save_success_popup_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveSuccess);
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneSaveSuccess);
|
||||
}
|
||||
|
||||
void subghz_scene_save_success_on_enter(void* context) {
|
||||
@ -20,13 +20,13 @@ void subghz_scene_save_success_on_enter(void* context) {
|
||||
popup_set_context(popup, subghz);
|
||||
popup_set_callback(popup, subghz_scene_save_success_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup);
|
||||
}
|
||||
|
||||
bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubghzCustomEventSceneSaveSuccess) {
|
||||
if(event.event == SubGhzCustomEventSceneSaveSuccess) {
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneReceiver)) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user