From c741727b96cfecb067a82313586b8065077e37d8 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Tue, 5 Nov 2024 13:53:24 +0300 Subject: [PATCH 01/59] I am own the JS (#3982) * fix: js app template * i am own the js * farewell --- .github/CODEOWNERS | 10 +++++----- .../system/js_app/packages/create-fz-app/package.json | 2 +- .../packages/create-fz-app/template/tsconfig.json | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index aab3ff353..dcf964add 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -36,7 +36,7 @@ /applications/services/power_settings_app/ @skotopes @DrZlo13 @hedger @gsurkov @gornekich /applications/system/storage_move_to_sd/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov -/applications/system/js_app/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov +/applications/system/js_app/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov @portasynthinca3 /applications/debug/unit_tests/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov @gornekich @Astrrra @Skorpionm @@ -49,8 +49,8 @@ /applications/main/infrared/resources/ @skotopes @DrZlo13 @hedger @gsurkov # Documentation -/documentation/ @skotopes @DrZlo13 @hedger @gsurkov @drunkbatya -/scripts/toolchain/ @skotopes @DrZlo13 @hedger @gsurkov @drunkbatya +/documentation/ @skotopes @DrZlo13 @hedger @gsurkov +/scripts/toolchain/ @skotopes @DrZlo13 @hedger @gsurkov # Lib /lib/stm32wb_copro/ @skotopes @DrZlo13 @hedger @gsurkov @gornekich @@ -59,11 +59,11 @@ /lib/lfrfid/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov /lib/libusb_stm32/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov /lib/mbedtls/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov -/lib/mjs/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov +/lib/mjs/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov @portasynthinca3 /lib/nanopb/ @skotopes @DrZlo13 @hedger @gsurkov @nminaylov /lib/nfc/ @skotopes @DrZlo13 @hedger @gsurkov @gornekich @Astrrra /lib/one_wire/ @skotopes @DrZlo13 @hedger @gsurkov /lib/subghz/ @skotopes @DrZlo13 @hedger @gsurkov @Skorpionm # CI/CD -/.github/workflows/ @skotopes @DrZlo13 @hedger @gsurkov @drunkbatya +/.github/workflows/ @skotopes @DrZlo13 @hedger @gsurkov diff --git a/applications/system/js_app/packages/create-fz-app/package.json b/applications/system/js_app/packages/create-fz-app/package.json index 216423396..7778104e2 100644 --- a/applications/system/js_app/packages/create-fz-app/package.json +++ b/applications/system/js_app/packages/create-fz-app/package.json @@ -1,6 +1,6 @@ { "name": "@flipperdevices/create-fz-app", - "version": "0.1.0", + "version": "0.1.1", "description": "Template package for JS apps Flipper Zero", "bin": "index.js", "type": "module", diff --git a/applications/system/js_app/packages/create-fz-app/template/tsconfig.json b/applications/system/js_app/packages/create-fz-app/template/tsconfig.json index c7b83cd5d..1e6fc6018 100644 --- a/applications/system/js_app/packages/create-fz-app/template/tsconfig.json +++ b/applications/system/js_app/packages/create-fz-app/template/tsconfig.json @@ -5,13 +5,14 @@ "module": "CommonJS", "noLib": true, "target": "ES2015", + "types": [], }, "files": [ "./node_modules/@flipperdevices/fz-sdk/global.d.ts", ], "include": [ "./**/*.ts", - "./**/*.js" + "./**/*.js", ], "exclude": [ "./node_modules/**/*", From b86b9b87b8d5977bfd25c7ac344c4db9d63fb53f Mon Sep 17 00:00:00 2001 From: WillyJL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:41:03 +0000 Subject: [PATCH 02/59] JS: Add die() typedoc (#3985) * JS: Add die() to typedocs * JS: Never type for die() --------- Co-authored-by: Anna Antonenko --- applications/system/js_app/packages/fz-sdk/global.d.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/applications/system/js_app/packages/fz-sdk/global.d.ts b/applications/system/js_app/packages/fz-sdk/global.d.ts index d2e73f7de..ba6996f27 100644 --- a/applications/system/js_app/packages/fz-sdk/global.d.ts +++ b/applications/system/js_app/packages/fz-sdk/global.d.ts @@ -202,6 +202,13 @@ declare function chr(n: number): string | null; */ declare function require(module: string): any; +/** + * @brief Exit JavaScript with given message + * @param message The error message to show to user + * @version Added in JS SDK 0.1 + */ +declare function die(message: string): never; + /** * @brief mJS Foreign Pointer type * From 51aafd1b5ea1023616c88d2294ab411679ad8915 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Tue, 5 Nov 2024 14:58:19 +0300 Subject: [PATCH 03/59] fix: bump fz-sdk to 0.1.2 (#3989) --- applications/system/js_app/packages/fz-sdk/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/system/js_app/packages/fz-sdk/package.json b/applications/system/js_app/packages/fz-sdk/package.json index 4d18f3f20..3c2954c9c 100644 --- a/applications/system/js_app/packages/fz-sdk/package.json +++ b/applications/system/js_app/packages/fz-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@flipperdevices/fz-sdk", - "version": "0.1.1", + "version": "0.1.2", "description": "Type declarations and documentation for native JS modules available on Flipper Zero", "keywords": [ "flipper", From e3c3edcc7e3c8ffea3475aee62acd590fa9a92c4 Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Sun, 17 Nov 2024 21:01:15 +0000 Subject: [PATCH 04/59] Add send break support --- applications/main/gpio/usb_uart_bridge.c | 13 ++++++++++++- applications/services/cli/cli_vcp.c | 1 + targets/f18/api_symbols.csv | 3 ++- targets/f7/api_symbols.csv | 3 ++- targets/f7/furi_hal/furi_hal_serial.c | 10 ++++++++++ targets/f7/furi_hal/furi_hal_serial.h | 6 ++++++ targets/f7/furi_hal/furi_hal_usb_cdc.c | 13 ++++++++++--- targets/f7/furi_hal/furi_hal_usb_cdc.h | 1 + 8 files changed, 44 insertions(+), 6 deletions(-) diff --git a/applications/main/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c index f6e68b109..f3a9775a6 100644 --- a/applications/main/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -35,7 +35,7 @@ typedef enum { WorkerEvtLineCfgSet = (1 << 6), WorkerEvtCtrlLineSet = (1 << 7), - + WorkerEvtSendBreak = (1 << 8), } WorkerEvtFlags; #define WORKER_ALL_RX_EVENTS \ @@ -69,6 +69,7 @@ static void vcp_on_cdc_rx(void* context); static void vcp_state_callback(void* context, uint8_t state); static void vcp_on_cdc_control_line(void* context, uint8_t state); static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config); +static void vcp_on_cdc_break(void* context, uint16_t duration); static const CdcCallbacks cdc_cb = { vcp_on_cdc_tx_complete, @@ -76,6 +77,7 @@ static const CdcCallbacks cdc_cb = { vcp_state_callback, vcp_on_cdc_control_line, vcp_on_line_config, + vcp_on_cdc_break, }; /* USB UART worker */ @@ -287,6 +289,9 @@ static int32_t usb_uart_worker(void* context) { if(events & WorkerEvtCtrlLineSet) { usb_uart_update_ctrl_lines(usb_uart); } + if(events & WorkerEvtSendBreak) { + furi_hal_serial_send_break(usb_uart->serial_handle); + } } usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); usb_uart_serial_deinit(usb_uart); @@ -377,6 +382,12 @@ static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtLineCfgSet); } +static void vcp_on_cdc_break(void* context, uint16_t duration) { + UNUSED(duration); + UsbUartBridge* usb_uart = (UsbUartBridge*)context; + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtSendBreak); +} + UsbUartBridge* usb_uart_enable(UsbUartConfig* cfg) { UsbUartBridge* usb_uart = malloc(sizeof(UsbUartBridge)); diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index cdabaaa05..83f4f8214 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -57,6 +57,7 @@ static CdcCallbacks cdc_cb = { vcp_state_callback, vcp_on_cdc_control_line, NULL, + NULL, }; static CliVcp* vcp = NULL; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index b5d51a0dd..79610d0bb 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,78.1,, +Version,+,78.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -1446,6 +1446,7 @@ Function,+,furi_hal_serial_get_gpio_pin,const GpioPin*,"FuriHalSerialHandle*, Fu Function,+,furi_hal_serial_init,void,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_is_baud_rate_supported,_Bool,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_resume,void,FuriHalSerialHandle* +Function,+,furi_hal_serial_send_break,void,FuriHalSerialHandle* Function,+,furi_hal_serial_set_br,void,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_suspend,void,FuriHalSerialHandle* Function,+,furi_hal_serial_tx,void,"FuriHalSerialHandle*, const uint8_t*, size_t" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index ee81f76a9..7da0c727f 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,78.1,, +Version,+,78.2,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -1635,6 +1635,7 @@ Function,+,furi_hal_serial_get_gpio_pin,const GpioPin*,"FuriHalSerialHandle*, Fu Function,+,furi_hal_serial_init,void,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_is_baud_rate_supported,_Bool,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_resume,void,FuriHalSerialHandle* +Function,+,furi_hal_serial_send_break,void,FuriHalSerialHandle* Function,+,furi_hal_serial_set_br,void,"FuriHalSerialHandle*, uint32_t" Function,+,furi_hal_serial_suspend,void,FuriHalSerialHandle* Function,+,furi_hal_serial_tx,void,"FuriHalSerialHandle*, const uint8_t*, size_t" diff --git a/targets/f7/furi_hal/furi_hal_serial.c b/targets/f7/furi_hal/furi_hal_serial.c index 5ddb0785f..3f6b575a6 100644 --- a/targets/f7/furi_hal/furi_hal_serial.c +++ b/targets/f7/furi_hal/furi_hal_serial.c @@ -950,3 +950,13 @@ const GpioPin* return furi_hal_serial_config[handle->id].gpio[direction]; } + +void furi_hal_serial_send_break(FuriHalSerialHandle* handle) { + furi_check(handle); + + if(handle->id == FuriHalSerialIdUsart) { + LL_USART_RequestBreakSending(USART1); + } else { + LL_LPUART_RequestBreakSending(LPUART1); + } +} diff --git a/targets/f7/furi_hal/furi_hal_serial.h b/targets/f7/furi_hal/furi_hal_serial.h index 00010d83c..6dad8ec31 100644 --- a/targets/f7/furi_hal/furi_hal_serial.h +++ b/targets/f7/furi_hal/furi_hal_serial.h @@ -239,6 +239,12 @@ void furi_hal_serial_dma_rx_stop(FuriHalSerialHandle* handle); */ size_t furi_hal_serial_dma_rx(FuriHalSerialHandle* handle, uint8_t* data, size_t len); +/** Send a break sequence (low level for the whole character duration) + * + * @param handle Serial handle + */ +void furi_hal_serial_send_break(FuriHalSerialHandle* handle); + #ifdef __cplusplus } #endif diff --git a/targets/f7/furi_hal/furi_hal_usb_cdc.c b/targets/f7/furi_hal/furi_hal_usb_cdc.c index cfedb5e76..3408789dd 100644 --- a/targets/f7/furi_hal/furi_hal_usb_cdc.c +++ b/targets/f7/furi_hal/furi_hal_usb_cdc.c @@ -122,7 +122,7 @@ static const struct CdcConfigDescriptorSingle cdc_cfg_desc_single = { .bFunctionLength = sizeof(struct usb_cdc_acm_desc), .bDescriptorType = USB_DTYPE_CS_INTERFACE, .bDescriptorSubType = USB_DTYPE_CDC_ACM, - .bmCapabilities = 0, + .bmCapabilities = USB_CDC_CAP_BRK, }, .cdc_union = { @@ -235,7 +235,7 @@ static const struct CdcConfigDescriptorDual .bFunctionLength = sizeof(struct usb_cdc_acm_desc), .bDescriptorType = USB_DTYPE_CS_INTERFACE, .bDescriptorSubType = USB_DTYPE_CDC_ACM, - .bmCapabilities = 0, + .bmCapabilities = USB_CDC_CAP_BRK, }, .cdc_union = { @@ -330,7 +330,7 @@ static const struct CdcConfigDescriptorDual .bFunctionLength = sizeof(struct usb_cdc_acm_desc), .bDescriptorType = USB_DTYPE_CS_INTERFACE, .bDescriptorSubType = USB_DTYPE_CDC_ACM, - .bmCapabilities = 0, + .bmCapabilities = USB_CDC_CAP_BRK, }, .cdc_union = { @@ -680,6 +680,13 @@ static usbd_respond cdc_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_cal dev->status.data_ptr = &cdc_config[if_num]; dev->status.data_count = sizeof(cdc_config[0]); return usbd_ack; + case USB_CDC_SEND_BREAK: + if(callbacks[if_num] != NULL) { + if(callbacks[if_num]->break_callback != NULL) { + callbacks[if_num]->break_callback(cb_ctx[if_num], req->wValue); + } + } + return usbd_ack; default: return usbd_fail; } diff --git a/targets/f7/furi_hal/furi_hal_usb_cdc.h b/targets/f7/furi_hal/furi_hal_usb_cdc.h index 89b68991b..995e9009a 100644 --- a/targets/f7/furi_hal/furi_hal_usb_cdc.h +++ b/targets/f7/furi_hal/furi_hal_usb_cdc.h @@ -15,6 +15,7 @@ typedef struct { void (*state_callback)(void* context, uint8_t state); void (*ctrl_line_callback)(void* context, uint8_t state); void (*config_callback)(void* context, struct usb_cdc_line_coding* config); + void (*break_callback)(void* context, uint16_t duration); } CdcCallbacks; void furi_hal_cdc_set_callbacks(uint8_t if_num, CdcCallbacks* cb, void* context); From 07426b6df22ebd0e845d24c94f5d942266dcc158 Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Mon, 18 Nov 2024 11:29:54 +0000 Subject: [PATCH 05/59] Add SendBreak event to waiting mask --- applications/main/gpio/usb_uart_bridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c index f3a9775a6..0d2c63b3c 100644 --- a/applications/main/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -40,7 +40,7 @@ typedef enum { #define WORKER_ALL_RX_EVENTS \ (WorkerEvtStop | WorkerEvtRxDone | WorkerEvtCfgChange | WorkerEvtLineCfgSet | \ - WorkerEvtCtrlLineSet | WorkerEvtCdcTxComplete) + WorkerEvtCtrlLineSet | WorkerEvtCdcTxComplete | WorkerEvtSendBreak) #define WORKER_ALL_TX_EVENTS (WorkerEvtTxStop | WorkerEvtCdcRx) struct UsbUartBridge { From 7e0f292615298b597ef7f7a97ca6ab22e759920e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 26 Nov 2024 05:46:32 +0300 Subject: [PATCH 06/59] upd changelog --- CHANGELOG.md | 116 ++------------------------------------------------- 1 file changed, 3 insertions(+), 113 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d263bb8ba..b5058c114 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,119 +1,9 @@ ## Main changes -- Current API: 78.1 -- SubGHz: - - Frequency analyzer fixes and improvements: - - **Enforce int module** (like in OFW) usage due to lack of required hardware on external boards (PathIsolate (+rf switch for multiple paths)) and incorrect usage and/or understanding the purpose of frequency analyzer app by users, it should be used only to get frequency of the remote placed around 1-10cm around flipper's left corner - - **Fix possible GSM mobile towers signal interference** by limiting upper frequency to 920mhz max - - Fix buttons logic, **fix crash** - - Protocol improvements: - - **Keeloq: Monarch full support, with add manually option** (thanks @ashphx !) - - **Princeton support for second button encoding type** (8bit) - - GangQi fix serial check and remove broken check from UI - - Hollarm add more button codes (thanks to @mishamyte for captures) - - Misc: - - Add extra settings to disable GPIO pins control used for external modules amplifiers and/or LEDs (in radio settings menu with debug ON) -- NFC: - - Read Ultralight block by block (**fix password protected MFUL reading issue**) (by @mishamyte | PR #825 #826) - - **Update NDEF parser** (SLIX and MFC support) (by @luu176 and @jaylikesbunda and @Willy-JL) - - OFW PR 3822: **MIFARE Classic Key Recovery Improvements** (by @noproto) - - OFW PR 3930: NFC Emulation freeze fix (by @RebornedBrain) - - OFW: H World Hotel Chain Room Key Parser - - OFW: Parser for Tianjin Railway Transit - - New keys in system dict -- Infrared: - - **Add LEDs universal remote** (DB by @amec0e) - - Update universal remote assets (by @amec0e | PR #813 #816) -- JS: - - OFW: JS modules & SDK -> **Breaking API change** - - **Backporting custom features** (read about most of the changes after other changes section) (by @xMasterX and @Willy-JL) - - Add i2c & SPI module (by @jamisonderek) -* OFW: FuriHal, drivers: rework gauge initialization routine -> **Downgrade to older releases may break battery UI percent indicator, upgrade to this or newer version to restore** -* OFW: heap: increased size -> **More free RAM!!** -* OFW: New layout for BadUSB (es-LA) -* OFW: Require PIN on boot +- Current API: 78.2 +* OFW: merged gsurkov/vcp_break_support branch for usb uart bridge (WIP!!!) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes -* SubGHz: Freq analyzer - Fix duplicated frequency lists and use user config for nearest frequency selector too -* SubGHz: Code cleanup and fix for rare dupicated (Data) field cases -* OFW: NFC TRT Parser: Additional checks to prevent false positives -* OFW PR 3992: Loader: Fix BusFault in handling of OOM (by @Willy-JL) -* OFW PR 3885: NFC: Add API to enforce ISO15693 mode (by @aaronjamt) -* OFW: NFC: iso14443_4a improvements (by @RebornedBrain) -* OFW: NFC: Plantain parser improvements (by @assasinfil) & fixes (by @mxcdoam) -* OFW: NFC: Moscow social card parser (by @assasinfil) -* OFW: fix: npm deps -* OFW: 目覚め時計 (Added alarm option and clock settings) -* OFW: JS: Backport and more additions & fixes -* OFW: nfc: add Caltrain zones for Clipper -* OFW: Update unit tests docs -* OFW: Fix JS memory corruption (in gpio module) -* OFW: Full-fledged JS SDK + npm packages -* OFW: FurEventLoop: add support for FuriEventFlag, simplify API -* OFW: lib: digital_signal: digital_sequence: add furi_hal.h wrapped in ifdefs -* OFW: Add warning about stealth mode in vibro CLI -* OFW: Small fixes in the wifi devboard docs -* OFW: BadUSB - Improve ChromeOS and GNOME demo scripts -* OFW: Small JS fixes -* OFW: Canvas: extended icon draw. -* OFW: Fixes Mouse Clicker Should have a "0" value setting for "as fast as possible" -* OFW: Wi-Fi Devboard documentation rework -* OFW: Furi: A Lot of Fixes -* OFW PR 3933: furi_hal_random: Wait for ready state and no errors before sampling (by @n1kolasM) -* OFW: nfc/clipper: Update BART station codes -* OFW: FuriThread: Improve state callbacks -* OFW: Documentation: update and cleanup -* OFW: Improve bit_buffer.h docs -* OFW: Prevent idle priority threads from potentially starving the FreeRTOS idle task -* OFW: IR universal remote additions -* OFW: Fix EM4100 T5577 writing block order (was already done in UL) -* OFW: kerel typo -* OFW: Folder rename fails -* OFW: Put errno into TCB -* OFW: Fix USB-UART bridge exit screen stopping the bridge prematurely -**More details on JS changes** (js changelog written by @Willy-JL , thanks!): -- Our custom JS SDK can be found on npm now: https://www.npmjs.com/org/darkflippers -- Non-exhaustive list of changes to help you fix your scripts: - - `badusb`: - - `setup()`: `mfr_name`, `prod_name`, `layout_path` parameters renamed to `mfrName`, `prodName`, `layoutPath` - - effort required to update old scripts using badusb: very minimal - - `dialog`: - - removed, now replaced by `gui/dialog` and `gui/file_picker` (see below) - - `event_loop`: - - new module, allows timer functionality, callbacks and event-driven programming, used heavily alongside gpio and gui modules - - `gpio`: - - fully overhauled, now you `get()` pin instances and perform actions on them like `.init()` - - now supports interrupts, callbacks and more cool things - - effort required to update old scripts using gpio: moderate - - `gui`: - - new module, fully overhauled, replaces dialog, keyboard, submenu, textbox modules - - higher barrier to entry than older modules (requires usage of `event_loop` and `gui.viewDispatcher`), but much more flexible, powerful and easier to extend - - includes all previously available js gui functionality (except `widget`), and also adds `gui/loading` and `gui/empty_screen` views - - currently `gui/file_picker` works different than other new view objects, it is a simple `.pickFile()` synchronous function, but this [may change later](https://github.com/flipperdevices/flipperzero-firmware/pull/3961#discussion_r1805579153) - - effort required to update old scripts using gui: extensive - - `keyboard`: - - removed, now replaced by `gui/text_input` and `gui/byte_input` (see above) - - `math`: - - `is_equal()` renamed to `isEqual()` - - `storage`: - - fully overhauled, now you `openFile()`s and perform actions on them like `.read()` - - now supports many more operations including different open modes, directories and much more - - effort required to update old scripts using storage: moderate - - `submenu`: - - removed, now replaced by `gui/submenu` (see above) - - `textbox`: - - removed, now replace by `gui/text_box` (see above) - - `widget`: - - only gui functionality not ported to new gui module, remains unchanged for now but likely to be ported later on - - globals: - - `__filepath` and `__dirpath` renamed to `__filename` and `__dirname` like in nodejs - - `to_string()` renamed and moved to number class as `n.toString()`, now supports optional base parameter - - `to_hex_string()` removed, now use `n.toString(16)` - - `parse_int()` renamed to `parseInt()`, now supports optional base parameter - - `to_upper_case()` and `to_lower_case()` renamed and moved to string class as `s.toUpperCase()` and `s.toLowerCase()` - - effort required to update old scripts using these: minimal - - Added type definitions (typescript files for type checking in IDE, Flipper does not run typescript) - - Documentation is incomplete and deprecated, from now on you should refer to type definitions (`applications/system/js_app/types`), those will always be correct - - Type definitions for extra modules we have that OFW doesn't will come later +* No changes yet :(

#### Known NFC post-refactor regressions list: - Mifare Mini clones reading is broken (original mini working fine) (OFW) From 0ef9f7d308e093f3dc45df79202c73c150756957 Mon Sep 17 00:00:00 2001 From: Ruslan Nadyrshin <110516632+rnadyrshin@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:58:13 +0400 Subject: [PATCH 07/59] JS packages folder included to the doxygen's exclude list (#4021) --- documentation/doxygen/Doxyfile.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/doxygen/Doxyfile.cfg b/documentation/doxygen/Doxyfile.cfg index e01631749..3df12f08f 100644 --- a/documentation/doxygen/Doxyfile.cfg +++ b/documentation/doxygen/Doxyfile.cfg @@ -1042,6 +1042,7 @@ EXCLUDE = $(DOXY_SRC_ROOT)/lib/mlib \ $(DOXY_SRC_ROOT)/applications/plugins/dap_link/lib/free-dap \ $(DOXY_SRC_ROOT)/applications/debug \ $(DOXY_SRC_ROOT)/applications/main \ + $(DOXY_SRC_ROOT)/applications/system/js_app/packages \ $(DOXY_SRC_ROOT)/applications/settings \ $(DOXY_SRC_ROOT)/lib/micro-ecc \ $(DOXY_SRC_ROOT)/lib/ReadMe.md \ From 399bcdcc13765cff4701eb8ddb2dbeddcb5ba59f Mon Sep 17 00:00:00 2001 From: Nicolas Marie-Magdelaine PhD Date: Mon, 2 Dec 2024 08:15:29 +0100 Subject: [PATCH 08/59] Add IR command for NAD DR2 D7050 D3020 (#4020) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../resources/infrared/assets/audio.ir | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/applications/main/infrared/resources/infrared/assets/audio.ir b/applications/main/infrared/resources/infrared/assets/audio.ir index 20070bbe0..efd0382e3 100644 --- a/applications/main/infrared/resources/infrared/assets/audio.ir +++ b/applications/main/infrared/resources/infrared/assets/audio.ir @@ -4650,3 +4650,42 @@ type: parsed protocol: NECext address: 7F 01 00 00 command: 69 96 00 00 +# +# Model : NAD DR2 remote for NAD D7050 and D3020 +# +name: Power +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 25 DA 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 88 77 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 8C 73 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 94 6B 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 1A E5 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 1D E2 00 00 +# From c3dc9e1ec2aa785f346d979e906ecef82dc2ab74 Mon Sep 17 00:00:00 2001 From: Luu <112649910+luu176@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:27:16 +0100 Subject: [PATCH 09/59] Fix typo for mf_classic_key_cahce_get_next_key() function (#4015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update mf_classic_key_cache.c * Update mf_classic_key_cache.h * Update mf_classic.c * Update nfc_scene_mf_classic_update_initial.c Co-authored-by: あく --- applications/main/nfc/helpers/mf_classic_key_cache.c | 2 +- applications/main/nfc/helpers/mf_classic_key_cache.h | 2 +- .../main/nfc/helpers/protocol_support/mf_classic/mf_classic.c | 2 +- .../main/nfc/scenes/nfc_scene_mf_classic_update_initial.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/main/nfc/helpers/mf_classic_key_cache.c b/applications/main/nfc/helpers/mf_classic_key_cache.c index 1b945660c..763c4dea7 100644 --- a/applications/main/nfc/helpers/mf_classic_key_cache.c +++ b/applications/main/nfc/helpers/mf_classic_key_cache.c @@ -166,7 +166,7 @@ void mf_classic_key_cache_load_from_data(MfClassicKeyCache* instance, const MfCl } } -bool mf_classic_key_cahce_get_next_key( +bool mf_classic_key_cache_get_next_key( MfClassicKeyCache* instance, uint8_t* sector_num, MfClassicKey* key, diff --git a/applications/main/nfc/helpers/mf_classic_key_cache.h b/applications/main/nfc/helpers/mf_classic_key_cache.h index b09f4526b..50a1f5c30 100644 --- a/applications/main/nfc/helpers/mf_classic_key_cache.h +++ b/applications/main/nfc/helpers/mf_classic_key_cache.h @@ -16,7 +16,7 @@ bool mf_classic_key_cache_load(MfClassicKeyCache* instance, const uint8_t* uid, void mf_classic_key_cache_load_from_data(MfClassicKeyCache* instance, const MfClassicData* data); -bool mf_classic_key_cahce_get_next_key( +bool mf_classic_key_cache_get_next_key( MfClassicKeyCache* instance, uint8_t* sector_num, MfClassicKey* key, diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index 4fece16be..6f7be7f4c 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -72,7 +72,7 @@ static NfcCommand nfc_scene_read_poller_callback_mf_classic(NfcGenericEvent even uint8_t sector_num = 0; MfClassicKey key = {}; MfClassicKeyType key_type = MfClassicKeyTypeA; - if(mf_classic_key_cahce_get_next_key( + if(mf_classic_key_cache_get_next_key( instance->mfc_key_cache, §or_num, &key, &key_type)) { mfc_event->data->read_sector_request_data.sector_num = sector_num; mfc_event->data->read_sector_request_data.key = key; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c index 7c76260b4..a477a08b9 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c @@ -34,7 +34,7 @@ NfcCommand nfc_mf_classic_update_initial_worker_callback(NfcGenericEvent event, uint8_t sector_num = 0; MfClassicKey key = {}; MfClassicKeyType key_type = MfClassicKeyTypeA; - if(mf_classic_key_cahce_get_next_key( + if(mf_classic_key_cache_get_next_key( instance->mfc_key_cache, §or_num, &key, &key_type)) { mfc_event->data->read_sector_request_data.sector_num = sector_num; mfc_event->data->read_sector_request_data.key = key; From 2f30817dc9a052a9d033b53c6f32de6b67d74b0c Mon Sep 17 00:00:00 2001 From: WillyJL <49810075+Willy-JL@users.noreply.github.com> Date: Mon, 2 Dec 2024 07:54:50 +0000 Subject: [PATCH 10/59] Settings: More granularity for LCD and Notification (#4010) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../notification_settings_app.c | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index ada2bfdd4..2462b32bd 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -20,8 +20,11 @@ static const NotificationSequence sequence_note_c = { NULL, }; -#define CONTRAST_COUNT 11 +#define CONTRAST_COUNT 17 const char* const contrast_text[CONTRAST_COUNT] = { + "-8", + "-7", + "-6", "-5", "-4", "-3", @@ -33,8 +36,14 @@ const char* const contrast_text[CONTRAST_COUNT] = { "+3", "+4", "+5", + "+6", + "+7", + "+8", }; const int32_t contrast_value[CONTRAST_COUNT] = { + -8, + -7, + -6, -5, -4, -3, @@ -46,44 +55,47 @@ const int32_t contrast_value[CONTRAST_COUNT] = { 3, 4, 5, + 6, + 7, + 8, }; -#define BACKLIGHT_COUNT 5 +#define BACKLIGHT_COUNT 21 const char* const backlight_text[BACKLIGHT_COUNT] = { - "0%", - "25%", - "50%", - "75%", - "100%", + "0%", "5%", "10%", "15%", "20%", "25%", "30%", "35%", "40%", "45%", "50%", + "55%", "60%", "65%", "70%", "75%", "80%", "85%", "90%", "95%", "100%", }; const float backlight_value[BACKLIGHT_COUNT] = { - 0.0f, - 0.25f, - 0.5f, - 0.75f, - 1.0f, + 0.00f, 0.05f, 0.10f, 0.15f, 0.20f, 0.25f, 0.30f, 0.35f, 0.40f, 0.45f, 0.50f, + 0.55f, 0.60f, 0.65f, 0.70f, 0.75f, 0.80f, 0.85f, 0.90f, 0.95f, 1.00f, }; -#define VOLUME_COUNT 5 +#define VOLUME_COUNT 21 const char* const volume_text[VOLUME_COUNT] = { - "0%", - "25%", - "50%", - "75%", - "100%", + "0%", "5%", "10%", "15%", "20%", "25%", "30%", "35%", "40%", "45%", "50%", + "55%", "60%", "65%", "70%", "75%", "80%", "85%", "90%", "95%", "100%", +}; +const float volume_value[VOLUME_COUNT] = { + 0.00f, 0.05f, 0.10f, 0.15f, 0.20f, 0.25f, 0.30f, 0.35f, 0.40f, 0.45f, 0.50f, + 0.55f, 0.60f, 0.65f, 0.70f, 0.75f, 0.80f, 0.85f, 0.90f, 0.95f, 1.00f, }; -const float volume_value[VOLUME_COUNT] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f}; -#define DELAY_COUNT 6 +#define DELAY_COUNT 11 const char* const delay_text[DELAY_COUNT] = { "1s", "5s", + "10s", "15s", "30s", "60s", + "90s", "120s", + "5min", + "10min", + "30min", }; -const uint32_t delay_value[DELAY_COUNT] = {1000, 5000, 15000, 30000, 60000, 120000}; +const uint32_t delay_value[DELAY_COUNT] = + {1000, 5000, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000, 1800000}; #define VIBRO_COUNT 2 const char* const vibro_text[VIBRO_COUNT] = { From 8629c61dc91f843577d9214b4a60b9b607fe1914 Mon Sep 17 00:00:00 2001 From: mxcdoam <72457810+mxcdoam@users.noreply.github.com> Date: Mon, 2 Dec 2024 11:08:17 +0300 Subject: [PATCH 11/59] NFC: Plantain parser Last payment amount fix (#3998) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../main/nfc/plugins/supported_cards/plantain.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/plantain.c b/applications/main/nfc/plugins/supported_cards/plantain.c index 9f2491691..49bbaebe8 100644 --- a/applications/main/nfc/plugins/supported_cards/plantain.c +++ b/applications/main/nfc/plugins/supported_cards/plantain.c @@ -310,9 +310,11 @@ static bool plantain_parse(const NfcDevice* device, FuriString* parsed_data) { last_payment_date.year, last_payment_date.hour, last_payment_date.minute); - //payment amount. This needs to be investigated more, currently it shows incorrect amount on some cards. - uint16_t last_payment = (data->block[18].data[9] << 8) | data->block[18].data[8]; - furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment / 100); + //Last payment amount. + uint16_t last_payment = ((data->block[18].data[10] << 16) | + (data->block[18].data[9] << 8) | (data->block[18].data[8])) / + 100; + furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment); furi_string_free(card_number_s); furi_string_free(tmp_s); //This is for 4K Plantains. @@ -369,9 +371,11 @@ static bool plantain_parse(const NfcDevice* device, FuriString* parsed_data) { last_payment_date.year, last_payment_date.hour, last_payment_date.minute); - //payment amount - uint16_t last_payment = (data->block[18].data[9] << 8) | data->block[18].data[8]; - furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment / 100); + //Last payment amount + uint16_t last_payment = ((data->block[18].data[10] << 16) | + (data->block[18].data[9] << 8) | (data->block[18].data[8])) / + 100; + furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment); furi_string_free(card_number_s); furi_string_free(tmp_s); } From 3d6fd9b00d216f744a69472341e1bca89fa7a83c Mon Sep 17 00:00:00 2001 From: ted-logan Date: Mon, 2 Dec 2024 01:51:57 -0800 Subject: [PATCH 12/59] nfc/clipper: (#3991) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfs/clipper: BART station ids for San Lorenzo, Bay Fair Update the BART station ids for the San Lorenzo and Bay Fair stations in the East Bay of the San Francisco Bay Area. * nfc/clipper: Update MUNI station ids Add MUNI station ids for the T line "Central Subway" project, which opened three new underground stations in 2022. --------- Co-authored-by: あく --- applications/main/nfc/plugins/supported_cards/clipper.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/plugins/supported_cards/clipper.c b/applications/main/nfc/plugins/supported_cards/clipper.c index 3eba82425..eb459d419 100644 --- a/applications/main/nfc/plugins/supported_cards/clipper.c +++ b/applications/main/nfc/plugins/supported_cards/clipper.c @@ -101,7 +101,8 @@ static const IdMapping bart_zones[] = { {.id = 0x001d, .name = "Lake Merrit"}, {.id = 0x001e, .name = "Fruitvale"}, {.id = 0x001f, .name = "Coliseum"}, - {.id = 0x0021, .name = "San Leandro"}, + {.id = 0x0020, .name = "San Leandro"}, + {.id = 0x0021, .name = "Bay Fair"}, {.id = 0x0022, .name = "Hayward"}, {.id = 0x0023, .name = "South Hayward"}, {.id = 0x0024, .name = "Union City"}, @@ -131,6 +132,9 @@ static const IdMapping muni_zones[] = { {.id = 0x000b, .name = "Castro"}, {.id = 0x000c, .name = "Forest Hill"}, // Guessed {.id = 0x000d, .name = "West Portal"}, + {.id = 0x0019, .name = "Union Square/Market Street"}, + {.id = 0x001a, .name = "Chinatown - Rose Pak"}, + {.id = 0x001b, .name = "Yerba Buena/Moscone"}, }; static const size_t kNumMUNIZones = COUNT(muni_zones); From 0fd26ee14826247ea77c1ee8ee121952ae6924c7 Mon Sep 17 00:00:00 2001 From: Astra Date: Mon, 2 Dec 2024 19:24:20 +0900 Subject: [PATCH 13/59] Increase system stack's reserved memory size --- targets/f7/stm32wb55xx_flash.ld | 2 +- targets/f7/stm32wb55xx_ram_fw.ld | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/f7/stm32wb55xx_flash.ld b/targets/f7/stm32wb55xx_flash.ld index 524da6fc3..ef61bb238 100644 --- a/targets/f7/stm32wb55xx_flash.ld +++ b/targets/f7/stm32wb55xx_flash.ld @@ -3,7 +3,7 @@ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _stack_end = 0x20030000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ -_stack_size = 0x200; /* required amount of stack */ +_stack_size = 0x400; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K diff --git a/targets/f7/stm32wb55xx_ram_fw.ld b/targets/f7/stm32wb55xx_ram_fw.ld index f0e8ad678..93579788d 100644 --- a/targets/f7/stm32wb55xx_ram_fw.ld +++ b/targets/f7/stm32wb55xx_ram_fw.ld @@ -3,7 +3,7 @@ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _stack_end = 0x20030000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ -_stack_size = 0x200; /* required amount of stack */ +_stack_size = 0x400; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K From 7d5358b9d3b0d6493a8be3d0e76dfd58de913493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Tue, 3 Dec 2024 07:30:25 +0100 Subject: [PATCH 14/59] Replace mf_classic_dict.nfc with Proxmark3 version (#4013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../resources/nfc/assets/mf_classic_dict.nfc | 3712 ++++++++++++----- 1 file changed, 2556 insertions(+), 1156 deletions(-) diff --git a/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc b/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc index e2b74f847..0a3de18af 100644 --- a/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc +++ b/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc @@ -1,126 +1,82 @@ -# Key dictionary from https://github.com/ikarus23/MifareClassicTool.git - -# More well known keys! -# Standard keys +# Key dictionary from https://github.com/RfidResearchGroup/proxmark3/ +# +# Mifare Default Keys +# -- iceman fork version -- +# -- contribute to this list, sharing is caring -- +# +# Default key FFFFFFFFFFFF -A0A1A2A3A4A5 -D3F7D3F7D3F7 +# +# Blank key 000000000000 - -# Keys from mfoc +# +# NFC Forum MADkey +A0A1A2A3A4A5 +# +# MAD access key A (reversed) +A5A4A3A2A1A0 +# +# MAD access key B +89ECA97F8C2A +# +# Mifare 1k EV1 (S50) hidden blocks, Signature data +# 16 A +5C8FF9990DA2 +# +# 17 A +75CCB59C9BED +# +# 16 B +D01AFEEB890A +# +# 17 B +4B791BEA7BCC +# +# QL88 keys +# 17 A/B +2612C6DE84CA +707B11FC1481 +# +# QL88 diversifed +03F9067646AE +2352C5B56D85 +# B0B1B2B3B4B5 +C0C1C2C3C4C5 +D0D1D2D3D4D5 +AABBCCDDEEFF 4D3A99C351DD 1A982C7E459A -AABBCCDDEEFF +# +# key A Wien +D3F7D3F7D3F7 +# +# key B Wien +5A1B85FCE20A +# +# 714C5C886E97 587EE5F9350F A0478CC39091 533CB6C723F6 8FD0A4F256E9 - -# Keys from: -# http://pastebin.com/wcTHXLZZ -A64598A77478 -26940B21FF5D -FC00018778F7 -00000FFE2488 -5C598C9C58B5 -E4D2770A89BE - -# Keys from: -# http://pastebin.com/svGjN30Q -434F4D4D4F41 -434F4D4D4F42 -47524F555041 -47524F555042 -505249564141 -505249564142 - -# Keys from: -# http://pastebin.com/d7sSetef -0297927C0F77 -EE0042F88840 -722BFCC5375F -F1D83F964314 - -# Keys from: -# http://pastebin.com/pvJX0xVS -54726176656C -776974687573 -4AF9D7ADEBE4 -2BA9621E0A36 - -# Keys from: -# http://pastebin.com/y3PDBWR1 -000000000001 -123456789ABC -B127C6F41436 -12F2EE3478C1 -34D1DF9934C5 -55F5A5DD38C9 -F1A97341A9FC -33F974B42769 -14D446E33363 -C934FE34D934 -1999A3554A55 -27DD91F1FCF1 -A94133013401 -99C636334433 -43AB19EF5C31 -A053A292A4AF -505249565441 -505249565442 - -# Keys from: -# http://pastebin.com/TUXj17K3 -FC0001877BF7 - -# Keys from: -# http://0x9000.blogspot.com/2010/12/mifare-classic-default-keys.html -A0B0C0D0E0F0 -A1B1C1D1E1F1 - -# Keys from: -# https://code.google.com/p/mifare-key-cracker/downloads/list -BD493A3962B6 -010203040506 -111111111111 -222222222222 -333333333333 -444444444444 -555555555555 -666666666666 -777777777777 -888888888888 -999999999999 -AAAAAAAAAAAA -BBBBBBBBBBBB -CCCCCCCCCCCC -DDDDDDDDDDDD -EEEEEEEEEEEE -0123456789AB - -# Keys from: -# https://github.com/4ZM/mfterm/blob/master/dictionary.txt -000000000002 -00000000000A -00000000000B -100000000000 -200000000000 -A00000000000 -B00000000000 - -# Key from: -# ladyada.net -ABCDEF123456 - -# Key from: -# http://irq5.io/2013/04/13/decoding-bcard-conference-badges/ -F4A9EF2AFC6D - -# Keys from: -# https://github.com/iceman1001/proxmark -4B0B20107CCB +# +# iCopy-X +E00000000000 +# +# +E7D6064C5860 +B27CCAB30DBD +# +# lib / Nat Bieb +D2ECE8B9395E +# NSCP default key +1494E81663D7 +# +# NFC tools +7c9fb8474242 +# +# Kiev keys 569369C5A0E5 632193BE1C3C 644672BD4AFE @@ -129,410 +85,926 @@ F4A9EF2AFC6D B5FF67CBA951 EFF603E1EFE9 F14EE7CAE863 +# +# ICT S14 A/B +9C28A60F7249 +C9826AF02794 +# +# RKF +# Västtrafiken KeyA, RKF ÖstgötaTrafiken KeyA +FC00018778F7 +# +# Västtrafiken KeyA +0297927C0F77 +54726176656C +# +# Västtrafiken KeyB +00000FFE2488 +776974687573 +EE0042F88840 +# +# RKF SLKeyA +26940B21FF5D +A64598A77478 +# +# RKF SLKeyB +5C598C9C58B5 +E4D2770A89BE +# +# RKF Rejskort Danmark KeyA +722BFCC5375F +# +# RKF Rejskort Danmark KeyB +F1D83F964314 +# +# RKF JOJOPRIVA KeyA +505249564141 +# +# RKF JOJOPRIVA KeyB +505249564142 +# +# RKF JOJOGROUP KeyA +47524F555041 +434F4D4D4F41 +# +# RKF JOJOGROUP KeyB +47524F555042 +434F4D4D4F42 +# +# TNP3xxx +4B0B20107CCB +# +# Access control system +605F5E5D5C5B +# +# NSP Global keys A and B (uk housing access control) +199404281970 +199404281998 +# +# Data from http://www.proxmark.org/forum/viewtopic.php?pid=25925#p25925 +# Tengo Cards Key A +FFF011223358 +FF9F11223358 +# +# Elevator system Kherson, Ukraine +AC37E76385F5 +576DCFFF2F25 +# +# Car wash system +1EE38419EF39 +26578719DCD9 +# +# more Keys from mfc_default_keys.lua +000000000001 +000000000002 +00000000000A +00000000000B +010203040506 +0123456789AB +100000000000 +111111111111 +123456789ABC +12F2EE3478C1 +14D446E33363 +1999A3554A55 +200000000000 +222222222222 +27DD91F1FCF1 +# +# Hotel system +505209016A1F +# +# Directory and eventlog KeyB +2BA9621E0A36 +# +# Directory and eventlog KeyA +4AF9D7ADEBE4 +# +# +333333333333 +33F974B42769 +34D1DF9934C5 +43AB19EF5C31 +444444444444 +505249565441 +505249565442 +555555555555 +55F5A5DD38C9 +666666666666 +777777777777 +888888888888 +999999999999 +99C636334433 +A00000000000 +A053A292A4AF +A94133013401 +AAAAAAAAAAAA +# +# Key from ladyada.net +ABCDEF123456 +# +# +B00000000000 +B127C6F41436 +BBBBBBBBBBBB +BD493A3962B6 +C934FE34D934 +CCCCCCCCCCCC +DDDDDDDDDDDD +EEEEEEEEEEEE +# +# elevator +# data from forum +FFFFFF545846 +# +# +F1A97341A9FC +# +# hotel system 44AB09010845 85FED980EA5A -314B49474956 -564C505F4D41 -0263DE1278F3 -067DB45454A9 -15FC4C7613FE -16F21A82EC84 -16F3D5AB1139 -17758856B182 -1FC235AC1309 -22C1BAE1AACD -243F160918D1 -25094DF6F148 -2A3C347A1200 -324F5DF65310 -32AC3B90AC13 -35C3D2CAEE88 -3A42F33AF429 -3DF14C8000A1 -3E3554AF0E12 -3E65E4FB65B3 -454841585443 -460722122510 -48FFE71294A0 -491CDCFB7752 -4AD1E273EAF1 -4B791BEA7BCC -51284C3686A6 -528C9DFFE28C -5EB8F884C8D1 -5F146716E373 -6338A371C0ED -63F17A449AF0 -643FB6DE2217 -64E3C10394C2 -682D401ABB09 -68D30288910A -693143F10368 -6A470D54127C -740E9A4F9AAF -75CCB59C9BED -75D8690F21B6 -75EDE6A84460 -82F435DEDF01 -85675B200017 -871B8C085997 -937A4FFF3011 -97184D136233 -97D1101F18B0 -9AFC42372AF1 -A27D3804C259 -A3F97428DD01 -A8966C7CC54B +# +# ARD (fr) key A +43454952534E +# ARD (fr) key B +4A2B29111213 +# +# +4143414F5250 +# +# Tehran Railway +A9B43414F585 +1FB235AC1388 +# +# Data from http://irq5.io/2013/04/13/decoding-bcard-conference-badges/ +# BCARD KeyB +F4A9EF2AFC6D +# +# +# S0 B +89EAC97F8C2A +# +# S4 A +43C7600DEE6B +# +# S6 A +0120BF672A64 +# +# S6 B +FB0B20DF1F34 +# +# A9F953DEF0A3 -AAFB06045877 -AC0E24C75527 -AE3FF4EEA0DB -B0C9DD55DD4D -B736412614AF -C4652C54261C -C6AD00254562 -C82EC29E3235 -D39BB83F5297 -D49E2826664F -DF27A8F1CB8E -E2C42591368A -E3429281EFC1 -E444D53D359F +# +# Data from forum +74A386AD0A6D +3F7A5C2DBD81 +21EDF95E7433 +C121FF19F681 +3D5D9996359A +# +# Here be BIP keys... +3A42F33AF429 +1FC235AC1309 +6338A371C0ED +243F160918D1 F124C2578AD0 +9AFC42372AF1 +32AC3B90AC13 +682D401ABB09 +4AD1E273EAF1 +067DB45454A9 +E2C42591368A +15FC4C7613FE +2A3C347A1200 +68D30288910A +16F3D5AB1139 F59A36A2546D -FEE470A4CB58 -0000000018DE -0000014B5C31 -003003003003 -003CC420001A -013889343891 -01FA3FC68349 -021209197591 -050908080008 -0A7932DC7E65 -0C669993C776 -0C71BCFB7E72 -0D258FE90296 +937A4FFF3011 +64E3C10394C2 +35C3D2CAEE88 +B736412614AF +693143F10368 +324F5DF65310 +A3F97428DD01 +643FB6DE2217 +63F17A449AF0 +82F435DEDF01 +C4652C54261C +0263DE1278F3 +D49E2826664F +51284C3686A6 +3DF14C8000A1 +6A470D54127C +# +# Data from http://pastebin.com/AK9Bftpw +# Länstrafiken i Västerbotten +48FFE71294A0 +E3429281EFC1 +16F21A82EC84 +460722122510 +# +# 3dprinter +# EPI Envisionte +AAFB06045877 +# +# Gyms / Fitness Clubs / Health Clubs / Wellness Centres +# +# Fysiken A +3E65E4FB65B3 +# +# Fysiken B +25094DF6F148 +# +# +# https://mattionline.de/fitnessstudio-armband-reverse-engineering/ +# https://mattionline.de/milazycracker/ +# Gym Wristband A - Same as Fysiken A +# Gym Wristband B +81CC25EBBB6A +195DC63DB3A3 +# +# CleverFit +A05DBD98E0FC +# +# GoFit +AA4DDA458EBB +EAB8066C7479 +# +# Nordic Wellness A - Same as Fysiken A +# Nordic Wellness B +E5519E1CC92B +# +# Jett's 24 Hour Fitness S0 KA/B +# 049979614077 +# 829338771705 +# +# Hotel KeyCard +D3B595E9DD63 +AFBECD121004 +# +# SimonsVoss +6471A5EF2D1A +# +# ID06 +4E3552426B32 +22BDACF5A33F +6E7747394E63 +763958704B78 +# +# Onity S1 A/B +8A19D40CF2B5 +# +3961EA82C46D +# +# 24-7 +D21762B2DE3B 0E83A374B513 -0F230695923F +1F1FFE000000 +A10F303FC879 +1322285230B8 +0C71BCFB7E72 +C3C88C6340B8 +F101622750B7 +1F107328DC8D +710732200D34 +7C335FB121B5 +B39AE17435DC +# +# key A +454841585443 +# +# Lift system +190819842023 +# +# Data from http://pastebin.com/gQ6nk38G +D39BB83F5297 +85675B200017 +528C9DFFE28C +C82EC29E3235 +3E3554AF0E12 +491CDCFB7752 +22C1BAE1AACD +5F146716E373 +740E9A4F9AAF +AC0E24C75527 +97184D136233 +E444D53D359F +17758856B182 +A8966C7CC54B +C6AD00254562 +AE3FF4EEA0DB +5EB8F884C8D1 +FEE470A4CB58 +75D8690F21B6 +871B8C085997 +97D1101F18B0 +75EDE6A84460 +DF27A8F1CB8E +B0C9DD55DD4D +# +# Data from http://bit.ly/1bdSbJl +A0B0C0D0E0F0 +A1B1C1D1E1F1 +# +# Data from msk social +2735FC181807 +2ABA9519F574 +84FD7F7A12B6 +186D8C4B93F9 +3A4BBA8ADAF0 +8765B17968A2 +40EAD80721CE +0DB5E6523F7C +51119DAE5216 +83E3549CE42D +136BDB246CAC +7DE02A7F6025 +BF23A53C1F63 +CB9A1F2D7368 +C7C0ADB3284F +9F131D8C2057 +67362D90F973 +6202A38F69E2 +100533B89331 +653A87594079 +D8A274B2E026 +B20B83CB145C +9AFA6CB4FC3D +A229E68AD9E5 +49C2B5296EF4 +# +# Data from http://pastebin.com/RRJUEDCM +0D258FE90296 +E55A3CA71826 +A4F204203F56 +EEB420209D0C +911E52FD7CE4 +752FBB5B7B45 +66B03ACA6EE9 +48734389EDC3 +17193709ADF4 +1ACC3189578C +C2B7EC7D4EB1 +369A4663ACD2 +# +# Data from https://github.com/zhangjingye03/zxcardumper +# zxcard Key A/B +668770666644 +003003003003 +# +# Data from http://phreakerclub.com/forum/showthread.php?p=41266 +26973EA74321 +71F3A315AD26 +51044EFB5AAB +AC70CA327A04 +EB0A8FF88ADE +# +# Transport system Metromoney +2803BCB0C7E1 +9C616585E26D +4FA9EB49F75E +2DADE48942C5 +A160FCD5EC4C +112233445566 +361A62F35BC9 +# +# Transport system Spain +83F3CB98C258 +070D486BC555 +A9B018868CC1 +9DCDB136110C +749934CC8ED3 +506DB955F161 +F088A85E71D7 +72B458D60363 +70C714869DC7 +B32464412EE3 +F253C30568C4 +1C68315674AC +CFE63749080A +C1E6F8AFC9EC +DD0DE3BA08A6 +3D923EB73534 +FF94F86B09A6 +D61707FFDFB1 +8223205047B6 +9951A273DEE7 +C9449301AF93 +66695A45C9FA +89AA9D743812 +C41514DEFC07 +C52876869800 +5353B3AECB53 +2E4169A5C79D +4BB747E48C2A +6285A1C8EB5C +5145C34DBA19 +25352912CD8D +81B20C274C3F +00B70875AF1D +04B787B2F3A5 +05412723F1B6 +05C301C8795A +066F5AF3CCEE +0A1B6C50E04E +0AD0956DF6EE +0AD6B7E37183 +0F3A4D48757B +1417E5671417 +18AB07270506 +18E887D625B4 +1ABC15934F5A +1AF66F83F5BE +260480290483 +2900AAC52BC3 +2910AFE15C99 +374521A38BCC +3A4C47757B07 +3A524B7A7B37 +3C4ABB877EAF +3F3A534B7B7B +4B787B273A50 +4B92DF1BF25D +4F0E4AE8051A +514B797B2F3A +529CF51F05C5 +52B26C199862 +57A18BFEC381 +5A7D87876EA8 +64CBADC7A313 +65B6C3200736 +67B1B3A4E497 +6B0454D5D3C3 +6B3B7AF45777 +6C273F431564 +702C1BF025DD +738385948494 +76E450094393 +777B1F3A4F4A +7B173A4E4976 +81504133B13C +826576A1AB68 +8A55194F6587 +8DFACF11E778 +8FD6D76742DC +9AFEE1F65742 +9D56D83658AC +9FAC23197904 +A1AB3A08712C +A514B797B373 +A58AB5619631 +A5BB18152EF1 +A777B233A4F4 +AB19BC885A29 +AB91BDA25F00 +AE98BA1E6F2C +B133A4D48757 +B3A4C47757B0 +B6803136F5AF +B793ADA6DB0C +B95BFDEBA7E4 +C0AA2BBD27CD +C27F5C1A9C2B +C9BE49675FE4 +CCCE24102003 +CDE668FDCDBA +D23A31A4AAB9 +DEDD7688BC38 +E9AE90885C39 +F0A3C5182007 +F3A524B7A7B3 +# +# Data from mall +# playland balikesir +ABBA1234FCB0 +# +# A trio bowling bahcelievler +314F495254FF +4152414B4E41 +# +# karinca park nigde +4E474434FFFF +# +# hotel system +537930363139 +# +# Data from https://github.com/RadioWar/NFCGUI +44DD5A385AAF +21A600056CB0 +B1ACA33180A5 +DD61EB6BCE22 +1565A172770F +3E84D2612E2A +F23442436765 +79674F96C771 +87DF99D496CB +C5132C8980BC +A21680C27773 +F26E21EDCEE2 +675557ECC92E +F4396E468114 +6DB17C16B35B +4186562A5BB2 +2FEAE851C199 +DB1A3338B2EB +157B10D84C6B +A643F952EA57 +DF37DCB6AFB3 +4C32BAF326E0 +91CE16C07AC5 +3C5D1C2BCD18 +C3F19EC592A2 +F72A29005459 +185FA3438949 +321A695BD266 +D327083A60A7 +45635EF66EF3 +5481986D2D62 +CBA6AE869AD5 +645A166B1EEB +A7ABBC77CC9E +F792C4C76A5C +BFB6796A11DB +# +# Data from Salto A/B +6A1987C40A21 +7F33625BC129 +6BE9314930D8 +# +# Data from forum +2338B4913111 +# +# Data from stoye +CB779C50E1BD +A27D3804C259 +003CC420001A +F9861526130F +381ECE050FBD +A57186BDD2B9 +48C739E21A04 +36ABF5874ED7 +649D2ABBBD20 +BBE8FFFCF363 +AB4E7045E97D +340E40F81CD8 +E4F65C0EF32C +D2A597D76936 +A920F32FE93A +86AFD95200F7 +9B832A9881FF +26643965B16E +0C669993C776 +B468D1991AF9 +D9A37831DCE5 +2FC1F32F51B1 0FFBF65B5A14 +C5CFE06D9EA3 +C0DECE673829 +# +# +A56C2DF9A26D +# +# Data from https://pastebin.com/vbwast74 +68D3F7307C89 +# +# Smart Rider. Western Australian Public Transport Cards +568C9083F71C +117E5C165B10 +24BB421C7973 +3E3A546650EA +41F262D3AB66 +514956AB3142 +863933AE8388 +# +# Bangkok metro key +97F5DA640B18 +# +# Metro Valencia key +A8844B0BCA06 +# +# HTC Eindhoven key +857464D3AAD1 +# +# Vigik Keys +# Various sources : +# * https://github.com/DumpDos/Vigik +# * http://newffr.com/viewtopic.php?&forum=235&topic=11559 +# * Own dumps +# +# French VIGIK +# VIGIK1 A +314B49474956 +# +# VIGIK1 B +564C505F4D41 +BA5B895DA162 +# +# BTCINO UNDETERMINED SPREAKD 0x01->0x13 key +021209197591 +# +# +2EF720F2AF76 +414C41524F4E +424C41524F4E +4A6352684677 +BF1F4424AF76 +536653644C65 +# +# Intratone Cogelec +# Data from http://bouzdeck.com/rfid/32-cloning-a-mifare-classic-1k-tag.html +484558414354 +A22AE129C013 +49FAE4E3849F +38FCF33072E0 +8AD5517B4B18 +509359F131B1 +6C78928E1317 +AA0720018738 +A6CAC2886412 +62D0C424ED8E +E64A986A5D94 +8FA1D601D0A2 +89347350BD36 +66D2B7DC39EF +6BC1E1AE547D +22729A9BD40F +# +# Data from https://dfir.lu/blog/cloning-a-mifare-classic-1k-tag.html +925B158F796F +FAD63ECB5891 +BBA840BA1C57 +CC6B3B3CD263 +6245E47352E6 +8ED41E8B8056 +2DD39A54E1F3 +6D4C5B3658D2 +1877ED29435A +52264716EFDE +961C0DB4A7ED +703140FD6D86 +157C9A513FA5 +E2A5DC8E066F +# +# Data from forum, schlage 9691T fob +EF1232AB18A0 +# +# Data from a oyster card +374BF468607F +BFC8E353AF63 +15CAFD6159F6 +62EFD80AB715 +987A7F7F1A35 +C4104FA3C526 +4C961F23E6BE +67546972BC69 +F4CD5D4C13FF +94414C1A07DC +16551D52FD20 +9CB290282F7D +77A84170B574 +ED646C83A4F3 +E703589DB50B +513C85D06CDE +95093F0B2E22 +543B01B27A95 +C6D375B99972 +EE4CC572B40E +5106CA7E4A69 +C96BD1CE607F +167A1BE102E0 +A8D0D850A606 +A2ABB693CE34 +7B296C40C486 +91F93A5564C9 +E10623E7A016 +B725F9CBF183 +# +# Data from FDi tag +8829DA9DAF76 +# +# Data from GitHub issue +0A7932DC7E65 11428B5BCE06 11428B5BCE07 11428B5BCE08 11428B5BCE09 11428B5BCE0A 11428B5BCE0F -11496F97752A -123F8888F322 -1322285230B8 -1565A172770F -157B10D84C6B -157C9A513FA5 -15CAFD6159F6 -160A91D29A9C -16551D52FD20 -167A1BE102E0 -16DDCB6B3F24 -1717E34A7A8A -17193709ADF4 -185FA3438949 -1877ED29435A 18971D893494 -1AB23CD45EF6 -1ACC3189578C -1F107328DC8D -1F1A0A111B5B -1F1FFE000000 -2031D1E57A3B -# HID Key B -204752454154 -21A600056CB0 -22729A9BD40F -2338B4913111 -2548A443DF28 25D60050BF6E -26643965B16E -26973EA74321 -27FBC86A00D0 -2A2C13CC242A -2A6D9205E7CA -2CB1A90071C8 -2DD39A54E1F3 -2ED3B15E7C0F -2EF720F2AF76 -2FC1F32F51B1 -2FEAE851C199 -3060206F5B0A -31646241686C -321958042333 -321A695BD266 -340E40F81CD8 -345547514B4D -356D46474348 -369A4663ACD2 -36ABF5874ED7 -374BF468607F -381ECE050FBD -386B4D634A65 -38FCF33072E0 -3A09594C8587 -3B7E4FD575AD -3C5D1C2BCD18 -3E84D2612E2A -3FA7217EC575 -410B9B40B872 -414C41524F4E -415A54454B4D -4186562A5BB2 -424C41524F4E -425A73484166 -436A46587552 -447AB7FD5A6B -44DD5A385AAF 44F0B5FBE344 -45635EF66EF3 -476242304C53 -484558414354 -# HID Key A -484944204953 -484A57696F4A -48734389EDC3 -48C739E21A04 -49FAE4E3849F -4A6352684677 -4C32BAF326E0 -4C6B69723461 -4C961F23E6BE -4D3248735131 -4D5076656D58 -4E32336C6E38 -4E4175623670 -4F9F59C9C875 -509359F131B1 -51044EFB5AAB -5106CA7E4A69 -513C85D06CDE -52264716EFDE -536653644C65 -53C11F90822A -543B01B27A95 -5481986D2D62 -5544564E6E67 -564777315276 -568C9083F71C -57734F6F6974 -57784A533069 -584F66326877 -5A1B85FCE20A -5EC39B022F2B -623055724556 -62387B8D250D -6245E47352E6 -62CED42A6D87 -62D0C424ED8E -62EFD80AB715 -645A166B1EEB -649D2ABBBD20 -666E564F4A44 -668770666644 -66B03ACA6EE9 -66D2B7DC39EF -66F3ED00FED7 -67546972BC69 -675557ECC92E -686A736A356E -68D3F7307C89 -69FB7B7CD8EE -6A1987C40A21 -6A676C315142 -6A696B646631 -6B6579737472 -6BC1E1AE547D -6C78928E1317 -6C94E1CED026 -6D44B5AAF464 -6D4C5B3658D2 -6D4E334B6C48 -6DB17C16B35B -6F4B6D644178 -6F506F493353 -703140FD6D86 -70564650584F -710732200D34 -71F3A315AD26 -744E326B3441 -752FBB5B7B45 -756EF55E2507 -77494C526339 -77646B633657 -77A84170B574 -79674F96C771 -7B296C40C486 7B296F353C6B -7C335FB121B5 -7F33625BC129 8553263F4FF0 -8697389ACA26 -86AFD95200F7 -87DF99D496CB -8829DA9DAF76 -89347350BD36 -8AD5517B4B18 8E5D33A6ED51 -8ED41E8B8056 -8FA1D601D0A2 -911E52FD7CE4 -9189449EA24E -91CE16C07AC5 -91F93A5564C9 -925B158F796F -92EE4DC87191 -932B9CB730EF -94414C1A07DC -95093F0B2E22 -961C0DB4A7ED -987A7F7F1A35 -9B832A9881FF -9CB290282F7D -9DC282D46217 9F42971E8322 -A10F303FC879 -A21680C27773 -A22AE129C013 -A2ABB693CE34 -A4F204203F56 -A56C2DF9A26D -A57186BDD2B9 -A643F952EA57 -A6CAC2886412 -A7ABBC77CC9E -A8D0D850A606 -A920F32FE93A -AA0720018738 -AB4E7045E97D -AC70CA327A04 -AD4FB33388BF -AD9E0A1CA2F7 -AFD0BA94D624 -B1ACA33180A5 -B35A0E4ACC09 -B39AE17435DC -B468D1991AF9 -B578F38A5C61 -B725F9CBF183 -B7BF0C13066E -B8A1F613CF3D -BA5B895DA162 -BBA840BA1C57 -BBE8FFFCF363 -BEDB604CC9D1 -BF1F4424AF76 -BFB6796A11DB -BFC8E353AF63 -C0C1C2C3C4C5 -C0DECE673829 -C2B7EC7D4EB1 -C3C88C6340B8 -C3F19EC592A2 -C4104FA3C526 -C5132C8980BC -C5CFE06D9EA3 C620318EF179 -C6D375B99972 -C96BD1CE607F -CB779C50E1BD -CBA6AE869AD5 -CC6B3B3CD263 -D0D1D2D3D4D5 -D21762B2DE3B -D2A597D76936 -D327083A60A7 D4FE03CE5B06 D4FE03CE5B07 D4FE03CE5B08 D4FE03CE5B09 D4FE03CE5B0A D4FE03CE5B0F -D58023BA2BDC -D9A37831DCE5 -DB1A3338B2EB -DD61EB6BCE22 -DF37DCB6AFB3 -E10623E7A016 E241E8AFCBAF -E2A5DC8E066F -E4F65C0EF32C -E55A3CA71826 -E64A986A5D94 -E703589DB50B -EB0A8FF88ADE -EC0A9B1A9E06 -ED646C83A4F3 -EE4CC572B40E -EEB420209D0C -F101622750B7 -F1B9F5669CC8 -F23442436765 -F238D78FF48F -F26E21EDCEE2 -F4396E468114 -F4CD5D4C13FF -F662248E7E89 -F72A29005459 -F792C4C76A5C +# Transport system Argentina - SUBE +# Shared key - sec 3 blk 15 +3FA7217EC575 +# +# Data from forum post +123F8888F322 +050908080008 +# +# Data from hoist +4F9F59C9C875 +# +# Data from pastebin +66F3ED00FED7 F7A39753D018 -F9861526130F -FAD63ECB5891 - -# Some keys of https://w3bsit3-dns.com and https://ikey.ru -BC4580B7F20B -8E26E45E7D65 -A7141147D430 -18E3A02B5EFF -E328A1C7156D -8A8D88151A00 -7A86AA203788 -72F96BDD3714 -C76BF71A2509 -1B61B2E78C75 -045CECA15535 -6B07877E2C5C -0CE7CD2CC72B -EA0FD73CB149 -B81F2B0C2F66 -BB52F8CCE07F -46D78E850A7E -E4821A377B75 -8791B2CCB5C4 -D5524F591EED -BAFF3053B496 -0F318130ED18 -42E9B54E51AB -7413B599C4EA -9EA3387A63C1 -B27ADDFB64B0 -E56AC127DD45 -0BE5FAC8B06A -FD8705E721B0 -7259FA0197C6 -22052B480D11 -9D993C5D4EF4 -C65D4EAA645B -0EB23CC8110B -3A8A139C20B4 -19FC84A3784B -0F01CEFF2742 -A3FAA6DAFF67 -BC2D1791DEC1 -7A396F0D633D -ACFFFFFFFFFF -77DABC9825E1 -518DC6EEA089 -044CE1872BC3 -114D6BE9440C -AFCEF64C9913 - +# +# Data from https://pastebin.com/Z7pEeZif +386B4D634A65 +666E564F4A44 +564777315276 +476242304C53 +6A696B646631 +4D3248735131 +425A73484166 +57784A533069 +345547514B4D +4C6B69723461 +4E4175623670 +4D5076656D58 +686A736A356E +484A57696F4A +6F4B6D644178 +744E326B3441 +70564650584F +584F66326877 +6D4E334B6C48 +6A676C315142 +77494C526339 +623055724556 +356D46474348 +4E32336C6E38 +57734F6F6974 +436A46587552 +5544564E6E67 +6F506F493353 +31646241686C +77646B633657 +# +# Data from TransPert +2031D1E57A3B +53C11F90822A +9189449EA24E +# +# data from Github +410B9B40B872 +2CB1A90071C8 +# +# +8697389ACA26 +1AB23CD45EF6 +013889343891 +# +# +0000000018DE +16DDCB6B3F24 +# +# Data from https://pastebin.com/vwDRZW7d +# Vingcard Mifare 4k Staff card +EC0A9B1A9E06 +6C94E1CED026 +0F230695923F +0000014B5C31 +# +# +BEDB604CC9D1 +B8A1F613CF3D +B578F38A5C61 +B66AC040203A +6D0B6A2A0003 +2E641D99AD5B +AD4FB33388BF +69FB7B7CD8EE +# +# Hotel +2A6D9205E7CA +13B91C226E56 +# +# KABA Hotel Locks +2A2C13CC242A +# +# +27FBC86A00D0 +01FA3FC68349 +# +# Smart Rider. Western Australian Public Transport Cards +6D44B5AAF464 +1717E34A7A8A +# +# RFIDeas +6B6579737472 +# +# HID MIFARE Classic 1k Key +484944204953 +204752454154 +# HID MIFARE SO +3B7E4FD575AD +11496F97752A +# +# Luxeo/Aztek cashless vending +415A54454B4D +# +# BQT +321958042333 +# +# Aperio KEY_A Sector 1, 12, 13, 14, 15 Data Start 0 Length 48 +160A91D29A9C +# +# Gallagher +B7BF0C13066E +# +# PIK Comfort Moscow keys (ISBC Mifare Plus SE 1K) +009FB42D98ED +002E626E2820 +# +# Boston, MA, USA Transit - MBTA Charlie Card +3060206F5B0A +5EC39B022F2B +3A09594C8587 +F1B9F5669CC8 +F662248E7E89 +62387B8D250D +F238D78FF48F +9DC282D46217 +AFD0BA94D624 +92EE4DC87191 +B35A0E4ACC09 +756EF55E2507 +447AB7FD5A6B +932B9CB730EF +1F1A0A111B5B +AD9E0A1CA2F7 +D58023BA2BDC +62CED42A6D87 +2548A443DF28 +2ED3B15E7C0F +F66224EE1E89 +# +# +60012E9BA3FA +# +# +DE1FCBEC764B +81BFBE8CACBA +BFF123126C9B +2F47741062A0 +B4166B0A27EA +A170D9B59F95 +400BC9BE8976 +D80511FC2AB4 +1FCEF3005BCF +BB467463ACD6 +E67C8010502D +FF58BA1B4478 +# +# Data from https://pastebin.com/Kz8xp4ev +FBF225DC5D58 +# +# Data https://pastebin.com/BEm6bdAE +# vingcard.txt +# Note: most likely diversified +96A301BCE267 +4708111C8604 +3D50D902EA48 +6700F10FEC09 +7A09CC1DB70A +560F7CFF2D81 +66B31E64CA4B +9E53491F685B +3A09911D860C +8A036920AC0C +361F69D2C462 +D9BCDE7FC489 +0C03A720F208 +6018522FAC02 +# +# Data from https://pastebin.com/4t2yFMgt +# Mifare technische Universität Graz TUG +D58660D1ACDE +50A11381502C +C01FC822C6E5 +0854BF31111E +# +# More keys - Found 8A at Sebel Hotel in Canberra, Australia +AE8587108640 +# +# SafLock standalone door locks +135B88A94B8B +# # Russian Troika card +EC29806D9738 08B386463229 0E8F64340BA4 0F1C63013DBA @@ -587,545 +1059,284 @@ EAAC88E5DC99 F8493407799D 6B8BD9860763 D3A297DC2698 -FBF225DC5D58 -# Strelka extension +# +# Data from reddit +34635A313344 +593367486137 +# +# Keys from Mifare Classic Tool project +044CE1872BC3 +045CECA15535 +0BE5FAC8B06A +0CE7CD2CC72B +0EB23CC8110B +0F01CEFF2742 +0F318130ED18 +114D6BE9440C +18E3A02B5EFF +19FC84A3784B +1B61B2E78C75 +22052B480D11 3367BFAA91DB +3A8A139C20B4 +42E9B54E51AB +46D78E850A7E 4B609876BBA3 -5C83859F2224 -66B504430416 -70D1CF2C6843 +518DC6EEA089 +6B07877E2C5C +7259FA0197C6 +72F96BDD3714 +7413B599C4EA +77DABC9825E1 +7A396F0D633D +7A86AA203788 +8791B2CCB5C4 +8A8D88151A00 8C97CD7A0E56 +8E26E45E7D65 +9D993C5D4EF4 +9EA3387A63C1 +A3FAA6DAFF67 +A7141147D430 +ACFFFFFFFFFF +AFCEF64C9913 +B27ADDFB64B0 +B81F2B0C2F66 B9F8A7D83978 -C4B3BD0ED5F1 -C4D3911AD1B3 -CAD7D4A6A996 -DA898ACBB854 -FEA1295774F9 - -# Moscow public toilets card -807119F81418 -22C8BCD10AAA -0AAABA420191 -E51B4C22C8BC -DBF9F79AB7A2 -34EDE51B4C22 -C8BCD10AAABA -BCD10AAABA42 - -# Moscow social card -2735FC181807 -2ABA9519F574 -84FD7F7A12B6 -186D8C4B93F9 -3A4BBA8ADAF0 -8765B17968A2 -40EAD80721CE -0DB5E6523F7C -51119DAE5216 -83E3549CE42D -136BDB246CAC -2F87F74090D1 -E53EAEFE478F -CE2797E73070 -328A034B93DB -81E1529AE22B -FC55C50E579F -1A72E2337BC3 -5DB52676BE07 -F64FBF085098 -8FE758A8F039 -BB1484CC155D -41990A529AE2 -CD2E9EE62F77 -69C1327AC20B -3C9C0D559DE5 -67BF3880C811 -48A01159A1E9 -2B83FB448CD4 -F24BBB044C94 -7DE02A7F6025 -BF23A53C1F63 -CB9A1F2D7368 -C7C0ADB3284F -9F131D8C2057 -67362D90F973 -6202A38F69E2 -100533B89331 -653A87594079 -D8A274B2E026 -B20B83CB145C -9AFA6CB4FC3D -94F46DB5FD46 -C31C8CD41D65 -BB1684CC155D -CA2393DB246C -1D75E52E76BE -81D9529AE223 -0159C9125AA2 -52AA1B6BB3FB -97EF60A8F031 -6FC73888D011 -3A92FA438BD3 -74CC3D85CD0E -025ACA1B63A3 -AF0878C81151 -9BFB6CB4FC45 -F750C0095199 -075FCF1860A8 -2686EE3F87C7 -277FEF3880C0 -82DA4B93DB1C -9CF46DB5FD46 -93EB64ACF43D - -# Keys from RfidResearchGroup proxmark3 project -# https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_default_keys.dic -0854BF31111E -0C03A720F208 -135B88A94B8B -1FCEF3005BCF -2F47741062A0 -361F69D2C462 -3A09911D860C -3D50D902EA48 -400BC9BE8976 -4708111C8604 -50A11381502C -560F7CFF2D81 -60012E9BA3FA -6018522FAC02 -66B31E64CA4B -6700F10FEC09 -7A09CC1DB70A -81BFBE8CACBA -8A036920AC0C -8A19D40CF2B5 -96A301BCE267 -9E53491F685B -A170D9B59F95 -AE8587108640 -B4166B0A27EA -BB467463ACD6 -BFF123126C9B -C01FC822C6E5 -D58660D1ACDE -D80511FC2AB4 -D9BCDE7FC489 -DE1FCBEC764B -E67C8010502D -FF58BA1B4478 - -C1E51C63B8F5 -4143414F5250 -474249437569 -B0699AD03D17 -B18CDCDE52B7 -3864FCBA5937 -85A438F72A8A -C342F825B01B -C6A76CB2F3B5 -323334353637 -43C7600DEE6B -D01AFEEB890A -26396F2042E7 -F3F0172066B2 -BB320A757099 -00F0BD116D70 -25094DF2C1BD -E41E6199318F -F00DFEEDD0D0 -6D9B485A4845 -71171A82D951 -62711F1A83E9 -1711B1A82E96 -F3864FCCA693 -7B7E752B6A2D -2012053082AD -9AEDF9931EC1 -B9C874AE63D0 -83BAB5ACAD62 -A541538F1416 -4A2B29111213 -D31463A7AB6D -AD5645062534 -B069D0D03D17 -30FFB6B056F5 -D7744A1A0C44 -D1991E71E2C5 -1795902DBAF9 -4243414F5250 -C554EF6A6015 -A5524645CD91 -200306202033 -A00003000084 -CEE3632EEFF5 -F0F0172066B2 -B021669B44BB -3F1A87298691 -A2B2C9D187FB -4B511F4D28DD -E3AD9E9BA5D4 -B3630C9F11C8 -F83466888612 -857464D3AAD1 -A2A3CCA2A3CC -35D850D10A24 -B2F170172066 -0D8CA561BDF3 -05F89678CFCF -850984712F1A -21EDF95E7433 -172066B2F2F0 -6B2F1B017206 -363119000001 -23D4CDFF8DA3 -EF4C5A7AC6FC -123456ABCDEF -8F9B229047AC -E96246531342 -5D293AFC8D7E -AABBCC660429 -63FCA9492F38 -354A787087F1 -40E5EA1EFC00 -675A32413770 -12FD3A94DF0E -C4F271F5F0B3 -4A306E62E9B6 -4CFF128FA3EF -0000085F0000 -0F385FFB6529 -FA38F70215AD -904735F00F9E -B66AC040203A -BCFE01BCFE01 -2FCA8492F386 -237A4D0D9119 -E6849FCC324B -0ED7846C2BC9 -1FB235AC1388 -EA1B88DF0A76 -C9739233861F -89EAC97F8C2A -D964406E67B4 -563A22C01FC8 -DB5181C92CBE -1E352F9E19E5 -6291B3860FC8 -A9A4045DCE77 -434456495243 -B5F454568271 -491CDC863104 -4D8B8B95FDEE -AFBECD121004 -4D48414C5648 -E1DD284379D4 -AFBECD120454 -CFC738403AB0 -0AF7DB99AEE4 -772219470B38 -EF61A3D48E2A -4A4C474F524D -0172066B2F03 -3D5D9996359A -66A163BA82B4 -2011092119F1 -BB2C0007D022 -1494E81663D7 -590BD659CDD2 -A6C028A12FBB -BCF5A6B5E13F -A2F63A485632 -39CF885474DD -D2ECE8B9395E -17505586EF02 -70172066B2F0 -B385EFA64290 -B7C344A36D88 -010000000000 -2F130172066B -DFED39FFBB76 -3F7A5C2DBD81 -DFE73BE48AC6 -FB0B20DF1F34 -913385FFB752 -2066B2F27017 -91FF18E63887 -0734BFB93DAB -97F5DA640B18 -B42C4DFD7A90 -C121FF19F681 -BE7C4F6C7A9A -FE04ECFE5577 -18F34C92A56E -0BB31DC123E5 -0E0E8C6D8EB6 -1CFA22DBDFC3 -0F1A81C95071 -AA4D051954AC -9F9D8EEDDCCE -863FCB959373 -98631ED2B229 -A23456789123 -833FBD3CFE51 -AB28A44AD5F5 -74A386AD0A6D -4C60F4B15BA8 -022FE48B3072 -97271231A83F -385EFA542907 -066B2F230172 -BA729428E808 -BDF837787A71 -A05DBD98E0FC -395244733978 -9B1DD7C030A1 -2C9F3D45BA13 -1DB710648A65 -E65B66089AFC -A85198481331 -5A12F83326E7 -A7D71AC06DC2 -64E2283FCF5E -FFFFAE82366C -10F3BEBC01DF +BAFF3053B496 +BB52F8CCE07F +BC2D1791DEC1 +BC4580B7F20B +C65D4EAA645B +C76BF71A2509 +D5524F591EED +E328A1C7156D +E4821A377B75 +E56AC127DD45 +EA0FD73CB149 +FC0001877BF7 +FD8705E721B0 00ADA2CD516D -1D28C58BBE8A -6936C035AE1B -AC45AD2D620D -64A2EE93B12B -A9F95891F0A4 -E45230E7A9E8 -A7FB4824ACBF -223C3427108A -58AC17BF3629 -535F47D35E39 -10F2BBAA4D1C -A0004A000036 -3F3865FCCB69 -0B0172066B2F -4098653289D3 -BA28CFD15EE8 -A22647F422AE -99858A49C119 -29173860FC76 -1A80B93F7107 -1A2B3C4D5E6F -2C60E904539C -6C9EC046C1A4 -FC9839273862 -1C1532A6F1BC -09800FF94AAF +518108E061E2 +558AAD64EB5B +001122334455 +6CA761AB6CA7 +B1C4A8F7F6E3 +FF75AFDA5A3C +FCDDF7767C10 +A6B3F6C8F1D4 +# +# +237A4D0D9119 +0ED7846C2BC9 FFFFD06F83E3 -0B83797A9C64 -13B91C226E56 -A4EF6C3BB692 -000000270000 -A00002000021 -872B71F9D15A -A37A30004AC9 -B1A862985913 -A4CDFF3B1848 -2E641D99AD5B -827ED62B31A7 -CD212889C3ED -B1A80C94F710 -CB911A1A1929 -A844F4F52385 -C0BEEFEC850B -5C8FF9990DA2 -160F4B7AB806 -B8937130B6BA -66B2F1F01720 -82D58AA49CCB -A9B43414F585 -C38197C36420 -0172066B2F33 -434143445649 -34B16CD59FF8 -5A7A52D5E20D -6471A5EF2D1A -F57F410E18FF -3B0172066B2F -E907470D31CC -B8457ACC5F5D -67CC03B7D577 -A8844B0BCA06 -435330666666 -B47058139187 -46868F6D5677 -C27D999912EA -37FC71221B46 -F97371271A84 -AE43F36C1A9A -5EC7938F140A -AA734D2F40E0 -A5A4A3A2A1A0 -70172066B2F3 -03EA4053C6ED -06FF5F03AA1A -5554AAA96321 -0120BF672A64 -87291F3861FC -9EBC3EB37130 -B4C36C79DA8D -43CA22C13091 -6D0B6A2A0003 -FB6C88B7E279 -013940233313 -7DD399D4E897 -ED3A7EFBFF56 -68F9A1F0B424 -6476FA0746E7 -1A8619858137 -1131A81D9507 -8268046CD154 -4857DD68ECD9 -B62307B62307 -C6C866AA421E -F66224EE1E89 -4ECCA6236400 -72066B2F2B01 -34D3C568B348 -000131B93F28 -419A13811554 -B6323F550F54 +FFFFAE82366C F89C86B2A961 -B268F7C9CA63 -B8B1CFA646A8 -4D57414C5648 -6A0E215D1EEB -70758FDD31E0 +F83466888612 +ED3A7EFBFF56 +E96246531342 +E1DD284379D4 +DFED39FFBB76 +DB5181C92CBE +CFC738403AB0 +BCFE01BCFE01 +BA28CFD15EE8 +B0699AD03D17 +AABBCC660429 +A4EF6C3BB692 +A2B2C9D187FB +9B1DD7C030A1 +9AEDF9931EC1 +8F9B229047AC +872B71F9D15A +833FBD3CFE51 +5D293AFC8D7E +5554AAA96321 +474249437569 +435330666666 +1A2B3C4D5E6F +123456ABCDEF +83BAB5ACAD62 +64E2283FCF5E +64A2EE93B12B +46868F6D5677 +40E5EA1EFC00 37D4DCA92451 -444156494442 -B210CFA436D2 -207FFED492FD -7578BF2C66A9 -50983712B1A8 -5A85536395B3 -B81846F06EDF -842146108088 +2012053082AD +2011092119F1 +200306202033 +1795902DBAF9 +17505586EF02 +022FE48B3072 +013940233313 +# +# Hotel Adina +9EBC3EB37130 +# +# Misc. keys from hotels & library cards in Germany +914f57280ce3 +324a82200018 +370aee95cd69 +2e032ad6850d +1feda39d38ec +288b7a34dbf8 +0965e3193497 +18c628493f7f +064d9423938a +995fd2a2351e +7c7d672bc62e +217250fb7014 +ae7478ccaee7 +abbf6d116eaf +05862c58edfb +e43b7f185460 +6a59aa9a959b +b79e5b175227 +7bc9ebb8274b +b2afbf2331d4 +223e5847dd79 +640524d2a39b +aee297cb2fd6 +3da5dfa54604 +0cf1a2aa1f8d +# +# most likely diversifed individual keys. +# data from https://github.com/korsehindi/proxmark3/commit/24fdbfa9a1d5c996aaa5c192bc07e4ab28db4c5c +491CDC863104 +A2F63A485632 +98631ED2B229 19F1FFE02563 -D3B595E9DD63 +# +# Argentina +563A22C01FC8 +43CA22C13091 +25094DF2C1BD +# +# OMNITEC.ES HOTEL TIMECARD / MAINTENANCECARD +AFBECD120454 +# +# OMNITEC.ES HOTEL EMERGENCYCARD +842146108088 +# +# TAPCARD PUBLIC TRANSPORT LA +EA1B88DF0A76 +D1991E71E2C5 +05F89678CFCF +D31463A7AB6D +C38197C36420 +772219470B38 +1C1532A6F1BC +FA38F70215AD +E907470D31CC +160F4B7AB806 +1D28C58BBE8A B3830B95CA34 -A506370E7C0F +6A0E215D1EEB +E41E6199318F +C4F271F5F0B3 +1E352F9E19E5 +0E0E8C6D8EB6 +C342F825B01B +CB911A1A1929 +E65B66089AFC +B81846F06EDF +37FC71221B46 880C09CFA23C -43454952534E -39AD2963D3D1 +6476FA0746E7 +419A13811554 +2C60E904539C +4ECCA6236400 +10F2BBAA4D1C +4857DD68ECD9 +C6A76CB2F3B5 +E3AD9E9BA5D4 +6C9EC046C1A4 +# +# ROC HIGHSCHOOL ACCESSCARD +B021669B44BB +B18CDCDE52B7 +A22647F422AE +B268F7C9CA63 +A37A30004AC9 +B3630C9F11C8 +A4CDFF3B1848 +B42C4DFD7A90 +A541538F1416 +B5F454568271 +A6C028A12FBB +B6323F550F54 +A7D71AC06DC2 +B7C344A36D88 +A844F4F52385 +B8457ACC5F5D +A9A4045DCE77 B9B8B7B6B5B3 -82908B57EF4F - -C67BEB41FFBF -2AFFD6F88B97 -E77952748484 -988ACDECDFB0 -605F5E5D5C5B -42EF7BF572AB -4087C6A75A96 -AADE86B1F9C1 -5EA088C824C9 -120D00FFFFFF -CA679D6291B0 -E2A9E88BFE16 -0A4600FF00FF -43B04995D234 -0602721E8F06 -5F31F6FCD3A0 -4AE23A562A80 -A0974382C4C5 -91C2376005A1 -FEE2A3FBC5B6 -2602FFFFFFFF -CA3A24669D45 -A9F3F289B70C -B84D52971107 -274E6101FC5E -00DD300F4F10 -F7BA51A9434E -4A832584637D -B16B2E573235 -A82045A10949 -FC0B50AF8700 -403F09848B87 -DFF293979FA7 -4118D7EF0902 -30B7680B2BC9 -52B0D3F6116E -5296C26109D4 -DB6819558A25 -4D6F62692E45 -0406080A0C0E -6130DFA578A0 -30D9690FC5BC -D73438698EEA -005078565703 - -7C87013A648A -9E7168064993 -45FEE09C1D06 -734EBE504CE8 -E592ED478E59 -C229CE5123D5 -240F0BB84681 -D8BA1AA9ABA0 -865B6472B1C0 -974A36E2B1BA -57D83754711D -C9CD8D7C65E5 -C197AE6D6990 -AABAFFCC7612 -C0AD1B72921A -AFAAFCC40DEC -E902395C1744 -DAC7E0CBA8FD -755D49191A78 -68D3263A8CD6 -2F8A867B06B4 -7357EBD483CC -ABCC1276FCB0 -26BF1A68B00F -704A81DDACED -E8794FB14C63 -EC070A52E539 -037F64F470AD -76939DDD9E97 -4D80A10649DF -89E00BC444EF -26107E7006A0 -B1D3BC5A7CCA -ECC58C5D34CA -9F97C182585B -B2FE3B2875A6 -B70B1957FE71 -E495D6E69D9C -0860318A3A89 -4051A85E7F2D -17D071403C20 -3BF391815A8D -1927A45A83D3 -CE7712C5071D -F3C1F1DB1D83 -D0DDDF2933EC - -# Iron Logic -A3A26EF4C6B0 -2C3FEAAE99FC -E85B73382E1F -F4ED24C2B998 -CB574C6D3B19 -E092081D724B -B38D82CF7B6C -8228D2AA6EFA -2C7E983588A3 -CF7A7B77E232 -32A7F5EAF87D -7453A687B5F0 -01A0C008A5B9 -DEC0CEB0CE24 -413BED2AE45B -D6261A9A4B3F -CB9D507CE56D - +AA4D051954AC +BA729428E808 +AB28A44AD5F5 +BB320A757099 +AC45AD2D620D +BCF5A6B5E13F +AD5645062534 +BDF837787A71 +AE43F36C1A9A +BE7C4F6C7A9A +5EC7938F140A +82D58AA49CCB +# +# MELON CARD +323334353637 +# +# +CEE3632EEFF5 +827ED62B31A7 +03EA4053C6ED +C0BEEFEC850B +F57F410E18FF +0AF7DB99AEE4 +A7FB4824ACBF +207FFED492FD +1CFA22DBDFC3 +30FFB6B056F5 +39CF885474DD +00F0BD116D70 +4CFF128FA3EF +10F3BEBC01DF +# +# Transportes Insular La Palma +0172066B2F03 +0000085F0000 +1A80B93F7107 +70172066B2F0 +B1A80C94F710 +0B0172066B2F +0F1A81C95071 +F0F0172066B2 +1131A81D9507 +2F130172066B +71171A82D951 +B2F170172066 +1711B1A82E96 +6B2F1B017206 +62711F1A83E9 +66B2F1F01720 +97271231A83F +066B2F230172 +F97371271A84 +2066B2F27017 +50983712B1A8 +72066B2F2B01 +850984712F1A +172066B2F2F0 +A85198481331 +0172066B2F33 +1A8619858137 +70172066B2F3 +B1A862985913 +3B0172066B2F +3F1A87298691 +F3F0172066B2 +# # Tehran ezpay 38A88AEC1C43 CBD2568BC7C6 @@ -1142,138 +1353,404 @@ D3B1C7EA5C53 604AC8D87C7E 8E7B29460F12 BB3D7B11D224 - -# More keys from the PM3 repo -DC018FC1D126 -C428C4550A75 -0C4233587119 -5B0C7EC83645 -540D5E6355CC -35C649004000 -CFE63749080A -6307417353C1 -411053C05273 -749934CC8ED3 -1C68315674AC -35D152154017 -D1417E431949 -26B85DCA4321 -D973D917A4C7 -3A471B2192BF -534F4C303232 -730956C72BC2 -C9449301AF93 -F678905568C3 -4578ABFEDC12 -075D1A4DD323 -43E69C28F08C -0F35D5660653 -F7FA2F629BB1 -5145C34DBA19 -124578ABFEDC -E2F14D0A0E28 -C8AACD7CF3D1 -9C616585E26D -4927C97F1D57 -6F30126EE7E4 -155332417E00 -5353B3AECB53 -361A62F35BC9 -00460740D722 -A9B018868CC1 -2E71D3BD262A -4F75030AD12B -42454C4C4147 -D75971531042 -25352912CD8D -51E97FFF51E9 -1170553E4304 -D1F71E05AD9D -541C417E57C0 -AE76242931F1 -6039ABB101BB -0E620691B9FE -4BF6DE347FB6 -10510049D725 -1F0128447C00 -D14E615E0545 -94B6A644DFF6 -81B20C274C3F -66695A45C9FA -130662240200 -DD0DE3BA08A6 -05F5EC05133C -4FA9EB49F75E -C1E6F8AFC9EC -28D70900734C -32CA52054416 -703265497350 -3D923EB73534 -C151D998C669 +# +# Chaco +B210CFA436D2 +B8B1CFA646A8 +A9F95891F0A4 +# +# Keys from APK application "Scan Badge" +4A4C474F524D +444156494442 +434143445649 +434456495243 +A00002000021 +EF61A3D48E2A +A23456789123 +010000000000 +363119000001 +A00003000084 +675A32413770 +395244733978 +A0004A000036 +2C9F3D45BA13 +4243414F5250 +DFE73BE48AC6 +# +# +B069D0D03D17 +000131B93F28 +# +# From the DFW Area, TX, USA +A506370E7C0F +26396F2042E7 +70758FDD31E0 +9F9D8EEDDCCE +06FF5F03AA1A +4098653289D3 +904735F00F9E +B4C36C79DA8D +68F9A1F0B424 +5A85536395B3 +7DD399D4E897 +EF4C5A7AC6FC +B47058139187 +8268046CD154 +67CC03B7D577 +# +# From the HTL Mödling, NÖ, AT +A5524645CD91 +D964406E67B4 +99858A49C119 +7B7E752B6A2D +C27D999912EA +66A163BA82B4 +4C60F4B15BA8 +# +# CAFE + CO, AT +35D850D10A24 +4B511F4D28DD +E45230E7A9E8 +535F47D35E39 +FB6C88B7E279 +# +# Metro Card, AT +223C3427108A +# +# Unknown, AT +23D4CDFF8DA3 +E6849FCC324B +12FD3A94DF0E +# +# Unknown, AT +0B83797A9C64 +39AD2963D3D1 +# +# Hotel Berlin Classic room A KEY +34B16CD59FF8 +# +# Hotel Berlin Classic room B KEY +BB2C0007D022 +# +# Coinmatic laundry Smart card +# data from: https://pastebin.com/XZQiLtUf +0734BFB93DAB +85A438F72A8A +# +# Data from forum, Chinese hotel +58AC17BF3629 +B62307B62307 +# +# +A2A3CCA2A3CC +# +# Granada, ES Transport Card +000000270000 +0F385FFB6529 +29173860FC76 +2FCA8492F386 +385EFA542907 +3864FCBA5937 +3F3865FCCB69 +6291B3860FC8 +63FCA9492F38 +863FCB959373 +87291F3861FC +913385FFB752 +B385EFA64290 +C9739233861F +F3864FCCA693 +FC9839273862 +# +# various hotel keys +34D3C568B348 +91FF18E63887 +4D8B8B95FDEE +354A787087F1 +4A306E62E9B6 +B9C874AE63D0 +# +# Data from official repo +F00DFEEDD0D0 +0BB31DC123E5 +7578BF2C66A9 +CD212889C3ED +6936C035AE1B +C6C866AA421E +590BD659CDD2 +AA734D2F40E0 +09800FF94AAF +5A12F83326E7 +C554EF6A6015 +0D8CA561BDF3 +B8937130B6BA +D7744A1A0C44 +82908B57EF4F +FE04ECFE5577 +# +# comfort inn hotel +4D57414C5648 +4D48414C5648 +# +# unknown hotel key +6D9B485A4845 +# +# Bosch Solution 6000 +5A7A52D5E20D +# +# Found in TagInfo app +# RATB key +C1E51C63B8F5 +1DB710648A65 +# E-GO card key +18F34C92A56E +# +# Library Card MFP - SL1 +4A832584637D +CA679D6291B0 +30D9690FC5BC +5296C26109D4 +E77952748484 +91C2376005A1 +30B7680B2BC9 +E2A9E88BFE16 +43B04995D234 +AADE86B1F9C1 +5EA088C824C9 +C67BEB41FFBF +B84D52971107 +52B0D3F6116E +# +# Data from https://pastebin.com/cLSQQ9xN +CA3A24669D45 +4087C6A75A96 +403F09848B87 +D73438698EEA +5F31F6FCD3A0 +A0974382C4C5 +A82045A10949 +# +# Data from https://pastebin.com/2iV8h93h +# +# funnivarium +# forum ankara +2602FFFFFFFF +# +# macera adasi +# ankara kentpark +# INACTIVE +0A4600FF00FF +DFF293979FA7 +4D6F62692E45 +4118D7EF0902 +# +# petrol ofisi +# positive card +# ode-gec +0406080A0C0E +# +# konya elkart +988ACDECDFB0 +120D00FFFFFF +# +# bowlingo +# serdivan avym +4AE23A562A80 +# +# kart 54 +2AFFD6F88B97 +A9F3F289B70C +DB6819558A25 +6130DFA578A0 +B16B2E573235 +42EF7BF572AB +274E6101FC5E +# +# crazy park +# kizilay avm +00DD300F4F10 +# +# kartsistem B +FEE2A3FBC5B6 +# +# toru ent +# taurus avm +005078565703 +# +# Ving? +0602721E8F06 +FC0B50AF8700 +F7BA51A9434E +# +# eskart +# eskisehir transport card +E902395C1744 +4051A85E7F2D +7357EBD483CC +D8BA1AA9ABA0 +76939DDD9E97 +3BF391815A8D +# +# muzekart +# museum card for turkey +7C87013A648A +E8794FB14C63 +9F97C182585B +EC070A52E539 +C229CE5123D5 +E495D6E69D9C +26BF1A68B00F +B1D3BC5A7CCA +734EBE504CE8 +974A36E2B1BA +C197AE6D6990 +4D80A10649DF +037F64F470AD +C9CD8D7C65E5 +B70B1957FE71 +CE7712C5071D +C0AD1B72921A +45FEE09C1D06 +E592ED478E59 +F3C1F1DB1D83 +704A81DDACED +89E00BC444EF +AFAAFCC40DEC +ECC58C5D34CA +57D83754711D +D0DDDF2933EC +240F0BB84681 +9E7168064993 +2F8A867B06B4 +# +# bursakart +# bursa transport card +755D49191A78 +DAC7E0CBA8FD +68D3263A8CD6 +865B6472B1C0 +0860318A3A89 +1927A45A83D3 +B2FE3B2875A6 +# +# playland +# maltepe park +ABCC1276FCB0 +AABAFFCC7612 +# +# lunasan +# kocaeli fair +26107E7006A0 +# +# gamefactory +# ozdilek +17D071403C20 +# +# 534F4C415249 -70C714869DC7 -A7395CCB42A0 -89AA9D743812 -A160FCD5EC4C -9DCDB136110C -9951A273DEE7 -AA0857C641A3 -F1A1239A4487 -B882FD4A9F78 -9386E2A48280 -460661C93045 -EF1232AB18A0 -6285A1C8EB5C -C41514DEFC07 -ABFEDC124578 -046154274C11 -5429D67E1F57 -# SMARTair Key B -E7316853E731 -CD7FFFF81C4A -F253C30568C4 -E7D6064C5860 -506DB955F161 -8223205047B6 -070D486BC555 -D4B2D140CB2D -0C734F230E13 -2E4169A5C79D -69D92108C8B5 -A297CEB7D34B +534F4C303232 +# +# Nespresso, smart card +# key-gen algo, these keys are for one card (keys diversified) FF9A84635BD2 -735175696421 -5D0762D13401 -D61707FFDFB1 -2803BCB0C7E1 -C52876869800 -424C0FFBF657 -AF9E38D36582 -B32464412EE3 -50240A68D1D8 -6B13935CD550 -83F3CB98C258 -521B517352C7 -4BB747E48C2A -5E594208EF02 -FFFFFF545846 -D65561530174 -52750A0E592A -112233445566 -2DADE48942C5 -A7765C952DDF -2CA4A4D68B8E -72B458D60363 -F088A85E71D7 -FF94F86B09A6 -B27CCAB30DBD -89ECA97F8C2A -E00000000000 +6F30126EE7E4 +6039ABB101BB +F1A1239A4487 +# +# +B882FD4A9F78 +CD7FFFF81C4A +AA0857C641A3 +C8AACD7CF3D1 9FFDA233B496 +26B85DCA4321 +D4B2D140CB2D +A7395CCB42A0 +541C417E57C0 +D14E615E0545 +69D92108C8B5 +703265497350 +D75971531042 +10510049D725 +35C649004000 +5B0C7EC83645 +05F5EC05133C +521B517352C7 +94B6A644DFF6 +2CA4A4D68B8E +A7765C952DDF +E2F14D0A0E28 +DC018FC1D126 +4927C97F1D57 +046154274C11 +155332417E00 +6B13935CD550 +C151D998C669 +D973D917A4C7 +130662240200 +9386E2A48280 +52750A0E592A +075D1A4DD323 +32CA52054416 +460661C93045 +5429D67E1F57 +0C734F230E13 +1F0128447C00 +411053C05273 +42454C4C4147 +C428C4550A75 +730956C72BC2 +28D70900734C +4F75030AD12B +6307417353C1 +D65561530174 +D1F71E05AD9D +F7FA2F629BB1 +0E620691B9FE +43E69C28F08C +735175696421 +424C0FFBF657 +51E97FFF51E9 +E7316853E731 +00460740D722 +35D152154017 +5D0762D13401 +0F35D5660653 +1170553E4304 +0C4233587119 +F678905568C3 +50240A68D1D8 +2E71D3BD262A +540D5E6355CC +D1417E431949 +4BF6DE347FB6 +# +# +3A471B2192BF +A297CEB7D34B +AE76242931F1 +# +# +124578ABFEDC +ABFEDC124578 +4578ABFEDC12 +# +# Data from +# premier inn hotel chain +5E594208EF02 +AF9E38D36582 +# +# Norwegian building site identication card. (HMS KORT) +# Key a 10DF4D1859C8 +# +# Key B B5244E79B0C8 +# +# Ukraine hotel F5C1C4C5DE34 - +# +# Data from Mifare Classic Tool repo # Rotterdam University of applied sciences campus card BB7923232725 A95BD5BB4FC5 @@ -1297,27 +1774,406 @@ B5ADEFCA46C4 BF3FE47637EC B290401B0CAD AD11006B0601 - -# Keys of Armenian underground ticket -A0A1A2A8A4A5 +# +# Data from Mifare Classic Tool repo +# Armenian Metro +E4410EF8ED2D +6A68A7D83E11 0D6057E8133B D3F3B958B8A3 -6A68A7D83E11 -7C469FE86855 -E4410EF8ED2D 3E120568A35C -CE99FBC8BD26 2196FAD8115B - -# PIK Comfort Moscow keys (ISBC Mifare Plus SE 1K) -009FB42D98ED -002E626E2820 - -# Volgograd (Russia) Volna transport cards keys -2B787A063D5D -D37C8F1793F7 - +7C469FE86855 +CE99FBC8BD26 +# +# keys from Eurothermes group (Switzerland) +D66D91829013 +75B691829013 +83E391829013 +A23C91829013 +E46A91829013 +D9E091829013 +FED791829013 +155F91829013 +06CC91829013 +8DDC91829013 +54AF91829013 +29A791829013 +668091829013 +00008627C10A +# +# easycard +310D51E539CA +2CCDA1358323 +03E0094CEDFE +562E6EF73DB6 +F53E9F4114A9 +AD38C17DE7D2 +# +# SUBE cards keys (new) +2DEB57A3EA8F +32C1BB023F87 +70E3AD3F2D29 +202ECDCCC642 +3686192D813F +24501C422387 +2C7813A721C3 +FFE04BE3D995 +D28F090677A1 +DE2D83E2DCCC +A66A478712EA +643232ADB2D5 +C7F4A4478415 +95C013B70D99 +3C383889362A +3C6D9C4A90FA +51BEDBA005E5 +74BF7363F354 +53B09DB89111 +E98075318085 +2F904641D75F +7F60AEF68136 +F5C1B3F62FDA +3E6E5713BA10 +8B75A29D4AB2 +7E6545076619 +# +# SUBE cards keys (old) +4C5A766DFE3A +32C6768847F5 +F68930789631 +8B42B6D64B02 +B627A3CB13F8 +562A4FB8260B +88DDC24E1671 +91CB7802A559 +7A3E0F5B63FC +8CA2C9DC8292 +5CCC6D50EAAC +DE4F5AA9A7F3 +52D0145E1AF5 +C10F92A4E57E +7D6E7AF43C97 +DE1E7D5F6DF1 +F4CB751B031A +C54474936B59 +2A1F900D4533 +6303CDCBB233 +F115E91357B3 +BFE25035B0C8 +62FF943EB069 +7C82EF592001 +D5C172325DD3 +992B152E834A +CE75D7EADEAF +# +# Russian Podorozhnik card (Saint-Petersburg transport) +# may be combined with Troika +038B5F9B5A2A +04DC35277635 +0C420A20E056 +152FD0C420A7 +296FC317A513 +29C35FA068FB +31BEC3D9E510 +462225CD34CF +4B7CB25354D3 +5583698DF085 +578A9ADA41E3 +6F95887A4FD3 +7600E889ADF9 +86120E488ABF +8818A9C5D406 +8C90C70CFF4A +8E65B3AF7D22 +9764FEC3154A +9BA241DB3F56 +AD2BDC097023 +B0A2AAF3A1BA +B69D40D1A439 +C956C3B80DA3 +CA96A487DE0B +D0A4131FB290 +D27058C6E2C7 +E19504C39461 +FA1FBB3F0F1F +FF16014FEFC7 +# +# Food GEM +6686FADE5566 +# +# Samsung Data Systems (SDS) — Electronic Locks +# Gen 1 S10 KA/KB is FFFFFFFFFFFF, incompatible with Gen 2 locks +# +# SDS Gen 2 S10 KB +C22E04247D9A +# +# Data from Discord, French pool +# SDS Gen 2 S10 KA +9B7C25052FC3 +494446555455 +# +# Data from Discord, seems to be related to ASSA +427553754D47 +# Keys found on Edith Cowan University Smart Riders +9A677289564D +186C59E6AFC9 +DDDAA35A9749 +9D0D0A829F49 +# Mercator Pika Card, Slovenia +97D77FAE77D3 +5AF445D2B87A +# +# Vilniečio/JUDU kortelė, Lithuania +# A +16901CB400BC +F0FE56621A42 +8C187E78EE9C +FE2A42E85CA8 +# B +6A6C80423226 +F4CE4AF888AE +307448829EBC +C2A0105EB028 +# +# Keys from Flipper Zero Community +# Last update: Aug 13, 2022 +# +# unknown if keys are diversified or static default +# +# Strelka Extension +5C83859F2224 +66B504430416 +70D1CF2C6843 +C4B3BD0ED5F1 +C4D3911AD1B3 +CAD7D4A6A996 +DA898ACBB854 +FEA1295774F9 +# +# Moscow Public Toilets Card +807119F81418 +22C8BCD10AAA +0AAABA420191 +E51B4C22C8BC +DBF9F79AB7A2 +34EDE51B4C22 +C8BCD10AAABA +BCD10AAABA42 +# +# Moscow Social Card +2F87F74090D1 +E53EAEFE478F +CE2797E73070 +328A034B93DB +81E1529AE22B +FC55C50E579F +1A72E2337BC3 +5DB52676BE07 +F64FBF085098 +8FE758A8F039 +BB1484CC155D +41990A529AE2 +CD2E9EE62F77 +69C1327AC20B +3C9C0D559DE5 +67BF3880C811 +48A01159A1E9 +2B83FB448CD4 +F24BBB044C94 +94F46DB5FD46 +C31C8CD41D65 +BB1684CC155D +CA2393DB246C +1D75E52E76BE +81D9529AE223 +0159C9125AA2 +52AA1B6BB3FB +97EF60A8F031 +6FC73888D011 +3A92FA438BD3 +74CC3D85CD0E +025ACA1B63A3 +AF0878C81151 +9BFB6CB4FC45 +F750C0095199 +075FCF1860A8 +2686EE3F87C7 +277FEF3880C0 +82DA4B93DB1C +9CF46DB5FD46 +93EB64ACF43D +# +# Iron Logic RU +A3A26EF4C6B0 +2C3FEAAE99FC +E85B73382E1F +F4ED24C2B998 +CB574C6D3B19 +E092081D724B +B38D82CF7B6C +8228D2AA6EFA +2C7E983588A3 +CF7A7B77E232 +32A7F5EAF87D +7453A687B5F0 +01A0C008A5B9 +DEC0CEB0CE24 +413BED2AE45B +D6261A9A4B3F +CB9D507CE56D +# +# Armenian Underground Ticket +A0A1A2A8A4A5 +# +# Badge Maker Leaked from https://github.com/UberGuidoZ +1A1B1C1D1E1F +1665FE2AE945 +158B51947A8E +E167EC67C7FF +D537320FF90E +5E56BFA9E2C9 +F81CED821B63 +C81584EF5EDF +9551F8F9259D +36E1765CE3E8 +509052C8E42E +776C9B03BE71 +C608E13ADD50 +BEE8B345B949 +ED0EC56EEFDD +9716D5241E28 +05D1FC14DC31 +3321FB75A356 +F22A78E29880 +EC211D12C98D +8CCA8F62A551 +B637E46AD674 +39605B3C8917 +3882719778A1 +9F27D36C4230 +DB32A6811327 +8AA8544A2207 +8C5819E780A4 +7549E90353A2 +2E52ABE0CE95 +E46210ED98AB +61D030C0D7A8 +18E20102821E +DA59354DFB88 +040047C12B75 +D10008074A6F +686E736F6E20 +446176696453 +6F6674776172 +6520446F7665 +# +# Apartment keyfobs (USA) (Corvette830) +E60F8387F0B9 +FFD46FF6C5EE +4F9661ED2E70 +576A798C9904 +1C5179C4A8A1 +16CA203B811B +11AC8C8F3AF2 +# +# The Westin Jakarta Indonesia (D4DB0D) +# Peppers Hotel Unknown location (D4D0D) +6E0DD4136B0A +141940E9B71B +3B1D3AAC866E +95E9EE4CCF8F +FEA6B332F04A +BE0EC5155806 +0500D6BFCC4F +FC5AC7678BE3 +F09BB8DD142D +B4B3FFEDBE0A +540E0D2D1D08 +# +# Schlage 9691T Keyfob (seasnaill) +7579B671051A +4F4553746B41 +# +# Vigik ScanBadge App (fr.badgevigik.scanbadge) +# Website https://badge-vigik.fr/ (Alex) +0000A2B3C86F +021200C20307 +021209197507 +1E34B127AF9C +303041534956 +4143532D494E +41454E521985 +43412D627400 +455249524345 +456666456666 +45B722C63319 +484585414354 +4D414C414741 +536563644C65 +57D27B730760 +593DD8FE167A +6472616E7265 +65626F726369 +680E95F3C287 +709BA7D4F920 +8829DAD9AF76 +92D0A0999CBA +948EE7CFC9DB +9EB7C8A6D4E3 +A22AE12C9013 +AFC984A3576E +# +# Vigik verified by quantum-x +# https://github.com/RfidResearchGroup/proxmark3/pull/1742#issuecomment-1206113976 +A00027000099 +A00016000028 +A00003000028 +A0000F000345 +A00001000030 +A00002000086 +A00002000036 +A00002000088 +A00000000058 +A00000000096 +A00000000008 +A00000043D79 +A00000000064 +A00025000030 +A00003000057 +# +# BH USA 2013 conference +012279BAD3E5 +# +# iGuard Simple (and reverse) keys +AAAAAAFFFFFF +FFFFFFAAAAAA +# +# Random Hotel A Key Sec 0 Blk 3 - KABA Lock (VideoMan) +3111A3A303EB +# Transport system Uruguay - STM +# Shared key - sec 0 blk 3 +D144BD193063 +# +# Data from http://www.proxmark.org/forum/viewtopic.php?pid=45659#p45659 +3515AE068CAD +# +# Keys Catering +6A0D531DA1A7 +4BB29463DC29 +# +# Keys Swim +8627C10A7014 +453857395635 +# +# Unknown hotel system Sec 0 / A +353038383134 +# +# Brazil transport Sec 8 / A +50d4c54fcdf5 +# # Bandai Namco Passport [fka Banapassport] / Sega Aime Card +# Dumped on the Flipper Devices Discord Server 6090D00632F5 019761AA8082 574343467632 @@ -1351,7 +2207,551 @@ E69DD9015A43 C8382A233993 7B304F2A12A6 FC9418BF788B +# +# Guest Cashless Prepaid Arcade Payment Cards +168168168168 +198407157610 +4E4F584D2101 +4E4F584D2105 +686B35333376 +861861861861 +# +# Transport System Cracow / Polen +B071A76BA2E9 +B3A181BCA5F2 +3225942F7717 +80D00703C5FB +6DD510E080B1 +87529F30FC58 +B75C4FA614AE +42DC568C64F4 +# Data from "the more the marriott" mifare project (colonelborkmundus) +# aka The Horde +# +# These keys seem to be from Vingcard / Saflok system which means they are diversified +# and not static default keys. To verify this, the UID from such a card is needed. +# +# 20230125-01, Elite Member Marriott Rewards +43012BD9EB87 +# 20230125-02, Elite Member Marriott Rewards +3119A70628EB +# 20230125-03, Elite Member Marriott Rewards +23C9FDD9A366 +# 20230125-04, Elite Member Marriott Rewards +7B4DFC6D6525 +# 20230125-05, Elite Member Marriott Rewards +1330824CD356 +# 20230125-06, Elite Member Marriott Rewards +30AAD6A711EF +# 20230125-07, Fairfield Inn & Suites Marriott +7B3B589A5525 +# 20230125-08, Moxy Hotels +20C166C00ADB +# 20230125-09, Westin Hotels & Resorts +7D0A1C277C05 +2058580A941F +8C29F8320617 +# 20230125-10, Westin Hotels & Resorts +C40964215509 +D44CFC178460 +5697519A8F02 +# 20230125-12, AC Hotels Marriott +7B56B2B38725 +# 20230125-13, AC Hotels Marriott +8EA8EC3F2320 +# 20230125-14, Waldorf Astoria Chicago +011C6CF459E8 +# 20230125-24, Aria Resort & Casino +A18D9F4E75AF +# 20230125-25, Aria Resort & Casino +316B8FAA12EF +# 20230125-26, Residence Inn Mariott +3122AE5341EB +# 20230125-27, Residence Inn Mariott +F72CD208FDF9 +# 20230125-28, Marriott +035C70558D7B +# 20230125-29, Marriott +12AB4C37BB8B +# 20230125-30, Marriott +9966588CB9A0 +# 20230125-31, Sheraton +42FC522DE987 +# 20230125-32, The Industrialist +2158E314C3DF +# 20230125-39, The Ritz-Carlton Balharbour +30FB20D0EFEF +# 20230125-40, The Ritz-Carlton Balharbour +66A3B064CC4B +# 20230125-41, The Ritz-Carlton Balharbour +D18296CD9E6E +# 20230125-42, The Ritz-Carlton Balharbour +D20289CD9E6E +# 20230125-44, Graduate Hotels +209A2B910545 +C49DAE1C6049 +# 20230125-46, AmericInn +8AC04C1A4A25 +# 20230129-53, Marriott Bonvoy +6E029927600D +3E173F64C01C +C670A9AD6066 +# 20230413-69, Westin +487339FA02E0 +# 20230413-70, Marriott Bonvoy +DBD5CA4EE467 +A0B1F234006C +180DE12B700E +# 20230413-71, Westin +1352C68F7A56 +# 20230413-76, Ritz Carlton +318BD98C1CEF +# 20230413-77, Marriott +D23C1CB1216E +# 20230413-78, Caesars +A1D92F808CAF +# 20230413-79, The Cosmopolitan, Vegas +# 20230413-80, Aria +1153C319B4F8 +# 20230413-81, Aria +110C819BBEF8 +# 20230413-82, Aria +1332117E8756 +# 20230413-83, Kimpton +500AE915F50A +5032E362B484 +8B63AB712753 +# 20230413-85, Kimpton +06106E187106 +2E45C23DC541 +D9FF8BEE7550 +# 20230413-87, Marriott +42F7A186BF87 +# 20230413-88, Meritage Resort +D213B093B79A +# 20230413-89, Meritage Resort +216024C49EDF +# 20230413-90, Gaylord Palms +D201DBB6AB6E +# 20230413-91, Residence Inn +9F4AD875BB30 +# 20230413-92, Marriott +3352DB1E8777 +# 20230413-94, Marriott +09074A146605 +151F3E85EC46 +# +# Travelodge by Wyndham Berkeley +0000FFFFFFFF +4663ACD2FFFF +EDC317193709 +# Hotel Santa Cruz +75FAB77E2E5B +# saflok brand HOTEL key +32F093536677 +# A WaterFront Hotel in Oakland +3351916B5A77 +# Ballys (2018) +336E34CC2177 +# Random Hawaiian Hotel +A1670589B2AF +# SF Hotel (SoMa area) +2E0F00700000 +# +# Unknown PACS from Western Australia +CA80E51FA52B +A71E80EA35E1 +05597810D63D +# +# Hotel Key from Las Vegas +EA0CA627FD06 +80BB8436024C +5044068C5183 +# +# Key from Hotel M Montreal (probably diversified) +7E5E05866ED6 +661ABF99AFAD +# +# Key from evo Montreal (probably diversified) +1064BA5D6DF8 +# Hotel key +CE0F4F15E909 +D60DE9436219 +# +# ATM Area de Girona, spanish transport card +A01000000000 +A02000000000 +A03000000000 +A04000000000 +A05000000000 +A06000000000 +A07000000000 +A08000000000 +A09000000000 +A10000000000 +A11000000000 +A12000000000 +A13000000000 +A14000000000 +A15000000000 +B01000000000 +B02000000000 +B03000000000 +B04000000000 +B05000000000 +B06000000000 +B07000000000 +B08000000000 +B09000000000 +B10000000000 +B11000000000 +B12000000000 +B13000000000 +B14000000000 +B15000000000 +# +# Pittsburgh, PA, USA - Pittsburgh Regional Transit ConnectCard +A7AE4A5A33DC +6B857B568C10 +E2CE9A674CBE +A4896B2EBA4E +0724DF9AEDE8 +0E368FB140C1 +874EB25C8721 +5C313F4539CD +C5498606E0A8 +79C69F7EC7C0 +DA7DD0044DA2 +1B8189BD966B +765584147990 +4B7C7C315E6E +46CAAD12C524 +53BD03DEA5C9 +D2D72CB60F59 +14D258786538 +E2E89A375B36 +B3FA87DB0C45 +44D3B1561B34 +2817C6E02F97 +A513FF1232E9 +BD454BD52792 +391771654DC8 +5162797F8E1C +F700BD8E042D +3973ABFD8B66 +CE8BFF3728EE +09938D05DA78 +EACDA4DBE420 +EC2B9FD483CA +# +# Hotel Intelier Orange - Benicasim, Spain +# block 1 - key A +04256CFE0425 +# +# InsideWash Membership Card - Portugal +C18063858BB9 +# +# An apartment building in Sydney Olympic Park +13254608D0AB +24A2971BC0B2 +14264709D1AC +25A3981CC1B3 +1527480AD2AD +26A4991DC2B4 +1628490BD3AE +27A59A1EC3B5 +17294A0CD4AF +28A69B1FC4B6 +182A4B0DD5B0 +29A79C20C5B7 +192B4C0ED6B1 +2AA89D21C6B8 +1A2C4D0FD7B2 +2BA99E22C7B9 +1B2D4E10D8B3 +2CAA9F23C8BA +1C2E4F11D9B4 +2DABA024C9BB +1D2F5012DAB5 +2EACA125CABC +1E305113DBB6 +2FADA226CBBD +1F315214DCB7 +30AEA327CCBE +20325315DDB8 +31AFA428CDBF +21335416DEB9 +32B0A529CEC0 +22345517DFBA +33B1A62ACFC1 +# +# Universidade de São Paulo (USP) student card +17B50E38F1B0 +24E311F594CE +3794FBFB1A54 +43B229069F6A +4531952F765F +4943F2F35E0A +4985E681EF88 +4F56C88E0337 +710070E92C79 +8A036C5C35D4 +A027BD830A06 +D33673C19243 +D89A506542F2 +E5813CD228F1 +FAB943906E9C +# +# R.A.T.T transport card key A/B +AA034F342A55 +456776908C48 +# BusFacil - Brazilian public transport card for some cities +7b296f353c6b +3fa7217ec575 +fae9b14365a9 +c567dd4a6004 +c567dd4a6005 +c567dd4a6006 +c567dd4a6007 +c567dd4a6008 +c567dd4a6009 +c567dd4a600a +c567dd4a600d +c567dd4a600e +c567dd4a600f +5ef014ec5d7f +5086052022ac +bd6af9754c18 +5d67d4732a7d +17fe45604a04 +17fe45604a05 +17fe45604a06 +17fe45604a07 +17fe45604a08 +17fe45604a09 +17fe45604a0a +17fe45604a0d +17fe45604a0e +17fe45604a0f +# keys for swimming pool cards in Reykjavík Iceland +28220F14BEF0 +# key for Orkan keyfobs +300724070486 +# key for Atlantsolía keyfobs +60FCB3C42ABF +# key for hotel in greece +722F24F0722F +# STS Hotel 2A +535453535453 +# Public transport in Sofia, Bulgaria (SKGT) +# upgraded to DESFire since January 2024 +# SKGT common +# Sector 15, key A +f618b3d7855a +# Sector 15, key B +f1afa4da949f +# SKGT multi-use ticket +# Sector 0 +67362dace527 +633a010fa3c3 +# Sector 1 +f93c98655b9c +67ec0a47b0fb +# Sector 2 +54a028818ac7 +b2e87e53c5a0 +# Sector 3 +3e93cf0644b6 +79e12280e219 +# Sector 4 +2204b9fbf033 +4537fd238c8e +# Sector 5 +d1b44a9df05f +cfa526835a1f +# Sector 6 +21cc007ad81c +c097d0a85446 +# Sector 7 +d2268262710f +730bb7b8b3de +# Sector 8 +9fe7c5be7dff +61ae2d920c79 +# Sector 9 +78fcd4470c50 +b638caf7357b +# Sector 10 +0dc1dd7c8ea2 +4c6a6866b934 +# Sector 11 +03de2ceb2ea1 +93e0118b21ed +# Sector 12 +8fbced387bf4 +f57ca95c6edd +# Sector 13 +ef24fe3b4cf7 +8b44d303d62f +# Sector 14 +b1ea40b2caa6 +3abf8431003b +# Sector 15 - see above +# SKGT personalised subscription card +# Sector 0, 2, 16, key A +a0a1a2a3a4a5 +# Sector 8-14, 17-39, key A +ffffffffffff +# Sector 1, key A +# blue +f1df0ca8948b +# yellow +7747b4912984 +# Sector 3, key A +# blue +09d556d57a4b +# yellow +3ed158c6934e +# Sector 4-7, key A +# blue +839dedbfec0d +# yellow +c694a9ed2f9e +# Sector 15 - see above +# Sector 0, 16, key B (blue) +81d55f4551b9 +# Sector 0, key B (yellow) +6e9a040c3c91 +# Sector 1, key B +# blue +5b72c63fb416 +# yellow +a3cdced46371 +# Sector 2, key B +# blue +87a61433d026 +# yellow +9cd3a81f11ab +# Sector 3, key B +# blue +7070d331360c +# yellow +836c790f6e2c +# Sector 4-7, key B +# blue +7fe057787c4f +# yellow +ff59c6d13f88 +# Sector 8-14, 17-39, key B +536f6669614d +# Sector 15 - see above +# End of SKGT +# Hanoi Bus Rapid Transit - 1/2/3 A +AAAFBA10FC37 +C61F2C28DADF +23AACA30CBF2 +# +# Keys dumped from student ID (AGH Cracow - Poland), may be diversified +# Need to be verified +833E4F32589E +432D02DA59F3 +5C161CA2716F +F60B5F9666B8 +98EAC5321D2F +CC945E3FE5C4 +70783C436CF4 +2D186C7149A9 +5D60AC0939FC +93A5CE63C873 +87174550E900 +45675B25A3DA +F91750E629D5 +A3E662ABCDC8 +33D99E9FFA6A +FF7AABA39C61 +A8248C049BEA +C2AF731771C4 +9263B2E0DD80 +CE7FCCBBA5D8 +F8E385E5A2A0 +B27678B5C4AE +D68D7EBB9551 +7AB63F082328 +# +# Payment cards used by Eurest on certain campuses +7E2BC58168EB +# +# Shower cards provided by Seijsener +291A65CBEA7B +344A359BBAD9 +476572726974 +4D696368656C +4F3748E6C826 +69D40AF8B353 +72DEA10F21DF +74845AA8E3F1 +8C3C43EDCC55 +ACD30DFFB434 +D1A27C8EC5DF +F14D329CBDBE +# +# Hotel cards from Austria +AB287B3B4903 +7B0DEDA7E162 +# +#Metro Q transit cards from Huston, Texas +373B72D34B80 +BF3FFC245C9b +7D1D9E7CF8A7 +6A917BF357E6 +B1D461EC62CA +C6BECABEBE8A +66026782D435 +4547E34E40D9 +753897b99AAE +1C36761E8ABD +6D8FBD8CC524 +5A3274779706 +23F13602CC1A +511C1C2C9804 +F8B2B926555E +2593E37D9B2E +41A1F17EE990 +64DD48AEDE88 +7915ED4D9903 +D139DD71DB92 +216D97D46E88 +D9D1C447E427 +911E789433CB +93B43D689F85 +525A869053F1 +69B25667E0B4 +6AACA2D97645 +# UK London Office +435DF6296EC4 +2338B4913222 +# Acces card of students, and more in Occitanie, France +E9A553102EA5 +F982E971CFED +1F42AB9159EE +BBFB836A48B8 +B5D170B2E8F5 +E76978A05F10 +0B1A995DD007 +650DB9CEDB6B +13E54B4448B7 +3E3540C2C273 +A76152840117 +066CCC7666BC +3C0B3AC3AFA3 +CCB541598D72 +1988B5D48EC3 +892EEF0D30FB +0FE5CE5CC640 +# Volgograd (Russia) Volna transport cards keys +2B787A063D5D +D37C8F1793F7 # H World Hotel Chain Room Keys 543071543071 5F01015F0101 From dd6e0a9b721c09b82a127aadd0a1accba8b18f7c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:53:09 +0300 Subject: [PATCH 15/59] keeloq jolly motors add full support with add manually thanks @pkooiman ! --- .../main/subghz/helpers/subghz_custom_event.h | 1 + .../resources/subghz/assets/keeloq_mfcodes | 117 +++++++++--------- .../subghz/scenes/subghz_scene_set_type.c | 11 ++ 3 files changed, 71 insertions(+), 58 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index e28c018d8..093ca9526 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -82,6 +82,7 @@ typedef enum { SetTypeAllmatic868, SetTypeCenturion433, SetTypeMonarch433, + SetTypeJollyMotors433, SetTypeSommer_FM_434, SetTypeSommer_FM_868, SetTypeSommer_FM238_434, diff --git a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes index 23b7a031a..97e1aab47 100644 --- a/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes +++ b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes @@ -1,61 +1,62 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: 46 75 72 72 79 20 63 68 65 63 6B 20 3F 3F 21 21 -3FF98B52C38558ECDB26C3E86D118FAC9AF22EDDDE7649CB53726855CEBCCF9E -06B901C6E36E381B4A83554ED972288977F999C232106D337C3BE4A9A44608F8 -8153E6CAF4B272BA0EA168B9F0F29CF02CEB33E4ABBD4D5C858D1ADBFF474A25 -F61216CE3A7E500E0C9B2173F91C2E7B1BB7D7AA65D4150EAC28169116647DDD -A3ABC262415035A190447EC9C15CFD1AB1720560AB7C82D7447215342305299732776A9A6DEA4D359C52A23BFCE6B015 -5784D0E77A55E1361F47A1F6CFFBFAF715CFCAD2BD502ED266AA86DC47F98541 -E082BF64C75023F23FB333C53F2590F408FD932EB71DF4ED4D0E0EAF2AEBD488 -EFF328889D57D9F4B9111918F9C9BC641645104223009842FFF7B6F73E24E5B7 -BDCD1DBCBCA789C5A5C3623C0A287D791F1CACCBBD7D144E2EF1F92DA5513D90 -6310362BE6ED7CB5E3F4CA84D3093DF620BABD2C9D419A2BA5AA05F241EE7592 -4C6F97C553276D5403103A6BA6C4DBBE017A9E4159E6E5AC4C28ACD645DB1E8D4551CDC228A0457BEEF49179A081E1FD -861ECA071AEEF3854005FEC9BF22C7DB76D07B7930968314FFAC70995E28680E473F8A1A7E56E8776EDD1C6E2DD6DD26 -55ADDFBE97BCB0FB43EDEB9CAFF9F32DD788A6306D3702BC2923DA5C69F5F0A5 -AB838DA2B25547AA43DEB7FB40B15E289B9209057BE564E7CB78F0D5DCFC65FD -21BACE924E522AD0E97F0AAF64A9DB6A5F7BA09B3A1759AAFD4016F3ADD4353D -4B37D449E44BAE7F377EE5CE52E94882E42617417F77ECE9803D9435892167F2 -E63BA93D98BB3EEEAD34B38C5F271FB777AEABD9E6A05597AE09815E578AA811900AE9F144FBEC7DBFDDEC87D1ED368B -7DF24DCB7D73F1638FFD22325463B23C101653EE770F086D323BE90868A7E267 -18E533990C408061309323675116429652B3F4D228F00D704310E7AB26F6BAF4 -26042EC21D73490D9E7F968EDCC4CECF3989E6E982427DEB7012478E214CED8797A9BEBC481C81E9646214809A409B4A -AC4169C26E402720F1E2A0AD690AE2CF708CE203898BC7102178A738C70F361718E794F0D0CB1A2F1938EF35CCA11887 -6962CADB9BD1B86B779DF7F4D7E06E92EB42474C7FD9EA23879F9982D7127357 -23AEC0F6F9FF529DDDCD1CDAA77F7B136CE2CCD3AC8B949954D5D3B2ECFA8CBC -C6A3A849BC4A8DB438065255BD387DCD77AD7E7FEB3B0E11B6D3A43279AB9087 -CCB71F8BDC8B31F36D6141B3B57BF31B7EDF72B87593B7497871F5738A0B7E00 -345FE0FAD3F60C017D9793406981878EA2226072D624208AC33682793B415C41 -78AF1FCFDB780744708DBB547F7C3F095BA5FAFB34FA83BF4323B32829836ED1 -C2F19F077E71E710D39F5F11C1FE55C2A3CD6F33384CD8603288765F266F1BDF -084B1A9565AFC88900D0FF25413E659E17AAB649DB2B7A9F0381CB0DF6D2B8E5 -568CECD994676CF3D6B225DEF21D40787DCB41C101F52B0C5AA43ED66709D158 -0742E0AAB6504AC63A9C59FBDD980BD4C4760EFF3E556C8A6241442CDDD23A74 -37BB60EE11BEC7D25A607DE9B0B6D3EAD23321AFEB94995FAB42184A95D1CADA -42FD71B98A3BEE9CF372B03E158D51181BFAA9CF54F7300A93FE7665402B3D1F -9346B7D12346E264E84F91145EBF86C53DD0061E0FA6556FAE5F6FBB8CEB799E -430B0D7FC09C09051AEB667A370E6D9D9BDF0C0C553AD2791682D43CE5DC48B7 -5BBB5129797BC07CDC1D25A8A919A637B9FFF2F920BD42D1721018ABF8D34959AF877AFF450AD91548184E1A0D991CC8 -0BC8D3E1C2D9A8FB445FC55564471007A28C09C9CE602203176F1BFF02AC6328 -1C4CA912791BCD9CB231C64AB479AF240D02EC9F431D7C479B9A172E5B97F5CD -15A9CDF17E72255DE0942C09E67CD251C3D465246845F9C0B97A7EFEE4AF9110 -F95543395BFF39B0A093AC80D0EF1BEFA218A3769D074250414D1357105A4D34 -138D433824E691C6B67A08CF1DDE55FBCA2D65AC0B7D9320EA1FDCB1742B11BF -3BE3A385F1C0B8922C4E23EFF6912748DF715A4546CECB5E8972C1D1E47D0D3A -9ECA2554ED36700326F2E5140C434ADA8DFF55A53382F19541E9AAE45DA5CBF2 -5C75D528678AF199E191C49F310913F401014F97EEA5FA507C7310B48A98FDE3297EA398B08959951FF99EDDB64C5E0D -22A9C66645B3944925A496D9F2312429CC787B6314948B482EAD9360124F59DA -DA3A8571664DBBFC1DE97B53E7C141554A2FBCEBA980696D32409CC5ADB7FC41 -20A52AABC518FCC2FC75AE3F5CC7C4838AA4973111DA696B890D884A18098D91 -EBB7163F580A1A5D26F12FBE650A227791193BA9AFCE277584B171F2FE1C77CF -86369EE5277CB81B9417B6232F8D994FAEAB34D0D5363B143257C62B10CACAFD -2E2EAB32891E172A3C31D434703480E69793435BB198E6AA06AA066EE8234D85 -745FC576D77C41BAEFF15A822E6B4058A485A2CAA0A3B283928D17AC02299AD9 -1FF8D49F2F7D785D64B6FE365CD9C2BD958E9527F66BB8A85C9AEBC73ECFE064 -3CFB77F3E274C1EB2772CDFA7B5B17255C2554198BE60C058A3405AEC644FABC5AAECC8F9C7F4A4E5B2D5252E8C62628 -AE514C44B55A1A4744E1106FD226C587D1B71CA7B5DCF010265D769E22012866 -2B2D787A4B0F30CAB9CD3DBC7686165637F091B31745CAB53B369A804F76F9EE -EA4279C80F0B4AC0B32AB9E8B8CFB9C25FF81840BEE65B2160F85E56FA576C48 -E41D853750D68643E929F94F46BCDC050040935883E9A0C45BB238CDE06340DD745BDA7D6C16AE2B028E073EDDC0FC49 +IV: 46 75 72 69 20 63 68 65 63 6B 20 4F 77 4F 21 3F +796353C129CC2B688FE158D36E82001F7450D58DD763BCF4D6FA1CE6C3D598EA +1E7DDEB3B54A42B8993C32AF209CBCC9A1137CE334449F016B993D673EB15C69 +F9CB2DDC4E3D45694292C7DE45F1DC0BD74235B36F624AF39E8C3D211A713408 +538F46EF4250801434FEA469EE07E8C8BF71C6179442718A05455BB501D797C4 +F2BF384DBF7F828E025F020E47D1D637B497FB470444F0C6F9DC67C6830EDDE8A26A6EE89A321D3924D9099895AB2EA1 +2CA8A8A4866D5C2B715B520F641B41355A81BA73170842233806D8AA3E3F3D62 +80CF5DEF931CF902EE602319F7CD506D42E5FBC06ABBF9F05D474C8E8A2AAC4E +15CB465F7A646226C987BB4928E92A61F350ADCDDE355B717730ADDD1B738950 +86B7597ED3EDF6826124ABD7AE419197DC4A93FA064179ACAD853EC670F93995 +28263A286F1ADA0E851E8A27AFD7706CF3513D8A24D41CF7E24A925FE3D86305 +AF29A08AB877F12681706D71B82B8E2447DA18EBF9731EF3CE91FA5ECAC4E98F8FDC817E0F67C3D7348DD2AF128F1E62 +A675C5BB6AC41336B5F5A27FC062FBF30DC39B1E5C498F0FD823261C3177FA58416C5402554742370CB0DAFD2895F6F8 +0073790C26BD0224F5560161A4D4C4F8E05498E995FD2BF12EA9926A5127E9A5 +235ADFE253B51260DCF5C66F9CB9602B91A0C57BE14D1BE1E11EB309643B29DB +F9C2E3A926AAA108F474075F0B4EDFF3135492B1529EAB150CF78E748BF36E17 +50F442CC9D90B9FF8C786245EC442B911A28A04D829D0E45D7D2D4C5A3F5B864 +9EA00CD21C0BE1BB15A0CAD31097A44CAF42868F259E8ED25F361986C26161514FA85D78F3889B4185D2A1484C1DA88C +52DFE7D9052F29071922876723C30CF6FE6247D6439590C5C7C0493120ACA096 +D5AF176D59779A92F6EFB34F271D76D60780C3EA83306326E0119CD3B0417687 +C4CC4E589CCCEC609B4DE39F926F83CCFFCC966871B9A998514910A3F59E86FB56C476DFFB4181E3D22E86A760C4C137 +50A64FEDA64B61A5C123906426EF726D98AC70C15F38245A931B5649F0944930679513D9862091275F10A804EBB610DE +E7938C4F32E571582D73F855ACC40FF0153EFBAB6D184F2DBE8EAC63C4276D92 +7667993F35F1363C0A3AEB5222F07F91904B3F6FA375BF062B269B09706764CB +9DF764EE4A70D331BA8870F4D27C3E90E811A5E306BC72701A99A0377AC7B189 +324D0FBC096A489983C45E82B2745A83A3725A87D2D2CA676A521075065D5047 +8EA1A30AE08CEBD03A52EB2512C7C69CB824E0B9BE900E25F15FAB17ADBB1188 +CE379182103FC4E0442745F6F202AB6ED8EBC051B5F5537916938D9DB8FCD6BE +752BD22AA37D030C60E48CB57309AF631682AC4A0D67C3A7D1130EB056717FB6 +9ECFE7D24BF25BD543E1EAE8116D95C110BD4514EE279BCA71234865EB9166BD +14B3FA8704BA3B284C65F1A6FD114E53B883E12EAFB24B574F84585BD20157DA +D026E1E2CA70E33291482EEFCE11123540BBF591D400C92CEBB8CAF99A9DE882 +88E618EF5E76D1F5A60926D48D3D58FF67B4A92DE6EECA271EDAFC2419AE787B +74E14AD8ADE2BC575048325D1B3990669CDB35D840169B913043DAC938862AE4 +BEB5388B6A7D5C9EF65BDD7577D1DD654B7FAECE5A4CF0937BB7D0C0C5494CD0 +761356D494E3C947CBDCA887A30071A675FE1BE6E77FC9016DB9B5659B7FF9E7 +7503725DFC7212F5F719AFC9DF29F07321511BE4896E12D1D10C68BB07C6483A2CE5FFDFD074CFC279E42E6DD860C496 +BD03D78399DE44449AEE9F00EBCABBF419EDEA1701B9979A97D57AECB5139D1E +E80EB84DF9DA2E34B78F50D6488A30F8EFD11E7C6DBEB7CFEDE83BE5CA86B6DF +9332A130138F2AC11A12030CF43EFF77E7CABE761EDE14748112E13267496CE9 +E657F3C95EEF0AF92A5C49F66BD9C053A82493C7D6267F1E7C038473AE488116 +6F37491FFE130F90B77D7E5EA4AA75A1DB0CA3644F68B6502DFC302DDB80367B +3B37C5CCDD510873628D92B352907FEFF0AC2B38C751C2E46C3B97C3E365972B +A4C845187BEC75669234EE07B839DCFF618678D2EAA5596350F0936A400099A5 +2C961EF4F2454771B2646ECBAA1D0B7DAA2FD8ECC7228037A36E24FE30C43ABAA446C1B5968C0E2DD141C55557A4CCB8 +C4E0D43E9670C2B91F6AF03D60F216625CC19C697331BC443194D2BB88E042DF +3DC5584F43061AF79907D6342DF3344435B5AA6277B33D7DC56C429D1EB81BC4 +D9186791E907CBB9EF26EDDAEA9F0DBC8D24E213E55942ED5E1790B5A55F8758 +2B54CB727BBFD8567543448D2D24B3865329F89936D3B035ED2185BA88F1DF2E +A08F0D881AF001E52FF2CF9D232A9A566EB1900B351AFEEFEE666BEC40588F64 +46A11CA89BA1998A247275EEDF504DAFC5F97B41DFF4943F531A9F8F43DF19C5 +EF70A3858E84B13DF606317381B2E9DFFC346E96AF7C1DF0001586B8BF35808F +38EAF18DB8096C7427EBD36CBC5B0E945A3286278CC0227EB056F7ACB9E450D4 +28278D1DAA263E9A45ED17F67F6B6B0CF00F8C0F58F86C8161F8D4266FE556CB +0B0C79FDD7C9EA31FAA4AA829EDDD2A3453C05A74F5B53BBEAE83E1F4913FD1C18BD235D14D06D9E567DDB273E4C1F2A +7D663A93AE1B9A2E00E944B92838DED3376E09C5179C8F3037B2EAE9E7326C2A +D64EC2C7BD8CFA152368DF6BB75D66EF24EAA9C864A1386184B793C0585D82BC +51D8EB188E833891CCD15919FAC8FE56ACAB1007699F4FDCB53A6DDAB02E5CAA +650866D34DECD1D1F3559EFD8D2A4C1DB51C005F5932608CB6062B384D7A1F59C8E3FBF2C0A5AEFFB631D7B88A630AAB diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index a03c194f8..6c3e44894 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -29,6 +29,7 @@ static const char* submenu_names[SetTypeMAX] = { [SetTypeAllmatic868] = "KL: Allmatic 868MHz", [SetTypeCenturion433] = "KL: Centurion 433MHz", [SetTypeMonarch433] = "KL: Monarch 433MHz", + [SetTypeJollyMotors433] = "KL: Jolly Mot. 433MHz", [SetTypeSommer_FM_434] = "KL: Sommer 434MHz", [SetTypeSommer_FM_868] = "KL: Sommer 868MHz", [SetTypeSommer_FM238_434] = "KL: Sommer fm2 434Mhz", @@ -428,6 +429,16 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { .keeloq.cnt = 0x03, .keeloq.manuf = "Monarch"}; break; + case SetTypeJollyMotors433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF), + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Jolly_Motors"}; + break; case SetTypeElmesElectronic: gen_info = (GenInfo){ .type = GenKeeloq, From c9bc05199e24e059a394f97cb36f90a2927b2d4d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 6 Dec 2024 12:18:51 +0300 Subject: [PATCH 16/59] add auto power off timer setting [ci skip] by @Dmitry422 with little fixes by @xMasterX --- applications/services/desktop/desktop.c | 55 +++++++++++++++++++ applications/services/desktop/desktop_i.h | 3 + .../services/desktop/desktop_settings.c | 40 ++++++++++---- .../services/desktop/desktop_settings.h | 3 + .../scenes/desktop_settings_scene_start.c | 35 ++++++++++++ 5 files changed, 124 insertions(+), 12 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 1132760d5..8b24e38f0 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -19,6 +19,12 @@ static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); static void desktop_apply_settings(Desktop*); +//--- auto_power_off_timer +#include +static void desktop_start_auto_poweroff_timer(Desktop*); +static void desktop_auto_poweroff_arm(Desktop*); +static void desktop_auto_poweroff_inhibit(Desktop*); +//--- static void desktop_loader_callback(const void* message, void* context) { furi_assert(context); @@ -131,6 +137,9 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { } desktop_auto_lock_inhibit(desktop); + //--- auto_power_off_timer + desktop_auto_poweroff_inhibit(desktop); + //-- desktop->app_running = true; furi_semaphore_release(desktop->animation_semaphore); @@ -138,6 +147,9 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { } else if(event == DesktopGlobalAfterAppFinished) { animation_manager_load_and_continue_animation(desktop->animation_manager); desktop_auto_lock_arm(desktop); + //--- auto_power_off_timer + desktop_auto_poweroff_arm(desktop); + //--- desktop->app_running = false; } else if(event == DesktopGlobalAutoLock) { @@ -179,6 +191,9 @@ static void desktop_input_event_callback(const void* value, void* context) { Desktop* desktop = context; if(event->type == InputTypePress) { desktop_start_auto_lock_timer(desktop); + //--- m96yda + desktop_start_auto_poweroff_timer(desktop); + //--- } } @@ -213,6 +228,39 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { } } +//--- auto_power_off_timer +static void desktop_auto_poweroff_timer_callback(void* context) { + UNUSED(context); + Power* power = furi_record_open(RECORD_POWER); + power_off(power); +} + +static void desktop_start_auto_poweroff_timer(Desktop* desktop) { + furi_timer_start( + desktop->auto_poweroff_timer, furi_ms_to_ticks(desktop->settings.auto_poweroff_delay_ms)); +} + +static void desktop_stop_auto_poweroff_timer(Desktop* desktop) { + furi_timer_stop(desktop->auto_poweroff_timer); +} + +static void desktop_auto_poweroff_arm(Desktop* desktop) { + if(desktop->settings.auto_poweroff_delay_ms) { + desktop->input_events_subscription = furi_pubsub_subscribe( + desktop->input_events_pubsub, desktop_input_event_callback, desktop); + desktop_start_auto_poweroff_timer(desktop); + } +} + +static void desktop_auto_poweroff_inhibit(Desktop* desktop) { + desktop_stop_auto_poweroff_timer(desktop); + if(desktop->input_events_subscription) { + furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription); + desktop->input_events_subscription = NULL; + } +} +//--- + static void desktop_clock_timer_callback(void* context) { furi_assert(context); Desktop* desktop = context; @@ -238,6 +286,9 @@ static void desktop_apply_settings(Desktop* desktop) { if(!desktop->app_running && !desktop->locked) { desktop_auto_lock_arm(desktop); + //--- auto_power_off_timer + desktop_auto_poweroff_arm(desktop); + //--- } desktop->in_transition = false; @@ -373,6 +424,10 @@ static Desktop* desktop_alloc(void) { desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); + //--- auto_power_off_timer + desktop->auto_poweroff_timer = + furi_timer_alloc(desktop_auto_poweroff_timer_callback, FuriTimerTypeOnce, desktop); + //--- desktop->status_pubsub = furi_pubsub_alloc(); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index 1dc7c7d21..abf5cd579 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -75,6 +75,9 @@ struct Desktop { FuriTimer* auto_lock_timer; FuriTimer* update_clock_timer; + //--- auto_power_off_timer + FuriTimer* auto_poweroff_timer; + //--- AnimationManager* animation_manager; FuriSemaphore* animation_semaphore; diff --git a/applications/services/desktop/desktop_settings.c b/applications/services/desktop/desktop_settings.c index 828ec5f0d..45b9e5ee3 100644 --- a/applications/services/desktop/desktop_settings.c +++ b/applications/services/desktop/desktop_settings.c @@ -6,16 +6,20 @@ #define TAG "DesktopSettings" -#define DESKTOP_SETTINGS_VER_13 (13) -#define DESKTOP_SETTINGS_VER (14) +#define DESKTOP_SETTINGS_VER_14 (14) +#define DESKTOP_SETTINGS_VER (15) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) typedef struct { - uint8_t reserved[11]; - DesktopSettings settings; -} DesktopSettingsV13; + uint32_t auto_lock_delay_ms; + uint8_t displayBatteryPercentage; + uint8_t dummy_mode; + uint8_t display_clock; + FavoriteApp favorite_apps[FavoriteAppNumber]; + FavoriteApp dummy_apps[DummyAppNumber]; +} DesktopSettingsV14; // Actual size of DesktopSettings v13 //static_assert(sizeof(DesktopSettingsV13) == 1234); @@ -37,21 +41,33 @@ void desktop_settings_load(DesktopSettings* settings) { DESKTOP_SETTINGS_MAGIC, DESKTOP_SETTINGS_VER); - } else if(version == DESKTOP_SETTINGS_VER_13) { - DesktopSettingsV13* settings_v13 = malloc(sizeof(DesktopSettingsV13)); + } else if(version == DESKTOP_SETTINGS_VER_14) { + DesktopSettingsV14* settings_v14 = malloc(sizeof(DesktopSettingsV14)); success = saved_struct_load( DESKTOP_SETTINGS_PATH, - settings_v13, - sizeof(DesktopSettingsV13), + settings_v14, + sizeof(DesktopSettingsV14), DESKTOP_SETTINGS_MAGIC, - DESKTOP_SETTINGS_VER_13); + DESKTOP_SETTINGS_VER_14); if(success) { - *settings = settings_v13->settings; + settings->auto_lock_delay_ms = settings_v14->auto_lock_delay_ms; + settings->auto_poweroff_delay_ms = 0; + settings->displayBatteryPercentage = settings_v14->displayBatteryPercentage; + settings->dummy_mode = settings_v14->dummy_mode; + settings->display_clock = settings_v14->display_clock; + memcpy( + settings_v14->favorite_apps, + settings->favorite_apps, + sizeof(settings_v14->favorite_apps)); + memcpy( + settings_v14->dummy_apps, + settings->dummy_apps, + sizeof(settings_v14->dummy_apps)); } - free(settings_v13); + free(settings_v14); } } while(false); diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index ba5a78840..e2e91d2dd 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -38,6 +38,9 @@ typedef struct { typedef struct { uint32_t auto_lock_delay_ms; + //--- auto_power_off_timer + uint32_t auto_poweroff_delay_ms; + //--- uint8_t displayBatteryPercentage; uint8_t dummy_mode; uint8_t display_clock; diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 04cb0182b..9954a2c28 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -28,6 +28,15 @@ typedef enum { DesktopSettingsDummyOkLong, } DesktopSettingsEntry; +// --- auto_power_off_timer +#define AUTO_POWEROFF_DELAY_COUNT 8 +const char* const auto_poweroff_delay_text[AUTO_POWEROFF_DELAY_COUNT] = + {"OFF", "5min", "10min", "15min", "30min", "45min", "60min", "90min"}; + +const uint32_t auto_poweroff_delay_value[AUTO_POWEROFF_DELAY_COUNT] = + {0, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; +// --- + #define AUTO_LOCK_DELAY_COUNT 9 const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { "OFF", @@ -86,6 +95,16 @@ static void desktop_settings_scene_start_clock_enable_changed(VariableItem* item app->settings.display_clock = index; } +// --- auto_power_off_timer +static void desktop_settings_scene_start_auto_poweroff_delay_changed(VariableItem* item) { + DesktopSettingsApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, auto_poweroff_delay_text[index]); + app->settings.auto_poweroff_delay_ms = auto_poweroff_delay_value[index]; +} +// --- + static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) { DesktopSettingsApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -115,6 +134,22 @@ void desktop_settings_scene_start_on_enter(void* context) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]); + // --- auto_power_off_timer + item = variable_item_list_add( + variable_item_list, + "Auto PowerOff", + AUTO_POWEROFF_DELAY_COUNT, + desktop_settings_scene_start_auto_poweroff_delay_changed, + app); + + value_index = value_index_uint32( + app->settings.auto_poweroff_delay_ms, + auto_poweroff_delay_value, + AUTO_POWEROFF_DELAY_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, auto_poweroff_delay_text[value_index]); + // --- + item = variable_item_list_add( variable_item_list, "Battery View", From d566f650bdf4f8f1669b41ebeb8fbc280cd677ec Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 6 Dec 2024 12:20:41 +0300 Subject: [PATCH 17/59] fix order [ci skip] --- .../desktop_settings/scenes/desktop_settings_scene_start.c | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 9954a2c28..f674380af 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -9,6 +9,7 @@ typedef enum { DesktopSettingsPinSetup = 0, DesktopSettingsAutoLockDelay, + DesktopSettingsAutoPowerOff, DesktopSettingsBatteryDisplay, DesktopSettingsClockDisplay, DesktopSettingsChangeName, From 53fa3f85b30de8c236a768257fe8317143041bc8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 6 Dec 2024 12:51:06 +0300 Subject: [PATCH 18/59] upd changelog --- CHANGELOG.md | 7 ++++++- applications/services/desktop/desktop.c | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5058c114..f12e3bd56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,14 @@ ## Main changes - Current API: 78.2 +* SubGHz: Jolly Motors support (with add manually) (Thanks @pkooiman !) +* Desktop: Auto Power Off Timer (by @Dmitry422 with some fixes by @xMasterX) +* OFW PR 4025: Increase system stack's reserved memory size (Fix USB UART Bridge Crash) (by @Astrrra) * OFW: merged gsurkov/vcp_break_support branch for usb uart bridge (WIP!!!) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes -* No changes yet :( +* OFW: NFC: Plantain parser Last payment amount fix +* OFW: NFC clipper: BART station ids for San Lorenzo, Bay Fair +* OFW: Fix typo for mf_classic_key_cahce_get_next_key() function

#### Known NFC post-refactor regressions list: - Mifare Mini clones reading is broken (original mini working fine) (OFW) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 8b24e38f0..9366d6508 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -191,7 +191,7 @@ static void desktop_input_event_callback(const void* value, void* context) { Desktop* desktop = context; if(event->type == InputTypePress) { desktop_start_auto_lock_timer(desktop); - //--- m96yda + //--- auto_power_off_timer desktop_start_auto_poweroff_timer(desktop); //--- } From 306b7285879abe05b1e3e7bfdca6442c86161b94 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 8 Dec 2024 13:39:34 +0300 Subject: [PATCH 19/59] fix wrong order --- applications/services/desktop/desktop_settings.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/applications/services/desktop/desktop_settings.c b/applications/services/desktop/desktop_settings.c index 45b9e5ee3..7a99dd365 100644 --- a/applications/services/desktop/desktop_settings.c +++ b/applications/services/desktop/desktop_settings.c @@ -58,13 +58,11 @@ void desktop_settings_load(DesktopSettings* settings) { settings->dummy_mode = settings_v14->dummy_mode; settings->display_clock = settings_v14->display_clock; memcpy( - settings_v14->favorite_apps, settings->favorite_apps, - sizeof(settings_v14->favorite_apps)); + settings_v14->favorite_apps, + sizeof(settings->favorite_apps)); memcpy( - settings_v14->dummy_apps, - settings->dummy_apps, - sizeof(settings_v14->dummy_apps)); + settings->dummy_apps, settings_v14->dummy_apps, sizeof(settings->dummy_apps)); } free(settings_v14); From 256c1a114013ff4a36487240b187c98b320ecbb1 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Tue, 17 Dec 2024 22:12:55 +0900 Subject: [PATCH 20/59] [FL-3917] Add the ability to send a signal once via RPC (#4000) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add the ability to send a signal once * Update protobuf * Fix sending infrared signals * Review changes * Update protobuf * Separate sending an IR signal once into a function * Update protobuf module --------- Co-authored-by: あく Co-authored-by: Georgii Surkov --- applications/main/infrared/infrared_app.c | 33 ++++++++++++++ applications/main/infrared/infrared_app_i.h | 14 ++++++ .../main/infrared/infrared_custom_event.h | 2 + .../main/infrared/scenes/infrared_scene_rpc.c | 43 +++++++++++++++++++ .../main/subghz/helpers/subghz_custom_event.h | 1 + .../main/subghz/scenes/subghz_scene_rpc.c | 37 ++++++++++++++++ applications/main/subghz/subghz.c | 3 ++ applications/services/rpc/rpc_app.c | 39 +++++++++++++++++ applications/services/rpc/rpc_app.h | 8 ++++ assets/protobuf | 2 +- 10 files changed, 181 insertions(+), 1 deletion(-) diff --git a/applications/main/infrared/infrared_app.c b/applications/main/infrared/infrared_app.c index a93fd766d..c50039760 100644 --- a/applications/main/infrared/infrared_app.c +++ b/applications/main/infrared/infrared_app.c @@ -88,6 +88,19 @@ static void infrared_rpc_command_callback(const RpcAppSystemEvent* event, void* view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressIndex); } + } else if(event->type == RpcAppEventTypeButtonPressRelease) { + furi_assert( + event->data.type == RpcAppSystemEventDataTypeString || + event->data.type == RpcAppSystemEventDataTypeInt32); + if(event->data.type == RpcAppSystemEventDataTypeString) { + furi_string_set(infrared->button_name, event->data.string); + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressReleaseName); + } else { + infrared->app_state.current_button_index = event->data.i32; + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressReleaseIndex); + } } else if(event->type == RpcAppEventTypeButtonRelease) { view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonRelease); @@ -411,6 +424,26 @@ void infrared_tx_stop(InfraredApp* infrared) { infrared->app_state.last_transmit_time = furi_get_tick(); } +void infrared_tx_send_once(InfraredApp* infrared) { + if(infrared->app_state.is_transmitting) { + return; + } + + dolphin_deed(DolphinDeedIrSend); + infrared_signal_transmit(infrared->current_signal); +} + +InfraredErrorCode infrared_tx_send_once_button_index(InfraredApp* infrared, size_t button_index) { + furi_assert(button_index < infrared_remote_get_signal_count(infrared->remote)); + + InfraredErrorCode error = infrared_remote_load_signal( + infrared->remote, infrared->current_signal, infrared->app_state.current_button_index); + if(!INFRARED_ERROR_PRESENT(error)) { + infrared_tx_send_once(infrared); + } + + return error; +} void infrared_blocking_task_start(InfraredApp* infrared, FuriThreadCallback callback) { view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewLoading); furi_thread_set_callback(infrared->task_thread, callback); diff --git a/applications/main/infrared/infrared_app_i.h b/applications/main/infrared/infrared_app_i.h index 692cc9671..75d8502f2 100644 --- a/applications/main/infrared/infrared_app_i.h +++ b/applications/main/infrared/infrared_app_i.h @@ -218,6 +218,20 @@ InfraredErrorCode infrared_tx_start_button_index(InfraredApp* infrared, size_t b */ void infrared_tx_stop(InfraredApp* infrared); +/** + * @brief Transmit the currently loaded signal once. + * + * @param[in,out] infrared pointer to the application instance. + */ +void infrared_tx_send_once(InfraredApp* infrared); + +/** + * @brief Load the signal under the given index and transmit it once. + * + * @param[in,out] infrared pointer to the application instance. + */ +InfraredErrorCode infrared_tx_send_once_button_index(InfraredApp* infrared, size_t button_index); + /** * @brief Start a blocking task in a separate thread. * diff --git a/applications/main/infrared/infrared_custom_event.h b/applications/main/infrared/infrared_custom_event.h index 02d9a276f..2efc99f4b 100644 --- a/applications/main/infrared/infrared_custom_event.h +++ b/applications/main/infrared/infrared_custom_event.h @@ -21,6 +21,8 @@ enum InfraredCustomEventType { InfraredCustomEventTypeRpcButtonPressName, InfraredCustomEventTypeRpcButtonPressIndex, InfraredCustomEventTypeRpcButtonRelease, + InfraredCustomEventTypeRpcButtonPressReleaseName, + InfraredCustomEventTypeRpcButtonPressReleaseIndex, InfraredCustomEventTypeRpcSessionClose, InfraredCustomEventTypeGpioTxPinChanged, diff --git a/applications/main/infrared/scenes/infrared_scene_rpc.c b/applications/main/infrared/scenes/infrared_scene_rpc.c index 8f9dc4338..35cd971d8 100644 --- a/applications/main/infrared/scenes/infrared_scene_rpc.c +++ b/applications/main/infrared/scenes/infrared_scene_rpc.c @@ -124,6 +124,49 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { rpc_system_app_confirm(infrared->rpc_ctx, result); + } else if( + event.event == InfraredCustomEventTypeRpcButtonPressReleaseName || + event.event == InfraredCustomEventTypeRpcButtonPressReleaseIndex) { + bool result = false; + + // Send the signal once and stop + if(rpc_state == InfraredRpcStateLoaded) { + if(event.event == InfraredCustomEventTypeRpcButtonPressReleaseName) { + const char* button_name = furi_string_get_cstr(infrared->button_name); + size_t index; + const bool index_found = + infrared_remote_get_signal_index(infrared->remote, button_name, &index); + app_state->current_button_index = index_found ? (signed)index : + InfraredButtonIndexNone; + FURI_LOG_D(TAG, "Sending signal with name \"%s\"", button_name); + } else { + FURI_LOG_D( + TAG, "Sending signal with index \"%ld\"", app_state->current_button_index); + } + if(infrared->app_state.current_button_index != InfraredButtonIndexNone) { + InfraredErrorCode error = infrared_tx_send_once_button_index( + infrared, app_state->current_button_index); + if(!INFRARED_ERROR_PRESENT(error)) { + const char* remote_name = infrared_remote_get_name(infrared->remote); + infrared_text_store_set(infrared, 0, "emulating\n%s", remote_name); + + infrared_scene_rpc_show(infrared); + result = true; + } else { + rpc_system_app_set_error_code( + infrared->rpc_ctx, RpcAppSystemErrorCodeInternalParse); + rpc_system_app_set_error_text( + infrared->rpc_ctx, "Cannot load button data"); + result = false; + } + } + } + + if(result) { + scene_manager_set_scene_state( + infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded); + } + rpc_system_app_confirm(infrared->rpc_ctx, result); } else if( event.event == InfraredCustomEventTypeRpcExit || event.event == InfraredCustomEventTypeRpcSessionClose || diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index fe2c08fc6..571f3feb9 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -49,6 +49,7 @@ typedef enum { SubGhzCustomEventSceneRpcLoad, SubGhzCustomEventSceneRpcButtonPress, SubGhzCustomEventSceneRpcButtonRelease, + SubGhzCustomEventSceneRpcButtonPressRelease, SubGhzCustomEventSceneRpcSessionClose, SubGhzCustomEventViewReceiverOK, diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index c1476746d..040a15114 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -85,6 +85,43 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); rpc_system_app_confirm(subghz->rpc_ctx, result); + } else if(event.event == SubGhzCustomEventSceneRpcButtonPressRelease) { + bool result = false; + if(state == SubGhzRpcStateLoaded) { + switch( + subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) { + case SubGhzTxRxStartTxStateErrorOnlyRx: + rpc_system_app_set_error_code( + subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock); + rpc_system_app_set_error_text( + subghz->rpc_ctx, + "Transmission on this frequency is restricted in your region"); + break; + case SubGhzTxRxStartTxStateErrorParserOthers: + rpc_system_app_set_error_code( + subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse); + rpc_system_app_set_error_text( + subghz->rpc_ctx, "Error in protocol parameters description"); + break; + + default: //if(SubGhzTxRxStartTxStateOk) + result = true; + subghz_blink_start(subghz); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateTx); + break; + } + } + + // Stop transmission + if(state == SubGhzRpcStateTx) { + subghz_txrx_stop(subghz->txrx); + subghz_blink_stop(subghz); + result = true; + } + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); + rpc_system_app_confirm(subghz->rpc_ctx, result); } else if(event.event == SubGhzCustomEventSceneRpcLoad) { bool result = false; if(state == SubGhzRpcStateIdle) { diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 22e81f2eb..b17a232a8 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -43,6 +43,9 @@ static void subghz_rpc_command_callback(const RpcAppSystemEvent* event, void* co } else if(event->type == RpcAppEventTypeButtonRelease) { view_dispatcher_send_custom_event( subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonRelease); + } else if(event->type == RpcAppEventTypeButtonPressRelease) { + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonPressRelease); } else { rpc_system_app_confirm(subghz->rpc_ctx, false); } diff --git a/applications/services/rpc/rpc_app.c b/applications/services/rpc/rpc_app.c index aa2a3f64f..2b9a6542d 100644 --- a/applications/services/rpc/rpc_app.c +++ b/applications/services/rpc/rpc_app.c @@ -258,6 +258,41 @@ static void rpc_system_app_button_release(const PB_Main* request, void* context) } } +static void rpc_system_app_button_press_release(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(request->which_content == PB_Main_app_button_press_release_request_tag); + + RpcAppSystem* rpc_app = context; + furi_assert(rpc_app); + + if(rpc_app->callback) { + FURI_LOG_D(TAG, "ButtonPressRelease"); + + RpcAppSystemEvent event; + event.type = RpcAppEventTypeButtonPressRelease; + + if(strlen(request->content.app_button_press_release_request.args) != 0) { + event.data.type = RpcAppSystemEventDataTypeString; + event.data.string = request->content.app_button_press_release_request.args; + } else { + event.data.type = RpcAppSystemEventDataTypeInt32; + event.data.i32 = request->content.app_button_press_release_request.index; + } + + rpc_system_app_error_reset(rpc_app); + rpc_system_app_set_last_command(rpc_app, request->command_id, &event); + + rpc_app->callback(&event, rpc_app->callback_context); + + } else { + rpc_system_app_send_error_response( + rpc_app, + request->command_id, + PB_CommandStatus_ERROR_APP_NOT_RUNNING, + "ButtonPressRelease"); + } +} + static void rpc_system_app_get_error_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(request->which_content == PB_Main_app_get_error_request_tag); @@ -332,6 +367,7 @@ void rpc_system_app_confirm(RpcAppSystem* rpc_app, bool result) { rpc_app->last_event_type == RpcAppEventTypeLoadFile || rpc_app->last_event_type == RpcAppEventTypeButtonPress || rpc_app->last_event_type == RpcAppEventTypeButtonRelease || + rpc_app->last_event_type == RpcAppEventTypeButtonPressRelease || rpc_app->last_event_type == RpcAppEventTypeDataExchange); const uint32_t last_command_id = rpc_app->last_command_id; @@ -432,6 +468,9 @@ void* rpc_system_app_alloc(RpcSession* session) { rpc_handler.message_handler = rpc_system_app_button_release; rpc_add_handler(session, PB_Main_app_button_release_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_system_app_button_press_release; + rpc_add_handler(session, PB_Main_app_button_press_release_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_system_app_get_error_process; rpc_add_handler(session, PB_Main_app_get_error_request_tag, &rpc_handler); diff --git a/applications/services/rpc/rpc_app.h b/applications/services/rpc/rpc_app.h index aa6fd81cc..377d9ccb3 100644 --- a/applications/services/rpc/rpc_app.h +++ b/applications/services/rpc/rpc_app.h @@ -90,6 +90,13 @@ typedef enum { * all activities to be conducted while a button is being pressed. */ RpcAppEventTypeButtonRelease, + /** + * @brief The client has informed the application that a button has been pressed and released. + * + * This command's meaning is application-specific, e.g. to perform an action + * once without repeating it. + */ + RpcAppEventTypeButtonPressRelease, /** * @brief The client has sent a byte array of arbitrary size. * @@ -162,6 +169,7 @@ void rpc_system_app_send_exited(RpcAppSystem* rpc_app); * - RpcAppEventTypeLoadFile * - RpcAppEventTypeButtonPress * - RpcAppEventTypeButtonRelease + * - RpcAppEventTypeButtonPressRelease * - RpcAppEventTypeDataExchange * * Not confirming these events will result in a client-side timeout. diff --git a/assets/protobuf b/assets/protobuf index 6c7c0d55e..1c84fa489 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 6c7c0d55e82cb89223cf4890a540af4cff837fa7 +Subproject commit 1c84fa48919cbb71d1cc65236fc0ee36740e24c6 From 99175796199ef4e0d6a166d3beb7db18c8fc071c Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Wed, 18 Dec 2024 21:23:29 +0200 Subject: [PATCH 21/59] Increase system stack's reserved memory size (#4025) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- targets/f7/stm32wb55xx_flash.ld | 2 +- targets/f7/stm32wb55xx_ram_fw.ld | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/f7/stm32wb55xx_flash.ld b/targets/f7/stm32wb55xx_flash.ld index 524da6fc3..ef61bb238 100644 --- a/targets/f7/stm32wb55xx_flash.ld +++ b/targets/f7/stm32wb55xx_flash.ld @@ -3,7 +3,7 @@ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _stack_end = 0x20030000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ -_stack_size = 0x200; /* required amount of stack */ +_stack_size = 0x400; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K diff --git a/targets/f7/stm32wb55xx_ram_fw.ld b/targets/f7/stm32wb55xx_ram_fw.ld index f0e8ad678..93579788d 100644 --- a/targets/f7/stm32wb55xx_ram_fw.ld +++ b/targets/f7/stm32wb55xx_ram_fw.ld @@ -3,7 +3,7 @@ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _stack_end = 0x20030000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ -_stack_size = 0x200; /* required amount of stack */ +_stack_size = 0x400; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K From 8d078e4b8cc7a3e2eb3aafc5f0a0055618511d26 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Thu, 19 Dec 2024 00:38:43 +0400 Subject: [PATCH 22/59] [FL-3927] FuriThread stdin (#3979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: FuriThread stdin * ci: fix f18 * feat: stdio callback context Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Co-authored-by: あく --- .../unit_tests/tests/furi/furi_stdio_test.c | 108 ++++++++++++++++++ .../debug/unit_tests/tests/furi/furi_test.c | 8 ++ applications/services/cli/cli.c | 10 +- applications/services/cli/cli_i.h | 3 +- applications/services/cli/cli_vcp.c | 9 +- furi/core/string.h | 8 +- furi/core/thread.c | 80 +++++++++++-- furi/core/thread.h | 59 +++++++++- lib/print/SConscript | 20 ++-- lib/print/wrappers.c | 47 +++++++- lib/print/wrappers.h | 6 + targets/f18/api_symbols.csv | 13 ++- targets/f7/api_symbols.csv | 13 ++- 13 files changed, 346 insertions(+), 38 deletions(-) create mode 100644 applications/debug/unit_tests/tests/furi/furi_stdio_test.c diff --git a/applications/debug/unit_tests/tests/furi/furi_stdio_test.c b/applications/debug/unit_tests/tests/furi/furi_stdio_test.c new file mode 100644 index 000000000..94e2f613b --- /dev/null +++ b/applications/debug/unit_tests/tests/furi/furi_stdio_test.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include "../test.h" // IWYU pragma: keep + +#define TAG "StdioTest" + +#define CONTEXT_MAGIC ((void*)0xDEADBEEF) + +// stdin + +static char mock_in[256]; +static size_t mock_in_len, mock_in_pos; + +static void set_mock_in(const char* str) { + size_t len = strlen(str); + strcpy(mock_in, str); + mock_in_len = len; + mock_in_pos = 0; +} + +static size_t mock_in_cb(char* buffer, size_t size, FuriWait wait, void* context) { + UNUSED(wait); + furi_check(context == CONTEXT_MAGIC); + size_t remaining = mock_in_len - mock_in_pos; + size = MIN(remaining, size); + memcpy(buffer, mock_in + mock_in_pos, size); + mock_in_pos += size; + return size; +} + +void test_stdin(void) { + FuriThreadStdinReadCallback in_cb = furi_thread_get_stdin_callback(); + furi_thread_set_stdin_callback(mock_in_cb, CONTEXT_MAGIC); + char buf[256]; + + // plain in + set_mock_in("Hello, World!\n"); + fgets(buf, sizeof(buf), stdin); + mu_assert_string_eq("Hello, World!\n", buf); + mu_assert_int_eq(EOF, getchar()); + + // ungetc + ungetc('i', stdin); + ungetc('H', stdin); + fgets(buf, sizeof(buf), stdin); + mu_assert_string_eq("Hi", buf); + mu_assert_int_eq(EOF, getchar()); + + // ungetc + plain in + set_mock_in(" World"); + ungetc('i', stdin); + ungetc('H', stdin); + fgets(buf, sizeof(buf), stdin); + mu_assert_string_eq("Hi World", buf); + mu_assert_int_eq(EOF, getchar()); + + // partial plain in + set_mock_in("Hello, World!\n"); + fgets(buf, strlen("Hello") + 1, stdin); + mu_assert_string_eq("Hello", buf); + mu_assert_int_eq(',', getchar()); + fgets(buf, sizeof(buf), stdin); + mu_assert_string_eq(" World!\n", buf); + + furi_thread_set_stdin_callback(in_cb, CONTEXT_MAGIC); +} + +// stdout + +static FuriString* mock_out; +FuriThreadStdoutWriteCallback original_out_cb; + +static void mock_out_cb(const char* data, size_t size, void* context) { + furi_check(context == CONTEXT_MAGIC); + // there's no furi_string_cat_strn :( + for(size_t i = 0; i < size; i++) { + furi_string_push_back(mock_out, data[i]); + } +} + +static void assert_and_clear_mock_out(const char* expected) { + // return the original stdout callback for the duration of the check + // if the check fails, we don't want the error to end up in our buffer, + // we want to be able to see it! + furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC); + mu_assert_string_eq(expected, furi_string_get_cstr(mock_out)); + furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC); + + furi_string_reset(mock_out); +} + +void test_stdout(void) { + original_out_cb = furi_thread_get_stdout_callback(); + furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC); + mock_out = furi_string_alloc(); + + puts("Hello, World!"); + assert_and_clear_mock_out("Hello, World!\n"); + + printf("He"); + printf("llo!"); + fflush(stdout); + assert_and_clear_mock_out("Hello!"); + + furi_string_free(mock_out); + furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC); +} diff --git a/applications/debug/unit_tests/tests/furi/furi_test.c b/applications/debug/unit_tests/tests/furi/furi_test.c index 193a8124d..f23be37a9 100644 --- a/applications/debug/unit_tests/tests/furi/furi_test.c +++ b/applications/debug/unit_tests/tests/furi/furi_test.c @@ -10,6 +10,8 @@ void test_furi_memmgr(void); void test_furi_event_loop(void); void test_errno_saving(void); void test_furi_primitives(void); +void test_stdin(void); +void test_stdout(void); static int foo = 0; @@ -52,6 +54,11 @@ MU_TEST(mu_test_furi_primitives) { test_furi_primitives(); } +MU_TEST(mu_test_stdio) { + test_stdin(); + test_stdout(); +} + MU_TEST_SUITE(test_suite) { MU_SUITE_CONFIGURE(&test_setup, &test_teardown); MU_RUN_TEST(test_check); @@ -61,6 +68,7 @@ MU_TEST_SUITE(test_suite) { MU_RUN_TEST(mu_test_furi_pubsub); MU_RUN_TEST(mu_test_furi_memmgr); MU_RUN_TEST(mu_test_furi_event_loop); + MU_RUN_TEST(mu_test_stdio); MU_RUN_TEST(mu_test_errno_saving); MU_RUN_TEST(mu_test_furi_primitives); } diff --git a/applications/services/cli/cli.c b/applications/services/cli/cli.c index 0d8f52c04..28ba417c2 100644 --- a/applications/services/cli/cli.c +++ b/applications/services/cli/cli.c @@ -431,9 +431,9 @@ void cli_session_open(Cli* cli, void* session) { cli->session = session; if(cli->session != NULL) { cli->session->init(); - furi_thread_set_stdout_callback(cli->session->tx_stdout); + furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL); } else { - furi_thread_set_stdout_callback(NULL); + furi_thread_set_stdout_callback(NULL, NULL); } furi_semaphore_release(cli->idle_sem); furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); @@ -447,7 +447,7 @@ void cli_session_close(Cli* cli) { cli->session->deinit(); } cli->session = NULL; - furi_thread_set_stdout_callback(NULL); + furi_thread_set_stdout_callback(NULL, NULL); furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); } @@ -461,9 +461,9 @@ int32_t cli_srv(void* p) { furi_record_create(RECORD_CLI, cli); if(cli->session != NULL) { - furi_thread_set_stdout_callback(cli->session->tx_stdout); + furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL); } else { - furi_thread_set_stdout_callback(NULL); + furi_thread_set_stdout_callback(NULL, NULL); } if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) { diff --git a/applications/services/cli/cli_i.h b/applications/services/cli/cli_i.h index d4cac6e7d..d7351b9ff 100644 --- a/applications/services/cli/cli_i.h +++ b/applications/services/cli/cli_i.h @@ -28,8 +28,9 @@ struct CliSession { void (*init)(void); void (*deinit)(void); size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout); + size_t (*rx_stdin)(uint8_t* buffer, size_t size, uint32_t timeout, void* context); void (*tx)(const uint8_t* buffer, size_t size); - void (*tx_stdout)(const char* data, size_t size); + void (*tx_stdout)(const char* data, size_t size, void* context); bool (*is_connected)(void); }; diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index cdabaaa05..aa399e78a 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -242,6 +242,11 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) { return rx_cnt; } +static size_t cli_vcp_rx_stdin(uint8_t* data, size_t size, uint32_t timeout, void* context) { + UNUSED(context); + return cli_vcp_rx(data, size, timeout); +} + static void cli_vcp_tx(const uint8_t* buffer, size_t size) { furi_assert(vcp); furi_assert(buffer); @@ -267,7 +272,8 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) { VCP_DEBUG("tx %u end", size); } -static void cli_vcp_tx_stdout(const char* data, size_t size) { +static void cli_vcp_tx_stdout(const char* data, size_t size, void* context) { + UNUSED(context); cli_vcp_tx((const uint8_t*)data, size); } @@ -310,6 +316,7 @@ CliSession cli_vcp = { cli_vcp_init, cli_vcp_deinit, cli_vcp_rx, + cli_vcp_rx_stdin, cli_vcp_tx, cli_vcp_tx_stdout, cli_vcp_is_connected, diff --git a/furi/core/string.h b/furi/core/string.h index 84b8c6a24..0d407356b 100644 --- a/furi/core/string.h +++ b/furi/core/string.h @@ -129,12 +129,12 @@ void furi_string_swap(FuriString* string_1, FuriString* string_2); /** Move string_2 content to string_1. * - * Set the string to the other one, and destroy the other one. + * Copy data from one string to another and destroy the source. * - * @param string_1 The FuriString instance 1 - * @param string_2 The FuriString instance 2 + * @param destination The destination FuriString + * @param source The source FuriString */ -void furi_string_move(FuriString* string_1, FuriString* string_2); +void furi_string_move(FuriString* destination, FuriString* source); /** Compute a hash for the string. * diff --git a/furi/core/thread.c b/furi/core/thread.c index fd576ea72..6e5157957 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -23,12 +23,17 @@ #define THREAD_MAX_STACK_SIZE (UINT16_MAX * sizeof(StackType_t)) -typedef struct FuriThreadStdout FuriThreadStdout; - -struct FuriThreadStdout { +typedef struct { FuriThreadStdoutWriteCallback write_callback; FuriString* buffer; -}; + void* context; +} FuriThreadStdout; + +typedef struct { + FuriThreadStdinReadCallback read_callback; + FuriString* unread_buffer; // output.buffer = furi_string_alloc(); + thread->input.unread_buffer = furi_string_alloc(); FuriThread* parent = NULL; if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { @@ -245,6 +252,7 @@ void furi_thread_free(FuriThread* thread) { } furi_string_free(thread->output.buffer); + furi_string_free(thread->input.unread_buffer); free(thread); } @@ -710,13 +718,22 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id) { static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size) { if(thread->output.write_callback != NULL) { - thread->output.write_callback(data, size); + thread->output.write_callback(data, size, thread->output.context); } else { furi_log_tx((const uint8_t*)data, size); } return size; } +static size_t + __furi_thread_stdin_read(FuriThread* thread, char* data, size_t size, FuriWait timeout) { + if(thread->input.read_callback != NULL) { + return thread->input.read_callback(data, size, timeout, thread->input.context); + } else { + return 0; + } +} + static int32_t __furi_thread_stdout_flush(FuriThread* thread) { FuriString* buffer = thread->output.buffer; size_t size = furi_string_size(buffer); @@ -727,19 +744,33 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) { return 0; } -void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { - FuriThread* thread = furi_thread_get_current(); - furi_check(thread); - __furi_thread_stdout_flush(thread); - thread->output.write_callback = callback; -} - FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void) { FuriThread* thread = furi_thread_get_current(); furi_check(thread); return thread->output.write_callback; } +FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void) { + FuriThread* thread = furi_thread_get_current(); + furi_check(thread); + return thread->input.read_callback; +} + +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback, void* context) { + FuriThread* thread = furi_thread_get_current(); + furi_check(thread); + __furi_thread_stdout_flush(thread); + thread->output.write_callback = callback; + thread->output.context = context; +} + +void furi_thread_set_stdin_callback(FuriThreadStdinReadCallback callback, void* context) { + FuriThread* thread = furi_thread_get_current(); + furi_check(thread); + thread->input.read_callback = callback; + thread->input.context = context; +} + size_t furi_thread_stdout_write(const char* data, size_t size) { FuriThread* thread = furi_thread_get_current(); furi_check(thread); @@ -772,6 +803,31 @@ int32_t furi_thread_stdout_flush(void) { return __furi_thread_stdout_flush(thread); } +size_t furi_thread_stdin_read(char* buffer, size_t size, FuriWait timeout) { + FuriThread* thread = furi_thread_get_current(); + furi_check(thread); + + size_t from_buffer = MIN(furi_string_size(thread->input.unread_buffer), size); + size_t from_input = size - from_buffer; + size_t from_input_actual = + __furi_thread_stdin_read(thread, buffer + from_buffer, from_input, timeout); + memcpy(buffer, furi_string_get_cstr(thread->input.unread_buffer), from_buffer); + furi_string_right(thread->input.unread_buffer, from_buffer); + + return from_buffer + from_input_actual; +} + +void furi_thread_stdin_unread(char* buffer, size_t size) { + FuriThread* thread = furi_thread_get_current(); + furi_check(thread); + + FuriString* new_buf = furi_string_alloc(); // there's no furi_string_alloc_set_strn :( + furi_string_set_strn(new_buf, buffer, size); + furi_string_cat(new_buf, thread->input.unread_buffer); + furi_string_free(thread->input.unread_buffer); + thread->input.unread_buffer = new_buf; +} + void furi_thread_suspend(FuriThreadId thread_id) { furi_check(thread_id); diff --git a/furi/core/thread.h b/furi/core/thread.h index ed7aa4553..9abfde5cd 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -74,8 +74,23 @@ typedef int32_t (*FuriThreadCallback)(void* context); * * @param[in] data pointer to the data to be written to the standard out * @param[in] size size of the data in bytes + * @param[in] context optional context */ -typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size); +typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size, void* context); + +/** + * @brief Standard input callback function pointer type + * + * The function to be used as a standard input callback MUST follow this signature. + * + * @param[out] buffer buffer to read data into + * @param[in] size maximum number of bytes to read into the buffer + * @param[in] timeout how long to wait for (in ticks) before giving up + * @param[in] context optional context + * @returns number of bytes that was actually read into the buffer + */ +typedef size_t ( + *FuriThreadStdinReadCallback)(char* buffer, size_t size, FuriWait timeout, void* context); /** * @brief State change callback function pointer type. @@ -468,13 +483,30 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); */ FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void); +/** + * @brief Get the standard input callback for the current thead. + * + * @return pointer to the standard in callback function + */ +FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void); + /** Set standard output callback for the current thread. * * @param[in] callback pointer to the callback function or NULL to clear + * @param[in] context context to be passed to the callback */ -void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback, void* context); + +/** Set standard input callback for the current thread. + * + * @param[in] callback pointer to the callback function or NULL to clear + * @param[in] context context to be passed to the callback + */ +void furi_thread_set_stdin_callback(FuriThreadStdinReadCallback callback, void* context); /** Write data to buffered standard output. + * + * @note You can also use the standard C `putc`, `puts`, `printf` and friends. * * @param[in] data pointer to the data to be written * @param[in] size data size in bytes @@ -489,6 +521,29 @@ size_t furi_thread_stdout_write(const char* data, size_t size); */ int32_t furi_thread_stdout_flush(void); +/** Read data from the standard input + * + * @note You can also use the standard C `getc`, `gets` and friends. + * + * @param[in] buffer pointer to the buffer to read data into + * @param[in] size how many bytes to read into the buffer + * @param[in] timeout how long to wait for (in ticks) before giving up + * @return number of bytes that was actually read + */ +size_t furi_thread_stdin_read(char* buffer, size_t size, FuriWait timeout); + +/** Puts data back into the standard input buffer + * + * `furi_thread_stdin_read` will return the bytes in the same order that they + * were supplied to this function. + * + * @note You can also use the standard C `ungetc`. + * + * @param[in] buffer pointer to the buffer to get data from + * @param[in] size how many bytes to read from the buffer + */ +void furi_thread_stdin_unread(char* buffer, size_t size); + /** * @brief Suspend a thread. * diff --git a/lib/print/SConscript b/lib/print/SConscript index 07be8d890..90028cf06 100644 --- a/lib/print/SConscript +++ b/lib/print/SConscript @@ -44,18 +44,24 @@ wrapped_fn_list = [ "vsiprintf", "vsniprintf", # - # Scanf is not implemented 4 now + # standard input + # + "fgetc", + "getc", + "getchar", + "fgets", + "ungetc", + # + # standard input, but unimplemented + # + "gets", + # + # scanf, not implemented for now # # "fscanf", # "scanf", # "sscanf", # "vsprintf", - # "fgetc", - # "fgets", - # "getc", - # "getchar", - # "gets", - # "ungetc", # "vfscanf", # "vscanf", # "vsscanf", diff --git a/lib/print/wrappers.c b/lib/print/wrappers.c index c8d72d192..18df92def 100644 --- a/lib/print/wrappers.c +++ b/lib/print/wrappers.c @@ -51,11 +51,54 @@ int __wrap_snprintf(char* str, size_t size, const char* format, ...) { } int __wrap_fflush(FILE* stream) { - UNUSED(stream); - furi_thread_stdout_flush(); + if(stream == stdout) furi_thread_stdout_flush(); return 0; } +int __wrap_fgetc(FILE* stream) { + if(stream != stdin) return EOF; + char c; + if(furi_thread_stdin_read(&c, 1, FuriWaitForever) == 0) return EOF; + return c; +} + +int __wrap_getc(FILE* stream) { + return __wrap_fgetc(stream); +} + +int __wrap_getchar(void) { + return __wrap_fgetc(stdin); +} + +char* __wrap_fgets(char* str, size_t n, FILE* stream) { + // leave space for the zero terminator + furi_check(n >= 1); + n--; + + if(stream != stdin) { + *str = '\0'; + return str; + } + + // read characters + int c; + do { + c = __wrap_fgetc(stdin); + if(c > 0) *(str++) = c; + } while(c != EOF && c != '\n' && --n); + + // place zero terminator + *str = '\0'; + return str; +} + +int __wrap_ungetc(int ch, FILE* stream) { + char c = ch; + if(stream != stdin) return EOF; + furi_thread_stdin_unread(&c, 1); + return ch; +} + __attribute__((__noreturn__)) void __wrap___assert(const char* file, int line, const char* e) { UNUSED(file); UNUSED(line); diff --git a/lib/print/wrappers.h b/lib/print/wrappers.h index 3cec88249..8a4599b41 100644 --- a/lib/print/wrappers.h +++ b/lib/print/wrappers.h @@ -16,6 +16,12 @@ int __wrap_putc(int ch, FILE* stream); int __wrap_snprintf(char* str, size_t size, const char* format, ...); int __wrap_fflush(FILE* stream); +int __wrap_fgetc(FILE* stream); +int __wrap_getc(FILE* stream); +int __wrap_getchar(void); +char* __wrap_fgets(char* str, size_t n, FILE* stream); +int __wrap_ungetc(int ch, FILE* stream); + __attribute__((__noreturn__)) void __wrap___assert(const char* file, int line, const char* e); __attribute__((__noreturn__)) void diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index b5d51a0dd..23421712d 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,78.1,, +Version,+,79.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -371,11 +371,16 @@ Function,-,__utoa,char*,"unsigned, char*, int" Function,+,__wrap___assert,void,"const char*, int, const char*" Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*" Function,+,__wrap_fflush,int,FILE* +Function,+,__wrap_fgetc,int,FILE* +Function,+,__wrap_fgets,char*,"char*, size_t, FILE*" +Function,+,__wrap_getc,int,FILE* +Function,+,__wrap_getchar,int, Function,+,__wrap_printf,int,"const char*, ..." Function,+,__wrap_putc,int,"int, FILE*" Function,+,__wrap_putchar,int,int Function,+,__wrap_puts,int,const char* Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..." +Function,+,__wrap_ungetc,int,"int, FILE*" Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list" Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..." Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..." @@ -1654,6 +1659,7 @@ Function,+,furi_thread_get_return_code,int32_t,FuriThread* Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* +Function,+,furi_thread_get_stdin_callback,FuriThreadStdinReadCallback, Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, Function,+,furi_thread_is_suspended,_Bool,FuriThreadId Function,+,furi_thread_join,_Bool,FuriThread* @@ -1674,9 +1680,12 @@ Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCa Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdin_callback,void,"FuriThreadStdinReadCallback, void*" +Function,+,furi_thread_set_stdout_callback,void,"FuriThreadStdoutWriteCallback, void*" Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*" Function,+,furi_thread_start,void,FuriThread* +Function,+,furi_thread_stdin_read,size_t,"char*, size_t, FuriWait" +Function,+,furi_thread_stdin_unread,void,"char*, size_t" Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" Function,+,furi_thread_suspend,void,FuriThreadId diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index ee81f76a9..6f9fc5466 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,78.1,, +Version,+,79.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -448,11 +448,16 @@ Function,-,__utoa,char*,"unsigned, char*, int" Function,+,__wrap___assert,void,"const char*, int, const char*" Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*" Function,+,__wrap_fflush,int,FILE* +Function,+,__wrap_fgetc,int,FILE* +Function,+,__wrap_fgets,char*,"char*, size_t, FILE*" +Function,+,__wrap_getc,int,FILE* +Function,+,__wrap_getchar,int, Function,+,__wrap_printf,int,"const char*, ..." Function,+,__wrap_putc,int,"int, FILE*" Function,+,__wrap_putchar,int,int Function,+,__wrap_puts,int,const char* Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..." +Function,+,__wrap_ungetc,int,"int, FILE*" Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list" Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..." Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..." @@ -1873,6 +1878,7 @@ Function,+,furi_thread_get_return_code,int32_t,FuriThread* Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* +Function,+,furi_thread_get_stdin_callback,FuriThreadStdinReadCallback, Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, Function,+,furi_thread_is_suspended,_Bool,FuriThreadId Function,+,furi_thread_join,_Bool,FuriThread* @@ -1893,9 +1899,12 @@ Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCa Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdin_callback,void,"FuriThreadStdinReadCallback, void*" +Function,+,furi_thread_set_stdout_callback,void,"FuriThreadStdoutWriteCallback, void*" Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*" Function,+,furi_thread_start,void,FuriThread* +Function,+,furi_thread_stdin_read,size_t,"char*, size_t, FuriWait" +Function,+,furi_thread_stdin_unread,void,"char*, size_t" Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" Function,+,furi_thread_suspend,void,FuriThreadId From 8c4922a32212a47b25fde268365cd0068003fbdc Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Wed, 18 Dec 2024 22:55:21 +0200 Subject: [PATCH 23/59] Update `infrared_test.c` reference (#3983) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Emmanuel Ferdman Co-authored-by: あく --- documentation/UnitTests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/UnitTests.md b/documentation/UnitTests.md index 9711c6ae1..5d04c8f67 100644 --- a/documentation/UnitTests.md +++ b/documentation/UnitTests.md @@ -43,7 +43,7 @@ To add unit tests for your protocol, follow these steps: 1. Create a file named `test_.irtest` in the [assets](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/debug/unit_tests/resources/unit_tests/infrared) directory. 2. Fill it with the test data (more on it below). -3. Add the test code to [infrared_test.c](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/applications/debug/unit_tests/infrared/infrared_test.c). +3. Add the test code to [infrared_test.c](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/applications/debug/unit_tests/tests/infrared/infrared_test.c). 4. Build and install firmware with resources, install it on your Flipper and run the tests to see if they pass. ##### Test data format From 9c96bbfc540b0719cb58095e88fb9dc06b5c61d2 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Thu, 19 Dec 2024 00:01:20 +0300 Subject: [PATCH 24/59] [NFC] Fix ISO15693 stucking in wrong mode. (#3988) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/signal_reader/parsers/iso15693/iso15693_parser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/signal_reader/parsers/iso15693/iso15693_parser.c b/lib/signal_reader/parsers/iso15693/iso15693_parser.c index a2c6912e6..e47c734a2 100644 --- a/lib/signal_reader/parsers/iso15693/iso15693_parser.c +++ b/lib/signal_reader/parsers/iso15693/iso15693_parser.c @@ -243,6 +243,8 @@ static Iso15693ParserCommand iso15693_parser_parse_1_out_of_256(Iso15693Parser* instance->parsed_frame, instance->next_byte_part * 4 + j / 2); } } + } else { + instance->zero_found = true; } } instance->next_byte_part = (instance->next_byte_part + 1) % 64; From a7b3a135815f403006b52ba55d7e82234378a596 Mon Sep 17 00:00:00 2001 From: WillyJL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:33:59 +0100 Subject: [PATCH 25/59] Loader: Fix BusFault in handling of OOM (#3992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Loader: Fix BusFault in handling of OOM * Furi: fix crash in aligned_alloc, cleanup aligned_alloc use Co-authored-by: あく --- furi/core/memmgr.c | 4 +++- lib/flipper_application/elf/elf_file.c | 12 +++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index d3ff873ae..8ee0d1723 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -106,5 +106,7 @@ void* aligned_malloc(size_t size, size_t alignment) { } void aligned_free(void* p) { - free(((void**)p)[-1]); + if(p) { + free(((void**)p)[-1]); + } } diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index d0c4f52fb..bd8ecdf7e 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -8,11 +8,11 @@ #define TAG "Elf" -#define ELF_NAME_BUFFER_LEN 32 -#define SECTION_OFFSET(e, n) ((e)->section_table + (n) * sizeof(Elf32_Shdr)) -#define IS_FLAGS_SET(v, m) (((v) & (m)) == (m)) +#define ELF_NAME_BUFFER_LEN 32 +#define SECTION_OFFSET(e, n) ((e)->section_table + (n) * sizeof(Elf32_Shdr)) +#define IS_FLAGS_SET(v, m) (((v) & (m)) == (m)) #define RESOLVER_THREAD_YIELD_STEP 30 -#define FAST_RELOCATION_VERSION 1 +#define FAST_RELOCATION_VERSION 1 // #define ELF_DEBUG_LOG 1 @@ -830,9 +830,7 @@ void elf_file_free(ELFFile* elf) { for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); ELFSectionDict_next(it)) { const ELFSectionDict_itref_t* itref = ELFSectionDict_cref(it); - if(itref->value.data) { - aligned_free(itref->value.data); - } + aligned_free(itref->value.data); if(itref->value.fast_rel) { aligned_free(itref->value.fast_rel->data); free(itref->value.fast_rel); From 8dd5e64c0384edf93f33eaf01fce412c38a3858d Mon Sep 17 00:00:00 2001 From: Evgeny E <10674163+ssecsd@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:52:37 +0000 Subject: [PATCH 26/59] Move updater and unit tests to dockerized runner (#4028) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * extended unit_tests and changed to dockerized runner * added branch to run units * fixing unit-tests-output * online output * command not found fix * added stm logging * cleaned output * Updated updater test to work on dockerized runner * Test run for changed actions * small refactor of run_unit_tests * Final test of jobs * Checked * On-failure actions runs only on fail * Set action trigger to pull request * Bumped timeout a little * Removed extra steps * Removed stm monitor, as it's now part of docker-runner * fix: testops without stm_monitoring * fix: timeout extended Co-authored-by: あく --- .github/workflows/unit_tests.yml | 48 ++++------ .github/workflows/updater_test.yml | 54 ++--------- scripts/testops.py | 148 +++++++++++++++++++---------- 3 files changed, 127 insertions(+), 123 deletions(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index d37337452..309dd7ebd 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -5,54 +5,39 @@ on: env: TARGETS: f7 DEFAULT_TARGET: f7 - FBT_TOOLCHAIN_PATH: /opt + FBT_TOOLCHAIN_PATH: /opt/ FBT_GIT_SUBMODULE_SHALLOW: 1 jobs: run_units_on_bench: - runs-on: [self-hosted, FlipperZeroUnitTest] + runs-on: [ self-hosted, FlipperZeroTest ] steps: - - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 1 ref: ${{ github.event.pull_request.head.sha }} - - name: 'Get flipper from device manager (mock)' - id: device - run: | - echo "flipper=auto" >> $GITHUB_OUTPUT - - name: 'Flash unit tests firmware' id: flashing if: success() - timeout-minutes: 10 - run: | - ./fbt resources firmware_latest flash SWD_TRANSPORT_SERIAL=2A0906016415303030303032 LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 - - - name: 'Wait for flipper and format ext' - id: format_ext - if: steps.flashing.outcome == 'success' - timeout-minutes: 5 + timeout-minutes: 20 run: | source scripts/toolchain/fbtenv.sh - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=120 await_flipper - python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext + ./fbt resources firmware_latest flash LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 + - name: 'Copy assets and unit data, reboot and wait for flipper' id: copy - if: steps.format_ext.outcome == 'success' + if: steps.flashing.outcome == 'success' timeout-minutes: 7 run: | source scripts/toolchain/fbtenv.sh - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=15 await_flipper - rm -rf build/latest/resources/dolphin - python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send build/latest/resources /ext - python3 scripts/power.py -p ${{steps.device.outputs.flipper}} reboot - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=15 await_flipper + python3 scripts/testops.py -t=15 await_flipper + python3 scripts/storage.py -f send build/latest/resources /ext + python3 scripts/storage.py -f send /region_data /ext/.int/.region_data + python3 scripts/power.py reboot + python3 scripts/testops.py -t=30 await_flipper - name: 'Run units and validate results' id: run_units @@ -60,9 +45,16 @@ jobs: timeout-minutes: 7 run: | source scripts/toolchain/fbtenv.sh - python3 scripts/testops.py run_units -p ${{steps.device.outputs.flipper}} + python3 scripts/testops.py run_units + + - name: 'Upload test results' + if: failure() && steps.flashing.outcome == 'success' && steps.run_units.outcome != 'skipped' + uses: actions/upload-artifact@v4 + with: + name: unit-tests_output + path: unit_tests*.txt - name: 'Check GDB output' if: failure() && steps.flashing.outcome == 'success' run: | - ./fbt gdb_trace_all SWD_TRANSPORT_SERIAL=2A0906016415303030303032 LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 + ./fbt gdb_trace_all LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index dbe5df883..59cc6e716 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -1,39 +1,31 @@ name: 'Updater test' on: pull_request: + env: TARGETS: f7 DEFAULT_TARGET: f7 - FBT_TOOLCHAIN_PATH: /opt + FBT_TOOLCHAIN_PATH: /opt/ FBT_GIT_SUBMODULE_SHALLOW: 1 jobs: test_updater_on_bench: - runs-on: [self-hosted, FlipperZeroUpdaterTest] + runs-on: [self-hosted, FlipperZeroTest ] steps: - - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 1 - submodules: false ref: ${{ github.event.pull_request.head.sha }} - - name: 'Get flipper from device manager (mock)' - id: device - run: | - echo "flipper=auto" >> $GITHUB_OUTPUT - echo "stlink=0F020D026415303030303032" >> $GITHUB_OUTPUT - - name: 'Flashing target firmware' id: first_full_flash - timeout-minutes: 10 + timeout-minutes: 20 run: | source scripts/toolchain/fbtenv.sh - ./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1 - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=180 await_flipper + python3 scripts/testops.py -t=180 await_flipper + ./fbt flash_usb_full FORCE=1 + - name: 'Validating updater' id: second_full_flash @@ -41,33 +33,7 @@ jobs: if: success() run: | source scripts/toolchain/fbtenv.sh - ./fbt flash_usb PORT=${{steps.device.outputs.flipper}} FORCE=1 - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=180 await_flipper + python3 scripts/testops.py -t=180 await_flipper + ./fbt flash_usb FORCE=1 + python3 scripts/testops.py -t=180 await_flipper - - name: 'Get last release tag' - id: release_tag - if: failure() - run: | - echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT - - - name: 'Wipe workspace' - run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - - - name: 'Checkout latest release' - uses: actions/checkout@v4 - if: failure() - with: - fetch-depth: 1 - ref: ${{ steps.release_tag.outputs.tag }} - - - name: 'Flash last release' - if: failure() - run: | - ./fbt flash SWD_TRANSPORT_SERIAL=${{steps.device.outputs.stlink}} FORCE=1 - - - name: 'Wait for flipper and format ext' - if: failure() - run: | - source scripts/toolchain/fbtenv.sh - python3 scripts/testops.py -p=${{steps.device.outputs.flipper}} -t=180 await_flipper - python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext diff --git a/scripts/testops.py b/scripts/testops.py index 4ae10c7f4..3100a9b7f 100644 --- a/scripts/testops.py +++ b/scripts/testops.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 - import re -import sys import time +from datetime import datetime from typing import Optional from flipper.app import App @@ -11,7 +10,10 @@ from flipper.utils.cdc import resolve_port class Main(App): - # this is basic use without sub-commands, simply to reboot flipper / power it off, not meant as a full CLI wrapper + def __init__(self, no_exit=False): + super().__init__(no_exit) + self.test_results = None + def init(self): self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") self.parser.add_argument( @@ -67,64 +69,108 @@ class Main(App): self.logger.info("Running unit tests") flipper.send("unit_tests" + "\r") self.logger.info("Waiting for unit tests to complete") - data = flipper.read.until(">: ") - self.logger.info("Parsing result") - - lines = data.decode().split("\r\n") - - tests_re = r"Failed tests: \d{0,}" - time_re = r"Consumed: \d{0,}" - leak_re = r"Leaked: \d{0,}" - status_re = r"Status: \w{3,}" - - tests_pattern = re.compile(tests_re) - time_pattern = re.compile(time_re) - leak_pattern = re.compile(leak_re) - status_pattern = re.compile(status_re) tests, elapsed_time, leak, status = None, None, None, None total = 0 + all_required_found = False - for line in lines: - self.logger.info(line) - if "()" in line: - total += 1 + full_output = [] - if not tests: - tests = re.match(tests_pattern, line) - if not elapsed_time: - elapsed_time = re.match(time_pattern, line) - if not leak: - leak = re.match(leak_pattern, line) - if not status: - status = re.match(status_pattern, line) + tests_pattern = re.compile(r"Failed tests: \d{0,}") + time_pattern = re.compile(r"Consumed: \d{0,}") + leak_pattern = re.compile(r"Leaked: \d{0,}") + status_pattern = re.compile(r"Status: \w{3,}") - if None in (tests, elapsed_time, leak, status): - self.logger.error( - f"Failed to parse output: {tests} {elapsed_time} {leak} {status}" + try: + while not all_required_found: + try: + line = flipper.read.until("\r\n", cut_eol=True).decode() + self.logger.info(line) + if "command not found," in line: + self.logger.error(f"Command not found: {line}") + return 1 + + if "()" in line: + total += 1 + self.logger.debug(f"Test completed: {line}") + + if not tests: + tests = tests_pattern.match(line) + if not elapsed_time: + elapsed_time = time_pattern.match(line) + if not leak: + leak = leak_pattern.match(line) + if not status: + status = status_pattern.match(line) + + pattern = re.compile( + r"(\[-]|\[\\]|\[\|]|\[/-]|\[[^\]]*\]|\x1b\[\d+D)" + ) + line_to_append = pattern.sub("", line) + pattern = re.compile(r"\[3D[^\]]*") + line_to_append = pattern.sub("", line_to_append) + line_to_append = f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S,%f')} {line_to_append}" + + full_output.append(line_to_append) + + if tests and elapsed_time and leak and status: + all_required_found = True + try: + remaining = flipper.read.until(">: ", cut_eol=True).decode() + if remaining.strip(): + full_output.append(remaining) + except: + pass + break + + except Exception as e: + self.logger.error(f"Error reading output: {e}") + raise + + if None in (tests, elapsed_time, leak, status): + raise RuntimeError( + f"Failed to parse output: {tests} {elapsed_time} {leak} {status}" + ) + + leak = int(re.findall(r"[- ]\d+", leak.group(0))[0]) + status = re.findall(r"\w+", status.group(0))[1] + tests = int(re.findall(r"\d+", tests.group(0))[0]) + elapsed_time = int(re.findall(r"\d+", elapsed_time.group(0))[0]) + + test_results = { + "full_output": "\n".join(full_output), + "total_tests": total, + "failed_tests": tests, + "elapsed_time_ms": elapsed_time, + "memory_leak_bytes": leak, + "status": status, + } + + self.test_results = test_results + + output_file = "unit_tests_output.txt" + with open(output_file, "w") as f: + f.write(test_results["full_output"]) + + print( + f"::notice:: Total tests: {total} Failed tests: {tests} Status: {status} Elapsed time: {elapsed_time / 1000} s Memory leak: {leak} bytes" ) - sys.exit(1) - leak = int(re.findall(r"[- ]\d+", leak.group(0))[0]) - status = re.findall(r"\w+", status.group(0))[1] - tests = int(re.findall(r"\d+", tests.group(0))[0]) - elapsed_time = int(re.findall(r"\d+", elapsed_time.group(0))[0]) + if tests > 0 or status != "PASSED": + self.logger.error(f"Got {tests} failed tests.") + self.logger.error(f"Leaked (not failing on this stat): {leak}") + self.logger.error(f"Status: {status}") + self.logger.error(f"Time: {elapsed_time / 1000} seconds") + return 1 - if tests > 0 or status != "PASSED": - self.logger.error(f"Got {tests} failed tests.") - self.logger.error(f"Leaked (not failing on this stat): {leak}") - self.logger.error(f"Status: {status}") - self.logger.error(f"Time: {elapsed_time/1000} seconds") + self.logger.info(f"Leaked (not failing on this stat): {leak}") + self.logger.info( + f"Tests ran successfully! Time elapsed {elapsed_time / 1000} seconds. Passed {total} tests." + ) + return 0 + + finally: flipper.stop() - return 1 - - self.logger.info(f"Leaked (not failing on this stat): {leak}") - self.logger.info( - f"Tests ran successfully! Time elapsed {elapsed_time/1000} seconds. Passed {total} tests." - ) - - flipper.stop() - return 0 if __name__ == "__main__": From a02781b93687086f546df1a48f7f0ca3f7724c5a Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Mon, 23 Dec 2024 09:18:14 +0900 Subject: [PATCH 27/59] [FL-3920] Fix lost BadBLE keystrokes (#3993) * WIP: fix lost BadBLE keystrokes * Switch to semaphores for synchronization * Move checking to the gap level * Remove leftovers from hid_service * Remove more leftovers from hid_service * De-allocate the semaphore after use * Change the timeout to account for unforeseen situation * Update F18 API * Fix naming and unbump api version * Move away from semaphores * Remove the left over include * Ble: cleanup error handling in ble_gatt_characteristic_update * Fix PVS warning Co-authored-by: Aleksandr Kutuzov --- lib/ble_profile/extra_services/hid_service.c | 14 ++++---- lib/nfc/protocols/mf_plus/mf_plus_poller.c | 4 +-- lib/subghz/protocols/bin_raw.c | 2 +- targets/f7/ble_glue/furi_ble/gatt.c | 34 +++++++++++++++++--- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/lib/ble_profile/extra_services/hid_service.c b/lib/ble_profile/extra_services/hid_service.c index e46d2010c..9f9a0f752 100644 --- a/lib/ble_profile/extra_services/hid_service.c +++ b/lib/ble_profile/extra_services/hid_service.c @@ -10,13 +10,13 @@ #define TAG "BleHid" #define BLE_SVC_HID_REPORT_MAP_MAX_LEN (255) -#define BLE_SVC_HID_REPORT_MAX_LEN (255) -#define BLE_SVC_HID_REPORT_REF_LEN (2) -#define BLE_SVC_HID_INFO_LEN (4) -#define BLE_SVC_HID_CONTROL_POINT_LEN (1) +#define BLE_SVC_HID_REPORT_MAX_LEN (255) +#define BLE_SVC_HID_REPORT_REF_LEN (2) +#define BLE_SVC_HID_INFO_LEN (4) +#define BLE_SVC_HID_CONTROL_POINT_LEN (1) -#define BLE_SVC_HID_INPUT_REPORT_COUNT (3) -#define BLE_SVC_HID_OUTPUT_REPORT_COUNT (0) +#define BLE_SVC_HID_INPUT_REPORT_COUNT (3) +#define BLE_SVC_HID_OUTPUT_REPORT_COUNT (0) #define BLE_SVC_HID_FEATURE_REPORT_COUNT (0) #define BLE_SVC_HID_REPORT_COUNT \ (BLE_SVC_HID_INPUT_REPORT_COUNT + BLE_SVC_HID_OUTPUT_REPORT_COUNT + \ @@ -157,6 +157,7 @@ static BleEventAckStatus ble_svc_hid_event_handler(void* event, void* context) { hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; // aci_gatt_attribute_modified_event_rp0* attribute_modified; + if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { // Process modification events @@ -274,6 +275,7 @@ bool ble_svc_hid_update_input_report( .data_ptr = data, .data_len = len, }; + return ble_gatt_characteristic_update( hid_svc->svc_handle, &hid_svc->input_report_chars[input_report_num], &report_data); } diff --git a/lib/nfc/protocols/mf_plus/mf_plus_poller.c b/lib/nfc/protocols/mf_plus/mf_plus_poller.c index 8d1cc1c99..57a26a9cf 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus_poller.c +++ b/lib/nfc/protocols/mf_plus/mf_plus_poller.c @@ -146,7 +146,7 @@ static void mf_plus_poller_set_callback( static NfcCommand mf_plus_poller_run(NfcGenericEvent event, void* context) { furi_assert(context); - furi_assert(event.protocol = NfcProtocolIso14443_4a); + furi_assert(event.protocol == NfcProtocolIso14443_4a); furi_assert(event.event_data); MfPlusPoller* instance = context; @@ -178,7 +178,7 @@ void mf_plus_poller_free(MfPlusPoller* instance) { static bool mf_plus_poller_detect(NfcGenericEvent event, void* context) { furi_assert(context); - furi_assert(event.protocol = NfcProtocolIso14443_4a); + furi_assert(event.protocol == NfcProtocolIso14443_4a); furi_assert(event.event_data); MfPlusPoller* instance = context; diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index 8298bce6b..c2aebb6ab 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -314,8 +314,8 @@ SubGhzProtocolStatus flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); if(!subghz_protocol_encoder_bin_raw_get_upload(instance)) { - break; res = SubGhzProtocolStatusErrorEncoderGetUpload; + break; } instance->encoder.is_running = true; diff --git a/targets/f7/ble_glue/furi_ble/gatt.c b/targets/f7/ble_glue/furi_ble/gatt.c index e40786583..b8ab094f9 100644 --- a/targets/f7/ble_glue/furi_ble/gatt.c +++ b/targets/f7/ble_glue/furi_ble/gatt.c @@ -7,6 +7,12 @@ #define GATT_MIN_READ_KEY_SIZE (10) +#ifdef BLE_GATT_STRICT +#define ble_gatt_strict_crash(message) furi_crash(message) +#else +#define ble_gatt_strict_crash(message) +#endif + void ble_gatt_characteristic_init( uint16_t svc_handle, const BleGattCharacteristicParams* char_descriptor, @@ -42,6 +48,7 @@ void ble_gatt_characteristic_init( &char_instance->handle); if(status) { FURI_LOG_E(TAG, "Failed to add %s char: %d", char_descriptor->name, status); + ble_gatt_strict_crash("Failed to add characteristic"); } char_instance->descriptor_handle = 0; @@ -68,6 +75,7 @@ void ble_gatt_characteristic_init( &char_instance->descriptor_handle); if(status) { FURI_LOG_E(TAG, "Failed to add %s char descriptor: %d", char_descriptor->name, status); + ble_gatt_strict_crash("Failed to add characteristic descriptor"); } if(release_data) { free((void*)char_data); @@ -82,6 +90,7 @@ void ble_gatt_characteristic_delete( if(status) { FURI_LOG_E( TAG, "Failed to delete %s char: %d", char_instance->characteristic->name, status); + ble_gatt_strict_crash("Failed to delete characteristic"); } free((void*)char_instance->characteristic); } @@ -111,14 +120,27 @@ bool ble_gatt_characteristic_update( release_data = char_descriptor->data.callback.fn(context, &char_data, &char_data_size); } - tBleStatus result = aci_gatt_update_char_value( - svc_handle, char_instance->handle, 0, char_data_size, char_data); - if(result) { - FURI_LOG_E(TAG, "Failed updating %s characteristic: %d", char_descriptor->name, result); - } + tBleStatus result; + size_t retries_left = 1000; + do { + retries_left--; + result = aci_gatt_update_char_value( + svc_handle, char_instance->handle, 0, char_data_size, char_data); + if(result == BLE_STATUS_INSUFFICIENT_RESOURCES) { + FURI_LOG_W(TAG, "Insufficient resources for %s characteristic", char_descriptor->name); + furi_delay_ms(1); + } + } while(result == BLE_STATUS_INSUFFICIENT_RESOURCES && retries_left); + if(release_data) { free((void*)char_data); } + + if(result != BLE_STATUS_SUCCESS) { + FURI_LOG_E(TAG, "Failed updating %s characteristic: %d", char_descriptor->name, result); + ble_gatt_strict_crash("Failed to update characteristic"); + } + return result != BLE_STATUS_SUCCESS; } @@ -132,6 +154,7 @@ bool ble_gatt_service_add( Service_UUID_Type, Service_UUID, Service_Type, Max_Attribute_Records, Service_Handle); if(result) { FURI_LOG_E(TAG, "Failed to add service: %x", result); + ble_gatt_strict_crash("Failed to add service"); } return result == BLE_STATUS_SUCCESS; @@ -141,6 +164,7 @@ bool ble_gatt_service_delete(uint16_t svc_handle) { tBleStatus result = aci_gatt_del_service(svc_handle); if(result) { FURI_LOG_E(TAG, "Failed to delete service: %x", result); + ble_gatt_strict_crash("Failed to delete service"); } return result == BLE_STATUS_SUCCESS; From 33f1a1609455ed78f19178367056fd63d77d1951 Mon Sep 17 00:00:00 2001 From: WillyJL <49810075+Willy-JL@users.noreply.github.com> Date: Mon, 23 Dec 2024 01:52:37 +0100 Subject: [PATCH 28/59] FBT: Don't lint JS packages (#4030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- firmware.scons | 2 ++ scripts/lint.py | 26 ++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/firmware.scons b/firmware.scons index 4c5e05873..e7378f957 100644 --- a/firmware.scons +++ b/firmware.scons @@ -29,6 +29,8 @@ env = ENV.Clone( TARGETS_ROOT=Dir("#/targets"), LINT_SOURCES=[ Dir("applications"), + # Not C code + Dir("!applications/system/js_app/packages"), ], LIBPATH=[ "${LIB_DIST_DIR}", diff --git a/scripts/lint.py b/scripts/lint.py index 8530209be..896cd3812 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -35,21 +35,25 @@ class Main(App): self.parser_format.set_defaults(func=self.format) @staticmethod - def _filter_lint_directories(dirnames: list[str]): + def _filter_lint_directories( + dirpath: str, dirnames: list[str], excludes: tuple[str] + ): # Skipping 3rd-party code - usually resides in subfolder "lib" if "lib" in dirnames: dirnames.remove("lib") - # Skipping hidden folders + # Skipping hidden and excluded folders for dirname in dirnames.copy(): if dirname.startswith("."): dirnames.remove(dirname) + if os.path.join(dirpath, dirname).startswith(excludes): + dirnames.remove(dirname) - def _check_folders(self, folders: list): + def _check_folders(self, folders: list, excludes: tuple[str]): show_message = False pattern = re.compile(SOURCE_CODE_DIR_PATTERN) for folder in folders: for dirpath, dirnames, filenames in os.walk(folder): - self._filter_lint_directories(dirnames) + self._filter_lint_directories(dirpath, dirnames, excludes) for dirname in dirnames: if not pattern.match(dirname): @@ -61,11 +65,11 @@ class Main(App): "Folders are not renamed automatically, please fix it by yourself" ) - def _find_sources(self, folders: list): + def _find_sources(self, folders: list, excludes: tuple[str]): output = [] for folder in folders: for dirpath, dirnames, filenames in os.walk(folder): - self._filter_lint_directories(dirnames) + self._filter_lint_directories(dirpath, dirnames, excludes) for filename in filenames: ext = os.path.splitext(filename.lower())[1] @@ -168,14 +172,20 @@ class Main(App): def _perform(self, dry_run: bool): result = 0 - sources = self._find_sources(self.args.input) + excludes = [] + for folder in self.args.input.copy(): + if folder.startswith("!"): + excludes.append(folder.removeprefix("!")) + self.args.input.remove(folder) + excludes = tuple(excludes) + sources = self._find_sources(self.args.input, excludes) if not self._format_sources(sources, dry_run=dry_run): result |= 0b001 if not self._apply_file_naming_convention(sources, dry_run=dry_run): result |= 0b010 if not self._apply_file_permissions(sources, dry_run=dry_run): result |= 0b100 - self._check_folders(self.args.input) + self._check_folders(self.args.input, excludes) return result def check(self): From 6d20bc7e50df4384d8713dd3f9f17042a097f30f Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Mon, 23 Dec 2024 10:09:40 +0900 Subject: [PATCH 29/59] [FL-3938] Add winter animations (#4032) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add winter animations * Format images Co-authored-by: あく --- .../L1_Happy_holidays_128x64/frame_0.png | Bin 0 -> 858 bytes .../L1_Happy_holidays_128x64/frame_1.png | Bin 0 -> 855 bytes .../L1_Happy_holidays_128x64/frame_10.png | Bin 0 -> 872 bytes .../L1_Happy_holidays_128x64/frame_11.png | Bin 0 -> 861 bytes .../L1_Happy_holidays_128x64/frame_12.png | Bin 0 -> 853 bytes .../L1_Happy_holidays_128x64/frame_2.png | Bin 0 -> 851 bytes .../L1_Happy_holidays_128x64/frame_3.png | Bin 0 -> 852 bytes .../L1_Happy_holidays_128x64/frame_4.png | Bin 0 -> 856 bytes .../L1_Happy_holidays_128x64/frame_5.png | Bin 0 -> 850 bytes .../L1_Happy_holidays_128x64/frame_6.png | Bin 0 -> 851 bytes .../L1_Happy_holidays_128x64/frame_7.png | Bin 0 -> 860 bytes .../L1_Happy_holidays_128x64/frame_8.png | Bin 0 -> 857 bytes .../L1_Happy_holidays_128x64/frame_9.png | Bin 0 -> 863 bytes .../L1_Happy_holidays_128x64/meta.txt | 23 ++++++++++++++++++ .../L1_Sleigh_ride_128x64/frame_0.png | Bin 0 -> 820 bytes .../L1_Sleigh_ride_128x64/frame_1.png | Bin 0 -> 881 bytes .../L1_Sleigh_ride_128x64/frame_10.png | Bin 0 -> 788 bytes .../L1_Sleigh_ride_128x64/frame_11.png | Bin 0 -> 816 bytes .../L1_Sleigh_ride_128x64/frame_12.png | Bin 0 -> 864 bytes .../L1_Sleigh_ride_128x64/frame_13.png | Bin 0 -> 798 bytes .../L1_Sleigh_ride_128x64/frame_14.png | Bin 0 -> 813 bytes .../L1_Sleigh_ride_128x64/frame_15.png | Bin 0 -> 879 bytes .../L1_Sleigh_ride_128x64/frame_16.png | Bin 0 -> 855 bytes .../L1_Sleigh_ride_128x64/frame_17.png | Bin 0 -> 772 bytes .../L1_Sleigh_ride_128x64/frame_18.png | Bin 0 -> 817 bytes .../L1_Sleigh_ride_128x64/frame_19.png | Bin 0 -> 867 bytes .../L1_Sleigh_ride_128x64/frame_2.png | Bin 0 -> 866 bytes .../L1_Sleigh_ride_128x64/frame_20.png | Bin 0 -> 809 bytes .../L1_Sleigh_ride_128x64/frame_21.png | Bin 0 -> 795 bytes .../L1_Sleigh_ride_128x64/frame_22.png | Bin 0 -> 870 bytes .../L1_Sleigh_ride_128x64/frame_23.png | Bin 0 -> 852 bytes .../L1_Sleigh_ride_128x64/frame_24.png | Bin 0 -> 805 bytes .../L1_Sleigh_ride_128x64/frame_25.png | Bin 0 -> 858 bytes .../L1_Sleigh_ride_128x64/frame_26.png | Bin 0 -> 830 bytes .../L1_Sleigh_ride_128x64/frame_27.png | Bin 0 -> 828 bytes .../L1_Sleigh_ride_128x64/frame_28.png | Bin 0 -> 585 bytes .../L1_Sleigh_ride_128x64/frame_29.png | Bin 0 -> 431 bytes .../L1_Sleigh_ride_128x64/frame_3.png | Bin 0 -> 812 bytes .../L1_Sleigh_ride_128x64/frame_30.png | Bin 0 -> 281 bytes .../L1_Sleigh_ride_128x64/frame_31.png | Bin 0 -> 270 bytes .../L1_Sleigh_ride_128x64/frame_32.png | Bin 0 -> 236 bytes .../L1_Sleigh_ride_128x64/frame_33.png | Bin 0 -> 485 bytes .../L1_Sleigh_ride_128x64/frame_34.png | Bin 0 -> 771 bytes .../L1_Sleigh_ride_128x64/frame_35.png | Bin 0 -> 887 bytes .../L1_Sleigh_ride_128x64/frame_36.png | Bin 0 -> 809 bytes .../L1_Sleigh_ride_128x64/frame_4.png | Bin 0 -> 890 bytes .../L1_Sleigh_ride_128x64/frame_5.png | Bin 0 -> 819 bytes .../L1_Sleigh_ride_128x64/frame_6.png | Bin 0 -> 799 bytes .../L1_Sleigh_ride_128x64/frame_7.png | Bin 0 -> 817 bytes .../L1_Sleigh_ride_128x64/frame_8.png | Bin 0 -> 875 bytes .../L1_Sleigh_ride_128x64/frame_9.png | Bin 0 -> 823 bytes .../external/L1_Sleigh_ride_128x64/meta.txt | 23 ++++++++++++++++++ assets/dolphin/external/manifest.txt | 20 ++++++++++++--- 53 files changed, 63 insertions(+), 3 deletions(-) create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_11.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_2.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_4.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_5.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_6.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_8.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/frame_9.png create mode 100755 assets/dolphin/external/L1_Happy_holidays_128x64/meta.txt create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_0.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_1.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_11.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_12.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_13.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_17.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_18.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_19.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_2.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_20.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_21.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_22.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_24.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_25.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_26.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_29.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_30.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_33.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_36.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png create mode 100755 assets/dolphin/external/L1_Sleigh_ride_128x64/meta.txt diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png new file mode 100755 index 0000000000000000000000000000000000000000..f1207ed14b35cd01eafa00342f2801d74b46c622 GIT binary patch literal 858 zcmV-g1Eu_lP)b3G}_zPLJOisK}_wXw<>5vl)fnyEcmLJ)0YM`-qsd9LG<*g zg3uHHfWB#8LN=zM6$A}^iEZj_uEAVvNj6Dq_mbTmAFd!cFTa@&W`4{t&64fs z1O6+|kM;zum_y0;LR;%E{4|RT5jh|65*n~`w!6HK#2L%5CukdP2q1}?sRvZR12EsS zP6BKKYE)f>e;Pi(R|nZq8>DGO9+1VXzqs;Y z>zzX{C5FwW0Jpr#S{j^JpU8;?=-uOueU6(!BS9RndoqvP1aOo&p}tH{j*$Y>F2CbY zJTRxpb}`rb=#NmV8-pBq^GnU*vUM}Lrs&3DVX2NWQRPbV9Eu_gHSp)RdG_xa2L$n& zAzo{&Ly7kt@}aaYyloeLFiehuLtK&CfvZv9i~0aRdxU@_`$?=4uDcSHyHB@B=3sjv z1Yp-C*-y?RIqd_Gb4_y*`NdA5GkU`(19o4%V_h1`c<^#Zb!*T(J_a>H!@b?Pw{we% z1dHI&$2X)22_qD0fIX;@)4QwO+?wU}hx4OTV?~Yn&m|Y9uV0s?!lVme6X@3g$i9tJ zAw<+xNi6@`UU{o9>1u#x3Q(N{@}pCiFtmK`&hbpo$P?pJF1bH9`LkVT#6U2cFbE**&wk(4~aXcues_UO>rxTx;jl=<04a40ce_veR#+-lBGlmLLRKtj8 k04biGE0u;J2K9h{0X->d_eOezlK=n!07*qoM6N<$g2W|{hX4Qo literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png new file mode 100755 index 0000000000000000000000000000000000000000..9d9012281f0193620bc458455f6a93538fad2e96 GIT binary patch literal 855 zcmV-d1E~CoP);NOWB)|bSkT1aRXRBA7yY|TxF{FSfXu8*lUk&&qCXhO8F)FkoA>H2*0;2g2fv& z(d#Xs;?yt-?E~*0`D{sLX^yAU0@$ekWb2zI3N8X{Fs83orr0sQ#X|guwcpNP1=Z{G zSdat3yA1rXr`2nki#Nt*x!NSyKj4u+UwHlRdp$A`_S7#~2^ znalc2P!kjpqG|x})i68iBGTxNe8ACYahNl>a$BAkJMa8EWISSW9x^|7!7He$DqzaK zHH~UJtLg*3q0pI4GT^O->aCwBq?&T_iw|3e_BWDe59<_EmFTb&R`!3M<{$oTix6M< z>)gGM21gU)@>GCLe`>uG{-^#CUE~ZdT5WwA&`g90koSOKH57+|(uvFv@ zu5jrw5_rGj>oQ@wX!V1Y;}RF$?qIcGbR!}y4R^HsbN*(0SXHAg%c)Z)Sl#Bty=5=L zsgMqRmyS4iNFy-1b&V$Edv0=qawEuV>%O>0>(QCF8Rm}903b;}$!G~1tcE58ti4NG z#Li1EDY$>yq#tK|B{A92+mN-R_2;-oJ?~InHFlt@zLj6-(yP6H#HwvaCccFQEMv5L zf=vPm?`HFc&NPYoHp(3VcND9qw+G8F!`Z&vP|e+|N$-{9)>3?5mJ2g}w){{ph6J4J z%MI1syar5eO=xJuFUo-&*Dz1D2A`uKvLp&GC&Xeh15D$Dcrr0Le)4jNZU3t?tW+aRjFfo7> hF5f7XLU{2m{sTJ-XIlu4y4L^z002ovPDHLkV1fh!ld%8* literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png new file mode 100755 index 0000000000000000000000000000000000000000..cb8f173b0bdd8ae661a0e3c000fa88fe256b3a30 GIT binary patch literal 872 zcmV-u1DE`XP)?*-2wV(L$SR8{9F5vK7gWF*K9z%sdYhFTTrr?}P9A_;@_Xs~B$& zdb=C`2i$J}PvkF<5Lip!C9yJmJk zyD)1^<~b8;r*9}UQQZePJA_5QLN`m13s@3OkFb+2eNEr3q|e{3Do1W(`LOHQ*{Ccc zB5$Q4jUTjXj@h}Yt9&X@PQ4@to~kt#+CNgxBxB&i*V>Ql>6XdOn;M1U`%k`JdYzb# zxvXjd@yA2gSI!^4_f;b4ZVha>V{2(}QKcwlYoN5(9sVe;;QMGaV0UFMDS=xLDQI_k zl`c30L1j1u&AC6(zViz%&P+gL(A6Pd>t%<3qVh2Bofy|h5cY3#mMO5li|Y^PWBb5vv#*6Jr_FPc<~!% zzI?osA0I4#%i;aLLUqKAW@~uXa`(Ts#~MgIadhi(T6M8oL-0000;RtW zYC;GgHWEVi?&N>ACW2t*m9`GWO9_C1mL9w88*tuE7R2n%(<4e*f~ghW9``l2w{(Idzmy zutB!vuh7(q6FumKEzuwW3j>H)yTC$Q)<$cl-5z|y-D(1|M{-+S4~zn(Om^kCIMPHS9NRn-wo zb-G{73WfIdhPR*xoUE3%!LeNDq5+&-b6)u9wbmmCRLA3PDHsgjUH*FU4P5pLwkgFV zmxg|AeEVE-xl4Bs3UJRKUC+WFO%Y=k1n4^CS3kxxCIG~RLNWKb&+NDt@uDzso1(=) ziO{b`1j1wkskuLG`gr?8T!vo%MDt|Wxs$H6RMRzvDm|*B)6Vsz{HJQVCiK<`7I%66 zpD+s`5q~AZZ&Y`vK%F#^#?`Zh(igxfh#;bQczHYO!l%F7Qcd2Iw2#!O6k`4kFx=;dmqLL2aI=r`kQ=1B2Is`ynS&V z<-m2T+}iw1!W-ao64<|YDyCoJj>kKX`oA%;cSfI$NThnHV{pp1@th#<3}a7jmBu`P zDqsa5kKKJg0*?!;XMmeM@@8qw(-6&dL7+AUbPP_-V{~{se>K-hd3t2Z!}?=`PrJ;# zQnh39NRQzpt(~lq3*y4nYpOBlET<#Dr92W2XR56aRW)_yVsXJ!W4uiuWfyz#sBd~p naeM(t04ZO&R;l#2#RBjz<}zf`VzpON00000NkvXXu0mjf*Yuj_ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png new file mode 100755 index 0000000000000000000000000000000000000000..5d4c7e7c55fb7012fa223c9084bfe754c5b50e4f GIT binary patch literal 853 zcmV-b1FHOqP)24#t z)$%{!Q45Ty-Up3=wft=c7FG4Oco@|*;BzJ3rR*z7I#_C0{0L^xB_+HdKGwmDt*hX6 zDH20Ibn!pi0Fyv8^LjZu2{ML(&ZIO+ZL(v#u~+Zi{QU%ZB`c)=A=;6(xnT!)w=IGt z=rYN(4d4fF8i~Na_14g#ID(kx5x^!L#~NS7XoQad>-6bk!-Etiv{*>*vHHuoDNw!k z6Bgu&=ryXNZat%G8DUk&U%K4Vh#e5;u5{tcO?gnuU;Vpo0uJJxMn=zn8dOzP6(9`7 zEDrjmYFK79AIVDKNJDk`d#Z&N9J_G3ad7`tJ->0As;ZJa<+8$t^j++69Ulc2wFZz}~l6 z2i~c<%n15&MiH}mc>V#t(I9v-Q%ybCJHJ&K+pAM;f5?b#dvfM$7{k&>F~d5MxP|iG zuzq5)*a~gZ@(lPVvHC{youmzh+FR<={yxpxF6ZCPB+GWTdbU|UpW2_RHsYTJ;tjyJJ$FNDVQx?~LS0I5z~ f@9uVx0t);KGZb(kKhPw)00000NkvXXu0mjfXi1u-?7W>nA=QF^N=Sn#Tt)k_1K?$nA#5M6H- z3SIFJs3+S?$SlbLxQwjlT}@4XMa_vL+g&bDiVrlO%h|I11tkAJR*h4?o`ocsAzjOk`v+05A z6S0AbLLD1$CbL%`nE^E%K>+(g<*^MDqF^JyR=fZHhu$#kT7e)w$r|myavG?9auyq; zKYZndksi}ZIGTPdw6*@?p1uO!w znz&u}0w4q@tEFA=Y*Y2x6`WjihCh3K<3L|C-CkX!q^iUR3udD4T<)wc*+BBe^$%O` z9DO;pT($(b6I9nTb45d9FA<=3UoiGLeh!Tk@xblL1OCRq3Fd|R3OxmeO3e8Dibr{1 zUeld&q4m*kk=8c%bL`D8HBUyJ+v!b3H;0AgI@Uyu>*@0-ig2hwxUj=>f6jU!NYIQ3 zT4Nn5ydO}Eq;>UexAYxw0t`u2rUq`rdtV~p$Dq)4{V=Ihabs3ZrTcVC0t^1*bx8)pZ36wySQ=&?|`G43`_qCmSb|uFJ9h)-AGPdfGG$gIuCG%s+c7RI1Xef zDMOT|0C&IEz1}^e&Fwi(K3p7`9xLnjeV5W}Gq-NZa%s{B7{ln-2ISGra}oGVt&uw6 z&4cn*Y0_7N<_b`o1d1cmKVj+UrGHN4dS0F!pY|#IzQs2U8)eLn$s>IRC)sFNgSj9c zT%A{qnQ&zVJj&x{G*jL9R6CvI^js_+_-a}HHpK^%`VRKOQ-O7;6vtCo$t)n{i}RJr dAS9px@GqP{Wg0BXhk5`2002ovPDHLkV1gwEk39eY literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png new file mode 100755 index 0000000000000000000000000000000000000000..3a47dfc170224127ad04528accd7b47104c33ae9 GIT binary patch literal 852 zcmV-a1FQUrP)`u%7fF~_5srm=#DzMRcpHmH0U6ukyH3_+-tnN~JbCOQv8kQi2h4Vg#S0unXINGxg zZkHmf(E0H4f3_jULp=X_eme(@K&?>6D75yyarmQomH8?DIxB$n{l}YMtfCMgz$WARRBeK`i7Xb9N38#N{wk>6 zn8t$ai(jKW?KTqz)31beoqg$Au^EG>5F@0_K|5OoAV!jm2e98^DtSPu+D-&p6T7j? z22=T#GHT)qf}e{4E{@RF0Fg$IkAQ;u*%3|?$ZdIC>Ad>eun9>hhRF2Pg|Muus(`6R z)->i?xoVVmxigvOz>5vlTi;O5G~@UuZ#56>ZKQucT&Aq5_(KI(+xu}=dbnaMkX%?k zbML*uvD5@?3a}MTY;@e$8so!6fS&!)_@_xFgSiv|g03v0gM*XQC7OLe7Yx9Bg*ybo z<=>Gw{DDXpaM`TYH+n_1%^eCrrGy!?Ak{p{GzI z8~!pIEf6A&*y#3kR-v@#Cda7$LP?wVC3xSi3@2 z!A?tGJB8q9N&6|Bbg2;*OYx3%VpovwG3?>ipJCRCq5JN3X{KARhKwUBo|D-PFjKokHKSty^2^5?rk6=KdDEDqO$ zlE(C=O?Adb3-7cQG}Eo^pfh<6C=Srv}f|5b-c_7Lq9ky$8NSLWtCuN(*43ja_;nGG^5I8Gz^?q6nP)ZGpk{ZHis=6xRwwiRTHA8TKI}=fhUKOwbyp*p) z2p|>-q51KR|71-Kg38;iIutJ<0D2>80Fl&>=|L8@mlf0m2&d@4?5vamXlM>`E$uM& zLKMOdA7KG!y!qBs72u{$B7pt6@44MDK-D!^V87mRI{WLlLppT;;t_9C|0|_TN*h>^ zj^N5re|xwI8NVphb@q+h3wV$~8SxX!(74qyUqIrNE$9sE#={~=qPFP+W1vSt9(&E1 z0@w#M;|jvVascq_~JyI!tV!l;9SsuG>egr&l+Zp2-t5D{M= zxWD<`Yin~kj-C+Uz#rRbhI1ica{}Z${oyYtVl@D9A=jSz95#dEluuTe-J(51Z@~=S z7ayPQ^NX4scV{*~`TbBe`9Qia-9u8(wg>LXe{9TRN|XGS=5{@Zg<_dt<(Sv&+FJ*o ziN0^Nat=6q6b)+J;3_!3{A4WGN_o||LH+#NqgtL0dO9am(d!IKB4BSt_PHey6Isf7y-< z!wfa!9l9>;)g)X8pEG;~IUur8_8G`M#z14}0c@3I_-9^=i5){Fe2nIfdcshi9*ImQ~PmS^Z0g~t#yK>Pt#X=O#0ChmR iZ!Pxq^*{`ifqwzxpI*j|*hYB(00007mXC8pbK{fp*z8BBm>suB`z94 zFfN2z#O6;ZBKV8g7q#_QCCN@qXeOGrX(7q8#^xpS-n%X)ZoHd&?}2j;hXd^?#CwPA zZOi|FM=da>x(?a|HqzI5V_8*ymmEel_W3|*?omo@k`A{uEM5S!qfr}P5)T`~@!}eU zdlYFxI&$ehTOSiaaP7tRABvyQ0Q#b~$wP^DsbasocXJFd1{r#UZe(Mj5kjgVg2g{! zqNg^2ZK_BB-fyps9Bu~itIHvPje7exFE?RqvK{*YgMaUzt9`2BE?9`~vG&X8RZ#K) z7UV#1mhwdS08C|FSktM~pXWCN$lx48!Zft9CIB81XRJb3h^a7vAc@-4!PamLsmo(G z7;ooH(D5G)LNpx!ygxvW^j~~s^Wd{{%hC2_%Bo6qC>J(LcU4;-n|et6 z;lSJ~e$e#y#ZU2?PPWj?9s!L5~f{i={^$pKjX?pAQF9f0f{TU#lQ!M$*KdX4t-O&vGdPrS(ARtsZ%Cc+2!QQ{=VDb z$ZDTt^&CF36BRUR(S*Xj8=PdQQ7miHV(rM{c2K0j(_N#gNlTJmk~39ouyWD33IS_J z7XP|CXfrx*)k97CSv|YB^_+)F=h8LRI45=q`3b{5Jz4>f1FM)q(809%5-`|T2Vru@ zGKlX3frLxo*sC6#jq*=|cLuA^-vNb@?tE>=D{0cXn5jm8+S&5?R=a$R3xT(~^R*eT zpaBK_K|^ER?D>|0W*YN^<82^co0-IDeXEol(ku3ud+BR(w;t!C()#IT&PhZT>YIlj zV>2mDWvKY@{dLud2K0bP1Opc!9uJ{(@LR+Or^Zxv0OniRg=d^G^)Q+QXo8flT(4F` chyfh@3(5jmrgn0s#I%4<)Bp&osQ-~KgQQ%<@;Hi6Q z(k904#d!5(@qoOhMQKuPI7tL$L1LF^*jJ?G0dL=USP~QG@}2o6Gv9n?23nDej}kdT z%m0YSEikG2H%!)m?dFG!uBqxWM%Pu7wAs|rc~xB&@LEke)|w&YfSVIhi(VG60lZkK zLkJ)i38DG%)&FEo4TAZ%TXiUYLICte)Bqx>AJBu`+PbTtCO|kw2WESz9KfOG5zo>N zW6wt+Z1WKo$c;DOdU_tXrjrO@zvz3m5eBGw1`F)eJ08pa^3{+|?SlBkTh#wbsglwL z7NjG1bEv;P+<=TL33aW!apM*~Bv3_MLKP0Lx6BujIAs$$!@BXY2$HC6I$#WRKPX@? z=B5C40L^%U@TeL9Tz-aQyl;>-6FDHG4=Ro}JPG;MZ=V12InxGY0+11nx>Z$m^oHv9 zJ!00#x3=d1ACr6Z*?8-)XLd*YpYD=NHRbi`cN$$Ut<8r~2SrsSI*|#>#fGlOU8Wcj zUm3W!@y)9%vw8NP5@6SjZ8yW&5U_ax3Y~8Fb4pkZKs?B|r;dlspfu&k3YAUTGxQeC z;5~6Tx=$}?a?qXG_~f^Ts>ucEK6eL6ecK**NB^;2!IUTYHO)7Ch=o#>VCjI@>e^ce z$3)+kI)4&4u^$a;e8_u{`}qgpV!5CiA5uTPvR5nM=;@qLjSnR`MUv~wN8Fz_&NpST ztE3)r-lspDs^Lj;ii`tWV>=jR&xu_{?u0VL{y86*m5xnJE=-M|y$MLj$k!`-mlsi< zTxzKPaa_VxaGVFo0};g;Ab(sd-V^((KVFjIE7|@zXYq53SpZotj{5+^U>rC(`QTCw zd}g-JFvE8P_T8lqRy2G?Q;j+67zeWbbBh=q+%0OVSLKD#IiJk$J6tQSJ7w5Lq&0n+ zT-->gq=I;GdqFj#3?=X+f`LyVo(`eVbsO=(S7ZEtfFwG=E}eCzRE(k-pbkj)^@YB^ d9*BV|@Gpq#TX#gkE++s0002ovPDHLkV1lDnjsE}u literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png new file mode 100755 index 0000000000000000000000000000000000000000..da3a78f4c7d2364f251efcf0d311cfeadf3693ab GIT binary patch literal 860 zcmV-i1Ec(jP)HGw^KWKzD1O2?a4gD9ViVO(ALi=Ao3~!3nM+a`evB?;V{tr$^<9Ht z@Ozx-`5N$}TShE+x8EB(Sg}yy2m+X>`*`iE3Tp8XV3Q$zVtka;2@D3}hg5HzodeaM zuV6r)vTsm07j7o>+()SD%qy4MY8GPL03l%(8fhil9EnrbU|)z+i~uB2(+ps1v~_mb zU^43xhMmAih-NLo^Z-r$6p@vVC;(iIW>)CMlbf<#Y`*@W-|d2p} z`R|OgGP|3p27rY^b0W!r7i;O6Uw)vFYRd8R@6`71T~K%Z4h2;uI^c%mdrNwLec366 z#9s{jc5kkyehI4U0&E4N8_n>0h2Q;HfR25^&}VTGcrHNzuRRTD68cmrOE9xWI~;@g zRa*h!!Xw1`zY<8^2~%tI?Zu-K7rhR99V&Q&Uq>%2}c?`l}k+I{g3Ek&naV}M(`v%`QS-6Vs37`vu}7BFU+ zw1_z;d5(bhha}y&C&I*$mHU1m6Kn? z6o#RHp1Ib6S_zl4d*i*e8be^Bwr9Z`#3bzima(q3{<4?X#IMh*M(>-2!l_2~{L;4& z!N*-~{betw7I$4WbWE^ts-d8%#zHc2259RqPvK~3t8?OkUX;Tl>$Z m(G*Yzq;TDI@s{A_#w=kO&avP_}B;zHLpOl zBas;Lp^N{;2ABlG>9-nlBtgb7(4I6xQk!hsPVA5OZ~bv>g;d?_qHs8 zCFn58i#6aoZwd*)zy03OfjESiml41wZAWWg#%PF-0BiK>lf#1)##t<+_gVSn>=jVG z{sR`|nea`@qtRMM#}dMdj=y@fsTM+t=MXX`pxCl2s58CN>+<(53EMTR1?@1s!UhNz zA0T1yGfqsHXe9d1ERt5*nnQEm^aDj_SFZivmu{xz3DwlI96M&h#chtg~lh@tevO^(pN5SMgwUHpS{$p^2~#jlQbK(aQno=$AI7%fJCweu7e?5MO* zfPHAQHoOzFnGy80j3Q>`;M^m8qe1X&rkZ-Ndv3Edwp*{X{2?Q{<;lBW!5EfaifPse zC7K5Zz}oT2V$<2A=>_n6u=;lW{iFqkTAQj<{vOR*uI87flO;P-K3Q)(pW^Z8`A<00 z+EktLOB!;xepw@9-OS0lf);uk82K1zs!okzwEJFuxzGuDX<*9X{k6sy6*H-vkc1-A z4-Y&=ZNpqEPzm7r4b_BUlYaz4c_8Y}RcoQDmkiA$5`a@kJquYuQ+46qht*5 j04Y!0=|GNY91Bxel{hfU)#i;bjeXFf0r)cg|m z+s-(^7BF=7szJD24*=ER!!^!mfoCz4qOTO&dXl>^D)ywH&zYgxW*M#RUNTZ zr~AaLQfyyu=r(kNlhx8TIFjpJ)Q^*E&T}8W*1G?Y>Udn1qQUU(#jh9Nz-7N^o35DT z!r-rsZ=OjmcIw`J0^IUPH?!~uQ^MFq0Xh%+!yn-p69D2uv6TD#!|b>h@q#e1M#-YT zi_jmA2!zQ7QgeUW_VEscxD3AjvF6E;b0b}CsiqqYR=ZV4r=9tv@`q}=A@tM<7Wa7e z?=TA>5q~wpZw&8Jg*s^>jmvKpyS^|s#~^};=EKW7Q72{kDlOIIJxO~>ohqL9R~WaS zZiU>X=tpQTfTX=xKIz$j{av76>=oq4FoWFzCqO2oyoPZ?PlCeq8MbyKj(@ehbAG|7 zcWB1v7=iJOBZEdWHjA-aY7b&xlmQc{Dndu)E{2@XnsnFVNDlS}PQBY`^8LX}% znuTQJqM~4B#zm-92_+Bf zi2p4g0OtWXwe8q|fXG%h&?xNYu0n&b4sL z^QO4X%7Pd6w}FAu%DJt*<9W?LZ}sJzDy)43;DZ5hUZWUqm44ih4)g{eVM}X9JCviI{E9d-bNa6iy*vm1^Sk%H{e(E@vBc# z-aP=|TlA@2q#79;JlIL1;H0w(ER>@j&yA3SNAp3&T#H2>$DO}UvOsY1@;7Fh)u(4; zt7iZxPyTM3-}yp`+0emQD`kSyQQMw0=@Wb0>0bbdoVK6z&aSpu)4j*~fWh82J(ahs zk^ZhEfYWDrc$Q;hgYH!iU><9-BSbx#yM_UN8nQ>e1vk4G9Zmr(R&7rJ9b9?yXnzv? z9;|Z+f{l5Tx$42x*?ZPK)0H*h3u1W~-EK=+bL4|;=wAanQcUf8|2Udo2oy+Cdv8L! zW>BpbXhV_;PA=Cmfr9i4`d*SM(!HKE(xp(jyCf-y=RThl2`wDk>F<@KOZp)req5=I zt7oqy&E?_}H9tt7zmbrnS|wGI<6b=68QGTva1ZnsG5TzOwD^4e+eWX)-a-qNT3C{T yjOM;xOQ2ei-mUtO+R?u!EKPKl0XTtM6#oJKCt7uy9%sA&0000O9aKtjFBFS<5rrbC%}m9M zUgRQo7XRX1b*D;^N?Ky=V?0!jd8EhM#x;n(iGKn8%i01^Q66Wj%mffr}U0-1Ob zAb^oTl>oMustNt26ldfm(WIn8cS^nw*cymV$9HzJdP{oZX z0DX}26@XXvB7mt|#QDeoiB>l%gnMp9<1RSsACR#L4*RrA4QTF}P@O3{P!=X&k|;Kw z{GG>YUjb)6wR^FoRzzG(K&R@4c1B+{Ck6u80E)uu#8e?{x_(D|nn3F|y%Owv`RPM< z0svYxdV1{gIr|r%6wR|rG z_Ipb9%K2T_WLJOdjU!Ia9LO0bFr9z*qjY7Kfbu;WBwM0Eytoa zv${bA+da&=CaBL3UV&D9ecr}20W+2Rq}Z_9H}LJJs7bb1)9v4MC!20Be7t`SouEjX zTsClwx2-l*f?XqA@%P8snc^`e*gjXTY;jv*Dp1Iz~P7fSP6>B%@=;M*NoN z&=$~kJR8Xvu~Q%XbJo)dAR^srD5aiZ-)UR74#8G8#=Rxu>vO8x(`%goMkdxKM;_5P zZ5{Tx07J%srCf@u9_7-oIH4>{e&LkJ13AL?UJoUdiY%}6iF|KsmFfb)$i%E)32)oT z?B9E2TqG~)Q3Yqo~o zxmYX{aZx*b>OB*Z?-*%R3J$iGAKipVIPm_Zv=l_ja&*?#pgOGkGbAD6?ryXZk;1r$ zgpSDY)KMFee7R0UWLTsi-{lZl4&zc)SuWa$RAgPDvy}TEA-!}aN+5?L00000NkvXX Hu0mjfdXb+( literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png new file mode 100755 index 0000000000000000000000000000000000000000..5459ae27c3e0b2d87cd3a2b68996ceda57cd6f41 GIT binary patch literal 788 zcmV+v1MB>WP)EtRqp8xfd%lOk=O*D>zE{8R{hs%EA5QbX z69Qmufyo`u1_Y$GvzL2?9p9?;NLR-=tK3H!AMk?h0wr)JIMuBH8gL~tfxn}}F~9Hl z<$3d+?Z7x3h(1Z$TV(8#I-a(CS;x3zBfP(Wy?+u2f9ZjcsCemK z<&Wal6rHP)KJnQ2Yvtay%j@gj8B=M*sn}#EX+NR&Um>=qX!_pf8Yg>hEzIEY$uM!~ zuUHdl*=yJLoQZl3Qs7L?KGb=y3kHxh*8cX{mbzm{kTmB!c5`-UTn&J< zi;4=Jp|JJtQ2@uGxF8J={k*IYuw2(H9Nf*1CmUz4QUwRhM%rSr=%v%@1-VHpG zX>Y!S*k6sK>@W1)wyDj22^axEz0^)k#2Eth(ON0dDZdreV{iwM$xVfJ3=R;nmUjlM zkIP-KkC1@=DueNqUDFnguRnB%j=2~?_}!KM4^rcK@M}knfZv+b-#PpJX`*(@2BJ)} zaNeHDRUsAFK-0he>Q9Cj2YSXfuX=A1S-C3gx@!a32OlmiuH_RBGzvD5ICz5x0uoat z{>dS!r6pY}w)Cs(4!d3ZqOY|2)f=COOUEq0l(VRO$UN>m{f%P*rjW;&`K2T7Tmw8Z6lW$uEFf_3*{&fP*BdvUl3oztSDYF#=e*{#<6Y z@2PT-f}$j~78AujRW#=~%x_4F-kx6gRJYs_*EOv~0=S@wNBws2I@rmXS`A)kr86X- z{0xjPjE+M4?q1+r4UAUOdqB_spqcWYb+E}M%Vo@AOo3b#kW`T*X<5;T>;4B1IZ1|x S#su9y zXzB&EP@D+}ih{(@X_M%bTA~QHMVd@Y+lgp0)1+x;&YU^F4|6efz3jcey;y7gKP>j} zzX$+u{sV*8eH#$awvz2^UTou3wn^%BjQ2M!)KLP8Whk`@B*5FwGi6BBK^~5Vrc%Bx z!!zfWgB5Ly#h+_Mtr*Q?Q|*O~S36pyZ&YD)F=)-@3=BUtO)xW*`MN8{(m6=&19!`NGz28WWYy2D z+1q#;8#7%4>R+{grs+~ag<|;qeU-2dT)UpNLrnkp%Qp?vkksdoM7O&2zCB2q^rAsE zNbCd5P9!bNM#nGd%QDb@1W7?6sy8)N0=&nOq>e}!Nh$?S`fDTL)RSjdZ#ZYc!?#qd zxhr<#Lh17CddFkQqNHjmoZb7Atjo}DRGw6jONIUf+tP50#f}GqIZXdUSuX>36-<}@nO@B3Kfof;!_8)rw+(TC;ykfz3 z+Zs!+ik#i9-MjZss&8!74os3!|1P@JqO^C)hRgXd3V3~VaW*aQ(dK( zBVB#P?3!PZr114b5K-1ir#FsS0MmVwb-Aa;(!pa$k_xATeam5Q`irBg?^UPoj(3>X zyvk%>=v;R5m{&()cOXqk3LlW9 u3nR;Mq(w=3Ly{^F&W|AlYDO5H8~Yc`rGxxvN7noR0000kltwRJ zHqlzsn8JD1t4U*p9c#2VF|pAm3NBb#Y=vFe5@y-ic^+mVzRUaPd*A#M}wUV0b+eehAL4h6(YK+)S~90XEeon$0@jRSee z1**;&2U2LCpW?xeSzJ_+`+MV|XB|L)n`aCBzmD9N9DuHZ(CO(LZ-gH-r2tr3l^L;t zh=jz-8J6!X#34GaY(O_2UWzjVn5E+Yni{+@Dhu{LyZNn9T?(s@Y97h_%fF3;*|l64 z4QBKGnSYn#VJt@ClE2XvRIamHipXqg_Ee4_ZP<)L#To26V6Da&ME`Geo*HOF!ECLr_vT<^KPyZ&y? zf)c1S`fIsY%e9pgb_i6X!JW^z8JU}?A3#?OD*E0FdvVCq0_AEJVIuEarTvP0NgR%&>G&UbFoz$}i=uVA#~b z@Jo4rqi^uVLmy*$I?%p8W;R6omrW~_o$vgsqp~|Tvx_aeVN(MJ(5tCT&tl7lb->bL z&s5C(Vk+OL&9>t;O9{dBF{%qaEO$IV zv>!x*Ga}WfB&%{VxnU`R>F;g-aq}-PM6T`+1B%6<^tj6iUP-m5bf9+=RR4pYg2rr{ zr37mC`h49p*P9mG&Y}c37`tV9rq~y6ndm7OrU1`WT}F2X?v_Q$YsH{bq_CcF994-# zsQJ&G+jo{N?>y+n71xansHHc-xMG2>;u-iTC;$NOo|M2iWDSBIL?2C`f~p6notk`0000R1tyh>M^I#_qv{QP$XrggLvOd7m!M?9MzFFYo`y^Z8emhj(nv z&MH@wAp>JwRUy-zK)tsfn@+-UZl|( zT7umoary&@;Oto&cW3Bxp*q?DA-WPrA>Hx(-0YX#T9+ErYr6N+8=_3c0}@aG`layq zN0$!)qX#{0U+lCF<*WJUhC+sxnbha4L=+=ZR}5>LR2JCsG3^VgcA{F1 zl`I{k9ksc1ZQRVK zs9{9@mEvq55&=BuE5Rz;SH`(93Ah+Q>i_(-uGBK1U6f$$-P@7 z(E61dDTey6mx6n*{JdiTU@i-Y$m03`yu#^%@1Mr^mB8YP>BfrpKk}dvmX*M-&%Chl z^X>1_z%FK#(CW1d&HkQIfJ|&a3Ab}S3uDRBV(L7#cer#4ps%S;ym8{*ajG1z0Yr|u z{Xpp)Y_$i+0q*3CF-`)`7eyD~@B#Cz2I%*C_Lm^JS}}PwK;(S(miZxq>)*I$GhQa# zoxo!sB6A1#DPd~L8DH6BTi&P74SqA!tz1T%l3RUw>0QI)JDF~1od#ln~EgM8``UT%NteSRUuc||C zBnU9%Ym+e8N}%_NW1xh^KT1|xb;RS-5DZ*8Rsxg*uV%r(BToac4{`w@QomVk$$b$K cTk!q=0mCXct2Z>fF#rGn07*qoM6N<$g2`}%OaK4? literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png new file mode 100755 index 0000000000000000000000000000000000000000..a5d6c1a7a59b8116e393bfade90b5891981070b4 GIT binary patch literal 813 zcmV+|1JeA7P)1v7b7Rs(o7gnOg*DS66-E$$HkCr=ieeTj1et54L@9!bl#=W!D4i)HB3-mD zBK|A}E3_q3jZ`XySZ7>F0;NuAp%t~swa`vAaemsAnaSKauZzi~iDz@Z?>R3o@Aq*S z=YJ;zz_|-X*F75$(7BfFY8CFvt!#@leT=`rD(Wo(#p+rE5BxZLniW6*8EdNR6~6g% zU6f*RCS2RQZ?Wy0b&8$SvTJiO;lI}MFaX>rG!-oiw{H~M8ml10#-{6slXoSKdF6}U zzj|z0Wy%){3Wx>Gtr(Y0qc}Bo9ARYw*+gAcqm|aUnEQ9r;m&Er6R9{RyRj9f&4}QK ztYe+X#{l%Xz{2$p7vpS50&I2w9r`r-`sFNud7MylDk&`m0A0t8yl*#Mc-|xO$9I6g zOe|Mc?Dup=A>d3-ncTx&#%>q^(%`dfZg;_ro*&JK{&~PT!5#NrtgZLNIfm#<)8&E* zFAn(aFOoeu0sTg(_Rd%F);6L>F!u6u#~{8~orUv8Fm>_F7J$%2U%G&0>g%ntfW-- zec$&Vk}J=g8cHOS-9Et0s%s*2!V{5TuLt1}uGy0fVQ`ky0sQvnlH2_0r6`XaLVs`e z9athzww-R@e{A1pB}yHO`%?`mq5hGW?z`%Al-tgfY^~QLeQIyIH=w4criPVln^##{ z8ajX-yn47^O?;G>jZPlTh*-XmYuriYYEnwSB*aYZ)|G?ji}N<2Ym-sQ+3|VzCzWvm z<1sM&XaM&8L{W{63FTzBrKg3Yq8j_8+tS3Y{qxj%ic;ePrNV@+ovg&j-+C{jM#a8u rQ>r~%IE&P{qDHY?HF?>=f6x90pDlLgl6o*(00000NkvXXu0mjf1J{uq literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png new file mode 100755 index 0000000000000000000000000000000000000000..57b2c9bbee26fbc31ea9e384d8ca8c44936db89f GIT binary patch literal 879 zcmV-#1CacQP)~9or#-tqXwE=trZzs6*sn#Qc^H<9#z~Z znvGTpHdzRj*EHGvpJk|zVmyz3{er~ zRJ4A-qSzE22f*LtK!6Znr32yxpa5V8kOUDc9n>+g7yva{Xara*@Sg)>UsD<0H9F4%#7+c6@3i;;3lqVlFP?gN7EtTWC;%2# z#Rt^ml^V7kc?m2Jsjg(W_|fU|hYloy3n=+GP3T~(?GFi-licd6WZ5MW!Uk-bp0CnH zdV;G!!aw|$6jWZssSq8i``+Ff`{ua=Pdyq(|Kd!Z+7C|A0as;{qC>(E#(S*jb* zz%}pic+asr#b5aDQ=TphvIIU13}^V}&P1 z7AI2-Uz|81a{PEhru0d^T$|K(b8`s#qVomo%#_-Z(oa63UFf(JZk5-&^^##mem^L( zQkLlI9`QY+yJ@_a<)q6fgQ!Q1hAV%kJr^Dbe-7`Zln}2uGrz_1J!{)7|137+9bI#E zCp@g!Y1DQ{b8Xl6lSN-SjJjF%k+ErRSGv>zbOO`Mn$Eh=J2wY_`qSCMt47NYttvkR zpdL=MC505m65=&TyGYK@|CmHX65<^qCsLH7w@vUlBc2OY&dz#+Nb$0G;`s@YvCL6} z$U?t(;>nmuPA()h6rTVf4oyT-h~#c1JSmHa_=&s8e*u(ie_+i17}Nj&002ovPDHLk FV1imcqT>Jn literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png new file mode 100755 index 0000000000000000000000000000000000000000..4be832c648910992ec977cd567913fc99db14545 GIT binary patch literal 855 zcmV-d1E~CoP)KUdworlw-BFPg1P$sm6{!i*7qQZo8dHS0D;13N z$%nr9vh_vEth9X*1EygLLIXh(icMPr*-6mG{t20q(4A~%=lHOj&8na9}5Wptd<+DbzR3cxt*Ewh4m34o@}VAfhVy@PsMiN2QcLsHlbZ=iN@H^J-wY%Wz~Wu%moQnV?E zl&<|PvNT)+NkmHdy&`3)&FwM(`N?Hs)&)@e2xVUUoXm*_(C8r9Wtr}g<)JKd+m=go)IkZXy)*G?=PZEl_9=ml8wVe`O|AGu6;sJtb0sn3 zXD+({W}vAs*>m!ZR}VcC)`OK3@o2q4QWn6DvXY99$wCKH9)OqDB;-05bL=?}a6g5J zoDs=M=s1q!WE>5ca3Jk{Zb5kKsFLcrV3e8m_9+kUWYCB;27VWN&La=c3~G!tUWc2d z$>vVxHyepoh6`1ZoFx0QlC(8y)c2!})K!XaUMePSME>aSm3*uuk44sOTM5x87pvc! zgYB|EAD9>x3mDb(;WpHey}MZCMl|x#w|}jaqMR%`U5;ZMlw(ppg{Lf1z59wq9nZh^ z*74}6(^f0-y`z8>UYaXZzYtj!xnSEivQ(%JRL@Bv%*mqTIGQ#KpD$%{AWf~ULk_;(y4AEptLo<`ScaMvi$)DcMJ@lu9EEl#Kq`+yXr&IxC;l5FY?FvWz zxh=}_@^8V`xBid=!`l>x#>H&S#Wm-2#X|w`_fknwvCws=AQEnX0FxYFA8RG8|$;q6XG%r=c zSh^nM%kI`Ly9DYGnU(x~U!>GGVZmPJIuh?c$pEM(ME;TFoG+3E*zGC7D6=b#Ju?b8 zXh3q$f8Li0HCPTxFy^m=?SKysXi&jayj!K^n|jMBZ*FwqCPN5yJ}7~{caIKLwUIgI zQ34}VV-1@-1Pmj;K>M@8!?NPh>g<~?5a=>^_UZoWMv@upqFVwhC+@vd3$PdiL}YE^ zUpH|p;d!_4JSDKUV=}+v^Q$i8GifF8;LwrA8^)Qxgn+#_u-)cCD&`4+d7Q(9e}YfUK>b?o8c{&#~h1?Em)xqyb(Ibn|#eaqF=P7ftn__;9!x;sMT`- z>J#Un?;|s3`X$^euZYZh3D48)nY7`I%0ax<_tDf3jzV1+K-KG)K?!TWri^9OC70_N z(D3|n3Q#tjjDd#YTLAPx+y_K*^ZlW$i-?$n=e+=t8zr75sa7BfZXZXg8NeK5LsQ!P!!h0x$q9-Z^pKELh6!9z9p95xv#B_CqZ&{nIMI zj`RjmE?4}-CoxyOig9>&u(XuqnK9NkPzYV6zGK^i3acPu zp+)?B{7}3KVixL3k%|63wxj`C9Wd`lu6u`n^8w6m0_ls7!(GxGK;yVk(!cV=KW`EL z{UYF2NKEN={nW0k0>JUUG*g{TH`^22feg4*%-u$(VX5J3)2mzU&ga~-O%!OJALksR zB}1bT_nL#zozVmM-5#_V5i}JeeH+*4vfx}Ys~4c}uhJ#BVnq0NOwYFgfkmh7$sv|w zMo-5RzB8OwXe;F?$X^`vU|S|ESSdY_{-CbSP5Oj~#=o*#(>)?2lF0zwum5UFqc0am zE*1{I8)KQU@{&=w^2@-i)7%3iKKfK=02nL}U7#U15`T3N!0EI4^QVs3 z?o+h505>pejJ&DsllyfL;PQ3WLZ!6wtkmUsp0~GX&6c?&W*AP7L9h>_%KXGT#YgfZ z$G(NDZ(B=r;KTHL)2s3N3|eY+EoK0iySabsIj-(J*^QK2NEQ7(Qd@6A5Bz~tUdR@e zmwd zO=w(I7>1v7@43m%Pdnq!XvEY+Ce^{zI;~I}qs$a4wzv{|W6%gOq!B?hJ4LH=t)SvU zLZL3S+5`%XorN2PqQ;q(;zAwh!XFwk{Yg8f+L?6H%)QCX{aoBh?YBAbocBDOZ}Bq8 z#@OLe2f(-ij8OoBCQu+Z?xJC081MjeQziKg=}rLj(3K|#+@>d50m@#anMnd^jENBd z(y$MhhFlN{U+_kl_~hA}yyT%={!zS}{;Vgsd*DO800ZZU^j28o*FPpUTV` z+p?e<=X;h5X}i=>ZT$O;3kFeeeQ)*omd<*AHk;Lo!Y##eY|F_`-hK|yYTr-A$u7M< zG{not0JXdnKiB0)%b{6Lonlo^R4Q*R z1cP((gY$&tXp{B`nXL=k>Xo7sykP5=sRw~M^PbJScD#@6X)dNf-Ct{cwPZVhLHkx0 z>PBi(>;CN5S&j8)6i`z|lJicnR|)yO^}4QmAMM%hPyT(U5(?J`>)Nx7cgywkJBJae zo=MfDCaKyNv8Nl35*mN3C+v&eg@oNdoB$DdXh%8dmg>43NL_a{FzqMDE~MuIwkN)E z5Rq!7NaiZ0@xpmBC(vNX1= zNV`=hEsPys#*@zakEsOspa6_lxRos51<*!}LiPTXXO&<0MwoGb=;KSfO_gLWeeVTt zZ%dGg#fl3vYfCN>05mLaPNlLRR8ewkSbL|{LL<))Zudw;3lINOLC4&7sJZ)zqe~f? zEhl0i%cJkFisbrBAckyC&t^r|r8GBbV63}G9Ij6}0O}b7BRetY@Ko|LK$VFEnU%X+ zlJDyVFioV8srzb6?uZWk z`sZl*J$|J+N`YWAqW3kbfs+m48*L*15l=S^zPt9QR!0s$URnwL*@=z^yCXLvq-p$%Z*QysNn4?nzjye9?zUuU)P znq>vWJ1R5g!t{5h4u1iv@)JL_JcQi;Fs)U>vO-&m)P%`&>zIk;z6m4{nUq*}r^HNT zVg)WSa zJB>!GF_F9>tW+9W?b{e9F%c4DB_Wh2tx{T$!VJ!x`sN)MGt#-6d(W41zVCitjvDWJ z)k(8?^m}&uI_OR0=*`vNH!B6r>Oa4_9U~M(@&K4N@UO^Bo33?@h}i$TlK_8=kl(1<4*5_WLJlW{%hR8cAHq-F0tCAlWY!ftXQZrk%tLa767O)Eux&PC|SJHNv)xg;&YW>F+0s!@}Zo>SK zUP@=D0k#&9oOP;=r+1&o0~8A6&Tptle|$wEK>NNa^*e7lcZP?a2Y9xOs%}%)dvD*j zFes~g^eHgioPS6iJo2rFu&WG8IQwXl>A?YlVZW7aKM+3i0u;)C64nwI4m-^=&)u+< z7I4$a&lwqk$h1aQB#iDJ=$;SsL=lwm^?`HaYRmfptnCIR%a{7njh^IeDj**9F>Ihr z%_}`P1`NNLS8`?QoxLAD9v=RIb>a=zu*3WCcu3%V0^nLD)}5)mnO@?92imD?ybAL$ zG7fC58xqAK)PVJ73qY7MDE7cgv*eV4>wO0D-@tlpf8rD{@tP89%bDoUL(9D$M5jlU z&|I26X{`Hm2p2Obfx+aAYu!6z$l7Pz?1Zr{Ivp=Nw(5;}?LqsCG zZ|XCVK>L2yH-Ph)`s-yl*yL`xtOWQ)XX`!4K+(F86On3l@ra0gENqMkozM9HtZM>Pv%4_IT4XK?fbq_sS;#70QGtql&oyq-dfnH;!*_+I}^ns nfJ)I<216I^jeL^CZ$d11@;kWVw|A_%ItK^W7EB z2jgA3l%Z1jQH?Ge_7uDKzug6#rBm-o<-5Lk-#Z@2?=%7|twr@NBbLC+Rx;hHQD*uD ze|wjxIr5P{yUD$wxhVH7j_J5H_964YtMPjLiaJwT z*7BuKEV*h6#E=>zi_P3y?IG+yQY_t^y_0KI>_uwCYQaJfxd3JyX~TrEbGqdNY&(PI zHcxB)u-+U4@Sd}*?3>sOyv>c01;^{LKq~gcuB(@i0nZmVjOOF_r#PQU=w`oDVBM1X z=@2{|9YO3UvdxHdhkkPtE88iLo`pUm_FWh|A75&BJ7mGF`jx(cLiX>*MYv?a)nvbI z9xW1D^s&+PT5o@l)EAku^Lkz*Mr${E_f)g95^L}I(p_Si#fUT zpLd~H1V&H%ZWJDP$8A2gP)boH+IZHsesm_51t4+468n4!v$y`G4FQ7@t6n*@&D}15 zQ?T&I7+}8k0sg{>@<7Y&!lSBjCxNLXhV6eXKv@8UepLL-izjJl_~_k)&GfiYsYKKjefYg<<;ilyvRvkXk?o z(^{5-Ti!w&T+AqtqDP9;YVGErOHUs2a_KuCX-<-)Dd}3NoLUANfIZOAa`EHXP`8`Pm&ZK4P(h<0c%ii$YU%_p4?zWA_o8@|Yp zf>ie)v-71k0U3(S(Mq!y6%{KunKE4OgKf~dCT+UqCb_xChopF3J~-cx!^h#{Bu$yI z=CtRUgALhN00=iY5D*0-`4;g!-~%`do859zHX z01xIuqcI@iHwpXUb5v9+jdv zfJ667{=}xp!B#6++WM!CtT!AOYZ(`}Zylub_fsBpfI)A1k#eo$-iGpQ0c#n)Cyd2L zW*Qyg)pki2z8TeR*CkvSkZL!irJK_#WwR*t ztyFJUs{V$nYMYDXXH+i+^NkaGHT!AS0^?9B^lsYx;B4 z%D?)F(^6{XS%nQ3DY)j-F3qn@N&Q(Q?K@PsE|n`I(pRnnOxC;qfmq~c!rLyA%4^~A zjFg&D_?v5iSkyd{fbqaH6Rrb9hT1;+19k&5%MQQ?wmS)37oOSqTGFP0`}-D;fq5WL zXO8d6QV=B0N-BhvAF@;fNka)qs_N}UmoSr(zE4R~nE8Ay>zL#?>`4QdG6Qa~idZU6uP07*qoM6N<$g5|EIEdT%j literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png new file mode 100755 index 0000000000000000000000000000000000000000..639834612c846903283f6ed6628f2c79c3fd6a1e GIT binary patch literal 852 zcmV-a1FQUrP)1v7=A^kbt&`HmrW%{6C=M}V3a-o|chR6ILKaRZph%VYN2(T;23%w=byKKd zK^HE>R7EJ0`cp*v12MOv(9&vybP;K2rms`?;8z^xJ(e?|IKT&-o4q z@B1c3g{)W9{bqnFuJ?MtHb&?TwN`-~Tpm1}h}In@`<0F(W5C#|5=)dO83VeSkwxA^ z0AiW}<|UY-O=<})WOKnap1A5&g#sq)@+CKCYL0#A??S}?XT0X{;fJXei5lZOM^By& z#Y^51^Z{EI@fD`7jJ$QLB!Sc}0{W@27@up!0|YR7%L7EYCF|A}SfnTUVqx=`zaA>b z{**6f)TH{{s<zCKn4VKM5y(OT z;I6!Z;83FYU-Ksy0iGE(QJ5U4l$I;y69#k!)pWjThm*S3onjO+pl$~Hv8-?{oD?9zJ?wvK{&E&bT;3D@~|Gk$L#P#-@&bh7VEWB6))9A3Gw6c&P(Z4Y0$ z6`co^HEq9~JYdTGU=3h2j(UB;%HAGd4||~EL*8^-_}q9Fm~R0U&!mEFpYCbz^nK#~ zJVqTw-97??gFx@|eM(L}Ev!8>eJLa)E<1)DAuyJ>asvPgl;H2N*4UK+fZ6Q^n$H2YDFZOPUkOWv{imJCxyJ>2qF)J> z$+fg|qwQh=CetW^F8y!lf!t+j>Fbe}3?gF7 zGV-~Iuk-niyb_?h;drT?;@vF2gc9Hn-LaZPI=#pN5s}5kYp#fl$ZwepA|lqde=s64 zlkdn^Gw8WqxYrh~e3 zL!wPgT(s%}oi=XVV72Mnn3h<@1W^)!4j@#mcBUP$@6pFQE?x^$@8yn@(@;@U~vu zl%z^!OIHK1$LMHl>~L-zE6H!jWk!7SMVMqa0=TghsMH|gY&$-vd+~{g3zMNL4XPR$ zSoLA&-D_G{sultYmE={7<$=NGPqy>)NrH7Now(ffW^24*jRLcmx6_x_2TGyUl|6K@ zVU$7(XD4yABcFh6&e%#VY>GyHaOs2EtM~lC&3^`MLYv#!;AHFb@B<;4nrMZ`~U>1I` ze7g(Z?fYeXoXDb&t^e@-l)kRb9W3}xv834O_1w$uY%V|o{a#5ksPu1 z$ovi$!1>%_=76cxnF_#ljF|2v$^`!&1vqoXLR+as6t#K)e*_k~vH+>qT!?xw;?A#+ zMK-eESKz{{)(9Ry7ug`Qauogfl4pU>+|w3XJud8iZy%ECXIE8~a{UEuxrC%>xf(wx z`A)gKa|%h?lRr_BmZh6LMI>p?H#I5lE`K^L3X8Ri+H#o%@!mnerWs~S<`tEcDn%Pjfu`Kw6H8mQar4y6RQOj#={92Rru`E jl;u7;lYj0beNp@eu20-ipVE6~Uf(?YKCPa%s!3ChnPn!ZgKpNQZ z0|#=Ra)E8K8KD^jI`URfrBJvs4Lm*JSHnEY!*2u6Hf%KZ%y)&qfdgY3&7ZMrPg=08 zq)-BIYqc=uK&SXgO*1yACa|ooO*Opaw^D?$U?xb$2V~AgHo^YTswC@5#0mRg;;bHZ z3FY5+0tsLJx+hr>(+Nid5K29C?!Iv<*S8_6RIaRC+Ou%tvagGQ2(9UseRnTU0}wY@ z^Lm|fW3k-{K-pNk#Co%5YzI)gjb_;+UGmy;WrZgFz1tz%8sSAt>xS+?ku1Rh1i{)6k?NHteb%0MqdDo_0wVf z`n=X!xvPt>{TZ&CXH!%5N*t6l|6YF}v7A`FQ*yi`8I+u8`f|42>8jkSS`_U=%5&Qz z-#lT@e7M&e!K;OpnCmyXRW)$)vvqfN(g(a0wM#DQUEQ6{A|g_~UTP)-KeX5?XDMO0d1lUP{Bp(GzWlHIs((L zt8l}X3p25r+G6!ud_LN&O{7kr+LAGlNV3Tny1V}DG(ZFjKtD=X*ZLx0bgQ}T;nYTl zh=lKFTD(n7E2W%sB4Fn_J13V)$I3Y6wX3v9H{k8w)@c=;W#}?(|1^S2w>W2rTw+{c-BToST=D=u-gmks;^vVo6_VwQX?N4{byAa!t7k%0PfPv$S+D+;X?zot z!aGEs^rz=s;O3gq-t%u>_zd;Hd!s-(Z&beX%uB7%zpV&d*@n!?xPBJKNk`G`n@B%QTE8I-EEN`PPPN8WjZck^Ke6Q^JaxEG%3 z_-PoOa^Y4F+Hu>8FIbC=iCjM>$+c)KUbNOKsb)<4#~ztYHMi!6KuJuByML8S`(`;F zfD&ASiw8?8(aep45-!qHow`RSn&qcK300GcYfU;b$R3aX0WNV?X=dOLZ2$lO07*qo IM6N<$f@c1SEdT%j literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png new file mode 100755 index 0000000000000000000000000000000000000000..962349bfdec5503429689825577af262921ac6c3 GIT binary patch literal 828 zcmV-C1H=4@P);MYf0)t1eLxntVNLyloX+DW?F4xn>Lx4kC|lVz2hP?>BPG^=lt&B&;Nhe z$Nydh0DT7xZunLpKw~}YuQjGxC8&`#9c5=&N6iIbu2e6O2D^vhwGJQ;rz2I`xM9`h z4OZsney!Bc=1tm9ZrFI?M~Uiv@ueNAX(#}uX4f`q5^7~o&di2&DB5-Eug~SqtX1DP z_x?f9>aIt8y%2v0r+v736~o;DEi^xOh-v}}MRKyT9$ND;fSLNc>P3gEkVkZT&0JYT zM56wYHIUNPsBVi}1ts_tc>iJmpgIjuT269gUOB)ft8$JgKlS47!h_?0g`9*kG0=KK zDuDJpm2)Cp87qz(e6XN$&Y7-CY44@1+-%XKU?6$C>!-d;eF*pXpmNUCzFW^uFOL#* zdw|Lnw*J5;@+}xLYJiw^qRKm&Htcw_)b33 zUNqEb3X6BW3)_NBrX2OtSTd4OJrK_;W?Lp)P+=G^$00KuI7fbI-c;0)xY~v9)6S5* zXSZ8bRxvLAY@zUQF?w^c$I(=<;fF$we>%ki@tEa4`EDLf|WcomHtkl$Pt=2S9cG-e) z5_8wBH44S%G)78~Q10~6%8j{+4DxU($qj3*IpoZ5j|~@^Ui)`TxV0C|wSjr>!qu-y zZkvx?IS1WaHM2&Rw-*#8yCq(l6|wakAriAN@4v~-jJ0000C6`P9 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png new file mode 100755 index 0000000000000000000000000000000000000000..2eb4456cc780a288fda6b71ff3ca99b931c51b2d GIT binary patch literal 585 zcmV-P0=E5$P)>Nh!OB=PyYTx622!q|kdqdsU?O6C zY`-77ka~b3JP3L3LgIs!0Zd;Hk+vjd7p0MO?%AFTaRBBC085+0@+}?!{nZ#{lBAI| zk}kVDr6OOCFON@Iau4&u`Bx3c7{kY_)lM4#Ej_Q+6-Yh8Z=k>B*GUKAX*Ese$ICP0 z8L+!^i5ZYC-uYR90EnFzb<-`4*OguP)Ht&3V|Fb%C>5PO>Cx+2p|}NS-`J?gV=)ir zz70x62H<0TQ-CQh41ETce^co0FIr!Wq z)xD}&RR9ok+5ix`BC#9JkkfQycE+FiSLaaE>t?%f+t<`R>!|U-2%8EfD`o&RA>zGy z-TmLTSAiX{>=J&-=7C$F==OWd64&-!+h`ToJoNh)^6=0kLjn7IB#T*5XBMEG*2HBJ~;}B+3L_Rues8tiw8w|~g@?NH`D5Z=;plA# Z{Rey_OQicOEv5hf002ovPDHLkV1i=g!{7h_ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png new file mode 100755 index 0000000000000000000000000000000000000000..e5772a672f9a63d511a03cd14cba48df73df3662 GIT binary patch literal 812 zcmV+{1JnG8P)Nkl)On1-IBH1q<;PWKD5!)^K#Gm-NXO<@41Ze zzwiNY{sXUWyEY)8t(lEB61#OO-ymB$!zBLg?gY45Y!*ns=rxXRW&kDlp=4^?JLamh z+pLsx{?psQ;nd2H&9$@0>|@QooFtWY03Qs1^AczMhH1c3pIA$Wnni;CTdm=A6HvBD zGSA)yb9kU=Vo_p8H@9Leot2K0zwqQFTQ5l6j6QXzX0%lrC%R+u;nrjJ>a~VMdA&GS z4(?H~2|`92GnJ8N11I`10J~7|-FPYNg|#{NK?{Ww{z7T#*F1oE#NjSICp*rq_k97d za|n?Nb}N4A-5~(?5K6>r4=ISt2ORHP%UI$1<@7syMgR_H)=m8Lea!rPr*}v=q>$rkwl*0<*&ZC zU?yImHA4m%OwQOyZvL-(F;7H0sSqT)ZQ<>F^-XwX41l(z{m9Jo9PDVVMF`%KQW{s)bzRqu$o?Gz2qm&E!1bC94yDt;WaxMT`~j@f z9R;OVIa7k-8>=Q5U;fO!(|0web&Z8)^pVL4F?q0000P43(XaExcZC)XO5g_}>Ap4BQE&%nc>iptZDLR|u?6uJVm%UC@+kLF@2I$vP@~#&R zxZV{tB$?U`%t5S1;qJ5m9kDuJM}JpjA48EIcNKk+9(EOFv?MK_o~iwzsEP7#?DW_H f$=?+J;Lm^?$5Vh#T320I00000NkvXXu0mjfxI%Y8 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png new file mode 100755 index 0000000000000000000000000000000000000000..ec47b899c994843115098e2b481d4be9e3545bd9 GIT binary patch literal 270 zcmV+p0rCEcP)g#Y&IE8RMH&I=ZT-N9#$G7Z;2?CV z!MD6x1bD!iYcNdCSF^9tY4hauHh`CC?40-Z-=cvn*3{YeK2>8 ze+2U>lk@GCfAh=B#t>UH24K-BvC9r%eZAQz=j37B8kTNI77Uy6BwY4=Pwc+n50F}o UZhAxmRsaA107*qoM6N<$g4SGi=l}o! literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png new file mode 100755 index 0000000000000000000000000000000000000000..3f345b563e9eeed887691ea64fd476c58e9eade1 GIT binary patch literal 236 zcmVukXtLRdY<7&Yil?6l5smS!)4=ixyV{H|i zEVZ~qQTSxJvPvwAS+^ZYlHpRc4b{SFksE~%lY85BfJbk@bKKYrf4%(Tbt~+$){Jx@>H0 z9v!U*E>kPOV&QLk{US7P`x)X2@FjRl)L3A-;}s^}z6-}5I>m6R*COBYii7&ERd`uB zg+3&W`T8Obyggs*z8c*$1-S7%TAE9JE`yu<`gW@2bNRjVnA)?Z&*lEIf=!Xm246;w!wPWp`HmW)LcC6j8v((m0$X#-)(gTGH^FsQna8H2~_{aHwIgSCq bjE?>S{e=)!nb_>V00000NkvXXu0mjfi(20( literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png new file mode 100755 index 0000000000000000000000000000000000000000..44c4d0d498b2ebfd6caf104f011430dfe5b1d362 GIT binary patch literal 771 zcmV+e1N{7nP)-)V`@Jcg?b! z8h15C(1l>d;+xnmB8bn0s0B?%Nll~j^76-I($3t^#mqxoUG9(XoO|xacaS8dU}7Ul zvH+yz0pJ4=0SEvKI~0J8h$~QMwbUk6iDv-FZCWX+W})l<4*=N!%mPs`Nk=`_H&U(RQN03dn~zOR4?0F^bcZ+3Jd|f@+2ZE!M+C?0$2hh zw{b3pwgYGh$>~DExEw%JKEP9k2~3drd00M~y~*R%-#{v~l9@dz#;0AHy!)E}^O+Rx z94I<&WVukn2$BWI?n_UP21jE!C^3x zDZI1qZ-3U!AASDMd$7RXZN&e z0fPM>xds;872w$+fB2Cr%~H`{g2wRTyVJ=QSO^(AJ6nsq`o(wFD^F{B%*=)68BWF} zXvTF8XWqhPlMHg|MfEYgan$}7+&OQ0>r%*vAZ@7aw5@LMqSO@9nv+wm?Y$}K6O~oM zi|WC5xD2E}p3qgPtJartKM85w>$fDS`}vAa$%oo~qjz(2j6=ZJSTHBHSJMXE^+B4= zU?IC%uSc~Qb0kp_Bdvd-<4w&=Yi?5=q~4jgms(nr_H|mausIPt6w!cMd<>9Q)~-r& zZE1c*ve0jw1WX8%DOgyo1(dtlNXk_={mO$H@Gr*&ZJJBPG>ZTL002ovPDHLkV1id3 BYq9_U literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png new file mode 100755 index 0000000000000000000000000000000000000000..f70ecb3abe0a34f98debe1b004eb08b12c98673b GIT binary patch literal 887 zcmV--1Bm>IP)I|X#-uh;n6?-_SZ&e{l2{{$MlW29fAFB}G}ef6 z^We24CdMpP8)HLjLOaozka(ay2$(iyAm9RpvIS%ZcJ_NcEbH}`=Y5{{AKi!E42k#v zphU=jbn`Zm>HmS%9n|H~b!8xcSy~v6Rp-lqj970})rLVV1{%PFlE?{~Lcju=gp(qd z*%bni;C>+|5^&gTdAuyV+9n|%4%uZeCHnQFxLmLD%HZub4lT)5>VmBj+N=Ys2_K~^ zV1&lW)zNY+0M!g#3me@gLq(%!W}f@y-)j(p62OXcD-EhLnzo)IU-P&fxLXyWwT&xb z|HtPlrdaioIrn2=-l|Ag9$u{a^!EC)Ppq60V{voLo_a4%xm$}zC)9i+&-Yb4NaVNu zT}A86)|x5aNgZC!$fT(ViYpi2T@%Uml)-}(Hzy{iL<&;QO|N1JE$x+v{x@M(!=v#?_jqm~nttmr=t z7iljxDh0nY&TkKQ|yw=xuTui4JdN{KB-Euw&K_M zu{BbrM#JrEfIY|m{;WB-CK-FYS(nvM?GAtt1i*TU3t>YvU|1~Pc4N&XpYNDWq}(Rp z%1DKNpNATlm3g=#xh%PX6<18Wv~9zwZ|N?vGQrSH_Q|xNkpJuzI{_f%wM-vl7TrJv3XRa0I{>wWXqt=#1!scW6rfAj(5QHzka zQyVTW<<9`DcMJh@nWN{PdHpKD^JPY&Lac7bwMEwITfBfU#P$ zpzZ?at5EsKk!a|~d!n)&`)d%L`FKEdSYMII!X7zGr3=u>>pS#Q)ytacEojC;7Z+o- zf~u--d0yT_qhcE=ol>1wU2q&x&iL;z`(Ogy;s!}joq9G5+oR*Er}dKKpt^WLd)oE1 z>NPL#d7`Mhy!(hh-O5rh2nM8MqRZx9h;M!aL}7YtJLn0QcYQGMO@3zpl7-zF5M|-c ndusK)F7<&Z%d5Xbx48TZM|mrzzUzGF00000NkvXXu0mjf3B8d` literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png new file mode 100755 index 0000000000000000000000000000000000000000..7d970234f57cdecc7e45bf765ed313ad92c3161b GIT binary patch literal 890 zcmV-=1BLvFP)6U8pcMp@S4V4`@4ocyo`72k70Lo9~?a<@?V4 z7-HkNVF>`RHUVn@0J9D#kj-8!oah5e0M0sEsTMByP~%y4 zifHE_S9;&`9T#56Ak&f!I@>Q6lLt#!o~PvQmWV0$Q@q{!jiW({!Iqm>)!xxJ?AFuZ zU`dwo>wNprw)yQDKtzs+Bql2VEZ#_Xp67&V7#vKE*?+fZ!Vmso8&H_w08_NvAH?=jCdf)!o1&-%i|OKByIox zqfF}OBHD?>C(oWM%kkR4&uP=|I_j5b%BsXW8h&_k_ouieho*b(@fTn6Bc%mb16K9q z*3XMWKdF`T9i{?#J9BX{Js+F+dx0w|yy5+vx-q!{q<+4=$2V`|kdXo3F66A36uoXB} z6B%s-2h^jkvB2)S^h~NLg^1+yYf==Mu3qsHo)V~txG|rV+P@lK2N5wJ)=f>1h#6iy z<#|>LREs*&0;(mlE0f{!s>rQ;P#O`*uOvKAm2H~}_jk`hrE~}|BS|sCby*QHA9$YU zsQ3v~3!Q-4l>sFSHQSiqlS7WB^FM<_LnNJkFb*ot#_xYEA|jF(lkmKM0Xq7HHc@&K QWdHyG07*qoM6N<$g4?&KI{*Lx literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png new file mode 100755 index 0000000000000000000000000000000000000000..70eab1f3e8c945560bd8aac429f4ae7e15401456 GIT binary patch literal 819 zcmV-31I+x1P) zUuYav6vlt|=B93H!FAKbeW-EU1Z_*GEfkSfldZI*f?}ae8v4g9A}AVcAQbvgb_ad1 z_+L=a2Qj|sjFwP*$U~(g*ir=9^q~+?$RMFRB|@f9lG)Ad93N&k+xu|ge4Ou`?|%0j zHPQd_kqn)qmV5r}K8jA-fW8>+@Sz(>OpOMw#lnx|~>+7u6}GfM*!KBRqQW$9C?c4A!&7q&C) zZR#>l`I#;9n;`}zfIja1F(kDxeFzxcYip8?Y`a8Eaw+*|eJ)F*YtkW27#2cQ3fD9xxO7i8G3U60x|3hHSFj?51%w@g*Fe6W3Pen(-lWthqH zIKkiFo>@#YdUcaWUK;ygeb245ZyzF3y)D)2H^w|bSsEA$o9Abri#(vmLPTOE(QB~) zSe5~l5WL-02egF&)bGsRKK>VQ(gpckWJY9Pc_ctPj$;TQ18@D9pQ6_VgMkYJ99z_qrZHz^_5-O!*)p0$SA@8>``u9&5i?P zA|=hi@vU}}3!lBz`j-#=wU1y@SuW7CZiv^m0KM@Q0KcH*jeYOjEG9ac0J!&rVWd>M zTm-QI%2S3C^+SMqw+Qi_2_+D0d{@?S)rZC17$6rG63sIoBP%l{B_LDHuT0c^g~i>i z$@@l4X0l=b;Z?7{h=@pS`7uw#(~h&(K}4h;O*1O@MIKm|5nrOJfLwFl+f(jocm#${{bV`LSb#O+VcPa002ovPDHLkV1lqyd=>xz literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png new file mode 100755 index 0000000000000000000000000000000000000000..8169e0766fd617850ef249e6919e2c7715e8cd9e GIT binary patch literal 799 zcmV+)1K|9LP)@2%14c(S3tq0sqQ7jEH5Dt=*W+!+tAtp8Hr$`!T0+9nA>H+_Nu>*%{ z!r3O^VVig%GbQn&7sQSz>BdX-(8LRNqlAUFbXQ8s>@Yj8hn=OZ-{pJr``+()pXX(q z|D6y3V*`wCc~&4mdNX^kU6}DLUYoRZlwRfq%GQCJzgfTnJ;GS40;s@jr2P7p4z2EO z`BkgUH8%sL>5Hx;%?&bmOPV#=@MWC5ermDatP_F);K8ay`L*yx0CU$U5dPW*AyM(x z^U`0%jVUtakvX+@=#1S?TU}kPT~eh=ycLt~QG(ax)Axz(Ni^|%eTCC)w+3qW$n?oI2)|Li?GX$SGl8*dSc?ud<`f8{IV6KN8%j`Qq+U;K{fgcF08uYQ&u>V>*Dtc2!ZX}?$gX!6H# zq9Cn==(qf}v5Vg(raVadCdiQojiEb=w{x+vg#B^nIU=LSh3(Hwpb#Cg{#fZvXs8rS zpx-R8%_ni*;!%$Q97uyP7Vy2+OWFi7VFxK|`I`@}h6^VQKwSwCd!Kq$AG)axK=pN@ z)ZD^x=k{?|2~f>$uM}>t@@GFFBGOowS((iZ7bT}nfaD|=o_p+uo70GhNU3w8F8_)= z)mjO_!)u>sms1C9KaF7lba$l=XVnG0*L9g&6OrikiTN+(Z)d=9R3ni9re$PLJ@C(h znY`?I@Kz&}CAt4AP%?e+AOz1kfhiA^Jk0C_dGjZ^Z2waRlkTK#qmH2p^tdhSB@q#k dszd{h^B;3hM?PLq!U_NY002ovPDHLkV1lI=dW!%6 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png new file mode 100755 index 0000000000000000000000000000000000000000..adee1a63dac8b87d57862f233107c1f961f39cac GIT binary patch literal 817 zcmV-11J3-3P)RhGNuC&1^3lbT18NI;gl(OH8CIa|J4-6 z(9S=ILoqD~ih^##tZOy%4^>3nkhO7aYed^*?YbskzI=}tNn_`GbI$pl!}Gk)3x{3& zuL1y^|G>Z{*9HW%EN2fcZERyzc8Sz=jQclD6e|J6GL)JEDR8&*NEuRfkcY2BQz>8a z!ZoKBgJrhG;k3$Z5YIixT?A2j=N`iCBxBp4$A1Hidih4IN`Gk{$) z08G7~Xn=q)d8oQ~xAB^ZOz%*CwyJlUMANgg7yseme0?g$(l$VCe`M3^GyRY*IssWhRbTRzmwo2GAv1_?vkjcY8eA*Zql6w4+_~uC6_XZ@5yYZkJ zq@DvzFOud8@ndK8K^bWM5J^EQt`{{?0^IwMq*yeJrsaW?`NRnL@qv@8)}6B8;#(@# z+?ZG~S2|Z%>$ogflvd5d*|{gpnqgXv%Hs-hUg(dpH3L^!?6F`Vhv~a3>kdP=Q7sal z+%a0YJGrx*gI|q6zmGkh+uTcF(E%j+XHF=YZ_SK!XFi^>K()=g_RFq6cF{f@p10sT zky|(I&Ck1peII>hq4v@}eWf8H!?1Pm7bD8w_(u0hj%`@qWPBZb26TCpn%6&SC_-{V4gwZyxYn-U8Fd&v>xl0)?^# zuHM(>!OCF>?!W@(WZ7Za!0EEuiE^`mY8|g zU7rO>QutJQ;uW3FbW3%h_uie0s&d|)QeA^W<+}BGZFnta8^B+T0{cf3+mI$Cg?CEQ v>5;|Tk>(}o1xc!GnLUCOXsN>Z%vb*cYgu*d%gmGW00000NkvXXu0mjfmz0(k literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png new file mode 100755 index 0000000000000000000000000000000000000000..db6e667fb77d119f4150c6a1ec875be023846c19 GIT binary patch literal 875 zcmV-x1C;!UP)~KgG zR}iEKYkd&s5>XHzgbo{2);@?U76v}7jm|c0SDM(WxlQlAUmue0ynNw%zURyLoI^kL zGTAy>AJ&1*viblBH+3K&3PcJG#WBDGup1&ZI*~%d$8{V4nu?GFD0|!@zybGp`T!?U z0Vu+FXuJxL@-`K&x$fN}fO2^v@PK`OBbv*7;lLJ~Gm(Khvu{j6SulUGk@WbdCub`` z#Z=lc0L-r_Os)Cmk-CR%xAg-4&)Qm_@CkdyHb!T9$TTis^htr($(@hgP-8ijR#wVq z%mpcm4H(sWsqG$YTgG7ffWpkif6KfeWw8MZbNlgLKhph95n^DFO6A(*_O}BS*bbHr zEidX={A}`M!Uli0op_nh zy7S_t!gp1q>P8?#z*R_CPxQ`+cX9UxkHv&I6 zXB;Pcc;Wu^DaQzc_;96iITfyx{hJFr)~AcC`;s&|vYODkUY~ObGd+?@ML(r5^Yv=ZHt8XtwHhg6(hr?2qSD`z z!Y34FRMNLOi`H#fFb6PcT4~E8X;k$v3Nx#@{{d={ku%1$CRzXh002ovPDHLkV1k;- BrV{`F literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png new file mode 100755 index 0000000000000000000000000000000000000000..a6a37fe29c7f17cec2d4824961e1acfe37f0d353 GIT binary patch literal 823 zcmV-71IYY|P)de9(=SZW1EY1mdVOhDM_c6MG5vwyzZ`^%H}ee=A}$LQ95 zF=jyHg=34CF#l@Q#%R2kI}nFKWUgz1neW&VR+pM! zBwEhe<@Uy2y7&2nVtj@elmP1LJezOG3#aM=kNA}QW9}aFhB*PvWR_uB5A7lEkYhOWwzPxbk_-U#y zg(S~e8g@uwO?$n#9ByJQ zGvG#6dKXzeCxaQ8l3B+|Bi?fK&dC{e`mUQ!fzM=bPgsdwY<$iqS6e%2d0>LNqEgNQ z9~D6fzibBC`8{xD4m8{csK)>{_^E|vBliO?{{st?Q~gh3V Date: Mon, 23 Dec 2024 05:34:05 +0400 Subject: [PATCH 30/59] [FL-3940] Work around incorrect serial port handling by the OS (#4040) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: js sdk flipper detection * chore: bump ver Co-authored-by: あく --- .../system/js_app/packages/fz-sdk/package.json | 2 +- .../system/js_app/packages/fz-sdk/pnpm-lock.yaml | 13 ++++++------- .../system/js_app/packages/fz-sdk/sdk.js | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/applications/system/js_app/packages/fz-sdk/package.json b/applications/system/js_app/packages/fz-sdk/package.json index 3c2954c9c..f500fae2b 100644 --- a/applications/system/js_app/packages/fz-sdk/package.json +++ b/applications/system/js_app/packages/fz-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@flipperdevices/fz-sdk", - "version": "0.1.2", + "version": "0.1.3", "description": "Type declarations and documentation for native JS modules available on Flipper Zero", "keywords": [ "flipper", diff --git a/applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml b/applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml index 45944a854..67d3bde82 100644 --- a/applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml +++ b/applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml @@ -8,13 +8,6 @@ importers: .: dependencies: - prompts: - specifier: ^2.4.2 - version: 2.4.2 - serialport: - specifier: ^12.0.0 - version: 12.0.0 - devDependencies: esbuild: specifier: ^0.24.0 version: 0.24.0 @@ -24,6 +17,12 @@ importers: json5: specifier: ^2.2.3 version: 2.2.3 + prompts: + specifier: ^2.4.2 + version: 2.4.2 + serialport: + specifier: ^12.0.0 + version: 12.0.0 typedoc: specifier: ^0.26.10 version: 0.26.10(typescript@5.6.3) diff --git a/applications/system/js_app/packages/fz-sdk/sdk.js b/applications/system/js_app/packages/fz-sdk/sdk.js index 2eecf032d..44663203d 100644 --- a/applications/system/js_app/packages/fz-sdk/sdk.js +++ b/applications/system/js_app/packages/fz-sdk/sdk.js @@ -85,9 +85,21 @@ async function build(config) { async function upload(config) { const appFile = fs.readFileSync(config.input, "utf8"); - const flippers = (await SerialPort.list()).filter(x => x.serialNumber?.startsWith("flip_")); + const serialPorts = await SerialPort.list(); - if (!flippers) { + let flippers = serialPorts + .filter(x => x.serialNumber?.startsWith("flip_")) + .map(x => ({ path: x.path, name: x.serialNumber.replace("flip_", "") })); + + if (!flippers.length) { + // some Windows installations don't report the serial number correctly; + // filter by STM VCP VID:PID instead + flippers = serialPorts + .filter(x => x?.vendorId === "0483" && x?.productId === "5740") + .map(x => ({ path: x.path, name: x.path })); + } + + if (!flippers.length) { console.error("No Flippers found"); process.exit(1); } From 626d7ef509af0902b795ef802cd4a31b68bfa1d1 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sun, 22 Dec 2024 17:56:19 -0800 Subject: [PATCH 31/59] Fix skylander ID reading (#4038) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Read skylanders faster * Correct parsing ID from skylanders Co-authored-by: あく --- .../nfc/plugins/supported_cards/skylanders.c | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/skylanders.c b/applications/main/nfc/plugins/supported_cards/skylanders.c index 6c199f114..b5dc0ab86 100644 --- a/applications/main/nfc/plugins/supported_cards/skylanders.c +++ b/applications/main/nfc/plugins/supported_cards/skylanders.c @@ -7,13 +7,36 @@ #include #include -#define TAG "Skylanders" +#define TAG "Skylanders" +#define POLY UINT64_C(0x42f0e1eba9ea3693) +#define TOP UINT64_C(0x800000000000) +#define UID_LEN 4 +#define KEY_MASK 0xFFFFFFFFFFFF static const uint64_t skylanders_key = 0x4b0b20107ccb; static const char* nfc_resources_header = "Flipper NFC resources"; static const uint32_t nfc_resources_file_version = 1; +uint64_t crc64_like(uint64_t result, uint8_t sector) { + result ^= (uint64_t)sector << 40; + for(int i = 0; i < 8; i++) { + result = (result & TOP) ? (result << 1) ^ POLY : result << 1; + } + return result; +} + +uint64_t taghash(uint32_t uid) { + uint64_t result = 0x9AE903260CC4; + uint8_t uidBytes[UID_LEN] = {0}; + memcpy(uidBytes, &uid, UID_LEN); + + for(int i = 0; i < UID_LEN; i++) { + result = crc64_like(result, uidBytes[i]); + } + return result; +} + static bool skylanders_search_data( Storage* storage, const char* file_name, @@ -88,6 +111,12 @@ static bool skylanders_read(Nfc* nfc, NfcDevice* device) { MfClassicData* data = mf_classic_alloc(); nfc_device_copy_data(device, NfcProtocolMfClassic, data); + size_t* uid_len = 0; + const uint8_t* uid_bytes = mf_classic_get_uid(data, uid_len); + uint32_t uid = 0; + memcpy(&uid, uid_bytes, sizeof(uid)); + uint64_t hash = taghash(uid); + do { MfClassicType type = MfClassicType1k; MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); @@ -96,10 +125,18 @@ static bool skylanders_read(Nfc* nfc, NfcDevice* device) { data->type = type; MfClassicDeviceKeys keys = {}; for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { - bit_lib_num_to_bytes_be(skylanders_key, sizeof(MfClassicKey), keys.key_a[i].data); - FURI_BIT_SET(keys.key_a_mask, i); - bit_lib_num_to_bytes_be(skylanders_key, sizeof(MfClassicKey), keys.key_b[i].data); - FURI_BIT_SET(keys.key_b_mask, i); + if(i == 0) { + bit_lib_num_to_bytes_be(skylanders_key, sizeof(MfClassicKey), keys.key_a[i].data); + FURI_BIT_SET(keys.key_a_mask, i); + } else { + uint64_t sectorhash = crc64_like(hash, i); + uint64_t key = sectorhash & KEY_MASK; + uint8_t* keyBytes = (uint8_t*)&key; + memcpy(keys.key_a[i].data, keyBytes, sizeof(MfClassicKey)); + FURI_BIT_SET(keys.key_a_mask, i); + memset(keys.key_b[i].data, 0, sizeof(MfClassicKey)); + FURI_BIT_SET(keys.key_b_mask, i); + } } error = mf_classic_poller_sync_read(nfc, &keys, data); @@ -134,7 +171,7 @@ static bool skylanders_parse(const NfcDevice* device, FuriString* parsed_data) { uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6); if(key != skylanders_key) break; - const uint16_t id = (uint16_t)*data->block[1].data; + const uint16_t id = data->block[1].data[1] << 8 | data->block[1].data[0]; if(id == 0) break; Storage* storage = furi_record_open(RECORD_STORAGE); From dc73096966be9d5b7085a99a1bb6bd0a278f985f Mon Sep 17 00:00:00 2001 From: ru-asdx <39434750+ru-asdx@users.noreply.github.com> Date: Mon, 23 Dec 2024 02:05:19 +0000 Subject: [PATCH 32/59] using GITHUB_TOKEN to make API requests in scripts/get_env.py (#4033) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .github/workflows/build.yml | 1 + .github/workflows/build_compact.yml | 1 + .github/workflows/docs.yml | 1 + .github/workflows/merge_report.yml | 1 + .github/workflows/pvs_studio.yml | 1 + scripts/get_env.py | 6 +++++- 6 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bc2178ae..66a2bdf73 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,6 +12,7 @@ env: DEFAULT_TARGET: f7 FBT_TOOLCHAIN_PATH: /runner/_work FBT_GIT_SUBMODULE_SHALLOW: 1 + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: main: diff --git a/.github/workflows/build_compact.yml b/.github/workflows/build_compact.yml index f45275204..f98ab8b49 100644 --- a/.github/workflows/build_compact.yml +++ b/.github/workflows/build_compact.yml @@ -6,6 +6,7 @@ on: env: FBT_TOOLCHAIN_PATH: /runner/_work FBT_GIT_SUBMODULE_SHALLOW: 1 + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: compact: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 1fa025085..65af450cf 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -9,6 +9,7 @@ on: env: TARGETS: f7 DEFAULT_TARGET: f7 + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: check-secret: diff --git a/.github/workflows/merge_report.yml b/.github/workflows/merge_report.yml index 90302ce1a..9ee7884c8 100644 --- a/.github/workflows/merge_report.yml +++ b/.github/workflows/merge_report.yml @@ -7,6 +7,7 @@ on: env: FBT_TOOLCHAIN_PATH: /runner/_work + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: merge_report: diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index 8eb6fea48..3f1a164bc 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -11,6 +11,7 @@ env: DEFAULT_TARGET: f7 FBT_TOOLCHAIN_PATH: /runner/_work FBT_GIT_SUBMODULE_SHALLOW: 1 + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: analyse_c_cpp: diff --git a/scripts/get_env.py b/scripts/get_env.py index e8f6b3b77..6d6b3cce5 100755 --- a/scripts/get_env.py +++ b/scripts/get_env.py @@ -34,7 +34,11 @@ def get_commit_json(event): commit_url = event["pull_request"]["base"]["repo"]["commits_url"].replace( "{/sha}", f"/{event['pull_request']['head']['sha']}" ) - with urllib.request.urlopen(commit_url, context=context) as commit_file: + request = urllib.request.Request(commit_url) + if "GH_TOKEN" in os.environ: + request.add_header("Authorization", "Bearer %s" % (os.environ["GH_TOKEN"])) + + with urllib.request.urlopen(request, context=context) as commit_file: commit_json = json.loads(commit_file.read().decode("utf-8")) return commit_json From e11a62694ef9809ca845c4680d5582aa7c12446e Mon Sep 17 00:00:00 2001 From: Jan Wiesemann Date: Mon, 23 Dec 2024 03:32:53 +0100 Subject: [PATCH 33/59] Added flipper_format_write_empty_line(...) (#4029) * Added flipper_format_write_empty_line(...) * Format sources Co-authored-by: Aleksandr Kutuzov --- .../unit_tests/tests/flipper_format/flipper_format_test.c | 1 + lib/flipper_format/flipper_format.c | 5 +++++ lib/flipper_format/flipper_format.h | 8 ++++++++ targets/f18/api_symbols.csv | 3 ++- targets/f7/api_symbols.csv | 3 ++- 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/applications/debug/unit_tests/tests/flipper_format/flipper_format_test.c b/applications/debug/unit_tests/tests/flipper_format/flipper_format_test.c index 888a66444..934634c71 100644 --- a/applications/debug/unit_tests/tests/flipper_format/flipper_format_test.c +++ b/applications/debug/unit_tests/tests/flipper_format/flipper_format_test.c @@ -265,6 +265,7 @@ static bool test_write(const char* file_name) { if(!flipper_format_file_open_always(file, file_name)) break; if(!flipper_format_write_header_cstr(file, test_filetype, test_version)) break; if(!flipper_format_write_comment_cstr(file, "This is comment")) break; + if(!flipper_format_write_empty_line(file)) break; if(!flipper_format_write_string_cstr(file, test_string_key, test_string_data)) break; if(!flipper_format_write_int32(file, test_int_key, test_int_data, COUNT_OF(test_int_data))) break; diff --git a/lib/flipper_format/flipper_format.c b/lib/flipper_format/flipper_format.c index 8992247d1..d07022e12 100644 --- a/lib/flipper_format/flipper_format.c +++ b/lib/flipper_format/flipper_format.c @@ -403,6 +403,11 @@ bool flipper_format_write_comment_cstr(FlipperFormat* flipper_format, const char return flipper_format_stream_write_comment_cstr(flipper_format->stream, data); } +bool flipper_format_write_empty_line(FlipperFormat* flipper_format) { + furi_check(flipper_format); + return flipper_format_stream_write_eol(flipper_format->stream); +} + bool flipper_format_delete_key(FlipperFormat* flipper_format, const char* key) { furi_check(flipper_format); FlipperStreamWriteData write_data = { diff --git a/lib/flipper_format/flipper_format.h b/lib/flipper_format/flipper_format.h index 46f78e255..4a1bb767b 100644 --- a/lib/flipper_format/flipper_format.h +++ b/lib/flipper_format/flipper_format.h @@ -518,6 +518,14 @@ bool flipper_format_write_comment(FlipperFormat* flipper_format, FuriString* dat */ bool flipper_format_write_comment_cstr(FlipperFormat* flipper_format, const char* data); +/** Write empty line (Improves readability for human based parsing) + * + * @param flipper_format Pointer to a FlipperFormat instance + * + * @return True on success + */ +bool flipper_format_write_empty_line(FlipperFormat* flipper_format); + /** Removes the first matching key and its value. Sets the RW pointer to a * position of deleted data. * diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 23421712d..e18aee04d 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.0,, +Version,+,79.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -1054,6 +1054,7 @@ Function,+,flipper_format_update_uint32,_Bool,"FlipperFormat*, const char*, cons Function,+,flipper_format_write_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_write_comment,_Bool,"FlipperFormat*, FuriString*" Function,+,flipper_format_write_comment_cstr,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_write_empty_line,_Bool,FlipperFormat* Function,+,flipper_format_write_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" Function,+,flipper_format_write_header,_Bool,"FlipperFormat*, FuriString*, const uint32_t" Function,+,flipper_format_write_header_cstr,_Bool,"FlipperFormat*, const char*, const uint32_t" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 6f9fc5466..51404c951 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.0,, +Version,+,79.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -1164,6 +1164,7 @@ Function,+,flipper_format_update_uint32,_Bool,"FlipperFormat*, const char*, cons Function,+,flipper_format_write_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_write_comment,_Bool,"FlipperFormat*, FuriString*" Function,+,flipper_format_write_comment_cstr,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_write_empty_line,_Bool,FlipperFormat* Function,+,flipper_format_write_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" Function,+,flipper_format_write_header,_Bool,"FlipperFormat*, FuriString*, const uint32_t" Function,+,flipper_format_write_header_cstr,_Bool,"FlipperFormat*, const char*, const uint32_t" From 519b89665f6b444ccb3ac4178c89229fda0a42c2 Mon Sep 17 00:00:00 2001 From: Sanghee Park Date: Mon, 23 Dec 2024 11:55:58 +0900 Subject: [PATCH 34/59] Fix invalid path errors while deploying SDK by enforcing toolchain to use UTF-8 on initial SDK Extraction (#4036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix invalid path errors for non-Latin characters by enforcing UTF-8 (#4024) Due to cryillic alphabet on `/openocd/scripts/target/1986ве1т.cfg`, If the system codepage is handling `WideChar` for cryillic properly, It would cause jumbled characters and fail to decompress via System.IO.Compression.ZipFile without Encoding enforcement. (See https://github.com/flipperdevices/flipperzero-firmware/issues/4024#issuecomment-2545385580) * Scripts: fix line endings Co-authored-by: あく --- scripts/toolchain/windows-toolchain-download.ps1 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index 025f8341f..85a5ab724 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -16,15 +16,15 @@ $toolchain_dist_temp_path = "$download_dir\$toolchain_dist_folder" try { if (Test-Path -LiteralPath "$toolchain_target_path") { - Write-Host -NoNewline "Removing old Windows toolchain.." - Remove-Item -LiteralPath "$toolchain_target_path" -Force -Recurse - Write-Host "done!" + Write-Host -NoNewline "Removing old Windows toolchain.." + Remove-Item -LiteralPath "$toolchain_target_path" -Force -Recurse + Write-Host "done!" } if (Test-path -LiteralPath "$toolchain_target_path\..\current") { - Write-Host -NoNewline "Unlinking 'current'.." + Write-Host -NoNewline "Unlinking 'current'.." Remove-Item -LiteralPath "$toolchain_target_path\..\current" -Force - Write-Host "done!" + Write-Host "done!" } if (!(Test-Path -LiteralPath "$toolchain_zip_temp_path" -PathType Leaf)) { @@ -46,7 +46,8 @@ if (Test-Path -LiteralPath "$toolchain_dist_temp_path") { Write-Host -NoNewline "Extracting Windows toolchain.." # This is faster than Expand-Archive Add-Type -Assembly "System.IO.Compression.Filesystem" -[System.IO.Compression.ZipFile]::ExtractToDirectory("$toolchain_zip_temp_path", "$download_dir") +Add-Type -Assembly "System.Text.Encoding" +[System.IO.Compression.ZipFile]::ExtractToDirectory("$toolchain_zip_temp_path", "$download_dir", [System.Text.Encoding]::UTF8) # Expand-Archive -LiteralPath "$toolchain_zip_temp_path" -DestinationPath "$download_dir" Write-Host -NoNewline "moving.." From 38326877eab18cb3c4150df51c32afe5ed459f0b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 23 Dec 2024 19:19:12 +0300 Subject: [PATCH 35/59] add input events sub check [ci skip] --- applications/services/desktop/desktop.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 9366d6508..abe7d69bc 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -214,8 +214,10 @@ static void desktop_stop_auto_lock_timer(Desktop* desktop) { static void desktop_auto_lock_arm(Desktop* desktop) { if(desktop->settings.auto_lock_delay_ms) { - desktop->input_events_subscription = furi_pubsub_subscribe( - desktop->input_events_pubsub, desktop_input_event_callback, desktop); + if(!desktop->input_events_subscription) { + desktop->input_events_subscription = furi_pubsub_subscribe( + desktop->input_events_pubsub, desktop_input_event_callback, desktop); + } desktop_start_auto_lock_timer(desktop); } } @@ -246,8 +248,10 @@ static void desktop_stop_auto_poweroff_timer(Desktop* desktop) { static void desktop_auto_poweroff_arm(Desktop* desktop) { if(desktop->settings.auto_poweroff_delay_ms) { - desktop->input_events_subscription = furi_pubsub_subscribe( - desktop->input_events_pubsub, desktop_input_event_callback, desktop); + if(desktop->input_events_subscription) { + desktop->input_events_subscription = furi_pubsub_subscribe( + desktop->input_events_pubsub, desktop_input_event_callback, desktop); + } desktop_start_auto_poweroff_timer(desktop); } } From 4694492ed4c68c5660e10e60c32cb4f89e76de18 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 23 Dec 2024 21:03:53 +0300 Subject: [PATCH 36/59] upd changelog --- CHANGELOG.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f12e3bd56..122f5ccf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,24 @@ ## Main changes -- Current API: 78.2 +- Current API: 79.1 * SubGHz: Jolly Motors support (with add manually) (Thanks @pkooiman !) * Desktop: Auto Power Off Timer (by @Dmitry422 with some fixes by @xMasterX) * OFW PR 4025: Increase system stack's reserved memory size (Fix USB UART Bridge Crash) (by @Astrrra) * OFW: merged gsurkov/vcp_break_support branch for usb uart bridge (WIP!!!) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes +* Desktop: Add input events sub check +* OFW: Fix invalid path errors while deploying SDK by enforcing toolchain to use UTF-8 on initial SDK Extraction +* OFW: **Added flipper_format_write_empty_line(...)** +* OFW: Fix skylander ID reading +* OFW: Work around incorrect serial port handling by the OS +* OFW: Add winter animations +* OFW: FBT: Don't lint JS packages +* OFW: **Fix lost BadBLE keystrokes** +* OFW: **Loader: Fix BusFault in handling of OOM** (was already included in previous UL release) +* OFW: **NFC Fix ISO15693 stucking in wrong mode.** +* OFW: Update `infrared_test.c` reference +* OFW: **FuriThread stdin** +* OFW: **Add the ability to send a signal once via RPC** * OFW: NFC: Plantain parser Last payment amount fix * OFW: NFC clipper: BART station ids for San Lorenzo, Bay Fair * OFW: Fix typo for mf_classic_key_cahce_get_next_key() function From 1739f57c7a9f0e95079870c43c9eb5a238663d84 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 24 Dec 2024 01:02:05 +0300 Subject: [PATCH 37/59] enable anim --- assets/dolphin/external/manifest.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index 32295b50b..7e8bee083 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -225,6 +225,13 @@ Min level: 1 Max level: 3 Weight: 4 +Name: L1_New_year_128x64 +Min butthurt: 0 +Max butthurt: 14 +Min level: 1 +Max level: 3 +Weight: 4 + Name: L3_Fireplace_128x64 Min butthurt: 0 Max butthurt: 13 From 5fd423951bb5fa98c0a4187b68bacb2dbff97f2e Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Tue, 24 Dec 2024 05:58:27 +0400 Subject: [PATCH 38/59] [FL-3933] Pipe (#3996) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: FuriThread stdin * ci: fix f18 * feat: stdio callback context * feat: FuriPipe * POTENTIALLY EXPLOSIVE pipe welding * fix: non-explosive welding * Revert welding * docs: furi_pipe * feat: pipe event loop integration * update f18 sdk * f18 * docs: make doxygen happy * fix: event loop not triggering when pipe attached to stdio * fix: partial stdout in pipe * allow simultaneous in and out subscription in event loop * refactor: move pipe out of furi and decouple from event loop * chore: api versioning * Bump api versions * refactor: rename pipe_set_pipe_broken_callback * Toolbox: add missing pragma once Co-authored-by: あく --- applications/debug/unit_tests/application.fam | 8 + .../debug/unit_tests/tests/pipe/pipe_test.c | 153 +++++++++ furi/core/stream_buffer.c | 5 + furi/core/stream_buffer.h | 11 + lib/toolbox/SConscript | 1 + lib/toolbox/pipe.c | 241 ++++++++++++++ lib/toolbox/pipe.h | 295 ++++++++++++++++++ targets/f18/api_symbols.csv | 20 +- targets/f7/api_symbols.csv | 20 +- 9 files changed, 752 insertions(+), 2 deletions(-) create mode 100644 applications/debug/unit_tests/tests/pipe/pipe_test.c create mode 100644 lib/toolbox/pipe.c create mode 100644 lib/toolbox/pipe.h diff --git a/applications/debug/unit_tests/application.fam b/applications/debug/unit_tests/application.fam index dec3283e4..f92d7e66f 100644 --- a/applications/debug/unit_tests/application.fam +++ b/applications/debug/unit_tests/application.fam @@ -236,3 +236,11 @@ App( entry_point="get_api", requires=["unit_tests"], ) + +App( + appid="test_pipe", + sources=["tests/common/*.c", "tests/pipe/*.c"], + apptype=FlipperAppType.PLUGIN, + entry_point="get_api", + requires=["unit_tests"], +) diff --git a/applications/debug/unit_tests/tests/pipe/pipe_test.c b/applications/debug/unit_tests/tests/pipe/pipe_test.c new file mode 100644 index 000000000..d440a04ee --- /dev/null +++ b/applications/debug/unit_tests/tests/pipe/pipe_test.c @@ -0,0 +1,153 @@ +#include "../test.h" // IWYU pragma: keep + +#include +#include + +#define PIPE_SIZE 128U +#define PIPE_TRG_LEVEL 1U + +MU_TEST(pipe_test_trivial) { + PipeSideBundle bundle = pipe_alloc(PIPE_SIZE, PIPE_TRG_LEVEL); + PipeSide* alice = bundle.alices_side; + PipeSide* bob = bundle.bobs_side; + + mu_assert_int_eq(PipeRoleAlice, pipe_role(alice)); + mu_assert_int_eq(PipeRoleBob, pipe_role(bob)); + mu_assert_int_eq(PipeStateOpen, pipe_state(alice)); + mu_assert_int_eq(PipeStateOpen, pipe_state(bob)); + + mu_assert_int_eq(PIPE_SIZE, pipe_spaces_available(alice)); + mu_assert_int_eq(PIPE_SIZE, pipe_spaces_available(bob)); + mu_assert_int_eq(0, pipe_bytes_available(alice)); + mu_assert_int_eq(0, pipe_bytes_available(bob)); + + for(uint8_t i = 0;; ++i) { + mu_assert_int_eq(PIPE_SIZE - i, pipe_spaces_available(alice)); + mu_assert_int_eq(i, pipe_bytes_available(bob)); + + if(pipe_send(alice, &i, sizeof(uint8_t), 0) != sizeof(uint8_t)) { + break; + } + + mu_assert_int_eq(PIPE_SIZE - i, pipe_spaces_available(bob)); + mu_assert_int_eq(i, pipe_bytes_available(alice)); + + if(pipe_send(bob, &i, sizeof(uint8_t), 0) != sizeof(uint8_t)) { + break; + } + } + + pipe_free(alice); + mu_assert_int_eq(PipeStateBroken, pipe_state(bob)); + + for(uint8_t i = 0;; ++i) { + mu_assert_int_eq(PIPE_SIZE - i, pipe_bytes_available(bob)); + + uint8_t value; + if(pipe_receive(bob, &value, sizeof(uint8_t), 0) != sizeof(uint8_t)) { + break; + } + + mu_assert_int_eq(i, value); + } + + pipe_free(bob); +} + +typedef enum { + TestFlagDataArrived = 1 << 0, + TestFlagSpaceFreed = 1 << 1, + TestFlagBecameBroken = 1 << 2, +} TestFlag; + +typedef struct { + TestFlag flag; + FuriEventLoop* event_loop; +} AncillaryThreadContext; + +static void on_data_arrived(PipeSide* pipe, void* context) { + AncillaryThreadContext* ctx = context; + ctx->flag |= TestFlagDataArrived; + uint8_t buffer[PIPE_SIZE]; + size_t size = pipe_receive(pipe, buffer, sizeof(buffer), 0); + pipe_send(pipe, buffer, size, 0); +} + +static void on_space_freed(PipeSide* pipe, void* context) { + AncillaryThreadContext* ctx = context; + ctx->flag |= TestFlagSpaceFreed; + const char* message = "Hi!"; + pipe_send(pipe, message, strlen(message), 0); +} + +static void on_became_broken(PipeSide* pipe, void* context) { + UNUSED(pipe); + AncillaryThreadContext* ctx = context; + ctx->flag |= TestFlagBecameBroken; + furi_event_loop_stop(ctx->event_loop); +} + +static int32_t ancillary_thread(void* context) { + PipeSide* pipe = context; + AncillaryThreadContext thread_ctx = { + .flag = 0, + .event_loop = furi_event_loop_alloc(), + }; + + pipe_attach_to_event_loop(pipe, thread_ctx.event_loop); + pipe_set_callback_context(pipe, &thread_ctx); + pipe_set_data_arrived_callback(pipe, on_data_arrived, 0); + pipe_set_space_freed_callback(pipe, on_space_freed, FuriEventLoopEventFlagEdge); + pipe_set_broken_callback(pipe, on_became_broken, 0); + + furi_event_loop_run(thread_ctx.event_loop); + + pipe_detach_from_event_loop(pipe); + pipe_free(pipe); + furi_event_loop_free(thread_ctx.event_loop); + return thread_ctx.flag; +} + +MU_TEST(pipe_test_event_loop) { + PipeSideBundle bundle = pipe_alloc(PIPE_SIZE, PIPE_TRG_LEVEL); + PipeSide* alice = bundle.alices_side; + PipeSide* bob = bundle.bobs_side; + + FuriThread* thread = furi_thread_alloc_ex("PipeTestAnc", 2048, ancillary_thread, bob); + furi_thread_start(thread); + + const char* message = "Hello!"; + pipe_send(alice, message, strlen(message), FuriWaitForever); + + char buffer_1[16]; + size_t size = pipe_receive(alice, buffer_1, sizeof(buffer_1), FuriWaitForever); + buffer_1[size] = 0; + + char buffer_2[16]; + const char* expected_reply = "Hi!"; + size = pipe_receive(alice, buffer_2, sizeof(buffer_2), FuriWaitForever); + buffer_2[size] = 0; + + pipe_free(alice); + furi_thread_join(thread); + + mu_assert_string_eq(message, buffer_1); + mu_assert_string_eq(expected_reply, buffer_2); + mu_assert_int_eq( + TestFlagDataArrived | TestFlagSpaceFreed | TestFlagBecameBroken, + furi_thread_get_return_code(thread)); + + furi_thread_free(thread); +} + +MU_TEST_SUITE(test_pipe) { + MU_RUN_TEST(pipe_test_trivial); + MU_RUN_TEST(pipe_test_event_loop); +} + +int run_minunit_test_pipe(void) { + MU_RUN_SUITE(test_pipe); + return MU_EXIT_CODE; +} + +TEST_API_DEFINE(run_minunit_test_pipe) diff --git a/furi/core/stream_buffer.c b/furi/core/stream_buffer.c index 783b2d741..902ec931c 100644 --- a/furi/core/stream_buffer.c +++ b/furi/core/stream_buffer.c @@ -54,6 +54,11 @@ bool furi_stream_set_trigger_level(FuriStreamBuffer* stream_buffer, size_t trigg pdTRUE; } +size_t furi_stream_get_trigger_level(FuriStreamBuffer* stream_buffer) { + furi_check(stream_buffer); + return ((StaticStreamBuffer_t*)stream_buffer)->xTriggerLevelBytes; +} + size_t furi_stream_buffer_send( FuriStreamBuffer* stream_buffer, const void* data, diff --git a/furi/core/stream_buffer.h b/furi/core/stream_buffer.h index eef8ee510..deca813c7 100644 --- a/furi/core/stream_buffer.h +++ b/furi/core/stream_buffer.h @@ -54,6 +54,17 @@ void furi_stream_buffer_free(FuriStreamBuffer* stream_buffer); */ bool furi_stream_set_trigger_level(FuriStreamBuffer* stream_buffer, size_t trigger_level); +/** + * @brief Get trigger level for stream buffer. + * A stream buffer's trigger level is the number of bytes that must be in the + * stream buffer before a task that is blocked on the stream buffer to + * wait for data is moved out of the blocked state. + * + * @param stream_buffer The stream buffer instance + * @return The trigger level for the stream buffer + */ +size_t furi_stream_get_trigger_level(FuriStreamBuffer* stream_buffer); + /** * @brief Sends bytes to a stream buffer. The bytes are copied into the stream buffer. * Wakes up task waiting for data to become available if called from ISR. diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 03b8999c4..8a1c4a8c5 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -30,6 +30,7 @@ env.Append( File("stream/string_stream.h"), File("stream/buffered_file_stream.h"), File("strint.h"), + File("pipe.h"), File("protocols/protocol_dict.h"), File("pretty_format.h"), File("hex.h"), diff --git a/lib/toolbox/pipe.c b/lib/toolbox/pipe.c new file mode 100644 index 000000000..9dc1d368e --- /dev/null +++ b/lib/toolbox/pipe.c @@ -0,0 +1,241 @@ +#include "pipe.h" +#include + +/** + * Data shared between both sides. + */ +typedef struct { + FuriSemaphore* instance_count; // role; +} + +PipeState pipe_state(PipeSide* pipe) { + furi_check(pipe); + uint32_t count = furi_semaphore_get_count(pipe->shared->instance_count); + return (count == 1) ? PipeStateOpen : PipeStateBroken; +} + +void pipe_free(PipeSide* pipe) { + furi_check(pipe); + furi_check(!pipe->event_loop); + + furi_mutex_acquire(pipe->shared->state_transition, FuriWaitForever); + FuriStatus status = furi_semaphore_acquire(pipe->shared->instance_count, 0); + + if(status == FuriStatusOk) { + // the other side is still intact + furi_mutex_release(pipe->shared->state_transition); + free(pipe); + } else { + // the other side is gone too + furi_stream_buffer_free(pipe->sending); + furi_stream_buffer_free(pipe->receiving); + furi_semaphore_free(pipe->shared->instance_count); + furi_mutex_free(pipe->shared->state_transition); + free(pipe->shared); + free(pipe); + } +} + +static void _pipe_stdout_cb(const char* data, size_t size, void* context) { + furi_assert(context); + PipeSide* pipe = context; + while(size) { + size_t sent = pipe_send(pipe, data, size, FuriWaitForever); + data += sent; + size -= sent; + } +} + +static size_t _pipe_stdin_cb(char* data, size_t size, FuriWait timeout, void* context) { + furi_assert(context); + PipeSide* pipe = context; + return pipe_receive(pipe, data, size, timeout); +} + +void pipe_install_as_stdio(PipeSide* pipe) { + furi_check(pipe); + furi_thread_set_stdout_callback(_pipe_stdout_cb, pipe); + furi_thread_set_stdin_callback(_pipe_stdin_cb, pipe); +} + +size_t pipe_receive(PipeSide* pipe, void* data, size_t length, FuriWait timeout) { + furi_check(pipe); + return furi_stream_buffer_receive(pipe->receiving, data, length, timeout); +} + +size_t pipe_send(PipeSide* pipe, const void* data, size_t length, FuriWait timeout) { + furi_check(pipe); + return furi_stream_buffer_send(pipe->sending, data, length, timeout); +} + +size_t pipe_bytes_available(PipeSide* pipe) { + furi_check(pipe); + return furi_stream_buffer_bytes_available(pipe->receiving); +} + +size_t pipe_spaces_available(PipeSide* pipe) { + furi_check(pipe); + return furi_stream_buffer_spaces_available(pipe->sending); +} + +static void pipe_receiving_buffer_callback(FuriEventLoopObject* buffer, void* context) { + UNUSED(buffer); + PipeSide* pipe = context; + furi_assert(pipe); + if(pipe->on_space_freed) pipe->on_data_arrived(pipe, pipe->callback_context); +} + +static void pipe_sending_buffer_callback(FuriEventLoopObject* buffer, void* context) { + UNUSED(buffer); + PipeSide* pipe = context; + furi_assert(pipe); + if(pipe->on_data_arrived) pipe->on_space_freed(pipe, pipe->callback_context); +} + +static void pipe_semaphore_callback(FuriEventLoopObject* semaphore, void* context) { + UNUSED(semaphore); + PipeSide* pipe = context; + furi_assert(pipe); + if(pipe->on_pipe_broken) pipe->on_pipe_broken(pipe, pipe->callback_context); +} + +void pipe_attach_to_event_loop(PipeSide* pipe, FuriEventLoop* event_loop) { + furi_check(pipe); + furi_check(event_loop); + furi_check(!pipe->event_loop); + + pipe->event_loop = event_loop; +} + +void pipe_detach_from_event_loop(PipeSide* pipe) { + furi_check(pipe); + furi_check(pipe->event_loop); + + furi_event_loop_maybe_unsubscribe(pipe->event_loop, pipe->receiving); + furi_event_loop_maybe_unsubscribe(pipe->event_loop, pipe->sending); + furi_event_loop_maybe_unsubscribe(pipe->event_loop, pipe->shared->instance_count); + + pipe->event_loop = NULL; +} + +void pipe_set_callback_context(PipeSide* pipe, void* context) { + furi_check(pipe); + pipe->callback_context = context; +} + +void pipe_set_data_arrived_callback( + PipeSide* pipe, + PipeSideDataArrivedCallback callback, + FuriEventLoopEvent event) { + furi_check(pipe); + furi_check(pipe->event_loop); + furi_check((event & FuriEventLoopEventMask) == 0); + + furi_event_loop_maybe_unsubscribe(pipe->event_loop, pipe->receiving); + pipe->on_data_arrived = callback; + if(callback) + furi_event_loop_subscribe_stream_buffer( + pipe->event_loop, + pipe->receiving, + FuriEventLoopEventIn | event, + pipe_receiving_buffer_callback, + pipe); +} + +void pipe_set_space_freed_callback( + PipeSide* pipe, + PipeSideSpaceFreedCallback callback, + FuriEventLoopEvent event) { + furi_check(pipe); + furi_check(pipe->event_loop); + furi_check((event & FuriEventLoopEventMask) == 0); + + furi_event_loop_maybe_unsubscribe(pipe->event_loop, pipe->sending); + pipe->on_space_freed = callback; + if(callback) + furi_event_loop_subscribe_stream_buffer( + pipe->event_loop, + pipe->sending, + FuriEventLoopEventOut | event, + pipe_sending_buffer_callback, + pipe); +} + +void pipe_set_broken_callback( + PipeSide* pipe, + PipeSideBrokenCallback callback, + FuriEventLoopEvent event) { + furi_check(pipe); + furi_check(pipe->event_loop); + furi_check((event & FuriEventLoopEventMask) == 0); + + furi_event_loop_maybe_unsubscribe(pipe->event_loop, pipe->shared->instance_count); + pipe->on_pipe_broken = callback; + if(callback) + furi_event_loop_subscribe_semaphore( + pipe->event_loop, + pipe->shared->instance_count, + FuriEventLoopEventOut | event, + pipe_semaphore_callback, + pipe); +} diff --git a/lib/toolbox/pipe.h b/lib/toolbox/pipe.h new file mode 100644 index 000000000..df75f4c48 --- /dev/null +++ b/lib/toolbox/pipe.h @@ -0,0 +1,295 @@ +/** + * @file pipe.h + * Pipe convenience module + * + * Pipes are used to send bytes between two threads in both directions. The two + * threads are referred to as Alice and Bob and their abilities regarding what + * they can do with the pipe are equal. + * + * It is also possible to use both sides of the pipe within one thread. + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** + * @brief The role of a pipe side + * + * Both roles are equal, as they can both read and write the data. This status + * might be helpful in determining the role of a thread w.r.t. another thread in + * an application that builds on the pipe. + */ +typedef enum { + PipeRoleAlice, + PipeRoleBob, +} PipeRole; + +/** + * @brief The state of a pipe + * + * - `PipeStateOpen`: Both pipe sides are in place, meaning data that is sent + * down the pipe _might_ be read by the peer, and new data sent by the peer + * _might_ arrive. + * - `PipeStateBroken`: The other side of the pipe has been freed, meaning + * data that is written will never reach its destination, and no new data + * will appear in the buffer. + * + * A broken pipe can never become open again, because there's no way to connect + * a side of a pipe to another side of a pipe. + */ +typedef enum { + PipeStateOpen, + PipeStateBroken, +} PipeState; + +typedef struct PipeSide PipeSide; + +typedef struct { + PipeSide* alices_side; + PipeSide* bobs_side; +} PipeSideBundle; + +typedef struct { + size_t capacity; + size_t trigger_level; +} PipeSideReceiveSettings; + +/** + * @brief Allocates two connected sides of one pipe. + * + * Creating a pair of sides using this function is the only way to connect two + * pipe sides together. Two unrelated orphaned sides may never be connected back + * together. + * + * The capacity and trigger level for both directions are the same when the pipe + * is created using this function. Use `pipe_alloc_ex` if you want more + * control. + * + * @param capacity Maximum number of bytes buffered in one direction + * @param trigger_level Number of bytes that need to be available in the buffer + * in order for a blocked thread to unblock + * @returns Bundle with both sides of the pipe + */ +PipeSideBundle pipe_alloc(size_t capacity, size_t trigger_level); + +/** + * @brief Allocates two connected sides of one pipe. + * + * Creating a pair of sides using this function is the only way to connect two + * pipe sides together. Two unrelated orphaned sides may never be connected back + * together. + * + * The capacity and trigger level may be different for the two directions when + * the pipe is created using this function. Use `pipe_alloc` if you don't + * need control this fine. + * + * @param alice `capacity` and `trigger_level` settings for Alice's receiving + * buffer + * @param bob `capacity` and `trigger_level` settings for Bob's receiving buffer + * @returns Bundle with both sides of the pipe + */ +PipeSideBundle pipe_alloc_ex(PipeSideReceiveSettings alice, PipeSideReceiveSettings bob); + +/** + * @brief Gets the role of a pipe side. + * + * The roles (Alice and Bob) are equal, as both can send and receive data. This + * status might be helpful in determining the role of a thread w.r.t. another + * thread. + * + * @param [in] pipe Pipe side to query + * @returns Role of provided pipe side + */ +PipeRole pipe_role(PipeSide* pipe); + +/** + * @brief Gets the state of a pipe. + * + * When the state is `PipeStateOpen`, both sides are active and may send or + * receive data. When the state is `PipeStateBroken`, only one side is active + * (the one that this method has been called on). If you find yourself in that + * state, the data that you send will never be heard by anyone, and the data you + * receive are leftovers in the buffer. + * + * @param [in] pipe Pipe side to query + * @returns State of the pipe + */ +PipeState pipe_state(PipeSide* pipe); + +/** + * @brief Frees a side of a pipe. + * + * When only one of the sides is freed, the pipe is transitioned from the "Open" + * state into the "Broken" state. When both sides are freed, the underlying data + * structures are freed too. + * + * @param [in] pipe Pipe side to free + */ +void pipe_free(PipeSide* pipe); + +/** + * @brief Connects the pipe to the `stdin` and `stdout` of the current thread. + * + * After performing this operation, you can use `getc`, `puts`, etc. to send and + * receive data to and from the pipe. If the pipe becomes broken, C stdlib calls + * will return `EOF` wherever possible. + * + * You can disconnect the pipe by manually calling + * `furi_thread_set_stdout_callback` and `furi_thread_set_stdin_callback` with + * `NULL`. + * + * @param [in] pipe Pipe side to connect to the stdio + */ +void pipe_install_as_stdio(PipeSide* pipe); + +/** + * @brief Receives data from the pipe. + * + * @param [in] pipe The pipe side to read data out of + * @param [out] data The buffer to fill with data + * @param length Maximum length of data to read + * @param timeout The timeout (in ticks) after which the read operation is + * interrupted + * @returns The number of bytes actually written into the provided buffer + */ +size_t pipe_receive(PipeSide* pipe, void* data, size_t length, FuriWait timeout); + +/** + * @brief Sends data into the pipe. + * + * @param [in] pipe The pipe side to send data into + * @param [out] data The buffer to get data from + * @param length Maximum length of data to send + * @param timeout The timeout (in ticks) after which the write operation is + * interrupted + * @returns The number of bytes actually read from the provided buffer + */ +size_t pipe_send(PipeSide* pipe, const void* data, size_t length, FuriWait timeout); + +/** + * @brief Determines how many bytes there are in the pipe available to be read. + * + * @param [in] pipe Pipe side to query + * @returns Number of bytes available to be read out from that side of the pipe + */ +size_t pipe_bytes_available(PipeSide* pipe); + +/** + * @brief Determines how many space there is in the pipe for data to be written + * into. + * + * @param [in] pipe Pipe side to query + * @returns Number of bytes available to be written into that side of the pipe + */ +size_t pipe_spaces_available(PipeSide* pipe); + +/** + * @brief Attaches a `PipeSide` to a `FuriEventLoop`, allowing to attach + * callbacks to the PipeSide. + * + * @param [in] pipe Pipe side to attach to the event loop + * @param [in] event_loop Event loop to attach the pipe side to + */ +void pipe_attach_to_event_loop(PipeSide* pipe, FuriEventLoop* event_loop); + +/** + * @brief Detaches a `PipeSide` from the `FuriEventLoop` that it was previously + * attached to. + * + * @param [in] pipe Pipe side to detach to the event loop + */ +void pipe_detach_from_event_loop(PipeSide* pipe); + +/** + * @brief Callback for when data arrives to a `PipeSide`. + * + * @param [in] pipe Pipe side that called the callback + * @param [inout] context Custom context + */ +typedef void (*PipeSideDataArrivedCallback)(PipeSide* pipe, void* context); + +/** + * @brief Callback for when data is read out of the opposite `PipeSide`. + * + * @param [in] pipe Pipe side that called the callback + * @param [inout] context Custom context + */ +typedef void (*PipeSideSpaceFreedCallback)(PipeSide* pipe, void* context); + +/** + * @brief Callback for when the opposite `PipeSide` is freed, making the pipe + * broken. + * + * @param [in] pipe Pipe side that called the callback + * @param [inout] context Custom context + */ +typedef void (*PipeSideBrokenCallback)(PipeSide* pipe, void* context); + +/** + * @brief Sets the custom context for all callbacks. + * + * @param [in] pipe Pipe side to set the context of + * @param [inout] context Custom context that will be passed to callbacks + */ +void pipe_set_callback_context(PipeSide* pipe, void* context); + +/** + * @brief Sets the callback for when data arrives. + * + * @param [in] pipe Pipe side to assign the callback to + * @param [in] callback Callback to assign to the pipe side. Set to NULL to + * unsubscribe. + * @param [in] event Additional event loop flags (e.g. `Edge`, `Once`, etc.). + * Non-flag values of the enum are not allowed. + * + * @warning Attach the pipe side to an event loop first using + * `pipe_attach_to_event_loop`. + */ +void pipe_set_data_arrived_callback( + PipeSide* pipe, + PipeSideDataArrivedCallback callback, + FuriEventLoopEvent event); + +/** + * @brief Sets the callback for when data is read out of the opposite `PipeSide`. + * + * @param [in] pipe Pipe side to assign the callback to + * @param [in] callback Callback to assign to the pipe side. Set to NULL to + * unsubscribe. + * @param [in] event Additional event loop flags (e.g. `Edge`, `Once`, etc.). + * Non-flag values of the enum are not allowed. + * + * @warning Attach the pipe side to an event loop first using + * `pipe_attach_to_event_loop`. + */ +void pipe_set_space_freed_callback( + PipeSide* pipe, + PipeSideSpaceFreedCallback callback, + FuriEventLoopEvent event); + +/** + * @brief Sets the callback for when the opposite `PipeSide` is freed, making + * the pipe broken. + * + * @param [in] pipe Pipe side to assign the callback to + * @param [in] callback Callback to assign to the pipe side. Set to NULL to + * unsubscribe. + * @param [in] event Additional event loop flags (e.g. `Edge`, `Once`, etc.). + * Non-flag values of the enum are not allowed. + * + * @warning Attach the pipe side to an event loop first using + * `pipe_attach_to_event_loop`. + */ +void pipe_set_broken_callback( + PipeSide* pipe, + PipeSideBrokenCallback callback, + FuriEventLoopEvent event); + +#ifdef __cplusplus +} +#endif diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index e18aee04d..0a4b7dde6 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.1,, +Version,+,79.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -161,6 +161,7 @@ Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/md5_calc.h,, Header,+,lib/toolbox/name_generator.h,, Header,+,lib/toolbox/path.h,, +Header,+,lib/toolbox/pipe.h,, Header,+,lib/toolbox/pretty_format.h,, Header,+,lib/toolbox/protocols/protocol_dict.h,, Header,+,lib/toolbox/pulse_protocols/pulse_glue.h,, @@ -1580,6 +1581,7 @@ Function,+,furi_stream_buffer_receive,size_t,"FuriStreamBuffer*, void*, size_t, Function,+,furi_stream_buffer_reset,FuriStatus,FuriStreamBuffer* Function,+,furi_stream_buffer_send,size_t,"FuriStreamBuffer*, const void*, size_t, uint32_t" Function,+,furi_stream_buffer_spaces_available,size_t,FuriStreamBuffer* +Function,+,furi_stream_get_trigger_level,size_t,FuriStreamBuffer* Function,+,furi_stream_set_trigger_level,_Bool,"FuriStreamBuffer*, size_t" Function,+,furi_string_alloc,FuriString*, Function,+,furi_string_alloc_move,FuriString*,FuriString* @@ -2290,6 +2292,22 @@ Function,+,pb_skip_field,_Bool,"pb_istream_t*, pb_wire_type_t" Function,+,pb_write,_Bool,"pb_ostream_t*, const pb_byte_t*, size_t" Function,-,pclose,int,FILE* Function,-,perror,void,const char* +Function,+,pipe_alloc,PipeSideBundle,"size_t, size_t" +Function,+,pipe_alloc_ex,PipeSideBundle,"PipeSideReceiveSettings, PipeSideReceiveSettings" +Function,+,pipe_attach_to_event_loop,void,"PipeSide*, FuriEventLoop*" +Function,+,pipe_bytes_available,size_t,PipeSide* +Function,+,pipe_detach_from_event_loop,void,PipeSide* +Function,+,pipe_free,void,PipeSide* +Function,+,pipe_install_as_stdio,void,PipeSide* +Function,+,pipe_receive,size_t,"PipeSide*, void*, size_t, FuriWait" +Function,+,pipe_role,PipeRole,PipeSide* +Function,+,pipe_send,size_t,"PipeSide*, const void*, size_t, FuriWait" +Function,+,pipe_set_callback_context,void,"PipeSide*, void*" +Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent" +Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, FuriEventLoopEvent" +Function,+,pipe_set_space_freed_callback,void,"PipeSide*, PipeSideSpaceFreedCallback, FuriEventLoopEvent" +Function,+,pipe_spaces_available,size_t,PipeSide* +Function,+,pipe_state,PipeState,PipeSide* Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*" Function,+,plugin_manager_free,void,PluginManager* Function,+,plugin_manager_get,const FlipperAppPluginDescriptor*,"PluginManager*, uint32_t" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 51404c951..15f4d70d7 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.1,, +Version,+,79.2,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -233,6 +233,7 @@ Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/md5_calc.h,, Header,+,lib/toolbox/name_generator.h,, Header,+,lib/toolbox/path.h,, +Header,+,lib/toolbox/pipe.h,, Header,+,lib/toolbox/pretty_format.h,, Header,+,lib/toolbox/protocols/protocol_dict.h,, Header,+,lib/toolbox/pulse_protocols/pulse_glue.h,, @@ -1799,6 +1800,7 @@ Function,+,furi_stream_buffer_receive,size_t,"FuriStreamBuffer*, void*, size_t, Function,+,furi_stream_buffer_reset,FuriStatus,FuriStreamBuffer* Function,+,furi_stream_buffer_send,size_t,"FuriStreamBuffer*, const void*, size_t, uint32_t" Function,+,furi_stream_buffer_spaces_available,size_t,FuriStreamBuffer* +Function,+,furi_stream_get_trigger_level,size_t,FuriStreamBuffer* Function,+,furi_stream_set_trigger_level,_Bool,"FuriStreamBuffer*, size_t" Function,+,furi_string_alloc,FuriString*, Function,+,furi_string_alloc_move,FuriString*,FuriString* @@ -2926,6 +2928,22 @@ Function,+,pb_skip_field,_Bool,"pb_istream_t*, pb_wire_type_t" Function,+,pb_write,_Bool,"pb_ostream_t*, const pb_byte_t*, size_t" Function,-,pclose,int,FILE* Function,-,perror,void,const char* +Function,+,pipe_alloc,PipeSideBundle,"size_t, size_t" +Function,+,pipe_alloc_ex,PipeSideBundle,"PipeSideReceiveSettings, PipeSideReceiveSettings" +Function,+,pipe_attach_to_event_loop,void,"PipeSide*, FuriEventLoop*" +Function,+,pipe_bytes_available,size_t,PipeSide* +Function,+,pipe_detach_from_event_loop,void,PipeSide* +Function,+,pipe_free,void,PipeSide* +Function,+,pipe_install_as_stdio,void,PipeSide* +Function,+,pipe_receive,size_t,"PipeSide*, void*, size_t, FuriWait" +Function,+,pipe_role,PipeRole,PipeSide* +Function,+,pipe_send,size_t,"PipeSide*, const void*, size_t, FuriWait" +Function,+,pipe_set_callback_context,void,"PipeSide*, void*" +Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent" +Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, FuriEventLoopEvent" +Function,+,pipe_set_space_freed_callback,void,"PipeSide*, PipeSideSpaceFreedCallback, FuriEventLoopEvent" +Function,+,pipe_spaces_available,size_t,PipeSide* +Function,+,pipe_state,PipeState,PipeSide* Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*" Function,+,plugin_manager_free,void,PluginManager* Function,+,plugin_manager_get,const FlipperAppPluginDescriptor*,"PluginManager*, uint32_t" From 5fb9558dbb1b48dca1d48e6bffad9f7bf9d9f7a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 11:24:01 +0900 Subject: [PATCH 39/59] Bump cross-spawn in /applications/system/js_app/packages/create-fz-app (#4043) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6. - [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md) - [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6) --- updated-dependencies: - dependency-name: cross-spawn dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: あく --- .../system/js_app/packages/create-fz-app/pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/system/js_app/packages/create-fz-app/pnpm-lock.yaml b/applications/system/js_app/packages/create-fz-app/pnpm-lock.yaml index 58f20a385..3f753df15 100644 --- a/applications/system/js_app/packages/create-fz-app/pnpm-lock.yaml +++ b/applications/system/js_app/packages/create-fz-app/pnpm-lock.yaml @@ -62,8 +62,8 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} eastasianwidth@0.2.0: @@ -240,7 +240,7 @@ snapshots: color-name@1.1.4: {} - cross-spawn@7.0.3: + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -256,7 +256,7 @@ snapshots: foreground-child@3.3.0: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 get-caller-file@2.0.5: {} From 7fc34db57b40b58404910a0eeef87dffbea40729 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 24 Dec 2024 14:04:34 +0300 Subject: [PATCH 40/59] use event system --- applications/services/desktop/desktop.c | 12 ++++++++---- applications/services/desktop/views/desktop_events.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index abe7d69bc..d77be68a0 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -156,7 +156,11 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { if(!desktop->app_running && !desktop->locked) { desktop_lock(desktop); } - + } else if(event == DesktopGlobalAutoPowerOff) { + if(!desktop->app_running) { + Power* power = furi_record_open(RECORD_POWER); + power_off(power); + } } else if(event == DesktopGlobalSaveSettings) { desktop_settings_save(&desktop->settings); desktop_apply_settings(desktop); @@ -232,9 +236,9 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { //--- auto_power_off_timer static void desktop_auto_poweroff_timer_callback(void* context) { - UNUSED(context); - Power* power = furi_record_open(RECORD_POWER); - power_off(power); + furi_assert(context); + Desktop* desktop = context; + view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAutoPowerOff); } static void desktop_start_auto_poweroff_timer(Desktop* desktop) { diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index ba91a30cc..57cc0fdaa 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -62,4 +62,5 @@ typedef enum { DesktopGlobalApiUnlock, DesktopGlobalSaveSettings, DesktopGlobalReloadSettings, + DesktopGlobalAutoPowerOff, } DesktopEvent; From 1a95757a75f42054b88c6bb9dcb44227175d1a42 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 24 Dec 2024 14:23:07 +0300 Subject: [PATCH 41/59] upd changelog --- CHANGELOG.md | 10 ++++++---- applications/services/desktop/desktop.c | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 122f5ccf2..245ffe0de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,26 @@ ## Main changes -- Current API: 79.1 +- Current API: 79.2 * SubGHz: Jolly Motors support (with add manually) (Thanks @pkooiman !) * Desktop: Auto Power Off Timer (by @Dmitry422 with some fixes by @xMasterX) +* OFW: **Fix lost BadBLE keystrokes** +* OFW: **Add the ability to send a signal once via RPC** * OFW PR 4025: Increase system stack's reserved memory size (Fix USB UART Bridge Crash) (by @Astrrra) * OFW: merged gsurkov/vcp_break_support branch for usb uart bridge (WIP!!!) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes -* Desktop: Add input events sub check +* Desktop: Add input events sub check & use event system for auto power off +* OFW: Bump cross-spawn in /applications/system/js_app/packages/create-fz-app +* OFW: **Pipe** (new api funcs) * OFW: Fix invalid path errors while deploying SDK by enforcing toolchain to use UTF-8 on initial SDK Extraction * OFW: **Added flipper_format_write_empty_line(...)** * OFW: Fix skylander ID reading * OFW: Work around incorrect serial port handling by the OS * OFW: Add winter animations * OFW: FBT: Don't lint JS packages -* OFW: **Fix lost BadBLE keystrokes** * OFW: **Loader: Fix BusFault in handling of OOM** (was already included in previous UL release) * OFW: **NFC Fix ISO15693 stucking in wrong mode.** * OFW: Update `infrared_test.c` reference * OFW: **FuriThread stdin** -* OFW: **Add the ability to send a signal once via RPC** * OFW: NFC: Plantain parser Last payment amount fix * OFW: NFC clipper: BART station ids for San Lorenzo, Bay Fair * OFW: Fix typo for mf_classic_key_cahce_get_next_key() function diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index d77be68a0..59c5290f4 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -252,7 +252,7 @@ static void desktop_stop_auto_poweroff_timer(Desktop* desktop) { static void desktop_auto_poweroff_arm(Desktop* desktop) { if(desktop->settings.auto_poweroff_delay_ms) { - if(desktop->input_events_subscription) { + if(!desktop->input_events_subscription) { desktop->input_events_subscription = furi_pubsub_subscribe( desktop->input_events_pubsub, desktop_input_event_callback, desktop); } From f2c84e0510390380b540b81dff6ca5f63f152133 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 5 Jan 2025 17:14:41 +0300 Subject: [PATCH 42/59] docker image source --- .ci_files/imgs/fztools/Dockerfile | 13 +++++++++++++ .ci_files/imgs/fztools/entrypoint.sh | 10 ++++++++++ 2 files changed, 23 insertions(+) create mode 100644 .ci_files/imgs/fztools/Dockerfile create mode 100644 .ci_files/imgs/fztools/entrypoint.sh diff --git a/.ci_files/imgs/fztools/Dockerfile b/.ci_files/imgs/fztools/Dockerfile new file mode 100644 index 000000000..c14096416 --- /dev/null +++ b/.ci_files/imgs/fztools/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:hirsute + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ + ca-certificates \ + git \ + wget \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +COPY entrypoint.sh / + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/.ci_files/imgs/fztools/entrypoint.sh b/.ci_files/imgs/fztools/entrypoint.sh new file mode 100644 index 000000000..13dec493b --- /dev/null +++ b/.ci_files/imgs/fztools/entrypoint.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +if [ -z "$1" ]; then + bash +else + echo "Running $1" + set -ex + bash -c "$1" +fi + From 668500e98581d62240ea322923e1b40f1a7b0bf9 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Fri, 10 Jan 2025 01:20:34 -0700 Subject: [PATCH 43/59] nfc: Fix MFUL PWD_AUTH command creation (#4051) --- lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 141ab6c46..d84377612 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -37,7 +37,7 @@ MfUltralightError mf_ultralight_poller_auth_pwd( furi_check(data); uint8_t auth_cmd[5] = {MF_ULTRALIGHT_CMD_PWD_AUTH}; //-V1009 - memccpy(&auth_cmd[1], data->password.data, 0, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE); + memcpy(&auth_cmd[1], data->password.data, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE); bit_buffer_copy_bytes(instance->tx_buffer, auth_cmd, sizeof(auth_cmd)); MfUltralightError ret = MfUltralightErrorNone; From 5efdab863bbd51997f272236ce8c3e1043cd496d Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Fri, 10 Jan 2025 01:39:39 -0700 Subject: [PATCH 44/59] u2f: Fix leaking message digest contexts (#4052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * u2f: Fix leaking message digest contexts * Github: fix doxygen version to 1.12 Co-authored-by: あく --- .github/workflows/docs.yml | 2 +- applications/main/u2f/u2f.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 65af450cf..c291fe0ca 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -56,7 +56,7 @@ jobs: python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" - name: 'Generate documentation' - uses: mattnotmitt/doxygen-action@edge + uses: mattnotmitt/doxygen-action@1.12.0 env: DOXY_SRC_ROOT: "${{ github.workspace }}" DOXY_CONFIG_DIR: "${{ github.workspace }}/documentation/doxygen" diff --git a/applications/main/u2f/u2f.c b/applications/main/u2f/u2f.c index 0143eb245..132baf4f9 100644 --- a/applications/main/u2f/u2f.c +++ b/applications/main/u2f/u2f.c @@ -280,6 +280,8 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { MCHECK(mbedtls_md_hmac_update(&hmac_ctx, private, sizeof(private))); MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, handle.hash)); + + mbedtls_md_free(&hmac_ctx); } // Generate public key @@ -387,6 +389,8 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { MCHECK(mbedtls_md_hmac_update(&hmac_ctx, priv_key, sizeof(priv_key))); MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, mac_control)); + + mbedtls_md_free(&hmac_ctx); } if(memcmp(req->key_handle.hash, mac_control, sizeof(mac_control)) != 0) { From 35c1bfc0570e82ceaaa452f562f30e0f42b5dfab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Fri, 10 Jan 2025 20:03:47 +0900 Subject: [PATCH 45/59] Github: update doxygen workflow to use exact version (#4065) * Github: update doxygen workflow to use exact version * Github: inject DOXY_CONFIG_DIR into doxygen execution env * Github: use fbt to build doxygen docs --- .github/workflows/docs.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c291fe0ca..064c43655 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -55,15 +55,13 @@ jobs: fi python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" - - name: 'Generate documentation' - uses: mattnotmitt/doxygen-action@1.12.0 - env: - DOXY_SRC_ROOT: "${{ github.workspace }}" - DOXY_CONFIG_DIR: "${{ github.workspace }}/documentation/doxygen" - DOXY_OUTPUT_DIR: "${{ github.workspace }}/documentation/doxygen/build" + - name: install-doxygen + uses: AdarshRawat1/Install-Doxygen@v1.0 with: - working-directory: 'documentation/' - doxyfile-path: './doxygen/Doxyfile-awesome.cfg' + version: "1.12.0" + + - name: 'Generate documentation' + run: ./fbt doxygen - name: 'Upload documentation' if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/dev' && needs.check-secret.outputs.s3-valid-config == 'true' }} From a0d1d3fa0fed7f6b263ec63686323793619c8292 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Sun, 12 Jan 2025 11:15:52 -0700 Subject: [PATCH 46/59] nfc: Fix MIFARE Plus detection (#4049) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: Fix MIFARE Plus detection MIFARE Plus original doesn't have GetVersion support, so detection for SL2 has been moved. Also, SL2 only exists in MIFARE Plus X, so despite it not being specified in the type identification procedure chart, it's safe to call it for what it is. * Fix spelling * TODO: mark as non flipper one Co-authored-by: あく --- lib/nfc/protocols/mf_plus/mf_plus_i.c | 126 +++++++++++++++----------- lib/nfc/protocols/mf_plus/mf_plus_i.h | 3 + 2 files changed, 74 insertions(+), 55 deletions(-) diff --git a/lib/nfc/protocols/mf_plus/mf_plus_i.c b/lib/nfc/protocols/mf_plus/mf_plus_i.c index 4ad2ff878..bd32956d6 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus_i.c +++ b/lib/nfc/protocols/mf_plus/mf_plus_i.c @@ -27,65 +27,51 @@ MfPlusError mf_plus_get_type_from_version( MfPlusError error = MfPlusErrorProtocol; - if(mf_plus_data->version.hw_major == 0x02 || mf_plus_data->version.hw_major == 0x82) { + if(mf_plus_data->version.hw_type == 0x02 || mf_plus_data->version.hw_type == 0x82) { error = MfPlusErrorNone; - if(iso14443_4a_data->iso14443_3a_data->sak == 0x10) { - // Mifare Plus 2K SL2 - mf_plus_data->type = MfPlusTypePlus; + // Mifare Plus EV1/EV2 + + // Revision + switch(mf_plus_data->version.hw_major) { + case 0x11: + mf_plus_data->type = MfPlusTypeEV1; + FURI_LOG_D(TAG, "Mifare Plus EV1"); + break; + case 0x22: + mf_plus_data->type = MfPlusTypeEV2; + FURI_LOG_D(TAG, "Mifare Plus EV2"); + break; + default: + mf_plus_data->type = MfPlusTypeUnknown; + FURI_LOG_D(TAG, "Unknown Mifare Plus EV type"); + break; + } + + // Storage size + switch(mf_plus_data->version.hw_storage) { + case 0x16: mf_plus_data->size = MfPlusSize2K; - mf_plus_data->security_level = MfPlusSecurityLevel2; - FURI_LOG_D(TAG, "Mifare Plus 2K SL2"); - } else if(iso14443_4a_data->iso14443_3a_data->sak == 0x11) { - // Mifare Plus 4K SL3 - mf_plus_data->type = MfPlusTypePlus; + FURI_LOG_D(TAG, "2K"); + break; + case 0x18: mf_plus_data->size = MfPlusSize4K; + FURI_LOG_D(TAG, "4K"); + break; + default: + mf_plus_data->size = MfPlusSizeUnknown; + FURI_LOG_D(TAG, "Unknown storage size"); + break; + } + + // Security level + if(iso14443_4a_data->iso14443_3a_data->sak == 0x20) { + // Mifare Plus EV1/2 SL3 mf_plus_data->security_level = MfPlusSecurityLevel3; - FURI_LOG_D(TAG, "Mifare Plus 4K SL3"); + FURI_LOG_D(TAG, "Mifare Plus EV1/2 SL3"); } else { - // Mifare Plus EV1/EV2 - - // Revision - switch(mf_plus_data->version.hw_major) { - case 0x11: - mf_plus_data->type = MfPlusTypeEV1; - FURI_LOG_D(TAG, "Mifare Plus EV1"); - break; - case 0x22: - mf_plus_data->type = MfPlusTypeEV2; - FURI_LOG_D(TAG, "Mifare Plus EV2"); - break; - default: - mf_plus_data->type = MfPlusTypeUnknown; - FURI_LOG_D(TAG, "Unknown Mifare Plus EV type"); - break; - } - - // Storage size - switch(mf_plus_data->version.hw_storage) { - case 0x16: - mf_plus_data->size = MfPlusSize2K; - FURI_LOG_D(TAG, "2K"); - break; - case 0x18: - mf_plus_data->size = MfPlusSize4K; - FURI_LOG_D(TAG, "4K"); - break; - default: - mf_plus_data->size = MfPlusSizeUnknown; - FURI_LOG_D(TAG, "Unknown storage size"); - break; - } - - // Security level - if(iso14443_4a_data->iso14443_3a_data->sak == 0x20) { - // Mifare Plus EV1/2 SL3 - mf_plus_data->security_level = MfPlusSecurityLevel3; - FURI_LOG_D(TAG, "Miare Plus EV1/2 SL3"); - } else { - // Mifare Plus EV1/2 SL1 - mf_plus_data->security_level = MfPlusSecurityLevel1; - FURI_LOG_D(TAG, "Miare Plus EV1/2 SL1"); - } + // Mifare Plus EV1/2 SL1 + mf_plus_data->security_level = MfPlusSecurityLevel1; + FURI_LOG_D(TAG, "Mifare Plus EV1/2 SL1"); } } @@ -148,6 +134,24 @@ MfPlusError FURI_LOG_D(TAG, "Sak 08 but no known Mifare Plus type"); } + break; + case 0x10: + // Mifare Plus X 2K SL2 + mf_plus_data->type = MfPlusTypeX; + mf_plus_data->size = MfPlusSize2K; + mf_plus_data->security_level = MfPlusSecurityLevel2; + FURI_LOG_D(TAG, "Mifare Plus X 2K SL2"); + error = MfPlusErrorNone; + + break; + case 0x11: + // Mifare Plus X 4K SL2 + mf_plus_data->type = MfPlusTypeX; + mf_plus_data->size = MfPlusSize4K; + mf_plus_data->security_level = MfPlusSecurityLevel2; + FURI_LOG_D(TAG, "Mifare Plus X 4K SL2"); + error = MfPlusErrorNone; + break; case 0x18: if(memcmp( @@ -234,10 +238,22 @@ MfPlusError } MfPlusError mf_plus_version_parse(MfPlusVersion* data, const BitBuffer* buf) { - const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion); + bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfPlusVersion); if(can_parse) { bit_buffer_write_bytes(buf, data, sizeof(MfPlusVersion)); + } else if( + bit_buffer_get_size_bytes(buf) == 8 && + bit_buffer_get_byte(buf, 0) == MF_PLUS_STATUS_ADDITIONAL_FRAME) { + // HACK(-nofl): There are supposed to be three parts to the GetVersion command, + // with the second and third parts fetched by sending the AdditionalFrame + // command. I don't know whether the entire MIFARE Plus line uses status as + // the first byte, so let's just assume we only have the first part of + // the response if it's size 8 and starts with the AF status. The second + // part of the response is the same size and status byte, but so far + // we're only reading one response. + can_parse = true; + bit_buffer_write_bytes_mid(buf, data, 1, bit_buffer_get_size_bytes(buf) - 1); } return can_parse ? MfPlusErrorNone : MfPlusErrorProtocol; diff --git a/lib/nfc/protocols/mf_plus/mf_plus_i.h b/lib/nfc/protocols/mf_plus/mf_plus_i.h index 1b80030f9..302f5a178 100644 --- a/lib/nfc/protocols/mf_plus/mf_plus_i.h +++ b/lib/nfc/protocols/mf_plus/mf_plus_i.h @@ -4,6 +4,9 @@ #define MF_PLUS_FFF_PICC_PREFIX "PICC" +#define MF_PLUS_STATUS_OPERATION_OK (0x90) +#define MF_PLUS_STATUS_ADDITIONAL_FRAME (0xAF) + MfPlusError mf_plus_get_type_from_version( const Iso14443_4aData* iso14443_4a_data, MfPlusData* mf_plus_data); From 7291e6bd46c564400cdd3e9e7434f2c6e3a5ff28 Mon Sep 17 00:00:00 2001 From: NotLukas <126127787+NotLukas001@users.noreply.github.com> Date: Sun, 12 Jan 2025 14:12:59 -0500 Subject: [PATCH 47/59] Rename FuriHalDebuging.md to FuriHalDebugging.md (#4047) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed Typo Co-authored-by: あく --- documentation/{FuriHalDebuging.md => FuriHalDebugging.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{FuriHalDebuging.md => FuriHalDebugging.md} (100%) diff --git a/documentation/FuriHalDebuging.md b/documentation/FuriHalDebugging.md similarity index 100% rename from documentation/FuriHalDebuging.md rename to documentation/FuriHalDebugging.md From c73495767cc3e11e8d0dc6a8a5fdb5d8197ad638 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 14 Jan 2025 02:01:54 +0700 Subject: [PATCH 48/59] Auto_poweroff option moved from desktop to power. Add settings for power service (load|save). --- applications/services/desktop/desktop.c | 63 +------ applications/services/desktop/desktop_i.h | 3 - .../services/desktop/desktop_settings.c | 31 ++- .../services/desktop/desktop_settings.h | 3 - .../services/desktop/views/desktop_events.h | 1 - .../services/power/power_service/power.c | 178 ++++++++++++++++++ .../services/power/power_service/power.h | 8 +- .../services/power/power_service/power_i.h | 10 + .../power/power_service/power_settings.c | 75 ++++++++ .../power/power_service/power_settings.h | 16 ++ .../power_service/power_settings_filename.h | 3 + .../scenes/desktop_settings_scene_start.c | 35 ---- .../power_settings_app/power_settings_app.c | 13 ++ .../power_settings_app/power_settings_app.h | 5 + .../scenes/power_settings_scene_start.c | 69 ++++--- targets/f7/api_symbols.csv | 8 +- 16 files changed, 375 insertions(+), 146 deletions(-) create mode 100644 applications/services/power/power_service/power_settings.c create mode 100644 applications/services/power/power_service/power_settings.h create mode 100644 applications/services/power/power_service/power_settings_filename.h diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 59c5290f4..66c4ca174 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -19,12 +19,6 @@ static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); static void desktop_apply_settings(Desktop*); -//--- auto_power_off_timer -#include -static void desktop_start_auto_poweroff_timer(Desktop*); -static void desktop_auto_poweroff_arm(Desktop*); -static void desktop_auto_poweroff_inhibit(Desktop*); -//--- static void desktop_loader_callback(const void* message, void* context) { furi_assert(context); @@ -137,9 +131,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { } desktop_auto_lock_inhibit(desktop); - //--- auto_power_off_timer - desktop_auto_poweroff_inhibit(desktop); - //-- + desktop->app_running = true; furi_semaphore_release(desktop->animation_semaphore); @@ -147,20 +139,12 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { } else if(event == DesktopGlobalAfterAppFinished) { animation_manager_load_and_continue_animation(desktop->animation_manager); desktop_auto_lock_arm(desktop); - //--- auto_power_off_timer - desktop_auto_poweroff_arm(desktop); - //--- desktop->app_running = false; } else if(event == DesktopGlobalAutoLock) { if(!desktop->app_running && !desktop->locked) { desktop_lock(desktop); } - } else if(event == DesktopGlobalAutoPowerOff) { - if(!desktop->app_running) { - Power* power = furi_record_open(RECORD_POWER); - power_off(power); - } } else if(event == DesktopGlobalSaveSettings) { desktop_settings_save(&desktop->settings); desktop_apply_settings(desktop); @@ -195,9 +179,6 @@ static void desktop_input_event_callback(const void* value, void* context) { Desktop* desktop = context; if(event->type == InputTypePress) { desktop_start_auto_lock_timer(desktop); - //--- auto_power_off_timer - desktop_start_auto_poweroff_timer(desktop); - //--- } } @@ -234,41 +215,6 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { } } -//--- auto_power_off_timer -static void desktop_auto_poweroff_timer_callback(void* context) { - furi_assert(context); - Desktop* desktop = context; - view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAutoPowerOff); -} - -static void desktop_start_auto_poweroff_timer(Desktop* desktop) { - furi_timer_start( - desktop->auto_poweroff_timer, furi_ms_to_ticks(desktop->settings.auto_poweroff_delay_ms)); -} - -static void desktop_stop_auto_poweroff_timer(Desktop* desktop) { - furi_timer_stop(desktop->auto_poweroff_timer); -} - -static void desktop_auto_poweroff_arm(Desktop* desktop) { - if(desktop->settings.auto_poweroff_delay_ms) { - if(!desktop->input_events_subscription) { - desktop->input_events_subscription = furi_pubsub_subscribe( - desktop->input_events_pubsub, desktop_input_event_callback, desktop); - } - desktop_start_auto_poweroff_timer(desktop); - } -} - -static void desktop_auto_poweroff_inhibit(Desktop* desktop) { - desktop_stop_auto_poweroff_timer(desktop); - if(desktop->input_events_subscription) { - furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription); - desktop->input_events_subscription = NULL; - } -} -//--- - static void desktop_clock_timer_callback(void* context) { furi_assert(context); Desktop* desktop = context; @@ -294,9 +240,6 @@ static void desktop_apply_settings(Desktop* desktop) { if(!desktop->app_running && !desktop->locked) { desktop_auto_lock_arm(desktop); - //--- auto_power_off_timer - desktop_auto_poweroff_arm(desktop); - //--- } desktop->in_transition = false; @@ -432,10 +375,6 @@ static Desktop* desktop_alloc(void) { desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); - //--- auto_power_off_timer - desktop->auto_poweroff_timer = - furi_timer_alloc(desktop_auto_poweroff_timer_callback, FuriTimerTypeOnce, desktop); - //--- desktop->status_pubsub = furi_pubsub_alloc(); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index abf5cd579..1dc7c7d21 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -75,9 +75,6 @@ struct Desktop { FuriTimer* auto_lock_timer; FuriTimer* update_clock_timer; - //--- auto_power_off_timer - FuriTimer* auto_poweroff_timer; - //--- AnimationManager* animation_manager; FuriSemaphore* animation_semaphore; diff --git a/applications/services/desktop/desktop_settings.c b/applications/services/desktop/desktop_settings.c index 7a99dd365..43b5cf412 100644 --- a/applications/services/desktop/desktop_settings.c +++ b/applications/services/desktop/desktop_settings.c @@ -6,8 +6,8 @@ #define TAG "DesktopSettings" -#define DESKTOP_SETTINGS_VER_14 (14) -#define DESKTOP_SETTINGS_VER (15) +#define DESKTOP_SETTINGS_VER_15 (15) +#define DESKTOP_SETTINGS_VER (16) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) @@ -19,7 +19,7 @@ typedef struct { uint8_t display_clock; FavoriteApp favorite_apps[FavoriteAppNumber]; FavoriteApp dummy_apps[DummyAppNumber]; -} DesktopSettingsV14; +} DesktopSettingsV15; // Actual size of DesktopSettings v13 //static_assert(sizeof(DesktopSettingsV13) == 1234); @@ -41,31 +41,30 @@ void desktop_settings_load(DesktopSettings* settings) { DESKTOP_SETTINGS_MAGIC, DESKTOP_SETTINGS_VER); - } else if(version == DESKTOP_SETTINGS_VER_14) { - DesktopSettingsV14* settings_v14 = malloc(sizeof(DesktopSettingsV14)); + } else if(version == DESKTOP_SETTINGS_VER_15) { + DesktopSettingsV15* settings_v15 = malloc(sizeof(DesktopSettingsV15)); success = saved_struct_load( DESKTOP_SETTINGS_PATH, - settings_v14, - sizeof(DesktopSettingsV14), + settings_v15, + sizeof(DesktopSettingsV15), DESKTOP_SETTINGS_MAGIC, - DESKTOP_SETTINGS_VER_14); + DESKTOP_SETTINGS_VER_15); if(success) { - settings->auto_lock_delay_ms = settings_v14->auto_lock_delay_ms; - settings->auto_poweroff_delay_ms = 0; - settings->displayBatteryPercentage = settings_v14->displayBatteryPercentage; - settings->dummy_mode = settings_v14->dummy_mode; - settings->display_clock = settings_v14->display_clock; + settings->auto_lock_delay_ms = settings_v15->auto_lock_delay_ms; + settings->displayBatteryPercentage = settings_v15->displayBatteryPercentage; + settings->dummy_mode = settings_v15->dummy_mode; + settings->display_clock = settings_v15->display_clock; memcpy( settings->favorite_apps, - settings_v14->favorite_apps, + settings_v15->favorite_apps, sizeof(settings->favorite_apps)); memcpy( - settings->dummy_apps, settings_v14->dummy_apps, sizeof(settings->dummy_apps)); + settings->dummy_apps, settings_v15->dummy_apps, sizeof(settings->dummy_apps)); } - free(settings_v14); + free(settings_v15); } } while(false); diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index e2e91d2dd..ba5a78840 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -38,9 +38,6 @@ typedef struct { typedef struct { uint32_t auto_lock_delay_ms; - //--- auto_power_off_timer - uint32_t auto_poweroff_delay_ms; - //--- uint8_t displayBatteryPercentage; uint8_t dummy_mode; uint8_t display_clock; diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index 57cc0fdaa..ba91a30cc 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -62,5 +62,4 @@ typedef enum { DesktopGlobalApiUnlock, DesktopGlobalSaveSettings, DesktopGlobalReloadSettings, - DesktopGlobalAutoPowerOff, } DesktopEvent; diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 8d387612a..dea911834 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -7,6 +7,8 @@ #include #include +#include + #define TAG "Power" #define POWER_OFF_TIMEOUT_S (90U) @@ -379,7 +381,120 @@ static void power_handle_reboot(PowerBootMode mode) { furi_hal_power_reset(); } +// get settings from service to settings_app by send message to power queue +void power_api_get_settings(Power* power, PowerSettings* settings) { + furi_assert(power); + furi_assert(settings); + PowerMessage msg = { + .type = PowerMessageTypeGetSettings, + .settings = settings, + .lock = api_lock_alloc_locked(), + }; + + furi_check( + furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk); + api_lock_wait_unlock_and_free(msg.lock); +} + +// set settings from settings_app to service by send message to power queue +void power_api_set_settings(Power* power, const PowerSettings* settings) { + furi_assert(power); + furi_assert(settings); + + PowerMessage msg = { + .type = PowerMessageTypeSetSettings, + .csettings = settings, + .lock = api_lock_alloc_locked(), + }; + + furi_check( + furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk); + api_lock_wait_unlock_and_free(msg.lock); +} + +//start furi timer for autopoweroff +static void power_start_auto_poweroff_timer(Power* power) { + furi_timer_start( + power->p_auto_poweroff_timer, furi_ms_to_ticks(power->settings.p_auto_poweroff_delay_ms)); +} + +//stop furi timer for autopoweroff +static void power_stop_auto_poweroff_timer(Power* power) { + furi_timer_stop(power->p_auto_poweroff_timer); +} + +static uint32_t power_is_running_auto_poweroff_timer(Power* power) { + return furi_timer_is_running(power->p_auto_poweroff_timer); +} + +// start|restart poweroff timer +static void power_auto_poweroff_callback(const void* value, void* context) { + furi_assert(value); + furi_assert(context); + Power* power = context; + power_start_auto_poweroff_timer(power); +} + +// callback for poweroff timer (what we do when timer end) +static void power_auto_poweroff_timer_callback(void* context) { + furi_assert(context); + Power* power = context; + power_off(power); +} + +//start|restart timer and events subscription and callbacks for input events (we restart timer when user press keys) +static void power_auto_poweroff_arm(Power* power) { + if(power->settings.p_auto_poweroff_delay_ms) { + if(power->input_events_subscription == NULL) { + power->input_events_subscription = furi_pubsub_subscribe( + power->input_events_pubsub, power_auto_poweroff_callback, power); + } + power_start_auto_poweroff_timer(power); + } +} + +// stop timer and event subscription +static void power_auto_poweroff_disarm(Power* power) { + power_stop_auto_poweroff_timer(power); + if(power->input_events_subscription) { + furi_pubsub_unsubscribe(power->input_events_pubsub, power->input_events_subscription); + power->input_events_subscription = NULL; + } +} + +//check message queue from Loader - is some app started or not (if started we dont do auto poweroff) +static void power_loader_callback(const void* message, void* context) { + furi_assert(context); + Power* power = context; + const LoaderEvent* event = message; + + // disarm timer if some apps started + if(event->type == LoaderEventTypeApplicationBeforeLoad) { + power->app_running = true; + power_auto_poweroff_disarm(power); + // arm timer if some apps was not loaded or was stoped + } else if( + event->type == LoaderEventTypeApplicationLoadFailed || + event->type == LoaderEventTypeApplicationStopped) { + power->app_running = false; + power_auto_poweroff_arm(power); + } +} + +// apply power settings +static void power_settings_apply(Power* power) { + //apply auto_poweroff settings + if(power->settings.p_auto_poweroff_delay_ms && !power->app_running) { + return; + power_auto_poweroff_arm(power); + } else if (power_is_running_auto_poweroff_timer(power)) { + power_auto_poweroff_disarm(power); + } + return; +} + +// do something depend from power queue message static void power_message_callback(FuriEventLoopObject* object, void* context) { furi_assert(context); Power* power = context; @@ -405,6 +520,20 @@ static void power_message_callback(FuriEventLoopObject* object, void* context) { case PowerMessageTypeShowBatteryLowWarning: power->show_battery_low_warning = *msg.bool_param; break; + case PowerMessageTypeGetSettings: + furi_assert(msg.lock); + *msg.settings = power->settings; + break; + case PowerMessageTypeSetSettings: + furi_assert(msg.lock); + power->settings = *msg.csettings; + power_settings_apply(power); + power_settings_save(&power->settings); + break; + case PowerMessageTypeReloadSettings: + power_settings_load(&power->settings); + power_settings_apply(power); + break; default: furi_crash(); } @@ -436,6 +565,36 @@ static void power_tick_callback(void* context) { } } +static void power_storage_callback(const void* message, void* context) { + furi_assert(context); + Power* power = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + PowerMessage msg = { + .type = PowerMessageTypeReloadSettings, + }; + + furi_check( + furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk); + } +} + +// load inital settings from file for power service +static void power_init_settings(Power* power) { + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), power_storage_callback, power); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + return; + } + + power_settings_load(&power->settings); + power_settings_apply(power); + furi_record_close(RECORD_STORAGE); +} + static Power* power_alloc(void) { Power* power = malloc(sizeof(Power)); // Pubsub @@ -449,6 +608,16 @@ static Power* power_alloc(void) { desktop_settings_load(settings); power->displayBatteryPercentage = settings->displayBatteryPercentage; free(settings); + + // auto_poweroff + //---define subscription to loader events message (info about started apps) and defina callback for this + Loader* loader = furi_record_open(RECORD_LOADER); + furi_pubsub_subscribe(loader_get_pubsub(loader), power_loader_callback, power); + power->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS); + //define autopoweroff timer and they callback + power->p_auto_poweroff_timer = + furi_timer_alloc(power_auto_poweroff_timer_callback, FuriTimerTypeOnce, power); + // Gui Gui* gui = furi_record_open(RECORD_GUI); @@ -489,6 +658,15 @@ int32_t power_srv(void* p) { power_update_info(power); furi_record_create(RECORD_POWER, power); + +// Can't be done in alloc, other things in startup need power service and it would deadlock by waiting for loader + Loader* loader = furi_record_open(RECORD_LOADER); + power->app_running = loader_is_locked(loader); + furi_record_close(RECORD_LOADER); + + // load inital settings for power service + power_init_settings(power); + furi_event_loop_run(power->event_loop); return 0; diff --git a/applications/services/power/power_service/power.h b/applications/services/power/power_service/power.h index 34d58353a..59947fa52 100644 --- a/applications/services/power/power_service/power.h +++ b/applications/services/power/power_service/power.h @@ -2,7 +2,7 @@ #include #include - +#include #include #ifdef __cplusplus @@ -102,6 +102,12 @@ void power_enable_low_battery_level_notification(Power* power, bool enable); */ void power_trigger_ui_update(Power* power); +// get settings from service to app +void power_api_get_settings(Power* instance, PowerSettings* settings); + +// set settings from app to service +void power_api_set_settings(Power* instance, const PowerSettings* settings); + #ifdef __cplusplus } #endif diff --git a/applications/services/power/power_service/power_i.h b/applications/services/power/power_service/power_i.h index d75071f8f..1bb0fc3e8 100644 --- a/applications/services/power/power_service/power_i.h +++ b/applications/services/power/power_service/power_i.h @@ -36,6 +36,11 @@ struct Power { uint8_t displayBatteryPercentage; uint8_t battery_level; uint8_t power_off_timeout; + PowerSettings settings; + FuriTimer* p_auto_poweroff_timer; + bool app_running; + FuriPubSub* input_events_pubsub; + FuriPubSubSubscription* input_events_subscription; }; typedef enum { @@ -49,6 +54,9 @@ typedef enum { PowerMessageTypeGetInfo, PowerMessageTypeIsBatteryHealthy, PowerMessageTypeShowBatteryLowWarning, + PowerMessageTypeGetSettings, + PowerMessageTypeSetSettings, + PowerMessageTypeReloadSettings, } PowerMessageType; typedef struct { @@ -57,6 +65,8 @@ typedef struct { PowerBootMode boot_mode; PowerInfo* power_info; bool* bool_param; + PowerSettings* settings; + const PowerSettings* csettings; }; FuriApiLock lock; } PowerMessage; diff --git a/applications/services/power/power_service/power_settings.c b/applications/services/power/power_service/power_settings.c new file mode 100644 index 000000000..0cc18569b --- /dev/null +++ b/applications/services/power/power_service/power_settings.c @@ -0,0 +1,75 @@ +#include "power_settings.h" +#include "power_settings_filename.h" + +#include +#include + +#define TAG "PowerSettings" + +#define POWER_SETTINGS_VER_0 (0) // OLD version number +#define POWER_SETTINGS_VER (1) // NEW actual version nnumber + +#define POWER_SETTINGS_PATH INT_PATH(POWER_SETTINGS_FILE_NAME) +#define POWER_SETTINGS_MAGIC (0x18) + +typedef struct { +//inital set - empty +} PowerSettingsV0; + +void power_settings_load(PowerSettings* settings) { + furi_assert(settings); + + bool success = false; + + do { + uint8_t version; + if(!saved_struct_get_metadata(POWER_SETTINGS_PATH, NULL, &version, NULL)) break; + + if(version == POWER_SETTINGS_VER) { // if config actual version - load it directly + success = saved_struct_load( + POWER_SETTINGS_PATH, + settings, + sizeof(PowerSettings), + POWER_SETTINGS_MAGIC, + POWER_SETTINGS_VER); + + } else if(version == POWER_SETTINGS_VER_0) { // if config previous version - load it and manual set new settings to inital value + PowerSettingsV0* settings_v0 = malloc(sizeof(PowerSettingsV0)); + + success = saved_struct_load( + POWER_SETTINGS_PATH, + settings_v0, + sizeof(PowerSettingsV0), + POWER_SETTINGS_MAGIC, + POWER_SETTINGS_VER_0); + + if(success) { + settings->p_auto_poweroff_delay_ms = 0; + } + + free(settings_v0); + } + + } while(false); + + if(!success) { + FURI_LOG_W(TAG, "Failed to load file, using defaults"); + memset(settings, 0, sizeof(PowerSettings)); + power_settings_save(settings); + } +} + +void power_settings_save(const PowerSettings* settings) { + furi_assert(settings); + + const bool success = saved_struct_save( + POWER_SETTINGS_PATH, + settings, + sizeof(PowerSettings), + POWER_SETTINGS_MAGIC, + POWER_SETTINGS_VER); + + if(!success) { + FURI_LOG_E(TAG, "Failed to save file"); + } +} diff --git a/applications/services/power/power_service/power_settings.h b/applications/services/power/power_service/power_settings.h new file mode 100644 index 000000000..58c38ab3a --- /dev/null +++ b/applications/services/power/power_service/power_settings.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +typedef struct { + uint32_t p_auto_poweroff_delay_ms; +} PowerSettings; + +#ifdef __cplusplus +extern "C" { +#endif +void power_settings_load(PowerSettings* settings); +void power_settings_save(const PowerSettings* settings); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/services/power/power_service/power_settings_filename.h b/applications/services/power/power_service/power_settings_filename.h new file mode 100644 index 000000000..e8c6fbfce --- /dev/null +++ b/applications/services/power/power_service/power_settings_filename.h @@ -0,0 +1,3 @@ +#pragma once + +#define POWER_SETTINGS_FILE_NAME ".power.settings" diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index f674380af..a9aa4145c 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -29,15 +29,6 @@ typedef enum { DesktopSettingsDummyOkLong, } DesktopSettingsEntry; -// --- auto_power_off_timer -#define AUTO_POWEROFF_DELAY_COUNT 8 -const char* const auto_poweroff_delay_text[AUTO_POWEROFF_DELAY_COUNT] = - {"OFF", "5min", "10min", "15min", "30min", "45min", "60min", "90min"}; - -const uint32_t auto_poweroff_delay_value[AUTO_POWEROFF_DELAY_COUNT] = - {0, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; -// --- - #define AUTO_LOCK_DELAY_COUNT 9 const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { "OFF", @@ -96,16 +87,6 @@ static void desktop_settings_scene_start_clock_enable_changed(VariableItem* item app->settings.display_clock = index; } -// --- auto_power_off_timer -static void desktop_settings_scene_start_auto_poweroff_delay_changed(VariableItem* item) { - DesktopSettingsApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - variable_item_set_current_value_text(item, auto_poweroff_delay_text[index]); - app->settings.auto_poweroff_delay_ms = auto_poweroff_delay_value[index]; -} -// --- - static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) { DesktopSettingsApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -135,22 +116,6 @@ void desktop_settings_scene_start_on_enter(void* context) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]); - // --- auto_power_off_timer - item = variable_item_list_add( - variable_item_list, - "Auto PowerOff", - AUTO_POWEROFF_DELAY_COUNT, - desktop_settings_scene_start_auto_poweroff_delay_changed, - app); - - value_index = value_index_uint32( - app->settings.auto_poweroff_delay_ms, - auto_poweroff_delay_value, - AUTO_POWEROFF_DELAY_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, auto_poweroff_delay_text[value_index]); - // --- - item = variable_item_list_add( variable_item_list, "Battery View", diff --git a/applications/settings/power_settings_app/power_settings_app.c b/applications/settings/power_settings_app/power_settings_app.c index 57df1344f..8fa824252 100644 --- a/applications/settings/power_settings_app/power_settings_app.c +++ b/applications/settings/power_settings_app/power_settings_app.c @@ -46,10 +46,16 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) { app->submenu = submenu_alloc(); view_dispatcher_add_view( app->view_dispatcher, PowerSettingsAppViewSubmenu, submenu_get_view(app->submenu)); + app->variable_item_list = variable_item_list_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, PowerSettingsAppViewVariableItemList, variable_item_list_get_view(app->variable_item_list)); app->dialog = dialog_ex_alloc(); view_dispatcher_add_view( app->view_dispatcher, PowerSettingsAppViewDialog, dialog_ex_get_view(app->dialog)); + // get settings from service to app + power_api_get_settings(app->power, &app->settings); + // Set first scene scene_manager_next_scene(app->scene_manager, first_scene); return app; @@ -57,16 +63,23 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) { void power_settings_app_free(PowerSettingsApp* app) { furi_assert(app); + + // set settings from app to service + power_api_set_settings(app->power, &app->settings); // Views view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo); battery_info_free(app->battery_info); view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewSubmenu); submenu_free(app->submenu); + view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewVariableItemList); + variable_item_list_free(app->variable_item_list); view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewDialog); dialog_ex_free(app->dialog); + // View dispatcher view_dispatcher_free(app->view_dispatcher); scene_manager_free(app->scene_manager); + // Records furi_record_close(RECORD_POWER); furi_record_close(RECORD_GUI); diff --git a/applications/settings/power_settings_app/power_settings_app.h b/applications/settings/power_settings_app/power_settings_app.h index bbbbacd61..f28e6a548 100644 --- a/applications/settings/power_settings_app/power_settings_app.h +++ b/applications/settings/power_settings_app/power_settings_app.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -10,11 +11,13 @@ #include "views/battery_info.h" #include +#include #include #include "scenes/power_settings_scene.h" typedef struct { + PowerSettings settings; Power* power; Gui* gui; SceneManager* scene_manager; @@ -23,12 +26,14 @@ typedef struct { Submenu* submenu; DialogEx* dialog; PowerInfo info; + VariableItemList* variable_item_list; } PowerSettingsApp; typedef enum { PowerSettingsAppViewBatteryInfo, PowerSettingsAppViewSubmenu, PowerSettingsAppViewDialog, + PowerSettingsAppViewVariableItemList } PowerSettingsAppView; typedef enum { diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c index 63f123d89..6d79ba0af 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c @@ -1,12 +1,30 @@ #include "../power_settings_app.h" +#include enum PowerSettingsSubmenuIndex { + PowerSettingsSubmenuIndexAutoPowerOff, PowerSettingsSubmenuIndexBatteryInfo, PowerSettingsSubmenuIndexReboot, PowerSettingsSubmenuIndexOff, }; -static void power_settings_scene_start_submenu_callback(void* context, uint32_t index) { +#define P_AUTO_POWEROFF_DELAY_COUNT 9 +const char* const p_auto_poweroff_delay_text[P_AUTO_POWEROFF_DELAY_COUNT] = + {"OFF","5 sec" ,"5min", "10min", "15min", "30min", "45min", "60min", "90min"}; + +const uint32_t p_auto_poweroff_delay_value[P_AUTO_POWEROFF_DELAY_COUNT] = + {0, 5000, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; + +// change variable_item_list visible text and app_poweroff_delay_time_settings when user change item in variable_item_list +static void power_settings_scene_start_auto_poweroff_delay_changed(VariableItem* item) { + PowerSettingsApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, p_auto_poweroff_delay_text[index]); + app->settings.p_auto_poweroff_delay_ms = p_auto_poweroff_delay_value[index]; +} + +static void power_settings_scene_start_submenu_callback(void* context, uint32_t index) { //show selected menu screen furi_assert(context); PowerSettingsApp* app = context; view_dispatcher_send_custom_event(app->view_dispatcher, index); @@ -14,30 +32,34 @@ static void power_settings_scene_start_submenu_callback(void* context, uint32_t void power_settings_scene_start_on_enter(void* context) { PowerSettingsApp* app = context; - Submenu* submenu = app->submenu; + VariableItemList* variable_item_list = app->variable_item_list; - submenu_add_item( - submenu, - "Battery Info", - PowerSettingsSubmenuIndexBatteryInfo, - power_settings_scene_start_submenu_callback, + VariableItem* item; + uint8_t value_index; + item = variable_item_list_add( + variable_item_list, + "Auto PowerOff Time", + P_AUTO_POWEROFF_DELAY_COUNT, + power_settings_scene_start_auto_poweroff_delay_changed, //function for change visible item list value and app settings app); - submenu_add_item( - submenu, - "Reboot", - PowerSettingsSubmenuIndexReboot, - power_settings_scene_start_submenu_callback, - app); - submenu_add_item( - submenu, - "Power OFF", - PowerSettingsSubmenuIndexOff, - power_settings_scene_start_submenu_callback, - app); - submenu_set_selected_item( - submenu, scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart)); - view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewSubmenu); + value_index = value_index_uint32( + app->settings.p_auto_poweroff_delay_ms, + p_auto_poweroff_delay_value, + P_AUTO_POWEROFF_DELAY_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, p_auto_poweroff_delay_text[value_index]); + + variable_item_list_add(variable_item_list, "Battery Info", 1, NULL, NULL); + variable_item_list_add(variable_item_list, "Reboot", 1, NULL, NULL); + variable_item_list_add(variable_item_list, "Power OFF", 1, NULL, NULL); + + variable_item_list_set_selected_item( + variable_item_list, scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart)); + variable_item_list_set_enter_callback( //callback to show next mennu screen + variable_item_list, power_settings_scene_start_submenu_callback, app); + + view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewVariableItemList); } bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event) { @@ -60,5 +82,6 @@ bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event) void power_settings_scene_start_on_exit(void* context) { PowerSettingsApp* app = context; - submenu_reset(app->submenu); + variable_item_list_reset(app->variable_item_list); + power_settings_save(&app->settings); //actual need save every time when use ? } diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 80effa9af..b649f1f99 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,79.2,, +Version,+,79.3,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -2993,9 +2993,9 @@ Function,+,pipe_install_as_stdio,void,PipeSide* Function,+,pipe_receive,size_t,"PipeSide*, void*, size_t, FuriWait" Function,+,pipe_role,PipeRole,PipeSide* Function,+,pipe_send,size_t,"PipeSide*, const void*, size_t, FuriWait" +Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, FuriEventLoopEvent" Function,+,pipe_set_callback_context,void,"PipeSide*, void*" Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent" -Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, FuriEventLoopEvent" Function,+,pipe_set_space_freed_callback,void,"PipeSide*, PipeSideSpaceFreedCallback, FuriEventLoopEvent" Function,+,pipe_spaces_available,size_t,PipeSide* Function,+,pipe_state,PipeState,PipeSide* @@ -3023,12 +3023,16 @@ Function,-,posix_memalign,int,"void**, size_t, size_t" Function,-,pow,double,"double, double" Function,-,pow10,double,double Function,-,pow10f,float,float +Function,+,power_api_get_settings,void,"Power*, PowerSettings*" +Function,+,power_api_set_settings,void,"Power*, const PowerSettings*" Function,+,power_enable_low_battery_level_notification,void,"Power*, _Bool" Function,+,power_get_info,void,"Power*, PowerInfo*" Function,+,power_get_pubsub,FuriPubSub*,Power* Function,+,power_is_battery_healthy,_Bool,Power* Function,+,power_off,void,Power* Function,+,power_reboot,void,"Power*, PowerBootMode" +Function,+,power_settings_load,void,PowerSettings* +Function,+,power_settings_save,void,const PowerSettings* Function,-,power_trigger_ui_update,void,Power* Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" From ec75de032052f20a6798408c38c05a6bb8c482c7 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Tue, 14 Jan 2025 02:08:35 +0700 Subject: [PATCH 49/59] Auto_poweroff_delay correction (removed test delay value) --- .../power_settings_app/scenes/power_settings_scene_start.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c index 6d79ba0af..681247668 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c @@ -8,12 +8,12 @@ enum PowerSettingsSubmenuIndex { PowerSettingsSubmenuIndexOff, }; -#define P_AUTO_POWEROFF_DELAY_COUNT 9 +#define P_AUTO_POWEROFF_DELAY_COUNT 8 const char* const p_auto_poweroff_delay_text[P_AUTO_POWEROFF_DELAY_COUNT] = - {"OFF","5 sec" ,"5min", "10min", "15min", "30min", "45min", "60min", "90min"}; + {"OFF","5min", "10min", "15min", "30min", "45min", "60min", "90min"}; const uint32_t p_auto_poweroff_delay_value[P_AUTO_POWEROFF_DELAY_COUNT] = - {0, 5000, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; + {0, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; // change variable_item_list visible text and app_poweroff_delay_time_settings when user change item in variable_item_list static void power_settings_scene_start_auto_poweroff_delay_changed(VariableItem* item) { From cf50875c5cde3501ccf66ab3a36261dce488f476 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 15 Jan 2025 01:33:49 +0700 Subject: [PATCH 50/59] *POWER* - serice: renamed function and variable - settings: add test value 5 sec for auto_power_off timer *DESKTOP* - settings|service add USB_inhibit for desktop_auto_lock (dont autolock desktop with different condition) PS. RPC condition now working now. --- applications/services/desktop/desktop.c | 15 +++++++ .../services/desktop/desktop_settings.c | 2 + .../services/desktop/desktop_settings.h | 1 + .../services/power/power_service/power.c | 21 ++++++---- .../services/power/power_service/power_i.h | 2 +- .../power/power_service/power_settings.c | 2 +- .../power/power_service/power_settings.h | 2 +- .../scenes/desktop_settings_scene_start.c | 39 +++++++++++++++++++ .../scenes/power_settings_scene_start.c | 24 ++++++------ 9 files changed, 86 insertions(+), 22 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 66c4ca174..43356cf25 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -13,8 +13,15 @@ #include "scenes/desktop_scene.h" #include "scenes/desktop_scene_locked.h" +#include "furi_hal_power.h" + #define TAG "Desktop" +// dublicate constants from desktop_setting_scene_start.c +#define USB_INHIBIT_AUTOLOCK_OFF 0 +#define USB_INHIBIT_AUTOLOCK_ON 1 +#define USB_INHIBIT_AUTOLOCK_RPC 2 + static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); @@ -143,6 +150,14 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { } else if(event == DesktopGlobalAutoLock) { if(!desktop->app_running && !desktop->locked) { + // if usb_inhibit_autolock enabled and device charging or device charged but still connected to USB then break desktop locking. + if ((desktop->settings.usb_inhibit_auto_lock == USB_INHIBIT_AUTOLOCK_ON) && ((furi_hal_power_is_charging()) || (furi_hal_power_is_charging_done()))){ + return(0); + } + // if usb_inhibit_autolock set to RPC and we have F0 connected to phone or PC app then break desktop locking. + if (desktop->settings.usb_inhibit_auto_lock == USB_INHIBIT_AUTOLOCK_RPC){ + return(0); + } desktop_lock(desktop); } } else if(event == DesktopGlobalSaveSettings) { diff --git a/applications/services/desktop/desktop_settings.c b/applications/services/desktop/desktop_settings.c index 43b5cf412..bf9215dd2 100644 --- a/applications/services/desktop/desktop_settings.c +++ b/applications/services/desktop/desktop_settings.c @@ -14,6 +14,7 @@ typedef struct { uint32_t auto_lock_delay_ms; + uint32_t auto_poweroff_delay_ms; uint8_t displayBatteryPercentage; uint8_t dummy_mode; uint8_t display_clock; @@ -53,6 +54,7 @@ void desktop_settings_load(DesktopSettings* settings) { if(success) { settings->auto_lock_delay_ms = settings_v15->auto_lock_delay_ms; + settings->usb_inhibit_auto_lock = 0; settings->displayBatteryPercentage = settings_v15->displayBatteryPercentage; settings->dummy_mode = settings_v15->dummy_mode; settings->display_clock = settings_v15->display_clock; diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index ba5a78840..784b1eeba 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -38,6 +38,7 @@ typedef struct { typedef struct { uint32_t auto_lock_delay_ms; + uint8_t usb_inhibit_auto_lock; uint8_t displayBatteryPercentage; uint8_t dummy_mode; uint8_t display_clock; diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index dea911834..1814dbd4a 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -416,16 +416,16 @@ void power_api_set_settings(Power* power, const PowerSettings* settings) { //start furi timer for autopoweroff static void power_start_auto_poweroff_timer(Power* power) { furi_timer_start( - power->p_auto_poweroff_timer, furi_ms_to_ticks(power->settings.p_auto_poweroff_delay_ms)); + power->auto_poweroff_timer, furi_ms_to_ticks(power->settings.auto_poweroff_delay_ms)); } //stop furi timer for autopoweroff static void power_stop_auto_poweroff_timer(Power* power) { - furi_timer_stop(power->p_auto_poweroff_timer); + furi_timer_stop(power->auto_poweroff_timer); } static uint32_t power_is_running_auto_poweroff_timer(Power* power) { - return furi_timer_is_running(power->p_auto_poweroff_timer); + return furi_timer_is_running(power->auto_poweroff_timer); } // start|restart poweroff timer @@ -440,12 +440,19 @@ static void power_auto_poweroff_callback(const void* value, void* context) { static void power_auto_poweroff_timer_callback(void* context) { furi_assert(context); Power* power = context; - power_off(power); + //check charging state and dont poweroff if battery not fully charged + power_check_charging_state(power); + if (power->state == PowerStateCharged) { + power_off(power); + } + else { + FURI_LOG_D(TAG, "We dont auto_power_off until battery is charging"); + } } //start|restart timer and events subscription and callbacks for input events (we restart timer when user press keys) static void power_auto_poweroff_arm(Power* power) { - if(power->settings.p_auto_poweroff_delay_ms) { + if(power->settings.auto_poweroff_delay_ms) { if(power->input_events_subscription == NULL) { power->input_events_subscription = furi_pubsub_subscribe( power->input_events_pubsub, power_auto_poweroff_callback, power); @@ -485,7 +492,7 @@ static void power_loader_callback(const void* message, void* context) { // apply power settings static void power_settings_apply(Power* power) { //apply auto_poweroff settings - if(power->settings.p_auto_poweroff_delay_ms && !power->app_running) { + if(power->settings.auto_poweroff_delay_ms && !power->app_running) { return; power_auto_poweroff_arm(power); } else if (power_is_running_auto_poweroff_timer(power)) { @@ -615,7 +622,7 @@ static Power* power_alloc(void) { furi_pubsub_subscribe(loader_get_pubsub(loader), power_loader_callback, power); power->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS); //define autopoweroff timer and they callback - power->p_auto_poweroff_timer = + power->auto_poweroff_timer = furi_timer_alloc(power_auto_poweroff_timer_callback, FuriTimerTypeOnce, power); // Gui diff --git a/applications/services/power/power_service/power_i.h b/applications/services/power/power_service/power_i.h index 1bb0fc3e8..40b4a1ef4 100644 --- a/applications/services/power/power_service/power_i.h +++ b/applications/services/power/power_service/power_i.h @@ -37,7 +37,7 @@ struct Power { uint8_t battery_level; uint8_t power_off_timeout; PowerSettings settings; - FuriTimer* p_auto_poweroff_timer; + FuriTimer* auto_poweroff_timer; bool app_running; FuriPubSub* input_events_pubsub; FuriPubSubSubscription* input_events_subscription; diff --git a/applications/services/power/power_service/power_settings.c b/applications/services/power/power_service/power_settings.c index 0cc18569b..9682a65e0 100644 --- a/applications/services/power/power_service/power_settings.c +++ b/applications/services/power/power_service/power_settings.c @@ -44,7 +44,7 @@ void power_settings_load(PowerSettings* settings) { POWER_SETTINGS_VER_0); if(success) { - settings->p_auto_poweroff_delay_ms = 0; + settings->auto_poweroff_delay_ms = 0; } free(settings_v0); diff --git a/applications/services/power/power_service/power_settings.h b/applications/services/power/power_service/power_settings.h index 58c38ab3a..038531752 100644 --- a/applications/services/power/power_service/power_settings.h +++ b/applications/services/power/power_service/power_settings.h @@ -3,7 +3,7 @@ #include typedef struct { - uint32_t p_auto_poweroff_delay_ms; + uint32_t auto_poweroff_delay_ms; } PowerSettings; #ifdef __cplusplus diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index a9aa4145c..dee9d40be 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -45,6 +45,23 @@ const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] = {0, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000}; +#define USB_INHIBIT_AUTO_LOCK_DELAY_COUNT 3 +#define USB_INHIBIT_AUTOLOCK_OFF 0 +#define USB_INHIBIT_AUTOLOCK_ON 1 +#define USB_INHIBIT_AUTOLOCK_RPC 2 + +const char* const usb_inhibit_auto_lock_delay_text[USB_INHIBIT_AUTO_LOCK_DELAY_COUNT] = { + "OFF", + "ON", + "RPC", +}; + +const uint32_t usb_inhibit_auto_lock_delay_value[USB_INHIBIT_AUTO_LOCK_DELAY_COUNT] = { + USB_INHIBIT_AUTOLOCK_OFF, + USB_INHIBIT_AUTOLOCK_ON, + USB_INHIBIT_AUTOLOCK_RPC, +}; + #define CLOCK_ENABLE_COUNT 2 const char* const clock_enable_text[CLOCK_ENABLE_COUNT] = { "OFF", @@ -87,6 +104,7 @@ static void desktop_settings_scene_start_clock_enable_changed(VariableItem* item app->settings.display_clock = index; } + static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) { DesktopSettingsApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -95,6 +113,14 @@ static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* i app->settings.auto_lock_delay_ms = auto_lock_delay_value[index]; } +static void desktop_settings_scene_start_usb_inhibit_auto_lock_delay_changed(VariableItem* item) { + DesktopSettingsApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, usb_inhibit_auto_lock_delay_text[index]); + app->settings.usb_inhibit_auto_lock = usb_inhibit_auto_lock_delay_value[index]; +} + void desktop_settings_scene_start_on_enter(void* context) { DesktopSettingsApp* app = context; VariableItemList* variable_item_list = app->variable_item_list; @@ -116,6 +142,19 @@ void desktop_settings_scene_start_on_enter(void* context) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]); + // USB connection Inhibit autolock OFF|ON|with opened RPC session + item = variable_item_list_add( + variable_item_list, + "USB disarm Auto Lock", + USB_INHIBIT_AUTO_LOCK_DELAY_COUNT, + desktop_settings_scene_start_usb_inhibit_auto_lock_delay_changed, + app); + + value_index = value_index_uint32( + app->settings.usb_inhibit_auto_lock, usb_inhibit_auto_lock_delay_value, USB_INHIBIT_AUTO_LOCK_DELAY_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, usb_inhibit_auto_lock_delay_text[value_index]); + item = variable_item_list_add( variable_item_list, "Battery View", diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c index 681247668..6f9975114 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c @@ -8,20 +8,20 @@ enum PowerSettingsSubmenuIndex { PowerSettingsSubmenuIndexOff, }; -#define P_AUTO_POWEROFF_DELAY_COUNT 8 -const char* const p_auto_poweroff_delay_text[P_AUTO_POWEROFF_DELAY_COUNT] = - {"OFF","5min", "10min", "15min", "30min", "45min", "60min", "90min"}; +#define AUTO_POWEROFF_DELAY_COUNT 9 +const char* const auto_poweroff_delay_text[AUTO_POWEROFF_DELAY_COUNT] = + {"OFF","5 sec","5min", "10min", "15min", "30min", "45min", "60min", "90min"}; -const uint32_t p_auto_poweroff_delay_value[P_AUTO_POWEROFF_DELAY_COUNT] = - {0, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; +const uint32_t auto_poweroff_delay_value[AUTO_POWEROFF_DELAY_COUNT] = + {0, 5000, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; // change variable_item_list visible text and app_poweroff_delay_time_settings when user change item in variable_item_list static void power_settings_scene_start_auto_poweroff_delay_changed(VariableItem* item) { PowerSettingsApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, p_auto_poweroff_delay_text[index]); - app->settings.p_auto_poweroff_delay_ms = p_auto_poweroff_delay_value[index]; + variable_item_set_current_value_text(item, auto_poweroff_delay_text[index]); + app->settings.auto_poweroff_delay_ms = auto_poweroff_delay_value[index]; } static void power_settings_scene_start_submenu_callback(void* context, uint32_t index) { //show selected menu screen @@ -39,16 +39,16 @@ void power_settings_scene_start_on_enter(void* context) { item = variable_item_list_add( variable_item_list, "Auto PowerOff Time", - P_AUTO_POWEROFF_DELAY_COUNT, + AUTO_POWEROFF_DELAY_COUNT, power_settings_scene_start_auto_poweroff_delay_changed, //function for change visible item list value and app settings app); value_index = value_index_uint32( - app->settings.p_auto_poweroff_delay_ms, - p_auto_poweroff_delay_value, - P_AUTO_POWEROFF_DELAY_COUNT); + app->settings.auto_poweroff_delay_ms, + auto_poweroff_delay_value, + AUTO_POWEROFF_DELAY_COUNT); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, p_auto_poweroff_delay_text[value_index]); + variable_item_set_current_value_text(item, auto_poweroff_delay_text[value_index]); variable_item_list_add(variable_item_list, "Battery Info", 1, NULL, NULL); variable_item_list_add(variable_item_list, "Reboot", 1, NULL, NULL); From 1666c4d04fb138e4efc2f2f16e75e0fe306a0868 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 15 Jan 2025 00:42:43 +0300 Subject: [PATCH 51/59] upd settings to see release version only and current --- .../services/desktop/desktop_settings.c | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/applications/services/desktop/desktop_settings.c b/applications/services/desktop/desktop_settings.c index bf9215dd2..f5d0cf896 100644 --- a/applications/services/desktop/desktop_settings.c +++ b/applications/services/desktop/desktop_settings.c @@ -6,7 +6,7 @@ #define TAG "DesktopSettings" -#define DESKTOP_SETTINGS_VER_15 (15) +#define DESKTOP_SETTINGS_VER_14 (14) #define DESKTOP_SETTINGS_VER (16) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) @@ -14,13 +14,12 @@ typedef struct { uint32_t auto_lock_delay_ms; - uint32_t auto_poweroff_delay_ms; uint8_t displayBatteryPercentage; uint8_t dummy_mode; uint8_t display_clock; FavoriteApp favorite_apps[FavoriteAppNumber]; FavoriteApp dummy_apps[DummyAppNumber]; -} DesktopSettingsV15; +} DesktopSettingsV14; // Actual size of DesktopSettings v13 //static_assert(sizeof(DesktopSettingsV13) == 1234); @@ -42,31 +41,31 @@ void desktop_settings_load(DesktopSettings* settings) { DESKTOP_SETTINGS_MAGIC, DESKTOP_SETTINGS_VER); - } else if(version == DESKTOP_SETTINGS_VER_15) { - DesktopSettingsV15* settings_v15 = malloc(sizeof(DesktopSettingsV15)); + } else if(version == DESKTOP_SETTINGS_VER_14) { + DesktopSettingsV14* settings_v14 = malloc(sizeof(DesktopSettingsV14)); success = saved_struct_load( DESKTOP_SETTINGS_PATH, - settings_v15, - sizeof(DesktopSettingsV15), + settings_v14, + sizeof(DesktopSettingsV14), DESKTOP_SETTINGS_MAGIC, - DESKTOP_SETTINGS_VER_15); + DESKTOP_SETTINGS_VER_14); if(success) { - settings->auto_lock_delay_ms = settings_v15->auto_lock_delay_ms; + settings->auto_lock_delay_ms = settings_v14->auto_lock_delay_ms; settings->usb_inhibit_auto_lock = 0; - settings->displayBatteryPercentage = settings_v15->displayBatteryPercentage; - settings->dummy_mode = settings_v15->dummy_mode; - settings->display_clock = settings_v15->display_clock; + settings->displayBatteryPercentage = settings_v14->displayBatteryPercentage; + settings->dummy_mode = settings_v14->dummy_mode; + settings->display_clock = settings_v14->display_clock; memcpy( settings->favorite_apps, - settings_v15->favorite_apps, + settings_v14->favorite_apps, sizeof(settings->favorite_apps)); memcpy( - settings->dummy_apps, settings_v15->dummy_apps, sizeof(settings->dummy_apps)); + settings->dummy_apps, settings_v14->dummy_apps, sizeof(settings->dummy_apps)); } - free(settings_v15); + free(settings_v14); } } while(false); From d09bbd18fad01c969babab18257cd6e2eae7daaf Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 15 Jan 2025 00:53:47 +0300 Subject: [PATCH 52/59] upd changelog --- CHANGELOG.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 245ffe0de..6e7d0aa0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,18 @@ ## Main changes -- Current API: 79.2 +- Current API: 79.3 * SubGHz: Jolly Motors support (with add manually) (Thanks @pkooiman !) -* Desktop: Auto Power Off Timer (by @Dmitry422 with some fixes by @xMasterX) +* Power: Auto Power Off Timer (by @Dmitry422 with some fixes by @xMasterX) * OFW: **Fix lost BadBLE keystrokes** * OFW: **Add the ability to send a signal once via RPC** * OFW PR 4025: Increase system stack's reserved memory size (Fix USB UART Bridge Crash) (by @Astrrra) * OFW: merged gsurkov/vcp_break_support branch for usb uart bridge (WIP!!!) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes -* Desktop: Add input events sub check & use event system for auto power off +* Power & Desktop: Add input events sub check & use event system for auto power off +* OFW: Rename FuriHalDebuging.md to FuriHalDebugging.md +* OFW: nfc: Fix MIFARE Plus detection +* OFW: u2f: Fix leaking message digest contexts +* OFW: nfc: Fix MFUL PWD_AUTH command creation * OFW: Bump cross-spawn in /applications/system/js_app/packages/create-fz-app * OFW: **Pipe** (new api funcs) * OFW: Fix invalid path errors while deploying SDK by enforcing toolchain to use UTF-8 on initial SDK Extraction From 818a47085e7d3504dd68ceffc312cf1153c9b57d Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Wed, 15 Jan 2025 18:37:35 +0700 Subject: [PATCH 53/59] fix errors --- .../services/power/power_service/power.c | 17 +++++++++-------- .../scenes/power_settings_scene_start.c | 18 +++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 1814dbd4a..207764e99 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -440,13 +440,15 @@ static void power_auto_poweroff_callback(const void* value, void* context) { static void power_auto_poweroff_timer_callback(void* context) { furi_assert(context); Power* power = context; - //check charging state and dont poweroff if battery not fully charged - power_check_charging_state(power); - if (power->state == PowerStateCharged) { + + //poweroff if not charging now or if connected to charger and charging done + if (((!furi_hal_power_is_charging())) || (furi_hal_power_is_charging_done())) { power_off(power); } else { + //else we dont poweroff device and restart timer FURI_LOG_D(TAG, "We dont auto_power_off until battery is charging"); + power_start_auto_poweroff_timer(power); } } @@ -493,12 +495,10 @@ static void power_loader_callback(const void* message, void* context) { static void power_settings_apply(Power* power) { //apply auto_poweroff settings if(power->settings.auto_poweroff_delay_ms && !power->app_running) { - return; power_auto_poweroff_arm(power); } else if (power_is_running_auto_poweroff_timer(power)) { power_auto_poweroff_disarm(power); } - return; } // do something depend from power queue message @@ -662,6 +662,10 @@ int32_t power_srv(void* p) { } Power* power = power_alloc(); + + // load inital settings for power service + power_init_settings(power); + power_update_info(power); furi_record_create(RECORD_POWER, power); @@ -671,9 +675,6 @@ int32_t power_srv(void* p) { power->app_running = loader_is_locked(loader); furi_record_close(RECORD_LOADER); - // load inital settings for power service - power_init_settings(power); - furi_event_loop_run(power->event_loop); return 0; diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c index 6f9975114..9a12d65aa 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c @@ -2,18 +2,18 @@ #include enum PowerSettingsSubmenuIndex { - PowerSettingsSubmenuIndexAutoPowerOff, PowerSettingsSubmenuIndexBatteryInfo, PowerSettingsSubmenuIndexReboot, PowerSettingsSubmenuIndexOff, + PowerSettingsSubmenuIndexAutoPowerOff, }; -#define AUTO_POWEROFF_DELAY_COUNT 9 +#define AUTO_POWEROFF_DELAY_COUNT 8 const char* const auto_poweroff_delay_text[AUTO_POWEROFF_DELAY_COUNT] = - {"OFF","5 sec","5min", "10min", "15min", "30min", "45min", "60min", "90min"}; + {"OFF","5min", "10min", "15min", "30min", "45min", "60min", "90min"}; const uint32_t auto_poweroff_delay_value[AUTO_POWEROFF_DELAY_COUNT] = - {0, 5000, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; + {0, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; // change variable_item_list visible text and app_poweroff_delay_time_settings when user change item in variable_item_list static void power_settings_scene_start_auto_poweroff_delay_changed(VariableItem* item) { @@ -34,6 +34,10 @@ void power_settings_scene_start_on_enter(void* context) { PowerSettingsApp* app = context; VariableItemList* variable_item_list = app->variable_item_list; + variable_item_list_add(variable_item_list, "Battery Info", 1, NULL, NULL); + variable_item_list_add(variable_item_list, "Reboot", 1, NULL, NULL); + variable_item_list_add(variable_item_list, "Power OFF", 1, NULL, NULL); + VariableItem* item; uint8_t value_index; item = variable_item_list_add( @@ -49,11 +53,7 @@ void power_settings_scene_start_on_enter(void* context) { AUTO_POWEROFF_DELAY_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, auto_poweroff_delay_text[value_index]); - - variable_item_list_add(variable_item_list, "Battery Info", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Reboot", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Power OFF", 1, NULL, NULL); - + variable_item_list_set_selected_item( variable_item_list, scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart)); variable_item_list_set_enter_callback( //callback to show next mennu screen From 633f5d7c570f1aa7b552d791b35113a3788956a6 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:23:38 +0300 Subject: [PATCH 54/59] fbt format and naming fix --- applications/services/desktop/desktop.c | 19 ++++++++++--------- .../services/power/power_service/power.c | 15 +++++++-------- .../power/power_service/power_settings.c | 6 ++++-- .../power/power_service/power_settings.h | 2 +- .../scenes/desktop_settings_scene_start.c | 15 ++++++++------- .../power_settings_app/power_settings_app.c | 4 +++- .../scenes/power_settings_scene_start.c | 17 +++++++++++------ .../parsers/iso15693/iso15693_parser.c | 2 +- lib/subghz/protocols/protocol_items.h | 2 +- 9 files changed, 46 insertions(+), 36 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 43356cf25..1c368338c 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -18,9 +18,9 @@ #define TAG "Desktop" // dublicate constants from desktop_setting_scene_start.c -#define USB_INHIBIT_AUTOLOCK_OFF 0 -#define USB_INHIBIT_AUTOLOCK_ON 1 -#define USB_INHIBIT_AUTOLOCK_RPC 2 +#define USB_INHIBIT_AUTOLOCK_OFF 0 +#define USB_INHIBIT_AUTOLOCK_ON 1 +#define USB_INHIBIT_AUTOLOCK_RPC 2 static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); @@ -151,13 +151,14 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { } else if(event == DesktopGlobalAutoLock) { if(!desktop->app_running && !desktop->locked) { // if usb_inhibit_autolock enabled and device charging or device charged but still connected to USB then break desktop locking. - if ((desktop->settings.usb_inhibit_auto_lock == USB_INHIBIT_AUTOLOCK_ON) && ((furi_hal_power_is_charging()) || (furi_hal_power_is_charging_done()))){ - return(0); - } + if((desktop->settings.usb_inhibit_auto_lock == USB_INHIBIT_AUTOLOCK_ON) && + ((furi_hal_power_is_charging()) || (furi_hal_power_is_charging_done()))) { + return (0); + } // if usb_inhibit_autolock set to RPC and we have F0 connected to phone or PC app then break desktop locking. - if (desktop->settings.usb_inhibit_auto_lock == USB_INHIBIT_AUTOLOCK_RPC){ - return(0); - } + if(desktop->settings.usb_inhibit_auto_lock == USB_INHIBIT_AUTOLOCK_RPC) { + return (0); + } desktop_lock(desktop); } } else if(event == DesktopGlobalSaveSettings) { diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 207764e99..dcbac6717 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -442,10 +442,9 @@ static void power_auto_poweroff_timer_callback(void* context) { Power* power = context; //poweroff if not charging now or if connected to charger and charging done - if (((!furi_hal_power_is_charging())) || (furi_hal_power_is_charging_done())) { + if(((!furi_hal_power_is_charging())) || (furi_hal_power_is_charging_done())) { power_off(power); - } - else { + } else { //else we dont poweroff device and restart timer FURI_LOG_D(TAG, "We dont auto_power_off until battery is charging"); power_start_auto_poweroff_timer(power); @@ -463,7 +462,7 @@ static void power_auto_poweroff_arm(Power* power) { } } -// stop timer and event subscription +// stop timer and event subscription static void power_auto_poweroff_disarm(Power* power) { power_stop_auto_poweroff_timer(power); if(power->input_events_subscription) { @@ -482,7 +481,7 @@ static void power_loader_callback(const void* message, void* context) { if(event->type == LoaderEventTypeApplicationBeforeLoad) { power->app_running = true; power_auto_poweroff_disarm(power); - // arm timer if some apps was not loaded or was stoped + // arm timer if some apps was not loaded or was stoped } else if( event->type == LoaderEventTypeApplicationLoadFailed || event->type == LoaderEventTypeApplicationStopped) { @@ -496,7 +495,7 @@ static void power_settings_apply(Power* power) { //apply auto_poweroff settings if(power->settings.auto_poweroff_delay_ms && !power->app_running) { power_auto_poweroff_arm(power); - } else if (power_is_running_auto_poweroff_timer(power)) { + } else if(power_is_running_auto_poweroff_timer(power)) { power_auto_poweroff_disarm(power); } } @@ -621,7 +620,7 @@ static Power* power_alloc(void) { Loader* loader = furi_record_open(RECORD_LOADER); furi_pubsub_subscribe(loader_get_pubsub(loader), power_loader_callback, power); power->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS); - //define autopoweroff timer and they callback + //define autopoweroff timer and they callback power->auto_poweroff_timer = furi_timer_alloc(power_auto_poweroff_timer_callback, FuriTimerTypeOnce, power); @@ -670,7 +669,7 @@ int32_t power_srv(void* p) { furi_record_create(RECORD_POWER, power); -// Can't be done in alloc, other things in startup need power service and it would deadlock by waiting for loader + // Can't be done in alloc, other things in startup need power service and it would deadlock by waiting for loader Loader* loader = furi_record_open(RECORD_LOADER); power->app_running = loader_is_locked(loader); furi_record_close(RECORD_LOADER); diff --git a/applications/services/power/power_service/power_settings.c b/applications/services/power/power_service/power_settings.c index 9682a65e0..139323a7a 100644 --- a/applications/services/power/power_service/power_settings.c +++ b/applications/services/power/power_service/power_settings.c @@ -13,7 +13,7 @@ #define POWER_SETTINGS_MAGIC (0x18) typedef struct { -//inital set - empty + //inital set - empty } PowerSettingsV0; void power_settings_load(PowerSettings* settings) { @@ -33,7 +33,9 @@ void power_settings_load(PowerSettings* settings) { POWER_SETTINGS_MAGIC, POWER_SETTINGS_VER); - } else if(version == POWER_SETTINGS_VER_0) { // if config previous version - load it and manual set new settings to inital value + } else if( + version == + POWER_SETTINGS_VER_0) { // if config previous version - load it and manual set new settings to inital value PowerSettingsV0* settings_v0 = malloc(sizeof(PowerSettingsV0)); success = saved_struct_load( diff --git a/applications/services/power/power_service/power_settings.h b/applications/services/power/power_service/power_settings.h index 038531752..65d8e079e 100644 --- a/applications/services/power/power_service/power_settings.h +++ b/applications/services/power/power_service/power_settings.h @@ -13,4 +13,4 @@ void power_settings_load(PowerSettings* settings); void power_settings_save(const PowerSettings* settings); #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index dee9d40be..8764d4c16 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -45,10 +45,10 @@ const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] = {0, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000}; -#define USB_INHIBIT_AUTO_LOCK_DELAY_COUNT 3 -#define USB_INHIBIT_AUTOLOCK_OFF 0 -#define USB_INHIBIT_AUTOLOCK_ON 1 -#define USB_INHIBIT_AUTOLOCK_RPC 2 +#define USB_INHIBIT_AUTO_LOCK_DELAY_COUNT 3 +#define USB_INHIBIT_AUTOLOCK_OFF 0 +#define USB_INHIBIT_AUTOLOCK_ON 1 +#define USB_INHIBIT_AUTOLOCK_RPC 2 const char* const usb_inhibit_auto_lock_delay_text[USB_INHIBIT_AUTO_LOCK_DELAY_COUNT] = { "OFF", @@ -104,7 +104,6 @@ static void desktop_settings_scene_start_clock_enable_changed(VariableItem* item app->settings.display_clock = index; } - static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) { DesktopSettingsApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -151,10 +150,12 @@ void desktop_settings_scene_start_on_enter(void* context) { app); value_index = value_index_uint32( - app->settings.usb_inhibit_auto_lock, usb_inhibit_auto_lock_delay_value, USB_INHIBIT_AUTO_LOCK_DELAY_COUNT); + app->settings.usb_inhibit_auto_lock, + usb_inhibit_auto_lock_delay_value, + USB_INHIBIT_AUTO_LOCK_DELAY_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, usb_inhibit_auto_lock_delay_text[value_index]); - + item = variable_item_list_add( variable_item_list, "Battery View", diff --git a/applications/settings/power_settings_app/power_settings_app.c b/applications/settings/power_settings_app/power_settings_app.c index 8fa824252..c0e73e256 100644 --- a/applications/settings/power_settings_app/power_settings_app.c +++ b/applications/settings/power_settings_app/power_settings_app.c @@ -48,7 +48,9 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) { app->view_dispatcher, PowerSettingsAppViewSubmenu, submenu_get_view(app->submenu)); app->variable_item_list = variable_item_list_alloc(); view_dispatcher_add_view( - app->view_dispatcher, PowerSettingsAppViewVariableItemList, variable_item_list_get_view(app->variable_item_list)); + app->view_dispatcher, + PowerSettingsAppViewVariableItemList, + variable_item_list_get_view(app->variable_item_list)); app->dialog = dialog_ex_alloc(); view_dispatcher_add_view( app->view_dispatcher, PowerSettingsAppViewDialog, dialog_ex_get_view(app->dialog)); diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c index 9a12d65aa..3fc3a8a30 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_start.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_start.c @@ -10,7 +10,7 @@ enum PowerSettingsSubmenuIndex { #define AUTO_POWEROFF_DELAY_COUNT 8 const char* const auto_poweroff_delay_text[AUTO_POWEROFF_DELAY_COUNT] = - {"OFF","5min", "10min", "15min", "30min", "45min", "60min", "90min"}; + {"OFF", "5min", "10min", "15min", "30min", "45min", "60min", "90min"}; const uint32_t auto_poweroff_delay_value[AUTO_POWEROFF_DELAY_COUNT] = {0, 300000, 600000, 900000, 1800000, 2700000, 3600000, 5400000}; @@ -24,7 +24,9 @@ static void power_settings_scene_start_auto_poweroff_delay_changed(VariableItem* app->settings.auto_poweroff_delay_ms = auto_poweroff_delay_value[index]; } -static void power_settings_scene_start_submenu_callback(void* context, uint32_t index) { //show selected menu screen +static void power_settings_scene_start_submenu_callback( + void* context, + uint32_t index) { //show selected menu screen furi_assert(context); PowerSettingsApp* app = context; view_dispatcher_send_custom_event(app->view_dispatcher, index); @@ -42,7 +44,7 @@ void power_settings_scene_start_on_enter(void* context) { uint8_t value_index; item = variable_item_list_add( variable_item_list, - "Auto PowerOff Time", + "Auto PowerOff", AUTO_POWEROFF_DELAY_COUNT, power_settings_scene_start_auto_poweroff_delay_changed, //function for change visible item list value and app settings app); @@ -53,11 +55,14 @@ void power_settings_scene_start_on_enter(void* context) { AUTO_POWEROFF_DELAY_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, auto_poweroff_delay_text[value_index]); - + variable_item_list_set_selected_item( - variable_item_list, scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart)); + variable_item_list, + scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart)); variable_item_list_set_enter_callback( //callback to show next mennu screen - variable_item_list, power_settings_scene_start_submenu_callback, app); + variable_item_list, + power_settings_scene_start_submenu_callback, + app); view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewVariableItemList); } diff --git a/lib/signal_reader/parsers/iso15693/iso15693_parser.c b/lib/signal_reader/parsers/iso15693/iso15693_parser.c index 7823a1237..3bf04d4c6 100644 --- a/lib/signal_reader/parsers/iso15693/iso15693_parser.c +++ b/lib/signal_reader/parsers/iso15693/iso15693_parser.c @@ -321,4 +321,4 @@ void iso15693_parser_force_1outof256(Iso15693Parser* instance) { instance->detect_mode = false; instance->mode = Iso15693ParserMode1OutOf256; -} \ No newline at end of file +} diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 9ca7d91ec..71265e88c 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -51,4 +51,4 @@ #include "gangqi.h" #include "marantec24.h" #include "hollarm.h" -#include "hay21.h" \ No newline at end of file +#include "hay21.h" From 5096b9c88ba8b2788a976c4b0baa891ef128221a Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Thu, 16 Jan 2025 23:51:10 +0900 Subject: [PATCH 55/59] Infrared: increase max carrier limit --- targets/furi_hal_include/furi_hal_infrared.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/furi_hal_include/furi_hal_infrared.h b/targets/furi_hal_include/furi_hal_infrared.h index 29f7101c1..36eaf122d 100644 --- a/targets/furi_hal_include/furi_hal_infrared.h +++ b/targets/furi_hal_include/furi_hal_infrared.h @@ -13,7 +13,7 @@ extern "C" { #endif -#define INFRARED_MAX_FREQUENCY 56000 +#define INFRARED_MAX_FREQUENCY 1000000 #define INFRARED_MIN_FREQUENCY 10000 typedef enum { From 0a2b47c7e114807c9bab3cbbec442062d17967a4 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 17 Jan 2025 12:12:27 +0700 Subject: [PATCH 56/59] Autolock disarm by active USB connection instead of USB charging connection. --- applications/services/desktop/desktop.c | 15 +++------------ .../scenes/desktop_settings_scene_start.c | 14 +++----------- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 1c368338c..79eace4a3 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -17,11 +17,6 @@ #define TAG "Desktop" -// dublicate constants from desktop_setting_scene_start.c -#define USB_INHIBIT_AUTOLOCK_OFF 0 -#define USB_INHIBIT_AUTOLOCK_ON 1 -#define USB_INHIBIT_AUTOLOCK_RPC 2 - static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); @@ -150,15 +145,11 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { } else if(event == DesktopGlobalAutoLock) { if(!desktop->app_running && !desktop->locked) { - // if usb_inhibit_autolock enabled and device charging or device charged but still connected to USB then break desktop locking. - if((desktop->settings.usb_inhibit_auto_lock == USB_INHIBIT_AUTOLOCK_ON) && - ((furi_hal_power_is_charging()) || (furi_hal_power_is_charging_done()))) { - return (0); - } - // if usb_inhibit_autolock set to RPC and we have F0 connected to phone or PC app then break desktop locking. - if(desktop->settings.usb_inhibit_auto_lock == USB_INHIBIT_AUTOLOCK_RPC) { + // Disable AutoLock if usb_inhibit_autolock option enabled and device have active USB connection. + if((desktop->settings.usb_inhibit_auto_lock) && (furi_hal_usb_is_locked())) { return (0); } + desktop_lock(desktop); } } else if(event == DesktopGlobalSaveSettings) { diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 8764d4c16..74266b28d 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -45,22 +45,14 @@ const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] = {0, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000}; -#define USB_INHIBIT_AUTO_LOCK_DELAY_COUNT 3 -#define USB_INHIBIT_AUTOLOCK_OFF 0 -#define USB_INHIBIT_AUTOLOCK_ON 1 -#define USB_INHIBIT_AUTOLOCK_RPC 2 +#define USB_INHIBIT_AUTO_LOCK_DELAY_COUNT 2 const char* const usb_inhibit_auto_lock_delay_text[USB_INHIBIT_AUTO_LOCK_DELAY_COUNT] = { "OFF", "ON", - "RPC", }; -const uint32_t usb_inhibit_auto_lock_delay_value[USB_INHIBIT_AUTO_LOCK_DELAY_COUNT] = { - USB_INHIBIT_AUTOLOCK_OFF, - USB_INHIBIT_AUTOLOCK_ON, - USB_INHIBIT_AUTOLOCK_RPC, -}; +const uint32_t usb_inhibit_auto_lock_delay_value[USB_INHIBIT_AUTO_LOCK_DELAY_COUNT] = {0,1}; #define CLOCK_ENABLE_COUNT 2 const char* const clock_enable_text[CLOCK_ENABLE_COUNT] = { @@ -144,7 +136,7 @@ void desktop_settings_scene_start_on_enter(void* context) { // USB connection Inhibit autolock OFF|ON|with opened RPC session item = variable_item_list_add( variable_item_list, - "USB disarm Auto Lock", + "Auto Lock disarm by active USB connection", USB_INHIBIT_AUTO_LOCK_DELAY_COUNT, desktop_settings_scene_start_usb_inhibit_auto_lock_delay_changed, app); From fbc29f519f5e0888eeec79f3056bbe8c6d0246f6 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 17 Jan 2025 13:01:38 +0700 Subject: [PATCH 57/59] Disable autopoweroff if charger connected. --- applications/services/power/power_service/power.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index dcbac6717..511c64c78 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -441,13 +441,12 @@ static void power_auto_poweroff_timer_callback(void* context) { furi_assert(context); Power* power = context; - //poweroff if not charging now or if connected to charger and charging done - if(((!furi_hal_power_is_charging())) || (furi_hal_power_is_charging_done())) { - power_off(power); - } else { - //else we dont poweroff device and restart timer + //Dont poweroff device if charger connected + if (furi_hal_power_is_charging()) { FURI_LOG_D(TAG, "We dont auto_power_off until battery is charging"); power_start_auto_poweroff_timer(power); + } else { + power_off(power); } } From e809e3ddbbe538f7c6924a341de248a7ee9d72c7 Mon Sep 17 00:00:00 2001 From: Dmitry422 Date: Fri, 17 Jan 2025 13:12:20 +0700 Subject: [PATCH 58/59] Cosmetic menu changes --- applications/services/desktop/desktop.c | 2 +- .../desktop_settings/scenes/desktop_settings_scene_start.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 79eace4a3..843dbebb0 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -145,7 +145,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { } else if(event == DesktopGlobalAutoLock) { if(!desktop->app_running && !desktop->locked) { - // Disable AutoLock if usb_inhibit_autolock option enabled and device have active USB connection. + // Disable AutoLock if usb_inhibit_autolock option enabled and device have active USB session. if((desktop->settings.usb_inhibit_auto_lock) && (furi_hal_usb_is_locked())) { return (0); } diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 74266b28d..9b992c80c 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -136,7 +136,7 @@ void desktop_settings_scene_start_on_enter(void* context) { // USB connection Inhibit autolock OFF|ON|with opened RPC session item = variable_item_list_add( variable_item_list, - "Auto Lock disarm by active USB connection", + "Auto Lock disarm by active USB session", USB_INHIBIT_AUTO_LOCK_DELAY_COUNT, desktop_settings_scene_start_usb_inhibit_auto_lock_delay_changed, app); From 1acc814b2acb5b026ebc4695e505572e69f58f54 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 17 Jan 2025 14:59:05 +0300 Subject: [PATCH 59/59] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e7d0aa0b..30c0c1f7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Power: Auto Power Off Timer (by @Dmitry422 with some fixes by @xMasterX) * OFW: **Fix lost BadBLE keystrokes** * OFW: **Add the ability to send a signal once via RPC** +* OFW PR 4070: Infrared: increase max carrier limit (by @skotopes) * OFW PR 4025: Increase system stack's reserved memory size (Fix USB UART Bridge Crash) (by @Astrrra) * OFW: merged gsurkov/vcp_break_support branch for usb uart bridge (WIP!!!) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev)