Merge remote-tracking branch 'origin/dev' into release-candidate

This commit is contained in:
Aleksandr Kutuzov 2023-12-19 14:17:20 +00:00
commit c0be669a30
52 changed files with 1558 additions and 728 deletions

View File

@ -7,35 +7,62 @@
//This arrays contains the font itself. You can use any u8g2 font you want //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 Fontname: -Misc-Fixed-Medium-R-Normal--6-60-75-75-C-40-ISO10646-1
Copyright: Copyright: Public domain font. Share and enjoy.
Glyphs: 95/203 Glyphs: 191/919
BBX Build Mode: 0 BBX Build Mode: 0
*/ */
const uint8_t u8g2_font_tom_thumb_4x6_tr[725] = const uint8_t u8g2_font_4x6_t_cyrillic[] =
"_\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" "\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\213\313$\25#\10\227\310\244\241\206\12$\10\227\310\215\70b\2%\10\227\310d\324F\1" "\254\0\42\6\223\313$\25#\12\254\310\244\64T\32*\1$\11\263\307\245\241\301H\11%\10\253\310d"
"&\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" "\324F\1&\11\254\310\305\24\253\230\2'\5\321\313\10(\7\362\307\251f\0)\10\262\307\304T)\0"
"\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\253\310\244j\65+\10\253\310\305\264b\2,\6\222\307)\0-\5\213\312\14.\5\311\310\4/"
"\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" "\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"
"\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" "\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"
"\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" "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"
"d\20=\6\217\311l\60>\11\227\310d\220A*\1\77\10\227\310\314\224a\2@\10\227\310UC\3" "\253\310\246\32d\20=\6\233\311l\60>\11\253\310d\220A*\1\77\11\253\310h\220\62L\0@\7"
"\1A\10\227\310UC\251\0B\10\227\310\250\264\322\2C\7\227\310\315\32\10D\10\227\310\250d-\0" "\253\310-\33\10A\10\253\310UC\251\0B\10\253\310\250\264\322\2C\10\253\310U\62U\0D\10\253"
"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" "\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"
"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$\65\224\12I\7\253\310\254X\15J\7\253\310\226\252\2K\10\253\310$\265\222\12L\7\253\310\304"
"\310\244\61\224\12N\10\227\310\244q\250\0O\7\227\310UV\5P\10\227\310\250\264b\4Q\10\227\310" "\346\0M\10\253\310\244\61\224\12N\10\253\310\252\241$\0O\7\253\310UV\5P\10\253\310\250\264b"
"Uj$\1R\10\227\310\250\64V\1S\10\227\310m\220\301\2T\7\227\310\254\330\2U\7\227\310$" "\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"
"W\22V\10\227\310$\253L\0W\10\227\310$\65\206\12X\10\227\310$\325R\1Y\10\227\310$U" "U\7\253\310$\327\10V\10\253\310$k\244\4W\10\253\310$\65\206\12X\10\253\310$\325R\1Y"
"V\0Z\7\227\310\314T\16[\7\227\310\214X\16\134\10\217\311d\220A\0]\7\227\310\314r\4^" "\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"
"\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" "\310\250j^\5\223\313\65_\5\213\307\14`\6\322\313\304\0a\7\243\310-\225\4b\10\253\310D\225"
"\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" "\324\2c\7\243\310\315\14\4d\10\253\310\246\245\222\0e\6\243\310USf\10\253\310\246\264b\2g"
"\61%\0h\10\227\310D\225\254\0i\6\265\310\244\1j\10\233\307f\30U\5k\10\227\310\304\264T" "\10\253\307\255$\27\0h\10\253\310D\225\254\0i\10\253\310e$\323\0j\10\263\307fX.\0k"
"\1l\7\227\310\310\326\0m\7\223\310<R\0n\7\223\310\250d\5o\7\223\310U\252\2p\10\227" "\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"
"\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" "\310U\252\2p\10\253\307\250\264b\4q\10\253\307-\225d\0r\10\243\310\244\25#\0s\10\243\310"
"\25\243\0u\7\223\310$+\11v\10\223\310$\65R\2w\7\223\310\244q\4x\7\223\310\244\62\25" "\215\14\26\0t\10\253\310\245\25\63\10u\7\243\310$+\11v\7\243\310$\253\2w\10\243\310$\65"
"y\11\227\307$\225dJ\0z\7\223\310\254\221\6{\10\227\310\251\32D\1|\6\265\310(\1}\11" "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"
"\227\310\310\14RR\0~\6\213\313\215\4\0\0\0\4\377\377\0"; "|\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 // Screen is 128x64 px
static void app_draw_callback(Canvas* canvas, void* ctx) { 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_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, 6, "This is a tiny custom font");
canvas_draw_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%"); canvas_draw_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%");
canvas_draw_str(canvas, 0, 18, "И немного юникода");
} }
static void app_input_callback(InputEvent* input_event, void* ctx) { static void app_input_callback(InputEvent* input_event, void* ctx) {

View File

@ -12,7 +12,7 @@
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h> #include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h>
#include <nfc/protocols/mf_classic/mf_classic_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 <nfc/nfc.h>
#include "../minunit.h" #include "../minunit.h"
@ -443,36 +443,36 @@ MU_TEST(mf_classic_dict_test) {
"Remove test dict failed"); "Remove test dict failed");
} }
NfcDict* dict = nfc_dict_alloc( KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
mu_assert(dict != NULL, "nfc_dict_alloc() failed"); mu_assert(dict != NULL, "keys_dict_alloc() failed");
size_t dict_keys_total = nfc_dict_get_total_keys(dict); size_t dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(dict_keys_total == 0, "nfc_dict_keys_total() failed"); mu_assert(dict_keys_total == 0, "keys_dict_keys_total() failed");
const uint32_t test_key_num = 30; const uint32_t test_key_num = 30;
MfClassicKey* key_arr_ref = malloc(test_key_num * sizeof(MfClassicKey)); MfClassicKey* key_arr_ref = malloc(test_key_num * sizeof(MfClassicKey));
for(size_t i = 0; i < test_key_num; i++) { for(size_t i = 0; i < test_key_num; i++) {
furi_hal_random_fill_buf(key_arr_ref[i].data, sizeof(MfClassicKey)); furi_hal_random_fill_buf(key_arr_ref[i].data, sizeof(MfClassicKey));
mu_assert( 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); size_t dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(dict_keys_total == (i + 1), "nfc_dict_keys_total() failed"); mu_assert(dict_keys_total == (i + 1), "keys_dict_keys_total() failed");
} }
nfc_dict_free(dict); keys_dict_free(dict);
dict = nfc_dict_alloc( dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
mu_assert(dict != NULL, "nfc_dict_alloc() failed"); mu_assert(dict != NULL, "keys_dict_alloc() 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, "nfc_dict_keys_total() failed"); mu_assert(dict_keys_total == test_key_num, "keys_dict_keys_total() failed");
MfClassicKey key_dut = {}; MfClassicKey key_dut = {};
size_t key_idx = 0; 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( mu_assert(
memcmp(key_arr_ref[key_idx].data, key_dut.data, sizeof(MfClassicKey)) == 0, memcmp(key_arr_ref[key_idx].data, key_dut.data, sizeof(MfClassicKey)) == 0,
"Loaded key data mismatch"); "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++) { for(size_t i = 0; i < COUNT_OF(delete_keys_idx); i++) {
MfClassicKey* key = &key_arr_ref[delete_keys_idx[i]]; MfClassicKey* key = &key_arr_ref[delete_keys_idx[i]];
mu_assert( mu_assert(
nfc_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)), keys_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)),
"nfc_dict_is_key_present() failed"); "keys_dict_is_key_present() failed");
mu_assert( mu_assert(
nfc_dict_delete_key(dict, key->data, sizeof(MfClassicKey)), keys_dict_delete_key(dict, key->data, sizeof(MfClassicKey)),
"nfc_dict_delete_key() failed"); "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( mu_assert(
dict_keys_total == test_key_num - COUNT_OF(delete_keys_idx), 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); free(key_arr_ref);
mu_assert( mu_assert(

View File

@ -27,6 +27,7 @@ static const uint32_t baudrate_list[] = {
460800, 460800,
921600, 921600,
}; };
static const char* software_de_re[] = {"None", "4"};
bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) { bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) {
GpioApp* app = context; GpioApp* app = context;
@ -84,6 +85,17 @@ static void line_port_cb(VariableItem* item) {
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet); 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) { static void line_flow_cb(VariableItem* item) {
GpioApp* app = variable_item_get_context(item); GpioApp* app = variable_item_get_context(item);
furi_assert(app); furi_assert(app);
@ -155,6 +167,11 @@ void gpio_scene_usb_uart_cfg_on_enter(void* context) {
app->var_item_flow = item; app->var_item_flow = item;
line_ensure_flow_invariant(app); 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( variable_item_list_set_selected_item(
var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUartCfg)); var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUartCfg));

View File

@ -6,11 +6,16 @@
#include <furi_hal.h> #include <furi_hal.h>
#include <furi_hal_usb_cdc.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_CDC_PKT_LEN CDC_DATA_SZ
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) #define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
#define USB_CDC_BIT_DTR (1 << 0) #define USB_CDC_BIT_DTR (1 << 0)
#define USB_CDC_BIT_RTS (1 << 1) #define USB_CDC_BIT_RTS (1 << 1)
#define USB_USART_DE_RE_PIN &gpio_ext_pa4
static const GpioPin* flow_pins[][2] = { static const GpioPin* flow_pins[][2] = {
{&gpio_ext_pa7, &gpio_ext_pa6}, // 2, 3 {&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; usb_uart->cfg.flow_pins = usb_uart->cfg_new.flow_pins;
events |= WorkerEvtCtrlLineSet; 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); api_lock_unlock(usb_uart->cfg_lock);
} }
if(events & WorkerEvtLineCfgSet) { 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_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch);
usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_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) { 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][0], GpioModeAnalog);
furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], 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) { if(len > 0) {
usb_uart->st.tx_cnt += len; 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); 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);
}
} }
} }
} }

View File

