From 7618c8ba6ffe3026858373f8346b052dd45193ef Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Wed, 15 Jun 2022 06:20:46 +0300 Subject: [PATCH 01/17] Change "cad" to "card" (#1320) This bugs me too much to just ignore it -_- --- applications/nfc/scenes/nfc_scene_read_emv_data_success.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/nfc/scenes/nfc_scene_read_emv_data_success.c b/applications/nfc/scenes/nfc_scene_read_emv_data_success.c index 275e9b86..4b3be9e1 100755 --- a/applications/nfc/scenes/nfc_scene_read_emv_data_success.c +++ b/applications/nfc/scenes/nfc_scene_read_emv_data_success.c @@ -37,7 +37,7 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { // Add card name widget_add_string_element( nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name); - // Add cad number + // Add card number string_t pan_str; string_init(pan_str); for(uint8_t i = 0; i < emv_data->number_len; i += 2) { From 839e52ac32ada5eaa08796a2022c7aa6187845a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 20 Jun 2022 17:54:48 +0300 Subject: [PATCH 02/17] [FL-2591] Furi: remove CMSIS thread api, migrate to FuriThread, remove unused CMSIS APIs (#1333) * Furi: remove CMSIS thread api, migrate to FuriThread, remove unused CMSIS APIs * Furi: magic thread catcher validating thread completion; backtrace improver * Furi: allow furi_thread_get_current_id outside of thread context * Furi: use IRQ instead of ISR for core primitives --- applications/bad_usb/bad_usb_script.c | 18 +- applications/cli/cli_commands.c | 12 +- applications/cli/cli_vcp.c | 19 +- applications/debug_tools/uart_echo.c | 7 +- applications/gpio/usb_uart_bridge.c | 26 +- applications/gui/gui.c | 11 +- applications/gui/gui_i.h | 2 +- .../gui/modules/file_browser_worker.c | 18 +- applications/input/input.c | 6 +- applications/input/input_i.h | 2 +- applications/loader/loader.c | 15 +- applications/loader/loader_i.h | 2 +- applications/rpc/rpc.c | 8 +- applications/rpc/rpc_gui.c | 12 +- applications/subghz/helpers/subghz_chat.c | 4 +- applications/u2f/u2f_hid.c | 12 +- .../unit_tests/furi_valuemutex_test.c | 88 - applications/unit_tests/minunit_test.c | 5 - .../unit_tests/storage/storage_test.c | 4 +- applications/unit_tests/subghz/subghz_test.c | 4 +- applications/updater/util/update_task.c | 4 +- applications/updater/util/update_task.h | 2 +- core/furi.h | 7 +- core/furi/base.h | 45 + core/furi/check.c | 5 +- core/furi/check.h | 1 + core/furi/event_flags.c | 222 +++ core/furi/event_flags.h | 63 + core/furi/log.c | 1 + core/furi/memmgr_heap.c | 14 +- core/furi/memmgr_heap.h | 8 +- core/furi/mutex.c | 217 ++ core/furi/mutex.h | 56 + core/furi/pubsub.c | 2 +- core/furi/record.c | 3 +- core/furi/semaphore.c | 190 ++ core/furi/semaphore.h | 57 + core/furi/stdglue.c | 14 +- core/furi/thread.c | 293 ++- core/furi/thread.h | 77 +- core/furi/valuemutex.h | 1 + firmware/targets/f7/Inc/FreeRTOSConfig.h | 7 +- firmware/targets/f7/Src/main.c | 18 +- firmware/targets/f7/ble_glue/ble_app.c | 11 +- firmware/targets/f7/ble_glue/ble_glue.c | 10 +- firmware/targets/f7/furi_hal/furi_hal_bt.c | 2 +- firmware/targets/f7/furi_hal/furi_hal_crc.c | 2 +- firmware/targets/f7/furi_hal/furi_hal_flash.c | 12 +- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 6 +- .../targets/f7/furi_hal/furi_hal_resources.c | 4 +- .../targets/f7/furi_hal/furi_hal_resources.h | 2 +- firmware/targets/f7/furi_hal/furi_hal_rfid.c | 18 +- firmware/targets/f7/furi_hal/furi_hal_usb.c | 16 +- lib/FreeRTOS-glue/cmsis_os2.c | 1756 +---------------- lib/FreeRTOS-glue/cmsis_os2.h | 572 +----- lib/FreeRTOS-glue/freertos_mpool.h | 63 - lib/FreeRTOS-glue/freertos_os2.h | 31 +- lib/FreeRTOS-glue/os_tick.h | 80 - lib/ST25RFAL002/platform.c | 51 +- lib/infrared/worker/infrared_worker.c | 28 +- lib/subghz/subghz_file_encoder_worker.c | 5 +- 61 files changed, 1467 insertions(+), 2784 deletions(-) create mode 100644 core/furi/base.h create mode 100644 core/furi/event_flags.c create mode 100644 core/furi/event_flags.h create mode 100644 core/furi/mutex.c create mode 100644 core/furi/mutex.h create mode 100644 core/furi/semaphore.c create mode 100644 core/furi/semaphore.h delete mode 100644 lib/FreeRTOS-glue/freertos_mpool.h delete mode 100644 lib/FreeRTOS-glue/os_tick.h diff --git a/applications/bad_usb/bad_usb_script.c b/applications/bad_usb/bad_usb_script.c index 685e5083..0266b51f 100644 --- a/applications/bad_usb/bad_usb_script.c +++ b/applications/bad_usb/bad_usb_script.c @@ -440,9 +440,9 @@ static void bad_usb_hid_state_callback(bool state, void* context) { BadUsbScript* bad_usb = context; if(state == true) - osThreadFlagsSet(furi_thread_get_thread_id(bad_usb->thread), WorkerEvtConnect); + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect); else - osThreadFlagsSet(furi_thread_get_thread_id(bad_usb->thread), WorkerEvtDisconnect); + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect); } static int32_t bad_usb_worker(void* context) { @@ -483,8 +483,8 @@ static int32_t bad_usb_worker(void* context) { bad_usb->st.state = worker_state; } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected - uint32_t flags = - osThreadFlagsWait(WorkerEvtEnd | WorkerEvtConnect, osFlagsWaitAny, osWaitForever); + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd | WorkerEvtConnect, osFlagsWaitAny, osWaitForever); furi_check((flags & osFlagsError) == 0); if(flags & WorkerEvtEnd) { break; @@ -494,7 +494,7 @@ static int32_t bad_usb_worker(void* context) { bad_usb->st.state = worker_state; } else if(worker_state == BadUsbStateIdle) { // State: ready to start - uint32_t flags = osThreadFlagsWait( + uint32_t flags = furi_thread_flags_wait( WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, osFlagsWaitAny, osWaitForever); @@ -518,7 +518,7 @@ static int32_t bad_usb_worker(void* context) { } else if(worker_state == BadUsbStateRunning) { // State: running uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); - uint32_t flags = osThreadFlagsWait( + uint32_t flags = furi_thread_flags_wait( WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, osFlagsWaitAny, delay_cur); delay_val -= delay_cur; if(!(flags & osFlagsError)) { @@ -561,7 +561,7 @@ static int32_t bad_usb_worker(void* context) { } else if( (worker_state == BadUsbStateFileError) || (worker_state == BadUsbStateScriptError)) { // State: error - uint32_t flags = osThreadFlagsWait( + uint32_t flags = furi_thread_flags_wait( WorkerEvtEnd, osFlagsWaitAny, osWaitForever); // Waiting for exit command furi_check((flags & osFlagsError) == 0); if(flags & WorkerEvtEnd) { @@ -605,7 +605,7 @@ BadUsbScript* bad_usb_script_open(string_t file_path) { void bad_usb_script_close(BadUsbScript* bad_usb) { furi_assert(bad_usb); - osThreadFlagsSet(furi_thread_get_thread_id(bad_usb->thread), WorkerEvtEnd); + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd); furi_thread_join(bad_usb->thread); furi_thread_free(bad_usb->thread); string_clear(bad_usb->file_path); @@ -614,7 +614,7 @@ void bad_usb_script_close(BadUsbScript* bad_usb) { void bad_usb_script_toggle(BadUsbScript* bad_usb) { furi_assert(bad_usb); - osThreadFlagsSet(furi_thread_get_thread_id(bad_usb->thread), WorkerEvtToggle); + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle); } BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb) { diff --git a/applications/cli/cli_commands.c b/applications/cli/cli_commands.c index 8271ab31..c99f4edc 100644 --- a/applications/cli/cli_commands.c +++ b/applications/cli/cli_commands.c @@ -255,19 +255,19 @@ void cli_command_ps(Cli* cli, string_t args, void* context) { UNUSED(context); const uint8_t threads_num_max = 32; - osThreadId_t threads_id[threads_num_max]; - uint8_t thread_num = osThreadEnumerate(threads_id, threads_num_max); + FuriThreadId threads_ids[threads_num_max]; + uint8_t thread_num = furi_thread_enumerate(threads_ids, threads_num_max); printf( "%-20s %-14s %-8s %-8s %s\r\n", "Name", "Stack start", "Heap", "Stack", "Stack min free"); for(uint8_t i = 0; i < thread_num; i++) { - TaskControlBlock* tcb = (TaskControlBlock*)threads_id[i]; + TaskControlBlock* tcb = (TaskControlBlock*)threads_ids[i]; printf( "%-20s 0x%-12lx %-8d %-8ld %-8ld\r\n", - osThreadGetName(threads_id[i]), + furi_thread_get_name(threads_ids[i]), (uint32_t)tcb->pxStack, - memmgr_heap_get_thread_memory(threads_id[i]), + memmgr_heap_get_thread_memory(threads_ids[i]), (uint32_t)(tcb->pxEndOfStack - tcb->pxStack + 1) * sizeof(StackType_t), - osThreadGetStackSpace(threads_id[i])); + furi_thread_get_stack_space(threads_ids[i])); } printf("\r\nTotal: %d", thread_num); } diff --git a/applications/cli/cli_vcp.c b/applications/cli/cli_vcp.c index 84edca18..7e23e4b1 100644 --- a/applications/cli/cli_vcp.c +++ b/applications/cli/cli_vcp.c @@ -79,7 +79,7 @@ static void cli_vcp_init() { } static void cli_vcp_deinit() { - osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStop); + furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStop); furi_thread_join(vcp->thread); furi_thread_free(vcp->thread); vcp->thread = NULL; @@ -102,7 +102,8 @@ static int32_t vcp_worker(void* context) { vcp->running = true; while(1) { - uint32_t flags = osThreadFlagsWait(VCP_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever); + uint32_t flags = + furi_thread_flags_wait(VCP_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever); furi_assert((flags & osFlagsError) == 0); // VCP session opened @@ -232,7 +233,7 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) { FURI_LOG_D(TAG, "rx %u ", batch_size); #endif if(len == 0) break; - osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStreamRx); + furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamRx); size -= len; buffer += len; rx_cnt += len; @@ -261,7 +262,7 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) { if(batch_size > USB_CDC_PKT_LEN) batch_size = USB_CDC_PKT_LEN; xStreamBufferSend(vcp->tx_stream, buffer, batch_size, osWaitForever); - osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStreamTx); + furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamTx); #ifdef CLI_VCP_DEBUG FURI_LOG_D(TAG, "tx %u", batch_size); #endif @@ -283,7 +284,7 @@ static void cli_vcp_tx_stdout(void* _cookie, const char* data, size_t size) { static void vcp_state_callback(void* context, uint8_t state) { UNUSED(context); if(state == 0) { - osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtDisconnect); + furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtDisconnect); } } @@ -293,21 +294,21 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) { bool dtr = state & (1 << 0); if(dtr == true) { - osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtConnect); + furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtConnect); } else { - osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtDisconnect); + furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtDisconnect); } } static void vcp_on_cdc_rx(void* context) { UNUSED(context); - uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx); + uint32_t ret = furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtRx); furi_check((ret & osFlagsError) == 0); } static void vcp_on_cdc_tx_complete(void* context) { UNUSED(context); - osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtTx); + furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtTx); } static bool cli_vcp_is_connected(void) { diff --git a/applications/debug_tools/uart_echo.c b/applications/debug_tools/uart_echo.c index 206c6c06..213769a5 100644 --- a/applications/debug_tools/uart_echo.c +++ b/applications/debug_tools/uart_echo.c @@ -97,7 +97,7 @@ static void uart_echo_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { if(ev == UartIrqEventRXNE) { xStreamBufferSendFromISR(app->rx_stream, &data, 1, &xHigherPriorityTaskWoken); - osThreadFlagsSet(furi_thread_get_thread_id(app->worker_thread), WorkerEventRx); + furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventRx); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } @@ -149,7 +149,8 @@ static int32_t uart_echo_worker(void* context) { UartEchoApp* app = context; while(1) { - uint32_t events = osThreadFlagsWait(WORKER_EVENTS_MASK, osFlagsWaitAny, osWaitForever); + uint32_t events = + furi_thread_flags_wait(WORKER_EVENTS_MASK, osFlagsWaitAny, osWaitForever); furi_check((events & osFlagsError) == 0); if(events & WorkerEventStop) break; @@ -234,7 +235,7 @@ static UartEchoApp* uart_echo_app_alloc() { static void uart_echo_app_free(UartEchoApp* app) { furi_assert(app); - osThreadFlagsSet(furi_thread_get_thread_id(app->worker_thread), WorkerEventStop); + furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventStop); furi_thread_join(app->worker_thread); furi_thread_free(app->worker_thread); diff --git a/applications/gpio/usb_uart_bridge.c b/applications/gpio/usb_uart_bridge.c index f70cf640..cf7e7687 100644 --- a/applications/gpio/usb_uart_bridge.c +++ b/applications/gpio/usb_uart_bridge.c @@ -78,7 +78,7 @@ static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { if(ev == UartIrqEventRXNE) { xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken); - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtRxDone); + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtRxDone); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } @@ -181,12 +181,13 @@ static int32_t usb_uart_worker(void* context) { usb_uart_update_ctrl_lines(usb_uart); } - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtCdcRx); + furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtCdcRx); furi_thread_start(usb_uart->tx_thread); while(1) { - uint32_t events = osThreadFlagsWait(WORKER_ALL_RX_EVENTS, osFlagsWaitAny, osWaitForever); + uint32_t events = + furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, osFlagsWaitAny, osWaitForever); furi_check((events & osFlagsError) == 0); if(events & WorkerEvtStop) break; if(events & WorkerEvtRxDone) { @@ -205,7 +206,7 @@ static int32_t usb_uart_worker(void* context) { } if(events & WorkerEvtCfgChange) { if(usb_uart->cfg.vcp_ch != usb_uart->cfg_new.vcp_ch) { - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtTxStop); + furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtTxStop); furi_thread_join(usb_uart->tx_thread); usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); @@ -217,7 +218,7 @@ static int32_t usb_uart_worker(void* context) { events |= WorkerEvtLineCfgSet; } if(usb_uart->cfg.uart_ch != usb_uart->cfg_new.uart_ch) { - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtTxStop); + furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtTxStop); furi_thread_join(usb_uart->tx_thread); usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch); @@ -266,7 +267,7 @@ static int32_t usb_uart_worker(void* context) { furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], GpioModeAnalog); } - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtTxStop); + furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtTxStop); furi_thread_join(usb_uart->tx_thread); furi_thread_free(usb_uart->tx_thread); @@ -288,7 +289,8 @@ static int32_t usb_uart_tx_thread(void* context) { uint8_t data[USB_CDC_PKT_LEN]; while(1) { - uint32_t events = osThreadFlagsWait(WORKER_ALL_TX_EVENTS, osFlagsWaitAny, osWaitForever); + uint32_t events = + furi_thread_flags_wait(WORKER_ALL_TX_EVENTS, osFlagsWaitAny, osWaitForever); furi_check((events & osFlagsError) == 0); if(events & WorkerEvtTxStop) break; if(events & WorkerEvtCdcRx) { @@ -314,7 +316,7 @@ static void vcp_on_cdc_tx_complete(void* context) { static void vcp_on_cdc_rx(void* context) { UsbUartBridge* usb_uart = (UsbUartBridge*)context; - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->tx_thread), WorkerEvtCdcRx); + furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtCdcRx); } static void vcp_state_callback(void* context, uint8_t state) { @@ -325,13 +327,13 @@ static void vcp_state_callback(void* context, uint8_t state) { static void vcp_on_cdc_control_line(void* context, uint8_t state) { UNUSED(state); UsbUartBridge* usb_uart = (UsbUartBridge*)context; - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtCtrlLineSet); + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCtrlLineSet); } static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) { UNUSED(config); UsbUartBridge* usb_uart = (UsbUartBridge*)context; - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtLineCfgSet); + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtLineCfgSet); } UsbUartBridge* usb_uart_enable(UsbUartConfig* cfg) { @@ -351,7 +353,7 @@ UsbUartBridge* usb_uart_enable(UsbUartConfig* cfg) { void usb_uart_disable(UsbUartBridge* usb_uart) { furi_assert(usb_uart); - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtStop); + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtStop); furi_thread_join(usb_uart->thread); furi_thread_free(usb_uart->thread); free(usb_uart); @@ -361,7 +363,7 @@ void usb_uart_set_config(UsbUartBridge* usb_uart, UsbUartConfig* cfg) { furi_assert(usb_uart); furi_assert(cfg); memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig)); - osThreadFlagsSet(furi_thread_get_thread_id(usb_uart->thread), WorkerEvtCfgChange); + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCfgChange); } void usb_uart_get_config(UsbUartBridge* usb_uart, UsbUartConfig* cfg) { diff --git a/applications/gui/gui.c b/applications/gui/gui.c index 77ee4487..d9e32cdd 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -19,7 +19,7 @@ ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { void gui_update(Gui* gui) { furi_assert(gui); - osThreadFlagsSet(gui->thread, GUI_THREAD_FLAG_DRAW); + furi_thread_flags_set(gui->thread_id, GUI_THREAD_FLAG_DRAW); } void gui_input_events_callback(const void* value, void* ctx) { @@ -29,7 +29,7 @@ void gui_input_events_callback(const void* value, void* ctx) { Gui* gui = ctx; osMessageQueuePut(gui->input_queue, value, 0, osWaitForever); - osThreadFlagsSet(gui->thread, GUI_THREAD_FLAG_INPUT); + furi_thread_flags_set(gui->thread_id, GUI_THREAD_FLAG_INPUT); } // Only Fullscreen supports vertical display for now @@ -471,7 +471,7 @@ void gui_set_lockdown(Gui* gui, bool lockdown) { Gui* gui_alloc() { Gui* gui = malloc(sizeof(Gui)); // Thread ID - gui->thread = osThreadGetId(); + gui->thread_id = furi_thread_get_current_id(); // Allocate mutex gui->mutex = osMutexNew(NULL); furi_check(gui->mutex); @@ -500,7 +500,8 @@ int32_t gui_srv(void* p) { furi_record_create("gui", gui); while(1) { - uint32_t flags = osThreadFlagsWait(GUI_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever); + uint32_t flags = + furi_thread_flags_wait(GUI_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever); // Process and dispatch input if(flags & GUI_THREAD_FLAG_INPUT) { // Process till queue become empty @@ -512,7 +513,7 @@ int32_t gui_srv(void* p) { // Process and dispatch draw call if(flags & GUI_THREAD_FLAG_DRAW) { // Clear flags that arrived on input step - osThreadFlagsClear(GUI_THREAD_FLAG_DRAW); + furi_thread_flags_clear(GUI_THREAD_FLAG_DRAW); gui_redraw(gui); } } diff --git a/applications/gui/gui_i.h b/applications/gui/gui_i.h index ea26339d..abe85615 100644 --- a/applications/gui/gui_i.h +++ b/applications/gui/gui_i.h @@ -57,7 +57,7 @@ ALGO_DEF(CanvasCallbackPairArray, CanvasCallbackPairArray_t); /** Gui structure */ struct Gui { // Thread and lock - osThreadId_t thread; + FuriThreadId thread_id; osMutexId_t mutex; // Layers and Canvas diff --git a/applications/gui/modules/file_browser_worker.c b/applications/gui/modules/file_browser_worker.c index 4931cb26..cd7b6cb7 100644 --- a/applications/gui/modules/file_browser_worker.c +++ b/applications/gui/modules/file_browser_worker.c @@ -259,10 +259,10 @@ static int32_t browser_worker(void* context) { string_t filename; string_init(filename); - osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtConfigChange); + furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtConfigChange); while(1) { - uint32_t flags = osThreadFlagsWait(WORKER_FLAGS_ALL, osFlagsWaitAny, osWaitForever); + uint32_t flags = furi_thread_flags_wait(WORKER_FLAGS_ALL, osFlagsWaitAny, osWaitForever); furi_assert((flags & osFlagsError) == 0); if(flags & WorkerEvtConfigChange) { @@ -272,7 +272,7 @@ static int32_t browser_worker(void* context) { } idx_last_array_reset(browser->idx_last); - osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtFolderEnter); + furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderEnter); } if(flags & WorkerEvtFolderEnter) { @@ -369,7 +369,7 @@ BrowserWorker* file_browser_worker_alloc(string_t path, const char* filter_ext, void file_browser_worker_free(BrowserWorker* browser) { furi_assert(browser); - osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtStop); + furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtStop); furi_thread_join(browser->thread); furi_thread_free(browser->thread); @@ -423,30 +423,30 @@ void file_browser_worker_set_config( string_set(browser->path_next, path); string_set_str(browser->filter_extension, filter_ext); browser->skip_assets = skip_assets; - osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtConfigChange); + furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtConfigChange); } void file_browser_worker_folder_enter(BrowserWorker* browser, string_t path, int32_t item_idx) { furi_assert(browser); string_set(browser->path_next, path); browser->item_sel_idx = item_idx; - osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtFolderEnter); + furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderEnter); } void file_browser_worker_folder_exit(BrowserWorker* browser) { furi_assert(browser); - osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtFolderExit); + furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderExit); } void file_browser_worker_folder_refresh(BrowserWorker* browser, int32_t item_idx) { furi_assert(browser); browser->item_sel_idx = item_idx; - osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtFolderRefresh); + furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderRefresh); } void file_browser_worker_load(BrowserWorker* browser, uint32_t offset, uint32_t count) { furi_assert(browser); browser->load_offset = offset; browser->load_count = count; - osThreadFlagsSet(furi_thread_get_thread_id(browser->thread), WorkerEvtLoad); + furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtLoad); } diff --git a/applications/input/input.c b/applications/input/input.c index dd824dcb..2be67a71 100644 --- a/applications/input/input.c +++ b/applications/input/input.c @@ -36,7 +36,7 @@ void input_press_timer_callback(void* arg) { void input_isr(void* _ctx) { UNUSED(_ctx); - osThreadFlagsSet(input->thread, INPUT_THREAD_FLAG_ISR); + furi_thread_flags_set(input->thread_id, INPUT_THREAD_FLAG_ISR); } const char* input_get_key_name(InputKey key) { @@ -66,7 +66,7 @@ const char* input_get_type_name(InputType type) { int32_t input_srv() { input = malloc(sizeof(Input)); - input->thread = osThreadGetId(); + input->thread_id = furi_thread_get_current_id(); input->event_pubsub = furi_pubsub_alloc(); furi_record_create("input_events", input->event_pubsub); @@ -129,7 +129,7 @@ int32_t input_srv() { if(is_changing) { osDelay(1); } else { - osThreadFlagsWait(INPUT_THREAD_FLAG_ISR, osFlagsWaitAny, osWaitForever); + furi_thread_flags_wait(INPUT_THREAD_FLAG_ISR, osFlagsWaitAny, osWaitForever); } } diff --git a/applications/input/input_i.h b/applications/input/input_i.h index 4bd777ef..63a9c85a 100644 --- a/applications/input/input_i.h +++ b/applications/input/input_i.h @@ -32,7 +32,7 @@ typedef struct { /** Input state */ typedef struct { - osThreadId_t thread; + FuriThreadId thread_id; FuriPubSub* event_pubsub; InputPinState* pin_states; Cli* cli; diff --git a/applications/loader/loader.c b/applications/loader/loader.c index e5d59702..1acff8b7 100644 --- a/applications/loader/loader.c +++ b/applications/loader/loader.c @@ -29,13 +29,9 @@ static bool furi_thread_set_callback( loader_instance->application_thread, loader_instance->application->app); - bool result = furi_thread_start(loader_instance->application_thread); + furi_thread_start(loader_instance->application_thread); - if(!result) { - loader_instance->application = NULL; - } - - return result; + return true; } static void loader_menu_callback(void* _ctx, uint32_t index) { @@ -300,7 +296,7 @@ static Loader* loader_alloc() { UNUSED(loader_cli); #endif - instance->loader_thread = osThreadGetId(); + instance->loader_thread = furi_thread_get_current_id(); // Gui instance->gui = furi_record_open("gui"); @@ -444,7 +440,7 @@ static void loader_build_submenu() { void loader_show_menu() { furi_assert(loader_instance); - osThreadFlagsSet(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); + furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); } void loader_update_menu() { @@ -474,7 +470,8 @@ int32_t loader_srv(void* p) { #endif while(1) { - uint32_t flags = osThreadFlagsWait(LOADER_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever); + uint32_t flags = + furi_thread_flags_wait(LOADER_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever); if(flags & LOADER_THREAD_FLAG_SHOW_MENU) { menu_set_selected_item(loader_instance->primary_menu, 0); view_dispatcher_switch_to_view( diff --git a/applications/loader/loader_i.h b/applications/loader/loader_i.h index 4c937b94..a311c6e8 100644 --- a/applications/loader/loader_i.h +++ b/applications/loader/loader_i.h @@ -15,7 +15,7 @@ #include struct Loader { - osThreadId_t loader_thread; + FuriThreadId loader_thread; const FlipperApplication* application; FuriThread* application_thread; diff --git a/applications/rpc/rpc.c b/applications/rpc/rpc.c index 7d51defd..c974a0e5 100644 --- a/applications/rpc/rpc.c +++ b/applications/rpc/rpc.c @@ -408,7 +408,7 @@ size_t furi_assert(session); size_t bytes_sent = xStreamBufferSend(session->stream, encoded_bytes, size, timeout); - osThreadFlagsSet(furi_thread_get_thread_id(session->thread), RpcEvtNewData); + furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtNewData); return bytes_sent; } @@ -441,7 +441,7 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { if(count == bytes_received) { break; } else { - flags = osThreadFlagsWait(RPC_ALL_EVENTS, osFlagsWaitAny, osWaitForever); + flags = furi_thread_flags_wait(RPC_ALL_EVENTS, osFlagsWaitAny, osWaitForever); if(flags & RpcEvtDisconnect) { if(xStreamBufferIsEmpty(session->stream)) { session->terminate = true; @@ -450,7 +450,7 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { break; } else { /* Save disconnect flag and continue reading buffer */ - osThreadFlagsSet(furi_thread_get_thread_id(session->thread), RpcEvtDisconnect); + furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect); } } else if(flags & RpcEvtNewData) { // Just wake thread up @@ -643,7 +643,7 @@ void rpc_session_close(RpcSession* session) { rpc_session_set_send_bytes_callback(session, NULL); rpc_session_set_close_callback(session, NULL); rpc_session_set_buffer_is_empty_callback(session, NULL); - osThreadFlagsSet(furi_thread_get_thread_id(session->thread), RpcEvtDisconnect); + furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect); } int32_t rpc_srv(void* p) { diff --git a/applications/rpc/rpc_gui.c b/applications/rpc/rpc_gui.c index f390d983..da91ae06 100644 --- a/applications/rpc/rpc_gui.c +++ b/applications/rpc/rpc_gui.c @@ -40,8 +40,7 @@ static void memcpy(buffer, data, size); - osThreadFlagsSet( - furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagTransmit); + furi_thread_flags_set(furi_thread_get_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagTransmit); } static int32_t rpc_system_gui_screen_stream_frame_transmit_thread(void* context) { @@ -50,7 +49,8 @@ static int32_t rpc_system_gui_screen_stream_frame_transmit_thread(void* context) RpcGuiSystem* rpc_gui = (RpcGuiSystem*)context; while(true) { - uint32_t flags = osThreadFlagsWait(RpcGuiWorkerFlagAny, osFlagsWaitAny, osWaitForever); + uint32_t flags = + furi_thread_flags_wait(RpcGuiWorkerFlagAny, osFlagsWaitAny, osWaitForever); if(flags & RpcGuiWorkerFlagTransmit) { rpc_send(rpc_gui->session, rpc_gui->transmit_frame); } @@ -117,8 +117,7 @@ static void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, vo gui_remove_framebuffer_callback( rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context); // Stop and release worker thread - osThreadFlagsSet( - furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit); + furi_thread_flags_set(furi_thread_get_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit); furi_thread_join(rpc_gui->transmit_thread); furi_thread_free(rpc_gui->transmit_thread); // Release frame @@ -367,8 +366,7 @@ void rpc_system_gui_free(void* context) { gui_remove_framebuffer_callback( rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context); // Stop and release worker thread - osThreadFlagsSet( - furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit); + furi_thread_flags_set(furi_thread_get_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit); furi_thread_join(rpc_gui->transmit_thread); furi_thread_free(rpc_gui->transmit_thread); // Release frame diff --git a/applications/subghz/helpers/subghz_chat.c b/applications/subghz/helpers/subghz_chat.c index e6b7b7bc..7a359165 100644 --- a/applications/subghz/helpers/subghz_chat.c +++ b/applications/subghz/helpers/subghz_chat.c @@ -92,7 +92,9 @@ bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency) { instance->worker_running = true; instance->last_time_rx_data = 0; - res = furi_thread_start(instance->thread); + furi_thread_start(instance->thread); + + res = true; } return res; } diff --git a/applications/u2f/u2f_hid.c b/applications/u2f/u2f_hid.c index a2b291d6..581feadb 100644 --- a/applications/u2f/u2f_hid.c +++ b/applications/u2f/u2f_hid.c @@ -72,18 +72,18 @@ static void u2f_hid_event_callback(HidU2fEvent ev, void* context) { U2fHid* u2f_hid = context; if(ev == HidU2fDisconnected) - osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtDisconnect); + furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtDisconnect); else if(ev == HidU2fConnected) - osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtConnect); + furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtConnect); else if(ev == HidU2fRequest) - osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtRequest); + furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtRequest); } static void u2f_hid_lock_timeout_callback(void* context) { furi_assert(context); U2fHid* u2f_hid = context; - osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtUnlock); + furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtUnlock); } static void u2f_hid_send_response(U2fHid* u2f_hid) { @@ -198,7 +198,7 @@ static int32_t u2f_hid_worker(void* context) { furi_hal_hid_u2f_set_callback(u2f_hid_event_callback, u2f_hid); while(1) { - uint32_t flags = osThreadFlagsWait( + uint32_t flags = furi_thread_flags_wait( WorkerEvtStop | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtRequest, osFlagsWaitAny, osWaitForever); @@ -292,7 +292,7 @@ U2fHid* u2f_hid_start(U2fData* u2f_inst) { void u2f_hid_stop(U2fHid* u2f_hid) { furi_assert(u2f_hid); - osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtStop); + furi_thread_flags_set(furi_thread_get_id(u2f_hid->thread), WorkerEvtStop); furi_thread_join(u2f_hid->thread); furi_thread_free(u2f_hid->thread); free(u2f_hid); diff --git a/applications/unit_tests/furi_valuemutex_test.c b/applications/unit_tests/furi_valuemutex_test.c index 4deb4f61..12613239 100644 --- a/applications/unit_tests/furi_valuemutex_test.c +++ b/applications/unit_tests/furi_valuemutex_test.c @@ -40,91 +40,3 @@ void test_furi_valuemutex() { mu_check(delete_mutex(&valuemutex)); } - -/* -TEST: concurrent access - -1. Create holding record -2. Open it twice -3. Change value simultaneously in two app and check integrity -*/ - -// TODO this test broke because mutex in furi is not implemented - -typedef struct { - // a and b must be equal - uint8_t a; - uint8_t b; -} ConcurrentValue; - -void furi_concurent_app(void* p) { - ValueMutex* mutex = (ValueMutex*)p; - if(mutex == NULL) { - printf("cannot open mutex\r\n"); - osThreadExit(); - } - - for(size_t i = 0; i < 10; i++) { - ConcurrentValue* value = (ConcurrentValue*)acquire_mutex_block(mutex); - - if(value == NULL) { - printf("cannot take record\r\n"); - release_mutex(mutex, value); - osThreadExit(); - } - - // emulate read-modify-write broken by context switching - uint8_t a = value->a; - uint8_t b = value->b; - a++; - b++; - furi_hal_delay_ms(2); - value->a = a; - value->b = b; - release_mutex(mutex, value); - } - - osThreadExit(); -} - -void test_furi_concurrent_access() { - // TODO: reimplement or delete test - return; - /* - // 1. Create holding record - ConcurrentValue value = {.a = 0, .b = 0}; - ValueMutex mutex; - mu_check(init_mutex(&mutex, &value, sizeof(value))); - - // 3. Create second app for interact with it - FuriApp* second_app = furiac_start(furi_concurent_app, "furi concurent app", (void*)&mutex); - - // 4. multiply ConcurrentValue::a - for(size_t i = 0; i < 4; i++) { - ConcurrentValue* value = (ConcurrentValue*)acquire_mutex_block(&mutex); - - if(value == NULL) { - release_mutex(&mutex, value); - mu_fail("cannot take record\r\n"); - } - - // emulate read-modify-write broken by context switching - uint8_t a = value->a; - uint8_t b = value->b; - a++; - b++; - value->a = a; - furi_hal_delay_ms(10); // this is only for test, do not add delay between take/give in prod! - value->b = b; - release_mutex(&mutex, value); - } - - furi_hal_delay_ms(50); - - mu_assert_pointers_eq(second_app->handler, NULL); - - mu_assert_int_eq(value.a, value.b); - - mu_check(delete_mutex(&mutex)); - */ -} diff --git a/applications/unit_tests/minunit_test.c b/applications/unit_tests/minunit_test.c index 1e71fd07..9d564df6 100644 --- a/applications/unit_tests/minunit_test.c +++ b/applications/unit_tests/minunit_test.c @@ -33,10 +33,6 @@ MU_TEST(mu_test_furi_valuemutex) { test_furi_valuemutex(); } -MU_TEST(mu_test_furi_concurrent_access) { - test_furi_concurrent_access(); -} - MU_TEST(mu_test_furi_pubsub) { test_furi_pubsub(); } @@ -55,7 +51,6 @@ MU_TEST_SUITE(test_suite) { // v2 tests MU_RUN_TEST(mu_test_furi_create_open); MU_RUN_TEST(mu_test_furi_valuemutex); - MU_RUN_TEST(mu_test_furi_concurrent_access); MU_RUN_TEST(mu_test_furi_pubsub); MU_RUN_TEST(mu_test_furi_memmgr); } diff --git a/applications/unit_tests/storage/storage_test.c b/applications/unit_tests/storage/storage_test.c index 9f237bd0..db78583d 100644 --- a/applications/unit_tests/storage/storage_test.c +++ b/applications/unit_tests/storage/storage_test.c @@ -49,7 +49,7 @@ MU_TEST(storage_file_open_lock) { furi_thread_set_stack_size(locker_thread, 2048); furi_thread_set_context(locker_thread, semaphore); furi_thread_set_callback(locker_thread, storage_file_locker); - mu_check(furi_thread_start(locker_thread)); + furi_thread_start(locker_thread); // wait for file lock osSemaphoreAcquire(semaphore, osWaitForever); @@ -139,7 +139,7 @@ MU_TEST(storage_dir_open_lock) { furi_thread_set_stack_size(locker_thread, 2048); furi_thread_set_context(locker_thread, semaphore); furi_thread_set_callback(locker_thread, storage_dir_locker); - mu_check(furi_thread_start(locker_thread)); + furi_thread_start(locker_thread); // wait for dir lock osSemaphoreAcquire(semaphore, osWaitForever); diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/unit_tests/subghz/subghz_test.c index c8f23780..680f199a 100644 --- a/applications/unit_tests/subghz/subghz_test.c +++ b/applications/unit_tests/subghz/subghz_test.c @@ -75,7 +75,7 @@ static bool subghz_decoder_test(const char* path, const char* name_decoder) { bool level = level_duration_get_level(level_duration); uint32_t duration = level_duration_get_duration(level_duration); // Yield, to load data inside the worker - osThreadYield(); + furi_thread_yield(); decoder->protocol->decoder->feed(decoder, level, duration); } else { break; @@ -115,7 +115,7 @@ static bool subghz_decode_random_test(const char* path) { bool level = level_duration_get_level(level_duration); uint32_t duration = level_duration_get_duration(level_duration); // Yield, to load data inside the worker - osThreadYield(); + furi_thread_yield(); subghz_receiver_decode(receiver_handler, level, duration); } else { break; diff --git a/applications/updater/util/update_task.c b/applications/updater/util/update_task.c index fd2344c1..58b0c975 100644 --- a/applications/updater/util/update_task.c +++ b/applications/updater/util/update_task.c @@ -324,9 +324,9 @@ void update_task_set_progress_cb(UpdateTask* update_task, updateProgressCb cb, v update_task->status_change_cb_state = state; } -bool update_task_start(UpdateTask* update_task) { +void update_task_start(UpdateTask* update_task) { furi_assert(update_task); - return furi_thread_start(update_task->thread); + furi_thread_start(update_task->thread); } bool update_task_is_running(UpdateTask* update_task) { diff --git a/applications/updater/util/update_task.h b/applications/updater/util/update_task.h index cfbbb850..ac9dadd6 100644 --- a/applications/updater/util/update_task.h +++ b/applications/updater/util/update_task.h @@ -74,7 +74,7 @@ void update_task_free(UpdateTask* update_task); void update_task_set_progress_cb(UpdateTask* update_task, updateProgressCb cb, void* state); -bool update_task_start(UpdateTask* update_task); +void update_task_start(UpdateTask* update_task); bool update_task_is_running(UpdateTask* update_task); diff --git a/core/furi.h b/core/furi.h index 6a0d1b0a..7a36c1ba 100644 --- a/core/furi.h +++ b/core/furi.h @@ -6,16 +6,19 @@ #include -#include #include +#include +#include +#include #include #include +#include #include #include +#include #include #include #include -#include #include diff --git a/core/furi/base.h b/core/furi/base.h new file mode 100644 index 00000000..41873fbd --- /dev/null +++ b/core/furi/base.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +// FreeRTOS part +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Timeout value. +#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value. + +// Flags options (\ref furi_thread_flags_wait and \ref osEventFlagsWait). +#define osFlagsWaitAny 0x00000000U ///< Wait for any flag (default). +#define osFlagsWaitAll 0x00000001U ///< Wait for all flags. +#define osFlagsNoClear 0x00000002U ///< Do not clear flags which have been specified to wait for. + +// Flags errors (returned by osThreadFlagsXxxx and osEventFlagsXxxx). +#define osFlagsError 0x80000000U ///< Error indicator. +#define osFlagsErrorUnknown 0xFFFFFFFFU ///< osError (-1). +#define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2). +#define osFlagsErrorResource 0xFFFFFFFDU ///< osErrorResource (-3). +#define osFlagsErrorParameter 0xFFFFFFFCU ///< osErrorParameter (-4). +#define osFlagsErrorISR 0xFFFFFFFAU ///< osErrorISR (-6). + +/// Status code values returned by CMSIS-RTOS functions. +typedef enum { + osOK = 0, ///< Operation completed successfully. + osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits. + osErrorTimeout = -2, ///< Operation not completed within the timeout period. + osErrorResource = -3, ///< Resource not available. + osErrorParameter = -4, ///< Parameter error. + osErrorNoMemory = + -5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation. + osErrorISR = + -6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines. + osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. +} osStatus_t; + +#ifdef __cplusplus +} +#endif diff --git a/core/furi/check.c b/core/furi/check.c index b59e490c..ca945ada 100644 --- a/core/furi/check.c +++ b/core/furi/check.c @@ -6,11 +6,14 @@ #include #include +#include +#include + void __furi_print_name() { if(FURI_IS_ISR()) { furi_hal_console_puts("[ISR] "); } else { - const char* name = osThreadGetName(osThreadGetId()); + const char* name = pcTaskGetName(xTaskGetCurrentTaskHandle()); if(name == NULL) { furi_hal_console_puts("[main] "); } else { diff --git a/core/furi/check.h b/core/furi/check.h index 4165c3c2..30efdf01 100644 --- a/core/furi/check.h +++ b/core/furi/check.h @@ -1,4 +1,5 @@ #pragma once + #ifdef __cplusplus extern "C" { #define FURI_NORETURN [[noreturn]] diff --git a/core/furi/event_flags.c b/core/furi/event_flags.c new file mode 100644 index 00000000..ba8cba48 --- /dev/null +++ b/core/furi/event_flags.c @@ -0,0 +1,222 @@ +#include "event_flags.h" +#include "common_defines.h" + +#include + +#define MAX_BITS_EVENT_GROUPS 24U +#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U)) + +osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t* attr) { + EventGroupHandle_t hEventGroup; + int32_t mem; + + hEventGroup = NULL; + + if(FURI_IS_IRQ_MODE() == 0U) { + mem = -1; + + if(attr != NULL) { + if((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticEventGroup_t))) { + /* The memory for control block is provided, use static object */ + mem = 1; + } else { + if((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { + /* Control block will be allocated from the dynamic pool */ + mem = 0; + } + } + } else { + mem = 0; + } + + if(mem == 1) { +#if(configSUPPORT_STATIC_ALLOCATION == 1) + hEventGroup = xEventGroupCreateStatic(attr->cb_mem); +#endif + } else { + if(mem == 0) { +#if(configSUPPORT_DYNAMIC_ALLOCATION == 1) + hEventGroup = xEventGroupCreate(); +#endif + } + } + } + + /* Return event flags ID */ + return ((osEventFlagsId_t)hEventGroup); +} + +/* + Set the specified Event Flags. + + Limitations: + - Event flags are limited to 24 bits. +*/ +uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) { + EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; + uint32_t rflags; + BaseType_t yield; + + if((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { + rflags = (uint32_t)osErrorParameter; + } else if(FURI_IS_IRQ_MODE() != 0U) { +#if(configUSE_OS2_EVENTFLAGS_FROM_ISR == 0) + (void)yield; + /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */ + rflags = (uint32_t)osErrorResource; +#else + yield = pdFALSE; + + if(xEventGroupSetBitsFromISR(hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) { + rflags = (uint32_t)osErrorResource; + } else { + rflags = flags; + portYIELD_FROM_ISR(yield); + } +#endif + } else { + rflags = xEventGroupSetBits(hEventGroup, (EventBits_t)flags); + } + + /* Return event flags after setting */ + return (rflags); +} + +/* + Clear the specified Event Flags. + + Limitations: + - Event flags are limited to 24 bits. +*/ +uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) { + EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; + uint32_t rflags; + + if((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { + rflags = (uint32_t)osErrorParameter; + } else if(FURI_IS_IRQ_MODE() != 0U) { +#if(configUSE_OS2_EVENTFLAGS_FROM_ISR == 0) + /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */ + rflags = (uint32_t)osErrorResource; +#else + rflags = xEventGroupGetBitsFromISR(hEventGroup); + + if(xEventGroupClearBitsFromISR(hEventGroup, (EventBits_t)flags) == pdFAIL) { + rflags = (uint32_t)osErrorResource; + } else { + /* xEventGroupClearBitsFromISR only registers clear operation in the timer command queue. */ + /* Yield is required here otherwise clear operation might not execute in the right order. */ + /* See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/93 for more info. */ + portYIELD_FROM_ISR(pdTRUE); + } +#endif + } else { + rflags = xEventGroupClearBits(hEventGroup, (EventBits_t)flags); + } + + /* Return event flags before clearing */ + return (rflags); +} + +/* + Get the current Event Flags. + + Limitations: + - Event flags are limited to 24 bits. +*/ +uint32_t osEventFlagsGet(osEventFlagsId_t ef_id) { + EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; + uint32_t rflags; + + if(ef_id == NULL) { + rflags = 0U; + } else if(FURI_IS_IRQ_MODE() != 0U) { + rflags = xEventGroupGetBitsFromISR(hEventGroup); + } else { + rflags = xEventGroupGetBits(hEventGroup); + } + + /* Return current event flags */ + return (rflags); +} + +/* + Wait for one or more Event Flags to become signaled. + + Limitations: + - Event flags are limited to 24 bits. + - osEventFlagsWait cannot be called from an ISR. +*/ +uint32_t + osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) { + EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; + BaseType_t wait_all; + BaseType_t exit_clr; + uint32_t rflags; + + if((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { + rflags = (uint32_t)osErrorParameter; + } else if(FURI_IS_IRQ_MODE() != 0U) { + rflags = (uint32_t)osErrorISR; + } else { + if(options & osFlagsWaitAll) { + wait_all = pdTRUE; + } else { + wait_all = pdFAIL; + } + + if(options & osFlagsNoClear) { + exit_clr = pdFAIL; + } else { + exit_clr = pdTRUE; + } + + rflags = xEventGroupWaitBits( + hEventGroup, (EventBits_t)flags, exit_clr, wait_all, (TickType_t)timeout); + + if(options & osFlagsWaitAll) { + if((flags & rflags) != flags) { + if(timeout > 0U) { + rflags = (uint32_t)osErrorTimeout; + } else { + rflags = (uint32_t)osErrorResource; + } + } + } else { + if((flags & rflags) == 0U) { + if(timeout > 0U) { + rflags = (uint32_t)osErrorTimeout; + } else { + rflags = (uint32_t)osErrorResource; + } + } + } + } + + /* Return event flags before clearing */ + return (rflags); +} + +/* + Delete an Event Flags object. +*/ +osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) { + EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; + osStatus_t stat; + +#ifndef USE_FreeRTOS_HEAP_1 + if(FURI_IS_IRQ_MODE() != 0U) { + stat = osErrorISR; + } else if(hEventGroup == NULL) { + stat = osErrorParameter; + } else { + stat = osOK; + vEventGroupDelete(hEventGroup); + } +#else + stat = osError; +#endif + + /* Return execution status */ + return (stat); +} diff --git a/core/furi/event_flags.h b/core/furi/event_flags.h new file mode 100644 index 00000000..66aa2d7a --- /dev/null +++ b/core/furi/event_flags.h @@ -0,0 +1,63 @@ +#pragma once + +#include "base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Attributes structure for event flags. +typedef struct { + const char* name; ///< name of the event flags + uint32_t attr_bits; ///< attribute bits + void* cb_mem; ///< memory for control block + uint32_t cb_size; ///< size of provided memory for control block +} osEventFlagsAttr_t; + +/// \details Event Flags ID identifies the event flags. +typedef void* osEventFlagsId_t; + +/// Create and Initialize an Event Flags object. +/// \param[in] attr event flags attributes; NULL: default values. +/// \return event flags ID for reference by other functions or NULL in case of error. +osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t* attr); + +/// Get name of an Event Flags object. +/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. +/// \return name as null-terminated string. +const char* osEventFlagsGetName(osEventFlagsId_t ef_id); + +/// Set the specified Event Flags. +/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. +/// \param[in] flags specifies the flags that shall be set. +/// \return event flags after setting or error code if highest bit set. +uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags); + +/// Clear the specified Event Flags. +/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. +/// \param[in] flags specifies the flags that shall be cleared. +/// \return event flags before clearing or error code if highest bit set. +uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags); + +/// Get the current Event Flags. +/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. +/// \return current event flags. +uint32_t osEventFlagsGet(osEventFlagsId_t ef_id); + +/// Wait for one or more Event Flags to become signaled. +/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. +/// \param[in] flags specifies the flags to wait for. +/// \param[in] options specifies flags options (osFlagsXxxx). +/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. +/// \return event flags before clearing or error code if highest bit set. +uint32_t + osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout); + +/// Delete an Event Flags object. +/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. +/// \return status code that indicates the execution status of the function. +osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id); + +#ifdef __cplusplus +} +#endif diff --git a/core/furi/log.c b/core/furi/log.c index 9ce025b9..4653603c 100644 --- a/core/furi/log.c +++ b/core/furi/log.c @@ -1,5 +1,6 @@ #include "log.h" #include "check.h" +#include "mutex.h" #include #include diff --git a/core/furi/memmgr_heap.c b/core/furi/memmgr_heap.c index 618d7e74..92e99b92 100644 --- a/core/furi/memmgr_heap.c +++ b/core/furi/memmgr_heap.c @@ -133,7 +133,7 @@ void memmgr_heap_init() { MemmgrHeapThreadDict_init(memmgr_heap_thread_dict); } -void memmgr_heap_enable_thread_trace(osThreadId_t thread_id) { +void memmgr_heap_enable_thread_trace(FuriThreadId thread_id) { vTaskSuspendAll(); { memmgr_heap_thread_trace_depth++; @@ -147,7 +147,7 @@ void memmgr_heap_enable_thread_trace(osThreadId_t thread_id) { (void)xTaskResumeAll(); } -void memmgr_heap_disable_thread_trace(osThreadId_t thread_id) { +void memmgr_heap_disable_thread_trace(FuriThreadId thread_id) { vTaskSuspendAll(); { memmgr_heap_thread_trace_depth++; @@ -158,7 +158,7 @@ void memmgr_heap_disable_thread_trace(osThreadId_t thread_id) { (void)xTaskResumeAll(); } -size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id) { +size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) { size_t leftovers = MEMMGR_HEAP_UNKNOWN; vTaskSuspendAll(); { @@ -192,7 +192,7 @@ size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id) { #undef traceMALLOC static inline void traceMALLOC(void* pointer, size_t size) { - osThreadId_t thread_id = osThreadGetId(); + FuriThreadId thread_id = furi_thread_get_current_id(); if(thread_id && memmgr_heap_thread_trace_depth == 0) { memmgr_heap_thread_trace_depth++; MemmgrHeapAllocDict_t* alloc_dict = @@ -207,7 +207,7 @@ static inline void traceMALLOC(void* pointer, size_t size) { #undef traceFREE static inline void traceFREE(void* pointer, size_t size) { UNUSED(size); - osThreadId_t thread_id = osThreadGetId(); + FuriThreadId thread_id = furi_thread_get_current_id(); if(thread_id && memmgr_heap_thread_trace_depth == 0) { memmgr_heap_thread_trace_depth++; MemmgrHeapAllocDict_t* alloc_dict = @@ -297,7 +297,7 @@ static void print_heap_init() { static void print_heap_malloc(void* ptr, size_t size) { char tmp_str[33]; - const char* name = osThreadGetName(osThreadGetId()); + const char* name = furi_thread_get_name(furi_thread_get_current_id()); if(!name) { name = ""; } @@ -318,7 +318,7 @@ static void print_heap_malloc(void* ptr, size_t size) { static void print_heap_free(void* ptr) { char tmp_str[33]; - const char* name = osThreadGetName(osThreadGetId()); + const char* name = furi_thread_get_name(furi_thread_get_current_id()); if(!name) { name = ""; } diff --git a/core/furi/memmgr_heap.h b/core/furi/memmgr_heap.h index 04dced06..f76102ec 100644 --- a/core/furi/memmgr_heap.h +++ b/core/furi/memmgr_heap.h @@ -6,7 +6,7 @@ #pragma once #include -#include +#include "furi/thread.h" #ifdef __cplusplus extern "C" { @@ -18,13 +18,13 @@ extern "C" { * * @param thread_id - thread id to track */ -void memmgr_heap_enable_thread_trace(osThreadId_t thread_id); +void memmgr_heap_enable_thread_trace(FuriThreadId taks_handle); /** Memmgr heap disable thread allocation tracking * * @param thread_id - thread id to track */ -void memmgr_heap_disable_thread_trace(osThreadId_t thread_id); +void memmgr_heap_disable_thread_trace(FuriThreadId taks_handle); /** Memmgr heap get allocatred thread memory * @@ -32,7 +32,7 @@ void memmgr_heap_disable_thread_trace(osThreadId_t thread_id); * * @return bytes allocated right now */ -size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id); +size_t memmgr_heap_get_thread_memory(FuriThreadId taks_handle); /** Memmgr heap get the max contiguous block size on the heap * diff --git a/core/furi/mutex.c b/core/furi/mutex.c new file mode 100644 index 00000000..42f1d528 --- /dev/null +++ b/core/furi/mutex.c @@ -0,0 +1,217 @@ +#include "mutex.h" +#include "check.h" +#include "common_defines.h" + +#include + +osMutexId_t osMutexNew(const osMutexAttr_t* attr) { + SemaphoreHandle_t hMutex; + uint32_t type; + uint32_t rmtx; + int32_t mem; + + hMutex = NULL; + + if(FURI_IS_IRQ_MODE() == 0U) { + if(attr != NULL) { + type = attr->attr_bits; + } else { + type = 0U; + } + + if((type & osMutexRecursive) == osMutexRecursive) { + rmtx = 1U; + } else { + rmtx = 0U; + } + + if((type & osMutexRobust) != osMutexRobust) { + mem = -1; + + if(attr != NULL) { + if((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) { + /* The memory for control block is provided, use static object */ + mem = 1; + } else { + if((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { + /* Control block will be allocated from the dynamic pool */ + mem = 0; + } + } + } else { + mem = 0; + } + + if(mem == 1) { +#if(configSUPPORT_STATIC_ALLOCATION == 1) + if(rmtx != 0U) { +#if(configUSE_RECURSIVE_MUTEXES == 1) + hMutex = xSemaphoreCreateRecursiveMutexStatic(attr->cb_mem); +#endif + } else { + hMutex = xSemaphoreCreateMutexStatic(attr->cb_mem); + } +#endif + } else { + if(mem == 0) { +#if(configSUPPORT_DYNAMIC_ALLOCATION == 1) + if(rmtx != 0U) { +#if(configUSE_RECURSIVE_MUTEXES == 1) + hMutex = xSemaphoreCreateRecursiveMutex(); +#endif + } else { + hMutex = xSemaphoreCreateMutex(); + } +#endif + } + } + +#if(configQUEUE_REGISTRY_SIZE > 0) + if(hMutex != NULL) { + if((attr != NULL) && (attr->name != NULL)) { + /* Only non-NULL name objects are added to the Queue Registry */ + vQueueAddToRegistry(hMutex, attr->name); + } + } +#endif + + if((hMutex != NULL) && (rmtx != 0U)) { + /* Set LSB as 'recursive mutex flag' */ + hMutex = (SemaphoreHandle_t)((uint32_t)hMutex | 1U); + } + } + } + + /* Return mutex ID */ + return ((osMutexId_t)hMutex); +} + +/* + Acquire a Mutex or timeout if it is locked. +*/ +osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout) { + SemaphoreHandle_t hMutex; + osStatus_t stat; + uint32_t rmtx; + + hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); + + /* Extract recursive mutex flag */ + rmtx = (uint32_t)mutex_id & 1U; + + stat = osOK; + + if(FURI_IS_IRQ_MODE() != 0U) { + stat = osErrorISR; + } else if(hMutex == NULL) { + stat = osErrorParameter; + } else { + if(rmtx != 0U) { +#if(configUSE_RECURSIVE_MUTEXES == 1) + if(xSemaphoreTakeRecursive(hMutex, timeout) != pdPASS) { + if(timeout != 0U) { + stat = osErrorTimeout; + } else { + stat = osErrorResource; + } + } +#endif + } else { + if(xSemaphoreTake(hMutex, timeout) != pdPASS) { + if(timeout != 0U) { + stat = osErrorTimeout; + } else { + stat = osErrorResource; + } + } + } + } + + /* Return execution status */ + return (stat); +} + +/* + Release a Mutex that was acquired by osMutexAcquire. +*/ +osStatus_t osMutexRelease(osMutexId_t mutex_id) { + SemaphoreHandle_t hMutex; + osStatus_t stat; + uint32_t rmtx; + + hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); + + /* Extract recursive mutex flag */ + rmtx = (uint32_t)mutex_id & 1U; + + stat = osOK; + + if(FURI_IS_IRQ_MODE() != 0U) { + stat = osErrorISR; + } else if(hMutex == NULL) { + stat = osErrorParameter; + } else { + if(rmtx != 0U) { +#if(configUSE_RECURSIVE_MUTEXES == 1) + if(xSemaphoreGiveRecursive(hMutex) != pdPASS) { + stat = osErrorResource; + } +#endif + } else { + if(xSemaphoreGive(hMutex) != pdPASS) { + stat = osErrorResource; + } + } + } + + /* Return execution status */ + return (stat); +} + +/* + Get Thread which owns a Mutex object. +*/ +FuriThreadId osMutexGetOwner(osMutexId_t mutex_id) { + SemaphoreHandle_t hMutex; + FuriThreadId owner; + + hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); + + if((FURI_IS_IRQ_MODE() != 0U) || (hMutex == NULL)) { + owner = 0; + } else { + owner = (FuriThreadId)xSemaphoreGetMutexHolder(hMutex); + } + + /* Return owner thread ID */ + return (owner); +} + +/* + Delete a Mutex object. +*/ +osStatus_t osMutexDelete(osMutexId_t mutex_id) { + osStatus_t stat; +#ifndef USE_FreeRTOS_HEAP_1 + SemaphoreHandle_t hMutex; + + hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); + + if(FURI_IS_IRQ_MODE() != 0U) { + stat = osErrorISR; + } else if(hMutex == NULL) { + stat = osErrorParameter; + } else { +#if(configQUEUE_REGISTRY_SIZE > 0) + vQueueUnregisterQueue(hMutex); +#endif + stat = osOK; + vSemaphoreDelete(hMutex); + } +#else + stat = osError; +#endif + + /* Return execution status */ + return (stat); +} diff --git a/core/furi/mutex.h b/core/furi/mutex.h new file mode 100644 index 00000000..44f351b7 --- /dev/null +++ b/core/furi/mutex.h @@ -0,0 +1,56 @@ +#pragma once + +#include "base.h" +#include "thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Mutex attributes (attr_bits in \ref osMutexAttr_t). +#define osMutexRecursive 0x00000001U ///< Recursive mutex. +#define osMutexPrioInherit 0x00000002U ///< Priority inherit protocol. +#define osMutexRobust 0x00000008U ///< Robust mutex. + +/// Attributes structure for mutex. +typedef struct { + const char* name; ///< name of the mutex + uint32_t attr_bits; ///< attribute bits + void* cb_mem; ///< memory for control block + uint32_t cb_size; ///< size of provided memory for control block +} osMutexAttr_t; + +/// \details Mutex ID identifies the mutex. +typedef void* osMutexId_t; + +/// Create and Initialize a Mutex object. +/// \param[in] attr mutex attributes; NULL: default values. +/// \return mutex ID for reference by other functions or NULL in case of error. +osMutexId_t osMutexNew(const osMutexAttr_t* attr); + +/// Get name of a Mutex object. +/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. +/// \return name as null-terminated string. +const char* osMutexGetName(osMutexId_t mutex_id); + +/// Acquire a Mutex or timeout if it is locked. +/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. +/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. +/// \return status code that indicates the execution status of the function. +osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout); + +/// Release a Mutex that was acquired by \ref osMutexAcquire. +/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. +/// \return status code that indicates the execution status of the function. +osStatus_t osMutexRelease(osMutexId_t mutex_id); + +/// Delete a Mutex object. +/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. +/// \return status code that indicates the execution status of the function. +osStatus_t osMutexDelete(osMutexId_t mutex_id); + +FuriThreadId osMutexGetOwner(osMutexId_t mutex_id); + +#ifdef __cplusplus +} +#endif diff --git a/core/furi/pubsub.c b/core/furi/pubsub.c index 8e9adda8..88839ec2 100644 --- a/core/furi/pubsub.c +++ b/core/furi/pubsub.c @@ -1,9 +1,9 @@ #include "pubsub.h" #include "memmgr.h" #include "check.h" +#include "mutex.h" #include -#include struct FuriPubSubSubscription { FuriPubSubCallback callback; diff --git a/core/furi/record.c b/core/furi/record.c index 501091d4..d7afbf9c 100644 --- a/core/furi/record.c +++ b/core/furi/record.c @@ -1,8 +1,9 @@ #include "record.h" #include "check.h" #include "memmgr.h" +#include "mutex.h" +#include "event_flags.h" -#include #include #include diff --git a/core/furi/semaphore.c b/core/furi/semaphore.c new file mode 100644 index 00000000..cbacdef0 --- /dev/null +++ b/core/furi/semaphore.c @@ -0,0 +1,190 @@ +#include "semaphore.h" +#include "check.h" +#include "common_defines.h" + +#include + +osSemaphoreId_t + osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t* attr) { + SemaphoreHandle_t hSemaphore; + int32_t mem; + + hSemaphore = NULL; + + if((FURI_IS_IRQ_MODE() == 0U) && (max_count > 0U) && (initial_count <= max_count)) { + mem = -1; + + if(attr != NULL) { + if((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) { + /* The memory for control block is provided, use static object */ + mem = 1; + } else { + if((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { + /* Control block will be allocated from the dynamic pool */ + mem = 0; + } + } + } else { + mem = 0; + } + + if(mem != -1) { + if(max_count == 1U) { + if(mem == 1) { +#if(configSUPPORT_STATIC_ALLOCATION == 1) + hSemaphore = xSemaphoreCreateBinaryStatic((StaticSemaphore_t*)attr->cb_mem); +#endif + } else { +#if(configSUPPORT_DYNAMIC_ALLOCATION == 1) + hSemaphore = xSemaphoreCreateBinary(); +#endif + } + + if((hSemaphore != NULL) && (initial_count != 0U)) { + if(xSemaphoreGive(hSemaphore) != pdPASS) { + vSemaphoreDelete(hSemaphore); + hSemaphore = NULL; + } + } + } else { + if(mem == 1) { +#if(configSUPPORT_STATIC_ALLOCATION == 1) + hSemaphore = xSemaphoreCreateCountingStatic( + max_count, initial_count, (StaticSemaphore_t*)attr->cb_mem); +#endif + } else { +#if(configSUPPORT_DYNAMIC_ALLOCATION == 1) + hSemaphore = xSemaphoreCreateCounting(max_count, initial_count); +#endif + } + } + +#if(configQUEUE_REGISTRY_SIZE > 0) + if(hSemaphore != NULL) { + if((attr != NULL) && (attr->name != NULL)) { + /* Only non-NULL name objects are added to the Queue Registry */ + vQueueAddToRegistry(hSemaphore, attr->name); + } + } +#endif + } + } + + /* Return semaphore ID */ + return ((osSemaphoreId_t)hSemaphore); +} + +/* + Acquire a Semaphore token or timeout if no tokens are available. +*/ +osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout) { + SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; + osStatus_t stat; + BaseType_t yield; + + stat = osOK; + + if(hSemaphore == NULL) { + stat = osErrorParameter; + } else if(FURI_IS_IRQ_MODE() != 0U) { + if(timeout != 0U) { + stat = osErrorParameter; + } else { + yield = pdFALSE; + + if(xSemaphoreTakeFromISR(hSemaphore, &yield) != pdPASS) { + stat = osErrorResource; + } else { + portYIELD_FROM_ISR(yield); + } + } + } else { + if(xSemaphoreTake(hSemaphore, (TickType_t)timeout) != pdPASS) { + if(timeout != 0U) { + stat = osErrorTimeout; + } else { + stat = osErrorResource; + } + } + } + + /* Return execution status */ + return (stat); +} + +/* + Release a Semaphore token up to the initial maximum count. +*/ +osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id) { + SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; + osStatus_t stat; + BaseType_t yield; + + stat = osOK; + + if(hSemaphore == NULL) { + stat = osErrorParameter; + } else if(FURI_IS_IRQ_MODE() != 0U) { + yield = pdFALSE; + + if(xSemaphoreGiveFromISR(hSemaphore, &yield) != pdTRUE) { + stat = osErrorResource; + } else { + portYIELD_FROM_ISR(yield); + } + } else { + if(xSemaphoreGive(hSemaphore) != pdPASS) { + stat = osErrorResource; + } + } + + /* Return execution status */ + return (stat); +} + +/* + Get current Semaphore token count. +*/ +uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id) { + SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; + uint32_t count; + + if(hSemaphore == NULL) { + count = 0U; + } else if(FURI_IS_IRQ_MODE() != 0U) { + count = (uint32_t)uxSemaphoreGetCountFromISR(hSemaphore); + } else { + count = (uint32_t)uxSemaphoreGetCount(hSemaphore); + } + + /* Return number of tokens */ + return (count); +} + +/* + Delete a Semaphore object. +*/ +osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id) { + SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; + osStatus_t stat; + +#ifndef USE_FreeRTOS_HEAP_1 + if(FURI_IS_IRQ_MODE() != 0U) { + stat = osErrorISR; + } else if(hSemaphore == NULL) { + stat = osErrorParameter; + } else { +#if(configQUEUE_REGISTRY_SIZE > 0) + vQueueUnregisterQueue(hSemaphore); +#endif + + stat = osOK; + vSemaphoreDelete(hSemaphore); + } +#else + stat = osError; +#endif + + /* Return execution status */ + return (stat); +} diff --git a/core/furi/semaphore.h b/core/furi/semaphore.h new file mode 100644 index 00000000..b4de78fd --- /dev/null +++ b/core/furi/semaphore.h @@ -0,0 +1,57 @@ +#pragma once + +#include "base.h" +#include "thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Attributes structure for semaphore. +typedef struct { + const char* name; ///< name of the semaphore + uint32_t attr_bits; ///< attribute bits + void* cb_mem; ///< memory for control block + uint32_t cb_size; ///< size of provided memory for control block +} osSemaphoreAttr_t; + +/// \details Semaphore ID identifies the semaphore. +typedef void* osSemaphoreId_t; + +/// Create and Initialize a Semaphore object. +/// \param[in] max_count maximum number of available tokens. +/// \param[in] initial_count initial number of available tokens. +/// \param[in] attr semaphore attributes; NULL: default values. +/// \return semaphore ID for reference by other functions or NULL in case of error. +osSemaphoreId_t + osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t* attr); + +/// Get name of a Semaphore object. +/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. +/// \return name as null-terminated string. +const char* osSemaphoreGetName(osSemaphoreId_t semaphore_id); + +/// Acquire a Semaphore token or timeout if no tokens are available. +/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. +/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. +/// \return status code that indicates the execution status of the function. +osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout); + +/// Release a Semaphore token up to the initial maximum count. +/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. +/// \return status code that indicates the execution status of the function. +osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id); + +/// Get current Semaphore token count. +/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. +/// \return number of tokens available. +uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id); + +/// Delete a Semaphore object. +/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. +/// \return status code that indicates the execution status of the function. +osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id); + +#ifdef __cplusplus +} +#endif diff --git a/core/furi/stdglue.c b/core/furi/stdglue.c index 1eccafc9..8c1d0813 100644 --- a/core/furi/stdglue.c +++ b/core/furi/stdglue.c @@ -26,13 +26,13 @@ static ssize_t stdout_write(void* _cookie, const char* data, size_t size) { furi_assert(furi_stdglue); bool consumed = false; osKernelState_t state = osKernelGetState(); - osThreadId_t thread_id = osThreadGetId(); - if(state == osKernelRunning && thread_id && + FuriThreadId task_id = furi_thread_get_current_id(); + if(state == osKernelRunning && task_id && osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK) { // We are in the thread context // Handle thread callbacks FuriStdglueWriteCallback* callback_ptr = - FuriStdglueCallbackDict_get(furi_stdglue->thread_outputs, (uint32_t)thread_id); + FuriStdglueCallbackDict_get(furi_stdglue->thread_outputs, (uint32_t)task_id); if(callback_ptr) { (*callback_ptr)(_cookie, data, size); consumed = true; @@ -76,14 +76,14 @@ void furi_stdglue_init() { bool furi_stdglue_set_thread_stdout_callback(FuriStdglueWriteCallback callback) { furi_assert(furi_stdglue); - osThreadId_t thread_id = osThreadGetId(); - if(thread_id) { + FuriThreadId task_id = furi_thread_get_current_id(); + if(task_id) { furi_check(osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK); if(callback) { FuriStdglueCallbackDict_set_at( - furi_stdglue->thread_outputs, (uint32_t)thread_id, callback); + furi_stdglue->thread_outputs, (uint32_t)task_id, callback); } else { - FuriStdglueCallbackDict_erase(furi_stdglue->thread_outputs, (uint32_t)thread_id); + FuriStdglueCallbackDict_erase(furi_stdglue->thread_outputs, (uint32_t)task_id); } furi_check(osMutexRelease(furi_stdglue->mutex) == osOK); return true; diff --git a/core/furi/thread.c b/core/furi/thread.c index a2898c1a..692e5e05 100644 --- a/core/furi/thread.c +++ b/core/furi/thread.c @@ -2,7 +2,9 @@ #include "memmgr.h" #include "memmgr_heap.h" #include "check.h" +#include "common_defines.h" +#include #include struct FuriThread { @@ -15,14 +17,22 @@ struct FuriThread { FuriThreadStateCallback state_callback; void* state_context; - osThreadAttr_t attr; - volatile osThreadId_t id; + char* name; + configSTACK_DEPTH_TYPE stack_size; + FuriThreadPriority priority; + TaskHandle_t task_handle; bool heap_trace_enabled; size_t heap_size; }; -void furi_thread_set_state(FuriThread* thread, FuriThreadState state) { +/** Catch threads that are trying to exit wrong way */ +__attribute__((__noreturn__)) void furi_thread_catch() { + asm volatile("nop"); // extra magic + furi_crash("You are doing it wrong"); +} + +static void furi_thread_set_state(FuriThread* thread, FuriThreadState state) { furi_assert(thread); thread->state = state; if(thread->state_callback) { @@ -37,23 +47,24 @@ static void furi_thread_body(void* context) { furi_assert(thread->state == FuriThreadStateStarting); furi_thread_set_state(thread, FuriThreadStateRunning); - osThreadId_t thread_id = osThreadGetId(); + TaskHandle_t task_handle = xTaskGetCurrentTaskHandle(); if(thread->heap_trace_enabled == true) { - memmgr_heap_enable_thread_trace(thread_id); + memmgr_heap_enable_thread_trace((FuriThreadId)task_handle); } thread->ret = thread->callback(thread->context); if(thread->heap_trace_enabled == true) { osDelay(33); - thread->heap_size = memmgr_heap_get_thread_memory(thread_id); - memmgr_heap_disable_thread_trace(thread_id); + thread->heap_size = memmgr_heap_get_thread_memory((FuriThreadId)task_handle); + memmgr_heap_disable_thread_trace((FuriThreadId)task_handle); } furi_assert(thread->state == FuriThreadStateRunning); furi_thread_set_state(thread, FuriThreadStateStopped); - osThreadExit(); + vTaskDelete(thread->task_handle); + furi_thread_catch(); } FuriThread* furi_thread_alloc() { @@ -66,21 +77,22 @@ void furi_thread_free(FuriThread* thread) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->attr.name) free((void*)thread->attr.name); + if(thread->name) free((void*)thread->name); free(thread); } void furi_thread_set_name(FuriThread* thread, const char* name) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - if(thread->attr.name) free((void*)thread->attr.name); - thread->attr.name = strdup(name); + if(thread->name) free((void*)thread->name); + thread->name = strdup(name); } void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); - thread->attr.stack_size = stack_size; + furi_assert(stack_size % 4 == 0); + thread->stack_size = stack_size; } void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback) { @@ -95,6 +107,13 @@ void furi_thread_set_context(FuriThread* thread, void* context) { thread->context = context; } +void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority) { + furi_assert(thread); + furi_assert(thread->state == FuriThreadStateStopped); + furi_assert(priority >= FuriThreadPriorityIdle && priority <= FuriThreadPriorityIsr); + thread->priority = priority; +} + void furi_thread_set_state_callback(FuriThread* thread, FuriThreadStateCallback callback) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); @@ -112,41 +131,39 @@ FuriThreadState furi_thread_get_state(FuriThread* thread) { return thread->state; } -bool furi_thread_start(FuriThread* thread) { +void furi_thread_start(FuriThread* thread) { furi_assert(thread); furi_assert(thread->callback); furi_assert(thread->state == FuriThreadStateStopped); - furi_assert(thread->attr.stack_size > 0); + furi_assert(thread->stack_size > 0 && thread->stack_size < 0xFFFF * 4); + furi_thread_set_state(thread, FuriThreadStateStarting); - thread->id = osThreadNew(furi_thread_body, thread, &thread->attr); - if(thread->id) { - return true; - } else { - furi_assert(thread->state == FuriThreadStateStarting); - furi_thread_set_state(thread, FuriThreadStateStopped); - return false; - } + + BaseType_t ret = xTaskCreate( + furi_thread_body, + thread->name, + thread->stack_size / 4, + thread, + thread->priority ? thread->priority : FuriThreadPriorityNormal, + &thread->task_handle); + + furi_check(ret == pdPASS); + furi_check(thread->task_handle); } -osStatus_t furi_thread_terminate(FuriThread* thread) { +bool furi_thread_join(FuriThread* thread) { furi_assert(thread); - osStatus_t ret = osThreadTerminate(thread->id); - if(ret == osOK) { - furi_thread_set_state(thread, FuriThreadStateStopped); - } - return ret; -} -osStatus_t furi_thread_join(FuriThread* thread) { - furi_assert(thread); while(thread->state != FuriThreadStateStopped) { osDelay(10); } + return osOK; } -osThreadId_t furi_thread_get_thread_id(FuriThread* thread) { - return thread->id; +FuriThreadId furi_thread_get_id(FuriThread* thread) { + furi_assert(thread); + return thread->task_handle; } void furi_thread_enable_heap_trace(FuriThread* thread) { @@ -174,3 +191,213 @@ int32_t furi_thread_get_return_code(FuriThread* thread) { furi_assert(thread->state == FuriThreadStateStopped); return thread->ret; } + +FuriThreadId furi_thread_get_current_id() { + return xTaskGetCurrentTaskHandle(); +} + +void furi_thread_yield() { + furi_assert(!FURI_IS_IRQ_MODE()); + taskYIELD(); +} + +/* Limits */ +#define MAX_BITS_TASK_NOTIFY 31U +#define MAX_BITS_EVENT_GROUPS 24U + +#define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U)) +#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U)) + +uint32_t furi_thread_flags_set(FuriThreadId thread_id, uint32_t flags) { + TaskHandle_t hTask = (TaskHandle_t)thread_id; + uint32_t rflags; + BaseType_t yield; + + if((hTask == NULL) || ((flags & THREAD_FLAGS_INVALID_BITS) != 0U)) { + rflags = (uint32_t)osErrorParameter; + } else { + rflags = (uint32_t)osError; + + if(FURI_IS_IRQ_MODE()) { + yield = pdFALSE; + + (void)xTaskNotifyFromISR(hTask, flags, eSetBits, &yield); + (void)xTaskNotifyAndQueryFromISR(hTask, 0, eNoAction, &rflags, NULL); + + portYIELD_FROM_ISR(yield); + } else { + (void)xTaskNotify(hTask, flags, eSetBits); + (void)xTaskNotifyAndQuery(hTask, 0, eNoAction, &rflags); + } + } + /* Return flags after setting */ + return (rflags); +} + +uint32_t furi_thread_flags_clear(uint32_t flags) { + TaskHandle_t hTask; + uint32_t rflags, cflags; + + if(FURI_IS_IRQ_MODE()) { + rflags = (uint32_t)osErrorISR; + } else if((flags & THREAD_FLAGS_INVALID_BITS) != 0U) { + rflags = (uint32_t)osErrorParameter; + } else { + hTask = xTaskGetCurrentTaskHandle(); + + if(xTaskNotifyAndQuery(hTask, 0, eNoAction, &cflags) == pdPASS) { + rflags = cflags; + cflags &= ~flags; + + if(xTaskNotify(hTask, cflags, eSetValueWithOverwrite) != pdPASS) { + rflags = (uint32_t)osError; + } + } else { + rflags = (uint32_t)osError; + } + } + + /* Return flags before clearing */ + return (rflags); +} + +uint32_t furi_thread_flags_get(void) { + TaskHandle_t hTask; + uint32_t rflags; + + if(FURI_IS_IRQ_MODE()) { + rflags = (uint32_t)osErrorISR; + } else { + hTask = xTaskGetCurrentTaskHandle(); + + if(xTaskNotifyAndQuery(hTask, 0, eNoAction, &rflags) != pdPASS) { + rflags = (uint32_t)osError; + } + } + + return (rflags); +} + +uint32_t furi_thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout) { + uint32_t rflags, nval; + uint32_t clear; + TickType_t t0, td, tout; + BaseType_t rval; + + if(FURI_IS_IRQ_MODE()) { + rflags = (uint32_t)osErrorISR; + } else if((flags & THREAD_FLAGS_INVALID_BITS) != 0U) { + rflags = (uint32_t)osErrorParameter; + } else { + if((options & osFlagsNoClear) == osFlagsNoClear) { + clear = 0U; + } else { + clear = flags; + } + + rflags = 0U; + tout = timeout; + + t0 = xTaskGetTickCount(); + do { + rval = xTaskNotifyWait(0, clear, &nval, tout); + + if(rval == pdPASS) { + rflags &= flags; + rflags |= nval; + + if((options & osFlagsWaitAll) == osFlagsWaitAll) { + if((flags & rflags) == flags) { + break; + } else { + if(timeout == 0U) { + rflags = (uint32_t)osErrorResource; + break; + } + } + } else { + if((flags & rflags) != 0) { + break; + } else { + if(timeout == 0U) { + rflags = (uint32_t)osErrorResource; + break; + } + } + } + + /* Update timeout */ + td = xTaskGetTickCount() - t0; + + if(td > tout) { + tout = 0; + } else { + tout -= td; + } + } else { + if(timeout == 0) { + rflags = (uint32_t)osErrorResource; + } else { + rflags = (uint32_t)osErrorTimeout; + } + } + } while(rval != pdFAIL); + } + + /* Return flags before clearing */ + return (rflags); +} + +uint32_t furi_thread_enumerate(FuriThreadId* thread_array, uint32_t array_items) { + uint32_t i, count; + TaskStatus_t* task; + + if(FURI_IS_IRQ_MODE() || (thread_array == NULL) || (array_items == 0U)) { + count = 0U; + } else { + vTaskSuspendAll(); + + count = uxTaskGetNumberOfTasks(); + task = pvPortMalloc(count * sizeof(TaskStatus_t)); + + if(task != NULL) { + count = uxTaskGetSystemState(task, count, NULL); + + for(i = 0U; (i < count) && (i < array_items); i++) { + thread_array[i] = (FuriThreadId)task[i].xHandle; + } + count = i; + } + (void)xTaskResumeAll(); + + vPortFree(task); + } + + return (count); +} + +const char* furi_thread_get_name(FuriThreadId thread_id) { + TaskHandle_t hTask = (TaskHandle_t)thread_id; + const char* name; + + if(FURI_IS_IRQ_MODE() || (hTask == NULL)) { + name = NULL; + } else { + name = pcTaskGetName(hTask); + } + + return (name); +} + +uint32_t furi_thread_get_stack_space(FuriThreadId thread_id) { + TaskHandle_t hTask = (TaskHandle_t)thread_id; + uint32_t sz; + + if(FURI_IS_IRQ_MODE() || (hTask == NULL)) { + sz = 0U; + } else { + sz = (uint32_t)(uxTaskGetStackHighWaterMark(hTask) * sizeof(StackType_t)); + } + + return (sz); +} diff --git a/core/furi/thread.h b/core/furi/thread.h index 83e6bb93..11dd997c 100644 --- a/core/furi/thread.h +++ b/core/furi/thread.h @@ -5,9 +5,7 @@ #pragma once -#include -#include -#include +#include "base.h" #ifdef __cplusplus extern "C" { @@ -20,9 +18,24 @@ typedef enum { FuriThreadStateRunning, } FuriThreadState; +/** FuriThreadPriority */ +typedef enum { + FuriThreadPriorityNone = 0, /**< Uninitialized, choose system default */ + FuriThreadPriorityIdle = 1, /**< Idle priority */ + FuriThreadPriorityLowest = 14, /**< Lowest */ + FuriThreadPriorityLow = 15, /**< Low */ + FuriThreadPriorityNormal = 16, /**< Normal */ + FuriThreadPriorityHigh = 17, /**< High */ + FuriThreadPriorityHighest = 18, /**< Highest */ + FuriThreadPriorityIsr = 32, /**< Deffered Isr (highest possible) */ +} FuriThreadPriority; + /** FuriThread anonymous structure */ typedef struct FuriThread FuriThread; +/** FuriThreadId proxy type to OS low level functions */ +typedef void* FuriThreadId; + /** FuriThreadCallback Your callback to run in new thread * @warning never use osThreadExit in FuriThread */ @@ -74,6 +87,13 @@ void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback); */ void furi_thread_set_context(FuriThread* thread, void* context); +/** Set FuriThread priority + * + * @param thread FuriThread instance + * @param priority FuriThreadPriority value + */ +void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority); + /** Set FuriThread state change callback * * @param thread FuriThread instance @@ -99,36 +119,24 @@ FuriThreadState furi_thread_get_state(FuriThread* thread); /** Start FuriThread * * @param thread FuriThread instance - * - * @return true on success */ -bool furi_thread_start(FuriThread* thread); - -/** Treminate FuriThread - * - * @param thread FuriThread instance - * - * @return osStatus_t - * @warning terminating statefull thread is dangerous use only if you know - * what you doing - */ -osStatus_t furi_thread_terminate(FuriThread* thread); +void furi_thread_start(FuriThread* thread); /** Join FuriThread * * @param thread FuriThread instance * - * @return osStatus_t + * @return bool */ -osStatus_t furi_thread_join(FuriThread* thread); +bool furi_thread_join(FuriThread* thread); -/** Get CMSIS Thread ID +/** Get FreeRTOS FuriThreadId for FuriThread instance * * @param thread FuriThread instance * - * @return osThreadId_t or NULL + * @return FuriThreadId or NULL */ -osThreadId_t furi_thread_get_thread_id(FuriThread* thread); +FuriThreadId furi_thread_get_id(FuriThread* thread); /** Enable heap tracing * @@ -158,6 +166,33 @@ size_t furi_thread_get_heap_size(FuriThread* thread); */ int32_t furi_thread_get_return_code(FuriThread* thread); +/** Thread releated methods that doesn't involve FuriThread directly */ + +/** Get FreeRTOS FuriThreadId for current thread + * + * @param thread FuriThread instance + * + * @return FuriThreadId or NULL + */ +FuriThreadId furi_thread_get_current_id(); + +/** Return control to scheduler */ +void furi_thread_yield(); + +uint32_t furi_thread_flags_set(FuriThreadId thread_id, uint32_t flags); + +uint32_t furi_thread_flags_clear(uint32_t flags); + +uint32_t furi_thread_flags_get(void); + +uint32_t furi_thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout); + +uint32_t furi_thread_enumerate(FuriThreadId* thread_array, uint32_t array_items); + +const char* furi_thread_get_name(FuriThreadId thread_id); + +uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); + #ifdef __cplusplus } #endif diff --git a/core/furi/valuemutex.h b/core/furi/valuemutex.h index 63dfac61..bd149316 100644 --- a/core/furi/valuemutex.h +++ b/core/furi/valuemutex.h @@ -2,6 +2,7 @@ #include #include +#include "mutex.h" #ifdef __cplusplus extern "C" { diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/Inc/FreeRTOSConfig.h index 0204826a..9f1b83c0 100644 --- a/firmware/targets/f7/Inc/FreeRTOSConfig.h +++ b/firmware/targets/f7/Inc/FreeRTOSConfig.h @@ -20,7 +20,7 @@ extern uint32_t SystemCoreClock; #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ (SystemCoreClock) #define configTICK_RATE_HZ ((TickType_t)1000) -#define configMAX_PRIORITIES (56) +#define configMAX_PRIORITIES (32) #define configMINIMAL_STACK_SIZE ((uint16_t)128) /* Heap size determined automatically by linker */ @@ -35,7 +35,7 @@ extern uint32_t SystemCoreClock; #define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_COUNTING_SEMAPHORES 1 #define configENABLE_BACKWARD_COMPATIBILITY 0 -#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 #define configUSE_TICKLESS_IDLE 2 #define configRECORD_STACK_HIGH_ADDRESS 1 #define configUSE_NEWLIB_REENTRANT 0 @@ -89,6 +89,9 @@ to exclude the API function. */ #define configTASK_NOTIFICATION_ARRAY_ENTRIES 2 #define CMSIS_TASK_NOTIFY_INDEX 1 +extern __attribute__((__noreturn__)) void furi_thread_catch(); +#define configTASK_RETURN_ADDRESS (furi_thread_catch + 2) + /* * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used * by the application thus the correct define need to be enabled below diff --git a/firmware/targets/f7/Src/main.c b/firmware/targets/f7/Src/main.c index 3de1c6ca..82a2819b 100644 --- a/firmware/targets/f7/Src/main.c +++ b/firmware/targets/f7/Src/main.c @@ -7,19 +7,16 @@ #define TAG "Main" -static const osThreadAttr_t init_thread_attr = { - .name = "Init", - .stack_size = 4096, -}; +int32_t init_task(void* context) { + UNUSED(context); -void init_task() { // Flipper FURI HAL furi_hal_init(); // Init flipper flipper_init(); - osThreadExit(); + return 0; } int main() { @@ -29,8 +26,13 @@ int main() { // Flipper critical FURI HAL furi_hal_init_early(); + FuriThread* main_thread = furi_thread_alloc(); + furi_thread_set_name(main_thread, "Init"); + furi_thread_set_stack_size(main_thread, 4096); + furi_thread_set_callback(main_thread, init_task); + #ifdef FURI_RAM_EXEC - osThreadNew(init_task, NULL, &init_thread_attr); + furi_thread_start(main_thread); #else furi_hal_light_sequence("RGB"); @@ -52,7 +54,7 @@ int main() { furi_hal_power_reset(); } else { furi_hal_light_sequence("rgb G"); - osThreadNew(init_task, NULL, &init_thread_attr); + furi_thread_start(main_thread); } #endif diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/firmware/targets/f7/ble_glue/ble_app.c index 618e2b94..f0406a88 100644 --- a/firmware/targets/f7/ble_glue/ble_app.c +++ b/firmware/targets/f7/ble_glue/ble_app.c @@ -6,6 +6,7 @@ #include "gap.h" #include +#include #define TAG "Bt" @@ -106,9 +107,9 @@ void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size) { void ble_app_thread_stop() { if(ble_app) { - osThreadId_t thread_id = furi_thread_get_thread_id(ble_app->thread); + FuriThreadId thread_id = furi_thread_get_id(ble_app->thread); furi_assert(thread_id); - osThreadFlagsSet(thread_id, BLE_APP_FLAG_KILL_THREAD); + furi_thread_flags_set(thread_id, BLE_APP_FLAG_KILL_THREAD); furi_thread_join(ble_app->thread); furi_thread_free(ble_app->thread); // Free resources @@ -125,7 +126,7 @@ static int32_t ble_app_hci_thread(void* arg) { uint32_t flags = 0; while(1) { - flags = osThreadFlagsWait(BLE_APP_FLAG_ALL, osFlagsWaitAny, osWaitForever); + flags = furi_thread_flags_wait(BLE_APP_FLAG_ALL, osFlagsWaitAny, osWaitForever); if(flags & BLE_APP_FLAG_KILL_THREAD) { break; } @@ -141,9 +142,9 @@ static int32_t ble_app_hci_thread(void* arg) { void hci_notify_asynch_evt(void* pdata) { UNUSED(pdata); if(ble_app) { - osThreadId_t thread_id = furi_thread_get_thread_id(ble_app->thread); + FuriThreadId thread_id = furi_thread_get_id(ble_app->thread); furi_assert(thread_id); - osThreadFlagsSet(thread_id, BLE_APP_FLAG_HCI_EVENT); + furi_thread_flags_set(thread_id, BLE_APP_FLAG_HCI_EVENT); } } diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 6a100bea..dd3fc280 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -333,9 +333,9 @@ static void ble_glue_clear_shared_memory() { void ble_glue_thread_stop() { if(ble_glue) { - osThreadId_t thread_id = furi_thread_get_thread_id(ble_glue->thread); + FuriThreadId thread_id = furi_thread_get_id(ble_glue->thread); furi_assert(thread_id); - osThreadFlagsSet(thread_id, BLE_GLUE_FLAG_KILL_THREAD); + furi_thread_flags_set(thread_id, BLE_GLUE_FLAG_KILL_THREAD); furi_thread_join(ble_glue->thread); furi_thread_free(ble_glue->thread); // Free resources @@ -353,7 +353,7 @@ static int32_t ble_glue_shci_thread(void* context) { uint32_t flags = 0; while(true) { - flags = osThreadFlagsWait(BLE_GLUE_FLAG_ALL, osFlagsWaitAny, osWaitForever); + flags = furi_thread_flags_wait(BLE_GLUE_FLAG_ALL, osFlagsWaitAny, osWaitForever); if(flags & BLE_GLUE_FLAG_SHCI_EVENT) { shci_user_evt_proc(); } @@ -368,9 +368,9 @@ static int32_t ble_glue_shci_thread(void* context) { void shci_notify_asynch_evt(void* pdata) { UNUSED(pdata); if(ble_glue) { - osThreadId_t thread_id = furi_thread_get_thread_id(ble_glue->thread); + FuriThreadId thread_id = furi_thread_get_id(ble_glue->thread); furi_assert(thread_id); - osThreadFlagsSet(thread_id, BLE_GLUE_FLAG_SHCI_EVENT); + furi_thread_flags_set(thread_id, BLE_GLUE_FLAG_SHCI_EVENT); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index c7ee7dc2..ad12d773 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -322,7 +322,7 @@ void furi_hal_bt_set_key_storage_change_callback( void furi_hal_bt_nvm_sram_sem_acquire() { while(LL_HSEM_1StepLock(HSEM, CFG_HW_BLE_NVM_SRAM_SEMID)) { - osThreadYield(); + furi_thread_yield(); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_crc.c b/firmware/targets/f7/furi_hal/furi_hal_crc.c index 322a83bb..9ac13e97 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_crc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_crc.c @@ -34,7 +34,7 @@ void furi_hal_crc_init(bool synchronize) { void furi_hal_crc_reset() { furi_check(hal_crc_control.state == CRC_State_Ready); if(hal_crc_control.mtx) { - furi_check(osMutexGetOwner(hal_crc_control.mtx) == osThreadGetId()); + furi_check(osMutexGetOwner(hal_crc_control.mtx) == furi_thread_get_current_id()); osMutexRelease(hal_crc_control.mtx); } LL_CRC_ResetCRCCalculationUnit(CRC); diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/firmware/targets/f7/furi_hal/furi_hal_flash.c index 1d9c3fd9..ac141db0 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_flash.c +++ b/firmware/targets/f7/furi_hal/furi_hal_flash.c @@ -112,7 +112,7 @@ static void furi_hal_flash_lock(void) { static void furi_hal_flash_begin_with_core2(bool erase_flag) { // Take flash controller ownership while(LL_HSEM_1StepLock(HSEM, CFG_HW_FLASH_SEMID) != 0) { - osThreadYield(); + furi_thread_yield(); } // Unlock flash operation @@ -128,7 +128,7 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) { while(true) { // Wait till flash controller become usable while(LL_FLASH_IsActiveFlag_OperationSuspended()) { - osThreadYield(); + furi_thread_yield(); }; // Just a little more love @@ -137,14 +137,14 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) { // Actually we already have mutex for it, but specification is specification if(LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) { taskEXIT_CRITICAL(); - osThreadYield(); + furi_thread_yield(); continue; } // Take sempahopre and prevent core2 from anything funky if(LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != 0) { taskEXIT_CRITICAL(); - osThreadYield(); + furi_thread_yield(); continue; } @@ -173,7 +173,7 @@ static void furi_hal_flash_end_with_core2(bool erase_flag) { // Doesn't make much sense, does it? while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) { - osThreadYield(); + furi_thread_yield(); } // Erase activity over, core2 can continue @@ -498,7 +498,7 @@ bool furi_hal_flash_ob_set_word(size_t word_idx, const uint32_t value) { /* 3. Check that no Flash memory operation is on going by checking the BSY && PESD */ furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT)); while(LL_FLASH_IsActiveFlag_OperationSuspended()) { - osThreadYield(); + furi_thread_yield(); }; /* 4. Set the Options start bit OPTSTRT */ diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 6ffb6e3a..3e6d18eb 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -179,7 +179,7 @@ bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) { FURI_LOG_T(TAG, "Timeout"); return false; } - osThreadYield(); + furi_thread_yield(); } rfalNfcGetDevicesFound(&dev_list, &dev_cnt); // Take first device and set cuid @@ -397,14 +397,14 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_ } // Manually wait for interrupt - furi_hal_gpio_init(&gpio_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh); + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh); st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_RXE); uint32_t irq = 0; uint8_t rxe = 0; uint32_t start = DWT->CYCCNT; while(true) { - if(furi_hal_gpio_read(&gpio_rfid_pull) == true) { + if(furi_hal_gpio_read(&gpio_nfc_irq_rfid_pull) == true) { st25r3916ReadRegister(ST25R3916_REG_IRQ_MAIN, &rxe); if(rxe & (1 << 4)) { irq = 1; diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/firmware/targets/f7/furi_hal/furi_hal_resources.c index 0af33cac..21fac834 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.c @@ -42,7 +42,7 @@ const GpioPin gpio_ext_pa4 = {.port = GPIOA, .pin = LL_GPIO_PIN_4}; const GpioPin gpio_ext_pa6 = {.port = GPIOA, .pin = LL_GPIO_PIN_6}; const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = LL_GPIO_PIN_7}; -const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin}; +const GpioPin gpio_nfc_irq_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin}; const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin}; const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin}; const GpioPin gpio_rfid_carrier = {.port = RFID_CARRIER_GPIO_Port, .pin = RFID_CARRIER_Pin}; @@ -138,7 +138,7 @@ void furi_hal_resources_init() { furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_init(&gpio_rfid_pull, GpioModeInterruptRise, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullNo, GpioSpeedLow); furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.h b/firmware/targets/f7/furi_hal/furi_hal_resources.h index e9d19827..820760a1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.h +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.h @@ -77,7 +77,7 @@ extern const GpioPin gpio_ext_pa4; extern const GpioPin gpio_ext_pa6; extern const GpioPin gpio_ext_pa7; -extern const GpioPin gpio_rfid_pull; +extern const GpioPin gpio_nfc_irq_rfid_pull; extern const GpioPin gpio_rfid_carrier_out; extern const GpioPin gpio_rfid_data_in; extern const GpioPin gpio_rfid_carrier; diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index 86fecc99..507c53bf 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.c @@ -69,8 +69,8 @@ void furi_hal_rfid_pins_reset() { furi_hal_gpio_write(&gpio_rfid_carrier_out, false); // from both sides - furi_hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_write(&gpio_rfid_pull, true); + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, true); furi_hal_gpio_init_simple(&gpio_rfid_carrier, GpioModeAnalog); @@ -84,7 +84,11 @@ void furi_hal_rfid_pins_emulate() { // pull pin to timer out furi_hal_gpio_init_ex( - &gpio_rfid_pull, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + &gpio_nfc_irq_rfid_pull, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedLow, + GpioAltFn1TIM2); // pull rfid antenna from carrier side furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); @@ -100,8 +104,8 @@ void furi_hal_rfid_pins_read() { furi_hal_ibutton_pin_low(); // dont pull rfid antenna - furi_hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_write(&gpio_rfid_pull, false); + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false); // carrier pin to timer out furi_hal_gpio_init_ex( @@ -116,11 +120,11 @@ void furi_hal_rfid_pins_read() { } void furi_hal_rfid_pin_pull_release() { - furi_hal_gpio_write(&gpio_rfid_pull, true); + furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, true); } void furi_hal_rfid_pin_pull_pulldown() { - furi_hal_gpio_write(&gpio_rfid_pull, false); + furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false); } void furi_hal_rfid_tim_read(float freq, float duty_cycle) { diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 6a5e534e..cedcc82a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -101,7 +101,7 @@ bool furi_hal_usb_set_config(FuriHalUsbInterface* new_if, void* ctx) { return true; } furi_assert(usb.thread); - osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); + furi_thread_flags_set(furi_thread_get_id(usb.thread), EventModeChange); return true; } @@ -125,17 +125,17 @@ bool furi_hal_usb_is_locked() { void furi_hal_usb_disable() { furi_assert(usb.thread); - osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventDisable); + furi_thread_flags_set(furi_thread_get_id(usb.thread), EventDisable); } void furi_hal_usb_enable() { furi_assert(usb.thread); - osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventEnable); + furi_thread_flags_set(furi_thread_get_id(usb.thread), EventEnable); } void furi_hal_usb_reinit() { furi_assert(usb.thread); - osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReinit); + furi_thread_flags_set(furi_thread_get_id(usb.thread), EventReinit); } /* Get device / configuration descriptors */ @@ -148,7 +148,7 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ switch(dtype) { case USB_DTYPE_DEVICE: - osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventRequest); + furi_thread_flags_set(furi_thread_get_id(usb.thread), EventRequest); if(usb.callback != NULL) { usb.callback(FuriHalUsbStateEventDescriptorRequest, usb.cb_ctx); } @@ -192,7 +192,7 @@ static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep) { UNUSED(dev); UNUSED(event); UNUSED(ep); - osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReset); + furi_thread_flags_set(furi_thread_get_id(usb.thread), EventReset); if(usb.callback != NULL) { usb.callback(FuriHalUsbStateEventReset, usb.cb_ctx); } @@ -236,11 +236,11 @@ static int32_t furi_hal_usb_thread(void* context) { FuriHalUsbInterface* if_ctx_new = NULL; if(usb.if_next != NULL) { - osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); + furi_thread_flags_set(furi_thread_get_id(usb.thread), EventModeChange); } while(true) { - uint32_t flags = osThreadFlagsWait(USB_SRV_ALL_EVENTS, osFlagsWaitAny, 500); + uint32_t flags = furi_thread_flags_wait(USB_SRV_ALL_EVENTS, osFlagsWaitAny, 500); if((flags & osFlagsError) == 0) { if(flags & EventModeChange) { if(usb.if_next != usb.if_cur) { diff --git a/lib/FreeRTOS-glue/cmsis_os2.c b/lib/FreeRTOS-glue/cmsis_os2.c index 4e59fb54..bee37572 100644 --- a/lib/FreeRTOS-glue/cmsis_os2.c +++ b/lib/FreeRTOS-glue/cmsis_os2.c @@ -26,15 +26,11 @@ #include "cmsis_os2.h" // ::CMSIS:RTOS2 #include "cmsis_compiler.h" // Compiler agnostic definitions -#include "os_tick.h" // OS Tick API #include "FreeRTOS.h" // ARM.FreeRTOS::RTOS:Core -#include "task.h" // ARM.FreeRTOS::RTOS:Core -#include "event_groups.h" // ARM.FreeRTOS::RTOS:Event Groups -#include "semphr.h" // ARM.FreeRTOS::RTOS:Core #include "timers.h" // ARM.FreeRTOS::RTOS:Timers +#include "queue.h" -#include "freertos_mpool.h" // osMemoryPool definitions #include "freertos_os2.h" // Configuration check and setup #include CMSIS_device_header @@ -87,10 +83,8 @@ /* Limits */ #define MAX_BITS_TASK_NOTIFY 31U -#define MAX_BITS_EVENT_GROUPS 24U #define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U)) -#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U)) /* Kernel version and identification string definition (major.minor.rev: mmnnnrrrr dec) */ #define KERNEL_VERSION (((uint32_t)tskKERNEL_VERSION_MAJOR * 10000000UL) | \ @@ -453,31 +447,6 @@ uint32_t osKernelGetTickFreq (void) { return (configTICK_RATE_HZ); } -/* - Get the RTOS kernel system timer count. -*/ -uint32_t osKernelGetSysTimerCount (void) { - TickType_t ticks; - uint32_t val; - - FURI_CRITICAL_ENTER(); - - ticks = xTaskGetTickCount(); - val = OS_Tick_GetCount(); - - /* Update tick count and timer value when timer overflows */ - if (OS_Tick_GetOverflow() != 0U) { - val = OS_Tick_GetCount(); - ticks++; - } - val += ticks * OS_Tick_GetInterval(); - - FURI_CRITICAL_EXIT(); - - /* Return system timer count */ - return (val); -} - /* Get the RTOS kernel system timer frequency. */ @@ -486,531 +455,6 @@ uint32_t osKernelGetSysTimerFreq (void) { return (configCPU_CLOCK_HZ); } - -/* ==== Thread Management Functions ==== */ - -/* - Create a thread and add it to Active Threads. - - Limitations: - - The memory for control block and stack must be provided in the osThreadAttr_t - structure in order to allocate object statically. - - Attribute osThreadJoinable is not supported, NULL is returned if used. -*/ -osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) { - const char *name; - uint32_t stack; - TaskHandle_t hTask; - UBaseType_t prio; - int32_t mem; - - hTask = NULL; - - if ((IRQ_Context() == 0U) && (func != NULL)) { - stack = configMINIMAL_STACK_SIZE; - prio = (UBaseType_t)osPriorityNormal; - - name = NULL; - mem = -1; - - if (attr != NULL) { - if (attr->name != NULL) { - name = attr->name; - } - if (attr->priority != osPriorityNone) { - prio = (UBaseType_t)attr->priority; - } - - if ((prio < osPriorityIdle) || (prio > osPriorityISR) || ((attr->attr_bits & osThreadJoinable) == osThreadJoinable)) { - /* Invalid priority or unsupported osThreadJoinable attribute used */ - return (NULL); - } - - if (attr->stack_size > 0U) { - /* In FreeRTOS stack is not in bytes, but in sizeof(StackType_t) which is 4 on ARM ports. */ - /* Stack size should be therefore 4 byte aligned in order to avoid division caused side effects */ - stack = attr->stack_size / sizeof(StackType_t); - } - - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticTask_t)) && - (attr->stack_mem != NULL) && (attr->stack_size > 0U)) { - /* The memory for control block and stack is provided, use static object */ - mem = 1; - } - else { - if ((attr->cb_mem == NULL) && (attr->cb_size == 0U) && (attr->stack_mem == NULL)) { - /* Control block and stack memory will be allocated from the dynamic pool */ - mem = 0; - } - } - } - else { - mem = 0; - } - - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - hTask = xTaskCreateStatic ((TaskFunction_t)func, name, stack, argument, prio, (StackType_t *)attr->stack_mem, - (StaticTask_t *)attr->cb_mem); - #endif - } - else { - if (mem == 0) { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - if (xTaskCreate ((TaskFunction_t)func, name, (configSTACK_DEPTH_TYPE)stack, argument, prio, &hTask) != pdPASS) { - hTask = NULL; - } - #endif - } - } - } - - /* Return thread ID */ - return ((osThreadId_t)hTask); -} - -/* - Get name of a thread. -*/ -const char *osThreadGetName (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - const char *name; - - if ((IRQ_Context() != 0U) || (hTask == NULL)) { - name = NULL; - } else if(osKernelGetState() == osKernelRunning) { - name = pcTaskGetName (hTask); - } else { - name = NULL; - } - - /* Return name as null-terminated string */ - return (name); -} - -/* - Return the thread ID of the current running thread. -*/ -osThreadId_t osThreadGetId (void) { - osThreadId_t id; - - id = (osThreadId_t)xTaskGetCurrentTaskHandle(); - - /* Return thread ID */ - return (id); -} - -/* - Get current thread state of a thread. -*/ -osThreadState_t osThreadGetState (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osThreadState_t state; - - if ((IRQ_Context() != 0U) || (hTask == NULL)) { - state = osThreadError; - } - else { - switch (eTaskGetState (hTask)) { - case eRunning: state = osThreadRunning; break; - case eReady: state = osThreadReady; break; - case eBlocked: - case eSuspended: state = osThreadBlocked; break; - case eDeleted: state = osThreadTerminated; break; - case eInvalid: - default: state = osThreadError; break; - } - } - - /* Return current thread state */ - return (state); -} - -/* - Get available stack space of a thread based on stack watermark recording during execution. -*/ -uint32_t osThreadGetStackSpace (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - uint32_t sz; - - if ((IRQ_Context() != 0U) || (hTask == NULL)) { - sz = 0U; - } else { - sz = (uint32_t)(uxTaskGetStackHighWaterMark(hTask) * sizeof(StackType_t)); - } - - /* Return remaining stack space in bytes */ - return (sz); -} - -/* - Change priority of a thread. -*/ -osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osStatus_t stat; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if ((hTask == NULL) || (priority < osPriorityIdle) || (priority > osPriorityISR)) { - stat = osErrorParameter; - } - else { - stat = osOK; - vTaskPrioritySet (hTask, (UBaseType_t)priority); - } - - /* Return execution status */ - return (stat); -} - -/* - Get current priority of a thread. -*/ -osPriority_t osThreadGetPriority (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osPriority_t prio; - - if ((IRQ_Context() != 0U) || (hTask == NULL)) { - prio = osPriorityError; - } else { - prio = (osPriority_t)((int32_t)uxTaskPriorityGet (hTask)); - } - - /* Return current thread priority */ - return (prio); -} - -/* - Pass control to next thread that is in state READY. -*/ -osStatus_t osThreadYield (void) { - osStatus_t stat; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } else { - stat = osOK; - taskYIELD(); - } - - /* Return execution status */ - return (stat); -} - -#if (configUSE_OS2_THREAD_SUSPEND_RESUME == 1) -/* - Suspend execution of a thread. -*/ -osStatus_t osThreadSuspend (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osStatus_t stat; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hTask == NULL) { - stat = osErrorParameter; - } - else { - stat = osOK; - vTaskSuspend (hTask); - } - - /* Return execution status */ - return (stat); -} - -/* - Resume execution of a thread. -*/ -osStatus_t osThreadResume (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osStatus_t stat; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hTask == NULL) { - stat = osErrorParameter; - } - else { - stat = osOK; - vTaskResume (hTask); - } - - /* Return execution status */ - return (stat); -} -#endif /* (configUSE_OS2_THREAD_SUSPEND_RESUME == 1) */ - -/* - Terminate execution of current running thread. -*/ -__NO_RETURN void osThreadExit (void) { -#ifndef USE_FreeRTOS_HEAP_1 - vTaskDelete (NULL); -#endif - for (;;); -} - -/* - Terminate execution of a thread. -*/ -osStatus_t osThreadTerminate (osThreadId_t thread_id) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - osStatus_t stat; -#ifndef USE_FreeRTOS_HEAP_1 - eTaskState tstate; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hTask == NULL) { - stat = osErrorParameter; - } - else { - tstate = eTaskGetState (hTask); - - if (tstate != eDeleted) { - stat = osOK; - vTaskDelete (hTask); - } else { - stat = osErrorResource; - } - } -#else - stat = osError; -#endif - - /* Return execution status */ - return (stat); -} - -/* - Get number of active threads. -*/ -uint32_t osThreadGetCount (void) { - uint32_t count; - - if (IRQ_Context() != 0U) { - count = 0U; - } else { - count = uxTaskGetNumberOfTasks(); - } - - /* Return number of active threads */ - return (count); -} - -#if (configUSE_OS2_THREAD_ENUMERATE == 1) -/* - Enumerate active threads. -*/ -uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items) { - uint32_t i, count; - TaskStatus_t *task; - - if ((IRQ_Context() != 0U) || (thread_array == NULL) || (array_items == 0U)) { - count = 0U; - } else { - vTaskSuspendAll(); - - /* Allocate memory on heap to temporarily store TaskStatus_t information */ - count = uxTaskGetNumberOfTasks(); - task = pvPortMalloc (count * sizeof(TaskStatus_t)); - - if (task != NULL) { - /* Retrieve task status information */ - count = uxTaskGetSystemState (task, count, NULL); - - /* Copy handles from task status array into provided thread array */ - for (i = 0U; (i < count) && (i < array_items); i++) { - thread_array[i] = (osThreadId_t)task[i].xHandle; - } - count = i; - } - (void)xTaskResumeAll(); - - vPortFree (task); - } - - /* Return number of enumerated threads */ - return (count); -} -#endif /* (configUSE_OS2_THREAD_ENUMERATE == 1) */ - - -/* ==== Thread Flags Functions ==== */ - -#if (configUSE_OS2_THREAD_FLAGS == 1) -/* - Set the specified Thread Flags of a thread. -*/ -uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags) { - TaskHandle_t hTask = (TaskHandle_t)thread_id; - uint32_t rflags; - BaseType_t yield; - - if ((hTask == NULL) || ((flags & THREAD_FLAGS_INVALID_BITS) != 0U)) { - rflags = (uint32_t)osErrorParameter; - } - else { - rflags = (uint32_t)osError; - - if (IRQ_Context() != 0U) { - yield = pdFALSE; - - (void)xTaskNotifyIndexedFromISR (hTask, CMSIS_TASK_NOTIFY_INDEX, flags, eSetBits, &yield); - (void)xTaskNotifyAndQueryIndexedFromISR (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &rflags, NULL); - - portYIELD_FROM_ISR (yield); - } - else { - (void)xTaskNotifyIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, flags, eSetBits); - (void)xTaskNotifyAndQueryIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &rflags); - } - } - /* Return flags after setting */ - return (rflags); -} - -/* - Clear the specified Thread Flags of current running thread. -*/ -uint32_t osThreadFlagsClear (uint32_t flags) { - TaskHandle_t hTask; - uint32_t rflags, cflags; - - if (IRQ_Context() != 0U) { - rflags = (uint32_t)osErrorISR; - } - else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) { - rflags = (uint32_t)osErrorParameter; - } - else { - hTask = xTaskGetCurrentTaskHandle(); - - if (xTaskNotifyAndQueryIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &cflags) == pdPASS) { - rflags = cflags; - cflags &= ~flags; - - if (xTaskNotifyIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, cflags, eSetValueWithOverwrite) != pdPASS) { - rflags = (uint32_t)osError; - } - } - else { - rflags = (uint32_t)osError; - } - } - - /* Return flags before clearing */ - return (rflags); -} - -/* - Get the current Thread Flags of current running thread. -*/ -uint32_t osThreadFlagsGet (void) { - TaskHandle_t hTask; - uint32_t rflags; - - if (IRQ_Context() != 0U) { - rflags = (uint32_t)osErrorISR; - } - else { - hTask = xTaskGetCurrentTaskHandle(); - - if (xTaskNotifyAndQueryIndexed (hTask, CMSIS_TASK_NOTIFY_INDEX, 0, eNoAction, &rflags) != pdPASS) { - rflags = (uint32_t)osError; - } - } - - /* Return current flags */ - return (rflags); -} - -/* - Wait for one or more Thread Flags of the current running thread to become signaled. -*/ -uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout) { - uint32_t rflags, nval; - uint32_t clear; - TickType_t t0, td, tout; - BaseType_t rval; - - if (IRQ_Context() != 0U) { - rflags = (uint32_t)osErrorISR; - } - else if ((flags & THREAD_FLAGS_INVALID_BITS) != 0U) { - rflags = (uint32_t)osErrorParameter; - } - else { - if ((options & osFlagsNoClear) == osFlagsNoClear) { - clear = 0U; - } else { - clear = flags; - } - - rflags = 0U; - tout = timeout; - - t0 = xTaskGetTickCount(); - do { - rval = xTaskNotifyWaitIndexed (CMSIS_TASK_NOTIFY_INDEX, 0, clear, &nval, tout); - - if (rval == pdPASS) { - rflags &= flags; - rflags |= nval; - - if ((options & osFlagsWaitAll) == osFlagsWaitAll) { - if ((flags & rflags) == flags) { - break; - } else { - if (timeout == 0U) { - rflags = (uint32_t)osErrorResource; - break; - } - } - } - else { - if ((flags & rflags) != 0) { - break; - } else { - if (timeout == 0U) { - rflags = (uint32_t)osErrorResource; - break; - } - } - } - - /* Update timeout */ - td = xTaskGetTickCount() - t0; - - if (td > timeout) { - tout = 0; - } else { - tout = timeout - td; - } - } - else { - if (timeout == 0) { - rflags = (uint32_t)osErrorResource; - } else { - rflags = (uint32_t)osErrorTimeout; - } - } - } - while (rval != pdFAIL); - } - - /* Return flags before clearing */ - return (rflags); -} -#endif /* (configUSE_OS2_THREAD_FLAGS == 1) */ - - /* ==== Generic Wait Functions ==== */ /* @@ -1330,681 +774,6 @@ osStatus_t osTimerDelete (osTimerId_t timer_id) { #endif /* (configUSE_OS2_TIMER == 1) */ -/* ==== Event Flags Management Functions ==== */ - -/* - Create and Initialize an Event Flags object. - - Limitations: - - Event flags are limited to 24 bits. -*/ -osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr) { - EventGroupHandle_t hEventGroup; - int32_t mem; - - hEventGroup = NULL; - - if (IRQ_Context() == 0U) { - mem = -1; - - if (attr != NULL) { - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticEventGroup_t))) { - /* The memory for control block is provided, use static object */ - mem = 1; - } - else { - if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { - /* Control block will be allocated from the dynamic pool */ - mem = 0; - } - } - } - else { - mem = 0; - } - - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - hEventGroup = xEventGroupCreateStatic (attr->cb_mem); - #endif - } - else { - if (mem == 0) { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - hEventGroup = xEventGroupCreate(); - #endif - } - } - } - - /* Return event flags ID */ - return ((osEventFlagsId_t)hEventGroup); -} - -/* - Set the specified Event Flags. - - Limitations: - - Event flags are limited to 24 bits. -*/ -uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - uint32_t rflags; - BaseType_t yield; - - if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { - rflags = (uint32_t)osErrorParameter; - } - else if (IRQ_Context() != 0U) { - #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0) - (void)yield; - /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */ - rflags = (uint32_t)osErrorResource; - #else - yield = pdFALSE; - - if (xEventGroupSetBitsFromISR (hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) { - rflags = (uint32_t)osErrorResource; - } else { - rflags = flags; - portYIELD_FROM_ISR (yield); - } - #endif - } - else { - rflags = xEventGroupSetBits (hEventGroup, (EventBits_t)flags); - } - - /* Return event flags after setting */ - return (rflags); -} - -/* - Clear the specified Event Flags. - - Limitations: - - Event flags are limited to 24 bits. -*/ -uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - uint32_t rflags; - - if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { - rflags = (uint32_t)osErrorParameter; - } - else if (IRQ_Context() != 0U) { - #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0) - /* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */ - rflags = (uint32_t)osErrorResource; - #else - rflags = xEventGroupGetBitsFromISR (hEventGroup); - - if (xEventGroupClearBitsFromISR (hEventGroup, (EventBits_t)flags) == pdFAIL) { - rflags = (uint32_t)osErrorResource; - } - else { - /* xEventGroupClearBitsFromISR only registers clear operation in the timer command queue. */ - /* Yield is required here otherwise clear operation might not execute in the right order. */ - /* See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/93 for more info. */ - portYIELD_FROM_ISR (pdTRUE); - } - #endif - } - else { - rflags = xEventGroupClearBits (hEventGroup, (EventBits_t)flags); - } - - /* Return event flags before clearing */ - return (rflags); -} - -/* - Get the current Event Flags. - - Limitations: - - Event flags are limited to 24 bits. -*/ -uint32_t osEventFlagsGet (osEventFlagsId_t ef_id) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - uint32_t rflags; - - if (ef_id == NULL) { - rflags = 0U; - } - else if (IRQ_Context() != 0U) { - rflags = xEventGroupGetBitsFromISR (hEventGroup); - } - else { - rflags = xEventGroupGetBits (hEventGroup); - } - - /* Return current event flags */ - return (rflags); -} - -/* - Wait for one or more Event Flags to become signaled. - - Limitations: - - Event flags are limited to 24 bits. - - osEventFlagsWait cannot be called from an ISR. -*/ -uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - BaseType_t wait_all; - BaseType_t exit_clr; - uint32_t rflags; - - if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) { - rflags = (uint32_t)osErrorParameter; - } - else if (IRQ_Context() != 0U) { - rflags = (uint32_t)osErrorISR; - } - else { - if (options & osFlagsWaitAll) { - wait_all = pdTRUE; - } else { - wait_all = pdFAIL; - } - - if (options & osFlagsNoClear) { - exit_clr = pdFAIL; - } else { - exit_clr = pdTRUE; - } - - rflags = xEventGroupWaitBits (hEventGroup, (EventBits_t)flags, exit_clr, wait_all, (TickType_t)timeout); - - if (options & osFlagsWaitAll) { - if ((flags & rflags) != flags) { - if (timeout > 0U) { - rflags = (uint32_t)osErrorTimeout; - } else { - rflags = (uint32_t)osErrorResource; - } - } - } - else { - if ((flags & rflags) == 0U) { - if (timeout > 0U) { - rflags = (uint32_t)osErrorTimeout; - } else { - rflags = (uint32_t)osErrorResource; - } - } - } - } - - /* Return event flags before clearing */ - return (rflags); -} - -/* - Delete an Event Flags object. -*/ -osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id) { - EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id; - osStatus_t stat; - -#ifndef USE_FreeRTOS_HEAP_1 - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hEventGroup == NULL) { - stat = osErrorParameter; - } - else { - stat = osOK; - vEventGroupDelete (hEventGroup); - } -#else - stat = osError; -#endif - - /* Return execution status */ - return (stat); -} - - -/* ==== Mutex Management Functions ==== */ - -#if (configUSE_OS2_MUTEX == 1) -/* - Create and Initialize a Mutex object. - - Limitations: - - Priority inherit protocol is used by default, osMutexPrioInherit attribute is ignored. - - Robust mutex is not supported, NULL is returned if used. -*/ -osMutexId_t osMutexNew (const osMutexAttr_t *attr) { - SemaphoreHandle_t hMutex; - uint32_t type; - uint32_t rmtx; - int32_t mem; - - hMutex = NULL; - - if (IRQ_Context() == 0U) { - if (attr != NULL) { - type = attr->attr_bits; - } else { - type = 0U; - } - - if ((type & osMutexRecursive) == osMutexRecursive) { - rmtx = 1U; - } else { - rmtx = 0U; - } - - if ((type & osMutexRobust) != osMutexRobust) { - mem = -1; - - if (attr != NULL) { - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) { - /* The memory for control block is provided, use static object */ - mem = 1; - } - else { - if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { - /* Control block will be allocated from the dynamic pool */ - mem = 0; - } - } - } - else { - mem = 0; - } - - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - if (rmtx != 0U) { - #if (configUSE_RECURSIVE_MUTEXES == 1) - hMutex = xSemaphoreCreateRecursiveMutexStatic (attr->cb_mem); - #endif - } - else { - hMutex = xSemaphoreCreateMutexStatic (attr->cb_mem); - } - #endif - } - else { - if (mem == 0) { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - if (rmtx != 0U) { - #if (configUSE_RECURSIVE_MUTEXES == 1) - hMutex = xSemaphoreCreateRecursiveMutex (); - #endif - } else { - hMutex = xSemaphoreCreateMutex (); - } - #endif - } - } - - #if (configQUEUE_REGISTRY_SIZE > 0) - if (hMutex != NULL) { - if ((attr != NULL) && (attr->name != NULL)) { - /* Only non-NULL name objects are added to the Queue Registry */ - vQueueAddToRegistry (hMutex, attr->name); - } - } - #endif - - if ((hMutex != NULL) && (rmtx != 0U)) { - /* Set LSB as 'recursive mutex flag' */ - hMutex = (SemaphoreHandle_t)((uint32_t)hMutex | 1U); - } - } - } - - /* Return mutex ID */ - return ((osMutexId_t)hMutex); -} - -/* - Acquire a Mutex or timeout if it is locked. -*/ -osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) { - SemaphoreHandle_t hMutex; - osStatus_t stat; - uint32_t rmtx; - - hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); - - /* Extract recursive mutex flag */ - rmtx = (uint32_t)mutex_id & 1U; - - stat = osOK; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hMutex == NULL) { - stat = osErrorParameter; - } - else { - if (rmtx != 0U) { - #if (configUSE_RECURSIVE_MUTEXES == 1) - if (xSemaphoreTakeRecursive (hMutex, timeout) != pdPASS) { - if (timeout != 0U) { - stat = osErrorTimeout; - } else { - stat = osErrorResource; - } - } - #endif - } - else { - if (xSemaphoreTake (hMutex, timeout) != pdPASS) { - if (timeout != 0U) { - stat = osErrorTimeout; - } else { - stat = osErrorResource; - } - } - } - } - - /* Return execution status */ - return (stat); -} - -/* - Release a Mutex that was acquired by osMutexAcquire. -*/ -osStatus_t osMutexRelease (osMutexId_t mutex_id) { - SemaphoreHandle_t hMutex; - osStatus_t stat; - uint32_t rmtx; - - hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); - - /* Extract recursive mutex flag */ - rmtx = (uint32_t)mutex_id & 1U; - - stat = osOK; - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hMutex == NULL) { - stat = osErrorParameter; - } - else { - if (rmtx != 0U) { - #if (configUSE_RECURSIVE_MUTEXES == 1) - if (xSemaphoreGiveRecursive (hMutex) != pdPASS) { - stat = osErrorResource; - } - #endif - } - else { - if (xSemaphoreGive (hMutex) != pdPASS) { - stat = osErrorResource; - } - } - } - - /* Return execution status */ - return (stat); -} - -/* - Get Thread which owns a Mutex object. -*/ -osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) { - SemaphoreHandle_t hMutex; - osThreadId_t owner; - - hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); - - if ((IRQ_Context() != 0U) || (hMutex == NULL)) { - owner = NULL; - } else { - owner = (osThreadId_t)xSemaphoreGetMutexHolder (hMutex); - } - - /* Return owner thread ID */ - return (owner); -} - -/* - Delete a Mutex object. -*/ -osStatus_t osMutexDelete (osMutexId_t mutex_id) { - osStatus_t stat; -#ifndef USE_FreeRTOS_HEAP_1 - SemaphoreHandle_t hMutex; - - hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U); - - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hMutex == NULL) { - stat = osErrorParameter; - } - else { - #if (configQUEUE_REGISTRY_SIZE > 0) - vQueueUnregisterQueue (hMutex); - #endif - stat = osOK; - vSemaphoreDelete (hMutex); - } -#else - stat = osError; -#endif - - /* Return execution status */ - return (stat); -} -#endif /* (configUSE_OS2_MUTEX == 1) */ - - -/* ==== Semaphore Management Functions ==== */ - -/* - Create and Initialize a Semaphore object. -*/ -osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) { - SemaphoreHandle_t hSemaphore; - int32_t mem; - - hSemaphore = NULL; - - if ((IRQ_Context() == 0U) && (max_count > 0U) && (initial_count <= max_count)) { - mem = -1; - - if (attr != NULL) { - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) { - /* The memory for control block is provided, use static object */ - mem = 1; - } - else { - if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { - /* Control block will be allocated from the dynamic pool */ - mem = 0; - } - } - } - else { - mem = 0; - } - - if (mem != -1) { - if (max_count == 1U) { - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - hSemaphore = xSemaphoreCreateBinaryStatic ((StaticSemaphore_t *)attr->cb_mem); - #endif - } - else { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - hSemaphore = xSemaphoreCreateBinary(); - #endif - } - - if ((hSemaphore != NULL) && (initial_count != 0U)) { - if (xSemaphoreGive (hSemaphore) != pdPASS) { - vSemaphoreDelete (hSemaphore); - hSemaphore = NULL; - } - } - } - else { - if (mem == 1) { - #if (configSUPPORT_STATIC_ALLOCATION == 1) - hSemaphore = xSemaphoreCreateCountingStatic (max_count, initial_count, (StaticSemaphore_t *)attr->cb_mem); - #endif - } - else { - #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) - hSemaphore = xSemaphoreCreateCounting (max_count, initial_count); - #endif - } - } - - #if (configQUEUE_REGISTRY_SIZE > 0) - if (hSemaphore != NULL) { - if ((attr != NULL) && (attr->name != NULL)) { - /* Only non-NULL name objects are added to the Queue Registry */ - vQueueAddToRegistry (hSemaphore, attr->name); - } - } - #endif - } - } - - /* Return semaphore ID */ - return ((osSemaphoreId_t)hSemaphore); -} - -/* - Acquire a Semaphore token or timeout if no tokens are available. -*/ -osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) { - SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; - osStatus_t stat; - BaseType_t yield; - - stat = osOK; - - if (hSemaphore == NULL) { - stat = osErrorParameter; - } - else if (IRQ_Context() != 0U) { - if (timeout != 0U) { - stat = osErrorParameter; - } - else { - yield = pdFALSE; - - if (xSemaphoreTakeFromISR (hSemaphore, &yield) != pdPASS) { - stat = osErrorResource; - } else { - portYIELD_FROM_ISR (yield); - } - } - } - else { - if (xSemaphoreTake (hSemaphore, (TickType_t)timeout) != pdPASS) { - if (timeout != 0U) { - stat = osErrorTimeout; - } else { - stat = osErrorResource; - } - } - } - - /* Return execution status */ - return (stat); -} - -/* - Release a Semaphore token up to the initial maximum count. -*/ -osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) { - SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; - osStatus_t stat; - BaseType_t yield; - - stat = osOK; - - if (hSemaphore == NULL) { - stat = osErrorParameter; - } - else if (IRQ_Context() != 0U) { - yield = pdFALSE; - - if (xSemaphoreGiveFromISR (hSemaphore, &yield) != pdTRUE) { - stat = osErrorResource; - } else { - portYIELD_FROM_ISR (yield); - } - } - else { - if (xSemaphoreGive (hSemaphore) != pdPASS) { - stat = osErrorResource; - } - } - - /* Return execution status */ - return (stat); -} - -/* - Get current Semaphore token count. -*/ -uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) { - SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; - uint32_t count; - - if (hSemaphore == NULL) { - count = 0U; - } - else if (IRQ_Context() != 0U) { - count = (uint32_t)uxSemaphoreGetCountFromISR (hSemaphore); - } else { - count = (uint32_t)uxSemaphoreGetCount (hSemaphore); - } - - /* Return number of tokens */ - return (count); -} - -/* - Delete a Semaphore object. -*/ -osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) { - SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id; - osStatus_t stat; - -#ifndef USE_FreeRTOS_HEAP_1 - if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else if (hSemaphore == NULL) { - stat = osErrorParameter; - } - else { - #if (configQUEUE_REGISTRY_SIZE > 0) - vQueueUnregisterQueue (hSemaphore); - #endif - - stat = osOK; - vSemaphoreDelete (hSemaphore); - } -#else - stat = osError; -#endif - - /* Return execution status */ - return (stat); -} - - /* ==== Message Queue Management Functions ==== */ /* @@ -2301,498 +1070,6 @@ osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) { return (stat); } - -/* ==== Memory Pool Management Functions ==== */ - -#ifdef FREERTOS_MPOOL_H_ -/* Static memory pool functions */ -static void FreeBlock (MemPool_t *mp, void *block); -static void *AllocBlock (MemPool_t *mp); -static void *CreateBlock (MemPool_t *mp); - -/* - Create and Initialize a Memory Pool object. -*/ -osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) { - MemPool_t *mp; - const char *name; - int32_t mem_cb, mem_mp; - uint32_t sz; - - if (IRQ_Context() != 0U) { - mp = NULL; - } - else if ((block_count == 0U) || (block_size == 0U)) { - mp = NULL; - } - else { - mp = NULL; - sz = MEMPOOL_ARR_SIZE (block_count, block_size); - - name = NULL; - mem_cb = -1; - mem_mp = -1; - - if (attr != NULL) { - if (attr->name != NULL) { - name = attr->name; - } - - if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(MemPool_t))) { - /* Static control block is provided */ - mem_cb = 1; - } - else if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) { - /* Allocate control block memory on heap */ - mem_cb = 0; - } - - if ((attr->mp_mem == NULL) && (attr->mp_size == 0U)) { - /* Allocate memory array on heap */ - mem_mp = 0; - } - else { - if (attr->mp_mem != NULL) { - /* Check if array is 4-byte aligned */ - if (((uint32_t)attr->mp_mem & 3U) == 0U) { - /* Check if array big enough */ - if (attr->mp_size >= sz) { - /* Static memory pool array is provided */ - mem_mp = 1; - } - } - } - } - } - else { - /* Attributes not provided, allocate memory on heap */ - mem_cb = 0; - mem_mp = 0; - } - - if (mem_cb == 0) { - mp = pvPortMalloc (sizeof(MemPool_t)); - } else { - mp = attr->cb_mem; - } - - if (mp != NULL) { - /* Create a semaphore (max count == initial count == block_count) */ - #if (configSUPPORT_STATIC_ALLOCATION == 1) - mp->sem = xSemaphoreCreateCountingStatic (block_count, block_count, &mp->mem_sem); - #elif (configSUPPORT_DYNAMIC_ALLOCATION == 1) - mp->sem = xSemaphoreCreateCounting (block_count, block_count); - #else - mp->sem = NULL; - #endif - - if (mp->sem != NULL) { - /* Setup memory array */ - if (mem_mp == 0) { - mp->mem_arr = pvPortMalloc (sz); - } else { - mp->mem_arr = attr->mp_mem; - } - } - } - - if ((mp != NULL) && (mp->mem_arr != NULL)) { - /* Memory pool can be created */ - mp->head = NULL; - mp->mem_sz = sz; - mp->name = name; - mp->bl_sz = block_size; - mp->bl_cnt = block_count; - mp->n = 0U; - - /* Set heap allocated memory flags */ - mp->status = MPOOL_STATUS; - - if (mem_cb == 0) { - /* Control block on heap */ - mp->status |= 1U; - } - if (mem_mp == 0) { - /* Memory array on heap */ - mp->status |= 2U; - } - } - else { - /* Memory pool cannot be created, release allocated resources */ - if ((mem_cb == 0) && (mp != NULL)) { - /* Free control block memory */ - vPortFree (mp); - } - mp = NULL; - } - } - - /* Return memory pool ID */ - return (mp); -} - -/* - Get name of a Memory Pool object. -*/ -const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id) { - MemPool_t *mp = (osMemoryPoolId_t)mp_id; - const char *p; - - if (IRQ_Context() != 0U) { - p = NULL; - } - else if (mp_id == NULL) { - p = NULL; - } - else { - p = mp->name; - } - - /* Return name as null-terminated string */ - return (p); -} - -/* - Allocate a memory block from a Memory Pool. -*/ -void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) { - MemPool_t *mp; - void *block; - uint32_t isrm; - - if (mp_id == NULL) { - /* Invalid input parameters */ - block = NULL; - } - else { - block = NULL; - - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) { - if (IRQ_Context() != 0U) { - if (timeout == 0U) { - if (xSemaphoreTakeFromISR (mp->sem, NULL) == pdTRUE) { - if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) { - isrm = taskENTER_CRITICAL_FROM_ISR(); - - /* Get a block from the free-list */ - block = AllocBlock(mp); - - if (block == NULL) { - /* List of free blocks is empty, 'create' new block */ - block = CreateBlock(mp); - } - - taskEXIT_CRITICAL_FROM_ISR(isrm); - } - } - } - } - else { - if (xSemaphoreTake (mp->sem, (TickType_t)timeout) == pdTRUE) { - if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS) { - taskENTER_CRITICAL(); - - /* Get a block from the free-list */ - block = AllocBlock(mp); - - if (block == NULL) { - /* List of free blocks is empty, 'create' new block */ - block = CreateBlock(mp); - } - - taskEXIT_CRITICAL(); - } - } - } - } - } - - /* Return memory block address */ - return (block); -} - -/* - Return an allocated memory block back to a Memory Pool. -*/ -osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block) { - MemPool_t *mp; - osStatus_t stat; - uint32_t isrm; - BaseType_t yield; - - if ((mp_id == NULL) || (block == NULL)) { - /* Invalid input parameters */ - stat = osErrorParameter; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - stat = osErrorResource; - } - else if ((block < (void *)&mp->mem_arr[0]) || (block > (void*)&mp->mem_arr[mp->mem_sz-1])) { - /* Block pointer outside of memory array area */ - stat = osErrorParameter; - } - else { - stat = osOK; - - if (IRQ_Context() != 0U) { - if (uxSemaphoreGetCountFromISR (mp->sem) == mp->bl_cnt) { - stat = osErrorResource; - } - else { - isrm = taskENTER_CRITICAL_FROM_ISR(); - - /* Add block to the list of free blocks */ - FreeBlock(mp, block); - - taskEXIT_CRITICAL_FROM_ISR(isrm); - - yield = pdFALSE; - xSemaphoreGiveFromISR (mp->sem, &yield); - portYIELD_FROM_ISR (yield); - } - } - else { - if (uxSemaphoreGetCount (mp->sem) == mp->bl_cnt) { - stat = osErrorResource; - } - else { - taskENTER_CRITICAL(); - - /* Add block to the list of free blocks */ - FreeBlock(mp, block); - - taskEXIT_CRITICAL(); - - xSemaphoreGive (mp->sem); - } - } - } - } - - /* Return execution status */ - return (stat); -} - -/* - Get maximum number of memory blocks in a Memory Pool. -*/ -uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - uint32_t n; - - if (mp_id == NULL) { - /* Invalid input parameters */ - n = 0U; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - n = 0U; - } - else { - n = mp->bl_cnt; - } - } - - /* Return maximum number of memory blocks */ - return (n); -} - -/* - Get memory block size in a Memory Pool. -*/ -uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - uint32_t sz; - - if (mp_id == NULL) { - /* Invalid input parameters */ - sz = 0U; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - sz = 0U; - } - else { - sz = mp->bl_sz; - } - } - - /* Return memory block size in bytes */ - return (sz); -} - -/* - Get number of memory blocks used in a Memory Pool. -*/ -uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - uint32_t n; - - if (mp_id == NULL) { - /* Invalid input parameters */ - n = 0U; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - n = 0U; - } - else { - if (IRQ_Context() != 0U) { - n = uxSemaphoreGetCountFromISR (mp->sem); - } else { - n = uxSemaphoreGetCount (mp->sem); - } - - n = mp->bl_cnt - n; - } - } - - /* Return number of memory blocks used */ - return (n); -} - -/* - Get number of memory blocks available in a Memory Pool. -*/ -uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - uint32_t n; - - if (mp_id == NULL) { - /* Invalid input parameters */ - n = 0U; - } - else { - mp = (MemPool_t *)mp_id; - - if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS) { - /* Invalid object status */ - n = 0U; - } - else { - if (IRQ_Context() != 0U) { - n = uxSemaphoreGetCountFromISR (mp->sem); - } else { - n = uxSemaphoreGetCount (mp->sem); - } - } - } - - /* Return number of memory blocks available */ - return (n); -} - -/* - Delete a Memory Pool object. -*/ -osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id) { - MemPool_t *mp; - osStatus_t stat; - - if (mp_id == NULL) { - /* Invalid input parameters */ - stat = osErrorParameter; - } - else if (IRQ_Context() != 0U) { - stat = osErrorISR; - } - else { - mp = (MemPool_t *)mp_id; - - taskENTER_CRITICAL(); - - /* Invalidate control block status */ - mp->status = mp->status & 3U; - - /* Wake-up tasks waiting for pool semaphore */ - while (xSemaphoreGive (mp->sem) == pdTRUE); - - mp->head = NULL; - mp->bl_sz = 0U; - mp->bl_cnt = 0U; - - if ((mp->status & 2U) != 0U) { - /* Memory pool array allocated on heap */ - vPortFree (mp->mem_arr); - } - if ((mp->status & 1U) != 0U) { - /* Memory pool control block allocated on heap */ - vPortFree (mp); - } - - taskEXIT_CRITICAL(); - - stat = osOK; - } - - /* Return execution status */ - return (stat); -} - -/* - Create new block given according to the current block index. -*/ -static void *CreateBlock (MemPool_t *mp) { - MemPoolBlock_t *p = NULL; - - if (mp->n < mp->bl_cnt) { - /* Unallocated blocks exist, set pointer to new block */ - p = (void *)(mp->mem_arr + (mp->bl_sz * mp->n)); - - /* Increment block index */ - mp->n += 1U; - } - - return (p); -} - -/* - Allocate a block by reading the list of free blocks. -*/ -static void *AllocBlock (MemPool_t *mp) { - MemPoolBlock_t *p = NULL; - - if (mp->head != NULL) { - /* List of free block exists, get head block */ - p = mp->head; - - /* Head block is now next on the list */ - mp->head = p->next; - } - - return (p); -} - -/* - Free block by putting it to the list of free blocks. -*/ -static void FreeBlock (MemPool_t *mp, void *block) { - MemPoolBlock_t *p = block; - - /* Store current head into block memory space */ - p->next = mp->head; - - /* Store current block as new head */ - mp->head = p; -} -#endif /* FREERTOS_MPOOL_H_ */ -/*---------------------------------------------------------------------------*/ - /* Callback function prototypes */ extern void vApplicationIdleHook (void); extern void vApplicationMallocFailedHook (void); @@ -2841,34 +1118,3 @@ __WEAK void vApplicationStackOverflowHook (TaskHandle_t xTask, char *pcTaskName) configASSERT(0); } #endif - -/*---------------------------------------------------------------------------*/ -#if (configSUPPORT_STATIC_ALLOCATION == 1) -/* - vApplicationGetIdleTaskMemory gets called when configSUPPORT_STATIC_ALLOCATION - equals to 1 and is required for static memory allocation support. -*/ -__WEAK void vApplicationGetIdleTaskMemory (StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { - /* Idle task control block and stack */ - static StaticTask_t Idle_TCB; - static StackType_t Idle_Stack[configMINIMAL_STACK_SIZE]; - - *ppxIdleTaskTCBBuffer = &Idle_TCB; - *ppxIdleTaskStackBuffer = &Idle_Stack[0]; - *pulIdleTaskStackSize = (uint32_t)configMINIMAL_STACK_SIZE; -} - -/* - vApplicationGetTimerTaskMemory gets called when configSUPPORT_STATIC_ALLOCATION - equals to 1 and is required for static memory allocation support. -*/ -__WEAK void vApplicationGetTimerTaskMemory (StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { - /* Timer task control block and stack */ - static StaticTask_t Timer_TCB; - static StackType_t Timer_Stack[configTIMER_TASK_STACK_DEPTH]; - - *ppxTimerTaskTCBBuffer = &Timer_TCB; - *ppxTimerTaskStackBuffer = &Timer_Stack[0]; - *pulTimerTaskStackSize = (uint32_t)configTIMER_TASK_STACK_DEPTH; -} -#endif diff --git a/lib/FreeRTOS-glue/cmsis_os2.h b/lib/FreeRTOS-glue/cmsis_os2.h index 76612e29..044c9851 100644 --- a/lib/FreeRTOS-glue/cmsis_os2.h +++ b/lib/FreeRTOS-glue/cmsis_os2.h @@ -43,10 +43,10 @@ * Version 2.0.0 * Initial Release *---------------------------------------------------------------------------*/ - + #ifndef CMSIS_OS2_H_ #define CMSIS_OS2_H_ - + #ifndef __NO_RETURN #if defined(__CC_ARM) #define __NO_RETURN __declspec(noreturn) @@ -60,24 +60,23 @@ #define __NO_RETURN #endif #endif - -#include -#include - + +#include + #ifdef __cplusplus extern "C" { #endif - - + + // ==== Enumerations, structures, defines ==== - + /// Version information. typedef struct { uint32_t api; ///< API version (major.minor.rev: mmnnnrrrr dec). uint32_t kernel; ///< Kernel version (major.minor.rev: mmnnnrrrr dec). } osVersion_t; - + /// Kernel state. typedef enum { osKernelInactive = 0, ///< Inactive. @@ -88,167 +87,31 @@ typedef enum { osKernelError = -1, ///< Error. osKernelReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. } osKernelState_t; - -/// Thread state. -typedef enum { - osThreadInactive = 0, ///< Inactive. - osThreadReady = 1, ///< Ready. - osThreadRunning = 2, ///< Running. - osThreadBlocked = 3, ///< Blocked. - osThreadTerminated = 4, ///< Terminated. - osThreadError = -1, ///< Error. - osThreadReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. -} osThreadState_t; - -/// Priority values. -typedef enum { - osPriorityNone = 0, ///< No priority (not initialized). - osPriorityIdle = 1, ///< Reserved for Idle thread. - osPriorityLow = 8, ///< Priority: low - osPriorityLow1 = 8+1, ///< Priority: low + 1 - osPriorityLow2 = 8+2, ///< Priority: low + 2 - osPriorityLow3 = 8+3, ///< Priority: low + 3 - osPriorityLow4 = 8+4, ///< Priority: low + 4 - osPriorityLow5 = 8+5, ///< Priority: low + 5 - osPriorityLow6 = 8+6, ///< Priority: low + 6 - osPriorityLow7 = 8+7, ///< Priority: low + 7 - osPriorityBelowNormal = 16, ///< Priority: below normal - osPriorityBelowNormal1 = 16+1, ///< Priority: below normal + 1 - osPriorityBelowNormal2 = 16+2, ///< Priority: below normal + 2 - osPriorityBelowNormal3 = 16+3, ///< Priority: below normal + 3 - osPriorityBelowNormal4 = 16+4, ///< Priority: below normal + 4 - osPriorityBelowNormal5 = 16+5, ///< Priority: below normal + 5 - osPriorityBelowNormal6 = 16+6, ///< Priority: below normal + 6 - osPriorityBelowNormal7 = 16+7, ///< Priority: below normal + 7 - osPriorityNormal = 24, ///< Priority: normal - osPriorityNormal1 = 24+1, ///< Priority: normal + 1 - osPriorityNormal2 = 24+2, ///< Priority: normal + 2 - osPriorityNormal3 = 24+3, ///< Priority: normal + 3 - osPriorityNormal4 = 24+4, ///< Priority: normal + 4 - osPriorityNormal5 = 24+5, ///< Priority: normal + 5 - osPriorityNormal6 = 24+6, ///< Priority: normal + 6 - osPriorityNormal7 = 24+7, ///< Priority: normal + 7 - osPriorityAboveNormal = 32, ///< Priority: above normal - osPriorityAboveNormal1 = 32+1, ///< Priority: above normal + 1 - osPriorityAboveNormal2 = 32+2, ///< Priority: above normal + 2 - osPriorityAboveNormal3 = 32+3, ///< Priority: above normal + 3 - osPriorityAboveNormal4 = 32+4, ///< Priority: above normal + 4 - osPriorityAboveNormal5 = 32+5, ///< Priority: above normal + 5 - osPriorityAboveNormal6 = 32+6, ///< Priority: above normal + 6 - osPriorityAboveNormal7 = 32+7, ///< Priority: above normal + 7 - osPriorityHigh = 40, ///< Priority: high - osPriorityHigh1 = 40+1, ///< Priority: high + 1 - osPriorityHigh2 = 40+2, ///< Priority: high + 2 - osPriorityHigh3 = 40+3, ///< Priority: high + 3 - osPriorityHigh4 = 40+4, ///< Priority: high + 4 - osPriorityHigh5 = 40+5, ///< Priority: high + 5 - osPriorityHigh6 = 40+6, ///< Priority: high + 6 - osPriorityHigh7 = 40+7, ///< Priority: high + 7 - osPriorityRealtime = 48, ///< Priority: realtime - osPriorityRealtime1 = 48+1, ///< Priority: realtime + 1 - osPriorityRealtime2 = 48+2, ///< Priority: realtime + 2 - osPriorityRealtime3 = 48+3, ///< Priority: realtime + 3 - osPriorityRealtime4 = 48+4, ///< Priority: realtime + 4 - osPriorityRealtime5 = 48+5, ///< Priority: realtime + 5 - osPriorityRealtime6 = 48+6, ///< Priority: realtime + 6 - osPriorityRealtime7 = 48+7, ///< Priority: realtime + 7 - osPriorityISR = 56, ///< Reserved for ISR deferred thread. - osPriorityError = -1, ///< System cannot determine priority or illegal priority. - osPriorityReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. -} osPriority_t; - -/// Entry point of a thread. -typedef void (*osThreadFunc_t) (void *argument); - + /// Timer callback function. typedef void (*osTimerFunc_t) (void *argument); - + /// Timer type. typedef enum { osTimerOnce = 0, ///< One-shot timer. osTimerPeriodic = 1 ///< Repeating timer. } osTimerType_t; - -// Timeout value. -#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value. - -// Flags options (\ref osThreadFlagsWait and \ref osEventFlagsWait). -#define osFlagsWaitAny 0x00000000U ///< Wait for any flag (default). -#define osFlagsWaitAll 0x00000001U ///< Wait for all flags. -#define osFlagsNoClear 0x00000002U ///< Do not clear flags which have been specified to wait for. - -// Flags errors (returned by osThreadFlagsXxxx and osEventFlagsXxxx). -#define osFlagsError 0x80000000U ///< Error indicator. -#define osFlagsErrorUnknown 0xFFFFFFFFU ///< osError (-1). -#define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2). -#define osFlagsErrorResource 0xFFFFFFFDU ///< osErrorResource (-3). -#define osFlagsErrorParameter 0xFFFFFFFCU ///< osErrorParameter (-4). -#define osFlagsErrorISR 0xFFFFFFFAU ///< osErrorISR (-6). - -// Thread attributes (attr_bits in \ref osThreadAttr_t). -#define osThreadDetached 0x00000000U ///< Thread created in detached mode (default) -#define osThreadJoinable 0x00000001U ///< Thread created in joinable mode - -// Mutex attributes (attr_bits in \ref osMutexAttr_t). -#define osMutexRecursive 0x00000001U ///< Recursive mutex. -#define osMutexPrioInherit 0x00000002U ///< Priority inherit protocol. -#define osMutexRobust 0x00000008U ///< Robust mutex. - -/// Status code values returned by CMSIS-RTOS functions. -typedef enum { - osOK = 0, ///< Operation completed successfully. - osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits. - osErrorTimeout = -2, ///< Operation not completed within the timeout period. - osErrorResource = -3, ///< Resource not available. - osErrorParameter = -4, ///< Parameter error. - osErrorNoMemory = -5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation. - osErrorISR = -6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines. - osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. -} osStatus_t; - - -/// \details Thread ID identifies the thread. -typedef void *osThreadId_t; - + + /// \details Timer ID identifies the timer. typedef void *osTimerId_t; - -/// \details Event Flags ID identifies the event flags. -typedef void *osEventFlagsId_t; - -/// \details Mutex ID identifies the mutex. -typedef void *osMutexId_t; - -/// \details Semaphore ID identifies the semaphore. -typedef void *osSemaphoreId_t; - -/// \details Memory Pool ID identifies the memory pool. -typedef void *osMemoryPoolId_t; - + /// \details Message Queue ID identifies the message queue. typedef void *osMessageQueueId_t; - - + + #ifndef TZ_MODULEID_T #define TZ_MODULEID_T /// \details Data type that identifies secure software modules called by a process. typedef uint32_t TZ_ModuleId_t; #endif - - -/// Attributes structure for thread. -typedef struct { - const char *name; ///< name of the thread - uint32_t attr_bits; ///< attribute bits - void *cb_mem; ///< memory for control block - uint32_t cb_size; ///< size of provided memory for control block - void *stack_mem; ///< memory for stack - uint32_t stack_size; ///< size of stack - osPriority_t priority; ///< initial thread priority (default: osPriorityNormal) - TZ_ModuleId_t tz_module; ///< TrustZone module identifier - uint32_t reserved; ///< reserved (must be 0) -} osThreadAttr_t; - + + /// Attributes structure for timer. typedef struct { const char *name; ///< name of the timer @@ -256,41 +119,7 @@ typedef struct { void *cb_mem; ///< memory for control block uint32_t cb_size; ///< size of provided memory for control block } osTimerAttr_t; - -/// Attributes structure for event flags. -typedef struct { - const char *name; ///< name of the event flags - uint32_t attr_bits; ///< attribute bits - void *cb_mem; ///< memory for control block - uint32_t cb_size; ///< size of provided memory for control block -} osEventFlagsAttr_t; - -/// Attributes structure for mutex. -typedef struct { - const char *name; ///< name of the mutex - uint32_t attr_bits; ///< attribute bits - void *cb_mem; ///< memory for control block - uint32_t cb_size; ///< size of provided memory for control block -} osMutexAttr_t; - -/// Attributes structure for semaphore. -typedef struct { - const char *name; ///< name of the semaphore - uint32_t attr_bits; ///< attribute bits - void *cb_mem; ///< memory for control block - uint32_t cb_size; ///< size of provided memory for control block -} osSemaphoreAttr_t; - -/// Attributes structure for memory pool. -typedef struct { - const char *name; ///< name of the memory pool - uint32_t attr_bits; ///< attribute bits - void *cb_mem; ///< memory for control block - uint32_t cb_size; ///< size of provided memory for control block - void *mp_mem; ///< memory for data storage - uint32_t mp_size; ///< size of provided memory for data storage -} osMemoryPoolAttr_t; - + /// Attributes structure for message queue. typedef struct { const char *name; ///< name of the message queue @@ -298,196 +127,79 @@ typedef struct { void *cb_mem; ///< memory for control block uint32_t cb_size; ///< size of provided memory for control block void *mq_mem; ///< memory for data storage - uint32_t mq_size; ///< size of provided memory for data storage + uint32_t mq_size; ///< size of provided memory for data storage } osMessageQueueAttr_t; - - + + // ==== Kernel Management Functions ==== - + /// Initialize the RTOS Kernel. /// \return status code that indicates the execution status of the function. osStatus_t osKernelInitialize (void); - + /// Get RTOS Kernel Information. /// \param[out] version pointer to buffer for retrieving version information. /// \param[out] id_buf pointer to buffer for retrieving kernel identification string. /// \param[in] id_size size of buffer for kernel identification string. /// \return status code that indicates the execution status of the function. osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size); - + /// Get the current RTOS Kernel state. /// \return current RTOS Kernel state. osKernelState_t osKernelGetState (void); - + /// Start the RTOS Kernel scheduler. /// \return status code that indicates the execution status of the function. osStatus_t osKernelStart (void); - + /// Lock the RTOS Kernel scheduler. /// \return previous lock state (1 - locked, 0 - not locked, error code if negative). int32_t osKernelLock (void); - + /// Unlock the RTOS Kernel scheduler. /// \return previous lock state (1 - locked, 0 - not locked, error code if negative). int32_t osKernelUnlock (void); - + /// Restore the RTOS Kernel scheduler lock state. /// \param[in] lock lock state obtained by \ref osKernelLock or \ref osKernelUnlock. /// \return new lock state (1 - locked, 0 - not locked, error code if negative). int32_t osKernelRestoreLock (int32_t lock); - + /// Suspend the RTOS Kernel scheduler. /// \return time in ticks, for how long the system can sleep or power-down. uint32_t osKernelSuspend (void); - + /// Resume the RTOS Kernel scheduler. /// \param[in] sleep_ticks time in ticks for how long the system was in sleep or power-down mode. void osKernelResume (uint32_t sleep_ticks); - + /// Get the RTOS kernel tick count. /// \return RTOS kernel current tick count. uint32_t osKernelGetTickCount (void); - + /// Get the RTOS kernel tick frequency. /// \return frequency of the kernel tick in hertz, i.e. kernel ticks per second. uint32_t osKernelGetTickFreq (void); - -/// Get the RTOS kernel system timer count. -/// \return RTOS kernel current system timer count as 32-bit value. -uint32_t osKernelGetSysTimerCount (void); - + /// Get the RTOS kernel system timer frequency. /// \return frequency of the system timer in hertz, i.e. timer ticks per second. uint32_t osKernelGetSysTimerFreq (void); - - -// ==== Thread Management Functions ==== - -/// Create a thread and add it to Active Threads. -/// \param[in] func thread function. -/// \param[in] argument pointer that is passed to the thread function as start argument. -/// \param[in] attr thread attributes; NULL: default values. -/// \return thread ID for reference by other functions or NULL in case of error. -osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr); - -/// Get name of a thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return name as null-terminated string. -const char *osThreadGetName (osThreadId_t thread_id); - -/// Return the thread ID of the current running thread. -/// \return thread ID for reference by other functions or NULL in case of error. -osThreadId_t osThreadGetId (void); - -/// Get current thread state of a thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return current thread state of the specified thread. -osThreadState_t osThreadGetState (osThreadId_t thread_id); - -/// Get stack size of a thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return stack size in bytes. -uint32_t osThreadGetStackSize (osThreadId_t thread_id); - -/// Get available stack space of a thread based on stack watermark recording during execution. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return remaining stack space in bytes. -uint32_t osThreadGetStackSpace (osThreadId_t thread_id); - -/// Change priority of a thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \param[in] priority new priority value for the thread function. -/// \return status code that indicates the execution status of the function. -osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority); - -/// Get current priority of a thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return current priority value of the specified thread. -osPriority_t osThreadGetPriority (osThreadId_t thread_id); - -/// Pass control to next thread that is in state \b READY. -/// \return status code that indicates the execution status of the function. -osStatus_t osThreadYield (void); - -/// Suspend execution of a thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return status code that indicates the execution status of the function. -osStatus_t osThreadSuspend (osThreadId_t thread_id); - -/// Resume execution of a thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return status code that indicates the execution status of the function. -osStatus_t osThreadResume (osThreadId_t thread_id); - -/// Detach a thread (thread storage can be reclaimed when thread terminates). -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return status code that indicates the execution status of the function. -osStatus_t osThreadDetach (osThreadId_t thread_id); - -/// Wait for specified thread to terminate. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return status code that indicates the execution status of the function. -osStatus_t osThreadJoin (osThreadId_t thread_id); - -/// Terminate execution of current running thread. -__NO_RETURN void osThreadExit (void); - -/// Terminate execution of a thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \return status code that indicates the execution status of the function. -osStatus_t osThreadTerminate (osThreadId_t thread_id); - -/// Get number of active threads. -/// \return number of active threads. -uint32_t osThreadGetCount (void); - -/// Enumerate active threads. -/// \param[out] thread_array pointer to array for retrieving thread IDs. -/// \param[in] array_items maximum number of items in array for retrieving thread IDs. -/// \return number of enumerated threads. -uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items); - - -// ==== Thread Flags Functions ==== - -/// Set the specified Thread Flags of a thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. -/// \param[in] flags specifies the flags of the thread that shall be set. -/// \return thread flags after setting or error code if highest bit set. -uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags); - -/// Clear the specified Thread Flags of current running thread. -/// \param[in] flags specifies the flags of the thread that shall be cleared. -/// \return thread flags before clearing or error code if highest bit set. -uint32_t osThreadFlagsClear (uint32_t flags); - -/// Get the current Thread Flags of current running thread. -/// \return current thread flags. -uint32_t osThreadFlagsGet (void); - -/// Wait for one or more Thread Flags of the current running thread to become signaled. -/// \param[in] flags specifies the flags to wait for. -/// \param[in] options specifies flags options (osFlagsXxxx). -/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. -/// \return thread flags before clearing or error code if highest bit set. -uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout); - - + // ==== Generic Wait Functions ==== - + /// Wait for Timeout (Time Delay). /// \param[in] ticks \ref CMSIS_RTOS_TimeOutValue "time ticks" value /// \return status code that indicates the execution status of the function. osStatus_t osDelay (uint32_t ticks); - + /// Wait until specified time. /// \param[in] ticks absolute time in ticks /// \return status code that indicates the execution status of the function. osStatus_t osDelayUntil (uint32_t ticks); - - + + // ==== Timer Management Functions ==== - + /// Create and Initialize a timer. /// \param[in] func function pointer to callback function. /// \param[in] type \ref osTimerOnce for one-shot or \ref osTimerPeriodic for periodic behavior. @@ -495,213 +207,47 @@ osStatus_t osDelayUntil (uint32_t ticks); /// \param[in] attr timer attributes; NULL: default values. /// \return timer ID for reference by other functions or NULL in case of error. osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr); - + /// Get name of a timer. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \return name as null-terminated string. const char *osTimerGetName (osTimerId_t timer_id); - + /// Start or restart a timer. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \param[in] ticks \ref CMSIS_RTOS_TimeOutValue "time ticks" value of the timer. /// \return status code that indicates the execution status of the function. osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks); - + /// Stop a timer. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \return status code that indicates the execution status of the function. osStatus_t osTimerStop (osTimerId_t timer_id); - + /// Check if a timer is running. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \return 0 not running, 1 running. uint32_t osTimerIsRunning (osTimerId_t timer_id); - + /// Delete a timer. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \return status code that indicates the execution status of the function. osStatus_t osTimerDelete (osTimerId_t timer_id); - - -// ==== Event Flags Management Functions ==== - -/// Create and Initialize an Event Flags object. -/// \param[in] attr event flags attributes; NULL: default values. -/// \return event flags ID for reference by other functions or NULL in case of error. -osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr); - -/// Get name of an Event Flags object. -/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. -/// \return name as null-terminated string. -const char *osEventFlagsGetName (osEventFlagsId_t ef_id); - -/// Set the specified Event Flags. -/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. -/// \param[in] flags specifies the flags that shall be set. -/// \return event flags after setting or error code if highest bit set. -uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags); - -/// Clear the specified Event Flags. -/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. -/// \param[in] flags specifies the flags that shall be cleared. -/// \return event flags before clearing or error code if highest bit set. -uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags); - -/// Get the current Event Flags. -/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. -/// \return current event flags. -uint32_t osEventFlagsGet (osEventFlagsId_t ef_id); - -/// Wait for one or more Event Flags to become signaled. -/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. -/// \param[in] flags specifies the flags to wait for. -/// \param[in] options specifies flags options (osFlagsXxxx). -/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. -/// \return event flags before clearing or error code if highest bit set. -uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout); - -/// Delete an Event Flags object. -/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. -/// \return status code that indicates the execution status of the function. -osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id); - - -// ==== Mutex Management Functions ==== - -/// Create and Initialize a Mutex object. -/// \param[in] attr mutex attributes; NULL: default values. -/// \return mutex ID for reference by other functions or NULL in case of error. -osMutexId_t osMutexNew (const osMutexAttr_t *attr); - -/// Get name of a Mutex object. -/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. -/// \return name as null-terminated string. -const char *osMutexGetName (osMutexId_t mutex_id); - -/// Acquire a Mutex or timeout if it is locked. -/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. -/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. -/// \return status code that indicates the execution status of the function. -osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout); - -/// Release a Mutex that was acquired by \ref osMutexAcquire. -/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. -/// \return status code that indicates the execution status of the function. -osStatus_t osMutexRelease (osMutexId_t mutex_id); - -/// Get Thread which owns a Mutex object. -/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. -/// \return thread ID of owner thread or NULL when mutex was not acquired. -osThreadId_t osMutexGetOwner (osMutexId_t mutex_id); - -/// Delete a Mutex object. -/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. -/// \return status code that indicates the execution status of the function. -osStatus_t osMutexDelete (osMutexId_t mutex_id); - - -// ==== Semaphore Management Functions ==== - -/// Create and Initialize a Semaphore object. -/// \param[in] max_count maximum number of available tokens. -/// \param[in] initial_count initial number of available tokens. -/// \param[in] attr semaphore attributes; NULL: default values. -/// \return semaphore ID for reference by other functions or NULL in case of error. -osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr); - -/// Get name of a Semaphore object. -/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. -/// \return name as null-terminated string. -const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id); - -/// Acquire a Semaphore token or timeout if no tokens are available. -/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. -/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. -/// \return status code that indicates the execution status of the function. -osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout); - -/// Release a Semaphore token up to the initial maximum count. -/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. -/// \return status code that indicates the execution status of the function. -osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id); - -/// Get current Semaphore token count. -/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. -/// \return number of tokens available. -uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id); - -/// Delete a Semaphore object. -/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. -/// \return status code that indicates the execution status of the function. -osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id); - - -// ==== Memory Pool Management Functions ==== - -/// Create and Initialize a Memory Pool object. -/// \param[in] block_count maximum number of memory blocks in memory pool. -/// \param[in] block_size memory block size in bytes. -/// \param[in] attr memory pool attributes; NULL: default values. -/// \return memory pool ID for reference by other functions or NULL in case of error. -osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr); - -/// Get name of a Memory Pool object. -/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. -/// \return name as null-terminated string. -const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id); - -/// Allocate a memory block from a Memory Pool. -/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. -/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. -/// \return address of the allocated memory block or NULL in case of no memory is available. -void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout); - -/// Return an allocated memory block back to a Memory Pool. -/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. -/// \param[in] block address of the allocated memory block to be returned to the memory pool. -/// \return status code that indicates the execution status of the function. -osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block); - -/// Get maximum number of memory blocks in a Memory Pool. -/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. -/// \return maximum number of memory blocks. -uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id); - -/// Get memory block size in a Memory Pool. -/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. -/// \return memory block size in bytes. -uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id); - -/// Get number of memory blocks used in a Memory Pool. -/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. -/// \return number of memory blocks used. -uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id); - -/// Get number of memory blocks available in a Memory Pool. -/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. -/// \return number of memory blocks available. -uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id); - -/// Delete a Memory Pool object. -/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. -/// \return status code that indicates the execution status of the function. -osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id); - - + // ==== Message Queue Management Functions ==== - + /// Create and Initialize a Message Queue object. /// \param[in] msg_count maximum number of messages in queue. /// \param[in] msg_size maximum message size in bytes. /// \param[in] attr message queue attributes; NULL: default values. /// \return message queue ID for reference by other functions or NULL in case of error. osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr); - + /// Get name of a Message Queue object. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return name as null-terminated string. const char *osMessageQueueGetName (osMessageQueueId_t mq_id); - + /// Put a Message into a Queue or timeout if Queue is full. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \param[in] msg_ptr pointer to buffer with message to put into a queue. @@ -709,7 +255,7 @@ const char *osMessageQueueGetName (osMessageQueueId_t mq_id); /// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. /// \return status code that indicates the execution status of the function. osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout); - + /// Get a Message from a Queue or timeout if Queue is empty. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \param[out] msg_ptr pointer to buffer for message to get from a queue. @@ -717,40 +263,40 @@ osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uin /// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. /// \return status code that indicates the execution status of the function. osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout); - + /// Get maximum number of messages in a Message Queue. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return maximum number of messages. uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id); - + /// Get maximum message size in a Message Queue. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return maximum message size in bytes. uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id); - + /// Get number of queued messages in a Message Queue. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return number of queued messages. uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id); - + /// Get number of available slots for messages in a Message Queue. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return number of available slots for messages. uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id); - + /// Reset a Message Queue to initial empty state. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return status code that indicates the execution status of the function. osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id); - + /// Delete a Message Queue object. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return status code that indicates the execution status of the function. osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id); - - + + #ifdef __cplusplus } #endif - + #endif // CMSIS_OS2_H_ diff --git a/lib/FreeRTOS-glue/freertos_mpool.h b/lib/FreeRTOS-glue/freertos_mpool.h deleted file mode 100644 index cea5017e..00000000 --- a/lib/FreeRTOS-glue/freertos_mpool.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -------------------------------------------------------------------------- - * Copyright (c) 2013-2020 Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Name: freertos_mpool.h - * Purpose: CMSIS RTOS2 wrapper for FreeRTOS - * - *---------------------------------------------------------------------------*/ - -#ifndef FREERTOS_MPOOL_H_ -#define FREERTOS_MPOOL_H_ - -#include -#include "FreeRTOS.h" -#include "semphr.h" - -/* Memory Pool implementation definitions */ -#define MPOOL_STATUS 0x5EED0000U - -/* Memory Block header */ -typedef struct { - void *next; /* Pointer to next block */ -} MemPoolBlock_t; - -/* Memory Pool control block */ -typedef struct MemPoolDef_t { - MemPoolBlock_t *head; /* Pointer to head block */ - SemaphoreHandle_t sem; /* Pool semaphore handle */ - uint8_t *mem_arr; /* Pool memory array */ - uint32_t mem_sz; /* Pool memory array size */ - const char *name; /* Pointer to name string */ - uint32_t bl_sz; /* Size of a single block */ - uint32_t bl_cnt; /* Number of blocks */ - uint32_t n; /* Block allocation index */ - volatile uint32_t status; /* Object status flags */ -#if (configSUPPORT_STATIC_ALLOCATION == 1) - StaticSemaphore_t mem_sem; /* Semaphore object memory */ -#endif -} MemPool_t; - -/* No need to hide static object type, just align to coding style */ -#define StaticMemPool_t MemPool_t - -/* Define memory pool control block size */ -#define MEMPOOL_CB_SIZE (sizeof(StaticMemPool_t)) - -/* Define size of the byte array required to create count of blocks of given size */ -#define MEMPOOL_ARR_SIZE(bl_count, bl_size) (((((bl_size) + (4 - 1)) / 4) * 4)*(bl_count)) - -#endif /* FREERTOS_MPOOL_H_ */ diff --git a/lib/FreeRTOS-glue/freertos_os2.h b/lib/FreeRTOS-glue/freertos_os2.h index f67d2ae9..1e70b3fc 100644 --- a/lib/FreeRTOS-glue/freertos_os2.h +++ b/lib/FreeRTOS-glue/freertos_os2.h @@ -75,7 +75,7 @@ #endif /* - Option to exclude CMSIS-RTOS2 function osThreadEnumerate from the application image. + Option to exclude CMSIS-RTOS2 function furi_thread_enumerate from the application image. */ #ifndef configUSE_OS2_THREAD_ENUMERATE #define configUSE_OS2_THREAD_ENUMERATE 1 @@ -153,7 +153,7 @@ #if (INCLUDE_xTaskGetCurrentTaskHandle == 0) /* CMSIS-RTOS2 API uses FreeRTOS function xTaskGetCurrentTaskHandle to implement - functions osThreadGetId, osThreadFlagsClear and osThreadFlagsGet. In case if these + functions osThreadGetId, furi_thread_flags_clear and furi_thread_flags_get. In case if these functions are not used in the application image, compiler will optimize them away. Set #define INCLUDE_xTaskGetCurrentTaskHandle 1 to fix this error. */ @@ -170,8 +170,8 @@ #endif #if (INCLUDE_uxTaskGetStackHighWaterMark == 0) /* - CMSIS-RTOS2 function osThreadGetStackSpace uses FreeRTOS function uxTaskGetStackHighWaterMark. - In case if osThreadGetStackSpace is not used in the application image, compiler will + CMSIS-RTOS2 function furi_thread_get_stack_space uses FreeRTOS function uxTaskGetStackHighWaterMark. + In case if furi_thread_get_stack_space is not used in the application image, compiler will optimize it away. Set #define INCLUDE_uxTaskGetStackHighWaterMark 1 to fix this error. */ @@ -294,16 +294,16 @@ #if (configUSE_TRACE_FACILITY == 0) /* - CMSIS-RTOS2 function osThreadEnumerate requires FreeRTOS function uxTaskGetSystemState + CMSIS-RTOS2 function furi_thread_enumerate requires FreeRTOS function uxTaskGetSystemState which is only enabled if configUSE_TRACE_FACILITY == 1. Set #define configUSE_TRACE_FACILITY 1 to fix this error. - Alternatively, if the application does not use osThreadEnumerate it can be + Alternatively, if the application does not use furi_thread_enumerate it can be excluded from the image code by setting: #define configUSE_OS2_THREAD_ENUMERATE 0 (in FreeRTOSConfig.h) */ #if (configUSE_OS2_THREAD_ENUMERATE == 1) - #error "Definition configUSE_TRACE_FACILITY must equal 1 to implement osThreadEnumerate." + #error "Definition configUSE_TRACE_FACILITY must equal 1 to implement furi_thread_enumerate." #endif #endif @@ -316,21 +316,4 @@ #error "Definition configUSE_16_BIT_TICKS must be zero to implement CMSIS-RTOS2 API." #endif -#if (configMAX_PRIORITIES != 56) - /* - CMSIS-RTOS2 defines 56 different priorities (see osPriority_t) and portable CMSIS-RTOS2 - implementation should implement the same number of priorities. - Set #define configMAX_PRIORITIES 56 to fix this error. - */ - #error "Definition configMAX_PRIORITIES must equal 56 to implement Thread Management API." -#endif -#if (configUSE_PORT_OPTIMISED_TASK_SELECTION != 0) - /* - CMSIS-RTOS2 requires handling of 56 different priorities (see osPriority_t) while FreeRTOS port - optimised selection for Cortex core only handles 32 different priorities. - Set #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 to fix this error. - */ - #error "Definition configUSE_PORT_OPTIMISED_TASK_SELECTION must be zero to implement Thread Management API." -#endif - #endif /* FREERTOS_OS2_H_ */ diff --git a/lib/FreeRTOS-glue/os_tick.h b/lib/FreeRTOS-glue/os_tick.h deleted file mode 100644 index 3cfd8954..00000000 --- a/lib/FreeRTOS-glue/os_tick.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************//** - * @file os_tick.h - * @brief CMSIS OS Tick header file - * @version V1.0.2 - * @date 19. March 2021 - ******************************************************************************/ -/* - * Copyright (c) 2017-2021 ARM Limited. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef OS_TICK_H -#define OS_TICK_H - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -/// IRQ Handler. -#ifndef IRQHANDLER_T -#define IRQHANDLER_T -typedef void (*IRQHandler_t) (void); -#endif - -/// Setup OS Tick timer to generate periodic RTOS Kernel Ticks -/// \param[in] freq tick frequency in Hz -/// \param[in] handler tick IRQ handler -/// \return 0 on success, -1 on error. -int32_t OS_Tick_Setup (uint32_t freq, IRQHandler_t handler); - -/// Enable OS Tick timer interrupt -void OS_Tick_Enable (void); - -/// Disable OS Tick timer interrupt -void OS_Tick_Disable (void); - -/// Acknowledge execution of OS Tick timer interrupt -void OS_Tick_AcknowledgeIRQ (void); - -/// Get OS Tick timer IRQ number -/// \return OS Tick IRQ number -int32_t OS_Tick_GetIRQn (void); - -/// Get OS Tick timer clock frequency -/// \return OS Tick timer clock frequency in Hz -uint32_t OS_Tick_GetClock (void); - -/// Get OS Tick timer interval reload value -/// \return OS Tick timer interval reload value -uint32_t OS_Tick_GetInterval (void); - -/// Get OS Tick timer counter value -/// \return OS Tick timer counter value -uint32_t OS_Tick_GetCount (void); - -/// Get OS Tick timer overflow status -/// \return OS Tick overflow status (1 - overflow, 0 - no overflow). -uint32_t OS_Tick_GetOverflow (void); - -#ifdef __cplusplus -} -#endif - -#endif /* OS_TICK_H */ diff --git a/lib/ST25RFAL002/platform.c b/lib/ST25RFAL002/platform.c index 52ac843e..c688bd59 100644 --- a/lib/ST25RFAL002/platform.c +++ b/lib/ST25RFAL002/platform.c @@ -3,49 +3,58 @@ #include #include -static const osThreadAttr_t platform_irq_thread_attr = { - .name = "RfalIrqDriver", - .stack_size = 1024, - .priority = osPriorityRealtime, -}; +typedef struct { + FuriThread* thread; + volatile PlatformIrqCallback callback; +} RfalPlatform; -static volatile osThreadId_t platform_irq_thread_id = NULL; -static volatile PlatformIrqCallback platform_irq_callback = NULL; -static const GpioPin pin = {ST25R_INT_PORT, ST25R_INT_PIN}; +static volatile RfalPlatform rfal_platform = { + .thread = NULL, + .callback = NULL, +}; void nfc_isr(void* _ctx) { UNUSED(_ctx); - if(platform_irq_callback && platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) { - osThreadFlagsSet(platform_irq_thread_id, 0x1); + if(rfal_platform.callback && platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) { + furi_thread_flags_set(furi_thread_get_id(rfal_platform.thread), 0x1); } } -void platformIrqThread() { +int32_t rfal_platform_irq_thread(void* context) { + UNUSED(context); + while(1) { - uint32_t flags = osThreadFlagsWait(0x1, osFlagsWaitAny, osWaitForever); + uint32_t flags = furi_thread_flags_wait(0x1, osFlagsWaitAny, osWaitForever); if(flags & 0x1) { - platform_irq_callback(); + rfal_platform.callback(); } } } void platformEnableIrqCallback() { - furi_hal_gpio_init(&pin, GpioModeInterruptRise, GpioPullDown, GpioSpeedLow); - furi_hal_gpio_enable_int_callback(&pin); + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullDown, GpioSpeedLow); + furi_hal_gpio_enable_int_callback(&gpio_nfc_irq_rfid_pull); } void platformDisableIrqCallback() { - furi_hal_gpio_init(&pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_disable_int_callback(&pin); + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull); } void platformSetIrqCallback(PlatformIrqCallback callback) { - platform_irq_callback = callback; - platform_irq_thread_id = osThreadNew(platformIrqThread, NULL, &platform_irq_thread_attr); - furi_hal_gpio_add_int_callback(&pin, nfc_isr, NULL); + rfal_platform.callback = callback; + rfal_platform.thread = furi_thread_alloc(); + + furi_thread_set_name(rfal_platform.thread, "RfalIrqDriver"); + furi_thread_set_callback(rfal_platform.thread, rfal_platform_irq_thread); + furi_thread_set_stack_size(rfal_platform.thread, 1024); + furi_thread_set_priority(rfal_platform.thread, FuriThreadPriorityIsr); + furi_thread_start(rfal_platform.thread); + + furi_hal_gpio_add_int_callback(&gpio_nfc_irq_rfid_pull, nfc_isr, NULL); // Disable interrupt callback as the pin is shared between 2 apps // It is enabled in rfalLowPowerModeStop() - furi_hal_gpio_disable_int_callback(&pin); + furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull); } bool platformSpiTxRx(const uint8_t* txBuf, uint8_t* rxBuf, uint16_t len) { diff --git a/lib/infrared/worker/infrared_worker.c b/lib/infrared/worker/infrared_worker.c index 71126c86..b24b7480 100644 --- a/lib/infrared/worker/infrared_worker.c +++ b/lib/infrared/worker/infrared_worker.c @@ -92,8 +92,8 @@ static void infrared_worker_furi_hal_message_sent_isr_callback(void* context); static void infrared_worker_rx_timeout_callback(void* context) { InfraredWorker* instance = context; - uint32_t flags_set = osThreadFlagsSet( - furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_RX_TIMEOUT_RECEIVED); + uint32_t flags_set = furi_thread_flags_set( + furi_thread_get_id(instance->thread), INFRARED_WORKER_RX_TIMEOUT_RECEIVED); furi_check(flags_set & INFRARED_WORKER_RX_TIMEOUT_RECEIVED); } @@ -110,7 +110,7 @@ static void infrared_worker_rx_callback(void* context, bool level, uint32_t dura INFRARED_WORKER_OVERRUN; portYIELD_FROM_ISR(xHigherPriorityTaskWoken); - uint32_t flags_set = osThreadFlagsSet(furi_thread_get_thread_id(instance->thread), events); + uint32_t flags_set = furi_thread_flags_set(furi_thread_get_id(instance->thread), events); furi_check(flags_set & events); } @@ -152,8 +152,8 @@ static void instance->signal.timings[instance->signal.timings_cnt] = duration; ++instance->signal.timings_cnt; } else { - uint32_t flags_set = osThreadFlagsSet( - furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_OVERRUN); + uint32_t flags_set = furi_thread_flags_set( + furi_thread_get_id(instance->thread), INFRARED_WORKER_OVERRUN); furi_check(flags_set & INFRARED_WORKER_OVERRUN); instance->rx.overrun = true; } @@ -167,7 +167,7 @@ static int32_t infrared_worker_rx_thread(void* thread_context) { TickType_t last_blink_time = 0; while(1) { - events = osThreadFlagsWait(INFRARED_WORKER_ALL_RX_EVENTS, 0, osWaitForever); + events = furi_thread_flags_wait(INFRARED_WORKER_ALL_RX_EVENTS, 0, osWaitForever); furi_check(events & INFRARED_WORKER_ALL_RX_EVENTS); /* at least one caught */ if(events & INFRARED_WORKER_RX_RECEIVED) { @@ -282,7 +282,7 @@ void infrared_worker_rx_stop(InfraredWorker* instance) { furi_hal_infrared_async_rx_set_capture_isr_callback(NULL, NULL); furi_hal_infrared_async_rx_stop(); - osThreadFlagsSet(furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_EXIT); + furi_thread_flags_set(furi_thread_get_id(instance->thread), INFRARED_WORKER_EXIT); furi_thread_join(instance->thread); BaseType_t xReturn = xStreamBufferReset(instance->stream); @@ -342,8 +342,8 @@ void infrared_worker_tx_start(InfraredWorker* instance) { static void infrared_worker_furi_hal_message_sent_isr_callback(void* context) { InfraredWorker* instance = context; - uint32_t flags_set = osThreadFlagsSet( - furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_TX_MESSAGE_SENT); + uint32_t flags_set = furi_thread_flags_set( + furi_thread_get_id(instance->thread), INFRARED_WORKER_TX_MESSAGE_SENT); furi_check(flags_set & INFRARED_WORKER_TX_MESSAGE_SENT); } @@ -369,8 +369,8 @@ static FuriHalInfraredTxGetDataState state = FuriHalInfraredTxGetDataStateDone; } - uint32_t flags_set = osThreadFlagsSet( - furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_TX_FILL_BUFFER); + uint32_t flags_set = furi_thread_flags_set( + furi_thread_get_id(instance->thread), INFRARED_WORKER_TX_FILL_BUFFER); furi_check(flags_set & INFRARED_WORKER_TX_FILL_BUFFER); return state; @@ -498,7 +498,7 @@ static int32_t infrared_worker_tx_thread(void* thread_context) { furi_hal_infrared_async_tx_wait_termination(); instance->state = InfraredWorkerStateStartTx; - events = osThreadFlagsGet(); + events = furi_thread_flags_get(); if(events & INFRARED_WORKER_EXIT) { exit = true; break; @@ -506,7 +506,7 @@ static int32_t infrared_worker_tx_thread(void* thread_context) { break; case InfraredWorkerStateRunTx: - events = osThreadFlagsWait(INFRARED_WORKER_ALL_TX_EVENTS, 0, osWaitForever); + events = furi_thread_flags_wait(INFRARED_WORKER_ALL_TX_EVENTS, 0, osWaitForever); furi_check(events & INFRARED_WORKER_ALL_TX_EVENTS); /* at least one caught */ if(events & INFRARED_WORKER_EXIT) { @@ -558,7 +558,7 @@ void infrared_worker_tx_stop(InfraredWorker* instance) { furi_assert(instance); furi_assert(instance->state != InfraredWorkerStateRunRx); - osThreadFlagsSet(furi_thread_get_thread_id(instance->thread), INFRARED_WORKER_EXIT); + furi_thread_flags_set(furi_thread_get_id(instance->thread), INFRARED_WORKER_EXIT); furi_thread_join(instance->thread); furi_hal_infrared_async_tx_set_data_isr_callback(NULL, NULL); furi_hal_infrared_async_tx_set_signal_sent_isr_callback(NULL, NULL); diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index 83cf90b7..0ec4c861 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -216,8 +216,9 @@ bool subghz_file_encoder_worker_start(SubGhzFileEncoderWorker* instance, const c xStreamBufferReset(instance->stream); string_set(instance->file_path, file_path); instance->worker_running = true; - bool res = furi_thread_start(instance->thread); - return res; + furi_thread_start(instance->thread); + + return true; } void subghz_file_encoder_worker_stop(SubGhzFileEncoderWorker* instance) { From a8acfcabb4104045b6eadd6c215fc3c88b88614e Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 21 Jun 2022 15:45:50 +0300 Subject: [PATCH 03/17] [FL-2568] Infrared C port (#1326) * Add skeleton for infrared C port, rename old app * Add scene stubs * Add more views * Misc changes * Add remote and signal class stubs * Complete infrared signal class * Add remote button class stub * Check if button contains a signal during destruction * Complete infrared signal class more * Implement remote storing * Implement remote loading * Fix error handling * Implement remote transmitting * Rename scene * Canonise event consumption * Implement remote learning (stub) * Implement learn success screen (stub) * Implement AskBack scene * Improve remote saving&loading * Fix remote file name * Add LearnDone scene * Switch from Remote scene correctly * Add SceneButtonSelect * Remove unneeded assert * Add new SceneManager method * Use new SceneManager method in Infrared * Implement renaming of buttons and remotes * Implement deleting of buttons and remotes * Add universal remotes list * Add brute force code * Brute force code improvements * Partially implement Universal Remote GUI * Fix wrong singnal handling * Fully implement Universal Remote * Use standard custom events everywhere * Return infrared CLI * Remove old Infrared app * Change container name * Fix scene order * Put ButtonPanel into stack only when needed * Show loading animation during slow operations * Do not hardcode Loading widget coordinates * Switch Loading widget orientation as needed * Save Start scene state * Save Remote scene state * Save Edit scene state * Save EditButtonSelect scene state * Do not use scene state * Use string_t instead of const char* for brevity * Fix memory leak * Fix saving raw remotes * Add Infrared debug menu * Add debug view * Move Infrared monitor into Infrared application * Remove old Infrared monitor app * Use common signal received callback everywhere --- applications/applications.c | 9 - applications/applications.mk | 9 - applications/gui/modules/loading.c | 4 +- applications/gui/scene_manager.c | 19 + applications/gui/scene_manager.h | 14 + .../infrared/helpers/infrared_parser.cpp | 157 ------- .../infrared/helpers/infrared_parser.h | 48 --- applications/infrared/infrared.c | 397 ++++++++++++++++++ applications/infrared/infrared.h | 3 + applications/infrared/infrared_app.cpp | 250 ----------- applications/infrared/infrared_app.h | 326 -------------- .../infrared/infrared_app_brute_force.cpp | 93 ---- .../infrared/infrared_app_brute_force.h | 67 --- applications/infrared/infrared_app_event.h | 48 --- .../infrared/infrared_app_remote_manager.cpp | 266 ------------ .../infrared/infrared_app_remote_manager.h | 189 --------- applications/infrared/infrared_app_signal.cpp | 116 ----- applications/infrared/infrared_app_signal.h | 134 ------ .../infrared/infrared_app_view_manager.cpp | 163 ------- .../infrared/infrared_app_view_manager.h | 164 -------- applications/infrared/infrared_brute_force.c | 153 +++++++ applications/infrared/infrared_brute_force.h | 22 + .../{cli/infrared_cli.cpp => infrared_cli.c} | 117 +++--- applications/infrared/infrared_custom_event.h | 51 +++ applications/infrared/infrared_i.h | 132 ++++++ applications/infrared/infrared_remote.c | 176 ++++++++ applications/infrared/infrared_remote.h | 28 ++ .../infrared/infrared_remote_button.c | 38 ++ .../infrared/infrared_remote_button.h | 14 + applications/infrared/infrared_runner.cpp | 9 - applications/infrared/infrared_signal.c | 264 ++++++++++++ applications/infrared/infrared_signal.h | 41 ++ .../infrared/scene/infrared_app_scene.h | 305 -------------- .../scene/infrared_app_scene_ask_back.cpp | 73 ---- .../scene/infrared_app_scene_edit.cpp | 79 ---- .../scene/infrared_app_scene_edit_delete.cpp | 100 ----- .../infrared_app_scene_edit_delete_done.cpp | 38 -- .../infrared_app_scene_edit_key_select.cpp | 58 --- .../scene/infrared_app_scene_edit_rename.cpp | 83 ---- .../infrared_app_scene_edit_rename_done.cpp | 30 -- .../scene/infrared_app_scene_learn.cpp | 76 ---- .../scene/infrared_app_scene_learn_done.cpp | 41 -- .../infrared_app_scene_learn_enter_name.cpp | 60 --- .../infrared_app_scene_learn_success.cpp | 142 ------- .../scene/infrared_app_scene_remote.cpp | 131 ------ .../scene/infrared_app_scene_remote_list.cpp | 45 -- .../scene/infrared_app_scene_start.cpp | 68 --- .../scene/infrared_app_scene_universal.cpp | 57 --- .../infrared_app_scene_universal_common.cpp | 107 ----- .../scene/infrared_app_scene_universal_tv.cpp | 123 ------ .../common/infrared_scene_universal_common.c | 92 ++++ .../common/infrared_scene_universal_common.h | 8 + applications/infrared/scenes/infrared_scene.c | 30 ++ applications/infrared/scenes/infrared_scene.h | 29 ++ .../infrared/scenes/infrared_scene_ask_back.c | 59 +++ .../infrared/scenes/infrared_scene_config.h | 17 + .../infrared/scenes/infrared_scene_debug.c | 68 +++ .../infrared/scenes/infrared_scene_edit.c | 101 +++++ .../infrared_scene_edit_button_select.c | 63 +++ .../scenes/infrared_scene_edit_delete.c | 112 +++++ .../scenes/infrared_scene_edit_delete_done.c | 46 ++ .../scenes/infrared_scene_edit_rename.c | 107 +++++ .../scenes/infrared_scene_edit_rename_done.c | 35 ++ .../infrared/scenes/infrared_scene_learn.c | 46 ++ .../scenes/infrared_scene_learn_done.c | 44 ++ .../scenes/infrared_scene_learn_enter_name.c | 66 +++ .../scenes/infrared_scene_learn_success.c | 131 ++++++ .../infrared/scenes/infrared_scene_remote.c | 119 ++++++ .../scenes/infrared_scene_remote_list.c | 44 ++ .../infrared/scenes/infrared_scene_start.c | 83 ++++ .../scenes/infrared_scene_universal.c | 53 +++ .../scenes/infrared_scene_universal_tv.c | 111 +++++ .../infrared/views/infrared_debug_view.c | 59 +++ .../infrared/views/infrared_debug_view.h | 11 + .../{view => views}/infrared_progress_view.c | 0 .../{view => views}/infrared_progress_view.h | 0 .../infrared_monitor/infrared_monitor.c | 140 ------ 77 files changed, 2946 insertions(+), 3865 deletions(-) delete mode 100644 applications/infrared/helpers/infrared_parser.cpp delete mode 100644 applications/infrared/helpers/infrared_parser.h create mode 100644 applications/infrared/infrared.c create mode 100644 applications/infrared/infrared.h delete mode 100644 applications/infrared/infrared_app.cpp delete mode 100644 applications/infrared/infrared_app.h delete mode 100644 applications/infrared/infrared_app_brute_force.cpp delete mode 100644 applications/infrared/infrared_app_brute_force.h delete mode 100644 applications/infrared/infrared_app_event.h delete mode 100644 applications/infrared/infrared_app_remote_manager.cpp delete mode 100644 applications/infrared/infrared_app_remote_manager.h delete mode 100644 applications/infrared/infrared_app_signal.cpp delete mode 100644 applications/infrared/infrared_app_signal.h delete mode 100644 applications/infrared/infrared_app_view_manager.cpp delete mode 100644 applications/infrared/infrared_app_view_manager.h create mode 100644 applications/infrared/infrared_brute_force.c create mode 100644 applications/infrared/infrared_brute_force.h rename applications/infrared/{cli/infrared_cli.cpp => infrared_cli.c} (72%) create mode 100644 applications/infrared/infrared_custom_event.h create mode 100644 applications/infrared/infrared_i.h create mode 100644 applications/infrared/infrared_remote.c create mode 100644 applications/infrared/infrared_remote.h create mode 100644 applications/infrared/infrared_remote_button.c create mode 100644 applications/infrared/infrared_remote_button.h delete mode 100644 applications/infrared/infrared_runner.cpp create mode 100644 applications/infrared/infrared_signal.c create mode 100644 applications/infrared/infrared_signal.h delete mode 100644 applications/infrared/scene/infrared_app_scene.h delete mode 100644 applications/infrared/scene/infrared_app_scene_ask_back.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_delete.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_delete_done.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_key_select.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_rename.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_rename_done.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_learn.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_learn_done.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_learn_success.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_remote.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_remote_list.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_start.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_universal.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_universal_common.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_universal_tv.cpp create mode 100644 applications/infrared/scenes/common/infrared_scene_universal_common.c create mode 100644 applications/infrared/scenes/common/infrared_scene_universal_common.h create mode 100644 applications/infrared/scenes/infrared_scene.c create mode 100644 applications/infrared/scenes/infrared_scene.h create mode 100644 applications/infrared/scenes/infrared_scene_ask_back.c create mode 100644 applications/infrared/scenes/infrared_scene_config.h create mode 100644 applications/infrared/scenes/infrared_scene_debug.c create mode 100644 applications/infrared/scenes/infrared_scene_edit.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_button_select.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_delete.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_delete_done.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_rename.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_rename_done.c create mode 100644 applications/infrared/scenes/infrared_scene_learn.c create mode 100644 applications/infrared/scenes/infrared_scene_learn_done.c create mode 100644 applications/infrared/scenes/infrared_scene_learn_enter_name.c create mode 100644 applications/infrared/scenes/infrared_scene_learn_success.c create mode 100644 applications/infrared/scenes/infrared_scene_remote.c create mode 100644 applications/infrared/scenes/infrared_scene_remote_list.c create mode 100644 applications/infrared/scenes/infrared_scene_start.c create mode 100644 applications/infrared/scenes/infrared_scene_universal.c create mode 100644 applications/infrared/scenes/infrared_scene_universal_tv.c create mode 100644 applications/infrared/views/infrared_debug_view.c create mode 100644 applications/infrared/views/infrared_debug_view.h rename applications/infrared/{view => views}/infrared_progress_view.c (100%) rename applications/infrared/{view => views}/infrared_progress_view.h (100%) delete mode 100644 applications/infrared_monitor/infrared_monitor.c diff --git a/applications/applications.c b/applications/applications.c index dccab589..22f9520e 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -29,7 +29,6 @@ extern int32_t display_test_app(void* p); extern int32_t gpio_app(void* p); extern int32_t ibutton_app(void* p); extern int32_t infrared_app(void* p); -extern int32_t infrared_monitor_app(void* p); extern int32_t keypad_test_app(void* p); extern int32_t lfrfid_app(void* p); extern int32_t lfrfid_debug_app(void* p); @@ -412,14 +411,6 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { .flags = FlipperApplicationFlagDefault}, #endif -#ifdef APP_INFRARED_MONITOR - {.app = infrared_monitor_app, - .name = "Infrared Monitor", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - #ifdef APP_LF_RFID {.app = lfrfid_debug_app, .name = "LF-RFID Debug", diff --git a/applications/applications.mk b/applications/applications.mk index e7a9ebfc..d2272efb 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -51,7 +51,6 @@ APP_SNAKE_GAME = 1 # Debug APP_ACCESSOR = 1 APP_BLINK = 1 -APP_INFRARED_MONITOR = 1 APP_KEYPAD_TEST = 1 APP_SD_TEST = 1 APP_VIBRO_TEST = 1 @@ -70,14 +69,6 @@ endif # that will be shown in menu # Prefix with APP_* - -APP_INFRARED_MONITOR ?= 0 -ifeq ($(APP_INFRARED_MONITOR), 1) -CFLAGS += -DAPP_INFRARED_MONITOR -SRV_GUI = 1 -endif - - APP_UNIT_TESTS ?= 0 ifeq ($(APP_UNIT_TESTS), 1) CFLAGS += -DAPP_UNIT_TESTS diff --git a/applications/gui/modules/loading.c b/applications/gui/modules/loading.c index 60dc8338..57512697 100644 --- a/applications/gui/modules/loading.c +++ b/applications/gui/modules/loading.c @@ -20,10 +20,10 @@ typedef struct { static void loading_draw_callback(Canvas* canvas, void* _model) { LoadingModel* model = (LoadingModel*)_model; - uint8_t x = 7; - uint8_t y = 40; uint8_t width = 49; uint8_t height = 47; + uint8_t x = (canvas_width(canvas) - width) / 2; + uint8_t y = (canvas_height(canvas) - height) / 2; elements_bold_rounded_frame(canvas, x, y, width, height); diff --git a/applications/gui/scene_manager.c b/applications/gui/scene_manager.c index a8c40320..590145e1 100755 --- a/applications/gui/scene_manager.c +++ b/applications/gui/scene_manager.c @@ -165,6 +165,25 @@ bool scene_manager_search_and_switch_to_previous_scene( } } +bool scene_manager_search_and_switch_to_previous_scene_one_of( + SceneManager* scene_manager, + const uint32_t* scene_ids, + size_t scene_ids_size) { + furi_assert(scene_manager); + furi_assert(scene_ids); + bool scene_found = false; + + for(size_t i = 0; i < scene_ids_size; ++i) { + const uint32_t scene_id = scene_ids[i]; + if(scene_manager_has_previous_scene(scene_manager, scene_id)) { + scene_manager_search_and_switch_to_previous_scene(scene_manager, scene_id); + scene_found = true; + break; + } + } + return scene_found; +} + bool scene_manager_has_previous_scene(SceneManager* scene_manager, uint32_t scene_id) { furi_assert(scene_manager); bool scene_found = false; diff --git a/applications/gui/scene_manager.h b/applications/gui/scene_manager.h index 69162853..5b833e5d 100755 --- a/applications/gui/scene_manager.h +++ b/applications/gui/scene_manager.h @@ -5,6 +5,7 @@ #pragma once +#include #include #include @@ -146,6 +147,19 @@ bool scene_manager_search_and_switch_to_previous_scene( SceneManager* scene_manager, uint32_t scene_id); +/** Search and switch to previous Scene, multiple choice + * + * @param scene_manager SceneManager instance + * @param scene_ids Array of scene IDs + * @param scene_ids_size Array of scene IDs size + * + * @return true if one of previous scenes was found, false otherwise + */ +bool scene_manager_search_and_switch_to_previous_scene_one_of( + SceneManager* scene_manager, + const uint32_t* scene_ids, + size_t scene_ids_size); + /** Clear Scene stack and switch to another Scene * * @param scene_manager SceneManager instance diff --git a/applications/infrared/helpers/infrared_parser.cpp b/applications/infrared/helpers/infrared_parser.cpp deleted file mode 100644 index d85a7269..00000000 --- a/applications/infrared/helpers/infrared_parser.cpp +++ /dev/null @@ -1,157 +0,0 @@ - -#include "../infrared_app_signal.h" -#include "infrared.h" -#include "infrared/helpers/infrared_parser.h" -#include "infrared_worker.h" -#include "m-string.h" -#include -#include -#include -#include - -#define TAG "InfraredParser" - -bool infrared_parser_save_signal( - FlipperFormat* ff, - const InfraredAppSignal& signal, - const std::string& name) { - furi_assert(ff); - furi_assert(!name.empty()); - - bool result = false; - - do { - if(!flipper_format_write_comment_cstr(ff, "")) break; - if(!flipper_format_write_string_cstr(ff, "name", name.c_str())) break; - if(signal.is_raw()) { - furi_assert(signal.get_raw_signal().timings_cnt <= MAX_TIMINGS_AMOUNT); - auto raw_signal = signal.get_raw_signal(); - if(!flipper_format_write_string_cstr(ff, "type", "raw")) break; - if(!flipper_format_write_uint32(ff, "frequency", &raw_signal.frequency, 1)) break; - if(!flipper_format_write_float(ff, "duty_cycle", &raw_signal.duty_cycle, 1)) break; - if(!flipper_format_write_uint32(ff, "data", raw_signal.timings, raw_signal.timings_cnt)) - break; - } else { - auto parsed_signal = signal.get_message(); - const char* protocol_name = infrared_get_protocol_name(parsed_signal.protocol); - if(!flipper_format_write_string_cstr(ff, "type", "parsed")) break; - if(!flipper_format_write_string_cstr(ff, "protocol", protocol_name)) break; - if(!flipper_format_write_hex(ff, "address", (uint8_t*)&parsed_signal.address, 4)) - break; - if(!flipper_format_write_hex(ff, "command", (uint8_t*)&parsed_signal.command, 4)) - break; - } - result = true; - } while(0); - - return result; -} - -bool infrared_parser_read_signal(FlipperFormat* ff, InfraredAppSignal& signal, std::string& name) { - furi_assert(ff); - - bool result = false; - string_t read_string; - string_init(read_string); - - do { - if(!flipper_format_read_string(ff, "name", read_string)) break; - name = string_get_cstr(read_string); - if(!flipper_format_read_string(ff, "type", read_string)) break; - if(!string_cmp_str(read_string, "raw")) { - uint32_t* timings = nullptr; - uint32_t timings_cnt = 0; - uint32_t frequency = 0; - float duty_cycle = 0; - - if(!flipper_format_read_uint32(ff, "frequency", &frequency, 1)) break; - if(!flipper_format_read_float(ff, "duty_cycle", &duty_cycle, 1)) break; - if(!flipper_format_get_value_count(ff, "data", &timings_cnt)) break; - if(timings_cnt > MAX_TIMINGS_AMOUNT) break; - timings = (uint32_t*)malloc(sizeof(uint32_t) * timings_cnt); - if(flipper_format_read_uint32(ff, "data", timings, timings_cnt)) { - signal.set_raw_signal(timings, timings_cnt, frequency, duty_cycle); - result = true; - } - free(timings); - } else if(!string_cmp_str(read_string, "parsed")) { - InfraredMessage parsed_signal; - if(!flipper_format_read_string(ff, "protocol", read_string)) break; - parsed_signal.protocol = infrared_get_protocol_by_name(string_get_cstr(read_string)); - if(!flipper_format_read_hex(ff, "address", (uint8_t*)&parsed_signal.address, 4)) break; - if(!flipper_format_read_hex(ff, "command", (uint8_t*)&parsed_signal.command, 4)) break; - if(!infrared_parser_is_parsed_signal_valid(&parsed_signal)) break; - signal.set_message(&parsed_signal); - result = true; - } else { - FURI_LOG_E(TAG, "Unknown type of signal (allowed - raw/parsed) "); - } - } while(0); - - string_clear(read_string); - return result; -} - -bool infrared_parser_is_parsed_signal_valid(const InfraredMessage* signal) { - furi_assert(signal); - bool result = true; - - if(!infrared_is_protocol_valid(signal->protocol)) { - FURI_LOG_E(TAG, "Unknown protocol"); - result = false; - } - - if(result) { - uint32_t address_length = infrared_get_protocol_address_length(signal->protocol); - uint32_t address_mask = (1LU << address_length) - 1; - if(signal->address != (signal->address & address_mask)) { - FURI_LOG_E( - TAG, - "Address is out of range (mask 0x%08lX): 0x%lX\r\n", - address_mask, - signal->address); - result = false; - } - } - - if(result) { - uint32_t command_length = infrared_get_protocol_command_length(signal->protocol); - uint32_t command_mask = (1LU << command_length) - 1; - if(signal->command != (signal->command & command_mask)) { - FURI_LOG_E( - TAG, - "Command is out of range (mask 0x%08lX): 0x%lX\r\n", - command_mask, - signal->command); - result = false; - } - } - - return result; -} - -bool infrared_parser_is_raw_signal_valid( - uint32_t frequency, - float duty_cycle, - uint32_t timings_cnt) { - bool result = true; - - if((frequency > INFRARED_MAX_FREQUENCY) || (frequency < INFRARED_MIN_FREQUENCY)) { - FURI_LOG_E( - TAG, - "Frequency is out of range (%lX - %lX): %lX", - INFRARED_MIN_FREQUENCY, - INFRARED_MAX_FREQUENCY, - frequency); - result = false; - } else if((duty_cycle <= 0) || (duty_cycle > 1)) { - FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", (double)duty_cycle); - result = false; - } else if((timings_cnt <= 0) || (timings_cnt > MAX_TIMINGS_AMOUNT)) { - FURI_LOG_E( - TAG, "Timings amount is out of range (0 - %lX): %lX", MAX_TIMINGS_AMOUNT, timings_cnt); - result = false; - } - - return result; -} diff --git a/applications/infrared/helpers/infrared_parser.h b/applications/infrared/helpers/infrared_parser.h deleted file mode 100644 index 2e790c38..00000000 --- a/applications/infrared/helpers/infrared_parser.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file infrared_parser.h - * Infrared: Helper file for conversion Flipper File Format - * to Infrared signal class, and backwards - */ -#pragma once - -#include "../infrared_app_signal.h" -#include -#include - -/** Save Infrared signal into file - * - * @param ff - Flipper File Format instance - * @param signal - Infrared signal to save - * @param name - name for saved signal. Every - * signal on disk has name. - */ -bool infrared_parser_save_signal( - FlipperFormat* ff, - const InfraredAppSignal& signal, - const std::string& name); - -/** Read Infrared signal from file - * - * @param ff - Flipper File Format instance - * @param signal - Infrared signal to read to - * @param name - name for saved signal. Every - * signal in file has name. - */ -bool infrared_parser_read_signal(FlipperFormat* ff, InfraredAppSignal& signal, std::string& name); - -/** Validate parsed signal - * - * @signal - signal to validate - * @retval true if valid, false otherwise - */ -bool infrared_parser_is_parsed_signal_valid(const InfraredMessage* signal); - -/** Validate raw signal - * - * @signal - signal to validate - * @retval true if valid, false otherwise - */ -bool infrared_parser_is_raw_signal_valid( - uint32_t frequency, - float duty_cycle, - uint32_t timings_cnt); diff --git a/applications/infrared/infrared.c b/applications/infrared/infrared.c new file mode 100644 index 00000000..ee6b931e --- /dev/null +++ b/applications/infrared/infrared.c @@ -0,0 +1,397 @@ +#include "infrared_i.h" + +#include +#include + +static const NotificationSequence* infrared_notification_sequences[] = { + &sequence_success, + &sequence_set_only_green_255, + &sequence_reset_green, + &sequence_blink_cyan_10, + &sequence_blink_magenta_10}; + +static void infrared_make_app_folder(Infrared* infrared) { + if(!storage_simply_mkdir(infrared->storage, INFRARED_APP_FOLDER)) { + dialog_message_show_storage_error(infrared->dialogs, "Cannot create\napp folder"); + } +} + +static bool infrared_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + Infrared* infrared = context; + return scene_manager_handle_custom_event(infrared->scene_manager, event); +} + +static bool infrared_back_event_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + return scene_manager_handle_back_event(infrared->scene_manager); +} + +static void infrared_tick_event_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + scene_manager_handle_tick_event(infrared->scene_manager); +} + +static void infrared_find_vacant_remote_name(string_t name, const char* path) { + Storage* storage = furi_record_open("storage"); + + string_t base_path; + string_init_set_str(base_path, path); + + if(string_end_with_str_p(base_path, INFRARED_APP_EXTENSION)) { + size_t filename_start = string_search_rchar(base_path, '/'); + string_left(base_path, filename_start); + } + + string_printf(base_path, "%s/%s%s", path, string_get_cstr(name), INFRARED_APP_EXTENSION); + + FS_Error status = storage_common_stat(storage, string_get_cstr(base_path), NULL); + + if(status == FSE_OK) { + /* If the suggested name is occupied, try another one (name2, name3, etc) */ + size_t dot = string_search_rchar(base_path, '.'); + string_left(base_path, dot); + + string_t path_temp; + string_init(path_temp); + + uint32_t i = 1; + do { + string_printf( + path_temp, "%s%u%s", string_get_cstr(base_path), ++i, INFRARED_APP_EXTENSION); + status = storage_common_stat(storage, string_get_cstr(path_temp), NULL); + } while(status == FSE_OK); + + string_clear(path_temp); + + if(status == FSE_NOT_EXIST) { + string_cat_printf(name, "%u", i); + } + } + + string_clear(base_path); + furi_record_close("storage"); +} + +static Infrared* infrared_alloc() { + Infrared* infrared = malloc(sizeof(Infrared)); + + string_init(infrared->file_path); + + InfraredAppState* app_state = &infrared->app_state; + app_state->is_learning_new_remote = false; + app_state->is_debug_enabled = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); + app_state->edit_target = InfraredEditTargetNone; + app_state->edit_mode = InfraredEditModeNone; + app_state->current_button_index = InfraredButtonIndexNone; + + infrared->scene_manager = scene_manager_alloc(&infrared_scene_handlers, infrared); + infrared->view_dispatcher = view_dispatcher_alloc(); + + infrared->gui = furi_record_open("gui"); + + ViewDispatcher* view_dispatcher = infrared->view_dispatcher; + view_dispatcher_attach_to_gui(view_dispatcher, infrared->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_enable_queue(view_dispatcher); + view_dispatcher_set_event_callback_context(view_dispatcher, infrared); + view_dispatcher_set_custom_event_callback(view_dispatcher, infrared_custom_event_callback); + view_dispatcher_set_navigation_event_callback(view_dispatcher, infrared_back_event_callback); + view_dispatcher_set_tick_event_callback(view_dispatcher, infrared_tick_event_callback, 100); + + infrared->storage = furi_record_open("storage"); + infrared->dialogs = furi_record_open("dialogs"); + infrared->notifications = furi_record_open("notification"); + + infrared->worker = infrared_worker_alloc(); + infrared->remote = infrared_remote_alloc(); + infrared->received_signal = infrared_signal_alloc(); + infrared->brute_force = infrared_brute_force_alloc(); + + infrared->submenu = submenu_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewSubmenu, submenu_get_view(infrared->submenu)); + + infrared->text_input = text_input_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewTextInput, text_input_get_view(infrared->text_input)); + + infrared->dialog_ex = dialog_ex_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewDialogEx, dialog_ex_get_view(infrared->dialog_ex)); + + infrared->button_menu = button_menu_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewButtonMenu, button_menu_get_view(infrared->button_menu)); + + infrared->popup = popup_alloc(); + view_dispatcher_add_view(view_dispatcher, InfraredViewPopup, popup_get_view(infrared->popup)); + + infrared->view_stack = view_stack_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewStack, view_stack_get_view(infrared->view_stack)); + + if(app_state->is_debug_enabled) { + infrared->debug_view = infrared_debug_view_alloc(); + view_dispatcher_add_view( + view_dispatcher, + InfraredViewDebugView, + infrared_debug_view_get_view(infrared->debug_view)); + } + + infrared->button_panel = button_panel_alloc(); + infrared->loading = loading_alloc(); + infrared->progress = infrared_progress_view_alloc(); + + return infrared; +} + +static void infrared_free(Infrared* infrared) { + furi_assert(infrared); + ViewDispatcher* view_dispatcher = infrared->view_dispatcher; + InfraredAppState* app_state = &infrared->app_state; + + view_dispatcher_remove_view(view_dispatcher, InfraredViewSubmenu); + submenu_free(infrared->submenu); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewTextInput); + text_input_free(infrared->text_input); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewDialogEx); + dialog_ex_free(infrared->dialog_ex); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewButtonMenu); + button_menu_free(infrared->button_menu); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewPopup); + popup_free(infrared->popup); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewStack); + view_stack_free(infrared->view_stack); + + if(app_state->is_debug_enabled) { + view_dispatcher_remove_view(view_dispatcher, InfraredViewDebugView); + infrared_debug_view_free(infrared->debug_view); + } + + button_panel_free(infrared->button_panel); + loading_free(infrared->loading); + infrared_progress_view_free(infrared->progress); + + view_dispatcher_free(view_dispatcher); + scene_manager_free(infrared->scene_manager); + + infrared_brute_force_free(infrared->brute_force); + infrared_signal_free(infrared->received_signal); + infrared_remote_free(infrared->remote); + infrared_worker_free(infrared->worker); + + furi_record_close("gui"); + infrared->gui = NULL; + + furi_record_close("notification"); + infrared->notifications = NULL; + + furi_record_close("dialogs"); + infrared->dialogs = NULL; + + furi_record_close("gui"); + infrared->gui = NULL; + + string_clear(infrared->file_path); + + free(infrared); +} + +bool infrared_add_remote_with_button( + Infrared* infrared, + const char* button_name, + InfraredSignal* signal) { + InfraredRemote* remote = infrared->remote; + + string_t new_name, new_path; + string_init_set_str(new_name, INFRARED_DEFAULT_REMOTE_NAME); + string_init_set_str(new_path, INFRARED_APP_FOLDER); + + infrared_find_vacant_remote_name(new_name, string_get_cstr(new_path)); + string_cat_printf(new_path, "/%s%s", string_get_cstr(new_name), INFRARED_APP_EXTENSION); + + infrared_remote_reset(remote); + infrared_remote_set_name(remote, string_get_cstr(new_name)); + infrared_remote_set_path(remote, string_get_cstr(new_path)); + + string_clear(new_name); + string_clear(new_path); + return infrared_remote_add_button(remote, button_name, signal); +} + +bool infrared_rename_current_remote(Infrared* infrared, const char* name) { + InfraredRemote* remote = infrared->remote; + const char* remote_path = infrared_remote_get_path(remote); + + if(!strcmp(infrared_remote_get_name(remote), name)) { + return true; + } + + string_t new_name; + string_init_set_str(new_name, name); + + infrared_find_vacant_remote_name(new_name, remote_path); + + string_t new_path; + string_init_set(new_path, infrared_remote_get_path(remote)); + if(string_end_with_str_p(new_path, INFRARED_APP_EXTENSION)) { + size_t filename_start = string_search_rchar(new_path, '/'); + string_left(new_path, filename_start); + } + string_cat_printf(new_path, "/%s%s", string_get_cstr(new_name), INFRARED_APP_EXTENSION); + + Storage* storage = furi_record_open("storage"); + + FS_Error status = storage_common_rename( + storage, infrared_remote_get_path(remote), string_get_cstr(new_path)); + infrared_remote_set_name(remote, string_get_cstr(new_name)); + + string_clear(new_name); + string_clear(new_path); + + furi_record_close("storage"); + return (status == FSE_OK || status == FSE_EXIST); +} + +void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { + if(infrared_signal_is_raw(signal)) { + InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size); + } else { + InfraredMessage* message = infrared_signal_get_message(signal); + infrared_worker_set_decoded_signal(infrared->worker, message); + } + + DOLPHIN_DEED(DolphinDeedIrSend); + infrared_worker_tx_start(infrared->worker); +} + +void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { + furi_assert(button_index < infrared_remote_get_button_count(infrared->remote)); + + InfraredRemoteButton* button = infrared_remote_get_button(infrared->remote, button_index); + InfraredSignal* signal = infrared_remote_button_get_signal(button); + + infrared_tx_start_signal(infrared, signal); +} + +void infrared_tx_start_received(Infrared* infrared) { + infrared_tx_start_signal(infrared, infrared->received_signal); +} + +void infrared_tx_stop(Infrared* infrared) { + infrared_worker_tx_stop(infrared->worker); +} + +void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) { + va_list args; + va_start(args, text); + + vsnprintf(infrared->text_store[bank], INFRARED_TEXT_STORE_SIZE, text, args); + + va_end(args); +} + +void infrared_text_store_clear(Infrared* infrared, uint32_t bank) { + memset(infrared->text_store[bank], 0, INFRARED_TEXT_STORE_SIZE); +} + +void infrared_play_notification_message(Infrared* infrared, uint32_t message) { + furi_assert(message < sizeof(infrared_notification_sequences) / sizeof(NotificationSequence*)); + notification_message(infrared->notifications, infrared_notification_sequences[message]); +} + +void infrared_show_loading_popup(Infrared* infrared, bool show) { + TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + ViewStack* view_stack = infrared->view_stack; + Loading* loading = infrared->loading; + + if(show) { + // Raise timer priority so that animations can play + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + view_stack_add_view(view_stack, loading_get_view(loading)); + } else { + view_stack_remove_view(view_stack, loading_get_view(loading)); + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + +void infrared_signal_sent_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend); +} + +void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { + furi_assert(context); + Infrared* infrared = context; + + if(infrared_worker_signal_is_decoded(received_signal)) { + infrared_signal_set_message( + infrared->received_signal, infrared_worker_get_decoded_signal(received_signal)); + } else { + const uint32_t* timings; + size_t timings_size; + infrared_worker_get_raw_signal(received_signal, &timings, &timings_size); + infrared_signal_set_raw_signal( + infrared->received_signal, + timings, + timings_size, + INFRARED_COMMON_CARRIER_FREQUENCY, + INFRARED_COMMON_DUTY_CYCLE); + } + + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeSignalReceived); +} + +void infrared_text_input_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeTextEditDone); +} + +void infrared_popup_timeout_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypePopupTimeout); +} + +int32_t infrared_app(void* p) { + Infrared* infrared = infrared_alloc(); + + infrared_make_app_folder(infrared); + + bool is_remote_loaded = false; + + if(p) { + string_set_str(infrared->file_path, (const char*)p); + is_remote_loaded = infrared_remote_load(infrared->remote, infrared->file_path); + if(!is_remote_loaded) { + dialog_message_show_storage_error( + infrared->dialogs, "Failed to load\nselected remote"); + return -1; + } + } + + if(is_remote_loaded) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); + } else { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneStart); + } + + view_dispatcher_run(infrared->view_dispatcher); + + infrared_free(infrared); + return 0; +} diff --git a/applications/infrared/infrared.h b/applications/infrared/infrared.h new file mode 100644 index 00000000..e5eeb117 --- /dev/null +++ b/applications/infrared/infrared.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct Infrared Infrared; diff --git a/applications/infrared/infrared_app.cpp b/applications/infrared/infrared_app.cpp deleted file mode 100644 index 1ac859d1..00000000 --- a/applications/infrared/infrared_app.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "infrared_app.h" -#include "m-string.h" -#include -#include -#include -#include -#include -#include - -int32_t InfraredApp::run(void* args) { - InfraredAppEvent event; - bool consumed; - bool exit = false; - - if(args) { - string_t path; - string_init_set_str(path, (char*)args); - if(string_end_with_str_p(path, InfraredApp::infrared_extension)) { - bool result = remote_manager.load(path); - if(result) { - current_scene = InfraredApp::Scene::Remote; - } else { - printf("Failed to load remote \'%s\'\r\n", string_get_cstr(path)); - return -1; - } - } - string_clear(path); - } - - scenes[current_scene]->on_enter(this); - - while(!exit) { - view_manager.receive_event(&event); - - if(event.type == InfraredAppEvent::Type::Exit) break; - - consumed = scenes[current_scene]->on_event(this, &event); - - if(!consumed) { - if(event.type == InfraredAppEvent::Type::Back) { - exit = switch_to_previous_scene(); - } - } - }; - - scenes[current_scene]->on_exit(this); - - return 0; -}; - -InfraredApp::InfraredApp() { - furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size()); - string_init_set_str(file_path, InfraredApp::infrared_directory); - notification = static_cast(furi_record_open("notification")); - dialogs = static_cast(furi_record_open("dialogs")); - infrared_worker = infrared_worker_alloc(); -} - -InfraredApp::~InfraredApp() { - infrared_worker_free(infrared_worker); - furi_record_close("notification"); - furi_record_close("dialogs"); - string_clear(file_path); - for(auto& [key, scene] : scenes) delete scene; -} - -InfraredAppViewManager* InfraredApp::get_view_manager() { - return &view_manager; -} - -void InfraredApp::set_learn_new_remote(bool value) { - learn_new_remote = value; -} - -bool InfraredApp::get_learn_new_remote() { - return learn_new_remote; -} - -void InfraredApp::switch_to_next_scene(Scene next_scene) { - previous_scenes_list.push_front(current_scene); - switch_to_next_scene_without_saving(next_scene); -} - -void InfraredApp::switch_to_next_scene_without_saving(Scene next_scene) { - if(next_scene != Scene::Exit) { - scenes[current_scene]->on_exit(this); - current_scene = next_scene; - scenes[current_scene]->on_enter(this); - view_manager.clear_events(); - } -} - -void InfraredApp::search_and_switch_to_previous_scene( - const std::initializer_list& scenes_list) { - Scene previous_scene = Scene::Start; - bool scene_found = false; - - while(!scene_found) { - previous_scene = get_previous_scene(); - - if(previous_scene == Scene::Exit) break; - - for(Scene element : scenes_list) { - if(previous_scene == element) { - scene_found = true; - break; - } - } - } - - if(previous_scene == Scene::Exit) { - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::Exit; - view_manager.send_event(&event); - } else { - scenes[current_scene]->on_exit(this); - current_scene = previous_scene; - scenes[current_scene]->on_enter(this); - view_manager.clear_events(); - } -} - -bool InfraredApp::switch_to_previous_scene(uint8_t count) { - Scene previous_scene = Scene::Start; - - for(uint8_t i = 0; i < count; i++) previous_scene = get_previous_scene(); - - if(previous_scene == Scene::Exit) return true; - - scenes[current_scene]->on_exit(this); - current_scene = previous_scene; - scenes[current_scene]->on_enter(this); - view_manager.clear_events(); - return false; -} - -InfraredApp::Scene InfraredApp::get_previous_scene() { - Scene scene = Scene::Exit; - - if(!previous_scenes_list.empty()) { - scene = previous_scenes_list.front(); - previous_scenes_list.pop_front(); - } - - return scene; -} - -InfraredAppRemoteManager* InfraredApp::get_remote_manager() { - return &remote_manager; -} - -void InfraredApp::set_text_store(uint8_t index, const char* text...) { - furi_check(index < text_store_max); - - va_list args; - va_start(args, text); - - vsnprintf(text_store[index], text_store_size, text, args); - - va_end(args); -} - -char* InfraredApp::get_text_store(uint8_t index) { - furi_check(index < text_store_max); - - return text_store[index]; -} - -uint8_t InfraredApp::get_text_store_size() { - return text_store_size; -} - -void InfraredApp::text_input_callback(void* context) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::TextEditDone; - app->get_view_manager()->send_event(&event); -} - -void InfraredApp::popup_callback(void* context) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::PopupTimer; - app->get_view_manager()->send_event(&event); -} - -void InfraredApp::set_edit_element(InfraredApp::EditElement value) { - element = value; -} - -InfraredApp::EditElement InfraredApp::get_edit_element(void) { - return element; -} - -void InfraredApp::set_edit_action(InfraredApp::EditAction value) { - action = value; -} - -InfraredApp::EditAction InfraredApp::get_edit_action(void) { - return action; -} - -void InfraredApp::set_current_button(int value) { - current_button = value; -} - -int InfraredApp::get_current_button() { - return current_button; -} - -void InfraredApp::notify_success() { - notification_message(notification, &sequence_success); -} - -void InfraredApp::notify_blink_read() { - notification_message(notification, &sequence_blink_cyan_10); -} - -void InfraredApp::notify_blink_send() { - notification_message(notification, &sequence_blink_magenta_10); -} - -DialogsApp* InfraredApp::get_dialogs() { - return dialogs; -} - -void InfraredApp::notify_green_on() { - notification_message(notification, &sequence_set_only_green_255); -} - -void InfraredApp::notify_green_off() { - notification_message(notification, &sequence_reset_green); -} - -InfraredWorker* InfraredApp::get_infrared_worker() { - return infrared_worker; -} - -const InfraredAppSignal& InfraredApp::get_received_signal() const { - return received_signal; -} - -void InfraredApp::set_received_signal(const InfraredAppSignal& signal) { - received_signal = signal; -} - -void InfraredApp::signal_sent_callback(void* context) { - InfraredApp* app = static_cast(context); - app->notify_blink_send(); -} diff --git a/applications/infrared/infrared_app.h b/applications/infrared/infrared_app.h deleted file mode 100644 index 1cb8b661..00000000 --- a/applications/infrared/infrared_app.h +++ /dev/null @@ -1,326 +0,0 @@ -/** - * @file infrared_app.h - * Infrared: Main infrared application class - */ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scene/infrared_app_scene.h" -#include "scene/infrared_app_scene.h" -#include "infrared_app_view_manager.h" -#include "infrared_app_remote_manager.h" -#include "infrared_app_view_manager.h" - -/** Main Infrared application class */ -class InfraredApp { -public: - /** Enum to save scene state: edit element */ - enum class EditElement : uint8_t { - Button, - Remote, - }; - /** Enum to save scene state: edit action */ - enum class EditAction : uint8_t { - Rename, - Delete, - }; - /** List of scenes for Infrared application */ - enum class Scene : uint8_t { - Exit, - Start, - Universal, - UniversalTV, - UniversalAudio, - UniversalAirConditioner, - Learn, - LearnSuccess, - LearnEnterName, - LearnDone, - AskBack, - Remote, - RemoteList, - Edit, - EditKeySelect, - EditRename, - EditDelete, - EditRenameDone, - EditDeleteDone, - }; - - /** Start application - * - * @param args - application arguments. - * Allowed argument is path to remote file. - * @retval 0 on success, error code otherwise - */ - int32_t run(void* args); - - /** Switch to next scene. Put current scene number on stack. - * Doesn't save scene state. - * - * @param index - next scene index - */ - void switch_to_next_scene(Scene index); - - /** Switch to next scene, but don't put current scene on - * stack. Thus calling switch_to_previous_scene() doesn't return - * to current scene. - * - * @param index - next scene index - */ - void switch_to_next_scene_without_saving(Scene index); - - /** Switch to previous scene. Pop scenes from stack and switch to last one. - * - * @param count - how many scenes should be popped - * @retval false on failed, true on success - */ - bool switch_to_previous_scene(uint8_t count = 1); - - /** Get previous scene in scene stack - * - * @retval previous scene - */ - Scene get_previous_scene(); - - /** Get view manager instance - * - * @retval view manager instance - */ - InfraredAppViewManager* get_view_manager(); - - /** Set one of text stores - * - * @param index - index of text store - * @param text - text to set - */ - void set_text_store(uint8_t index, const char* text...); - - /** Get value in text store - * - * @param index - index of text store - * @retval value in text_store - */ - char* get_text_store(uint8_t index); - - /** Get text store size - * - * @retval size of text store - */ - uint8_t get_text_store_size(); - - /** Get remote manager instance - * - * @retval remote manager instance - */ - InfraredAppRemoteManager* get_remote_manager(); - - /** Get infrared worker instance - * - * @retval infrared worker instance - */ - InfraredWorker* get_infrared_worker(); - - /** Get signal, previously got on Learn scene - * - * @retval received signal - */ - const InfraredAppSignal& get_received_signal() const; - - /** Set received signal - * - * @param signal - signal - */ - void set_received_signal(const InfraredAppSignal& signal); - - /** Switch to previous scene in one of provided in list. - * Pop scene stack, and find first scene from list. - * - * @param scenes_list - list of scenes - */ - void search_and_switch_to_previous_scene(const std::initializer_list& scenes_list); - - /** Set edit element value. It is used on edit scene to determine - * what should be deleted - remote or button. - * - * @param value - value to set - */ - void set_edit_element(EditElement value); - - /** Get edit element - * - * @retval edit element value - */ - EditElement get_edit_element(void); - - /** Set edit action value. It is used on edit scene to determine - * what action to perform - deletion or renaming. - * - * @param value - value to set - */ - void set_edit_action(EditAction value); - - /** Get edit action - * - * @retval edit action value - */ - EditAction get_edit_action(void); - - /** Get state of learning new signal. - * Adding new remote with 1 button from start scene and - * learning 1 additional button to remote have very similar - * flow, so they are joined. Difference in flow is handled - * by this boolean flag. - * - * @retval false if flow is in learning new remote, true if - * adding signal to created remote - * - */ - bool get_learn_new_remote(); - - /** Set state of learning new signal. - * Adding new remote with 1 button from start scene and - * learning 1 additional button to remote have very similar - * flow, so they are joined. Difference in flow is handled - * by this boolean flag. - * - * @param value - false if flow is in learning new remote, true if - * adding signal to created remote - */ - void set_learn_new_remote(bool value); - - /** Button is not assigned value - */ - enum : int { - ButtonNA = -1, - }; - - /** Get current button index - * - * @retval current button index - */ - int get_current_button(); - - /** Set current button index - * - * @param current button index - */ - void set_current_button(int value); - - /** Play success notification */ - void notify_success(); - /** Play red blink notification */ - void notify_blink_read(); - /** Light green */ - void notify_green_on(); - /** Disable green light */ - void notify_green_off(); - /** Blink on send */ - void notify_blink_send(); - - /** Get Dialogs instance */ - DialogsApp* get_dialogs(); - - /** Text input callback - * - * @param context - context to pass to callback - */ - static void text_input_callback(void* context); - - /** Popup callback - * - * @param context - context to pass to callback - */ - static void popup_callback(void* context); - - /** Signal sent callback - * - * @param context - context to pass to callback - */ - static void signal_sent_callback(void* context); - - /** Main class constructor, initializes all critical objects */ - InfraredApp(); - /** Main class destructor, deinitializes all critical objects */ - ~InfraredApp(); - - string_t file_path; - - /** Path to Infrared directory */ - static constexpr const char* infrared_directory = "/any/infrared"; - /** Infrared files extension (remote files and universal databases) */ - static constexpr const char* infrared_extension = ".ir"; - /** Max Raw timings in signal */ - static constexpr const uint32_t max_raw_timings_in_signal = 512; - /** Max line length in Infrared file */ - static constexpr const uint32_t max_line_length = - (9 + 1) * InfraredApp::max_raw_timings_in_signal + 100; - -private: - /** Text store size */ - static constexpr const uint8_t text_store_size = 128; - /** Amount of text stores */ - static constexpr const uint8_t text_store_max = 2; - /** Store text here, for some views, because they doesn't - * hold ownership of text */ - char text_store[text_store_max][text_store_size + 1]; - /** - * Flag to control adding new signal flow. - * Adding new remote with 1 button from start scene and - * learning 1 additional button to remote have very similar - * flow, so they are joined. Difference in flow is handled - * by this boolean flag. - */ - bool learn_new_remote; - /** Value to control edit scene */ - EditElement element; - /** Value to control edit scene */ - EditAction action; - /** Selected button index */ - uint32_t current_button; - - /** Notification instance */ - NotificationApp* notification; - /** Dialogs instance */ - DialogsApp* dialogs; - /** View manager instance */ - InfraredAppViewManager view_manager; - /** Remote manager instance */ - InfraredAppRemoteManager remote_manager; - /** Infrared worker instance */ - InfraredWorker* infrared_worker; - /** Signal received on Learn scene */ - InfraredAppSignal received_signal; - - /** Stack of previous scenes */ - std::forward_list previous_scenes_list; - /** Now acting scene */ - Scene current_scene = Scene::Start; - - /** Map of index/scene objects */ - std::map scenes = { - {Scene::Start, new InfraredAppSceneStart()}, - {Scene::Universal, new InfraredAppSceneUniversal()}, - {Scene::UniversalTV, new InfraredAppSceneUniversalTV()}, - {Scene::Learn, new InfraredAppSceneLearn()}, - {Scene::LearnSuccess, new InfraredAppSceneLearnSuccess()}, - {Scene::LearnEnterName, new InfraredAppSceneLearnEnterName()}, - {Scene::LearnDone, new InfraredAppSceneLearnDone()}, - {Scene::AskBack, new InfraredAppSceneAskBack()}, - {Scene::Remote, new InfraredAppSceneRemote()}, - {Scene::RemoteList, new InfraredAppSceneRemoteList()}, - {Scene::Edit, new InfraredAppSceneEdit()}, - {Scene::EditKeySelect, new InfraredAppSceneEditKeySelect()}, - {Scene::EditRename, new InfraredAppSceneEditRename()}, - {Scene::EditDelete, new InfraredAppSceneEditDelete()}, - {Scene::EditRenameDone, new InfraredAppSceneEditRenameDone()}, - {Scene::EditDeleteDone, new InfraredAppSceneEditDeleteDone()}, - }; -}; diff --git a/applications/infrared/infrared_app_brute_force.cpp b/applications/infrared/infrared_app_brute_force.cpp deleted file mode 100644 index 2910a399..00000000 --- a/applications/infrared/infrared_app_brute_force.cpp +++ /dev/null @@ -1,93 +0,0 @@ - -#include "helpers/infrared_parser.h" -#include "infrared_app_brute_force.h" -#include "infrared_app_signal.h" -#include -#include -#include - -void InfraredAppBruteForce::add_record(int index, const char* name) { - records[name].index = index; - records[name].amount = 0; -} - -bool InfraredAppBruteForce::calculate_messages() { - bool result = false; - - Storage* storage = static_cast(furi_record_open("storage")); - FlipperFormat* ff = flipper_format_file_alloc(storage); - result = flipper_format_file_open_existing(ff, universal_db_filename); - - if(result) { - InfraredAppSignal signal; - - string_t signal_name; - string_init(signal_name); - while(flipper_format_read_string(ff, "name", signal_name)) { - auto element = records.find(string_get_cstr(signal_name)); - if(element != records.cend()) { - ++element->second.amount; - } - } - string_clear(signal_name); - } - - flipper_format_free(ff); - furi_record_close("storage"); - return result; -} - -void InfraredAppBruteForce::stop_bruteforce() { - furi_assert((current_record.size())); - - if(current_record.size()) { - furi_assert(ff); - current_record.clear(); - flipper_format_free(ff); - furi_record_close("storage"); - } -} - -bool InfraredAppBruteForce::send_next_bruteforce(void) { - furi_assert(current_record.size()); - furi_assert(ff); - - InfraredAppSignal signal; - std::string signal_name; - bool result = false; - do { - result = infrared_parser_read_signal(ff, signal, signal_name); - } while(result && current_record.compare(signal_name)); - - if(result) { - signal.transmit(); - } - return result; -} - -bool InfraredAppBruteForce::start_bruteforce(int index, int& record_amount) { - bool result = false; - record_amount = 0; - - for(const auto& it : records) { - if(it.second.index == index) { - record_amount = it.second.amount; - if(record_amount) { - current_record = it.first; - } - break; - } - } - - if(record_amount) { - Storage* storage = static_cast(furi_record_open("storage")); - ff = flipper_format_file_alloc(storage); - result = flipper_format_file_open_existing(ff, universal_db_filename); - if(!result) { - flipper_format_free(ff); - furi_record_close("storage"); - } - } - - return result; -} diff --git a/applications/infrared/infrared_app_brute_force.h b/applications/infrared/infrared_app_brute_force.h deleted file mode 100644 index 2dd3ade9..00000000 --- a/applications/infrared/infrared_app_brute_force.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file infrared_app_brute_force.h - * Infrared: Brute Force class description - */ -#pragma once - -#include -#include -#include - -/** Class handles brute force mechanic */ -class InfraredAppBruteForce { - /** Universal database filename */ - const char* universal_db_filename; - - /** Current record name (POWER, MUTE, VOL+, etc). - * This is the name of signal to brute force. */ - std::string current_record; - - /** Flipper File Format instance */ - FlipperFormat* ff; - - /** Data about every record - index in button panel view - * and amount of signals, which is need for correct - * progress bar displaying. */ - typedef struct { - /** Index of record in button panel view model */ - int index; - /** Amount of signals of that type (POWER, MUTE, etc) */ - int amount; - } Record; - - /** Container to hold Record info. - * 'key' is record name, because we have to search by both, index and name, - * but index search has place once per button press, and should not be - * noticed, but name search should occur during entering universal menu, - * and will go through container for every record in file, that's why - * more critical to have faster search by record name. - */ - std::unordered_map records; - -public: - /** Calculate messages. Walk through the file ('universal_db_name') - * and calculate amount of records of certain type. */ - bool calculate_messages(); - - /** Start brute force */ - bool start_bruteforce(int index, int& record_amount); - - /** Stop brute force */ - void stop_bruteforce(); - - /** Send next signal during brute force */ - bool send_next_bruteforce(); - - /** Add record to container of records */ - void add_record(int index, const char* name); - - /** Initialize class, set db file */ - InfraredAppBruteForce(const char* filename) - : universal_db_filename(filename) { - } - - /** Deinitialize class */ - ~InfraredAppBruteForce() { - } -}; diff --git a/applications/infrared/infrared_app_event.h b/applications/infrared/infrared_app_event.h deleted file mode 100644 index 168ba0b1..00000000 --- a/applications/infrared/infrared_app_event.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file infrared_app_event.h - * Infrared: Scene events description - */ -#pragma once -#include -#include - -/** Infrared events class */ -class InfraredAppEvent { -public: - /** Type of event enum */ - enum class Type : uint8_t { - /** Tick event come after no other events came in 100 ms */ - Tick, - /** Exit application event */ - Exit, - /** Back event */ - Back, - /** Menu selected event type. Provided with payload value. */ - MenuSelected, - /** Button press event. Need for continuous signal sending. */ - MenuSelectedPress, - /** Button release event. Need for continuous signal sending. */ - MenuSelectedRelease, - /** Events from DialogEx view module */ - DialogExSelected, - /** Infrared signal received event */ - InfraredMessageReceived, - /** Text edit done event */ - TextEditDone, - /** Popup timer finished event */ - PopupTimer, - /** Button panel pressed event */ - ButtonPanelPressed, - }; - - union { - int32_t dummy; - /** Menu selected event type payload. Selected index. */ - int32_t menu_index; - /** DialogEx view module event type payload */ - DialogExResult dialog_ex_result; - } payload; - - /** Type of event */ - Type type; -}; diff --git a/applications/infrared/infrared_app_remote_manager.cpp b/applications/infrared/infrared_app_remote_manager.cpp deleted file mode 100644 index faeccb39..00000000 --- a/applications/infrared/infrared_app_remote_manager.cpp +++ /dev/null @@ -1,266 +0,0 @@ -#include "m-string.h" -#include "storage/filesystem_api_defines.h" -#include -#include "infrared_app_remote_manager.h" -#include "infrared/helpers/infrared_parser.h" -#include "infrared/infrared_app_signal.h" - -#include - -#include -#include -#include -#include -#include -#include "infrared_app.h" -#include - -static const char* default_remote_name = "remote"; - -void InfraredAppRemoteManager::find_vacant_remote_name(string_t name, string_t path) { - Storage* storage = static_cast(furi_record_open("storage")); - - string_t base_path; - string_init_set(base_path, path); - - if(string_end_with_str_p(base_path, InfraredApp::infrared_extension)) { - size_t filename_start = string_search_rchar(base_path, '/'); - string_left(base_path, filename_start); - } - - string_printf( - base_path, - "%s/%s%s", - string_get_cstr(path), - string_get_cstr(name), - InfraredApp::infrared_extension); - - FS_Error error = storage_common_stat(storage, string_get_cstr(base_path), NULL); - - if(error == FSE_OK) { - /* if suggested name is occupied, try another one (name2, name3, etc) */ - size_t dot = string_search_rchar(base_path, '.'); - string_left(base_path, dot); - - string_t path_temp; - string_init(path_temp); - - uint32_t i = 1; - do { - string_printf( - path_temp, - "%s%u%s", - string_get_cstr(base_path), - ++i, - InfraredApp::infrared_extension); - error = storage_common_stat(storage, string_get_cstr(path_temp), NULL); - } while(error == FSE_OK); - - string_clear(path_temp); - - if(error == FSE_NOT_EXIST) { - string_cat_printf(name, "%u", i); - } - } - - string_clear(base_path); - furi_record_close("storage"); -} - -bool InfraredAppRemoteManager::add_button(const char* button_name, const InfraredAppSignal& signal) { - remote->buttons.emplace_back(button_name, signal); - return store(); -} - -bool InfraredAppRemoteManager::add_remote_with_button( - const char* button_name, - const InfraredAppSignal& signal) { - furi_check(button_name != nullptr); - - string_t new_name; - string_init_set_str(new_name, default_remote_name); - - string_t new_path; - string_init_set_str(new_path, InfraredApp::infrared_directory); - - find_vacant_remote_name(new_name, new_path); - - string_cat_printf( - new_path, "/%s%s", string_get_cstr(new_name), InfraredApp::infrared_extension); - - remote = std::make_unique(new_path); - remote->name = std::string(string_get_cstr(new_name)); - - string_clear(new_path); - string_clear(new_name); - - return add_button(button_name, signal); -} - -std::vector InfraredAppRemoteManager::get_button_list(void) const { - std::vector name_vector; - name_vector.reserve(remote->buttons.size()); - - for(const auto& it : remote->buttons) { - name_vector.emplace_back(it.name); - } - - // copy elision - return name_vector; -} - -const InfraredAppSignal& InfraredAppRemoteManager::get_button_data(size_t index) const { - furi_check(remote.get() != nullptr); - auto& buttons = remote->buttons; - furi_check(index < buttons.size()); - - return buttons.at(index).signal; -} - -bool InfraredAppRemoteManager::delete_remote() { - Storage* storage = static_cast(furi_record_open("storage")); - - FS_Error error = storage_common_remove(storage, string_get_cstr(remote->path)); - reset_remote(); - - furi_record_close("storage"); - return (error == FSE_OK || error == FSE_NOT_EXIST); -} - -void InfraredAppRemoteManager::reset_remote() { - remote.reset(); -} - -bool InfraredAppRemoteManager::delete_button(uint32_t index) { - furi_check(remote.get() != nullptr); - auto& buttons = remote->buttons; - furi_check(index < buttons.size()); - - buttons.erase(buttons.begin() + index); - return store(); -} - -std::string InfraredAppRemoteManager::get_button_name(uint32_t index) { - furi_check(remote.get() != nullptr); - auto& buttons = remote->buttons; - furi_check(index < buttons.size()); - return buttons[index].name.c_str(); -} - -std::string InfraredAppRemoteManager::get_remote_name() { - return remote.get() ? remote->name : std::string(); -} - -bool InfraredAppRemoteManager::rename_remote(const char* str) { - furi_check(str != nullptr); - furi_check(remote.get() != nullptr); - furi_check(!string_empty_p(remote->path)); - - if(!remote->name.compare(str)) { - return true; - } - - string_t new_name; - string_init_set_str(new_name, str); - find_vacant_remote_name(new_name, remote->path); - - string_t new_path; - string_init_set(new_path, remote->path); - if(string_end_with_str_p(new_path, InfraredApp::infrared_extension)) { - size_t filename_start = string_search_rchar(new_path, '/'); - string_left(new_path, filename_start); - } - string_cat_printf( - new_path, "/%s%s", string_get_cstr(new_name), InfraredApp::infrared_extension); - - Storage* storage = static_cast(furi_record_open("storage")); - - FS_Error error = - storage_common_rename(storage, string_get_cstr(remote->path), string_get_cstr(new_path)); - remote->name = std::string(string_get_cstr(new_name)); - - string_clear(new_name); - string_clear(new_path); - - furi_record_close("storage"); - return (error == FSE_OK || error == FSE_EXIST); -} - -bool InfraredAppRemoteManager::rename_button(uint32_t index, const char* str) { - furi_check(remote.get() != nullptr); - auto& buttons = remote->buttons; - furi_check(index < buttons.size()); - - buttons[index].name = str; - return store(); -} - -size_t InfraredAppRemoteManager::get_number_of_buttons() { - furi_check(remote.get() != nullptr); - return remote->buttons.size(); -} - -bool InfraredAppRemoteManager::store(void) { - bool result = false; - Storage* storage = static_cast(furi_record_open("storage")); - - if(!storage_simply_mkdir(storage, InfraredApp::infrared_directory)) return false; - - FlipperFormat* ff = flipper_format_file_alloc(storage); - - FURI_LOG_I("RemoteManager", "store file: \'%s\'", string_get_cstr(remote->path)); - result = flipper_format_file_open_always(ff, string_get_cstr(remote->path)); - if(result) { - result = flipper_format_write_header_cstr(ff, "IR signals file", 1); - } - if(result) { - for(const auto& button : remote->buttons) { - result = infrared_parser_save_signal(ff, button.signal, button.name.c_str()); - if(!result) { - break; - } - } - } - - flipper_format_free(ff); - furi_record_close("storage"); - return result; -} - -bool InfraredAppRemoteManager::load(string_t path) { - bool result = false; - Storage* storage = static_cast(furi_record_open("storage")); - FlipperFormat* ff = flipper_format_file_alloc(storage); - - FURI_LOG_I("RemoteManager", "load file: \'%s\'", string_get_cstr(path)); - result = flipper_format_file_open_existing(ff, string_get_cstr(path)); - if(result) { - string_t header; - string_init(header); - uint32_t version; - result = flipper_format_read_header(ff, header, &version); - if(result) { - result = !string_cmp_str(header, "IR signals file") && (version == 1); - } - string_clear(header); - } - if(result) { - string_t new_name; - string_init(new_name); - - remote = std::make_unique(path); - path_extract_filename(path, new_name, true); - remote->name = std::string(string_get_cstr(new_name)); - - string_clear(new_name); - InfraredAppSignal signal; - std::string signal_name; - while(infrared_parser_read_signal(ff, signal, signal_name)) { - remote->buttons.emplace_back(signal_name.c_str(), std::move(signal)); - } - } - - flipper_format_free(ff); - furi_record_close("storage"); - return result; -} diff --git a/applications/infrared/infrared_app_remote_manager.h b/applications/infrared/infrared_app_remote_manager.h deleted file mode 100644 index b6f0b170..00000000 --- a/applications/infrared/infrared_app_remote_manager.h +++ /dev/null @@ -1,189 +0,0 @@ -/** - * @file infrared_app_remote_manager.h - * Infrared: Remote manager class. - * It holds remote, can load/save/rename remote, - * add/remove/rename buttons. - */ -#pragma once - -#include "infrared_app_signal.h" - -#include "m-string.h" -#include -#include - -#include -#include -#include -#include - -/** Class to handle remote button */ -class InfraredAppRemoteButton { - /** Allow field access */ - friend class InfraredAppRemoteManager; - /** Name of signal */ - std::string name; - /** Signal data */ - InfraredAppSignal signal; - -public: - /** Initialize remote button - * - * @param name - button name - * @param signal - signal to copy for remote button - */ - InfraredAppRemoteButton(const char* name, const InfraredAppSignal& signal) - : name(name) - , signal(signal) { - } - - /** Initialize remote button - * - * @param name - button name - * @param signal - signal to move for remote button - */ - InfraredAppRemoteButton(const char* name, InfraredAppSignal&& signal) - : name(name) - , signal(std::move(signal)) { - } - - /** Deinitialize remote button */ - ~InfraredAppRemoteButton() { - } -}; - -/** Class to handle remote */ -class InfraredAppRemote { - /** Allow field access */ - friend class InfraredAppRemoteManager; - /** Button container */ - std::vector buttons; - /** Name of remote */ - std::string name; - /** Path to remote file */ - string_t path; - -public: - /** Initialize new remote - * - * @param path - remote file path - */ - InfraredAppRemote(string_t file_path) { - string_init_set(path, file_path); - } - - ~InfraredAppRemote() { - string_clear(path); - } -}; - -/** Class to handle remote manager */ -class InfraredAppRemoteManager { - /** Remote instance. There can be 1 remote loaded at a time. */ - std::unique_ptr remote; - -public: - /** Restriction to button name length. Buttons larger are ignored. */ - static constexpr const uint32_t max_button_name_length = 22; - - /** Restriction to remote name length. Remotes larger are ignored. */ - static constexpr const uint32_t max_remote_name_length = 22; - - /** Construct button from signal, and create remote - * - * @param button_name - name of button to create - * @param signal - signal to create button from - * @retval true for success, false otherwise - * */ - bool add_remote_with_button(const char* button_name, const InfraredAppSignal& signal); - - /** Add button to current remote - * - * @param button_name - name of button to create - * @param signal - signal to create button from - * @retval true for success, false otherwise - * */ - bool add_button(const char* button_name, const InfraredAppSignal& signal); - - /** Rename button in current remote - * - * @param index - index of button to rename - * @param str - new button name - */ - bool rename_button(uint32_t index, const char* str); - - /** Rename current remote - * - * @param str - new remote name - */ - bool rename_remote(const char* str); - - /** Find vacant remote name. If suggested name is occupied, - * incremented digit(2,3,4,etc) added to name and check repeated. - * - * @param name - suggested remote name - * @param path - remote file path - */ - void find_vacant_remote_name(string_t name, string_t path); - - /** Get button list - * - * @retval container of button names - */ - std::vector get_button_list() const; - - /** Get button name by index - * - * @param index - index of button to get name from - * @retval button name - */ - std::string get_button_name(uint32_t index); - - /** Get remote name - * - * @retval remote name - */ - std::string get_remote_name(); - - /** Get number of buttons - * - * @retval number of buttons - */ - size_t get_number_of_buttons(); - - /** Get button's signal - * - * @param index - index of interested button - * @retval signal - */ - const InfraredAppSignal& get_button_data(size_t index) const; - - /** Delete button - * - * @param index - index of interested button - * @retval true if success, false otherwise - */ - bool delete_button(uint32_t index); - - /** Delete remote - * - * @retval true if success, false otherwise - */ - bool delete_remote(); - - /** Clean all loaded info in current remote */ - void reset_remote(); - - /** Store current remote data on disk - * - * @retval true if success, false otherwise - */ - bool store(); - - /** Load data from disk into current remote - * - * @param path - path to remote file - * @retval true if success, false otherwise - */ - bool load(string_t path); -}; diff --git a/applications/infrared/infrared_app_signal.cpp b/applications/infrared/infrared_app_signal.cpp deleted file mode 100644 index 3344b3ca..00000000 --- a/applications/infrared/infrared_app_signal.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "infrared_app_signal.h" -#include - -void InfraredAppSignal::copy_raw_signal( - const uint32_t* timings, - size_t size, - uint32_t frequency, - float duty_cycle) { - furi_assert(size); - furi_assert(timings); - - payload.raw.frequency = frequency; - payload.raw.duty_cycle = duty_cycle; - payload.raw.timings_cnt = size; - if(size) { - payload.raw.timings = new uint32_t[size]; - memcpy(payload.raw.timings, timings, size * sizeof(uint32_t)); - } -} - -void InfraredAppSignal::clear_timings() { - if(raw_signal) { - delete[] payload.raw.timings; - payload.raw.timings_cnt = 0; - payload.raw.timings = nullptr; - } -} - -InfraredAppSignal::InfraredAppSignal( - const uint32_t* timings, - size_t timings_cnt, - uint32_t frequency, - float duty_cycle) { - raw_signal = true; - copy_raw_signal(timings, timings_cnt, frequency, duty_cycle); -} - -InfraredAppSignal::InfraredAppSignal(const InfraredMessage* infrared_message) { - raw_signal = false; - payload.message = *infrared_message; -} - -InfraredAppSignal& InfraredAppSignal::operator=(const InfraredAppSignal& other) { - clear_timings(); - raw_signal = other.raw_signal; - if(!raw_signal) { - payload.message = other.payload.message; - } else { - copy_raw_signal( - other.payload.raw.timings, - other.payload.raw.timings_cnt, - other.payload.raw.frequency, - other.payload.raw.duty_cycle); - } - - return *this; -} - -InfraredAppSignal::InfraredAppSignal(const InfraredAppSignal& other) { - raw_signal = other.raw_signal; - if(!raw_signal) { - payload.message = other.payload.message; - } else { - copy_raw_signal( - other.payload.raw.timings, - other.payload.raw.timings_cnt, - other.payload.raw.frequency, - other.payload.raw.duty_cycle); - } -} - -InfraredAppSignal::InfraredAppSignal(InfraredAppSignal&& other) { - raw_signal = other.raw_signal; - if(!raw_signal) { - payload.message = other.payload.message; - } else { - furi_assert(other.payload.raw.timings_cnt > 0); - - payload.raw.timings = other.payload.raw.timings; - payload.raw.timings_cnt = other.payload.raw.timings_cnt; - payload.raw.frequency = other.payload.raw.frequency; - payload.raw.duty_cycle = other.payload.raw.duty_cycle; - other.payload.raw.timings = nullptr; - other.payload.raw.timings_cnt = 0; - other.raw_signal = false; - } -} - -void InfraredAppSignal::set_message(const InfraredMessage* infrared_message) { - clear_timings(); - raw_signal = false; - payload.message = *infrared_message; -} - -void InfraredAppSignal::set_raw_signal( - uint32_t* timings, - size_t timings_cnt, - uint32_t frequency, - float duty_cycle) { - clear_timings(); - raw_signal = true; - copy_raw_signal(timings, timings_cnt, frequency, duty_cycle); -} - -void InfraredAppSignal::transmit() const { - if(!raw_signal) { - infrared_send(&payload.message, 1); - } else { - infrared_send_raw_ext( - payload.raw.timings, - payload.raw.timings_cnt, - true, - payload.raw.frequency, - payload.raw.duty_cycle); - } -} diff --git a/applications/infrared/infrared_app_signal.h b/applications/infrared/infrared_app_signal.h deleted file mode 100644 index 7b0b491b..00000000 --- a/applications/infrared/infrared_app_signal.h +++ /dev/null @@ -1,134 +0,0 @@ -/** - * @file infrared_app_signal.h - * Infrared: Signal class - */ -#pragma once -#include -#include -#include -#include - -/** Infrared application signal class */ -class InfraredAppSignal { -public: - /** Raw signal structure */ - typedef struct { - /** Timings amount */ - size_t timings_cnt; - /** Samples of raw signal in ms */ - uint32_t* timings; - /** PWM Frequency of raw signal */ - uint32_t frequency; - /** PWM Duty cycle of raw signal */ - float duty_cycle; - } RawSignal; - -private: - /** if true - signal is raw, if false - signal is parsed */ - bool raw_signal; - /** signal data, either raw or parsed */ - union { - /** signal data for parsed signal */ - InfraredMessage message; - /** raw signal data */ - RawSignal raw; - } payload; - - /** Copy raw signal into object - * - * @param timings - timings (samples) of raw signal - * @param size - number of timings - * @frequency - PWM frequency of raw signal - * @duty_cycle - PWM duty cycle - */ - void - copy_raw_signal(const uint32_t* timings, size_t size, uint32_t frequency, float duty_cycle); - /** Clear and free timings data */ - void clear_timings(); - -public: - /** Construct Infrared signal class */ - InfraredAppSignal() { - raw_signal = false; - payload.message.protocol = InfraredProtocolUnknown; - } - - /** Destruct signal class and free all allocated data */ - ~InfraredAppSignal() { - clear_timings(); - } - - /** Construct object with raw signal - * - * @param timings - timings (samples) of raw signal - * @param size - number of timings - * @frequency - PWM frequency of raw signal - * @duty_cycle - PWM duty cycle - */ - InfraredAppSignal( - const uint32_t* timings, - size_t timings_cnt, - uint32_t frequency, - float duty_cycle); - - /** Construct object with parsed signal - * - * @param infrared_message - parsed_signal to construct from - */ - InfraredAppSignal(const InfraredMessage* infrared_message); - - /** Copy constructor */ - InfraredAppSignal(const InfraredAppSignal& other); - /** Move constructor */ - InfraredAppSignal(InfraredAppSignal&& other); - - /** Assignment operator */ - InfraredAppSignal& operator=(const InfraredAppSignal& signal); - - /** Set object to parsed signal - * - * @param infrared_message - parsed_signal to construct from - */ - void set_message(const InfraredMessage* infrared_message); - - /** Set object to raw signal - * - * @param timings - timings (samples) of raw signal - * @param size - number of timings - * @frequency - PWM frequency of raw signal - * @duty_cycle - PWM duty cycle - */ - void - set_raw_signal(uint32_t* timings, size_t timings_cnt, uint32_t frequency, float duty_cycle); - - /** Transmit held signal (???) */ - void transmit() const; - - /** Show is held signal raw - * - * @retval true if signal is raw, false if signal is parsed - */ - bool is_raw(void) const { - return raw_signal; - } - - /** Get parsed signal. - * User must check is_raw() signal before calling this function. - * - * @retval parsed signal pointer - */ - const InfraredMessage& get_message(void) const { - furi_assert(!raw_signal); - return payload.message; - } - - /** Get raw signal. - * User must check is_raw() signal before calling this function. - * - * @retval raw signal - */ - const RawSignal& get_raw_signal(void) const { - furi_assert(raw_signal); - return payload.raw; - } -}; diff --git a/applications/infrared/infrared_app_view_manager.cpp b/applications/infrared/infrared_app_view_manager.cpp deleted file mode 100644 index f1e48ed4..00000000 --- a/applications/infrared/infrared_app_view_manager.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "infrared/infrared_app_view_manager.h" -#include "infrared/view/infrared_progress_view.h" -#include "infrared_app.h" -#include "infrared/infrared_app_event.h" - -InfraredAppViewManager::InfraredAppViewManager() { - event_queue = osMessageQueueNew(10, sizeof(InfraredAppEvent), NULL); - - view_dispatcher = view_dispatcher_alloc(); - auto callback = cbc::obtain_connector(this, &InfraredAppViewManager::previous_view_callback); - - gui = static_cast(furi_record_open("gui")); - view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); - - button_menu = button_menu_alloc(); - submenu = submenu_alloc(); - popup = popup_alloc(); - dialog_ex = dialog_ex_alloc(); - text_input = text_input_alloc(); - button_panel = button_panel_alloc(); - progress_view = infrared_progress_view_alloc(); - loading_view = loading_alloc(); - universal_view_stack = view_stack_alloc(); - view_stack_add_view(universal_view_stack, button_panel_get_view(button_panel)); - view_set_orientation(view_stack_get_view(universal_view_stack), ViewOrientationVertical); - - add_view(ViewId::UniversalRemote, view_stack_get_view(universal_view_stack)); - add_view(ViewId::ButtonMenu, button_menu_get_view(button_menu)); - add_view(ViewId::Submenu, submenu_get_view(submenu)); - add_view(ViewId::Popup, popup_get_view(popup)); - add_view(ViewId::DialogEx, dialog_ex_get_view(dialog_ex)); - add_view(ViewId::TextInput, text_input_get_view(text_input)); - - view_set_previous_callback(view_stack_get_view(universal_view_stack), callback); - view_set_previous_callback(button_menu_get_view(button_menu), callback); - view_set_previous_callback(submenu_get_view(submenu), callback); - view_set_previous_callback(popup_get_view(popup), callback); - view_set_previous_callback(dialog_ex_get_view(dialog_ex), callback); - view_set_previous_callback(text_input_get_view(text_input), callback); -} - -InfraredAppViewManager::~InfraredAppViewManager() { - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::UniversalRemote)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::ButtonMenu)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::TextInput)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::DialogEx)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::Submenu)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::Popup)); - - view_stack_remove_view(universal_view_stack, button_panel_get_view(button_panel)); - view_stack_free(universal_view_stack); - button_panel_free(button_panel); - submenu_free(submenu); - popup_free(popup); - button_menu_free(button_menu); - dialog_ex_free(dialog_ex); - text_input_free(text_input); - infrared_progress_view_free(progress_view); - loading_free(loading_view); - - view_dispatcher_free(view_dispatcher); - furi_record_close("gui"); - osMessageQueueDelete(event_queue); -} - -void InfraredAppViewManager::switch_to(ViewId type) { - view_dispatcher_switch_to_view(view_dispatcher, static_cast(type)); -} - -TextInput* InfraredAppViewManager::get_text_input() { - return text_input; -} - -DialogEx* InfraredAppViewManager::get_dialog_ex() { - return dialog_ex; -} - -Submenu* InfraredAppViewManager::get_submenu() { - return submenu; -} - -Popup* InfraredAppViewManager::get_popup() { - return popup; -} - -ButtonMenu* InfraredAppViewManager::get_button_menu() { - return button_menu; -} - -ButtonPanel* InfraredAppViewManager::get_button_panel() { - return button_panel; -} - -InfraredProgressView* InfraredAppViewManager::get_progress() { - return progress_view; -} - -Loading* InfraredAppViewManager::get_loading() { - return loading_view; -} - -ViewStack* InfraredAppViewManager::get_universal_view_stack() { - return universal_view_stack; -} - -osMessageQueueId_t InfraredAppViewManager::get_event_queue() { - return event_queue; -} - -void InfraredAppViewManager::clear_events() { - InfraredAppEvent event; - while(osMessageQueueGet(event_queue, &event, NULL, 0) == osOK) - ; -} - -void InfraredAppViewManager::receive_event(InfraredAppEvent* event) { - if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) { - event->type = InfraredAppEvent::Type::Tick; - } -} - -void InfraredAppViewManager::send_event(InfraredAppEvent* event) { - uint32_t timeout = 0; - /* Rapid button hammering on signal send scenes causes queue overflow - ignore it, - * but try to keep button release event - it switches off INFRARED DMA sending. */ - if(event->type == InfraredAppEvent::Type::MenuSelectedRelease) { - timeout = 200; - } - if((event->type == InfraredAppEvent::Type::DialogExSelected) && - (event->payload.dialog_ex_result == DialogExReleaseCenter)) { - timeout = 200; - } - - osMessageQueuePut(event_queue, event, 0, timeout); -} - -uint32_t InfraredAppViewManager::previous_view_callback(void*) { - if(event_queue != NULL) { - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::Back; - send_event(&event); - } - - return VIEW_IGNORE; -} - -void InfraredAppViewManager::add_view(ViewId view_type, View* view) { - view_dispatcher_add_view(view_dispatcher, static_cast(view_type), view); -} diff --git a/applications/infrared/infrared_app_view_manager.h b/applications/infrared/infrared_app_view_manager.h deleted file mode 100644 index 106d2660..00000000 --- a/applications/infrared/infrared_app_view_manager.h +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @file infrared_app_view_manager.h - * Infrared: Scene events description - */ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "infrared_app_event.h" -#include "view/infrared_progress_view.h" - -/** Infrared View manager class */ -class InfraredAppViewManager { -public: - /** Infrared View Id enum, it is used - * to identify added views */ - enum class ViewId : uint8_t { - DialogEx, - TextInput, - Submenu, - ButtonMenu, - UniversalRemote, - Popup, - }; - - /** Class constructor */ - InfraredAppViewManager(); - /** Class destructor */ - ~InfraredAppViewManager(); - - /** Switch to another view - * - * @param id - view id to switch to - */ - void switch_to(ViewId id); - - /** Receive event from queue - * - * @param event - received event - */ - void receive_event(InfraredAppEvent* event); - - /** Send event to queue - * - * @param event - event to send - */ - void send_event(InfraredAppEvent* event); - - /** Clear events that already in queue - * - * @param event - event to send - */ - void clear_events(); - - /** Get dialog_ex view module - * - * @retval dialog_ex view module - */ - DialogEx* get_dialog_ex(); - - /** Get submenu view module - * - * @retval submenu view module - */ - Submenu* get_submenu(); - - /** Get popup view module - * - * @retval popup view module - */ - Popup* get_popup(); - - /** Get text_input view module - * - * @retval text_input view module - */ - TextInput* get_text_input(); - - /** Get button_menu view module - * - * @retval button_menu view module - */ - ButtonMenu* get_button_menu(); - - /** Get button_panel view module - * - * @retval button_panel view module - */ - ButtonPanel* get_button_panel(); - - /** Get view_stack view module used in universal remote - * - * @retval view_stack view module - */ - ViewStack* get_universal_view_stack(); - - /** Get progress view module - * - * @retval progress view module - */ - InfraredProgressView* get_progress(); - - /** Get loading view module - * - * @retval loading view module - */ - Loading* get_loading(); - - /** Get event queue - * - * @retval event queue - */ - osMessageQueueId_t get_event_queue(); - - /** Callback to handle back button - * - * @param context - context to pass to callback - * @retval always returns VIEW_IGNORE - */ - uint32_t previous_view_callback(void* context); - -private: - /** View Dispatcher instance. - * It handles view switching */ - ViewDispatcher* view_dispatcher; - /** Gui instance */ - Gui* gui; - /** Text input view module instance */ - TextInput* text_input; - /** DialogEx view module instance */ - DialogEx* dialog_ex; - /** Submenu view module instance */ - Submenu* submenu; - /** Popup view module instance */ - Popup* popup; - /** ButtonMenu view module instance */ - ButtonMenu* button_menu; - /** ButtonPanel view module instance */ - ButtonPanel* button_panel; - /** ViewStack view module instance */ - ViewStack* universal_view_stack; - /** ProgressView view module instance */ - InfraredProgressView* progress_view; - /** Loading view module instance */ - Loading* loading_view; - - /** Queue to handle events, which are processed in scenes */ - osMessageQueueId_t event_queue; - - /** Add View to pull of views - * - * @param view_id - id to identify view - * @param view - view to add - */ - void add_view(ViewId view_id, View* view); -}; diff --git a/applications/infrared/infrared_brute_force.c b/applications/infrared/infrared_brute_force.c new file mode 100644 index 00000000..872a7637 --- /dev/null +++ b/applications/infrared/infrared_brute_force.c @@ -0,0 +1,153 @@ +#include "infrared_brute_force.h" + +#include +#include +#include +#include + +#include "infrared_signal.h" + +typedef struct { + uint32_t index; + uint32_t count; +} InfraredBruteForceRecord; + +DICT_DEF2( + InfraredBruteForceRecordDict, + string_t, + STRING_OPLIST, + InfraredBruteForceRecord, + M_POD_OPLIST); + +struct InfraredBruteForce { + FlipperFormat* ff; + const char* db_filename; + string_t current_record_name; + InfraredBruteForceRecordDict_t records; +}; + +InfraredBruteForce* infrared_brute_force_alloc() { + InfraredBruteForce* brute_force = malloc(sizeof(InfraredBruteForce)); + brute_force->ff = NULL; + brute_force->db_filename = NULL; + string_init(brute_force->current_record_name); + InfraredBruteForceRecordDict_init(brute_force->records); + return brute_force; +} + +void infrared_brute_force_free(InfraredBruteForce* brute_force) { + furi_assert(!brute_force->ff); + InfraredBruteForceRecordDict_clear(brute_force->records); + string_clear(brute_force->current_record_name); + free(brute_force); +} + +void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename) { + brute_force->db_filename = db_filename; +} + +bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) { + furi_assert(brute_force->db_filename); + bool success = false; + + Storage* storage = furi_record_open("storage"); + FlipperFormat* ff = flipper_format_file_alloc(storage); + + success = flipper_format_file_open_existing(ff, brute_force->db_filename); + if(success) { + string_t signal_name; + string_init(signal_name); + while(flipper_format_read_string(ff, "name", signal_name)) { + InfraredBruteForceRecord* record = + InfraredBruteForceRecordDict_get(brute_force->records, signal_name); + if(record) { + ++(record->count); + } + } + string_clear(signal_name); + } + + flipper_format_free(ff); + furi_record_close("storage"); + return success; +} + +bool infrared_brute_force_start( + InfraredBruteForce* brute_force, + uint32_t index, + uint32_t* record_count) { + bool success = false; + *record_count = 0; + + InfraredBruteForceRecordDict_it_t it; + for(InfraredBruteForceRecordDict_it(it, brute_force->records); + !InfraredBruteForceRecordDict_end_p(it); + InfraredBruteForceRecordDict_next(it)) { + const InfraredBruteForceRecordDict_itref_t* record = InfraredBruteForceRecordDict_cref(it); + if(record->value.index == index) { + *record_count = record->value.count; + if(*record_count) { + string_set(brute_force->current_record_name, record->key); + } + break; + } + } + + if(*record_count) { + Storage* storage = furi_record_open("storage"); + brute_force->ff = flipper_format_file_alloc(storage); + success = flipper_format_file_open_existing(brute_force->ff, brute_force->db_filename); + if(!success) { + flipper_format_free(brute_force->ff); + furi_record_close("storage"); + } + } + return success; +} + +bool infrared_brute_force_is_started(InfraredBruteForce* brute_force) { + return brute_force->ff; +} + +void infrared_brute_force_stop(InfraredBruteForce* brute_force) { + furi_assert(string_size(brute_force->current_record_name)); + furi_assert(brute_force->ff); + + string_reset(brute_force->current_record_name); + flipper_format_free(brute_force->ff); + furi_record_close("storage"); + brute_force->ff = NULL; +} + +bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) { + furi_assert(string_size(brute_force->current_record_name)); + furi_assert(brute_force->ff); + bool success = false; + + string_t signal_name; + string_init(signal_name); + InfraredSignal* signal = infrared_signal_alloc(); + + do { + success = infrared_signal_read(signal, brute_force->ff, signal_name); + } while(success && !string_equal_p(brute_force->current_record_name, signal_name)); + + if(success) { + infrared_signal_transmit(signal); + } + + infrared_signal_free(signal); + string_clear(signal_name); + return success; +} + +void infrared_brute_force_add_record( + InfraredBruteForce* brute_force, + uint32_t index, + const char* name) { + InfraredBruteForceRecord value = {.index = index, .count = 0}; + string_t key; + string_init_set_str(key, name); + InfraredBruteForceRecordDict_set_at(brute_force->records, key, value); + string_clear(key); +} diff --git a/applications/infrared/infrared_brute_force.h b/applications/infrared/infrared_brute_force.h new file mode 100644 index 00000000..acf0d7b6 --- /dev/null +++ b/applications/infrared/infrared_brute_force.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +typedef struct InfraredBruteForce InfraredBruteForce; + +InfraredBruteForce* infrared_brute_force_alloc(); +void infrared_brute_force_free(InfraredBruteForce* brute_force); +void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename); +bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force); +bool infrared_brute_force_start( + InfraredBruteForce* brute_force, + uint32_t index, + uint32_t* record_count); +bool infrared_brute_force_is_started(InfraredBruteForce* brute_force); +void infrared_brute_force_stop(InfraredBruteForce* brute_force); +bool infrared_brute_force_send_next(InfraredBruteForce* brute_force); +void infrared_brute_force_add_record( + InfraredBruteForce* brute_force, + uint32_t index, + const char* name); diff --git a/applications/infrared/cli/infrared_cli.cpp b/applications/infrared/infrared_cli.c similarity index 72% rename from applications/infrared/cli/infrared_cli.cpp rename to applications/infrared/infrared_cli.c index 79ab987d..1b3ec4b3 100644 --- a/applications/infrared/cli/infrared_cli.cpp +++ b/applications/infrared/infrared_cli.c @@ -1,16 +1,12 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include "../helpers/infrared_parser.h" +#include +#include +#include +#include + +#include "infrared_signal.h" + +#define INFRARED_CLI_BUF_SIZE 10 static void infrared_cli_start_ir_rx(Cli* cli, string_t args); static void infrared_cli_start_ir_tx(Cli* cli, string_t args); @@ -92,79 +88,83 @@ static void infrared_cli_print_usage(void) { INFRARED_MAX_FREQUENCY); } -static bool parse_message(const char* str, InfraredMessage* message) { +static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) { char protocol_name[32]; - int parsed = sscanf(str, "%31s %lX %lX", protocol_name, &message->address, &message->command); + InfraredMessage message; + int parsed = sscanf(str, "%31s %lX %lX", protocol_name, &message.address, &message.command); if(parsed != 3) { return false; } - message->protocol = infrared_get_protocol_by_name(protocol_name); - message->repeat = false; - - return infrared_parser_is_parsed_signal_valid(message); + message.repeat = false; + infrared_signal_set_message(signal, &message); + return infrared_signal_is_valid(signal); } -static bool parse_signal_raw( - const char* str, - uint32_t* timings, - uint32_t* timings_cnt, - float* duty_cycle, - uint32_t* frequency) { - char frequency_str[10]; - char duty_cycle_str[10]; +static bool infrared_cli_parse_raw(const char* str, InfraredSignal* signal) { + char frequency_str[INFRARED_CLI_BUF_SIZE]; + char duty_cycle_str[INFRARED_CLI_BUF_SIZE]; int parsed = sscanf(str, "RAW F:%9s DC:%9s", frequency_str, duty_cycle_str); - if(parsed != 2) return false; - *frequency = atoi(frequency_str); - *duty_cycle = (float)atoi(duty_cycle_str) / 100; - str += strlen(frequency_str) + strlen(duty_cycle_str) + 10; - - uint32_t timings_cnt_max = *timings_cnt; - *timings_cnt = 0; - - while(1) { - char timing_str[10]; - for(; *str == ' '; ++str) - ; - if(1 != sscanf(str, "%9s", timing_str)) break; - str += strlen(timing_str); - uint32_t timing = atoi(timing_str); - if(timing <= 0) break; - if(*timings_cnt >= timings_cnt_max) break; - timings[*timings_cnt] = timing; - ++*timings_cnt; + if(parsed != 2) { + return false; } - return infrared_parser_is_raw_signal_valid(*frequency, *duty_cycle, *timings_cnt); + uint32_t* timings = malloc(sizeof(uint32_t) * MAX_TIMINGS_AMOUNT); + uint32_t frequency = atoi(frequency_str); + float duty_cycle = (float)atoi(duty_cycle_str) / 100; + + str += strlen(frequency_str) + strlen(duty_cycle_str) + INFRARED_CLI_BUF_SIZE; + + size_t timings_size = 0; + while(1) { + while(*str == ' ') { + ++str; + } + + char timing_str[INFRARED_CLI_BUF_SIZE]; + if(sscanf(str, "%9s", timing_str) != 1) { + break; + } + + str += strlen(timing_str); + uint32_t timing = atoi(timing_str); + + if((timing <= 0) || (timings_size >= MAX_TIMINGS_AMOUNT)) { + break; + } + + timings[timings_size] = timing; + ++timings_size; + } + + infrared_signal_set_raw_signal(signal, timings, timings_size, frequency, duty_cycle); + free(timings); + + return infrared_signal_is_valid(signal); } static void infrared_cli_start_ir_tx(Cli* cli, string_t args) { UNUSED(cli); - InfraredMessage message; const char* str = string_get_cstr(args); - uint32_t frequency; - float duty_cycle; - uint32_t timings_cnt = MAX_TIMINGS_AMOUNT; - uint32_t* timings = (uint32_t*)malloc(sizeof(uint32_t) * timings_cnt); + InfraredSignal* signal = infrared_signal_alloc(); - if(parse_message(str, &message)) { - infrared_send(&message, 1); - } else if(parse_signal_raw(str, timings, &timings_cnt, &duty_cycle, &frequency)) { - infrared_send_raw_ext(timings, timings_cnt, true, frequency, duty_cycle); + bool success = infrared_cli_parse_message(str, signal) || infrared_cli_parse_raw(str, signal); + if(success) { + infrared_signal_transmit(signal); } else { printf("Wrong arguments.\r\n"); infrared_cli_print_usage(); } - free(timings); + infrared_signal_free(signal); } static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { UNUSED(context); if(furi_hal_infrared_is_busy()) { - printf("INFRARED is busy. Exit."); + printf("INFRARED is busy. Exiting."); return; } @@ -189,8 +189,7 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { infrared_cli_print_usage(); } } - -extern "C" void infrared_on_system_start() { +void infrared_on_system_start() { #ifdef SRV_CLI Cli* cli = (Cli*)furi_record_open("cli"); cli_add_command(cli, "ir", CliCommandFlagDefault, infrared_cli_start_ir, NULL); diff --git a/applications/infrared/infrared_custom_event.h b/applications/infrared/infrared_custom_event.h new file mode 100644 index 00000000..d991afb9 --- /dev/null +++ b/applications/infrared/infrared_custom_event.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +enum InfraredCustomEventType { + // Reserve first 100 events for button types and indexes, starting from 0 + InfraredCustomEventTypeReserved = 100, + InfraredCustomEventTypeMenuSelected, + InfraredCustomEventTypeTransmitStarted, + InfraredCustomEventTypeTransmitStopped, + InfraredCustomEventTypeSignalReceived, + InfraredCustomEventTypeTextEditDone, + InfraredCustomEventTypePopupTimeout, + InfraredCustomEventTypeButtonSelected, + InfraredCustomEventTypeBackPressed, +}; + +#pragma pack(push, 1) +typedef union { + uint32_t packed_value; + struct { + uint16_t type; + int16_t value; + } content; +} InfraredCustomEvent; +#pragma pack(pop) + +static inline uint32_t infrared_custom_event_pack(uint16_t type, int16_t value) { + InfraredCustomEvent event = {.content = {.type = type, .value = value}}; + return event.packed_value; +} + +static inline void + infrared_custom_event_unpack(uint32_t packed_value, uint16_t* type, int16_t* value) { + InfraredCustomEvent event = {.packed_value = packed_value}; + if(type) *type = event.content.type; + if(value) *value = event.content.value; +} + +static inline uint16_t infrared_custom_event_get_type(uint32_t packed_value) { + uint16_t type; + infrared_custom_event_unpack(packed_value, &type, NULL); + return type; +} + +static inline int16_t infrared_custom_event_get_value(uint32_t packed_value) { + int16_t value; + infrared_custom_event_unpack(packed_value, NULL, &value); + return value; +} diff --git a/applications/infrared/infrared_i.h b/applications/infrared/infrared_i.h new file mode 100644 index 00000000..06c6a5f7 --- /dev/null +++ b/applications/infrared/infrared_i.h @@ -0,0 +1,132 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include "infrared.h" +#include "infrared_remote.h" +#include "infrared_brute_force.h" +#include "infrared_custom_event.h" + +#include "scenes/infrared_scene.h" +#include "views/infrared_progress_view.h" +#include "views/infrared_debug_view.h" + +#define INFRARED_FILE_NAME_SIZE 100 +#define INFRARED_TEXT_STORE_NUM 2 +#define INFRARED_TEXT_STORE_SIZE 128 + +#define INFRARED_MAX_BUTTON_NAME_LENGTH 22 +#define INFRARED_MAX_REMOTE_NAME_LENGTH 22 + +#define INFRARED_APP_FOLDER "/any/infrared" +#define INFRARED_APP_EXTENSION ".ir" + +#define INFRARED_DEFAULT_REMOTE_NAME "Remote" + +typedef enum { + InfraredButtonIndexNone = -1, +} InfraredButtonIndex; + +typedef enum { + InfraredEditTargetNone, + InfraredEditTargetRemote, + InfraredEditTargetButton, +} InfraredEditTarget; + +typedef enum { + InfraredEditModeNone, + InfraredEditModeRename, + InfraredEditModeDelete, +} InfraredEditMode; + +typedef struct { + bool is_learning_new_remote; + bool is_debug_enabled; + InfraredEditTarget edit_target : 8; + InfraredEditMode edit_mode : 8; + int32_t current_button_index; +} InfraredAppState; + +struct Infrared { + SceneManager* scene_manager; + ViewDispatcher* view_dispatcher; + + Gui* gui; + Storage* storage; + DialogsApp* dialogs; + NotificationApp* notifications; + InfraredWorker* worker; + InfraredRemote* remote; + InfraredSignal* received_signal; + InfraredBruteForce* brute_force; + + Submenu* submenu; + TextInput* text_input; + DialogEx* dialog_ex; + ButtonMenu* button_menu; + Popup* popup; + + ViewStack* view_stack; + InfraredDebugView* debug_view; + + ButtonPanel* button_panel; + Loading* loading; + InfraredProgressView* progress; + + string_t file_path; + char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1]; + InfraredAppState app_state; +}; + +typedef enum { + InfraredViewSubmenu, + InfraredViewTextInput, + InfraredViewDialogEx, + InfraredViewButtonMenu, + InfraredViewPopup, + InfraredViewStack, + InfraredViewDebugView, +} InfraredView; + +typedef enum { + InfraredNotificationMessageSuccess, + InfraredNotificationMessageGreenOn, + InfraredNotificationMessageGreenOff, + InfraredNotificationMessageBlinkRead, + InfraredNotificationMessageBlinkSend, +} InfraredNotificationMessage; + +bool infrared_add_remote_with_button(Infrared* infrared, const char* name, InfraredSignal* signal); +bool infrared_rename_current_remote(Infrared* infrared, const char* name); +void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal); +void infrared_tx_start_button_index(Infrared* infrared, size_t button_index); +void infrared_tx_start_received(Infrared* infrared); +void infrared_tx_stop(Infrared* infrared); +void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...); +void infrared_text_store_clear(Infrared* infrared, uint32_t bank); +void infrared_play_notification_message(Infrared* infrared, uint32_t message); +void infrared_show_loading_popup(Infrared* infrared, bool show); + +void infrared_signal_sent_callback(void* context); +void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal); +void infrared_text_input_callback(void* context); +void infrared_popup_timeout_callback(void* context); diff --git a/applications/infrared/infrared_remote.c b/applications/infrared/infrared_remote.c new file mode 100644 index 00000000..ad75efe7 --- /dev/null +++ b/applications/infrared/infrared_remote.c @@ -0,0 +1,176 @@ +#include "infrared_remote.h" + +#include +#include +#include +#include +#include +#include + +#define TAG "InfraredRemote" + +ARRAY_DEF(InfraredButtonArray, InfraredRemoteButton*, M_PTR_OPLIST); + +struct InfraredRemote { + InfraredButtonArray_t buttons; + string_t name; + string_t path; +}; + +static void infrared_remote_clear_buttons(InfraredRemote* remote) { + InfraredButtonArray_it_t it; + for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it); + InfraredButtonArray_next(it)) { + infrared_remote_button_free(*InfraredButtonArray_cref(it)); + } + InfraredButtonArray_reset(remote->buttons); +} + +InfraredRemote* infrared_remote_alloc() { + InfraredRemote* remote = malloc(sizeof(InfraredRemote)); + InfraredButtonArray_init(remote->buttons); + string_init(remote->name); + string_init(remote->path); + return remote; +} + +void infrared_remote_free(InfraredRemote* remote) { + infrared_remote_clear_buttons(remote); + InfraredButtonArray_clear(remote->buttons); + string_clear(remote->path); + string_clear(remote->name); + free(remote); +} + +void infrared_remote_reset(InfraredRemote* remote) { + infrared_remote_clear_buttons(remote); + string_reset(remote->name); + string_reset(remote->path); +} + +void infrared_remote_set_name(InfraredRemote* remote, const char* name) { + string_set_str(remote->name, name); +} + +const char* infrared_remote_get_name(InfraredRemote* remote) { + return string_get_cstr(remote->name); +} + +void infrared_remote_set_path(InfraredRemote* remote, const char* path) { + string_set_str(remote->path, path); +} + +const char* infrared_remote_get_path(InfraredRemote* remote) { + return string_get_cstr(remote->path); +} + +size_t infrared_remote_get_button_count(InfraredRemote* remote) { + return InfraredButtonArray_size(remote->buttons); +} + +InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t index) { + furi_assert(index < InfraredButtonArray_size(remote->buttons)); + return *InfraredButtonArray_get(remote->buttons, index); +} + +bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal) { + InfraredRemoteButton* button = infrared_remote_button_alloc(); + infrared_remote_button_set_name(button, name); + infrared_remote_button_set_signal(button, signal); + InfraredButtonArray_push_back(remote->buttons, button); + return infrared_remote_store(remote); +} + +bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index) { + furi_assert(index < InfraredButtonArray_size(remote->buttons)); + InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, index); + infrared_remote_button_set_name(button, new_name); + return infrared_remote_store(remote); +} + +bool infrared_remote_delete_button(InfraredRemote* remote, size_t index) { + furi_assert(index < InfraredButtonArray_size(remote->buttons)); + InfraredRemoteButton* button; + InfraredButtonArray_pop_at(&button, remote->buttons, index); + infrared_remote_button_free(button); + return infrared_remote_store(remote); +} + +bool infrared_remote_store(InfraredRemote* remote) { + Storage* storage = furi_record_open("storage"); + FlipperFormat* ff = flipper_format_file_alloc(storage); + const char* path = string_get_cstr(remote->path); + + FURI_LOG_I(TAG, "store file: \'%s\'", path); + + bool success = flipper_format_file_open_always(ff, path) && + flipper_format_write_header_cstr(ff, "IR signals file", 1); + if(success) { + InfraredButtonArray_it_t it; + for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it); + InfraredButtonArray_next(it)) { + InfraredRemoteButton* button = *InfraredButtonArray_cref(it); + success = infrared_signal_save( + infrared_remote_button_get_signal(button), + ff, + infrared_remote_button_get_name(button)); + if(!success) { + break; + } + } + } + + flipper_format_free(ff); + furi_record_close("storage"); + return success; +} + +bool infrared_remote_load(InfraredRemote* remote, string_t path) { + Storage* storage = furi_record_open("storage"); + FlipperFormat* ff = flipper_format_file_alloc(storage); + + string_t buf; + string_init(buf); + + FURI_LOG_I(TAG, "load file: \'%s\'", string_get_cstr(path)); + bool success = flipper_format_file_open_existing(ff, string_get_cstr(path)); + + if(success) { + uint32_t version; + success = flipper_format_read_header(ff, buf, &version) && + !string_cmp_str(buf, "IR signals file") && (version == 1); + } + + if(success) { + path_extract_filename(path, buf, true); + infrared_remote_clear_buttons(remote); + infrared_remote_set_name(remote, string_get_cstr(buf)); + infrared_remote_set_path(remote, string_get_cstr(path)); + + for(bool can_read = true; can_read;) { + InfraredRemoteButton* button = infrared_remote_button_alloc(); + can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf); + if(can_read) { + infrared_remote_button_set_name(button, string_get_cstr(buf)); + InfraredButtonArray_push_back(remote->buttons, button); + } else { + infrared_remote_button_free(button); + } + } + } + + string_clear(buf); + flipper_format_free(ff); + furi_record_close("storage"); + return success; +} + +bool infrared_remote_remove(InfraredRemote* remote) { + Storage* storage = furi_record_open("storage"); + + FS_Error status = storage_common_remove(storage, string_get_cstr(remote->path)); + infrared_remote_reset(remote); + + furi_record_close("storage"); + return (status == FSE_OK || status == FSE_NOT_EXIST); +} diff --git a/applications/infrared/infrared_remote.h b/applications/infrared/infrared_remote.h new file mode 100644 index 00000000..1336383f --- /dev/null +++ b/applications/infrared/infrared_remote.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "infrared_remote_button.h" + +typedef struct InfraredRemote InfraredRemote; + +InfraredRemote* infrared_remote_alloc(); +void infrared_remote_free(InfraredRemote* remote); +void infrared_remote_reset(InfraredRemote* remote); + +void infrared_remote_set_name(InfraredRemote* remote, const char* name); +const char* infrared_remote_get_name(InfraredRemote* remote); + +void infrared_remote_set_path(InfraredRemote* remote, const char* path); +const char* infrared_remote_get_path(InfraredRemote* remote); + +size_t infrared_remote_get_button_count(InfraredRemote* remote); +InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t index); + +bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal); +bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index); +bool infrared_remote_delete_button(InfraredRemote* remote, size_t index); + +bool infrared_remote_store(InfraredRemote* remote); +bool infrared_remote_load(InfraredRemote* remote, string_t path); +bool infrared_remote_remove(InfraredRemote* remote); diff --git a/applications/infrared/infrared_remote_button.c b/applications/infrared/infrared_remote_button.c new file mode 100644 index 00000000..7525ce48 --- /dev/null +++ b/applications/infrared/infrared_remote_button.c @@ -0,0 +1,38 @@ +#include "infrared_remote_button.h" + +#include +#include + +struct InfraredRemoteButton { + string_t name; + InfraredSignal* signal; +}; + +InfraredRemoteButton* infrared_remote_button_alloc() { + InfraredRemoteButton* button = malloc(sizeof(InfraredRemoteButton)); + string_init(button->name); + button->signal = infrared_signal_alloc(); + return button; +} + +void infrared_remote_button_free(InfraredRemoteButton* button) { + string_clear(button->name); + infrared_signal_free(button->signal); + free(button); +} + +void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name) { + string_set_str(button->name, name); +} + +const char* infrared_remote_button_get_name(InfraredRemoteButton* button) { + return string_get_cstr(button->name); +} + +void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal) { + infrared_signal_set_signal(button->signal, signal); +} + +InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button) { + return button->signal; +} diff --git a/applications/infrared/infrared_remote_button.h b/applications/infrared/infrared_remote_button.h new file mode 100644 index 00000000..f25b759b --- /dev/null +++ b/applications/infrared/infrared_remote_button.h @@ -0,0 +1,14 @@ +#pragma once + +#include "infrared_signal.h" + +typedef struct InfraredRemoteButton InfraredRemoteButton; + +InfraredRemoteButton* infrared_remote_button_alloc(); +void infrared_remote_button_free(InfraredRemoteButton* button); + +void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name); +const char* infrared_remote_button_get_name(InfraredRemoteButton* button); + +void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal); +InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button); diff --git a/applications/infrared/infrared_runner.cpp b/applications/infrared/infrared_runner.cpp deleted file mode 100644 index 650b0fcd..00000000 --- a/applications/infrared/infrared_runner.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "infrared_app.h" - -extern "C" int32_t infrared_app(void* p) { - InfraredApp* app = new InfraredApp(); - int32_t result = app->run(p); - delete app; - - return result; -} diff --git a/applications/infrared/infrared_signal.c b/applications/infrared/infrared_signal.c new file mode 100644 index 00000000..79eafb30 --- /dev/null +++ b/applications/infrared/infrared_signal.c @@ -0,0 +1,264 @@ +#include "infrared_signal.h" + +#include +#include +#include +#include +#include + +#define TAG "InfraredSignal" + +struct InfraredSignal { + bool is_raw; + union { + InfraredMessage message; + InfraredRawSignal raw; + } payload; +}; + +static void infrared_signal_clear_timings(InfraredSignal* signal) { + if(signal->is_raw) { + free(signal->payload.raw.timings); + signal->payload.raw.timings_size = 0; + signal->payload.raw.timings = NULL; + } +} + +static bool infrared_signal_is_message_valid(InfraredMessage* message) { + if(!infrared_is_protocol_valid(message->protocol)) { + FURI_LOG_E(TAG, "Unknown protocol"); + return false; + } + + uint32_t address_length = infrared_get_protocol_address_length(message->protocol); + uint32_t address_mask = (1UL << address_length) - 1; + + if(message->address != (message->address & address_mask)) { + FURI_LOG_E( + TAG, + "Address is out of range (mask 0x%08lX): 0x%lX\r\n", + address_mask, + message->address); + return false; + } + + uint32_t command_length = infrared_get_protocol_command_length(message->protocol); + uint32_t command_mask = (1UL << command_length) - 1; + + if(message->command != (message->command & command_mask)) { + FURI_LOG_E( + TAG, + "Command is out of range (mask 0x%08lX): 0x%lX\r\n", + command_mask, + message->command); + return false; + } + + return true; +} + +static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) { + if((raw->frequency > INFRARED_MAX_FREQUENCY) || (raw->frequency < INFRARED_MIN_FREQUENCY)) { + FURI_LOG_E( + TAG, + "Frequency is out of range (%lX - %lX): %lX", + INFRARED_MIN_FREQUENCY, + INFRARED_MAX_FREQUENCY, + raw->frequency); + return false; + + } else if((raw->duty_cycle <= 0) || (raw->duty_cycle > 1)) { + FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", (double)raw->duty_cycle); + return false; + + } else if((raw->timings_size <= 0) || (raw->timings_size > MAX_TIMINGS_AMOUNT)) { + FURI_LOG_E( + TAG, + "Timings amount is out of range (0 - %lX): %lX", + MAX_TIMINGS_AMOUNT, + raw->timings_size); + return false; + } + + return true; +} + +static inline bool infrared_signal_save_message(InfraredMessage* message, FlipperFormat* ff) { + const char* protocol_name = infrared_get_protocol_name(message->protocol); + return flipper_format_write_string_cstr(ff, "type", "parsed") && + flipper_format_write_string_cstr(ff, "protocol", protocol_name) && + flipper_format_write_hex(ff, "address", (uint8_t*)&message->address, 4) && + flipper_format_write_hex(ff, "command", (uint8_t*)&message->command, 4); +} + +static inline bool infrared_signal_save_raw(InfraredRawSignal* raw, FlipperFormat* ff) { + furi_assert(raw->timings_size <= MAX_TIMINGS_AMOUNT); + return flipper_format_write_string_cstr(ff, "type", "raw") && + flipper_format_write_uint32(ff, "frequency", &raw->frequency, 1) && + flipper_format_write_float(ff, "duty_cycle", &raw->duty_cycle, 1) && + flipper_format_write_uint32(ff, "data", raw->timings, raw->timings_size); +} + +static inline bool infrared_signal_read_message(InfraredSignal* signal, FlipperFormat* ff) { + string_t buf; + string_init(buf); + bool success = false; + + do { + if(!flipper_format_read_string(ff, "protocol", buf)) break; + + InfraredMessage message; + message.protocol = infrared_get_protocol_by_name(string_get_cstr(buf)); + + success = flipper_format_read_hex(ff, "address", (uint8_t*)&message.address, 4) && + flipper_format_read_hex(ff, "command", (uint8_t*)&message.command, 4) && + infrared_signal_is_message_valid(&message); + + if(!success) break; + + infrared_signal_set_message(signal, &message); + } while(0); + + string_clear(buf); + return success; +} + +static inline bool infrared_signal_read_raw(InfraredSignal* signal, FlipperFormat* ff) { + uint32_t timings_size, frequency; + float duty_cycle; + + bool success = flipper_format_read_uint32(ff, "frequency", &frequency, 1) && + flipper_format_read_float(ff, "duty_cycle", &duty_cycle, 1) && + flipper_format_get_value_count(ff, "data", &timings_size); + + if(!success || timings_size > MAX_TIMINGS_AMOUNT) { + return false; + } + + uint32_t* timings = malloc(sizeof(uint32_t) * timings_size); + success = flipper_format_read_uint32(ff, "data", timings, timings_size); + + if(success) { + infrared_signal_set_raw_signal(signal, timings, timings_size, frequency, duty_cycle); + } + + free(timings); + return success; +} + +InfraredSignal* infrared_signal_alloc() { + InfraredSignal* signal = malloc(sizeof(InfraredSignal)); + + signal->is_raw = false; + signal->payload.message.protocol = InfraredProtocolUnknown; + + return signal; +} + +void infrared_signal_free(InfraredSignal* signal) { + infrared_signal_clear_timings(signal); + free(signal); +} + +bool infrared_signal_is_raw(InfraredSignal* signal) { + return signal->is_raw; +} + +bool infrared_signal_is_valid(InfraredSignal* signal) { + return signal->is_raw ? infrared_signal_is_raw_valid(&signal->payload.raw) : + infrared_signal_is_message_valid(&signal->payload.message); +} + +void infrared_signal_set_signal(InfraredSignal* signal, const InfraredSignal* other) { + if(other->is_raw) { + const InfraredRawSignal* raw = &other->payload.raw; + infrared_signal_set_raw_signal( + signal, raw->timings, raw->timings_size, raw->frequency, raw->duty_cycle); + } else { + const InfraredMessage* message = &other->payload.message; + infrared_signal_set_message(signal, message); + } +} + +void infrared_signal_set_raw_signal( + InfraredSignal* signal, + const uint32_t* timings, + size_t timings_size, + uint32_t frequency, + float duty_cycle) { + infrared_signal_clear_timings(signal); + + signal->is_raw = true; + + signal->payload.raw.timings_size = timings_size; + signal->payload.raw.frequency = frequency; + signal->payload.raw.duty_cycle = duty_cycle; + + signal->payload.raw.timings = malloc(timings_size * sizeof(uint32_t)); + memcpy(signal->payload.raw.timings, timings, timings_size * sizeof(uint32_t)); +} + +InfraredRawSignal* infrared_signal_get_raw_signal(InfraredSignal* signal) { + furi_assert(signal->is_raw); + return &signal->payload.raw; +} + +void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* message) { + infrared_signal_clear_timings(signal); + + signal->is_raw = false; + signal->payload.message = *message; +} + +InfraredMessage* infrared_signal_get_message(InfraredSignal* signal) { + furi_assert(!signal->is_raw); + return &signal->payload.message; +} + +bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name) { + if(!flipper_format_write_comment_cstr(ff, "") || + !flipper_format_write_string_cstr(ff, "name", name)) { + return false; + } else if(signal->is_raw) { + return infrared_signal_save_raw(&signal->payload.raw, ff); + } else { + return infrared_signal_save_message(&signal->payload.message, ff); + } +} + +bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name) { + string_t buf; + string_init(buf); + bool success = false; + + do { + if(!flipper_format_read_string(ff, "name", buf)) break; + string_set(name, buf); + if(!flipper_format_read_string(ff, "type", buf)) break; + if(!string_cmp_str(buf, "raw")) { + success = infrared_signal_read_raw(signal, ff); + } else if(!string_cmp_str(buf, "parsed")) { + success = infrared_signal_read_message(signal, ff); + } else { + FURI_LOG_E(TAG, "Unknown type of signal (allowed - raw/parsed) "); + } + } while(0); + + string_clear(buf); + return success; +} + +void infrared_signal_transmit(InfraredSignal* signal) { + if(signal->is_raw) { + InfraredRawSignal* raw_signal = &signal->payload.raw; + infrared_send_raw_ext( + raw_signal->timings, + raw_signal->timings_size, + true, + raw_signal->frequency, + raw_signal->duty_cycle); + } else { + InfraredMessage* message = &signal->payload.message; + infrared_send(message, 1); + } +} diff --git a/applications/infrared/infrared_signal.h b/applications/infrared/infrared_signal.h new file mode 100644 index 00000000..2dbaa75f --- /dev/null +++ b/applications/infrared/infrared_signal.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include + +#include +#include + +typedef struct InfraredSignal InfraredSignal; + +typedef struct { + size_t timings_size; + uint32_t* timings; + uint32_t frequency; + float duty_cycle; +} InfraredRawSignal; + +InfraredSignal* infrared_signal_alloc(); +void infrared_signal_free(InfraredSignal* signal); + +bool infrared_signal_is_raw(InfraredSignal* signal); +bool infrared_signal_is_valid(InfraredSignal* signal); + +void infrared_signal_set_signal(InfraredSignal* signal, const InfraredSignal* other); + +void infrared_signal_set_raw_signal( + InfraredSignal* signal, + const uint32_t* timings, + size_t timings_size, + uint32_t frequency, + float duty_cycle); +InfraredRawSignal* infrared_signal_get_raw_signal(InfraredSignal* signal); + +void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* message); +InfraredMessage* infrared_signal_get_message(InfraredSignal* signal); + +bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name); +bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name); + +void infrared_signal_transmit(InfraredSignal* signal); diff --git a/applications/infrared/scene/infrared_app_scene.h b/applications/infrared/scene/infrared_app_scene.h deleted file mode 100644 index 9c2e20e9..00000000 --- a/applications/infrared/scene/infrared_app_scene.h +++ /dev/null @@ -1,305 +0,0 @@ -/** - * @file infrared_app_scene.h - * Infrared: Application scenes - */ -#pragma once -#include "../infrared_app_event.h" -#include -#include "infrared.h" -#include -#include -#include "../infrared_app_brute_force.h" - -/** Anonymous class */ -class InfraredApp; - -/** Base Scene class */ -class InfraredAppScene { -public: - /** Called when enter scene */ - virtual void on_enter(InfraredApp* app) = 0; - /** Events handler callback */ - virtual bool on_event(InfraredApp* app, InfraredAppEvent* event) = 0; - /** Called when exit scene */ - virtual void on_exit(InfraredApp* app) = 0; - /** Virtual destructor of base class */ - virtual ~InfraredAppScene(){}; - -private: -}; - -/** Start scene - * Main Infrared application menu - */ -class InfraredAppSceneStart : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Save previously selected submenu index - * to highlight it when get back */ - uint32_t submenu_item_selected = 0; -}; - -/** Universal menu scene - * Scene to select universal remote - */ -class InfraredAppSceneUniversal : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Save previously selected submenu index - * to highlight it when get back */ - uint32_t submenu_item_selected = 0; -}; - -/** Learn new signal scene - * On this scene catching new IR signal performed. - */ -class InfraredAppSceneLearn : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -/** New signal learn succeeded scene - */ -class InfraredAppSceneLearnSuccess : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - bool button_pressed = false; -}; - -/** Scene to enter name for new button in remote - */ -class InfraredAppSceneLearnEnterName : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -/** Scene where signal is learnt - */ -class InfraredAppSceneLearnDone : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -/** Remote interface scene - * On this scene you can send IR signals from selected remote - */ -class InfraredAppSceneRemote : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** container of button names in current remote. */ - std::vector buttons_names; - /** Save previously selected index - * to highlight it when get back */ - uint32_t buttonmenu_item_selected = 0; - /** state flag to show button is pressed. - * As long as send-signal button pressed no other button - * events are handled. */ - bool button_pressed = false; -}; - -/** List of remotes scene - * Every remote is a file, located on internal/external storage. - * Every file has same format, and same extension. - * Files are parsed as you enter 'Remote scene' and showed - * as a buttons. - */ -class InfraredAppSceneRemoteList : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Save previously selected index - * to highlight it when get back */ - uint32_t submenu_item_selected = 0; - /** Remote names to show them in submenu */ - std::vector remote_names; -}; - -class InfraredAppSceneAskBack : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneEdit : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Save previously selected index - * to highlight it when get back */ - uint32_t submenu_item_selected = 0; -}; - -class InfraredAppSceneEditKeySelect : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Button names to show them in submenu */ - std::vector buttons_names; -}; - -class InfraredAppSceneEditRename : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneEditDelete : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneEditRenameDone : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneEditDeleteDone : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneUniversalCommon : public InfraredAppScene { - /** Brute force started flag */ - bool brute_force_started = false; - -protected: - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - - /** Show popup window - * - * @param app - application instance - */ - void show_popup(InfraredApp* app, int record_amount); - - /** Hide popup window - * - * @param app - application instance - */ - void hide_popup(InfraredApp* app); - - /** Propagate progress in popup window - * - * @param app - application instance - */ - bool progress_popup(InfraredApp* app); - - /** Item selected callback - * - * @param context - context - * @param index - selected item index - */ - static void infrared_app_item_callback(void* context, uint32_t index); - - /** Brute Force instance */ - InfraredAppBruteForce brute_force; - - /** Constructor */ - InfraredAppSceneUniversalCommon(const char* filename) - : brute_force(filename) { - } - - /** Destructor */ - ~InfraredAppSceneUniversalCommon() { - } -}; - -class InfraredAppSceneUniversalTV : public InfraredAppSceneUniversalCommon { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - - /** Constructor - * Specifies path to brute force db library */ - InfraredAppSceneUniversalTV() - : InfraredAppSceneUniversalCommon("/ext/infrared/assets/tv.ir") { - } - - /** Destructor */ - ~InfraredAppSceneUniversalTV() { - } -}; diff --git a/applications/infrared/scene/infrared_app_scene_ask_back.cpp b/applications/infrared/scene/infrared_app_scene_ask_back.cpp deleted file mode 100644 index 65d7ca57..00000000 --- a/applications/infrared/scene/infrared_app_scene_ask_back.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "../infrared_app.h" -#include "gui/modules/dialog_ex.h" -#include "infrared.h" -#include "infrared/scene/infrared_app_scene.h" -#include - -static void dialog_result_callback(DialogExResult result, void* context) { - auto app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::DialogExSelected; - event.payload.dialog_ex_result = result; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneAskBack::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - - if(app->get_learn_new_remote()) { - dialog_ex_set_header(dialog_ex, "Exit to Infrared menu?", 64, 0, AlignCenter, AlignTop); - } else { - dialog_ex_set_header(dialog_ex, "Exit to remote menu?", 64, 0, AlignCenter, AlignTop); - } - - dialog_ex_set_text( - dialog_ex, "All unsaved data\nwill be lost", 64, 31, AlignCenter, AlignCenter); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, "Exit"); - dialog_ex_set_center_button_text(dialog_ex, nullptr); - dialog_ex_set_right_button_text(dialog_ex, "Stay"); - dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); - dialog_ex_set_context(dialog_ex, app); - - view_manager->switch_to(InfraredAppViewManager::ViewId::DialogEx); -} - -bool InfraredAppSceneAskBack::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::DialogExSelected) { - switch(event->payload.dialog_ex_result) { - case DialogExResultLeft: - consumed = true; - if(app->get_learn_new_remote()) { - app->search_and_switch_to_previous_scene({InfraredApp::Scene::Start}); - } else { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Edit, InfraredApp::Scene::Remote}); - } - break; - case DialogExResultCenter: - furi_assert(0); - break; - case DialogExResultRight: - app->switch_to_previous_scene(); - consumed = true; - break; - default: - break; - } - } - - if(event->type == InfraredAppEvent::Type::Back) { - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneAskBack::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_edit.cpp b/applications/infrared/scene/infrared_app_scene_edit.cpp deleted file mode 100644 index 5a2ae72f..00000000 --- a/applications/infrared/scene/infrared_app_scene_edit.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "../infrared_app.h" -#include "gui/modules/submenu.h" - -typedef enum { - SubmenuIndexAddKey, - SubmenuIndexRenameKey, - SubmenuIndexDeleteKey, - SubmenuIndexRenameRemote, - SubmenuIndexDeleteRemote, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::MenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneEdit::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item(submenu, "Add Button", SubmenuIndexAddKey, submenu_callback, app); - submenu_add_item(submenu, "Rename Button", SubmenuIndexRenameKey, submenu_callback, app); - submenu_add_item(submenu, "Delete Button", SubmenuIndexDeleteKey, submenu_callback, app); - submenu_add_item(submenu, "Rename Remote", SubmenuIndexRenameRemote, submenu_callback, app); - submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app); - submenu_set_selected_item(submenu, submenu_item_selected); - submenu_item_selected = 0; - - view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu); -} - -bool InfraredAppSceneEdit::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuIndexAddKey: - app->set_learn_new_remote(false); - app->switch_to_next_scene(InfraredApp::Scene::Learn); - break; - case SubmenuIndexRenameKey: - app->set_edit_action(InfraredApp::EditAction::Rename); - app->set_edit_element(InfraredApp::EditElement::Button); - app->switch_to_next_scene(InfraredApp::Scene::EditKeySelect); - break; - case SubmenuIndexDeleteKey: - app->set_edit_action(InfraredApp::EditAction::Delete); - app->set_edit_element(InfraredApp::EditElement::Button); - app->switch_to_next_scene(InfraredApp::Scene::EditKeySelect); - break; - case SubmenuIndexRenameRemote: - app->set_edit_action(InfraredApp::EditAction::Rename); - app->set_edit_element(InfraredApp::EditElement::Remote); - app->switch_to_next_scene(InfraredApp::Scene::EditRename); - break; - case SubmenuIndexDeleteRemote: - app->set_edit_action(InfraredApp::EditAction::Delete); - app->set_edit_element(InfraredApp::EditElement::Remote); - app->switch_to_next_scene(InfraredApp::Scene::EditDelete); - break; - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneEdit::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_delete.cpp b/applications/infrared/scene/infrared_app_scene_edit_delete.cpp deleted file mode 100644 index e17cfee0..00000000 --- a/applications/infrared/scene/infrared_app_scene_edit_delete.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "../infrared_app.h" -#include "infrared.h" -#include "infrared/scene/infrared_app_scene.h" -#include - -static void dialog_result_callback(DialogExResult result, void* context) { - auto app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::DialogExSelected; - event.payload.dialog_ex_result = result; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneEditDelete::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - - auto remote_manager = app->get_remote_manager(); - - if(app->get_edit_element() == InfraredApp::EditElement::Button) { - auto signal = remote_manager->get_button_data(app->get_current_button()); - dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop); - if(!signal.is_raw()) { - auto message = &signal.get_message(); - app->set_text_store( - 0, - "%s\n%s\nA=0x%0*lX C=0x%0*lX", - remote_manager->get_button_name(app->get_current_button()).c_str(), - infrared_get_protocol_name(message->protocol), - ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), - message->address, - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), - message->command); - } else { - app->set_text_store( - 0, - "%s\nRAW\n%ld samples", - remote_manager->get_button_name(app->get_current_button()).c_str(), - signal.get_raw_signal().timings_cnt); - } - } else { - dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 0, AlignCenter, AlignTop); - app->set_text_store( - 0, - "%s\n with %lu buttons", - remote_manager->get_remote_name().c_str(), - remote_manager->get_number_of_buttons()); - } - - dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, "Cancel"); - dialog_ex_set_right_button_text(dialog_ex, "Delete"); - dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); - dialog_ex_set_context(dialog_ex, app); - - view_manager->switch_to(InfraredAppViewManager::ViewId::DialogEx); -} - -bool InfraredAppSceneEditDelete::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::DialogExSelected) { - switch(event->payload.dialog_ex_result) { - case DialogExResultLeft: - app->switch_to_previous_scene(); - break; - case DialogExResultCenter: - furi_assert(0); - break; - case DialogExResultRight: { - auto remote_manager = app->get_remote_manager(); - bool result = false; - if(app->get_edit_element() == InfraredApp::EditElement::Remote) { - result = remote_manager->delete_remote(); - } else { - result = remote_manager->delete_button(app->get_current_button()); - app->set_current_button(InfraredApp::ButtonNA); - } - - if(!result) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::RemoteList, InfraredApp::Scene::Start}); - } else { - app->switch_to_next_scene(InfraredApp::Scene::EditDeleteDone); - } - break; - } - default: - break; - } - } - - return consumed; -} - -void InfraredAppSceneEditDelete::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_delete_done.cpp b/applications/infrared/scene/infrared_app_scene_edit_delete_done.cpp deleted file mode 100644 index 3f9800e1..00000000 --- a/applications/infrared/scene/infrared_app_scene_edit_delete_done.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "../infrared_app.h" - -void InfraredAppSceneEditDeleteDone::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - - popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); - - popup_set_callback(popup, InfraredApp::popup_callback); - popup_set_context(popup, app); - popup_set_timeout(popup, 1500); - popup_enable_timeout(popup); - - view_manager->switch_to(InfraredAppViewManager::ViewId::Popup); -} - -bool InfraredAppSceneEditDeleteDone::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::PopupTimer) { - if(app->get_edit_element() == InfraredApp::EditElement::Remote) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList}); - } else { - app->search_and_switch_to_previous_scene({InfraredApp::Scene::Remote}); - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneEditDeleteDone::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop); -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp b/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp deleted file mode 100644 index 49142c21..00000000 --- a/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "../infrared_app.h" -#include "gui/modules/submenu.h" - -static void submenu_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::MenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneEditKeySelect::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - int item_number = 0; - - const char* header = app->get_edit_action() == InfraredApp::EditAction::Rename ? - "Rename Button:" : - "Delete Button:"; - submenu_set_header(submenu, header); - - auto remote_manager = app->get_remote_manager(); - buttons_names = remote_manager->get_button_list(); - for(const auto& it : buttons_names) { - submenu_add_item(submenu, it.c_str(), item_number++, submenu_callback, app); - } - if((item_number > 0) && (app->get_current_button() != InfraredApp::ButtonNA)) { - submenu_set_selected_item(submenu, app->get_current_button()); - app->set_current_button(InfraredApp::ButtonNA); - } - - view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu); -} - -bool InfraredAppSceneEditKeySelect::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::MenuSelected) { - app->set_current_button(event->payload.menu_index); - consumed = true; - if(app->get_edit_action() == InfraredApp::EditAction::Rename) { - app->switch_to_next_scene(InfraredApp::Scene::EditRename); - } else { - app->switch_to_next_scene(InfraredApp::Scene::EditDelete); - } - } - - return consumed; -} - -void InfraredAppSceneEditKeySelect::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_rename.cpp b/applications/infrared/scene/infrared_app_scene_edit_rename.cpp deleted file mode 100644 index 761da49f..00000000 --- a/applications/infrared/scene/infrared_app_scene_edit_rename.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "../infrared_app.h" -#include "m-string.h" -#include "toolbox/path.h" - -void InfraredAppSceneEditRename::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - TextInput* text_input = view_manager->get_text_input(); - size_t enter_name_length = 0; - - auto remote_manager = app->get_remote_manager(); - if(app->get_edit_element() == InfraredApp::EditElement::Button) { - furi_assert(app->get_current_button() != InfraredApp::ButtonNA); - auto button_name = remote_manager->get_button_name(app->get_current_button()); - char* buffer_str = app->get_text_store(0); - size_t max_len = InfraredAppRemoteManager::max_button_name_length; - strncpy(buffer_str, button_name.c_str(), max_len); - buffer_str[max_len + 1] = 0; - enter_name_length = max_len; - text_input_set_header_text(text_input, "Name the button"); - } else { - auto remote_name = remote_manager->get_remote_name(); - strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size()); - enter_name_length = InfraredAppRemoteManager::max_remote_name_length; - text_input_set_header_text(text_input, "Name the remote"); - - string_t folder_path; - string_init(folder_path); - - if(string_end_with_str_p(app->file_path, InfraredApp::infrared_extension)) { - path_extract_dirname(string_get_cstr(app->file_path), folder_path); - } - - ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( - string_get_cstr(folder_path), app->infrared_extension, remote_name.c_str()); - text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); - - string_clear(folder_path); - } - - text_input_set_result_callback( - text_input, - InfraredApp::text_input_callback, - app, - app->get_text_store(0), - enter_name_length, - false); - - view_manager->switch_to(InfraredAppViewManager::ViewId::TextInput); -} - -bool InfraredAppSceneEditRename::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::TextEditDone) { - auto remote_manager = app->get_remote_manager(); - bool result = false; - if(app->get_edit_element() == InfraredApp::EditElement::Button) { - result = - remote_manager->rename_button(app->get_current_button(), app->get_text_store(0)); - app->set_current_button(InfraredApp::ButtonNA); - } else { - result = remote_manager->rename_remote(app->get_text_store(0)); - } - if(!result) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList}); - } else { - app->switch_to_next_scene_without_saving(InfraredApp::Scene::EditRenameDone); - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneEditRename::on_exit(InfraredApp* app) { - TextInput* text_input = app->get_view_manager()->get_text_input(); - - void* validator_context = text_input_get_validator_callback_context(text_input); - text_input_set_validator(text_input, NULL, NULL); - - if(validator_context != NULL) validator_is_file_free((ValidatorIsFile*)validator_context); -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_rename_done.cpp b/applications/infrared/scene/infrared_app_scene_edit_rename_done.cpp deleted file mode 100644 index 803481f6..00000000 --- a/applications/infrared/scene/infrared_app_scene_edit_rename_done.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "../infrared_app.h" - -void InfraredAppSceneEditRenameDone::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); - - popup_set_callback(popup, InfraredApp::popup_callback); - popup_set_context(popup, app); - popup_set_timeout(popup, 1500); - popup_enable_timeout(popup); - - view_manager->switch_to(InfraredAppViewManager::ViewId::Popup); -} - -bool InfraredAppSceneEditRenameDone::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::PopupTimer) { - app->switch_to_next_scene(InfraredApp::Scene::Remote); - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneEditRenameDone::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_learn.cpp b/applications/infrared/scene/infrared_app_scene_learn.cpp deleted file mode 100644 index 3ad152cf..00000000 --- a/applications/infrared/scene/infrared_app_scene_learn.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "../infrared_app.h" -#include "../infrared_app_event.h" -#include "infrared.h" -#include - -static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { - furi_assert(context); - furi_assert(received_signal); - - InfraredApp* app = static_cast(context); - - if(infrared_worker_signal_is_decoded(received_signal)) { - InfraredAppSignal signal(infrared_worker_get_decoded_signal(received_signal)); - app->set_received_signal(signal); - } else { - const uint32_t* timings; - size_t timings_cnt; - infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt); - InfraredAppSignal signal( - timings, timings_cnt, INFRARED_COMMON_CARRIER_FREQUENCY, INFRARED_COMMON_DUTY_CYCLE); - app->set_received_signal(signal); - } - - infrared_worker_rx_set_received_signal_callback(app->get_infrared_worker(), NULL, NULL); - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::InfraredMessageReceived; - auto view_manager = app->get_view_manager(); - view_manager->send_event(&event); -} - -void InfraredAppSceneLearn::on_enter(InfraredApp* app) { - auto view_manager = app->get_view_manager(); - auto popup = view_manager->get_popup(); - - auto worker = app->get_infrared_worker(); - infrared_worker_rx_set_received_signal_callback(worker, signal_received_callback, app); - infrared_worker_rx_start(worker); - - popup_set_icon(popup, 0, 32, &I_InfraredLearnShort_128x31); - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignCenter); - popup_set_text( - popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter); - popup_set_callback(popup, NULL); - - view_manager->switch_to(InfraredAppViewManager::ViewId::Popup); -} - -bool InfraredAppSceneLearn::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - switch(event->type) { - case InfraredAppEvent::Type::Tick: - consumed = true; - app->notify_blink_read(); - break; - case InfraredAppEvent::Type::InfraredMessageReceived: - app->notify_success(); - app->switch_to_next_scene_without_saving(InfraredApp::Scene::LearnSuccess); - break; - case InfraredAppEvent::Type::Back: - consumed = true; - app->switch_to_previous_scene(); - break; - default: - furi_assert(0); - } - - return consumed; -} - -void InfraredAppSceneLearn::on_exit(InfraredApp* app) { - infrared_worker_rx_stop(app->get_infrared_worker()); - auto view_manager = app->get_view_manager(); - auto popup = view_manager->get_popup(); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter); -} diff --git a/applications/infrared/scene/infrared_app_scene_learn_done.cpp b/applications/infrared/scene/infrared_app_scene_learn_done.cpp deleted file mode 100644 index 6ee13b43..00000000 --- a/applications/infrared/scene/infrared_app_scene_learn_done.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "../infrared_app.h" -#include - -void InfraredAppSceneLearnDone::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - DOLPHIN_DEED(DolphinDeedIrSave); - - if(app->get_learn_new_remote()) { - popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); - } else { - popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); - } - - popup_set_callback(popup, InfraredApp::popup_callback); - popup_set_context(popup, app); - popup_set_timeout(popup, 1500); - popup_enable_timeout(popup); - - view_manager->switch_to(InfraredAppViewManager::ViewId::Popup); -} - -bool InfraredAppSceneLearnDone::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::PopupTimer) { - app->switch_to_next_scene(InfraredApp::Scene::Remote); - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneLearnDone::on_exit(InfraredApp* app) { - app->set_learn_new_remote(false); - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop); -} diff --git a/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp b/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp deleted file mode 100644 index 7d15a7c5..00000000 --- a/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "../infrared_app.h" -#include "gui/modules/text_input.h" - -void InfraredAppSceneLearnEnterName::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - TextInput* text_input = view_manager->get_text_input(); - - auto signal = app->get_received_signal(); - - if(!signal.is_raw()) { - auto message = &signal.get_message(); - app->set_text_store( - 0, - "%.4s_%0*lX", - infrared_get_protocol_name(message->protocol), - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), - message->command); - } else { - auto raw_signal = signal.get_raw_signal(); - app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt); - } - - text_input_set_header_text(text_input, "Name the button"); - text_input_set_result_callback( - text_input, - InfraredApp::text_input_callback, - app, - app->get_text_store(0), - InfraredAppRemoteManager::max_button_name_length, - true); - - view_manager->switch_to(InfraredAppViewManager::ViewId::TextInput); -} - -bool InfraredAppSceneLearnEnterName::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::TextEditDone) { - auto remote_manager = app->get_remote_manager(); - bool result = false; - if(app->get_learn_new_remote()) { - result = remote_manager->add_remote_with_button( - app->get_text_store(0), app->get_received_signal()); - } else { - result = - remote_manager->add_button(app->get_text_store(0), app->get_received_signal()); - } - - if(!result) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList}); - } else { - app->switch_to_next_scene_without_saving(InfraredApp::Scene::LearnDone); - } - } - return consumed; -} - -void InfraredAppSceneLearnEnterName::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_learn_success.cpp b/applications/infrared/scene/infrared_app_scene_learn_success.cpp deleted file mode 100644 index a7f7c4cd..00000000 --- a/applications/infrared/scene/infrared_app_scene_learn_success.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include - -#include "../infrared_app.h" -#include "infrared.h" - -static void dialog_result_callback(DialogExResult result, void* context) { - auto app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::DialogExSelected; - event.payload.dialog_ex_result = result; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneLearnSuccess::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - - DOLPHIN_DEED(DolphinDeedIrLearnSuccess); - app->notify_green_on(); - - infrared_worker_tx_set_get_signal_callback( - app->get_infrared_worker(), infrared_worker_tx_get_signal_steady_callback, app); - infrared_worker_tx_set_signal_sent_callback( - app->get_infrared_worker(), InfraredApp::signal_sent_callback, app); - - auto signal = app->get_received_signal(); - - if(!signal.is_raw()) { - auto message = &signal.get_message(); - uint8_t adr_digits = - ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4); - uint8_t cmd_digits = - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4); - uint8_t max_digits = MAX(adr_digits, cmd_digits); - max_digits = MIN(max_digits, 7); - size_t label_x_offset = 63 + (7 - max_digits) * 3; - - app->set_text_store(0, "%s", infrared_get_protocol_name(message->protocol)); - app->set_text_store( - 1, - "A: 0x%0*lX\nC: 0x%0*lX\n", - adr_digits, - message->address, - cmd_digits, - message->command); - - dialog_ex_set_header(dialog_ex, app->get_text_store(0), 95, 7, AlignCenter, AlignCenter); - dialog_ex_set_text( - dialog_ex, app->get_text_store(1), label_x_offset, 34, AlignLeft, AlignCenter); - } else { - dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); - app->set_text_store(0, "%d samples", signal.get_raw_signal().timings_cnt); - dialog_ex_set_text(dialog_ex, app->get_text_store(0), 75, 23, AlignLeft, AlignTop); - } - - dialog_ex_set_left_button_text(dialog_ex, "Retry"); - dialog_ex_set_right_button_text(dialog_ex, "Save"); - dialog_ex_set_center_button_text(dialog_ex, "Send"); - dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63); - dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); - dialog_ex_set_context(dialog_ex, app); - dialog_ex_enable_extended_events(dialog_ex); - - view_manager->switch_to(InfraredAppViewManager::ViewId::DialogEx); -} - -bool InfraredAppSceneLearnSuccess::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - if(event->type == InfraredAppEvent::Type::Tick) { - /* Send event every tick to suppress any switching off green light */ - if(!button_pressed) { - app->notify_green_on(); - } - } - - if(event->type == InfraredAppEvent::Type::DialogExSelected) { - switch(event->payload.dialog_ex_result) { - case DialogExResultLeft: - consumed = true; - if(!button_pressed) { - app->switch_to_next_scene_without_saving(InfraredApp::Scene::Learn); - } - break; - case DialogExResultRight: { - consumed = true; - if(!button_pressed) { - app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName); - } - break; - } - case DialogExPressCenter: - if(!button_pressed) { - button_pressed = true; - - auto signal = app->get_received_signal(); - if(signal.is_raw()) { - infrared_worker_set_raw_signal( - app->get_infrared_worker(), - signal.get_raw_signal().timings, - signal.get_raw_signal().timings_cnt); - } else { - infrared_worker_set_decoded_signal( - app->get_infrared_worker(), &signal.get_message()); - } - - infrared_worker_tx_start(app->get_infrared_worker()); - } - break; - case DialogExReleaseCenter: - if(button_pressed) { - button_pressed = false; - infrared_worker_tx_stop(app->get_infrared_worker()); - app->notify_green_off(); - } - break; - default: - break; - } - } - - if(event->type == InfraredAppEvent::Type::Back) { - if(!button_pressed) { - app->switch_to_next_scene(InfraredApp::Scene::AskBack); - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneLearnSuccess::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - dialog_ex_reset(dialog_ex); - app->notify_green_off(); - infrared_worker_tx_set_get_signal_callback(app->get_infrared_worker(), nullptr, nullptr); - infrared_worker_tx_set_signal_sent_callback(app->get_infrared_worker(), nullptr, nullptr); -} diff --git a/applications/infrared/scene/infrared_app_scene_remote.cpp b/applications/infrared/scene/infrared_app_scene_remote.cpp deleted file mode 100644 index ac87b581..00000000 --- a/applications/infrared/scene/infrared_app_scene_remote.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include -#include -#include -#include "../infrared_app.h" -#include "../infrared_app_view_manager.h" - -typedef enum { - ButtonIndexPlus = -2, - ButtonIndexEdit = -1, - ButtonIndexNA = 0, -} ButtonIndex; - -static void button_menu_callback(void* context, int32_t index, InputType type) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - if(type == InputTypePress) { - event.type = InfraredAppEvent::Type::MenuSelectedPress; - } else if(type == InputTypeRelease) { - event.type = InfraredAppEvent::Type::MenuSelectedRelease; - } else if(type == InputTypeShort) { - event.type = InfraredAppEvent::Type::MenuSelected; - } else { - furi_assert(0); - } - - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneRemote::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonMenu* button_menu = view_manager->get_button_menu(); - auto remote_manager = app->get_remote_manager(); - int i = 0; - button_pressed = false; - - infrared_worker_tx_set_get_signal_callback( - app->get_infrared_worker(), infrared_worker_tx_get_signal_steady_callback, app); - infrared_worker_tx_set_signal_sent_callback( - app->get_infrared_worker(), InfraredApp::signal_sent_callback, app); - buttons_names = remote_manager->get_button_list(); - - i = 0; - for(auto& name : buttons_names) { - button_menu_add_item( - button_menu, name.c_str(), i++, button_menu_callback, ButtonMenuItemTypeCommon, app); - } - - button_menu_add_item( - button_menu, "+", ButtonIndexPlus, button_menu_callback, ButtonMenuItemTypeControl, app); - button_menu_add_item( - button_menu, "Edit", ButtonIndexEdit, button_menu_callback, ButtonMenuItemTypeControl, app); - - app->set_text_store(0, "%s", remote_manager->get_remote_name().c_str()); - button_menu_set_header(button_menu, app->get_text_store(0)); - if(buttonmenu_item_selected != ButtonIndexNA) { - button_menu_set_selected_item(button_menu, buttonmenu_item_selected); - buttonmenu_item_selected = ButtonIndexNA; - } - view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu); -} - -bool InfraredAppSceneRemote::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = true; - - if((event->type == InfraredAppEvent::Type::MenuSelected) || - (event->type == InfraredAppEvent::Type::MenuSelectedPress) || - (event->type == InfraredAppEvent::Type::MenuSelectedRelease)) { - switch(event->payload.menu_index) { - case ButtonIndexPlus: - furi_assert(event->type == InfraredAppEvent::Type::MenuSelected); - buttonmenu_item_selected = event->payload.menu_index; - app->set_learn_new_remote(false); - app->switch_to_next_scene(InfraredApp::Scene::Learn); - break; - case ButtonIndexEdit: - furi_assert(event->type == InfraredAppEvent::Type::MenuSelected); - buttonmenu_item_selected = event->payload.menu_index; - app->switch_to_next_scene(InfraredApp::Scene::Edit); - break; - default: - furi_assert(event->type != InfraredAppEvent::Type::MenuSelected); - bool pressed = (event->type == InfraredAppEvent::Type::MenuSelectedPress); - - if(pressed && !button_pressed) { - button_pressed = true; - - auto button_signal = - app->get_remote_manager()->get_button_data(event->payload.menu_index); - if(button_signal.is_raw()) { - infrared_worker_set_raw_signal( - app->get_infrared_worker(), - button_signal.get_raw_signal().timings, - button_signal.get_raw_signal().timings_cnt); - } else { - infrared_worker_set_decoded_signal( - app->get_infrared_worker(), &button_signal.get_message()); - } - - DOLPHIN_DEED(DolphinDeedIrSend); - infrared_worker_tx_start(app->get_infrared_worker()); - } else if(!pressed && button_pressed) { - button_pressed = false; - infrared_worker_tx_stop(app->get_infrared_worker()); - app->notify_green_off(); - } - break; - } - } else if(event->type == InfraredAppEvent::Type::Back) { - if(!button_pressed) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList}); - } - } else { - consumed = false; - } - - return consumed; -} - -void InfraredAppSceneRemote::on_exit(InfraredApp* app) { - infrared_worker_tx_set_get_signal_callback(app->get_infrared_worker(), nullptr, nullptr); - infrared_worker_tx_set_signal_sent_callback(app->get_infrared_worker(), nullptr, nullptr); - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonMenu* button_menu = view_manager->get_button_menu(); - - button_menu_reset(button_menu); -} diff --git a/applications/infrared/scene/infrared_app_scene_remote_list.cpp b/applications/infrared/scene/infrared_app_scene_remote_list.cpp deleted file mode 100644 index c72acb6e..00000000 --- a/applications/infrared/scene/infrared_app_scene_remote_list.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "../infrared_app.h" -#include "assets_icons.h" -#include "infrared/infrared_app_event.h" -#include - -void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) { - furi_assert(app); - - bool result = false; - bool file_select_result; - auto remote_manager = app->get_remote_manager(); - DialogsApp* dialogs = app->get_dialogs(); - - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonMenu* button_menu = view_manager->get_button_menu(); - button_menu_reset(button_menu); - view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu); - - file_select_result = dialog_file_browser_show( - dialogs, - app->file_path, - app->file_path, - InfraredApp::infrared_extension, - true, - &I_ir_10px, - true); - - if(file_select_result) { - if(remote_manager->load(app->file_path)) { - app->switch_to_next_scene(InfraredApp::Scene::Remote); - result = true; - } - } - - if(!result) { - app->switch_to_previous_scene(); - } -} - -bool InfraredAppSceneRemoteList::on_event(InfraredApp*, InfraredAppEvent*) { - return false; -} - -void InfraredAppSceneRemoteList::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_start.cpp b/applications/infrared/scene/infrared_app_scene_start.cpp deleted file mode 100644 index 5efdce7a..00000000 --- a/applications/infrared/scene/infrared_app_scene_start.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "../infrared_app.h" - -typedef enum { - SubmenuIndexUniversalLibrary, - SubmenuIndexLearnNewRemote, - SubmenuIndexSavedRemotes, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::MenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneStart::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item( - submenu, "Universal Library", SubmenuIndexUniversalLibrary, submenu_callback, app); - submenu_add_item( - submenu, "Learn New Remote", SubmenuIndexLearnNewRemote, submenu_callback, app); - submenu_add_item(submenu, "Saved Remotes", SubmenuIndexSavedRemotes, submenu_callback, app); - submenu_set_selected_item(submenu, submenu_item_selected); - - string_set_str(app->file_path, InfraredApp::infrared_directory); - submenu_item_selected = 0; - - view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu); -} - -bool InfraredAppSceneStart::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuIndexUniversalLibrary: - app->switch_to_next_scene(InfraredApp::Scene::Universal); - break; - case SubmenuIndexLearnNewRemote: - app->set_learn_new_remote(true); - app->switch_to_next_scene(InfraredApp::Scene::Learn); - break; - case SubmenuIndexSavedRemotes: - app->switch_to_next_scene(InfraredApp::Scene::RemoteList); - break; - default: - furi_assert(0); - break; - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneStart::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - app->get_remote_manager()->reset_remote(); - submenu_reset(submenu); -} diff --git a/applications/infrared/scene/infrared_app_scene_universal.cpp b/applications/infrared/scene/infrared_app_scene_universal.cpp deleted file mode 100644 index 57b5653a..00000000 --- a/applications/infrared/scene/infrared_app_scene_universal.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "../infrared_app.h" - -typedef enum { - SubmenuIndexUniversalTV, - SubmenuIndexUniversalAudio, - SubmenuIndexUniversalAirConditioner, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::MenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneUniversal::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item(submenu, "TVs", SubmenuIndexUniversalTV, submenu_callback, app); - submenu_set_selected_item(submenu, submenu_item_selected); - submenu_item_selected = 0; - - view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu); -} - -bool InfraredAppSceneUniversal::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuIndexUniversalTV: - app->switch_to_next_scene(InfraredApp::Scene::UniversalTV); - break; - case SubmenuIndexUniversalAudio: - // app->switch_to_next_scene(InfraredApp::Scene::UniversalAudio); - break; - case SubmenuIndexUniversalAirConditioner: - // app->switch_to_next_scene(InfraredApp::Scene::UniversalAirConditioner); - break; - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneUniversal::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/infrared/scene/infrared_app_scene_universal_common.cpp b/applications/infrared/scene/infrared_app_scene_universal_common.cpp deleted file mode 100644 index 9e7a18f4..00000000 --- a/applications/infrared/scene/infrared_app_scene_universal_common.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include -#include -#include -#include - -#include "../infrared_app.h" -#include "infrared/infrared_app_event.h" -#include "infrared/infrared_app_view_manager.h" -#include "infrared/scene/infrared_app_scene.h" -#include "../view/infrared_progress_view.h" - -void InfraredAppSceneUniversalCommon::infrared_app_item_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::ButtonPanelPressed; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -static void infrared_progress_back_callback(void* context) { - furi_assert(context); - auto app = static_cast(context); - - InfraredAppEvent infrared_event = { - .payload = {.dummy = 0}, - .type = InfraredAppEvent::Type::Back, - }; - app->get_view_manager()->clear_events(); - app->get_view_manager()->send_event(&infrared_event); -} - -void InfraredAppSceneUniversalCommon::hide_popup(InfraredApp* app) { - auto stack_view = app->get_view_manager()->get_universal_view_stack(); - auto progress_view = app->get_view_manager()->get_progress(); - view_stack_remove_view(stack_view, infrared_progress_view_get_view(progress_view)); -} - -void InfraredAppSceneUniversalCommon::show_popup(InfraredApp* app, int record_amount) { - auto stack_view = app->get_view_manager()->get_universal_view_stack(); - auto progress_view = app->get_view_manager()->get_progress(); - infrared_progress_view_set_progress_total(progress_view, record_amount); - infrared_progress_view_set_back_callback(progress_view, infrared_progress_back_callback, app); - view_stack_add_view(stack_view, infrared_progress_view_get_view(progress_view)); -} - -bool InfraredAppSceneUniversalCommon::progress_popup(InfraredApp* app) { - auto progress_view = app->get_view_manager()->get_progress(); - return infrared_progress_view_increase_progress(progress_view); -} - -bool InfraredAppSceneUniversalCommon::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(brute_force_started) { - if(event->type == InfraredAppEvent::Type::Tick) { - auto view_manager = app->get_view_manager(); - app->notify_blink_send(); - InfraredAppEvent tick_event = { - .payload = {.dummy = 0}, - .type = InfraredAppEvent::Type::Tick, - }; - view_manager->send_event(&tick_event); - bool result = brute_force.send_next_bruteforce(); - if(result) { - result = progress_popup(app); - } - if(!result) { - brute_force.stop_bruteforce(); - brute_force_started = false; - hide_popup(app); - } - consumed = true; - } else if(event->type == InfraredAppEvent::Type::Back) { - brute_force_started = false; - brute_force.stop_bruteforce(); - hide_popup(app); - consumed = true; - } - } else { - if(event->type == InfraredAppEvent::Type::ButtonPanelPressed) { - int record_amount = 0; - if(brute_force.start_bruteforce(event->payload.menu_index, record_amount)) { - DOLPHIN_DEED(DolphinDeedIrBruteForce); - brute_force_started = true; - show_popup(app, record_amount); - app->notify_blink_send(); - } else { - app->switch_to_previous_scene(); - } - consumed = true; - } else if(event->type == InfraredAppEvent::Type::Back) { - app->switch_to_previous_scene(); - consumed = true; - } - } - - return consumed; -} - -void InfraredAppSceneUniversalCommon::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonPanel* button_panel = view_manager->get_button_panel(); - button_panel_reset(button_panel); -} diff --git a/applications/infrared/scene/infrared_app_scene_universal_tv.cpp b/applications/infrared/scene/infrared_app_scene_universal_tv.cpp deleted file mode 100644 index a12481ec..00000000 --- a/applications/infrared/scene/infrared_app_scene_universal_tv.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include -#include -#include -#include "infrared/scene/infrared_app_scene.h" -#include "infrared/infrared_app.h" - -void InfraredAppSceneUniversalTV::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonPanel* button_panel = view_manager->get_button_panel(); - button_panel_reserve(button_panel, 2, 3); - - int i = 0; - button_panel_add_item( - button_panel, - i, - 0, - 0, - 3, - 19, - &I_Power_25x27, - &I_Power_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "POWER"); - ++i; - button_panel_add_item( - button_panel, - i, - 1, - 0, - 36, - 19, - &I_Mute_25x27, - &I_Mute_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "MUTE"); - ++i; - button_panel_add_item( - button_panel, - i, - 0, - 1, - 3, - 66, - &I_Vol_up_25x27, - &I_Vol_up_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "VOL+"); - ++i; - button_panel_add_item( - button_panel, - i, - 1, - 1, - 36, - 66, - &I_Up_25x27, - &I_Up_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "CH+"); - ++i; - button_panel_add_item( - button_panel, - i, - 0, - 2, - 3, - 98, - &I_Vol_down_25x27, - &I_Vol_down_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "VOL-"); - ++i; - button_panel_add_item( - button_panel, - i, - 1, - 2, - 36, - 98, - &I_Down_25x27, - &I_Down_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "CH-"); - - button_panel_add_label(button_panel, 6, 11, FontPrimary, "TV remote"); - button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol"); - button_panel_add_label(button_panel, 43, 64, FontSecondary, "Ch"); - - view_manager->switch_to(InfraredAppViewManager::ViewId::UniversalRemote); - - auto stack_view = app->get_view_manager()->get_universal_view_stack(); - auto loading_view = app->get_view_manager()->get_loading(); - view_stack_add_view(stack_view, loading_get_view(loading_view)); - - /** - * Problem: Update events are not handled in Loading View, because: - * 1) Timer task has least prio - * 2) Storage service uses drivers that capture whole CPU time - * to handle SD communication - * - * Ugly workaround, but it works for current situation: - * raise timer task prio for DB scanning period. - */ - TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); - TaskHandle_t storage_task = xTaskGetHandle("StorageSrv"); - uint32_t timer_prio = uxTaskPriorityGet(timer_task); - uint32_t storage_prio = uxTaskPriorityGet(storage_task); - vTaskPrioritySet(timer_task, storage_prio + 1); - bool result = brute_force.calculate_messages(); - vTaskPrioritySet(timer_task, timer_prio); - - view_stack_remove_view(stack_view, loading_get_view(loading_view)); - - if(!result) { - app->switch_to_previous_scene(); - } -} diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.c b/applications/infrared/scenes/common/infrared_scene_universal_common.c new file mode 100644 index 00000000..f0e69030 --- /dev/null +++ b/applications/infrared/scenes/common/infrared_scene_universal_common.c @@ -0,0 +1,92 @@ +#include "../../infrared_i.h" + +#include + +void infrared_scene_universal_common_item_callback(void* context, uint32_t index) { + Infrared* infrared = context; + uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeButtonSelected, index); + view_dispatcher_send_custom_event(infrared->view_dispatcher, event); +} + +static void infrared_scene_universal_common_progress_back_callback(void* context) { + Infrared* infrared = context; + uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeBackPressed, -1); + view_dispatcher_send_custom_event(infrared->view_dispatcher, event); +} + +static void infrared_scene_universal_common_show_popup(Infrared* infrared, uint32_t record_count) { + ViewStack* view_stack = infrared->view_stack; + InfraredProgressView* progress = infrared->progress; + infrared_progress_view_set_progress_total(progress, record_count); + infrared_progress_view_set_back_callback( + progress, infrared_scene_universal_common_progress_back_callback, infrared); + view_stack_add_view(view_stack, infrared_progress_view_get_view(progress)); +} + +static void infrared_scene_universal_common_hide_popup(Infrared* infrared) { + ViewStack* view_stack = infrared->view_stack; + InfraredProgressView* progress = infrared->progress; + view_stack_remove_view(view_stack, infrared_progress_view_get_view(progress)); +} + +void infrared_scene_universal_common_on_enter(void* context) { + Infrared* infrared = context; + view_stack_add_view(infrared->view_stack, button_panel_get_view(infrared->button_panel)); +} + +bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + InfraredBruteForce* brute_force = infrared->brute_force; + bool consumed = false; + + if(infrared_brute_force_is_started(brute_force)) { + if(event.type == SceneManagerEventTypeTick) { + infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend); + bool success = infrared_brute_force_send_next(brute_force); + if(success) { + success = infrared_progress_view_increase_progress(infrared->progress); + } + if(!success) { + infrared_brute_force_stop(brute_force); + infrared_scene_universal_common_hide_popup(infrared); + } + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(infrared_custom_event_get_type(event.event) == InfraredCustomEventTypeBackPressed) { + infrared_brute_force_stop(brute_force); + infrared_scene_universal_common_hide_popup(infrared); + consumed = true; + } + } + } else { + if(event.type == SceneManagerEventTypeBack) { + scene_manager_previous_scene(scene_manager); + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(infrared_custom_event_get_type(event.event) == + InfraredCustomEventTypeButtonSelected) { + uint32_t record_count; + if(infrared_brute_force_start( + brute_force, infrared_custom_event_get_value(event.event), &record_count)) { + DOLPHIN_DEED(DolphinDeedIrBruteForce); + infrared_scene_universal_common_show_popup(infrared, record_count); + infrared_play_notification_message( + infrared, InfraredNotificationMessageBlinkSend); + } else { + scene_manager_previous_scene(scene_manager); + } + consumed = true; + } + } + } + + return consumed; +} + +void infrared_scene_universal_common_on_exit(void* context) { + Infrared* infrared = context; + ButtonPanel* button_panel = infrared->button_panel; + view_stack_remove_view(infrared->view_stack, button_panel_get_view(button_panel)); + button_panel_reset(button_panel); +} diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.h b/applications/infrared/scenes/common/infrared_scene_universal_common.h new file mode 100644 index 00000000..a6c697d7 --- /dev/null +++ b/applications/infrared/scenes/common/infrared_scene_universal_common.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +void infrared_scene_universal_common_on_enter(void* context); +bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent event); +void infrared_scene_universal_common_on_exit(void* context); +void infrared_scene_universal_common_item_callback(void* context, uint32_t index); diff --git a/applications/infrared/scenes/infrared_scene.c b/applications/infrared/scenes/infrared_scene.c new file mode 100644 index 00000000..b0f298e6 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene.c @@ -0,0 +1,30 @@ +#include "infrared_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const infrared_on_enter_handlers[])(void*) = { +#include "infrared_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const infrared_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "infrared_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const infrared_on_exit_handlers[])(void* context) = { +#include "infrared_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers infrared_scene_handlers = { + .on_enter_handlers = infrared_on_enter_handlers, + .on_event_handlers = infrared_on_event_handlers, + .on_exit_handlers = infrared_on_exit_handlers, + .scene_num = InfraredSceneNum, +}; diff --git a/applications/infrared/scenes/infrared_scene.h b/applications/infrared/scenes/infrared_scene.h new file mode 100644 index 00000000..e9d499a7 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) InfraredScene##id, +typedef enum { +#include "infrared_scene_config.h" + InfraredSceneNum, +} InfraredScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers infrared_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "infrared_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "infrared_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "infrared_scene_config.h" +#undef ADD_SCENE diff --git a/applications/infrared/scenes/infrared_scene_ask_back.c b/applications/infrared/scenes/infrared_scene_ask_back.c new file mode 100644 index 00000000..11cfcb04 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_ask_back.c @@ -0,0 +1,59 @@ +#include "../infrared_i.h" + +static void infrared_scene_dialog_result_callback(DialogExResult result, void* context) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, result); +} + +void infrared_scene_ask_back_on_enter(void* context) { + Infrared* infrared = context; + DialogEx* dialog_ex = infrared->dialog_ex; + + if(infrared->app_state.is_learning_new_remote) { + dialog_ex_set_header(dialog_ex, "Exit to Infrared menu?", 64, 0, AlignCenter, AlignTop); + } else { + dialog_ex_set_header(dialog_ex, "Exit to remote menu?", 64, 0, AlignCenter, AlignTop); + } + + dialog_ex_set_text( + dialog_ex, "All unsaved data\nwill be lost", 64, 31, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 0, 0, NULL); + dialog_ex_set_left_button_text(dialog_ex, "Exit"); + dialog_ex_set_center_button_text(dialog_ex, NULL); + dialog_ex_set_right_button_text(dialog_ex, "Stay"); + dialog_ex_set_result_callback(dialog_ex, infrared_scene_dialog_result_callback); + dialog_ex_set_context(dialog_ex, context); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); +} + +bool infrared_scene_ask_back_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultLeft) { + if(infrared->app_state.is_learning_new_remote) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneStart); + } else { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneRemote); + } + consumed = true; + } else if(event.event == DialogExResultRight) { + scene_manager_previous_scene(scene_manager); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_ask_back_on_exit(void* context) { + Infrared* infrared = context; + dialog_ex_reset(infrared->dialog_ex); +} diff --git a/applications/infrared/scenes/infrared_scene_config.h b/applications/infrared/scenes/infrared_scene_config.h new file mode 100644 index 00000000..3677ab3c --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_config.h @@ -0,0 +1,17 @@ +ADD_SCENE(infrared, start, Start) +ADD_SCENE(infrared, ask_back, AskBack) +ADD_SCENE(infrared, edit, Edit) +ADD_SCENE(infrared, edit_delete, EditDelete) +ADD_SCENE(infrared, edit_delete_done, EditDeleteDone) +ADD_SCENE(infrared, edit_button_select, EditButtonSelect) +ADD_SCENE(infrared, edit_rename, EditRename) +ADD_SCENE(infrared, edit_rename_done, EditRenameDone) +ADD_SCENE(infrared, learn, Learn) +ADD_SCENE(infrared, learn_done, LearnDone) +ADD_SCENE(infrared, learn_enter_name, LearnEnterName) +ADD_SCENE(infrared, learn_success, LearnSuccess) +ADD_SCENE(infrared, remote, Remote) +ADD_SCENE(infrared, remote_list, RemoteList) +ADD_SCENE(infrared, universal, Universal) +ADD_SCENE(infrared, universal_tv, UniversalTV) +ADD_SCENE(infrared, debug, Debug) diff --git a/applications/infrared/scenes/infrared_scene_debug.c b/applications/infrared/scenes/infrared_scene_debug.c new file mode 100644 index 00000000..ddb85644 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_debug.c @@ -0,0 +1,68 @@ +#include "../infrared_i.h" + +void infrared_scene_debug_on_enter(void* context) { + Infrared* infrared = context; + InfraredWorker* worker = infrared->worker; + + infrared_worker_rx_set_received_signal_callback( + worker, infrared_signal_received_callback, context); + infrared_worker_rx_enable_blink_on_receiving(worker, true); + infrared_worker_rx_start(worker); + + infrared_debug_view_set_text(infrared->debug_view, "Received signals\nwill appear here"); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDebugView); +} + +bool infrared_scene_debug_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypeSignalReceived) { + InfraredDebugView* debug_view = infrared->debug_view; + InfraredSignal* signal = infrared->received_signal; + + if(infrared_signal_is_raw(signal)) { + InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + infrared_debug_view_set_text(debug_view, "RAW\n%d samples\n", raw->timings_size); + + printf("RAW, %d samples:\r\n", raw->timings_size); + for(size_t i = 0; i < raw->timings_size; ++i) { + printf("%lu ", raw->timings[i]); + } + printf("\r\n"); + + } else { + InfraredMessage* message = infrared_signal_get_message(signal); + infrared_debug_view_set_text( + debug_view, + "%s\nA:0x%0*lX\nC:0x%0*lX\n%s\n", + infrared_get_protocol_name(message->protocol), + ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), + message->address, + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), + message->command, + message->repeat ? " R" : ""); + + printf( + "== %s, A:0x%0*lX, C:0x%0*lX%s ==\r\n", + infrared_get_protocol_name(message->protocol), + ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), + message->address, + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), + message->command, + message->repeat ? " R" : ""); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_debug_on_exit(void* context) { + Infrared* infrared = context; + InfraredWorker* worker = infrared->worker; + infrared_worker_rx_stop(worker); + infrared_worker_rx_enable_blink_on_receiving(worker, false); +} diff --git a/applications/infrared/scenes/infrared_scene_edit.c b/applications/infrared/scenes/infrared_scene_edit.c new file mode 100644 index 00000000..360ed49b --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit.c @@ -0,0 +1,101 @@ +#include "../infrared_i.h" + +typedef enum { + SubmenuIndexAddButton, + SubmenuIndexRenameButton, + SubmenuIndexDeleteButton, + SubmenuIndexRenameRemote, + SubmenuIndexDeleteRemote, +} SubmenuIndex; + +static void infrared_scene_edit_submenu_callback(void* context, uint32_t index) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, index); +} + +void infrared_scene_edit_on_enter(void* context) { + Infrared* infrared = context; + Submenu* submenu = infrared->submenu; + SceneManager* scene_manager = infrared->scene_manager; + + submenu_add_item( + submenu, + "Add Button", + SubmenuIndexAddButton, + infrared_scene_edit_submenu_callback, + context); + submenu_add_item( + submenu, + "Rename Button", + SubmenuIndexRenameButton, + infrared_scene_edit_submenu_callback, + context); + submenu_add_item( + submenu, + "Delete Button", + SubmenuIndexDeleteButton, + infrared_scene_edit_submenu_callback, + context); + submenu_add_item( + submenu, + "Rename Remote", + SubmenuIndexRenameRemote, + infrared_scene_edit_submenu_callback, + context); + submenu_add_item( + submenu, + "Delete Remote", + SubmenuIndexDeleteRemote, + infrared_scene_edit_submenu_callback, + context); + + const uint32_t submenu_index = scene_manager_get_scene_state(scene_manager, InfraredSceneEdit); + submenu_set_selected_item(submenu, submenu_index); + scene_manager_set_scene_state(scene_manager, InfraredSceneEdit, SubmenuIndexAddButton); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); +} + +bool infrared_scene_edit_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + const uint32_t submenu_index = event.event; + scene_manager_set_scene_state(scene_manager, InfraredSceneEdit, submenu_index); + + if(submenu_index == SubmenuIndexAddButton) { + infrared->app_state.is_learning_new_remote = false; + scene_manager_next_scene(scene_manager, InfraredSceneLearn); + consumed = true; + } else if(submenu_index == SubmenuIndexRenameButton) { + infrared->app_state.edit_target = InfraredEditTargetButton; + infrared->app_state.edit_mode = InfraredEditModeRename; + scene_manager_next_scene(scene_manager, InfraredSceneEditButtonSelect); + consumed = true; + } else if(submenu_index == SubmenuIndexDeleteButton) { + infrared->app_state.edit_target = InfraredEditTargetButton; + infrared->app_state.edit_mode = InfraredEditModeDelete; + scene_manager_next_scene(scene_manager, InfraredSceneEditButtonSelect); + consumed = true; + } else if(submenu_index == SubmenuIndexRenameRemote) { + infrared->app_state.edit_target = InfraredEditTargetRemote; + infrared->app_state.edit_mode = InfraredEditModeRename; + scene_manager_next_scene(scene_manager, InfraredSceneEditRename); + consumed = true; + } else if(submenu_index == SubmenuIndexDeleteRemote) { + infrared->app_state.edit_target = InfraredEditTargetRemote; + infrared->app_state.edit_mode = InfraredEditModeDelete; + scene_manager_next_scene(scene_manager, InfraredSceneEditDelete); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_on_exit(void* context) { + Infrared* infrared = context; + submenu_reset(infrared->submenu); +} diff --git a/applications/infrared/scenes/infrared_scene_edit_button_select.c b/applications/infrared/scenes/infrared_scene_edit_button_select.c new file mode 100644 index 00000000..a7f8a2bf --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_button_select.c @@ -0,0 +1,63 @@ +#include "../infrared_i.h" + +static void infrared_scene_edit_button_select_submenu_callback(void* context, uint32_t index) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, index); +} + +void infrared_scene_edit_button_select_on_enter(void* context) { + Infrared* infrared = context; + Submenu* submenu = infrared->submenu; + InfraredRemote* remote = infrared->remote; + InfraredAppState* app_state = &infrared->app_state; + + const char* header = infrared->app_state.edit_mode == InfraredEditModeRename ? + "Rename Button:" : + "Delete Button:"; + submenu_set_header(submenu, header); + + const size_t button_count = infrared_remote_get_button_count(remote); + for(size_t i = 0; i < button_count; ++i) { + InfraredRemoteButton* button = infrared_remote_get_button(remote, i); + submenu_add_item( + submenu, + infrared_remote_button_get_name(button), + i, + infrared_scene_edit_button_select_submenu_callback, + context); + } + + if(button_count && app_state->current_button_index != InfraredButtonIndexNone) { + submenu_set_selected_item(submenu, app_state->current_button_index); + app_state->current_button_index = InfraredButtonIndexNone; + } + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); +} + +bool infrared_scene_edit_button_select_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + InfraredAppState* app_state = &infrared->app_state; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + app_state->current_button_index = event.event; + const InfraredEditMode edit_mode = app_state->edit_mode; + if(edit_mode == InfraredEditModeRename) { + scene_manager_next_scene(scene_manager, InfraredSceneEditRename); + } else if(edit_mode == InfraredEditModeDelete) { + scene_manager_next_scene(scene_manager, InfraredSceneEditDelete); + } else { + furi_assert(0); + } + consumed = true; + } + + return consumed; +} + +void infrared_scene_edit_button_select_on_exit(void* context) { + Infrared* infrared = context; + submenu_reset(infrared->submenu); +} diff --git a/applications/infrared/scenes/infrared_scene_edit_delete.c b/applications/infrared/scenes/infrared_scene_edit_delete.c new file mode 100644 index 00000000..0842cd61 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_delete.c @@ -0,0 +1,112 @@ +#include "../infrared_i.h" + +static void + infrared_scene_edit_delete_dialog_result_callback(DialogExResult result, void* context) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, result); +} + +void infrared_scene_edit_delete_on_enter(void* context) { + Infrared* infrared = context; + DialogEx* dialog_ex = infrared->dialog_ex; + InfraredRemote* remote = infrared->remote; + + const InfraredEditTarget edit_target = infrared->app_state.edit_target; + if(edit_target == InfraredEditTargetButton) { + int32_t current_button_index = infrared->app_state.current_button_index; + furi_assert(current_button_index != InfraredButtonIndexNone); + + dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop); + InfraredRemoteButton* current_button = + infrared_remote_get_button(remote, current_button_index); + InfraredSignal* signal = infrared_remote_button_get_signal(current_button); + + if(infrared_signal_is_raw(signal)) { + const InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + infrared_text_store_set( + infrared, + 0, + "%s\nRAW\n%ld samples", + infrared_remote_button_get_name(current_button), + raw->timings_size); + + } else { + const InfraredMessage* message = infrared_signal_get_message(signal); + infrared_text_store_set( + infrared, + 0, + "%s\n%s\nA=0x%0*lX C=0x%0*lX", + infrared_remote_button_get_name(current_button), + infrared_get_protocol_name(message->protocol), + ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), + message->address, + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), + message->command); + } + + } else if(edit_target == InfraredEditTargetRemote) { + dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 0, AlignCenter, AlignTop); + infrared_text_store_set( + infrared, + 0, + "%s\n with %lu buttons", + infrared_remote_get_name(remote), + infrared_remote_get_button_count(remote)); + } else { + furi_assert(0); + } + + dialog_ex_set_text(dialog_ex, infrared->text_store[0], 64, 31, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 0, 0, NULL); + dialog_ex_set_left_button_text(dialog_ex, "Cancel"); + dialog_ex_set_right_button_text(dialog_ex, "Delete"); + dialog_ex_set_result_callback(dialog_ex, infrared_scene_edit_delete_dialog_result_callback); + dialog_ex_set_context(dialog_ex, context); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); +} + +bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultLeft) { + scene_manager_previous_scene(scene_manager); + consumed = true; + } else if(event.event == DialogExResultRight) { + bool success = false; + InfraredRemote* remote = infrared->remote; + InfraredAppState* app_state = &infrared->app_state; + const InfraredEditTarget edit_target = app_state->edit_target; + + if(edit_target == InfraredEditTargetButton) { + furi_assert(app_state->current_button_index != InfraredButtonIndexNone); + success = infrared_remote_delete_button(remote, app_state->current_button_index); + app_state->current_button_index = InfraredButtonIndexNone; + } else if(edit_target == InfraredEditTargetRemote) { + success = infrared_remote_remove(remote); + app_state->current_button_index = InfraredButtonIndexNone; + } else { + furi_assert(0); + } + + if(success) { + scene_manager_next_scene(scene_manager, InfraredSceneEditDeleteDone); + } else { + const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; + scene_manager_search_and_switch_to_previous_scene_one_of( + scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_delete_on_exit(void* context) { + Infrared* infrared = context; + UNUSED(infrared); +} diff --git a/applications/infrared/scenes/infrared_scene_edit_delete_done.c b/applications/infrared/scenes/infrared_scene_edit_delete_done.c new file mode 100644 index 00000000..688c3a45 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_delete_done.c @@ -0,0 +1,46 @@ +#include "../infrared_i.h" + +void infrared_scene_edit_delete_done_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + + popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + + popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_context(popup, context); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_edit_delete_done_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypePopupTimeout) { + const InfraredEditTarget edit_target = infrared->app_state.edit_target; + if(edit_target == InfraredEditTargetButton) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneRemote); + } else if(edit_target == InfraredEditTargetRemote) { + const uint32_t possible_scenes[] = {InfraredSceneStart, InfraredSceneRemoteList}; + scene_manager_search_and_switch_to_previous_scene_one_of( + scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); + } else { + furi_assert(0); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_delete_done_on_exit(void* context) { + Infrared* infrared = context; + UNUSED(infrared); +} diff --git a/applications/infrared/scenes/infrared_scene_edit_rename.c b/applications/infrared/scenes/infrared_scene_edit_rename.c new file mode 100644 index 00000000..ebe7c2a9 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_rename.c @@ -0,0 +1,107 @@ +#include "../infrared_i.h" + +#include +#include + +void infrared_scene_edit_rename_on_enter(void* context) { + Infrared* infrared = context; + InfraredRemote* remote = infrared->remote; + TextInput* text_input = infrared->text_input; + size_t enter_name_length = 0; + + const InfraredEditTarget edit_target = infrared->app_state.edit_target; + if(edit_target == InfraredEditTargetButton) { + text_input_set_header_text(text_input, "Name the button"); + + const int32_t current_button_index = infrared->app_state.current_button_index; + furi_assert(current_button_index != InfraredButtonIndexNone); + + InfraredRemoteButton* current_button = + infrared_remote_get_button(remote, current_button_index); + enter_name_length = INFRARED_MAX_BUTTON_NAME_LENGTH; + strncpy( + infrared->text_store[0], + infrared_remote_button_get_name(current_button), + enter_name_length); + + } else if(edit_target == InfraredEditTargetRemote) { + text_input_set_header_text(text_input, "Name the remote"); + enter_name_length = INFRARED_MAX_REMOTE_NAME_LENGTH; + strncpy(infrared->text_store[0], infrared_remote_get_name(remote), enter_name_length); + + string_t folder_path; + string_init(folder_path); + + if(string_end_with_str_p(infrared->file_path, INFRARED_APP_EXTENSION)) { + path_extract_dirname(string_get_cstr(infrared->file_path), folder_path); + } + + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + string_get_cstr(folder_path), + INFRARED_APP_EXTENSION, + infrared_remote_get_name(remote)); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + string_clear(folder_path); + } else { + furi_assert(0); + } + + text_input_set_result_callback( + text_input, + infrared_text_input_callback, + context, + infrared->text_store[0], + enter_name_length, + false); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewTextInput); +} + +bool infrared_scene_edit_rename_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + InfraredRemote* remote = infrared->remote; + SceneManager* scene_manager = infrared->scene_manager; + InfraredAppState* app_state = &infrared->app_state; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypeTextEditDone) { + bool success = false; + const InfraredEditTarget edit_target = app_state->edit_target; + if(edit_target == InfraredEditTargetButton) { + const int32_t current_button_index = app_state->current_button_index; + furi_assert(current_button_index != InfraredButtonIndexNone); + success = infrared_remote_rename_button( + remote, infrared->text_store[0], current_button_index); + app_state->current_button_index = InfraredButtonIndexNone; + } else if(edit_target == InfraredEditTargetRemote) { + success = infrared_rename_current_remote(infrared, infrared->text_store[0]); + } else { + furi_assert(0); + } + + if(success) { + scene_manager_next_scene(scene_manager, InfraredSceneEditRenameDone); + } else { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneRemoteList); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_rename_on_exit(void* context) { + Infrared* infrared = context; + TextInput* text_input = infrared->text_input; + + void* validator_context = text_input_get_validator_callback_context(text_input); + text_input_set_validator(text_input, NULL, NULL); + + if(validator_context) { + validator_is_file_free((ValidatorIsFile*)validator_context); + } +} diff --git a/applications/infrared/scenes/infrared_scene_edit_rename_done.c b/applications/infrared/scenes/infrared_scene_edit_rename_done.c new file mode 100644 index 00000000..60a26954 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_rename_done.c @@ -0,0 +1,35 @@ +#include "../infrared_i.h" + +void infrared_scene_edit_rename_done_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + + popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_context(popup, context); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_edit_rename_done_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypePopupTimeout) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_rename_done_on_exit(void* context) { + Infrared* infrared = context; + UNUSED(infrared); +} diff --git a/applications/infrared/scenes/infrared_scene_learn.c b/applications/infrared/scenes/infrared_scene_learn.c new file mode 100644 index 00000000..d91b8676 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_learn.c @@ -0,0 +1,46 @@ +#include "../infrared_i.h" + +void infrared_scene_learn_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + InfraredWorker* worker = infrared->worker; + + infrared_worker_rx_set_received_signal_callback( + worker, infrared_signal_received_callback, context); + infrared_worker_rx_start(worker); + + popup_set_icon(popup, 0, 32, &I_InfraredLearnShort_128x31); + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignCenter); + popup_set_text( + popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter); + popup_set_callback(popup, NULL); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkRead); + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypeSignalReceived) { + infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL); + infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); + scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_learn_on_exit(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + infrared_worker_rx_stop(infrared->worker); + popup_set_icon(popup, 0, 0, NULL); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter); +} diff --git a/applications/infrared/scenes/infrared_scene_learn_done.c b/applications/infrared/scenes/infrared_scene_learn_done.c new file mode 100644 index 00000000..a24bb918 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_learn_done.c @@ -0,0 +1,44 @@ +#include "../infrared_i.h" + +#include + +void infrared_scene_learn_done_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + DOLPHIN_DEED(DolphinDeedIrSave); + + if(infrared->app_state.is_learning_new_remote) { + popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); + } else { + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + } + + popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_context(popup, context); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_learn_done_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypePopupTimeout) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_learn_done_on_exit(void* context) { + Infrared* infrared = context; + infrared->app_state.is_learning_new_remote = false; + popup_set_header(infrared->popup, NULL, 0, 0, AlignLeft, AlignTop); +} diff --git a/applications/infrared/scenes/infrared_scene_learn_enter_name.c b/applications/infrared/scenes/infrared_scene_learn_enter_name.c new file mode 100644 index 00000000..b7f4179e --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_learn_enter_name.c @@ -0,0 +1,66 @@ +#include "../infrared_i.h" + +void infrared_scene_learn_enter_name_on_enter(void* context) { + Infrared* infrared = context; + TextInput* text_input = infrared->text_input; + InfraredSignal* signal = infrared->received_signal; + + if(infrared_signal_is_raw(signal)) { + InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + infrared_text_store_set(infrared, 0, "RAW_%d", raw->timings_size); + } else { + InfraredMessage* message = infrared_signal_get_message(signal); + infrared_text_store_set( + infrared, + 0, + "%.4s_%0*lX", + infrared_get_protocol_name(message->protocol), + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), + message->command); + } + + text_input_set_header_text(text_input, "Name the button"); + text_input_set_result_callback( + text_input, + infrared_text_input_callback, + context, + infrared->text_store[0], + INFRARED_MAX_BUTTON_NAME_LENGTH, + true); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewTextInput); +} + +bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + InfraredSignal* signal = infrared->received_signal; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypeTextEditDone) { + bool success = false; + if(infrared->app_state.is_learning_new_remote) { + success = + infrared_add_remote_with_button(infrared, infrared->text_store[0], signal); + } else { + success = + infrared_remote_add_button(infrared->remote, infrared->text_store[0], signal); + } + + if(success) { + scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); + } else { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneRemoteList); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_learn_enter_name_on_exit(void* context) { + Infrared* infrared = context; + UNUSED(infrared); +} diff --git a/applications/infrared/scenes/infrared_scene_learn_success.c b/applications/infrared/scenes/infrared_scene_learn_success.c new file mode 100644 index 00000000..ec950ca7 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_learn_success.c @@ -0,0 +1,131 @@ +#include "../infrared_i.h" + +#include + +typedef enum { + InfraredSceneLearnSuccessStateIdle = 0, + InfraredSceneLearnSuccessStateSending = 1, +} InfraredSceneLearnSuccessState; + +static void + infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, result); +} + +void infrared_scene_learn_success_on_enter(void* context) { + Infrared* infrared = context; + DialogEx* dialog_ex = infrared->dialog_ex; + InfraredSignal* signal = infrared->received_signal; + + DOLPHIN_DEED(DolphinDeedIrLearnSuccess); + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); + + infrared_worker_tx_set_get_signal_callback( + infrared->worker, infrared_worker_tx_get_signal_steady_callback, context); + infrared_worker_tx_set_signal_sent_callback( + infrared->worker, infrared_signal_sent_callback, context); + + if(infrared_signal_is_raw(signal)) { + InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); + infrared_text_store_set(infrared, 0, "%d samples", raw->timings_size); + dialog_ex_set_text(dialog_ex, infrared->text_store[0], 75, 23, AlignLeft, AlignTop); + + } else { + InfraredMessage* message = infrared_signal_get_message(signal); + uint8_t addr_digits = + ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4); + uint8_t cmd_digits = + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4); + uint8_t max_digits = MAX(addr_digits, cmd_digits); + max_digits = MIN(max_digits, 7); + size_t label_x_offset = 63 + (7 - max_digits) * 3; + + infrared_text_store_set(infrared, 0, "%s", infrared_get_protocol_name(message->protocol)); + infrared_text_store_set( + infrared, + 1, + "A: 0x%0*lX\nC: 0x%0*lX\n", + addr_digits, + message->address, + cmd_digits, + message->command); + + dialog_ex_set_header(dialog_ex, infrared->text_store[0], 95, 7, AlignCenter, AlignCenter); + dialog_ex_set_text( + dialog_ex, infrared->text_store[1], label_x_offset, 34, AlignLeft, AlignCenter); + } + + dialog_ex_set_left_button_text(dialog_ex, "Retry"); + dialog_ex_set_right_button_text(dialog_ex, "Save"); + dialog_ex_set_center_button_text(dialog_ex, "Send"); + dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63); + dialog_ex_set_result_callback(dialog_ex, infrared_scene_learn_success_dialog_result_callback); + dialog_ex_set_context(dialog_ex, context); + dialog_ex_enable_extended_events(dialog_ex); + + scene_manager_set_scene_state( + infrared->scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); +} + +bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + uint32_t scene_state = scene_manager_get_scene_state(scene_manager, InfraredSceneLearnSuccess); + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); + } + consumed = true; + } else if(event.type == SceneManagerEventTypeBack) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + scene_manager_next_scene(scene_manager, InfraredSceneAskBack); + } + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultLeft) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneLearn); + } + consumed = true; + } else if(event.event == DialogExResultRight) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + scene_manager_next_scene(scene_manager, InfraredSceneLearnEnterName); + } + consumed = true; + } else if(event.event == DialogExPressCenter) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + scene_manager_set_scene_state( + scene_manager, + InfraredSceneLearnSuccess, + InfraredSceneLearnSuccessStateSending); + infrared_tx_start_received(infrared); + } + consumed = true; + } else if(event.event == DialogExReleaseCenter) { + if(scene_state == InfraredSceneLearnSuccessStateSending) { + scene_manager_set_scene_state( + scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle); + infrared_tx_stop(infrared); + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_learn_success_on_exit(void* context) { + Infrared* infrared = context; + InfraredWorker* worker = infrared->worker; + dialog_ex_reset(infrared->dialog_ex); + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); + infrared_worker_tx_set_get_signal_callback(worker, NULL, NULL); + infrared_worker_tx_set_signal_sent_callback(worker, NULL, NULL); +} diff --git a/applications/infrared/scenes/infrared_scene_remote.c b/applications/infrared/scenes/infrared_scene_remote.c new file mode 100644 index 00000000..0b7a1ad9 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_remote.c @@ -0,0 +1,119 @@ +#include "../infrared_i.h" + +typedef enum { + ButtonIndexPlus = -2, + ButtonIndexEdit = -1, + ButtonIndexNA = 0, +} ButtonIndex; + +static void + infrared_scene_remote_button_menu_callback(void* context, int32_t index, InputType type) { + Infrared* infrared = context; + + uint16_t custom_type; + if(type == InputTypePress) { + custom_type = InfraredCustomEventTypeTransmitStarted; + } else if(type == InputTypeRelease) { + custom_type = InfraredCustomEventTypeTransmitStopped; + } else if(type == InputTypeShort) { + custom_type = InfraredCustomEventTypeMenuSelected; + } else { + furi_crash("Unexpected input type"); + } + + view_dispatcher_send_custom_event( + infrared->view_dispatcher, infrared_custom_event_pack(custom_type, index)); +} + +void infrared_scene_remote_on_enter(void* context) { + Infrared* infrared = context; + InfraredRemote* remote = infrared->remote; + ButtonMenu* button_menu = infrared->button_menu; + SceneManager* scene_manager = infrared->scene_manager; + + infrared_worker_tx_set_get_signal_callback( + infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); + infrared_worker_tx_set_signal_sent_callback( + infrared->worker, infrared_signal_sent_callback, infrared); + + size_t button_count = infrared_remote_get_button_count(remote); + for(size_t i = 0; i < button_count; ++i) { + InfraredRemoteButton* button = infrared_remote_get_button(remote, i); + button_menu_add_item( + button_menu, + infrared_remote_button_get_name(button), + i, + infrared_scene_remote_button_menu_callback, + ButtonMenuItemTypeCommon, + context); + } + + button_menu_add_item( + button_menu, + "+", + ButtonIndexPlus, + infrared_scene_remote_button_menu_callback, + ButtonMenuItemTypeControl, + context); + button_menu_add_item( + button_menu, + "Edit", + ButtonIndexEdit, + infrared_scene_remote_button_menu_callback, + ButtonMenuItemTypeControl, + context); + + button_menu_set_header(button_menu, infrared_remote_get_name(remote)); + const int16_t button_index = + (signed)scene_manager_get_scene_state(scene_manager, InfraredSceneRemote); + button_menu_set_selected_item(button_menu, button_index); + scene_manager_set_scene_state(scene_manager, InfraredSceneRemote, ButtonIndexNA); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewButtonMenu); +} + +bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; + scene_manager_search_and_switch_to_previous_scene_one_of( + scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + const uint16_t custom_type = infrared_custom_event_get_type(event.event); + const int16_t button_index = infrared_custom_event_get_value(event.event); + + if(custom_type == InfraredCustomEventTypeTransmitStarted) { + furi_assert(button_index >= 0); + infrared_tx_start_button_index(infrared, button_index); + consumed = true; + } else if(custom_type == InfraredCustomEventTypeTransmitStopped) { + infrared_tx_stop(infrared); + consumed = true; + } else if(custom_type == InfraredCustomEventTypeMenuSelected) { + furi_assert(button_index < 0); + scene_manager_set_scene_state( + scene_manager, InfraredSceneRemote, (unsigned)button_index); + if(button_index == ButtonIndexPlus) { + infrared->app_state.is_learning_new_remote = false; + scene_manager_next_scene(scene_manager, InfraredSceneLearn); + consumed = true; + } else if(button_index == ButtonIndexEdit) { + scene_manager_next_scene(scene_manager, InfraredSceneEdit); + consumed = true; + } + } + } + + return consumed; +} + +void infrared_scene_remote_on_exit(void* context) { + Infrared* infrared = context; + infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL); + infrared_worker_tx_set_signal_sent_callback(infrared->worker, NULL, NULL); + button_menu_reset(infrared->button_menu); +} diff --git a/applications/infrared/scenes/infrared_scene_remote_list.c b/applications/infrared/scenes/infrared_scene_remote_list.c new file mode 100644 index 00000000..25b37759 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_remote_list.c @@ -0,0 +1,44 @@ +#include "../infrared_i.h" + +void infrared_scene_remote_list_on_enter(void* context) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + ViewDispatcher* view_dispatcher = infrared->view_dispatcher; + + string_set_str(infrared->file_path, INFRARED_APP_FOLDER); + bool success = dialog_file_browser_show( + infrared->dialogs, + infrared->file_path, + infrared->file_path, + INFRARED_APP_EXTENSION, + true, + &I_ir_10px, + true); + + if(success) { + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationHorizontal); + view_dispatcher_switch_to_view(view_dispatcher, InfraredViewStack); + + infrared_show_loading_popup(infrared, true); + success = infrared_remote_load(infrared->remote, infrared->file_path); + infrared_show_loading_popup(infrared, false); + } + + if(success) { + scene_manager_next_scene(scene_manager, InfraredSceneRemote); + } else { + scene_manager_previous_scene(scene_manager); + } +} + +bool infrared_scene_remote_list_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + + return consumed; +} + +void infrared_scene_remote_list_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/infrared/scenes/infrared_scene_start.c b/applications/infrared/scenes/infrared_scene_start.c new file mode 100644 index 00000000..6b874a3a --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_start.c @@ -0,0 +1,83 @@ +#include "../infrared_i.h" + +enum SubmenuIndex { + SubmenuIndexUniversalRemotes, + SubmenuIndexLearnNewRemote, + SubmenuIndexSavedRemotes, + SubmenuIndexDebug +}; + +static void infrared_scene_start_submenu_callback(void* context, uint32_t index) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, index); +} + +void infrared_scene_start_on_enter(void* context) { + Infrared* infrared = context; + Submenu* submenu = infrared->submenu; + SceneManager* scene_manager = infrared->scene_manager; + + submenu_add_item( + submenu, + "Universal Remotes", + SubmenuIndexUniversalRemotes, + infrared_scene_start_submenu_callback, + infrared); + submenu_add_item( + submenu, + "Learn New Remote", + SubmenuIndexLearnNewRemote, + infrared_scene_start_submenu_callback, + infrared); + submenu_add_item( + submenu, + "Saved Remotes", + SubmenuIndexSavedRemotes, + infrared_scene_start_submenu_callback, + infrared); + + if(infrared->app_state.is_debug_enabled) { + submenu_add_item( + submenu, "Debug", SubmenuIndexDebug, infrared_scene_start_submenu_callback, infrared); + } + + const uint32_t submenu_index = + scene_manager_get_scene_state(scene_manager, InfraredSceneStart); + submenu_set_selected_item(submenu, submenu_index); + scene_manager_set_scene_state(scene_manager, InfraredSceneStart, SubmenuIndexUniversalRemotes); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); +} + +bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + const uint32_t submenu_index = event.event; + scene_manager_set_scene_state(scene_manager, InfraredSceneStart, submenu_index); + if(submenu_index == SubmenuIndexUniversalRemotes) { + scene_manager_next_scene(scene_manager, InfraredSceneUniversal); + consumed = true; + } else if(submenu_index == SubmenuIndexLearnNewRemote) { + infrared->app_state.is_learning_new_remote = true; + scene_manager_next_scene(scene_manager, InfraredSceneLearn); + consumed = true; + } else if(submenu_index == SubmenuIndexSavedRemotes) { + scene_manager_next_scene(scene_manager, InfraredSceneRemoteList); + consumed = true; + } else if(submenu_index == SubmenuIndexDebug) { + scene_manager_next_scene(scene_manager, InfraredSceneDebug); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_start_on_exit(void* context) { + Infrared* infrared = context; + submenu_reset(infrared->submenu); +} diff --git a/applications/infrared/scenes/infrared_scene_universal.c b/applications/infrared/scenes/infrared_scene_universal.c new file mode 100644 index 00000000..cc656883 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_universal.c @@ -0,0 +1,53 @@ +#include "../infrared_i.h" + +typedef enum { + SubmenuIndexUniversalTV, + SubmenuIndexUniversalAudio, + SubmenuIndexUniversalAirConditioner, +} SubmenuIndex; + +static void infrared_scene_universal_submenu_callback(void* context, uint32_t index) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, index); +} + +void infrared_scene_universal_on_enter(void* context) { + Infrared* infrared = context; + Submenu* submenu = infrared->submenu; + + submenu_add_item( + submenu, + "TVs", + SubmenuIndexUniversalTV, + infrared_scene_universal_submenu_callback, + context); + submenu_set_selected_item(submenu, 0); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); +} + +bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexUniversalTV) { + scene_manager_next_scene(scene_manager, InfraredSceneUniversalTV); + consumed = true; + } else if(event.event == SubmenuIndexUniversalAudio) { + //TODO Implement Audio universal remote + consumed = true; + } else if(event.event == SubmenuIndexUniversalAirConditioner) { + //TODO Implement A/C universal remote + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_universal_on_exit(void* context) { + Infrared* infrared = context; + submenu_reset(infrared->submenu); +} diff --git a/applications/infrared/scenes/infrared_scene_universal_tv.c b/applications/infrared/scenes/infrared_scene_universal_tv.c new file mode 100644 index 00000000..f3a9a06b --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_universal_tv.c @@ -0,0 +1,111 @@ +#include "../infrared_i.h" + +#include "common/infrared_scene_universal_common.h" + +void infrared_scene_universal_tv_on_enter(void* context) { + infrared_scene_universal_common_on_enter(context); + + Infrared* infrared = context; + ButtonPanel* button_panel = infrared->button_panel; + InfraredBruteForce* brute_force = infrared->brute_force; + + infrared_brute_force_set_db_filename(brute_force, "/ext/infrared/assets/tv.ir"); + + button_panel_reserve(button_panel, 2, 3); + uint32_t i = 0; + button_panel_add_item( + button_panel, + i, + 0, + 0, + 3, + 19, + &I_Power_25x27, + &I_Power_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "POWER"); + button_panel_add_item( + button_panel, + i, + 1, + 0, + 36, + 19, + &I_Mute_25x27, + &I_Mute_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "MUTE"); + button_panel_add_item( + button_panel, + i, + 0, + 1, + 3, + 66, + &I_Vol_up_25x27, + &I_Vol_up_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "VOL+"); + button_panel_add_item( + button_panel, + i, + 1, + 1, + 36, + 66, + &I_Up_25x27, + &I_Up_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "CH+"); + button_panel_add_item( + button_panel, + i, + 0, + 2, + 3, + 98, + &I_Vol_down_25x27, + &I_Vol_down_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "VOL-"); + button_panel_add_item( + button_panel, + i, + 1, + 2, + 36, + 98, + &I_Down_25x27, + &I_Down_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "CH-"); + + button_panel_add_label(button_panel, 6, 11, FontPrimary, "TV remote"); + button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol"); + button_panel_add_label(button_panel, 43, 64, FontSecondary, "Ch"); + + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); + + infrared_show_loading_popup(infrared, true); + bool success = infrared_brute_force_calculate_messages(brute_force); + infrared_show_loading_popup(infrared, false); + + if(!success) { + scene_manager_previous_scene(infrared->scene_manager); + } +} + +bool infrared_scene_universal_tv_on_event(void* context, SceneManagerEvent event) { + return infrared_scene_universal_common_on_event(context, event); +} + +void infrared_scene_universal_tv_on_exit(void* context) { + infrared_scene_universal_common_on_exit(context); +} diff --git a/applications/infrared/views/infrared_debug_view.c b/applications/infrared/views/infrared_debug_view.c new file mode 100644 index 00000000..ab2c679c --- /dev/null +++ b/applications/infrared/views/infrared_debug_view.c @@ -0,0 +1,59 @@ +#include "infrared_debug_view.h" + +#include +#include + +#include +#include + +#define INFRARED_DEBUG_TEXT_LENGTH 64 + +struct InfraredDebugView { + View* view; +}; + +typedef struct { + char text[INFRARED_DEBUG_TEXT_LENGTH]; +} InfraredDebugViewModel; + +static void infrared_debug_view_draw_callback(Canvas* canvas, void* model) { + InfraredDebugViewModel* debug_view_model = model; + + canvas_clear(canvas); + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "INFRARED monitor\n"); + canvas_set_font(canvas, FontKeyboard); + + if(strlen(debug_view_model->text)) { + elements_multiline_text_aligned( + canvas, 64, 43, AlignCenter, AlignCenter, debug_view_model->text); + } +} + +InfraredDebugView* infrared_debug_view_alloc() { + InfraredDebugView* debug_view = malloc(sizeof(InfraredDebugView)); + debug_view->view = view_alloc(); + view_allocate_model(debug_view->view, ViewModelTypeLocking, sizeof(InfraredDebugViewModel)); + view_set_draw_callback(debug_view->view, infrared_debug_view_draw_callback); + view_set_context(debug_view->view, debug_view); + return debug_view; +} +void infrared_debug_view_free(InfraredDebugView* debug_view) { + view_free(debug_view->view); + free(debug_view); +} + +View* infrared_debug_view_get_view(InfraredDebugView* debug_view) { + return debug_view->view; +} + +void infrared_debug_view_set_text(InfraredDebugView* debug_view, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + + InfraredDebugViewModel* model = view_get_model(debug_view->view); + vsnprintf(model->text, INFRARED_DEBUG_TEXT_LENGTH, fmt, args); + view_commit_model(debug_view->view, true); + + va_end(args); +} diff --git a/applications/infrared/views/infrared_debug_view.h b/applications/infrared/views/infrared_debug_view.h new file mode 100644 index 00000000..722850f8 --- /dev/null +++ b/applications/infrared/views/infrared_debug_view.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +typedef struct InfraredDebugView InfraredDebugView; + +InfraredDebugView* infrared_debug_view_alloc(); +void infrared_debug_view_free(InfraredDebugView* debug_view); + +View* infrared_debug_view_get_view(InfraredDebugView* debug_view); +void infrared_debug_view_set_text(InfraredDebugView* debug_view, const char* fmt, ...); diff --git a/applications/infrared/view/infrared_progress_view.c b/applications/infrared/views/infrared_progress_view.c similarity index 100% rename from applications/infrared/view/infrared_progress_view.c rename to applications/infrared/views/infrared_progress_view.c diff --git a/applications/infrared/view/infrared_progress_view.h b/applications/infrared/views/infrared_progress_view.h similarity index 100% rename from applications/infrared/view/infrared_progress_view.h rename to applications/infrared/views/infrared_progress_view.h diff --git a/applications/infrared_monitor/infrared_monitor.c b/applications/infrared_monitor/infrared_monitor.c deleted file mode 100644 index 08691dfa..00000000 --- a/applications/infrared_monitor/infrared_monitor.c +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define INFRARED_TIMINGS_SIZE 700 - -typedef struct { - uint32_t timing_cnt; - struct { - uint8_t level; - uint32_t duration; - } timing[INFRARED_TIMINGS_SIZE]; -} InfraredDelaysArray; - -typedef struct { - char display_text[64]; - osMessageQueueId_t event_queue; - InfraredDelaysArray delays; - InfraredWorker* worker; - ViewPort* view_port; -} InfraredMonitor; - -void infrared_monitor_input_callback(InputEvent* input_event, void* ctx) { - furi_assert(ctx); - InfraredMonitor* infrared_monitor = (InfraredMonitor*)ctx; - - if((input_event->type == InputTypeShort) && (input_event->key == InputKeyBack)) { - osMessageQueuePut(infrared_monitor->event_queue, input_event, 0, 0); - } -} - -static void infrared_monitor_draw_callback(Canvas* canvas, void* ctx) { - furi_assert(canvas); - furi_assert(ctx); - InfraredMonitor* infrared_monitor = (InfraredMonitor*)ctx; - - canvas_clear(canvas); - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "INFRARED monitor\n"); - canvas_set_font(canvas, FontKeyboard); - if(strlen(infrared_monitor->display_text)) { - elements_multiline_text_aligned( - canvas, 64, 43, AlignCenter, AlignCenter, infrared_monitor->display_text); - } -} - -static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { - furi_assert(context); - furi_assert(received_signal); - InfraredMonitor* infrared_monitor = context; - - if(infrared_worker_signal_is_decoded(received_signal)) { - const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal); - snprintf( - infrared_monitor->display_text, - sizeof(infrared_monitor->display_text), - "%s\nA:0x%0*lX\nC:0x%0*lX\n%s\n", - infrared_get_protocol_name(message->protocol), - ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), - message->address, - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), - message->command, - message->repeat ? " R" : ""); - view_port_update(infrared_monitor->view_port); - printf( - "== %s, A:0x%0*lX, C:0x%0*lX%s ==\r\n", - infrared_get_protocol_name(message->protocol), - ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), - message->address, - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), - message->command, - message->repeat ? " R" : ""); - } else { - const uint32_t* timings; - size_t timings_cnt; - infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt); - snprintf( - infrared_monitor->display_text, - sizeof(infrared_monitor->display_text), - "RAW\n%d samples\n", - timings_cnt); - view_port_update(infrared_monitor->view_port); - printf("RAW, %d samples:\r\n", timings_cnt); - for(size_t i = 0; i < timings_cnt; ++i) { - printf("%lu ", timings[i]); - } - printf("\r\n"); - } -} - -int32_t infrared_monitor_app(void* p) { - (void)p; - - InfraredMonitor* infrared_monitor = malloc(sizeof(InfraredMonitor)); - infrared_monitor->display_text[0] = 0; - infrared_monitor->event_queue = osMessageQueueNew(1, sizeof(InputEvent), NULL); - infrared_monitor->view_port = view_port_alloc(); - Gui* gui = furi_record_open("gui"); - - view_port_draw_callback_set( - infrared_monitor->view_port, infrared_monitor_draw_callback, infrared_monitor); - view_port_input_callback_set( - infrared_monitor->view_port, infrared_monitor_input_callback, infrared_monitor); - - gui_add_view_port(gui, infrared_monitor->view_port, GuiLayerFullscreen); - - infrared_monitor->worker = infrared_worker_alloc(); - infrared_worker_rx_start(infrared_monitor->worker); - infrared_worker_rx_set_received_signal_callback( - infrared_monitor->worker, signal_received_callback, infrared_monitor); - infrared_worker_rx_enable_blink_on_receiving(infrared_monitor->worker, true); - - while(1) { - InputEvent event; - if(osOK == osMessageQueueGet(infrared_monitor->event_queue, &event, NULL, 50)) { - if((event.type == InputTypeShort) && (event.key == InputKeyBack)) { - break; - } - } - } - - infrared_worker_rx_stop(infrared_monitor->worker); - infrared_worker_free(infrared_monitor->worker); - osMessageQueueDelete(infrared_monitor->event_queue); - view_port_enabled_set(infrared_monitor->view_port, false); - gui_remove_view_port(gui, infrared_monitor->view_port); - view_port_free(infrared_monitor->view_port); - furi_record_close("gui"); - free(infrared_monitor); - - return 0; -} From f060d005f4d7f78f1eb1578d45ca0ff773c7153f Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 21 Jun 2022 16:25:05 +0300 Subject: [PATCH 04/17] [FL-2511] Updater: fixed long update descriptions overlapping UI elements #1327 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/updater/scenes/updater_scene_loadcfg.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/applications/updater/scenes/updater_scene_loadcfg.c b/applications/updater/scenes/updater_scene_loadcfg.c index 8e477b14..1fd87d00 100644 --- a/applications/updater/scenes/updater_scene_loadcfg.c +++ b/applications/updater/scenes/updater_scene_loadcfg.c @@ -29,14 +29,16 @@ void updater_scene_loadcfg_on_enter(void* context) { widget_add_string_element( updater->widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, "Update"); - widget_add_string_multiline_element( + widget_add_text_box_element( updater->widget, - 64, + 5, + 20, + 118, 32, AlignCenter, AlignCenter, - FontSecondary, - string_get_cstr(pending_upd->manifest->version)); + string_get_cstr(pending_upd->manifest->version), + true); widget_add_button_element( updater->widget, From dab1313a3bada3ab77d3a6baa79d388426b0015a Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Tue, 21 Jun 2022 17:30:30 +0400 Subject: [PATCH 05/17] SubGhz: frequency analyzer combined frequency detection method (#1321) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../subghz_frequency_analyzer_worker.c | 68 ++++++++++++------- .../subghz_frequency_analyzer_worker.h | 6 +- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/applications/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/subghz/helpers/subghz_frequency_analyzer_worker.c index 69e59759..43acf034 100644 --- a/applications/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -67,7 +67,8 @@ static uint32_t subghz_frequency_analyzer_worker_expRunningAverageAdaptive( static int32_t subghz_frequency_analyzer_worker_thread(void* context) { SubGhzFrequencyAnalyzerWorker* instance = context; - FrequencyRSSI frequency_rssi = {.frequency = 0, .rssi = 0}; + FrequencyRSSI frequency_rssi = { + .frequency_coarse = 0, .rssi_coarse = 0, .frequency_fine = 0, .rssi_fine = 0}; float rssi = 0; uint32_t frequency = 0; CC1101Status status; @@ -105,7 +106,8 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { float rssi_avg = 0; size_t rssi_avg_samples = 0; - frequency_rssi.rssi = -127.0f; + frequency_rssi.rssi_coarse = -127.0f; + frequency_rssi.rssi_fine = -127.0f; furi_hal_subghz_idle(); subghz_frequency_analyzer_worker_load_registers(subghz_preset_ook_650khz); @@ -137,9 +139,9 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { if(rssi < rssi_min) rssi_min = rssi; - if(frequency_rssi.rssi < rssi) { - frequency_rssi.rssi = rssi; - frequency_rssi.frequency = frequency; + if(frequency_rssi.rssi_coarse < rssi) { + frequency_rssi.rssi_coarse = rssi; + frequency_rssi.frequency_coarse = frequency; } } } @@ -148,20 +150,17 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { TAG, "RSSI: avg %f, max %f at %u, min %f", (double)(rssi_avg / rssi_avg_samples), - (double)frequency_rssi.rssi, - frequency_rssi.frequency, + (double)frequency_rssi.rssi_coarse, + frequency_rssi.frequency_coarse, (double)rssi_min); // Second stage: fine scan - if(frequency_rssi.rssi > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) { - FURI_LOG_D(TAG, "~:%u:%f", frequency_rssi.frequency, (double)frequency_rssi.rssi); - - frequency_rssi.rssi = -127.0; + if(frequency_rssi.rssi_coarse > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) { furi_hal_subghz_idle(); subghz_frequency_analyzer_worker_load_registers(subghz_preset_ook_58khz); - //-0.3 ... 433.92 ... +0.3 step 10KHz - for(uint32_t i = frequency_rssi.frequency - 300000; - i < frequency_rssi.frequency + 300000; + //for example -0.3 ... 433.92 ... +0.3 step 20KHz + for(uint32_t i = frequency_rssi.frequency_coarse - 300000; + i < frequency_rssi.frequency_coarse + 300000; i += 20000) { if(furi_hal_subghz_is_frequency_valid(i)) { furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); @@ -183,28 +182,51 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { FURI_LOG_T(TAG, "#:%u:%f", frequency, (double)rssi); - if(frequency_rssi.rssi < rssi) { - frequency_rssi.rssi = rssi; - frequency_rssi.frequency = frequency; + if(frequency_rssi.rssi_fine < rssi) { + frequency_rssi.rssi_fine = rssi; + frequency_rssi.frequency_fine = frequency; } } } } - // Deliver results - if(frequency_rssi.rssi > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) { - FURI_LOG_D(TAG, "=:%u:%f", frequency_rssi.frequency, (double)frequency_rssi.rssi); + // Deliver results fine + if(frequency_rssi.rssi_fine > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) { + FURI_LOG_D( + TAG, "=:%u:%f", frequency_rssi.frequency_fine, (double)frequency_rssi.rssi_fine); instance->sample_hold_counter = 20; if(instance->filVal) { - frequency_rssi.frequency = + frequency_rssi.frequency_fine = subghz_frequency_analyzer_worker_expRunningAverageAdaptive( - instance, frequency_rssi.frequency); + instance, frequency_rssi.frequency_fine); } // Deliver callback if(instance->pair_callback) { instance->pair_callback( - instance->context, frequency_rssi.frequency, frequency_rssi.rssi); + instance->context, frequency_rssi.frequency_fine, frequency_rssi.rssi_fine); + } + } else if( // Deliver results coarse + (frequency_rssi.rssi_coarse > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) && + (instance->sample_hold_counter < 10)) { + FURI_LOG_D( + TAG, + "~:%u:%f", + frequency_rssi.frequency_coarse, + (double)frequency_rssi.rssi_coarse); + + instance->sample_hold_counter = 20; + if(instance->filVal) { + frequency_rssi.frequency_coarse = + subghz_frequency_analyzer_worker_expRunningAverageAdaptive( + instance, frequency_rssi.frequency_coarse); + } + // Deliver callback + if(instance->pair_callback) { + instance->pair_callback( + instance->context, + frequency_rssi.frequency_coarse, + frequency_rssi.rssi_coarse); } } else { if(instance->sample_hold_counter > 0) { diff --git a/applications/subghz/helpers/subghz_frequency_analyzer_worker.h b/applications/subghz/helpers/subghz_frequency_analyzer_worker.h index 424270a0..50687c76 100644 --- a/applications/subghz/helpers/subghz_frequency_analyzer_worker.h +++ b/applications/subghz/helpers/subghz_frequency_analyzer_worker.h @@ -9,8 +9,10 @@ typedef void ( *SubGhzFrequencyAnalyzerWorkerPairCallback)(void* context, uint32_t frequency, float rssi); typedef struct { - uint32_t frequency; - float rssi; + uint32_t frequency_coarse; + float rssi_coarse; + uint32_t frequency_fine; + float rssi_fine; } FrequencyRSSI; /** Allocate SubGhzFrequencyAnalyzerWorker From 4b02a404badac4efa86a1793ca28c627c0629f53 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Tue, 21 Jun 2022 16:46:39 +0300 Subject: [PATCH 06/17] [FL-2588] RPC storage: Ignore incorrect file names #1318 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/rpc/rpc_storage.c | 95 +++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 20 deletions(-) diff --git a/applications/rpc/rpc_storage.c b/applications/rpc/rpc_storage.c index e6a59ea8..624d7c7b 100644 --- a/applications/rpc/rpc_storage.c +++ b/applications/rpc/rpc_storage.c @@ -100,6 +100,35 @@ static PB_CommandStatus rpc_system_storage_get_file_error(File* file) { return rpc_system_storage_get_error(storage_file_get_error(file)); } +static bool rpc_system_storage_is_filename_correct(const char* path) { + const char* name_pos = strrchr(path, '/'); + if(name_pos == NULL) { + name_pos = path; + } else { + name_pos++; + } + + while(*name_pos != '\0') { + if((*name_pos >= '0') && (*name_pos <= '9')) { + name_pos++; + continue; + } else if((*name_pos >= 'A') && (*name_pos <= 'Z')) { + name_pos++; + continue; + } else if((*name_pos >= 'a') && (*name_pos <= 'z')) { + name_pos++; + continue; + } else if(strchr(".!#\\$%&'()-@^_`{}~", *name_pos) != NULL) { + name_pos++; + continue; + } + + return false; + } + + return true; +} + static void rpc_system_storage_info_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(context); @@ -245,18 +274,23 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex FileInfo fileinfo; char* name = malloc(MAX_NAME_LENGTH + 1); if(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) { - if(i == COUNT_OF(list->file)) { - list->file_count = i; - response.has_next = true; - rpc_send_and_release(session, &response); - i = 0; + if(rpc_system_storage_is_filename_correct(name)) { + if(i == COUNT_OF(list->file)) { + list->file_count = i; + response.has_next = true; + rpc_send_and_release(session, &response); + i = 0; + } + list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? + PB_Storage_File_FileType_DIR : + PB_Storage_File_FileType_FILE; + list->file[i].size = fileinfo.size; + list->file[i].data = NULL; + list->file[i].name = name; + ++i; + } else { + free(name); } - list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? PB_Storage_File_FileType_DIR : - PB_Storage_File_FileType_FILE; - list->file[i].size = fileinfo.size; - list->file[i].data = NULL; - list->file[i].name = name; - ++i; } else { list->file_count = i; finish = true; @@ -345,6 +379,14 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte bool result = true; + if(!rpc_system_storage_is_filename_correct(request->content.storage_write_request.path)) { + rpc_storage->current_command_id = request->command_id; + rpc_send_and_release_empty( + session, rpc_storage->current_command_id, PB_CommandStatus_ERROR_STORAGE_INVALID_NAME); + rpc_system_storage_reset_state(rpc_storage, session, false); + return; + } + if((request->command_id != rpc_storage->current_command_id) && (rpc_storage->state == RpcStorageStateWriting)) { rpc_system_storage_reset_state(rpc_storage, session, true); @@ -384,13 +426,18 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte static bool rpc_system_storage_is_dir_is_empty(Storage* fs_api, const char* path) { FileInfo fileinfo; - bool is_dir_is_empty = false; + bool is_dir_is_empty = true; FS_Error error = storage_common_stat(fs_api, path, &fileinfo); if((error == FSE_OK) && (fileinfo.flags & FSF_DIRECTORY)) { File* dir = storage_file_alloc(fs_api); if(storage_dir_open(dir, path)) { char* name = malloc(MAX_NAME_LENGTH); - is_dir_is_empty = !storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH); + while(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) { + if(rpc_system_storage_is_filename_correct(name)) { + is_dir_is_empty = false; + break; + } + } free(name); } storage_dir_close(dir); @@ -458,8 +505,12 @@ static void rpc_system_storage_mkdir_process(const PB_Main* request, void* conte Storage* fs_api = furi_record_open("storage"); char* path = request->content.storage_mkdir_request.path; if(path) { - FS_Error error = storage_common_mkdir(fs_api, path); - status = rpc_system_storage_get_error(error); + if(rpc_system_storage_is_filename_correct(path)) { + FS_Error error = storage_common_mkdir(fs_api, path); + status = rpc_system_storage_get_error(error); + } else { + status = PB_CommandStatus_ERROR_STORAGE_INVALID_NAME; + } } else { status = PB_CommandStatus_ERROR_INVALID_PARAMETERS; } @@ -551,11 +602,15 @@ static void rpc_system_storage_rename_process(const PB_Main* request, void* cont Storage* fs_api = furi_record_open("storage"); - FS_Error error = storage_common_rename( - fs_api, - request->content.storage_rename_request.old_path, - request->content.storage_rename_request.new_path); - status = rpc_system_storage_get_error(error); + if(rpc_system_storage_is_filename_correct(request->content.storage_rename_request.new_path)) { + FS_Error error = storage_common_rename( + fs_api, + request->content.storage_rename_request.old_path, + request->content.storage_rename_request.new_path); + status = rpc_system_storage_get_error(error); + } else { + status = PB_CommandStatus_ERROR_STORAGE_INVALID_NAME; + } furi_record_close("storage"); rpc_send_and_release_empty(session, request->command_id, status); From eb31fed0e2a4d0bf07973cd76b86207588d3f29c Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 21 Jun 2022 17:11:34 +0300 Subject: [PATCH 07/17] [FL-2556] Update complete screen (#1332) * Desktop: slideshow implementation * Updater: handling splashscreen installation; added format version field to slideshow binary * Desktop: added bidirectional slideshow navigation + instant cancel by "back" button; Updater: rebalanced update stages weights * Updater: fixed missing field init; fixed potential loop when baking slideshows * Assets: fixed "update complete" image to match original * Desktop: added check for slideshow file version * Scripts: slideshow.py cleanup * Desktop: removed first start intro sequence * Desktop: removed first start remnants --- Makefile | 4 +- applications/desktop/desktop.c | 20 +-- applications/desktop/desktop_i.h | 6 +- applications/desktop/helpers/slideshow.c | 115 ++++++++++++ applications/desktop/helpers/slideshow.h | 13 ++ .../desktop/scenes/desktop_scene_config.h | 2 +- .../scenes/desktop_scene_first_start.c | 54 ------ .../desktop/scenes/desktop_scene_slideshow.c | 45 +++++ applications/desktop/views/desktop_events.h | 5 +- .../desktop/views/desktop_view_first_start.c | 166 ------------------ .../desktop/views/desktop_view_first_start.h | 20 --- .../desktop/views/desktop_view_slideshow.c | 108 ++++++++++++ .../desktop/views/desktop_view_slideshow.h | 20 +++ applications/updater/util/update_task.c | 15 +- applications/updater/util/update_task.h | 2 + .../updater/util/update_task_worker_backup.c | 13 ++ assets/slideshow/update_default/frame_00.png | Bin 0 -> 2211 bytes assets/splash.mk | 3 + lib/update_util/update_manifest.c | 6 + lib/update_util/update_manifest.h | 1 + scripts/bin2dfu.py | 4 +- scripts/slideshow.py | 61 +++++++ scripts/update.py | 20 +++ 23 files changed, 437 insertions(+), 266 deletions(-) create mode 100644 applications/desktop/helpers/slideshow.c create mode 100644 applications/desktop/helpers/slideshow.h delete mode 100644 applications/desktop/scenes/desktop_scene_first_start.c create mode 100644 applications/desktop/scenes/desktop_scene_slideshow.c delete mode 100644 applications/desktop/views/desktop_view_first_start.c delete mode 100644 applications/desktop/views/desktop_view_first_start.h create mode 100644 applications/desktop/views/desktop_view_slideshow.c create mode 100644 applications/desktop/views/desktop_view_slideshow.h create mode 100644 assets/slideshow/update_default/frame_00.png create mode 100644 assets/splash.mk create mode 100644 scripts/slideshow.py diff --git a/Makefile b/Makefile index 8834cba6..a48ed613 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ PROJECT_ROOT := $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))) include $(PROJECT_ROOT)/make/git.mk include $(PROJECT_ROOT)/assets/copro.mk +include $(PROJECT_ROOT)/assets/splash.mk PROJECT_SOURCE_DIRECTORIES := \ $(PROJECT_ROOT)/applications \ @@ -103,7 +104,8 @@ updater_package: firmware_all updater assets_manifest --radio $(COPRO_STACK_BIN_PATH) \ --radiotype $(COPRO_STACK_TYPE) \ $(COPRO_DISCLAIMER) \ - --obdata $(PROJECT_ROOT)/scripts/$(COPRO_OB_DATA) + --obdata $(PROJECT_ROOT)/scripts/$(COPRO_OB_DATA) \ + --splash $(UPDATER_SPLASH_DIR) .PHONY: assets_manifest assets_manifest: diff --git a/applications/desktop/desktop.c b/applications/desktop/desktop.c index 34c169e0..52091753 100644 --- a/applications/desktop/desktop.c +++ b/applications/desktop/desktop.c @@ -158,11 +158,11 @@ Desktop* desktop_alloc() { desktop->lock_menu = desktop_lock_menu_alloc(); desktop->debug_view = desktop_debug_alloc(); - desktop->first_start_view = desktop_first_start_alloc(); desktop->hw_mismatch_popup = popup_alloc(); desktop->locked_view = desktop_view_locked_alloc(); desktop->pin_input_view = desktop_view_pin_input_alloc(); desktop->pin_timeout_view = desktop_view_pin_timeout_alloc(); + desktop->slideshow_view = desktop_view_slideshow_alloc(); desktop->main_view_stack = view_stack_alloc(); desktop->main_view = desktop_main_alloc(); @@ -193,10 +193,6 @@ Desktop* desktop_alloc() { desktop_lock_menu_get_view(desktop->lock_menu)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdDebug, desktop_debug_get_view(desktop->debug_view)); - view_dispatcher_add_view( - desktop->view_dispatcher, - DesktopViewIdFirstStart, - desktop_first_start_get_view(desktop->first_start_view)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdHwMismatch, @@ -209,6 +205,10 @@ Desktop* desktop_alloc() { desktop->view_dispatcher, DesktopViewIdPinInput, desktop_view_pin_input_get_view(desktop->pin_input_view)); + view_dispatcher_add_view( + desktop->view_dispatcher, + DesktopViewIdSlideshow, + desktop_view_slideshow_get_view(desktop->slideshow_view)); // Lock icon desktop->lock_viewport = view_port_alloc(); @@ -258,7 +258,6 @@ void desktop_free(Desktop* desktop) { view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLocked); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdDebug); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdFirstStart); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdHwMismatch); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinInput); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinTimeout); @@ -274,7 +273,6 @@ void desktop_free(Desktop* desktop) { desktop_lock_menu_free(desktop->lock_menu); desktop_view_locked_free(desktop->locked_view); desktop_debug_free(desktop->debug_view); - desktop_first_start_free(desktop->first_start_view); popup_free(desktop->hw_mismatch_popup); desktop_view_pin_timeout_free(desktop->pin_timeout_view); @@ -290,9 +288,9 @@ void desktop_free(Desktop* desktop) { free(desktop); } -static bool desktop_is_first_start() { +static bool desktop_check_file_flag(const char* flag_path) { Storage* storage = furi_record_open("storage"); - bool exists = storage_common_stat(storage, "/int/first_start", NULL) == FSE_OK; + bool exists = storage_common_stat(storage, flag_path, NULL) == FSE_OK; furi_record_close("storage"); return exists; @@ -320,8 +318,8 @@ int32_t desktop_srv(void* p) { desktop_lock(desktop); } - if(desktop_is_first_start()) { - scene_manager_next_scene(desktop->scene_manager, DesktopSceneFirstStart); + if(desktop_check_file_flag("/int/slideshow")) { + scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow); } if(!furi_hal_version_do_i_belong_here()) { diff --git a/applications/desktop/desktop_i.h b/applications/desktop/desktop_i.h index 2888f099..8dc92e84 100644 --- a/applications/desktop/desktop_i.h +++ b/applications/desktop/desktop_i.h @@ -6,9 +6,9 @@ #include "views/desktop_view_pin_input.h" #include "views/desktop_view_locked.h" #include "views/desktop_view_main.h" -#include "views/desktop_view_first_start.h" #include "views/desktop_view_lock_menu.h" #include "views/desktop_view_debug.h" +#include "views/desktop_view_slideshow.h" #include "desktop/desktop_settings/desktop_settings.h" #include @@ -28,10 +28,10 @@ typedef enum { DesktopViewIdLockMenu, DesktopViewIdLocked, DesktopViewIdDebug, - DesktopViewIdFirstStart, DesktopViewIdHwMismatch, DesktopViewIdPinInput, DesktopViewIdPinTimeout, + DesktopViewIdSlideshow, DesktopViewIdTotal, } DesktopViewId; @@ -43,13 +43,13 @@ struct Desktop { ViewDispatcher* view_dispatcher; SceneManager* scene_manager; - DesktopFirstStartView* first_start_view; Popup* hw_mismatch_popup; DesktopLockMenuView* lock_menu; DesktopDebugView* debug_view; DesktopViewLocked* locked_view; DesktopMainView* main_view; DesktopViewPinTimeout* pin_timeout_view; + DesktopSlideshowView* slideshow_view; ViewStack* main_view_stack; ViewStack* locked_view_stack; diff --git a/applications/desktop/helpers/slideshow.c b/applications/desktop/helpers/slideshow.c new file mode 100644 index 00000000..37f66cf3 --- /dev/null +++ b/applications/desktop/helpers/slideshow.c @@ -0,0 +1,115 @@ +#include "slideshow.h" + +#include +#include +#include +#include +#include + +#define SLIDESHOW_MAGIC 0x72676468 +#define SLIDESHOW_MAX_SUPPORTED_VERSION 1 + +struct Slideshow { + Icon icon; + uint32_t current_frame; +}; + +#pragma pack(push, 1) + +typedef struct { + uint32_t magic; + uint8_t version; + uint8_t width; + uint8_t height; + uint8_t frame_count; +} SlideshowFileHeader; +_Static_assert(sizeof(SlideshowFileHeader) == 8, "Incorrect SlideshowFileHeader size"); + +typedef struct { + uint16_t size; +} SlideshowFrameHeader; +_Static_assert(sizeof(SlideshowFrameHeader) == 2, "Incorrect SlideshowFrameHeader size"); + +#pragma pack(pop) + +Slideshow* slideshow_alloc() { + Slideshow* ret = malloc(sizeof(Slideshow)); + return ret; +} + +void slideshow_free(Slideshow* slideshow) { + Icon* icon = &slideshow->icon; + if(icon) { + for(int frame_idx = 0; frame_idx < icon->frame_count; ++frame_idx) { + uint8_t* frame_data = (uint8_t*)icon->frames[frame_idx]; + free(frame_data); + } + free((uint8_t**)icon->frames); + } + free(slideshow); +} + +bool slideshow_load(Slideshow* slideshow, const char* fspath) { + Storage* storage = furi_record_open("storage"); + File* slideshow_file = storage_file_alloc(storage); + bool load_success = false; + do { + if(!storage_file_open(slideshow_file, fspath, FSAM_READ, FSOM_OPEN_EXISTING)) { + break; + } + SlideshowFileHeader header; + if((storage_file_read(slideshow_file, &header, sizeof(header)) != sizeof(header)) || + (header.magic != SLIDESHOW_MAGIC) || + (header.version > SLIDESHOW_MAX_SUPPORTED_VERSION)) { + break; + } + Icon* icon = &slideshow->icon; + FURI_CONST_ASSIGN(icon->frame_count, header.frame_count); + FURI_CONST_ASSIGN(icon->width, header.width); + FURI_CONST_ASSIGN(icon->height, header.height); + icon->frames = malloc(header.frame_count * sizeof(uint8_t*)); + for(int frame_idx = 0; frame_idx < header.frame_count; ++frame_idx) { + SlideshowFrameHeader frame_header; + if(storage_file_read(slideshow_file, &frame_header, sizeof(frame_header)) != + sizeof(frame_header)) { + break; + } + FURI_CONST_ASSIGN_PTR(icon->frames[frame_idx], malloc(frame_header.size)); + uint8_t* frame_data = (uint8_t*)icon->frames[frame_idx]; + if(storage_file_read(slideshow_file, frame_data, frame_header.size) != + frame_header.size) { + break; + } + load_success = (frame_idx + 1) == header.frame_count; + } + } while(false); + storage_file_free(slideshow_file); + furi_record_close("storage"); + return load_success; +} + +bool slideshow_advance(Slideshow* slideshow) { + uint8_t next_frame = slideshow->current_frame + 1; + if(next_frame < slideshow->icon.frame_count) { + slideshow->current_frame = next_frame; + return true; + } + return false; +} + +void slideshow_goback(Slideshow* slideshow) { + if(slideshow->current_frame > 0) { + slideshow->current_frame--; + } +} + +void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y) { + furi_assert(slideshow->current_frame < slideshow->icon.frame_count); + canvas_draw_bitmap( + canvas, + x, + y, + slideshow->icon.width, + slideshow->icon.height, + slideshow->icon.frames[slideshow->current_frame]); +} \ No newline at end of file diff --git a/applications/desktop/helpers/slideshow.h b/applications/desktop/helpers/slideshow.h new file mode 100644 index 00000000..db19779a --- /dev/null +++ b/applications/desktop/helpers/slideshow.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct Slideshow Slideshow; + +Slideshow* slideshow_alloc(); + +void slideshow_free(Slideshow* slideshow); +bool slideshow_load(Slideshow* slideshow, const char* fspath); +void slideshow_goback(Slideshow* slideshow); +bool slideshow_advance(Slideshow* slideshow); +void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y); diff --git a/applications/desktop/scenes/desktop_scene_config.h b/applications/desktop/scenes/desktop_scene_config.h index c84d6ff8..c153972b 100644 --- a/applications/desktop/scenes/desktop_scene_config.h +++ b/applications/desktop/scenes/desktop_scene_config.h @@ -1,9 +1,9 @@ ADD_SCENE(desktop, main, Main) ADD_SCENE(desktop, lock_menu, LockMenu) ADD_SCENE(desktop, debug, Debug) -ADD_SCENE(desktop, first_start, FirstStart) ADD_SCENE(desktop, hw_mismatch, HwMismatch) ADD_SCENE(desktop, fault, Fault) ADD_SCENE(desktop, locked, Locked) ADD_SCENE(desktop, pin_input, PinInput) ADD_SCENE(desktop, pin_timeout, PinTimeout) +ADD_SCENE(desktop, slideshow, Slideshow) diff --git a/applications/desktop/scenes/desktop_scene_first_start.c b/applications/desktop/scenes/desktop_scene_first_start.c deleted file mode 100644 index dbdf8919..00000000 --- a/applications/desktop/scenes/desktop_scene_first_start.c +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include - -#include "../desktop_i.h" -#include "../views/desktop_view_first_start.h" -#include "../views/desktop_events.h" - -void desktop_scene_first_start_callback(DesktopEvent event, void* context) { - Desktop* desktop = (Desktop*)context; - view_dispatcher_send_custom_event(desktop->view_dispatcher, event); -} - -void desktop_scene_first_start_on_enter(void* context) { - Desktop* desktop = (Desktop*)context; - DesktopFirstStartView* first_start_view = desktop->first_start_view; - - desktop_first_start_set_callback( - first_start_view, desktop_scene_first_start_callback, desktop); - - view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdFirstStart); -} - -bool desktop_scene_first_start_on_event(void* context, SceneManagerEvent event) { - Desktop* desktop = (Desktop*)context; - bool consumed = false; - Storage* storage = NULL; - Power* power = NULL; - - if(event.type == SceneManagerEventTypeCustom) { - switch(event.event) { - case DesktopFirstStartCompleted: - storage = furi_record_open("storage"); - storage_common_remove(storage, "/int/first_start"); - furi_record_close("storage"); - scene_manager_previous_scene(desktop->scene_manager); - consumed = true; - break; - case DesktopFirstStartPoweroff: - power = furi_record_open("power"); - power_off(power); - furi_record_close("power"); - consumed = true; - break; - - default: - break; - } - } - return consumed; -} - -void desktop_scene_first_start_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/desktop/scenes/desktop_scene_slideshow.c b/applications/desktop/scenes/desktop_scene_slideshow.c new file mode 100644 index 00000000..70080127 --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_slideshow.c @@ -0,0 +1,45 @@ +#include + +#include "../desktop_i.h" +#include "../views/desktop_view_slideshow.h" +#include "../views/desktop_events.h" + +void desktop_scene_slideshow_callback(DesktopEvent event, void* context) { + Desktop* desktop = (Desktop*)context; + view_dispatcher_send_custom_event(desktop->view_dispatcher, event); +} + +void desktop_scene_slideshow_on_enter(void* context) { + Desktop* desktop = (Desktop*)context; + DesktopSlideshowView* slideshow_view = desktop->slideshow_view; + + desktop_view_slideshow_set_callback(slideshow_view, desktop_scene_slideshow_callback, desktop); + + view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdSlideshow); +} + +bool desktop_scene_slideshow_on_event(void* context, SceneManagerEvent event) { + Desktop* desktop = (Desktop*)context; + bool consumed = false; + Storage* storage = NULL; + + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case DesktopSlideshowCompleted: + storage = furi_record_open("storage"); + storage_common_remove(storage, "/int/slideshow"); + furi_record_close("storage"); + scene_manager_previous_scene(desktop->scene_manager); + consumed = true; + break; + + default: + break; + } + } + return consumed; +} + +void desktop_scene_slideshow_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/desktop/views/desktop_events.h b/applications/desktop/views/desktop_events.h index bbb6ff62..4ff5f795 100644 --- a/applications/desktop/views/desktop_events.h +++ b/applications/desktop/views/desktop_events.h @@ -26,9 +26,6 @@ typedef enum { DesktopDebugEventSaveState, DesktopDebugEventExit, - DesktopFirstStartCompleted, - DesktopFirstStartPoweroff, - DesktopLockMenuEventLock, DesktopLockMenuEventPinLock, DesktopLockMenuEventExit, @@ -37,6 +34,8 @@ typedef enum { DesktopAnimationEventNewIdleAnimation, DesktopAnimationEventInteractAnimation, + DesktopSlideshowCompleted, + // Global events DesktopGlobalBeforeAppStarted, DesktopGlobalAfterAppFinished, diff --git a/applications/desktop/views/desktop_view_first_start.c b/applications/desktop/views/desktop_view_first_start.c deleted file mode 100644 index 87c07ad2..00000000 --- a/applications/desktop/views/desktop_view_first_start.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include - -#include "../desktop_i.h" -#include "desktop_view_first_start.h" - -#define DESKTOP_FIRST_START_POWEROFF_SHORT 5000 -#define DESKTOP_FIRST_START_POWEROFF_LONG (60 * 60 * 1000) - -struct DesktopFirstStartView { - View* view; - DesktopFirstStartViewCallback callback; - void* context; - osTimerId_t timer; -}; - -typedef struct { - uint8_t page; -} DesktopFirstStartViewModel; - -static void desktop_first_start_draw(Canvas* canvas, void* model) { - DesktopFirstStartViewModel* m = model; - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - uint8_t width = canvas_width(canvas); - uint8_t height = canvas_height(canvas); - const char* my_name = furi_hal_version_get_name_ptr(); - if(m->page == 0) { - canvas_draw_icon(canvas, 0, height - 51, &I_DolphinFirstStart0_70x53); - elements_multiline_text_framed( - canvas, 75, 16 + STATUS_BAR_Y_SHIFT, "Hey m8,\npress > to\ncontinue"); - } else if(m->page == 1) { - canvas_draw_icon(canvas, 0, height - 51, &I_DolphinFirstStart1_59x53); - elements_multiline_text_framed( - canvas, 64, 16 + STATUS_BAR_Y_SHIFT, "First Of All,\n... >"); - } else if(m->page == 2) { - canvas_draw_icon(canvas, 0, height - 51, &I_DolphinFirstStart2_59x51); - elements_multiline_text_framed( - canvas, 64, 16 + STATUS_BAR_Y_SHIFT, "Thank you\nfor your\nsupport! >"); - } else if(m->page == 3) { - canvas_draw_icon(canvas, width - 57, height - 45, &I_DolphinFirstStart3_57x48); - elements_multiline_text_framed( - canvas, 0, 16 + STATUS_BAR_Y_SHIFT, "Kickstarter\ncampaign\nwas INSANE! >"); - } else if(m->page == 4) { - canvas_draw_icon(canvas, width - 67, height - 51, &I_DolphinFirstStart4_67x53); - elements_multiline_text_framed( - canvas, 0, 13 + STATUS_BAR_Y_SHIFT, "Now\nallow me\nto introduce\nmyself >"); - } else if(m->page == 5) { - char buf[64]; - snprintf( - buf, - 64, - "%s %s%s", - "I am", - my_name ? my_name : "Unknown", - ",\ncyberdolphin\nliving in your\npocket >"); - canvas_draw_icon(canvas, 0, height - 49, &I_DolphinFirstStart5_54x49); - elements_multiline_text_framed(canvas, 60, 13 + STATUS_BAR_Y_SHIFT, buf); - } else if(m->page == 6) { - canvas_draw_icon(canvas, 0, height - 51, &I_DolphinFirstStart6_58x54); - elements_multiline_text_framed( - canvas, - 63, - 13 + STATUS_BAR_Y_SHIFT, - "I can grow\nsmart'n'cool\nif you use me\noften >"); - } else if(m->page == 7) { - canvas_draw_icon(canvas, width - 61, height - 51, &I_DolphinFirstStart7_61x51); - elements_multiline_text_framed( - canvas, 0, 13 + STATUS_BAR_Y_SHIFT, "As long as\nyou read, write\nand emulate >"); - } else if(m->page == 8) { - canvas_draw_icon(canvas, width - 56, height - 51, &I_DolphinFirstStart8_56x51); - elements_multiline_text_framed( - canvas, - 0, - 13 + STATUS_BAR_Y_SHIFT, - "You can check\nmy level and\nmood in the\nPassport menu"); - } -} - -static bool desktop_first_start_input(InputEvent* event, void* context) { - furi_assert(event); - DesktopFirstStartView* instance = context; - - if(event->type == InputTypeShort) { - DesktopFirstStartViewModel* model = view_get_model(instance->view); - if(event->key == InputKeyLeft) { - if(model->page > 0) model->page--; - } else if(event->key == InputKeyRight) { - uint32_t page = ++model->page; - if(page > 8) { - instance->callback(DesktopFirstStartCompleted, instance->context); - } - } - view_commit_model(instance->view, true); - } - - if(event->key == InputKeyOk) { - if(event->type == InputTypePress) { - osTimerStart(instance->timer, DESKTOP_FIRST_START_POWEROFF_SHORT); - } else if(event->type == InputTypeRelease) { - osTimerStop(instance->timer); - } - } - - return true; -} - -static void desktop_first_start_timer_callback(void* context) { - DesktopFirstStartView* instance = context; - instance->callback(DesktopFirstStartPoweroff, instance->context); -} - -static void desktop_first_start_enter(void* context) { - DesktopFirstStartView* instance = context; - - furi_assert(instance->timer == NULL); - instance->timer = osTimerNew(desktop_first_start_timer_callback, osTimerOnce, instance, NULL); - - osTimerStart(instance->timer, DESKTOP_FIRST_START_POWEROFF_LONG); -} - -static void desktop_first_start_exit(void* context) { - DesktopFirstStartView* instance = context; - - osTimerStop(instance->timer); - osTimerDelete(instance->timer); - instance->timer = NULL; -} - -DesktopFirstStartView* desktop_first_start_alloc() { - DesktopFirstStartView* instance = malloc(sizeof(DesktopFirstStartView)); - instance->view = view_alloc(); - view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(DesktopFirstStartViewModel)); - view_set_context(instance->view, instance); - view_set_draw_callback(instance->view, (ViewDrawCallback)desktop_first_start_draw); - view_set_input_callback(instance->view, desktop_first_start_input); - view_set_enter_callback(instance->view, desktop_first_start_enter); - view_set_exit_callback(instance->view, desktop_first_start_exit); - - return instance; -} - -void desktop_first_start_free(DesktopFirstStartView* instance) { - furi_assert(instance); - - view_free(instance->view); - free(instance); -} - -View* desktop_first_start_get_view(DesktopFirstStartView* instance) { - furi_assert(instance); - return instance->view; -} - -void desktop_first_start_set_callback( - DesktopFirstStartView* instance, - DesktopFirstStartViewCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - instance->callback = callback; - instance->context = context; -} diff --git a/applications/desktop/views/desktop_view_first_start.h b/applications/desktop/views/desktop_view_first_start.h deleted file mode 100644 index 9b7b3c93..00000000 --- a/applications/desktop/views/desktop_view_first_start.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -#include "desktop_events.h" - -typedef struct DesktopFirstStartView DesktopFirstStartView; - -typedef void (*DesktopFirstStartViewCallback)(DesktopEvent event, void* context); - -DesktopFirstStartView* desktop_first_start_alloc(); - -void desktop_first_start_free(DesktopFirstStartView* main_view); - -View* desktop_first_start_get_view(DesktopFirstStartView* main_view); - -void desktop_first_start_set_callback( - DesktopFirstStartView* main_view, - DesktopFirstStartViewCallback callback, - void* context); diff --git a/applications/desktop/views/desktop_view_slideshow.c b/applications/desktop/views/desktop_view_slideshow.c new file mode 100644 index 00000000..97f779b5 --- /dev/null +++ b/applications/desktop/views/desktop_view_slideshow.c @@ -0,0 +1,108 @@ +#include +#include +#include + +#include "../desktop_i.h" +#include "desktop_view_slideshow.h" +#include "../helpers/slideshow.h" + +struct DesktopSlideshowView { + View* view; + DesktopSlideshowViewCallback callback; + void* context; +}; + +typedef struct { + uint8_t page; + Slideshow* slideshow; +} DesktopSlideshowViewModel; + +static void desktop_view_slideshow_draw(Canvas* canvas, void* model) { + DesktopSlideshowViewModel* m = model; + + canvas_clear(canvas); + slideshow_draw(m->slideshow, canvas, 0, 0); +} + +static bool desktop_view_slideshow_input(InputEvent* event, void* context) { + furi_assert(event); + DesktopSlideshowView* instance = context; + + if(event->type == InputTypeShort) { + DesktopSlideshowViewModel* model = view_get_model(instance->view); + bool end_slideshow = false; + switch(event->key) { + case InputKeyLeft: + slideshow_goback(model->slideshow); + break; + case InputKeyRight: + case InputKeyOk: + end_slideshow = !slideshow_advance(model->slideshow); + break; + case InputKeyBack: + end_slideshow = true; + default: + break; + } + if(end_slideshow) { + instance->callback(DesktopSlideshowCompleted, instance->context); + } + view_commit_model(instance->view, true); + } + + return true; +} + +static void desktop_view_slideshow_enter(void* context) { + DesktopSlideshowView* instance = context; + + DesktopSlideshowViewModel* model = view_get_model(instance->view); + model->slideshow = slideshow_alloc(); + if(!slideshow_load(model->slideshow, "/int/slideshow")) { + instance->callback(DesktopSlideshowCompleted, instance->context); + } + view_commit_model(instance->view, false); +} + +static void desktop_view_slideshow_exit(void* context) { + DesktopSlideshowView* instance = context; + + DesktopSlideshowViewModel* model = view_get_model(instance->view); + slideshow_free(model->slideshow); + view_commit_model(instance->view, false); +} + +DesktopSlideshowView* desktop_view_slideshow_alloc() { + DesktopSlideshowView* instance = malloc(sizeof(DesktopSlideshowView)); + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(DesktopSlideshowViewModel)); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, (ViewDrawCallback)desktop_view_slideshow_draw); + view_set_input_callback(instance->view, desktop_view_slideshow_input); + view_set_enter_callback(instance->view, desktop_view_slideshow_enter); + view_set_exit_callback(instance->view, desktop_view_slideshow_exit); + + return instance; +} + +void desktop_view_slideshow_free(DesktopSlideshowView* instance) { + furi_assert(instance); + + view_free(instance->view); + free(instance); +} + +View* desktop_view_slideshow_get_view(DesktopSlideshowView* instance) { + furi_assert(instance); + return instance->view; +} + +void desktop_view_slideshow_set_callback( + DesktopSlideshowView* instance, + DesktopSlideshowViewCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + instance->callback = callback; + instance->context = context; +} \ No newline at end of file diff --git a/applications/desktop/views/desktop_view_slideshow.h b/applications/desktop/views/desktop_view_slideshow.h new file mode 100644 index 00000000..5b45a6b7 --- /dev/null +++ b/applications/desktop/views/desktop_view_slideshow.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "desktop_events.h" + +typedef struct DesktopSlideshowView DesktopSlideshowView; + +typedef void (*DesktopSlideshowViewCallback)(DesktopEvent event, void* context); + +DesktopSlideshowView* desktop_view_slideshow_alloc(); + +void desktop_view_slideshow_free(DesktopSlideshowView* main_view); + +View* desktop_view_slideshow_get_view(DesktopSlideshowView* main_view); + +void desktop_view_slideshow_set_callback( + DesktopSlideshowView* main_view, + DesktopSlideshowViewCallback callback, + void* context); diff --git a/applications/updater/util/update_task.c b/applications/updater/util/update_task.c index 58b0c975..316fe680 100644 --- a/applications/updater/util/update_task.c +++ b/applications/updater/util/update_task.c @@ -24,6 +24,7 @@ static const char* update_task_stage_descr[] = { [UpdateTaskStageLfsBackup] = "Backing up LFS", [UpdateTaskStageLfsRestore] = "Restoring LFS", [UpdateTaskStageResourcesUpdate] = "Updating resources", + [UpdateTaskStageSplashscreenInstall] = "Installing splashscreen", [UpdateTaskStageCompleted] = "Restarting...", [UpdateTaskStageError] = "Error", [UpdateTaskStageOBError] = "OB, report", @@ -41,13 +42,13 @@ static const UpdateTaskStageGroupMap update_task_stage_progress[] = { [UpdateTaskStageProgress] = STAGE_DEF(UpdateTaskStageGroupMisc, 0), [UpdateTaskStageReadManifest] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 5), - [UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 30), + [UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 15), - [UpdateTaskStageRadioImageValidate] = STAGE_DEF(UpdateTaskStageGroupRadio, 30), + [UpdateTaskStageRadioImageValidate] = STAGE_DEF(UpdateTaskStageGroupRadio, 10), [UpdateTaskStageRadioErase] = STAGE_DEF(UpdateTaskStageGroupRadio, 50), - [UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 100), - [UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 5), - [UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 70), + [UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 90), + [UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 15), + [UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 60), [UpdateTaskStageOBValidation] = STAGE_DEF(UpdateTaskStageGroupOptionBytes, 10), @@ -58,6 +59,7 @@ static const UpdateTaskStageGroupMap update_task_stage_progress[] = { [UpdateTaskStageLfsRestore] = STAGE_DEF(UpdateTaskStageGroupPostUpdate, 30), [UpdateTaskStageResourcesUpdate] = STAGE_DEF(UpdateTaskStageGroupResources, 255), + [UpdateTaskStageSplashscreenInstall] = STAGE_DEF(UpdateTaskStageGroupSplashscreen, 5), [UpdateTaskStageCompleted] = STAGE_DEF(UpdateTaskStageGroupMisc, 1), [UpdateTaskStageError] = STAGE_DEF(UpdateTaskStageGroupMisc, 1), @@ -79,6 +81,9 @@ static UpdateTaskStageGroup update_task_get_task_groups(UpdateTask* update_task) if(!string_empty_p(manifest->resource_bundle)) { ret |= UpdateTaskStageGroupResources; } + if(!string_empty_p(manifest->splash_file)) { + ret |= UpdateTaskStageGroupSplashscreen; + } return ret; } diff --git a/applications/updater/util/update_task.h b/applications/updater/util/update_task.h index ac9dadd6..1f291556 100644 --- a/applications/updater/util/update_task.h +++ b/applications/updater/util/update_task.h @@ -33,6 +33,7 @@ typedef enum { UpdateTaskStageLfsRestore, UpdateTaskStageResourcesUpdate, + UpdateTaskStageSplashscreenInstall, UpdateTaskStageCompleted, UpdateTaskStageError, @@ -52,6 +53,7 @@ typedef enum { UpdateTaskStageGroupRadio = 1 << 4, UpdateTaskStageGroupPostUpdate = 1 << 5, UpdateTaskStageGroupResources = 1 << 6, + UpdateTaskStageGroupSplashscreen = 1 << 7, } UpdateTaskStageGroup; typedef struct { diff --git a/applications/updater/util/update_task_worker_backup.c b/applications/updater/util/update_task_worker_backup.c index 011510ed..f1ce5281 100644 --- a/applications/updater/util/update_task_worker_backup.c +++ b/applications/updater/util/update_task_worker_backup.c @@ -93,6 +93,19 @@ static bool update_task_post_update(UpdateTask* update_task) { CHECK_RESULT(tar_archive_unpack_to(archive, EXT_PATH)); } } + + if(update_task->state.groups & UpdateTaskStageGroupSplashscreen) { + update_task_set_progress(update_task, UpdateTaskStageSplashscreenInstall, 0); + string_t tmp_path; + string_init_set(tmp_path, update_task->update_path); + path_append(tmp_path, string_get_cstr(update_task->manifest->splash_file)); + if(storage_common_copy( + update_task->storage, string_get_cstr(tmp_path), "/int/slideshow") != FSE_OK) { + // actually, not critical + } + string_clear(tmp_path); + update_task_set_progress(update_task, UpdateTaskStageSplashscreenInstall, 100); + } success = true; } while(false); diff --git a/assets/slideshow/update_default/frame_00.png b/assets/slideshow/update_default/frame_00.png new file mode 100644 index 0000000000000000000000000000000000000000..385fbbe061539ecd682922a07996d5b5ad23bfd9 GIT binary patch literal 2211 zcmbVOdrT8|94~D{53CHZTNM2Sf&>Bq zML?34G?C%CzBNQk_SP~j&` zJVS~cZ|6AANV;t!Rv=udK%u!-l45<5-FZ?-VHL(qii`o4k`K}j4m+kJaFBoXJE)RC z(Gb+i(X6vF0>$MhCdW}brY6)n0#&{Q1*J!mBKay{tCg_$1d;SnjKyq#fl~^WrNQ2M zm6LShat(!RxoJx`!_6z8nIjUSDa73R5`f78Q7R}I@)k>Wf z!!k{JbC%MKXKGL^OM_DF#TMF}gshjM*O;G`EQL(Of_P-4Rlv+@#ON zfH@5M@&yGTEJT`Eqk~OHLdklWmk@5$qzg^aVQnx*!3yY&3~^}{`4BKZuqzM7e2IE{ z3-|!_SZphzO)Yp7P zRX@MbICGh{rX{812W?#OKy=3EdrFFD0l|KGh1HCvNv_IiT*b z9oW11DeITjdI>}qxIJJEgp(Xlo|aLs33KX>lF_2)p>_1V2iYo07@J#u8nwT0c+ zi)s#J#mU=>n&;?ZHF1~gOo!sQ)+X22lUhn|%(3)e-FRy0)f?m~Z+35O>ifQNoYXxAO6^L@uaeCaI5|7?9P(*-2NkV&sN#j zu|gwpcCr27*-5w7AKvoSv%!+WyhApsF5#P>mc-7Qu|K%LnD}=xT1zKB8@v~r*p**# zXaDJ=71RH^-SEb&cY9hcSEn8PcyM2v_jb)&+Z6TP{+m0NSSMExbl+U|MJYP*!p*f4 zR=s{6y&Lxl);;m)y2f@(QhdXQrp3#@Pxe5kR?LZd98)+o`Z(EVX=;45HLm@Ve2?!u zotm4r2&t~W6qDLC)hSGv_F&%g>^)7oGbzeIrOT#W2{$|}JpE5GYPpq@e^+<>arVyV z=QPKX{oJp;GinPCMm^d1X%!Tc%bg+mH*ZqB`Q2n=c3@ztY$$41{C3;v^{SQ9{{l;9 Kp1C=rwB}#tL-H*E literal 0 HcmV?d00001 diff --git a/assets/splash.mk b/assets/splash.mk new file mode 100644 index 00000000..6b01b5c3 --- /dev/null +++ b/assets/splash.mk @@ -0,0 +1,3 @@ +ASSETS_DIR ?= $(PROJECT_ROOT)/assets +UPDATER_SPLASH ?= update_default +UPDATER_SPLASH_DIR := $(ASSETS_DIR)/slideshow/$(UPDATER_SPLASH) diff --git a/lib/update_util/update_manifest.c b/lib/update_util/update_manifest.c index 2fe0a1ef..d1ac0d7d 100644 --- a/lib/update_util/update_manifest.c +++ b/lib/update_util/update_manifest.c @@ -17,6 +17,7 @@ #define MANIFEST_KEY_OB_REFERENCE "OB reference" #define MANIFEST_KEY_OB_MASK "OB mask" #define MANIFEST_KEY_OB_WRITE_MASK "OB write mask" +#define MANIFEST_KEY_SPLASH_FILE "Splashscreen" UpdateManifest* update_manifest_alloc() { UpdateManifest* update_manifest = malloc(sizeof(UpdateManifest)); @@ -25,6 +26,7 @@ UpdateManifest* update_manifest_alloc() { string_init(update_manifest->radio_image); string_init(update_manifest->staged_loader_file); string_init(update_manifest->resource_bundle); + string_init(update_manifest->splash_file); update_manifest->target = 0; update_manifest->manifest_version = 0; memset(update_manifest->ob_reference.bytes, 0, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES); @@ -41,6 +43,7 @@ void update_manifest_free(UpdateManifest* update_manifest) { string_clear(update_manifest->radio_image); string_clear(update_manifest->staged_loader_file); string_clear(update_manifest->resource_bundle); + string_clear(update_manifest->splash_file); free(update_manifest); } @@ -107,6 +110,9 @@ static bool update_manifest->ob_write_mask.bytes, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES); + flipper_format_read_string( + flipper_file, MANIFEST_KEY_SPLASH_FILE, update_manifest->splash_file); + update_manifest->valid = (!string_empty_p(update_manifest->firmware_dfu_image) || !string_empty_p(update_manifest->radio_image) || diff --git a/lib/update_util/update_manifest.h b/lib/update_util/update_manifest.h index 2b1e6857..2b0c9179 100644 --- a/lib/update_util/update_manifest.h +++ b/lib/update_util/update_manifest.h @@ -42,6 +42,7 @@ typedef struct { FuriHalFlashRawOptionByteData ob_reference; FuriHalFlashRawOptionByteData ob_compare_mask; FuriHalFlashRawOptionByteData ob_write_mask; + string_t splash_file; bool valid; } UpdateManifest; diff --git a/scripts/bin2dfu.py b/scripts/bin2dfu.py index 62554f69..d27b44aa 100755 --- a/scripts/bin2dfu.py +++ b/scripts/bin2dfu.py @@ -38,9 +38,9 @@ class Main(App): return 1 with open(self.args.input, mode="rb") as file: - bin = file.read() + bindata = file.read() - data = struct.pack(" Date: Tue, 21 Jun 2022 17:45:55 +0300 Subject: [PATCH 08/17] [FL-2548] Infrared: show error if no SD card/databases (#1337) * Add Database error scene * More general popup callback name --- applications/infrared/infrared.c | 8 ++-- applications/infrared/infrared_custom_event.h | 2 +- applications/infrared/infrared_i.h | 4 +- .../infrared/scenes/infrared_scene_config.h | 1 + .../scenes/infrared_scene_edit_delete_done.c | 4 +- .../scenes/infrared_scene_edit_rename_done.c | 4 +- .../scenes/infrared_scene_error_databases.c | 37 +++++++++++++++++++ .../scenes/infrared_scene_learn_done.c | 4 +- .../scenes/infrared_scene_universal_tv.c | 2 +- .../notification/notification_messages.c | 9 +++++ .../notification/notification_messages.h | 3 ++ 11 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 applications/infrared/scenes/infrared_scene_error_databases.c diff --git a/applications/infrared/infrared.c b/applications/infrared/infrared.c index ee6b931e..e641302c 100644 --- a/applications/infrared/infrared.c +++ b/applications/infrared/infrared.c @@ -8,7 +8,9 @@ static const NotificationSequence* infrared_notification_sequences[] = { &sequence_set_only_green_255, &sequence_reset_green, &sequence_blink_cyan_10, - &sequence_blink_magenta_10}; + &sequence_blink_magenta_10, + &sequence_solid_yellow, + &sequence_reset_rgb}; static void infrared_make_app_folder(Infrared* infrared) { if(!storage_simply_mkdir(infrared->storage, INFRARED_APP_FOLDER)) { @@ -360,11 +362,11 @@ void infrared_text_input_callback(void* context) { infrared->view_dispatcher, InfraredCustomEventTypeTextEditDone); } -void infrared_popup_timeout_callback(void* context) { +void infrared_popup_closed_callback(void* context) { furi_assert(context); Infrared* infrared = context; view_dispatcher_send_custom_event( - infrared->view_dispatcher, InfraredCustomEventTypePopupTimeout); + infrared->view_dispatcher, InfraredCustomEventTypePopupClosed); } int32_t infrared_app(void* p) { diff --git a/applications/infrared/infrared_custom_event.h b/applications/infrared/infrared_custom_event.h index d991afb9..46d75a9e 100644 --- a/applications/infrared/infrared_custom_event.h +++ b/applications/infrared/infrared_custom_event.h @@ -11,7 +11,7 @@ enum InfraredCustomEventType { InfraredCustomEventTypeTransmitStopped, InfraredCustomEventTypeSignalReceived, InfraredCustomEventTypeTextEditDone, - InfraredCustomEventTypePopupTimeout, + InfraredCustomEventTypePopupClosed, InfraredCustomEventTypeButtonSelected, InfraredCustomEventTypeBackPressed, }; diff --git a/applications/infrared/infrared_i.h b/applications/infrared/infrared_i.h index 06c6a5f7..5c447adc 100644 --- a/applications/infrared/infrared_i.h +++ b/applications/infrared/infrared_i.h @@ -113,6 +113,8 @@ typedef enum { InfraredNotificationMessageGreenOff, InfraredNotificationMessageBlinkRead, InfraredNotificationMessageBlinkSend, + InfraredNotificationMessageYellowOn, + InfraredNotificationMessageYellowOff, } InfraredNotificationMessage; bool infrared_add_remote_with_button(Infrared* infrared, const char* name, InfraredSignal* signal); @@ -129,4 +131,4 @@ void infrared_show_loading_popup(Infrared* infrared, bool show); void infrared_signal_sent_callback(void* context); void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal); void infrared_text_input_callback(void* context); -void infrared_popup_timeout_callback(void* context); +void infrared_popup_closed_callback(void* context); diff --git a/applications/infrared/scenes/infrared_scene_config.h b/applications/infrared/scenes/infrared_scene_config.h index 3677ab3c..c4e083c1 100644 --- a/applications/infrared/scenes/infrared_scene_config.h +++ b/applications/infrared/scenes/infrared_scene_config.h @@ -15,3 +15,4 @@ ADD_SCENE(infrared, remote_list, RemoteList) ADD_SCENE(infrared, universal, Universal) ADD_SCENE(infrared, universal_tv, UniversalTV) ADD_SCENE(infrared, debug, Debug) +ADD_SCENE(infrared, error_databases, ErrorDatabases) diff --git a/applications/infrared/scenes/infrared_scene_edit_delete_done.c b/applications/infrared/scenes/infrared_scene_edit_delete_done.c index 688c3a45..4502abbd 100644 --- a/applications/infrared/scenes/infrared_scene_edit_delete_done.c +++ b/applications/infrared/scenes/infrared_scene_edit_delete_done.c @@ -7,7 +7,7 @@ void infrared_scene_edit_delete_done_on_enter(void* context) { popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); - popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -21,7 +21,7 @@ bool infrared_scene_edit_delete_done_on_event(void* context, SceneManagerEvent e bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == InfraredCustomEventTypePopupTimeout) { + if(event.event == InfraredCustomEventTypePopupClosed) { const InfraredEditTarget edit_target = infrared->app_state.edit_target; if(edit_target == InfraredEditTargetButton) { scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/infrared/scenes/infrared_scene_edit_rename_done.c b/applications/infrared/scenes/infrared_scene_edit_rename_done.c index 60a26954..54b18ab6 100644 --- a/applications/infrared/scenes/infrared_scene_edit_rename_done.c +++ b/applications/infrared/scenes/infrared_scene_edit_rename_done.c @@ -7,7 +7,7 @@ void infrared_scene_edit_rename_done_on_enter(void* context) { popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); - popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -20,7 +20,7 @@ bool infrared_scene_edit_rename_done_on_event(void* context, SceneManagerEvent e bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == InfraredCustomEventTypePopupTimeout) { + if(event.event == InfraredCustomEventTypePopupClosed) { scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); consumed = true; } diff --git a/applications/infrared/scenes/infrared_scene_error_databases.c b/applications/infrared/scenes/infrared_scene_error_databases.c new file mode 100644 index 00000000..4ed4dee5 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_error_databases.c @@ -0,0 +1,37 @@ +#include "../infrared_i.h" + +void infrared_scene_error_databases_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + + popup_set_icon(popup, 5, 11, &I_SDQuestion_35x43); + popup_set_text( + popup, "Function requires\nSD card with fresh\ndatabases.", 47, 17, AlignLeft, AlignTop); + + popup_set_context(popup, context); + popup_set_callback(popup, infrared_popup_closed_callback); + + infrared_play_notification_message(infrared, InfraredNotificationMessageYellowOn); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_error_databases_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypePopupClosed) { + scene_manager_search_and_switch_to_previous_scene( + infrared->scene_manager, InfraredSceneUniversal); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_error_databases_on_exit(void* context) { + Infrared* infrared = context; + popup_reset(infrared->popup); + infrared_play_notification_message(infrared, InfraredNotificationMessageYellowOff); +} diff --git a/applications/infrared/scenes/infrared_scene_learn_done.c b/applications/infrared/scenes/infrared_scene_learn_done.c index a24bb918..eb6cced8 100644 --- a/applications/infrared/scenes/infrared_scene_learn_done.c +++ b/applications/infrared/scenes/infrared_scene_learn_done.c @@ -15,7 +15,7 @@ void infrared_scene_learn_done_on_enter(void* context) { popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); } - popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -28,7 +28,7 @@ bool infrared_scene_learn_done_on_event(void* context, SceneManagerEvent event) bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == InfraredCustomEventTypePopupTimeout) { + if(event.event == InfraredCustomEventTypePopupClosed) { scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); consumed = true; } diff --git a/applications/infrared/scenes/infrared_scene_universal_tv.c b/applications/infrared/scenes/infrared_scene_universal_tv.c index f3a9a06b..83b084c3 100644 --- a/applications/infrared/scenes/infrared_scene_universal_tv.c +++ b/applications/infrared/scenes/infrared_scene_universal_tv.c @@ -98,7 +98,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { infrared_show_loading_popup(infrared, false); if(!success) { - scene_manager_previous_scene(infrared->scene_manager); + scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases); } } diff --git a/applications/notification/notification_messages.c b/applications/notification/notification_messages.c index b14c08e3..b469cb5f 100644 --- a/applications/notification/notification_messages.c +++ b/applications/notification/notification_messages.c @@ -335,6 +335,15 @@ const NotificationSequence sequence_set_blue_255 = { NULL, }; +// Solid colors +const NotificationSequence sequence_solid_yellow = { + &message_red_255, + &message_green_255, + &message_blue_0, + &message_do_not_reset, + NULL, +}; + // Blink const NotificationSequence sequence_blink_blue_10 = { &message_blue_255, diff --git a/applications/notification/notification_messages.h b/applications/notification/notification_messages.h index a0ef654e..92a105f6 100644 --- a/applications/notification/notification_messages.h +++ b/applications/notification/notification_messages.h @@ -103,6 +103,9 @@ extern const NotificationSequence sequence_set_red_255; extern const NotificationSequence sequence_set_green_255; extern const NotificationSequence sequence_set_blue_255; +// Solid colors +extern const NotificationSequence sequence_solid_yellow; + // Blink extern const NotificationSequence sequence_blink_blue_10; extern const NotificationSequence sequence_blink_red_10; From 88facf20c15f416551a2960dab0e22f09216e749 Mon Sep 17 00:00:00 2001 From: Kevin Wallace <184975+kevinwallace@users.noreply.github.com> Date: Tue, 21 Jun 2022 07:58:22 -0700 Subject: [PATCH 09/17] nfc: DESFire fixes (#1334) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: don't give up on reading DESFire card if GET_KEY_SETTINGS fails Some cards are configured to refuse to provide key settings, but still provide other info. For example, Ubiquiti UniFi Protect access cards won't list keys or applications, but will still answer GET_FREE_MEMORY. * nfc: don't show error when saving DESFire card with no applications * nfc: fix DESFire load with 0 applications or no PICC key settings Co-authored-by: Kevin Wallace Co-authored-by: gornekich Co-authored-by: あく --- applications/nfc/nfc_device.c | 67 +++++++++++++++++++---------------- applications/nfc/nfc_worker.c | 41 +++++++++++---------- 2 files changed, 56 insertions(+), 52 deletions(-) diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index 51e14a6c..d5cc422f 100644 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -495,16 +495,17 @@ static bool nfc_device_save_mifare_df_data(FlipperFormat* file, NfcDevice* dev) n_apps++; } if(!flipper_format_write_uint32(file, "Application Count", &n_apps, 1)) break; - if(n_apps == 0) break; - tmp = malloc(n_apps * 3); - int i = 0; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - memcpy(tmp + i, app->id, 3); - i += 3; - } - if(!flipper_format_write_hex(file, "Application IDs", tmp, n_apps * 3)) break; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - if(!nfc_device_save_mifare_df_app(file, app)) break; + if(n_apps) { + tmp = malloc(n_apps * 3); + int i = 0; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + memcpy(tmp + i, app->id, 3); + i += 3; + } + if(!flipper_format_write_hex(file, "Application IDs", tmp, n_apps * 3)) break; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + if(!nfc_device_save_mifare_df_app(file, app)) break; + } } saved = true; } while(false); @@ -532,32 +533,36 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { break; } } - data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); - memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); - if(!nfc_device_load_mifare_df_key_settings(file, data->master_key_settings, "PICC")) { - free(data->master_key_settings); - data->master_key_settings = NULL; - break; + if(flipper_format_key_exist(file, "PICC Change Key ID")) { + data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); + memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); + if(!nfc_device_load_mifare_df_key_settings(file, data->master_key_settings, "PICC")) { + free(data->master_key_settings); + data->master_key_settings = NULL; + break; + } } uint32_t n_apps; if(!flipper_format_read_uint32(file, "Application Count", &n_apps, 1)) break; - tmp = malloc(n_apps * 3); - if(!flipper_format_read_hex(file, "Application IDs", tmp, n_apps * 3)) break; - bool parsed_apps = true; - MifareDesfireApplication** app_head = &data->app_head; - for(uint32_t i = 0; i < n_apps; i++) { - MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication)); - memset(app, 0, sizeof(MifareDesfireApplication)); - memcpy(app->id, &tmp[i * 3], 3); - if(!nfc_device_load_mifare_df_app(file, app)) { - free(app); - parsed_apps = false; - break; + if(n_apps) { + tmp = malloc(n_apps * 3); + if(!flipper_format_read_hex(file, "Application IDs", tmp, n_apps * 3)) break; + bool parsed_apps = true; + MifareDesfireApplication** app_head = &data->app_head; + for(uint32_t i = 0; i < n_apps; i++) { + MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication)); + memset(app, 0, sizeof(MifareDesfireApplication)); + memcpy(app->id, &tmp[i * 3], 3); + if(!nfc_device_load_mifare_df_app(file, app)) { + free(app); + parsed_apps = false; + break; + } + *app_head = app; + app_head = &app->next; } - *app_head = app; - app_head = &app->next; + if(!parsed_apps) break; } - if(!parsed_apps) break; parsed = true; } while(false); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 8c8512f3..11b6b51e 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -576,28 +576,27 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); free(data->master_key_settings); data->master_key_settings = NULL; - continue; - } - - MifareDesfireKeyVersion** key_version_head = - &data->master_key_settings->key_version_head; - for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { - tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange getting key version"); - continue; + } else { + MifareDesfireKeyVersion** key_version_head = + &data->master_key_settings->key_version_head; + for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { + tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting key version"); + continue; + } + MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); + memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); + key_version->id = key_id; + if(!mf_df_parse_get_key_version_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { + FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); + free(key_version); + continue; + } + *key_version_head = key_version; + key_version_head = &key_version->next; } - MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); - memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); - key_version->id = key_id; - if(!mf_df_parse_get_key_version_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { - FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); - free(key_version); - continue; - } - *key_version_head = key_version; - key_version_head = &key_version->next; } } From 556af0b82b4965c3def35ef2779d37b153038f4d Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Tue, 21 Jun 2022 09:04:35 -0600 Subject: [PATCH 10/17] nfc: NTAG21x complete emulation (#1313) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: Refactor Mifare Ultralight feature flags Unify them in both reader and emulator to make handling easier * nfc: Refactor MFUL PWD_AUTH and add AUTHLIM counter * nfc: Add MFUL EV1 VCSL command emulation * nfc: Enforce message size check in MFUL emulation Also fix READ_CNT byte order, but it's not fully working * nfc: Add MFUL auth counter serialization Also fill counter on successful read from tag * nfc: Fix MFUL INCR_CNT emulation * nfc: Fix MFUL READ_CNT emulation * nfc: Refactor MFUL emulation and implement full write support * nfc: Fix Mifare Ultralight serialization * nfc: Add MFUL OTP/CC handling * nfc: Make sure MF0UL21 dynamic lock byte 3 also reads 0xBD * nfc: Small MFUL refactor and fix CFGLCK behavior * WIP: nfc: MFUL read support with ASCII mirror and auth roll-over This is too complex and I don't like it * nfc: Simplify MFUL read emulation, fix mirror range check * nfc: Implement MFUL auth and ASCII mirror for FAST_READ * nfc: Fix MFUL read roll-over with AUTH0 set * nfc: Implement MFUL read counter increment * nfc: Align ASCII mirror to NTAG21x behavior * nfc: Handle invalid command in MFUL emulation * nfc: Fix MFUL static lock check * nfc: Refactor MFUL emulation to use cached config pages * nfc: Refactor MFUL auth counter to count up instead of down * nfc: Add missing NULL check * WIP: nfc: Various MFUL emulation behavior tweaks * WIP: nfc: More MFUL emulation behavior adjustments * nfc: Match AUTHLIM emulation to NTAG21x behavior * nfc: Fix MFUL dynamic lock emulation * nfc: Fix typo in MFUL read counters * nfc: Fix typo in MFUL FAST_READ emulation * nfc: Increase emulation TX buffer size Enough space for if someone requests FAST_READ of all pages of an NTAG * nfc: Fix MFUL negative verification counter overflow * nfc: Change auth counter kv name * nfc: Fix NTAG I2C FAST_READ emulation * nfc: Fix NTAG21x config reload behavior Co-authored-by: あく --- applications/nfc/nfc_device.c | 12 + applications/nfc/nfc_worker.c | 6 +- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 2 +- lib/nfc_protocols/mifare_ultralight.c | 1179 ++++++++++++++----- lib/nfc_protocols/mifare_ultralight.h | 85 +- 5 files changed, 957 insertions(+), 327 deletions(-) diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index d5cc422f..092d0089 100644 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -120,6 +120,12 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) } } if(!pages_saved) break; + + // Write authentication counter + uint32_t auth_counter = data->curr_authlim; + if(!flipper_format_write_uint32(file, "Failed authentication attempts", &auth_counter, 1)) + break; + saved = true; } while(false); @@ -169,6 +175,12 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { } } if(!pages_parsed) break; + + // Read authentication counter + uint32_t auth_counter; + if(!flipper_format_read_uint32(file, "Failed authentication attempts", &auth_counter, 1)) + auth_counter = 0; + parsed = true; } while(false); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 11b6b51e..176b15c6 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -319,11 +319,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { MfUltralightEmulator emulator = {}; mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data); while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) { - emulator.auth_success = false; - if(emulator.data.type >= MfUltralightTypeNTAGI2C1K) { - // Sector index needs to be reset - emulator.curr_sector = 0; - } + mf_ul_reset_emulation(&emulator, true); furi_hal_nfc_emulate_nfca( nfc_data->uid, nfc_data->uid_len, diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 3e6d18eb..cba2a703 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -277,7 +277,7 @@ bool furi_hal_nfc_emulate_nfca( uint8_t buff_rx[256]; uint16_t buff_rx_size = 256; uint16_t buff_rx_len = 0; - uint8_t buff_tx[256]; + uint8_t buff_tx[1040]; uint16_t buff_tx_len = 0; uint32_t data_type = FURI_HAL_NFC_TXRX_DEFAULT; diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc_protocols/mifare_ultralight.c index fb425ea7..21dbd9c4 100644 --- a/lib/nfc_protocols/mifare_ultralight.c +++ b/lib/nfc_protocols/mifare_ultralight.c @@ -12,13 +12,38 @@ bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { return false; } +static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { + switch(type) { + case MfUltralightTypeUL11: + case MfUltralightTypeUL21: + return MfUltralightSupportFastRead | MfUltralightSupportCompatWrite | + MfUltralightSupportReadCounter | MfUltralightSupportIncrCounter | + MfUltralightSupportAuth | MfUltralightSupportSignature | + MfUltralightSupportTearingFlags | MfUltralightSupportVcsl; + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + return MfUltralightSupportFastRead | MfUltralightSupportCompatWrite | + MfUltralightSupportReadCounter | MfUltralightSupportAuth | + MfUltralightSupportSignature | MfUltralightSupportSingleCounter | + MfUltralightSupportAsciiMirror; + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2C2K: + return MfUltralightSupportFastRead | MfUltralightSupportSectorSelect; + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + return MfUltralightSupportFastRead | MfUltralightSupportAuth | + MfUltralightSupportFastWrite | MfUltralightSupportSignature | + MfUltralightSupportSectorSelect; + default: + // Assumed original MFUL 512-bit + return MfUltralightSupportNone; + } +} + static void mf_ul_set_default_version(MfUltralightReader* reader, MfUltralightData* data) { data->type = MfUltralightTypeUnknown; reader->pages_to_read = 16; - reader->support_fast_read = false; - reader->support_tearing_flags = false; - reader->support_counters = false; - reader->support_signature = false; } bool mf_ultralight_read_version( @@ -44,31 +69,15 @@ bool mf_ultralight_read_version( if(version->storage_size == 0x0B || version->storage_size == 0x00) { data->type = MfUltralightTypeUL11; reader->pages_to_read = 20; - reader->support_fast_read = true; - reader->support_tearing_flags = true; - reader->support_counters = true; - reader->support_signature = true; } else if(version->storage_size == 0x0E) { data->type = MfUltralightTypeUL21; reader->pages_to_read = 41; - reader->support_fast_read = true; - reader->support_tearing_flags = true; - reader->support_counters = true; - reader->support_signature = true; } else if(version->storage_size == 0x0F) { data->type = MfUltralightTypeNTAG213; reader->pages_to_read = 45; - reader->support_fast_read = true; - reader->support_tearing_flags = false; - reader->support_counters = false; - reader->support_signature = true; } else if(version->storage_size == 0x11) { data->type = MfUltralightTypeNTAG215; reader->pages_to_read = 135; - reader->support_fast_read = true; - reader->support_tearing_flags = false; - reader->support_counters = false; - reader->support_signature = true; } else if(version->prod_subtype == 5 && version->prod_ver_major == 2) { // NTAG I2C bool known = false; @@ -76,42 +85,30 @@ bool mf_ultralight_read_version( if(version->storage_size == 0x13) { data->type = MfUltralightTypeNTAGI2C1K; reader->pages_to_read = 231; - reader->support_signature = false; known = true; } else if(version->storage_size == 0x15) { data->type = MfUltralightTypeNTAGI2C2K; reader->pages_to_read = 485; - reader->support_signature = false; known = true; } } else if(version->prod_ver_minor == 2) { if(version->storage_size == 0x13) { data->type = MfUltralightTypeNTAGI2CPlus1K; reader->pages_to_read = 236; - reader->support_signature = true; known = true; } else if(version->storage_size == 0x15) { data->type = MfUltralightTypeNTAGI2CPlus2K; reader->pages_to_read = 492; - reader->support_signature = true; known = true; } } - if(known) { - reader->support_fast_read = true; - reader->support_tearing_flags = false; - reader->support_counters = false; - } else { + if(!known) { mf_ul_set_default_version(reader, data); } } else if(version->storage_size == 0x13) { data->type = MfUltralightTypeNTAG216; reader->pages_to_read = 231; - reader->support_fast_read = true; - reader->support_tearing_flags = false; - reader->support_counters = false; - reader->support_signature = true; } else { mf_ul_set_default_version(reader, data); break; @@ -119,9 +116,14 @@ bool mf_ultralight_read_version( version_read = true; } while(false); + reader->supported_features = mf_ul_get_features(data->type); return version_read; } +static int16_t mf_ultralight_page_addr_to_tag_addr(uint8_t sector, uint8_t page) { + return sector * 256 + page; +} + static int16_t mf_ultralight_ntag_i2c_addr_lin_to_tag_1k( int16_t linear_address, uint8_t* sector, @@ -404,6 +406,41 @@ static int16_t mf_ultralight_ntag_i2c_addr_tag_to_lin( } } +static MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data) { + if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) { + return (MfUltralightConfigPages*)&data->data[data->data_size - 4 * 4]; + } else if( + data->type >= MfUltralightTypeNTAGI2CPlus1K && + data->type <= MfUltralightTypeNTAGI2CPlus2K) { + return (MfUltralightConfigPages*)&data->data[0xe3 * 4]; + } else { + return NULL; + } +} + +static uint16_t mf_ultralight_calc_auth_count(MfUltralightData* data) { + if(mf_ul_get_features(data->type) & MfUltralightSupportAuth) { + MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data); + uint16_t scaled_authlim = config->access.authlim; + // NTAG I2C Plus uses 2^AUTHLIM attempts rather than the direct number + if(scaled_authlim > 0 && data->type >= MfUltralightTypeNTAGI2CPlus1K && + data->type <= MfUltralightTypeNTAGI2CPlus2K) { + scaled_authlim = 1 << scaled_authlim; + } + return scaled_authlim; + } + + return 0; +} + +// NTAG21x will NAK if NFC_CNT_EN unset, so preempt +static bool mf_ultralight_should_read_counters(MfUltralightData* data) { + if(data->type < MfUltralightTypeNTAG213 || data->type > MfUltralightTypeNTAG216) return true; + + MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data); + return config->access.nfc_cnt_en; +} + static bool mf_ultralight_sector_select(FuriHalNfcTxRxContext* tx_rx, uint8_t sector) { FURI_LOG_D(TAG, "Selecting sector %u", sector); tx_rx->tx_data[0] = MF_UL_SECTOR_SELECT; @@ -455,7 +492,7 @@ bool mf_ultralight_read_pages( tx_rx->tx_data[1] = tag_page; tx_rx->tx_bits = 16; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; - if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { + if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits < 16 * 8) { FURI_LOG_D( TAG, "Failed to read pages %d - %d", @@ -540,9 +577,11 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* uint8_t counter_read = 0; FURI_LOG_D(TAG, "Reading counters"); - for(size_t i = 0; i < 3; i++) { + bool is_single_counter = (mf_ul_get_features(data->type) & MfUltralightSupportSingleCounter) != + 0; + for(size_t i = is_single_counter ? 2 : 0; i < 3; i++) { tx_rx->tx_data[0] = MF_UL_READ_CNT; - tx_rx->rx_data[1] = i; + tx_rx->tx_data[1] = i; tx_rx->tx_bits = 16; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { @@ -554,7 +593,7 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* counter_read++; } - return counter_read == 2; + return counter_read == (is_single_counter ? 1 : 3); } bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) { @@ -589,38 +628,26 @@ bool mf_ul_read_card( // Read Mifare Ultralight version if(mf_ultralight_read_version(tx_rx, reader, data)) { - if(reader->support_signature) { + if(reader->supported_features & MfUltralightSupportSignature) { // Read Signature mf_ultralight_read_signature(tx_rx, data); } } - if(reader->support_counters) { - mf_ultralight_read_counters(tx_rx, data); - } - if(reader->support_tearing_flags) { - mf_ultralight_read_tearing_flags(tx_rx, data); - } + card_read = mf_ultralight_read_pages(tx_rx, reader, data); - return card_read; -} - -// TODO rework -static void mf_ul_protect_auth_data_on_read_command( - uint8_t* tx_buff, - uint8_t start_page, - uint8_t end_page, - MfUltralightEmulator* emulator) { - if(emulator->data.type >= MfUltralightTypeNTAG213) { - uint8_t pwd_page = (emulator->data.data_size / 4) - 2; - uint8_t pack_page = pwd_page + 1; - if((start_page <= pwd_page) && (end_page >= pwd_page)) { - memset(&tx_buff[(pwd_page - start_page) * 4], 0, 4); + if(card_read) { + if(reader->supported_features & MfUltralightSupportReadCounter && + mf_ultralight_should_read_counters(data)) { + mf_ultralight_read_counters(tx_rx, data); } - if((start_page <= pack_page) && (end_page >= pack_page)) { - memset(&tx_buff[(pack_page - start_page) * 4], 0, 2); + if(reader->supported_features & MfUltralightSupportTearingFlags) { + mf_ultralight_read_tearing_flags(tx_rx, data); } + data->curr_authlim = 0; } + + return card_read; } static void mf_ul_protect_auth_data_on_read_command_i2c( @@ -639,9 +666,8 @@ static void mf_ul_protect_auth_data_on_read_command_i2c( // Handle AUTH0 for sector 0 if(!emulator->auth_success) { - uint8_t access = emulator->data.data[228 * 4]; - if(access & 0x80) { - uint8_t auth0 = emulator->data.data[227 * 4 + 3]; + if(emulator->config_cache.access.prot) { + uint8_t auth0 = emulator->config_cache.auth0; if(auth0 < end_page) { // start_page is always < auth0; otherwise is NAK'd already uint8_t page_offset = auth0 - start_page; @@ -704,16 +730,29 @@ static void mf_ul_ntag_i2c_fill_cross_area_read( } } +static bool mf_ul_check_auth(MfUltralightEmulator* emulator, uint8_t start_page, bool is_write) { + if(!emulator->auth_success) { + if(start_page >= emulator->config_cache.auth0 && + (emulator->config_cache.access.prot || is_write)) + return false; + } + + if(is_write && emulator->config_cache.access.cfglck) { + uint16_t config_start_page = emulator->page_num - 4; + if(start_page == config_start_page || start_page == config_start_page + 1) return false; + } + + return true; +} + static bool mf_ul_ntag_i2c_plus_check_auth( MfUltralightEmulator* emulator, uint8_t start_page, bool is_write) { if(!emulator->auth_success) { - uint8_t access = emulator->data.data[228 * 4]; // Check NFC_PROT - if(emulator->curr_sector == 0 && ((access & 0x80) || is_write)) { - uint8_t auth0 = emulator->data.data[227 * 4 + 3]; - if(start_page >= auth0) return false; + if(emulator->curr_sector == 0 && (emulator->config_cache.access.prot || is_write)) { + if(start_page >= emulator->config_cache.auth0) return false; } else if(emulator->curr_sector == 1) { // We don't have to specifically check for type because this is done // by address translator @@ -725,43 +764,288 @@ static bool mf_ul_ntag_i2c_plus_check_auth( if(emulator->curr_sector == 1) { // Check NFC_DIS_SEC1 - uint8_t access = emulator->data.data[228 * 4]; - if(access & 0x20) return false; + if(emulator->config_cache.access.nfc_dis_sec1) return false; } return true; } +static int16_t mf_ul_get_dynamic_lock_page_addr(MfUltralightData* data) { + switch(data->type) { + case MfUltralightTypeUL21: + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + return data->data_size / 4 - 5; + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + return 0xe2; + case MfUltralightTypeNTAGI2C2K: + return 0x1e0; + default: + return -1; // No dynamic lock bytes + } +} + +// Returns true if page not locked +// write_page is tag address +static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) { + if(write_page < 2) return false; // Page 0-1 is always locked + if(write_page == 2) return true; // Page 2 does not have a lock flag + + // Check static lock bytes + if(write_page <= 15) { + uint16_t static_lock_bytes = emulator->data.data[10] | (emulator->data.data[11] << 8); + return (static_lock_bytes & (1 << write_page)) == 0; + } + + // Check dynamic lock bytes + + // Check max page + switch(emulator->data.type) { + case MfUltralightTypeUL21: + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + if(write_page >= emulator->page_num - 5) return true; + break; + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2CPlus1K: + if(write_page > 225) return true; + break; + case MfUltralightTypeNTAGI2C2K: + if(write_page > 479) return true; + break; + case MfUltralightTypeNTAGI2CPlus2K: + if(write_page >= 226 && write_page <= 255) return true; + if(write_page >= 512) return true; + break; + default: + furi_assert(false); + return true; + } + + int16_t dynamic_lock_index = mf_ul_get_dynamic_lock_page_addr(&emulator->data); + if(dynamic_lock_index == -1) return true; + // Run address through converter because NTAG I2C 2K is special + uint16_t valid_pages; // unused + dynamic_lock_index = + mf_ultralight_ntag_i2c_addr_tag_to_lin( + &emulator->data, dynamic_lock_index & 0xff, dynamic_lock_index >> 8, &valid_pages) * + 4; + + uint16_t dynamic_lock_bytes = emulator->data.data[dynamic_lock_index] | + (emulator->data.data[dynamic_lock_index + 1] << 8); + uint8_t shift; + + switch(emulator->data.type) { + // low byte LSB range, MSB range + case MfUltralightTypeUL21: + case MfUltralightTypeNTAG213: + // 16-17, 30-31 + shift = (write_page - 16) / 2; + break; + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2CPlus1K: + // 16-31, 128-129 + // 16-31, 128-143 + shift = (write_page - 16) / 16; + break; + case MfUltralightTypeNTAGI2C2K: + // 16-47, 240-271 + shift = (write_page - 16) / 32; + break; + case MfUltralightTypeNTAGI2CPlus2K: + // 16-47, 256-271 + if(write_page >= 208 && write_page <= 225) + shift = 6; + else if(write_page >= 256 && write_page <= 271) + shift = 7; + else + shift = (write_page - 16) / 32; + break; + default: + furi_assert(false); + shift = 0; + break; + } + + return (dynamic_lock_bytes & (1 << shift)) == 0; +} + +static void mf_ul_make_ascii_mirror(MfUltralightEmulator* emulator, string_t str) { + // Locals to improve readability + uint8_t mirror_page = emulator->config->mirror_page; + uint8_t mirror_byte = emulator->config->mirror.mirror_byte; + MfUltralightMirrorConf mirror_conf = emulator->config_cache.mirror.mirror_conf; + uint16_t last_user_page_index = emulator->page_num - 6; + bool uid_printed = false; + + if(mirror_conf == MfUltralightMirrorUid || mirror_conf == MfUltralightMirrorUidCounter) { + // UID range check + if(mirror_page < 4 || mirror_page > last_user_page_index - 3 || + (mirror_page == last_user_page_index - 3 && mirror_byte > 2)) { + if(mirror_conf == MfUltralightMirrorUid) return; + // NTAG21x has the peculiar behavior when UID+counter selected, if UID does not fit but + // counter will fit, it will actually mirror the counter + string_cat_str(str, " "); + } else { + for(int i = 0; i < 3; ++i) { + string_cat_printf(str, "%02X", emulator->data.data[i]); + } + // Skip BCC0 + for(int i = 4; i < 8; ++i) { + string_cat_printf(str, "%02X", emulator->data.data[i]); + } + uid_printed = true; + } + + uint16_t next_byte_offset = mirror_page * 4 + mirror_byte + 14; + if(mirror_conf == MfUltralightMirrorUidCounter) ++next_byte_offset; + mirror_page = next_byte_offset / 4; + mirror_byte = next_byte_offset % 4; + } + + if(mirror_conf == MfUltralightMirrorCounter || mirror_conf == MfUltralightMirrorUidCounter) { + // Counter is only printed if counter enabled + if(emulator->config_cache.access.nfc_cnt_en) { + // Counter protection check + if(emulator->config_cache.access.nfc_cnt_pwd_prot && !emulator->auth_success) return; + // Counter range check + if(mirror_page < 4) return; + if(mirror_page > last_user_page_index - 1) return; + if(mirror_page == last_user_page_index - 1 && mirror_byte > 2) return; + + if(mirror_conf == MfUltralightMirrorUidCounter) + string_cat_str(str, uid_printed ? "x" : " "); + + string_cat_printf(str, "%06X", emulator->data.counter[2]); + } + } +} + +static void mf_ul_increment_single_counter(MfUltralightEmulator* emulator) { + if(!emulator->read_counter_incremented && emulator->config_cache.access.nfc_cnt_en) { + if(emulator->data.counter[2] < 0xFFFFFF) { + ++emulator->data.counter[2]; + emulator->data_changed = true; + } + emulator->read_counter_incremented = true; + } +} + +static void mf_ul_emulate_write( + MfUltralightEmulator* emulator, + int16_t tag_addr, + int16_t write_page, + uint8_t* page_buff) { + // Assumption: all access checks have been completed + + if(tag_addr == 2) { + // Handle static locks + uint16_t orig_static_locks = emulator->data.data[write_page * 4 + 2] | + (emulator->data.data[write_page * 4 + 3] << 8); + uint16_t new_static_locks = page_buff[2] | (page_buff[3] << 8); + if(orig_static_locks & 1) new_static_locks &= ~0x08; + if(orig_static_locks & 2) new_static_locks &= ~0xF0; + if(orig_static_locks & 4) new_static_locks &= 0xFF; + new_static_locks |= orig_static_locks; + page_buff[0] = emulator->data.data[write_page * 4]; + page_buff[1] = emulator->data.data[write_page * 4 + 1]; + page_buff[2] = new_static_locks & 0xff; + page_buff[3] = new_static_locks >> 8; + } else if(tag_addr == 3) { + // Handle OTP/capability container + *(uint32_t*)page_buff |= *(uint32_t*)&emulator->data.data[write_page * 4]; + } else if(tag_addr == mf_ul_get_dynamic_lock_page_addr(&emulator->data)) { + // Handle dynamic locks + uint16_t orig_locks = emulator->data.data[write_page * 4] | + (emulator->data.data[write_page * 4 + 1] << 8); + uint8_t orig_block_locks = emulator->data.data[write_page * 4 + 2]; + uint16_t new_locks = page_buff[0] | (page_buff[1] << 8); + uint8_t new_block_locks = page_buff[2]; + + int block_lock_count; + switch(emulator->data.type) { + case MfUltralightTypeUL21: + block_lock_count = 5; + break; + case MfUltralightTypeNTAG213: + block_lock_count = 6; + break; + case MfUltralightTypeNTAG215: + block_lock_count = 4; + break; + case MfUltralightTypeNTAG216: + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2CPlus1K: + block_lock_count = 7; + break; + case MfUltralightTypeNTAGI2C2K: + case MfUltralightTypeNTAGI2CPlus2K: + block_lock_count = 8; + break; + default: + furi_assert(false); + block_lock_count = 0; + break; + } + + for(int i = 0; i < block_lock_count; ++i) { + if(orig_block_locks & (1 << i)) new_locks &= ~(3 << (2 * i)); + } + + new_locks |= orig_locks; + new_block_locks |= orig_block_locks; + + page_buff[0] = new_locks & 0xff; + page_buff[1] = new_locks >> 8; + page_buff[2] = new_block_locks; + if(emulator->data.type >= MfUltralightTypeUL21 && + emulator->data.type <= MfUltralightTypeNTAG216) + page_buff[3] = MF_UL_TEARING_FLAG_DEFAULT; + else + page_buff[3] = 0; + } + + memcpy(&emulator->data.data[write_page * 4], page_buff, 4); + emulator->data_changed = true; +} + +void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) { + emulator->curr_sector = 0; + emulator->ntag_i2c_plus_sector3_lockout = false; + emulator->auth_success = false; + if(is_power_cycle) { + if(emulator->config != NULL) emulator->config_cache = *emulator->config; + + if(emulator->supported_features & MfUltralightSupportSingleCounter) { + emulator->read_counter_incremented = false; + } + } else { + if(emulator->config != NULL) { + // ACCESS (less CFGLCK) and AUTH0 are updated when reactivated + // MIRROR_CONF is not; don't know about STRG_MOD_EN, but we're not using that anyway + emulator->config_cache.access.value = (emulator->config->access.value & 0xBF) | + (emulator->config_cache.access.value & 0x40); + emulator->config_cache.auth0 = emulator->config->auth0; + } + } +} + void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) { FURI_LOG_D(TAG, "Prepare emulation"); emulator->data = *data; - emulator->auth_data = NULL; + emulator->supported_features = mf_ul_get_features(data->type); + emulator->config = mf_ultralight_get_config_pages(&emulator->data); + emulator->page_num = emulator->data.data_size / 4; emulator->data_changed = false; emulator->comp_write_cmd_started = false; emulator->sector_select_cmd_started = false; - emulator->ntag_i2c_plus_sector3_lockout = false; - if(data->type == MfUltralightTypeUnknown) { - emulator->support_fast_read = false; - } else if(data->type == MfUltralightTypeUL11) { - emulator->support_fast_read = true; - } else if(data->type == MfUltralightTypeUL21) { - emulator->support_fast_read = true; - } else if(data->type == MfUltralightTypeNTAG213) { - emulator->support_fast_read = true; - } else if(data->type == MfUltralightTypeNTAG215) { - emulator->support_fast_read = true; - } else if(data->type == MfUltralightTypeNTAG216) { - emulator->support_fast_read = true; - } else if(data->type >= MfUltralightTypeNTAGI2C1K) { - emulator->support_fast_read = true; - } - - if(data->type >= MfUltralightTypeNTAG213 && data->type < MfUltralightTypeNTAGI2C1K) { - uint16_t pwd_page = (data->data_size / 4) - 2; - emulator->auth_data = (MfUltralightAuth*)&data->data[pwd_page * 4]; - } else if(data->type >= MfUltralightTypeNTAGI2CPlus1K) { - emulator->auth_data = (MfUltralightAuth*)&data->data[229 * 4]; - } + mf_ul_reset_emulation(emulator, true); } bool mf_ul_prepare_emulation_response( @@ -773,13 +1057,12 @@ bool mf_ul_prepare_emulation_response( void* context) { furi_assert(context); MfUltralightEmulator* emulator = context; - uint8_t cmd = buff_rx[0]; - uint16_t page_num = emulator->data.data_size / 4; uint16_t tx_bytes = 0; uint16_t tx_bits = 0; bool command_parsed = false; bool send_ack = false; bool respond_nothing = false; + bool reset_idle = false; #ifdef FURI_DEBUG string_t debug_buf; @@ -795,118 +1078,138 @@ bool mf_ul_prepare_emulation_response( // Check composite commands if(emulator->comp_write_cmd_started) { // Compatibility write is the only one composit command - if(buff_rx_len == 16) { - memcpy(&emulator->data.data[emulator->comp_write_page_addr * 4], buff_rx, 4); - emulator->data_changed = true; - // Send ACK message - buff_tx[0] = 0x0A; - tx_bits = 4; - *data_type = FURI_HAL_NFC_TXRX_RAW; + if(buff_rx_len == 16 * 8) { + mf_ul_emulate_write( + emulator, emulator->comp_write_page_addr, emulator->comp_write_page_addr, buff_rx); + send_ack = true; command_parsed = true; } emulator->comp_write_cmd_started = false; } else if(emulator->sector_select_cmd_started) { - if(buff_rx[0] <= 0xFE) { - emulator->curr_sector = buff_rx[0] > 3 ? 0 : buff_rx[0]; - emulator->ntag_i2c_plus_sector3_lockout = false; - command_parsed = true; - respond_nothing = true; - FURI_LOG_D(TAG, "Changing sector to %d", emulator->curr_sector); + if(buff_rx_len == 4 * 8) { + if(buff_rx[0] <= 0xFE) { + emulator->curr_sector = buff_rx[0] > 3 ? 0 : buff_rx[0]; + emulator->ntag_i2c_plus_sector3_lockout = false; + command_parsed = true; + respond_nothing = true; + FURI_LOG_D(TAG, "Changing sector to %d", emulator->curr_sector); + } } emulator->sector_select_cmd_started = false; - } else if(cmd == MF_UL_GET_VERSION_CMD) { - if(emulator->data.type != MfUltralightTypeUnknown) { - tx_bytes = sizeof(emulator->data.version); - memcpy(buff_tx, &emulator->data.version, tx_bytes); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; - } - } else if(cmd == MF_UL_READ_CMD) { - int16_t start_page = buff_rx[1]; - tx_bytes = 16; - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - if(start_page < page_num) { - if(start_page + 4 > page_num) { - // Handle roll-over mechanism - uint8_t end_pages_num = page_num - start_page; - memcpy(buff_tx, &emulator->data.data[start_page * 4], end_pages_num * 4); - memcpy( - &buff_tx[end_pages_num * 4], emulator->data.data, (4 - end_pages_num) * 4); - } else { - memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes); - } - mf_ul_protect_auth_data_on_read_command( - buff_tx, start_page, (start_page + 4), emulator); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; - } - } else { - uint16_t valid_pages; - start_page = mf_ultralight_ntag_i2c_addr_tag_to_lin( - &emulator->data, start_page, emulator->curr_sector, &valid_pages); - if(start_page != -1) { - if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K || - mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], false)) { - if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K && - emulator->curr_sector == 3 && valid_pages == 1) { - // Rewind back a sector to match behavior on a real tag - --start_page; - ++valid_pages; - } - - uint16_t copy_count = (valid_pages > 4 ? 4 : valid_pages) * 4; - FURI_LOG_D( - TAG, - "NTAG I2C Emu: page valid, %02x:%02x -> %d, %d", - emulator->curr_sector, - buff_rx[1], - start_page, - valid_pages); - memcpy(buff_tx, &emulator->data.data[start_page * 4], copy_count); - // For NTAG I2C, there's no roll-over; remainder is filled by null bytes - if(copy_count < tx_bytes) - memset(&buff_tx[copy_count], 0, tx_bytes - copy_count); - // Special case: NTAG I2C Plus sector 0 page 233 read crosses into page 236 - if(start_page == 233) - memcpy(&buff_tx[12], &emulator->data.data[(start_page + 1) * 4], 4); - mf_ul_protect_auth_data_on_read_command_i2c( - buff_tx, start_page, start_page + copy_count / 4 - 1, emulator); + } else if(buff_rx_len >= 8) { + uint8_t cmd = buff_rx[0]; + if(cmd == MF_UL_GET_VERSION_CMD) { + if(emulator->data.type != MfUltralightTypeUnknown) { + if(buff_rx_len == 1 * 8) { + tx_bytes = sizeof(emulator->data.version); + memcpy(buff_tx, &emulator->data.version, tx_bytes); *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; } - } else { - FURI_LOG_D( - TAG, - "NTAG I2C Emu: page invalid, %02x:%02x", - emulator->curr_sector, - buff_rx[1]); - if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K && - emulator->curr_sector == 3 && !emulator->ntag_i2c_plus_sector3_lockout) { - // NTAG I2C Plus has a weird behavior where if you read sector 3 - // at an invalid address, it responds with zeroes then locks - // the read out, while if you read the mirrored session registers, - // it returns both session registers on either pages - memset(buff_tx, 0, tx_bytes); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; - emulator->ntag_i2c_plus_sector3_lockout = true; - } } - } - if(!command_parsed) tx_bytes = 0; - } else if(cmd == MF_UL_FAST_READ_CMD) { - if(emulator->support_fast_read) { - int16_t start_page = buff_rx[1]; - uint8_t end_page = buff_rx[2]; - if(start_page <= end_page) { - tx_bytes = ((end_page + 1) - start_page) * 4; + } else if(cmd == MF_UL_READ_CMD) { + if(buff_rx_len == (1 + 1) * 8) { + int16_t start_page = buff_rx[1]; + tx_bytes = 16; if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - if((start_page < page_num) && (end_page < page_num)) { - memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes); - mf_ul_protect_auth_data_on_read_command( - buff_tx, start_page, end_page, emulator); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; + if(start_page < emulator->page_num) { + do { + uint8_t copied_pages = 0; + uint8_t src_page = start_page; + uint8_t last_page_plus_one = start_page + 4; + uint8_t pwd_page = emulator->page_num - 2; + string_t ascii_mirror; + size_t ascii_mirror_len = 0; + const char* ascii_mirror_cptr = NULL; + uint8_t ascii_mirror_curr_page = 0; + uint8_t ascii_mirror_curr_byte = 0; + if(last_page_plus_one > emulator->page_num) + last_page_plus_one = emulator->page_num; + if(emulator->supported_features & MfUltralightSupportAuth) { + if(!mf_ul_check_auth(emulator, start_page, false)) break; + if(!emulator->auth_success && emulator->config_cache.access.prot && + emulator->config_cache.auth0 < last_page_plus_one) + last_page_plus_one = emulator->config_cache.auth0; + } + if(emulator->supported_features & MfUltralightSupportSingleCounter) + mf_ul_increment_single_counter(emulator); + if(emulator->supported_features & MfUltralightSupportAsciiMirror && + emulator->config_cache.mirror.mirror_conf != + MfUltralightMirrorNone) { + ascii_mirror_curr_byte = emulator->config->mirror.mirror_byte; + ascii_mirror_curr_page = emulator->config->mirror_page; + // Try to avoid wasting time making mirror if we won't copy it + // Conservatively check with UID+counter mirror size + if(last_page_plus_one > ascii_mirror_curr_page && + start_page + 3 >= ascii_mirror_curr_page && + start_page <= ascii_mirror_curr_page + 6) { + string_init(ascii_mirror); + mf_ul_make_ascii_mirror(emulator, ascii_mirror); + ascii_mirror_len = string_length_u(ascii_mirror); + ascii_mirror_cptr = string_get_cstr(ascii_mirror); + // Move pointer to where it should be to start copying + if(ascii_mirror_len > 0 && + ascii_mirror_curr_page < start_page && + ascii_mirror_curr_byte != 0) { + uint8_t diff = 4 - ascii_mirror_curr_byte; + ascii_mirror_len -= diff; + ascii_mirror_cptr += diff; + ascii_mirror_curr_byte = 0; + ++ascii_mirror_curr_page; + } + while(ascii_mirror_len > 0 && + ascii_mirror_curr_page < start_page) { + uint8_t diff = ascii_mirror_len > 4 ? 4 : ascii_mirror_len; + ascii_mirror_len -= diff; + ascii_mirror_cptr += diff; + ++ascii_mirror_curr_page; + } + } + } + + uint8_t* dest_ptr = buff_tx; + while(copied_pages < 4) { + // Copy page + memcpy(dest_ptr, &emulator->data.data[src_page * 4], 4); + + // Note: don't have to worry about roll-over with ASCII mirror because + // lowest valid page for it is 4, while roll-over will at best read + // pages 0-2 + if(ascii_mirror_len > 0 && src_page == ascii_mirror_curr_page) { + // Copy ASCII mirror + size_t copy_len = 4 - ascii_mirror_curr_byte; + if(copy_len > ascii_mirror_len) copy_len = ascii_mirror_len; + for(size_t i = 0; i < copy_len; ++i) { + if(*ascii_mirror_cptr != ' ') + dest_ptr[ascii_mirror_curr_byte] = + (uint8_t)*ascii_mirror_cptr; + ++ascii_mirror_curr_byte; + ++ascii_mirror_cptr; + } + ascii_mirror_len -= copy_len; + // Don't care if this is inaccurate after ascii_mirror_len = 0 + ascii_mirror_curr_byte = 0; + ++ascii_mirror_curr_page; + } + + if(emulator->supported_features & MfUltralightSupportAuth) { + if(src_page == pwd_page || src_page == pwd_page + 1) { + // Blank out PWD and PACK pages + memset(dest_ptr, 0, 4); + } + } + + dest_ptr += 4; + ++copied_pages; + ++src_page; + if(src_page >= last_page_plus_one) src_page = 0; + } + if(ascii_mirror_cptr != NULL) { + string_clear(ascii_mirror); + } + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } while(false); } } else { uint16_t valid_pages; @@ -915,151 +1218,401 @@ bool mf_ul_prepare_emulation_response( if(start_page != -1) { if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K || mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], false)) { + if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K && + emulator->curr_sector == 3 && valid_pages == 1) { + // Rewind back a sector to match behavior on a real tag + --start_page; + ++valid_pages; + } + uint16_t copy_count = (valid_pages > 4 ? 4 : valid_pages) * 4; + FURI_LOG_D( + TAG, + "NTAG I2C Emu: page valid, %02x:%02x -> %d, %d", + emulator->curr_sector, + buff_rx[1], + start_page, + valid_pages); memcpy(buff_tx, &emulator->data.data[start_page * 4], copy_count); + // For NTAG I2C, there's no roll-over; remainder is filled by null bytes if(copy_count < tx_bytes) memset(&buff_tx[copy_count], 0, tx_bytes - copy_count); - mf_ul_ntag_i2c_fill_cross_area_read( - buff_tx, buff_rx[1], buff_rx[2], emulator); + // Special case: NTAG I2C Plus sector 0 page 233 read crosses into page 236 + if(start_page == 233) + memcpy( + &buff_tx[12], &emulator->data.data[(start_page + 1) * 4], 4); mf_ul_protect_auth_data_on_read_command_i2c( buff_tx, start_page, start_page + copy_count / 4 - 1, emulator); *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; } + } else { + FURI_LOG_D( + TAG, + "NTAG I2C Emu: page invalid, %02x:%02x", + emulator->curr_sector, + buff_rx[1]); + if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K && + emulator->curr_sector == 3 && + !emulator->ntag_i2c_plus_sector3_lockout) { + // NTAG I2C Plus has a weird behavior where if you read sector 3 + // at an invalid address, it responds with zeroes then locks + // the read out, while if you read the mirrored session registers, + // it returns both session registers on either pages + memset(buff_tx, 0, tx_bytes); + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + emulator->ntag_i2c_plus_sector3_lockout = true; + } } } if(!command_parsed) tx_bytes = 0; } - } - } else if(cmd == MF_UL_WRITE) { - int16_t write_page = buff_rx[1]; - if(write_page > 1) { - uint16_t valid_pages; - write_page = mf_ultralight_ntag_i2c_addr_tag_to_lin( - &emulator->data, write_page, emulator->curr_sector, &valid_pages); - if(write_page != -1 && - (emulator->data.type >= MfUltralightTypeNTAGI2C1K || (write_page < page_num - 2))) { - if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K || - mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], true)) { - memcpy(&emulator->data.data[write_page * 4], &buff_rx[2], 4); - emulator->data_changed = true; + } else if(cmd == MF_UL_FAST_READ_CMD) { + if(emulator->supported_features & MfUltralightSupportFastRead) { + if(buff_rx_len == (1 + 2) * 8) { + int16_t start_page = buff_rx[1]; + uint8_t end_page = buff_rx[2]; + if(start_page <= end_page) { + tx_bytes = ((end_page + 1) - start_page) * 4; + if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { + if((start_page < emulator->page_num) && + (end_page < emulator->page_num)) { + do { + if(emulator->supported_features & MfUltralightSupportAuth) { + // NAK if not authenticated and requested pages cross over AUTH0 + if(!emulator->auth_success && + emulator->config_cache.access.prot && + (start_page >= emulator->config_cache.auth0 || + end_page >= emulator->config_cache.auth0)) + break; + } + if(emulator->supported_features & + MfUltralightSupportSingleCounter) + mf_ul_increment_single_counter(emulator); + + // Copy requested pages + memcpy( + buff_tx, &emulator->data.data[start_page * 4], tx_bytes); + + if(emulator->supported_features & + MfUltralightSupportAsciiMirror && + emulator->config_cache.mirror.mirror_conf != + MfUltralightMirrorNone) { + // Copy ASCII mirror + // Less stringent check here, because expecting FAST_READ to + // only be issued once rather than repeatedly + string_t ascii_mirror; + string_init(ascii_mirror); + mf_ul_make_ascii_mirror(emulator, ascii_mirror); + size_t ascii_mirror_len = string_length_u(ascii_mirror); + const char* ascii_mirror_cptr = + string_get_cstr(ascii_mirror); + int16_t mirror_start_offset = + (emulator->config->mirror_page - start_page) * 4 + + emulator->config->mirror.mirror_byte; + if(mirror_start_offset < 0) { + if(mirror_start_offset < -(int16_t)ascii_mirror_len) { + // Past ASCII mirror, don't copy + ascii_mirror_len = 0; + } else { + ascii_mirror_cptr += -mirror_start_offset; + ascii_mirror_len -= -mirror_start_offset; + mirror_start_offset = 0; + } + } + if(ascii_mirror_len > 0) { + int16_t mirror_end_offset = + mirror_start_offset + ascii_mirror_len; + if(mirror_end_offset > (end_page + 1) * 4) { + mirror_end_offset = (end_page + 1) * 4; + ascii_mirror_len = + mirror_end_offset - mirror_start_offset; + } + for(size_t i = 0; i < ascii_mirror_len; ++i) { + if(*ascii_mirror_cptr != ' ') + buff_tx[mirror_start_offset] = + (uint8_t)*ascii_mirror_cptr; + ++mirror_start_offset; + ++ascii_mirror_cptr; + } + } + string_clear(ascii_mirror); + } + + if(emulator->supported_features & MfUltralightSupportAuth) { + // Clear PWD and PACK pages + uint8_t pwd_page = emulator->page_num - 2; + int16_t pwd_page_offset = pwd_page - start_page; + // PWD page + if(pwd_page_offset >= 0 && pwd_page <= end_page) { + memset(&buff_tx[pwd_page_offset * 4], 0, 4); + // PACK page + if(pwd_page + 1 <= end_page) + memset(&buff_tx[(pwd_page_offset + 1) * 4], 0, 4); + } + } + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } while(false); + } + } else { + uint16_t valid_pages; + start_page = mf_ultralight_ntag_i2c_addr_tag_to_lin( + &emulator->data, start_page, emulator->curr_sector, &valid_pages); + if(start_page != -1) { + if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K || + mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], false)) { + uint16_t copy_count = tx_bytes; + if(copy_count > valid_pages * 4) copy_count = valid_pages * 4; + memcpy( + buff_tx, &emulator->data.data[start_page * 4], copy_count); + if(copy_count < tx_bytes) + memset(&buff_tx[copy_count], 0, tx_bytes - copy_count); + mf_ul_ntag_i2c_fill_cross_area_read( + buff_tx, buff_rx[1], buff_rx[2], emulator); + mf_ul_protect_auth_data_on_read_command_i2c( + buff_tx, + start_page, + start_page + copy_count / 4 - 1, + emulator); + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } + } + } + if(!command_parsed) tx_bytes = 0; + } + } + } + } else if(cmd == MF_UL_WRITE) { + if(buff_rx_len == (1 + 5) * 8) { + do { + uint8_t orig_write_page = buff_rx[1]; + int16_t write_page = orig_write_page; + uint16_t valid_pages; // unused + write_page = mf_ultralight_ntag_i2c_addr_tag_to_lin( + &emulator->data, write_page, emulator->curr_sector, &valid_pages); + if(write_page == -1) // NTAG I2C range check + break; + else if(write_page < 2 || write_page >= emulator->page_num) // Other MFUL/NTAG range check + break; + + if(emulator->supported_features & MfUltralightSupportAuth) { + if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K) { + if(!mf_ul_ntag_i2c_plus_check_auth(emulator, orig_write_page, true)) + break; + } else { + if(!mf_ul_check_auth(emulator, orig_write_page, true)) break; + } + } + int16_t tag_addr = mf_ultralight_page_addr_to_tag_addr( + emulator->curr_sector, orig_write_page); + if(!mf_ul_check_lock(emulator, tag_addr)) break; + mf_ul_emulate_write(emulator, tag_addr, write_page, &buff_rx[2]); + send_ack = true; + command_parsed = true; + } while(false); + } + } else if(cmd == MF_UL_FAST_WRITE) { + if(emulator->supported_features & MfUltralightSupportFastWrite) { + if(buff_rx_len == (1 + 66) * 8) { + if(buff_rx[1] == 0xF0 && buff_rx[2] == 0xFF) { + // TODO: update when SRAM emulation implemented + send_ack = true; + command_parsed = true; + } + } + } + } else if(cmd == MF_UL_COMP_WRITE) { + if(emulator->supported_features & MfUltralightSupportCompatWrite) { + if(buff_rx_len == (1 + 1) * 8) { + uint8_t write_page = buff_rx[1]; + do { + if(write_page < 2 || write_page >= emulator->page_num) break; + if(emulator->supported_features & MfUltralightSupportAuth && + !mf_ul_check_auth(emulator, write_page, true)) + break; + // Note we don't convert to tag addr here because there's only one sector + if(!mf_ul_check_lock(emulator, write_page)) break; + + emulator->comp_write_cmd_started = true; + emulator->comp_write_page_addr = write_page; + send_ack = true; + command_parsed = true; + } while(false); + } + } + } else if(cmd == MF_UL_READ_CNT) { + if(emulator->supported_features & MfUltralightSupportReadCounter) { + if(buff_rx_len == (1 + 1) * 8) { + do { + uint8_t cnt_num = buff_rx[1]; + + // NTAG21x checks + if(emulator->supported_features & MfUltralightSupportSingleCounter) { + if(cnt_num != 2) break; // Only counter 2 is available + if(!emulator->config_cache.access.nfc_cnt_en) + break; // NAK if counter not enabled + if(emulator->config_cache.access.nfc_cnt_pwd_prot && + !emulator->auth_success) + break; + } + + if(cnt_num < 3) { + buff_tx[0] = emulator->data.counter[cnt_num] & 0xFF; + buff_tx[1] = (emulator->data.counter[cnt_num] >> 8) & 0xFF; + buff_tx[2] = (emulator->data.counter[cnt_num] >> 16) & 0xFF; + tx_bytes = 3; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } + } while(false); + } + } + } else if(cmd == MF_UL_INC_CNT) { + if(emulator->supported_features & MfUltralightSupportIncrCounter) { + if(buff_rx_len == (1 + 5) * 8) { + uint8_t cnt_num = buff_rx[1]; + uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16)); + // TODO: can you increment by 0 when counter is at 0xffffff? + if((cnt_num < 3) && (emulator->data.counter[cnt_num] != 0x00FFFFFF) && + (emulator->data.counter[cnt_num] + inc <= 0x00FFFFFF)) { + emulator->data.counter[cnt_num] += inc; + // We're RAM-backed, so tearing never happens + emulator->data.tearing[cnt_num] = MF_UL_TEARING_FLAG_DEFAULT; + emulator->data_changed = true; + send_ack = true; + command_parsed = true; + } + } + } + } else if(cmd == MF_UL_AUTH) { + if(emulator->supported_features & MfUltralightSupportAuth) { + if(buff_rx_len == (1 + 4) * 8) { + uint16_t scaled_authlim = mf_ultralight_calc_auth_count(&emulator->data); + if(scaled_authlim != 0 && emulator->data.curr_authlim >= scaled_authlim) { + if(emulator->data.curr_authlim != UINT16_MAX) { + // Handle case where AUTHLIM has been lowered or changed from 0 + emulator->data.curr_authlim = UINT16_MAX; + emulator->data_changed = true; + } + // AUTHLIM reached, always fail + buff_tx[0] = MF_UL_NAK_AUTHLIM_REACHED; + tx_bits = 4; + *data_type = FURI_HAL_NFC_TX_RAW_RX_DEFAULT; + mf_ul_reset_emulation(emulator, false); + command_parsed = true; + } else { + if(memcmp(&buff_rx[1], emulator->config->auth_data.pwd.raw, 4) == 0) { + // Correct password + buff_tx[0] = emulator->config->auth_data.pack.raw[0]; + buff_tx[1] = emulator->config->auth_data.pack.raw[1]; + tx_bytes = 2; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + emulator->auth_success = true; + command_parsed = true; + if(emulator->data.curr_authlim != 0) { + // Reset current AUTHLIM + emulator->data.curr_authlim = 0; + emulator->data_changed = true; + } + } else if(!emulator->config->auth_data.pwd.value) { + // Unknown password, pretend to be an Amiibo + buff_tx[0] = 0x80; + buff_tx[1] = 0x80; + tx_bytes = 2; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + emulator->auth_success = true; + command_parsed = true; + } else { + // Wrong password, increase negative verification count + if(emulator->data.curr_authlim < UINT16_MAX) { + ++emulator->data.curr_authlim; + emulator->data_changed = true; + } + if(scaled_authlim != 0 && + emulator->data.curr_authlim >= scaled_authlim) { + emulator->data.curr_authlim = UINT16_MAX; + buff_tx[0] = MF_UL_NAK_AUTHLIM_REACHED; + tx_bits = 4; + *data_type = FURI_HAL_NFC_TX_RAW_RX_DEFAULT; + mf_ul_reset_emulation(emulator, false); + command_parsed = true; + } else { + // Should delay here to slow brute forcing + } + } + } + } + } + } else if(cmd == MF_UL_READ_SIG) { + if(emulator->supported_features & MfUltralightSupportSignature) { + // Check 2nd byte = 0x00 - RFU + if(buff_rx_len == (1 + 1) * 8 && buff_rx[1] == 0x00) { + tx_bytes = sizeof(emulator->data.signature); + memcpy(buff_tx, emulator->data.signature, tx_bytes); + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } + } + } else if(cmd == MF_UL_CHECK_TEARING) { + if(emulator->supported_features & MfUltralightSupportTearingFlags) { + if(buff_rx_len == (1 + 1) * 8) { + uint8_t cnt_num = buff_rx[1]; + if(cnt_num < 3) { + buff_tx[0] = emulator->data.tearing[cnt_num]; + tx_bytes = 1; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } + } + } + } else if(cmd == MF_UL_HALT_START) { + reset_idle = true; + FURI_LOG_D(TAG, "Received HLTA"); + } else if(cmd == MF_UL_SECTOR_SELECT) { + if(emulator->supported_features & MfUltralightSupportSectorSelect) { + if(buff_rx_len == (1 + 1) * 8 && buff_rx[1] == 0xFF) { + // Send ACK + emulator->sector_select_cmd_started = true; send_ack = true; command_parsed = true; } } - } - } else if(cmd == MF_UL_FAST_WRITE) { - if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K) { - if(buff_rx[1] == 0xF0 && buff_rx[2] == 0xFF) { - // TODO: update when SRAM emulation implemented - send_ack = true; - command_parsed = true; + } else if(cmd == MF_UL_READ_VCSL) { + if(emulator->supported_features & MfUltralightSupportVcsl) { + if(buff_rx_len == (1 + 20) * 8) { + buff_tx[0] = emulator->config_cache.vctid; + tx_bytes = 1; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } } + } else { + reset_idle = true; + FURI_LOG_D(TAG, "Received invalid command"); } - } else if(cmd == MF_UL_COMP_WRITE) { - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - uint8_t write_page = buff_rx[1]; - if((write_page > 1) && (write_page < page_num - 2)) { - emulator->comp_write_cmd_started = true; - emulator->comp_write_page_addr = write_page; - // ACK - buff_tx[0] = 0x0A; - tx_bits = 4; - *data_type = FURI_HAL_NFC_TXRX_RAW; - command_parsed = true; - } - } - } else if(cmd == MF_UL_READ_CNT) { - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - uint8_t cnt_num = buff_rx[1]; - if(cnt_num < 3) { - buff_tx[0] = emulator->data.counter[cnt_num] >> 16; - buff_tx[1] = emulator->data.counter[cnt_num] >> 8; - buff_tx[2] = emulator->data.counter[cnt_num]; - tx_bytes = 3; - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; - } - } - } else if(cmd == MF_UL_INC_CNT) { - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - uint8_t cnt_num = buff_rx[1]; - uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16)); - if((cnt_num < 3) && (emulator->data.counter[cnt_num] + inc < 0x00FFFFFF)) { - emulator->data.counter[cnt_num] += inc; - emulator->data_changed = true; - // ACK - buff_tx[0] = 0x0A; - tx_bits = 4; - *data_type = FURI_HAL_NFC_TXRX_RAW; - command_parsed = true; - } - } - } else if(cmd == MF_UL_AUTH) { - if(emulator->data.type >= MfUltralightTypeNTAG213 && - emulator->data.type != MfUltralightTypeNTAGI2C1K && - emulator->data.type != MfUltralightTypeNTAGI2C2K) { - if(memcmp(&buff_rx[1], emulator->auth_data->pwd, 4) == 0) { - buff_tx[0] = emulator->auth_data->pack.raw[0]; - buff_tx[1] = emulator->auth_data->pack.raw[1]; - tx_bytes = 2; - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - emulator->auth_success = true; - command_parsed = true; - } else if(!emulator->auth_data->pack.value) { - buff_tx[0] = 0x80; - buff_tx[1] = 0x80; - tx_bytes = 2; - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; - } - } - } else if(cmd == MF_UL_READ_SIG) { - if(emulator->data.type != MfUltralightTypeNTAGI2C1K && - emulator->data.type != MfUltralightTypeNTAGI2C2K) { - // Check 2nd byte = 0x00 - RFU - if(buff_rx[1] == 0x00) { - tx_bytes = sizeof(emulator->data.signature); - memcpy(buff_tx, emulator->data.signature, tx_bytes); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; - } - } - } else if(cmd == MF_UL_CHECK_TEARING) { - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - uint8_t cnt_num = buff_rx[1]; - if(cnt_num < 3) { - buff_tx[0] = emulator->data.tearing[cnt_num]; - tx_bytes = 1; - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; - } - } - } else if(cmd == MF_UL_HALT_START) { + } else { + reset_idle = true; + FURI_LOG_D(TAG, "Received invalid buffer less than 8 bits in length"); + } + + if(reset_idle) { + mf_ul_reset_emulation(emulator, false); tx_bits = 0; - emulator->curr_sector = 0; - emulator->ntag_i2c_plus_sector3_lockout = false; - emulator->auth_success = false; command_parsed = true; - FURI_LOG_D(TAG, "Received HLTA"); - } else if(cmd == MF_UL_SECTOR_SELECT) { - if(emulator->data.type >= MfUltralightTypeNTAGI2C1K) { - if(buff_rx[1] == 0xFF) { - // Send ACK - emulator->sector_select_cmd_started = true; - send_ack = true; - command_parsed = true; - } - } } if(!command_parsed) { // Send NACK - buff_tx[0] = 0x00; + buff_tx[0] = MF_UL_NAK_INVALID_ARGUMENT; tx_bits = 4; *data_type = FURI_HAL_NFC_TX_RAW_RX_DEFAULT; + // Every NAK should cause reset to IDLE + mf_ul_reset_emulation(emulator, false); } else if(send_ack) { - buff_tx[0] = 0x0A; + buff_tx[0] = MF_UL_ACK; tx_bits = 4; *data_type = FURI_HAL_NFC_TX_RAW_RX_DEFAULT; } diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc_protocols/mifare_ultralight.h index 76dc2edb..36b81fdf 100644 --- a/lib/nfc_protocols/mifare_ultralight.h +++ b/lib/nfc_protocols/mifare_ultralight.h @@ -22,6 +22,10 @@ #define MF_UL_READ_VCSL (0x4B) #define MF_UL_SECTOR_SELECT (0xC2) +#define MF_UL_ACK (0xa) +#define MF_UL_NAK_INVALID_ARGUMENT (0x0) +#define MF_UL_NAK_AUTHLIM_REACHED (0x4) + typedef enum { MfUltralightTypeUnknown, MfUltralightTypeUL11, @@ -38,6 +42,31 @@ typedef enum { MfUltralightTypeNum, } MfUltralightType; +typedef enum { + MfUltralightSupportNone = 0, + MfUltralightSupportFastRead = 1 << 0, + MfUltralightSupportTearingFlags = 1 << 1, + MfUltralightSupportReadCounter = 1 << 2, + MfUltralightSupportIncrCounter = 1 << 3, + MfUltralightSupportSignature = 1 << 4, + MfUltralightSupportFastWrite = 1 << 5, + MfUltralightSupportCompatWrite = 1 << 6, + MfUltralightSupportAuth = 1 << 7, + MfUltralightSupportVcsl = 1 << 8, + MfUltralightSupportSectorSelect = 1 << 9, + // NTAG21x only has counter 2 + MfUltralightSupportSingleCounter = 1 << 10, + // ASCII mirror is not a command, but handy to have as a flag + MfUltralightSupportAsciiMirror = 1 << 11, +} MfUltralightFeatures; + +typedef enum { + MfUltralightMirrorNone, + MfUltralightMirrorUid, + MfUltralightMirrorCounter, + MfUltralightMirrorUidCounter, +} MfUltralightMirrorConf; + typedef struct { uint8_t header; uint8_t vendor_id; @@ -65,38 +94,76 @@ typedef struct { uint8_t signature[32]; uint32_t counter[3]; uint8_t tearing[3]; + uint16_t curr_authlim; uint16_t data_size; uint8_t data[MF_UL_MAX_DUMP_SIZE]; } MfUltralightData; -typedef struct { - uint8_t pwd[4]; +typedef struct __attribute__((packed)) { + union { + uint8_t raw[4]; + uint32_t value; + } pwd; union { uint8_t raw[2]; uint16_t value; } pack; } MfUltralightAuth; +// Common configuration pages for MFUL EV1, NTAG21x, and NTAG I2C Plus +typedef struct __attribute__((packed)) { + union { + uint8_t value; + struct { + uint8_t rfui1 : 2; + bool strg_mod_en : 1; + bool rfui2 : 1; + uint8_t mirror_byte : 2; + MfUltralightMirrorConf mirror_conf : 2; + }; + } mirror; + uint8_t rfui1; + uint8_t mirror_page; + uint8_t auth0; + union { + uint8_t value; + struct { + uint8_t authlim : 3; + bool nfc_cnt_pwd_prot : 1; + bool nfc_cnt_en : 1; + bool nfc_dis_sec1 : 1; // NTAG I2C Plus only + bool cfglck : 1; + bool prot : 1; + }; + } access; + uint8_t vctid; + uint8_t rfui2[2]; + MfUltralightAuth auth_data; + uint8_t rfui3[2]; +} MfUltralightConfigPages; + typedef struct { uint16_t pages_to_read; int16_t pages_read; - bool support_fast_read; - bool support_tearing_flags; - bool support_counters; - bool support_signature; + MfUltralightFeatures supported_features; } MfUltralightReader; typedef struct { MfUltralightData data; - bool support_fast_read; + MfUltralightConfigPages* config; + // Most config values don't apply until power cycle, so cache config pages + // for correct behavior + MfUltralightConfigPages config_cache; + MfUltralightFeatures supported_features; + uint16_t page_num; bool data_changed; bool comp_write_cmd_started; uint8_t comp_write_page_addr; - MfUltralightAuth* auth_data; bool auth_success; uint8_t curr_sector; bool sector_select_cmd_started; bool ntag_i2c_plus_sector3_lockout; + bool read_counter_incremented; } MfUltralightEmulator; bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); @@ -127,6 +194,8 @@ bool mf_ul_read_card( MfUltralightReader* reader, MfUltralightData* data); +void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle); + void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data); bool mf_ul_prepare_emulation_response( From 9868a65c15dfe2b152cde67d792d2de5264452bd Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 22 Jun 2022 18:05:17 +0300 Subject: [PATCH 11/17] [FL-2602] Infrared: Fix crash when messing with SD card (#1339) * Fix crash after removing SD card and exiting * Show an error if SD card was removed on Universal remote screen --- applications/infrared/infrared_brute_force.c | 1 + .../infrared/scenes/common/infrared_scene_universal_common.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/infrared/infrared_brute_force.c b/applications/infrared/infrared_brute_force.c index 872a7637..55bf5c7f 100644 --- a/applications/infrared/infrared_brute_force.c +++ b/applications/infrared/infrared_brute_force.c @@ -99,6 +99,7 @@ bool infrared_brute_force_start( success = flipper_format_file_open_existing(brute_force->ff, brute_force->db_filename); if(!success) { flipper_format_free(brute_force->ff); + brute_force->ff = NULL; furi_record_close("storage"); } } diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.c b/applications/infrared/scenes/common/infrared_scene_universal_common.c index f0e69030..7eff81ee 100644 --- a/applications/infrared/scenes/common/infrared_scene_universal_common.c +++ b/applications/infrared/scenes/common/infrared_scene_universal_common.c @@ -74,7 +74,7 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e infrared_play_notification_message( infrared, InfraredNotificationMessageBlinkSend); } else { - scene_manager_previous_scene(scene_manager); + scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases); } consumed = true; } From 0b8331656069bbbd011f2dfa0b0c2a03b5d8a859 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 22 Jun 2022 18:12:39 +0300 Subject: [PATCH 12/17] [FL-2603] Infrared: exit app properly if ran from outside the launcher (#1340) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Exit app if no previous scene was found * Infrared: correct return logic for started from archive app Co-authored-by: あく --- applications/infrared/scenes/infrared_scene_remote.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/infrared/scenes/infrared_scene_remote.c b/applications/infrared/scenes/infrared_scene_remote.c index 0b7a1ad9..50f71488 100644 --- a/applications/infrared/scenes/infrared_scene_remote.c +++ b/applications/infrared/scenes/infrared_scene_remote.c @@ -79,9 +79,8 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeBack) { const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; - scene_manager_search_and_switch_to_previous_scene_one_of( + consumed = scene_manager_search_and_switch_to_previous_scene_one_of( scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); - consumed = true; } else if(event.type == SceneManagerEventTypeCustom) { const uint16_t custom_type = infrared_custom_event_get_type(event.event); const int16_t button_index = infrared_custom_event_get_value(event.event); From c79fb61909fbb68aa9bc7ef7cfe25063f1ee9a7f Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 22 Jun 2022 19:18:52 +0400 Subject: [PATCH 13/17] SubGhz: add protocol PowerSmart / SolarSmart Roller Shutters (#1335) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add protocol Power Smart * SubGhz: parsing protocol Power Smart * SubGhz: add parsing cannel * SubGhz: add unit test * SubGhz: update files unit test_random_raw Co-authored-by: あく --- applications/unit_tests/subghz/subghz_test.c | 17 +- assets/unit_tests/subghz/power_smart.sub | 7 + assets/unit_tests/subghz/power_smart_raw.sub | 7 + assets/unit_tests/subghz/test_random_raw.sub | 3 + lib/subghz/protocols/power_smart.c | 380 +++++++++++++++++++ lib/subghz/protocols/power_smart.h | 109 ++++++ lib/subghz/protocols/registry.c | 18 +- lib/subghz/protocols/registry.h | 1 + 8 files changed, 532 insertions(+), 10 deletions(-) create mode 100644 assets/unit_tests/subghz/power_smart.sub create mode 100644 assets/unit_tests/subghz/power_smart_raw.sub create mode 100644 lib/subghz/protocols/power_smart.c create mode 100644 lib/subghz/protocols/power_smart.h diff --git a/applications/unit_tests/subghz/subghz_test.c b/applications/unit_tests/subghz/subghz_test.c index 680f199a..fea407ed 100644 --- a/applications/unit_tests/subghz/subghz_test.c +++ b/applications/unit_tests/subghz/subghz_test.c @@ -13,7 +13,7 @@ #define CAME_ATOMO_DIR_NAME "/ext/subghz/assets/came_atomo" #define NICE_FLOR_S_DIR_NAME "/ext/subghz/assets/nice_flor_s" #define TEST_RANDOM_DIR_NAME "/ext/unit_tests/subghz/test_random_raw.sub" -#define TEST_RANDOM_COUNT_PARSE 113 +#define TEST_RANDOM_COUNT_PARSE 119 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -361,6 +361,13 @@ MU_TEST(subghz_decoder_holtek_test) { "Test decoder " SUBGHZ_PROTOCOL_HOLTEK_NAME " error\r\n"); } +MU_TEST(subghz_decoder_power_smart_test) { + mu_assert( + subghz_decoder_test( + "/ext/unit_tests/subghz/power_smart_raw.sub", SUBGHZ_PROTOCOL_POWER_SMART_NAME), + "Test decoder " SUBGHZ_PROTOCOL_POWER_SMART_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -428,6 +435,12 @@ MU_TEST(subghz_encoder_secplus_v2_test) { "Test encoder " SUBGHZ_PROTOCOL_SECPLUS_V2_NAME " error\r\n"); } +MU_TEST(subghz_encoder_power_smart_test) { + mu_assert( + subghz_encoder_test("/ext/unit_tests/subghz/power_smart.sub"), + "Test encoder " SUBGHZ_PROTOCOL_POWER_SMART_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -459,6 +472,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_secplus_v1_test); MU_RUN_TEST(subghz_decoder_secplus_v2_test); MU_RUN_TEST(subghz_decoder_holtek_test); + MU_RUN_TEST(subghz_decoder_power_smart_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -471,6 +485,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_holtek_test); MU_RUN_TEST(subghz_encoder_secplus_v1_test); MU_RUN_TEST(subghz_encoder_secplus_v2_test); + MU_RUN_TEST(subghz_encoder_power_smart_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/assets/unit_tests/subghz/power_smart.sub b/assets/unit_tests/subghz/power_smart.sub new file mode 100644 index 00000000..445458b8 --- /dev/null +++ b/assets/unit_tests/subghz/power_smart.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433420000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Power Smart +Bit: 64 +Key: FD C1 36 AC AA 3E C9 52 diff --git a/assets/unit_tests/subghz/power_smart_raw.sub b/assets/unit_tests/subghz/power_smart_raw.sub new file mode 100644 index 00000000..0aafc87c --- /dev/null +++ b/assets/unit_tests/subghz/power_smart_raw.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433420000 +Preset: FuriHalSubGhzPresetOok270Async +Protocol: RAW +RAW_Data: -68 521674 -200 213 -258 217 -218 217 -246 193 -242 211 -466 451 -450 225 -212 211 -242 211 -238 243 -200 223 -254 419 -226 221 -432 251 -212 467 -240 203 -450 449 -246 205 -238 217 -218 217 -444 439 -478 431 -230 211 -462 247 -214 435 -454 449 -456 441 -442 471 -448 449 -246 205 -238 215 -220 217 -244 201 -254 217 -430 235 -220 461 -198 223 -442 275 -212 429 -458 245 -212 203 -228 253 -218 431 -448 451 -442 235 -218 463 -426 485 -214 209 -234 221 -254 219 -214 207 -228 253 -428 459 -418 245 -216 243 -194 241 -212 241 -212 211 -244 441 -228 215 -460 217 -244 435 -236 235 -440 439 -246 213 -208 229 -256 217 -430 445 -450 445 -236 253 -420 225 -232 429 -450 465 -448 439 -448 449 -454 453 -230 225 -214 241 -212 211 -242 211 -244 237 -442 237 -218 429 -230 221 -442 241 -246 425 -458 245 -212 203 -228 255 -218 427 -448 451 -446 235 -256 425 -462 417 -244 251 -208 201 -256 217 -218 209 -232 255 -420 451 -448 217 -242 211 -238 209 -234 221 -256 217 -218 437 -238 217 -464 203 -256 419 -226 223 -464 441 -244 213 -240 197 -254 219 -430 445 -452 479 -204 253 -420 225 -222 463 -452 449 -450 449 -452 447 -450 451 -238 215 -220 217 -244 199 -256 217 -218 207 -440 241 -254 423 -238 217 -462 197 -224 471 -448 225 -220 213 -242 211 -212 465 -446 449 -456 245 -214 437 -456 449 -232 233 -216 219 -254 207 -204 253 -218 219 -440 451 -456 237 -216 217 -254 209 -202 253 -218 219 -210 437 -244 253 -422 237 -218 423 -226 247 -430 451 -242 203 -228 253 -220 217 -442 449 -454 449 -240 217 -430 237 -218 461 -426 453 -450 465 -448 451 -440 443 -246 215 -250 201 -224 255 -218 215 -208 227 -442 239 -208 457 -238 219 -464 201 -256 425 -464 201 -256 217 -210 241 -216 451 -426 445 -486 207 -236 441 -430 479 -194 223 -256 217 -218 209 -234 253 -218 217 -438 449 -454 239 -216 217 -256 207 -202 255 -218 217 -210 439 -244 253 -424 235 -218 457 -224 229 -436 449 -230 221 -214 211 -242 211 -468 447 -450 449 -250 207 -454 239 -218 431 -446 451 -448 443 -486 447 -448 431 -240 207 -232 223 -254 219 -216 209 -230 253 -426 233 -234 433 -244 213 -432 237 -218 463 -446 221 -212 211 -242 239 -208 457 -456 451 -456 223 -212 467 -450 453 -204 253 -218 211 -240 215 -218 255 -208 201 -442 479 -452 203 -254 217 -212 241 -216 217 -256 207 -202 439 -240 245 -430 237 -218 463 -240 217 -428 465 -202 253 -218 213 -234 219 +RAW_Data: -444 443 -452 455 -244 213 -440 237 -254 427 -450 429 -480 417 -454 477 -430 445 -244 217 -250 203 -224 253 -220 215 -206 221 -462 217 -212 467 -234 231 -440 239 -220 427 -446 219 -242 211 -244 237 -206 451 -458 451 -458 203 -254 427 -450 441 -246 213 -242 193 -244 211 -242 211 -212 241 -442 451 -454 245 -214 241 -198 255 -218 217 -210 225 -212 461 -246 213 -440 225 -242 435 -240 209 -456 457 -246 211 -204 229 -254 219 -428 445 -452 445 -238 253 -426 231 -232 435 -448 455 -448 439 -446 449 -456 451 -230 223 -214 241 -212 211 -242 211 -244 237 -442 237 -218 427 -232 221 -442 239 -246 427 -458 245 -212 205 -228 253 -220 427 -446 471 -442 237 -216 451 -462 411 -244 251 -216 205 -222 211 -242 211 -242 211 -480 453 -418 245 -252 207 -202 253 -218 219 -210 229 -256 425 -232 221 -430 251 -212 469 -204 235 -446 441 -246 213 -242 193 -244 211 -464 451 -456 441 -248 215 -450 201 -256 427 -452 457 -450 455 -450 439 -446 451 -238 217 -256 207 -202 255 -218 217 -210 231 -442 237 -244 423 -240 217 -464 203 -254 419 -454 227 -210 243 -212 241 -212 477 -418 453 -484 199 -226 431 -267004 97 -422 97 -164 65 -490 97 -2222 559 -66 163 -64 295 -100 497 -100 263 -98 361 -460 793 -66 1803 -100 339 -68 1733 diff --git a/assets/unit_tests/subghz/test_random_raw.sub b/assets/unit_tests/subghz/test_random_raw.sub index 9d1cdd67..df36e125 100644 --- a/assets/unit_tests/subghz/test_random_raw.sub +++ b/assets/unit_tests/subghz/test_random_raw.sub @@ -100,3 +100,6 @@ RAW_Data: -202 531 -66 531 -66 1093 -66 1389 -66 1551 -134 2699 -66 1291 -132 65 RAW_Data: -132 2291 -66 3057 -68 2521 -166 333 -134 503 -400 3235 -66 2329 -68 995 -100 333 -100 97 -166 1757 -100 397 -100 165 -66 2755 -132 297 -134 163 -100 565 -100 1793 -100 1813 -162 1293 -98 97 -66 999 -66 1763 -68 261 -68 2391 -100 765 -364 859 -100 1855 -98 1399 -230 463 -134 301 -198 397 -100 961 -68 431 -134 695 -202 133 -100 365 -66 925 -98 165 -66 365 -132 663 -98 4573 -134 1479 -66 1019 -66 629 -66 233 -68 201 -66 569 -66 295 -134 1755 -296 3199 -100 3261 -168 3373 -132 1425 -100 759 -66 895 -98 201 -100 265 -166 99 -66 695 -66 1091 -66 855 -168 299 -100 229 -164 589 -66 521 -66 655 -134 329 -98 493 -200 429 -66 929 -66 673 -100 953 -66 823 -66 1283 -66 1979 -68 233 -66 1547 -164 589 -132 597 -66 131 -66 265 -100 761 -200 759 -66 689 -332 263 -100 1227 -68 1067 -164 2945 -100 959 -100 995 -100 399 -100 1193 -100 625 -66 399 -66 3021 -134 393 -66 4805 -66 1095 -68 231 -332 399 -166 1663 -68 561 -66 927 -98 1085 -164 1155 -98 627 -66 265 -132 263 -130 2211 -66 2159 -66 1029 -264 2669 -66 295 -66 8747 -100 329 -232 625 -134 429 -68 1329 -168 1355 -98 987 -66 1545 -98 1015 -98 699 -134 133 -134 1263 -66 4687 -166 8299 -66 1349 -434 933 -906 443 -452 949 -894 441 -480 909 -486 907 -456 947 -448 949 -434 969 -454 931 -460 941 -448 933 -450 979 -450 945 -450 935 -458 935 -486 927 -456 947 -450 951 -482 945 -428 975 -446 967 -452 955 -458 945 -912 485 -434 971 -902 481 -450 949 -926 451 -478 941 -920 481 -450 949 -920 473 -450 955 -916 471 -452 981 -918 449 -486 945 -910 483 -924 473 -15780 479 -450 967 -948 449 -482 943 -944 485 -468 941 -484 979 -446 1001 -444 999 -446 967 -484 969 -482 979 -478 947 -484 985 -470 973 -458 983 -492 971 -458 979 -494 971 -458 983 -494 973 -458 981 -498 975 -458 1013 -466 973 -952 475 -458 973 -950 489 -450 1011 -916 481 -478 1001 -918 481 -478 1001 -916 481 -478 1001 -920 483 -480 983 -946 479 -458 1013 -932 485 -952 479 -16040 493 -476 1009 -912 515 -464 1007 -910 517 -464 1007 -450 1001 -488 1001 -484 1011 -450 1019 -458 1039 -450 1031 -454 1005 -484 1009 -458 1015 -476 1009 -478 1035 -462 1015 -468 1007 -480 1001 -486 1015 -460 1041 -450 1017 -484 1019 -482 1009 -952 477 -494 1003 -944 485 -478 1013 -944 519 -482 1013 -942 487 -482 1013 -946 487 -484 1015 -944 487 -484 1015 -946 519 -454 1019 -942 505 -952 487 -16238 517 -468 1007 -942 521 -482 1011 -944 519 RAW_Data: -450 1019 -482 1035 -480 1033 -460 1047 -476 1017 -484 1007 -484 1051 -484 1027 -452 1039 -478 1035 -458 1049 -480 1017 -480 1035 -480 1035 -472 1047 -484 1027 -454 1039 -480 1033 -488 1031 -488 1009 -962 521 -486 1017 -966 485 -490 1015 -139210 229 -98 461 -364 165 -334 131 -168 2121 -66 1049 -66 1215 -166 297 -136 1449 -100 3877 -100 1495 -234 331 -64 1345 -262 393 -100 529 -132 2921 -164 1223 -132 1807 -66 765 -66 397 -98 3405 -132 2123 -230 231 -66 2541 -100 2489 -98 4397 -132 461 -98 293 -64 991 -66 1125 -166 401 -100 131 -100 99 -100 265 -100 2555 -100 499 -98 1361 -134 265 -166 895 -100 2253 -100 1057 -100 129 -296 1147 -198 197 -66 1163 -66 1935 -98 1675 -66 1103 -100 891 -100 989 -164 1019 -66 2967 -68 1293 -166 3161 -66 133 -264 1065 -100 731 -66 1693 -66 529 -100 165 -68 865 -66 825 -232 1117 -196 2401 -66 3051 -296 229 -132 1843 -132 1687 -68 1119 -68 299 -68 97 -66 4741 -66 197 -200 2319 -100 1097 -66 3765 -66 131 -100 695 -132 2753 -66 2287 -100 1129 -68 331 -98 1433 -132 893 -100 465 -100 801 -66 529 -66 1515 -264 393 -98 263 -66 1831 -166 3533 -100 633 -100 1051 -100 331 -98 795 -134 959 -132 1229 -100 627 -132 2517 -66 165 -98 131 -66 2301 -166 163 -134 465 -66 2767 -66 1019 -66 401 -134 397 -232 893 -66 397 -66 833 -66 199 -66 303 -66 2775 -66 2069 -98 1841 -100 399 -66 793 -98 2793 -68 3769 -100 867 -66 861 -100 399 -66 1859 -100 631 -132 755 -100 689 -66 163 -64 2045 -64 2191 -102 1127 -68 727 -68 625 -164 1381 -66 1153 -132 1115 -98 1017 -100 491 -100 593 -132 991 -98 1415 -98 4813 -66 331 -98 131 -102 1847 -98 197 -68 263 -100 3265 -66 431 -100 493 -98 435 -134 133 -68 1185 -134 395 -100 131 -66 399 -134 767 -134 1125 -66 429 -198 3185 -100 2261 -66 523 -230 2475 -168 1297 -66 3243 -66 1853 -100 1657 -66 459 -66 827 -100 263 -66 303 -234 197 -166 1167 -100 2299 -66 1329 -68 461 -100 763 -132 3819 -366 757 -66 591 -164 621 -98 1445 -100 2155 -100 231 -100 631 -68 1161 -66 131 -166 67 -98 1915 -166 1891 -66 1261 -68 999 -164 165 -132 133 -168 2695 -68 1055 -198 97 -98 229 -66 229 -66 1215 -66 885 -100 303 -132 297 -164 619 -198 459 -64 989 -66 229 -66 597 -134 693 -64 1255 -100 65 -132 331 -66 199 -98 529 -100 2831 -98 1259 -66 4855 -100 1163 -166 299 -66 395 -98 3141 -66 1319 -66 2139 -100 161 -132 261 -130 821 -200 263 -134 931 -330 65 -98 99 -134 793 RAW_Data: -66 597 -100 231 -68 167 -66 1659 -100 733 -66 1631 -100 165 -66 199 -66 233 -166 165 -100 1925 -68 595 -198 1785 -134 2177 -134 131 -66 1049 -98 3087 -132 195 -64 589 -66 397 -134 329 -66 2565 -164 327 -100 689 -64 1775 -100 5183 -132 1187 -66 329 -66 395 -132 165 -98 261 -98 1247 -64 1217 -66 927 -66 997 -66 199 -98 1419 -66 531 -166 1231 -66 697 -100 97 -66 563 -66 161 -264 3205 -200 525 -98 293 -100 291 -100 133 -66 759 -66 659 -100 983 -64 523 -130 431 -166 919 -66 1097 -100 1757 -66 1119 -66 917 -98 2647 -166 1247 -66 165 -264 1189 -100 899 -134 597 -68 2323 -66 1893 -66 1095 -100 533 -64 965 -100 1817 -130 1215 -66 1879 -64 821 -164 1117 -132 263 -132 131 -66 557 -66 431 -132 661 -100 1183 -98 629 -100 1679 -132 259 -66 623 -98 431 -66 399 -164 923 -100 297 -66 165 -166 2521 -198 99 -66 431 -132 1225 -66 1063 -68 131 -136 631 -66 163 -100 99 -298 965 -68 465 -68 465 -298 2545 -134 2639 -230 1489 -66 299 -66 1991 -234 65 -132 693 -134 429 -102 101 -68 461 -66 3333 -64 1229 -68 333 -66 265 -66 885 -64 3163 -100 467 -66 2651 -164 1221 -100 1527 -66 1259 -134 431 -232 1259 -100 6029 -164 297 -98 1151 -66 1415 -100 5289 -66 2467 -100 493 -132 495 -200 1121 -66 129 -66 757 -166 327 -130 5477 -66 1227 -230 395 -100 265 -132 497 -132 1133 -132 361 -100 1051 -164 3089 -132 1583 -100 65 -68 2315 -100 529 -132 2157 -68 1257 -66 1975 -98 427 -98 1347 -66 719 -164 857 -66 165 -66 1029 -132 297 -132 467 -100 731 -130 1985 -98 199 -166 899 -100 1391 -166 3425 -100 261 -132 721 -66 4845 -98 1193 -68 1225 -66 721 -100 1015 -64 983 -66 557 -130 693 -98 99 -64 1091 -98 197 -100 2321 -66 431 -134 727 -66 467 -102 891 -98 167 -134 2619 -66 393 -64 97 -100 589 -98 1583 -164 301 -68 1481 -98 295 -98 959 -66 365 -98 1253 -66 231 -100 1255 -132 1813 -132 1645 -100 361 -132 395 -100 427 -164 1197 -98 1001 -100 861 -66 1161 -98 195 -100 197 -66 1429 -66 663 -66 1427 -98 665 -66 699 -100 663 -66 855 -196 161 -100 361 -98 823 -66 227 -66 621 -132 1853 -230 461 -230 623 -100 557 -98 229 -98 133 -134 1291 -66 533 -166 627 -134 195 -134 593 -64 591 -66 1019 -66 1049 -262 297 -100 2921 -66 133 -66 963 -134 165 -100 +RAW_Data: -68 521674 -200 213 -258 217 -218 217 -246 193 -242 211 -466 451 -450 225 -212 211 -242 211 -238 243 -200 223 -254 419 -226 221 -432 251 -212 467 -240 203 -450 449 -246 205 -238 217 -218 217 -444 439 -478 431 -230 211 -462 247 -214 435 -454 449 -456 441 -442 471 -448 449 -246 205 -238 215 -220 217 -244 201 -254 217 -430 235 -220 461 -198 223 -442 275 -212 429 -458 245 -212 203 -228 253 -218 431 -448 451 -442 235 -218 463 -426 485 -214 209 -234 221 -254 219 -214 207 -228 253 -428 459 -418 245 -216 243 -194 241 -212 241 -212 211 -244 441 -228 215 -460 217 -244 435 -236 235 -440 439 -246 213 -208 229 -256 217 -430 445 -450 445 -236 253 -420 225 -232 429 -450 465 -448 439 -448 449 -454 453 -230 225 -214 241 -212 211 -242 211 -244 237 -442 237 -218 429 -230 221 -442 241 -246 425 -458 245 -212 203 -228 255 -218 427 -448 451 -446 235 -256 425 -462 417 -244 251 -208 201 -256 217 -218 209 -232 255 -420 451 -448 217 -242 211 -238 209 -234 221 -256 217 -218 437 -238 217 -464 203 -256 419 -226 223 -464 441 -244 213 -240 197 -254 219 -430 445 -452 479 -204 253 -420 225 -222 463 -452 449 -450 449 -452 447 -450 451 -238 215 -220 217 -244 199 -256 217 -218 207 -440 241 -254 423 -238 217 -462 197 -224 471 -448 225 -220 213 -242 211 -212 465 -446 449 -456 245 -214 437 -456 449 -232 233 -216 219 -254 207 -204 253 -218 219 -440 451 -456 237 -216 217 -254 209 -202 253 -218 219 -210 437 -244 253 -422 237 -218 423 -226 247 -430 451 -242 203 -228 253 -220 217 -442 449 -454 449 -240 217 -430 237 -218 461 -426 453 -450 465 -448 451 -440 443 -246 215 -250 201 -224 255 -218 215 -208 227 -442 239 -208 457 -238 219 -464 201 -256 425 -464 201 -256 217 -210 241 -216 451 -426 445 -486 207 -236 441 -430 479 -194 223 -256 217 -218 209 -234 253 -218 217 -438 449 -454 239 -216 217 -256 207 -202 255 -218 217 -210 439 -244 253 -424 235 -218 457 -224 229 -436 449 -230 221 -214 211 -242 211 -468 447 -450 449 -250 207 -454 239 -218 431 -446 451 -448 443 -486 447 -448 431 -240 207 -232 223 -254 219 -216 209 -230 253 -426 233 -234 433 -244 213 -432 237 -218 463 -446 221 -212 211 -242 239 -208 457 -456 451 -456 223 -212 467 -450 453 -204 253 -218 211 -240 215 -218 255 -208 201 -442 479 -452 203 -254 217 -212 241 -216 217 -256 207 -202 439 -240 245 -430 237 -218 463 -240 217 -428 465 -202 253 -218 213 -234 219 +RAW_Data: -444 443 -452 455 -244 213 -440 237 -254 427 -450 429 -480 417 -454 477 -430 445 -244 217 -250 203 -224 253 -220 215 -206 221 -462 217 -212 467 -234 231 -440 239 -220 427 -446 219 -242 211 -244 237 -206 451 -458 451 -458 203 -254 427 -450 441 -246 213 -242 193 -244 211 -242 211 -212 241 -442 451 -454 245 -214 241 -198 255 -218 217 -210 225 -212 461 -246 213 -440 225 -242 435 -240 209 -456 457 -246 211 -204 229 -254 219 -428 445 -452 445 -238 253 -426 231 -232 435 -448 455 -448 439 -446 449 -456 451 -230 223 -214 241 -212 211 -242 211 -244 237 -442 237 -218 427 -232 221 -442 239 -246 427 -458 245 -212 205 -228 253 -220 427 -446 471 -442 237 -216 451 -462 411 -244 251 -216 205 -222 211 -242 211 -242 211 -480 453 -418 245 -252 207 -202 253 -218 219 -210 229 -256 425 -232 221 -430 251 -212 469 -204 235 -446 441 -246 213 -242 193 -244 211 -464 451 -456 441 -248 215 -450 201 -256 427 -452 457 -450 455 -450 439 -446 451 -238 217 -256 207 -202 255 -218 217 -210 231 -442 237 -244 423 -240 217 -464 203 -254 419 -454 227 -210 243 -212 241 -212 477 -418 453 -484 199 -226 431 -267004 97 -422 97 -164 65 -490 97 -2222 559 -66 163 -64 295 -100 497 -100 263 -98 361 -460 793 -66 1803 -100 339 -68 1733 + diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c new file mode 100644 index 00000000..0dc81f2a --- /dev/null +++ b/lib/subghz/protocols/power_smart.c @@ -0,0 +1,380 @@ +#include "power_smart.h" +#include +#include +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolPowerSmart" +#define POWER_SMART_PACKET_HEADER 0xFD000000AA000000 +#define POWER_SMART_PACKET_HEADER_MASK 0xFF000000FF000000 + +#define CHANNEL_PATTERN "%c%c%c%c%c%c" +#define CNT_TO_CHANNEL(dip) \ + (dip & 0x0001 ? '*' : '-'), (dip & 0x0002 ? '*' : '-'), (dip & 0x0004 ? '*' : '-'), \ + (dip & 0x0008 ? '*' : '-'), (dip & 0x0010 ? '*' : '-'), (dip & 0x0020 ? '*' : '-') + +static const SubGhzBlockConst subghz_protocol_power_smart_const = { + .te_short = 225, + .te_long = 450, + .te_delta = 100, + .min_count_bit_for_found = 64, +}; + +struct SubGhzProtocolDecoderPowerSmart { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + ManchesterState manchester_saved_state; + uint16_t header_count; +}; + +struct SubGhzProtocolEncoderPowerSmart { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + PowerSmartDecoderStepReset = 0, + PowerSmartDecoderFoundHeader, + PowerSmartDecoderStepDecoderData, +} PowerSmartDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_power_smart_decoder = { + .alloc = subghz_protocol_decoder_power_smart_alloc, + .free = subghz_protocol_decoder_power_smart_free, + + .feed = subghz_protocol_decoder_power_smart_feed, + .reset = subghz_protocol_decoder_power_smart_reset, + + .get_hash_data = subghz_protocol_decoder_power_smart_get_hash_data, + .serialize = subghz_protocol_decoder_power_smart_serialize, + .deserialize = subghz_protocol_decoder_power_smart_deserialize, + .get_string = subghz_protocol_decoder_power_smart_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_power_smart_encoder = { + .alloc = subghz_protocol_encoder_power_smart_alloc, + .free = subghz_protocol_encoder_power_smart_free, + + .deserialize = subghz_protocol_encoder_power_smart_deserialize, + .stop = subghz_protocol_encoder_power_smart_stop, + .yield = subghz_protocol_encoder_power_smart_yield, +}; + +const SubGhzProtocol subghz_protocol_power_smart = { + .name = SUBGHZ_PROTOCOL_POWER_SMART_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_power_smart_decoder, + .encoder = &subghz_protocol_power_smart_encoder, +}; + +void* subghz_protocol_encoder_power_smart_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderPowerSmart* instance = malloc(sizeof(SubGhzProtocolEncoderPowerSmart)); + + instance->base.protocol = &subghz_protocol_power_smart; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 1024; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_runing = false; + return instance; +} + +void subghz_protocol_encoder_power_smart_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderPowerSmart* instance = context; + free(instance->encoder.upload); + free(instance); +} + +static LevelDuration + subghz_protocol_encoder_power_smart_add_duration_to_upload(ManchesterEncoderResult result) { + LevelDuration data = {.duration = 0, .level = 0}; + switch(result) { + case ManchesterEncoderResultShortLow: + data.duration = subghz_protocol_power_smart_const.te_short; + data.level = false; + break; + case ManchesterEncoderResultLongLow: + data.duration = subghz_protocol_power_smart_const.te_long; + data.level = false; + break; + case ManchesterEncoderResultLongHigh: + data.duration = subghz_protocol_power_smart_const.te_long; + data.level = true; + break; + case ManchesterEncoderResultShortHigh: + data.duration = subghz_protocol_power_smart_const.te_short; + data.level = true; + break; + + default: + furi_crash("SubGhz: ManchesterEncoderResult is incorrect."); + break; + } + return level_duration_make(data.level, data.duration); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderPowerSmart instance + */ +static void + subghz_protocol_encoder_power_smart_get_upload(SubGhzProtocolEncoderPowerSmart* instance) { + furi_assert(instance); + size_t index = 0; + + ManchesterEncoderState enc_state; + manchester_encoder_reset(&enc_state); + ManchesterEncoderResult result; + + for(int i = 8; i > 0; i--) { + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(!manchester_encoder_advance( + &enc_state, !bit_read(instance->generic.data, i - 1), &result)) { + instance->encoder.upload[index++] = + subghz_protocol_encoder_power_smart_add_duration_to_upload(result); + manchester_encoder_advance( + &enc_state, !bit_read(instance->generic.data, i - 1), &result); + } + instance->encoder.upload[index++] = + subghz_protocol_encoder_power_smart_add_duration_to_upload(result); + } + } + instance->encoder.upload[index] = subghz_protocol_encoder_power_smart_add_duration_to_upload( + manchester_encoder_finish(&enc_state)); + if(level_duration_get_level(instance->encoder.upload[index])) { + index++; + } + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_power_smart_const.te_long * 1111); + instance->encoder.size_upload = index; +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_power_smart_remote_controller(SubGhzBlockGeneric* instance) { + /* + * Protocol: Manchester encoding, symbol rate ~2222. + * Packet Format: + * 0xFDXXXXYYAAZZZZWW where 0xFD and 0xAA sync word + * XXXX = ~ZZZZ, YY=(~WW)-1 + * Example: + * SYNC1 K1 CHANNEL DATA1 K2 DATA2 SYNC2 ~K1 ~CHANNEL ~DATA2 ~K2 (~DATA2)-1 + * 0xFD2137ACAADEC852 => 11111101 0 010000 10011011 1 10101100 10101010 1 1011110 1100100 0 01010010 + * 0xFDA137ACAA5EC852 => 11111101 1 010000 10011011 1 10101100 10101010 0 1011110 1100100 0 01010010 + * 0xFDA136ACAA5EC952 => 11111101 1 010000 10011011 0 10101100 10101010 0 1011110 1100100 1 01010010 + * + * Key: + * K1K2 + * 0 0 - key_unknown + * 0 1 - key_down + * 1 0 - key_up + * 1 1 - key_stop + * + */ + + instance->btn = ((instance->data >> 54) & 0x02) | ((instance->data >> 40) & 0x1); + instance->serial = ((instance->data >> 33) & 0x3FFF00) | ((instance->data >> 32) & 0xFF); + instance->cnt = ((instance->data >> 49) & 0x3F); +} + +bool subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderPowerSmart* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_power_smart_remote_controller(&instance->generic); + subghz_protocol_encoder_power_smart_get_upload(instance); + instance->encoder.is_runing = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_power_smart_stop(void* context) { + SubGhzProtocolEncoderPowerSmart* instance = context; + instance->encoder.is_runing = false; +} + +LevelDuration subghz_protocol_encoder_power_smart_yield(void* context) { + SubGhzProtocolEncoderPowerSmart* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { + instance->encoder.is_runing = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_power_smart_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderPowerSmart* instance = malloc(sizeof(SubGhzProtocolDecoderPowerSmart)); + instance->base.protocol = &subghz_protocol_power_smart; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_power_smart_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + free(instance); +} + +void subghz_protocol_decoder_power_smart_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); +} + +bool subghz_protocol_power_smart_chek_valid(uint64_t packet) { + uint32_t data_1 = (uint32_t)((packet >> 40) & 0xFFFF); + uint32_t data_2 = (uint32_t)((~packet >> 8) & 0xFFFF); + uint8_t data_3 = (uint8_t)(packet >> 32) & 0xFF; + uint8_t data_4 = (uint8_t)(((~packet) & 0xFF) - 1); + return (data_1 == data_2) && (data_3 == data_4); +} + +void subghz_protocol_decoder_power_smart_feed( + void* context, + bool level, + volatile uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + ManchesterEvent event = ManchesterEventReset; + if(!level) { + if(DURATION_DIFF(duration, subghz_protocol_power_smart_const.te_short) < + subghz_protocol_power_smart_const.te_delta) { + event = ManchesterEventShortLow; + } else if( + DURATION_DIFF(duration, subghz_protocol_power_smart_const.te_long) < + subghz_protocol_power_smart_const.te_delta * 2) { + event = ManchesterEventLongLow; + } + } else { + if(DURATION_DIFF(duration, subghz_protocol_power_smart_const.te_short) < + subghz_protocol_power_smart_const.te_delta) { + event = ManchesterEventShortHigh; + } else if( + DURATION_DIFF(duration, subghz_protocol_power_smart_const.te_long) < + subghz_protocol_power_smart_const.te_delta * 2) { + event = ManchesterEventLongHigh; + } + } + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + instance->manchester_saved_state, event, &instance->manchester_saved_state, &data); + + if(data_ok) { + instance->decoder.decode_data = (instance->decoder.decode_data << 1) | !data; + } + if((instance->decoder.decode_data & POWER_SMART_PACKET_HEADER_MASK) == + POWER_SMART_PACKET_HEADER) { + if(subghz_protocol_power_smart_chek_valid(instance->decoder.decode_data)) { + instance->decoder.decode_data = instance->decoder.decode_data; + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = + subghz_protocol_power_smart_const.min_count_bit_for_found; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + } + } else { + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + } +} + +static const char* subghz_protocol_power_smart_get_name_button(uint8_t btn) { + btn &= 0x3; + const char* name_btn[0x4] = {"Unknown", "Down", "Up", "Stop"}; + return name_btn[btn]; +} + +uint8_t subghz_protocol_decoder_power_smart_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_power_smart_serialize( + void* context, + FlipperFormat* flipper_format, + uint32_t frequency, + FuriHalSubGhzPreset preset) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); +} + +bool subghz_protocol_decoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + return subghz_block_generic_deserialize(&instance->generic, flipper_format); +} + +void subghz_protocol_decoder_power_smart_get_string(void* context, string_t output) { + furi_assert(context); + SubGhzProtocolDecoderPowerSmart* instance = context; + subghz_protocol_power_smart_remote_controller(&instance->generic); + + string_cat_printf( + output, + "%s %db\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%07lX \r\n" + "Btn:%s\r\n" + "Channel:" CHANNEL_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data & 0xFFFFFFFF), + instance->generic.serial, + subghz_protocol_power_smart_get_name_button(instance->generic.btn), + CNT_TO_CHANNEL(instance->generic.cnt)); +} diff --git a/lib/subghz/protocols/power_smart.h b/lib/subghz/protocols/power_smart.h new file mode 100644 index 00000000..346fe537 --- /dev/null +++ b/lib/subghz/protocols/power_smart.h @@ -0,0 +1,109 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_POWER_SMART_NAME "Power Smart" + +typedef struct SubGhzProtocolDecoderPowerSmart SubGhzProtocolDecoderPowerSmart; +typedef struct SubGhzProtocolEncoderPowerSmart SubGhzProtocolEncoderPowerSmart; + +extern const SubGhzProtocolDecoder subghz_protocol_power_smart_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_power_smart_encoder; +extern const SubGhzProtocol subghz_protocol_power_smart; + +/** + * Allocate SubGhzProtocolEncoderPowerSmart. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderPowerSmart* pointer to a SubGhzProtocolEncoderPowerSmart instance + */ +void* subghz_protocol_encoder_power_smart_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderPowerSmart. + * @param context Pointer to a SubGhzProtocolEncoderPowerSmart instance + */ +void subghz_protocol_encoder_power_smart_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderPowerSmart instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderPowerSmart instance + */ +void subghz_protocol_encoder_power_smart_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderPowerSmart instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_power_smart_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderPowerSmart. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderPowerSmart* pointer to a SubGhzProtocolDecoderPowerSmart instance + */ +void* subghz_protocol_decoder_power_smart_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderPowerSmart. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + */ +void subghz_protocol_decoder_power_smart_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderPowerSmart. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + */ +void subghz_protocol_decoder_power_smart_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_power_smart_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_power_smart_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderPowerSmart. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param frequency The frequency at which the signal was received, Hz + * @param preset The modulation on which the signal was received, FuriHalSubGhzPreset + * @return true On success + */ +bool subghz_protocol_decoder_power_smart_serialize( + void* context, + FlipperFormat* flipper_format, + uint32_t frequency, + FuriHalSubGhzPreset preset); + +/** + * Deserialize data SubGhzProtocolDecoderPowerSmart. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_power_smart_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderPowerSmart instance + * @param output Resulting text + */ +void subghz_protocol_decoder_power_smart_get_string(void* context, string_t output); diff --git a/lib/subghz/protocols/registry.c b/lib/subghz/protocols/registry.c index 668e6ad5..5a09ee8c 100644 --- a/lib/subghz/protocols/registry.c +++ b/lib/subghz/protocols/registry.c @@ -1,15 +1,15 @@ #include "registry.h" const SubGhzProtocol* subghz_protocol_registry[] = { - &subghz_protocol_gate_tx, &subghz_protocol_keeloq, &subghz_protocol_star_line, - &subghz_protocol_nice_flo, &subghz_protocol_came, &subghz_protocol_faac_slh, - &subghz_protocol_nice_flor_s, &subghz_protocol_came_twee, &subghz_protocol_came_atomo, - &subghz_protocol_nero_sketch, &subghz_protocol_ido, &subghz_protocol_kia, - &subghz_protocol_hormann, &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis, - &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, - &subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2, - &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, - &subghz_protocol_chamb_code, + &subghz_protocol_gate_tx, &subghz_protocol_keeloq, &subghz_protocol_star_line, + &subghz_protocol_nice_flo, &subghz_protocol_came, &subghz_protocol_faac_slh, + &subghz_protocol_nice_flor_s, &subghz_protocol_came_twee, &subghz_protocol_came_atomo, + &subghz_protocol_nero_sketch, &subghz_protocol_ido, &subghz_protocol_kia, + &subghz_protocol_hormann, &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis, + &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, + &subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2, + &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, + &subghz_protocol_chamb_code, &subghz_protocol_power_smart, }; diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h index 39322380..d64b0cdd 100644 --- a/lib/subghz/protocols/registry.h +++ b/lib/subghz/protocols/registry.h @@ -27,6 +27,7 @@ #include "megacode.h" #include "holtek.h" #include "chamberlain_code.h" +#include "power_smart.h" /** * Registration by name SubGhzProtocol. From f3b1475ede9b4d6240c492d708af4d317381a55c Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 26 Jun 2022 15:00:03 +0300 Subject: [PATCH 14/17] [FL-2052] New build system based on scons (#1269) --- .github/workflows/build.yml | 24 +- .github/workflows/lint_c.yml | 2 +- .gitignore | 8 + .gitmodules | 3 + Brewfile | 2 - CODING_STYLE.md | 2 +- Makefile | 178 +--- ReadMe.md | 28 +- SConstruct | 150 ++++ applications/ReadMe.md | 3 - applications/about/about.c | 12 +- applications/about/application.fam | 13 + applications/accessor/application.fam | 10 + applications/applications.c | 549 ------------ applications/applications.mk | 353 -------- applications/archive/application.fam | 11 + applications/bad_usb/application.fam | 14 + applications/bt/application.fam | 66 ++ applications/cli/application.fam | 9 + applications/crypto/application.fam | 6 + applications/debug_tools/application.fam | 115 +++ applications/desktop/application.fam | 30 + .../desktop/views/desktop_view_debug.c | 10 +- applications/dialogs/application.fam | 10 + applications/dolphin/application.fam | 23 + applications/extapps.scons | 57 ++ applications/gpio/application.fam | 11 + applications/gui/application.fam | 13 + applications/ibutton/application.fam | 23 + applications/infrared/application.fam | 23 + applications/input/application.fam | 9 + applications/lfrfid/application.fam | 26 + applications/lfrfid_debug/application.fam | 12 + applications/loader/application.fam | 10 + applications/meta/application.fam | 41 + applications/music_player/application.fam | 22 + applications/nfc/application.fam | 23 + applications/notification/application.fam | 21 + applications/power/application.fam | 53 ++ applications/rpc/application.fam | 12 + applications/rpc/rpc_storage.c | 40 +- applications/snake_game/application.fam | 11 + applications/storage/application.fam | 19 + applications/storage_settings/application.fam | 9 + applications/subghz/application.fam | 24 + .../subghz/scenes/subghz_scene_save_success.c | 2 +- applications/system/application.fam | 9 + applications/u2f/application.fam | 14 + applications/unit_tests/application.fam | 18 + applications/unit_tests/rpc/rpc_test.c | 21 +- applications/unit_tests/test_index.c | 2 +- applications/updater/application.fam | 39 + assets/Makefile | 48 - assets/ReadMe.md | 9 +- assets/SConscript | 113 +++ assets/assets.mk | 32 - assets/compiled/application.pb.c | 18 - assets/compiled/application.pb.h | 79 -- assets/compiled/assets_dolphin_blocking.c | 330 ------- assets/compiled/assets_dolphin_blocking.h | 7 - assets/compiled/assets_dolphin_internal.c | 330 ------- assets/compiled/assets_dolphin_internal.h | 7 - assets/compiled/assets_icons.c | 829 ------------------ assets/compiled/assets_icons.h | 178 ---- assets/compiled/flipper.pb.c | 19 - assets/compiled/flipper.pb.h | 302 ------- assets/compiled/gui.pb.c | 29 - assets/compiled/gui.pb.h | 152 ---- assets/compiled/protobuf_version.h | 3 - assets/compiled/storage.pb.c | 61 -- assets/compiled/storage.pb.h | 328 ------- assets/compiled/system.pb.c | 62 -- assets/compiled/system.pb.h | 342 -------- assets/copro.mk | 14 - assets/icons/About/Certification1_103x23.png | Bin 2105 -> 0 bytes assets/icons/About/Certification1_103x56.png | Bin 0 -> 3038 bytes assets/icons/About/Certification2_119x30.png | Bin 2437 -> 0 bytes assets/icons/About/Certification2_98x33.png | Bin 0 -> 2495 bytes assets/icons/Archive/back_10px.png | Bin 154 -> 154 bytes assets/icons/Common/Loading_24/frame_01.png | Bin 233 -> 194 bytes assets/icons/Common/Loading_24/frame_02.png | Bin 245 -> 194 bytes assets/icons/Common/Loading_24/frame_03.png | Bin 239 -> 192 bytes assets/icons/Common/Loading_24/frame_04.png | Bin 234 -> 190 bytes assets/icons/Common/Loading_24/frame_05.png | Bin 246 -> 203 bytes assets/icons/Common/Loading_24/frame_06.png | Bin 234 -> 184 bytes assets/icons/Common/Loading_24/frame_07.png | Bin 249 -> 203 bytes .../Dolphin/DolphinFirstStart5_54x49.png | Bin 1856 -> 1721 bytes assets/splash.mk | 3 - core/SConscript | 13 + core/core.mk | 8 - docker/Dockerfile | 7 +- documentation/AppManifests.md | 3 + documentation/OTA.md | 6 +- documentation/fbt.md | 77 ++ fbt | 12 + fbt.cmd | 8 + fbt_options.py | 72 ++ firmware.scons | 227 +++++ firmware/Makefile | 27 - firmware/ReadMe.md | 35 +- firmware/SConscript | 14 + firmware/targets/f7/application-ext.ld | 37 + firmware/targets/f7/ble_glue/ble_glue.c | 33 +- firmware/targets/f7/ble_glue/ble_glue.h | 2 + .../targets/f7/ble_glue/dev_info_service.c | 31 +- .../targets/f7/ble_glue/dev_info_service.h | 6 - firmware/targets/f7/ble_glue/tl_dbg_conf.h | 1 - firmware/targets/f7/target.mk | 162 ---- lib/SConscript | 78 ++ lib/ST25RFAL002/SConscript | 19 + lib/STM32CubeWB.scons | 66 ++ lib/appframe.scons | 26 + lib/drivers/SConscript | 17 + lib/fatfs/SConscript | 13 + lib/flipper_format/SConscript | 25 + lib/freertos.scons | 28 + lib/infrared/SConscript | 18 + lib/lib.mk | 138 --- lib/libusb_stm32.scons | 24 + lib/littlefs.scons | 20 + lib/microtar.scons | 21 + lib/misc.scons | 46 + lib/nanopb | 2 +- lib/one_wire/ibutton/ibutton_worker_i.h | 6 +- lib/one_wire/one_wire_slave.c | 3 +- lib/scons | 1 + lib/subghz/SConscript | 16 + lib/toolbox/.gitignore | 1 + lib/toolbox/SConscript | 47 + lib/toolbox/path.c | 29 + lib/toolbox/path.h | 9 + lib/toolbox/version.c | 3 + make/base.mk | 11 - make/defaults.mk | 2 - make/freertos-heap.mk | 1 - make/git.mk | 32 - make/rules.mk | 185 ---- make/toolchain.mk | 41 - scripts/assets.py | 43 +- scripts/bin2dfu.py | 3 +- scripts/compile_db.py | 77 -- scripts/flipper/assets/copro.py | 3 +- scripts/flipper/assets/dolphin.py | 18 +- scripts/flipper/assets/icon.py | 69 +- scripts/flipper/assets/manifest.py | 35 +- scripts/flipper/storage.py | 46 +- scripts/flipper/utils/__init__.py | 14 +- scripts/flipper/utils/fff.py | 2 +- scripts/lint.py | 1 + scripts/ob.py | 8 +- scripts/otp.py | 26 +- scripts/requirements.txt | 7 + scripts/{dist.py => sconsdist.py} | 69 +- scripts/storage.py | 3 +- scripts/version.py | 131 +++ site_scons/cc.scons | 47 + site_scons/commandline.scons | 202 +++++ site_scons/environ.scons | 82 ++ site_scons/fbt/__init__.py | 0 site_scons/fbt/appmanifest.py | 243 +++++ site_scons/fbt/util.py | 19 + site_scons/fbt/version.py | 23 + site_scons/firmwareopts.scons | 50 ++ site_scons/site_init.py | 40 + site_scons/site_tools/ccache.py | 14 + site_scons/site_tools/crosscc.py | 72 ++ site_scons/site_tools/fbt_apps.py | 61 ++ site_scons/site_tools/fbt_assets.py | 151 ++++ site_scons/site_tools/fbt_dist.py | 104 +++ site_scons/site_tools/fbt_extapps.py | 30 + site_scons/site_tools/fbt_version.py | 29 + site_scons/site_tools/fwbin.py | 52 ++ site_scons/site_tools/gdb.py | 33 + site_scons/site_tools/objdump.py | 26 + site_scons/site_tools/openocd.py | 48 + site_scons/site_tools/python3.py | 13 + site_scons/site_tools/sconsmodular.py | 38 + site_scons/site_tools/sconsrecursiveglob.py | 25 + site_scons/site_tools/strip.py | 26 + 179 files changed, 3986 insertions(+), 5196 deletions(-) create mode 100644 SConstruct create mode 100644 applications/about/application.fam create mode 100644 applications/accessor/application.fam delete mode 100644 applications/applications.c delete mode 100644 applications/applications.mk create mode 100644 applications/archive/application.fam create mode 100644 applications/bad_usb/application.fam create mode 100644 applications/bt/application.fam create mode 100644 applications/cli/application.fam create mode 100644 applications/crypto/application.fam create mode 100644 applications/debug_tools/application.fam create mode 100644 applications/desktop/application.fam create mode 100644 applications/dialogs/application.fam create mode 100644 applications/dolphin/application.fam create mode 100644 applications/extapps.scons create mode 100644 applications/gpio/application.fam create mode 100644 applications/gui/application.fam create mode 100644 applications/ibutton/application.fam create mode 100644 applications/infrared/application.fam create mode 100644 applications/input/application.fam create mode 100644 applications/lfrfid/application.fam create mode 100644 applications/lfrfid_debug/application.fam create mode 100644 applications/loader/application.fam create mode 100644 applications/meta/application.fam create mode 100644 applications/music_player/application.fam create mode 100644 applications/nfc/application.fam create mode 100644 applications/notification/application.fam create mode 100644 applications/power/application.fam create mode 100644 applications/rpc/application.fam create mode 100644 applications/snake_game/application.fam create mode 100644 applications/storage/application.fam create mode 100644 applications/storage_settings/application.fam create mode 100644 applications/subghz/application.fam create mode 100644 applications/system/application.fam create mode 100644 applications/u2f/application.fam create mode 100644 applications/unit_tests/application.fam create mode 100644 applications/updater/application.fam delete mode 100644 assets/Makefile create mode 100644 assets/SConscript delete mode 100644 assets/assets.mk delete mode 100644 assets/compiled/application.pb.c delete mode 100644 assets/compiled/application.pb.h delete mode 100644 assets/compiled/assets_dolphin_blocking.c delete mode 100644 assets/compiled/assets_dolphin_blocking.h delete mode 100644 assets/compiled/assets_dolphin_internal.c delete mode 100644 assets/compiled/assets_dolphin_internal.h delete mode 100644 assets/compiled/assets_icons.c delete mode 100644 assets/compiled/assets_icons.h delete mode 100644 assets/compiled/flipper.pb.c delete mode 100644 assets/compiled/flipper.pb.h delete mode 100644 assets/compiled/gui.pb.c delete mode 100644 assets/compiled/gui.pb.h delete mode 100644 assets/compiled/protobuf_version.h delete mode 100644 assets/compiled/storage.pb.c delete mode 100644 assets/compiled/storage.pb.h delete mode 100644 assets/compiled/system.pb.c delete mode 100644 assets/compiled/system.pb.h delete mode 100644 assets/copro.mk delete mode 100644 assets/icons/About/Certification1_103x23.png create mode 100644 assets/icons/About/Certification1_103x56.png delete mode 100644 assets/icons/About/Certification2_119x30.png create mode 100644 assets/icons/About/Certification2_98x33.png delete mode 100644 assets/splash.mk create mode 100644 core/SConscript delete mode 100644 core/core.mk create mode 100644 documentation/AppManifests.md create mode 100644 documentation/fbt.md create mode 100755 fbt create mode 100644 fbt.cmd create mode 100644 fbt_options.py create mode 100644 firmware.scons delete mode 100644 firmware/Makefile create mode 100644 firmware/SConscript create mode 100644 firmware/targets/f7/application-ext.ld delete mode 100644 firmware/targets/f7/target.mk create mode 100644 lib/SConscript create mode 100644 lib/ST25RFAL002/SConscript create mode 100644 lib/STM32CubeWB.scons create mode 100644 lib/appframe.scons create mode 100644 lib/drivers/SConscript create mode 100644 lib/fatfs/SConscript create mode 100644 lib/flipper_format/SConscript create mode 100644 lib/freertos.scons create mode 100644 lib/infrared/SConscript delete mode 100644 lib/lib.mk create mode 100644 lib/libusb_stm32.scons create mode 100644 lib/littlefs.scons create mode 100644 lib/microtar.scons create mode 100644 lib/misc.scons create mode 160000 lib/scons create mode 100644 lib/subghz/SConscript create mode 100644 lib/toolbox/.gitignore create mode 100644 lib/toolbox/SConscript delete mode 100644 make/base.mk delete mode 100644 make/defaults.mk delete mode 100644 make/freertos-heap.mk delete mode 100644 make/git.mk delete mode 100644 make/rules.mk delete mode 100644 make/toolchain.mk delete mode 100755 scripts/compile_db.py create mode 100644 scripts/requirements.txt rename scripts/{dist.py => sconsdist.py} (55%) mode change 100755 => 100644 create mode 100644 scripts/version.py create mode 100644 site_scons/cc.scons create mode 100644 site_scons/commandline.scons create mode 100644 site_scons/environ.scons create mode 100644 site_scons/fbt/__init__.py create mode 100644 site_scons/fbt/appmanifest.py create mode 100644 site_scons/fbt/util.py create mode 100644 site_scons/fbt/version.py create mode 100644 site_scons/firmwareopts.scons create mode 100644 site_scons/site_init.py create mode 100644 site_scons/site_tools/ccache.py create mode 100644 site_scons/site_tools/crosscc.py create mode 100644 site_scons/site_tools/fbt_apps.py create mode 100644 site_scons/site_tools/fbt_assets.py create mode 100644 site_scons/site_tools/fbt_dist.py create mode 100644 site_scons/site_tools/fbt_extapps.py create mode 100644 site_scons/site_tools/fbt_version.py create mode 100644 site_scons/site_tools/fwbin.py create mode 100644 site_scons/site_tools/gdb.py create mode 100644 site_scons/site_tools/objdump.py create mode 100644 site_scons/site_tools/openocd.py create mode 100644 site_scons/site_tools/python3.py create mode 100644 site_scons/site_tools/sconsmodular.py create mode 100644 site_scons/site_tools/sconsrecursiveglob.py create mode 100644 site_scons/site_tools/strip.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 45a97746..15b7f786 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,14 +71,6 @@ jobs: run: | tar czpf artifacts/flipper-z-any-scripts-${{steps.names.outputs.suffix}}.tgz scripts - - name: 'Rebuild Assets' - uses: ./.github/actions/docker - with: - run: | - set -e - make assets_rebuild assets_manifest - git diff --quiet || ( echo "Assets recompilation required."; exit 255 ) - - name: 'Build the firmware in docker' uses: ./.github/actions/docker with: @@ -86,7 +78,7 @@ jobs: set -e for TARGET in ${TARGETS} do - make updater_package TARGET=${TARGET} ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} + ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` --with-updater updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} done - name: 'Move upload files' @@ -97,7 +89,7 @@ jobs: set -e for TARGET in ${TARGETS} do - mv dist/${TARGET}/* artifacts/ + mv dist/${TARGET}-*/* artifacts/ done - name: 'Bundle self-update package' @@ -124,7 +116,7 @@ jobs: uses: ./.github/actions/docker with: run: | - make -C assets copro_bundle + ./fbt copro_dist tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz -C assets core2_firmware - name: 'Upload artifacts to update server' @@ -208,14 +200,6 @@ jobs: echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV - - name: 'Rebuild Assets' - uses: ./.github/actions/docker - with: - run: | - set -e - make assets_rebuild assets_manifest - git diff --quiet || ( echo "Assets recompilation required."; exit 255 ) - - name: 'Build the firmware in docker' uses: ./.github/actions/docker with: @@ -223,5 +207,5 @@ jobs: set -e for TARGET in ${TARGETS} do - make TARGET=${TARGET} DEBUG=0 COMPACT=1 + ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` --with-updater updater_package DEBUG=0 COMPACT=1 done diff --git a/.github/workflows/lint_c.yml b/.github/workflows/lint_c.yml index 97ef9fb9..f834586d 100644 --- a/.github/workflows/lint_c.yml +++ b/.github/workflows/lint_c.yml @@ -47,7 +47,7 @@ jobs: id: syntax_check uses: ./.github/actions/docker with: - run: SET_GH_OUTPUT=1 make lint + run: SET_GH_OUTPUT=1 ./fbt lint - name: Report code formatting errors if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request diff --git a/.gitignore b/.gitignore index 6577101d..2d66413b 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,11 @@ dist # kde .directory + +# SCons +.sconsign.dblite +# SCons build dir +build/ + +# Toolchain +toolchain*/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index c4649fdc..5846b705 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "lib/microtar"] path = lib/microtar url = https://github.com/amachronic/microtar.git +[submodule "lib/scons"] + path = lib/scons + url = https://github.com/SCons/scons.git diff --git a/Brewfile b/Brewfile index 963a687c..d9ba70e0 100644 --- a/Brewfile +++ b/Brewfile @@ -1,8 +1,6 @@ cask "gcc-arm-embedded" brew "protobuf" brew "gdb" -brew "heatshrink" brew "open-ocd" brew "clang-format" brew "dfu-util" -brew "imagemagick" diff --git a/CODING_STYLE.md b/CODING_STYLE.md index ccadbe8e..31426b94 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -48,7 +48,7 @@ Almost everything in flipper firmware is built around this concept. # C coding style - Tab is 4 spaces -- Use `make format` to reformat source code and check style guide before commit +- Use `fbt format` to reformat source code and check style guide before commit ## Naming diff --git a/Makefile b/Makefile index a48ed613..ff701a42 100644 --- a/Makefile +++ b/Makefile @@ -1,157 +1,21 @@ -PROJECT_ROOT := $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))) - -include $(PROJECT_ROOT)/make/git.mk -include $(PROJECT_ROOT)/assets/copro.mk -include $(PROJECT_ROOT)/assets/splash.mk - -PROJECT_SOURCE_DIRECTORIES := \ - $(PROJECT_ROOT)/applications \ - $(PROJECT_ROOT)/core \ - $(PROJECT_ROOT)/firmware/targets \ - $(PROJECT_ROOT)/lib/app-template \ - $(PROJECT_ROOT)/lib/app-scened-template \ - $(PROJECT_ROOT)/lib/common-api \ - $(PROJECT_ROOT)/lib/drivers \ - $(PROJECT_ROOT)/lib/flipper_file \ - $(PROJECT_ROOT)/lib/infrared \ - $(PROJECT_ROOT)/lib/nfc_protocols \ - $(PROJECT_ROOT)/lib/ST25RFAL002 \ - $(PROJECT_ROOT)/lib/onewire \ - $(PROJECT_ROOT)/lib/qrcode \ - $(PROJECT_ROOT)/lib/subghz \ - $(PROJECT_ROOT)/lib/toolbox \ - $(PROJECT_ROOT)/lib/u8g2 - -NPROCS := 3 -OS := $(shell uname -s) - -ifeq ($(OS), Linux) -NPROCS := $(shell grep -c ^processor /proc/cpuinfo) -else ifeq ($(OS), Darwin) -NPROCS := $(shell sysctl -n hw.ncpu) -endif - -include $(PROJECT_ROOT)/make/defaults.mk - -.PHONY: all -all: firmware_all - @$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware -s $(DIST_SUFFIX) - -.PHONY: whole -whole: flash_radio firmware_flash - -.PHONY: clean -clean: firmware_clean updater_clean - @rm -rf $(PROJECT_ROOT)/dist/$(TARGET) - -.PHONY: flash -flash: firmware_flash - -.PHONY: debug -debug: - @$(MAKE) -C firmware -j$(NPROCS) debug - -.PHONY: debug_other -debug_other: - @$(MAKE) -C firmware -j$(NPROCS) debug_other - -.PHONY: blackmagic -blackmagic: - @$(MAKE) -C firmware -j$(NPROCS) blackmagic - -.PHONY: wipe -wipe: - @$(PROJECT_ROOT)/scripts/flash.py wipe - @$(PROJECT_ROOT)/scripts/ob.py set - -.PHONY: firmware_all -firmware_all: - @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) all - -.PHONY: firmware_clean -firmware_clean: - @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) clean - -.PHONY: firmware_flash -firmware_flash: -ifeq ($(FORCE), 1) - @rm $(PROJECT_ROOT)/firmware/.obj/f*-firmware/flash || true -endif - @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash - -.PHONY: updater -updater: - @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all - -.PHONY: updater_clean -updater_clean: - @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 clean - -.PHONY: updater_debug -updater_debug: - @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 debug - -.PHONY: updater_package_bin -updater_package_bin: firmware_all updater - @$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) --bundlever "$(VERSION_STRING)" - -.PHONY: updater_package -updater_package: firmware_all updater assets_manifest - @$(PROJECT_ROOT)/scripts/dist.py copy \ - -t $(TARGET) -p firmware updater \ - -s $(DIST_SUFFIX) -r $(PROJECT_ROOT)/assets/resources \ - --bundlever "$(VERSION_STRING)" \ - --radio $(COPRO_STACK_BIN_PATH) \ - --radiotype $(COPRO_STACK_TYPE) \ - $(COPRO_DISCLAIMER) \ - --obdata $(PROJECT_ROOT)/scripts/$(COPRO_OB_DATA) \ - --splash $(UPDATER_SPLASH_DIR) - -.PHONY: assets_manifest -assets_manifest: - @$(MAKE) -C $(PROJECT_ROOT)/assets manifest - -.PHONY: assets_rebuild -assets_rebuild: - @$(MAKE) -C $(PROJECT_ROOT)/assets clean all - -.PHONY: flash_radio -flash_radio: - @$(PROJECT_ROOT)/scripts/flash.py core2radio $(COPRO_STACK_BIN_PATH) --addr=$(COPRO_STACK_ADDR) - @$(PROJECT_ROOT)/scripts/ob.py set - -.PHONY: flash_radio_fus -flash_radio_fus: - @echo - @echo "================ DON'T DO IT ================" - @echo "= Flashing FUS is going to erase secure enclave =" - @echo "= You will lose ability to use encrypted assets =" - @echo "= type 'find / -exec rm -rf {} \;' =" - @echo "= In case if you still want to continue =" - @echo "================ JUST DON'T ================" - @echo - -.PHONY: flash_radio_fus_please_i_m_not_going_to_complain -flash_radio_fus_please_i_m_not_going_to_complain: - @$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_FIRMWARE_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin - @$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_FIRMWARE_DIR)/stm32wb5x_FUS_fw.bin - @$(PROJECT_ROOT)/scripts/ob.py set - -.PHONY: lint -lint: - @echo "Checking source code formatting" - @$(PROJECT_ROOT)/scripts/lint.py check $(PROJECT_SOURCE_DIRECTORIES) - -.PHONY: format -format: - @echo "Reformating sources code" - @$(PROJECT_ROOT)/scripts/lint.py format $(PROJECT_SOURCE_DIRECTORIES) - -.PHONY: guruguru -guruguru: - @echo "ぐるぐる回る" - @$(PROJECT_ROOT)/scripts/guruguru.py $(PROJECT_ROOT) - -.PHONY: generate_compile_db -generate_compile_db: - @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) generate_compile_db \ No newline at end of file +$(info +-------------------------------------------------+) +$(info | |) +$(info | Hello, this is Flipper team speaking! |) +$(info | |) +$(info | We've migrated to new build system |) +$(info | It's nice and based on scons |) +$(info | |) +$(info | Crash course: |) +$(info | |) +$(info | `./fbt` |) +$(info | `./fbt flash` |) +$(info | `./fbt debug` |) +$(info | |) +$(info | More details in documentation/fbt.md |) +$(info | |) +$(info | Also Please leave your feedback here: |) +$(info | https://flipp.dev/4RDu |) +$(info | or |) +$(info | https://flipp.dev/2XM8 |) +$(info | |) +$(info +-------------------------------------------------+) \ No newline at end of file diff --git a/ReadMe.md b/ReadMe.md index 9e34148f..6a3eed37 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -25,6 +25,12 @@ Flipper Zero's firmware consists of two components: They both must be flashed in order described. +## With offline update package + +`./fbt --with-updater updater_package` + +Copy the resulting directory to Flipper's SD card and navigate to `update.fuf` file in Archive app. + ## With STLink ### Core1 Firmware @@ -36,17 +42,7 @@ Prerequisites: - [arm-gcc-none-eabi](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) - openocd -One liner: `make flash` - -### Core2 flashing procedures - -Prerequisites: - -- Linux / macOS -- Terminal -- STM32_Programmer_CLI (v2.5.0) added to $PATH - -One liner: `make flash_radio` +One liner: `./fbt firmware_flash` ## With USB DFU @@ -56,7 +52,6 @@ One liner: `make flash_radio` - Press and hold `← Left` + `↩ Back` for reset - Release `↩ Back` and keep holding `← Left` until blue LED lights up - Release `← Left` - 3. Run `dfu-util -D full.dfu -a 0` @@ -74,7 +69,7 @@ One liner: `make flash_radio` ## Compile everything ```sh -docker-compose exec dev make +docker-compose exec dev ./fbt ``` Check `dist/` for build outputs. @@ -85,6 +80,8 @@ If compilation fails, make sure all submodules are all initialized. Either clone # Build on Linux/macOS +Check out `documentation/fbt.md` for details on building and flashing firmware. + ## macOS Prerequisites Make sure you have [brew](https://brew.sh) and install all the dependencies: @@ -127,7 +124,7 @@ heatshrink has to be compiled [from sources](https://github.com/atomicobject/hea ## Compile everything ```sh -make +./fbt ``` Check `dist/` for build outputs. @@ -138,7 +135,7 @@ Use **`flipper-z-{target}-full-{suffix}.dfu`** to flash your device. Connect your device via ST-Link and run: ```sh -make whole +./fbt firmware_flash ``` # Links @@ -158,7 +155,6 @@ make whole - `documentation` - Documentation generation system configs and input files - `firmware` - Firmware source code - `lib` - Our and 3rd party libraries, drivers and etc... -- `make` - Make helpers - `scripts` - Supplementary scripts and python libraries home Also pay attention to `ReadMe.md` files inside of those directories. diff --git a/SConstruct b/SConstruct new file mode 100644 index 00000000..a31811ae --- /dev/null +++ b/SConstruct @@ -0,0 +1,150 @@ +# +# Main Fipper Build System entry point +# +# This file is evaluated by scons (the build system) every time fbt is invoked. +# Scons constructs all referenced environments & their targets' dependency +# trees on startup. So, to keep startup time as low as possible, we're hiding +# construction of certain targets behind command-line options. + +import os + +DefaultEnvironment(tools=[]) +# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) + + +# This environment is created only for loading options & validating file/dir existance +fbt_variables = SConscript("site_scons/commandline.scons") +cmd_environment = Environment(tools=[], variables=fbt_variables) +Help(fbt_variables.GenerateHelpText(cmd_environment)) + + +# Building basic environment - tools, utility methods, cross-compilation +# settings, gcc flags for Cortex-M4, basic builders and more +coreenv = SConscript( + "site_scons/environ.scons", + exports={"VAR_ENV": cmd_environment}, +) +SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) + +# Store root dir in environment for certain tools +coreenv["ROOT_DIR"] = Dir(".") + +# Create a separate "dist" environment and add construction envs to it +distenv = coreenv.Clone( + tools=["fbt_dist", "openocd"], + GDBOPTS="-ex 'target extended-remote | ${OPENOCD} -c \"gdb_port pipe\" ${OPENOCD_OPTS}' " + '-ex "set confirm off" ', + ENV=os.environ, +) + +firmware_out = distenv.AddFwProject( + base_env=coreenv, + fw_type="firmware", + fw_env_key="FW_ENV", +) + + +# If enabled, initialize updater-related targets +if GetOption("fullenv"): + updater_out = distenv.AddFwProject( + base_env=coreenv, + fw_type="updater", + fw_env_key="UPD_ENV", + ) + + # Target for self-update package + dist_arguments = [ + "-r", + '"${ROOT_DIR.abspath}/assets/resources"', + "--bundlever", + '"${UPDATE_VERSION_STRING}"', + "--radio", + '"${ROOT_DIR.abspath}/${COPRO_STACK_BIN_DIR}/${COPRO_STACK_BIN}"', + "--radiotype", + "${COPRO_STACK_TYPE}", + "${COPRO_DISCLAIMER}", + "--obdata", + '"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"', + ] + if distenv["UPDATE_SPLASH"]: + dist_arguments += [ + "--splash", + distenv.subst("assets/slideshow/$UPDATE_SPLASH"), + ] + selfupdate_dist = distenv.DistBuilder( + "selfupdate.pseudo", + (distenv["DIST_DEPENDS"], firmware_out["FW_RESOURCES"]), + DIST_EXTRA=dist_arguments, + ) + distenv.Pseudo("selfupdate.pseudo") + AlwaysBuild(selfupdate_dist) + Alias("updater_package", selfupdate_dist) + + # Updater debug + debug_updater_elf = distenv.AddDebugTarget(updater_out, False) + Alias("updater_debug", debug_updater_elf) + + +# Target for copying & renaming binaries to dist folder +basic_dist = distenv.DistBuilder("dist.pseudo", distenv["DIST_DEPENDS"]) +distenv.Pseudo("dist.pseudo") +AlwaysBuild(basic_dist) +Alias("fw_dist", basic_dist) +Default(basic_dist) + +# Target for bundling core2 package for qFlipper +copro_dist = distenv.CoproBuilder( + Dir("assets/core2_firmware"), + [], +) +AlwaysBuild(copro_dist) +Alias("copro_dist", copro_dist) + + +# Debugging firmware + +debug_fw_elf = distenv.AddDebugTarget(firmware_out) +Alias("debug", debug_fw_elf) + + +# Debug alien elf +debug_other = distenv.GDBPy( + "debugother.pseudo", + None, + GDBPYOPTS= + # '-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' + '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ' +) +distenv.Pseudo("debugother.pseudo") +AlwaysBuild(debug_other) +Alias("debug_other", debug_other) + + +# Just start OpenOCD +openocd = distenv.OOCDCommand("openocd.pseudo", []) +distenv.Pseudo("openocd.pseudo") +AlwaysBuild(openocd) +Alias("openocd", openocd) + + +# Linter +lint_check = distenv.Command( + "lint.check.pseudo", + [], + "${PYTHON3} scripts/lint.py check $LINT_SOURCES", + LINT_SOURCES=firmware_out["LINT_SOURCES"], +) +distenv.Pseudo("lint.check.pseudo") +AlwaysBuild(lint_check) +Alias("lint", lint_check) + + +lint_format = distenv.Command( + "lint.format.pseudo", + [], + "${PYTHON3} scripts/lint.py format $LINT_SOURCES", + LINT_SOURCES=firmware_out["LINT_SOURCES"], +) +distenv.Pseudo("lint.format.pseudo") +AlwaysBuild(lint_format) +Alias("format", lint_format) diff --git a/applications/ReadMe.md b/applications/ReadMe.md index 2c78dfa2..cb2f5628 100644 --- a/applications/ReadMe.md +++ b/applications/ReadMe.md @@ -16,7 +16,6 @@ - `ibutton` - iButton application, onewire keys and more - `input` - Input service - `infrared` - Infrared application, controls your IR devices -- `infrared_monitor` - Infrared debug tool - `lfrfid` - LF RFID application - `lfrfid_debug` - LF RFID debug tool - `loader` - Application loader service @@ -36,6 +35,4 @@ - `u2f` - U2F Application - `updater` - Update service & application -- `application.c` - Firmware application list source - `application.h` - Firmware application list header -- `application.mk` - Makefile helper diff --git a/applications/about/about.c b/applications/about/about.c index 7c8a4c69..6f8ebdf3 100644 --- a/applications/about/about.c +++ b/applications/about/about.c @@ -5,6 +5,7 @@ #include #include #include +#include typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message); @@ -57,7 +58,7 @@ static DialogMessageButton compliance_screen(DialogsApp* dialogs, DialogMessage* static DialogMessageButton icon1_screen(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; - dialog_message_set_icon(message, &I_Certification1_103x23, 12, 12); + dialog_message_set_icon(message, &I_Certification1_103x56, 13, 0); result = dialog_message_show(dialogs, message); dialog_message_set_icon(message, NULL, 0, 0); @@ -67,7 +68,7 @@ static DialogMessageButton icon1_screen(DialogsApp* dialogs, DialogMessage* mess static DialogMessageButton icon2_screen(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; - dialog_message_set_icon(message, &I_Certification2_119x30, 4, 9); + dialog_message_set_icon(message, &I_Certification2_98x33, 15, 10); result = dialog_message_show(dialogs, message); dialog_message_set_icon(message, NULL, 0, 0); @@ -111,18 +112,23 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* string_t buffer; string_init(buffer); const Version* ver = furi_hal_version_get_firmware_version(); + const BleGlueC2Info* c2_ver = NULL; +#ifdef SRV_BT + c2_ver = ble_glue_get_c2_info(); +#endif if(!ver) { string_cat_printf(buffer, "No info\n"); } else { string_cat_printf( buffer, - "%s [%s]\n%s%s [%s]\n[%d] %s", + "%s [%s]\n%s%s [%s] %s\n[%d] %s", version_get_version(ver), version_get_builddate(ver), version_get_dirty_flag(ver) ? "[!] " : "", version_get_githash(ver), version_get_gitbranchnum(ver), + c2_ver ? c2_ver->StackTypeString : "", version_get_target(ver), version_get_gitbranch(ver)); } diff --git a/applications/about/application.fam b/applications/about/application.fam new file mode 100644 index 00000000..d97817b4 --- /dev/null +++ b/applications/about/application.fam @@ -0,0 +1,13 @@ +App( + appid="about", + name="About", + apptype=FlipperAppType.SETTINGS, + entry_point="about_settings_app", + cdefines=["APP_ABOUT"], + requires=[ + "gui", + "dialogs", + ], + stack_size=1 * 1024, + order=1000, +) diff --git a/applications/accessor/application.fam b/applications/accessor/application.fam new file mode 100644 index 00000000..8a94049e --- /dev/null +++ b/applications/accessor/application.fam @@ -0,0 +1,10 @@ +App( + appid="accessor", + name="Accessor", + apptype=FlipperAppType.DEBUG, + entry_point="accessor_app", + cdefines=["APP_ACCESSOR"], + requires=["gui"], + stack_size=4 * 1024, + order=40, +) diff --git a/applications/applications.c b/applications/applications.c deleted file mode 100644 index 22f9520e..00000000 --- a/applications/applications.c +++ /dev/null @@ -1,549 +0,0 @@ -#include "applications.h" -#include - -// Services -extern int32_t rpc_srv(void* p); -extern int32_t bt_srv(void* p); -extern int32_t cli_srv(void* p); -extern int32_t dialogs_srv(void* p); -extern int32_t dolphin_srv(void* p); -extern int32_t gui_srv(void* p); -extern int32_t input_srv(void* p); -extern int32_t loader_srv(void* p); -extern int32_t notification_srv(void* p); -extern int32_t power_srv(void* p); -extern int32_t storage_srv(void* p); -extern int32_t desktop_srv(void* p); -extern int32_t updater_srv(void* p); - -// Apps -extern int32_t accessor_app(void* p); -extern int32_t archive_app(void* p); -extern int32_t bad_usb_app(void* p); -extern int32_t u2f_app(void* p); -extern int32_t uart_echo_app(void* p); -extern int32_t blink_test_app(void* p); -extern int32_t bt_debug_app(void* p); -extern int32_t delay_test_app(void* p); -extern int32_t display_test_app(void* p); -extern int32_t gpio_app(void* p); -extern int32_t ibutton_app(void* p); -extern int32_t infrared_app(void* p); -extern int32_t keypad_test_app(void* p); -extern int32_t lfrfid_app(void* p); -extern int32_t lfrfid_debug_app(void* p); -extern int32_t nfc_app(void* p); -extern int32_t passport_app(void* p); -extern int32_t scened_app(void* p); -extern int32_t storage_test_app(void* p); -extern int32_t subghz_app(void* p); -extern int32_t usb_mouse_app(void* p); -extern int32_t usb_test_app(void* p); -extern int32_t vibro_test_app(void* p); -extern int32_t bt_hid_app(void* p); -extern int32_t battery_test_app(void* p); -extern int32_t text_box_test_app(void* p); -extern int32_t file_browser_app(void* p); - -// Plugins -extern int32_t music_player_app(void* p); -extern int32_t snake_game_app(void* p); - -// On system start hooks declaration -extern void bt_on_system_start(); -extern void crypto_on_system_start(); -extern void ibutton_on_system_start(); -extern void infrared_on_system_start(); -extern void lfrfid_on_system_start(); -extern void music_player_on_system_start(); -extern void nfc_on_system_start(); -extern void storage_on_system_start(); -extern void subghz_on_system_start(); -extern void power_on_system_start(); -extern void unit_tests_on_system_start(); -extern void updater_on_system_start(); - -// Settings -extern int32_t notification_settings_app(void* p); -extern int32_t storage_settings_app(void* p); -extern int32_t bt_settings_app(void* p); -extern int32_t desktop_settings_app(void* p); -extern int32_t about_settings_app(void* p); -extern int32_t power_settings_app(void* p); -extern int32_t system_settings_app(void* p); - -const FlipperApplication FLIPPER_SERVICES[] = { -/* Services */ -#ifdef SRV_RPC - {.app = rpc_srv, - .name = "RpcSrv", - .stack_size = 1024 * 4, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_BT - {.app = bt_srv, - .name = "BtSrv", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_CLI - {.app = cli_srv, - .name = "CliSrv", - .stack_size = 4096, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_DIALOGS - {.app = dialogs_srv, - .name = "DialogsSrv", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_DOLPHIN - {.app = dolphin_srv, - .name = "DolphinSrv", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_DESKTOP -#ifdef SRV_UPDATER -#error SRV_UPDATER and SRV_DESKTOP are mutually exclusive! -#endif - {.app = desktop_srv, - .name = "DesktopSrv", - .stack_size = 2048, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_GUI - {.app = gui_srv, - .name = "GuiSrv", - .stack_size = 2048, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_INPUT - {.app = input_srv, - .name = "InputSrv", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_LOADER - {.app = loader_srv, - .name = "LoaderSrv", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_NOTIFICATION - {.app = notification_srv, - .name = "NotificationSrv", - .stack_size = 1536, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_POWER - {.app = power_srv, - .name = "PowerSrv", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_STORAGE - {.app = storage_srv, - .name = "StorageSrv", - .stack_size = 3072, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_UPDATER -#ifdef SRV_DESKTOP -#error SRV_UPDATER and SRV_DESKTOP are mutually exclusive! -#endif - {.app = updater_srv, - .name = "UpdaterSrv", - .stack_size = 2048, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif -}; - -const size_t FLIPPER_SERVICES_COUNT = COUNT_OF(FLIPPER_SERVICES); - -const FlipperApplication FLIPPER_SYSTEM_APPS[] = { -#ifdef APP_UPDATER -#ifdef SRV_UPDATER -#error APP_UPDATER and SRV_UPDATER are mutually exclusive! -#endif - {.app = updater_srv, - .name = "UpdaterApp", - .stack_size = 2048, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif -}; - -const size_t FLIPPER_SYSTEM_APPS_COUNT = COUNT_OF(FLIPPER_SYSTEM_APPS); - -// Main menu APP -const FlipperApplication FLIPPER_APPS[] = { - -#ifdef APP_SUBGHZ - {.app = subghz_app, - .name = "Sub-GHz", - .stack_size = 2048, - .icon = &A_Sub1ghz_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_LF_RFID - {.app = lfrfid_app, - .name = "125 kHz RFID", - .stack_size = 2048, - .icon = &A_125khz_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_NFC - {.app = nfc_app, - .name = "NFC", - .stack_size = 4096, - .icon = &A_NFC_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_INFRARED - {.app = infrared_app, - .name = "Infrared", - .stack_size = 1024 * 3, - .icon = &A_Infrared_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_GPIO - {.app = gpio_app, - .name = "GPIO", - .stack_size = 1024, - .icon = &A_GPIO_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_IBUTTON - {.app = ibutton_app, - .name = "iButton", - .stack_size = 2048, - .icon = &A_iButton_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_BAD_USB - {.app = bad_usb_app, - .name = "Bad USB", - .stack_size = 2048, - .icon = &A_BadUsb_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_U2F - {.app = u2f_app, - .name = "U2F", - .stack_size = 2048, - .icon = &A_U2F_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -}; - -const size_t FLIPPER_APPS_COUNT = COUNT_OF(FLIPPER_APPS); - -// On system start hooks -const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[] = { - crypto_on_system_start, - -#ifdef APP_INFRARED - infrared_on_system_start, -#endif - -#ifdef APP_MUSIC_PLAYER - music_player_on_system_start, -#endif - -#ifdef APP_NFC - nfc_on_system_start, -#endif - -#ifdef APP_SUBGHZ - subghz_on_system_start, -#endif - -#ifdef APP_LF_RFID - lfrfid_on_system_start, -#endif - -#ifdef APP_IBUTTON - ibutton_on_system_start, -#endif - -#ifdef SRV_BT - bt_on_system_start, -#endif - -#ifdef SRV_POWER - power_on_system_start, -#endif - -#ifdef SRV_STORAGE - storage_on_system_start, -#endif - -#ifdef APP_UNIT_TESTS - unit_tests_on_system_start, -#endif - -#ifdef APP_UPDATER - updater_on_system_start, -#endif -}; - -const size_t FLIPPER_ON_SYSTEM_START_COUNT = COUNT_OF(FLIPPER_ON_SYSTEM_START); - -// Plugin menu -const FlipperApplication FLIPPER_PLUGINS[] = { -#ifdef APP_BLE_HID - {.app = bt_hid_app, - .name = "Bluetooth Remote", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_MUSIC_PLAYER - {.app = music_player_app, - .name = "Music Player", - .stack_size = 2048, - .icon = &A_Plugins_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_SNAKE_GAME - {.app = snake_game_app, - .name = "Snake Game", - .stack_size = 1024, - .icon = &A_Plugins_14, - .flags = FlipperApplicationFlagDefault}, -#endif -}; - -const size_t FLIPPER_PLUGINS_COUNT = COUNT_OF(FLIPPER_PLUGINS); - -// Plugin menu -const FlipperApplication FLIPPER_DEBUG_APPS[] = { -#ifdef APP_BLINK - {.app = blink_test_app, - .name = "Blink Test", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_VIBRO_TEST - {.app = vibro_test_app, - .name = "Vibro Test", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_KEYPAD_TEST - {.app = keypad_test_app, - .name = "Keypad Test", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_ACCESSOR - {.app = accessor_app, - .name = "Accessor", - .stack_size = 4096, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_USB_TEST - {.app = usb_test_app, - .name = "USB Test", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_USB_MOUSE - {.app = usb_mouse_app, - .name = "USB Mouse Demo", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_UART_ECHO - {.app = uart_echo_app, - .name = "Uart Echo", - .stack_size = 2048, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_LF_RFID - {.app = lfrfid_debug_app, - .name = "LF-RFID Debug", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_BT - {.app = bt_debug_app, - .name = "Bluetooth Debug", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_UNIT_TESTS - {.app = delay_test_app, - .name = "Delay Test", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_DISPLAY_TEST - {.app = display_test_app, - .name = "Display Test", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_FILE_BROWSER_TEST - {.app = file_browser_app, - .name = "File Browser test", - .stack_size = 2048, - .icon = &A_BadUsb_14, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_BATTERY_TEST - {.app = battery_test_app, - .name = "Battery Test", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_TEXT_BOX_TEST - {.app = text_box_test_app, - .name = "Text Box Test", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif -}; - -const size_t FLIPPER_DEBUG_APPS_COUNT = COUNT_OF(FLIPPER_DEBUG_APPS); - -#ifdef APP_ARCHIVE -const FlipperApplication FLIPPER_ARCHIVE = { - .app = archive_app, - .name = "Archive", - .stack_size = 4096, - .icon = &A_FileManager_14, - .flags = FlipperApplicationFlagDefault}; -#endif - -// Settings menu -const FlipperApplication FLIPPER_SETTINGS_APPS[] = { -#ifdef SRV_BT - {.app = bt_settings_app, - .name = "Bluetooth", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_NOTIFICATION - {.app = notification_settings_app, - .name = "LCD and Notifications", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_STORAGE - {.app = storage_settings_app, - .name = "Storage", - .stack_size = 2048, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_POWER - {.app = power_settings_app, - .name = "Power", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagInsomniaSafe}, -#endif - -#ifdef SRV_DESKTOP - {.app = desktop_settings_app, - .name = "Desktop", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_PASSPORT - {.app = passport_app, - .name = "Passport", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef SRV_GUI - {.app = system_settings_app, - .name = "System", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - -#ifdef APP_ABOUT - {.app = about_settings_app, - .name = "About", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif -}; - -const size_t FLIPPER_SETTINGS_APPS_COUNT = COUNT_OF(FLIPPER_SETTINGS_APPS); diff --git a/applications/applications.mk b/applications/applications.mk deleted file mode 100644 index d2272efb..00000000 --- a/applications/applications.mk +++ /dev/null @@ -1,353 +0,0 @@ -APP_DIR = $(PROJECT_ROOT)/applications -LIB_DIR = $(PROJECT_ROOT)/lib - -CFLAGS += -I$(APP_DIR) -C_SOURCES += $(shell find $(APP_DIR) -name "*.c") -CPP_SOURCES += $(shell find $(APP_DIR) -name "*.cpp") - -RAM_EXEC ?= 0 -ifeq ($(RAM_EXEC), 1) -APP_RELEASE = 0 -SRV_GUI = 1 -SRV_INPUT = 1 -SRV_NOTIFICATION = 1 -SRV_STORAGE = 1 -SRV_UPDATER = 1 -APP_UPDATER = 0 -endif - -APP_RELEASE ?= 1 -ifeq ($(APP_RELEASE), 1) -# Services -SRV_BT = 1 -SRV_CLI = 1 -SRV_DIALOGS = 1 -SRV_DOLPHIN = 1 -SRV_GUI = 1 -SRV_INPUT = 1 -SRV_LOADER = 1 -SRV_NOTIFICATION = 1 -SRV_POWER = 1 -SRV_RPC = 1 -SRV_STORAGE = 1 - -# Apps -SRV_DESKTOP = 1 -APP_ARCHIVE = 1 -APP_GPIO = 1 -APP_IBUTTON = 1 -APP_INFRARED = 1 -APP_LF_RFID = 1 -APP_NFC = 1 -APP_SUBGHZ = 1 -APP_ABOUT = 1 -APP_PASSPORT = 1 -APP_UPDATER = 1 - -# Plugins -APP_MUSIC_PLAYER = 1 -APP_SNAKE_GAME = 1 - -# Debug -APP_ACCESSOR = 1 -APP_BLINK = 1 -APP_KEYPAD_TEST = 1 -APP_SD_TEST = 1 -APP_VIBRO_TEST = 1 -APP_USB_TEST = 1 -APP_DISPLAY_TEST = 1 -APP_BLE_HID = 1 -APP_USB_MOUSE = 1 -APP_BAD_USB = 1 -APP_U2F = 1 -APP_UART_ECHO = 1 -APP_FILE_BROWSER_TEST = 1 -endif - - -# Applications -# that will be shown in menu -# Prefix with APP_* - -APP_UNIT_TESTS ?= 0 -ifeq ($(APP_UNIT_TESTS), 1) -CFLAGS += -DAPP_UNIT_TESTS -endif - - -APP_ARCHIVE ?= 0 -ifeq ($(APP_ARCHIVE), 1) -CFLAGS += -DAPP_ARCHIVE -SRV_GUI = 1 -endif - - -APP_BLINK ?= 0 -ifeq ($(APP_BLINK), 1) -CFLAGS += -DAPP_BLINK -SRV_GUI = 1 -endif - - -APP_SUBGHZ ?= 0 -ifeq ($(APP_SUBGHZ), 1) -CFLAGS += -DAPP_SUBGHZ -SRV_GUI = 1 -SRV_CLI = 1 -endif - - -APP_ABOUT ?= 0 -ifeq ($(APP_ABOUT), 1) -CFLAGS += -DAPP_ABOUT -SRV_GUI = 1 -endif - - -APP_PASSPORT ?= 0 -ifeq ($(APP_PASSPORT), 1) -CFLAGS += -DAPP_PASSPORT -SRV_GUI = 1 -endif - - -APP_LF_RFID ?= 0 -ifeq ($(APP_LF_RFID), 1) -CFLAGS += -DAPP_LF_RFID -SRV_GUI = 1 -endif - - -APP_NFC ?= 0 -ifeq ($(APP_NFC), 1) -CFLAGS += -DAPP_NFC -SRV_GUI = 1 -endif - - -APP_INFRARED ?= 0 -ifeq ($(APP_INFRARED), 1) -CFLAGS += -DAPP_INFRARED -SRV_GUI = 1 -endif - - -APP_VIBRO_TEST ?= 0 -ifeq ($(APP_VIBRO_TEST), 1) -CFLAGS += -DAPP_VIBRO_TEST -SRV_GUI = 1 -endif - - -APP_USB_TEST ?= 0 -ifeq ($(APP_USB_TEST), 1) -CFLAGS += -DAPP_USB_TEST -SRV_GUI = 1 -endif - -APP_UART_ECHO ?= 0 -ifeq ($(APP_UART_ECHO), 1) -CFLAGS += -DAPP_UART_ECHO -SRV_GUI = 1 -endif - -APP_DISPLAY_TEST ?= 0 -ifeq ($(APP_DISPLAY_TEST), 1) -CFLAGS += -DAPP_DISPLAY_TEST -SRV_GUI = 1 -endif - -APP_TEXT_BOX_TEST ?= 0 -ifeq ($(APP_TEXT_BOX_TEST), 1) -CFLAGS += -DAPP_TEXT_BOX_TEST -SRV_GUI = 1 -endif - -APP_BATTERY_TEST ?= 0 -ifeq ($(APP_BATTERY_TEST), 1) -CFLAGS += -DAPP_BATTERY_TEST -SRV_GUI = 1 -endif - -APP_USB_MOUSE ?= 0 -ifeq ($(APP_USB_MOUSE), 1) -CFLAGS += -DAPP_USB_MOUSE -SRV_GUI = 1 -endif - -APP_BAD_USB ?= 0 -ifeq ($(APP_BAD_USB), 1) -CFLAGS += -DAPP_BAD_USB -SRV_GUI = 1 -endif - -APP_U2F ?= 0 -ifeq ($(APP_U2F), 1) -CFLAGS += -DAPP_U2F -SRV_GUI = 1 -endif - -APP_BLE_HID ?=0 -ifeq ($(APP_BLE_HID), 1) -CFLAGS += -DAPP_BLE_HID -SRV_GUI = 1 -endif - -APP_KEYPAD_TEST ?= 0 -ifeq ($(APP_KEYPAD_TEST), 1) -CFLAGS += -DAPP_KEYPAD_TEST -SRV_GUI = 1 -endif - -APP_FILE_BROWSER_TEST ?= 0 -ifeq ($(APP_FILE_BROWSER_TEST), 1) -CFLAGS += -DAPP_FILE_BROWSER_TEST -SRV_GUI = 1 -endif - -APP_ACCESSOR ?= 0 -ifeq ($(APP_ACCESSOR), 1) -CFLAGS += -DAPP_ACCESSOR -SRV_GUI = 1 -endif - - -APP_GPIO ?= 0 -ifeq ($(APP_GPIO), 1) -CFLAGS += -DAPP_GPIO -SRV_GUI = 1 -endif - - -APP_MUSIC_PLAYER ?= 0 -ifeq ($(APP_MUSIC_PLAYER), 1) -CFLAGS += -DAPP_MUSIC_PLAYER -SRV_GUI = 1 -endif - -APP_SNAKE_GAME ?= 0 -ifeq ($(APP_SNAKE_GAME), 1) -CFLAGS += -DAPP_SNAKE_GAME -SRV_GUI = 1 -endif - -APP_IBUTTON ?= 0 -ifeq ($(APP_IBUTTON), 1) -CFLAGS += -DAPP_IBUTTON -SRV_GUI = 1 -endif - -APP_UPDATER ?= 0 -ifeq ($(APP_UPDATER), 1) -CFLAGS += -DAPP_UPDATER -SRV_GUI = 1 -SRV_STORAGE = 1 -SRV_NOTIFICATION = 1 -SRV_INPUT = 1 -endif - -# Services -# that will start with OS -# Prefix with SRV_* - - -SRV_BT ?= 0 -ifeq ($(SRV_BT), 1) -CFLAGS += -DSRV_BT -SRV_CLI = 1 -endif - - -SRV_DESKTOP ?= 0 -ifeq ($(SRV_DESKTOP), 1) -CFLAGS += -DSRV_DESKTOP -SRV_DOLPHIN = 1 -SRV_STORAGE = 1 -SRV_GUI = 1 -endif - - -SRV_UPDATER ?= 0 -ifeq ($(SRV_UPDATER), 1) -CFLAGS += -DSRV_UPDATER -SRV_STORAGE = 1 -SRV_GUI = 1 -endif - - -SRV_DOLPHIN ?= 0 -ifeq ($(SRV_DOLPHIN), 1) -CFLAGS += -DSRV_DOLPHIN -SRV_DOLPHIN_STATE_DEBUG ?= 0 -ifeq ($(SRV_DOLPHIN_STATE_DEBUG), 1) -CFLAGS += -DSRV_DOLPHIN_STATE_DEBUG -endif -endif - - -SRV_POWER ?= 0 -ifeq ($(SRV_POWER), 1) -CFLAGS += -DSRV_POWER -SRV_GUI = 1 -SRV_CLI = 1 -endif - -SRV_RPC ?= 0 -ifeq ($(SRV_RPC), 1) -CFLAGS += -DSRV_RPC -ifeq ($(SRV_RPC_DEBUG), 1) -CFLAGS += -DSRV_RPC_DEBUG -endif -SRV_CLI = 1 -endif - -SRV_LOADER ?= 0 -ifeq ($(SRV_LOADER), 1) -CFLAGS += -DSRV_LOADER -SRV_GUI = 1 -# Loader autostart hook -LOADER_AUTOSTART ?= "" -ifneq ($(strip $(LOADER_AUTOSTART)), "") -CFLAGS += -DLOADER_AUTOSTART="\"$(LOADER_AUTOSTART)\"" -endif -# Loader autostart hook END -endif - - -SRV_DIALOGS ?= 0 -ifeq ($(SRV_DIALOGS), 1) -CFLAGS += -DSRV_DIALOGS -SRV_GUI = 1 -endif - - -SRV_GUI ?= 0 -ifeq ($(SRV_GUI), 1) -CFLAGS += -DSRV_GUI -SRV_INPUT = 1 -SRV_NOTIFICATION = 1 -endif - - -SRV_INPUT ?= 0 -ifeq ($(SRV_INPUT), 1) -CFLAGS += -DSRV_INPUT -endif - - -SRV_CLI ?= 0 -ifeq ($(SRV_CLI), 1) -CFLAGS += -DSRV_CLI -endif - - -SRV_NOTIFICATION ?= 0 -ifeq ($(SRV_NOTIFICATION), 1) -CFLAGS += -DSRV_NOTIFICATION -endif - - -SRV_STORAGE ?= 0 -ifeq ($(SRV_STORAGE), 1) -CFLAGS += -DSRV_STORAGE -endif diff --git a/applications/archive/application.fam b/applications/archive/application.fam new file mode 100644 index 00000000..f0a980ab --- /dev/null +++ b/applications/archive/application.fam @@ -0,0 +1,11 @@ +App( + appid="archive", + name="Archive", + apptype=FlipperAppType.ARCHIVE, + entry_point="archive_app", + cdefines=["APP_ARCHIVE"], + requires=["gui"], + stack_size=4 * 1024, + icon="A_FileManager_14", + order=0, +) diff --git a/applications/bad_usb/application.fam b/applications/bad_usb/application.fam new file mode 100644 index 00000000..4da34f0d --- /dev/null +++ b/applications/bad_usb/application.fam @@ -0,0 +1,14 @@ +App( + appid="bad_usb", + name="Bad USB", + apptype=FlipperAppType.APP, + entry_point="bad_usb_app", + cdefines=["APP_BAD_USB"], + requires=[ + "gui", + "dialogs", + ], + stack_size=2 * 1024, + icon="A_BadUsb_14", + order=70, +) diff --git a/applications/bt/application.fam b/applications/bt/application.fam new file mode 100644 index 00000000..248386ff --- /dev/null +++ b/applications/bt/application.fam @@ -0,0 +1,66 @@ +App( + appid="bt", + name="BtSrv", + apptype=FlipperAppType.SERVICE, + entry_point="bt_srv", + cdefines=["SRV_BT"], + requires=[ + "cli", + "dialogs", + ], + provides=[ + "bt_start", + "bt_settings", + "bt_debug", + ], + stack_size=1 * 1024, + order=20, +) + +App( + appid="bt_start", + apptype=FlipperAppType.STARTUP, + entry_point="bt_on_system_start", + order=70, +) + +App( + appid="bt_settings", + name="Bluetooth", + apptype=FlipperAppType.SETTINGS, + entry_point="bt_settings_app", + stack_size=1 * 1024, + requires=[ + "bt", + "gui", + ], + order=10, +) + +App( + appid="bt_debug", + name="Bluetooth Debug", + apptype=FlipperAppType.DEBUG, + entry_point="bt_debug_app", + stack_size=1 * 1024, + requires=[ + "bt", + "gui", + "dialogs", + ], + order=110, +) + +App( + appid="bt_hid", + name="Bluetooth Remote", + apptype=FlipperAppType.PLUGIN, + entry_point="bt_hid_app", + stack_size=1 * 1024, + cdefines=["APP_BLE_HID"], + requires=[ + "bt", + "gui", + ], + order=10, +) diff --git a/applications/cli/application.fam b/applications/cli/application.fam new file mode 100644 index 00000000..73c70aa4 --- /dev/null +++ b/applications/cli/application.fam @@ -0,0 +1,9 @@ +App( + appid="cli", + name="CliSrv", + apptype=FlipperAppType.SERVICE, + entry_point="cli_srv", + cdefines=["SRV_CLI"], + stack_size=4 * 1024, + order=30, +) diff --git a/applications/crypto/application.fam b/applications/crypto/application.fam new file mode 100644 index 00000000..7771c5ed --- /dev/null +++ b/applications/crypto/application.fam @@ -0,0 +1,6 @@ +App( + appid="crypto_start", + apptype=FlipperAppType.STARTUP, + entry_point="crypto_on_system_start", + order=10, +) diff --git a/applications/debug_tools/application.fam b/applications/debug_tools/application.fam new file mode 100644 index 00000000..8cb495b0 --- /dev/null +++ b/applications/debug_tools/application.fam @@ -0,0 +1,115 @@ +App( + appid="debug_apps", + name="Basic debug apps bundle", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "blink_test", + "vibro_test", + "keypad_test", + "usb_test", + "usb_mouse", + "uart_echo", + "display_test", + "text_box_test", + "file_browser_test", + ], +) + +App( + appid="blink_test", + name="Blink Test", + apptype=FlipperAppType.DEBUG, + entry_point="blink_test_app", + cdefines=["APP_BLINK"], + requires=["gui"], + stack_size=1 * 1024, + order=10, +) + +App( + appid="vibro_test", + name="Vibro Test", + apptype=FlipperAppType.DEBUG, + entry_point="vibro_test_app", + cdefines=["APP_VIBRO_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=20, +) + +App( + appid="keypad_test", + name="Keypad Test", + apptype=FlipperAppType.DEBUG, + entry_point="keypad_test_app", + cdefines=["APP_KEYPAD_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=30, +) + +App( + appid="usb_test", + name="USB Test", + apptype=FlipperAppType.DEBUG, + entry_point="usb_test_app", + cdefines=["APP_USB_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=50, +) + +App( + appid="usb_mouse", + name="USB Mouse Demo", + apptype=FlipperAppType.DEBUG, + entry_point="usb_mouse_app", + cdefines=["APP_USB_MOUSE"], + requires=["gui"], + stack_size=1 * 1024, + order=60, +) + +App( + appid="uart_echo", + name="UART Echo", + apptype=FlipperAppType.DEBUG, + entry_point="uart_echo_app", + cdefines=["APP_UART_ECHO"], + requires=["gui"], + stack_size=2 * 1024, + order=70, +) + +App( + appid="display_test", + name="Display Test", + apptype=FlipperAppType.DEBUG, + entry_point="display_test_app", + cdefines=["APP_DISPLAY_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=120, +) + +App( + appid="text_box_test", + name="Text Box Test", + apptype=FlipperAppType.DEBUG, + entry_point="text_box_test_app", + cdefines=["APP_TEXT_BOX_TEST"], + requires=["gui"], + stack_size=1 * 1024, + order=140, +) + +App( + appid="file_browser_test", + name="File Browser Test", + apptype=FlipperAppType.DEBUG, + entry_point="file_browser_app", + cdefines=["APP_FILE_BROWSER_TEST"], + requires=["gui"], + stack_size=2 * 1024, + order=150, +) diff --git a/applications/desktop/application.fam b/applications/desktop/application.fam new file mode 100644 index 00000000..5f3dcdfd --- /dev/null +++ b/applications/desktop/application.fam @@ -0,0 +1,30 @@ +App( + appid="desktop", + name="DesktopSrv", + apptype=FlipperAppType.SERVICE, + entry_point="desktop_srv", + cdefines=["SRV_DESKTOP"], + requires=[ + "gui", + "dolphin", + "storage", + "input", + ], + provides=["desktop_settings"], + conflicts=["updater"], + stack_size=2 * 1024, + order=60, +) + +App( + appid="desktop_settings", + name="Desktop", + apptype=FlipperAppType.SETTINGS, + entry_point="desktop_settings_app", + requires=[ + "desktop", + "gui", + ], + stack_size=1 * 1024, + order=50, +) diff --git a/applications/desktop/views/desktop_view_debug.c b/applications/desktop/views/desktop_view_debug.c index 6ac62b49..3a6c87f1 100644 --- a/applications/desktop/views/desktop_view_debug.c +++ b/applications/desktop/views/desktop_view_debug.c @@ -46,7 +46,10 @@ void desktop_debug_render(Canvas* canvas, void* model) { canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); ver = furi_hal_version_get_firmware_version(); - + const BleGlueC2Info* c2_ver = NULL; +#ifdef SRV_BT + c2_ver = ble_glue_get_c2_info(); +#endif if(!ver) { canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, "No info"); return; @@ -63,10 +66,11 @@ void desktop_debug_render(Canvas* canvas, void* model) { snprintf( buffer, sizeof(buffer), - "%s%s [%s]", + "%s%s [%s] %s", version_get_dirty_flag(ver) ? "[!] " : "", version_get_githash(ver), - version_get_gitbranchnum(ver)); + version_get_gitbranchnum(ver), + c2_ver ? c2_ver->StackTypeString : ""); canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer); snprintf( diff --git a/applications/dialogs/application.fam b/applications/dialogs/application.fam new file mode 100644 index 00000000..0a18c79a --- /dev/null +++ b/applications/dialogs/application.fam @@ -0,0 +1,10 @@ +App( + appid="dialogs", + name="DialogsSrv", + apptype=FlipperAppType.SERVICE, + entry_point="dialogs_srv", + cdefines=["SRV_DIALOGS"], + requires=["gui"], + stack_size=1 * 1024, + order=40, +) diff --git a/applications/dolphin/application.fam b/applications/dolphin/application.fam new file mode 100644 index 00000000..1ee0e3cf --- /dev/null +++ b/applications/dolphin/application.fam @@ -0,0 +1,23 @@ +App( + appid="dolphin", + name="DolphinSrv", + apptype=FlipperAppType.SERVICE, + entry_point="dolphin_srv", + cdefines=["SRV_DOLPHIN"], + stack_size=1 * 1024, + order=50, +) + +App( + appid="passport", + name="Passport", + apptype=FlipperAppType.SETTINGS, + entry_point="passport_app", + cdefines=["APP_PASSPORT"], + requires=[ + "gui", + "dolphin", + ], + stack_size=1 * 1024, + order=60, +) diff --git a/applications/extapps.scons b/applications/extapps.scons new file mode 100644 index 00000000..7b1cae7d --- /dev/null +++ b/applications/extapps.scons @@ -0,0 +1,57 @@ +Import("ENV") + + +from fbt.appmanifest import FlipperAppType + + +appenv = ENV.Clone(tools=["fbt_extapps"]) + +appenv.Replace( + LINKER_SCRIPT="application-ext", + STRIPFLAGS=[ + "--strip-debug", + "--strip-unneeded", + "-d", + "-g", + "-S", + ], +) + +appenv.AppendUnique( + CCFLAGS=[ + "-Os", + "-ggdb3", + "-mword-relocations", + "-mlong-calls", + "-fno-common", + "-nostdlib", + "-fvisibility=hidden", + ], + LINKFLAGS=[ + "-r", + "-s", + # "-Bsymbolic", + "-nostartfiles", + "-mlong-calls", + "-fno-common", + "-nostdlib", + "-Wl,--gc-sections", + "-Wl,--no-export-dynamic", + "-fvisibility=hidden", + "-Wl,-e${APP_ENTRY}", + ], +) + + +extapps = [] +for apptype in (FlipperAppType.PLUGIN, FlipperAppType.EXTERNAL): + for app in appenv["APPBUILD"].get_apps_of_type(apptype): + extapps.append(appenv.BuildAppElf(app)) + +# Ugly access to global option +if extra_app_list := GetOption("extra_ext_apps"): + for extra_app in extra_app_list.split(","): + extapps.append(appenv.BuildAppElf(appenv["APPMGR"].get(extra_app))) + +Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) +Return("extapps") diff --git a/applications/gpio/application.fam b/applications/gpio/application.fam new file mode 100644 index 00000000..64f8db5b --- /dev/null +++ b/applications/gpio/application.fam @@ -0,0 +1,11 @@ +App( + appid="gpio", + name="GPIO", + apptype=FlipperAppType.APP, + entry_point="gpio_app", + cdefines=["APP_GPIO"], + requires=["gui"], + stack_size=1 * 1024, + icon="A_GPIO_14", + order=50, +) diff --git a/applications/gui/application.fam b/applications/gui/application.fam new file mode 100644 index 00000000..0116f5b8 --- /dev/null +++ b/applications/gui/application.fam @@ -0,0 +1,13 @@ +App( + appid="gui", + name="GuiSrv", + apptype=FlipperAppType.SERVICE, + entry_point="gui_srv", + cdefines=["SRV_GUI"], + requires=[ + "input", + "notification", + ], + stack_size=2 * 1024, + order=70, +) diff --git a/applications/ibutton/application.fam b/applications/ibutton/application.fam new file mode 100644 index 00000000..0bc6f8a9 --- /dev/null +++ b/applications/ibutton/application.fam @@ -0,0 +1,23 @@ +App( + appid="ibutton", + name="iButton", + apptype=FlipperAppType.APP, + entry_point="ibutton_app", + cdefines=["APP_IBUTTON"], + requires=[ + "gui", + "dialogs", + ], + provides=["ibutton_start"], + icon="A_iButton_14", + stack_size=2 * 1024, + order=60, +) + +App( + appid="ibutton_start", + apptype=FlipperAppType.STARTUP, + entry_point="ibutton_on_system_start", + requires=["ibutton"], + order=60, +) diff --git a/applications/infrared/application.fam b/applications/infrared/application.fam new file mode 100644 index 00000000..6f76ed42 --- /dev/null +++ b/applications/infrared/application.fam @@ -0,0 +1,23 @@ +App( + appid="infrared", + name="Infrared", + apptype=FlipperAppType.APP, + entry_point="infrared_app", + cdefines=["APP_INFRARED"], + requires=[ + "gui", + "dialogs", + ], + provides=["infrared_start"], + icon="A_Infrared_14", + stack_size=3 * 1024, + order=40, +) + +App( + appid="infrared_start", + apptype=FlipperAppType.STARTUP, + entry_point="infrared_on_system_start", + requires=["infrared"], + order=20, +) diff --git a/applications/input/application.fam b/applications/input/application.fam new file mode 100644 index 00000000..545630e6 --- /dev/null +++ b/applications/input/application.fam @@ -0,0 +1,9 @@ +App( + appid="input", + name="InputSrv", + apptype=FlipperAppType.SERVICE, + entry_point="input_srv", + cdefines=["SRV_INPUT"], + stack_size=1 * 1024, + order=80, +) diff --git a/applications/lfrfid/application.fam b/applications/lfrfid/application.fam new file mode 100644 index 00000000..8722bb4f --- /dev/null +++ b/applications/lfrfid/application.fam @@ -0,0 +1,26 @@ +App( + appid="lfrfid", + name="125 kHz RFID", + apptype=FlipperAppType.APP, + entry_point="lfrfid_app", + cdefines=["APP_LF_RFID"], + requires=[ + "gui", + "dialogs", + ], + provides=[ + "lfrfid_start", + "lfrfid_debug", + ], + icon="A_125khz_14", + stack_size=2 * 1024, + order=20, +) + +App( + appid="lfrfid_start", + apptype=FlipperAppType.STARTUP, + entry_point="lfrfid_on_system_start", + requires=["lfrfid"], + order=50, +) diff --git a/applications/lfrfid_debug/application.fam b/applications/lfrfid_debug/application.fam new file mode 100644 index 00000000..910f65cf --- /dev/null +++ b/applications/lfrfid_debug/application.fam @@ -0,0 +1,12 @@ +App( + appid="lfrfid_debug", + name="LF-RFID Debug", + apptype=FlipperAppType.DEBUG, + entry_point="lfrfid_debug_app", + requires=[ + "gui", + "lfrfid", + ], + stack_size=1 * 1024, + order=100, +) diff --git a/applications/loader/application.fam b/applications/loader/application.fam new file mode 100644 index 00000000..16351f8d --- /dev/null +++ b/applications/loader/application.fam @@ -0,0 +1,10 @@ +App( + appid="loader", + name="LoaderSrv", + apptype=FlipperAppType.SERVICE, + entry_point="loader_srv", + cdefines=["SRV_LOADER"], + requires=["gui"], + stack_size=1 * 1024, + order=90, +) diff --git a/applications/meta/application.fam b/applications/meta/application.fam new file mode 100644 index 00000000..a447b94a --- /dev/null +++ b/applications/meta/application.fam @@ -0,0 +1,41 @@ +App( + appid="basic_services", + name="Basic services", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "rpc", + "bt", + "desktop", + "loader", + "power", + ], +) + + +App( + appid="basic_apps", + name="Basic applications for main menu", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "gpio", + "ibutton", + "infrared", + "lfrfid", + "nfc", + "subghz", + "bad_usb", + "u2f", + ], +) + + +App( + appid="basic_plugins", + name="Basic applications for plug-in menu", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "music_player", + "snake_game", + "bt_hid", + ], +) diff --git a/applications/music_player/application.fam b/applications/music_player/application.fam new file mode 100644 index 00000000..70e29743 --- /dev/null +++ b/applications/music_player/application.fam @@ -0,0 +1,22 @@ +App( + appid="music_player", + name="Music Player", + apptype=FlipperAppType.PLUGIN, + entry_point="music_player_app", + cdefines=["APP_MUSIC_PLAYER"], + requires=[ + "gui", + "dialogs", + ], + provides=["music_player_start"], + stack_size=2 * 1024, + order=20, +) + +App( + appid="music_player_start", + apptype=FlipperAppType.STARTUP, + entry_point="music_player_on_system_start", + requires=["music_player"], + order=30, +) diff --git a/applications/nfc/application.fam b/applications/nfc/application.fam new file mode 100644 index 00000000..f43ed314 --- /dev/null +++ b/applications/nfc/application.fam @@ -0,0 +1,23 @@ +App( + appid="nfc", + name="NFC", + apptype=FlipperAppType.APP, + entry_point="nfc_app", + cdefines=["APP_NFC"], + requires=[ + "gui", + "dialogs", + ], + provides=["nfc_start"], + icon="A_NFC_14", + stack_size=4 * 1024, + order=30, +) + +App( + appid="nfc_start", + apptype=FlipperAppType.STARTUP, + entry_point="nfc_on_system_start", + requires=["nfc"], + order=30, +) diff --git a/applications/notification/application.fam b/applications/notification/application.fam new file mode 100644 index 00000000..be730d51 --- /dev/null +++ b/applications/notification/application.fam @@ -0,0 +1,21 @@ +App( + appid="notification", + name="NotificationSrv", + apptype=FlipperAppType.SERVICE, + entry_point="notification_srv", + cdefines=["SRV_NOTIFICATION"], + requires=["input"], + provides=["notification_settings"], + stack_size=int(1.5 * 1024), + order=100, +) + +App( + appid="notification_settings", + name="LCD and Notifications", + apptype=FlipperAppType.SETTINGS, + entry_point="notification_settings_app", + requires=["notification"], + stack_size=1 * 1024, + order=20, +) diff --git a/applications/power/application.fam b/applications/power/application.fam new file mode 100644 index 00000000..1e503749 --- /dev/null +++ b/applications/power/application.fam @@ -0,0 +1,53 @@ +App( + appid="power", + name="PowerSrv", + apptype=FlipperAppType.SERVICE, + entry_point="power_srv", + cdefines=["SRV_POWER"], + requires=[ + "gui", + "cli", + ], + provides=[ + "power_settings", + "power_start", + ], + stack_size=1 * 1024, + order=110, +) + +App( + appid="power_settings", + name="Power", + apptype=FlipperAppType.SETTINGS, + entry_point="power_settings_app", + requires=[ + "gui", + "power", + ], + flags=["InsomniaSafe"], + stack_size=1 * 1024, + order=40, +) + +App( + appid="power_start", + apptype=FlipperAppType.STARTUP, + entry_point="power_on_system_start", + requires=["power"], + order=80, +) + +App( + appid="battery_test", + name="Battery Test", + apptype=FlipperAppType.DEBUG, + entry_point="battery_test_app", + cdefines=["APP_BATTERY_TEST"], + requires=[ + "gui", + "power", + ], + stack_size=1 * 1024, + order=130, +) diff --git a/applications/rpc/application.fam b/applications/rpc/application.fam new file mode 100644 index 00000000..683396e3 --- /dev/null +++ b/applications/rpc/application.fam @@ -0,0 +1,12 @@ +App( + appid="rpc", + name="RpcSrv", + apptype=FlipperAppType.SERVICE, + entry_point="rpc_srv", + cdefines=["SRV_RPC"], + requires=[ + "cli", + ], + stack_size=4 * 1024, + order=10, +) diff --git a/applications/rpc/rpc_storage.c b/applications/rpc/rpc_storage.c index 624d7c7b..336346b5 100644 --- a/applications/rpc/rpc_storage.c +++ b/applications/rpc/rpc_storage.c @@ -10,6 +10,7 @@ #include "storage/storage.h" #include #include +#include #include #define TAG "RpcStorage" @@ -100,35 +101,6 @@ static PB_CommandStatus rpc_system_storage_get_file_error(File* file) { return rpc_system_storage_get_error(storage_file_get_error(file)); } -static bool rpc_system_storage_is_filename_correct(const char* path) { - const char* name_pos = strrchr(path, '/'); - if(name_pos == NULL) { - name_pos = path; - } else { - name_pos++; - } - - while(*name_pos != '\0') { - if((*name_pos >= '0') && (*name_pos <= '9')) { - name_pos++; - continue; - } else if((*name_pos >= 'A') && (*name_pos <= 'Z')) { - name_pos++; - continue; - } else if((*name_pos >= 'a') && (*name_pos <= 'z')) { - name_pos++; - continue; - } else if(strchr(".!#\\$%&'()-@^_`{}~", *name_pos) != NULL) { - name_pos++; - continue; - } - - return false; - } - - return true; -} - static void rpc_system_storage_info_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(context); @@ -274,7 +246,7 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex FileInfo fileinfo; char* name = malloc(MAX_NAME_LENGTH + 1); if(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) { - if(rpc_system_storage_is_filename_correct(name)) { + if(path_contains_only_ascii(name)) { if(i == COUNT_OF(list->file)) { list->file_count = i; response.has_next = true; @@ -379,7 +351,7 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte bool result = true; - if(!rpc_system_storage_is_filename_correct(request->content.storage_write_request.path)) { + if(!path_contains_only_ascii(request->content.storage_write_request.path)) { rpc_storage->current_command_id = request->command_id; rpc_send_and_release_empty( session, rpc_storage->current_command_id, PB_CommandStatus_ERROR_STORAGE_INVALID_NAME); @@ -433,7 +405,7 @@ static bool rpc_system_storage_is_dir_is_empty(Storage* fs_api, const char* path if(storage_dir_open(dir, path)) { char* name = malloc(MAX_NAME_LENGTH); while(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) { - if(rpc_system_storage_is_filename_correct(name)) { + if(path_contains_only_ascii(name)) { is_dir_is_empty = false; break; } @@ -505,7 +477,7 @@ static void rpc_system_storage_mkdir_process(const PB_Main* request, void* conte Storage* fs_api = furi_record_open("storage"); char* path = request->content.storage_mkdir_request.path; if(path) { - if(rpc_system_storage_is_filename_correct(path)) { + if(path_contains_only_ascii(path)) { FS_Error error = storage_common_mkdir(fs_api, path); status = rpc_system_storage_get_error(error); } else { @@ -602,7 +574,7 @@ static void rpc_system_storage_rename_process(const PB_Main* request, void* cont Storage* fs_api = furi_record_open("storage"); - if(rpc_system_storage_is_filename_correct(request->content.storage_rename_request.new_path)) { + if(path_contains_only_ascii(request->content.storage_rename_request.new_path)) { FS_Error error = storage_common_rename( fs_api, request->content.storage_rename_request.old_path, diff --git a/applications/snake_game/application.fam b/applications/snake_game/application.fam new file mode 100644 index 00000000..5d6ad527 --- /dev/null +++ b/applications/snake_game/application.fam @@ -0,0 +1,11 @@ +App( + appid="snake_game", + name="Snake Game", + apptype=FlipperAppType.PLUGIN, + entry_point="snake_game_app", + cdefines=["APP_SNAKE_GAME"], + requires=["gui"], + stack_size=1 * 1024, + icon="A_Plugins_14", + order=30, +) diff --git a/applications/storage/application.fam b/applications/storage/application.fam new file mode 100644 index 00000000..21089635 --- /dev/null +++ b/applications/storage/application.fam @@ -0,0 +1,19 @@ +App( + appid="storage", + name="StorageSrv", + apptype=FlipperAppType.SERVICE, + entry_point="storage_srv", + cdefines=["SRV_STORAGE"], + requires=["storage_settings"], + provides=["storage_start"], + stack_size=3 * 1024, + order=120, +) + +App( + appid="storage_start", + apptype=FlipperAppType.STARTUP, + entry_point="storage_on_system_start", + requires=["storage"], + order=90, +) diff --git a/applications/storage_settings/application.fam b/applications/storage_settings/application.fam new file mode 100644 index 00000000..1ba0ccd4 --- /dev/null +++ b/applications/storage_settings/application.fam @@ -0,0 +1,9 @@ +App( + appid="storage_settings", + name="Storage", + apptype=FlipperAppType.SETTINGS, + entry_point="storage_settings_app", + requires=["storage"], + stack_size=2 * 1024, + order=30, +) diff --git a/applications/subghz/application.fam b/applications/subghz/application.fam new file mode 100644 index 00000000..7d31ecae --- /dev/null +++ b/applications/subghz/application.fam @@ -0,0 +1,24 @@ +App( + appid="subghz", + name="Sub-GHz", + apptype=FlipperAppType.APP, + entry_point="subghz_app", + cdefines=["APP_SUBGHZ"], + requires=[ + "gui", + "cli", + "dialogs", + ], + provides=["subghz_start"], + icon="A_Sub1ghz_14", + stack_size=2 * 1024, + order=10, +) + +App( + appid="subghz_start", + apptype=FlipperAppType.STARTUP, + entry_point="subghz_on_system_start", + requires=["subghz"], + order=40, +) diff --git a/applications/subghz/scenes/subghz_scene_save_success.c b/applications/subghz/scenes/subghz_scene_save_success.c index 53cd93ce..3d5c16ca 100644 --- a/applications/subghz/scenes/subghz_scene_save_success.c +++ b/applications/subghz/scenes/subghz_scene_save_success.c @@ -1,6 +1,6 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -#include "dolphin/helpers/dolphin_deed.h" +#include #include void subghz_scene_save_success_popup_callback(void* context) { diff --git a/applications/system/application.fam b/applications/system/application.fam new file mode 100644 index 00000000..0fc456b2 --- /dev/null +++ b/applications/system/application.fam @@ -0,0 +1,9 @@ +App( + appid="system_settings", + name="System", + apptype=FlipperAppType.SETTINGS, + entry_point="system_settings_app", + requires=["gui"], + stack_size=1 * 1024, + order=70, +) diff --git a/applications/u2f/application.fam b/applications/u2f/application.fam new file mode 100644 index 00000000..6b32e022 --- /dev/null +++ b/applications/u2f/application.fam @@ -0,0 +1,14 @@ +App( + appid="u2f", + name="U2F", + apptype=FlipperAppType.APP, + entry_point="u2f_app", + cdefines=["APP_U2F"], + requires=[ + "gui", + "dialogs", + ], + stack_size=2 * 1024, + icon="A_U2F_14", + order=80, +) diff --git a/applications/unit_tests/application.fam b/applications/unit_tests/application.fam new file mode 100644 index 00000000..54e6feae --- /dev/null +++ b/applications/unit_tests/application.fam @@ -0,0 +1,18 @@ +App( + appid="unit_tests", + apptype=FlipperAppType.STARTUP, + entry_point="unit_tests_on_system_start", + cdefines=["APP_UNIT_TESTS"], + provides=["delay_test"], + order=100, +) + +App( + appid="delay_test", + name="Delay Test", + apptype=FlipperAppType.DEBUG, + entry_point="delay_test_app", + stack_size=1 * 1024, + requires=["unit_tests"], + order=110, +) diff --git a/applications/unit_tests/rpc/rpc_test.c b/applications/unit_tests/rpc/rpc_test.c index 2f97343e..ca894cb4 100644 --- a/applications/unit_tests/rpc/rpc_test.c +++ b/applications/unit_tests/rpc/rpc_test.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -495,7 +496,7 @@ static void test_rpc_compare_messages(PB_Main* result, PB_Main* expected) { case PB_Main_storage_list_response_tag: { size_t expected_msg_files = expected->content.storage_list_response.file_count; size_t result_msg_files = result->content.storage_list_response.file_count; - mu_check(result_msg_files == expected_msg_files); + mu_assert_int_eq(expected_msg_files, result_msg_files); for(size_t i = 0; i < expected_msg_files; ++i) { PB_Storage_File* result_msg_file = &result->content.storage_list_response.file[i]; PB_Storage_File* expected_msg_file = &expected->content.storage_list_response.file[i]; @@ -603,13 +604,17 @@ static void test_rpc_storage_list_create_expected_list( MsgList_push_back(msg_list, response); i = 0; } - list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? PB_Storage_File_FileType_DIR : - PB_Storage_File_FileType_FILE; - list->file[i].size = fileinfo.size; - list->file[i].data = NULL; - /* memory free inside rpc_encode_and_send() -> pb_release() */ - list->file[i].name = name; - ++i; + + if(path_contains_only_ascii(name)) { + list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? + PB_Storage_File_FileType_DIR : + PB_Storage_File_FileType_FILE; + list->file[i].size = fileinfo.size; + list->file[i].data = NULL; + /* memory free inside rpc_encode_and_send() -> pb_release() */ + list->file[i].name = name; + ++i; + } } else { finish = true; free(name); diff --git a/applications/unit_tests/test_index.c b/applications/unit_tests/test_index.c index a1acbed4..d8a8174c 100644 --- a/applications/unit_tests/test_index.c +++ b/applications/unit_tests/test_index.c @@ -32,7 +32,7 @@ void minunit_print_progress(void) { } void minunit_print_fail(const char* str) { - printf(FURI_LOG_CLR_E "%s\n" FURI_LOG_CLR_RESET, str); + printf(FURI_LOG_CLR_E "%s\r\n" FURI_LOG_CLR_RESET, str); } void unit_tests_cli(Cli* cli, string_t args, void* context) { diff --git a/applications/updater/application.fam b/applications/updater/application.fam new file mode 100644 index 00000000..a693fa6f --- /dev/null +++ b/applications/updater/application.fam @@ -0,0 +1,39 @@ +App( + appid="updater", + name="UpdaterSrv", + apptype=FlipperAppType.SERVICE, + cdefines=["SRV_UPDATER"], + requires=[ + "gui", + "storage", + ], + conflicts=["desktop"], + entry_point="updater_srv", + stack_size=2 * 1024, + order=130, +) + +App( + appid="updater_app", + name="UpdaterApp", + apptype=FlipperAppType.SYSTEM, + cdefines=["APP_UPDATER"], + requires=[ + "gui", + "storage", + "bt", + ], + conflicts=["updater"], + provides=["updater_start"], + entry_point="updater_srv", + stack_size=2 * 1024, + order=10, +) + +App( + appid="updater_start", + apptype=FlipperAppType.STARTUP, + entry_point="updater_on_system_start", + requires=["updater_app"], + order=110, +) diff --git a/assets/Makefile b/assets/Makefile deleted file mode 100644 index 2c743601..00000000 --- a/assets/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -PROJECT_ROOT = $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..) - -include $(PROJECT_ROOT)/assets/assets.mk -include $(PROJECT_ROOT)/assets/copro.mk - -.PHONY: all -all: icons protobuf dolphin manifest - -$(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILER) - @echo "\tASSETS\t\t" $@ - @$(ASSETS_COMPILER) icons "$(ASSETS_SOURCE_DIR)" "$(ASSETS_COMPILED_DIR)" - -.PHONY: icons -icons: $(ASSETS) - -$(PROTOBUF) &: $(PROTOBUF_SOURCES) $(PROTOBUF_COMPILER) - @echo "\tPROTOBUF\t" $(PROTOBUF_FILENAMES) - @$(PROTOBUF_COMPILER) -q -I$(PROTOBUF_SOURCE_DIR) -D$(PROTOBUF_COMPILED_DIR) $(PROTOBUF_SOURCES) - @printf "#pragma once\n#define PROTOBUF_MAJOR_VERSION $(PROTOBUF_MAJOR_VERSION)\n#define PROTOBUF_MINOR_VERSION $(PROTOBUF_MINOR_VERSION)\n" > $(PROTOBUF_COMPILED_DIR)/protobuf_version.h - -.PHONY: protobuf -protobuf: $(PROTOBUF) - -$(DOLPHIN_EXTERNAL_OUTPUT_DIR): $(DOLPHIN_SOURCE_DIR) - @echo "\tDOLPHIN blocking" - @$(ASSETS_COMPILER) dolphin -s dolphin_blocking "$(DOLPHIN_SOURCE_DIR)/blocking" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)" - @echo "\tDOLPHIN internal" - @$(ASSETS_COMPILER) dolphin -s dolphin_internal "$(DOLPHIN_SOURCE_DIR)/internal" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)" - @echo "\tDOLPHIN external" - @$(ASSETS_COMPILER) dolphin "$(DOLPHIN_SOURCE_DIR)/external" "$(DOLPHIN_EXTERNAL_OUTPUT_DIR)" - -.PHONY: manifest -manifest: - $(ASSETS_COMPILER) manifest $(RESOURCES_DIR) - -.PHONY: dolphin -dolphin: $(DOLPHIN_EXTERNAL_OUTPUT_DIR) - -.PHONY: copro_bundle -copro_bundle: - @mkdir -p $(COPRO_BUNDLE_DIR) - @$(ASSETS_COMPILER) copro $(COPRO_CUBE_DIR) $(COPRO_BUNDLE_DIR) $(COPRO_MCU_FAMILY) --cube_ver=$(COPRO_CUBE_VERSION) --stack_type=$(COPRO_STACK_TYPE) --stack_file=$(COPRO_STACK_BIN) --stack_addr=$(COPRO_STACK_ADDR) - -clean: - @echo "\tCLEAN\t" - @$(RM) $(ASSETS_COMPILED_DIR)/* - @$(RM) -rf $(COPRO_BUNDLE_DIR) - @$(RM) -rf $(DOLPHIN_EXTERNAL_OUTPUT_DIR) diff --git a/assets/ReadMe.md b/assets/ReadMe.md index 0e5b0bdb..09ec4cff 100644 --- a/assets/ReadMe.md +++ b/assets/ReadMe.md @@ -1,20 +1,18 @@ # Requirements - Python3 -- ImageMagic -- Make +- Python3 packages: Pillow & heatshrink2 # Compiling ```bash -make all +./fbt icons proto dolphin_internal dolphin_blocking dolphin_ext resources ``` # Compiling with Docker-Compose ```bash -docker-compose exec dev make -C assets clean -docker-compose exec dev make -C assets all +docker-compose exec dev ./fbt icons proto dolphin_internal dolphin_blocking dolphin_ext resources ``` # Asset naming rules @@ -46,3 +44,4 @@ Don't include assets that you are not using, compiler is not going to strip unus - `icons` - Icons sources. Goes to `compiled` folder. - `protobuf` - Protobuf sources. Goes to `compiled` folder. - `resources` - Assets that is going to be provisioned to SD card. +- `slideshow` - One-time slideshows for desktop diff --git a/assets/SConscript b/assets/SConscript new file mode 100644 index 00000000..e70208ab --- /dev/null +++ b/assets/SConscript @@ -0,0 +1,113 @@ +Import("env") + +# HACHHACK +# Currently injected to CPPPATH by libs - since they are built earlier and depend on assets +# env.Append( +# CPPPATH=[ +# Dir("./compiled"), +# ] +# ) + +assetsenv = env.Clone( + tools=["fbt_assets"], + FW_LIB_NAME="assets", +) +assetsenv.ApplyLibFlags() + +if not assetsenv["VERBOSE"]: + assetsenv.SetDefault( + ICONSCOMSTR="\tICONS\t${TARGET}", + PROTOCOMSTR="\tPROTO\t${SOURCE}", + DOLPHINCOMSTR="\tDOLPHIN\t${DOLPHIN_RES_TYPE}", + RESMANIFESTCOMSTR="\tMANIFEST\t${TARGET}", + PBVERCOMSTR="\tPBVER\t${TARGET}", + ) + +# Gathering icons sources +icons_src = assetsenv.GlobRecursive("*.png", "icons") +icons_src += assetsenv.GlobRecursive("frame_rate", "icons") + +icons = assetsenv.IconBuilder(Dir("compiled"), Dir("#/assets/icons")) +Depends(icons, icons_src) +Alias("icons", icons) + + +# Protobuf .proto -> .c + .h + +proto_src = Glob("protobuf/*.proto", source=True) +proto_options = Glob("protobuf/*.options", source=True) +proto = assetsenv.ProtoBuilder(Dir("compiled"), proto_src) +Depends(proto, proto_options) +# Precious(proto) +Alias("proto", proto) + + +# Internal animations + +dolphin_internal = assetsenv.DolphinSymBuilder( + Dir("compiled"), + Dir("#/assets/dolphin"), + DOLPHIN_RES_TYPE="internal", +) +Alias("dolphin_internal", dolphin_internal) + + +# Blocking animations + +dolphin_blocking = assetsenv.DolphinSymBuilder( + Dir("compiled"), + Dir("#/assets/dolphin"), + DOLPHIN_RES_TYPE="blocking", +) +Alias("dolphin_blocking", dolphin_blocking) + + +# Protobuf version meta +proto_ver = assetsenv.ProtoVerBuilder( + "compiled/protobuf_version.h", + "#/assets/protobuf/Changelog", +) +Depends(proto_ver, proto) +Alias("proto_ver", proto_ver) + +# Gather everything into a static lib +assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) + +assetslib = assetsenv.Library("${FW_LIB_NAME}", assets_parts) +assetsenv.Install("${LIB_DIST_DIR}", assetslib) + + +# Resources for SD card + +if assetsenv["IS_BASE_FIRMWARE"]: + # External dolphin animations + dolphin_external = assetsenv.DolphinExtBuilder( + Dir("#/assets/resources/dolphin"), + Dir("#/assets/dolphin"), + DOLPHIN_RES_TYPE="external", + ) + NoClean(dolphin_external) + if assetsenv["FORCE"]: + AlwaysBuild(dolphin_external) + Alias("dolphin_ext", dolphin_external) + + # Resources manifest + + resources = assetsenv.Command( + "#/assets/resources/Manifest", + assetsenv.GlobRecursive("*", "resources", exclude="Manifest"), + action=Action( + '${PYTHON3} ${ASSETS_COMPILER} manifest "${TARGET.dir.posix}"', + "${RESMANIFESTCOMSTR}", + ), + ) + Precious(resources) + NoClean(resources) + if assetsenv["FORCE"]: + AlwaysBuild(resources) + + # Exporting resources node to external environment + env["FW_RESOURCES"] = resources + Alias("resources", resources) + +Return("assetslib") diff --git a/assets/assets.mk b/assets/assets.mk deleted file mode 100644 index 18e0a244..00000000 --- a/assets/assets.mk +++ /dev/null @@ -1,32 +0,0 @@ -ASSETS_DIR := $(PROJECT_ROOT)/assets -ASSETS_COMPILER := $(PROJECT_ROOT)/scripts/assets.py -ASSETS_COMPILED_DIR := $(ASSETS_DIR)/compiled -ASSETS_SOURCE_DIR := $(ASSETS_DIR)/icons - -ASSETS_SOURCES += $(shell find $(ASSETS_SOURCE_DIR) -type f -iname '*.png' -or -iname 'frame_rate') -ASSETS += $(ASSETS_COMPILED_DIR)/assets_icons.c - -RESOURCES_DIR := $(ASSETS_DIR)/resources -RESOURCES_MANIFEST := $(RESOURCES_DIR)/Manifest -RESOURCES_FILES := $(shell find $(RESOURCES_DIR) ! -name Manifest -type f) - -DOLPHIN_SOURCE_DIR := $(ASSETS_DIR)/dolphin -DOLPHIN_INTERNAL_OUTPUT_DIR := $(ASSETS_COMPILED_DIR) -DOLPHIN_EXTERNAL_OUTPUT_DIR := $(ASSETS_DIR)/resources/dolphin - -PROTOBUF_SOURCE_DIR := $(ASSETS_DIR)/protobuf -PROTOBUF_COMPILER := $(PROJECT_ROOT)/lib/nanopb/generator/nanopb_generator.py -PROTOBUF_COMPILED_DIR := $(ASSETS_COMPILED_DIR) -PROTOBUF_SOURCES := $(shell find $(PROTOBUF_SOURCE_DIR) -type f -iname '*.proto') -PROTOBUF_FILENAMES := $(notdir $(addsuffix .pb.c,$(basename $(PROTOBUF_SOURCES)))) -PROTOBUF := $(addprefix $(PROTOBUF_COMPILED_DIR)/,$(PROTOBUF_FILENAMES)) $(PROTOBUF_COMPILED_DIR)/protobuf_version.h -PROTOBUF_VERSION := $(shell git -C $(PROTOBUF_SOURCE_DIR) fetch --tags 2>/dev/null ; git -C $(PROTOBUF_SOURCE_DIR) describe --tags --abbrev=0 2>/dev/null || echo 'unknown') -PROTOBUF_MAJOR_VERSION := $(word 1,$(subst ., ,$(PROTOBUF_VERSION))) -PROTOBUF_MINOR_VERSION := $(word 2,$(subst ., ,$(PROTOBUF_VERSION))) -$(if $(PROTOBUF_MAJOR_VERSION),,$(error "Protobuf major version is not specified, $$PROTOBUF_VERSION=$(PROTOBUF_VERSION), please perform git fetch in assets/protobuf directory")) -$(if $(PROTOBUF_MINOR_VERSION),,$(error "Protobuf minor version is not specified, $$PROTOBUF_VERSION=$(PROTOBUF_VERSION), please perform git fetch in assets/protobuf directory")) - -PROTOBUF_CFLAGS += -DPB_ENABLE_MALLOC - -CFLAGS += -I$(ASSETS_COMPILED_DIR) $(PROTOBUF_CFLAGS) -C_SOURCES += $(wildcard $(ASSETS_COMPILED_DIR)/*.c) diff --git a/assets/compiled/application.pb.c b/assets/compiled/application.pb.c deleted file mode 100644 index a50850b2..00000000 --- a/assets/compiled/application.pb.c +++ /dev/null @@ -1,18 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5 */ - -#include "application.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(PB_App_StartRequest, PB_App_StartRequest, AUTO) - - -PB_BIND(PB_App_LockStatusRequest, PB_App_LockStatusRequest, AUTO) - - -PB_BIND(PB_App_LockStatusResponse, PB_App_LockStatusResponse, AUTO) - - - diff --git a/assets/compiled/application.pb.h b/assets/compiled/application.pb.h deleted file mode 100644 index 4b05c46b..00000000 --- a/assets/compiled/application.pb.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5 */ - -#ifndef PB_PB_APP_APPLICATION_PB_H_INCLUDED -#define PB_PB_APP_APPLICATION_PB_H_INCLUDED -#include - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Struct definitions */ -typedef struct _PB_App_LockStatusRequest { - char dummy_field; -} PB_App_LockStatusRequest; - -typedef struct _PB_App_StartRequest { - char *name; - char *args; -} PB_App_StartRequest; - -typedef struct _PB_App_LockStatusResponse { - bool locked; -} PB_App_LockStatusResponse; - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initializer values for message structs */ -#define PB_App_StartRequest_init_default {NULL, NULL} -#define PB_App_LockStatusRequest_init_default {0} -#define PB_App_LockStatusResponse_init_default {0} -#define PB_App_StartRequest_init_zero {NULL, NULL} -#define PB_App_LockStatusRequest_init_zero {0} -#define PB_App_LockStatusResponse_init_zero {0} - -/* Field tags (for use in manual encoding/decoding) */ -#define PB_App_StartRequest_name_tag 1 -#define PB_App_StartRequest_args_tag 2 -#define PB_App_LockStatusResponse_locked_tag 1 - -/* Struct field encoding specification for nanopb */ -#define PB_App_StartRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, name, 1) \ -X(a, POINTER, SINGULAR, STRING, args, 2) -#define PB_App_StartRequest_CALLBACK NULL -#define PB_App_StartRequest_DEFAULT NULL - -#define PB_App_LockStatusRequest_FIELDLIST(X, a) \ - -#define PB_App_LockStatusRequest_CALLBACK NULL -#define PB_App_LockStatusRequest_DEFAULT NULL - -#define PB_App_LockStatusResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, BOOL, locked, 1) -#define PB_App_LockStatusResponse_CALLBACK NULL -#define PB_App_LockStatusResponse_DEFAULT NULL - -extern const pb_msgdesc_t PB_App_StartRequest_msg; -extern const pb_msgdesc_t PB_App_LockStatusRequest_msg; -extern const pb_msgdesc_t PB_App_LockStatusResponse_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define PB_App_StartRequest_fields &PB_App_StartRequest_msg -#define PB_App_LockStatusRequest_fields &PB_App_LockStatusRequest_msg -#define PB_App_LockStatusResponse_fields &PB_App_LockStatusResponse_msg - -/* Maximum encoded size of messages (where known) */ -/* PB_App_StartRequest_size depends on runtime parameters */ -#define PB_App_LockStatusRequest_size 0 -#define PB_App_LockStatusResponse_size 2 - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/assets/compiled/assets_dolphin_blocking.c b/assets/compiled/assets_dolphin_blocking.c deleted file mode 100644 index a1ec14b4..00000000 --- a/assets/compiled/assets_dolphin_blocking.c +++ /dev/null @@ -1,330 +0,0 @@ -#include -#include -#include -#include - - - -const uint8_t _A_L0_NoDb_128x51_0[] = { - 0x1,0x0,0x43,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xff,0x11,0x0,0x88,0x0,0x4,0x16,0x34,0x0,0x10,0xc1,0x1,0xf7,0x20,0x7,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x7,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x4,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x1,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x7,0x9c,0x4a,0xb,0x22,0x7,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x7,0xf8,0x3f,0xc1,0xf9,0x7,0x7,0xbd,0xc2,0x3c,0xaf,0x2a,0x7,0xff,0xf3,0xfc,0x7,0xb6,0x22,0x44,0xf,0x2d,0x7,0xff,0x1d,0xfb,0x7,0xa6,0x2,0x73,0x8,0x91,0x63,0x27,0x70,0x7e,0x85,0xff,0xf7,0xf7,0x7,0xa5,0x2,0x95,0x70,0x91,0x54,0xb1,0x50,0x4f,0x86,0xff,0xfb,0xef,0x7,0xb6,0x2,0x45,0x42,0x7,0x9f,0xfc,0x1e,0xe3,0xf1,0xf,0x9f,0x7e,0x3f,0xdf,0x1f,0xad,0x24,0xbe,0x38,0xc8,0x5c,0x1c,0x1e,0x3e,0xfe,0xf1,0xfe,0xc1,0xe3,0xff,0x7,0xe7,0x0,0x5a,0x22,0xf5,0x7,0xc6,0xfc,0x1f,0xa5,0xf7,0x7,0xc6,0xfc,0x1e,0xff,0xe6,0xd1,0x40,0x68,0x17,0xff,0xff,0x9c,0x1e,0xb8,0x8,0x8,0x10,0xa0,0x4b,0xf1,0xff,0x70,0xc1,0xeb,0xc0,0x2,0x1c,0x13,0xa0,0xdf,0x1c,0x0,0x3e,0xfe,0xf,0xf1,0x83,0x83,0xda,0x11,0x2,0x80,0x42,0x1,0xe5,0xff,0x87,0xdf,0x81,0xeb,0x18,0x81,0xc0,0x23,0x0,0xf3,0x8f,0xdf,0x1,0xeb,0xa8,0x99,0x59,0xe7,0x0,0xf3,0x9f,0xde,0x1,0xeb,0x48,0xa5,0x64,0x6f,0x0,0xf3,0xbf,0x83,0xda,0x11,0x4a,0xf8,0x87,0xd3,0xfe,0xf,0x88,0x88,0xfd,0x4,0x2,0xf,0x69,0x95,0x84,0xbe,0x80,0xf7,0x3f,0xb0,0x3f,0xc1,0xf0,0xbf,0x40,0x7c,0xe0,0x1,0x24,0xdf,0x1f,0x0,0x10,0xa7,0xee,0xf5,0x7,0x98,0x25,0x40,0x1e,0x0,0xf0,0x7,0x80,0x28 -}; - -const uint8_t _A_L0_NoDb_128x51_1[] = { - 0x1,0x0,0x45,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xff,0x11,0x0,0x88,0x0,0x4,0x16,0x34,0x0,0x10,0xc1,0x1,0xf7,0x20,0x7,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x7,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x4,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x1,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x7,0x9c,0x4a,0xb,0x22,0x7,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x7,0xf8,0x3f,0xc1,0xf9,0x1f,0xfe,0x3,0xda,0xe1,0x1e,0x57,0x95,0x3,0xff,0xe7,0xf9,0x83,0xdb,0x11,0x22,0x7,0x96,0x83,0xff,0x3b,0xf7,0x3,0xd3,0x1,0x39,0x84,0x48,0xb1,0x93,0xb8,0x3f,0x43,0xff,0xed,0xef,0x83,0xd2,0x81,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc3,0xff,0xf6,0xdf,0x83,0xdb,0x1,0x22,0xa1,0x3,0xcf,0xfc,0xf,0x71,0xf8,0x87,0xce,0xff,0x1f,0xbf,0x8f,0xd6,0x92,0x5f,0x1c,0x64,0x2e,0xe,0xf,0x1f,0x7d,0xf8,0xff,0x60,0xf1,0xff,0x83,0xf3,0x80,0x2d,0x11,0x7a,0x83,0xe0,0x9c,0x20,0xfc,0x2f,0xb8,0x3e,0x37,0xc0,0xf7,0xff,0x36,0x8a,0x2,0xbf,0x1f,0xee,0x7c,0x1e,0xb8,0x8,0x8,0x10,0xa0,0x4b,0xf1,0xfd,0xc3,0xc1,0xeb,0xc0,0x2,0x1c,0x11,0x7e,0x3e,0x78,0x1d,0xf8,0x1f,0x4a,0xf1,0x8f,0xc7,0x2f,0x80,0xf5,0x84,0x40,0xa0,0x10,0x80,0x79,0x7f,0xe7,0xf7,0x80,0x7a,0xc6,0x20,0x70,0x8,0xc0,0x3c,0xef,0xf7,0x0,0x7a,0xea,0x26,0x56,0x79,0xc0,0x3c,0xff,0xf6,0x0,0x7a,0xd2,0x29,0x59,0x1b,0xc0,0x3d,0x2c,0x23,0xf6,0xa5,0x7c,0x43,0xeb,0x63,0x7,0xbc,0x44,0x7e,0x84,0x1,0x7,0xb4,0xca,0xc2,0x5f,0x40,0x7b,0x9f,0xd8,0x1f,0xe0,0xf8,0x5f,0xa0,0x3e,0x70,0x0,0x92,0x6f,0x8f,0x80,0x8,0x53,0xf7,0x7a,0x83,0xcc,0x12,0xa0,0xf,0x0,0x78,0x3,0xc0,0x14 -}; - -const uint8_t _A_L0_NoDb_128x51_2[] = { - 0x1,0x0,0x43,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xff,0x11,0x0,0x88,0x0,0x4,0x16,0x34,0x0,0x10,0xc1,0x1,0xf7,0x20,0x7,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x7,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x4,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x1,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x7,0x9c,0x4a,0xb,0x22,0x7,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x7,0xf8,0x3f,0xc1,0xfe,0xa,0x5b,0x84,0x79,0x5e,0x54,0x0,0x7c,0xe2,0x24,0x40,0xf2,0xd0,0x7f,0xe3,0xff,0xc0,0x7a,0x60,0x27,0x30,0x89,0x16,0x32,0x77,0x7,0xe8,0x7f,0xfc,0xff,0x30,0x7a,0x50,0x29,0x57,0x9,0x15,0x4b,0x15,0x4,0xf8,0x7f,0xe7,0x7e,0xe0,0x7b,0x60,0x24,0x54,0x20,0x79,0xfb,0x7b,0xe0,0xf6,0x1f,0x88,0x7d,0x22,0xdb,0xf1,0xfa,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xe3,0xee,0xdf,0x1f,0xef,0xe1,0x7f,0xff,0xdf,0x81,0xf7,0xc0,0xbf,0x80,0x8,0x1f,0x83,0xe1,0x7,0xea,0x78,0x43,0xfe,0xf,0x6f,0xf2,0xe8,0xa0,0x2b,0xf1,0xff,0x1b,0xd4,0xe0,0x30,0x10,0x21,0x40,0x97,0xe2,0xf,0x7e,0x0,0x10,0xe0,0x8b,0xf1,0xfe,0xe7,0xc1,0xf6,0x8f,0x1f,0xdc,0x3c,0x1e,0xd0,0x88,0x14,0x2,0x10,0xf,0x2f,0x3c,0xe,0xfc,0xf,0x58,0xc4,0xe,0x1,0x18,0x7,0x94,0x7e,0x39,0x7c,0x7,0xae,0xa2,0x65,0x67,0x9c,0x3,0xcb,0xff,0x3f,0xbc,0x3,0xd6,0x91,0x4a,0xc8,0xde,0x1,0xe7,0x7f,0xb8,0xf,0xda,0x95,0xf1,0xf,0xa7,0xfe,0xc0,0xf,0x78,0x88,0xfc,0xc0,0x3,0x61,0x7,0xb4,0xca,0xc2,0x5f,0x30,0x0,0xd8,0xcf,0xf8,0x40,0x20,0x7f,0x83,0xd5,0x7e,0x80,0xf9,0xc0,0x2,0x49,0xbe,0x3e,0x0,0x21,0x4f,0xdd,0xea,0xf,0x30,0x4a,0x80,0x3c,0x1,0xe0,0xf,0x0,0x50 -}; - -const uint8_t _A_L0_NoDb_128x51_3[] = { - 0x1,0x0,0x43,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xff,0x11,0x0,0x88,0x0,0x4,0x16,0x34,0x0,0x10,0xc1,0x1,0xf7,0x20,0x7,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x7,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x4,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x1,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x7,0x9c,0x4a,0xb,0x22,0x7,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x7,0xf8,0x3f,0xc1,0xfe,0xa,0x5b,0x84,0x79,0x5e,0x54,0x0,0x7c,0xe2,0x24,0x40,0xf2,0xd0,0x7f,0xe0,0xe0,0xf5,0xc0,0x4e,0x61,0x12,0x2c,0x64,0xee,0xf,0xd0,0xff,0xfe,0x7f,0x80,0xf4,0xa0,0x52,0xae,0x12,0x2a,0x96,0x2a,0x9,0xf0,0xff,0xe3,0xbf,0x60,0xf6,0xc0,0x48,0xa8,0x40,0xf2,0xbf,0xfe,0xfe,0xe0,0xf6,0x1f,0x88,0x7c,0xf7,0xf1,0xdf,0x78,0xfd,0x69,0x25,0xf1,0xc6,0x42,0xe0,0xe0,0xf1,0xf7,0xfb,0x8f,0xf7,0xf0,0xef,0xff,0xfb,0xc0,0xfb,0xe0,0x77,0xef,0xe0,0x11,0x7,0xe6,0xfc,0x1f,0xdf,0xf0,0xff,0x83,0xdf,0xfc,0xba,0x28,0xd,0x3,0x7f,0xff,0x37,0xa9,0xc0,0x60,0x20,0x42,0x81,0x68,0x1,0xf1,0xc0,0x2,0x1c,0x13,0xa1,0x7f,0xff,0xf9,0xc1,0xf6,0xbf,0x1f,0xf7,0xc,0x1e,0xd0,0x88,0x14,0x2,0x10,0xf,0x2f,0xce,0x0,0x1e,0xd1,0x88,0x1c,0x2,0x30,0xf,0x28,0x3c,0x1c,0x1e,0xda,0x89,0x95,0x9e,0x70,0xf,0x2f,0xfc,0x3e,0xfc,0xf,0x5a,0x45,0x2b,0x23,0x78,0x7,0x9c,0x7e,0xf8,0x3f,0x6a,0x57,0xc4,0x3e,0x93,0xfb,0xc0,0x3d,0xe2,0x23,0xf3,0xff,0xdf,0xc1,0xef,0x32,0xb0,0x97,0xcc,0x0,0x20,0xf6,0x3f,0xb0,0x80,0x81,0xfe,0xf,0x55,0xfa,0x3,0xe7,0x0,0x9,0x26,0xf8,0xf8,0x0,0x85,0x3f,0x77,0xa8,0x3c,0xc1,0x2a,0x0,0xf0,0x7,0x80,0x3c,0x1,0x40 -}; - - -const uint8_t * const _A_L0_NoDb_128x51[] = { - - _A_L0_NoDb_128x51_0, - - _A_L0_NoDb_128x51_1, - - _A_L0_NoDb_128x51_2, - - _A_L0_NoDb_128x51_3, - -}; - - - -const uint8_t L0_NoDb_128x51_frame_order[] = { 0, 1, 2, 3 }; - -const BubbleAnimation BA_L0_NoDb_128x51 = { - .icon_animation = { - .width = 128, - .height = 51, - .frame_count = 4, - .frame_rate = 2, - .frames = _A_L0_NoDb_128x51 - }, - .frame_order = L0_NoDb_128x51_frame_order, - .passive_frames = 4, - .active_frames = 0, - .active_cooldown = 0, - .active_cycles = 0, - .duration = 0, - - .frame_bubble_sequences = NULL, - .frame_bubble_sequences_count = 0, - -}; - - -const uint8_t _A_L0_SdBad_128x51_0[] = { - 0x1,0x0,0x1,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfe,0x1,0x82,0x4,0xc,0x4a,0x1,0x70,0x8f,0x1,0x46,0x8,0xf,0x5e,0x30,0x24,0x60,0x50,0xc,0x44,0x88,0x1f,0x1a,0xaa,0x64,0xeb,0xaf,0x71,0x84,0x48,0xb1,0x93,0xb8,0x39,0x3d,0x72,0x55,0x2a,0x50,0x4,0x6e,0x12,0x2a,0x96,0x28,0x3e,0x20,0xf4,0xc1,0x3,0xcf,0x1,0x22,0xa1,0x3,0xf0,0x7e,0x21,0xf9,0xc6,0x52,0xea,0x57,0x22,0xf8,0xe3,0x21,0x63,0xf6,0x0,0x1d,0x1,0x3f,0xd3,0x5,0x7f,0x83,0xfc,0x1f,0xe0,0xf5,0xcf,0xfc,0xee,0x77,0xe0,0x5b,0x7e,0x28,0x10,0x18,0x25,0x2,0x7f,0xf9,0x93,0x87,0xde,0x11,0x0,0x7,0x8e,0x82,0xff,0xfc,0xc7,0x83,0xe2,0xb9,0x19,0x83,0xf4,0x1,0xf5,0x78,0xa9,0x69,0x60,0x9f,0x1,0x7d,0xd4,0xb7,0xa0,0xf1,0x27,0xd0,0x3c,0x70,0xa0,0xf1,0x37,0xd0,0xfc,0xc1,0xf6,0x0,0x30,0x7f,0xf0,0x1,0xff,0xff,0x83,0xfe,0x1,0xfb,0xf9,0xf0,0x83,0xf6,0x19,0xc6,0x7,0xb0,0xe8,0xe0,0x34,0xf,0xfc,0x1b,0x90,0xf,0x69,0x80,0xc,0xa0,0x5a,0xf,0xfc,0xd8,0x1e,0xf1,0x80,0x19,0x41,0x3a,0x5,0xd1,0xfe,0x3,0xec,0xff,0x51,0x8b,0x84,0x8a,0x4,0xf,0xcc,0x44,0x4a,0xc,0xf,0xd8,0x54,0x38,0x1f,0xb0,0x68,0xf0,0x7f,0xc7,0xfe,0x5f,0xf0,0x7e,0x1f,0xfc,0x1f,0xd3,0x85,0xf9,0x83,0xe8,0x14,0x70,0x1f,0x0,0x10,0xa7,0xe0,0xf5,0x5,0x18,0x25,0x40,0x1e,0x0,0xf0,0x7,0x80,0x28 -}; - -const uint8_t _A_L0_SdBad_128x51_1[] = { - 0x1,0x0,0x12,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfe,0x1,0x82,0x4,0xc,0x4a,0x1,0x70,0x8f,0x1,0x46,0x8,0xf,0x5e,0x30,0x24,0x60,0x50,0xc,0x44,0x88,0x1f,0x1a,0xaa,0x64,0xeb,0xaf,0x71,0x84,0x48,0xb1,0x93,0xb8,0x39,0x3d,0x72,0x55,0x2a,0x50,0x4,0x6e,0x12,0x2a,0x96,0x28,0x3e,0x20,0xf4,0xc1,0x3,0xcf,0x1,0x22,0xa1,0x3,0xf0,0x7e,0x21,0xf9,0xc6,0x52,0xea,0x57,0x22,0xf8,0xe3,0x21,0x63,0xf6,0x0,0x1d,0x1,0x3f,0xd3,0x5,0x7f,0x83,0xfc,0x1f,0xe0,0xf5,0xcf,0xfc,0xee,0x77,0xe0,0x5b,0x7e,0x28,0x10,0x18,0x25,0x2,0x7f,0xf9,0x93,0x87,0xde,0x11,0x0,0x7,0x8e,0x82,0xff,0xfc,0xc7,0x83,0xe2,0xb9,0x19,0x83,0xf4,0x1,0xf5,0x78,0xa9,0x69,0x60,0x9f,0x1,0x7d,0xd4,0xb7,0xa0,0xf1,0x27,0xd0,0x3c,0x70,0xa0,0xf1,0x37,0xd0,0xfc,0xc1,0xf6,0x0,0x30,0x7f,0xf0,0x1,0xff,0xff,0x81,0xfc,0x1,0xfb,0xf8,0xe0,0x83,0xf2,0xff,0x4c,0xc3,0x3,0xd8,0x74,0x70,0x15,0xf8,0xe1,0xa1,0x0,0xf6,0x98,0x0,0xca,0x5,0xa0,0x9f,0xc5,0xa1,0x20,0xf6,0x8c,0x0,0xca,0x9,0xd0,0xbb,0xcf,0xb3,0x17,0xb0,0x7d,0x7c,0x3e,0xf3,0xff,0xc0,0x3d,0xee,0x12,0x28,0x10,0x3c,0x7d,0xee,0x1,0xbe,0x83,0xdb,0x11,0x12,0x83,0x2f,0xec,0x1e,0x30,0xa8,0x70,0x3f,0x60,0xd1,0xe0,0xff,0x83,0xf4,0x7f,0xc5,0xf4,0x7,0xd1,0xfd,0x1,0xfe,0xf,0x99,0xc2,0xfc,0xc1,0xf4,0xa,0x38,0xf,0x80,0x8,0x53,0xf0,0x7a,0x82,0x8c,0x12,0xa0,0xf,0x0,0x78,0x3,0xc0,0x14 -}; - - -const uint8_t * const _A_L0_SdBad_128x51[] = { - - _A_L0_SdBad_128x51_0, - - _A_L0_SdBad_128x51_1, - -}; - - - -const uint8_t L0_SdBad_128x51_frame_order[] = { 0, 1 }; - -const BubbleAnimation BA_L0_SdBad_128x51 = { - .icon_animation = { - .width = 128, - .height = 51, - .frame_count = 2, - .frame_rate = 2, - .frames = _A_L0_SdBad_128x51 - }, - .frame_order = L0_SdBad_128x51_frame_order, - .passive_frames = 2, - .active_frames = 0, - .active_cooldown = 0, - .active_cycles = 0, - .duration = 0, - - .frame_bubble_sequences = NULL, - .frame_bubble_sequences_count = 0, - -}; - - -const uint8_t _A_L0_SdOk_128x51_0[] = { - 0x1,0x0,0x19,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0xe,0x54,0xec,0xe,0x0,0x8,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x3,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x3,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x7,0xcc,0x1f,0xf8,0xf,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x9,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x9,0x4e,0xf4,0x1e,0x38,0x9,0x15,0x8,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x7,0xa4,0xc3,0x9d,0x18,0xc3,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xea,0x0,0x90,0x78,0x9f,0x84,0x1f,0x7c,0x0,0x7f,0xf7,0xfe,0xe0,0xfe,0x1f,0xef,0x0,0xfe,0x80,0xa5,0x75,0x14,0x6,0x80,0xf,0x99,0x80,0xc,0xa0,0x4b,0xf5,0x0,0x24,0x61,0xaa,0x7d,0x6,0xfb,0x83,0xdb,0xe0,0xff,0x70,0x79,0x34,0x6,0x4,0xf,0x28,0x3f,0xf0,0x1e,0xf8,0x88,0x94,0x18,0x1e,0x40,0x1,0x7,0xc4,0x2a,0x1c,0xf,0xd8,0x34,0x78,0x3f,0xe0,0xfd,0x1f,0xf1,0x7d,0x41,0xf2,0x7f,0x50,0x7f,0x83,0xe2,0x70,0xbf,0x30,0x7d,0x2,0x8e,0x3,0xe0,0x2,0x14,0xfc,0x1e,0xa0,0xa3,0x4,0xa8,0x3,0xc0,0x1e,0x0,0xf0,0x5,0x0 -}; - -const uint8_t _A_L0_SdOk_128x51_1[] = { - 0x1,0x0,0x1e,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0xe,0x54,0xec,0xe,0x0,0x8,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x3,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x3,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x7,0xcc,0x1f,0xf8,0xf,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x9,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x9,0x4e,0xf4,0x1e,0x38,0x9,0x15,0x8,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x7,0xa4,0xc3,0x9d,0x18,0xc3,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xea,0x0,0x90,0x78,0x9f,0x84,0x1f,0x7c,0xe,0xff,0x8c,0x1f,0xd8,0x70,0x7f,0x63,0xc1,0xfb,0xbf,0xcf,0x9f,0xc8,0x14,0xae,0xa2,0x80,0xd0,0x11,0xe8,0x0,0x49,0x80,0xc,0xa0,0x4b,0xf5,0x0,0x24,0x61,0xaa,0x7d,0x6,0xfb,0x83,0xdb,0xe0,0xff,0x70,0x79,0x34,0x6,0x4,0xf,0x28,0x3f,0xf0,0x1e,0xf8,0x88,0x94,0x18,0x1e,0x40,0x1,0x7,0xc4,0x2a,0x1c,0xf,0xd8,0x34,0x78,0x3f,0xe0,0xfd,0x1f,0xf1,0x7d,0x41,0xf2,0x7f,0x50,0x7f,0x83,0xe2,0x70,0xbf,0x30,0x7d,0x2,0x8e,0x3,0xe0,0x2,0x14,0xfc,0x1e,0xa0,0xa3,0x4,0xa8,0x3,0xc0,0x1e,0x0,0xf0,0x5,0x0 -}; - -const uint8_t _A_L0_SdOk_128x51_2[] = { - 0x1,0x0,0x22,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0xe,0x54,0xec,0xe,0x0,0x8,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x3,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x3,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x7,0xcc,0x1f,0xf8,0xf,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x9,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x9,0x4e,0xf4,0x1e,0x38,0x9,0x15,0x8,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x7,0xa4,0xc3,0x9d,0x18,0xc3,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xe5,0x7d,0x3f,0xd8,0x3c,0x7e,0x77,0xc0,0x7d,0xf0,0x3b,0xf6,0x30,0x7f,0x41,0xef,0xc0,0xfd,0x87,0x93,0xc8,0x1f,0x5b,0xfc,0xf9,0xfc,0x81,0x4a,0xea,0x28,0xd,0x1,0x1e,0x80,0x4,0x98,0x0,0xca,0x4,0xbf,0x50,0x2,0x46,0x1a,0xa7,0xd0,0x6f,0xb8,0x3d,0xbe,0xf,0xf7,0x7,0x93,0x40,0x60,0x40,0xf2,0x83,0xff,0x1,0xef,0x88,0x89,0x41,0x81,0xe4,0x0,0x10,0x7c,0x42,0xa1,0xc0,0xfd,0x83,0x47,0x83,0xfe,0xf,0xd1,0xff,0x17,0xd4,0x1f,0x27,0xf5,0x7,0xf8,0x3e,0x27,0xb,0xf3,0x7,0xd0,0x28,0xe0,0x3e,0x0,0x21,0x4f,0xc1,0xea,0xa,0x30,0x4a,0x80,0x3c,0x1,0xe0,0xf,0x0,0x50 -}; - -const uint8_t _A_L0_SdOk_128x51_3[] = { - 0x1,0x0,0x26,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0xe,0x54,0xec,0xe,0x0,0x8,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x3,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x3,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x7,0xcc,0x1f,0xf8,0xf,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x9,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x9,0x4e,0xf4,0x1e,0x38,0x9,0x15,0x8,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x7,0x8d,0xcc,0x1e,0x33,0xe,0x74,0x63,0xf,0x49,0x2f,0x8e,0x32,0x17,0x7,0x7,0x95,0xc4,0xff,0x60,0xf1,0xf9,0xde,0x1,0xf7,0xc0,0xef,0xd8,0xef,0x80,0xfd,0x83,0xdf,0x81,0xfb,0xf,0x2f,0x90,0x3e,0xb7,0xf9,0xf3,0xf9,0x2,0x95,0xd4,0x50,0x1a,0x2,0x3d,0x0,0x9,0x30,0x1,0x94,0x9,0x7e,0xa0,0x4,0x8c,0x35,0x4f,0xa0,0xdf,0x70,0x7b,0x7c,0x1f,0xee,0xf,0x26,0x80,0xc0,0x81,0xe5,0x7,0xfe,0x3,0xdf,0x11,0x12,0x83,0x3,0xc8,0x0,0x20,0xf8,0x85,0x43,0x81,0xfb,0x6,0x8f,0x7,0xfc,0x1f,0xa3,0xfe,0x2f,0xa8,0x3e,0x4f,0xea,0xf,0xf0,0x7c,0x4e,0x17,0xe6,0xf,0xa0,0x51,0xc0,0x7c,0x0,0x42,0x9f,0x83,0xd4,0x14,0x60,0x95,0x0,0x78,0x3,0xc0,0x1e,0x0,0xa0 -}; - - -const uint8_t * const _A_L0_SdOk_128x51[] = { - - _A_L0_SdOk_128x51_0, - - _A_L0_SdOk_128x51_1, - - _A_L0_SdOk_128x51_2, - - _A_L0_SdOk_128x51_3, - -}; - - - -const uint8_t L0_SdOk_128x51_frame_order[] = { 0, 1, 2, 3 }; - -const BubbleAnimation BA_L0_SdOk_128x51 = { - .icon_animation = { - .width = 128, - .height = 51, - .frame_count = 4, - .frame_rate = 2, - .frames = _A_L0_SdOk_128x51 - }, - .frame_order = L0_SdOk_128x51_frame_order, - .passive_frames = 4, - .active_frames = 0, - .active_cooldown = 0, - .active_cycles = 0, - .duration = 0, - - .frame_bubble_sequences = NULL, - .frame_bubble_sequences_count = 0, - -}; - - -const uint8_t _A_L0_Url_128x51_0[] = { - 0x1,0x0,0x2d,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7d,0x7e,0x1,0x89,0x4,0x7,0x9c,0x1c,0x1e,0x71,0xca,0xc,0x16,0x1,0x8,0x7,0x94,0xa,0x81,0xff,0xfc,0xff,0x1,0xe5,0xba,0x91,0x40,0x41,0xe5,0x2,0x0,0x8e,0x83,0xff,0x8e,0xfd,0x83,0xcb,0xe5,0x22,0xba,0xc3,0xb9,0xd2,0x4c,0x96,0x3a,0x7,0xd0,0xbf,0xfe,0xfe,0xe0,0xf2,0x9f,0x58,0xb2,0xb1,0x29,0x4c,0x97,0x23,0x52,0x81,0x7c,0x37,0xff,0xdf,0x78,0x3c,0xaf,0x52,0x20,0x78,0xfa,0x41,0xeb,0xff,0x7,0xa4,0x8c,0x3e,0x5a,0x4c,0x80,0x3c,0xbb,0xf1,0xfe,0xf8,0x3c,0xbf,0x92,0x1b,0xad,0x3b,0x9d,0x98,0xf0,0xf,0xc4,0x1e,0x3e,0xfe,0xf1,0xfd,0x22,0x5,0xc1,0x0,0x8,0xc,0x41,0xe3,0xff,0x7,0x98,0x0,0x41,0xed,0xc0,0x16,0x88,0xbc,0xc0,0x10,0xf,0x1d,0xf8,0x3f,0x4b,0xea,0xf,0xad,0xf8,0x3e,0x3f,0xd,0xa1,0x80,0xd0,0x2f,0xff,0xff,0x38,0x3d,0xe0,0xc5,0x2,0x5f,0x8f,0xfb,0x86,0xf,0x78,0x1b,0xc4,0xba,0xd,0xf1,0xc0,0x3,0xef,0xe0,0xff,0x18,0x38,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbf,0xf0,0xfb,0xf0,0x3d,0xa4,0x74,0xa8,0xc0,0x3c,0xe3,0xf7,0xc0,0x7b,0xca,0xa7,0x0,0xf3,0x9f,0xde,0x1,0xef,0x1a,0xbc,0x3,0xce,0xfe,0xf,0x80,0xfa,0xff,0xc1,0xf0,0x3f,0x51,0x0,0x97,0xf4,0x1f,0x7,0xf5,0x7,0xf8,0x3e,0x60,0xeb,0xf2,0x7,0xdf,0xf9,0xbe,0x5e,0x0,0x79,0x4f,0xc1,0xed,0xfc,0x5,0x8,0x25,0x80,0x1e,0x0,0xf0,0x7,0x80,0x24 -}; - -const uint8_t _A_L0_Url_128x51_1[] = { - 0x1,0x0,0x2d,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7d,0x7e,0x1,0x89,0x4,0x7,0x9c,0x7f,0xf8,0xf,0x28,0xe5,0x6,0xb,0x0,0x84,0x3,0xca,0x5,0x40,0xff,0xf9,0xfe,0x60,0xf2,0xdd,0x48,0xa0,0x20,0xf2,0x81,0x0,0x47,0x41,0xff,0x9d,0xfb,0x81,0xe5,0xf2,0x91,0x5d,0x61,0xdc,0xe9,0x26,0x4b,0x1d,0x3,0xe8,0x7f,0xfd,0xbd,0xf0,0x79,0x4f,0xac,0x59,0x58,0x94,0xa6,0x4b,0x91,0xa9,0x40,0xbe,0x1f,0xff,0xb6,0xfc,0x1e,0x57,0xa9,0x10,0x3c,0x7d,0x20,0xf5,0xff,0x3,0xd2,0x46,0x1f,0x2d,0x26,0x40,0x1e,0x57,0xf8,0xfd,0xfc,0x1e,0x5f,0xc9,0xd,0xd6,0x9d,0xce,0xcc,0x78,0x7,0xe2,0xf,0x1f,0x7d,0xf8,0xfe,0x91,0x2,0xe0,0x80,0x4,0x6,0x20,0xf1,0xff,0x83,0xcc,0x0,0x20,0xf6,0xe0,0xb,0x44,0x5e,0x60,0x8,0x7,0x89,0x38,0x41,0xf8,0x5f,0x50,0x7d,0x6f,0x81,0xf1,0xf8,0x6d,0xc,0x5,0x7e,0x3f,0xdc,0xf8,0x3d,0xe0,0xc5,0x2,0x5f,0x8f,0xee,0x1e,0xf,0x78,0x1b,0xc4,0x97,0xe3,0xe7,0x81,0xdf,0x81,0xf4,0xaf,0x18,0xfc,0x72,0xf8,0xf,0x6e,0x1e,0x26,0x10,0xf,0x2f,0xfc,0xfe,0xf0,0xf,0x69,0x1d,0x2a,0x30,0xf,0x3b,0xfd,0xc0,0x1e,0xf2,0xa9,0xc0,0x3c,0xff,0xf6,0x0,0x7b,0xc6,0xaf,0x0,0xf4,0xb0,0x87,0xfa,0xc6,0x3f,0xd2,0x0,0x97,0xf4,0x1f,0x7,0xf5,0x7,0xf8,0x3e,0x60,0xeb,0xf2,0x7,0xdf,0xf9,0xbe,0x5e,0x0,0x79,0x4f,0xc1,0xed,0xfc,0x5,0x8,0x25,0x80,0x1e,0x0,0xf0,0x7,0x80,0x24 -}; - -const uint8_t _A_L0_Url_128x51_2[] = { - 0x1,0x0,0x29,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7d,0x7e,0x1,0x89,0x4,0x7,0xc4,0x72,0x83,0x5,0x80,0x42,0x1,0xe5,0x2,0xa0,0x3,0xd7,0x75,0x22,0x80,0x83,0xca,0x4,0x1,0x1d,0x7,0xfe,0x3f,0xfc,0x7,0x97,0xca,0x45,0x75,0x87,0x73,0xa4,0x99,0x2c,0x74,0xf,0xa1,0xff,0xf3,0xfc,0xc1,0xe5,0x3e,0xb1,0x65,0x62,0x52,0x99,0x2e,0x46,0xa5,0x2,0xf8,0x7f,0xe7,0x7e,0xe0,0x79,0x5e,0xa4,0x40,0xf1,0xf4,0x83,0xd7,0xdb,0xdf,0x7,0x9c,0x8c,0x3e,0x5a,0x4c,0x80,0x3c,0xe2,0xdb,0xf0,0x79,0x7f,0x24,0x37,0x5a,0x77,0x3b,0x31,0xe0,0x1f,0x88,0x3c,0x7d,0xdb,0xe3,0xfa,0x44,0xb,0x82,0x0,0x10,0x18,0xfc,0x2f,0xff,0xfb,0xf2,0x7d,0x1,0xed,0xc0,0xbf,0x80,0x9,0x5f,0x40,0xf1,0x1f,0x8,0x3f,0x53,0xc2,0x1f,0xf0,0x7b,0xfe,0x17,0x43,0x1,0x5f,0x8f,0xf8,0xde,0x60,0x4,0x83,0x14,0x9,0x7e,0x20,0xf9,0x81,0xbc,0x49,0x7e,0x3f,0xdc,0xf8,0x3e,0xd1,0xe3,0xfb,0x87,0x83,0xdf,0x87,0x89,0x84,0x3,0xcb,0xcf,0x3,0xbf,0x3,0xda,0x47,0x4a,0x8c,0x3,0xca,0x3f,0x1c,0xbe,0x3,0xde,0x55,0x38,0x7,0x97,0xfe,0x7f,0x78,0x7,0xbc,0x6a,0xf0,0xf,0x3b,0xfd,0xc0,0x3f,0xbf,0xfb,0x0,0xff,0x0,0x3,0x61,0x2f,0xe0,0x0,0x6c,0x67,0xfc,0x20,0x10,0x3f,0xc1,0xed,0x7,0x5f,0x90,0x3e,0xff,0xcd,0xf2,0xf0,0x3,0xca,0x7e,0xf,0x6f,0xe0,0x28,0x41,0x2c,0x0,0xf0,0x7,0x80,0x3c,0x1,0x20 -}; - -const uint8_t _A_L0_Url_128x51_3[] = { - 0x1,0x0,0x2a,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7d,0x7e,0x1,0x89,0x4,0x7,0xc4,0x72,0x83,0x5,0x80,0x42,0x1,0xe5,0x2,0xa0,0x3,0xd7,0x75,0x22,0x80,0x83,0xca,0x4,0x1,0x1d,0x7,0xfe,0xe,0xf,0x3f,0x94,0x8a,0xeb,0xe,0xe7,0x49,0x32,0x58,0xe8,0x1f,0x43,0xff,0xf9,0xfe,0x3,0xca,0x7d,0x62,0xca,0xc4,0xa5,0x32,0x5c,0x8d,0x4a,0x5,0xf0,0xff,0xe3,0xbf,0x60,0xf2,0xbd,0x48,0x81,0xe3,0xe9,0x7,0xa5,0xff,0xf7,0xf7,0x7,0x9c,0x8c,0x3e,0x5a,0x4c,0x80,0x3c,0xb7,0xf1,0xdf,0x78,0x3c,0xbf,0x92,0x1b,0xad,0x3b,0x9d,0x98,0xf0,0xf,0xc4,0x1e,0x3e,0xff,0x71,0xfd,0x22,0x5,0xc1,0x0,0x8,0xc,0x7e,0x1d,0xff,0xff,0x79,0x3e,0x80,0xf6,0xe0,0x77,0xef,0xe0,0x11,0x57,0xd0,0x3c,0x77,0xe0,0xfe,0xff,0x87,0xfc,0x1f,0x1f,0x85,0xd0,0xc0,0x68,0x1b,0xff,0xf9,0xbc,0xc0,0x9,0x6,0x28,0x16,0x80,0x1f,0x50,0x37,0x89,0x74,0x2f,0xff,0xff,0x38,0x3e,0xd7,0xe3,0xfe,0xe1,0x83,0xdf,0x87,0x89,0x84,0x3,0xcb,0xf3,0x80,0x7,0xbc,0x8e,0x95,0x18,0x7,0x94,0x1e,0xe,0xf,0x89,0x54,0xe0,0x1e,0x5f,0xf8,0x7d,0xf8,0x1e,0xf1,0xab,0xc0,0x3c,0xe3,0xf7,0xc0,0xfe,0xcf,0xef,0x3,0xfc,0xff,0xdf,0xc1,0xee,0x5f,0x50,0x0,0x83,0xdc,0xfe,0xa2,0x2,0x7,0xf8,0x3d,0xa0,0xeb,0xf2,0x7,0xdf,0xf9,0xbe,0x5e,0x0,0x79,0x4f,0xc1,0xed,0xfc,0x5,0x8,0x25,0x80,0x1e,0x0,0xf0,0x7,0x80,0x24 -}; - - -const uint8_t * const _A_L0_Url_128x51[] = { - - _A_L0_Url_128x51_0, - - _A_L0_Url_128x51_1, - - _A_L0_Url_128x51_2, - - _A_L0_Url_128x51_3, - -}; - - - -const uint8_t L0_Url_128x51_frame_order[] = { 0, 1, 2, 3 }; - -const BubbleAnimation BA_L0_Url_128x51 = { - .icon_animation = { - .width = 128, - .height = 51, - .frame_count = 4, - .frame_rate = 2, - .frames = _A_L0_Url_128x51 - }, - .frame_order = L0_Url_128x51_frame_order, - .passive_frames = 4, - .active_frames = 0, - .active_cooldown = 0, - .active_cycles = 0, - .duration = 0, - - .frame_bubble_sequences = NULL, - .frame_bubble_sequences_count = 0, - -}; - - -const uint8_t _A_L0_NewMail_128x51_0[] = { - 0x1,0x0,0x50,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf0,0x7,0x80,0x3c,0x1,0xe0,0x6,0xf8,0x40,0x40,0x63,0x30,0xfb,0x73,0x61,0x80,0xf7,0xfe,0x41,0xc0,0x63,0x70,0x9b,0x73,0x1,0xf1,0xfe,0x87,0x83,0xf7,0xff,0x1f,0x1,0x8e,0xc3,0xed,0xd9,0x83,0x3,0xdf,0x7e,0xf,0x39,0xb7,0x60,0x1e,0xf8,0xc,0xfc,0xfc,0x9e,0x53,0x7f,0xc1,0x14,0x81,0xeb,0xbf,0x7,0xa4,0xc2,0x6,0xa,0x2f,0xf8,0x0,0xc1,0xe9,0xf6,0x98,0x83,0xcb,0x80,0x1f,0x80,0x2,0xd0,0x11,0x24,0xf,0xc8,0x10,0x14,0xe1,0xf1,0xe0,0x7c,0x41,0xf,0xef,0xc,0xe3,0x6c,0x6c,0x20,0xf2,0x84,0x27,0xde,0x39,0xc7,0x7,0xa4,0x40,0x1e,0x7f,0xd3,0xc9,0x47,0x2c,0xfb,0x30,0x79,0xc8,0x9,0xe6,0xdf,0x3d,0xe0,0x3d,0x68,0x4,0x43,0x2,0x1e,0xb3,0xcd,0xb3,0x90,0x82,0x8b,0x0,0xa,0x29,0x0,0x3c,0xfd,0x93,0x6d,0xb0,0x3c,0xe0,0x2,0xa2,0x88,0x3,0xce,0x98,0xf,0x10,0x51,0x2,0x45,0x0,0x50,0x80,0x7b,0x5b,0xc1,0xe6,0x80,0x28,0x20,0x3c,0xd1,0xec,0x1c,0x10,0x20,0xc0,0x81,0xf6,0x80,0x28,0x8,0x3e,0xe6,0x7,0xe1,0x7,0xe5,0x21,0xa6,0x40,0xfb,0xc2,0x1f,0x84,0x9e,0x9f,0xef,0xf8,0x0,0x4e,0x2,0x6f,0x28,0xc,0x40,0xde,0x63,0x41,0x9,0x91,0xec,0x51,0xe5,0x2,0x84,0x23,0xcf,0x80,0x2d,0x33,0xd8,0xab,0xca,0x9,0x4,0x57,0x98,0x3d,0xc1,0x43,0xf8,0x81,0xb3,0xcf,0x81,0x8,0x16,0xc,0x20,0x1e,0x4e,0xf4,0x7,0x9c,0x62,0x7,0x0,0x8c,0x3,0xc9,0x1c,0x40,0x1,0xa0,0x83,0xcb,0x51,0x32,0xb3,0xce,0x1,0xe4,0xae,0x20,0x0,0xd0,0x81,0xe5,0x48,0xa5,0x64,0x6f,0x0,0xf2,0x67,0x10,0x0,0x68,0x83,0xf3,0xa5,0x7c,0x43,0xe6,0xee,0x20,0x0,0xa8,0xc4,0x1e,0x71,0x11,0xf9,0xa1,0x8e,0x1,0x50,0x7,0x9c,0xca,0xc2,0x5f,0x23,0xb2,0x40,0x2c,0x7,0xf8,0xc0,0x2d,0x48,0x0,0x33,0xf0,0x7c,0x0,0x23,0x80,0xbf,0x50,0x4,0xa,0x10,0x98,0x80,0x6,0x7,0x98,0x3a,0x80,0x1e,0x0,0xf0,0x7,0x80,0x14 -}; - -const uint8_t _A_L0_NewMail_128x51_1[] = { - 0x1,0x0,0x5d,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf0,0x7,0x80,0x3c,0x1,0xe0,0xa,0x98,0x7d,0xb9,0xb0,0xc0,0x7d,0xdc,0x26,0xdc,0xc0,0x7f,0x83,0xe3,0xe1,0x1,0x1,0x8e,0xc3,0xed,0xd9,0x83,0x3,0x13,0xfd,0xf,0x80,0x7f,0x20,0xe0,0xf2,0x9b,0x76,0x1,0xe9,0xc0,0x80,0xdc,0x2,0x46,0x4f,0x19,0xbf,0xe0,0x2a,0x40,0x1,0x9c,0x7f,0xb1,0xf0,0x3f,0xfc,0x7c,0x1e,0x73,0x8,0x18,0x38,0xb0,0x1c,0x7f,0xfd,0xfe,0x79,0xbf,0x7,0x9f,0xda,0x62,0xf,0x3b,0x87,0xf3,0xff,0xff,0xe3,0xe7,0xe7,0xe6,0x68,0xe7,0x3,0x84,0x0,0x3b,0xf0,0x7c,0x60,0x1,0xc6,0xf,0xae,0x0,0x3e,0x21,0x9c,0x6d,0x8d,0x84,0xa,0x34,0x0,0x7c,0x47,0x38,0xe0,0xf4,0x41,0xa4,0x3e,0x3c,0xf,0x2b,0x3e,0xcc,0x1e,0x70,0x40,0x79,0x9f,0xcf,0x78,0xf,0x58,0x42,0xc9,0xa0,0x1a,0xcf,0x36,0xce,0x42,0xf,0x28,0x80,0x3c,0xff,0xaa,0x92,0xf6,0x4d,0xb6,0xc0,0xf3,0xd0,0x13,0x8d,0xbe,0x74,0xc0,0x78,0x81,0x4a,0x81,0x40,0xf,0x10,0x11,0x1,0xe5,0x6f,0x5,0x16,0x0,0x14,0x52,0x0,0x79,0x80,0x14,0x12,0x22,0x42,0x88,0x3,0xef,0xfc,0x3f,0x18,0x78,0x3e,0xf0,0x82,0xe1,0x82,0x3,0xee,0x90,0x3,0x18,0x10,0x3e,0xe6,0xe,0x31,0x80,0x83,0xcc,0x6e,0x5f,0xf2,0x58,0x82,0x45,0x20,0x40,0xf3,0xa,0x8,0x4c,0xa0,0x40,0xf2,0x58,0x10,0xbc,0xf8,0x2,0xd3,0x66,0x8,0x24,0x5a,0x4,0x4f,0x30,0x7c,0x8,0xc4,0x44,0x20,0xf3,0x84,0x2,0x6,0x10,0xf,0x34,0x7b,0x70,0x23,0x10,0x38,0x4,0x60,0x1e,0x4a,0xf7,0xe0,0x6a,0x26,0x56,0x79,0xc0,0x3c,0x99,0xef,0xc0,0xa4,0x52,0xb2,0x37,0x80,0x79,0x48,0x1,0xe5,0x80,0x1f,0xa5,0x2b,0xe2,0x1f,0x33,0xf1,0x0,0x6,0x82,0xf,0x48,0x88,0xfc,0xcf,0xc4,0x0,0x1a,0x10,0x3c,0xe6,0x56,0x12,0xf9,0x9f,0x88,0x0,0x34,0x43,0xfc,0x9f,0x88,0x0,0x2d,0x31,0x7,0xc2,0xd8,0xe0,0x15,0x0,0x79,0x2f,0xd4,0x2c,0x90,0xb,0x1,0x8c,0x9b,0xc4,0xdf,0x20,0x32,0x7f,0xe7,0xe1,0x32,0x3,0x98,0x71,0x0,0x1e,0x0,0xf0,0x7,0x80,0x2c -}; - -const uint8_t _A_L0_NewMail_128x51_2[] = { - 0x1,0x0,0x79,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf0,0x1,0xfc,0x20,0x20,0xfd,0x84,0x40,0x81,0xfb,0xf6,0x86,0x83,0xf7,0xf3,0x13,0x3,0x24,0xc3,0xed,0xcd,0x86,0x1,0xcf,0x81,0xfe,0xb7,0x83,0xd2,0xe1,0x36,0xe6,0x3,0xd2,0x41,0xff,0xcf,0x83,0xf3,0xb1,0xff,0xbf,0xc0,0xc0,0xe7,0xb0,0xfb,0x76,0x60,0xc0,0x73,0xf2,0x7f,0xff,0xf0,0x40,0x7a,0x4d,0xbb,0x0,0xf4,0xfd,0x83,0xc6,0x36,0x82,0x39,0x84,0xdf,0xf1,0x7,0x7,0x16,0x3,0xf8,0xf,0x19,0x3f,0xf0,0x12,0x40,0xf1,0x98,0xd,0xcc,0x1c,0x40,0x2,0x87,0x9b,0xce,0x62,0xf,0x31,0xda,0x7f,0xe3,0xe8,0xd8,0x7,0xa6,0xfc,0x1f,0x25,0x33,0xc0,0x67,0xe7,0xe0,0xf8,0x82,0x83,0xcf,0x7e,0xf,0x28,0x67,0x1b,0x63,0x61,0x5,0x16,0x1c,0x9a,0x5b,0xf0,0x79,0xc7,0x38,0xe0,0xf3,0xe0,0x1c,0xd0,0x1e,0x96,0x7d,0x98,0x3c,0xa8,0x0,0xf8,0xde,0x3,0xd5,0x46,0x90,0xf8,0xf0,0xc,0x75,0x9e,0x6d,0x9c,0x84,0x1e,0x58,0x41,0xf9,0x4f,0xcf,0xe7,0xec,0x9b,0x6d,0x81,0xe7,0x8,0xf,0x9f,0xf9,0x3e,0x54,0xc0,0x78,0xb1,0x4a,0x81,0x10,0x7,0x9f,0xf4,0x8a,0x40,0xf2,0xb7,0x83,0xca,0x40,0x4f,0x36,0xf9,0x80,0x16,0x81,0xc0,0x1f,0x95,0xfe,0x80,0x9e,0x8a,0x6,0x0,0x8,0x52,0x0,0x7d,0x40,0x5,0x45,0x10,0x7,0xdc,0x8,0xd8,0x30,0x80,0x7d,0xff,0x20,0x1e,0x8,0x38,0x3c,0xff,0xc4,0x82,0x15,0x88,0x24,0x69,0x0,0x31,0x81,0x3,0xcb,0x0,0x62,0x38,0x10,0x3c,0xa6,0x0,0xa2,0x7,0x97,0x0,0x5a,0x70,0x40,0x79,0x24,0x8,0x1f,0x8b,0x2,0x17,0x9f,0x2,0x10,0x2c,0x18,0x40,0x3c,0xc0,0x62,0x2,0x10,0x79,0xc6,0x20,0x70,0x8,0xc0,0x3c,0xc2,0xc2,0x17,0x10,0x79,0xea,0x26,0x56,0x79,0xc0,0x3c,0xd1,0xed,0xc0,0xa4,0x52,0xb2,0x37,0x80,0x79,0x2b,0xdc,0x7e,0x34,0xaf,0x88,0x7c,0xd1,0x46,0x4,0x30,0x79,0x44,0x47,0xe6,0xef,0x40,0x7a,0x4c,0xac,0x25,0xf3,0x3f,0x10,0x0,0x68,0x27,0xf9,0x3f,0x10,0x0,0x68,0x40,0xf9,0x3f,0x10,0x0,0x68,0x80,0xf2,0x5f,0xb1,0xf8,0x80,0x2,0xd3,0x12,0x18,0xb7,0x89,0xbe,0x61,0x63,0x80,0x54,0x0,0x64,0xf,0x31,0xb3,0x40,0x2c,0x0,0x54,0x0,0x18,0x99,0x3f,0xf3,0xf0,0x7c,0x0,0x3c,0x1,0xc0 -}; - -const uint8_t _A_L0_NewMail_128x51_3[] = { - 0x1,0x0,0x77,0x1,0x0,0x1f,0xe2,0x6,0xf,0xd8,0x24,0x10,0x1f,0xbf,0xa8,0x58,0x3f,0x7f,0xb1,0x70,0x76,0x60,0x3f,0xd2,0xf0,0x7e,0x50,0x3f,0xf5,0xf0,0x7e,0x68,0x3f,0xfb,0xf0,0x7e,0x74,0x3f,0xf7,0xf8,0x8,0x1c,0xe6,0x1f,0x6e,0x6c,0x30,0xc,0x5f,0xcf,0xf8,0x0,0xa0,0xe0,0x82,0xb8,0x4d,0xb9,0x80,0xf3,0x3e,0x20,0x10,0xc1,0xff,0xb0,0xfb,0x76,0x60,0xc0,0xfc,0x9b,0x76,0x1,0xf9,0x30,0x9b,0xfe,0x8,0xc7,0x84,0x27,0x14,0xff,0xe8,0x61,0x20,0x78,0xcc,0x1b,0x6,0x1f,0x4f,0xe0,0x64,0x8d,0xe3,0x31,0x7,0xc7,0xfa,0x1e,0xed,0x90,0x21,0xff,0xe3,0xe0,0xf8,0x1f,0xa6,0xfc,0x1f,0x26,0x33,0xc0,0x67,0xe7,0xe0,0x41,0x86,0x71,0xb6,0x36,0x10,0x59,0x41,0x41,0xe7,0xbf,0x7,0x94,0x73,0x8e,0xf,0x3c,0x0,0x7d,0x1,0xe9,0x67,0xd9,0x83,0xcb,0x81,0x87,0x1f,0x96,0xfc,0x1e,0x7b,0xc0,0x7a,0x50,0x12,0x66,0x1f,0x4d,0x67,0x9b,0x67,0x21,0x7,0x90,0xbc,0xe0,0x10,0xf8,0xf0,0xc,0x7d,0x93,0x6d,0xb0,0x3c,0xcf,0xf1,0x4c,0x7,0x8a,0xd4,0xa8,0x18,0x83,0xf9,0xa7,0xcc,0x1e,0x56,0xf0,0x79,0x44,0x3,0xe7,0xfd,0x22,0x98,0x1,0x28,0x12,0x2,0x79,0xfc,0x5,0x24,0xf,0x6a,0x0,0x11,0xc1,0xed,0x80,0x1f,0x98,0x3e,0xa0,0x2,0xa2,0x88,0x3,0xee,0x4,0x6c,0x18,0x40,0x3c,0xff,0xc2,0x82,0xd,0x88,0x24,0x70,0x90,0x9,0x4,0x10,0x1e,0x58,0x2,0x91,0xc0,0x81,0xe5,0x48,0x1,0x8c,0x8,0x1e,0x5c,0x1,0x69,0xa7,0x4,0x12,0x33,0x0,0xd1,0x3,0xed,0x20,0x40,0xf4,0x84,0xb,0x6,0x10,0xf,0x38,0x40,0xd8,0x81,0xe7,0x18,0x81,0xc0,0x23,0x0,0xf3,0x68,0x11,0x3c,0xf8,0x1a,0x89,0x95,0x9e,0x70,0xf,0x31,0x30,0x88,0x84,0x1e,0x74,0x8a,0x56,0x46,0xf0,0xf,0x34,0x7b,0xf,0xc6,0x95,0xf1,0xf,0x9e,0x0,0xac,0x52,0x0,0x7a,0xc4,0x47,0xe6,0xcf,0x70,0x78,0xcc,0xac,0x25,0xf3,0x77,0xa1,0xfe,0x8f,0xc4,0x0,0x1a,0x8,0x3e,0x4f,0xc4,0x0,0x1a,0x10,0x3c,0x97,0xec,0x7e,0x20,0x0,0xd1,0x6,0x64,0xde,0x26,0xf9,0x9f,0x88,0x0,0x2d,0x31,0x0,0x8,0x3c,0xcb,0x44,0x26,0x38,0x5,0x40,0x8,0x60,0x4,0x23,0x24,0x2,0xc0,0xf,0x81,0xb2,0x7f,0xe7,0xe0,0xf8,0x0,0x70 -}; - - -const uint8_t * const _A_L0_NewMail_128x51[] = { - - _A_L0_NewMail_128x51_0, - - _A_L0_NewMail_128x51_1, - - _A_L0_NewMail_128x51_2, - - _A_L0_NewMail_128x51_3, - -}; - - - -const uint8_t L0_NewMail_128x51_frame_order[] = { 0, 1, 2, 3, 2, 1 }; - -const BubbleAnimation BA_L0_NewMail_128x51 = { - .icon_animation = { - .width = 128, - .height = 51, - .frame_count = 4, - .frame_rate = 2, - .frames = _A_L0_NewMail_128x51 - }, - .frame_order = L0_NewMail_128x51_frame_order, - .passive_frames = 6, - .active_frames = 0, - .active_cooldown = 0, - .active_cycles = 0, - .duration = 0, - - .frame_bubble_sequences = NULL, - .frame_bubble_sequences_count = 0, - -}; - - -const StorageAnimation dolphin_blocking[] = { - - { - .animation = &BA_L0_NoDb_128x51, - .manifest_info = { - .name = "L0_NoDb_128x51", - .min_butthurt = 0, - .max_butthurt = 0, - .min_level = 0, - .max_level = 0, - .weight = 0, - } - }, - - { - .animation = &BA_L0_SdBad_128x51, - .manifest_info = { - .name = "L0_SdBad_128x51", - .min_butthurt = 0, - .max_butthurt = 0, - .min_level = 0, - .max_level = 0, - .weight = 0, - } - }, - - { - .animation = &BA_L0_SdOk_128x51, - .manifest_info = { - .name = "L0_SdOk_128x51", - .min_butthurt = 0, - .max_butthurt = 0, - .min_level = 0, - .max_level = 0, - .weight = 0, - } - }, - - { - .animation = &BA_L0_Url_128x51, - .manifest_info = { - .name = "L0_Url_128x51", - .min_butthurt = 0, - .max_butthurt = 0, - .min_level = 0, - .max_level = 0, - .weight = 0, - } - }, - - { - .animation = &BA_L0_NewMail_128x51, - .manifest_info = { - .name = "L0_NewMail_128x51", - .min_butthurt = 0, - .max_butthurt = 0, - .min_level = 0, - .max_level = 0, - .weight = 0, - } - }, - -}; - -const size_t dolphin_blocking_size = COUNT_OF(dolphin_blocking); diff --git a/assets/compiled/assets_dolphin_blocking.h b/assets/compiled/assets_dolphin_blocking.h deleted file mode 100644 index ba3996ca..00000000 --- a/assets/compiled/assets_dolphin_blocking.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include -#include - -extern const StorageAnimation dolphin_blocking[]; -extern const size_t dolphin_blocking_size; diff --git a/assets/compiled/assets_dolphin_internal.c b/assets/compiled/assets_dolphin_internal.c deleted file mode 100644 index 8400052c..00000000 --- a/assets/compiled/assets_dolphin_internal.c +++ /dev/null @@ -1,330 +0,0 @@ -#include -#include -#include -#include - - - -const uint8_t _A_L1_Tv_128x47_0[] = { - 0x1,0x0,0xca,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x66,0x33,0x30,0x50,0x81,0x88,0x1e,0xd0,0x50,0x19,0xa,0x8a,0x8,0x24,0x21,0x31,0x40,0x38,0x0,0x81,0x2d,0x20,0x8,0x41,0xeb,0x38,0x7,0xc0,0xb4,0x46,0xc4,0x78,0x10,0x79,0x80,0xc8,0x64,0x20,0xf4,0x86,0x2,0xcc,0x1e,0xa6,0x21,0xe8,0x40,0x21,0xe5,0x61,0x82,0x60,0x2f,0xe0,0xf7,0xa8,0x78,0x66,0x7,0x61,0x81,0x58,0x11,0xa3,0x2,0xc0,0x43,0xce,0x47,0x48,0x8f,0x25,0x8a,0x5,0x30,0x80,0x41,0x90,0x64,0xf,0x43,0xf9,0xc0,0x7f,0x5,0xb1,0x81,0x78,0x27,0xe0,0xf1,0xff,0xff,0xc7,0x2,0xba,0x20,0x30,0xc0,0x7e,0x10,0x3f,0x4,0x9f,0xc1,0x1f,0x22,0x8e,0x10,0x1e,0x56,0x1,0x39,0x2,0xc6,0xc1,0x26,0xf0,0x48,0xc4,0xc3,0x82,0x7,0x94,0x78,0x1e,0x5c,0x8,0x1f,0x2,0x27,0xc0,0xa0,0x8d,0x8a,0x7,0x0,0xf0,0x38,0x8a,0x8,0x55,0x12,0xf8,0xf0,0x11,0xc3,0x10,0x80,0xa3,0x44,0xec,0x41,0x71,0x30,0x8b,0x1c,0x81,0xe7,0xf0,0x9f,0xae,0x48,0x1e,0x20,0x43,0x7,0x96,0x80,0xa,0x34,0x0,0x51,0xc4,0x16,0x46,0xf,0xa9,0x7,0xd0,0x1e,0xbf,0x2,0x58,0x83,0xd6,0x18,0x5f,0x10,0x79,0xff,0x20,0xe0,0xf1,0x27,0x9d,0x2,0x9,0x7c,0x63,0x88,0x3c,0xbf,0xd0,0xf0,0x7a,0xe0,0x21,0x6,0xe1,0x16,0xe,0xf,0xff,0xfd,0xfb,0xaa,0xc7,0xfe,0xa6,0x10,0x78,0x9b,0xce,0x19,0x9c,0xff,0xa3,0x4,0x1e,0x51,0xd0,0x59,0x70,0x52,0xe2,0xa4,0x1d,0xc0,0x30,0x80,0x3,0x3f,0xf,0x97,0xe0,0x54,0x22,0xf1,0x45,0x88,0x3d,0x39,0xe0,0xf1,0xc0,0x15,0x87,0xff,0x3,0x26,0x8f,0x81,0xf8,0x64,0x61,0x7,0x8d,0xc0,0xa,0x3f,0xc0,0xa0,0x8f,0x10,0x0,0x3f,0x30,0x78,0xc3,0x82,0xe7,0x40,0x7,0xb7,0xd2,0x7f,0xf0,0xe0,0x83,0xd7,0xf8,0xe,0x3b,0xff,0xdf,0xbf,0xf,0xd3,0x18,0x8c,0x1e,0x3c,0x30,0x79,0xe7,0xfe,0xf1,0xfd,0x85,0xe6,0xfc,0xb3,0x3c,0x6,0x0,0x1e,0x7e,0xf0,0x78,0xd3,0xe9,0x39,0x26,0x38,0x83,0xc6,0x80,0xf,0x4f,0x9f,0xdf,0x3e,0x5,0x23,0xe8,0x83,0xc4,0x40,0x24,0x63,0xfe,0x3,0xc4,0xa,0x51,0x80,0x7a,0x7,0xcd,0x84,0x31,0xf1,0x61,0x47,0x1,0xe5,0x10,0x7,0xbc,0x8,0x18,0x31,0xe0,0x10,0xd8,0x1,0xf1,0x4,0x6,0x8,0xfc,0xae,0xf,0x31,0xf3,0x83,0xd4,0x78,0x3c,0x6,0x99,0x6f,0x1,0xe3,0xc3,0xb,0xf,0xe0,0x1e,0x56,0x6,0x18,0xdf,0xc1,0xe3,0x3f,0x83,0x83,0xc7,0x5f,0x32,0xfd,0x83,0xc5,0x6a,0x8f,0x72,0x68,0x8f,0x9c,0x3e,0xae,0x64,0x80,0x4e,0x1,0xe2,0x4f,0x60,0x7a,0xc8,0x1,0xfe,0x2f,0x20,0x7f,0x0 -}; - -const uint8_t _A_L1_Tv_128x47_1[] = { - 0x1,0x0,0xcc,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x9c,0xaf,0xe0,0xf9,0x10,0x88,0x28,0x6c,0x8,0xd1,0x81,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xe3,0x30,0x41,0x8a,0xdc,0x81,0xea,0x1,0x10,0x50,0xfe,0x0,0xa3,0x2,0xf0,0x4f,0xc1,0xe3,0xff,0x0,0x14,0x3e,0x1,0xfe,0x2,0xc,0x7,0xe1,0x3,0xf0,0x49,0xfc,0x11,0xf1,0x50,0xc1,0x3c,0xe,0x61,0x8,0x88,0x88,0x41,0x63,0x20,0x7,0x8c,0xfc,0x4c,0x30,0x68,0xe1,0x70,0x60,0x60,0xf2,0xe0,0x40,0xf8,0x11,0x3e,0x5,0x1c,0x1e,0x31,0xa0,0x60,0xf8,0xf,0xa6,0x75,0x12,0xf8,0xf0,0x30,0x65,0xc1,0xf2,0x82,0xc6,0xf0,0xad,0x33,0x8,0xae,0x8,0x1e,0x50,0x50,0x30,0xc7,0x81,0xe6,0xa3,0x30,0x79,0x68,0x12,0xc4,0x50,0x14,0xd1,0x1,0xc8,0x1e,0x81,0x72,0x27,0x12,0x28,0x7e,0x80,0xf5,0xf8,0x44,0x60,0x10,0xe0,0xf9,0xc8,0x21,0x85,0xf1,0x7,0x9f,0xf3,0xcf,0xc0,0x84,0xc1,0x81,0xe5,0x40,0x82,0x5f,0x26,0x10,0x10,0x79,0x7f,0xa1,0xf3,0xf8,0x80,0x3c,0xf0,0x10,0x83,0x70,0x8b,0x7,0x3f,0xff,0xfe,0xfd,0xd6,0x24,0xa6,0x10,0x78,0x9b,0xce,0x19,0xbc,0xff,0xa3,0x4,0x1e,0x51,0xd0,0x59,0x70,0x54,0x87,0xf8,0x67,0x9f,0xfe,0x7e,0x1f,0x2f,0xc6,0xc,0x4a,0x4d,0x41,0x7,0xa7,0x3c,0x12,0x38,0x3,0x18,0xff,0xe0,0xf8,0x5,0xca,0x0,0x7,0xe0,0xf,0x1b,0x80,0x14,0x7f,0x90,0x10,0x79,0x7,0xd3,0xe6,0xf,0x18,0x70,0x5c,0xe8,0x0,0xf6,0xfa,0x4f,0xfe,0x1c,0x10,0x7a,0xff,0x1,0xc7,0x7f,0xfb,0xf7,0xe1,0xfa,0x63,0x11,0x83,0xc4,0x3c,0x99,0xff,0xbc,0x7f,0x61,0x79,0xbf,0x2c,0xcf,0x1,0x87,0x7,0x9f,0xbc,0x1e,0x34,0xfa,0x4e,0x4a,0x2,0xf,0x2e,0x6,0x4,0x9c,0x9f,0x75,0x30,0x80,0x8,0x1e,0x5e,0x3,0x8,0x80,0xb,0xf8,0xf,0x10,0x29,0x7e,0x1,0xe5,0x60,0xc0,0x6,0xd,0x84,0x31,0xf1,0x61,0x7f,0x1,0xe5,0x30,0x7,0xbc,0x8,0x18,0x25,0x2,0xb0,0x3,0xe2,0x8,0xc,0x1b,0xf8,0x8,0x6e,0x11,0x8c,0x7,0x9c,0x1e,0xb1,0x88,0x7,0x0,0x9e,0x5b,0xc0,0x78,0xf0,0xe1,0xe4,0x81,0x7,0x95,0x81,0x86,0x3f,0xf7,0x78,0xcf,0xe1,0xe0,0xf1,0xd7,0xcc,0xbf,0x60,0xf1,0x4b,0x23,0xdc,0x9c,0xc3,0xe7,0xf,0xab,0x99,0x20,0x13,0x80,0x78,0x93,0xd8,0x1e,0xb2,0x0,0x7f,0x8b,0xc8,0x1f,0xc0 -}; - -const uint8_t _A_L1_Tv_128x47_2[] = { - 0x1,0x0,0xc1,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x66,0x33,0x30,0x50,0x81,0x88,0x1e,0xd0,0x50,0x19,0xa,0x8a,0x8,0x24,0x21,0x31,0x40,0x38,0x0,0x81,0x2d,0x20,0x8,0x41,0xeb,0x38,0x7,0xc0,0xb4,0x46,0xc4,0x78,0x10,0x79,0x80,0xc8,0x64,0x20,0xf4,0x86,0x2,0xcc,0x1e,0xa6,0x21,0xe8,0x40,0x21,0xe5,0x61,0x7,0xd5,0x43,0xc3,0x30,0x3b,0x9,0xbc,0xe0,0x58,0x8,0x79,0xc8,0xe9,0x11,0xe4,0xb1,0x3,0xd1,0x4,0xb4,0x83,0xf9,0xa8,0xce,0x5,0xe0,0x9f,0x83,0xc7,0xff,0xff,0xbf,0xae,0x8c,0xc,0x20,0x1,0x81,0xf8,0x24,0xfe,0x8,0xf9,0x14,0x70,0x80,0xf2,0xb0,0x8,0xce,0x3d,0x60,0x93,0x78,0x24,0x68,0x21,0xc1,0x2,0x8c,0x1e,0x70,0x3e,0x4,0x4f,0x81,0x41,0x7,0x8c,0xa,0x7,0x0,0xf0,0xf,0x8c,0xaa,0x25,0xf1,0xe0,0x23,0x86,0x21,0x1,0x46,0x89,0xd8,0x80,0x3,0x30,0x9,0x98,0x3c,0xfe,0x13,0xf5,0xc9,0x40,0x3f,0x10,0x90,0x7a,0xe8,0x0,0xa3,0x40,0x7,0x9c,0x1e,0xc,0xf,0xc1,0xe8,0xfd,0x1,0xeb,0xf0,0x25,0x88,0x3c,0xd1,0x23,0xfc,0x2f,0x88,0x3c,0xff,0x90,0x70,0x78,0x93,0xc8,0x4,0x3e,0xb,0xfb,0x1c,0x41,0xe5,0xfe,0x87,0x83,0xdb,0x81,0xe1,0x4,0x8f,0xc3,0x7,0xff,0xfe,0xfd,0xd5,0x44,0xa6,0x11,0x90,0xce,0x3e,0x1,0x51,0x86,0x67,0x3f,0xe2,0x71,0x7,0x94,0x74,0x1e,0x30,0x8f,0xe0,0x78,0x5a,0x43,0xb8,0x64,0x1f,0xfe,0x7e,0x1f,0x2f,0xc4,0x4e,0x1,0xe,0x73,0xf,0xc0,0x1e,0x9c,0xf0,0x79,0x44,0x3c,0x1c,0x8,0x19,0x34,0x7c,0xa,0x93,0x23,0x8,0x3c,0xdf,0x42,0xf,0x30,0xfa,0x7c,0xc1,0xe3,0x1e,0x40,0x9,0x3c,0x68,0x0,0xf6,0xfa,0x4f,0xfe,0x13,0x99,0x30,0x9c,0x81,0xe3,0xfc,0x7,0x1d,0xff,0xef,0xdf,0x87,0xfd,0xa7,0xe0,0xf4,0xe1,0x83,0xcf,0x3f,0xf7,0x8f,0xec,0x2f,0x37,0xe0,0x79,0x48,0x30,0x18,0x0,0x79,0xfb,0xc1,0xe3,0x4f,0xa4,0xe6,0x98,0xe2,0xf,0x1a,0x0,0x3d,0x3e,0x7f,0x7c,0xf8,0x14,0x91,0xc5,0x20,0x10,0x9,0xb8,0xff,0x80,0xf1,0x2,0x94,0x60,0x1e,0x81,0xf3,0x61,0xc,0x7c,0x58,0x51,0xc0,0x79,0x44,0x1,0xef,0x2,0x6,0xc,0x78,0x4,0x36,0x0,0x7c,0x41,0x1,0x82,0x3f,0x2b,0x84,0x23,0x1,0xe7,0x7,0xa8,0xf0,0x78,0xa,0x31,0x80,0x6f,0x1,0xe3,0xc3,0xb,0xf,0xe0,0x1e,0x56,0x5,0x68,0xdf,0xc1,0xe3,0x3f,0x83,0x83,0xc7,0x5f,0x32,0xfd,0x83,0xc5,0x6a,0x8f,0x72,0x80,0xb,0xc4,0x3e,0xae,0x64,0x80,0x4e,0x1,0xe2,0x4f,0x60,0x7a,0xb8,0xc4,0x1f,0xe5,0xf7,0x7,0xc0 -}; - -const uint8_t _A_L1_Tv_128x47_3[] = { - 0x1,0x0,0xc0,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x3f,0x44,0x22,0xa,0x23,0x61,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xea,0x82,0x50,0x78,0x80,0x45,0x84,0x90,0x2f,0x4,0xfc,0x1e,0x3f,0xf0,0x1,0x43,0xe0,0x1f,0xe0,0x31,0xc0,0xfc,0x12,0x7f,0x4,0x7c,0x54,0x30,0x4f,0x3,0x98,0x42,0x22,0x0,0x28,0xf4,0x80,0x1e,0x33,0xf1,0x60,0xc1,0xa3,0x87,0x41,0x81,0x83,0xce,0x7,0xc0,0x89,0xf0,0x28,0xe0,0xf1,0x8d,0x3,0x7,0xc0,0xe,0x33,0xa8,0x97,0xc7,0x81,0x83,0x2e,0xf,0x94,0x14,0x37,0x80,0x79,0xcc,0x2,0x66,0xf,0x28,0x28,0xe4,0x97,0xcc,0xf,0x3d,0x1,0xec,0x8a,0x2,0x9e,0x43,0x68,0x83,0xcc,0x2e,0x44,0xe4,0xf2,0x2e,0x4c,0x1e,0x3f,0x8,0x8c,0x2,0x1c,0x1f,0x39,0xe5,0xf2,0xd,0x18,0x7,0x9f,0xf3,0xcf,0xc0,0x84,0xc1,0x81,0xe5,0xc2,0x87,0xf3,0x11,0x82,0xf,0x2f,0xf4,0x3e,0x7f,0x10,0x7,0x9c,0x4,0x42,0x22,0xf1,0xf8,0x67,0xff,0xff,0xdf,0xba,0xa8,0x83,0x23,0x80,0x8,0x8c,0x38,0x9e,0x30,0xcd,0xe7,0xfd,0x18,0x20,0xf2,0x8e,0x83,0xcc,0x8a,0x50,0x2f,0xc3,0x20,0xff,0xf3,0xf0,0xf9,0xe0,0x4,0xa5,0x1,0xf8,0x3,0xd3,0x9e,0xf,0x31,0x38,0xc1,0xc0,0x84,0x79,0x32,0x30,0x83,0xc6,0xe1,0x1,0xfe,0x7f,0x20,0x21,0x43,0x0,0x1f,0xcc,0x1e,0x30,0xef,0xf3,0xa8,0x60,0x14,0x0,0x7b,0x7d,0x27,0xff,0xe,0x8,0x9c,0xc1,0xe3,0xfc,0x7,0x1d,0xff,0xef,0xdf,0x87,0xe9,0x8c,0x42,0xf,0x30,0xf2,0x67,0xfe,0xf1,0xfd,0x85,0xe6,0xfc,0xf,0x29,0x6,0x3,0xe,0xf,0x3f,0x78,0x3c,0x69,0xf4,0x9c,0x92,0x80,0x41,0xe3,0xc0,0xc0,0x93,0x93,0xee,0xa6,0x10,0x1,0x3,0xcb,0xc0,0x96,0x20,0x0,0xff,0x1,0xe2,0x5,0x2f,0xc0,0x3c,0xac,0x9,0x41,0x0,0x13,0x8,0x63,0xe2,0xc2,0xfe,0x3,0xca,0x60,0xf,0x78,0x10,0x30,0x4a,0x5,0x60,0x7,0xc4,0x10,0x18,0x37,0xf0,0x10,0xdc,0x23,0x18,0xf,0x38,0x3d,0x63,0x10,0xe,0x1,0x3c,0xb7,0x80,0xf1,0xe1,0xc3,0xc9,0x2,0xf,0x2b,0x3,0xc,0x7f,0xf0,0x38,0x4,0xfe,0x1e,0xf,0x1d,0x7c,0xcb,0xf6,0xf,0x14,0xb2,0x3d,0xc9,0xcc,0x3e,0x70,0xfa,0xb9,0x92,0x1,0x38,0x7,0x89,0x3d,0x81,0xeb,0x20,0x7,0xf8,0xbc,0x81,0xfc -}; - -const uint8_t _A_L1_Tv_128x47_4[] = { - 0x1,0x0,0xcb,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x9c,0xaf,0xe0,0xf9,0x10,0x88,0x28,0x6c,0x8,0xd1,0x81,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xe3,0x30,0x41,0x8a,0xdc,0x81,0xea,0x1,0x10,0x50,0xfe,0x0,0xa3,0x2,0xf0,0x4f,0xc1,0xe3,0xff,0x0,0x14,0x3e,0x1,0xfe,0x2,0xc,0x7,0xe1,0x3,0xf0,0x49,0xfc,0x11,0xf1,0x50,0xc1,0x3c,0xe,0x61,0x61,0x10,0x74,0x63,0xf6,0x9,0x37,0x82,0x46,0x26,0x18,0x34,0x71,0x64,0x90,0x2e,0x4,0xf,0x81,0x13,0xe0,0x50,0x41,0xe3,0x1a,0x81,0x97,0x4,0xfa,0x67,0x51,0x2f,0x8f,0x0,0x32,0x31,0xf,0x28,0x2c,0x63,0xa,0xd3,0x30,0x8a,0xe0,0x81,0xe5,0x5,0x77,0x2c,0x20,0xca,0x25,0xd1,0x7,0x96,0x81,0x2c,0x44,0xe2,0xb,0x88,0x1c,0x55,0x24,0xf,0x25,0xd9,0x3,0xce,0x41,0xf4,0x1b,0x10,0x3c,0xbe,0x11,0x18,0x4,0x38,0x1e,0x90,0xc8,0x7c,0x58,0x1e,0x7f,0xcf,0x3f,0x2,0x12,0xa9,0x28,0x5,0x2,0x8,0x19,0x20,0x79,0x7f,0xa1,0xf3,0xf8,0x80,0x3c,0xf0,0x4,0xf3,0xf8,0x60,0xff,0xff,0xdf,0xba,0xc4,0x94,0xc2,0xf,0x13,0x79,0xc3,0x33,0x9f,0xf8,0x7,0x80,0x1e,0x51,0xd0,0x59,0x70,0x52,0xe2,0xa4,0x1d,0xc3,0x3c,0xff,0xf3,0xf0,0xf9,0x7e,0x5,0x42,0xd7,0x16,0xa0,0x83,0xd3,0x9e,0xf,0x1c,0x3,0x50,0x7f,0xf0,0x32,0x68,0xf8,0x5,0x4,0x0,0x1f,0x80,0x3c,0x6e,0x0,0x51,0xfe,0x40,0x41,0xe4,0x1f,0x4f,0x98,0x3c,0x61,0xc1,0x73,0xa0,0x3,0xdb,0xe9,0x3f,0xf8,0x70,0x41,0xeb,0xfc,0x7,0x1d,0xff,0xef,0xdf,0x87,0xe9,0x8c,0x46,0xf,0x1e,0x18,0x3c,0xf3,0xff,0x78,0xfe,0xc2,0xf3,0x7e,0x59,0x9e,0x3,0x0,0xf,0x3f,0x78,0x3c,0x69,0xf4,0x9c,0x93,0x10,0xa4,0x14,0x0,0x7a,0x7c,0xfe,0xf9,0xf0,0x29,0x1f,0x44,0x1e,0x22,0x1,0x23,0x1f,0xf0,0x1e,0x20,0x52,0x76,0x88,0x3c,0xc3,0xe6,0xc2,0x18,0xf8,0xb0,0xa3,0x80,0xf2,0x88,0x3,0xdd,0xc2,0x51,0xe0,0x10,0xd8,0x1,0xf1,0x4,0x6,0x8,0xfc,0xae,0x10,0x8c,0x7,0x9c,0x1e,0xa3,0xc1,0xe0,0x34,0xcb,0x78,0xf,0x1e,0x18,0x58,0x7f,0x0,0xf2,0xb0,0x30,0xc6,0xfe,0xf,0x19,0xfc,0x1c,0x1e,0x3a,0xf9,0x97,0xec,0x1e,0x2b,0x54,0x7b,0x93,0x98,0x7c,0xe1,0xf5,0x73,0x24,0x2,0x70,0xf,0x12,0x7b,0x3,0xd6,0x40,0xf,0xf1,0x79,0x3,0xf8 -}; - -const uint8_t _A_L1_Tv_128x47_5[] = { - 0x1,0x0,0xd1,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x9c,0xaf,0xe0,0xf9,0x10,0x88,0x28,0x6c,0x8,0xd1,0x81,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xe3,0x30,0x41,0x8a,0xdc,0x81,0xea,0x1,0x10,0x50,0xfe,0x0,0xa3,0x2,0xf0,0x4f,0xc1,0xe3,0xff,0x0,0x14,0x3e,0x1,0xfe,0x2,0xc,0x7,0xe1,0x3,0xf0,0x49,0xfc,0x11,0xf1,0x50,0xc1,0x3c,0xe,0x61,0x8,0x88,0x88,0x41,0x63,0x20,0x7,0x8c,0xfc,0x4c,0x30,0x68,0xe1,0x70,0x60,0x60,0xf2,0xe0,0x40,0xf8,0x11,0x3e,0x5,0x1c,0x1e,0x31,0xa0,0x60,0xf8,0xf,0xa6,0x75,0x12,0xf8,0xf0,0x30,0x65,0xc1,0xf2,0x82,0xc6,0xf0,0xad,0x33,0x8,0xae,0x8,0x1e,0x50,0x50,0x30,0xc7,0x81,0xe6,0xa3,0x30,0x79,0x68,0x12,0xc4,0x50,0x14,0xd1,0x1,0xc8,0x1e,0x81,0x72,0x27,0x12,0x28,0x7e,0x9f,0x3,0xe8,0x83,0xcb,0xe1,0x11,0x80,0x43,0x83,0xe7,0x20,0x86,0x43,0xe2,0x60,0xf3,0xfe,0x79,0xf8,0x10,0x98,0x30,0x3c,0xa8,0x2,0xf1,0x3c,0x8,0x3c,0xbf,0xd0,0xf9,0xfc,0x40,0x1e,0x78,0x6,0x39,0xfc,0x33,0xff,0xff,0xef,0xdd,0x62,0x4a,0x61,0x7,0x89,0xbc,0x41,0xe3,0xc,0xde,0x7f,0xd1,0x82,0xf,0x28,0xe8,0x80,0xb8,0x30,0x32,0x78,0xc0,0xbf,0xc,0xf3,0xff,0xcf,0xc3,0xe5,0xf8,0xc1,0x89,0x49,0xa8,0x20,0xf4,0xe7,0x82,0x47,0x0,0x63,0x1f,0xfc,0x1f,0x0,0xb9,0x40,0x0,0xfc,0x1,0xe3,0x70,0x2,0x8f,0xf2,0x2,0xf,0x20,0xfa,0x7c,0xc1,0xe3,0xe,0xb,0x9d,0x0,0x1e,0xdf,0x49,0xff,0xc3,0x82,0xf,0x5f,0xe0,0x38,0xef,0xff,0x7e,0xfc,0x3f,0x4c,0x62,0x30,0x78,0x87,0x93,0x3f,0xf7,0x8f,0xec,0x2f,0x37,0xe5,0x99,0xe0,0x30,0xe0,0xf3,0xf7,0x83,0xc6,0x9f,0x49,0xc9,0x40,0x41,0xe5,0xc0,0xc0,0x93,0x93,0xee,0xa6,0x10,0x1,0x3,0xcb,0xc0,0x61,0x10,0x1,0x7f,0x1,0xe2,0x5,0x2f,0xc0,0x3c,0xac,0x18,0x0,0xc1,0xb0,0x86,0x3e,0x2c,0x2f,0xe0,0x3c,0xa6,0x0,0xf7,0x81,0x3,0x4,0xa0,0x56,0x0,0x7c,0x3f,0x6,0x1,0x7f,0x1,0xd,0xc2,0x31,0x80,0xf3,0x83,0xd6,0x31,0x0,0xe0,0x13,0xcb,0x78,0xf,0x1e,0x1c,0x3c,0x90,0x20,0xf2,0xb0,0x30,0xc7,0xff,0x3,0x80,0x4f,0xe1,0xe0,0xf1,0xd7,0xcc,0xbf,0x60,0xf1,0x4b,0x23,0xdc,0x9c,0xc3,0xe7,0xf,0xab,0x99,0x20,0x13,0x80,0x78,0x93,0xd8,0x1e,0xb2,0x0,0x7f,0x8b,0xc8,0x1f,0xc0 -}; - -const uint8_t _A_L1_Tv_128x47_6[] = { - 0x1,0x0,0xc1,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x3f,0x44,0x22,0xa,0x23,0x61,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xea,0x82,0x50,0x78,0x80,0x45,0x84,0x90,0x2f,0x4,0xfc,0x1e,0x3f,0xf0,0x1,0x43,0xe0,0x1f,0xe0,0x31,0xc0,0xfc,0x12,0x7f,0x4,0x7c,0x54,0x30,0x4f,0x3,0x98,0x58,0x49,0x1e,0xb0,0x49,0xbc,0x12,0x31,0x60,0xc1,0xa3,0x8b,0x24,0x0,0xc,0xf,0x81,0x13,0xe0,0x50,0x41,0xe3,0x1a,0x81,0xc0,0x2c,0x0,0xe3,0x3a,0x89,0x7c,0x78,0x1,0x91,0x88,0x79,0x41,0x43,0x18,0x7,0x9c,0xc0,0x26,0x60,0xf2,0x82,0xbb,0x8f,0xf0,0x41,0x14,0x99,0x83,0xcb,0x40,0x7b,0x20,0x60,0xc1,0x2f,0xc8,0x34,0x7,0x98,0x5c,0x81,0xe5,0x80,0x8f,0xfd,0x1,0xeb,0xf0,0x88,0xc0,0x21,0xc2,0xc3,0xf0,0x43,0xcf,0x62,0xf,0x3f,0xe7,0x9f,0x81,0x9,0x4f,0xb,0x20,0x90,0xe2,0x10,0x10,0x79,0x7f,0xa1,0xf3,0xf8,0x80,0x3c,0x57,0x4,0x22,0x10,0x20,0xfc,0x30,0x7f,0xff,0xef,0xdd,0x54,0x51,0xf3,0xe0,0x9b,0xd2,0x19,0x9c,0xff,0x8e,0x4,0x1e,0x51,0xd8,0x2,0xcc,0x78,0x9,0x71,0x69,0xe,0xe1,0x90,0x7f,0xf9,0xf8,0xe4,0x6f,0x1f,0x81,0x50,0xb5,0xc6,0x3,0xf0,0x7,0xa7,0x3c,0x1e,0x38,0x1,0x0,0xb8,0x4,0x9a,0x3e,0x6,0x4a,0x7c,0x1,0xe3,0x70,0x2,0x8f,0xf1,0xae,0x43,0xc3,0x0,0xf,0xcc,0x1e,0x30,0xe0,0xb9,0xd0,0x1,0xed,0xf4,0x9f,0xfc,0x38,0x20,0xf5,0xfe,0x3,0x8e,0xff,0xf7,0xef,0xc3,0xf4,0xc6,0x21,0x7,0x9f,0xc,0x1e,0x79,0xff,0xbc,0x7f,0x61,0x79,0x68,0x8,0x0,0x64,0x18,0xc,0x0,0x3c,0xfd,0xe0,0xf1,0xa7,0xd2,0x72,0x4c,0x41,0x7,0x8d,0x0,0x1e,0x9f,0x3f,0xbe,0x7c,0xa,0x47,0xd1,0x7,0x88,0x80,0x48,0xc7,0xfc,0x7,0x88,0x14,0xa3,0x0,0xf4,0xf,0x9b,0x8,0x63,0xe2,0xc2,0x8e,0x3,0xca,0x20,0xf,0x77,0x8,0xc0,0x23,0xc0,0x21,0xb0,0x3,0xe2,0x8,0xc,0x11,0xf9,0x5c,0x21,0x18,0xf,0x38,0x3d,0x47,0x83,0xc0,0x51,0x8c,0x3,0x78,0xf,0x1e,0x18,0x58,0x7f,0x0,0xf2,0xb0,0x30,0xc6,0xfe,0xf,0x19,0xfc,0x1c,0x1e,0x3a,0xf9,0x97,0xec,0x1e,0x2b,0x54,0x7b,0x93,0x44,0x7c,0xe1,0xf5,0x73,0x24,0x2,0x70,0xf,0x12,0x7b,0x3,0xd6,0x40,0xf,0xf1,0x79,0x3,0xf8 -}; - -const uint8_t _A_L1_Tv_128x47_7[] = { - 0x1,0x0,0xcd,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x3f,0x44,0x22,0xa,0x23,0x61,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xea,0x82,0x50,0x78,0x80,0x45,0x84,0x7f,0x8,0x1f,0x82,0x7e,0xf,0x1f,0xf8,0x0,0xa1,0xf0,0xf,0xf0,0x14,0xe1,0xde,0x9,0x3f,0x82,0x3e,0x2a,0x18,0x27,0x81,0xcc,0x21,0x11,0x27,0x14,0xc2,0x40,0xf,0x19,0xf8,0xb0,0x60,0xd1,0xc3,0xa0,0xc0,0xc1,0xe5,0x74,0xe0,0x70,0x22,0x7c,0xa,0x38,0x3c,0x63,0x40,0xc1,0xf0,0x13,0x8f,0xf9,0x1,0x2f,0x8f,0x3,0x6,0x5c,0x1f,0x28,0x28,0x6f,0x0,0xf3,0xfc,0xd,0x85,0x12,0x20,0xf2,0x82,0x81,0x86,0x3c,0xc,0x17,0xc8,0x92,0xc8,0x1e,0x7a,0x3,0xd9,0x6,0x46,0x9,0x7e,0x22,0xd,0xfc,0x1e,0xaa,0xb2,0x20,0x8c,0x13,0x0,0x1d,0x1c,0x38,0x18,0x41,0xe5,0xf0,0x88,0xc0,0x21,0xc1,0xf1,0xa,0xf,0x83,0x1f,0x1,0x9,0x8,0x3c,0xbf,0x9e,0x7e,0x4,0x26,0xc,0xc8,0x3f,0xc7,0xfd,0x3a,0x20,0xf2,0xff,0x43,0xe7,0xf1,0x0,0x78,0xae,0x9,0xc6,0x7f,0xc,0xff,0xff,0xfb,0xf7,0x55,0x94,0x7d,0xe4,0x20,0xf4,0x86,0x6f,0x3f,0xe3,0x81,0x7,0x94,0x74,0xc4,0x53,0x7,0x11,0x8d,0x4,0x0,0x73,0xf2,0x48,0xde,0x3f,0x1c,0x31,0x28,0xc0,0x20,0x3f,0x0,0x7a,0x73,0xc1,0x23,0x80,0x83,0xe0,0x3f,0xe0,0x21,0x5c,0xa9,0x18,0x41,0xe3,0x70,0x2,0x8f,0xf9,0x80,0x23,0xc4,0x0,0xf,0xcc,0x1e,0x30,0xe0,0xb9,0xd0,0x1,0xed,0xf4,0x9f,0xfc,0x38,0x20,0xf5,0xfe,0x3,0x8e,0xff,0xf7,0xef,0xc3,0xf4,0xc6,0x21,0x7,0x98,0x79,0x33,0xff,0x78,0xfe,0xc2,0xf2,0xd0,0x10,0x0,0xc8,0x30,0x18,0x70,0x79,0xfb,0xc1,0xe3,0x4f,0xa4,0xe4,0x9e,0x22,0xf,0x1e,0x6,0x4,0x9c,0x9f,0x75,0x30,0x80,0x8,0x1e,0x5e,0x3,0x8,0x80,0xb,0xf8,0xf,0x10,0x29,0x7e,0x1,0xe5,0x60,0x42,0x8,0x0,0x98,0x43,0x1f,0x16,0x17,0xf0,0x1e,0x53,0x0,0x7b,0xc0,0x81,0x82,0x50,0x2b,0x0,0x3e,0x20,0x80,0xc1,0xbf,0x80,0x86,0xe1,0x18,0xc0,0x79,0xc1,0xeb,0x18,0x80,0x70,0x9,0xe5,0xbc,0x7,0x8f,0xe,0x1e,0x48,0x10,0x79,0x58,0x18,0x63,0xff,0x81,0xc0,0x27,0xf0,0xf0,0x78,0xeb,0xe6,0x5f,0xb0,0x78,0xa5,0x91,0xee,0x4e,0x61,0xf3,0x87,0xd5,0xcc,0x90,0x9,0xc0,0x3c,0x49,0xec,0xf,0x59,0x0,0x3f,0xc5,0xe4,0xf,0xe0 -}; - - -const uint8_t * const _A_L1_Tv_128x47[] = { - - _A_L1_Tv_128x47_0, - - _A_L1_Tv_128x47_1, - - _A_L1_Tv_128x47_2, - - _A_L1_Tv_128x47_3, - - _A_L1_Tv_128x47_4, - - _A_L1_Tv_128x47_5, - - _A_L1_Tv_128x47_6, - - _A_L1_Tv_128x47_7, - -}; - - - -const FrameBubble L1_Tv_128x47_bubble_0_0; - -const FrameBubble L1_Tv_128x47_bubble_1_0; - - -const FrameBubble* const L1_Tv_128x47_bubble_sequences[] = { - - &L1_Tv_128x47_bubble_0_0, - - &L1_Tv_128x47_bubble_1_0, - -}; - - - -const FrameBubble L1_Tv_128x47_bubble_0_0 = { - .bubble = { - .x = 1, - .y = 23, - .text = "Take the red pill", - .align_h = AlignRight, - .align_v = AlignBottom, - }, - .start_frame = 7, - .end_frame = 9, - .next_bubble = NULL, -}; - - -const FrameBubble L1_Tv_128x47_bubble_1_0 = { - .bubble = { - .x = 1, - .y = 23, - .text = "I can joke better", - .align_h = AlignRight, - .align_v = AlignBottom, - }, - .start_frame = 7, - .end_frame = 9, - .next_bubble = NULL, -}; - - - -const uint8_t L1_Tv_128x47_frame_order[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - -const BubbleAnimation BA_L1_Tv_128x47 = { - .icon_animation = { - .width = 128, - .height = 47, - .frame_count = 8, - .frame_rate = 2, - .frames = _A_L1_Tv_128x47 - }, - .frame_order = L1_Tv_128x47_frame_order, - .passive_frames = 6, - .active_frames = 2, - .active_cooldown = 5, - .active_cycles = 2, - .duration = 3600, - - .frame_bubble_sequences = L1_Tv_128x47_bubble_sequences, - .frame_bubble_sequences_count = COUNT_OF(L1_Tv_128x47_bubble_sequences), - -}; - - -const uint8_t _A_L1_BadBattery_128x47_0[] = { - 0x1,0x0,0xb,0x1,0x0,0x47,0xfb,0xfe,0x0,0x2b,0x38,0x3e,0x60,0x40,0x43,0xbf,0x3,0xe7,0xa5,0xf3,0xff,0xf9,0x2f,0xf5,0x60,0xff,0x5a,0x81,0xf3,0xa,0x2,0x18,0x7e,0x81,0xe9,0xea,0x87,0x8b,0xf7,0xad,0x1d,0x7,0xef,0xaa,0x30,0x2f,0xd0,0xfd,0x62,0xa6,0x30,0x9,0x84,0x18,0x7f,0x50,0xa8,0xdc,0x2,0xc1,0x3,0x2f,0xdc,0x3a,0x1,0xc0,0x80,0x9f,0xec,0x1e,0x61,0xfb,0x17,0x98,0x7e,0x89,0xe8,0x9f,0xf5,0xff,0x87,0xfc,0xff,0x69,0xf4,0x8f,0x83,0xe3,0xc5,0x1,0xff,0x40,0xd7,0xf7,0xfa,0x83,0xfc,0x60,0xe1,0xfb,0x7,0x8f,0xfc,0x1e,0x23,0xfa,0xff,0x2,0x8c,0xbf,0x40,0xf4,0x3f,0xd0,0x7f,0xfe,0x5c,0xff,0xff,0xd2,0xa2,0x1f,0xaf,0x9,0x34,0x40,0x3,0x7e,0x7,0x46,0x3,0x8f,0xff,0x0,0x15,0x9c,0x1f,0x1c,0xe,0x7c,0x4,0x57,0x20,0x2,0xa0,0x4b,0xc1,0xd9,0x0,0x90,0x47,0x81,0xfb,0x10,0x87,0x3,0xf6,0x10,0x5e,0x30,0x5,0x61,0x20,0xa0,0xfd,0xa1,0x3,0xfa,0x4c,0xf,0x64,0x29,0x80,0xe,0x3e,0xf,0xe0,0x7,0x97,0x9f,0x8f,0x18,0xb3,0x62,0xe6,0xd6,0xed,0xc,0x6c,0x1e,0xfb,0x7e,0xb5,0x6f,0xbb,0xd4,0xa7,0xef,0x7d,0x70,0x78,0x84,0xe6,0x71,0xe6,0xf7,0x53,0xa0,0x21,0xf1,0xa1,0x77,0xaa,0x52,0xed,0xe,0x6a,0xf,0xb0,0x82,0xd2,0x29,0x32,0x4a,0x94,0x7,0x6f,0xda,0xf,0x8f,0x5a,0xdd,0xbd,0xbd,0x41,0xea,0x11,0x99,0xc5,0x3f,0xc9,0x8e,0x1f,0x8c,0x5a,0xb4,0x3f,0x1b,0x7d,0x87,0x1a,0x2f,0x19,0x8,0x7c,0xb1,0x46,0xf8,0x7,0x8e,0x76,0x71,0x49,0xf2,0x64,0x81,0xf2,0x5f,0x60,0x7f,0x80 -}; - -const uint8_t _A_L1_BadBattery_128x47_1[] = { - 0x1,0x0,0x11,0x1,0x0,0x47,0xfb,0xfe,0x0,0x2b,0x38,0x3e,0x60,0x40,0x43,0xbf,0x3,0xe7,0xa5,0xf3,0xff,0xf9,0x2f,0xf5,0x60,0xff,0x5a,0x81,0xf3,0xa,0x2,0x18,0x7e,0x81,0xe9,0xea,0x87,0x8b,0xf7,0xad,0x1d,0x7,0xef,0xaa,0x30,0x2f,0xd0,0xfd,0x62,0xa6,0x30,0x9,0x84,0x18,0x7f,0x50,0xa8,0xdc,0x2,0xc1,0x3,0x2f,0xdc,0x3a,0x1,0xc0,0x80,0x9f,0xec,0x1e,0x61,0xfb,0x17,0x98,0x7e,0x89,0xe8,0x9f,0xf5,0xff,0x87,0xfc,0xff,0x70,0xf,0xe4,0x5,0x3e,0x31,0xf0,0x7c,0x78,0xa0,0x3c,0x28,0x1a,0xfe,0xff,0x50,0x7f,0x8c,0x1c,0x3f,0x60,0xf1,0xfc,0x83,0xc4,0x7f,0x5f,0xe8,0x7f,0xfc,0x1e,0x25,0xfa,0x7,0x89,0xff,0x41,0xe8,0x1f,0xaf,0x97,0x3f,0xff,0xf4,0xa8,0x87,0xeb,0xc2,0x3d,0x10,0x0,0xdf,0x81,0xd1,0x80,0xe3,0xff,0xc0,0x5,0x67,0x7,0xc7,0x3,0x9e,0x9d,0x10,0x5,0xd0,0x25,0xe0,0xec,0x80,0x48,0x23,0xc0,0xfd,0x88,0x43,0x81,0xfb,0x8,0x2f,0x18,0x2,0xb0,0x90,0x50,0x7e,0xd0,0x81,0xfd,0x26,0x7,0xb2,0x14,0xc0,0x7,0x1f,0x7,0xf0,0x3,0xcb,0xcf,0xc7,0x8c,0x59,0xb1,0x73,0x6b,0x76,0x86,0x36,0xf,0x7d,0xbf,0x5a,0xb7,0xdd,0xea,0x53,0xf7,0xbe,0xb8,0x3c,0x42,0x73,0x38,0xf3,0x7b,0xa9,0xd0,0x10,0xf8,0xd0,0xbb,0xd5,0x29,0x76,0x87,0x35,0x7,0xd8,0x41,0x69,0x14,0x99,0x25,0x4a,0x3,0xb7,0xed,0x7,0xc7,0xad,0x6e,0xde,0xde,0xa0,0xf5,0x8,0xcc,0xe2,0x9f,0xe4,0xc7,0xf,0xc6,0x2d,0x5a,0x1f,0x8d,0xbe,0xc3,0x8d,0x17,0x8c,0x84,0x3e,0x58,0xa3,0x7c,0x3,0xc7,0x3b,0x38,0xa4,0xf9,0x32,0x40,0xf9,0x2f,0xb0,0x3f,0xc0 -}; - - -const uint8_t * const _A_L1_BadBattery_128x47[] = { - - _A_L1_BadBattery_128x47_0, - - _A_L1_BadBattery_128x47_1, - -}; - - - -const FrameBubble L1_BadBattery_128x47_bubble_0_0; - - -const FrameBubble* const L1_BadBattery_128x47_bubble_sequences[] = { - - &L1_BadBattery_128x47_bubble_0_0, - -}; - - - -const FrameBubble L1_BadBattery_128x47_bubble_0_0 = { - .bubble = { - .x = 4, - .y = 21, - .text = "I feel so sick!\nI'm dying...", - .align_h = AlignRight, - .align_v = AlignCenter, - }, - .start_frame = 0, - .end_frame = 1, - .next_bubble = NULL, -}; - - - -const uint8_t L1_BadBattery_128x47_frame_order[] = { 0, 1 }; - -const BubbleAnimation BA_L1_BadBattery_128x47 = { - .icon_animation = { - .width = 128, - .height = 47, - .frame_count = 2, - .frame_rate = 2, - .frames = _A_L1_BadBattery_128x47 - }, - .frame_order = L1_BadBattery_128x47_frame_order, - .passive_frames = 2, - .active_frames = 0, - .active_cooldown = 0, - .active_cycles = 0, - .duration = 3600, - - .frame_bubble_sequences = L1_BadBattery_128x47_bubble_sequences, - .frame_bubble_sequences_count = COUNT_OF(L1_BadBattery_128x47_bubble_sequences), - -}; - - -const uint8_t _A_L1_NoSd_128x49_0[] = { - 0x1,0x0,0x49,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x80,0x86,0x1e,0xf,0xde,0x4,0xf0,0x1f,0xb6,0xb,0xc0,0x3f,0xc1,0xfb,0x70,0xfc,0x40,0x3a,0x0,0xfc,0xec,0x40,0x3d,0x0,0xfb,0xf8,0x7f,0x20,0x1f,0x40,0x7d,0xec,0x35,0xf0,0xf,0xe7,0x26,0x4d,0xe7,0xf,0xce,0xf4,0x1e,0x38,0xd,0xdf,0x68,0x1f,0x1e,0xa,0xe8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xb0,0x9,0x5,0x1c,0x1e,0x5a,0x61,0x7b,0xc0,0xd3,0xe3,0x30,0x7,0x92,0xff,0x7e,0x19,0x48,0x1f,0x44,0x1e,0xb8,0x0,0x1a,0x3,0xc7,0xf3,0x2f,0x7,0xad,0x0,0x6,0x54,0x88,0x17,0xc3,0xff,0xc0,0x8f,0x83,0xd6,0x40,0x3,0x29,0x24,0x4,0x1e,0x38,0x18,0x78,0x3d,0x62,0x0,0x32,0xc9,0x2f,0xcb,0x1f,0x0,0x7,0xac,0x20,0x6,0x54,0x95,0xf8,0xdf,0xf0,0x18,0x8,0x3f,0x80,0x22,0x70,0x40,0x10,0xc1,0x80,0x43,0xf4,0x7,0x8f,0x2,0xf,0x10,0xec,0x4,0x8,0x1e,0x38,0x3,0x89,0x7f,0x19,0xe7,0x10,0x90,0xb,0x8,0x1e,0x37,0x81,0x29,0x3,0xd8,0x98,0x40,0xf1,0x1a,0x98,0x3d,0x2c,0x0,0xf3,0xf2,0x78,0x16,0x24,0xf,0x5c,0x4,0xff,0xc0,0x3a,0x18,0xc4,0x7c,0x8,0x40,0xf6,0x45,0x8c,0xf8,0xfe,0x5f,0xc0,0x7b,0xd0,0x28,0x10,0x4e,0x4,0x3e,0xc1,0x80,0xff,0x8f,0xdc,0x1e,0x4c,0x81,0x3,0x8c,0xfc,0x1f,0x1c,0x2,0x49,0x40,0x3f,0xce,0xd1,0x7,0xc2,0xc0,0xff,0xc1,0x43,0x7,0xd4,0x8,0x8,0x60,0xff,0xfc,0x3,0xca,0x7,0x80,0xb0,0x2,0x8c,0xda,0x40,0x7,0xb0,0x83,0xfb,0xfc,0xb,0x30,0x7a,0x0 -}; - -const uint8_t _A_L1_NoSd_128x49_1[] = { - 0x1,0x0,0x42,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x80,0x86,0x1e,0xf,0xde,0x4,0xf0,0x1f,0xb6,0xb,0xc0,0x3f,0xc1,0xfb,0x70,0xfc,0x40,0x3a,0x0,0xfc,0xec,0x40,0x3d,0x0,0xfb,0xf8,0x7f,0x20,0x1f,0x40,0x7d,0xec,0x35,0xf0,0xf,0xe7,0x26,0x4d,0xe7,0xf,0xce,0xf4,0x1e,0x38,0xd,0xdf,0x68,0x1f,0x1e,0xa,0xe8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xb0,0x9,0x5,0x1c,0x1e,0x5a,0x61,0x7b,0xc0,0xd3,0xe3,0x30,0x7,0x92,0xff,0x7e,0x19,0x48,0x1f,0x44,0x1e,0xb8,0x0,0x1a,0x3,0xc7,0xf3,0x2f,0x7,0xad,0x0,0x6,0x54,0x88,0x17,0xc3,0xff,0xc0,0x8f,0x83,0xd6,0x40,0x3,0x29,0x24,0x4,0x1e,0x38,0x18,0x78,0x3d,0x62,0x0,0x32,0xc9,0x2f,0xcb,0x1f,0x0,0x7,0xac,0x20,0x6,0x54,0x95,0xf8,0xdf,0xf0,0x18,0x0,0x7a,0xc1,0x0,0x43,0x6,0x1,0xf,0xd0,0x1e,0x3c,0x0,0x78,0xf8,0x2,0x44,0xf,0x1c,0x1,0xc4,0xbf,0x8c,0xf4,0x88,0x76,0x0,0x62,0xf,0x1b,0xc0,0x94,0x81,0xed,0x20,0x1e,0x88,0x3c,0x46,0xe6,0xf,0x72,0xe8,0xf9,0x3c,0xb,0x12,0x7,0xb5,0x80,0x1e,0x51,0x88,0xff,0x80,0x7f,0x18,0x9,0xf8,0x2c,0x42,0x23,0xfc,0x7,0xca,0x70,0x67,0xd6,0xc,0x7,0xfc,0x7f,0x14,0xa,0x4,0x13,0x81,0x8f,0xff,0xcf,0xc1,0xf6,0xd9,0x1f,0xfb,0xb4,0x41,0xf1,0xc0,0x2d,0x17,0xf8,0x6,0x40,0xf8,0x5,0x14,0x9,0x6a,0x60,0xff,0xfc,0x3,0xc8,0x4e,0x20,0xf4,0x36,0x90,0x1,0xf0,0x16,0x0,0x7e,0xc0,0x2c,0x20,0xf7 -}; - -const uint8_t _A_L1_NoSd_128x49_2[] = { - 0x1,0x0,0x41,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x83,0xfc,0x1f,0xe0,0xff,0x2e,0x8c,0xfc,0x1f,0xbe,0xb,0xc4,0x3,0xa0,0xf,0xbb,0x6,0xe2,0x1,0xe8,0x7,0xdf,0xc3,0xf9,0x0,0xfa,0x3,0xef,0x61,0xdf,0x80,0x7f,0x39,0x32,0x6f,0x38,0x7e,0x77,0x20,0xf1,0xc0,0x6e,0xfb,0x44,0xf9,0xac,0x83,0xc7,0x29,0xba,0xed,0x83,0xda,0xb,0x0,0xe0,0x1b,0xc4,0x1e,0x3a,0x61,0x7b,0xc0,0xc0,0x86,0xf,0x14,0xfd,0xe4,0x8,0x43,0x94,0x81,0xf4,0x41,0xeb,0x80,0x1,0x95,0x22,0x4,0xf,0x1f,0xcc,0xbc,0x1e,0xb4,0x0,0x91,0x49,0x20,0x3f,0xf,0xff,0x2,0x3e,0xf,0x59,0x0,0x48,0xb2,0x50,0x40,0x78,0xe0,0x61,0xe0,0xf5,0x88,0x4,0x8a,0x93,0x2,0x5f,0x8e,0x3e,0x0,0xf,0x58,0x40,0x8c,0xe1,0x3e,0x8b,0xfe,0x3,0x0,0xf,0x58,0x20,0x8,0x60,0xd8,0x8,0x27,0xd0,0x1e,0x3c,0x0,0x7b,0xe0,0xe,0x25,0xfc,0x67,0xc0,0x3c,0x5f,0xa2,0xf,0x7f,0xc0,0x64,0x81,0xe3,0x1f,0x7,0xc4,0x13,0xec,0x10,0x1f,0x27,0x80,0x4e,0x60,0xf6,0x84,0x40,0xa0,0x1d,0x8f,0xf8,0x90,0x81,0xf0,0x2d,0x1f,0x7,0xc5,0x62,0x60,0xf5,0x8c,0x3,0xce,0x3f,0x70,0x7,0xc7,0x82,0x1e,0x5b,0x15,0x78,0xcf,0x1,0xf1,0x20,0x84,0x60,0x21,0xe0,0xf1,0x2f,0xcc,0x42,0x20,0xd8,0x1a,0x1f,0x2,0x1e,0xf,0xb0,0x49,0x1b,0xe6,0x21,0xf0,0x5,0x17,0xf8,0xde,0x7f,0x80,0x79,0x40,0xc1,0xe3,0x30,0x5,0x15,0xf5,0x6c,0x8f,0xb5,0x7,0x98,0x78,0xc1,0xff,0x0 -}; - -const uint8_t _A_L1_NoSd_128x49_3[] = { - 0x1,0x0,0x45,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x83,0xfc,0x1f,0xe0,0xff,0x2e,0x8c,0xfc,0x1f,0xbe,0xb,0xc4,0x3,0xa0,0xf,0xbb,0x6,0xe2,0x1,0xe8,0x7,0xdf,0xc3,0xf9,0x0,0xfa,0x3,0xef,0x61,0xdf,0x80,0x7f,0x39,0x32,0x6f,0x38,0x7e,0x77,0x20,0xf1,0xc0,0x6e,0xfb,0x44,0xf9,0xac,0x83,0xc7,0x29,0xba,0xed,0x83,0xda,0xb,0x0,0xe0,0x1b,0xc4,0x1e,0x3a,0x61,0x7b,0xc0,0xc0,0x86,0xf,0x14,0xfd,0xe4,0x8,0x43,0x94,0x81,0xf4,0x41,0xeb,0x80,0x1,0x95,0x22,0x4,0xf,0x1f,0xcc,0xbc,0x1e,0xb4,0x0,0x91,0x49,0x20,0x3f,0xf,0xff,0x2,0x3e,0xf,0x59,0x0,0x48,0xb2,0x50,0x40,0x78,0xe0,0x61,0xe0,0xf5,0x88,0x4,0x8a,0x93,0x2,0x5f,0x8e,0x3e,0x0,0xf,0x58,0x40,0x8c,0xe1,0x3e,0x8b,0xfe,0x3,0x0,0xf,0x58,0x20,0x8,0x60,0xd8,0x8,0x27,0xd0,0x1e,0x3c,0x0,0x7b,0xe0,0xe,0x25,0xfc,0x67,0xc0,0x3c,0x5f,0xa2,0xf,0x7f,0xc0,0x64,0x81,0xe2,0x17,0x30,0x7a,0xc1,0x3e,0xc1,0x1,0xf2,0x78,0x16,0x26,0xf,0x68,0x44,0xa,0x1,0x18,0x8f,0xf8,0x7,0xf0,0xf,0x11,0x68,0x9f,0xc7,0xf8,0xf,0x88,0xc0,0x3c,0xac,0x18,0xf,0xf8,0xfe,0x3c,0x10,0xf2,0xd8,0x83,0x85,0xfa,0x20,0xf7,0x90,0x42,0x30,0x10,0xf8,0x7,0xf8,0x4,0x20,0xf7,0x88,0x44,0x1b,0x3,0x3,0xff,0x17,0x88,0x1f,0x20,0x91,0x8f,0xa5,0x4c,0x1e,0xdf,0x0,0x51,0x1c,0x84,0x0,0x5f,0x80,0x79,0x9,0xc6,0x21,0x30,0x5,0x11,0xb4,0x80,0xe,0xf,0xf0,0x7c,0x80 -}; - -const uint8_t _A_L1_NoSd_128x49_4[] = { - 0x1,0x0,0x3d,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x83,0xfc,0x1f,0xe0,0xff,0x7,0xf8,0x10,0xfa,0x0,0xfc,0xe0,0x40,0x3d,0x0,0xfc,0xf0,0x40,0x3e,0x80,0xfb,0x98,0x7c,0x20,0x1f,0xce,0x4c,0x9b,0xce,0xf,0x8f,0x85,0xfc,0x1e,0x38,0xd,0xdf,0x68,0x1f,0x1e,0x9,0xf8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xa4,0xe1,0x8f,0x83,0xcb,0x4c,0x2f,0x78,0x18,0x10,0xc1,0xe2,0x5f,0xbc,0x81,0x8,0x72,0x90,0x3e,0x88,0x3d,0x70,0x0,0x32,0xa4,0x40,0x81,0xe3,0xf9,0x97,0x83,0xd6,0x80,0x12,0x29,0x24,0x7,0xe1,0xff,0x22,0x8,0x3d,0x64,0x1,0x22,0xc9,0x41,0x1,0xe3,0x81,0x87,0x83,0xd6,0x20,0x12,0x2a,0x4c,0x9,0x7e,0x38,0xf8,0x0,0x3d,0x61,0x2,0x33,0x84,0xfa,0x2f,0xf8,0xc,0x0,0x3d,0x60,0x80,0x21,0x83,0x60,0x20,0x9f,0x40,0x78,0xf0,0x1,0xef,0x80,0x38,0x97,0xf1,0x9f,0x0,0xf1,0xbc,0x23,0xcc,0x1e,0x9f,0x80,0xc9,0x3,0xc5,0x5a,0x20,0xf7,0x82,0x7d,0x82,0x3,0xe4,0xf0,0x9,0xcc,0x1e,0xd0,0x88,0x14,0x3,0xb1,0xff,0x12,0x10,0x3e,0x5,0xa3,0xe0,0xf8,0xac,0x4c,0x1e,0xb1,0x80,0x79,0xc7,0xee,0x0,0xf8,0xf0,0x43,0xcb,0x62,0xaf,0x19,0xe0,0x3e,0x24,0x10,0x8c,0x4,0x3c,0x1e,0x25,0xf9,0x88,0x44,0x1b,0x3,0x43,0xe0,0x43,0xc1,0xf6,0x9,0x23,0x7c,0xc4,0x3e,0x0,0xa2,0xff,0x1b,0xcf,0xf0,0xf,0x28,0x18,0x3c,0x66,0x0,0xa2,0xbe,0xad,0x91,0xf6,0xa0,0xf3,0xf,0x18,0x3f,0xe0,0x0 -}; - -const uint8_t _A_L1_NoSd_128x49_5[] = { - 0x1,0x0,0x43,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x80,0x86,0x1e,0xf,0xde,0x4,0xf0,0x1f,0xb6,0xb,0xc0,0x3f,0xc1,0xfb,0x70,0xfc,0x40,0x3a,0x0,0xfc,0xec,0x40,0x3d,0x0,0xfb,0xf8,0x7f,0x20,0x1f,0x40,0x7d,0xec,0x35,0xf0,0xf,0xe7,0x26,0x4d,0xe7,0xf,0xce,0xf4,0x1e,0x38,0xd,0xdf,0x68,0x1f,0x1e,0xa,0xe8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xb0,0x9,0x5,0x1c,0x1e,0x5a,0x61,0x7b,0xc0,0xd3,0xe3,0x30,0x7,0x92,0xff,0x7e,0x19,0x48,0x1f,0x44,0x1e,0xb8,0x0,0x1a,0x3,0xc7,0xf3,0x2f,0x7,0xad,0x0,0x6,0x54,0x88,0x17,0xc3,0xff,0xc0,0x8f,0x83,0xd6,0x40,0x3,0x29,0x24,0x4,0x1e,0x38,0x18,0x78,0x3d,0x62,0x0,0x32,0xc9,0x2f,0xcb,0x1f,0x0,0x7,0xac,0x20,0x6,0x54,0x95,0xf8,0xdf,0xf0,0x18,0x0,0x7a,0xc1,0x0,0x43,0x6,0x1,0xf,0xd0,0x1e,0x3c,0x0,0x7b,0xe0,0xe,0x25,0xfc,0x67,0xc0,0x3c,0x6f,0x0,0x52,0x7,0xaf,0xe0,0x32,0x40,0xf1,0x8f,0x83,0xe2,0x9,0xf6,0x8,0xf,0x93,0xc0,0x27,0x30,0x7b,0x42,0x20,0x50,0xe,0xc7,0xfc,0x48,0x40,0xf8,0x16,0x8f,0x83,0xe2,0xb1,0x30,0x7a,0xc6,0x1,0xe7,0x1f,0xb8,0x3,0xe3,0xc1,0xf,0x2d,0x8a,0xbc,0x67,0x80,0xf8,0x90,0x42,0x30,0x10,0xf0,0x78,0x97,0xe6,0x21,0x10,0x64,0xd,0xf,0x80,0xfd,0x10,0x7d,0x2,0x48,0xdf,0x31,0xf,0x80,0x28,0xbf,0xc6,0xf3,0xfc,0x3,0xca,0x6,0xf,0x19,0x80,0x28,0xaf,0xab,0x64,0x7d,0xa8,0x3c,0xc3,0xc6,0xf,0xf8,0x0 -}; - - -const uint8_t * const _A_L1_NoSd_128x49[] = { - - _A_L1_NoSd_128x49_0, - - _A_L1_NoSd_128x49_1, - - _A_L1_NoSd_128x49_2, - - _A_L1_NoSd_128x49_3, - - _A_L1_NoSd_128x49_4, - - _A_L1_NoSd_128x49_5, - -}; - - - -const FrameBubble L1_NoSd_128x49_bubble_0_0; - - -const FrameBubble* const L1_NoSd_128x49_bubble_sequences[] = { - - &L1_NoSd_128x49_bubble_0_0, - -}; - - - -const FrameBubble L1_NoSd_128x49_bubble_0_0 = { - .bubble = { - .x = 40, - .y = 18, - .text = "Need an\nSD card", - .align_h = AlignRight, - .align_v = AlignBottom, - }, - .start_frame = 0, - .end_frame = 9, - .next_bubble = NULL, -}; - - - -const uint8_t L1_NoSd_128x49_frame_order[] = { 0, 1, 0, 1, 0, 2, 3, 4, 3, 5 }; - -const BubbleAnimation BA_L1_NoSd_128x49 = { - .icon_animation = { - .width = 128, - .height = 49, - .frame_count = 6, - .frame_rate = 2, - .frames = _A_L1_NoSd_128x49 - }, - .frame_order = L1_NoSd_128x49_frame_order, - .passive_frames = 10, - .active_frames = 0, - .active_cooldown = 0, - .active_cycles = 0, - .duration = 3600, - - .frame_bubble_sequences = L1_NoSd_128x49_bubble_sequences, - .frame_bubble_sequences_count = COUNT_OF(L1_NoSd_128x49_bubble_sequences), - -}; - - -const StorageAnimation dolphin_internal[] = { - - { - .animation = &BA_L1_Tv_128x47, - .manifest_info = { - .name = "L1_Tv_128x47", - .min_butthurt = 0, - .max_butthurt = 14, - .min_level = 1, - .max_level = 3, - .weight = 3, - } - }, - - { - .animation = &BA_L1_BadBattery_128x47, - .manifest_info = { - .name = "L1_BadBattery_128x47", - .min_butthurt = 0, - .max_butthurt = 14, - .min_level = 1, - .max_level = 3, - .weight = 3, - } - }, - - { - .animation = &BA_L1_NoSd_128x49, - .manifest_info = { - .name = "L1_NoSd_128x49", - .min_butthurt = 0, - .max_butthurt = 14, - .min_level = 1, - .max_level = 3, - .weight = 6, - } - }, - -}; - -const size_t dolphin_internal_size = COUNT_OF(dolphin_internal); diff --git a/assets/compiled/assets_dolphin_internal.h b/assets/compiled/assets_dolphin_internal.h deleted file mode 100644 index f4f415fa..00000000 --- a/assets/compiled/assets_dolphin_internal.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include -#include - -extern const StorageAnimation dolphin_internal[]; -extern const size_t dolphin_internal_size; diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c deleted file mode 100644 index fb125095..00000000 --- a/assets/compiled/assets_icons.c +++ /dev/null @@ -1,829 +0,0 @@ -#include "assets_icons.h" - -#include - -const uint8_t _I_Certification1_103x23_0[] = {0x01,0x00,0x98,0x00,0x9f,0xff,0xbe,0x30,0x38,0x04,0xf2,0x01,0xe0,0x80,0x82,0x87,0xf9,0x01,0x06,0x24,0xfe,0x01,0xf8,0x80,0xfe,0x21,0xff,0xf8,0x3c,0xff,0x9c,0x0c,0x1e,0x00,0x30,0x7f,0xc0,0xc1,0xe3,0xc0,0xe3,0xd0,0x7e,0x75,0xc4,0x46,0x30,0x70,0xd9,0x46,0x3c,0x10,0x09,0xc0,0x30,0xfe,0x10,0x1c,0x04,0x3c,0x18,0x37,0x08,0x05,0xc0,0x18,0x77,0x88,0x07,0x00,0x6e,0x31,0x89,0x87,0xe2,0x00,0x0c,0x39,0xc0,0x30,0x49,0x83,0x18,0x8c,0x7f,0xa0,0x60,0xc3,0x2c,0xa0,0x30,0x60,0xe0,0x01,0x06,0x14,0x70,0x18,0x26,0x51,0x8c,0x43,0x20,0x70,0x20,0x64,0xe3,0x03,0xa2,0x74,0x10,0x62,0x5f,0xce,0xc3,0x8f,0x06,0x78,0x31,0xc4,0xc6,0x33,0xc2,0x6f,0x99,0xf5,0x03,0x89,0xb7,0xb0,0x2d,0x7d,0x9f,0x2e,0x98,0x8c,0x0a,0x86,0x3c,0x0c,0x30,0xb9,0x7e,0x20,0x30,0x88,0x07,0xfe,0x0e,0x0c,0x42,0xda,0x40,0x3f,0x90,0x10,}; -const uint8_t* const _I_Certification1_103x23[] = {_I_Certification1_103x23_0}; - -const uint8_t _I_Certification2_119x30_0[] = {0x01,0x00,0x3c,0x01,0x00,0x5c,0x06,0x01,0x40,0x07,0x5e,0x0b,0xff,0x20,0x07,0x5d,0x92,0x01,0x13,0x03,0xa4,0x70,0x06,0x5f,0xe0,0x10,0xc6,0x20,0x10,0xc8,0x1c,0xce,0x70,0x07,0x19,0xf0,0x08,0x70,0x10,0x18,0x1c,0x03,0xe1,0xff,0x83,0x83,0x84,0x34,0x57,0xf0,0x10,0xd8,0x03,0x23,0x00,0x1c,0x8c,0x08,0x1c,0x30,0xf0,0xc8,0xf8,0xc1,0xc3,0x10,0x00,0x90,0x48,0x60,0x70,0x3d,0x98,0x90,0x70,0x1c,0x10,0x70,0xc2,0x03,0x65,0xa0,0xc0,0x07,0x47,0xe6,0x6d,0x1e,0x07,0x04,0x06,0x20,0xe3,0x90,0x5f,0x41,0xc9,0xe0,0xc0,0x08,0x46,0x09,0x18,0x41,0x0c,0x82,0x44,0x0e,0x11,0x61,0x5c,0x27,0xd0,0x70,0x70,0xc5,0xc1,0xc3,0x40,0x8a,0x17,0x84,0x94,0x53,0x0a,0x0c,0x1a,0x01,0xe2,0x88,0x7e,0x01,0xc3,0x08,0x80,0xff,0xcd,0x05,0xb8,0x80,0x43,0xa0,0x11,0xe8,0x80,0x84,0x43,0xa5,0xfe,0x98,0xa1,0x86,0xb9,0x00,0x8e,0x9c,0x47,0xe0,0x5d,0x1a,0x04,0x88,0x8e,0x20,0x02,0x97,0x60,0x27,0x40,0xe1,0x03,0x95,0x02,0x82,0x0e,0x49,0x35,0x0a,0x65,0x00,0xe1,0x28,0x04,0xfe,0x38,0x05,0xc8,0xf8,0xe3,0xf0,0x09,0x3c,0x8a,0xe4,0x0e,0x4e,0x02,0xe0,0x7f,0xff,0x39,0xfe,0x02,0x47,0x14,0xf1,0x0b,0x13,0x41,0xc0,0x52,0x0c,0xc2,0x61,0xc0,0x90,0xc3,0x38,0x50,0x1e,0x27,0xfe,0x8f,0x00,0xc8,0x48,0x20,0xc0,0xe3,0x40,0x0e,0x04,0x1c,0x98,0x8d,0x04,0x28,0x1c,0x4a,0x31,0x00,0x0c,0x0e,0x11,0x38,0x59,0x8c,0x12,0x7f,0x12,0x81,0xfc,0x27,0xf7,0x08,0x05,0x06,0x01,0x07,0x07,0x1c,0x08,0x6c,0x20,0xe2,0x98,0x40,0x27,0xd0,0x08,0x34,0x42,0x70,0xef,0x13,0xa8,0xd0,0x05,0x84,0x1d,0x10,0x00,0xc1,0xdf,0x43,0x0c,0x41,0x1a,0xcc,0x47,0x63,0xff,0x00,0x0c,0x0c,0xe4,0x2d,0x91,0x00,0x17,0xf8,0x1c,0x3c,0x00,0x71,0x09,0xc7,0xfc,0x0d,0x30,0x06,0x7f,0x3f,0xea,0x11,0x07,0x78,0x3b,0xc1,0xd6,}; -const uint8_t* const _I_Certification2_119x30[] = {_I_Certification2_119x30_0}; - -const uint8_t _A_Levelup1_128x64_0[] = {0x01,0x00,0x22,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0x38,0x1f,0xe0,0x1d,0x97,0xff,0xe7,0x1c,0x1f,0x99,0xf8,0x1c,0xe0,0x1f,0x96,0x78,0x07,0x03,0xf8,0x0f,0xb8,0xdc,0x02,0x01,0xfb,0x07,0xdc,0x14,0x1e,0x3f,0x40,0x7d,0xc0,0x81,0xe3,0xe8,0x2f,0x5c,0x04,0x1e,0x3d,0x00,0x7d,0x6f,0xc1,0xc3,0x00,0xd0,0x03,0xea,0xbe,0x0f,0xf0,0x79,0x50,0x01,0xf5,0x2f,0x07,0xf8,0x38,0x63,0xf8,0x0f,0xf1,0x7a,0x62,0x10,0x0c,0x04,0x80,0x1f,0x59,0xf8,0xf8,0xb4,0x6f,0x80,0xfa,0xb7,0xcc,0x20,0x12,0x0f,0x34,0x03,0xfa,0x0f,0x88,0xbd,0x00,0x1e,0x3e,0x30,0x7d,0x42,0xf0,0x10,0x18,0x87,0x9c,0x1f,0x70,0x08,0x16,0x43,0xfe,0x0f,0xaf,0x5c,0x02,0x18,0x0f,0xc8,0xdc,0x0e,0x20,0x0f,0xc8,0x5c,0x31,0x7a,0x37,0xf0,0x7d,0xa3,0xc6,0x81,0x3f,0x37,0xdc,0x82,0x01,0xc0,0x49,0x09,0xff,0x61,0x00,0xfa,0x97,0x9f,0xc6,0x00,0x32,0x10,0x7d,0x40,0x20,0xc0,0xfc,0xaf,0xc0,0x23,0x0f,0x01,0x07,0xd6,0xfe,0x01,0xe0,0x07,0xe5,0xfc,0x7c,0x30,0xf0,0x7d,0xff,0xe0,0x41,0xe2,0x07,0xdc,0x14,0x1f,0xd0,0xd0,0x7f,0x45,0x45,0xfe,0x0f,0xf0,0x7f,0x17,0xd3,0xf4,0x7f,0x98,0x18,0x3f,0xc1,0xe7,0xf4,0x57,0xc8,0xbd,0x01,0xff,0xe8,0x6f,0xc8,0x3d,0x3a,0x0f,0xf9,0x67,0x88,0x00,0xb4,0x00,0xf8,0x8b,0x83,0xd2,0x80,0x0f,0x88,0x48,0x3d,0x30,0x1f,0xc0,0x6a,0xe3,0xef,0xf0,0x60,0x7a,0x40,0x3e,0x60,0xf5,0xbb,0xe0,0x20,0x20,0xf4,0x80,0xf3,0x01,0xeb,0x8b,0xbf,0x82,0x84,0x1e,0x93,0x0c,0x00,0x3d,0x21,0x60,0xa2,0x07,0xa7,0x02,0xfe,0x0f,0xd2,0x88,0xff,0x81,0xe6,}; -const uint8_t _A_Levelup1_128x64_1[] = {0x01,0x00,0x02,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2f,0xf8,0x17,0x59,0xfe,0xf8,0x6b,0x37,0xf9,0xf0,0x32,0x7e,0xc1,0xac,0x02,0x19,0xff,0xfe,0x03,0xfc,0x11,0x5c,0xfe,0x7f,0xfe,0xf1,0x8c,0x2e,0x3d,0xce,0x80,0xe7,0x3e,0xff,0x90,0x7c,0xc3,0xe6,0x10,0x0b,0x07,0xfb,0xf0,0x61,0x8c,0x7c,0x3e,0x19,0x00,0xc0,0x43,0x6f,0xc1,0xe8,0xbf,0xe3,0xa0,0x50,0x08,0x04,0x0a,0xfe,0x83,0x7f,0xdf,0xf6,0x09,0x01,0x07,0x8e,0x11,0x25,0x1f,0x7f,0x7e,0x00,0x1c,0x30,0x09,0x41,0xfd,0xc0,0x03,0x1f,0xa0,0x03,0xca,0x21,0xfe,0x30,0x45,0xfe,0x90,0x0f,0x3f,0xe7,0xf4,0x1e,0xff,0x79,0x00,0x3c,0xa4,0x1b,0xc4,0xf4,0xca,0x01,0xe5,0xa0,0xfc,0x03,0xe6,0x20,0x0f,0x2a,0x00,0x3c,0x7c,0xef,0x96,0xbf,0xcc,0x81,0xc3,0xf8,0x07,0x93,0x0d,0xaf,0xbf,0xf5,0x70,0xc0,0x20,0x94,0x1d,0xc4,0x3f,0xf9,0xef,0x08,0x2f,0xf0,0x7e,0x5e,0x2c,0x17,0xf3,0xee,0x6f,0x89,0xc0,0x3c,0xb0,0x7f,0xc7,0x93,0x83,0x87,0xf1,0x07,0x80,0x79,0x70,0xbf,0x80,0x7b,0xc9,0xe0,0x13,0x86,0xf8,0xff,0x70,0xbc,0x0f,0x80,0x3d,0xb0,0xfa,0x18,0xe1,0x40,0x7f,0xb0,0x58,0x4f,0xf3,0xff,0xdf,0x08,0x2c,0x0e,0x18,0xc0,0x10,0x78,0xc0,0x7f,0xdb,0xfd,0xf8,0x3d,0x74,0x70,0x4c,0x04,0x07,0xfb,0x03,0x84,0xe3,0xfe,0xe0,0xf6,0x87,0xf9,0x20,0x10,0x6f,0xd4,0x0b,0x03,0xe7,0xf9,0xf7,0xce,0x47,0x7b,0xbf,0x67,0xe2,0x90,0x38,0x05,0xfe,0x03,0xc9,0xff,0xfe,0xfd,0xee,0x23,0x9f,0xff,0x27,0xd0,0xc2,0xf8,0xfc,0x20,0x18,0x16,0x6b,0xff,0xf3,0xf0,0xe6,0x81,0xca,0x7c,0x00,0xf5,0x22,0x0c,0x02,0x15,0x20,0x07,0x94,0x04,0x1e,0xd7,0xf8,0xfe,0x82,0x14,0x6f,0x10,0x00,0xea,0x51,0xe3,0xf3,0x08,0x26,0x7a,0x03,0x12,0x37,0x88,0x7c,0x91,0xe3,0xe7,0x3f,0xb4,0x48,0xde,0x21,0xf2,0xff,0x7f,0xf9,0xe7,0xf6,0x91,0x40,0x2f,0x01,0xf2,0x07,0xba,0x58,0x68,0x43,0xe2,0x0f,0x88,0xbc,0x7d,0xff,0xb0,0x79,0xf3,0xe1,0x78,0x20,0x79,0xc0,0x47,0xc2,0x8f,0x43,0xf0,0xe8,0xe0,0x44,0xe2,0x0f,0x8f,0xdf,0xc6,0xae,0x35,0x28,0xb7,0xc6,0x05,0x02,0x07,0x97,0x07,0xff,0xf1,0x17,0x20,0x10,0x74,0xe0,0xe3,0x80,0x72,0x67,0xff,0x82,0xf2,0xfc,0xe1,0xec,0xe1,0x00,0x15,0x0a,0x1e,0x60,0x12,0x72,0x70,0xe5,0xe0,0xf4,0x85,0x41,0x83,0xcb,0x37,0x83,0xe1,0xc5,0xe9,0x04,0x81,0x07,0xc7,0xde,0x0f,0x2a,0x5c,0x3b,0x40,0x0f,0x4d,0x24,0x83,0x3d,0xbf,0x30,0x1e,0x2e,0x39,0x40,0x07,0xa4,0x22,0x01,0x67,0xcf,0x8b,0xce,0x17,0x83,0x91,0x03,0xd2,0x61,0x2a,0xcc,0xf3,0x81,0xe9,0x1c,0x8c,0x03,0xd3,0x81,0x00,0xc3,0x18,0x12,0x2f,0xe0,0x83,0x83,0xd2,0x01,0xff,0xc0,0x83,0xd4,0x12,0x20,0xf5,0x80,0x60,0x01,0xe2,0x50,0x29,0x78,0x3d,0x98,0x63,0x40,0x48,0xa0,0x3e,0xac,0xc0,0xf3,0xa0,0x83,0xe2,0x41,0xc0,0x3f,0x9e,0x04,0x1f,0x3e,0x0f,0xc8,0x80,0xa0,0x60,0x81,0x07,0xb6,0x42,0x85,0xfc,0x0f,0x90,}; -const uint8_t _A_Levelup1_128x64_2[] = {0x01,0x00,0xc1,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x3f,0xe4,0x1f,0xdf,0x40,0x43,0xf3,0xc0,0xa9,0x7f,0xfb,0x03,0xdf,0x66,0x05,0x4d,0xff,0xbc,0x1e,0xf3,0xbf,0xf0,0x14,0xe3,0xf7,0x8f,0xf7,0xc4,0x1e,0xb1,0x3f,0xe0,0x14,0xe1,0xf9,0x02,0x0b,0xc5,0xc1,0xeb,0xcc,0xff,0x03,0xda,0x1e,0x0f,0x48,0x3f,0xbf,0xfd,0xf8,0x07,0xad,0xfc,0x1e,0x57,0xff,0xf4,0x0f,0xe7,0xff,0x07,0xaf,0x8e,0xff,0xf8,0xed,0xc7,0xee,0x1f,0xc8,0x18,0x34,0x41,0xeb,0xc3,0x9f,0xfc,0x3f,0x70,0xfe,0x07,0xfe,0x01,0x9c,0x0b,0x88,0x88,0x41,0xe7,0x1f,0xc8,0x5f,0xe0,0x7c,0x08,0x7c,0x03,0xf9,0x7f,0x9e,0x07,0xd3,0x8f,0x17,0x80,0x7e,0xe0,0x2f,0x71,0x85,0x7f,0xa7,0xf1,0xe0,0x7a,0x63,0xe7,0xf0,0x09,0x99,0x34,0x42,0x03,0xfb,0x9f,0xa5,0xd3,0xf1,0x3f,0xbf,0xc1,0x38,0x10,0x1c,0xe6,0xaa,0x04,0x1f,0x10,0xf2,0x7e,0x26,0xff,0x88,0x74,0xc2,0x01,0x60,0x0f,0x8d,0xfc,0x5c,0x2c,0x23,0xff,0x4c,0xed,0x18,0xe8,0x64,0x03,0x01,0xa9,0xc1,0x5e,0xf3,0xc1,0xf4,0x9f,0xcc,0xf8,0x10,0x48,0x10,0x74,0x60,0x58,0x0b,0xfe,0x32,0xfe,0xbe,0x50,0x78,0x97,0x8b,0x49,0xc0,0xf7,0xe0,0x14,0xc4,0xbe,0x3c,0x06,0x00,0x1c,0x30,0x08,0x46,0x02,0x78,0x0f,0x20,0x01,0xdf,0xb0,0x14,0x00,0x79,0x64,0x21,0x41,0x11,0x07,0x23,0x30,0x60,0x00,0xf3,0x88,0x00,0x87,0x81,0xbf,0x07,0x9e,0x73,0xdf,0x01,0x90,0x03,0xcb,0x40,0x53,0x19,0x02,0x3d,0x23,0x3f,0xf0,0x7a,0x00,0xc8,0x1e,0x5c,0x70,0x78,0xc6,0xb9,0xd0,0x11,0x59,0x0c,0xc7,0x51,0x0a,0x80,0x03,0x07,0x16,0x02,0x13,0xc0,0x83,0xd4,0x04,0x38,0xef,0xff,0x8f,0xfa,0x0f,0x18,0x3a,0x6c,0x43,0x22,0x00,0x1c,0x06,0xaa,0x14,0xd9,0x1f,0x38,0xfc,0xa1,0xa4,0x81,0x84,0x03,0xcc,0x02,0x3f,0xf0,0x71,0x80,0x06,0x02,0x1f,0x5d,0x14,0x2b,0xf0,0x0f,0x51,0x80,0xc1,0x01,0xe5,0x00,0x0b,0x0f,0xe7,0xf6,0x0f,0x5c,0x50,0x3d,0x35,0x3e,0x07,0x59,0x03,0x8a,0xff,0x0f,0x80,0x51,0x13,0xe7,0x01,0xf8,0x7b,0xff,0xa0,0xf2,0x87,0xff,0xe3,0xd2,0x8e,0x20,0x3c,0xa3,0x1a,0x9f,0x87,0x1e,0xff,0xde,0xc7,0x8b,0x47,0xd2,0x1f,0x10,0x7a,0x07,0xc7,0x8f,0x3f,0xff,0x61,0xff,0xff,0x7e,0xfc,0x1f,0x40,0x1f,0x5f,0x07,0x9d,0xfa,0x3e,0x37,0xf9,0x87,0xc6,0x02,0x0f,0x18,0xe4,0x07,0x80,0x0c,0x24,0xf9,0x14,0x04,0x3e,0x31,0xf7,0x58,0xc7,0xf5,0x38,0x0f,0x1b,0xbd,0x00,0x03,0x00,0xc2,0x03,0xca,0x1e,0x23,0x1f,0x80,0x28,0x73,0xe0,0x21,0xf9,0xff,0x70,0x30,0x41,0x90,0xe0,0x20,0xfa,0x98,0x17,0xf3,0xee,0x0f,0x2f,0xe7,0x83,0xdf,0x01,0x4f,0xac,0x03,0xfc,0x0f,0x10,0xe8,0xa4,0xc9,0x5e,0xba,0x96,0xf8,0x87,0x87,0xcf,0xf1,0xff,0xf1,0xe7,0x80,0xf1,0x88,0x3f,0x88,0x3e,0x3f,0xfe,0x7f,0x7f,0xcf,0xf9,0xff,0xc0,0xa3,0x1a,0x08,0x24,0x82,0x00,0x01,0x1d,0x4e,0x0b,0x3f,0xc7,0xf3,0xfc,0xff,0x9f,0xf9,0x08,0xa8,0x41,0xe8,0xdf,0x18,0x7f,0x07,0xcf,0x78,0x1e,0x8d,0xfe,0x00,0x1f,0x5c,0x0c,0x2a,0x0f,0xe0,0xbb,0xc7,0x0f,0xc7,0x00,0x83,0x0f,0x44,0x82,0x30,0x30,0x38,0xf8,0x22,0x78,0x00,0x70,0xf3,0xf0,0x1a,0xa0,0x7a,0x60,0xe1,0x50,0xaf,0x84,0x07,0xc0,0x0f,0x1d,0xb8,0x5c,0x60,0xbc,0x06,0x70,0x81,0x06,0x01,0x60,0xf0,0x28,0x85,0x64,0x34,0xad,0x46,0x2a,0x09,0x80,0xfc,0xc3,0x20,0x18,0x9d,0x56,0x48,0x32,0x3f,0x80,0xf8,0xe2,0xa0,0x36,0x00,0x78,0xc1,0xd6,0x23,0x31,0x80,0x63,0x01,0xe3,0xb8,0xfd,0xff,0xe1,0x10,0xe8,0xc2,0x7c,0x56,0x45,0xc1,0xc0,0x60,0xe0,0x52,0xae,0x41,0xb8,0x61,0x1f,0x08,0x38,0x30,0x60,0xc5,0xd1,0x80,0xdf,0xf0,0x06,0x12,0x17,0x89,0x64,0x57,0xe5,0xf8,0x60,0x9d,0x03,0x44,0x61,0x10,0x7b,0x00,0x10,0xea,0x25,0xf1,0x07,0x8a,0xbc,0xc1,0xeb,0xa0,0xd5,0x42,0x97,0xc3,0xff,0x54,0x88,0x3d,0xc1,0x25,0xfe,0x5f,0x88,0x94,0x80,0x0d,0x90,0xd5,0x4a,0x81,0xc3,0xfe,0xce,0x03,0xe2,0x10,0x1f,0x2f,0xff,0xe2,0x7f,0x01,0x06,0xa8,0x18,0x74,0x83,0xf1,0xfb,0x7f,0xff,0x33,0xf8,0x30,0xfd,0x41,0xe2,0xe1,0x25,0x79,0x41,0xcf,0x62,0x0f,0x5f,0xc6,0xa3,0x55,0x8a,0x07,0x90,}; -const uint8_t _A_Levelup1_128x64_3[] = {0x01,0x00,0x0a,0x03,0x8f,0xc0,0xb8,0x1f,0xfb,0xfd,0xe2,0x7f,0xf8,0x02,0x0f,0xff,0xff,0x03,0xff,0x00,0xc6,0xff,0x36,0xe0,0x47,0xfd,0xff,0x08,0xff,0xf3,0xff,0x3f,0x05,0x8f,0xf0,0x1e,0x5f,0xf8,0xfe,0x02,0xfb,0xff,0xf8,0x43,0xff,0x99,0xfd,0xf8,0x44,0x81,0xe7,0x17,0x88,0x7d,0x37,0xe0,0xf2,0x87,0xe7,0xff,0xe0,0x11,0xfe,0x83,0xca,0x1f,0x20,0xf8,0x0f,0x46,0x0f,0xfe,0x83,0xf6,0xff,0xfc,0xf0,0xfa,0x47,0xec,0x1e,0x08,0xf8,0x3c,0xa0,0x7c,0x3f,0xff,0x9c,0x1e,0x93,0xf8,0x06,0x02,0x1f,0xf8,0x2c,0x8c,0x07,0xc1,0xff,0xfd,0x83,0xdb,0xc1,0x07,0xfc,0x40,0x6f,0xda,0x0d,0x47,0xff,0xf2,0x0f,0x4b,0xf8,0x7c,0x60,0xda,0x88,0x0c,0x72,0x01,0xb0,0xff,0xe0,0x01,0xe9,0xff,0x80,0x68,0x21,0xff,0xa9,0x06,0x02,0x01,0xf2,0xbf,0x40,0x12,0x44,0x1f,0x2b,0x82,0xa1,0x7d,0x11,0xf8,0x05,0xf8,0x1e,0x74,0x7f,0x80,0xc0,0x75,0x50,0xa8,0x04,0x83,0xf0,0x0f,0x1b,0xe1,0x48,0x6f,0xfb,0x78,0x38,0x3c,0x40,0x09,0xfc,0x81,0x83,0xcb,0xfb,0xbf,0xbf,0xcb,0xbe,0x1a,0x8d,0x56,0xaa,0x55,0x80,0x85,0x18,0xc4,0x5e,0xb3,0xce,0x00,0x7d,0x7b,0x80,0x21,0xdf,0xcf,0xef,0xee,0x72,0x2f,0x8e,0xaa,0x01,0xa8,0xd1,0x62,0xa7,0xfa,0x0c,0x06,0x7d,0x82,0x33,0x8f,0x3d,0xfe,0x04,0x18,0x15,0x68,0xc0,0x1e,0xa2,0x02,0x1f,0x0f,0xff,0xbf,0x3f,0xe3,0xcf,0xc7,0x63,0xca,0xd5,0xe7,0xb5,0x58,0xa8,0x3e,0xa3,0x80,0x8e,0x29,0xfe,0x3c,0x2e,0x30,0x0b,0x85,0x56,0xea,0x73,0x11,0x10,0xd8,0x01,0xe5,0xcf,0x9f,0xcf,0xf5,0x50,0x2d,0x61,0x80,0x75,0x38,0xa2,0x28,0xda,0x09,0x63,0x9f,0x1f,0x0c,0xf8,0x3e,0x35,0x6a,0xad,0x54,0x3a,0x20,0x01,0xba,0x7f,0xf7,0xf9,0xff,0xbc,0xfe,0x7c,0x9c,0x1d,0x58,0x7c,0x74,0xd0,0xad,0x16,0xab,0x71,0xbf,0xef,0xfb,0xc1,0xe3,0x0c,0x1d,0x08,0x78,0x6a,0xb0,0xd0,0xf9,0x66,0x3f,0xbf,0xff,0x3f,0x9c,0x9c,0x3a,0x8e,0x50,0x78,0x75,0x59,0xa8,0x50,0x0c,0x7c,0x9f,0xff,0xcf,0x9f,0xe3,0x07,0x0b,0x8d,0x00,0x3e,0x51,0x50,0xf9,0x7c,0x3e,0x7f,0x99,0x3f,0xe2,0x0f,0x2a,0x5f,0x10,0x00,0xb1,0x4c,0x31,0xf8,0x7c,0x77,0x10,0x3f,0xe4,0x3c,0x2e,0x36,0x00,0xf9,0x4d,0x43,0xe5,0xe0,0x9c,0xfb,0xa0,0x7e,0x88,0x78,0x68,0x76,0x41,0xe2,0xb5,0x17,0x86,0x05,0xf8,0xcc,0x7f,0xe0,0x3f,0xc8,0x30,0x5c,0x6a,0x01,0xf2,0xaa,0x87,0xcb,0xf1,0xc2,0xff,0xc0,0x00,0x22,0x3e,0x50,0x01,0x42,0xaf,0x1d,0x09,0xfe,0x00,0x1e,0x20,0x01,0xac,0x07,0x8b,0xaa,0x07,0x29,0xe7,0x0a,0x1e,0x0f,0x20,0xfc,0x4a,0xa7,0x9e,0x85,0xa8,0xf0,0xc2,0xe5,0x54,0x1f,0x9c,0x04,0x3e,0x5e,0x00,0x18,0xf1,0xe0,0x3a,0x06,0xf1,0xb8,0x08,0x7e,0x33,0x8a,0x04,0x02,0x51,0xe3,0x4f,0x90,0x7d,0xc0,0x07,0xfa,0x80,0x68,0xe1,0x5e,0xc0,0xf1,0x6e,0x83,0xe4,0x0e,0x28,0x57,0xe3,0xce,0x18,0x1e,0xa0,0x78,0xab,0xa1,0xf6,0xfc,0x7f,0xf0,0x72,0xa0,0xfa,0xca,0xa5,0x50,0x08,0x46,0x01,0x46,0x3f,0xf3,0x18,0x87,0xf3,0xbf,0x00,0xd5,0x7b,0x37,0xfa,0xaf,0x56,0xff,0x53,0x82,0x0f,0x8c,0x83,0x51,0x02,0xff,0x5f,0xc2,0x63,0xd4,0xaf,0xa7,0x86,0xbe,0x1f,0x6d,0xf5,0xff,0x51,0x2a,0xd6,0x6b,0xc7,0xe3,0xaf,0xd4,0xe0,0x03,0xe2,0x06,0x18,0x17,0xf2,0xf6,0x7f,0xd2,0x78,0xea,0x21,0x49,0xf4,0x80,0xe0,0x35,0x40,0x11,0x0f,0x97,0xfc,0x30,0x21,0xfb,0xbf,0x43,0xc3,0xed,0x81,0x0e,0x90,0x7c,0xa7,0xd1,0xf1,0xf9,0x5d,0x6a,0xa0,0x11,0x0f,0xb4,0xf2,0x7c,0x57,0x16,0xfa,0xe2,0x80,0xa7,0x00,0x9c,0x07,0xca,0xac,0x3f,0x35,0x30,0x80,0x19,0x6e,0x3a,0xef,0x52,0xf8,0x75,0x5a,0xbd,0x10,0x80,0x90,0x43,0xe0,0x98,0x04,0x45,0x3a,0x2b,0xe1,0xaa,0xc1,0x60,0x16,0x00,0xe9,0xfd,0x2d,0x1a,0xac,0x56,0xbb,0x55,0xfb,0x01,0x0e,0x2f,0x45,0xb2,0x0f,0x8c,0x2a,0x01,0xfc,0xec,0x40,0x6c,0x01,0xf1,0xab,0xb0,0x46,0x6b,0x00,0xee,0x27,0xd3,0x51,0x0e,0xdc,0x07,0x07,0x56,0x02,0x1f,0x5e,0x03,0x56,0x1f,0x1d,0x04,0x2b,0xfd,0x59,0xfa,0xd5,0xcb,0x83,0x57,0x01,0x95,0xff,0xaa,0x1f,0x3f,0xfe,0xdc,0x2a,0x21,0xc1,0xfd,0x1e,0xce,0xd5,0x0a,0x85,0x10,0x06,0x7b,0x53,0x3e,0x18,0x01,0x43,0xe7,0xc0,0x7d,0x90,0x7c,0x40,0x09,0x2a,0x94,0x4a,0x17,0xe3,0xe3,0xb5,0x87,0xa0,0xc2,0x20,0x01,0xc0,0x78,0x7b,0xe1,0xc5,0x00,0x16,0x68,0x42,0x3a,0xae,0x17,0xc7,0x3e,0x1f,0x88,0x68,0xf8,0xfe,0x10,0x13,0xb1,0x00,0x0c,0x0c,0x3a,0x65,0x48,0x8f,0xc7,0xf0,0xdd,0x57,0x0c,0x7f,0x14,0x22,0x5f,0x5d,0x5f,0xeb,0x51,0xaa,0xd1,0x07,0xc7,0xf8,}; -const uint8_t _A_Levelup1_128x64_4[] = {0x01,0x00,0x7e,0x02,0xff,0x80,0x3c,0x01,0xf1,0xff,0xe0,0x3f,0x7d,0xff,0xd1,0x0f,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2d,0xff,0xee,0x0f,0xef,0x47,0xff,0xfc,0x06,0x2d,0xf8,0x3d,0xe0,0x3e,0x49,0x3f,0xc0,0xfc,0x7f,0x8f,0xfc,0xed,0x02,0x37,0xff,0xc5,0xbe,0x01,0xf0,0xaf,0xe0,0xc1,0xe7,0xe0,0xff,0xc0,0xc2,0xe3,0x1f,0xf8,0x4f,0xe0,0x17,0x0b,0xf5,0x81,0x34,0x40,0xf1,0xb8,0xc1,0x38,0x1f,0xd8,0x3f,0xe2,0x73,0x00,0xf7,0xc7,0xe4,0x02,0xb1,0xff,0xcf,0xf0,0x02,0x81,0xc0,0x77,0xe0,0x37,0xf8,0x47,0x82,0xff,0x0e,0x6e,0x1c,0x1d,0xc4,0x3e,0x08,0x0d,0xfb,0x80,0x2e,0x1f,0x00,0x08,0x60,0x06,0x02,0xc3,0xc0,0x41,0x23,0x81,0x04,0x89,0x38,0x6c,0x11,0xfc,0x04,0x3c,0x1e,0x3f,0x78,0x3c,0x0e,0x01,0xc0,0x83,0xff,0xa0,0x60,0x52,0x8c,0x88,0x45,0x00,0x63,0x02,0xe2,0x6a,0xe3,0xc0,0x41,0x00,0x09,0xf8,0xd2,0x63,0x4f,0x04,0x1d,0xfc,0x1e,0x65,0xd2,0x01,0x09,0xc8,0x60,0xd0,0x0d,0x66,0xab,0x54,0x45,0x10,0x00,0xfb,0x3f,0xff,0x3f,0x8f,0xcf,0xd9,0xf9,0x87,0xd4,0x06,0xc5,0x03,0x8a,0x03,0xc7,0xf9,0xcf,0xf3,0xdf,0xfc,0xfc,0x4f,0xfc,0x2e,0x01,0xab,0x0f,0x88,0x90,0x45,0xe5,0x87,0x1f,0x94,0x02,0x9f,0x08,0xca,0x01,0x8a,0x9f,0x15,0x07,0x8d,0xe3,0x80,0x0f,0x30,0xc8,0xf0,0x03,0xc3,0xaa,0x8d,0x14,0x13,0x9f,0xfb,0x07,0x8c,0x02,0x21,0xd0,0x0b,0x15,0x7e,0x2a,0x51,0x1b,0x07,0xfb,0xcd,0xff,0xe1,0x9f,0x8b,0x40,0x1f,0x29,0x50,0x78,0xa7,0x93,0x9c,0x87,0xfe,0x03,0x1f,0x5f,0x90,0x7c,0xa7,0xf5,0x5a,0x84,0x07,0x7c,0x95,0x1f,0xbb,0x48,0x41,0xe3,0xb0,0x0f,0x95,0xa8,0x3e,0x51,0xe7,0x00,0xdf,0xe6,0x0a,0xf1,0x82,0x29,0xce,0xff,0x55,0xaa,0xc0,0x60,0x90,0x0c,0x04,0x7f,0xfd,0xfd,0x20,0x0e,0xa0,0x3e,0x5a,0xa2,0xf9,0x9a,0x47,0x8e,0x19,0x14,0xf0,0xfe,0x58,0xe7,0x54,0xaa,0x84,0x13,0xdf,0xfb,0x12,0x88,0x7e,0x4b,0x43,0xe3,0xb7,0xc0,0x2a,0x9f,0xd0,0xf9,0x8f,0xc5,0xe4,0x9c,0x38,0x18,0x10,0x5b,0xc4,0xe0,0x50,0x79,0x60,0x40,0x63,0x40,0x0f,0xbd,0x50,0x26,0xaf,0x71,0x0f,0x16,0xe8,0x16,0xd1,0xfb,0x85,0xc2,0x00,0x1f,0x50,0x80,0xd5,0x22,0x20,0xf1,0xff,0x7e,0x3f,0x01,0xfb,0xec,0x7f,0xef,0x12,0x08,0x07,0xf0,0x3e,0x71,0x58,0x24,0x16,0x28,0x1e,0x20,0x40,0xf8,0xe0,0x3e,0xcd,0xfe,0xab,0xd5,0xbf,0x0f,0xad,0x6d,0x3e,0x41,0xf5,0xa8,0xd5,0x60,0xa0,0x11,0x67,0x8e,0xfa,0xfe,0x0f,0x1d,0x66,0xbc,0x7e,0x3a,0xf0,0xfa,0xff,0xe3,0xe0,0x11,0x0f,0xad,0x56,0x8b,0x41,0xaa,0xc5,0x60,0x1f,0xb8,0x4e,0x5c,0x1e,0x29,0xf9,0xe0,0x7f,0xe1,0xb1,0xf8,0x7a,0xfd,0xc3,0xe3,0x05,0xb0,0x43,0xf8,0x17,0xf6,0xf8,0x87,0xe6,0x61,0x04,0xf0,0x46,0x20,0x15,0x50,0xfc,0x04,0xca,0xe4,0x15,0x26,0xfd,0x40,0x22,0x00,0x21,0xa8,0xa5,0x08,0x00,0x35,0x3a,0xad,0x50,0xbc,0x20,0x01,0xb0,0x00,0xcb,0x5d,0xea,0x5f,0x0e,0xaa,0x06,0x1f,0x5f,0xc4,0xc2,0x01,0x15,0x0f,0x1f,0xfe,0xaf,0x55,0xb2,0x9f,0xc8,0x1e,0x36,0x88,0x06,0x03,0x5d,0xaa,0xfd,0x80,0x86,0x17,0x00,0xd8,0x07,0xcf,0xdd,0xf9,0xa8,0xf9,0x43,0xe9,0x3f,0xaa,0xff,0x08,0x02,0x61,0x1f,0xf6,0xae,0x1d,0xb8,0x0e,0x0e,0xac,0x04,0x3e,0xbc,0x06,0xac,0x3c,0x58,0x0f,0xff,0xec,0x3a,0x80,0x04,0xaa,0x20,0xc7,0xc1,0x4f,0xd9,0x9e,0x84,0x38,0x3f,0xa4,0x09,0xda,0x87,0xe7,0x08,0xfb,0x87,0xa2,0xff,0x55,0xa8,0x18,0x0b,0x4e,0x1f,0x30,0x02,0x4a,0x90,0x09,0xef,0x0f,0xc1,0x84,0x60,0xb4,0x16,0xe0,0xf7,0x43,0x8a,0x00,0x28,0xd0,0x7d,0x0c,0x22,0x00,0x7a,0x79,0x78,0x55,0x62,0x10,0x1d,0x58,0x75,0x40,0xc3,0x06,0x60,0xab,0x75,0x1c,0x2b,0x55,0xa0,0xb0,0x4c,0xbe,0xba,0xbf,0xd0,0x79,0x40,}; -const uint8_t _A_Levelup1_128x64_5[] = {0x01,0x00,0x79,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1f,0xff,0xfb,0xcf,0xc0,0xc9,0xf0,0xf1,0x84,0x1e,0xff,0xfe,0x80,0xff,0x3f,0xb7,0xbf,0xe7,0x3c,0x1c,0xdb,0xff,0xfc,0xff,0xfc,0x1b,0x80,0x02,0x73,0xf5,0xf9,0xf8,0xff,0xff,0x8f,0x9f,0xfc,0x0b,0xde,0xe5,0xdd,0xba,0xf3,0xbe,0x3c,0x78,0x08,0xf5,0xe6,0x3a,0xcd,0x56,0xaa,0xc3,0xf0,0xa7,0xe0,0x3f,0xff,0xe1,0xf2,0x5f,0x20,0x15,0x6a,0xad,0x57,0x07,0xf3,0x87,0xf8,0x3f,0xfe,0x11,0x02,0x4d,0xe0,0x1a,0xbd,0x76,0xaf,0x0d,0xff,0x80,0x7c,0x3f,0xbc,0x70,0x7a,0x4f,0xf0,0x41,0xe1,0xaa,0xfb,0x67,0xf0,0x02,0x70,0x9c,0x4c,0x7c,0x33,0xfe,0x3e,0xa8,0x3e,0x31,0xa8,0x78,0x3c,0x89,0xc9,0xd0,0xff,0xd1,0xea,0xb5,0x7a,0xbc,0x56,0x01,0x00,0xfe,0x03,0xd4,0x2c,0x3a,0xf2,0xf0,0xea,0xa5,0x40,0xf1,0x9c,0x1f,0xdb,0x1f,0x67,0x0f,0x94,0xd6,0x01,0x04,0x80,0x18,0x07,0x7f,0xef,0x07,0x94,0x3f,0x64,0x1f,0x2b,0x50,0x7c,0x46,0x25,0xfd,0xef,0xb7,0x47,0x3f,0x0c,0xa8,0x07,0xc8,0xc2,0x30,0x10,0x78,0xfc,0x08,0x09,0x18,0xd4,0x6a,0x90,0x03,0xaa,0x06,0x8c,0x70,0x60,0x47,0xd2,0xff,0xcc,0xfb,0x01,0xd2,0xef,0xd5,0x20,0x37,0xf0,0x78,0xfe,0xc2,0x05,0xc7,0x83,0xfa,0x35,0x46,0x21,0xdd,0x40,0x30,0x10,0xfc,0x63,0xd4,0x5f,0x03,0xef,0x07,0x8d,0xd7,0xab,0x55,0xae,0xdd,0x6a,0xb8,0x58,0x7e,0xff,0xce,0x1d,0x12,0x10,0xfc,0xe0,0xfa,0xcf,0xd6,0xa8,0x02,0x24,0xe1,0x81,0xb7,0x84,0xdc,0x57,0xf9,0x7c,0x02,0xab,0x75,0x00,0x0d,0x56,0x82,0x10,0x10,0x78,0xc3,0xde,0x25,0x06,0x3b,0x0e,0xeb,0x55,0xea,0xfd,0x1b,0x8a,0xff,0x7f,0xbf,0x2c,0xc7,0xe7,0x0e,0x80,0x75,0x2a,0xb7,0x7a,0xbd,0x76,0x8b,0x05,0x80,0x06,0xc6,0xf8,0xb2,0x1b,0x1a,0x58,0x83,0xec,0x6e,0x41,0x70,0xd5,0x0b,0xc2,0x00,0x10,0xf9,0x08,0x04,0x7a,0x5f,0xf8,0x60,0x7c,0xb7,0xe1,0xf1,0xff,0x87,0xca,0x01,0xfd,0x07,0x96,0x26,0x07,0x40,0xfa,0xb1,0x47,0xbf,0x7f,0xa2,0xb0,0x0b,0xf1,0x7f,0x10,0x8f,0x82,0x0f,0x00,0xd6,0x7b,0xcf,0xe3,0xaf,0x0f,0x96,0x03,0xff,0x39,0xff,0x63,0x7f,0xf1,0xf3,0xf9,0x00,0x4a,0x82,0x01,0x1c,0x07,0x7c,0xc4,0x38,0x71,0x88,0xc0,0x75,0x83,0xf2,0x0f,0x9c,0x02,0x0c,0x21,0x17,0x01,0x41,0xea,0x85,0xf2,0x00,0x12,0x84,0xb0,0x0d,0x11,0xff,0xcf,0xa0,0xba,0xcd,0x50,0x00,0x83,0xe7,0x00,0xe0,0x7c,0x57,0xe3,0x78,0x9c,0x55,0x07,0xe7,0x55,0x8a,0xd0,0x02,0x43,0xe0,0xfe,0x7d,0xff,0xfe,0x9b,0xc0,0x7e,0x60,0x13,0x07,0x01,0x5e,0x2a,0xc3,0xd3,0x43,0x0a,0x04,0x42,0x05,0x8c,0xc1,0xc7,0xfe,0x1a,0xef,0x56,0xa9,0x82,0x30,0x30,0xfa,0x08,0x4a,0x1d,0x40,0xaa,0xb0,0x06,0xbb,0x55,0x82,0xd4,0x2c,0xa4,0x21,0x80,0x7c,0x20,0x76,0x83,0x20,0xeb,0xb5,0x5f,0xb0,0x10,0xc2,0xe0,0x1b,0x00,0xe9,0x2c,0x47,0xb1,0x01,0x0b,0x8f,0x56,0xaf,0x5f,0xaa,0xcd,0x6a,0x9d,0xca,0xa3,0x84,0xf5,0x10,0xed,0xc0,0x70,0x75,0x60,0x21,0xf5,0xe0,0x35,0x6c,0x13,0xbf,0x56,0xfe,0xb5,0x72,0xe0,0xd5,0xc0,0x65,0x7f,0xea,0xd1,0x20,0x14,0x0f,0x84,0xff,0x6e,0x7a,0x10,0xe0,0xfe,0x90,0x27,0x6a,0x1f,0x97,0x82,0x7e,0x19,0x20,0x03,0x8f,0x86,0x01,0xe7,0xbf,0xeb,0x43,0xe6,0x00,0x49,0x50,0x38,0x7f,0x9c,0xff,0xfd,0xbc,0x3d,0x13,0x5a,0xa9,0x38,0x78,0xf9,0xce,0xf0,0x71,0x40,0x05,0x1a,0x2f,0x0f,0x7f,0xff,0xf9,0xd8,0x07,0xe2,0x9b,0x50,0x80,0x33,0x47,0xc7,0x00,0xd5,0x87,0x54,0x0c,0x30,0x61,0xf8,0xdf,0xfe,0xc0,0xf1,0x6e,0xa3,0x85,0x0c,0x03,0x1c,0x10,0x0a,0xc8,0x4b,0xeb,0xab,0xfd,0x37,0x4e,0x77,0xfe,}; -const uint8_t _A_Levelup1_128x64_6[] = {0x01,0x00,0x38,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0x5f,0x78,0x37,0x20,0x3f,0xc0,0x7e,0x4f,0xff,0xde,0x3e,0x38,0xae,0xf9,0xf0,0x5c,0xe8,0x7e,0xf8,0xf3,0x3c,0x45,0x83,0xdc,0x1f,0xb8,0x6e,0x23,0x01,0xfd,0x1f,0xdc,0x0a,0x09,0x01,0xfd,0x03,0xaa,0xff,0x01,0x07,0x8f,0xd0,0x1f,0x5b,0xf8,0x00,0x3c,0x7d,0x00,0xfa,0xaf,0x83,0xcb,0xa0,0x0e,0x9f,0xb8,0x3c,0x60,0x50,0x20,0x7d,0xcb,0xc1,0xe5,0xa0,0xdb,0x83,0xe3,0xc6,0x0f,0x4d,0xff,0xdc,0x3f,0x11,0x70,0x79,0x50,0x23,0xe0,0xe7,0xfe,0x83,0xd7,0x7e,0x2f,0x8f,0xe4,0x2e,0x00,0x80,0x1c,0x06,0xf9,0x1b,0x1f,0xcc,0x5c,0x1c,0x1e,0x38,0xfd,0xf6,0x0f,0xbe,0xb3,0x5b,0xfd,0xf2,0x97,0x08,0xff,0xe1,0xf2,0x1e,0xec,0x38,0xfd,0xff,0x12,0x5c,0x84,0x06,0x99,0x20,0xfa,0xff,0x81,0xed,0xfb,0xfd,0xc9,0x6a,0x10,0x0a,0x84,0x80,0x58,0x9e,0xf3,0x7a,0x55,0x66,0x12,0x0b,0x05,0x40,0x1e,0x5f,0x11,0x0b,0x75,0x66,0x12,0x2b,0x15,0x63,0x7a,0x07,0x1f,0x80,0xf4,0xca,0x05,0xd5,0x88,0x48,0xa8,0x55,0x80,0x40,0xdf,0x3e,0x1f,0x30,0x60,0xff,0xb0,0xfe,0x3f,0xf0,0x3d,0x6e,0xf1,0xef,0xc7,0xec,0x40,0x58,0x7e,0x1f,0xbf,0xab,0x11,0x80,0x50,0x2b,0x81,0xf1,0x87,0xff,0x0c,0x49,0x07,0xc1,0xf5,0x63,0xf0,0x0e,0x05,0x7c,0x7e,0x30,0x70,0x71,0x35,0x0a,0x7f,0x02,0xd2,0xe7,0xff,0xfc,0xf9,0x78,0x7c,0x7c,0x7f,0xf8,0xf8,0x44,0xaf,0xb7,0xeb,0x14,0x92,0x9f,0x00,0xe8,0x49,0xf9,0xb3,0xdf,0x01,0x64,0x40,0x42,0x1e,0x1f,0xe5,0xda,0x89,0x30,0x80,0x58,0x22,0x1f,0x58,0xff,0xe2,0xf7,0xfc,0xf0,0x83,0xca,0x01,0x78,0xc2,0x0f,0xca,0x1f,0xfd,0x87,0xff,0xaf,0xbf,0xc1,0x90,0xff,0xe3,0xb0,0x0f,0x84,0x12,0x20,0x5f,0x18,0x07,0xf5,0x56,0x5f,0xcf,0xfe,0xff,0xbf,0x18,0x07,0x94,0x82,0x00,0x01,0x1f,0xe8,0x30,0x7f,0xbe,0xcf,0xf5,0xef,0xfd,0x38,0x83,0x70,0xa0,0xa0,0xf3,0x80,0xfe,0x38,0x56,0xf0,0x90,0xff,0xff,0x31,0x08,0x7c,0x10,0x3e,0x80,0xf1,0xa1,0x9b,0x87,0xef,0xfd,0xf9,0xc0,0x20,0xf1,0x88,0x30,0xf4,0x48,0x23,0x03,0xbf,0x79,0xe0,0x7f,0xe2,0x18,0xfc,0xf8,0x10,0x3f,0x80,0x3d,0x67,0x90,0x18,0x04,0x73,0xf8,0x10,0x1d,0x9c,0x0e,0xe1,0x05,0xe0,0x40,0x0a,0xa3,0x05,0x41,0x8c,0x00,0x04,0x2f,0x21,0xa5,0xc3,0xb2,0x10,0x4c,0x07,0xe6,0x19,0x00,0x84,0xc0,0x32,0x00,0xf1,0x80,0x78,0x3d,0xf8,0xb8,0x0d,0x80,0x1e,0x30,0x78,0x7c,0x02,0x63,0x00,0xc6,0x29,0x87,0xe0,0xb0,0x18,0x5c,0x3a,0x31,0x04,0x2e,0x08,0x08,0x78,0x38,0x0c,0x1e,0xe2,0x01,0xfe,0xf8,0x83,0xc7,0xe1,0x07,0x06,0x0c,0x1a,0x06,0x12,0x1b,0xfe,0x03,0x01,0x0f,0xf7,0x7f,0xfd,0x91,0x71,0xa0,0x83,0xc7,0xf0,0x3a,0x25,0x98,0xf0,0x21,0x69,0x01,0xe0,0x83,0xd0,0x00,0x80,0xf1,0x88,0xf6,0x3f,0x18,0x79,0x78,0x3e,0x14,0x62,0x6e,0x1b,0xc4,0x7e,0x4e,0x0f,0xaf,0x85,0xc7,0xf1,0x3f,0xa1,0x83,0x14,0x00,0x4a,0x31,0xf0,0x40,0xc1,0xe3,0x87,0x07,0xc7,0x20,0x04,0x30,0xee,0x7c,0xbe,0x06,0xb6,0x10,0x02,0x01,0x87,0xe9,0xc3,0x87,0xfe,0x23,0x77,0xc8,0x2c,0x18,0x7e,0xa0,0xf1,0xfd,0xf9,0xe3,0xf7,0x0b,0xdf,0xf0,0xf6,0x40,0xf5,0xfc,0x5c,0x27,0x93,0xc5,0x70,0xff,0xc0,}; -const uint8_t _A_Levelup1_128x64_7[] = {0x01,0x00,0xd0,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x05,0xfd,0x83,0xfb,0xbe,0x20,0xf0,0xff,0x83,0x72,0x01,0xfe,0x07,0xdf,0xf6,0x3f,0xff,0xf8,0x83,0xf3,0xcf,0x03,0xe7,0x40,0xff,0xc0,0xf9,0xfc,0x46,0x61,0x93,0x00,0xfe,0x41,0xa2,0x1c,0x0e,0xf0,0x3e,0xaf,0xb0,0x19,0x06,0x03,0xba,0x0f,0xad,0xfc,0x02,0x81,0x00,0xed,0x83,0xea,0xbe,0x0f,0x2f,0xa8,0x3e,0xa5,0xf0,0x0c,0x04,0x03,0xd4,0x0f,0xdf,0xc7,0xad,0xb5,0x51,0x70,0x78,0xc1,0xfa,0xdb,0xf0,0x84,0xc5,0xff,0xdc,0x08,0x07,0x60,0x3f,0x50,0xb8,0x0c,0x86,0x81,0xb0,0x0f,0xcf,0xef,0x17,0x7c,0x89,0x50,0x37,0x00,0xfa,0xa5,0xe0,0xa1,0x98,0x20,0x7d,0x78,0x28,0xb1,0xd8,0x2e,0x0a,0xa0,0xe3,0x10,0xfc,0x49,0x63,0xf0,0x9c,0x25,0xc2,0x17,0xfa,0x07,0xc6,0x97,0x3d,0x0a,0x82,0x5f,0xc3,0xf3,0xff,0xd2,0xff,0xa1,0x5c,0x0b,0x81,0x3e,0xb4,0x40,0xf1,0x98,0x78,0x37,0xc1,0xf9,0x07,0x94,0x23,0x81,0xbe,0xff,0x03,0xe2,0x85,0xff,0x85,0x41,0xb0,0x00,0xe1,0xfe,0x83,0x56,0x7e,0x0f,0x1b,0xef,0x36,0x03,0x9c,0x17,0xc5,0xff,0xdd,0x82,0xfd,0x4f,0xe0,0x1a,0x3e,0xf0,0xfe,0x70,0x51,0xc8,0x07,0x03,0x80,0x3e,0x9f,0xfc,0x0a,0x17,0x00,0x90,0x70,0x3f,0xbf,0x70,0x7c,0xc1,0x20,0x11,0x0a,0x01,0x34,0x7d,0xe3,0xe5,0x03,0x88,0x3c,0xa1,0x00,0xf2,0xf1,0x87,0xe6,0x03,0x06,0x90,0x03,0xc7,0xf7,0xe7,0x07,0xbc,0x03,0x0d,0x01,0x07,0x90,0x81,0x7f,0x00,0xf3,0xbc,0x10,0x04,0x1e,0x5f,0x10,0x79,0xfc,0x11,0xe2,0x0f,0x10,0x00,0xc2,0x01,0xe3,0x7f,0x50,0x27,0x82,0x7f,0xdc,0x07,0x9c,0x10,0x18,0x84,0x12,0x07,0x8f,0xf0,0x1e,0x70,0x2f,0xec,0xfd,0x22,0x5e,0x00,0x10,0xf0,0x7f,0x82,0xf4,0x80,0xef,0x63,0xe0,0xf1,0xdf,0x94,0x4a,0x0f,0xf0,0x07,0xa4,0x03,0xfb,0xc7,0xff,0xfd,0xe1,0xe2,0x22,0x8f,0xf2,0x2f,0xf0,0x10,0x79,0xfe,0xc7,0xc5,0x71,0xe0,0x28,0x0c,0x1e,0xfc,0xf0,0x58,0xe0,0x4a,0x87,0xbe,0x07,0x1c,0x03,0xeb,0xff,0xdb,0x8f,0x08,0xc4,0x7b,0xf0,0x7b,0x52,0xc1,0x83,0x0f,0xff,0xfc,0xf3,0x7f,0xfa,0x78,0x3d,0x3d,0x3f,0xfa,0x20,0x3c,0x71,0xea,0x31,0xb2,0xff,0xa6,0x60,0xf4,0xc8,0xc7,0xe8,0x7d,0x01,0xe9,0xe1,0x60,0x30,0xc0,0x7a,0x58,0x7c,0x14,0x0f,0x07,0x84,0xc8,0x50,0x5f,0xf4,0x0c,0x1e,0x98,0x18,0xfc,0x82,0x00,0x6e,0x38,0x28,0x35,0x14,0x05,0x00,0x90,0x7c,0x20,0x7f,0xe4,0x80,0xc2,0xd7,0x64,0x0f,0x58,0x87,0xc1,0x64,0x39,0xff,0xfc,0x20,0x1f,0x31,0x8b,0xf6,0x78,0xe0,0x31,0x70,0x7c,0x5a,0x26,0x1f,0x8c,0x7a,0x40,0x41,0xf3,0xf4,0xf0,0x40,0x70,0x04,0xf1,0x97,0x83,0xe3,0xf5,0xe1,0x83,0x98,0x08,}; -const uint8_t _A_Levelup1_128x64_8[] = {0x01,0x00,0xe6,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x00,0xbf,0xb0,0x7f,0x88,0x3c,0x3f,0xe1,0x0f,0x00,0x5c,0x3f,0xc0,0x1f,0xdf,0x8c,0x7c,0x1f,0x97,0xfb,0xf7,0x83,0xf8,0x21,0x10,0x04,0xe7,0xf0,0x30,0x7f,0x98,0x7e,0xed,0xf0,0x08,0x47,0xb0,0x1e,0x7c,0xf8,0x4c,0xcb,0xe6,0x0f,0x38,0xbc,0x02,0x21,0xd0,0x03,0x9e,0x3f,0x93,0x33,0x07,0xa4,0x2e,0x01,0x20,0xdc,0x07,0xcc,0x1e,0xf0,0x50,0x78,0xd1,0x80,0xe7,0x4f,0x84,0xc9,0xbf,0x20,0x62,0xff,0x40,0xa0,0x14,0x0c,0x0f,0xfb,0xde,0x0f,0x2e,0x4c,0x9c,0x1e,0xdc,0x08,0x07,0xf4,0x1e,0x5c,0xfe,0x44,0x1f,0xf0,0x7e,0x38,0x0f,0xfa,0x81,0x10,0xfe,0xf1,0xc1,0xe7,0xcf,0xfe,0x03,0xca,0xfd,0x01,0x80,0xc8,0x64,0x1f,0xa0,0xf9,0xc2,0x79,0xc0,0xf2,0xbf,0xff,0x30,0x17,0xc8,0x95,0x00,0x1e,0x60,0x06,0xdf,0x50,0x30,0x51,0x4a,0x0c,0x11,0x3d,0x3b,0xe9,0x04,0x7e,0x13,0x42,0xfe,0x0e,0x4c,0x00,0xb5,0xfd,0x04,0xce,0x15,0x04,0x83,0x24,0x07,0x9f,0x83,0xce,0x48,0x29,0xff,0x20,0x78,0xd7,0xb4,0x16,0x38,0x94,0x12,0x03,0xf4,0x07,0x8f,0xcf,0x39,0x3c,0x07,0x98,0x7c,0x6e,0x71,0x44,0x00,0xfa,0x01,0xe5,0xc9,0x07,0xb7,0xfe,0x29,0x20,0x07,0x9e,0x0f,0x92,0x2f,0x40,0x79,0xc6,0x30,0x1e,0xb0,0xfa,0x5b,0xda,0xe4,0x0f,0x38,0x3d,0x83,0xd8,0x0f,0x2f,0x18,0x3d,0x64,0x1f,0xfe,0x94,0x02,0x30,0x3f,0x30,0x78,0x9b,0xd2,0x81,0xfe,0x9d,0xc0,0x20,0x80,0xf1,0x87,0xe0,0xbe,0xf2,0x0a,0x40,0xfc,0xf0,0x11,0xc8,0x64,0x02,0x04,0x6f,0x14,0x7c,0x40,0x20,0xb0,0x88,0x01,0xfc,0x81,0xf3,0x02,0x80,0x1f,0xc7,0xf4,0x0f,0xc9,0x80,0x3f,0x30,0x10,0x02,0x00,0xff,0x41,0xf5,0x00,0xc1,0xc0,0xf0,0x1f,0xe0,0x7d,0xdf,0x20,0x14,0x00,0x41,0x43,0xc1,0x03,0x80,0x07,0xa8,0x00,0x54,0x62,0x00,0x1f,0x98,0x08,0x6f,0xe0,0xf7,0xe8,0x02,0x0a,0x1a,0x1f,0x21,0xb1,0x03,0xd3,0xb0,0x0f,0x28,0x30,0x1c,0x8a,0xc4,0x0f,0x4e,0xa0,0x3f,0x85,0xe7,0x06,0xce,0x62,0x01,0xe7,0x4f,0x07,0xc6,0x8b,0x09,0x01,0x07,0x8e,0xfe,0x5e,0x5f,0x70,0x78,0xe0,0xa0,0x61,0xf2,0x07,0xa5,0x80,0x1e,0x98,0x18,0x38,0x3c,0xa2,0xe0,0xf4,0xef,0xef,0xc3,0xee,0x0f,0x4d,0x01,0xe0,0x7f,0xc3,0xf5,0xff,0xc2,0xc1,0xed,0xfc,0x2f,0xaf,0x7e,0x0a,0x0f,0x39,0x00,0x60,0x8f,0xe9,0xf7,0xf8,0xbf,0x44,0x00,0x54,0x0f,0xd0,0x40,0x51,0xeb,0x78,0x80,0x83,0xd3,0xe8,0x1f,0x18,0x72,0xfd,0x33,0xe0,0xe3,0x07,0x8f,0x20,0x1e,0x23,0x22,0x6f,0x95,0x9c,0x1e,0xb3,0x0f,0xff,0xe3,0xf6,0x0c,0x13,0xa0,0xff,0xe3,0x34,0x00,0x7a,0x70,0x20,0x1f,0x78,0x38,0x18,0x78,0x1f,0xf8,0x0c,0x18,0x1e,0xb0,0x0f,0xff,0xa1,0x44,0x40,0x01,0xff,0x40,0x41,0xed,0x00,0xf4,0x7f,0x7b,0xe0,0xf2,0x2e,0x88,0x3e,0x3c,0x61,0xf3,}; -const uint8_t _A_Levelup1_128x64_9[] = {0x01,0x00,0xd6,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x01,0x3d,0xe0,0xff,0x06,0xe4,0x0f,0xf0,0x0f,0xab,0xf8,0x04,0x7f,0x9c,0x7c,0x18,0x7a,0xf3,0xf0,0xf9,0xc0,0x7f,0x2c,0xff,0x0e,0x07,0xb8,0x1f,0x71,0xb8,0x04,0x0f,0xda,0x09,0x3e,0x7c,0x26,0x65,0xf3,0x07,0x9c,0x16,0x01,0x0c,0xfd,0x03,0xcf,0x1f,0xc9,0x99,0x83,0xd2,0x05,0x00,0x88,0x71,0x0e,0x26,0x0f,0x59,0x7d,0xea,0x03,0x00,0x90,0x6f,0x81,0xe7,0x4f,0x84,0xc9,0xbf,0x21,0xf2,0xdf,0xc0,0x20,0x14,0x0a,0x08,0x3d,0x39,0x32,0x70,0x7b,0x60,0x30,0x1f,0xee,0x39,0x3c,0xb9,0x10,0x7f,0xc0,0x3c,0xab,0xf0,0x09,0xfd,0x03,0x21,0xfe,0x80,0x83,0xcf,0x9f,0xfc,0x2b,0x15,0x7f,0x81,0xc0,0x90,0x48,0x3f,0xa1,0xf3,0x84,0xf3,0x81,0xe5,0x7f,0x97,0xc8,0x23,0xd1,0x10,0x78,0xa8,0x66,0x5f,0x90,0xb0,0xc2,0xa4,0x3c,0x20,0x7d,0x54,0x33,0xf0,0x68,0x14,0xe8,0x1f,0x31,0x7e,0x46,0xce,0x09,0x02,0xe3,0x7f,0x87,0xc3,0x83,0xce,0x48,0x29,0xff,0x20,0x79,0x7a,0x2c,0x70,0x5c,0x14,0x07,0xfa,0x0f,0x1f,0x9e,0x72,0x78,0x0f,0x5b,0x9c,0x16,0x81,0x00,0x60,0x88,0x3c,0x79,0x20,0xf6,0xbf,0xc1,0x66,0x00,0xf3,0xc1,0xf2,0x45,0xec,0x0f,0x18,0x67,0x03,0xf6,0x1f,0x4b,0x78,0x18,0x7f,0xf0,0xbe,0x47,0xfe,0x09,0x03,0xf8,0x03,0xcf,0xc6,0x0f,0x5e,0x87,0xff,0x85,0x00,0xfc,0x5f,0x41,0xe8,0x6f,0x38,0x5e,0x42,0x1f,0x3f,0x80,0x7f,0x27,0xdf,0xe8,0x7e,0x0b,0xef,0x20,0xa4,0x0f,0xca,0x17,0x20,0x81,0x41,0x20,0x17,0xfb,0xfa,0x3e,0x21,0x7c,0x08,0x0b,0xc0,0x77,0xe0,0xe8,0x07,0x8c,0x00,0x1e,0x3e,0x0e,0xf8,0x3a,0x3e,0xe0,0xf3,0xfc,0x2f,0xa4,0x1e,0x49,0xd1,0xe7,0x40,0xd7,0xe2,0x00,0x6f,0x18,0x3c,0x70,0x1c,0x18,0x1f,0xfd,0x7e,0x21,0xf9,0x80,0x7f,0xa0,0x28,0xf2,0xff,0xc3,0xc1,0x03,0x80,0x07,0xa8,0x40,0x61,0xeb,0xf1,0xff,0xfc,0xc0,0x42,0x75,0x30,0x79,0x80,0x04,0x1e,0x50,0xd0,0xf9,0x11,0x88,0x1e,0xa2,0xf2,0x83,0x01,0x88,0x8c,0x40,0xf4,0xe0,0x7f,0x01,0xfb,0x30,0x1c,0x14,0x1b,0x39,0x88,0x07,0xc7,0x38,0x1e,0x7a,0x2c,0x24,0x04,0x1e,0xdc,0x01,0xf1,0x03,0xcb,0x05,0x03,0x07,0xb7,0xf0,0x1e,0xb8,0x18,0x38,0x3c,0xa0,0xa0,0xf2,0xfc,0x07,0xe8,0x1e,0x7e,0x0f,0xa8,0xfe,0x41,0xe7,0x00,0xfa,0x17,0xe6,0x04,0x0f,0x3f,0x60,0x3c,0xcf,0xea,0x0f,0xeb,0xfc,0x04,0x1e,0x7d,0x80,0x79,0x43,0x97,0xe8,0x0f,0x91,0x59,0x37,0xcb,0x7e,0xce,0x4d,0x40,0x3c,0x8e,0x65,0xbf,0x07,0x9d,0x00,0x1e,0xd0,0x75,0x39,0x01,0x46,0xbe,0x0f,0x4a,0x40,0x3c,0x80,0x0b,0x2f,0x80,0x48,0x01,0xe5,0x88,0x24,0x08,0x01,0xa2,0xe0,0xf4,0x84,0x13,0x08,0x00,0x80,}; -const uint8_t _A_Levelup1_128x64_10[] = {0x01,0x00,0xde,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x09,0xef,0x06,0xe4,0x0f,0xf0,0x0f,0xcb,0xff,0xf3,0x8f,0xc7,0x07,0xde,0x7e,0x1f,0x38,0x0f,0xe5,0x9f,0xe1,0xc0,0xf7,0x03,0xee,0x37,0x00,0x81,0xff,0x4a,0x27,0xcf,0x84,0xcc,0xbe,0x63,0xd2,0xff,0xc1,0x60,0x10,0xcf,0xd0,0x5c,0xf1,0xfc,0x99,0x98,0x3d,0x20,0x50,0x08,0x87,0x10,0x3e,0x60,0xf5,0x9f,0xdf,0xa0,0x30,0x09,0x06,0xf8,0x1e,0x74,0xf8,0x4c,0x9b,0xf2,0x1f,0x2d,0xfc,0x02,0x01,0x40,0xa0,0xff,0xce,0x25,0x4f,0xe4,0xc9,0xc1,0xed,0x80,0xc0,0x7f,0xb5,0x64,0xf2,0xe4,0x41,0xff,0x04,0x62,0xaf,0xc0,0x27,0xf4,0x0c,0x85,0xfa,0x22,0x62,0x10,0x78,0xf3,0xff,0x80,0xf3,0xe0,0x70,0x24,0x12,0x0f,0xe8,0x7c,0xe1,0x3c,0xe0,0x79,0xcb,0xe4,0x11,0xe8,0x88,0x3c,0x56,0x33,0x2f,0xc8,0x58,0x61,0x52,0x1e,0x12,0xc6,0x3f,0xd2,0xfa,0x86,0x7e,0x0d,0x02,0x9d,0x2b,0xa6,0x2f,0xc8,0xd9,0xc1,0x20,0x5c,0x66,0x08,0xf3,0xf0,0x79,0xc9,0x05,0x3f,0xe4,0x1f,0x18,0xbf,0xa2,0xc7,0x05,0xc1,0x40,0x4b,0xc5,0xf3,0xce,0x4f,0x01,0xeb,0x73,0x82,0xd0,0x20,0x0c,0x11,0x07,0x8f,0x24,0x1e,0xd7,0xf8,0x2c,0xc0,0x1e,0x78,0x3e,0x48,0xbc,0xab,0xff,0x40,0x79,0xc3,0x38,0x1f,0xb0,0xfa,0x5b,0xc0,0xc3,0xfe,0x85,0xf2,0x3f,0xf0,0x48,0x1f,0xc0,0x1e,0x7e,0x30,0x7a,0xf4,0x3f,0xfc,0x28,0x07,0xe0,0x9e,0x60,0xf1,0x37,0x9c,0x2f,0x21,0x0f,0x9f,0xc0,0x3f,0x9f,0xef,0xfc,0x3f,0x05,0xf7,0x90,0x52,0x09,0xe5,0x0b,0x90,0x40,0xa0,0x90,0x0b,0xfa,0x3e,0x61,0x7c,0x08,0x0b,0xc0,0x77,0xe0,0xfa,0x80,0x03,0xc7,0xc1,0xdf,0x07,0xef,0xe1,0x9d,0x00,0xf3,0x4e,0x8f,0x3a,0x06,0x4f,0x10,0x03,0x7d,0xc1,0xe3,0x80,0xe0,0xc0,0xff,0xe6,0xf1,0x0f,0xcc,0x03,0xfd,0x01,0x47,0x91,0xc0,0x41,0x03,0x80,0x07,0xa8,0x40,0x61,0xeb,0xf1,0xff,0xfc,0xc0,0x42,0x76,0x30,0x79,0x80,0x04,0x1e,0x50,0xd0,0xf9,0x11,0x88,0x1e,0xa2,0xf2,0x83,0x01,0x88,0x8c,0x40,0xf4,0xe0,0x7f,0x01,0xfb,0x30,0x1c,0x94,0x1b,0x39,0x88,0x07,0xc7,0x38,0x1e,0x7a,0x2c,0x24,0x04,0x1e,0xdc,0x0f,0xdc,0xfc,0x92,0x20,0xf1,0xc1,0x40,0xc1,0xed,0xfc,0xfd,0x87,0xd3,0x03,0x07,0x07,0x94,0x14,0x1e,0x5f,0x80,0x7a,0x87,0xd0,0x1e,0x7e,0x0f,0xaa,0x20,0x87,0xec,0x0f,0x38,0x07,0xd0,0x1e,0x65,0xf5,0x81,0x03,0xcf,0xd8,0x0f,0x33,0xfa,0x83,0xfa,0xff,0x01,0x07,0x9f,0x60,0x1e,0x50,0xe5,0xfa,0x03,0xe4,0x56,0x46,0x52,0xdf,0xb3,0x93,0x50,0x0f,0x26,0x91,0x6f,0xc1,0xe7,0x40,0x07,0xb4,0x1d,0x4e,0x40,0x51,0xaf,0x83,0xd2,0x90,0x0f,0x20,0x02,0xcb,0xe0,0x12,0x00,0x79,0x62,0x09,0x02,0x00,0x68,0xb8,0x3d,0x21,0x04,0xc2,0x00,0x20,}; -const uint8_t* const _A_Levelup1_128x64[] = {_A_Levelup1_128x64_0,_A_Levelup1_128x64_1,_A_Levelup1_128x64_2,_A_Levelup1_128x64_3,_A_Levelup1_128x64_4,_A_Levelup1_128x64_5,_A_Levelup1_128x64_6,_A_Levelup1_128x64_7,_A_Levelup1_128x64_8,_A_Levelup1_128x64_9,_A_Levelup1_128x64_10}; - -const uint8_t _A_Levelup2_128x64_0[] = {0x01,0x00,0x34,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0x38,0x1f,0xe0,0x1d,0x97,0xff,0xe7,0x1c,0x1f,0x99,0xf8,0x1c,0xfc,0x1f,0x96,0x7f,0x87,0x03,0xf8,0x0f,0xb8,0xdc,0x22,0x01,0xfb,0x07,0xdc,0x16,0x09,0x00,0xfa,0x03,0xee,0x1d,0x02,0x80,0x7a,0x0b,0xd7,0x31,0x07,0x8f,0x40,0x1f,0x5b,0xfa,0x04,0x06,0x01,0xa0,0x07,0xd5,0x7f,0x00,0x0f,0xe8,0x26,0x06,0x7f,0x40,0x07,0xd4,0xbe,0x05,0x42,0xa0,0x03,0xf2,0x03,0x24,0xcf,0xe0,0x3f,0xc5,0xe9,0x88,0x50,0x72,0x92,0x0c,0x08,0x3e,0x73,0xf1,0xf9,0x0d,0x22,0xf9,0x82,0x07,0xcd,0xbe,0x61,0x10,0x94,0x79,0xa0,0x5f,0xd0,0x7c,0x45,0xe8,0x11,0x09,0x27,0x8c,0x1f,0x50,0xb3,0xf0,0xc5,0x3c,0xe0,0xfb,0x80,0x40,0xb2,0x9f,0xf0,0x7d,0x7a,0xe0,0x10,0xc0,0x7e,0x46,0xe0,0x77,0x00,0x7e,0x42,0xe1,0x98,0x0d,0x2d,0xfc,0x1f,0x71,0x08,0x05,0x3a,0x7f,0x01,0x37,0xd4,0x81,0xfa,0x39,0xf8,0x01,0xfe,0xe0,0x12,0x0a,0x40,0x3e,0xa5,0xef,0xe2,0x98,0x03,0xee,0x01,0x06,0x80,0x10,0x84,0x1f,0x35,0xf8,0x04,0x62,0x00,0x00,0x10,0x7c,0xef,0xe0,0x1e,0x00,0x7e,0x5f,0xc7,0xc3,0x0f,0x07,0xda,0x6c,0x43,0xc4,0x0f,0xb8,0x28,0x3f,0xa1,0xa0,0xfe,0x8a,0x8b,0xfc,0x1f,0xe0,0xfe,0x2f,0xa7,0xe8,0xff,0x30,0x30,0x7f,0x83,0xcf,0xe8,0xaf,0x91,0x7a,0x03,0xff,0xd0,0xdf,0x90,0x7a,0x74,0x1f,0xf2,0xcf,0x10,0x01,0x68,0x01,0xf1,0x17,0x07,0xa5,0x00,0x1f,0x10,0x90,0x7a,0x60,0x3f,0x80,0xd5,0xc7,0xdf,0xe0,0xc0,0xf4,0x80,0x7c,0xc1,0xeb,0x77,0xc0,0x40,0x41,0xe9,0x01,0xe6,0x03,0xd7,0x17,0x7f,0x05,0x08,0x3d,0x26,0x18,0x00,0x7a,0x42,0xc1,0x44,0x0f,0x4e,0x05,0xfc,0x1f,0xa5,0x11,0xff,0x03,0xcc,}; -const uint8_t _A_Levelup2_128x64_1[] = {0x01,0x00,0x17,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2f,0xf8,0x17,0x59,0xfe,0xf8,0x6b,0x37,0xf9,0xf0,0x32,0x7e,0xc1,0xac,0x02,0x19,0xff,0xfe,0x03,0xfc,0x11,0x5c,0xfe,0x7f,0xfe,0xf1,0x8c,0x2e,0x3d,0xce,0x80,0xe7,0xbe,0xff,0x90,0x7c,0xc3,0xe6,0x18,0x0b,0x0f,0xfb,0xf0,0x61,0x8c,0x7c,0x3e,0x19,0x40,0xc0,0x43,0x6f,0xc1,0xe8,0xbf,0xe3,0xa1,0x52,0x08,0x04,0x0a,0xfe,0x83,0x7f,0xdf,0xf6,0x09,0x05,0x88,0x40,0x30,0x89,0x28,0xfb,0xfb,0xf0,0x10,0x40,0x78,0xca,0x0f,0xee,0x00,0x18,0xfd,0x02,0x05,0x08,0x80,0x44,0x3f,0xc6,0x08,0xbf,0xd2,0x3f,0xc0,0xf2,0xfe,0x7f,0x41,0xef,0xf7,0x90,0x40,0xe1,0xf0,0x09,0x06,0xf1,0x3d,0x3a,0x88,0x04,0x63,0xf1,0xa3,0xfc,0x03,0xe6,0xa1,0x10,0x90,0x41,0x28,0x80,0xf1,0xf3,0xbe,0x5a,0xff,0xb2,0x88,0x50,0x3f,0x54,0x80,0x78,0xb0,0xda,0xfb,0xff,0xd8,0x42,0x30,0x50,0x5a,0x8e,0xe2,0x1f,0xfc,0xf7,0x84,0x17,0xf9,0x68,0x84,0x40,0xbc,0x79,0x2f,0xe7,0xdc,0xdf,0x17,0x88,0x46,0x07,0xc5,0xa3,0xfe,0x3c,0x9e,0xff,0x38,0xfc,0x41,0xf0,0x3e,0x5d,0x2f,0xe0,0x1e,0xf2,0x78,0x04,0xe2,0x19,0x80,0xfe,0xe9,0x78,0x1f,0x00,0x7b,0x61,0xf4,0x31,0xc7,0xf8,0xff,0x64,0xb0,0x9f,0xe7,0xff,0xbe,0x10,0x58,0x1b,0xf8,0x81,0xe3,0x01,0xff,0x6f,0xf7,0xe0,0xf5,0xd1,0xc1,0x30,0x18,0x1f,0xec,0x4e,0x13,0x8f,0xfb,0x83,0xda,0x1f,0xe4,0x80,0x65,0xbf,0x71,0x2c,0x0f,0x9f,0xe7,0xdf,0x39,0x1d,0xee,0xfd,0x9f,0x8a,0x40,0xfc,0x17,0xf8,0x4f,0x27,0xff,0xfb,0xf7,0xb8,0x8e,0x7f,0xfc,0x9f,0x43,0x21,0x90,0x0f,0x82,0x08,0x59,0xaf,0xff,0xcf,0xc3,0xa2,0x10,0x0c,0x04,0x1a,0x53,0xe0,0x07,0xa9,0x10,0x60,0x10,0xa9,0x04,0x02,0x01,0x01,0x80,0x83,0xda,0xff,0x1f,0xd0,0x42,0xa8,0x00,0xf1,0x80,0x6a,0x51,0xe3,0xf3,0x08,0x26,0x7a,0x03,0x12,0xc0,0x40,0x44,0x04,0x8f,0x1f,0x39,0xfd,0xa2,0x50,0x08,0x30,0x7c,0xbf,0xdf,0xfe,0x79,0xfd,0xa4,0x50,0x0b,0xc0,0x7c,0x81,0xee,0x96,0x1a,0x10,0xf8,0x83,0xe2,0x2f,0x1f,0x7f,0xec,0x1e,0x7c,0xf8,0x5e,0x08,0x1e,0x70,0x11,0xf0,0xa3,0xd0,0xfc,0x3a,0x38,0x11,0x38,0x83,0xe3,0xf7,0xf1,0xab,0x8d,0x4a,0x2d,0xf1,0x81,0x40,0x81,0xe5,0xc1,0xff,0xfc,0x45,0xc8,0x04,0x1d,0x38,0x38,0xe0,0x1c,0x99,0xff,0xe0,0xbc,0xbf,0x38,0x7c,0x0c,0x1e,0x74,0x28,0x79,0x80,0x49,0xc9,0xc3,0x97,0x83,0xd2,0x15,0x06,0x0f,0x2c,0xde,0x0f,0x87,0x17,0xa4,0x12,0x04,0x1f,0x1f,0x78,0x3c,0xa9,0x70,0xed,0x00,0x3d,0x34,0x92,0x0c,0xf6,0xfc,0xc0,0x78,0xb8,0xe5,0x00,0x1e,0x90,0x88,0x05,0x9f,0x3e,0x2f,0x38,0x5e,0x0e,0x44,0x0f,0x49,0x84,0xab,0x33,0xce,0x07,0xa4,0x72,0x30,0x0f,0x4e,0x04,0x03,0x0c,0x60,0x48,0xbf,0x82,0x0e,0x0f,0x48,0x07,0xff,0x02,0x0f,0x50,0x48,0x83,0xd6,0x01,0x80,0x07,0x89,0x40,0xa5,0xe0,0xf6,0x61,0x8d,0x01,0x22,0x80,0xfa,0xb3,0x03,0xce,0x82,0x0f,0x89,0x07,0x00,0xfe,0x78,0x10,0x7c,0xf8,0x3f,0x22,0x02,0x81,0x82,0x04,0x1e,0xd9,0x0a,0x17,0xf0,0x3e,0x40,}; -const uint8_t _A_Levelup2_128x64_2[] = {0x01,0x00,0xed,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x3f,0xe4,0x1f,0xdf,0x40,0x43,0xf3,0xc0,0xa9,0x7f,0xfb,0x03,0xdf,0x66,0x05,0x4d,0xff,0xbc,0x1e,0xf3,0xbf,0xf0,0x14,0xe3,0xf7,0x8f,0xf7,0xc4,0x1e,0xb1,0x3f,0xe0,0x14,0xe1,0xf9,0x02,0x0b,0xc5,0xc1,0xeb,0xcc,0xff,0x03,0xda,0x1e,0x0f,0x48,0x3f,0xbf,0xfd,0xf8,0x07,0xad,0xfc,0x1e,0x57,0xff,0xf4,0x0f,0xe7,0xff,0x07,0xaf,0x8e,0xff,0xf8,0xed,0xc7,0xee,0x1f,0xc8,0x18,0x34,0x41,0xeb,0xc3,0x9f,0xfc,0x3f,0x70,0xfe,0x07,0xfe,0x01,0x9c,0x0b,0x88,0x88,0x41,0xe7,0x1f,0xc8,0x5f,0xe0,0x7c,0x08,0x7c,0x03,0xf9,0x7f,0x9e,0x07,0xd3,0x8f,0x17,0x80,0x5e,0xde,0xe5,0x0a,0xff,0x4f,0xe3,0xc0,0xf4,0xc7,0xcf,0xe0,0x11,0x32,0x68,0x84,0x07,0xf7,0x3f,0x4b,0xa7,0xe2,0x7f,0x7f,0x82,0x70,0x20,0xb9,0xdd,0x54,0x08,0x3e,0x21,0xe4,0xfc,0x4d,0xff,0x10,0xe9,0x86,0x22,0xc0,0x1f,0x1b,0xf8,0xb8,0x58,0x47,0xfe,0x99,0xda,0x31,0xd0,0xcc,0x46,0x03,0x53,0x82,0xbd,0xe7,0x83,0xe9,0x3f,0x99,0xf0,0x20,0x90,0x28,0x24,0x06,0x05,0x80,0xbf,0xe3,0x2f,0xeb,0xe5,0x07,0x8c,0x04,0x02,0x3a,0x4e,0x07,0xbf,0x00,0xa6,0x25,0xf1,0xe0,0x30,0x10,0x00,0x78,0xc2,0x30,0x13,0xc0,0x79,0x00,0x0e,0xfd,0x80,0xa0,0x03,0xcb,0x21,0x0a,0x08,0x88,0x39,0x19,0x83,0x00,0x07,0x8c,0x0a,0x05,0x10,0x30,0x0f,0x03,0x7e,0x0f,0x3c,0xe7,0xbe,0x03,0x20,0x07,0x96,0x82,0x05,0x00,0x90,0x23,0xd2,0x33,0xff,0x07,0xa0,0x0c,0x41,0xe7,0xc7,0x07,0x8c,0x6b,0x9d,0x01,0x15,0x88,0x3c,0x68,0x1a,0x88,0x54,0x00,0x18,0x38,0xb0,0x10,0x9e,0x04,0x1e,0xa1,0xf1,0xc7,0x7f,0xfc,0x7f,0xd0,0x78,0xc1,0xe0,0x18,0x00,0xc8,0xa0,0x07,0x01,0xaa,0x85,0x36,0x47,0xce,0x3f,0x28,0x69,0x20,0x71,0x10,0x70,0x78,0xe3,0xc2,0xc3,0xff,0x07,0x18,0x00,0x60,0x38,0x0a,0x54,0x23,0xff,0x87,0xc8,0x68,0xa1,0x5f,0x80,0x7a,0x8c,0x06,0x49,0x90,0x80,0xd3,0x24,0x01,0x61,0xfc,0xfe,0xc1,0xeb,0x8a,0x92,0x54,0x20,0x15,0x09,0x06,0xa7,0xc0,0xeb,0x20,0x71,0x5f,0xe1,0xf0,0x0a,0xa4,0xc2,0x41,0x60,0xa8,0x40,0x7e,0x1e,0xff,0xe8,0x3c,0xa1,0xff,0xf8,0xf4,0xa3,0xa9,0x30,0x91,0x58,0xab,0x1a,0x9f,0x87,0x1e,0xff,0xde,0xc7,0x8b,0x47,0xd2,0x1f,0x1e,0xa4,0x42,0x45,0x42,0xac,0x07,0xc7,0x8f,0x3f,0xff,0x61,0xff,0xff,0x7e,0xfc,0x1f,0x40,0x0f,0x41,0xf8,0xf9,0xdf,0xa3,0xe3,0x7f,0x98,0x7c,0x62,0x2e,0x21,0xae,0x40,0x78,0x00,0xc2,0x4f,0x91,0x40,0x43,0xe3,0x1f,0x75,0x8d,0x7f,0x53,0x80,0xf1,0xbb,0xd0,0x00,0x30,0x0d,0x26,0x7f,0xff,0xcf,0x97,0xc0,0x60,0x1f,0x00,0x50,0x82,0x07,0xff,0xf3,0xfe,0xe0,0x64,0x94,0xf8,0x07,0x42,0x4f,0xa9,0x81,0x7f,0x3e,0xe0,0xf2,0xfe,0x78,0x3d,0xf0,0x1a,0x24,0xc2,0x01,0x60,0x88,0x07,0xc7,0xfc,0x0f,0x10,0xe8,0xa4,0xca,0x01,0x84,0x1f,0x94,0x3f,0x52,0xdf,0x10,0xf0,0xf9,0xfe,0x3f,0xfe,0x3c,0xf2,0x01,0x04,0x88,0x17,0xc5,0xe4,0x30,0x02,0x20,0xf7,0xfc,0xff,0x9f,0xfc,0x0a,0x31,0xa0,0x82,0x48,0x20,0x00,0x11,0xd4,0xe0,0xb3,0xfc,0x7f,0x3f,0xcf,0xf9,0xff,0x90,0xc0,0x03,0xe2,0x0f,0x36,0xf8,0xc3,0xf8,0x3e,0x7b,0xc0,0xf4,0x6f,0xf0,0x00,0xfa,0xe0,0x61,0x50,0x7f,0x05,0xde,0x38,0x7e,0x38,0x04,0x18,0x7a,0x24,0x11,0x81,0x81,0xc7,0xc1,0x13,0xc0,0x03,0x87,0x9f,0x80,0xd5,0x03,0xd3,0x07,0x0a,0x85,0x7c,0x20,0x3e,0x00,0x78,0xed,0xc2,0xe3,0x05,0xe0,0x40,0x23,0x00,0x41,0x41,0x8f,0x81,0x44,0x2b,0x21,0xa5,0x6a,0x31,0x50,0x4c,0x07,0xe6,0x19,0x00,0xc4,0xea,0xb2,0x41,0x91,0xfc,0x07,0xc7,0x15,0x01,0xb0,0x03,0xc6,0x0e,0xe4,0x19,0x8c,0x03,0x18,0x0f,0x1d,0xc7,0xef,0xff,0x08,0x87,0x46,0x20,0x86,0xc1,0x01,0x0f,0x07,0x01,0x83,0x81,0x4a,0xb9,0x06,0xe1,0x84,0x7c,0x20,0xe0,0xc1,0x83,0x17,0x46,0x03,0x7f,0xc0,0x18,0x48,0x5e,0x25,0x91,0x47,0x88,0xdc,0x40,0x82,0x00,0x1a,0x06,0x88,0xc2,0x20,0xf6,0x00,0x21,0xd4,0x4b,0xe2,0x0f,0x15,0x79,0x83,0xd7,0x41,0xaa,0x85,0x2f,0x87,0xfe,0xa9,0x10,0x7b,0x82,0x4b,0xfc,0xbf,0x11,0x29,0x00,0x1b,0x21,0xaa,0x95,0x03,0x87,0xfd,0x94,0x07,0xc4,0x20,0x3e,0x5f,0xff,0xc4,0x2e,0x02,0x0d,0x50,0x30,0xe9,0x07,0xe3,0xf6,0xff,0xfe,0x61,0x70,0x61,0xfa,0x83,0xc5,0xc2,0x4a,0xf2,0x81,0x9e,0xc4,0x1e,0xbf,0x8d,0x46,0xab,0x14,0x0f,0x20,}; -const uint8_t _A_Levelup2_128x64_3[] = {0x01,0x00,0x2d,0x03,0x8f,0xc0,0xb8,0x1f,0xfb,0xfd,0xe2,0x7f,0xf8,0x02,0x0f,0xff,0xff,0x03,0xff,0x00,0xc6,0xff,0x36,0xe0,0x47,0xfd,0xff,0x08,0xff,0xf3,0xff,0x3f,0x05,0x8f,0xf0,0x1e,0x5f,0xf8,0xfe,0x02,0xfb,0xff,0xf8,0x43,0xff,0x99,0xfd,0xf8,0x44,0x81,0xe7,0x17,0x88,0x7d,0x37,0xe0,0xf2,0x87,0xe7,0xff,0xe0,0x11,0xfe,0x83,0xca,0x1f,0x20,0xf8,0x0f,0x46,0x0f,0xfe,0x83,0xf6,0xff,0xfc,0xf0,0xfa,0x47,0xec,0x1e,0x08,0xf8,0x3c,0xa0,0x7c,0x3f,0xff,0x9c,0x1e,0x93,0xf8,0x06,0x02,0x1f,0xf8,0x2c,0x8c,0x07,0xc1,0xff,0xfd,0x83,0xdb,0xc1,0x07,0xfc,0x40,0x6f,0xda,0x0d,0x47,0xff,0xf2,0x0f,0x4b,0xf8,0x7c,0x60,0xda,0x88,0x0c,0x72,0x01,0xb0,0xff,0xe0,0x01,0xe9,0xff,0x80,0x68,0x21,0xff,0xa9,0x06,0x02,0x01,0xf2,0xbf,0x40,0x12,0x44,0x1f,0x2b,0x82,0xa1,0x7d,0x11,0xf8,0x05,0xf8,0x1e,0x74,0x7f,0x80,0xc0,0x75,0x50,0xa8,0x04,0x83,0xf0,0x0f,0x1b,0xe1,0x48,0x6f,0xfb,0x78,0x38,0x3c,0x40,0x09,0xfc,0x81,0x83,0xcb,0xfb,0xbf,0xbf,0xcb,0xbe,0x1a,0x8d,0x56,0xaa,0x55,0x80,0x85,0x18,0xc4,0x5e,0xb3,0xce,0x00,0x7d,0x7b,0x80,0x21,0xdf,0xcf,0xef,0xee,0x72,0x2f,0x8e,0xaa,0x01,0xa8,0xd1,0x62,0xa7,0xfa,0x0c,0x06,0x7d,0x82,0x33,0x8f,0x3d,0xfe,0x04,0x18,0x15,0x68,0xc0,0x1e,0xa2,0x02,0x1f,0x0f,0xff,0xbf,0x3f,0xe3,0xcf,0xc7,0x63,0xca,0xd7,0xe7,0xf5,0x58,0xa8,0x3e,0xa3,0x80,0x8e,0x29,0xfe,0x3c,0x2e,0x30,0x0b,0x87,0x76,0xea,0x73,0x11,0x10,0xd8,0x01,0xe5,0xcf,0x9f,0xcf,0xf5,0x50,0x2d,0x61,0x80,0x75,0x38,0xa2,0x28,0xda,0x09,0x63,0x9f,0x1f,0x0c,0xf8,0x3e,0x35,0x6a,0xad,0x54,0x3a,0x20,0x01,0xba,0x7f,0xf7,0xf9,0xff,0xbc,0xfe,0x7c,0x9c,0x1d,0x5e,0xbb,0x57,0xa6,0x85,0x68,0xb5,0x5b,0x8d,0xff,0x7f,0xde,0x0f,0x18,0x60,0xe8,0x43,0xc3,0x55,0x86,0x87,0xcb,0x31,0xfd,0xff,0xf9,0xfc,0xe4,0xe1,0xd4,0x72,0xb5,0x41,0xf1,0xcd,0x42,0x88,0x63,0xe4,0xff,0xfe,0x7c,0xff,0x18,0x38,0x5c,0x68,0x15,0x5a,0xbd,0x5e,0x2a,0x1f,0x2f,0x87,0xcf,0xf3,0x27,0xfc,0x41,0xe5,0x4b,0xe2,0x00,0x16,0x29,0x86,0x3f,0x0f,0x8e,0xe2,0x07,0xfc,0x87,0x85,0xc6,0xc0,0x1f,0x29,0xa8,0x7c,0xbc,0x13,0x9f,0x74,0x0f,0xd1,0x0f,0x0d,0x0e,0xc8,0x3c,0x56,0xa2,0xf0,0xc0,0xbf,0x19,0x8f,0xfc,0x07,0xf9,0x06,0x0b,0x8d,0x40,0x3e,0x55,0x50,0xf9,0x7e,0x38,0x5f,0xf8,0x00,0x04,0x47,0xc6,0x80,0x10,0x21,0x42,0xaf,0x1d,0x09,0xfe,0x00,0x1e,0x20,0x01,0xec,0x07,0x46,0xab,0xdf,0x03,0x94,0xf3,0x85,0x0f,0x07,0x90,0x7c,0x7d,0x5a,0xaf,0xfe,0xbf,0x74,0x1f,0x19,0x54,0xf3,0xd0,0xb5,0x1e,0x1a,0xdc,0xfa,0xb5,0x5a,0xed,0xd6,0x02,0x1f,0x2f,0x00,0x0c,0x78,0xf0,0x1d,0x03,0x78,0x7f,0x5a,0xa0,0x08,0xea,0x47,0xe3,0x38,0xa0,0x40,0x25,0x1e,0x34,0xf9,0x55,0x2e,0xa0,0x01,0xaa,0x87,0xc8,0x00,0x7f,0xa8,0x06,0x8e,0x15,0xfc,0x1e,0x0f,0xab,0xf4,0x1f,0x20,0x71,0x42,0xbf,0x1e,0x70,0xc0,0xf5,0x2a,0xb7,0x7a,0xbd,0x74,0x3e,0xdf,0x8f,0xfe,0x0e,0x54,0x1f,0x59,0x54,0xaa,0x01,0x08,0xc0,0x28,0xc7,0xfe,0x63,0x10,0xf8,0x80,0x04,0x3f,0x08,0x81,0xd5,0x7f,0x37,0xe1,0xf1,0xff,0xea,0x70,0x41,0xf1,0x90,0x6a,0x20,0x5f,0xeb,0xf8,0x4c,0x7e,0x9d,0xff,0xff,0x7e,0xfe,0x1f,0x6d,0xf5,0xff,0x51,0x2a,0xd6,0x7b,0xcf,0xe3,0xaf,0xd4,0xe0,0x03,0xe2,0xa3,0x18,0x17,0xf2,0xf6,0x7f,0x3a,0xa9,0xfe,0x09,0xe3,0xa8,0x85,0x6b,0x07,0xe5,0xaf,0x80,0xe0,0x35,0x40,0x11,0x0f,0x97,0xfc,0x30,0x35,0x42,0xf9,0x07,0xde,0xfd,0x0f,0x0f,0x93,0xf0,0xb5,0x58,0x10,0xe9,0x07,0xca,0x7d,0x1f,0x1f,0xec,0xf2,0x7c,0x57,0x10,0xfa,0x6a,0x71,0x40,0x53,0x80,0x4e,0x03,0xe5,0x56,0x1f,0x9a,0x98,0x40,0x0c,0xb7,0x1d,0x77,0xab,0x54,0xc1,0x1d,0x5e,0x88,0x40,0x48,0x21,0xf0,0x4c,0x02,0x23,0x55,0xea,0xaf,0x86,0xab,0x05,0x80,0x58,0x03,0xa7,0xf4,0xb4,0x6a,0xb1,0x5a,0xed,0x57,0xec,0x04,0x38,0xbd,0x16,0xc8,0x3e,0x30,0xa8,0x07,0xf3,0xb1,0x01,0xb0,0x07,0xc6,0xaf,0x5f,0xaa,0xcd,0x60,0x1d,0xc4,0xfa,0x6a,0x21,0xdb,0x80,0xe0,0xea,0xc0,0x43,0xeb,0xc0,0x6a,0xc3,0xe3,0xa0,0x85,0x7f,0xab,0x3f,0x5a,0xb9,0x70,0x6a,0xe0,0x32,0xbf,0xf5,0x43,0xe7,0xff,0xdb,0x85,0x44,0x38,0x3f,0xa3,0xd9,0xda,0xa1,0x50,0xa2,0x00,0xcf,0x6a,0x67,0xc3,0x00,0x28,0x7c,0xf8,0x1a,0xf0,0xf9,0x80,0x12,0x55,0x28,0x94,0x2f,0xc7,0xc7,0x6b,0x0f,0x41,0x84,0x40,0x03,0x80,0xf0,0xf7,0xc3,0x8a,0x00,0x2c,0xd0,0x84,0x75,0x5c,0x2f,0x8e,0x7c,0x3f,0x10,0xd1,0xf1,0xfc,0x20,0x27,0x62,0x00,0x18,0x18,0x74,0xca,0x91,0x1f,0x8f,0xe1,0xba,0xae,0x18,0xfe,0x28,0x44,0xbe,0xba,0xbf,0xd6,0xa3,0x55,0xa2,0x0f,0x8f,0xf0,}; -const uint8_t _A_Levelup2_128x64_4[] = {0x01,0x00,0x90,0x02,0xff,0x80,0x3c,0x01,0xf1,0xff,0xe0,0x3f,0x7d,0xff,0xd1,0x0f,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2d,0xff,0xee,0x0f,0xef,0x47,0xff,0xfc,0x06,0x2d,0xf8,0x3d,0xe0,0x3e,0x49,0x3f,0xc0,0xfc,0x7f,0x8f,0xfc,0xed,0x02,0x37,0xff,0xc5,0xbe,0x01,0xf0,0xaf,0xe0,0xc1,0xe7,0xe0,0xff,0xc0,0xc2,0xe3,0x1f,0xf8,0x4f,0xe0,0x17,0x0b,0xf5,0x81,0x34,0x40,0xf1,0xb8,0xc1,0x38,0x1f,0xd8,0x3f,0xe2,0x73,0x00,0xf7,0xc7,0xe4,0x02,0xb1,0xff,0xcf,0xf0,0x02,0x81,0xc0,0x77,0xe0,0x37,0xf8,0x47,0x82,0xff,0x0e,0x6e,0x1c,0x1d,0xc4,0x3e,0x08,0x0c,0x0b,0x80,0x2e,0x1f,0x00,0x08,0x60,0x06,0x02,0xc3,0xc0,0x41,0xe4,0x09,0x12,0x70,0xd8,0x23,0xf8,0x08,0x78,0x3c,0x7e,0xf0,0x78,0x1c,0x03,0x81,0x07,0xff,0x40,0xc0,0xa5,0x19,0x10,0x8a,0x00,0xc6,0x05,0xc4,0xd7,0xc7,0xc0,0x82,0x00,0x13,0xf1,0xa4,0xc6,0x9e,0x08,0x3b,0xf8,0x3c,0xcb,0xa4,0x02,0x13,0x90,0xc1,0xa0,0x1a,0xcd,0x56,0xa8,0x84,0x50,0x0f,0x67,0xff,0xe7,0xf1,0xf9,0xfb,0x3f,0x30,0xfa,0x80,0xd8,0xa0,0x71,0x40,0x78,0xff,0x39,0xfe,0x7b,0xff,0x9f,0x89,0xff,0x85,0xc0,0x35,0x7a,0xed,0x58,0x90,0x45,0xe5,0x87,0x1f,0x94,0x02,0x9f,0x08,0xca,0x01,0x8a,0x9f,0x15,0x07,0x8d,0xe3,0x80,0x0f,0x30,0xc8,0xf0,0x35,0x41,0xf1,0x8d,0x14,0x13,0x9f,0xfb,0x07,0x8c,0x02,0x21,0xd0,0x0b,0x15,0x7e,0x2a,0x51,0x1b,0x07,0xfb,0xcd,0xff,0xe1,0x9f,0x8b,0x40,0x5e,0x1d,0x54,0xa8,0x3c,0x53,0xc9,0xce,0x43,0xff,0x01,0x44,0x93,0xc4,0x5a,0xc5,0x55,0xa8,0x40,0x77,0xd1,0xe8,0x07,0xdd,0xa4,0x20,0xf1,0xd8,0x07,0xca,0xd4,0x1f,0x28,0xf3,0x80,0x6f,0xf3,0x05,0x78,0xc1,0x14,0xe7,0x7f,0xaa,0xd5,0x60,0x30,0x48,0x06,0x02,0x3f,0xfe,0xfe,0x90,0x07,0x51,0xaa,0x40,0x0e,0xa8,0xbe,0x66,0x91,0xe3,0x86,0x45,0x3c,0x3f,0x96,0x39,0xd5,0x2a,0xa1,0x04,0xf7,0xfe,0xc4,0xa3,0xe8,0xd5,0x7f,0xf5,0xfb,0xa0,0xfa,0x16,0x87,0xc7,0x6f,0x80,0x55,0x3f,0xa1,0xf3,0x1f,0x8b,0xc9,0x38,0x70,0x30,0x20,0xeb,0x3f,0x5a,0xa0,0x08,0xb8,0x0c,0x1e,0x58,0x10,0x18,0xd0,0x03,0xef,0x54,0x09,0xab,0x9c,0x77,0x5a,0xaf,0x57,0xe8,0x16,0xd1,0xfb,0x85,0xc2,0x00,0x1f,0x50,0x80,0xd5,0x22,0x20,0xf1,0xff,0x7e,0x3f,0x01,0xfb,0xec,0x7f,0xef,0x12,0x00,0x78,0x87,0xce,0x2b,0x04,0x82,0xc5,0x03,0xc4,0x08,0x1f,0x1c,0x07,0xf9,0xbf,0x0f,0x8b,0x60,0x43,0xe9,0x5b,0x4f,0x90,0x7d,0x6a,0x35,0x58,0x28,0x04,0x59,0xe3,0xbe,0xbf,0x83,0xc7,0x59,0xef,0x3f,0x8e,0xbc,0x3e,0xbf,0xf8,0xf8,0x04,0x43,0xeb,0x55,0xa2,0xd0,0x6a,0xb1,0x58,0x07,0xee,0x13,0x97,0x07,0x8e,0xb0,0x7e,0x41,0xf5,0xe0,0x7f,0xe1,0xb1,0xf8,0x7a,0xfd,0xc3,0xe3,0x05,0xb0,0x43,0xf8,0x17,0xf6,0xf8,0xeb,0x35,0x40,0x02,0x0f,0xa4,0xc2,0x09,0xe0,0x8c,0x40,0x2a,0xa1,0xf8,0x09,0x95,0xc8,0x2a,0x41,0xf9,0x00,0x0c,0x40,0x04,0x35,0x14,0xa1,0x00,0x06,0xa7,0x55,0xaa,0x17,0x84,0x00,0x36,0x00,0x19,0x6b,0xbd,0x5a,0xa6,0x08,0xc0,0xc3,0xeb,0xf8,0x98,0x40,0x22,0xa1,0xe3,0xff,0xd5,0xea,0xb6,0x53,0xf9,0x03,0xc6,0xd1,0x00,0xc0,0x6b,0xb5,0x5f,0xb0,0x10,0xc2,0xe0,0x1b,0x00,0xf9,0xfb,0xbf,0x35,0x1f,0x28,0x7d,0x27,0xf5,0x5f,0xe1,0x00,0x4c,0x23,0xfe,0xd5,0xc3,0xb7,0x01,0xc1,0xd5,0x80,0x87,0xd7,0x80,0xd5,0x87,0x8b,0x01,0xff,0xfd,0x87,0x50,0x00,0x95,0x44,0x18,0xf8,0x29,0xfb,0x33,0xd0,0x87,0x07,0xf4,0x81,0x3b,0x50,0xfc,0xe1,0x1f,0x70,0xf4,0x5f,0xea,0xb5,0x03,0x01,0x69,0xc3,0xe6,0x00,0x49,0x52,0x01,0x3d,0xe1,0xf8,0x30,0x8c,0x16,0x82,0xdc,0x1e,0x68,0x71,0x40,0x05,0x1a,0x0f,0xa1,0x84,0x40,0x0f,0x4f,0x2f,0x0a,0xac,0x42,0x03,0xab,0x0e,0xa8,0x18,0x60,0xcc,0x15,0x6e,0xa3,0x85,0x6a,0xb4,0x16,0x09,0x97,0xd7,0x57,0xfa,0x0f,0x28,}; -const uint8_t _A_Levelup2_128x64_5[] = {0x01,0x00,0x9c,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1f,0xff,0xfb,0xcf,0xff,0xf0,0x3f,0xc0,0x18,0x7e,0x1e,0x30,0x83,0xdf,0xef,0xd0,0x0e,0x27,0xf6,0xf7,0xfc,0xe7,0x83,0x9b,0x7f,0xff,0x8f,0xff,0xa4,0x63,0x1c,0xe3,0xea,0xf3,0xd1,0xc0,0x20,0xe7,0xc6,0x84,0x2f,0x5b,0x97,0xfe,0xef,0xca,0xf8,0xf1,0xe0,0x20,0xd6,0xff,0x4c,0x7d,0x9a,0xad,0xd5,0x87,0xe1,0x4f,0xc0,0x7f,0xff,0xc3,0xe4,0xbe,0x40,0x2e,0xd5,0x5b,0xae,0x0f,0xe7,0x0f,0xf0,0x7f,0xfc,0x22,0x04,0x9b,0xc0,0x35,0x7a,0xad,0x56,0x1b,0xff,0x00,0xf8,0x7f,0x78,0xe0,0xf4,0x9f,0xe0,0xaa,0xa0,0x01,0xd6,0xcf,0xe0,0x04,0xe1,0x38,0x98,0xf8,0x67,0xfc,0x70,0xf0,0xea,0xa3,0x50,0xf0,0x79,0x13,0x93,0xa1,0xff,0xa3,0xd5,0xc3,0xe3,0x17,0x80,0x40,0x3f,0x80,0xf5,0x0b,0x0e,0xbf,0x56,0x02,0x19,0x70,0x3c,0x67,0x07,0xf6,0xc7,0xd9,0xee,0xa5,0xf1,0x9a,0xc0,0x20,0x90,0x03,0x00,0xef,0xfd,0xe0,0xf2,0x87,0xec,0x37,0x5a,0xaf,0x55,0xa8,0x3e,0x23,0x12,0xfe,0xf7,0xdb,0xa3,0x9f,0x86,0x74,0x2b,0xb5,0x5e,0xa8,0x08,0x60,0x20,0xf1,0xf8,0x10,0x12,0x11,0xa8,0xd7,0x17,0xc7,0x56,0x0d,0x18,0xe0,0xc0,0x8f,0xa5,0xff,0x89,0xf6,0x0b,0xe5,0xdf,0xaa,0x40,0x6f,0xe0,0xf1,0xfd,0xb7,0x0e,0x07,0xe8,0xd5,0x7f,0xb5,0x7b,0xa8,0x06,0x02,0x1f,0x8c,0xf1,0xb0,0x47,0xc7,0xef,0x07,0x8f,0xd7,0xaf,0x57,0xaf,0xdf,0xea,0xb8,0x58,0x7e,0xff,0xce,0x1d,0x12,0x10,0xfc,0xe0,0x7e,0xcf,0xd6,0xab,0xf5,0xba,0x27,0x0c,0x0d,0xbc,0x26,0xe2,0xbf,0xcb,0xe0,0x15,0x5b,0xed,0x5f,0xef,0x55,0xa0,0x84,0x04,0x1e,0x30,0xf7,0x89,0x41,0x8e,0xc2,0x7f,0x2f,0xd1,0xb8,0xaf,0xf7,0xfb,0xf2,0xcc,0x7e,0x70,0xe8,0x07,0x52,0xab,0x57,0xab,0xd7,0x68,0xb0,0x58,0x00,0x6c,0x6f,0x8b,0x21,0xb1,0xa5,0x88,0x3e,0xc6,0xe4,0x17,0x0d,0x53,0xaa,0x1f,0x51,0x00,0x8f,0x4b,0xff,0x0c,0x0f,0x96,0xfc,0x3e,0x3f,0xf0,0xf9,0x40,0x3f,0xa0,0xf2,0xc4,0xc0,0xe8,0x1f,0x5e,0xef,0xff,0xbf,0x7d,0xa2,0xb0,0x0b,0xf1,0x7f,0x10,0x8f,0x82,0x0f,0x00,0xd7,0x7f,0xf5,0x7f,0xed,0x7c,0x0c,0x3c,0x38,0x0f,0xfc,0xe7,0xfd,0x8d,0xff,0xc7,0xcf,0xe2,0xff,0x2a,0xa8,0x7c,0x68,0x38,0x0e,0xf9,0x88,0x70,0xe3,0x11,0x80,0xeb,0xf7,0xfa,0xbf,0x76,0xbc,0x4c,0x20,0x01,0x83,0x08,0x45,0xc0,0x50,0x76,0xe8,0x80,0x11,0x42,0x58,0x06,0x88,0xff,0xe7,0xd0,0x5d,0x5b,0xf8,0x40,0x02,0x77,0x10,0x01,0x70,0x3e,0x2b,0xf1,0xbc,0x4e,0x2b,0xb7,0x5a,0xbd,0xdd,0x06,0x31,0x5a,0x00,0x7c,0x7c,0x1f,0xcf,0xbf,0xff,0xd3,0x78,0xdd,0x87,0x8b,0xd4,0x1f,0x48,0x04,0xc1,0xc0,0x57,0x81,0xd0,0xa7,0xc6,0xab,0x05,0xa0,0x18,0x44,0x20,0x58,0xcc,0x1c,0x7f,0xe1,0xab,0xf5,0x6b,0x84,0x42,0x1f,0x51,0x09,0x43,0xa8,0x17,0x51,0xe0,0x90,0x86,0x0b,0x50,0xb2,0x90,0x86,0x01,0xf0,0x81,0xda,0x0c,0x82,0x5f,0x1f,0xfe,0xbf,0x54,0xf6,0x1d,0x80,0x74,0x96,0x23,0xd8,0x80,0x85,0xc7,0xab,0x57,0xaf,0xd5,0x66,0xb5,0x4e,0xe5,0x51,0xc2,0x7a,0x88,0x76,0xe0,0x78,0x3a,0xbd,0x77,0xab,0xdc,0x26,0x16,0x09,0xdf,0xab,0x7f,0x52,0xd8,0x97,0xce,0xab,0x7f,0xea,0xd1,0x20,0x14,0x0f,0x84,0xff,0x6e,0x7b,0x11,0xf8,0xfe,0x80,0x83,0xae,0xd5,0x5a,0x87,0xe5,0xe0,0x9f,0xd5,0xdb,0x43,0x5d,0x5e,0x11,0x88,0x40,0xe2,0x3e,0x18,0x07,0x9e,0xff,0xad,0x5e,0x18,0x00,0x83,0xe3,0x2a,0x07,0x0f,0xf3,0x9f,0xff,0xb7,0x85,0xc4,0xb8,0x21,0xf2,0x13,0x8c,0xd6,0xaa,0x4e,0x1e,0x3e,0x73,0x9d,0xba,0x10,0x37,0xaa,0x34,0x5e,0x1e,0xff,0xff,0xf3,0xb0,0x1e,0x88,0x7d,0x7a,0xb4,0xda,0x84,0x01,0x9a,0x3e,0x38,0x02,0x68,0x40,0x0d,0x07,0x1f,0x8d,0xff,0xec,0x0f,0x1a,0xb0,0x7d,0xaa,0xb0,0x33,0x00,0xc7,0x04,0x02,0xb2,0x10,0xf3,0x7e,0x9b,0xa7,0x3b,0xff,0x00,}; -const uint8_t _A_Levelup2_128x64_6[] = {0x01,0x00,0x54,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0x5f,0x78,0x37,0x20,0x3f,0xc0,0x7e,0x4f,0xff,0xde,0x3e,0x38,0xae,0xf9,0xf0,0x1c,0xe0,0x7e,0xf8,0xf3,0x3f,0xfd,0x9f,0xdc,0x1f,0xbe,0x6c,0x03,0x31,0xfd,0x1f,0xdc,0xca,0x01,0x60,0xfd,0x03,0xaa,0xff,0x09,0x80,0x60,0x3e,0x80,0xfa,0xdf,0xc1,0x20,0x10,0x0f,0x48,0x3e,0xab,0xf0,0x20,0x78,0xf4,0x81,0xd3,0xf7,0x07,0xfc,0xbf,0x03,0xff,0x87,0xe9,0x36,0xe0,0xf8,0xf1,0xcb,0xec,0x30,0x09,0x86,0x93,0x7f,0xf7,0x0f,0xc6,0x5e,0x21,0x00,0xa0,0x52,0x23,0xe0,0xe7,0xfe,0x83,0xc6,0x10,0x6f,0x1a,0x46,0xfc,0x5f,0x1f,0xcc,0x59,0xbc,0xb1,0x3b,0xe4,0x6c,0x03,0xc6,0x0e,0x0f,0x1c,0x7e,0xfb,0x07,0xdf,0x59,0xad,0xfe,0xf9,0x4b,0x84,0x7f,0xb0,0x79,0x0f,0x76,0x1c,0x7e,0xff,0x8d,0x2e,0x5e,0x07,0x4e,0x97,0xfd,0x7f,0xc0,0xf6,0xfd,0xfe,0xec,0xb5,0x88,0x17,0x4a,0x60,0x2c,0x4f,0x79,0xbd,0x2a,0xb3,0x88,0x17,0x8a,0xa0,0x0f,0x2f,0x88,0x85,0xaa,0xb3,0x08,0x15,0x8a,0xa1,0xbd,0x03,0x8f,0xc0,0x7a,0x65,0x02,0xea,0xc4,0x20,0x54,0x2a,0xc0,0x20,0x6f,0x9f,0x0f,0x98,0x30,0x7f,0xd8,0x7f,0x1f,0xf8,0x1e,0xb7,0x78,0xf7,0xe3,0xf6,0x20,0x2c,0x3f,0x0f,0xdf,0xd5,0x88,0x83,0xc6,0xb8,0x1f,0x18,0x7f,0xf0,0xc4,0x90,0x7c,0x1d,0x56,0x3f,0x02,0xe1,0x55,0xc7,0xe3,0x07,0x07,0x13,0x50,0xa7,0xf0,0x2d,0x2e,0x63,0xff,0xcf,0x94,0x07,0xc7,0xc7,0xff,0x8f,0x84,0x4a,0xfb,0x7e,0xb1,0x49,0xab,0xf0,0x1e,0xa4,0x9f,0x97,0x3d,0xf0,0x16,0x44,0x04,0x21,0xe1,0xfe,0x5d,0xa8,0xb3,0x08,0x0d,0x92,0x21,0xf5,0x8f,0xfe,0x2f,0x7f,0xcf,0x08,0x3c,0xa0,0x17,0x8c,0x2c,0x7e,0x03,0xc4,0x87,0xfd,0x61,0xff,0xeb,0xef,0xf0,0x64,0x3f,0xf8,0xec,0x02,0xe1,0x05,0x88,0x40,0x68,0x90,0x0f,0xaa,0xac,0xbf,0x9f,0xfd,0xff,0x7e,0x30,0x0f,0x18,0x4c,0x82,0x05,0x22,0xc0,0x7d,0x01,0x83,0xfd,0xf6,0x7f,0xaf,0x7f,0xe9,0xc4,0x1a,0x84,0x0f,0x48,0x27,0xe3,0x85,0x6f,0x09,0x0f,0xff,0xf3,0x10,0x87,0xc1,0x22,0x20,0xf2,0xa0,0x03,0xc6,0x86,0x6e,0x1f,0xbf,0xf7,0xe7,0x00,0x83,0xc6,0x22,0x34,0x08,0x14,0x48,0x1e,0x37,0xef,0x3c,0x0f,0xfc,0x43,0x1f,0x9f,0x02,0x07,0xf0,0x90,0x83,0x04,0x44,0x30,0x49,0xe4,0x06,0x01,0x1c,0xfe,0x04,0x07,0x67,0x03,0xb8,0x48,0x78,0x10,0x48,0xc8,0x3c,0x60,0x16,0x08,0x00,0x08,0x5e,0x43,0x4b,0x87,0x64,0x24,0x38,0x0f,0xec,0x36,0x41,0x0c,0x80,0x64,0x01,0xe3,0x00,0xf0,0x7b,0xf1,0x70,0x1b,0x04,0x47,0x01,0x07,0x87,0xd0,0x26,0x90,0x0c,0x64,0xc2,0x01,0xf0,0x58,0x0c,0x2e,0x1c,0x4f,0x18,0x04,0x06,0x09,0x40,0xe2,0x60,0x30,0x7b,0x88,0x07,0xfb,0xe2,0x0f,0x1f,0x84,0x1c,0x1e,0x30,0x68,0x19,0x48,0x6f,0xf8,0x0c,0x04,0x3f,0xdd,0xff,0xf6,0x45,0xe4,0x10,0x08,0x4c,0x03,0xf1,0x00,0x47,0x8c,0x82,0x81,0xc0,0x85,0xa4,0x07,0x82,0x0f,0x40,0x00,0x83,0xd2,0x23,0xd8,0xfc,0x61,0xe5,0xe0,0xf1,0x85,0x03,0xd4,0x10,0x26,0xe1,0xbc,0x47,0xe4,0xe0,0xf6,0x81,0x03,0xcb,0xe1,0x71,0xfc,0x4f,0xe8,0x71,0x00,0x7b,0x50,0x01,0x03,0xe0,0x81,0x83,0xc7,0x0f,0x08,0x07,0xb6,0x03,0x90,0x05,0x18,0x77,0x3e,0x5f,0x03,0x83,0x83,0xda,0x01,0xf7,0xe1,0xc3,0xff,0x11,0xbb,0xe4,0x16,0x0c,0x0f,0x7f,0xdf,0x9e,0x3f,0x70,0xbd,0xff,0x0f,0x64,0x0f,0x5f,0xc5,0xc2,0x79,0x3c,0x57,0x0f,0xfc,}; -const uint8_t _A_Levelup2_128x64_7[] = {0x01,0x00,0xf7,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x05,0xfd,0x83,0xfb,0xbe,0x20,0xf0,0xff,0x83,0x72,0x01,0xfe,0x07,0xdf,0xf6,0x3f,0xff,0xf8,0x83,0xf3,0xcf,0xf8,0xe7,0xc0,0xff,0xc0,0xf9,0xfc,0x46,0x60,0xd3,0x00,0xfe,0x41,0xa0,0x3c,0x0e,0xf0,0x3e,0xaf,0xb8,0x18,0x06,0x03,0xba,0x0f,0xad,0xfd,0x06,0x01,0x00,0xed,0x9e,0xee,0x80,0x0f,0x1f,0xa8,0x3e,0xb5,0xf2,0x00,0x78,0xfa,0x81,0xfb,0xf8,0xf5,0xb6,0xab,0x2e,0x0f,0x18,0x3f,0x5b,0x7e,0x10,0x9c,0xbf,0xfb,0x01,0x00,0xec,0x07,0xeb,0x17,0x01,0xa0,0xc0,0x76,0x01,0xf9,0x07,0x8d,0xf2,0x45,0x02,0x07,0xdd,0x2f,0x05,0x14,0x82,0x68,0x01,0xf3,0xe0,0xa2,0xe0,0xe1,0xb0,0x4b,0x03,0x8c,0x43,0xf1,0x25,0xa1,0xc2,0x61,0x16,0x08,0x5f,0xe8,0x1f,0x1a,0x59,0xe4,0x2b,0x11,0x6f,0x0f,0xcf,0xff,0x4b,0x24,0x85,0x5a,0x2e,0x04,0xfa,0xd1,0x03,0xc6,0x31,0xa0,0xdf,0x07,0xe7,0x44,0x2f,0x18,0x67,0x03,0x7d,0xfe,0x07,0xc5,0x0a,0x87,0x0a,0x89,0x60,0x01,0xc3,0xfd,0x06,0xac,0xff,0xff,0x46,0xc1,0xf3,0x64,0xf9,0xc1,0x7c,0x5f,0xfd,0xd8,0x6f,0x14,0xfe,0x51,0xa3,0xef,0x0f,0xe7,0x15,0x1c,0x80,0x7a,0x38,0x03,0xe9,0xff,0xc2,0xa1,0x70,0x09,0x47,0x03,0xfb,0xf7,0x07,0xc4,0x4a,0x09,0x00,0x8c,0x50,0x09,0xa3,0xef,0x1f,0x28,0x1c,0x41,0xe5,0x08,0x07,0x97,0x8c,0x3f,0x30,0x18,0x34,0x80,0x1e,0x3f,0xbf,0x38,0x3d,0xe0,0x18,0x68,0x08,0x3c,0x84,0x0b,0xf8,0x18,0x89,0x38,0x6f,0x10,0x08,0x80,0x3c,0xbe,0x20,0xf3,0xf8,0x4f,0xf7,0xf0,0x68,0x00,0x00,0x61,0x00,0xf1,0xbf,0xa8,0x13,0xc1,0x3f,0xce,0x40,0x81,0xe5,0x04,0x06,0x21,0x04,0x81,0xe3,0xbc,0x2f,0x08,0x00,0x60,0x5f,0x99,0xfa,0x44,0xbc,0x00,0x21,0xe0,0xff,0x37,0xf1,0x80,0x79,0x40,0x76,0xf1,0xf0,0x78,0xef,0xca,0x25,0x07,0xf8,0x6f,0xec,0x00,0xf2,0x80,0x7a,0x78,0xff,0xff,0xbc,0x3c,0x44,0x51,0xfe,0x46,0xff,0x81,0x01,0x07,0x98,0xf8,0xae,0x3c,0x05,0x01,0xef,0xe8,0x05,0x03,0x07,0x8f,0x3c,0x16,0x38,0x12,0xa1,0xef,0x81,0xed,0xb7,0x1e,0x11,0x88,0xc3,0xeb,0xed,0xff,0xd2,0xc1,0x83,0x0f,0xff,0xfc,0xf3,0x7f,0xfa,0x7c,0x84,0x7e,0x60,0xf1,0xa2,0x03,0xc7,0x1e,0xa3,0x1b,0x2f,0xfa,0x66,0x0f,0x4c,0xac,0x7e,0x87,0xd0,0x1e,0x9e,0x16,0x03,0x0c,0xd0,0x9b,0xce,0xc7,0xe0,0xa0,0x78,0x3c,0x3f,0xb0,0x78,0xc1,0x7f,0xd0,0x3c,0x88,0x3c,0xf0,0x71,0xf9,0x04,0x00,0xdc,0x70,0x58,0x44,0x02,0xa2,0x0f,0x38,0x1c,0x22,0x41,0xf0,0x81,0xff,0x92,0x03,0x0b,0x07,0x8d,0x28,0x1e,0x70,0x18,0x44,0x43,0xe0,0xb2,0x1c,0xff,0xfe,0x10,0x0f,0x19,0x50,0x3d,0x22,0x11,0x08,0xc5,0xfb,0x3c,0x70,0x18,0xbb,0x74,0x64,0xc0,0xf5,0xb4,0x4c,0x3f,0x18,0xf4,0x80,0x83,0xca,0x2c,0x0f,0x49,0x07,0xd3,0xc1,0x01,0xc0,0x13,0xc6,0x5e,0x9c,0x10,0x7a,0xd0,0x3f,0x5e,0x18,0x39,0x80,0x80,}; -const uint8_t _A_Levelup2_128x64_8[] = {0x01,0x00,0x02,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x00,0xbf,0xb0,0x7f,0x88,0x3c,0x3f,0xe1,0x0f,0x00,0x5c,0x3f,0xc0,0x1f,0xdf,0x8c,0x7c,0x1f,0x97,0xf8,0x77,0xf3,0xf8,0x21,0x10,0x04,0xe7,0xe0,0x30,0x2f,0x98,0x7e,0xed,0xf0,0x18,0x0f,0xb0,0x1e,0x7c,0xf8,0x4c,0xcb,0xe6,0x0f,0x38,0xb8,0x3c,0x7a,0x00,0x73,0xc7,0xf2,0x66,0x60,0xf4,0x85,0xe0,0x60,0x1a,0x00,0xf9,0x83,0xde,0x0b,0x82,0x80,0x50,0x00,0xe7,0x4f,0x84,0xc9,0xbf,0x20,0x62,0xff,0x40,0xa8,0x50,0x0f,0xc7,0xfb,0xde,0x0f,0x2e,0x4c,0x9c,0x1e,0xf0,0x6f,0xe8,0x3c,0xb9,0xfc,0x88,0x3f,0xe0,0xfc,0x70,0x1f,0xf4,0x02,0x03,0xfd,0xe3,0x83,0xcf,0x9f,0xfc,0x07,0x95,0xf8,0xbc,0x25,0x01,0xfd,0x07,0xce,0x13,0xce,0x07,0x95,0xff,0xf9,0x80,0xbe,0x0c,0x04,0x1e,0x60,0x06,0xdf,0x50,0x30,0x52,0x48,0x04,0x11,0x3d,0x3b,0xe9,0x06,0x0e,0x53,0x00,0x60,0x88,0x3e,0x2b,0xfa,0x0a,0x14,0x68,0xc0,0x29,0x01,0xe7,0xe0,0xf3,0x92,0x0a,0x7f,0xc8,0x1e,0x35,0xed,0x04,0xf0,0x1e,0x30,0x1f,0xa0,0x3c,0x7e,0x79,0xc9,0xe0,0x3c,0xc3,0xe3,0x24,0x85,0x70,0x20,0x1e,0x80,0x79,0x72,0x41,0xf1,0x30,0x80,0x83,0xcb,0x07,0xc9,0x17,0xa7,0x7c,0x5e,0x30,0xaf,0xc6,0x0b,0xd6,0x1f,0x4b,0x7b,0x5c,0x81,0xe3,0xc2,0x85,0x43,0xac,0xbe,0xc0,0x79,0x78,0xc1,0xeb,0x20,0x81,0xe2,0xe0,0x31,0xa1,0xf9,0x83,0xc4,0xde,0x94,0x1f,0x15,0xed,0x1e,0x20,0xf1,0x87,0xe0,0xbe,0xf2,0x0a,0x41,0x3c,0xf0,0x31,0xc8,0x64,0x02,0x04,0x6f,0x14,0x7c,0x40,0xa0,0xb0,0x83,0xf9,0x83,0xe2,0x09,0x02,0x80,0x1f,0xc7,0xf4,0x0f,0x98,0x40,0x3c,0x66,0x00,0xfb,0x88,0x60,0x20,0x04,0x01,0xfe,0x83,0xe6,0x41,0x00,0xc1,0xc0,0xf0,0x1f,0xe0,0x7d,0xdf,0x20,0x14,0x00,0x41,0x43,0xe0,0x10,0x0c,0x00,0x18,0xad,0xe0,0xf1,0x00,0x0e,0x80,0x10,0x5f,0x30,0x10,0xdf,0xc0,0xc5,0x97,0x8c,0x03,0xcb,0xa0,0x08,0x28,0x68,0x7c,0x86,0xc5,0x17,0x83,0x83,0xcb,0x30,0x0f,0x28,0x30,0x1c,0x8a,0xc5,0x17,0x37,0x08,0x00,0x6e,0x80,0xfa,0x82,0x01,0xcb,0x20,0x28,0x28,0x36,0x73,0x10,0x0f,0x45,0x68,0x83,0xdb,0x45,0x84,0x80,0x83,0xc7,0x7f,0x17,0x4e,0x09,0x7c,0x81,0xe9,0x82,0x81,0x87,0xcd,0x78,0x20,0xf7,0xc0,0xc1,0xc1,0xe7,0x40,0x80,0x83,0xcb,0xbd,0xbf,0x0f,0xc5,0x00,0xc0,0x41,0xf2,0xff,0x0f,0xd7,0xff,0x1b,0x07,0xb7,0xf0,0xbe,0xbd,0xf9,0x28,0x3c,0xfc,0x01,0x82,0x3f,0xa7,0xdf,0xe3,0x22,0x07,0x9f,0x03,0xf4,0x10,0x14,0x7a,0xde,0x24,0x20,0xf4,0xfa,0x07,0xc6,0x1c,0xbf,0x4c,0xfc,0x82,0x40,0x5f,0x2e,0x07,0x20,0x1e,0x23,0x22,0x6f,0x95,0x9c,0x1e,0xb3,0x0f,0xff,0xe3,0xf6,0x0c,0x13,0xa0,0xff,0xe3,0x20,0xf5,0x4a,0x0f,0xdd,0xce,0x5c,0x0f,0xfc,0x06,0x0d,0x40,0xc8,0x11,0xca,0x81,0x00,0xff,0xfa,0x1c,0x44,0x00,0x1f,0xf4,0x24,0x1e,0xd0,0x4f,0x47,0xf7,0xbe,0x0f,0x28,0x0c,0x22,0x81,0x50,0x07,0xa4,0x0b,0xd1,0xe3,0x0f,0x98,}; -const uint8_t _A_Levelup2_128x64_9[] = {0x01,0x00,0xfb,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x01,0x3d,0xe0,0xff,0x06,0xe4,0x07,0xe0,0x0f,0xab,0xff,0xfe,0x7f,0xfe,0xe7,0xe0,0xc3,0xd7,0xdf,0x80,0xce,0x03,0xf9,0x67,0x80,0x71,0xbd,0xc0,0xfb,0xad,0xc0,0x20,0x3e,0xd0,0x49,0xf3,0xe1,0x33,0x2f,0x98,0x3c,0xe8,0xb8,0x08,0x07,0xe8,0x1e,0x78,0xfe,0x4c,0xcc,0x1e,0x98,0x2a,0x04,0x03,0x88,0x71,0x30,0x7a,0xcb,0xef,0x58,0x10,0x78,0xee,0x01,0xe7,0x4f,0x84,0xc9,0xbf,0x21,0xf2,0xdf,0xe0,0x24,0x10,0x0a,0x30,0x3d,0x39,0x32,0x70,0x7a,0x40,0x24,0x30,0x0c,0x0f,0xfb,0x8e,0x4f,0x2e,0x44,0x1f,0xf0,0x0f,0x2a,0xfc,0x02,0x7f,0x80,0xc0,0x7f,0xa0,0x20,0xf3,0xe7,0xff,0x0a,0xc5,0x5f,0xe0,0x00,0x06,0x01,0xfd,0x0f,0x9c,0x27,0x9c,0x0f,0x2b,0xfc,0xbe,0x41,0x1e,0x90,0xc0,0x7f,0xaa,0x19,0x97,0xe4,0x2c,0x31,0x28,0x17,0x08,0x1f,0x5d,0x0e,0x04,0x3a,0x05,0x3a,0x07,0xcc,0x5e,0x91,0xa1,0x86,0x41,0x38,0xdf,0xe1,0xf0,0xe0,0xf3,0x92,0x0a,0x7f,0xc8,0x1e,0x52,0x88,0xf4,0x17,0x08,0x40,0x10,0x78,0xfc,0xf3,0x93,0xc0,0x7a,0xc4,0xa0,0xb4,0x86,0x09,0x03,0xc7,0x92,0x0f,0x8f,0xc0,0x3c,0xf0,0x7c,0x91,0x7c,0x43,0x38,0x3f,0xb0,0xfa,0x5b,0xc0,0xc3,0xff,0x9d,0x93,0xc6,0x09,0x7f,0xf9,0x03,0xcf,0xc6,0x0f,0x4a,0x5f,0x43,0xe1,0xc2,0xc0,0x7f,0x2f,0xa0,0xf4,0x37,0x9e,0x2f,0x21,0x0d,0x9f,0xc0,0x3f,0xf3,0xef,0xf4,0x3f,0x05,0xf7,0x90,0x52,0x07,0xe5,0x0b,0x90,0xc0,0xa0,0x90,0x0b,0xfd,0xfd,0x1f,0x10,0xbe,0x14,0x06,0x01,0x80,0xdf,0x83,0xa0,0x1e,0x30,0x40,0x78,0xf8,0x3b,0xe0,0xe8,0xfb,0xc2,0xe1,0x00,0xf1,0xfc,0x2f,0xa4,0x1e,0x54,0x08,0x07,0x3a,0x06,0xbf,0x10,0x03,0x78,0xc1,0xe3,0x80,0xe0,0xc0,0xff,0xeb,0xf1,0x0f,0xbc,0x34,0xba,0x3f,0xe8,0x0f,0xc1,0x10,0x50,0xf8,0x01,0x5c,0x41,0xe5,0x12,0x81,0x01,0xc4,0xf8,0x2b,0xf1,0xff,0xfc,0xc0,0x42,0x75,0x39,0x11,0x38,0x40,0x04,0x0f,0x28,0x68,0x7c,0x88,0xc5,0xc2,0x07,0x1c,0x00,0x5e,0x50,0x60,0x31,0x11,0x8a,0x05,0x03,0x03,0x97,0x03,0xf8,0x0f,0x98,0x60,0x1c,0xa6,0x03,0x82,0x83,0x67,0x31,0x00,0xf4,0x98,0x03,0xcb,0x9c,0x0f,0x3d,0x16,0x12,0x02,0x0f,0x3e,0x00,0xb8,0x87,0xc4,0x0f,0x2c,0x14,0x0c,0x1e,0x70,0x02,0x00,0xff,0x01,0xeb,0x81,0x83,0x83,0xd2,0x1c,0xbf,0x10,0xfe,0x44,0x9b,0xe3,0xf5,0x1f,0xd0,0x3c,0xa0,0x1f,0x42,0xfc,0xce,0xa0,0x10,0x90,0x78,0xfb,0x01,0xe6,0x7f,0x5a,0x30,0x3f,0x6f,0xf8,0x18,0x04,0x14,0x0e,0x3d,0x80,0x79,0x15,0x85,0x7e,0x77,0xf8,0x0e,0x05,0xe0,0x20,0xf4,0x15,0x93,0x7c,0xb7,0xf0,0x0c,0x13,0xc0,0xb5,0x00,0xf2,0x39,0x96,0xfc,0x1e,0x74,0x40,0x7b,0x41,0xd4,0xe4,0x05,0x1a,0xf8,0x3c,0x60,0x20,0x81,0xa4,0x03,0xc8,0x00,0xb2,0xf8,0x04,0xa0,0x1e,0x58,0x82,0x40,0x80,0x1a,0x2e,0x2b,0x13,0x39,0x42,0x09,0x84,0x00,0x40,}; -const uint8_t _A_Levelup2_128x64_10[] = {0x01,0x00,0x06,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x09,0xef,0x06,0xe4,0x07,0xe0,0x0f,0xc9,0xff,0xfb,0x9f,0xc7,0x07,0xdf,0x7e,0x03,0x38,0x0f,0xe5,0x9e,0x01,0xc6,0xf7,0x03,0xee,0xb7,0x00,0x80,0xff,0x4a,0x27,0xcf,0x84,0xcc,0xbe,0x60,0x51,0xbf,0xff,0xe8,0xb8,0x08,0x07,0xe8,0x2e,0x78,0xfe,0x4c,0xcc,0x1e,0x98,0x2a,0x04,0x03,0x88,0x1f,0x30,0x7a,0xcf,0xef,0xd8,0x10,0x78,0xee,0x01,0xe7,0x4f,0x84,0xc9,0xbf,0x21,0xf2,0xdf,0xe0,0x24,0x10,0x0a,0x37,0xfc,0xe2,0x54,0xfe,0x4c,0x9c,0x1e,0x90,0x09,0x0c,0x03,0x03,0xfe,0xd5,0x93,0xcb,0x91,0x07,0xfc,0x11,0x8a,0xbf,0x00,0x9f,0xe0,0x30,0x17,0xe8,0x89,0x88,0x41,0xe3,0xcf,0xfe,0x03,0xcf,0x80,0x00,0x18,0x07,0xf4,0x3e,0x70,0x9e,0x70,0x3c,0xe5,0xf2,0x08,0xf4,0x85,0x00,0x2b,0x19,0x97,0xe4,0x2c,0x31,0x28,0x17,0x09,0x63,0x1f,0xe9,0x7f,0x43,0x81,0x0e,0x81,0x4e,0x95,0xd3,0x17,0xa4,0x68,0x61,0x90,0x46,0x09,0x73,0xf0,0x79,0xc9,0x05,0x3f,0xe4,0x1f,0x18,0xbc,0xa2,0x3d,0x05,0xc2,0x30,0x4b,0x9f,0xf3,0xce,0x4f,0x01,0xeb,0x12,0x82,0xd2,0x18,0x24,0x0f,0x1e,0x48,0x3e,0x3f,0x00,0xf3,0xc1,0xf2,0x45,0xe5,0x5f,0xfa,0x0b,0xce,0x19,0xc1,0xfd,0x87,0xd2,0xde,0x06,0x1f,0xf4,0xec,0x9e,0x30,0x4b,0xff,0xc8,0x1e,0x7e,0x30,0x7a,0x52,0xfa,0x1f,0x0e,0x16,0x03,0xf8,0x4f,0x30,0x78,0x9b,0xcf,0x17,0x90,0x86,0xcf,0xe0,0x01,0x61,0xff,0xc3,0xf0,0x5f,0x79,0x05,0x20,0x9e,0x50,0xb9,0x0c,0x0a,0x09,0x00,0xbf,0xa3,0xe6,0x17,0xc2,0x80,0xc0,0x30,0x1b,0xf0,0x7d,0x41,0x01,0xe3,0xe0,0xef,0x83,0xea,0x10,0x0f,0x1f,0xc3,0x3a,0x01,0xe7,0x40,0x80,0x73,0xa0,0x64,0xf1,0x00,0x37,0xdc,0x1e,0x38,0x0e,0x0c,0x0f,0xfe,0x6f,0x10,0x03,0xc3,0x4b,0xa3,0xfe,0x80,0xfc,0x11,0x02,0x70,0x18,0x01,0x5c,0x41,0xe5,0x12,0x81,0x01,0xc7,0xfd,0x0f,0x5f,0x8f,0xff,0xe6,0x02,0x13,0xb1,0xc8,0x89,0xc2,0x00,0x20,0x79,0x43,0x43,0xe4,0x46,0x2e,0x10,0x38,0xe0,0x02,0xf2,0x83,0x01,0x88,0x8c,0x50,0x28,0x18,0x1c,0xb8,0x1f,0xc0,0x7c,0xc3,0x00,0xe5,0x30,0x1c,0x94,0x1b,0x39,0x88,0x07,0xa4,0xc0,0x1e,0x5c,0xe0,0x79,0xe8,0xb0,0x90,0x10,0x79,0xf0,0x05,0xc5,0xfb,0x9f,0x92,0x44,0x1e,0x38,0x28,0x18,0x3c,0xe0,0x04,0x01,0xfe,0x7e,0xc3,0xe9,0x81,0x83,0x83,0xd2,0x1c,0xbf,0x10,0x7a,0x87,0xda,0x24,0xdf,0x1f,0xaa,0x20,0x87,0xee,0x0f,0x28,0x07,0xd0,0x1e,0x65,0xf5,0x9d,0x40,0x21,0x20,0xf1,0xf6,0x03,0xcc,0xfe,0xb4,0x60,0x7e,0xdf,0xf0,0x30,0x08,0x28,0x1c,0x7b,0x00,0xf2,0x2b,0x0a,0xfc,0xef,0xf0,0x1c,0x0b,0xc0,0x41,0xe8,0x2b,0x23,0x29,0x6f,0xe0,0x18,0x27,0x81,0x6a,0x01,0xe4,0xd2,0x2d,0xf8,0x3c,0xe8,0x80,0xf6,0x83,0xa9,0xc8,0x0a,0x35,0xf0,0x78,0xc0,0x41,0x03,0x48,0x07,0x90,0x01,0x65,0xf0,0x09,0x40,0x3c,0xb1,0x04,0x81,0x00,0x34,0x5c,0x56,0x26,0x72,0x84,0x13,0x08,0x00,0x80,}; -const uint8_t* const _A_Levelup2_128x64[] = {_A_Levelup2_128x64_0,_A_Levelup2_128x64_1,_A_Levelup2_128x64_2,_A_Levelup2_128x64_3,_A_Levelup2_128x64_4,_A_Levelup2_128x64_5,_A_Levelup2_128x64_6,_A_Levelup2_128x64_7,_A_Levelup2_128x64_8,_A_Levelup2_128x64_9,_A_Levelup2_128x64_10}; - -const uint8_t _I_125_10px_0[] = {0x00,0xE0,0x00,0x00,0x01,0x0E,0x02,0x31,0x02,0x45,0x02,0x91,0x00,0xAA,0x00,0x92,0x00,0x44,0x00,0x38,0x00,}; -const uint8_t* const _I_125_10px[] = {_I_125_10px_0}; - -const uint8_t _I_Nfc_10px_0[] = {0x00,0x80,0x00,0x00,0x01,0x22,0x02,0x43,0x02,0x45,0x02,0x49,0x02,0x31,0x02,0x22,0x02,0x00,0x01,0x80,0x00,}; -const uint8_t* const _I_Nfc_10px[] = {_I_Nfc_10px_0}; - -const uint8_t _I_back_10px_0[] = {0x00,0x00,0x00,0x10,0x00,0x38,0x00,0x7C,0x00,0xFE,0x00,0x38,0x00,0x38,0x00,0xF8,0x01,0xF8,0x01,0x00,0x00,}; -const uint8_t* const _I_back_10px[] = {_I_back_10px_0}; - -const uint8_t _I_badusb_10px_0[] = {0x01,0x00,0x11,0x00,0x00,0x0f,0xe2,0x01,0xfc,0x80,0xdd,0x20,0x32,0x48,0x08,0x14,0x40,0x23,0xa8,0x08,0xa0,}; -const uint8_t* const _I_badusb_10px[] = {_I_badusb_10px_0}; - -const uint8_t _I_ble_10px_0[] = {0x00,0x04,0x00,0x8C,0x00,0x15,0x01,0x56,0x02,0x8C,0x02,0x8C,0x02,0x56,0x02,0x15,0x01,0x8C,0x00,0x04,0x00,}; -const uint8_t* const _I_ble_10px[] = {_I_ble_10px_0}; - -const uint8_t _I_dir_10px_0[] = {0x01,0x00,0x11,0x00,0x00,0x0c,0xfe,0x01,0x41,0x80,0x7f,0xe0,0x70,0x18,0x10,0x05,0x7f,0xd0,0x10,0x88,0x80,}; -const uint8_t* const _I_dir_10px[] = {_I_dir_10px_0}; - -const uint8_t _I_ibutt_10px_0[] = {0x00,0x80,0x03,0x40,0x02,0x20,0x02,0x10,0x01,0x8E,0x00,0x41,0x00,0x2D,0x00,0x2D,0x00,0x21,0x00,0x1E,0x00,}; -const uint8_t* const _I_ibutt_10px[] = {_I_ibutt_10px_0}; - -const uint8_t _I_ir_10px_0[] = {0x00,0xFC,0x00,0x02,0x01,0x79,0x02,0x84,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x58,0x00,0x78,0x00,0xFF,0x03,}; -const uint8_t* const _I_ir_10px[] = {_I_ir_10px_0}; - -const uint8_t _I_loading_10px_0[] = {0x00,0xFE,0x00,0x82,0x00,0xBA,0x00,0x54,0x00,0x28,0x00,0x28,0x00,0x44,0x00,0x92,0x00,0xBA,0x00,0xFE,0x00,}; -const uint8_t* const _I_loading_10px[] = {_I_loading_10px_0}; - -const uint8_t _I_music_10px_0[] = {0x01,0x00,0x10,0x00,0xf0,0x00,0x46,0x03,0x20,0x80,0x00,0x4e,0x7d,0x00,0x9f,0x80,0x4a,0x3c,0x13,0x20,}; -const uint8_t* const _I_music_10px[] = {_I_music_10px_0}; - -const uint8_t _I_sub1_10px_0[] = {0x01,0x00,0x12,0x00,0x81,0x40,0x69,0x30,0x2c,0x2c,0x0b,0x6a,0x01,0x28,0x0c,0x0a,0x65,0x01,0x98,0x40,0x00,0x26,}; -const uint8_t* const _I_sub1_10px[] = {_I_sub1_10px_0}; - -const uint8_t _I_u2f_10px_0[] = {0x00,0x00,0x00,0xFE,0x01,0x01,0x02,0x0C,0x00,0xF2,0x03,0x92,0x02,0x0C,0x00,0x01,0x02,0xFE,0x01,0x00,0x00,}; -const uint8_t* const _I_u2f_10px[] = {_I_u2f_10px_0}; - -const uint8_t _I_unknown_10px_0[] = {0x01,0x00,0x12,0x00,0xbc,0x40,0x39,0x90,0x0c,0x24,0x03,0x81,0x00,0xb0,0x40,0x26,0x00,0x12,0x00,0x08,0x14,0xc0,}; -const uint8_t* const _I_unknown_10px[] = {_I_unknown_10px_0}; - -const uint8_t _I_update_10px_0[] = {0x00,0xFE,0x01,0x01,0x02,0xFF,0x03,0x01,0x02,0x31,0x02,0x79,0x02,0xFD,0x02,0x31,0x02,0x31,0x02,0xFF,0x03,}; -const uint8_t* const _I_update_10px[] = {_I_update_10px_0}; - -const uint8_t _I_BLE_Pairing_128x64_0[] = {0x01,0x00,0xb7,0x01,0x00,0x6c,0x38,0x1f,0xd0,0x10,0x76,0xe0,0x03,0xdd,0x40,0x07,0xf4,0x82,0x01,0x08,0x07,0xf4,0xc0,0x1f,0x91,0x08,0x07,0x00,0x1f,0xc0,0x0d,0x1e,0xe8,0x3f,0xc0,0x03,0x58,0x80,0xcf,0x11,0xd9,0xaf,0x85,0x77,0x01,0xf7,0x60,0xf8,0x45,0xff,0x05,0xed,0x9e,0x7c,0x09,0xdb,0xe0,0x2f,0x78,0x03,0x3c,0x8e,0xee,0x8a,0x43,0x81,0xfb,0x0c,0x66,0xe8,0xfc,0x59,0xba,0x6f,0x28,0x1b,0xfb,0xa3,0x80,0xfc,0xa0,0x1f,0xc6,0x86,0xbf,0xc3,0x78,0xce,0x04,0x19,0x26,0x77,0xfa,0x43,0xbe,0x12,0xa0,0x7e,0xf8,0x2a,0xa2,0x02,0xff,0x89,0x27,0x01,0xbf,0x99,0x38,0x8a,0xfc,0x0f,0x8e,0x07,0xfe,0x0e,0x94,0x2c,0x07,0xfc,0x7f,0x1f,0xf5,0x00,0xc3,0x00,0xe4,0x31,0x13,0xd1,0x00,0x0a,0xb8,0x19,0x25,0x91,0xc0,0x81,0xe2,0xb9,0x4d,0x5d,0x78,0x64,0x2e,0x84,0x80,0x61,0x07,0x02,0x3e,0x2a,0xa4,0xa2,0x00,0xf2,0x40,0x20,0xe3,0x21,0xa0,0x62,0x9f,0x60,0x05,0x02,0x3e,0x36,0x41,0x66,0x23,0x20,0x51,0xfc,0x40,0x68,0x0f,0x15,0x90,0x60,0x20,0x1b,0x09,0x89,0x70,0x46,0x42,0x07,0x14,0x99,0x41,0xe8,0x1f,0x18,0x0c,0x07,0xc1,0x19,0xff,0xc3,0xce,0x6b,0x54,0x8f,0xe0,0x3f,0x90,0x78,0x17,0x02,0x1a,0x70,0x39,0x01,0xa0,0xb1,0x53,0xb5,0x88,0xc7,0xe0,0x98,0x08,0x3a,0xd5,0xe8,0x97,0xd0,0x78,0xcf,0xe1,0x07,0xf1,0x0d,0x08,0x00,0x74,0x10,0x80,0x18,0xe8,0x97,0xc3,0xf2,0xff,0xc4,0x03,0xe3,0x04,0x8c,0x19,0xcc,0x00,0x35,0x0c,0x3c,0x03,0xf9,0x3f,0xb0,0x8f,0xc6,0x31,0x0e,0x0f,0x90,0x90,0xb5,0x45,0xc1,0xf8,0x4f,0xf0,0xde,0x18,0xcc,0x82,0x08,0x1f,0x22,0x20,0xd0,0x3a,0xab,0xd1,0xe0,0x5f,0xa1,0x1b,0x19,0x8d,0x02,0x04,0x9a,0x1d,0x04,0x28,0x26,0x36,0xa8,0x05,0xf0,0xe0,0x3f,0x04,0xf8,0xd0,0x30,0x55,0xfa,0xad,0x54,0x3e,0x35,0x09,0xab,0xac,0xbf,0x2b,0xf2,0x0a,0x0e,0xfb,0x55,0xaa,0x0f,0x94,0x68,0x04,0x30,0x6f,0xd3,0x7c,0xb0,0x15,0x0f,0xfd,0x7f,0xeb,0x05,0x4f,0x0b,0x60,0xa3,0x1f,0x28,0x0b,0xfc,0xbc,0x30,0x1f,0xf7,0xfe,0x54,0x2c,0x18,0x30,0x3c,0x6f,0x00,0xf2,0x1c,0x8c,0xf8,0x10,0x3c,0x00,0xf8,0xd5,0x5c,0x05,0xb8,0xb0,0xaa,0xdb,0x01,0x2b,0x31,0x0a,0xdc,0xa7,0x00,0xe6,0x00,0x0c,0x56,0x00,0x7e,0x10,0x00,0xcc,0x01,0xf0,0x1f,0x1b,0x40,0x2e,0x00,0x07,0x16,0x10,0x90,0x02,0xe5,0x90,0x06,0x29,0x00,0x2a,0xa9,0x00,0x2f,0x10,0x02,0xa5,0x10,0x02,0xf1,0x00,0x2a,0xa0,0x0d,0xc0,0x00,0xec,0x01,0xfd,0x60,0x17,0x6a,0xc0,0x60,0x40,0xfd,0xc0,0x30,0x04,0x01,0xb0,0xb0,0x7f,0x45,0x80,}; -const uint8_t* const _I_BLE_Pairing_128x64[] = {_I_BLE_Pairing_128x64_0}; - -const uint8_t _I_Ble_connected_38x34_0[] = {0x01,0x00,0x60,0x00,0x80,0x7f,0xc0,0x65,0xc0,0xff,0xc0,0xc0,0x83,0xf0,0xff,0xc3,0xc0,0x83,0xf8,0xff,0xc7,0xc0,0x83,0xfc,0xff,0xcf,0xc0,0x8d,0xfe,0xf9,0xdf,0xe0,0x10,0x30,0x21,0xc1,0xff,0xfc,0x31,0x40,0xc3,0x80,0x87,0x0c,0xff,0xcc,0xc0,0x83,0x1c,0x02,0x1c,0x62,0x7f,0xf3,0xfe,0x4c,0x27,0x00,0x42,0xb8,0x4e,0x3f,0xf3,0x0f,0xff,0x80,0x04,0x20,0x11,0xe0,0x00,0x84,0x44,0x20,0x47,0x07,0x20,0x60,0xc4,0x48,0x2c,0x41,0xb2,0x10,0x14,0x94,0x85,0x43,0x2f,0x21,0xa1,0x0e,0xf2,0x86,0x44,0x82,0x26,0x91,0x48,0x80,}; -const uint8_t* const _I_Ble_connected_38x34[] = {_I_Ble_connected_38x34_0}; - -const uint8_t _I_Ble_disconnected_24x34_0[] = {0x01,0x00,0x3c,0x00,0x80,0x7f,0xe0,0x1c,0x08,0x04,0x0e,0x61,0x00,0x86,0x42,0x20,0x11,0x08,0x24,0x02,0x40,0x02,0x28,0x14,0x32,0x80,0x02,0x28,0x0c,0xf3,0x00,0x02,0x3e,0x60,0x08,0xf8,0x30,0xcc,0x18,0x08,0xa0,0x3c,0xf0,0x58,0x80,0x88,0x2e,0xa0,0xb4,0x0b,0xb0,0x8d,0x02,0xea,0x3b,0x52,0x3a,0x94,0x08,0xac,0x45,0xc2,0x31,0x10,}; -const uint8_t* const _I_Ble_disconnected_24x34[] = {_I_Ble_disconnected_24x34_0}; - -const uint8_t _I_Button_18x18_0[] = {0x01,0x00,0x19,0x00,0xfc,0x7f,0xe0,0x10,0x68,0x04,0x06,0x07,0x00,0x81,0x00,0xbc,0x05,0xe0,0x23,0x83,0xc0,0x20,0x7f,0xef,0xfc,0x07,0xf8,0x32,0x10,}; -const uint8_t* const _I_Button_18x18[] = {_I_Button_18x18_0}; - -const uint8_t _I_Circles_47x47_0[] = {0x01,0x00,0x7e,0x00,0x00,0x0f,0xe2,0x3e,0x04,0x2c,0x04,0x1f,0xc0,0x05,0x2b,0x00,0x08,0x60,0x60,0x21,0x8c,0x00,0x86,0x18,0x02,0x18,0x20,0x08,0x62,0x00,0xe4,0x0a,0x0e,0x00,0x40,0x70,0x0a,0x00,0xb0,0xe0,0x32,0x00,0x29,0xc0,0x80,0xaa,0x1f,0x21,0x39,0x42,0x00,0xa7,0x08,0x02,0xa8,0xd0,0x86,0xc4,0x05,0x1f,0x84,0x1c,0x0a,0x30,0x22,0x28,0x92,0x46,0x40,0x05,0x11,0x61,0x01,0x4a,0x02,0x3e,0x10,0x28,0x91,0x04,0x02,0x32,0x08,0x08,0x14,0xe8,0x00,0xf2,0x09,0x90,0x17,0xc0,0xbe,0x05,0x41,0x7a,0x0e,0xd4,0x8e,0xc5,0x36,0x2f,0x99,0xad,0x4e,0xea,0x89,0xb4,0xda,0xab,0x6d,0x7e,0xac,0xb5,0x6b,0xab,0x8d,0x9d,0xea,0xfb,0x5c,0x04,0x1f,0xe0,0x26,0x3f,0xc4,0x3c,0x06,0x20,}; -const uint8_t* const _I_Circles_47x47[] = {_I_Circles_47x47_0}; - -const uint8_t _I_Ok_btn_9x9_0[] = {0x01,0x00,0x0f,0x00,0xbe,0x40,0x30,0x50,0x09,0xcc,0x06,0xfa,0x01,0x40,0x38,0x82,0xc4,0x1e,0x20,}; -const uint8_t* const _I_Ok_btn_9x9[] = {_I_Ok_btn_9x9_0}; - -const uint8_t _I_Pressed_Button_13x13_0[] = {0x01,0x00,0x12,0x00,0xf8,0x40,0x7f,0x90,0x7f,0xf4,0x3c,0x02,0x3f,0xf8,0xf8,0x05,0xc1,0xa6,0x13,0x10,0xb8,0x80,}; -const uint8_t* const _I_Pressed_Button_13x13[] = {_I_Pressed_Button_13x13_0}; - -const uint8_t _I_Space_65x18_0[] = {0x01,0x00,0x26,0x00,0xfc,0x7f,0xc0,0x09,0x7f,0x80,0x41,0x81,0xeb,0x80,0x80,0x40,0xc3,0x2d,0x01,0x04,0x78,0x23,0xc1,0x1e,0x08,0xf0,0x47,0x82,0x3c,0x11,0x70,0x73,0xeb,0x40,0x7f,0xc8,0xf5,0xff,0xc0,0x3f,0x89,0x87,}; -const uint8_t* const _I_Space_65x18[] = {_I_Space_65x18_0}; - -const uint8_t _I_Voldwn_6x6_0[] = {0x00,0x08,0x0C,0x2F,0x2F,0x0C,0x08,}; -const uint8_t* const _I_Voldwn_6x6[] = {_I_Voldwn_6x6_0}; - -const uint8_t _I_Volup_8x6_0[] = {0x00,0x48,0x8C,0xAF,0xAF,0x8C,0x48,}; -const uint8_t* const _I_Volup_8x6[] = {_I_Volup_8x6_0}; - -const uint8_t _I_Clock_18x18_0[] = {0x01,0x00,0x31,0x00,0xe0,0x43,0xe0,0x1f,0x09,0xfc,0x03,0xf1,0x7f,0x80,0x47,0x3c,0x10,0x0d,0xf7,0xde,0x02,0x02,0x2d,0xff,0xde,0x07,0x7f,0xfd,0xc0,0xff,0xff,0xc0,0x11,0xdf,0xff,0x30,0x3d,0xff,0xca,0x07,0x3e,0xfa,0x85,0xc7,0xe5,0x01,0x10,0x10,0x98,0x85,0x84,0x32,0x20,}; -const uint8_t* const _I_Clock_18x18[] = {_I_Clock_18x18_0}; - -const uint8_t _I_Error_18x18_0[] = {0x01,0x00,0x2c,0x00,0xe0,0x43,0xe0,0x1f,0x09,0xfc,0x03,0xf1,0x7f,0x80,0x7f,0x3f,0xf0,0x0e,0x77,0x3e,0x03,0x8e,0xe3,0xc0,0x63,0xfe,0x38,0x1c,0xff,0xe1,0x03,0xbf,0xfe,0x00,0x46,0x08,0x20,0x71,0x05,0x08,0x34,0x42,0x02,0x13,0x10,0xb0,0x86,0x44,}; -const uint8_t* const _I_Error_18x18[] = {_I_Error_18x18_0}; - -const uint8_t _I_EviSmile1_18x21_0[] = {0x01,0x00,0x39,0x00,0x86,0x70,0x20,0x10,0x6c,0x04,0x06,0x0f,0x80,0x81,0xf3,0xf9,0xf0,0x3f,0xff,0xfc,0x04,0x7f,0xef,0xfc,0x04,0x04,0xbf,0x7d,0xfc,0x0f,0xcf,0x9f,0x81,0xf1,0xf1,0xf0,0x3c,0x3e,0x1e,0x07,0x8f,0xe3,0x86,0x9b,0xbd,0xef,0x80,0xef,0x3e,0x90,0x0b,0xc5,0xe2,0x01,0xf0,0x9f,0xc0,0x38,0x10,0xf8,0x00,}; -const uint8_t* const _I_EviSmile1_18x21[] = {_I_EviSmile1_18x21_0}; - -const uint8_t _I_EviSmile2_18x21_0[] = {0x01,0x00,0x37,0x00,0x00,0x14,0x3b,0x81,0x01,0x83,0xe0,0x20,0x7c,0xfe,0x7c,0x0f,0xff,0xff,0x01,0x1f,0xfb,0xff,0x01,0x01,0x2f,0x9f,0x3f,0x03,0xe3,0xe3,0xe0,0x78,0x7c,0x3c,0x0f,0x1f,0xc7,0x0d,0x37,0x3b,0x99,0x01,0xcf,0x79,0x20,0x33,0xcf,0x84,0x03,0xf1,0x7f,0x80,0x7c,0x27,0xf0,0x0e,0x04,0x3e,0x00,}; -const uint8_t* const _I_EviSmile2_18x21[] = {_I_EviSmile2_18x21_0}; - -const uint8_t _I_EviWaiting1_18x21_0[] = {0x01,0x00,0x34,0x00,0x86,0x70,0x20,0x10,0x6c,0x04,0x06,0x0f,0x80,0x81,0xf3,0xf9,0xf0,0x3f,0xff,0xfc,0x04,0x7f,0xef,0xfc,0x04,0x04,0xa0,0xb2,0xdb,0xeb,0xe0,0x7b,0xfd,0xfc,0x0f,0x3f,0x9f,0x81,0xf1,0xf8,0xe1,0xa9,0xfe,0x7f,0xe0,0x1f,0x8b,0xfc,0x03,0xe1,0x3f,0x80,0x70,0x21,0xf0,0x00,}; -const uint8_t* const _I_EviWaiting1_18x21[] = {_I_EviWaiting1_18x21_0}; - -const uint8_t _I_EviWaiting2_18x21_0[] = {0x01,0x00,0x31,0x00,0x86,0x70,0x20,0x10,0x6c,0x04,0x06,0x0f,0x80,0x81,0xf3,0xf9,0xf0,0x3f,0xff,0xfc,0x04,0x7f,0xef,0xfc,0x04,0x04,0xa0,0xb2,0xeb,0xed,0xe0,0x7f,0x7f,0xb8,0x08,0xf1,0xf8,0xf0,0xd4,0xff,0x3f,0xf0,0x0f,0xc5,0xfe,0x01,0xf0,0x9f,0xc0,0x38,0x10,0xf8,0x00,}; -const uint8_t* const _I_EviWaiting2_18x21[] = {_I_EviWaiting2_18x21_0}; - -const uint8_t _I_Percent_10x14_0[] = {0x00,0x0C,0x03,0x1E,0x03,0x33,0x03,0xB3,0x03,0xDE,0x01,0xEC,0x00,0x70,0x00,0x38,0x00,0xDC,0x00,0xEE,0x01,0x37,0x03,0x33,0x03,0xE3,0x01,0xC3,0x00,}; -const uint8_t* const _I_Percent_10x14[] = {_I_Percent_10x14_0}; - -const uint8_t _I_Smile_18x18_0[] = {0x01,0x00,0x2d,0x00,0xe0,0x43,0xe0,0x1f,0x09,0xfc,0x03,0xf1,0x7f,0x80,0x7f,0x3f,0xf0,0x0f,0xf7,0xfe,0x02,0x02,0x2f,0xff,0xfe,0x07,0xcf,0xe7,0xc0,0xf0,0xf8,0x70,0x11,0x82,0x08,0x1c,0x41,0x42,0xdf,0x7d,0xe0,0x37,0xcf,0xc0,0x98,0xc5,0x84,0x32,0x20,}; -const uint8_t* const _I_Smile_18x18[] = {_I_Smile_18x18_0}; - -const uint8_t _I_UsbTree_48x22_0[] = {0x01,0x00,0x3c,0x00,0x00,0x14,0x3c,0x08,0x78,0x08,0xf8,0x10,0xff,0xe0,0x59,0xb0,0x04,0x52,0xc0,0x1d,0x48,0xc0,0x9d,0x00,0xa7,0x02,0x80,0x41,0x80,0xa5,0x0e,0x02,0xa4,0xfb,0xfe,0x00,0xa1,0x49,0x04,0x48,0x0a,0x81,0xd1,0xc0,0x40,0x45,0x26,0x05,0x30,0x01,0x41,0xbe,0x10,0x30,0x2c,0x7e,0x3f,0xe0,0x59,0x80,0x04,0x50,0x0a,0x60,}; -const uint8_t* const _I_UsbTree_48x22[] = {_I_UsbTree_48x22_0}; - -const uint8_t _I_ButtonCenter_7x7_0[] = {0x00,0x1C,0x22,0x5D,0x5D,0x5D,0x22,0x1C,}; -const uint8_t* const _I_ButtonCenter_7x7[] = {_I_ButtonCenter_7x7_0}; - -const uint8_t _I_ButtonDown_7x4_0[] = {0x00,0x7F,0x3E,0x1C,0x08,}; -const uint8_t* const _I_ButtonDown_7x4[] = {_I_ButtonDown_7x4_0}; - -const uint8_t _I_ButtonLeftSmall_3x5_0[] = {0x00,0x04,0x06,0x07,0x06,0x04,}; -const uint8_t* const _I_ButtonLeftSmall_3x5[] = {_I_ButtonLeftSmall_3x5_0}; - -const uint8_t _I_ButtonLeft_4x7_0[] = {0x00,0x08,0x0C,0x0E,0x0F,0x0E,0x0C,0x08,}; -const uint8_t* const _I_ButtonLeft_4x7[] = {_I_ButtonLeft_4x7_0}; - -const uint8_t _I_ButtonRightSmall_3x5_0[] = {0x00,0x01,0x03,0x07,0x03,0x01,}; -const uint8_t* const _I_ButtonRightSmall_3x5[] = {_I_ButtonRightSmall_3x5_0}; - -const uint8_t _I_ButtonRight_4x7_0[] = {0x00,0x01,0x03,0x07,0x0F,0x07,0x03,0x01,}; -const uint8_t* const _I_ButtonRight_4x7[] = {_I_ButtonRight_4x7_0}; - -const uint8_t _I_ButtonUp_7x4_0[] = {0x00,0x08,0x1C,0x3E,0x7F,}; -const uint8_t* const _I_ButtonUp_7x4[] = {_I_ButtonUp_7x4_0}; - -const uint8_t _I_DFU_128x50_0[] = {0x01,0x00,0x2e,0x02,0x00,0x57,0xfe,0x0e,0x0e,0xcf,0x84,0x02,0x70,0x0f,0xc8,0x74,0x03,0x80,0x0e,0xbc,0x7c,0x04,0x06,0x30,0x30,0x74,0xe0,0x2f,0xe0,0x42,0x82,0x03,0xe7,0x81,0xff,0x02,0x14,0x20,0x1f,0x3e,0x00,0x79,0xc4,0x01,0xfd,0x20,0x07,0xd5,0xd4,0xe2,0x53,0xf2,0x74,0xff,0xe1,0x40,0x41,0x87,0xd8,0x01,0xf1,0x60,0xf0,0x43,0xca,0x43,0xe0,0xa7,0x83,0xe2,0x30,0x01,0x29,0x84,0x7b,0x20,0x0f,0x88,0x30,0x3c,0xb1,0x90,0x1d,0x00,0xfa,0x30,0x3f,0xf8,0xcc,0x02,0xc6,0x31,0x1f,0x83,0x49,0xa8,0x16,0x0a,0xf4,0x7f,0x00,0x21,0x1f,0x04,0x38,0x06,0x20,0x04,0x90,0x46,0x35,0xf0,0xfa,0x00,0xcc,0x7f,0x10,0x14,0x0b,0x46,0x20,0xd5,0x70,0x50,0xb4,0x06,0xf1,0x00,0x9f,0x03,0xd7,0x09,0x81,0xd7,0xc0,0x8b,0x85,0x38,0xc0,0x50,0x41,0xeb,0x63,0xc0,0x07,0xc6,0x90,0xbf,0x2b,0x05,0x01,0xb8,0xb1,0x0c,0x06,0xae,0x01,0x24,0x6f,0x94,0x42,0x80,0xb2,0x49,0xc4,0x33,0x80,0x1f,0x18,0x93,0xfc,0xa1,0x14,0x0e,0x02,0x9c,0x43,0xc3,0x07,0x81,0xfc,0x03,0xe2,0xc0,0x28,0x14,0x10,0x5e,0x3f,0x03,0xc0,0xcf,0xf8,0x10,0x0f,0xe5,0x56,0x03,0x05,0xf0,0x40,0x20,0x20,0xf2,0x42,0x0d,0xfd,0x72,0x30,0x0f,0xf8,0x7c,0x41,0xe3,0x80,0x10,0x0d,0x00,0x5c,0x4a,0xd1,0x87,0xf8,0x39,0xf5,0x5c,0x0c,0x0b,0xe0,0x1c,0x10,0x78,0xfc,0x02,0x04,0x20,0x1f,0xf7,0x0f,0x57,0x80,0x81,0x5e,0x13,0x83,0x01,0x1f,0x97,0xff,0xfe,0x03,0x2e,0x07,0x57,0x03,0x01,0xbf,0x1d,0x45,0x70,0x27,0xe4,0xff,0x8c,0x07,0xf5,0x83,0xe0,0xcf,0xe1,0x00,0xf6,0x10,0x8c,0x07,0xb1,0x07,0xc1,0xfc,0x63,0xe5,0xd2,0x07,0x8f,0x80,0x1a,0x21,0xe1,0xc0,0x71,0xe0,0x20,0xf1,0x24,0x88,0x34,0x62,0x00,0xe3,0x3f,0x8d,0xfe,0x81,0x80,0xc1,0xf8,0x5b,0xe2,0x0f,0x18,0xc7,0xf0,0x1e,0x50,0x35,0xa0,0xc8,0x3f,0x98,0x30,0x70,0x87,0x44,0x1e,0x21,0xe3,0xf8,0x02,0x4b,0xaf,0x01,0x81,0xb3,0xca,0x01,0x1c,0x25,0x94,0x01,0x04,0x58,0x8d,0x5c,0x0b,0xc6,0x08,0x10,0x78,0xc3,0x3f,0xf0,0x72,0x88,0x98,0x8b,0x89,0x55,0x82,0xc7,0x9b,0xe5,0x00,0x87,0x26,0xc4,0x46,0x20,0xf2,0xd1,0x87,0xc6,0x0c,0xdf,0x21,0x50,0x8a,0xc7,0x00,0x38,0x2e,0x04,0x42,0xaf,0x05,0x06,0x0a,0xb8,0x70,0x0f,0x91,0x80,0x5c,0x03,0xc5,0x30,0x84,0x6a,0xe1,0x40,0xf1,0x7b,0x0f,0x00,0x7a,0x24,0x21,0x07,0x94,0x33,0x09,0x57,0x8a,0x93,0x85,0xec,0x3e,0x00,0x79,0x0b,0x88,0x06,0x3c,0x3f,0xfc,0xa8,0x1e,0x21,0x91,0x76,0x90,0x90,0x40,0x03,0xe0,0xe0,0x78,0x3f,0xd5,0x58,0x0e,0x08,0x32,0x3f,0x88,0xa8,0x90,0x8c,0x25,0x30,0xbc,0x7f,0xb5,0x50,0x1b,0xe0,0x20,0x7f,0x92,0x33,0x88,0x97,0x4a,0x07,0x0c,0x9e,0x5f,0xeb,0xaa,0xf2,0x74,0x8d,0x17,0x80,0x06,0x29,0xf1,0xe0,0x71,0xfb,0xfd,0x71,0xd8,0xff,0xf8,0x21,0x71,0x04,0x87,0x01,0xc1,0xa1,0xff,0x83,0xe7,0xf0,0xff,0xc1,0x51,0xe4,0xdd,0x1b,0x07,0xc2,0x63,0xf6,0x0f,0x9f,0xeb,0x5f,0x02,0x77,0x8a,0xc4,0xa3,0x17,0xc8,0x44,0x8c,0x34,0x20,0x71,0xfe,0x99,0x04,0x88,0x40,0x01,0xc3,0x47,0xf0,0x93,0x0f,0xf4,0x28,0x0e,0x3a,0xad,0x50,0x39,0x30,0x1f,0x18,0x3d,0x0e,0x31,0xff,0x3d,0x0c,0x02,0xa8,0x03,0x20,0x01,0x7e,0x3f,0xf8,0x09,0x06,0x33,0xfe,0x1b,0x50,}; -const uint8_t* const _I_DFU_128x50[] = {_I_DFU_128x50_0}; - -const uint8_t _I_Warning_30x23_0[] = {0x01,0x00,0x47,0x00,0x80,0x70,0x00,0x65,0xe0,0x80,0x80,0xc7,0xe1,0x03,0x01,0xaf,0xe2,0x0e,0x03,0x19,0xe4,0x3c,0x06,0xb3,0xe8,0xf8,0x0c,0x67,0xf3,0xf0,0x1a,0x60,0x27,0xf7,0xf1,0x50,0xcf,0xff,0xe0,0x34,0xf0,0x00,0xc6,0x03,0xf0,0x01,0x8c,0x0c,0x06,0x7f,0x80,0x18,0xc1,0xff,0x9f,0xff,0xfc,0x3c,0x06,0x7f,0xe0,0x58,0xc7,0xff,0xe0,0x31,0x00,0x88,0x00,0x67,0xff,0xe0,0x18,0xc7,0xc0,}; -const uint8_t* const _I_Warning_30x23[] = {_I_Warning_30x23_0}; - -const uint8_t _A_Loading_24_0[] = {0x01,0x00,0x37,0x00,0x00,0x17,0x83,0xff,0x0f,0x90,0x40,0x21,0x1c,0x0f,0xfc,0x1f,0x01,0x00,0x81,0x60,0x35,0x40,0x21,0xaa,0x00,0x86,0x51,0x02,0x80,0x44,0x60,0x30,0x0c,0x10,0x6c,0x6a,0x80,0x21,0x94,0x00,0x92,0x88,0x02,0x1c,0x90,0x08,0x60,0x30,0x11,0x19,0x80,0x9c,0x64,0x43,0x82,0x1f,0x11,0x10,0x80,}; -const uint8_t _A_Loading_24_1[] = {0x01,0x00,0x38,0x00,0x00,0x17,0x83,0xff,0x0f,0x90,0x40,0x21,0x1c,0x0f,0xfc,0x1f,0x01,0x00,0x81,0x00,0x8e,0xa8,0x02,0x19,0x44,0x0a,0x01,0x11,0x80,0xc0,0x30,0x41,0xb1,0xa2,0x00,0x86,0x50,0x02,0x40,0x41,0x64,0x80,0x43,0x01,0x80,0xe0,0x22,0x02,0x34,0x01,0x16,0xaa,0x04,0x32,0x21,0xc1,0x0f,0x88,0x88,0x40,}; -const uint8_t _A_Loading_24_2[] = {0x01,0x00,0x36,0x00,0x00,0x17,0x83,0xff,0x0f,0x90,0x40,0x21,0x1c,0x0f,0xfc,0x1f,0x01,0x00,0x81,0x00,0x9a,0x51,0x02,0x80,0x44,0x60,0x30,0x0c,0x10,0x6c,0x68,0x80,0x21,0x94,0x00,0x92,0xa8,0x02,0x10,0x71,0x05,0x04,0x3a,0x70,0x80,0x10,0xd5,0x00,0x43,0xaa,0x81,0x0c,0x88,0x70,0x43,0xe2,0x22,0x10,}; -const uint8_t _A_Loading_24_3[] = {0x01,0x00,0x33,0x00,0x00,0x17,0x83,0xff,0x0f,0x90,0x40,0x21,0x1c,0x0f,0xfc,0x1f,0x01,0x00,0x81,0x00,0xa2,0x01,0x01,0x80,0xc0,0x30,0x41,0xb1,0xa2,0x00,0x86,0x50,0x02,0x40,0x41,0x64,0x80,0x43,0x29,0x80,0xe0,0x2a,0x81,0xd1,0xd5,0x00,0x84,0x0a,0x83,0x22,0x1c,0x10,0xf8,0x88,0x84,}; -const uint8_t _A_Loading_24_4[] = {0x01,0x00,0x42,0x00,0x80,0x40,0x80,0x43,0x07,0x80,0x60,0x00,0xa3,0x40,0x82,0xc0,0x34,0x10,0x88,0x05,0x42,0x21,0x00,0x94,0x00,0x86,0x28,0x02,0x18,0x50,0x08,0x60,0xe0,0x54,0x88,0x78,0x20,0xe0,0x11,0x0c,0x0c,0xa2,0xa1,0x00,0xa4,0x79,0x60,0x1a,0x8a,0x90,0x14,0x65,0x20,0x51,0x8a,0x01,0x46,0x14,0x18,0x11,0x81,0x0d,0x8a,0x03,0x00,0xf0,0x10,0x46,0x81,0x00,}; -const uint8_t _A_Loading_24_5[] = {0x01,0x00,0x2d,0x00,0x00,0x74,0x1a,0x01,0x60,0x85,0x40,0x2a,0x1f,0xa8,0x05,0x7e,0x15,0x81,0xa8,0x42,0xa8,0x40,0x21,0x92,0x00,0x86,0x31,0x5a,0x85,0x50,0x2a,0xb0,0xac,0xc0,0x14,0x64,0x80,0x51,0xa1,0x01,0x44,0x2e,0x21,0xd3,0x11,0x88,0xa4,0x87,0x16,}; -const uint8_t _A_Loading_24_6[] = {0x01,0x00,0x43,0x00,0x80,0x50,0x00,0x43,0xe0,0x02,0x94,0x06,0x01,0xa0,0x81,0x40,0x22,0x10,0x58,0x04,0x22,0x14,0x02,0x18,0xa4,0x02,0x91,0x29,0x80,0x6a,0x2a,0x40,0x51,0xf2,0x81,0x4b,0xc1,0x07,0x84,0x44,0x00,0x63,0x0a,0x88,0x40,0x20,0xe0,0x21,0x02,0x94,0x50,0x04,0x32,0x80,0x10,0xd4,0x00,0x43,0xa0,0x84,0x0d,0x04,0x5c,0x38,0x01,0xa0,0x86,0x04,0x04,0x20,0x51,}; -const uint8_t* const _A_Loading_24[] = {_A_Loading_24_0,_A_Loading_24_1,_A_Loading_24_2,_A_Loading_24_3,_A_Loading_24_4,_A_Loading_24_5,_A_Loading_24_6}; - -const uint8_t _I_DolphinFirstStart0_70x53_0[] = {0x01,0x00,0x5a,0x01,0x80,0x60,0x3f,0xf7,0xf0,0x42,0xf8,0x01,0x43,0x07,0x04,0x24,0x72,0x01,0xc0,0x9d,0x82,0x13,0xff,0xff,0xbd,0x70,0x20,0x20,0x72,0xe0,0x40,0x2a,0x11,0xdb,0x00,0x6c,0xec,0x10,0x0d,0x44,0x3a,0x71,0x0e,0x04,0x14,0x42,0x01,0x54,0x86,0xd3,0x27,0x02,0x44,0xd4,0x41,0xb0,0xf2,0x10,0x42,0x55,0x38,0x71,0x1b,0x10,0x18,0xa0,0x41,0x11,0xb1,0xc8,0x28,0x98,0x09,0xfc,0x00,0x72,0x35,0x49,0x8d,0x0b,0xc1,0x70,0xf0,0x10,0x4b,0x51,0x11,0xc2,0x6c,0x0a,0xa3,0x03,0x80,0x7f,0xbf,0xf3,0x08,0x46,0x60,0x90,0x30,0x60,0x50,0xd8,0x2c,0x11,0x0c,0x71,0x5c,0x60,0xf8,0x0f,0xcf,0x3f,0x81,0x80,0xa1,0x9e,0x86,0x0f,0xc0,0x82,0x64,0x30,0x3e,0x09,0x84,0x03,0xf1,0x03,0xa0,0x40,0xa4,0x18,0x39,0xfc,0x20,0x52,0x30,0x19,0x07,0xc6,0x8e,0x4a,0x18,0x22,0x74,0x60,0x1a,0x0f,0xc6,0x3c,0x60,0x5c,0x05,0x28,0xe4,0x3f,0x99,0xf8,0x22,0x28,0x7e,0x05,0x91,0xa8,0x7f,0x23,0xf0,0x59,0x00,0xac,0x63,0xe0,0x81,0xcf,0x4f,0xe0,0xb1,0x81,0x58,0xc3,0xc1,0x08,0x24,0x1f,0xf9,0x68,0x6a,0x1f,0xe9,0xff,0x16,0x02,0x34,0x13,0x50,0x82,0x0a,0xea,0x60,0x1f,0xf9,0xf0,0x41,0x05,0x1d,0x30,0x09,0x18,0x60,0x15,0xa3,0xe8,0x83,0x47,0xe0,0xec,0x2c,0xaf,0xf2,0x0e,0x08,0x1f,0xc1,0x18,0x60,0x1a,0xaf,0xc2,0x6c,0x89,0x62,0x03,0x19,0xad,0xe5,0x70,0x44,0x62,0x80,0x5a,0xa1,0x4f,0x63,0x23,0x0c,0x7a,0xaa,0x4d,0x11,0xe9,0x00,0x06,0x73,0xaa,0x25,0x0a,0x78,0xaf,0x90,0x09,0x25,0x54,0x56,0x5f,0x04,0x30,0xc0,0x64,0x7a,0xa1,0x11,0x7e,0x20,0x18,0x0f,0x3c,0x82,0xaa,0x04,0x18,0x0d,0xf8,0x16,0x33,0xe8,0x84,0xa8,0x08,0x3c,0x33,0x00,0xf0,0x20,0x71,0x08,0xa9,0x38,0x86,0x62,0x62,0x18,0x40,0x44,0x80,0x09,0x04,0x08,0x90,0x01,0x20,0x41,0x17,0x22,0x90,0x01,0x3e,0x00,0x76,0x80,0x1d,0x48,0x00,0x8d,0x91,0x00,0x34,0xf8,0x20,0xe2,0xa7,0x9c,0x06,0x5c,0x11,0x02,0x28,0x5d,0x91,0x35,0x48,0xaf,0xf8,0x04,0x3f,0xf9,0x88,0x20,0x01,}; -const uint8_t* const _I_DolphinFirstStart0_70x53[] = {_I_DolphinFirstStart0_70x53_0}; - -const uint8_t _I_DolphinFirstStart1_59x53_0[] = {0x01,0x00,0x1e,0x01,0x00,0x0e,0x03,0xfe,0x07,0x5b,0x84,0x02,0x06,0x07,0x48,0x64,0x02,0x08,0x07,0x48,0x14,0x02,0x10,0x07,0x48,0x0c,0x03,0x21,0x3f,0x13,0x18,0x84,0xa8,0x00,0x75,0x8c,0x00,0xca,0x00,0x0b,0x28,0x20,0x1d,0xa0,0x59,0xe0,0x39,0x48,0x07,0x03,0x81,0xd5,0x81,0xd6,0x81,0x55,0x8c,0x01,0xc6,0x21,0x00,0x87,0x68,0x25,0x52,0x40,0x39,0x7c,0x21,0xf5,0x08,0xa8,0x1d,0x20,0xfa,0x88,0x70,0x1c,0xfd,0x10,0x3a,0xa4,0x1f,0x88,0x54,0x18,0x85,0x52,0x09,0xbe,0x81,0xc1,0x0c,0x83,0x10,0x94,0x40,0x39,0xf0,0x19,0x21,0xc8,0x62,0x12,0x0c,0x04,0x0e,0x0c,0x07,0x38,0x07,0x86,0x07,0x18,0x03,0x94,0xc2,0x01,0x9e,0x81,0xca,0x38,0x89,0x21,0x0f,0x0c,0x03,0xf9,0x27,0x13,0x94,0xd0,0xb6,0x70,0x20,0x38,0xda,0x80,0xe5,0x10,0x03,0x95,0x59,0x54,0x70,0x10,0x38,0xda,0xc0,0xc3,0xfe,0xc1,0xab,0x0b,0xaa,0x2a,0x1c,0x05,0x81,0x58,0x38,0x09,0xd0,0x5c,0xa3,0xe0,0x72,0x86,0xae,0x8d,0x40,0x34,0x06,0xa1,0xc0,0xc0,0xe3,0xc0,0x65,0x1c,0x19,0x58,0x29,0xe1,0x00,0x14,0x28,0x0a,0x26,0x61,0x00,0x15,0x58,0x0a,0x2e,0x34,0xd6,0x42,0x9e,0x6b,0x54,0x82,0x92,0x08,0x1e,0x63,0x41,0x1d,0x0a,0x88,0x60,0x1d,0x42,0x11,0x5c,0x01,0xe5,0x3c,0x03,0x97,0x30,0x0e,0x42,0x42,0x80,0xd0,0x82,0xe4,0x07,0x28,0x17,0x10,0x1e,0xb0,0x4a,0x20,0x3d,0x61,0x1a,0x80,0x79,0x0f,0x0a,0x21,0x70,0x07,0x90,0x1c,0xa4,0x1a,0x00,0x7a,0xd0,0x0e,0x42,0x34,0x20,0x10,0xe0,0x00,0xed,0x00,0xa1,0x82,0xc8,0xc6,0x74,0x40,0xd9,0x01,0xce,0x84,0x07,0x69,0x10,0xcc,0x80,0xe7,0x5c,0x03,0xb4,0xa8,0x96,0x40,0x73,0x8a,0x96,0xc8,0x0c,0x40,}; -const uint8_t* const _I_DolphinFirstStart1_59x53[] = {_I_DolphinFirstStart1_59x53_0}; - -const uint8_t _I_DolphinFirstStart2_59x51_0[] = {0x01,0x00,0x2e,0x01,0x00,0x1f,0xfe,0x06,0x05,0x3f,0xc7,0xfe,0x01,0x1c,0x03,0x16,0x02,0xaf,0x0f,0x80,0x58,0x01,0xc7,0xaa,0x80,0x82,0xc4,0x0e,0x55,0x6b,0x28,0x10,0x81,0x45,0xab,0x8d,0x01,0xca,0x04,0x1a,0x1a,0xac,0x1c,0x0e,0x50,0x48,0x06,0xc0,0x3c,0x40,0x01,0x84,0x40,0x2b,0x15,0x51,0xd9,0xc4,0x20,0x1a,0xc9,0x50,0x1c,0xe4,0x02,0xe1,0x8a,0x81,0xd7,0x55,0x0a,0x03,0x9d,0x02,0x01,0x5c,0x82,0x81,0xd7,0xc0,0x3a,0x10,0x3a,0x12,0x88,0xc8,0x60,0x11,0x07,0xa0,0x1c,0x68,0x00,0xf6,0xe0,0x22,0x50,0x0e,0x36,0x00,0x7b,0x68,0x00,0x83,0xa0,0x11,0x08,0x1c,0x6a,0x03,0x42,0x44,0x1e,0xc0,0x28,0x50,0x61,0xf9,0x56,0x00,0xe3,0x60,0x40,0x88,0x1c,0x75,0x01,0x42,0x07,0x9d,0x50,0x5e,0x4b,0x01,0x37,0x8e,0xb0,0x0e,0x51,0xd8,0x04,0xc2,0x01,0xd4,0x5d,0x1c,0x02,0x30,0x7f,0x14,0x99,0x5c,0x20,0x11,0x48,0x07,0x58,0x0e,0x20,0x81,0xd0,0x23,0x04,0x1e,0x30,0x80,0x38,0xd4,0x11,0x82,0x0f,0x18,0x40,0xb0,0xb0,0x50,0x3d,0x58,0x1c,0x52,0x85,0xf1,0x83,0x75,0x58,0x64,0x49,0x1a,0xfc,0x17,0x57,0x01,0x88,0x25,0x0b,0x55,0x02,0xaa,0xc0,0x64,0x14,0x08,0x1e,0x02,0xaa,0x1f,0x18,0x0f,0x00,0xbe,0x20,0xf1,0x80,0x82,0x46,0x01,0x03,0x82,0xe0,0x04,0xa3,0xab,0x46,0x0e,0x32,0x15,0x80,0xb5,0x40,0x2a,0xa4,0x21,0x98,0x43,0x70,0x13,0x58,0x04,0xac,0xa4,0x3c,0x08,0xd6,0x02,0x35,0x00,0x8a,0xcd,0x06,0xa3,0x1d,0xa0,0x24,0x46,0x57,0xe8,0x26,0x8c,0xdb,0x80,0x84,0x18,0xad,0x42,0x07,0x5f,0xbf,0xb9,0x8a,0x17,0x80,0xff,0x6a,0xb0,0x46,0x91,0x07,0x88,0xc4,0x4a,0x43,0x1f,0x07,0x92,0xc4,0x49,0x82,0x9b,0x25,0x98,0xc0,0x28,0xa0,0x73,0x1f,0x0b,0x50,0x81,0xea,0x07,0x40,0x7b,0xac,0x44,0x0e,0xa0,}; -const uint8_t* const _I_DolphinFirstStart2_59x51[] = {_I_DolphinFirstStart2_59x51_0}; - -const uint8_t _I_DolphinFirstStart3_57x48_0[] = {0x01,0x00,0x12,0x01,0x00,0x16,0x03,0xff,0x07,0x03,0xa5,0x82,0x01,0x38,0x03,0xa4,0x62,0x01,0xc0,0x03,0xa4,0x10,0x04,0x30,0x10,0x39,0xc0,0x80,0x48,0x0c,0x40,0x91,0x7e,0x20,0x60,0x72,0x84,0x02,0x8b,0x78,0x12,0x28,0x80,0x68,0x85,0x87,0x20,0x11,0x18,0x5c,0x80,0xe8,0x01,0x19,0xc5,0x00,0x0e,0x62,0xc1,0x9f,0x01,0xcb,0xe9,0x03,0x84,0x60,0x20,0xf8,0x00,0x38,0xd7,0x21,0xb1,0x0f,0x04,0x04,0x0e,0x5a,0x89,0xd4,0x83,0xc0,0x4b,0x3a,0xc5,0x54,0xcc,0x20,0x51,0x00,0x8e,0xc3,0x54,0x80,0x13,0xf8,0x81,0xc6,0xc1,0x55,0x01,0x8c,0x78,0x0e,0x30,0xee,0x06,0xaa,0x05,0xe0,0xae,0x01,0xc6,0x23,0x80,0xaa,0xc1,0x60,0x1a,0x90,0x38,0xc8,0x60,0x1a,0xb8,0x54,0x02,0xad,0x07,0x80,0xd0,0x40,0x83,0x15,0x80,0x7b,0x21,0x10,0x1c,0x0c,0x03,0x7f,0x2a,0x80,0x4d,0x00,0xe3,0x01,0xf8,0xf0,0x2a,0xf0,0x08,0x60,0x1c,0x60,0x41,0xd1,0xdf,0x1a,0x44,0x0e,0x50,0x68,0x05,0xe3,0x07,0x02,0x82,0x01,0xc6,0x19,0x00,0xf8,0x5f,0xe0,0x20,0x72,0xfa,0x40,0x7f,0xc2,0xb1,0x03,0x88,0x68,0x7f,0xf6,0xb4,0x28,0xc0,0x80,0xe3,0x88,0xaa,0xc7,0x40,0xe9,0x50,0xd5,0x41,0x94,0xa2,0x07,0x29,0x87,0x52,0x02,0x07,0x12,0x30,0xc1,0x22,0x16,0x86,0x29,0x01,0xca,0x30,0xf6,0x10,0x39,0xc2,0x23,0x10,0x6c,0x00,0x1d,0x3d,0x10,0x1b,0x02,0xe0,0x41,0x03,0x08,0x75,0x0c,0x60,0x0e,0x4f,0x11,0x0a,0x0c,0x18,0x0e,0x96,0x06,0x28,0x81,0xd3,0x01,0x1f,0x01,0x90,0x1c,0xdc,0xc2,0x01,0x15,0xd0,0x81,0xdc,0x4c,0x30,0x30,0x3f,0x00,0xc4,0x0e,0x30,0x20,0x3c,0x8c,0xc8,0x0f,0x2b,0x41,}; -const uint8_t* const _I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_0}; - -const uint8_t _I_DolphinFirstStart4_67x53_0[] = {0x01,0x00,0x1f,0x01,0x00,0x17,0xc3,0xfe,0x08,0x68,0x74,0x02,0x0e,0x07,0x4c,0x04,0x06,0x01,0x18,0x04,0x25,0x00,0x04,0x36,0x00,0x42,0x48,0x02,0x88,0x00,0x28,0x80,0x0c,0xa0,0x40,0x83,0x84,0x00,0xca,0x08,0x08,0x30,0x21,0x83,0x0c,0x2c,0x81,0xe3,0x04,0x20,0xc0,0x80,0x02,0x31,0x32,0x11,0x02,0x27,0x00,0x5d,0x40,0x45,0x87,0x90,0x3e,0x7c,0x00,0x43,0x84,0x4e,0x60,0x43,0x30,0x89,0x82,0x12,0x80,0x15,0x20,0x40,0x99,0xc8,0x22,0x7b,0x88,0x10,0x20,0x82,0x27,0x7c,0x82,0x9d,0x48,0x22,0x5f,0x0d,0xfc,0x08,0x10,0x41,0x12,0xf8,0x57,0xc2,0x28,0x30,0x1e,0x07,0x9e,0x06,0x87,0x25,0x79,0xc4,0x20,0x40,0x83,0x21,0x14,0x22,0x08,0x08,0x38,0x2a,0xb8,0xd9,0x47,0x0a,0x14,0x09,0xf0,0x54,0x47,0x1f,0x81,0x82,0x1a,0xde,0x8e,0x33,0xd1,0xc7,0x81,0x0f,0x0e,0x45,0x18,0x20,0xa1,0xe6,0xf2,0x10,0x89,0xa0,0x70,0x11,0x00,0x41,0x46,0x03,0x86,0x55,0x10,0x40,0xc1,0x82,0x25,0x20,0x04,0x11,0x94,0x80,0x43,0x10,0x84,0x01,0x46,0xc0,0xbd,0x38,0x40,0x20,0x8f,0x49,0x08,0xc4,0x1c,0xc8,0x22,0x50,0x38,0x20,0x20,0x86,0xe4,0x83,0x10,0x41,0x8b,0x87,0xf9,0x03,0x81,0xc0,0x81,0x05,0x81,0xc0,0x40,0xf3,0x90,0x60,0x41,0x70,0x2c,0x17,0x01,0xc0,0xc1,0x41,0x05,0x30,0x98,0x43,0x04,0x65,0x01,0x04,0x0c,0x32,0x38,0x91,0x18,0x04,0x14,0x10,0x38,0x18,0x1e,0xac,0x7c,0x41,0x11,0x88,0x5f,0xfc,0x17,0x55,0xa9,0x82,0x06,0x05,0xbc,0x85,0x02,0x08,0xc6,0x32,0x0f,0xe5,0x5e,0x1a,0x08,0x5c,0x06,0xaa,0x34,0x08,0x4a,0x06,0x02,0xab,0x75,0xf0,0x4f,0xc1,0x05,0x80,0x08,0x8e,0xab,0x7f,0xea,0x04,0x11,0x80,0x6a,0xa0,0x02,0x03,0x08,}; -const uint8_t* const _I_DolphinFirstStart4_67x53[] = {_I_DolphinFirstStart4_67x53_0}; - -const uint8_t _I_DolphinFirstStart5_54x49_0[] = {0x01,0x00,0x0b,0x01,0x00,0x0f,0xf2,0xfe,0x06,0x48,0x1e,0x02,0x06,0x05,0x2e,0x00,0x08,0x61,0x80,0x62,0x98,0x00,0x86,0x20,0x06,0x28,0x40,0x08,0x64,0x00,0x62,0x82,0x00,0x86,0x80,0x06,0x28,0x14,0x72,0x01,0x80,0x03,0x14,0x06,0x44,0x03,0x20,0x49,0x00,0xc4,0x0c,0x61,0x13,0x81,0x07,0x90,0x0c,0xff,0xa8,0x18,0xcc,0xe0,0x10,0x78,0x60,0x18,0xc9,0xe3,0x10,0x03,0x0e,0x02,0x02,0x4f,0x19,0x00,0x18,0x78,0x10,0x12,0x78,0xc8,0x0a,0xc3,0xf8,0x80,0xc1,0x80,0xc5,0xe0,0xff,0x8f,0x47,0xe1,0x27,0x03,0x0d,0xfc,0x80,0x3b,0xc9,0x74,0x43,0x81,0x0f,0xb0,0x40,0x2b,0xd2,0xd3,0x71,0x07,0x87,0x5f,0x16,0x84,0x54,0x23,0xe3,0x21,0xab,0xc5,0x61,0x1a,0x82,0xf0,0xf0,0x35,0x70,0xa8,0x45,0x50,0x2a,0x3e,0x0a,0xac,0x1e,0x11,0x28,0x03,0x0f,0xc3,0xfe,0x06,0x19,0xa0,0x18,0x6f,0x9f,0x08,0x7c,0x22,0x30,0x06,0x1d,0xfc,0x3e,0x21,0x08,0x00,0x8f,0x01,0x7a,0x31,0x08,0x24,0x42,0x21,0xf0,0x5e,0x08,0x18,0x44,0xe3,0x0f,0x59,0x92,0xb4,0x96,0x66,0x06,0x58,0x10,0x19,0x60,0x20,0x64,0x46,0x08,0x19,0x27,0x00,0x65,0x9f,0x81,0x93,0xd1,0x2b,0x03,0x17,0x82,0x3f,0x50,0x9a,0x81,0x87,0x51,0x1e,0xf0,0x68,0x69,0x40,0x61,0xea,0x9d,0x86,0x1d,0x45,0x80,0x61,0x2d,0x48,0xc2,0x67,0x8d,0x12,0x3a,0x06,0x19,0x02,0x88,0x74,0x4b,0x21,0x03,0x1d,0x08,0xca,0x21,0x41,0x06,0x93,0xe8,0xa1,0x85,0x31,0xe9,0x24,0x48,0x20,0x30,0x1b,0x10,0x18,0x77,0x8f,0xa1,0x80,0xcc,0x40,0xc3,0x56,0x0b,0x8c,0x0a,0x22,0xba,0x12,0x88,0x81,0x84,}; -const uint8_t* const _I_DolphinFirstStart5_54x49[] = {_I_DolphinFirstStart5_54x49_0}; - -const uint8_t _I_DolphinFirstStart6_58x54_0[] = {0x01,0x00,0x21,0x01,0x00,0x0f,0xf2,0x7e,0x06,0x4c,0x04,0x0f,0x81,0x03,0x03,0x9d,0x80,0x04,0x30,0xc0,0x39,0xc6,0x00,0x43,0x30,0x03,0x9c,0x10,0x04,0x34,0x00,0x39,0xc0,0x84,0x44,0x07,0x38,0x08,0x0d,0x41,0x68,0x13,0x70,0x39,0x08,0xd0,0x56,0xa1,0xd1,0x03,0x94,0x80,0x04,0x30,0x68,0x04,0x20,0x0e,0x84,0x91,0x03,0xa9,0x64,0x62,0x80,0x41,0x88,0x40,0x3f,0xc6,0xf1,0xfe,0x43,0xc0,0xe3,0x80,0xff,0xff,0xe0,0x3f,0xf8,0xf8,0x1c,0x78,0x18,0x1f,0xfe,0x0f,0x02,0x12,0x18,0x47,0x03,0x82,0x10,0x1e,0x08,0x1c,0xf5,0x60,0x71,0xd4,0x81,0xcf,0xab,0xff,0xd5,0xf5,0xc0,0xe3,0x04,0xe0,0x03,0x86,0xae,0x27,0x28,0x27,0x40,0x0e,0x21,0x91,0x03,0x96,0x80,0x0e,0x34,0x18,0x79,0x28,0x60,0x95,0x00,0x38,0xf8,0x20,0x27,0xd1,0x82,0x6a,0x03,0xc3,0x1c,0x39,0x94,0x0a,0xa1,0xc0,0xc5,0x2f,0xca,0x05,0x02,0x90,0x24,0x56,0x04,0x68,0x10,0x01,0x4f,0x80,0xea,0x5b,0x10,0x38,0x83,0x8d,0xa0,0x30,0x30,0x38,0xa3,0x09,0xc0,0x20,0xf2,0x03,0x90,0xc0,0x46,0xe2,0x91,0x2f,0x80,0xfc,0xe0,0x1e,0x08,0x02,0x54,0x47,0x62,0x27,0x2f,0xfb,0x14,0xdc,0xc6,0xb5,0x30,0x38,0x8b,0x05,0x6a,0x60,0x01,0x89,0x00,0xc8,0x16,0x50,0x29,0x10,0x1c,0x8d,0x25,0x05,0xa1,0x15,0xc9,0xfe,0x50,0xaa,0x08,0x10,0x67,0x01,0x22,0x8a,0xe0,0x60,0xe5,0xf2,0x07,0x8e,0xa8,0xb0,0x49,0xe1,0x00,0x0d,0xd4,0x68,0x5a,0x00,0x39,0x46,0x88,0x84,0x07,0x30,0xe8,0x81,0xc6,0x40,0x4d,0x11,0x91,0x17,0x06,0x40,0x65,0x11,0x51,0x01,0xc6,0x81,0x04,0x32,0x18,0x1e,0x92,0x64,0x00,0x11,0x68,0x81,0xd6,0xa0,0x07,0x16,0x22,0x6b,0x0a,0x82,0x07,0x3f,0x05,0x4d,0xdc,0x24,0x21,}; -const uint8_t* const _I_DolphinFirstStart6_58x54[] = {_I_DolphinFirstStart6_58x54_0}; - -const uint8_t _I_DolphinFirstStart7_61x51_0[] = {0x01,0x00,0x13,0x01,0x00,0x17,0x03,0xff,0x01,0x03,0xa4,0xe2,0x01,0x0e,0x03,0xa4,0x1a,0x01,0x30,0x03,0x1e,0x00,0x2a,0x3c,0x00,0x39,0xd0,0x00,0x65,0x03,0x01,0x94,0x80,0x06,0x50,0x40,0x19,0x44,0x00,0x65,0x08,0x01,0xb0,0x2c,0xe2,0x81,0xb6,0x86,0x0a,0xd8,0x7c,0x20,0x75,0x85,0x10,0xcc,0x06,0x50,0x50,0x3b,0x10,0xce,0x00,0x69,0x20,0x79,0x7c,0x20,0x20,0x71,0xc0,0x07,0xca,0xf1,0x02,0x81,0x01,0xc6,0x3a,0x07,0x1f,0xe4,0x10,0x0e,0x53,0xe0,0x38,0xe7,0xa0,0xa0,0x72,0xbb,0x81,0xca,0x12,0x68,0x1c,0x05,0x5c,0x0e,0x3f,0xe8,0xc8,0x1c,0xab,0xe0,0x72,0x94,0x81,0xda,0xb2,0x07,0x5f,0xe0,0x3d,0xbf,0x95,0x44,0x20,0x81,0xce,0xf1,0x2f,0x03,0x94,0xb8,0xae,0x51,0x00,0x39,0x47,0x60,0xd0,0x84,0x70,0x81,0xcb,0x44,0x9d,0x10,0x3a,0x58,0xce,0xe6,0x07,0x29,0x10,0x18,0xa0,0x50,0x88,0x76,0x02,0x22,0x07,0x49,0x8e,0x02,0x24,0x07,0x4e,0x0e,0x02,0x12,0x96,0x38,0x44,0x07,0x02,0x8f,0x1c,0x07,0x1c,0x4e,0x30,0x1c,0x10,0x3c,0x6c,0x13,0x80,0x38,0xc0,0xb0,0x80,0xf1,0x6e,0x90,0x1c,0x71,0x10,0xd7,0x49,0x81,0xc7,0x20,0x0f,0x17,0xe9,0x42,0x20,0x91,0x09,0xeb,0x24,0xe2,0x10,0x49,0x07,0x6f,0xff,0x80,0x56,0x88,0x1c,0xa2,0xae,0xd1,0x66,0x89,0xe0,0x68,0x11,0xb8,0x06,0xc0,0x2e,0x40,0x71,0x9a,0xc0,0x2b,0x00,0x73,0xc0,0x7a,0xe0,0x09,0x12,0x03,0x95,0x57,0xff,0x17,0x03,0x9c,0x03,0x57,0xaa,0x78,0x94,0x40,0xa6,0x35,0x5a,0xac,0x14,0x0e,0x9a,0xad,0x50,0xf8,0x41,0x05,0x00,0x83,0x55,0x14,0x06,0x07,0x18,0x54,0xa0,0x0e,0xb0,0x60,0x31,0xc0,0x00,}; -const uint8_t* const _I_DolphinFirstStart7_61x51[] = {_I_DolphinFirstStart7_61x51_0}; - -const uint8_t _I_DolphinFirstStart8_56x51_0[] = {0x01,0x00,0xfd,0x00,0x00,0x17,0x83,0xff,0x01,0x03,0x1c,0x72,0x01,0x06,0x03,0x1c,0x0e,0x01,0x18,0x02,0x96,0x00,0x04,0x36,0x00,0x31,0x50,0x01,0x24,0x1c,0x29,0x00,0x28,0xa0,0x40,0x21,0x88,0x01,0x8a,0x08,0x02,0x18,0x40,0x18,0x80,0x64,0x09,0x20,0x89,0x81,0x98,0x3c,0x42,0x63,0x03,0x30,0xcc,0x70,0x10,0x71,0xd9,0x01,0x86,0xc1,0x1c,0x03,0x24,0x42,0x7e,0x50,0x12,0x91,0x62,0x2f,0xf8,0x0e,0x00,0x18,0xb9,0x17,0x1c,0x04,0x83,0x02,0x06,0x1e,0x27,0xc4,0x54,0x20,0x62,0xf2,0x7c,0xe0,0x52,0x0c,0x10,0x88,0x7c,0x9f,0xf8,0x28,0x18,0x41,0xa5,0xff,0x85,0x48,0x30,0x80,0xd1,0xe4,0x5f,0xc1,0xa3,0x84,0x26,0x0f,0x23,0xfe,0x1b,0x18,0x44,0x16,0x01,0x90,0x81,0xc1,0x62,0x10,0x84,0xc0,0xf8,0x20,0x30,0x28,0x84,0x40,0x1a,0x25,0x11,0x82,0x42,0x22,0x11,0xf4,0xd9,0xc1,0x02,0x22,0xb2,0x38,0x14,0xc1,0x8e,0x90,0x14,0xc1,0xa2,0x86,0x02,0xc6,0x30,0x31,0x06,0x8c,0x0c,0x26,0x02,0x56,0x9d,0x04,0x0c,0x6a,0xa1,0x03,0x21,0x20,0x68,0x5f,0xe7,0xa9,0x00,0x86,0x85,0x01,0x8f,0xe0,0x08,0xe3,0x00,0xe1,0x02,0xc6,0xfe,0x16,0x23,0xe1,0x13,0x10,0xa4,0x82,0xb1,0x12,0x88,0x00,0xf0,0x91,0xe0,0x6a,0xfd,0x63,0xfc,0x08,0x78,0x18,0xb5,0x5e,0xad,0xfb,0x84,0xa0,0x95,0x48,0xad,0x54,0x4a,0x50,0x4d,0x44,0x6b,0x56,0x0d,0x28,0x45,0x42,0x6a,0x0d,0x38,0x46,0x02,0x55,0xaa,0x35,0x25,0x52,0xac,0x06,0x4b,0x04,0xa8,0x0c,0x94,0x03,0xa0,0x80,0x04,}; -const uint8_t* const _I_DolphinFirstStart8_56x51[] = {_I_DolphinFirstStart8_56x51_0}; - -const uint8_t _I_DolphinOkay_41x43_0[] = {0x01,0x00,0xa0,0x00,0x00,0x0f,0x82,0x3e,0x05,0x38,0xf7,0x80,0x08,0x58,0x08,0x0c,0x02,0x0e,0x05,0x1b,0x00,0x08,0x63,0x00,0x21,0x88,0x00,0x86,0x40,0x02,0x18,0x40,0x08,0x68,0x00,0x21,0x82,0x06,0x88,0x0a,0xf0,0x21,0x39,0x09,0x84,0x02,0x20,0x57,0x09,0x98,0x15,0x67,0xc0,0x54,0xbe,0x81,0x4f,0x01,0xfe,0x02,0x9d,0x03,0xc4,0x20,0x10,0x29,0x7c,0x80,0xa9,0xfe,0x02,0xac,0x14,0x0a,0x77,0xc8,0x58,0x8c,0xf0,0x11,0x51,0x79,0xff,0x61,0x44,0x93,0x81,0x02,0xc4,0x9e,0x60,0xb2,0xf0,0xa0,0x46,0x0c,0x17,0x14,0x99,0x1a,0x07,0x80,0x59,0x49,0x82,0x21,0xc0,0xa4,0x82,0x24,0xb9,0x20,0x88,0x1c,0x47,0xc2,0x07,0x11,0x54,0xa0,0x60,0x53,0xb8,0x0a,0x4b,0xf3,0x03,0x87,0x81,0x4a,0x0d,0xfc,0x1a,0x98,0x68,0xb8,0x01,0x51,0x13,0x15,0xe0,0x82,0x7f,0x8d,0x78,0x38,0xbf,0xff,0xfa,0xb8,0x60,0xbf,0x1b,0xf9,0x50,0x14,0xea,0xe7,0x02,0x02,0x8e,0xac,0x94,0x40,}; -const uint8_t* const _I_DolphinOkay_41x43[] = {_I_DolphinOkay_41x43_0}; - -const uint8_t _I_ArrowDownEmpty_14x15_0[] = {0x01,0x00,0x17,0x00,0xfc,0x41,0xe1,0x10,0x40,0x0c,0xc3,0xe7,0x90,0x19,0x04,0x0a,0x20,0x08,0x10,0x48,0xc4,0x20,0x52,0x08,0x0f,0x02,0x00,}; -const uint8_t* const _I_ArrowDownEmpty_14x15[] = {_I_ArrowDownEmpty_14x15_0}; - -const uint8_t _I_ArrowDownFilled_14x15_0[] = {0x00,0xF8,0x07,0x08,0x04,0xE8,0x05,0x68,0x05,0xA8,0x05,0x68,0x05,0xA8,0x05,0x6F,0x3D,0xA1,0x21,0xFA,0x17,0xF4,0x0B,0xE8,0x05,0xD0,0x02,0x20,0x01,0xC0,0x00,}; -const uint8_t* const _I_ArrowDownFilled_14x15[] = {_I_ArrowDownFilled_14x15_0}; - -const uint8_t _I_ArrowUpEmpty_14x15_0[] = {0x01,0x00,0x18,0x00,0xe0,0x40,0x24,0x10,0x18,0x84,0x0a,0x11,0x04,0x82,0x42,0x20,0x51,0x08,0x0c,0x82,0x1f,0x3c,0x04,0x88,0x06,0x7f,0x10,0x70,}; -const uint8_t* const _I_ArrowUpEmpty_14x15[] = {_I_ArrowUpEmpty_14x15_0}; - -const uint8_t _I_ArrowUpFilled_14x15_0[] = {0x00,0xC0,0x00,0x20,0x01,0xD0,0x02,0xE8,0x05,0xF4,0x0B,0xFA,0x17,0x61,0x21,0xAF,0x3D,0x68,0x05,0xA8,0x05,0x68,0x05,0xA8,0x05,0xE8,0x05,0x08,0x04,0xF8,0x07,}; -const uint8_t* const _I_ArrowUpFilled_14x15[] = {_I_ArrowUpFilled_14x15_0}; - -const uint8_t _I_DolphinReadingSuccess_59x63_0[] = {0x01,0x00,0x19,0x01,0x00,0x1d,0x00,0x0f,0xd2,0x00,0x21,0xe0,0x3f,0xf0,0xf9,0x00,0x40,0xee,0x00,0x11,0x88,0x04,0x0e,0x18,0x11,0x18,0x8c,0x40,0x0e,0x50,0x30,0x10,0xc0,0xa1,0x01,0xe2,0x05,0x14,0x12,0x08,0x33,0x58,0x44,0x08,0x66,0xa1,0xe3,0x01,0x9c,0x83,0x00,0x24,0x11,0x11,0x06,0xc4,0x76,0x20,0x75,0x15,0x99,0x48,0xc0,0xe9,0x0f,0x03,0x95,0xfc,0x86,0x3c,0x09,0x80,0x1c,0x7c,0x00,0x91,0x81,0x48,0x2f,0xc1,0x41,0x8c,0xc0,0x20,0x30,0x1c,0x87,0xfc,0x0e,0x30,0x70,0x70,0x81,0xc7,0xe6,0x07,0x18,0x08,0x1c,0xb9,0x1e,0x38,0x0f,0x02,0x01,0xf0,0x03,0xa0,0xa4,0x7f,0x90,0x30,0x38,0xff,0xe0,0x28,0x21,0xff,0x06,0x44,0x0e,0x46,0xe1,0x01,0x8c,0x03,0x34,0x2f,0x25,0x18,0x80,0xc7,0x2a,0x03,0x2e,0x01,0x3c,0x70,0x12,0xa2,0x39,0x78,0x27,0xe0,0x31,0xea,0x82,0xc4,0x6c,0x31,0xf0,0x78,0xea,0xb0,0x22,0x31,0xfc,0x1a,0xc6,0x01,0x55,0x25,0x88,0xf8,0x4b,0x02,0x1f,0x13,0xe1,0x7f,0x97,0x85,0x15,0x03,0x90,0xf8,0xa0,0x10,0xa1,0xb1,0x0e,0x88,0x00,0x7f,0x0f,0xc0,0x7c,0x57,0x27,0x3c,0xb0,0x7f,0x5f,0xa9,0x1f,0xc0,0x6a,0xc5,0x05,0xc0,0xf0,0x11,0x46,0xac,0x18,0x3f,0xf9,0x54,0x75,0x00,0x73,0x1f,0x0f,0xfe,0xfe,0xc6,0x30,0x01,0xbc,0x48,0x00,0x84,0x82,0x00,0x1b,0x64,0xc0,0x07,0x60,0x03,0xb4,0x70,0x0c,0xbf,0x82,0x31,0x01,0x8d,0x0c,0x40,0x02,0x37,0x08,0x1d,0x74,0x00,0x76,0xa0,0x01,0xdb,0x01,0xfe,0x85,0x8b,0x96,0xaa,0x9b,0x30,0x01,0x6a,0xa3,0x40,0x75,0xaa,0x03,0xdb,0x50,0xbb,0x30,0x01,0x54,0x24,0x25,0xe6,0x51,0x08,0x1f,0x68,0x00,0x7f,0x03,0xf2,0x79,0xc0,0xf4,}; -const uint8_t* const _I_DolphinReadingSuccess_59x63[] = {_I_DolphinReadingSuccess_59x63_0}; - -const uint8_t _I_Down_25x27_0[] = {0x01,0x00,0x46,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x3f,0x01,0x9f,0xc7,0xff,0x1f,0x01,0xa7,0x87,0xff,0x0f,0x80,0xf0,0x7f,0xf0,0x78,0x0e,0x07,0xff,0x03,0x0b,0x8f,0xfc,0x04,0x30,0x1f,0xf0,0x7c,0xaf,0x80,0x32,0x9c,0x00,0xca,0x20,0x37,0xf0,0x18,0xc0,0xca,0x63,0x01,0x83,0x40,0x38,0x10,0x0f,0xe7,0xfe,0xfe,0x67,0x40,}; -const uint8_t* const _I_Down_25x27[] = {_I_Down_25x27_0}; - -const uint8_t _I_Down_hvr_25x27_0[] = {0x01,0x00,0x3a,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x3f,0x01,0x9c,0x3e,0x01,0xe0,0x01,0xa4,0x7e,0x01,0xf0,0x80,0x8b,0x47,0xf1,0x01,0x16,0x8f,0xf0,0x2e,0x23,0x11,0x01,0x88,0x04,0xf0,0x60,0x32,0xe3,0x80,0xcb,0xde,0x37,0xf0,0x1a,0x95,0xcc,0xbe,0x66,0x73,}; -const uint8_t* const _I_Down_hvr_25x27[] = {_I_Down_hvr_25x27_0}; - -const uint8_t _I_InfraredArrowDown_4x8_0[] = {0x00,0xFF,0x7E,0x3C,0x18,}; -const uint8_t* const _I_InfraredArrowDown_4x8[] = {_I_InfraredArrowDown_4x8_0}; - -const uint8_t _I_InfraredArrowUp_4x8_0[] = {0x00,0x18,0x3C,0x7E,0xFF,}; -const uint8_t* const _I_InfraredArrowUp_4x8[] = {_I_InfraredArrowUp_4x8_0}; - -const uint8_t _I_InfraredLearnShort_128x31_0[] = {0x01,0x00,0x10,0x01,0x00,0x47,0xfb,0xfe,0x00,0x38,0x38,0x3e,0x20,0x20,0x54,0x84,0x03,0x9f,0xc0,0x06,0x58,0x80,0x3d,0xf2,0x00,0x65,0x90,0x03,0xde,0x90,0x06,0x5a,0x07,0xc0,0x8a,0x70,0x1a,0x04,0x02,0x51,0x80,0x03,0x94,0x02,0x3f,0x40,0x20,0x24,0x0b,0x01,0x00,0x92,0x70,0x35,0x40,0x01,0xe0,0xdf,0xf0,0x10,0x40,0x71,0x58,0x20,0x90,0x88,0x0c,0x4a,0x81,0x55,0x00,0x0f,0x87,0xf7,0x00,0x82,0x43,0x36,0x16,0xdc,0x9c,0x12,0x21,0x01,0x85,0x70,0x3f,0xc1,0xf1,0xf8,0xfc,0x60,0x20,0xf5,0x90,0x40,0xa1,0x34,0x08,0x18,0x7c,0x7e,0x24,0x91,0x07,0x8c,0xc0,0x5e,0x52,0x28,0x14,0x17,0x81,0x01,0x0f,0x8f,0xe7,0xe3,0x03,0x1f,0x8e,0x02,0xdb,0x03,0x8e,0x49,0x20,0x50,0x2e,0x04,0x72,0xbd,0x55,0xdc,0xeb,0xa0,0x7c,0x4f,0x68,0xbc,0x60,0x72,0x40,0x79,0x50,0x23,0x9a,0x6d,0x56,0x66,0x5c,0x0f,0x21,0x78,0x9b,0x04,0x1e,0x28,0x21,0x8e,0x5c,0x43,0xe6,0x2f,0x10,0xf9,0x0b,0xc7,0x04,0x99,0x18,0x06,0xe0,0x7e,0x56,0x32,0x78,0x8f,0xc4,0x08,0x32,0x20,0x79,0x48,0x2b,0x85,0xf2,0xf8,0x83,0xc4,0x5c,0x3f,0x03,0x78,0xd0,0x81,0xe3,0xc0,0xdf,0x9f,0xcb,0xf3,0x04,0xc6,0x7d,0xfb,0xdf,0x34,0x78,0xd0,0x45,0xe5,0x7e,0x4f,0x97,0xe2,0x09,0x80,0x07,0x88,0xbc,0x61,0x00,0xf3,0xd8,0x2f,0xcb,0xe0,0xcf,0x60,0x68,0xd0,0x30,0x15,0xfa,0xac,0x36,0x3f,0x60,0x77,0xb3,0x80,0x5d,0xe6,0x4b,0x20,0x03,0x03,0xc4,0x01,0xd0,0x10,0x7f,0x40,0x81,0xfc,0xa7,0x10,0x06,0x99,0xd0,0x01,0x51,0x00,0x7f,0x48,0x01,0xfd,0xc0,0x43,0x98,0x00,0x8e,0xfe,0x00,0xf0,}; -const uint8_t* const _I_InfraredLearnShort_128x31[] = {_I_InfraredLearnShort_128x31_0}; - -const uint8_t _I_InfraredLearn_128x64_0[] = {0x01,0x00,0xcc,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3f,0x01,0x07,0x82,0x41,0x21,0x20,0x73,0x00,0x8e,0x82,0x0f,0x00,0xa0,0x01,0x46,0x11,0x00,0x07,0xc0,0x28,0x41,0xe5,0xc8,0xba,0x63,0xa7,0x70,0x6b,0x3d,0xbb,0x99,0x19,0xee,0x68,0x71,0x16,0x3f,0x70,0x3c,0x64,0xf9,0x58,0x25,0x26,0x13,0x91,0xc9,0x64,0xa4,0x99,0x2d,0x06,0x1f,0x29,0x42,0x07,0x8c,0x80,0x1e,0x50,0xff,0x88,0x3c,0x67,0x80,0xf1,0xc1,0x03,0xde,0x03,0x11,0x07,0x8c,0x10,0x1e,0x38,0x40,0x79,0xf0,0x32,0x80,0xf1,0x83,0x58,0x72,0x58,0xc8,0xc6,0x73,0x40,0x3f,0x10,0x78,0x9e,0xf1,0x17,0xe9,0xcf,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x02,0x44,0x18,0xa3,0x80,0x82,0x32,0x06,0x44,0x0f,0xf0,0x73,0x5d,0xe3,0x92,0x7e,0xcf,0x06,0x3b,0xc3,0xa4,0xdd,0xfc,0xc8,0x35,0xca,0x44,0xa5,0x34,0x5c,0x16,0x92,0x89,0x4a,0x91,0x4a,0x60,0x20,0xf7,0xa4,0x83,0xc6,0x8e,0x0f,0xba,0x88,0x3c,0x68,0x00,0xf7,0x80,0x65,0xe3,0x9c,0x7a,0x6e,0x0a,0x49,0xc3,0xb8,0xc8,0xa4,0xc0,0xf5,0x00,0x08,0x1d,0xc0,0x0e,0x0f,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2f,0xfb,0xfe,0x00,0x38,0x39,0x97,0xa1,0x00,0xe7,0xf0,0x3b,0x1c,0x00,0xd9,0x00,0x32,0xc8,0x01,0xef,0x48,0x03,0x2d,0x03,0xe0,0x45,0x38,0x0d,0x02,0x01,0x28,0xc0,0x01,0xca,0x01,0x1f,0xa0,0x10,0x12,0x05,0x80,0x80,0x49,0x38,0x1a,0xa0,0x00,0xf0,0x6f,0xf8,0x08,0x20,0x38,0xac,0x10,0x48,0x44,0x06,0x25,0x40,0xaa,0x80,0x07,0xc3,0xfb,0x80,0x41,0x21,0x9b,0x0b,0x6e,0x4e,0x09,0x10,0x80,0xc2,0xb8,0x1f,0xe0,0xf8,0xfc,0x7e,0x30,0x10,0x7a,0xc8,0x20,0x50,0x9a,0x04,0x0c,0x3e,0x3f,0x12,0x48,0x83,0xc6,0x60,0x2f,0x29,0x14,0x0a,0x0b,0xc0,0x80,0x87,0xc7,0xf3,0xf1,0x81,0x8f,0xc7,0x01,0x6d,0x81,0xc7,0x24,0x90,0x28,0x17,0x02,0x39,0x5e,0xaa,0xee,0x75,0xd0,0x3e,0x27,0xb4,0x5e,0x30,0x39,0x20,0x3c,0xa8,0x11,0xcd,0x36,0xab,0x33,0x2e,0x07,0x90,0xbc,0x4d,0x82,0x0f,0x14,0x10,0xc7,0x2e,0x21,0xf3,0x17,0x88,0x7c,0x85,0xe3,0x82,0x4c,0x8c,0x03,0x70,0x3f,0x2b,0x19,0x3c,0x47,0xe2,0x04,0x19,0x10,0x3c,0xa4,0x15,0xc2,0xf9,0x7c,0x41,0xe2,0x2e,0x1f,0x81,0xbc,0x68,0x40,0xf1,0xe0,0x6f,0xcf,0xe5,0xf9,0x82,0x63,0x3e,0xfd,0xef,0x9a,0x3c,0x68,0x22,0xf2,0xbf,0x27,0xcb,0xf1,0x04,0xc0,0x03,0xc4,0x5e,0x30,0x80,0x79,0xec,0x17,0xe5,0xf0,0x67,0xb0,0x34,0x68,0x18,0x0a,0xfd,0x56,0x1b,0x1f,0xb0,0x3b,0xd9,0xc0,0x2e,0xf3,0x25,0x90,0x01,0x81,0xe2,0x00,0xe8,0x08,0x3f,0xa0,0x40,0xfe,0x53,0x88,0x03,0x4c,0xe8,0x00,0xa8,0x80,0x3f,0xa4,0x00,0xfe,0xe0,0x21,0xcc,0x00,0x47,0x7f,0x00,0x78,}; -const uint8_t* const _I_InfraredLearn_128x64[] = {_I_InfraredLearn_128x64_0}; - -const uint8_t _I_InfraredSendShort_128x34_0[] = {0x01,0x00,0x42,0x01,0xfe,0x7f,0xc0,0x07,0x03,0x07,0xc4,0x10,0x0a,0x90,0x20,0x7f,0x83,0xfc,0x04,0x3c,0x01,0xc2,0x7f,0xf8,0x80,0x43,0x9f,0x83,0xca,0x40,0x1f,0x5e,0x27,0x7e,0xab,0x55,0xee,0x83,0xce,0x38,0x0f,0x6d,0x50,0x00,0xa5,0xc0,0xf2,0x89,0x03,0xda,0xfe,0x1f,0x1f,0xa8,0x7c,0x48,0xc3,0x09,0x07,0xb6,0xae,0x54,0x1f,0x19,0xd4,0x08,0x40,0x30,0x5f,0x81,0x1c,0x63,0xfe,0x08,0x1f,0x12,0xbe,0x3f,0x49,0x0e,0x02,0x09,0x58,0x04,0x0c,0xd7,0xf1,0x0f,0x1f,0x8e,0x2b,0x11,0xaa,0x95,0x40,0xa2,0x34,0x08,0x16,0xa0,0x4e,0x32,0xab,0xe4,0x7f,0x89,0x77,0x0b,0x0d,0xd6,0x7f,0x82,0x84,0x50,0x20,0x3d,0x81,0x48,0xcd,0x67,0xd3,0xe1,0xf8,0xc8,0xb4,0x43,0xf1,0xc1,0x62,0x24,0x10,0x1b,0x46,0x80,0x3e,0x3f,0xe9,0xf8,0xfc,0xfa,0xa1,0xf1,0xa4,0x68,0x20,0x13,0x8a,0x00,0x7c,0x67,0xf7,0xe3,0xfa,0x4a,0x81,0xe3,0x40,0x80,0x66,0x38,0x66,0xa1,0xeb,0xdd,0x47,0xec,0x0f,0x2c,0x47,0x0e,0xa9,0x35,0xe9,0xd9,0x47,0xe2,0x1f,0x21,0xf8,0xd2,0x17,0xc3,0x88,0x91,0xeb,0x83,0xe6,0xbf,0x42,0x78,0xc4,0x20,0x10,0x88,0x05,0x5c,0x7e,0x7a,0xe1,0xfa,0x42,0x01,0xe5,0x84,0x1f,0x89,0x7c,0xbf,0xf7,0x7b,0xaf,0xdd,0x3e,0x31,0x10,0xe8,0xc2,0x3f,0x01,0xf1,0x3f,0x98,0x7c,0xa7,0x6a,0xf1,0x07,0x97,0x03,0x5e,0x9f,0x36,0x28,0xf7,0x7f,0xa1,0xf1,0x81,0x03,0xca,0x01,0x56,0x5f,0x9f,0xb8,0x3c,0x3e,0xa7,0xf8,0xc1,0x01,0xe5,0xf0,0x15,0x0f,0x85,0xbe,0x21,0xf1,0x00,0x08,0x7c,0x60,0x04,0xf1,0x77,0x96,0x7e,0x02,0xff,0x10,0x7c,0x00,0x16,0x08,0x05,0x40,0x78,0xa3,0xc4,0x00,0xb2,0x40,0x7b,0x2b,0xc4,0x00,0xb5,0x48,0x78,0x3d,0x70,0x01,0xf7,0x07,0xb4,0x00,0x94,0x23,0xfc,0x01,0x18,0x00,0xff,0x85,0xf3,0xff,0xc0,0xc3,0x0f,0x00,0xf0,0x09,0xce,0xf0,0x03,0x2f,0xc0,0x61,0x3f,0xe0,0xf8,0x00,0x30,0x3f,0xc0,}; -const uint8_t* const _I_InfraredSendShort_128x34[] = {_I_InfraredSendShort_128x34_0}; - -const uint8_t _I_InfraredSend_128x64_0[] = {0x01,0x00,0xe2,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xfe,0x04,0x0e,0x05,0x82,0xd7,0x81,0xca,0x21,0x08,0x01,0x8c,0x10,0x0e,0x54,0x00,0x20,0xe0,0xa4,0x00,0xfb,0xb2,0x4e,0xb0,0xfa,0x0e,0x74,0xc7,0x0f,0x3b,0xce,0x4e,0xec,0xf0,0xe1,0x79,0xe4,0xe9,0x58,0x2d,0x3d,0x4a,0x95,0x41,0x89,0x52,0x31,0x59,0x40,0xfa,0x64,0x01,0xe3,0xa0,0xa9,0x5e,0x81,0xe7,0xf4,0x07,0xcc,0x28,0x1e,0x71,0x40,0x7a,0x58,0x01,0xe4,0x3f,0x1c,0x0c,0x4f,0x11,0x0b,0xb3,0x83,0xcc,0x00,0x94,0x20,0x2a,0x03,0xa0,0x1e,0xd0,0x34,0xdf,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x4c,0xf0,0x17,0x4c,0x81,0xa0,0x18,0x18,0x1f,0x39,0x90,0x6c,0x60,0x27,0x70,0xe9,0x3f,0x67,0x03,0x3c,0x80,0x83,0xde,0x81,0x4a,0x84,0xca,0x68,0xb8,0x2b,0xf0,0x3f,0x29,0x20,0xfe,0xa8,0xe0,0x85,0xf3,0x80,0xa5,0xc3,0xb8,0xf4,0xd8,0x11,0x3e,0x40,0x04,0x1b,0x23,0x7d,0x83,0xcd,0x1f,0x60,0x0f,0x00,0x78,0x03,0x7f,0x9f,0xf0,0x01,0xc0,0xc1,0xf1,0x04,0x02,0xa4,0x08,0x1f,0xe0,0xff,0x01,0x0f,0x00,0x70,0x9f,0xfe,0x20,0x10,0xe7,0xe0,0xf2,0x90,0x07,0xd7,0x89,0xdf,0xaa,0xd5,0x7b,0xa0,0xf3,0x8e,0x03,0xdb,0x54,0x00,0x29,0x70,0x3c,0xa2,0x40,0xf6,0xbf,0x87,0xc7,0xea,0x1f,0x12,0x30,0xc2,0x41,0xed,0xab,0x95,0x07,0xc6,0x75,0x02,0x10,0x0c,0x17,0xe0,0x47,0x18,0xff,0x82,0x07,0xc4,0xaf,0x8f,0xd2,0x43,0x80,0x82,0x56,0x01,0x03,0x35,0xfc,0x43,0xc7,0xe3,0x8a,0xc4,0x6a,0xa5,0x50,0x28,0x8d,0x02,0x05,0xa8,0x13,0x8c,0xaa,0xf9,0x1f,0xe2,0x5d,0xc2,0xc3,0x75,0x9f,0xe0,0xa1,0x14,0x08,0x0f,0x60,0x52,0x33,0x59,0xf4,0xf8,0x7e,0x32,0x2d,0x10,0xfc,0x70,0x58,0x89,0x04,0x06,0xd1,0xa0,0x0f,0x8f,0xfa,0x7e,0x3f,0x3e,0xa8,0x7c,0x69,0x1a,0x08,0x04,0xe2,0x80,0x1f,0x19,0xfd,0xf8,0xfe,0x92,0xa0,0x78,0xd0,0x20,0x19,0x8e,0x19,0xa8,0x7a,0xf7,0x51,0xfb,0x03,0xcb,0x11,0xc3,0xaa,0x4d,0x7a,0x76,0x51,0xf8,0x87,0xc8,0x7e,0x34,0x85,0xf0,0xe2,0x24,0x7a,0xe0,0xf9,0xaf,0xd0,0x9e,0x31,0x08,0x04,0x22,0x01,0x57,0x1f,0x9e,0xb8,0x7e,0x90,0x80,0x79,0x61,0x07,0xe2,0x5f,0x2f,0xfd,0xde,0xeb,0xf7,0x4f,0x8c,0x44,0x3a,0x30,0x8f,0xc0,0x7c,0x4f,0xe6,0x1f,0x29,0xda,0xbc,0x41,0xe5,0xc0,0xd7,0xa7,0xcd,0x8a,0x3d,0xdf,0xe8,0x7c,0x60,0x40,0xf2,0x80,0x55,0x97,0xe7,0xee,0x0f,0x0f,0xa9,0xfe,0x30,0x40,0x79,0x7c,0x05,0x43,0xe1,0x6f,0x88,0x7c,0x40,0x02,0x1f,0x18,0x01,0x3c,0x5d,0xe5,0x9f,0x80,0xbf,0xc4,0x1f,0x00,0x05,0x82,0x01,0x50,0x1e,0x28,0xf1,0x00,0x2c,0x90,0x1e,0xca,0xf1,0x00,0x2d,0x52,0x1e,0x0f,0x5c,0x00,0x7d,0xc1,0xed,0x00,0x25,0x08,0xff,0x00,0x46,0x00,0x3f,0xe1,0x7c,0xff,0xf0,0x30,0xc3,0xc0,0x3c,0x02,0x73,0xbc,0x00,0xcb,0xf0,0x18,0x4f,0xf8,0x3e,0x00,0x0c,0x0f,0xf0,}; -const uint8_t* const _I_InfraredSend_128x64[] = {_I_InfraredSend_128x64_0}; - -const uint8_t _I_Mute_25x27_0[] = {0x01,0x00,0x51,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x31,0x81,0xc0,0x64,0x38,0x08,0xa4,0x06,0x83,0x40,0x86,0x40,0x70,0x32,0x08,0x20,0x3c,0x63,0xf0,0x60,0x38,0xc0,0xa0,0xa0,0x31,0xc2,0x02,0xc7,0x03,0x48,0x01,0x94,0xc0,0x06,0xc0,0xb3,0x09,0x98,0x6c,0x84,0x68,0x2b,0x21,0x99,0x8e,0xcc,0x86,0x64,0xb3,0x81,0x94,0xc6,0x03,0x06,0x80,0x70,0x20,0x1f,0xcf,0xfd,0xfc,0xce,0x80,}; -const uint8_t* const _I_Mute_25x27[] = {_I_Mute_25x27_0}; - -const uint8_t _I_Mute_hvr_25x27_0[] = {0x01,0x00,0x4a,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x21,0xfe,0x40,0x7b,0xf7,0xff,0x5c,0x07,0x7f,0xbf,0xf9,0xc0,0x6f,0xfd,0xff,0xd8,0x3c,0x7c,0x1f,0x90,0x38,0xff,0x7f,0x40,0x31,0xbd,0x82,0xc6,0xff,0xb7,0x01,0x97,0x3c,0x06,0xc0,0xb3,0x09,0x98,0x6c,0x84,0x68,0x2b,0x21,0x99,0x8e,0xcc,0x86,0x64,0xb5,0x01,0x89,0x5c,0xcb,0xe6,0x67,0x30,}; -const uint8_t* const _I_Mute_hvr_25x27[] = {_I_Mute_hvr_25x27_0}; - -const uint8_t _I_Power_25x27_0[] = {0x01,0x00,0x54,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x30,0x18,0x80,0x0c,0xa7,0x00,0x35,0xc0,0xce,0x60,0x70,0x1e,0x0c,0xe6,0x0f,0x01,0xf0,0xce,0x21,0xd0,0x1b,0x0c,0xe2,0x18,0x03,0x58,0x80,0x0c,0xa0,0x00,0x39,0xf0,0xc0,0x03,0x63,0xc1,0x80,0x88,0xc7,0x03,0x83,0x15,0x8c,0x07,0xfe,0x02,0x18,0x0d,0xf0,0x76,0x44,0x73,0x01,0x94,0x0c,0xa6,0x30,0x18,0x34,0x03,0x81,0x00,0xfe,0x7f,0xef,0xe6,0x74,}; -const uint8_t* const _I_Power_25x27[] = {_I_Power_25x27_0}; - -const uint8_t _I_Power_hvr_25x27_0[] = {0x01,0x00,0x4b,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x3f,0xff,0x78,0x0c,0xb8,0xe0,0x35,0xbf,0xf1,0xbf,0x90,0x19,0xff,0x1b,0xf1,0x01,0x8f,0xf1,0xfe,0x30,0x1c,0xff,0x1f,0xe6,0x03,0x5f,0x78,0x0c,0xbf,0xe0,0x39,0x8f,0xff,0xc3,0x63,0x3f,0xff,0x08,0xc6,0xff,0x7c,0x15,0x89,0x04,0x7f,0xc0,0x31,0xc1,0x8e,0xc8,0x8e,0x60,0x36,0x2b,0x99,0x7c,0xcc,0xe6,}; -const uint8_t* const _I_Power_hvr_25x27[] = {_I_Power_hvr_25x27_0}; - -const uint8_t _I_Up_25x27_0[] = {0x01,0x00,0x44,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x3c,0x88,0x00,0xca,0x70,0x03,0x2b,0xe0,0x0c,0xbf,0xc0,0x32,0xff,0x80,0x87,0x03,0xff,0x81,0xc0,0x78,0x3f,0xf8,0x3c,0x07,0xc3,0xff,0x87,0xc0,0x7e,0x3f,0xf8,0xf8,0x0d,0x06,0xfe,0x03,0x78,0x19,0x4c,0x60,0x30,0x68,0x07,0x02,0x01,0xfc,0xff,0xdf,0xcc,0xe8,}; -const uint8_t* const _I_Up_25x27[] = {_I_Up_25x27_0}; - -const uint8_t _I_Up_hvr_25x27_0[] = {0x01,0x00,0x39,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x3c,0xf7,0x80,0xcb,0x8e,0x03,0x2c,0x18,0x0c,0x80,0x26,0x25,0x18,0x08,0xa4,0x7f,0x90,0x11,0x88,0xfe,0x20,0x31,0xf8,0x07,0xc2,0x03,0x0f,0x80,0x78,0x00,0x68,0x37,0xf0,0x1d,0x95,0xcc,0xbe,0x66,0x73,}; -const uint8_t* const _I_Up_hvr_25x27[] = {_I_Up_hvr_25x27_0}; - -const uint8_t _I_Vol_down_25x27_0[] = {0x01,0x00,0x2c,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x3f,0x01,0xff,0x07,0xff,0x07,0x01,0xa0,0x5f,0xc0,0x7e,0x03,0x38,0x19,0x4c,0x60,0x30,0x68,0x07,0x02,0x01,0xfc,0xff,0xdf,0xcc,0xe8,}; -const uint8_t* const _I_Vol_down_25x27[] = {_I_Vol_down_25x27_0}; - -const uint8_t _I_Vol_down_hvr_25x27_0[] = {0x01,0x00,0x23,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x3f,0x01,0xf8,0xb4,0x7f,0x00,0x34,0x0b,0xf8,0x0f,0xc0,0x6e,0x57,0x32,0xf9,0x99,0xcc,}; -const uint8_t* const _I_Vol_down_hvr_25x27[] = {_I_Vol_down_hvr_25x27_0}; - -const uint8_t _I_Vol_up_25x27_0[] = {0x01,0x00,0x2f,0x00,0xfc,0x7f,0xe7,0xf0,0x08,0x24,0x02,0x81,0x00,0x81,0x40,0x30,0x10,0x08,0x08,0x38,0x60,0x20,0x38,0x88,0x00,0xfc,0x06,0xbc,0x1f,0xfc,0x1c,0x06,0x81,0x7f,0x01,0xc1,0x0e,0xa0,0x65,0x31,0x80,0xc1,0xa0,0x1c,0x08,0x07,0xf3,0xff,0x7f,0x33,0xa0,}; -const uint8_t* const _I_Vol_up_25x27[] = {_I_Vol_up_25x27_0}; - -const uint8_t _I_Vol_up_hvr_25x27_0[] = {0x01,0x00,0x28,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x38,0xf7,0x80,0xfc,0x06,0xa2,0xd1,0xfc,0x00,0xd0,0x2f,0xe0,0x38,0x21,0xd8,0x0c,0x8a,0xe6,0x5f,0x33,0x39,0x80,}; -const uint8_t* const _I_Vol_up_hvr_25x27[] = {_I_Vol_up_hvr_25x27_0}; - -const uint8_t _I_DoorLeft_70x55_0[] = {0x01,0x00,0x19,0x01,0x00,0x2c,0x32,0x01,0x03,0x04,0x2c,0x18,0x10,0xf0,0x40,0x47,0x82,0x06,0x81,0x03,0xff,0x80,0x08,0x1a,0x20,0x82,0x15,0x28,0x21,0x87,0x82,0x08,0x6f,0xc0,0xb1,0xe6,0x10,0x10,0x8b,0x46,0x20,0x43,0x55,0x8f,0x82,0x10,0x32,0x73,0x0a,0x09,0x89,0x6c,0x1e,0x09,0x00,0x18,0x60,0xf0,0x0c,0x84,0x93,0x82,0x03,0x18,0x0c,0x02,0x1d,0x00,0x90,0x52,0x70,0x50,0x1e,0x00,0x58,0x63,0x90,0x0a,0x06,0x4a,0x09,0x03,0xb0,0x02,0x06,0x70,0x62,0x49,0xf8,0x0c,0x66,0x3f,0xf0,0x41,0x63,0x04,0x43,0x00,0x99,0x60,0x00,0x85,0xc8,0x06,0x14,0xd0,0x80,0x3f,0xc8,0x0d,0xb8,0x10,0x70,0xf8,0x34,0x13,0x03,0x39,0x04,0x1c,0x42,0x19,0xf8,0xa0,0xc2,0x01,0x07,0xef,0x02,0x8c,0x80,0x10,0x9d,0x00,0x43,0xec,0x00,0xa3,0x10,0x04,0x25,0xce,0x19,0xfc,0x88,0x82,0x12,0x0c,0x35,0x10,0x42,0x4c,0xa1,0x90,0x3f,0xc0,0x21,0x22,0x39,0x82,0xc8,0x88,0xd2,0x11,0xf0,0x01,0x88,0xd5,0x18,0xe2,0x08,0x68,0x10,0x0c,0xa8,0x00,0x83,0x81,0xcc,0xd5,0xc3,0x80,0x84,0x82,0x0e,0xcc,0xc0,0x15,0x79,0x02,0x0b,0x98,0xf8,0x11,0x88,0x82,0x0f,0x31,0x19,0x02,0x08,0x2c,0x9f,0x6a,0x1d,0x20,0x41,0x31,0x4c,0x10,0x8d,0x73,0x04,0x23,0xa4,0xc4,0x6c,0xde,0x20,0x42,0xcc,0x01,0x07,0x07,0xff,0x80,0x06,0x3e,0x08,0x38,0x70,0x20,0xa1,0xe0,0x83,0x8e,0x01,0x0c,0xf0,0x73,0x80,0x43,0x70,0x05,0x08,0x00,0x2c,0x04,0xc4,0x46,0x53,0x09,0x98,0x24,0x80,0x65,0x80,0xb0,0xd9,0x84,0x65,0x32,0x06,0x17,0x0f,0x98,0x23,0x63,0xe1,0x88,0xc4,0x08,0x5f,0xc1,0x30,0x9d,0x84,0x4e,0x66,0x94,0x11,0x98,0x75,0x26,0x00,}; -const uint8_t* const _I_DoorLeft_70x55[] = {_I_DoorLeft_70x55_0}; - -const uint8_t _I_DoorLocked_10x56_0[] = {0x01,0x00,0x4e,0x00,0x86,0x40,0x25,0xb0,0x0b,0x6c,0x03,0x9b,0x00,0xc6,0xc0,0x65,0x90,0x10,0x3a,0xc3,0x20,0x31,0xc8,0x04,0xe2,0x01,0x70,0x80,0x78,0x20,0x1c,0x48,0x07,0x22,0x01,0xd0,0x00,0xf0,0x44,0x68,0x90,0x09,0x04,0x02,0x21,0x00,0x84,0x40,0x25,0x80,0x12,0x1e,0x88,0x14,0xc0,0x2e,0x0d,0x11,0xca,0xf8,0x60,0x1c,0x38,0x07,0x1a,0x05,0xcc,0x80,0x72,0x60,0x5c,0x38,0x10,0x1c,0xf9,0x10,0x2e,0x00,0x05,0x60,0x00,0x11,}; -const uint8_t* const _I_DoorLocked_10x56[] = {_I_DoorLocked_10x56_0}; - -const uint8_t _I_DoorRight_70x55_0[] = {0x01,0x00,0x16,0x01,0x81,0xcc,0x01,0x0f,0x60,0x04,0x3f,0x00,0x10,0xf8,0x08,0x0c,0x02,0x05,0x01,0x84,0x02,0x06,0x26,0x0a,0x10,0x8a,0xcc,0xe0,0x1d,0x68,0xe0,0x18,0xab,0xd0,0x0b,0x18,0x10,0x46,0xe6,0x16,0x1e,0x18,0x10,0x46,0xe4,0x28,0x2c,0x98,0x14,0x68,0x00,0x21,0x1d,0x10,0x8c,0x40,0x02,0x0e,0x10,0xa1,0x08,0xc8,0x40,0x42,0x62,0x11,0x94,0x03,0xfd,0xff,0x00,0x0c,0xff,0x0c,0x08,0x28,0x60,0xe4,0xc0,0x85,0x00,0x83,0x00,0x87,0xf1,0x00,0x8c,0x02,0x0b,0x07,0x24,0x84,0xff,0x04,0xc7,0x80,0xa0,0xe4,0xa0,0x81,0x41,0x04,0x17,0x02,0x41,0x49,0x81,0x0e,0x10,0xb2,0xa0,0x82,0x0e,0x9f,0xfc,0x0a,0x62,0xf2,0xc0,0x03,0x92,0xf0,0x08,0x2d,0x78,0x20,0xff,0x02,0x01,0x08,0xae,0x60,0x64,0x38,0x0d,0xb0,0x8d,0x08,0x82,0x11,0x58,0xc4,0x13,0xc0,0x35,0x68,0x62,0x68,0x81,0x09,0x08,0x84,0x40,0x81,0x0d,0x18,0x69,0x10,0x47,0x44,0x66,0x5f,0x21,0xa9,0x29,0x94,0x10,0x2f,0x23,0x53,0x14,0x60,0x42,0x3c,0x08,0xfc,0x02,0x2c,0x62,0x23,0x58,0xd0,0x22,0x00,0x83,0x3e,0x98,0x44,0x43,0x46,0x22,0x30,0x89,0xce,0x01,0x0f,0x70,0x04,0x3f,0x81,0x8a,0x3c,0x21,0xaa,0x70,0x1a,0xe3,0x44,0x1a,0xa6,0x01,0xd2,0x38,0x90,0x8a,0x40,0x20,0xe5,0x96,0x80,0x43,0x81,0x06,0x6b,0x28,0x07,0xf3,0xfe,0x00,0x19,0xf9,0x34,0xc1,0x08,0x8f,0x20,0xf1,0x3e,0x16,0x00,0xa8,0x19,0x00,0x10,0x76,0x03,0xe2,0x3e,0x90,0x45,0x38,0x01,0x42,0x05,0x88,0x44,0x67,0x15,0x70,0x41,0x38,0x04,0x10,0x24,0x03,0x00,0x10,0x20,0x4a,0x46,0xe9,0x46,0xe1,0x04,0x50,0x66,0x40,0x85,0x19,0x98,0x00,0xc0,}; -const uint8_t* const _I_DoorRight_70x55[] = {_I_DoorRight_70x55_0}; - -const uint8_t _I_PassportBottom_128x17_0[] = {0x01,0x00,0x5e,0x00,0x96,0x01,0x97,0xe1,0xff,0x00,0x2e,0x3e,0x68,0x0f,0x5a,0xc5,0x54,0x00,0xb9,0x50,0xfb,0x6a,0x35,0x40,0x05,0xcd,0x4e,0x03,0xfd,0x30,0x0f,0xf8,0x7f,0xa0,0x81,0xfe,0xf9,0x1b,0xfb,0xf3,0x01,0x47,0x66,0x02,0x1b,0x03,0x07,0xe7,0x02,0x0b,0x02,0x07,0xe5,0x82,0x0b,0xf2,0x1c,0xb0,0x01,0x67,0xf0,0x5f,0xd0,0x3f,0x23,0xf0,0x9b,0xc9,0xe5,0x80,0x03,0xd5,0xc0,0x00,0x86,0x01,0xf3,0xe6,0x1e,0x58,0x00,0x36,0xa8,0x06,0xac,0x04,0x30,0x6c,0x30,0xee,0x60,0x1f,0xe0,0x10,0xff,0x0d,0xfb,0x00,}; -const uint8_t* const _I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; - -const uint8_t _I_PassportLeft_6x47_0[] = {0x01,0x00,0x1c,0x00,0x9e,0x40,0xa3,0x32,0x59,0x2c,0x66,0x03,0x01,0x82,0xc2,0x62,0x32,0x50,0x16,0xc8,0x60,0x30,0x28,0x24,0x32,0x39,0x3c,0x9e,0x4d,0x25,0x80,0x1a,}; -const uint8_t* const _I_PassportLeft_6x47[] = {_I_PassportLeft_6x47_0}; - -const uint8_t _I_WarningDolphin_45x42_0[] = {0x01,0x00,0xc6,0x00,0x00,0x1c,0x22,0x04,0x05,0x7f,0xfc,0x1e,0x20,0x05,0x1e,0x04,0x02,0x30,0x05,0x29,0x84,0x02,0xc1,0x20,0x02,0x8c,0x22,0x01,0x80,0x02,0x94,0x10,0x32,0x30,0x10,0x10,0x87,0xca,0x84,0x03,0x10,0x42,0x81,0x48,0x28,0x38,0x08,0x04,0x3e,0x01,0x84,0x83,0xe0,0x30,0x11,0x08,0x05,0xa2,0x11,0x40,0xa0,0x4b,0xc6,0xc5,0x40,0xd0,0x56,0xe0,0x10,0x60,0x29,0x54,0xf0,0x10,0x18,0xf0,0x14,0x6b,0xf6,0x0c,0x04,0x3e,0x40,0x05,0x12,0x80,0xc1,0xe4,0x01,0xd2,0xf8,0x40,0xe4,0x18,0x09,0xf4,0x03,0xf1,0x01,0x90,0x40,0x28,0x30,0x0f,0xe4,0x00,0x16,0x24,0x11,0xbf,0x01,0x44,0xee,0x53,0xf0,0x29,0xf0,0x3e,0x02,0x91,0x3b,0x8c,0xc3,0x81,0x13,0x90,0x48,0x20,0x3f,0xf9,0xfc,0x42,0x60,0x05,0x10,0x98,0x81,0x56,0x11,0x38,0x02,0x9c,0x1a,0x31,0x1e,0x02,0x8f,0x02,0x03,0x1c,0x90,0xc0,0x7c,0x02,0xf1,0xce,0x02,0x07,0x01,0x1f,0x80,0x63,0xa8,0x08,0x71,0x3c,0x8e,0x39,0x24,0x40,0x51,0xc7,0x81,0x53,0x0f,0x3c,0x02,0x9d,0x1e,0x38,0x29,0x10,0x29,0x17,0xc8,0x0a,0x32,0x3a,0x00,0x14,0x4b,0xa2,0x05,0x58,0x98,0x15,0x22,0x20,0x54,0x84,0x81,0x50,}; -const uint8_t* const _I_WarningDolphin_45x42[] = {_I_WarningDolphin_45x42_0}; - -const uint8_t _I_KeyBackspaceSelected_16x9_0[] = {0x00,0xFE,0x7F,0xFF,0xFF,0xEF,0xFF,0xE7,0xFF,0x03,0xC0,0xE7,0xFF,0xEF,0xFF,0xFF,0xFF,0xFE,0x7F,}; -const uint8_t* const _I_KeyBackspaceSelected_16x9[] = {_I_KeyBackspaceSelected_16x9_0}; - -const uint8_t _I_KeyBackspace_16x9_0[] = {0x00,0xFE,0x7F,0x01,0x80,0x11,0x80,0x19,0x80,0xFD,0xBF,0x19,0x80,0x11,0x80,0x01,0x80,0xFE,0x7F,}; -const uint8_t* const _I_KeyBackspace_16x9[] = {_I_KeyBackspace_16x9_0}; - -const uint8_t _I_KeySaveSelected_24x11_0[] = {0x01,0x00,0x1a,0x00,0xff,0x7f,0xc0,0x0d,0xcf,0xb4,0x7c,0xee,0xf6,0xbf,0x6d,0xbe,0xd7,0xe1,0xaf,0xda,0xff,0xbe,0x7c,0xc7,0xcc,0x28,0xa1,0xd1,0xbf,0x80,}; -const uint8_t* const _I_KeySaveSelected_24x11[] = {_I_KeySaveSelected_24x11_0}; - -const uint8_t _I_KeySave_24x11_0[] = {0x01,0x00,0x1e,0x00,0xff,0x7f,0xff,0xf0,0x18,0x06,0x00,0x04,0x53,0x1c,0xbe,0x33,0x13,0x94,0xc9,0x64,0x72,0x99,0xed,0x0e,0x53,0x05,0x19,0xb3,0xe3,0x02,0x8a,0x1d,0x1b,0xf8,}; -const uint8_t* const _I_KeySave_24x11[] = {_I_KeySave_24x11_0}; - -const uint8_t _A_125khz_14_0[] = {0x00,0x80,0x07,0x00,0x08,0x00,0x13,0x00,0x24,0x0E,0x28,0x71,0x28,0x85,0x21,0x01,0x02,0x62,0x02,0x92,0x02,0x92,0x02,0x64,0x02,0x04,0x01,0xF8,0x00,}; -const uint8_t _A_125khz_14_1[] = {0x00,0x80,0x07,0x00,0x08,0x00,0x10,0x00,0x20,0x0E,0x20,0x71,0x20,0x85,0x21,0x01,0x02,0x62,0x02,0x92,0x02,0x92,0x02,0x64,0x02,0x04,0x01,0xF8,0x00,}; -const uint8_t _A_125khz_14_2[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3a,0x01,0x71,0x80,0x61,0x60,0x30,0x18,0x15,0x8a,0x05,0x92,0x00,0x95,0x92,0x05,0x04,0x80,0xfe,0x20,0x00,}; -const uint8_t _A_125khz_14_3[] = {0x01,0x00,0x1a,0x00,0x00,0x24,0x0e,0x01,0x04,0x87,0x42,0x2e,0x30,0x8c,0x2c,0x06,0x03,0x02,0xb1,0x40,0xb2,0x40,0x12,0xb2,0x40,0xa0,0x90,0x1f,0xc4,0x00,}; -const uint8_t* const _A_125khz_14[] = {_A_125khz_14_0,_A_125khz_14_1,_A_125khz_14_2,_A_125khz_14_3}; - -const uint8_t _A_BadUsb_14_0[] = {0x00,0xFF,0x1F,0x01,0x10,0x01,0x10,0xF1,0x11,0xF9,0x13,0xE9,0x12,0x49,0x12,0xF9,0x13,0xF1,0x11,0x51,0x11,0x01,0x10,0xFF,0x1F,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_1[] = {0x00,0x01,0x10,0x01,0x10,0xE1,0x13,0xFD,0x10,0xF9,0x13,0x01,0x17,0xF9,0x13,0x3D,0x10,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x06,0x0C,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_2[] = {0x00,0x01,0x10,0xF1,0x11,0xF9,0x13,0x59,0x13,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB6,0x0D,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_3[] = {0x00,0xF1,0x11,0xF9,0x13,0x59,0x13,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x06,0x0C,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_4[] = {0x00,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x04,0x04,0xFC,0x07,0xFC,0x07,0xFE,0x0F,0xFE,0x0F,0x02,0x08,}; -const uint8_t _A_BadUsb_14_5[] = {0x00,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x04,0x04,0xFC,0x07,0xFC,0x07,0x04,0x04,0xFC,0x07,0x00,0x00,0xFE,0x0F,0xFE,0x0F,0x02,0x08,}; -const uint8_t _A_BadUsb_14_6[] = {0x00,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x04,0x04,0xFC,0x07,0xFC,0x07,0xFE,0x0F,0xFE,0x0F,0x02,0x08,}; -const uint8_t _A_BadUsb_14_7[] = {0x00,0xF1,0x11,0xF9,0x13,0x59,0x13,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x06,0x0C,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_8[] = {0x00,0x01,0x10,0xF1,0x11,0xF9,0x13,0x59,0x13,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB6,0x0D,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_9[] = {0x00,0x01,0x10,0x01,0x10,0xE1,0x13,0xFD,0x10,0xF9,0x13,0x01,0x17,0xF9,0x13,0x3D,0x10,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x06,0x0C,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_10[] = {0x00,0xFF,0x1F,0x01,0x10,0x01,0x10,0xF1,0x11,0xF9,0x13,0xE9,0x12,0x49,0x12,0xF9,0x13,0xF1,0x11,0x51,0x11,0x01,0x10,0xFF,0x1F,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t* const _A_BadUsb_14[] = {_A_BadUsb_14_0,_A_BadUsb_14_1,_A_BadUsb_14_2,_A_BadUsb_14_3,_A_BadUsb_14_4,_A_BadUsb_14_5,_A_BadUsb_14_6,_A_BadUsb_14_7,_A_BadUsb_14_8,_A_BadUsb_14_9,_A_BadUsb_14_10}; - -const uint8_t _A_Bluetooth_14_0[] = {0x00,0x10,0x00,0x30,0x00,0x51,0x08,0x92,0x10,0x94,0x24,0x58,0x28,0x30,0x29,0x30,0x29,0x58,0x28,0x94,0x24,0x92,0x10,0x51,0x08,0x30,0x00,0x10,0x00,}; -const uint8_t _A_Bluetooth_14_1[] = {0x01,0x00,0x1a,0x00,0x88,0x40,0x26,0x10,0x0a,0x8c,0x23,0x25,0x10,0xca,0x49,0x2b,0x12,0x89,0x80,0x04,0x80,0xa2,0x09,0x10,0x68,0x84,0x44,0x2a,0x21,0x91,}; -const uint8_t _A_Bluetooth_14_2[] = {0x01,0x00,0x1a,0x00,0x88,0x40,0x26,0x10,0x0a,0x8c,0x23,0x25,0x10,0xca,0x48,0x2b,0x12,0x09,0x80,0x04,0x80,0xa2,0x09,0x10,0x68,0x84,0x44,0x2a,0x21,0x91,}; -const uint8_t _A_Bluetooth_14_3[] = {0x01,0x00,0x1a,0x00,0x88,0x40,0x26,0x10,0x0a,0x8c,0x03,0x25,0x00,0xca,0x40,0x2b,0x00,0x92,0x00,0x88,0x14,0x41,0x22,0x0d,0x10,0x88,0x82,0x44,0x32,0x20,}; -const uint8_t _A_Bluetooth_14_4[] = {0x00,0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x00,0x94,0x00,0x58,0x00,0x30,0x01,0x30,0x01,0x58,0x00,0x94,0x00,0x92,0x00,0x51,0x00,0x30,0x00,0x10,0x00,}; -const uint8_t _A_Bluetooth_14_5[] = {0x00,0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x00,0x94,0x04,0x58,0x08,0x30,0x09,0x30,0x09,0x58,0x08,0x94,0x04,0x92,0x00,0x51,0x00,0x30,0x00,0x10,0x00,}; -const uint8_t* const _A_Bluetooth_14[] = {_A_Bluetooth_14_0,_A_Bluetooth_14_1,_A_Bluetooth_14_2,_A_Bluetooth_14_3,_A_Bluetooth_14_4,_A_Bluetooth_14_5}; - -const uint8_t _A_Debug_14_0[] = {0x00,0x20,0x01,0xC1,0x20,0x22,0x11,0x24,0x09,0xD9,0x26,0x16,0x1A,0xD8,0x06,0xD8,0x06,0xD6,0x1A,0x19,0x26,0xE4,0x09,0xC2,0x10,0x01,0x20,0x00,0x00,}; -const uint8_t _A_Debug_14_1[] = {0x00,0x20,0x01,0xC0,0x00,0x22,0x11,0x25,0x29,0xD8,0x06,0x16,0x1A,0xD9,0x26,0xD8,0x06,0xD4,0x0A,0x12,0x12,0xEA,0x15,0xC5,0x28,0x02,0x10,0x02,0x10,}; -const uint8_t _A_Debug_14_2[] = {0x00,0x20,0x01,0xC0,0x00,0x20,0x01,0x24,0x09,0xDA,0x16,0x11,0x22,0xDC,0x0E,0xDA,0x16,0xD9,0x26,0x14,0x0A,0xF2,0x13,0xD1,0x22,0x08,0x04,0x06,0x18,}; -const uint8_t _A_Debug_14_3[] = {0x00,0x22,0x11,0xC4,0x08,0x24,0x09,0x25,0x29,0xD9,0x26,0x12,0x12,0xDC,0x0E,0xD8,0x06,0xD8,0x06,0x14,0x0A,0xF4,0x0B,0xD2,0x12,0x19,0x26,0x06,0x18,}; -const uint8_t* const _A_Debug_14[] = {_A_Debug_14_0,_A_Debug_14_1,_A_Debug_14_2,_A_Debug_14_3}; - -const uint8_t _A_FileManager_14_0[] = {0x00,0xFC,0x07,0x04,0x04,0xF4,0x05,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,}; -const uint8_t _A_FileManager_14_1[] = {0x00,0x00,0x00,0x00,0x00,0xFC,0x07,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,}; -const uint8_t _A_FileManager_14_2[] = {0x01,0x00,0x17,0x00,0x00,0x3f,0xfe,0x0f,0x05,0x82,0x7d,0x67,0xf1,0x59,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; -const uint8_t _A_FileManager_14_3[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3e,0x01,0x11,0x80,0x7f,0x67,0xf1,0x59,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; -const uint8_t _A_FileManager_14_4[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3e,0x01,0x11,0x80,0x7c,0x67,0xf1,0x19,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; -const uint8_t _A_FileManager_14_5[] = {0x01,0x00,0x0f,0x00,0x00,0x3c,0x3e,0x01,0x11,0x80,0x7f,0xe0,0xf0,0x18,0x40,0x06,0x7f,0xd0,0x70,}; -const uint8_t _A_FileManager_14_6[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3e,0x01,0x11,0x80,0x7c,0x67,0xf1,0x19,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; -const uint8_t _A_FileManager_14_7[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3e,0x01,0x11,0x80,0x7f,0x67,0xf1,0x59,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; -const uint8_t _A_FileManager_14_8[] = {0x01,0x00,0x17,0x00,0x00,0x3f,0xfe,0x0f,0x05,0x82,0x7d,0x67,0xf1,0x59,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; -const uint8_t _A_FileManager_14_9[] = {0x00,0x00,0x00,0x00,0x00,0xFC,0x07,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,}; -const uint8_t* const _A_FileManager_14[] = {_A_FileManager_14_0,_A_FileManager_14_1,_A_FileManager_14_2,_A_FileManager_14_3,_A_FileManager_14_4,_A_FileManager_14_5,_A_FileManager_14_6,_A_FileManager_14_7,_A_FileManager_14_8,_A_FileManager_14_9}; - -const uint8_t _A_GPIO_14_0[] = {0x01,0x00,0x15,0x00,0xa2,0x41,0x00,0x23,0xee,0x87,0x00,0x54,0x16,0x60,0x11,0x09,0x8f,0xfe,0x3f,0x11,0x88,0xd5,0x62,0xa0,0x31,}; -const uint8_t _A_GPIO_14_1[] = {0x01,0x00,0x12,0x00,0xa2,0x41,0x00,0x27,0xee,0x87,0x00,0x54,0x1a,0xbf,0xf8,0xfc,0x46,0x23,0x55,0x8a,0x80,0xc4,}; -const uint8_t _A_GPIO_14_2[] = {0x01,0x00,0x12,0x00,0xa2,0x41,0x00,0x2f,0xee,0x87,0x00,0x54,0x12,0x3f,0xf8,0xfd,0x56,0x2a,0x01,0x18,0x8c,0x44,}; -const uint8_t _A_GPIO_14_3[] = {0x01,0x00,0x11,0x00,0xa2,0x41,0x00,0x37,0xee,0x87,0x00,0x4f,0xff,0x1f,0xaa,0xc5,0x40,0x23,0x11,0x88,0x80,}; -const uint8_t _A_GPIO_14_4[] = {0x01,0x00,0x0d,0x00,0xa2,0x41,0x00,0x3f,0xee,0x87,0x7f,0xe3,0xe0,0x13,0x88,0xc4,0x40,}; -const uint8_t _A_GPIO_14_5[] = {0x01,0x00,0x11,0x00,0xa2,0x41,0x00,0x3b,0xee,0x87,0x00,0x47,0xff,0x1f,0x00,0x8d,0x56,0x2b,0x11,0x88,0x80,}; -const uint8_t _A_GPIO_14_6[] = {0x01,0x00,0x11,0x00,0xa2,0x41,0x00,0x33,0xee,0x87,0x00,0x57,0xff,0x1f,0xaa,0xc5,0x40,0x23,0x11,0x88,0x80,}; -const uint8_t _A_GPIO_14_7[] = {0x01,0x00,0x12,0x00,0xa2,0x41,0x00,0x2b,0xee,0x87,0x00,0x54,0x16,0x7f,0xf8,0xfc,0x46,0x23,0x55,0x8a,0x80,0xc4,}; -const uint8_t* const _A_GPIO_14[] = {_A_GPIO_14_0,_A_GPIO_14_1,_A_GPIO_14_2,_A_GPIO_14_3,_A_GPIO_14_4,_A_GPIO_14_5,_A_GPIO_14_6,_A_GPIO_14_7}; - -const uint8_t _A_Games_14_0[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x62,0x0d,0xfc,0x87,0xc0,0xa2,0x10,0x99,0x24,0x76,0x54,0x03,0x1f,0x0c,0x86,0x23,0x22,0x02,0x8c,0x1a,0x30,}; -const uint8_t _A_Games_14_1[] = {0x01,0x00,0x1a,0x00,0x00,0x2c,0x62,0x0d,0xfc,0x87,0xc0,0xa2,0x10,0x99,0x24,0x76,0x54,0x03,0x1f,0x0c,0x87,0x23,0x22,0x02,0x8c,0x5a,0x35,0x01,0x90,0x00,}; -const uint8_t _A_Games_14_2[] = {0x00,0x00,0x00,0x00,0x00,0x18,0x06,0xFC,0x0F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x91,0x22,0x89,0x24,0x16,0x1A,0x11,0x22,0x01,0x20,}; -const uint8_t _A_Games_14_3[] = {0x00,0x00,0x00,0x18,0x06,0xFC,0x0F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x91,0x22,0x89,0x24,0x96,0x1A,0x11,0x22,0x11,0x22,0x01,0x20,}; -const uint8_t _A_Games_14_4[] = {0x00,0x18,0x06,0xFC,0x0F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x91,0x22,0x89,0x24,0x16,0x1A,0x11,0x22,0x01,0x20,0x00,0x00,0x00,0x00,}; -const uint8_t _A_Games_14_5[] = {0x00,0x84,0x08,0x18,0x06,0xFD,0x2F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x91,0x22,0x09,0x24,0x16,0x1A,0x01,0x20,0x00,0x00,0x00,0x00,}; -const uint8_t _A_Games_14_6[] = {0x00,0x84,0x08,0x84,0x08,0x19,0x26,0xFD,0x2F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x11,0x22,0x09,0x24,0x06,0x18,0x00,0x00,0x00,0x00,}; -const uint8_t _A_Games_14_7[] = {0x00,0x84,0x08,0x84,0x08,0x85,0x28,0x19,0x26,0xFD,0x2F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x11,0x22,0x09,0x24,0x06,0x18,0x00,0x00,}; -const uint8_t _A_Games_14_8[] = {0x00,0x00,0x00,0x00,0x00,0x84,0x08,0x84,0x08,0x19,0x26,0xFD,0x2F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x11,0x22,0x09,0x24,0x06,0x18,}; -const uint8_t* const _A_Games_14[] = {_A_Games_14_0,_A_Games_14_1,_A_Games_14_2,_A_Games_14_3,_A_Games_14_4,_A_Games_14_5,_A_Games_14_6,_A_Games_14_7,_A_Games_14_8}; - -const uint8_t _A_Infrared_14_0[] = {0x01,0x00,0x1a,0x00,0xfc,0x41,0xe0,0xd1,0x88,0x0c,0x83,0xe1,0x03,0x84,0x41,0x01,0x63,0xe0,0x80,0x84,0x4c,0x0a,0x20,0xd1,0x0a,0x88,0x04,0x7f,0xf3,0xf0,}; -const uint8_t _A_Infrared_14_1[] = {0x01,0x00,0x17,0x00,0xfc,0x41,0xe0,0xd1,0x88,0x0c,0x83,0xe1,0x03,0x84,0x41,0x02,0x2f,0xe0,0x80,0x83,0x44,0x2a,0x20,0x11,0xff,0xcf,0xc0,}; -const uint8_t _A_Infrared_14_2[] = {0x01,0x00,0x13,0x00,0xfc,0x41,0xe0,0xd1,0x88,0x0c,0x80,0x23,0x7e,0x08,0x0f,0xc2,0x06,0x15,0x10,0x08,0xff,0xe7,0xe0,}; -const uint8_t _A_Infrared_14_3[] = {0x01,0x00,0x0e,0x00,0x00,0x78,0x00,0x7c,0x10,0x1f,0x84,0x0f,0xf1,0x07,0x00,0x8f,0xfe,0x7e,}; -const uint8_t _A_Infrared_14_4[] = {0x01,0x00,0x0e,0x00,0x00,0x5f,0x82,0x02,0x05,0x5f,0x84,0x0f,0xf1,0x07,0x00,0x8f,0xfe,0x7e,}; -const uint8_t _A_Infrared_14_5[] = {0x01,0x00,0x15,0x00,0x00,0x2f,0xc2,0x07,0x08,0x82,0x01,0x47,0xc1,0x01,0x05,0x98,0x14,0x41,0xa3,0xf8,0x83,0x80,0x47,0xff,0x3f,}; -const uint8_t* const _A_Infrared_14[] = {_A_Infrared_14_0,_A_Infrared_14_1,_A_Infrared_14_2,_A_Infrared_14_3,_A_Infrared_14_4,_A_Infrared_14_5}; - -const uint8_t _A_NFC_14_0[] = {0x00,0x00,0x08,0x00,0x10,0x00,0x12,0x00,0x22,0x42,0x24,0x87,0x24,0x8D,0x24,0x99,0x24,0xF1,0x24,0x62,0x24,0x00,0x22,0x00,0x12,0x00,0x10,0x00,0x08,}; -const uint8_t _A_NFC_14_1[] = {0x01,0x00,0x1a,0x00,0x80,0x42,0x20,0x11,0x00,0x09,0x48,0x28,0x52,0x0c,0x3c,0x83,0x1b,0x20,0xcc,0xc8,0x3e,0x32,0x0b,0x14,0x80,0x1a,0x21,0x34,0x84,0x00,}; -const uint8_t _A_NFC_14_2[] = {0x01,0x00,0x10,0x00,0x00,0x3d,0x0a,0x01,0x87,0x80,0x63,0x60,0x19,0x98,0x07,0xc6,0x01,0x62,0x09,0xc0,}; -const uint8_t _A_NFC_14_3[] = {0x01,0x00,0x16,0x00,0x00,0x24,0x08,0x02,0x34,0x28,0x26,0x1e,0x09,0x8d,0x82,0x66,0x60,0x9f,0x18,0x25,0x8a,0x08,0x0f,0x30,0xb1,0x80,}; -const uint8_t* const _A_NFC_14[] = {_A_NFC_14_0,_A_NFC_14_1,_A_NFC_14_2,_A_NFC_14_3}; - -const uint8_t _A_Passport_14_0[] = {0x00,0xC0,0x00,0x20,0x01,0x20,0x01,0xFE,0x1F,0x01,0x20,0x39,0x2F,0x39,0x20,0x39,0x2F,0x11,0x20,0x39,0x2B,0x45,0x20,0x7D,0x25,0x01,0x20,0xFE,0x1F,}; -const uint8_t _A_Passport_14_1[] = {0x01,0x00,0x0e,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x42,0x00,0xf0,0x4c,0x40,}; -const uint8_t _A_Passport_14_2[] = {0x01,0x00,0x13,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x42,0x90,0x42,0x40,0x24,0x07,0x30,0x0a,0x84,0xc4,}; -const uint8_t _A_Passport_14_3[] = {0x01,0x00,0x14,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0xc8,0x21,0x20,0x12,0x06,0x10,0x05,0x82,0x62,}; -const uint8_t _A_Passport_14_4[] = {0x01,0x00,0x13,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0x80,0x52,0x22,0x0e,0x30,0x0a,0x04,0xc4,}; -const uint8_t _A_Passport_14_5[] = {0x01,0x00,0x18,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0x80,0x52,0x23,0x20,0x84,0xc8,0x20,0xa0,0x12,0x07,0x88,0x4c,0x40,}; -const uint8_t _A_Passport_14_6[] = {0x01,0x00,0x18,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0x80,0x52,0x23,0x20,0x84,0xc8,0x20,0xb2,0x0b,0xe8,0x50,0x82,0x62,}; -const uint8_t _A_Passport_14_7[] = {0x01,0x00,0x1a,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0xc8,0xe7,0x20,0x31,0x90,0x44,0x40,0x65,0x45,0x90,0x5f,0x42,0x84,0x13,0x10,}; -const uint8_t _A_Passport_14_8[] = {0x00,0xC0,0x00,0x20,0x01,0x20,0x01,0xFE,0x1F,0x01,0x20,0x39,0x2F,0x39,0x20,0x39,0x23,0x11,0x20,0x39,0x20,0x45,0x20,0x7D,0x20,0x01,0x20,0xFE,0x1F,}; -const uint8_t _A_Passport_14_9[] = {0x01,0x00,0x1a,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0xcb,0xe7,0x20,0x32,0x88,0x80,0xc6,0x47,0x45,0x90,0x5f,0x42,0x84,0x13,0x10,}; -const uint8_t* const _A_Passport_14[] = {_A_Passport_14_0,_A_Passport_14_1,_A_Passport_14_2,_A_Passport_14_3,_A_Passport_14_4,_A_Passport_14_5,_A_Passport_14_6,_A_Passport_14_7,_A_Passport_14_8,_A_Passport_14_9}; - -const uint8_t _A_Plugins_14_0[] = {0x00,0xE7,0x00,0xA5,0x00,0x99,0x01,0x01,0x02,0x01,0x02,0x81,0x01,0x81,0x0E,0xE7,0x08,0x24,0x18,0x58,0x20,0x40,0x20,0x30,0x18,0x10,0x08,0xF0,0x0F,}; -const uint8_t _A_Plugins_14_1[] = {0x00,0x70,0x0E,0x50,0x0A,0x90,0x19,0x10,0x20,0x10,0x20,0x18,0x18,0x1E,0x08,0x72,0x0E,0x46,0x02,0x88,0x05,0x08,0x04,0x06,0x03,0x02,0x01,0xFE,0x01,}; -const uint8_t _A_Plugins_14_2[] = {0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xE4,0x1C,0xA7,0x14,0x21,0x33,0x23,0x00,0x24,0x00,0x24,0x30,0x23,0x10,0xE1,0x1C,0xFF,0x04,0x00,0x03,0x00,0x00,}; -const uint8_t _A_Plugins_14_3[] = {0x00,0x30,0x00,0x48,0x00,0xCE,0x01,0x02,0x01,0x3E,0x07,0x28,0x05,0xC8,0x0C,0x0E,0x10,0x0A,0x10,0x0E,0x0C,0x08,0x04,0x38,0x07,0x20,0x01,0xC0,0x00,}; -const uint8_t _A_Plugins_14_4[] = {0x00,0x40,0x02,0x70,0x0E,0x10,0x08,0x30,0x18,0xCE,0x21,0x4A,0x21,0x32,0x1B,0x02,0x0C,0x02,0x0C,0x02,0x03,0x02,0x01,0xCE,0x01,0x48,0x00,0x30,0x00,}; -const uint8_t _A_Plugins_14_5[] = {0x00,0x00,0x0C,0x00,0x12,0x80,0x33,0x80,0x00,0xB9,0x01,0x29,0x02,0x66,0x02,0x80,0x01,0x80,0x00,0x60,0x3F,0x20,0x00,0x39,0x00,0x09,0x00,0x06,0x00,}; -const uint8_t _A_Plugins_14_6[] = {0x00,0x00,0x00,0x00,0x06,0x00,0x09,0xF3,0x39,0x52,0x20,0xCC,0x20,0x00,0x01,0x00,0x01,0xC0,0x20,0x40,0x20,0xF3,0x3F,0x12,0x00,0x0C,0x00,0x00,0x00,}; -const uint8_t _A_Plugins_14_7[] = {0x00,0x00,0x00,0x00,0x0C,0x00,0x12,0xB9,0x33,0xA9,0x00,0x66,0x01,0x80,0x02,0x80,0x02,0x60,0x01,0xA0,0x00,0xB9,0x3F,0x09,0x00,0x06,0x00,0x00,0x00,}; -const uint8_t _A_Plugins_14_8[] = {0x00,0x00,0x00,0x39,0x00,0x29,0x00,0x66,0x06,0x80,0x09,0x80,0x39,0x60,0x20,0xE0,0x20,0x39,0x01,0x09,0x01,0xC6,0x20,0x40,0x20,0xC0,0x3F,0x00,0x00,}; -const uint8_t* const _A_Plugins_14[] = {_A_Plugins_14_0,_A_Plugins_14_1,_A_Plugins_14_2,_A_Plugins_14_3,_A_Plugins_14_4,_A_Plugins_14_5,_A_Plugins_14_6,_A_Plugins_14_7,_A_Plugins_14_8}; - -const uint8_t _A_Power_14_0[] = {0x01,0x00,0x17,0x00,0xa0,0x00,0x4a,0x99,0x06,0xa1,0x42,0x00,0x23,0x41,0x88,0x00,0x56,0x05,0x08,0x00,0x8c,0x32,0x0d,0xf0,0x80,0x86,0xc4,}; -const uint8_t* const _A_Power_14[] = {_A_Power_14_0}; - -const uint8_t _A_Settings_14_0[] = {0x00,0x03,0x07,0x87,0x04,0x8E,0x02,0x9C,0x32,0xF8,0x2C,0x50,0x20,0x30,0x1E,0x1E,0x03,0x81,0x04,0xCD,0x09,0x53,0x13,0x50,0x26,0x48,0x2C,0x38,0x18,}; -const uint8_t _A_Settings_14_1[] = {0x00,0x03,0x00,0x87,0x03,0x4E,0x02,0x7C,0x01,0x48,0x19,0x58,0x16,0x30,0x10,0x10,0x0F,0x8F,0x04,0xC0,0x09,0x26,0x13,0x29,0x16,0x28,0x0C,0x24,0x00,}; -const uint8_t _A_Settings_14_2[] = {0x00,0x03,0x00,0x07,0x00,0xDE,0x01,0x24,0x01,0xAC,0x00,0xB8,0x0C,0x30,0x0B,0x10,0x08,0x88,0x07,0xC7,0x09,0x20,0x0B,0x13,0x06,0x14,0x00,0x14,0x00,}; -const uint8_t _A_Settings_14_3[] = {0x00,0x04,0x0C,0x09,0x00,0x13,0x20,0x26,0x20,0x4C,0x00,0xB8,0x00,0xA4,0x00,0x74,0x00,0x94,0x01,0x64,0x01,0x02,0x01,0xF1,0x18,0x08,0x38,0x04,0x30,}; -const uint8_t _A_Settings_14_4[] = {0x00,0x04,0x0F,0x89,0x00,0x93,0x26,0xA6,0x29,0x2C,0x28,0x18,0x24,0x00,0x1C,0x0E,0x00,0x09,0x00,0x05,0x06,0x65,0x0E,0x59,0x1C,0x40,0x38,0x3C,0x30,}; -const uint8_t _A_Settings_14_5[] = {0x00,0x04,0x08,0x05,0x04,0xC3,0x23,0x20,0x10,0xA0,0x09,0x60,0x0A,0x00,0x0A,0x80,0x09,0x80,0x07,0x03,0x07,0x02,0x0E,0x01,0x3C,0x19,0x08,0x16,0x18,}; -const uint8_t _A_Settings_14_6[] = {0x00,0x00,0x14,0x00,0x24,0x00,0x02,0x18,0x31,0xF8,0x08,0x08,0x04,0x68,0x02,0xD8,0x02,0x80,0x06,0xC0,0x0A,0xC0,0x13,0x00,0x26,0x00,0x0C,0x00,0x18,}; -const uint8_t _A_Settings_14_7[] = {0x00,0x00,0x0A,0x00,0x0A,0x0C,0x32,0x1C,0x01,0xB8,0x38,0x78,0x04,0x04,0x02,0x34,0x03,0x4C,0x05,0x40,0x09,0x20,0x13,0xE0,0x26,0x00,0x0C,0x00,0x18,}; -const uint8_t _A_Settings_14_8[] = {0x00,0x00,0x09,0x06,0x05,0x0E,0x25,0x1C,0x19,0xB8,0x00,0x70,0x3C,0x3C,0x02,0x02,0x03,0x9A,0x04,0xA6,0x09,0xA0,0x13,0x90,0x26,0x70,0x0C,0x00,0x18,}; -const uint8_t _A_Settings_14_9[] = {0x00,0x03,0x07,0x87,0x04,0x8E,0x02,0x9C,0x32,0xF8,0x2C,0x50,0x20,0x30,0x1E,0x1E,0x03,0x81,0x04,0xCD,0x09,0x53,0x13,0x50,0x26,0x48,0x2C,0x38,0x18,}; -const uint8_t* const _A_Settings_14[] = {_A_Settings_14_0,_A_Settings_14_1,_A_Settings_14_2,_A_Settings_14_3,_A_Settings_14_4,_A_Settings_14_5,_A_Settings_14_6,_A_Settings_14_7,_A_Settings_14_8,_A_Settings_14_9}; - -const uint8_t _A_Sub1ghz_14_0[] = {0x01,0x00,0x1a,0x00,0x82,0x42,0x20,0x51,0x08,0x4c,0x92,0x0b,0x28,0xea,0xca,0x80,0x22,0x05,0x1e,0x4c,0x93,0x85,0x10,0xe2,0x42,0x38,0x10,0x00,0x0a,0x80,}; -const uint8_t _A_Sub1ghz_14_1[] = {0x01,0x00,0x18,0x00,0x82,0x42,0x20,0x51,0x08,0x4c,0x92,0x0b,0x28,0xe2,0x80,0x48,0x0a,0x3c,0x99,0x27,0x0a,0x21,0xc4,0x84,0x70,0x20,0x00,0x15,}; -const uint8_t _A_Sub1ghz_14_2[] = {0x01,0x00,0x16,0x00,0x82,0x42,0x20,0x51,0x08,0x0c,0x80,0x02,0x3c,0x10,0x09,0x01,0x4f,0x85,0x10,0xe2,0x42,0x38,0x10,0x00,0x0a,0x80,}; -const uint8_t _A_Sub1ghz_14_3[] = {0x01,0x00,0x08,0x00,0x00,0x3f,0x00,0x02,0x40,0x55,0x00,0xc8,}; -const uint8_t _A_Sub1ghz_14_4[] = {0x01,0x00,0x0a,0x00,0x00,0x3f,0x42,0x04,0x01,0x10,0x28,0xf0,0x00,0x38,}; -const uint8_t _A_Sub1ghz_14_5[] = {0x01,0x00,0x12,0x00,0x00,0x1c,0x22,0x09,0x04,0x84,0x75,0x21,0x40,0x11,0x02,0x8f,0x22,0x09,0xc0,0x80,0x00,0x64,}; -const uint8_t* const _A_Sub1ghz_14[] = {_A_Sub1ghz_14_0,_A_Sub1ghz_14_1,_A_Sub1ghz_14_2,_A_Sub1ghz_14_3,_A_Sub1ghz_14_4,_A_Sub1ghz_14_5}; - -const uint8_t _A_Tamagotchi_14_0[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x2A,0x1A,0x19,0x33,0x89,0x32,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_1[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x1A,0x1B,0xA9,0x32,0x19,0x33,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_2[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x8A,0x1A,0x19,0x33,0x29,0x32,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_3[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x4A,0x1B,0xA9,0x32,0x59,0x32,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_4[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0xAA,0x1A,0x49,0x32,0xA9,0x32,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_5[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x5A,0x1A,0xA9,0x32,0x49,0x33,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t* const _A_Tamagotchi_14[] = {_A_Tamagotchi_14_0,_A_Tamagotchi_14_1,_A_Tamagotchi_14_2,_A_Tamagotchi_14_3,_A_Tamagotchi_14_4,_A_Tamagotchi_14_5}; - -const uint8_t _A_U2F_14_0[] = {0x00,0x00,0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; -const uint8_t _A_U2F_14_1[] = {0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; -const uint8_t _A_U2F_14_2[] = {0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0x08,0x00,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; -const uint8_t _A_U2F_14_3[] = {0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; -const uint8_t* const _A_U2F_14[] = {_A_U2F_14_0,_A_U2F_14_1,_A_U2F_14_2,_A_U2F_14_3}; - -const uint8_t _A_iButton_14_0[] = {0x00,0x00,0x1C,0x00,0x3E,0x00,0x35,0x80,0x3A,0x78,0x15,0x84,0x0A,0x32,0x05,0x49,0x02,0x85,0x02,0x85,0x02,0x49,0x02,0x32,0x01,0x84,0x00,0x78,0x00,}; -const uint8_t _A_iButton_14_1[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x26,0x80,0x21,0xE0,0x10,0x38,0x0D,0x6C,0x03,0x56,0x01,0x2B,0x01,0x97,0x00,0x4D,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,}; -const uint8_t _A_iButton_14_2[] = {0x01,0x00,0x1a,0x00,0x00,0x24,0xc2,0x01,0x2c,0x80,0x48,0xfb,0x11,0x89,0x64,0x1b,0x2d,0x01,0xa5,0xc0,0x24,0xb0,0x08,0x94,0x02,0x13,0x00,0x83,0x85,0x88,}; -const uint8_t _A_iButton_14_3[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x26,0x80,0x21,0x60,0x18,0x98,0x06,0x04,0x01,0x02,0x01,0x01,0x01,0x81,0x00,0x41,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,}; -const uint8_t _A_iButton_14_4[] = {0x01,0x00,0x1a,0x00,0x80,0x47,0x20,0x13,0xe8,0x04,0xd7,0x01,0x3a,0xbc,0x45,0x70,0x90,0xa8,0x14,0x16,0x03,0x02,0x00,0xa8,0x08,0x70,0x90,0x0b,0xc4,0x00,}; -const uint8_t _A_iButton_14_5[] = {0x01,0x00,0x1a,0x00,0x00,0x14,0xe2,0x01,0x24,0x80,0x48,0xb0,0x11,0x1f,0x04,0x22,0x31,0x05,0x83,0x40,0xa0,0x20,0x13,0x80,0xf0,0x60,0x13,0xe0,0xc1,0x00,}; -const uint8_t _A_iButton_14_6[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x24,0x00,0x23,0x80,0x20,0xF0,0x10,0x0C,0x0D,0xE2,0x02,0x91,0x01,0x69,0x01,0x15,0x01,0x8D,0x00,0x4D,0x00,0x3E,0x00,}; -const uint8_t* const _A_iButton_14[] = {_A_iButton_14_0,_A_iButton_14_1,_A_iButton_14_2,_A_iButton_14_3,_A_iButton_14_4,_A_iButton_14_5,_A_iButton_14_6}; - -const uint8_t _I_Detailed_chip_17x13_0[] = {0x01,0x00,0x1e,0x00,0xfe,0x5f,0xe0,0x10,0x2c,0x04,0x02,0x23,0x11,0x80,0xe4,0x62,0x50,0x1a,0xff,0xc2,0x03,0x21,0x84,0x00,0x9a,0xbf,0xf4,0x08,0x98,0x5c,0x83,0xa4,0x23,0x20,}; -const uint8_t* const _I_Detailed_chip_17x13[] = {_I_Detailed_chip_17x13_0}; - -const uint8_t _I_Medium_chip_22x21_0[] = {0x01,0x00,0x35,0x00,0xfe,0x7f,0xe1,0xf0,0x28,0x04,0x43,0xf3,0xff,0x93,0xe1,0x6a,0x52,0x8e,0x2f,0xfe,0x51,0x25,0x80,0x4a,0x72,0xb6,0x79,0x55,0x76,0xc1,0x2e,0xaa,0xc0,0x25,0x51,0xdc,0x00,0x14,0x70,0x00,0x56,0xae,0x81,0x47,0x2b,0x7d,0x95,0x07,0x48,0x46,0x42,0x92,0x17,0x90,0xd4,0x87,0x64,}; -const uint8_t* const _I_Medium_chip_22x21[] = {_I_Medium_chip_22x21_0}; - -const uint8_t _I_Pin_arrow_down_7x9_0[] = {0x00,0x1C,0x1C,0x1C,0x1C,0x1C,0x7F,0x3E,0x1C,0x08,}; -const uint8_t* const _I_Pin_arrow_down_7x9[] = {_I_Pin_arrow_down_7x9_0}; - -const uint8_t _I_Pin_arrow_left_9x7_0[] = {0x00,0x08,0x00,0x0C,0x00,0xFE,0x01,0xFF,0x01,0xFE,0x01,0x0C,0x00,0x08,0x00,}; -const uint8_t* const _I_Pin_arrow_left_9x7[] = {_I_Pin_arrow_left_9x7_0}; - -const uint8_t _I_Pin_arrow_right_9x7_0[] = {0x00,0x20,0x00,0x60,0x00,0xFF,0x00,0xFF,0x01,0xFF,0x00,0x60,0x00,0x20,0x00,}; -const uint8_t* const _I_Pin_arrow_right_9x7[] = {_I_Pin_arrow_right_9x7_0}; - -const uint8_t _I_Pin_arrow_up7x9_0[] = {0x00,0x08,0x1C,0x3E,0x7F,0x1C,0x1C,0x1C,0x1C,0x1C,}; -const uint8_t* const _I_Pin_arrow_up7x9[] = {_I_Pin_arrow_up7x9_0}; - -const uint8_t _I_Pin_attention_dpad_29x29_0[] = {0x01,0x00,0x56,0x00,0x80,0x7f,0x20,0xe0,0x31,0x81,0xc6,0x20,0x1c,0x08,0x05,0x82,0x01,0x20,0xa0,0x60,0x20,0x11,0x0f,0x04,0x02,0x03,0x08,0xf8,0x40,0x60,0x50,0x4f,0xc4,0x0e,0x09,0x04,0x05,0x8c,0x12,0x04,0x03,0x18,0x44,0x08,0x42,0x30,0x88,0x08,0x0c,0x62,0x14,0x18,0x05,0x02,0x21,0x61,0x14,0x8c,0x43,0xe3,0x01,0xf8,0x44,0x7f,0x20,0x31,0x89,0x81,0xcc,0x1e,0x61,0x73,0x0f,0x98,0x9c,0xc5,0xe6,0x37,0x31,0xf9,0x91,0xcc,0x9e,0x65,0x73,0x2f,0x99,0x9c,0xcd,0xe6,}; -const uint8_t* const _I_Pin_attention_dpad_29x29[] = {_I_Pin_attention_dpad_29x29_0}; - -const uint8_t _I_Pin_back_arrow_10x8_0[] = {0x00,0x04,0x00,0x06,0x00,0xFF,0x00,0x06,0x01,0x04,0x02,0x00,0x02,0x00,0x01,0xF8,0x00,}; -const uint8_t* const _I_Pin_back_arrow_10x8[] = {_I_Pin_back_arrow_10x8_0}; - -const uint8_t _I_Pin_back_full_40x8_0[] = {0x01,0x00,0x26,0x00,0x82,0x01,0x0e,0x0c,0x02,0x18,0x14,0x03,0xfe,0x04,0x38,0x37,0xc6,0xc3,0x32,0xf7,0x41,0x20,0x59,0x0a,0x54,0xa6,0x01,0xf2,0x88,0xde,0x80,0x83,0x01,0xc8,0x42,0xa5,0x3f,0x88,0x05,0x82,0x65,0x2e,}; -const uint8_t* const _I_Pin_back_full_40x8[] = {_I_Pin_back_full_40x8_0}; - -const uint8_t _I_Pin_cell_13x13_0[] = {0x01,0x00,0x0a,0x00,0xff,0xc7,0xe0,0x31,0x00,0x0f,0x80,0x4c,0x2e,0x20,}; -const uint8_t* const _I_Pin_cell_13x13[] = {_I_Pin_cell_13x13_0}; - -const uint8_t _I_Pin_pointer_5x3_0[] = {0x00,0x04,0x0E,0x1F,}; -const uint8_t* const _I_Pin_pointer_5x3[] = {_I_Pin_pointer_5x3_0}; - -const uint8_t _I_Pin_star_7x7_0[] = {0x00,0x49,0x2A,0x1C,0x7F,0x1C,0x2A,0x49,}; -const uint8_t* const _I_Pin_star_7x7[] = {_I_Pin_star_7x7_0}; - -const uint8_t _I_passport_bad1_46x49_0[] = {0x01,0x00,0xd2,0x00,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7e,0x02,0x18,0x0f,0xe0,0x0a,0x57,0xff,0xf7,0x9c,0x0a,0x59,0xf8,0x0e,0x60,0x0a,0x56,0xf8,0x05,0x83,0xfc,0x05,0x18,0xbc,0x03,0x01,0xfd,0x02,0x8c,0x2c,0x5a,0x3f,0xa0,0x28,0xc1,0x40,0xa3,0xf4,0x02,0x8c,0x08,0x0a,0x77,0xf8,0x08,0x14,0x7d,0x13,0xfd,0xf9,0x14,0x80,0xab,0xd0,0x9f,0xd7,0xe0,0x10,0x60,0x2a,0x42,0x20,0x1a,0x09,0xfc,0xbe,0x01,0x10,0x02,0xa5,0x9c,0x0a,0x78,0x0e,0x74,0x04,0x0a,0x31,0x7a,0x06,0x7a,0x06,0x05,0x39,0xb0,0x44,0x80,0xa3,0x7e,0x02,0xa5,0xf0,0x0a,0x78,0x0a,0x00,0x14,0xf8,0x13,0xf0,0x29,0xc8,0x07,0x66,0x70,0x11,0xd8,0xea,0xa7,0xf1,0xb2,0x99,0x4c,0x00,0xa9,0xc0,0x9f,0x01,0x4e,0x01,0x3d,0x02,0x8c,0x38,0x0a,0x33,0xa8,0x6c,0x02,0x62,0x05,0x19,0xa0,0x14,0x78,0x00,0x51,0x94,0x01,0x46,0x01,0x03,0x02,0xa4,0x30,0x0a,0x2a,0x02,0x98,0x7c,0x25,0x60,0x52,0xe0,0x43,0xe5,0x80,0x51,0xc0,0x27,0x46,0x51,0x09,0x05,0x88,0xc0,0x66,0x80,0x52,0xfe,0x40,0x27,0x60,0x52,0xf8,0x7f,0xe7,0xa0,0x52,0xe0,0x5f,0xe7,0xc0,0x52,0x80,0x6f,0xe7,0xe0,0x53,0xde,0x01,0x50,0xe2,0x20,0x5f,0x02,0xbf,0xfb,0xfe,0x00,0x28,0xf8,}; -const uint8_t* const _I_passport_bad1_46x49[] = {_I_passport_bad1_46x49_0}; - -const uint8_t _I_passport_bad2_46x49_0[] = {0x01,0x00,0xee,0x00,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7e,0x02,0x18,0x0f,0xe0,0x0a,0x57,0xff,0xf7,0x9c,0x0a,0x59,0xf8,0x0e,0x60,0x0a,0x5e,0xf8,0xfd,0x83,0xfc,0x05,0x18,0xbd,0x83,0x01,0xfd,0x02,0x8c,0x2f,0x01,0x01,0xfd,0x01,0x46,0x0b,0x00,0x81,0x7d,0x00,0xa3,0x02,0x80,0x41,0x3d,0x13,0xfb,0xfc,0x04,0x0a,0x3d,0x09,0xfe,0xfc,0x88,0x30,0x80,0x2a,0xea,0xa7,0xf5,0xf8,0x04,0x7e,0xa1,0xb5,0x02,0x8f,0x02,0xc1,0xb8,0xbf,0x4f,0xe5,0xf2,0x0e,0x07,0x53,0x03,0x3e,0x02,0x8e,0x9e,0x75,0x80,0x02,0x8e,0x42,0x9d,0x05,0xd1,0x4f,0xa2,0xf5,0x08,0xf4,0x0c,0x0a,0x73,0x69,0x08,0x14,0xab,0x17,0xe0,0x29,0xd4,0x2f,0x80,0x53,0xcc,0x50,0x24,0x22,0x31,0x8b,0xfc,0x08,0x62,0x05,0x29,0x07,0x32,0x0f,0x40,0x9f,0xc5,0xe2,0x13,0x8f,0xc5,0xfe,0x7f,0x1b,0x4f,0x90,0x44,0x40,0xa7,0x00,0x9e,0x81,0x52,0x75,0x1d,0x80,0x43,0x80,0xa3,0x34,0x86,0xc0,0x26,0x20,0x54,0xe0,0x01,0x46,0x51,0x0b,0x01,0x8c,0x0c,0x0a,0x90,0xc0,0x2a,0x4c,0x3e,0x12,0xb0,0x28,0xcc,0x38,0x10,0xf9,0x64,0x24,0x3a,0x29,0xd1,0x94,0x01,0x47,0x00,0x30,0x19,0xa0,0x14,0x60,0x1f,0xd8,0x04,0xec,0x0a,0x5f,0xaf,0xfc,0xf4,0x0a,0x5f,0x4b,0xfc,0xf8,0x0a,0x5a,0x8d,0xfc,0xfc,0x0a,0x54,0x00,0x2a,0x60,0x37,0x40,0x53,0x80,0x2e,0x44,0x0a,0x7a,0x00,0x2e,0x7f,0xbf,0xe0,0x02,0x8f,0x80,}; -const uint8_t* const _I_passport_bad2_46x49[] = {_I_passport_bad2_46x49_0}; - -const uint8_t _I_passport_bad3_46x49_0[] = {0x01,0x00,0x07,0x01,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7e,0x02,0x18,0x0f,0xc0,0x0a,0x57,0xff,0xf7,0xbc,0x0a,0x59,0xf8,0x0f,0x40,0x0a,0x56,0xf8,0x04,0xe0,0x0a,0x51,0x78,0x07,0x1b,0xfc,0x05,0x18,0x5c,0x02,0x03,0xfd,0x02,0x8c,0x37,0x01,0x00,0xfd,0x01,0x46,0x15,0x40,0x80,0x7d,0x27,0xf7,0xf8,0x48,0x14,0xf7,0xf0,0x80,0x28,0xfa,0x00,0xa5,0x20,0x80,0x72,0x27,0xf5,0xf8,0x80,0x14,0x76,0x00,0x52,0x9f,0xc0,0x2f,0xd3,0xf9,0x7e,0x82,0x81,0xc0,0xc8,0xcf,0xa5,0xf6,0x0d,0x3c,0xe3,0x20,0x05,0x1d,0x05,0x32,0x4b,0xa0,0x9f,0x45,0xec,0x11,0xc9,0x18,0x14,0xe6,0x94,0x10,0x29,0xd7,0x00,0xa9,0x62,0x02,0x9f,0x02,0x83,0x41,0x11,0x88,0x14,0x77,0xf2,0x00,0x29,0x48,0x39,0x92,0x7a,0x84,0xfe,0x27,0x10,0x9c,0x7e,0x2f,0xf3,0xf8,0xea,0x78,0x68,0x18,0x09,0xf4,0x7c,0x0a,0x27,0x21,0x9e,0xc6,0xd5,0x65,0x01,0x9d,0x44,0xe0,0x10,0xe8,0x04,0x0a,0x69,0x63,0x80,0x4c,0x60,0x10,0x49,0xa6,0x0e,0x03,0xc0,0x80,0x42,0x25,0x10,0x38,0x34,0x02,0x06,0x05,0x28,0x44,0x02,0x19,0x10,0x02,0x8c,0x42,0x01,0x30,0xf8,0x4b,0xe0,0x71,0x48,0x07,0x02,0x3f,0x2c,0x05,0x8e,0x02,0x03,0x00,0x94,0x43,0xc2,0x22,0x30,0x19,0xa5,0xc4,0x0a,0x3f,0xc8,0x04,0xef,0x02,0x3c,0x16,0xe8,0xcf,0x60,0x31,0xc0,0xe8,0xdf,0xe7,0xd0,0x1b,0x01,0x34,0x77,0xf3,0xf8,0x08,0x88,0xb7,0x80,0x51,0x80,0x10,0x87,0x40,0x05,0x22,0x10,0xd8,0x00,0xa5,0x0a,0x05,0x88,0x74,0x41,0x64,0x05,0x7f,0xf7,0xfc,0x00,0x51,0xf0,}; -const uint8_t* const _I_passport_bad3_46x49[] = {_I_passport_bad3_46x49_0}; - -const uint8_t _I_passport_bottom_128x18_0[] = {0x01,0x00,0x54,0x00,0x99,0x01,0x97,0xf1,0xff,0x00,0x2e,0x1c,0x1e,0xdf,0xc0,0x7b,0x63,0xe6,0xc0,0xfe,0x9e,0x03,0xfa,0x70,0x0f,0xe9,0x80,0x7f,0xc1,0xfd,0x04,0x37,0xf7,0xc9,0x1d,0xb8,0x08,0x4c,0x04,0x1f,0xb0,0x58,0x10,0x3f,0x38,0x00,0xfe,0xb0,0x41,0x7e,0x44,0x96,0x00,0x2c,0xfe,0x0b,0xfa,0x07,0xe4,0x7e,0x13,0x79,0x1d,0xce,0x02,0x03,0xc0,0x80,0x7c,0xf9,0x83,0xb9,0x80,0x40,0xc0,0x43,0x06,0xc3,0x0e,0xe6,0x01,0xfe,0x01,0x0f,0xf2,0x06,0x90,0xd0,}; -const uint8_t* const _I_passport_bottom_128x18[] = {_I_passport_bottom_128x18_0}; - -const uint8_t _I_passport_happy1_46x49_0[] = {0x01,0x00,0x09,0x01,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7f,0xff,0x87,0xe0,0x00,0xa7,0xf1,0xbf,0x85,0x04,0x0a,0x30,0xec,0x07,0xe4,0x0a,0x37,0xf8,0x0c,0x03,0xec,0x05,0x1d,0xf8,0x98,0x7d,0x00,0x51,0xaf,0x81,0x47,0xa0,0x05,0x19,0x78,0x14,0xa0,0x73,0xf8,0xb8,0x14,0x74,0x1f,0xc9,0xf0,0x14,0xa4,0x10,0x39,0xec,0x2c,0x0a,0x3c,0x08,0x04,0xe8,0x0a,0x52,0x00,0x28,0xc1,0x7c,0x10,0x08,0x87,0x82,0x77,0x05,0xfc,0x40,0xe1,0x1f,0x80,0x28,0xff,0x20,0x70,0x4f,0xe4,0xf6,0x07,0xfe,0x80,0xc0,0xbf,0xd3,0xe8,0x1e,0x7a,0x0f,0x00,0xbf,0xcf,0xe0,0x74,0xe8,0x46,0x03,0x7e,0x05,0x19,0x70,0xbc,0x7b,0xe0,0x51,0x8a,0x40,0x3c,0x1e,0xf0,0x28,0xc4,0x20,0x1f,0x0f,0xb8,0x14,0xff,0x1f,0xb9,0xf9,0xa8,0x60,0x3f,0xcf,0xc8,0x14,0xff,0xde,0x70,0x29,0x61,0xb0,0xf9,0xf0,0x29,0x12,0x06,0xfd,0x3e,0x02,0x8f,0x82,0x0f,0xf8,0x9c,0x81,0x44,0x80,0x3e,0x09,0xb8,0x14,0x94,0x43,0x2b,0x80,0xcc,0x20,0xc0,0x71,0x94,0x40,0x69,0x10,0x90,0x29,0xe2,0x21,0x00,0x51,0x9b,0x01,0x4f,0xc0,0x23,0x1c,0x24,0x43,0xf5,0x1f,0x17,0x88,0x14,0x7e,0x1e,0x31,0xd8,0xe0,0xa4,0x18,0x02,0x99,0x01,0x46,0x01,0xfa,0x02,0x8e,0x06,0x80,0x05,0x6f,0xa4,0xff,0x03,0x80,0xc0,0x01,0x4a,0x82,0x04,0x18,0x08,0x14,0xb8,0x10,0x18,0x0f,0xa2,0x7f,0x21,0x02,0x8c,0x08,0x0a,0x31,0x10,0x28,0xc1,0x3a,0x13,0xf8,0x6f,0x82,0x07,0x18,0x02,0x8c,0x0c,0x0a,0x3e,0x0d,0x00,0xbc,0x7e,0x0b,0x31,0xb3,0xcf,0xff,0xdf,0xf0,0x01,0x47,0xc0,}; -const uint8_t* const _I_passport_happy1_46x49[] = {_I_passport_happy1_46x49_0}; - -const uint8_t _I_passport_happy2_46x49_0[] = {0x01,0x00,0x16,0x01,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7f,0xff,0x87,0xe0,0x00,0xa7,0xf1,0xbf,0x85,0x04,0x0a,0x30,0xec,0x07,0x84,0x0a,0x37,0xf8,0x0c,0x03,0xbe,0x05,0x1d,0xfc,0xfb,0x81,0xa0,0x02,0x8f,0x7f,0x83,0x21,0xa4,0x43,0xe7,0xf2,0xf8,0x06,0x4a,0xa1,0xf3,0x9f,0x45,0xe0,0x10,0xcc,0x8c,0x32,0x7b,0x17,0xb8,0x42,0x30,0x50,0x39,0xd4,0x2f,0x19,0x25,0xe1,0x40,0x26,0x90,0xb8,0x15,0x1a,0x40,0x05,0x18,0x2f,0x86,0x89,0x18,0xf0,0x4d,0xe0,0xbf,0x98,0x2c,0x13,0xf1,0x3b,0xc2,0xff,0x20,0xb0,0x2f,0xe4,0xf7,0x07,0xfe,0x82,0xc0,0x7f,0xd3,0xec,0x1e,0x7b,0x8f,0x00,0xbf,0xcf,0xf0,0x74,0xc9,0xc6,0x03,0x7f,0x3f,0x81,0xc8,0x60,0x1c,0x0e,0xf8,0x14,0x62,0xd0,0x0f,0x07,0xbc,0x0a,0x31,0x88,0x07,0xc3,0xee,0x05,0x18,0x84,0x03,0xf1,0xfb,0x9f,0x9a,0x86,0x03,0xfc,0xfc,0x81,0x4f,0xfd,0xe7,0x02,0x96,0x1b,0x0f,0x9f,0x02,0x97,0xe2,0x07,0x7e,0x9f,0x01,0x47,0xc1,0x07,0xfc,0x4c,0x40,0xa2,0x40,0x1f,0x04,0xbc,0x0a,0x4a,0x21,0x95,0xc0,0x66,0x10,0x60,0x38,0xca,0x20,0x34,0x88,0x48,0x14,0xf1,0x10,0x80,0x28,0xcd,0x80,0xa7,0xe0,0x9c,0xc0,0x70,0x91,0x0f,0xd4,0x7c,0x5e,0x20,0x51,0xf8,0x78,0xc7,0x63,0x82,0x90,0x60,0x0a,0x64,0x05,0x18,0x07,0xe8,0x0a,0x38,0x1a,0x00,0x15,0xbe,0x93,0xfc,0x0e,0x03,0x00,0x05,0x2a,0x08,0x10,0x60,0x20,0x52,0xe0,0x40,0x60,0x3e,0x89,0xfc,0x84,0x0a,0x30,0x20,0x28,0xc4,0x40,0xa3,0x04,0xe8,0x4f,0xe1,0xbe,0x04,0x88,0x81,0x46,0x06,0x05,0x1f,0x06,0x80,0x5e,0x3f,0x08,0x3c,0x02,0xcf,0x3f,0xff,0x7f,0xc0,0x05,0x1f,}; -const uint8_t* const _I_passport_happy2_46x49[] = {_I_passport_happy2_46x49_0}; - -const uint8_t _I_passport_happy3_46x49_0[] = {0x01,0x00,0x23,0x01,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7f,0xff,0x81,0xe0,0x00,0xa7,0xfc,0xbf,0xff,0x00,0xa3,0x7f,0x85,0xe0,0x3e,0x60,0x51,0xdf,0xc1,0x38,0x1e,0xc0,0x28,0xd7,0xe0,0x52,0x0e,0x98,0x14,0x65,0xf0,0x28,0x86,0x92,0x1f,0x3f,0x8b,0xc0,0xa1,0x14,0x8f,0x9c,0xfa,0x2f,0x04,0x84,0x64,0x21,0x93,0xd8,0x5f,0xf2,0x6b,0xa0,0x81,0xce,0xa1,0x70,0x2a,0x37,0x82,0x05,0x34,0x82,0xfe,0x70,0x92,0x08,0x24,0xd3,0x1b,0x04,0x82,0xc4,0x7d,0x13,0x7c,0xbf,0xca,0x0b,0x0d,0xfc,0x4e,0xf4,0x7f,0xa8,0x2c,0x0f,0xf9,0x3d,0xe1,0xe7,0xa0,0xf0,0x1f,0xf4,0xfb,0x07,0x8e,0xe3,0xc0,0x2f,0xf3,0xfc,0x0d,0xd2,0x71,0x80,0xdf,0x81,0x46,0x73,0x00,0xe0,0x77,0xe7,0xf0,0x18,0x9c,0x03,0xc1,0xef,0x02,0x8c,0x7a,0x01,0xf0,0xfb,0x81,0x46,0x21,0x00,0xfc,0x7e,0xe7,0xf0,0x38,0x04,0x07,0xf9,0xf9,0x9f,0xc1,0x40,0xa3,0xfe,0xf3,0xcf,0xe1,0x30,0x0c,0x36,0x1f,0x3f,0x3f,0x88,0x85,0x86,0x07,0x7e,0x9f,0x48,0x45,0x03,0x07,0xfc,0x4c,0x68,0x2a,0xa1,0xbf,0xf8,0x25,0xf4,0x30,0x28,0xa8,0x86,0x57,0x47,0x98,0x41,0x80,0xe3,0x28,0x96,0xd2,0x04,0xa2,0x05,0x18,0xce,0x22,0x10,0x05,0x19,0xb4,0xc4,0x0a,0x5e,0x09,0xcd,0x87,0x09,0x10,0xfd,0x47,0xe7,0xdc,0x10,0x28,0xfc,0x3c,0x66,0x51,0xc1,0x48,0x30,0x05,0x31,0x02,0x94,0x03,0xf4,0x05,0x1c,0x0d,0x00,0x0a,0xdf,0x40,0x28,0xe0,0x30,0x00,0x52,0xa0,0x81,0x06,0x02,0x05,0x2e,0x04,0x06,0x03,0xe8,0x9f,0xc8,0x40,0xa3,0x02,0x02,0x8c,0x44,0x0a,0x30,0x4e,0x84,0xfe,0x1b,0xe0,0x81,0xc6,0x00,0xa3,0x03,0x02,0x8f,0x83,0x40,0x95,0x1f,0x84,0x1e,0x01,0x67,0x9f,0xff,0xbf,0xe0,0x02,0x8f,0x80,}; -const uint8_t* const _I_passport_happy3_46x49[] = {_I_passport_happy3_46x49_0}; - -const uint8_t _I_passport_left_6x46_0[] = {0x01,0x00,0x1b,0x00,0x9e,0x40,0xa3,0x32,0x59,0x2c,0x66,0x03,0x01,0x82,0xc2,0x62,0x32,0x50,0x16,0xc8,0x60,0x30,0x28,0x34,0x3a,0x3d,0x3e,0x9d,0x4c,0x80,0x14,}; -const uint8_t* const _I_passport_left_6x46[] = {_I_passport_left_6x46_0}; - -const uint8_t _I_passport_okay1_46x49_0[] = {0x01,0x00,0xcc,0x00,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7e,0x02,0x1b,0xfc,0x00,0x0a,0x78,0xff,0xff,0xe0,0x0a,0x57,0x38,0x07,0x9c,0x0a,0x50,0xc8,0x06,0x60,0x0a,0x37,0xf8,0x1c,0x02,0xc0,0x05,0x1d,0xf8,0xb4,0x70,0x13,0xef,0xfd,0x7c,0x68,0x53,0xdf,0xfc,0xbc,0x0a,0x53,0xaf,0xfc,0x5c,0x0b,0x13,0x4f,0xfc,0x2c,0x0b,0x12,0x8f,0xfc,0x14,0x0a,0xdf,0x08,0x0c,0xc3,0xff,0x02,0x80,0x7a,0x20,0x60,0x53,0xfa,0x41,0xc0,0xa7,0x12,0x87,0xc8,0x00,0xa5,0x92,0x02,0xa7,0xc8,0x0b,0x5e,0x28,0x58,0x14,0xe0,0x90,0xc0,0x29,0xfa,0x20,0xe0,0x51,0x1d,0x8c,0x42,0x10,0x05,0x38,0x44,0x40,0x0a,0x38,0x58,0x78,0x30,0x40,0xa3,0x7d,0x29,0x94,0x82,0xff,0x06,0x02,0x9e,0x7e,0x02,0x88,0x10,0x28,0xdb,0xd1,0xc4,0x05,0x13,0xe1,0x50,0x00,0xa2,0x76,0x29,0x00,0x15,0x22,0x00,0x51,0x3e,0x14,0x38,0x0a,0x7c,0x01,0x28,0xc8,0x3c,0xb0,0xf9,0xe0,0x64,0xa3,0x7f,0x05,0xf8,0x8a,0x50,0x0a,0x4b,0x83,0x02,0x8f,0x7e,0x01,0xe0,0x2a,0x0c,0x81,0xbc,0x41,0x81,0x2c,0x8f,0x83,0xfe,0x11,0x2f,0xff,0xbe,0x3e,0x05,0x40,0xb0,0x81,0x4c,0x74,0x20,0x52,0x15,0x1c,0x83,0xfc,0x23,0x10,0x00,0xc7,0xc0,}; -const uint8_t* const _I_passport_okay1_46x49[] = {_I_passport_okay1_46x49_0}; - -const uint8_t _I_passport_okay2_46x49_0[] = {0x01,0x00,0xe5,0x00,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7e,0x02,0x1b,0xfe,0x00,0x0a,0x78,0x7b,0xff,0xf0,0x0a,0x57,0x9c,0x77,0x8c,0x0a,0x37,0xfc,0x34,0x07,0x38,0x05,0x1d,0xfd,0x06,0x01,0x60,0x02,0x8d,0x7e,0x41,0x00,0xc0,0x4f,0xbf,0xf2,0xf8,0x80,0xd0,0x67,0xbf,0xf8,0xb8,0x14,0xa7,0x40,0x51,0x84,0x01,0x4e,0x17,0x0c,0x02,0x8c,0xd3,0xff,0x05,0x82,0x01,0x5e,0x51,0xff,0x81,0x40,0xbf,0x10,0x30,0x29,0xc1,0x20,0x93,0x00,0x29,0x7c,0xa1,0x20,0x51,0xff,0x40,0xfd,0x31,0x39,0x85,0xfe,0x03,0x1c,0x8a,0xc4,0xe4,0x17,0xf8,0x2f,0x83,0x2b,0x17,0x90,0x6f,0xf0,0x90,0x0f,0xa8,0x16,0xbc,0xa0,0x52,0x84,0x40,0x61,0x51,0x20,0x29,0xfd,0xa3,0xe0,0x52,0x80,0x46,0xa1,0x02,0x91,0x80,0xf8,0x21,0x31,0x00,0x28,0xe0,0x63,0xf0,0x80,0x28,0xff,0xef,0xca,0xc2,0x90,0x4f,0xe0,0x68,0x21,0x02,0x8f,0x7c,0x12,0x20,0x52,0x97,0x81,0x52,0x2e,0x05,0x1a,0x00,0x14,0x61,0x61,0xb2,0x00,0x8c,0x14,0x0a,0x31,0x80,0x2a,0x41,0x80,0xa7,0xc0,0x80,0x81,0x47,0xcb,0x03,0x9e,0x06,0x4a,0x37,0xfc,0x1b,0x08,0xa5,0x00,0xa4,0x35,0x20,0x29,0x10,0x47,0xc1,0x0f,0x26,0x93,0x90,0x43,0x02,0x59,0x1f,0x07,0xfc,0x22,0x5f,0xff,0x7c,0x7c,0x0a,0x81,0x61,0x02,0x98,0xe8,0x40,0xa4,0x2a,0x39,0x07,0xf8,0x46,0x20,0x01,0x8f,0x80,}; -const uint8_t* const _I_passport_okay2_46x49[] = {_I_passport_okay2_46x49_0}; - -const uint8_t _I_passport_okay3_46x49_0[] = {0x01,0x00,0x06,0x01,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7e,0x02,0x2c,0x00,0x14,0xfb,0xf7,0xff,0xe0,0x14,0xa4,0xf8,0x0f,0x18,0x14,0xaf,0x30,0x0c,0xe0,0x14,0x6f,0xf8,0x68,0x05,0xa0,0x0a,0x3b,0xf8,0x0c,0x07,0x11,0x3e,0xff,0xd7,0xe0,0x10,0x28,0x44,0xf7,0xff,0x2f,0x02,0x8c,0x12,0x75,0xff,0x8b,0xc0,0x20,0x80,0x52,0x85,0x81,0x4a,0x68,0x05,0x28,0x44,0x08,0x0a,0x30,0x50,0x29,0x4a,0x00,0xa5,0xfc,0x81,0x81,0x4e,0x05,0x06,0x98,0x01,0x4b,0xf3,0x04,0x02,0x8f,0xfb,0x07,0x04,0x84,0xcc,0x2f,0xf0,0x1c,0xee,0x2a,0x15,0x28,0x02,0x8f,0x86,0xe4,0x05,0x1d,0xfe,0x03,0x01,0x52,0x02,0xa0,0x2c,0x64,0x80,0x52,0xc5,0x43,0x80,0xa7,0x07,0x87,0x81,0x4a,0x01,0xff,0x83,0xc8,0xb7,0xf0,0x08,0x0c,0x3a,0x09,0x22,0x14,0x94,0x16,0x11,0x21,0xbf,0xe0,0x6f,0xf0,0x40,0x28,0xff,0xef,0xd1,0x45,0x60,0xc8,0x67,0xf0,0x38,0x58,0x7c,0x64,0x5d,0xfe,0x04,0x18,0x0a,0x33,0xc9,0x7e,0x82,0x03,0x40,0x80,0x48,0x22,0xf5,0x08,0x00,0x14,0xa1,0x60,0x51,0x90,0x40,0x26,0x10,0x59,0x44,0x02,0x21,0x00,0x94,0x01,0x4a,0x1d,0x00,0x92,0x01,0x47,0x81,0x01,0x02,0x8f,0x96,0x57,0x3c,0x1a,0x8c,0x8a,0x36,0x8d,0x10,0x29,0x2b,0x04,0x00,0x52,0x15,0xc0,0x80,0x07,0x00,0x41,0x18,0x07,0x82,0x1f,0x80,0x92,0x37,0x88,0x30,0x32,0x9f,0xff,0x83,0xfe,0x12,0x19,0x97,0xff,0xdf,0x1f,0x02,0x8c,0x90,0x0a,0x30,0xf0,0x28,0xae,0x47,0xde,0x3a,0x12,0x68,0xb8,0xc8,0x00,0x32,0x0f,0xf0,0x8c,0x40,0x03,0x1f,}; -const uint8_t* const _I_passport_okay3_46x49[] = {_I_passport_okay3_46x49_0}; - -const uint8_t _I_BatteryBody_52x28_0[] = {0x01,0x00,0x45,0x00,0xe0,0x7f,0x3f,0xe0,0x02,0x87,0xf0,0x21,0xe0,0xc3,0x84,0x50,0x39,0xbf,0xff,0x27,0xfe,0xf3,0x09,0xe0,0x42,0x81,0xab,0x0d,0x03,0x1c,0x2b,0xfc,0x0d,0x48,0x55,0xdc,0x1a,0x90,0x8f,0x18,0x6d,0x41,0xaa,0x1b,0x71,0x4b,0x0d,0xd4,0x1b,0xe0,0xdf,0x1b,0xd5,0xfc,0x1a,0xa5,0x36,0x06,0xac,0x20,0xa7,0xe0,0xdc,0xa5,0x7c,0x7c,0xb7,0xff,0xb4,0x21,0x5c,0xcb,0xc6,}; -const uint8_t* const _I_BatteryBody_52x28[] = {_I_BatteryBody_52x28_0}; - -const uint8_t _I_Battery_16x16_0[] = {0x01,0x00,0x12,0x00,0x00,0x1e,0x02,0x03,0xc0,0x81,0xc8,0x20,0x80,0x11,0xd0,0x41,0x40,0x72,0x11,0x10,0xda,0x80,}; -const uint8_t* const _I_Battery_16x16[] = {_I_Battery_16x16_0}; - -const uint8_t _I_FaceCharging_29x14_0[] = {0x01,0x00,0x28,0x00,0xa0,0x00,0x86,0x05,0x60,0x01,0x8c,0x0e,0x61,0x00,0xc0,0x40,0x63,0x10,0x0e,0x04,0x03,0xf9,0x00,0xf0,0x41,0xc0,0x66,0x13,0xb8,0x40,0x94,0xc0,0x07,0x04,0x82,0x00,0xc6,0x11,0x02,0x01,0x8f,0xc2,0x03,0x00,}; -const uint8_t* const _I_FaceCharging_29x14[] = {_I_FaceCharging_29x14_0}; - -const uint8_t _I_FaceConfused_29x14_0[] = {0x01,0x00,0x30,0x00,0xc0,0x00,0x46,0x1f,0x38,0x80,0xd0,0x22,0x14,0x48,0x0c,0x82,0x0f,0x52,0x80,0xe8,0x21,0x14,0xa0,0x18,0xc2,0xa6,0x59,0x19,0x24,0x27,0x09,0x48,0xa1,0x41,0x2f,0x12,0x4c,0x0c,0x0c,0x51,0x1f,0xc8,0x78,0x0c,0x7f,0xd1,0xf0,0x18,0xc3,0xa3,0x00,0x74,}; -const uint8_t* const _I_FaceConfused_29x14[] = {_I_FaceConfused_29x14_0}; - -const uint8_t _I_FaceNopower_29x14_0[] = {0x01,0x00,0x24,0x00,0x00,0x1f,0x02,0x01,0x60,0x01,0xa7,0x80,0x02,0x57,0xe0,0x48,0xc3,0xe7,0xd0,0x0c,0x04,0x3c,0x39,0x1f,0x88,0x18,0x0c,0x61,0x90,0x60,0x18,0xff,0x82,0x44,0x03,0x38,0x74,0x38,0x2c,0x80,}; -const uint8_t* const _I_FaceNopower_29x14[] = {_I_FaceNopower_29x14_0}; - -const uint8_t _I_FaceNormal_29x14_0[] = {0x01,0x00,0x1e,0x00,0x00,0x1c,0xf2,0x01,0x80,0x83,0xd7,0xa0,0x1c,0x08,0x5d,0xf8,0x06,0x30,0xf0,0x1b,0x84,0xcc,0x41,0x10,0x88,0x10,0x0e,0x62,0x10,0x10,0x18,0xf8,0x00,0x42,}; -const uint8_t* const _I_FaceNormal_29x14[] = {_I_FaceNormal_29x14_0}; - -const uint8_t _I_Health_16x16_0[] = {0x01,0x00,0x12,0x00,0x00,0x2f,0x02,0x03,0x40,0x00,0x95,0xe2,0x1f,0x08,0x84,0x00,0xc4,0x12,0x60,0xf1,0x0c,0xb8,}; -const uint8_t* const _I_Health_16x16[] = {_I_Health_16x16_0}; - -const uint8_t _I_Temperature_16x16_0[] = {0x01,0x00,0x12,0x00,0x00,0x1e,0x02,0x01,0x40,0x80,0x80,0x66,0x41,0x02,0xf0,0x40,0xc0,0x23,0xc0,0x80,0x86,0xd4,}; -const uint8_t* const _I_Temperature_16x16[] = {_I_Temperature_16x16_0}; - -const uint8_t _I_Voltage_16x16_0[] = {0x01,0x00,0x1a,0x00,0x00,0x24,0x0a,0x01,0x03,0xc0,0x40,0x78,0x10,0x1f,0x04,0x03,0xe1,0x07,0xc0,0x40,0xc0,0xe3,0xc0,0x80,0x58,0x20,0x12,0x00,0xd3,0x00,}; -const uint8_t* const _I_Voltage_16x16[] = {_I_Voltage_16x16_0}; - -const uint8_t _I_RFIDBigChip_37x36_0[] = {0x01,0x00,0x6e,0x00,0x83,0x01,0x0f,0xcd,0xff,0x00,0x0c,0x1e,0x24,0x08,0x28,0x47,0x24,0x12,0x51,0x39,0x28,0x24,0xa2,0x91,0x5e,0x07,0xab,0xfe,0x04,0x1c,0x04,0xaa,0x01,0x15,0x02,0x28,0x4c,0x81,0x2c,0x04,0x4e,0x05,0xfc,0x08,0x35,0x59,0x06,0x02,0x81,0x15,0xca,0xe4,0x26,0xf2,0x10,0x70,0xd7,0x66,0x11,0x70,0x70,0xd4,0x20,0x14,0x10,0x70,0xc7,0x68,0x13,0x70,0x70,0xd4,0x28,0x10,0x10,0x4a,0x84,0xc6,0x80,0x13,0x10,0xe8,0xd0,0x03,0xa2,0x27,0x19,0xf0,0x9c,0x46,0x28,0x3b,0x42,0xcf,0x96,0x6a,0xd4,0x13,0x6f,0x2a,0x2c,0xa2,0x90,0x54,0x59,0xfe,0x52,0xa7,0x02,0x4f,0x9f,0xf1,0x52,0x60,}; -const uint8_t* const _I_RFIDBigChip_37x36[] = {_I_RFIDBigChip_37x36_0}; - -const uint8_t _I_RFIDDolphinReceive_97x61_0[] = {0x01,0x00,0x87,0x01,0x00,0x0f,0xfa,0x3e,0x04,0x28,0x08,0x2d,0x78,0x10,0x1f,0x00,0x24,0x70,0x01,0x86,0x98,0x00,0x86,0x0c,0x0c,0x88,0x60,0x08,0x63,0x10,0x0a,0x00,0x31,0xa0,0x40,0x21,0x90,0x03,0x04,0x1a,0x5a,0x08,0x50,0xe9,0x01,0x23,0x20,0x07,0x88,0x30,0xc5,0xa6,0x03,0x10,0x61,0xfc,0x0a,0xa2,0x2d,0x48,0x0c,0x82,0x20,0x04,0x18,0x40,0x40,0x42,0x44,0x37,0x28,0x80,0x30,0xbc,0x94,0xd0,0x62,0x4f,0x20,0x91,0x08,0x44,0x12,0x01,0x17,0xe6,0x40,0x42,0x45,0x00,0xa1,0x03,0x08,0xa8,0x31,0x41,0x88,0x83,0x0f,0x03,0x08,0x06,0x1c,0x1f,0xa1,0x01,0x84,0x1f,0x8a,0x31,0x09,0x0c,0xa5,0x40,0x86,0x30,0x98,0x46,0x02,0x48,0x0c,0x40,0xc9,0x61,0x00,0xe2,0x0c,0x18,0x88,0x65,0xb8,0x85,0x51,0x06,0x21,0x34,0x83,0x23,0x44,0x06,0x29,0x1c,0xb4,0x94,0xf8,0x05,0x19,0x12,0x20,0xc2,0x40,0xb4,0xa8,0x18,0xa9,0xb5,0x9b,0x48,0x28,0x05,0xa1,0x06,0x22,0xd4,0xa3,0x7e,0x05,0x98,0xe0,0x62,0x0c,0xf6,0x86,0xf8,0x16,0x63,0x42,0x06,0x0b,0xa1,0x60,0xfe,0x06,0xe8,0xcf,0x23,0x0d,0x53,0x00,0x14,0x0f,0xe0,0xea,0x28,0xa0,0x31,0xa0,0x3f,0x08,0x18,0x10,0x45,0xa2,0x11,0x20,0x01,0xf4,0x3f,0xe0,0x81,0x84,0x02,0x94,0x18,0xb0,0xc0,0x63,0xc6,0x3f,0xe0,0x31,0x87,0x03,0x1e,0x11,0x3c,0x80,0x47,0xc1,0x91,0x18,0x80,0x58,0x30,0x0e,0x01,0x00,0x30,0xbc,0x47,0xc3,0x05,0x06,0x3c,0x52,0x00,0xe4,0x20,0xcc,0x80,0x04,0x4d,0x00,0x83,0x73,0x08,0x01,0x8f,0xa2,0x0c,0xa1,0xe1,0xa0,0x62,0x16,0x0c,0xac,0x04,0x14,0xd0,0x30,0x08,0x80,0x31,0xb8,0x10,0x27,0x89,0x03,0x1e,0x81,0x05,0xe0,0x01,0x04,0x1e,0x40,0x04,0xd0,0x1c,0x85,0x6a,0x20,0xc7,0xa8,0x02,0x84,0xd2,0x34,0x00,0x63,0x6c,0x11,0xe2,0x4b,0x10,0x63,0xd6,0x20,0x16,0xa9,0x80,0x32,0x35,0x90,0x0e,0xa5,0x04,0x19,0x15,0x48,0x06,0xa3,0x07,0x01,0x06,0x3c,0xa8,0x84,0x30,0xf8,0x10,0x31,0xe2,0xa5,0xc1,0x8f,0x7f,0x2b,0xe9,0xa8,0xa0,0x5f,0x60,0x04,0x21,0x00,0x29,0x98,0x74,0x1f,0xa8,0x0a,0x39,0xc0,0x05,0xf5,0x83,0xb0,0xa0,0x00,0x3e,0xaf,0xfc,0x1c,0x19,0x3d,0x01,0xfb,0xaa,0xd3,0x3c,0x0c,0xaa,0x06,0x54,0x19,0x50,0x0c,0xd0,0x32,0xe2,0x05,0xf1,0x00,0x4c,0x20,0x19,0xe0,0xc9,0x7d,0x08,0x33,0xc0,0x04,}; -const uint8_t* const _I_RFIDDolphinReceive_97x61[] = {_I_RFIDDolphinReceive_97x61_0}; - -const uint8_t _I_RFIDDolphinSend_97x61_0[] = {0x01,0x00,0x8d,0x01,0x00,0x0f,0xfa,0x3e,0x04,0x2a,0x00,0x2d,0x78,0x10,0x1f,0x04,0x04,0x0a,0x38,0x00,0x62,0xcc,0x00,0x43,0x06,0x06,0x44,0x30,0x04,0x31,0x80,0x31,0x07,0x48,0x00,0x50,0x20,0x10,0xc8,0x01,0x64,0x0c,0x1d,0x04,0x28,0x24,0x83,0xd2,0x81,0x04,0xc4,0x18,0x42,0xc3,0x01,0x90,0x30,0xbe,0x05,0x51,0x29,0xa0,0x74,0x60,0x80,0xc1,0x84,0x0b,0x44,0x5e,0x43,0x73,0x82,0x41,0x20,0x1e,0x4a,0x68,0x31,0x27,0x90,0x48,0x84,0x20,0x18,0x31,0x7e,0x64,0x06,0x20,0x0c,0x2a,0x14,0x12,0x40,0x0c,0x28,0xa0,0xc4,0x41,0x87,0x81,0x17,0x08,0x30,0xa0,0xfd,0x08,0x0c,0x20,0xfc,0x38,0x08,0xc4,0x24,0x32,0x95,0x02,0x18,0xc2,0x61,0x18,0x09,0x20,0x31,0x03,0x25,0x84,0x1d,0x88,0x30,0x62,0x21,0x96,0xe2,0x44,0x22,0x00,0xc2,0x26,0xa0,0x64,0x68,0x80,0xc4,0x33,0x9e,0x92,0x9f,0x00,0xa3,0x48,0x24,0x00,0xc4,0x40,0xa4,0xa8,0x18,0xa9,0xb5,0x9b,0x48,0x28,0x05,0xa1,0x06,0x22,0xd4,0xa3,0x7e,0x05,0x98,0xe0,0x4f,0x22,0xcf,0x58,0x6f,0x80,0x10,0x34,0x24,0x31,0x3a,0x52,0x0f,0xe0,0x03,0x0c,0xf1,0xee,0x2d,0x63,0x00,0x0c,0x0f,0xe0,0x13,0x28,0xa0,0x31,0xa0,0x3f,0x08,0x18,0x10,0x45,0xa2,0xe3,0x40,0x00,0xf4,0x3f,0xe1,0xa1,0x84,0x02,0x94,0x18,0xb0,0xc0,0x63,0xc6,0x3f,0xe0,0x31,0x87,0x03,0x1e,0x11,0x3c,0x80,0x47,0xc1,0x90,0x56,0x1b,0x06,0x01,0xc0,0x20,0x06,0x17,0x88,0xf8,0x60,0xa0,0xc7,0x31,0x8a,0x58,0x60,0xe1,0x99,0x00,0x08,0x9a,0x01,0x06,0xd9,0x10,0x03,0x1f,0x44,0x19,0x43,0xc3,0x40,0xc4,0x2c,0x19,0x58,0x08,0x29,0xa0,0x60,0x0c,0xf2,0x00,0x27,0x02,0x05,0x20,0x06,0x4d,0x02,0x0b,0xc0,0x02,0x08,0x3c,0x80,0x09,0xa0,0x39,0x0a,0xd4,0x41,0x8f,0x50,0x05,0x09,0xa4,0x5b,0x4d,0x00,0xd8,0x23,0xc4,0x96,0x20,0xc7,0xac,0x40,0x2d,0x53,0x00,0x64,0x6b,0x20,0x1d,0x4a,0x08,0x32,0x2a,0x90,0x0d,0x46,0x0e,0x02,0x0c,0x79,0x51,0x08,0x61,0xf0,0x20,0x63,0xc5,0x4b,0x83,0x1e,0xfe,0x57,0xd3,0x51,0x40,0xbe,0xc0,0x08,0x42,0x00,0x53,0x30,0xe8,0x3f,0x50,0x14,0x73,0x80,0x0b,0xeb,0x07,0x61,0x40,0x00,0x7d,0x5f,0xf8,0x38,0x32,0x7a,0x03,0xf7,0x55,0xa6,0x78,0x19,0x54,0x0c,0xa8,0x32,0xa0,0x19,0xa0,0x65,0xc4,0x0b,0xe2,0x00,0x98,0x40,0x33,0xc1,0x92,0xfa,0x10,0x67,0x80,0x08,}; -const uint8_t* const _I_RFIDDolphinSend_97x61[] = {_I_RFIDDolphinSend_97x61_0}; - -const uint8_t _I_RFIDDolphinSuccess_108x57_0[] = {0x01,0x00,0xe7,0x01,0x00,0x0f,0x03,0xff,0x1f,0x06,0xd4,0xe2,0x01,0xe0,0x06,0xd4,0x18,0x04,0x30,0x30,0x64,0x60,0x20,0x20,0x31,0x86,0x03,0x62,0x80,0x03,0x28,0x80,0x36,0x24,0x00,0x36,0x00,0x28,0x5c,0xc3,0xe6,0x00,0x58,0x40,0xec,0xc1,0xb1,0x04,0x02,0x19,0x24,0x80,0x0b,0x02,0x02,0x40,0x37,0xc4,0x8c,0x2e,0x40,0x6f,0x93,0x8b,0x81,0x07,0x06,0xdc,0xc2,0x38,0x66,0x50,0x6a,0xe2,0x27,0xe0,0xd2,0xfc,0x08,0x09,0x0c,0x9c,0x4b,0x98,0x34,0xa0,0xe1,0xd5,0x06,0x8f,0x92,0xc2,0x05,0x1e,0x42,0xe1,0x81,0xa3,0xe2,0xf0,0xbc,0x4c,0x1a,0xff,0x2f,0x9b,0x80,0xd8,0xca,0x05,0x1f,0x97,0xfd,0xf8,0x60,0xd2,0x01,0x1e,0x00,0x1a,0x5c,0x00,0x08,0xc9,0xc1,0xab,0x40,0xf9,0x83,0x46,0x61,0x00,0xd8,0x4a,0x81,0xab,0xa0,0xf3,0x5f,0xc6,0x05,0x58,0x8a,0xa4,0x09,0x76,0x21,0xb1,0xf2,0x83,0x4f,0x5d,0x1a,0x01,0x8c,0x90,0x1a,0x31,0x0d,0x07,0xa9,0x16,0x50,0x0a,0xac,0x34,0xba,0x42,0xa1,0x88,0x50,0x23,0xaa,0x72,0xe0,0x6a,0xa1,0x4a,0x32,0x39,0x88,0x6c,0x60,0xc7,0x82,0xb0,0x55,0x60,0xa2,0x92,0x80,0xc0,0x43,0x63,0x03,0x25,0x96,0xe3,0x54,0x33,0x18,0xc4,0x90,0x22,0x21,0x81,0x81,0x03,0x4a,0xa9,0x55,0x7a,0x17,0xf3,0x82,0x9f,0x6d,0x5e,0xa9,0xb6,0x50,0x38,0x70,0x35,0x70,0x15,0x5a,0xa9,0xb8,0xa3,0x46,0x12,0x06,0x9f,0x83,0x54,0x8a,0x28,0x80,0x34,0xfc,0x08,0x93,0xaa,0xc7,0x40,0x83,0x83,0x81,0xd3,0xa1,0xd1,0x08,0x84,0x0c,0x24,0x3f,0xed,0x54,0x18,0x26,0x50,0x20,0xd9,0x42,0x21,0x90,0x4c,0x07,0xff,0xae,0x52,0x20,0x6a,0xc4,0x23,0x1f,0x88,0x3f,0xf0,0x1a,0x45,0x31,0xe7,0x03,0x4a,0x41,0xe0,0x69,0x0f,0xc2,0x1e,0x0d,0x19,0x80,0x48,0xa2,0x10,0xc5,0x68,0xdf,0x0a,0x82,0xb9,0x28,0x22,0x2c,0xe3,0x0a,0xd1,0x2b,0x0f,0x00,0x3c,0x22,0x91,0x53,0x9c,0x50,0x1a,0x30,0x08,0x39,0x1c,0x60,0x6d,0x12,0x3d,0x8c,0xc2,0x51,0x00,0x17,0x0c,0xe2,0x01,0xff,0x83,0x84,0xc6,0x40,0xb0,0x19,0x84,0xd0,0x1a,0x5c,0x08,0x1f,0xf8,0x8c,0x50,0x43,0x08,0xce,0x2d,0x06,0x71,0x5f,0x17,0xfe,0x12,0xdf,0x20,0x69,0x55,0x01,0xa6,0x00,0x18,0x40,0xa4,0x80,0x63,0x3c,0xb5,0x03,0x56,0x08,0x8b,0x20,0x10,0xcf,0x03,0x62,0x08,0x20,0x00,0x94,0xc6,0x01,0x70,0x01,0x0c,0xe8,0x36,0x20,0xd3,0xe0,0x00,0xcb,0x10,0x02,0x19,0xf3,0x9c,0x41,0xa3,0x15,0x31,0x90,0x00,0x70,0xc0,0x21,0xdd,0x86,0xc4,0x78,0x3e,0xa3,0x71,0xe0,0x30,0x20,0x31,0xbe,0x86,0xc4,0x1a,0x35,0x40,0x20,0x8d,0x89,0x28,0x5b,0xa0,0xd9,0xea,0x3d,0x44,0x42,0x87,0x83,0x48,0x36,0x49,0xe1,0xa0,0x75,0x67,0x8d,0x41,0x54,0x14,0x03,0xf5,0x2a,0x06,0x96,0x03,0x54,0xc4,0x14,0xd0,0x83,0x4a,0xfb,0x35,0x06,0x90,0x38,0x4e,0x46,0xb4,0x10,0xd9,0x81,0x49,0x72,0x40,0x01,0x0a,0x95,0xd4,0x36,0x20,0xd7,0x55,0x10,}; -const uint8_t* const _I_RFIDDolphinSuccess_108x57[] = {_I_RFIDDolphinSuccess_108x57_0}; - -const uint8_t _I_SDQuestion_35x43_0[] = {0x01,0x00,0x67,0x00,0xf8,0x7f,0xc0,0x03,0x03,0xfc,0x01,0x0a,0x0f,0x38,0xa4,0xe4,0xa4,0x80,0x4f,0x0c,0x20,0x13,0xc0,0x9f,0x80,0x02,0x15,0xfe,0x00,0x04,0x29,0xfc,0x03,0xfd,0x07,0xfa,0x47,0xe7,0xdf,0xc8,0x3f,0xea,0x1f,0x7f,0xfc,0x41,0xff,0xb8,0xff,0xf8,0x10,0x7f,0xe0,0x4e,0xef,0x86,0x08,0x68,0x33,0xf1,0x10,0xff,0x3f,0xf1,0xf1,0x60,0x81,0x06,0x1e,0x36,0x10,0x20,0xe1,0xc0,0x87,0xc7,0x02,0x0f,0xd3,0xff,0xe3,0x02,0x0f,0xe8,0x08,0x7f,0xd0,0x21,0x89,0xc4,0x08,0x9f,0x70,0x21,0x9a,0x08,0x08,0xc1,0x89,0x02,0x20,0x62,0x40,0x8f,0xfe,0x68,0x98,}; -const uint8_t* const _I_SDQuestion_35x43[] = {_I_SDQuestion_35x43_0}; - -const uint8_t _I_Cry_dolph_55x52_0[] = {0x01,0x00,0xe8,0x00,0x00,0x0f,0xe3,0xff,0x01,0x03,0x1f,0xfb,0xff,0x0f,0x02,0x96,0x02,0x0f,0x00,0x9f,0x01,0x8b,0xc0,0x12,0x1f,0x80,0x18,0xae,0x00,0x21,0xe0,0x07,0x0a,0x30,0x0a,0x28,0x18,0x08,0x61,0x80,0x62,0x83,0x00,0x90,0x14,0x61,0x02,0x0c,0x16,0x00,0x76,0x60,0x66,0x98,0x0b,0x04,0x90,0x60,0x66,0xb0,0x00,0x48,0x0d,0x21,0x21,0x03,0x30,0x74,0x40,0xd3,0x80,0x03,0x34,0x04,0xc0,0x52,0x00,0x32,0xc7,0xa0,0x18,0x80,0x31,0x80,0x07,0xe1,0x01,0x37,0x18,0x50,0x80,0xc2,0x92,0x10,0x31,0xe8,0x23,0xe9,0x63,0x86,0x54,0x3f,0xe0,0xe1,0x0d,0x96,0x83,0xfc,0x06,0x40,0x69,0x6c,0x3c,0x60,0xd2,0xfc,0xc0,0x60,0x58,0x48,0x0c,0x1b,0x81,0x08,0x14,0x9c,0x1a,0x81,0x04,0x03,0x46,0x80,0x0c,0x50,0x26,0x21,0xc1,0x94,0x26,0x14,0x27,0x8a,0x40,0xc0,0xc2,0xe7,0x26,0x40,0x81,0x86,0xc0,0x6b,0x28,0x64,0x0f,0x01,0x10,0x4e,0x14,0x60,0x0c,0x29,0x02,0x48,0x8b,0x5c,0x45,0x22,0x01,0x10,0x31,0x3a,0x4c,0x0c,0x34,0x06,0xf1,0xd8,0x00,0xc5,0x1a,0x64,0x94,0x0c,0xc0,0x37,0x52,0x20,0x81,0x84,0x26,0x3e,0x88,0x0c,0x38,0x28,0x54,0x0e,0xac,0x1f,0xe1,0x3f,0x06,0x96,0x82,0x7e,0x29,0x4a,0xaf,0xfd,0x76,0x30,0x3a,0x41,0x14,0x7f,0xd0,0xf8,0x78,0x18,0xaa,0x9f,0xd4,0xe0,0x83,0x4f,0xf5,0xf7,0x38,0x0b,0x9c,0x6a,0x1f,0x5b,0x5c,0x00,}; -const uint8_t* const _I_Cry_dolph_55x52[] = {_I_Cry_dolph_55x52_0}; - -const uint8_t _I_Attention_5x8_0[] = {0x00,0x0E,0x0A,0x0A,0x0A,0x0E,0x04,0x00,0x0E,}; -const uint8_t* const _I_Attention_5x8[] = {_I_Attention_5x8_0}; - -const uint8_t _I_Background_128x11_0[] = {0x01,0x00,0x70,0x00,0xff,0x40,0x40,0xc9,0xe0,0xff,0x80,0x06,0x1e,0x08,0x38,0x0c,0x0c,0x1e,0x93,0x00,0x19,0x46,0x01,0x07,0x7d,0x83,0x03,0xd2,0x31,0xff,0xdb,0xd5,0x66,0x20,0x83,0xc0,0xff,0x05,0x24,0x00,0x1c,0x78,0x28,0xbc,0x40,0x72,0xbf,0xcf,0x47,0xeb,0x40,0xdb,0x7a,0xbf,0xf0,0x40,0x39,0x60,0x28,0x3f,0xe0,0xa0,0xea,0x80,0x63,0x3f,0x0b,0x17,0xe4,0x3e,0x5a,0xbc,0xf9,0x99,0x70,0x1f,0x81,0x50,0xc0,0x80,0xe7,0x3e,0x1e,0x9d,0x57,0xfb,0x7f,0x23,0x15,0xb0,0x12,0x5b,0x5b,0x02,0x1d,0x8c,0xc3,0x80,0x24,0x9e,0x03,0x80,0x5e,0x40,0x00,0xa1,0x88,0x0e,0x98,0x00,0x7b,0x07,0x08,0xb2,0x44,0x41,}; -const uint8_t* const _I_Background_128x11[] = {_I_Background_128x11_0}; - -const uint8_t _I_BadUsb_9x8_0[] = {0x00,0x01,0x01,0xBB,0x01,0xFE,0x00,0xFE,0x00,0xD6,0x00,0xD6,0x00,0x7C,0x00,0x38,0x00,}; -const uint8_t* const _I_BadUsb_9x8[] = {_I_BadUsb_9x8_0}; - -const uint8_t _I_Battery_19x8_0[] = {0x01,0x00,0x0f,0x00,0xff,0x7f,0xe0,0x30,0x18,0x04,0x08,0x04,0x90,0x60,0x12,0x02,0xcc,0x28,0x40,}; -const uint8_t* const _I_Battery_19x8[] = {_I_Battery_19x8_0}; - -const uint8_t _I_Battery_26x8_0[] = {0x01,0x00,0x13,0x00,0xff,0x7f,0xef,0xf0,0x08,0x0c,0x03,0x00,0x03,0x38,0x18,0x0c,0xa0,0x40,0x36,0x05,0x98,0x6d,0x00,}; -const uint8_t* const _I_Battery_26x8[] = {_I_Battery_26x8_0}; - -const uint8_t _I_Bluetooth_Connected_16x8_0[] = {0x00,0x04,0x00,0x0D,0x00,0x16,0x60,0x4C,0x97,0x4C,0x97,0x16,0x60,0x0D,0x00,0x04,0x00,}; -const uint8_t* const _I_Bluetooth_Connected_16x8[] = {_I_Bluetooth_Connected_16x8_0}; - -const uint8_t _I_Bluetooth_Idle_5x8_0[] = {0x00,0x04,0x0D,0x16,0x0C,0x0C,0x16,0x0D,0x04,}; -const uint8_t* const _I_Bluetooth_Idle_5x8[] = {_I_Bluetooth_Idle_5x8_0}; - -const uint8_t _I_Charging_lightning_9x10_0[] = {0x00,0x40,0x01,0xA0,0x00,0x50,0x00,0xE8,0x01,0x84,0x00,0x42,0x00,0x2F,0x00,0x14,0x00,0x0A,0x00,0x05,0x00,}; -const uint8_t* const _I_Charging_lightning_9x10[] = {_I_Charging_lightning_9x10_0}; - -const uint8_t _I_Charging_lightning_mask_9x10_0[] = {0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x10,0x00,0x78,0x00,0x3C,0x00,0x10,0x00,0x08,0x00,0x04,0x00,0x02,0x00,}; -const uint8_t* const _I_Charging_lightning_mask_9x10[] = {_I_Charging_lightning_mask_9x10_0}; - -const uint8_t _I_Lock_8x8_0[] = {0x00,0x3C,0x42,0x42,0xFF,0xFF,0xE7,0xFF,0xFF,}; -const uint8_t* const _I_Lock_8x8[] = {_I_Lock_8x8_0}; - -const uint8_t _I_PlaceholderL_11x13_0[] = {0x01,0x00,0x10,0x00,0xfe,0x40,0x60,0x50,0x28,0x0c,0x10,0x03,0xb0,0x38,0x37,0xfe,0x07,0xfe,0x80,0x80,}; -const uint8_t* const _I_PlaceholderL_11x13[] = {_I_PlaceholderL_11x13_0}; - -const uint8_t _I_PlaceholderR_30x13_0[] = {0x01,0x00,0x19,0x00,0xfe,0x7f,0xff,0xf0,0xf8,0x10,0x18,0x62,0x10,0x10,0x18,0xc8,0x00,0x7e,0x03,0xb8,0x18,0x0c,0x66,0x1f,0xe1,0x58,0xc7,0xc5,0xe6,}; -const uint8_t* const _I_PlaceholderR_30x13[] = {_I_PlaceholderR_30x13_0}; - -const uint8_t _I_SDcardFail_11x8_0[] = {0x00,0xFF,0x07,0xB7,0x07,0xFF,0x07,0x87,0x07,0x7B,0x07,0xFF,0x07,0xFF,0x07,0x67,0x00,}; -const uint8_t* const _I_SDcardFail_11x8[] = {_I_SDcardFail_11x8_0}; - -const uint8_t _I_SDcardMounted_11x8_0[] = {0x01,0x00,0x09,0x00,0xff,0xc1,0xff,0xf0,0x40,0x1c,0xd9,0xe0,0x00,}; -const uint8_t* const _I_SDcardMounted_11x8[] = {_I_SDcardMounted_11x8_0}; - -const uint8_t _I_Lock_7x8_0[] = {0x00,0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; -const uint8_t* const _I_Lock_7x8[] = {_I_Lock_7x8_0}; - -const uint8_t _I_MHz_25x11_0[] = {0x01,0x00,0x21,0x00,0xe1,0xe1,0xa0,0x30,0x0f,0x38,0x0c,0xbf,0xe0,0x34,0xfe,0xc0,0x7b,0x7f,0xe0,0x19,0xf0,0x60,0x1d,0xbc,0x35,0x84,0x36,0x53,0x10,0x19,0x46,0x40,0x64,0x13,0x10,0x19,0x80,}; -const uint8_t* const _I_MHz_25x11[] = {_I_MHz_25x11_0}; - -const uint8_t _I_Quest_7x8_0[] = {0x00,0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,}; -const uint8_t* const _I_Quest_7x8[] = {_I_Quest_7x8_0}; - -const uint8_t _I_Scanning_123x52_0[] = {0x01,0x00,0xd3,0x01,0x00,0x78,0x03,0xc0,0x1f,0x00,0xe0,0x7f,0xc1,0xfb,0xf0,0x80,0x41,0xc0,0xc7,0x03,0x07,0xbe,0xb2,0x07,0x18,0x07,0xc4,0x40,0x06,0x55,0x68,0x2d,0x80,0x0a,0x58,0x08,0x10,0x3c,0xe1,0x00,0x32,0xc0,0xc2,0xb0,0x00,0xf8,0x82,0x02,0x0a,0x01,0x15,0x80,0x40,0x40,0xc3,0x40,0x07,0xa0,0x10,0xa8,0x10,0x09,0xc0,0x19,0x01,0xe9,0x82,0x01,0x0c,0x82,0x01,0x74,0x13,0x1d,0x03,0x04,0x24,0x28,0x05,0x04,0x1e,0x76,0x80,0x79,0xc8,0x30,0x50,0x28,0x30,0x14,0x64,0x26,0x23,0xe8,0x78,0x21,0xe0,0xf4,0x85,0x43,0x30,0x12,0x03,0x00,0x83,0xc7,0x41,0x1c,0x3b,0x10,0x3c,0xe2,0x98,0x08,0x80,0xa4,0x61,0x1e,0x0e,0x9c,0x0c,0x1e,0x51,0x00,0x7a,0x95,0x46,0x11,0x90,0xd3,0xd0,0x24,0x80,0xfb,0xe4,0x5f,0xf0,0x92,0x80,0x79,0x61,0x01,0xe3,0xff,0x07,0x9e,0x22,0xcf,0x3e,0xc4,0x03,0xd3,0xf5,0xff,0x07,0xa5,0x12,0xc9,0x2e,0x07,0xa7,0xf3,0x5f,0xff,0x8a,0x93,0xce,0x89,0xe4,0x97,0xe2,0x25,0x40,0xf1,0x8c,0x75,0x3b,0xf1,0xf1,0xf8,0x9b,0xc8,0x1e,0x55,0x0f,0xfc,0x03,0xfd,0x1f,0xf6,0x4f,0xc9,0xe2,0x8f,0x3a,0x27,0x12,0x5f,0xea,0x68,0x0c,0x06,0x35,0xfc,0x2f,0x92,0xbc,0xf0,0x98,0x89,0x7c,0x75,0x8e,0x37,0xd8,0xf1,0x7c,0xa3,0x0c,0xf3,0xc3,0x47,0xf8,0xcb,0x81,0xc2,0x5f,0x62,0xc0,0xf2,0x77,0xa5,0x1b,0xeb,0xc3,0x6c,0x8d,0x12,0x03,0x22,0x07,0x8c,0x30,0x18,0x2d,0x82,0xc3,0xc2,0xaf,0x84,0x42,0x81,0xc8,0xb1,0x01,0xb2,0x4e,0x08,0x08,0x68,0xb0,0x50,0x20,0xdf,0xb4,0x90,0x3a,0x10,0x3d,0x19,0x05,0x86,0x1e,0x8f,0x03,0x03,0xa5,0x83,0xd0,0xa1,0x10,0x30,0x79,0x00,0x0a,0x0a,0x02,0x19,0x84,0x03,0xa5,0xff,0xc0,0x8a,0x88,0x00,0x81,0xe1,0x80,0x12,0x07,0xa5,0x1f,0xc0,0x03,0xde,0x0b,0x80,0x80,0x0a,0x47,0xa3,0x1f,0x80,0x42,0x43,0xf1,0xe1,0x80,0x60,0x3d,0x30,0xf8,0x04,0x48,0x3e,0xf0,0x08,0xf1,0x40,0x7d,0x00,0xf1,0x56,0x08,0xfe,0x20,0x17,0x0f,0x70,0x3c,0x55,0x82,0x00,0x58,0x38,0x0c,0xa7,0x9f,0x90,0x78,0x80,0x1c,0xec,0x5a,0xac,0xff,0xc0,0x1f,0x30,0x1a,0x05,0x57,0xfb,0x5f,0xf8,0x45,0xc3,0xf3,0x80,0xf5,0x7f,0xe7,0xfe,0x00,0x7c,0x87,0xc7,0xab,0xff,0x8f,0x83,0xea,0x05,0x80,0xd5,0x7f,0xe1,0xfe,0x08,0x98,0x7e,0x60,0x15,0x5a,0xac,0x0f,0xe1,0x15,0x0f,0xc9,0x78,0x75,0x50,0x0d,0x84,0x28,0x3f,0x55,0x4b,0xac,0x02,0xb1,0x0d,0x0f,0xd6,0xa0,0xf8,0x3a,0x85,0x29,0xaf,0xde,0xf8,0x04,0x1a,0xe2,0x54,0x83,0xf0,0x00,0x2d,0x70,0xd4,0x43,0xf2,0x00,0x2e,0xb8,0x3a,0x20,0x05,0x93,0xc0,0x5e,0xc1,0xf2,0x79,0x3e,0x04,0x7c,0x1f,0x32,0xa0,0x19,0x7c,0x1e,0x86,0x00,0x6a,0xa8,0x0c,0xbf,0x84,0xe9,0x4e,0x88,0x0c,0x85,0xd5,0x00,}; -const uint8_t* const _I_Scanning_123x52[] = {_I_Scanning_123x52_0}; - -const uint8_t _I_Unlock_7x8_0[] = {0x00,0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; -const uint8_t* const _I_Unlock_7x8[] = {_I_Unlock_7x8_0}; - -const uint8_t _I_Auth_62x31_0[] = {0x01,0x00,0xaf,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x02,0x1b,0x04,0x02,0x40,0x04,0x10,0x11,0x01,0xc4,0x18,0x40,0x72,0xf0,0x40,0x40,0xe4,0x1a,0x20,0x38,0xc2,0x3e,0x00,0x71,0xbc,0x05,0xca,0x11,0x08,0x80,0xe0,0x30,0xc0,0x72,0x82,0x7d,0x20,0x44,0x81,0x80,0x81,0xcb,0x75,0x05,0x02,0x08,0x1c,0xe7,0x50,0x58,0xc0,0x94,0x40,0xe5,0xfa,0x82,0xc1,0xbf,0x06,0xc1,0x80,0x40,0x80,0xe3,0x00,0xbe,0x40,0x3f,0x10,0x18,0x17,0xd0,0xd0,0x33,0xf3,0xa0,0xc0,0xe0,0x52,0x88,0x26,0x02,0x3e,0x1d,0x18,0x14,0x08,0xa0,0x3c,0x08,0x78,0x3c,0xc0,0xe3,0xe0,0x83,0x87,0xcd,0x32,0x42,0x11,0x17,0x90,0x04,0x61,0x9f,0xf8,0x06,0x20,0x0e,0x41,0xb1,0x9e,0x1b,0x44,0x2e,0x5f,0x0f,0xfc,0x0c,0x0e,0x80,0x02,0x80,0xc1,0x00,0xe8,0xab,0x11,0xf9,0x01,0xca,0xe0,0x07,0x68,0x60,0xb4,0x40,0xe7,0xfe,0x1f,0x88,0x1d,0x09,0x82,0x28,0x10,0xba,0x01,0xcc,}; -const uint8_t* const _I_Auth_62x31[] = {_I_Auth_62x31_0}; - -const uint8_t _I_Connect_me_62x31_0[] = {0x01,0x00,0xb7,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x02,0x1b,0xe4,0x02,0x40,0x04,0x10,0x11,0x51,0x01,0x86,0x07,0x2b,0x60,0x1c,0xc3,0x44,0x0f,0x18,0x47,0xc0,0x0e,0x37,0x80,0xf9,0x42,0x21,0x10,0x1c,0x06,0x1a,0x01,0x82,0x80,0x41,0x3e,0x90,0x22,0x40,0xc0,0x40,0xe5,0xba,0x82,0xd8,0x20,0x00,0x73,0x9d,0x41,0x63,0x1e,0x00,0x39,0xfe,0xa0,0xb0,0x6f,0xc0,0x7c,0xa0,0x40,0x71,0x16,0x90,0x1c,0xbe,0x86,0x81,0x9f,0x81,0xce,0x51,0x04,0xc0,0x47,0xe0,0x1f,0xe0,0x38,0x94,0x07,0x81,0x0f,0x80,0x4a,0x00,0xe7,0xe0,0x83,0x81,0xcd,0x32,0x42,0x11,0x03,0x9c,0x0a,0x19,0xff,0x80,0x4e,0x00,0xe5,0x0c,0x81,0xcf,0x20,0x21,0xc1,0x03,0x8f,0xc3,0xff,0x03,0x80,0x92,0x44,0x3e,0x40,0x01,0x80,0xc1,0x20,0x60,0x73,0x55,0x8c,0x0a,0x08,0x07,0x3b,0x80,0x1c,0x61,0x00,0x73,0x86,0x11,0x48,0x0e,0x5f,0xe1,0xf8,0xc3,0x00,0xe7,0xf8,0x6c,0x0c,0x42,0x40,0x17,0x30,0x38,0xcc,0x24,0x00,}; -const uint8_t* const _I_Connect_me_62x31[] = {_I_Connect_me_62x31_0}; - -const uint8_t _I_Connected_62x31_0[] = {0x01,0x00,0xaa,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x07,0x39,0x00,0x09,0x01,0x88,0x07,0x70,0xd1,0x09,0x0b,0xe0,0x07,0x1b,0xc0,0x1c,0xe1,0x10,0x1c,0x06,0x18,0x0e,0x50,0x4f,0xa4,0x08,0x90,0x24,0x92,0x82,0x6e,0xa0,0xb6,0x08,0x07,0x04,0x10,0x30,0x49,0xd4,0x16,0x31,0xe0,0xa0,0xfc,0x80,0xe3,0xfa,0x82,0xc1,0xbf,0x14,0x08,0x64,0x06,0x04,0x07,0x18,0x05,0xf2,0x81,0x04,0x81,0x40,0xbe,0x86,0x81,0x9f,0xe0,0x20,0x80,0x81,0x94,0x41,0x30,0x11,0xf0,0x39,0x94,0x07,0x81,0x0f,0x03,0xaf,0x82,0x0f,0x00,0x84,0x81,0xc5,0x32,0x42,0x11,0x98,0x89,0xc6,0x01,0x02,0x86,0x7f,0xc9,0x03,0x03,0x03,0x8c,0x32,0x07,0x3c,0x2c,0x08,0x3c,0xbe,0x1f,0xf8,0x18,0x1d,0x00,0x05,0x81,0x0e,0x08,0x1c,0xf0,0x0a,0xc1,0x03,0xa5,0xc0,0x0e,0xd0,0xc4,0xc8,0x81,0xcf,0xfd,0x03,0x03,0xaf,0xe2,0x02,0xb1,0x10,0xba,0x01,0xcc,}; -const uint8_t* const _I_Connected_62x31[] = {_I_Connected_62x31_0}; - -const uint8_t _I_Drive_112x35_0[] = {0x01,0x00,0x72,0x00,0xf0,0x7f,0xc0,0x0f,0x1f,0x06,0x94,0x40,0x2f,0x12,0x00,0x19,0x42,0x01,0xb1,0x40,0x01,0x94,0x10,0x1b,0x18,0x00,0x19,0x41,0x81,0xb9,0x07,0x06,0xc9,0x24,0x81,0xb4,0x02,0x20,0x6f,0x83,0x66,0x7c,0x0d,0xc9,0x10,0x6f,0xc1,0xbe,0x0d,0xf2,0x9f,0x83,0x7c,0x14,0x3f,0x8f,0xff,0xe4,0x1b,0x4c,0xe1,0xc4,0x83,0x6a,0x1f,0x00,0xc7,0x8d,0xfc,0xc3,0xe0,0xdf,0x06,0xfa,0xd7,0xc3,0x7e,0x99,0xf0,0x6d,0x7f,0xc0,0x02,0x0d,0xcb,0xf8,0x37,0x27,0xe3,0x7c,0x80,0x2a,0x84,0x00,0xf4,0x00,0x19,0x47,0xc1,0xb1,0x20,0x01,0x97,0xf8,0x92,0x40,0x05,0x0b,0x9f,0xf0,0x1b,0x03,0x33,0x7f,0x08,0x01,0xc9,0xe6,}; -const uint8_t* const _I_Drive_112x35[] = {_I_Drive_112x35_0}; - -const uint8_t _I_Error_62x31_0[] = {0x01,0x00,0x9e,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x07,0x39,0x00,0x09,0x01,0x88,0x07,0x70,0xd1,0x09,0x0b,0xe0,0x07,0x38,0x1c,0x62,0x11,0x08,0x80,0x8c,0x8a,0x0f,0x1c,0x82,0x7d,0x20,0x58,0x0b,0xe4,0x02,0x1d,0x0e,0x82,0x6e,0xa0,0xb8,0x0c,0x1c,0x02,0x39,0x07,0x82,0x4e,0xa0,0xb7,0x08,0x04,0x07,0x71,0x03,0x82,0x7e,0xa0,0xb0,0xe8,0x04,0x0b,0xe1,0x01,0x81,0x01,0xc6,0x01,0xc0,0x81,0xf8,0x01,0x42,0x27,0x18,0x04,0xc0,0x1e,0x63,0x71,0x3d,0x0c,0x08,0x3e,0x20,0xa1,0x22,0x94,0x08,0x5e,0x21,0x51,0x0f,0x08,0xbc,0x47,0xe2,0x07,0x29,0x81,0x40,0x49,0xe2,0x07,0x28,0x61,0x80,0x4b,0xe2,0x07,0x28,0x19,0xe0,0xc0,0xe2,0x0d,0x18,0xc0,0x1d,0x00,0x02,0xa8,0x30,0x39,0x2e,0x10,0x0e,0x5e,0x00,0x3b,0x7e,0x00,0xec,0x46,0x10,0x3f,0x80,0xc8,}; -const uint8_t* const _I_Error_62x31[] = {_I_Error_62x31_0}; - -const uint8_t _I_Updating_32x40_0[] = {0x01,0x00,0x56,0x00,0xc0,0x7f,0xc0,0x03,0xc0,0x01,0x97,0x82,0x07,0x00,0xe0,0x5c,0x00,0x65,0x38,0x01,0x94,0x70,0x06,0x50,0xe0,0x19,0x41,0xc0,0x65,0xff,0x01,0xb4,0x0c,0x02,0x7e,0x08,0x38,0x0c,0x7c,0xd6,0x70,0x18,0xfb,0xfe,0xfc,0x0c,0x18,0xc8,0x78,0x20,0x33,0x81,0x8f,0x8a,0x07,0x3e,0xbe,0x70,0x38,0x71,0xff,0xc7,0x0f,0xc7,0x0f,0xf8,0x71,0xc0,0x76,0x13,0x30,0xd9,0x88,0xcc,0x5f,0x03,0xb2,0x21,0xa1,0x2c,0xc0,0x26,0x82,0x10,0x1f,0x80,0xd1,0x24,0x40,0x04,}; -const uint8_t* const _I_Updating_32x40[] = {_I_Updating_32x40_0}; - -const uint8_t _I_DolphinMafia_115x62_0[] = {0x01,0x00,0x21,0x02,0x00,0x1e,0x02,0x06,0x0e,0xcb,0x04,0x10,0x1d,0x91,0x88,0x40,0x3b,0x20,0xc0,0xec,0xc0,0x40,0x62,0x03,0xac,0x80,0x03,0xb2,0x31,0x00,0x90,0x03,0xae,0x5e,0x0e,0xcf,0xc4,0x56,0x01,0x40,0x07,0x56,0xbe,0x14,0x0e,0x2f,0xf1,0x5e,0x2a,0xa1,0xd1,0xc0,0x7c,0x3f,0xf0,0x70,0x73,0x70,0x35,0x41,0xd1,0xc0,0x7f,0xff,0xf0,0xf0,0x73,0x50,0x03,0xa4,0x0d,0x10,0x74,0x07,0x46,0x55,0xe0,0x07,0x10,0xb1,0xc3,0xa3,0x55,0xfe,0x03,0x88,0x94,0xe1,0xd1,0xd5,0x03,0x4a,0x3e,0x59,0x9e,0xaf,0xfe,0xff,0x05,0x60,0x4e,0xab,0xf5,0xff,0x95,0xb4,0xa4,0x3a,0x3f,0xd0,0xe0,0xfa,0x20,0x20,0xf8,0xd5,0xff,0xb5,0xf0,0x0f,0x88,0x3a,0x6a,0xbf,0xf8,0xaf,0x82,0x6f,0x03,0x07,0x47,0xaf,0xff,0x0a,0xfe,0x5f,0xc1,0xd3,0xf6,0xbf,0xe0,0x7f,0xfe,0xf0,0x73,0x41,0x00,0x43,0xfa,0xd7,0xf8,0x27,0xfe,0xe0,0x73,0x40,0x80,0x43,0xfe,0xab,0xfe,0x21,0xfc,0xe5,0x9b,0x05,0x48,0xea,0x3f,0xc8,0xfa,0xc4,0x66,0x07,0x44,0x0e,0x8f,0x00,0xb0,0x2b,0x31,0x07,0x0f,0x00,0x1c,0x72,0x00,0x70,0xf8,0x37,0xe5,0x81,0xff,0x89,0x08,0xf2,0x71,0x80,0x20,0xfe,0x2b,0xf0,0x5f,0xc0,0x38,0xc8,0xa5,0x60,0xc3,0x00,0xc7,0xf9,0xaf,0x81,0x2d,0x04,0x34,0x40,0xe1,0x98,0x47,0x68,0x04,0x92,0xab,0xc0,0x7e,0xb7,0xf7,0x39,0x03,0x85,0x8e,0x24,0xf1,0xc0,0x7f,0xf5,0x78,0x0f,0x53,0xb4,0xbc,0x1f,0xb8,0x1a,0x0c,0x61,0xc5,0x82,0xab,0xc0,0x3e,0xa3,0xa2,0xfc,0x07,0x46,0x09,0x60,0x19,0x8f,0x80,0xec,0x38,0x08,0x52,0x6c,0xb8,0xdc,0x28,0x7c,0x10,0x2a,0x5f,0x0f,0xfc,0x5a,0x01,0x05,0x1a,0x8e,0x02,0x02,0x1d,0x1f,0x81,0xa8,0xbe,0x13,0xf8,0x52,0x2c,0x8c,0x62,0x77,0x42,0x11,0x40,0xe0,0xca,0x93,0x8e,0x03,0x8a,0x30,0x10,0x48,0x54,0x03,0x04,0xbb,0x2c,0x00,0x0c,0x64,0x80,0xe4,0x0e,0x88,0x38,0x7c,0x10,0x04,0x09,0x48,0x83,0xac,0x1b,0x18,0xf3,0x44,0xc1,0xca,0x1d,0x15,0x40,0x8e,0x05,0x02,0x20,0xe6,0x24,0x12,0x8c,0x8b,0x05,0x21,0x07,0x24,0x14,0x08,0x73,0x80,0x19,0x78,0x43,0xb2,0xff,0x15,0x30,0xc4,0x01,0x26,0x8f,0x14,0x61,0xa9,0x8a,0x09,0x10,0x02,0x12,0x1c,0x80,0x84,0xaf,0x10,0x71,0xaa,0xc4,0x00,0x3b,0x04,0xea,0x24,0x48,0x1c,0xbd,0x8f,0xf8,0x00,0x67,0xf0,0x09,0x40,0x20,0x61,0x00,0xe4,0xf6,0x07,0x4b,0xc1,0x1f,0x07,0x14,0x40,0x1c,0x9d,0x66,0x79,0x24,0xc6,0xa0,0x0e,0x32,0x51,0xfa,0xce,0xe7,0x50,0x07,0x1c,0x80,0x30,0x58,0x0e,0xa2,0xcc,0xa0,0x19,0x00,0x71,0x42,0x13,0x27,0x40,0xf5,0x45,0x41,0xc5,0x08,0xb0,0x80,0xc6,0x18,0xf2,0x28,0x04,0x83,0xe8,0x58,0x10,0x30,0xc2,0x2c,0x40,0x91,0x89,0x3c,0x88,0x62,0x21,0xd2,0xff,0x03,0x87,0xc8,0x12,0x19,0x08,0x39,0x3e,0x83,0xb2,0x4a,0x0e,0xa2,0x0d,0xc0,0xe0,0x50,0x06,0xa7,0xe8,0x2c,0x94,0xc2,0x09,0x50,0x8c,0xce,0x20,0x34,0x70,0x71,0x41,0x3e,0x85,0xe2,0xe0,0x41,0x38,0x1e,0x28,0x3c,0x19,0xc8,0x70,0x4f,0xc1,0xdc,0xe0,0x74,0x01,0xd8,0xc6,0x24,0x00,0x82,0x81,0x7c,0x12,0xa6,0x7e,0x10,0x28,0xd8,0x22,0x00,0xe3,0xfc,0x34,0x53,0x00,0x23,0x1c,0x04,0x44,0x0e,0x50,0x10,0xeb,0x17,0xca,0x1c,0x07,0x20,}; -const uint8_t* const _I_DolphinMafia_115x62[] = {_I_DolphinMafia_115x62_0}; - -const uint8_t _I_DolphinNice_96x59_0[] = {0x01,0x00,0x8a,0x01,0x00,0x37,0xfa,0x3e,0x0a,0x8f,0x04,0x04,0x02,0x20,0xb7,0x8c,0x00,0x86,0x1c,0x0b,0x78,0x20,0x08,0x66,0x00,0xb7,0x81,0x00,0x86,0x80,0x0b,0x71,0x61,0x60,0x01,0x4c,0x07,0x41,0xe3,0x07,0xd0,0x4e,0x40,0xb8,0x1f,0x90,0x00,0xe4,0x00,0xba,0x88,0x01,0x0e,0x10,0x0a,0x48,0xf9,0x6c,0xbe,0x10,0x70,0x82,0x78,0x3c,0x15,0x82,0x18,0xc2,0x21,0x00,0xb4,0x02,0x0e,0xbc,0x86,0x30,0x48,0x80,0xd1,0x05,0x03,0x78,0x82,0xc0,0x3e,0x52,0x32,0x63,0x70,0x20,0x70,0x09,0xd4,0x98,0xb0,0xf0,0x60,0x58,0xc9,0xce,0x12,0x0b,0xbf,0xd4,0x9d,0x28,0x9e,0x24,0xa9,0x82,0xda,0x24,0x2d,0x10,0x00,0xfd,0x2a,0x60,0xb4,0x85,0x4e,0x00,0x85,0xf8,0xd4,0x82,0xd2,0x09,0xc0,0x12,0x14,0x12,0xad,0x81,0x29,0xa8,0x90,0xf5,0x01,0x75,0x80,0x46,0x00,0xa5,0x50,0x0b,0x90,0x1c,0x41,0x63,0x60,0x05,0x96,0xc0,0x2e,0x52,0x44,0x79,0x60,0x06,0x05,0x50,0x05,0x94,0x89,0x88,0x63,0x02,0x98,0x02,0xc7,0xc1,0x21,0x6a,0x98,0xa0,0x62,0x11,0x00,0x58,0xc6,0x02,0xe2,0xb8,0x21,0x80,0xc3,0x05,0x02,0x38,0x11,0x78,0xa5,0x0b,0x01,0x81,0x5a,0x88,0x2c,0x60,0x40,0xb1,0xc0,0x27,0x0a,0xfc,0x0f,0x28,0x04,0x06,0x50,0x05,0x18,0xa9,0x94,0xc1,0x67,0x48,0x02,0x8c,0xb8,0x16,0xf8,0x80,0x28,0xd6,0x16,0x86,0x0b,0x38,0x40,0xd4,0x76,0x0c,0xd4,0x05,0x94,0x10,0x9a,0x34,0x01,0x82,0x1f,0x06,0x05,0x02,0x98,0x01,0x47,0x54,0x18,0x35,0xc8,0xff,0x20,0x3c,0x00,0x58,0xd5,0x6a,0xa0,0xb3,0x81,0xa3,0x0a,0x0f,0x80,0xd5,0xea,0x81,0x67,0x07,0x46,0x14,0xe3,0xe1,0x55,0x18,0x18,0x2c,0x51,0x85,0xc0,0xef,0x85,0x8c,0x0c,0x30,0xf4,0x61,0x40,0x2d,0x46,0xb4,0x05,0x8b,0x04,0xb0,0x15,0x40,0x5a,0x50,0x23,0xe6,0x01,0x02,0x8c,0xa8,0x2e,0xb1,0xe5,0x40,0x81,0x46,0x6a,0x17,0x59,0xeb,0xe4,0xa8,0x11,0xa0,0x5a,0x68,0x27,0x4e,0xd3,0x59,0xad,0x82,0xfa,0xed,0x2a,0x04,0x28,0x2e,0xb7,0xa7,0x69,0xc3,0x42,0xeb,0xf5,0x1f,0x09,0x4c,0x42,0xed,0xea,0x01,0x8c,0x06,0x41,0x05,0x0b,0xbc,0x02,0x0d,0x80,0x83,0x05,0xe2,0x11,0x40,0x0b,0xb7,0x14,0x06,0x33,0x0c,0x83,0x89,0x02,0xe3,0xca,0x3d,0x95,0x01,0xe2,0x21,0x74,0xc2,0x81,0x0b,0x0e,0x17,0x6c,0x10,0x10,0xaf,0x09,0xe2,0x0b,0xbb,0xd0,0x42,0xeb,0x02,}; -const uint8_t* const _I_DolphinNice_96x59[] = {_I_DolphinNice_96x59_0}; - -const uint8_t _I_DolphinWait_61x59_0[] = {0x01,0x00,0x56,0x01,0x00,0x17,0xfa,0x1e,0x06,0x4f,0x84,0x06,0xe0,0x07,0x48,0x64,0x03,0x01,0x01,0x03,0x9c,0x0c,0x04,0x30,0x60,0x31,0x70,0x00,0x65,0x08,0x01,0x94,0xc0,0x06,0x51,0x00,0x5b,0x48,0x00,0x65,0x04,0x01,0x95,0x00,0x82,0xd8,0x00,0x19,0x40,0x7e,0x00,0x75,0x1f,0x88,0xe0,0x88,0x02,0x1a,0x1f,0x94,0x14,0x0e,0xbf,0x98,0x58,0x5c,0x42,0x45,0x00,0x9e,0x99,0x87,0x01,0x02,0x11,0x94,0xf2,0x2e,0x03,0x18,0x39,0x28,0x70,0x1f,0xc0,0x3e,0x42,0x00,0xe5,0x80,0xff,0xdf,0xc0,0xe5,0xf8,0x85,0xd8,0x10,0x27,0x40,0xf9,0xc2,0x63,0x88,0x12,0x82,0x6a,0x20,0x50,0x41,0xe9,0x42,0x20,0x95,0x48,0x6e,0x0c,0xfa,0x9a,0xaf,0xf9,0x90,0xe2,0x10,0x2e,0xac,0xe0,0x0e,0x98,0x29,0x52,0x11,0x13,0x23,0x15,0x3e,0x20,0x3c,0x61,0x40,0x52,0xfc,0x4f,0xe2,0x10,0x38,0x68,0x1c,0xa0,0xfc,0x08,0xbe,0x04,0x1e,0x5e,0x01,0xb9,0x03,0xc5,0x60,0x24,0xf2,0x84,0x60,0x63,0x40,0x71,0x27,0x9c,0x0e,0x2b,0x04,0x6c,0xa4,0x06,0x15,0x08,0x6c,0x99,0x8c,0xa6,0x0f,0x81,0x00,0x0c,0x08,0xf0,0x3c,0x05,0x61,0xc0,0x40,0x86,0xd0,0x30,0x78,0x80,0x0c,0xc6,0x2b,0x92,0x00,0x0d,0x51,0xf0,0x2d,0x42,0x0a,0x8e,0xaa,0x34,0x0f,0x4a,0x85,0x55,0x6e,0x20,0xf3,0xd5,0x6a,0x84,0xa2,0x66,0x2a,0x05,0xf7,0xaa,0x07,0x18,0xaf,0xfb,0x7f,0xea,0xc1,0xef,0xc0,0xe3,0xea,0x80,0xf8,0x27,0xf0,0x0a,0xc0,0x1c,0x67,0xa2,0xd1,0xb1,0xc0,0x34,0x00,0x71,0x14,0x8f,0x00,0x98,0x34,0x02,0x69,0xd0,0x37,0x90,0x16,0xf1,0x00,0x06,0xe1,0x84,0x31,0x89,0x14,0xe9,0xdc,0x40,0x38,0xa4,0xc4,0x4c,0x3c,0x1f,0x88,0x8c,0x5b,0xc3,0x01,0xbc,0x40,0x3f,0xf0,0xf6,0x71,0x0c,0x0b,0xe0,0x07,0x3c,0x0a,0xf8,0xa3,0xf0,0x03,0xb8,0xd8,0x80,0xe8,0x87,0x1b,0xa8,0x1c,0x78,0x1f,0xf8,0x0e,0x7e,0x01,0x6a,0x03,0x94,0x0f,0xfd,0xa0,0x80,0x7d,0x49,0x04,0x4d,0x12,0xc0,0xfa,0x83,0x83,0xbe,0x26,0x8d,0x02,0x05,0xd5,0xff,0xff,0xeb,0xe9,0x31,0x90,0x40,0x80,}; -const uint8_t* const _I_DolphinWait_61x59[] = {_I_DolphinWait_61x59_0}; - -const uint8_t _I_iButtonDolphinVerySuccess_108x52_0[] = {0x01,0x00,0xc2,0x01,0x00,0x0f,0xe2,0xfe,0x0d,0xb8,0x3e,0x02,0x06,0x0c,0x9f,0x00,0x08,0x61,0x80,0xd9,0x8c,0x00,0x86,0x60,0x0d,0x98,0x30,0x08,0x6a,0x00,0xd9,0x80,0x80,0x87,0x40,0x0c,0x8c,0x00,0x0c,0xa8,0x01,0x12,0x00,0x2d,0x00,0x22,0x70,0x20,0x6b,0xc8,0x02,0x26,0x62,0x88,0x80,0x6c,0xc9,0x24,0x0d,0x9a,0x07,0x17,0xfe,0x1d,0x68,0x40,0x6c,0xe7,0x48,0x04,0x28,0x10,0x34,0xe8,0x10,0xd1,0x11,0xc4,0x01,0xa5,0x04,0x06,0x96,0xa0,0xa6,0x24,0xc2,0x88,0x17,0x88,0x1a,0x7d,0x43,0x78,0x82,0x4a,0x40,0x03,0x20,0xb0,0xff,0x20,0x16,0xa3,0xb2,0x48,0x03,0xe4,0x0d,0x1f,0xfc,0x06,0x3a,0x0d,0x4a,0x00,0x34,0xf8,0x00,0xd1,0x37,0x0f,0x82,0x9e,0x95,0x58,0x17,0x83,0xff,0x81,0x1b,0x0f,0xf1,0xfe,0x71,0xe0,0x69,0x7c,0x3f,0xe0,0x82,0xff,0xcf,0xc0,0x85,0x61,0x80,0x43,0xb0,0x5f,0xa8,0x79,0xdc,0x81,0xa5,0x70,0xc0,0x68,0x3c,0x10,0x1a,0x17,0xd5,0x28,0x42,0xd1,0x8f,0x84,0x46,0x83,0xb0,0x8e,0x40,0x34,0x5f,0xa8,0x38,0x34,0x45,0xa2,0x0d,0x18,0x04,0x9b,0x50,0x03,0x1a,0x14,0x35,0x36,0x5f,0x8f,0xf8,0xb8,0xa4,0x19,0x40,0x18,0xe8,0xa0,0xca,0x22,0xfe,0x7f,0xc4,0x05,0x20,0xa5,0x80,0xc6,0x82,0xcb,0x3f,0xf3,0x44,0xfc,0x12,0x40,0x18,0xe8,0x51,0x82,0x52,0x28,0xfc,0x38,0x0a,0x3e,0x48,0x98,0x6c,0x8f,0x43,0x00,0xe0,0x63,0xe0,0x62,0xe2,0x91,0x90,0x0a,0x02,0x0d,0x2f,0x82,0x50,0x41,0xa3,0x80,0x90,0x41,0x04,0xc3,0x01,0xc0,0x83,0x46,0x71,0x30,0x06,0x95,0x82,0x21,0x02,0x6e,0x88,0x6c,0x43,0x83,0x1f,0x2f,0x88,0x34,0x62,0x00,0xd1,0x15,0x08,0x2c,0x60,0xcc,0x51,0x0f,0x08,0xcc,0x81,0xa2,0x12,0x10,0x68,0xc6,0x3f,0x06,0xc2,0x06,0x8e,0x02,0x16,0x41,0x20,0x10,0xf8,0x01,0x85,0x00,0x19,0x0d,0x82,0x18,0x07,0x20,0x81,0x00,0x0c,0x9c,0x31,0x08,0x42,0x74,0x81,0xab,0x80,0x03,0x0c,0x32,0x11,0x0b,0x06,0xb9,0xc0,0x43,0xa3,0x10,0x8b,0x83,0x5c,0xe0,0x20,0x81,0xc8,0x26,0x49,0x4c,0x40,0x02,0x86,0x0a,0xc5,0x22,0x32,0x50,0x6b,0x93,0x86,0xc0,0x0d,0x19,0x18,0x35,0x8c,0x84,0x79,0x1a,0x84,0x84,0x1a,0xdf,0xc2,0xe0,0x8a,0xc7,0x51,0x22,0x06,0xb5,0x5e,0x3f,0x00,0x77,0x0d,0x60,0x36,0xfa,0xa9,0xd7,0x00,0x08,0x3a,0xc9,0x02,0x48,0xc0,0x05,0x54,0xba,0x98,0x8a,0xa8,0xf1,0x20,0x6a,0x6a,0x3d,0x43,0x61,0x80,0x4a,0x81,0xaf,0x40,0xea,0x8d,0x86,0x01,0x56,0x06,0x93,0x60,0x80,0x05,0xea,0x01,0x94,0xac,0x1b,0x11,0x80,0x19,0x45,0x41,0x44,0x0d,0x58,0x33,0x18,0xa1,0x4f,0xf3,0x06,0x1f,0x01,0x76,0x58,0x00,0xd9,0x83,0x52,0x7c,0x11,0x38,0x51,0x40,0x80,}; -const uint8_t* const _I_iButtonDolphinVerySuccess_108x52[] = {_I_iButtonDolphinVerySuccess_108x52_0}; - -const uint8_t _I_iButtonKey_49x44_0[] = {0x01,0x00,0xb4,0x00,0x00,0x24,0xfc,0x0a,0x9c,0x0e,0x00,0x19,0x26,0x18,0x00,0x32,0x43,0x20,0x10,0x10,0x31,0xc0,0x80,0xc9,0x80,0x02,0x08,0x18,0xec,0x00,0x21,0x03,0x1c,0x40,0x1e,0x22,0x15,0xa0,0x08,0x56,0x40,0x06,0x30,0xc0,0x85,0x84,0x86,0x40,0x21,0x84,0x10,0xcc,0x04,0x30,0x40,0x31,0x02,0x88,0x3a,0x20,0x01,0x83,0x0d,0x94,0x06,0x26,0x03,0xf8,0x43,0xc5,0xe9,0x0c,0x11,0x08,0xbc,0xe0,0x64,0x21,0x23,0x09,0x38,0x80,0x22,0x28,0x20,0x58,0x99,0xc4,0x50,0x41,0xe1,0xc0,0x60,0xcc,0xab,0x47,0x21,0xa6,0x02,0x9e,0x06,0x22,0x70,0xf0,0x00,0xcb,0x40,0x03,0x18,0xb0,0x78,0x14,0xe0,0x32,0x58,0x28,0xa5,0x84,0xd0,0x51,0x80,0xc9,0x30,0x06,0xae,0x62,0x84,0x06,0x48,0x64,0x88,0x0c,0x90,0x29,0x08,0x19,0x30,0x31,0x13,0x71,0xb8,0xc4,0xea,0x70,0x6b,0xc5,0x01,0x4a,0x7f,0xc8,0x7c,0x81,0x4a,0x77,0x8a,0xac,0x45,0x4a,0x7f,0x08,0x54,0x39,0x4a,0x7e,0x0e,0xa9,0xf0,0xcb,0xe3,0x7f,0x6e,0x22,0x5c,0x59,0x44,0x00,0x28,0x7a,0xd4,0x40,0x07,0xf0,0x02,0xa0,}; -const uint8_t* const _I_iButtonKey_49x44[] = {_I_iButtonKey_49x44_0}; - -const Icon I_Certification1_103x23 = {.width=103,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Certification1_103x23}; -const Icon I_Certification2_119x30 = {.width=119,.height=30,.frame_count=1,.frame_rate=0,.frames=_I_Certification2_119x30}; -const Icon A_Levelup1_128x64 = {.width=128,.height=64,.frame_count=11,.frame_rate=2,.frames=_A_Levelup1_128x64}; -const Icon A_Levelup2_128x64 = {.width=128,.height=64,.frame_count=11,.frame_rate=2,.frames=_A_Levelup2_128x64}; -const Icon I_125_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_125_10px}; -const Icon I_Nfc_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Nfc_10px}; -const Icon I_back_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_back_10px}; -const Icon I_badusb_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_badusb_10px}; -const Icon I_ble_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ble_10px}; -const Icon I_dir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_dir_10px}; -const Icon I_ibutt_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ibutt_10px}; -const Icon I_ir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ir_10px}; -const Icon I_loading_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_loading_10px}; -const Icon I_music_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_music_10px}; -const Icon I_sub1_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_sub1_10px}; -const Icon I_u2f_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_u2f_10px}; -const Icon I_unknown_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_unknown_10px}; -const Icon I_update_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_update_10px}; -const Icon I_BLE_Pairing_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_BLE_Pairing_128x64}; -const Icon I_Ble_connected_38x34 = {.width=38,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_Ble_connected_38x34}; -const Icon I_Ble_disconnected_24x34 = {.width=24,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_Ble_disconnected_24x34}; -const Icon I_Button_18x18 = {.width=18,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Button_18x18}; -const Icon I_Circles_47x47 = {.width=47,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_Circles_47x47}; -const Icon I_Ok_btn_9x9 = {.width=9,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_Ok_btn_9x9}; -const Icon I_Pressed_Button_13x13 = {.width=13,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Pressed_Button_13x13}; -const Icon I_Space_65x18 = {.width=65,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Space_65x18}; -const Icon I_Voldwn_6x6 = {.width=6,.height=6,.frame_count=1,.frame_rate=0,.frames=_I_Voldwn_6x6}; -const Icon I_Volup_8x6 = {.width=8,.height=6,.frame_count=1,.frame_rate=0,.frames=_I_Volup_8x6}; -const Icon I_Clock_18x18 = {.width=18,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Clock_18x18}; -const Icon I_Error_18x18 = {.width=18,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Error_18x18}; -const Icon I_EviSmile1_18x21 = {.width=18,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_EviSmile1_18x21}; -const Icon I_EviSmile2_18x21 = {.width=18,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_EviSmile2_18x21}; -const Icon I_EviWaiting1_18x21 = {.width=18,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_EviWaiting1_18x21}; -const Icon I_EviWaiting2_18x21 = {.width=18,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_EviWaiting2_18x21}; -const Icon I_Percent_10x14 = {.width=10,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_Percent_10x14}; -const Icon I_Smile_18x18 = {.width=18,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Smile_18x18}; -const Icon I_UsbTree_48x22 = {.width=48,.height=22,.frame_count=1,.frame_rate=0,.frames=_I_UsbTree_48x22}; -const Icon I_ButtonCenter_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonCenter_7x7}; -const Icon I_ButtonDown_7x4 = {.width=7,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_ButtonDown_7x4}; -const Icon I_ButtonLeftSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeftSmall_3x5}; -const Icon I_ButtonLeft_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeft_4x7}; -const Icon I_ButtonRightSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRightSmall_3x5}; -const Icon I_ButtonRight_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRight_4x7}; -const Icon I_ButtonUp_7x4 = {.width=7,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_ButtonUp_7x4}; -const Icon I_DFU_128x50 = {.width=128,.height=50,.frame_count=1,.frame_rate=0,.frames=_I_DFU_128x50}; -const Icon I_Warning_30x23 = {.width=30,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Warning_30x23}; -const Icon A_Loading_24 = {.width=24,.height=24,.frame_count=7,.frame_rate=5,.frames=_A_Loading_24}; -const Icon I_DolphinFirstStart0_70x53 = {.width=70,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart0_70x53}; -const Icon I_DolphinFirstStart1_59x53 = {.width=59,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart1_59x53}; -const Icon I_DolphinFirstStart2_59x51 = {.width=59,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart2_59x51}; -const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48}; -const Icon I_DolphinFirstStart4_67x53 = {.width=67,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart4_67x53}; -const Icon I_DolphinFirstStart5_54x49 = {.width=54,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart5_54x49}; -const Icon I_DolphinFirstStart6_58x54 = {.width=58,.height=54,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart6_58x54}; -const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; -const Icon I_DolphinFirstStart8_56x51 = {.width=56,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart8_56x51}; -const Icon I_DolphinOkay_41x43 = {.width=41,.height=43,.frame_count=1,.frame_rate=0,.frames=_I_DolphinOkay_41x43}; -const Icon I_ArrowDownEmpty_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowDownEmpty_14x15}; -const Icon I_ArrowDownFilled_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowDownFilled_14x15}; -const Icon I_ArrowUpEmpty_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowUpEmpty_14x15}; -const Icon I_ArrowUpFilled_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowUpFilled_14x15}; -const Icon I_DolphinReadingSuccess_59x63 = {.width=59,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinReadingSuccess_59x63}; -const Icon I_Down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_25x27}; -const Icon I_Down_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_hvr_25x27}; -const Icon I_InfraredArrowDown_4x8 = {.width=8,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_InfraredArrowDown_4x8}; -const Icon I_InfraredArrowUp_4x8 = {.width=8,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_InfraredArrowUp_4x8}; -const Icon I_InfraredLearnShort_128x31 = {.width=128,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_InfraredLearnShort_128x31}; -const Icon I_InfraredLearn_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_InfraredLearn_128x64}; -const Icon I_InfraredSendShort_128x34 = {.width=128,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_InfraredSendShort_128x34}; -const Icon I_InfraredSend_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_InfraredSend_128x64}; -const Icon I_Mute_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_25x27}; -const Icon I_Mute_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_hvr_25x27}; -const Icon I_Power_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_25x27}; -const Icon I_Power_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_hvr_25x27}; -const Icon I_Up_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Up_25x27}; -const Icon I_Up_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Up_hvr_25x27}; -const Icon I_Vol_down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_down_25x27}; -const Icon I_Vol_down_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_down_hvr_25x27}; -const Icon I_Vol_up_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_up_25x27}; -const Icon I_Vol_up_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_up_hvr_25x27}; -const Icon I_DoorLeft_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_70x55}; -const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; -const Icon I_DoorRight_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorRight_70x55}; -const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; -const Icon I_PassportLeft_6x47 = {.width=6,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_PassportLeft_6x47}; -const Icon I_WarningDolphin_45x42 = {.width=45,.height=42,.frame_count=1,.frame_rate=0,.frames=_I_WarningDolphin_45x42}; -const Icon I_KeyBackspaceSelected_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspaceSelected_16x9}; -const Icon I_KeyBackspace_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspace_16x9}; -const Icon I_KeySaveSelected_24x11 = {.width=24,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_KeySaveSelected_24x11}; -const Icon I_KeySave_24x11 = {.width=24,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_KeySave_24x11}; -const Icon A_125khz_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_125khz_14}; -const Icon A_BadUsb_14 = {.width=14,.height=14,.frame_count=11,.frame_rate=3,.frames=_A_BadUsb_14}; -const Icon A_Bluetooth_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Bluetooth_14}; -const Icon A_Debug_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_Debug_14}; -const Icon A_FileManager_14 = {.width=14,.height=14,.frame_count=10,.frame_rate=3,.frames=_A_FileManager_14}; -const Icon A_GPIO_14 = {.width=14,.height=14,.frame_count=8,.frame_rate=3,.frames=_A_GPIO_14}; -const Icon A_Games_14 = {.width=14,.height=14,.frame_count=9,.frame_rate=3,.frames=_A_Games_14}; -const Icon A_Infrared_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Infrared_14}; -const Icon A_NFC_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_NFC_14}; -const Icon A_Passport_14 = {.width=14,.height=14,.frame_count=10,.frame_rate=3,.frames=_A_Passport_14}; -const Icon A_Plugins_14 = {.width=14,.height=14,.frame_count=9,.frame_rate=3,.frames=_A_Plugins_14}; -const Icon A_Power_14 = {.width=14,.height=14,.frame_count=1,.frame_rate=3,.frames=_A_Power_14}; -const Icon A_Settings_14 = {.width=14,.height=14,.frame_count=10,.frame_rate=3,.frames=_A_Settings_14}; -const Icon A_Sub1ghz_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Sub1ghz_14}; -const Icon A_Tamagotchi_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Tamagotchi_14}; -const Icon A_U2F_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_U2F_14}; -const Icon A_iButton_14 = {.width=14,.height=14,.frame_count=7,.frame_rate=3,.frames=_A_iButton_14}; -const Icon I_Detailed_chip_17x13 = {.width=17,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Detailed_chip_17x13}; -const Icon I_Medium_chip_22x21 = {.width=22,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_Medium_chip_22x21}; -const Icon I_Pin_arrow_down_7x9 = {.width=7,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_Pin_arrow_down_7x9}; -const Icon I_Pin_arrow_left_9x7 = {.width=9,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_Pin_arrow_left_9x7}; -const Icon I_Pin_arrow_right_9x7 = {.width=9,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_Pin_arrow_right_9x7}; -const Icon I_Pin_arrow_up7x9 = {.width=7,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_Pin_arrow_up7x9}; -const Icon I_Pin_attention_dpad_29x29 = {.width=29,.height=29,.frame_count=1,.frame_rate=0,.frames=_I_Pin_attention_dpad_29x29}; -const Icon I_Pin_back_arrow_10x8 = {.width=10,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Pin_back_arrow_10x8}; -const Icon I_Pin_back_full_40x8 = {.width=40,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Pin_back_full_40x8}; -const Icon I_Pin_cell_13x13 = {.width=13,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Pin_cell_13x13}; -const Icon I_Pin_pointer_5x3 = {.width=5,.height=3,.frame_count=1,.frame_rate=0,.frames=_I_Pin_pointer_5x3}; -const Icon I_Pin_star_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_Pin_star_7x7}; -const Icon I_passport_bad1_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_bad1_46x49}; -const Icon I_passport_bad2_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_bad2_46x49}; -const Icon I_passport_bad3_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_bad3_46x49}; -const Icon I_passport_bottom_128x18 = {.width=128,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_passport_bottom_128x18}; -const Icon I_passport_happy1_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_happy1_46x49}; -const Icon I_passport_happy2_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_happy2_46x49}; -const Icon I_passport_happy3_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_happy3_46x49}; -const Icon I_passport_left_6x46 = {.width=6,.height=46,.frame_count=1,.frame_rate=0,.frames=_I_passport_left_6x46}; -const Icon I_passport_okay1_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_okay1_46x49}; -const Icon I_passport_okay2_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_okay2_46x49}; -const Icon I_passport_okay3_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_okay3_46x49}; -const Icon I_BatteryBody_52x28 = {.width=52,.height=28,.frame_count=1,.frame_rate=0,.frames=_I_BatteryBody_52x28}; -const Icon I_Battery_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Battery_16x16}; -const Icon I_FaceCharging_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceCharging_29x14}; -const Icon I_FaceConfused_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceConfused_29x14}; -const Icon I_FaceNopower_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceNopower_29x14}; -const Icon I_FaceNormal_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceNormal_29x14}; -const Icon I_Health_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Health_16x16}; -const Icon I_Temperature_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Temperature_16x16}; -const Icon I_Voltage_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Voltage_16x16}; -const Icon I_RFIDBigChip_37x36 = {.width=37,.height=36,.frame_count=1,.frame_rate=0,.frames=_I_RFIDBigChip_37x36}; -const Icon I_RFIDDolphinReceive_97x61 = {.width=97,.height=61,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinReceive_97x61}; -const Icon I_RFIDDolphinSend_97x61 = {.width=97,.height=61,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinSend_97x61}; -const Icon I_RFIDDolphinSuccess_108x57 = {.width=108,.height=57,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinSuccess_108x57}; -const Icon I_SDQuestion_35x43 = {.width=35,.height=43,.frame_count=1,.frame_rate=0,.frames=_I_SDQuestion_35x43}; -const Icon I_Cry_dolph_55x52 = {.width=55,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Cry_dolph_55x52}; -const Icon I_Attention_5x8 = {.width=5,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Attention_5x8}; -const Icon I_Background_128x11 = {.width=128,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_Background_128x11}; -const Icon I_BadUsb_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BadUsb_9x8}; -const Icon I_Battery_19x8 = {.width=19,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Battery_19x8}; -const Icon I_Battery_26x8 = {.width=26,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Battery_26x8}; -const Icon I_Bluetooth_Connected_16x8 = {.width=16,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Bluetooth_Connected_16x8}; -const Icon I_Bluetooth_Idle_5x8 = {.width=5,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Bluetooth_Idle_5x8}; -const Icon I_Charging_lightning_9x10 = {.width=9,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Charging_lightning_9x10}; -const Icon I_Charging_lightning_mask_9x10 = {.width=9,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Charging_lightning_mask_9x10}; -const Icon I_Lock_8x8 = {.width=8,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_8x8}; -const Icon I_PlaceholderL_11x13 = {.width=11,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderL_11x13}; -const Icon I_PlaceholderR_30x13 = {.width=30,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderR_30x13}; -const Icon I_SDcardFail_11x8 = {.width=11,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_SDcardFail_11x8}; -const Icon I_SDcardMounted_11x8 = {.width=11,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_SDcardMounted_11x8}; -const Icon I_Lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_7x8}; -const Icon I_MHz_25x11 = {.width=25,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_MHz_25x11}; -const Icon I_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8}; -const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52}; -const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8}; -const Icon I_Auth_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Auth_62x31}; -const Icon I_Connect_me_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Connect_me_62x31}; -const Icon I_Connected_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Connected_62x31}; -const Icon I_Drive_112x35 = {.width=112,.height=35,.frame_count=1,.frame_rate=0,.frames=_I_Drive_112x35}; -const Icon I_Error_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Error_62x31}; -const Icon I_Updating_32x40 = {.width=32,.height=40,.frame_count=1,.frame_rate=0,.frames=_I_Updating_32x40}; -const Icon I_DolphinMafia_115x62 = {.width=115,.height=62,.frame_count=1,.frame_rate=0,.frames=_I_DolphinMafia_115x62}; -const Icon I_DolphinNice_96x59 = {.width=96,.height=59,.frame_count=1,.frame_rate=0,.frames=_I_DolphinNice_96x59}; -const Icon I_DolphinWait_61x59 = {.width=61,.height=59,.frame_count=1,.frame_rate=0,.frames=_I_DolphinWait_61x59}; -const Icon I_iButtonDolphinVerySuccess_108x52 = {.width=108,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_iButtonDolphinVerySuccess_108x52}; -const Icon I_iButtonKey_49x44 = {.width=49,.height=44,.frame_count=1,.frame_rate=0,.frames=_I_iButtonKey_49x44}; - diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h deleted file mode 100644 index 45947880..00000000 --- a/assets/compiled/assets_icons.h +++ /dev/null @@ -1,178 +0,0 @@ -#pragma once -#include - -extern const Icon I_Certification1_103x23; -extern const Icon I_Certification2_119x30; -extern const Icon A_Levelup1_128x64; -extern const Icon A_Levelup2_128x64; -extern const Icon I_125_10px; -extern const Icon I_Nfc_10px; -extern const Icon I_back_10px; -extern const Icon I_badusb_10px; -extern const Icon I_ble_10px; -extern const Icon I_dir_10px; -extern const Icon I_ibutt_10px; -extern const Icon I_ir_10px; -extern const Icon I_loading_10px; -extern const Icon I_music_10px; -extern const Icon I_sub1_10px; -extern const Icon I_u2f_10px; -extern const Icon I_unknown_10px; -extern const Icon I_update_10px; -extern const Icon I_BLE_Pairing_128x64; -extern const Icon I_Ble_connected_38x34; -extern const Icon I_Ble_disconnected_24x34; -extern const Icon I_Button_18x18; -extern const Icon I_Circles_47x47; -extern const Icon I_Ok_btn_9x9; -extern const Icon I_Pressed_Button_13x13; -extern const Icon I_Space_65x18; -extern const Icon I_Voldwn_6x6; -extern const Icon I_Volup_8x6; -extern const Icon I_Clock_18x18; -extern const Icon I_Error_18x18; -extern const Icon I_EviSmile1_18x21; -extern const Icon I_EviSmile2_18x21; -extern const Icon I_EviWaiting1_18x21; -extern const Icon I_EviWaiting2_18x21; -extern const Icon I_Percent_10x14; -extern const Icon I_Smile_18x18; -extern const Icon I_UsbTree_48x22; -extern const Icon I_ButtonCenter_7x7; -extern const Icon I_ButtonDown_7x4; -extern const Icon I_ButtonLeftSmall_3x5; -extern const Icon I_ButtonLeft_4x7; -extern const Icon I_ButtonRightSmall_3x5; -extern const Icon I_ButtonRight_4x7; -extern const Icon I_ButtonUp_7x4; -extern const Icon I_DFU_128x50; -extern const Icon I_Warning_30x23; -extern const Icon A_Loading_24; -extern const Icon I_DolphinFirstStart0_70x53; -extern const Icon I_DolphinFirstStart1_59x53; -extern const Icon I_DolphinFirstStart2_59x51; -extern const Icon I_DolphinFirstStart3_57x48; -extern const Icon I_DolphinFirstStart4_67x53; -extern const Icon I_DolphinFirstStart5_54x49; -extern const Icon I_DolphinFirstStart6_58x54; -extern const Icon I_DolphinFirstStart7_61x51; -extern const Icon I_DolphinFirstStart8_56x51; -extern const Icon I_DolphinOkay_41x43; -extern const Icon I_ArrowDownEmpty_14x15; -extern const Icon I_ArrowDownFilled_14x15; -extern const Icon I_ArrowUpEmpty_14x15; -extern const Icon I_ArrowUpFilled_14x15; -extern const Icon I_DolphinReadingSuccess_59x63; -extern const Icon I_Down_25x27; -extern const Icon I_Down_hvr_25x27; -extern const Icon I_InfraredArrowDown_4x8; -extern const Icon I_InfraredArrowUp_4x8; -extern const Icon I_InfraredLearnShort_128x31; -extern const Icon I_InfraredLearn_128x64; -extern const Icon I_InfraredSendShort_128x34; -extern const Icon I_InfraredSend_128x64; -extern const Icon I_Mute_25x27; -extern const Icon I_Mute_hvr_25x27; -extern const Icon I_Power_25x27; -extern const Icon I_Power_hvr_25x27; -extern const Icon I_Up_25x27; -extern const Icon I_Up_hvr_25x27; -extern const Icon I_Vol_down_25x27; -extern const Icon I_Vol_down_hvr_25x27; -extern const Icon I_Vol_up_25x27; -extern const Icon I_Vol_up_hvr_25x27; -extern const Icon I_DoorLeft_70x55; -extern const Icon I_DoorLocked_10x56; -extern const Icon I_DoorRight_70x55; -extern const Icon I_PassportBottom_128x17; -extern const Icon I_PassportLeft_6x47; -extern const Icon I_WarningDolphin_45x42; -extern const Icon I_KeyBackspaceSelected_16x9; -extern const Icon I_KeyBackspace_16x9; -extern const Icon I_KeySaveSelected_24x11; -extern const Icon I_KeySave_24x11; -extern const Icon A_125khz_14; -extern const Icon A_BadUsb_14; -extern const Icon A_Bluetooth_14; -extern const Icon A_Debug_14; -extern const Icon A_FileManager_14; -extern const Icon A_GPIO_14; -extern const Icon A_Games_14; -extern const Icon A_Infrared_14; -extern const Icon A_NFC_14; -extern const Icon A_Passport_14; -extern const Icon A_Plugins_14; -extern const Icon A_Power_14; -extern const Icon A_Settings_14; -extern const Icon A_Sub1ghz_14; -extern const Icon A_Tamagotchi_14; -extern const Icon A_U2F_14; -extern const Icon A_iButton_14; -extern const Icon I_Detailed_chip_17x13; -extern const Icon I_Medium_chip_22x21; -extern const Icon I_Pin_arrow_down_7x9; -extern const Icon I_Pin_arrow_left_9x7; -extern const Icon I_Pin_arrow_right_9x7; -extern const Icon I_Pin_arrow_up7x9; -extern const Icon I_Pin_attention_dpad_29x29; -extern const Icon I_Pin_back_arrow_10x8; -extern const Icon I_Pin_back_full_40x8; -extern const Icon I_Pin_cell_13x13; -extern const Icon I_Pin_pointer_5x3; -extern const Icon I_Pin_star_7x7; -extern const Icon I_passport_bad1_46x49; -extern const Icon I_passport_bad2_46x49; -extern const Icon I_passport_bad3_46x49; -extern const Icon I_passport_bottom_128x18; -extern const Icon I_passport_happy1_46x49; -extern const Icon I_passport_happy2_46x49; -extern const Icon I_passport_happy3_46x49; -extern const Icon I_passport_left_6x46; -extern const Icon I_passport_okay1_46x49; -extern const Icon I_passport_okay2_46x49; -extern const Icon I_passport_okay3_46x49; -extern const Icon I_BatteryBody_52x28; -extern const Icon I_Battery_16x16; -extern const Icon I_FaceCharging_29x14; -extern const Icon I_FaceConfused_29x14; -extern const Icon I_FaceNopower_29x14; -extern const Icon I_FaceNormal_29x14; -extern const Icon I_Health_16x16; -extern const Icon I_Temperature_16x16; -extern const Icon I_Voltage_16x16; -extern const Icon I_RFIDBigChip_37x36; -extern const Icon I_RFIDDolphinReceive_97x61; -extern const Icon I_RFIDDolphinSend_97x61; -extern const Icon I_RFIDDolphinSuccess_108x57; -extern const Icon I_SDQuestion_35x43; -extern const Icon I_Cry_dolph_55x52; -extern const Icon I_Attention_5x8; -extern const Icon I_Background_128x11; -extern const Icon I_BadUsb_9x8; -extern const Icon I_Battery_19x8; -extern const Icon I_Battery_26x8; -extern const Icon I_Bluetooth_Connected_16x8; -extern const Icon I_Bluetooth_Idle_5x8; -extern const Icon I_Charging_lightning_9x10; -extern const Icon I_Charging_lightning_mask_9x10; -extern const Icon I_Lock_8x8; -extern const Icon I_PlaceholderL_11x13; -extern const Icon I_PlaceholderR_30x13; -extern const Icon I_SDcardFail_11x8; -extern const Icon I_SDcardMounted_11x8; -extern const Icon I_Lock_7x8; -extern const Icon I_MHz_25x11; -extern const Icon I_Quest_7x8; -extern const Icon I_Scanning_123x52; -extern const Icon I_Unlock_7x8; -extern const Icon I_Auth_62x31; -extern const Icon I_Connect_me_62x31; -extern const Icon I_Connected_62x31; -extern const Icon I_Drive_112x35; -extern const Icon I_Error_62x31; -extern const Icon I_Updating_32x40; -extern const Icon I_DolphinMafia_115x62; -extern const Icon I_DolphinNice_96x59; -extern const Icon I_DolphinWait_61x59; -extern const Icon I_iButtonDolphinVerySuccess_108x52; -extern const Icon I_iButtonKey_49x44; diff --git a/assets/compiled/flipper.pb.c b/assets/compiled/flipper.pb.c deleted file mode 100644 index 684ffe8c..00000000 --- a/assets/compiled/flipper.pb.c +++ /dev/null @@ -1,19 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5 */ - -#include "flipper.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(PB_Empty, PB_Empty, AUTO) - - -PB_BIND(PB_StopSession, PB_StopSession, AUTO) - - -PB_BIND(PB_Main, PB_Main, AUTO) - - - - diff --git a/assets/compiled/flipper.pb.h b/assets/compiled/flipper.pb.h deleted file mode 100644 index 3199090d..00000000 --- a/assets/compiled/flipper.pb.h +++ /dev/null @@ -1,302 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5 */ - -#ifndef PB_PB_FLIPPER_PB_H_INCLUDED -#define PB_PB_FLIPPER_PB_H_INCLUDED -#include -#include "storage.pb.h" -#include "system.pb.h" -#include "application.pb.h" -#include "gui.pb.h" - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Enum definitions */ -typedef enum _PB_CommandStatus { - PB_CommandStatus_OK = 0, - /* *< Common Errors */ - PB_CommandStatus_ERROR = 1, /* *< Unknown error */ - PB_CommandStatus_ERROR_DECODE = 2, /* *< Command can't be decoded successfully - command_id in response may be wrong! */ - PB_CommandStatus_ERROR_NOT_IMPLEMENTED = 3, /* *< Command succesfully decoded, but not implemented (deprecated or not yet implemented) */ - PB_CommandStatus_ERROR_BUSY = 4, /* *< Somebody took global lock, so not all commands are available */ - PB_CommandStatus_ERROR_CONTINUOUS_COMMAND_INTERRUPTED = 14, /* *< Not received has_next == 0 */ - PB_CommandStatus_ERROR_INVALID_PARAMETERS = 15, /* *< not provided (or provided invalid) crucial parameters to perform rpc */ - /* *< Storage Errors */ - PB_CommandStatus_ERROR_STORAGE_NOT_READY = 5, /* *< FS not ready */ - PB_CommandStatus_ERROR_STORAGE_EXIST = 6, /* *< File/Dir alrady exist */ - PB_CommandStatus_ERROR_STORAGE_NOT_EXIST = 7, /* *< File/Dir does not exist */ - PB_CommandStatus_ERROR_STORAGE_INVALID_PARAMETER = 8, /* *< Invalid API parameter */ - PB_CommandStatus_ERROR_STORAGE_DENIED = 9, /* *< Access denied */ - PB_CommandStatus_ERROR_STORAGE_INVALID_NAME = 10, /* *< Invalid name/path */ - PB_CommandStatus_ERROR_STORAGE_INTERNAL = 11, /* *< Internal error */ - PB_CommandStatus_ERROR_STORAGE_NOT_IMPLEMENTED = 12, /* *< Functon not implemented */ - PB_CommandStatus_ERROR_STORAGE_ALREADY_OPEN = 13, /* *< File/Dir already opened */ - PB_CommandStatus_ERROR_STORAGE_DIR_NOT_EMPTY = 18, /* *< Directory, you're going to remove is not empty */ - /* *< Application Errors */ - PB_CommandStatus_ERROR_APP_CANT_START = 16, /* *< Can't start app - internal error */ - PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED = 17, /* *< Another app is running */ - /* *< Virtual Display Errors */ - PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_ALREADY_STARTED = 19, /* *< Virtual Display session can't be started twice */ - PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED = 20 /* *< Virtual Display session can't be stopped when it's not started */ -} PB_CommandStatus; - -/* Struct definitions */ -/* There are Server commands (e.g. Storage_write), which have no body message - in response. But 'oneof' obligate to have at least 1 encoded message - in scope. For this needs Empty message is implemented. */ -typedef struct _PB_Empty { - char dummy_field; -} PB_Empty; - -typedef struct _PB_StopSession { - char dummy_field; -} PB_StopSession; - -typedef struct _PB_Main { - uint32_t command_id; - PB_CommandStatus command_status; - bool has_next; - pb_callback_t cb_content; - pb_size_t which_content; - union { - PB_Empty empty; - PB_System_PingRequest system_ping_request; - PB_System_PingResponse system_ping_response; - PB_Storage_ListRequest storage_list_request; - PB_Storage_ListResponse storage_list_response; - PB_Storage_ReadRequest storage_read_request; - PB_Storage_ReadResponse storage_read_response; - PB_Storage_WriteRequest storage_write_request; - PB_Storage_DeleteRequest storage_delete_request; - PB_Storage_MkdirRequest storage_mkdir_request; - PB_Storage_Md5sumRequest storage_md5sum_request; - PB_Storage_Md5sumResponse storage_md5sum_response; - PB_App_StartRequest app_start_request; - PB_App_LockStatusRequest app_lock_status_request; - PB_App_LockStatusResponse app_lock_status_response; - PB_StopSession stop_session; - PB_Gui_StartScreenStreamRequest gui_start_screen_stream_request; - PB_Gui_StopScreenStreamRequest gui_stop_screen_stream_request; - PB_Gui_ScreenFrame gui_screen_frame; - PB_Gui_SendInputEventRequest gui_send_input_event_request; - PB_Storage_StatRequest storage_stat_request; - PB_Storage_StatResponse storage_stat_response; - PB_Gui_StartVirtualDisplayRequest gui_start_virtual_display_request; - PB_Gui_StopVirtualDisplayRequest gui_stop_virtual_display_request; - PB_Storage_InfoRequest storage_info_request; - PB_Storage_InfoResponse storage_info_response; - PB_Storage_RenameRequest storage_rename_request; - PB_System_RebootRequest system_reboot_request; - PB_System_DeviceInfoRequest system_device_info_request; - PB_System_DeviceInfoResponse system_device_info_response; - PB_System_FactoryResetRequest system_factory_reset_request; - PB_System_GetDateTimeRequest system_get_datetime_request; - PB_System_GetDateTimeResponse system_get_datetime_response; - PB_System_SetDateTimeRequest system_set_datetime_request; - PB_System_PlayAudiovisualAlertRequest system_play_audiovisual_alert_request; - PB_System_ProtobufVersionRequest system_protobuf_version_request; - PB_System_ProtobufVersionResponse system_protobuf_version_response; - PB_System_UpdateRequest system_update_request; - PB_Storage_BackupCreateRequest storage_backup_create_request; - PB_Storage_BackupRestoreRequest storage_backup_restore_request; - PB_System_PowerInfoRequest system_power_info_request; - PB_System_PowerInfoResponse system_power_info_response; - PB_System_UpdateResponse system_update_response; - } content; -} PB_Main; - - -/* Helper constants for enums */ -#define _PB_CommandStatus_MIN PB_CommandStatus_OK -#define _PB_CommandStatus_MAX PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED -#define _PB_CommandStatus_ARRAYSIZE ((PB_CommandStatus)(PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED+1)) - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initializer values for message structs */ -#define PB_Empty_init_default {0} -#define PB_StopSession_init_default {0} -#define PB_Main_init_default {0, _PB_CommandStatus_MIN, 0, {{NULL}, NULL}, 0, {PB_Empty_init_default}} -#define PB_Empty_init_zero {0} -#define PB_StopSession_init_zero {0} -#define PB_Main_init_zero {0, _PB_CommandStatus_MIN, 0, {{NULL}, NULL}, 0, {PB_Empty_init_zero}} - -/* Field tags (for use in manual encoding/decoding) */ -#define PB_Main_command_id_tag 1 -#define PB_Main_command_status_tag 2 -#define PB_Main_has_next_tag 3 -#define PB_Main_empty_tag 4 -#define PB_Main_system_ping_request_tag 5 -#define PB_Main_system_ping_response_tag 6 -#define PB_Main_storage_list_request_tag 7 -#define PB_Main_storage_list_response_tag 8 -#define PB_Main_storage_read_request_tag 9 -#define PB_Main_storage_read_response_tag 10 -#define PB_Main_storage_write_request_tag 11 -#define PB_Main_storage_delete_request_tag 12 -#define PB_Main_storage_mkdir_request_tag 13 -#define PB_Main_storage_md5sum_request_tag 14 -#define PB_Main_storage_md5sum_response_tag 15 -#define PB_Main_app_start_request_tag 16 -#define PB_Main_app_lock_status_request_tag 17 -#define PB_Main_app_lock_status_response_tag 18 -#define PB_Main_stop_session_tag 19 -#define PB_Main_gui_start_screen_stream_request_tag 20 -#define PB_Main_gui_stop_screen_stream_request_tag 21 -#define PB_Main_gui_screen_frame_tag 22 -#define PB_Main_gui_send_input_event_request_tag 23 -#define PB_Main_storage_stat_request_tag 24 -#define PB_Main_storage_stat_response_tag 25 -#define PB_Main_gui_start_virtual_display_request_tag 26 -#define PB_Main_gui_stop_virtual_display_request_tag 27 -#define PB_Main_storage_info_request_tag 28 -#define PB_Main_storage_info_response_tag 29 -#define PB_Main_storage_rename_request_tag 30 -#define PB_Main_system_reboot_request_tag 31 -#define PB_Main_system_device_info_request_tag 32 -#define PB_Main_system_device_info_response_tag 33 -#define PB_Main_system_factory_reset_request_tag 34 -#define PB_Main_system_get_datetime_request_tag 35 -#define PB_Main_system_get_datetime_response_tag 36 -#define PB_Main_system_set_datetime_request_tag 37 -#define PB_Main_system_play_audiovisual_alert_request_tag 38 -#define PB_Main_system_protobuf_version_request_tag 39 -#define PB_Main_system_protobuf_version_response_tag 40 -#define PB_Main_system_update_request_tag 41 -#define PB_Main_storage_backup_create_request_tag 42 -#define PB_Main_storage_backup_restore_request_tag 43 -#define PB_Main_system_power_info_request_tag 44 -#define PB_Main_system_power_info_response_tag 45 -#define PB_Main_system_update_response_tag 46 - -/* Struct field encoding specification for nanopb */ -#define PB_Empty_FIELDLIST(X, a) \ - -#define PB_Empty_CALLBACK NULL -#define PB_Empty_DEFAULT NULL - -#define PB_StopSession_FIELDLIST(X, a) \ - -#define PB_StopSession_CALLBACK NULL -#define PB_StopSession_DEFAULT NULL - -#define PB_Main_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, command_id, 1) \ -X(a, STATIC, SINGULAR, UENUM, command_status, 2) \ -X(a, STATIC, SINGULAR, BOOL, has_next, 3) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,empty,content.empty), 4) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_ping_request,content.system_ping_request), 5) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_ping_response,content.system_ping_response), 6) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_list_request,content.storage_list_request), 7) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_list_response,content.storage_list_response), 8) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_read_request,content.storage_read_request), 9) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_read_response,content.storage_read_response), 10) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_write_request,content.storage_write_request), 11) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_delete_request,content.storage_delete_request), 12) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_mkdir_request,content.storage_mkdir_request), 13) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_md5sum_request,content.storage_md5sum_request), 14) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_md5sum_response,content.storage_md5sum_response), 15) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,app_start_request,content.app_start_request), 16) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,app_lock_status_request,content.app_lock_status_request), 17) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,app_lock_status_response,content.app_lock_status_response), 18) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,stop_session,content.stop_session), 19) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_start_screen_stream_request,content.gui_start_screen_stream_request), 20) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_stop_screen_stream_request,content.gui_stop_screen_stream_request), 21) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_screen_frame,content.gui_screen_frame), 22) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_send_input_event_request,content.gui_send_input_event_request), 23) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_stat_request,content.storage_stat_request), 24) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_stat_response,content.storage_stat_response), 25) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_start_virtual_display_request,content.gui_start_virtual_display_request), 26) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_stop_virtual_display_request,content.gui_stop_virtual_display_request), 27) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_info_request,content.storage_info_request), 28) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_info_response,content.storage_info_response), 29) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_rename_request,content.storage_rename_request), 30) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_reboot_request,content.system_reboot_request), 31) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_device_info_request,content.system_device_info_request), 32) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_device_info_response,content.system_device_info_response), 33) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_factory_reset_request,content.system_factory_reset_request), 34) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_get_datetime_request,content.system_get_datetime_request), 35) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_get_datetime_response,content.system_get_datetime_response), 36) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_set_datetime_request,content.system_set_datetime_request), 37) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_play_audiovisual_alert_request,content.system_play_audiovisual_alert_request), 38) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_protobuf_version_request,content.system_protobuf_version_request), 39) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_protobuf_version_response,content.system_protobuf_version_response), 40) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_update_request,content.system_update_request), 41) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_backup_create_request,content.storage_backup_create_request), 42) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_backup_restore_request,content.storage_backup_restore_request), 43) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_power_info_request,content.system_power_info_request), 44) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_power_info_response,content.system_power_info_response), 45) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,system_update_response,content.system_update_response), 46) -#define PB_Main_CALLBACK NULL -#define PB_Main_DEFAULT NULL -#define PB_Main_content_empty_MSGTYPE PB_Empty -#define PB_Main_content_system_ping_request_MSGTYPE PB_System_PingRequest -#define PB_Main_content_system_ping_response_MSGTYPE PB_System_PingResponse -#define PB_Main_content_storage_list_request_MSGTYPE PB_Storage_ListRequest -#define PB_Main_content_storage_list_response_MSGTYPE PB_Storage_ListResponse -#define PB_Main_content_storage_read_request_MSGTYPE PB_Storage_ReadRequest -#define PB_Main_content_storage_read_response_MSGTYPE PB_Storage_ReadResponse -#define PB_Main_content_storage_write_request_MSGTYPE PB_Storage_WriteRequest -#define PB_Main_content_storage_delete_request_MSGTYPE PB_Storage_DeleteRequest -#define PB_Main_content_storage_mkdir_request_MSGTYPE PB_Storage_MkdirRequest -#define PB_Main_content_storage_md5sum_request_MSGTYPE PB_Storage_Md5sumRequest -#define PB_Main_content_storage_md5sum_response_MSGTYPE PB_Storage_Md5sumResponse -#define PB_Main_content_app_start_request_MSGTYPE PB_App_StartRequest -#define PB_Main_content_app_lock_status_request_MSGTYPE PB_App_LockStatusRequest -#define PB_Main_content_app_lock_status_response_MSGTYPE PB_App_LockStatusResponse -#define PB_Main_content_stop_session_MSGTYPE PB_StopSession -#define PB_Main_content_gui_start_screen_stream_request_MSGTYPE PB_Gui_StartScreenStreamRequest -#define PB_Main_content_gui_stop_screen_stream_request_MSGTYPE PB_Gui_StopScreenStreamRequest -#define PB_Main_content_gui_screen_frame_MSGTYPE PB_Gui_ScreenFrame -#define PB_Main_content_gui_send_input_event_request_MSGTYPE PB_Gui_SendInputEventRequest -#define PB_Main_content_storage_stat_request_MSGTYPE PB_Storage_StatRequest -#define PB_Main_content_storage_stat_response_MSGTYPE PB_Storage_StatResponse -#define PB_Main_content_gui_start_virtual_display_request_MSGTYPE PB_Gui_StartVirtualDisplayRequest -#define PB_Main_content_gui_stop_virtual_display_request_MSGTYPE PB_Gui_StopVirtualDisplayRequest -#define PB_Main_content_storage_info_request_MSGTYPE PB_Storage_InfoRequest -#define PB_Main_content_storage_info_response_MSGTYPE PB_Storage_InfoResponse -#define PB_Main_content_storage_rename_request_MSGTYPE PB_Storage_RenameRequest -#define PB_Main_content_system_reboot_request_MSGTYPE PB_System_RebootRequest -#define PB_Main_content_system_device_info_request_MSGTYPE PB_System_DeviceInfoRequest -#define PB_Main_content_system_device_info_response_MSGTYPE PB_System_DeviceInfoResponse -#define PB_Main_content_system_factory_reset_request_MSGTYPE PB_System_FactoryResetRequest -#define PB_Main_content_system_get_datetime_request_MSGTYPE PB_System_GetDateTimeRequest -#define PB_Main_content_system_get_datetime_response_MSGTYPE PB_System_GetDateTimeResponse -#define PB_Main_content_system_set_datetime_request_MSGTYPE PB_System_SetDateTimeRequest -#define PB_Main_content_system_play_audiovisual_alert_request_MSGTYPE PB_System_PlayAudiovisualAlertRequest -#define PB_Main_content_system_protobuf_version_request_MSGTYPE PB_System_ProtobufVersionRequest -#define PB_Main_content_system_protobuf_version_response_MSGTYPE PB_System_ProtobufVersionResponse -#define PB_Main_content_system_update_request_MSGTYPE PB_System_UpdateRequest -#define PB_Main_content_storage_backup_create_request_MSGTYPE PB_Storage_BackupCreateRequest -#define PB_Main_content_storage_backup_restore_request_MSGTYPE PB_Storage_BackupRestoreRequest -#define PB_Main_content_system_power_info_request_MSGTYPE PB_System_PowerInfoRequest -#define PB_Main_content_system_power_info_response_MSGTYPE PB_System_PowerInfoResponse -#define PB_Main_content_system_update_response_MSGTYPE PB_System_UpdateResponse - -extern const pb_msgdesc_t PB_Empty_msg; -extern const pb_msgdesc_t PB_StopSession_msg; -extern const pb_msgdesc_t PB_Main_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define PB_Empty_fields &PB_Empty_msg -#define PB_StopSession_fields &PB_StopSession_msg -#define PB_Main_fields &PB_Main_msg - -/* Maximum encoded size of messages (where known) */ -#define PB_Empty_size 0 -#define PB_StopSession_size 0 -#if defined(PB_System_PingRequest_size) && defined(PB_System_PingResponse_size) && defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_StartRequest_size) && defined(PB_Gui_ScreenFrame_size) && defined(PB_Storage_StatRequest_size) && defined(PB_Storage_StatResponse_size) && defined(PB_Gui_StartVirtualDisplayRequest_size) && defined(PB_Storage_InfoRequest_size) && defined(PB_Storage_RenameRequest_size) && defined(PB_System_DeviceInfoResponse_size) && defined(PB_System_UpdateRequest_size) && defined(PB_Storage_BackupCreateRequest_size) && defined(PB_Storage_BackupRestoreRequest_size) && defined(PB_System_PowerInfoResponse_size) -#define PB_Main_size (10 + sizeof(union PB_Main_content_size_union)) -union PB_Main_content_size_union {char f5[(6 + PB_System_PingRequest_size)]; char f6[(6 + PB_System_PingResponse_size)]; char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_StartRequest_size)]; char f22[(7 + PB_Gui_ScreenFrame_size)]; char f24[(7 + PB_Storage_StatRequest_size)]; char f25[(7 + PB_Storage_StatResponse_size)]; char f26[(7 + PB_Gui_StartVirtualDisplayRequest_size)]; char f28[(7 + PB_Storage_InfoRequest_size)]; char f30[(7 + PB_Storage_RenameRequest_size)]; char f33[(7 + PB_System_DeviceInfoResponse_size)]; char f41[(7 + PB_System_UpdateRequest_size)]; char f42[(7 + PB_Storage_BackupCreateRequest_size)]; char f43[(7 + PB_Storage_BackupRestoreRequest_size)]; char f45[(7 + PB_System_PowerInfoResponse_size)]; char f0[36];}; -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/assets/compiled/gui.pb.c b/assets/compiled/gui.pb.c deleted file mode 100644 index 2c1d8490..00000000 --- a/assets/compiled/gui.pb.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5 */ - -#include "gui.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(PB_Gui_ScreenFrame, PB_Gui_ScreenFrame, AUTO) - - -PB_BIND(PB_Gui_StartScreenStreamRequest, PB_Gui_StartScreenStreamRequest, AUTO) - - -PB_BIND(PB_Gui_StopScreenStreamRequest, PB_Gui_StopScreenStreamRequest, AUTO) - - -PB_BIND(PB_Gui_SendInputEventRequest, PB_Gui_SendInputEventRequest, AUTO) - - -PB_BIND(PB_Gui_StartVirtualDisplayRequest, PB_Gui_StartVirtualDisplayRequest, AUTO) - - -PB_BIND(PB_Gui_StopVirtualDisplayRequest, PB_Gui_StopVirtualDisplayRequest, AUTO) - - - - - diff --git a/assets/compiled/gui.pb.h b/assets/compiled/gui.pb.h deleted file mode 100644 index 7ab8a97d..00000000 --- a/assets/compiled/gui.pb.h +++ /dev/null @@ -1,152 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5 */ - -#ifndef PB_PB_GUI_GUI_PB_H_INCLUDED -#define PB_PB_GUI_GUI_PB_H_INCLUDED -#include - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Enum definitions */ -typedef enum _PB_Gui_InputKey { - PB_Gui_InputKey_UP = 0, - PB_Gui_InputKey_DOWN = 1, - PB_Gui_InputKey_RIGHT = 2, - PB_Gui_InputKey_LEFT = 3, - PB_Gui_InputKey_OK = 4, - PB_Gui_InputKey_BACK = 5 -} PB_Gui_InputKey; - -typedef enum _PB_Gui_InputType { - PB_Gui_InputType_PRESS = 0, /* *< Press event, emitted after debounce */ - PB_Gui_InputType_RELEASE = 1, /* *< Release event, emitted after debounce */ - PB_Gui_InputType_SHORT = 2, /* *< Short event, emitted after InputTypeRelease done withing INPUT_LONG_PRESS interval */ - PB_Gui_InputType_LONG = 3, /* *< Long event, emmited after INPUT_LONG_PRESS interval, asynchronouse to InputTypeRelease */ - PB_Gui_InputType_REPEAT = 4 /* *< Repeat event, emmited with INPUT_REPEATE_PRESS period after InputTypeLong event */ -} PB_Gui_InputType; - -/* Struct definitions */ -typedef struct _PB_Gui_ScreenFrame { - pb_bytes_array_t *data; -} PB_Gui_ScreenFrame; - -typedef struct _PB_Gui_StartScreenStreamRequest { - char dummy_field; -} PB_Gui_StartScreenStreamRequest; - -typedef struct _PB_Gui_StopScreenStreamRequest { - char dummy_field; -} PB_Gui_StopScreenStreamRequest; - -typedef struct _PB_Gui_StopVirtualDisplayRequest { - char dummy_field; -} PB_Gui_StopVirtualDisplayRequest; - -typedef struct _PB_Gui_SendInputEventRequest { - PB_Gui_InputKey key; - PB_Gui_InputType type; -} PB_Gui_SendInputEventRequest; - -typedef struct _PB_Gui_StartVirtualDisplayRequest { - bool has_first_frame; - PB_Gui_ScreenFrame first_frame; /* optional */ -} PB_Gui_StartVirtualDisplayRequest; - - -/* Helper constants for enums */ -#define _PB_Gui_InputKey_MIN PB_Gui_InputKey_UP -#define _PB_Gui_InputKey_MAX PB_Gui_InputKey_BACK -#define _PB_Gui_InputKey_ARRAYSIZE ((PB_Gui_InputKey)(PB_Gui_InputKey_BACK+1)) - -#define _PB_Gui_InputType_MIN PB_Gui_InputType_PRESS -#define _PB_Gui_InputType_MAX PB_Gui_InputType_REPEAT -#define _PB_Gui_InputType_ARRAYSIZE ((PB_Gui_InputType)(PB_Gui_InputType_REPEAT+1)) - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initializer values for message structs */ -#define PB_Gui_ScreenFrame_init_default {NULL} -#define PB_Gui_StartScreenStreamRequest_init_default {0} -#define PB_Gui_StopScreenStreamRequest_init_default {0} -#define PB_Gui_SendInputEventRequest_init_default {_PB_Gui_InputKey_MIN, _PB_Gui_InputType_MIN} -#define PB_Gui_StartVirtualDisplayRequest_init_default {false, PB_Gui_ScreenFrame_init_default} -#define PB_Gui_StopVirtualDisplayRequest_init_default {0} -#define PB_Gui_ScreenFrame_init_zero {NULL} -#define PB_Gui_StartScreenStreamRequest_init_zero {0} -#define PB_Gui_StopScreenStreamRequest_init_zero {0} -#define PB_Gui_SendInputEventRequest_init_zero {_PB_Gui_InputKey_MIN, _PB_Gui_InputType_MIN} -#define PB_Gui_StartVirtualDisplayRequest_init_zero {false, PB_Gui_ScreenFrame_init_zero} -#define PB_Gui_StopVirtualDisplayRequest_init_zero {0} - -/* Field tags (for use in manual encoding/decoding) */ -#define PB_Gui_ScreenFrame_data_tag 1 -#define PB_Gui_SendInputEventRequest_key_tag 1 -#define PB_Gui_SendInputEventRequest_type_tag 2 -#define PB_Gui_StartVirtualDisplayRequest_first_frame_tag 1 - -/* Struct field encoding specification for nanopb */ -#define PB_Gui_ScreenFrame_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, BYTES, data, 1) -#define PB_Gui_ScreenFrame_CALLBACK NULL -#define PB_Gui_ScreenFrame_DEFAULT NULL - -#define PB_Gui_StartScreenStreamRequest_FIELDLIST(X, a) \ - -#define PB_Gui_StartScreenStreamRequest_CALLBACK NULL -#define PB_Gui_StartScreenStreamRequest_DEFAULT NULL - -#define PB_Gui_StopScreenStreamRequest_FIELDLIST(X, a) \ - -#define PB_Gui_StopScreenStreamRequest_CALLBACK NULL -#define PB_Gui_StopScreenStreamRequest_DEFAULT NULL - -#define PB_Gui_SendInputEventRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, key, 1) \ -X(a, STATIC, SINGULAR, UENUM, type, 2) -#define PB_Gui_SendInputEventRequest_CALLBACK NULL -#define PB_Gui_SendInputEventRequest_DEFAULT NULL - -#define PB_Gui_StartVirtualDisplayRequest_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, first_frame, 1) -#define PB_Gui_StartVirtualDisplayRequest_CALLBACK NULL -#define PB_Gui_StartVirtualDisplayRequest_DEFAULT NULL -#define PB_Gui_StartVirtualDisplayRequest_first_frame_MSGTYPE PB_Gui_ScreenFrame - -#define PB_Gui_StopVirtualDisplayRequest_FIELDLIST(X, a) \ - -#define PB_Gui_StopVirtualDisplayRequest_CALLBACK NULL -#define PB_Gui_StopVirtualDisplayRequest_DEFAULT NULL - -extern const pb_msgdesc_t PB_Gui_ScreenFrame_msg; -extern const pb_msgdesc_t PB_Gui_StartScreenStreamRequest_msg; -extern const pb_msgdesc_t PB_Gui_StopScreenStreamRequest_msg; -extern const pb_msgdesc_t PB_Gui_SendInputEventRequest_msg; -extern const pb_msgdesc_t PB_Gui_StartVirtualDisplayRequest_msg; -extern const pb_msgdesc_t PB_Gui_StopVirtualDisplayRequest_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define PB_Gui_ScreenFrame_fields &PB_Gui_ScreenFrame_msg -#define PB_Gui_StartScreenStreamRequest_fields &PB_Gui_StartScreenStreamRequest_msg -#define PB_Gui_StopScreenStreamRequest_fields &PB_Gui_StopScreenStreamRequest_msg -#define PB_Gui_SendInputEventRequest_fields &PB_Gui_SendInputEventRequest_msg -#define PB_Gui_StartVirtualDisplayRequest_fields &PB_Gui_StartVirtualDisplayRequest_msg -#define PB_Gui_StopVirtualDisplayRequest_fields &PB_Gui_StopVirtualDisplayRequest_msg - -/* Maximum encoded size of messages (where known) */ -/* PB_Gui_ScreenFrame_size depends on runtime parameters */ -/* PB_Gui_StartVirtualDisplayRequest_size depends on runtime parameters */ -#define PB_Gui_SendInputEventRequest_size 4 -#define PB_Gui_StartScreenStreamRequest_size 0 -#define PB_Gui_StopScreenStreamRequest_size 0 -#define PB_Gui_StopVirtualDisplayRequest_size 0 - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/assets/compiled/protobuf_version.h b/assets/compiled/protobuf_version.h deleted file mode 100644 index 6b401411..00000000 --- a/assets/compiled/protobuf_version.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once -#define PROTOBUF_MAJOR_VERSION 0 -#define PROTOBUF_MINOR_VERSION 7 diff --git a/assets/compiled/storage.pb.c b/assets/compiled/storage.pb.c deleted file mode 100644 index 244b273d..00000000 --- a/assets/compiled/storage.pb.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5 */ - -#include "storage.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(PB_Storage_File, PB_Storage_File, AUTO) - - -PB_BIND(PB_Storage_InfoRequest, PB_Storage_InfoRequest, AUTO) - - -PB_BIND(PB_Storage_InfoResponse, PB_Storage_InfoResponse, AUTO) - - -PB_BIND(PB_Storage_StatRequest, PB_Storage_StatRequest, AUTO) - - -PB_BIND(PB_Storage_StatResponse, PB_Storage_StatResponse, AUTO) - - -PB_BIND(PB_Storage_ListRequest, PB_Storage_ListRequest, AUTO) - - -PB_BIND(PB_Storage_ListResponse, PB_Storage_ListResponse, AUTO) - - -PB_BIND(PB_Storage_ReadRequest, PB_Storage_ReadRequest, AUTO) - - -PB_BIND(PB_Storage_ReadResponse, PB_Storage_ReadResponse, AUTO) - - -PB_BIND(PB_Storage_WriteRequest, PB_Storage_WriteRequest, AUTO) - - -PB_BIND(PB_Storage_DeleteRequest, PB_Storage_DeleteRequest, AUTO) - - -PB_BIND(PB_Storage_MkdirRequest, PB_Storage_MkdirRequest, AUTO) - - -PB_BIND(PB_Storage_Md5sumRequest, PB_Storage_Md5sumRequest, AUTO) - - -PB_BIND(PB_Storage_Md5sumResponse, PB_Storage_Md5sumResponse, AUTO) - - -PB_BIND(PB_Storage_RenameRequest, PB_Storage_RenameRequest, AUTO) - - -PB_BIND(PB_Storage_BackupCreateRequest, PB_Storage_BackupCreateRequest, AUTO) - - -PB_BIND(PB_Storage_BackupRestoreRequest, PB_Storage_BackupRestoreRequest, AUTO) - - - - diff --git a/assets/compiled/storage.pb.h b/assets/compiled/storage.pb.h deleted file mode 100644 index 9b31dc31..00000000 --- a/assets/compiled/storage.pb.h +++ /dev/null @@ -1,328 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5 */ - -#ifndef PB_PB_STORAGE_STORAGE_PB_H_INCLUDED -#define PB_PB_STORAGE_STORAGE_PB_H_INCLUDED -#include - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Enum definitions */ -typedef enum _PB_Storage_File_FileType { - PB_Storage_File_FileType_FILE = 0, - PB_Storage_File_FileType_DIR = 1 -} PB_Storage_File_FileType; - -/* Struct definitions */ -typedef struct _PB_Storage_BackupCreateRequest { - char *archive_path; -} PB_Storage_BackupCreateRequest; - -typedef struct _PB_Storage_BackupRestoreRequest { - char *archive_path; -} PB_Storage_BackupRestoreRequest; - -typedef struct _PB_Storage_InfoRequest { - char *path; -} PB_Storage_InfoRequest; - -typedef struct _PB_Storage_ListRequest { - char *path; -} PB_Storage_ListRequest; - -typedef struct _PB_Storage_Md5sumRequest { - char *path; -} PB_Storage_Md5sumRequest; - -typedef struct _PB_Storage_MkdirRequest { - char *path; -} PB_Storage_MkdirRequest; - -typedef struct _PB_Storage_ReadRequest { - char *path; -} PB_Storage_ReadRequest; - -typedef struct _PB_Storage_RenameRequest { - char *old_path; - char *new_path; -} PB_Storage_RenameRequest; - -typedef struct _PB_Storage_StatRequest { - char *path; -} PB_Storage_StatRequest; - -typedef struct _PB_Storage_DeleteRequest { - char *path; - bool recursive; -} PB_Storage_DeleteRequest; - -typedef struct _PB_Storage_File { - PB_Storage_File_FileType type; - char *name; - uint32_t size; - pb_bytes_array_t *data; -} PB_Storage_File; - -typedef struct _PB_Storage_InfoResponse { - uint64_t total_space; - uint64_t free_space; -} PB_Storage_InfoResponse; - -typedef struct _PB_Storage_Md5sumResponse { - char md5sum[33]; -} PB_Storage_Md5sumResponse; - -typedef struct _PB_Storage_ListResponse { - pb_size_t file_count; - PB_Storage_File file[8]; -} PB_Storage_ListResponse; - -typedef struct _PB_Storage_ReadResponse { - bool has_file; - PB_Storage_File file; -} PB_Storage_ReadResponse; - -typedef struct _PB_Storage_StatResponse { - bool has_file; - PB_Storage_File file; -} PB_Storage_StatResponse; - -typedef struct _PB_Storage_WriteRequest { - char *path; - bool has_file; - PB_Storage_File file; -} PB_Storage_WriteRequest; - - -/* Helper constants for enums */ -#define _PB_Storage_File_FileType_MIN PB_Storage_File_FileType_FILE -#define _PB_Storage_File_FileType_MAX PB_Storage_File_FileType_DIR -#define _PB_Storage_File_FileType_ARRAYSIZE ((PB_Storage_File_FileType)(PB_Storage_File_FileType_DIR+1)) - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initializer values for message structs */ -#define PB_Storage_File_init_default {_PB_Storage_File_FileType_MIN, NULL, 0, NULL} -#define PB_Storage_InfoRequest_init_default {NULL} -#define PB_Storage_InfoResponse_init_default {0, 0} -#define PB_Storage_StatRequest_init_default {NULL} -#define PB_Storage_StatResponse_init_default {false, PB_Storage_File_init_default} -#define PB_Storage_ListRequest_init_default {NULL} -#define PB_Storage_ListResponse_init_default {0, {PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default, PB_Storage_File_init_default}} -#define PB_Storage_ReadRequest_init_default {NULL} -#define PB_Storage_ReadResponse_init_default {false, PB_Storage_File_init_default} -#define PB_Storage_WriteRequest_init_default {NULL, false, PB_Storage_File_init_default} -#define PB_Storage_DeleteRequest_init_default {NULL, 0} -#define PB_Storage_MkdirRequest_init_default {NULL} -#define PB_Storage_Md5sumRequest_init_default {NULL} -#define PB_Storage_Md5sumResponse_init_default {""} -#define PB_Storage_RenameRequest_init_default {NULL, NULL} -#define PB_Storage_BackupCreateRequest_init_default {NULL} -#define PB_Storage_BackupRestoreRequest_init_default {NULL} -#define PB_Storage_File_init_zero {_PB_Storage_File_FileType_MIN, NULL, 0, NULL} -#define PB_Storage_InfoRequest_init_zero {NULL} -#define PB_Storage_InfoResponse_init_zero {0, 0} -#define PB_Storage_StatRequest_init_zero {NULL} -#define PB_Storage_StatResponse_init_zero {false, PB_Storage_File_init_zero} -#define PB_Storage_ListRequest_init_zero {NULL} -#define PB_Storage_ListResponse_init_zero {0, {PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero, PB_Storage_File_init_zero}} -#define PB_Storage_ReadRequest_init_zero {NULL} -#define PB_Storage_ReadResponse_init_zero {false, PB_Storage_File_init_zero} -#define PB_Storage_WriteRequest_init_zero {NULL, false, PB_Storage_File_init_zero} -#define PB_Storage_DeleteRequest_init_zero {NULL, 0} -#define PB_Storage_MkdirRequest_init_zero {NULL} -#define PB_Storage_Md5sumRequest_init_zero {NULL} -#define PB_Storage_Md5sumResponse_init_zero {""} -#define PB_Storage_RenameRequest_init_zero {NULL, NULL} -#define PB_Storage_BackupCreateRequest_init_zero {NULL} -#define PB_Storage_BackupRestoreRequest_init_zero {NULL} - -/* Field tags (for use in manual encoding/decoding) */ -#define PB_Storage_BackupCreateRequest_archive_path_tag 1 -#define PB_Storage_BackupRestoreRequest_archive_path_tag 1 -#define PB_Storage_InfoRequest_path_tag 1 -#define PB_Storage_ListRequest_path_tag 1 -#define PB_Storage_Md5sumRequest_path_tag 1 -#define PB_Storage_MkdirRequest_path_tag 1 -#define PB_Storage_ReadRequest_path_tag 1 -#define PB_Storage_RenameRequest_old_path_tag 1 -#define PB_Storage_RenameRequest_new_path_tag 2 -#define PB_Storage_StatRequest_path_tag 1 -#define PB_Storage_DeleteRequest_path_tag 1 -#define PB_Storage_DeleteRequest_recursive_tag 2 -#define PB_Storage_File_type_tag 1 -#define PB_Storage_File_name_tag 2 -#define PB_Storage_File_size_tag 3 -#define PB_Storage_File_data_tag 4 -#define PB_Storage_InfoResponse_total_space_tag 1 -#define PB_Storage_InfoResponse_free_space_tag 2 -#define PB_Storage_Md5sumResponse_md5sum_tag 1 -#define PB_Storage_ListResponse_file_tag 1 -#define PB_Storage_ReadResponse_file_tag 1 -#define PB_Storage_StatResponse_file_tag 1 -#define PB_Storage_WriteRequest_path_tag 1 -#define PB_Storage_WriteRequest_file_tag 2 - -/* Struct field encoding specification for nanopb */ -#define PB_Storage_File_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, type, 1) \ -X(a, POINTER, SINGULAR, STRING, name, 2) \ -X(a, STATIC, SINGULAR, UINT32, size, 3) \ -X(a, POINTER, SINGULAR, BYTES, data, 4) -#define PB_Storage_File_CALLBACK NULL -#define PB_Storage_File_DEFAULT NULL - -#define PB_Storage_InfoRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, path, 1) -#define PB_Storage_InfoRequest_CALLBACK NULL -#define PB_Storage_InfoRequest_DEFAULT NULL - -#define PB_Storage_InfoResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT64, total_space, 1) \ -X(a, STATIC, SINGULAR, UINT64, free_space, 2) -#define PB_Storage_InfoResponse_CALLBACK NULL -#define PB_Storage_InfoResponse_DEFAULT NULL - -#define PB_Storage_StatRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, path, 1) -#define PB_Storage_StatRequest_CALLBACK NULL -#define PB_Storage_StatRequest_DEFAULT NULL - -#define PB_Storage_StatResponse_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, file, 1) -#define PB_Storage_StatResponse_CALLBACK NULL -#define PB_Storage_StatResponse_DEFAULT NULL -#define PB_Storage_StatResponse_file_MSGTYPE PB_Storage_File - -#define PB_Storage_ListRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, path, 1) -#define PB_Storage_ListRequest_CALLBACK NULL -#define PB_Storage_ListRequest_DEFAULT NULL - -#define PB_Storage_ListResponse_FIELDLIST(X, a) \ -X(a, STATIC, REPEATED, MESSAGE, file, 1) -#define PB_Storage_ListResponse_CALLBACK NULL -#define PB_Storage_ListResponse_DEFAULT NULL -#define PB_Storage_ListResponse_file_MSGTYPE PB_Storage_File - -#define PB_Storage_ReadRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, path, 1) -#define PB_Storage_ReadRequest_CALLBACK NULL -#define PB_Storage_ReadRequest_DEFAULT NULL - -#define PB_Storage_ReadResponse_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, file, 1) -#define PB_Storage_ReadResponse_CALLBACK NULL -#define PB_Storage_ReadResponse_DEFAULT NULL -#define PB_Storage_ReadResponse_file_MSGTYPE PB_Storage_File - -#define PB_Storage_WriteRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, path, 1) \ -X(a, STATIC, OPTIONAL, MESSAGE, file, 2) -#define PB_Storage_WriteRequest_CALLBACK NULL -#define PB_Storage_WriteRequest_DEFAULT NULL -#define PB_Storage_WriteRequest_file_MSGTYPE PB_Storage_File - -#define PB_Storage_DeleteRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, path, 1) \ -X(a, STATIC, SINGULAR, BOOL, recursive, 2) -#define PB_Storage_DeleteRequest_CALLBACK NULL -#define PB_Storage_DeleteRequest_DEFAULT NULL - -#define PB_Storage_MkdirRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, path, 1) -#define PB_Storage_MkdirRequest_CALLBACK NULL -#define PB_Storage_MkdirRequest_DEFAULT NULL - -#define PB_Storage_Md5sumRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, path, 1) -#define PB_Storage_Md5sumRequest_CALLBACK NULL -#define PB_Storage_Md5sumRequest_DEFAULT NULL - -#define PB_Storage_Md5sumResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, STRING, md5sum, 1) -#define PB_Storage_Md5sumResponse_CALLBACK NULL -#define PB_Storage_Md5sumResponse_DEFAULT NULL - -#define PB_Storage_RenameRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, old_path, 1) \ -X(a, POINTER, SINGULAR, STRING, new_path, 2) -#define PB_Storage_RenameRequest_CALLBACK NULL -#define PB_Storage_RenameRequest_DEFAULT NULL - -#define PB_Storage_BackupCreateRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, archive_path, 1) -#define PB_Storage_BackupCreateRequest_CALLBACK NULL -#define PB_Storage_BackupCreateRequest_DEFAULT NULL - -#define PB_Storage_BackupRestoreRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, archive_path, 1) -#define PB_Storage_BackupRestoreRequest_CALLBACK NULL -#define PB_Storage_BackupRestoreRequest_DEFAULT NULL - -extern const pb_msgdesc_t PB_Storage_File_msg; -extern const pb_msgdesc_t PB_Storage_InfoRequest_msg; -extern const pb_msgdesc_t PB_Storage_InfoResponse_msg; -extern const pb_msgdesc_t PB_Storage_StatRequest_msg; -extern const pb_msgdesc_t PB_Storage_StatResponse_msg; -extern const pb_msgdesc_t PB_Storage_ListRequest_msg; -extern const pb_msgdesc_t PB_Storage_ListResponse_msg; -extern const pb_msgdesc_t PB_Storage_ReadRequest_msg; -extern const pb_msgdesc_t PB_Storage_ReadResponse_msg; -extern const pb_msgdesc_t PB_Storage_WriteRequest_msg; -extern const pb_msgdesc_t PB_Storage_DeleteRequest_msg; -extern const pb_msgdesc_t PB_Storage_MkdirRequest_msg; -extern const pb_msgdesc_t PB_Storage_Md5sumRequest_msg; -extern const pb_msgdesc_t PB_Storage_Md5sumResponse_msg; -extern const pb_msgdesc_t PB_Storage_RenameRequest_msg; -extern const pb_msgdesc_t PB_Storage_BackupCreateRequest_msg; -extern const pb_msgdesc_t PB_Storage_BackupRestoreRequest_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define PB_Storage_File_fields &PB_Storage_File_msg -#define PB_Storage_InfoRequest_fields &PB_Storage_InfoRequest_msg -#define PB_Storage_InfoResponse_fields &PB_Storage_InfoResponse_msg -#define PB_Storage_StatRequest_fields &PB_Storage_StatRequest_msg -#define PB_Storage_StatResponse_fields &PB_Storage_StatResponse_msg -#define PB_Storage_ListRequest_fields &PB_Storage_ListRequest_msg -#define PB_Storage_ListResponse_fields &PB_Storage_ListResponse_msg -#define PB_Storage_ReadRequest_fields &PB_Storage_ReadRequest_msg -#define PB_Storage_ReadResponse_fields &PB_Storage_ReadResponse_msg -#define PB_Storage_WriteRequest_fields &PB_Storage_WriteRequest_msg -#define PB_Storage_DeleteRequest_fields &PB_Storage_DeleteRequest_msg -#define PB_Storage_MkdirRequest_fields &PB_Storage_MkdirRequest_msg -#define PB_Storage_Md5sumRequest_fields &PB_Storage_Md5sumRequest_msg -#define PB_Storage_Md5sumResponse_fields &PB_Storage_Md5sumResponse_msg -#define PB_Storage_RenameRequest_fields &PB_Storage_RenameRequest_msg -#define PB_Storage_BackupCreateRequest_fields &PB_Storage_BackupCreateRequest_msg -#define PB_Storage_BackupRestoreRequest_fields &PB_Storage_BackupRestoreRequest_msg - -/* Maximum encoded size of messages (where known) */ -/* PB_Storage_File_size depends on runtime parameters */ -/* PB_Storage_InfoRequest_size depends on runtime parameters */ -/* PB_Storage_StatRequest_size depends on runtime parameters */ -/* PB_Storage_StatResponse_size depends on runtime parameters */ -/* PB_Storage_ListRequest_size depends on runtime parameters */ -/* PB_Storage_ListResponse_size depends on runtime parameters */ -/* PB_Storage_ReadRequest_size depends on runtime parameters */ -/* PB_Storage_ReadResponse_size depends on runtime parameters */ -/* PB_Storage_WriteRequest_size depends on runtime parameters */ -/* PB_Storage_DeleteRequest_size depends on runtime parameters */ -/* PB_Storage_MkdirRequest_size depends on runtime parameters */ -/* PB_Storage_Md5sumRequest_size depends on runtime parameters */ -/* PB_Storage_RenameRequest_size depends on runtime parameters */ -/* PB_Storage_BackupCreateRequest_size depends on runtime parameters */ -/* PB_Storage_BackupRestoreRequest_size depends on runtime parameters */ -#define PB_Storage_InfoResponse_size 22 -#define PB_Storage_Md5sumResponse_size 34 - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/assets/compiled/system.pb.c b/assets/compiled/system.pb.c deleted file mode 100644 index e05ff90e..00000000 --- a/assets/compiled/system.pb.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5 */ - -#include "system.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(PB_System_PingRequest, PB_System_PingRequest, AUTO) - - -PB_BIND(PB_System_PingResponse, PB_System_PingResponse, AUTO) - - -PB_BIND(PB_System_RebootRequest, PB_System_RebootRequest, AUTO) - - -PB_BIND(PB_System_DeviceInfoRequest, PB_System_DeviceInfoRequest, AUTO) - - -PB_BIND(PB_System_DeviceInfoResponse, PB_System_DeviceInfoResponse, AUTO) - - -PB_BIND(PB_System_FactoryResetRequest, PB_System_FactoryResetRequest, AUTO) - - -PB_BIND(PB_System_GetDateTimeRequest, PB_System_GetDateTimeRequest, AUTO) - - -PB_BIND(PB_System_GetDateTimeResponse, PB_System_GetDateTimeResponse, AUTO) - - -PB_BIND(PB_System_SetDateTimeRequest, PB_System_SetDateTimeRequest, AUTO) - - -PB_BIND(PB_System_DateTime, PB_System_DateTime, AUTO) - - -PB_BIND(PB_System_PlayAudiovisualAlertRequest, PB_System_PlayAudiovisualAlertRequest, AUTO) - - -PB_BIND(PB_System_ProtobufVersionRequest, PB_System_ProtobufVersionRequest, AUTO) - - -PB_BIND(PB_System_ProtobufVersionResponse, PB_System_ProtobufVersionResponse, AUTO) - - -PB_BIND(PB_System_UpdateRequest, PB_System_UpdateRequest, AUTO) - - -PB_BIND(PB_System_UpdateResponse, PB_System_UpdateResponse, AUTO) - - -PB_BIND(PB_System_PowerInfoRequest, PB_System_PowerInfoRequest, AUTO) - - -PB_BIND(PB_System_PowerInfoResponse, PB_System_PowerInfoResponse, AUTO) - - - - - diff --git a/assets/compiled/system.pb.h b/assets/compiled/system.pb.h deleted file mode 100644 index aef2c75b..00000000 --- a/assets/compiled/system.pb.h +++ /dev/null @@ -1,342 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5 */ - -#ifndef PB_PB_SYSTEM_SYSTEM_PB_H_INCLUDED -#define PB_PB_SYSTEM_SYSTEM_PB_H_INCLUDED -#include - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Enum definitions */ -typedef enum _PB_System_RebootRequest_RebootMode { - PB_System_RebootRequest_RebootMode_OS = 0, - PB_System_RebootRequest_RebootMode_DFU = 1, - PB_System_RebootRequest_RebootMode_UPDATE = 2 -} PB_System_RebootRequest_RebootMode; - -typedef enum _PB_System_UpdateResponse_UpdateResultCode { - PB_System_UpdateResponse_UpdateResultCode_OK = 0, - PB_System_UpdateResponse_UpdateResultCode_ManifestPathInvalid = 1, - PB_System_UpdateResponse_UpdateResultCode_ManifestFolderNotFound = 2, - PB_System_UpdateResponse_UpdateResultCode_ManifestInvalid = 3, - PB_System_UpdateResponse_UpdateResultCode_StageMissing = 4, - PB_System_UpdateResponse_UpdateResultCode_StageIntegrityError = 5, - PB_System_UpdateResponse_UpdateResultCode_ManifestPointerError = 6, - PB_System_UpdateResponse_UpdateResultCode_TargetMismatch = 7 -} PB_System_UpdateResponse_UpdateResultCode; - -/* Struct definitions */ -typedef struct _PB_System_DeviceInfoRequest { - char dummy_field; -} PB_System_DeviceInfoRequest; - -typedef struct _PB_System_DeviceInfoResponse { - char *key; - char *value; -} PB_System_DeviceInfoResponse; - -typedef struct _PB_System_FactoryResetRequest { - char dummy_field; -} PB_System_FactoryResetRequest; - -typedef struct _PB_System_GetDateTimeRequest { - char dummy_field; -} PB_System_GetDateTimeRequest; - -typedef struct _PB_System_PingRequest { - pb_bytes_array_t *data; -} PB_System_PingRequest; - -typedef struct _PB_System_PingResponse { - pb_bytes_array_t *data; -} PB_System_PingResponse; - -typedef struct _PB_System_PlayAudiovisualAlertRequest { - char dummy_field; -} PB_System_PlayAudiovisualAlertRequest; - -typedef struct _PB_System_PowerInfoRequest { - char dummy_field; -} PB_System_PowerInfoRequest; - -typedef struct _PB_System_PowerInfoResponse { - char *key; - char *value; -} PB_System_PowerInfoResponse; - -typedef struct _PB_System_ProtobufVersionRequest { - char dummy_field; -} PB_System_ProtobufVersionRequest; - -typedef struct _PB_System_UpdateRequest { - char *update_manifest; -} PB_System_UpdateRequest; - -typedef struct _PB_System_DateTime { - /* Time */ - uint8_t hour; /* *< Hour in 24H format: 0-23 */ - uint8_t minute; /* *< Minute: 0-59 */ - uint8_t second; /* *< Second: 0-59 */ - /* Date */ - uint8_t day; /* *< Current day: 1-31 */ - uint8_t month; /* *< Current month: 1-12 */ - uint16_t year; /* *< Current year: 2000-2099 */ - uint8_t weekday; /* *< Current weekday: 1-7 */ -} PB_System_DateTime; - -typedef struct _PB_System_ProtobufVersionResponse { - uint32_t major; - uint32_t minor; -} PB_System_ProtobufVersionResponse; - -typedef struct _PB_System_RebootRequest { - PB_System_RebootRequest_RebootMode mode; -} PB_System_RebootRequest; - -typedef struct _PB_System_UpdateResponse { - PB_System_UpdateResponse_UpdateResultCode code; -} PB_System_UpdateResponse; - -typedef struct _PB_System_GetDateTimeResponse { - bool has_datetime; - PB_System_DateTime datetime; -} PB_System_GetDateTimeResponse; - -typedef struct _PB_System_SetDateTimeRequest { - bool has_datetime; - PB_System_DateTime datetime; -} PB_System_SetDateTimeRequest; - - -/* Helper constants for enums */ -#define _PB_System_RebootRequest_RebootMode_MIN PB_System_RebootRequest_RebootMode_OS -#define _PB_System_RebootRequest_RebootMode_MAX PB_System_RebootRequest_RebootMode_UPDATE -#define _PB_System_RebootRequest_RebootMode_ARRAYSIZE ((PB_System_RebootRequest_RebootMode)(PB_System_RebootRequest_RebootMode_UPDATE+1)) - -#define _PB_System_UpdateResponse_UpdateResultCode_MIN PB_System_UpdateResponse_UpdateResultCode_OK -#define _PB_System_UpdateResponse_UpdateResultCode_MAX PB_System_UpdateResponse_UpdateResultCode_TargetMismatch -#define _PB_System_UpdateResponse_UpdateResultCode_ARRAYSIZE ((PB_System_UpdateResponse_UpdateResultCode)(PB_System_UpdateResponse_UpdateResultCode_TargetMismatch+1)) - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initializer values for message structs */ -#define PB_System_PingRequest_init_default {NULL} -#define PB_System_PingResponse_init_default {NULL} -#define PB_System_RebootRequest_init_default {_PB_System_RebootRequest_RebootMode_MIN} -#define PB_System_DeviceInfoRequest_init_default {0} -#define PB_System_DeviceInfoResponse_init_default {NULL, NULL} -#define PB_System_FactoryResetRequest_init_default {0} -#define PB_System_GetDateTimeRequest_init_default {0} -#define PB_System_GetDateTimeResponse_init_default {false, PB_System_DateTime_init_default} -#define PB_System_SetDateTimeRequest_init_default {false, PB_System_DateTime_init_default} -#define PB_System_DateTime_init_default {0, 0, 0, 0, 0, 0, 0} -#define PB_System_PlayAudiovisualAlertRequest_init_default {0} -#define PB_System_ProtobufVersionRequest_init_default {0} -#define PB_System_ProtobufVersionResponse_init_default {0, 0} -#define PB_System_UpdateRequest_init_default {NULL} -#define PB_System_UpdateResponse_init_default {_PB_System_UpdateResponse_UpdateResultCode_MIN} -#define PB_System_PowerInfoRequest_init_default {0} -#define PB_System_PowerInfoResponse_init_default {NULL, NULL} -#define PB_System_PingRequest_init_zero {NULL} -#define PB_System_PingResponse_init_zero {NULL} -#define PB_System_RebootRequest_init_zero {_PB_System_RebootRequest_RebootMode_MIN} -#define PB_System_DeviceInfoRequest_init_zero {0} -#define PB_System_DeviceInfoResponse_init_zero {NULL, NULL} -#define PB_System_FactoryResetRequest_init_zero {0} -#define PB_System_GetDateTimeRequest_init_zero {0} -#define PB_System_GetDateTimeResponse_init_zero {false, PB_System_DateTime_init_zero} -#define PB_System_SetDateTimeRequest_init_zero {false, PB_System_DateTime_init_zero} -#define PB_System_DateTime_init_zero {0, 0, 0, 0, 0, 0, 0} -#define PB_System_PlayAudiovisualAlertRequest_init_zero {0} -#define PB_System_ProtobufVersionRequest_init_zero {0} -#define PB_System_ProtobufVersionResponse_init_zero {0, 0} -#define PB_System_UpdateRequest_init_zero {NULL} -#define PB_System_UpdateResponse_init_zero {_PB_System_UpdateResponse_UpdateResultCode_MIN} -#define PB_System_PowerInfoRequest_init_zero {0} -#define PB_System_PowerInfoResponse_init_zero {NULL, NULL} - -/* Field tags (for use in manual encoding/decoding) */ -#define PB_System_DeviceInfoResponse_key_tag 1 -#define PB_System_DeviceInfoResponse_value_tag 2 -#define PB_System_PingRequest_data_tag 1 -#define PB_System_PingResponse_data_tag 1 -#define PB_System_PowerInfoResponse_key_tag 1 -#define PB_System_PowerInfoResponse_value_tag 2 -#define PB_System_UpdateRequest_update_manifest_tag 1 -#define PB_System_DateTime_hour_tag 1 -#define PB_System_DateTime_minute_tag 2 -#define PB_System_DateTime_second_tag 3 -#define PB_System_DateTime_day_tag 4 -#define PB_System_DateTime_month_tag 5 -#define PB_System_DateTime_year_tag 6 -#define PB_System_DateTime_weekday_tag 7 -#define PB_System_ProtobufVersionResponse_major_tag 1 -#define PB_System_ProtobufVersionResponse_minor_tag 2 -#define PB_System_RebootRequest_mode_tag 1 -#define PB_System_UpdateResponse_code_tag 1 -#define PB_System_GetDateTimeResponse_datetime_tag 1 -#define PB_System_SetDateTimeRequest_datetime_tag 1 - -/* Struct field encoding specification for nanopb */ -#define PB_System_PingRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, BYTES, data, 1) -#define PB_System_PingRequest_CALLBACK NULL -#define PB_System_PingRequest_DEFAULT NULL - -#define PB_System_PingResponse_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, BYTES, data, 1) -#define PB_System_PingResponse_CALLBACK NULL -#define PB_System_PingResponse_DEFAULT NULL - -#define PB_System_RebootRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, mode, 1) -#define PB_System_RebootRequest_CALLBACK NULL -#define PB_System_RebootRequest_DEFAULT NULL - -#define PB_System_DeviceInfoRequest_FIELDLIST(X, a) \ - -#define PB_System_DeviceInfoRequest_CALLBACK NULL -#define PB_System_DeviceInfoRequest_DEFAULT NULL - -#define PB_System_DeviceInfoResponse_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, key, 1) \ -X(a, POINTER, SINGULAR, STRING, value, 2) -#define PB_System_DeviceInfoResponse_CALLBACK NULL -#define PB_System_DeviceInfoResponse_DEFAULT NULL - -#define PB_System_FactoryResetRequest_FIELDLIST(X, a) \ - -#define PB_System_FactoryResetRequest_CALLBACK NULL -#define PB_System_FactoryResetRequest_DEFAULT NULL - -#define PB_System_GetDateTimeRequest_FIELDLIST(X, a) \ - -#define PB_System_GetDateTimeRequest_CALLBACK NULL -#define PB_System_GetDateTimeRequest_DEFAULT NULL - -#define PB_System_GetDateTimeResponse_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, datetime, 1) -#define PB_System_GetDateTimeResponse_CALLBACK NULL -#define PB_System_GetDateTimeResponse_DEFAULT NULL -#define PB_System_GetDateTimeResponse_datetime_MSGTYPE PB_System_DateTime - -#define PB_System_SetDateTimeRequest_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, datetime, 1) -#define PB_System_SetDateTimeRequest_CALLBACK NULL -#define PB_System_SetDateTimeRequest_DEFAULT NULL -#define PB_System_SetDateTimeRequest_datetime_MSGTYPE PB_System_DateTime - -#define PB_System_DateTime_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, hour, 1) \ -X(a, STATIC, SINGULAR, UINT32, minute, 2) \ -X(a, STATIC, SINGULAR, UINT32, second, 3) \ -X(a, STATIC, SINGULAR, UINT32, day, 4) \ -X(a, STATIC, SINGULAR, UINT32, month, 5) \ -X(a, STATIC, SINGULAR, UINT32, year, 6) \ -X(a, STATIC, SINGULAR, UINT32, weekday, 7) -#define PB_System_DateTime_CALLBACK NULL -#define PB_System_DateTime_DEFAULT NULL - -#define PB_System_PlayAudiovisualAlertRequest_FIELDLIST(X, a) \ - -#define PB_System_PlayAudiovisualAlertRequest_CALLBACK NULL -#define PB_System_PlayAudiovisualAlertRequest_DEFAULT NULL - -#define PB_System_ProtobufVersionRequest_FIELDLIST(X, a) \ - -#define PB_System_ProtobufVersionRequest_CALLBACK NULL -#define PB_System_ProtobufVersionRequest_DEFAULT NULL - -#define PB_System_ProtobufVersionResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, major, 1) \ -X(a, STATIC, SINGULAR, UINT32, minor, 2) -#define PB_System_ProtobufVersionResponse_CALLBACK NULL -#define PB_System_ProtobufVersionResponse_DEFAULT NULL - -#define PB_System_UpdateRequest_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, update_manifest, 1) -#define PB_System_UpdateRequest_CALLBACK NULL -#define PB_System_UpdateRequest_DEFAULT NULL - -#define PB_System_UpdateResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, code, 1) -#define PB_System_UpdateResponse_CALLBACK NULL -#define PB_System_UpdateResponse_DEFAULT NULL - -#define PB_System_PowerInfoRequest_FIELDLIST(X, a) \ - -#define PB_System_PowerInfoRequest_CALLBACK NULL -#define PB_System_PowerInfoRequest_DEFAULT NULL - -#define PB_System_PowerInfoResponse_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, STRING, key, 1) \ -X(a, POINTER, SINGULAR, STRING, value, 2) -#define PB_System_PowerInfoResponse_CALLBACK NULL -#define PB_System_PowerInfoResponse_DEFAULT NULL - -extern const pb_msgdesc_t PB_System_PingRequest_msg; -extern const pb_msgdesc_t PB_System_PingResponse_msg; -extern const pb_msgdesc_t PB_System_RebootRequest_msg; -extern const pb_msgdesc_t PB_System_DeviceInfoRequest_msg; -extern const pb_msgdesc_t PB_System_DeviceInfoResponse_msg; -extern const pb_msgdesc_t PB_System_FactoryResetRequest_msg; -extern const pb_msgdesc_t PB_System_GetDateTimeRequest_msg; -extern const pb_msgdesc_t PB_System_GetDateTimeResponse_msg; -extern const pb_msgdesc_t PB_System_SetDateTimeRequest_msg; -extern const pb_msgdesc_t PB_System_DateTime_msg; -extern const pb_msgdesc_t PB_System_PlayAudiovisualAlertRequest_msg; -extern const pb_msgdesc_t PB_System_ProtobufVersionRequest_msg; -extern const pb_msgdesc_t PB_System_ProtobufVersionResponse_msg; -extern const pb_msgdesc_t PB_System_UpdateRequest_msg; -extern const pb_msgdesc_t PB_System_UpdateResponse_msg; -extern const pb_msgdesc_t PB_System_PowerInfoRequest_msg; -extern const pb_msgdesc_t PB_System_PowerInfoResponse_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define PB_System_PingRequest_fields &PB_System_PingRequest_msg -#define PB_System_PingResponse_fields &PB_System_PingResponse_msg -#define PB_System_RebootRequest_fields &PB_System_RebootRequest_msg -#define PB_System_DeviceInfoRequest_fields &PB_System_DeviceInfoRequest_msg -#define PB_System_DeviceInfoResponse_fields &PB_System_DeviceInfoResponse_msg -#define PB_System_FactoryResetRequest_fields &PB_System_FactoryResetRequest_msg -#define PB_System_GetDateTimeRequest_fields &PB_System_GetDateTimeRequest_msg -#define PB_System_GetDateTimeResponse_fields &PB_System_GetDateTimeResponse_msg -#define PB_System_SetDateTimeRequest_fields &PB_System_SetDateTimeRequest_msg -#define PB_System_DateTime_fields &PB_System_DateTime_msg -#define PB_System_PlayAudiovisualAlertRequest_fields &PB_System_PlayAudiovisualAlertRequest_msg -#define PB_System_ProtobufVersionRequest_fields &PB_System_ProtobufVersionRequest_msg -#define PB_System_ProtobufVersionResponse_fields &PB_System_ProtobufVersionResponse_msg -#define PB_System_UpdateRequest_fields &PB_System_UpdateRequest_msg -#define PB_System_UpdateResponse_fields &PB_System_UpdateResponse_msg -#define PB_System_PowerInfoRequest_fields &PB_System_PowerInfoRequest_msg -#define PB_System_PowerInfoResponse_fields &PB_System_PowerInfoResponse_msg - -/* Maximum encoded size of messages (where known) */ -/* PB_System_PingRequest_size depends on runtime parameters */ -/* PB_System_PingResponse_size depends on runtime parameters */ -/* PB_System_DeviceInfoResponse_size depends on runtime parameters */ -/* PB_System_UpdateRequest_size depends on runtime parameters */ -/* PB_System_PowerInfoResponse_size depends on runtime parameters */ -#define PB_System_DateTime_size 22 -#define PB_System_DeviceInfoRequest_size 0 -#define PB_System_FactoryResetRequest_size 0 -#define PB_System_GetDateTimeRequest_size 0 -#define PB_System_GetDateTimeResponse_size 24 -#define PB_System_PlayAudiovisualAlertRequest_size 0 -#define PB_System_PowerInfoRequest_size 0 -#define PB_System_ProtobufVersionRequest_size 0 -#define PB_System_ProtobufVersionResponse_size 12 -#define PB_System_RebootRequest_size 2 -#define PB_System_SetDateTimeRequest_size 24 -#define PB_System_UpdateResponse_size 2 - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/assets/copro.mk b/assets/copro.mk deleted file mode 100644 index eb9b83b7..00000000 --- a/assets/copro.mk +++ /dev/null @@ -1,14 +0,0 @@ -COPRO_CUBE_VERSION := 1.13.3 -COPRO_MCU_FAMILY := STM32WB5x -COPRO_STACK_BIN ?= stm32wb5x_BLE_Stack_light_fw.bin -# See __STACK_TYPE_CODES in scripts/flipper/assets/coprobin.py -COPRO_STACK_TYPE ?= ble_light -COPRO_DISCLAIMER ?= -COPRO_OB_DATA ?= ob.data -# Keep 0 for auto, or put a value from release_notes for chosen stack -COPRO_STACK_ADDR := 0 - -COPRO_BUNDLE_DIR := $(ASSETS_DIR)/core2_firmware -COPRO_CUBE_DIR := $(PROJECT_ROOT)/lib/STM32CubeWB -COPRO_FIRMWARE_DIR := $(COPRO_CUBE_DIR)/Projects/STM32WB_Copro_Wireless_Binaries/$(COPRO_MCU_FAMILY) -COPRO_STACK_BIN_PATH := $(COPRO_FIRMWARE_DIR)/$(COPRO_STACK_BIN) diff --git a/assets/icons/About/Certification1_103x23.png b/assets/icons/About/Certification1_103x23.png deleted file mode 100644 index 4713dc355ae3ee55e4d68a21d8817f3dc259ef3f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2105 zcmcIlTWl0n7@mR(v@S*^+CYfIV2B20=en~y6SlD3-O^RIEM<{G0&y;9cPG1ZVP@Lh zqWDmt#b^_`G(o@%XiSWS_yB^aA<;$+h?J;2h&56{LMjkZ0*R!0W^bT@+7~yOopa9o z=lj0%|KB<1#YD>@Pwn(t1VKEp=141ir{VMH%Pzj_}J&0ZT=qQG&N)TJ&i<5CP z3^Ho-ItwgY*OHXiWo2H$7Bryq3jzetfFq&>EvMT;A&3=m1=x0n2@EZUIN2Z;atYD4 zcmfR@7C<>KiOVEOqki5?aV*P`^H7?kNrLnd6pd4yK(YemN6SA9vRO(>XpJLQAg(e4B> zsI;^M&8))eb~#NjVMIYR3Cc^lOR5CM<70toM$ zN>mt8n)1@<6Dw3*G4l44uA=e;5D^^^#9-AZoaAwuNs^4<^9d|Fmm&p{EQQ9Q4;0Z6 z#}{lUYN~TQq4Bs7(``r8We|%5F(}Hbs)_&r0|J~sfXe}y#c7VEabAX9UJ@mS^E1HD z`HQ;X{D>j9yP0t3mu#yTGQ_B6Q&3o+%ux)$Ng%R#N@7#E2&4c`rdU>_Imt%>se-n| zQsK@KbGM_qsuYMA5J{P4QvsY-QY=m}EQ#|zKZ^&X04MXn@AvZ*hTh^08#%*@8w$)W zbNhHK98Oq9O3lF!cI%=>G!_kW6wh%u?S%k}ETjxe6QR*mO-uvA)YGo*p$xd(X4Qr@ z?ksPlWngW&l~d88I|Wg8H$@PWT{i#)D-Wx8Nb~p>RD#WC00bSwC8aRiNI7}Y0--c4 z$$z?#xSM!e>=;}6_#E;-N-w8X&WL&%z!R3h+{F;?SyUS}6?NWrhE^uS zgV}9XZv@z>-YGzb%e3H)apM#7CW6#Ru}CP{w&~K!(9{8R@_}6qZ;t-8<$3XeIUASn zncaRWeBs-~!q>3I;Qo=Pj-q?7zGAlo>uYb;Zv2B(M!12Y>7yrC{@mO6=i}daJnLgU zd!AVn1Dg*@KdnjUAKKEr+Q~2W=U(bMclm&)DQ(tWf9HiA9u{^XY}XRg}! z!-;GCk?zEtNnm)m?F{}~wxO38I9b;+@%pg~t*3vvq5qisuC+e9Yd7-c!lA*r7hm4= z#txqPz{6_Wv3Jj%>c2FlcVNPM$9z+_zpqJ1|Mxv#4He`Q8^FxvMvwQ^ x9v_{?cb(reYxt3mmA2C}Hm>bSFFB!&oUPlPtUF9}_Q~$$9*ed__BTG;^*1Y=%1!_P diff --git a/assets/icons/About/Certification1_103x56.png b/assets/icons/About/Certification1_103x56.png new file mode 100644 index 0000000000000000000000000000000000000000..6e11bbbb222cc54a3e6883f81522af25fd847e52 GIT binary patch literal 3038 zcmb7GX;@QN8V;he)ul=cf&(#HL1^|pBvP^~ic)21m5K^h9>uM#%iJVvjyO-}N0xKmZ+XA>e&;)Pb6~)- z8MaQg7z}2H*iRUY{>Gypmh}|$8~!sT2ZNd30!ihFT;k7Bz-j`ZgyTShL9In`42J7% z&;p7i5W&WQ@sNgx8)`g-!$L|PE{rZANwfkm0rJb#fgzazQblHxf~~}PFSX?wIA{Ph zhyYlFI$5LV7%l=~M!&izkxVY&MZZAyO!K)B>;1&>(;TuhB0whA_tvf_jAx(jpM7 z!5U)%ad0Za!{JaII}#i;K;zLh`jPTcA&5qVNG6bo6V0^=FaqlnVC@*AcYMa+_Z$&O z^?^J__2 zw9!ncyI7+~0F441b%(~?eg1;`N*#nw4Ip_k77ReCWYZW-JWW9Z@k}a>hK~c73Ot|y z04ktTGC(TBbd<4Nl(?}JPzR-fN?#qU9y!3qUF9SN(&k(xcBi!?b0dJ0W0-d1YQELngk)kz>pV zD2&aFa^kOg;UqR@^cyCf*Fz$J&c|Uuu3vxW~ zz037lo4rGRElu<7w-Md$kxq5Bs+Ouzwwb#lKqWf`!Wo zcZ-ktRNbS~FYLai-`)EA?qP1}@ce4utIK_>9&PexRBf~TAM ze;~o#{=mKyJ+b7z9bFZ&-@8wRo^tH`q`JdqoBQEH2N#E#gnP0A=7z}aQY7f5{8(6l zoo&pn%!;O!i``bd0*-!a^XHjciyr#Fx$_e-G&sUn9-Zr1KydedL5{gPyER~?_@O<# z%*`L;8nD>$?6x9{jo|Y;&4RLu@^5~ATk0(i(0#H~7TPAqiL<#U_I-LFGb)b%^jHqf zQ}y=kbJ@y|GM8U>UK2PR>quM`+m+S25BOoox%r-jwC8MieMwo@y1ilTTfob8cDZyG zo0wFCXRX?F!;5}cbm|`-DM>hs)@5xhyURtfWyEI>|mxxkth$^N4M&8DZ; zH)na;4_Z1c%8dlSl*|(zw8}_usp|B6ExOXcjq2QyIeY4Tx7ktapvu*_%FwpAIT5Yd z?QS+@?my}|Q)`~gb=WBPoZCHglOA`siE!NO;9$KdOaEfKn;ai_ySJmDJ$8|Q;xu(P zR5{qfCid*TzN@hz*H&o_t_i|v{+84@?M+_5ZM*j288=VA?yuQiM?UGyjI626sgqDJ zM*};bEobdNQ$}ZeT%TIo?g1Wfin)Aiw_~0hD{J8M!|Nqevt*6Xap&`$++*MGkNBwJ zhw3Qwwm|o#u3?+2I^L@lK%xA+BFE=$v-H{!yX+ zQD}p#v#xgaz37EuJA&r=NPF`4lw6VzB&q+f>N(H*Sh^*lZ`Enb24;Cl#*^MJPUL=F zT7KNkPhz? zwDvxyt9OrWi{BtpY#ww9d2p)OZhiae2R)6662q2&8=ImA|L(M&*pWzjW!3FL70)|V z`k2M$KHiSEt_@Y&clzFF+-$jv8=k?mRX5!#%3PP7m)IGy_N+tVcT!GYWBQAyLH7H7 z3eH~;Cm*oAPz}wEDOgCZGCXdJcJWPYjPWDwzx5q(vj58TgV$z;$T8bmY-%S76Kh uKZdmO;a~c@3d^&P^feXSAlN!%%<6CD5WVhLIBeW0kOj#FYVG~H|%bkw2YN{ zz-W#0KDk}Pinc3{y_kQ2^yT12! z-yS=9M0|%H9SjCTyd&H0g7*NtdbNKF{#Px3ZVbG|`m-l!21CbZLsu)q;w9Y;hM1F5 zu3L9IN3nw9GjXEA15?oFht>u|T6)mW357sMc#tp2Hsj5mdyI%A+Kl7PPTc9w1O-xd zsS0vRN9PKqg@RQyrVl~Vf-EHP0i8pFKCi5?L7Oqm%ffMJ8Z#nc6TQ%8%m_I|+|IE` zrlJCbG2y6y<0N9Snh1ub89W6caT3RHGe(do!LT^Z5*DQCXN2BV(Zjmz!<&4;C!4WA z*ZnMp1p)z6fHEm+K1NurRtzUGl0=~es+Gt(7er;PPcwrZXo4#FbxDzt5F^JcMY_!h zBaNis^E;hUVp(e{6f7AQ!6{ML;=$<0#G} zGJs;5c^<__bR;SQzN0_#y!9|r{``M7+5`Q>~g(o(rh#jB{$F^mpYsAb-fnK@QfJdzhK zXs!{%5Jy%fLs%IGB~3(V&qP{m2dY#I#Nn#qL&BnGrN@=`iJBe3!`A*cv0%}lvLy|+ zsHEv=$N^KEMqUZV2=^At388Hc6XRg)#-_=~1#V$PGhqe-N_#{L%8N9QT6w52K9wV= z)KrnQ0HGNlC;*T$+TuU=E#g~KJbHjrK}J5@5s#4&VIm)uPy{3taB@C?$1Y|Jr5QS( z{(Uk}Ch~~G|1lXXlue{bSVUAU{R^)>ax%l*!&C6M4-KR58Tb%=Qvn&)NrmsBh5J4^ zVlX`AcGxp=3(CKn__DkYiR)XFh+KF$H?jAxL${{%syj1uhl@%&C0}Y6cYyKExwpHn zVhBHLV6~&;!TMXB%*TlXOZ{k-t8~ID#GYT4p%=C~{)U=?_j^~6wf7PkZ#~R<=+o`^0P}ikr=I`3rb3S|M z1YdEvWP0_WO*2n$!O#ns;yMnUktQ=h zSDtAzBX0`oI#GUwv*$?(zcx0EIKA`Z)~)$jLQKL36-Apoab>ZG7*@JZruU!H^ e$L>l=FHe%zE}qh^O3ey=C^@o5+t&}9{Q7Uwhg>cI diff --git a/assets/icons/About/Certification2_98x33.png b/assets/icons/About/Certification2_98x33.png new file mode 100644 index 0000000000000000000000000000000000000000..49c5581c7523f2956fda218cfa9c048cf1998ef5 GIT binary patch literal 2495 zcma)7eN+=y77u<<3c9DF1uNPeM(e@FB$G)pm^lQ^7bZ%SFD0_A?JzSTQ=2gmAE?2J5Xf$#Jm7}N>SV;K-w?O!$Zhp2HA`rt! z^CZW31cr4(VoV~3%@edR3~*>DxWL$h(cSz|`k)YU5s@oohAdtmS;=X1IVKB& zqBJTjL8>BEv@}7fQb}`&1X4@KnY}J8eb=iatwkMFfl-d12T>@5bno-1ON*3OAxXc45=JzXPf}z(--R@i^+f~G#HRartn{9 zC=nD?EHTY7`81Wxv96&@EbdZc6dq01V>(oA9H|_tQ5Z~mjmfCeAc)cEPZtaU(VrQk z@Qh6jz1=tLu zJZl%c1V`&~K{tW+w%ZwSX$k@z4k=^`M5cb+!|R|yv?n)pfGm_K7suc*wM2O!{ZZrt z2BYRC$RV%?<}n!T@{!3779-yV+6_Jk9GLu$M_VRIBq4#Ys@tw&4`C)Q2QeoB`% z;R2c+T{rKuis}uK1x3ovo!8E3&XtEOMfUFLuh*G#YqJ|~=g)sLYSxvk8MnTAcT-_a zRrQuXHEce3zkkuD=YD?Cez?2yQQb{PO4jauX+C{g-JxHO)v(&?9iPYl;K zQ+uu=1A`}ytX)t2)%N4fq6g7U|GpJ+`*$6DQQzy%>HnF!|MjBk6wMp`VP}#|=eMdm zW3QfQ`>Fnr>3$m*gYUXj6D2d({q%uv=0DHxeqn;^#P`QCdsZlt|Kz*M(FaSqs1W=`??1& zmu);-rqAdrXl!qP@Amc04|ly*cW>N{o)ezkOw!CMw0~c7JgrCTE_TGn_kGyfyFIkh zN#D5^8MP#9>7H`slqp|$)3@RG|5#JS__|645+%zr&Nt17(2jq9#}(&|`Q+8^`n?~0 z>@Me84b^>LJiulR#vGSU&zMFYh&<@t&o@UsZ*7VWU0r$M>~p*=35~jvbf>iXyS?9? zI`B}p9$wS&A^Ob53ER%Rx_JE!y0K+qVT9V(d#|-6tWBNFpAzLv$@yYa_ZoN#+Nq#Kx~p6 zI1|4u?Z2nG3f~<#*7fmndV}-0?)(p`($JL8^l(qG4Ox QDWC=hPgg&ebxsLQ0KZ@&0{{R3 delta 117 zcmbQmIE!(D1Sba*0|Nt7K*Xzw0TPMqC7!;n?9W(vdBwyRURZV!C}rvC;us=vIr-21 zvkmM9ip3J%h2G9jE`%5)zH&}8PBazPJH$~g6~l3JqYqC7Blj|aO@=Hb#*g^L7~BqW Vzv1mptp*yx;OXk;vd$@?2>@J;C1U^p diff --git a/assets/icons/Common/Loading_24/frame_01.png b/assets/icons/Common/Loading_24/frame_01.png index 438f971f174e7b2e3327d009ec6099fe6a426fb7..d1f35692590a934aa850a77b71c7923fc1b1b360 100644 GIT binary patch delta 157 zcmaFKc!+U=gasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`C=uoA>Eak7aXFcR@!NlSi3kZ6i5dUx6B1Gi5)yb=lXMlt3KJ4u zWF#aMuxMRkN)prvV@mQ@$jfM0;eJTL*deX)OiDrm14Ca2ZOd;zB)j)8m322!%tQf3 zH#TkoL=Z+Pz&6`Uj$qJ%2Vs*_01Fx8{XN(r8ZcHpGwJl8_2fM<3xNRpzwH@8QUEd2 zOa!^7$=3oT+Q~;3&dj8uci~3+v-lxkrTR!8a{5v~DbMiz00000NkvXXu0mjfk;YV( diff --git a/assets/icons/Common/Loading_24/frame_02.png b/assets/icons/Common/Loading_24/frame_02.png index 3455cd4043ff7ac84d67b36e625f47e95a500710..b1617692131bd61a713453f0a025810acb8e446b 100644 GIT binary patch delta 157 zcmey$c!+U=gasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`C=uoA>Eak7aXFcR@!NlSi3kZ6i5dUx6B1Gi8WMCB#0nD1YyN#fQ4-9!H!66)8RUE(kZ|!K7?6F2(b0G?-4y@ z2|&%Xf)OO$Eak7aXFcR@!NlSi3kZ6i5dUx6B1Gi91;ZC+1mQp*x1|` zD5)xlH74n@bw~v8t?^^%*xF!mg)xWigwBMSJUl!Mr3SoRnZ1h@fW|U-y85}Sb4q9e E0GClOoB#j- delta 203 zcmV;+05t!=0q+5j7zqdl0002scRl!#P#AxqNklF$m~Q>jIf_JFv=i;_bUwcdGsc7`bHf zaRF=CD3>Uwumc2Pi&FpuVT;p%6~Y!z0aVd|;d)*_1I)i%Q={*;6Yb654*`n%ogNxtPCID?lqLWG002ovPDHLk FV1oH}SFHd5 diff --git a/assets/icons/Common/Loading_24/frame_04.png b/assets/icons/Common/Loading_24/frame_04.png index 12d127e0cc5fb78c4735b8d647cdefddc84bc50d..7f55b0df457223e99a1eefbb4fbc5d1ad75dd431 100644 GIT binary patch delta 153 zcmaFGxQ}sygasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`C=ur9>Eak7aXFcR@!NlSi3kZ6i5dUx6B1Gi91imE^78QXIkHl3ah9v0ZlAPbnZf{>+0tKq}f@Y z(gYC%c?8fESrGJv!9CCr)Vu`f3I^z^E0YcZwD~edAt~T(u8k2$2=L4+kkS=-kajYH zCC~h`IoL@+-cCNca4M6U{pW79oyDI5I@No60EE9*J3{~X-T(jq07*qoM6N<$g0Lb~ Av>Eak7aap%#Bj*7H5mtZ2nvIhZ$_jd}tdu#aD5DU2?bqTb zoMOjKk00c| R(pR7j44$rjF6*2UngH6`K5PI0 delta 210 zcmV;@04@K^0rmlq7zqdl0002scRl!#P#AxxNklgg-dRQRf}Bv~~g{r3ZS4YcM&fM&2u$?vGkP7<9Lul!pGAniV> zk%+ICqXa8+dX|!4bruF#&D{VxK#RE>z#*1rn>yq)fM-F56VSTT3xYL+uIKrC$p8QV M07*qoM6N<$g1B8-pa1{> diff --git a/assets/icons/Common/Loading_24/frame_06.png b/assets/icons/Common/Loading_24/frame_06.png index a876adc541e72d22b13829e4888c44645ea092e7..3354ecda423dfc60a6836f8541f78b8f0bdde6bf 100644 GIT binary patch delta 147 zcmaFGxPx(mgasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`C=p=o>Eak7aXI+_n~=l}2_}gh5|1S73|UNy3|TA~H*yJhyBM+< wtWDyWz;a2;;g%+s4u2SX2>+#aCJ6}!?gZ{W-rKQZK;sxZUHx3vIVCg!0KWAq_y7O^ delta 198 zcmV;%06G7-0qOye7zqdl0002scRl!#P#AxlNklHNbP4FglEgAC zXswJ&aKwD-WXtbG?PM+HPWCj9CVVvII+K4FoVVsvGrbTfGXMYp07*qoM6N<$f@V%t A3;+NC diff --git a/assets/icons/Common/Loading_24/frame_07.png b/assets/icons/Common/Loading_24/frame_07.png index 04049ebd2b4b66a1dc3f8190b215bb3bc4dd9e4a..70bb37f699a73101bf7a6eabb14418a9eeafec35 100644 GIT binary patch delta 166 zcmey#c$#s7gasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`D3R>v>Eak7aas1vM&1Sk9+!*$OHPPQZB1zJnK(;JIhBKLL9%ZD zA;*tjR$FT{c+L#4{=sXw0r>%t7zqdl0002scRl!#P#Ax!NklkjlCH5cma>+=HY6`tKu<6u@e%2Z6q5j1>e1 zj7pk8wl>+?gJtSLq>ybdkmi3>W?98da-KC;M1%fy~fDm+K}fiZik5PPFo8;^msymB-A>r7-b_6DyEXP}pq6c!0?i%mngmDsl^a zeXTq)i%as0D(zsxK#8K1G^^m$LL?!D$s#Pf>lO5oglzQDmD%WHGZCWBCAB!YD6^m> zGd~Y(21GQ-#SO><>azms%uOvx1o7-E3KEmEQ%e+5^HOY;ij?f_e6KQ*jJQ;u3cWdg^O zza5XX16CNTh!&(StIpZ<`Ay!pY_=Qu5nE1$wzW6jY))`{F@sfS=2N|MQ=H$vh-l92 ze)@mjwa;2}=kkeF?cLZsdEPO;xJAbf)VKAV&FOnGKkKnXoN&$FGjC_x%KzA>P?o-9 zy?Rpo2YK})xhLi=KO%bK`76FRPfZJX>s~wXTr{uR!lAg{XVa}onjR-rPKS9`O?ti7 z{^ZrpnP+#c&-$;n+d4G9WwrYao6G!Jo1))GsjoelF~{aY65H(VtHBo6^21&U@_2t` j)N{Qrwg0&9f|? zmrwuLFz*m^mCSed`ZQ%nyL$||sWR!;**>)hEVy~^e0B8nw;!F_j`kSe3>USMvG^Y0 z*;aaZ>huR%rGi_}u$=Kb(9tikIXdHQSl-2H-#_!oZRKxvO!%OB{@|rkp)RxYZMb$z zhEFktarA?oq2R^ILHA5tF{s z)>Zaz|E+Rl(SDMp_||(cXQ{KW@or)#=C`d0u~N2H)4DIj`^cS?v8W#qX{1v&a5Ep=O4Qzw~!M zb5+rm7T*1t?`CpVFN-zP^v>iJyCmLo=AD-jGZBlmT;aO>ckpGmD_q_4=R5a^9JuUq zI`6vjuItXz6(5Pd-V>3sH|GDu(p!sC_I7OVDZ4+_X^ZYI@d+h8cg3@|dbzq-SvoKC zE|uK0HaY#HoWI+ZA4ywXay%z$yjc`?ueMq*{`H#;m*>69jf?p?+beE|IRDe`y|D#H zntxR3mGE{|>&93={h1Yg>twfTzLxh?=1n)BEt&8n`@mbKr1n)G_DDQlJTEz=QvV;L Y{&7Qo$7 application_list:tuple(str)). To specify application set to use in a build, set `FIRMWARE_APP_SET` to its name. +For example, to build firmware image with unit tests, run `./fbt FIRMWARE_APP_SET=unit_tests`. + +Check out `fbt_options.py` for details. diff --git a/fbt b/fbt new file mode 100755 index 00000000..81193a46 --- /dev/null +++ b/fbt @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +if [[ -d .git ]]; then + echo "Updating git submodules" + git submodule update --init +fi + +SCRIPTDIR="$( dirname -- "$0"; )"; +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" +python3 ${SCRIPTDIR}/lib/scons/scripts/scons.py ${SCONS_DEFAULT_FLAGS} "$@" diff --git a/fbt.cmd b/fbt.cmd new file mode 100644 index 00000000..7711e44b --- /dev/null +++ b/fbt.cmd @@ -0,0 +1,8 @@ +@echo off +if exist ".git" ( + echo Prepairing git submodules + git submodule update --init +) + +set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" +python lib/scons/scripts/scons.py %SCONS_DEFAULT_FLAGS% %* diff --git a/fbt_options.py b/fbt_options.py new file mode 100644 index 00000000..ddeff048 --- /dev/null +++ b/fbt_options.py @@ -0,0 +1,72 @@ +import posixpath + + +# Default hardware target +TARGET_HW = 7 + +# Optimization flags +## Optimize for size +COMPACT = 0 +## Optimize for debugging experience +DEBUG = 1 + +# Suffix to add to files when building distribution. +# If OS environment has DIST_SUFFIX set, it will be used instead.. +DIST_SUFFIX = "local" + +# Coprocessor firmware +COPRO_OB_DATA = "scripts/ob.data" + +# Must match lib/STM32CubeWB version +COPRO_CUBE_VERSION = "1.13.3" + +COPRO_CUBE_DIR = "lib/STM32CubeWB" + +# Default radio stack +COPRO_STACK_BIN = "stm32wb5x_BLE_Stack_light_fw.bin" +# Firmware also supports "ble_full", but it might not fit into debug builds +COPRO_STACK_TYPE = "ble_light" + +# Leave 0 to lets scripts automatically calculate it +COPRO_STACK_ADDR = "0x0" + +# If you override COPRO_CUBE_DIR on commandline, override this aswell +COPRO_STACK_BIN_DIR = posixpath.join( + COPRO_CUBE_DIR, + "Projects", + "STM32WB_Copro_Wireless_Binaries", + "STM32WB5x", +) + +# Supported toolchain versions +FBT_TOOLCHAIN_VERSIONS = (" 10.3.",) + +OPENOCD_OPTS = '-f interface/stlink.cfg -c "transport select hla_swd" -f debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init"' + +SVD_FILE = "debug/STM32WB55_CM4.svd" + +FIRMWARE_APPS = { + "default": ( + "crypto_start", + # Svc + "basic_services", + # Apps + "basic_apps", + "updater_app", + "archive", + # Settings + "passport", + "system_settings", + "about", + # Plugins + "basic_plugins", + # Debug + "debug_apps", + ), + "unit_tests": ( + "basic_services", + "unit_tests", + ), +} + +FIRMWARE_APP_SET = "default" diff --git a/firmware.scons b/firmware.scons new file mode 100644 index 00000000..3652c298 --- /dev/null +++ b/firmware.scons @@ -0,0 +1,227 @@ +Import("ENV", "fw_build_meta") + +import os + + +# Building initial C environment for libs +env = ENV.Clone( + tools=["compilation_db", "fwbin", "openocd", "fbt_apps"], + COMPILATIONDB_USE_ABSPATH=True, + BUILD_DIR=fw_build_meta["build_dir"], + IS_BASE_FIRMWARE=fw_build_meta["type"] == "firmware", + FW_FLAVOR=fw_build_meta["flavor"], + PLUGIN_ELF_DIR="${BUILD_DIR}", + LIB_DIST_DIR="${BUILD_DIR}/lib", + LINT_SOURCES=[ + "applications", + ], + LIBPATH=[ + "${LIB_DIST_DIR}", + ], + CPPPATH=[ + "#/core", + "#/applications", + "#/firmware/targets/f${TARGET_HW}/ble_glue", + "#/firmware/targets/f${TARGET_HW}/fatfs", + "#/firmware/targets/f${TARGET_HW}/furi_hal", + "#/firmware/targets/f${TARGET_HW}/Inc", + "#/firmware/targets/furi_hal_include", + ], + # Specific flags for building libraries - always do optimized builds + FW_LIB_OPTS={ + "Default": { + "CCFLAGS": [ + "-Os", + ], + "CPPDEFINES": [ + "NDEBUG", + "FURI_NDEBUG", + ], + # You can add other entries named after libraries + # If they are present, they have precedence over Default + } + }, +) + + +def ApplyLibFlags(env): + flags_to_apply = env["FW_LIB_OPTS"].get( + env.get("FW_LIB_NAME"), + env["FW_LIB_OPTS"]["Default"], + ) + # print("Flags for ", env.get("FW_LIB_NAME", "Default"), flags_to_apply) + env.MergeFlags(flags_to_apply) + + +env.AddMethod(ApplyLibFlags) + +Export("env") + +if not env["VERBOSE"]: + env.SetDefault( + HEXCOMSTR="\tHEX\t${TARGET}", + BINCOMSTR="\tBIN\t${TARGET}", + DFUCOMSTR="\tDFU\t${TARGET}", + OOCDCOMSTR="\tFLASH\t${SOURCE}", + ) + + +if fw_build_meta["type"] == "updater": + env.Append( + FIRMWARE_BUILD_CFG="updater", + RAM_EXEC=True, + CPPDEFINES=[ + "FURI_RAM_EXEC", + ], + ) +else: + env.Append( + FIRMWARE_BUILD_CFG="firmware", + RAM_EXEC=False, + ) +# print(env.Dump()) + + +# Invoke child SCopscripts to populate global `env` + build their own part of the code +lib_targets = env.BuildModules( + [ + "lib", + "assets", + "firmware", + "core", + ], +) + + +# Now, env is fully set up with everything to build apps +fwenv = env.Clone() + +# Set up additional app-specific build flags +SConscript("site_scons/firmwareopts.scons", exports={"ENV": fwenv}) + +# Set up app configuration +if env["IS_BASE_FIRMWARE"]: + fwenv.Append(APPS=fwenv["FIRMWARE_APPS"].get(fwenv.subst("$FIRMWARE_APP_SET"))) +else: + fwenv.Append(APPS=["updater"]) + +if extra_int_apps := GetOption("extra_int_apps"): + for extra_int_app in extra_int_apps.split(","): + fwenv.Append(APPS=[extra_int_app]) + +fwenv.LoadApplicationManifests() +fwenv.PrepareApplicationsBuild() + +# Build external apps +extapps = SConscript("applications/extapps.scons", exports={"ENV": fwenv}) + + +# Add preprocessor definitions for current set of apps +fwenv.AppendUnique( + CPPDEFINES=fwenv["APPBUILD"].get_apps_cdefs(), +) + + +# Build applications.c for selected services & apps + +# Depends on virtual value-only node, so it only gets rebuilt when set of apps changes +apps_c = fwenv.ApplicationsC( + "applications/applications.c", + Value(fwenv["APPS"]), +) + +sources = [apps_c] +# Gather sources only from app folders from current configuration +for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): + sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder)) + + +fwenv.AppendUnique( + LINKFLAGS=[ + "-specs=nano.specs", + "-specs=nosys.specs", + "-Wl,--start-group", + "-lstdc++", + "-lsupc++", + "-Wl,--end-group", + "-Wl,--gc-sections", + "-Wl,--undefined=uxTopUsedPriority", + "-Wl,--wrap,_malloc_r", + "-Wl,--wrap,_free_r", + "-Wl,--wrap,_calloc_r", + "-Wl,--wrap,_realloc_r", + "-u", + "_printf_float", + "-n", + ], +) + +# Debug +# print(fwenv.Dump()) + +# Full firmware definition + +fwelf = fwenv["FW_ELF"] = fwenv.Program( + "${FIRMWARE_BUILD_CFG}", + sources, + LIBS=[ + "flipper${TARGET_HW}", + "core", + "freertos", + "stm32cubewb", + "hwdrivers", + "fatfs", + "littlefs", + "subghz", + "flipperformat", + "toolbox", + "microtar", + "usb_stm32", + "st25rfal002", + "infrared", + "appframe", + "assets", + "misc", + # 2nd round + "flipperformat", + "toolbox", + ], +) + +# Make it depend on everything child builders returned +Depends(fwelf, lib_targets) +AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) + + +fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") +fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") +fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") +# Default(dfu) +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu) + +fwdump = fwenv.ObjDump("${FIRMWARE_BUILD_CFG}") +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_list", fwdump) + +# Additional FW-related pseudotargets +flash = fwenv["FW_FLASH"] = fwenv.OOCDFlashCommand( + "${FIRMWARE_BUILD_CFG}", + OPENOCD_COMMAND='-c "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}"', +) +if fwenv["FORCE"]: + AlwaysBuild(flash) +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) +if fwenv["IS_BASE_FIRMWARE"]: + Alias("flash", flash) + + +# Compile DB generation +fwcdb = fwenv["FW_CDB"] = fwenv.CompilationDatabase("compile_commands.json") +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb) + + +artifacts = [fwhex, fwbin, fwdfu, env["FW_VERSION_JSON"]] +fwenv["FW_ARTIFACTS"] = artifacts + +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", artifacts) + +Return("fwenv") diff --git a/firmware/Makefile b/firmware/Makefile deleted file mode 100644 index efa185ca..00000000 --- a/firmware/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -MAKEFILE_DIR := $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) -PROJECT_ROOT := $(abspath $(MAKEFILE_DIR)/..) - -include $(PROJECT_ROOT)/make/base.mk -include $(PROJECT_ROOT)/make/freertos-heap.mk -include $(PROJECT_ROOT)/assets/assets.mk -include $(PROJECT_ROOT)/core/core.mk -include $(PROJECT_ROOT)/applications/applications.mk -include $(PROJECT_ROOT)/lib/lib.mk - -CFLAGS += -I$(PROJECT_ROOT) -Itargets/furi_hal_include -CFLAGS += -Werror -Wno-address-of-packed-member -CPPFLAGS += -Werror - -include $(PROJECT_ROOT)/make/defaults.mk -TARGET_DIR = targets/$(TARGET) -include $(TARGET_DIR)/target.mk - -ifeq ($(RAM_EXEC), 0) -PROJECT := firmware -else -PROJECT := updater -endif - -include $(PROJECT_ROOT)/make/git.mk -include $(PROJECT_ROOT)/make/toolchain.mk -include $(PROJECT_ROOT)/make/rules.mk diff --git a/firmware/ReadMe.md b/firmware/ReadMe.md index 38271fd2..d2baedfd 100644 --- a/firmware/ReadMe.md +++ b/firmware/ReadMe.md @@ -19,37 +19,4 @@ Target independent code and headers in `target/include` folders. More details in # Building -## With dev docker image: - -`docker-compose exec dev make -C firmware` - -## With toolchain installed in path: - -`make -C firmware` - -## Build Options - -- `DEBUG` - 0/1 - enable or disable debug build. Default is 1. -- `COMPACT` - 0/1 - enable or disable compiler optimizations. Significantly reduces binary size. Default is 0. -- `TARGET` - string - target to build. Default is `f7`. -- `RAM_EXEC` - 0/1 - whether to build full firmware or RAM-based stage for firmware update. 0 is default, builds firmware. - -# Building self-update package - -`make DEBUG=0 COMPACT=1 updater_package` - -# Flashing - -Using SWD (STLink): - -`make -C firmware flash` - -Or use DFU (USB): - -`make -C firmware upload` - -# Debug - -Using SWD (STLink): - -`make -C firmware debug` +Check out `documentation/fbt.md` on how to build and flash firmware. \ No newline at end of file diff --git a/firmware/SConscript b/firmware/SConscript new file mode 100644 index 00000000..8dade34e --- /dev/null +++ b/firmware/SConscript @@ -0,0 +1,14 @@ +Import("env") + +env.Append(LINT_SOURCES=["firmware"]) + +libenv = env.Clone(FW_LIB_NAME="flipper${TARGET_HW}") +libenv.ApplyLibFlags() + + +sources = ["targets/f${TARGET_HW}/startup_stm32wb55xx_cm4.s"] +sources += libenv.GlobRecursive("*.c") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/firmware/targets/f7/application-ext.ld b/firmware/targets/f7/application-ext.ld new file mode 100644 index 00000000..45fe431c --- /dev/null +++ b/firmware/targets/f7/application-ext.ld @@ -0,0 +1,37 @@ +SECTIONS +{ + .text 0x00000000 : + { + *(.text) + *(.text.*) + } + + .rodata : + { + *(.rodata) + *(.rodata1) + *(.rodata.*) + } + + .data : + { + *(.data) + *(.data1) + *(.data.*) + } + + .bss : + { + *(.bss) + *(.bss.*) + *(.sbss) + *(.sbss.*) + *(COMMON) + } + + /DISCARD/ : + { + *(.comment) + *(.comment.*) + } +} diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index dd3fc280..6fa3dbd0 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -113,13 +113,34 @@ BleGlueStatus ble_glue_get_c2_status() { return ble_glue->status; } +static const char* ble_glue_get_reltype_str(const uint8_t reltype) { + static char relcode[3] = {0}; + switch(reltype) { + case INFO_STACK_TYPE_BLE_FULL: + return "F"; + case INFO_STACK_TYPE_BLE_HCI: + return "H"; + case INFO_STACK_TYPE_BLE_LIGHT: + return "L"; + case INFO_STACK_TYPE_BLE_BEACON: + return "Be"; + case INFO_STACK_TYPE_BLE_BASIC: + return "Ba"; + case INFO_STACK_TYPE_BLE_FULL_EXT_ADV: + return "F+"; + case INFO_STACK_TYPE_BLE_HCI_EXT_ADV: + return "H+"; + default: + snprintf(relcode, sizeof(relcode), "%X", reltype); + return relcode; + } +} + static void ble_glue_update_c2_fw_info() { WirelessFwInfo_t wireless_info; SHCI_GetWirelessFwInfo(&wireless_info); BleGlueC2Info* local_info = &ble_glue->c2_info; - local_info->VersionMajor = wireless_info.VersionMajor; - local_info->VersionMinor = wireless_info.VersionMinor; local_info->VersionMajor = wireless_info.VersionMajor; local_info->VersionMinor = wireless_info.VersionMinor; local_info->VersionSub = wireless_info.VersionSub; @@ -132,6 +153,14 @@ static void ble_glue_update_c2_fw_info() { local_info->MemorySizeFlash = wireless_info.MemorySizeFlash; local_info->StackType = wireless_info.StackType; + snprintf( + local_info->StackTypeString, + BLE_GLUE_MAX_VERSION_STRING_LEN, + "%d.%d.%d.%s", + local_info->VersionMajor, + local_info->VersionMinor, + local_info->VersionSub, + ble_glue_get_reltype_str(local_info->StackType)); local_info->FusVersionMajor = wireless_info.FusVersionMajor; local_info->FusVersionMinor = wireless_info.FusVersionMinor; diff --git a/firmware/targets/f7/ble_glue/ble_glue.h b/firmware/targets/f7/ble_glue/ble_glue.h index fe43ae09..bd2588a0 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.h +++ b/firmware/targets/f7/ble_glue/ble_glue.h @@ -13,6 +13,7 @@ typedef enum { BleGlueC2ModeStack, } BleGlueC2Mode; +#define BLE_GLUE_MAX_VERSION_STRING_LEN 20 typedef struct { BleGlueC2Mode mode; /** @@ -28,6 +29,7 @@ typedef struct { uint8_t MemorySizeSram1; /*< Multiple of 1K */ uint8_t MemorySizeFlash; /*< Multiple of 4K */ uint8_t StackType; + char StackTypeString[BLE_GLUE_MAX_VERSION_STRING_LEN]; /** * Fus Info */ diff --git a/firmware/targets/f7/ble_glue/dev_info_service.c b/firmware/targets/f7/ble_glue/dev_info_service.c index 4adfce59..d6d1e479 100755 --- a/firmware/targets/f7/ble_glue/dev_info_service.c +++ b/firmware/targets/f7/ble_glue/dev_info_service.c @@ -5,6 +5,7 @@ #include #include #include +#include #define TAG "BtDevInfoSvc" @@ -15,15 +16,14 @@ typedef struct { uint16_t firmware_rev_char_handle; uint16_t software_rev_char_handle; uint16_t rpc_version_char_handle; + string_t version_string; + char hardware_revision[4]; } DevInfoSvc; static DevInfoSvc* dev_info_svc = NULL; static const char dev_info_man_name[] = "Flipper Devices Inc."; static const char dev_info_serial_num[] = "1.0"; -static const char dev_info_firmware_rev_num[] = TOSTRING(TARGET); -static const char dev_info_software_rev_num[] = GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM - " " BUILD_DATE; static const char dev_info_rpc_version[] = TOSTRING(PROTOBUF_MAJOR_VERSION.PROTOBUF_MINOR_VERSION); static const uint8_t dev_info_rpc_version_uuid[] = @@ -31,6 +31,18 @@ static const uint8_t dev_info_rpc_version_uuid[] = void dev_info_svc_start() { dev_info_svc = malloc(sizeof(DevInfoSvc)); + string_init_printf( + dev_info_svc->version_string, + "%s %s %s %s", + version_get_githash(NULL), + version_get_gitbranch(NULL), + version_get_gitbranchnum(NULL), + version_get_builddate(NULL)); + snprintf( + dev_info_svc->hardware_revision, + sizeof(dev_info_svc->hardware_revision), + "%d", + version_get_target(NULL)); tBleStatus status; // Add Device Information Service @@ -77,7 +89,7 @@ void dev_info_svc_start() { dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(dev_info_firmware_rev_num), + strlen(dev_info_svc->hardware_revision), CHAR_PROP_READ, ATTR_PERMISSION_AUTHEN_READ, GATT_DONT_NOTIFY_EVENTS, @@ -92,7 +104,7 @@ void dev_info_svc_start() { dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(dev_info_software_rev_num), + string_size(dev_info_svc->version_string), CHAR_PROP_READ, ATTR_PERMISSION_AUTHEN_READ, GATT_DONT_NOTIFY_EVENTS, @@ -140,8 +152,8 @@ void dev_info_svc_start() { dev_info_svc->service_handle, dev_info_svc->firmware_rev_char_handle, 0, - strlen(dev_info_firmware_rev_num), - (uint8_t*)dev_info_firmware_rev_num); + strlen(dev_info_svc->hardware_revision), + (uint8_t*)dev_info_svc->hardware_revision); if(status) { FURI_LOG_E(TAG, "Failed to update firmware revision char: %d", status); } @@ -149,8 +161,8 @@ void dev_info_svc_start() { dev_info_svc->service_handle, dev_info_svc->software_rev_char_handle, 0, - strlen(dev_info_software_rev_num), - (uint8_t*)dev_info_software_rev_num); + string_size(dev_info_svc->version_string), + (uint8_t*)string_get_cstr(dev_info_svc->version_string)); if(status) { FURI_LOG_E(TAG, "Failed to update software revision char: %d", status); } @@ -168,6 +180,7 @@ void dev_info_svc_start() { void dev_info_svc_stop() { tBleStatus status; if(dev_info_svc) { + string_clear(dev_info_svc->version_string); // Delete service characteristics status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->man_name_char_handle); diff --git a/firmware/targets/f7/ble_glue/dev_info_service.h b/firmware/targets/f7/ble_glue/dev_info_service.h index 2faac8a6..8cce20a6 100644 --- a/firmware/targets/f7/ble_glue/dev_info_service.h +++ b/firmware/targets/f7/ble_glue/dev_info_service.h @@ -7,12 +7,6 @@ extern "C" { #endif -#define DEV_INFO_MANUFACTURER_NAME "Flipper Devices Inc." -#define DEV_INFO_SERIAL_NUMBER "1.0" -#define DEV_INFO_FIRMWARE_REVISION_NUMBER TARGET -#define DEV_INFO_SOFTWARE_REVISION_NUMBER \ - GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE - void dev_info_svc_start(); void dev_info_svc_stop(); diff --git a/firmware/targets/f7/ble_glue/tl_dbg_conf.h b/firmware/targets/f7/ble_glue/tl_dbg_conf.h index 1f09b7e4..ce58af32 100644 --- a/firmware/targets/f7/ble_glue/tl_dbg_conf.h +++ b/firmware/targets/f7/ble_glue/tl_dbg_conf.h @@ -33,7 +33,6 @@ extern "C" { #include "app_conf.h" /* required as some configuration used in dbg_trace.h are set there */ #include "dbg_trace.h" #include "hw_if.h" -#include /** * Enable or Disable traces diff --git a/firmware/targets/f7/target.mk b/firmware/targets/f7/target.mk deleted file mode 100644 index 8e58a71c..00000000 --- a/firmware/targets/f7/target.mk +++ /dev/null @@ -1,162 +0,0 @@ -TOOLCHAIN = arm - -FLASH_ADDRESS = 0x08000000 - -RAM_EXEC ?= 0 -ifeq ($(RAM_EXEC), 1) -CFLAGS += -DFURI_RAM_EXEC -DVECT_TAB_SRAM -DFLIPPER_STREAM_LITE -else -LDFLAGS += -u _printf_float -endif - -DEBUG_RTOS_THREADS ?= 1 -ifeq ($(DEBUG_RTOS_THREADS), 1) -OPENOCD_OPTS = -f interface/stlink.cfg -c "transport select hla_swd" -f ../debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init" -else -OPENOCD_OPTS = -f interface/stlink.cfg -c "transport select hla_swd" -f ../debug/stm32wbx.cfg -c "init" -endif - -MCU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard - -# Warnings configuration -CFLAGS += -Wall -Wextra -Wredundant-decls -Wdouble-promotion - -CFLAGS += $(MCU_FLAGS) -DSTM32WB55xx -fdata-sections -ffunction-sections -fsingle-precision-constant -LDFLAGS += $(MCU_FLAGS) -specs=nosys.specs -specs=nano.specs - -CPPFLAGS += -fno-rtti -fno-use-cxa-atexit -fno-exceptions -LDFLAGS += -Wl,--start-group -lstdc++ -lsupc++ -Wl,--end-group - -HARDWARE_TARGET = 7 - -MXPROJECT_DIR = $(TARGET_DIR) - -# Entry Point -ASM_SOURCES += $(MXPROJECT_DIR)/startup_stm32wb55xx_cm4.s - -# STM32WB HAL -CUBE_DIR = ../lib/STM32CubeWB -CFLAGS += \ - -DUSE_FULL_LL_DRIVER \ - -DUSE_FULL_ASSERT \ - -DHAVE_FREERTOS -CFLAGS += \ - -I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc \ - -I$(CUBE_DIR)/Drivers/CMSIS/Device/ST \ - -I$(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Include \ - -I$(CUBE_DIR)/Drivers/CMSIS/Include -C_SOURCES += \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_adc.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_comp.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_dma.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lptim.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rtc.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lpuart.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c \ - $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rng.c - -# FreeRTOS -CFLAGS += \ - -I$(LIB_DIR)/FreeRTOS-Kernel/include \ - -I$(LIB_DIR)/FreeRTOS-Kernel/portable/GCC/ARM_CM4F \ - -I$(LIB_DIR)/FreeRTOS-glue/ - -C_SOURCES += \ - $(LIB_DIR)/FreeRTOS-Kernel/event_groups.c \ - $(LIB_DIR)/FreeRTOS-Kernel/list.c \ - $(LIB_DIR)/FreeRTOS-Kernel/queue.c \ - $(LIB_DIR)/FreeRTOS-Kernel/stream_buffer.c \ - $(LIB_DIR)/FreeRTOS-Kernel/tasks.c \ - $(LIB_DIR)/FreeRTOS-Kernel/timers.c \ - $(LIB_DIR)/FreeRTOS-Kernel/portable/GCC/ARM_CM4F/port.c \ - $(LIB_DIR)/FreeRTOS-glue/cmsis_os2.c \ - -# BLE glue -CFLAGS += \ - -I$(TARGET_DIR)/ble_glue \ - -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN \ - -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble \ - -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core \ - -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/template \ - -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities \ - -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread \ - -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl \ - -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci -C_SOURCES += \ - $(wildcard $(TARGET_DIR)/ble_glue/*.c) \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/otp.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/stm_list.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/dbg_trace.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/svc/Src/svc_ctl.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hci_le.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl_if.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl_if.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c - -# USB stack -CFLAGS += \ - -DSTM32WB \ - -DUSB_PMASIZE=0x400 - -# Furi HAL -FURI_HAL_OS_DEBUG ?= 0 -ifeq ($(FURI_HAL_OS_DEBUG), 1) -CFLAGS += -DFURI_HAL_OS_DEBUG -endif - -FURI_HAL_USB_VCP_DEBUG ?= 0 -ifeq ($(FURI_HAL_USB_VCP_DEBUG), 1) -CFLAGS += -DFURI_HAL_USB_VCP_DEBUG -endif - -ifeq ($(FURI_HAL_POWER_DEEP_SLEEP_ENABLED), 1) -CFLAGS += -DFURI_HAL_POWER_DEEP_SLEEP_ENABLED -endif - -FURI_HAL_SUBGHZ_TX_GPIO ?= 0 -ifneq ($(FURI_HAL_SUBGHZ_TX_GPIO), 0) -CFLAGS += -DFURI_HAL_SUBGHZ_TX_GPIO=$(FURI_HAL_SUBGHZ_TX_GPIO) -endif - -ifeq ($(INVERT_RFID_IN), 1) -CFLAGS += -DINVERT_RFID_IN -endif - -ifeq ($(BLE_GLUE_DEBUG), 1) -CFLAGS += -DBLE_GLUE_DEBUG -endif - -FURI_HAL_DIR = $(TARGET_DIR)/furi_hal -CFLAGS += -I$(FURI_HAL_DIR) -C_SOURCES += $(wildcard $(FURI_HAL_DIR)/*.c) - -# Other -CFLAGS += \ - -I$(MXPROJECT_DIR)/Inc \ - -I$(MXPROJECT_DIR)/fatfs -C_SOURCES += \ - $(wildcard $(MXPROJECT_DIR)/Src/*.c) \ - $(wildcard $(MXPROJECT_DIR)/fatfs/*.c) - -ifeq ($(RAM_EXEC), 1) -LDFLAGS += -T$(MXPROJECT_DIR)/stm32wb55xx_ram_fw.ld -else # RAM_EXEC -# Linker options -LDFLAGS += -T$(MXPROJECT_DIR)/stm32wb55xx_flash.ld -endif # RAM_EXEC - -SVD_FILE = ../debug/STM32WB55_CM4.svd diff --git a/lib/SConscript b/lib/SConscript new file mode 100644 index 00000000..ee8b8356 --- /dev/null +++ b/lib/SConscript @@ -0,0 +1,78 @@ +Import("env") + +env.Append( + LINT_SOURCES=[ + "lib/app-scened-template", + "lib/digital_signal", + "lib/drivers", + "lib/flipper_format", + "lib/infrared", + "lib/nfc_protocols", + "lib/one_wire", + "lib/ST25RFAL002", + "lib/subghz", + "lib/toolbox", + "lib/u8g2", + "lib/update_util", + ] +) + +env.Append( + CPPPATH=[ + "#/", + "#/lib", # TODO: remove! + "#/lib/mlib", + # Ugly hack + "${BUILD_DIR}/assets/compiled", + ], + CPPDEFINES=[ + '"M_MEMORY_FULL(x)=abort()"', + ], +) + + +# drivers +# fatfs +# flipper_format +# infrared +# littlefs +# subghz +# toolbox +# misc +# digital_signal +# fnv1a-hash +# micro-ecc +# microtar +# nfc_protocols +# one_wire +# qrcode +# u8g2 +# update_util +# heatshrink +# nanopb +# apps +# app-scened-template +# callback-connector +# app-template + + +libs = env.BuildModules( + [ + "STM32CubeWB", + "freertos", + "microtar", + "toolbox", + "ST25RFAL002", + "libusb_stm32", + "drivers", + "fatfs", + "flipper_format", + "infrared", + "littlefs", + "subghz", + "appframe", + "misc", + ], +) + +Return("libs") diff --git a/lib/ST25RFAL002/SConscript b/lib/ST25RFAL002/SConscript new file mode 100644 index 00000000..d86d2d00 --- /dev/null +++ b/lib/ST25RFAL002/SConscript @@ -0,0 +1,19 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/ST25RFAL002", + "#/lib/ST25RFAL002/include", + "#/lib/ST25RFAL002/source/st25r3916", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="st25rfal002") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons new file mode 100644 index 00000000..02618ae7 --- /dev/null +++ b/lib/STM32CubeWB.scons @@ -0,0 +1,66 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/STM32CubeWB/Drivers/CMSIS/Device/ST", + "#/lib/STM32CubeWB/Drivers/CMSIS/Device/ST/STM32WBxx/Include", + "#/lib/STM32CubeWB/Drivers/CMSIS/Include", + "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc", + "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities", + ], + CPPDEFINES=[ + "STM32WB", + "STM32WB55xx", + "USE_FULL_ASSERT", + "USE_FULL_LL_DRIVER", + ], +) + +if env["RAM_EXEC"]: + env.Append( + CPPDEFINES=[ + "VECT_TAB_SRAM", + ], + ) + + +libenv = env.Clone(FW_LIB_NAME="stm32cubewb") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive( + "*_ll_*.c", "STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/", exclude="*usb.c" +) +sources += Glob( + "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/*.c", + source=True, +) +sources += Glob( + "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/*_tl*.c", + source=True, +) +sources += [ + "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/svc/Src/svc_ctl.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hci_le.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/dbg_trace.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/otp.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/stm_list.c", +] + + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/appframe.scons b/lib/appframe.scons new file mode 100644 index 00000000..935986d6 --- /dev/null +++ b/lib/appframe.scons @@ -0,0 +1,26 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/app-scened-template", + "#/lib/callback-connector", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="appframe") +libenv.ApplyLibFlags() + +sources = [] + +recurse_dirs = [ + "app-scened-template", + "callback-connector", +] + +for recurse_dir in recurse_dirs: + sources += libenv.GlobRecursive("*.c*", recurse_dir) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript new file mode 100644 index 00000000..3b7ee240 --- /dev/null +++ b/lib/drivers/SConscript @@ -0,0 +1,17 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/drivers", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="hwdrivers") +libenv.ApplyLibFlags() + +sources = Glob("*.c", source=True) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/fatfs/SConscript b/lib/fatfs/SConscript new file mode 100644 index 00000000..c20e2936 --- /dev/null +++ b/lib/fatfs/SConscript @@ -0,0 +1,13 @@ +Import("env") + + +libenv = env.Clone(FW_LIB_NAME="fatfs") +libenv.ApplyLibFlags() + + +sources = ["option/unicode.c"] +sources += Glob("*.c", source=True) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript new file mode 100644 index 00000000..e5d61a07 --- /dev/null +++ b/lib/flipper_format/SConscript @@ -0,0 +1,25 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/flipper_format", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="flipperformat") +libenv.ApplyLibFlags() + +if libenv["RAM_EXEC"]: + libenv.Append( + CPPDEFINES=[ + "FLIPPER_STREAM_LITE", + ], + ) + + +sources = libenv.GlobRecursive("*.c") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/freertos.scons b/lib/freertos.scons new file mode 100644 index 00000000..992c4f87 --- /dev/null +++ b/lib/freertos.scons @@ -0,0 +1,28 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/drivers", + "#/lib/FreeRTOS-Kernel/include", + "#/lib/FreeRTOS-Kernel/portable/GCC/ARM_CM4F", + "#/lib/FreeRTOS-glue", + ], + CPPDEFINES=[ + "HAVE_FREERTOS", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="freertos") +libenv.ApplyLibFlags() + + +sources = libenv.Glob("FreeRTOS-Kernel/*.c", source=True) +sources += [ + "FreeRTOS-Kernel/portable/GCC/ARM_CM4F/port.c", + "FreeRTOS-glue/cmsis_os2.c", +] + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/infrared/SConscript b/lib/infrared/SConscript new file mode 100644 index 00000000..35db75f8 --- /dev/null +++ b/lib/infrared/SConscript @@ -0,0 +1,18 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/infrared/encoder_decoder", + "#/lib/infrared/worker", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="infrared") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/lib.mk b/lib/lib.mk deleted file mode 100644 index 43f4a1a2..00000000 --- a/lib/lib.mk +++ /dev/null @@ -1,138 +0,0 @@ -LIB_DIR = $(PROJECT_ROOT)/lib - -# TODO: some places use lib/header.h includes, is it ok? -CFLAGS += -I$(LIB_DIR) - -# Mlib containers -CFLAGS += -I$(LIB_DIR)/mlib -D'M_MEMORY_FULL(x)=abort()' - -# U8G2 display library -U8G2_DIR = $(LIB_DIR)/u8g2 -CFLAGS += -I$(U8G2_DIR) -C_SOURCES += $(U8G2_DIR)/u8g2_glue.c -C_SOURCES += $(U8G2_DIR)/u8g2_intersection.c -C_SOURCES += $(U8G2_DIR)/u8g2_setup.c -C_SOURCES += $(U8G2_DIR)/u8g2_d_memory.c -C_SOURCES += $(U8G2_DIR)/u8x8_cad.c -C_SOURCES += $(U8G2_DIR)/u8x8_byte.c -C_SOURCES += $(U8G2_DIR)/u8x8_gpio.c -C_SOURCES += $(U8G2_DIR)/u8x8_display.c -C_SOURCES += $(U8G2_DIR)/u8x8_setup.c -C_SOURCES += $(U8G2_DIR)/u8g2_hvline.c -C_SOURCES += $(U8G2_DIR)/u8g2_line.c -C_SOURCES += $(U8G2_DIR)/u8g2_ll_hvline.c -C_SOURCES += $(U8G2_DIR)/u8g2_circle.c -C_SOURCES += $(U8G2_DIR)/u8g2_box.c -C_SOURCES += $(U8G2_DIR)/u8g2_buffer.c -C_SOURCES += $(U8G2_DIR)/u8g2_font.c -C_SOURCES += $(U8G2_DIR)/u8g2_fonts.c -C_SOURCES += $(U8G2_DIR)/u8x8_8x8.c -C_SOURCES += $(U8G2_DIR)/u8g2_bitmap.c - -FATFS_DIR = $(LIB_DIR)/fatfs -C_SOURCES += $(FATFS_DIR)/ff.c -C_SOURCES += $(FATFS_DIR)/ff_gen_drv.c -C_SOURCES += $(FATFS_DIR)/diskio.c -C_SOURCES += $(FATFS_DIR)/option/unicode.c - -# Little FS -LITTLEFS_DIR = $(LIB_DIR)/littlefs -CFLAGS += -I$(LITTLEFS_DIR) -DLFS_CONFIG=lfs_config.h -C_SOURCES += $(LITTLEFS_DIR)/lfs.c -C_SOURCES += $(LITTLEFS_DIR)/lfs_util.c - -ST25RFAL002_DIR = $(LIB_DIR)/ST25RFAL002 -CFLAGS += -I$(ST25RFAL002_DIR) -CFLAGS += -I$(ST25RFAL002_DIR)/include -CFLAGS += -I$(ST25RFAL002_DIR)/source/st25r3916 -C_SOURCES += $(wildcard $(ST25RFAL002_DIR)/*.c) -C_SOURCES += $(wildcard $(ST25RFAL002_DIR)/source/*.c) -C_SOURCES += $(wildcard $(ST25RFAL002_DIR)/source/st25r3916/*.c) - -CFLAGS += -I$(LIB_DIR)/nfc_protocols -C_SOURCES += $(wildcard $(LIB_DIR)/nfc_protocols/*.c) - -# callback connector (C to CPP) library -CFLAGS += -I$(LIB_DIR)/callback-connector - -# app template library -CFLAGS += -I$(LIB_DIR)/app-template - -# add C scene template -CFLAGS += -I$(LIB_DIR)/app_scene_template - -# fnv1a hash library -CFLAGS += -I$(LIB_DIR)/fnv1a-hash -C_SOURCES += $(LIB_DIR)/fnv1a-hash/fnv1a-hash.c - -# common apps api -CFLAGS += -I$(LIB_DIR)/common-api - -# drivers -CFLAGS += -I$(LIB_DIR)/drivers -C_SOURCES += $(wildcard $(LIB_DIR)/drivers/*.c) - -# IR lib -CFLAGS += -I$(LIB_DIR)/infrared/encoder_decoder -CFLAGS += -I$(LIB_DIR)/infrared/worker -C_SOURCES += $(wildcard $(LIB_DIR)/infrared/encoder_decoder/*.c) -C_SOURCES += $(wildcard $(LIB_DIR)/infrared/encoder_decoder/*/*.c) -C_SOURCES += $(wildcard $(LIB_DIR)/infrared/worker/*.c) - -# SubGhz -C_SOURCES += $(wildcard $(LIB_DIR)/subghz/*.c) -C_SOURCES += $(wildcard $(LIB_DIR)/subghz/*/*.c) - -#scened app template lib -CFLAGS += -I$(LIB_DIR)/app-scened-template -C_SOURCES += $(wildcard $(LIB_DIR)/app-scened-template/*.c) -CPP_SOURCES += $(wildcard $(LIB_DIR)/app-scened-template/*.cpp) -CPP_SOURCES += $(wildcard $(LIB_DIR)/app-scened-template/*/*.cpp) - -# Toolbox -C_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*.c) -C_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*/*.c) -CPP_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*.cpp) -CPP_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*/*.cpp) - -# Digital signal -CFLAGS += -I$(LIB_DIR)/digital_signal -C_SOURCES += $(wildcard $(LIB_DIR)/digital_signal/*.c) - - -# USB Stack -CFLAGS += -I$(LIB_DIR)/libusb_stm32/inc -C_SOURCES += $(LIB_DIR)/libusb_stm32/src/usbd_stm32wb55_devfs.c -C_SOURCES += $(LIB_DIR)/libusb_stm32/src/usbd_core.c - -# protobuf -CFLAGS += -I$(LIB_DIR)/nanopb -C_SOURCES += $(wildcard $(LIB_DIR)/nanopb/*.c) - -# heatshrink -CFLAGS += -I$(LIB_DIR)/heatshrink -C_SOURCES += $(wildcard $(LIB_DIR)/heatshrink/*.c) - -# Toolbox -CFLAGS += -I$(LIB_DIR)/flipper_file -C_SOURCES += $(wildcard $(LIB_DIR)/flipper_file/*.c) - -# Flipper format -CFLAGS += -I$(LIB_DIR)/flipper_format -C_SOURCES += $(wildcard $(LIB_DIR)/flipper_format/*.c) - -# Micro-ECC -CFLAGS += -I$(LIB_DIR)/micro-ecc -C_SOURCES += $(wildcard $(LIB_DIR)/micro-ecc/*.c) - -# iButton and OneWire -C_SOURCES += $(wildcard $(LIB_DIR)/one_wire/*.c) -C_SOURCES += $(wildcard $(LIB_DIR)/one_wire/*/*.c) -C_SOURCES += $(wildcard $(LIB_DIR)/one_wire/*/*/*.c) - -# microtar -CFLAGS += -I$(LIB_DIR)/microtar/src -C_SOURCES += $(wildcard $(LIB_DIR)/microtar/src/*.c) - -# Update-related common code -C_SOURCES += $(wildcard $(LIB_DIR)/update_util/*.c) diff --git a/lib/libusb_stm32.scons b/lib/libusb_stm32.scons new file mode 100644 index 00000000..cb867fdb --- /dev/null +++ b/lib/libusb_stm32.scons @@ -0,0 +1,24 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/libusb_stm32/inc", + ], + CPPDEFINES=[ + ("USB_PMASIZE", "0x400"), + ], +) + + +libenv = env.Clone(FW_LIB_NAME="usb_stm32") +libenv.ApplyLibFlags() + + +sources = [ + "libusb_stm32/src/usbd_core.c", + "libusb_stm32/src/usbd_stm32wb55_devfs.c", +] + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/littlefs.scons b/lib/littlefs.scons new file mode 100644 index 00000000..792142c3 --- /dev/null +++ b/lib/littlefs.scons @@ -0,0 +1,20 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/littlefs", + ], + CPPDEFINES=[ + ("LFS_CONFIG", "lfs_config.h"), + ], +) + + +libenv = env.Clone(FW_LIB_NAME="littlefs") +libenv.ApplyLibFlags() + +sources = Glob("littlefs/*.c", source=True) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/microtar.scons b/lib/microtar.scons new file mode 100644 index 00000000..6ee36d40 --- /dev/null +++ b/lib/microtar.scons @@ -0,0 +1,21 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/microtar/src", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="microtar") +libenv.ApplyLibFlags() + +libenv.Append( + CPPDEFINES=["MICROTAR_DISABLE_API_CHECKS"], +) + +sources = libenv.GlobRecursive("*.c", "microtar/src") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/misc.scons b/lib/misc.scons new file mode 100644 index 00000000..91a11ff6 --- /dev/null +++ b/lib/misc.scons @@ -0,0 +1,46 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/digital_signal", + "#/lib/fnv1a_hash", + "#/lib/heatshrink", + "#/lib/micro-ecc", + "#/lib/nanopb", + "#/lib/nfc_protocols", + "#/lib/u8g2", + ], + CPPDEFINES=[ + "PB_ENABLE_MALLOC", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="misc") +libenv.ApplyLibFlags() + +sources = [] + +libs_recurse = [ + "digital_signal", + "micro-ecc", + "nfc_protocols", + "one_wire", + "u8g2", + "update_util", +] + +for lib in libs_recurse: + sources += libenv.GlobRecursive("*.c*", lib) + +libs_plain = [ + "heatshrink", + "nanopb", +] + +for lib in libs_plain: + sources += Glob(lib + "/*.c*", source=True) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/nanopb b/lib/nanopb index c9124132..afc499f9 160000 --- a/lib/nanopb +++ b/lib/nanopb @@ -1 +1 @@ -Subproject commit c9124132a604047d0ef97a09c0e99cd9bed2c818 +Subproject commit afc499f9a410fc9bbf6c9c48cdd8d8b199d49eb4 diff --git a/lib/one_wire/ibutton/ibutton_worker_i.h b/lib/one_wire/ibutton/ibutton_worker_i.h index 93755481..48d03595 100644 --- a/lib/one_wire/ibutton/ibutton_worker_i.h +++ b/lib/one_wire/ibutton/ibutton_worker_i.h @@ -27,9 +27,9 @@ typedef enum { typedef struct { const uint32_t quant; - void (*const start) (iButtonWorker* worker); - void (*const tick) (iButtonWorker* worker); - void (*const stop) (iButtonWorker* worker); + void (*const start)(iButtonWorker* worker); + void (*const tick)(iButtonWorker* worker); + void (*const stop)(iButtonWorker* worker); } iButtonWorkerModeType; typedef enum { diff --git a/lib/one_wire/one_wire_slave.c b/lib/one_wire/one_wire_slave.c index 3c9a796d..1f389623 100644 --- a/lib/one_wire/one_wire_slave.c +++ b/lib/one_wire/one_wire_slave.c @@ -212,7 +212,8 @@ static void exti_cb(void* context) { static uint32_t pulse_start = 0; if(input_state) { - uint32_t pulse_length = (DWT->CYCCNT - pulse_start) / furi_hal_delay_instructions_per_microsecond(); + uint32_t pulse_length = + (DWT->CYCCNT - pulse_start) / furi_hal_delay_instructions_per_microsecond(); if(pulse_length >= OWS_RESET_MIN) { if(pulse_length <= OWS_RESET_MAX) { // reset cycle ok diff --git a/lib/scons b/lib/scons new file mode 160000 index 00000000..c2d1f09f --- /dev/null +++ b/lib/scons @@ -0,0 +1 @@ +Subproject commit c2d1f09f615a9ef3fb5497a7e8e5ee2c900d21a7 diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript new file mode 100644 index 00000000..3c6728af --- /dev/null +++ b/lib/subghz/SConscript @@ -0,0 +1,16 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/subghz", + ], +) + +libenv = env.Clone(FW_LIB_NAME="subghz") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/toolbox/.gitignore b/lib/toolbox/.gitignore new file mode 100644 index 00000000..912c1405 --- /dev/null +++ b/lib/toolbox/.gitignore @@ -0,0 +1 @@ +version.inc.h diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript new file mode 100644 index 00000000..26c233d9 --- /dev/null +++ b/lib/toolbox/SConscript @@ -0,0 +1,47 @@ +Import("env") + +from fbt.version import get_fast_git_version_id + + +env.Append( + CPPPATH=[ + "#/lib/toolbox", + ], +) + + +libenv = env.Clone(tools=["fbt_version"], FW_LIB_NAME="toolbox") +libenv.ApplyLibFlags() + + +# Git Version management +version_depends = [] +version_id_data = get_fast_git_version_id() +if version_id_data: + version_depends = Value(version_id_data) + +# Only invoke version generator if preliminary check target (version_depends) has changed +build_version = libenv.VersionBuilder( + Dir("."), + version_depends, +) + +fw_version_json = libenv.InstallAs( + "${BUILD_DIR}/${FIRMWARE_BUILD_CFG}.json", "version.json" +) +env.Append(FW_VERSION_JSON=fw_version_json) + +# Default(fw_version_json) + + +if not version_depends: + libenv.Precious(build_version) + libenv.AlwaysBuild(build_version) + +sources = libenv.GlobRecursive("*.c") + +libenv.Append(CPPPATH=["."]) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/toolbox/path.c b/lib/toolbox/path.c index c6add856..607671fb 100644 --- a/lib/toolbox/path.c +++ b/lib/toolbox/path.c @@ -83,3 +83,32 @@ void path_concat(const char* path, const char* suffix, string_t out_path) { string_set(out_path, path); path_append(out_path, suffix); } + +bool path_contains_only_ascii(const char* path) { + const char* name_pos = strrchr(path, '/'); + if(name_pos == NULL) { + name_pos = path; + } else { + name_pos++; + } + + while(*name_pos != '\0') { + if((*name_pos >= '0') && (*name_pos <= '9')) { + name_pos++; + continue; + } else if((*name_pos >= 'A') && (*name_pos <= 'Z')) { + name_pos++; + continue; + } else if((*name_pos >= 'a') && (*name_pos <= 'z')) { + name_pos++; + continue; + } else if(strchr(".!#\\$%&'()-@^_`{}~", *name_pos) != NULL) { + name_pos++; + continue; + } + + return false; + } + + return true; +} \ No newline at end of file diff --git a/lib/toolbox/path.h b/lib/toolbox/path.h index 5c91e3fc..d46b210f 100644 --- a/lib/toolbox/path.h +++ b/lib/toolbox/path.h @@ -65,6 +65,15 @@ void path_append(string_t path, const char* suffix); */ void path_concat(const char* path, const char* suffix, string_t out_path); +/** + * @brief Check that path contains only ascii characters + * + * @param path + * @return true + * @return false + */ +bool path_contains_only_ascii(const char* path); + #ifdef __cplusplus } #endif diff --git a/lib/toolbox/version.c b/lib/toolbox/version.c index 40c48370..c6c10b41 100644 --- a/lib/toolbox/version.c +++ b/lib/toolbox/version.c @@ -1,5 +1,8 @@ #include "version.h" +/* This header is autogenerated by build system */ +#include "version.inc.h" + struct Version { const char* git_hash; const char* git_branch; diff --git a/make/base.mk b/make/base.mk deleted file mode 100644 index 281419e9..00000000 --- a/make/base.mk +++ /dev/null @@ -1,11 +0,0 @@ -OBJ_DIR = .obj -ASM_SOURCES = -C_SOURCES = -CPP_SOURCES = -ASSETS = -OPENOCD_OPTS = - -CFLAGS = -CPPFLAGS = -LDFLAGS = -SVD_FILE = diff --git a/make/defaults.mk b/make/defaults.mk deleted file mode 100644 index ade34a6b..00000000 --- a/make/defaults.mk +++ /dev/null @@ -1,2 +0,0 @@ -TARGET ?= f7 -export TARGET diff --git a/make/freertos-heap.mk b/make/freertos-heap.mk deleted file mode 100644 index 93992900..00000000 --- a/make/freertos-heap.mk +++ /dev/null @@ -1 +0,0 @@ -LDFLAGS += -Wl,--wrap,_malloc_r -Wl,--wrap,_free_r -Wl,--wrap,_calloc_r -Wl,--wrap,_realloc_r diff --git a/make/git.mk b/make/git.mk deleted file mode 100644 index e58876a8..00000000 --- a/make/git.mk +++ /dev/null @@ -1,32 +0,0 @@ -GIT_COMMIT := $(shell git rev-parse --short HEAD || echo 'unknown') -GIT_BRANCH := $(shell echo $${WORKFLOW_BRANCH_OR_TAG-$$(git rev-parse --abbrev-ref HEAD || echo 'unknown')}) -GIT_BRANCH_NUM := $(shell git rev-list --count HEAD || echo 'nan') -BUILD_DATE := $(shell date '+%d-%m-%Y' || echo 'unknown') -BUILD_TIME := $(shell date '+%H:%M:%S' || echo 'unknown') -VERSION := $(shell git describe --tags --abbrev=0 --exact-match 2>/dev/null || echo 'unknown') -GIT_DIRTY_BUILD := $(shell git diff --quiet ; echo $$?) - -GIT_DIRTY_SUFFIX := -ifeq ($(GIT_DIRTY_BUILD), 1) - GIT_DIRTY_SUFFIX := -dirty -endif - -CFLAGS += \ - -DGIT_COMMIT=\"$(GIT_COMMIT)\" \ - -DGIT_BRANCH=\"$(GIT_BRANCH)\" \ - -DGIT_BRANCH_NUM=\"$(GIT_BRANCH_NUM)\" \ - -DBUILD_DATE=\"$(BUILD_DATE)\" \ - -DVERSION=\"$(VERSION)\" \ - -DTARGET=$(HARDWARE_TARGET) \ - -DBUILD_DIRTY=$(GIT_DIRTY_BUILD) - -# if suffix is set in environment (by Github), use it -ifeq (${DIST_SUFFIX},) - DIST_SUFFIX := local-$(GIT_COMMIT)$(GIT_DIRTY_SUFFIX) -else - DIST_SUFFIX := ${DIST_SUFFIX}$(GIT_DIRTY_SUFFIX) -endif - -#VERSION_STRING := $(VERSION) ($(GIT_BRANCH) @ $(GIT_COMMIT)), built $(BUILD_DATE) $(BUILD_TIME) -VERSION_STRING := $(DIST_SUFFIX), $(GIT_BRANCH) - diff --git a/make/rules.mk b/make/rules.mk deleted file mode 100644 index bdf8a4af..00000000 --- a/make/rules.mk +++ /dev/null @@ -1,185 +0,0 @@ -OBJ_DIR := $(OBJ_DIR)/$(TARGET)-$(PROJECT) - -# Include source folder paths to virtual paths -C_SOURCES := $(abspath ${C_SOURCES}) -ASM_SOURCES := $(abspath ${ASM_SOURCES}) -CPP_SOURCES := $(abspath ${CPP_SOURCES}) - -# Gather object -OBJECTS = $(addprefix $(OBJ_DIR)/, $(C_SOURCES:.c=.o)) -OBJECTS += $(addprefix $(OBJ_DIR)/, $(ASM_SOURCES:.s=.o)) -OBJECTS += $(addprefix $(OBJ_DIR)/, $(CPP_SOURCES:.cpp=.o)) - -OBJECT_DIRS = $(sort $(dir $(OBJECTS))) - -# Generate dependencies -DEPS = $(OBJECTS:.o=.d) - -ifdef DFU_SERIAL - DFU_OPTIONS += -S $(DFU_SERIAL) -endif - -$(foreach dir, $(OBJECT_DIRS),$(shell mkdir -p $(dir))) - -BUILD_FLAGS_SHELL=\ - echo $(OBJ_DIR) ;\ - echo "$(CFLAGS)" > $(OBJ_DIR)/BUILD_FLAGS.tmp; \ - diff -u $(OBJ_DIR)/BUILD_FLAGS $(OBJ_DIR)/BUILD_FLAGS.tmp 2>&1 > /dev/null \ - && ( echo "CFLAGS ok"; rm $(OBJ_DIR)/BUILD_FLAGS.tmp) \ - || ( echo "CFLAGS has been changed"; mv $(OBJ_DIR)/BUILD_FLAGS.tmp $(OBJ_DIR)/BUILD_FLAGS ) -$(info $(shell $(BUILD_FLAGS_SHELL))) - -CHECK_AND_REINIT_SUBMODULES_SHELL=\ - if git submodule status | egrep -q '^[-]|^[+]' ; then \ - echo "INFO: Need to reinitialize git submodules"; \ - git submodule sync; \ - git submodule update --init; \ - fi -$(info $(shell $(CHECK_AND_REINIT_SUBMODULES_SHELL))) - - -all: $(OBJ_DIR)/$(PROJECT).elf $(OBJ_DIR)/$(PROJECT).hex $(OBJ_DIR)/$(PROJECT).bin $(OBJ_DIR)/$(PROJECT).dfu $(OBJ_DIR)/$(PROJECT).json - @: - -$(OBJ_DIR)/$(PROJECT).elf: $(OBJECTS) - @echo "\tLD\t" $@ - @$(LD) $(LDFLAGS) $(OBJECTS) -o $@ - @$(SZ) $@ - -$(OBJ_DIR)/$(PROJECT).hex: $(OBJ_DIR)/$(PROJECT).elf - @echo "\tHEX\t" $@ - @$(HEX) $< $@ - -$(OBJ_DIR)/$(PROJECT).bin: $(OBJ_DIR)/$(PROJECT).elf - @echo "\tBIN\t" $@ - @$(BIN) $< $@ - -$(OBJ_DIR)/$(PROJECT).dfu: $(OBJ_DIR)/$(PROJECT).bin - @echo "\tDFU\t" $@ - @../scripts/bin2dfu.py \ - -i $(OBJ_DIR)/$(PROJECT).bin \ - -o $(OBJ_DIR)/$(PROJECT).dfu \ - -a $(FLASH_ADDRESS) \ - -l "Flipper Zero $(shell echo $(TARGET) | tr a-z A-Z)" > /dev/null - -$(OBJ_DIR)/$(PROJECT).json: $(OBJ_DIR)/$(PROJECT).dfu - @echo "\tJSON\t" $@ - @$(PROJECT_ROOT)/scripts/meta.py generate -p $(PROJECT) $(CFLAGS) > $(OBJ_DIR)/$(PROJECT).json - -$(OBJ_DIR)/%.o: %.c $(OBJ_DIR)/BUILD_FLAGS - @echo "\tCC\t" $(subst $(PROJECT_ROOT)/, , $<) - @$(CC) $(CFLAGS) -c $< -o $@ - -$(OBJ_DIR)/%.o: %.s $(OBJ_DIR)/BUILD_FLAGS - @echo "\tASM\t" $(subst $(PROJECT_ROOT)/, , $<) - @$(AS) $(CFLAGS) -c $< -o $@ - -$(OBJ_DIR)/%.o: %.cpp $(OBJ_DIR)/BUILD_FLAGS - @echo "\tCPP\t" $(subst $(PROJECT_ROOT)/, , $<) - @$(CPP) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ - -$(OBJ_DIR)/flash: $(OBJ_DIR)/$(PROJECT).bin - openocd $(OPENOCD_OPTS) -c "program $(OBJ_DIR)/$(PROJECT).bin reset exit $(FLASH_ADDRESS)" - touch $@ - -$(OBJ_DIR)/upload: $(OBJ_DIR)/$(PROJECT).bin - dfu-util -d 0483:df11 -D $(OBJ_DIR)/$(PROJECT).bin -a 0 -s $(FLASH_ADDRESS) $(DFU_OPTIONS) - touch $@ - -.PHONY: flash -flash: $(OBJ_DIR)/flash - -.PHONY: upload -upload: $(OBJ_DIR)/upload - -.PHONY: debug -debug: flash - $(GDB) \ - -ex 'target extended-remote | openocd -c "gdb_port pipe" $(OPENOCD_OPTS)' \ - -ex "set confirm off" \ - -ex "source ../debug/FreeRTOS/FreeRTOS.py" \ - -ex "source ../debug/PyCortexMDebug/PyCortexMDebug.py" \ - -ex "svd_load $(SVD_FILE)" \ - -ex "compare-sections" \ - $(OBJ_DIR)/$(PROJECT).elf; \ - -.PHONY: debug_other -debug_other: - $(GDB) \ - -ex 'target extended-remote | openocd -c "gdb_port pipe" $(OPENOCD_OPTS)' \ - -ex "set confirm off" \ - -ex "source ../debug/PyCortexMDebug/PyCortexMDebug.py" \ - -ex "svd_load $(SVD_FILE)" \ - -.PHONY: blackmagic -blackmagic: - $(GDB) \ - -ex 'target extended-remote $(BLACKMAGIC)' \ - -ex 'monitor swdp_scan' \ - -ex 'monitor debug_bmp enable' \ - -ex 'attach 1' \ - -ex 'set confirm off' \ - -ex 'set mem inaccessible-by-default off' \ - -ex "source ../debug/FreeRTOS/FreeRTOS.py" \ - -ex "source ../debug/PyCortexMDebug/PyCortexMDebug.py" \ - -ex "svd_load $(SVD_FILE)" \ - -ex "compare-sections" \ - $(OBJ_DIR)/$(PROJECT).elf; \ - -.PHONY: openocd -openocd: - openocd $(OPENOCD_OPTS) - -.PHONY: clean -clean: - @echo "\tCLEAN\t" - @$(RM) -rf $(OBJ_DIR) - -.PHONY: z -z: clean - $(MAKE) all - -.PHONY: zz -zz: clean - $(MAKE) flash - -.PHONY: zzz -zzz: clean - $(MAKE) debug - -.PHONY: generate_cscope_db -generate_cscope_db: - @echo "$(C_SOURCES) $(CPP_SOURCES) $(ASM_SOURCES)" | tr ' ' '\n' > $(OBJ_DIR)/source.list.p - @cat ~/headers.list >> $(OBJ_DIR)/source.list.p - @cat $(OBJ_DIR)/source.list.p | sed -e "s|^[^//]|$$PWD/&|g" > $(OBJ_DIR)/source.list - @cscope -b -k -i $(OBJ_DIR)/source.list -f $(OBJ_DIR)/cscope.out - @rm -rf $(OBJ_DIR)/source.list $(OBJ_DIR)/source.list.p - -.PHONY: generate_compile_db -generate_compile_db: - @echo "$(ASM_SOURCES)" | tr ' ' '\n' > $(OBJ_DIR)/db.asm_source.list - @echo "$(C_SOURCES)" | tr ' ' '\n' > $(OBJ_DIR)/db.c_source.list - @echo "$(CPP_SOURCES)" | tr ' ' '\n' > $(OBJ_DIR)/db.cpp_source.list - @echo "$(AS)$(CFLAGS)" | tr ' ' '\n' > $(OBJ_DIR)/db.asm_flags.list - @echo "$(CC)$(CFLAGS)" | tr ' ' '\n' > $(OBJ_DIR)/db.c_flags.list - @echo "$(CPP)$(CFLAGS)$(CPPFLAGS)" | tr ' ' '\n' > $(OBJ_DIR)/db.cpp_flags.list - @$(PROJECT_ROOT)/scripts/compile_db.py generate -p $(OBJ_DIR) - @rm $(OBJ_DIR)/db.asm_source.list - @rm $(OBJ_DIR)/db.c_source.list - @rm $(OBJ_DIR)/db.cpp_source.list - @rm $(OBJ_DIR)/db.asm_flags.list - @rm $(OBJ_DIR)/db.c_flags.list - @rm $(OBJ_DIR)/db.cpp_flags.list - -# Prevent make from searching targets for real files -%.d: ; - -%.c: ; - -%.cpp: ; - -%.s: ; - -$(OBJ_DIR)/BUILD_FLAGS: ; - --include $(DEPS) diff --git a/make/toolchain.mk b/make/toolchain.mk deleted file mode 100644 index f161d3d1..00000000 --- a/make/toolchain.mk +++ /dev/null @@ -1,41 +0,0 @@ -OS := $(shell uname -s) - -# Compiller -ifeq ($(TOOLCHAIN), arm) -PREFIX = arm-none-eabi- -ifdef GCC_PATH -PREFIX := $(GCC_PATH)/$(PREFIX) -endif -endif - -CCACHE := $(shell which ccache) - -CC = $(CCACHE) $(PREFIX)gcc -std=gnu17 -CPP = $(CCACHE) $(PREFIX)g++ -std=gnu++17 -LD = $(PREFIX)g++ -AS = $(PREFIX)gcc -x assembler-with-cpp -CP = $(PREFIX)objcopy -SZ = $(PREFIX)size -HEX = $(CP) -O ihex -BIN = $(CP) -O binary -S - - -ifeq ($(OS), Darwin) -GDB = gdb -else -GDB = $(PREFIX)gdb-py -endif - -DEBUG ?= 1 -COMPACT ?= 0 -ifeq ($(DEBUG), 1) -CFLAGS += -DFURI_DEBUG -DNDEBUG -Og -g -else ifeq ($(COMPACT), 1) -CFLAGS += -DFURI_NDEBUG -DNDEBUG -Os -g -else -CFLAGS += -DFURI_NDEBUG -DNDEBUG -Og -g -endif - -CFLAGS += -fdata-sections -ffunction-sections -fno-math-errno -fstack-usage -MMD -MP -MF "$(@:%.o=%.d)" -CPPFLAGS += -fno-threadsafe-statics -fno-use-cxa-atexit -fno-exceptions -fno-rtti -LDFLAGS += -Wl,-Map=$(OBJ_DIR)/$(PROJECT).map,--cref -Wl,--gc-sections -Wl,--undefined=uxTopUsedPriority -n diff --git a/scripts/assets.py b/scripts/assets.py index 1363900f..b27b29ef 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from flipper.app import App +from flipper.assets.icon import file2image import logging import argparse @@ -90,31 +91,8 @@ class Main(App): self.parser_dolphin.set_defaults(func=self.dolphin) def _icon2header(self, file): - output = subprocess.check_output(["convert", file, "xbm:-"]) - assert output - f = io.StringIO(output.decode().strip()) - width = int(f.readline().strip().split(" ")[2]) - height = int(f.readline().strip().split(" ")[2]) - data = f.read().strip().replace("\n", "").replace(" ", "").split("=")[1][:-1] - data_bin_str = data[1:-1].replace(",", " ").replace("0x", "") - data_bin = bytearray.fromhex(data_bin_str) - # Encode icon data with LZSS - data_encoded_str = subprocess.check_output( - ["heatshrink", "-e", "-w8", "-l4"], input=data_bin - ) - assert data_encoded_str - data_enc = bytearray(data_encoded_str) - data_enc = bytearray([len(data_enc) & 0xFF, len(data_enc) >> 8]) + data_enc - # Use encoded data only if its lenght less than original, including header - if len(data_enc) < len(data_bin) + 1: - data = ( - "{0x01,0x00," - + "".join("0x{:02x},".format(byte) for byte in data_enc) - + "}" - ) - else: - data = "{0x00," + data[1:] - return width, height, data + image = file2image(file) + return image.width, image.height, image.data_as_carray() def _iconIsSupported(self, filename): extension = filename.lower().split(".")[-1] @@ -122,7 +100,11 @@ class Main(App): def icons(self): self.logger.debug(f"Converting icons") - icons_c = open(os.path.join(self.args.output_directory, "assets_icons.c"), "w") + icons_c = open( + os.path.join(self.args.output_directory, "assets_icons.c"), + "w", + newline="\n", + ) icons_c.write(ICONS_TEMPLATE_C_HEADER) icons = [] # Traverse icons tree, append image data to source file @@ -204,12 +186,19 @@ class Main(App): ) ) icons_c.write("\n") + icons_c.close() + # Create Public Header self.logger.debug(f"Creating header") - icons_h = open(os.path.join(self.args.output_directory, "assets_icons.h"), "w") + icons_h = open( + os.path.join(self.args.output_directory, "assets_icons.h"), + "w", + newline="\n", + ) icons_h.write(ICONS_TEMPLATE_H_HEADER) for name, width, height, frame_rate, frame_count in icons: icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name)) + icons_h.close() self.logger.debug(f"Done") return 0 diff --git a/scripts/bin2dfu.py b/scripts/bin2dfu.py index d27b44aa..7484738f 100755 --- a/scripts/bin2dfu.py +++ b/scripts/bin2dfu.py @@ -62,7 +62,8 @@ class Main(App): data += struct.pack(" 0: - h.update(data) - else: - break + with open(path, "rb") as fd: + while True: + data = fd.read(block_size) + if len(data) > 0: + h.update(data) + else: + break return h.hexdigest() diff --git a/scripts/flipper/utils/fff.py b/scripts/flipper/utils/fff.py index b7f89321..fa689b01 100644 --- a/scripts/flipper/utils/fff.py +++ b/scripts/flipper/utils/fff.py @@ -99,5 +99,5 @@ class FlipperFormatFile: self.lines = file.readlines() def save(self, filename: str): - with open(filename, "w") as file: + with open(filename, "w", newline="\n") as file: file.write("\n".join(self.lines)) diff --git a/scripts/lint.py b/scripts/lint.py index bf1f5e68..b3c3e7da 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -117,6 +117,7 @@ class Main(App): if dry_run: if len(bad) > 0: self.logger.error(f"Found {len(bad)} incorrectly named files") + self.logger.info(bad) return False else: # Replace occurances in text files diff --git a/scripts/ob.py b/scripts/ob.py index 17de08fd..722549d6 100755 --- a/scripts/ob.py +++ b/scripts/ob.py @@ -40,10 +40,10 @@ class Main(App): def before(self): self.logger.info(f"Loading Option Bytes data") file_path = os.path.join(os.path.dirname(sys.argv[0]), "ob.data") - file = open(file_path, "r") - for line in file.readlines(): - k, v, o = line.split(":") - self.ob[k.strip()] = v.strip(), o.strip() + with open(file_path, "r") as file: + for line in file.readlines(): + k, v, o = line.split(":") + self.ob[k.strip()] = v.strip(), o.strip() def check(self): self.logger.info(f"Checking Option Bytes") diff --git a/scripts/otp.py b/scripts/otp.py index 54714961..7b2378d1 100755 --- a/scripts/otp.py +++ b/scripts/otp.py @@ -149,8 +149,10 @@ class Main(App): self.logger.info(f"Generating OTP") self._processFirstArgs() self._processSecondArgs() - open(f"{self.args.file}_first.bin", "wb").write(self._packFirst()) - open(f"{self.args.file}_second.bin", "wb").write(self._packSecond()) + with open(f"{self.args.file}_first.bin", "wb") as file: + file.write(self._packFirst()) + with open(f"{self.args.file}_second.bin", "wb") as file: + file.write(self._packSecond()) self.logger.info( f"Generated files: {self.args.file}_first.bin and {self.args.file}_second.bin" ) @@ -166,9 +168,9 @@ class Main(App): try: self.logger.info(f"Packing binary data") - file = open(filename, "wb") - file.write(self._packFirst()) - file.close() + with open(filename, "wb") as file: + file.write(self._packFirst()) + self.logger.info(f"Flashing OTP") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x1FFF7000", filename) @@ -190,9 +192,9 @@ class Main(App): try: self.logger.info(f"Packing binary data") - file = open(filename, "wb") - file.write(self._packSecond()) - file.close() + with open(filename, "wb") as file: + file.write(self._packSecond()) + self.logger.info(f"Flashing OTP") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x1FFF7010", filename) @@ -215,10 +217,10 @@ class Main(App): try: self.logger.info(f"Packing binary data") - file = open(filename, "wb") - file.write(self._packFirst()) - file.write(self._packSecond()) - file.close() + with open(filename, "wb") as file: + file.write(self._packFirst()) + file.write(self._packSecond()) + self.logger.info(f"Flashing OTP") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x1FFF7000", filename) diff --git a/scripts/requirements.txt b/scripts/requirements.txt new file mode 100644 index 00000000..4c4b7279 --- /dev/null +++ b/scripts/requirements.txt @@ -0,0 +1,7 @@ +pyserial==3.5 +heatshrink2==0.11.0 +Pillow==9.1.1 +grpcio==1.47.0 +grpcio-tools==1.47.0 +protobuf==3.20.1 +python3-protobuf==2.5.0 diff --git a/scripts/dist.py b/scripts/sconsdist.py old mode 100755 new mode 100644 similarity index 55% rename from scripts/dist.py rename to scripts/sconsdist.py index ccede12b..1e95ee2f --- a/scripts/dist.py +++ b/scripts/sconsdist.py @@ -7,6 +7,15 @@ from update import Main as UpdateMain import shutil +class ProjectDir: + def __init__(self, project_dir): + self.dir = project_dir + parts = project_dir.split("-") + self.target = parts[0] + self.project = parts[1] + self.flavor = parts[2] if len(parts) > 2 else "" + + class Main(App): def init(self): self.subparsers = self.parser.add_subparsers(help="sub-command help") @@ -15,8 +24,7 @@ class Main(App): "copy", help="Copy firmware binaries & metadata" ) - self.parser_copy.add_argument("-t", dest="target", required=True) - self.parser_copy.add_argument("-p", dest="projects", nargs="+", required=True) + self.parser_copy.add_argument("-p", dest="project", nargs="+", required=True) self.parser_copy.add_argument("-s", dest="suffix", required=True) self.parser_copy.add_argument("-r", dest="resources", required=False) self.parser_copy.add_argument( @@ -36,40 +44,67 @@ class Main(App): def get_project_filename(self, project, filetype): # Temporary fix - if project == "firmware" and filetype != "elf": - project = "full" - return f"flipper-z-{self.args.target}-{project}-{self.args.suffix}.{filetype}" + project_name = project.project + if project_name == "firmware" and filetype != "elf": + project_name = "full" + return f"flipper-z-{self.target}-{project_name}-{self.args.suffix}.{filetype}" def get_dist_filepath(self, filename): return join(self.output_dir_path, filename) def copy_single_project(self, project): - target_project = f"{self.args.target}-{project}" - obj_directory = join("firmware", ".obj", target_project) + obj_directory = join("build", project.dir) for filetype in ("elf", "bin", "dfu", "json"): shutil.copyfile( - join(obj_directory, f"{project}.{filetype}"), + join(obj_directory, f"{project.project}.{filetype}"), self.get_dist_filepath(self.get_project_filename(project, filetype)), ) def copy(self): - self.output_dir_path = join("dist", self.args.target) + self.projects = dict( + map( + lambda pd: (pd.project, pd), + map(ProjectDir, self.args.project), + ) + ) + + project_targets = set(map(lambda p: p.target, self.projects.values())) + if len(project_targets) != 1: + self.logger.error(f"Cannot mix targets {project_targets}!") + return 1 + self.target = project_targets.pop() + + project_flavors = set(map(lambda p: p.flavor, self.projects.values())) + if len(project_flavors) != 1: + self.logger.error(f"Cannot mix flavors {project_flavors}!") + return 2 + self.flavor = project_flavors.pop() + + dist_dir_components = [self.target] + if self.flavor: + dist_dir_components.append(self.flavor) + + self.output_dir_path = join("dist", "-".join(dist_dir_components)) if exists(self.output_dir_path) and not self.args.noclean: - shutil.rmtree(self.output_dir_path) + try: + shutil.rmtree(self.output_dir_path) + except Exception as ex: + pass if not exists(self.output_dir_path): makedirs(self.output_dir_path) - for project in self.args.projects: + for project in self.projects.values(): self.copy_single_project(project) self.logger.info( f"Firmware binaries can be found at:\n\t{self.output_dir_path}" ) + if self.args.version: bundle_dir = join( - self.output_dir_path, f"{self.args.target}-update-{self.args.suffix}" + self.output_dir_path, f"{self.target}-update-{self.args.suffix}" ) bundle_args = [ "generate", @@ -78,11 +113,15 @@ class Main(App): "-v", self.args.version, "-t", - self.args.target, + self.target, "--dfu", - self.get_dist_filepath(self.get_project_filename("firmware", "dfu")), + self.get_dist_filepath( + self.get_project_filename(self.projects["firmware"], "dfu") + ), "--stage", - self.get_dist_filepath(self.get_project_filename("updater", "bin")), + self.get_dist_filepath( + self.get_project_filename(self.projects["updater"], "bin") + ), ] if self.args.resources: bundle_args.extend( diff --git a/scripts/storage.py b/scripts/storage.py index a56dcd8b..4364eb28 100755 --- a/scripts/storage.py +++ b/scripts/storage.py @@ -293,7 +293,8 @@ class Main: with tempfile.TemporaryDirectory() as tmpdirname: send_file_name = os.path.join(tmpdirname, "send") receive_file_name = os.path.join(tmpdirname, "receive") - open(send_file_name, "w").write("A" * self.args.file_size) + with open(send_file_name, "w") as fout: + fout.write("A" * self.args.file_size) storage = FlipperStorage(self.args.port) storage.start() if storage.exist_file(self.args.flipper_path): diff --git a/scripts/version.py b/scripts/version.py new file mode 100644 index 00000000..87bf7ed8 --- /dev/null +++ b/scripts/version.py @@ -0,0 +1,131 @@ +#!/usb/bin/env python3 + +from flipper.app import App + +import subprocess +import os +import json +from datetime import date + + +class GitVersion: + def __init__(self, source_dir): + self.source_dir = source_dir + + def get_version_info(self): + commit = self._exec_git("rev-parse --short HEAD") or "unknown" + + dirty = False + try: + self._exec_git("diff --quiet") + except subprocess.CalledProcessError as e: + if e.returncode == 1: + dirty = True + + # If WORKFLOW_BRANCH_OR_TAG is set in environment, is has precedence + # (set by CI) + branch = ( + os.environ.get("WORKFLOW_BRANCH_OR_TAG", None) + or self._exec_git("rev-parse --abbrev-ref HEAD") + or "unknown" + ) + + branch_num = self._exec_git("rev-list --count HEAD") or "n/a" + + try: + version = self._exec_git("describe --tags --abbrev=0 --exact-match") + except subprocess.CalledProcessError: + version = "unknown" + + return { + "GIT_COMMIT": commit, + "GIT_BRANCH": branch, + "GIT_BRANCH_NUM": branch_num, + "VERSION": version, + "BUILD_DIRTY": dirty and 1 or 0, + } + + def _exec_git(self, args): + cmd = ["git"] + cmd.extend(args.split(" ")) + return ( + subprocess.check_output(cmd, cwd=self.source_dir, stderr=subprocess.STDOUT) + .strip() + .decode() + ) + + +class Main(App): + def init(self): + self.subparsers = self.parser.add_subparsers(help="sub-command help") + + # generate + self.parser_generate = self.subparsers.add_parser( + "generate", help="Generate version header" + ) + + self.parser_generate.add_argument("-o", dest="outdir", required=True) + self.parser_generate.add_argument( + "-t", + dest="target", + type=int, + help="hardware target", + required=True, + ) + self.parser_generate.add_argument("--dir", dest="sourcedir", required=True) + self.parser_generate.set_defaults(func=self.generate) + + def generate(self): + current_info = GitVersion(self.args.sourcedir).get_version_info() + current_info.update( + { + "BUILD_DATE": date.today().strftime("%d-%m-%Y"), + "TARGET": self.args.target, + } + ) + + version_values = [] + for key in current_info: + val = current_info[key] + if isinstance(val, str): + val = f'"{val}"' + version_values.append(f"#define {key} {val}") + + new_version_info_fmt = "\n".join(version_values) + "\n" + + current_version_info = None + version_header_name = os.path.join(self.args.outdir, "version.inc.h") + version_json_name = os.path.join(self.args.outdir, "version.json") + + try: + with open(version_header_name, "r") as file: + current_version_info = file.read() + except EnvironmentError as e: + if self.args.debug: + print(e) + + if current_version_info != new_version_info_fmt: + if self.args.debug: + print("old: ", current_version_info) + print("new: ", new_version_info_fmt) + with open(version_header_name, "w", newline="\n") as file: + file.write(new_version_info_fmt) + # os.utime("../lib/toolbox/version.c", None) + print("Version information updated") + else: + if self.args.debug: + print("Version information hasn't changed") + + version_json = { + "firmware_build_date": current_info["BUILD_DATE"], + "firmware_commit": current_info["GIT_COMMIT"], + "firmware_branch": current_info["GIT_BRANCH"], + "firmware_target": current_info["TARGET"], + } + with open(version_json_name, "w", newline="\n") as file: + json.dump(version_json, file, indent=4) + return 0 + + +if __name__ == "__main__": + Main()() diff --git a/site_scons/cc.scons b/site_scons/cc.scons new file mode 100644 index 00000000..e71db2ba --- /dev/null +++ b/site_scons/cc.scons @@ -0,0 +1,47 @@ +Import("ENV") + + +ENV.AppendUnique( + CFLAGS=[ + "-std=gnu17", + ], + CXXFLAGS=[ + "-std=c++17", + "-fno-rtti", + "-fno-use-cxa-atexit", + "-fno-exceptions", + "-fno-threadsafe-statics", + ], + CCFLAGS=[ + "-mcpu=cortex-m4", + "-mfloat-abi=hard", + "-mfpu=fpv4-sp-d16", + "-mthumb", + # "-MMD", + # "-MP", + "-Wall", + "-Wextra", + "-Werror", + "-Wno-address-of-packed-member", + "-Wredundant-decls", + "-Wdouble-promotion", + "-fdata-sections", + "-ffunction-sections", + "-fsingle-precision-constant", + "-fno-math-errno", + "-fstack-usage", + "-g", + # "-Wno-stringop-overread", + # "-Wno-stringop-overflow", + ], + CPPDEFINES=[ + "_GNU_SOURCE", + ], + LINKFLAGS=[ + "-mcpu=cortex-m4", + "-mfloat-abi=hard", + "-mfpu=fpv4-sp-d16", + "-mlittle-endian", + "-mthumb", + ], +) diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons new file mode 100644 index 00000000..06e83657 --- /dev/null +++ b/site_scons/commandline.scons @@ -0,0 +1,202 @@ +# Commandline options + +# To build updater-related targets, you need to set this option +AddOption( + "--with-updater", + dest="fullenv", + action="store_true", + help="Full firmware environment", +) + +AddOption( + "--options", + dest="optionfile", + type="string", + nargs=1, + action="store", + default="fbt_options.py", + help="Enviroment option file", +) + +AddOption( + "--extra-int-apps", + action="store", + dest="extra_int_apps", + default="", + help="List of applications to add to firmare's built-ins. Also see FIRMWARE_APP_SET and FIRMWARE_APPS", +) + +AddOption( + "--extra-ext-apps", + action="store", + dest="extra_ext_apps", + default="", + help="List of applications to forcefully build as standalone .elf", +) + + +# Construction environment variables + +vars = Variables(GetOption("optionfile"), ARGUMENTS) + +vars.AddVariables( + BoolVariable( + "VERBOSE", + help="Print full commands", + default=False, + ), + BoolVariable( + "FORCE", + help="Force target action (for supported targets)", + default=False, + ), + BoolVariable( + "DEBUG", + help="Enable debug build", + default=True, + ), + BoolVariable( + "COMPACT", + help="Optimize for size", + default=False, + ), + EnumVariable( + "TARGET_HW", + help="Hardware target", + default="7", + allowed_values=[ + "7", + ], + ), +) + +vars.Add( + "DIST_SUFFIX", + help="Suffix for binaries in build output for dist targets", + default="local", +) + +vars.Add( + "UPDATE_VERSION_STRING", + help="Version string for updater package", + default="${DIST_SUFFIX}", +) + + +vars.Add( + "COPRO_CUBE_VERSION", + help="Cube version", + default="", +) + +vars.Add( + "COPRO_STACK_ADDR", + help="Core2 Firmware address", + default="0", +) + +vars.Add( + "COPRO_STACK_BIN", + help="Core2 Firmware file name", + default="", +) + +vars.Add( + "COPRO_DISCLAIMER", + help="Value to pass to bundling script to confirm dangerous operations", + default="", +) + +vars.AddVariables( + PathVariable( + "COPRO_OB_DATA", + help="Path to OB reference data", + validator=PathVariable.PathIsFile, + default="", + ), + PathVariable( + "COPRO_STACK_BIN_DIR", + help="Path to ST-provided stacks", + validator=PathVariable.PathIsDir, + default="", + ), + PathVariable( + "COPRO_CUBE_DIR", + help="Path to Cube root", + validator=PathVariable.PathIsDir, + default="", + ), + EnumVariable( + "COPRO_STACK_TYPE", + help="Core2 stack type", + default="ble_light", + allowed_values=[ + "ble_full", + "ble_light", + "ble_basic", + ], + ), + PathVariable( + "SVD_FILE", + help="Path to SVD file", + validator=PathVariable.PathIsFile, + default="", + ), + PathVariable( + "OTHER_ELF", + help="Path to prebuilt ELF file to debug", + validator=PathVariable.PathAccept, + default="", + ), +) + +vars.Add( + "FBT_TOOLCHAIN_VERSIONS", + help="Whitelisted toolchain versions (leave empty for no check)", + default=tuple(), +) + +vars.Add( + "OPENOCD_OPTS", + help="Options to pass to OpenOCD", + default="", +) + +vars.Add( + "UPDATE_SPLASH", + help="Directory name with slideshow frames to render after installing update package", + default="update_default", +) + + +vars.Add( + "FIRMWARE_APPS", + help="Map of (configuration_name->application_list)", + default={ + "default": ( + "crypto_start", + # Svc + "basic_services", + # Apps + "basic_apps", + "updater_app", + "archive", + # Settings + "passport", + "system_settings", + "about", + # Plugins + "basic_plugins", + # Debug + "debug_apps", + ) + }, +) + +vars.Add( + "FIRMWARE_APP_SET", + help="Application set to use from FIRMWARE_APPS", + default="default", +) + +Return("vars") diff --git a/site_scons/environ.scons b/site_scons/environ.scons new file mode 100644 index 00000000..9e49e8b6 --- /dev/null +++ b/site_scons/environ.scons @@ -0,0 +1,82 @@ +import SCons +from SCons.Platform import TempFileMunge +from fbt import util + +import os +import multiprocessing + +Import("VAR_ENV") + +forward_os_env = { + # Import PATH from OS env - scons doesn't do that by default + "PATH": os.environ["PATH"], +} +# Proxying CI environment to child processes & scripts +for env_value_name in ("WORKFLOW_BRANCH_OR_TAG", "DIST_SUFFIX", "HOME", "APPDATA"): + if environ_value := os.environ.get(env_value_name, None): + forward_os_env[env_value_name] = environ_value + + +coreenv = VAR_ENV.Clone( + tools=[ + ( + "crosscc", + { + "toolchain_prefix": "arm-none-eabi-", + "versions": VAR_ENV["FBT_TOOLCHAIN_VERSIONS"], + }, + ), + "python3", + "sconsmodular", + "sconsrecursiveglob", + "ccache", + ], + TEMPFILE=TempFileMunge, + MAXLINELENGTH=2048, + PROGSUFFIX=".elf", + ENV=forward_os_env, +) + +# If DIST_SUFFIX is set in environment, is has precedence (set by CI) +if os_suffix := os.environ.get("DIST_SUFFIX", None): + coreenv.Replace( + DIST_SUFFIX=os_suffix, + ) + +# print(coreenv.Dump()) +if not coreenv["VERBOSE"]: + coreenv.SetDefault( + CCCOMSTR="\tCC\t${SOURCE}", + CXXCOMSTR="\tCPP\t${SOURCE}", + ASCOMSTR="\tASM\t${SOURCE}", + ARCOMSTR="\tAR\t${TARGET}", + RANLIBCOMSTR="\tRANLIB\t${TARGET}", + LINKCOMSTR="\tLINK\t${TARGET}", + INSTALLSTR="\tINSTALL\t${TARGET}", + APPSCOMSTR="\tAPPS\t${TARGET}", + VERSIONCOMSTR="\tVERSION\t${TARGET}", + STRIPCOMSTR="\tSTRIP\t${TARGET}", + OBJDUMPCOMSTR="\tOBJDUMP\t${TARGET}", + # GDBCOMSTR="\tGDB\t${SOURCE}", + # GDBPYCOMSTR="\tGDB-PY\t${SOURCE}", + ) + +# Default value for commandline options + +SetOption("num_jobs", multiprocessing.cpu_count()) +# Avoiding re-scan of all sources on every startup +SetOption("implicit_cache", True) +SetOption("implicit_deps_unchanged", True) +# More aggressive caching +SetOption("max_drift", 1) +# Random task queue - to discover isses with build logic faster +# SetOption("random", 1) + + +# Setting up temp file parameters - to overcome command line length limits +coreenv["TEMPFILEARGESCFUNC"] = util.tempfile_arg_esc_func +util.wrap_tempfile(coreenv, "LINKCOM") +util.wrap_tempfile(coreenv, "ARCOM") + + +Return("coreenv") diff --git a/site_scons/fbt/__init__.py b/site_scons/fbt/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/site_scons/fbt/appmanifest.py b/site_scons/fbt/appmanifest.py new file mode 100644 index 00000000..218b139f --- /dev/null +++ b/site_scons/fbt/appmanifest.py @@ -0,0 +1,243 @@ +from dataclasses import dataclass, field +from typing import List, Optional +from enum import Enum +import os + + +class FlipperManifestException(Exception): + pass + + +class FlipperAppType(Enum): + SERVICE = "Service" + SYSTEM = "System" + APP = "App" + PLUGIN = "Plugin" + DEBUG = "Debug" + ARCHIVE = "Archive" + SETTINGS = "Settings" + STARTUP = "StartupHook" + EXTERNAL = "External" + METAPACKAGE = "Package" + + +@dataclass +class FlipperApplication: + appid: str + apptype: FlipperAppType + name: Optional[str] = None + entry_point: Optional[str] = None + flags: List[str] = field(default_factory=lambda: ["Default"]) + cdefines: List[str] = field(default_factory=list) + requires: List[str] = field(default_factory=list) + conflicts: List[str] = field(default_factory=list) + provides: List[str] = field(default_factory=list) + stack_size: int = 2048 + icon: Optional[str] = None + order: int = 0 + _appdir: Optional[str] = None + + +class AppManager: + def __init__(self): + self.known_apps = {} + + def get(self, appname: str): + try: + return self.known_apps[appname] + except KeyError as _: + raise FlipperManifestException( + f"Missing application manifest for '{appname}'" + ) + + def load_manifest(self, app_manifest_path: str, app_dir_name: str): + if not os.path.exists(app_manifest_path): + raise FlipperManifestException( + f"App manifest not found at path {app_manifest_path}" + ) + # print("Loading", app_manifest_path) + + app_manifests = [] + + def App(*args, **kw): + nonlocal app_manifests + app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name)) + + with open(app_manifest_path, "rt") as manifest_file: + exec(manifest_file.read()) + + if len(app_manifests) == 0: + raise FlipperManifestException( + f"App manifest '{app_manifest_path}' is malformed" + ) + + # print("Built", app_manifests) + for app in app_manifests: + self._add_known_app(app) + + def _add_known_app(self, app: FlipperApplication): + if self.known_apps.get(app.appid, None): + raise FlipperManifestException(f"Duplicate app declaration: {app.appid}") + self.known_apps[app.appid] = app + + def filter_apps(self, applist: List[str]): + return AppBuildset(self, applist) + + +class AppBuilderException(Exception): + pass + + +class AppBuildset: + BUILTIN_APP_TYPES = ( + FlipperAppType.SERVICE, + FlipperAppType.SYSTEM, + FlipperAppType.APP, + FlipperAppType.PLUGIN, + FlipperAppType.DEBUG, + FlipperAppType.ARCHIVE, + FlipperAppType.SETTINGS, + FlipperAppType.STARTUP, + ) + + def __init__(self, appmgr: AppManager, appnames: List[str]): + self.appmgr = appmgr + self.appnames = set(appnames) + self._orig_appnames = appnames + self._process_deps() + self._check_conflicts() + self._check_unsatisfied() # unneeded? + self.apps = sorted( + list(map(self.appmgr.get, self.appnames)), + key=lambda app: app.appid, + ) + + def _is_missing_dep(self, dep_name: str): + return dep_name not in self.appnames + + def _process_deps(self): + while True: + provided = [] + for app in self.appnames: + # print(app) + provided.extend( + filter( + self._is_missing_dep, + self.appmgr.get(app).provides + self.appmgr.get(app).requires, + ) + ) + # print("provides round", provided) + if len(provided) == 0: + break + self.appnames.update(provided) + + def _check_conflicts(self): + conflicts = [] + for app in self.appnames: + # print(app) + if conflict_app_name := list( + filter( + lambda dep_name: dep_name in self.appnames, + self.appmgr.get(app).conflicts, + ) + ): + conflicts.append((app, conflict_app_name)) + + if len(conflicts): + raise AppBuilderException( + f"App conflicts for {', '.join(f'{conflict_dep[0]}: {conflict_dep[1]}' for conflict_dep in conflicts)}" + ) + + def _check_unsatisfied(self): + unsatisfied = [] + for app in self.appnames: + if missing_dep := list( + filter(self._is_missing_dep, self.appmgr.get(app).requires) + ): + unsatisfied.append((app, missing_dep)) + + if len(unsatisfied): + raise AppBuilderException( + f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" + ) + + def get_apps_cdefs(self): + cdefs = set() + for app in self.apps: + cdefs.update(app.cdefines) + return sorted(list(cdefs)) + + def get_apps_of_type(self, apptype: FlipperAppType): + return sorted( + filter(lambda app: app.apptype == apptype, self.apps), + key=lambda app: app.order, + ) + + def get_builtin_app_folders(self): + return sorted( + set( + app._appdir + for app in filter( + lambda app: app.apptype in self.BUILTIN_APP_TYPES, self.apps + ) + ) + ) + + +class ApplicationsCGenerator: + APP_TYPE_MAP = { + FlipperAppType.SERVICE: ("FlipperApplication", "FLIPPER_SERVICES"), + FlipperAppType.SYSTEM: ("FlipperApplication", "FLIPPER_SYSTEM_APPS"), + FlipperAppType.APP: ("FlipperApplication", "FLIPPER_APPS"), + FlipperAppType.PLUGIN: ("FlipperApplication", "FLIPPER_PLUGINS"), + FlipperAppType.DEBUG: ("FlipperApplication", "FLIPPER_DEBUG_APPS"), + FlipperAppType.SETTINGS: ("FlipperApplication", "FLIPPER_SETTINGS_APPS"), + FlipperAppType.STARTUP: ("FlipperOnStartHook", "FLIPPER_ON_SYSTEM_START"), + } + + def __init__(self, buildset: AppBuildset): + self.buildset = buildset + + def get_app_ep_forward(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return f"extern void {app.entry_point}();" + return f"extern int32_t {app.entry_point}(void* p);" + + def get_app_descr(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return app.entry_point + return f""" + {{.app = {app.entry_point}, + .name = "{app.name}", + .stack_size = {app.stack_size}, + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" + + def generate(self): + contents = ['#include "applications.h"', "#include "] + for apptype in self.APP_TYPE_MAP: + contents.extend( + map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) + ) + entry_type, entry_block = self.APP_TYPE_MAP[apptype] + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append( + ",\n".join( + map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) + ) + ) + contents.append("};") + contents.append( + f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" + ) + + archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) + if archive_app: + contents.extend( + [ + self.get_app_ep_forward(archive_app[0]), + f"const FlipperApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", + ] + ) + + return "\n".join(contents) diff --git a/site_scons/fbt/util.py b/site_scons/fbt/util.py new file mode 100644 index 00000000..9de24a9a --- /dev/null +++ b/site_scons/fbt/util.py @@ -0,0 +1,19 @@ +import SCons +from SCons.Subst import quote_spaces + +import re + + +WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") + + +def tempfile_arg_esc_func(arg): + arg = quote_spaces(arg) + if SCons.Platform.platform_default() != "win32": + return arg + # GCC requires double Windows slashes, let's use UNIX separator + return WINPATHSEP_RE.sub(r"/\1", arg) + + +def wrap_tempfile(env, command): + env[command] = '${TEMPFILE("' + env[command] + '","$' + command + 'STR")}' diff --git a/site_scons/fbt/version.py b/site_scons/fbt/version.py new file mode 100644 index 00000000..4745c700 --- /dev/null +++ b/site_scons/fbt/version.py @@ -0,0 +1,23 @@ +import subprocess +import datetime + + +def get_fast_git_version_id(): + try: + version = ( + subprocess.check_output( + [ + "git", + "describe", + "--always", + "--dirty", + "--all", + "--long", + ] + ) + .strip() + .decode() + ) + return (version, datetime.date.today()) + except Exception as e: + print("Failed to check for git changes", e) diff --git a/site_scons/firmwareopts.scons b/site_scons/firmwareopts.scons new file mode 100644 index 00000000..f04b55cd --- /dev/null +++ b/site_scons/firmwareopts.scons @@ -0,0 +1,50 @@ +Import("ENV") + + +if ENV["DEBUG"]: + ENV.Append( + CPPDEFINES=[ + "FURI_DEBUG", + "NDEBUG", + ], + CCFLAGS=[ + "-Og", + ], + ) +elif ENV["COMPACT"]: + ENV.Append( + CPPDEFINES=[ + "FURI_NDEBUG", + "NDEBUG", + ], + CCFLAGS=[ + "-Os", + ], + ) +else: + ENV.Append( + CPPDEFINES=[ + "FURI_NDEBUG", + "NDEBUG", + ], + CCFLAGS=[ + "-Og", + ], + ) + +ENV.Append( + LINKFLAGS=[ + "-Tfirmware/targets/f${TARGET_HW}/${LINKER_SCRIPT}.ld", + ], +) + +if ENV["FIRMWARE_BUILD_CFG"] == "updater": + ENV.Append( + IMAGE_BASE_ADDRESS="0x20000000", + LINKER_SCRIPT="stm32wb55xx_ram_fw", + ) +else: + ENV.Append( + IMAGE_BASE_ADDRESS="0x8000000", + LINKER_SCRIPT="stm32wb55xx_flash", + ) diff --git a/site_scons/site_init.py b/site_scons/site_init.py new file mode 100644 index 00000000..817269e2 --- /dev/null +++ b/site_scons/site_init.py @@ -0,0 +1,40 @@ +from SCons.Script import GetBuildFailures + +import sys +import os +import atexit + +sys.path.insert(0, os.path.join(os.getcwd(), "scripts")) + + +def bf_to_str(bf): + """Convert an element of GetBuildFailures() to a string + in a useful way.""" + import SCons.Errors + + if bf is None: # unknown targets product None in list + return "(unknown tgt)" + elif isinstance(bf, SCons.Errors.StopError): + return str(bf) + elif bf.node: + return str(bf.node) + ": " + bf.errstr + elif bf.filename: + return bf.filename + ": " + bf.errstr + return "unknown failure: " + bf.errstr + + +def display_build_status(): + """Display the build status. Called by atexit. + Here you could do all kinds of complicated things.""" + bf = GetBuildFailures() + if bf: + # bf is normally a list of build failures; if an element is None, + # it's because of a target that scons doesn't know anything about. + failures_message = "\n".join( + ["Failed building %s" % bf_to_str(x) for x in bf if x is not None] + ) + print("*" * 10, "ERRORS", "*" * 10) + print(failures_message) + + +atexit.register(display_build_status) diff --git a/site_scons/site_tools/ccache.py b/site_scons/site_tools/ccache.py new file mode 100644 index 00000000..e88886ad --- /dev/null +++ b/site_scons/site_tools/ccache.py @@ -0,0 +1,14 @@ +def exists(): + return True + + +def generate(env): + if ccache := env.WhereIs("ccache"): + env["CCACHE"] = "ccache" + env["CC_NOCACHE"] = env["CC"] + env["CC"] = "$CCACHE $CC_NOCACHE" + # Tricky place: linking is done with CXX + # Using ccache breaks it + env["LINK"] = env["CXX"] + env["CXX_NOCACHE"] = env["CXX"] + env["CXX"] = "$CCACHE $CXX_NOCACHE" diff --git a/site_scons/site_tools/crosscc.py b/site_scons/site_tools/crosscc.py new file mode 100644 index 00000000..0770df71 --- /dev/null +++ b/site_scons/site_tools/crosscc.py @@ -0,0 +1,72 @@ +from SCons.Tool import asm +from SCons.Tool import gcc +from SCons.Tool import gxx +from SCons.Tool import ar +from SCons.Tool import gnulink +import strip +import gdb +import objdump + +from SCons.Action import _subproc +import subprocess + + +def prefix_commands(env, command_prefix, cmd_list): + for command in cmd_list: + if command in env: + env[command] = command_prefix + env[command] + + +def _get_tool_version(env, tool): + verstr = "version unknown" + proc = _subproc( + env, + env.subst("${%s} --version" % tool), + stdout=subprocess.PIPE, + stderr="devnull", + stdin="devnull", + universal_newlines=True, + error="raise", + shell=True, + ) + if proc: + verstr = proc.stdout.readline() + proc.communicate() + return verstr + + +def generate(env, **kw): + for orig_tool in (asm, gcc, gxx, ar, gnulink, strip, gdb, objdump): + orig_tool.generate(env) + env.SetDefault( + TOOLCHAIN_PREFIX=kw.get("toolchain_prefix"), + ) + prefix_commands( + env, + env.subst("$TOOLCHAIN_PREFIX"), + [ + "AR", + "AS", + "CC", + "CXX", + "OBJCOPY", + "RANLIB", + "STRIP", + "GDB", + "GDBPY", + "OBJDUMP", + ], + ) + # Call CC to check version + if whitelisted_versions := kw.get("versions", ()): + cc_version = _get_tool_version(env, "CC") + # print("CC version =", cc_version) + # print(list(filter(lambda v: v in cc_version, whitelisted_versions))) + if not any(filter(lambda v: v in cc_version, whitelisted_versions)): + raise Exception( + f"Toolchain version is not supported. Allowed: {whitelisted_versions}, toolchain: {cc_version} " + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/fbt_apps.py b/site_scons/site_tools/fbt_apps.py new file mode 100644 index 00000000..cbeae2d0 --- /dev/null +++ b/site_scons/site_tools/fbt_apps.py @@ -0,0 +1,61 @@ +from SCons.Builder import Builder +from SCons.Action import Action + +import SCons +from fbt.appmanifest import FlipperAppType, AppManager, ApplicationsCGenerator + +# Adding objects for application management to env +# AppManager env["APPMGR"] - loads all manifests; manages list of known apps +# AppBuildset env["APPBUILD"] - contains subset of apps, filtered for current config + + +def LoadApplicationManifests(env): + appmgr = env["APPMGR"] = AppManager() + for entry in env.Glob("#/applications/*"): + if isinstance(entry, SCons.Node.FS.Dir) and not str(entry).startswith("."): + appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) + + +def PrepareApplicationsBuild(env): + env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"]) + env["APPBUILD_DUMP"] = env.Action( + DumpApplicationConfig, + "\tINFO\t", + ) + + +def DumpApplicationConfig(target, source, env): + print(f"Loaded {len(env['APPMGR'].known_apps)} app definitions.") + print("Firmware modules configuration:") + for apptype in FlipperAppType: + app_sublist = env["APPBUILD"].get_apps_of_type(apptype) + if app_sublist: + print( + f"{apptype.value}:\n\t", + ", ".join(app.appid for app in app_sublist), + ) + + +def build_apps_c(target, source, env): + target_file_name = target[0].path + + gen = ApplicationsCGenerator(env["APPBUILD"]) + with open(target_file_name, "w") as file: + file.write(gen.generate()) + + +def generate(env): + env.AddMethod(LoadApplicationManifests) + env.AddMethod(PrepareApplicationsBuild) + + env.Append( + BUILDERS={ + "ApplicationsC": Builder( + action=Action(build_apps_c, "${APPSCOMSTR}"), + ), + } + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/fbt_assets.py b/site_scons/site_tools/fbt_assets.py new file mode 100644 index 00000000..0c2ce6f7 --- /dev/null +++ b/site_scons/site_tools/fbt_assets.py @@ -0,0 +1,151 @@ +import SCons + +from SCons.Builder import Builder +from SCons.Action import Action +from SCons.Node.FS import File + +import os +import subprocess + + +def icons_emitter(target, source, env): + target = [ + "compiled/assets_icons.c", + "compiled/assets_icons.h", + ] + return target, source + + +def proto_emitter(target, source, env): + out_path = target[0].path + target = [] + for src in source: + basename = os.path.splitext(src.name)[0] + target.append(env.File(f"compiled/{basename}.pb.c")) + target.append(env.File(f"compiled/{basename}.pb.h")) + return target, source + + +def dolphin_emitter(target, source, env): + res_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) + source = [res_root_dir] + source.extend( + env.GlobRecursive("*.*", res_root_dir), + ) + + target_base_dir = target[0] + env.Replace(_DOLPHIN_OUT_DIR=target[0]) + + if env["DOLPHIN_RES_TYPE"] == "external": + target = [] + target.extend( + map( + lambda node: target_base_dir.File( + res_root_dir.rel_path(node).replace(".png", ".bm") + ), + filter(lambda node: isinstance(node, SCons.Node.FS.File), source), + ) + ) + else: + asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" + target = [ + target_base_dir.File(asset_basename + ".c"), + target_base_dir.File(asset_basename + ".h"), + ] + + return target, source + + +def _invoke_git(args, source_dir): + cmd = ["git"] + cmd.extend(args) + return ( + subprocess.check_output(cmd, cwd=source_dir, stderr=subprocess.STDOUT) + .strip() + .decode() + ) + + +def proto_ver_generator(target, source, env): + target_file = target[0] + src_dir = source[0].dir.abspath + try: + git_fetch = _invoke_git( + ["fetch", "--tags"], + source_dir=src_dir, + ) + except (subprocess.CalledProcessError, EnvironmentError) as e: + # Not great, not terrible + print("Git: fetch failed") + + try: + git_describe = _invoke_git( + ["describe", "--tags", "--abbrev=0"], + source_dir=src_dir, + ) + except (subprocess.CalledProcessError, EnvironmentError) as e: + print("Git: describe failed") + Exit("git error") + + # print("describe=", git_describe) + git_major, git_minor = git_describe.split(".") + version_file_data = ( + "#pragma once", + f"#define PROTOBUF_MAJOR_VERSION {git_major}", + f"#define PROTOBUF_MINOR_VERSION {git_minor}", + "", + ) + with open(str(target_file), "wt") as file: + file.write("\n".join(version_file_data)) + + +def generate(env): + env.SetDefault( + ASSETS_COMPILER="${ROOT_DIR.abspath}/scripts/assets.py", + NANOPB_COMPILER="${ROOT_DIR.abspath}/lib/nanopb/generator/nanopb_generator.py", + ) + + env.Append( + BUILDERS={ + "IconBuilder": Builder( + action=Action( + "${PYTHON3} ${ASSETS_COMPILER} icons ${SOURCE.posix} ${TARGET.dir.posix}", + "${ICONSCOMSTR}", + ), + emitter=icons_emitter, + ), + "ProtoBuilder": Builder( + action=Action( + "${PYTHON3} ${NANOPB_COMPILER} -q -I${SOURCE.dir.posix} -D${TARGET.dir.posix} ${SOURCES.posix}", + "${PROTOCOMSTR}", + ), + emitter=proto_emitter, + suffix=".pb.c", + src_suffix=".proto", + ), + "DolphinSymBuilder": Builder( + action=Action( + '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', + "${DOLPHINCOMSTR}", + ), + emitter=dolphin_emitter, + ), + "DolphinExtBuilder": Builder( + action=Action( + '${PYTHON3} ${ASSETS_COMPILER} dolphin "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', + "${DOLPHINCOMSTR}", + ), + emitter=dolphin_emitter, + ), + "ProtoVerBuilder": Builder( + action=Action( + proto_ver_generator, + "${PBVERCOMSTR}", + ), + ), + } + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/fbt_dist.py b/site_scons/site_tools/fbt_dist.py new file mode 100644 index 00000000..c39f7242 --- /dev/null +++ b/site_scons/site_tools/fbt_dist.py @@ -0,0 +1,104 @@ +from SCons.Builder import Builder +from SCons.Action import Action +from SCons.Script import Mkdir + + +def get_variant_dirname(env, project=None): + parts = [f"f{env['TARGET_HW']}"] + if project: + parts.append(project) + + suffix = "" + if env["DEBUG"]: + suffix += "D" + if env["COMPACT"]: + suffix += "C" + if suffix: + parts.append(suffix) + + return "-".join(parts) + + +def create_fw_build_targets(env, configuration_name): + flavor = get_variant_dirname(env, configuration_name) + build_dir = env.Dir("build").Dir(flavor).abspath + return env.SConscript( + "firmware.scons", + variant_dir=build_dir, + duplicate=0, + exports={ + "ENV": env, + "fw_build_meta": { + "type": configuration_name, + "flavor": flavor, + "build_dir": build_dir, + }, + }, + ) + + +def AddFwProject(env, base_env, fw_type, fw_env_key): + project_env = env[fw_env_key] = create_fw_build_targets(base_env, fw_type) + env.Append( + DIST_PROJECTS=[ + project_env["FW_FLAVOR"], + ], + DIST_DEPENDS=[ + project_env["FW_ARTIFACTS"], + ], + ) + return project_env + + +def AddDebugTarget(env, targetenv, force_flash=True): + pseudo_name = f"debug.{targetenv.subst('$FIRMWARE_BUILD_CFG')}.pseudo" + debug_target = env.GDBPy( + pseudo_name, + targetenv["FW_ELF"], + GDBPYOPTS='-ex "source debug/FreeRTOS/FreeRTOS.py" ' + '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ' + '-ex "svd_load ${SVD_FILE}" ' + '-ex "compare-sections"', + ) + if force_flash: + env.Depends(debug_target, targetenv["FW_FLASH"]) + env.Pseudo(pseudo_name) + env.AlwaysBuild(debug_target) + return debug_target + + +def generate(env): + env.AddMethod(AddFwProject) + env.AddMethod(AddDebugTarget) + env.SetDefault( + COPRO_MCU_FAMILY="STM32WB5x", + ) + env.Append( + BUILDERS={ + "DistBuilder": Builder( + action=Action( + '${PYTHON3} ${ROOT_DIR.abspath}/scripts/sconsdist.py copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}" ${DIST_EXTRA}', + "${DISTCOMSTR}", + ), + ), + "CoproBuilder": Builder( + action=Action( + [ + Mkdir("$TARGET"), + "${PYTHON3} ${ROOT_DIR.abspath}/scripts/assets.py " + "copro ${COPRO_CUBE_DIR} " + "${TARGET} ${COPRO_MCU_FAMILY} " + "--cube_ver=${COPRO_CUBE_VERSION} " + "--stack_type=${COPRO_STACK_TYPE} " + '--stack_file="${COPRO_STACK_BIN}" ' + "--stack_addr=${COPRO_STACK_ADDR} ", + ], + "", + ) + ), + } + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/fbt_extapps.py b/site_scons/site_tools/fbt_extapps.py new file mode 100644 index 00000000..17c4bf6c --- /dev/null +++ b/site_scons/site_tools/fbt_extapps.py @@ -0,0 +1,30 @@ +import os + + +def BuildAppElf(env, app): + work_dir = env.subst("$EXT_APPS_WORK_DIR") + app_target_name = os.path.join(work_dir, app.appid) + app_alias = f"{env['FIRMWARE_BUILD_CFG']}_{app.appid}" + app_elf = env.Program( + app_target_name, + env.GlobRecursive("*.c*", os.path.join(work_dir, app._appdir)), + APP_ENTRY=app.entry_point, + ) + app_elf_dump = env.ObjDump(app_target_name) + env.Alias(f"{app_alias}_list", app_elf_dump) + + app_stripped_elf = env.ELFStripper( + os.path.join(env.subst("$PLUGIN_ELF_DIR"), app.appid), app_elf + ) + env.Alias(app_alias, app_stripped_elf) + return app_stripped_elf + + +def generate(env, **kw): + env.SetDefault(EXT_APPS_WORK_DIR=kw.get("EXT_APPS_WORK_DIR", ".extapps")) + env.VariantDir(env.subst("$EXT_APPS_WORK_DIR"), ".", duplicate=False) + env.AddMethod(BuildAppElf) + + +def exists(env): + return True diff --git a/site_scons/site_tools/fbt_version.py b/site_scons/site_tools/fbt_version.py new file mode 100644 index 00000000..5073c55d --- /dev/null +++ b/site_scons/site_tools/fbt_version.py @@ -0,0 +1,29 @@ +from SCons.Builder import Builder +from SCons.Action import Action + + +def version_emitter(target, source, env): + target_dir = target[0] + target = [ + target_dir.File("version.inc.h"), + target_dir.File("version.json"), + ] + return target, source + + +def generate(env): + env.Append( + BUILDERS={ + "VersionBuilder": Builder( + action=Action( + "${PYTHON3} ${ROOT_DIR.abspath}/scripts/version.py generate -t ${TARGET_HW} -o ${TARGET.dir.posix} --dir ${ROOT_DIR}", + "${VERSIONCOMSTR}", + ), + emitter=version_emitter, + ), + } + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/fwbin.py b/site_scons/site_tools/fwbin.py new file mode 100644 index 00000000..848571e3 --- /dev/null +++ b/site_scons/site_tools/fwbin.py @@ -0,0 +1,52 @@ +from SCons.Builder import Builder +from SCons.Action import Action +import SCons + +__OBJCOPY_ARM_BIN = "arm-none-eabi-objcopy" + + +def generate(env): + env.SetDefault( + BIN2DFU="${ROOT_DIR.abspath}/scripts/bin2dfu.py", + OBJCOPY=__OBJCOPY_ARM_BIN, # FIXME + ) + env.Append( + BUILDERS={ + "HEXBuilder": Builder( + action=Action( + '${OBJCOPY} -O ihex "${SOURCE}" "${TARGET}"', + "${HEXCOMSTR}", + ), + suffix=".hex", + src_suffix=".elf", + ), + "BINBuilder": Builder( + action=Action( + '${OBJCOPY} -O binary -S "${SOURCE}" "${TARGET}"', + "${BINCOMSTR}", + ), + suffix=".bin", + src_suffix=".elf", + ), + "DFUBuilder": Builder( + action=Action( + '${PYTHON3} ${BIN2DFU} -i "${SOURCE}" -o "${TARGET}" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"', + "${DFUCOMSTR}", + ), + suffix=".dfu", + src_suffix=".bin", + ), + } + ) + + +def exists(env): + try: + return env["OBJCOPY"] + except KeyError: + pass + + if objcopy := env.WhereIs(__OBJCOPY_ARM_BIN): + return objcopy + + raise SCons.Errors.StopError("Could not detect objcopy for arm") diff --git a/site_scons/site_tools/gdb.py b/site_scons/site_tools/gdb.py new file mode 100644 index 00000000..e7b6bdd6 --- /dev/null +++ b/site_scons/site_tools/gdb.py @@ -0,0 +1,33 @@ +from SCons.Builder import Builder +from SCons.Action import Action + + +def generate(env): + env.SetDefault( + GDB="gdb", + GDBPY="gdb-py", + GDBOPTS="", + GDBPYOPTS="", + GDBCOM="$GDB $GDBOPTS $SOURCES", # no $TARGET + GDBPYCOM="$GDBPY $GDBOPTS $GDBPYOPTS $SOURCES", # no $TARGET + ) + env.Append( + BUILDERS={ + "GDB": Builder( + action=Action( + "${GDBCOM}", + "${GDBCOMSTR}", + ), + ), + "GDBPy": Builder( + action=Action( + "${GDBPYCOM}", + "${GDBPYCOMSTR}", + ), + ), + } + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/objdump.py b/site_scons/site_tools/objdump.py new file mode 100644 index 00000000..f5fa938a --- /dev/null +++ b/site_scons/site_tools/objdump.py @@ -0,0 +1,26 @@ +from SCons.Builder import Builder +from SCons.Action import Action + + +def generate(env): + env.SetDefault( + OBJDUMP="objdump", + OBJDUMPFLAGS=[], + OBJDUMPCOM="$OBJDUMP $OBJDUMPFLAGS -S $SOURCES > $TARGET", + ) + env.Append( + BUILDERS={ + "ObjDump": Builder( + action=Action( + "${OBJDUMPCOM}", + "${OBJDUMPCOMSTR}", + ), + suffix=".lst", + src_suffix=".elf", + ), + } + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/openocd.py b/site_scons/site_tools/openocd.py new file mode 100644 index 00000000..135e1100 --- /dev/null +++ b/site_scons/site_tools/openocd.py @@ -0,0 +1,48 @@ +from SCons.Builder import Builder +from SCons.Action import Action +from SCons.Defaults import Touch +import SCons + +__OPENOCD_BIN = "openocd" + +_oocd_action = Action( + "${OPENOCD} ${OPENOCD_OPTS} ${OPENOCD_COMMAND}", + "${OOCDCOMSTR}", +) + + +def generate(env): + env.SetDefault( + OPENOCD=__OPENOCD_BIN, + OPENOCD_OPTS="", + OPENOCD_COMMAND="", + OOCDCOMSTR="", + ) + + env.Append( + BUILDERS={ + "OOCDFlashCommand": Builder( + action=[ + _oocd_action, + Touch("${TARGET}"), + ], + suffix=".flash", + src_suffix=".bin", + ), + "OOCDCommand": Builder( + action=_oocd_action, + ), + } + ) + + +def exists(env): + try: + return env["OPENOCD"] + except KeyError: + pass + + if openocd := env.WhereIs(__OPENOCD_BIN): + return openocd + + raise SCons.Errors.StopError("Could not detect openocd") diff --git a/site_scons/site_tools/python3.py b/site_scons/site_tools/python3.py new file mode 100644 index 00000000..8ac5490d --- /dev/null +++ b/site_scons/site_tools/python3.py @@ -0,0 +1,13 @@ +def generate(env): + py_name = "python3" + if env["PLATFORM"] == "win32": + # On Windows, Python 3 executable is usually just "python" + py_name = "python" + + env.SetDefault( + PYTHON3=py_name, + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/sconsmodular.py b/site_scons/site_tools/sconsmodular.py new file mode 100644 index 00000000..eeb90022 --- /dev/null +++ b/site_scons/site_tools/sconsmodular.py @@ -0,0 +1,38 @@ +import posixpath +import os + + +def BuildModule(env, module): + src_dir = str(env.Dir(".").srcdir or os.getcwd()) + module_sconscript = posixpath.join(src_dir, module, "SConscript") + if not os.path.exists(module_sconscript): + module_sconscript = posixpath.join(src_dir, f"{module}.scons") + if not os.path.exists(module_sconscript): + print(f"Cannot build module {module}: scons file not found") + Exit(2) + + return env.SConscript( + module_sconscript, + variant_dir=posixpath.join(env.subst("$BUILD_DIR"), module), + duplicate=0, + ) + + +def BuildModules(env, modules): + result = [] + for module in modules: + build_res = env.BuildModule(module) + # print("module ", module, build_res) + if build_res is None: + continue + result.append(build_res) + return result + + +def generate(env): + env.AddMethod(BuildModule) + env.AddMethod(BuildModules) + + +def exists(env): + return True diff --git a/site_scons/site_tools/sconsrecursiveglob.py b/site_scons/site_tools/sconsrecursiveglob.py new file mode 100644 index 00000000..32ff55ea --- /dev/null +++ b/site_scons/site_tools/sconsrecursiveglob.py @@ -0,0 +1,25 @@ +import SCons + + +def GlobRecursive(env, pattern, node=".", exclude=None): + results = [] + if isinstance(node, str): + node = env.Dir(node) + for f in node.glob("*", source=True, exclude=exclude): + if isinstance(f, SCons.Node.FS.Dir): + results += env.GlobRecursive(pattern, f, exclude) + results += node.glob( + pattern, + source=True, + exclude=exclude, + ) + # print(f"Glob for {pattern} from {node}: {results}") + return results + + +def generate(env): + env.AddMethod(GlobRecursive) + + +def exists(env): + return True diff --git a/site_scons/site_tools/strip.py b/site_scons/site_tools/strip.py new file mode 100644 index 00000000..053956f2 --- /dev/null +++ b/site_scons/site_tools/strip.py @@ -0,0 +1,26 @@ +from SCons.Builder import Builder +from SCons.Action import Action + + +def generate(env): + env.SetDefault( + STRIP="strip", + STRIPFLAGS=[], + STRIPCOM="$STRIP $STRIPFLAGS $SOURCES -o $TARGET", + ) + env.Append( + BUILDERS={ + "ELFStripper": Builder( + action=Action( + "${STRIPCOM}", + "${STRIPCOMSTR}", + ), + suffix=".elf", + src_suffix=".elf", + ), + } + ) + + +def exists(env): + return True From 6d38740a4669261d9c865c4c6f6924ae4cb2afc5 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Sun, 26 Jun 2022 16:16:56 +0400 Subject: [PATCH 15/17] SubGhz: fix protocol scher_khan (#1323) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/subghz/protocols/scher_khan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/subghz/protocols/scher_khan.c b/lib/subghz/protocols/scher_khan.c index a9a7c040..233b9564 100644 --- a/lib/subghz/protocols/scher_khan.c +++ b/lib/subghz/protocols/scher_khan.c @@ -233,7 +233,7 @@ static void subghz_protocol_scher_khan_check_remote_controller( // break; default: - instance->protocol_name = "Unknown"; + *protocol_name = "Unknown"; instance->serial = 0; instance->btn = 0; instance->cnt = 0; From e6f18cc32272bd4e23ac9eee8241c6e916b3b9ad Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 28 Jun 2022 15:28:55 +0300 Subject: [PATCH 16/17] fbt: building `core` with respect for debug flag (#1347) * fbt: building `core` with respect for debug flag * fbt: added size output for firmware elf * Infrared: fix cli Co-authored-by: Aleksandr Kutuzov --- applications/infrared/infrared_cli.c | 1 + firmware.scons | 13 ++++++++++++- site_scons/site_tools/crosscc.py | 4 +++- site_scons/site_tools/fbt_dist.py | 3 +-- site_scons/site_tools/size.py | 24 ++++++++++++++++++++++++ 5 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 site_scons/site_tools/size.py diff --git a/applications/infrared/infrared_cli.c b/applications/infrared/infrared_cli.c index 1b3ec4b3..d88e7fff 100644 --- a/applications/infrared/infrared_cli.c +++ b/applications/infrared/infrared_cli.c @@ -97,6 +97,7 @@ static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) return false; } + message.protocol = infrared_get_protocol_by_name(protocol_name); message.repeat = false; infrared_signal_set_message(signal, &message); return infrared_signal_is_valid(signal); diff --git a/firmware.scons b/firmware.scons index 3652c298..890be5f8 100644 --- a/firmware.scons +++ b/firmware.scons @@ -39,7 +39,17 @@ env = ENV.Clone( ], # You can add other entries named after libraries # If they are present, they have precedence over Default - } + }, + # for furi_check to respect build type + "core": { + "CCFLAGS": [ + "-Os", + ], + "CPPDEFINES": [ + "NDEBUG", + "FURI_DEBUG" if ENV["DEBUG"] else "FURI_NDEBUG", + ], + }, }, ) @@ -191,6 +201,7 @@ fwelf = fwenv["FW_ELF"] = fwenv.Program( # Make it depend on everything child builders returned Depends(fwelf, lib_targets) AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) +AddPostAction(fwelf, Action("@$SIZECOM")) fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") diff --git a/site_scons/site_tools/crosscc.py b/site_scons/site_tools/crosscc.py index 0770df71..8d6b4a61 100644 --- a/site_scons/site_tools/crosscc.py +++ b/site_scons/site_tools/crosscc.py @@ -6,6 +6,7 @@ from SCons.Tool import gnulink import strip import gdb import objdump +import size from SCons.Action import _subproc import subprocess @@ -36,7 +37,7 @@ def _get_tool_version(env, tool): def generate(env, **kw): - for orig_tool in (asm, gcc, gxx, ar, gnulink, strip, gdb, objdump): + for orig_tool in (asm, gcc, gxx, ar, gnulink, strip, gdb, objdump, size): orig_tool.generate(env) env.SetDefault( TOOLCHAIN_PREFIX=kw.get("toolchain_prefix"), @@ -55,6 +56,7 @@ def generate(env, **kw): "GDB", "GDBPY", "OBJDUMP", + "SIZE", ], ) # Call CC to check version diff --git a/site_scons/site_tools/fbt_dist.py b/site_scons/site_tools/fbt_dist.py index c39f7242..8fad2156 100644 --- a/site_scons/site_tools/fbt_dist.py +++ b/site_scons/site_tools/fbt_dist.py @@ -77,8 +77,7 @@ def generate(env): BUILDERS={ "DistBuilder": Builder( action=Action( - '${PYTHON3} ${ROOT_DIR.abspath}/scripts/sconsdist.py copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}" ${DIST_EXTRA}', - "${DISTCOMSTR}", + '@${PYTHON3} ${ROOT_DIR.abspath}/scripts/sconsdist.py copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}" ${DIST_EXTRA}', ), ), "CoproBuilder": Builder( diff --git a/site_scons/site_tools/size.py b/site_scons/site_tools/size.py new file mode 100644 index 00000000..56d4f3c9 --- /dev/null +++ b/site_scons/site_tools/size.py @@ -0,0 +1,24 @@ +from SCons.Builder import Builder +from SCons.Action import Action + + +def generate(env): + env.SetDefault( + SIZE="size", + SIZEFLAGS=[], + SIZECOM="$SIZE $SIZEFLAGS $TARGETS", + ) + env.Append( + BUILDERS={ + "ELFSize": Builder( + action=Action( + "${SIZECOM}", + "${SIZECOMSTR}", + ), + ), + } + ) + + +def exists(env): + return True From 8b988e2b17ec512505f7c9362794e82ff49fe17d Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 28 Jun 2022 16:03:49 +0300 Subject: [PATCH 17/17] fbt: updater over USB (#1344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Scripts: added update package uploader over USB; fbt: added flash_usb target * fbt: additional dependencies for flash_usb * Cli: fix cursor_position corruption Co-authored-by: あく --- SConstruct | 13 ++- applications/cli/cli.c | 3 +- documentation/fbt.md | 4 +- scripts/flipper/storage.py | 4 +- scripts/selfupdate.py | 143 ++++++++++++++++++++++++++++++ scripts/storage.py | 24 +++-- site_scons/site_tools/fbt_dist.py | 10 +++ 7 files changed, 188 insertions(+), 13 deletions(-) create mode 100644 scripts/selfupdate.py diff --git a/SConstruct b/SConstruct index a31811ae..312b23a6 100644 --- a/SConstruct +++ b/SConstruct @@ -84,6 +84,16 @@ if GetOption("fullenv"): debug_updater_elf = distenv.AddDebugTarget(updater_out, False) Alias("updater_debug", debug_updater_elf) + # Installation over USB & CLI + usb_update_package = distenv.UsbInstall( + "usbinstall.flag", + (distenv["DIST_DEPENDS"], firmware_out["FW_RESOURCES"], selfupdate_dist), + ) + if distenv["FORCE"]: + AlwaysBuild(usb_update_package) + Depends(usb_update_package, selfupdate_dist) + Alias("flash_usb", usb_update_package) + # Target for copying & renaming binaries to dist folder basic_dist = distenv.DistBuilder("dist.pseudo", distenv["DIST_DEPENDS"]) @@ -92,6 +102,7 @@ AlwaysBuild(basic_dist) Alias("fw_dist", basic_dist) Default(basic_dist) + # Target for bundling core2 package for qFlipper copro_dist = distenv.CoproBuilder( Dir("assets/core2_firmware"), @@ -113,7 +124,7 @@ debug_other = distenv.GDBPy( None, GDBPYOPTS= # '-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' - '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ' + '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ', ) distenv.Pseudo("debugother.pseudo") AlwaysBuild(debug_other) diff --git a/applications/cli/cli.c b/applications/cli/cli.c index eefbb305..aa48e93b 100644 --- a/applications/cli/cli.c +++ b/applications/cli/cli.c @@ -149,7 +149,8 @@ void cli_reset(Cli* cli) { } static void cli_handle_backspace(Cli* cli) { - if(string_size(cli->line) > 0) { + if(cli->cursor_position > 0) { + furi_assert(string_size(cli->line) > 0); // Other side printf("\e[D\e[1P"); fflush(stdout); diff --git a/documentation/fbt.md b/documentation/fbt.md index 7ada4bea..061339da 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -28,6 +28,8 @@ FBT keeps track of internal dependencies, so you only need to build the highest- - `fw_dist` - build & publish firmware to `dist` folder - `updater_package` - build self-update package. _Requires `--with-updater` option_ - `copro_dist` - bundle Core2 FUS+stack binaries for qFlipper +- `flash` - flash attached device with OpenOCD over ST-Link +- `flash_usb` - build, upload and install update package to device over USB. _Requires `--with-updater` option_ - `debug` - build and flash firmware, then attach with gdb with firmware's .elf loaded - `debug_updater` - attach gdb with updater's .elf loaded. _Requires `--with-updater` option_ - `debug_other` - attach gdb without loading built elf. Allows to manually add external elf files with `add-symbol-file` in gdb. @@ -39,7 +41,7 @@ FBT keeps track of internal dependencies, so you only need to build the highest- - `firmware_snake_game`, etc - build single plug-in as .elf by its name - Check out `--extra-ext-apps` for force adding extra apps to external build - `firmware_snake_game_list`, etc - generate source + assembler listing for app's .elf -- `firmware_flash` - flash current version to attached device with OpenOCD +- `flash`, `firmware_flash` - flash current version to attached device with OpenOCD over ST-Link - `firmware_cdb` - generate compilation database - `firmware_all`, `updater_all` - build basic set of binaries - `firmware_list`, `updater_list` - generate source + assembler listing diff --git a/scripts/flipper/storage.py b/scripts/flipper/storage.py index e15377d7..3d1b46b9 100644 --- a/scripts/flipper/storage.py +++ b/scripts/flipper/storage.py @@ -53,11 +53,11 @@ class FlipperStorage: CLI_PROMPT = ">: " CLI_EOL = "\r\n" - def __init__(self, portname: str): + def __init__(self, portname: str, portbaud: int = 115200): self.port = serial.Serial() self.port.port = portname self.port.timeout = 2 - self.port.baudrate = 115200 + self.port.baudrate = portbaud self.read = BufferedRead(self.port) self.last_error = "" diff --git a/scripts/selfupdate.py b/scripts/selfupdate.py new file mode 100644 index 00000000..538ecdb9 --- /dev/null +++ b/scripts/selfupdate.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +from flipper.storage import FlipperStorage + +import logging +import argparse +import os +import sys +import pathlib +import serial.tools.list_ports as list_ports + + +class Main: + def __init__(self): + # command args + self.parser = argparse.ArgumentParser() + self.parser.add_argument("-d", "--debug", action="store_true", help="Debug") + self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") + self.parser.add_argument( + "-b", + "--baud", + help="Port Baud rate", + required=False, + default=115200 * 4, + type=int, + ) + + self.subparsers = self.parser.add_subparsers(help="sub-command help") + + self.parser_install = self.subparsers.add_parser( + "install", help="Install OTA package" + ) + self.parser_install.add_argument("manifest_path", help="Manifest path") + self.parser_install.add_argument( + "--pkg_dir_name", help="Update dir name", default="pcbundle", required=False + ) + self.parser_install.set_defaults(func=self.install) + + # logging + self.logger = logging.getLogger() + + def __call__(self): + self.args = self.parser.parse_args() + if "func" not in self.args: + self.parser.error("Choose something to do") + # configure log output + self.log_level = logging.DEBUG if self.args.debug else logging.INFO + self.logger.setLevel(self.log_level) + self.handler = logging.StreamHandler(sys.stdout) + self.handler.setLevel(self.log_level) + self.formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s") + self.handler.setFormatter(self.formatter) + self.logger.addHandler(self.handler) + # execute requested function + self.args.func() + + # make directory with exist check + def mkdir_on_storage(self, storage, flipper_dir_path): + if not storage.exist_dir(flipper_dir_path): + self.logger.debug(f'"{flipper_dir_path}" does not exist, creating') + if not storage.mkdir(flipper_dir_path): + self.logger.error(f"Error: {storage.last_error}") + return False + else: + self.logger.debug(f'"{flipper_dir_path}" already exists') + return True + + # send file with exist check and hash check + def send_file_to_storage(self, storage, flipper_file_path, local_file_path, force): + exists = storage.exist_file(flipper_file_path) + do_upload = not exists + if exists: + hash_local = storage.hash_local(local_file_path) + hash_flipper = storage.hash_flipper(flipper_file_path) + self.logger.debug(f"hash check: local {hash_local}, flipper {hash_flipper}") + do_upload = force or (hash_local != hash_flipper) + + if do_upload: + self.logger.info(f'Sending "{local_file_path}" to "{flipper_file_path}"') + if not storage.send_file(local_file_path, flipper_file_path): + self.logger.error(f"Error: {storage.last_error}") + return False + return True + + def _get_port(self): + if self.args.port != "auto": + return self.args.port + # Try guessing + flippers = list(list_ports.grep("flip")) + if len(flippers) == 1: + flipper = flippers[0] + self.logger.info(f"Using {flipper.serial_number} on {flipper.device}") + return flipper.device + elif len(flippers) == 0: + self.logger.error("Failed to find connected Flipper") + elif len(flippers) > 1: + self.logger.error("More than one Flipper is attached") + self.logger.error("Failed to guess which port to use. Specify --port") + + def install(self): + if not (port := self._get_port()): + return 1 + + storage = FlipperStorage(port, self.args.baud) + storage.start() + + if not os.path.isfile(self.args.manifest_path): + self.logger.error("Error: manifest not found") + return 2 + + manifest_path = pathlib.Path(os.path.abspath(self.args.manifest_path)) + manifest_name, pkg_name = manifest_path.parts[-1], manifest_path.parts[-2] + + pkg_dir_name = self.args.pkg_dir_name or pkg_name + flipper_update_path = f"/ext/update/{pkg_dir_name}" + + self.logger.info(f'Installing "{pkg_name}" from {flipper_update_path}') + # if not os.path.exists(self.args.manifest_path): + # self.logger.error("Error: package not found") + if not self.mkdir_on_storage(storage, flipper_update_path): + self.logger.error(f"Error: cannot create {storage.last_error}") + return -2 + + for dirpath, dirnames, filenames in os.walk(manifest_path.parents[0]): + for fname in filenames: + self.logger.debug(f"Uploading {fname}") + local_file_path = os.path.join(dirpath, fname) + flipper_file_path = f"{flipper_update_path}/{fname}" + if not self.send_file_to_storage( + storage, flipper_file_path, local_file_path, False + ): + self.logger.error(f"Error: {storage.last_error}") + return -3 + + storage.send_and_wait_eol( + f"update install {flipper_update_path}/{manifest_name}\r" + ) + break + storage.stop() + + +if __name__ == "__main__": + Main()() diff --git a/scripts/storage.py b/scripts/storage.py index 4364eb28..1281253b 100755 --- a/scripts/storage.py +++ b/scripts/storage.py @@ -18,6 +18,14 @@ class Main: self.parser = argparse.ArgumentParser() self.parser.add_argument("-d", "--debug", action="store_true", help="Debug") self.parser.add_argument("-p", "--port", help="CDC Port", required=True) + self.parser.add_argument( + "-b", + "--baud", + help="Port Baud rate", + required=False, + default=115200 * 4, + type=int, + ) self.subparsers = self.parser.add_subparsers(help="sub-command help") self.parser_mkdir = self.subparsers.add_parser("mkdir", help="Create directory") @@ -195,31 +203,31 @@ class Main: # make directory with exist check def mkdir_on_storage(self, storage, flipper_dir_path): if not storage.exist_dir(flipper_dir_path): - self.logger.debug(f'"{flipper_dir_path}" not exist, creating') + self.logger.debug(f'"{flipper_dir_path}" does not exist, creating') if not storage.mkdir(flipper_dir_path): self.logger.error(f"Error: {storage.last_error}") else: - self.logger.debug(f'"{flipper_dir_path}" already exist') + self.logger.debug(f'"{flipper_dir_path}" already exists') # send file with exist check and hash check def send_file_to_storage(self, storage, flipper_file_path, local_file_path, force): if not storage.exist_file(flipper_file_path): self.logger.debug( - f'"{flipper_file_path}" not exist, sending "{local_file_path}"' + f'"{flipper_file_path}" does not exist, sending "{local_file_path}"' ) self.logger.info(f'Sending "{local_file_path}" to "{flipper_file_path}"') if not storage.send_file(local_file_path, flipper_file_path): self.logger.error(f"Error: {storage.last_error}") elif force: self.logger.debug( - f'"{flipper_file_path}" exist, but will be overwritten by "{local_file_path}"' + f'"{flipper_file_path}" exists, but will be overwritten by "{local_file_path}"' ) self.logger.info(f'Sending "{local_file_path}" to "{flipper_file_path}"') if not storage.send_file(local_file_path, flipper_file_path): self.logger.error(f"Error: {storage.last_error}") else: self.logger.debug( - f'"{flipper_file_path}" exist, compare hash with "{local_file_path}"' + f'"{flipper_file_path}" exists, compare hash with "{local_file_path}"' ) hash_local = storage.hash_local(local_file_path) hash_flipper = storage.hash_flipper(flipper_file_path) @@ -229,11 +237,11 @@ class Main: if hash_local == hash_flipper: self.logger.debug( - f'"{flipper_file_path}" are equal to "{local_file_path}"' + f'"{flipper_file_path}" is equal to "{local_file_path}"' ) else: self.logger.debug( - f'"{flipper_file_path}" are not equal to "{local_file_path}"' + f'"{flipper_file_path}" is NOT equal to "{local_file_path}"' ) self.logger.info( f'Sending "{local_file_path}" to "{flipper_file_path}"' @@ -242,7 +250,7 @@ class Main: self.logger.error(f"Error: {storage.last_error}") def read(self): - storage = FlipperStorage(self.args.port) + storage = FlipperStorage(self.args.port, self.args.baud) storage.start() self.logger.debug(f'Reading "{self.args.flipper_path}"') data = storage.read_file(self.args.flipper_path) diff --git a/site_scons/site_tools/fbt_dist.py b/site_scons/site_tools/fbt_dist.py index 8fad2156..8bfb4068 100644 --- a/site_scons/site_tools/fbt_dist.py +++ b/site_scons/site_tools/fbt_dist.py @@ -1,6 +1,7 @@ from SCons.Builder import Builder from SCons.Action import Action from SCons.Script import Mkdir +from SCons.Defaults import Touch def get_variant_dirname(env, project=None): @@ -47,6 +48,7 @@ def AddFwProject(env, base_env, fw_type, fw_env_key): project_env["FW_ARTIFACTS"], ], ) + env.Replace(DIST_DIR=get_variant_dirname(env)) return project_env @@ -80,6 +82,14 @@ def generate(env): '@${PYTHON3} ${ROOT_DIR.abspath}/scripts/sconsdist.py copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}" ${DIST_EXTRA}', ), ), + "UsbInstall": Builder( + action=[ + Action( + "${PYTHON3} ${ROOT_DIR.abspath}/scripts/selfupdate.py install dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}/update.fuf" + ), + Touch("${TARGET}"), + ] + ), "CoproBuilder": Builder( action=Action( [