Merge branch 'dev' into cc1101_ext_pocsag
16
.vscode/example/tasks.json
vendored
@ -13,7 +13,7 @@
|
||||
"label": "[Debug] Build",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack"
|
||||
"command": "./fbt"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (ST-Link)",
|
||||
@ -25,7 +25,7 @@
|
||||
"label": "[Debug] Flash (ST-Link)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash"
|
||||
"command": "./fbt FORCE=1 flash"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (blackmagic)",
|
||||
@ -37,7 +37,7 @@
|
||||
"label": "[Debug] Flash (blackmagic)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_blackmagic"
|
||||
"command": "./fbt FORCE=1 flash_blackmagic"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (JLink)",
|
||||
@ -49,7 +49,7 @@
|
||||
"label": "[Debug] Flash (JLink)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 jflash"
|
||||
"command": "./fbt FORCE=1 jflash"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build update bundle",
|
||||
@ -61,7 +61,7 @@
|
||||
"label": "[Debug] Build update bundle",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack updater_package"
|
||||
"command": "./fbt updater_package"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build updater",
|
||||
@ -73,13 +73,13 @@
|
||||
"label": "[Debug] Build updater",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack updater_all"
|
||||
"command": "./fbt updater_all"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Flash (USB, w/o resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_usb"
|
||||
"command": "./fbt FORCE=1 flash_usb"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (USB, w/o resources)",
|
||||
@ -97,7 +97,7 @@
|
||||
"label": "[Debug] Flash (USB, with resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_usb_full"
|
||||
"command": "./fbt FORCE=1 flash_usb_full"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (USB, with resources)",
|
||||
|
@ -1,11 +1,14 @@
|
||||
## New changes
|
||||
* SubGHz: Keeloq: Centurion Nova read and emulate support (+ add manually)
|
||||
* !!! **Warning! After installing, Desktop settings (Favoutite apps, PIN Code, AutoLock time..) will be resetted to default due to settings changes, Please set your PIN code, Favourite apps again in Settings->Desktop** !!!
|
||||
* If you have copied any apps manually into `apps` folder - remove `apps` folder or that specific apps you copied on your microSD before installing this release to avoid issues due to OFW API version update! If you using regular builds or extra pack builds (e) without your manually added apps, all included apps will be installed automatically, no extra actions needed!
|
||||
-----
|
||||
* SubGHz: **Keeloq: Centurion Nova read and emulate support (+ add manually)**
|
||||
* SubGHz: FAAC SLH - UI Fixes, Fix sending signals with no seed
|
||||
* SubGHz: Code cleanup, proper handling of protocols ignore options (by @gid9798 | PR #516)
|
||||
* SubGHz: Various UI fixes (by @wosk | PR #527)
|
||||
* NFC: Fixed issue #532 (Mifare classic user dict - delete removes more than selected key)
|
||||
* Infrared: Updated universal remote assets (by @amec0e | PR #529)
|
||||
* Plugins: Use correct categories for all plugins (extra pack too)
|
||||
* Plugins: **Use correct categories (folders) for all plugins (extra pack too)**
|
||||
* Plugins: Various fixes for uFBT (by @hedger)
|
||||
* Plugins: Added **NFC Maker** plugin (make tags with URLs, Wifi and other things) [(by Willy-JL)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/external/nfc_maker)
|
||||
* Plugins: Added JetPack Joyride [(by timstrasser)](https://github.com/timstrasser)
|
||||
@ -14,7 +17,7 @@
|
||||
* Plugins: Updated i2c Tools [(by NaejEL)](https://github.com/NaejEL/flipperzero-i2ctools)
|
||||
* Settings: Change LED and volume settings by 5% steps (by @cokyrain)
|
||||
* BLE: BadBT fixes and furi_hal_bt cleanup (by @Willy-JL)
|
||||
* WIP OFW PR 2825: NFC: Improved MFC emulation on some readers (by AloneLiberty)
|
||||
* WIP OFW PR 2825: **NFC: Improved MFC emulation on some readers (by AloneLiberty)**
|
||||
* OFW PR 2829: Decode only supported Oregon 3 sensor (by @wosk)
|
||||
* OFW PR: Update OFW PR 2782
|
||||
* OFW: SubGhz: add "SubGhz test" external application and the ability to work "SubGhz" as an external application
|
||||
|
2
applications/external/bad_bt/application.fam
vendored
@ -10,7 +10,7 @@ App(
|
||||
stack_size=2 * 1024,
|
||||
order=70,
|
||||
fap_libs=["assets"],
|
||||
fap_category="Tools",
|
||||
fap_category="Bluetooth",
|
||||
fap_icon="images/badbt_10px.png",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
|
@ -21,5 +21,5 @@ App(
|
||||
fap_author="AloneLiberty",
|
||||
fap_description="Recover Mifare Classic keys",
|
||||
fap_weburl="https://github.com/AloneLiberty/FlipperNested",
|
||||
fap_version="1.5.0"
|
||||
fap_version="1.5.1"
|
||||
)
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include "mifare_nested_icons.h"
|
||||
|
||||
#define NESTED_VERSION_APP "1.5.0"
|
||||
#define NESTED_VERSION_APP "1.5.1"
|
||||
#define NESTED_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNested"
|
||||
#define NESTED_RECOVER_KEYS_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNestedRecovery"
|
||||
#define NESTED_NONCE_FORMAT_VERSION "3"
|
||||
|
@ -478,9 +478,13 @@ SaveNoncesResult_t* mifare_nested_worker_write_nonces(
|
||||
for(uint8_t sector = 0; sector < sector_count; sector++) {
|
||||
for(uint8_t key_type = 0; key_type < 2; key_type++) {
|
||||
if(nonces->nonces[sector][key_type][tries]->invalid) {
|
||||
result->invalid++;
|
||||
if(tries == 0) {
|
||||
result->invalid++;
|
||||
}
|
||||
} else if(nonces->nonces[sector][key_type][tries]->skipped) {
|
||||
result->skipped++;
|
||||
if(tries == 0) {
|
||||
result->skipped++;
|
||||
}
|
||||
} else if(nonces->nonces[sector][key_type][tries]->collected) {
|
||||
if(nonces->nonces[sector][key_type][tries]->hardnested) {
|
||||
FuriString* hardnested_path = furi_string_alloc();
|
||||
|
BIN
applications/external/nfc_maker/assets/KeyBackspaceSelected_16x9.png
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/nfc_maker/assets/KeyBackspace_16x9.png
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/nfc_maker/assets/KeyKeyboardSelected_10x11.png
vendored
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
applications/external/nfc_maker/assets/KeyKeyboard_10x11.png
vendored
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
applications/external/nfc_maker/assets/KeySaveSelected_24x11.png
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/nfc_maker/assets/KeySave_24x11.png
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
applications/external/nfc_maker/assets/WarningDolphin_45x42.png
vendored
Normal file
After Width: | Height: | Size: 1.1 KiB |
8
applications/external/nfc_maker/nfc_maker.c
vendored
@ -35,9 +35,11 @@ NfcMaker* nfc_maker_alloc() {
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, NfcMakerViewSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
app->text_input = text_input_alloc();
|
||||
app->text_input = nfc_maker_text_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, NfcMakerViewTextInput, text_input_get_view(app->text_input));
|
||||
app->view_dispatcher,
|
||||
NfcMakerViewTextInput,
|
||||
nfc_maker_text_input_get_view(app->text_input));
|
||||
|
||||
app->byte_input = byte_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
@ -56,7 +58,7 @@ void nfc_maker_free(NfcMaker* app) {
|
||||
view_dispatcher_remove_view(app->view_dispatcher, NfcMakerViewSubmenu);
|
||||
submenu_free(app->submenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, NfcMakerViewTextInput);
|
||||
text_input_free(app->text_input);
|
||||
nfc_maker_text_input_free(app->text_input);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, NfcMakerViewByteInput);
|
||||
byte_input_free(app->byte_input);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, NfcMakerViewPopup);
|
||||
|
4
applications/external/nfc_maker/nfc_maker.h
vendored
@ -8,7 +8,7 @@
|
||||
#include <gui/scene_manager.h>
|
||||
#include "nfc_maker_icons.h"
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include "nfc_maker_text_input.h"
|
||||
#include <gui/modules/byte_input.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include "scenes/nfc_maker_scene.h"
|
||||
@ -42,7 +42,7 @@ typedef struct {
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Submenu* submenu;
|
||||
TextInput* text_input;
|
||||
NFCMaker_TextInput* text_input;
|
||||
ByteInput* byte_input;
|
||||
Popup* popup;
|
||||
|
||||
|
762
applications/external/nfc_maker/nfc_maker_text_input.c
vendored
Normal file
@ -0,0 +1,762 @@
|
||||
#include "nfc_maker_text_input.h"
|
||||
#include <gui/elements.h>
|
||||
#include "nfc_maker.h"
|
||||
#include <furi.h>
|
||||
|
||||
struct NFCMaker_TextInput {
|
||||
View* view;
|
||||
FuriTimer* timer;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char text;
|
||||
const uint8_t x;
|
||||
const uint8_t y;
|
||||
} NFCMaker_TextInputKey;
|
||||
|
||||
typedef struct {
|
||||
const NFCMaker_TextInputKey* rows[3];
|
||||
const uint8_t keyboard_index;
|
||||
} Keyboard;
|
||||
|
||||
typedef struct {
|
||||
const char* header;
|
||||
char* text_buffer;
|
||||
size_t text_buffer_size;
|
||||
size_t minimum_length;
|
||||
bool clear_default_text;
|
||||
|
||||
bool cursor_select;
|
||||
size_t cursor_pos;
|
||||
|
||||
NFCMaker_TextInputCallback callback;
|
||||
void* callback_context;
|
||||
|
||||
uint8_t selected_row;
|
||||
uint8_t selected_column;
|
||||
uint8_t selected_keyboard;
|
||||
|
||||
NFCMaker_TextInputValidatorCallback validator_callback;
|
||||
void* validator_callback_context;
|
||||
FuriString* validator_text;
|
||||
bool validator_message_visible;
|
||||
} NFCMaker_TextInputModel;
|
||||
|
||||
static const uint8_t keyboard_origin_x = 1;
|
||||
static const uint8_t keyboard_origin_y = 29;
|
||||
static const uint8_t keyboard_row_count = 3;
|
||||
static const uint8_t keyboard_count = 2;
|
||||
|
||||
#define ENTER_KEY '\r'
|
||||
#define BACKSPACE_KEY '\b'
|
||||
#define SWITCH_KEYBOARD_KEY 0xfe
|
||||
|
||||
static const NFCMaker_TextInputKey keyboard_keys_row_1[] = {
|
||||
{'q', 1, 8},
|
||||
{'w', 10, 8},
|
||||
{'e', 19, 8},
|
||||
{'r', 28, 8},
|
||||
{'t', 37, 8},
|
||||
{'y', 46, 8},
|
||||
{'u', 55, 8},
|
||||
{'i', 64, 8},
|
||||
{'o', 73, 8},
|
||||
{'p', 82, 8},
|
||||
{'0', 91, 8},
|
||||
{'1', 100, 8},
|
||||
{'2', 110, 8},
|
||||
{'3', 120, 8},
|
||||
};
|
||||
|
||||
static const NFCMaker_TextInputKey keyboard_keys_row_2[] = {
|
||||
{'a', 1, 20},
|
||||
{'s', 10, 20},
|
||||
{'d', 19, 20},
|
||||
{'f', 28, 20},
|
||||
{'g', 37, 20},
|
||||
{'h', 46, 20},
|
||||
{'j', 55, 20},
|
||||
{'k', 64, 20},
|
||||
{'l', 73, 20},
|
||||
{BACKSPACE_KEY, 82, 12},
|
||||
{'4', 100, 20},
|
||||
{'5', 110, 20},
|
||||
{'6', 120, 20},
|
||||
};
|
||||
|
||||
static const NFCMaker_TextInputKey keyboard_keys_row_3[] = {
|
||||
{SWITCH_KEYBOARD_KEY, 1, 23},
|
||||
{'z', 13, 32},
|
||||
{'x', 21, 32},
|
||||
{'c', 28, 32},
|
||||
{'v', 36, 32},
|
||||
{'b', 44, 32},
|
||||
{'n', 52, 32},
|
||||
{'m', 59, 32},
|
||||
{'_', 67, 32},
|
||||
{ENTER_KEY, 74, 23},
|
||||
{'7', 100, 32},
|
||||
{'8', 110, 32},
|
||||
{'9', 120, 32},
|
||||
};
|
||||
|
||||
static const NFCMaker_TextInputKey symbol_keyboard_keys_row_1[] = {
|
||||
{'!', 2, 8},
|
||||
{'@', 12, 8},
|
||||
{'#', 22, 8},
|
||||
{'$', 32, 8},
|
||||
{'%', 42, 8},
|
||||
{'^', 52, 8},
|
||||
{'&', 62, 8},
|
||||
{'(', 71, 8},
|
||||
{')', 81, 8},
|
||||
{'0', 91, 8},
|
||||
{'1', 100, 8},
|
||||
{'2', 110, 8},
|
||||
{'3', 120, 8},
|
||||
};
|
||||
|
||||
static const NFCMaker_TextInputKey symbol_keyboard_keys_row_2[] = {
|
||||
{'~', 2, 20},
|
||||
{'+', 12, 20},
|
||||
{'-', 22, 20},
|
||||
{'=', 32, 20},
|
||||
{'[', 42, 20},
|
||||
{']', 52, 20},
|
||||
{'{', 62, 20},
|
||||
{'}', 72, 20},
|
||||
{BACKSPACE_KEY, 82, 12},
|
||||
{'4', 100, 20},
|
||||
{'5', 110, 20},
|
||||
{'6', 120, 20},
|
||||
};
|
||||
|
||||
static const NFCMaker_TextInputKey symbol_keyboard_keys_row_3[] = {
|
||||
{SWITCH_KEYBOARD_KEY, 1, 23},
|
||||
{'.', 15, 32},
|
||||
{',', 29, 32},
|
||||
{':', 41, 32},
|
||||
{'/', 53, 32},
|
||||
{'\\', 65, 32},
|
||||
{ENTER_KEY, 74, 23},
|
||||
{'7', 100, 32},
|
||||
{'8', 110, 32},
|
||||
{'9', 120, 32},
|
||||
};
|
||||
|
||||
static const Keyboard keyboard = {
|
||||
.rows =
|
||||
{
|
||||
keyboard_keys_row_1,
|
||||
keyboard_keys_row_2,
|
||||
keyboard_keys_row_3,
|
||||
},
|
||||
.keyboard_index = 0,
|
||||
};
|
||||
|
||||
static const Keyboard symbol_keyboard = {
|
||||
.rows =
|
||||
{
|
||||
symbol_keyboard_keys_row_1,
|
||||
symbol_keyboard_keys_row_2,
|
||||
symbol_keyboard_keys_row_3,
|
||||
},
|
||||
.keyboard_index = 1,
|
||||
};
|
||||
|
||||
static const Keyboard* keyboards[] = {
|
||||
&keyboard,
|
||||
&symbol_keyboard,
|
||||
};
|
||||
|
||||
static void switch_keyboard(NFCMaker_TextInputModel* model) {
|
||||
model->selected_keyboard = (model->selected_keyboard + 1) % keyboard_count;
|
||||
}
|
||||
|
||||
static uint8_t get_row_size(const Keyboard* keyboard, uint8_t row_index) {
|
||||
uint8_t row_size = 0;
|
||||
if(keyboard == &symbol_keyboard) {
|
||||
switch(row_index + 1) {
|
||||
case 1:
|
||||
row_size = COUNT_OF(symbol_keyboard_keys_row_1);
|
||||
break;
|
||||
case 2:
|
||||
row_size = COUNT_OF(symbol_keyboard_keys_row_2);
|
||||
break;
|
||||
case 3:
|
||||
row_size = COUNT_OF(symbol_keyboard_keys_row_3);
|
||||
break;
|
||||
default:
|
||||
furi_crash(NULL);
|
||||
}
|
||||
} else {
|
||||
switch(row_index + 1) {
|
||||
case 1:
|
||||
row_size = COUNT_OF(keyboard_keys_row_1);
|
||||
break;
|
||||
case 2:
|
||||
row_size = COUNT_OF(keyboard_keys_row_2);
|
||||
break;
|
||||
case 3:
|
||||
row_size = COUNT_OF(keyboard_keys_row_3);
|
||||
break;
|
||||
default:
|
||||
furi_crash(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return row_size;
|
||||
}
|
||||
|
||||
static const NFCMaker_TextInputKey* get_row(const Keyboard* keyboard, uint8_t row_index) {
|
||||
const NFCMaker_TextInputKey* row = NULL;
|
||||
if(row_index < 3) {
|
||||
row = keyboard->rows[row_index];
|
||||
} else {
|
||||
furi_crash(NULL);
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
static char get_selected_char(NFCMaker_TextInputModel* model) {
|
||||
return get_row(
|
||||
keyboards[model->selected_keyboard], model->selected_row)[model->selected_column]
|
||||
.text;
|
||||
}
|
||||
|
||||
static bool char_is_lowercase(char letter) {
|
||||
return (letter >= 0x61 && letter <= 0x7A);
|
||||
}
|
||||
|
||||
static char char_to_uppercase(const char letter) {
|
||||
if(letter == '_') {
|
||||
return 0x20;
|
||||
} else if(char_is_lowercase(letter)) {
|
||||
return (letter - 0x20);
|
||||
} else {
|
||||
return letter;
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_maker_text_input_backspace_cb(NFCMaker_TextInputModel* model) {
|
||||
if(model->clear_default_text) {
|
||||
model->text_buffer[0] = 0;
|
||||
model->cursor_pos = 0;
|
||||
} else if(model->cursor_pos > 0) {
|
||||
char* move = model->text_buffer + model->cursor_pos;
|
||||
memmove(move - 1, move, strlen(move) + 1);
|
||||
model->cursor_pos--;
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_maker_text_input_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
NFCMaker_TextInputModel* model = _model;
|
||||
uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0;
|
||||
uint8_t needed_string_width = canvas_width(canvas) - 8;
|
||||
uint8_t start_pos = 4;
|
||||
|
||||
model->cursor_pos = model->cursor_pos > text_length ? text_length : model->cursor_pos;
|
||||
size_t cursor_pos = model->cursor_pos;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
canvas_draw_str(canvas, 2, 8, model->header);
|
||||
elements_slightly_rounded_frame(canvas, 1, 12, 126, 15);
|
||||
|
||||
char buf[model->text_buffer_size + 1];
|
||||
if(model->text_buffer) {
|
||||
strlcpy(buf, model->text_buffer, sizeof(buf));
|
||||
}
|
||||
char* str = buf;
|
||||
|
||||
if(model->clear_default_text) {
|
||||
elements_slightly_rounded_box(
|
||||
canvas, start_pos - 1, 14, canvas_string_width(canvas, str) + 2, 10);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
} else {
|
||||
char* move = str + cursor_pos;
|
||||
memmove(move + 1, move, strlen(move) + 1);
|
||||
str[cursor_pos] = '|';
|
||||
}
|
||||
|
||||
if(cursor_pos > 0 && canvas_string_width(canvas, str) > needed_string_width) {
|
||||
canvas_draw_str(canvas, start_pos, 22, "...");
|
||||
start_pos += 6;
|
||||
needed_string_width -= 8;
|
||||
for(uint32_t off = 0;
|
||||
strlen(str) && canvas_string_width(canvas, str) > needed_string_width &&
|
||||
off < cursor_pos;
|
||||
off++) {
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
if(canvas_string_width(canvas, str) > needed_string_width) {
|
||||
needed_string_width -= 4;
|
||||
size_t len = strlen(str);
|
||||
while(len && canvas_string_width(canvas, str) > needed_string_width) {
|
||||
str[len--] = '\0';
|
||||
}
|
||||
strcat(str, "...");
|
||||
}
|
||||
|
||||
canvas_draw_str(canvas, start_pos, 22, str);
|
||||
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
|
||||
for(uint8_t row = 0; row < keyboard_row_count; row++) {
|
||||
const uint8_t column_count = get_row_size(keyboards[model->selected_keyboard], row);
|
||||
const NFCMaker_TextInputKey* keys = get_row(keyboards[model->selected_keyboard], row);
|
||||
|
||||
for(size_t column = 0; column < column_count; column++) {
|
||||
bool selected = !model->cursor_select && model->selected_row == row &&
|
||||
model->selected_column == column;
|
||||
const Icon* icon = NULL;
|
||||
if(keys[column].text == ENTER_KEY) {
|
||||
icon = selected ? &I_KeySaveSelected_24x11 : &I_KeySave_24x11;
|
||||
} else if(keys[column].text == SWITCH_KEYBOARD_KEY) {
|
||||
icon = selected ? &I_KeyKeyboardSelected_10x11 : &I_KeyKeyboard_10x11;
|
||||
} else if(keys[column].text == BACKSPACE_KEY) {
|
||||
icon = selected ? &I_KeyBackspaceSelected_16x9 : &I_KeyBackspace_16x9;
|
||||
}
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
if(icon != NULL) {
|
||||
canvas_draw_icon(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x,
|
||||
keyboard_origin_y + keys[column].y,
|
||||
icon);
|
||||
} else {
|
||||
if(selected) {
|
||||
canvas_draw_box(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x - 1,
|
||||
keyboard_origin_y + keys[column].y - 8,
|
||||
7,
|
||||
10);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
|
||||
if(model->clear_default_text || text_length == 0) {
|
||||
canvas_draw_glyph(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x,
|
||||
keyboard_origin_y + keys[column].y,
|
||||
char_to_uppercase(keys[column].text));
|
||||
} else {
|
||||
canvas_draw_glyph(
|
||||
canvas,
|
||||
keyboard_origin_x + keys[column].x,
|
||||
keyboard_origin_y + keys[column].y,
|
||||
keys[column].text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(model->validator_message_visible) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_box(canvas, 8, 10, 110, 48);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42);
|
||||
canvas_draw_rframe(canvas, 8, 8, 112, 50, 3);
|
||||
canvas_draw_rframe(canvas, 9, 9, 110, 48, 2);
|
||||
elements_multiline_text(canvas, 62, 20, furi_string_get_cstr(model->validator_text));
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_maker_text_input_handle_up(
|
||||
NFCMaker_TextInput* nfc_maker_text_input,
|
||||
NFCMaker_TextInputModel* model) {
|
||||
UNUSED(nfc_maker_text_input);
|
||||
if(model->selected_row > 0) {
|
||||
model->selected_row--;
|
||||
if(model->selected_row == 0 &&
|
||||
model->selected_column >
|
||||
get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 6) {
|
||||
model->selected_column = model->selected_column + 1;
|
||||
}
|
||||
if(model->selected_row == 1 &&
|
||||
model->selected_keyboard == symbol_keyboard.keyboard_index) {
|
||||
if(model->selected_column > 5)
|
||||
model->selected_column += 2;
|
||||
else if(model->selected_column > 1)
|
||||
model->selected_column += 1;
|
||||
}
|
||||
} else {
|
||||
model->cursor_select = true;
|
||||
model->clear_default_text = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_maker_text_input_handle_down(
|
||||
NFCMaker_TextInput* nfc_maker_text_input,
|
||||
NFCMaker_TextInputModel* model) {
|
||||
UNUSED(nfc_maker_text_input);
|
||||
if(model->cursor_select) {
|
||||
model->cursor_select = false;
|
||||
} else if(model->selected_row < keyboard_row_count - 1) {
|
||||
model->selected_row++;
|
||||
if(model->selected_row == 1 &&
|
||||
model->selected_column >
|
||||
get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 4) {
|
||||
model->selected_column = model->selected_column - 1;
|
||||
}
|
||||
if(model->selected_row == 2 &&
|
||||
model->selected_keyboard == symbol_keyboard.keyboard_index) {
|
||||
if(model->selected_column > 7)
|
||||
model->selected_column -= 2;
|
||||
else if(model->selected_column > 1)
|
||||
model->selected_column -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_maker_text_input_handle_left(
|
||||
NFCMaker_TextInput* nfc_maker_text_input,
|
||||
NFCMaker_TextInputModel* model) {
|
||||
UNUSED(nfc_maker_text_input);
|
||||
if(model->cursor_select) {
|
||||
if(model->cursor_pos > 0) {
|
||||
model->cursor_pos = CLAMP(model->cursor_pos - 1, strlen(model->text_buffer), 0u);
|
||||
}
|
||||
} else if(model->selected_column > 0) {
|
||||
model->selected_column--;
|
||||
} else {
|
||||
model->selected_column =
|
||||
get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_maker_text_input_handle_right(
|
||||
NFCMaker_TextInput* nfc_maker_text_input,
|
||||
NFCMaker_TextInputModel* model) {
|
||||
UNUSED(nfc_maker_text_input);
|
||||
if(model->cursor_select) {
|
||||
model->cursor_pos = CLAMP(model->cursor_pos + 1, strlen(model->text_buffer), 0u);
|
||||
} else if(
|
||||
model->selected_column <
|
||||
get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 1) {
|
||||
model->selected_column++;
|
||||
} else {
|
||||
model->selected_column = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_maker_text_input_handle_ok(
|
||||
NFCMaker_TextInput* nfc_maker_text_input,
|
||||
NFCMaker_TextInputModel* model,
|
||||
InputType type) {
|
||||
if(model->cursor_select) return;
|
||||
bool shift = type == InputTypeLong;
|
||||
bool repeat = type == InputTypeRepeat;
|
||||
char selected = get_selected_char(model);
|
||||
size_t text_length = strlen(model->text_buffer);
|
||||
|
||||
if(selected == ENTER_KEY) {
|
||||
if(model->validator_callback &&
|
||||
(!model->validator_callback(
|
||||
model->text_buffer, model->validator_text, model->validator_callback_context))) {
|
||||
model->validator_message_visible = true;
|
||||
furi_timer_start(nfc_maker_text_input->timer, furi_kernel_get_tick_frequency() * 4);
|
||||
} else if(model->callback != 0 && text_length >= model->minimum_length) {
|
||||
model->callback(model->callback_context);
|
||||
}
|
||||
} else if(selected == SWITCH_KEYBOARD_KEY) {
|
||||
switch_keyboard(model);
|
||||
} else {
|
||||
if(selected == BACKSPACE_KEY) {
|
||||
nfc_maker_text_input_backspace_cb(model);
|
||||
} else if(!repeat) {
|
||||
if(model->clear_default_text) {
|
||||
text_length = 0;
|
||||
}
|
||||
if(text_length < (model->text_buffer_size - 1)) {
|
||||
if(shift != (text_length == 0)) {
|
||||
selected = char_to_uppercase(selected);
|
||||
}
|
||||
if(model->clear_default_text) {
|
||||
model->text_buffer[0] = selected;
|
||||
model->text_buffer[1] = '\0';
|
||||
model->cursor_pos = 1;
|
||||
} else {
|
||||
char* move = model->text_buffer + model->cursor_pos;
|
||||
memmove(move + 1, move, strlen(move) + 1);
|
||||
model->text_buffer[model->cursor_pos] = selected;
|
||||
model->cursor_pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
model->clear_default_text = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool nfc_maker_text_input_view_input_callback(InputEvent* event, void* context) {
|
||||
NFCMaker_TextInput* nfc_maker_text_input = context;
|
||||
furi_assert(nfc_maker_text_input);
|
||||
|
||||
bool consumed = false;
|
||||
|
||||
// Acquire model
|
||||
NFCMaker_TextInputModel* model = view_get_model(nfc_maker_text_input->view);
|
||||
|
||||
if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) &&
|
||||
model->validator_message_visible) {
|
||||
model->validator_message_visible = false;
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeShort) {
|
||||
consumed = true;
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
nfc_maker_text_input_handle_up(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyDown:
|
||||
nfc_maker_text_input_handle_down(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
nfc_maker_text_input_handle_left(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyRight:
|
||||
nfc_maker_text_input_handle_right(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyOk:
|
||||
nfc_maker_text_input_handle_ok(nfc_maker_text_input, model, event->type);
|
||||
break;
|
||||
default:
|
||||
consumed = false;
|
||||
break;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
consumed = true;
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
nfc_maker_text_input_handle_up(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyDown:
|
||||
nfc_maker_text_input_handle_down(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
nfc_maker_text_input_handle_left(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyRight:
|
||||
nfc_maker_text_input_handle_right(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyOk:
|
||||
nfc_maker_text_input_handle_ok(nfc_maker_text_input, model, event->type);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
nfc_maker_text_input_backspace_cb(model);
|
||||
break;
|
||||
default:
|
||||
consumed = false;
|
||||
break;
|
||||
}
|
||||
} else if(event->type == InputTypeRepeat) {
|
||||
consumed = true;
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
nfc_maker_text_input_handle_up(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyDown:
|
||||
nfc_maker_text_input_handle_down(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
nfc_maker_text_input_handle_left(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyRight:
|
||||
nfc_maker_text_input_handle_right(nfc_maker_text_input, model);
|
||||
break;
|
||||
case InputKeyOk:
|
||||
nfc_maker_text_input_handle_ok(nfc_maker_text_input, model, event->type);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
nfc_maker_text_input_backspace_cb(model);
|
||||
break;
|
||||
default:
|
||||
consumed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit model
|
||||
view_commit_model(nfc_maker_text_input->view, consumed);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_maker_text_input_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
NFCMaker_TextInput* nfc_maker_text_input = context;
|
||||
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{ model->validator_message_visible = false; },
|
||||
true);
|
||||
}
|
||||
|
||||
NFCMaker_TextInput* nfc_maker_text_input_alloc() {
|
||||
NFCMaker_TextInput* nfc_maker_text_input = malloc(sizeof(NFCMaker_TextInput));
|
||||
nfc_maker_text_input->view = view_alloc();
|
||||
view_set_context(nfc_maker_text_input->view, nfc_maker_text_input);
|
||||
view_allocate_model(
|
||||
nfc_maker_text_input->view, ViewModelTypeLocking, sizeof(NFCMaker_TextInputModel));
|
||||
view_set_draw_callback(nfc_maker_text_input->view, nfc_maker_text_input_view_draw_callback);
|
||||
view_set_input_callback(nfc_maker_text_input->view, nfc_maker_text_input_view_input_callback);
|
||||
|
||||
nfc_maker_text_input->timer = furi_timer_alloc(
|
||||
nfc_maker_text_input_timer_callback, FuriTimerTypeOnce, nfc_maker_text_input);
|
||||
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{
|
||||
model->validator_text = furi_string_alloc();
|
||||
model->minimum_length = 1;
|
||||
model->cursor_pos = 0;
|
||||
model->cursor_select = false;
|
||||
},
|
||||
false);
|
||||
|
||||
nfc_maker_text_input_reset(nfc_maker_text_input);
|
||||
|
||||
return nfc_maker_text_input;
|
||||
}
|
||||
|
||||
void nfc_maker_text_input_free(NFCMaker_TextInput* nfc_maker_text_input) {
|
||||
furi_assert(nfc_maker_text_input);
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{ furi_string_free(model->validator_text); },
|
||||
false);
|
||||
|
||||
// Send stop command
|
||||
furi_timer_stop(nfc_maker_text_input->timer);
|
||||
// Release allocated memory
|
||||
furi_timer_free(nfc_maker_text_input->timer);
|
||||
|
||||
view_free(nfc_maker_text_input->view);
|
||||
|
||||
free(nfc_maker_text_input);
|
||||
}
|
||||
|
||||
void nfc_maker_text_input_reset(NFCMaker_TextInput* nfc_maker_text_input) {
|
||||
furi_assert(nfc_maker_text_input);
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{
|
||||
model->header = "";
|
||||
model->selected_row = 0;
|
||||
model->selected_column = 0;
|
||||
model->selected_keyboard = 0;
|
||||
model->minimum_length = 1;
|
||||
model->clear_default_text = false;
|
||||
model->cursor_pos = 0;
|
||||
model->cursor_select = false;
|
||||
model->text_buffer = NULL;
|
||||
model->text_buffer_size = 0;
|
||||
model->callback = NULL;
|
||||
model->callback_context = NULL;
|
||||
model->validator_callback = NULL;
|
||||
model->validator_callback_context = NULL;
|
||||
furi_string_reset(model->validator_text);
|
||||
model->validator_message_visible = false;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
View* nfc_maker_text_input_get_view(NFCMaker_TextInput* nfc_maker_text_input) {
|
||||
furi_assert(nfc_maker_text_input);
|
||||
return nfc_maker_text_input->view;
|
||||
}
|
||||
|
||||
void nfc_maker_text_input_set_result_callback(
|
||||
NFCMaker_TextInput* nfc_maker_text_input,
|
||||
NFCMaker_TextInputCallback callback,
|
||||
void* callback_context,
|
||||
char* text_buffer,
|
||||
size_t text_buffer_size,
|
||||
bool clear_default_text) {
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{
|
||||
model->callback = callback;
|
||||
model->callback_context = callback_context;
|
||||
model->text_buffer = text_buffer;
|
||||
model->text_buffer_size = text_buffer_size;
|
||||
model->clear_default_text = clear_default_text;
|
||||
model->cursor_select = false;
|
||||
if(text_buffer && text_buffer[0] != '\0') {
|
||||
model->cursor_pos = strlen(text_buffer);
|
||||
// Set focus on Save
|
||||
model->selected_row = 2;
|
||||
model->selected_column = 9;
|
||||
model->selected_keyboard = 0;
|
||||
} else {
|
||||
model->cursor_pos = 0;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void nfc_maker_text_input_set_minimum_length(
|
||||
NFCMaker_TextInput* nfc_maker_text_input,
|
||||
size_t minimum_length) {
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{ model->minimum_length = minimum_length; },
|
||||
true);
|
||||
}
|
||||
|
||||
void nfc_maker_text_input_set_validator(
|
||||
NFCMaker_TextInput* nfc_maker_text_input,
|
||||
NFCMaker_TextInputValidatorCallback callback,
|
||||
void* callback_context) {
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{
|
||||
model->validator_callback = callback;
|
||||
model->validator_callback_context = callback_context;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
NFCMaker_TextInputValidatorCallback
|
||||
nfc_maker_text_input_get_validator_callback(NFCMaker_TextInput* nfc_maker_text_input) {
|
||||
NFCMaker_TextInputValidatorCallback validator_callback = NULL;
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{ validator_callback = model->validator_callback; },
|
||||
false);
|
||||
return validator_callback;
|
||||
}
|
||||
|
||||
void* nfc_maker_text_input_get_validator_callback_context(
|
||||
NFCMaker_TextInput* nfc_maker_text_input) {
|
||||
void* validator_callback_context = NULL;
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{ validator_callback_context = model->validator_callback_context; },
|
||||
false);
|
||||
return validator_callback_context;
|
||||
}
|
||||
|
||||
void nfc_maker_text_input_set_header_text(
|
||||
NFCMaker_TextInput* nfc_maker_text_input,
|
||||
const char* text) {
|
||||
with_view_model(
|
||||
nfc_maker_text_input->view,
|
||||
NFCMaker_TextInputModel * model,
|
||||
{ model->header = text; },
|
||||
true);
|
||||
}
|
85
applications/external/nfc_maker/nfc_maker_text_input.h
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "nfc_maker_validators.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Text input anonymous structure */
|
||||
typedef struct NFCMaker_TextInput NFCMaker_TextInput;
|
||||
typedef void (*NFCMaker_TextInputCallback)(void* context);
|
||||
typedef bool (
|
||||
*NFCMaker_TextInputValidatorCallback)(const char* text, FuriString* error, void* context);
|
||||
|
||||
/** Allocate and initialize text input
|
||||
*
|
||||
* This text input is used to enter string
|
||||
*
|
||||
* @return NFCMaker_TextInput instance
|
||||
*/
|
||||
NFCMaker_TextInput* nfc_maker_text_input_alloc();
|
||||
|
||||
/** Deinitialize and free text input
|
||||
*
|
||||
* @param text_input NFCMaker_TextInput instance
|
||||
*/
|
||||
void nfc_maker_text_input_free(NFCMaker_TextInput* text_input);
|
||||
|
||||
/** Clean text input view Note: this function does not free memory
|
||||
*
|
||||
* @param text_input Text input instance
|
||||
*/
|
||||
void nfc_maker_text_input_reset(NFCMaker_TextInput* text_input);
|
||||
|
||||
/** Get text input view
|
||||
*
|
||||
* @param text_input NFCMaker_TextInput instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* nfc_maker_text_input_get_view(NFCMaker_TextInput* text_input);
|
||||
|
||||
/** Set text input result callback
|
||||
*
|
||||
* @param text_input NFCMaker_TextInput instance
|
||||
* @param callback callback fn
|
||||
* @param callback_context callback context
|
||||
* @param text_buffer pointer to YOUR text buffer, that we going
|
||||
* to modify
|
||||
* @param text_buffer_size YOUR text buffer size in bytes. Max string
|
||||
* length will be text_buffer_size-1.
|
||||
* @param clear_default_text clear text from text_buffer on first OK
|
||||
* event
|
||||
*/
|
||||
void nfc_maker_text_input_set_result_callback(
|
||||
NFCMaker_TextInput* text_input,
|
||||
NFCMaker_TextInputCallback callback,
|
||||
void* callback_context,
|
||||
char* text_buffer,
|
||||
size_t text_buffer_size,
|
||||
bool clear_default_text);
|
||||
|
||||
void nfc_maker_text_input_set_validator(
|
||||
NFCMaker_TextInput* text_input,
|
||||
NFCMaker_TextInputValidatorCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
void nfc_maker_text_input_set_minimum_length(NFCMaker_TextInput* text_input, size_t minimum_length);
|
||||
|
||||
NFCMaker_TextInputValidatorCallback
|
||||
nfc_maker_text_input_get_validator_callback(NFCMaker_TextInput* text_input);
|
||||
|
||||
void* nfc_maker_text_input_get_validator_callback_context(NFCMaker_TextInput* text_input);
|
||||
|
||||
/** Set text input header text
|
||||
*
|
||||
* @param text_input NFCMaker_TextInput instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void nfc_maker_text_input_set_header_text(NFCMaker_TextInput* text_input, const char* text);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
57
applications/external/nfc_maker/nfc_maker_validators.c
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
#include <furi.h>
|
||||
#include "nfc_maker_validators.h"
|
||||
#include <storage/storage.h>
|
||||
|
||||
struct ValidatorIsFile {
|
||||
char* app_path_folder;
|
||||
const char* app_extension;
|
||||
char* current_name;
|
||||
};
|
||||
|
||||
bool validator_is_file_callback(const char* text, FuriString* error, void* context) {
|
||||
furi_assert(context);
|
||||
ValidatorIsFile* instance = context;
|
||||
|
||||
if(instance->current_name != NULL) {
|
||||
if(strcmp(instance->current_name, text) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
FuriString* path = furi_string_alloc_printf(
|
||||
"%s/%s%s", instance->app_path_folder, text, instance->app_extension);
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
if(storage_common_stat(storage, furi_string_get_cstr(path), NULL) == FSE_OK) {
|
||||
ret = false;
|
||||
furi_string_printf(error, "This name\nexists!\nChoose\nanother one.");
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
furi_string_free(path);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ValidatorIsFile* validator_is_file_alloc_init(
|
||||
const char* app_path_folder,
|
||||
const char* app_extension,
|
||||
const char* current_name) {
|
||||
ValidatorIsFile* instance = malloc(sizeof(ValidatorIsFile));
|
||||
|
||||
instance->app_path_folder = strdup(app_path_folder);
|
||||
instance->app_extension = app_extension;
|
||||
if(current_name != NULL) {
|
||||
instance->current_name = strdup(current_name);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void validator_is_file_free(ValidatorIsFile* instance) {
|
||||
furi_assert(instance);
|
||||
free(instance->app_path_folder);
|
||||
free(instance->current_name);
|
||||
free(instance);
|
||||
}
|
21
applications/external/nfc_maker/nfc_maker_validators.h
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <core/common_defines.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef struct ValidatorIsFile ValidatorIsFile;
|
||||
|
||||
ValidatorIsFile* validator_is_file_alloc_init(
|
||||
const char* app_path_folder,
|
||||
const char* app_extension,
|
||||
const char* current_name);
|
||||
|
||||
void validator_is_file_free(ValidatorIsFile* instance);
|
||||
|
||||
bool validator_is_file_callback(const char* text, FuriString* error, void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -12,13 +12,13 @@ static void nfc_maker_scene_https_text_input_callback(void* context) {
|
||||
|
||||
void nfc_maker_scene_https_on_enter(void* context) {
|
||||
NfcMaker* app = context;
|
||||
TextInput* text_input = app->text_input;
|
||||
NFCMaker_TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Enter HTTPS Link:");
|
||||
nfc_maker_text_input_set_header_text(text_input, "Enter HTTPS Link:");
|
||||
|
||||
strlcpy(app->text_buf, "google.com", TEXT_INPUT_LEN);
|
||||
|
||||
text_input_set_result_callback(
|
||||
nfc_maker_text_input_set_result_callback(
|
||||
text_input,
|
||||
nfc_maker_scene_https_text_input_callback,
|
||||
app,
|
||||
@ -49,5 +49,5 @@ bool nfc_maker_scene_https_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void nfc_maker_scene_https_on_exit(void* context) {
|
||||
NfcMaker* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
nfc_maker_text_input_reset(app->text_input);
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ static void nfc_maker_scene_mail_text_input_callback(void* context) {
|
||||
|
||||
void nfc_maker_scene_mail_on_enter(void* context) {
|
||||
NfcMaker* app = context;
|
||||
TextInput* text_input = app->text_input;
|
||||
NFCMaker_TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Enter EMail Address:");
|
||||
nfc_maker_text_input_set_header_text(text_input, "Enter Email Address:");
|
||||
|
||||
strlcpy(app->text_buf, "ben.dover@example.com", TEXT_INPUT_LEN);
|
||||
|
||||
text_input_set_result_callback(
|
||||
nfc_maker_text_input_set_result_callback(
|
||||
text_input,
|
||||
nfc_maker_scene_mail_text_input_callback,
|
||||
app,
|
||||
@ -49,5 +49,5 @@ bool nfc_maker_scene_mail_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void nfc_maker_scene_mail_on_exit(void* context) {
|
||||
NfcMaker* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
nfc_maker_text_input_reset(app->text_input);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ void nfc_maker_scene_menu_on_enter(void* context) {
|
||||
submenu, "HTTPS Link", NfcMakerSceneHttps, nfc_maker_scene_menu_submenu_callback, app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "Mail Address", NfcMakerSceneMail, nfc_maker_scene_menu_submenu_callback, app);
|
||||
submenu, "Email Address", NfcMakerSceneMail, nfc_maker_scene_menu_submenu_callback, app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "Phone Number", NfcMakerScenePhone, nfc_maker_scene_menu_submenu_callback, app);
|
||||
|
@ -12,13 +12,13 @@ static void nfc_maker_scene_name_text_input_callback(void* context) {
|
||||
|
||||
void nfc_maker_scene_name_on_enter(void* context) {
|
||||
NfcMaker* app = context;
|
||||
TextInput* text_input = app->text_input;
|
||||
NFCMaker_TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Name the NFC tag:");
|
||||
nfc_maker_text_input_set_header_text(text_input, "Name the NFC tag:");
|
||||
|
||||
set_random_name(app->name_buf, TEXT_INPUT_LEN);
|
||||
|
||||
text_input_set_result_callback(
|
||||
nfc_maker_text_input_set_result_callback(
|
||||
text_input,
|
||||
nfc_maker_scene_name_text_input_callback,
|
||||
app,
|
||||
@ -28,7 +28,7 @@ void nfc_maker_scene_name_on_enter(void* context) {
|
||||
|
||||
ValidatorIsFile* validator_is_file =
|
||||
validator_is_file_alloc_init(NFC_APP_FOLDER, NFC_APP_EXTENSION, NULL);
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
nfc_maker_text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, NfcMakerViewTextInput);
|
||||
}
|
||||
@ -53,5 +53,5 @@ bool nfc_maker_scene_name_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void nfc_maker_scene_name_on_exit(void* context) {
|
||||
NfcMaker* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
nfc_maker_text_input_reset(app->text_input);
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ static void nfc_maker_scene_phone_text_input_callback(void* context) {
|
||||
|
||||
void nfc_maker_scene_phone_on_enter(void* context) {
|
||||
NfcMaker* app = context;
|
||||
TextInput* text_input = app->text_input;
|
||||
NFCMaker_TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Enter Phone Number:");
|
||||
nfc_maker_text_input_set_header_text(text_input, "Enter Phone Number:");
|
||||
|
||||
strlcpy(app->text_buf, "+", TEXT_INPUT_LEN);
|
||||
|
||||
text_input_set_result_callback(
|
||||
nfc_maker_text_input_set_result_callback(
|
||||
text_input,
|
||||
nfc_maker_scene_phone_text_input_callback,
|
||||
app,
|
||||
@ -49,5 +49,5 @@ bool nfc_maker_scene_phone_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void nfc_maker_scene_phone_on_exit(void* context) {
|
||||
NfcMaker* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
nfc_maker_text_input_reset(app->text_input);
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ static void nfc_maker_scene_text_text_input_callback(void* context) {
|
||||
|
||||
void nfc_maker_scene_text_on_enter(void* context) {
|
||||
NfcMaker* app = context;
|
||||
TextInput* text_input = app->text_input;
|
||||
NFCMaker_TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Enter Text Note:");
|
||||
nfc_maker_text_input_set_header_text(text_input, "Enter Text Note:");
|
||||
|
||||
strlcpy(app->text_buf, "Lorem ipsum", TEXT_INPUT_LEN);
|
||||
|
||||
text_input_set_result_callback(
|
||||
nfc_maker_text_input_set_result_callback(
|
||||
text_input,
|
||||
nfc_maker_scene_text_text_input_callback,
|
||||
app,
|
||||
@ -49,5 +49,5 @@ bool nfc_maker_scene_text_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void nfc_maker_scene_text_on_exit(void* context) {
|
||||
NfcMaker* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
nfc_maker_text_input_reset(app->text_input);
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ static void nfc_maker_scene_url_text_input_callback(void* context) {
|
||||
|
||||
void nfc_maker_scene_url_on_enter(void* context) {
|
||||
NfcMaker* app = context;
|
||||
TextInput* text_input = app->text_input;
|
||||
NFCMaker_TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Enter Plain URL:");
|
||||
nfc_maker_text_input_set_header_text(text_input, "Enter Plain URL:");
|
||||
|
||||
strlcpy(app->text_buf, "https://google.com", TEXT_INPUT_LEN);
|
||||
|
||||
text_input_set_result_callback(
|
||||
nfc_maker_text_input_set_result_callback(
|
||||
text_input,
|
||||
nfc_maker_scene_url_text_input_callback,
|
||||
app,
|
||||
@ -49,5 +49,5 @@ bool nfc_maker_scene_url_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void nfc_maker_scene_url_on_exit(void* context) {
|
||||
NfcMaker* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
nfc_maker_text_input_reset(app->text_input);
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ static void nfc_maker_scene_wifi_text_input_callback(void* context) {
|
||||
|
||||
void nfc_maker_scene_wifi_on_enter(void* context) {
|
||||
NfcMaker* app = context;
|
||||
TextInput* text_input = app->text_input;
|
||||
NFCMaker_TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Enter WiFi SSID:");
|
||||
nfc_maker_text_input_set_header_text(text_input, "Enter WiFi SSID:");
|
||||
|
||||
strlcpy(app->text_buf, "Bill Wi the Science Fi", WIFI_INPUT_LEN);
|
||||
|
||||
text_input_set_result_callback(
|
||||
nfc_maker_text_input_set_result_callback(
|
||||
text_input,
|
||||
nfc_maker_scene_wifi_text_input_callback,
|
||||
app,
|
||||
@ -51,5 +51,5 @@ bool nfc_maker_scene_wifi_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void nfc_maker_scene_wifi_on_exit(void* context) {
|
||||
NfcMaker* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
nfc_maker_text_input_reset(app->text_input);
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ static void nfc_maker_scene_wifi_pass_text_input_callback(void* context) {
|
||||
|
||||
void nfc_maker_scene_wifi_pass_on_enter(void* context) {
|
||||
NfcMaker* app = context;
|
||||
TextInput* text_input = app->text_input;
|
||||
NFCMaker_TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Enter WiFi Password:");
|
||||
nfc_maker_text_input_set_header_text(text_input, "Enter WiFi Password:");
|
||||
|
||||
strlcpy(app->pass_buf, "244466666", WIFI_INPUT_LEN);
|
||||
|
||||
text_input_set_result_callback(
|
||||
nfc_maker_text_input_set_result_callback(
|
||||
text_input,
|
||||
nfc_maker_scene_wifi_pass_text_input_callback,
|
||||
app,
|
||||
@ -49,5 +49,5 @@ bool nfc_maker_scene_wifi_pass_on_event(void* context, SceneManagerEvent event)
|
||||
|
||||
void nfc_maker_scene_wifi_pass_on_exit(void* context) {
|
||||
NfcMaker* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
nfc_maker_text_input_reset(app->text_input);
|
||||
}
|
||||
|
@ -182,6 +182,11 @@ bool wifi_marauder_scene_console_output_on_event(void* context, SceneManagerEven
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
consumed = true;
|
||||
} else {
|
||||
if(app->flash_worker_busy) {
|
||||
// ignore button presses while flashing
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
|
@ -1,9 +1,14 @@
|
||||
#include "../wifi_marauder_app_i.h"
|
||||
#include "../wifi_marauder_flasher.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexS3Mode,
|
||||
SubmenuIndexBoot,
|
||||
SubmenuIndexPart,
|
||||
SubmenuIndexNvs,
|
||||
SubmenuIndexBootApp0,
|
||||
SubmenuIndexApp,
|
||||
SubmenuIndexCustom,
|
||||
SubmenuIndexFlash,
|
||||
};
|
||||
|
||||
@ -20,16 +25,33 @@ static void wifi_marauder_scene_flasher_callback(void* context, uint32_t index)
|
||||
|
||||
// TODO refactor
|
||||
switch(index) {
|
||||
case SubmenuIndexS3Mode:
|
||||
// toggle S3 mode
|
||||
app->selected_flash_options[SelectedFlashS3Mode] =
|
||||
!app->selected_flash_options[SelectedFlashS3Mode];
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventRefreshSubmenu);
|
||||
break;
|
||||
case SubmenuIndexBoot:
|
||||
if(dialog_file_browser_show(
|
||||
app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
|
||||
strncpy(
|
||||
app->bin_file_path_boot,
|
||||
furi_string_get_cstr(selected_filepath),
|
||||
sizeof(app->bin_file_path_boot));
|
||||
app->selected_flash_options[SelectedFlashBoot] =
|
||||
!app->selected_flash_options[SelectedFlashBoot];
|
||||
if(app->selected_flash_options[SelectedFlashBoot]) {
|
||||
if(dialog_file_browser_show(
|
||||
app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
|
||||
strncpy(
|
||||
app->bin_file_path_boot,
|
||||
furi_string_get_cstr(selected_filepath),
|
||||
sizeof(app->bin_file_path_boot));
|
||||
}
|
||||
}
|
||||
if(app->bin_file_path_boot[0] == '\0') {
|
||||
// if user didn't select a file, leave unselected
|
||||
app->selected_flash_options[SelectedFlashBoot] = false;
|
||||
}
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventRefreshSubmenu);
|
||||
break;
|
||||
case SubmenuIndexPart:
|
||||
app->selected_flash_options[SelectedFlashPart] =
|
||||
!app->selected_flash_options[SelectedFlashPart];
|
||||
if(dialog_file_browser_show(
|
||||
app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
|
||||
strncpy(
|
||||
@ -37,8 +59,47 @@ static void wifi_marauder_scene_flasher_callback(void* context, uint32_t index)
|
||||
furi_string_get_cstr(selected_filepath),
|
||||
sizeof(app->bin_file_path_part));
|
||||
}
|
||||
if(app->bin_file_path_part[0] == '\0') {
|
||||
// if user didn't select a file, leave unselected
|
||||
app->selected_flash_options[SelectedFlashPart] = false;
|
||||
}
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventRefreshSubmenu);
|
||||
break;
|
||||
case SubmenuIndexNvs:
|
||||
app->selected_flash_options[SelectedFlashNvs] =
|
||||
!app->selected_flash_options[SelectedFlashNvs];
|
||||
if(dialog_file_browser_show(
|
||||
app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
|
||||
strncpy(
|
||||
app->bin_file_path_nvs,
|
||||
furi_string_get_cstr(selected_filepath),
|
||||
sizeof(app->bin_file_path_nvs));
|
||||
}
|
||||
if(app->bin_file_path_nvs[0] == '\0') {
|
||||
// if user didn't select a file, leave unselected
|
||||
app->selected_flash_options[SelectedFlashNvs] = false;
|
||||
}
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventRefreshSubmenu);
|
||||
break;
|
||||
case SubmenuIndexBootApp0:
|
||||
app->selected_flash_options[SelectedFlashBootApp0] =
|
||||
!app->selected_flash_options[SelectedFlashBootApp0];
|
||||
if(dialog_file_browser_show(
|
||||
app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
|
||||
strncpy(
|
||||
app->bin_file_path_boot_app0,
|
||||
furi_string_get_cstr(selected_filepath),
|
||||
sizeof(app->bin_file_path_boot_app0));
|
||||
}
|
||||
if(app->bin_file_path_boot_app0[0] == '\0') {
|
||||
// if user didn't select a file, leave unselected
|
||||
app->selected_flash_options[SelectedFlashBootApp0] = false;
|
||||
}
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventRefreshSubmenu);
|
||||
break;
|
||||
case SubmenuIndexApp:
|
||||
app->selected_flash_options[SelectedFlashApp] =
|
||||
!app->selected_flash_options[SelectedFlashApp];
|
||||
if(dialog_file_browser_show(
|
||||
app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
|
||||
strncpy(
|
||||
@ -46,10 +107,42 @@ static void wifi_marauder_scene_flasher_callback(void* context, uint32_t index)
|
||||
furi_string_get_cstr(selected_filepath),
|
||||
sizeof(app->bin_file_path_app));
|
||||
}
|
||||
if(app->bin_file_path_app[0] == '\0') {
|
||||
// if user didn't select a file, leave unselected
|
||||
app->selected_flash_options[SelectedFlashApp] = false;
|
||||
}
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventRefreshSubmenu);
|
||||
break;
|
||||
case SubmenuIndexCustom:
|
||||
app->selected_flash_options[SelectedFlashCustom] =
|
||||
!app->selected_flash_options[SelectedFlashCustom];
|
||||
if(dialog_file_browser_show(
|
||||
app->dialogs, selected_filepath, predefined_filepath, &browser_options)) {
|
||||
strncpy(
|
||||
app->bin_file_path_custom,
|
||||
furi_string_get_cstr(selected_filepath),
|
||||
sizeof(app->bin_file_path_custom));
|
||||
}
|
||||
if(app->bin_file_path_custom[0] == '\0') {
|
||||
// if user didn't select a file, leave unselected
|
||||
app->selected_flash_options[SelectedFlashCustom] = false;
|
||||
}
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventRefreshSubmenu);
|
||||
break;
|
||||
case SubmenuIndexFlash:
|
||||
// TODO error checking
|
||||
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput);
|
||||
// count how many options are selected
|
||||
app->num_selected_flash_options = 0;
|
||||
for(bool* option = &app->selected_flash_options[SelectedFlashBoot];
|
||||
option < &app->selected_flash_options[NUM_FLASH_OPTIONS];
|
||||
++option) {
|
||||
if(*option) {
|
||||
++app->num_selected_flash_options;
|
||||
}
|
||||
}
|
||||
if(app->num_selected_flash_options) {
|
||||
// only start next scene if at least one option is selected
|
||||
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -57,31 +150,112 @@ static void wifi_marauder_scene_flasher_callback(void* context, uint32_t index)
|
||||
furi_string_free(predefined_filepath);
|
||||
}
|
||||
|
||||
void wifi_marauder_scene_flasher_on_enter(void* context) {
|
||||
WifiMarauderApp* app = context;
|
||||
|
||||
#define STR_SELECT "[x]"
|
||||
#define STR_UNSELECT "[ ]"
|
||||
#define STR_BOOT "Bootloader (" TOSTRING(ESP_ADDR_BOOT) ")"
|
||||
#define STR_BOOT_S3 "Bootloader (" TOSTRING(ESP_ADDR_BOOT_S3) ")"
|
||||
#define STR_PART "Part Table (" TOSTRING(ESP_ADDR_PART) ")"
|
||||
#define STR_NVS "NVS (" TOSTRING(ESP_ADDR_NVS) ")"
|
||||
#define STR_BOOT_APP0 "boot_app0 (" TOSTRING(ESP_ADDR_BOOT_APP0) ")"
|
||||
#define STR_APP "Firmware (" TOSTRING(ESP_ADDR_APP) ")"
|
||||
#define STR_CUSTOM "Custom"
|
||||
#define STR_FLASH_S3 "[>] FLASH (ESP32-S3)"
|
||||
#define STR_FLASH "[>] FLASH"
|
||||
static void _refresh_submenu(WifiMarauderApp* app) {
|
||||
Submenu* submenu = app->submenu;
|
||||
|
||||
submenu_reset(app->submenu);
|
||||
|
||||
submenu_set_header(submenu, "Browse for files to flash");
|
||||
submenu_add_item(
|
||||
submenu, "Bootloader", SubmenuIndexBoot, wifi_marauder_scene_flasher_callback, app);
|
||||
submenu,
|
||||
app->selected_flash_options[SelectedFlashS3Mode] ? "[x] Using ESP32-S3" :
|
||||
"[ ] Check if using S3",
|
||||
SubmenuIndexS3Mode,
|
||||
wifi_marauder_scene_flasher_callback,
|
||||
app);
|
||||
const char* strSelectBootloader = STR_UNSELECT " " STR_BOOT;
|
||||
if(app->selected_flash_options[SelectedFlashS3Mode]) {
|
||||
if(app->selected_flash_options[SelectedFlashBoot]) {
|
||||
strSelectBootloader = STR_SELECT " " STR_BOOT_S3;
|
||||
} else {
|
||||
strSelectBootloader = STR_UNSELECT " " STR_BOOT_S3;
|
||||
}
|
||||
} else {
|
||||
if(app->selected_flash_options[SelectedFlashBoot]) {
|
||||
strSelectBootloader = STR_SELECT " " STR_BOOT;
|
||||
} else {
|
||||
strSelectBootloader = STR_UNSELECT " " STR_BOOT;
|
||||
}
|
||||
}
|
||||
submenu_add_item(
|
||||
submenu, "Partition Table", SubmenuIndexPart, wifi_marauder_scene_flasher_callback, app);
|
||||
submenu, strSelectBootloader, SubmenuIndexBoot, wifi_marauder_scene_flasher_callback, app);
|
||||
submenu_add_item(
|
||||
submenu, "Application", SubmenuIndexApp, wifi_marauder_scene_flasher_callback, app);
|
||||
submenu,
|
||||
app->selected_flash_options[SelectedFlashPart] ? STR_SELECT " " STR_PART :
|
||||
STR_UNSELECT " " STR_PART,
|
||||
SubmenuIndexPart,
|
||||
wifi_marauder_scene_flasher_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu, "[>] FLASH", SubmenuIndexFlash, wifi_marauder_scene_flasher_callback, app);
|
||||
submenu,
|
||||
app->selected_flash_options[SelectedFlashNvs] ? STR_SELECT " " STR_NVS :
|
||||
STR_UNSELECT " " STR_NVS,
|
||||
SubmenuIndexNvs,
|
||||
wifi_marauder_scene_flasher_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
app->selected_flash_options[SelectedFlashBootApp0] ? STR_SELECT " " STR_BOOT_APP0 :
|
||||
STR_UNSELECT " " STR_BOOT_APP0,
|
||||
SubmenuIndexBootApp0,
|
||||
wifi_marauder_scene_flasher_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
app->selected_flash_options[SelectedFlashApp] ? STR_SELECT " " STR_APP :
|
||||
STR_UNSELECT " " STR_APP,
|
||||
SubmenuIndexApp,
|
||||
wifi_marauder_scene_flasher_callback,
|
||||
app);
|
||||
// TODO: custom addr
|
||||
//submenu_add_item(
|
||||
// submenu, app->selected_flash_options[SelectedFlashCustom] ? STR_SELECT " " STR_CUSTOM : STR_UNSELECT " " STR_CUSTOM, SubmenuIndexCustom, wifi_marauder_scene_flasher_callback, app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
app->selected_flash_options[SelectedFlashS3Mode] ? STR_FLASH_S3 : STR_FLASH,
|
||||
SubmenuIndexFlash,
|
||||
wifi_marauder_scene_flasher_callback,
|
||||
app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneFlasher));
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewSubmenu);
|
||||
}
|
||||
|
||||
void wifi_marauder_scene_flasher_on_enter(void* context) {
|
||||
WifiMarauderApp* app = context;
|
||||
|
||||
memset(app->selected_flash_options, 0, sizeof(app->selected_flash_options));
|
||||
app->bin_file_path_boot[0] = '\0';
|
||||
app->bin_file_path_part[0] = '\0';
|
||||
app->bin_file_path_nvs[0] = '\0';
|
||||
app->bin_file_path_boot_app0[0] = '\0';
|
||||
app->bin_file_path_app[0] = '\0';
|
||||
app->bin_file_path_custom[0] = '\0';
|
||||
|
||||
_refresh_submenu(app);
|
||||
}
|
||||
|
||||
bool wifi_marauder_scene_flasher_on_event(void* context, SceneManagerEvent event) {
|
||||
//WifiMarauderApp* app = context;
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
WifiMarauderApp* app = context;
|
||||
bool consumed = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == WifiMarauderEventRefreshSubmenu) {
|
||||
_refresh_submenu(app);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
@ -243,7 +243,6 @@ void wifi_marauder_scene_start_on_enter(void* context) {
|
||||
}
|
||||
|
||||
bool wifi_marauder_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
WifiMarauderApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
|
@ -87,6 +87,7 @@ WifiMarauderApp* wifi_marauder_app_alloc() {
|
||||
app->view_dispatcher, WifiMarauderAppViewSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
app->flash_mode = false;
|
||||
app->flash_worker_busy = false;
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneStart);
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define WIFI_MARAUDER_APP_VERSION "v0.5.0"
|
||||
#define WIFI_MARAUDER_APP_VERSION "v0.5.1"
|
||||
|
||||
typedef struct WifiMarauderApp WifiMarauderApp;
|
||||
|
||||
|
@ -48,6 +48,17 @@ typedef enum WifiMarauderUserInputType {
|
||||
WifiMarauderUserInputTypeFileName
|
||||
} WifiMarauderUserInputType;
|
||||
|
||||
typedef enum SelectedFlashOptions {
|
||||
SelectedFlashS3Mode,
|
||||
SelectedFlashBoot,
|
||||
SelectedFlashPart,
|
||||
SelectedFlashNvs,
|
||||
SelectedFlashBootApp0,
|
||||
SelectedFlashApp,
|
||||
SelectedFlashCustom,
|
||||
NUM_FLASH_OPTIONS
|
||||
} SelectedFlashOptions;
|
||||
|
||||
struct WifiMarauderApp {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
@ -115,10 +126,16 @@ struct WifiMarauderApp {
|
||||
char special_case_input_dst_addr[20];
|
||||
|
||||
// For flashing - TODO: put into its own struct?
|
||||
bool selected_flash_options[NUM_FLASH_OPTIONS];
|
||||
int num_selected_flash_options;
|
||||
char bin_file_path_boot[100];
|
||||
char bin_file_path_part[100];
|
||||
char bin_file_path_nvs[100];
|
||||
char bin_file_path_boot_app0[100];
|
||||
char bin_file_path_app[100];
|
||||
char bin_file_path_custom[100];
|
||||
FuriThread* flash_worker;
|
||||
bool flash_worker_busy;
|
||||
bool flash_mode;
|
||||
};
|
||||
|
||||
|
@ -10,5 +10,6 @@ typedef enum {
|
||||
WifiMarauderEventStartLogViewer,
|
||||
WifiMarauderEventStartScriptSelect,
|
||||
WifiMarauderEventStartSniffPmkidOptions,
|
||||
WifiMarauderEventStartFlasher
|
||||
WifiMarauderEventStartFlasher,
|
||||
WifiMarauderEventRefreshSubmenu
|
||||
} WifiMarauderCustomEvent;
|
||||
|
@ -18,6 +18,8 @@ static esp_loader_error_t _flash_file(WifiMarauderApp* app, char* filepath, uint
|
||||
static uint8_t payload[1024];
|
||||
File* bin_file = storage_file_alloc(app->storage);
|
||||
|
||||
char user_msg[256];
|
||||
|
||||
// open file
|
||||
if(!storage_file_open(bin_file, filepath, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
storage_file_close(bin_file);
|
||||
@ -28,48 +30,34 @@ static esp_loader_error_t _flash_file(WifiMarauderApp* app, char* filepath, uint
|
||||
|
||||
uint64_t size = storage_file_size(bin_file);
|
||||
|
||||
/*
|
||||
// TODO packet drops with higher BR?
|
||||
err = esp_loader_change_transmission_rate(230400);
|
||||
if (err != ESP_LOADER_SUCCESS) {
|
||||
char err_msg[256];
|
||||
snprintf(
|
||||
err_msg,
|
||||
sizeof(err_msg),
|
||||
"Cannot change transmission rate. Error: %u\n",
|
||||
err);
|
||||
storage_file_close(bin_file);
|
||||
storage_file_free(bin_file);
|
||||
loader_port_debug_print(err_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
furi_hal_uart_set_br(FuriHalUartIdUSART1, 230400);
|
||||
// TODO remember to change BR back!
|
||||
*/
|
||||
|
||||
loader_port_debug_print("Erasing flash...this may take a while\n");
|
||||
err = esp_loader_flash_start(addr, size, sizeof(payload));
|
||||
if(err != ESP_LOADER_SUCCESS) {
|
||||
storage_file_close(bin_file);
|
||||
storage_file_free(bin_file);
|
||||
char err_msg[256];
|
||||
snprintf(err_msg, sizeof(err_msg), "Erasing flash failed with error %d\n", err);
|
||||
loader_port_debug_print(err_msg);
|
||||
snprintf(user_msg, sizeof(user_msg), "Erasing flash failed with error %d\n", err);
|
||||
loader_port_debug_print(user_msg);
|
||||
return err;
|
||||
}
|
||||
|
||||
loader_port_debug_print("Start programming\n");
|
||||
uint64_t last_updated = size;
|
||||
while(size > 0) {
|
||||
if((last_updated - size) > 50000) {
|
||||
// inform user every 50k bytes
|
||||
// TODO: draw a progress bar next update
|
||||
snprintf(user_msg, sizeof(user_msg), "%llu bytes left.\n", size);
|
||||
loader_port_debug_print(user_msg);
|
||||
last_updated = size;
|
||||
}
|
||||
size_t to_read = MIN(size, sizeof(payload));
|
||||
uint16_t num_bytes = storage_file_read(bin_file, payload, to_read);
|
||||
err = esp_loader_flash_write(payload, num_bytes);
|
||||
if(err != ESP_LOADER_SUCCESS) {
|
||||
char err_msg[256];
|
||||
snprintf(err_msg, sizeof(err_msg), "Packet could not be written! Error: %u\n", err);
|
||||
snprintf(user_msg, sizeof(user_msg), "Packet could not be written! Error: %u\n", err);
|
||||
storage_file_close(bin_file);
|
||||
storage_file_free(bin_file);
|
||||
loader_port_debug_print(err_msg);
|
||||
loader_port_debug_print(user_msg);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -86,10 +74,59 @@ static esp_loader_error_t _flash_file(WifiMarauderApp* app, char* filepath, uint
|
||||
return ESP_LOADER_SUCCESS;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
SelectedFlashOptions selected;
|
||||
const char* description;
|
||||
char* path;
|
||||
uint32_t addr;
|
||||
} FlashItem;
|
||||
|
||||
static void _flash_all_files(WifiMarauderApp* app) {
|
||||
esp_loader_error_t err;
|
||||
const int num_steps = app->num_selected_flash_options;
|
||||
|
||||
#define NUM_FLASH_ITEMS 6
|
||||
FlashItem items[NUM_FLASH_ITEMS] = {
|
||||
{SelectedFlashBoot,
|
||||
"bootloader",
|
||||
app->bin_file_path_boot,
|
||||
app->selected_flash_options[SelectedFlashS3Mode] ? ESP_ADDR_BOOT_S3 : ESP_ADDR_BOOT},
|
||||
{SelectedFlashPart, "partition table", app->bin_file_path_part, ESP_ADDR_PART},
|
||||
{SelectedFlashNvs, "NVS", app->bin_file_path_nvs, ESP_ADDR_NVS},
|
||||
{SelectedFlashBootApp0, "boot_app0", app->bin_file_path_boot_app0, ESP_ADDR_BOOT_APP0},
|
||||
{SelectedFlashApp, "firmware", app->bin_file_path_app, ESP_ADDR_APP},
|
||||
{SelectedFlashCustom, "custom data", app->bin_file_path_custom, 0x0},
|
||||
/* if you add more entries, update NUM_FLASH_ITEMS above! */
|
||||
};
|
||||
|
||||
char user_msg[256];
|
||||
|
||||
int current_step = 1;
|
||||
for(FlashItem* item = &items[0]; item < &items[NUM_FLASH_ITEMS]; ++item) {
|
||||
if(app->selected_flash_options[item->selected]) {
|
||||
snprintf(
|
||||
user_msg,
|
||||
sizeof(user_msg),
|
||||
"Flashing %s (%d/%d) to address 0x%lx\n",
|
||||
item->description,
|
||||
current_step++,
|
||||
num_steps,
|
||||
item->addr);
|
||||
loader_port_debug_print(user_msg);
|
||||
err = _flash_file(app, item->path, item->addr);
|
||||
if(err) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t wifi_marauder_flash_bin(void* context) {
|
||||
WifiMarauderApp* app = (void*)context;
|
||||
esp_loader_error_t err;
|
||||
|
||||
app->flash_worker_busy = true;
|
||||
|
||||
// alloc global objects
|
||||
flash_rx_stream = furi_stream_buffer_alloc(RX_BUF_SIZE, 1);
|
||||
timer = furi_timer_alloc(_timer_callback, FuriTimerTypePeriodic, app);
|
||||
@ -103,22 +140,36 @@ static int32_t wifi_marauder_flash_bin(void* context) {
|
||||
loader_port_debug_print(err_msg);
|
||||
}
|
||||
|
||||
#if 0 // still getting packet drops with this
|
||||
// higher BR
|
||||
if(!err) {
|
||||
loader_port_debug_print("Increasing speed for faster flash\n");
|
||||
err = esp_loader_change_transmission_rate(230400);
|
||||
if (err != ESP_LOADER_SUCCESS) {
|
||||
char err_msg[256];
|
||||
snprintf(
|
||||
err_msg,
|
||||
sizeof(err_msg),
|
||||
"Cannot change transmission rate. Error: %u\n",
|
||||
err);
|
||||
loader_port_debug_print(err_msg);
|
||||
}
|
||||
furi_hal_uart_set_br(FuriHalUartIdUSART1, 230400);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!err) {
|
||||
loader_port_debug_print("Connected\n");
|
||||
loader_port_debug_print("Flashing bootloader (1/3)\n");
|
||||
err = _flash_file(app, app->bin_file_path_boot, 0x1000);
|
||||
}
|
||||
if(!err) {
|
||||
loader_port_debug_print("Flashing partition table (2/3)\n");
|
||||
err = _flash_file(app, app->bin_file_path_part, 0x8000);
|
||||
}
|
||||
if(!err) {
|
||||
loader_port_debug_print("Flashing app (3/3)\n");
|
||||
err = _flash_file(app, app->bin_file_path_app, 0x10000);
|
||||
_flash_all_files(app);
|
||||
#if 0
|
||||
loader_port_debug_print("Restoring transmission rate\n");
|
||||
furi_hal_uart_set_br(FuriHalUartIdUSART1, 115200);
|
||||
#endif
|
||||
loader_port_debug_print("Done flashing. Please reset the board manually.\n");
|
||||
}
|
||||
|
||||
// done
|
||||
app->flash_worker_busy = false;
|
||||
|
||||
// cleanup
|
||||
furi_stream_buffer_free(flash_rx_stream);
|
||||
|
@ -5,6 +5,13 @@
|
||||
#define SERIAL_FLASHER_INTERFACE_UART /* TODO why is application.fam not passing this via cdefines */
|
||||
#include "esp_loader_io.h"
|
||||
|
||||
#define ESP_ADDR_BOOT_S3 0x0
|
||||
#define ESP_ADDR_BOOT 0x1000
|
||||
#define ESP_ADDR_PART 0x8000
|
||||
#define ESP_ADDR_NVS 0x9000
|
||||
#define ESP_ADDR_BOOT_APP0 0xE000
|
||||
#define ESP_ADDR_APP 0x10000
|
||||
|
||||
void wifi_marauder_flash_start_thread(WifiMarauderApp* app);
|
||||
void wifi_marauder_flash_stop_thread(WifiMarauderApp* app);
|
||||
void wifi_marauder_flash_handle_rx_data_cb(uint8_t* buf, size_t len, void* context);
|
@ -4,7 +4,6 @@ App(
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"gpio",
|
||||
"onewire",
|
||||
"ibutton",
|
||||
"infrared",
|
||||
"lfrfid",
|
||||
@ -15,23 +14,20 @@ App(
|
||||
"archive",
|
||||
"clock",
|
||||
"subghz_remote",
|
||||
"main_apps_on_start",
|
||||
],
|
||||
)
|
||||
|
||||
# Enable apps that you need in DEBUG firmware here:
|
||||
App(
|
||||
appid="main_apps_default",
|
||||
name="Basic applications for main menu",
|
||||
appid="main_apps_on_start",
|
||||
name="On start hooks",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
# "gpio",
|
||||
# "ibutton",
|
||||
# "infrared",
|
||||
"lfrfid",
|
||||
# "nfc",
|
||||
"subghz",
|
||||
# "bad_usb",
|
||||
# "u2f",
|
||||
"archive",
|
||||
"ibutton_start",
|
||||
"onewire_start",
|
||||
"subghz_start",
|
||||
"infrared_start",
|
||||
"lfrfid_start",
|
||||
"nfc_start",
|
||||
],
|
||||
)
|
||||
|
@ -5,13 +5,14 @@
|
||||
#include "../helpers/archive_browser.h"
|
||||
#include "../views/archive_browser_view.h"
|
||||
#include "archive/scenes/archive_scene.h"
|
||||
#include <applications.h>
|
||||
|
||||
#define TAG "ArchiveSceneBrowser"
|
||||
|
||||
#define SCENE_STATE_DEFAULT (0)
|
||||
#define SCENE_STATE_NEED_REFRESH (1)
|
||||
|
||||
const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) {
|
||||
static const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) {
|
||||
switch(file_type) {
|
||||
case ArchiveFileTypeIButton:
|
||||
return "iButton";
|
||||
|
@ -1,15 +1,12 @@
|
||||
App(
|
||||
appid="bad_usb",
|
||||
name="Bad USB",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
entry_point="bad_usb_app",
|
||||
cdefines=["APP_BAD_USB"],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
icon="A_BadUsb_14",
|
||||
order=70,
|
||||
fap_libs=["assets"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="USB",
|
||||
)
|
||||
|
BIN
applications/main/bad_usb/icon.png
Normal file
After Width: | Height: | Size: 576 B |
@ -1,12 +1,11 @@
|
||||
App(
|
||||
appid="clock",
|
||||
name="Clock",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
entry_point="clock_app",
|
||||
cdefines=["APP_CLOCK"],
|
||||
requires=["gui"],
|
||||
icon="A_Clock_14",
|
||||
stack_size=2 * 1024,
|
||||
order=81,
|
||||
fap_icon="icon.png",
|
||||
fap_category="Tools",
|
||||
)
|
||||
|
||||
|
BIN
applications/main/clock_app/icon.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
@ -1,12 +1,12 @@
|
||||
App(
|
||||
appid="gpio",
|
||||
name="GPIO",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
entry_point="gpio_app",
|
||||
cdefines=["APP_GPIO"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
icon="A_GPIO_14",
|
||||
order=50,
|
||||
fap_libs=["assets"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="GPIO",
|
||||
)
|
||||
|
BIN
applications/main/gpio/icon.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
@ -1,25 +1,21 @@
|
||||
App(
|
||||
appid="ibutton",
|
||||
name="iButton",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
targets=["f7"],
|
||||
entry_point="ibutton_app",
|
||||
cdefines=["APP_IBUTTON"],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
provides=["ibutton_start"],
|
||||
icon="A_iButton_14",
|
||||
stack_size=2 * 1024,
|
||||
order=60,
|
||||
fap_libs=["assets"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="iButton",
|
||||
)
|
||||
|
||||
App(
|
||||
appid="ibutton_start",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
targets=["f7"],
|
||||
entry_point="ibutton_on_system_start",
|
||||
requires=["ibutton"],
|
||||
order=60,
|
||||
)
|
||||
|
BIN
applications/main/ibutton/icon.png
Normal file
After Width: | Height: | Size: 304 B |
@ -1,25 +1,21 @@
|
||||
App(
|
||||
appid="infrared",
|
||||
name="Infrared",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
entry_point="infrared_app",
|
||||
targets=["f7"],
|
||||
cdefines=["APP_INFRARED"],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
provides=["infrared_start"],
|
||||
icon="A_Infrared_14",
|
||||
stack_size=3 * 1024,
|
||||
order=40,
|
||||
fap_libs=["assets"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="Infrared",
|
||||
)
|
||||
|
||||
App(
|
||||
appid="infrared_start",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
targets=["f7"],
|
||||
entry_point="infrared_on_system_start",
|
||||
requires=["infrared"],
|
||||
order=20,
|
||||
)
|
||||
|
BIN
applications/main/infrared/icon.png
Normal file
After Width: | Height: | Size: 305 B |
@ -1,27 +1,21 @@
|
||||
App(
|
||||
appid="lfrfid",
|
||||
name="125 kHz RFID",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
targets=["f7"],
|
||||
entry_point="lfrfid_app",
|
||||
cdefines=["APP_LF_RFID"],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
provides=[
|
||||
"lfrfid_start",
|
||||
],
|
||||
icon="A_125khz_14",
|
||||
stack_size=2 * 1024,
|
||||
order=20,
|
||||
fap_libs=["assets"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="RFID",
|
||||
)
|
||||
|
||||
App(
|
||||
appid="lfrfid_start",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="lfrfid_on_system_start",
|
||||
requires=["lfrfid"],
|
||||
order=50,
|
||||
)
|
||||
|
BIN
applications/main/lfrfid/icon.png
Normal file
After Width: | Height: | Size: 308 B |
@ -1,24 +1,21 @@
|
||||
App(
|
||||
appid="nfc",
|
||||
name="NFC",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
targets=["f7"],
|
||||
entry_point="nfc_app",
|
||||
cdefines=["APP_NFC"],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
provides=["nfc_start"],
|
||||
icon="A_NFC_14",
|
||||
stack_size=5 * 1024,
|
||||
order=30,
|
||||
fap_libs=["assets"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="NFC",
|
||||
)
|
||||
|
||||
App(
|
||||
appid="nfc_start",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="nfc_on_system_start",
|
||||
requires=["nfc"],
|
||||
order=30,
|
||||
)
|
||||
|
BIN
applications/main/nfc/icon.png
Normal file
After Width: | Height: | Size: 304 B |
@ -1,14 +1,6 @@
|
||||
App(
|
||||
appid="onewire",
|
||||
name="1-Wire",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=["onewire_start"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="onewire_start",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="onewire_on_system_start",
|
||||
requires=["onewire"],
|
||||
order=60,
|
||||
)
|
||||
|
@ -1,10 +1,9 @@
|
||||
App(
|
||||
appid="subghz",
|
||||
name="Sub-GHz",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
targets=["f7"],
|
||||
entry_point="subghz_app",
|
||||
cdefines=["APP_SUBGHZ"],
|
||||
requires=[
|
||||
"gui",
|
||||
"cli",
|
||||
@ -17,13 +16,16 @@ App(
|
||||
icon="A_Sub1ghz_14",
|
||||
stack_size=3 * 1024,
|
||||
order=10,
|
||||
fap_libs=["assets", "hwdrivers"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="Sub-GHz",
|
||||
)
|
||||
|
||||
App(
|
||||
appid="subghz_start",
|
||||
targets=["f7"],
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="subghz_on_system_start",
|
||||
requires=["subghz"],
|
||||
order=40,
|
||||
)
|
||||
|
||||
|
BIN
applications/main/subghz/icon.png
Normal file
After Width: | Height: | Size: 299 B |
@ -1,17 +1,12 @@
|
||||
App(
|
||||
appid="subghz_remote",
|
||||
name="Sub-GHz Remote",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
entry_point="subghz_remote_app",
|
||||
cdefines=[
|
||||
"APP_SUBGHZREMOTE",
|
||||
"SUBREM_LIGHT",
|
||||
],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
icon="A_SubGHzRemote_14",
|
||||
stack_size=2 * 1024,
|
||||
order=11,
|
||||
)
|
||||
fap_libs=["assets",],
|
||||
fap_icon="icon.png",
|
||||
fap_category="Sub-Ghz",
|
||||
)
|
||||
|
571
applications/main/subghz_remote/helpers/txrx/subghz_txrx.c
Normal file
@ -0,0 +1,571 @@
|
||||
#include "subghz_txrx_i.h"
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
#include <lib/subghz/blocks/custom_btn.h>
|
||||
|
||||
#define TAG "SubGhz"
|
||||
|
||||
SubGhzTxRx* subghz_txrx_alloc() {
|
||||
SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx));
|
||||
instance->setting = subghz_setting_alloc();
|
||||
subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user"));
|
||||
|
||||
instance->preset = malloc(sizeof(SubGhzRadioPreset));
|
||||
instance->preset->name = furi_string_alloc();
|
||||
subghz_txrx_set_preset(
|
||||
instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0);
|
||||
|
||||
instance->txrx_state = SubGhzTxRxStateSleep;
|
||||
|
||||
subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF);
|
||||
subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable);
|
||||
subghz_txrx_set_debug_pin_state(instance, false);
|
||||
|
||||
instance->worker = subghz_worker_alloc();
|
||||
instance->fff_data = flipper_format_string_alloc();
|
||||
|
||||
instance->environment = subghz_environment_alloc();
|
||||
instance->is_database_loaded = subghz_environment_load_keystore(
|
||||
instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes"));
|
||||
subghz_environment_load_keystore(
|
||||
instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"));
|
||||
subghz_environment_set_came_atomo_rainbow_table_file_name(
|
||||
instance->environment, EXT_PATH("subghz/assets/came_atomo"));
|
||||
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
||||
instance->environment, EXT_PATH("subghz/assets/alutech_at_4n"));
|
||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||
instance->environment, EXT_PATH("subghz/assets/nice_flor_s"));
|
||||
subghz_environment_set_protocol_registry(
|
||||
instance->environment, (void*)&subghz_protocol_registry);
|
||||
instance->receiver = subghz_receiver_alloc_init(instance->environment);
|
||||
|
||||
subghz_worker_set_overrun_callback(
|
||||
instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
|
||||
subghz_worker_set_pair_callback(
|
||||
instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
|
||||
subghz_worker_set_context(instance->worker, instance->receiver);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_txrx_free(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
subghz_worker_free(instance->worker);
|
||||
subghz_receiver_free(instance->receiver);
|
||||
subghz_environment_free(instance->environment);
|
||||
flipper_format_free(instance->fff_data);
|
||||
furi_string_free(instance->preset->name);
|
||||
subghz_setting_free(instance->setting);
|
||||
free(instance->preset);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->is_database_loaded;
|
||||
}
|
||||
|
||||
void subghz_txrx_set_preset(
|
||||
SubGhzTxRx* instance,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint8_t* preset_data,
|
||||
size_t preset_data_size) {
|
||||
furi_assert(instance);
|
||||
furi_string_set(instance->preset->name, preset_name);
|
||||
SubGhzRadioPreset* preset = instance->preset;
|
||||
preset->frequency = frequency;
|
||||
preset->data = preset_data;
|
||||
preset->data_size = preset_data_size;
|
||||
}
|
||||
|
||||
const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) {
|
||||
UNUSED(instance);
|
||||
const char* preset_name = "";
|
||||
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
|
||||
preset_name = "AM270";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
|
||||
preset_name = "AM650";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
||||
preset_name = "FM238";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
||||
preset_name = "FM476";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
|
||||
preset_name = "CUSTOM";
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown preset");
|
||||
}
|
||||
return preset_name;
|
||||
}
|
||||
|
||||
SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return *instance->preset;
|
||||
}
|
||||
|
||||
void subghz_txrx_get_frequency_and_modulation(
|
||||
SubGhzTxRx* instance,
|
||||
FuriString* frequency,
|
||||
FuriString* modulation,
|
||||
bool long_name) {
|
||||
furi_assert(instance);
|
||||
SubGhzRadioPreset* preset = instance->preset;
|
||||
if(frequency != NULL) {
|
||||
furi_string_printf(
|
||||
frequency,
|
||||
"%03ld.%02ld",
|
||||
preset->frequency / 1000000 % 1000,
|
||||
preset->frequency / 10000 % 100);
|
||||
}
|
||||
if(modulation != NULL) {
|
||||
if(long_name) {
|
||||
furi_string_printf(modulation, "%s", furi_string_get_cstr(preset->name));
|
||||
} else {
|
||||
furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) {
|
||||
furi_assert(instance);
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_idle();
|
||||
furi_hal_subghz_load_custom_preset(preset_data);
|
||||
furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
instance->txrx_state = SubGhzTxRxStateIDLE;
|
||||
}
|
||||
|
||||
static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) {
|
||||
furi_assert(instance);
|
||||
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
||||
furi_crash("SubGhz: Incorrect RX frequency.");
|
||||
}
|
||||
furi_assert(
|
||||
instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep);
|
||||
|
||||
furi_hal_subghz_idle();
|
||||
uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
|
||||
furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_subghz_flush_rx();
|
||||
subghz_txrx_speaker_on(instance);
|
||||
furi_hal_subghz_rx();
|
||||
|
||||
furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker);
|
||||
subghz_worker_start(instance->worker);
|
||||
instance->txrx_state = SubGhzTxRxStateRx;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void subghz_txrx_idle(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
|
||||
furi_hal_subghz_idle();
|
||||
subghz_txrx_speaker_off(instance);
|
||||
instance->txrx_state = SubGhzTxRxStateIDLE;
|
||||
}
|
||||
|
||||
static void subghz_txrx_rx_end(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->txrx_state == SubGhzTxRxStateRx);
|
||||
|
||||
if(subghz_worker_is_running(instance->worker)) {
|
||||
subghz_worker_stop(instance->worker);
|
||||
furi_hal_subghz_stop_async_rx();
|
||||
}
|
||||
furi_hal_subghz_idle();
|
||||
subghz_txrx_speaker_off(instance);
|
||||
instance->txrx_state = SubGhzTxRxStateIDLE;
|
||||
}
|
||||
|
||||
void subghz_txrx_sleep(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
furi_hal_subghz_sleep();
|
||||
instance->txrx_state = SubGhzTxRxStateSleep;
|
||||
}
|
||||
|
||||
static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) {
|
||||
furi_assert(instance);
|
||||
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
||||
furi_crash("SubGhz: Incorrect TX frequency.");
|
||||
}
|
||||
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
|
||||
furi_hal_subghz_idle();
|
||||
furi_hal_subghz_set_frequency_and_path(frequency);
|
||||
furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false);
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
bool ret = furi_hal_subghz_tx();
|
||||
if(ret) {
|
||||
subghz_txrx_speaker_on(instance);
|
||||
instance->txrx_state = SubGhzTxRxStateTx;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) {
|
||||
furi_assert(instance);
|
||||
furi_assert(flipper_format);
|
||||
|
||||
subghz_txrx_stop(instance);
|
||||
|
||||
SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
uint32_t repeat = 200;
|
||||
do {
|
||||
if(!flipper_format_rewind(flipper_format)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing Protocol");
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
|
||||
FURI_LOG_E(TAG, "Unable Repeat");
|
||||
break;
|
||||
}
|
||||
ret = SubGhzTxRxStartTxStateOk;
|
||||
|
||||
SubGhzRadioPreset* preset = instance->preset;
|
||||
instance->transmitter =
|
||||
subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str));
|
||||
|
||||
if(instance->transmitter) {
|
||||
if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) ==
|
||||
SubGhzProtocolStatusOk) {
|
||||
if(strcmp(furi_string_get_cstr(preset->name), "") != 0) {
|
||||
subghz_txrx_begin(
|
||||
instance,
|
||||
subghz_setting_get_preset_data_by_name(
|
||||
instance->setting, furi_string_get_cstr(preset->name)));
|
||||
if(preset->frequency) {
|
||||
if(!subghz_txrx_tx(instance, preset->frequency)) {
|
||||
FURI_LOG_E(TAG, "Only Rx");
|
||||
ret = SubGhzTxRxStartTxStateErrorOnlyRx;
|
||||
}
|
||||
} else {
|
||||
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
}
|
||||
|
||||
} else {
|
||||
FURI_LOG_E(
|
||||
TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name));
|
||||
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
}
|
||||
|
||||
if(ret == SubGhzTxRxStartTxStateOk) {
|
||||
//Start TX
|
||||
furi_hal_subghz_start_async_tx(
|
||||
subghz_transmitter_yield, instance->transmitter);
|
||||
}
|
||||
} else {
|
||||
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
}
|
||||
} else {
|
||||
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
}
|
||||
if(ret != SubGhzTxRxStartTxStateOk) {
|
||||
subghz_transmitter_free(instance->transmitter);
|
||||
if(instance->txrx_state != SubGhzTxRxStateIDLE) {
|
||||
subghz_txrx_idle(instance);
|
||||
}
|
||||
}
|
||||
|
||||
} while(false);
|
||||
furi_string_free(temp_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subghz_txrx_rx_start(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
subghz_txrx_stop(instance);
|
||||
subghz_txrx_begin(
|
||||
instance,
|
||||
subghz_setting_get_preset_data_by_name(
|
||||
subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name)));
|
||||
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||
}
|
||||
|
||||
void subghz_txrx_set_need_save_callback(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzTxRxNeedSaveCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
instance->need_save_callback = callback;
|
||||
instance->need_save_context = context;
|
||||
}
|
||||
|
||||
static void subghz_txrx_tx_stop(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->txrx_state == SubGhzTxRxStateTx);
|
||||
//Stop TX
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
subghz_transmitter_stop(instance->transmitter);
|
||||
subghz_transmitter_free(instance->transmitter);
|
||||
|
||||
//if protocol dynamic then we save the last upload
|
||||
if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) {
|
||||
if(instance->need_save_callback) {
|
||||
instance->need_save_callback(instance->need_save_context);
|
||||
}
|
||||
}
|
||||
subghz_txrx_idle(instance);
|
||||
subghz_txrx_speaker_off(instance);
|
||||
//Todo: Show message
|
||||
// notification_message(notifications, &sequence_reset_red);
|
||||
}
|
||||
|
||||
FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->fff_data;
|
||||
}
|
||||
|
||||
SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->setting;
|
||||
}
|
||||
|
||||
void subghz_txrx_stop(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
switch(instance->txrx_state) {
|
||||
case SubGhzTxRxStateTx:
|
||||
subghz_txrx_tx_stop(instance);
|
||||
subghz_txrx_speaker_unmute(instance);
|
||||
break;
|
||||
case SubGhzTxRxStateRx:
|
||||
subghz_txrx_rx_end(instance);
|
||||
subghz_txrx_speaker_mute(instance);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
switch(instance->hopper_state) {
|
||||
case SubGhzHopperStateOFF:
|
||||
case SubGhzHopperStatePause:
|
||||
return;
|
||||
case SubGhzHopperStateRSSITimeOut:
|
||||
if(instance->hopper_timeout != 0) {
|
||||
instance->hopper_timeout--;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
float rssi = -127.0f;
|
||||
if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) {
|
||||
// See RSSI Calculation timings in CC1101 17.3 RSSI
|
||||
rssi = furi_hal_subghz_get_rssi();
|
||||
|
||||
// Stay if RSSI is high enough
|
||||
if(rssi > -90.0f) {
|
||||
instance->hopper_timeout = 10;
|
||||
instance->hopper_state = SubGhzHopperStateRSSITimeOut;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
instance->hopper_state = SubGhzHopperStateRunning;
|
||||
}
|
||||
// Select next frequency
|
||||
if(instance->hopper_idx_frequency <
|
||||
subghz_setting_get_hopper_frequency_count(instance->setting) - 1) {
|
||||
instance->hopper_idx_frequency++;
|
||||
} else {
|
||||
instance->hopper_idx_frequency = 0;
|
||||
}
|
||||
|
||||
if(instance->txrx_state == SubGhzTxRxStateRx) {
|
||||
subghz_txrx_rx_end(instance);
|
||||
};
|
||||
if(instance->txrx_state == SubGhzTxRxStateIDLE) {
|
||||
subghz_receiver_reset(instance->receiver);
|
||||
instance->preset->frequency =
|
||||
subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency);
|
||||
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||
}
|
||||
}
|
||||
|
||||
SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->hopper_state;
|
||||
}
|
||||
|
||||
void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) {
|
||||
furi_assert(instance);
|
||||
instance->hopper_state = state;
|
||||
}
|
||||
|
||||
void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->hopper_state == SubGhzHopperStatePause) {
|
||||
instance->hopper_state = SubGhzHopperStateRunning;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_hopper_pause(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->hopper_state == SubGhzHopperStateRunning) {
|
||||
instance->hopper_state = SubGhzHopperStatePause;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_on(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton);
|
||||
}
|
||||
|
||||
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
if(furi_hal_speaker_acquire(30)) {
|
||||
if(!instance->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
|
||||
}
|
||||
} else {
|
||||
instance->speaker_state = SubGhzSpeakerStateDisable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_off(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(NULL);
|
||||
}
|
||||
if(instance->speaker_state != SubGhzSpeakerStateDisable) {
|
||||
if(furi_hal_speaker_is_mine()) {
|
||||
if(!instance->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(NULL);
|
||||
}
|
||||
furi_hal_speaker_release();
|
||||
if(instance->speaker_state == SubGhzSpeakerStateShutdown)
|
||||
instance->speaker_state = SubGhzSpeakerStateDisable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_mute(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(NULL);
|
||||
}
|
||||
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
if(furi_hal_speaker_is_mine()) {
|
||||
if(!instance->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton);
|
||||
}
|
||||
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
if(furi_hal_speaker_is_mine()) {
|
||||
if(!instance->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) {
|
||||
furi_assert(instance);
|
||||
instance->speaker_state = state;
|
||||
}
|
||||
|
||||
SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->speaker_state;
|
||||
}
|
||||
|
||||
bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) {
|
||||
furi_assert(instance);
|
||||
furi_assert(name_protocol);
|
||||
bool res = false;
|
||||
instance->decoder_result =
|
||||
subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol);
|
||||
if(instance->decoder_result) {
|
||||
res = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->decoder_result;
|
||||
}
|
||||
|
||||
bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return (
|
||||
(instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
|
||||
SubGhzProtocolFlag_Save);
|
||||
}
|
||||
|
||||
bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) {
|
||||
furi_assert(instance);
|
||||
const SubGhzProtocol* protocol = instance->decoder_result->protocol;
|
||||
if(check_type) {
|
||||
return (
|
||||
((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
|
||||
protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic);
|
||||
}
|
||||
return (
|
||||
((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
|
||||
protocol->encoder->deserialize);
|
||||
}
|
||||
|
||||
void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) {
|
||||
furi_assert(instance);
|
||||
subghz_receiver_set_filter(instance->receiver, filter);
|
||||
}
|
||||
|
||||
void subghz_txrx_set_rx_calback(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzReceiverCallback callback,
|
||||
void* context) {
|
||||
subghz_receiver_set_rx_callback(instance->receiver, callback, context);
|
||||
}
|
||||
|
||||
void subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzProtocolEncoderRAWCallbackEnd callback,
|
||||
void* context) {
|
||||
subghz_protocol_raw_file_encoder_worker_set_callback_end(
|
||||
(SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter),
|
||||
callback,
|
||||
context);
|
||||
}
|
||||
|
||||
void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state) {
|
||||
furi_assert(instance);
|
||||
instance->debug_pin_state = state;
|
||||
}
|
||||
|
||||
bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->debug_pin_state;
|
||||
}
|
||||
|
||||
void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
subghz_environment_reset_keeloq(instance->environment);
|
||||
|
||||
subghz_custom_btns_reset();
|
||||
}
|
||||
|
||||
SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->receiver;
|
||||
}
|
@ -1,3 +1,320 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../../subghz/helpers/subghz_txrx.h"
|
||||
#include <lib/subghz/subghz_worker.h>
|
||||
#include <lib/subghz/subghz_setting.h>
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/transmitter.h>
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
|
||||
typedef struct SubGhzTxRx SubGhzTxRx;
|
||||
|
||||
typedef void (*SubGhzTxRxNeedSaveCallback)(void* context);
|
||||
|
||||
typedef enum {
|
||||
SubGhzTxRxStartTxStateOk,
|
||||
SubGhzTxRxStartTxStateErrorOnlyRx,
|
||||
SubGhzTxRxStartTxStateErrorParserOthers,
|
||||
} SubGhzTxRxStartTxState;
|
||||
|
||||
// Type from subghz_types.h need for txrx working
|
||||
/** SubGhzTxRx state */
|
||||
typedef enum {
|
||||
SubGhzTxRxStateIDLE,
|
||||
SubGhzTxRxStateRx,
|
||||
SubGhzTxRxStateTx,
|
||||
SubGhzTxRxStateSleep,
|
||||
} SubGhzTxRxState;
|
||||
|
||||
/** SubGhzHopperState state */
|
||||
typedef enum {
|
||||
SubGhzHopperStateOFF,
|
||||
SubGhzHopperStateRunning,
|
||||
SubGhzHopperStatePause,
|
||||
SubGhzHopperStateRSSITimeOut,
|
||||
} SubGhzHopperState;
|
||||
|
||||
/** SubGhzSpeakerState state */
|
||||
typedef enum {
|
||||
SubGhzSpeakerStateDisable,
|
||||
SubGhzSpeakerStateShutdown,
|
||||
SubGhzSpeakerStateEnable,
|
||||
} SubGhzSpeakerState;
|
||||
|
||||
/**
|
||||
* Allocate SubGhzTxRx
|
||||
*
|
||||
* @return SubGhzTxRx* pointer to SubGhzTxRx
|
||||
*/
|
||||
SubGhzTxRx* subghz_txrx_alloc();
|
||||
|
||||
/**
|
||||
* Free SubGhzTxRx
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_free(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Check if the database is loaded
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return bool True if the database is loaded
|
||||
*/
|
||||
bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set preset
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param preset_name Name of preset
|
||||
* @param frequency Frequency in Hz
|
||||
* @param preset_data Data of preset
|
||||
* @param preset_data_size Size of preset data
|
||||
*/
|
||||
void subghz_txrx_set_preset(
|
||||
SubGhzTxRx* instance,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint8_t* preset_data,
|
||||
size_t preset_data_size);
|
||||
|
||||
/**
|
||||
* Get name of preset
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param preset String of preset
|
||||
* @return const char* Name of preset
|
||||
*/
|
||||
const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset);
|
||||
|
||||
/**
|
||||
* Get of preset
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzRadioPreset Preset
|
||||
*/
|
||||
SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Get string frequency and modulation
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param frequency Pointer to a string frequency
|
||||
* @param modulation Pointer to a string modulation
|
||||
*/
|
||||
void subghz_txrx_get_frequency_and_modulation(
|
||||
SubGhzTxRx* instance,
|
||||
FuriString* frequency,
|
||||
FuriString* modulation,
|
||||
bool long_name);
|
||||
|
||||
/**
|
||||
* Start TX CC1101
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param flipper_format Pointer to a FlipperFormat
|
||||
* @return SubGhzTxRxStartTxState
|
||||
*/
|
||||
SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format);
|
||||
|
||||
/**
|
||||
* Start RX CC1101
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_rx_start(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Stop TX/RX CC1101
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_stop(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set sleep mode CC1101
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_sleep(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Update frequency CC1101 in automatic mode (hopper)
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_hopper_update(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Get state hopper
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzHopperState
|
||||
*/
|
||||
SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set state hopper
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param state State hopper
|
||||
*/
|
||||
void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state);
|
||||
|
||||
/**
|
||||
* Unpause hopper
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_hopper_unpause(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set pause hopper
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_hopper_pause(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Speaker on
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_speaker_on(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Speaker off
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_speaker_off(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Speaker mute
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_speaker_mute(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Speaker unmute
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_speaker_unmute(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set state speaker
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param state State speaker
|
||||
*/
|
||||
void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state);
|
||||
|
||||
/**
|
||||
* Get state speaker
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzSpeakerState
|
||||
*/
|
||||
SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* load decoder by name protocol
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param name_protocol Name protocol
|
||||
* @return bool True if the decoder is loaded
|
||||
*/
|
||||
bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol);
|
||||
|
||||
/**
|
||||
* Get decoder
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase
|
||||
*/
|
||||
SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set callback for save data
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param callback Callback for save data
|
||||
* @param context Context for callback
|
||||
*/
|
||||
void subghz_txrx_set_need_save_callback(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzTxRxNeedSaveCallback callback,
|
||||
void* context);
|
||||
|
||||
/**
|
||||
* Get pointer to a load data key
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return FlipperFormat*
|
||||
*/
|
||||
FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Get pointer to a SugGhzSetting
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzSetting*
|
||||
*/
|
||||
SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Is it possible to save this protocol
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return bool True if it is possible to save this protocol
|
||||
*/
|
||||
bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Is it possible to send this protocol
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return bool True if it is possible to send this protocol
|
||||
*/
|
||||
bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type);
|
||||
|
||||
/**
|
||||
* Set filter, what types of decoder to use
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param filter Filter
|
||||
*/
|
||||
void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter);
|
||||
|
||||
/**
|
||||
* Set callback for receive data
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param callback Callback for receive data
|
||||
* @param context Context for callback
|
||||
*/
|
||||
void subghz_txrx_set_rx_calback(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzReceiverCallback callback,
|
||||
void* context);
|
||||
|
||||
/**
|
||||
* Set callback for Raw decoder, end of data transfer
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param callback Callback for Raw decoder, end of data transfer
|
||||
* @param context Context for callback
|
||||
*/
|
||||
void subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzProtocolEncoderRAWCallbackEnd callback,
|
||||
void* context);
|
||||
|
||||
void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state);
|
||||
bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance);
|
||||
|
||||
void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance);
|
||||
|
||||
SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance); // TODO use only in DecodeRaw
|
||||
|
29
applications/main/subghz_remote/helpers/txrx/subghz_txrx_i.h
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
#pragma once
|
||||
#include "subghz_txrx.h"
|
||||
|
||||
struct SubGhzTxRx {
|
||||
SubGhzWorker* worker;
|
||||
|
||||
SubGhzEnvironment* environment;
|
||||
SubGhzReceiver* receiver;
|
||||
SubGhzTransmitter* transmitter;
|
||||
SubGhzProtocolDecoderBase* decoder_result;
|
||||
FlipperFormat* fff_data;
|
||||
|
||||
SubGhzRadioPreset* preset;
|
||||
SubGhzSetting* setting;
|
||||
|
||||
uint8_t hopper_timeout;
|
||||
uint8_t hopper_idx_frequency;
|
||||
bool is_database_loaded;
|
||||
SubGhzHopperState hopper_state;
|
||||
|
||||
SubGhzTxRxState txrx_state;
|
||||
SubGhzSpeakerState speaker_state;
|
||||
|
||||
SubGhzTxRxNeedSaveCallback need_save_callback;
|
||||
void* need_save_context;
|
||||
|
||||
bool debug_pin_state;
|
||||
};
|
BIN
applications/main/subghz_remote/icon.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#define SUBREM_LIGHT 1
|
||||
#define APP_SUBGHZREMOTE 1
|
||||
|
||||
#include "helpers/subrem_types.h"
|
||||
#include "helpers/subrem_presets.h"
|
||||
#include "scenes/subrem_scene.h"
|
||||
|
@ -1,15 +1,12 @@
|
||||
App(
|
||||
appid="u2f",
|
||||
name="U2F",
|
||||
apptype=FlipperAppType.APP,
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
entry_point="u2f_app",
|
||||
cdefines=["APP_U2F"],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
icon="A_U2F_14",
|
||||
order=80,
|
||||
fap_libs=["assets"],
|
||||
fap_category="USB",
|
||||
fap_icon="icon.png",
|
||||
)
|
||||
|
BIN
applications/main/u2f/icon.png
Normal file
After Width: | Height: | Size: 583 B |
@ -17,6 +17,12 @@ typedef struct {
|
||||
const FlipperInternalApplicationFlag flags;
|
||||
} FlipperInternalApplication;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const Icon* icon;
|
||||
const char* path;
|
||||
} FlipperExternalApplication;
|
||||
|
||||
typedef void (*FlipperInternalOnStartHook)(void);
|
||||
|
||||
extern const char* FLIPPER_AUTORUN_APP_NAME;
|
||||
@ -52,3 +58,9 @@ extern const FlipperInternalApplication FLIPPER_ARCHIVE;
|
||||
*/
|
||||
extern const FlipperInternalApplication FLIPPER_SETTINGS_APPS[];
|
||||
extern const size_t FLIPPER_SETTINGS_APPS_COUNT;
|
||||
|
||||
/* External Menu Apps list
|
||||
* Spawned by loader
|
||||
*/
|
||||
extern const FlipperExternalApplication FLIPPER_EXTERNAL_APPS[];
|
||||
extern const size_t FLIPPER_EXTERNAL_APPS_COUNT;
|
||||
|
@ -170,6 +170,16 @@ static const FlipperInternalApplication* loader_find_application_by_name(const c
|
||||
return application;
|
||||
}
|
||||
|
||||
static const char* loader_find_external_application_by_name(const char* app_name) {
|
||||
for(size_t i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT; i++) {
|
||||
if(strcmp(FLIPPER_EXTERNAL_APPS[i].name, app_name) == 0) {
|
||||
return FLIPPER_EXTERNAL_APPS[i].path;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void loader_start_app_thread(Loader* loader, FlipperInternalApplicationFlag flags) {
|
||||
// setup heap trace
|
||||
FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode();
|
||||
@ -411,6 +421,14 @@ static LoaderStatus loader_do_start_by_name(
|
||||
break;
|
||||
}
|
||||
|
||||
// check External Applications
|
||||
{
|
||||
const char* path = loader_find_external_application_by_name(name);
|
||||
if(path) {
|
||||
name = path;
|
||||
}
|
||||
}
|
||||
|
||||
// check external apps
|
||||
{
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
@ -52,12 +52,18 @@ static void loader_menu_start(const char* name) {
|
||||
furi_record_close(RECORD_LOADER);
|
||||
}
|
||||
|
||||
static void loader_menu_callback(void* context, uint32_t index) {
|
||||
static void loader_menu_apps_callback(void* context, uint32_t index) {
|
||||
UNUSED(context);
|
||||
const char* name = FLIPPER_APPS[index].name;
|
||||
loader_menu_start(name);
|
||||
}
|
||||
|
||||
static void loader_menu_external_apps_callback(void* context, uint32_t index) {
|
||||
UNUSED(context);
|
||||
const char* path = FLIPPER_EXTERNAL_APPS[index].path;
|
||||
loader_menu_start(path);
|
||||
}
|
||||
|
||||
static void loader_menu_applications_callback(void* context, uint32_t index) {
|
||||
UNUSED(index);
|
||||
UNUSED(context);
|
||||
@ -89,13 +95,24 @@ static uint32_t loader_menu_exit(void* context) {
|
||||
|
||||
static void loader_menu_build_menu(LoaderMenuApp* app, LoaderMenu* menu) {
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT; i++) {
|
||||
menu_add_item(
|
||||
app->primary_menu,
|
||||
FLIPPER_EXTERNAL_APPS[i].name,
|
||||
FLIPPER_EXTERNAL_APPS[i].icon,
|
||||
i,
|
||||
loader_menu_external_apps_callback,
|
||||
(void*)menu);
|
||||
}
|
||||
|
||||
for(i = 0; i < FLIPPER_APPS_COUNT; i++) {
|
||||
menu_add_item(
|
||||
app->primary_menu,
|
||||
FLIPPER_APPS[i].name,
|
||||
FLIPPER_APPS[i].icon,
|
||||
i,
|
||||
loader_menu_callback,
|
||||
loader_menu_apps_callback,
|
||||
(void*)menu);
|
||||
}
|
||||
menu_add_item(
|
||||
|
@ -113,7 +113,9 @@ static DialogMessageButton icon1_screen(DialogsApp* dialogs, DialogMessage* mess
|
||||
static DialogMessageButton icon2_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
|
||||
dialog_message_set_icon(message, &I_Certification2_98x33, 15, 10);
|
||||
dialog_message_set_icon(message, &I_Certification2_46x33, 15, 10);
|
||||
dialog_message_set_text(
|
||||
message, furi_hal_version_get_mic_id(), 63, 27, AlignLeft, AlignCenter);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_icon(message, NULL, 0, 0);
|
||||
|
||||
|
BIN
assets/icons/About/Certification2_46x33.png
Normal file
After Width: | Height: | Size: 229 B |
Before Width: | Height: | Size: 2.4 KiB |
@ -31,11 +31,9 @@ Check out `documentation/fbt.md` for details on building and flashing firmware.
|
||||
|
||||
### Compile everything for development
|
||||
|
||||
Edit this file to enable/disable Main apps that you need in DEBUG mode, flash space doesn't allows us to fit them all in DEBUG currently
|
||||
- `applications/main/application.fam`
|
||||
|
||||
```sh
|
||||
./fbt FIRMWARE_APP_SET=debug_pack updater_package
|
||||
./fbt updater_package
|
||||
```
|
||||
|
||||
### Compile everything for release + get updater package to update from microSD card
|
||||
@ -55,11 +53,9 @@ Check out `documentation/fbt.md` for details on building and flashing firmware.
|
||||
|
||||
### Compile everything for development
|
||||
|
||||
Edit this file to enable/disable Main apps that you need in DEBUG mode, flash space doesn't allows us to fit them all in DEBUG currently
|
||||
- `applications/main/application.fam`
|
||||
|
||||
```sh
|
||||
./fbt.cmd FIRMWARE_APP_SET=debug_pack updater_package
|
||||
./fbt.cmd updater_package
|
||||
```
|
||||
|
||||
### Compile everything for release + get updater package to update from microSD card
|
||||
|
@ -74,19 +74,6 @@ FIRMWARE_APPS = {
|
||||
"updater_app",
|
||||
"unit_tests",
|
||||
],
|
||||
"debug_pack": [
|
||||
# Svc
|
||||
"basic_services",
|
||||
# Apps
|
||||
"main_apps_default",
|
||||
"system_apps",
|
||||
# Settings
|
||||
"settings_apps",
|
||||
# Plugins
|
||||
# "basic_plugins",
|
||||
# Debug
|
||||
# "debug_apps",
|
||||
],
|
||||
}
|
||||
|
||||
FIRMWARE_APP_SET = "default"
|
||||
|
@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,33.1,,
|
||||
Version,+,34.0,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
@ -1262,6 +1262,7 @@ Function,+,furi_hal_version_get_hw_target,uint8_t,
|
||||
Function,+,furi_hal_version_get_hw_timestamp,uint32_t,
|
||||
Function,+,furi_hal_version_get_hw_version,uint8_t,
|
||||
Function,+,furi_hal_version_get_ic_id,const char*,
|
||||
Function,+,furi_hal_version_get_mic_id,const char*,
|
||||
Function,+,furi_hal_version_get_model_code,const char*,
|
||||
Function,+,furi_hal_version_get_model_name,const char*,
|
||||
Function,+,furi_hal_version_get_name_ptr,const char*,
|
||||
|
|
@ -5,17 +5,21 @@ bool furi_hal_version_do_i_belong_here() {
|
||||
}
|
||||
|
||||
const char* furi_hal_version_get_model_name() {
|
||||
return "Komi";
|
||||
return "Flipper Nano";
|
||||
}
|
||||
|
||||
const char* furi_hal_version_get_model_code() {
|
||||
return "N/A";
|
||||
return "FN.1";
|
||||
}
|
||||
|
||||
const char* furi_hal_version_get_fcc_id() {
|
||||
return "N/A";
|
||||
return "Pending";
|
||||
}
|
||||
|
||||
const char* furi_hal_version_get_ic_id() {
|
||||
return "N/A";
|
||||
return "Pending";
|
||||
}
|
||||
|
||||
const char* furi_hal_version_get_mic_id() {
|
||||
return "Pending";
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,33.1,,
|
||||
Version,+,34.0,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
@ -147,7 +147,12 @@ Header,+,lib/mlib/m-rbtree.h,,
|
||||
Header,+,lib/mlib/m-tuple.h,,
|
||||
Header,+,lib/mlib/m-variant.h,,
|
||||
Header,+,lib/music_worker/music_worker.h,,
|
||||
Header,+,lib/nfc/helpers/mfkey32.h,,
|
||||
Header,+,lib/nfc/helpers/nfc_generators.h,,
|
||||
Header,+,lib/nfc/nfc_device.h,,
|
||||
Header,+,lib/nfc/nfc_types.h,,
|
||||
Header,+,lib/nfc/nfc_worker.h,,
|
||||
Header,+,lib/nfc/parsers/nfc_supported_card.h,,
|
||||
Header,+,lib/nfc/protocols/nfc_util.h,,
|
||||
Header,+,lib/one_wire/maxim_crc.h,,
|
||||
Header,+,lib/one_wire/one_wire_host.h,,
|
||||
@ -182,6 +187,7 @@ Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_usart.h,,
|
||||
Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_utils.h,,
|
||||
Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_wwdg.h,,
|
||||
Header,+,lib/subghz/blocks/const.h,,
|
||||
Header,+,lib/subghz/blocks/custom_btn.h,,
|
||||
Header,+,lib/subghz/blocks/decoder.h,,
|
||||
Header,+,lib/subghz/blocks/encoder.h,,
|
||||
Header,+,lib/subghz/blocks/generic.h,,
|
||||
@ -191,6 +197,7 @@ Header,+,lib/subghz/environment.h,,
|
||||
Header,+,lib/subghz/protocols/raw.h,,
|
||||
Header,+,lib/subghz/receiver.h,,
|
||||
Header,+,lib/subghz/registry.h,,
|
||||
Header,+,lib/subghz/subghz_file_encoder_worker.h,,
|
||||
Header,+,lib/subghz/subghz_protocol_registry.h,,
|
||||
Header,+,lib/subghz/subghz_setting.h,,
|
||||
Header,+,lib/subghz/subghz_tx_rx_worker.h,,
|
||||
@ -1410,9 +1417,9 @@ Function,+,furi_hal_subghz_rx_pipe_not_empty,_Bool,
|
||||
Function,+,furi_hal_subghz_set_async_mirror_pin,void,const GpioPin*
|
||||
Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t
|
||||
Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t
|
||||
Function,-,furi_hal_subghz_set_rolling_counter_mult,void,uint8_t
|
||||
Function,+,furi_hal_subghz_shutdown,void,
|
||||
Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath
|
||||
Function,+,furi_hal_subghz_set_rolling_counter_mult,void,uint8_t
|
||||
Function,+,furi_hal_subghz_shutdown,void,
|
||||
Function,+,furi_hal_subghz_sleep,void,
|
||||
Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*"
|
||||
Function,+,furi_hal_subghz_start_async_tx,_Bool,"FuriHalSubGhzAsyncTxCallback, void*"
|
||||
@ -1456,6 +1463,7 @@ Function,+,furi_hal_version_get_hw_target,uint8_t,
|
||||
Function,+,furi_hal_version_get_hw_timestamp,uint32_t,
|
||||
Function,+,furi_hal_version_get_hw_version,uint8_t,
|
||||
Function,+,furi_hal_version_get_ic_id,const char*,
|
||||
Function,+,furi_hal_version_get_mic_id,const char*,
|
||||
Function,+,furi_hal_version_get_model_code,const char*,
|
||||
Function,+,furi_hal_version_get_model_name,const char*,
|
||||
Function,+,furi_hal_version_get_name_ptr,const char*,
|
||||
@ -1967,40 +1975,40 @@ Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint6
|
||||
Function,-,mf_classic_authenticate_skip_activate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey, _Bool, uint32_t"
|
||||
Function,-,mf_classic_block_to_value,_Bool,"const uint8_t*, int32_t*, uint8_t*"
|
||||
Function,-,mf_classic_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t"
|
||||
Function,-,mf_classic_dict_add_key,_Bool,"MfClassicDict*, uint8_t*"
|
||||
Function,+,mf_classic_dict_add_key,_Bool,"MfClassicDict*, uint8_t*"
|
||||
Function,-,mf_classic_dict_add_key_str,_Bool,"MfClassicDict*, FuriString*"
|
||||
Function,-,mf_classic_dict_alloc,MfClassicDict*,MfClassicDictType
|
||||
Function,-,mf_classic_dict_check_presence,_Bool,MfClassicDictType
|
||||
Function,-,mf_classic_dict_delete_index,_Bool,"MfClassicDict*, uint32_t"
|
||||
Function,+,mf_classic_dict_alloc,MfClassicDict*,MfClassicDictType
|
||||
Function,+,mf_classic_dict_check_presence,_Bool,MfClassicDictType
|
||||
Function,+,mf_classic_dict_delete_index,_Bool,"MfClassicDict*, uint32_t"
|
||||
Function,-,mf_classic_dict_find_index,_Bool,"MfClassicDict*, uint8_t*, uint32_t*"
|
||||
Function,-,mf_classic_dict_find_index_str,_Bool,"MfClassicDict*, FuriString*, uint32_t*"
|
||||
Function,-,mf_classic_dict_free,void,MfClassicDict*
|
||||
Function,+,mf_classic_dict_free,void,MfClassicDict*
|
||||
Function,-,mf_classic_dict_get_key_at_index,_Bool,"MfClassicDict*, uint64_t*, uint32_t"
|
||||
Function,-,mf_classic_dict_get_key_at_index_str,_Bool,"MfClassicDict*, FuriString*, uint32_t"
|
||||
Function,+,mf_classic_dict_get_key_at_index_str,_Bool,"MfClassicDict*, FuriString*, uint32_t"
|
||||
Function,-,mf_classic_dict_get_next_key,_Bool,"MfClassicDict*, uint64_t*"
|
||||
Function,-,mf_classic_dict_get_next_key_str,_Bool,"MfClassicDict*, FuriString*"
|
||||
Function,-,mf_classic_dict_get_total_keys,uint32_t,MfClassicDict*
|
||||
Function,-,mf_classic_dict_is_key_present,_Bool,"MfClassicDict*, uint8_t*"
|
||||
Function,+,mf_classic_dict_get_next_key_str,_Bool,"MfClassicDict*, FuriString*"
|
||||
Function,+,mf_classic_dict_get_total_keys,uint32_t,MfClassicDict*
|
||||
Function,+,mf_classic_dict_is_key_present,_Bool,"MfClassicDict*, uint8_t*"
|
||||
Function,-,mf_classic_dict_is_key_present_str,_Bool,"MfClassicDict*, FuriString*"
|
||||
Function,-,mf_classic_dict_rewind,_Bool,MfClassicDict*
|
||||
Function,-,mf_classic_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*, _Bool"
|
||||
Function,-,mf_classic_get_classic_type,MfClassicType,"uint8_t, uint8_t, uint8_t"
|
||||
Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*"
|
||||
Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t
|
||||
Function,+,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*"
|
||||
Function,+,mf_classic_get_sector_by_block,uint8_t,uint8_t
|
||||
Function,-,mf_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t
|
||||
Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t"
|
||||
Function,+,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t"
|
||||
Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType
|
||||
Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType
|
||||
Function,+,mf_classic_get_total_sectors_num,uint8_t,MfClassicType
|
||||
Function,-,mf_classic_get_type_str,const char*,MfClassicType
|
||||
Function,-,mf_classic_halt,void,"FuriHalNfcTxRxContext*, Crypto1*"
|
||||
Function,-,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction"
|
||||
Function,-,mf_classic_is_allowed_access_sector_trailer,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction"
|
||||
Function,-,mf_classic_is_block_read,_Bool,"MfClassicData*, uint8_t"
|
||||
Function,-,mf_classic_is_card_read,_Bool,MfClassicData*
|
||||
Function,-,mf_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKey"
|
||||
Function,+,mf_classic_is_block_read,_Bool,"MfClassicData*, uint8_t"
|
||||
Function,+,mf_classic_is_card_read,_Bool,MfClassicData*
|
||||
Function,+,mf_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKey"
|
||||
Function,-,mf_classic_is_sector_data_read,_Bool,"MfClassicData*, uint8_t"
|
||||
Function,-,mf_classic_is_sector_read,_Bool,"MfClassicData*, uint8_t"
|
||||
Function,-,mf_classic_is_sector_trailer,_Bool,uint8_t
|
||||
Function,+,mf_classic_is_sector_trailer,_Bool,uint8_t
|
||||
Function,-,mf_classic_is_value_block,_Bool,"MfClassicData*, uint8_t"
|
||||
Function,-,mf_classic_read_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*"
|
||||
Function,-,mf_classic_read_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicReader*, MfClassicData*"
|
||||
@ -2018,10 +2026,10 @@ Function,-,mf_classic_value_to_block,void,"int32_t, uint8_t, uint8_t*"
|
||||
Function,-,mf_classic_write_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*"
|
||||
Function,-,mf_classic_write_sector,_Bool,"FuriHalNfcTxRxContext*, MfClassicData*, MfClassicData*, uint8_t"
|
||||
Function,-,mf_df_cat_application,void,"MifareDesfireApplication*, FuriString*"
|
||||
Function,-,mf_df_cat_application_info,void,"MifareDesfireApplication*, FuriString*"
|
||||
Function,-,mf_df_cat_card_info,void,"MifareDesfireData*, FuriString*"
|
||||
Function,+,mf_df_cat_application_info,void,"MifareDesfireApplication*, FuriString*"
|
||||
Function,+,mf_df_cat_card_info,void,"MifareDesfireData*, FuriString*"
|
||||
Function,-,mf_df_cat_data,void,"MifareDesfireData*, FuriString*"
|
||||
Function,-,mf_df_cat_file,void,"MifareDesfireFile*, FuriString*"
|
||||
Function,+,mf_df_cat_file,void,"MifareDesfireFile*, FuriString*"
|
||||
Function,-,mf_df_cat_free_mem,void,"MifareDesfireFreeMemory*, FuriString*"
|
||||
Function,-,mf_df_cat_key_settings,void,"MifareDesfireKeySettings*, FuriString*"
|
||||
Function,-,mf_df_cat_version,void,"MifareDesfireVersion*, FuriString*"
|
||||
@ -2051,8 +2059,8 @@ Function,-,mf_df_prepare_read_records,uint16_t,"uint8_t*, uint8_t, uint32_t, uin
|
||||
Function,-,mf_df_prepare_select_application,uint16_t,"uint8_t*, uint8_t[3]"
|
||||
Function,-,mf_df_read_card,_Bool,"FuriHalNfcTxRxContext*, MifareDesfireData*"
|
||||
Function,-,mf_ul_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t"
|
||||
Function,-,mf_ul_emulation_supported,_Bool,MfUltralightData*
|
||||
Function,-,mf_ul_is_full_capture,_Bool,MfUltralightData*
|
||||
Function,+,mf_ul_emulation_supported,_Bool,MfUltralightData*
|
||||
Function,+,mf_ul_is_full_capture,_Bool,MfUltralightData*
|
||||
Function,-,mf_ul_prepare_emulation,void,"MfUltralightEmulator*, MfUltralightData*"
|
||||
Function,-,mf_ul_prepare_emulation_response,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*, uint32_t*, void*"
|
||||
Function,-,mf_ul_pwdgen_amiibo,uint32_t,FuriHalNfcDevData*
|
||||
@ -2062,13 +2070,18 @@ Function,-,mf_ul_reset,void,MfUltralightData*
|
||||
Function,-,mf_ul_reset_emulation,void,"MfUltralightEmulator*, _Bool"
|
||||
Function,-,mf_ultralight_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint32_t, uint16_t*"
|
||||
Function,-,mf_ultralight_fast_read_pages,_Bool,"FuriHalNfcTxRxContext*, MfUltralightReader*, MfUltralightData*"
|
||||
Function,-,mf_ultralight_get_config_pages,MfUltralightConfigPages*,MfUltralightData*
|
||||
Function,+,mf_ultralight_get_config_pages,MfUltralightConfigPages*,MfUltralightData*
|
||||
Function,-,mf_ultralight_read_counters,_Bool,"FuriHalNfcTxRxContext*, MfUltralightData*"
|
||||
Function,-,mf_ultralight_read_pages,_Bool,"FuriHalNfcTxRxContext*, MfUltralightReader*, MfUltralightData*"
|
||||
Function,-,mf_ultralight_read_pages_direct,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint8_t*"
|
||||
Function,-,mf_ultralight_read_signature,_Bool,"FuriHalNfcTxRxContext*, MfUltralightData*"
|
||||
Function,-,mf_ultralight_read_tearing_flags,_Bool,"FuriHalNfcTxRxContext*, MfUltralightData*"
|
||||
Function,-,mf_ultralight_read_version,_Bool,"FuriHalNfcTxRxContext*, MfUltralightReader*, MfUltralightData*"
|
||||
Function,-,mfkey32_alloc,Mfkey32*,uint32_t
|
||||
Function,-,mfkey32_free,void,Mfkey32*
|
||||
Function,+,mfkey32_get_auth_sectors,uint16_t,FuriString*
|
||||
Function,-,mfkey32_process_data,void,"Mfkey32*, uint8_t*, uint16_t, _Bool, _Bool"
|
||||
Function,-,mfkey32_set_callback,void,"Mfkey32*, Mfkey32ParseDataCallback, void*"
|
||||
Function,-,mkdtemp,char*,char*
|
||||
Function,-,mkostemp,int,"char*, int"
|
||||
Function,-,mkostemps,int,"char*, int, int"
|
||||
@ -2117,11 +2130,25 @@ Function,+,nfc_device_save_shadow,_Bool,"NfcDevice*, const char*"
|
||||
Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*"
|
||||
Function,+,nfc_device_set_name,void,"NfcDevice*, const char*"
|
||||
Function,+,nfc_file_select,_Bool,NfcDevice*
|
||||
Function,-,nfc_generate_mf_classic,void,"NfcDeviceData*, uint8_t, MfClassicType"
|
||||
Function,+,nfc_get_dev_type,const char*,FuriHalNfcType
|
||||
Function,-,nfc_guess_protocol,const char*,NfcProtocol
|
||||
Function,+,nfc_mf_classic_type,const char*,MfClassicType
|
||||
Function,+,nfc_mf_ul_type,const char*,"MfUltralightType, _Bool"
|
||||
Function,+,nfc_supported_card_verify_and_parse,_Bool,NfcDeviceData*
|
||||
Function,+,nfc_util_bytes2num,uint64_t,"const uint8_t*, uint8_t"
|
||||
Function,+,nfc_util_even_parity32,uint8_t,uint32_t
|
||||
Function,+,nfc_util_num2bytes,void,"uint64_t, uint8_t, uint8_t*"
|
||||
Function,+,nfc_util_odd_parity,void,"const uint8_t*, uint8_t*, uint8_t"
|
||||
Function,+,nfc_util_odd_parity8,uint8_t,uint8_t
|
||||
Function,+,nfc_worker_alloc,NfcWorker*,
|
||||
Function,+,nfc_worker_free,void,NfcWorker*
|
||||
Function,+,nfc_worker_get_state,NfcWorkerState,NfcWorker*
|
||||
Function,-,nfc_worker_nfcv_emulate,void,NfcWorker*
|
||||
Function,-,nfc_worker_nfcv_sniff,void,NfcWorker*
|
||||
Function,-,nfc_worker_nfcv_unlock,void,NfcWorker*
|
||||
Function,+,nfc_worker_start,void,"NfcWorker*, NfcWorkerState, NfcDeviceData*, NfcWorkerCallback, void*"
|
||||
Function,+,nfc_worker_stop,void,NfcWorker*
|
||||
Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t"
|
||||
Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*"
|
||||
Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t"
|
||||
@ -2699,10 +2726,16 @@ Function,-,strupr,char*,char*
|
||||
Function,-,strverscmp,int,"const char*, const char*"
|
||||
Function,-,strxfrm,size_t,"char*, const char*, size_t"
|
||||
Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t"
|
||||
Function,-,stub_parser_verify_read,_Bool,"NfcWorker*, FuriHalNfcTxRxContext*"
|
||||
Function,+,subghz_block_generic_deserialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*"
|
||||
Function,+,subghz_block_generic_deserialize_check_count_bit,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, uint16_t"
|
||||
Function,+,subghz_block_generic_get_preset_name,void,"const char*, FuriString*"
|
||||
Function,+,subghz_block_generic_serialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*"
|
||||
Function,+,subghz_custom_btn_get,uint8_t,
|
||||
Function,+,subghz_custom_btn_get_original,uint8_t,
|
||||
Function,+,subghz_custom_btn_is_allowed,_Bool,
|
||||
Function,+,subghz_custom_btn_set,_Bool,uint8_t
|
||||
Function,+,subghz_custom_btns_reset,void,
|
||||
Function,+,subghz_devices_begin,_Bool,const SubGhzDevice*
|
||||
Function,+,subghz_devices_deinit,void,
|
||||
Function,+,subghz_devices_end,void,const SubGhzDevice*
|
||||
@ -2747,6 +2780,14 @@ Function,+,subghz_environment_set_alutech_at_4n_rainbow_table_file_name,void,"Su
|
||||
Function,+,subghz_environment_set_came_atomo_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*"
|
||||
Function,+,subghz_environment_set_nice_flor_s_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*"
|
||||
Function,+,subghz_environment_set_protocol_registry,void,"SubGhzEnvironment*, const SubGhzProtocolRegistry*"
|
||||
Function,+,subghz_file_encoder_worker_alloc,SubGhzFileEncoderWorker*,
|
||||
Function,+,subghz_file_encoder_worker_callback_end,void,"SubGhzFileEncoderWorker*, SubGhzFileEncoderWorkerCallbackEnd, void*"
|
||||
Function,+,subghz_file_encoder_worker_free,void,SubGhzFileEncoderWorker*
|
||||
Function,+,subghz_file_encoder_worker_get_level_duration,LevelDuration,void*
|
||||
Function,+,subghz_file_encoder_worker_get_text_progress,void,"SubGhzFileEncoderWorker*, FuriString*"
|
||||
Function,+,subghz_file_encoder_worker_is_running,_Bool,SubGhzFileEncoderWorker*
|
||||
Function,+,subghz_file_encoder_worker_start,_Bool,"SubGhzFileEncoderWorker*, const char*, const char*"
|
||||
Function,+,subghz_file_encoder_worker_stop,void,SubGhzFileEncoderWorker*
|
||||
Function,-,subghz_keystore_alloc,SubGhzKeystore*,
|
||||
Function,-,subghz_keystore_free,void,SubGhzKeystore*
|
||||
Function,-,subghz_keystore_get_data,SubGhzKeyArray_t*,SubGhzKeystore*
|
||||
@ -2755,6 +2796,7 @@ Function,-,subghz_keystore_raw_encrypted_save,_Bool,"const char*, const char*, u
|
||||
Function,-,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t"
|
||||
Function,-,subghz_keystore_reset_kl,void,SubGhzKeystore*
|
||||
Function,-,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*"
|
||||
Function,+,subghz_protocol_alutech_at_4n_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t"
|
||||
Function,+,subghz_protocol_blocks_add_bytes,uint8_t,"const uint8_t[], size_t"
|
||||
Function,+,subghz_protocol_blocks_add_to_128_bit,void,"SubGhzBlockDecoder*, uint8_t, uint64_t*"
|
||||
@ -2776,6 +2818,7 @@ Function,+,subghz_protocol_blocks_parity_bytes,uint8_t,"const uint8_t[], size_t"
|
||||
Function,+,subghz_protocol_blocks_reverse_key,uint64_t,"uint64_t, uint8_t"
|
||||
Function,+,subghz_protocol_blocks_set_bit_array,void,"_Bool, uint8_t[], size_t, size_t"
|
||||
Function,+,subghz_protocol_blocks_xor_bytes,uint8_t,"const uint8_t[], size_t"
|
||||
Function,+,subghz_protocol_came_atomo_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint16_t, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_decoder_base_deserialize,SubGhzProtocolStatus,"SubGhzProtocolDecoderBase*, FlipperFormat*"
|
||||
Function,+,subghz_protocol_decoder_base_get_hash_data,uint8_t,SubGhzProtocolDecoderBase*
|
||||
Function,+,subghz_protocol_decoder_base_get_string,_Bool,"SubGhzProtocolDecoderBase*, FuriString*"
|
||||
@ -2793,7 +2836,10 @@ Function,+,subghz_protocol_encoder_raw_deserialize,SubGhzProtocolStatus,"void*,
|
||||
Function,+,subghz_protocol_encoder_raw_free,void,void*
|
||||
Function,+,subghz_protocol_encoder_raw_stop,void,void*
|
||||
Function,+,subghz_protocol_encoder_raw_yield,LevelDuration,void*
|
||||
Function,+,subghz_protocol_faac_slh_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, uint32_t, const char*, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_keeloq_bft_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, uint32_t, const char*, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_keeloq_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_nice_flor_s_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*, _Bool"
|
||||
Function,+,subghz_protocol_raw_file_encoder_worker_set_callback_end,void,"SubGhzProtocolEncoderRAW*, SubGhzProtocolEncoderRAWCallbackEnd, void*"
|
||||
Function,+,subghz_protocol_raw_gen_fff_data,void,"FlipperFormat*, const char*, const char*"
|
||||
Function,+,subghz_protocol_raw_get_sample_write,size_t,SubGhzProtocolDecoderRAW*
|
||||
@ -2805,6 +2851,7 @@ Function,+,subghz_protocol_registry_get_by_index,const SubGhzProtocol*,"const Su
|
||||
Function,+,subghz_protocol_registry_get_by_name,const SubGhzProtocol*,"const SubGhzProtocolRegistry*, const char*"
|
||||
Function,+,subghz_protocol_secplus_v1_check_fixed,_Bool,uint32_t
|
||||
Function,+,subghz_protocol_secplus_v2_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_somfy_telis_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*"
|
||||
Function,+,subghz_receiver_alloc_init,SubGhzReceiver*,SubGhzEnvironment*
|
||||
Function,+,subghz_receiver_decode,void,"SubGhzReceiver*, _Bool, uint32_t"
|
||||
Function,+,subghz_receiver_free,void,SubGhzReceiver*
|
||||
@ -2813,7 +2860,7 @@ Function,+,subghz_receiver_search_decoder_base_by_name,SubGhzProtocolDecoderBase
|
||||
Function,+,subghz_receiver_set_filter,void,"SubGhzReceiver*, SubGhzProtocolFlag"
|
||||
Function,+,subghz_receiver_set_rx_callback,void,"SubGhzReceiver*, SubGhzReceiverCallback, void*"
|
||||
Function,+,subghz_setting_alloc,SubGhzSetting*,
|
||||
Function,-,subghz_setting_customs_presets_to_log,uint8_t,SubGhzSetting*
|
||||
Function,+,subghz_setting_customs_presets_to_log,uint8_t,SubGhzSetting*
|
||||
Function,+,subghz_setting_delete_custom_preset,_Bool,"SubGhzSetting*, const char*"
|
||||
Function,+,subghz_setting_free,void,SubGhzSetting*
|
||||
Function,+,subghz_setting_get_default_frequency,uint32_t,SubGhzSetting*
|
||||
@ -2866,7 +2913,7 @@ Function,+,submenu_set_header,void,"Submenu*, const char*"
|
||||
Function,+,submenu_set_selected_item,void,"Submenu*, uint32_t"
|
||||
Function,-,system,int,const char*
|
||||
Function,+,t5577_write,void,LFRFIDT5577*
|
||||
Function,-,t5577_write_with_pass,void,"LFRFIDT5577*, uint32_t"
|
||||
Function,+,t5577_write_with_pass,void,"LFRFIDT5577*, uint32_t"
|
||||
Function,-,tan,double,double
|
||||
Function,-,tanf,float,float
|
||||
Function,-,tanh,double,double
|
||||
@ -3401,6 +3448,8 @@ Variable,+,message_red_255,const NotificationMessage,
|
||||
Variable,+,message_sound_off,const NotificationMessage,
|
||||
Variable,+,message_vibro_off,const NotificationMessage,
|
||||
Variable,+,message_vibro_on,const NotificationMessage,
|
||||
Variable,+,nfc_generators,const NfcGenerator*[],
|
||||
Variable,-,nfc_supported_card,NfcSupportedCard[NfcSupportedCardTypeEnd],
|
||||
Variable,+,sequence_audiovisual_alert,const NotificationSequence,
|
||||
Variable,+,sequence_blink_blue_10,const NotificationSequence,
|
||||
Variable,+,sequence_blink_blue_100,const NotificationSequence,
|
||||
|
|
@ -19,3 +19,7 @@ const char* furi_hal_version_get_fcc_id() {
|
||||
const char* furi_hal_version_get_ic_id() {
|
||||
return "27624-FZ";
|
||||
}
|
||||
|
||||
const char* furi_hal_version_get_mic_id() {
|
||||
return "210-175991";
|
||||
}
|
||||
|
@ -87,6 +87,12 @@ const char* furi_hal_version_get_fcc_id();
|
||||
*/
|
||||
const char* furi_hal_version_get_ic_id();
|
||||
|
||||
/** Get MIC id
|
||||
*
|
||||
* @return MIC id as C-string
|
||||
*/
|
||||
const char* furi_hal_version_get_mic_id();
|
||||
|
||||
/** Get OTP version
|
||||
*
|
||||
* @return OTP Version
|
||||
|
@ -6,6 +6,11 @@ env.Append(
|
||||
],
|
||||
SDK_HEADERS=[
|
||||
File("nfc_device.h"),
|
||||
File("nfc_worker.h"),
|
||||
File("nfc_types.h"),
|
||||
File("helpers/mfkey32.h"),
|
||||
File("parsers/nfc_supported_card.h"),
|
||||
File("helpers/nfc_generators.h"),
|
||||
File("protocols/nfc_util.h"),
|
||||
],
|
||||
)
|
||||
|
@ -6,6 +6,10 @@
|
||||
#include <lib/toolbox/stream/file_stream.h>
|
||||
#include <lib/toolbox/stream/buffered_file_stream.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
MfClassicDictTypeUser,
|
||||
MfClassicDictTypeSystem,
|
||||
@ -97,3 +101,7 @@ bool mf_classic_dict_find_index_str(MfClassicDict* dict, FuriString* key, uint32
|
||||
* @return true on success
|
||||
*/
|
||||
bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -2,6 +2,10 @@
|
||||
|
||||
#include <lib/nfc/protocols/mifare_classic.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct Mfkey32 Mfkey32;
|
||||
|
||||
typedef enum {
|
||||
@ -24,3 +28,7 @@ void mfkey32_process_data(
|
||||
void mfkey32_set_callback(Mfkey32* instance, Mfkey32ParseDataCallback callback, void* context);
|
||||
|
||||
uint16_t mfkey32_get_auth_sectors(FuriString* string);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -2,6 +2,10 @@
|
||||
|
||||
#include "nfc_device.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const char* nfc_get_dev_type(FuriHalNfcType type);
|
||||
|
||||
const char* nfc_guess_protocol(NfcProtocol protocol);
|
||||
@ -9,3 +13,7 @@ const char* nfc_guess_protocol(NfcProtocol protocol);
|
||||
const char* nfc_mf_ul_type(MfUltralightType type, bool full_name);
|
||||
|
||||
const char* nfc_mf_classic_type(MfClassicType type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -2,6 +2,10 @@
|
||||
|
||||
#include "nfc_device.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct NfcWorker NfcWorker;
|
||||
|
||||
typedef enum {
|
||||
@ -98,4 +102,8 @@ void nfc_worker_start(
|
||||
void nfc_worker_stop(NfcWorker* nfc_worker);
|
||||
void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker);
|
||||
void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker);
|
||||
void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker);
|
||||
void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -4,6 +4,10 @@
|
||||
#include "../nfc_worker.h"
|
||||
#include "../nfc_device.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
NfcSupportedCardTypePlantain,
|
||||
NfcSupportedCardTypeTroika,
|
||||
@ -37,3 +41,7 @@ bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data);
|
||||
// support the card. This is needed for DESFire card parsers which can't
|
||||
// provide keys, and only use NfcSupportedCard->parse.
|
||||
bool stub_parser_verify_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -3,6 +3,10 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t odd;
|
||||
uint32_t even;
|
||||
@ -35,3 +39,7 @@ void crypto1_encrypt(
|
||||
uint16_t plain_data_bits,
|
||||
uint8_t* encrypted_data,
|
||||
uint8_t* encrypted_parity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -4,6 +4,10 @@
|
||||
|
||||
#include "crypto1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MF_CLASSIC_BLOCK_SIZE (16)
|
||||
#define MF_CLASSIC_TOTAL_BLOCKS_MAX (256)
|
||||
#define MF_MINI_TOTAL_SECTORS_NUM (5)
|
||||
@ -241,3 +245,7 @@ bool mf_classic_write_sector(
|
||||
MfClassicData* dest_data,
|
||||
MfClassicData* src_data,
|
||||
uint8_t sec_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -5,6 +5,10 @@
|
||||
|
||||
#include <furi_hal_nfc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MF_DF_GET_VERSION (0x60)
|
||||
#define MF_DF_GET_FREE_MEMORY (0x6E)
|
||||
#define MF_DF_GET_KEY_SETTINGS (0x45)
|
||||
@ -169,3 +173,7 @@ uint16_t mf_df_prepare_read_records(uint8_t* dest, uint8_t file_id, uint32_t off
|
||||
bool mf_df_parse_read_data_response(uint8_t* buf, uint16_t len, MifareDesfireFile* out);
|
||||
|
||||
bool mf_df_read_card(FuriHalNfcTxRxContext* tx_rx, MifareDesfireData* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -2,6 +2,10 @@
|
||||
|
||||
#include <furi_hal_nfc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Largest tag is NTAG I2C Plus 2K, both data sectors plus SRAM
|
||||
#define MF_UL_MAX_DUMP_SIZE ((238 + 256 + 16) * 4)
|
||||
|
||||
@ -259,3 +263,7 @@ uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data);
|
||||
uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data);
|
||||
|
||||
bool mf_ul_is_full_capture(MfUltralightData* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -10,6 +10,7 @@ env.Append(
|
||||
File("registry.h"),
|
||||
File("subghz_worker.h"),
|
||||
File("subghz_tx_rx_worker.h"),
|
||||
File("subghz_file_encoder_worker.h"),
|
||||
File("transmitter.h"),
|
||||
File("protocols/raw.h"),
|
||||
File("blocks/const.h"),
|
||||
@ -17,6 +18,7 @@ env.Append(
|
||||
File("blocks/encoder.h"),
|
||||
File("blocks/generic.h"),
|
||||
File("blocks/math.h"),
|
||||
File("blocks/custom_btn.h"),
|
||||
File("subghz_setting.h"),
|
||||
File("subghz_protocol_registry.h"),
|
||||
File("devices/cc1101_configs.h"),
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Default btn ID
|
||||
#define SUBGHZ_CUSTOM_BTN_OK (0U)
|
||||
#define SUBGHZ_CUSTOM_BTN_UP (1U)
|
||||
@ -19,4 +23,8 @@ uint8_t subghz_custom_btn_get_original();
|
||||
|
||||
void subghz_custom_btns_reset();
|
||||
|
||||
bool subghz_custom_btn_is_allowed();
|
||||
bool subghz_custom_btn_is_allowed();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -2,6 +2,10 @@
|
||||
|
||||
#include <furi_hal.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*SubGhzFileEncoderWorkerCallbackEnd)(void* context);
|
||||
|
||||
typedef struct SubGhzFileEncoderWorker SubGhzFileEncoderWorker;
|
||||
@ -68,3 +72,7 @@ void subghz_file_encoder_worker_stop(SubGhzFileEncoderWorker* instance);
|
||||
* @return bool - true if running
|
||||
*/
|
||||
bool subghz_file_encoder_worker_is_running(SubGhzFileEncoderWorker* instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -27,12 +27,64 @@ bool subghz_protocol_keeloq_create_data(
|
||||
const char* manufacture_name,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
bool subghz_protocol_keeloq_bft_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
uint32_t seed,
|
||||
const char* manufacture_name,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
void subghz_protocol_decoder_bin_raw_data_input_rssi(
|
||||
SubGhzProtocolDecoderBinRAW* instance,
|
||||
float rssi);
|
||||
|
||||
bool subghz_protocol_secplus_v1_check_fixed(uint32_t fixed);
|
||||
|
||||
bool subghz_protocol_faac_slh_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint32_t cnt,
|
||||
uint32_t seed,
|
||||
const char* manufacture_name,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
bool subghz_protocol_came_atomo_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
bool subghz_protocol_somfy_telis_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
bool subghz_protocol_nice_flor_s_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset,
|
||||
bool nice_one);
|
||||
|
||||
bool subghz_protocol_alutech_at_4n_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -18,6 +18,7 @@ class FlipperAppType(Enum):
|
||||
SETTINGS = "Settings"
|
||||
STARTUP = "StartupHook"
|
||||
EXTERNAL = "External"
|
||||
MENUEXTERNAL = "MenuExternal"
|
||||
METAPACKAGE = "Package"
|
||||
PLUGIN = "Plugin"
|
||||
|
||||
@ -213,7 +214,7 @@ class AppBuildset:
|
||||
appmgr: AppManager,
|
||||
appnames: List[str],
|
||||
hw_target: str,
|
||||
message_writer: Callable = None,
|
||||
message_writer: Callable | None = None,
|
||||
):
|
||||
self.appmgr = appmgr
|
||||
self.appnames = set(appnames)
|
||||
@ -367,6 +368,11 @@ class ApplicationsCGenerator:
|
||||
),
|
||||
}
|
||||
|
||||
APP_EXTERNAL_TYPE = (
|
||||
"FlipperExternalApplication",
|
||||
"FLIPPER_EXTERNAL_APPS",
|
||||
)
|
||||
|
||||
def __init__(self, buildset: AppBuildset, autorun_app: str = ""):
|
||||
self.buildset = buildset
|
||||
self.autorun = autorun_app
|
||||
@ -387,6 +393,17 @@ class ApplicationsCGenerator:
|
||||
.icon = {f"&{app.icon}" if app.icon else "NULL"},
|
||||
.flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}"""
|
||||
|
||||
def get_external_app_descr(self, app: FlipperApplication):
|
||||
app_path = "/ext/apps"
|
||||
if app.fap_category:
|
||||
app_path += f"/{app.fap_category}"
|
||||
app_path += f"/{app.appid}.fap"
|
||||
return f"""
|
||||
{{
|
||||
.name = "{app.name}",
|
||||
.icon = {f"&{app.icon}" if app.icon else "NULL"},
|
||||
.path = "{app_path}" }}"""
|
||||
|
||||
def generate(self):
|
||||
contents = [
|
||||
'#include "applications.h"',
|
||||
@ -418,4 +435,11 @@ class ApplicationsCGenerator:
|
||||
]
|
||||
)
|
||||
|
||||
entry_type, entry_block = self.APP_EXTERNAL_TYPE
|
||||
external_apps = self.buildset.get_apps_of_type(FlipperAppType.MENUEXTERNAL)
|
||||
contents.append(f"const {entry_type} {entry_block}[] = {{")
|
||||
contents.append(",\n".join(map(self.get_external_app_descr, external_apps)))
|
||||
contents.append("};")
|
||||
contents.append(f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});")
|
||||
|
||||
return "\n".join(contents)
|
||||
|
@ -423,7 +423,10 @@ def AddAppLaunchTarget(env, appname, launch_target_name):
|
||||
host_app = env["APPMGR"].get(artifacts_app_to_run.app.requires[0])
|
||||
|
||||
if host_app:
|
||||
if host_app.apptype == FlipperAppType.EXTERNAL:
|
||||
if host_app.apptype in [
|
||||
FlipperAppType.EXTERNAL,
|
||||
FlipperAppType.MENUEXTERNAL,
|
||||
]:
|
||||
_add_host_app_to_targets(host_app)
|
||||
else:
|
||||
# host app is a built-in app
|
||||
|
@ -262,6 +262,7 @@ apps_artifacts = appenv["EXT_APPS"]
|
||||
apps_to_build_as_faps = [
|
||||
FlipperAppType.PLUGIN,
|
||||
FlipperAppType.EXTERNAL,
|
||||
FlipperAppType.MENUEXTERNAL,
|
||||
]
|
||||
|
||||
known_extapps = [
|
||||
|
@ -67,6 +67,7 @@ class FlipperExtAppBuildArtifacts:
|
||||
apps_to_build_as_faps = [
|
||||
FlipperAppType.PLUGIN,
|
||||
FlipperAppType.EXTERNAL,
|
||||
FlipperAppType.MENUEXTERNAL,
|
||||
FlipperAppType.DEBUG,
|
||||
]
|
||||
|
||||
|