From 709fa633ffdd50ea4cf5111681027944f566b775 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 25 Jan 2023 12:15:01 +0700 Subject: [PATCH 01/17] ELF-loader: wait for notification to complete on app exit (#2335) --- applications/plugins/snake_game/snake_game.c | 4 ++-- lib/flipper_application/flipper_application.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/applications/plugins/snake_game/snake_game.c b/applications/plugins/snake_game/snake_game.c index f9b4d30af..2815e2f37 100644 --- a/applications/plugins/snake_game/snake_game.c +++ b/applications/plugins/snake_game/snake_game.c @@ -394,8 +394,8 @@ int32_t snake_game_app(void* p) { release_mutex(&state_mutex, snake_state); } - // Wait for all notifications to be played and return backlight to normal state - notification_message_block(notification, &sequence_display_backlight_enforce_auto); + // Return backlight to normal state + notification_message(notification, &sequence_display_backlight_enforce_auto); furi_timer_free(timer); view_port_enabled_set(view_port, false); diff --git a/lib/flipper_application/flipper_application.c b/lib/flipper_application/flipper_application.c index 618a36231..8b049a7d4 100644 --- a/lib/flipper_application/flipper_application.c +++ b/lib/flipper_application/flipper_application.c @@ -1,5 +1,6 @@ #include "flipper_application.h" #include "elf/elf_file.h" +#include #define TAG "fapp" @@ -95,6 +96,15 @@ static int32_t flipper_application_thread(void* context) { elf_file_pre_run(last_loaded_app->elf); int32_t result = elf_file_run(last_loaded_app->elf, context); elf_file_post_run(last_loaded_app->elf); + + // wait until all notifications from RAM are completed + NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); + const NotificationSequence sequence_empty = { + NULL, + }; + notification_message_block(notifications, &sequence_empty); + furi_record_close(RECORD_NOTIFICATION); + return result; } From 5134f44c09d39344a8747655c0d59864bb574b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82adyn=20=28krzys=5Fh=29?= Date: Thu, 26 Jan 2023 09:28:36 +0100 Subject: [PATCH 02/17] nfc: Fix crash when using debug PCAP trace (#2338) --- lib/nfc/helpers/reader_analyzer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/nfc/helpers/reader_analyzer.c b/lib/nfc/helpers/reader_analyzer.c index af4869ca9..9bf37a60d 100644 --- a/lib/nfc/helpers/reader_analyzer.c +++ b/lib/nfc/helpers/reader_analyzer.c @@ -159,6 +159,7 @@ void reader_analyzer_stop(ReaderAnalyzer* instance) { } if(instance->pcap) { nfc_debug_pcap_free(instance->pcap); + instance->pcap = NULL; } } From 8fc834090d289ad75de8261ad69ec310a39b5834 Mon Sep 17 00:00:00 2001 From: Krzysztof Zdulski Date: Fri, 27 Jan 2023 06:00:25 +0100 Subject: [PATCH 03/17] nfc: Fix sector reads when one block is unreadable for MIFARE Classic (#2296) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix sector reads when one block is unreadable * Auth on the correct block instead of first * Fix in sector reader as well * Apply patch by @gornekich Co-authored-by: gornekich Co-authored-by: あく --- lib/nfc/protocols/mifare_classic.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index c91e9c605..d1aadf06f 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -595,6 +595,14 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { mf_classic_set_block_read(data, i, &block_tmp); blocks_read++; + } else if(i > start_block) { + // Try to re-auth to read block in case prevous block was protected from read + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyA, &crypto, false, 0)) break; + if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mf_classic_set_block_read(data, i, &block_tmp); + blocks_read++; + } } } else { blocks_read++; @@ -607,13 +615,20 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u if(!key_b_found) break; FURI_LOG_D(TAG, "Try to read blocks with key B"); key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b)); - furi_hal_nfc_sleep(); if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break; for(size_t i = start_block; i < start_block + total_blocks; i++) { if(!mf_classic_is_block_read(data, i)) { if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { mf_classic_set_block_read(data, i, &block_tmp); blocks_read++; + } else if(i > start_block) { + // Try to re-auth to read block in case prevous block was protected from read + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyB, &crypto, false, 0)) break; + if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mf_classic_set_block_read(data, i, &block_tmp); + blocks_read++; + } } } else { blocks_read++; @@ -665,6 +680,11 @@ static bool mf_classic_read_sector_with_reader( // Read blocks for(uint8_t i = 0; i < sector->total_blocks; i++) { + if(mf_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i])) continue; + if(i == 0) continue; + // Try to auth to read next block in case previous is locked + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, first_block + i, key, key_type, crypto, false, 0)) continue; mf_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i]); } // Save sector keys in last block From 4dc4d34d04c4d998ba5e05a2bca8a6d17aeefd01 Mon Sep 17 00:00:00 2001 From: Emily Trau Date: Fri, 27 Jan 2023 16:10:08 +1100 Subject: [PATCH 04/17] emv: parse track1&2 equivalent data (#2332) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * emv: parse track1&2 equivalent data * emv: alternate expiry parser * nfc: log EMV track1&2 data to trace output Co-authored-by: gornekich Co-authored-by: あく --- lib/nfc/protocols/emv.c | 35 +++++++++++++++++++++++++++++------ lib/nfc/protocols/emv.h | 3 ++- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/lib/nfc/protocols/emv.c b/lib/nfc/protocols/emv.c index e00d09e70..4c4ac856b 100644 --- a/lib/nfc/protocols/emv.c +++ b/lib/nfc/protocols/emv.c @@ -142,21 +142,44 @@ static bool emv_decode_response(uint8_t* buff, uint16_t len, EmvApplication* app success = true; FURI_LOG_T(TAG, "found EMV_TAG_AFL %x (len=%d)", tag, tlen); break; - case EMV_TAG_CARD_NUM: // Track 2 Equivalent Data. 0xD0 delimits PAN from expiry (YYMM) + case EMV_TAG_TRACK_1_EQUIV: { + char track_1_equiv[80]; + memcpy(track_1_equiv, &buff[i], tlen); + track_1_equiv[tlen] = '\0'; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_1_EQUIV %x : %s", tag, track_1_equiv); + break; + } + case EMV_TAG_TRACK_2_EQUIV: { + // 0xD0 delimits PAN from expiry (YYMM) for(int x = 1; x < tlen; x++) { if(buff[i + x + 1] > 0xD0) { memcpy(app->card_number, &buff[i], x + 1); app->card_number_len = x + 1; + app->exp_year = (buff[i + x + 1] << 4) | (buff[i + x + 2] >> 4); + app->exp_month = (buff[i + x + 2] << 4) | (buff[i + x + 3] >> 4); break; } } + + // Convert 4-bit to ASCII representation + char track_2_equiv[41]; + uint8_t track_2_equiv_len = 0; + for(int x = 0; x < tlen; x++) { + char top = (buff[i + x] >> 4) + '0'; + char bottom = (buff[i + x] & 0x0F) + '0'; + track_2_equiv[x * 2] = top; + track_2_equiv_len++; + if(top == '?') break; + track_2_equiv[x * 2 + 1] = bottom; + track_2_equiv_len++; + if(bottom == '?') break; + } + track_2_equiv[track_2_equiv_len] = '\0'; success = true; - FURI_LOG_T( - TAG, - "found EMV_TAG_CARD_NUM %x (len=%d)", - EMV_TAG_CARD_NUM, - app->card_number_len); + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x : %s", tag, track_2_equiv); break; + } case EMV_TAG_PAN: memcpy(app->card_number, &buff[i], tlen); app->card_number_len = tlen; diff --git a/lib/nfc/protocols/emv.h b/lib/nfc/protocols/emv.h index 0ccf7c3e0..c5b089fdf 100644 --- a/lib/nfc/protocols/emv.h +++ b/lib/nfc/protocols/emv.h @@ -11,7 +11,8 @@ #define EMV_TAG_CARD_NAME 0x50 #define EMV_TAG_FCI 0xBF0C #define EMV_TAG_LOG_CTRL 0x9F4D -#define EMV_TAG_CARD_NUM 0x57 +#define EMV_TAG_TRACK_1_EQUIV 0x56 +#define EMV_TAG_TRACK_2_EQUIV 0x57 #define EMV_TAG_PAN 0x5A #define EMV_TAG_AFL 0x94 #define EMV_TAG_EXP_DATE 0x5F24 From eee5c3540060abb4c7e48dbdbbbc045f9cc1b1ed Mon Sep 17 00:00:00 2001 From: Giacomo Ferretti Date: Fri, 27 Jan 2023 06:51:47 +0100 Subject: [PATCH 05/17] NFC: add MIFARE MINI support (#2307) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * NFC: add MIFARE MINI support * Move new value to end of enum * nfc: added missing unit test Co-authored-by: gornekich Co-authored-by: あく --- applications/debug/unit_tests/nfc/nfc_test.c | 5 +++++ lib/nfc/helpers/nfc_generators.c | 22 ++++++++++++++++++++ lib/nfc/nfc_device.c | 18 ++++++++++++---- lib/nfc/nfc_types.c | 4 +++- lib/nfc/protocols/mifare_classic.c | 20 +++++++++++++----- lib/nfc/protocols/mifare_classic.h | 2 ++ 6 files changed, 61 insertions(+), 10 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index e9e7b35f6..d613be2b9 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -466,6 +466,10 @@ static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) { nfc_device_free(nfc_keys); } +MU_TEST(mf_mini_file_test) { + mf_classic_generator_test(4, MfClassicTypeMini); +} + MU_TEST(mf_classic_1k_4b_file_test) { mf_classic_generator_test(4, MfClassicType1k); } @@ -486,6 +490,7 @@ MU_TEST_SUITE(nfc) { nfc_test_alloc(); MU_RUN_TEST(nfca_file_test); + MU_RUN_TEST(mf_mini_file_test); MU_RUN_TEST(mf_classic_1k_4b_file_test); MU_RUN_TEST(mf_classic_4k_4b_file_test); MU_RUN_TEST(mf_classic_1k_7b_file_test); diff --git a/lib/nfc/helpers/nfc_generators.c b/lib/nfc/helpers/nfc_generators.c index 769b9c7b6..590ff4d50 100644 --- a/lib/nfc/helpers/nfc_generators.c +++ b/lib/nfc/helpers/nfc_generators.c @@ -352,11 +352,27 @@ void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType } // Set SAK to 08 data->nfc_data.sak = 0x08; + } else if(type == MfClassicTypeMini) { + // Set every block to 0xFF + for(uint16_t i = 1; i < MF_MINI_TOTAL_SECTORS_NUM * 4; i += 1) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc, i); + } else { + memset(&mfc->block[i].value, 0xFF, 16); + } + mf_classic_set_block_read(mfc, i, &mfc->block[i]); + } + // Set SAK to 09 + data->nfc_data.sak = 0x09; } mfc->type = type; } +static void nfc_generate_mf_mini(NfcDeviceData* data) { + nfc_generate_mf_classic(data, 4, MfClassicTypeMini); +} + static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) { nfc_generate_mf_classic(data, 4, MfClassicType1k); } @@ -438,6 +454,11 @@ static const NfcGenerator ntag_i2c_plus_2k_generator = { .generator_func = nfc_generate_ntag_i2c_plus_2k, }; +static const NfcGenerator mifare_mini_generator = { + .name = "Mifare Mini", + .generator_func = nfc_generate_mf_mini, +}; + static const NfcGenerator mifare_classic_1k_4b_uid_generator = { .name = "Mifare Classic 1k 4byte UID", .generator_func = nfc_generate_mf_classic_1k_4b_uid, @@ -472,6 +493,7 @@ const NfcGenerator* const nfc_generators[] = { &ntag_i2c_2k_generator, &ntag_i2c_plus_1k_generator, &ntag_i2c_plus_2k_generator, + &mifare_mini_generator, &mifare_classic_1k_4b_uid_generator, &mifare_classic_1k_7b_uid_generator, &mifare_classic_4k_4b_uid_generator, diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index d10eaa0e5..517913070 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -745,7 +745,10 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* do { if(!flipper_format_write_comment_cstr(file, "Mifare Classic specific data")) break; - if(data->type == MfClassicType1k) { + if(data->type == MfClassicTypeMini) { + if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "MINI")) break; + blocks = 20; + } else if(data->type == MfClassicType1k) { if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break; blocks = 64; } else if(data->type == MfClassicType4k) { @@ -843,7 +846,10 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* do { // Read Mifare Classic type if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break; - if(!furi_string_cmp(temp_str, "1K")) { + if(!furi_string_cmp(temp_str, "MINI")) { + data->type = MfClassicTypeMini; + data_blocks = 20; + } else if(!furi_string_cmp(temp_str, "1K")) { data->type = MfClassicType1k; data_blocks = 64; } else if(!furi_string_cmp(temp_str, "4K")) { @@ -918,7 +924,9 @@ static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) { if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break; if(!flipper_format_write_header_cstr(file, nfc_keys_file_header, nfc_keys_file_version)) break; - if(data->type == MfClassicType1k) { + if(data->type == MfClassicTypeMini) { + if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "MINI")) break; + } else if(data->type == MfClassicType1k) { if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break; } else if(data->type == MfClassicType4k) { if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "4K")) break; @@ -968,7 +976,9 @@ bool nfc_device_load_key_cache(NfcDevice* dev) { if(furi_string_cmp_str(temp_str, nfc_keys_file_header)) break; if(version != nfc_keys_file_version) break; if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break; - if(!furi_string_cmp(temp_str, "1K")) { + if(!furi_string_cmp(temp_str, "MINI")) { + data->type = MfClassicTypeMini; + } else if(!furi_string_cmp(temp_str, "1K")) { data->type = MfClassicType1k; } else if(!furi_string_cmp(temp_str, "4K")) { data->type = MfClassicType4k; diff --git a/lib/nfc/nfc_types.c b/lib/nfc/nfc_types.c index 427628769..02ca85580 100644 --- a/lib/nfc/nfc_types.c +++ b/lib/nfc/nfc_types.c @@ -55,7 +55,9 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { } const char* nfc_mf_classic_type(MfClassicType type) { - if(type == MfClassicType1k) { + if(type == MfClassicTypeMini) { + return "Mifare Mini 0.3K"; + } else if(type == MfClassicType1k) { return "Mifare Classic 1K"; } else if(type == MfClassicType4k) { return "Mifare Classic 4K"; diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index d1aadf06f..2f340a5ce 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -13,7 +13,9 @@ #define MF_CLASSIC_WRITE_BLOCK_CMD (0xA0) const char* mf_classic_get_type_str(MfClassicType type) { - if(type == MfClassicType1k) { + if(type == MfClassicTypeMini) { + return "MIFARE Mini 0.3K"; + } else if(type == MfClassicType1k) { return "MIFARE Classic 1K"; } else if(type == MfClassicType4k) { return "MIFARE Classic 4K"; @@ -73,7 +75,9 @@ MfClassicSectorTrailer* } uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { - if(type == MfClassicType1k) { + if(type == MfClassicTypeMini) { + return MF_MINI_TOTAL_SECTORS_NUM; + } else if(type == MfClassicType1k) { return MF_CLASSIC_1K_TOTAL_SECTORS_NUM; } else if(type == MfClassicType4k) { return MF_CLASSIC_4K_TOTAL_SECTORS_NUM; @@ -83,7 +87,9 @@ uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { } uint16_t mf_classic_get_total_block_num(MfClassicType type) { - if(type == MfClassicType1k) { + if(type == MfClassicTypeMini) { + return 20; + } else if(type == MfClassicType1k) { return 64; } else if(type == MfClassicType4k) { return 256; @@ -363,8 +369,12 @@ bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { UNUSED(ATQA1); - if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) { - return MfClassicType1k; + if((ATQA0 == 0x44 || ATQA0 == 0x04)) { + if((SAK == 0x08 || SAK == 0x88)) { + return MfClassicType1k; + } else if(SAK == 0x09) { + return MfClassicTypeMini; + } } else if((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01)) { //skylanders support return MfClassicType1k; diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index 74beceb62..0346da0f7 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -6,6 +6,7 @@ #define MF_CLASSIC_BLOCK_SIZE (16) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) +#define MF_MINI_TOTAL_SECTORS_NUM (5) #define MF_CLASSIC_1K_TOTAL_SECTORS_NUM (16) #define MF_CLASSIC_4K_TOTAL_SECTORS_NUM (40) @@ -20,6 +21,7 @@ typedef enum { MfClassicType1k, MfClassicType4k, + MfClassicTypeMini, } MfClassicType; typedef enum { From 126a9efd091ea949cb9a26a01b0ee7f8c22a4a68 Mon Sep 17 00:00:00 2001 From: Giacomo Ferretti Date: Fri, 27 Jan 2023 09:21:52 +0100 Subject: [PATCH 06/17] NFC: change from int8_t to uint8_t (#2302) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: gornekich Co-authored-by: あく --- firmware/targets/f7/api_symbols.csv | 2 +- lib/nfc/protocols/mifare_classic.c | 2 +- lib/nfc/protocols/mifare_classic.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 3d7bd7cd2..0e4af3c1d 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1880,7 +1880,7 @@ Function,-,mf_classic_dict_is_key_present,_Bool,"MfClassicDict*, uint8_t*" Function,-,mf_classic_dict_is_key_present_str,_Bool,"MfClassicDict*, FuriString*" Function,-,mf_classic_dict_rewind,_Bool,MfClassicDict* Function,-,mf_classic_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*" -Function,-,mf_classic_get_classic_type,MfClassicType,"int8_t, uint8_t, uint8_t" +Function,-,mf_classic_get_classic_type,MfClassicType,"uint8_t, uint8_t, uint8_t" Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*" Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t Function,-,mf_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 2f340a5ce..5887ab4c1 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -367,7 +367,7 @@ bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { } } -MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { +MfClassicType mf_classic_get_classic_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { UNUSED(ATQA1); if((ATQA0 == 0x44 || ATQA0 == 0x04)) { if((SAK == 0x08 || SAK == 0x88)) { diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index 0346da0f7..321ab5f03 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -96,7 +96,7 @@ const char* mf_classic_get_type_str(MfClassicType type); bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); -MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t SAK); +MfClassicType mf_classic_get_classic_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); uint8_t mf_classic_get_total_sectors_num(MfClassicType type); From 24a23e5dc7b1719874f075abbf428bd5dd59e5e6 Mon Sep 17 00:00:00 2001 From: Emily Trau Date: Fri, 27 Jan 2023 20:41:55 +1100 Subject: [PATCH 07/17] debug apps: made runnable as .faps; sdk: resolved additional APIs in use by faps (#2333) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * sdk: resolve additional APIs in use by faps * debug tools: fixed battery_test, bt_debug, display_test, rpc_debug Co-authored-by: hedger Co-authored-by: hedger Co-authored-by: あく --- .../debug/battery_test_app/application.fam | 1 + .../battery_test_app/views/battery_info.c | 148 ++++++++++++++++++ .../battery_test_app/views/battery_info.h | 23 +++ .../debug/bt_debug_app/bt_debug_app.c | 7 +- .../debug/bt_debug_app/bt_debug_app.h | 5 +- .../debug/display_test/application.fam | 1 + .../debug/display_test/display_test.c | 1 - .../rpc_debug_app_scene_input_error_code.c | 6 +- applications/services/bt/bt_settings.h | 8 + firmware/targets/f7/api_symbols.csv | 8 +- lib/toolbox/SConscript | 1 + 11 files changed, 198 insertions(+), 11 deletions(-) create mode 100644 applications/debug/battery_test_app/views/battery_info.c create mode 100644 applications/debug/battery_test_app/views/battery_info.h diff --git a/applications/debug/battery_test_app/application.fam b/applications/debug/battery_test_app/application.fam index b388445cc..f97d10279 100644 --- a/applications/debug/battery_test_app/application.fam +++ b/applications/debug/battery_test_app/application.fam @@ -11,4 +11,5 @@ App( stack_size=1 * 1024, order=130, fap_category="Debug", + fap_libs=["assets"], ) diff --git a/applications/debug/battery_test_app/views/battery_info.c b/applications/debug/battery_test_app/views/battery_info.c new file mode 100644 index 000000000..5353a2e2a --- /dev/null +++ b/applications/debug/battery_test_app/views/battery_info.c @@ -0,0 +1,148 @@ +#include "battery_info.h" +#include +#include +#include + +#define LOW_CHARGE_THRESHOLD 10 +#define HIGH_DRAIN_CURRENT_THRESHOLD 100 + +struct BatteryInfo { + View* view; +}; + +static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) { + canvas_draw_frame(canvas, x - 7, y + 7, 30, 13); + canvas_draw_icon(canvas, x, y, icon); + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, x - 4, y + 16, 24, 6); + canvas_set_color(canvas, ColorBlack); + canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val); +}; + +static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { + char emote[20] = {}; + char header[20] = {}; + char value[20] = {}; + + int32_t drain_current = data->gauge_current * (-1000); + uint32_t charge_current = data->gauge_current * 1000; + + // Draw battery + canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28); + if(charge_current > 0) { + canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14); + } else if(drain_current > HIGH_DRAIN_CURRENT_THRESHOLD) { + canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14); + } else if(data->charge < LOW_CHARGE_THRESHOLD) { + canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14); + } else { + canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNormal_29x14); + } + + // Draw bubble + elements_bubble(canvas, 53, 0, 71, 39); + + // Set text + if(charge_current > 0) { + snprintf(emote, sizeof(emote), "%s", "Yummy!"); + snprintf(header, sizeof(header), "%s", "Charging at"); + snprintf( + value, + sizeof(value), + "%lu.%luV %lumA", + (uint32_t)(data->vbus_voltage), + (uint32_t)(data->vbus_voltage * 10) % 10, + charge_current); + } else if(drain_current > 0) { + snprintf( + emote, + sizeof(emote), + "%s", + drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "Oh no!" : "Om-nom-nom!"); + snprintf(header, sizeof(header), "%s", "Consumption is"); + snprintf( + value, + sizeof(value), + "%ld %s", + drain_current, + drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); + } else if(drain_current != 0) { + snprintf(header, 20, "..."); + } else if(data->charging_voltage < 4.2) { + // Non-default battery charging limit, mention it + snprintf(emote, sizeof(emote), "Charged!"); + snprintf(header, sizeof(header), "Limited to"); + snprintf( + value, + sizeof(value), + "%lu.%luV", + (uint32_t)(data->charging_voltage), + (uint32_t)(data->charging_voltage * 10) % 10); + } else { + snprintf(header, sizeof(header), "Charged!"); + } + + canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote); + canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header); + canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value); +}; + +static void battery_info_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + BatteryInfoModel* model = context; + + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + draw_battery(canvas, model, 0, 5); + + char batt_level[10]; + char temperature[10]; + char voltage[10]; + char health[10]; + + snprintf(batt_level, sizeof(batt_level), "%lu%%", (uint32_t)model->charge); + snprintf(temperature, sizeof(temperature), "%lu C", (uint32_t)model->gauge_temperature); + snprintf( + voltage, + sizeof(voltage), + "%lu.%01lu V", + (uint32_t)model->gauge_voltage, + (uint32_t)(model->gauge_voltage * 10) % 10UL); + snprintf(health, sizeof(health), "%d%%", model->health); + + draw_stat(canvas, 8, 42, &I_Battery_16x16, batt_level); + draw_stat(canvas, 40, 42, &I_Temperature_16x16, temperature); + draw_stat(canvas, 72, 42, &I_Voltage_16x16, voltage); + draw_stat(canvas, 104, 42, &I_Health_16x16, health); +} + +BatteryInfo* battery_info_alloc() { + BatteryInfo* battery_info = malloc(sizeof(BatteryInfo)); + battery_info->view = view_alloc(); + view_set_context(battery_info->view, battery_info); + view_allocate_model(battery_info->view, ViewModelTypeLocking, sizeof(BatteryInfoModel)); + view_set_draw_callback(battery_info->view, battery_info_draw_callback); + + return battery_info; +} + +void battery_info_free(BatteryInfo* battery_info) { + furi_assert(battery_info); + view_free(battery_info->view); + free(battery_info); +} + +View* battery_info_get_view(BatteryInfo* battery_info) { + furi_assert(battery_info); + return battery_info->view; +} + +void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data) { + furi_assert(battery_info); + furi_assert(data); + with_view_model( + battery_info->view, + BatteryInfoModel * model, + { memcpy(model, data, sizeof(BatteryInfoModel)); }, + true); +} diff --git a/applications/debug/battery_test_app/views/battery_info.h b/applications/debug/battery_test_app/views/battery_info.h new file mode 100644 index 000000000..7bfacf69e --- /dev/null +++ b/applications/debug/battery_test_app/views/battery_info.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +typedef struct BatteryInfo BatteryInfo; + +typedef struct { + float vbus_voltage; + float gauge_voltage; + float gauge_current; + float gauge_temperature; + float charging_voltage; + uint8_t charge; + uint8_t health; +} BatteryInfoModel; + +BatteryInfo* battery_info_alloc(); + +void battery_info_free(BatteryInfo* battery_info); + +View* battery_info_get_view(BatteryInfo* battery_info); + +void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data); diff --git a/applications/debug/bt_debug_app/bt_debug_app.c b/applications/debug/bt_debug_app/bt_debug_app.c index 405051a4a..bf13f6570 100644 --- a/applications/debug/bt_debug_app/bt_debug_app.c +++ b/applications/debug/bt_debug_app/bt_debug_app.c @@ -31,9 +31,6 @@ uint32_t bt_debug_start_view(void* context) { BtDebugApp* bt_debug_app_alloc() { BtDebugApp* app = malloc(sizeof(BtDebugApp)); - // Load settings - bt_settings_load(&app->settings); - // Gui app->gui = furi_record_open(RECORD_GUI); @@ -105,13 +102,15 @@ int32_t bt_debug_app(void* p) { } BtDebugApp* app = bt_debug_app_alloc(); + // Was bt active? + const bool was_active = furi_hal_bt_is_active(); // Stop advertising furi_hal_bt_stop_advertising(); view_dispatcher_run(app->view_dispatcher); // Restart advertising - if(app->settings.enabled) { + if(was_active) { furi_hal_bt_start_advertising(); } bt_debug_app_free(app); diff --git a/applications/debug/bt_debug_app/bt_debug_app.h b/applications/debug/bt_debug_app/bt_debug_app.h index cd59e4d00..0ad94d7dd 100644 --- a/applications/debug/bt_debug_app/bt_debug_app.h +++ b/applications/debug/bt_debug_app/bt_debug_app.h @@ -4,15 +4,14 @@ #include #include #include +#include + #include -#include #include "views/bt_carrier_test.h" #include "views/bt_packet_test.h" -#include typedef struct { - BtSettings settings; Gui* gui; ViewDispatcher* view_dispatcher; Submenu* submenu; diff --git a/applications/debug/display_test/application.fam b/applications/debug/display_test/application.fam index 4b40322fb..e8a00d2ae 100644 --- a/applications/debug/display_test/application.fam +++ b/applications/debug/display_test/application.fam @@ -5,6 +5,7 @@ App( entry_point="display_test_app", cdefines=["APP_DISPLAY_TEST"], requires=["gui"], + fap_libs=["misc"], stack_size=1 * 1024, order=120, fap_category="Debug", diff --git a/applications/debug/display_test/display_test.c b/applications/debug/display_test/display_test.c index 5b46d2b41..8065a23a1 100644 --- a/applications/debug/display_test/display_test.c +++ b/applications/debug/display_test/display_test.c @@ -91,7 +91,6 @@ static void display_test_reload_config(DisplayTest* instance) { instance->config_contrast, instance->config_regulation_ratio, instance->config_bias); - gui_update(instance->gui); } static void display_config_set_bias(VariableItem* item) { diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c index eae12e6ee..367ca7a4f 100644 --- a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c @@ -44,7 +44,11 @@ bool rpc_debug_app_scene_input_error_code_on_event(void* context, SceneManagerEv if(event.type == SceneManagerEventTypeCustom) { if(event.event == RpcDebugAppCustomEventInputErrorCode) { - rpc_system_app_set_error_code(app->rpc, (uint32_t)atol(app->text_store)); + char* end; + int error_code = strtol(app->text_store, &end, 10); + if(!*end) { + rpc_system_app_set_error_code(app->rpc, error_code); + } scene_manager_previous_scene(app->scene_manager); consumed = true; } diff --git a/applications/services/bt/bt_settings.h b/applications/services/bt/bt_settings.h index 260d9c0e0..9ed8be89c 100644 --- a/applications/services/bt/bt_settings.h +++ b/applications/services/bt/bt_settings.h @@ -5,6 +5,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { bool enabled; } BtSettings; @@ -12,3 +16,7 @@ typedef struct { bool bt_settings_load(BtSettings* bt_settings); bool bt_settings_save(BtSettings* bt_settings); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 0e4af3c1d..0e027a6a2 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,11.7,, +Version,+,11.8,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -188,6 +188,7 @@ Header,+,lib/toolbox/stream/file_stream.h,, Header,+,lib/toolbox/stream/stream.h,, Header,+,lib/toolbox/stream/string_stream.h,, Header,+,lib/toolbox/tar/tar_archive.h,, +Header,+,lib/toolbox/value_index.h,, Header,+,lib/toolbox/version.h,, Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" @@ -2066,7 +2067,7 @@ Function,-,posix_memalign,int,"void**, size_t, size_t" Function,-,pow,double,"double, double" Function,-,pow10,double,double Function,-,pow10f,float,float -Function,-,power_enable_low_battery_level_notification,void,"Power*, _Bool" +Function,+,power_enable_low_battery_level_notification,void,"Power*, _Bool" Function,+,power_get_info,void,"Power*, PowerInfo*" Function,+,power_get_pubsub,FuriPubSub*,Power* Function,+,power_is_battery_healthy,_Bool,Power* @@ -2804,6 +2805,9 @@ Function,-,vTimerSetTimerNumber,void,"TimerHandle_t, UBaseType_t" Function,+,validator_is_file_alloc_init,ValidatorIsFile*,"const char*, const char*, const char*" Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*" Function,+,validator_is_file_free,void,ValidatorIsFile* +Function,+,value_index_bool,uint8_t,"const _Bool, const _Bool[], uint8_t" +Function,+,value_index_float,uint8_t,"const float, const float[], uint8_t" +Function,+,value_index_uint32,uint8_t,"const uint32_t, const uint32_t[], uint8_t" Function,+,variable_item_get_context,void*,VariableItem* Function,+,variable_item_get_current_value_index,uint8_t,VariableItem* Function,+,variable_item_list_add,VariableItem*,"VariableItemList*, const char*, uint8_t, VariableItemChangeCallback, void*" diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 724d25afa..8ce45d25f 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -20,6 +20,7 @@ env.Append( File("saved_struct.h"), File("version.h"), File("float_tools.h"), + File("value_index.h"), File("tar/tar_archive.h"), File("stream/stream.h"), File("stream/file_stream.h"), From d93ed003fec62ec8b9dc8a6b5ffbe93a25a0ef40 Mon Sep 17 00:00:00 2001 From: Krzysztof Zdulski Date: Sun, 29 Jan 2023 06:53:35 +0100 Subject: [PATCH 08/17] Change camelCase to PascalCase in code style (#2329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- CODING_STYLE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODING_STYLE.md b/CODING_STYLE.md index 6c7d6d792..c62009eff 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -52,7 +52,7 @@ Almost everything in flipper firmware is built around this concept. ## Naming -### Type names are CamelCase +### Type names are PascalCase Examples: From f5fe0ff694fd5c51472d3430565a156a66a05c15 Mon Sep 17 00:00:00 2001 From: Petr Portnov | PROgrm_JARvis Date: Sun, 29 Jan 2023 13:12:24 +0300 Subject: [PATCH 09/17] Furi: make `furi_is_irq_context` public (#2276) * Furi: make `furi_is_irq_context` public * Furi: proper name and documentation for furi_kernel_is_irq_or_masked. * Target: bump symbol table version * Furi: proper doxygen context for warnings Co-authored-by: Aleksandr Kutuzov --- firmware/targets/f7/api_symbols.csv | 1 + furi/core/common_defines.h | 24 ------------------- furi/core/kernel.c | 36 ++++++++++++++++++++++++----- furi/core/kernel.h | 29 ++++++++++++++++++++++- furi/core/message_queue.c | 16 ++++++------- furi/core/timer.c | 11 ++++----- furi/furi.c | 4 ++-- 7 files changed, 74 insertions(+), 47 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 0e027a6a2..a75e88bad 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1389,6 +1389,7 @@ Function,+,furi_hal_version_uid_size,size_t, Function,-,furi_hal_vibro_init,void, Function,+,furi_hal_vibro_on,void,_Bool Function,-,furi_init,void, +Function,+,furi_kernel_is_irq_or_masked,_Bool, Function,+,furi_kernel_get_tick_frequency,uint32_t, Function,+,furi_kernel_lock,int32_t, Function,+,furi_kernel_restore_lock,int32_t,int32_t diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index c7acf95b4..1ec847d45 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -52,30 +52,6 @@ extern "C" { } #endif -static inline bool furi_is_irq_context() { - bool irq = false; - BaseType_t state; - - if(FURI_IS_IRQ_MODE()) { - /* Called from interrupt context */ - irq = true; - } else { - /* Get FreeRTOS scheduler state */ - state = xTaskGetSchedulerState(); - - if(state != taskSCHEDULER_NOT_STARTED) { - /* Scheduler was started */ - if(FURI_IS_IRQ_MASKED()) { - /* Interrupts are masked */ - irq = true; - } - } - } - - /* Return context, 0: thread context, 1: IRQ context */ - return (irq); -} - #ifdef __cplusplus } #endif diff --git a/furi/core/kernel.c b/furi/core/kernel.c index 73d2012b4..7928ad11c 100644 --- a/furi/core/kernel.c +++ b/furi/core/kernel.c @@ -7,8 +7,32 @@ #include CMSIS_device_header +bool furi_kernel_is_irq_or_masked() { + bool irq = false; + BaseType_t state; + + if(FURI_IS_IRQ_MODE()) { + /* Called from interrupt context */ + irq = true; + } else { + /* Get FreeRTOS scheduler state */ + state = xTaskGetSchedulerState(); + + if(state != taskSCHEDULER_NOT_STARTED) { + /* Scheduler was started */ + if(FURI_IS_IRQ_MASKED()) { + /* Interrupts are masked */ + irq = true; + } + } + } + + /* Return context, 0: thread context, 1: IRQ context */ + return (irq); +} + int32_t furi_kernel_lock() { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); int32_t lock; @@ -33,7 +57,7 @@ int32_t furi_kernel_lock() { } int32_t furi_kernel_unlock() { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); int32_t lock; @@ -63,7 +87,7 @@ int32_t furi_kernel_unlock() { } int32_t furi_kernel_restore_lock(int32_t lock) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); switch(xTaskGetSchedulerState()) { case taskSCHEDULER_SUSPENDED: @@ -99,7 +123,7 @@ uint32_t furi_kernel_get_tick_frequency() { } void furi_delay_tick(uint32_t ticks) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); if(ticks == 0U) { taskYIELD(); } else { @@ -108,7 +132,7 @@ void furi_delay_tick(uint32_t ticks) { } FuriStatus furi_delay_until_tick(uint32_t tick) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); TickType_t tcnt, delay; FuriStatus stat; @@ -137,7 +161,7 @@ FuriStatus furi_delay_until_tick(uint32_t tick) { uint32_t furi_get_tick() { TickType_t ticks; - if(furi_is_irq_context() != 0U) { + if(furi_kernel_is_irq_or_masked() != 0U) { ticks = xTaskGetTickCountFromISR(); } else { ticks = xTaskGetTickCount(); diff --git a/furi/core/kernel.h b/furi/core/kernel.h index f30f109bb..371f76c1f 100644 --- a/furi/core/kernel.h +++ b/furi/core/kernel.h @@ -10,19 +10,42 @@ extern "C" { #endif +/** Check if CPU is in IRQ or kernel running and IRQ is masked + * + * Originally this primitive was born as a workaround for FreeRTOS kernel primitives shenanigans with PRIMASK. + * + * Meaningful use cases are: + * + * - When kernel is started and you want to ensure that you are not in IRQ or IRQ is not masked(like in critical section) + * - When kernel is not started and you want to make sure that you are not in IRQ mode, ignoring PRIMASK. + * + * As you can see there will be edge case when kernel is not started and PRIMASK is not 0 that may cause some funky behavior. + * Most likely it will happen after kernel primitives being used, but control not yet passed to kernel. + * It's up to you to figure out if it is safe for your code or not. + * + * @return true if CPU is in IRQ or kernel running and IRQ is masked + */ +bool furi_kernel_is_irq_or_masked(); + /** Lock kernel, pause process scheduling + * + * @warning This should never be called in interrupt request context. * * @return previous lock state(0 - unlocked, 1 - locked) */ int32_t furi_kernel_lock(); /** Unlock kernel, resume process scheduling + * + * @warning This should never be called in interrupt request context. * * @return previous lock state(0 - unlocked, 1 - locked) */ int32_t furi_kernel_unlock(); /** Restore kernel lock state + * + * @warning This should never be called in interrupt request context. * * @param[in] lock The lock state * @@ -37,7 +60,9 @@ int32_t furi_kernel_restore_lock(int32_t lock); uint32_t furi_kernel_get_tick_frequency(); /** Delay execution - * + * + * @warning This should never be called in interrupt request context. + * * Also keep in mind delay is aliased to scheduler timer intervals. * * @param[in] ticks The ticks count to pause @@ -45,6 +70,8 @@ uint32_t furi_kernel_get_tick_frequency(); void furi_delay_tick(uint32_t ticks); /** Delay until tick + * + * @warning This should never be called in interrupt request context. * * @param[in] ticks The tick until which kerel should delay task execution * diff --git a/furi/core/message_queue.c b/furi/core/message_queue.c index 9a41f8775..ddf56f006 100644 --- a/furi/core/message_queue.c +++ b/furi/core/message_queue.c @@ -1,11 +1,11 @@ +#include "kernel.h" #include "message_queue.h" -#include "core/common_defines.h" #include #include #include "check.h" FuriMessageQueue* furi_message_queue_alloc(uint32_t msg_count, uint32_t msg_size) { - furi_assert((furi_is_irq_context() == 0U) && (msg_count > 0U) && (msg_size > 0U)); + furi_assert((furi_kernel_is_irq_or_masked() == 0U) && (msg_count > 0U) && (msg_size > 0U)); QueueHandle_t handle = xQueueCreate(msg_count, msg_size); furi_check(handle); @@ -14,7 +14,7 @@ FuriMessageQueue* furi_message_queue_alloc(uint32_t msg_count, uint32_t msg_size } void furi_message_queue_free(FuriMessageQueue* instance) { - furi_assert(furi_is_irq_context() == 0U); + furi_assert(furi_kernel_is_irq_or_masked() == 0U); furi_assert(instance); vQueueDelete((QueueHandle_t)instance); @@ -28,7 +28,7 @@ FuriStatus stat = FuriStatusOk; - if(furi_is_irq_context() != 0U) { + if(furi_kernel_is_irq_or_masked() != 0U) { if((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) { stat = FuriStatusErrorParameter; } else { @@ -65,7 +65,7 @@ FuriStatus furi_message_queue_get(FuriMessageQueue* instance, void* msg_ptr, uin stat = FuriStatusOk; - if(furi_is_irq_context() != 0U) { + if(furi_kernel_is_irq_or_masked() != 0U) { if((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) { stat = FuriStatusErrorParameter; } else { @@ -131,7 +131,7 @@ uint32_t furi_message_queue_get_count(FuriMessageQueue* instance) { if(hQueue == NULL) { count = 0U; - } else if(furi_is_irq_context() != 0U) { + } else if(furi_kernel_is_irq_or_masked() != 0U) { count = uxQueueMessagesWaitingFromISR(hQueue); } else { count = uxQueueMessagesWaiting(hQueue); @@ -148,7 +148,7 @@ uint32_t furi_message_queue_get_space(FuriMessageQueue* instance) { if(mq == NULL) { space = 0U; - } else if(furi_is_irq_context() != 0U) { + } else if(furi_kernel_is_irq_or_masked() != 0U) { isrm = taskENTER_CRITICAL_FROM_ISR(); /* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */ @@ -167,7 +167,7 @@ FuriStatus furi_message_queue_reset(FuriMessageQueue* instance) { QueueHandle_t hQueue = (QueueHandle_t)instance; FuriStatus stat; - if(furi_is_irq_context() != 0U) { + if(furi_kernel_is_irq_or_masked() != 0U) { stat = FuriStatusErrorISR; } else if(hQueue == NULL) { stat = FuriStatusErrorParameter; diff --git a/furi/core/timer.c b/furi/core/timer.c index be7efebe2..4b6ccecba 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -3,7 +3,6 @@ #include "memmgr.h" #include "kernel.h" -#include "core/common_defines.h" #include #include @@ -27,7 +26,7 @@ static void TimerCallback(TimerHandle_t hTimer) { } FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* context) { - furi_assert((furi_is_irq_context() == 0U) && (func != NULL)); + furi_assert((furi_kernel_is_irq_or_masked() == 0U) && (func != NULL)); TimerHandle_t hTimer; TimerCallback_t* callb; @@ -60,7 +59,7 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co } void furi_timer_free(FuriTimer* instance) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -82,7 +81,7 @@ void furi_timer_free(FuriTimer* instance) { } FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -99,7 +98,7 @@ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { } FuriStatus furi_timer_stop(FuriTimer* instance) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -117,7 +116,7 @@ FuriStatus furi_timer_stop(FuriTimer* instance) { } uint32_t furi_timer_is_running(FuriTimer* instance) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; diff --git a/furi/furi.c b/furi/furi.c index a616bce63..cc0e3f4f1 100644 --- a/furi/furi.c +++ b/furi/furi.c @@ -3,7 +3,7 @@ #include "queue.h" void furi_init() { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED); furi_log_init(); @@ -11,7 +11,7 @@ void furi_init() { } void furi_run() { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED); #if(__ARM_ARCH_7A__ == 0U) From 55054fc1a7467aff87f7250178ecd8efd9e7a738 Mon Sep 17 00:00:00 2001 From: DEXV <89728480+DXVVAY@users.noreply.github.com> Date: Sun, 29 Jan 2023 11:55:04 +0100 Subject: [PATCH 10/17] Assets: correct MicroSD card pinout in service animations (#2323) * New Micro Sd-Card pinout: fixing the Micro Sd-Card pinout for the blocking an internal sd card animations * Updating the sd card pinout * Updating magnifying glass --- .../blocking/L0_NoDb_128x51/frame_0.png | Bin 1398 -> 1424 bytes .../blocking/L0_NoDb_128x51/frame_1.png | Bin 1403 -> 1425 bytes .../blocking/L0_NoDb_128x51/frame_2.png | Bin 1403 -> 1423 bytes .../blocking/L0_NoDb_128x51/frame_3.png | Bin 1401 -> 1420 bytes .../blocking/L0_SdBad_128x51/frame_0.png | Bin 1552 -> 1370 bytes .../blocking/L0_SdBad_128x51/frame_1.png | Bin 1586 -> 1387 bytes .../blocking/L0_SdOk_128x51/frame_0.png | Bin 1549 -> 1387 bytes .../blocking/L0_SdOk_128x51/frame_1.png | Bin 1559 -> 1395 bytes .../blocking/L0_SdOk_128x51/frame_2.png | Bin 1578 -> 1413 bytes .../blocking/L0_SdOk_128x51/frame_3.png | Bin 1567 -> 1403 bytes .../blocking/L0_Url_128x51/frame_0.png | Bin 1358 -> 1380 bytes .../blocking/L0_Url_128x51/frame_1.png | Bin 1964 -> 2046 bytes .../blocking/L0_Url_128x51/frame_2.png | Bin 1956 -> 2044 bytes .../blocking/L0_Url_128x51/frame_3.png | Bin 1955 -> 2045 bytes .../internal/L1_NoSd_128x49/frame_0.png | Bin 1382 -> 1411 bytes .../internal/L1_NoSd_128x49/frame_1.png | Bin 1376 -> 1410 bytes .../internal/L1_NoSd_128x49/frame_2.png | Bin 1381 -> 1416 bytes .../internal/L1_NoSd_128x49/frame_3.png | Bin 1378 -> 1415 bytes .../internal/L1_NoSd_128x49/frame_4.png | Bin 1372 -> 1401 bytes .../internal/L1_NoSd_128x49/frame_5.png | Bin 1377 -> 1412 bytes 20 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png index e82c6f2e9c6a2880b0b983e1a80497daac351704..759007623af4e16c1bbdd167750e2ee47152ff88 100644 GIT binary patch delta 602 zcmeyyHGzAAL?8<@0|UcaKUrlU#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s00=W?UF+mzU|^m((aWESmuupzJZ4@lg~=R@POLy$ zL1D8O;{rx@FjGNc@++o=^$PlS5U!1WQA(PXOKNd)QD#9&W_})693mRz;s)f|=vP=( zD9qCSiJ- zyW#1BPdSXM*p9d|D~2C5xiCr9gyl|;y#gb9`nMI)?=+sNMr(WO`!U+tTj@JUKXd43 z{Gi!Y|7GU6jt?Hb4EH3G9nM+%8b4F2)?(by@44lvs=}@Yjs1)%+zm__#v8t`=4hJ9 zc9Zq>j%)|lW|jln)juy-^<5+&DE+5E13$y-z#EJSoEb6Uu?I`}&M{_8KU?Bjaj>zN z_m_3M_?=#n*I#lSJ}P{gZNT_o%Z7!FOEkC{b@}3-$_-7%~V00001JzVIRd000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aik!eo>Ad$LmlPdv2vvL8T0h1X6p?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oM;Hv@wJ z000J1OjJbx00960|E1ZV-2eaqd`Uz>RCwC#n28R9APk28zW+;aS)`X$px}`Ow|GRb z-+KKr(0{`l7Qkx&aJpR&06avX0Dc$o_ay-EIfH{^TdLtk0MHzOa;2wyclM-QZUa%U z*?=0=nS|IrRQv%)YIbt+Grk{?0pKUq05-pwu~PtAJs>|`oG}Yvp9554D$(WetC@Vy zl=hn%(E?Zi*4PYyQYWBlD+Vc3`Y-|@?Vzd!+JC+-=6(R|N}K^;+JzZp?UQEd1aMuB zyA)9*6ao<1x2G8Z69Ut}&j2tD03M+30TOeLpeqM#2&Aq=415ka08T-=sSkuczY~BF zJj!zbgl7PTt6&-cjRQ2wo7V!{{qg|y8K7e=P_KbWfR+id7AQ5evAGr?h>m+N$N=DA zS#E|JK=fvk0zmAGomvy>1UV0sr5x0X(X4fA078%qK`4Pm?pgpa2tXFVER5R#FcqLX z2QbtJ*n+H*(N_h70O>yP9{^oiFdu-LpNO{Mm#Ojkvw8v0M}PqUpUe`n6H&y000000 LNkvXXu0mjfS)JjK diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png index 58dab74d4a618d0ccc4674be0754b2f11a28e111..c9810b61e34bfc61f4b62a26225afaab6a05490d 100644 GIT binary patch delta 603 zcmey(HIaLQL?8<@0|UcaKUrlU#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s00=W?UF+mzU|^m((aWESmuupzJZ4@lg~=R@POLy$ zL1D8O;{rx@FjGNc@++o=^$PlS5U!1WQA(PXOKNd)QD#9&W_})693mRz;s)f|=vP=( zw#+_v4VT99ldTO;^Yd!VcHOU+&u6IPQh4!Rae=@sf5r)id;HRkUwNA| zYDhC^zKm_2#HKbe>{OA5@tck2OBoCgo|as@q*SYF^1Har;g*yxYf5 zObhI0*hDuhb6mKJQ9RhubiypFDNK2{dZ`~99 z7&mBk)t@k)DL7BLo%usHS4X9K+^-mw;-ie)W>v&TG1{gf=iXSmvmTNHLopF6}g0)F({~@jmx34pL>g6#1O7XGdSBqbDyZ&o% b*eUK(MH8nPTONl3(*uL2tDnm{r-UW|yvo^{ delta 578 zcmV-I0=@l_3;PO?7%~V00001JzVIRd000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aik!eo>Ad$LmlPdv2vvL8T0h1X6p?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oOC5CQ4{ z000J1OjJbx00960|E1ZV-2eaqfk{L`RCwC#m9uK7aBSSEh13Cm;RV)TJ2MmBnK-$s=sy^Qd zAP}f^+ze0@;x>TEDp&?U^8ikHE484a3ITxr4A7kxh!?>SfM-HW3xpa9S3V3-jgNXS zh;sm-u`EL$pnNk40if=SLahmXf|v)=QVwFpsMflD0JuY14M9}`lic|LFa&U>cv7h@-A}f&37T^=& z`v3obAT#vPO>_%)r2R0E8K{u61%UFfh-Y=;hDE%QbOU9y2eO!ekCcCsrV> zps?ACaRDPcn5m#J`4!W`dIfzu2-ilxC?(CxCAB!YD6^m>Gd~Y34iOD7gEebrY#pM&; z)Nh_Vy+fg+g4D?$Q&(m^P|J;PVZPhH(v9(An@T*T|+p7|IW>`T;td(YD#u8JhAX$_#oi=Y^Iyb z6A#q}m3n*j?+rcHZ-qCW&{Jiw(@K8JDG=;%MW5kEf(=6fgB7ce*nP#sC(U!3eDBmc zwDU75JQKUu)x1cyaJej#)6sN>8m*Qgr1$WJiwROa&G5npZC0?L% zgzZ6%x$rZF5NYXk4CjxnIKxnL%Ao%W!+*IQi_;lye>xJe-Sd4dgTe~DWM4fw#Vk% delta 578 zcmV-I0=@l@3;PO?7%~V00001JzVIRd000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aik!eo>Ad$LmlPdv2vvL8T0h1X6p?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oMwV421M z000J1OjJbx00960|E1ZV-2eaqfk{L`RCwC#n2QdBAPhxs|Np1A7@#kdg2-ILw)lu> z4{hnS1AqPagAMQ+09<~a2LOIVAOMb&`tKzGusMU1eJs_m5CAj>AfL%wz8igzPt!nT z>|#KS>P$kUFJ*tgkg5$I9LD{C5rFcf7C`cw8ao9b>H(fSJ7X4r&jHFY<>;31i#y9T zwY1+|YxxTRy0lh_w0q7&Z07-ZfvS0hb Qf&c&j07*qoM6N<$f^|vo?*IS* diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png index 789dc8822e8442ddd49ea503b9ac8d109475e1ef..b48aef97839e4766b73c9630ae25c4fc2abb3d3a 100644 GIT binary patch delta 598 zcmey#)x$kOB9Midfq`MIpR6*FVk{1FcVbv~PUa<$!;&U>cv7h@-A}f&37T^=& z`v3obAT#vPO>_%)r2R0E8K{u61%UFfh-Y=;hDE%QbOU9y2eO!ekCcCsrV> zps?ACaRDPcn5m#J`4!W`dIfzu2-ilxC?(CxCAB!YD6^m>Gd~Y34iOD4`zo``_31b32qV@>rWQ9?@9NxS(A+JlrtPTc2?O zYs0iRdCiyD5=+-k`+6bm$K#AwOjktKhi}_-b>^F8cNaffU(&9?&yYJcV=v>a%#f-4 z43{6gi)0d!7m&9TDAJ$7za_0{SHtvg%zKzBPR+fl^U3JI|6qrS-W1%uJMFH1XI%QP7`_(^63JMb_Du4nvkZU$okLlmoyh3c1@3C8n+Z@cV{t0*s(kaZm5ZOoNS`1{exrSNu33E&5X58#IG@YS5MbV;d#e+ zYWqwB#s#--6fjnprBwozw^c4-`cWlNC&!p`TKK-&-_Wm86D}J`JKa<{xoH(^ON(Ly zlftJJ3My+De!OdTK2#%C)BdbXtgGd$#g0`!q!vu(KHXp@X}zDl+5YNN|G(PGznGtL WnK&{0-W3K+3JjjEelF{r5}E+=mf!XO delta 576 zcmV-G0>Ax?3;7C=7%~V00001JzVIRd000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aik!eo>Ad$LmlPdv2vvL8T0h1X6p?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oN5K?$w^ z000J1OjJbx00960|E1ZV-2eaqe@R3^RCwC#n2QdBAPhxs|Np1AEI=O=t@6+%xXnoh z_E1W%9e?QI0~_Eq060A60{{;Z2!LP1f4>9(HfGTHj)fW)0)WN<P3?TVU^&J8b^#D(voiPfajsePR%Bx$JUyLlj zsjdB{M6>}mz<7YXPe7-s7&HNZ)4{10X#1W^;(wF2Tf6{3r3=+b*-y3&LVVIP%atre zNJ}!Ebpog*Q2DzJK*BI}0>AJ3020R{j{A`-F)HA1og O0000U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s5C}7hYIrp;Ffh-Y=;hDE%QbOU9y2eO!ekCcCsrV> zps?ACaRDPcn5m#J`4!W`dIfzu2-ilxC?(CxCAB!YD6^m>Gd~Y34iODOmSOyv4Q%M`>aOn5*dHIgX+W?QkAwwy`O3H@L=4^)oo@i zzKS~6l>_CIVl`i!?wmJiOC^P?u>qNI^UZB z_TvrHHgG$v%Vlz4ePO4tWOtCCvx9krSD@q};RpLxJ`q-W(!~5ma>3c%THX2ywIc{w;!)foz+D=s%LwzPi+6`4nyAd$LmlPdv2vvL8T0h1X6p?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oMEGI*l^ z00JmUL_t(|+U#2Gj>I4cJR9Htm3y1poM}J-KWNnsKQ`Uex^+fiU=8Pa{=lBI0}y}! z5CD75Vt?sI2*K$mk#%$r@I&8w^4&tv`DX(!U<>2`?jmhYlb))5Jp3E^+V8u3hB)WG z_`GQHnEqu~IUo7y|>!DM4zFZj0QpJW%S`&z|Xm@w-`6)LFY#hn+m z91!%sUrXEYdY3;=23%*$a<39V-iJ@f{brdE^na{itqnLm?}E<;bG1f-Ask9JZNT@Wp1^M2ZR$(1-DI zOn>O`sBI$217y*rYG>oHr9+V2IYuU7l4s<8S^&>QfFSb+{#`Xy+2txdVy(au1ipM^VL9lB zuOf>~MK7qi*aP~)wmxdnm(ToM&m(=2zagi3NQd~FXriq;F=f!015yA LNkvXXu0mjfqA^8s diff --git a/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png b/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png index bd0f2b9338264ef39ffcf378f9e6017edc05286e..147561f0a40ab1c8ac7134844843d659783c2109 100644 GIT binary patch delta 565 zcmdnQ^O|ddL?8<@0|UcaKUrlU#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s5C}7hYIrp;Ffh-Y=;hDE%QbOU9y2eO!ekCcCsrV> zps?ACaRDPcn5m#J`4!W`dIfzu2-ilxC?(CxCAB!YD6^m>Gd~Y34iOD7K5f@kuUvl$d`dceBj?BVltoMHa~b5`YnL%L=JGReh8H(%VBLSrcGDk* zDh8IljMrOF)S5HQkYrL4lStTm?Zq_NE6?Wsy({qME`!`B%ibRQd*1h(UmW3g;5s-j zwBeYM8RI0z8O%!}WF4;8hz8XgvKKr3id86X=sUJw5tmEpqsDVK~`H#}*0;5XZpp|#)pPTYlQP6`fNS=RV0Viu5-JENbR%=aaL z{dmKy4crf&G9D1!z{{X*(B_oIb~;9&;^;f3d9JGO1rk`6@$@hR+3qf43~ZEQkJuQ) ze#5<1_E8QGV`Z@>qt+~Ap~V6_%oR3HTRMl)aN!pghG{0P=C&5In!jnSVc@D}yl|#< pYS$IHNJgvo^ZzgZ+bnj7-E@s%@+~b+J77#Rc)I$ztaD0e0sw!z%fSEu delta 763 zcmVAd$LmlPdv2vvL8T0h1X6p?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oO0n2LV@ z00K%$L_t(|+U#1{j>8}fED`_z%h{^cqR2M33AhPl{IE(D!ZCx-b=vp+1-VW(KmYOA6dF+Fn_yp6!bpi7k6@Caxsq&{Mz!rl7BzSD_O;&bERA51j7THWi=qk+FW}Z9! zP3kc8qR=tx_6Mw+Gb$kQR&6Ecuz7t(kx?FH6VW%pRbX`vTTCtZVZ}0$5d|seLwGu- zRDXEPGLfbMdeCOZ&dy;|n;^e(jC8`p&*=5YRXG^WR&LckT~VCFmVwwT{+MMVT5x|( z3W`Jw!U#a`!tdo|G0yy79gvM8KxtMeuO56Bl`m^5&hSp zeSxJOMQCdMCEXA9jO)^RdCfIJB9Midfq`MIpR6*FVk{1FcVbv~PUa<$!;&U>cv7h@-A}f&37T^=& z`v3obAT#vPO>_%)r2R2!t6$HM|-a7?@{H^zvuo<(fDvkC~TCVKN7!6DyEb zP}uCnxPXxz%v4aA{EBH|y@I|SglnT;l#*uUl3JWxlvz-cnV$z1hlmEbxB+=K`W03c zxdpkYC5a%OeMLcHa&~HoLTX-$tx}Paz1{yC;&wpydwRM!hIkx*I<0%%VFix1pZ6K= z{ZBo9G%EM%#xl>%#UA3~UGq=4de^%stc|H>DEZvFp6SH=YzDTg&u=quY|L`_$ekEk zD0CpNmf^y2hOf>MXH8twQnj{D=5c7wI-OV@%eZcp+h>zD_T+{;tR{K;m@9Y^m>XOD z41f5k{h*gK?#Oig delta 726 zcmV;{0xA9L3XKeq7%~U~0002c0+&Ys000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aik!eo>Ad$LmlPdv2vvL8T0h1X6p?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oNTQ!`Ki z00JdRL_t(|+U#1}vV$NDEDrzw%bYXq)JcKF5Qr#lo={sZ*<4pcO6dieCmU1%0001F zo<#0J2!Fw8No1X45Af5z_vEXEp!Al31IU6oAbf>-Sk=!s=QBGcU5ielpD-?<{oS|d z_#Ek9?kQCeb&@}6t6LKi9u`&&?{P`p4J?11SSB_E36|c}Slt&w zC+%}O*_z^vzBNaNFeYK;M@}3JpGT`|zkm7>syud~A_OO0*zkpqP|Lue57)70LkJ*( zu9XU}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s5C}7hYIrp;Ffh-Y=;hDE%QbOU9y2eO!ekCcCsrV> zps?ACaRDPcn5m#J`4!W`dIfzu2-ilxC?(CxCAB!YD6^m>Gd~Y34iODB1mW<1j6)WVvJ9oPPxyQ!48jGOlskvre!-&%m?l{BlNtq^k{E}{ z?x>7senJa+~jX3G0qkQoWZYdcR2>Cs}-xt=ljs?3_^!8hfzIzx&1YFU5FJ^T-N zN?o)M)q5-R__NnM>H7YwdzSvx_g7t9tG^uLXoygq#8Akh|3d75X}c!dM$5~b2N)lS zHdL?&^g3ELovr54IKJTZ!A%FQUo>Nw&0u%#lZb*egUi2**Brxl)t>(A^lDvxxt;8b zuTJN$pN`RbT4}zHVcB;_W(%oTOcA>#9(d~aAi=aDI!E1x;YV~eb3*gY+Vjn8C3rS( y;PLpx>abm0Z~d{C(_eiGOBN5?{>$F!3-e7Dv!zz0+0TJ7&fw|l=d#Wzp$P!L_tz)@ delta 736 zcmV<60w4YJ3YQF!7%~U~0002c0+&Ys000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aik!eo>Ad$LmlPdv2vvL8T0h1X6p?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oNGb`Hz{ z00J*bL_t(|+U#1}vV$NDEDrzw%bYXq)JcKF5Qr#lo={sZ*<4pcO6dieCmU1%0001F zo<#0J2!Fw8No1X45Af5z_vEXEp!Al31IU6oAbf>-Sk=!s=QBGcU5ielpD-?<{oS|d z_#Ek9?kQCeb&cR(W=_7euOHIU8o4bNf$PJ;Um;C zFzCZ|?AZ_kh@fjF26!p&qJ6!M0)X*_ja>KxfRiwA&jC+Xbf(<$&7HoD004F_fzx&U>cv7h@-A}f&36W|l# z`v3obAoK6vzyJRI`{g134#?pw@Q5sCVBk9h!i=ICUJVQk%rhr?`7`lyO`Mg-%*&-P znS;@Z6-X;6Z1!SYz{n0}Dkw~T#k8Y^rpl>0b=AFvA)PXxA4=E<|EgDRR_$kXFpuBBrLg}RLqgW| z-HbXcTMdrtvt4QNWVln!zF<0|RJ+67lI}C7eO{>>Gx)C3J^rf z4qTtP9#|&q7Ic20$^L%jk@xHh_Iu23{9=sgyL!XtS)00bPLzqL9s3KnBK1xYhoApg z5@OG09p64Dmi+Y5p9;U(`@Eru??RgX)yDJP%WBvYHr``Yu+?Eava}&o zw;+%?o}q1*tJV^3hx$*S#143HFODdGAEY^dbs<~9Eq*Hp(JOog9#(x{Wi9gq*LHum0&Vv8-3GiKkC_`5ij}!PerbR8<iZ0h1pCp?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oM%Oi~C71l@rZ^CN`rWH(PVL%q>bkUycgPaP-qu>$(mxMhY~CNP0@yp6uo9o!5R!k$u$X4#%CD7S(J% z`hR87A$*qJ`BIl#-kgE;&9&sq$)Y z|G5W~8GX5!ph=A-a`6;g(D+Wcbar4mKmpbmnqCI_M|(h4$$^JBS^*{8K;O3ts`hB| z5%#SK2@jJ}HDXrmrZjxzp<@rr#D*Y&jejulQ1>-|C-gZ?3|x?@HAhNlOu~8wO6U(} zMZfwdRC(+|MF>thvEd7ULM;P>K3vD14IzLCSSxjaLwOhU^)?Cxj4y2D!XFAaNC)mY z;K@LjOmG&9^lbzb(9R`rh?|-?grJKxVi3O~yIL|K1hKLH7&dfiNZcO#xN@v_og_2h lG!Z!f3V=WXkCi_G1^|H}F1Di~quBre002ovPDHLkV1k$oN;v=k diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png index 614ef9c5aeea94fc93a47ccf41b0ba8b4c8ee7ee..1e52f1513742e3b985d00385f5e153ccc3937edf 100644 GIT binary patch delta 581 zcmbQw^P6jeL?8<@0|UcaKUrlU#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s5C}7hYIrp;Ffh-Y=;hDE%QbOU9y2eO!ekCcCsrV> zps?ACaRDPcn5m#J`4!W`dIfzu2-ilxC?(CxCAB!YD6^m>Gd~Y34iOD9odm%?2E0G_Ydu}l%9{f|7{Pwvlh}5fR*!A_)YKG3&QVkQz_DVB|&SDFybIs7w zW0JVW-mr&fgT<7zH1{WA>x`^p86$%3%5J;PE3hif#QvDjL5T(BjGAZC8%{9(QCo1z zneSe3=YRPFe?H7Q@SJhs=e!&(^T*Be_O0O&ox}V_;o?>ot_APx858d9DSLE6u(lx~ zLLp2ruwLqD0l&h#oF6Op2Yuf9Y4NNjS=-}gFb0IJRCBoLBvQhkV10N>^P@SNm^Uz5 zFnX|Mlr(ISxuW~y_ld?QG8@7i#1C##V6dA~$o*jBJw^lD7^aLZOzXcfWtl(VOt`UK zM*LDi?fXjpge%;OBlzD3Y0fWy%=Mr|uB2h@LcWHjoh;W}W*#{7ib31BkXd2hEpvvz zl0PXd+lvfrTT>k-@iVmTE%;$F?_Y3inJItb)vND2PROSwnAsjIw2T7AJcFmJpUXO@ GgeCxpA=_&J delta 744 zcmVAd$LmlPdv2vvL8T0h1X6p?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oN1o5w={ z00K8jL_t(|+U#1{vV$NDEe`+x%icTflu3cautX3}p0HY$ll`bW&+`QtCkG&a0-ylM zIPu&K=YO2hlE^yO9$<&Q_2jFCpz|#q2apAGfcpydu&keP&R6Y}bS*lGenP(h`oXv8 z_#SCrZkH;Ex=7?Sk^M&g6j`*!&x93=J%C%ddN3rb2hRwo(aZla{e|9YcaG15>HO=2 zAQ}f|uCKVg`4?npw(y%Ao*H0uDLk3}P6ry34}VoS_pf}}VC~E33AU?(pa2LIFs0Nd z;UUQb3ixR;if#=jDk^IB^f-;>gQ^h=&0A5S7S&$Qb%iXsWJfpoj_4~VsW8UK5(V-= z?uxnDs>@|=QF?qiD){c`cho`F7&&A)?uC0MqHD6plofEfsAlti<}6B2RZX_E)ECOt zTYrMmQG~?}39x$I^DA9~p7md>xS+mOP?kT>+&rG&~IS@Ad#1WPttv1*C8TecLK1+gQoX(W40o3zN!*ci&ij zFKPJ7myRusJsW}q3Zba6dan5!q0eD*6n_yo`qmsNp)v_8KXT&K@VT`r`q__A<*^AB zAvo#6hA(`Cng#}axb`g@LI4r4R_XvRU}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O+BKL|5gum-CzFfg}F^zvuo<(fDvpP83SVKOJ96DyEb zP}uCvxPXxz%v4aA{FCzM>#8IXksPAvG_>R;ftI-tPJ7X{JE;hkLp>hIkx*JB>T9#em1f*nGy$ z|Eby5iuPu^8MQ*QUb|*Ap6Pz}&n8*Ht_WcUcAM?y#sVlDj4O{@87Xw70?z zOtDLMGhA>x_Tskp494r1en=$vMe+FDP5PkQ`o)_u;=vE53l?{UU9V1RXHZ@cx65m( zcr}B9!b0DUzz!>)Ejy10AK1XSV3E_}Ka%ASjxKn{;M60TAZ~VNS^|^4gZ<|J)5Tx$ zwM=`iTL0vyl!JCd7(;Kv6+hbp&(pQCUu=G`J)1|uu;I1NE?qX(h9A1G8caV0J6Scv zF|69lDzh$l*G_G5ML7ns$Q>L9|T#nOn<}vA5HgA*J2Fp};AT{lWY2k31Lj5}rDK`NEeV z%KS1?%#87D9b3V>)@+8J$ocs%KTm)4Eu{Wv&@ZO<4Ti?5S8OVQ@y_7s>gTe~DWM4f DD0JIS delta 554 zcmV+_0@eNG3eF0U7%~V00001JzVIRd000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000ANk!eo>Ad$LnlPm#3vvUEU0h1a7i+?XZAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oOw-4GW5 z000J1OjJbx00960|E1ZV-2eaqX-PyuRCwC#*nzHtAPhj!+yDRRB@Ss}1wldH+cZnm zMClQs#eX4-Hy*&B0Z`rM17MNB0JanV_XU8Y3GN4wgk1#KqG&8`9fa?Qgn04EZUxA1 z1Hv#ugWfy_{zoQ!0NsF28O;DsR36x&89oEhavFCgl--p9+btn3?(3n>E2o`FcbVTpnNNCEilzEeK&If&fCe>1s4IfYUG_? zSz8Vn!8JhkSwJg*Gb^teAnDu|fC`2H%$#opFcfg22V!MjGzJ)z2Tsm{ae%%&@NIyG sS}+qJ2QAX{WjL=IKYvy~0C@>806$X`4`zs|dH?_b07*qoM6N<$f+3vSUH||9 diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_1.png b/assets/dolphin/blocking/L0_Url_128x51/frame_1.png index 69f1fb365988f248aa238fa6a2d672fa7d8bcee1..9975ca3f042623b1cefdd5eb913a804dd185d734 100644 GIT binary patch delta 682 zcmZ3(|BruyL?8<@0|UcaKUrlU#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O*?7=#%aX3dcRs#2KflA_ zpXF>ll4hVPeRO3u`q)f_sB=jzPAbocRnwN7ht`GX(lx-}lyu z|AzPDq#B&{BP!Dh5S#|Hi>aZs!4%{dD^NuZ+)Mju{Sg6x+O`tx~ zx3|>Li$7o$b4%R9xPOm~HzXx&Wju0&@r&cttE{FQn6?DIihsBwpP}$|Y{yrw24@C# zhHVWYZEOtIKK$~pbZ(UNHCFH>lu6wcYG!VbSohkY=*jMu5QaF0O*JfYqQ(0d=RY+# zB7C4!%#1ODIb?15v>z|`m>=P3SS5Tru47J)KjYc#lhPe|KJU(%Da=>CSWxU>!clcV zaH^$4?pnh~DeoE1%)iIUuq=#1%;Y|NnpK&G~mH28c7U-kg}}&!{kQSN>!j zMyJiij9-~1=d&!7(YI5usmLwx^|kWIEH23}ss!?jQqrt~Qw!}Td$69Z2Px2pi2#}C ziotR&sl~}fnFS@8`FSwqK`w3}W`z|{LvCtGB9LQWQIMFNom!%hnwMg$RHS5YckBCC zYX%0!bWaz@kch)?XWZV@tiamQiU zxS;ARdqX=1%Yie0YZx6;ntn5O+_7UxNb8<^RD8SI!$%XZ-nZKv&G=?J<24f{i@lcY z|J>DU7VDGYvW8teSGB_FhEI#%ayX={<85eeeZw?iRzCX!r-op`3(8l8Ef1L1J}425VZCsheING% sNA5JH8;!2B{MtTW`SEx2FV+qGb}NPXFA6B10HzKGPgg&ebxsLQ04xUSEdT%j diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_2.png b/assets/dolphin/blocking/L0_Url_128x51/frame_2.png index 855e7450e53b99c522d473e9e913271be4b36536..84241c3f16ab65f696964e17ab96c1deb8a7dc6c 100644 GIT binary patch delta 680 zcmZ3&|A&8qL?8<@0|UcaKUrlU#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O*?7=#%aX3dcRs#2KflA_ zpXF>ll4hVPeRO3u`q)f_sB=jzPARUho>;uzv_{Oz>tqQeS2EnCea?*892QNUkV$miC- zjMX12at_sT*cLpwe`t&Oz3a&gFEkrIycSS!*;|snPr9Fx=dC&eW9-u93>VUt-8>$> zgX!JUkI4;|nT7_X-3OL8TN_JU(V znKXk*Q~sk_toF&-JTsCQu1A(c^Dr&2I~FRt!R_Cq2}}SSw$=v*})r_JJ=3#c-)oHf6uV&>#>f> zdl?tqo!)+fwPA)WLs8r}hJUr8=NQ(?|99q}#BJS>Zm6L*CvD-bf(Z6z;rrY(svpWR nB%fIC{OjNRSKor_kGjaE>KGbtX4qr|Ok50}u6{1-oD!Mq=#1%;Y|NnpK&G~mH28c7U-kg}}&!{kQSN>!j zMyJiij9-~1=d&!7(YI5usmLwx^|kWIEH23}ss!?jQqrt~Qw!}Td$69Z2Px2pi2#}C ziotR&sl~}fnFS@8`FSwqK`w3}W`z|{LvCtGB9LQWQIMFNom!%hnwMg$RHS5YcjC&P zrwj~?@t!V@ArXh)&bZxoSb@jo{Gb2+-xXQTm~LRbRG%vx>ZP@HUbA5`$F84`7=K7G z%(`C1u%q(;gU8kL;tVc|H~1Y?s)ZYtD4$z+^qP{5NMTi7N;Kn_+YIY^I2O&$eo$}m zklBF8z~fjBL--9no}CP~@qcqA7!I!VF03&T7GPZRt1?LIT^Hj6lS&awJEI8|?i(1E zBz+5GRXEe=&02r#-J#+`3H47Hll~s4uw*TKBExWuF{P!H*Fo6f=yJ7&bD6!IS*r!4 zEw3>J{5+S!)e!l4FT<1e-+LuLu*}X@P`$B-tEg$Oox%5%FN_SbdlOU}^pq}@ j8bn|3oj?65e?#1h55oNRTYdxrQw4*ktDnm{r-UW|Ys2O5 diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_3.png b/assets/dolphin/blocking/L0_Url_128x51/frame_3.png index 9e9a79405817d4f1f3ec242de249beedac773c57..c44b171bfaae20b74657855c263a48cb0ca3ae85 100644 GIT binary patch delta 681 zcmZ3?|CfJ)L?8<@0|UcaKUrlU#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O*?7=#%aX3dcRs#2KflA_ zpXF>ll4hVPeRO3u`q)f_sB=jzPA_)(Vst@sWaSZV|{&re+(P0IimYdRR-qqiH)yR5d*})}m z`?vL|CtKh0ck=K$^}kE?@1tT{wuU!M9J|dJTTgh0y~!<>&a&}@i^PKDw=QKk_mO148k(ujE_RS<(PUJYUVI9Fmlau?r~Z&^K=30ixu^S z3`e!EoSy%WEsW<9Yrqn}X2u2lS?i($8bue>Zrb17`zlC$*TdPmE&JIfa5Cr}<8^Rz z$dtEjSanw5SMUbO*_I2QGc3FOW}A$~fjiBYtrF7yl_-b`Y;<1c{59BNB|}$^-&3t4 zyBU5imdKI;Vst04103%>V!Z delta 569 zcmey%znFi5gfs^;0|P_Gz7I-3iY>q=#1%;Y|NnpK&G~mH28c7U-kg}}&!{kQSN>!j zMyJiij9-~1=d&!7(YI5usmLwx^|kWIEH23}ss!?jQqrt~Qw!}Td$69Z2Px2pi2#}C ziotR&sl~}fnFS@8`FSwqK`w3}W`z|{LvCtGB9LQWQIMFNom!%hnwMg$RHS5YXE%4t z0R{%fI8PVHkch)?XLR!&Qs8m*|NnovubR_ouBJ`r>W_<^-FD=w+&eFBC3X2226<+O z?-p_leo6rhw|oEpWMmL-s$l4O!Okg=ld>|y*8Ty7=GqAOmP#r_(0}IpH~H= z53|ptjZzA#Wn72j8YbSZnZd6Md9nT+5Rr(SumCB;Q{Rp6TdSUa4UF4xG}t7>ZrcTD3IHzmT}gp z+Pcd zYZ-)h@jh7VGmT+|r9ImL?dU}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s5C}7hYIrp;Ffh-b=;hDE%QbOU0W&X`!elN+CsrV> zps?A8aS0Gd~Y34iODy-7)iZ-yW^cKASs1s%!TYpTt@Q=^YUv z71E3s9z|MqZhqO+z!AgXaF0!9k{Cmc{DWD~b_;&8dr+eQS#MaGCx|y}NpR<3 zP(OIptDbd(nU`bt>72mw1I;@H7~7rAS!;IkH!NV>`*+nn;fhk{fOoRD7(tYR5DGNX3G}xo6A4`&apd}80Y#kUU=8jr}l|)!F2rx-0IKMfN{^@>FVdQ I&MBb@00G9?xc~qF delta 551 zcmV+?0@(e73+4)t7%~V00000bc2Ow+000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aok!eo>Ad$LolPv*4vvdKZ0h1pCp?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oL}eh47| z000J1OjJex|Nj6009C@%egFUgW=TXrRCwCtn2ip@AP9u--v6bSt<$Lkg{pKvW?7nQ zxvwaQ1%F~1i-z#lh(Yq%H(_gqvV83gECM*!&j&z5tqP0KouFdS##onB48q zUkUJZKc#Xg?L7HPf}Quk!5{z>)07x9@WLp_=6?kM;`x_H%>huPI_z};n3l!d6m$~- zbbw3tf*RmuU}6gB>aPF_FH}TJ&jZxYB~56a190kt3c=ZHlymlHutNY;m9%BapX#+?Pm2=7!0A+&c)!6Oo z=~z#K4?zC9GRm{d0Elv@P~)?H_fhPw02o6CH~_$P pEZ_$H6MOBI0I)7?qq&;^0|4Z21;)FNg7E+V002ovPDHLkV1nMUU}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s5C}7hYIrp;Ffh-b=;hDE%QbOU0W&X`!elN+CsrV> zps?A8aS0Gd~Y34iOD+9 zf0HHJC8H14qjK5W)do3KJdj%!Q&RggW877sQGTozB4}j`kuj#_1p&zg}wr&gcZ{N zI0cwff@PQ{`26%}R1Mt4B*yqF^cl}(uSNN9`1h=F*dNUx)?qZ$bluU&0EPgD1}o_# zrX3v1>ZeIH*liYA@@m(jyaxSmPE0J#i5!0n`WjX=x<3!CR$JiX9Fiw&#bCm;hM|f< zV_n`&u>#$rKR9oS34CYL5I@1n7}MEU;Sjs>0_&B3D*m%iZfauEe7e|D){Q~qd7olu5+Z>X@>H4PuH#$#hsOG3V$Z7UH8dXogv*L zy5ZEmdd}Gldour*{FAycM_YoSO#emA?ef_SheRB{FcyUBXO=|lJ_n3?22WQ%mvv4F FO#pDe(sBR* delta 545 zcmV++0^a?C3*ZWn7%~V00000bc2Ow+000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aok!eo>Ad$LolPv*4vvdKZ0h1pCp?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oM(r97wr z000J1OjJex|Nj6009C@%egFUgU`a$lRCwCtn2QdBAPhx&|No~KryyWKN+0e)mcl00jdy=@o$z5*z`P!XBl2hhKlG@-c$Ak-&x2v)DMQvFLVtUGpu>T~_Fjeg%w z_5ZnUwbwz(JAsvkkPX|Ww%h>Rd2tyaJ>Vw9buIA(z~x9~)pAc^2tdF9fKvV_)osr} zl~Sn~0SuO!0r0PRF8-dWXe$7qvScywDJiIy0K7%>D40r=^X-HVz~FZLH~=jN!MMUW jzXCRNfP%mP;3dESp_c`?`EG1V00000NkvXXu0mjfVa42_ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png index 12dc13430908844d89e0c7a002030cdc4999124b..5b474fff262306ecccbdc2a0ace273bd26e55219 100644 GIT binary patch delta 588 zcmaFL)xkYMB9Midfq~&c+a3)d#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s5C}7hYIrp;Ffh-b=;hDE%QbOU0W&X`!elN+CsrV> zps?A8aS0Gd~Y34iODv^(Izmxfoo%Z3S(t+2?qoBLQV~aLI#7j;5jElsuK4x{$WbkrF~__S?SyQ z4Xv$nD`T=F?l_n+eD*4}o3*)*;cTVZ&nds`8h%zWE%E-i*H6c~{A-oBtp0-CE~X9k zT!Gfn`<94*+8YqlaIVk2q0mO>u*F<$8OCPK^Y318J6LGRIdI6=gzKB#_`MI5Y#2OU L{an^LB{Ts5>L%C3 delta 550 zcmV+>0@?kD3*`!s7%~V00000bc2Ow+000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aok!eo>Ad$LolPv*4vvdKZ0h1pCp?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oML+;Z^% z000J1OjJex|Nj6009C@%egFUgWl2OqRCwC#n2Qd>AP7ad|Nqm=Qf+;Jq5|2LnPus! z<(>+HlYc0tp=cD|8qsJ5PA(8Zl4|Z_(9ZOAU4Rn-l$~!8@dGFQvfBv&>H$6gppOT* zhqwTMRsbAU0Tu>%0D!&%fPNQX?WsRN9Dral3g9x<+XRIHWDG3m+W}n0I-@gvOMt8n zaB+b&BwcZ^=QDub1(nK$_a1;7*fa>!TM`2RN`GHB#2Ekv>zzgb$YF8j0xV{s3=okC z(RSAWkAVXh%=IAw6thqf+317QXa2fAKehl=`VdM%wPg1IR`t7FSnt?j>3=o~N_}p> zY*mP*g;2dew_CNVgFCws1Av*0Wq=75xB_GefV#G_5teT2W^fZAUqCMVN(UYS5TvqO zI#(aIF`xlxHW_5P3Of53#NpHrI{^GK7k~U@z6y#o$sV@#2M-hlAlM^6fMGt;=h4j& om?U^|JQ>#kcpg9-0=xtm0DO@JvS@mv#Q*>R07*qoM6N<$g7Hz*umAu6 diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png index f17f8713d34b7702ad58def6cf332b1770412808..952f968fb673a5de24fefb834e6c8655cc29a6d4 100644 GIT binary patch delta 587 zcmaFF)y_RZB9Midfq~&c+a3)d#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s5C}7hYIrp;Ffh-b=;hDE%QbOU0W&X`!elN+CsrV> zps?A8aS0Gd~Y34iOD!g+4&{$9uXshIkymJ1uh3VFezSm(p9_ z)!&?WBpwptZfZ+(^0SUjtyk(cTKl47|Yk0XXAgSzR zb~yt#x3x!1_DR=AtTVz_eJ*`=GxU&o!?Qix-qkRC{>tFsCH3#o^V=Fv&fFDAmR(-$ zP~Q29^B{M^pDTYiU3-xXHjCsf*;S(Qsp`MB3A-}~ky{o^?wipBB OpTX1B&t;ucLK6VtnBzwP delta 547 zcmV+;0^I$F3*rip7%~V00000bc2Ow+000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aok!eo>Ad$LolPv*4vvdKZ0h1pCp?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oN4z+l$^ z000J1OjJex|Nj6009C@%egFUgVo5|nRCwC#m;nxhAPhzO?tkfJ5fr2dg+jJv#26>6 z|6xn1iht~BBu%!ro9J!^O>QGXP3m@^hc>6**9D6R=&0s#360Qp@2+rRz*`v58?cL5y6N}I?wfQW%X-w)t0Rv2yRdjdpt z(BgtHBwT5*^G|@%1)0i$_a49r>>7k&mZAV4;eT{O%mMJQ-sK5^7#4Fbz?g+1z>ZAF zy*mfE3{1G7txpXgc?ubkk3O2d^6Gm17y{_hr?M4fOLh#vs$b;7ykf`G|7sMZ`dYp0 zwGr1ALN7P^ lpO$=HP6xC7PXN3G7yx#e1*^`5DHH$z002ovPDHLkV1mgA;jjPz diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png index 7a6992a2b04cdaf35abb8c23f269293e143a4ea0..2bb43b306f3bf9025ba68190fb4903cc5a132133 100644 GIT binary patch delta 573 zcmcb^^^;M1%fy~fDm+OEOXMsm#F#`kNArNL1)$nRyU|^m<(aWESmuupz0%l$=g~?ouPOLy$ zL1D8G;}S-8FjGNc@&~4c^$PlS5U!1WQA(PXOKNd)QD#9&W_})693mRz;s)f|=vP=( z3GX z?|;K45}z%!CFpnd%qu-752SNv`LMGECR^2S72>k&jo)(aQFL@wwWL&=wfvcc^9*_g zsw*$N=4}vt@1-87e^Vf!L7HL7dPcQO<^%5;S82w%EqTxQ?ZjdJTC;trFl$Ns3O1XL@Pk`6ubuwKq0WDbz=F?@ x#S-4|pEmM)FWT2|aB6k>7gmMbNR|ng_&I;+l{b0*l?BE)gQu&X%Q~loCIB#J)NKF& delta 541 zcmV+&0^Ad$LolPv*4vvdKZ0h1pCp?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oL=qvEvy z000J1OjJex|Nj6009C@%egFUgTuDShRCwC#n2Qd>AP7ad|Nqm=nrTr{QGx8`mZqyM z_e>C}M1L_2tWkKYM57rbxj=-TRCOJLcBZfE0-Ok-?0kxJzi`s$-A({d-{1oPdV7F; ziwgi~1;AkzVBsbY0MJJO(DwqYJ@p6pc>qu}KvkoKk3ea3rf&xTmiO8KNGnf1L+UaF z5dTzh1s4M7`n<-*&IR(I-UIMDWQa3>!5GjG0Dmbg&Rl@SB#;0iW&!H%65uv);DWh6 zdH_6Bu=^s1sW`^3uJ?~E0F^#EO98vI`zpJt-{iuwVu$TAAVdMzm+EC3{d)b8^&wTO zHaT#&7%%{s*;odcUs0ZWtOW?Q@QKv4i4d*lZ&%t!h>x)}nK1W%4T<2nG( f4QNAvhX4Zr1eOJu%LfM}00000NkvXXu0mjf9sAk! diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png index 00d9843007e85a247de0c23257c310512b5f71f5..d7f8c6402a27c5a2eb565d12b595a3a438ed94ee 100644 GIT binary patch delta 584 zcmaFJ)xteNB9Midfq~&c+a3)d#aJBV?!>U}oXkrghb7(7*O7r?V?XzwL{=c5Ex;$l z_5c6>KxXKn%XL7Cv%n*=n1O-s5C}7hYIrp;Ffh-b=;hDE%QbOU0W&X`!elN+CsrV> zps?A8aS0Gd~Y34iODz$gZO)!`%nnn~{g8^b441&v9d6lX$2%~n|wpQUNDi>ERVTD;TVg~x&%=k2Q!AubA1(z zAx*2N)^jGDkLIu{+3kCmaeoB2xPqijTf^-4JSU_+l*FA)XNs2GRHXlcIYH=wbOQf^ zCpXvLW_lHJ#`(pzhCN~$sm(kb2Nc?FF`F<*{B>>aUYRR@`DFq7fs*hQn)CgqTQ^K^ zom)98JK~Om9K*b+vud`aS|uyuqh zX6oPe`*r@3B|}Ns9j2bgiIK-%#ysSZ@Yz}J9?y`n+Lb}cz9mQhq<7|ZMPTGJc)I$z JtaD0e0syY@+hza& delta 546 zcmV+-0^R+D3*ico7%~V00000bc2Ow+000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|Dh zWnpA_ami&o000Aok!eo>Ad$LolPv*4vvdKZ0h1pCp?@zvAUrQ}WM(=fFD zZ*D#yJTG!&W;#+tMm``sFL*k5ZE$U6bYVUqJU@7FVPk7$bRcDJWIZBsB0oNIez$f2 z000J1OjJex|Nj6009C@%egFUgVM#AP7ad|Nqm=)@jv(q5|E+G)*%N z_e=#5qJNl%qEUEjM57rvxj+O-s`(wAwx_S_0-Ok-?0kxd51jPNZYKb!2lxPhJ{}+s zaRC6$062I7CI)!`fW88Neir~8sT%=a?#7sm0yu0jHva_xCqR=8P%uCfUJ*D0NYg!` zZwc_8esJkfI(hOJ2fIH52Ll68EK_34z=mFs&3`ihp!X|}+5-Sfb=d0yAZ?4iCFlkM zk^ycx3u=JVz{V0_s=op#W}zZ7y$?XXmo%=q1~92l5C~SUva|Y^SXgK52-WBEWgC6j zPWAt}Y}GCkSV;&C07f>Z0R~u1nA=H-ne?eSTg8B{4dsgf=>y`iuU)`R0D>6s%VXYl z4^wCWnk0ivz2IUWoqaf5hZO+6%*B_V%)OuplWei=T6mx+0Kp#l0d(V$K8`MKfkA*L k$I7@4z_S2t2=EYK0A@u6zLP8OIRF3v07*qoM6N<$g6II$yZ`_I From e12958d408dfe0e1571b60451bf73b1d41914981 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Sun, 29 Jan 2023 15:08:26 +0400 Subject: [PATCH 11/17] [FL-3082] WS: add protocol LaCrosse-TX (TFA Dostmann) (#2292) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WS: add protocol LaCrosse-TX (TFA Dostmann) * WS: fix syntax * WS: fix MSG_TYPE * WS: fix PVS Co-authored-by: あく --- .../helpers/weather_station_types.h | 2 +- .../weather_station/protocols/lacrosse_tx.c | 329 ++++++++++++++++++ .../weather_station/protocols/lacrosse_tx.h | 79 +++++ .../protocols/protocol_items.c | 1 + .../protocols/protocol_items.h | 1 + 5 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 applications/plugins/weather_station/protocols/lacrosse_tx.c create mode 100644 applications/plugins/weather_station/protocols/lacrosse_tx.h diff --git a/applications/plugins/weather_station/helpers/weather_station_types.h b/applications/plugins/weather_station/helpers/weather_station_types.h index d512251f1..1f5612e2e 100644 --- a/applications/plugins/weather_station/helpers/weather_station_types.h +++ b/applications/plugins/weather_station/helpers/weather_station_types.h @@ -3,7 +3,7 @@ #include #include -#define WS_VERSION_APP "0.6.1" +#define WS_VERSION_APP "0.7" #define WS_DEVELOPED "SkorP" #define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" diff --git a/applications/plugins/weather_station/protocols/lacrosse_tx.c b/applications/plugins/weather_station/protocols/lacrosse_tx.c new file mode 100644 index 000000000..8d8a24e24 --- /dev/null +++ b/applications/plugins/weather_station/protocols/lacrosse_tx.c @@ -0,0 +1,329 @@ +#include "lacrosse_tx.h" + +#define TAG "WSProtocolLaCrosse_TX" + +/* + * Help + * https://github.com/merbanan/rtl_433/blob/master/src/devices/lacrosse.c + * + * + * LaCrosse TX 433 Mhz Temperature and Humidity Sensors. + * - Tested: TX-7U and TX-6U (Temperature only) + * - Not Tested but should work: TX-3, TX-4 + * - also TFA Dostmann 30.3120.90 sensor (for e.g. 35.1018.06 (WS-9015) station) + * - also TFA Dostmann 30.3121 sensor + * Protocol Documentation: http://www.f6fbb.org/domo/sensors/tx3_th.php + * Message is 44 bits, 11 x 4 bit nybbles: + * [00] [cnt = 10] [type] [addr] [addr + parity] [v1] [v2] [v3] [iv1] [iv2] [check] + * Notes: + * - Zero Pulses are longer (1,400 uS High, 1,000 uS Low) = 2,400 uS + * - One Pulses are shorter ( 550 uS High, 1,000 uS Low) = 1,600 uS + * - Sensor id changes when the battery is changed + * - Primary Value are BCD with one decimal place: vvv = 12.3 + * - Secondary value is integer only intval = 12, seems to be a repeat of primary + * This may actually be an additional data check because the 4 bit checksum + * and parity bit is pretty week at detecting errors. + * - Temperature is in Celsius with 50.0 added (to handle negative values) + * - Humidity values appear to be integer precision, decimal always 0. + * - There is a 4 bit checksum and a parity bit covering the three digit value + * - Parity check for TX-3 and TX-4 might be different. + * - Msg sent with one repeat after 30 mS + * - Temperature and humidity are sent as separate messages + * - Frequency for each sensor may be could be off by as much as 50-75 khz + * - LaCrosse Sensors in other frequency ranges (915 Mhz) use FSK not OOK + * so they can't be decoded by rtl_433 currently. + * - Temperature and Humidity are sent in different messages bursts. +*/ + +#define LACROSSE_TX_GAP 1000 +#define LACROSSE_TX_BIT_SIZE 44 +#define LACROSSE_TX_SUNC_PATTERN 0x0A000000000 +#define LACROSSE_TX_SUNC_MASK 0x0F000000000 +#define LACROSSE_TX_MSG_TYPE_TEMP 0x00 +#define LACROSSE_TX_MSG_TYPE_HUM 0x0E + +static const SubGhzBlockConst ws_protocol_lacrosse_tx_const = { + .te_short = 550, + .te_long = 1300, + .te_delta = 120, + .min_count_bit_for_found = 40, +}; + +struct WSProtocolDecoderLaCrosse_TX { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + WSBlockGeneric generic; + + uint16_t header_count; +}; + +struct WSProtocolEncoderLaCrosse_TX { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + WSBlockGeneric generic; +}; + +typedef enum { + LaCrosse_TXDecoderStepReset = 0, + LaCrosse_TXDecoderStepCheckPreambule, + LaCrosse_TXDecoderStepSaveDuration, + LaCrosse_TXDecoderStepCheckDuration, +} LaCrosse_TXDecoderStep; + +const SubGhzProtocolDecoder ws_protocol_lacrosse_tx_decoder = { + .alloc = ws_protocol_decoder_lacrosse_tx_alloc, + .free = ws_protocol_decoder_lacrosse_tx_free, + + .feed = ws_protocol_decoder_lacrosse_tx_feed, + .reset = ws_protocol_decoder_lacrosse_tx_reset, + + .get_hash_data = ws_protocol_decoder_lacrosse_tx_get_hash_data, + .serialize = ws_protocol_decoder_lacrosse_tx_serialize, + .deserialize = ws_protocol_decoder_lacrosse_tx_deserialize, + .get_string = ws_protocol_decoder_lacrosse_tx_get_string, +}; + +const SubGhzProtocolEncoder ws_protocol_lacrosse_tx_encoder = { + .alloc = NULL, + .free = NULL, + + .deserialize = NULL, + .stop = NULL, + .yield = NULL, +}; + +const SubGhzProtocol ws_protocol_lacrosse_tx = { + .name = WS_PROTOCOL_LACROSSE_TX_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + + .decoder = &ws_protocol_lacrosse_tx_decoder, + .encoder = &ws_protocol_lacrosse_tx_encoder, +}; + +void* ws_protocol_decoder_lacrosse_tx_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + WSProtocolDecoderLaCrosse_TX* instance = malloc(sizeof(WSProtocolDecoderLaCrosse_TX)); + instance->base.protocol = &ws_protocol_lacrosse_tx; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void ws_protocol_decoder_lacrosse_tx_free(void* context) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + free(instance); +} + +void ws_protocol_decoder_lacrosse_tx_reset(void* context) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + instance->header_count = 0; + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; +} + +static bool ws_protocol_lacrosse_tx_check_crc(WSProtocolDecoderLaCrosse_TX* instance) { + if(!instance->decoder.decode_data) return false; + uint8_t msg[] = { + (instance->decoder.decode_data >> 36) & 0x0F, + (instance->decoder.decode_data >> 32) & 0x0F, + (instance->decoder.decode_data >> 28) & 0x0F, + (instance->decoder.decode_data >> 24) & 0x0F, + (instance->decoder.decode_data >> 20) & 0x0F, + (instance->decoder.decode_data >> 16) & 0x0F, + (instance->decoder.decode_data >> 12) & 0x0F, + (instance->decoder.decode_data >> 8) & 0x0F, + (instance->decoder.decode_data >> 4) & 0x0F}; + + uint8_t crc = subghz_protocol_blocks_add_bytes(msg, 9); + return ((crc & 0x0F) == ((instance->decoder.decode_data) & 0x0F)); +} + +/** + * Analysis of received data + * @param instance Pointer to a WSBlockGeneric* instance + */ +static void ws_protocol_lacrosse_tx_remote_controller(WSBlockGeneric* instance) { + uint8_t msg_type = (instance->data >> 32) & 0x0F; + instance->id = (((instance->data >> 28) & 0x0F) << 3) | (((instance->data >> 24) & 0x0F) >> 1); + + float msg_value = (float)((instance->data >> 20) & 0x0F) * 10.0f + + (float)((instance->data >> 16) & 0x0F) + + (float)((instance->data >> 12) & 0x0F) * 0.1f; + + if(msg_type == LACROSSE_TX_MSG_TYPE_TEMP) { //-V1051 + instance->temp = msg_value - 50.0f; + instance->humidity = WS_NO_HUMIDITY; + } else if(msg_type == LACROSSE_TX_MSG_TYPE_HUM) { + //ToDo for verification, records are needed with sensors maintaining temperature and temperature for this standard + instance->humidity = (uint8_t)msg_value; + } else { + furi_crash("WS: WSProtocolLaCrosse_TX incorrect msg_type."); + } + + instance->btn = WS_NO_BTN; + instance->battery_low = WS_NO_BATT; + instance->channel = WS_NO_CHANNEL; +} + +void ws_protocol_decoder_lacrosse_tx_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + + switch(instance->decoder.parser_step) { + case LaCrosse_TXDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, LACROSSE_TX_GAP) < + ws_protocol_lacrosse_tx_const.te_delta * 2)) { + instance->decoder.parser_step = LaCrosse_TXDecoderStepCheckPreambule; + instance->header_count = 0; + } + break; + + case LaCrosse_TXDecoderStepCheckPreambule: + + if(level) { + if((DURATION_DIFF(duration, ws_protocol_lacrosse_tx_const.te_short) < + ws_protocol_lacrosse_tx_const.te_delta) && + (instance->header_count > 1)) { + instance->decoder.parser_step = LaCrosse_TXDecoderStepCheckDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.te_last = duration; + } else if(duration > (ws_protocol_lacrosse_tx_const.te_long * 2)) { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + } else { + if(DURATION_DIFF(duration, LACROSSE_TX_GAP) < + ws_protocol_lacrosse_tx_const.te_delta * 2) { + instance->decoder.te_last = duration; + instance->header_count++; + } else { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + } + + break; + + case LaCrosse_TXDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = LaCrosse_TXDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + break; + + case LaCrosse_TXDecoderStepCheckDuration: + + if(!level) { + if(duration > LACROSSE_TX_GAP * 3) { + if(DURATION_DIFF( + instance->decoder.te_last, ws_protocol_lacrosse_tx_const.te_short) < + ws_protocol_lacrosse_tx_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = LaCrosse_TXDecoderStepSaveDuration; + } else if( + DURATION_DIFF( + instance->decoder.te_last, ws_protocol_lacrosse_tx_const.te_long) < + ws_protocol_lacrosse_tx_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = LaCrosse_TXDecoderStepSaveDuration; + } + if((instance->decoder.decode_data & LACROSSE_TX_SUNC_MASK) == + LACROSSE_TX_SUNC_PATTERN) { + if(ws_protocol_lacrosse_tx_check_crc(instance)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = LACROSSE_TX_BIT_SIZE; + ws_protocol_lacrosse_tx_remote_controller(&instance->generic); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + } + + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->header_count = 0; + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + break; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_lacrosse_tx_const.te_short) < + ws_protocol_lacrosse_tx_const.te_delta) && + (DURATION_DIFF(duration, LACROSSE_TX_GAP) < + ws_protocol_lacrosse_tx_const.te_delta * 2)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = LaCrosse_TXDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_lacrosse_tx_const.te_long) < + ws_protocol_lacrosse_tx_const.te_delta) && + (DURATION_DIFF(duration, LACROSSE_TX_GAP) < + ws_protocol_lacrosse_tx_const.te_delta * 2)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = LaCrosse_TXDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + + } else { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + + break; + } +} + +uint8_t ws_protocol_decoder_lacrosse_tx_get_hash_data(void* context) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool ws_protocol_decoder_lacrosse_tx_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + return ws_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool ws_protocol_decoder_lacrosse_tx_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + bool ret = false; + do { + if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + ws_protocol_lacrosse_tx_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void ws_protocol_decoder_lacrosse_tx_get_string(void* context, FuriString* output) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + furi_string_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%lX Ch:%d Bat:%d\r\n" + "Temp:%3.1f C Hum:%d%%", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data), + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, + (double)instance->generic.temp, + instance->generic.humidity); +} diff --git a/applications/plugins/weather_station/protocols/lacrosse_tx.h b/applications/plugins/weather_station/protocols/lacrosse_tx.h new file mode 100644 index 000000000..e88455689 --- /dev/null +++ b/applications/plugins/weather_station/protocols/lacrosse_tx.h @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include +#include +#include +#include "ws_generic.h" +#include + +#define WS_PROTOCOL_LACROSSE_TX_NAME "LaCrosse_TX" + +typedef struct WSProtocolDecoderLaCrosse_TX WSProtocolDecoderLaCrosse_TX; +typedef struct WSProtocolEncoderLaCrosse_TX WSProtocolEncoderLaCrosse_TX; + +extern const SubGhzProtocolDecoder ws_protocol_lacrosse_tx_decoder; +extern const SubGhzProtocolEncoder ws_protocol_lacrosse_tx_encoder; +extern const SubGhzProtocol ws_protocol_lacrosse_tx; + +/** + * Allocate WSProtocolDecoderLaCrosse_TX. + * @param environment Pointer to a SubGhzEnvironment instance + * @return WSProtocolDecoderLaCrosse_TX* pointer to a WSProtocolDecoderLaCrosse_TX instance + */ +void* ws_protocol_decoder_lacrosse_tx_alloc(SubGhzEnvironment* environment); + +/** + * Free WSProtocolDecoderLaCrosse_TX. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + */ +void ws_protocol_decoder_lacrosse_tx_free(void* context); + +/** + * Reset decoder WSProtocolDecoderLaCrosse_TX. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + */ +void ws_protocol_decoder_lacrosse_tx_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void ws_protocol_decoder_lacrosse_tx_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @return hash Hash sum + */ +uint8_t ws_protocol_decoder_lacrosse_tx_get_hash_data(void* context); + +/** + * Serialize data WSProtocolDecoderLaCrosse_TX. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool ws_protocol_decoder_lacrosse_tx_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data WSProtocolDecoderLaCrosse_TX. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool ws_protocol_decoder_lacrosse_tx_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @param output Resulting text + */ +void ws_protocol_decoder_lacrosse_tx_get_string(void* context, FuriString* output); diff --git a/applications/plugins/weather_station/protocols/protocol_items.c b/applications/plugins/weather_station/protocols/protocol_items.c index 99c8344f4..2c9d751c7 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.c +++ b/applications/plugins/weather_station/protocols/protocol_items.c @@ -8,6 +8,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { &ws_protocol_gt_wt_03, &ws_protocol_acurite_606tx, &ws_protocol_acurite_609txc, + &ws_protocol_lacrosse_tx, &ws_protocol_lacrosse_tx141thbv2, &ws_protocol_oregon2, &ws_protocol_acurite_592txr, diff --git a/applications/plugins/weather_station/protocols/protocol_items.h b/applications/plugins/weather_station/protocols/protocol_items.h index 9d5d096f8..f9e443abc 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.h +++ b/applications/plugins/weather_station/protocols/protocol_items.h @@ -8,6 +8,7 @@ #include "gt_wt_03.h" #include "acurite_606tx.h" #include "acurite_609txc.h" +#include "lacrosse_tx.h" #include "lacrosse_tx141thbv2.h" #include "oregon2.h" #include "acurite_592txr.h" From a8e5f2250026c4260bb13fddf696acb7f9322b77 Mon Sep 17 00:00:00 2001 From: Angel Date: Sun, 29 Jan 2023 06:23:45 -0500 Subject: [PATCH 12/17] LF-RFID: add CRC calculation to paradox protocol (#2299) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Angel Co-authored-by: あく --- lib/lfrfid/protocols/protocol_paradox.c | 45 ++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/lib/lfrfid/protocols/protocol_paradox.c b/lib/lfrfid/protocols/protocol_paradox.c index 7e029f1de..26c9b55dc 100644 --- a/lib/lfrfid/protocols/protocol_paradox.c +++ b/lib/lfrfid/protocols/protocol_paradox.c @@ -136,17 +136,45 @@ LevelDuration protocol_paradox_encoder_yield(ProtocolParadox* protocol) { return level_duration_make(level, duration); }; +static uint8_t protocol_paradox_calculate_checksum(uint8_t fc, uint16_t card_id) { + uint8_t card_hi = (card_id >> 8) & 0xff; + uint8_t card_lo = card_id & 0xff; + + uint8_t arr[5] = {0, 0, fc, card_hi, card_lo}; + + uint8_t manchester[9]; + + bit_lib_push_bit(manchester, 9, false); + bit_lib_push_bit(manchester, 9, false); + bit_lib_push_bit(manchester, 9, false); + bit_lib_push_bit(manchester, 9, false); + + for(uint8_t i = 6; i < 40; i += 1) { + if(bit_lib_get_bit(arr, i) == 0b1) { + bit_lib_push_bit(manchester, 9, true); + bit_lib_push_bit(manchester, 9, false); + } else { + bit_lib_push_bit(manchester, 9, false); + bit_lib_push_bit(manchester, 9, true); + } + } + + uint8_t output = bit_lib_crc8(manchester, 9, 0x31, 0x00, true, true, 0x06); + + return output; +} + void protocol_paradox_render_data(ProtocolParadox* protocol, FuriString* result) { uint8_t* decoded_data = protocol->data; uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8); uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16); + uint8_t card_crc = bit_lib_get_bits_16(decoded_data, 34, 8); + uint8_t calc_crc = protocol_paradox_calculate_checksum(fc, card_id); furi_string_cat_printf(result, "Facility: %u\r\n", fc); furi_string_cat_printf(result, "Card: %u\r\n", card_id); - furi_string_cat_printf(result, "Data: "); - for(size_t i = 0; i < PARADOX_DECODED_DATA_SIZE; i++) { - furi_string_cat_printf(result, "%02X", decoded_data[i]); - } + furi_string_cat_printf(result, "CRC: %u Calc CRC: %u\r\n", card_crc, calc_crc); + if(card_crc != calc_crc) furi_string_cat_printf(result, "CRC Mismatch, Invalid Card!\r\n"); }; void protocol_paradox_render_brief_data(ProtocolParadox* protocol, FuriString* result) { @@ -154,8 +182,15 @@ void protocol_paradox_render_brief_data(ProtocolParadox* protocol, FuriString* r uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8); uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16); + uint8_t card_crc = bit_lib_get_bits_16(decoded_data, 34, 8); + uint8_t calc_crc = protocol_paradox_calculate_checksum(fc, card_id); - furi_string_cat_printf(result, "FC: %03u, Card: %05u", fc, card_id); + furi_string_cat_printf(result, "FC: %03u, Card: %05u\r\n", fc, card_id); + if(calc_crc == card_crc) { + furi_string_cat_printf(result, "CRC : %03u", card_crc); + } else { + furi_string_cat_printf(result, "Card is Invalid!"); + } }; bool protocol_paradox_write_data(ProtocolParadox* protocol, void* data) { From b1496ee9bd97ff8c34a67a49ec4ecdc6cfbd9436 Mon Sep 17 00:00:00 2001 From: Milk-Cool <43724263+Milk-Cool@users.noreply.github.com> Date: Mon, 30 Jan 2023 10:54:15 +0300 Subject: [PATCH 13/17] Furi: getter for current thread stdout write callback (#2344) --- firmware/targets/f7/api_symbols.csv | 5 +++-- furi/core/thread.c | 6 ++++++ furi/core/thread.h | 6 ++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index a75e88bad..7b247daed 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,11.8,, +Version,+,11.9,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1389,8 +1389,8 @@ Function,+,furi_hal_version_uid_size,size_t, Function,-,furi_hal_vibro_init,void, Function,+,furi_hal_vibro_on,void,_Bool Function,-,furi_init,void, -Function,+,furi_kernel_is_irq_or_masked,_Bool, Function,+,furi_kernel_get_tick_frequency,uint32_t, +Function,+,furi_kernel_is_irq_or_masked,_Bool, Function,+,furi_kernel_lock,int32_t, Function,+,furi_kernel_restore_lock,int32_t,int32_t Function,+,furi_kernel_unlock,int32_t, @@ -1515,6 +1515,7 @@ Function,+,furi_thread_get_name,const char*,FuriThreadId Function,+,furi_thread_get_return_code,int32_t,FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* +Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, Function,+,furi_thread_is_suspended,_Bool,FuriThreadId Function,+,furi_thread_join,_Bool,FuriThread* Function,+,furi_thread_mark_as_service,void,FuriThread* diff --git a/furi/core/thread.c b/furi/core/thread.c index c966dd572..ef9560b4a 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -530,6 +530,12 @@ bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { return true; } +FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() { + FuriThread* thread = furi_thread_get_current(); + + return thread->output.write_callback; +} + size_t furi_thread_stdout_write(const char* data, size_t size) { FuriThread* thread = furi_thread_get_current(); diff --git a/furi/core/thread.h b/furi/core/thread.h index c2f5a9130..1542d5bf0 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -227,6 +227,12 @@ const char* furi_thread_get_name(FuriThreadId thread_id); uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); +/** Get STDOUT callback for thead + * + * @return STDOUT callback + */ +FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(); + /** Set STDOUT callback for thread * * @param callback callback or NULL to clear From 5db7fdf9852ec4a412765e265cd10d39c02305b7 Mon Sep 17 00:00:00 2001 From: Noam Drong Date: Mon, 30 Jan 2023 09:03:10 +0100 Subject: [PATCH 14/17] Add support for `GUI-CTRL` in bad_usb (#2315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/main/bad_usb/bad_usb_script.c | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/main/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c index bbd721ed2..e2281133f 100644 --- a/applications/main/bad_usb/bad_usb_script.c +++ b/applications/main/bad_usb/bad_usb_script.c @@ -50,6 +50,7 @@ static const DuckyKey ducky_keys[] = { {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, + {"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL}, {"CTRL", KEY_MOD_LEFT_CTRL}, {"CONTROL", KEY_MOD_LEFT_CTRL}, From 7f3ebcd110e57193d903fed588920402952b0d0d Mon Sep 17 00:00:00 2001 From: Konstantin Volkov <72250702+doomwastaken@users.noreply.github.com> Date: Mon, 30 Jan 2023 15:59:45 +0700 Subject: [PATCH 15/17] Changed bench target, stlink serial and added error for testing the run (#2275) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * changed bench target, stlink serial and added error for testing the run * changed flipper name for macos and changed serial aquisition for device manager * tested broken pipeline, reverting test data * added timeout-minutes, testing if its int or float Co-authored-by: Konstantin Volkov Co-authored-by: あく --- .github/workflows/unit_tests.yml | 1 + .github/workflows/updater_test.yml | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index ac3fc3684..7e625229a 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -56,6 +56,7 @@ jobs: - name: 'Run units and validate results' id: run_units if: steps.copy.outcome == 'success' + timeout-minutes: 2.5 run: | source scripts/toolchain/fbtenv.sh python3 scripts/testing/units.py ${{steps.device.outputs.flipper}} diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index d4ca56fad..0b02920fa 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -10,7 +10,7 @@ env: jobs: test_updater_on_bench: - runs-on: [self-hosted, FlipperZeroTest] # currently on same bench as units, needs different bench + runs-on: [self-hosted, FlipperZeroTestMac1] steps: - name: 'Decontaminate previous build leftovers' run: | @@ -27,7 +27,8 @@ jobs: - name: 'Get flipper from device manager (mock)' id: device run: | - echo "flipper=/dev/ttyACM0" >> $GITHUB_OUTPUT + echo "flipper=/dev/tty.usbmodemflip_Rekigyn1" >> $GITHUB_OUTPUT + echo "stlink=0F020D026415303030303032" >> $GITHUB_OUTPUT - name: 'Flashing target firmware' id: first_full_flash @@ -67,7 +68,7 @@ jobs: - name: 'Flash last release' if: failure() run: | - ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FORCE=1 + ./fbt flash OPENOCD_ADAPTER_SERIAL=${{steps.device.outputs.stlink}} FORCE=1 - name: 'Wait for flipper and format ext' if: failure() From d9be81588955812942c13eda2d58864fc282b4e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= Date: Mon, 30 Jan 2023 10:14:30 +0100 Subject: [PATCH 16/17] Print card CID in storage info (#2227) --- applications/services/storage/storage_cli.c | 16 +++++++- .../scenes/storage_settings_scene_sd_info.c | 19 +++++++-- firmware/targets/f7/fatfs/stm32_adafruit_sd.c | 41 ++++++++++--------- firmware/targets/f7/fatfs/stm32_adafruit_sd.h | 21 +++++----- 4 files changed, 62 insertions(+), 35 deletions(-) diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index c83f16499..eeaa7fce8 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -60,17 +61,28 @@ static void storage_cli_info(Cli* cli, FuriString* path) { } } else if(furi_string_cmp_str(path, STORAGE_EXT_PATH_PREFIX) == 0) { SDInfo sd_info; + SD_CID sd_cid; FS_Error error = storage_sd_info(api, &sd_info); + BSP_SD_GetCIDRegister(&sd_cid); if(error != FSE_OK) { storage_cli_print_error(error); } else { printf( - "Label: %s\r\nType: %s\r\n%luKiB total\r\n%luKiB free\r\n", + "Label: %s\r\nType: %s\r\n%luKiB total\r\n%luKiB free\r\n" + "%02x%2.2s %5.5s %i.%i\r\nSN:%04lx %02i/%i\r\n", sd_info.label, sd_api_get_fs_type_text(sd_info.fs_type), sd_info.kb_total, - sd_info.kb_free); + sd_info.kb_free, + sd_cid.ManufacturerID, + sd_cid.OEM_AppliID, + sd_cid.ProdName, + sd_cid.ProdRev >> 4, + sd_cid.ProdRev & 0xf, + sd_cid.ProdSN, + sd_cid.ManufactMonth, + sd_cid.ManufactYear + 2000); } } else { storage_cli_print_usage(); diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c index 0c398ed5b..a7991bc19 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c @@ -1,4 +1,5 @@ #include "../storage_settings.h" +#include static void storage_settings_scene_sd_info_dialog_callback(DialogExResult result, void* context) { StorageSettings* app = context; @@ -11,7 +12,10 @@ void storage_settings_scene_sd_info_on_enter(void* context) { DialogEx* dialog_ex = app->dialog_ex; SDInfo sd_info; + SD_CID sd_cid; FS_Error sd_status = storage_sd_info(app->fs_api, &sd_info); + BSP_SD_GetCIDRegister(&sd_cid); + scene_manager_set_scene_state(app->scene_manager, StorageSettingsSDInfo, sd_status); dialog_ex_set_context(dialog_ex, app); @@ -26,13 +30,22 @@ void storage_settings_scene_sd_info_on_enter(void* context) { } else { furi_string_printf( app->text_string, - "Label: %s\nType: %s\n%lu KiB total\n%lu KiB free", + "Label: %s\nType: %s\n%lu KiB total\n%lu KiB free\n" + "%02X%2.2s %5.5s %i.%i\nSN:%04lX %02i/%i", sd_info.label, sd_api_get_fs_type_text(sd_info.fs_type), sd_info.kb_total, - sd_info.kb_free); + sd_info.kb_free, + sd_cid.ManufacturerID, + sd_cid.OEM_AppliID, + sd_cid.ProdName, + sd_cid.ProdRev >> 4, + sd_cid.ProdRev & 0xf, + sd_cid.ProdSN, + sd_cid.ManufactMonth, + sd_cid.ManufactYear + 2000); dialog_ex_set_text( - dialog_ex, furi_string_get_cstr(app->text_string), 4, 4, AlignLeft, AlignTop); + dialog_ex, furi_string_get_cstr(app->text_string), 4, 1, AlignLeft, AlignTop); } view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx); diff --git a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c index b9b65f06a..998adee29 100644 --- a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c +++ b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c @@ -779,25 +779,10 @@ uint8_t SD_GetCIDRegister(SD_CID* Cid) { Cid->ManufacturerID = CID_Tab[0]; /* Byte 1 */ - Cid->OEM_AppliID = CID_Tab[1] << 8; - - /* Byte 2 */ - Cid->OEM_AppliID |= CID_Tab[2]; + memcpy(Cid->OEM_AppliID, CID_Tab + 1, 2); /* Byte 3 */ - Cid->ProdName1 = CID_Tab[3] << 24; - - /* Byte 4 */ - Cid->ProdName1 |= CID_Tab[4] << 16; - - /* Byte 5 */ - Cid->ProdName1 |= CID_Tab[5] << 8; - - /* Byte 6 */ - Cid->ProdName1 |= CID_Tab[6]; - - /* Byte 7 */ - Cid->ProdName2 = CID_Tab[7]; + memcpy(Cid->ProdName, CID_Tab + 3, 5); /* Byte 8 */ Cid->ProdRev = CID_Tab[8]; @@ -815,11 +800,12 @@ uint8_t SD_GetCIDRegister(SD_CID* Cid) { Cid->ProdSN |= CID_Tab[12]; /* Byte 13 */ - Cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4; - Cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8; + Cid->Reserved1 = (CID_Tab[13] & 0xF0) >> 4; + Cid->ManufactYear = (CID_Tab[13] & 0x0F) << 4; /* Byte 14 */ - Cid->ManufactDate |= CID_Tab[14]; + Cid->ManufactYear |= (CID_Tab[14] & 0xF0) >> 4; + Cid->ManufactMonth = (CID_Tab[14] & 0x0F); /* Byte 15 */ Cid->CID_CRC = (CID_Tab[15] & 0xFE) >> 1; @@ -837,6 +823,21 @@ uint8_t SD_GetCIDRegister(SD_CID* Cid) { return retr; } +uint8_t BSP_SD_GetCIDRegister(SD_CID* Cid) { + uint8_t retr = BSP_SD_ERROR; + + /* Slow speed init */ + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_slow); + furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_slow; + + memset(Cid, 0, sizeof(SD_CID)); + retr = SD_GetCIDRegister(Cid); + + furi_hal_sd_spi_handle = NULL; + furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); + return retr; +} + /** * @brief Sends 5 bytes command to the SD card and get response * @param Cmd: The user expected command to send to SD card. diff --git a/firmware/targets/f7/fatfs/stm32_adafruit_sd.h b/firmware/targets/f7/fatfs/stm32_adafruit_sd.h index e0c5e3bef..a133c5922 100644 --- a/firmware/targets/f7/fatfs/stm32_adafruit_sd.h +++ b/firmware/targets/f7/fatfs/stm32_adafruit_sd.h @@ -133,16 +133,16 @@ typedef struct { * @brief Card Identification Data: CID Register */ typedef struct { - __IO uint8_t ManufacturerID; /* ManufacturerID */ - __IO uint16_t OEM_AppliID; /* OEM/Application ID */ - __IO uint32_t ProdName1; /* Product Name part1 */ - __IO uint8_t ProdName2; /* Product Name part2*/ - __IO uint8_t ProdRev; /* Product Revision */ - __IO uint32_t ProdSN; /* Product Serial Number */ - __IO uint8_t Reserved1; /* Reserved1 */ - __IO uint16_t ManufactDate; /* Manufacturing Date */ - __IO uint8_t CID_CRC; /* CID CRC */ - __IO uint8_t Reserved2; /* always 1 */ + uint8_t ManufacturerID; /* ManufacturerID */ + char OEM_AppliID[2]; /* OEM/Application ID */ + char ProdName[5]; /* Product Name */ + uint8_t ProdRev; /* Product Revision */ + uint32_t ProdSN; /* Product Serial Number */ + uint8_t Reserved1; /* Reserved1 */ + uint8_t ManufactYear; /* Manufacturing Year */ + uint8_t ManufactMonth; /* Manufacturing Month */ + uint8_t CID_CRC; /* CID CRC */ + uint8_t Reserved2; /* always 1 */ } SD_CID; /** @@ -207,6 +207,7 @@ uint8_t uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); uint8_t BSP_SD_GetCardState(void); uint8_t BSP_SD_GetCardInfo(SD_CardInfo* pCardInfo); +uint8_t BSP_SD_GetCIDRegister(SD_CID* Cid); /* Link functions for SD Card peripheral*/ void SD_SPI_Slow_Init(void); From 01a9854f8af8898a9a1138f1e1f496ff74b51b8d Mon Sep 17 00:00:00 2001 From: Giacomo Ferretti Date: Mon, 30 Jan 2023 10:49:51 +0100 Subject: [PATCH 17/17] Documentation: add BadUSB GUI-CTRL #2347 --- documentation/file_formats/BadUsbScriptFormat.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/file_formats/BadUsbScriptFormat.md b/documentation/file_formats/BadUsbScriptFormat.md index fa5038742..2ef1d3135 100644 --- a/documentation/file_formats/BadUsbScriptFormat.md +++ b/documentation/file_formats/BadUsbScriptFormat.md @@ -67,6 +67,7 @@ Can be combined with a special key command or a single character. |ALT-SHIFT|ALT+SHIFT| |ALT-GUI|ALT+WIN| |GUI-SHIFT|WIN+SHIFT| +|GUI-CTRL|WIN+CTRL| ## String