From fd8607398dbdb986888ee0b7517d9ef5c79e06e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 21 Mar 2023 18:55:20 +0900 Subject: [PATCH 01/26] Github: unshallow on decontamination (#2521) * Github: unshallow on decontamination * Github: fix syntax * Github: decontaminate without full tree * Github: update decontaminate action in all workflows --- .github/workflows/build.yml | 7 ++++++- .github/workflows/lint_and_submodule_check.yml | 7 ++++++- .github/workflows/merge_report.yml | 7 ++++++- .github/workflows/pvs_studio.yml | 7 ++++++- .github/workflows/unit_tests.yml | 9 +++++++-- .github/workflows/updater_test.yml | 7 ++++++- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79535c9344..6ab2490ce6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,12 @@ jobs: - name: 'Decontaminate previous build leftovers' run: | if [ -d .git ]; then - git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + git submodule status || ( + git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule + do + git rm -rf --cached "$submodule" + done + ) fi - name: 'Checkout code' diff --git a/.github/workflows/lint_and_submodule_check.yml b/.github/workflows/lint_and_submodule_check.yml index ede3579326..46cca5c0dc 100644 --- a/.github/workflows/lint_and_submodule_check.yml +++ b/.github/workflows/lint_and_submodule_check.yml @@ -21,7 +21,12 @@ jobs: - name: 'Decontaminate previous build leftovers' run: | if [ -d .git ]; then - git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + git submodule status || ( + git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule + do + git rm -rf --cached "$submodule" + done + ) fi - name: 'Checkout code' diff --git a/.github/workflows/merge_report.yml b/.github/workflows/merge_report.yml index 3b7cd23499..e88346edf5 100644 --- a/.github/workflows/merge_report.yml +++ b/.github/workflows/merge_report.yml @@ -15,7 +15,12 @@ jobs: - name: 'Decontaminate previous build leftovers' run: | if [ -d .git ]; then - git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + git submodule status || ( + git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule + do + git rm -rf --cached "$submodule" + done + ) fi - name: 'Checkout code' diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index 9105a0fd63..65ffd19546 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -22,7 +22,12 @@ jobs: - name: 'Decontaminate previous build leftovers' run: | if [ -d .git ]; then - git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + git submodule status || ( + git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule + do + git rm -rf --cached "$submodule" + done + ) fi - name: 'Checkout code' diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index bed5a470d5..6f044ebcae 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -15,7 +15,12 @@ jobs: - name: 'Decontaminate previous build leftovers' run: | if [ -d .git ]; then - git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + git submodule status || ( + git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule + do + git rm -rf --cached "$submodule" + done + ) fi - name: Checkout code @@ -32,7 +37,7 @@ jobs: - name: 'Flash unit tests firmware' id: flashing if: success() - run: | + run: | ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 - name: 'Wait for flipper and format ext' diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index eba34e988b..c04d526fc7 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -15,7 +15,12 @@ jobs: - name: 'Decontaminate previous build leftovers' run: | if [ -d .git ]; then - git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + git submodule status || ( + git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule + do + git rm -rf --cached "$submodule" + done + ) fi - name: Checkout code From bf70f4b71a6d75204613fb0ce19c84598e9f0457 Mon Sep 17 00:00:00 2001 From: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com> Date: Tue, 21 Mar 2023 15:03:14 +0300 Subject: [PATCH 02/26] NFC: Fixed writing gen1a magic tags with invalid BCC (#2511) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/external/nfc_magic/lib/magic/magic.c | 5 ++--- applications/external/nfc_magic/nfc_magic_worker.c | 8 +++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/applications/external/nfc_magic/lib/magic/magic.c b/applications/external/nfc_magic/lib/magic/magic.c index a922bc7a8f..9a71daaa0f 100644 --- a/applications/external/nfc_magic/lib/magic/magic.c +++ b/applications/external/nfc_magic/lib/magic/magic.c @@ -6,8 +6,7 @@ #define MAGIC_CMD_WUPA (0x40) #define MAGIC_CMD_WIPE (0x41) -#define MAGIC_CMD_READ (0x43) -#define MAGIC_CMD_WRITE (0x43) +#define MAGIC_CMD_ACCESS (0x43) #define MAGIC_MIFARE_READ_CMD (0x30) #define MAGIC_MIFARE_WRITE_CMD (0xA0) @@ -70,7 +69,7 @@ bool magic_data_access_cmd() { FuriHalNfcReturn ret = 0; do { - tx_data[0] = MAGIC_CMD_WRITE; + tx_data[0] = MAGIC_CMD_ACCESS; ret = furi_hal_nfc_ll_txrx_bits( tx_data, 8, diff --git a/applications/external/nfc_magic/nfc_magic_worker.c b/applications/external/nfc_magic/nfc_magic_worker.c index 523c794f7d..92eb793a71 100644 --- a/applications/external/nfc_magic/nfc_magic_worker.c +++ b/applications/external/nfc_magic/nfc_magic_worker.c @@ -85,15 +85,17 @@ void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) { card_found_notified = true; } furi_hal_nfc_sleep(); - if(!magic_wupa()) { - FURI_LOG_E(TAG, "Not Magic card"); + FURI_LOG_E(TAG, "No card response to WUPA (not a magic card)"); nfc_magic_worker->callback( NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); break; } + furi_hal_nfc_sleep(); + } + if(magic_wupa()) { if(!magic_data_access_cmd()) { - FURI_LOG_E(TAG, "Not Magic card"); + FURI_LOG_E(TAG, "No card response to data access command (not a magic card)"); nfc_magic_worker->callback( NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); break; From ce50b09b286835d24d5d4d1aeca048260f1205a6 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Tue, 21 Mar 2023 15:29:54 +0300 Subject: [PATCH 03/26] Remove hmac_sha256 from public API (#2519) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- {lib/toolbox => applications/main/u2f}/hmac_sha256.c | 0 {lib/toolbox => applications/main/u2f}/hmac_sha256.h | 0 applications/main/u2f/u2f.c | 2 +- firmware/targets/f18/api_symbols.csv | 7 ++----- firmware/targets/f7/api_symbols.csv | 7 ++----- lib/toolbox/SConscript | 2 +- 6 files changed, 6 insertions(+), 12 deletions(-) rename {lib/toolbox => applications/main/u2f}/hmac_sha256.c (100%) rename {lib/toolbox => applications/main/u2f}/hmac_sha256.h (100%) diff --git a/lib/toolbox/hmac_sha256.c b/applications/main/u2f/hmac_sha256.c similarity index 100% rename from lib/toolbox/hmac_sha256.c rename to applications/main/u2f/hmac_sha256.c diff --git a/lib/toolbox/hmac_sha256.h b/applications/main/u2f/hmac_sha256.h similarity index 100% rename from lib/toolbox/hmac_sha256.h rename to applications/main/u2f/hmac_sha256.h diff --git a/applications/main/u2f/u2f.c b/applications/main/u2f/u2f.c index 767733ce65..0ed5ebb296 100644 --- a/applications/main/u2f/u2f.c +++ b/applications/main/u2f/u2f.c @@ -7,7 +7,7 @@ #include // for lfs_tobe32 #include "toolbox/sha256.h" -#include "toolbox/hmac_sha256.h" +#include "hmac_sha256.h" #include "micro-ecc/uECC.h" #define TAG "U2F" diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 7fa269c961..b6be56f60d 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,18.2,, +Version,+,19.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -160,7 +160,6 @@ Header,+,lib/toolbox/args.h,, Header,+,lib/toolbox/crc32_calc.h,, Header,+,lib/toolbox/dir_walk.h,, Header,+,lib/toolbox/float_tools.h,, -Header,+,lib/toolbox/hmac_sha256.h,, Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/md5.h,, @@ -169,6 +168,7 @@ Header,+,lib/toolbox/pretty_format.h,, Header,+,lib/toolbox/protocols/protocol_dict.h,, Header,+,lib/toolbox/random_name.h,, Header,+,lib/toolbox/saved_struct.h,, +Header,+,lib/toolbox/sha256.h,, Header,+,lib/toolbox/stream/buffered_file_stream.h,, Header,+,lib/toolbox/stream/file_stream.h,, Header,+,lib/toolbox/stream/stream.h,, @@ -1316,9 +1316,6 @@ Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*" Function,+,hal_sd_detect,_Bool, Function,+,hal_sd_detect_init,void, Function,+,hal_sd_detect_set_low,void, -Function,+,hmac_sha256_finish,void,"const hmac_sha256_context*, const uint8_t*, uint8_t*" -Function,+,hmac_sha256_init,void,"hmac_sha256_context*, const uint8_t*" -Function,+,hmac_sha256_update,void,"const hmac_sha256_context*, const uint8_t*, unsigned" Function,+,icon_animation_alloc,IconAnimation*,const Icon* Function,+,icon_animation_free,void,IconAnimation* Function,+,icon_animation_get_height,uint8_t,const IconAnimation* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index c98e546727..e6de39b1d6 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,18.2,, +Version,+,19.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -192,7 +192,6 @@ Header,+,lib/toolbox/args.h,, Header,+,lib/toolbox/crc32_calc.h,, Header,+,lib/toolbox/dir_walk.h,, Header,+,lib/toolbox/float_tools.h,, -Header,+,lib/toolbox/hmac_sha256.h,, Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/md5.h,, @@ -201,6 +200,7 @@ Header,+,lib/toolbox/pretty_format.h,, Header,+,lib/toolbox/protocols/protocol_dict.h,, Header,+,lib/toolbox/random_name.h,, Header,+,lib/toolbox/saved_struct.h,, +Header,+,lib/toolbox/sha256.h,, Header,+,lib/toolbox/stream/buffered_file_stream.h,, Header,+,lib/toolbox/stream/file_stream.h,, Header,+,lib/toolbox/stream/stream.h,, @@ -1604,9 +1604,6 @@ Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*" Function,+,hal_sd_detect,_Bool, Function,+,hal_sd_detect_init,void, Function,+,hal_sd_detect_set_low,void, -Function,+,hmac_sha256_finish,void,"const hmac_sha256_context*, const uint8_t*, uint8_t*" -Function,+,hmac_sha256_init,void,"hmac_sha256_context*, const uint8_t*" -Function,+,hmac_sha256_update,void,"const hmac_sha256_context*, const uint8_t*, unsigned" Function,-,hypot,double,"double, double" Function,-,hypotf,float,"float, float" Function,-,hypotl,long double,"long double, long double" diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index d7b0e7bbc0..fad4c55841 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -12,7 +12,7 @@ env.Append( File("manchester_encoder.h"), File("path.h"), File("random_name.h"), - File("hmac_sha256.h"), + File("sha256.h"), File("crc32_calc.h"), File("dir_walk.h"), File("md5.h"), From db54c463e610e1ce9feae09b0c45af646a95864c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 21 Mar 2023 17:52:21 +0300 Subject: [PATCH 04/26] Fix hopper stuck at 433.42 due to wide range tx'es When we using 433.92 remote flipper in hopping mode will stuck at 433.42 and may loose signal because of that, need to avoid using close freqs in hopping, only freqs with bigger difference like 310 -> 315 --- documentation/SubGHzSettings.md | 1 - lib/subghz/subghz_setting.c | 1 - 2 files changed, 2 deletions(-) diff --git a/documentation/SubGHzSettings.md b/documentation/SubGHzSettings.md index d01cd62500..2d14307c7a 100644 --- a/documentation/SubGHzSettings.md +++ b/documentation/SubGHzSettings.md @@ -91,7 +91,6 @@ Your frequencies will be added after default ones ``` 310000000, 315000000, - 433420000, 433920000, 868350000, ``` diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 144c161203..34cf169159 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -79,7 +79,6 @@ static const uint32_t subghz_frequency_list[] = { static const uint32_t subghz_hopper_frequency_list[] = { 310000000, 315000000, - 433420000, 433920000, 868350000, 0, From 6089e9210f67712284e14c147123938cd7be9bd9 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 21 Mar 2023 08:53:07 -0600 Subject: [PATCH 05/26] BadUSB: implement boot protocol (#2496) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BadUSB: remove unused out EP * BadUSB: do not use iad for a single interface * BadUSB: implement the boot protocol * BadUSB: implement SET_PROTOCOL * Improve HID report descriptor readability * CODEOWNERS update Co-authored-by: nminaylov Co-authored-by: あく --- .github/CODEOWNERS | 3 + .../targets/f7/furi_hal/furi_hal_usb_hid.c | 247 ++++++++++-------- 2 files changed, 136 insertions(+), 114 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0bc130243b..c1684aa99b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -44,6 +44,9 @@ /applications/examples/example_thermo/ @skotopes @DrZlo13 @hedger @gsurkov +# Firmware targets +/firmware/ @skotopes @DrZlo13 @hedger @nminaylov + # Assets /assets/resources/infrared/ @skotopes @DrZlo13 @hedger @gsurkov diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c index 5cb7fd2983..d27613410b 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -8,7 +8,6 @@ #include "usb_hid.h" #define HID_EP_IN 0x81 -#define HID_EP_OUT 0x01 #define HID_EP_SZ 0x10 #define HID_INTERVAL 2 @@ -16,17 +15,15 @@ #define HID_VID_DEFAULT 0x046D #define HID_PID_DEFAULT 0xC529 -struct HidIadDescriptor { - struct usb_iad_descriptor hid_iad; +struct HidIntfDescriptor { struct usb_interface_descriptor hid; struct usb_hid_descriptor hid_desc; struct usb_endpoint_descriptor hid_ep_in; - struct usb_endpoint_descriptor hid_ep_out; }; struct HidConfigDescriptor { struct usb_config_descriptor config; - struct HidIadDescriptor iad_0; + struct HidIntfDescriptor intf_0; } __attribute__((packed)); enum HidReportId { @@ -35,78 +32,98 @@ enum HidReportId { ReportIdConsumer = 3, }; -/* HID report: keyboard+mouse */ +/* HID report descriptor: keyboard + mouse + consumer control */ static const uint8_t hid_report_desc[] = { + // clang-format off HID_USAGE_PAGE(HID_PAGE_DESKTOP), HID_USAGE(HID_DESKTOP_KEYBOARD), HID_COLLECTION(HID_APPLICATION_COLLECTION), - HID_REPORT_ID(ReportIdKeyboard), - HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), - HID_USAGE_MINIMUM(HID_KEYBOARD_L_CTRL), - HID_USAGE_MAXIMUM(HID_KEYBOARD_R_GUI), - HID_LOGICAL_MINIMUM(0), - HID_LOGICAL_MAXIMUM(1), - HID_REPORT_SIZE(1), - HID_REPORT_COUNT(8), - HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_REPORT_COUNT(1), - HID_REPORT_SIZE(8), - HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_USAGE_PAGE(HID_PAGE_LED), - HID_REPORT_COUNT(8), - HID_REPORT_SIZE(1), - HID_USAGE_MINIMUM(1), - HID_USAGE_MAXIMUM(8), - HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_REPORT_COUNT(HID_KB_MAX_KEYS), - HID_REPORT_SIZE(8), - HID_LOGICAL_MINIMUM(0), - HID_LOGICAL_MAXIMUM(101), - HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), - HID_USAGE_MINIMUM(0), - HID_USAGE_MAXIMUM(101), - HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), + HID_REPORT_ID(ReportIdKeyboard), + // Keyboard report + HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), + HID_USAGE_MINIMUM(HID_KEYBOARD_L_CTRL), + HID_USAGE_MAXIMUM(HID_KEYBOARD_R_GUI), + HID_LOGICAL_MINIMUM(0), + HID_LOGICAL_MAXIMUM(1), + HID_REPORT_SIZE(1), + HID_REPORT_COUNT(8), + // Input - Modifier keys byte + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + + HID_REPORT_COUNT(1), + HID_REPORT_SIZE(8), + // Input - Reserved byte + HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + + HID_USAGE_PAGE(HID_PAGE_LED), + HID_REPORT_COUNT(8), + HID_REPORT_SIZE(1), + HID_USAGE_MINIMUM(1), + HID_USAGE_MAXIMUM(8), + // Output - LEDs + HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + + HID_REPORT_COUNT(HID_KB_MAX_KEYS), + HID_REPORT_SIZE(8), + HID_LOGICAL_MINIMUM(0), + HID_LOGICAL_MAXIMUM(101), + HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), + HID_USAGE_MINIMUM(0), + HID_USAGE_MAXIMUM(101), + // Input - Key codes + HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), HID_END_COLLECTION, + HID_USAGE_PAGE(HID_PAGE_DESKTOP), HID_USAGE(HID_DESKTOP_MOUSE), HID_COLLECTION(HID_APPLICATION_COLLECTION), - HID_USAGE(HID_DESKTOP_POINTER), - HID_COLLECTION(HID_PHYSICAL_COLLECTION), - HID_REPORT_ID(ReportIdMouse), - HID_USAGE_PAGE(HID_PAGE_BUTTON), - HID_USAGE_MINIMUM(1), - HID_USAGE_MAXIMUM(3), - HID_LOGICAL_MINIMUM(0), - HID_LOGICAL_MAXIMUM(1), - HID_REPORT_COUNT(3), - HID_REPORT_SIZE(1), - HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_REPORT_SIZE(1), - HID_REPORT_COUNT(5), - HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_USAGE_PAGE(HID_PAGE_DESKTOP), - HID_USAGE(HID_DESKTOP_X), - HID_USAGE(HID_DESKTOP_Y), - HID_USAGE(HID_DESKTOP_WHEEL), - HID_LOGICAL_MINIMUM(-127), - HID_LOGICAL_MAXIMUM(127), - HID_REPORT_SIZE(8), - HID_REPORT_COUNT(3), - HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), - HID_END_COLLECTION, + HID_USAGE(HID_DESKTOP_POINTER), + HID_COLLECTION(HID_PHYSICAL_COLLECTION), + HID_REPORT_ID(ReportIdMouse), + // Mouse report + HID_USAGE_PAGE(HID_PAGE_BUTTON), + HID_USAGE_MINIMUM(1), + HID_USAGE_MAXIMUM(3), + HID_LOGICAL_MINIMUM(0), + HID_LOGICAL_MAXIMUM(1), + HID_REPORT_COUNT(3), + HID_REPORT_SIZE(1), + // Input - Mouse keys + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + + HID_REPORT_SIZE(1), + HID_REPORT_COUNT(5), + // Input - Mouse keys padding + HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + + HID_USAGE_PAGE(HID_PAGE_DESKTOP), + HID_USAGE(HID_DESKTOP_X), + HID_USAGE(HID_DESKTOP_Y), + HID_USAGE(HID_DESKTOP_WHEEL), + HID_LOGICAL_MINIMUM(-127), + HID_LOGICAL_MAXIMUM(127), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(3), + // Input - Mouse movement data (x, y, scroll) + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), + HID_END_COLLECTION, HID_END_COLLECTION, + HID_USAGE_PAGE(HID_PAGE_CONSUMER), HID_USAGE(HID_CONSUMER_CONTROL), HID_COLLECTION(HID_APPLICATION_COLLECTION), - HID_REPORT_ID(ReportIdConsumer), - HID_LOGICAL_MINIMUM(0), - HID_RI_LOGICAL_MAXIMUM(16, 0x3FF), - HID_USAGE_MINIMUM(0), - HID_RI_USAGE_MAXIMUM(16, 0x3FF), - HID_REPORT_COUNT(HID_CONSUMER_MAX_KEYS), - HID_REPORT_SIZE(16), - HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), + HID_REPORT_ID(ReportIdConsumer), + // Consumer report + HID_LOGICAL_MINIMUM(0), + HID_RI_LOGICAL_MAXIMUM(16, 0x3FF), + HID_USAGE_MINIMUM(0), + HID_RI_USAGE_MAXIMUM(16, 0x3FF), + HID_REPORT_COUNT(HID_CONSUMER_MAX_KEYS), + HID_REPORT_SIZE(16), + // Input - Consumer control keys + HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), HID_END_COLLECTION, + // clang-format on }; /* Device descriptor */ @@ -114,9 +131,9 @@ static struct usb_device_descriptor hid_device_desc = { .bLength = sizeof(struct usb_device_descriptor), .bDescriptorType = USB_DTYPE_DEVICE, .bcdUSB = VERSION_BCD(2, 0, 0), - .bDeviceClass = USB_CLASS_IAD, - .bDeviceSubClass = USB_SUBCLASS_IAD, - .bDeviceProtocol = USB_PROTO_IAD, + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = USB_SUBCLASS_NONE, + .bDeviceProtocol = USB_PROTO_NONE, .bMaxPacketSize0 = USB_EP0_SIZE, .idVendor = HID_VID_DEFAULT, .idProduct = HID_PID_DEFAULT, @@ -140,29 +157,18 @@ static const struct HidConfigDescriptor hid_cfg_desc = { .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, .bMaxPower = USB_CFG_POWER_MA(100), }, - .iad_0 = + .intf_0 = { - .hid_iad = - { - .bLength = sizeof(struct usb_iad_descriptor), - .bDescriptorType = USB_DTYPE_INTERFASEASSOC, - .bFirstInterface = 0, - .bInterfaceCount = 1, - .bFunctionClass = USB_CLASS_PER_INTERFACE, - .bFunctionSubClass = USB_SUBCLASS_NONE, - .bFunctionProtocol = USB_PROTO_NONE, - .iFunction = NO_DESCRIPTOR, - }, .hid = { .bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = USB_DTYPE_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, - .bNumEndpoints = 2, + .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_HID, - .bInterfaceSubClass = USB_HID_SUBCLASS_NONBOOT, - .bInterfaceProtocol = USB_HID_PROTO_NONBOOT, + .bInterfaceSubClass = USB_HID_SUBCLASS_BOOT, + .bInterfaceProtocol = USB_HID_PROTO_KEYBOARD, .iInterface = NO_DESCRIPTOR, }, .hid_desc = @@ -184,15 +190,6 @@ static const struct HidConfigDescriptor hid_cfg_desc = { .wMaxPacketSize = HID_EP_SZ, .bInterval = HID_INTERVAL, }, - .hid_ep_out = - { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DTYPE_ENDPOINT, - .bEndpointAddress = HID_EP_OUT, - .bmAttributes = USB_EPTYPE_INTERRUPT, - .wMaxPacketSize = HID_EP_SZ, - .bInterval = HID_INTERVAL, - }, }, }; @@ -206,9 +203,11 @@ struct HidReportMouse { struct HidReportKB { uint8_t report_id; - uint8_t mods; - uint8_t reserved; - uint8_t btn[HID_KB_MAX_KEYS]; + struct { + uint8_t mods; + uint8_t reserved; + uint8_t btn[HID_KB_MAX_KEYS]; + } boot; } __attribute__((packed)); struct HidReportConsumer { @@ -256,6 +255,7 @@ static bool hid_connected = false; static HidStateCallback callback; static void* cb_ctx; static uint8_t led_state; +static bool boot_protocol = false; bool furi_hal_hid_is_connected() { return hid_connected; @@ -280,31 +280,31 @@ void furi_hal_hid_set_state_callback(HidStateCallback cb, void* ctx) { bool furi_hal_hid_kb_press(uint16_t button) { for(uint8_t key_nb = 0; key_nb < HID_KB_MAX_KEYS; key_nb++) { - if(hid_report.keyboard.btn[key_nb] == 0) { - hid_report.keyboard.btn[key_nb] = button & 0xFF; + if(hid_report.keyboard.boot.btn[key_nb] == 0) { + hid_report.keyboard.boot.btn[key_nb] = button & 0xFF; break; } } - hid_report.keyboard.mods |= (button >> 8); + hid_report.keyboard.boot.mods |= (button >> 8); return hid_send_report(ReportIdKeyboard); } bool furi_hal_hid_kb_release(uint16_t button) { for(uint8_t key_nb = 0; key_nb < HID_KB_MAX_KEYS; key_nb++) { - if(hid_report.keyboard.btn[key_nb] == (button & 0xFF)) { - hid_report.keyboard.btn[key_nb] = 0; + if(hid_report.keyboard.boot.btn[key_nb] == (button & 0xFF)) { + hid_report.keyboard.boot.btn[key_nb] = 0; break; } } - hid_report.keyboard.mods &= ~(button >> 8); + hid_report.keyboard.boot.mods &= ~(button >> 8); return hid_send_report(ReportIdKeyboard); } bool furi_hal_hid_kb_release_all() { for(uint8_t key_nb = 0; key_nb < HID_KB_MAX_KEYS; key_nb++) { - hid_report.keyboard.btn[key_nb] = 0; + hid_report.keyboard.boot.btn[key_nb] = 0; } - hid_report.keyboard.mods = 0; + hid_report.keyboard.boot.mods = 0; return hid_send_report(ReportIdKeyboard); } @@ -434,27 +434,35 @@ static void hid_on_suspend(usbd_device* dev) { static bool hid_send_report(uint8_t report_id) { if((hid_semaphore == NULL) || (hid_connected == false)) return false; + if((boot_protocol == true) && (report_id != ReportIdKeyboard)) return false; furi_check(furi_semaphore_acquire(hid_semaphore, FuriWaitForever) == FuriStatusOk); - if(hid_connected == true) { + if(hid_connected == false) { + return false; + } + if(boot_protocol == true) { + usbd_ep_write( + usb_dev, HID_EP_IN, &hid_report.keyboard.boot, sizeof(hid_report.keyboard.boot)); + } else { if(report_id == ReportIdKeyboard) usbd_ep_write(usb_dev, HID_EP_IN, &hid_report.keyboard, sizeof(hid_report.keyboard)); else if(report_id == ReportIdMouse) usbd_ep_write(usb_dev, HID_EP_IN, &hid_report.mouse, sizeof(hid_report.mouse)); else if(report_id == ReportIdConsumer) usbd_ep_write(usb_dev, HID_EP_IN, &hid_report.consumer, sizeof(hid_report.consumer)); - return true; } - return false; + return true; } static void hid_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) { UNUSED(dev); if(event == usbd_evt_eptx) { furi_semaphore_release(hid_semaphore); + } else if(boot_protocol == true) { + usbd_ep_read(usb_dev, ep, &led_state, sizeof(led_state)); } else { struct HidReportLED leds; - usbd_ep_read(usb_dev, ep, &leds, 2); + usbd_ep_read(usb_dev, ep, &leds, sizeof(leds)); led_state = leds.led_state; } } @@ -464,18 +472,15 @@ static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg) { switch(cfg) { case 0: /* deconfiguring device */ - usbd_ep_deconfig(dev, HID_EP_OUT); usbd_ep_deconfig(dev, HID_EP_IN); - usbd_reg_endpoint(dev, HID_EP_OUT, 0); usbd_reg_endpoint(dev, HID_EP_IN, 0); return usbd_ack; case 1: /* configuring device */ usbd_ep_config(dev, HID_EP_IN, USB_EPTYPE_INTERRUPT, HID_EP_SZ); - usbd_ep_config(dev, HID_EP_OUT, USB_EPTYPE_INTERRUPT, HID_EP_SZ); usbd_reg_endpoint(dev, HID_EP_IN, hid_txrx_ep_callback); - usbd_reg_endpoint(dev, HID_EP_OUT, hid_txrx_ep_callback); usbd_ep_write(dev, HID_EP_IN, 0, 0); + boot_protocol = false; /* BIOS will SET_PROTOCOL if it wants this */ return usbd_ack; default: return usbd_fail; @@ -493,8 +498,21 @@ static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_cal case USB_HID_SETIDLE: return usbd_ack; case USB_HID_GETREPORT: - dev->status.data_ptr = &hid_report; - dev->status.data_count = sizeof(hid_report); + if(boot_protocol == true) { + dev->status.data_ptr = &hid_report.keyboard.boot; + dev->status.data_count = sizeof(hid_report.keyboard.boot); + } else { + dev->status.data_ptr = &hid_report; + dev->status.data_count = sizeof(hid_report); + } + return usbd_ack; + case USB_HID_SETPROTOCOL: + if(req->wValue == 0) + boot_protocol = true; + else if(req->wValue == 1) + boot_protocol = false; + else + return usbd_fail; return usbd_ack; default: return usbd_fail; @@ -505,10 +523,11 @@ static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_cal req->wIndex == 0 && req->bRequest == USB_STD_GET_DESCRIPTOR) { switch(req->wValue >> 8) { case USB_DTYPE_HID: - dev->status.data_ptr = (uint8_t*)&(hid_cfg_desc.iad_0.hid_desc); - dev->status.data_count = sizeof(hid_cfg_desc.iad_0.hid_desc); + dev->status.data_ptr = (uint8_t*)&(hid_cfg_desc.intf_0.hid_desc); + dev->status.data_count = sizeof(hid_cfg_desc.intf_0.hid_desc); return usbd_ack; case USB_DTYPE_HID_REPORT: + boot_protocol = false; /* BIOS does not read this */ dev->status.data_ptr = (uint8_t*)hid_report_desc; dev->status.data_count = sizeof(hid_report_desc); return usbd_ack; From f5b818541e9bf9f059947557179f0da712a2db9e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 21 Mar 2023 17:57:46 +0300 Subject: [PATCH 06/26] Add 318 mhz back to hopping list --- documentation/SubGHzSettings.md | 1 + lib/subghz/subghz_setting.c | 1 + 2 files changed, 2 insertions(+) diff --git a/documentation/SubGHzSettings.md b/documentation/SubGHzSettings.md index 2d14307c7a..9ba44ca332 100644 --- a/documentation/SubGHzSettings.md +++ b/documentation/SubGHzSettings.md @@ -91,6 +91,7 @@ Your frequencies will be added after default ones ``` 310000000, 315000000, + 318000000, 433920000, 868350000, ``` diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 34cf169159..8692e61942 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -79,6 +79,7 @@ static const uint32_t subghz_frequency_list[] = { static const uint32_t subghz_hopper_frequency_list[] = { 310000000, 315000000, + 318000000, 433920000, 868350000, 0, From c9cc2b5e20fa1bd8610f6b799be7da9c70dce940 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 21 Mar 2023 18:08:13 +0300 Subject: [PATCH 07/26] extra pack dev branch --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 9f8991c665..03f678bd5b 100644 --- a/.drone.yml +++ b/.drone.yml @@ -281,7 +281,7 @@ steps: image: hfdj/fztools pull: never commands: - - git clone https://github.com/xMasterX/unleashed-extra-pack.git + - git clone --branch dev https://github.com/xMasterX/unleashed-extra-pack.git - cp -R unleashed-extra-pack/apps/* assets/resources/apps/ - rm -rf unleashed-extra-pack - export DIST_SUFFIX=${DRONE_BUILD_NUMBER}e From 8373a21af20e5ffeb981676ced0731d7dab83df5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 21 Mar 2023 19:03:53 +0300 Subject: [PATCH 08/26] Update TOTP https://github.com/akopachov/flipper-zero_authenticator --- applications/external/totp/application.fam | 6 +- applications/external/totp/cli/cli.c | 3 + .../external/totp/cli/commands/add/add.c | 2 +- .../totp/cli/commands/automation/automation.c | 133 +++++++++++++++++ .../totp/cli/commands/automation/automation.h | 11 ++ .../totp/cli/commands/delete/delete.c | 2 +- .../external/totp/cli/commands/help/help.c | 4 + .../cli/commands/notification/notification.c | 4 +- .../totp/cli/commands/timezone/timezone.c | 2 +- applications/external/totp/features_config.h | 2 + .../external/totp/images/hid_ble_10x7.png | Bin 0 -> 158 bytes .../external/totp/services/config/config.c | 59 ++++++++ .../external/totp/services/config/config.h | 8 + .../external/totp/services/config/constants.h | 1 + applications/external/totp/totp_app.c | 16 ++ .../external/totp/types/automation_method.h | 13 ++ .../external/totp/types/plugin_state.h | 17 +++ .../external/totp/ui/scene_director.c | 4 +- .../scenes/app_settings/totp_app_settings.c | 104 ++++++++++++- .../totp_scene_generate_token.c | 93 +++++++++--- .../totp/workers/bt_type_code/bt_type_code.c | 141 ++++++++++++++++++ .../totp/workers/bt_type_code/bt_type_code.h | 35 +++++ .../external/totp/workers/constants.c | 14 ++ .../external/totp/workers/constants.h | 4 + .../totp/workers/type_code/type_code.h | 27 ---- .../usb_type_code.c} | 52 +++---- .../workers/usb_type_code/usb_type_code.h | 30 ++++ 27 files changed, 696 insertions(+), 91 deletions(-) create mode 100644 applications/external/totp/cli/commands/automation/automation.c create mode 100644 applications/external/totp/cli/commands/automation/automation.h create mode 100644 applications/external/totp/features_config.h create mode 100644 applications/external/totp/images/hid_ble_10x7.png create mode 100644 applications/external/totp/types/automation_method.h create mode 100644 applications/external/totp/workers/bt_type_code/bt_type_code.c create mode 100644 applications/external/totp/workers/bt_type_code/bt_type_code.h create mode 100644 applications/external/totp/workers/constants.c create mode 100644 applications/external/totp/workers/constants.h delete mode 100644 applications/external/totp/workers/type_code/type_code.h rename applications/external/totp/workers/{type_code/type_code.c => usb_type_code/usb_type_code.c} (68%) create mode 100644 applications/external/totp/workers/usb_type_code/usb_type_code.h diff --git a/applications/external/totp/application.fam b/applications/external/totp/application.fam index 600ed6ca3f..3c7ba149ed 100644 --- a/applications/external/totp/application.fam +++ b/applications/external/totp/application.fam @@ -9,10 +9,14 @@ App( "dialogs", "storage", "input", - "notification" + "notification", + "bt" ], stack_size=2 * 1024, order=20, + fap_author="Alexander Kopachov (@akopachov)", + fap_description="Software-based TOTP authenticator for Flipper Zero device", + fap_weburl="https://github.com/akopachov/flipper-zero_authenticator", fap_category="Misc", fap_icon_assets="images", fap_icon="totp_10px.png", diff --git a/applications/external/totp/cli/cli.c b/applications/external/totp/cli/cli.c index 28d1737662..ce25308042 100644 --- a/applications/external/totp/cli/cli.c +++ b/applications/external/totp/cli/cli.c @@ -12,6 +12,7 @@ #include "commands/pin/pin.h" #include "commands/notification/notification.h" #include "commands/reset/reset.h" +#include "commands/automation/automation.h" static void totp_cli_print_unknown_command(const FuriString* unknown_command) { TOTP_CLI_PRINTF_ERROR( @@ -57,6 +58,8 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) { totp_cli_command_pin_handle(plugin_state, args, cli); } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_NOTIFICATION) == 0) { totp_cli_command_notification_handle(plugin_state, args, cli); + } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_AUTOMATION) == 0) { + totp_cli_command_automation_handle(plugin_state, args, cli); } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_RESET) == 0) { totp_cli_command_reset_handle(cli, cli_context->event_queue); } else { diff --git a/applications/external/totp/cli/commands/add/add.c b/applications/external/totp/cli/commands/add/add.c index fbcd58530c..91f9256b29 100644 --- a/applications/external/totp/cli/commands/add/add.c +++ b/applications/external/totp/cli/commands/add/add.c @@ -62,7 +62,7 @@ void totp_cli_command_add_docopt_usage() { } void totp_cli_command_add_docopt_arguments() { - TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD_ARG_NAME " Token name\r\n"); + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_ADD_ARG_NAME " Token name\r\n"); } void totp_cli_command_add_docopt_options() { diff --git a/applications/external/totp/cli/commands/automation/automation.c b/applications/external/totp/cli/commands/automation/automation.c new file mode 100644 index 0000000000..1fd87f456b --- /dev/null +++ b/applications/external/totp/cli/commands/automation/automation.c @@ -0,0 +1,133 @@ +#include "automation.h" +#include +#include "../../../services/config/config.h" +#include "../../../ui/scene_director.h" +#include "../../cli_helpers.h" + +#define TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD "automation" +#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE "none" +#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "usb" +#ifdef TOTP_BADBT_TYPE_ENABLED +#define TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT "bt" +#endif + +void totp_cli_command_automation_docopt_commands() { + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_AUTOMATION " Get or set automation method\r\n"); +} + +void totp_cli_command_automation_docopt_usage() { + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_AUTOMATION " " DOCOPT_OPTIONAL( + DOCOPT_MULTIPLE(DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD))) "\r\n"); +} + +void totp_cli_command_automation_docopt_arguments() { + TOTP_CLI_PRINTF( + " " TOTP_CLI_COMMAND_AUTOMATION_ARG_METHOD + " Automation method to be set. Must be one of [" TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE + ", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB +#ifdef TOTP_BADBT_TYPE_ENABLED + ", " TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT +#endif + "]\r\n"); +} + +static void totp_cli_command_automation_print_method(AutomationMethod method, char* color) { +#ifdef TOTP_BADBT_TYPE_ENABLED + bool has_previous_method = false; +#endif + if(method & AutomationMethodBadUsb) { + TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB "\""); +#ifdef TOTP_BADBT_TYPE_ENABLED + has_previous_method = true; +#endif + } + +#ifdef TOTP_BADBT_TYPE_ENABLED + if(method & AutomationMethodBadBt) { + if(has_previous_method) { + TOTP_CLI_PRINTF_COLORFUL(color, " and "); + } + + TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT "\""); + } +#endif + + if(method == AutomationMethodNone) { + TOTP_CLI_PRINTF_COLORFUL(color, "\"" TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE "\""); + } +} + +void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* args, Cli* cli) { + if(!totp_cli_ensure_authenticated(plugin_state, cli)) { + return; + } + + FuriString* temp_str = furi_string_alloc(); + bool new_method_provided = false; + AutomationMethod new_method = AutomationMethodNone; + bool args_valid = true; + while(args_read_string_and_trim(args, temp_str)) { + if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_NONE) == 0) { + new_method_provided = true; + new_method = AutomationMethodNone; + } else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_USB) == 0) { + new_method_provided = true; + new_method |= AutomationMethodBadUsb; + } +#ifdef TOTP_BADBT_TYPE_ENABLED + else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_AUTOMATION_METHOD_BT) == 0) { + new_method_provided = true; + new_method |= AutomationMethodBadBt; + } +#endif + else { + args_valid = false; + break; + } + } + + do { + if(!args_valid) { + TOTP_CLI_PRINT_INVALID_ARGUMENTS(); + break; + } + + if(new_method_provided) { + Scene previous_scene = TotpSceneNone; + if(plugin_state->current_scene == TotpSceneGenerateToken || + plugin_state->current_scene == TotpSceneAppSettings) { + previous_scene = plugin_state->current_scene; + totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL); + } + + plugin_state->automation_method = new_method; + if(totp_config_file_update_automation_method(new_method) == + TotpConfigFileUpdateSuccess) { + TOTP_CLI_PRINTF_SUCCESS("Automation method is set to "); + totp_cli_command_automation_print_method(new_method, TOTP_CLI_COLOR_SUCCESS); + cli_nl(); + } else { + TOTP_CLI_PRINT_ERROR_UPDATING_CONFIG_FILE(); + } + +#ifdef TOTP_BADBT_TYPE_ENABLED + if(!(new_method & AutomationMethodBadBt) && + plugin_state->bt_type_code_worker_context != NULL) { + totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); + plugin_state->bt_type_code_worker_context = NULL; + } +#endif + + if(previous_scene != TotpSceneNone) { + totp_scene_director_activate_scene(plugin_state, previous_scene, NULL); + } + } else { + TOTP_CLI_PRINTF_INFO("Current automation method is "); + totp_cli_command_automation_print_method( + plugin_state->automation_method, TOTP_CLI_COLOR_INFO); + cli_nl(); + } + } while(false); + + furi_string_free(temp_str); +} \ No newline at end of file diff --git a/applications/external/totp/cli/commands/automation/automation.h b/applications/external/totp/cli/commands/automation/automation.h new file mode 100644 index 0000000000..fb62e638ef --- /dev/null +++ b/applications/external/totp/cli/commands/automation/automation.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include "../../../types/plugin_state.h" + +#define TOTP_CLI_COMMAND_AUTOMATION "automation" + +void totp_cli_command_automation_handle(PluginState* plugin_state, FuriString* args, Cli* cli); +void totp_cli_command_automation_docopt_commands(); +void totp_cli_command_automation_docopt_usage(); +void totp_cli_command_automation_docopt_arguments(); \ No newline at end of file diff --git a/applications/external/totp/cli/commands/delete/delete.c b/applications/external/totp/cli/commands/delete/delete.c index 8fe72e2209..04cc815a44 100644 --- a/applications/external/totp/cli/commands/delete/delete.c +++ b/applications/external/totp/cli/commands/delete/delete.c @@ -24,7 +24,7 @@ void totp_cli_command_delete_docopt_usage() { } void totp_cli_command_delete_docopt_arguments() { - TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_DELETE_ARG_INDEX " Token index in the list\r\n"); + TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_DELETE_ARG_INDEX " Token index in the list\r\n"); } void totp_cli_command_delete_docopt_options() { diff --git a/applications/external/totp/cli/commands/help/help.c b/applications/external/totp/cli/commands/help/help.c index 104b39e473..34b44debd2 100644 --- a/applications/external/totp/cli/commands/help/help.c +++ b/applications/external/totp/cli/commands/help/help.c @@ -8,6 +8,7 @@ #include "../pin/pin.h" #include "../notification/notification.h" #include "../reset/reset.h" +#include "../automation/automation.h" void totp_cli_command_help_docopt_commands() { TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_HELP ", " TOTP_CLI_COMMAND_HELP_ALT @@ -31,6 +32,7 @@ void totp_cli_command_help_handle() { totp_cli_command_pin_docopt_usage(); totp_cli_command_notification_docopt_usage(); totp_cli_command_reset_docopt_usage(); + totp_cli_command_automation_docopt_usage(); cli_nl(); TOTP_CLI_PRINTF("Commands:\r\n"); totp_cli_command_help_docopt_commands(); @@ -42,12 +44,14 @@ void totp_cli_command_help_handle() { totp_cli_command_pin_docopt_commands(); totp_cli_command_notification_docopt_commands(); totp_cli_command_reset_docopt_commands(); + totp_cli_command_automation_docopt_commands(); cli_nl(); TOTP_CLI_PRINTF("Arguments:\r\n"); totp_cli_command_add_docopt_arguments(); totp_cli_command_delete_docopt_arguments(); totp_cli_command_timezone_docopt_arguments(); totp_cli_command_notification_docopt_arguments(); + totp_cli_command_automation_docopt_arguments(); cli_nl(); TOTP_CLI_PRINTF("Options:\r\n"); totp_cli_command_add_docopt_options(); diff --git a/applications/external/totp/cli/commands/notification/notification.c b/applications/external/totp/cli/commands/notification/notification.c index bbbd52703b..016b83d0d6 100644 --- a/applications/external/totp/cli/commands/notification/notification.c +++ b/applications/external/totp/cli/commands/notification/notification.c @@ -4,7 +4,7 @@ #include "../../../ui/scene_director.h" #include "../../cli_helpers.h" -#define TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD "method" +#define TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD "notification" #define TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE "none" #define TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND "sound" #define TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "vibro" @@ -23,7 +23,7 @@ void totp_cli_command_notification_docopt_usage() { void totp_cli_command_notification_docopt_arguments() { TOTP_CLI_PRINTF( " " TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD - " Notification method to be set. Must be one of [" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE + " Notification method to be set. Must be one of [" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE ", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND ", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "]\r\n"); } diff --git a/applications/external/totp/cli/commands/timezone/timezone.c b/applications/external/totp/cli/commands/timezone/timezone.c index 9eb0cb5f64..265d80e533 100644 --- a/applications/external/totp/cli/commands/timezone/timezone.c +++ b/applications/external/totp/cli/commands/timezone/timezone.c @@ -20,7 +20,7 @@ void totp_cli_command_timezone_docopt_usage() { void totp_cli_command_timezone_docopt_arguments() { TOTP_CLI_PRINTF(" " TOTP_CLI_COMMAND_TIMEZONE_ARG_TIMEZONE - " Timezone offset in hours to be set\r\n"); + " Timezone offset in hours to be set\r\n"); } void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* args, Cli* cli) { diff --git a/applications/external/totp/features_config.h b/applications/external/totp/features_config.h new file mode 100644 index 0000000000..d3b30aee01 --- /dev/null +++ b/applications/external/totp/features_config.h @@ -0,0 +1,2 @@ +#define TOTP_BADBT_TYPE_ENABLED +#define TOTP_BADBT_TYPE_ICON_ENABLED \ No newline at end of file diff --git a/applications/external/totp/images/hid_ble_10x7.png b/applications/external/totp/images/hid_ble_10x7.png new file mode 100644 index 0000000000000000000000000000000000000000..3cd1ff95c839feb20b715a60d402412836234dcd GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^AT~P-Gmt#obT9x&F%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl{i3-AeX{r~?zkQsXDavhN3EbxddW?FVdQ&MBb@0LsoQ&Hw-a literal 0 HcmV?d00001 diff --git a/applications/external/totp/services/config/config.c b/applications/external/totp/services/config/config.c index 034ed925e2..66c07ebfa8 100644 --- a/applications/external/totp/services/config/config.c +++ b/applications/external/totp/services/config/config.c @@ -4,6 +4,7 @@ #include "../list/list.h" #include "../../types/common.h" #include "../../types/token_info.h" +#include "../../features_config.h" #include "migrations/config_migration_v1_to_v2.h" #include "migrations/config_migration_v2_to_v3.h" @@ -136,6 +137,14 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF flipper_format_write_uint32( fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1); + tmp_uint32 = AutomationMethodBadUsb; + flipper_format_write_comment_cstr(fff_data_file, " "); + flipper_format_write_comment_cstr( + fff_data_file, + "Automation method (0 - None, 1 - BadUSB, 2 - BadBT, 3 - BadUSB and BadBT)"); + flipper_format_write_uint32( + fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1); + FuriString* temp_str = furi_string_alloc(); flipper_format_write_comment_cstr(fff_data_file, " "); @@ -329,6 +338,33 @@ TotpConfigFileUpdateResult return update_result; } +TotpConfigFileUpdateResult + totp_config_file_update_automation_method(AutomationMethod new_automation_method) { + Storage* cfg_storage = totp_open_storage(); + FlipperFormat* file; + TotpConfigFileUpdateResult update_result; + + if(totp_open_config_file(cfg_storage, &file) == TotpConfigFileOpenSuccess) { + do { + uint32_t tmp_uint32 = new_automation_method; + if(!flipper_format_insert_or_update_uint32( + file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) { + update_result = TotpConfigFileUpdateError; + break; + } + + update_result = TotpConfigFileUpdateSuccess; + } while(false); + + totp_close_config_file(file); + } else { + update_result = TotpConfigFileUpdateError; + } + + totp_close_storage(); + return update_result; +} + TotpConfigFileUpdateResult totp_config_file_update_user_settings(const PluginState* plugin_state) { Storage* cfg_storage = totp_open_storage(); FlipperFormat* file; @@ -347,6 +383,13 @@ TotpConfigFileUpdateResult totp_config_file_update_user_settings(const PluginSta break; } + tmp_uint32 = plugin_state->automation_method; + if(!flipper_format_insert_or_update_uint32( + file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) { + update_result = TotpConfigFileUpdateError; + break; + } + update_result = TotpConfigFileUpdateSuccess; } while(false); @@ -409,6 +452,13 @@ TotpConfigFileUpdateResult totp_full_save_config_file(const PluginState* const p break; } + tmp_uint32 = plugin_state->automation_method; + if(!flipper_format_write_uint32( + fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) { + result = TotpConfigFileUpdateError; + break; + } + bool tokens_written = true; TOTP_LIST_FOREACH(plugin_state->tokens_list, node, { const TokenInfo* token_info = node->data; @@ -594,6 +644,15 @@ TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_st } plugin_state->notification_method = tmp_uint32; + + flipper_format_rewind(fff_data_file); + + if(!flipper_format_read_uint32( + fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1)) { + tmp_uint32 = AutomationMethodBadUsb; + } + + plugin_state->automation_method = tmp_uint32; } while(false); furi_string_free(temp_str); diff --git a/applications/external/totp/services/config/config.h b/applications/external/totp/services/config/config.h index c630810a65..3d325368d4 100644 --- a/applications/external/totp/services/config/config.h +++ b/applications/external/totp/services/config/config.h @@ -103,6 +103,14 @@ TotpConfigFileUpdateResult totp_config_file_update_timezone_offset(float new_tim TotpConfigFileUpdateResult totp_config_file_update_notification_method(NotificationMethod new_notification_method); +/** + * @brief Updates automation method in an application config file + * @param new_automation_method new automation method to be set + * @return Config file update result + */ +TotpConfigFileUpdateResult + totp_config_file_update_automation_method(AutomationMethod new_automation_method); + /** * @brief Updates application user settings * @param plugin_state application state diff --git a/applications/external/totp/services/config/constants.h b/applications/external/totp/services/config/constants.h index 487fb159e1..526179f412 100644 --- a/applications/external/totp/services/config/constants.h +++ b/applications/external/totp/services/config/constants.h @@ -13,6 +13,7 @@ #define TOTP_CONFIG_KEY_BASE_IV "BaseIV" #define TOTP_CONFIG_KEY_PINSET "PinIsSet" #define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod" +#define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod" #define TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME "sha1" #define TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME "sha256" diff --git a/applications/external/totp/totp_app.c b/applications/external/totp/totp_app.c index 966c9fb346..74ec52f2c0 100644 --- a/applications/external/totp/totp_app.c +++ b/applications/external/totp/totp_app.c @@ -8,6 +8,7 @@ #include #include #include +#include "features_config.h" #include "services/config/config.h" #include "types/plugin_state.h" #include "types/token_info.h" @@ -108,6 +109,14 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) { return false; } +#ifdef TOTP_BADBT_TYPE_ENABLED + if(plugin_state->automation_method & AutomationMethodBadBt) { + plugin_state->bt_type_code_worker_context = totp_bt_type_code_worker_init(); + } else { + plugin_state->bt_type_code_worker_context = NULL; + } +#endif + return true; } @@ -130,6 +139,13 @@ static void totp_plugin_state_free(PluginState* plugin_state) { free(plugin_state->crypto_verify_data); } +#ifdef TOTP_BADBT_TYPE_ENABLED + if(plugin_state->bt_type_code_worker_context != NULL) { + totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); + plugin_state->bt_type_code_worker_context = NULL; + } +#endif + furi_mutex_free(plugin_state->mutex); free(plugin_state); } diff --git a/applications/external/totp/types/automation_method.h b/applications/external/totp/types/automation_method.h new file mode 100644 index 0000000000..b51e59e03c --- /dev/null +++ b/applications/external/totp/types/automation_method.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../features_config.h" + +typedef uint8_t AutomationMethod; + +enum AutomationMethods { + AutomationMethodNone = 0b00, + AutomationMethodBadUsb = 0b01, +#ifdef TOTP_BADBT_TYPE_ENABLED + AutomationMethodBadBt = 0b10, +#endif +}; diff --git a/applications/external/totp/types/plugin_state.h b/applications/external/totp/types/plugin_state.h index dee5003052..59a218ce3b 100644 --- a/applications/external/totp/types/plugin_state.h +++ b/applications/external/totp/types/plugin_state.h @@ -3,9 +3,14 @@ #include #include #include +#include "../features_config.h" #include "../lib/list/list.h" #include "../ui/totp_scenes_enum.h" #include "notification_method.h" +#include "automation_method.h" +#ifdef TOTP_BADBT_TYPE_ENABLED +#include "../workers/bt_type_code/bt_type_code.h" +#endif #define TOTP_IV_SIZE 16 @@ -92,4 +97,16 @@ typedef struct { * @brief Main rendering loop mutex */ FuriMutex* mutex; + + /** + * @brief Automation method + */ + AutomationMethod automation_method; + +#ifdef TOTP_BADBT_TYPE_ENABLED + /** + * @brief Bad-Bluetooth worker context + */ + TotpBtTypeCodeWorkerContext* bt_type_code_worker_context; +#endif } PluginState; diff --git a/applications/external/totp/ui/scene_director.c b/applications/external/totp/ui/scene_director.c index fcc9f37d8e..c77e88ab4b 100644 --- a/applications/external/totp/ui/scene_director.c +++ b/applications/external/totp/ui/scene_director.c @@ -37,7 +37,9 @@ void totp_scene_director_activate_scene( } void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state) { - switch(plugin_state->current_scene) { + Scene current_scene = plugin_state->current_scene; + plugin_state->current_scene = TotpSceneNone; + switch(current_scene) { case TotpSceneGenerateToken: totp_scene_generate_token_deactivate(plugin_state); break; diff --git a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c index b8936f3955..1671542b87 100644 --- a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c +++ b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c @@ -10,16 +10,35 @@ #include "../../../services/convert/convert.h" #include "../../../lib/roll_value/roll_value.h" #include "../../../types/nullable.h" +#include "../../../features_config.h" +#ifdef TOTP_BADBT_TYPE_ENABLED +#include "../../../workers/bt_type_code/bt_type_code.h" +#endif char* YES_NO_LIST[] = {"NO", "YES"}; +char* ON_OFF_LIST[] = {"OFF", "ON"}; -typedef enum { HoursInput, MinutesInput, Sound, Vibro, ConfirmButton } Control; +typedef enum { + HoursInput, + MinutesInput, + Sound, + Vibro, + BadUsb, +#ifdef TOTP_BADBT_TYPE_ENABLED + BadBt, +#endif + ConfirmButton +} Control; typedef struct { int8_t tz_offset_hours; uint8_t tz_offset_minutes; bool notification_sound; bool notification_vibro; + bool badusb_enabled; +#ifdef TOTP_BADBT_TYPE_ENABLED + bool badbt_enabled; +#endif uint8_t y_offset; TotpNullable_uint16_t current_token_index; Control selected_control; @@ -47,6 +66,10 @@ void totp_scene_app_settings_activate( scene_state->tz_offset_minutes = 60.0f * off_dec; scene_state->notification_sound = plugin_state->notification_method & NotificationMethodSound; scene_state->notification_vibro = plugin_state->notification_method & NotificationMethodVibro; + scene_state->badusb_enabled = plugin_state->automation_method & AutomationMethodBadUsb; +#ifdef TOTP_BADBT_TYPE_ENABLED + scene_state->badbt_enabled = plugin_state->automation_method & AutomationMethodBadBt; +#endif } static void two_digit_to_str(int8_t num, char* str) { @@ -73,7 +96,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu char tmp_str[4]; two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]); - canvas_draw_str_aligned(canvas, 0, 16 - scene_state->y_offset, AlignLeft, AlignTop, "Hours:"); + canvas_draw_str_aligned(canvas, 0, 17 - scene_state->y_offset, AlignLeft, AlignTop, "Hours:"); ui_control_select_render( canvas, 36, @@ -84,7 +107,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu two_digit_to_str(scene_state->tz_offset_minutes, &tmp_str[0]); canvas_draw_str_aligned( - canvas, 0, 34 - scene_state->y_offset, AlignLeft, AlignTop, "Minutes:"); + canvas, 0, 35 - scene_state->y_offset, AlignLeft, AlignTop, "Minutes:"); ui_control_select_render( canvas, 36, @@ -104,7 +127,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications"); canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 0, 80 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:"); + canvas_draw_str_aligned(canvas, 0, 81 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:"); ui_control_select_render( canvas, 36, @@ -113,7 +136,7 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu YES_NO_LIST[scene_state->notification_sound], scene_state->selected_control == Sound); - canvas_draw_str_aligned(canvas, 0, 98 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:"); + canvas_draw_str_aligned(canvas, 0, 99 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:"); ui_control_select_render( canvas, 36, @@ -122,10 +145,43 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu YES_NO_LIST[scene_state->notification_vibro], scene_state->selected_control == Vibro); + canvas_draw_icon( + canvas, SCREEN_WIDTH_CENTER - 5, 123 - scene_state->y_offset, &I_totp_arrow_bottom_10x5); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 0, 128 - scene_state->y_offset, AlignLeft, AlignTop, "Automation"); + canvas_set_font(canvas, FontSecondary); + + canvas_draw_str_aligned( + canvas, 0, 145 - scene_state->y_offset, AlignLeft, AlignTop, "BadUSB:"); + ui_control_select_render( + canvas, + 36, + 138 - scene_state->y_offset, + SCREEN_WIDTH - 36, + ON_OFF_LIST[scene_state->badusb_enabled], + scene_state->selected_control == BadUsb); + +#ifdef TOTP_BADBT_TYPE_ENABLED + canvas_draw_str_aligned(canvas, 0, 163 - scene_state->y_offset, AlignLeft, AlignTop, "BadBT:"); + ui_control_select_render( + canvas, + 36, + 156 - scene_state->y_offset, + SCREEN_WIDTH - 36, + ON_OFF_LIST[scene_state->badbt_enabled], + scene_state->selected_control == BadBt); +#endif + ui_control_button_render( canvas, SCREEN_WIDTH_CENTER - 24, - 115 - scene_state->y_offset, +#ifdef TOTP_BADBT_TYPE_ENABLED + 178 - scene_state->y_offset, +#else + 165 - scene_state->y_offset, +#endif 48, 13, "Confirm", @@ -152,7 +208,9 @@ bool totp_scene_app_settings_handle_event( HoursInput, ConfirmButton, RollOverflowBehaviorStop); - if(scene_state->selected_control > MinutesInput) { + if(scene_state->selected_control > Vibro) { + scene_state->y_offset = 128; + } else if(scene_state->selected_control > MinutesInput) { scene_state->y_offset = 64; } else { scene_state->y_offset = 0; @@ -161,7 +219,9 @@ bool totp_scene_app_settings_handle_event( case InputKeyDown: totp_roll_value_uint8_t( &scene_state->selected_control, 1, HoursInput, ConfirmButton, RollOverflowBehaviorStop); - if(scene_state->selected_control > MinutesInput) { + if(scene_state->selected_control > Vibro) { + scene_state->y_offset = 128; + } else if(scene_state->selected_control > MinutesInput) { scene_state->y_offset = 64; } else { scene_state->y_offset = 0; @@ -178,7 +238,14 @@ bool totp_scene_app_settings_handle_event( scene_state->notification_sound = !scene_state->notification_sound; } else if(scene_state->selected_control == Vibro) { scene_state->notification_vibro = !scene_state->notification_vibro; + } else if(scene_state->selected_control == BadUsb) { + scene_state->badusb_enabled = !scene_state->badusb_enabled; } +#ifdef TOTP_BADBT_TYPE_ENABLED + else if(scene_state->selected_control == BadBt) { + scene_state->badbt_enabled = !scene_state->badbt_enabled; + } +#endif break; case InputKeyLeft: if(scene_state->selected_control == HoursInput) { @@ -191,7 +258,14 @@ bool totp_scene_app_settings_handle_event( scene_state->notification_sound = !scene_state->notification_sound; } else if(scene_state->selected_control == Vibro) { scene_state->notification_vibro = !scene_state->notification_vibro; + } else if(scene_state->selected_control == BadUsb) { + scene_state->badusb_enabled = !scene_state->badusb_enabled; + } +#ifdef TOTP_BADBT_TYPE_ENABLED + else if(scene_state->selected_control == BadBt) { + scene_state->badbt_enabled = !scene_state->badbt_enabled; } +#endif break; case InputKeyOk: if(scene_state->selected_control == ConfirmButton) { @@ -204,12 +278,26 @@ bool totp_scene_app_settings_handle_event( (scene_state->notification_vibro ? NotificationMethodVibro : NotificationMethodNone); + plugin_state->automation_method = + scene_state->badusb_enabled ? AutomationMethodBadUsb : AutomationMethodNone; +#ifdef TOTP_BADBT_TYPE_ENABLED + plugin_state->automation_method |= scene_state->badbt_enabled ? AutomationMethodBadBt : + AutomationMethodNone; +#endif + if(totp_config_file_update_user_settings(plugin_state) != TotpConfigFileUpdateSuccess) { totp_dialogs_config_updating_error(plugin_state); return false; } +#ifdef TOTP_BADBT_TYPE_ENABLED + if(!scene_state->badbt_enabled && plugin_state->bt_type_code_worker_context != NULL) { + totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); + plugin_state->bt_type_code_worker_context = NULL; + } +#endif + if(!scene_state->current_token_index.is_null) { TokenMenuSceneContext generate_scene_context = { .current_token_index = scene_state->current_token_index.value}; diff --git a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c index a882ae78ca..9e8b21d09a 100644 --- a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -14,7 +14,11 @@ #include "../../../lib/roll_value/roll_value.h" #include "../../scene_director.h" #include "../token_menu/totp_scene_token_menu.h" -#include "../../../workers/type_code/type_code.h" +#include "../../../features_config.h" +#include "../../../workers/usb_type_code/usb_type_code.h" +#ifdef TOTP_BADBT_TYPE_ENABLED +#include "../../../workers/bt_type_code/bt_type_code.h" +#endif static const uint8_t PROGRESS_BAR_MARGIN = 3; static const uint8_t PROGRESS_BAR_HEIGHT = 4; @@ -25,9 +29,10 @@ typedef struct { bool need_token_update; TokenInfo* current_token; uint32_t last_token_gen_time; - TotpTypeCodeWorkerContext* type_code_worker_context; + TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context; NotificationMessage const** notification_sequence_new_token; NotificationMessage const** notification_sequence_badusb; + FuriMutex* last_code_update_sync; } SceneState; static const NotificationSequence* @@ -72,7 +77,7 @@ static const NotificationSequence* } static const NotificationSequence* - get_notification_sequence_badusb(const PluginState* plugin_state, SceneState* scene_state) { + get_notification_sequence_automation(const PluginState* plugin_state, SceneState* scene_state) { if(scene_state->notification_sequence_badusb == NULL) { uint8_t i = 0; uint8_t length = 3; @@ -201,9 +206,28 @@ void totp_scene_generate_token_activate( plugin_state->current_scene_state = scene_state; FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset); update_totp_params(plugin_state); - scene_state->type_code_worker_context = totp_type_code_worker_start(); - scene_state->type_code_worker_context->string = &scene_state->last_code[0]; - scene_state->type_code_worker_context->string_length = TOTP_TOKEN_DIGITS_MAX_COUNT + 1; + + scene_state->last_code_update_sync = furi_mutex_alloc(FuriMutexTypeNormal); + if(plugin_state->automation_method & AutomationMethodBadUsb) { + scene_state->usb_type_code_worker_context = totp_usb_type_code_worker_start( + &scene_state->last_code[0], + TOTP_TOKEN_DIGITS_MAX_COUNT + 1, + scene_state->last_code_update_sync); + } + +#ifdef TOTP_BADBT_TYPE_ENABLED + + if(plugin_state->automation_method & AutomationMethodBadBt) { + if(plugin_state->bt_type_code_worker_context == NULL) { + plugin_state->bt_type_code_worker_context = totp_bt_type_code_worker_init(); + } + totp_bt_type_code_worker_start( + plugin_state->bt_type_code_worker_context, + &scene_state->last_code[0], + TOTP_TOKEN_DIGITS_MAX_COUNT + 1, + scene_state->last_code_update_sync); + } +#endif } void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) { @@ -242,8 +266,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ const TokenInfo* tokenInfo = scene_state->current_token; if(tokenInfo->token != NULL && tokenInfo->token_length > 0) { - furi_mutex_acquire( - scene_state->type_code_worker_context->string_sync, FuriWaitForever); + furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever); size_t key_length; uint8_t* key = totp_crypto_decrypt( tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length); @@ -262,12 +285,11 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ memset_s(key, key_length, 0, key_length); free(key); } else { - furi_mutex_acquire( - scene_state->type_code_worker_context->string_sync, FuriWaitForever); + furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever); int_token_to_str(0, scene_state->last_code, tokenInfo->digits); } - furi_mutex_release(scene_state->type_code_worker_context->string_sync); + furi_mutex_release(scene_state->last_code_update_sync); if(is_new_token_time) { notification_message( @@ -327,6 +349,15 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ canvas_draw_icon( canvas, SCREEN_WIDTH - 9, SCREEN_HEIGHT_CENTER - 24, &I_totp_arrow_right_8x9); } + +#if defined(TOTP_BADBT_TYPE_ENABLED) && defined(TOTP_BADBT_TYPE_ICON_ENABLED) + if(plugin_state->automation_method & AutomationMethodBadBt && + plugin_state->bt_type_code_worker_context != NULL && + plugin_state->bt_type_code_worker_context->is_advertising) { + canvas_draw_icon( + canvas, SCREEN_WIDTH_CENTER - 5, SCREEN_HEIGHT_CENTER + 13, &I_hid_ble_10x7); + } +#endif } bool totp_scene_generate_token_handle_event( @@ -341,14 +372,27 @@ bool totp_scene_generate_token_handle_event( } SceneState* scene_state; - if(event->input.type == InputTypeLong && event->input.key == InputKeyDown) { - scene_state = (SceneState*)plugin_state->current_scene_state; - totp_type_code_worker_notify( - scene_state->type_code_worker_context, TotpTypeCodeWorkerEventType); - notification_message( - plugin_state->notification_app, - get_notification_sequence_badusb(plugin_state, scene_state)); - return true; + if(event->input.type == InputTypeLong) { + if(event->input.key == InputKeyDown && plugin_state->automation_method & AutomationMethodBadUsb) { + scene_state = (SceneState*)plugin_state->current_scene_state; + totp_usb_type_code_worker_notify( + scene_state->usb_type_code_worker_context, TotpUsbTypeCodeWorkerEventType); + notification_message( + plugin_state->notification_app, + get_notification_sequence_automation(plugin_state, scene_state)); + return true; + } +#ifdef TOTP_BADBT_TYPE_ENABLED + else if(event->input.key == InputKeyUp && plugin_state->automation_method & AutomationMethodBadBt) { + scene_state = (SceneState*)plugin_state->current_scene_state; + totp_bt_type_code_worker_notify( + plugin_state->bt_type_code_worker_context, TotpBtTypeCodeWorkerEventType); + notification_message( + plugin_state->notification_app, + get_notification_sequence_automation(plugin_state, scene_state)); + return true; + } +#endif } if(event->input.type != InputTypePress && event->input.type != InputTypeRepeat) { @@ -400,7 +444,14 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { if(plugin_state->current_scene_state == NULL) return; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - totp_type_code_worker_stop(scene_state->type_code_worker_context); + if(plugin_state->automation_method & AutomationMethodBadUsb) { + totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context); + } +#ifdef TOTP_BADBT_TYPE_ENABLED + if(plugin_state->automation_method & AutomationMethodBadBt) { + totp_bt_type_code_worker_stop(plugin_state->bt_type_code_worker_context); + } +#endif if(scene_state->notification_sequence_new_token != NULL) { free(scene_state->notification_sequence_new_token); @@ -410,6 +461,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { free(scene_state->notification_sequence_badusb); } + furi_mutex_free(scene_state->last_code_update_sync); + free(scene_state); plugin_state->current_scene_state = NULL; } diff --git a/applications/external/totp/workers/bt_type_code/bt_type_code.c b/applications/external/totp/workers/bt_type_code/bt_type_code.c new file mode 100644 index 0000000000..8b9cf6548b --- /dev/null +++ b/applications/external/totp/workers/bt_type_code/bt_type_code.c @@ -0,0 +1,141 @@ +#include "bt_type_code.h" +#include +#include +#include "../../types/common.h" +#include "../../services/convert/convert.h" +#include "../constants.h" + +#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys") + +static inline bool totp_type_code_worker_stop_requested() { + return furi_thread_flags_get() & TotpBtTypeCodeWorkerEventStop; +} + +static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context) { + uint8_t i = 0; + do { + furi_delay_ms(500); + i++; + } while(!furi_hal_bt_is_active() && i < 100 && !totp_type_code_worker_stop_requested()); + + if(furi_hal_bt_is_active() && furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) { + furi_delay_ms(500); + i = 0; + while(i < context->string_length && context->string[i] != 0) { + uint8_t digit = CONVERT_CHAR_TO_DIGIT(context->string[i]); + if(digit > 9) break; + uint8_t hid_kb_key = hid_number_keys[digit]; + furi_hal_bt_hid_kb_press(hid_kb_key); + furi_delay_ms(30); + furi_hal_bt_hid_kb_release(hid_kb_key); + i++; + } + + furi_mutex_release(context->string_sync); + } +} + +static int32_t totp_type_code_worker_callback(void* context) { + furi_assert(context); + FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + if(context_mutex == NULL) { + return 251; + } + + TotpBtTypeCodeWorkerContext* bt_context = context; + + furi_hal_bt_start_advertising(); + bt_context->is_advertising = true; + + while(true) { + uint32_t flags = furi_thread_flags_wait( + TotpBtTypeCodeWorkerEventStop | TotpBtTypeCodeWorkerEventType, + FuriFlagWaitAny, + FuriWaitForever); + furi_check((flags & FuriFlagError) == 0); //-V562 + if(flags & TotpBtTypeCodeWorkerEventStop) break; + + if(furi_mutex_acquire(context_mutex, FuriWaitForever) == FuriStatusOk) { + if(flags & TotpBtTypeCodeWorkerEventType) { + totp_type_code_worker_type_code(bt_context); + } + + furi_mutex_release(context_mutex); + } + } + + furi_hal_bt_stop_advertising(); + + bt_context->is_advertising = false; + + furi_mutex_free(context_mutex); + + return 0; +} + +void totp_bt_type_code_worker_start( + TotpBtTypeCodeWorkerContext* context, + char* code_buf, + uint8_t code_buf_length, + FuriMutex* code_buf_update_sync) { + furi_assert(context != NULL); + context->string = code_buf; + context->string_length = code_buf_length; + context->string_sync = code_buf_update_sync; + context->thread = furi_thread_alloc(); + furi_thread_set_name(context->thread, "TOTPBtHidWorker"); + furi_thread_set_stack_size(context->thread, 1024); + furi_thread_set_context(context->thread, context); + furi_thread_set_callback(context->thread, totp_type_code_worker_callback); + furi_thread_start(context->thread); +} + +void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context) { + furi_assert(context != NULL); + furi_thread_flags_set(furi_thread_get_id(context->thread), TotpBtTypeCodeWorkerEventStop); + furi_thread_join(context->thread); + furi_thread_free(context->thread); + context->thread = NULL; +} + +void totp_bt_type_code_worker_notify( + TotpBtTypeCodeWorkerContext* context, + TotpBtTypeCodeWorkerEvent event) { + furi_assert(context != NULL); + furi_thread_flags_set(furi_thread_get_id(context->thread), event); +} + +TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() { + TotpBtTypeCodeWorkerContext* context = malloc(sizeof(TotpBtTypeCodeWorkerContext)); + furi_check(context != NULL); + + context->bt = furi_record_open(RECORD_BT); + context->is_advertising = false; + bt_disconnect(context->bt); + furi_delay_ms(200); + bt_keys_storage_set_storage_path(context->bt, HID_BT_KEYS_STORAGE_PATH); + if(!bt_set_profile(context->bt, BtProfileHidKeyboard)) { + FURI_LOG_E(LOGGING_TAG, "Failed to switch BT to keyboard HID profile"); + } + + return context; +} + +void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context) { + furi_assert(context != NULL); + + if(context->thread != NULL) { + totp_bt_type_code_worker_stop(context); + } + + bt_disconnect(context->bt); + bt_keys_storage_set_default_path(context->bt); + + if(!bt_set_profile(context->bt, BtProfileSerial)) { + FURI_LOG_E(LOGGING_TAG, "Failed to switch BT to Serial profile"); + } + furi_record_close(RECORD_BT); + context->bt = NULL; + + free(context); +} \ No newline at end of file diff --git a/applications/external/totp/workers/bt_type_code/bt_type_code.h b/applications/external/totp/workers/bt_type_code/bt_type_code.h new file mode 100644 index 0000000000..475b66db40 --- /dev/null +++ b/applications/external/totp/workers/bt_type_code/bt_type_code.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include + +typedef uint8_t TotpBtTypeCodeWorkerEvent; + +typedef struct { + char* string; + uint8_t string_length; + FuriThread* thread; + FuriMutex* string_sync; + Bt* bt; + bool is_advertising; +} TotpBtTypeCodeWorkerContext; + +enum TotpBtTypeCodeWorkerEvents { + TotpBtTypeCodeWorkerEventReserved = (1 << 0), + TotpBtTypeCodeWorkerEventStop = (1 << 1), + TotpBtTypeCodeWorkerEventType = (1 << 2) +}; + +TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init(); +void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context); +void totp_bt_type_code_worker_start( + TotpBtTypeCodeWorkerContext* context, + char* code_buf, + uint8_t code_buf_length, + FuriMutex* code_buf_update_sync); +void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context); +void totp_bt_type_code_worker_notify( + TotpBtTypeCodeWorkerContext* context, + TotpBtTypeCodeWorkerEvent event); \ No newline at end of file diff --git a/applications/external/totp/workers/constants.c b/applications/external/totp/workers/constants.c new file mode 100644 index 0000000000..f3c1035781 --- /dev/null +++ b/applications/external/totp/workers/constants.c @@ -0,0 +1,14 @@ +#include "constants.h" +#include + +const uint8_t hid_number_keys[10] = { + HID_KEYBOARD_0, + HID_KEYBOARD_1, + HID_KEYBOARD_2, + HID_KEYBOARD_3, + HID_KEYBOARD_4, + HID_KEYBOARD_5, + HID_KEYBOARD_6, + HID_KEYBOARD_7, + HID_KEYBOARD_8, + HID_KEYBOARD_9}; \ No newline at end of file diff --git a/applications/external/totp/workers/constants.h b/applications/external/totp/workers/constants.h new file mode 100644 index 0000000000..c314b6c166 --- /dev/null +++ b/applications/external/totp/workers/constants.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const uint8_t hid_number_keys[10]; \ No newline at end of file diff --git a/applications/external/totp/workers/type_code/type_code.h b/applications/external/totp/workers/type_code/type_code.h deleted file mode 100644 index 27f2e02d4c..0000000000 --- a/applications/external/totp/workers/type_code/type_code.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include -#include - -typedef uint8_t TotpTypeCodeWorkerEvent; - -typedef struct { - char* string; - uint8_t string_length; - FuriThread* thread; - FuriMutex* string_sync; - FuriHalUsbInterface* usb_mode_prev; -} TotpTypeCodeWorkerContext; - -enum TotpTypeCodeWorkerEvents { - TotpTypeCodeWorkerEventReserved = (1 << 0), - TotpTypeCodeWorkerEventStop = (1 << 1), - TotpTypeCodeWorkerEventType = (1 << 2) -}; - -TotpTypeCodeWorkerContext* totp_type_code_worker_start(); -void totp_type_code_worker_stop(TotpTypeCodeWorkerContext* context); -void totp_type_code_worker_notify( - TotpTypeCodeWorkerContext* context, - TotpTypeCodeWorkerEvent event); \ No newline at end of file diff --git a/applications/external/totp/workers/type_code/type_code.c b/applications/external/totp/workers/usb_type_code/usb_type_code.c similarity index 68% rename from applications/external/totp/workers/type_code/type_code.c rename to applications/external/totp/workers/usb_type_code/usb_type_code.c index f2b4c9b9e6..3132e2317e 100644 --- a/applications/external/totp/workers/type_code/type_code.c +++ b/applications/external/totp/workers/usb_type_code/usb_type_code.c @@ -1,19 +1,8 @@ -#include "type_code.h" +#include "usb_type_code.h" #include "../../services/convert/convert.h" +#include "../constants.h" -static const uint8_t hid_number_keys[10] = { - HID_KEYBOARD_0, - HID_KEYBOARD_1, - HID_KEYBOARD_2, - HID_KEYBOARD_3, - HID_KEYBOARD_4, - HID_KEYBOARD_5, - HID_KEYBOARD_6, - HID_KEYBOARD_7, - HID_KEYBOARD_8, - HID_KEYBOARD_9}; - -static void totp_type_code_worker_restore_usb_mode(TotpTypeCodeWorkerContext* context) { +static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) { if(context->usb_mode_prev != NULL) { furi_hal_usb_set_config(context->usb_mode_prev, NULL); context->usb_mode_prev = NULL; @@ -21,10 +10,10 @@ static void totp_type_code_worker_restore_usb_mode(TotpTypeCodeWorkerContext* co } static inline bool totp_type_code_worker_stop_requested() { - return furi_thread_flags_get() & TotpTypeCodeWorkerEventStop; + return furi_thread_flags_get() & TotpUsbTypeCodeWorkerEventStop; } -static void totp_type_code_worker_type_code(TotpTypeCodeWorkerContext* context) { +static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* context) { context->usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_unlock(); furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true); @@ -57,6 +46,7 @@ static void totp_type_code_worker_type_code(TotpTypeCodeWorkerContext* context) } static int32_t totp_type_code_worker_callback(void* context) { + furi_assert(context); FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal); if(context_mutex == NULL) { return 251; @@ -64,14 +54,14 @@ static int32_t totp_type_code_worker_callback(void* context) { while(true) { uint32_t flags = furi_thread_flags_wait( - TotpTypeCodeWorkerEventStop | TotpTypeCodeWorkerEventType, + TotpUsbTypeCodeWorkerEventStop | TotpUsbTypeCodeWorkerEventType, FuriFlagWaitAny, FuriWaitForever); furi_check((flags & FuriFlagError) == 0); //-V562 - if(flags & TotpTypeCodeWorkerEventStop) break; + if(flags & TotpUsbTypeCodeWorkerEventStop) break; if(furi_mutex_acquire(context_mutex, FuriWaitForever) == FuriStatusOk) { - if(flags & TotpTypeCodeWorkerEventType) { + if(flags & TotpUsbTypeCodeWorkerEventType) { totp_type_code_worker_type_code(context); } @@ -84,13 +74,18 @@ static int32_t totp_type_code_worker_callback(void* context) { return 0; } -TotpTypeCodeWorkerContext* totp_type_code_worker_start() { - TotpTypeCodeWorkerContext* context = malloc(sizeof(TotpTypeCodeWorkerContext)); +TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start( + char* code_buf, + uint8_t code_buf_length, + FuriMutex* code_buf_update_sync) { + TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext)); furi_check(context != NULL); - context->string_sync = furi_mutex_alloc(FuriMutexTypeNormal); + context->string = code_buf; + context->string_length = code_buf_length; + context->string_sync = code_buf_update_sync; context->thread = furi_thread_alloc(); context->usb_mode_prev = NULL; - furi_thread_set_name(context->thread, "TOTPHidWorker"); + furi_thread_set_name(context->thread, "TOTPUsbHidWorker"); furi_thread_set_stack_size(context->thread, 1024); furi_thread_set_context(context->thread, context); furi_thread_set_callback(context->thread, totp_type_code_worker_callback); @@ -98,19 +93,18 @@ TotpTypeCodeWorkerContext* totp_type_code_worker_start() { return context; } -void totp_type_code_worker_stop(TotpTypeCodeWorkerContext* context) { +void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context) { furi_assert(context != NULL); - furi_thread_flags_set(furi_thread_get_id(context->thread), TotpTypeCodeWorkerEventStop); + furi_thread_flags_set(furi_thread_get_id(context->thread), TotpUsbTypeCodeWorkerEventStop); furi_thread_join(context->thread); furi_thread_free(context->thread); - furi_mutex_free(context->string_sync); totp_type_code_worker_restore_usb_mode(context); free(context); } -void totp_type_code_worker_notify( - TotpTypeCodeWorkerContext* context, - TotpTypeCodeWorkerEvent event) { +void totp_usb_type_code_worker_notify( + TotpUsbTypeCodeWorkerContext* context, + TotpUsbTypeCodeWorkerEvent event) { furi_assert(context != NULL); furi_thread_flags_set(furi_thread_get_id(context->thread), event); } \ No newline at end of file diff --git a/applications/external/totp/workers/usb_type_code/usb_type_code.h b/applications/external/totp/workers/usb_type_code/usb_type_code.h new file mode 100644 index 0000000000..94fddcc596 --- /dev/null +++ b/applications/external/totp/workers/usb_type_code/usb_type_code.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +typedef uint8_t TotpUsbTypeCodeWorkerEvent; + +typedef struct { + char* string; + uint8_t string_length; + FuriThread* thread; + FuriMutex* string_sync; + FuriHalUsbInterface* usb_mode_prev; +} TotpUsbTypeCodeWorkerContext; + +enum TotpUsbTypeCodeWorkerEvents { + TotpUsbTypeCodeWorkerEventReserved = (1 << 0), + TotpUsbTypeCodeWorkerEventStop = (1 << 1), + TotpUsbTypeCodeWorkerEventType = (1 << 2) +}; + +TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start( + char* code_buf, + uint8_t code_buf_length, + FuriMutex* code_buf_update_sync); +void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context); +void totp_usb_type_code_worker_notify( + TotpUsbTypeCodeWorkerContext* context, + TotpUsbTypeCodeWorkerEvent event); \ No newline at end of file From df766b1476dd82f86acf0441f9a8af9cbf9796ff Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 21 Mar 2023 19:08:58 +0300 Subject: [PATCH 09/26] Update changelog --- CHANGELOG.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 564b5a3ed0..6458d9599e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,13 @@ ### New changes -* Plugins: Fix minesweeper freeze bugs, do some refactoring -* Plugins: Update WAV Player, 16 bit support by @LTVA1 -* Infrared: Update universal remote assets (by @amec0e | PR #394) -* OFW PR: Fixed writing gen1a magic tags with invalid BCC [(PR 2511 by AloneLiberty)](https://github.com/AloneLiberty/flipperzero-firmware/tree/nfc-magic-write-fix) -* OFW: BadUSB: Script interpreter refactoring -* OFW: SubGhz: fix Incorrect comparison in subghz_setting_get_hopper_frequency -* OFW: Add one_wire lib to f18, separate ibutton -* OFW: Improved debugging experience for external apps -* OFW: SD Driver: reinit sd card on error -* OFW: OTP programmer: return exit code based on error type +* If you have copied apps into `apps` folder - remove `apps` folder on your microSD before installing this release to avoid issues! +* Dev Builds: Add extra pack dev branch to avoid "bug" reports with `API mismatch` +* SubGHz: Add 318 MHz back to hopping list +* SubGHz: Fix hopper stuck at 433.42 due to wide range signals - +When we using 433.92 remote flipper in hopping mode will stuck at 433.42 and may loose signal because of that, need to avoid using close freqs in hopping, only freqs with bigger difference like 310 -> 315 +* Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -> BadBT Support +* OFW: BadUSB: implement boot protocol +* OFW: Remove hmac_sha256 from public API -> **Breaking API change, api was changed from 18.x to 19.x** +**(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip) From 5b6b081664a6e802cd73b973215c15a5db8581ac Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 21 Mar 2023 20:09:18 +0300 Subject: [PATCH 10/26] GSN - Add manually support --- CHANGELOG.md | 1 + .../main/subghz/helpers/subghz_custom_event.h | 1 + .../subghz/scenes/subghz_scene_set_type.c | 31 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6458d9599e..7728ffa4a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ### New changes * If you have copied apps into `apps` folder - remove `apps` folder on your microSD before installing this release to avoid issues! * Dev Builds: Add extra pack dev branch to avoid "bug" reports with `API mismatch` +* SubGHz: Add manually -> GSN protocol support * SubGHz: Add 318 MHz back to hopping list * SubGHz: Fix hopper stuck at 433.42 due to wide range signals - When we using 433.92 remote flipper in hopping mode will stuck at 433.42 and may loose signal because of that, need to avoid using close freqs in hopping, only freqs with bigger difference like 310 -> 315 diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 69f946a9a5..f94b97659b 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -19,6 +19,7 @@ typedef enum { SubmenuIndexSommer_FM_868, SubmenuIndexDTMNeo433, SubmenuIndexGibidi433, + SubmenuIndexGSN, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, SubmenuIndexNiceFlorS_433_92, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 50af126693..ac177c0d03 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -152,6 +152,12 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexGibidi433, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "KL: GSN 433MHz", + SubmenuIndexGSN, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "KL: Elmes (PL) 433MHz", @@ -521,6 +527,31 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } break; + case SubmenuIndexGSN: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_keeloq_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + key & 0x0FFFFFFF, + 0x2, + 0x0003, + "GSN", + subghz->txrx->preset); + flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "GSN"); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; case SubmenuIndexIronLogic: subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); From 94d238c61171185a2948acb41ccd0b1f7314f8cd Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 21 Mar 2023 23:38:37 +0300 Subject: [PATCH 11/26] Add 418mhz to hopping list --- CHANGELOG.md | 2 +- documentation/SubGHzSettings.md | 1 + lib/subghz/subghz_setting.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7728ffa4a5..af5fdf9668 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ * If you have copied apps into `apps` folder - remove `apps` folder on your microSD before installing this release to avoid issues! * Dev Builds: Add extra pack dev branch to avoid "bug" reports with `API mismatch` * SubGHz: Add manually -> GSN protocol support -* SubGHz: Add 318 MHz back to hopping list +* SubGHz: Add 318 and 418 MHz back to hopping list * SubGHz: Fix hopper stuck at 433.42 due to wide range signals - When we using 433.92 remote flipper in hopping mode will stuck at 433.42 and may loose signal because of that, need to avoid using close freqs in hopping, only freqs with bigger difference like 310 -> 315 * Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -> BadBT Support diff --git a/documentation/SubGHzSettings.md b/documentation/SubGHzSettings.md index 9ba44ca332..41cf0d6bc0 100644 --- a/documentation/SubGHzSettings.md +++ b/documentation/SubGHzSettings.md @@ -92,6 +92,7 @@ Your frequencies will be added after default ones 310000000, 315000000, 318000000, + 418000000, 433920000, 868350000, ``` diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 8692e61942..b72cf99eb5 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -80,6 +80,7 @@ static const uint32_t subghz_hopper_frequency_list[] = { 310000000, 315000000, 318000000, + 418000000, 433920000, 868350000, 0, From 204b50381a0975b72af8b0be33b6371e69c024a0 Mon Sep 17 00:00:00 2001 From: Shukai Ni Date: Wed, 22 Mar 2023 05:47:47 -0400 Subject: [PATCH 12/26] Correct FAP default upload path in AppsOnSDCard.md (#2524) Since the fap's source code is in `applications_user`, the documentation should also point to `applications_user` as the parent directory --- documentation/AppsOnSDCard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/AppsOnSDCard.md b/documentation/AppsOnSDCard.md index 7543057069..212df5b1bf 100644 --- a/documentation/AppsOnSDCard.md +++ b/documentation/AppsOnSDCard.md @@ -13,7 +13,7 @@ FAPs are created and developed the same way as internal applications that are pa To build your application as a FAP, create a folder with your app's source code in `applications_user`, then write its code the way you'd do when creating a regular built-in application. Then configure its `application.fam` manifest, and set its _apptype_ to FlipperAppType.EXTERNAL. See [Application Manifests](./AppManifests.md#application-definition) for more details. - To build your application, run `./fbt fap_{APPID}`, where APPID is your application's ID in its manifest. -- To build your app and upload it over USB to run on Flipper, use `./fbt launch_app APPSRC=applications/path/to/app`. This command is configured in the default [VS Code profile](../.vscode/ReadMe.md) as a "Launch App on Flipper" build action (Ctrl+Shift+B menu). +- To build your app and upload it over USB to run on Flipper, use `./fbt launch_app APPSRC=applications_user/path/to/app`. This command is configured in the default [VS Code profile](../.vscode/ReadMe.md) as a "Launch App on Flipper" build action (Ctrl+Shift+B menu). - To build all FAPs, run `./fbt faps` or `./fbt fap_dist`. ## FAP assets From acc32f66e843a13996ae16c6287de6cbcf98be70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 22 Mar 2023 19:48:41 +0900 Subject: [PATCH 13/26] Github: force cleanup tree on decontaminate (#2526) --- .github/workflows/build.yml | 2 +- .github/workflows/lint_and_submodule_check.yml | 2 +- .github/workflows/merge_report.yml | 2 +- .github/workflows/pvs_studio.yml | 2 +- .github/workflows/unit_tests.yml | 2 +- .github/workflows/updater_test.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6ab2490ce6..898a1291c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/lint_and_submodule_check.yml b/.github/workflows/lint_and_submodule_check.yml index 46cca5c0dc..10b3c1d9aa 100644 --- a/.github/workflows/lint_and_submodule_check.yml +++ b/.github/workflows/lint_and_submodule_check.yml @@ -24,7 +24,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/merge_report.yml b/.github/workflows/merge_report.yml index e88346edf5..a382733dfc 100644 --- a/.github/workflows/merge_report.yml +++ b/.github/workflows/merge_report.yml @@ -18,7 +18,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index 65ffd19546..d11e268da4 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -25,7 +25,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 6f044ebcae..0ec531064c 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -18,7 +18,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index c04d526fc7..e1e655b003 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -18,7 +18,7 @@ jobs: git submodule status || ( git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule do - git rm -rf --cached "$submodule" + git rm -rf "$submodule" done ) fi From 973287b09b2e001503d91d94e05d9fe04bfafd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 22 Mar 2023 20:26:40 +0900 Subject: [PATCH 14/26] Github: wipe workspace before checkout (#2527) * Github: wipe workspace before checkout * Github: allow find to fail * Github: limit maxdepth for find --- .github/workflows/build.yml | 21 ++++--------------- .../workflows/lint_and_submodule_check.yml | 12 ++--------- .github/workflows/merge_report.yml | 12 ++--------- .github/workflows/pvs_studio.yml | 12 ++--------- .github/workflows/unit_tests.yml | 12 ++--------- .github/workflows/updater_test.yml | 20 ++++-------------- 6 files changed, 16 insertions(+), 73 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 898a1291c6..56e50d5f40 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,16 +18,8 @@ jobs: main: runs-on: [self-hosted,FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 @@ -171,13 +163,8 @@ jobs: if: ${{ !startsWith(github.ref, 'refs/tags') }} runs-on: [self-hosted,FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ] - then - git submodule status \ - || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/lint_and_submodule_check.yml b/.github/workflows/lint_and_submodule_check.yml index 10b3c1d9aa..cecfd12481 100644 --- a/.github/workflows/lint_and_submodule_check.yml +++ b/.github/workflows/lint_and_submodule_check.yml @@ -18,16 +18,8 @@ jobs: lint_sources_check_submodules: runs-on: [self-hosted,FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/merge_report.yml b/.github/workflows/merge_report.yml index a382733dfc..71515e1c5c 100644 --- a/.github/workflows/merge_report.yml +++ b/.github/workflows/merge_report.yml @@ -12,16 +12,8 @@ jobs: merge_report: runs-on: [self-hosted,FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index d11e268da4..6dbf84edb8 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -19,16 +19,8 @@ jobs: if: ${{ !github.event.pull_request.head.repo.fork }} runs-on: [self-hosted, FlipperZeroShell] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' uses: actions/checkout@v3 diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 0ec531064c..6a824fac31 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -12,16 +12,8 @@ jobs: run_units_on_bench: runs-on: [self-hosted, FlipperZeroUnitTest] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: Checkout code uses: actions/checkout@v3 diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index e1e655b003..2861529d83 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -12,16 +12,8 @@ jobs: test_updater_on_bench: runs-on: [self-hosted, FlipperZeroUpdaterTest] steps: - - name: 'Decontaminate previous build leftovers' - run: | - if [ -d .git ]; then - git submodule status || ( - git ls-files --stage | egrep '^160000' | awk '{print $4}' | while read submodule - do - git rm -rf "$submodule" - done - ) - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: Checkout code uses: actions/checkout@v3 @@ -57,12 +49,8 @@ jobs: run: | echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT - - name: 'Decontaminate previous build leftovers' - if: failure() - run: | - if [ -d .git ]; then - git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" - fi + - name: 'Wipe workspace' + run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout latest release' uses: actions/checkout@v3 From 1f236ede0e4d13f2ca0c031bd7c0e2017540d68c Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Wed, 22 Mar 2023 17:41:14 +0300 Subject: [PATCH 15/26] [#2501] Disable UART IRQs by default (#2523) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- firmware/targets/f7/furi_hal/furi_hal_uart.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_uart.c b/firmware/targets/f7/furi_hal/furi_hal_uart.c index 54232e67fa..71b5c7ba04 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_uart.c +++ b/firmware/targets/f7/furi_hal/furi_hal_uart.c @@ -44,7 +44,8 @@ static void furi_hal_usart_init(uint32_t baud) { while(!LL_USART_IsActiveFlag_TEACK(USART1) || !LL_USART_IsActiveFlag_REACK(USART1)) ; - LL_USART_EnableIT_RXNE_RXFNE(USART1); + LL_USART_DisableIT_ERROR(USART1); + NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); } @@ -79,8 +80,8 @@ static void furi_hal_lpuart_init(uint32_t baud) { ; furi_hal_uart_set_br(FuriHalUartIdLPUART1, baud); + LL_LPUART_DisableIT_ERROR(LPUART1); - LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1); NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); } @@ -190,19 +191,25 @@ void furi_hal_uart_set_irq_cb( void (*cb)(UartIrqEvent ev, uint8_t data, void* ctx), void* ctx) { if(cb == NULL) { - if(ch == FuriHalUartIdUSART1) + if(ch == FuriHalUartIdUSART1) { NVIC_DisableIRQ(USART1_IRQn); - else if(ch == FuriHalUartIdLPUART1) + LL_USART_DisableIT_RXNE_RXFNE(USART1); + } else if(ch == FuriHalUartIdLPUART1) { NVIC_DisableIRQ(LPUART1_IRQn); + LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1); + } irq_cb[ch] = cb; irq_ctx[ch] = ctx; } else { irq_ctx[ch] = ctx; irq_cb[ch] = cb; - if(ch == FuriHalUartIdUSART1) + if(ch == FuriHalUartIdUSART1) { NVIC_EnableIRQ(USART1_IRQn); - else if(ch == FuriHalUartIdLPUART1) + LL_USART_EnableIT_RXNE_RXFNE(USART1); + } else if(ch == FuriHalUartIdLPUART1) { NVIC_EnableIRQ(LPUART1_IRQn); + LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1); + } } } From 8b224ecb15d0899c3e67edd693a18f58d9029b57 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 22 Mar 2023 17:54:06 +0300 Subject: [PATCH 16/26] [FL-3179] 1-Wire Overdrive Mode (#2522) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Separate ibutton to its own module, add one_wire to f18 * Move onewire cli to a separate app * Add definitions for normal and overdrive timings * Update api definitions * Add rough overdrive timings definition for onewire emulation * Remove one_wire_host_timing.h * Add rough overdrive timings for onewire host * Improve overdrive mode * Working overdrive mode from flipper to flipper * Update thermometer example app * Turn on otg power when running thermometer example app * Implement reset overdrive switching * Always exit out of overdrive mode * Improve overdrive timings * Fix typos * Fix reset behaviour * Use overdrive mode everywhere in DS1996 * Improve comments * Bump API version Co-authored-by: あく --- .../examples/example_thermo/example_thermo.c | 13 +- firmware/targets/f18/api_symbols.csv | 8 +- firmware/targets/f7/api_symbols.csv | 8 +- lib/ibutton/protocols/dallas/dallas_common.h | 4 +- .../protocols/dallas/protocol_dallas_base.h | 4 +- .../protocols/dallas/protocol_ds1971.c | 18 +- .../protocols/dallas/protocol_ds1990.c | 10 +- .../protocols/dallas/protocol_ds1992.c | 10 +- .../protocols/dallas/protocol_ds1996.c | 62 ++++-- .../protocols/dallas/protocol_ds_generic.c | 10 +- lib/one_wire/SConscript | 1 - lib/one_wire/one_wire_host.c | 85 ++++++-- lib/one_wire/one_wire_host.h | 89 +++++---- lib/one_wire/one_wire_host_timing.h | 30 --- lib/one_wire/one_wire_slave.c | 188 +++++++++++------- lib/one_wire/one_wire_slave.h | 84 +++++--- 16 files changed, 397 insertions(+), 227 deletions(-) delete mode 100644 lib/one_wire/one_wire_host_timing.h diff --git a/applications/examples/example_thermo/example_thermo.c b/applications/examples/example_thermo/example_thermo.c index b3bc7cd990..4241cb59d9 100644 --- a/applications/examples/example_thermo/example_thermo.c +++ b/applications/examples/example_thermo/example_thermo.c @@ -19,9 +19,12 @@ #include #include +#include + #define UPDATE_PERIOD_MS 1000UL #define TEXT_STORE_SIZE 64U +#define DS18B20_CMD_SKIP_ROM 0xccU #define DS18B20_CMD_CONVERT 0x44U #define DS18B20_CMD_READ_SCRATCHPAD 0xbeU @@ -92,7 +95,7 @@ static void example_thermo_request_temperature(ExampleThermoContext* context) { /* After the reset, a ROM operation must follow. If there is only one device connected, the "Skip ROM" command is most appropriate (it can also be used to address all of the connected devices in some cases).*/ - onewire_host_skip(onewire); + onewire_host_write(onewire, DS18B20_CMD_SKIP_ROM); /* After the ROM operation, a device-specific command is issued. In this case, it's a request to start measuring the temperature. */ onewire_host_write(onewire, DS18B20_CMD_CONVERT); @@ -133,7 +136,7 @@ static void example_thermo_read_temperature(ExampleThermoContext* context) { /* After the reset, a ROM operation must follow. If there is only one device connected, the "Skip ROM" command is most appropriate (it can also be used to address all of the connected devices in some cases).*/ - onewire_host_skip(onewire); + onewire_host_write(onewire, DS18B20_CMD_SKIP_ROM); /* After the ROM operation, a device-specific command is issued. This time, it will be the "Read Scratchpad" command which will @@ -267,6 +270,9 @@ static void example_thermo_input_callback(InputEvent* event, void* ctx) { /* Starts the reader thread and handles the input */ static void example_thermo_run(ExampleThermoContext* context) { + /* Enable power on external pins */ + furi_hal_power_enable_otg(); + /* Configure the hardware in host mode */ onewire_host_start(context->onewire); @@ -299,6 +305,9 @@ static void example_thermo_run(ExampleThermoContext* context) { /* Reset the hardware */ onewire_host_stop(context->onewire); + + /* Disable power on external pins */ + furi_hal_power_disable_otg(); } /******************** Initialisation & startup *****************************/ diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index b6be56f60d..e6fae33ee4 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,19.0,, +Version,+,20.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -153,7 +153,6 @@ Header,+,lib/mlib/m-tuple.h,, Header,+,lib/mlib/m-variant.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, -Header,+,lib/one_wire/one_wire_host_timing.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, Header,+,lib/toolbox/args.h,, @@ -1481,8 +1480,8 @@ Function,+,onewire_host_read_bit,_Bool,OneWireHost* Function,+,onewire_host_read_bytes,void,"OneWireHost*, uint8_t*, uint16_t" Function,+,onewire_host_reset,_Bool,OneWireHost* Function,+,onewire_host_reset_search,void,OneWireHost* -Function,+,onewire_host_search,uint8_t,"OneWireHost*, uint8_t*, OneWireHostSearchMode" -Function,+,onewire_host_skip,void,OneWireHost* +Function,+,onewire_host_search,_Bool,"OneWireHost*, uint8_t*, OneWireHostSearchMode" +Function,+,onewire_host_set_overdrive,void,"OneWireHost*, _Bool" Function,+,onewire_host_start,void,OneWireHost* Function,+,onewire_host_stop,void,OneWireHost* Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t" @@ -1496,6 +1495,7 @@ Function,+,onewire_slave_receive_bit,_Bool,OneWireSlave* Function,+,onewire_slave_send,_Bool,"OneWireSlave*, const uint8_t*, size_t" Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool" Function,+,onewire_slave_set_command_callback,void,"OneWireSlave*, OneWireSlaveCommandCallback, void*" +Function,+,onewire_slave_set_overdrive,void,"OneWireSlave*, _Bool" Function,+,onewire_slave_set_reset_callback,void,"OneWireSlave*, OneWireSlaveResetCallback, void*" Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*" Function,+,onewire_slave_start,void,OneWireSlave* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index e6de39b1d6..7ac9a24599 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,19.0,, +Version,+,20.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -172,7 +172,6 @@ Header,+,lib/mlib/m-variant.h,, Header,+,lib/nfc/nfc_device.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, -Header,+,lib/one_wire/one_wire_host_timing.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, Header,+,lib/subghz/blocks/const.h,, @@ -2062,8 +2061,8 @@ Function,+,onewire_host_read_bit,_Bool,OneWireHost* Function,+,onewire_host_read_bytes,void,"OneWireHost*, uint8_t*, uint16_t" Function,+,onewire_host_reset,_Bool,OneWireHost* Function,+,onewire_host_reset_search,void,OneWireHost* -Function,+,onewire_host_search,uint8_t,"OneWireHost*, uint8_t*, OneWireHostSearchMode" -Function,+,onewire_host_skip,void,OneWireHost* +Function,+,onewire_host_search,_Bool,"OneWireHost*, uint8_t*, OneWireHostSearchMode" +Function,+,onewire_host_set_overdrive,void,"OneWireHost*, _Bool" Function,+,onewire_host_start,void,OneWireHost* Function,+,onewire_host_stop,void,OneWireHost* Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t" @@ -2077,6 +2076,7 @@ Function,+,onewire_slave_receive_bit,_Bool,OneWireSlave* Function,+,onewire_slave_send,_Bool,"OneWireSlave*, const uint8_t*, size_t" Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool" Function,+,onewire_slave_set_command_callback,void,"OneWireSlave*, OneWireSlaveCommandCallback, void*" +Function,+,onewire_slave_set_overdrive,void,"OneWireSlave*, _Bool" Function,+,onewire_slave_set_reset_callback,void,"OneWireSlave*, OneWireSlaveResetCallback, void*" Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*" Function,+,onewire_slave_start,void,OneWireSlave* diff --git a/lib/ibutton/protocols/dallas/dallas_common.h b/lib/ibutton/protocols/dallas/dallas_common.h index 7991a1f8ba..6f5ff7cc01 100644 --- a/lib/ibutton/protocols/dallas/dallas_common.h +++ b/lib/ibutton/protocols/dallas/dallas_common.h @@ -1,10 +1,10 @@ #pragma once -#include - #include #include +#include + #define DALLAS_COMMON_MANUFACTURER_NAME "Dallas" #define DALLAS_COMMON_CMD_READ_ROM 0x33U diff --git a/lib/ibutton/protocols/dallas/protocol_dallas_base.h b/lib/ibutton/protocols/dallas/protocol_dallas_base.h index b4edb2b20d..55e1099360 100644 --- a/lib/ibutton/protocols/dallas/protocol_dallas_base.h +++ b/lib/ibutton/protocols/dallas/protocol_dallas_base.h @@ -2,11 +2,11 @@ #include "../protocol_common_i.h" -#include - #include #include +#include + typedef bool (*iButtonProtocolDallasReadWriteFunc)(OneWireHost*, iButtonProtocolData*); typedef void (*iButtonProtocolDallasEmulateFunc)(OneWireSlave*, iButtonProtocolData*); typedef bool (*iButtonProtocolDallasSaveFunc)(FlipperFormat*, const iButtonProtocolData*); diff --git a/lib/ibutton/protocols/dallas/protocol_ds1971.c b/lib/ibutton/protocols/dallas/protocol_ds1971.c index eb5b330b79..a806acb22e 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1971.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1971.c @@ -53,7 +53,7 @@ const iButtonProtocolDallasBase ibutton_protocol_ds1971 = { .name = DS1971_FAMILY_NAME, .read = dallas_ds1971_read, - .write_blank = NULL, /* No data to write a blank */ + .write_blank = NULL, // TODO: Implement writing to blank .write_copy = dallas_ds1971_write_copy, .emulate = dallas_ds1971_emulate, .save = dallas_ds1971_save, @@ -76,7 +76,7 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d DS1971ProtocolData* data = protocol_data; onewire_host_reset(host); - onewire_host_skip(host); + onewire_host_write(host, DALLAS_COMMON_CMD_SKIP_ROM); // Starting writing from address 0x0000 onewire_host_write(host, DALLAS_COMMON_CMD_WRITE_SCRATCH); onewire_host_write(host, 0x00); @@ -87,7 +87,7 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d bool pad_valid = false; if(onewire_host_reset(host)) { pad_valid = true; - onewire_host_skip(host); + onewire_host_write(host, DALLAS_COMMON_CMD_SKIP_ROM); onewire_host_write(host, DALLAS_COMMON_CMD_READ_SCRATCH); onewire_host_write(host, 0x00); @@ -103,7 +103,7 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d // Copy scratchpad to memory and confirm if(pad_valid) { if(onewire_host_reset(host)) { - onewire_host_skip(host); + onewire_host_write(host, DALLAS_COMMON_CMD_SKIP_ROM); onewire_host_write(host, DALLAS_COMMON_CMD_COPY_SCRATCH); onewire_host_write(host, DS1971_CMD_FINALIZATION); @@ -114,10 +114,16 @@ bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d return pad_valid; } -static void dallas_ds1971_reset_callback(void* context) { +static bool dallas_ds1971_reset_callback(bool is_short, void* context) { furi_assert(context); DS1971ProtocolData* data = context; - data->state.command_state = DallasCommonCommandStateIdle; + + if(!is_short) { + data->state.command_state = DallasCommonCommandStateIdle; + onewire_slave_set_overdrive(data->state.bus, is_short); + } + + return !is_short; } static bool dallas_ds1971_command_callback(uint8_t command, void* context) { diff --git a/lib/ibutton/protocols/dallas/protocol_ds1990.c b/lib/ibutton/protocols/dallas/protocol_ds1990.c index 0d9c937ee4..86d39f1bd8 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1990.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1990.c @@ -67,6 +67,14 @@ bool dallas_ds1990_write_blank(OneWireHost* host, iButtonProtocolData* protocol_ tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); } +static bool dallas_ds1990_reset_callback(bool is_short, void* context) { + DS1990ProtocolData* data = context; + if(!is_short) { + onewire_slave_set_overdrive(data->state.bus, is_short); + } + return !is_short; +} + static bool dallas_ds1990_command_callback(uint8_t command, void* context) { furi_assert(context); DS1990ProtocolData* data = context; @@ -92,7 +100,7 @@ void dallas_ds1990_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data DS1990ProtocolData* data = protocol_data; data->state.bus = bus; - onewire_slave_set_reset_callback(bus, NULL, NULL); + onewire_slave_set_reset_callback(bus, dallas_ds1990_reset_callback, protocol_data); onewire_slave_set_command_callback(bus, dallas_ds1990_command_callback, protocol_data); } diff --git a/lib/ibutton/protocols/dallas/protocol_ds1992.c b/lib/ibutton/protocols/dallas/protocol_ds1992.c index 17d631259e..0b4d4b34f2 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1992.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1992.c @@ -87,10 +87,16 @@ bool dallas_ds1992_write_copy(OneWireHost* host, iButtonProtocolData* protocol_d DS1992_SRAM_DATA_SIZE); } -static void dallas_ds1992_reset_callback(void* context) { +static bool dallas_ds1992_reset_callback(bool is_short, void* context) { furi_assert(context); DS1992ProtocolData* data = context; - data->state.command_state = DallasCommonCommandStateIdle; + + if(!is_short) { + data->state.command_state = DallasCommonCommandStateIdle; + onewire_slave_set_overdrive(data->state.bus, is_short); + } + + return !is_short; } static bool dallas_ds1992_command_callback(uint8_t command, void* context) { diff --git a/lib/ibutton/protocols/dallas/protocol_ds1996.c b/lib/ibutton/protocols/dallas/protocol_ds1996.c index 74a5792c66..5358b63e26 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1996.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1996.c @@ -63,24 +63,54 @@ const iButtonProtocolDallasBase ibutton_protocol_ds1996 = { bool dallas_ds1996_read(OneWireHost* host, iButtonProtocolData* protocol_data) { DS1996ProtocolData* data = protocol_data; - return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data) && - dallas_common_read_mem(host, 0, data->sram_data, DS1996_SRAM_DATA_SIZE); + bool success = false; + + do { + if(!onewire_host_reset(host)) break; + if(!dallas_common_read_rom(host, &data->rom_data)) break; + if(!onewire_host_reset(host)) break; + + onewire_host_write(host, DALLAS_COMMON_CMD_OVERDRIVE_SKIP_ROM); + onewire_host_set_overdrive(host, true); + + if(!dallas_common_read_mem(host, 0, data->sram_data, DS1996_SRAM_DATA_SIZE)) break; + success = true; + } while(false); + + onewire_host_set_overdrive(host, false); + return success; } bool dallas_ds1996_write_copy(OneWireHost* host, iButtonProtocolData* protocol_data) { DS1996ProtocolData* data = protocol_data; - return dallas_common_write_mem( - host, - DS1996_COPY_SCRATCH_TIMEOUT_US, - DS1996_SRAM_PAGE_SIZE, - data->sram_data, - DS1996_SRAM_DATA_SIZE); + bool success = false; + + do { + if(!onewire_host_reset(host)) break; + + onewire_host_write(host, DALLAS_COMMON_CMD_OVERDRIVE_SKIP_ROM); + onewire_host_set_overdrive(host, true); + + if(!dallas_common_write_mem( + host, + DS1996_COPY_SCRATCH_TIMEOUT_US, + DS1996_SRAM_PAGE_SIZE, + data->sram_data, + DS1996_SRAM_DATA_SIZE)) + break; + success = true; + } while(false); + + onewire_host_set_overdrive(host, false); + return success; } -static void dallas_ds1996_reset_callback(void* context) { +static bool dallas_ds1996_reset_callback(bool is_short, void* context) { furi_assert(context); DS1996ProtocolData* data = context; data->state.command_state = DallasCommonCommandStateIdle; + onewire_slave_set_overdrive(data->state.bus, is_short); + return true; } static bool dallas_ds1996_command_callback(uint8_t command, void* context) { @@ -96,8 +126,7 @@ static bool dallas_ds1996_command_callback(uint8_t command, void* context) { } else if(data->state.command_state == DallasCommonCommandStateRomCmd) { data->state.command_state = DallasCommonCommandStateMemCmd; - dallas_common_emulate_read_mem(bus, data->sram_data, DS1996_SRAM_DATA_SIZE); - return false; + return dallas_common_emulate_read_mem(bus, data->sram_data, DS1996_SRAM_DATA_SIZE); } else { return false; @@ -120,8 +149,17 @@ static bool dallas_ds1996_command_callback(uint8_t command, void* context) { } case DALLAS_COMMON_CMD_OVERDRIVE_SKIP_ROM: + if(data->state.command_state == DallasCommonCommandStateIdle) { + data->state.command_state = DallasCommonCommandStateRomCmd; + onewire_slave_set_overdrive(bus, true); + return true; + } else { + return false; + } + + case DALLAS_COMMON_CMD_MATCH_ROM: case DALLAS_COMMON_CMD_OVERDRIVE_MATCH_ROM: - /* TODO: Overdrive mode support */ + /* TODO: Match ROM command support */ default: return false; } diff --git a/lib/ibutton/protocols/dallas/protocol_ds_generic.c b/lib/ibutton/protocols/dallas/protocol_ds_generic.c index 50fd045112..af355f4612 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds_generic.c +++ b/lib/ibutton/protocols/dallas/protocol_ds_generic.c @@ -61,6 +61,14 @@ bool ds_generic_write_blank(OneWireHost* host, iButtonProtocolData* protocol_dat return tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); } +static bool ds_generic_reset_callback(bool is_short, void* context) { + DallasGenericProtocolData* data = context; + if(!is_short) { + onewire_slave_set_overdrive(data->state.bus, is_short); + } + return !is_short; +} + static bool ds_generic_command_callback(uint8_t command, void* context) { furi_assert(context); DallasGenericProtocolData* data = context; @@ -85,7 +93,7 @@ void ds_generic_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) { DallasGenericProtocolData* data = protocol_data; data->state.bus = bus; - onewire_slave_set_reset_callback(bus, NULL, NULL); + onewire_slave_set_reset_callback(bus, ds_generic_reset_callback, NULL); onewire_slave_set_command_callback(bus, ds_generic_command_callback, protocol_data); } diff --git a/lib/one_wire/SConscript b/lib/one_wire/SConscript index 8d73c9dbf0..2dde9153df 100644 --- a/lib/one_wire/SConscript +++ b/lib/one_wire/SConscript @@ -8,7 +8,6 @@ env.Append( "#/lib/one_wire", ], SDK_HEADERS=[ - File("one_wire_host_timing.h"), File("one_wire_host.h"), File("one_wire_slave.h"), File("maxim_crc.h"), diff --git a/lib/one_wire/one_wire_host.c b/lib/one_wire/one_wire_host.c index 0a4a79f5cc..678812105c 100644 --- a/lib/one_wire/one_wire_host.c +++ b/lib/one_wire/one_wire_host.c @@ -1,10 +1,54 @@ #include +/** + * Timings based on Application Note 126: + * https://www.analog.com/media/en/technical-documentation/tech-articles/1wire-communication-through-software--maxim-integrated.pdf + */ + #include "one_wire_host.h" -#include "one_wire_host_timing.h" + +typedef struct { + uint16_t a; + uint16_t b; + uint16_t c; + uint16_t d; + uint16_t e; + uint16_t f; + uint16_t g; + uint16_t h; + uint16_t i; + uint16_t j; +} OneWireHostTimings; + +static const OneWireHostTimings onewire_host_timings_normal = { + .a = 9, + .b = 64, + .c = 64, + .d = 14, + .e = 9, + .f = 55, + .g = 0, + .h = 480, + .i = 70, + .j = 410, +}; + +static const OneWireHostTimings onewire_host_timings_overdrive = { + .a = 1, + .b = 8, + .c = 8, + .d = 3, + .e = 1, + .f = 7, + .g = 3, + .h = 70, + .i = 9, + .j = 40, +}; struct OneWireHost { const GpioPin* gpio_pin; + const OneWireHostTimings* timings; unsigned char saved_rom[8]; /** < global search state */ uint8_t last_discrepancy; uint8_t last_family_discrepancy; @@ -15,6 +59,7 @@ OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin) { OneWireHost* host = malloc(sizeof(OneWireHost)); host->gpio_pin = gpio_pin; onewire_host_reset_search(host); + onewire_host_set_overdrive(host, false); return host; } @@ -27,6 +72,8 @@ bool onewire_host_reset(OneWireHost* host) { uint8_t r; uint8_t retries = 125; + const OneWireHostTimings* timings = host->timings; + // wait until the gpio is high furi_hal_gpio_write(host->gpio_pin, true); do { @@ -35,19 +82,19 @@ bool onewire_host_reset(OneWireHost* host) { } while(!furi_hal_gpio_read(host->gpio_pin)); // pre delay - furi_delay_us(OWH_RESET_DELAY_PRE); + furi_delay_us(timings->g); // drive low furi_hal_gpio_write(host->gpio_pin, false); - furi_delay_us(OWH_RESET_DRIVE); + furi_delay_us(timings->h); // release furi_hal_gpio_write(host->gpio_pin, true); - furi_delay_us(OWH_RESET_RELEASE); + furi_delay_us(timings->i); // read and post delay r = !furi_hal_gpio_read(host->gpio_pin); - furi_delay_us(OWH_RESET_DELAY_POST); + furi_delay_us(timings->j); return r; } @@ -55,17 +102,19 @@ bool onewire_host_reset(OneWireHost* host) { bool onewire_host_read_bit(OneWireHost* host) { bool result; + const OneWireHostTimings* timings = host->timings; + // drive low furi_hal_gpio_write(host->gpio_pin, false); - furi_delay_us(OWH_READ_DRIVE); + furi_delay_us(timings->a); // release furi_hal_gpio_write(host->gpio_pin, true); - furi_delay_us(OWH_READ_RELEASE); + furi_delay_us(timings->e); // read and post delay result = furi_hal_gpio_read(host->gpio_pin); - furi_delay_us(OWH_READ_DELAY_POST); + furi_delay_us(timings->f); return result; } @@ -89,22 +138,24 @@ void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count) } void onewire_host_write_bit(OneWireHost* host, bool value) { + const OneWireHostTimings* timings = host->timings; + if(value) { // drive low furi_hal_gpio_write(host->gpio_pin, false); - furi_delay_us(OWH_WRITE_1_DRIVE); + furi_delay_us(timings->a); // release furi_hal_gpio_write(host->gpio_pin, true); - furi_delay_us(OWH_WRITE_1_RELEASE); + furi_delay_us(timings->b); } else { // drive low furi_hal_gpio_write(host->gpio_pin, false); - furi_delay_us(OWH_WRITE_0_DRIVE); + furi_delay_us(timings->c); // release furi_hal_gpio_write(host->gpio_pin, true); - furi_delay_us(OWH_WRITE_0_RELEASE); + furi_delay_us(timings->d); } } @@ -122,10 +173,6 @@ void onewire_host_write_bytes(OneWireHost* host, const uint8_t* buffer, uint16_t } } -void onewire_host_skip(OneWireHost* host) { - onewire_host_write(host, 0xCC); -} - void onewire_host_start(OneWireHost* host) { furi_hal_gpio_write(host->gpio_pin, true); furi_hal_gpio_init(host->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); @@ -154,7 +201,7 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code) { host->last_device_flag = false; } -uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode) { +bool onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode) { uint8_t id_bit_number; uint8_t last_zero, rom_byte_number, search_result; uint8_t id_bit, cmp_id_bit; @@ -268,3 +315,7 @@ uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSea return search_result; } + +void onewire_host_set_overdrive(OneWireHost* host, bool set) { + host->timings = set ? &onewire_host_timings_overdrive : &onewire_host_timings_normal; +} diff --git a/lib/one_wire/one_wire_host.h b/lib/one_wire/one_wire_host.h index dc469904dd..9f9bd4ffd7 100644 --- a/lib/one_wire/one_wire_host.h +++ b/lib/one_wire/one_wire_host.h @@ -15,114 +15,115 @@ extern "C" { typedef enum { OneWireHostSearchModeConditional = 0, /**< Search for alarmed device */ - OneWireHostSearchModeNormal = 1, /**< Search all devices */ + OneWireHostSearchModeNormal = 1, /**< Search for all devices */ } OneWireHostSearchMode; typedef struct OneWireHost OneWireHost; /** - * Allocate onewire host bus - * @param pin - * @return OneWireHost* + * Allocate OneWireHost instance + * @param [in] gpio_pin connection pin + * @return pointer to OneWireHost instance */ OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin); /** - * Deallocate onewire host bus - * @param host + * Destroy OneWireHost instance, free resources + * @param [in] host pointer to OneWireHost instance */ void onewire_host_free(OneWireHost* host); /** - * Reset bus - * @param host - * @return bool + * Reset the 1-Wire bus + * @param [in] host pointer to OneWireHost instance + * @return true if presence was detected, false otherwise */ bool onewire_host_reset(OneWireHost* host); /** * Read one bit - * @param host - * @return bool + * @param [in] host pointer to OneWireHost instance + * @return received bit value */ bool onewire_host_read_bit(OneWireHost* host); /** * Read one byte - * @param host - * @return uint8_t + * @param [in] host pointer to OneWireHost instance + * @return received byte value */ uint8_t onewire_host_read(OneWireHost* host); /** - * Read many bytes - * @param host - * @param buffer - * @param count + * Read one or more bytes + * @param [in] host pointer to OneWireHost instance + * @param [out] buffer received data buffer + * @param [in] count number of bytes to read */ void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count); /** * Write one bit - * @param host - * @param value + * @param [in] host pointer to OneWireHost instance + * @param value bit value to write */ void onewire_host_write_bit(OneWireHost* host, bool value); /** * Write one byte - * @param host - * @param value + * @param [in] host pointer to OneWireHost instance + * @param value byte value to write */ void onewire_host_write(OneWireHost* host, uint8_t value); /** - * Write many bytes - * @param host - * @param buffer - * @param count + * Write one or more bytes + * @param [in] host pointer to OneWireHost instance + * @param [in] buffer pointer to the data to write + * @param [in] count size of the data to write */ void onewire_host_write_bytes(OneWireHost* host, const uint8_t* buffer, uint16_t count); -/** - * Skip ROM command - * @param host - */ -void onewire_host_skip(OneWireHost* host); - /** * Start working with the bus - * @param host + * @param [in] host pointer to OneWireHost instance */ void onewire_host_start(OneWireHost* host); /** * Stop working with the bus - * @param host + * @param [in] host pointer to OneWireHost instance */ void onewire_host_stop(OneWireHost* host); /** - * - * @param host + * Reset previous search results + * @param [in] host pointer to OneWireHost instance */ void onewire_host_reset_search(OneWireHost* host); /** - * - * @param host - * @param family_code + * Set the family code to search for + * @param [in] host pointer to OneWireHost instance + * @param [in] family_code device family code */ void onewire_host_target_search(OneWireHost* host, uint8_t family_code); /** - * - * @param host - * @param newAddr - * @param mode - * @return uint8_t + * Search for devices on the 1-Wire bus + * @param [in] host pointer to OneWireHost instance + * @param [out] new_addr pointer to the buffer to contain the unique ROM of the found device + * @param [in] mode search mode + * @return true on success, false otherwise + */ +bool onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode); + +/** + * Enable overdrive mode + * @param [in] host pointer to OneWireHost instance + * @param [in] set true to turn overdrive on, false to turn it off */ -uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode); +void onewire_host_set_overdrive(OneWireHost* host, bool set); #ifdef __cplusplus } diff --git a/lib/one_wire/one_wire_host_timing.h b/lib/one_wire/one_wire_host_timing.h deleted file mode 100644 index f95dd3561e..0000000000 --- a/lib/one_wire/one_wire_host_timing.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file one_wire_host_timing.h - * - * 1-Wire library, timing list - */ - -#pragma once - -#define OWH_TIMING_A 9 -#define OWH_TIMING_B 64 -#define OWH_TIMING_C 64 -#define OWH_TIMING_D 14 -#define OWH_TIMING_E 9 -#define OWH_TIMING_F 55 -#define OWH_TIMING_G 0 -#define OWH_TIMING_H 480 -#define OWH_TIMING_I 70 -#define OWH_TIMING_J 410 - -#define OWH_WRITE_1_DRIVE OWH_TIMING_A -#define OWH_WRITE_1_RELEASE OWH_TIMING_B -#define OWH_WRITE_0_DRIVE OWH_TIMING_C -#define OWH_WRITE_0_RELEASE OWH_TIMING_D -#define OWH_READ_DRIVE 3 -#define OWH_READ_RELEASE OWH_TIMING_E -#define OWH_READ_DELAY_POST OWH_TIMING_F -#define OWH_RESET_DELAY_PRE OWH_TIMING_G -#define OWH_RESET_DRIVE OWH_TIMING_H -#define OWH_RESET_RELEASE OWH_TIMING_I -#define OWH_RESET_DELAY_POST OWH_TIMING_J diff --git a/lib/one_wire/one_wire_slave.c b/lib/one_wire/one_wire_slave.c index d1676cf3b8..733b36e30e 100644 --- a/lib/one_wire/one_wire_slave.c +++ b/lib/one_wire/one_wire_slave.c @@ -3,20 +3,7 @@ #include #include -#define ONEWIRE_TRSTL_MIN 270 /* Minimum Reset Low time */ -#define ONEWIRE_TRSTL_MAX 1200 /* Maximum Reset Low time */ - -#define ONEWIRE_TPDH_TYP 20 /* Typical Presence Detect High time */ -#define ONEWIRE_TPDL_MIN 100 /* Minimum Presence Detect Low time */ -#define ONEWIRE_TPDL_MAX 480 /* Maximum Presence Detect Low time */ - -#define ONEWIRE_TSLOT_MIN 60 /* Minimum Read/Write Slot time */ -#define ONEWIRE_TSLOT_MAX 135 /* Maximum Read/Write Slot time */ - -#define ONEWIRE_TW1L_MAX 20 /* Maximum Master Write 1 time */ -#define ONEWIRE_TRL_TMSR_MAX 30 /* Maximum Master Read Low + Read Sample time */ - -#define ONEWIRE_TH_TIMEOUT 15000 /* Maximum time before general timeout */ +#define TH_TIMEOUT_MAX 15000 /* Maximum time before general timeout */ typedef enum { OneWireSlaveErrorNone = 0, @@ -26,10 +13,29 @@ typedef enum { OneWireSlaveErrorTimeout, } OneWireSlaveError; +typedef struct { + uint16_t trstl_min; /* Minimum Reset Low time */ + uint16_t trstl_max; /* Maximum Reset Low time */ + + uint16_t tpdh_typ; /* Typical Presence Detect High time */ + uint16_t tpdl_min; /* Minimum Presence Detect Low time */ + uint16_t tpdl_max; /* Maximum Presence Detect Low time */ + + uint16_t tslot_min; /* Minimum Read/Write Slot time */ + uint16_t tslot_max; /* Maximum Read/Write Slot time */ + + uint16_t tw1l_max; /* Maximum Master Write 1 time */ + uint16_t trl_tmsr_max; /* Maximum Master Read Low + Read Sample time */ +} OneWireSlaveTimings; + struct OneWireSlave { const GpioPin* gpio_pin; + const OneWireSlaveTimings* timings; OneWireSlaveError error; + bool is_first_reset; + bool is_short_reset; + OneWireSlaveResetCallback reset_callback; OneWireSlaveCommandCallback command_callback; OneWireSlaveResultCallback result_callback; @@ -39,42 +45,72 @@ struct OneWireSlave { void* command_callback_context; }; +static const OneWireSlaveTimings onewire_slave_timings_normal = { + .trstl_min = 270, + .trstl_max = 1200, + + .tpdh_typ = 20, + .tpdl_min = 100, + .tpdl_max = 480, + + .tslot_min = 60, + .tslot_max = 135, + + .tw1l_max = 20, + .trl_tmsr_max = 30, +}; + +static const OneWireSlaveTimings onewire_slave_timings_overdrive = { + .trstl_min = 48, + .trstl_max = 80, + + .tpdh_typ = 0, + .tpdl_min = 8, + .tpdl_max = 24, + + .tslot_min = 6, + .tslot_max = 16, + + .tw1l_max = 2, + .trl_tmsr_max = 3, +}; + /*********************** PRIVATE ***********************/ -static uint32_t - onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, const bool pin_value) { - uint32_t start = DWT->CYCCNT; - uint32_t time_ticks = time * furi_hal_cortex_instructions_per_microsecond(); - uint32_t time_captured; +static bool + onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time_us, const bool pin_value) { + const uint32_t time_start = DWT->CYCCNT; + const uint32_t time_ticks = time_us * furi_hal_cortex_instructions_per_microsecond(); + + uint32_t time_elapsed; do { //-V1044 - time_captured = DWT->CYCCNT; + time_elapsed = DWT->CYCCNT - time_start; if(furi_hal_gpio_read(bus->gpio_pin) != pin_value) { - uint32_t remaining_time = time_ticks - (time_captured - start); - remaining_time /= furi_hal_cortex_instructions_per_microsecond(); - return remaining_time; + return time_ticks >= time_elapsed; } - } while((time_captured - start) < time_ticks); + } while(time_elapsed < time_ticks); - return 0; + return false; } -static bool onewire_slave_show_presence(OneWireSlave* bus) { +static inline bool onewire_slave_show_presence(OneWireSlave* bus) { + const OneWireSlaveTimings* timings = bus->timings; // wait until the bus is high (might return immediately) - onewire_slave_wait_while_gpio_is(bus, ONEWIRE_TRSTL_MAX, false); + onewire_slave_wait_while_gpio_is(bus, timings->trstl_max, false); // wait while master delay presence check - furi_delay_us(ONEWIRE_TPDH_TYP); + furi_delay_us(timings->tpdh_typ); // show presence furi_hal_gpio_write(bus->gpio_pin, false); - furi_delay_us(ONEWIRE_TPDL_MIN); + furi_delay_us(timings->tpdl_min); furi_hal_gpio_write(bus->gpio_pin, true); // somebody also can show presence - const uint32_t wait_low_time = ONEWIRE_TPDL_MAX - ONEWIRE_TPDL_MIN; + const uint32_t wait_low_time = timings->tpdl_max - timings->tpdl_min; // so we will wait - if(onewire_slave_wait_while_gpio_is(bus, wait_low_time, false) == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, wait_low_time, false)) { bus->error = OneWireSlaveErrorPresenceConflict; return false; } @@ -85,27 +121,36 @@ static bool onewire_slave_show_presence(OneWireSlave* bus) { static inline bool onewire_slave_receive_and_process_command(OneWireSlave* bus) { /* Reset condition detected, send a presence pulse and reset protocol state */ if(bus->error == OneWireSlaveErrorResetInProgress) { - if(onewire_slave_show_presence(bus)) { - bus->error = OneWireSlaveErrorNone; + if(!bus->is_first_reset) { + /* Guess the reset type */ + bus->is_short_reset = onewire_slave_wait_while_gpio_is( + bus, + onewire_slave_timings_overdrive.trstl_max - + onewire_slave_timings_overdrive.tslot_max, + false); + } else { + bus->is_first_reset = false; + } - if(bus->reset_callback != NULL) { - bus->reset_callback(bus->reset_callback_context); - } + furi_assert(bus->reset_callback); - return true; + if(bus->reset_callback(bus->is_short_reset, bus->reset_callback_context)) { + if(onewire_slave_show_presence(bus)) { + bus->error = OneWireSlaveErrorNone; + return true; + } } } else if(bus->error == OneWireSlaveErrorNone) { uint8_t command; - if(!onewire_slave_receive(bus, &command, 1)) { - /* Upon failure, request an additional iteration to - choose the appropriate action by checking bus->error */ - return true; - } else if(bus->command_callback) { - return bus->command_callback(command, bus->command_callback_context); - } else { - bus->error = OneWireSlaveErrorInvalidCommand; + if(onewire_slave_receive(bus, &command, sizeof(command))) { + furi_assert(bus->command_callback); + if(bus->command_callback(command, bus->command_callback_context)) { + return true; + } } + + return (bus->error == OneWireSlaveErrorResetInProgress); } return false; @@ -115,9 +160,6 @@ static inline bool onewire_slave_bus_start(OneWireSlave* bus) { FURI_CRITICAL_ENTER(); furi_hal_gpio_init(bus->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); - /* Start in Reset state in order to send a presence pulse immediately */ - bus->error = OneWireSlaveErrorResetInProgress; - while(onewire_slave_receive_and_process_command(bus)) ; @@ -139,7 +181,15 @@ static void onewire_slave_exti_callback(void* context) { const uint32_t pulse_length = (DWT->CYCCNT - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); - if((pulse_length >= ONEWIRE_TRSTL_MIN) && pulse_length <= (ONEWIRE_TRSTL_MAX)) { + if((pulse_length >= onewire_slave_timings_overdrive.trstl_min) && + (pulse_length <= onewire_slave_timings_normal.trstl_max)) { + /* Start in reset state in order to send a presence pulse immediately */ + bus->error = OneWireSlaveErrorResetInProgress; + /* Determine reset type (chooses speed mode if supported by the emulated device) */ + bus->is_short_reset = pulse_length <= onewire_slave_timings_overdrive.trstl_max; + /* Initial reset allows going directly into overdrive mode */ + bus->is_first_reset = true; + const bool result = onewire_slave_bus_start(bus); if(result && bus->result_callback != NULL) { @@ -158,6 +208,7 @@ OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin) { OneWireSlave* bus = malloc(sizeof(OneWireSlave)); bus->gpio_pin = gpio_pin; + bus->timings = &onewire_slave_timings_normal; bus->error = OneWireSlaveErrorNone; return bus; @@ -205,52 +256,45 @@ void onewire_slave_set_result_callback( } bool onewire_slave_receive_bit(OneWireSlave* bus) { + const OneWireSlaveTimings* timings = bus->timings; // wait while bus is low - uint32_t time = ONEWIRE_TSLOT_MAX; - time = onewire_slave_wait_while_gpio_is(bus, time, false); - if(time == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, timings->tslot_max, false)) { bus->error = OneWireSlaveErrorResetInProgress; return false; } // wait while bus is high - time = ONEWIRE_TH_TIMEOUT; - time = onewire_slave_wait_while_gpio_is(bus, time, true); - if(time == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, TH_TIMEOUT_MAX, true)) { bus->error = OneWireSlaveErrorTimeout; return false; } // wait a time of zero - time = ONEWIRE_TW1L_MAX; - time = onewire_slave_wait_while_gpio_is(bus, time, false); - - return (time > 0); + return onewire_slave_wait_while_gpio_is(bus, timings->tw1l_max, false); } bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { + const OneWireSlaveTimings* timings = bus->timings; // wait while bus is low - uint32_t time = ONEWIRE_TSLOT_MAX; - time = onewire_slave_wait_while_gpio_is(bus, time, false); - if(time == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, timings->tslot_max, false)) { bus->error = OneWireSlaveErrorResetInProgress; return false; } // wait while bus is high - time = ONEWIRE_TH_TIMEOUT; - time = onewire_slave_wait_while_gpio_is(bus, time, true); - if(time == 0) { + if(!onewire_slave_wait_while_gpio_is(bus, TH_TIMEOUT_MAX, true)) { bus->error = OneWireSlaveErrorTimeout; return false; } // choose write time + uint32_t time; + if(!value) { furi_hal_gpio_write(bus->gpio_pin, false); - time = ONEWIRE_TRL_TMSR_MAX; + time = timings->trl_tmsr_max; } else { - time = ONEWIRE_TSLOT_MIN; + time = timings->tslot_min; } // hold line for ZERO or ONE time @@ -301,3 +345,13 @@ bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, size_t data_size) { } return true; } + +void onewire_slave_set_overdrive(OneWireSlave* bus, bool set) { + const OneWireSlaveTimings* new_timings = set ? &onewire_slave_timings_overdrive : + &onewire_slave_timings_normal; + if(bus->timings != new_timings) { + /* Prevent erroneous reset by waiting for the previous time slot to finish */ + onewire_slave_wait_while_gpio_is(bus, bus->timings->tslot_max, false); + bus->timings = new_timings; + } +} diff --git a/lib/one_wire/one_wire_slave.h b/lib/one_wire/one_wire_slave.h index 914cd9335e..21114b912c 100644 --- a/lib/one_wire/one_wire_slave.h +++ b/lib/one_wire/one_wire_slave.h @@ -18,68 +18,85 @@ extern "C" { typedef struct OneWireDevice OneWireDevice; typedef struct OneWireSlave OneWireSlave; -typedef void (*OneWireSlaveResetCallback)(void* context); -typedef void (*OneWireSlaveResultCallback)(void* context); +typedef bool (*OneWireSlaveResetCallback)(bool is_short, void* context); typedef bool (*OneWireSlaveCommandCallback)(uint8_t command, void* context); +typedef void (*OneWireSlaveResultCallback)(void* context); /** - * Allocate onewire slave - * @param gpio_pin - * @return OneWireSlave* + * Allocate OneWireSlave instance + * @param [in] gpio_pin connection pin + * @return pointer to OneWireSlave instance */ OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin); /** - * Free onewire slave - * @param bus + * Destroy OneWireSlave instance, free resources + * @param [in] bus pointer to OneWireSlave instance */ void onewire_slave_free(OneWireSlave* bus); /** * Start working with the bus - * @param bus + * @param [in] bus pointer to OneWireSlave instance */ void onewire_slave_start(OneWireSlave* bus); /** * Stop working with the bus - * @param bus + * @param [in] bus pointer to OneWireSlave instance */ void onewire_slave_stop(OneWireSlave* bus); /** - * TODO: description comment + * Receive one bit + * @param [in] bus pointer to OneWireSlave instance + * @return received bit value */ bool onewire_slave_receive_bit(OneWireSlave* bus); /** - * TODO: description comment + * Send one bit + * @param [in] bus pointer to OneWireSlave instance + * @param [in] value bit value to send + * @return true on success, false on failure */ bool onewire_slave_send_bit(OneWireSlave* bus, bool value); /** - * Send data - * @param bus - * @param data - * @param data_size - * @return bool + * Send one or more bytes of data + * @param [in] bus pointer to OneWireSlave instance + * @param [in] data pointer to the data to send + * @param [in] data_size size of the data to send + * @return true on success, false on failure */ bool onewire_slave_send(OneWireSlave* bus, const uint8_t* data, size_t data_size); /** - * Receive data - * @param bus - * @param data - * @param data_size - * @return bool + * Receive one or more bytes of data + * @param [in] bus pointer to OneWireSlave instance + * @param [out] data pointer to the receive buffer + * @param [in] data_size number of bytes to receive + * @return true on success, false on failure */ bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, size_t data_size); /** - * Set a callback to be called on each reset - * @param bus - * @param callback - * @param context + * Enable overdrive mode + * @param [in] bus pointer to OneWireSlave instance + * @param [in] set true to turn overdrive on, false to turn it off + */ +void onewire_slave_set_overdrive(OneWireSlave* bus, bool set); + +/** + * Set a callback function to be called on each reset. + * The return value of the callback determines whether the emulated device + * supports the short reset (passed as the is_short parameter). + * In most applications, it should also call onewire_slave_set_overdrive() + * to set the appropriate speed mode. + * + * @param [in] bus pointer to OneWireSlave instance + * @param [in] callback pointer to a callback function + * @param [in] context additional parameter to be passed to the callback */ void onewire_slave_set_reset_callback( OneWireSlave* bus, @@ -87,10 +104,13 @@ void onewire_slave_set_reset_callback( void* context); /** - * Set a callback to be called on each command - * @param bus - * @param callback - * @param context + * Set a callback function to be called on each command. + * The return value of the callback determines whether further operation + * is possible. As a rule of thumb, return true unless a critical error happened. + * + * @param [in] bus pointer to OneWireSlave instance + * @param [in] callback pointer to a callback function + * @param [in] context additional parameter to be passed to the callback */ void onewire_slave_set_command_callback( OneWireSlave* bus, @@ -99,9 +119,9 @@ void onewire_slave_set_command_callback( /** * Set a callback to report emulation success - * @param bus - * @param result_cb - * @param context + * @param [in] bus pointer to OneWireSlave instance + * @param [in] result_cb pointer to a callback function + * @param [in] context additional parameter to be passed to the callback */ void onewire_slave_set_result_callback( OneWireSlave* bus, From 9daa51eda4a723135e3e0fd4b63835173dad3575 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 22 Mar 2023 18:41:50 +0300 Subject: [PATCH 17/26] Update DS1420 to latest changes --- lib/ibutton/protocols/dallas/protocol_ds1420.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/ibutton/protocols/dallas/protocol_ds1420.c b/lib/ibutton/protocols/dallas/protocol_ds1420.c index ebfb700ce4..85e0145f47 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1420.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1420.c @@ -67,6 +67,14 @@ bool dallas_ds1420_write_blank(OneWireHost* host, iButtonProtocolData* protocol_ tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); } +static bool dallas_ds1420_reset_callback(bool is_short, void* context) { + DS1420ProtocolData* data = context; + if(!is_short) { + onewire_slave_set_overdrive(data->state.bus, is_short); + } + return !is_short; +} + static bool dallas_ds1420_command_callback(uint8_t command, void* context) { furi_assert(context); DS1420ProtocolData* data = context; @@ -92,7 +100,7 @@ void dallas_ds1420_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data DS1420ProtocolData* data = protocol_data; data->state.bus = bus; - onewire_slave_set_reset_callback(bus, NULL, NULL); + onewire_slave_set_reset_callback(bus, dallas_ds1420_reset_callback, protocol_data); onewire_slave_set_command_callback(bus, dallas_ds1420_command_callback, protocol_data); } From 7bf0a4786c6987b756683f6ee0af866833a8b4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 23 Mar 2023 02:00:48 +0900 Subject: [PATCH 18/26] [FL-3152] Screen streaming improvements (#2498) * Rpc: reserve some bandwidth when screen streaming * Move furi_hal_compress to toolbox/comporess * Lib: heatshrink as external submodule, compile warnings fixes, better buffer management * Lib: cleanup compressor definitions * Rpc: add canvas orientation support * Format Sources --- .gitmodules | 3 + applications/services/gui/canvas.c | 9 +- applications/services/gui/canvas_i.h | 2 + applications/services/gui/gui.c | 1 + applications/services/gui/gui.h | 6 +- applications/services/rpc/rpc_gui.c | 26 +- assets/protobuf | 2 +- firmware/targets/f18/api_symbols.csv | 13 +- firmware/targets/f18/furi_hal/furi_hal.c | 34 +- .../targets/f18/furi_hal/furi_hal_resources.c | 4 + firmware/targets/f7/api_symbols.csv | 7 - firmware/targets/f7/furi_hal/furi_hal.c | 26 - .../targets/f7/furi_hal/furi_hal_ibutton.c | 3 + .../targets/f7/furi_hal/furi_hal_resources.c | 4 + firmware/targets/f7/src/dfu.c | 7 +- firmware/targets/f7/src/recovery.c | 6 +- firmware/targets/furi_hal_include/furi_hal.h | 1 - .../furi_hal_include/furi_hal_compress.h | 87 --- lib/err.h | 4 + lib/heatshrink | 1 + lib/heatshrink/heatshrink_common.h | 20 - lib/heatshrink/heatshrink_config.h | 28 - lib/heatshrink/heatshrink_decoder.c | 364 ----------- lib/heatshrink/heatshrink_decoder.h | 100 --- lib/heatshrink/heatshrink_encoder.c | 602 ------------------ lib/heatshrink/heatshrink_encoder.h | 109 ---- lib/misc.scons | 7 +- .../toolbox/compress.c | 127 ++-- lib/toolbox/compress.h | 96 +++ 29 files changed, 242 insertions(+), 1457 deletions(-) delete mode 100644 firmware/targets/furi_hal_include/furi_hal_compress.h create mode 100644 lib/err.h create mode 160000 lib/heatshrink delete mode 100644 lib/heatshrink/heatshrink_common.h delete mode 100644 lib/heatshrink/heatshrink_config.h delete mode 100644 lib/heatshrink/heatshrink_decoder.c delete mode 100644 lib/heatshrink/heatshrink_decoder.h delete mode 100644 lib/heatshrink/heatshrink_encoder.c delete mode 100644 lib/heatshrink/heatshrink_encoder.h rename firmware/targets/f7/furi_hal/furi_hal_compress.c => lib/toolbox/compress.c (67%) create mode 100644 lib/toolbox/compress.h diff --git a/.gitmodules b/.gitmodules index 56368cd588..3a15177bd1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,3 +31,6 @@ [submodule "applications/external/dap_link/lib/free-dap"] path = applications/external/dap_link/lib/free-dap url = https://github.com/ataradov/free-dap.git +[submodule "lib/heatshrink"] + path = lib/heatshrink + url = https://github.com/flipperdevices/heatshrink.git diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 9c29a39fd9..40797c0867 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -17,6 +17,7 @@ const CanvasFontParameters canvas_font_params[FontTotalNumber] = { Canvas* canvas_init() { Canvas* canvas = malloc(sizeof(Canvas)); + canvas->compress_icon = compress_icon_alloc(); // Setup u8g2 u8g2_Setup_st756x_flipper(&canvas->fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); @@ -35,6 +36,7 @@ Canvas* canvas_init() { void canvas_free(Canvas* canvas) { furi_assert(canvas); + compress_icon_free(canvas->compress_icon); free(canvas); } @@ -218,7 +220,7 @@ void canvas_draw_bitmap( x += canvas->offset_x; y += canvas->offset_y; uint8_t* bitmap_data = NULL; - furi_hal_compress_icon_decode(compressed_bitmap_data, &bitmap_data); + compress_icon_decode(canvas->compress_icon, compressed_bitmap_data, &bitmap_data); u8g2_DrawXBM(&canvas->fb, x, y, width, height, bitmap_data); } @@ -233,7 +235,8 @@ void canvas_draw_icon_animation( x += canvas->offset_x; y += canvas->offset_y; uint8_t* icon_data = NULL; - furi_hal_compress_icon_decode(icon_animation_get_data(icon_animation), &icon_data); + compress_icon_decode( + canvas->compress_icon, icon_animation_get_data(icon_animation), &icon_data); u8g2_DrawXBM( &canvas->fb, x, @@ -250,7 +253,7 @@ void canvas_draw_icon(Canvas* canvas, uint8_t x, uint8_t y, const Icon* icon) { x += canvas->offset_x; y += canvas->offset_y; uint8_t* icon_data = NULL; - furi_hal_compress_icon_decode(icon_get_data(icon), &icon_data); + compress_icon_decode(canvas->compress_icon, icon_get_data(icon), &icon_data); u8g2_DrawXBM(&canvas->fb, x, y, icon_get_width(icon), icon_get_height(icon), icon_data); } diff --git a/applications/services/gui/canvas_i.h b/applications/services/gui/canvas_i.h index 12cabfa7d9..39e7021bc9 100644 --- a/applications/services/gui/canvas_i.h +++ b/applications/services/gui/canvas_i.h @@ -7,6 +7,7 @@ #include "canvas.h" #include +#include /** Canvas structure */ @@ -17,6 +18,7 @@ struct Canvas { uint8_t offset_y; uint8_t width; uint8_t height; + CompressIcon* compress_icon; }; /** Allocate memory and initialize canvas diff --git a/applications/services/gui/gui.c b/applications/services/gui/gui.c index 24b48a837d..392011620a 100644 --- a/applications/services/gui/gui.c +++ b/applications/services/gui/gui.c @@ -250,6 +250,7 @@ static void gui_redraw(Gui* gui) { p->callback( canvas_get_buffer(gui->canvas), canvas_get_buffer_size(gui->canvas), + canvas_get_orientation(gui->canvas), p->context); } } while(false); diff --git a/applications/services/gui/gui.h b/applications/services/gui/gui.h index d7d73f27b6..1b5987edac 100644 --- a/applications/services/gui/gui.h +++ b/applications/services/gui/gui.h @@ -27,7 +27,11 @@ typedef enum { } GuiLayer; /** Gui Canvas Commit Callback */ -typedef void (*GuiCanvasCommitCallback)(uint8_t* data, size_t size, void* context); +typedef void (*GuiCanvasCommitCallback)( + uint8_t* data, + size_t size, + CanvasOrientation orientation, + void* context); #define RECORD_GUI "gui" diff --git a/applications/services/rpc/rpc_gui.c b/applications/services/rpc/rpc_gui.c index c2af425e93..0c70702cf4 100644 --- a/applications/services/rpc/rpc_gui.c +++ b/applications/services/rpc/rpc_gui.c @@ -33,8 +33,18 @@ typedef struct { uint32_t input_counter; } RpcGuiSystem; -static void - rpc_system_gui_screen_stream_frame_callback(uint8_t* data, size_t size, void* context) { +static const PB_Gui_ScreenOrientation rpc_system_gui_screen_orientation_map[] = { + [CanvasOrientationHorizontal] = PB_Gui_ScreenOrientation_HORIZONTAL, + [CanvasOrientationHorizontalFlip] = PB_Gui_ScreenOrientation_HORIZONTAL_FLIP, + [CanvasOrientationVertical] = PB_Gui_ScreenOrientation_VERTICAL, + [CanvasOrientationVerticalFlip] = PB_Gui_ScreenOrientation_VERTICAL_FLIP, +}; + +static void rpc_system_gui_screen_stream_frame_callback( + uint8_t* data, + size_t size, + CanvasOrientation orientation, + void* context) { furi_assert(data); furi_assert(context); @@ -44,6 +54,8 @@ static void furi_assert(size == rpc_gui->transmit_frame->content.gui_screen_frame.data->size); memcpy(buffer, data, size); + rpc_gui->transmit_frame->content.gui_screen_frame.orientation = + rpc_system_gui_screen_orientation_map[orientation]; furi_thread_flags_set(furi_thread_get_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagTransmit); } @@ -53,12 +65,22 @@ static int32_t rpc_system_gui_screen_stream_frame_transmit_thread(void* context) RpcGuiSystem* rpc_gui = (RpcGuiSystem*)context; + uint32_t transmit_time = 0; while(true) { uint32_t flags = furi_thread_flags_wait(RpcGuiWorkerFlagAny, FuriFlagWaitAny, FuriWaitForever); + if(flags & RpcGuiWorkerFlagTransmit) { + transmit_time = furi_get_tick(); rpc_send(rpc_gui->session, rpc_gui->transmit_frame); + transmit_time = furi_get_tick() - transmit_time; + + // Guaranteed bandwidth reserve + uint32_t extra_delay = transmit_time / 20; + if(extra_delay > 500) extra_delay = 500; + if(extra_delay) furi_delay_tick(extra_delay); } + if(flags & RpcGuiWorkerFlagExit) { break; } diff --git a/assets/protobuf b/assets/protobuf index 6460660237..1f6b4a08c5 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 6460660237005d02d5c223835659b40e373bade9 +Subproject commit 1f6b4a08c5d05c2b17926a3ba79f60109638932f diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index e6fae33ee4..40e23a747f 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -57,7 +57,6 @@ Header,+,firmware/targets/furi_hal_include/furi_hal.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt_hid.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt_serial.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_compress.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_cortex.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_crypto.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_debug.h,, @@ -876,12 +875,12 @@ Function,-,furi_hal_clock_resume_tick,void, Function,-,furi_hal_clock_suspend_tick,void, Function,-,furi_hal_clock_switch_to_hsi,void, Function,-,furi_hal_clock_switch_to_pll,void, -Function,-,furi_hal_compress_alloc,FuriHalCompress*,uint16_t -Function,-,furi_hal_compress_decode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" -Function,-,furi_hal_compress_encode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" -Function,-,furi_hal_compress_free,void,FuriHalCompress* -Function,-,furi_hal_compress_icon_decode,void,"const uint8_t*, uint8_t**" -Function,-,furi_hal_compress_icon_init,void, +Function,-,compress_alloc,Compress*,uint16_t +Function,-,compress_decode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" +Function,-,compress_encode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" +Function,-,compress_free,void,Compress* +Function,-,compress_icon_decode,void,"const uint8_t*, uint8_t**" +Function,-,compress_icon_init,void, Function,+,furi_hal_console_disable,void, Function,+,furi_hal_console_enable,void, Function,+,furi_hal_console_init,void, diff --git a/firmware/targets/f18/furi_hal/furi_hal.c b/firmware/targets/f18/furi_hal/furi_hal.c index 2c255fa0de..4064dd6472 100644 --- a/firmware/targets/f18/furi_hal/furi_hal.c +++ b/firmware/targets/f18/furi_hal/furi_hal.c @@ -1,5 +1,6 @@ #include #include +#include #include @@ -7,29 +8,20 @@ void furi_hal_init_early() { furi_hal_cortex_init_early(); - furi_hal_clock_init_early(); - furi_hal_resources_init_early(); - furi_hal_os_init(); - furi_hal_spi_config_init_early(); - furi_hal_i2c_init_early(); furi_hal_light_init(); - furi_hal_rtc_init_early(); } void furi_hal_deinit_early() { furi_hal_rtc_deinit_early(); - furi_hal_i2c_deinit_early(); furi_hal_spi_config_deinit_early(); - furi_hal_resources_deinit_early(); - furi_hal_clock_deinit_early(); } @@ -38,40 +30,24 @@ void furi_hal_init() { furi_hal_clock_init(); furi_hal_console_init(); furi_hal_rtc_init(); - furi_hal_interrupt_init(); - furi_hal_flash_init(); - furi_hal_resources_init(); - FURI_LOG_I(TAG, "GPIO OK"); - furi_hal_version_init(); - furi_hal_spi_config_init(); furi_hal_spi_dma_init(); - furi_hal_speaker_init(); - FURI_LOG_I(TAG, "Speaker OK"); - furi_hal_crypto_init(); - - // USB -#ifndef FURI_RAM_EXEC - furi_hal_usb_init(); - FURI_LOG_I(TAG, "USB OK"); -#endif - furi_hal_i2c_init(); - - // High Level furi_hal_power_init(); furi_hal_light_init(); + furi_hal_bt_init(); + furi_hal_memory_init(); + #ifndef FURI_RAM_EXEC + furi_hal_usb_init(); furi_hal_vibro_init(); #endif - furi_hal_bt_init(); - furi_hal_compress_icon_init(); } void furi_hal_switch(void* address) { diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.c b/firmware/targets/f18/furi_hal/furi_hal_resources.c index 41cc80bfba..abb258cb11 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f18/furi_hal/furi_hal_resources.c @@ -4,6 +4,8 @@ #include #include +#define TAG "FuriHalResources" + const GpioPin vibro_gpio = {.port = GPIOA, .pin = LL_GPIO_PIN_8}; const GpioPin ibutton_gpio = {.port = GPIOB, .pin = LL_GPIO_PIN_14}; @@ -198,6 +200,8 @@ void furi_hal_resources_init() { NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(EXTI15_10_IRQn); + + FURI_LOG_I(TAG, "Init OK"); } int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio) { diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 7ac9a24599..8b1d29b1ce 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -62,7 +62,6 @@ Header,+,firmware/targets/furi_hal_include/furi_hal.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt_hid.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt_serial.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_compress.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_cortex.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_crypto.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_debug.h,, @@ -1057,12 +1056,6 @@ Function,-,furi_hal_clock_resume_tick,void, Function,-,furi_hal_clock_suspend_tick,void, Function,-,furi_hal_clock_switch_to_hsi,void, Function,-,furi_hal_clock_switch_to_pll,void, -Function,-,furi_hal_compress_alloc,FuriHalCompress*,uint16_t -Function,-,furi_hal_compress_decode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" -Function,-,furi_hal_compress_encode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" -Function,-,furi_hal_compress_free,void,FuriHalCompress* -Function,-,furi_hal_compress_icon_decode,void,"const uint8_t*, uint8_t**" -Function,-,furi_hal_compress_icon_init,void, Function,+,furi_hal_console_disable,void, Function,+,furi_hal_console_enable,void, Function,+,furi_hal_console_init,void, diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index 5840a697e4..1b710bb963 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -8,29 +8,20 @@ void furi_hal_init_early() { furi_hal_cortex_init_early(); - furi_hal_clock_init_early(); - furi_hal_resources_init_early(); - furi_hal_os_init(); - furi_hal_spi_config_init_early(); - furi_hal_i2c_init_early(); furi_hal_light_init(); - furi_hal_rtc_init_early(); } void furi_hal_deinit_early() { furi_hal_rtc_deinit_early(); - furi_hal_i2c_deinit_early(); furi_hal_spi_config_deinit_early(); - furi_hal_resources_deinit_early(); - furi_hal_clock_deinit_early(); } @@ -39,41 +30,24 @@ void furi_hal_init() { furi_hal_clock_init(); furi_hal_console_init(); furi_hal_rtc_init(); - furi_hal_interrupt_init(); - furi_hal_flash_init(); - furi_hal_resources_init(); - FURI_LOG_I(TAG, "GPIO OK"); - furi_hal_version_init(); furi_hal_region_init(); - furi_hal_spi_config_init(); furi_hal_spi_dma_init(); - furi_hal_ibutton_init(); - FURI_LOG_I(TAG, "iButton OK"); furi_hal_speaker_init(); - FURI_LOG_I(TAG, "Speaker OK"); - furi_hal_crypto_init(); - furi_hal_i2c_init(); - - // High Level furi_hal_power_init(); furi_hal_light_init(); - furi_hal_bt_init(); furi_hal_memory_init(); - furi_hal_compress_icon_init(); #ifndef FURI_RAM_EXEC - // USB furi_hal_usb_init(); - FURI_LOG_I(TAG, "USB OK"); furi_hal_vibro_init(); furi_hal_subghz_init(); furi_hal_nfc_init(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c index c05cd69a82..f19fd0a0ef 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c +++ b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c @@ -7,6 +7,7 @@ #include +#define TAG "FuriHalIbutton" #define FURI_HAL_IBUTTON_TIMER TIM1 #define FURI_HAL_IBUTTON_TIMER_IRQ FuriHalInterruptIdTim1UpTim16 @@ -33,6 +34,8 @@ static void furi_hal_ibutton_emulate_isr() { void furi_hal_ibutton_init() { furi_hal_ibutton = malloc(sizeof(FuriHalIbutton)); furi_hal_ibutton->state = FuriHalIbuttonStateIdle; + + FURI_LOG_I(TAG, "Init OK"); } void furi_hal_ibutton_emulate_start( diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/firmware/targets/f7/furi_hal/furi_hal_resources.c index c0eb9ee67c..d0d85cb2d6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.c @@ -4,6 +4,8 @@ #include #include +#define TAG "FuriHalResources" + const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin}; const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin}; @@ -190,6 +192,8 @@ void furi_hal_resources_init() { NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(EXTI15_10_IRQn); + + FURI_LOG_I(TAG, "Init OK"); } int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio) { diff --git a/firmware/targets/f7/src/dfu.c b/firmware/targets/f7/src/dfu.c index f32ac2ac48..b060bc8d26 100644 --- a/firmware/targets/f7/src/dfu.c +++ b/firmware/targets/f7/src/dfu.c @@ -4,10 +4,11 @@ #include #include #include +#include void flipper_boot_dfu_show_splash() { // Initialize - furi_hal_compress_icon_init(); + CompressIcon* compress_icon = compress_icon_alloc(); u8g2_t* fb = malloc(sizeof(u8g2_t)); memset(fb, 0, sizeof(u8g2_t)); @@ -15,13 +16,15 @@ void flipper_boot_dfu_show_splash() { u8g2_InitDisplay(fb); u8g2_SetDrawColor(fb, 0x01); uint8_t* splash_data = NULL; - furi_hal_compress_icon_decode(icon_get_data(&I_DFU_128x50), &splash_data); + compress_icon_decode(compress_icon, icon_get_data(&I_DFU_128x50), &splash_data); u8g2_DrawXBM(fb, 0, 64 - 50, 128, 50, splash_data); u8g2_SetFont(fb, u8g2_font_helvB08_tr); u8g2_DrawStr(fb, 2, 8, "Update & Recovery Mode"); u8g2_DrawStr(fb, 2, 21, "DFU Started"); u8g2_SetPowerSave(fb, 0); u8g2_SendBuffer(fb); + + compress_icon_free(compress_icon); } void flipper_boot_dfu_exec() { diff --git a/firmware/targets/f7/src/recovery.c b/firmware/targets/f7/src/recovery.c index db538b0d51..d037e8118f 100644 --- a/firmware/targets/f7/src/recovery.c +++ b/firmware/targets/f7/src/recovery.c @@ -4,6 +4,7 @@ #include #include #include +#include #define COUNTER_VALUE (136U) @@ -27,9 +28,9 @@ void flipper_boot_recovery_exec() { u8g2_Setup_st756x_flipper(fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); u8g2_InitDisplay(fb); - furi_hal_compress_icon_init(); + CompressIcon* compress_icon = compress_icon_alloc(); uint8_t* splash_data = NULL; - furi_hal_compress_icon_decode(icon_get_data(&I_Erase_pin_128x64), &splash_data); + compress_icon_decode(compress_icon, icon_get_data(&I_Erase_pin_128x64), &splash_data); u8g2_ClearBuffer(fb); u8g2_SetDrawColor(fb, 0x01); @@ -38,6 +39,7 @@ void flipper_boot_recovery_exec() { u8g2_DrawXBM(fb, 0, 0, 128, 64, splash_data); u8g2_SendBuffer(fb); u8g2_SetPowerSave(fb, 0); + compress_icon_free(compress_icon); size_t counter = COUNTER_VALUE; while(counter) { diff --git a/firmware/targets/furi_hal_include/furi_hal.h b/firmware/targets/furi_hal_include/furi_hal.h index ad4340dd40..2eb4688d42 100644 --- a/firmware/targets/furi_hal_include/furi_hal.h +++ b/firmware/targets/furi_hal_include/furi_hal.h @@ -33,7 +33,6 @@ struct STOP_EXTERNING_ME {}; #include #include #include -#include #include #include #include diff --git a/firmware/targets/furi_hal_include/furi_hal_compress.h b/firmware/targets/furi_hal_include/furi_hal_compress.h deleted file mode 100644 index f80aee5162..0000000000 --- a/firmware/targets/furi_hal_include/furi_hal_compress.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file furi_hal_compress.h - * LZSS based compression HAL API - */ -#pragma once - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Defines encoder and decoder window size */ -#define FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG (8) - -/** Defines encoder and decoder lookahead buffer size */ -#define FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG (4) - -/** FuriHalCompress control structure */ -typedef struct FuriHalCompress FuriHalCompress; - -/** Initialize icon decoder - */ -void furi_hal_compress_icon_init(); - -/** Icon decoder - * - * @param icon_data pointer to icon data - * @param decoded_buff pointer to decoded buffer - */ -void furi_hal_compress_icon_decode(const uint8_t* icon_data, uint8_t** decoded_buff); - -/** Allocate encoder and decoder - * - * @param compress_buff_size size of decoder and encoder buffer to allocate - * - * @return FuriHalCompress instance - */ -FuriHalCompress* furi_hal_compress_alloc(uint16_t compress_buff_size); - -/** Free encoder and decoder - * - * @param compress FuriHalCompress instance - */ -void furi_hal_compress_free(FuriHalCompress* compress); - -/** Encode data - * - * @param compress FuriHalCompress instance - * @param data_in pointer to input data - * @param data_in_size size of input data - * @param data_out maximum size of output data - * @param data_res_size pointer to result output data size - * - * @return true on success - */ -bool furi_hal_compress_encode( - FuriHalCompress* compress, - uint8_t* data_in, - size_t data_in_size, - uint8_t* data_out, - size_t data_out_size, - size_t* data_res_size); - -/** Decode data - * - * @param compress FuriHalCompress instance - * @param data_in pointer to input data - * @param data_in_size size of input data - * @param data_out maximum size of output data - * @param data_res_size pointer to result output data size - * - * @return true on success - */ -bool furi_hal_compress_decode( - FuriHalCompress* compress, - uint8_t* data_in, - size_t data_in_size, - uint8_t* data_out, - size_t data_out_size, - size_t* data_res_size); - -#ifdef __cplusplus -} -#endif diff --git a/lib/err.h b/lib/err.h new file mode 100644 index 0000000000..a0e93874e6 --- /dev/null +++ b/lib/err.h @@ -0,0 +1,4 @@ +#pragma once +#include + +#define err(...) FURI_LOG_E("Heatshrink", "Error: %d-%s", __VA_ARGS__) \ No newline at end of file diff --git a/lib/heatshrink b/lib/heatshrink new file mode 160000 index 0000000000..7398ccc916 --- /dev/null +++ b/lib/heatshrink @@ -0,0 +1 @@ +Subproject commit 7398ccc91652a33483245200cfa1a83b073bc206 diff --git a/lib/heatshrink/heatshrink_common.h b/lib/heatshrink/heatshrink_common.h deleted file mode 100644 index 243f447029..0000000000 --- a/lib/heatshrink/heatshrink_common.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef HEATSHRINK_H -#define HEATSHRINK_H - -#define HEATSHRINK_AUTHOR "Scott Vokes " -#define HEATSHRINK_URL "https://github.com/atomicobject/heatshrink" - -/* Version 0.4.1 */ -#define HEATSHRINK_VERSION_MAJOR 0 -#define HEATSHRINK_VERSION_MINOR 4 -#define HEATSHRINK_VERSION_PATCH 1 - -#define HEATSHRINK_MIN_WINDOW_BITS 4 -#define HEATSHRINK_MAX_WINDOW_BITS 15 - -#define HEATSHRINK_MIN_LOOKAHEAD_BITS 3 - -#define HEATSHRINK_LITERAL_MARKER 0x01 -#define HEATSHRINK_BACKREF_MARKER 0x00 - -#endif diff --git a/lib/heatshrink/heatshrink_config.h b/lib/heatshrink/heatshrink_config.h deleted file mode 100644 index 7f2373c0d4..0000000000 --- a/lib/heatshrink/heatshrink_config.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef HEATSHRINK_CONFIG_H -#define HEATSHRINK_CONFIG_H - -#include - -/* Should functionality assuming dynamic allocation be used? */ -#ifndef HEATSHRINK_DYNAMIC_ALLOC -#define HEATSHRINK_DYNAMIC_ALLOC 1 -#endif - -#if HEATSHRINK_DYNAMIC_ALLOC - /* Optional replacement of malloc/free */ - #define HEATSHRINK_MALLOC(SZ) malloc(SZ) - #define HEATSHRINK_FREE(P, SZ) free(P) -#else - /* Required parameters for static configuration */ - #define HEATSHRINK_STATIC_INPUT_BUFFER_SIZE 1024 - #define HEATSHRINK_STATIC_WINDOW_BITS 8 - #define HEATSHRINK_STATIC_LOOKAHEAD_BITS 4 -#endif - -/* Turn on logging for debugging. */ -#define HEATSHRINK_DEBUGGING_LOGS 0 - -/* Use indexing for faster compression. (This requires additional space.) */ -#define HEATSHRINK_USE_INDEX 1 - -#endif diff --git a/lib/heatshrink/heatshrink_decoder.c b/lib/heatshrink/heatshrink_decoder.c deleted file mode 100644 index 2878283675..0000000000 --- a/lib/heatshrink/heatshrink_decoder.c +++ /dev/null @@ -1,364 +0,0 @@ -#include -#include -#include "heatshrink_decoder.h" - -/* States for the polling state machine. */ -typedef enum { - HSDS_TAG_BIT, /* tag bit */ - HSDS_YIELD_LITERAL, /* ready to yield literal byte */ - HSDS_BACKREF_INDEX_MSB, /* most significant byte of index */ - HSDS_BACKREF_INDEX_LSB, /* least significant byte of index */ - HSDS_BACKREF_COUNT_MSB, /* most significant byte of count */ - HSDS_BACKREF_COUNT_LSB, /* least significant byte of count */ - HSDS_YIELD_BACKREF, /* ready to yield back-reference */ -} HSD_state; - -#if HEATSHRINK_DEBUGGING_LOGS -#include -#include -#include -#define LOG(...) fprintf(stderr, __VA_ARGS__) -#define ASSERT(X) assert(X) -static const char *state_names[] = { - "tag_bit", - "yield_literal", - "backref_index_msb", - "backref_index_lsb", - "backref_count_msb", - "backref_count_lsb", - "yield_backref", -}; -#else -#define LOG(...) /* no-op */ -#define ASSERT(X) /* no-op */ -#endif - -typedef struct { - uint8_t *buf; /* output buffer */ - size_t buf_size; /* buffer size */ - size_t *output_size; /* bytes pushed to buffer, so far */ -} output_info; - -#define NO_BITS ((uint16_t)-1) - -/* Forward references. */ -static uint16_t get_bits(heatshrink_decoder *hsd, uint8_t count); -static void push_byte(heatshrink_decoder *hsd, output_info *oi, uint8_t byte); - -#if HEATSHRINK_DYNAMIC_ALLOC -heatshrink_decoder *heatshrink_decoder_alloc(uint8_t* buffer, - uint16_t input_buffer_size, - uint8_t window_sz2, - uint8_t lookahead_sz2) { - if ((window_sz2 < HEATSHRINK_MIN_WINDOW_BITS) || - (window_sz2 > HEATSHRINK_MAX_WINDOW_BITS) || - (input_buffer_size == 0) || - (lookahead_sz2 < HEATSHRINK_MIN_LOOKAHEAD_BITS) || - (lookahead_sz2 >= window_sz2)) { - return NULL; - } - size_t sz = sizeof(heatshrink_decoder); - heatshrink_decoder *hsd = HEATSHRINK_MALLOC(sz); - if (hsd == NULL) { return NULL; } - hsd->input_buffer_size = input_buffer_size; - hsd->window_sz2 = window_sz2; - hsd->lookahead_sz2 = lookahead_sz2; - hsd->buffers = buffer; - heatshrink_decoder_reset(hsd); - LOG("-- allocated decoder with buffer size of %zu (%zu + %u + %u)\n", - sz, sizeof(heatshrink_decoder), (1 << window_sz2), input_buffer_size); - return hsd; -} - -void heatshrink_decoder_free(heatshrink_decoder *hsd) { - size_t sz = sizeof(heatshrink_decoder); - HEATSHRINK_FREE(hsd, sz); - (void)sz; /* may not be used by free */ -} -#endif - -void heatshrink_decoder_reset(heatshrink_decoder *hsd) { - hsd->state = HSDS_TAG_BIT; - hsd->input_size = 0; - hsd->input_index = 0; - hsd->bit_index = 0x00; - hsd->current_byte = 0x00; - hsd->output_count = 0; - hsd->output_index = 0; - hsd->head_index = 0; -} - -/* Copy SIZE bytes into the decoder's input buffer, if it will fit. */ -HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd, - uint8_t *in_buf, size_t size, size_t *input_size) { - if ((hsd == NULL) || (in_buf == NULL) || (input_size == NULL)) { - return HSDR_SINK_ERROR_NULL; - } - - size_t rem = HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd) - hsd->input_size; - if (rem == 0) { - *input_size = 0; - return HSDR_SINK_FULL; - } - - size = rem < size ? rem : size; - LOG("-- sinking %zd bytes\n", size); - /* copy into input buffer (at head of buffers) */ - memcpy(&hsd->buffers[hsd->input_size], in_buf, size); - hsd->input_size += size; - *input_size = size; - return HSDR_SINK_OK; -} - - -/***************** - * Decompression * - *****************/ - -#define BACKREF_COUNT_BITS(HSD) (HEATSHRINK_DECODER_LOOKAHEAD_BITS(HSD)) -#define BACKREF_INDEX_BITS(HSD) (HEATSHRINK_DECODER_WINDOW_BITS(HSD)) - -// States -static HSD_state st_tag_bit(heatshrink_decoder *hsd); -static HSD_state st_yield_literal(heatshrink_decoder *hsd, - output_info *oi); -static HSD_state st_backref_index_msb(heatshrink_decoder *hsd); -static HSD_state st_backref_index_lsb(heatshrink_decoder *hsd); -static HSD_state st_backref_count_msb(heatshrink_decoder *hsd); -static HSD_state st_backref_count_lsb(heatshrink_decoder *hsd); -static HSD_state st_yield_backref(heatshrink_decoder *hsd, - output_info *oi); - -HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd, - uint8_t *out_buf, size_t out_buf_size, size_t *output_size) { - if ((hsd == NULL) || (out_buf == NULL) || (output_size == NULL)) { - return HSDR_POLL_ERROR_NULL; - } - *output_size = 0; - - output_info oi; - oi.buf = out_buf; - oi.buf_size = out_buf_size; - oi.output_size = output_size; - - while (1) { - LOG("-- poll, state is %d (%s), input_size %d\n", - hsd->state, state_names[hsd->state], hsd->input_size); - uint8_t in_state = hsd->state; - switch (in_state) { - case HSDS_TAG_BIT: - hsd->state = st_tag_bit(hsd); - break; - case HSDS_YIELD_LITERAL: - hsd->state = st_yield_literal(hsd, &oi); - break; - case HSDS_BACKREF_INDEX_MSB: - hsd->state = st_backref_index_msb(hsd); - break; - case HSDS_BACKREF_INDEX_LSB: - hsd->state = st_backref_index_lsb(hsd); - break; - case HSDS_BACKREF_COUNT_MSB: - hsd->state = st_backref_count_msb(hsd); - break; - case HSDS_BACKREF_COUNT_LSB: - hsd->state = st_backref_count_lsb(hsd); - break; - case HSDS_YIELD_BACKREF: - hsd->state = st_yield_backref(hsd, &oi); - break; - default: - return HSDR_POLL_ERROR_UNKNOWN; - } - - /* If the current state cannot advance, check if input or output - * buffer are exhausted. */ - if (hsd->state == in_state) { - if (*output_size == out_buf_size) { return HSDR_POLL_MORE; } - return HSDR_POLL_EMPTY; - } - } -} - -static HSD_state st_tag_bit(heatshrink_decoder *hsd) { - uint32_t bits = get_bits(hsd, 1); // get tag bit - if (bits == NO_BITS) { - return HSDS_TAG_BIT; - } else if (bits) { - return HSDS_YIELD_LITERAL; - } else if (HEATSHRINK_DECODER_WINDOW_BITS(hsd) > 8) { - return HSDS_BACKREF_INDEX_MSB; - } else { - hsd->output_index = 0; - return HSDS_BACKREF_INDEX_LSB; - } -} - -static HSD_state st_yield_literal(heatshrink_decoder *hsd, - output_info *oi) { - /* Emit a repeated section from the window buffer, and add it (again) - * to the window buffer. (Note that the repetition can include - * itself.)*/ - if (*oi->output_size < oi->buf_size) { - uint16_t byte = get_bits(hsd, 8); - if (byte == NO_BITS) { return HSDS_YIELD_LITERAL; } /* out of input */ - uint8_t *buf = &hsd->buffers[HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd)]; - uint16_t mask = (1 << HEATSHRINK_DECODER_WINDOW_BITS(hsd)) - 1; - uint8_t c = byte & 0xFF; - LOG("-- emitting literal byte 0x%02x ('%c')\n", c, isprint(c) ? c : '.'); - buf[hsd->head_index++ & mask] = c; - push_byte(hsd, oi, c); - return HSDS_TAG_BIT; - } else { - return HSDS_YIELD_LITERAL; - } -} - -static HSD_state st_backref_index_msb(heatshrink_decoder *hsd) { - uint8_t bit_ct = BACKREF_INDEX_BITS(hsd); - ASSERT(bit_ct > 8); - uint16_t bits = get_bits(hsd, bit_ct - 8); - LOG("-- backref index (msb), got 0x%04x (+1)\n", bits); - if (bits == NO_BITS) { return HSDS_BACKREF_INDEX_MSB; } - hsd->output_index = bits << 8; - return HSDS_BACKREF_INDEX_LSB; -} - -static HSD_state st_backref_index_lsb(heatshrink_decoder *hsd) { - uint8_t bit_ct = BACKREF_INDEX_BITS(hsd); - uint16_t bits = get_bits(hsd, bit_ct < 8 ? bit_ct : 8); - LOG("-- backref index (lsb), got 0x%04x (+1)\n", bits); - if (bits == NO_BITS) { return HSDS_BACKREF_INDEX_LSB; } - hsd->output_index |= bits; - hsd->output_index++; - uint8_t br_bit_ct = BACKREF_COUNT_BITS(hsd); - hsd->output_count = 0; - return (br_bit_ct > 8) ? HSDS_BACKREF_COUNT_MSB : HSDS_BACKREF_COUNT_LSB; -} - -static HSD_state st_backref_count_msb(heatshrink_decoder *hsd) { - uint8_t br_bit_ct = BACKREF_COUNT_BITS(hsd); - ASSERT(br_bit_ct > 8); - uint16_t bits = get_bits(hsd, br_bit_ct - 8); - LOG("-- backref count (msb), got 0x%04x (+1)\n", bits); - if (bits == NO_BITS) { return HSDS_BACKREF_COUNT_MSB; } - hsd->output_count = bits << 8; - return HSDS_BACKREF_COUNT_LSB; -} - -static HSD_state st_backref_count_lsb(heatshrink_decoder *hsd) { - uint8_t br_bit_ct = BACKREF_COUNT_BITS(hsd); - uint16_t bits = get_bits(hsd, br_bit_ct < 8 ? br_bit_ct : 8); - LOG("-- backref count (lsb), got 0x%04x (+1)\n", bits); - if (bits == NO_BITS) { return HSDS_BACKREF_COUNT_LSB; } - hsd->output_count |= bits; - hsd->output_count++; - return HSDS_YIELD_BACKREF; -} - -static HSD_state st_yield_backref(heatshrink_decoder *hsd, - output_info *oi) { - size_t count = oi->buf_size - *oi->output_size; - if (count > 0) { - size_t i = 0; - if (hsd->output_count < count) count = hsd->output_count; - uint8_t *buf = &hsd->buffers[HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd)]; - uint16_t mask = (1 << HEATSHRINK_DECODER_WINDOW_BITS(hsd)) - 1; - uint16_t neg_offset = hsd->output_index; - LOG("-- emitting %zu bytes from -%u bytes back\n", count, neg_offset); - ASSERT(neg_offset <= mask + 1); - ASSERT(count <= (size_t)(1 << BACKREF_COUNT_BITS(hsd))); - - for (i=0; ihead_index - neg_offset) & mask]; - push_byte(hsd, oi, c); - buf[hsd->head_index & mask] = c; - hsd->head_index++; - LOG(" -- ++ 0x%02x\n", c); - } - hsd->output_count -= count; - if (hsd->output_count == 0) { return HSDS_TAG_BIT; } - } - return HSDS_YIELD_BACKREF; -} - -/* Get the next COUNT bits from the input buffer, saving incremental progress. - * Returns NO_BITS on end of input, or if more than 15 bits are requested. */ -static uint16_t get_bits(heatshrink_decoder *hsd, uint8_t count) { - uint16_t accumulator = 0; - int i = 0; - if (count > 15) { return NO_BITS; } - LOG("-- popping %u bit(s)\n", count); - - /* If we aren't able to get COUNT bits, suspend immediately, because we - * don't track how many bits of COUNT we've accumulated before suspend. */ - if (hsd->input_size == 0) { - if (hsd->bit_index < (1 << (count - 1))) { return NO_BITS; } - } - - for (i = 0; i < count; i++) { - if (hsd->bit_index == 0x00) { - if (hsd->input_size == 0) { - LOG(" -- out of bits, suspending w/ accumulator of %u (0x%02x)\n", - accumulator, accumulator); - return NO_BITS; - } - hsd->current_byte = hsd->buffers[hsd->input_index++]; - LOG(" -- pulled byte 0x%02x\n", hsd->current_byte); - if (hsd->input_index == hsd->input_size) { - hsd->input_index = 0; /* input is exhausted */ - hsd->input_size = 0; - } - hsd->bit_index = 0x80; - } - accumulator <<= 1; - if (hsd->current_byte & hsd->bit_index) { - accumulator |= 0x01; - if (0) { - LOG(" -- got 1, accumulator 0x%04x, bit_index 0x%02x\n", - accumulator, hsd->bit_index); - } - } else { - if (0) { - LOG(" -- got 0, accumulator 0x%04x, bit_index 0x%02x\n", - accumulator, hsd->bit_index); - } - } - hsd->bit_index >>= 1; - } - - if (count > 1) { LOG(" -- accumulated %08x\n", accumulator); } - return accumulator; -} - -HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd) { - if (hsd == NULL) { return HSDR_FINISH_ERROR_NULL; } - switch (hsd->state) { - case HSDS_TAG_BIT: - return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE; - - /* If we want to finish with no input, but are in these states, it's - * because the 0-bit padding to the last byte looks like a backref - * marker bit followed by all 0s for index and count bits. */ - case HSDS_BACKREF_INDEX_LSB: - case HSDS_BACKREF_INDEX_MSB: - case HSDS_BACKREF_COUNT_LSB: - case HSDS_BACKREF_COUNT_MSB: - return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE; - - /* If the output stream is padded with 0xFFs (possibly due to being in - * flash memory), also explicitly check the input size rather than - * uselessly returning MORE but yielding 0 bytes when polling. */ - case HSDS_YIELD_LITERAL: - return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE; - - default: - return HSDR_FINISH_MORE; - } -} - -static void push_byte(heatshrink_decoder *hsd, output_info *oi, uint8_t byte) { - LOG(" -- pushing byte: 0x%02x ('%c')\n", byte, isprint(byte) ? byte : '.'); - oi->buf[(*oi->output_size)++] = byte; - (void)hsd; -} diff --git a/lib/heatshrink/heatshrink_decoder.h b/lib/heatshrink/heatshrink_decoder.h deleted file mode 100644 index 687b0806b4..0000000000 --- a/lib/heatshrink/heatshrink_decoder.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef HEATSHRINK_DECODER_H -#define HEATSHRINK_DECODER_H - -#include -#include -#include "heatshrink_common.h" -#include "heatshrink_config.h" - -typedef enum { - HSDR_SINK_OK, /* data sunk, ready to poll */ - HSDR_SINK_FULL, /* out of space in internal buffer */ - HSDR_SINK_ERROR_NULL=-1, /* NULL argument */ -} HSD_sink_res; - -typedef enum { - HSDR_POLL_EMPTY, /* input exhausted */ - HSDR_POLL_MORE, /* more data remaining, call again w/ fresh output buffer */ - HSDR_POLL_ERROR_NULL=-1, /* NULL arguments */ - HSDR_POLL_ERROR_UNKNOWN=-2, -} HSD_poll_res; - -typedef enum { - HSDR_FINISH_DONE, /* output is done */ - HSDR_FINISH_MORE, /* more output remains */ - HSDR_FINISH_ERROR_NULL=-1, /* NULL arguments */ -} HSD_finish_res; - -#if HEATSHRINK_DYNAMIC_ALLOC -#define HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(BUF) \ - ((BUF)->input_buffer_size) -#define HEATSHRINK_DECODER_WINDOW_BITS(BUF) \ - ((BUF)->window_sz2) -#define HEATSHRINK_DECODER_LOOKAHEAD_BITS(BUF) \ - ((BUF)->lookahead_sz2) -#else -#define HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(_) \ - HEATSHRINK_STATIC_INPUT_BUFFER_SIZE -#define HEATSHRINK_DECODER_WINDOW_BITS(_) \ - (HEATSHRINK_STATIC_WINDOW_BITS) -#define HEATSHRINK_DECODER_LOOKAHEAD_BITS(BUF) \ - (HEATSHRINK_STATIC_LOOKAHEAD_BITS) -#endif - -typedef struct { - uint16_t input_size; /* bytes in input buffer */ - uint16_t input_index; /* offset to next unprocessed input byte */ - uint16_t output_count; /* how many bytes to output */ - uint16_t output_index; /* index for bytes to output */ - uint16_t head_index; /* head of window buffer */ - uint8_t state; /* current state machine node */ - uint8_t current_byte; /* current byte of input */ - uint8_t bit_index; /* current bit index */ - -#if HEATSHRINK_DYNAMIC_ALLOC - /* Fields that are only used if dynamically allocated. */ - uint8_t window_sz2; /* window buffer bits */ - uint8_t lookahead_sz2; /* lookahead bits */ - uint16_t input_buffer_size; /* input buffer size */ - - /* Input buffer, then expansion window buffer */ - uint8_t* buffers; -#else - /* Input buffer, then expansion window buffer */ - uint8_t buffers[(1 << HEATSHRINK_DECODER_WINDOW_BITS(_)) - + HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(_)]; -#endif -} heatshrink_decoder; - -#if HEATSHRINK_DYNAMIC_ALLOC -/* Allocate a decoder with an input buffer of INPUT_BUFFER_SIZE bytes, - * an expansion buffer size of 2^WINDOW_SZ2, and a lookahead - * size of 2^lookahead_sz2. (The window buffer and lookahead sizes - * must match the settings used when the data was compressed.) - * Returns NULL on error. */ -heatshrink_decoder *heatshrink_decoder_alloc(uint8_t* buffer, uint16_t input_buffer_size, - uint8_t expansion_buffer_sz2, uint8_t lookahead_sz2); - -/* Free a decoder. */ -void heatshrink_decoder_free(heatshrink_decoder *hsd); -#endif - -/* Reset a decoder. */ -void heatshrink_decoder_reset(heatshrink_decoder *hsd); - -/* Sink at most SIZE bytes from IN_BUF into the decoder. *INPUT_SIZE is set to - * indicate how many bytes were actually sunk (in case a buffer was filled). */ -HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd, - uint8_t *in_buf, size_t size, size_t *input_size); - -/* Poll for output from the decoder, copying at most OUT_BUF_SIZE bytes into - * OUT_BUF (setting *OUTPUT_SIZE to the actual amount copied). */ -HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd, - uint8_t *out_buf, size_t out_buf_size, size_t *output_size); - -/* Notify the dencoder that the input stream is finished. - * If the return value is HSDR_FINISH_MORE, there is still more output, so - * call heatshrink_decoder_poll and repeat. */ -HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd); - -#endif diff --git a/lib/heatshrink/heatshrink_encoder.c b/lib/heatshrink/heatshrink_encoder.c deleted file mode 100644 index 98f27dff87..0000000000 --- a/lib/heatshrink/heatshrink_encoder.c +++ /dev/null @@ -1,602 +0,0 @@ -#include -#include -#include -#include "heatshrink_encoder.h" - -typedef enum { - HSES_NOT_FULL, /* input buffer not full enough */ - HSES_FILLED, /* buffer is full */ - HSES_SEARCH, /* searching for patterns */ - HSES_YIELD_TAG_BIT, /* yield tag bit */ - HSES_YIELD_LITERAL, /* emit literal byte */ - HSES_YIELD_BR_INDEX, /* yielding backref index */ - HSES_YIELD_BR_LENGTH, /* yielding backref length */ - HSES_SAVE_BACKLOG, /* copying buffer to backlog */ - HSES_FLUSH_BITS, /* flush bit buffer */ - HSES_DONE, /* done */ -} HSE_state; - -#if HEATSHRINK_DEBUGGING_LOGS -#include -#include -#include -#define LOG(...) fprintf(stderr, __VA_ARGS__) -#define ASSERT(X) assert(X) -static const char *state_names[] = { - "not_full", - "filled", - "search", - "yield_tag_bit", - "yield_literal", - "yield_br_index", - "yield_br_length", - "save_backlog", - "flush_bits", - "done", -}; -#else -#define LOG(...) /* no-op */ -#define ASSERT(X) /* no-op */ -#endif - -// Encoder flags -enum { - FLAG_IS_FINISHING = 0x01, -}; - -typedef struct { - uint8_t *buf; /* output buffer */ - size_t buf_size; /* buffer size */ - size_t *output_size; /* bytes pushed to buffer, so far */ -} output_info; - -#define MATCH_NOT_FOUND ((uint16_t)-1) - -static uint16_t get_input_offset(heatshrink_encoder *hse); -static uint16_t get_input_buffer_size(heatshrink_encoder *hse); -static uint16_t get_lookahead_size(heatshrink_encoder *hse); -static void add_tag_bit(heatshrink_encoder *hse, output_info *oi, uint8_t tag); -static int can_take_byte(output_info *oi); -static int is_finishing(heatshrink_encoder *hse); -static void save_backlog(heatshrink_encoder *hse); - -/* Push COUNT (max 8) bits to the output buffer, which has room. */ -static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits, - output_info *oi); -static uint8_t push_outgoing_bits(heatshrink_encoder *hse, output_info *oi); -static void push_literal_byte(heatshrink_encoder *hse, output_info *oi); - -#if HEATSHRINK_DYNAMIC_ALLOC -heatshrink_encoder *heatshrink_encoder_alloc(uint8_t* buffer, uint8_t window_sz2, - uint8_t lookahead_sz2) { - if ((window_sz2 < HEATSHRINK_MIN_WINDOW_BITS) || - (window_sz2 > HEATSHRINK_MAX_WINDOW_BITS) || - (lookahead_sz2 < HEATSHRINK_MIN_LOOKAHEAD_BITS) || - (lookahead_sz2 >= window_sz2)) { - return NULL; - } - - /* Note: 2 * the window size is used because the buffer needs to fit - * (1 << window_sz2) bytes for the current input, and an additional - * (1 << window_sz2) bytes for the previous buffer of input, which - * will be scanned for useful backreferences. */ - size_t buf_sz = (2 << window_sz2); - - heatshrink_encoder *hse = HEATSHRINK_MALLOC(sizeof(*hse)); - if (hse == NULL) { return NULL; } - hse->window_sz2 = window_sz2; - hse->lookahead_sz2 = lookahead_sz2; - hse->buffer = buffer; - heatshrink_encoder_reset(hse); - -#if HEATSHRINK_USE_INDEX - size_t index_sz = buf_sz*sizeof(uint16_t); - hse->search_index = HEATSHRINK_MALLOC(index_sz + sizeof(struct hs_index)); - if (hse->search_index == NULL) { - HEATSHRINK_FREE(hse, sizeof(*hse) + buf_sz); - return NULL; - } - hse->search_index->size = index_sz; -#endif - - LOG("-- allocated encoder with buffer size of %zu (%u byte input size)\n", - buf_sz, get_input_buffer_size(hse)); - return hse; -} - -void heatshrink_encoder_free(heatshrink_encoder *hse) { -#if HEATSHRINK_USE_INDEX - size_t index_sz = sizeof(struct hs_index) + hse->search_index->size; - HEATSHRINK_FREE(hse->search_index, index_sz); - (void)index_sz; -#endif - HEATSHRINK_FREE(hse, sizeof(heatshrink_encoder)); -} -#endif - -void heatshrink_encoder_reset(heatshrink_encoder *hse) { - hse->input_size = 0; - hse->state = HSES_NOT_FULL; - hse->match_scan_index = 0; - hse->flags = 0; - hse->bit_index = 0x80; - hse->current_byte = 0x00; - hse->match_length = 0; - - hse->outgoing_bits = 0x0000; - hse->outgoing_bits_count = 0; - - #ifdef LOOP_DETECT - hse->loop_detect = (uint32_t)-1; - #endif -} - -HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, - uint8_t *in_buf, size_t size, size_t *input_size) { - if ((hse == NULL) || (in_buf == NULL) || (input_size == NULL)) { - return HSER_SINK_ERROR_NULL; - } - - /* Sinking more content after saying the content is done, tsk tsk */ - if (is_finishing(hse)) { return HSER_SINK_ERROR_MISUSE; } - - /* Sinking more content before processing is done */ - if (hse->state != HSES_NOT_FULL) { return HSER_SINK_ERROR_MISUSE; } - - uint16_t write_offset = get_input_offset(hse) + hse->input_size; - uint16_t ibs = get_input_buffer_size(hse); - uint16_t rem = ibs - hse->input_size; - uint16_t cp_sz = rem < size ? rem : size; - - memcpy(&hse->buffer[write_offset], in_buf, cp_sz); - *input_size = cp_sz; - hse->input_size += cp_sz; - - LOG("-- sunk %u bytes (of %zu) into encoder at %d, input buffer now has %u\n", - cp_sz, size, write_offset, hse->input_size); - if (cp_sz == rem) { - LOG("-- internal buffer is now full\n"); - hse->state = HSES_FILLED; - } - - return HSER_SINK_OK; -} - - -/*************** - * Compression * - ***************/ - -static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, - uint16_t end, const uint16_t maxlen, uint16_t *match_length); -static void do_indexing(heatshrink_encoder *hse); - -static HSE_state st_step_search(heatshrink_encoder *hse); -static HSE_state st_yield_tag_bit(heatshrink_encoder *hse, - output_info *oi); -static HSE_state st_yield_literal(heatshrink_encoder *hse, - output_info *oi); -static HSE_state st_yield_br_index(heatshrink_encoder *hse, - output_info *oi); -static HSE_state st_yield_br_length(heatshrink_encoder *hse, - output_info *oi); -static HSE_state st_save_backlog(heatshrink_encoder *hse); -static HSE_state st_flush_bit_buffer(heatshrink_encoder *hse, - output_info *oi); - -HSE_poll_res heatshrink_encoder_poll(heatshrink_encoder *hse, - uint8_t *out_buf, size_t out_buf_size, size_t *output_size) { - if ((hse == NULL) || (out_buf == NULL) || (output_size == NULL)) { - return HSER_POLL_ERROR_NULL; - } - if (out_buf_size == 0) { - LOG("-- MISUSE: output buffer size is 0\n"); - return HSER_POLL_ERROR_MISUSE; - } - *output_size = 0; - - output_info oi; - oi.buf = out_buf; - oi.buf_size = out_buf_size; - oi.output_size = output_size; - - while (1) { - LOG("-- polling, state %u (%s), flags 0x%02x\n", - hse->state, state_names[hse->state], hse->flags); - - uint8_t in_state = hse->state; - switch (in_state) { - case HSES_NOT_FULL: - return HSER_POLL_EMPTY; - case HSES_FILLED: - do_indexing(hse); - hse->state = HSES_SEARCH; - break; - case HSES_SEARCH: - hse->state = st_step_search(hse); - break; - case HSES_YIELD_TAG_BIT: - hse->state = st_yield_tag_bit(hse, &oi); - break; - case HSES_YIELD_LITERAL: - hse->state = st_yield_literal(hse, &oi); - break; - case HSES_YIELD_BR_INDEX: - hse->state = st_yield_br_index(hse, &oi); - break; - case HSES_YIELD_BR_LENGTH: - hse->state = st_yield_br_length(hse, &oi); - break; - case HSES_SAVE_BACKLOG: - hse->state = st_save_backlog(hse); - break; - case HSES_FLUSH_BITS: - hse->state = st_flush_bit_buffer(hse, &oi); - /* fall through */ - case HSES_DONE: - return HSER_POLL_EMPTY; - default: - LOG("-- bad state %s\n", state_names[hse->state]); - return HSER_POLL_ERROR_MISUSE; - } - - if (hse->state == in_state) { - /* Check if output buffer is exhausted. */ - if (*output_size == out_buf_size) return HSER_POLL_MORE; - } - } -} - -HSE_finish_res heatshrink_encoder_finish(heatshrink_encoder *hse) { - if (hse == NULL) { return HSER_FINISH_ERROR_NULL; } - LOG("-- setting is_finishing flag\n"); - hse->flags |= FLAG_IS_FINISHING; - if (hse->state == HSES_NOT_FULL) { hse->state = HSES_FILLED; } - return hse->state == HSES_DONE ? HSER_FINISH_DONE : HSER_FINISH_MORE; -} - -static HSE_state st_step_search(heatshrink_encoder *hse) { - uint16_t window_length = get_input_buffer_size(hse); - uint16_t lookahead_sz = get_lookahead_size(hse); - uint16_t msi = hse->match_scan_index; - LOG("## step_search, scan @ +%d (%d/%d), input size %d\n", - msi, hse->input_size + msi, 2*window_length, hse->input_size); - - bool fin = is_finishing(hse); - if (msi > hse->input_size - (fin ? 1 : lookahead_sz)) { - /* Current search buffer is exhausted, copy it into the - * backlog and await more input. */ - LOG("-- end of search @ %d\n", msi); - return fin ? HSES_FLUSH_BITS : HSES_SAVE_BACKLOG; - } - - uint16_t input_offset = get_input_offset(hse); - uint16_t end = input_offset + msi; - uint16_t start = end - window_length; - - uint16_t max_possible = lookahead_sz; - if (hse->input_size - msi < lookahead_sz) { - max_possible = hse->input_size - msi; - } - - uint16_t match_length = 0; - uint16_t match_pos = find_longest_match(hse, - start, end, max_possible, &match_length); - - if (match_pos == MATCH_NOT_FOUND) { - LOG("ss Match not found\n"); - hse->match_scan_index++; - hse->match_length = 0; - return HSES_YIELD_TAG_BIT; - } else { - LOG("ss Found match of %d bytes at %d\n", match_length, match_pos); - hse->match_pos = match_pos; - hse->match_length = match_length; - ASSERT(match_pos <= 1 << HEATSHRINK_ENCODER_WINDOW_BITS(hse) /*window_length*/); - - return HSES_YIELD_TAG_BIT; - } -} - -static HSE_state st_yield_tag_bit(heatshrink_encoder *hse, - output_info *oi) { - if (can_take_byte(oi)) { - if (hse->match_length == 0) { - add_tag_bit(hse, oi, HEATSHRINK_LITERAL_MARKER); - return HSES_YIELD_LITERAL; - } else { - add_tag_bit(hse, oi, HEATSHRINK_BACKREF_MARKER); - hse->outgoing_bits = hse->match_pos - 1; - hse->outgoing_bits_count = HEATSHRINK_ENCODER_WINDOW_BITS(hse); - return HSES_YIELD_BR_INDEX; - } - } else { - return HSES_YIELD_TAG_BIT; /* output is full, continue */ - } -} - -static HSE_state st_yield_literal(heatshrink_encoder *hse, - output_info *oi) { - if (can_take_byte(oi)) { - push_literal_byte(hse, oi); - return HSES_SEARCH; - } else { - return HSES_YIELD_LITERAL; - } -} - -static HSE_state st_yield_br_index(heatshrink_encoder *hse, - output_info *oi) { - if (can_take_byte(oi)) { - LOG("-- yielding backref index %u\n", hse->match_pos); - if (push_outgoing_bits(hse, oi) > 0) { - return HSES_YIELD_BR_INDEX; /* continue */ - } else { - hse->outgoing_bits = hse->match_length - 1; - hse->outgoing_bits_count = HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse); - return HSES_YIELD_BR_LENGTH; /* done */ - } - } else { - return HSES_YIELD_BR_INDEX; /* continue */ - } -} - -static HSE_state st_yield_br_length(heatshrink_encoder *hse, - output_info *oi) { - if (can_take_byte(oi)) { - LOG("-- yielding backref length %u\n", hse->match_length); - if (push_outgoing_bits(hse, oi) > 0) { - return HSES_YIELD_BR_LENGTH; - } else { - hse->match_scan_index += hse->match_length; - hse->match_length = 0; - return HSES_SEARCH; - } - } else { - return HSES_YIELD_BR_LENGTH; - } -} - -static HSE_state st_save_backlog(heatshrink_encoder *hse) { - LOG("-- saving backlog\n"); - save_backlog(hse); - return HSES_NOT_FULL; -} - -static HSE_state st_flush_bit_buffer(heatshrink_encoder *hse, - output_info *oi) { - if (hse->bit_index == 0x80) { - LOG("-- done!\n"); - return HSES_DONE; - } else if (can_take_byte(oi)) { - LOG("-- flushing remaining byte (bit_index == 0x%02x)\n", hse->bit_index); - oi->buf[(*oi->output_size)++] = hse->current_byte; - LOG("-- done!\n"); - return HSES_DONE; - } else { - return HSES_FLUSH_BITS; - } -} - -static void add_tag_bit(heatshrink_encoder *hse, output_info *oi, uint8_t tag) { - LOG("-- adding tag bit: %d\n", tag); - push_bits(hse, 1, tag, oi); -} - -static uint16_t get_input_offset(heatshrink_encoder *hse) { - return get_input_buffer_size(hse); -} - -static uint16_t get_input_buffer_size(heatshrink_encoder *hse) { - return (1 << HEATSHRINK_ENCODER_WINDOW_BITS(hse)); - (void)hse; -} - -static uint16_t get_lookahead_size(heatshrink_encoder *hse) { - return (1 << HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse)); - (void)hse; -} - -static void do_indexing(heatshrink_encoder *hse) { -#if HEATSHRINK_USE_INDEX - /* Build an index array I that contains flattened linked lists - * for the previous instances of every byte in the buffer. - * - * For example, if buf[200] == 'x', then index[200] will either - * be an offset i such that buf[i] == 'x', or a negative offset - * to indicate end-of-list. This significantly speeds up matching, - * while only using sizeof(uint16_t)*sizeof(buffer) bytes of RAM. - * - * Future optimization options: - * 1. Since any negative value represents end-of-list, the other - * 15 bits could be used to improve the index dynamically. - * - * 2. Likewise, the last lookahead_sz bytes of the index will - * not be usable, so temporary data could be stored there to - * dynamically improve the index. - * */ - struct hs_index *hsi = HEATSHRINK_ENCODER_INDEX(hse); - int16_t last[256]; - memset(last, 0xFF, sizeof(last)); - - uint8_t * const data = hse->buffer; - int16_t * const index = hsi->index; - - const uint16_t input_offset = get_input_offset(hse); - const uint16_t end = input_offset + hse->input_size; - - for (uint16_t i=0; iflags & FLAG_IS_FINISHING; -} - -static int can_take_byte(output_info *oi) { - return *oi->output_size < oi->buf_size; -} - -/* Return the longest match for the bytes at buf[end:end+maxlen] between - * buf[start] and buf[end-1]. If no match is found, return -1. */ -static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, - uint16_t end, const uint16_t maxlen, uint16_t *match_length) { - LOG("-- scanning for match of buf[%u:%u] between buf[%u:%u] (max %u bytes)\n", - end, end + maxlen, start, end + maxlen - 1, maxlen); - uint8_t *buf = hse->buffer; - - uint16_t match_maxlen = 0; - uint16_t match_index = MATCH_NOT_FOUND; - - uint16_t len = 0; - uint8_t * const needlepoint = &buf[end]; -#if HEATSHRINK_USE_INDEX - struct hs_index *hsi = HEATSHRINK_ENCODER_INDEX(hse); - int16_t pos = hsi->index[end]; - - while (pos - (int16_t)start >= 0) { - uint8_t * const pospoint = &buf[pos]; - len = 0; - - /* Only check matches that will potentially beat the current maxlen. - * This is redundant with the index if match_maxlen is 0, but the - * added branch overhead to check if it == 0 seems to be worse. */ - if (pospoint[match_maxlen] != needlepoint[match_maxlen]) { - pos = hsi->index[pos]; - continue; - } - - for (len = 1; len < maxlen; len++) { - if (pospoint[len] != needlepoint[len]) break; - } - - if (len > match_maxlen) { - match_maxlen = len; - match_index = pos; - if (len == maxlen) { break; } /* won't find better */ - } - pos = hsi->index[pos]; - } -#else - for (int16_t pos=end - 1; pos - (int16_t)start >= 0; pos--) { - uint8_t * const pospoint = &buf[pos]; - if ((pospoint[match_maxlen] == needlepoint[match_maxlen]) - && (*pospoint == *needlepoint)) { - for (len=1; len cmp buf[%d] == 0x%02x against %02x (start %u)\n", - pos + len, pospoint[len], needlepoint[len], start); - } - if (pospoint[len] != needlepoint[len]) { break; } - } - if (len > match_maxlen) { - match_maxlen = len; - match_index = pos; - if (len == maxlen) { break; } /* don't keep searching */ - } - } - } -#endif - - const size_t break_even_point = - (1 + HEATSHRINK_ENCODER_WINDOW_BITS(hse) + - HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse)); - - /* Instead of comparing break_even_point against 8*match_maxlen, - * compare match_maxlen against break_even_point/8 to avoid - * overflow. Since MIN_WINDOW_BITS and MIN_LOOKAHEAD_BITS are 4 and - * 3, respectively, break_even_point/8 will always be at least 1. */ - if (match_maxlen > (break_even_point / 8)) { - LOG("-- best match: %u bytes at -%u\n", - match_maxlen, end - match_index); - *match_length = match_maxlen; - return end - match_index; - } - LOG("-- none found\n"); - return MATCH_NOT_FOUND; -} - -static uint8_t push_outgoing_bits(heatshrink_encoder *hse, output_info *oi) { - uint8_t count = 0; - uint8_t bits = 0; - if (hse->outgoing_bits_count > 8) { - count = 8; - bits = hse->outgoing_bits >> (hse->outgoing_bits_count - 8); - } else { - count = hse->outgoing_bits_count; - bits = hse->outgoing_bits; - } - - if (count > 0) { - LOG("-- pushing %d outgoing bits: 0x%02x\n", count, bits); - push_bits(hse, count, bits, oi); - hse->outgoing_bits_count -= count; - } - return count; -} - -/* Push COUNT (max 8) bits to the output buffer, which has room. - * Bytes are set from the lowest bits, up. */ -static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits, - output_info *oi) { - ASSERT(count <= 8); - LOG("++ push_bits: %d bits, input of 0x%02x\n", count, bits); - - /* If adding a whole byte and at the start of a new output byte, - * just push it through whole and skip the bit IO loop. */ - if (count == 8 && hse->bit_index == 0x80) { - oi->buf[(*oi->output_size)++] = bits; - } else { - for (int i=count - 1; i>=0; i--) { - bool bit = bits & (1 << i); - if (bit) { hse->current_byte |= hse->bit_index; } - if (0) { - LOG(" -- setting bit %d at bit index 0x%02x, byte => 0x%02x\n", - bit ? 1 : 0, hse->bit_index, hse->current_byte); - } - hse->bit_index >>= 1; - if (hse->bit_index == 0x00) { - hse->bit_index = 0x80; - LOG(" > pushing byte 0x%02x\n", hse->current_byte); - oi->buf[(*oi->output_size)++] = hse->current_byte; - hse->current_byte = 0x00; - } - } - } -} - -static void push_literal_byte(heatshrink_encoder *hse, output_info *oi) { - uint16_t processed_offset = hse->match_scan_index - 1; - uint16_t input_offset = get_input_offset(hse) + processed_offset; - uint8_t c = hse->buffer[input_offset]; - LOG("-- yielded literal byte 0x%02x ('%c') from +%d\n", - c, isprint(c) ? c : '.', input_offset); - push_bits(hse, 8, c, oi); -} - -static void save_backlog(heatshrink_encoder *hse) { - size_t input_buf_sz = get_input_buffer_size(hse); - - uint16_t msi = hse->match_scan_index; - - /* Copy processed data to beginning of buffer, so it can be - * used for future matches. Don't bother checking whether the - * input is less than the maximum size, because if it isn't, - * we're done anyway. */ - uint16_t rem = input_buf_sz - msi; // unprocessed bytes - uint16_t shift_sz = input_buf_sz + rem; - - memmove(&hse->buffer[0], - &hse->buffer[input_buf_sz - rem], - shift_sz); - - hse->match_scan_index = 0; - hse->input_size -= input_buf_sz - rem; -} diff --git a/lib/heatshrink/heatshrink_encoder.h b/lib/heatshrink/heatshrink_encoder.h deleted file mode 100644 index e2ccb44c7c..0000000000 --- a/lib/heatshrink/heatshrink_encoder.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef HEATSHRINK_ENCODER_H -#define HEATSHRINK_ENCODER_H - -#include -#include -#include "heatshrink_common.h" -#include "heatshrink_config.h" - -typedef enum { - HSER_SINK_OK, /* data sunk into input buffer */ - HSER_SINK_ERROR_NULL=-1, /* NULL argument */ - HSER_SINK_ERROR_MISUSE=-2, /* API misuse */ -} HSE_sink_res; - -typedef enum { - HSER_POLL_EMPTY, /* input exhausted */ - HSER_POLL_MORE, /* poll again for more output */ - HSER_POLL_ERROR_NULL=-1, /* NULL argument */ - HSER_POLL_ERROR_MISUSE=-2, /* API misuse */ -} HSE_poll_res; - -typedef enum { - HSER_FINISH_DONE, /* encoding is complete */ - HSER_FINISH_MORE, /* more output remaining; use poll */ - HSER_FINISH_ERROR_NULL=-1, /* NULL argument */ -} HSE_finish_res; - -#if HEATSHRINK_DYNAMIC_ALLOC -#define HEATSHRINK_ENCODER_WINDOW_BITS(HSE) \ - ((HSE)->window_sz2) -#define HEATSHRINK_ENCODER_LOOKAHEAD_BITS(HSE) \ - ((HSE)->lookahead_sz2) -#define HEATSHRINK_ENCODER_INDEX(HSE) \ - ((HSE)->search_index) -struct hs_index { - uint16_t size; - int16_t index[]; -}; -#else -#define HEATSHRINK_ENCODER_WINDOW_BITS(_) \ - (HEATSHRINK_STATIC_WINDOW_BITS) -#define HEATSHRINK_ENCODER_LOOKAHEAD_BITS(_) \ - (HEATSHRINK_STATIC_LOOKAHEAD_BITS) -#define HEATSHRINK_ENCODER_INDEX(HSE) \ - (&(HSE)->search_index) -struct hs_index { - uint16_t size; - int16_t index[2 << HEATSHRINK_STATIC_WINDOW_BITS]; -}; -#endif - -typedef struct { - uint16_t input_size; /* bytes in input buffer */ - uint16_t match_scan_index; - uint16_t match_length; - uint16_t match_pos; - uint16_t outgoing_bits; /* enqueued outgoing bits */ - uint8_t outgoing_bits_count; - uint8_t flags; - uint8_t state; /* current state machine node */ - uint8_t current_byte; /* current byte of output */ - uint8_t bit_index; /* current bit index */ -#if HEATSHRINK_DYNAMIC_ALLOC - uint8_t window_sz2; /* 2^n size of window */ - uint8_t lookahead_sz2; /* 2^n size of lookahead */ -#if HEATSHRINK_USE_INDEX - struct hs_index *search_index; -#endif - /* input buffer and / sliding window for expansion */ - uint8_t* buffer; -#else - #if HEATSHRINK_USE_INDEX - struct hs_index search_index; - #endif - /* input buffer and / sliding window for expansion */ - uint8_t buffer[2 << HEATSHRINK_ENCODER_WINDOW_BITS(_)]; -#endif -} heatshrink_encoder; - -#if HEATSHRINK_DYNAMIC_ALLOC -/* Allocate a new encoder struct and its buffers. - * Returns NULL on error. */ -heatshrink_encoder *heatshrink_encoder_alloc(uint8_t* buffer, uint8_t window_sz2, - uint8_t lookahead_sz2); - -/* Free an encoder. */ -void heatshrink_encoder_free(heatshrink_encoder *hse); -#endif - -/* Reset an encoder. */ -void heatshrink_encoder_reset(heatshrink_encoder *hse); - -/* Sink up to SIZE bytes from IN_BUF into the encoder. - * INPUT_SIZE is set to the number of bytes actually sunk (in case a - * buffer was filled.). */ -HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, - uint8_t *in_buf, size_t size, size_t *input_size); - -/* Poll for output from the encoder, copying at most OUT_BUF_SIZE bytes into - * OUT_BUF (setting *OUTPUT_SIZE to the actual amount copied). */ -HSE_poll_res heatshrink_encoder_poll(heatshrink_encoder *hse, - uint8_t *out_buf, size_t out_buf_size, size_t *output_size); - -/* Notify the encoder that the input stream is finished. - * If the return value is HSER_FINISH_MORE, there is still more output, so - * call heatshrink_encoder_poll and repeat. */ -HSE_finish_res heatshrink_encoder_finish(heatshrink_encoder *hse); - -#endif diff --git a/lib/misc.scons b/lib/misc.scons index 49b6b61d97..b479851b12 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -36,7 +36,6 @@ for lib in libs_recurse: sources += libenv.GlobRecursive("*.c*", lib) libs_plain = [ - "heatshrink", "nanopb", ] @@ -47,6 +46,12 @@ for lib in libs_plain: source=True, ) +sources += Glob( + "heatshrink/heatshrink_*.c*", + exclude=GLOB_FILE_EXCLUSION, + source=True, +) + lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/firmware/targets/f7/furi_hal/furi_hal_compress.c b/lib/toolbox/compress.c similarity index 67% rename from firmware/targets/f7/furi_hal/furi_hal_compress.c rename to lib/toolbox/compress.c index 7e31dbbf7f..0d5e1c654d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_compress.c +++ b/lib/toolbox/compress.c @@ -1,115 +1,112 @@ -#include +#include "compress.h" #include #include #include -#define TAG "FuriHalCompress" +/** Defines encoder and decoder window size */ +#define COMPRESS_EXP_BUFF_SIZE_LOG (8u) -#define FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE (2 * 512) -#define FURI_HAL_COMPRESS_ICON_DECODED_BUFF_SIZE (1024) +/** Defines encoder and decoder lookahead buffer size */ +#define COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG (4u) -#define FURI_HAL_COMPRESS_EXP_BUFF_SIZE (1 << FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG) +/** Buffer sizes for input and output data */ +#define COMPRESS_ICON_ENCODED_BUFF_SIZE (1024u) +#define COMPRESS_ICON_DECODED_BUFF_SIZE (1024u) typedef struct { uint8_t is_compressed; uint8_t reserved; uint16_t compressed_buff_size; -} FuriHalCompressHeader; +} CompressHeader; -typedef struct { - heatshrink_decoder* decoder; - uint8_t - compress_buff[FURI_HAL_COMPRESS_EXP_BUFF_SIZE + FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE]; - uint8_t decoded_buff[FURI_HAL_COMPRESS_ICON_DECODED_BUFF_SIZE]; -} FuriHalCompressIcon; +_Static_assert(sizeof(CompressHeader) == 4, "Incorrect CompressHeader size"); -struct FuriHalCompress { - heatshrink_encoder* encoder; +struct CompressIcon { heatshrink_decoder* decoder; - uint8_t* compress_buff; - uint16_t compress_buff_size; + uint8_t decoded_buff[COMPRESS_ICON_DECODED_BUFF_SIZE]; }; -static FuriHalCompressIcon* icon_decoder; +CompressIcon* compress_icon_alloc() { + CompressIcon* instance = malloc(sizeof(CompressIcon)); + instance->decoder = heatshrink_decoder_alloc( + COMPRESS_ICON_ENCODED_BUFF_SIZE, + COMPRESS_EXP_BUFF_SIZE_LOG, + COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG); + heatshrink_decoder_reset(instance->decoder); + memset(instance->decoded_buff, 0, sizeof(instance->decoded_buff)); -static void furi_hal_compress_reset(FuriHalCompress* compress) { - furi_assert(compress); - heatshrink_encoder_reset(compress->encoder); - heatshrink_decoder_reset(compress->decoder); - memset(compress->compress_buff, 0, compress->compress_buff_size); + return instance; } -void furi_hal_compress_icon_init() { - icon_decoder = malloc(sizeof(FuriHalCompressIcon)); - icon_decoder->decoder = heatshrink_decoder_alloc( - icon_decoder->compress_buff, - FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE, - FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG, - FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG); - heatshrink_decoder_reset(icon_decoder->decoder); - memset(icon_decoder->decoded_buff, 0, sizeof(icon_decoder->decoded_buff)); - FURI_LOG_I(TAG, "Init OK"); +void compress_icon_free(CompressIcon* instance) { + furi_assert(instance); + heatshrink_decoder_free(instance->decoder); + free(instance); } -void furi_hal_compress_icon_decode(const uint8_t* icon_data, uint8_t** decoded_buff) { +void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** decoded_buff) { + furi_assert(instance); furi_assert(icon_data); furi_assert(decoded_buff); - FuriHalCompressHeader* header = (FuriHalCompressHeader*)icon_data; + CompressHeader* header = (CompressHeader*)icon_data; if(header->is_compressed) { size_t data_processed = 0; heatshrink_decoder_sink( - icon_decoder->decoder, - (uint8_t*)&icon_data[4], + instance->decoder, + (uint8_t*)&icon_data[sizeof(CompressHeader)], header->compressed_buff_size, &data_processed); while(1) { HSD_poll_res res = heatshrink_decoder_poll( - icon_decoder->decoder, - icon_decoder->decoded_buff, - sizeof(icon_decoder->decoded_buff), + instance->decoder, + instance->decoded_buff, + sizeof(instance->decoded_buff), &data_processed); furi_assert((res == HSDR_POLL_EMPTY) || (res == HSDR_POLL_MORE)); if(res != HSDR_POLL_MORE) { break; } } - heatshrink_decoder_reset(icon_decoder->decoder); - memset(icon_decoder->compress_buff, 0, sizeof(icon_decoder->compress_buff)); - *decoded_buff = icon_decoder->decoded_buff; + heatshrink_decoder_reset(instance->decoder); + *decoded_buff = instance->decoded_buff; } else { *decoded_buff = (uint8_t*)&icon_data[1]; } } -FuriHalCompress* furi_hal_compress_alloc(uint16_t compress_buff_size) { - FuriHalCompress* compress = malloc(sizeof(FuriHalCompress)); - compress->compress_buff = malloc(compress_buff_size + FURI_HAL_COMPRESS_EXP_BUFF_SIZE); - compress->encoder = heatshrink_encoder_alloc( - compress->compress_buff, - FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG, - FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG); +struct Compress { + heatshrink_encoder* encoder; + heatshrink_decoder* decoder; +}; + +static void compress_reset(Compress* compress) { + furi_assert(compress); + heatshrink_encoder_reset(compress->encoder); + heatshrink_decoder_reset(compress->decoder); +} + +Compress* compress_alloc(uint16_t compress_buff_size) { + Compress* compress = malloc(sizeof(Compress)); + compress->encoder = + heatshrink_encoder_alloc(COMPRESS_EXP_BUFF_SIZE_LOG, COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG); compress->decoder = heatshrink_decoder_alloc( - compress->compress_buff, - compress_buff_size, - FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG, - FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG); + compress_buff_size, COMPRESS_EXP_BUFF_SIZE_LOG, COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG); return compress; } -void furi_hal_compress_free(FuriHalCompress* compress) { +void compress_free(Compress* compress) { furi_assert(compress); heatshrink_encoder_free(compress->encoder); heatshrink_decoder_free(compress->decoder); - free(compress->compress_buff); free(compress); } -bool furi_hal_compress_encode( - FuriHalCompress* compress, +bool compress_encode( + Compress* compress, uint8_t* data_in, size_t data_in_size, uint8_t* data_out, @@ -126,7 +123,7 @@ bool furi_hal_compress_encode( HSE_finish_res finish_res; bool encode_failed = false; size_t sunk = 0; - size_t res_buff_size = sizeof(FuriHalCompressHeader); + size_t res_buff_size = sizeof(CompressHeader); // Sink data to encoding buffer while((sunk < data_in_size) && !encode_failed) { @@ -174,7 +171,7 @@ bool furi_hal_compress_encode( bool result = true; // Write encoded data to output buffer if compression is efficient. Else - write header and original data if(!encode_failed && (res_buff_size < data_in_size + 1)) { - FuriHalCompressHeader header = { + CompressHeader header = { .is_compressed = 0x01, .reserved = 0x00, .compressed_buff_size = res_buff_size}; memcpy(data_out, &header, sizeof(header)); *data_res_size = res_buff_size; @@ -186,13 +183,13 @@ bool furi_hal_compress_encode( *data_res_size = 0; result = false; } - furi_hal_compress_reset(compress); + compress_reset(compress); return result; } -bool furi_hal_compress_decode( - FuriHalCompress* compress, +bool compress_decode( + Compress* compress, uint8_t* data_in, size_t data_in_size, uint8_t* data_out, @@ -212,11 +209,11 @@ bool furi_hal_compress_decode( size_t res_buff_size = 0; size_t poll_size = 0; - FuriHalCompressHeader* header = (FuriHalCompressHeader*)data_in; + CompressHeader* header = (CompressHeader*)data_in; if(header->is_compressed) { // Sink data to decoding buffer size_t compressed_size = header->compressed_buff_size; - size_t sunk = sizeof(FuriHalCompressHeader); + size_t sunk = sizeof(CompressHeader); while(sunk < compressed_size && !decode_failed) { sink_res = heatshrink_decoder_sink( compress->decoder, &data_in[sunk], compressed_size - sunk, &sink_size); @@ -258,7 +255,7 @@ bool furi_hal_compress_decode( } else { result = false; } - furi_hal_compress_reset(compress); + compress_reset(compress); return result; } diff --git a/lib/toolbox/compress.h b/lib/toolbox/compress.h new file mode 100644 index 0000000000..a18551d7f9 --- /dev/null +++ b/lib/toolbox/compress.h @@ -0,0 +1,96 @@ +/** + * @file compress.h + * LZSS based compression HAL API + */ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Compress Icon control structure */ +typedef struct CompressIcon CompressIcon; + +/** Initialize icon compressor + * + * @return Compress Icon instance + */ +CompressIcon* compress_icon_alloc(); + +/** Free icon compressor + * + * @param instance The Compress Icon instance + */ +void compress_icon_free(CompressIcon* instance); + +/** Decompress icon + * + * @warning decoded_buff pointer set by this function is valid till next + * `compress_icon_decode` or `compress_icon_free` call + * + * @param instance The Compress Icon instance + * @param icon_data pointer to icon data + * @param[in] decoded_buff pointer to decoded buffer pointer + */ +void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** decoded_buff); + +/** Compress control structure */ +typedef struct Compress Compress; + +/** Allocate encoder and decoder + * + * @param compress_buff_size size of decoder and encoder buffer to allocate + * + * @return Compress instance + */ +Compress* compress_alloc(uint16_t compress_buff_size); + +/** Free encoder and decoder + * + * @param compress Compress instance + */ +void compress_free(Compress* compress); + +/** Encode data + * + * @param compress Compress instance + * @param data_in pointer to input data + * @param data_in_size size of input data + * @param data_out maximum size of output data + * @param data_res_size pointer to result output data size + * + * @return true on success + */ +bool compress_encode( + Compress* compress, + uint8_t* data_in, + size_t data_in_size, + uint8_t* data_out, + size_t data_out_size, + size_t* data_res_size); + +/** Decode data + * + * @param compress Compress instance + * @param data_in pointer to input data + * @param data_in_size size of input data + * @param data_out maximum size of output data + * @param data_res_size pointer to result output data size + * + * @return true on success + */ +bool compress_decode( + Compress* compress, + uint8_t* data_in, + size_t data_in_size, + uint8_t* data_out, + size_t data_out_size, + size_t* data_res_size); + +#ifdef __cplusplus +} +#endif From 8002c6465d5988682e5917ef2f37136f1ba9da88 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 22 Mar 2023 21:13:59 +0300 Subject: [PATCH 19/26] up --- assets/protobuf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/protobuf b/assets/protobuf index 1f6b4a08c5..6460660237 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 1f6b4a08c5d05c2b17926a3ba79f60109638932f +Subproject commit 6460660237005d02d5c223835659b40e373bade9 From 6057262c182a83bad4e45462cf3ff62690be3868 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 22 Mar 2023 21:15:45 +0300 Subject: [PATCH 20/26] update submodule --- assets/protobuf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/protobuf b/assets/protobuf index 6460660237..1f6b4a08c5 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 6460660237005d02d5c223835659b40e373bade9 +Subproject commit 1f6b4a08c5d05c2b17926a3ba79f60109638932f From 9165b819f4b077f7371a51b18b12ba13454fbf91 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 22 Mar 2023 22:04:04 +0300 Subject: [PATCH 21/26] fix merge issues --- applications/services/gui/canvas.c | 2 +- firmware/targets/f7/api_symbols.csv | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 26d061083c..2f3ca18f4e 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -390,7 +390,7 @@ void canvas_draw_icon_bitmap( x += canvas->offset_x; y += canvas->offset_y; uint8_t* icon_data = NULL; - furi_hal_compress_icon_decode(icon_get_data(icon), &icon_data); + compress_icon_decode(canvas->compress_icon, icon_get_data(icon), &icon_data); u8g2_DrawXBM(&canvas->fb, x, y, w, h, icon_data); } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index a044372cb0..a1830aba8e 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -706,6 +706,13 @@ Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiI Function,+,composite_api_resolver_alloc,CompositeApiResolver*, Function,+,composite_api_resolver_free,void,CompositeApiResolver* Function,+,composite_api_resolver_get,const ElfApiInterface*,CompositeApiResolver* +Function,-,compress_alloc,Compress*,uint16_t +Function,-,compress_decode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" +Function,-,compress_encode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" +Function,-,compress_free,void,Compress* +Function,-,compress_icon_alloc,CompressIcon*, +Function,-,compress_icon_decode,void,"CompressIcon*, const uint8_t*, uint8_t**" +Function,-,compress_icon_free,void,CompressIcon* Function,-,copysign,double,"double, double" Function,-,copysignf,float,"float, float" Function,-,copysignl,long double,"long double, long double" From 5ab574d7f2f856142f2476973fe5c13ec858b6b6 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 21 Mar 2023 00:03:03 +0000 Subject: [PATCH 22/26] Fap loader add option to ignore api mismatch --- applications/main/fap_loader/fap_loader_app.c | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c index f5c7af0248..d85eb784b6 100644 --- a/applications/main/fap_loader/fap_loader_app.c +++ b/applications/main/fap_loader/fap_loader_app.c @@ -63,7 +63,7 @@ static bool fap_loader_item_callback( return fap_loader_load_name_and_icon(path, fap_loader->storage, icon_ptr, item_name); } -static bool fap_loader_run_selected_app(FapLoader* loader) { +static bool fap_loader_run_selected_app(FapLoader* loader, bool ignore_mismatch) { furi_assert(loader); FuriString* error_message; @@ -72,6 +72,7 @@ static bool fap_loader_run_selected_app(FapLoader* loader) { bool file_selected = false; bool show_error = true; + bool retry = false; do { file_selected = true; loader->app = flipper_application_alloc(loader->storage, firmware_api_interface); @@ -82,14 +83,29 @@ static bool fap_loader_run_selected_app(FapLoader* loader) { FlipperApplicationPreloadStatus preload_res = flipper_application_preload(loader->app, furi_string_get_cstr(loader->fap_path)); if(preload_res != FlipperApplicationPreloadStatusSuccess) { - const char* err_msg = flipper_application_preload_status_to_string(preload_res); - furi_string_printf(error_message, "Preload failed: %s", err_msg); - FURI_LOG_E( - TAG, - "FAP Loader failed to preload %s: %s", - furi_string_get_cstr(loader->fap_path), - err_msg); - break; + if(preload_res == FlipperApplicationPreloadStatusApiMismatch) { + if(!ignore_mismatch) { + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "API Mismatch", 64, 0, AlignCenter, AlignTop); + dialog_message_set_buttons(message, "Cancel", NULL, "Continue"); + dialog_message_set_text(message, "This app might not\nwork correctly\nContinue anyways?", 64, 32, AlignCenter, AlignCenter); + if(dialog_message_show(loader->dialogs, message) == DialogMessageButtonRight) { + retry = true; + } + dialog_message_free(message); + show_error = false; + break; + } + } else { + const char* err_msg = flipper_application_preload_status_to_string(preload_res); + furi_string_printf(error_message, "Preload failed: %s", err_msg); + FURI_LOG_E( + TAG, + "FAP Loader failed to preload %s: %s", + furi_string_get_cstr(loader->fap_path), + err_msg); + break; + } } FURI_LOG_I(TAG, "FAP Loader is mapping"); @@ -155,7 +171,7 @@ static bool fap_loader_run_selected_app(FapLoader* loader) { flipper_application_free(loader->app); } - return file_selected; + return retry; } static bool fap_loader_select_app(FapLoader* loader) { @@ -203,12 +219,16 @@ int32_t fap_loader_app(void* p) { if(p) { loader = fap_loader_alloc((const char*)p); view_dispatcher_switch_to_view(loader->view_dispatcher, 0); - fap_loader_run_selected_app(loader); + if(fap_loader_run_selected_app(loader, false)) { + fap_loader_run_selected_app(loader, true); + } } else { loader = fap_loader_alloc(EXT_PATH("apps")); while(fap_loader_select_app(loader)) { view_dispatcher_switch_to_view(loader->view_dispatcher, 0); - fap_loader_run_selected_app(loader); + if(fap_loader_run_selected_app(loader, false)) { + fap_loader_run_selected_app(loader, true); + } }; } From 9a14699aa062590744acd8d3fb65476308c26a42 Mon Sep 17 00:00:00 2001 From: Shukai Ni Date: Wed, 22 Mar 2023 16:19:07 -0400 Subject: [PATCH 23/26] Fix relative links in .md files (#2528) Fixed some incorrect relative link, which caused 404 error when viewing in GitHub. --- documentation/UnitTests.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/UnitTests.md b/documentation/UnitTests.md index d38d4c4b19..4717daa8ca 100644 --- a/documentation/UnitTests.md +++ b/documentation/UnitTests.md @@ -17,11 +17,11 @@ To run the unit tests, follow these steps: 1. Compile the firmware with the tests enabled: `./fbt FIRMWARE_APP_SET=unit_tests`. 2. Flash the firmware using your preferred method. -3. Copy the [assets/unit_tests](assets/unit_tests) folder to the root of your Flipper Zero's SD card. +3. Copy the [assets/unit_tests](/assets/unit_tests) folder to the root of your Flipper Zero's SD card. 4. Launch the CLI session and run the `unit_tests` command. **NOTE:** To run a particular test (and skip all others), specify its name as the command argument. -See [test_index.c](applications/debug/unit_tests/test_index.c) for the complete list of test names. +See [test_index.c](/applications/debug/unit_tests/test_index.c) for the complete list of test names. ## Adding unit tests @@ -29,7 +29,7 @@ See [test_index.c](applications/debug/unit_tests/test_index.c) for the complete #### Entry point -The common entry point for all tests is the [unit_tests](applications/debug/unit_tests) application. Test-specific code is placed into an arbitrarily named subdirectory and is then called from the [test_index.c](applications/debug/unit_tests/test_index.c) source file. +The common entry point for all tests is the [unit_tests](/applications/debug/unit_tests) application. Test-specific code is placed into an arbitrarily named subdirectory and is then called from the [test_index.c](/applications/debug/unit_tests/test_index.c) source file. #### Test assets @@ -42,10 +42,10 @@ Some unit tests require external data in order to function. These files (commonl Each infrared protocol has a corresponding set of unit tests, so it makes sense to implement one when adding support for a new protocol. To add unit tests for your protocol, follow these steps: -1. Create a file named `test_.irtest` in the [assets](assets/unit_tests/infrared) directory. +1. Create a file named `test_.irtest` in the [assets](/assets/unit_tests/infrared) directory. 2. Fill it with the test data (more on it below). -3. Add the test code to [infrared_test.c](applications/debug/unit_tests/infrared/infrared_test.c). -4. Update the [assets](assets/unit_tests/infrared) on your Flipper Zero and run the tests to see if they pass. +3. Add the test code to [infrared_test.c](/applications/debug/unit_tests/infrared/infrared_test.c). +4. Update the [assets](/assets/unit_tests/infrared) on your Flipper Zero and run the tests to see if they pass. ##### Test data format From 4d7232d5edab8dbc7960b7ad5a75474588ec6fb3 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 22 Mar 2023 23:22:18 +0300 Subject: [PATCH 24/26] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af5fdf9668..2da161ed0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,15 @@ ### New changes * If you have copied apps into `apps` folder - remove `apps` folder on your microSD before installing this release to avoid issues! * Dev Builds: Add extra pack dev branch to avoid "bug" reports with `API mismatch` +* App Loader: Add option to ignore api mismatch (warning! some apps WILL not work, please update them to avoid any issues) -> (by @Willy-JL | PR #395) * SubGHz: Add manually -> GSN protocol support * SubGHz: Add 318 and 418 MHz back to hopping list * SubGHz: Fix hopper stuck at 433.42 due to wide range signals - When we using 433.92 remote flipper in hopping mode will stuck at 433.42 and may loose signal because of that, need to avoid using close freqs in hopping, only freqs with bigger difference like 310 -> 315 * Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -> BadBT Support +* OFW: Screen streaming improvements +* OFW: 1-Wire Overdrive Mode -> **Breaking API change, api was changed from 19.x to 20.x** +* OFW: Disable UART IRQs by default * OFW: BadUSB: implement boot protocol * OFW: Remove hmac_sha256 from public API -> **Breaking API change, api was changed from 18.x to 19.x** **(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** From 831999f5e116ee4f96a7c7a6a4df735fe7c0ba3b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 22 Mar 2023 23:52:34 +0300 Subject: [PATCH 25/26] Update extra pack links --- .drone.yml | 8 ++++---- CHANGELOG.md | 2 +- ReadMe.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index 03f678bd5b..26b8318288 100644 --- a/.drone.yml +++ b/.drone.yml @@ -40,7 +40,7 @@ steps: image: hfdj/fztools pull: never commands: - - git clone https://github.com/xMasterX/unleashed-extra-pack.git + - git clone https://github.com/xMasterX/all-the-plugins.git - cp -R unleashed-extra-pack/apps/* assets/resources/apps/ - rm -rf unleashed-extra-pack - export DIST_SUFFIX=${DRONE_TAG}e @@ -201,7 +201,7 @@ steps: [-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) - [-Download latest extra apps pack-](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip) + [-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) [-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=release-cfw&version=${DRONE_TAG}) @@ -223,7 +223,7 @@ steps: commands: - wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh" - chmod +x ./discord.sh - - ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)' + - ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)' - name: "Send extra pack build to telegram" image: appleboy/drone-telegram @@ -281,7 +281,7 @@ steps: image: hfdj/fztools pull: never commands: - - git clone --branch dev https://github.com/xMasterX/unleashed-extra-pack.git + - git clone --branch dev https://github.com/xMasterX/all-the-plugins.git - cp -R unleashed-extra-pack/apps/* assets/resources/apps/ - rm -rf unleashed-extra-pack - export DIST_SUFFIX=${DRONE_BUILD_NUMBER}e diff --git a/CHANGELOG.md b/CHANGELOG.md index 2da161ed0a..20dd09d503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ When we using 433.92 remote flipper in hopping mode will stuck at 433.42 and may * OFW: Remove hmac_sha256 from public API -> **Breaking API change, api was changed from 18.x to 19.x** **(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** -#### [🎲 Download latest extra apps pack](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip) +#### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) [-> How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) diff --git a/ReadMe.md b/ReadMe.md index 68c78239af..edaa9b1524 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -195,7 +195,7 @@ Games: ### **Plugins** -## [- 🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/unleashed-extra-pack) +## [- 🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/all-the-plugins) ## [- TOTP (Authenticator) config description](https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md) From 2ff07a0b54fcc085d188144a3c1568597d9214b5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 23 Mar 2023 00:06:45 +0300 Subject: [PATCH 26/26] fix folders --- .drone.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.drone.yml b/.drone.yml index 26b8318288..9b4765a8fb 100644 --- a/.drone.yml +++ b/.drone.yml @@ -41,8 +41,8 @@ steps: pull: never commands: - git clone https://github.com/xMasterX/all-the-plugins.git - - cp -R unleashed-extra-pack/apps/* assets/resources/apps/ - - rm -rf unleashed-extra-pack + - cp -R all-the-plugins/apps/* assets/resources/apps/ + - rm -rf all-the-plugins - export DIST_SUFFIX=${DRONE_TAG}e - export WORKFLOW_BRANCH_OR_TAG=release-cfw - export FORCE_NO_DIRTY=yes @@ -282,8 +282,8 @@ steps: pull: never commands: - git clone --branch dev https://github.com/xMasterX/all-the-plugins.git - - cp -R unleashed-extra-pack/apps/* assets/resources/apps/ - - rm -rf unleashed-extra-pack + - cp -R all-the-plugins/apps/* assets/resources/apps/ + - rm -rf all-the-plugins - export DIST_SUFFIX=${DRONE_BUILD_NUMBER}e - export WORKFLOW_BRANCH_OR_TAG=dev-cfw - export FORCE_NO_DIRTY=yes