@ -11,6 +11,7 @@ typedef struct {
uint8_t flow_pins; uint8_t flow_pins;
uint8_t baudrate_mode; uint8_t baudrate_mode;
uint32_t baudrate; uint32_t baudrate;
uint8_t software_de_re;
} UsbUartConfig; } UsbUartConfig;
typedef struct { typedef struct {

View File

@ -2,6 +2,7 @@ Filetype: IR library file
Version: 1 Version: 1
# #
# Model: Electrolux EACM-16 HP/N3 # Model: Electrolux EACM-16 HP/N3
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -39,6 +40,7 @@ duty_cycle: 0.33
data: 506 3430 506 478 506 479 505 480 504 481 503 482 502 484 500 1463 505 1465 503 482 502 483 501 484 500 485 509 476 508 477 507 478 506 486 508 477 507 478 506 479 505 480 504 481 503 482 502 483 500 523 502 482 502 483 501 484 500 485 509 476 508 478 506 1455 502 498 507 478 506 479 505 481 503 482 501 483 500 484 500 485 509 500 505 481 502 482 502 1461 507 1455 502 1459 509 476 508 477 507 563 504 1453 504 1454 503 1454 503 1453 504 3426 499 data: 506 3430 506 478 506 479 505 480 504 481 503 482 502 484 500 1463 505 1465 503 482 502 483 501 484 500 485 509 476 508 477 507 478 506 486 508 477 507 478 506 479 505 480 504 481 503 482 502 483 500 523 502 482 502 483 501 484 500 485 509 476 508 478 506 1455 502 498 507 478 506 479 505 481 503 482 501 483 500 484 500 485 509 500 505 481 502 482 502 1461 507 1455 502 1459 509 476 508 477 507 563 504 1453 504 1454 503 1454 503 1453 504 3426 499
# #
# Model: Hisense Generic # Model: Hisense Generic
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -76,6 +78,7 @@ duty_cycle: 0.330000
data: 8972 4491 592 1651 592 1655 598 532 599 535 597 542 600 541 601 544 598 1656 597 526 595 1652 591 1658 595 539 593 545 597 545 597 546 596 537 594 529 592 535 596 1653 600 534 597 541 601 539 592 552 600 533 598 525 596 530 591 538 593 539 592 1665 598 1662 591 1673 601 533 598 526 595 533 598 532 600 534 597 540 591 548 594 550 592 542 600 523 598 528 593 536 595 537 594 543 599 542 600 543 599 517 594 7937 593 531 601 526 595 535 597 537 594 542 600 541 601 543 599 1654 599 523 598 528 593 536 596 538 594 542 600 541 590 552 600 532 599 524 597 528 593 536 595 537 595 541 601 539 593 551 591 542 600 522 599 527 594 536 595 537 594 543 599 540 591 552 600 532 600 523 598 527 594 535 596 537 595 542 600 540 591 552 600 532 600 523 598 528 593 536 595 538 593 543 599 541 601 543 599 535 596 527 594 532 600 531 601 534 597 540 592 549 593 552 600 534 597 525 596 529 592 1655 598 534 597 1656 597 1661 592 1671 592 1644 599 7934 596 529 592 535 597 535 597 538 593 544 598 543 599 545 597 538 593 1650 593 535 596 534 597 536 595 540 591 547 595 547 595 536 595 526 595 529 592 536 595 535 596 539 593 546 596 547 595 538 593 528 593 531 601 529 592 541 601 536 596 545 597 548 594 540 592 532 600 526 595 535 596 1656 597 541 601 540 592 553 599 534 597 526 595 532 599 531 600 533 598 539 593 548 594 552 600 535 596 1647 596 531 590 538 593 1656 597 538 594 545 597 545 597 518 593 data: 8972 4491 592 1651 592 1655 598 532 599 535 597 542 600 541 601 544 598 1656 597 526 595 1652 591 1658 595 539 593 545 597 545 597 546 596 537 594 529 592 535 596 1653 600 534 597 541 601 539 592 552 600 533 598 525 596 530 591 538 593 539 592 1665 598 1662 591 1673 601 533 598 526 595 533 598 532 600 534 597 540 591 548 594 550 592 542 600 523 598 528 593 536 595 537 594 543 599 542 600 543 599 517 594 7937 593 531 601 526 595 535 597 537 594 542 600 541 601 543 599 1654 599 523 598 528 593 536 596 538 594 542 600 541 590 552 600 532 599 524 597 528 593 536 595 537 595 541 601 539 593 551 591 542 600 522 599 527 594 536 595 537 594 543 599 540 591 552 600 532 600 523 598 527 594 535 596 537 595 542 600 540 591 552 600 532 600 523 598 528 593 536 595 538 593 543 599 541 601 543 599 535 596 527 594 532 600 531 601 534 597 540 592 549 593 552 600 534 597 525 596 529 592 1655 598 534 597 1656 597 1661 592 1671 592 1644 599 7934 596 529 592 535 597 535 597 538 593 544 598 543 599 545 597 538 593 1650 593 535 596 534 597 536 595 540 591 547 595 547 595 536 595 526 595 529 592 536 595 535 596 539 593 546 596 547 595 538 593 528 593 531 601 529 592 541 601 536 596 545 597 548 594 540 592 532 600 526 595 535 596 1656 597 541 601 540 592 553 599 534 597 526 595 532 599 531 600 533 598 539 593 548 594 552 600 535 596 1647 596 531 590 538 593 1656 597 538 594 545 597 545 597 518 593
# #
# Model: Daichi DA25AVQS1-W # Model: Daichi DA25AVQS1-W
#
name: Dh name: Dh
type: raw type: raw
frequency: 38000 frequency: 38000
@ -113,6 +116,7 @@ duty_cycle: 0.330000
data: 9106 4398 731 499 706 500 705 502 702 504 701 505 701 505 701 1606 701 505 701 1607 701 505 701 506 700 1607 700 506 700 506 700 505 700 505 701 506 700 506 700 506 699 506 700 506 700 1607 700 506 700 506 700 506 700 505 701 506 700 506 700 1608 699 506 700 1608 699 506 700 506 700 1608 700 506 700 19941 701 1606 700 505 701 505 701 506 700 505 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 701 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 699 506 700 506 700 1608 700 1607 700 506 700 506 700 data: 9106 4398 731 499 706 500 705 502 702 504 701 505 701 505 701 1606 701 505 701 1607 701 505 701 506 700 1607 700 506 700 506 700 505 700 505 701 506 700 506 700 506 699 506 700 506 700 1607 700 506 700 506 700 506 700 505 701 506 700 506 700 1608 699 506 700 1608 699 506 700 506 700 1608 700 506 700 19941 701 1606 700 505 701 505 701 506 700 505 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 701 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 700 506 699 506 700 506 700 1608 700 1607 700 506 700 506 700
# #
# Model: Saturn CS-TL09CHR # Model: Saturn CS-TL09CHR
#
name: Dh name: Dh
type: raw type: raw
frequency: 38000 frequency: 38000
@ -150,6 +154,7 @@ duty_cycle: 0.330000
data: 3013 1709 463 1085 462 1084 463 387 461 355 469 355 444 1084 463 387 461 378 436 1084 462 1084 487 355 469 1059 463 387 460 355 444 1083 463 1098 464 386 437 1083 463 1083 489 361 463 360 463 1082 464 361 462 376 462 1085 461 363 460 364 459 364 459 365 458 365 459 364 459 380 459 365 458 365 458 365 458 365 458 365 458 365 458 365 459 380 458 365 459 365 458 365 459 365 458 365 458 1089 458 365 458 380 459 1088 459 365 458 365 458 365 458 365 459 365 458 365 458 381 458 365 458 365 458 365 458 1089 458 365 458 365 458 365 458 381 458 365 458 365 458 365 458 365 458 365 458 365 458 365 458 381 457 366 457 366 457 366 457 366 457 366 458 365 458 366 457 381 458 366 458 366 457 366 457 366 457 366 457 366 457 366 457 381 458 366 457 366 457 366 457 366 457 366 457 366 457 366 457 382 457 366 457 366 457 366 457 366 457 366 457 367 457 366 457 382 457 367 456 1090 457 1090 456 1090 457 1090 457 1090 456 367 457 372 457 data: 3013 1709 463 1085 462 1084 463 387 461 355 469 355 444 1084 463 387 461 378 436 1084 462 1084 487 355 469 1059 463 387 460 355 444 1083 463 1098 464 386 437 1083 463 1083 489 361 463 360 463 1082 464 361 462 376 462 1085 461 363 460 364 459 364 459 365 458 365 459 364 459 380 459 365 458 365 458 365 458 365 458 365 458 365 458 365 459 380 458 365 459 365 458 365 459 365 458 365 458 1089 458 365 458 380 459 1088 459 365 458 365 458 365 458 365 459 365 458 365 458 381 458 365 458 365 458 365 458 1089 458 365 458 365 458 365 458 381 458 365 458 365 458 365 458 365 458 365 458 365 458 365 458 381 457 366 457 366 457 366 457 366 457 366 458 365 458 366 457 381 458 366 458 366 457 366 457 366 457 366 457 366 457 366 457 381 458 366 457 366 457 366 457 366 457 366 457 366 457 366 457 382 457 366 457 366 457 366 457 366 457 366 457 367 457 366 457 382 457 367 456 1090 457 1090 456 1090 457 1090 457 1090 456 367 457 372 457
# #
# Model: Olimpia Splendid OS-SEAMH09EI # Model: Olimpia Splendid OS-SEAMH09EI
#
name: Dh name: Dh
type: raw type: raw
frequency: 38000 frequency: 38000
@ -186,7 +191,8 @@ frequency: 38000
duty_cycle: 0.330000 duty_cycle: 0.330000
data: 4403 4333 563 1615 563 528 561 1618 560 1618 560 531 558 561 538 1614 564 556 533 558 541 1611 557 562 537 555 534 1619 559 1618 560 558 541 1613 565 551 538 1614 564 1614 564 1614 564 1613 565 528 561 1617 561 1619 559 1617 561 557 532 535 564 528 561 533 566 1611 557 562 537 558 531 1619 559 1619 559 1619 559 559 540 553 536 557 532 561 538 557 532 559 540 553 536 557 532 1620 558 1620 558 1620 558 1620 558 1618 560 5188 4398 4346 561 1618 560 558 531 1621 557 1621 557 561 538 555 534 1619 559 561 538 553 536 1616 562 556 533 560 539 1614 564 1613 565 554 535 1619 559 557 532 1621 557 1620 558 1620 558 1620 558 560 539 1613 565 1615 563 1613 565 553 536 557 532 535 564 554 535 1618 560 558 531 564 535 1615 563 1615 563 1614 564 555 534 559 540 552 537 530 559 536 563 528 561 532 557 562 537 1615 563 1615 563 1614 564 1614 564 1616 562 data: 4403 4333 563 1615 563 528 561 1618 560 1618 560 531 558 561 538 1614 564 556 533 558 541 1611 557 562 537 555 534 1619 559 1618 560 558 541 1613 565 551 538 1614 564 1614 564 1614 564 1613 565 528 561 1617 561 1619 559 1617 561 557 532 535 564 528 561 533 566 1611 557 562 537 558 531 1619 559 1619 559 1619 559 559 540 553 536 557 532 561 538 557 532 559 540 553 536 557 532 1620 558 1620 558 1620 558 1620 558 1618 560 5188 4398 4346 561 1618 560 558 531 1621 557 1621 557 561 538 555 534 1619 559 561 538 553 536 1616 562 556 533 560 539 1614 564 1613 565 554 535 1619 559 557 532 1621 557 1620 558 1620 558 1620 558 560 539 1613 565 1615 563 1613 565 553 536 557 532 535 564 554 535 1618 560 558 531 564 535 1615 563 1615 563 1614 564 555 534 559 540 552 537 530 559 536 563 528 561 532 557 562 537 1615 563 1615 563 1614 564 1614 564 1616 562
# #
# Model: Sharp AH-X9VEW. Doesn't have heat function. # Model: Sharp AH-X9VEW. Doesn't have heat function
#
name: Dh name: Dh
type: raw type: raw
frequency: 38000 frequency: 38000
@ -211,7 +217,8 @@ frequency: 38000
duty_cycle: 0.330000 duty_cycle: 0.330000
data: 3826 1866 490 481 482 1382 461 484 490 1392 461 467 486 1396 457 471 482 1400 464 479 463 1390 463 481 482 1399 465 1398 518 401 510 1379 464 480 483 1398 456 1408 487 1392 482 1399 517 386 483 487 466 1399 486 1392 461 483 459 470 462 482 460 469 484 1397 456 473 459 459 483 472 460 484 458 471 461 483 459 1411 463 480 462 467 486 1377 487 1392 482 1396 457 486 456 472 460 486 456 473 480 1400 464 465 456 488 454 475 488 1393 460 468 464 480 462 467 486 1395 458 470 462 483 459 485 436 493 460 469 463 481 461 486 435 500 463 463 458 486 456 1397 488 1390 484 1394 480 1400 464 465 456 488 465 464 457 487 455 474 458 487 455 473 459 485 457 472 460 485 457 472 481 1399 517 401 458 497 456 473 459 485 457 487 434 495 458 471 461 484 458 488 433 502 430 507 435 500 432 498 455 1409 486 1392 482 1399 454 1409 455 488 465 480 462 467 465 480 462 1408 456 473 459 486 488 data: 3826 1866 490 481 482 1382 461 484 490 1392 461 467 486 1396 457 471 482 1400 464 479 463 1390 463 481 482 1399 465 1398 518 401 510 1379 464 480 483 1398 456 1408 487 1392 482 1399 517 386 483 487 466 1399 486 1392 461 483 459 470 462 482 460 469 484 1397 456 473 459 459 483 472 460 484 458 471 461 483 459 1411 463 480 462 467 486 1377 487 1392 482 1396 457 486 456 472 460 486 456 473 480 1400 464 465 456 488 454 475 488 1393 460 468 464 480 462 467 486 1395 458 470 462 483 459 485 436 493 460 469 463 481 461 486 435 500 463 463 458 486 456 1397 488 1390 484 1394 480 1400 464 465 456 488 465 464 457 487 455 474 458 487 455 473 459 485 457 472 460 485 457 472 481 1399 517 401 458 497 456 473 459 485 457 487 434 495 458 471 461 484 458 488 433 502 430 507 435 500 432 498 455 1409 486 1392 482 1399 454 1409 455 488 465 480 462 467 465 480 462 1408 456 473 459 486 488
# #
# Model: Electrolux ESV09CRO-B21. Doesn't have heat function. # Model: Electrolux ESV09CRO-B21. Doesn't have heat function
#
name: Dh name: Dh
type: raw type: raw
frequency: 38000 frequency: 38000
@ -236,7 +243,8 @@ frequency: 38000
duty_cycle: 0.330000 duty_cycle: 0.330000
data: 3093 3058 3090 4441 576 1652 579 528 571 1654 577 531 579 526 573 1652 579 1649 582 525 574 1652 579 528 571 1654 577 1651 580 527 572 533 577 528 571 533 577 1649 582 1646 574 1653 578 529 581 525 574 530 580 525 574 530 580 525 574 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 532 578 1647 573 533 577 1648 572 535 575 530 569 535 575 530 580 525 574 531 579 525 574 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 1651 580 527 572 533 577 528 571 533 577 528 571 533 577 528 571 533 577 528 571 534 576 528 571 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 1649 582 525 574 1650 581 1647 573 1654 577 1651 580 1647 573 1654 577 531 579 1646 574 1653 578 data: 3093 3058 3090 4441 576 1652 579 528 571 1654 577 531 579 526 573 1652 579 1649 582 525 574 1652 579 528 571 1654 577 1651 580 527 572 533 577 528 571 533 577 1649 582 1646 574 1653 578 529 581 525 574 530 580 525 574 530 580 525 574 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 532 578 1647 573 533 577 1648 572 535 575 530 569 535 575 530 580 525 574 531 579 525 574 531 579 526 573 531 579 526 573 531 579 526 573 531 579 526 573 1651 580 527 572 533 577 528 571 533 577 528 571 533 577 528 571 533 577 528 571 534 576 528 571 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 529 570 534 576 1649 582 525 574 1650 581 1647 573 1654 577 1651 580 1647 573 1654 577 531 579 1646 574 1653 578
# #
# Model: Daikin FTE35KV1. Doesn't have heat function. # Model: Daikin FTE35KV1. Doesn't have heat function
#
name: Dh name: Dh
type: raw type: raw
frequency: 38000 frequency: 38000
@ -262,6 +270,7 @@ duty_cycle: 0.330000
data: 5043 2132 361 1770 356 723 335 715 332 718 329 1774 363 715 332 719 328 722 336 714 333 1770 356 722 336 1767 360 1772 354 724 334 1769 357 1774 363 1768 358 1773 364 1767 359 720 327 723 335 1768 359 720 327 723 335 716 331 719 328 722 336 714 333 1770 356 1774 363 1769 357 1773 364 1767 360 720 327 1775 362 1769 357 721 326 725 333 717 330 720 327 723 335 716 331 719 328 722 336 714 333 717 330 720 327 723 335 1768 359 1773 364 1767 360 1772 354 724 334 717 330 720 327 723 335 29451 5041 2134 359 1772 354 724 334 717 330 720 327 1775 362 717 330 720 327 723 335 715 332 1771 355 723 335 1768 358 1773 364 715 332 1770 357 1775 362 1769 357 1774 363 1768 359 720 327 723 335 1768 359 720 327 724 334 716 331 719 328 722 336 715 332 718 329 720 327 723 335 716 331 1771 355 1776 361 718 329 721 326 1776 361 718 329 1773 364 1767 360 720 327 723 335 715 332 718 329 1774 363 1768 359 720 327 723 335 1768 358 721 326 724 334 716 331 719 328 722 336 1767 360 719 328 722 336 715 332 718 329 721 326 724 334 717 330 720 327 723 335 715 332 719 328 722 325 725 333 717 330 720 327 723 335 716 331 719 328 1774 363 716 331 1771 355 1776 361 718 329 721 326 724 334 717 330 1772 365 714 333 1770 356 722 336 715 332 718 329 721 326 724 334 717 330 719 328 1775 362 717 330 720 327 723 335 715 332 718 329 1774 363 715 332 718 329 721 326 725 333 717 330 1772 365 data: 5043 2132 361 1770 356 723 335 715 332 718 329 1774 363 715 332 719 328 722 336 714 333 1770 356 722 336 1767 360 1772 354 724 334 1769 357 1774 363 1768 358 1773 364 1767 359 720 327 723 335 1768 359 720 327 723 335 716 331 719 328 722 336 714 333 1770 356 1774 363 1769 357 1773 364 1767 360 720 327 1775 362 1769 357 721 326 725 333 717 330 720 327 723 335 716 331 719 328 722 336 714 333 717 330 720 327 723 335 1768 359 1773 364 1767 360 1772 354 724 334 717 330 720 327 723 335 29451 5041 2134 359 1772 354 724 334 717 330 720 327 1775 362 717 330 720 327 723 335 715 332 1771 355 723 335 1768 358 1773 364 715 332 1770 357 1775 362 1769 357 1774 363 1768 359 720 327 723 335 1768 359 720 327 724 334 716 331 719 328 722 336 715 332 718 329 720 327 723 335 716 331 1771 355 1776 361 718 329 721 326 1776 361 718 329 1773 364 1767 360 720 327 723 335 715 332 718 329 1774 363 1768 359 720 327 723 335 1768 358 721 326 724 334 716 331 719 328 722 336 1767 360 719 328 722 336 715 332 718 329 721 326 724 334 717 330 720 327 723 335 715 332 719 328 722 325 725 333 717 330 720 327 723 335 716 331 719 328 1774 363 716 331 1771 355 1776 361 718 329 721 326 724 334 717 330 1772 365 714 333 1770 356 722 336 715 332 718 329 721 326 724 334 717 330 719 328 1775 362 717 330 720 327 723 335 715 332 718 329 1774 363 715 332 718 329 721 326 725 333 717 330 1772 365
# #
# Model: Dyson Purifier Hot+Cool # Model: Dyson Purifier Hot+Cool
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -298,7 +307,8 @@ frequency: 38000
duty_cycle: 0.330000 duty_cycle: 0.330000
data: 2320 634 837 637 838 637 838 640 835 642 832 1378 836 645 826 670 809 667 808 1406 806 672 803 674 802 1412 802 1412 800 676 801 675 802 1412 802 674 802 1413 801 1412 801 1413 802 1412 802 50937 2285 671 801 1411 802 51225 2280 696 775 1412 801 51212 2283 671 775 1412 802 data: 2320 634 837 637 838 637 838 640 835 642 832 1378 836 645 826 670 809 667 808 1406 806 672 803 674 802 1412 802 1412 800 676 801 675 802 1412 802 674 802 1413 801 1412 801 1413 802 1412 802 50937 2285 671 801 1411 802 51225 2280 696 775 1412 801 51212 2283 671 775 1412 802
# #
# Model: Daikin FTXM20M. # Model: Daikin FTXM20M
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -335,7 +345,8 @@ frequency: 38000
duty_cycle: 0.330000 duty_cycle: 0.330000
data: 503 365 500 364 501 366 499 365 500 364 502 25049 3535 1660 504 1228 503 390 474 391 473 393 471 1261 469 397 468 397 469 397 469 397 469 1264 468 398 468 1264 468 1264 468 398 468 1265 467 1265 467 1265 467 1265 467 1265 467 399 467 399 467 1266 466 399 467 400 466 400 466 400 466 423 443 423 443 401 465 423 442 424 442 424 442 1290 442 424 442 1290 442 424 442 424 441 424 442 1290 442 1291 441 425 441 424 442 425 441 425 441 1291 441 425 440 425 441 425 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 426 440 1292 440 1292 440 1292 440 426 440 426 440 1292 440 1293 439 1293 439 35480 3503 1696 467 1264 468 398 468 398 467 398 468 1265 467 398 467 399 467 399 466 399 467 1265 467 399 467 1266 466 1267 465 400 466 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 442 1290 442 424 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 425 441 425 441 1291 441 425 441 425 441 425 441 425 440 1292 440 425 441 425 440 426 440 426 440 426 440 426 440 426 440 426 440 426 440 426 439 427 439 426 440 426 440 1293 439 427 439 427 439 427 438 427 439 428 438 1294 438 428 437 428 438 1295 437 1319 413 453 413 35480 3503 1696 468 1265 467 398 468 398 468 398 468 1265 467 398 468 399 466 399 467 399 467 1266 466 399 466 1267 465 1290 442 401 465 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 441 1291 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 424 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 425 441 425 441 1292 440 426 440 426 440 1292 440 426 440 426 440 1293 439 426 440 426 440 1293 439 1293 439 1293 439 427 439 1294 438 427 438 427 439 427 438 428 438 428 438 428 438 428 438 453 413 429 437 453 413 1319 413 1320 412 1320 412 1320 412 454 412 1320 412 454 412 1321 411 1321 411 1321 411 1321 411 1321 411 455 410 455 411 455 411 455 410 456 410 456 410 456 410 481 384 481 385 482 383 482 383 483 358 507 359 1374 358 1374 358 508 358 508 358 508 358 509 357 509 357 535 331 535 331 535 330 535 330 536 330 1403 329 1403 329 563 302 564 301 564 302 564 301 565 301 591 274 619 246 593 273 620 245 620 245 621 245 673 189 data: 503 365 500 364 501 366 499 365 500 364 502 25049 3535 1660 504 1228 503 390 474 391 473 393 471 1261 469 397 468 397 469 397 469 397 469 1264 468 398 468 1264 468 1264 468 398 468 1265 467 1265 467 1265 467 1265 467 1265 467 399 467 399 467 1266 466 399 467 400 466 400 466 400 466 423 443 423 443 401 465 423 442 424 442 424 442 1290 442 424 442 1290 442 424 442 424 441 424 442 1290 442 1291 441 425 441 424 442 425 441 425 441 1291 441 425 440 425 441 425 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 426 440 1292 440 1292 440 1292 440 426 440 426 440 1292 440 1293 439 1293 439 35480 3503 1696 467 1264 468 398 468 398 467 398 468 1265 467 398 467 399 467 399 466 399 467 1265 467 399 467 1266 466 1267 465 400 466 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 442 1290 442 424 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 425 441 425 441 1291 441 425 441 425 441 425 441 425 440 1292 440 425 441 425 440 426 440 426 440 426 440 426 440 426 440 426 440 426 440 426 439 427 439 426 440 426 440 1293 439 427 439 427 439 427 438 427 439 428 438 1294 438 428 437 428 438 1295 437 1319 413 453 413 35480 3503 1696 468 1265 467 398 468 398 468 398 468 1265 467 398 468 399 466 399 467 399 467 1266 466 399 466 1267 465 1290 442 401 465 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 441 1291 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 424 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 425 441 425 441 1292 440 426 440 426 440 1292 440 426 440 426 440 1293 439 426 440 426 440 1293 439 1293 439 1293 439 427 439 1294 438 427 438 427 439 427 438 428 438 428 438 428 438 428 438 453 413 429 437 453 413 1319 413 1320 412 1320 412 1320 412 454 412 1320 412 454 412 1321 411 1321 411 1321 411 1321 411 1321 411 455 410 455 411 455 411 455 410 456 410 456 410 456 410 481 384 481 385 482 383 482 383 483 358 507 359 1374 358 1374 358 508 358 508 358 508 358 509 357 509 357 535 331 535 331 535 330 535 330 536 330 1403 329 1403 329 563 302 564 301 564 302 564 301 565 301 591 274 619 246 593 273 620 245 620 245 621 245 673 189
# #
# Model: Mitsubishi SRK63HE. # Model: Mitsubishi SRK63HE
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -373,6 +384,7 @@ duty_cycle: 0.330000
data: 3234 1525 463 333 462 1127 465 332 462 333 436 1153 518 307 488 1073 518 307 488 308 434 1131 459 1155 435 1156 434 362 433 1159 432 363 432 1159 432 1159 432 1159 433 363 432 363 432 363 433 363 432 1159 433 1159 432 363 432 1159 433 1159 432 363 432 363 432 1159 432 363 433 363 432 1159 432 363 432 363 432 1159 432 1159 432 363 432 1160 432 1160 431 1160 432 1160 431 1160 431 1160 431 364 431 1160 431 1160 431 1160 431 364 431 364 431 364 431 364 431 1160 431 364 431 364 431 364 431 1160 432 1160 431 1160 432 364 431 1160 431 1160 431 1161 431 1161 430 364 431 364 431 364 431 1160 432 364 431 364 431 364 432 364 431 1161 431 1161 431 364 431 364 431 1161 430 364 432 364 431 1161 430 365 431 365 431 1161 430 1161 430 365 431 1161 430 1161 430 365 430 data: 3234 1525 463 333 462 1127 465 332 462 333 436 1153 518 307 488 1073 518 307 488 308 434 1131 459 1155 435 1156 434 362 433 1159 432 363 432 1159 432 1159 432 1159 433 363 432 363 432 363 433 363 432 1159 433 1159 432 363 432 1159 433 1159 432 363 432 363 432 1159 432 363 433 363 432 1159 432 363 432 363 432 1159 432 1159 432 363 432 1160 432 1160 431 1160 432 1160 431 1160 431 1160 431 364 431 1160 431 1160 431 1160 431 364 431 364 431 364 431 364 431 1160 431 364 431 364 431 364 431 1160 432 1160 431 1160 432 364 431 1160 431 1160 431 1161 431 1161 430 364 431 364 431 364 431 1160 432 364 431 364 431 364 432 364 431 1161 431 1161 431 364 431 364 431 1161 430 364 432 364 431 1161 430 365 431 365 431 1161 430 1161 430 365 431 1161 430 1161 430 365 430
# #
# Model: Airwell Prime DCI Series # Model: Airwell Prime DCI Series
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -410,6 +422,7 @@ duty_cycle: 0.330000
data: 3108 3851 2062 1793 2006 1821 1103 839 2031 859 1085 829 1081 833 1079 836 1045 1911 1973 897 1015 898 1016 899 1041 871 1016 899 1014 898 1015 899 1015 899 1014 899 1041 872 1015 899 1041 872 1041 872 1015 899 1015 899 1041 873 1014 899 1041 873 1014 899 1014 1883 1975 900 3045 3886 1997 1856 1945 1857 1012 927 1945 900 1013 901 1012 901 1013 901 1012 1859 1999 901 1012 930 1012 903 1011 903 1010 903 1011 902 1012 960 1011 928 986 932 1010 903 1011 928 1015 928 985 929 985 928 1014 928 985 929 985 929 984 929 985 928 986 1915 1971 928 3017 3915 1942 1885 1943 1885 985 930 1971 929 984 930 983 930 984 930 984 1887 1942 929 983 960 983 931 982 931 983 932 981 958 985 958 956 958 984 959 954 931 983 932 981 959 955 932 982 959 954 960 982 961 983 933 955 988 955 985 929 1943 1915 958 4003 data: 3108 3851 2062 1793 2006 1821 1103 839 2031 859 1085 829 1081 833 1079 836 1045 1911 1973 897 1015 898 1016 899 1041 871 1016 899 1014 898 1015 899 1015 899 1014 899 1041 872 1015 899 1041 872 1041 872 1015 899 1015 899 1041 873 1014 899 1041 873 1014 899 1014 1883 1975 900 3045 3886 1997 1856 1945 1857 1012 927 1945 900 1013 901 1012 901 1013 901 1012 1859 1999 901 1012 930 1012 903 1011 903 1010 903 1011 902 1012 960 1011 928 986 932 1010 903 1011 928 1015 928 985 929 985 928 1014 928 985 929 985 929 984 929 985 928 986 1915 1971 928 3017 3915 1942 1885 1943 1885 985 930 1971 929 984 930 983 930 984 930 984 1887 1942 929 983 960 983 931 982 931 983 932 981 958 985 958 956 958 984 959 954 931 983 932 981 959 955 932 982 959 954 960 982 961 983 933 955 988 955 985 929 1943 1915 958 4003
# #
# Model: Danby DAC060EB7WDB # Model: Danby DAC060EB7WDB
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -435,6 +448,7 @@ duty_cycle: 0.330000
data: 4401 4441 528 1629 529 550 528 1628 529 551 528 550 528 551 527 551 528 1629 529 1629 529 550 529 1630 528 551 528 549 530 550 529 551 528 549 529 550 529 1629 529 1628 530 549 530 1629 529 550 529 1628 529 1629 529 1631 527 1628 530 1628 529 1629 528 1628 530 1629 529 1629 529 1629 529 1629 528 1629 529 1629 529 1630 528 1629 529 1629 529 1628 529 1629 528 551 528 1629 529 550 529 550 530 548 529 1631 527 551 528 1629 529 5235 4402 4439 530 550 528 1629 529 549 530 1628 529 1629 529 1628 530 1629 529 549 530 550 529 1628 530 552 526 1628 529 1628 530 1628 530 1627 531 1628 529 1629 528 551 528 550 529 1628 530 550 528 1628 529 549 529 550 528 550 529 549 530 548 530 551 528 550 528 578 500 550 529 550 529 551 527 549 530 549 529 549 529 550 528 548 530 550 528 549 529 1629 528 550 529 1630 528 1628 530 1628 530 549 530 1628 529 549 529 data: 4401 4441 528 1629 529 550 528 1628 529 551 528 550 528 551 527 551 528 1629 529 1629 529 550 529 1630 528 551 528 549 530 550 529 551 528 549 529 550 529 1629 529 1628 530 549 530 1629 529 550 529 1628 529 1629 529 1631 527 1628 530 1628 529 1629 528 1628 530 1629 529 1629 529 1629 529 1629 528 1629 529 1629 529 1630 528 1629 529 1629 529 1628 529 1629 528 551 528 1629 529 550 529 550 530 548 529 1631 527 551 528 1629 529 5235 4402 4439 530 550 528 1629 529 549 530 1628 529 1629 529 1628 530 1629 529 549 530 550 529 1628 530 552 526 1628 529 1628 530 1628 530 1627 531 1628 529 1629 528 551 528 550 529 1628 530 550 528 1628 529 549 529 550 528 550 529 549 530 548 530 551 528 550 528 578 500 550 529 550 529 551 527 549 530 549 529 549 529 550 528 548 530 550 528 549 529 1629 528 550 529 1630 528 1628 530 1628 530 549 530 1628 529 549 529
# #
# Model: Carrier 42QHB12D8S # Model: Carrier 42QHB12D8S
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -472,6 +486,7 @@ duty_cycle: 0.330000
data: 4467 4390 571 1583 572 505 595 1560 572 1583 572 505 572 505 596 1559 596 482 596 481 597 1559 626 451 655 422 625 1529 596 1559 596 481 572 1582 573 1583 571 505 572 1583 595 1560 594 1561 592 1562 594 1561 593 1562 593 484 593 1563 592 485 592 485 592 485 592 485 593 484 593 485 592 485 592 1562 593 485 592 1563 592 1562 593 1562 594 483 593 485 593 1562 592 485 593 1561 593 484 593 484 593 484 593 1562 593 1562 592 5163 4462 4370 592 1563 593 484 592 1563 592 1563 592 485 592 485 593 1562 593 484 593 485 592 1562 593 484 593 485 592 1562 593 1562 593 485 592 1563 592 1563 592 485 592 1563 592 1562 593 1562 593 1563 592 1563 592 1562 592 485 593 1562 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 1563 592 485 592 1563 591 1563 592 1563 593 485 592 485 592 1563 592 485 592 1563 591 485 593 485 592 485 592 1563 592 1563 591 data: 4467 4390 571 1583 572 505 595 1560 572 1583 572 505 572 505 596 1559 596 482 596 481 597 1559 626 451 655 422 625 1529 596 1559 596 481 572 1582 573 1583 571 505 572 1583 595 1560 594 1561 592 1562 594 1561 593 1562 593 484 593 1563 592 485 592 485 592 485 592 485 593 484 593 485 592 485 592 1562 593 485 592 1563 592 1562 593 1562 594 483 593 485 593 1562 592 485 593 1561 593 484 593 484 593 484 593 1562 593 1562 592 5163 4462 4370 592 1563 593 484 592 1563 592 1563 592 485 592 485 593 1562 593 484 593 485 592 1562 593 484 593 485 592 1562 593 1562 593 485 592 1563 592 1563 592 485 592 1563 592 1562 593 1562 593 1563 592 1563 592 1562 592 485 593 1562 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 1563 592 485 592 1563 591 1563 592 1563 593 485 592 485 592 1563 592 485 592 1563 591 485 593 485 592 485 592 1563 592 1563 591
# #
# Model: Mitsubishi MSZ-AP25VGK # Model: Mitsubishi MSZ-AP25VGK
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -509,6 +524,7 @@ duty_cycle: 0.330000
data: 3539 1637 533 1225 502 1193 534 375 501 376 501 376 500 1226 501 376 501 376 500 1226 500 1227 501 376 529 1197 558 320 557 319 555 1169 531 1195 531 346 529 1196 530 1198 528 349 526 352 524 1229 497 379 497 379 497 1230 497 380 497 380 497 379 498 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 9042 3535 1674 496 1230 497 1230 497 380 497 380 497 380 497 1230 497 380 497 380 496 1230 497 1230 497 380 497 1230 497 380 497 380 497 1231 496 1230 497 380 497 1231 496 1231 496 380 496 380 497 1231 496 380 497 380 496 1231 496 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 496 380 497 380 497 380 497 380 497 380 496 381 496 380 497 380 497 380 497 381 496 1231 496 381 496 380 497 380 497 381 496 381 496 1231 496 381 496 381 496 380 497 381 495 1231 496 1231 496 1231 496 380 497 381 496 381 496 380 496 381 496 381 496 381 496 381 496 381 496 1231 496 1231 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 1231 496 381 496 381 496 1232 495 381 495 1232 495 381 496 1231 496 1231 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 495 381 496 381 496 381 496 381 496 1232 495 381 496 381 496 381 496 381 496 381 495 381 496 381 495 382 495 381 496 382 495 381 495 382 495 381 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 381 495 1232 495 1232 495 1232 495 1232 495 1232 495 382 495 382 495 382 495 data: 3539 1637 533 1225 502 1193 534 375 501 376 501 376 500 1226 501 376 501 376 500 1226 500 1227 501 376 529 1197 558 320 557 319 555 1169 531 1195 531 346 529 1196 530 1198 528 349 526 352 524 1229 497 379 497 379 497 1230 497 380 497 380 497 379 498 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 9042 3535 1674 496 1230 497 1230 497 380 497 380 497 380 497 1230 497 380 497 380 496 1230 497 1230 497 380 497 1230 497 380 497 380 497 1231 496 1230 497 380 497 1231 496 1231 496 380 496 380 497 1231 496 380 497 380 496 1231 496 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 496 380 497 380 497 380 497 380 497 380 496 381 496 380 497 380 497 380 497 381 496 1231 496 381 496 380 497 380 497 381 496 381 496 1231 496 381 496 381 496 380 497 381 495 1231 496 1231 496 1231 496 380 497 381 496 381 496 380 496 381 496 381 496 381 496 381 496 381 496 1231 496 1231 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 1231 496 381 496 381 496 1232 495 381 495 1232 495 381 496 1231 496 1231 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 495 381 496 381 496 381 496 381 496 1232 495 381 496 381 496 381 496 381 496 381 495 381 496 381 495 382 495 381 496 382 495 381 495 382 495 381 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 381 495 1232 495 1232 495 1232 495 1232 495 1232 495 382 495 382 495 382 495
# #
# Model: Hitachi RAK-50PEB # Model: Hitachi RAK-50PEB
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -546,6 +562,7 @@ duty_cycle: 0.330000
data: 30675 50953 3432 1606 490 1190 489 350 489 350 489 350 489 350 489 351 488 350 489 351 489 351 488 351 489 351 488 351 489 1191 488 351 488 351 489 351 488 351 488 351 488 351 489 351 488 1191 489 1191 489 351 488 351 488 351 488 351 488 351 489 351 489 351 488 351 489 1191 488 351 488 1191 489 1191 488 1191 488 1191 488 1191 488 1191 488 351 489 1191 488 1191 489 351 488 351 489 351 488 351 489 351 488 351 488 351 488 351 488 1191 488 1191 488 1191 488 1191 489 1191 488 1191 488 1191 489 1191 488 351 488 351 489 351 488 1191 488 351 489 351 488 351 488 351 489 1191 488 351 489 351 488 1191 488 351 488 351 488 351 489 351 489 351 488 351 489 1191 488 351 488 351 489 351 488 351 488 1191 488 1191 488 351 488 351 489 351 488 351 489 351 488 351 489 351 489 1191 488 1192 488 1191 488 351 489 1191 489 351 488 351 488 351 489 351 489 351 488 351 488 351 489 351 488 351 488 351 488 1192 488 351 489 351 488 351 488 351 489 351 489 351 488 351 488 351 488 352 487 352 488 351 488 352 488 351 488 351 488 351 488 1192 488 1192 487 352 488 352 487 352 487 352 488 352 487 352 488 351 488 352 488 352 488 352 487 352 488 351 488 351 488 352 488 352 487 352 488 352 487 352 488 352 488 352 488 352 487 1192 487 352 487 352 488 352 488 352 488 352 487 352 487 352 488 352 487 352 487 352 487 352 488 352 488 352 487 352 487 352 488 352 487 352 488 352 487 352 487 352 487 352 487 352 487 352 488 352 487 352 487 352 487 352 488 352 487 352 488 352 487 352 488 352 487 352 487 352 488 352 487 352 488 352 487 352 488 352 488 352 487 352 487 352 487 352 487 352 487 352 488 352 487 352 487 352 487 1193 486 352 487 352 488 352 487 352 487 352 488 352 487 352 488 352 488 352 487 352 488 352 487 353 486 353 487 352 487 352 488 352 488 352 487 352 487 352 487 352 487 353 487 352 488 352 488 352 487 1193 486 1193 486 1193 486 1193 487 353 487 352 487 353 486 data: 30675 50953 3432 1606 490 1190 489 350 489 350 489 350 489 350 489 351 488 350 489 351 489 351 488 351 489 351 488 351 489 1191 488 351 488 351 489 351 488 351 488 351 488 351 489 351 488 1191 489 1191 489 351 488 351 488 351 488 351 488 351 489 351 489 351 488 351 489 1191 488 351 488 1191 489 1191 488 1191 488 1191 488 1191 488 1191 488 351 489 1191 488 1191 489 351 488 351 489 351 488 351 489 351 488 351 488 351 488 351 488 1191 488 1191 488 1191 488 1191 489 1191 488 1191 488 1191 489 1191 488 351 488 351 489 351 488 1191 488 351 489 351 488 351 488 351 489 1191 488 351 489 351 488 1191 488 351 488 351 488 351 489 351 489 351 488 351 489 1191 488 351 488 351 489 351 488 351 488 1191 488 1191 488 351 488 351 489 351 488 351 489 351 488 351 489 351 489 1191 488 1192 488 1191 488 351 489 1191 489 351 488 351 488 351 489 351 489 351 488 351 488 351 489 351 488 351 488 351 488 1192 488 351 489 351 488 351 488 351 489 351 489 351 488 351 488 351 488 352 487 352 488 351 488 352 488 351 488 351 488 351 488 1192 488 1192 487 352 488 352 487 352 487 352 488 352 487 352 488 351 488 352 488 352 488 352 487 352 488 351 488 351 488 352 488 352 487 352 488 352 487 352 488 352 488 352 488 352 487 1192 487 352 487 352 488 352 488 352 488 352 487 352 487 352 488 352 487 352 487 352 487 352 488 352 488 352 487 352 487 352 488 352 487 352 488 352 487 352 487 352 487 352 487 352 487 352 488 352 487 352 487 352 487 352 488 352 487 352 488 352 487 352 488 352 487 352 487 352 488 352 487 352 488 352 487 352 488 352 488 352 487 352 487 352 487 352 487 352 487 352 488 352 487 352 487 352 487 1193 486 352 487 352 488 352 487 352 487 352 488 352 487 352 488 352 488 352 487 352 488 352 487 353 486 353 487 352 487 352 488 352 488 352 487 352 487 352 487 352 487 353 487 352 488 352 488 352 487 1193 486 1193 486 1193 486 1193 487 353 487 352 487 353 486
# #
# Model: LG PC07SQR # Model: LG PC07SQR
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -583,6 +600,7 @@ duty_cycle: 0.330000
data: 3204 9889 537 1587 491 529 512 544 489 545 489 1573 510 530 511 543 491 552 490 538 511 543 491 543 491 532 509 543 491 1587 489 537 512 543 491 1577 490 543 491 543 491 544 489 543 491 1586 489 544 490 1587 489 539 510 543 491 543 491 1586 490 data: 3204 9889 537 1587 491 529 512 544 489 545 489 1573 510 530 511 543 491 552 490 538 511 543 491 543 491 532 509 543 491 1587 489 537 512 543 491 1577 490 543 491 543 491 544 489 543 491 1586 489 544 490 1587 489 539 510 543 491 543 491 1586 490
# #
# Model: Daikin FTXC35DV1B # Model: Daikin FTXC35DV1B
#
name: Off name: Off
type: raw type: raw
frequency: 38000 frequency: 38000
@ -618,3 +636,79 @@ type: raw
frequency: 38000 frequency: 38000
duty_cycle: 0.330000 duty_cycle: 0.330000
data: 535 314 532 314 533 313 533 312 534 313 533 312 508 24840 3569 1647 508 1213 536 342 505 342 504 341 505 1214 506 340 506 340 506 340 505 340 506 1214 506 341 504 1216 504 1217 503 343 503 1218 502 1219 501 1219 502 1219 502 1219 502 345 502 344 502 1219 502 345 501 345 502 345 502 345 501 345 501 345 501 345 501 345 501 345 502 345 501 1219 502 345 501 1219 501 345 502 345 501 345 501 1219 501 1219 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 1220 500 1219 501 1220 500 345 501 1220 500 345 501 1220 501 1220 500 34815 3564 1653 502 1218 502 344 502 345 501 344 502 1219 501 345 501 345 501 345 501 345 501 1219 502 345 501 1219 502 1220 501 345 502 1219 501 1219 502 1219 501 1219 502 1219 502 345 501 345 501 1220 501 345 502 345 501 345 501 345 501 345 501 345 501 345 502 345 501 345 502 345 501 345 501 1220 501 345 501 345 501 345 501 345 501 1220 500 345 501 346 501 1220 500 1220 501 345 501 345 501 346 500 1220 500 1220 500 1220 500 1220 500 346 500 346 500 346 500 345 501 346 500 345 501 1220 500 346 500 1220 500 1220 500 1220 500 346 500 346 500 346 500 34816 3565 1653 502 1219 501 344 502 345 501 345 501 1219 502 345 501 345 502 345 501 345 501 1219 501 345 501 1219 502 1219 501 345 501 1219 502 1219 501 1219 501 1219 501 1219 501 345 501 345 501 1219 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 1220 501 346 501 345 501 1220 501 346 500 346 500 1220 500 346 500 345 501 346 500 1220 500 1220 500 1220 501 1220 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 1220 500 346 500 1220 500 347 499 346 500 346 500 346 500 347 499 347 499 346 500 346 500 347 499 347 499 347 499 347 499 347 499 347 499 347 499 347 499 347 499 1222 498 1222 499 1222 498 347 499 348 498 348 498 347 499 371 475 348 498 348 498 348 498 371 475 1222 498 1246 474 1246 474 372 475 371 475 372 474 372 474 348 498 371 475 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 1246 474 372 474 1246 474 372 474 372 474 372 474 1246 474 1246 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 1246 474 372 474 1247 473 372 474 1246 474 1246 474 1246 474 data: 535 314 532 314 533 313 533 312 534 313 533 312 508 24840 3569 1647 508 1213 536 342 505 342 504 341 505 1214 506 340 506 340 506 340 505 340 506 1214 506 341 504 1216 504 1217 503 343 503 1218 502 1219 501 1219 502 1219 502 1219 502 345 502 344 502 1219 502 345 501 345 502 345 502 345 501 345 501 345 501 345 501 345 501 345 502 345 501 1219 502 345 501 1219 501 345 502 345 501 345 501 1219 501 1219 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 1220 500 1219 501 1220 500 345 501 1220 500 345 501 1220 501 1220 500 34815 3564 1653 502 1218 502 344 502 345 501 344 502 1219 501 345 501 345 501 345 501 345 501 1219 502 345 501 1219 502 1220 501 345 502 1219 501 1219 502 1219 501 1219 502 1219 502 345 501 345 501 1220 501 345 502 345 501 345 501 345 501 345 501 345 501 345 502 345 501 345 502 345 501 345 501 1220 501 345 501 345 501 345 501 345 501 1220 500 345 501 346 501 1220 500 1220 501 345 501 345 501 346 500 1220 500 1220 500 1220 500 1220 500 346 500 346 500 346 500 345 501 346 500 345 501 1220 500 346 500 1220 500 1220 500 1220 500 346 500 346 500 346 500 34816 3565 1653 502 1219 501 344 502 345 501 345 501 1219 502 345 501 345 502 345 501 345 501 1219 501 345 501 1219 502 1219 501 345 501 1219 502 1219 501 1219 501 1219 501 1219 501 345 501 345 501 1219 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 345 501 1220 501 346 501 345 501 1220 501 346 500 346 500 1220 500 346 500 345 501 346 500 1220 500 1220 500 1220 501 1220 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 346 500 1220 500 346 500 1220 500 347 499 346 500 346 500 346 500 347 499 347 499 346 500 346 500 347 499 347 499 347 499 347 499 347 499 347 499 347 499 347 499 347 499 1222 498 1222 499 1222 498 347 499 348 498 348 498 347 499 371 475 348 498 348 498 348 498 371 475 1222 498 1246 474 1246 474 372 475 371 475 372 474 372 474 348 498 371 475 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 1246 474 372 474 1246 474 372 474 372 474 372 474 1246 474 1246 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 372 474 1246 474 372 474 1247 473 372 474 1246 474 1246 474 1246 474
#
# Model: AUX YKR-H/006E
#
name: Off
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8957 4502 539 1683 538 1681 540 559 538 559 538 556 541 557 540 1683 538 1682 539 1684 537 1682 539 1681 540 1684 537 1684 537 1682 539 1684 537 558 539 558 539 558 539 558 539 559 538 558 539 1682 539 1681 540 1683 538 557 540 558 539 558 539 557 540 559 538 557 540 557 540 561 536 559 538 558 539 557 540 558 539 558 539 1683 538 558 539 1682 540 557 540 559 538 557 540 557 540 561 536 558 539 559 538 558 539 560 537 557 540 558 539 558 539 558 539 559 538 558 539 1682 539 557 540 558 539 557 540 557 540 558 539 560 537 557 540 557 540 558 539 559 538 557 540 559 538 556 541 558 539 558 539 558 539 556 541 559 538 557 540 558 539 558 539 558 539 557 540 558 539 557 541 557 540 557 540 559 538 558 539 558 539 558 539 558 539 1681 540 557 540 1683 538 558 539 559 538 557 540 559 538 559 538 1683 538 1683 538 1683 538 557 540 558 539 558 540 1683 538 560 563
#
name: Dh
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8956 4504 536 1684 537 1687 534 559 538 559 538 559 538 560 537 1683 538 1685 536 1682 539 1684 537 1683 538 1684 537 1683 538 1684 537 1683 538 558 539 562 535 559 538 558 539 562 535 560 537 1683 538 1684 537 1683 538 561 536 561 536 561 537 560 537 561 536 558 539 560 537 559 538 560 537 561 536 561 536 563 534 559 538 1684 537 559 538 1684 537 561 536 560 537 560 537 560 537 560 537 560 537 559 538 559 538 559 538 588 509 558 539 559 538 559 538 564 533 1684 537 559 538 560 537 559 538 588 509 563 534 559 538 559 538 558 539 562 535 558 539 561 536 560 537 560 537 559 538 588 509 561 536 560 537 561 536 563 534 561 536 560 537 561 536 1684 537 559 538 559 538 559 538 561 536 560 537 560 537 559 538 561 536 558 539 560 537 1684 537 559 538 1683 538 561 536 561 536 563 534 559 538 558 539 1683 538 1684 537 1684 537 560 537 560 537 1683 538 560 537 560 563
#
name: Cool_hi
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8957 4502 538 1683 538 1684 537 562 535 560 537 559 538 559 539 1683 538 1682 539 1711 510 1685 536 1683 538 558 539 588 509 557 540 1682 539 557 540 558 539 559 538 559 538 558 539 561 536 1681 540 1682 539 1683 538 559 538 559 538 559 538 561 536 560 537 559 538 558 539 559 538 559 538 559 538 559 538 560 537 560 537 1685 536 560 537 1685 536 560 537 559 538 560 537 560 537 559 538 558 539 559 538 560 537 587 510 562 535 559 538 560 537 557 540 1685 536 559 538 560 537 587 510 588 509 559 538 562 535 560 537 557 540 559 538 557 540 560 537 587 510 560 538 558 539 559 538 559 538 561 536 560 537 560 537 558 540 560 537 559 538 560 537 1683 538 562 535 560 537 559 538 560 537 558 539 559 538 558 539 560 537 560 537 559 538 1683 538 558 539 1684 537 559 538 558 539 559 538 558 539 558 539 1682 539 1684 537 1684 537 1683 538 560 537 558 539 1683 538 1684 564
#
name: Cool_lo
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8956 4501 539 1682 539 1682 539 559 538 557 540 587 510 558 539 1684 537 1682 539 1682 539 1682 539 1680 541 1682 539 1682 539 1682 539 1681 540 558 539 558 539 558 539 557 540 558 539 557 540 1683 538 1683 538 1683 538 558 539 558 539 558 539 557 540 560 537 560 537 557 540 558 539 557 540 558 539 557 540 560 537 558 539 1681 540 556 541 1684 537 558 539 557 540 559 538 558 539 557 540 558 539 558 539 560 537 559 538 558 539 558 539 557 540 559 538 1685 536 559 538 558 539 587 510 557 540 559 538 559 538 560 537 560 537 558 539 559 538 558 539 559 538 562 535 558 539 557 540 557 540 559 538 559 538 558 539 559 538 558 539 558 539 557 540 1682 539 557 540 558 539 559 538 557 540 558 539 560 537 559 538 557 540 561 536 558 539 1682 539 558 539 1682 539 559 538 557 540 558 539 559 538 559 538 1682 539 1684 537 1683 538 557 540 558 539 558 539 560 537 559 564
#
name: Heat_hi
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8959 4502 539 1682 539 1682 539 556 541 559 538 558 539 559 538 1680 541 1681 540 1684 537 1683 538 1684 537 557 540 560 537 558 539 1683 538 1682 539 558 539 559 538 559 538 558 539 558 539 1683 538 1681 540 1683 538 559 538 560 537 560 537 559 538 561 536 560 537 559 538 559 538 559 538 559 538 559 538 560 537 557 540 1682 539 557 540 1682 539 559 538 558 539 560 538 558 539 558 539 558 539 558 539 558 539 559 538 559 538 557 540 558 539 558 539 559 538 560 537 1684 537 561 536 557 540 559 538 559 538 557 540 558 539 559 538 560 537 558 539 558 539 559 538 558 539 559 539 559 538 557 540 559 538 557 540 558 540 561 536 558 539 558 539 1683 538 558 539 559 538 557 540 559 538 557 540 558 539 559 538 559 538 558 539 559 538 1681 540 558 539 1684 537 562 535 560 537 559 538 559 538 560 537 1682 539 1682 539 1682 539 1686 535 559 538 1682 539 559 538 1682 565
#
name: Heat_lo
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8961 4501 539 1681 540 1681 540 559 538 558 539 558 539 557 540 1682 539 1682 539 1681 540 1682 539 1682 539 1683 538 1682 539 1683 538 1682 539 557 540 560 537 558 539 560 537 560 537 558 539 1681 540 1681 540 1682 539 557 540 558 539 561 536 558 539 560 537 558 539 556 541 558 539 558 539 557 540 559 538 558 539 559 538 1684 537 559 538 1682 539 558 539 556 541 559 538 562 535 556 541 558 539 558 539 557 540 558 539 557 540 558 539 559 538 560 537 557 540 557 540 1682 539 558 539 557 540 558 539 559 538 559 538 557 540 558 539 558 539 558 539 558 539 557 540 561 536 558 539 586 511 558 539 557 540 586 511 559 539 556 541 557 540 557 540 1682 539 559 538 558 539 558 539 559 538 558 539 560 537 558 539 559 538 558 539 557 540 1681 540 558 539 1680 541 557 540 557 540 559 538 558 539 559 538 1682 539 1682 539 1682 539 558 539 558 539 1682 539 1682 539 558 565
#
# Model: Carrier 42QG5A580SC
#
name: Off
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8403 4308 519 1425 518 625 520 1461 485 1427 518 559 517 564 567 1386 518 1429 517 562 597 524 519 1431 517 1430 518 567 516 1426 518 565 517 1429 518 1431 518 1425 519 565 517 1457 485 562 518 1429 519 1424 520 565 516 1426 517 561 519 1430 515 1427 518 563 595 525 518 1428 517 528 489 21085 8424 4296 642 467 568 1400 569 533 569 536 647 1402 569 1395 569 535 568 534 569 1405 566 1397 567 549 568 535 569 1401 567 533 570 1399 571 537 570 534 568 537 567 1397 570 535 571 1401 568 534 567 533 567 1399 567 539 568 1402 569 565 569 532 571 1399 571 1397 569 535 566 1358 489 21085 8401 4318 512 1438 517 573 515 1476 532 1389 516 573 518 609 535 1393 568 1392 516 574 567 528 566 1393 565 1390 516 576 516 1437 517 574 517 1441 516 1445 567 1389 517 578 566 1390 516 578 568 1398 566 1392 515 575 516 1437 516 574 517 1442 567 1425 483 597 515 575 516 1446 514 539 490
#
name: Dh
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8391 4318 536 1417 518 564 516 1432 517 1428 518 563 518 562 517 1433 516 1428 518 564 519 565 513 1433 517 1430 517 562 518 1463 483 561 517 1430 516 1428 518 563 595 1393 516 559 519 565 514 1425 519 1429 517 569 514 1426 518 566 514 1466 485 562 518 559 518 561 518 1425 519 531 488 21116 8369 4318 569 534 641 1326 640 462 641 465 641 1330 641 1325 639 464 568 534 595 1403 641 1328 641 462 639 467 640 1328 568 536 642 1367 568 531 567 536 569 1398 568 537 542 1432 640 1327 567 532 568 535 567 1400 567 539 567 1399 568 536 568 1402 569 1402 568 1401 567 537 565 1359 487 21117 8392 4294 565 1388 517 575 566 1393 516 1443 514 574 516 573 517 1443 567 1391 515 574 516 577 566 1393 565 1390 566 528 567 1392 516 575 567 1395 565 1390 515 576 568 1391 515 572 566 528 565 1395 565 1393 515 572 564 1391 515 581 563 1389 516 578 513 609 483 576 566 1391 514 538 487
#
name: Cool_hi
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8424 4292 514 1428 518 559 518 1431 514 1432 517 561 515 566 512 1433 516 1434 516 562 519 562 516 1432 517 1426 518 566 516 1429 517 566 516 1429 518 1428 517 562 516 1467 481 570 517 561 518 565 519 563 515 566 516 567 516 1433 516 1429 514 564 518 561 518 562 519 1428 519 536 562 21009 8478 4280 638 461 641 1328 641 456 642 467 637 1325 643 1326 568 597 568 537 639 1330 641 1327 568 535 640 468 639 1324 568 534 543 1432 566 535 641 494 637 1327 566 532 640 1329 567 1398 640 1327 641 1327 640 1326 642 1328 568 531 568 538 567 1402 567 1406 566 1402 568 532 569 1357 489 21085 8401 4319 565 1394 516 577 567 1396 565 1390 515 574 543 566 516 1441 568 1392 516 575 566 531 566 1393 567 1390 516 576 515 1456 515 579 562 1392 515 1440 515 575 566 1391 516 576 544 569 563 525 516 574 514 606 514 576 514 1439 567 1390 515 575 515 574 570 566 567 1390 515 540 488
#
name: Cool_lo
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8401 4306 518 1460 483 566 518 1432 517 1430 514 561 516 564 517 1429 518 1430 519 592 485 564 517 1427 517 1432 516 561 545 1430 516 566 518 1462 483 1430 515 568 517 1427 516 566 516 564 517 1430 518 1425 518 559 518 562 518 1426 518 1425 517 593 484 561 516 573 516 1427 517 530 564 21007 8401 4322 642 465 643 1324 643 457 643 458 643 1327 643 1327 641 463 642 461 644 1325 644 1324 643 462 642 483 643 1328 641 460 645 1321 643 458 643 464 641 1325 643 459 644 1327 642 1323 643 461 643 461 642 1347 644 1331 641 463 639 462 641 1327 571 1405 542 1428 670 462 645 1282 562 21007 8402 4317 515 1436 517 606 641 1321 516 1438 517 572 515 578 516 1441 515 1440 516 572 515 575 515 1474 610 1316 515 574 644 1314 516 574 567 1394 640 1316 517 578 639 1319 516 576 517 575 513 1447 641 1315 516 576 515 577 566 1396 514 1440 516 573 518 571 638 456 565 1393 515 538 564
#
name: Heat_hi
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8399 4307 519 1426 518 560 517 1432 517 1460 485 561 518 558 517 1436 518 1427 518 555 520 561 517 1430 519 1428 516 560 519 1425 518 566 517 1430 516 1432 519 563 519 1425 518 563 515 1429 517 1433 517 1430 516 1432 518 1429 518 568 516 1432 515 1429 519 561 516 567 517 1427 519 533 487 21083 8424 4339 567 536 568 1402 641 493 608 462 545 1431 640 1326 567 532 568 538 640 1331 640 1329 641 536 565 534 641 1329 567 537 639 1329 640 462 642 467 641 1325 568 532 642 1332 640 488 568 534 565 536 566 566 536 567 641 1329 570 535 638 464 569 1401 641 1326 568 534 639 1287 490 21083 8403 4313 567 1390 516 579 514 1441 515 1438 517 575 516 576 568 1393 568 1394 515 606 534 530 515 1441 567 1425 482 576 568 1392 514 578 566 1392 569 1432 515 576 568 1389 517 577 515 1444 515 1437 569 1393 516 1444 566 1389 566 528 567 1394 566 1419 517 575 513 578 515 1440 516 539 490
#
name: Heat_lo
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8425 4291 542 1401 544 538 542 1404 518 1427 544 534 570 540 516 1434 542 1399 544 539 544 539 541 1403 541 1402 516 570 517 1427 545 566 511 1406 517 1431 542 534 544 1406 543 536 517 567 543 1404 542 1400 595 525 544 1405 542 534 516 1433 516 1428 544 537 544 535 543 1403 542 505 488 21084 8424 4298 566 535 569 1402 567 533 568 537 570 1403 570 1403 565 534 566 537 566 1402 569 1398 569 533 569 538 592 1446 569 535 570 1400 569 567 535 535 568 1437 568 533 568 1398 569 1402 565 533 567 534 569 1403 568 536 569 1402 568 535 567 534 571 1403 568 1415 566 536 571 1362 489 21084 8403 4313 516 1439 517 574 515 1442 515 1441 518 573 516 574 567 1397 514 1440 515 573 516 575 516 1443 515 1439 518 574 516 1440 517 608 535 1396 517 1441 517 579 515 1438 515 576 517 578 568 1390 569 1391 516 575 518 1439 516 573 517 1445 566 1391 516 571 517 572 516 1441 514 543 487

View File

@ -1686,3 +1686,41 @@ type: parsed
protocol: NEC protocol: NEC
address: 40 00 00 00 address: 40 00 00 00
command: 10 00 00 00 command: 10 00 00 00
#
# Philips OLED 934/12
#
name: Power
type: parsed
protocol: RC6
address: 00 00 00 00
command: 0C 00 00 00
#
name: Mute
type: parsed
protocol: RC6
address: 00 00 00 00
command: 0D 00 00 00
#
name: Vol_up
type: parsed
protocol: RC6
address: 00 00 00 00
command: 10 00 00 00
#
name: Vol_dn
type: parsed
protocol: RC6
address: 00 00 00 00
command: 11 00 00 00
#
name: Ch_next
type: parsed
protocol: RC6
address: 00 00 00 00
command: 20 00 00 00
#
name: Ch_prev
type: parsed
protocol: RC6
address: 00 00 00 00
command: 21 00 00 00

View File

@ -38,6 +38,15 @@ App(
sources=["plugins/supported_cards/opal.c"], sources=["plugins/supported_cards/opal.c"],
) )
App(
appid="mykey_parser",
apptype=FlipperAppType.PLUGIN,
entry_point="mykey_plugin_ep",
targets=["f7"],
requires=["nfc"],
sources=["plugins/supported_cards/mykey.c"],
)
App( App(
appid="myki_parser", appid="myki_parser",
apptype=FlipperAppType.PLUGIN, apptype=FlipperAppType.PLUGIN,
@ -83,6 +92,15 @@ App(
sources=["plugins/supported_cards/aime.c"], sources=["plugins/supported_cards/aime.c"],
) )
App(
appid="umarsh_parser",
apptype=FlipperAppType.PLUGIN,
entry_point="umarsh_plugin_ep",
targets=["f7"],
requires=["nfc"],
sources=["plugins/supported_cards/umarsh.c"],
)
App( App(
appid="nfc_start", appid="nfc_start",
targets=["f7"], targets=["f7"],

View File

@ -1,6 +1,6 @@
#include "mf_user_dict.h" #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 <nfc/protocols/mf_classic/mf_classic.h>
#include <furi/furi.h> #include <furi/furi.h>
@ -15,22 +15,22 @@ struct MfUserDict {
MfUserDict* mf_user_dict_alloc(size_t max_keys_to_load) { MfUserDict* mf_user_dict_alloc(size_t max_keys_to_load) {
MfUserDict* instance = malloc(sizeof(MfUserDict)); MfUserDict* instance = malloc(sizeof(MfUserDict));
NfcDict* dict = nfc_dict_alloc( KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
furi_assert(dict); 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); instance->keys_num = MIN(max_keys_to_load, dict_keys_num);
if(instance->keys_num > 0) { if(instance->keys_num > 0) {
instance->keys_arr = malloc(instance->keys_num * sizeof(MfClassicKey)); instance->keys_arr = malloc(instance->keys_num * sizeof(MfClassicKey));
for(size_t i = 0; i < instance->keys_num; i++) { for(size_t i = 0; i < instance->keys_num; i++) {
bool key_loaded = 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); furi_assert(key_loaded);
} }
} }
nfc_dict_free(dict); keys_dict_free(dict);
return instance; 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(index < instance->keys_num);
furi_assert(instance->keys_arr); furi_assert(instance->keys_arr);
NfcDict* dict = nfc_dict_alloc( KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
furi_assert(dict); furi_assert(dict);
bool key_delete_success = bool key_delete_success =
nfc_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey)); keys_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey));
nfc_dict_free(dict); keys_dict_free(dict);
if(key_delete_success) { if(key_delete_success) {
instance->keys_num--; instance->keys_num--;

View File

@ -1,4 +1,5 @@
#include "nfc_supported_cards.h" #include "nfc_supported_cards.h"
#include "../plugins/supported_cards/nfc_supported_card_plugin.h" #include "../plugins/supported_cards/nfc_supported_card_plugin.h"
#include <flipper_application/flipper_application.h> #include <flipper_application/flipper_application.h>
@ -7,22 +8,72 @@
#include <furi.h> #include <furi.h>
#include <path.h> #include <path.h>
#include <m-array.h>
#define TAG "NfcSupportedCards" #define TAG "NfcSupportedCards"
#define NFC_SUPPORTED_CARDS_PLUGINS_PATH APP_DATA_PATH("plugins") #define NFC_SUPPORTED_CARDS_PLUGINS_PATH APP_DATA_PATH("plugins")
#define NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX "_parser.fal" #define NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX "_parser.fal"
typedef enum {
NfcSupportedCardsPluginFeatureHasVerify = (1U << 0),
NfcSupportedCardsPluginFeatureHasRead = (1U << 1),
NfcSupportedCardsPluginFeatureHasParse = (1U << 2),
} NfcSupportedCardsPluginFeature;
typedef struct {
FuriString* path;
NfcProtocol protocol;
NfcSupportedCardsPluginFeature feature;
} NfcSupportedCardsPluginCache;
ARRAY_DEF(NfcSupportedCardsPluginCache, NfcSupportedCardsPluginCache, M_POD_OPLIST);
typedef enum {
NfcSupportedCardsLoadStateIdle,
NfcSupportedCardsLoadStateInProgress,
NfcSupportedCardsLoadStateSuccess,
NfcSupportedCardsLoadStateFail,
} NfcSupportedCardsLoadState;
typedef struct { typedef struct {
Storage* storage; Storage* storage;
File* directory; File* directory;
FuriString* file_path; FuriString* file_path;
char file_name[256]; char file_name[256];
FlipperApplication* app; FlipperApplication* app;
} NfcSupportedCards; } NfcSupportedCardsLoadContext;
static NfcSupportedCards* nfc_supported_cards_alloc() { struct NfcSupportedCards {
NfcSupportedCardsPluginCache_t plugins_cache_arr;
NfcSupportedCardsLoadState load_state;
NfcSupportedCardsLoadContext* load_context;
};
NfcSupportedCards* nfc_supported_cards_alloc() {
NfcSupportedCards* instance = malloc(sizeof(NfcSupportedCards)); NfcSupportedCards* instance = malloc(sizeof(NfcSupportedCards));
NfcSupportedCardsPluginCache_init(instance->plugins_cache_arr);
return instance;
}
void nfc_supported_cards_free(NfcSupportedCards* instance) {
furi_assert(instance);
NfcSupportedCardsPluginCache_it_t iter;
for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr);
!NfcSupportedCardsPluginCache_end_p(iter);
NfcSupportedCardsPluginCache_next(iter)) {
NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter);
furi_string_free(plugin_cache->path);
}
NfcSupportedCardsPluginCache_clear(instance->plugins_cache_arr);
free(instance);
}
static NfcSupportedCardsLoadContext* nfc_supported_cards_load_context_alloc() {
NfcSupportedCardsLoadContext* instance = malloc(sizeof(NfcSupportedCardsLoadContext));
instance->storage = furi_record_open(RECORD_STORAGE); instance->storage = furi_record_open(RECORD_STORAGE);
instance->directory = storage_file_alloc(instance->storage); instance->directory = storage_file_alloc(instance->storage);
@ -35,7 +86,7 @@ static NfcSupportedCards* nfc_supported_cards_alloc() {
return instance; return instance;
} }
static void nfc_supported_cards_free(NfcSupportedCards* instance) { static void nfc_supported_cards_load_context_free(NfcSupportedCardsLoadContext* instance) {
if(instance->app) { if(instance->app) {
flipper_application_free(instance->app); flipper_application_free(instance->app);
} }
@ -50,7 +101,36 @@ static void nfc_supported_cards_free(NfcSupportedCards* instance) {
} }
static const NfcSupportedCardsPlugin* static const NfcSupportedCardsPlugin*
nfc_supported_cards_get_next_plugin(NfcSupportedCards* instance) { nfc_supported_cards_get_plugin(NfcSupportedCardsLoadContext* instance, FuriString* path) {
furi_assert(instance);
furi_assert(path);
const NfcSupportedCardsPlugin* plugin = NULL;
do {
if(instance->app) flipper_application_free(instance->app);
instance->app = flipper_application_alloc(instance->storage, firmware_api_interface);
if(flipper_application_preload(instance->app, furi_string_get_cstr(path)) !=
FlipperApplicationPreloadStatusSuccess)
break;
if(!flipper_application_is_plugin(instance->app)) break;
if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess)
break;
const FlipperAppPluginDescriptor* descriptor =
flipper_application_plugin_get_descriptor(instance->app);
if(descriptor == NULL) break;
if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) break;
if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) break;
plugin = descriptor->entry_point;
} while(false);
return plugin;
}
static const NfcSupportedCardsPlugin*
nfc_supported_cards_get_next_plugin(NfcSupportedCardsLoadContext* instance) {
const NfcSupportedCardsPlugin* plugin = NULL; const NfcSupportedCardsPlugin* plugin = NULL;
do { do {
@ -65,83 +145,137 @@ static const NfcSupportedCardsPlugin*
path_concat(NFC_SUPPORTED_CARDS_PLUGINS_PATH, instance->file_name, instance->file_path); path_concat(NFC_SUPPORTED_CARDS_PLUGINS_PATH, instance->file_name, instance->file_path);
if(instance->app) flipper_application_free(instance->app); plugin = nfc_supported_cards_get_plugin(instance, instance->file_path);
instance->app = flipper_application_alloc(instance->storage, firmware_api_interface);
if(flipper_application_preload(instance->app, furi_string_get_cstr(instance->file_path)) !=
FlipperApplicationPreloadStatusSuccess)
continue;
if(!flipper_application_is_plugin(instance->app)) continue;
if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess)
continue;
const FlipperAppPluginDescriptor* descriptor =
flipper_application_plugin_get_descriptor(instance->app);
if(descriptor == NULL) continue;
if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) continue;
if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) continue;
plugin = descriptor->entry_point;
} while(plugin == NULL); //-V654 } while(plugin == NULL); //-V654
return plugin; return plugin;
} }
bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc) { void nfc_supported_cards_load_cache(NfcSupportedCards* instance) {
furi_assert(instance);
do {
if((instance->load_state == NfcSupportedCardsLoadStateSuccess) ||
(instance->load_state == NfcSupportedCardsLoadStateFail))
break;
instance->load_context = nfc_supported_cards_load_context_alloc();
while(true) {
const NfcSupportedCardsPlugin* plugin =
nfc_supported_cards_get_next_plugin(instance->load_context);
if(plugin == NULL) break; //-V547
NfcSupportedCardsPluginCache plugin_cache = {}; //-V779
plugin_cache.path = furi_string_alloc_set(instance->load_context->file_path);
plugin_cache.protocol = plugin->protocol;
if(plugin->verify) {
plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasVerify;
}
if(plugin->read) {
plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasRead;
}
if(plugin->parse) {
plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasParse;
}
NfcSupportedCardsPluginCache_push_back(instance->plugins_cache_arr, plugin_cache);
}
nfc_supported_cards_load_context_free(instance->load_context);
size_t plugins_loaded = NfcSupportedCardsPluginCache_size(instance->plugins_cache_arr);
if(plugins_loaded == 0) {
FURI_LOG_D(TAG, "Plugins not found");
instance->load_state = NfcSupportedCardsLoadStateFail;
} else {
FURI_LOG_D(TAG, "Loaded %zu plugins", plugins_loaded);
instance->load_state = NfcSupportedCardsLoadStateSuccess;
}
} while(false);
}
bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nfc* nfc) {
furi_assert(instance);
furi_assert(device); furi_assert(device);
furi_assert(nfc); furi_assert(nfc);
bool card_read = false; bool card_read = false;
NfcProtocol protocol = nfc_device_get_protocol(device);
NfcSupportedCards* supported_cards = nfc_supported_cards_alloc();
do { do {
const NfcSupportedCardsPlugin* plugin = if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break;
nfc_supported_cards_get_next_plugin(supported_cards);
if(plugin == NULL) break; //-V547
const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779 instance->load_context = nfc_supported_cards_load_context_alloc();
if(plugin->protocol != protocol) continue;
if(plugin->verify) { NfcSupportedCardsPluginCache_it_t iter;
if(!plugin->verify(nfc)) continue; for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr);
!NfcSupportedCardsPluginCache_end_p(iter);
NfcSupportedCardsPluginCache_next(iter)) {
NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter);
if(plugin_cache->protocol != protocol) continue;
if((plugin_cache->feature & NfcSupportedCardsPluginFeatureHasRead) == 0) continue;
const NfcSupportedCardsPlugin* plugin =
nfc_supported_cards_get_plugin(instance->load_context, plugin_cache->path);
if(plugin == NULL) continue;
if(plugin->verify) {
if(!plugin->verify(nfc)) continue;
}
if(plugin->read) {
if(plugin->read(nfc, device)) {
card_read = true;
break;
}
}
} }
if(plugin->read) { nfc_supported_cards_load_context_free(instance->load_context);
card_read = plugin->read(nfc, device); } while(false);
}
} while(!card_read);
nfc_supported_cards_free(supported_cards);
return card_read; return card_read;
} }
bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data) { bool nfc_supported_cards_parse(
NfcSupportedCards* instance,
NfcDevice* device,
FuriString* parsed_data) {
furi_assert(instance);
furi_assert(device); furi_assert(device);
furi_assert(parsed_data); furi_assert(parsed_data);
bool parsed = false; bool card_parsed = false;
NfcProtocol protocol = nfc_device_get_protocol(device);
NfcSupportedCards* supported_cards = nfc_supported_cards_alloc();
do { do {
const NfcSupportedCardsPlugin* plugin = if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break;
nfc_supported_cards_get_next_plugin(supported_cards);
if(plugin == NULL) break; //-V547
const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779 instance->load_context = nfc_supported_cards_load_context_alloc();
if(plugin->protocol != protocol) continue;
if(plugin->parse) { NfcSupportedCardsPluginCache_it_t iter;
parsed = plugin->parse(device, parsed_data); for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr);
!NfcSupportedCardsPluginCache_end_p(iter);
NfcSupportedCardsPluginCache_next(iter)) {
NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter);
if(plugin_cache->protocol != protocol) continue;
if((plugin_cache->feature & NfcSupportedCardsPluginFeatureHasParse) == 0) continue;
const NfcSupportedCardsPlugin* plugin =
nfc_supported_cards_get_plugin(instance->load_context, plugin_cache->path);
if(plugin == NULL) continue;
if(plugin->parse) {
if(plugin->parse(device, parsed_data)) {
card_parsed = true;
break;
}
}
} }
} while(!parsed); nfc_supported_cards_load_context_free(instance->load_context);
} while(false);
nfc_supported_cards_free(supported_cards); return card_parsed;
return parsed;
} }

