mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-11 06:09:08 -07:00
Merge branch 'dev' into nfc-parsers
This commit is contained in:
@@ -7,35 +7,62 @@
|
||||
//This arrays contains the font itself. You can use any u8g2 font you want
|
||||
|
||||
/*
|
||||
Fontname: -Raccoon-Fixed4x6-Medium-R-Normal--6-60-75-75-P-40-ISO10646-1
|
||||
Copyright:
|
||||
Glyphs: 95/203
|
||||
BBX Build Mode: 0
|
||||
Fontname: -Misc-Fixed-Medium-R-Normal--6-60-75-75-C-40-ISO10646-1
|
||||
Copyright: Public domain font. Share and enjoy.
|
||||
Glyphs: 191/919
|
||||
BBX Build Mode: 0
|
||||
*/
|
||||
const uint8_t u8g2_font_tom_thumb_4x6_tr[725] =
|
||||
"_\0\2\2\2\3\3\4\4\3\6\0\377\5\377\5\0\0\352\1\330\2\270 \5\340\315\0!\6\265\310"
|
||||
"\254\0\42\6\213\313$\25#\10\227\310\244\241\206\12$\10\227\310\215\70b\2%\10\227\310d\324F\1"
|
||||
"&\10\227\310(\65R\22'\5\251\313\10(\6\266\310\251\62)\10\226\310\304\224\24\0*\6\217\312\244"
|
||||
"\16+\7\217\311\245\225\0,\6\212\310)\0-\5\207\312\14.\5\245\310\4/\7\227\310Ve\4\60"
|
||||
"\7\227\310-k\1\61\6\226\310\255\6\62\10\227\310h\220\312\1\63\11\227\310h\220\62X\0\64\10\227"
|
||||
"\310$\65b\1\65\10\227\310\214\250\301\2\66\10\227\310\315\221F\0\67\10\227\310\314TF\0\70\10\227"
|
||||
"\310\214\64\324\10\71\10\227\310\214\64\342\2:\6\255\311\244\0;\7\222\310e\240\0<\10\227\310\246\32"
|
||||
"d\20=\6\217\311l\60>\11\227\310d\220A*\1\77\10\227\310\314\224a\2@\10\227\310UC\3"
|
||||
"\1A\10\227\310UC\251\0B\10\227\310\250\264\322\2C\7\227\310\315\32\10D\10\227\310\250d-\0"
|
||||
"E\10\227\310\214\70\342\0F\10\227\310\214\70b\4G\10\227\310\315\221\222\0H\10\227\310$\65\224\12"
|
||||
"I\7\227\310\254X\15J\7\227\310\226\252\2K\10\227\310$\265\222\12L\7\227\310\304\346\0M\10\227"
|
||||
"\310\244\61\224\12N\10\227\310\244q\250\0O\7\227\310UV\5P\10\227\310\250\264b\4Q\10\227\310"
|
||||
"Uj$\1R\10\227\310\250\64V\1S\10\227\310m\220\301\2T\7\227\310\254\330\2U\7\227\310$"
|
||||
"W\22V\10\227\310$\253L\0W\10\227\310$\65\206\12X\10\227\310$\325R\1Y\10\227\310$U"
|
||||
"V\0Z\7\227\310\314T\16[\7\227\310\214X\16\134\10\217\311d\220A\0]\7\227\310\314r\4^"
|
||||
"\5\213\313\65_\5\207\310\14`\6\212\313\304\0a\7\223\310\310\65\2b\10\227\310D\225\324\2c\7"
|
||||
"\223\310\315\14\4d\10\227\310\246\245\222\0e\6\223\310\235\2f\10\227\310\246\264b\2g\10\227\307\35"
|
||||
"\61%\0h\10\227\310D\225\254\0i\6\265\310\244\1j\10\233\307f\30U\5k\10\227\310\304\264T"
|
||||
"\1l\7\227\310\310\326\0m\7\223\310<R\0n\7\223\310\250d\5o\7\223\310U\252\2p\10\227"
|
||||
"\307\250\244V\4q\10\227\307-\225d\0r\6\223\310\315\22s\10\223\310\215\70\22\0t\10\227\310\245"
|
||||
"\25\243\0u\7\223\310$+\11v\10\223\310$\65R\2w\7\223\310\244q\4x\7\223\310\244\62\25"
|
||||
"y\11\227\307$\225dJ\0z\7\223\310\254\221\6{\10\227\310\251\32D\1|\6\265\310(\1}\11"
|
||||
"\227\310\310\14RR\0~\6\213\313\215\4\0\0\0\4\377\377\0";
|
||||
const uint8_t u8g2_font_4x6_t_cyrillic[] =
|
||||
"\277\0\2\2\3\3\2\4\4\4\6\0\377\5\377\5\377\0\356\1\334\2\301 \5\200\315\0!\6\351\310"
|
||||
"\254\0\42\6\223\313$\25#\12\254\310\244\64T\32*\1$\11\263\307\245\241\301H\11%\10\253\310d"
|
||||
"\324F\1&\11\254\310\305\24\253\230\2'\5\321\313\10(\7\362\307\251f\0)\10\262\307\304T)\0"
|
||||
"*\7\253\310\244j\65+\10\253\310\305\264b\2,\6\222\307)\0-\5\213\312\14.\5\311\310\4/"
|
||||
"\7\253\310Ve\4\60\10\253\310UCU\0\61\7\253\310%Y\15\62\7\253\310\65S\32\63\10\253\310"
|
||||
"\314\224\301\2\64\10\253\310$\65b\1\65\10\253\310\214\250\301\2\66\7\253\310M\325\2\67\10\253\310\314"
|
||||
"TF\0\70\7\253\310\255\326\2\71\7\253\310\265\344\2:\6\341\310\304\0;\7\252\307e\250\0<\10"
|
||||
"\253\310\246\32d\20=\6\233\311l\60>\11\253\310d\220A*\1\77\11\253\310h\220\62L\0@\7"
|
||||
"\253\310-\33\10A\10\253\310UC\251\0B\10\253\310\250\264\322\2C\10\253\310U\62U\0D\10\253"
|
||||
"\310\250d-\0E\10\253\310\214\250\342\0F\10\253\310\214\250b\4G\10\253\310\315\244\222\0H\10\253"
|
||||
"\310$\65\224\12I\7\253\310\254X\15J\7\253\310\226\252\2K\10\253\310$\265\222\12L\7\253\310\304"
|
||||
"\346\0M\10\253\310\244\61\224\12N\10\253\310\252\241$\0O\7\253\310UV\5P\10\253\310\250\264b"
|
||||
"\4Q\10\263\307UV\15\2R\10\253\310\250\264\222\12S\10\253\310m\220\301\2T\7\253\310\254\330\2"
|
||||
"U\7\253\310$\327\10V\10\253\310$k\244\4W\10\253\310$\65\206\12X\10\253\310$\325R\1Y"
|
||||
"\10\253\310$UV\0Z\7\253\310\314T\16[\6\352\310\254J\134\11\253\310\304\14\62\210\1]\6\252"
|
||||
"\310\250j^\5\223\313\65_\5\213\307\14`\6\322\313\304\0a\7\243\310-\225\4b\10\253\310D\225"
|
||||
"\324\2c\7\243\310\315\14\4d\10\253\310\246\245\222\0e\6\243\310USf\10\253\310\246\264b\2g"
|
||||
"\10\253\307\255$\27\0h\10\253\310D\225\254\0i\10\253\310e$\323\0j\10\263\307fX.\0k"
|
||||
"\10\253\310\304\264\222\12l\7\253\310\310\326\0m\10\243\310\244\241T\0n\7\243\310\250d\5o\7\243"
|
||||
"\310U\252\2p\10\253\307\250\264b\4q\10\253\307-\225d\0r\10\243\310\244\25#\0s\10\243\310"
|
||||
"\215\14\26\0t\10\253\310\245\25\63\10u\7\243\310$+\11v\7\243\310$\253\2w\10\243\310$\65"
|
||||
"T\0x\7\243\310\244\62\25y\10\253\307$\225\344\2z\7\243\310\314\224\6{\10\263\307\246$k\20"
|
||||
"|\6\351\310\14\1}\11\263\307d\20UL\21~\7\224\313%\225\0\0\0\0\4\377\377\4\1\11\253"
|
||||
"\310\244\261\342\0\4\2\11\253\310\214\250\222\12\4\3\10\253\310\16Y\2\4\4\11\253\310M\225\201\0\4"
|
||||
"\5\11\253\310m\220\301\2\4\6\10\253\310\254X\15\4\7\11\253\310\244\221b\32\4\10\10\253\310\226\252"
|
||||
"\2\4\11\11\254\310L\325Z\2\4\12\11\254\310\244\326JK\4\13\11\253\310\250\250\222\12\4\14\10\253"
|
||||
"\310\312\264\12\4\16\11\263\307\244\32u\2\4\17\11\263\307$\327H\11\4\20\11\253\310UC\251\0\4"
|
||||
"\21\11\253\310\214\250\322\2\4\22\11\253\310\250\264\322\2\4\23\10\253\310\214\330\4\4\24\11\263\307\254\245"
|
||||
"\206\12\4\25\11\253\310\214\250\342\0\4\26\12\253\310\244\221\322H\1\4\27\12\253\310h\220\62X\0\4"
|
||||
"\30\11\253\310\304\64T\14\4\31\11\263\307\315\64T\14\4\32\11\253\310$\265\222\12\4\33\10\253\310-"
|
||||
"W\0\4\34\11\253\310\244\241\254\0\4\35\11\253\310$\65\224\12\4\36\10\253\310UV\5\4\37\10\253"
|
||||
"\310\214\344\12\4 \11\253\310\250\264b\4\4!\11\253\310U\62U\0\4\42\10\253\310\254\330\2\4#"
|
||||
"\11\263\307$\253L\21\4$\12\253\310\245\221FJ\0\4%\11\253\310$\325R\1\4&\10\253\310$"
|
||||
"\327\10\4'\11\253\310$\225d\1\4(\11\253\310$\65\216\0\4)\12\264\307\244\326#\203\0\4*"
|
||||
"\13\254\310h\220\201LI\1\4+\12\254\310D\271\324H\1\4,\11\253\310\304\250\322\2\4-\11\253"
|
||||
"\310h\220\344\2\4.\12\254\310\244\244.\225\0\4/\11\253\310\255\264T\0\4\60\10\243\310-\225\4"
|
||||
"\4\61\11\253\310\315\221*\0\4\62\11\243\310\14\225\26\0\4\63\10\243\310\214X\2\4\64\11\253\307-"
|
||||
"\65T\0\4\65\7\243\310US\4\66\11\244\310$S%\1\4\67\11\243\310\254\14\26\0\4\70\11\243"
|
||||
"\310\244\61T\0\4\71\11\253\310\244\326P\1\4:\10\243\310$\265\12\4;\7\243\310-+\4<\11"
|
||||
"\243\310\244\241T\0\4=\11\243\310\244\241T\0\4>\10\243\310U\252\2\4\77\10\243\310\214d\5\4"
|
||||
"@\11\253\307\250\264b\4\4A\10\243\310\315\14\4\4B\10\243\310\254X\1\4C\11\253\307$\225\344"
|
||||
"\2\4D\12\263\307\305\224T\231\0\4E\10\243\310\244\62\25\4F\11\253\307$k\304\0\4G\11\243"
|
||||
"\310$\225d\0\4H\10\243\310\244q\4\4I\11\254\307\244\364\310 \4J\12\244\310h SR\0"
|
||||
"\4K\11\244\310\304\245F\12\4L\11\243\310D\225\26\0\4M\10\243\310H\271\0\4N\12\244\310\244"
|
||||
"\244\226J\0\4O\10\243\310\255\264\2\4Q\10\253\310\244\326\24\4R\11\263\307D\25U\31\4S\11"
|
||||
"\253\310\246\64b\4\4T\11\243\310\215\224\201\0\4U\11\243\310\215\14\26\0\4V\11\253\310e$\323"
|
||||
"\0\4W\11\253\310\244\14d\32\4X\11\263\307fX.\0\4Y\10\244\310\251\326\22\4Z\11\244\310"
|
||||
"\244\264\322\22\4[\11\253\310D\25U\1\4\134\10\253\310\312\264\12\4^\11\263\307\244\32u\2\4_"
|
||||
"\11\253\307$k\244\4\4\220\10\253\310\16Y\2\4\221\10\243\310\16\31\1\4\222\11\253\310\251\264b\2"
|
||||
"\4\223\11\243\310\251\264\22\0\0";
|
||||
|
||||
// Screen is 128x64 px
|
||||
static void app_draw_callback(Canvas* canvas, void* ctx) {
|
||||
@@ -43,10 +70,11 @@ static void app_draw_callback(Canvas* canvas, void* ctx) {
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
canvas_set_custom_u8g2_font(canvas, u8g2_font_tom_thumb_4x6_tr);
|
||||
canvas_set_custom_u8g2_font(canvas, u8g2_font_4x6_t_cyrillic);
|
||||
|
||||
canvas_draw_str(canvas, 0, 6, "This is a tiny custom font");
|
||||
canvas_draw_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%");
|
||||
canvas_draw_utf8_str(canvas, 0, 6, "This is a tiny custom font");
|
||||
canvas_draw_utf8_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%");
|
||||
canvas_draw_utf8_str(canvas, 0, 18, "И немного юникода");
|
||||
}
|
||||
|
||||
static void app_input_callback(InputEvent* input_event, void* ctx) {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h>
|
||||
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
|
||||
|
||||
#include <nfc/helpers/nfc_dict.h>
|
||||
#include <toolbox/keys_dict.h>
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "../minunit.h"
|
||||
@@ -443,36 +443,36 @@ MU_TEST(mf_classic_dict_test) {
|
||||
"Remove test dict failed");
|
||||
}
|
||||
|
||||
NfcDict* dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
mu_assert(dict != NULL, "nfc_dict_alloc() failed");
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
mu_assert(dict != NULL, "keys_dict_alloc() failed");
|
||||
|
||||
size_t dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == 0, "nfc_dict_keys_total() failed");
|
||||
size_t dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == 0, "keys_dict_keys_total() failed");
|
||||
|
||||
const uint32_t test_key_num = 30;
|
||||
MfClassicKey* key_arr_ref = malloc(test_key_num * sizeof(MfClassicKey));
|
||||
for(size_t i = 0; i < test_key_num; i++) {
|
||||
furi_hal_random_fill_buf(key_arr_ref[i].data, sizeof(MfClassicKey));
|
||||
mu_assert(
|
||||
nfc_dict_add_key(dict, key_arr_ref[i].data, sizeof(MfClassicKey)), "add key failed");
|
||||
keys_dict_add_key(dict, key_arr_ref[i].data, sizeof(MfClassicKey)), "add key failed");
|
||||
|
||||
size_t dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == (i + 1), "nfc_dict_keys_total() failed");
|
||||
size_t dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == (i + 1), "keys_dict_keys_total() failed");
|
||||
}
|
||||
|
||||
nfc_dict_free(dict);
|
||||
keys_dict_free(dict);
|
||||
|
||||
dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
mu_assert(dict != NULL, "nfc_dict_alloc() failed");
|
||||
dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
mu_assert(dict != NULL, "keys_dict_alloc() failed");
|
||||
|
||||
dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == test_key_num, "nfc_dict_keys_total() failed");
|
||||
dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == test_key_num, "keys_dict_keys_total() failed");
|
||||
|
||||
MfClassicKey key_dut = {};
|
||||
size_t key_idx = 0;
|
||||
while(nfc_dict_get_next_key(dict, key_dut.data, sizeof(MfClassicKey))) {
|
||||
while(keys_dict_get_next_key(dict, key_dut.data, sizeof(MfClassicKey))) {
|
||||
mu_assert(
|
||||
memcmp(key_arr_ref[key_idx].data, key_dut.data, sizeof(MfClassicKey)) == 0,
|
||||
"Loaded key data mismatch");
|
||||
@@ -484,19 +484,19 @@ MU_TEST(mf_classic_dict_test) {
|
||||
for(size_t i = 0; i < COUNT_OF(delete_keys_idx); i++) {
|
||||
MfClassicKey* key = &key_arr_ref[delete_keys_idx[i]];
|
||||
mu_assert(
|
||||
nfc_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)),
|
||||
"nfc_dict_is_key_present() failed");
|
||||
keys_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)),
|
||||
"keys_dict_is_key_present() failed");
|
||||
mu_assert(
|
||||
nfc_dict_delete_key(dict, key->data, sizeof(MfClassicKey)),
|
||||
"nfc_dict_delete_key() failed");
|
||||
keys_dict_delete_key(dict, key->data, sizeof(MfClassicKey)),
|
||||
"keys_dict_delete_key() failed");
|
||||
}
|
||||
|
||||
dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
mu_assert(
|
||||
dict_keys_total == test_key_num - COUNT_OF(delete_keys_idx),
|
||||
"nfc_dict_keys_total() failed");
|
||||
"keys_dict_keys_total() failed");
|
||||
|
||||
nfc_dict_free(dict);
|
||||
keys_dict_free(dict);
|
||||
free(key_arr_ref);
|
||||
|
||||
mu_assert(
|
||||
|
||||
@@ -27,6 +27,7 @@ static const uint32_t baudrate_list[] = {
|
||||
460800,
|
||||
921600,
|
||||
};
|
||||
static const char* software_de_re[] = {"None", "4"};
|
||||
|
||||
bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) {
|
||||
GpioApp* app = context;
|
||||
@@ -84,6 +85,17 @@ static void line_port_cb(VariableItem* item) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
|
||||
}
|
||||
|
||||
static void line_software_de_re_cb(VariableItem* item) {
|
||||
GpioApp* app = variable_item_get_context(item);
|
||||
furi_assert(app);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, software_de_re[index]);
|
||||
|
||||
app->usb_uart_cfg->software_de_re = index;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
|
||||
}
|
||||
|
||||
static void line_flow_cb(VariableItem* item) {
|
||||
GpioApp* app = variable_item_get_context(item);
|
||||
furi_assert(app);
|
||||
@@ -155,6 +167,11 @@ void gpio_scene_usb_uart_cfg_on_enter(void* context) {
|
||||
app->var_item_flow = item;
|
||||
line_ensure_flow_invariant(app);
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list, "DE/RE Pin", COUNT_OF(software_de_re), line_software_de_re_cb, app);
|
||||
variable_item_set_current_value_index(item, app->usb_uart_cfg->software_de_re);
|
||||
variable_item_set_current_value_text(item, software_de_re[app->usb_uart_cfg->software_de_re]);
|
||||
|
||||
variable_item_list_set_selected_item(
|
||||
var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUartCfg));
|
||||
|
||||
|
||||
@@ -6,11 +6,16 @@
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_usb_cdc.h>
|
||||
|
||||
//TODO: FL-3276 port to new USART API
|
||||
#include <stm32wbxx_ll_lpuart.h>
|
||||
#include <stm32wbxx_ll_usart.h>
|
||||
|
||||
#define USB_CDC_PKT_LEN CDC_DATA_SZ
|
||||
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
|
||||
|
||||
#define USB_CDC_BIT_DTR (1 << 0)
|
||||
#define USB_CDC_BIT_RTS (1 << 1)
|
||||
#define USB_USART_DE_RE_PIN &gpio_ext_pa4
|
||||
|
||||
static const GpioPin* flow_pins[][2] = {
|
||||
{&gpio_ext_pa7, &gpio_ext_pa6}, // 2, 3
|
||||
@@ -247,6 +252,17 @@ static int32_t usb_uart_worker(void* context) {
|
||||
usb_uart->cfg.flow_pins = usb_uart->cfg_new.flow_pins;
|
||||
events |= WorkerEvtCtrlLineSet;
|
||||
}
|
||||
if(usb_uart->cfg.software_de_re != usb_uart->cfg_new.software_de_re) {
|
||||
usb_uart->cfg.software_de_re = usb_uart->cfg_new.software_de_re;
|
||||
if(usb_uart->cfg.software_de_re != 0) {
|
||||
furi_hal_gpio_write(USB_USART_DE_RE_PIN, true);
|
||||
furi_hal_gpio_init(
|
||||
USB_USART_DE_RE_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedMedium);
|
||||
} else {
|
||||
furi_hal_gpio_init(
|
||||
USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
}
|
||||
api_lock_unlock(usb_uart->cfg_lock);
|
||||
}
|
||||
if(events & WorkerEvtLineCfgSet) {
|
||||
@@ -260,6 +276,8 @@ static int32_t usb_uart_worker(void* context) {
|
||||
usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch);
|
||||
usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch);
|
||||
|
||||
furi_hal_gpio_init(USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
if(usb_uart->cfg.flow_pins != 0) {
|
||||
furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][0], GpioModeAnalog);
|
||||
furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], GpioModeAnalog);
|
||||
@@ -298,7 +316,24 @@ static int32_t usb_uart_tx_thread(void* context) {
|
||||
|
||||
if(len > 0) {
|
||||
usb_uart->st.tx_cnt += len;
|
||||
|
||||
if(usb_uart->cfg.software_de_re != 0)
|
||||
furi_hal_gpio_write(USB_USART_DE_RE_PIN, false);
|
||||
|
||||
furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, len);
|
||||
|
||||
if(usb_uart->cfg.software_de_re != 0) {
|
||||
//TODO: FL-3276 port to new USART API
|
||||
if(usb_uart->cfg.uart_ch == FuriHalUartIdUSART1) {
|
||||
while(!LL_USART_IsActiveFlag_TC(USART1))
|
||||
;
|
||||
} else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) {
|
||||
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
|
||||
;
|
||||
}
|
||||
|
||||
furi_hal_gpio_write(USB_USART_DE_RE_PIN, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ typedef struct {
|
||||
uint8_t flow_pins;
|
||||
uint8_t baudrate_mode;
|
||||
uint32_t baudrate;
|
||||
uint8_t software_de_re;
|
||||
} UsbUartConfig;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -54,11 +54,11 @@ static void infrared_progress_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
float progress_value = (float)model->progress / model->progress_total;
|
||||
elements_progress_bar(canvas, x + 4, y + 19, width - 7, progress_value);
|
||||
|
||||
uint8_t percent_value = 100 * model->progress / model->progress_total;
|
||||
char percents_string[10] = {0};
|
||||
snprintf(percents_string, sizeof(percents_string), "%d%%", percent_value);
|
||||
char number_string[10] = {0};
|
||||
snprintf(
|
||||
number_string, sizeof(number_string), "%d/%d", model->progress, model->progress_total);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, x + 33, y + 37, AlignCenter, AlignCenter, percents_string);
|
||||
canvas, x + 33, y + 37, AlignCenter, AlignCenter, number_string);
|
||||
|
||||
canvas_draw_icon(canvas, x + 14, y + height - 14, &I_Pin_back_arrow_10x8);
|
||||
canvas_draw_str(canvas, x + 30, y + height - 6, "= stop");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "mf_user_dict.h"
|
||||
|
||||
#include <nfc/helpers/nfc_dict.h>
|
||||
#include <toolbox/keys_dict.h>
|
||||
#include <nfc/protocols/mf_classic/mf_classic.h>
|
||||
#include <furi/furi.h>
|
||||
|
||||
@@ -15,22 +15,22 @@ struct MfUserDict {
|
||||
MfUserDict* mf_user_dict_alloc(size_t max_keys_to_load) {
|
||||
MfUserDict* instance = malloc(sizeof(MfUserDict));
|
||||
|
||||
NfcDict* dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
furi_assert(dict);
|
||||
|
||||
size_t dict_keys_num = nfc_dict_get_total_keys(dict);
|
||||
size_t dict_keys_num = keys_dict_get_total_keys(dict);
|
||||
instance->keys_num = MIN(max_keys_to_load, dict_keys_num);
|
||||
|
||||
if(instance->keys_num > 0) {
|
||||
instance->keys_arr = malloc(instance->keys_num * sizeof(MfClassicKey));
|
||||
for(size_t i = 0; i < instance->keys_num; i++) {
|
||||
bool key_loaded =
|
||||
nfc_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey));
|
||||
keys_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey));
|
||||
furi_assert(key_loaded);
|
||||
}
|
||||
}
|
||||
nfc_dict_free(dict);
|
||||
keys_dict_free(dict);
|
||||
|
||||
return instance;
|
||||
}
|
||||
@@ -67,13 +67,13 @@ bool mf_user_dict_delete_key(MfUserDict* instance, uint32_t index) {
|
||||
furi_assert(index < instance->keys_num);
|
||||
furi_assert(instance->keys_arr);
|
||||
|
||||
NfcDict* dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
furi_assert(dict);
|
||||
|
||||
bool key_delete_success =
|
||||
nfc_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey));
|
||||
nfc_dict_free(dict);
|
||||
keys_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey));
|
||||
keys_dict_free(dict);
|
||||
|
||||
if(key_delete_success) {
|
||||
instance->keys_num--;
|
||||
|
||||
@@ -343,7 +343,7 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) {
|
||||
nfc_supported_cards_load_cache(instance->nfc_supported_cards);
|
||||
|
||||
FuriString* load_path = furi_string_alloc();
|
||||
if(nfc_has_shadow_file_internal(instance, path)) {
|
||||
if(nfc_has_shadow_file_internal(instance, path)) { //-V1051
|
||||
nfc_set_shadow_file_path(path, load_path);
|
||||
} else if(furi_string_end_with(path, NFC_APP_SHADOW_EXTENSION)) {
|
||||
size_t path_len = furi_string_size(path);
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
#include <nfc/nfc_device.h>
|
||||
#include <nfc/helpers/nfc_data_generator.h>
|
||||
#include <nfc/helpers/nfc_dict.h>
|
||||
#include <toolbox/keys_dict.h>
|
||||
|
||||
#include <gui/modules/validators.h>
|
||||
#include <toolbox/path.h>
|
||||
@@ -80,7 +80,7 @@ typedef enum {
|
||||
} NfcRpcState;
|
||||
|
||||
typedef struct {
|
||||
NfcDict* dict;
|
||||
KeysDict* dict;
|
||||
uint8_t sectors_total;
|
||||
uint8_t sectors_read;
|
||||
uint8_t current_sector;
|
||||
|
||||
@@ -41,7 +41,8 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
|
||||
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||
} else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) {
|
||||
MfClassicKey key = {};
|
||||
if(nfc_dict_get_next_key(instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) {
|
||||
if(keys_dict_get_next_key(
|
||||
instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) {
|
||||
mfc_event->data->key_request_data.key = key;
|
||||
mfc_event->data->key_request_data.key_provided = true;
|
||||
instance->nfc_dict_context.dict_keys_current++;
|
||||
@@ -60,7 +61,7 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||
} else if(mfc_event->type == MfClassicPollerEventTypeNextSector) {
|
||||
nfc_dict_rewind(instance->nfc_dict_context.dict);
|
||||
keys_dict_rewind(instance->nfc_dict_context.dict);
|
||||
instance->nfc_dict_context.dict_keys_current = 0;
|
||||
instance->nfc_dict_context.current_sector =
|
||||
mfc_event->data->next_sector_data.current_sector;
|
||||
@@ -79,7 +80,7 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||
} else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStop) {
|
||||
nfc_dict_rewind(instance->nfc_dict_context.dict);
|
||||
keys_dict_rewind(instance->nfc_dict_context.dict);
|
||||
instance->nfc_dict_context.is_key_attack = false;
|
||||
instance->nfc_dict_context.dict_keys_current = 0;
|
||||
view_dispatcher_send_custom_event(
|
||||
@@ -124,15 +125,15 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) {
|
||||
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack);
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
do {
|
||||
if(!nfc_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) {
|
||||
if(!keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) {
|
||||
state = DictAttackStateSystemDictInProgress;
|
||||
break;
|
||||
}
|
||||
|
||||
instance->nfc_dict_context.dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
if(nfc_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
|
||||
nfc_dict_free(instance->nfc_dict_context.dict);
|
||||
instance->nfc_dict_context.dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
state = DictAttackStateSystemDictInProgress;
|
||||
break;
|
||||
}
|
||||
@@ -141,13 +142,13 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) {
|
||||
} while(false);
|
||||
}
|
||||
if(state == DictAttackStateSystemDictInProgress) {
|
||||
instance->nfc_dict_context.dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey));
|
||||
instance->nfc_dict_context.dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey));
|
||||
dict_attack_set_header(instance->dict_attack, "MF Classic System Dictionary");
|
||||
}
|
||||
|
||||
instance->nfc_dict_context.dict_keys_total =
|
||||
nfc_dict_get_total_keys(instance->nfc_dict_context.dict);
|
||||
keys_dict_get_total_keys(instance->nfc_dict_context.dict);
|
||||
dict_attack_set_total_dict_keys(
|
||||
instance->dict_attack, instance->nfc_dict_context.dict_keys_total);
|
||||
instance->nfc_dict_context.dict_keys_current = 0;
|
||||
@@ -185,7 +186,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
nfc_poller_stop(instance->poller);
|
||||
nfc_poller_free(instance->poller);
|
||||
nfc_dict_free(instance->nfc_dict_context.dict);
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager,
|
||||
NfcSceneMfClassicDictAttack,
|
||||
@@ -215,7 +216,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
||||
if(instance->nfc_dict_context.is_card_present) {
|
||||
nfc_poller_stop(instance->poller);
|
||||
nfc_poller_free(instance->poller);
|
||||
nfc_dict_free(instance->nfc_dict_context.dict);
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager,
|
||||
NfcSceneMfClassicDictAttack,
|
||||
@@ -253,7 +254,7 @@ void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateUserDictInProgress);
|
||||
|
||||
nfc_dict_free(instance->nfc_dict_context.dict);
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
|
||||
instance->nfc_dict_context.current_sector = 0;
|
||||
instance->nfc_dict_context.sectors_total = 0;
|
||||
|
||||
@@ -14,20 +14,20 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) {
|
||||
|
||||
// Load flipper dict keys total
|
||||
uint32_t flipper_dict_keys_total = 0;
|
||||
NfcDict* dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey));
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey));
|
||||
if(dict) {
|
||||
flipper_dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
nfc_dict_free(dict);
|
||||
flipper_dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
keys_dict_free(dict);
|
||||
}
|
||||
|
||||
// Load user dict keys total
|
||||
uint32_t user_dict_keys_total = 0;
|
||||
dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
if(dict) {
|
||||
user_dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
nfc_dict_free(dict);
|
||||
user_dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
keys_dict_free(dict);
|
||||
}
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
@@ -29,23 +29,23 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventByteInputDone) {
|
||||
// Add key to dict
|
||||
NfcDict* dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
furi_assert(dict);
|
||||
|
||||
MfClassicKey key = {};
|
||||
memcpy(key.data, instance->byte_input_store, sizeof(MfClassicKey));
|
||||
if(nfc_dict_is_key_present(dict, key.data, sizeof(MfClassicKey))) {
|
||||
if(keys_dict_is_key_present(dict, key.data, sizeof(MfClassicKey))) {
|
||||
scene_manager_next_scene(
|
||||
instance->scene_manager, NfcSceneMfClassicKeysWarnDuplicate);
|
||||
} else if(nfc_dict_add_key(dict, key.data, sizeof(MfClassicKey))) {
|
||||
} else if(keys_dict_add_key(dict, key.data, sizeof(MfClassicKey))) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess);
|
||||
dolphin_deed(DolphinDeedNfcMfcAdd);
|
||||
} else {
|
||||
scene_manager_previous_scene(instance->scene_manager);
|
||||
}
|
||||
|
||||
nfc_dict_free(dict);
|
||||
keys_dict_free(dict);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ typedef enum {
|
||||
SubmenuIndexGibidi433,
|
||||
SubmenuIndexNiceMHouse_433_92,
|
||||
SubmenuIndexJCM_433_92,
|
||||
SubmenuIndexFAACRCXT_433_92,
|
||||
SubmenuIndexFAACRCXT_868,
|
||||
SubmenuIndexNormstahl_433_92,
|
||||
SubmenuIndexGSN,
|
||||
SubmenuIndexAprimatic,
|
||||
|
||||
@@ -249,7 +249,9 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz_view_receiver_disable_draw_callback(subghz->subghz_receiver);
|
||||
|
||||
subghz_history_delete_item(subghz->history, subghz->idx_menu_chosen);
|
||||
subghz_view_receiver_delete_element_callback(subghz->subghz_receiver);
|
||||
subghz_view_receiver_delete_item(
|
||||
subghz->subghz_receiver,
|
||||
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver));
|
||||
subghz_view_receiver_enable_draw_callback(subghz->subghz_receiver);
|
||||
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
|
||||
@@ -181,6 +181,18 @@ void subghz_scene_set_type_on_enter(void* context) {
|
||||
SubmenuIndexJCM_433_92,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"KL: FAAC RC,XT 433MHz",
|
||||
SubmenuIndexFAACRCXT_433_92,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"KL: FAAC RC,XT 868MHz",
|
||||
SubmenuIndexFAACRCXT_868,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"KL: Nice Mhouse 433MHz",
|
||||
@@ -744,6 +756,36 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
break;
|
||||
case SubmenuIndexFAACRCXT_433_92:
|
||||
generated_protocol = subghz_txrx_gen_keeloq_protocol(
|
||||
subghz->txrx,
|
||||
"AM650",
|
||||
433920000,
|
||||
(key & 0x0000FFFF) | 0x00100000,
|
||||
0x2,
|
||||
0x0003,
|
||||
"FAAC_RC,XT");
|
||||
if(!generated_protocol) {
|
||||
furi_string_set(
|
||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
break;
|
||||
case SubmenuIndexFAACRCXT_868:
|
||||
generated_protocol = subghz_txrx_gen_keeloq_protocol(
|
||||
subghz->txrx,
|
||||
"AM650",
|
||||
868350000,
|
||||
(key & 0x0000FFFF) | 0x00100000,
|
||||
0x2,
|
||||
0x0003,
|
||||
"FAAC_RC,XT");
|
||||
if(!generated_protocol) {
|
||||
furi_string_set(
|
||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
break;
|
||||
case SubmenuIndexNormstahl_433_92:
|
||||
generated_protocol = subghz_txrx_gen_keeloq_protocol(
|
||||
subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Normstahl");
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "subghz_history.h"
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <rpc/rpc.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define SUBGHZ_HISTORY_MAX 55
|
||||
#define SUBGHZ_HISTORY_FREE_HEAP 20480
|
||||
#define SUBGHZ_HISTORY_MAX 65530 // uint16_t index max, ram limit below
|
||||
#define SUBGHZ_HISTORY_FREE_HEAP (10240 * (3 - MIN(rpc_get_sessions_count(instance->rpc), 2U)))
|
||||
#define TAG "SubGhzHistory"
|
||||
|
||||
typedef struct {
|
||||
@@ -29,6 +30,7 @@ struct SubGhzHistory {
|
||||
uint8_t code_last_hash_data;
|
||||
FuriString* tmp_string;
|
||||
SubGhzHistoryStruct* history;
|
||||
Rpc* rpc;
|
||||
};
|
||||
|
||||
SubGhzHistory* subghz_history_alloc(void) {
|
||||
@@ -36,6 +38,7 @@ SubGhzHistory* subghz_history_alloc(void) {
|
||||
instance->tmp_string = furi_string_alloc();
|
||||
instance->history = malloc(sizeof(SubGhzHistoryStruct));
|
||||
SubGhzHistoryItemArray_init(instance->history->data);
|
||||
instance->rpc = furi_record_open(RECORD_RPC);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -52,6 +55,7 @@ void subghz_history_free(SubGhzHistory* instance) {
|
||||
}
|
||||
SubGhzHistoryItemArray_clear(instance->history->data);
|
||||
free(instance->history);
|
||||
furi_record_close(RECORD_RPC);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
@@ -89,26 +93,19 @@ void subghz_history_reset(SubGhzHistory* instance) {
|
||||
instance->code_last_hash_data = 0;
|
||||
}
|
||||
|
||||
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id) {
|
||||
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t idx) {
|
||||
furi_assert(instance);
|
||||
|
||||
SubGhzHistoryItemArray_it_t it;
|
||||
//SubGhzHistoryItem* target_item = SubGhzHistoryItemArray_get(instance->history->data, item_id);
|
||||
SubGhzHistoryItemArray_it_last(it, instance->history->data);
|
||||
while(!SubGhzHistoryItemArray_end_p(it)) {
|
||||
SubGhzHistoryItem* item = SubGhzHistoryItemArray_ref(it);
|
||||
|
||||
if(it->index == (size_t)(item_id)) {
|
||||
furi_string_free(item->item_str);
|
||||
furi_string_free(item->preset->name);
|
||||
free(item->preset);
|
||||
flipper_format_free(item->flipper_string);
|
||||
item->type = 0;
|
||||
SubGhzHistoryItemArray_remove(instance->history->data, it);
|
||||
}
|
||||
SubGhzHistoryItemArray_previous(it);
|
||||
if(idx < SubGhzHistoryItemArray_size(instance->history->data)) {
|
||||
SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
|
||||
furi_string_free(item->item_str);
|
||||
furi_string_free(item->preset->name);
|
||||
free(item->preset);
|
||||
flipper_format_free(item->flipper_string);
|
||||
item->type = 0;
|
||||
SubGhzHistoryItemArray_remove_v(instance->history->data, idx, idx + 1);
|
||||
instance->last_index_write--;
|
||||
}
|
||||
instance->last_index_write--;
|
||||
}
|
||||
|
||||
uint16_t subghz_history_get_item(SubGhzHistory* instance) {
|
||||
@@ -150,15 +147,14 @@ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx
|
||||
bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output) {
|
||||
furi_assert(instance);
|
||||
if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) {
|
||||
if(output != NULL) furi_string_printf(output, " Free heap LOW");
|
||||
if(output != NULL) furi_string_printf(output, " Memory is FULL");
|
||||
return true;
|
||||
}
|
||||
if(instance->last_index_write == SUBGHZ_HISTORY_MAX) {
|
||||
if(output != NULL) furi_string_printf(output, " Memory is FULL");
|
||||
if(output != NULL) furi_string_printf(output, " History is FULL");
|
||||
return true;
|
||||
}
|
||||
if(output != NULL)
|
||||
furi_string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
|
||||
if(output != NULL) furi_string_printf(output, "%02u", instance->last_index_write);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ void subghz_history_free(SubGhzHistory* instance);
|
||||
*/
|
||||
void subghz_history_reset(SubGhzHistory* instance);
|
||||
|
||||
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id);
|
||||
void subghz_history_delete_item(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Get frequency to history[idx]
|
||||
*
|
||||
|
||||
@@ -383,7 +383,16 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
|
||||
#else
|
||||
canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str));
|
||||
#endif
|
||||
canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str));
|
||||
if(!furi_string_empty(model->history_stat_str)) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
114,
|
||||
62,
|
||||
AlignRight,
|
||||
AlignBottom,
|
||||
furi_string_get_cstr(model->history_stat_str));
|
||||
canvas_draw_icon(canvas, 116, 53, &I_sub1_10px);
|
||||
}
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_bold_rounded_frame(canvas, 14, 8, 99, 48);
|
||||
elements_multiline_text(canvas, 65, 26, "To unlock\npress:");
|
||||
@@ -419,7 +428,16 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
|
||||
#else
|
||||
canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str));
|
||||
#endif
|
||||
canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str));
|
||||
if(!furi_string_empty(model->history_stat_str)) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
114,
|
||||
62,
|
||||
AlignRight,
|
||||
AlignBottom,
|
||||
furi_string_get_cstr(model->history_stat_str));
|
||||
canvas_draw_icon(canvas, 116, 53, &I_sub1_10px);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -655,40 +673,32 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver)
|
||||
return idx;
|
||||
}
|
||||
|
||||
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver) {
|
||||
void subghz_view_receiver_delete_item(SubGhzViewReceiver* subghz_receiver, uint16_t idx) {
|
||||
furi_assert(subghz_receiver);
|
||||
|
||||
with_view_model(
|
||||
subghz_receiver->view,
|
||||
SubGhzViewReceiverModel * model,
|
||||
{
|
||||
SubGhzReceiverMenuItemArray_it_t it;
|
||||
// SubGhzReceiverMenuItem* target_item =
|
||||
// SubGhzReceiverMenuItemArray_get(model->history->data, model->idx);
|
||||
SubGhzReceiverMenuItemArray_it_last(it, model->history->data);
|
||||
while(!SubGhzReceiverMenuItemArray_end_p(it)) {
|
||||
SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it);
|
||||
if(idx < SubGhzReceiverMenuItemArray_size(model->history->data)) {
|
||||
SubGhzReceiverMenuItem* item =
|
||||
SubGhzReceiverMenuItemArray_get(model->history->data, idx);
|
||||
furi_string_free(item->item_str);
|
||||
furi_string_free(item->time);
|
||||
item->type = 0;
|
||||
SubGhzReceiverMenuItemArray_remove_v(model->history->data, idx, idx + 1);
|
||||
|
||||
if(it->index == (size_t)(model->idx)) {
|
||||
furi_string_free(item->item_str);
|
||||
furi_string_free(item->time);
|
||||
item->type = 0;
|
||||
SubGhzReceiverMenuItemArray_remove(model->history->data, it);
|
||||
if(model->history_item == 5) {
|
||||
if(model->idx >= 2) {
|
||||
model->idx = model->history_item - 1;
|
||||
}
|
||||
}
|
||||
model->history_item--;
|
||||
|
||||
SubGhzReceiverMenuItemArray_previous(it);
|
||||
}
|
||||
|
||||
if(model->history_item == 5) {
|
||||
if(model->idx >= 2) {
|
||||
model->idx = model->history_item - 1;
|
||||
if(model->idx && (model->idx > idx || model->idx == model->history_item)) {
|
||||
model->idx--;
|
||||
}
|
||||
}
|
||||
model->history_item--;
|
||||
|
||||
if(model->idx != 0) {
|
||||
model->idx--;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver);
|
||||
|
||||
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx);
|
||||
|
||||
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver);
|
||||
void subghz_view_receiver_delete_item(SubGhzViewReceiver* subghz_receiver, uint16_t idx);
|
||||
|
||||
void subghz_view_receiver_enable_draw_callback(SubGhzViewReceiver* subghz_receiver);
|
||||
|
||||
|
||||
@@ -161,6 +161,14 @@ void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str) {
|
||||
u8g2_DrawStr(&canvas->fb, x, y, str);
|
||||
}
|
||||
|
||||
void canvas_draw_utf8_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str) {
|
||||
furi_assert(canvas);
|
||||
if(!str) return;
|
||||
x += canvas->offset_x;
|
||||
y += canvas->offset_y;
|
||||
u8g2_DrawUTF8(&canvas->fb, x, y, str);
|
||||
}
|
||||
|
||||
void canvas_draw_str_aligned(
|
||||
Canvas* canvas,
|
||||
uint8_t x,
|
||||
@@ -204,12 +212,61 @@ void canvas_draw_str_aligned(
|
||||
u8g2_DrawStr(&canvas->fb, x, y, str);
|
||||
}
|
||||
|
||||
void canvas_draw_utf8_str_aligned(
|
||||
Canvas* canvas,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical,
|
||||
const char* str) {
|
||||
furi_assert(canvas);
|
||||
if(!str) return;
|
||||
x += canvas->offset_x;
|
||||
y += canvas->offset_y;
|
||||
|
||||
switch(horizontal) {
|
||||
case AlignLeft:
|
||||
break;
|
||||
case AlignRight:
|
||||
x -= u8g2_GetUTF8Width(&canvas->fb, str);
|
||||
break;
|
||||
case AlignCenter:
|
||||
x -= (u8g2_GetUTF8Width(&canvas->fb, str) / 2);
|
||||
break;
|
||||
default:
|
||||
furi_crash();
|
||||
break;
|
||||
}
|
||||
|
||||
switch(vertical) {
|
||||
case AlignTop:
|
||||
y += u8g2_GetAscent(&canvas->fb);
|
||||
break;
|
||||
case AlignBottom:
|
||||
break;
|
||||
case AlignCenter:
|
||||
y += (u8g2_GetAscent(&canvas->fb) / 2);
|
||||
break;
|
||||
default:
|
||||
furi_crash();
|
||||
break;
|
||||
}
|
||||
|
||||
u8g2_DrawUTF8(&canvas->fb, x, y, str);
|
||||
}
|
||||
|
||||
uint16_t canvas_string_width(Canvas* canvas, const char* str) {
|
||||
furi_assert(canvas);
|
||||
if(!str) return 0;
|
||||
return u8g2_GetStrWidth(&canvas->fb, str);
|
||||
}
|
||||
|
||||
uint16_t canvas_utf8_string_width(Canvas* canvas, const char* str) {
|
||||
furi_assert(canvas);
|
||||
if(!str) return 0;
|
||||
return u8g2_GetUTF8Width(&canvas->fb, str);
|
||||
}
|
||||
|
||||
uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol) {
|
||||
furi_assert(canvas);
|
||||
return u8g2_GetGlyphWidth(&canvas->fb, symbol);
|
||||
|
||||
@@ -187,6 +187,15 @@ void canvas_set_custom_u8g2_font(Canvas* canvas, const uint8_t* font);
|
||||
*/
|
||||
void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str);
|
||||
|
||||
/** Draw UTF8 string at position of baseline defined by x, y.
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x anchor point x coordinate
|
||||
* @param y anchor point y coordinate
|
||||
* @param str C-string
|
||||
*/
|
||||
void canvas_draw_utf8_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str);
|
||||
|
||||
/** Draw aligned string defined by x, y.
|
||||
*
|
||||
* Align calculated from position of baseline, string width and ascent (height
|
||||
@@ -207,6 +216,26 @@ void canvas_draw_str_aligned(
|
||||
Align vertical,
|
||||
const char* str);
|
||||
|
||||
/** Draw aligned UTF8 string defined by x, y.
|
||||
*
|
||||
* Align calculated from position of baseline, string width and ascent (height
|
||||
* of the glyphs above the baseline)
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x anchor point x coordinate
|
||||
* @param y anchor point y coordinate
|
||||
* @param horizontal horizontal alignment
|
||||
* @param vertical vertical alignment
|
||||
* @param str C-string
|
||||
*/
|
||||
void canvas_draw_utf8_str_aligned(
|
||||
Canvas* canvas,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical,
|
||||
const char* str);
|
||||
|
||||
/** Get string width
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
@@ -216,6 +245,15 @@ void canvas_draw_str_aligned(
|
||||
*/
|
||||
uint16_t canvas_string_width(Canvas* canvas, const char* str);
|
||||
|
||||
/** Get UTF8 string width
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param str C-string
|
||||
*
|
||||
* @return width in pixels.
|
||||
*/
|
||||
uint16_t canvas_utf8_string_width(Canvas* canvas, const char* str);
|
||||
|
||||
/** Get glyph width
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
|
||||
@@ -87,6 +87,7 @@ struct RpcSession {
|
||||
|
||||
struct Rpc {
|
||||
FuriMutex* busy_mutex;
|
||||
size_t sessions_count;
|
||||
};
|
||||
|
||||
RpcOwner rpc_session_get_owner(RpcSession* session) {
|
||||
@@ -407,6 +408,8 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) {
|
||||
|
||||
furi_thread_start(session->thread);
|
||||
|
||||
rpc->sessions_count++;
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
@@ -414,6 +417,8 @@ void rpc_session_close(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
furi_assert(session->rpc);
|
||||
|
||||
session->rpc->sessions_count--;
|
||||
|
||||
rpc_session_set_send_bytes_callback(session, NULL);
|
||||
rpc_session_set_close_callback(session, NULL);
|
||||
rpc_session_set_buffer_is_empty_callback(session, NULL);
|
||||
@@ -489,3 +494,7 @@ void rpc_send_and_release_empty(RpcSession* session, uint32_t command_id, PB_Com
|
||||
rpc_send_and_release(session, &message);
|
||||
pb_release(&PB_Main_msg, &message);
|
||||
}
|
||||
|
||||
size_t rpc_get_sessions_count(Rpc* rpc) {
|
||||
return rpc->sessions_count;
|
||||
}
|
||||
|
||||
@@ -134,6 +134,13 @@ size_t rpc_session_feed(RpcSession* session, uint8_t* buffer, size_t size, uint3
|
||||
*/
|
||||
size_t rpc_session_get_available_size(RpcSession* session);
|
||||
|
||||
/** Get number of open RPC sessions
|
||||
*
|
||||
* @param rpc instance
|
||||
* @return sessions count
|
||||
*/
|
||||
size_t rpc_get_sessions_count(Rpc* rpc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user