From 0ef9f7d308e093f3dc45df79202c73c150756957 Mon Sep 17 00:00:00 2001 From: Ruslan Nadyrshin <110516632+rnadyrshin@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:58:13 +0400 Subject: [PATCH 01/22] JS packages folder included to the doxygen's exclude list (#4021) --- documentation/doxygen/Doxyfile.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/doxygen/Doxyfile.cfg b/documentation/doxygen/Doxyfile.cfg index e016317494f..3df12f08f0a 100644 --- a/documentation/doxygen/Doxyfile.cfg +++ b/documentation/doxygen/Doxyfile.cfg @@ -1042,6 +1042,7 @@ EXCLUDE = $(DOXY_SRC_ROOT)/lib/mlib \ $(DOXY_SRC_ROOT)/applications/plugins/dap_link/lib/free-dap \ $(DOXY_SRC_ROOT)/applications/debug \ $(DOXY_SRC_ROOT)/applications/main \ + $(DOXY_SRC_ROOT)/applications/system/js_app/packages \ $(DOXY_SRC_ROOT)/applications/settings \ $(DOXY_SRC_ROOT)/lib/micro-ecc \ $(DOXY_SRC_ROOT)/lib/ReadMe.md \ From 399bcdcc13765cff4701eb8ddb2dbeddcb5ba59f Mon Sep 17 00:00:00 2001 From: Nicolas Marie-Magdelaine PhD Date: Mon, 2 Dec 2024 08:15:29 +0100 Subject: [PATCH 02/22] Add IR command for NAD DR2 D7050 D3020 (#4020) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../resources/infrared/assets/audio.ir | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/applications/main/infrared/resources/infrared/assets/audio.ir b/applications/main/infrared/resources/infrared/assets/audio.ir index 20070bbe06e..efd0382e3af 100644 --- a/applications/main/infrared/resources/infrared/assets/audio.ir +++ b/applications/main/infrared/resources/infrared/assets/audio.ir @@ -4650,3 +4650,42 @@ type: parsed protocol: NECext address: 7F 01 00 00 command: 69 96 00 00 +# +# Model : NAD DR2 remote for NAD D7050 and D3020 +# +name: Power +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 25 DA 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 88 77 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 8C 73 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 94 6B 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 1A E5 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 1D E2 00 00 +# From c3dc9e1ec2aa785f346d979e906ecef82dc2ab74 Mon Sep 17 00:00:00 2001 From: Luu <112649910+luu176@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:27:16 +0100 Subject: [PATCH 03/22] Fix typo for mf_classic_key_cahce_get_next_key() function (#4015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update mf_classic_key_cache.c * Update mf_classic_key_cache.h * Update mf_classic.c * Update nfc_scene_mf_classic_update_initial.c Co-authored-by: あく --- applications/main/nfc/helpers/mf_classic_key_cache.c | 2 +- applications/main/nfc/helpers/mf_classic_key_cache.h | 2 +- .../main/nfc/helpers/protocol_support/mf_classic/mf_classic.c | 2 +- .../main/nfc/scenes/nfc_scene_mf_classic_update_initial.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/main/nfc/helpers/mf_classic_key_cache.c b/applications/main/nfc/helpers/mf_classic_key_cache.c index 1b945660c0a..763c4dea7e3 100644 --- a/applications/main/nfc/helpers/mf_classic_key_cache.c +++ b/applications/main/nfc/helpers/mf_classic_key_cache.c @@ -166,7 +166,7 @@ void mf_classic_key_cache_load_from_data(MfClassicKeyCache* instance, const MfCl } } -bool mf_classic_key_cahce_get_next_key( +bool mf_classic_key_cache_get_next_key( MfClassicKeyCache* instance, uint8_t* sector_num, MfClassicKey* key, diff --git a/applications/main/nfc/helpers/mf_classic_key_cache.h b/applications/main/nfc/helpers/mf_classic_key_cache.h index b09f4526bab..50a1f5c30f6 100644 --- a/applications/main/nfc/helpers/mf_classic_key_cache.h +++ b/applications/main/nfc/helpers/mf_classic_key_cache.h @@ -16,7 +16,7 @@ bool mf_classic_key_cache_load(MfClassicKeyCache* instance, const uint8_t* uid, void mf_classic_key_cache_load_from_data(MfClassicKeyCache* instance, const MfClassicData* data); -bool mf_classic_key_cahce_get_next_key( +bool mf_classic_key_cache_get_next_key( MfClassicKeyCache* instance, uint8_t* sector_num, MfClassicKey* key, diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index 4fece16be5a..6f7be7f4c45 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -72,7 +72,7 @@ static NfcCommand nfc_scene_read_poller_callback_mf_classic(NfcGenericEvent even uint8_t sector_num = 0; MfClassicKey key = {}; MfClassicKeyType key_type = MfClassicKeyTypeA; - if(mf_classic_key_cahce_get_next_key( + if(mf_classic_key_cache_get_next_key( instance->mfc_key_cache, §or_num, &key, &key_type)) { mfc_event->data->read_sector_request_data.sector_num = sector_num; mfc_event->data->read_sector_request_data.key = key; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c index 7c76260b4fa..a477a08b925 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c @@ -34,7 +34,7 @@ NfcCommand nfc_mf_classic_update_initial_worker_callback(NfcGenericEvent event, uint8_t sector_num = 0; MfClassicKey key = {}; MfClassicKeyType key_type = MfClassicKeyTypeA; - if(mf_classic_key_cahce_get_next_key( + if(mf_classic_key_cache_get_next_key( instance->mfc_key_cache, §or_num, &key, &key_type)) { mfc_event->data->read_sector_request_data.sector_num = sector_num; mfc_event->data->read_sector_request_data.key = key; From 2f30817dc9a052a9d033b53c6f32de6b67d74b0c Mon Sep 17 00:00:00 2001 From: WillyJL <49810075+Willy-JL@users.noreply.github.com> Date: Mon, 2 Dec 2024 07:54:50 +0000 Subject: [PATCH 04/22] Settings: More granularity for LCD and Notification (#4010) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../notification_settings_app.c | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index ada2bfdd42c..2462b32bdeb 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -20,8 +20,11 @@ static const NotificationSequence sequence_note_c = { NULL, }; -#define CONTRAST_COUNT 11 +#define CONTRAST_COUNT 17 const char* const contrast_text[CONTRAST_COUNT] = { + "-8", + "-7", + "-6", "-5", "-4", "-3", @@ -33,8 +36,14 @@ const char* const contrast_text[CONTRAST_COUNT] = { "+3", "+4", "+5", + "+6", + "+7", + "+8", }; const int32_t contrast_value[CONTRAST_COUNT] = { + -8, + -7, + -6, -5, -4, -3, @@ -46,44 +55,47 @@ const int32_t contrast_value[CONTRAST_COUNT] = { 3, 4, 5, + 6, + 7, + 8, }; -#define BACKLIGHT_COUNT 5 +#define BACKLIGHT_COUNT 21 const char* const backlight_text[BACKLIGHT_COUNT] = { - "0%", - "25%", - "50%", - "75%", - "100%", + "0%", "5%", "10%", "15%", "20%", "25%", "30%", "35%", "40%", "45%", "50%", + "55%", "60%", "65%", "70%", "75%", "80%", "85%", "90%", "95%", "100%", }; const float backlight_value[BACKLIGHT_COUNT] = { - 0.0f, - 0.25f, - 0.5f, - 0.75f, - 1.0f, + 0.00f, 0.05f, 0.10f, 0.15f, 0.20f, 0.25f, 0.30f, 0.35f, 0.40f, 0.45f, 0.50f, + 0.55f, 0.60f, 0.65f, 0.70f, 0.75f, 0.80f, 0.85f, 0.90f, 0.95f, 1.00f, }; -#define VOLUME_COUNT 5 +#define VOLUME_COUNT 21 const char* const volume_text[VOLUME_COUNT] = { - "0%", - "25%", - "50%", - "75%", - "100%", + "0%", "5%", "10%", "15%", "20%", "25%", "30%", "35%", "40%", "45%", "50%", + "55%", "60%", "65%", "70%", "75%", "80%", "85%", "90%", "95%", "100%", +}; +const float volume_value[VOLUME_COUNT] = { + 0.00f, 0.05f, 0.10f, 0.15f, 0.20f, 0.25f, 0.30f, 0.35f, 0.40f, 0.45f, 0.50f, + 0.55f, 0.60f, 0.65f, 0.70f, 0.75f, 0.80f, 0.85f, 0.90f, 0.95f, 1.00f, }; -const float volume_value[VOLUME_COUNT] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f}; -#define DELAY_COUNT 6 +#define DELAY_COUNT 11 const char* const delay_text[DELAY_COUNT] = { "1s", "5s", + "10s", "15s", "30s", "60s", + "90s", "120s", + "5min", + "10min", + "30min", }; -const uint32_t delay_value[DELAY_COUNT] = {1000, 5000, 15000, 30000, 60000, 120000}; +const uint32_t delay_value[DELAY_COUNT] = + {1000, 5000, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000, 1800000}; #define VIBRO_COUNT 2 const char* const vibro_text[VIBRO_COUNT] = { From 8629c61dc91f843577d9214b4a60b9b607fe1914 Mon Sep 17 00:00:00 2001 From: mxcdoam <72457810+mxcdoam@users.noreply.github.com> Date: Mon, 2 Dec 2024 11:08:17 +0300 Subject: [PATCH 05/22] NFC: Plantain parser Last payment amount fix (#3998) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../main/nfc/plugins/supported_cards/plantain.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/plantain.c b/applications/main/nfc/plugins/supported_cards/plantain.c index 9f2491691be..49bbaebe8ec 100644 --- a/applications/main/nfc/plugins/supported_cards/plantain.c +++ b/applications/main/nfc/plugins/supported_cards/plantain.c @@ -310,9 +310,11 @@ static bool plantain_parse(const NfcDevice* device, FuriString* parsed_data) { last_payment_date.year, last_payment_date.hour, last_payment_date.minute); - //payment amount. This needs to be investigated more, currently it shows incorrect amount on some cards. - uint16_t last_payment = (data->block[18].data[9] << 8) | data->block[18].data[8]; - furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment / 100); + //Last payment amount. + uint16_t last_payment = ((data->block[18].data[10] << 16) | + (data->block[18].data[9] << 8) | (data->block[18].data[8])) / + 100; + furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment); furi_string_free(card_number_s); furi_string_free(tmp_s); //This is for 4K Plantains. @@ -369,9 +371,11 @@ static bool plantain_parse(const NfcDevice* device, FuriString* parsed_data) { last_payment_date.year, last_payment_date.hour, last_payment_date.minute); - //payment amount - uint16_t last_payment = (data->block[18].data[9] << 8) | data->block[18].data[8]; - furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment / 100); + //Last payment amount + uint16_t last_payment = ((data->block[18].data[10] << 16) | + (data->block[18].data[9] << 8) | (data->block[18].data[8])) / + 100; + furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment); furi_string_free(card_number_s); furi_string_free(tmp_s); } From 3d6fd9b00d216f744a69472341e1bca89fa7a83c Mon Sep 17 00:00:00 2001 From: ted-logan Date: Mon, 2 Dec 2024 01:51:57 -0800 Subject: [PATCH 06/22] nfc/clipper: (#3991) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfs/clipper: BART station ids for San Lorenzo, Bay Fair Update the BART station ids for the San Lorenzo and Bay Fair stations in the East Bay of the San Francisco Bay Area. * nfc/clipper: Update MUNI station ids Add MUNI station ids for the T line "Central Subway" project, which opened three new underground stations in 2022. --------- Co-authored-by: あく --- applications/main/nfc/plugins/supported_cards/clipper.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/plugins/supported_cards/clipper.c b/applications/main/nfc/plugins/supported_cards/clipper.c index 3eba82425d1..eb459d41951 100644 --- a/applications/main/nfc/plugins/supported_cards/clipper.c +++ b/applications/main/nfc/plugins/supported_cards/clipper.c @@ -101,7 +101,8 @@ static const IdMapping bart_zones[] = { {.id = 0x001d, .name = "Lake Merrit"}, {.id = 0x001e, .name = "Fruitvale"}, {.id = 0x001f, .name = "Coliseum"}, - {.id = 0x0021, .name = "San Leandro"}, + {.id = 0x0020, .name = "San Leandro"}, + {.id = 0x0021, .name = "Bay Fair"}, {.id = 0x0022, .name = "Hayward"}, {.id = 0x0023, .name = "South Hayward"}, {.id = 0x0024, .name = "Union City"}, @@ -131,6 +132,9 @@ static const IdMapping muni_zones[] = { {.id = 0x000b, .name = "Castro"}, {.id = 0x000c, .name = "Forest Hill"}, // Guessed {.id = 0x000d, .name = "West Portal"}, + {.id = 0x0019, .name = "Union Square/Market Street"}, + {.id = 0x001a, .name = "Chinatown - Rose Pak"}, + {.id = 0x001b, .name = "Yerba Buena/Moscone"}, }; static const size_t kNumMUNIZones = COUNT(muni_zones); From 7d5358b9d3b0d6493a8be3d0e76dfd58de913493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 3 Dec 2024 07:30:25 +0100 Subject: [PATCH 07/22] Replace mf_classic_dict.nfc with Proxmark3 version (#4013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../resources/nfc/assets/mf_classic_dict.nfc | 3578 ++++++++++++----- 1 file changed, 2489 insertions(+), 1089 deletions(-) diff --git a/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc b/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc index e2b74f8475d..0a3de18af2c 100644 --- a/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc +++ b/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc @@ -1,538 +1,1010 @@ -# Key dictionary from https://github.com/ikarus23/MifareClassicTool.git - -# More well known keys! -# Standard keys +# Key dictionary from https://github.com/RfidResearchGroup/proxmark3/ +# +# Mifare Default Keys +# -- iceman fork version -- +# -- contribute to this list, sharing is caring -- +# +# Default key FFFFFFFFFFFF -A0A1A2A3A4A5 -D3F7D3F7D3F7 +# +# Blank key 000000000000 - -# Keys from mfoc +# +# NFC Forum MADkey +A0A1A2A3A4A5 +# +# MAD access key A (reversed) +A5A4A3A2A1A0 +# +# MAD access key B +89ECA97F8C2A +# +# Mifare 1k EV1 (S50) hidden blocks, Signature data +# 16 A +5C8FF9990DA2 +# +# 17 A +75CCB59C9BED +# +# 16 B +D01AFEEB890A +# +# 17 B +4B791BEA7BCC +# +# QL88 keys +# 17 A/B +2612C6DE84CA +707B11FC1481 +# +# QL88 diversifed +03F9067646AE +2352C5B56D85 +# B0B1B2B3B4B5 +C0C1C2C3C4C5 +D0D1D2D3D4D5 +AABBCCDDEEFF 4D3A99C351DD 1A982C7E459A -AABBCCDDEEFF +# +# key A Wien +D3F7D3F7D3F7 +# +# key B Wien +5A1B85FCE20A +# +# 714C5C886E97 587EE5F9350F A0478CC39091 533CB6C723F6 8FD0A4F256E9 - -# Keys from: -# http://pastebin.com/wcTHXLZZ -A64598A77478 -26940B21FF5D +# +# iCopy-X +E00000000000 +# +# +E7D6064C5860 +B27CCAB30DBD +# +# lib / Nat Bieb +D2ECE8B9395E +# NSCP default key +1494E81663D7 +# +# NFC tools +7c9fb8474242 +# +# Kiev keys +569369C5A0E5 +632193BE1C3C +644672BD4AFE +8FE644038790 +9DE89E070277 +B5FF67CBA951 +EFF603E1EFE9 +F14EE7CAE863 +# +# ICT S14 A/B +9C28A60F7249 +C9826AF02794 +# +# RKF +# Västtrafiken KeyA, RKF ÖstgötaTrafiken KeyA FC00018778F7 +# +# Västtrafiken KeyA +0297927C0F77 +54726176656C +# +# Västtrafiken KeyB 00000FFE2488 +776974687573 +EE0042F88840 +# +# RKF SLKeyA +26940B21FF5D +A64598A77478 +# +# RKF SLKeyB 5C598C9C58B5 E4D2770A89BE - -# Keys from: -# http://pastebin.com/svGjN30Q -434F4D4D4F41 -434F4D4D4F42 -47524F555041 -47524F555042 -505249564141 -505249564142 - -# Keys from: -# http://pastebin.com/d7sSetef -0297927C0F77 -EE0042F88840 +# +# RKF Rejskort Danmark KeyA 722BFCC5375F +# +# RKF Rejskort Danmark KeyB F1D83F964314 - -# Keys from: -# http://pastebin.com/pvJX0xVS -54726176656C -776974687573 -4AF9D7ADEBE4 -2BA9621E0A36 - -# Keys from: -# http://pastebin.com/y3PDBWR1 +# +# RKF JOJOPRIVA KeyA +505249564141 +# +# RKF JOJOPRIVA KeyB +505249564142 +# +# RKF JOJOGROUP KeyA +47524F555041 +434F4D4D4F41 +# +# RKF JOJOGROUP KeyB +47524F555042 +434F4D4D4F42 +# +# TNP3xxx +4B0B20107CCB +# +# Access control system +605F5E5D5C5B +# +# NSP Global keys A and B (uk housing access control) +199404281970 +199404281998 +# +# Data from http://www.proxmark.org/forum/viewtopic.php?pid=25925#p25925 +# Tengo Cards Key A +FFF011223358 +FF9F11223358 +# +# Elevator system Kherson, Ukraine +AC37E76385F5 +576DCFFF2F25 +# +# Car wash system +1EE38419EF39 +26578719DCD9 +# +# more Keys from mfc_default_keys.lua 000000000001 +000000000002 +00000000000A +00000000000B +010203040506 +0123456789AB +100000000000 +111111111111 123456789ABC -B127C6F41436 12F2EE3478C1 -34D1DF9934C5 -55F5A5DD38C9 -F1A97341A9FC -33F974B42769 14D446E33363 -C934FE34D934 1999A3554A55 +200000000000 +222222222222 27DD91F1FCF1 -A94133013401 -99C636334433 +# +# Hotel system +505209016A1F +# +# Directory and eventlog KeyB +2BA9621E0A36 +# +# Directory and eventlog KeyA +4AF9D7ADEBE4 +# +# +333333333333 +33F974B42769 +34D1DF9934C5 43AB19EF5C31 -A053A292A4AF +444444444444 505249565441 505249565442 - -# Keys from: -# http://pastebin.com/TUXj17K3 -FC0001877BF7 - -# Keys from: -# http://0x9000.blogspot.com/2010/12/mifare-classic-default-keys.html -A0B0C0D0E0F0 -A1B1C1D1E1F1 - -# Keys from: -# https://code.google.com/p/mifare-key-cracker/downloads/list -BD493A3962B6 -010203040506 -111111111111 -222222222222 -333333333333 -444444444444 555555555555 +55F5A5DD38C9 666666666666 777777777777 888888888888 999999999999 +99C636334433 +A00000000000 +A053A292A4AF +A94133013401 AAAAAAAAAAAA +# +# Key from ladyada.net +ABCDEF123456 +# +# +B00000000000 +B127C6F41436 BBBBBBBBBBBB +BD493A3962B6 +C934FE34D934 CCCCCCCCCCCC DDDDDDDDDDDD EEEEEEEEEEEE -0123456789AB - -# Keys from: -# https://github.com/4ZM/mfterm/blob/master/dictionary.txt -000000000002 -00000000000A -00000000000B -100000000000 -200000000000 -A00000000000 -B00000000000 - -# Key from: -# ladyada.net -ABCDEF123456 - -# Key from: -# http://irq5.io/2013/04/13/decoding-bcard-conference-badges/ -F4A9EF2AFC6D - -# Keys from: -# https://github.com/iceman1001/proxmark -4B0B20107CCB -569369C5A0E5 -632193BE1C3C -644672BD4AFE -8FE644038790 -9DE89E070277 -B5FF67CBA951 -EFF603E1EFE9 -F14EE7CAE863 +# +# elevator +# data from forum +FFFFFF545846 +# +# +F1A97341A9FC +# +# hotel system 44AB09010845 85FED980EA5A -314B49474956 -564C505F4D41 -0263DE1278F3 -067DB45454A9 -15FC4C7613FE -16F21A82EC84 -16F3D5AB1139 -17758856B182 +# +# ARD (fr) key A +43454952534E +# ARD (fr) key B +4A2B29111213 +# +# +4143414F5250 +# +# Tehran Railway +A9B43414F585 +1FB235AC1388 +# +# Data from http://irq5.io/2013/04/13/decoding-bcard-conference-badges/ +# BCARD KeyB +F4A9EF2AFC6D +# +# +# S0 B +89EAC97F8C2A +# +# S4 A +43C7600DEE6B +# +# S6 A +0120BF672A64 +# +# S6 B +FB0B20DF1F34 +# +# +A9F953DEF0A3 +# +# Data from forum +74A386AD0A6D +3F7A5C2DBD81 +21EDF95E7433 +C121FF19F681 +3D5D9996359A +# +# Here be BIP keys... +3A42F33AF429 1FC235AC1309 -22C1BAE1AACD +6338A371C0ED 243F160918D1 -25094DF6F148 -2A3C347A1200 -324F5DF65310 +F124C2578AD0 +9AFC42372AF1 32AC3B90AC13 +682D401ABB09 +4AD1E273EAF1 +067DB45454A9 +E2C42591368A +15FC4C7613FE +2A3C347A1200 +68D30288910A +16F3D5AB1139 +F59A36A2546D +937A4FFF3011 +64E3C10394C2 35C3D2CAEE88 -3A42F33AF429 +B736412614AF +693143F10368 +324F5DF65310 +A3F97428DD01 +643FB6DE2217 +63F17A449AF0 +82F435DEDF01 +C4652C54261C +0263DE1278F3 +D49E2826664F +51284C3686A6 3DF14C8000A1 -3E3554AF0E12 +6A470D54127C +# +# Data from http://pastebin.com/AK9Bftpw +# Länstrafiken i Västerbotten +48FFE71294A0 +E3429281EFC1 +16F21A82EC84 +460722122510 +# +# 3dprinter +# EPI Envisionte +AAFB06045877 +# +# Gyms / Fitness Clubs / Health Clubs / Wellness Centres +# +# Fysiken A 3E65E4FB65B3 +# +# Fysiken B +25094DF6F148 +# +# +# https://mattionline.de/fitnessstudio-armband-reverse-engineering/ +# https://mattionline.de/milazycracker/ +# Gym Wristband A - Same as Fysiken A +# Gym Wristband B +81CC25EBBB6A +195DC63DB3A3 +# +# CleverFit +A05DBD98E0FC +# +# GoFit +AA4DDA458EBB +EAB8066C7479 +# +# Nordic Wellness A - Same as Fysiken A +# Nordic Wellness B +E5519E1CC92B +# +# Jett's 24 Hour Fitness S0 KA/B +# 049979614077 +# 829338771705 +# +# Hotel KeyCard +D3B595E9DD63 +AFBECD121004 +# +# SimonsVoss +6471A5EF2D1A +# +# ID06 +4E3552426B32 +22BDACF5A33F +6E7747394E63 +763958704B78 +# +# Onity S1 A/B +8A19D40CF2B5 +# +3961EA82C46D +# +# 24-7 +D21762B2DE3B +0E83A374B513 +1F1FFE000000 +A10F303FC879 +1322285230B8 +0C71BCFB7E72 +C3C88C6340B8 +F101622750B7 +1F107328DC8D +710732200D34 +7C335FB121B5 +B39AE17435DC +# +# key A 454841585443 -460722122510 -48FFE71294A0 -491CDCFB7752 -4AD1E273EAF1 -4B791BEA7BCC -51284C3686A6 +# +# Lift system +190819842023 +# +# Data from http://pastebin.com/gQ6nk38G +D39BB83F5297 +85675B200017 528C9DFFE28C -5EB8F884C8D1 +C82EC29E3235 +3E3554AF0E12 +491CDCFB7752 +22C1BAE1AACD 5F146716E373 -6338A371C0ED -63F17A449AF0 -643FB6DE2217 -64E3C10394C2 -682D401ABB09 -68D30288910A -693143F10368 -6A470D54127C 740E9A4F9AAF -75CCB59C9BED -75D8690F21B6 -75EDE6A84460 -82F435DEDF01 -85675B200017 -871B8C085997 -937A4FFF3011 +AC0E24C75527 97184D136233 -97D1101F18B0 -9AFC42372AF1 -A27D3804C259 -A3F97428DD01 +E444D53D359F +17758856B182 A8966C7CC54B -A9F953DEF0A3 -AAFB06045877 -AC0E24C75527 -AE3FF4EEA0DB -B0C9DD55DD4D -B736412614AF -C4652C54261C C6AD00254562 -C82EC29E3235 -D39BB83F5297 -D49E2826664F -DF27A8F1CB8E -E2C42591368A -E3429281EFC1 -E444D53D359F -F124C2578AD0 -F59A36A2546D +AE3FF4EEA0DB +5EB8F884C8D1 FEE470A4CB58 -0000000018DE -0000014B5C31 -003003003003 -003CC420001A -013889343891 -01FA3FC68349 -021209197591 -050908080008 -0A7932DC7E65 -0C669993C776 -0C71BCFB7E72 +75D8690F21B6 +871B8C085997 +97D1101F18B0 +75EDE6A84460 +DF27A8F1CB8E +B0C9DD55DD4D +# +# Data from http://bit.ly/1bdSbJl +A0B0C0D0E0F0 +A1B1C1D1E1F1 +# +# Data from msk social +2735FC181807 +2ABA9519F574 +84FD7F7A12B6 +186D8C4B93F9 +3A4BBA8ADAF0 +8765B17968A2 +40EAD80721CE +0DB5E6523F7C +51119DAE5216 +83E3549CE42D +136BDB246CAC +7DE02A7F6025 +BF23A53C1F63 +CB9A1F2D7368 +C7C0ADB3284F +9F131D8C2057 +67362D90F973 +6202A38F69E2 +100533B89331 +653A87594079 +D8A274B2E026 +B20B83CB145C +9AFA6CB4FC3D +A229E68AD9E5 +49C2B5296EF4 +# +# Data from http://pastebin.com/RRJUEDCM 0D258FE90296 -0E83A374B513 -0F230695923F -0FFBF65B5A14 -11428B5BCE06 -11428B5BCE07 -11428B5BCE08 -11428B5BCE09 -11428B5BCE0A -11428B5BCE0F -11496F97752A -123F8888F322 -1322285230B8 -1565A172770F -157B10D84C6B -157C9A513FA5 -15CAFD6159F6 -160A91D29A9C -16551D52FD20 -167A1BE102E0 -16DDCB6B3F24 -1717E34A7A8A +E55A3CA71826 +A4F204203F56 +EEB420209D0C +911E52FD7CE4 +752FBB5B7B45 +66B03ACA6EE9 +48734389EDC3 17193709ADF4 -185FA3438949 -1877ED29435A -18971D893494 -1AB23CD45EF6 1ACC3189578C -1F107328DC8D -1F1A0A111B5B -1F1FFE000000 -2031D1E57A3B -# HID Key B -204752454154 -21A600056CB0 -22729A9BD40F -2338B4913111 -2548A443DF28 -25D60050BF6E -26643965B16E +C2B7EC7D4EB1 +369A4663ACD2 +# +# Data from https://github.com/zhangjingye03/zxcardumper +# zxcard Key A/B +668770666644 +003003003003 +# +# Data from http://phreakerclub.com/forum/showthread.php?p=41266 26973EA74321 -27FBC86A00D0 -2A2C13CC242A -2A6D9205E7CA -2CB1A90071C8 -2DD39A54E1F3 -2ED3B15E7C0F -2EF720F2AF76 -2FC1F32F51B1 +71F3A315AD26 +51044EFB5AAB +AC70CA327A04 +EB0A8FF88ADE +# +# Transport system Metromoney +2803BCB0C7E1 +9C616585E26D +4FA9EB49F75E +2DADE48942C5 +A160FCD5EC4C +112233445566 +361A62F35BC9 +# +# Transport system Spain +83F3CB98C258 +070D486BC555 +A9B018868CC1 +9DCDB136110C +749934CC8ED3 +506DB955F161 +F088A85E71D7 +72B458D60363 +70C714869DC7 +B32464412EE3 +F253C30568C4 +1C68315674AC +CFE63749080A +C1E6F8AFC9EC +DD0DE3BA08A6 +3D923EB73534 +FF94F86B09A6 +D61707FFDFB1 +8223205047B6 +9951A273DEE7 +C9449301AF93 +66695A45C9FA +89AA9D743812 +C41514DEFC07 +C52876869800 +5353B3AECB53 +2E4169A5C79D +4BB747E48C2A +6285A1C8EB5C +5145C34DBA19 +25352912CD8D +81B20C274C3F +00B70875AF1D +04B787B2F3A5 +05412723F1B6 +05C301C8795A +066F5AF3CCEE +0A1B6C50E04E +0AD0956DF6EE +0AD6B7E37183 +0F3A4D48757B +1417E5671417 +18AB07270506 +18E887D625B4 +1ABC15934F5A +1AF66F83F5BE +260480290483 +2900AAC52BC3 +2910AFE15C99 +374521A38BCC +3A4C47757B07 +3A524B7A7B37 +3C4ABB877EAF +3F3A534B7B7B +4B787B273A50 +4B92DF1BF25D +4F0E4AE8051A +514B797B2F3A +529CF51F05C5 +52B26C199862 +57A18BFEC381 +5A7D87876EA8 +64CBADC7A313 +65B6C3200736 +67B1B3A4E497 +6B0454D5D3C3 +6B3B7AF45777 +6C273F431564 +702C1BF025DD +738385948494 +76E450094393 +777B1F3A4F4A +7B173A4E4976 +81504133B13C +826576A1AB68 +8A55194F6587 +8DFACF11E778 +8FD6D76742DC +9AFEE1F65742 +9D56D83658AC +9FAC23197904 +A1AB3A08712C +A514B797B373 +A58AB5619631 +A5BB18152EF1 +A777B233A4F4 +AB19BC885A29 +AB91BDA25F00 +AE98BA1E6F2C +B133A4D48757 +B3A4C47757B0 +B6803136F5AF +B793ADA6DB0C +B95BFDEBA7E4 +C0AA2BBD27CD +C27F5C1A9C2B +C9BE49675FE4 +CCCE24102003 +CDE668FDCDBA +D23A31A4AAB9 +DEDD7688BC38 +E9AE90885C39 +F0A3C5182007 +F3A524B7A7B3 +# +# Data from mall +# playland balikesir +ABBA1234FCB0 +# +# A trio bowling bahcelievler +314F495254FF +4152414B4E41 +# +# karinca park nigde +4E474434FFFF +# +# hotel system +537930363139 +# +# Data from https://github.com/RadioWar/NFCGUI +44DD5A385AAF +21A600056CB0 +B1ACA33180A5 +DD61EB6BCE22 +1565A172770F +3E84D2612E2A +F23442436765 +79674F96C771 +87DF99D496CB +C5132C8980BC +A21680C27773 +F26E21EDCEE2 +675557ECC92E +F4396E468114 +6DB17C16B35B +4186562A5BB2 2FEAE851C199 -3060206F5B0A -31646241686C -321958042333 +DB1A3338B2EB +157B10D84C6B +A643F952EA57 +DF37DCB6AFB3 +4C32BAF326E0 +91CE16C07AC5 +3C5D1C2BCD18 +C3F19EC592A2 +F72A29005459 +185FA3438949 321A695BD266 -340E40F81CD8 -345547514B4D -356D46474348 -369A4663ACD2 -36ABF5874ED7 -374BF468607F +D327083A60A7 +45635EF66EF3 +5481986D2D62 +CBA6AE869AD5 +645A166B1EEB +A7ABBC77CC9E +F792C4C76A5C +BFB6796A11DB +# +# Data from Salto A/B +6A1987C40A21 +7F33625BC129 +6BE9314930D8 +# +# Data from forum +2338B4913111 +# +# Data from stoye +CB779C50E1BD +A27D3804C259 +003CC420001A +F9861526130F 381ECE050FBD -386B4D634A65 -38FCF33072E0 -3A09594C8587 -3B7E4FD575AD -3C5D1C2BCD18 -3E84D2612E2A -3FA7217EC575 -410B9B40B872 +A57186BDD2B9 +48C739E21A04 +36ABF5874ED7 +649D2ABBBD20 +BBE8FFFCF363 +AB4E7045E97D +340E40F81CD8 +E4F65C0EF32C +D2A597D76936 +A920F32FE93A +86AFD95200F7 +9B832A9881FF +26643965B16E +0C669993C776 +B468D1991AF9 +D9A37831DCE5 +2FC1F32F51B1 +0FFBF65B5A14 +C5CFE06D9EA3 +C0DECE673829 +# +# +A56C2DF9A26D +# +# Data from https://pastebin.com/vbwast74 +68D3F7307C89 +# +# Smart Rider. Western Australian Public Transport Cards +568C9083F71C +117E5C165B10 +24BB421C7973 +3E3A546650EA +41F262D3AB66 +514956AB3142 +863933AE8388 +# +# Bangkok metro key +97F5DA640B18 +# +# Metro Valencia key +A8844B0BCA06 +# +# HTC Eindhoven key +857464D3AAD1 +# +# Vigik Keys +# Various sources : +# * https://github.com/DumpDos/Vigik +# * http://newffr.com/viewtopic.php?&forum=235&topic=11559 +# * Own dumps +# +# French VIGIK +# VIGIK1 A +314B49474956 +# +# VIGIK1 B +564C505F4D41 +BA5B895DA162 +# +# BTCINO UNDETERMINED SPREAKD 0x01->0x13 key +021209197591 +# +# +2EF720F2AF76 414C41524F4E -415A54454B4D -4186562A5BB2 424C41524F4E -425A73484166 -436A46587552 -447AB7FD5A6B -44DD5A385AAF -44F0B5FBE344 -45635EF66EF3 -476242304C53 -484558414354 -# HID Key A -484944204953 -484A57696F4A -48734389EDC3 -48C739E21A04 -49FAE4E3849F 4A6352684677 -4C32BAF326E0 -4C6B69723461 -4C961F23E6BE -4D3248735131 -4D5076656D58 -4E32336C6E38 -4E4175623670 -4F9F59C9C875 -509359F131B1 -51044EFB5AAB -5106CA7E4A69 -513C85D06CDE -52264716EFDE +BF1F4424AF76 536653644C65 -53C11F90822A -543B01B27A95 -5481986D2D62 -5544564E6E67 -564777315276 -568C9083F71C -57734F6F6974 -57784A533069 -584F66326877 -5A1B85FCE20A -5EC39B022F2B -623055724556 -62387B8D250D -6245E47352E6 -62CED42A6D87 +# +# Intratone Cogelec +# Data from http://bouzdeck.com/rfid/32-cloning-a-mifare-classic-1k-tag.html +484558414354 +A22AE129C013 +49FAE4E3849F +38FCF33072E0 +8AD5517B4B18 +509359F131B1 +6C78928E1317 +AA0720018738 +A6CAC2886412 62D0C424ED8E -62EFD80AB715 -645A166B1EEB -649D2ABBBD20 -666E564F4A44 -668770666644 -66B03ACA6EE9 +E64A986A5D94 +8FA1D601D0A2 +89347350BD36 66D2B7DC39EF -66F3ED00FED7 -67546972BC69 -675557ECC92E -686A736A356E -68D3F7307C89 -69FB7B7CD8EE -6A1987C40A21 -6A676C315142 -6A696B646631 -6B6579737472 6BC1E1AE547D -6C78928E1317 -6C94E1CED026 -6D44B5AAF464 +22729A9BD40F +# +# Data from https://dfir.lu/blog/cloning-a-mifare-classic-1k-tag.html +925B158F796F +FAD63ECB5891 +BBA840BA1C57 +CC6B3B3CD263 +6245E47352E6 +8ED41E8B8056 +2DD39A54E1F3 6D4C5B3658D2 -6D4E334B6C48 -6DB17C16B35B -6F4B6D644178 -6F506F493353 +1877ED29435A +52264716EFDE +961C0DB4A7ED 703140FD6D86 -70564650584F -710732200D34 -71F3A315AD26 -744E326B3441 -752FBB5B7B45 -756EF55E2507 -77494C526339 -77646B633657 +157C9A513FA5 +E2A5DC8E066F +# +# Data from forum, schlage 9691T fob +EF1232AB18A0 +# +# Data from a oyster card +374BF468607F +BFC8E353AF63 +15CAFD6159F6 +62EFD80AB715 +987A7F7F1A35 +C4104FA3C526 +4C961F23E6BE +67546972BC69 +F4CD5D4C13FF +94414C1A07DC +16551D52FD20 +9CB290282F7D 77A84170B574 -79674F96C771 +ED646C83A4F3 +E703589DB50B +513C85D06CDE +95093F0B2E22 +543B01B27A95 +C6D375B99972 +EE4CC572B40E +5106CA7E4A69 +C96BD1CE607F +167A1BE102E0 +A8D0D850A606 +A2ABB693CE34 7B296C40C486 +91F93A5564C9 +E10623E7A016 +B725F9CBF183 +# +# Data from FDi tag +8829DA9DAF76 +# +# Data from GitHub issue +0A7932DC7E65 +11428B5BCE06 +11428B5BCE07 +11428B5BCE08 +11428B5BCE09 +11428B5BCE0A +11428B5BCE0F +18971D893494 +25D60050BF6E +44F0B5FBE344 7B296F353C6B -7C335FB121B5 -7F33625BC129 8553263F4FF0 -8697389ACA26 -86AFD95200F7 -87DF99D496CB -8829DA9DAF76 -89347350BD36 -8AD5517B4B18 8E5D33A6ED51 -8ED41E8B8056 -8FA1D601D0A2 -911E52FD7CE4 -9189449EA24E -91CE16C07AC5 -91F93A5564C9 -925B158F796F -92EE4DC87191 -932B9CB730EF -94414C1A07DC -95093F0B2E22 -961C0DB4A7ED -987A7F7F1A35 -9B832A9881FF -9CB290282F7D -9DC282D46217 9F42971E8322 -A10F303FC879 -A21680C27773 -A22AE129C013 -A2ABB693CE34 -A4F204203F56 -A56C2DF9A26D -A57186BDD2B9 -A643F952EA57 -A6CAC2886412 -A7ABBC77CC9E -A8D0D850A606 -A920F32FE93A -AA0720018738 -AB4E7045E97D -AC70CA327A04 -AD4FB33388BF -AD9E0A1CA2F7 -AFD0BA94D624 -B1ACA33180A5 -B35A0E4ACC09 -B39AE17435DC -B468D1991AF9 -B578F38A5C61 -B725F9CBF183 -B7BF0C13066E -B8A1F613CF3D -BA5B895DA162 -BBA840BA1C57 -BBE8FFFCF363 -BEDB604CC9D1 -BF1F4424AF76 -BFB6796A11DB -BFC8E353AF63 -C0C1C2C3C4C5 -C0DECE673829 -C2B7EC7D4EB1 -C3C88C6340B8 -C3F19EC592A2 -C4104FA3C526 -C5132C8980BC -C5CFE06D9EA3 C620318EF179 -C6D375B99972 -C96BD1CE607F -CB779C50E1BD -CBA6AE869AD5 -CC6B3B3CD263 -D0D1D2D3D4D5 -D21762B2DE3B -D2A597D76936 -D327083A60A7 D4FE03CE5B06 D4FE03CE5B07 D4FE03CE5B08 D4FE03CE5B09 D4FE03CE5B0A D4FE03CE5B0F -D58023BA2BDC -D9A37831DCE5 -DB1A3338B2EB -DD61EB6BCE22 -DF37DCB6AFB3 -E10623E7A016 E241E8AFCBAF -E2A5DC8E066F -E4F65C0EF32C -E55A3CA71826 -E64A986A5D94 -E703589DB50B -EB0A8FF88ADE -EC0A9B1A9E06 -ED646C83A4F3 -EE4CC572B40E -EEB420209D0C -F101622750B7 -F1B9F5669CC8 -F23442436765 -F238D78FF48F -F26E21EDCEE2 -F4396E468114 -F4CD5D4C13FF -F662248E7E89 -F72A29005459 -F792C4C76A5C +# Transport system Argentina - SUBE +# Shared key - sec 3 blk 15 +3FA7217EC575 +# +# Data from forum post +123F8888F322 +050908080008 +# +# Data from hoist +4F9F59C9C875 +# +# Data from pastebin +66F3ED00FED7 F7A39753D018 -F9861526130F -FAD63ECB5891 - -# Some keys of https://w3bsit3-dns.com and https://ikey.ru -BC4580B7F20B -8E26E45E7D65 -A7141147D430 -18E3A02B5EFF -E328A1C7156D -8A8D88151A00 -7A86AA203788 -72F96BDD3714 -C76BF71A2509 -1B61B2E78C75 -045CECA15535 -6B07877E2C5C -0CE7CD2CC72B -EA0FD73CB149 -B81F2B0C2F66 -BB52F8CCE07F -46D78E850A7E -E4821A377B75 -8791B2CCB5C4 -D5524F591EED -BAFF3053B496 -0F318130ED18 -42E9B54E51AB -7413B599C4EA -9EA3387A63C1 -B27ADDFB64B0 -E56AC127DD45 -0BE5FAC8B06A -FD8705E721B0 -7259FA0197C6 -22052B480D11 -9D993C5D4EF4 -C65D4EAA645B -0EB23CC8110B -3A8A139C20B4 -19FC84A3784B -0F01CEFF2742 -A3FAA6DAFF67 -BC2D1791DEC1 -7A396F0D633D -ACFFFFFFFFFF -77DABC9825E1 -518DC6EEA089 -044CE1872BC3 -114D6BE9440C -AFCEF64C9913 - +# +# Data from https://pastebin.com/Z7pEeZif +386B4D634A65 +666E564F4A44 +564777315276 +476242304C53 +6A696B646631 +4D3248735131 +425A73484166 +57784A533069 +345547514B4D +4C6B69723461 +4E4175623670 +4D5076656D58 +686A736A356E +484A57696F4A +6F4B6D644178 +744E326B3441 +70564650584F +584F66326877 +6D4E334B6C48 +6A676C315142 +77494C526339 +623055724556 +356D46474348 +4E32336C6E38 +57734F6F6974 +436A46587552 +5544564E6E67 +6F506F493353 +31646241686C +77646B633657 +# +# Data from TransPert +2031D1E57A3B +53C11F90822A +9189449EA24E +# +# data from Github +410B9B40B872 +2CB1A90071C8 +# +# +8697389ACA26 +1AB23CD45EF6 +013889343891 +# +# +0000000018DE +16DDCB6B3F24 +# +# Data from https://pastebin.com/vwDRZW7d +# Vingcard Mifare 4k Staff card +EC0A9B1A9E06 +6C94E1CED026 +0F230695923F +0000014B5C31 +# +# +BEDB604CC9D1 +B8A1F613CF3D +B578F38A5C61 +B66AC040203A +6D0B6A2A0003 +2E641D99AD5B +AD4FB33388BF +69FB7B7CD8EE +# +# Hotel +2A6D9205E7CA +13B91C226E56 +# +# KABA Hotel Locks +2A2C13CC242A +# +# +27FBC86A00D0 +01FA3FC68349 +# +# Smart Rider. Western Australian Public Transport Cards +6D44B5AAF464 +1717E34A7A8A +# +# RFIDeas +6B6579737472 +# +# HID MIFARE Classic 1k Key +484944204953 +204752454154 +# HID MIFARE SO +3B7E4FD575AD +11496F97752A +# +# Luxeo/Aztek cashless vending +415A54454B4D +# +# BQT +321958042333 +# +# Aperio KEY_A Sector 1, 12, 13, 14, 15 Data Start 0 Length 48 +160A91D29A9C +# +# Gallagher +B7BF0C13066E +# +# PIK Comfort Moscow keys (ISBC Mifare Plus SE 1K) +009FB42D98ED +002E626E2820 +# +# Boston, MA, USA Transit - MBTA Charlie Card +3060206F5B0A +5EC39B022F2B +3A09594C8587 +F1B9F5669CC8 +F662248E7E89 +62387B8D250D +F238D78FF48F +9DC282D46217 +AFD0BA94D624 +92EE4DC87191 +B35A0E4ACC09 +756EF55E2507 +447AB7FD5A6B +932B9CB730EF +1F1A0A111B5B +AD9E0A1CA2F7 +D58023BA2BDC +62CED42A6D87 +2548A443DF28 +2ED3B15E7C0F +F66224EE1E89 +# +# +60012E9BA3FA +# +# +DE1FCBEC764B +81BFBE8CACBA +BFF123126C9B +2F47741062A0 +B4166B0A27EA +A170D9B59F95 +400BC9BE8976 +D80511FC2AB4 +1FCEF3005BCF +BB467463ACD6 +E67C8010502D +FF58BA1B4478 +# +# Data from https://pastebin.com/Kz8xp4ev +FBF225DC5D58 +# +# Data https://pastebin.com/BEm6bdAE +# vingcard.txt +# Note: most likely diversified +96A301BCE267 +4708111C8604 +3D50D902EA48 +6700F10FEC09 +7A09CC1DB70A +560F7CFF2D81 +66B31E64CA4B +9E53491F685B +3A09911D860C +8A036920AC0C +361F69D2C462 +D9BCDE7FC489 +0C03A720F208 +6018522FAC02 +# +# Data from https://pastebin.com/4t2yFMgt +# Mifare technische Universität Graz TUG +D58660D1ACDE +50A11381502C +C01FC822C6E5 +0854BF31111E +# +# More keys - Found 8A at Sebel Hotel in Canberra, Australia +AE8587108640 +# +# SafLock standalone door locks +135B88A94B8B +# # Russian Troika card +EC29806D9738 08B386463229 0E8F64340BA4 0F1C63013DBA @@ -587,693 +1059,698 @@ EAAC88E5DC99 F8493407799D 6B8BD9860763 D3A297DC2698 -FBF225DC5D58 -# Strelka extension +# +# Data from reddit +34635A313344 +593367486137 +# +# Keys from Mifare Classic Tool project +044CE1872BC3 +045CECA15535 +0BE5FAC8B06A +0CE7CD2CC72B +0EB23CC8110B +0F01CEFF2742 +0F318130ED18 +114D6BE9440C +18E3A02B5EFF +19FC84A3784B +1B61B2E78C75 +22052B480D11 3367BFAA91DB +3A8A139C20B4 +42E9B54E51AB +46D78E850A7E 4B609876BBA3 -5C83859F2224 -66B504430416 -70D1CF2C6843 +518DC6EEA089 +6B07877E2C5C +7259FA0197C6 +72F96BDD3714 +7413B599C4EA +77DABC9825E1 +7A396F0D633D +7A86AA203788 +8791B2CCB5C4 +8A8D88151A00 8C97CD7A0E56 +8E26E45E7D65 +9D993C5D4EF4 +9EA3387A63C1 +A3FAA6DAFF67 +A7141147D430 +ACFFFFFFFFFF +AFCEF64C9913 +B27ADDFB64B0 +B81F2B0C2F66 B9F8A7D83978 -C4B3BD0ED5F1 -C4D3911AD1B3 -CAD7D4A6A996 -DA898ACBB854 -FEA1295774F9 - -# Moscow public toilets card -807119F81418 -22C8BCD10AAA -0AAABA420191 -E51B4C22C8BC -DBF9F79AB7A2 -34EDE51B4C22 -C8BCD10AAABA -BCD10AAABA42 - -# Moscow social card -2735FC181807 -2ABA9519F574 -84FD7F7A12B6 -186D8C4B93F9 -3A4BBA8ADAF0 -8765B17968A2 -40EAD80721CE -0DB5E6523F7C -51119DAE5216 -83E3549CE42D -136BDB246CAC -2F87F74090D1 -E53EAEFE478F -CE2797E73070 -328A034B93DB -81E1529AE22B -FC55C50E579F -1A72E2337BC3 -5DB52676BE07 -F64FBF085098 -8FE758A8F039 -BB1484CC155D -41990A529AE2 -CD2E9EE62F77 -69C1327AC20B -3C9C0D559DE5 -67BF3880C811 -48A01159A1E9 -2B83FB448CD4 -F24BBB044C94 -7DE02A7F6025 -BF23A53C1F63 -CB9A1F2D7368 -C7C0ADB3284F -9F131D8C2057 -67362D90F973 -6202A38F69E2 -100533B89331 -653A87594079 -D8A274B2E026 -B20B83CB145C -9AFA6CB4FC3D -94F46DB5FD46 -C31C8CD41D65 -BB1684CC155D -CA2393DB246C -1D75E52E76BE -81D9529AE223 -0159C9125AA2 -52AA1B6BB3FB -97EF60A8F031 -6FC73888D011 -3A92FA438BD3 -74CC3D85CD0E -025ACA1B63A3 -AF0878C81151 -9BFB6CB4FC45 -F750C0095199 -075FCF1860A8 -2686EE3F87C7 -277FEF3880C0 -82DA4B93DB1C -9CF46DB5FD46 -93EB64ACF43D - -# Keys from RfidResearchGroup proxmark3 project -# https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_default_keys.dic -0854BF31111E -0C03A720F208 -135B88A94B8B -1FCEF3005BCF -2F47741062A0 -361F69D2C462 -3A09911D860C -3D50D902EA48 -400BC9BE8976 -4708111C8604 -50A11381502C -560F7CFF2D81 -60012E9BA3FA -6018522FAC02 -66B31E64CA4B -6700F10FEC09 -7A09CC1DB70A -81BFBE8CACBA -8A036920AC0C -8A19D40CF2B5 -96A301BCE267 -9E53491F685B -A170D9B59F95 -AE8587108640 -B4166B0A27EA -BB467463ACD6 -BFF123126C9B -C01FC822C6E5 -D58660D1ACDE -D80511FC2AB4 -D9BCDE7FC489 -DE1FCBEC764B -E67C8010502D -FF58BA1B4478 - -C1E51C63B8F5 -4143414F5250 -474249437569 +BAFF3053B496 +BB52F8CCE07F +BC2D1791DEC1 +BC4580B7F20B +C65D4EAA645B +C76BF71A2509 +D5524F591EED +E328A1C7156D +E4821A377B75 +E56AC127DD45 +EA0FD73CB149 +FC0001877BF7 +FD8705E721B0 +00ADA2CD516D +518108E061E2 +558AAD64EB5B +001122334455 +6CA761AB6CA7 +B1C4A8F7F6E3 +FF75AFDA5A3C +FCDDF7767C10 +A6B3F6C8F1D4 +# +# +237A4D0D9119 +0ED7846C2BC9 +FFFFD06F83E3 +FFFFAE82366C +F89C86B2A961 +F83466888612 +ED3A7EFBFF56 +E96246531342 +E1DD284379D4 +DFED39FFBB76 +DB5181C92CBE +CFC738403AB0 +BCFE01BCFE01 +BA28CFD15EE8 B0699AD03D17 -B18CDCDE52B7 -3864FCBA5937 -85A438F72A8A -C342F825B01B -C6A76CB2F3B5 -323334353637 -43C7600DEE6B -D01AFEEB890A -26396F2042E7 -F3F0172066B2 -BB320A757099 -00F0BD116D70 -25094DF2C1BD -E41E6199318F -F00DFEEDD0D0 -6D9B485A4845 -71171A82D951 -62711F1A83E9 -1711B1A82E96 -F3864FCCA693 -7B7E752B6A2D -2012053082AD -9AEDF9931EC1 -B9C874AE63D0 -83BAB5ACAD62 -A541538F1416 -4A2B29111213 -D31463A7AB6D -AD5645062534 -B069D0D03D17 -30FFB6B056F5 -D7744A1A0C44 -D1991E71E2C5 -1795902DBAF9 -4243414F5250 -C554EF6A6015 -A5524645CD91 -200306202033 -A00003000084 -CEE3632EEFF5 -F0F0172066B2 -B021669B44BB -3F1A87298691 +AABBCC660429 +A4EF6C3BB692 A2B2C9D187FB -4B511F4D28DD -E3AD9E9BA5D4 -B3630C9F11C8 -F83466888612 -857464D3AAD1 -A2A3CCA2A3CC -35D850D10A24 -B2F170172066 -0D8CA561BDF3 -05F89678CFCF -850984712F1A -21EDF95E7433 -172066B2F2F0 -6B2F1B017206 -363119000001 -23D4CDFF8DA3 -EF4C5A7AC6FC -123456ABCDEF +9B1DD7C030A1 +9AEDF9931EC1 8F9B229047AC -E96246531342 +872B71F9D15A +833FBD3CFE51 5D293AFC8D7E -AABBCC660429 -63FCA9492F38 -354A787087F1 +5554AAA96321 +474249437569 +435330666666 +1A2B3C4D5E6F +123456ABCDEF +83BAB5ACAD62 +64E2283FCF5E +64A2EE93B12B +46868F6D5677 40E5EA1EFC00 -675A32413770 -12FD3A94DF0E -C4F271F5F0B3 -4A306E62E9B6 -4CFF128FA3EF -0000085F0000 -0F385FFB6529 -FA38F70215AD -904735F00F9E -B66AC040203A -BCFE01BCFE01 -2FCA8492F386 -237A4D0D9119 -E6849FCC324B -0ED7846C2BC9 -1FB235AC1388 -EA1B88DF0A76 -C9739233861F -89EAC97F8C2A -D964406E67B4 -563A22C01FC8 -DB5181C92CBE -1E352F9E19E5 -6291B3860FC8 -A9A4045DCE77 -434456495243 -B5F454568271 -491CDC863104 -4D8B8B95FDEE -AFBECD121004 -4D48414C5648 -E1DD284379D4 -AFBECD120454 -CFC738403AB0 -0AF7DB99AEE4 -772219470B38 -EF61A3D48E2A -4A4C474F524D -0172066B2F03 -3D5D9996359A -66A163BA82B4 +37D4DCA92451 +2012053082AD 2011092119F1 -BB2C0007D022 -1494E81663D7 -590BD659CDD2 -A6C028A12FBB -BCF5A6B5E13F -A2F63A485632 -39CF885474DD -D2ECE8B9395E +200306202033 +1795902DBAF9 17505586EF02 -70172066B2F0 -B385EFA64290 -B7C344A36D88 -010000000000 -2F130172066B -DFED39FFBB76 -3F7A5C2DBD81 -DFE73BE48AC6 -FB0B20DF1F34 -913385FFB752 -2066B2F27017 -91FF18E63887 -0734BFB93DAB -97F5DA640B18 -B42C4DFD7A90 -C121FF19F681 -BE7C4F6C7A9A -FE04ECFE5577 -18F34C92A56E -0BB31DC123E5 -0E0E8C6D8EB6 -1CFA22DBDFC3 -0F1A81C95071 -AA4D051954AC -9F9D8EEDDCCE -863FCB959373 -98631ED2B229 -A23456789123 -833FBD3CFE51 -AB28A44AD5F5 -74A386AD0A6D -4C60F4B15BA8 022FE48B3072 -97271231A83F -385EFA542907 -066B2F230172 -BA729428E808 -BDF837787A71 -A05DBD98E0FC -395244733978 -9B1DD7C030A1 -2C9F3D45BA13 -1DB710648A65 -E65B66089AFC -A85198481331 -5A12F83326E7 -A7D71AC06DC2 -64E2283FCF5E -FFFFAE82366C -10F3BEBC01DF -00ADA2CD516D +013940233313 +# +# Hotel Adina +9EBC3EB37130 +# +# Misc. keys from hotels & library cards in Germany +914f57280ce3 +324a82200018 +370aee95cd69 +2e032ad6850d +1feda39d38ec +288b7a34dbf8 +0965e3193497 +18c628493f7f +064d9423938a +995fd2a2351e +7c7d672bc62e +217250fb7014 +ae7478ccaee7 +abbf6d116eaf +05862c58edfb +e43b7f185460 +6a59aa9a959b +b79e5b175227 +7bc9ebb8274b +b2afbf2331d4 +223e5847dd79 +640524d2a39b +aee297cb2fd6 +3da5dfa54604 +0cf1a2aa1f8d +# +# most likely diversifed individual keys. +# data from https://github.com/korsehindi/proxmark3/commit/24fdbfa9a1d5c996aaa5c192bc07e4ab28db4c5c +491CDC863104 +A2F63A485632 +98631ED2B229 +19F1FFE02563 +# +# Argentina +563A22C01FC8 +43CA22C13091 +25094DF2C1BD +# +# OMNITEC.ES HOTEL TIMECARD / MAINTENANCECARD +AFBECD120454 +# +# OMNITEC.ES HOTEL EMERGENCYCARD +842146108088 +# +# TAPCARD PUBLIC TRANSPORT LA +EA1B88DF0A76 +D1991E71E2C5 +05F89678CFCF +D31463A7AB6D +C38197C36420 +772219470B38 +1C1532A6F1BC +FA38F70215AD +E907470D31CC +160F4B7AB806 1D28C58BBE8A -6936C035AE1B -AC45AD2D620D -64A2EE93B12B -A9F95891F0A4 -E45230E7A9E8 -A7FB4824ACBF -223C3427108A -58AC17BF3629 -535F47D35E39 -10F2BBAA4D1C -A0004A000036 -3F3865FCCB69 -0B0172066B2F -4098653289D3 -BA28CFD15EE8 -A22647F422AE -99858A49C119 -29173860FC76 -1A80B93F7107 -1A2B3C4D5E6F +B3830B95CA34 +6A0E215D1EEB +E41E6199318F +C4F271F5F0B3 +1E352F9E19E5 +0E0E8C6D8EB6 +C342F825B01B +CB911A1A1929 +E65B66089AFC +B81846F06EDF +37FC71221B46 +880C09CFA23C +6476FA0746E7 +419A13811554 2C60E904539C +4ECCA6236400 +10F2BBAA4D1C +4857DD68ECD9 +C6A76CB2F3B5 +E3AD9E9BA5D4 6C9EC046C1A4 -FC9839273862 -1C1532A6F1BC -09800FF94AAF -FFFFD06F83E3 -0B83797A9C64 -13B91C226E56 -A4EF6C3BB692 -000000270000 -A00002000021 -872B71F9D15A +# +# ROC HIGHSCHOOL ACCESSCARD +B021669B44BB +B18CDCDE52B7 +A22647F422AE +B268F7C9CA63 A37A30004AC9 -B1A862985913 +B3630C9F11C8 A4CDFF3B1848 -2E641D99AD5B -827ED62B31A7 -CD212889C3ED -B1A80C94F710 -CB911A1A1929 +B42C4DFD7A90 +A541538F1416 +B5F454568271 +A6C028A12FBB +B6323F550F54 +A7D71AC06DC2 +B7C344A36D88 A844F4F52385 -C0BEEFEC850B -5C8FF9990DA2 -160F4B7AB806 -B8937130B6BA -66B2F1F01720 -82D58AA49CCB -A9B43414F585 -C38197C36420 -0172066B2F33 -434143445649 -34B16CD59FF8 -5A7A52D5E20D -6471A5EF2D1A -F57F410E18FF -3B0172066B2F -E907470D31CC B8457ACC5F5D -67CC03B7D577 -A8844B0BCA06 -435330666666 -B47058139187 -46868F6D5677 -C27D999912EA -37FC71221B46 -F97371271A84 +A9A4045DCE77 +B9B8B7B6B5B3 +AA4D051954AC +BA729428E808 +AB28A44AD5F5 +BB320A757099 +AC45AD2D620D +BCF5A6B5E13F +AD5645062534 +BDF837787A71 AE43F36C1A9A +BE7C4F6C7A9A 5EC7938F140A -AA734D2F40E0 -A5A4A3A2A1A0 -70172066B2F3 +82D58AA49CCB +# +# MELON CARD +323334353637 +# +# +CEE3632EEFF5 +827ED62B31A7 03EA4053C6ED +C0BEEFEC850B +F57F410E18FF +0AF7DB99AEE4 +A7FB4824ACBF +207FFED492FD +1CFA22DBDFC3 +30FFB6B056F5 +39CF885474DD +00F0BD116D70 +4CFF128FA3EF +10F3BEBC01DF +# +# Transportes Insular La Palma +0172066B2F03 +0000085F0000 +1A80B93F7107 +70172066B2F0 +B1A80C94F710 +0B0172066B2F +0F1A81C95071 +F0F0172066B2 +1131A81D9507 +2F130172066B +71171A82D951 +B2F170172066 +1711B1A82E96 +6B2F1B017206 +62711F1A83E9 +66B2F1F01720 +97271231A83F +066B2F230172 +F97371271A84 +2066B2F27017 +50983712B1A8 +72066B2F2B01 +850984712F1A +172066B2F2F0 +A85198481331 +0172066B2F33 +1A8619858137 +70172066B2F3 +B1A862985913 +3B0172066B2F +3F1A87298691 +F3F0172066B2 +# +# Tehran ezpay +38A88AEC1C43 +CBD2568BC7C6 +7BCB4774EC8F +22ECE9316461 +AE4B497A2527 +EEC0626B01A1 +2C71E22A32FE +91142568B22F +7D56759A974A +D3B1C7EA5C53 +41C82D231497 +0B8B21C692C2 +604AC8D87C7E +8E7B29460F12 +BB3D7B11D224 +# +# Chaco +B210CFA436D2 +B8B1CFA646A8 +A9F95891F0A4 +# +# Keys from APK application "Scan Badge" +4A4C474F524D +444156494442 +434143445649 +434456495243 +A00002000021 +EF61A3D48E2A +A23456789123 +010000000000 +363119000001 +A00003000084 +675A32413770 +395244733978 +A0004A000036 +2C9F3D45BA13 +4243414F5250 +DFE73BE48AC6 +# +# +B069D0D03D17 +000131B93F28 +# +# From the DFW Area, TX, USA +A506370E7C0F +26396F2042E7 +70758FDD31E0 +9F9D8EEDDCCE 06FF5F03AA1A -5554AAA96321 -0120BF672A64 -87291F3861FC -9EBC3EB37130 +4098653289D3 +904735F00F9E B4C36C79DA8D -43CA22C13091 -6D0B6A2A0003 -FB6C88B7E279 -013940233313 -7DD399D4E897 -ED3A7EFBFF56 68F9A1F0B424 -6476FA0746E7 -1A8619858137 -1131A81D9507 +5A85536395B3 +7DD399D4E897 +EF4C5A7AC6FC +B47058139187 8268046CD154 -4857DD68ECD9 +67CC03B7D577 +# +# From the HTL Mödling, NÖ, AT +A5524645CD91 +D964406E67B4 +99858A49C119 +7B7E752B6A2D +C27D999912EA +66A163BA82B4 +4C60F4B15BA8 +# +# CAFE + CO, AT +35D850D10A24 +4B511F4D28DD +E45230E7A9E8 +535F47D35E39 +FB6C88B7E279 +# +# Metro Card, AT +223C3427108A +# +# Unknown, AT +23D4CDFF8DA3 +E6849FCC324B +12FD3A94DF0E +# +# Unknown, AT +0B83797A9C64 +39AD2963D3D1 +# +# Hotel Berlin Classic room A KEY +34B16CD59FF8 +# +# Hotel Berlin Classic room B KEY +BB2C0007D022 +# +# Coinmatic laundry Smart card +# data from: https://pastebin.com/XZQiLtUf +0734BFB93DAB +85A438F72A8A +# +# Data from forum, Chinese hotel +58AC17BF3629 B62307B62307 -C6C866AA421E -F66224EE1E89 -4ECCA6236400 -72066B2F2B01 +# +# +A2A3CCA2A3CC +# +# Granada, ES Transport Card +000000270000 +0F385FFB6529 +29173860FC76 +2FCA8492F386 +385EFA542907 +3864FCBA5937 +3F3865FCCB69 +6291B3860FC8 +63FCA9492F38 +863FCB959373 +87291F3861FC +913385FFB752 +B385EFA64290 +C9739233861F +F3864FCCA693 +FC9839273862 +# +# various hotel keys 34D3C568B348 -000131B93F28 -419A13811554 -B6323F550F54 -F89C86B2A961 -B268F7C9CA63 -B8B1CFA646A8 -4D57414C5648 -6A0E215D1EEB -70758FDD31E0 -37D4DCA92451 -444156494442 -B210CFA436D2 -207FFED492FD +91FF18E63887 +4D8B8B95FDEE +354A787087F1 +4A306E62E9B6 +B9C874AE63D0 +# +# Data from official repo +F00DFEEDD0D0 +0BB31DC123E5 7578BF2C66A9 -50983712B1A8 -5A85536395B3 -B81846F06EDF -842146108088 -19F1FFE02563 -D3B595E9DD63 -B3830B95CA34 -A506370E7C0F -880C09CFA23C -43454952534E -39AD2963D3D1 -B9B8B7B6B5B3 +CD212889C3ED +6936C035AE1B +C6C866AA421E +590BD659CDD2 +AA734D2F40E0 +09800FF94AAF +5A12F83326E7 +C554EF6A6015 +0D8CA561BDF3 +B8937130B6BA +D7744A1A0C44 82908B57EF4F - -C67BEB41FFBF -2AFFD6F88B97 -E77952748484 -988ACDECDFB0 -605F5E5D5C5B -42EF7BF572AB -4087C6A75A96 -AADE86B1F9C1 -5EA088C824C9 -120D00FFFFFF +FE04ECFE5577 +# +# comfort inn hotel +4D57414C5648 +4D48414C5648 +# +# unknown hotel key +6D9B485A4845 +# +# Bosch Solution 6000 +5A7A52D5E20D +# +# Found in TagInfo app +# RATB key +C1E51C63B8F5 +1DB710648A65 +# E-GO card key +18F34C92A56E +# +# Library Card MFP - SL1 +4A832584637D CA679D6291B0 +30D9690FC5BC +5296C26109D4 +E77952748484 +91C2376005A1 +30B7680B2BC9 E2A9E88BFE16 -0A4600FF00FF 43B04995D234 -0602721E8F06 +AADE86B1F9C1 +5EA088C824C9 +C67BEB41FFBF +B84D52971107 +52B0D3F6116E +# +# Data from https://pastebin.com/cLSQQ9xN +CA3A24669D45 +4087C6A75A96 +403F09848B87 +D73438698EEA 5F31F6FCD3A0 -4AE23A562A80 A0974382C4C5 -91C2376005A1 -FEE2A3FBC5B6 -2602FFFFFFFF -CA3A24669D45 -A9F3F289B70C -B84D52971107 -274E6101FC5E -00DD300F4F10 -F7BA51A9434E -4A832584637D -B16B2E573235 A82045A10949 -FC0B50AF8700 -403F09848B87 +# +# Data from https://pastebin.com/2iV8h93h +# +# funnivarium +# forum ankara +2602FFFFFFFF +# +# macera adasi +# ankara kentpark +# INACTIVE +0A4600FF00FF DFF293979FA7 -4118D7EF0902 -30B7680B2BC9 -52B0D3F6116E -5296C26109D4 -DB6819558A25 4D6F62692E45 +4118D7EF0902 +# +# petrol ofisi +# positive card +# ode-gec 0406080A0C0E +# +# konya elkart +988ACDECDFB0 +120D00FFFFFF +# +# bowlingo +# serdivan avym +4AE23A562A80 +# +# kart 54 +2AFFD6F88B97 +A9F3F289B70C +DB6819558A25 6130DFA578A0 -30D9690FC5BC -D73438698EEA +B16B2E573235 +42EF7BF572AB +274E6101FC5E +# +# crazy park +# kizilay avm +00DD300F4F10 +# +# kartsistem B +FEE2A3FBC5B6 +# +# toru ent +# taurus avm 005078565703 - -7C87013A648A -9E7168064993 -45FEE09C1D06 -734EBE504CE8 -E592ED478E59 -C229CE5123D5 -240F0BB84681 -D8BA1AA9ABA0 -865B6472B1C0 -974A36E2B1BA -57D83754711D -C9CD8D7C65E5 -C197AE6D6990 -AABAFFCC7612 -C0AD1B72921A -AFAAFCC40DEC +# +# Ving? +0602721E8F06 +FC0B50AF8700 +F7BA51A9434E +# +# eskart +# eskisehir transport card E902395C1744 -DAC7E0CBA8FD -755D49191A78 -68D3263A8CD6 -2F8A867B06B4 +4051A85E7F2D 7357EBD483CC -ABCC1276FCB0 -26BF1A68B00F -704A81DDACED +D8BA1AA9ABA0 +76939DDD9E97 +3BF391815A8D +# +# muzekart +# museum card for turkey +7C87013A648A E8794FB14C63 +9F97C182585B EC070A52E539 -037F64F470AD -76939DDD9E97 -4D80A10649DF -89E00BC444EF -26107E7006A0 +C229CE5123D5 +E495D6E69D9C +26BF1A68B00F B1D3BC5A7CCA -ECC58C5D34CA -9F97C182585B -B2FE3B2875A6 +734EBE504CE8 +974A36E2B1BA +C197AE6D6990 +4D80A10649DF +037F64F470AD +C9CD8D7C65E5 B70B1957FE71 -E495D6E69D9C -0860318A3A89 -4051A85E7F2D -17D071403C20 -3BF391815A8D -1927A45A83D3 CE7712C5071D +C0AD1B72921A +45FEE09C1D06 +E592ED478E59 F3C1F1DB1D83 +704A81DDACED +89E00BC444EF +AFAAFCC40DEC +ECC58C5D34CA +57D83754711D D0DDDF2933EC - -# Iron Logic -A3A26EF4C6B0 -2C3FEAAE99FC -E85B73382E1F -F4ED24C2B998 -CB574C6D3B19 -E092081D724B -B38D82CF7B6C -8228D2AA6EFA -2C7E983588A3 -CF7A7B77E232 -32A7F5EAF87D -7453A687B5F0 -01A0C008A5B9 -DEC0CEB0CE24 -413BED2AE45B -D6261A9A4B3F -CB9D507CE56D - -# Tehran ezpay -38A88AEC1C43 -CBD2568BC7C6 -7BCB4774EC8F -22ECE9316461 -AE4B497A2527 -EEC0626B01A1 -2C71E22A32FE -91142568B22F -7D56759A974A -D3B1C7EA5C53 -41C82D231497 -0B8B21C692C2 -604AC8D87C7E -8E7B29460F12 -BB3D7B11D224 - -# More keys from the PM3 repo -DC018FC1D126 -C428C4550A75 -0C4233587119 -5B0C7EC83645 -540D5E6355CC -35C649004000 -CFE63749080A -6307417353C1 -411053C05273 -749934CC8ED3 -1C68315674AC -35D152154017 -D1417E431949 -26B85DCA4321 -D973D917A4C7 -3A471B2192BF -534F4C303232 -730956C72BC2 -C9449301AF93 -F678905568C3 -4578ABFEDC12 -075D1A4DD323 -43E69C28F08C -0F35D5660653 -F7FA2F629BB1 -5145C34DBA19 -124578ABFEDC -E2F14D0A0E28 -C8AACD7CF3D1 -9C616585E26D -4927C97F1D57 +240F0BB84681 +9E7168064993 +2F8A867B06B4 +# +# bursakart +# bursa transport card +755D49191A78 +DAC7E0CBA8FD +68D3263A8CD6 +865B6472B1C0 +0860318A3A89 +1927A45A83D3 +B2FE3B2875A6 +# +# playland +# maltepe park +ABCC1276FCB0 +AABAFFCC7612 +# +# lunasan +# kocaeli fair +26107E7006A0 +# +# gamefactory +# ozdilek +17D071403C20 +# +# +534F4C415249 +534F4C303232 +# +# Nespresso, smart card +# key-gen algo, these keys are for one card (keys diversified) +FF9A84635BD2 6F30126EE7E4 -155332417E00 -5353B3AECB53 -361A62F35BC9 -00460740D722 -A9B018868CC1 -2E71D3BD262A -4F75030AD12B -42454C4C4147 -D75971531042 -25352912CD8D -51E97FFF51E9 -1170553E4304 -D1F71E05AD9D -541C417E57C0 -AE76242931F1 6039ABB101BB -0E620691B9FE -4BF6DE347FB6 -10510049D725 -1F0128447C00 +F1A1239A4487 +# +# +B882FD4A9F78 +CD7FFFF81C4A +AA0857C641A3 +C8AACD7CF3D1 +9FFDA233B496 +26B85DCA4321 +D4B2D140CB2D +A7395CCB42A0 +541C417E57C0 D14E615E0545 -94B6A644DFF6 -81B20C274C3F -66695A45C9FA -130662240200 -DD0DE3BA08A6 -05F5EC05133C -4FA9EB49F75E -C1E6F8AFC9EC -28D70900734C -32CA52054416 +69D92108C8B5 703265497350 -3D923EB73534 +D75971531042 +10510049D725 +35C649004000 +5B0C7EC83645 +05F5EC05133C +521B517352C7 +94B6A644DFF6 +2CA4A4D68B8E +A7765C952DDF +E2F14D0A0E28 +DC018FC1D126 +4927C97F1D57 +046154274C11 +155332417E00 +6B13935CD550 C151D998C669 -534F4C415249 -70C714869DC7 -A7395CCB42A0 -89AA9D743812 -A160FCD5EC4C -9DCDB136110C -9951A273DEE7 -AA0857C641A3 -F1A1239A4487 -B882FD4A9F78 +D973D917A4C7 +130662240200 9386E2A48280 +52750A0E592A +075D1A4DD323 +32CA52054416 460661C93045 -EF1232AB18A0 -6285A1C8EB5C -C41514DEFC07 -ABFEDC124578 -046154274C11 5429D67E1F57 -# SMARTair Key B -E7316853E731 -CD7FFFF81C4A -F253C30568C4 -E7D6064C5860 -506DB955F161 -8223205047B6 -070D486BC555 -D4B2D140CB2D 0C734F230E13 -2E4169A5C79D -69D92108C8B5 -A297CEB7D34B -FF9A84635BD2 +1F0128447C00 +411053C05273 +42454C4C4147 +C428C4550A75 +730956C72BC2 +28D70900734C +4F75030AD12B +6307417353C1 +D65561530174 +D1F71E05AD9D +F7FA2F629BB1 +0E620691B9FE +43E69C28F08C 735175696421 -5D0762D13401 -D61707FFDFB1 -2803BCB0C7E1 -C52876869800 424C0FFBF657 -AF9E38D36582 -B32464412EE3 +51E97FFF51E9 +E7316853E731 +00460740D722 +35D152154017 +5D0762D13401 +0F35D5660653 +1170553E4304 +0C4233587119 +F678905568C3 50240A68D1D8 -6B13935CD550 -83F3CB98C258 -521B517352C7 -4BB747E48C2A +2E71D3BD262A +540D5E6355CC +D1417E431949 +4BF6DE347FB6 +# +# +3A471B2192BF +A297CEB7D34B +AE76242931F1 +# +# +124578ABFEDC +ABFEDC124578 +4578ABFEDC12 +# +# Data from +# premier inn hotel chain 5E594208EF02 -FFFFFF545846 -D65561530174 -52750A0E592A -112233445566 -2DADE48942C5 -A7765C952DDF -2CA4A4D68B8E -72B458D60363 -F088A85E71D7 -FF94F86B09A6 -B27CCAB30DBD -89ECA97F8C2A -E00000000000 -9FFDA233B496 +AF9E38D36582 +# +# Norwegian building site identication card. (HMS KORT) +# Key a 10DF4D1859C8 +# +# Key B B5244E79B0C8 +# +# Ukraine hotel F5C1C4C5DE34 - +# +# Data from Mifare Classic Tool repo # Rotterdam University of applied sciences campus card BB7923232725 A95BD5BB4FC5 @@ -1297,27 +1774,406 @@ B5ADEFCA46C4 BF3FE47637EC B290401B0CAD AD11006B0601 - -# Keys of Armenian underground ticket -A0A1A2A8A4A5 +# +# Data from Mifare Classic Tool repo +# Armenian Metro +E4410EF8ED2D +6A68A7D83E11 0D6057E8133B D3F3B958B8A3 -6A68A7D83E11 -7C469FE86855 -E4410EF8ED2D 3E120568A35C -CE99FBC8BD26 2196FAD8115B - -# PIK Comfort Moscow keys (ISBC Mifare Plus SE 1K) -009FB42D98ED -002E626E2820 - -# Volgograd (Russia) Volna transport cards keys -2B787A063D5D -D37C8F1793F7 - +7C469FE86855 +CE99FBC8BD26 +# +# keys from Eurothermes group (Switzerland) +D66D91829013 +75B691829013 +83E391829013 +A23C91829013 +E46A91829013 +D9E091829013 +FED791829013 +155F91829013 +06CC91829013 +8DDC91829013 +54AF91829013 +29A791829013 +668091829013 +00008627C10A +# +# easycard +310D51E539CA +2CCDA1358323 +03E0094CEDFE +562E6EF73DB6 +F53E9F4114A9 +AD38C17DE7D2 +# +# SUBE cards keys (new) +2DEB57A3EA8F +32C1BB023F87 +70E3AD3F2D29 +202ECDCCC642 +3686192D813F +24501C422387 +2C7813A721C3 +FFE04BE3D995 +D28F090677A1 +DE2D83E2DCCC +A66A478712EA +643232ADB2D5 +C7F4A4478415 +95C013B70D99 +3C383889362A +3C6D9C4A90FA +51BEDBA005E5 +74BF7363F354 +53B09DB89111 +E98075318085 +2F904641D75F +7F60AEF68136 +F5C1B3F62FDA +3E6E5713BA10 +8B75A29D4AB2 +7E6545076619 +# +# SUBE cards keys (old) +4C5A766DFE3A +32C6768847F5 +F68930789631 +8B42B6D64B02 +B627A3CB13F8 +562A4FB8260B +88DDC24E1671 +91CB7802A559 +7A3E0F5B63FC +8CA2C9DC8292 +5CCC6D50EAAC +DE4F5AA9A7F3 +52D0145E1AF5 +C10F92A4E57E +7D6E7AF43C97 +DE1E7D5F6DF1 +F4CB751B031A +C54474936B59 +2A1F900D4533 +6303CDCBB233 +F115E91357B3 +BFE25035B0C8 +62FF943EB069 +7C82EF592001 +D5C172325DD3 +992B152E834A +CE75D7EADEAF +# +# Russian Podorozhnik card (Saint-Petersburg transport) +# may be combined with Troika +038B5F9B5A2A +04DC35277635 +0C420A20E056 +152FD0C420A7 +296FC317A513 +29C35FA068FB +31BEC3D9E510 +462225CD34CF +4B7CB25354D3 +5583698DF085 +578A9ADA41E3 +6F95887A4FD3 +7600E889ADF9 +86120E488ABF +8818A9C5D406 +8C90C70CFF4A +8E65B3AF7D22 +9764FEC3154A +9BA241DB3F56 +AD2BDC097023 +B0A2AAF3A1BA +B69D40D1A439 +C956C3B80DA3 +CA96A487DE0B +D0A4131FB290 +D27058C6E2C7 +E19504C39461 +FA1FBB3F0F1F +FF16014FEFC7 +# +# Food GEM +6686FADE5566 +# +# Samsung Data Systems (SDS) — Electronic Locks +# Gen 1 S10 KA/KB is FFFFFFFFFFFF, incompatible with Gen 2 locks +# +# SDS Gen 2 S10 KB +C22E04247D9A +# +# Data from Discord, French pool +# SDS Gen 2 S10 KA +9B7C25052FC3 +494446555455 +# +# Data from Discord, seems to be related to ASSA +427553754D47 +# Keys found on Edith Cowan University Smart Riders +9A677289564D +186C59E6AFC9 +DDDAA35A9749 +9D0D0A829F49 +# Mercator Pika Card, Slovenia +97D77FAE77D3 +5AF445D2B87A +# +# Vilniečio/JUDU kortelė, Lithuania +# A +16901CB400BC +F0FE56621A42 +8C187E78EE9C +FE2A42E85CA8 +# B +6A6C80423226 +F4CE4AF888AE +307448829EBC +C2A0105EB028 +# +# Keys from Flipper Zero Community +# Last update: Aug 13, 2022 +# +# unknown if keys are diversified or static default +# +# Strelka Extension +5C83859F2224 +66B504430416 +70D1CF2C6843 +C4B3BD0ED5F1 +C4D3911AD1B3 +CAD7D4A6A996 +DA898ACBB854 +FEA1295774F9 +# +# Moscow Public Toilets Card +807119F81418 +22C8BCD10AAA +0AAABA420191 +E51B4C22C8BC +DBF9F79AB7A2 +34EDE51B4C22 +C8BCD10AAABA +BCD10AAABA42 +# +# Moscow Social Card +2F87F74090D1 +E53EAEFE478F +CE2797E73070 +328A034B93DB +81E1529AE22B +FC55C50E579F +1A72E2337BC3 +5DB52676BE07 +F64FBF085098 +8FE758A8F039 +BB1484CC155D +41990A529AE2 +CD2E9EE62F77 +69C1327AC20B +3C9C0D559DE5 +67BF3880C811 +48A01159A1E9 +2B83FB448CD4 +F24BBB044C94 +94F46DB5FD46 +C31C8CD41D65 +BB1684CC155D +CA2393DB246C +1D75E52E76BE +81D9529AE223 +0159C9125AA2 +52AA1B6BB3FB +97EF60A8F031 +6FC73888D011 +3A92FA438BD3 +74CC3D85CD0E +025ACA1B63A3 +AF0878C81151 +9BFB6CB4FC45 +F750C0095199 +075FCF1860A8 +2686EE3F87C7 +277FEF3880C0 +82DA4B93DB1C +9CF46DB5FD46 +93EB64ACF43D +# +# Iron Logic RU +A3A26EF4C6B0 +2C3FEAAE99FC +E85B73382E1F +F4ED24C2B998 +CB574C6D3B19 +E092081D724B +B38D82CF7B6C +8228D2AA6EFA +2C7E983588A3 +CF7A7B77E232 +32A7F5EAF87D +7453A687B5F0 +01A0C008A5B9 +DEC0CEB0CE24 +413BED2AE45B +D6261A9A4B3F +CB9D507CE56D +# +# Armenian Underground Ticket +A0A1A2A8A4A5 +# +# Badge Maker Leaked from https://github.com/UberGuidoZ +1A1B1C1D1E1F +1665FE2AE945 +158B51947A8E +E167EC67C7FF +D537320FF90E +5E56BFA9E2C9 +F81CED821B63 +C81584EF5EDF +9551F8F9259D +36E1765CE3E8 +509052C8E42E +776C9B03BE71 +C608E13ADD50 +BEE8B345B949 +ED0EC56EEFDD +9716D5241E28 +05D1FC14DC31 +3321FB75A356 +F22A78E29880 +EC211D12C98D +8CCA8F62A551 +B637E46AD674 +39605B3C8917 +3882719778A1 +9F27D36C4230 +DB32A6811327 +8AA8544A2207 +8C5819E780A4 +7549E90353A2 +2E52ABE0CE95 +E46210ED98AB +61D030C0D7A8 +18E20102821E +DA59354DFB88 +040047C12B75 +D10008074A6F +686E736F6E20 +446176696453 +6F6674776172 +6520446F7665 +# +# Apartment keyfobs (USA) (Corvette830) +E60F8387F0B9 +FFD46FF6C5EE +4F9661ED2E70 +576A798C9904 +1C5179C4A8A1 +16CA203B811B +11AC8C8F3AF2 +# +# The Westin Jakarta Indonesia (D4DB0D) +# Peppers Hotel Unknown location (D4D0D) +6E0DD4136B0A +141940E9B71B +3B1D3AAC866E +95E9EE4CCF8F +FEA6B332F04A +BE0EC5155806 +0500D6BFCC4F +FC5AC7678BE3 +F09BB8DD142D +B4B3FFEDBE0A +540E0D2D1D08 +# +# Schlage 9691T Keyfob (seasnaill) +7579B671051A +4F4553746B41 +# +# Vigik ScanBadge App (fr.badgevigik.scanbadge) +# Website https://badge-vigik.fr/ (Alex) +0000A2B3C86F +021200C20307 +021209197507 +1E34B127AF9C +303041534956 +4143532D494E +41454E521985 +43412D627400 +455249524345 +456666456666 +45B722C63319 +484585414354 +4D414C414741 +536563644C65 +57D27B730760 +593DD8FE167A +6472616E7265 +65626F726369 +680E95F3C287 +709BA7D4F920 +8829DAD9AF76 +92D0A0999CBA +948EE7CFC9DB +9EB7C8A6D4E3 +A22AE12C9013 +AFC984A3576E +# +# Vigik verified by quantum-x +# https://github.com/RfidResearchGroup/proxmark3/pull/1742#issuecomment-1206113976 +A00027000099 +A00016000028 +A00003000028 +A0000F000345 +A00001000030 +A00002000086 +A00002000036 +A00002000088 +A00000000058 +A00000000096 +A00000000008 +A00000043D79 +A00000000064 +A00025000030 +A00003000057 +# +# BH USA 2013 conference +012279BAD3E5 +# +# iGuard Simple (and reverse) keys +AAAAAAFFFFFF +FFFFFFAAAAAA +# +# Random Hotel A Key Sec 0 Blk 3 - KABA Lock (VideoMan) +3111A3A303EB +# Transport system Uruguay - STM +# Shared key - sec 0 blk 3 +D144BD193063 +# +# Data from http://www.proxmark.org/forum/viewtopic.php?pid=45659#p45659 +3515AE068CAD +# +# Keys Catering +6A0D531DA1A7 +4BB29463DC29 +# +# Keys Swim +8627C10A7014 +453857395635 +# +# Unknown hotel system Sec 0 / A +353038383134 +# +# Brazil transport Sec 8 / A +50d4c54fcdf5 +# # Bandai Namco Passport [fka Banapassport] / Sega Aime Card +# Dumped on the Flipper Devices Discord Server 6090D00632F5 019761AA8082 574343467632 @@ -1351,7 +2207,551 @@ E69DD9015A43 C8382A233993 7B304F2A12A6 FC9418BF788B +# +# Guest Cashless Prepaid Arcade Payment Cards +168168168168 +198407157610 +4E4F584D2101 +4E4F584D2105 +686B35333376 +861861861861 +# +# Transport System Cracow / Polen +B071A76BA2E9 +B3A181BCA5F2 +3225942F7717 +80D00703C5FB +6DD510E080B1 +87529F30FC58 +B75C4FA614AE +42DC568C64F4 +# Data from "the more the marriott" mifare project (colonelborkmundus) +# aka The Horde +# +# These keys seem to be from Vingcard / Saflok system which means they are diversified +# and not static default keys. To verify this, the UID from such a card is needed. +# +# 20230125-01, Elite Member Marriott Rewards +43012BD9EB87 +# 20230125-02, Elite Member Marriott Rewards +3119A70628EB +# 20230125-03, Elite Member Marriott Rewards +23C9FDD9A366 +# 20230125-04, Elite Member Marriott Rewards +7B4DFC6D6525 +# 20230125-05, Elite Member Marriott Rewards +1330824CD356 +# 20230125-06, Elite Member Marriott Rewards +30AAD6A711EF +# 20230125-07, Fairfield Inn & Suites Marriott +7B3B589A5525 +# 20230125-08, Moxy Hotels +20C166C00ADB +# 20230125-09, Westin Hotels & Resorts +7D0A1C277C05 +2058580A941F +8C29F8320617 +# 20230125-10, Westin Hotels & Resorts +C40964215509 +D44CFC178460 +5697519A8F02 +# 20230125-12, AC Hotels Marriott +7B56B2B38725 +# 20230125-13, AC Hotels Marriott +8EA8EC3F2320 +# 20230125-14, Waldorf Astoria Chicago +011C6CF459E8 +# 20230125-24, Aria Resort & Casino +A18D9F4E75AF +# 20230125-25, Aria Resort & Casino +316B8FAA12EF +# 20230125-26, Residence Inn Mariott +3122AE5341EB +# 20230125-27, Residence Inn Mariott +F72CD208FDF9 +# 20230125-28, Marriott +035C70558D7B +# 20230125-29, Marriott +12AB4C37BB8B +# 20230125-30, Marriott +9966588CB9A0 +# 20230125-31, Sheraton +42FC522DE987 +# 20230125-32, The Industrialist +2158E314C3DF +# 20230125-39, The Ritz-Carlton Balharbour +30FB20D0EFEF +# 20230125-40, The Ritz-Carlton Balharbour +66A3B064CC4B +# 20230125-41, The Ritz-Carlton Balharbour +D18296CD9E6E +# 20230125-42, The Ritz-Carlton Balharbour +D20289CD9E6E +# 20230125-44, Graduate Hotels +209A2B910545 +C49DAE1C6049 +# 20230125-46, AmericInn +8AC04C1A4A25 +# 20230129-53, Marriott Bonvoy +6E029927600D +3E173F64C01C +C670A9AD6066 +# 20230413-69, Westin +487339FA02E0 +# 20230413-70, Marriott Bonvoy +DBD5CA4EE467 +A0B1F234006C +180DE12B700E +# 20230413-71, Westin +1352C68F7A56 +# 20230413-76, Ritz Carlton +318BD98C1CEF +# 20230413-77, Marriott +D23C1CB1216E +# 20230413-78, Caesars +A1D92F808CAF +# 20230413-79, The Cosmopolitan, Vegas +# 20230413-80, Aria +1153C319B4F8 +# 20230413-81, Aria +110C819BBEF8 +# 20230413-82, Aria +1332117E8756 +# 20230413-83, Kimpton +500AE915F50A +5032E362B484 +8B63AB712753 +# 20230413-85, Kimpton +06106E187106 +2E45C23DC541 +D9FF8BEE7550 +# 20230413-87, Marriott +42F7A186BF87 +# 20230413-88, Meritage Resort +D213B093B79A +# 20230413-89, Meritage Resort +216024C49EDF +# 20230413-90, Gaylord Palms +D201DBB6AB6E +# 20230413-91, Residence Inn +9F4AD875BB30 +# 20230413-92, Marriott +3352DB1E8777 +# 20230413-94, Marriott +09074A146605 +151F3E85EC46 +# +# Travelodge by Wyndham Berkeley +0000FFFFFFFF +4663ACD2FFFF +EDC317193709 +# Hotel Santa Cruz +75FAB77E2E5B +# saflok brand HOTEL key +32F093536677 +# A WaterFront Hotel in Oakland +3351916B5A77 +# Ballys (2018) +336E34CC2177 +# Random Hawaiian Hotel +A1670589B2AF +# SF Hotel (SoMa area) +2E0F00700000 +# +# Unknown PACS from Western Australia +CA80E51FA52B +A71E80EA35E1 +05597810D63D +# +# Hotel Key from Las Vegas +EA0CA627FD06 +80BB8436024C +5044068C5183 +# +# Key from Hotel M Montreal (probably diversified) +7E5E05866ED6 +661ABF99AFAD +# +# Key from evo Montreal (probably diversified) +1064BA5D6DF8 +# Hotel key +CE0F4F15E909 +D60DE9436219 +# +# ATM Area de Girona, spanish transport card +A01000000000 +A02000000000 +A03000000000 +A04000000000 +A05000000000 +A06000000000 +A07000000000 +A08000000000 +A09000000000 +A10000000000 +A11000000000 +A12000000000 +A13000000000 +A14000000000 +A15000000000 +B01000000000 +B02000000000 +B03000000000 +B04000000000 +B05000000000 +B06000000000 +B07000000000 +B08000000000 +B09000000000 +B10000000000 +B11000000000 +B12000000000 +B13000000000 +B14000000000 +B15000000000 +# +# Pittsburgh, PA, USA - Pittsburgh Regional Transit ConnectCard +A7AE4A5A33DC +6B857B568C10 +E2CE9A674CBE +A4896B2EBA4E +0724DF9AEDE8 +0E368FB140C1 +874EB25C8721 +5C313F4539CD +C5498606E0A8 +79C69F7EC7C0 +DA7DD0044DA2 +1B8189BD966B +765584147990 +4B7C7C315E6E +46CAAD12C524 +53BD03DEA5C9 +D2D72CB60F59 +14D258786538 +E2E89A375B36 +B3FA87DB0C45 +44D3B1561B34 +2817C6E02F97 +A513FF1232E9 +BD454BD52792 +391771654DC8 +5162797F8E1C +F700BD8E042D +3973ABFD8B66 +CE8BFF3728EE +09938D05DA78 +EACDA4DBE420 +EC2B9FD483CA +# +# Hotel Intelier Orange - Benicasim, Spain +# block 1 - key A +04256CFE0425 +# +# InsideWash Membership Card - Portugal +C18063858BB9 +# +# An apartment building in Sydney Olympic Park +13254608D0AB +24A2971BC0B2 +14264709D1AC +25A3981CC1B3 +1527480AD2AD +26A4991DC2B4 +1628490BD3AE +27A59A1EC3B5 +17294A0CD4AF +28A69B1FC4B6 +182A4B0DD5B0 +29A79C20C5B7 +192B4C0ED6B1 +2AA89D21C6B8 +1A2C4D0FD7B2 +2BA99E22C7B9 +1B2D4E10D8B3 +2CAA9F23C8BA +1C2E4F11D9B4 +2DABA024C9BB +1D2F5012DAB5 +2EACA125CABC +1E305113DBB6 +2FADA226CBBD +1F315214DCB7 +30AEA327CCBE +20325315DDB8 +31AFA428CDBF +21335416DEB9 +32B0A529CEC0 +22345517DFBA +33B1A62ACFC1 +# +# Universidade de São Paulo (USP) student card +17B50E38F1B0 +24E311F594CE +3794FBFB1A54 +43B229069F6A +4531952F765F +4943F2F35E0A +4985E681EF88 +4F56C88E0337 +710070E92C79 +8A036C5C35D4 +A027BD830A06 +D33673C19243 +D89A506542F2 +E5813CD228F1 +FAB943906E9C +# +# R.A.T.T transport card key A/B +AA034F342A55 +456776908C48 +# BusFacil - Brazilian public transport card for some cities +7b296f353c6b +3fa7217ec575 +fae9b14365a9 +c567dd4a6004 +c567dd4a6005 +c567dd4a6006 +c567dd4a6007 +c567dd4a6008 +c567dd4a6009 +c567dd4a600a +c567dd4a600d +c567dd4a600e +c567dd4a600f +5ef014ec5d7f +5086052022ac +bd6af9754c18 +5d67d4732a7d +17fe45604a04 +17fe45604a05 +17fe45604a06 +17fe45604a07 +17fe45604a08 +17fe45604a09 +17fe45604a0a +17fe45604a0d +17fe45604a0e +17fe45604a0f +# keys for swimming pool cards in Reykjavík Iceland +28220F14BEF0 +# key for Orkan keyfobs +300724070486 +# key for Atlantsolía keyfobs +60FCB3C42ABF +# key for hotel in greece +722F24F0722F +# STS Hotel 2A +535453535453 +# Public transport in Sofia, Bulgaria (SKGT) +# upgraded to DESFire since January 2024 +# SKGT common +# Sector 15, key A +f618b3d7855a +# Sector 15, key B +f1afa4da949f +# SKGT multi-use ticket +# Sector 0 +67362dace527 +633a010fa3c3 +# Sector 1 +f93c98655b9c +67ec0a47b0fb +# Sector 2 +54a028818ac7 +b2e87e53c5a0 +# Sector 3 +3e93cf0644b6 +79e12280e219 +# Sector 4 +2204b9fbf033 +4537fd238c8e +# Sector 5 +d1b44a9df05f +cfa526835a1f +# Sector 6 +21cc007ad81c +c097d0a85446 +# Sector 7 +d2268262710f +730bb7b8b3de +# Sector 8 +9fe7c5be7dff +61ae2d920c79 +# Sector 9 +78fcd4470c50 +b638caf7357b +# Sector 10 +0dc1dd7c8ea2 +4c6a6866b934 +# Sector 11 +03de2ceb2ea1 +93e0118b21ed +# Sector 12 +8fbced387bf4 +f57ca95c6edd +# Sector 13 +ef24fe3b4cf7 +8b44d303d62f +# Sector 14 +b1ea40b2caa6 +3abf8431003b +# Sector 15 - see above +# SKGT personalised subscription card +# Sector 0, 2, 16, key A +a0a1a2a3a4a5 +# Sector 8-14, 17-39, key A +ffffffffffff +# Sector 1, key A +# blue +f1df0ca8948b +# yellow +7747b4912984 +# Sector 3, key A +# blue +09d556d57a4b +# yellow +3ed158c6934e +# Sector 4-7, key A +# blue +839dedbfec0d +# yellow +c694a9ed2f9e +# Sector 15 - see above +# Sector 0, 16, key B (blue) +81d55f4551b9 +# Sector 0, key B (yellow) +6e9a040c3c91 +# Sector 1, key B +# blue +5b72c63fb416 +# yellow +a3cdced46371 +# Sector 2, key B +# blue +87a61433d026 +# yellow +9cd3a81f11ab +# Sector 3, key B +# blue +7070d331360c +# yellow +836c790f6e2c +# Sector 4-7, key B +# blue +7fe057787c4f +# yellow +ff59c6d13f88 +# Sector 8-14, 17-39, key B +536f6669614d +# Sector 15 - see above +# End of SKGT +# Hanoi Bus Rapid Transit - 1/2/3 A +AAAFBA10FC37 +C61F2C28DADF +23AACA30CBF2 +# +# Keys dumped from student ID (AGH Cracow - Poland), may be diversified +# Need to be verified +833E4F32589E +432D02DA59F3 +5C161CA2716F +F60B5F9666B8 +98EAC5321D2F +CC945E3FE5C4 +70783C436CF4 +2D186C7149A9 +5D60AC0939FC +93A5CE63C873 +87174550E900 +45675B25A3DA +F91750E629D5 +A3E662ABCDC8 +33D99E9FFA6A +FF7AABA39C61 +A8248C049BEA +C2AF731771C4 +9263B2E0DD80 +CE7FCCBBA5D8 +F8E385E5A2A0 +B27678B5C4AE +D68D7EBB9551 +7AB63F082328 +# +# Payment cards used by Eurest on certain campuses +7E2BC58168EB +# +# Shower cards provided by Seijsener +291A65CBEA7B +344A359BBAD9 +476572726974 +4D696368656C +4F3748E6C826 +69D40AF8B353 +72DEA10F21DF +74845AA8E3F1 +8C3C43EDCC55 +ACD30DFFB434 +D1A27C8EC5DF +F14D329CBDBE +# +# Hotel cards from Austria +AB287B3B4903 +7B0DEDA7E162 +# +#Metro Q transit cards from Huston, Texas +373B72D34B80 +BF3FFC245C9b +7D1D9E7CF8A7 +6A917BF357E6 +B1D461EC62CA +C6BECABEBE8A +66026782D435 +4547E34E40D9 +753897b99AAE +1C36761E8ABD +6D8FBD8CC524 +5A3274779706 +23F13602CC1A +511C1C2C9804 +F8B2B926555E +2593E37D9B2E +41A1F17EE990 +64DD48AEDE88 +7915ED4D9903 +D139DD71DB92 +216D97D46E88 +D9D1C447E427 +911E789433CB +93B43D689F85 +525A869053F1 +69B25667E0B4 +6AACA2D97645 +# UK London Office +435DF6296EC4 +2338B4913222 +# Acces card of students, and more in Occitanie, France +E9A553102EA5 +F982E971CFED +1F42AB9159EE +BBFB836A48B8 +B5D170B2E8F5 +E76978A05F10 +0B1A995DD007 +650DB9CEDB6B +13E54B4448B7 +3E3540C2C273 +A76152840117 +066CCC7666BC +3C0B3AC3AFA3 +CCB541598D72 +1988B5D48EC3 +892EEF0D30FB +0FE5CE5CC640 +# Volgograd (Russia) Volna transport cards keys +2B787A063D5D +D37C8F1793F7 # H World Hotel Chain Room Keys 543071543071 5F01015F0101 From 256c1a114013ff4a36487240b187c98b320ecbb1 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Tue, 17 Dec 2024 22:12:55 +0900 Subject: [PATCH 08/22] [FL-3917] Add the ability to send a signal once via RPC (#4000) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add the ability to send a signal once * Update protobuf * Fix sending infrared signals * Review changes * Update protobuf * Separate sending an IR signal once into a function * Update protobuf module --------- Co-authored-by: あく Co-authored-by: Georgii Surkov --- applications/main/infrared/infrared_app.c | 33 ++++++++++++++ applications/main/infrared/infrared_app_i.h | 14 ++++++ .../main/infrared/infrared_custom_event.h | 2 + .../main/infrared/scenes/infrared_scene_rpc.c | 43 +++++++++++++++++++ .../main/subghz/helpers/subghz_custom_event.h | 1 + .../main/subghz/scenes/subghz_scene_rpc.c | 37 ++++++++++++++++ applications/main/subghz/subghz.c | 3 ++ applications/services/rpc/rpc_app.c | 39 +++++++++++++++++ applications/services/rpc/rpc_app.h | 8 ++++ assets/protobuf | 2 +- 10 files changed, 181 insertions(+), 1 deletion(-) diff --git a/applications/main/infrared/infrared_app.c b/applications/main/infrared/infrared_app.c index a93fd766df3..c50039760c3 100644 --- a/applications/main/infrared/infrared_app.c +++ b/applications/main/infrared/infrared_app.c @@ -88,6 +88,19 @@ static void infrared_rpc_command_callback(const RpcAppSystemEvent* event, void* view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressIndex); } + } else if(event->type == RpcAppEventTypeButtonPressRelease) { + furi_assert( + event->data.type == RpcAppSystemEventDataTypeString || + event->data.type == RpcAppSystemEventDataTypeInt32); + if(event->data.type == RpcAppSystemEventDataTypeString) { + furi_string_set(infrared->button_name, event->data.string); + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressReleaseName); + } else { + infrared->app_state.current_button_index = event->data.i32; + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressReleaseIndex); + } } else if(event->type == RpcAppEventTypeButtonRelease) { view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonRelease); @@ -411,6 +424,26 @@ void infrared_tx_stop(InfraredApp* infrared) { infrared->app_state.last_transmit_time = furi_get_tick(); } +void infrared_tx_send_once(InfraredApp* infrared) { + if(infrared->app_state.is_transmitting) { + return; + } + + dolphin_deed(DolphinDeedIrSend); + infrared_signal_transmit(infrared->current_signal); +} + +InfraredErrorCode infrared_tx_send_once_button_index(InfraredApp* infrared, size_t button_index) { + furi_assert(button_index < infrared_remote_get_signal_count(infrared->remote)); + + InfraredErrorCode error = infrared_remote_load_signal( + infrared->remote, infrared->current_signal, infrared->app_state.current_button_index); + if(!INFRARED_ERROR_PRESENT(error)) { + infrared_tx_send_once(infrared); + } + + return error; +} void infrared_blocking_task_start(InfraredApp* infrared, FuriThreadCallback callback) { view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewLoading); furi_thread_set_callback(infrared->task_thread, callback); diff --git a/applications/main/infrared/infrared_app_i.h b/applications/main/infrared/infrared_app_i.h index 692cc967157..75d8502f26e 100644 --- a/applications/main/infrared/infrared_app_i.h +++ b/applications/main/infrared/infrared_app_i.h @@ -218,6 +218,20 @@ InfraredErrorCode infrared_tx_start_button_index(InfraredApp* infrared, size_t b */ void infrared_tx_stop(InfraredApp* infrared); +/** + * @brief Transmit the currently loaded signal once. + * + * @param[in,out] infrared pointer to the application instance. + */ +void infrared_tx_send_once(InfraredApp* infrared); + +/** + * @brief Load the signal under the given index and transmit it once. + * + * @param[in,out] infrared pointer to the application instance. + */ +InfraredErrorCode infrared_tx_send_once_button_index(InfraredApp* infrared, size_t button_index); + /** * @brief Start a blocking task in a separate thread. * diff --git a/applications/main/infrared/infrared_custom_event.h b/applications/main/infrared/infrared_custom_event.h index 02d9a276f17..2efc99f4b50 100644 --- a/applications/main/infrared/infrared_custom_event.h +++ b/applications/main/infrared/infrared_custom_event.h @@ -21,6 +21,8 @@ enum InfraredCustomEventType { InfraredCustomEventTypeRpcButtonPressName, InfraredCustomEventTypeRpcButtonPressIndex, InfraredCustomEventTypeRpcButtonRelease, + InfraredCustomEventTypeRpcButtonPressReleaseName, + InfraredCustomEventTypeRpcButtonPressReleaseIndex, InfraredCustomEventTypeRpcSessionClose, InfraredCustomEventTypeGpioTxPinChanged, diff --git a/applications/main/infrared/scenes/infrared_scene_rpc.c b/applications/main/infrared/scenes/infrared_scene_rpc.c index 8f9dc433881..35cd971d800 100644 --- a/applications/main/infrared/scenes/infrared_scene_rpc.c +++ b/applications/main/infrared/scenes/infrared_scene_rpc.c @@ -124,6 +124,49 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { rpc_system_app_confirm(infrared->rpc_ctx, result); + } else if( + event.event == InfraredCustomEventTypeRpcButtonPressReleaseName || + event.event == InfraredCustomEventTypeRpcButtonPressReleaseIndex) { + bool result = false; + + // Send the signal once and stop + if(rpc_state == InfraredRpcStateLoaded) { + if(event.event == InfraredCustomEventTypeRpcButtonPressReleaseName) { + const char* button_name = furi_string_get_cstr(infrared->button_name); + size_t index; + const bool index_found = + infrared_remote_get_signal_index(infrared->remote, button_name, &index); + app_state->current_button_index = index_found ? (signed)index : + InfraredButtonIndexNone; + FURI_LOG_D(TAG, "Sending signal with name \"%s\"", button_name); + } else { + FURI_LOG_D( + TAG, "Sending signal with index \"%ld\"", app_state->current_button_index); + } + if(infrared->app_state.current_button_index != InfraredButtonIndexNone) { + InfraredErrorCode error = infrared_tx_send_once_button_index( + infrared, app_state->current_button_index); + if(!INFRARED_ERROR_PRESENT(error)) { + const char* remote_name = infrared_remote_get_name(infrared->remote); + infrared_text_store_set(infrared, 0, "emulating\n%s", remote_name); + + infrared_scene_rpc_show(infrared); + result = true; + } else { + rpc_system_app_set_error_code( + infrared->rpc_ctx, RpcAppSystemErrorCodeInternalParse); + rpc_system_app_set_error_text( + infrared->rpc_ctx, "Cannot load button data"); + result = false; + } + } + } + + if(result) { + scene_manager_set_scene_state( + infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded); + } + rpc_system_app_confirm(infrared->rpc_ctx, result); } else if( event.event == InfraredCustomEventTypeRpcExit || event.event == InfraredCustomEventTypeRpcSessionClose || diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index fe2c08fc648..571f3feb9c9 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -49,6 +49,7 @@ typedef enum { SubGhzCustomEventSceneRpcLoad, SubGhzCustomEventSceneRpcButtonPress, SubGhzCustomEventSceneRpcButtonRelease, + SubGhzCustomEventSceneRpcButtonPressRelease, SubGhzCustomEventSceneRpcSessionClose, SubGhzCustomEventViewReceiverOK, diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index c1476746d4a..040a151140f 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -85,6 +85,43 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); rpc_system_app_confirm(subghz->rpc_ctx, result); + } else if(event.event == SubGhzCustomEventSceneRpcButtonPressRelease) { + bool result = false; + if(state == SubGhzRpcStateLoaded) { + switch( + subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) { + case SubGhzTxRxStartTxStateErrorOnlyRx: + rpc_system_app_set_error_code( + subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock); + rpc_system_app_set_error_text( + subghz->rpc_ctx, + "Transmission on this frequency is restricted in your region"); + break; + case SubGhzTxRxStartTxStateErrorParserOthers: + rpc_system_app_set_error_code( + subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse); + rpc_system_app_set_error_text( + subghz->rpc_ctx, "Error in protocol parameters description"); + break; + + default: //if(SubGhzTxRxStartTxStateOk) + result = true; + subghz_blink_start(subghz); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateTx); + break; + } + } + + // Stop transmission + if(state == SubGhzRpcStateTx) { + subghz_txrx_stop(subghz->txrx); + subghz_blink_stop(subghz); + result = true; + } + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); + rpc_system_app_confirm(subghz->rpc_ctx, result); } else if(event.event == SubGhzCustomEventSceneRpcLoad) { bool result = false; if(state == SubGhzRpcStateIdle) { diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 22e81f2eb71..b17a232a893 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -43,6 +43,9 @@ static void subghz_rpc_command_callback(const RpcAppSystemEvent* event, void* co } else if(event->type == RpcAppEventTypeButtonRelease) { view_dispatcher_send_custom_event( subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonRelease); + } else if(event->type == RpcAppEventTypeButtonPressRelease) { + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonPressRelease); } else { rpc_system_app_confirm(subghz->rpc_ctx, false); } diff --git a/applications/services/rpc/rpc_app.c b/applications/services/rpc/rpc_app.c index aa2a3f64fd6..2b9a6542d77 100644 --- a/applications/services/rpc/rpc_app.c +++ b/applications/services/rpc/rpc_app.c @@ -258,6 +258,41 @@ static void rpc_system_app_button_release(const PB_Main* request, void* context) } } +static void rpc_system_app_button_press_release(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(request->which_content == PB_Main_app_button_press_release_request_tag); + + RpcAppSystem* rpc_app = context; + furi_assert(rpc_app); + + if(rpc_app->callback) { + FURI_LOG_D(TAG, "ButtonPressRelease"); + + RpcAppSystemEvent event; + event.type = RpcAppEventTypeButtonPressRelease; + + if(strlen(request->content.app_button_press_release_request.args) != 0) { + event.data.type = RpcAppSystemEventDataTypeString; + event.data.string = request->content.app_button_press_release_request.args; + } else { + event.data.type = RpcAppSystemEventDataTypeInt32; + event.data.i32 = request->content.app_button_press_release_request.index; + } + + rpc_system_app_error_reset(rpc_app); + rpc_system_app_set_last_command(rpc_app, request->command_id, &event); + + rpc_app->callback(&event, rpc_app->callback_context); + + } else { + rpc_system_app_send_error_response( + rpc_app, + request->command_id, + PB_CommandStatus_ERROR_APP_NOT_RUNNING, + "ButtonPressRelease"); + } +} + static void rpc_system_app_get_error_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(request->which_content == PB_Main_app_get_error_request_tag); @@ -332,6 +367,7 @@ void rpc_system_app_confirm(RpcAppSystem* rpc_app, bool result) { rpc_app->last_event_type == RpcAppEventTypeLoadFile || rpc_app->last_event_type == RpcAppEventTypeButtonPress || rpc_app->last_event_type == RpcAppEventTypeButtonRelease || + rpc_app->last_event_type == RpcAppEventTypeButtonPressRelease || rpc_app->last_event_type == RpcAppEventTypeDataExchange); const uint32_t last_command_id = rpc_app->last_command_id; @@ -432,6 +468,9 @@ void* rpc_system_app_alloc(RpcSession* session) { rpc_handler.message_handler = rpc_system_app_button_release; rpc_add_handler(session, PB_Main_app_button_release_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_system_app_button_press_release; + rpc_add_handler(session, PB_Main_app_button_press_release_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_system_app_get_error_process; rpc_add_handler(session, PB_Main_app_get_error_request_tag, &rpc_handler); diff --git a/applications/services/rpc/rpc_app.h b/applications/services/rpc/rpc_app.h index aa6fd81cc81..377d9ccb345 100644 --- a/applications/services/rpc/rpc_app.h +++ b/applications/services/rpc/rpc_app.h @@ -90,6 +90,13 @@ typedef enum { * all activities to be conducted while a button is being pressed. */ RpcAppEventTypeButtonRelease, + /** + * @brief The client has informed the application that a button has been pressed and released. + * + * This command's meaning is application-specific, e.g. to perform an action + * once without repeating it. + */ + RpcAppEventTypeButtonPressRelease, /** * @brief The client has sent a byte array of arbitrary size. * @@ -162,6 +169,7 @@ void rpc_system_app_send_exited(RpcAppSystem* rpc_app); * - RpcAppEventTypeLoadFile * - RpcAppEventTypeButtonPress * - RpcAppEventTypeButtonRelease + * - RpcAppEventTypeButtonPressRelease * - RpcAppEventTypeDataExchange * * Not confirming these events will result in a client-side timeout. diff --git a/assets/protobuf b/assets/protobuf index 6c7c0d55e82..1c84fa48919 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 6c7c0d55e82cb89223cf4890a540af4cff837fa7 +Subproject commit 1c84fa48919cbb71d1cc65236fc0ee36740e24c6 From 99175796199ef4e0d6a166d3beb7db18c8fc071c Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Wed, 18 Dec 2024 21:23:29 +0200 Subject: [PATCH 09/22] Increase system stack's reserved memory size (#4025) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- targets/f7/stm32wb55xx_flash.ld | 2 +- targets/f7/stm32wb55xx_ram_fw.ld | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/f7/stm32wb55xx_flash.ld b/targets/f7/stm32wb55xx_flash.ld index 524da6fc327..ef61bb23887 100644 --- a/targets/f7/stm32wb55xx_flash.ld +++ b/targets/f7/stm32wb55xx_flash.ld @@ -3,7 +3,7 @@ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _stack_end = 0x20030000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ -_stack_size = 0x200; /* required amount of stack */ +_stack_size = 0x400; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K diff --git a/targets/f7/stm32wb55xx_ram_fw.ld b/targets/f7/stm32wb55xx_ram_fw.ld index f0e8ad678cd..93579788d00 100644 --- a/targets/f7/stm32wb55xx_ram_fw.ld +++ b/targets/f7/stm32wb55xx_ram_fw.ld @@ -3,7 +3,7 @@ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _stack_end = 0x20030000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ -_stack_size = 0x200; /* required amount of stack */ +_stack_size = 0x400; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K From 8d078e4b8cc7a3e2eb3aafc5f0a0055618511d26 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Thu, 19 Dec 2024 00:38:43 +0400 Subject: [PATCH 10/22] [FL-3927] FuriThread stdin (#3979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: FuriThread stdin * ci: fix f18 * feat: stdio callback context Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Co-authored-by: あく --- .../unit_tests/tests/furi/furi_stdio_test.c | 108 ++++++++++++++++++ .../debug/unit_tests/tests/furi/furi_test.c | 8 ++ applications/services/cli/cli.c | 10 +- applications/services/cli/cli_i.h | 3 +- applications/services/cli/cli_vcp.c | 9 +- furi/core/string.h | 8 +- furi/core/thread.c | 72 ++++++++++-- furi/core/thread.h | 59 +++++++++- lib/print/SConscript | 20 ++-- lib/print/wrappers.c | 47 +++++++- lib/print/wrappers.h | 6 + targets/f18/api_symbols.csv | 13 ++- targets/f7/api_symbols.csv | 13 ++- 13 files changed, 342 insertions(+), 34 deletions(-) create mode 100644 applications/debug/unit_tests/tests/furi/furi_stdio_test.c diff --git a/applications/debug/unit_tests/tests/furi/furi_stdio_test.c b/applications/debug/unit_tests/tests/furi/furi_stdio_test.c new file mode 100644 index 00000000000..94e2f613b6a --- /dev/null +++ b/applications/debug/unit_tests/tests/furi/furi_stdio_test.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include "../test.h" // IWYU pragma: keep + +#define TAG "StdioTest" + +#define CONTEXT_MAGIC ((void*)0xDEADBEEF) + +// stdin + +static char mock_in[256]; +static size_t mock_in_len, mock_in_pos; + +static void set_mock_in(const char* str) { + size_t len = strlen(str); + strcpy(mock_in, str); + mock_in_len = len; + mock_in_pos = 0; +} + +static size_t mock_in_cb(char* buffer, size_t size, FuriWait wait, void* context) { + UNUSED(wait); + furi_check(context == CONTEXT_MAGIC); + size_t remaining = mock_in_len - mock_in_pos; + size = MIN(remaining, size); + memcpy(buffer, mock_in + mock_in_pos, size); + mock_in_pos += size; + return size; +} + +void test_stdin(void) { + FuriThreadStdinReadCallback in_cb = furi_thread_get_stdin_callback(); + furi_thread_set_stdin_callback(mock_in_cb, CONTEXT_MAGIC); + char buf[256]; + + // plain in + set_mock_in("Hello, World!\n"); + fgets(buf, sizeof(buf), stdin); + mu_assert_string_eq("Hello, World!\n", buf); + mu_assert_int_eq(EOF, getchar()); + + // ungetc + ungetc('i', stdin); + ungetc('H', stdin); + fgets(buf, sizeof(buf), stdin); + mu_assert_string_eq("Hi", buf); + mu_assert_int_eq(EOF, getchar()); + + // ungetc + plain in + set_mock_in(" World"); + ungetc('i', stdin); + ungetc('H', stdin); + fgets(buf, sizeof(buf), stdin); + mu_assert_string_eq("Hi World", buf); + mu_assert_int_eq(EOF, getchar()); + + // partial plain in + set_mock_in("Hello, World!\n"); + fgets(buf, strlen("Hello") + 1, stdin); + mu_assert_string_eq("Hello", buf); + mu_assert_int_eq(',', getchar()); + fgets(buf, sizeof(buf), stdin); + mu_assert_string_eq(" World!\n", buf); + + furi_thread_set_stdin_callback(in_cb, CONTEXT_MAGIC); +} + +// stdout + +static FuriString* mock_out; +FuriThreadStdoutWriteCallback original_out_cb; + +static void mock_out_cb(const char* data, size_t size, void* context) { + furi_check(context == CONTEXT_MAGIC); + // there's no furi_string_cat_strn :( + for(size_t i = 0; i < size; i++) { + furi_string_push_back(mock_out, data[i]); + } +} + +static void assert_and_clear_mock_out(const char* expected) { + // return the original stdout callback for the duration of the check + // if the check fails, we don't want the error to end up in our buffer, + // we want to be able to see it! + furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC); + mu_assert_string_eq(expected, furi_string_get_cstr(mock_out)); + furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC); + + furi_string_reset(mock_out); +} + +void test_stdout(void) { + original_out_cb = furi_thread_get_stdout_callback(); + furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC); + mock_out = furi_string_alloc(); + + puts("Hello, World!"); + assert_and_clear_mock_out("Hello, World!\n"); + + printf("He"); + printf("llo!"); + fflush(stdout); + assert_and_clear_mock_out("Hello!"); + + furi_string_free(mock_out); + furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC); +} diff --git a/applications/debug/unit_tests/tests/furi/furi_test.c b/applications/debug/unit_tests/tests/furi/furi_test.c index 193a8124d98..f23be37a974 100644 --- a/applications/debug/unit_tests/tests/furi/furi_test.c +++ b/applications/debug/unit_tests/tests/furi/furi_test.c @@ -10,6 +10,8 @@ void test_furi_memmgr(void); void test_furi_event_loop(void); void test_errno_saving(void); void test_furi_primitives(void); +void test_stdin(void); +void test_stdout(void); static int foo = 0; @@ -52,6 +54,11 @@ MU_TEST(mu_test_furi_primitives) { test_furi_primitives(); } +MU_TEST(mu_test_stdio) { + test_stdin(); + test_stdout(); +} + MU_TEST_SUITE(test_suite) { MU_SUITE_CONFIGURE(&test_setup, &test_teardown); MU_RUN_TEST(test_check); @@ -61,6 +68,7 @@ MU_TEST_SUITE(test_suite) { MU_RUN_TEST(mu_test_furi_pubsub); MU_RUN_TEST(mu_test_furi_memmgr); MU_RUN_TEST(mu_test_furi_event_loop); + MU_RUN_TEST(mu_test_stdio); MU_RUN_TEST(mu_test_errno_saving); MU_RUN_TEST(mu_test_furi_primitives); } diff --git a/applications/services/cli/cli.c b/applications/services/cli/cli.c index 0d8f52c04ec..28ba417c261 100644 --- a/applications/services/cli/cli.c +++ b/applications/services/cli/cli.c @@ -431,9 +431,9 @@ void cli_session_open(Cli* cli, void* session) { cli->session = session; if(cli->session != NULL) { cli->session->init(); - furi_thread_set_stdout_callback(cli->session->tx_stdout); + furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL); } else { - furi_thread_set_stdout_callback(NULL); + furi_thread_set_stdout_callback(NULL, NULL); } furi_semaphore_release(cli->idle_sem); furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); @@ -447,7 +447,7 @@ void cli_session_close(Cli* cli) { cli->session->deinit(); } cli->session = NULL; - furi_thread_set_stdout_callback(NULL); + furi_thread_set_stdout_callback(NULL, NULL); furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); } @@ -461,9 +461,9 @@ int32_t cli_srv(void* p) { furi_record_create(RECORD_CLI, cli); if(cli->session != NULL) { - furi_thread_set_stdout_callback(cli->session->tx_stdout); + furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL); } else { - furi_thread_set_stdout_callback(NULL); + furi_thread_set_stdout_callback(NULL, NULL); } if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) { diff --git a/applications/services/cli/cli_i.h b/applications/services/cli/cli_i.h index d4cac6e7d92..d7351b9ffc3 100644 --- a/applications/services/cli/cli_i.h +++ b/applications/services/cli/cli_i.h @@ -28,8 +28,9 @@ struct CliSession { void (*init)(void); void (*deinit)(void); size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout); + size_t (*rx_stdin)(uint8_t* buffer, size_t size, uint32_t timeout, void* context); void (*tx)(const uint8_t* buffer, size_t size); - void (*tx_stdout)(const char* data, size_t size); + void (*tx_stdout)(const char* data, size_t size, void* context); bool (*is_connected)(void); }; diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index cdabaaa0544..aa399e78a29 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -242,6 +242,11 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) { return rx_cnt; } +static size_t cli_vcp_rx_stdin(uint8_t* data, size_t size, uint32_t timeout, void* context) { + UNUSED(context); + return cli_vcp_rx(data, size, timeout); +} + static void cli_vcp_tx(const uint8_t* buffer, size_t size) { furi_assert(vcp); furi_assert(buffer); @@ -267,7 +272,8 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) { VCP_DEBUG("tx %u end", size); } -static void cli_vcp_tx_stdout(const char* data, size_t size) { +static void cli_vcp_tx_stdout(const char* data, size_t size, void* context) { + UNUSED(context); cli_vcp_tx((const uint8_t*)data, size); } @@ -310,6 +316,7 @@ CliSession cli_vcp = { cli_vcp_init, cli_vcp_deinit, cli_vcp_rx, + cli_vcp_rx_stdin, cli_vcp_tx, cli_vcp_tx_stdout, cli_vcp_is_connected, diff --git a/furi/core/string.h b/furi/core/string.h index 84b8c6a2405..0d407356bc6 100644 --- a/furi/core/string.h +++ b/furi/core/string.h @@ -129,12 +129,12 @@ void furi_string_swap(FuriString* string_1, FuriString* string_2); /** Move string_2 content to string_1. * - * Set the string to the other one, and destroy the other one. + * Copy data from one string to another and destroy the source. * - * @param string_1 The FuriString instance 1 - * @param string_2 The FuriString instance 2 + * @param destination The destination FuriString + * @param source The source FuriString */ -void furi_string_move(FuriString* string_1, FuriString* string_2); +void furi_string_move(FuriString* destination, FuriString* source); /** Compute a hash for the string. * diff --git a/furi/core/thread.c b/furi/core/thread.c index fd576ea72bb..6e515795775 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -23,12 +23,17 @@ #define THREAD_MAX_STACK_SIZE (UINT16_MAX * sizeof(StackType_t)) -typedef struct FuriThreadStdout FuriThreadStdout; - -struct FuriThreadStdout { +typedef struct { FuriThreadStdoutWriteCallback write_callback; FuriString* buffer; -}; + void* context; +} FuriThreadStdout; + +typedef struct { + FuriThreadStdinReadCallback read_callback; + FuriString* unread_buffer; // output.buffer = furi_string_alloc(); + thread->input.unread_buffer = furi_string_alloc(); FuriThread* parent = NULL; if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { @@ -245,6 +252,7 @@ void furi_thread_free(FuriThread* thread) { } furi_string_free(thread->output.buffer); + furi_string_free(thread->input.unread_buffer); free(thread); } @@ -710,13 +718,22 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id) { static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size) { if(thread->output.write_callback != NULL) { - thread->output.write_callback(data, size); + thread->output.write_callback(data, size, thread->output.context); } else { furi_log_tx((const uint8_t*)data, size); } return size; } +static size_t + __furi_thread_stdin_read(FuriThread* thread, char* data, size_t size, FuriWait timeout) { + if(thread->input.read_callback != NULL) { + return thread->input.read_callback(data, size, timeout, thread->input.context); + } else { + return 0; + } +} + static int32_t __furi_thread_stdout_flush(FuriThread* thread) { FuriString* buffer = thread->output.buffer; size_t size = furi_string_size(buffer); @@ -727,17 +744,31 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) { return 0; } -void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { +FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void) { + FuriThread* thread = furi_thread_get_current(); + furi_check(thread); + return thread->output.write_callback; +} + +FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void) { + FuriThread* thread = furi_thread_get_current(); + furi_check(thread); + return thread->input.read_callback; +} + +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback, void* context) { FuriThread* thread = furi_thread_get_current(); furi_check(thread); __furi_thread_stdout_flush(thread); thread->output.write_callback = callback; + thread->output.context = context; } -FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void) { +void furi_thread_set_stdin_callback(FuriThreadStdinReadCallback callback, void* context) { FuriThread* thread = furi_thread_get_current(); furi_check(thread); - return thread->output.write_callback; + thread->input.read_callback = callback; + thread->input.context = context; } size_t furi_thread_stdout_write(const char* data, size_t size) { @@ -772,6 +803,31 @@ int32_t furi_thread_stdout_flush(void) { return __furi_thread_stdout_flush(thread); } +size_t furi_thread_stdin_read(char* buffer, size_t size, FuriWait timeout) { + FuriThread* thread = furi_thread_get_current(); + furi_check(thread); + + size_t from_buffer = MIN(furi_string_size(thread->input.unread_buffer), size); + size_t from_input = size - from_buffer; + size_t from_input_actual = + __furi_thread_stdin_read(thread, buffer + from_buffer, from_input, timeout); + memcpy(buffer, furi_string_get_cstr(thread->input.unread_buffer), from_buffer); + furi_string_right(thread->input.unread_buffer, from_buffer); + + return from_buffer + from_input_actual; +} + +void furi_thread_stdin_unread(char* buffer, size_t size) { + FuriThread* thread = furi_thread_get_current(); + furi_check(thread); + + FuriString* new_buf = furi_string_alloc(); // there's no furi_string_alloc_set_strn :( + furi_string_set_strn(new_buf, buffer, size); + furi_string_cat(new_buf, thread->input.unread_buffer); + furi_string_free(thread->input.unread_buffer); + thread->input.unread_buffer = new_buf; +} + void furi_thread_suspend(FuriThreadId thread_id) { furi_check(thread_id); diff --git a/furi/core/thread.h b/furi/core/thread.h index ed7aa4553b0..9abfde5cd85 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -74,8 +74,23 @@ typedef int32_t (*FuriThreadCallback)(void* context); * * @param[in] data pointer to the data to be written to the standard out * @param[in] size size of the data in bytes + * @param[in] context optional context */ -typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size); +typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size, void* context); + +/** + * @brief Standard input callback function pointer type + * + * The function to be used as a standard input callback MUST follow this signature. + * + * @param[out] buffer buffer to read data into + * @param[in] size maximum number of bytes to read into the buffer + * @param[in] timeout how long to wait for (in ticks) before giving up + * @param[in] context optional context + * @returns number of bytes that was actually read into the buffer + */ +typedef size_t ( + *FuriThreadStdinReadCallback)(char* buffer, size_t size, FuriWait timeout, void* context); /** * @brief State change callback function pointer type. @@ -468,13 +483,30 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); */ FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void); +/** + * @brief Get the standard input callback for the current thead. + * + * @return pointer to the standard in callback function + */ +FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void); + /** Set standard output callback for the current thread. * * @param[in] callback pointer to the callback function or NULL to clear + * @param[in] context context to be passed to the callback */ -void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback, void* context); + +/** Set standard input callback for the current thread. + * + * @param[in] callback pointer to the callback function or NULL to clear + * @param[in] context context to be passed to the callback + */ +void furi_thread_set_stdin_callback(FuriThreadStdinReadCallback callback, void* context); /** Write data to buffered standard output. + * + * @note You can also use the standard C `putc`, `puts`, `printf` and friends. * * @param[in] data pointer to the data to be written * @param[in] size data size in bytes @@ -489,6 +521,29 @@ size_t furi_thread_stdout_write(const char* data, size_t size); */ int32_t furi_thread_stdout_flush(void); +/** Read data from the standard input + * + * @note You can also use the standard C `getc`, `gets` and friends. + * + * @param[in] buffer pointer to the buffer to read data into + * @param[in] size how many bytes to read into the buffer + * @param[in] timeout how long to wait for (in ticks) before giving up + * @return number of bytes that was actually read + */ +size_t furi_thread_stdin_read(char* buffer, size_t size, FuriWait timeout); + +/** Puts data back into the standard input buffer + * + * `furi_thread_stdin_read` will return the bytes in the same order that they + * were supplied to this function. + * + * @note You can also use the standard C `ungetc`. + * + * @param[in] buffer pointer to the buffer to get data from + * @param[in] size how many bytes to read from the buffer + */ +void furi_thread_stdin_unread(char* buffer, size_t size); + /** * @brief Suspend a thread. * diff --git a/lib/print/SConscript b/lib/print/SConscript index 07be8d890e1..90028cf06a1 100644 --- a/lib/print/SConscript +++ b/lib/print/SConscript @@ -44,18 +44,24 @@ wrapped_fn_list = [ "vsiprintf", "vsniprintf", # - # Scanf is not implemented 4 now + # standard input + # + "fgetc", + "getc", + "getchar", + "fgets", + "ungetc", + # + # standard input, but unimplemented + # + "gets", + # + # scanf, not implemented for now # # "fscanf", # "scanf", # "sscanf", # "vsprintf", - # "fgetc", - # "fgets", - # "getc", - # "getchar", - # "gets", - # "ungetc", # "vfscanf", # "vscanf", # "vsscanf", diff --git a/lib/print/wrappers.c b/lib/print/wrappers.c index c8d72d19285..18df92def8c 100644 --- a/lib/print/wrappers.c +++ b/lib/print/wrappers.c @@ -51,11 +51,54 @@ int __wrap_snprintf(char* str, size_t size, const char* format, ...) { } int __wrap_fflush(FILE* stream) { - UNUSED(stream); - furi_thread_stdout_flush(); + if(stream == stdout) furi_thread_stdout_flush(); return 0; } +int __wrap_fgetc(FILE* stream) { + if(stream != stdin) return EOF; + char c; + if(furi_thread_stdin_read(&c, 1, FuriWaitForever) == 0) return EOF; + return c; +} + +int __wrap_getc(FILE* stream) { + return __wrap_fgetc(stream); +} + +int __wrap_getchar(void) { + return __wrap_fgetc(stdin); +} + +char* __wrap_fgets(char* str, size_t n, FILE* stream) { + // leave space for the zero terminator + furi_check(n >= 1); + n--; + + if(stream != stdin) { + *str = '\0'; + return str; + } + + // read characters + int c; + do { + c = __wrap_fgetc(stdin); + if(c > 0) *(str++) = c; + } while(c != EOF && c != '\n' && --n); + + // place zero terminator + *str = '\0'; + return str; +} + +int __wrap_ungetc(int ch, FILE* stream) { + char c = ch; + if(stream != stdin) return EOF; + furi_thread_stdin_unread(&c, 1); + return ch; +} + __attribute__((__noreturn__)) void __wrap___assert(const char* file, int line, const char* e) { UNUSED(file); UNUSED(line); diff --git a/lib/print/wrappers.h b/lib/print/wrappers.h index 3cec88249a2..8a4599b4174 100644 --- a/lib/print/wrappers.h +++ b/lib/print/wrappers.h @@ -16,6 +16,12 @@ int __wrap_putc(int ch, FILE* stream); int __wrap_snprintf(char* str, size_t size, const char* format, ...); int __wrap_fflush(FILE* stream); +int __wrap_fgetc(FILE* stream); +int __wrap_getc(FILE* stream); +int __wrap_getchar(void); +char* __wrap_fgets(char* str, size_t n, FILE* stream); +int __wrap_ungetc(int ch, FILE* stream); + __attribute__((__noreturn__)) void __wrap___assert(const char* file, int line, const char* e); __attribute__((__noreturn__)) void diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index b5d51a0dd5c..23421712d01 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,78.1,, +Version,+,79.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -371,11 +371,16 @@ Function,-,__utoa,char*,"unsigned, char*, int" Function,+,__wrap___assert,void,"const char*, int, const char*" Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*" Function,+,__wrap_fflush,int,FILE* +Function,+,__wrap_fgetc,int,FILE* +Function,+,__wrap_fgets,char*,"char*, size_t, FILE*" +Function,+,__wrap_getc,int,FILE* +Function,+,__wrap_getchar,int, Function,+,__wrap_printf,int,"const char*, ..." Function,+,__wrap_putc,int,"int, FILE*" Function,+,__wrap_putchar,int,int Function,+,__wrap_puts,int,const char* Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..." +Function,+,__wrap_ungetc,int,"int, FILE*" Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list" Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..." Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..." @@ -1654,6 +1659,7 @@ Function,+,furi_thread_get_return_code,int32_t,FuriThread* Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* +Function,+,furi_thread_get_stdin_callback,FuriThreadStdinReadCallback, Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, Function,+,furi_thread_is_suspended,_Bool,FuriThreadId Function,+,furi_thread_join,_Bool,FuriThread* @@ -1674,9 +1680,12 @@ Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCa Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdin_callback,void,"FuriThreadStdinReadCallback, void*" +Function,+,furi_thread_set_stdout_callback,void,"FuriThreadStdoutWriteCallback, void*" Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*" Function,+,furi_thread_start,void,FuriThread* +Function,+,furi_thread_stdin_read,size_t,"char*, size_t, FuriWait" +Function,+,furi_thread_stdin_unread,void,"char*, size_t" Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" Function,+,furi_thread_suspend,void,FuriThreadId diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index ee81f76a97a..6f9fc5466e6 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,78.1,, +Version,+,79.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -448,11 +448,16 @@ Function,-,__utoa,char*,"unsigned, char*, int" Function,+,__wrap___assert,void,"const char*, int, const char*" Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*" Function,+,__wrap_fflush,int,FILE* +Function,+,__wrap_fgetc,int,FILE* +Function,+,__wrap_fgets,char*,"char*, size_t, FILE*" +Function,+,__wrap_getc,int,FILE* +Function,+,__wrap_getchar,int, Function,+,__wrap_printf,int,"const char*, ..." Function,+,__wrap_putc,int,"int, FILE*" Function,+,__wrap_putchar,int,int Function,+,__wrap_puts,int,const char* Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..." +Function,+,__wrap_ungetc,int,"int, FILE*" Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list" Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..." Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..." @@ -1873,6 +1878,7 @@ Function,+,furi_thread_get_return_code,int32_t,FuriThread* Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* +Function,+,furi_thread_get_stdin_callback,FuriThreadStdinReadCallback, Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, Function,+,furi_thread_is_suspended,_Bool,FuriThreadId Function,+,furi_thread_join,_Bool,FuriThread* @@ -1893,9 +1899,12 @@ Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCa Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdin_callback,void,"FuriThreadStdinReadCallback, void*" +Function,+,furi_thread_set_stdout_callback,void,"FuriThreadStdoutWriteCallback, void*" Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*" Function,+,furi_thread_start,void,FuriThread* +Function,+,furi_thread_stdin_read,size_t,"char*, size_t, FuriWait" +Function,+,furi_thread_stdin_unread,void,"char*, size_t" Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" Function,+,furi_thread_suspend,void,FuriThreadId From 8c4922a32212a47b25fde268365cd0068003fbdc Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Wed, 18 Dec 2024 22:55:21 +0200 Subject: [PATCH 11/22] Update `infrared_test.c` reference (#3983) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emmanuel Ferdman Co-authored-by: あく --- documentation/UnitTests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/UnitTests.md b/documentation/UnitTests.md index 9711c6ae175..5d04c8f67d7 100644 --- a/documentation/UnitTests.md +++ b/documentation/UnitTests.md @@ -43,7 +43,7 @@ To add unit tests for your protocol, follow these steps: 1. Create a file named `test_.irtest` in the [assets](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/debug/unit_tests/resources/unit_tests/infrared) directory. 2. Fill it with the test data (more on it below). -3. Add the test code to [infrared_test.c](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/applications/debug/unit_tests/infrared/infrared_test.c). +3. Add the test code to [infrared_test.c](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/applications/debug/unit_tests/tests/infrared/infrared_test.c). 4. Build and install firmware with resources, install it on your Flipper and run the tests to see if they pass. ##### Test data format From 9c96bbfc540b0719cb58095e88fb9dc06b5c61d2 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Thu, 19 Dec 2024 00:01:20 +0300 Subject: [PATCH 12/22] [NFC] Fix ISO15693 stucking in wrong mode. (#3988) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/signal_reader/parsers/iso15693/iso15693_parser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/signal_reader/parsers/iso15693/iso15693_parser.c b/lib/signal_reader/parsers/iso15693/iso15693_parser.c index a2c6912e637..e47c734a279 100644 --- a/lib/signal_reader/parsers/iso15693/iso15693_parser.c +++ b/lib/signal_reader/parsers/iso15693/iso15693_parser.c @@ -243,6 +243,8 @@ static Iso15693ParserCommand iso15693_parser_parse_1_out_of_256(Iso15693Parser* instance->parsed_frame, instance->next_byte_part * 4 + j / 2); } } + } else { + instance->zero_found = true; } } instance->next_byte_part = (instance->next_byte_part + 1) % 64; From a7b3a135815f403006b52ba55d7e82234378a596 Mon Sep 17 00:00:00 2001 From: WillyJL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:33:59 +0100 Subject: [PATCH 13/22] Loader: Fix BusFault in handling of OOM (#3992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Loader: Fix BusFault in handling of OOM * Furi: fix crash in aligned_alloc, cleanup aligned_alloc use Co-authored-by: あく --- furi/core/memmgr.c | 4 +++- lib/flipper_application/elf/elf_file.c | 12 +++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index d3ff873ae50..8ee0d1723b7 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -106,5 +106,7 @@ void* aligned_malloc(size_t size, size_t alignment) { } void aligned_free(void* p) { - free(((void**)p)[-1]); + if(p) { + free(((void**)p)[-1]); + } } diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index d0c4f52fb1f..bd8ecdf7ef3 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -8,11 +8,11 @@ #define TAG "Elf" -#define ELF_NAME_BUFFER_LEN 32 -#define SECTION_OFFSET(e, n) ((e)->section_table + (n) * sizeof(Elf32_Shdr)) -#define IS_FLAGS_SET(v, m) (((v) & (m)) == (m)) +#define ELF_NAME_BUFFER_LEN 32 +#define SECTION_OFFSET(e, n) ((e)->section_table + (n) * sizeof(Elf32_Shdr)) +#define IS_FLAGS_SET(v, m) (((v) & (m)) == (m)) #define RESOLVER_THREAD_YIELD_STEP 30 -#define FAST_RELOCATION_VERSION 1 +#define FAST_RELOCATION_VERSION 1 // #define ELF_DEBUG_LOG 1 @@ -830,9 +830,7 @@ void elf_file_free(ELFFile* elf) { for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); ELFSectionDict_next(it)) { const ELFSectionDict_itref_t* itref = ELFSectionDict_cref(it); - if(itref->value.data) { - aligned_free(itref->value.data); - } + aligned_free(itref->value.data); if(itref->value.fast_rel) { aligned_free(itref->value.fast_rel->data); free(itref->value.fast_rel); From 8dd5e64c0384edf93f33eaf01fce412c38a3858d Mon Sep 17 00:00:00 2001 From: Evgeny E <10674163+ssecsd@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:52:37 +0000 Subject: [PATCH 14/22] Move updater and unit tests to dockerized runner (#4028) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * extended unit_tests and changed to dockerized runner * added branch to run units * fixing unit-tests-output * online output * command not found fix * added stm logging * cleaned output * Updated updater test to work on dockerized runner * Test run for changed actions * small refactor of run_unit_tests * Final test of jobs * Checked * On-failure actions runs only on fail * Set action trigger to pull request * Bumped timeout a little * Removed extra steps * Removed stm monitor, as it's now part of docker-runner * fix: testops without stm_monitoring * fix: timeout extended Co-authored-by: あく --- .github/workflows/unit_tests.yml | 48 ++++----- .github/workflows/updater_test.yml | 54 ++-------- scripts/testops.py | 156 +++++++++++++++++++---------- 3 files changed, 131 insertions(+), 127 deletions(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index d37337452a9..309dd7ebd4b 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -5,54 +5,39 @@ on: env: TARGETS: f7 DEFAULT_TARGET: f7 - FBT_TOOLCHAIN_PATH: /opt + FBT_TOOLCHAIN_PATH: /opt/ FBT_GIT_SUBMODULE_SHALLOW: 1 jobs: run_units_on_bench: - runs-on: [self-hosted, FlipperZeroUnitTest] + runs-on: [ self-hosted, FlipperZeroTest ] steps: - - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 1 ref: ${{ github.event.pull_request.head.sha }} - - name: 'Get flipper from device manager (mock)' - id: device - run: | - echo "flipper=auto" >> $GITHUB_OUTPUT - - name: 'Flash unit tests firmware' id: flashing if: success() - timeout-minutes: 10 - run: | - ./fbt resources firmware_latest flash SWD_TRANSPORT_SERIAL=2A0906016415303030303032 LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 - - - name: 'Wait for flipper and format ext' - id: format_ext - if: steps.flashing.outcome == 'success' - timeout-minutes: 5 + timeout-minutes: 20 run: | source scripts/toolchain/fbtenv.sh - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=120 await_flipper - python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext + ./fbt resources firmware_latest flash LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 + - name: 'Copy assets and unit data, reboot and wait for flipper' id: copy - if: steps.format_ext.outcome == 'success' + if: steps.flashing.outcome == 'success' timeout-minutes: 7 run: | source scripts/toolchain/fbtenv.sh - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=15 await_flipper - rm -rf build/latest/resources/dolphin - python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send build/latest/resources /ext - python3 scripts/power.py -p ${{steps.device.outputs.flipper}} reboot - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=15 await_flipper + python3 scripts/testops.py -t=15 await_flipper + python3 scripts/storage.py -f send build/latest/resources /ext + python3 scripts/storage.py -f send /region_data /ext/.int/.region_data + python3 scripts/power.py reboot + python3 scripts/testops.py -t=30 await_flipper - name: 'Run units and validate results' id: run_units @@ -60,9 +45,16 @@ jobs: timeout-minutes: 7 run: | source scripts/toolchain/fbtenv.sh - python3 scripts/testops.py run_units -p ${{steps.device.outputs.flipper}} + python3 scripts/testops.py run_units + + - name: 'Upload test results' + if: failure() && steps.flashing.outcome == 'success' && steps.run_units.outcome != 'skipped' + uses: actions/upload-artifact@v4 + with: + name: unit-tests_output + path: unit_tests*.txt - name: 'Check GDB output' if: failure() && steps.flashing.outcome == 'success' run: | - ./fbt gdb_trace_all SWD_TRANSPORT_SERIAL=2A0906016415303030303032 LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 + ./fbt gdb_trace_all LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index dbe5df883d6..59cc6e716be 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -1,39 +1,31 @@ name: 'Updater test' on: pull_request: + env: TARGETS: f7 DEFAULT_TARGET: f7 - FBT_TOOLCHAIN_PATH: /opt + FBT_TOOLCHAIN_PATH: /opt/ FBT_GIT_SUBMODULE_SHALLOW: 1 jobs: test_updater_on_bench: - runs-on: [self-hosted, FlipperZeroUpdaterTest] + runs-on: [self-hosted, FlipperZeroTest ] steps: - - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 1 - submodules: false ref: ${{ github.event.pull_request.head.sha }} - - name: 'Get flipper from device manager (mock)' - id: device - run: | - echo "flipper=auto" >> $GITHUB_OUTPUT - echo "stlink=0F020D026415303030303032" >> $GITHUB_OUTPUT - - name: 'Flashing target firmware' id: first_full_flash - timeout-minutes: 10 + timeout-minutes: 20 run: | source scripts/toolchain/fbtenv.sh - ./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1 - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=180 await_flipper + python3 scripts/testops.py -t=180 await_flipper + ./fbt flash_usb_full FORCE=1 + - name: 'Validating updater' id: second_full_flash @@ -41,33 +33,7 @@ jobs: if: success() run: | source scripts/toolchain/fbtenv.sh - ./fbt flash_usb PORT=${{steps.device.outputs.flipper}} FORCE=1 - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=180 await_flipper - - - name: 'Get last release tag' - id: release_tag - if: failure() - run: | - echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT - - - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; + python3 scripts/testops.py -t=180 await_flipper + ./fbt flash_usb FORCE=1 + python3 scripts/testops.py -t=180 await_flipper - - name: 'Checkout latest release' - uses: actions/checkout@v4 - if: failure() - with: - fetch-depth: 1 - ref: ${{ steps.release_tag.outputs.tag }} - - - name: 'Flash last release' - if: failure() - run: | - ./fbt flash SWD_TRANSPORT_SERIAL=${{steps.device.outputs.stlink}} FORCE=1 - - - name: 'Wait for flipper and format ext' - if: failure() - run: | - source scripts/toolchain/fbtenv.sh - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=180 await_flipper - python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext diff --git a/scripts/testops.py b/scripts/testops.py index 4ae10c7f4ae..3100a9b7fe7 100644 --- a/scripts/testops.py +++ b/scripts/testops.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 - import re -import sys import time +from datetime import datetime from typing import Optional from flipper.app import App @@ -11,7 +10,10 @@ class Main(App): - # this is basic use without sub-commands, simply to reboot flipper / power it off, not meant as a full CLI wrapper + def __init__(self, no_exit=False): + super().__init__(no_exit) + self.test_results = None + def init(self): self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") self.parser.add_argument( @@ -67,64 +69,108 @@ def run_units(self): self.logger.info("Running unit tests") flipper.send("unit_tests" + "\r") self.logger.info("Waiting for unit tests to complete") - data = flipper.read.until(">: ") - self.logger.info("Parsing result") - - lines = data.decode().split("\r\n") - - tests_re = r"Failed tests: \d{0,}" - time_re = r"Consumed: \d{0,}" - leak_re = r"Leaked: \d{0,}" - status_re = r"Status: \w{3,}" - - tests_pattern = re.compile(tests_re) - time_pattern = re.compile(time_re) - leak_pattern = re.compile(leak_re) - status_pattern = re.compile(status_re) tests, elapsed_time, leak, status = None, None, None, None total = 0 - - for line in lines: - self.logger.info(line) - if "()" in line: - total += 1 - - if not tests: - tests = re.match(tests_pattern, line) - if not elapsed_time: - elapsed_time = re.match(time_pattern, line) - if not leak: - leak = re.match(leak_pattern, line) - if not status: - status = re.match(status_pattern, line) - - if None in (tests, elapsed_time, leak, status): - self.logger.error( - f"Failed to parse output: {tests} {elapsed_time} {leak} {status}" + all_required_found = False + + full_output = [] + + tests_pattern = re.compile(r"Failed tests: \d{0,}") + time_pattern = re.compile(r"Consumed: \d{0,}") + leak_pattern = re.compile(r"Leaked: \d{0,}") + status_pattern = re.compile(r"Status: \w{3,}") + + try: + while not all_required_found: + try: + line = flipper.read.until("\r\n", cut_eol=True).decode() + self.logger.info(line) + if "command not found," in line: + self.logger.error(f"Command not found: {line}") + return 1 + + if "()" in line: + total += 1 + self.logger.debug(f"Test completed: {line}") + + if not tests: + tests = tests_pattern.match(line) + if not elapsed_time: + elapsed_time = time_pattern.match(line) + if not leak: + leak = leak_pattern.match(line) + if not status: + status = status_pattern.match(line) + + pattern = re.compile( + r"(\[-]|\[\\]|\[\|]|\[/-]|\[[^\]]*\]|\x1b\[\d+D)" + ) + line_to_append = pattern.sub("", line) + pattern = re.compile(r"\[3D[^\]]*") + line_to_append = pattern.sub("", line_to_append) + line_to_append = f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S,%f')} {line_to_append}" + + full_output.append(line_to_append) + + if tests and elapsed_time and leak and status: + all_required_found = True + try: + remaining = flipper.read.until(">: ", cut_eol=True).decode() + if remaining.strip(): + full_output.append(remaining) + except: + pass + break + + except Exception as e: + self.logger.error(f"Error reading output: {e}") + raise + + if None in (tests, elapsed_time, leak, status): + raise RuntimeError( + f"Failed to parse output: {tests} {elapsed_time} {leak} {status}" + ) + + leak = int(re.findall(r"[- ]\d+", leak.group(0))[0]) + status = re.findall(r"\w+", status.group(0))[1] + tests = int(re.findall(r"\d+", tests.group(0))[0]) + elapsed_time = int(re.findall(r"\d+", elapsed_time.group(0))[0]) + + test_results = { + "full_output": "\n".join(full_output), + "total_tests": total, + "failed_tests": tests, + "elapsed_time_ms": elapsed_time, + "memory_leak_bytes": leak, + "status": status, + } + + self.test_results = test_results + + output_file = "unit_tests_output.txt" + with open(output_file, "w") as f: + f.write(test_results["full_output"]) + + print( + f"::notice:: Total tests: {total} Failed tests: {tests} Status: {status} Elapsed time: {elapsed_time / 1000} s Memory leak: {leak} bytes" ) - sys.exit(1) - - leak = int(re.findall(r"[- ]\d+", leak.group(0))[0]) - status = re.findall(r"\w+", status.group(0))[1] - tests = int(re.findall(r"\d+", tests.group(0))[0]) - elapsed_time = int(re.findall(r"\d+", elapsed_time.group(0))[0]) - - if tests > 0 or status != "PASSED": - self.logger.error(f"Got {tests} failed tests.") - self.logger.error(f"Leaked (not failing on this stat): {leak}") - self.logger.error(f"Status: {status}") - self.logger.error(f"Time: {elapsed_time/1000} seconds") - flipper.stop() - return 1 - self.logger.info(f"Leaked (not failing on this stat): {leak}") - self.logger.info( - f"Tests ran successfully! Time elapsed {elapsed_time/1000} seconds. Passed {total} tests." - ) + if tests > 0 or status != "PASSED": + self.logger.error(f"Got {tests} failed tests.") + self.logger.error(f"Leaked (not failing on this stat): {leak}") + self.logger.error(f"Status: {status}") + self.logger.error(f"Time: {elapsed_time / 1000} seconds") + return 1 - flipper.stop() - return 0 + self.logger.info(f"Leaked (not failing on this stat): {leak}") + self.logger.info( + f"Tests ran successfully! Time elapsed {elapsed_time / 1000} seconds. Passed {total} tests." + ) + return 0 + + finally: + flipper.stop() if __name__ == "__main__": From a02781b93687086f546df1a48f7f0ca3f7724c5a Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Mon, 23 Dec 2024 09:18:14 +0900 Subject: [PATCH 15/22] [FL-3920] Fix lost BadBLE keystrokes (#3993) * WIP: fix lost BadBLE keystrokes * Switch to semaphores for synchronization * Move checking to the gap level * Remove leftovers from hid_service * Remove more leftovers from hid_service * De-allocate the semaphore after use * Change the timeout to account for unforeseen situation * Update F18 API * Fix naming and unbump api version * Move away from semaphores * Remove the left over include * Ble: cleanup error handling in ble_gatt_characteristic_update * Fix PVS warning Co-authored-by: Aleksandr Kutuzov --- lib/ble_profile/extra_services/hid_service.c | 14 ++++---- lib/nfc/protocols/mf_plus/mf_plus_poller.c | 4 +-- lib/subghz/protocols/bin_raw.c | 2 +- targets/f7/ble_glue/furi_ble/gatt.c | 34 +++++++++++++++++--- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/lib/ble_profile/extra_services/hid_service.c b/lib/ble_profile/extra_services/hid_service.c index e46d2010c52..9f9a0f7520e 100644 --- a/lib/ble_profile/extra_services/hid_service.c +++ b/lib/ble_profile/extra_services/hid_service.c @@ -10,13 +10,13 @@ #define TAG "BleHid" #define BLE_SVC_HID_REPORT_MAP_MAX_LEN (255) -#define BLE_SVC_HID_REPORT_MAX_LEN (255) -#define BLE_SVC_HID_REPORT_REF_LEN (2) -#define BLE_SVC_HID_INFO_LEN (4) -#define BLE_SVC_HID_CONTROL_POINT_LEN (1) +#define BLE_SVC_HID_REPORT_MAX_LEN (255) +#define BLE_SVC_HID_REPORT_REF_LEN (2) +#define BLE_SVC_HID_INFO_LEN (4) +#define BLE_SVC_HID_CONTROL_POINT_LEN (1) -#define BLE_SVC_HID_INPUT_REPORT_COUNT (3) -#define BLE_SVC_HID_OUTPUT_REPORT_COUNT (0) +#define BLE_SVC_HID_INPUT_REPORT_COUNT (3) +#define BLE_SVC_HID_OUTPUT_REPORT_COUNT (0) #define BLE_SVC_HID_FEATURE_REPORT_COUNT (0) #define BLE_SVC_HID_REPORT_COUNT \ (BLE_SVC_HID_INPUT_REPORT_COUNT + BLE_SVC_HID_OUTPUT_REPORT_COUNT + \ @@ -157,6 +157,7 @@ static BleEventAckStatus ble_svc_hid_event_handler(void* event, void* context) { hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; // aci_gatt_attribute_modified_event_rp0* attribute_modified; + if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { // Process modification events @@ -274,6 +275,7 @@ bool ble_svc_hid_update_input_report( .data_ptr = data, .data_len = len, }; + return ble_gatt_characteristic_update( hid_svc->svc_handle, &hid_svc->input_report_chars[input_report_num], &report_data); } diff --git a/lib/nfc/protocols/mf_plus/mf_plus_poller.c b/lib/nfc/protocols/mf_plus/mf_plus_poller.c index 8d1cc1c99a2..57a26a9cf7b 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus_poller.c +++ b/lib/nfc/protocols/mf_plus/mf_plus_poller.c @@ -146,7 +146,7 @@ static void mf_plus_poller_set_callback( static NfcCommand mf_plus_poller_run(NfcGenericEvent event, void* context) { furi_assert(context); - furi_assert(event.protocol = NfcProtocolIso14443_4a); + furi_assert(event.protocol == NfcProtocolIso14443_4a); furi_assert(event.event_data); MfPlusPoller* instance = context; @@ -178,7 +178,7 @@ void mf_plus_poller_free(MfPlusPoller* instance) { static bool mf_plus_poller_detect(NfcGenericEvent event, void* context) { furi_assert(context); - furi_assert(event.protocol = NfcProtocolIso14443_4a); + furi_assert(event.protocol == NfcProtocolIso14443_4a); furi_assert(event.event_data); MfPlusPoller* instance = context; diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index 8298bce6b06..c2aebb6aba5 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -314,8 +314,8 @@ SubGhzProtocolStatus flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); if(!subghz_protocol_encoder_bin_raw_get_upload(instance)) { - break; res = SubGhzProtocolStatusErrorEncoderGetUpload; + break; } instance->encoder.is_running = true; diff --git a/targets/f7/ble_glue/furi_ble/gatt.c b/targets/f7/ble_glue/furi_ble/gatt.c index e407865833c..b8ab094f96c 100644 --- a/targets/f7/ble_glue/furi_ble/gatt.c +++ b/targets/f7/ble_glue/furi_ble/gatt.c @@ -7,6 +7,12 @@ #define GATT_MIN_READ_KEY_SIZE (10) +#ifdef BLE_GATT_STRICT +#define ble_gatt_strict_crash(message) furi_crash(message) +#else +#define ble_gatt_strict_crash(message) +#endif + void ble_gatt_characteristic_init( uint16_t svc_handle, const BleGattCharacteristicParams* char_descriptor, @@ -42,6 +48,7 @@ void ble_gatt_characteristic_init( &char_instance->handle); if(status) { FURI_LOG_E(TAG, "Failed to add %s char: %d", char_descriptor->name, status); + ble_gatt_strict_crash("Failed to add characteristic"); } char_instance->descriptor_handle = 0; @@ -68,6 +75,7 @@ void ble_gatt_characteristic_init( &char_instance->descriptor_handle); if(status) { FURI_LOG_E(TAG, "Failed to add %s char descriptor: %d", char_descriptor->name, status); + ble_gatt_strict_crash("Failed to add characteristic descriptor"); } if(release_data) { free((void*)char_data); @@ -82,6 +90,7 @@ void ble_gatt_characteristic_delete( if(status) { FURI_LOG_E( TAG, "Failed to delete %s char: %d", char_instance->characteristic->name, status); + ble_gatt_strict_crash("Failed to delete characteristic"); } free((void*)char_instance->characteristic); } @@ -111,14 +120,27 @@ bool ble_gatt_characteristic_update( release_data = char_descriptor->data.callback.fn(context, &char_data, &char_data_size); } - tBleStatus result = aci_gatt_update_char_value( - svc_handle, char_instance->handle, 0, char_data_size, char_data); - if(result) { - FURI_LOG_E(TAG, "Failed updating %s characteristic: %d", char_descriptor->name, result); - } + tBleStatus result; + size_t retries_left = 1000; + do { + retries_left--; + result = aci_gatt_update_char_value( + svc_handle, char_instance->handle, 0, char_data_size, char_data); + if(result == BLE_STATUS_INSUFFICIENT_RESOURCES) { + FURI_LOG_W(TAG, "Insufficient resources for %s characteristic", char_descriptor->name); + furi_delay_ms(1); + } + } while(result == BLE_STATUS_INSUFFICIENT_RESOURCES && retries_left); + if(release_data) { free((void*)char_data); } + + if(result != BLE_STATUS_SUCCESS) { + FURI_LOG_E(TAG, "Failed updating %s characteristic: %d", char_descriptor->name, result); + ble_gatt_strict_crash("Failed to update characteristic"); + } + return result != BLE_STATUS_SUCCESS; } @@ -132,6 +154,7 @@ bool ble_gatt_service_add( Service_UUID_Type, Service_UUID, Service_Type, Max_Attribute_Records, Service_Handle); if(result) { FURI_LOG_E(TAG, "Failed to add service: %x", result); + ble_gatt_strict_crash("Failed to add service"); } return result == BLE_STATUS_SUCCESS; @@ -141,6 +164,7 @@ bool ble_gatt_service_delete(uint16_t svc_handle) { tBleStatus result = aci_gatt_del_service(svc_handle); if(result) { FURI_LOG_E(TAG, "Failed to delete service: %x", result); + ble_gatt_strict_crash("Failed to delete service"); } return result == BLE_STATUS_SUCCESS; From 33f1a1609455ed78f19178367056fd63d77d1951 Mon Sep 17 00:00:00 2001 From: WillyJL <49810075+Willy-JL@users.noreply.github.com> Date: Mon, 23 Dec 2024 01:52:37 +0100 Subject: [PATCH 16/22] FBT: Don't lint JS packages (#4030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- firmware.scons | 2 ++ scripts/lint.py | 26 ++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/firmware.scons b/firmware.scons index 4c5e058739d..e7378f957ed 100644 --- a/firmware.scons +++ b/firmware.scons @@ -29,6 +29,8 @@ env = ENV.Clone( TARGETS_ROOT=Dir("#/targets"), LINT_SOURCES=[ Dir("applications"), + # Not C code + Dir("!applications/system/js_app/packages"), ], LIBPATH=[ "${LIB_DIST_DIR}", diff --git a/scripts/lint.py b/scripts/lint.py index 8530209bec0..896cd381285 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -35,21 +35,25 @@ def init(self): self.parser_format.set_defaults(func=self.format) @staticmethod - def _filter_lint_directories(dirnames: list[str]): + def _filter_lint_directories( + dirpath: str, dirnames: list[str], excludes: tuple[str] + ): # Skipping 3rd-party code - usually resides in subfolder "lib" if "lib" in dirnames: dirnames.remove("lib") - # Skipping hidden folders + # Skipping hidden and excluded folders for dirname in dirnames.copy(): if dirname.startswith("."): dirnames.remove(dirname) + if os.path.join(dirpath, dirname).startswith(excludes): + dirnames.remove(dirname) - def _check_folders(self, folders: list): + def _check_folders(self, folders: list, excludes: tuple[str]): show_message = False pattern = re.compile(SOURCE_CODE_DIR_PATTERN) for folder in folders: for dirpath, dirnames, filenames in os.walk(folder): - self._filter_lint_directories(dirnames) + self._filter_lint_directories(dirpath, dirnames, excludes) for dirname in dirnames: if not pattern.match(dirname): @@ -61,11 +65,11 @@ def _check_folders(self, folders: list): "Folders are not renamed automatically, please fix it by yourself" ) - def _find_sources(self, folders: list): + def _find_sources(self, folders: list, excludes: tuple[str]): output = [] for folder in folders: for dirpath, dirnames, filenames in os.walk(folder): - self._filter_lint_directories(dirnames) + self._filter_lint_directories(dirpath, dirnames, excludes) for filename in filenames: ext = os.path.splitext(filename.lower())[1] @@ -168,14 +172,20 @@ def _apply_file_permissions(self, sources: list, dry_run: bool = False): def _perform(self, dry_run: bool): result = 0 - sources = self._find_sources(self.args.input) + excludes = [] + for folder in self.args.input.copy(): + if folder.startswith("!"): + excludes.append(folder.removeprefix("!")) + self.args.input.remove(folder) + excludes = tuple(excludes) + sources = self._find_sources(self.args.input, excludes) if not self._format_sources(sources, dry_run=dry_run): result |= 0b001 if not self._apply_file_naming_convention(sources, dry_run=dry_run): result |= 0b010 if not self._apply_file_permissions(sources, dry_run=dry_run): result |= 0b100 - self._check_folders(self.args.input) + self._check_folders(self.args.input, excludes) return result def check(self): From 6d20bc7e50df4384d8713dd3f9f17042a097f30f Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Mon, 23 Dec 2024 10:09:40 +0900 Subject: [PATCH 17/22] [FL-3938] Add winter animations (#4032) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add winter animations * Format images Co-authored-by: あく --- .../L1_Happy_holidays_128x64/frame_0.png | Bin 0 -> 858 bytes .../L1_Happy_holidays_128x64/frame_1.png | Bin 0 -> 855 bytes .../L1_Happy_holidays_128x64/frame_10.png | Bin 0 -> 872 bytes .../L1_Happy_holidays_128x64/frame_11.png | Bin 0 -> 861 bytes .../L1_Happy_holidays_128x64/frame_12.png | Bin 0 -> 853 bytes .../L1_Happy_holidays_128x64/frame_2.png | Bin 0 -> 851 bytes .../L1_Happy_holidays_128x64/frame_3.png | Bin 0 -> 852 bytes .../L1_Happy_holidays_128x64/frame_4.png | Bin 0 -> 856 bytes .../L1_Happy_holidays_128x64/frame_5.png | Bin 0 -> 850 bytes .../L1_Happy_holidays_128x64/frame_6.png | Bin 0 -> 851 bytes .../L1_Happy_holidays_128x64/frame_7.png | Bin 0 -> 860 bytes .../L1_Happy_holidays_128x64/frame_8.png | Bin 0 -> 857 bytes .../L1_Happy_holidays_128x64/frame_9.png | Bin 0 -> 863 bytes .../L1_Happy_holidays_128x64/meta.txt | 23 ++++++++++++++++++ .../L1_Sleigh_ride_128x64/frame_0.png | Bin 0 -> 820 bytes .../L1_Sleigh_ride_128x64/frame_1.png | Bin 0 -> 881 bytes .../L1_Sleigh_ride_128x64/frame_10.png | Bin 0 -> 788 bytes .../L1_Sleigh_ride_128x64/frame_11.png | Bin 0 -> 816 bytes .../L1_Sleigh_ride_128x64/frame_12.png | Bin 0 -> 864 bytes .../L1_Sleigh_ride_128x64/frame_13.png | Bin 0 -> 798 bytes .../L1_Sleigh_ride_128x64/frame_14.png | Bin 0 -> 813 bytes .../L1_Sleigh_ride_128x64/frame_15.png | Bin 0 -> 879 bytes .../L1_Sleigh_ride_128x64/frame_16.png | Bin 0 -> 855 bytes .../L1_Sleigh_ride_128x64/frame_17.png | Bin 0 -> 772 bytes .../L1_Sleigh_ride_128x64/frame_18.png | Bin 0 -> 817 bytes .../L1_Sleigh_ride_128x64/frame_19.png | Bin 0 -> 867 bytes .../L1_Sleigh_ride_128x64/frame_2.png | Bin 0 -> 866 bytes .../L1_Sleigh_ride_128x64/frame_20.png | Bin 0 -> 809 bytes .../L1_Sleigh_ride_128x64/frame_21.png | Bin 0 -> 795 bytes .../L1_Sleigh_ride_128x64/frame_22.png | Bin 0 -> 870 bytes .../L1_Sleigh_ride_128x64/frame_23.png | Bin 0 -> 852 bytes .../L1_Sleigh_ride_128x64/frame_24.png | Bin 0 -> 805 bytes .../L1_Sleigh_ride_128x64/frame_25.png | Bin 0 -> 858 bytes .../L1_Sleigh_ride_128x64/frame_26.png | Bin 0 -> 830 bytes .../L1_Sleigh_ride_128x64/frame_27.png | Bin 0 -> 828 bytes .../L1_Sleigh_ride_128x64/frame_28.png | Bin 0 -> 585 bytes .../L1_Sleigh_ride_128x64/frame_29.png | Bin 0 -> 431 bytes .../L1_Sleigh_ride_128x64/frame_3.png | Bin 0 -> 812 bytes .../L1_Sleigh_ride_128x64/frame_30.png | Bin 0 -> 281 bytes .../L1_Sleigh_ride_128x64/frame_31.png | Bin 0 -> 270 bytes .../L1_Sleigh_ride_128x64/frame_32.png | Bin 0 -> 236 bytes .../L1_Sleigh_ride_128x64/frame_33.png | Bin 0 -> 485 bytes .../L1_Sleigh_ride_128x64/frame_34.png | Bin 0 -> 771 bytes .../L1_Sleigh_ride_128x64/frame_35.png | Bin 0 -> 887 bytes .../L1_Sleigh_ride_128x64/frame_36.png | Bin 0 -> 809 bytes .../L1_Sleigh_ride_128x64/frame_4.png | Bin 0 -> 890 bytes .../L1_Sleigh_ride_128x64/frame_5.png | Bin 0 -> 819 bytes .../L1_Sleigh_ride_128x64/frame_6.png | Bin 0 -> 799 bytes .../L1_Sleigh_ride_128x64/frame_7.png | Bin 0 -> 817 bytes .../L1_Sleigh_ride_128x64/frame_8.png | Bin 0 -> 875 bytes .../L1_Sleigh_ride_128x64/frame_9.png | Bin 0 -> 823 bytes .../external/L1_Sleigh_ride_128x64/meta.txt | 23 ++++++++++++++++++ assets/dolphin/external/manifest.txt | 20 ++++++++++++--- 53 files changed, 63 insertions(+), 3 deletions(-) create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_11.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_2.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_4.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_5.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_6.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_8.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_9.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/meta.txt create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_0.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_1.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_11.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_12.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_13.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_17.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_18.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_19.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_2.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_20.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_21.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_22.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_24.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_25.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_26.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_29.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_30.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_33.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_36.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/meta.txt diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png new file mode 100755 index 0000000000000000000000000000000000000000..f1207ed14b35cd01eafa00342f2801d74b46c622 GIT binary patch literal 858 zcmV-g1Eu_lP)b3G}_zPLJOisK}_wXw<>5vl)fnyEcmLJ)0YM`-qsd9LG<*g zg3uHHfWB#8LN=zM6$A}^iEZj_uEAVvNj6Dq_mbTmAFd!cFTa@&W`4{t&64fs z1O6+|kM;zum_y0;LR;%E{4|RT5jh|65*n~`w!6HK#2L%5CukdP2q1}?sRvZR12EsS zP6BKKYE)f>e;Pi(R|nZq8>DGO9+1VXzqs;Y z>zzX{C5FwW0Jpr#S{j^JpU8;?=-uOueU6(!BS9RndoqvP1aOo&p}tH{j*$Y>F2CbY zJTRxpb}`rb=#NmV8-pBq^GnU*vUM}Lrs&3DVX2NWQRPbV9Eu_gHSp)RdG_xa2L$n& zAzo{&Ly7kt@}aaYyloeLFiehuLtK&CfvZv9i~0aRdxU@_`$?=4uDcSHyHB@B=3sjv z1Yp-C*-y?RIqd_Gb4_y*`NdA5GkU`(19o4%V_h1`c<^#Zb!*T(J_a>H!@b?Pw{we% z1dHI&$2X)22_qD0fIX;@)4QwO+?wU}hx4OTV?~Yn&m|Y9uV0s?!lVme6X@3g$i9tJ zAw<+xNi6@`UU{o9>1u#x3Q(N{@}pCiFtmK`&hbpo$P?pJF1bH9`LkVT#6U2cFbE**&wk(4~aXcues_UO>rxTx;jl=<04a40ce_veR#+-lBGlmLLRKtj8 k04biGE0u;J2K9h{0X->d_eOezlK=n!07*qoM6N<$g2W|{hX4Qo literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png new file mode 100755 index 0000000000000000000000000000000000000000..9d9012281f0193620bc458455f6a93538fad2e96 GIT binary patch literal 855 zcmV-d1E~CoP);NOWB)|bSkT1aRXRBA7yY|TxF{FSfXu8*lUk&&qCXhO8F)FkoA>H2*0;2g2fv& z(d#Xs;?yt-?E~*0`D{sLX^yAU0@$ekWb2zI3N8X{Fs83orr0sQ#X|guwcpNP1=Z{G zSdat3yA1rXr`2nki#Nt*x!NSyKj4u+UwHlRdp$A`_S7#~2^ znalc2P!kjpqG|x})i68iBGTxNe8ACYahNl>a$BAkJMa8EWISSW9x^|7!7He$DqzaK zHH~UJtLg*3q0pI4GT^O->aCwBq?&T_iw|3e_BWDe59<_EmFTb&R`!3M<{$oTix6M< z>)gGM21gU)@>GCLe`>uG{-^#CUE~ZdT5WwA&`g90koSOKH57+|(uvFv@ zu5jrw5_rGj>oQ@wX!V1Y;}RF$?qIcGbR!}y4R^HsbN*(0SXHAg%c)Z)Sl#Bty=5=L zsgMqRmyS4iNFy-1b&V$Edv0=qawEuV>%O>0>(QCF8Rm}903b;}$!G~1tcE58ti4NG z#Li1EDY$>yq#tK|B{A92+mN-R_2;-oJ?~InHFlt@zLj6-(yP6H#HwvaCccFQEMv5L zf=vPm?`HFc&NPYoHp(3VcND9qw+G8F!`Z&vP|e+|N$-{9)>3?5mJ2g}w){{ph6J4J z%MI1syar5eO=xJuFUo-&*Dz1D2A`uKvLp&GC&Xeh15D$Dcrr0Le)4jNZU3t?tW+aRjFfo7> hF5f7XLU{2m{sTJ-XIlu4y4L^z002ovPDHLkV1fh!ld%8* literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png new file mode 100755 index 0000000000000000000000000000000000000000..cb8f173b0bdd8ae661a0e3c000fa88fe256b3a30 GIT binary patch literal 872 zcmV-u1DE`XP)?*-2wV(L$SR8{9F5vK7gWF*K9z%sdYhFTTrr?}P9A_;@_Xs~B$& zdb=C`2i$J}PvkF<5Lip!C9yJmJk zyD)1^<~b8;r*9}UQQZePJA_5QLN`m13s@3OkFb+2eNEr3q|e{3Do1W(`LOHQ*{Ccc zB5$Q4jUTjXj@h}Yt9&X@PQ4@to~kt#+CNgxBxB&i*V>Ql>6XdOn;M1U`%k`JdYzb# zxvXjd@yA2gSI!^4_f;b4ZVha>V{2(}QKcwlYoN5(9sVe;;QMGaV0UFMDS=xLDQI_k zl`c30L1j1u&AC6(zViz%&P+gL(A6Pd>t%<3qVh2Bofy|h5cY3#mMO5li|Y^PWBb5vv#*6Jr_FPc<~!% zzI?osA0I4#%i;aLLUqKAW@~uXa`(Ts#~MgIadhi(T6M8oL-0000;RtW zYC;GgHWEVi?&N>ACW2t*m9`GWO9_C1mL9w88*tuE7R2n%(<4e*f~ghW9``l2w{(Idzmy zutB!vuh7(q6FumKEzuwW3j>H)yTC$Q)<$cl-5z|y-D(1|M{-+S4~zn(Om^kCIMPHS9NRn-wo zb-G{73WfIdhPR*xoUE3%!LeNDq5+&-b6)u9wbmmCRLA3PDHsgjUH*FU4P5pLwkgFV zmxg|AeEVE-xl4Bs3UJRKUC+WFO%Y=k1n4^CS3kxxCIG~RLNWKb&+NDt@uDzso1(=) ziO{b`1j1wkskuLG`gr?8T!vo%MDt|Wxs$H6RMRzvDm|*B)6Vsz{HJQVCiK<`7I%66 zpD+s`5q~AZZ&Y`vK%F#^#?`Zh(igxfh#;bQczHYO!l%F7Qcd2Iw2#!O6k`4kFx=;dmqLL2aI=r`kQ=1B2Is`ynS&V z<-m2T+}iw1!W-ao64<|YDyCoJj>kKX`oA%;cSfI$NThnHV{pp1@th#<3}a7jmBu`P zDqsa5kKKJg0*?!;XMmeM@@8qw(-6&dL7+AUbPP_-V{~{se>K-hd3t2Z!}?=`PrJ;# zQnh39NRQzpt(~lq3*y4nYpOBlET<#Dr92W2XR56aRW)_yVsXJ!W4uiuWfyz#sBd~p naeM(t04ZO&R;l#2#RBjz<}zf`VzpON00000NkvXXu0mjf*Yuj_ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png new file mode 100755 index 0000000000000000000000000000000000000000..5d4c7e7c55fb7012fa223c9084bfe754c5b50e4f GIT binary patch literal 853 zcmV-b1FHOqP)24#t z)$%{!Q45Ty-Up3=wft=c7FG4Oco@|*;BzJ3rR*z7I#_C0{0L^xB_+HdKGwmDt*hX6 zDH20Ibn!pi0Fyv8^LjZu2{ML(&ZIO+ZL(v#u~+Zi{QU%ZB`c)=A=;6(xnT!)w=IGt z=rYN(4d4fF8i~Na_14g#ID(kx5x^!L#~NS7XoQad>-6bk!-Etiv{*>*vHHuoDNw!k z6Bgu&=ryXNZat%G8DUk&U%K4Vh#e5;u5{tcO?gnuU;Vpo0uJJxMn=zn8dOzP6(9`7 zEDrjmYFK79AIVDKNJDk`d#Z&N9J_G3ad7`tJ->0As;ZJa<+8$t^j++69Ulc2wFZz}~l6 z2i~c<%n15&MiH}mc>V#t(I9v-Q%ybCJHJ&K+pAM;f5?b#dvfM$7{k&>F~d5MxP|iG zuzq5)*a~gZ@(lPVvHC{youmzh+FR<={yxpxF6ZCPB+GWTdbU|UpW2_RHsYTJ;tjyJJ$FNDVQx?~LS0I5z~ f@9uVx0t);KGZb(kKhPw)00000NkvXXu0mjfXi1u-?7W>nA=QF^N=Sn#Tt)k_1K?$nA#5M6H- z3SIFJs3+S?$SlbLxQwjlT}@4XMa_vL+g&bDiVrlO%h|I11tkAJR*h4?o`ocsAzjOk`v+05A z6S0AbLLD1$CbL%`nE^E%K>+(g<*^MDqF^JyR=fZHhu$#kT7e)w$r|myavG?9auyq; zKYZndksi}ZIGTPdw6*@?p1uO!w znz&u}0w4q@tEFA=Y*Y2x6`WjihCh3K<3L|C-CkX!q^iUR3udD4T<)wc*+BBe^$%O` z9DO;pT($(b6I9nTb45d9FA<=3UoiGLeh!Tk@xblL1OCRq3Fd|R3OxmeO3e8Dibr{1 zUeld&q4m*kk=8c%bL`D8HBUyJ+v!b3H;0AgI@Uyu>*@0-ig2hwxUj=>f6jU!NYIQ3 zT4Nn5ydO}Eq;>UexAYxw0t`u2rUq`rdtV~p$Dq)4{V=Ihabs3ZrTcVC0t^1*bx8)pZ36wySQ=&?|`G43`_qCmSb|uFJ9h)-AGPdfGG$gIuCG%s+c7RI1Xef zDMOT|0C&IEz1}^e&Fwi(K3p7`9xLnjeV5W}Gq-NZa%s{B7{ln-2ISGra}oGVt&uw6 z&4cn*Y0_7N<_b`o1d1cmKVj+UrGHN4dS0F!pY|#IzQs2U8)eLn$s>IRC)sFNgSj9c zT%A{qnQ&zVJj&x{G*jL9R6CvI^js_+_-a}HHpK^%`VRKOQ-O7;6vtCo$t)n{i}RJr dAS9px@GqP{Wg0BXhk5`2002ovPDHLkV1gwEk39eY literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png new file mode 100755 index 0000000000000000000000000000000000000000..3a47dfc170224127ad04528accd7b47104c33ae9 GIT binary patch literal 852 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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png new file mode 100755 index 0000000000000000000000000000000000000000..da3a78f4c7d2364f251efcf0d311cfeadf3693ab GIT binary patch literal 860 zcmV-i1Ec(jP)HGw^KWKzD1O2?a4gD9ViVO(ALi=Ao3~!3nM+a`evB?;V{tr$^<9Ht z@Ozx-`5N$}TShE+x8EB(Sg}yy2m+X>`*`iE3Tp8XV3Q$zVtka;2@D3}hg5HzodeaM zuV6r)vTsm07j7o>+()SD%qy4MY8GPL03l%(8fhil9EnrbU|)z+i~uB2(+ps1v~_mb zU^43xhMmAih-NLo^Z-r$6p@vVC;(iIW>)CMlbf<#Y`*@W-|d2p} z`R|OgGP|3p27rY^b0W!r7i;O6Uw)vFYRd8R@6`71T~K%Z4h2;uI^c%mdrNwLec366 z#9s{jc5kkyehI4U0&E4N8_n>0h2Q;HfR25^&}VTGcrHNzuRRTD68cmrOE9xWI~;@g zRa*h!!Xw1`zY<8^2~%tI?Zu-K7rhR99V&Q&Uq>%2}c?`l}k+I{g3Ek&naV}M(`v%`QS-6Vs37`vu}7BFU+ zw1_z;d5(bhha}y&C&I*$mHU1m6Kn? z6o#RHp1Ib6S_zl4d*i*e8be^Bwr9Z`#3bzima(q3{<4?X#IMh*M(>-2!l_2~{L;4& z!N*-~{betw7I$4WbWE^ts-d8%#zHc2259RqPvK~3t8?OkUX;Tl>$Z m(G*Yzq;TDI@s{A_#w=kO&avP_}B;zHLpOl zBas;Lp^N{;2ABlG>9-nlBtgb7(4I6xQk!hsPVA5OZ~bv>g;d?_qHs8 zCFn58i#6aoZwd*)zy03OfjESiml41wZAWWg#%PF-0BiK>lf#1)##t<+_gVSn>=jVG z{sR`|nea`@qtRMM#}dMdj=y@fsTM+t=MXX`pxCl2s58CN>+<(53EMTR1?@1s!UhNz zA0T1yGfqsHXe9d1ERt5*nnQEm^aDj_SFZivmu{xz3DwlI96M&h#chtg~lh@tevO^(pN5SMgwUHpS{$p^2~#jlQbK(aQno=$AI7%fJCweu7e?5MO* zfPHAQHoOzFnGy80j3Q>`;M^m8qe1X&rkZ-Ndv3Edwp*{X{2?Q{<;lBW!5EfaifPse zC7K5Zz}oT2V$<2A=>_n6u=;lW{iFqkTAQj<{vOR*uI87flO;P-K3Q)(pW^Z8`A<00 z+EktLOB!;xepw@9-OS0lf);uk82K1zs!okzwEJFuxzGuDX<*9X{k6sy6*H-vkc1-A z4-Y&=ZNpqEPzm7r4b_BUlYaz4c_8Y}RcoQDmkiA$5`a@kJquYuQ+46qht*5 j04Y!0=|GNY91Bxel{hfU)#i;bjeXFf0r)cg|m z+s-(^7BF=7szJD24*=ER!!^!mfoCz4qOTO&dXl>^D)ywH&zYgxW*M#RUNTZ zr~AaLQfyyu=r(kNlhx8TIFjpJ)Q^*E&T}8W*1G?Y>Udn1qQUU(#jh9Nz-7N^o35DT z!r-rsZ=OjmcIw`J0^IUPH?!~uQ^MFq0Xh%+!yn-p69D2uv6TD#!|b>h@q#e1M#-YT zi_jmA2!zQ7QgeUW_VEscxD3AjvF6E;b0b}CsiqqYR=ZV4r=9tv@`q}=A@tM<7Wa7e z?=TA>5q~wpZw&8Jg*s^>jmvKpyS^|s#~^};=EKW7Q72{kDlOIIJxO~>ohqL9R~WaS zZiU>X=tpQTfTX=xKIz$j{av76>=oq4FoWFzCqO2oyoPZ?PlCeq8MbyKj(@ehbAG|7 zcWB1v7=iJOBZEdWHjA-aY7b&xlmQc{Dndu)E{2@XnsnFVNDlS}PQBY`^8LX}% znuTQJqM~4B#zm-92_+Bf zi2p4g0OtWXwe8q|fXG%h&?xNYu0n&b4sL z^QO4X%7Pd6w}FAu%DJt*<9W?LZ}sJzDy)43;DZ5hUZWUqm44ih4)g{eVM}X9JCviI{E9d-bNa6iy*vm1^Sk%H{e(E@vBc# z-aP=|TlA@2q#79;JlIL1;H0w(ER>@j&yA3SNAp3&T#H2>$DO}UvOsY1@;7Fh)u(4; zt7iZxPyTM3-}yp`+0emQD`kSyQQMw0=@Wb0>0bbdoVK6z&aSpu)4j*~fWh82J(ahs zk^ZhEfYWDrc$Q;hgYH!iU><9-BSbx#yM_UN8nQ>e1vk4G9Zmr(R&7rJ9b9?yXnzv? z9;|Z+f{l5Tx$42x*?ZPK)0H*h3u1W~-EK=+bL4|;=wAanQcUf8|2Udo2oy+Cdv8L! zW>BpbXhV_;PA=Cmfr9i4`d*SM(!HKE(xp(jyCf-y=RThl2`wDk>F<@KOZp)req5=I zt7oqy&E?_}H9tt7zmbrnS|wGI<6b=68QGTva1ZnsG5TzOwD^4e+eWX)-a-qNT3C{T yjOM;xOQ2ei-mUtO+R?u!EKPKl0XTtM6#oJKCt7uy9%sA&0000O9aKtjFBFS<5rrbC%}m9M zUgRQo7XRX1b*D;^N?Ky=V?0!jd8EhM#x;n(iGKn8%i01^Q66Wj%mffr}U0-1Ob zAb^oTl>oMustNt26ldfm(WIn8cS^nw*cymV$9HzJdP{oZX z0DX}26@XXvB7mt|#QDeoiB>l%gnMp9<1RSsACR#L4*RrA4QTF}P@O3{P!=X&k|;Kw z{GG>YUjb)6wR^FoRzzG(K&R@4c1B+{Ck6u80E)uu#8e?{x_(D|nn3F|y%Owv`RPM< z0svYxdV1{gIr|r%6wR|rG z_Ipb9%K2T_WLJOdjU!Ia9LO0bFr9z*qjY7Kfbu;WBwM0Eytoa zv${bA+da&=CaBL3UV&D9ecr}20W+2Rq}Z_9H}LJJs7bb1)9v4MC!20Be7t`SouEjX zTsClwx2-l*f?XqA@%P8snc^`e*gjXTY;jv*Dp1Iz~P7fSP6>B%@=;M*NoN z&=$~kJR8Xvu~Q%XbJo)dAR^srD5aiZ-)UR74#8G8#=Rxu>vO8x(`%goMkdxKM;_5P zZ5{Tx07J%srCf@u9_7-oIH4>{e&LkJ13AL?UJoUdiY%}6iF|KsmFfb)$i%E)32)oT z?B9E2TqG~)Q3Yqo~o zxmYX{aZx*b>OB*Z?-*%R3J$iGAKipVIPm_Zv=l_ja&*?#pgOGkGbAD6?ryXZk;1r$ zgpSDY)KMFee7R0UWLTsi-{lZl4&zc)SuWa$RAgPDvy}TEA-!}aN+5?L00000NkvXX Hu0mjfdXb+( literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png new file mode 100755 index 0000000000000000000000000000000000000000..5459ae27c3e0b2d87cd3a2b68996ceda57cd6f41 GIT binary patch literal 788 zcmV+v1MB>WP)EtRqp8xfd%lOk=O*D>zE{8R{hs%EA5QbX z69Qmufyo`u1_Y$GvzL2?9p9?;NLR-=tK3H!AMk?h0wr)JIMuBH8gL~tfxn}}F~9Hl z<$3d+?Z7x3h(1Z$TV(8#I-a(CS;x3zBfP(Wy?+u2f9ZjcsCemK z<&Wal6rHP)KJnQ2Yvtay%j@gj8B=M*sn}#EX+NR&Um>=qX!_pf8Yg>hEzIEY$uM!~ zuUHdl*=yJLoQZl3Qs7L?KGb=y3kHxh*8cX{mbzm{kTmB!c5`-UTn&J< zi;4=Jp|JJtQ2@uGxF8J={k*IYuw2(H9Nf*1CmUz4QUwRhM%rSr=%v%@1-VHpG zX>Y!S*k6sK>@W1)wyDj22^axEz0^)k#2Eth(ON0dDZdreV{iwM$xVfJ3=R;nmUjlM zkIP-KkC1@=DueNqUDFnguRnB%j=2~?_}!KM4^rcK@M}knfZv+b-#PpJX`*(@2BJ)} zaNeHDRUsAFK-0he>Q9Cj2YSXfuX=A1S-C3gx@!a32OlmiuH_RBGzvD5ICz5x0uoat z{>dS!r6pY}w)Cs(4!d3ZqOY|2)f=COOUEq0l(VRO$UN>m{f%P*rjW;&`K2T7Tmw8Z6lW$uEFf_3*{&fP*BdvUl3oztSDYF#=e*{#<6Y z@2PT-f}$j~78AujRW#=~%x_4F-kx6gRJYs_*EOv~0=S@wNBws2I@rmXS`A)kr86X- z{0xjPjE+M4?q1+r4UAUOdqB_spqcWYb+E}M%Vo@AOo3b#kW`T*X<5;T>;4B1IZ1|x S#su9y zXzB&EP@D+}ih{(@X_M%bTA~QHMVd@Y+lgp0)1+x;&YU^F4|6efz3jcey;y7gKP>j} zzX$+u{sV*8eH#$awvz2^UTou3wn^%BjQ2M!)KLP8Whk`@B*5FwGi6BBK^~5Vrc%Bx z!!zfWgB5Ly#h+_Mtr*Q?Q|*O~S36pyZ&YD)F=)-@3=BUtO)xW*`MN8{(m6=&19!`NGz28WWYy2D z+1q#;8#7%4>R+{grs+~ag<|;qeU-2dT)UpNLrnkp%Qp?vkksdoM7O&2zCB2q^rAsE zNbCd5P9!bNM#nGd%QDb@1W7?6sy8)N0=&nOq>e}!Nh$?S`fDTL)RSjdZ#ZYc!?#qd zxhr<#Lh17CddFkQqNHjmoZb7Atjo}DRGw6jONIUf+tP50#f}GqIZXdUSuX>36-<}@nO@B3Kfof;!_8)rw+(TC;ykfz3 z+Zs!+ik#i9-MjZss&8!74os3!|1P@JqO^C)hRgXd3V3~VaW*aQ(dK( zBVB#P?3!PZr114b5K-1ir#FsS0MmVwb-Aa;(!pa$k_xATeam5Q`irBg?^UPoj(3>X zyvk%>=v;R5m{&()cOXqk3LlW9 u3nR;Mq(w=3Ly{^F&W|AlYDO5H8~Yc`rGxxvN7noR0000kltwRJ zHqlzsn8JD1t4U*p9c#2VF|pAm3NBb#Y=vFe5@y-ic^+mVzRUaPd*A#M}wUV0b+eehAL4h6(YK+)S~90XEeon$0@jRSee z1**;&2U2LCpW?xeSzJ_+`+MV|XB|L)n`aCBzmD9N9DuHZ(CO(LZ-gH-r2tr3l^L;t zh=jz-8J6!X#34GaY(O_2UWzjVn5E+Yni{+@Dhu{LyZNn9T?(s@Y97h_%fF3;*|l64 z4QBKGnSYn#VJt@ClE2XvRIamHipXqg_Ee4_ZP<)L#To26V6Da&ME`Geo*HOF!ECLr_vT<^KPyZ&y? zf)c1S`fIsY%e9pgb_i6X!JW^z8JU}?A3#?OD*E0FdvVCq0_AEJVIuEarTvP0NgR%&>G&UbFoz$}i=uVA#~b z@Jo4rqi^uVLmy*$I?%p8W;R6omrW~_o$vgsqp~|Tvx_aeVN(MJ(5tCT&tl7lb->bL z&s5C(Vk+OL&9>t;O9{dBF{%qaEO$IV zv>!x*Ga}WfB&%{VxnU`R>F;g-aq}-PM6T`+1B%6<^tj6iUP-m5bf9+=RR4pYg2rr{ zr37mC`h49p*P9mG&Y}c37`tV9rq~y6ndm7OrU1`WT}F2X?v_Q$YsH{bq_CcF994-# zsQJ&G+jo{N?>y+n71xansHHc-xMG2>;u-iTC;$NOo|M2iWDSBIL?2C`f~p6notk`0000R1tyh>M^I#_qv{QP$XrggLvOd7m!M?9MzFFYo`y^Z8emhj(nv z&MH@wAp>JwRUy-zK)tsfn@+-UZl|( zT7umoary&@;Oto&cW3Bxp*q?DA-WPrA>Hx(-0YX#T9+ErYr6N+8=_3c0}@aG`layq zN0$!)qX#{0U+lCF<*WJUhC+sxnbha4L=+=ZR}5>LR2JCsG3^VgcA{F1 zl`I{k9ksc1ZQRVK zs9{9@mEvq55&=BuE5Rz;SH`(93Ah+Q>i_(-uGBK1U6f$$-P@7 z(E61dDTey6mx6n*{JdiTU@i-Y$m03`yu#^%@1Mr^mB8YP>BfrpKk}dvmX*M-&%Chl z^X>1_z%FK#(CW1d&HkQIfJ|&a3Ab}S3uDRBV(L7#cer#4ps%S;ym8{*ajG1z0Yr|u z{Xpp)Y_$i+0q*3CF-`)`7eyD~@B#Cz2I%*C_Lm^JS}}PwK;(S(miZxq>)*I$GhQa# zoxo!sB6A1#DPd~L8DH6BTi&P74SqA!tz1T%l3RUw>0QI)JDF~1od#ln~EgM8``UT%NteSRUuc||C zBnU9%Ym+e8N}%_NW1xh^KT1|xb;RS-5DZ*8Rsxg*uV%r(BToac4{`w@QomVk$$b$K cTk!q=0mCXct2Z>fF#rGn07*qoM6N<$g2`}%OaK4? literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png new file mode 100755 index 0000000000000000000000000000000000000000..a5d6c1a7a59b8116e393bfade90b5891981070b4 GIT binary patch literal 813 zcmV+|1JeA7P)1v7b7Rs(o7gnOg*DS66-E$$HkCr=ieeTj1et54L@9!bl#=W!D4i)HB3-mD zBK|A}E3_q3jZ`XySZ7>F0;NuAp%t~swa`vAaemsAnaSKauZzi~iDz@Z?>R3o@Aq*S z=YJ;zz_|-X*F75$(7BfFY8CFvt!#@leT=`rD(Wo(#p+rE5BxZLniW6*8EdNR6~6g% zU6f*RCS2RQZ?Wy0b&8$SvTJiO;lI}MFaX>rG!-oiw{H~M8ml10#-{6slXoSKdF6}U zzj|z0Wy%){3Wx>Gtr(Y0qc}Bo9ARYw*+gAcqm|aUnEQ9r;m&Er6R9{RyRj9f&4}QK ztYe+X#{l%Xz{2$p7vpS50&I2w9r`r-`sFNud7MylDk&`m0A0t8yl*#Mc-|xO$9I6g zOe|Mc?Dup=A>d3-ncTx&#%>q^(%`dfZg;_ro*&JK{&~PT!5#NrtgZLNIfm#<)8&E* zFAn(aFOoeu0sTg(_Rd%F);6L>F!u6u#~{8~orUv8Fm>_F7J$%2U%G&0>g%ntfW-- zec$&Vk}J=g8cHOS-9Et0s%s*2!V{5TuLt1}uGy0fVQ`ky0sQvnlH2_0r6`XaLVs`e z9athzww-R@e{A1pB}yHO`%?`mq5hGW?z`%Al-tgfY^~QLeQIyIH=w4criPVln^##{ z8ajX-yn47^O?;G>jZPlTh*-XmYuriYYEnwSB*aYZ)|G?ji}N<2Ym-sQ+3|VzCzWvm z<1sM&XaM&8L{W{63FTzBrKg3Yq8j_8+tS3Y{qxj%ic;ePrNV@+ovg&j-+C{jM#a8u rQ>r~%IE&P{qDHY?HF?>=f6x90pDlLgl6o*(00000NkvXXu0mjf1J{uq literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png new file mode 100755 index 0000000000000000000000000000000000000000..57b2c9bbee26fbc31ea9e384d8ca8c44936db89f GIT binary patch literal 879 zcmV-#1CacQP)~9or#-tqXwE=trZzs6*sn#Qc^H<9#z~Z znvGTpHdzRj*EHGvpJk|zVmyz3{er~ zRJ4A-qSzE22f*LtK!6Znr32yxpa5V8kOUDc9n>+g7yva{Xara*@Sg)>UsD<0H9F4%#7+c6@3i;;3lqVlFP?gN7EtTWC;%2# z#Rt^ml^V7kc?m2Jsjg(W_|fU|hYloy3n=+GP3T~(?GFi-licd6WZ5MW!Uk-bp0CnH zdV;G!!aw|$6jWZssSq8i``+Ff`{ua=Pdyq(|Kd!Z+7C|A0as;{qC>(E#(S*jb* zz%}pic+asr#b5aDQ=TphvIIU13}^V}&P1 z7AI2-Uz|81a{PEhru0d^T$|K(b8`s#qVomo%#_-Z(oa63UFf(JZk5-&^^##mem^L( zQkLlI9`QY+yJ@_a<)q6fgQ!Q1hAV%kJr^Dbe-7`Zln}2uGrz_1J!{)7|137+9bI#E zCp@g!Y1DQ{b8Xl6lSN-SjJjF%k+ErRSGv>zbOO`Mn$Eh=J2wY_`qSCMt47NYttvkR zpdL=MC505m65=&TyGYK@|CmHX65<^qCsLH7w@vUlBc2OY&dz#+Nb$0G;`s@YvCL6} z$U?t(;>nmuPA()h6rTVf4oyT-h~#c1JSmHa_=&s8e*u(ie_+i17}Nj&002ovPDHLk FV1imcqT>Jn literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png new file mode 100755 index 0000000000000000000000000000000000000000..4be832c648910992ec977cd567913fc99db14545 GIT binary patch literal 855 zcmV-d1E~CoP)KUdworlw-BFPg1P$sm6{!i*7qQZo8dHS0D;13N z$%nr9vh_vEth9X*1EygLLIXh(icMPr*-6mG{t20q(4A~%=lHOj&8na9}5Wptd<+DbzR3cxt*Ewh4m34o@}VAfhVy@PsMiN2QcLsHlbZ=iN@H^J-wY%Wz~Wu%moQnV?E zl&<|PvNT)+NkmHdy&`3)&FwM(`N?Hs)&)@e2xVUUoXm*_(C8r9Wtr}g<)JKd+m=go)IkZXy)*G?=PZEl_9=ml8wVe`O|AGu6;sJtb0sn3 zXD+({W}vAs*>m!ZR}VcC)`OK3@o2q4QWn6DvXY99$wCKH9)OqDB;-05bL=?}a6g5J zoDs=M=s1q!WE>5ca3Jk{Zb5kKsFLcrV3e8m_9+kUWYCB;27VWN&La=c3~G!tUWc2d z$>vVxHyepoh6`1ZoFx0QlC(8y)c2!})K!XaUMePSME>aSm3*uuk44sOTM5x87pvc! zgYB|EAD9>x3mDb(;WpHey}MZCMl|x#w|}jaqMR%`U5;ZMlw(ppg{Lf1z59wq9nZh^ z*74}6(^f0-y`z8>UYaXZzYtj!xnSEivQ(%JRL@Bv%*mqTIGQ#KpD$%{AWf~ULk_;(y4AEptLo<`ScaMvi$)DcMJ@lu9EEl#Kq`+yXr&IxC;l5FY?FvWz zxh=}_@^8V`xBid=!`l>x#>H&S#Wm-2#X|w`_fknwvCws=AQEnX0FxYFA8RG8|$;q6XG%r=c zSh^nM%kI`Ly9DYGnU(x~U!>GGVZmPJIuh?c$pEM(ME;TFoG+3E*zGC7D6=b#Ju?b8 zXh3q$f8Li0HCPTxFy^m=?SKysXi&jayj!K^n|jMBZ*FwqCPN5yJ}7~{caIKLwUIgI zQ34}VV-1@-1Pmj;K>M@8!?NPh>g<~?5a=>^_UZoWMv@upqFVwhC+@vd3$PdiL}YE^ zUpH|p;d!_4JSDKUV=}+v^Q$i8GifF8;LwrA8^)Qxgn+#_u-)cCD&`4+d7Q(9e}YfUK>b?o8c{&#~h1?Em)xqyb(Ibn|#eaqF=P7ftn__;9!x;sMT`- z>J#Un?;|s3`X$^euZYZh3D48)nY7`I%0ax<_tDf3jzV1+K-KG)K?!TWri^9OC70_N z(D3|n3Q#tjjDd#YTLAPx+y_K*^ZlW$i-?$n=e+=t8zr75sa7BfZXZXg8NeK5LsQ!P!!h0x$q9-Z^pKELh6!9z9p95xv#B_CqZ&{nIMI zj`RjmE?4}-CoxyOig9>&u(XuqnK9NkPzYV6zGK^i3acPu zp+)?B{7}3KVixL3k%|63wxj`C9Wd`lu6u`n^8w6m0_ls7!(GxGK;yVk(!cV=KW`EL z{UYF2NKEN={nW0k0>JUUG*g{TH`^22feg4*%-u$(VX5J3)2mzU&ga~-O%!OJALksR zB}1bT_nL#zozVmM-5#_V5i}JeeH+*4vfx}Ys~4c}uhJ#BVnq0NOwYFgfkmh7$sv|w zMo-5RzB8OwXe;F?$X^`vU|S|ESSdY_{-CbSP5Oj~#=o*#(>)?2lF0zwum5UFqc0am zE*1{I8)KQU@{&=w^2@-i)7%3iKKfK=02nL}U7#U15`T3N!0EI4^QVs3 z?o+h505>pejJ&DsllyfL;PQ3WLZ!6wtkmUsp0~GX&6c?&W*AP7L9h>_%KXGT#YgfZ z$G(NDZ(B=r;KTHL)2s3N3|eY+EoK0iySabsIj-(J*^QK2NEQ7(Qd@6A5Bz~tUdR@e zmwd zO=w(I7>1v7@43m%Pdnq!XvEY+Ce^{zI;~I}qs$a4wzv{|W6%gOq!B?hJ4LH=t)SvU zLZL3S+5`%XorN2PqQ;q(;zAwh!XFwk{Yg8f+L?6H%)QCX{aoBh?YBAbocBDOZ}Bq8 z#@OLe2f(-ij8OoBCQu+Z?xJC081MjeQziKg=}rLj(3K|#+@>d50m@#anMnd^jENBd z(y$MhhFlN{U+_kl_~hA}yyT%={!zS}{;Vgsd*DO800ZZU^j28o*FPpUTV` z+p?e<=X;h5X}i=>ZT$O;3kFeeeQ)*omd<*AHk;Lo!Y##eY|F_`-hK|yYTr-A$u7M< zG{not0JXdnKiB0)%b{6Lonlo^R4Q*R z1cP((gY$&tXp{B`nXL=k>Xo7sykP5=sRw~M^PbJScD#@6X)dNf-Ct{cwPZVhLHkx0 z>PBi(>;CN5S&j8)6i`z|lJicnR|)yO^}4QmAMM%hPyT(U5(?J`>)Nx7cgywkJBJae zo=MfDCaKyNv8Nl35*mN3C+v&eg@oNdoB$DdXh%8dmg>43NL_a{FzqMDE~MuIwkN)E z5Rq!7NaiZ0@xpmBC(vNX1= zNV`=hEsPys#*@zakEsOspa6_lxRos51<*!}LiPTXXO&<0MwoGb=;KSfO_gLWeeVTt zZ%dGg#fl3vYfCN>05mLaPNlLRR8ewkSbL|{LL<))Zudw;3lINOLC4&7sJZ)zqe~f? zEhl0i%cJkFisbrBAckyC&t^r|r8GBbV63}G9Ij6}0O}b7BRetY@Ko|LK$VFEnU%X+ zlJDyVFioV8srzb6?uZWk z`sZl*J$|J+N`YWAqW3kbfs+m48*L*15l=S^zPt9QR!0s$URnwL*@=z^yCXLvq-p$%Z*QysNn4?nzjye9?zUuU)P znq>vWJ1R5g!t{5h4u1iv@)JL_JcQi;Fs)U>vO-&m)P%`&>zIk;z6m4{nUq*}r^HNT zVg)WSa zJB>!GF_F9>tW+9W?b{e9F%c4DB_Wh2tx{T$!VJ!x`sN)MGt#-6d(W41zVCitjvDWJ z)k(8?^m}&uI_OR0=*`vNH!B6r>Oa4_9U~M(@&K4N@UO^Bo33?@h}i$TlK_8=kl(1<4*5_WLJlW{%hR8cAHq-F0tCAlWY!ftXQZrk%tLa767O)Eux&PC|SJHNv)xg;&YW>F+0s!@}Zo>SK zUP@=D0k#&9oOP;=r+1&o0~8A6&Tptle|$wEK>NNa^*e7lcZP?a2Y9xOs%}%)dvD*j zFes~g^eHgioPS6iJo2rFu&WG8IQwXl>A?YlVZW7aKM+3i0u;)C64nwI4m-^=&)u+< z7I4$a&lwqk$h1aQB#iDJ=$;SsL=lwm^?`HaYRmfptnCIR%a{7njh^IeDj**9F>Ihr z%_}`P1`NNLS8`?QoxLAD9v=RIb>a=zu*3WCcu3%V0^nLD)}5)mnO@?92imD?ybAL$ zG7fC58xqAK)PVJ73qY7MDE7cgv*eV4>wO0D-@tlpf8rD{@tP89%bDoUL(9D$M5jlU z&|I26X{`Hm2p2Obfx+aAYu!6z$l7Pz?1Zr{Ivp=Nw(5;}?LqsCG zZ|XCVK>L2yH-Ph)`s-yl*yL`xtOWQ)XX`!4K+(F86On3l@ra0gENqMkozM9HtZM>Pv%4_IT4XK?fbq_sS;#70QGtql&oyq-dfnH;!*_+I}^ns nfJ)I<216I^jeL^CZ$d11@;kWVw|A_%ItK^W7EB z2jgA3l%Z1jQH?Ge_7uDKzug6#rBm-o<-5Lk-#Z@2?=%7|twr@NBbLC+Rx;hHQD*uD ze|wjxIr5P{yUD$wxhVH7j_J5H_964YtMPjLiaJwT z*7BuKEV*h6#E=>zi_P3y?IG+yQY_t^y_0KI>_uwCYQaJfxd3JyX~TrEbGqdNY&(PI zHcxB)u-+U4@Sd}*?3>sOyv>c01;^{LKq~gcuB(@i0nZmVjOOF_r#PQU=w`oDVBM1X z=@2{|9YO3UvdxHdhkkPtE88iLo`pUm_FWh|A75&BJ7mGF`jx(cLiX>*MYv?a)nvbI z9xW1D^s&+PT5o@l)EAku^Lkz*Mr${E_f)g95^L}I(p_Si#fUT zpLd~H1V&H%ZWJDP$8A2gP)boH+IZHsesm_51t4+468n4!v$y`G4FQ7@t6n*@&D}15 zQ?T&I7+}8k0sg{>@<7Y&!lSBjCxNLXhV6eXKv@8UepLL-izjJl_~_k)&GfiYsYKKjefYg<<;ilyvRvkXk?o z(^{5-Ti!w&T+AqtqDP9;YVGErOHUs2a_KuCX-<-)Dd}3NoLUANfIZOAa`EHXP`8`Pm&ZK4P(h<0c%ii$YU%_p4?zWA_o8@|Yp zf>ie)v-71k0U3(S(Mq!y6%{KunKE4OgKf~dCT+UqCb_xChopF3J~-cx!^h#{Bu$yI z=CtRUgALhN00=iY5D*0-`4;g!-~%`do859zHX z01xIuqcI@iHwpXUb5v9+jdv zfJ667{=}xp!B#6++WM!CtT!AOYZ(`}Zylub_fsBpfI)A1k#eo$-iGpQ0c#n)Cyd2L zW*Qyg)pki2z8TeR*CkvSkZL!irJK_#WwR*t ztyFJUs{V$nYMYDXXH+i+^NkaGHT!AS0^?9B^lsYx;B4 z%D?)F(^6{XS%nQ3DY)j-F3qn@N&Q(Q?K@PsE|n`I(pRnnOxC;qfmq~c!rLyA%4^~A zjFg&D_?v5iSkyd{fbqaH6Rrb9hT1;+19k&5%MQQ?wmS)37oOSqTGFP0`}-D;fq5WL zXO8d6QV=B0N-BhvAF@;fNka)qs_N}UmoSr(zE4R~nE8Ay>zL#?>`4QdG6Qa~idZU6uP07*qoM6N<$g5|EIEdT%j literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png new file mode 100755 index 0000000000000000000000000000000000000000..639834612c846903283f6ed6628f2c79c3fd6a1e GIT binary patch literal 852 zcmV-a1FQUrP)1v7=A^kbt&`HmrW%{6C=M}V3a-o|chR6ILKaRZph%VYN2(T;23%w=byKKd zK^HE>R7EJ0`cp*v12MOv(9&vybP;K2rms`?;8z^xJ(e?|IKT&-o4q z@B1c3g{)W9{bqnFuJ?MtHb&?TwN`-~Tpm1}h}In@`<0F(W5C#|5=)dO83VeSkwxA^ z0AiW}<|UY-O=<})WOKnap1A5&g#sq)@+CKCYL0#A??S}?XT0X{;fJXei5lZOM^By& z#Y^51^Z{EI@fD`7jJ$QLB!Sc}0{W@27@up!0|YR7%L7EYCF|A}SfnTUVqx=`zaA>b z{**6f)TH{{s<zCKn4VKM5y(OT z;I6!Z;83FYU-Ksy0iGE(QJ5U4l$I;y69#k!)pWjThm*S3onjO+pl$~Hv8-?{oD?9zJ?wvK{&E&bT;3D@~|Gk$L#P#-@&bh7VEWB6))9A3Gw6c&P(Z4Y0$ z6`co^HEq9~JYdTGU=3h2j(UB;%HAGd4||~EL*8^-_}q9Fm~R0U&!mEFpYCbz^nK#~ zJVqTw-97??gFx@|eM(L}Ev!8>eJLa)E<1)DAuyJ>asvPgl;H2N*4UK+fZ6Q^n$H2YDFZOPUkOWv{imJCxyJ>2qF)J> z$+fg|qwQh=CetW^F8y!lf!t+j>Fbe}3?gF7 zGV-~Iuk-niyb_?h;drT?;@vF2gc9Hn-LaZPI=#pN5s}5kYp#fl$ZwepA|lqde=s64 zlkdn^Gw8WqxYrh~e3 zL!wPgT(s%}oi=XVV72Mnn3h<@1W^)!4j@#mcBUP$@6pFQE?x^$@8yn@(@;@U~vu zl%z^!OIHK1$LMHl>~L-zE6H!jWk!7SMVMqa0=TghsMH|gY&$-vd+~{g3zMNL4XPR$ zSoLA&-D_G{sultYmE={7<$=NGPqy>)NrH7Now(ffW^24*jRLcmx6_x_2TGyUl|6K@ zVU$7(XD4yABcFh6&e%#VY>GyHaOs2EtM~lC&3^`MLYv#!;AHFb@B<;4nrMZ`~U>1I` ze7g(Z?fYeXoXDb&t^e@-l)kRb9W3}xv834O_1w$uY%V|o{a#5ksPu1 z$ovi$!1>%_=76cxnF_#ljF|2v$^`!&1vqoXLR+as6t#K)e*_k~vH+>qT!?xw;?A#+ zMK-eESKz{{)(9Ry7ug`Qauogfl4pU>+|w3XJud8iZy%ECXIE8~a{UEuxrC%>xf(wx z`A)gKa|%h?lRr_BmZh6LMI>p?H#I5lE`K^L3X8Ri+H#o%@!mnerWs~S<`tEcDn%Pjfu`Kw6H8mQar4y6RQOj#={92Rru`E jl;u7;lYj0beNp@eu20-ipVE6~Uf(?YKCPa%s!3ChnPn!ZgKpNQZ z0|#=Ra)E8K8KD^jI`URfrBJvs4Lm*JSHnEY!*2u6Hf%KZ%y)&qfdgY3&7ZMrPg=08 zq)-BIYqc=uK&SXgO*1yACa|ooO*Opaw^D?$U?xb$2V~AgHo^YTswC@5#0mRg;;bHZ z3FY5+0tsLJx+hr>(+Nid5K29C?!Iv<*S8_6RIaRC+Ou%tvagGQ2(9UseRnTU0}wY@ z^Lm|fW3k-{K-pNk#Co%5YzI)gjb_;+UGmy;WrZgFz1tz%8sSAt>xS+?ku1Rh1i{)6k?NHteb%0MqdDo_0wVf z`n=X!xvPt>{TZ&CXH!%5N*t6l|6YF}v7A`FQ*yi`8I+u8`f|42>8jkSS`_U=%5&Qz z-#lT@e7M&e!K;OpnCmyXRW)$)vvqfN(g(a0wM#DQUEQ6{A|g_~UTP)-KeX5?XDMO0d1lUP{Bp(GzWlHIs((L zt8l}X3p25r+G6!ud_LN&O{7kr+LAGlNV3Tny1V}DG(ZFjKtD=X*ZLx0bgQ}T;nYTl zh=lKFTD(n7E2W%sB4Fn_J13V)$I3Y6wX3v9H{k8w)@c=;W#}?(|1^S2w>W2rTw+{c-BToST=D=u-gmks;^vVo6_VwQX?N4{byAa!t7k%0PfPv$S+D+;X?zot z!aGEs^rz=s;O3gq-t%u>_zd;Hd!s-(Z&beX%uB7%zpV&d*@n!?xPBJKNk`G`n@B%QTE8I-EEN`PPPN8WjZck^Ke6Q^JaxEG%3 z_-PoOa^Y4F+Hu>8FIbC=iCjM>$+c)KUbNOKsb)<4#~ztYHMi!6KuJuByML8S`(`;F zfD&ASiw8?8(aep45-!qHow`RSn&qcK300GcYfU;b$R3aX0WNV?X=dOLZ2$lO07*qo IM6N<$f@c1SEdT%j literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png new file mode 100755 index 0000000000000000000000000000000000000000..962349bfdec5503429689825577af262921ac6c3 GIT binary patch literal 828 zcmV-C1H=4@P);MYf0)t1eLxntVNLyloX+DW?F4xn>Lx4kC|lVz2hP?>BPG^=lt&B&;Nhe z$Nydh0DT7xZunLpKw~}YuQjGxC8&`#9c5=&N6iIbu2e6O2D^vhwGJQ;rz2I`xM9`h z4OZsney!Bc=1tm9ZrFI?M~Uiv@ueNAX(#}uX4f`q5^7~o&di2&DB5-Eug~SqtX1DP z_x?f9>aIt8y%2v0r+v736~o;DEi^xOh-v}}MRKyT9$ND;fSLNc>P3gEkVkZT&0JYT zM56wYHIUNPsBVi}1ts_tc>iJmpgIjuT269gUOB)ft8$JgKlS47!h_?0g`9*kG0=KK zDuDJpm2)Cp87qz(e6XN$&Y7-CY44@1+-%XKU?6$C>!-d;eF*pXpmNUCzFW^uFOL#* zdw|Lnw*J5;@+}xLYJiw^qRKm&Htcw_)b33 zUNqEb3X6BW3)_NBrX2OtSTd4OJrK_;W?Lp)P+=G^$00KuI7fbI-c;0)xY~v9)6S5* zXSZ8bRxvLAY@zUQF?w^c$I(=<;fF$we>%ki@tEa4`EDLf|WcomHtkl$Pt=2S9cG-e) z5_8wBH44S%G)78~Q10~6%8j{+4DxU($qj3*IpoZ5j|~@^Ui)`TxV0C|wSjr>!qu-y zZkvx?IS1WaHM2&Rw-*#8yCq(l6|wakAriAN@4v~-jJ0000C6`P9 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png new file mode 100755 index 0000000000000000000000000000000000000000..2eb4456cc780a288fda6b71ff3ca99b931c51b2d GIT binary patch literal 585 zcmV-P0=E5$P)>Nh!OB=PyYTx622!q|kdqdsU?O6C zY`-77ka~b3JP3L3LgIs!0Zd;Hk+vjd7p0MO?%AFTaRBBC085+0@+}?!{nZ#{lBAI| zk}kVDr6OOCFON@Iau4&u`Bx3c7{kY_)lM4#Ej_Q+6-Yh8Z=k>B*GUKAX*Ese$ICP0 z8L+!^i5ZYC-uYR90EnFzb<-`4*OguP)Ht&3V|Fb%C>5PO>Cx+2p|}NS-`J?gV=)ir zz70x62H<0TQ-CQh41ETce^co0FIr!Wq z)xD}&RR9ok+5ix`BC#9JkkfQycE+FiSLaaE>t?%f+t<`R>!|U-2%8EfD`o&RA>zGy z-TmLTSAiX{>=J&-=7C$F==OWd64&-!+h`ToJoNh)^6=0kLjn7IB#T*5XBMEG*2HBJ~;}B+3L_Rues8tiw8w|~g@?NH`D5Z=;plA# Z{Rey_OQicOEv5hf002ovPDHLkV1i=g!{7h_ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png new file mode 100755 index 0000000000000000000000000000000000000000..e5772a672f9a63d511a03cd14cba48df73df3662 GIT binary patch literal 812 zcmV+{1JnG8P)Nkl)On1-IBH1q<;PWKD5!)^K#Gm-NXO<@41Ze zzwiNY{sXUWyEY)8t(lEB61#OO-ymB$!zBLg?gY45Y!*ns=rxXRW&kDlp=4^?JLamh z+pLsx{?psQ;nd2H&9$@0>|@QooFtWY03Qs1^AczMhH1c3pIA$Wnni;CTdm=A6HvBD zGSA)yb9kU=Vo_p8H@9Leot2K0zwqQFTQ5l6j6QXzX0%lrC%R+u;nrjJ>a~VMdA&GS z4(?H~2|`92GnJ8N11I`10J~7|-FPYNg|#{NK?{Ww{z7T#*F1oE#NjSICp*rq_k97d za|n?Nb}N4A-5~(?5K6>r4=ISt2ORHP%UI$1<@7syMgR_H)=m8Lea!rPr*}v=q>$rkwl*0<*&ZC zU?yImHA4m%OwQOyZvL-(F;7H0sSqT)ZQ<>F^-XwX41l(z{m9Jo9PDVVMF`%KQW{s)bzRqu$o?Gz2qm&E!1bC94yDt;WaxMT`~j@f z9R;OVIa7k-8>=Q5U;fO!(|0web&Z8)^pVL4F?q0000P43(XaExcZC)XO5g_}>Ap4BQE&%nc>iptZDLR|u?6uJVm%UC@+kLF@2I$vP@~#&R zxZV{tB$?U`%t5S1;qJ5m9kDuJM}JpjA48EIcNKk+9(EOFv?MK_o~iwzsEP7#?DW_H f$=?+J;Lm^?$5Vh#T320I00000NkvXXu0mjfxI%Y8 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png new file mode 100755 index 0000000000000000000000000000000000000000..ec47b899c994843115098e2b481d4be9e3545bd9 GIT binary patch literal 270 zcmV+p0rCEcP)g#Y&IE8RMH&I=ZT-N9#$G7Z;2?CV z!MD6x1bD!iYcNdCSF^9tY4hauHh`CC?40-Z-=cvn*3{YeK2>8 ze+2U>lk@GCfAh=B#t>UH24K-BvC9r%eZAQz=j37B8kTNI77Uy6BwY4=Pwc+n50F}o UZhAxmRsaA107*qoM6N<$g4SGi=l}o! literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png new file mode 100755 index 0000000000000000000000000000000000000000..3f345b563e9eeed887691ea64fd476c58e9eade1 GIT binary patch literal 236 zcmVukXtLRdY<7&Yil?6l5smS!)4=ixyV{H|i zEVZ~qQTSxJvPvwAS+^ZYlHpRc4b{SFksE~%lY85BfJbk@bKKYrf4%(Tbt~+$){Jx@>H0 z9v!U*E>kPOV&QLk{US7P`x)X2@FjRl)L3A-;}s^}z6-}5I>m6R*COBYii7&ERd`uB zg+3&W`T8Obyggs*z8c*$1-S7%TAE9JE`yu<`gW@2bNRjVnA)?Z&*lEIf=!Xm246;w!wPWp`HmW)LcC6j8v((m0$X#-)(gTGH^FsQna8H2~_{aHwIgSCq bjE?>S{e=)!nb_>V00000NkvXXu0mjfi(20( literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png new file mode 100755 index 0000000000000000000000000000000000000000..44c4d0d498b2ebfd6caf104f011430dfe5b1d362 GIT binary patch literal 771 zcmV+e1N{7nP)-)V`@Jcg?b! z8h15C(1l>d;+xnmB8bn0s0B?%Nll~j^76-I($3t^#mqxoUG9(XoO|xacaS8dU}7Ul zvH+yz0pJ4=0SEvKI~0J8h$~QMwbUk6iDv-FZCWX+W})l<4*=N!%mPs`Nk=`_H&U(RQN03dn~zOR4?0F^bcZ+3Jd|f@+2ZE!M+C?0$2hh zw{b3pwgYGh$>~DExEw%JKEP9k2~3drd00M~y~*R%-#{v~l9@dz#;0AHy!)E}^O+Rx z94I<&WVukn2$BWI?n_UP21jE!C^3x zDZI1qZ-3U!AASDMd$7RXZN&e z0fPM>xds;872w$+fB2Cr%~H`{g2wRTyVJ=QSO^(AJ6nsq`o(wFD^F{B%*=)68BWF} zXvTF8XWqhPlMHg|MfEYgan$}7+&OQ0>r%*vAZ@7aw5@LMqSO@9nv+wm?Y$}K6O~oM zi|WC5xD2E}p3qgPtJartKM85w>$fDS`}vAa$%oo~qjz(2j6=ZJSTHBHSJMXE^+B4= zU?IC%uSc~Qb0kp_Bdvd-<4w&=Yi?5=q~4jgms(nr_H|mausIPt6w!cMd<>9Q)~-r& zZE1c*ve0jw1WX8%DOgyo1(dtlNXk_={mO$H@Gr*&ZJJBPG>ZTL002ovPDHLkV1id3 BYq9_U literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png new file mode 100755 index 0000000000000000000000000000000000000000..f70ecb3abe0a34f98debe1b004eb08b12c98673b GIT binary patch literal 887 zcmV--1Bm>IP)I|X#-uh;n6?-_SZ&e{l2{{$MlW29fAFB}G}ef6 z^We24CdMpP8)HLjLOaozka(ay2$(iyAm9RpvIS%ZcJ_NcEbH}`=Y5{{AKi!E42k#v zphU=jbn`Zm>HmS%9n|H~b!8xcSy~v6Rp-lqj970})rLVV1{%PFlE?{~Lcju=gp(qd z*%bni;C>+|5^&gTdAuyV+9n|%4%uZeCHnQFxLmLD%HZub4lT)5>VmBj+N=Ys2_K~^ zV1&lW)zNY+0M!g#3me@gLq(%!W}f@y-)j(p62OXcD-EhLnzo)IU-P&fxLXyWwT&xb z|HtPlrdaioIrn2=-l|Ag9$u{a^!EC)Ppq60V{voLo_a4%xm$}zC)9i+&-Yb4NaVNu zT}A86)|x5aNgZC!$fT(ViYpi2T@%Uml)-}(Hzy{iL<&;QO|N1JE$x+v{x@M(!=v#?_jqm~nttmr=t z7iljxDh0nY&TkKQ|yw=xuTui4JdN{KB-Euw&K_M zu{BbrM#JrEfIY|m{;WB-CK-FYS(nvM?GAtt1i*TU3t>YvU|1~Pc4N&XpYNDWq}(Rp z%1DKNpNATlm3g=#xh%PX6<18Wv~9zwZ|N?vGQrSH_Q|xNkpJuzI{_f%wM-vl7TrJv3XRa0I{>wWXqt=#1!scW6rfAj(5QHzka zQyVTW<<9`DcMJh@nWN{PdHpKD^JPY&Lac7bwMEwITfBfU#P$ zpzZ?at5EsKk!a|~d!n)&`)d%L`FKEdSYMII!X7zGr3=u>>pS#Q)ytacEojC;7Z+o- zf~u--d0yT_qhcE=ol>1wU2q&x&iL;z`(Ogy;s!}joq9G5+oR*Er}dKKpt^WLd)oE1 z>NPL#d7`Mhy!(hh-O5rh2nM8MqRZx9h;M!aL}7YtJLn0QcYQGMO@3zpl7-zF5M|-c ndusK)F7<&Z%d5Xbx48TZM|mrzzUzGF00000NkvXXu0mjf3B8d` literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png new file mode 100755 index 0000000000000000000000000000000000000000..7d970234f57cdecc7e45bf765ed313ad92c3161b GIT binary patch literal 890 zcmV-=1BLvFP)6U8pcMp@S4V4`@4ocyo`72k70Lo9~?a<@?V4 z7-HkNVF>`RHUVn@0J9D#kj-8!oah5e0M0sEsTMByP~%y4 zifHE_S9;&`9T#56Ak&f!I@>Q6lLt#!o~PvQmWV0$Q@q{!jiW({!Iqm>)!xxJ?AFuZ zU`dwo>wNprw)yQDKtzs+Bql2VEZ#_Xp67&V7#vKE*?+fZ!Vmso8&H_w08_NvAH?=jCdf)!o1&-%i|OKByIox zqfF}OBHD?>C(oWM%kkR4&uP=|I_j5b%BsXW8h&_k_ouieho*b(@fTn6Bc%mb16K9q z*3XMWKdF`T9i{?#J9BX{Js+F+dx0w|yy5+vx-q!{q<+4=$2V`|kdXo3F66A36uoXB} z6B%s-2h^jkvB2)S^h~NLg^1+yYf==Mu3qsHo)V~txG|rV+P@lK2N5wJ)=f>1h#6iy z<#|>LREs*&0;(mlE0f{!s>rQ;P#O`*uOvKAm2H~}_jk`hrE~}|BS|sCby*QHA9$YU zsQ3v~3!Q-4l>sFSHQSiqlS7WB^FM<_LnNJkFb*ot#_xYEA|jF(lkmKM0Xq7HHc@&K QWdHyG07*qoM6N<$g4?&KI{*Lx literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png new file mode 100755 index 0000000000000000000000000000000000000000..70eab1f3e8c945560bd8aac429f4ae7e15401456 GIT binary patch literal 819 zcmV-31I+x1P) zUuYav6vlt|=B93H!FAKbeW-EU1Z_*GEfkSfldZI*f?}ae8v4g9A}AVcAQbvgb_ad1 z_+L=a2Qj|sjFwP*$U~(g*ir=9^q~+?$RMFRB|@f9lG)Ad93N&k+xu|ge4Ou`?|%0j zHPQd_kqn)qmV5r}K8jA-fW8>+@Sz(>OpOMw#lnx|~>+7u6}GfM*!KBRqQW$9C?c4A!&7q&C) zZR#>l`I#;9n;`}zfIja1F(kDxeFzxcYip8?Y`a8Eaw+*|eJ)F*YtkW27#2cQ3fD9xxO7i8G3U60x|3hHSFj?51%w@g*Fe6W3Pen(-lWthqH zIKkiFo>@#YdUcaWUK;ygeb245ZyzF3y)D)2H^w|bSsEA$o9Abri#(vmLPTOE(QB~) zSe5~l5WL-02egF&)bGsRKK>VQ(gpckWJY9Pc_ctPj$;TQ18@D9pQ6_VgMkYJ99z_qrZHz^_5-O!*)p0$SA@8>``u9&5i?P zA|=hi@vU}}3!lBz`j-#=wU1y@SuW7CZiv^m0KM@Q0KcH*jeYOjEG9ac0J!&rVWd>M zTm-QI%2S3C^+SMqw+Qi_2_+D0d{@?S)rZC17$6rG63sIoBP%l{B_LDHuT0c^g~i>i z$@@l4X0l=b;Z?7{h=@pS`7uw#(~h&(K}4h;O*1O@MIKm|5nrOJfLwFl+f(jocm#${{bV`LSb#O+VcPa002ovPDHLkV1lqyd=>xz literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png new file mode 100755 index 0000000000000000000000000000000000000000..8169e0766fd617850ef249e6919e2c7715e8cd9e GIT binary patch literal 799 zcmV+)1K|9LP)@2%14c(S3tq0sqQ7jEH5Dt=*W+!+tAtp8Hr$`!T0+9nA>H+_Nu>*%{ z!r3O^VVig%GbQn&7sQSz>BdX-(8LRNqlAUFbXQ8s>@Yj8hn=OZ-{pJr``+()pXX(q z|D6y3V*`wCc~&4mdNX^kU6}DLUYoRZlwRfq%GQCJzgfTnJ;GS40;s@jr2P7p4z2EO z`BkgUH8%sL>5Hx;%?&bmOPV#=@MWC5ermDatP_F);K8ay`L*yx0CU$U5dPW*AyM(x z^U`0%jVUtakvX+@=#1S?TU}kPT~eh=ycLt~QG(ax)Axz(Ni^|%eTCC)w+3qW$n?oI2)|Li?GX$SGl8*dSc?ud<`f8{IV6KN8%j`Qq+U;K{fgcF08uYQ&u>V>*Dtc2!ZX}?$gX!6H# zq9Cn==(qf}v5Vg(raVadCdiQojiEb=w{x+vg#B^nIU=LSh3(Hwpb#Cg{#fZvXs8rS zpx-R8%_ni*;!%$Q97uyP7Vy2+OWFi7VFxK|`I`@}h6^VQKwSwCd!Kq$AG)axK=pN@ z)ZD^x=k{?|2~f>$uM}>t@@GFFBGOowS((iZ7bT}nfaD|=o_p+uo70GhNU3w8F8_)= z)mjO_!)u>sms1C9KaF7lba$l=XVnG0*L9g&6OrikiTN+(Z)d=9R3ni9re$PLJ@C(h znY`?I@Kz&}CAt4AP%?e+AOz1kfhiA^Jk0C_dGjZ^Z2waRlkTK#qmH2p^tdhSB@q#k dszd{h^B;3hM?PLq!U_NY002ovPDHLkV1lI=dW!%6 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png new file mode 100755 index 0000000000000000000000000000000000000000..adee1a63dac8b87d57862f233107c1f961f39cac GIT binary patch literal 817 zcmV-11J3-3P)RhGNuC&1^3lbT18NI;gl(OH8CIa|J4-6 z(9S=ILoqD~ih^##tZOy%4^>3nkhO7aYed^*?YbskzI=}tNn_`GbI$pl!}Gk)3x{3& zuL1y^|G>Z{*9HW%EN2fcZERyzc8Sz=jQclD6e|J6GL)JEDR8&*NEuRfkcY2BQz>8a z!ZoKBgJrhG;k3$Z5YIixT?A2j=N`iCBxBp4$A1Hidih4IN`Gk{$) z08G7~Xn=q)d8oQ~xAB^ZOz%*CwyJlUMANgg7yseme0?g$(l$VCe`M3^GyRY*IssWhRbTRzmwo2GAv1_?vkjcY8eA*Zql6w4+_~uC6_XZ@5yYZkJ zq@DvzFOud8@ndK8K^bWM5J^EQt`{{?0^IwMq*yeJrsaW?`NRnL@qv@8)}6B8;#(@# z+?ZG~S2|Z%>$ogflvd5d*|{gpnqgXv%Hs-hUg(dpH3L^!?6F`Vhv~a3>kdP=Q7sal z+%a0YJGrx*gI|q6zmGkh+uTcF(E%j+XHF=YZ_SK!XFi^>K()=g_RFq6cF{f@p10sT zky|(I&Ck1peII>hq4v@}eWf8H!?1Pm7bD8w_(u0hj%`@qWPBZb26TCpn%6&SC_-{V4gwZyxYn-U8Fd&v>xl0)?^# zuHM(>!OCF>?!W@(WZ7Za!0EEuiE^`mY8|g zU7rO>QutJQ;uW3FbW3%h_uie0s&d|)QeA^W<+}BGZFnta8^B+T0{cf3+mI$Cg?CEQ v>5;|Tk>(}o1xc!GnLUCOXsN>Z%vb*cYgu*d%gmGW00000NkvXXu0mjfmz0(k literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png new file mode 100755 index 0000000000000000000000000000000000000000..db6e667fb77d119f4150c6a1ec875be023846c19 GIT binary patch literal 875 zcmV-x1C;!UP)~KgG zR}iEKYkd&s5>XHzgbo{2);@?U76v}7jm|c0SDM(WxlQlAUmue0ynNw%zURyLoI^kL zGTAy>AJ&1*viblBH+3K&3PcJG#WBDGup1&ZI*~%d$8{V4nu?GFD0|!@zybGp`T!?U z0Vu+FXuJxL@-`K&x$fN}fO2^v@PK`OBbv*7;lLJ~Gm(Khvu{j6SulUGk@WbdCub`` z#Z=lc0L-r_Os)Cmk-CR%xAg-4&)Qm_@CkdyHb!T9$TTis^htr($(@hgP-8ijR#wVq z%mpcm4H(sWsqG$YTgG7ffWpkif6KfeWw8MZbNlgLKhph95n^DFO6A(*_O}BS*bbHr zEidX={A}`M!Uli0op_nh zy7S_t!gp1q>P8?#z*R_CPxQ`+cX9UxkHv&I6 zXB;Pcc;Wu^DaQzc_;96iITfyx{hJFr)~AcC`;s&|vYODkUY~ObGd+?@ML(r5^Yv=ZHt8XtwHhg6(hr?2qSD`z z!Y34FRMNLOi`H#fFb6PcT4~E8X;k$v3Nx#@{{d={ku%1$CRzXh002ovPDHLkV1k;- BrV{`F literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png new file mode 100755 index 0000000000000000000000000000000000000000..a6a37fe29c7f17cec2d4824961e1acfe37f0d353 GIT binary patch literal 823 zcmV-71IYY|P)de9(=SZW1EY1mdVOhDM_c6MG5vwyzZ`^%H}ee=A}$LQ95 zF=jyHg=34CF#l@Q#%R2kI}nFKWUgz1neW&VR+pM! zBwEhe<@Uy2y7&2nVtj@elmP1LJezOG3#aM=kNA}QW9}aFhB*PvWR_uB5A7lEkYhOWwzPxbk_-U#y zg(S~e8g@uwO?$n#9ByJQ zGvG#6dKXzeCxaQ8l3B+|Bi?fK&dC{e`mUQ!fzM=bPgsdwY<$iqS6e%2d0>LNqEgNQ z9~D6fzibBC`8{xD4m8{csK)>{_^E|vBliO?{{st?Q~gh3V Date: Mon, 23 Dec 2024 05:34:05 +0400 Subject: [PATCH 18/22] [FL-3940] Work around incorrect serial port handling by the OS (#4040) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: js sdk flipper detection * chore: bump ver Co-authored-by: あく --- .../system/js_app/packages/fz-sdk/package.json | 2 +- .../system/js_app/packages/fz-sdk/pnpm-lock.yaml | 13 ++++++------- .../system/js_app/packages/fz-sdk/sdk.js | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/applications/system/js_app/packages/fz-sdk/package.json b/applications/system/js_app/packages/fz-sdk/package.json index 3c2954c9c4e..f500fae2b93 100644 --- a/applications/system/js_app/packages/fz-sdk/package.json +++ b/applications/system/js_app/packages/fz-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@flipperdevices/fz-sdk", - "version": "0.1.2", + "version": "0.1.3", "description": "Type declarations and documentation for native JS modules available on Flipper Zero", "keywords": [ "flipper", diff --git a/applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml b/applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml index 45944a8546b..67d3bde8240 100644 --- a/applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml +++ b/applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml @@ -8,13 +8,6 @@ importers: .: dependencies: - prompts: - specifier: ^2.4.2 - version: 2.4.2 - serialport: - specifier: ^12.0.0 - version: 12.0.0 - devDependencies: esbuild: specifier: ^0.24.0 version: 0.24.0 @@ -24,6 +17,12 @@ importers: json5: specifier: ^2.2.3 version: 2.2.3 + prompts: + specifier: ^2.4.2 + version: 2.4.2 + serialport: + specifier: ^12.0.0 + version: 12.0.0 typedoc: specifier: ^0.26.10 version: 0.26.10(typescript@5.6.3) diff --git a/applications/system/js_app/packages/fz-sdk/sdk.js b/applications/system/js_app/packages/fz-sdk/sdk.js index 2eecf032dcd..44663203d23 100644 --- a/applications/system/js_app/packages/fz-sdk/sdk.js +++ b/applications/system/js_app/packages/fz-sdk/sdk.js @@ -85,9 +85,21 @@ async function build(config) { async function upload(config) { const appFile = fs.readFileSync(config.input, "utf8"); - const flippers = (await SerialPort.list()).filter(x => x.serialNumber?.startsWith("flip_")); + const serialPorts = await SerialPort.list(); + + let flippers = serialPorts + .filter(x => x.serialNumber?.startsWith("flip_")) + .map(x => ({ path: x.path, name: x.serialNumber.replace("flip_", "") })); + + if (!flippers.length) { + // some Windows installations don't report the serial number correctly; + // filter by STM VCP VID:PID instead + flippers = serialPorts + .filter(x => x?.vendorId === "0483" && x?.productId === "5740") + .map(x => ({ path: x.path, name: x.path })); + } - if (!flippers) { + if (!flippers.length) { console.error("No Flippers found"); process.exit(1); } From 626d7ef509af0902b795ef802cd4a31b68bfa1d1 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sun, 22 Dec 2024 17:56:19 -0800 Subject: [PATCH 19/22] Fix skylander ID reading (#4038) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Read skylanders faster * Correct parsing ID from skylanders Co-authored-by: あく --- .../nfc/plugins/supported_cards/skylanders.c | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/skylanders.c b/applications/main/nfc/plugins/supported_cards/skylanders.c index 6c199f11462..b5dc0ab86e0 100644 --- a/applications/main/nfc/plugins/supported_cards/skylanders.c +++ b/applications/main/nfc/plugins/supported_cards/skylanders.c @@ -7,13 +7,36 @@ #include #include -#define TAG "Skylanders" +#define TAG "Skylanders" +#define POLY UINT64_C(0x42f0e1eba9ea3693) +#define TOP UINT64_C(0x800000000000) +#define UID_LEN 4 +#define KEY_MASK 0xFFFFFFFFFFFF static const uint64_t skylanders_key = 0x4b0b20107ccb; static const char* nfc_resources_header = "Flipper NFC resources"; static const uint32_t nfc_resources_file_version = 1; +uint64_t crc64_like(uint64_t result, uint8_t sector) { + result ^= (uint64_t)sector << 40; + for(int i = 0; i < 8; i++) { + result = (result & TOP) ? (result << 1) ^ POLY : result << 1; + } + return result; +} + +uint64_t taghash(uint32_t uid) { + uint64_t result = 0x9AE903260CC4; + uint8_t uidBytes[UID_LEN] = {0}; + memcpy(uidBytes, &uid, UID_LEN); + + for(int i = 0; i < UID_LEN; i++) { + result = crc64_like(result, uidBytes[i]); + } + return result; +} + static bool skylanders_search_data( Storage* storage, const char* file_name, @@ -88,6 +111,12 @@ static bool skylanders_read(Nfc* nfc, NfcDevice* device) { MfClassicData* data = mf_classic_alloc(); nfc_device_copy_data(device, NfcProtocolMfClassic, data); + size_t* uid_len = 0; + const uint8_t* uid_bytes = mf_classic_get_uid(data, uid_len); + uint32_t uid = 0; + memcpy(&uid, uid_bytes, sizeof(uid)); + uint64_t hash = taghash(uid); + do { MfClassicType type = MfClassicType1k; MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); @@ -96,10 +125,18 @@ static bool skylanders_read(Nfc* nfc, NfcDevice* device) { data->type = type; MfClassicDeviceKeys keys = {}; for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { - bit_lib_num_to_bytes_be(skylanders_key, sizeof(MfClassicKey), keys.key_a[i].data); - FURI_BIT_SET(keys.key_a_mask, i); - bit_lib_num_to_bytes_be(skylanders_key, sizeof(MfClassicKey), keys.key_b[i].data); - FURI_BIT_SET(keys.key_b_mask, i); + if(i == 0) { + bit_lib_num_to_bytes_be(skylanders_key, sizeof(MfClassicKey), keys.key_a[i].data); + FURI_BIT_SET(keys.key_a_mask, i); + } else { + uint64_t sectorhash = crc64_like(hash, i); + uint64_t key = sectorhash & KEY_MASK; + uint8_t* keyBytes = (uint8_t*)&key; + memcpy(keys.key_a[i].data, keyBytes, sizeof(MfClassicKey)); + FURI_BIT_SET(keys.key_a_mask, i); + memset(keys.key_b[i].data, 0, sizeof(MfClassicKey)); + FURI_BIT_SET(keys.key_b_mask, i); + } } error = mf_classic_poller_sync_read(nfc, &keys, data); @@ -134,7 +171,7 @@ static bool skylanders_parse(const NfcDevice* device, FuriString* parsed_data) { uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6); if(key != skylanders_key) break; - const uint16_t id = (uint16_t)*data->block[1].data; + const uint16_t id = data->block[1].data[1] << 8 | data->block[1].data[0]; if(id == 0) break; Storage* storage = furi_record_open(RECORD_STORAGE); From dc73096966be9d5b7085a99a1bb6bd0a278f985f Mon Sep 17 00:00:00 2001 From: ru-asdx <39434750+ru-asdx@users.noreply.github.com> Date: Mon, 23 Dec 2024 02:05:19 +0000 Subject: [PATCH 20/22] using GITHUB_TOKEN to make API requests in scripts/get_env.py (#4033) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .github/workflows/build.yml | 1 + .github/workflows/build_compact.yml | 1 + .github/workflows/docs.yml | 1 + .github/workflows/merge_report.yml | 1 + .github/workflows/pvs_studio.yml | 1 + scripts/get_env.py | 6 +++++- 6 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bc2178aea3..66a2bdf73ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,6 +12,7 @@ env: DEFAULT_TARGET: f7 FBT_TOOLCHAIN_PATH: /runner/_work FBT_GIT_SUBMODULE_SHALLOW: 1 + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: main: diff --git a/.github/workflows/build_compact.yml b/.github/workflows/build_compact.yml index f45275204a3..f98ab8b49a7 100644 --- a/.github/workflows/build_compact.yml +++ b/.github/workflows/build_compact.yml @@ -6,6 +6,7 @@ on: env: FBT_TOOLCHAIN_PATH: /runner/_work FBT_GIT_SUBMODULE_SHALLOW: 1 + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: compact: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 1fa02508567..65af450cf30 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -9,6 +9,7 @@ on: env: TARGETS: f7 DEFAULT_TARGET: f7 + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: check-secret: diff --git a/.github/workflows/merge_report.yml b/.github/workflows/merge_report.yml index 90302ce1aa0..9ee7884c82c 100644 --- a/.github/workflows/merge_report.yml +++ b/.github/workflows/merge_report.yml @@ -7,6 +7,7 @@ on: env: FBT_TOOLCHAIN_PATH: /runner/_work + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: merge_report: diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index 8eb6fea482b..3f1a164bc94 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -11,6 +11,7 @@ env: DEFAULT_TARGET: f7 FBT_TOOLCHAIN_PATH: /runner/_work FBT_GIT_SUBMODULE_SHALLOW: 1 + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: analyse_c_cpp: diff --git a/scripts/get_env.py b/scripts/get_env.py index e8f6b3b77fd..6d6b3cce57a 100755 --- a/scripts/get_env.py +++ b/scripts/get_env.py @@ -34,7 +34,11 @@ def get_commit_json(event): commit_url = event["pull_request"]["base"]["repo"]["commits_url"].replace( "{/sha}", f"/{event['pull_request']['head']['sha']}" ) - with urllib.request.urlopen(commit_url, context=context) as commit_file: + request = urllib.request.Request(commit_url) + if "GH_TOKEN" in os.environ: + request.add_header("Authorization", "Bearer %s" % (os.environ["GH_TOKEN"])) + + with urllib.request.urlopen(request, context=context) as commit_file: commit_json = json.loads(commit_file.read().decode("utf-8")) return commit_json From e11a62694ef9809ca845c4680d5582aa7c12446e Mon Sep 17 00:00:00 2001 From: Jan Wiesemann Date: Mon, 23 Dec 2024 03:32:53 +0100 Subject: [PATCH 21/22] Added flipper_format_write_empty_line(...) (#4029) * Added flipper_format_write_empty_line(...) * Format sources Co-authored-by: Aleksandr Kutuzov --- .../unit_tests/tests/flipper_format/flipper_format_test.c | 1 + lib/flipper_format/flipper_format.c | 5 +++++ lib/flipper_format/flipper_format.h | 8 ++++++++ targets/f18/api_symbols.csv | 3 ++- targets/f7/api_symbols.csv | 3 ++- 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/applications/debug/unit_tests/tests/flipper_format/flipper_format_test.c b/applications/debug/unit_tests/tests/flipper_format/flipper_format_test.c index 888a6644426..934634c7175 100644 --- a/applications/debug/unit_tests/tests/flipper_format/flipper_format_test.c +++ b/applications/debug/unit_tests/tests/flipper_format/flipper_format_test.c @@ -265,6 +265,7 @@ static bool test_write(const char* file_name) { if(!flipper_format_file_open_always(file, file_name)) break; if(!flipper_format_write_header_cstr(file, test_filetype, test_version)) break; if(!flipper_format_write_comment_cstr(file, "This is comment")) break; + if(!flipper_format_write_empty_line(file)) break; if(!flipper_format_write_string_cstr(file, test_string_key, test_string_data)) break; if(!flipper_format_write_int32(file, test_int_key, test_int_data, COUNT_OF(test_int_data))) break; diff --git a/lib/flipper_format/flipper_format.c b/lib/flipper_format/flipper_format.c index 8992247d1fb..d07022e122e 100644 --- a/lib/flipper_format/flipper_format.c +++ b/lib/flipper_format/flipper_format.c @@ -403,6 +403,11 @@ bool flipper_format_write_comment_cstr(FlipperFormat* flipper_format, const char return flipper_format_stream_write_comment_cstr(flipper_format->stream, data); } +bool flipper_format_write_empty_line(FlipperFormat* flipper_format) { + furi_check(flipper_format); + return flipper_format_stream_write_eol(flipper_format->stream); +} + bool flipper_format_delete_key(FlipperFormat* flipper_format, const char* key) { furi_check(flipper_format); FlipperStreamWriteData write_data = { diff --git a/lib/flipper_format/flipper_format.h b/lib/flipper_format/flipper_format.h index 46f78e25549..4a1bb767bb3 100644 --- a/lib/flipper_format/flipper_format.h +++ b/lib/flipper_format/flipper_format.h @@ -518,6 +518,14 @@ bool flipper_format_write_comment(FlipperFormat* flipper_format, FuriString* dat */ bool flipper_format_write_comment_cstr(FlipperFormat* flipper_format, const char* data); +/** Write empty line (Improves readability for human based parsing) + * + * @param flipper_format Pointer to a FlipperFormat instance + * + * @return True on success + */ +bool flipper_format_write_empty_line(FlipperFormat* flipper_format); + /** Removes the first matching key and its value. Sets the RW pointer to a * position of deleted data. * diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 23421712d01..e18aee04d1f 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.0,, +Version,+,79.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -1054,6 +1054,7 @@ Function,+,flipper_format_update_uint32,_Bool,"FlipperFormat*, const char*, cons Function,+,flipper_format_write_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_write_comment,_Bool,"FlipperFormat*, FuriString*" Function,+,flipper_format_write_comment_cstr,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_write_empty_line,_Bool,FlipperFormat* Function,+,flipper_format_write_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" Function,+,flipper_format_write_header,_Bool,"FlipperFormat*, FuriString*, const uint32_t" Function,+,flipper_format_write_header_cstr,_Bool,"FlipperFormat*, const char*, const uint32_t" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 6f9fc5466e6..51404c951cf 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.0,, +Version,+,79.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -1164,6 +1164,7 @@ Function,+,flipper_format_update_uint32,_Bool,"FlipperFormat*, const char*, cons Function,+,flipper_format_write_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_write_comment,_Bool,"FlipperFormat*, FuriString*" Function,+,flipper_format_write_comment_cstr,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_write_empty_line,_Bool,FlipperFormat* Function,+,flipper_format_write_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" Function,+,flipper_format_write_header,_Bool,"FlipperFormat*, FuriString*, const uint32_t" Function,+,flipper_format_write_header_cstr,_Bool,"FlipperFormat*, const char*, const uint32_t" From 519b89665f6b444ccb3ac4178c89229fda0a42c2 Mon Sep 17 00:00:00 2001 From: Sanghee Park Date: Mon, 23 Dec 2024 11:55:58 +0900 Subject: [PATCH 22/22] Fix invalid path errors while deploying SDK by enforcing toolchain to use UTF-8 on initial SDK Extraction (#4036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix invalid path errors for non-Latin characters by enforcing UTF-8 (#4024) Due to cryillic alphabet on `/openocd/scripts/target/1986ве1т.cfg`, If the system codepage is handling `WideChar` for cryillic properly, It would cause jumbled characters and fail to decompress via System.IO.Compression.ZipFile without Encoding enforcement. (See https://github.com/flipperdevices/flipperzero-firmware/issues/4024#issuecomment-2545385580) * Scripts: fix line endings Co-authored-by: あく --- scripts/toolchain/windows-toolchain-download.ps1 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index 025f8341f79..85a5ab7247a 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -16,15 +16,15 @@ $toolchain_dist_temp_path = "$download_dir\$toolchain_dist_folder" try { if (Test-Path -LiteralPath "$toolchain_target_path") { - Write-Host -NoNewline "Removing old Windows toolchain.." - Remove-Item -LiteralPath "$toolchain_target_path" -Force -Recurse - Write-Host "done!" + Write-Host -NoNewline "Removing old Windows toolchain.." + Remove-Item -LiteralPath "$toolchain_target_path" -Force -Recurse + Write-Host "done!" } if (Test-path -LiteralPath "$toolchain_target_path\..\current") { - Write-Host -NoNewline "Unlinking 'current'.." + Write-Host -NoNewline "Unlinking 'current'.." Remove-Item -LiteralPath "$toolchain_target_path\..\current" -Force - Write-Host "done!" + Write-Host "done!" } if (!(Test-Path -LiteralPath "$toolchain_zip_temp_path" -PathType Leaf)) { @@ -46,7 +46,8 @@ if (Test-Path -LiteralPath "$toolchain_dist_temp_path") { Write-Host -NoNewline "Extracting Windows toolchain.." # This is faster than Expand-Archive Add-Type -Assembly "System.IO.Compression.Filesystem" -[System.IO.Compression.ZipFile]::ExtractToDirectory("$toolchain_zip_temp_path", "$download_dir") +Add-Type -Assembly "System.Text.Encoding" +[System.IO.Compression.ZipFile]::ExtractToDirectory("$toolchain_zip_temp_path", "$download_dir", [System.Text.Encoding]::UTF8) # Expand-Archive -LiteralPath "$toolchain_zip_temp_path" -DestinationPath "$download_dir" Write-Host -NoNewline "moving.."