View File

@ -15,6 +15,34 @@
extern "C" { extern "C" {
#endif #endif
/**
* @brief NfcSupportedCards opaque type definition.
*/
typedef struct NfcSupportedCards NfcSupportedCards;
/**
* @brief Allocate NfcSupportedCards instance.
*
* @return pointer to allocated NfcSupportedCards instance.
*/
NfcSupportedCards* nfc_supported_cards_alloc();
/**
* @brief Delete an NfcSupportedCards instance
*
* @param[in] instance pointer to instance to be deleted.
*/
void nfc_supported_cards_free(NfcSupportedCards* instance);
/**
* @brief Load plugins information to cache.
*
* @note This function must be called before calling read and parse fanctions.
*
* @param[in, out] instance pointer to NfcSupportedCards instance.
*/
void nfc_supported_cards_load_cache(NfcSupportedCards* instance);
/** /**
* @brief Read the card using a custom procedure. * @brief Read the card using a custom procedure.
* *
@ -22,13 +50,14 @@ extern "C" {
* try to execute the custom read procedure specified in each. Upon first success, * try to execute the custom read procedure specified in each. Upon first success,
* no further attempts will be made and the function will return. * no further attempts will be made and the function will return.
* *
* @param[in, out] instance pointer to NfcSupportedCards instance.
* @param[in,out] device pointer to a device instance to hold the read data. * @param[in,out] device pointer to a device instance to hold the read data.
* @param[in,out] nfc pointer to an Nfc instance. * @param[in,out] nfc pointer to an Nfc instance.
* @returns true if the card was successfully read, false otherwise. * @returns true if the card was successfully read, false otherwise.
* *
* @see NfcSupportedCardPluginRead for detailed description. * @see NfcSupportedCardPluginRead for detailed description.
*/ */
bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc); bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nfc* nfc);
/** /**
* @brief Parse raw data into human-readable representation. * @brief Parse raw data into human-readable representation.
@ -37,13 +66,17 @@ bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc);
* try to parse the data according to each implementation. Upon first success, * try to parse the data according to each implementation. Upon first success,
* no further attempts will be made and the function will return. * no further attempts will be made and the function will return.
* *
* @param[in, out] instance pointer to NfcSupportedCards instance.
* @param[in] device pointer to a device instance holding the data is to be parsed. * @param[in] device pointer to a device instance holding the data is to be parsed.
* @param[out] parsed_data pointer to the string to contain the formatted result. * @param[out] parsed_data pointer to the string to contain the formatted result.
* @returns true if the card was successfully parsed, false otherwise. * @returns true if the card was successfully parsed, false otherwise.
* *
* @see NfcSupportedCardPluginParse for detailed description. * @see NfcSupportedCardPluginParse for detailed description.
*/ */
bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data); bool nfc_supported_cards_parse(
NfcSupportedCards* instance,
NfcDevice* device,
FuriString* parsed_data);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -8,7 +8,6 @@
#include "nfc_protocol_support.h" #include "nfc_protocol_support.h"
#include "nfc/nfc_app_i.h" #include "nfc/nfc_app_i.h"
#include "nfc/helpers/nfc_supported_cards.h"
#include "nfc_protocol_support_defs.h" #include "nfc_protocol_support_defs.h"
#include "nfc_protocol_support_gui_common.h" #include "nfc_protocol_support_gui_common.h"
@ -157,9 +156,11 @@ static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) {
instance->protocols_detected[instance->protocols_detected_selected_idx]; instance->protocols_detected[instance->protocols_detected_selected_idx];
instance->poller = nfc_poller_alloc(instance->nfc, protocol); instance->poller = nfc_poller_alloc(instance->nfc, protocol);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
nfc_supported_cards_load_cache(instance->nfc_supported_cards);
// Start poller with the appropriate callback // Start poller with the appropriate callback
nfc_protocol_support[protocol]->scene_read.on_enter(instance); nfc_protocol_support[protocol]->scene_read.on_enter(instance);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
nfc_blink_detect_start(instance); nfc_blink_detect_start(instance);
} }
@ -178,7 +179,8 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana
} else if(event.event == NfcCustomEventPollerIncomplete) { } else if(event.event == NfcCustomEventPollerIncomplete) {
nfc_poller_stop(instance->poller); nfc_poller_stop(instance->poller);
nfc_poller_free(instance->poller); nfc_poller_free(instance->poller);
bool card_read = nfc_supported_cards_read(instance->nfc_device, instance->nfc); bool card_read = nfc_supported_cards_read(
instance->nfc_supported_cards, instance->nfc_device, instance->nfc);
if(card_read) { if(card_read) {
notification_message(instance->notifications, &sequence_success); notification_message(instance->notifications, &sequence_success);
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
@ -303,7 +305,7 @@ static void nfc_protocol_support_scene_read_success_on_enter(NfcApp* instance) {
Widget* widget = instance->widget; Widget* widget = instance->widget;
FuriString* temp_str = furi_string_alloc(); FuriString* temp_str = furi_string_alloc();
if(nfc_supported_cards_parse(instance->nfc_device, temp_str)) { if(nfc_supported_cards_parse(instance->nfc_supported_cards, instance->nfc_device, temp_str)) {
widget_add_text_scroll_element( widget_add_text_scroll_element(
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
} else { } else {

View File

@ -51,6 +51,7 @@ NfcApp* nfc_app_alloc() {
instance->mf_ul_auth = mf_ultralight_auth_alloc(); instance->mf_ul_auth = mf_ultralight_auth_alloc();
instance->mfc_key_cache = mf_classic_key_cache_alloc(); instance->mfc_key_cache = mf_classic_key_cache_alloc();
instance->nfc_supported_cards = nfc_supported_cards_alloc();
// Nfc device // Nfc device
instance->nfc_device = nfc_device_alloc(); instance->nfc_device = nfc_device_alloc();
@ -110,7 +111,6 @@ NfcApp* nfc_app_alloc() {
instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget));
// Dict attack // Dict attack
instance->dict_attack = dict_attack_alloc(); instance->dict_attack = dict_attack_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
instance->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(instance->dict_attack)); instance->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(instance->dict_attack));
@ -141,6 +141,7 @@ void nfc_app_free(NfcApp* instance) {
mf_ultralight_auth_free(instance->mf_ul_auth); mf_ultralight_auth_free(instance->mf_ul_auth);
mf_classic_key_cache_free(instance->mfc_key_cache); mf_classic_key_cache_free(instance->mfc_key_cache);
nfc_supported_cards_free(instance->nfc_supported_cards);
// Nfc device // Nfc device
nfc_device_free(instance->nfc_device); nfc_device_free(instance->nfc_device);
@ -339,8 +340,10 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) {
furi_assert(path); furi_assert(path);
bool result = false; bool result = false;
nfc_supported_cards_load_cache(instance->nfc_supported_cards);
FuriString* load_path = furi_string_alloc(); 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); nfc_set_shadow_file_path(path, load_path);
} else if(furi_string_end_with(path, NFC_APP_SHADOW_EXTENSION)) { } else if(furi_string_end_with(path, NFC_APP_SHADOW_EXTENSION)) {
size_t path_len = furi_string_size(path); size_t path_len = furi_string_size(path);

View File

@ -31,6 +31,7 @@
#include "helpers/mf_user_dict.h" #include "helpers/mf_user_dict.h"
#include "helpers/mfkey32_logger.h" #include "helpers/mfkey32_logger.h"
#include "helpers/mf_classic_key_cache.h" #include "helpers/mf_classic_key_cache.h"
#include "helpers/nfc_supported_cards.h"
#include <dialogs/dialogs.h> #include <dialogs/dialogs.h>
#include <storage/storage.h> #include <storage/storage.h>
@ -51,7 +52,7 @@
#include <nfc/nfc_device.h> #include <nfc/nfc_device.h>
#include <nfc/helpers/nfc_data_generator.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 <gui/modules/validators.h>
#include <toolbox/path.h> #include <toolbox/path.h>
@ -79,7 +80,7 @@ typedef enum {
} NfcRpcState; } NfcRpcState;
typedef struct { typedef struct {
NfcDict* dict; KeysDict* dict;
uint8_t sectors_total; uint8_t sectors_total;
uint8_t sectors_read; uint8_t sectors_read;
uint8_t current_sector; uint8_t current_sector;
@ -132,6 +133,7 @@ struct NfcApp {
Mfkey32Logger* mfkey32_logger; Mfkey32Logger* mfkey32_logger;
MfUserDict* mf_user_dict; MfUserDict* mf_user_dict;
MfClassicKeyCache* mfc_key_cache; MfClassicKeyCache* mfc_key_cache;
NfcSupportedCards* nfc_supported_cards;
NfcDevice* nfc_device; NfcDevice* nfc_device;
Iso14443_3aData* iso14443_3a_edit_data; Iso14443_3aData* iso14443_3a_edit_data;

View File

@ -0,0 +1,130 @@
#include "nfc_supported_card_plugin.h"
#include <flipper_application/flipper_application.h>
#include <machine/endian.h>
#include <nfc/protocols/st25tb/st25tb.h>
#define TAG "MyKey"
const uint32_t blankBlock18 = 0x480FCD8F, blankBlock19 = 0x070082C0;
static bool mykey_is_blank(const St25tbData* data) {
return data->blocks[0x18] == blankBlock18 && data->blocks[0x19] == blankBlock19;
}
static bool mykey_has_lockid(const St25tbData* data) {
return (data->blocks[5] & 0xFF) == 0x7F;
}
static bool mykey_parse(const NfcDevice* device, FuriString* parsed_data) {
furi_assert(device);
furi_assert(parsed_data);
const St25tbData* data = nfc_device_get_data(device, NfcProtocolSt25tb);
if(data->type != St25tbType04k && data->type != St25tbTypeX4k) {
FURI_LOG_D(TAG, "bad type");
return false;
}
for(int i = 0; i < 5; i++) {
if(data->blocks[i] != 0xFFFFFFFF) {
FURI_LOG_D(TAG, "bad otp block %d", i);
return false;
}
}
if((data->blocks[8] >> 16 & 0xFF) > 0x31 || (data->blocks[8] >> 8 & 0xFF) > 0x12) {
FURI_LOG_D(TAG, "bad mfg date");
return false;
}
if(data->system_otp_block != 0xFEFFFFFF) {
FURI_LOG_D(TAG, "bad sys otp block");
return false;
}
furi_string_cat(parsed_data, "\e#MyKey\n");
if(data->blocks[6] == 0) { // Tag is actually a MyKey but it has been bricked by a reader
furi_string_cat(parsed_data, "\e#Bricked!\nBlock 6 is 0!");
return true;
}
bool is_blank = mykey_is_blank(data);
furi_string_cat_printf(parsed_data, "Serial#: %08lX\n", (uint32_t)__bswap32(data->blocks[7]));
furi_string_cat_printf(parsed_data, "Blank: %s\n", is_blank ? "yes" : "no");
furi_string_cat_printf(parsed_data, "LockID: %s\n", mykey_has_lockid(data) ? "maybe" : "no");
uint32_t block8 = data->blocks[8];
furi_string_cat_printf(
parsed_data,
"Prod. date: %02lX/%02lX/%04lX",
block8 >> 16 & 0xFF,
block8 >> 8 & 0xFF,
0x2000 + (block8 & 0xFF));
if(!is_blank) {
furi_string_cat_printf(
parsed_data, "\nOp. count: %zu\n", (size_t)__bswap32(data->blocks[0x12] & 0xFFFFFF00));
uint32_t block3C = data->blocks[0x3C];
if(block3C == 0xFFFFFFFF) {
furi_string_cat(parsed_data, "No history available!");
} else {
block3C ^= data->blocks[0x07];
uint32_t startingOffset = ((block3C & 0x30000000) >> 28) |
((block3C & 0x00100000) >> 18);
furi_check(startingOffset < 8); //-V547
for(int txnOffset = 8; txnOffset > 0; txnOffset--) {
uint32_t txnBlock =
__bswap32(data->blocks[0x34 + ((startingOffset + txnOffset) % 8)]);
if(txnBlock == 0xFFFFFFFF) {
break;
}
uint8_t day = txnBlock >> 27;
uint8_t month = txnBlock >> 23 & 0xF;
uint16_t year = 2000 + (txnBlock >> 16 & 0x7F);
uint16_t credit = txnBlock & 0xFFFF;
if(txnOffset == 8) {
furi_string_cat_printf(
parsed_data, "Current credit: %d.%02d euros\n", credit / 100, credit % 100);
furi_string_cat(parsed_data, "Op. history (newest first):");
}
furi_string_cat_printf(
parsed_data,
"\n %02d/%02d/%04d %d.%02d",
day,
month,
year,
credit / 100,
credit % 100);
}
}
}
return true;
}
/* Actual implementation of app<>plugin interface */
static const NfcSupportedCardsPlugin mykey_plugin = {
.protocol = NfcProtocolSt25tb,
.verify = NULL,
.read = NULL,
.parse = mykey_parse,
};
/* Plugin descriptor to comply with basic plugin specification */
static const FlipperAppPluginDescriptor mykey_plugin_descriptor = {
.appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID,
.ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION,
.entry_point = &mykey_plugin,
};
/* Plugin entry point - must return a pointer to const descriptor */
const FlipperAppPluginDescriptor* mykey_plugin_ep() {
return &mykey_plugin_descriptor;
}

View File

@ -0,0 +1,155 @@
/*
* Parser for Umarsh card (Russia).
*
* Copyright 2023 Leptoptilos <leptoptilos@icloud.com>
* Thanks https://github.com/krolchonok for the provided dumps and their analysis
*
* Note: All meaningful data is stored in sectors 0, 8 and 12, reading data
* from which is possible only with the B key. The key B for these sectors
* is unique for each card. To get it, you should use a nested attack.
* More info about Umarsh cards: https://github.com/metrodroid/metrodroid/wiki/Umarsh
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/core_defines.h"
#include "nfc_supported_card_plugin.h"
#include "protocols/mf_classic/mf_classic.h"
#include <flipper_application/flipper_application.h>
#include <nfc/nfc_device.h>
#include <nfc/helpers/nfc_util.h>
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
#include <stdbool.h>
#include <stdint.h>
#include <furi_hal_rtc.h>
#define TAG "Umarsh"
bool parse_datetime(uint16_t date, FuriHalRtcDateTime* result) {
result->year = 2000 + (date >> 9);
result->month = date >> 5 & 0x0F;
result->day = date & 0x1F;
return (date != 0);
}
static bool umarsh_parse(const NfcDevice* device, FuriString* parsed_data) {
furi_assert(device);
const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic);
bool parsed = false;
do {
// Verify card type
if(data->type != MfClassicType1k) break;
const uint8_t ticket_sector = 8;
const uint8_t ticket_sector_start_block_number =
mf_classic_get_first_block_num_of_sector(ticket_sector);
// Validate specific for Umarsh ticket sector header
const uint8_t* block_start_ptr = &data->block[ticket_sector_start_block_number].data[0];
const uint32_t header_part_0 = nfc_util_bytes2num(block_start_ptr, 4);
const uint32_t header_part_1 = nfc_util_bytes2num(block_start_ptr + 4, 4);
if((header_part_0 + header_part_1) != 0xFFFFFFFF) break;
// Data parsing from block 1
block_start_ptr = &data->block[ticket_sector_start_block_number + 1].data[0];
const uint16_t expiry_date = nfc_util_bytes2num(block_start_ptr + 1, 2);
const uint8_t region_number = (((block_start_ptr[8] >> 5) & 0x07) << 4) |
(block_start_ptr[12] & 0x0F);
const uint8_t refill_counter = nfc_util_bytes2num(block_start_ptr + 7, 1);
const uint32_t card_number = nfc_util_bytes2num(block_start_ptr + 8, 4) & 0x3FFFFFFF;
if(card_number == 0) break;
// Data parsing from block 2
block_start_ptr = &data->block[ticket_sector_start_block_number + 2].data[0];
const uint16_t valid_to = nfc_util_bytes2num(block_start_ptr, 2);
const uint32_t terminal_number = nfc_util_bytes2num(block_start_ptr + 3, 3);
const uint16_t last_refill_date = nfc_util_bytes2num(block_start_ptr + 6, 2);
const uint16_t balance_rub = (nfc_util_bytes2num(block_start_ptr + 8, 2)) & 0x7FFF;
const uint8_t balance_kop = nfc_util_bytes2num(block_start_ptr + 10, 1) & 0x7F;
FuriHalRtcDateTime expiry_datetime;
bool is_expiry_datetime_valid = parse_datetime(expiry_date, &expiry_datetime);
FuriHalRtcDateTime valid_to_datetime;
bool is_valid_to_datetime_valid = parse_datetime(valid_to, &valid_to_datetime);
FuriHalRtcDateTime last_refill_datetime;
bool is_last_refill_datetime_valid =
parse_datetime(last_refill_date, &last_refill_datetime);
furi_string_cat_printf(
parsed_data,
"\e#Umarsh\nCard number: %lu\nRegion: %02u\nTerminal number: %lu\nRefill counter: %u\nBalance: %u.%02u RUR",
card_number,
region_number,
terminal_number,
refill_counter,
balance_rub,
balance_kop);
if(is_expiry_datetime_valid)
furi_string_cat_printf(
parsed_data,
"\nExpires: %02u.%02u.%u",
expiry_datetime.day,
expiry_datetime.month,
expiry_datetime.year);
if(is_valid_to_datetime_valid)
furi_string_cat_printf(
parsed_data,
"\nValid to: %02u.%02u.%u",
valid_to_datetime.day,
valid_to_datetime.month,
valid_to_datetime.year);
if(is_last_refill_datetime_valid)
furi_string_cat_printf(
parsed_data,
"\nLast refill: %02u.%02u.%u",
last_refill_datetime.day,
last_refill_datetime.month,
last_refill_datetime.year);
parsed = true;
} while(false);
return parsed;
}
/* Actual implementation of app<>plugin interface */
static const NfcSupportedCardsPlugin umarsh_plugin = {
.protocol = NfcProtocolMfClassic,
.verify = NULL,
.read = NULL,
.parse = umarsh_parse,
};
/* Plugin descriptor to comply with basic plugin specification */
static const FlipperAppPluginDescriptor umarsh_plugin_descriptor = {
.appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID,
.ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION,
.entry_point = &umarsh_plugin,
};
/* Plugin entry point - must return a pointer to const descriptor */
const FlipperAppPluginDescriptor* umarsh_plugin_ep() {
return &umarsh_plugin_descriptor;
}

View File

@ -1312,3 +1312,7 @@ CE99FBC8BD26
# PIK Comfort Moscow keys (ISBC Mifare Plus SE 1K) # PIK Comfort Moscow keys (ISBC Mifare Plus SE 1K)
009FB42D98ED 009FB42D98ED
002E626E2820 002E626E2820
# Volgograd (Russia) Volna transport cards keys
2B787A063D5D
D37C8F1793F7

View File

@ -41,7 +41,8 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
} else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) { } else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) {
MfClassicKey key = {}; 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 = key;
mfc_event->data->key_request_data.key_provided = true; mfc_event->data->key_request_data.key_provided = true;
instance->nfc_dict_context.dict_keys_current++; 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( view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
} else if(mfc_event->type == MfClassicPollerEventTypeNextSector) { } 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.dict_keys_current = 0;
instance->nfc_dict_context.current_sector = instance->nfc_dict_context.current_sector =
mfc_event->data->next_sector_data.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( view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
} else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStop) { } 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.is_key_attack = false;
instance->nfc_dict_context.dict_keys_current = 0; instance->nfc_dict_context.dict_keys_current = 0;
view_dispatcher_send_custom_event( 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); scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack);
if(state == DictAttackStateUserDictInProgress) { if(state == DictAttackStateUserDictInProgress) {
do { 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; state = DictAttackStateSystemDictInProgress;
break; break;
} }
instance->nfc_dict_context.dict = nfc_dict_alloc( instance->nfc_dict_context.dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
if(nfc_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) { if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
nfc_dict_free(instance->nfc_dict_context.dict); keys_dict_free(instance->nfc_dict_context.dict);
state = DictAttackStateSystemDictInProgress; state = DictAttackStateSystemDictInProgress;
break; break;
} }
@ -141,13 +142,13 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) {
} while(false); } while(false);
} }
if(state == DictAttackStateSystemDictInProgress) { if(state == DictAttackStateSystemDictInProgress) {
instance->nfc_dict_context.dict = nfc_dict_alloc( instance->nfc_dict_context.dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey)); NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey));
dict_attack_set_header(instance->dict_attack, "MF Classic System Dictionary"); dict_attack_set_header(instance->dict_attack, "MF Classic System Dictionary");
} }
instance->nfc_dict_context.dict_keys_total = 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( dict_attack_set_total_dict_keys(
instance->dict_attack, instance->nfc_dict_context.dict_keys_total); instance->dict_attack, instance->nfc_dict_context.dict_keys_total);
instance->nfc_dict_context.dict_keys_current = 0; 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) { if(state == DictAttackStateUserDictInProgress) {
nfc_poller_stop(instance->poller); nfc_poller_stop(instance->poller);
nfc_poller_free(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( scene_manager_set_scene_state(
instance->scene_manager, instance->scene_manager,
NfcSceneMfClassicDictAttack, 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) { if(instance->nfc_dict_context.is_card_present) {
nfc_poller_stop(instance->poller); nfc_poller_stop(instance->poller);
nfc_poller_free(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( scene_manager_set_scene_state(
instance->scene_manager, instance->scene_manager,
NfcSceneMfClassicDictAttack, NfcSceneMfClassicDictAttack,
@ -253,7 +254,7 @@ void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
scene_manager_set_scene_state( scene_manager_set_scene_state(
instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateUserDictInProgress); 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.current_sector = 0;
instance->nfc_dict_context.sectors_total = 0; instance->nfc_dict_context.sectors_total = 0;

View File

@ -14,20 +14,20 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) {
// Load flipper dict keys total // Load flipper dict keys total
uint32_t flipper_dict_keys_total = 0; uint32_t flipper_dict_keys_total = 0;
NfcDict* dict = nfc_dict_alloc( KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey)); NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey));
if(dict) { if(dict) {
flipper_dict_keys_total = nfc_dict_get_total_keys(dict); flipper_dict_keys_total = keys_dict_get_total_keys(dict);
nfc_dict_free(dict); keys_dict_free(dict);
} }
// Load user dict keys total // Load user dict keys total
uint32_t user_dict_keys_total = 0; uint32_t user_dict_keys_total = 0;
dict = nfc_dict_alloc( dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
if(dict) { if(dict) {
user_dict_keys_total = nfc_dict_get_total_keys(dict); user_dict_keys_total = keys_dict_get_total_keys(dict);
nfc_dict_free(dict); keys_dict_free(dict);
} }
FuriString* temp_str = furi_string_alloc(); FuriString* temp_str = furi_string_alloc();

View File

@ -29,23 +29,23 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) { if(event.event == NfcCustomEventByteInputDone) {
// Add key to dict // Add key to dict
NfcDict* dict = nfc_dict_alloc( KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
furi_assert(dict); furi_assert(dict);
MfClassicKey key = {}; MfClassicKey key = {};
memcpy(key.data, instance->byte_input_store, sizeof(MfClassicKey)); 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( scene_manager_next_scene(
instance->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); 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); scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess);
dolphin_deed(DolphinDeedNfcMfcAdd); dolphin_deed(DolphinDeedNfcMfcAdd);
} else { } else {
scene_manager_previous_scene(instance->scene_manager); scene_manager_previous_scene(instance->scene_manager);
} }
nfc_dict_free(dict); keys_dict_free(dict);
consumed = true; consumed = true;
} }
} }

View File

@ -1,6 +1,5 @@
#include "nfc/nfc_app_i.h" #include "nfc/nfc_app_i.h"
#include "nfc/helpers/nfc_supported_cards.h"
#include "nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h" #include "nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h"
void nfc_scene_supported_card_on_enter(void* context) { void nfc_scene_supported_card_on_enter(void* context) {
@ -8,7 +7,7 @@ void nfc_scene_supported_card_on_enter(void* context) {
FuriString* temp_str = furi_string_alloc(); FuriString* temp_str = furi_string_alloc();
if(nfc_supported_cards_parse(instance->nfc_device, temp_str)) { if(nfc_supported_cards_parse(instance->nfc_supported_cards, instance->nfc_device, temp_str)) {
widget_add_text_scroll_element( widget_add_text_scroll_element(
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
widget_add_button_element( widget_add_button_element(

View File

@ -329,7 +329,7 @@ void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) {
case SubGhzReadRAWStatusLoadKeyTX: case SubGhzReadRAWStatusLoadKeyTX:
case SubGhzReadRAWStatusLoadKeyTXRepeat: case SubGhzReadRAWStatusLoadKeyTXRepeat:
graphics_mode = 0; graphics_mode = 0;
elements_button_center(canvas, "Send"); elements_button_center(canvas, "Hold to repeat");
break; break;
case SubGhzReadRAWStatusStart: case SubGhzReadRAWStatusStart:

View File

@ -118,7 +118,8 @@ void cli_motd() {
"|_| |____||___||_| |_| |___||_|_\\ \\___||____||___|\r\n" "|_| |____||___||_| |_| |___||_|_\\ \\___||____||___|\r\n"
"\r\n" "\r\n"
"Welcome to Flipper Zero Command Line Interface!\r\n" "Welcome to Flipper Zero Command Line Interface!\r\n"
"Read Manual https://docs.flipperzero.one\r\n" "Read the manual: https://docs.flipper.net/development/cli\r\n"
"Run `help` or `?` to list available commands\r\n"
"\r\n"); "\r\n");
const Version* firmware_version = furi_hal_version_get_firmware_version(); const Version* firmware_version = furi_hal_version_get_firmware_version();

View File

@ -150,7 +150,7 @@ void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str) {
if(!str) return; if(!str) return;
x += canvas->offset_x; x += canvas->offset_x;
y += canvas->offset_y; y += canvas->offset_y;
u8g2_DrawStr(&canvas->fb, x, y, str); u8g2_DrawUTF8(&canvas->fb, x, y, str);
} }
void canvas_draw_str_aligned( void canvas_draw_str_aligned(
@ -169,10 +169,10 @@ void canvas_draw_str_aligned(
case AlignLeft: case AlignLeft:
break; break;
case AlignRight: case AlignRight:
x -= u8g2_GetStrWidth(&canvas->fb, str); x -= u8g2_GetUTF8Width(&canvas->fb, str);
break; break;
case AlignCenter: case AlignCenter:
x -= (u8g2_GetStrWidth(&canvas->fb, str) / 2); x -= (u8g2_GetUTF8Width(&canvas->fb, str) / 2);
break; break;
default: default:
furi_crash(); furi_crash();
@ -193,13 +193,13 @@ void canvas_draw_str_aligned(
break; break;
} }
u8g2_DrawStr(&canvas->fb, x, y, str); u8g2_DrawUTF8(&canvas->fb, x, y, str);
} }
uint16_t canvas_string_width(Canvas* canvas, const char* str) { uint16_t canvas_string_width(Canvas* canvas, const char* str) {
furi_assert(canvas); furi_assert(canvas);
if(!str) return 0; if(!str) return 0;
return u8g2_GetStrWidth(&canvas->fb, str); return u8g2_GetUTF8Width(&canvas->fb, str);
} }
uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol) { uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol) {

View File

@ -179,7 +179,8 @@ static void rpc_system_system_factory_reset_process(const PB_Main* request, void
RpcSession* session = (RpcSession*)context; RpcSession* session = (RpcSession*)context;
furi_assert(session); furi_assert(session);
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); furi_hal_rtc_reset_registers();
furi_hal_rtc_set_flag(FuriHalRtcFlagStorageFormatInternal);
power_reboot(PowerBootModeNormal); power_reboot(PowerBootModeNormal);
(void)session; (void)session;

View File

@ -603,7 +603,8 @@ static void storage_cli_factory_reset(Cli* cli, FuriString* args, void* context)
char c = cli_getc(cli); char c = cli_getc(cli);
if(c == 'y' || c == 'Y') { if(c == 'y' || c == 'Y') {
printf("Data will be wiped after reboot.\r\n"); printf("Data will be wiped after reboot.\r\n");
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); furi_hal_rtc_reset_registers();
furi_hal_rtc_set_flag(FuriHalRtcFlagStorageFormatInternal);
power_reboot(PowerBootModeNormal); power_reboot(PowerBootModeNormal);
} else { } else {
printf("Safe choice.\r\n"); printf("Safe choice.\r\n");

View File

@ -189,7 +189,7 @@ static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) {
lfs_t* lfs = &lfs_data->lfs; lfs_t* lfs = &lfs_data->lfs;
bool was_fingerprint_outdated = storage_int_check_and_set_fingerprint(lfs_data); bool was_fingerprint_outdated = storage_int_check_and_set_fingerprint(lfs_data);
bool need_format = furi_hal_rtc_is_flag_set(FuriHalRtcFlagFactoryReset) || bool need_format = furi_hal_rtc_is_flag_set(FuriHalRtcFlagStorageFormatInternal) ||
was_fingerprint_outdated; was_fingerprint_outdated;
if(need_format) { if(need_format) {
@ -197,7 +197,7 @@ static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) {
err = lfs_format(lfs, &lfs_data->config); err = lfs_format(lfs, &lfs_data->config);
if(err == 0) { if(err == 0) {
FURI_LOG_I(TAG, "Factory reset: Format successful, trying to mount"); FURI_LOG_I(TAG, "Factory reset: Format successful, trying to mount");
furi_hal_rtc_reset_flag(FuriHalRtcFlagFactoryReset); furi_hal_rtc_reset_flag(FuriHalRtcFlagStorageFormatInternal);
err = lfs_mount(lfs, &lfs_data->config); err = lfs_mount(lfs, &lfs_data->config);
if(err == 0) { if(err == 0) {
FURI_LOG_I(TAG, "Factory reset: Mounted"); FURI_LOG_I(TAG, "Factory reset: Mounted");

View File

@ -63,7 +63,8 @@ bool storage_settings_scene_factory_reset_on_event(void* context, SceneManagerEv
scene_manager_set_scene_state( scene_manager_set_scene_state(
app->scene_manager, StorageSettingsFactoryReset, counter); app->scene_manager, StorageSettingsFactoryReset, counter);
} else { } else {
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); furi_hal_rtc_reset_registers();
furi_hal_rtc_set_flag(FuriHalRtcFlagStorageFormatInternal);
power_reboot(PowerBootModeNormal); power_reboot(PowerBootModeNormal);
} }

View File

@ -343,7 +343,7 @@ int32_t update_task_worker_flash_writer(void* context) {
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate);
// Format LFS before restoring backup on next boot // Format LFS before restoring backup on next boot
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); furi_hal_rtc_set_flag(FuriHalRtcFlagStorageFormatInternal);
#ifdef FURI_NDEBUG #ifdef FURI_NDEBUG
// Production // Production
furi_hal_rtc_set_log_level(FuriLogLevelDefault); furi_hal_rtc_set_log_level(FuriLogLevelDefault);

View File

@ -48,7 +48,6 @@ env.Append(
File("helpers/iso14443_crc.h"), File("helpers/iso14443_crc.h"),
File("helpers/iso13239_crc.h"), File("helpers/iso13239_crc.h"),
File("helpers/nfc_data_generator.h"), File("helpers/nfc_data_generator.h"),
File("helpers/nfc_dict.h"),
], ],
) )

View File

@ -1,270 +0,0 @@
#include "nfc_dict.h"
#include <storage/storage.h>
#include <flipper_format/flipper_format.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#include <toolbox/args.h>
#include <nfc/helpers/nfc_util.h>
#define TAG "NfcDict"
struct NfcDict {
Stream* stream;
size_t key_size;
size_t key_size_symbols;
uint32_t total_keys;
};
typedef struct {
const char* path;
FS_OpenMode open_mode;
} NfcDictFile;
bool nfc_dict_check_presence(const char* path) {
furi_assert(path);
Storage* storage = furi_record_open(RECORD_STORAGE);
bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK;
furi_record_close(RECORD_STORAGE);
return dict_present;
}
NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size) {
furi_assert(path);
NfcDict* instance = malloc(sizeof(NfcDict));
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->stream = buffered_file_stream_alloc(storage);
furi_record_close(RECORD_STORAGE);
FS_OpenMode open_mode = FSOM_OPEN_EXISTING;
if(mode == NfcDictModeOpenAlways) {
open_mode = FSOM_OPEN_ALWAYS;
}
instance->key_size = key_size;
// Byte = 2 symbols + 1 end of line
instance->key_size_symbols = key_size * 2 + 1;
bool dict_loaded = false;
do {
if(!buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode)) {
buffered_file_stream_close(instance->stream);
break;
}
// Check for new line ending
if(!stream_eof(instance->stream)) {
if(!stream_seek(instance->stream, -1, StreamOffsetFromEnd)) break;
uint8_t last_char = 0;
if(stream_read(instance->stream, &last_char, 1) != 1) break;
if(last_char != '\n') {
FURI_LOG_D(TAG, "Adding new line ending");
if(stream_write_char(instance->stream, '\n') != 1) break;
}
if(!stream_rewind(instance->stream)) break;
}
// Read total amount of keys
FuriString* next_line;
next_line = furi_string_alloc();
while(true) {
if(!stream_read_line(instance->stream, next_line)) {
FURI_LOG_T(TAG, "No keys left in dict");
break;
}
FURI_LOG_T(
TAG,
"Read line: %s, len: %zu",
furi_string_get_cstr(next_line),
furi_string_size(next_line));
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != instance->key_size_symbols) continue;
instance->total_keys++;
}
furi_string_free(next_line);
stream_rewind(instance->stream);
dict_loaded = true;
FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", instance->total_keys);
} while(false);
if(!dict_loaded) {
buffered_file_stream_close(instance->stream);
free(instance);
instance = NULL;
}
return instance;
}
void nfc_dict_free(NfcDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
buffered_file_stream_close(instance->stream);
stream_free(instance->stream);
free(instance);
}
static void nfc_dict_int_to_str(NfcDict* instance, const uint8_t* key_int, FuriString* key_str) {
furi_string_reset(key_str);
for(size_t i = 0; i < instance->key_size; i++) {
furi_string_cat_printf(key_str, "%02X", key_int[i]);
}
}
static void nfc_dict_str_to_int(NfcDict* instance, FuriString* key_str, uint64_t* key_int) {
uint8_t key_byte_tmp;
*key_int = 0ULL;
for(uint8_t i = 0; i < instance->key_size * 2; i += 2) {
args_char_to_hex(
furi_string_get_char(key_str, i), furi_string_get_char(key_str, i + 1), &key_byte_tmp);
*key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2));
}
}
uint32_t nfc_dict_get_total_keys(NfcDict* instance) {
furi_assert(instance);
return instance->total_keys;
}
bool nfc_dict_rewind(NfcDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
return stream_rewind(instance->stream);
}
static bool nfc_dict_get_next_key_str(NfcDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
bool key_read = false;
furi_string_reset(key);
while(!key_read) {
if(!stream_read_line(instance->stream, key)) break;
if(furi_string_get_char(key, 0) == '#') continue;
if(furi_string_size(key) != instance->key_size_symbols) continue;
furi_string_left(key, instance->key_size_symbols - 1);
key_read = true;
}
return key_read;
}
bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
FuriString* temp_key = furi_string_alloc();
uint64_t key_int = 0;
bool key_read = nfc_dict_get_next_key_str(instance, temp_key);
if(key_read) {
nfc_dict_str_to_int(instance, temp_key, &key_int);
nfc_util_num2bytes(key_int, key_size, key);
}
furi_string_free(temp_key);
return key_read;
}
static bool nfc_dict_is_key_present_str(NfcDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
FuriString* next_line;
next_line = furi_string_alloc();
bool key_found = false;
stream_rewind(instance->stream);
while(!key_found) { //-V654
if(!stream_read_line(instance->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != instance->key_size_symbols) continue;
furi_string_left(next_line, instance->key_size_symbols - 1);
if(!furi_string_equal(key, next_line)) continue;
key_found = true;
}
furi_string_free(next_line);
return key_found;
}
bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(key);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
FuriString* temp_key = furi_string_alloc();
nfc_dict_int_to_str(instance, key, temp_key);
bool key_found = nfc_dict_is_key_present_str(instance, temp_key);
furi_string_free(temp_key);
return key_found;
}
static bool nfc_dict_add_key_str(NfcDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
furi_string_cat_printf(key, "\n");
bool key_added = false;
do {
if(!stream_seek(instance->stream, 0, StreamOffsetFromEnd)) break;
if(!stream_insert_string(instance->stream, key)) break;
instance->total_keys++;
key_added = true;
} while(false);
furi_string_left(key, instance->key_size_symbols - 1);
return key_added;
}
bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(key);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
FuriString* temp_key = furi_string_alloc();
nfc_dict_int_to_str(instance, key, temp_key);
bool key_added = nfc_dict_add_key_str(instance, temp_key);
furi_string_free(temp_key);
return key_added;
}
bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(key);
furi_assert(instance->key_size == key_size);
bool key_removed = false;
uint8_t* temp_key = malloc(key_size);
nfc_dict_rewind(instance);
while(!key_removed) {
if(!nfc_dict_get_next_key(instance, temp_key, key_size)) break;
if(memcmp(temp_key, key, key_size) == 0) {
int32_t offset = (-1) * (instance->key_size_symbols);
stream_seek(instance->stream, offset, StreamOffsetFromCurrent);
if(!stream_delete(instance->stream, instance->key_size_symbols)) break;
instance->total_keys--;
key_removed = true;
}
}
nfc_dict_rewind(instance);
free(temp_key);
return key_removed;
}

View File

@ -1,103 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
NfcDictModeOpenExisting,
NfcDictModeOpenAlways,
} NfcDictMode;
typedef struct NfcDict NfcDict;
/** Check dictionary presence
*
* @param path - dictionary path
*
* @return true if dictionary exists, false otherwise
*/
bool nfc_dict_check_presence(const char* path);
/** Open or create dictionary
* Depending on mode, dictionary will be opened or created.
*
* @param path - dictionary path
* @param mode - NfcDictMode value
* @param key_size - size of dictionary keys in bytes
*
* @return NfcDict dictionary instance
*/
NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size);
/** Close dictionary
*
* @param instance - NfcDict dictionary instance
*/
void nfc_dict_free(NfcDict* instance);
/** Get total number of keys in dictionary
*
* @param instance - NfcDict dictionary instance
*
* @return total number of keys in dictionary
*/
uint32_t nfc_dict_get_total_keys(NfcDict* instance);
/** Rewind dictionary
*
* @param instance - NfcDict dictionary instance
*
* @return true if rewind was successful, false otherwise
*/
bool nfc_dict_rewind(NfcDict* instance);
/** Check if key is present in dictionary
*
* @param instance - NfcDict dictionary instance
* @param key - key to check
* @param key_size - size of key in bytes
*
* @return true if key is present, false otherwise
*/
bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size);
/** Get next key from dictionary
* This function will return next key from dictionary. If there are no more
* keys, it will return false, and nfc_dict_rewind() should be called.
*
* @param instance - NfcDict dictionary instance
* @param key - buffer to store key
* @param key_size - size of key in bytes
*
* @return true if key was successfully retrieved, false otherwise
*/
bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size);
/** Add key to dictionary
*
* @param instance - NfcDict dictionary instance
* @param key - key to add
* @param key_size - size of key in bytes
*
* @return true if key was successfully added, false otherwise
*/
bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size);
/** Delete key from dictionary
*
* @param instance - NfcDict dictionary instance
* @param key - key to delete
* @param key_size - size of key in bytes
*
* @return true if key was successfully deleted, false otherwise
*/
bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size);
#ifdef __cplusplus
}
#endif

View File

@ -35,6 +35,19 @@ uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) {
return res; return res;
} }
uint64_t nfc_util_bytes2num_little_endian(const uint8_t* src, uint8_t len) {
furi_assert(src);
furi_assert(len <= 8);
uint64_t res = 0;
uint8_t shift = 0;
while(len--) {
res |= ((uint64_t)*src) << (8 * shift++);
src++;
}
return res;
}
uint8_t nfc_util_even_parity32(uint32_t data) { uint8_t nfc_util_even_parity32(uint32_t data) {
// data ^= data >> 16; // data ^= data >> 16;
// data ^= data >> 8; // data ^= data >> 8;

View File

@ -10,6 +10,8 @@ void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest);
uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len); uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len);
uint64_t nfc_util_bytes2num_little_endian(const uint8_t* src, uint8_t len);
uint8_t nfc_util_even_parity32(uint32_t data); uint8_t nfc_util_even_parity32(uint32_t data);
uint8_t nfc_util_odd_parity8(uint8_t data); uint8_t nfc_util_odd_parity8(uint8_t data);

View File

@ -117,12 +117,13 @@ Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso144
bit_buffer_reset(instance->rx_buffer); bit_buffer_reset(instance->rx_buffer);
// Send ATTRIB // Send ATTRIB
uint8_t cid = 0;
bit_buffer_append_byte(instance->tx_buffer, 0x1d); bit_buffer_append_byte(instance->tx_buffer, 0x1d);
bit_buffer_append_bytes(instance->tx_buffer, data->uid, ISO14443_3B_UID_SIZE); bit_buffer_append_bytes(instance->tx_buffer, data->uid, ISO14443_3B_UID_SIZE);
bit_buffer_append_byte(instance->tx_buffer, 0x00); bit_buffer_append_byte(instance->tx_buffer, 0x00);
bit_buffer_append_byte(instance->tx_buffer, ISO14443_3B_ATTRIB_FRAME_SIZE_256); bit_buffer_append_byte(instance->tx_buffer, ISO14443_3B_ATTRIB_FRAME_SIZE_256);
bit_buffer_append_byte(instance->tx_buffer, 0x01); bit_buffer_append_byte(instance->tx_buffer, 0x01);
bit_buffer_append_byte(instance->tx_buffer, 0x00); bit_buffer_append_byte(instance->tx_buffer, cid);
ret = iso14443_3b_poller_frame_exchange( ret = iso14443_3b_poller_frame_exchange(
instance, instance->tx_buffer, instance->rx_buffer, iso14443_3b_get_fwt_fc_max(data)); instance, instance->tx_buffer, instance->rx_buffer, iso14443_3b_get_fwt_fc_max(data));
@ -138,11 +139,10 @@ Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso144
bit_buffer_get_size_bytes(instance->rx_buffer)); bit_buffer_get_size_bytes(instance->rx_buffer));
} }
if(bit_buffer_get_byte(instance->rx_buffer, 0) != 0) { uint8_t cid_received = bit_buffer_get_byte(instance->rx_buffer, 0);
FURI_LOG_D( // 15 bit is RFU
TAG, if((cid_received & 0x7f) != cid) {
"Incorrect CID in ATTRIB response: %02X", FURI_LOG_D(TAG, "Incorrect CID in ATTRIB response: %02X", cid_received);
bit_buffer_get_byte(instance->rx_buffer, 0));
instance->state = Iso14443_3bPollerStateActivationFailed; instance->state = Iso14443_3bPollerStateActivationFailed;
ret = Iso14443_3bErrorCommunication; ret = Iso14443_3bErrorCommunication;
break; break;

View File

@ -40,10 +40,11 @@ static void mf_classic_listener_reset_state(MfClassicListener* instance) {
static MfClassicListenerCommand static MfClassicListenerCommand
mf_classic_listener_halt_handler(MfClassicListener* instance, BitBuffer* buff) { mf_classic_listener_halt_handler(MfClassicListener* instance, BitBuffer* buff) {
UNUSED(instance);
MfClassicListenerCommand command = MfClassicListenerCommandNack; MfClassicListenerCommand command = MfClassicListenerCommandNack;
if(bit_buffer_get_byte(buff, 1) == MF_CLASSIC_CMD_HALT_LSB) { if(bit_buffer_get_byte(buff, 1) == MF_CLASSIC_CMD_HALT_LSB) {
mf_classic_listener_reset_state(instance);
command = MfClassicListenerCommandSleep; command = MfClassicListenerCommandSleep;
} }
@ -59,10 +60,7 @@ static MfClassicListenerCommand mf_classic_listener_auth_first_part_handler(
do { do {
instance->state = MfClassicListenerStateIdle; instance->state = MfClassicListenerStateIdle;
if(block_num >= instance->total_block_num) { if(block_num >= instance->total_block_num) break;
mf_classic_listener_reset_state(instance);
break;
}
uint8_t sector_num = mf_classic_get_sector_by_block(block_num); uint8_t sector_num = mf_classic_get_sector_by_block(block_num);
@ -135,7 +133,7 @@ static MfClassicListenerCommand
instance->cmd_in_progress = false; instance->cmd_in_progress = false;
if(bit_buffer_get_size_bytes(buff) != (sizeof(MfClassicNr) + sizeof(MfClassicAr))) { if(bit_buffer_get_size_bytes(buff) != (sizeof(MfClassicNr) + sizeof(MfClassicAr))) {
mf_classic_listener_reset_state(instance); command = MfClassicListenerCommandSleep;
break; break;
} }
bit_buffer_write_bytes_mid(buff, instance->auth_context.nr.data, 0, sizeof(MfClassicNr)); bit_buffer_write_bytes_mid(buff, instance->auth_context.nr.data, 0, sizeof(MfClassicNr));
@ -157,7 +155,7 @@ static MfClassicListenerCommand
if(secret_poller != prng_successor(nt_num, 64)) { if(secret_poller != prng_successor(nt_num, 64)) {
FURI_LOG_T( FURI_LOG_T(
TAG, "Wrong reader key: %08lX != %08lX", secret_poller, prng_successor(nt_num, 64)); TAG, "Wrong reader key: %08lX != %08lX", secret_poller, prng_successor(nt_num, 64));
mf_classic_listener_reset_state(instance); command = MfClassicListenerCommandSleep;
break; break;
} }
@ -610,9 +608,11 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) {
} }
mf_classic_listener_send_short_frame(instance, nack); mf_classic_listener_send_short_frame(instance, nack);
mf_classic_listener_reset_state(instance);
} else if(mfc_command == MfClassicListenerCommandSilent) { } else if(mfc_command == MfClassicListenerCommandSilent) {
command = NfcCommandReset; command = NfcCommandReset;
} else if(mfc_command == MfClassicListenerCommandSleep) { } else if(mfc_command == MfClassicListenerCommandSleep) {
mf_classic_listener_reset_state(instance);
command = NfcCommandSleep; command = NfcCommandSleep;
} }
} else if(iso3_event->type == Iso14443_3aListenerEventTypeHalted) { } else if(iso3_event->type == Iso14443_3aListenerEventTypeHalted) {

View File

@ -371,11 +371,14 @@ static NfcCommand mf_ultralight_poller_handler_read_counters(MfUltralightPoller*
} }
static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPoller* instance) { static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPoller* instance) {
NfcCommand command = NfcCommandContinue;
if(mf_ultralight_support_feature( if(mf_ultralight_support_feature(
instance->feature_set, instance->feature_set,
MfUltralightFeatureSupportCheckTearingFlag | MfUltralightFeatureSupportSingleCounter)) { MfUltralightFeatureSupportCheckTearingFlag | MfUltralightFeatureSupportSingleCounter)) {
if(instance->tearing_flag_read == instance->tearing_flag_total) { if(instance->tearing_flag_read == instance->tearing_flag_total) {
instance->state = MfUltralightPollerStateTryDefaultPass; instance->state = MfUltralightPollerStateTryDefaultPass;
command = NfcCommandReset;
} else { } else {
bool single_counter = mf_ultralight_support_feature( bool single_counter = mf_ultralight_support_feature(
instance->feature_set, MfUltralightFeatureSupportSingleCounter); instance->feature_set, MfUltralightFeatureSupportSingleCounter);
@ -391,6 +394,7 @@ static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPo
} else if(instance->error != MfUltralightErrorNone) { } else if(instance->error != MfUltralightErrorNone) {
FURI_LOG_D(TAG, "Reading tearing flag %d failed", instance->tearing_flag_read); FURI_LOG_D(TAG, "Reading tearing flag %d failed", instance->tearing_flag_read);
instance->state = MfUltralightPollerStateTryDefaultPass; instance->state = MfUltralightPollerStateTryDefaultPass;
command = NfcCommandReset;
} else { } else {
instance->tearing_flag_read++; instance->tearing_flag_read++;
} }
@ -398,9 +402,10 @@ static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPo
} else { } else {
FURI_LOG_D(TAG, "Skip reading tearing flags"); FURI_LOG_D(TAG, "Skip reading tearing flags");
instance->state = MfUltralightPollerStateTryDefaultPass; instance->state = MfUltralightPollerStateTryDefaultPass;
command = NfcCommandReset;
} }
return NfcCommandContinue; return command;
} }
static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance) { static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance) {

View File

@ -34,6 +34,7 @@ env.Append(
File("hex.h"), File("hex.h"),
File("simple_array.h"), File("simple_array.h"),
File("bit_buffer.h"), File("bit_buffer.h"),
File("keys_dict.h"),
], ],
) )

334
lib/toolbox/keys_dict.c Normal file
View File

@ -0,0 +1,334 @@
#include "keys_dict.h"
#include <storage/storage.h>
#include <flipper_format/flipper_format.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#include <toolbox/args.h>
#define TAG "KeysDict"
struct KeysDict {
Stream* stream;
size_t key_size;
size_t key_size_symbols;
size_t total_keys;
};
static inline void keys_dict_add_ending_new_line(KeysDict* instance) {
if(stream_seek(instance->stream, -1, StreamOffsetFromEnd)) {
uint8_t last_char = 0;
// Check if the last char is new line or add a new line
if(stream_read(instance->stream, &last_char, 1) == 1 && last_char != '\n') {
FURI_LOG_D(TAG, "Adding new line ending");
stream_write_char(instance->stream, '\n');
}
stream_rewind(instance->stream);
}
}
static bool keys_dict_read_key_line(KeysDict* instance, FuriString* line, bool* is_endfile) {
if(stream_read_line(instance->stream, line) == false) {
*is_endfile = true;
}
else {
FURI_LOG_T(
TAG, "Read line: %s, len: %zu", furi_string_get_cstr(line), furi_string_size(line));
bool is_comment = furi_string_get_char(line, 0) == '#';
if(!is_comment) {
furi_string_left(line, instance->key_size_symbols - 1);
}
bool is_correct_size = furi_string_size(line) == instance->key_size_symbols - 1;
return !is_comment && is_correct_size;
}
return false;
}
bool keys_dict_check_presence(const char* path) {
furi_assert(path);
Storage* storage = furi_record_open(RECORD_STORAGE);
bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK;
furi_record_close(RECORD_STORAGE);
return dict_present;
}
KeysDict* keys_dict_alloc(const char* path, KeysDictMode mode, size_t key_size) {
furi_assert(path);
furi_assert(key_size > 0);
KeysDict* instance = malloc(sizeof(KeysDict));
Storage* storage = furi_record_open(RECORD_STORAGE);
furi_assert(storage);
instance->stream = buffered_file_stream_alloc(storage);
furi_assert(instance->stream);
FS_OpenMode open_mode = (mode == KeysDictModeOpenAlways) ? FSOM_OPEN_ALWAYS :
FSOM_OPEN_EXISTING;
// Byte = 2 symbols + 1 end of line
instance->key_size = key_size;
instance->key_size_symbols = key_size * 2 + 1;
instance->total_keys = 0;
bool file_exists =
buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode);
if(!file_exists) {
buffered_file_stream_close(instance->stream);
} else {
// Eventually add new line character in the last line to avoid skipping keys
keys_dict_add_ending_new_line(instance);
}
FuriString* line = furi_string_alloc();
bool is_endfile = false;
// In this loop we only count the entries in the file
// We prefer not to load the whole file in memory for space reasons
while(file_exists && !is_endfile) {
bool read_key = keys_dict_read_key_line(instance, line, &is_endfile);
if(read_key) {
instance->total_keys++;
}
}
stream_rewind(instance->stream);
FURI_LOG_I(TAG, "Loaded dictionary with %zu keys", instance->total_keys);
furi_string_free(line);
return instance;
}
void keys_dict_free(KeysDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
buffered_file_stream_close(instance->stream);
stream_free(instance->stream);
free(instance);
furi_record_close(RECORD_STORAGE);
}
static void keys_dict_int_to_str(KeysDict* instance, const uint8_t* key_int, FuriString* key_str) {
furi_assert(instance);
furi_assert(key_str);
furi_assert(key_int);
furi_string_reset(key_str);
for(size_t i = 0; i < instance->key_size; i++)
furi_string_cat_printf(key_str, "%02X", key_int[i]);
}
static void keys_dict_str_to_int(KeysDict* instance, FuriString* key_str, uint64_t* key_int) {
furi_assert(instance);
furi_assert(key_str);
furi_assert(key_int);
uint8_t key_byte_tmp;
char h, l;
*key_int = 0ULL;
for(size_t i = 0; i < instance->key_size_symbols - 1; i += 2) {
h = furi_string_get_char(key_str, i);
l = furi_string_get_char(key_str, i + 1);
args_char_to_hex(h, l, &key_byte_tmp);
*key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2));
}
}
size_t keys_dict_get_total_keys(KeysDict* instance) {
furi_assert(instance);
return instance->total_keys;
}
bool keys_dict_rewind(KeysDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
return stream_rewind(instance->stream);
}
static bool keys_dict_get_next_key_str(KeysDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(key);
bool key_read = false;
bool is_endfile = false;
furi_string_reset(key);
while(!key_read && !is_endfile) key_read = keys_dict_read_key_line(instance, key, &is_endfile);
return key_read;
}
bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
furi_assert(key);
FuriString* temp_key = furi_string_alloc();
bool key_read = keys_dict_get_next_key_str(instance, temp_key);
if(key_read) {
size_t tmp_len = key_size;
uint64_t key_int = 0;
keys_dict_str_to_int(instance, temp_key, &key_int);
while(tmp_len--) {
key[tmp_len] = (uint8_t)key_int;
key_int >>= 8;
}
}
furi_string_free(temp_key);
return key_read;
}
static bool keys_dict_is_key_present_str(KeysDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(key);
FuriString* line = furi_string_alloc();
bool is_endfile = false;
bool line_found = false;
uint32_t actual_pos = stream_tell(instance->stream);
stream_rewind(instance->stream);
while(!line_found && !is_endfile)
line_found = // The line is found if the line was read and the key is equal to the line
(keys_dict_read_key_line(instance, line, &is_endfile)) &&
(furi_string_equal(key, line));
furi_string_free(line);
// Restore the position of the stream
stream_seek(instance->stream, actual_pos, StreamOffsetFromStart);
return line_found;
}
bool keys_dict_is_key_present(KeysDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
furi_assert(key);
FuriString* temp_key = furi_string_alloc();
keys_dict_int_to_str(instance, key, temp_key);
bool key_found = keys_dict_is_key_present_str(instance, temp_key);
furi_string_free(temp_key);
return key_found;
}
static bool keys_dict_add_key_str(KeysDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(key);
furi_string_cat_str(key, "\n");
bool key_added = false;
uint32_t actual_pos = stream_tell(instance->stream);
if(stream_seek(instance->stream, 0, StreamOffsetFromEnd) &&
stream_insert_string(instance->stream, key)) {
instance->total_keys++;
key_added = true;
}
stream_seek(instance->stream, actual_pos, StreamOffsetFromStart);
return key_added;
}
bool keys_dict_add_key(KeysDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
furi_assert(key);
FuriString* temp_key = furi_string_alloc();
furi_assert(temp_key);
keys_dict_int_to_str(instance, key, temp_key);
bool key_added = keys_dict_add_key_str(instance, temp_key);
FURI_LOG_I(TAG, "Added key %s", furi_string_get_cstr(temp_key));
furi_string_free(temp_key);
return key_added;
}
bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
furi_assert(key);
bool key_removed = false;
uint8_t* temp_key = malloc(key_size);
stream_rewind(instance->stream);
while(!key_removed) {
if(!keys_dict_get_next_key(instance, temp_key, key_size)) {
break;
}
if(memcmp(temp_key, key, key_size) == 0) {
stream_seek(instance->stream, -instance->key_size_symbols, StreamOffsetFromCurrent);
if(stream_delete(instance->stream, instance->key_size_symbols) == false) {
break;
}
instance->total_keys--;
key_removed = true;
}
}
FuriString* tmp = furi_string_alloc();
keys_dict_int_to_str(instance, key, tmp);
FURI_LOG_I(TAG, "Removed key %s", furi_string_get_cstr(tmp));
furi_string_free(tmp);
stream_rewind(instance->stream);
free(temp_key);
return key_removed;
}

103
lib/toolbox/keys_dict.h Normal file
View File

@ -0,0 +1,103 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
KeysDictModeOpenExisting,
KeysDictModeOpenAlways,
} KeysDictMode;
typedef struct KeysDict KeysDict;
/** Check if the file list exists
*
* @param path - list path
*
* @return true if list exists, false otherwise
*/
bool keys_dict_check_presence(const char* path);
/** Open or create list
* Depending on mode, list will be opened or created.
*
* @param path - Path of the file that contain the list
* @param mode - ListKeysMode value
* @param key_size - Size of each key in bytes
*
* @return Returns KeysDict list instance
*/
KeysDict* keys_dict_alloc(const char* path, KeysDictMode mode, size_t key_size);
/** Close list
*
* @param instance - KeysDict list instance
*/
void keys_dict_free(KeysDict* instance);
/** Get total number of keys in list
*
* @param instance - KeysDict list instance
*
* @return Returns total number of keys in list
*/
size_t keys_dict_get_total_keys(KeysDict* instance);
/** Rewind list
*
* @param instance - KeysDict list instance
*
* @return Returns true if rewind was successful, false otherwise
*/
bool keys_dict_rewind(KeysDict* instance);
/** Check if key is present in list
*
* @param instance - KeysDict list instance
* @param key - key to check
* @param key_size - Size of the key in bytes
*
* @return Returns true if key is present, false otherwise
*/
bool keys_dict_is_key_present(KeysDict* instance, const uint8_t* key, size_t key_size);
/** Get next key from the list
* This function will return next key from list. If there are no more
* keys, it will return false, and keys_dict_rewind() should be called.
*
* @param instance - KeysDict list instance
* @param key - Array where to store key
* @param key_size - Size of key in bytes
*
* @return Returns true if key was successfully retrieved, false otherwise
*/
bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size);
/** Add key to list
*
* @param instance - KeysDict list instance
* @param key - Key to add
* @param key_size - Size of the key in bytes
*
* @return Returns true if key was successfully added, false otherwise
*/
bool keys_dict_add_key(KeysDict* instance, const uint8_t* key, size_t key_size);
/** Delete key from list
*
* @param instance - KeysDict list instance
* @param key - Key to delete
* @param key_size - Size of the key in bytes
*
* @return Returns true if key was successfully deleted, false otherwise
*/
bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_size);
#ifdef __cplusplus
}
#endif

View File

@ -11,6 +11,27 @@ WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)")
# Excludes all files ending with ~, usually created by editors as backup files # Excludes all files ending with ~, usually created by editors as backup files
GLOB_FILE_EXCLUSION = ["*~"] GLOB_FILE_EXCLUSION = ["*~"]
# List of environment variables to proxy to child processes
FORWARDED_ENV_VARIABLES = [
# CI/CD variables
"WORKFLOW_BRANCH_OR_TAG",
"DIST_SUFFIX",
# Python & other tools
"HOME",
"APPDATA",
"PYTHONHOME",
"PYTHONNOUSERSITE",
"TMP",
"TEMP",
# ccache
"CCACHE_DISABLE",
# Colors for tools
"TERM",
# Toolchain
"FBT_TOOLCHAIN_PATH",
"UFBT_HOME",
]
def tempfile_arg_esc_func(arg): def tempfile_arg_esc_func(arg):
arg = quote_spaces(arg) arg = quote_spaces(arg)

View File

@ -25,33 +25,10 @@ forward_os_env = {
"PATH": os.environ["PATH"], "PATH": os.environ["PATH"],
} }
# Proxying environment to child processes & scripts
variables_to_forward = [
# CI/CD variables
"WORKFLOW_BRANCH_OR_TAG",
"DIST_SUFFIX",
# Python & other tools
"HOME",
"APPDATA",
"PYTHONHOME",
"PYTHONNOUSERSITE",
"TMP",
"TEMP",
# Colors for tools
"TERM",
]
if proxy_env := GetOption("proxy_env"):
variables_to_forward.extend(proxy_env.split(","))
for env_value_name in variables_to_forward:
if environ_value := os.environ.get(env_value_name, None):
forward_os_env[env_value_name] = environ_value
# Core environment init - loads SDK state, sets up paths, etc. # Core environment init - loads SDK state, sets up paths, etc.
core_env = Environment( core_env = Environment(
variables=ufbt_variables, variables=ufbt_variables,
ENV=forward_os_env,
UFBT_STATE_DIR=ufbt_state_dir, UFBT_STATE_DIR=ufbt_state_dir,
UFBT_CURRENT_SDK_DIR=ufbt_current_sdk_dir, UFBT_CURRENT_SDK_DIR=ufbt_current_sdk_dir,
UFBT_SCRIPT_DIR=ufbt_script_dir, UFBT_SCRIPT_DIR=ufbt_script_dir,
@ -69,6 +46,7 @@ core_env.Append(CPPDEFINES=GetOption("extra_defines"))
from fbt.appmanifest import FlipperApplication, FlipperAppType from fbt.appmanifest import FlipperApplication, FlipperAppType
from fbt.sdk.cache import SdkCache from fbt.sdk.cache import SdkCache
from fbt.util import ( from fbt.util import (
FORWARDED_ENV_VARIABLES,
path_as_posix, path_as_posix,
resolve_real_dir_node, resolve_real_dir_node,
single_quote, single_quote,
@ -76,8 +54,19 @@ from fbt.util import (
wrap_tempfile, wrap_tempfile,
) )
variables_to_forward = list(FORWARDED_ENV_VARIABLES)
if proxy_env := GetOption("proxy_env"):
variables_to_forward.extend(proxy_env.split(","))
for env_value_name in variables_to_forward:
if environ_value := os.environ.get(env_value_name, None):
forward_os_env[env_value_name] = environ_value
# Base environment with all tools loaded from SDK # Base environment with all tools loaded from SDK
env = core_env.Clone( env = core_env.Clone(
ENV=forward_os_env,
toolpath=[core_env["FBT_SCRIPT_DIR"].Dir("fbt_tools")], toolpath=[core_env["FBT_SCRIPT_DIR"].Dir("fbt_tools")],
tools=[ tools=[
"fbt_tweaks", "fbt_tweaks",
@ -477,9 +466,12 @@ else:
dist_env.PhonyTarget("dolphin_ext", Action(missing_dolphin_folder, None)) dist_env.PhonyTarget("dolphin_ext", Action(missing_dolphin_folder, None))
# print(env.Dump())
dist_env.PhonyTarget( dist_env.PhonyTarget(
"env", "env",
"@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", '@echo "FBT_TOOLCHAIN_PATH='
+ forward_os_env["FBT_TOOLCHAIN_PATH"]
+ '" source $( "${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh" $)',
) )
dist_env.PostConfigureUfbtEnvionment() dist_env.PostConfigureUfbtEnvionment()

View File

@ -2,3 +2,5 @@ dist/*
.vscode .vscode
.clang-format .clang-format
.editorconfig .editorconfig
.env
.ufbt

View File

@ -44,7 +44,11 @@ How to create a new application:
4. Run `ufbt launch` to build and upload your application. 4. Run `ufbt launch` to build and upload your application.
How to open a shell with toolchain environment and other build tools: How to open a shell with toolchain environment and other build tools:
In your shell, type "source `ufbt -s env`". You can also use "." instead of "source". In your shell, type "eval `ufbt -s env`".
How to update uFBT SDK:
Run "ufbt update" to fetch latest SDK.
You can also specify branch, target and/or channel options. See "ufbt update -h" for details.
""" """

View File

@ -1,6 +1,5 @@
import json import json
import os import os
import pathlib
import sys import sys
from functools import reduce from functools import reduce

View File

@ -1,13 +1,14 @@
from SCons.Platform import TempFileMunge
from fbt.util import (
tempfile_arg_esc_func,
single_quote,
wrap_tempfile,
resolve_real_dir_node,
)
import os
import multiprocessing import multiprocessing
import os
from fbt.util import (
FORWARDED_ENV_VARIABLES,
resolve_real_dir_node,
single_quote,
tempfile_arg_esc_func,
wrap_tempfile,
)
from SCons.Platform import TempFileMunge
Import("VAR_ENV") Import("VAR_ENV")
@ -15,23 +16,9 @@ forward_os_env = {
# Import PATH from OS env - scons doesn't do that by default # Import PATH from OS env - scons doesn't do that by default
"PATH": os.environ["PATH"], "PATH": os.environ["PATH"],
} }
# Proxying CI environment to child processes & scripts
variables_to_forward = [ variables_to_forward = list(FORWARDED_ENV_VARIABLES)
# CI/CD variables
"WORKFLOW_BRANCH_OR_TAG",
"DIST_SUFFIX",
# Python & other tools
"HOME",
"APPDATA",
"PYTHONHOME",
"PYTHONNOUSERSITE",
"TMP",
"TEMP",
# ccache
"CCACHE_DISABLE",
# Colors for tools
"TERM",
]
if proxy_env := GetOption("proxy_env"): if proxy_env := GetOption("proxy_env"):
variables_to_forward.extend(proxy_env.split(",")) variables_to_forward.extend(proxy_env.split(","))

View File

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,49.1,, Version,+,50.0,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,
@ -139,6 +139,7 @@ Header,+,lib/toolbox/crc32_calc.h,,
Header,+,lib/toolbox/dir_walk.h,, Header,+,lib/toolbox/dir_walk.h,,
Header,+,lib/toolbox/float_tools.h,, Header,+,lib/toolbox/float_tools.h,,
Header,+,lib/toolbox/hex.h,, Header,+,lib/toolbox/hex.h,,
Header,+,lib/toolbox/keys_dict.h,,
Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_decoder.h,,
Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/manchester_encoder.h,,
Header,+,lib/toolbox/name_generator.h,, Header,+,lib/toolbox/name_generator.h,,
@ -1247,6 +1248,7 @@ Function,-,furi_hal_rtc_init_early,void,
Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag
Function,+,furi_hal_rtc_is_leap_year,_Bool,uint16_t Function,+,furi_hal_rtc_is_leap_year,_Bool,uint16_t
Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag
Function,+,furi_hal_rtc_reset_registers,void,
Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode
Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime* Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime*
Function,+,furi_hal_rtc_set_fault_data,void,uint32_t Function,+,furi_hal_rtc_set_fault_data,void,uint32_t
@ -1591,6 +1593,15 @@ Function,-,j1f,float,float
Function,-,jn,double,"int, double" Function,-,jn,double,"int, double"
Function,-,jnf,float,"int, float" Function,-,jnf,float,"int, float"
Function,-,jrand48,long,unsigned short[3] Function,-,jrand48,long,unsigned short[3]
Function,+,keys_dict_add_key,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_alloc,KeysDict*,"const char*, KeysDictMode, size_t"
Function,+,keys_dict_check_presence,_Bool,const char*
Function,+,keys_dict_delete_key,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_free,void,KeysDict*
Function,+,keys_dict_get_next_key,_Bool,"KeysDict*, uint8_t*, size_t"
Function,+,keys_dict_get_total_keys,size_t,KeysDict*
Function,+,keys_dict_is_key_present,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_rewind,_Bool,KeysDict*
Function,-,l64a,char*,long Function,-,l64a,char*,long
Function,-,labs,long,long Function,-,labs,long,long
Function,-,lcong48,void,unsigned short[7] Function,-,lcong48,void,unsigned short[7]

1 entry status name type params
2 Version + 49.1 50.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
139 Header + lib/toolbox/dir_walk.h
140 Header + lib/toolbox/float_tools.h
141 Header + lib/toolbox/hex.h
142 Header + lib/toolbox/keys_dict.h
143 Header + lib/toolbox/manchester_decoder.h
144 Header + lib/toolbox/manchester_encoder.h
145 Header + lib/toolbox/name_generator.h
1248 Function + furi_hal_rtc_is_flag_set _Bool FuriHalRtcFlag
1249 Function + furi_hal_rtc_is_leap_year _Bool uint16_t
1250 Function + furi_hal_rtc_reset_flag void FuriHalRtcFlag
1251 Function + furi_hal_rtc_reset_registers void
1252 Function + furi_hal_rtc_set_boot_mode void FuriHalRtcBootMode
1253 Function + furi_hal_rtc_set_datetime void FuriHalRtcDateTime*
1254 Function + furi_hal_rtc_set_fault_data void uint32_t
1593 Function - jn double int, double
1594 Function - jnf float int, float
1595 Function - jrand48 long unsigned short[3]
1596 Function + keys_dict_add_key _Bool KeysDict*, const uint8_t*, size_t
1597 Function + keys_dict_alloc KeysDict* const char*, KeysDictMode, size_t
1598 Function + keys_dict_check_presence _Bool const char*
1599 Function + keys_dict_delete_key _Bool KeysDict*, const uint8_t*, size_t
1600 Function + keys_dict_free void KeysDict*
1601 Function + keys_dict_get_next_key _Bool KeysDict*, uint8_t*, size_t
1602 Function + keys_dict_get_total_keys size_t KeysDict*
1603 Function + keys_dict_is_key_present _Bool KeysDict*, const uint8_t*, size_t
1604 Function + keys_dict_rewind _Bool KeysDict*
1605 Function - l64a char* long
1606 Function - labs long long
1607 Function - lcong48 void unsigned short[7]

View File

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,49.1,, Version,+,50.0,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
@ -114,7 +114,6 @@ Header,+,lib/nanopb/pb_encode.h,,
Header,+,lib/nfc/helpers/iso13239_crc.h,, Header,+,lib/nfc/helpers/iso13239_crc.h,,
Header,+,lib/nfc/helpers/iso14443_crc.h,, Header,+,lib/nfc/helpers/iso14443_crc.h,,
Header,+,lib/nfc/helpers/nfc_data_generator.h,, Header,+,lib/nfc/helpers/nfc_data_generator.h,,
Header,+,lib/nfc/helpers/nfc_dict.h,,
Header,+,lib/nfc/helpers/nfc_util.h,, Header,+,lib/nfc/helpers/nfc_util.h,,
Header,+,lib/nfc/nfc.h,, Header,+,lib/nfc/nfc.h,,
Header,+,lib/nfc/nfc_device.h,, Header,+,lib/nfc/nfc_device.h,,
@ -204,6 +203,7 @@ Header,+,lib/toolbox/crc32_calc.h,,
Header,+,lib/toolbox/dir_walk.h,, Header,+,lib/toolbox/dir_walk.h,,
Header,+,lib/toolbox/float_tools.h,, Header,+,lib/toolbox/float_tools.h,,
Header,+,lib/toolbox/hex.h,, Header,+,lib/toolbox/hex.h,,
Header,+,lib/toolbox/keys_dict.h,,
Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_decoder.h,,
Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/manchester_encoder.h,,
Header,+,lib/toolbox/name_generator.h,, Header,+,lib/toolbox/name_generator.h,,
@ -1414,6 +1414,7 @@ Function,-,furi_hal_rtc_init_early,void,
Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag
Function,+,furi_hal_rtc_is_leap_year,_Bool,uint16_t Function,+,furi_hal_rtc_is_leap_year,_Bool,uint16_t
Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag
Function,+,furi_hal_rtc_reset_registers,void,
Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode
Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime* Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime*
Function,+,furi_hal_rtc_set_fault_data,void,uint32_t Function,+,furi_hal_rtc_set_fault_data,void,uint32_t
@ -1966,6 +1967,15 @@ Function,-,j1f,float,float
Function,-,jn,double,"int, double" Function,-,jn,double,"int, double"
Function,-,jnf,float,"int, float" Function,-,jnf,float,"int, float"
Function,-,jrand48,long,unsigned short[3] Function,-,jrand48,long,unsigned short[3]
Function,+,keys_dict_add_key,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_alloc,KeysDict*,"const char*, KeysDictMode, size_t"
Function,+,keys_dict_check_presence,_Bool,const char*
Function,+,keys_dict_delete_key,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_free,void,KeysDict*
Function,+,keys_dict_get_next_key,_Bool,"KeysDict*, uint8_t*, size_t"
Function,+,keys_dict_get_total_keys,size_t,KeysDict*
Function,+,keys_dict_is_key_present,_Bool,"KeysDict*, const uint8_t*, size_t"
Function,+,keys_dict_rewind,_Bool,KeysDict*
Function,-,l64a,char*,long Function,-,l64a,char*,long
Function,-,labs,long,long Function,-,labs,long,long
Function,-,lcong48,void,unsigned short[7] Function,-,lcong48,void,unsigned short[7]
@ -2289,8 +2299,8 @@ Function,+,mf_classic_is_value_block,_Bool,"MfClassicSectorTrailer*, uint8_t"
Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t"
Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*"
Function,+,mf_classic_poller_auth_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" Function,+,mf_classic_poller_auth_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*"
Function,+,mf_classic_poller_get_nt_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*"
Function,+,mf_classic_poller_get_nt,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" Function,+,mf_classic_poller_get_nt,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*"
Function,+,mf_classic_poller_get_nt_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*"
Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller* Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller*
Function,+,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*" Function,+,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*"
Function,+,mf_classic_poller_sync_auth,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" Function,+,mf_classic_poller_sync_auth,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*"
@ -2440,15 +2450,6 @@ Function,+,nfc_device_save,_Bool,"NfcDevice*, const char*"
Function,+,nfc_device_set_data,void,"NfcDevice*, NfcProtocol, const NfcDeviceData*" Function,+,nfc_device_set_data,void,"NfcDevice*, NfcProtocol, const NfcDeviceData*"
Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*" Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*"
Function,+,nfc_device_set_uid,_Bool,"NfcDevice*, const uint8_t*, size_t" Function,+,nfc_device_set_uid,_Bool,"NfcDevice*, const uint8_t*, size_t"
Function,+,nfc_dict_add_key,_Bool,"NfcDict*, const uint8_t*, size_t"
Function,+,nfc_dict_alloc,NfcDict*,"const char*, NfcDictMode, size_t"
Function,+,nfc_dict_check_presence,_Bool,const char*
Function,+,nfc_dict_delete_key,_Bool,"NfcDict*, const uint8_t*, size_t"
Function,+,nfc_dict_free,void,NfcDict*
Function,+,nfc_dict_get_next_key,_Bool,"NfcDict*, uint8_t*, size_t"
Function,+,nfc_dict_get_total_keys,uint32_t,NfcDict*
Function,+,nfc_dict_is_key_present,_Bool,"NfcDict*, const uint8_t*, size_t"
Function,+,nfc_dict_rewind,_Bool,NfcDict*
Function,+,nfc_felica_listener_set_sensf_res_data,NfcError,"Nfc*, const uint8_t*, const uint8_t, const uint8_t*, const uint8_t" Function,+,nfc_felica_listener_set_sensf_res_data,NfcError,"Nfc*, const uint8_t*, const uint8_t, const uint8_t*, const uint8_t"
Function,+,nfc_free,void,Nfc* Function,+,nfc_free,void,Nfc*
Function,+,nfc_iso14443a_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,+,nfc_iso14443a_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t"
@ -2487,6 +2488,7 @@ Function,+,nfc_set_mask_receive_time_fc,void,"Nfc*, uint32_t"
Function,+,nfc_start,void,"Nfc*, NfcEventCallback, void*" Function,+,nfc_start,void,"Nfc*, NfcEventCallback, void*"
Function,+,nfc_stop,void,Nfc* Function,+,nfc_stop,void,Nfc*
Function,+,nfc_util_bytes2num,uint64_t,"const uint8_t*, uint8_t" Function,+,nfc_util_bytes2num,uint64_t,"const uint8_t*, uint8_t"
Function,+,nfc_util_bytes2num_little_endian,uint64_t,"const uint8_t*, uint8_t"
Function,+,nfc_util_even_parity32,uint8_t,uint32_t Function,+,nfc_util_even_parity32,uint8_t,uint32_t
Function,+,nfc_util_num2bytes,void,"uint64_t, uint8_t, uint8_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_parity,void,"const uint8_t*, uint8_t*, uint8_t"

1 entry status name type params
2 Version + 49.1 50.0
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/cli/cli.h
114 Header + lib/nfc/helpers/iso13239_crc.h
115 Header + lib/nfc/helpers/iso14443_crc.h
116 Header + lib/nfc/helpers/nfc_data_generator.h
Header + lib/nfc/helpers/nfc_dict.h
117 Header + lib/nfc/helpers/nfc_util.h
118 Header + lib/nfc/nfc.h
119 Header + lib/nfc/nfc_device.h
203 Header + lib/toolbox/dir_walk.h
204 Header + lib/toolbox/float_tools.h
205 Header + lib/toolbox/hex.h
206 Header + lib/toolbox/keys_dict.h
207 Header + lib/toolbox/manchester_decoder.h
208 Header + lib/toolbox/manchester_encoder.h
209 Header + lib/toolbox/name_generator.h
1414 Function + furi_hal_rtc_is_flag_set _Bool FuriHalRtcFlag
1415 Function + furi_hal_rtc_is_leap_year _Bool uint16_t
1416 Function + furi_hal_rtc_reset_flag void FuriHalRtcFlag
1417 Function + furi_hal_rtc_reset_registers void
1418 Function + furi_hal_rtc_set_boot_mode void FuriHalRtcBootMode
1419 Function + furi_hal_rtc_set_datetime void FuriHalRtcDateTime*
1420 Function + furi_hal_rtc_set_fault_data void uint32_t
1967 Function - jn double int, double
1968 Function - jnf float int, float
1969 Function - jrand48 long unsigned short[3]
1970 Function + keys_dict_add_key _Bool KeysDict*, const uint8_t*, size_t
1971 Function + keys_dict_alloc KeysDict* const char*, KeysDictMode, size_t
1972 Function + keys_dict_check_presence _Bool const char*
1973 Function + keys_dict_delete_key _Bool KeysDict*, const uint8_t*, size_t
1974 Function + keys_dict_free void KeysDict*
1975 Function + keys_dict_get_next_key _Bool KeysDict*, uint8_t*, size_t
1976 Function + keys_dict_get_total_keys size_t KeysDict*
1977 Function + keys_dict_is_key_present _Bool KeysDict*, const uint8_t*, size_t
1978 Function + keys_dict_rewind _Bool KeysDict*
1979 Function - l64a char* long
1980 Function - labs long long
1981 Function - lcong48 void unsigned short[7]
2299 Function + mf_classic_load _Bool MfClassicData*, FlipperFormat*, uint32_t
2300 Function + mf_classic_poller_auth MfClassicError MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*
2301 Function + mf_classic_poller_auth_nested MfClassicError MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*
Function + mf_classic_poller_get_nt_nested MfClassicError MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*
2302 Function + mf_classic_poller_get_nt MfClassicError MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*
2303 Function + mf_classic_poller_get_nt_nested MfClassicError MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*
2304 Function + mf_classic_poller_halt MfClassicError MfClassicPoller*
2305 Function + mf_classic_poller_read_block MfClassicError MfClassicPoller*, uint8_t, MfClassicBlock*
2306 Function + mf_classic_poller_sync_auth MfClassicError Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*
2450 Function + nfc_device_set_data void NfcDevice*, NfcProtocol, const NfcDeviceData*
2451 Function + nfc_device_set_loading_callback void NfcDevice*, NfcLoadingCallback, void*
2452 Function + nfc_device_set_uid _Bool NfcDevice*, const uint8_t*, size_t
Function + nfc_dict_add_key _Bool NfcDict*, const uint8_t*, size_t
Function + nfc_dict_alloc NfcDict* const char*, NfcDictMode, size_t
Function + nfc_dict_check_presence _Bool const char*
Function + nfc_dict_delete_key _Bool NfcDict*, const uint8_t*, size_t
Function + nfc_dict_free void NfcDict*
Function + nfc_dict_get_next_key _Bool NfcDict*, uint8_t*, size_t
Function + nfc_dict_get_total_keys uint32_t NfcDict*
Function + nfc_dict_is_key_present _Bool NfcDict*, const uint8_t*, size_t
Function + nfc_dict_rewind _Bool NfcDict*
2453 Function + nfc_felica_listener_set_sensf_res_data NfcError Nfc*, const uint8_t*, const uint8_t, const uint8_t*, const uint8_t
2454 Function + nfc_free void Nfc*
2455 Function + nfc_iso14443a_listener_set_col_res_data NfcError Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t
2488 Function + nfc_start void Nfc*, NfcEventCallback, void*
2489 Function + nfc_stop void Nfc*
2490 Function + nfc_util_bytes2num uint64_t const uint8_t*, uint8_t
2491 Function + nfc_util_bytes2num_little_endian uint64_t const uint8_t*, uint8_t
2492 Function + nfc_util_even_parity32 uint8_t uint32_t
2493 Function + nfc_util_num2bytes void uint64_t, uint8_t, uint8_t*
2494 Function + nfc_util_odd_parity void const uint8_t*, uint8_t*, uint8_t

View File

@ -3,14 +3,21 @@
#include <furi_hal_version.h> #include <furi_hal_version.h>
#include <furi_hal_resources.h> #include <furi_hal_resources.h>
#include <stm32wbxx_ll_comp.h> #include <stm32wbxx_ll_comp.h>
#include <stm32wbxx_ll_pwr.h>
#define GET_SYSCFG_EXTI_PORT(gpio) \ static uint32_t furi_hal_gpio_invalid_argument_crash() {
(((gpio) == (GPIOA)) ? LL_SYSCFG_EXTI_PORTA : \ furi_crash("Invalid argument");
((gpio) == (GPIOB)) ? LL_SYSCFG_EXTI_PORTB : \ return 0;
((gpio) == (GPIOC)) ? LL_SYSCFG_EXTI_PORTC : \ }
((gpio) == (GPIOD)) ? LL_SYSCFG_EXTI_PORTD : \
((gpio) == (GPIOE)) ? LL_SYSCFG_EXTI_PORTE : \ #define GPIO_PORT_MAP(port, prefix) \
LL_SYSCFG_EXTI_PORTH) (((port) == (GPIOA)) ? prefix##A : \
((port) == (GPIOB)) ? prefix##B : \
((port) == (GPIOC)) ? prefix##C : \
((port) == (GPIOD)) ? prefix##D : \
((port) == (GPIOE)) ? prefix##E : \
((port) == (GPIOH)) ? prefix##H : \
furi_hal_gpio_invalid_argument_crash())
#define GPIO_PIN_MAP(pin, prefix) \ #define GPIO_PIN_MAP(pin, prefix) \
(((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \ (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \
@ -28,11 +35,16 @@
((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \ ((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \
((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \ ((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \
((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \ ((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \
prefix##15) ((pin) == (LL_GPIO_PIN_15)) ? prefix##15 : \
furi_hal_gpio_invalid_argument_crash())
#define GET_SYSCFG_EXTI_PORT(port) GPIO_PORT_MAP(port, LL_SYSCFG_EXTI_PORT)
#define GET_SYSCFG_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_SYSCFG_EXTI_LINE) #define GET_SYSCFG_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_SYSCFG_EXTI_LINE)
#define GET_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_EXTI_LINE_) #define GET_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_EXTI_LINE_)
#define GET_PWR_PORT(port) GPIO_PORT_MAP(port, LL_PWR_GPIO_)
#define GET_PWR_PIN(pin) GPIO_PIN_MAP(pin, LL_PWR_GPIO_BIT_)
static volatile GpioInterrupt gpio_interrupt[GPIO_NUMBER]; static volatile GpioInterrupt gpio_interrupt[GPIO_NUMBER];
static uint8_t furi_hal_gpio_get_pin_num(const GpioPin* gpio) { static uint8_t furi_hal_gpio_get_pin_num(const GpioPin* gpio) {
@ -65,9 +77,11 @@ void furi_hal_gpio_init_ex(
const GpioPull pull, const GpioPull pull,
const GpioSpeed speed, const GpioSpeed speed,
const GpioAltFn alt_fn) { const GpioAltFn alt_fn) {
uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port); const uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port);
uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin); const uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin);
uint32_t exti_line = GET_EXTI_LINE(gpio->pin); const uint32_t exti_line = GET_EXTI_LINE(gpio->pin);
const uint32_t pwr_port = GET_PWR_PORT(gpio->port);
const uint32_t pwr_pin = GET_PWR_PIN(gpio->pin);
// Configure gpio with interrupts disabled // Configure gpio with interrupts disabled
FURI_CRITICAL_ENTER(); FURI_CRITICAL_ENTER();
@ -92,13 +106,21 @@ void furi_hal_gpio_init_ex(
switch(pull) { switch(pull) {
case GpioPullNo: case GpioPullNo:
LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_NO); LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_NO);
LL_PWR_DisableGPIOPullUp(pwr_port, pwr_pin);
LL_PWR_DisableGPIOPullDown(pwr_port, pwr_pin);
break; break;
case GpioPullUp: case GpioPullUp:
LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_UP); LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_UP);
LL_PWR_DisableGPIOPullDown(pwr_port, pwr_pin);
LL_PWR_EnableGPIOPullUp(pwr_port, pwr_pin);
break; break;
case GpioPullDown: case GpioPullDown:
LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_DOWN); LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_DOWN);
LL_PWR_DisableGPIOPullUp(pwr_port, pwr_pin);
LL_PWR_EnableGPIOPullDown(pwr_port, pwr_pin);
break; break;
default:
furi_crash("Incorrect GpioPull");
} }
// Set gpio mode // Set gpio mode
@ -166,7 +188,7 @@ void furi_hal_gpio_init_ex(
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG); LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG);
break; break;
default: default:
break; furi_crash("Incorrect GpioMode");
} }
} }
FURI_CRITICAL_EXIT(); FURI_CRITICAL_EXIT();

View File

@ -132,13 +132,7 @@ void furi_hal_rtc_init_early() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterHeader); uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterHeader);
FuriHalRtcHeader* data = (FuriHalRtcHeader*)&data_reg; FuriHalRtcHeader* data = (FuriHalRtcHeader*)&data_reg;
if(data->magic != FURI_HAL_RTC_HEADER_MAGIC || data->version != FURI_HAL_RTC_HEADER_VERSION) { if(data->magic != FURI_HAL_RTC_HEADER_MAGIC || data->version != FURI_HAL_RTC_HEADER_VERSION) {
// Reset all our registers to ensure consistency furi_hal_rtc_reset_registers();
for(size_t i = 0; i < FuriHalRtcRegisterMAX; i++) {
furi_hal_rtc_set_register(i, 0);
}
data->magic = FURI_HAL_RTC_HEADER_MAGIC;
data->version = FURI_HAL_RTC_HEADER_VERSION;
furi_hal_rtc_set_register(FuriHalRtcRegisterHeader, data_reg);
} }
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
@ -171,6 +165,18 @@ void furi_hal_rtc_sync_shadow() {
} }
} }
void furi_hal_rtc_reset_registers() {
for(size_t i = 0; i < RTC_BKP_NUMBER; i++) {
furi_hal_rtc_set_register(i, 0);
}
uint32_t data_reg = 0;
FuriHalRtcHeader* data = (FuriHalRtcHeader*)&data_reg;
data->magic = FURI_HAL_RTC_HEADER_MAGIC;
data->version = FURI_HAL_RTC_HEADER_VERSION;
furi_hal_rtc_set_register(FuriHalRtcRegisterHeader, data_reg);
}
uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg) { uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg) {
return LL_RTC_BAK_GetRegister(RTC, reg); return LL_RTC_BAK_GetRegister(RTC, reg);
} }

View File

@ -56,8 +56,7 @@ void flipper_boot_recovery_exec() {
} }
if(!counter) { if(!counter) {
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); furi_hal_rtc_reset_registers();
furi_hal_rtc_set_pin_fails(0); furi_hal_rtc_set_flag(FuriHalRtcFlagStorageFormatInternal);
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
} }
} }

View File

@ -26,7 +26,7 @@ typedef struct {
typedef enum { typedef enum {
FuriHalRtcFlagDebug = (1 << 0), FuriHalRtcFlagDebug = (1 << 0),
FuriHalRtcFlagFactoryReset = (1 << 1), FuriHalRtcFlagStorageFormatInternal = (1 << 1),
FuriHalRtcFlagLock = (1 << 2), FuriHalRtcFlagLock = (1 << 2),
FuriHalRtcFlagC2Update = (1 << 3), FuriHalRtcFlagC2Update = (1 << 3),
FuriHalRtcFlagHandOrient = (1 << 4), FuriHalRtcFlagHandOrient = (1 << 4),
@ -91,6 +91,9 @@ void furi_hal_rtc_init();
/** Force sync shadow registers */ /** Force sync shadow registers */
void furi_hal_rtc_sync_shadow(); void furi_hal_rtc_sync_shadow();
/** Reset ALL RTC registers content */
void furi_hal_rtc_reset_registers();
/** Get RTC register content /** Get RTC register content
* *
* @param[in] reg The register identifier * @param[in] reg The register identifier