From 26b2d07dd623dbc781bd712e481d1fd375ddc1c3 Mon Sep 17 00:00:00 2001 From: Vlad Roskov Date: Sat, 18 Dec 2021 14:11:18 +0300 Subject: [PATCH 01/14] Round up the charge % when drawing battery icon (#912) Causes anxious urge to recharge otherwise --- applications/power/power_service/power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/power/power_service/power.c b/applications/power/power_service/power.c index a1bdc854..61a35b6a 100644 --- a/applications/power/power_service/power.c +++ b/applications/power/power_service/power.c @@ -17,7 +17,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { furi_assert(context); Power* power = context; canvas_draw_icon(canvas, 0, 0, &I_Battery_26x8); - canvas_draw_box(canvas, 2, 2, power->info.charge / 5, 4); + canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4); } static ViewPort* power_battery_view_port_alloc(Power* power) { From 439fb9c18dde63e3b4420e618978226ab50e75ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 21 Dec 2021 15:16:25 +0300 Subject: [PATCH 02/14] [FL-1910, FL-2146] Update to new FreeRTOS, fix CMSIS thread flags collision with stream buffer. New cube. (#917) * Libs: add FreeRTOS submodule. FuriHal: replace ST provided FreeRTOS with original one. FuriHal: for cmsis os hal and patch it for better compatibility with stream buffer. * Makefile: fix svd plugin on blackmagic * Lib: update STM32CubeWB package. Project: update project to match new cube package. * Lib: properly rebase and upload STM32CubeWB * BleGlue: switch ack logging level to trace --- .gitmodules | 3 + Makefile | 2 +- applications/debug_tools/usb_test.c | 2 +- applications/rpc/rpc.c | 5 +- applications/rpc/rpc.h | 3 +- .../subghz/views/subghz_test_carrier.c | 2 +- .../subghz/views/subghz_test_packet.c | 4 +- firmware/targets/f6/Inc/FreeRTOSConfig.h | 197 +- firmware/targets/f6/Src/freertos-openocd.c | 21 - firmware/targets/f6/ble-glue/ble_app.c | 1 - firmware/targets/f6/ble-glue/ble_glue.c | 1 - firmware/targets/f6/ble-glue/gap.c | 5 +- firmware/targets/f6/ble-glue/serial_service.c | 2 +- firmware/targets/f6/fatfs/ffconf.h | 1 - firmware/targets/f6/furi-hal/furi-hal-os.c | 4 +- firmware/targets/f6/furi-hal/furi-hal-task.c | 1 - firmware/targets/f6/target.mk | 23 +- firmware/targets/f7/Inc/FreeRTOSConfig.h | 197 +- firmware/targets/f7/Src/freertos-openocd.c | 21 - firmware/targets/f7/ble-glue/ble_app.c | 1 - firmware/targets/f7/ble-glue/ble_glue.c | 1 - firmware/targets/f7/ble-glue/gap.c | 5 +- firmware/targets/f7/ble-glue/serial_service.c | 2 +- firmware/targets/f7/fatfs/ffconf.h | 1 - firmware/targets/f7/furi-hal/furi-hal-os.c | 4 +- firmware/targets/f7/furi-hal/furi-hal-task.c | 1 - firmware/targets/f7/target.mk | 23 +- lib/FreeRTOS-Kernel | 1 + lib/FreeRTOS-glue/cmsis_os2.c | 2873 +++++++++++++++++ lib/FreeRTOS-glue/cmsis_os2.h | 756 +++++ lib/FreeRTOS-glue/freertos_mpool.h | 63 + lib/FreeRTOS-glue/freertos_os2.h | 336 ++ lib/FreeRTOS-glue/os_tick.h | 80 + lib/ST25RFAL002/platform.c | 2 +- lib/STM32CubeWB | 2 +- lib/lib.mk | 4 +- make/rules.mk | 3 +- scripts/flipper/copro.py | 10 +- scripts/ob.data | 4 +- 39 files changed, 4313 insertions(+), 354 deletions(-) delete mode 100644 firmware/targets/f6/Src/freertos-openocd.c delete mode 100644 firmware/targets/f7/Src/freertos-openocd.c create mode 160000 lib/FreeRTOS-Kernel create mode 100644 lib/FreeRTOS-glue/cmsis_os2.c create mode 100644 lib/FreeRTOS-glue/cmsis_os2.h create mode 100644 lib/FreeRTOS-glue/freertos_mpool.h create mode 100644 lib/FreeRTOS-glue/freertos_os2.h create mode 100644 lib/FreeRTOS-glue/os_tick.h diff --git a/.gitmodules b/.gitmodules index 27f32c67..a16101ad 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "lib/libusb_stm32"] path = lib/libusb_stm32 url = https://github.com/flipperdevices/libusb_stm32.git +[submodule "lib/FreeRTOS-Kernel"] + path = lib/FreeRTOS-Kernel + url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git diff --git a/Makefile b/Makefile index 05a3ae75..062f10a3 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ endif .PHONY: flash_radio flash_radio: - @$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080CA000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_full_fw.bin + @$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080C7000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_full_fw.bin @$(PROJECT_ROOT)/scripts/ob.py set .PHONY: flash_radio_fus diff --git a/applications/debug_tools/usb_test.c b/applications/debug_tools/usb_test.c index 1936fe21..cacd715a 100644 --- a/applications/debug_tools/usb_test.c +++ b/applications/debug_tools/usb_test.c @@ -1,10 +1,10 @@ #include #include + #include #include #include #include -#include typedef struct { Gui* gui; diff --git a/applications/rpc/rpc.c b/applications/rpc/rpc.c index 449ab015..bce934a5 100644 --- a/applications/rpc/rpc.c +++ b/applications/rpc/rpc.c @@ -1,13 +1,14 @@ #include "rpc_i.h" + #include #include #include + #include #include #include -#include -#include #include + #include #include diff --git a/applications/rpc/rpc.h b/applications/rpc/rpc.h index 61e315ba..2b53c9d5 100755 --- a/applications/rpc/rpc.h +++ b/applications/rpc/rpc.h @@ -1,8 +1,9 @@ #pragma once + #include #include #include -#include "cmsis_os.h" +#include #define RPC_BUFFER_SIZE (1024) #define RPC_MAX_MESSAGE_SIZE (1536) diff --git a/applications/subghz/views/subghz_test_carrier.c b/applications/subghz/views/subghz_test_carrier.c index e6e1ac30..a569db1f 100644 --- a/applications/subghz/views/subghz_test_carrier.c +++ b/applications/subghz/views/subghz_test_carrier.c @@ -8,7 +8,7 @@ struct SubghzTestCarrier { View* view; - osTimerId timer; + osTimerId_t timer; SubghzTestCarrierCallback callback; void* context; }; diff --git a/applications/subghz/views/subghz_test_packet.c b/applications/subghz/views/subghz_test_packet.c index 01c4bbff..155d4f07 100644 --- a/applications/subghz/views/subghz_test_packet.c +++ b/applications/subghz/views/subghz_test_packet.c @@ -12,7 +12,7 @@ struct SubghzTestPacket { View* view; - osTimerId timer; + osTimerId_t timer; SubGhzDecoderPrinceton* decoder; SubGhzEncoderPrinceton* encoder; @@ -262,4 +262,4 @@ void subghz_test_packet_free(SubghzTestPacket* instance) { View* subghz_test_packet_get_view(SubghzTestPacket* instance) { furi_assert(instance); return instance->view; -} \ No newline at end of file +} diff --git a/firmware/targets/f6/Inc/FreeRTOSConfig.h b/firmware/targets/f6/Inc/FreeRTOSConfig.h index 1ad20993..4a031f70 100644 --- a/firmware/targets/f6/Inc/FreeRTOSConfig.h +++ b/firmware/targets/f6/Inc/FreeRTOSConfig.h @@ -1,133 +1,89 @@ -/* USER CODE BEGIN Header */ -/* - * FreeRTOS Kernel V10.2.1 - * Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Portion Copyright (C) 2019 StMicroelectronics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * http://www.FreeRTOS.org - * http://aws.amazon.com/freertos - * - * 1 tab == 4 spaces! - */ -/* USER CODE END Header */ +#pragma once -#ifndef FREERTOS_CONFIG_H -#define FREERTOS_CONFIG_H - -/*----------------------------------------------------------- - * Application specific definitions. - * - * These definitions should be adjusted for your particular hardware and - * application requirements. - * - * These parameters and more are described within the 'configuration' section of the - * FreeRTOS API documentation available on the FreeRTOS.org web site. - * - * See http://www.freertos.org/a00110.html - *----------------------------------------------------------*/ - -/* USER CODE BEGIN Includes */ -/* Section where include file can be added */ -/* USER CODE END Includes */ - -/* Ensure definitions are only used by the compiler, and not by the assembler. */ #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) - #include - extern uint32_t SystemCoreClock; +#include +extern uint32_t SystemCoreClock; #endif + #ifndef CMSIS_device_header #define CMSIS_device_header "stm32wbxx.h" #endif /* CMSIS_device_header */ -#define configENABLE_FPU 1 -#define configENABLE_MPU 0 +#define configENABLE_FPU 1 +#define configENABLE_MPU 0 + +#define configUSE_PREEMPTION 1 +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ ( SystemCoreClock ) +#define configTICK_RATE_HZ ((TickType_t)1024) +#define configMAX_PRIORITIES ( 56 ) +#define configMINIMAL_STACK_SIZE ((uint16_t)128) -#define configUSE_PREEMPTION 1 -#define configSUPPORT_STATIC_ALLOCATION 0 -#define configSUPPORT_DYNAMIC_ALLOCATION 1 -#define configUSE_IDLE_HOOK 0 -#define configUSE_TICK_HOOK 0 -#define configCPU_CLOCK_HZ ( SystemCoreClock ) -#define configTICK_RATE_HZ ((TickType_t)1024) -#define configMAX_PRIORITIES ( 56 ) -#define configMINIMAL_STACK_SIZE ((uint16_t)128) /* Heap size determined automatically by linker */ // #define configTOTAL_HEAP_SIZE ((size_t)0) -#define configMAX_TASK_NAME_LEN ( 16 ) -#define configGENERATE_RUN_TIME_STATS 0 -#define configUSE_TRACE_FACILITY 1 -#define configUSE_16_BIT_TICKS 0 -#define configUSE_MUTEXES 1 -#define configQUEUE_REGISTRY_SIZE 8 -#define configCHECK_FOR_STACK_OVERFLOW 1 -#define configUSE_RECURSIVE_MUTEXES 1 -#define configUSE_COUNTING_SEMAPHORES 1 -#define configENABLE_BACKWARD_COMPATIBILITY 0 -#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 -#define configUSE_TICKLESS_IDLE 2 -#define configRECORD_STACK_HIGH_ADDRESS 1 -#define configUSE_NEWLIB_REENTRANT 0 -/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */ +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 2 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_NEWLIB_REENTRANT 0 + /* Defaults to size_t for backward compatibility, but can be changed if lengths will always be less than the number of bytes in a size_t. */ -#define configMESSAGE_BUFFER_LENGTH_TYPE size_t -#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 -#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 8 -/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */ +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 +#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 4 /* Co-routine definitions. */ -#define configUSE_CO_ROUTINES 0 -#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) +#define configUSE_CO_ROUTINES 0 /* Software timer definitions. */ -#define configUSE_TIMERS 1 -#define configTIMER_TASK_PRIORITY ( 2 ) -#define configTIMER_QUEUE_LENGTH 32 -#define configTIMER_TASK_STACK_DEPTH 256 -#define configTIMER_SERVICE_TASK_NAME "TimersSrv" +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( 2 ) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH 256 +#define configTIMER_SERVICE_TASK_NAME "TimersSrv" -#define configIDLE_TASK_NAME "(-_-)" +#define configIDLE_TASK_NAME "(-_-)" /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ -#define INCLUDE_eTaskGetState 1 -#define INCLUDE_uxTaskGetStackHighWaterMark 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskCleanUpResources 0 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_xQueueGetMutexHolder 1 -#define INCLUDE_xTaskGetCurrentTaskHandle 1 -#define INCLUDE_xTaskGetSchedulerState 1 -#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerPendFunctionCall 1 /* CMSIS-RTOS V2 flags */ -#define configUSE_OS2_THREAD_SUSPEND_RESUME 1 -#define configUSE_OS2_THREAD_ENUMERATE 1 -#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 -#define configUSE_OS2_THREAD_FLAGS 1 -#define configUSE_OS2_TIMER 1 -#define configUSE_OS2_MUTEX 1 +#define configUSE_OS2_THREAD_SUSPEND_RESUME 1 +#define configUSE_OS2_THREAD_ENUMERATE 1 +#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 +#define configUSE_OS2_THREAD_FLAGS 1 +#define configUSE_OS2_TIMER 1 +#define configUSE_OS2_MUTEX 1 + +/* CMSIS-RTOS */ +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 2 +#define CMSIS_TASK_NOTIFY_INDEX 1 /* * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used @@ -137,15 +93,15 @@ to exclude the API function. */ /* Cortex-M specific definitions. */ #ifdef __NVIC_PRIO_BITS - /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ - #define configPRIO_BITS __NVIC_PRIO_BITS + /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ + #define configPRIO_BITS __NVIC_PRIO_BITS #else - #define configPRIO_BITS 4 + #define configPRIO_BITS 4 #endif /* The lowest interrupt priority that can be used in a call to a "set priority" function. */ -#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 /* The highest interrupt priority that can be used by any interrupt service routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL @@ -155,29 +111,20 @@ PRIORITY THAN THIS! (higher priorities are lower numeric values. */ /* Interrupt priorities used by the kernel port layer itself. These are generic to all Cortex-M ports, and do not rely on any particular library functions. */ -#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) + /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ -#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) /* Normal assert() semantics without relying on the provision of an assert.h header file. */ -/* USER CODE BEGIN 1 */ -#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; );} -/* USER CODE END 1 */ +#define configASSERT( x ) if ((x) == 0) { taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; ); } /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS standard names. */ #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler -/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */ - #define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1 - -/* USER CODE BEGIN Defines */ -/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */ #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1 /* required only for Keil but does not hurt otherwise */ -/* USER CODE END Defines */ - -#endif /* FREERTOS_CONFIG_H */ diff --git a/firmware/targets/f6/Src/freertos-openocd.c b/firmware/targets/f6/Src/freertos-openocd.c deleted file mode 100644 index abde4411..00000000 --- a/firmware/targets/f6/Src/freertos-openocd.c +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer - * present in the kernel, so it has to be supplied by other means for - * OpenOCD's threads awareness. - * - * Add this file to your project, and, if you're using --gc-sections, - * ``--undefined=uxTopUsedPriority'' (or - * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final - * linking) to your LDFLAGS; same with all the other symbols you need. - */ - -#include "FreeRTOS.h" - -#ifdef __GNUC__ -#define USED __attribute__((used)) -#else -#define USED -#endif - -const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1; \ No newline at end of file diff --git a/firmware/targets/f6/ble-glue/ble_app.c b/firmware/targets/f6/ble-glue/ble_app.c index 3f09d1f0..3ceecbbc 100644 --- a/firmware/targets/f6/ble-glue/ble_app.c +++ b/firmware/targets/f6/ble-glue/ble_app.c @@ -3,7 +3,6 @@ #include "hci_tl.h" #include "ble.h" #include "shci.h" -#include "cmsis_os.h" #include "gap.h" #include diff --git a/firmware/targets/f6/ble-glue/ble_glue.c b/firmware/targets/f6/ble-glue/ble_glue.c index 007f3645..096bc614 100644 --- a/firmware/targets/f6/ble-glue/ble_glue.c +++ b/firmware/targets/f6/ble-glue/ble_glue.c @@ -5,7 +5,6 @@ #include "ble.h" #include "tl.h" #include "shci.h" -#include "cmsis_os.h" #include "shci_tl.h" #include "app_debug.h" #include diff --git a/firmware/targets/f6/ble-glue/gap.c b/firmware/targets/f6/ble-glue/gap.c index e2991fca..70d3bd4d 100644 --- a/firmware/targets/f6/ble-glue/gap.c +++ b/firmware/targets/f6/ble-glue/gap.c @@ -2,7 +2,6 @@ #include "ble.h" -#include "cmsis_os.h" #include #include @@ -28,7 +27,7 @@ typedef struct { osMutexId_t state_mutex; BleEventCallback on_event_cb; void* context; - osTimerId advertise_timer; + osTimerId_t advertise_timer; FuriThread* thread; osMessageQueueId_t command_queue; bool enable_adv; @@ -446,7 +445,7 @@ void gap_thread_stop() { static int32_t gap_app(void *context) { GapCommand command; while(1) { - osStatus status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever); + osStatus_t status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever); if(status != osOK) { FURI_LOG_E(TAG, "Message queue get error: %d", status); continue; diff --git a/firmware/targets/f6/ble-glue/serial_service.c b/firmware/targets/f6/ble-glue/serial_service.c index ab201546..ae887ceb 100644 --- a/firmware/targets/f6/ble-glue/serial_service.c +++ b/firmware/targets/f6/ble-glue/serial_service.c @@ -62,7 +62,7 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) { ret = SVCCTL_EvtAckFlowEnable; } } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { - FURI_LOG_D(TAG, "Ack received", blecore_evt->ecode); + FURI_LOG_T(TAG, "Ack received", blecore_evt->ecode); if(serial_svc->callback) { SerialServiceEvent event = { .event = SerialServiceEventTypeDataSent, diff --git a/firmware/targets/f6/fatfs/ffconf.h b/firmware/targets/f6/fatfs/ffconf.h index d32d49a4..354948d8 100644 --- a/firmware/targets/f6/fatfs/ffconf.h +++ b/firmware/targets/f6/fatfs/ffconf.h @@ -26,7 +26,6 @@ #include "main.h" #include "stm32wbxx_hal.h" -#include "cmsis_os.h" /* _FS_REENTRANT set to 1 and CMSIS API chosen */ /*-----------------------------------------------------------------------------/ / Function Configurations diff --git a/firmware/targets/f6/furi-hal/furi-hal-os.c b/firmware/targets/f6/furi-hal/furi-hal-os.c index aac1b10e..cd182136 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-os.c +++ b/firmware/targets/f6/furi-hal/furi-hal-os.c @@ -43,7 +43,7 @@ void furi_hal_os_init() { LL_GPIO_SetPinMode(LED_TICK_PORT, LED_TICK_PIN, LL_GPIO_MODE_OUTPUT); LL_GPIO_SetPinMode(LED_SECOND_PORT, LED_SECOND_PIN, LL_GPIO_MODE_OUTPUT); osTimerId_t second_timer = osTimerNew(furi_hal_os_timer_callback, osTimerPeriodic, NULL, NULL); - osTimerStart(second_timer, 1024); + osTimerStart(second_timer, FURI_HAL_OS_TICK_PER_SECOND); #endif FURI_LOG_I(TAG, "Init OK"); @@ -139,7 +139,7 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) { __enable_irq(); } -void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) { +void vApplicationStackOverflowHook(TaskHandle_t xTask, char * pcTaskName) { asm("bkpt 1"); while(1) {}; } diff --git a/firmware/targets/f6/furi-hal/furi-hal-task.c b/firmware/targets/f6/furi-hal/furi-hal-task.c index aca197a4..433070d2 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-task.c +++ b/firmware/targets/f6/furi-hal/furi-hal-task.c @@ -1,4 +1,3 @@ -#include "cmsis_os.h" #include "furi-hal-task.h" //-----------------------------cmsis_os2.c------------------------------- diff --git a/firmware/targets/f6/target.mk b/firmware/targets/f6/target.mk index e642e2aa..3b9ada6c 100644 --- a/firmware/targets/f6/target.mk +++ b/firmware/targets/f6/target.mk @@ -75,18 +75,19 @@ C_SOURCES += \ # FreeRTOS CFLAGS += \ - -I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/include \ - -I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \ - -I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F + -I$(LIB_DIR)/FreeRTOS-Kernel/include \ + -I$(LIB_DIR)/FreeRTOS-Kernel/portable/GCC/ARM_CM4F \ + -I$(LIB_DIR)/FreeRTOS-glue/ + C_SOURCES += \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/list.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/queue.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/timers.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c + $(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 += \ diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/Inc/FreeRTOSConfig.h index 1ad20993..4a031f70 100644 --- a/firmware/targets/f7/Inc/FreeRTOSConfig.h +++ b/firmware/targets/f7/Inc/FreeRTOSConfig.h @@ -1,133 +1,89 @@ -/* USER CODE BEGIN Header */ -/* - * FreeRTOS Kernel V10.2.1 - * Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * Portion Copyright (C) 2019 StMicroelectronics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * http://www.FreeRTOS.org - * http://aws.amazon.com/freertos - * - * 1 tab == 4 spaces! - */ -/* USER CODE END Header */ +#pragma once -#ifndef FREERTOS_CONFIG_H -#define FREERTOS_CONFIG_H - -/*----------------------------------------------------------- - * Application specific definitions. - * - * These definitions should be adjusted for your particular hardware and - * application requirements. - * - * These parameters and more are described within the 'configuration' section of the - * FreeRTOS API documentation available on the FreeRTOS.org web site. - * - * See http://www.freertos.org/a00110.html - *----------------------------------------------------------*/ - -/* USER CODE BEGIN Includes */ -/* Section where include file can be added */ -/* USER CODE END Includes */ - -/* Ensure definitions are only used by the compiler, and not by the assembler. */ #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) - #include - extern uint32_t SystemCoreClock; +#include +extern uint32_t SystemCoreClock; #endif + #ifndef CMSIS_device_header #define CMSIS_device_header "stm32wbxx.h" #endif /* CMSIS_device_header */ -#define configENABLE_FPU 1 -#define configENABLE_MPU 0 +#define configENABLE_FPU 1 +#define configENABLE_MPU 0 + +#define configUSE_PREEMPTION 1 +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ ( SystemCoreClock ) +#define configTICK_RATE_HZ ((TickType_t)1024) +#define configMAX_PRIORITIES ( 56 ) +#define configMINIMAL_STACK_SIZE ((uint16_t)128) -#define configUSE_PREEMPTION 1 -#define configSUPPORT_STATIC_ALLOCATION 0 -#define configSUPPORT_DYNAMIC_ALLOCATION 1 -#define configUSE_IDLE_HOOK 0 -#define configUSE_TICK_HOOK 0 -#define configCPU_CLOCK_HZ ( SystemCoreClock ) -#define configTICK_RATE_HZ ((TickType_t)1024) -#define configMAX_PRIORITIES ( 56 ) -#define configMINIMAL_STACK_SIZE ((uint16_t)128) /* Heap size determined automatically by linker */ // #define configTOTAL_HEAP_SIZE ((size_t)0) -#define configMAX_TASK_NAME_LEN ( 16 ) -#define configGENERATE_RUN_TIME_STATS 0 -#define configUSE_TRACE_FACILITY 1 -#define configUSE_16_BIT_TICKS 0 -#define configUSE_MUTEXES 1 -#define configQUEUE_REGISTRY_SIZE 8 -#define configCHECK_FOR_STACK_OVERFLOW 1 -#define configUSE_RECURSIVE_MUTEXES 1 -#define configUSE_COUNTING_SEMAPHORES 1 -#define configENABLE_BACKWARD_COMPATIBILITY 0 -#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 -#define configUSE_TICKLESS_IDLE 2 -#define configRECORD_STACK_HIGH_ADDRESS 1 -#define configUSE_NEWLIB_REENTRANT 0 -/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */ +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 2 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_NEWLIB_REENTRANT 0 + /* Defaults to size_t for backward compatibility, but can be changed if lengths will always be less than the number of bytes in a size_t. */ -#define configMESSAGE_BUFFER_LENGTH_TYPE size_t -#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 -#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 8 -/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */ +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 +#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 4 /* Co-routine definitions. */ -#define configUSE_CO_ROUTINES 0 -#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) +#define configUSE_CO_ROUTINES 0 /* Software timer definitions. */ -#define configUSE_TIMERS 1 -#define configTIMER_TASK_PRIORITY ( 2 ) -#define configTIMER_QUEUE_LENGTH 32 -#define configTIMER_TASK_STACK_DEPTH 256 -#define configTIMER_SERVICE_TASK_NAME "TimersSrv" +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( 2 ) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH 256 +#define configTIMER_SERVICE_TASK_NAME "TimersSrv" -#define configIDLE_TASK_NAME "(-_-)" +#define configIDLE_TASK_NAME "(-_-)" /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ -#define INCLUDE_eTaskGetState 1 -#define INCLUDE_uxTaskGetStackHighWaterMark 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskCleanUpResources 0 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_xQueueGetMutexHolder 1 -#define INCLUDE_xTaskGetCurrentTaskHandle 1 -#define INCLUDE_xTaskGetSchedulerState 1 -#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerPendFunctionCall 1 /* CMSIS-RTOS V2 flags */ -#define configUSE_OS2_THREAD_SUSPEND_RESUME 1 -#define configUSE_OS2_THREAD_ENUMERATE 1 -#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 -#define configUSE_OS2_THREAD_FLAGS 1 -#define configUSE_OS2_TIMER 1 -#define configUSE_OS2_MUTEX 1 +#define configUSE_OS2_THREAD_SUSPEND_RESUME 1 +#define configUSE_OS2_THREAD_ENUMERATE 1 +#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 +#define configUSE_OS2_THREAD_FLAGS 1 +#define configUSE_OS2_TIMER 1 +#define configUSE_OS2_MUTEX 1 + +/* CMSIS-RTOS */ +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 2 +#define CMSIS_TASK_NOTIFY_INDEX 1 /* * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used @@ -137,15 +93,15 @@ to exclude the API function. */ /* Cortex-M specific definitions. */ #ifdef __NVIC_PRIO_BITS - /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ - #define configPRIO_BITS __NVIC_PRIO_BITS + /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ + #define configPRIO_BITS __NVIC_PRIO_BITS #else - #define configPRIO_BITS 4 + #define configPRIO_BITS 4 #endif /* The lowest interrupt priority that can be used in a call to a "set priority" function. */ -#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 /* The highest interrupt priority that can be used by any interrupt service routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL @@ -155,29 +111,20 @@ PRIORITY THAN THIS! (higher priorities are lower numeric values. */ /* Interrupt priorities used by the kernel port layer itself. These are generic to all Cortex-M ports, and do not rely on any particular library functions. */ -#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) + /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ -#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) /* Normal assert() semantics without relying on the provision of an assert.h header file. */ -/* USER CODE BEGIN 1 */ -#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; );} -/* USER CODE END 1 */ +#define configASSERT( x ) if ((x) == 0) { taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; ); } /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS standard names. */ #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler -/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */ - #define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1 - -/* USER CODE BEGIN Defines */ -/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */ #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1 /* required only for Keil but does not hurt otherwise */ -/* USER CODE END Defines */ - -#endif /* FREERTOS_CONFIG_H */ diff --git a/firmware/targets/f7/Src/freertos-openocd.c b/firmware/targets/f7/Src/freertos-openocd.c deleted file mode 100644 index abde4411..00000000 --- a/firmware/targets/f7/Src/freertos-openocd.c +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer - * present in the kernel, so it has to be supplied by other means for - * OpenOCD's threads awareness. - * - * Add this file to your project, and, if you're using --gc-sections, - * ``--undefined=uxTopUsedPriority'' (or - * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final - * linking) to your LDFLAGS; same with all the other symbols you need. - */ - -#include "FreeRTOS.h" - -#ifdef __GNUC__ -#define USED __attribute__((used)) -#else -#define USED -#endif - -const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1; \ No newline at end of file diff --git a/firmware/targets/f7/ble-glue/ble_app.c b/firmware/targets/f7/ble-glue/ble_app.c index 3f09d1f0..3ceecbbc 100644 --- a/firmware/targets/f7/ble-glue/ble_app.c +++ b/firmware/targets/f7/ble-glue/ble_app.c @@ -3,7 +3,6 @@ #include "hci_tl.h" #include "ble.h" #include "shci.h" -#include "cmsis_os.h" #include "gap.h" #include diff --git a/firmware/targets/f7/ble-glue/ble_glue.c b/firmware/targets/f7/ble-glue/ble_glue.c index 007f3645..096bc614 100644 --- a/firmware/targets/f7/ble-glue/ble_glue.c +++ b/firmware/targets/f7/ble-glue/ble_glue.c @@ -5,7 +5,6 @@ #include "ble.h" #include "tl.h" #include "shci.h" -#include "cmsis_os.h" #include "shci_tl.h" #include "app_debug.h" #include diff --git a/firmware/targets/f7/ble-glue/gap.c b/firmware/targets/f7/ble-glue/gap.c index e2991fca..70d3bd4d 100644 --- a/firmware/targets/f7/ble-glue/gap.c +++ b/firmware/targets/f7/ble-glue/gap.c @@ -2,7 +2,6 @@ #include "ble.h" -#include "cmsis_os.h" #include #include @@ -28,7 +27,7 @@ typedef struct { osMutexId_t state_mutex; BleEventCallback on_event_cb; void* context; - osTimerId advertise_timer; + osTimerId_t advertise_timer; FuriThread* thread; osMessageQueueId_t command_queue; bool enable_adv; @@ -446,7 +445,7 @@ void gap_thread_stop() { static int32_t gap_app(void *context) { GapCommand command; while(1) { - osStatus status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever); + osStatus_t status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever); if(status != osOK) { FURI_LOG_E(TAG, "Message queue get error: %d", status); continue; diff --git a/firmware/targets/f7/ble-glue/serial_service.c b/firmware/targets/f7/ble-glue/serial_service.c index ab201546..ae887ceb 100644 --- a/firmware/targets/f7/ble-glue/serial_service.c +++ b/firmware/targets/f7/ble-glue/serial_service.c @@ -62,7 +62,7 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) { ret = SVCCTL_EvtAckFlowEnable; } } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { - FURI_LOG_D(TAG, "Ack received", blecore_evt->ecode); + FURI_LOG_T(TAG, "Ack received", blecore_evt->ecode); if(serial_svc->callback) { SerialServiceEvent event = { .event = SerialServiceEventTypeDataSent, diff --git a/firmware/targets/f7/fatfs/ffconf.h b/firmware/targets/f7/fatfs/ffconf.h index d32d49a4..354948d8 100644 --- a/firmware/targets/f7/fatfs/ffconf.h +++ b/firmware/targets/f7/fatfs/ffconf.h @@ -26,7 +26,6 @@ #include "main.h" #include "stm32wbxx_hal.h" -#include "cmsis_os.h" /* _FS_REENTRANT set to 1 and CMSIS API chosen */ /*-----------------------------------------------------------------------------/ / Function Configurations diff --git a/firmware/targets/f7/furi-hal/furi-hal-os.c b/firmware/targets/f7/furi-hal/furi-hal-os.c index aac1b10e..cd182136 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-os.c +++ b/firmware/targets/f7/furi-hal/furi-hal-os.c @@ -43,7 +43,7 @@ void furi_hal_os_init() { LL_GPIO_SetPinMode(LED_TICK_PORT, LED_TICK_PIN, LL_GPIO_MODE_OUTPUT); LL_GPIO_SetPinMode(LED_SECOND_PORT, LED_SECOND_PIN, LL_GPIO_MODE_OUTPUT); osTimerId_t second_timer = osTimerNew(furi_hal_os_timer_callback, osTimerPeriodic, NULL, NULL); - osTimerStart(second_timer, 1024); + osTimerStart(second_timer, FURI_HAL_OS_TICK_PER_SECOND); #endif FURI_LOG_I(TAG, "Init OK"); @@ -139,7 +139,7 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) { __enable_irq(); } -void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) { +void vApplicationStackOverflowHook(TaskHandle_t xTask, char * pcTaskName) { asm("bkpt 1"); while(1) {}; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-task.c b/firmware/targets/f7/furi-hal/furi-hal-task.c index aca197a4..433070d2 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-task.c +++ b/firmware/targets/f7/furi-hal/furi-hal-task.c @@ -1,4 +1,3 @@ -#include "cmsis_os.h" #include "furi-hal-task.h" //-----------------------------cmsis_os2.c------------------------------- diff --git a/firmware/targets/f7/target.mk b/firmware/targets/f7/target.mk index e642e2aa..3b9ada6c 100644 --- a/firmware/targets/f7/target.mk +++ b/firmware/targets/f7/target.mk @@ -75,18 +75,19 @@ C_SOURCES += \ # FreeRTOS CFLAGS += \ - -I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/include \ - -I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \ - -I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F + -I$(LIB_DIR)/FreeRTOS-Kernel/include \ + -I$(LIB_DIR)/FreeRTOS-Kernel/portable/GCC/ARM_CM4F \ + -I$(LIB_DIR)/FreeRTOS-glue/ + C_SOURCES += \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/list.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/queue.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/timers.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \ - $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c + $(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 += \ diff --git a/lib/FreeRTOS-Kernel b/lib/FreeRTOS-Kernel new file mode 160000 index 00000000..4c4089b1 --- /dev/null +++ b/lib/FreeRTOS-Kernel @@ -0,0 +1 @@ +Subproject commit 4c4089b1544b590ed3b72491a15365ec020c921f diff --git a/lib/FreeRTOS-glue/cmsis_os2.c b/lib/FreeRTOS-glue/cmsis_os2.c new file mode 100644 index 00000000..d1dcce86 --- /dev/null +++ b/lib/FreeRTOS-glue/cmsis_os2.c @@ -0,0 +1,2873 @@ +/* -------------------------------------------------------------------------- + * Copyright (c) 2013-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. + * + * Name: cmsis_os2.c + * Purpose: CMSIS RTOS2 wrapper for FreeRTOS + * + *---------------------------------------------------------------------------*/ + +#include + +#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 "freertos_mpool.h" // osMemoryPool definitions +#include "freertos_os2.h" // Configuration check and setup + +#include CMSIS_device_header + +#ifndef CMSIS_TASK_NOTIFY_INDEX +#define CMSIS_TASK_NOTIFY_INDEX 0 +#endif + +/*---------------------------------------------------------------------------*/ +#ifndef __ARM_ARCH_6M__ + #define __ARM_ARCH_6M__ 0 +#endif +#ifndef __ARM_ARCH_7M__ + #define __ARM_ARCH_7M__ 0 +#endif +#ifndef __ARM_ARCH_7EM__ + #define __ARM_ARCH_7EM__ 0 +#endif +#ifndef __ARM_ARCH_8M_MAIN__ + #define __ARM_ARCH_8M_MAIN__ 0 +#endif +#ifndef __ARM_ARCH_7A__ + #define __ARM_ARCH_7A__ 0 +#endif + +#if ((__ARM_ARCH_7M__ == 1U) || \ + (__ARM_ARCH_7EM__ == 1U) || \ + (__ARM_ARCH_8M_MAIN__ == 1U)) +#define IS_IRQ_MASKED() ((__get_PRIMASK() != 0U) || (__get_BASEPRI() != 0U)) +#elif (__ARM_ARCH_6M__ == 1U) +#define IS_IRQ_MASKED() (__get_PRIMASK() != 0U) +#elif (__ARM_ARCH_7A__ == 1U) +/* CPSR mask bits */ +#define CPSR_MASKBIT_I 0x80U + +#define IS_IRQ_MASKED() ((__get_CPSR() & CPSR_MASKBIT_I) != 0U) +#else +#define IS_IRQ_MASKED() (__get_PRIMASK() != 0U) +#endif + +#if (__ARM_ARCH_7A__ == 1U) +/* CPSR mode bitmasks */ +#define CPSR_MODE_USER 0x10U +#define CPSR_MODE_SYSTEM 0x1FU + +#define IS_IRQ_MODE() ((__get_mode() != CPSR_MODE_USER) && (__get_mode() != CPSR_MODE_SYSTEM)) +#else +#define IS_IRQ_MODE() (__get_IPSR() != 0U) +#endif + +/* 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) | \ + ((uint32_t)tskKERNEL_VERSION_MINOR * 10000UL) | \ + ((uint32_t)tskKERNEL_VERSION_BUILD * 1UL)) + +#define KERNEL_ID ("FreeRTOS " tskKERNEL_VERSION_NUMBER) + +/* Timer callback information structure definition */ +typedef struct { + osTimerFunc_t func; + void *arg; +} TimerCallback_t; + +/* Kernel initialization state */ +static osKernelState_t KernelState = osKernelInactive; + +/* + Heap region definition used by heap_5 variant + + Define configAPPLICATION_ALLOCATED_HEAP as nonzero value in FreeRTOSConfig.h if + heap regions are already defined and vPortDefineHeapRegions is called in application. + + Otherwise vPortDefineHeapRegions will be called by osKernelInitialize using + definition configHEAP_5_REGIONS as parameter. Overriding configHEAP_5_REGIONS + is possible by defining it globally or in FreeRTOSConfig.h. +*/ +#if defined(USE_FreeRTOS_HEAP_5) +#if (configAPPLICATION_ALLOCATED_HEAP == 0) + /* + FreeRTOS heap is not defined by the application. + Single region of size configTOTAL_HEAP_SIZE (defined in FreeRTOSConfig.h) + is provided by default. Define configHEAP_5_REGIONS to provide custom + HeapRegion_t array. + */ + #define HEAP_5_REGION_SETUP 1 + + #ifndef configHEAP_5_REGIONS + #define configHEAP_5_REGIONS xHeapRegions + + static uint8_t ucHeap[configTOTAL_HEAP_SIZE]; + + static HeapRegion_t xHeapRegions[] = { + { ucHeap, configTOTAL_HEAP_SIZE }, + { NULL, 0 } + }; + #else + /* Global definition is provided to override default heap array */ + extern HeapRegion_t configHEAP_5_REGIONS[]; + #endif +#else + /* + The application already defined the array used for the FreeRTOS heap and + called vPortDefineHeapRegions to initialize heap. + */ + #define HEAP_5_REGION_SETUP 0 +#endif /* configAPPLICATION_ALLOCATED_HEAP */ +#endif /* USE_FreeRTOS_HEAP_5 */ + +/* + Setup SVC to reset value. +*/ +__STATIC_INLINE void SVC_Setup (void) { +#if (__ARM_ARCH_7A__ == 0U) + /* Service Call interrupt might be configured before kernel start */ + /* and when its priority is lower or equal to BASEPRI, svc intruction */ + /* causes a Hard Fault. */ + NVIC_SetPriority (SVCall_IRQn, 0U); +#endif +} + +/* + Function macro used to retrieve semaphore count from ISR +*/ +#ifndef uxSemaphoreGetCountFromISR +#define uxSemaphoreGetCountFromISR( xSemaphore ) uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) ( xSemaphore ) ) +#endif + +/* + Determine if CPU executes from interrupt context or if interrupts are masked. +*/ +__STATIC_INLINE uint32_t IRQ_Context (void) { + uint32_t irq; + BaseType_t state; + + irq = 0U; + + if (IS_IRQ_MODE()) { + /* Called from interrupt context */ + irq = 1U; + } + else { + /* Get FreeRTOS scheduler state */ + state = xTaskGetSchedulerState(); + + if (state != taskSCHEDULER_NOT_STARTED) { + /* Scheduler was started */ + if (IS_IRQ_MASKED()) { + /* Interrupts are masked */ + irq = 1U; + } + } + } + + /* Return context, 0: thread context, 1: IRQ context */ + return (irq); +} + + +/* ==== Kernel Management Functions ==== */ + +/* + Initialize the RTOS Kernel. +*/ +osStatus_t osKernelInitialize (void) { + osStatus_t stat; + BaseType_t state; + + if (IRQ_Context() != 0U) { + stat = osErrorISR; + } + else { + state = xTaskGetSchedulerState(); + + /* Initialize if scheduler not started and not initialized before */ + if ((state == taskSCHEDULER_NOT_STARTED) && (KernelState == osKernelInactive)) { + #if defined(USE_TRACE_EVENT_RECORDER) + /* Initialize the trace macro debugging output channel */ + EvrFreeRTOSSetup(0U); + #endif + #if defined(USE_FreeRTOS_HEAP_5) && (HEAP_5_REGION_SETUP == 1) + /* Initialize the memory regions when using heap_5 variant */ + vPortDefineHeapRegions (configHEAP_5_REGIONS); + #endif + KernelState = osKernelReady; + stat = osOK; + } else { + stat = osError; + } + } + + /* Return execution status */ + return (stat); +} + +/* + Get RTOS Kernel Information. +*/ +osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size) { + + if (version != NULL) { + /* Version encoding is major.minor.rev: mmnnnrrrr dec */ + version->api = KERNEL_VERSION; + version->kernel = KERNEL_VERSION; + } + + if ((id_buf != NULL) && (id_size != 0U)) { + /* Buffer for retrieving identification string is provided */ + if (id_size > sizeof(KERNEL_ID)) { + id_size = sizeof(KERNEL_ID); + } + /* Copy kernel identification string into provided buffer */ + memcpy(id_buf, KERNEL_ID, id_size); + } + + /* Return execution status */ + return (osOK); +} + +/* + Get the current RTOS Kernel state. +*/ +osKernelState_t osKernelGetState (void) { + osKernelState_t state; + + switch (xTaskGetSchedulerState()) { + case taskSCHEDULER_RUNNING: + state = osKernelRunning; + break; + + case taskSCHEDULER_SUSPENDED: + state = osKernelLocked; + break; + + case taskSCHEDULER_NOT_STARTED: + default: + if (KernelState == osKernelReady) { + /* Ready, osKernelInitialize was already called */ + state = osKernelReady; + } else { + /* Not initialized */ + state = osKernelInactive; + } + break; + } + + /* Return current state */ + return (state); +} + +/* + Start the RTOS Kernel scheduler. +*/ +osStatus_t osKernelStart (void) { + osStatus_t stat; + BaseType_t state; + + if (IRQ_Context() != 0U) { + stat = osErrorISR; + } + else { + state = xTaskGetSchedulerState(); + + /* Start scheduler if initialized and not started before */ + if ((state == taskSCHEDULER_NOT_STARTED) && (KernelState == osKernelReady)) { + /* Ensure SVC priority is at the reset value */ + SVC_Setup(); + /* Change state to ensure correct API flow */ + KernelState = osKernelRunning; + /* Start the kernel scheduler */ + vTaskStartScheduler(); + stat = osOK; + } else { + stat = osError; + } + } + + /* Return execution status */ + return (stat); +} + +/* + Lock the RTOS Kernel scheduler. +*/ +int32_t osKernelLock (void) { + int32_t lock; + + if (IRQ_Context() != 0U) { + lock = (int32_t)osErrorISR; + } + else { + switch (xTaskGetSchedulerState()) { + case taskSCHEDULER_SUSPENDED: + lock = 1; + break; + + case taskSCHEDULER_RUNNING: + vTaskSuspendAll(); + lock = 0; + break; + + case taskSCHEDULER_NOT_STARTED: + default: + lock = (int32_t)osError; + break; + } + } + + /* Return previous lock state */ + return (lock); +} + +/* + Unlock the RTOS Kernel scheduler. +*/ +int32_t osKernelUnlock (void) { + int32_t lock; + + if (IRQ_Context() != 0U) { + lock = (int32_t)osErrorISR; + } + else { + switch (xTaskGetSchedulerState()) { + case taskSCHEDULER_SUSPENDED: + lock = 1; + + if (xTaskResumeAll() != pdTRUE) { + if (xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) { + lock = (int32_t)osError; + } + } + break; + + case taskSCHEDULER_RUNNING: + lock = 0; + break; + + case taskSCHEDULER_NOT_STARTED: + default: + lock = (int32_t)osError; + break; + } + } + + /* Return previous lock state */ + return (lock); +} + +/* + Restore the RTOS Kernel scheduler lock state. +*/ +int32_t osKernelRestoreLock (int32_t lock) { + + if (IRQ_Context() != 0U) { + lock = (int32_t)osErrorISR; + } + else { + switch (xTaskGetSchedulerState()) { + case taskSCHEDULER_SUSPENDED: + case taskSCHEDULER_RUNNING: + if (lock == 1) { + vTaskSuspendAll(); + } + else { + if (lock != 0) { + lock = (int32_t)osError; + } + else { + if (xTaskResumeAll() != pdTRUE) { + if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { + lock = (int32_t)osError; + } + } + } + } + break; + + case taskSCHEDULER_NOT_STARTED: + default: + lock = (int32_t)osError; + break; + } + } + + /* Return new lock state */ + return (lock); +} + +/* + Get the RTOS kernel tick count. +*/ +uint32_t osKernelGetTickCount (void) { + TickType_t ticks; + + if (IRQ_Context() != 0U) { + ticks = xTaskGetTickCountFromISR(); + } else { + ticks = xTaskGetTickCount(); + } + + /* Return kernel tick count */ + return (ticks); +} + +/* + Get the RTOS kernel tick frequency. +*/ +uint32_t osKernelGetTickFreq (void) { + /* Return frequency in hertz */ + return (configTICK_RATE_HZ); +} + +/* + Get the RTOS kernel system timer count. +*/ +uint32_t osKernelGetSysTimerCount (void) { + uint32_t irqmask = IS_IRQ_MASKED(); + TickType_t ticks; + uint32_t val; + + __disable_irq(); + + 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(); + + if (irqmask == 0U) { + __enable_irq(); + } + + /* Return system timer count */ + return (val); +} + +/* + Get the RTOS kernel system timer frequency. +*/ +uint32_t osKernelGetSysTimerFreq (void) { + /* Return frequency in hertz */ + 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 { + name = pcTaskGetName (hTask); + } + + /* 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 ==== */ + +/* + Wait for Timeout (Time Delay). +*/ +osStatus_t osDelay (uint32_t ticks) { + osStatus_t stat; + + if (IRQ_Context() != 0U) { + stat = osErrorISR; + } + else { + stat = osOK; + + if (ticks != 0U) { + vTaskDelay(ticks); + } + } + + /* Return execution status */ + return (stat); +} + +/* + Wait until specified time. +*/ +osStatus_t osDelayUntil (uint32_t ticks) { + TickType_t tcnt, delay; + osStatus_t stat; + + if (IRQ_Context() != 0U) { + stat = osErrorISR; + } + else { + stat = osOK; + tcnt = xTaskGetTickCount(); + + /* Determine remaining number of ticks to delay */ + delay = (TickType_t)ticks - tcnt; + + /* Check if target tick has not expired */ + if((delay != 0U) && (0 == (delay >> (8 * sizeof(TickType_t) - 1)))) { + if (xTaskDelayUntil (&tcnt, delay) == pdFALSE) { + /* Did not delay */ + stat = osError; + } + } + else + { + /* No delay or already expired */ + stat = osErrorParameter; + } + } + + /* Return execution status */ + return (stat); +} + + +/* ==== Timer Management Functions ==== */ + +#if (configUSE_OS2_TIMER == 1) + +static void TimerCallback (TimerHandle_t hTimer) { + TimerCallback_t *callb; + + /* Retrieve pointer to callback function and argument */ + callb = (TimerCallback_t *)pvTimerGetTimerID (hTimer); + + /* Remove dynamic allocation flag */ + callb = (TimerCallback_t *)((uint32_t)callb & ~1U); + + if (callb != NULL) { + callb->func (callb->arg); + } +} + +/* + Create and Initialize a timer. +*/ +osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) { + const char *name; + TimerHandle_t hTimer; + TimerCallback_t *callb; + UBaseType_t reload; + int32_t mem; + uint32_t callb_dyn; + + hTimer = NULL; + + if ((IRQ_Context() == 0U) && (func != NULL)) { + callb = NULL; + callb_dyn = 0U; + + #if (configSUPPORT_STATIC_ALLOCATION == 1) + /* Static memory allocation is available: check if memory for control block */ + /* is provided and if it also contains space for callback and its argument */ + if ((attr != NULL) && (attr->cb_mem != NULL)) { + if (attr->cb_size >= (sizeof(StaticTimer_t) + sizeof(TimerCallback_t))) { + callb = (TimerCallback_t *)((uint32_t)attr->cb_mem + sizeof(StaticTimer_t)); + } + } + #endif + + #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) + /* Dynamic memory allocation is available: if memory for callback and */ + /* its argument is not provided, allocate it from dynamic memory pool */ + if (callb == NULL) { + callb = (TimerCallback_t *)pvPortMalloc (sizeof(TimerCallback_t)); + + if (callb != NULL) { + /* Callback memory was allocated from dynamic pool, set flag */ + callb_dyn = 1U; + } + } + #endif + + if (callb != NULL) { + callb->func = func; + callb->arg = argument; + + if (type == osTimerOnce) { + reload = pdFALSE; + } else { + reload = pdTRUE; + } + + mem = -1; + name = NULL; + + if (attr != NULL) { + if (attr->name != NULL) { + name = attr->name; + } + + if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticTimer_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; + } + /* Store callback memory dynamic allocation flag */ + callb = (TimerCallback_t *)((uint32_t)callb | callb_dyn); + /* + TimerCallback function is always provided as a callback and is used to call application + specified function with its argument both stored in structure callb. + */ + if (mem == 1) { + #if (configSUPPORT_STATIC_ALLOCATION == 1) + hTimer = xTimerCreateStatic (name, 1, reload, callb, TimerCallback, (StaticTimer_t *)attr->cb_mem); + #endif + } + else { + if (mem == 0) { + #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) + hTimer = xTimerCreate (name, 1, reload, callb, TimerCallback); + #endif + } + } + + #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) + if ((hTimer == NULL) && (callb != NULL) && (callb_dyn == 1U)) { + /* Failed to create a timer, release allocated resources */ + callb = (TimerCallback_t *)((uint32_t)callb & ~1U); + + vPortFree (callb); + } + #endif + } + } + + /* Return timer ID */ + return ((osTimerId_t)hTimer); +} + +/* + Get name of a timer. +*/ +const char *osTimerGetName (osTimerId_t timer_id) { + TimerHandle_t hTimer = (TimerHandle_t)timer_id; + const char *p; + + if ((IRQ_Context() != 0U) || (hTimer == NULL)) { + p = NULL; + } else { + p = pcTimerGetName (hTimer); + } + + /* Return name as null-terminated string */ + return (p); +} + +/* + Start or restart a timer. +*/ +osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks) { + TimerHandle_t hTimer = (TimerHandle_t)timer_id; + osStatus_t stat; + + if (IRQ_Context() != 0U) { + stat = osErrorISR; + } + else if (hTimer == NULL) { + stat = osErrorParameter; + } + else { + if (xTimerChangePeriod (hTimer, ticks, 0) == pdPASS) { + stat = osOK; + } else { + stat = osErrorResource; + } + } + + /* Return execution status */ + return (stat); +} + +/* + Stop a timer. +*/ +osStatus_t osTimerStop (osTimerId_t timer_id) { + TimerHandle_t hTimer = (TimerHandle_t)timer_id; + osStatus_t stat; + + if (IRQ_Context() != 0U) { + stat = osErrorISR; + } + else if (hTimer == NULL) { + stat = osErrorParameter; + } + else { + if (xTimerIsTimerActive (hTimer) == pdFALSE) { + stat = osErrorResource; + } + else { + if (xTimerStop (hTimer, 0) == pdPASS) { + stat = osOK; + } else { + stat = osError; + } + } + } + + /* Return execution status */ + return (stat); +} + +/* + Check if a timer is running. +*/ +uint32_t osTimerIsRunning (osTimerId_t timer_id) { + TimerHandle_t hTimer = (TimerHandle_t)timer_id; + uint32_t running; + + if ((IRQ_Context() != 0U) || (hTimer == NULL)) { + running = 0U; + } else { + running = (uint32_t)xTimerIsTimerActive (hTimer); + } + + /* Return 0: not running, 1: running */ + return (running); +} + +/* + Delete a timer. +*/ +osStatus_t osTimerDelete (osTimerId_t timer_id) { + TimerHandle_t hTimer = (TimerHandle_t)timer_id; + osStatus_t stat; +#ifndef USE_FreeRTOS_HEAP_1 +#if (configSUPPORT_DYNAMIC_ALLOCATION == 1) + TimerCallback_t *callb; +#endif + + if (IRQ_Context() != 0U) { + stat = osErrorISR; + } + else if (hTimer == NULL) { + stat = osErrorParameter; + } + else { + #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) + callb = (TimerCallback_t *)pvTimerGetTimerID (hTimer); + #endif + + if (xTimerDelete (hTimer, 0) == pdPASS) { + #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) + if ((uint32_t)callb & 1U) { + /* Callback memory was allocated from dynamic pool, clear flag */ + callb = (TimerCallback_t *)((uint32_t)callb & ~1U); + + /* Return allocated memory to dynamic pool */ + vPortFree (callb); + } + #endif + stat = osOK; + } else { + stat = osErrorResource; + } + } +#else + stat = osError; +#endif + + /* Return execution status */ + return (stat); +} +#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 ==== */ + +/* + Create and Initialize a Message Queue object. + + Limitations: + - The memory for control block and and message data must be provided in the + osThreadAttr_t structure in order to allocate object statically. +*/ +osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) { + QueueHandle_t hQueue; + int32_t mem; + + hQueue = NULL; + + if ((IRQ_Context() == 0U) && (msg_count > 0U) && (msg_size > 0U)) { + mem = -1; + + if (attr != NULL) { + if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticQueue_t)) && + (attr->mq_mem != NULL) && (attr->mq_size >= (msg_count * msg_size))) { + /* The memory for control block and message data is provided, use static object */ + mem = 1; + } + else { + if ((attr->cb_mem == NULL) && (attr->cb_size == 0U) && + (attr->mq_mem == NULL) && (attr->mq_size == 0U)) { + /* Control block will be allocated from the dynamic pool */ + mem = 0; + } + } + } + else { + mem = 0; + } + + if (mem == 1) { + #if (configSUPPORT_STATIC_ALLOCATION == 1) + hQueue = xQueueCreateStatic (msg_count, msg_size, attr->mq_mem, attr->cb_mem); + #endif + } + else { + if (mem == 0) { + #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) + hQueue = xQueueCreate (msg_count, msg_size); + #endif + } + } + + #if (configQUEUE_REGISTRY_SIZE > 0) + if (hQueue != NULL) { + if ((attr != NULL) && (attr->name != NULL)) { + /* Only non-NULL name objects are added to the Queue Registry */ + vQueueAddToRegistry (hQueue, attr->name); + } + } + #endif + + } + + /* Return message queue ID */ + return ((osMessageQueueId_t)hQueue); +} + +/* + Put a Message into a Queue or timeout if Queue is full. + + Limitations: + - Message priority is ignored +*/ +osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) { + QueueHandle_t hQueue = (QueueHandle_t)mq_id; + osStatus_t stat; + BaseType_t yield; + + (void)msg_prio; /* Message priority is ignored */ + + stat = osOK; + + if (IRQ_Context() != 0U) { + if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) { + stat = osErrorParameter; + } + else { + yield = pdFALSE; + + if (xQueueSendToBackFromISR (hQueue, msg_ptr, &yield) != pdTRUE) { + stat = osErrorResource; + } else { + portYIELD_FROM_ISR (yield); + } + } + } + else { + if ((hQueue == NULL) || (msg_ptr == NULL)) { + stat = osErrorParameter; + } + else { + if (xQueueSendToBack (hQueue, msg_ptr, (TickType_t)timeout) != pdPASS) { + if (timeout != 0U) { + stat = osErrorTimeout; + } else { + stat = osErrorResource; + } + } + } + } + + /* Return execution status */ + return (stat); +} + +/* + Get a Message from a Queue or timeout if Queue is empty. + + Limitations: + - Message priority is ignored +*/ +osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) { + QueueHandle_t hQueue = (QueueHandle_t)mq_id; + osStatus_t stat; + BaseType_t yield; + + (void)msg_prio; /* Message priority is ignored */ + + stat = osOK; + + if (IRQ_Context() != 0U) { + if ((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) { + stat = osErrorParameter; + } + else { + yield = pdFALSE; + + if (xQueueReceiveFromISR (hQueue, msg_ptr, &yield) != pdPASS) { + stat = osErrorResource; + } else { + portYIELD_FROM_ISR (yield); + } + } + } + else { + if ((hQueue == NULL) || (msg_ptr == NULL)) { + stat = osErrorParameter; + } + else { + if (xQueueReceive (hQueue, msg_ptr, (TickType_t)timeout) != pdPASS) { + if (timeout != 0U) { + stat = osErrorTimeout; + } else { + stat = osErrorResource; + } + } + } + } + + /* Return execution status */ + return (stat); +} + +/* + Get maximum number of messages in a Message Queue. +*/ +uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id) { + StaticQueue_t *mq = (StaticQueue_t *)mq_id; + uint32_t capacity; + + if (mq == NULL) { + capacity = 0U; + } else { + /* capacity = pxQueue->uxLength */ + capacity = mq->uxDummy4[1]; + } + + /* Return maximum number of messages */ + return (capacity); +} + +/* + Get maximum message size in a Message Queue. +*/ +uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id) { + StaticQueue_t *mq = (StaticQueue_t *)mq_id; + uint32_t size; + + if (mq == NULL) { + size = 0U; + } else { + /* size = pxQueue->uxItemSize */ + size = mq->uxDummy4[2]; + } + + /* Return maximum message size */ + return (size); +} + +/* + Get number of queued messages in a Message Queue. +*/ +uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id) { + QueueHandle_t hQueue = (QueueHandle_t)mq_id; + UBaseType_t count; + + if (hQueue == NULL) { + count = 0U; + } + else if (IRQ_Context() != 0U) { + count = uxQueueMessagesWaitingFromISR (hQueue); + } + else { + count = uxQueueMessagesWaiting (hQueue); + } + + /* Return number of queued messages */ + return ((uint32_t)count); +} + +/* + Get number of available slots for messages in a Message Queue. +*/ +uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id) { + StaticQueue_t *mq = (StaticQueue_t *)mq_id; + uint32_t space; + uint32_t isrm; + + if (mq == NULL) { + space = 0U; + } + else if (IRQ_Context() != 0U) { + isrm = taskENTER_CRITICAL_FROM_ISR(); + + /* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */ + space = mq->uxDummy4[1] - mq->uxDummy4[0]; + + taskEXIT_CRITICAL_FROM_ISR(isrm); + } + else { + space = (uint32_t)uxQueueSpacesAvailable ((QueueHandle_t)mq); + } + + /* Return number of available slots */ + return (space); +} + +/* + Reset a Message Queue to initial empty state. +*/ +osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id) { + QueueHandle_t hQueue = (QueueHandle_t)mq_id; + osStatus_t stat; + + if (IRQ_Context() != 0U) { + stat = osErrorISR; + } + else if (hQueue == NULL) { + stat = osErrorParameter; + } + else { + stat = osOK; + (void)xQueueReset (hQueue); + } + + /* Return execution status */ + return (stat); +} + +/* + Delete a Message Queue object. +*/ +osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) { + QueueHandle_t hQueue = (QueueHandle_t)mq_id; + osStatus_t stat; + +#ifndef USE_FreeRTOS_HEAP_1 + if (IRQ_Context() != 0U) { + stat = osErrorISR; + } + else if (hQueue == NULL) { + stat = osErrorParameter; + } + else { + #if (configQUEUE_REGISTRY_SIZE > 0) + vQueueUnregisterQueue (hQueue); + #endif + + stat = osOK; + vQueueDelete (hQueue); + } +#else + stat = osError; +#endif + + /* Return execution status */ + 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); +extern void vApplicationDaemonTaskStartupHook (void); + +/** + Dummy implementation of the callback function vApplicationIdleHook(). +*/ +#if (configUSE_IDLE_HOOK == 1) +__WEAK void vApplicationIdleHook (void){} +#endif + +/** + Dummy implementation of the callback function vApplicationTickHook(). +*/ +#if (configUSE_TICK_HOOK == 1) + __WEAK void vApplicationTickHook (void){} +#endif + +/** + Dummy implementation of the callback function vApplicationMallocFailedHook(). +*/ +#if (configUSE_MALLOC_FAILED_HOOK == 1) +__WEAK void vApplicationMallocFailedHook (void) { + /* Assert when malloc failed hook is enabled but no application defined function exists */ + configASSERT(0); +} +#endif + +/** + Dummy implementation of the callback function vApplicationDaemonTaskStartupHook(). +*/ +#if (configUSE_DAEMON_TASK_STARTUP_HOOK == 1) +__WEAK void vApplicationDaemonTaskStartupHook (void){} +#endif + +/** + Dummy implementation of the callback function vApplicationStackOverflowHook(). +*/ +#if (configCHECK_FOR_STACK_OVERFLOW > 0) +__WEAK void vApplicationStackOverflowHook (TaskHandle_t xTask, char *pcTaskName) { + (void)xTask; + (void)pcTaskName; + + /* Assert when stack overflow is enabled but no application defined function exists */ + 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 new file mode 100644 index 00000000..76612e29 --- /dev/null +++ b/lib/FreeRTOS-glue/cmsis_os2.h @@ -0,0 +1,756 @@ +/* + * 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. + * + * ---------------------------------------------------------------------- + * + * $Date: 12. June 2020 + * $Revision: V2.1.3 + * + * Project: CMSIS-RTOS2 API + * Title: cmsis_os2.h header file + * + * Version 2.1.3 + * Additional functions allowed to be called from Interrupt Service Routines: + * - osThreadGetId + * Version 2.1.2 + * Additional functions allowed to be called from Interrupt Service Routines: + * - osKernelGetInfo, osKernelGetState + * Version 2.1.1 + * Additional functions allowed to be called from Interrupt Service Routines: + * - osKernelGetTickCount, osKernelGetTickFreq + * Changed Kernel Tick type to uint32_t: + * - updated: osKernelGetTickCount, osDelayUntil + * Version 2.1.0 + * Support for critical and uncritical sections (nesting safe): + * - updated: osKernelLock, osKernelUnlock + * - added: osKernelRestoreLock + * Updated Thread and Event Flags: + * - changed flags parameter and return type from int32_t to uint32_t + * 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) +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) +#define __NO_RETURN __attribute__((__noreturn__)) +#elif defined(__GNUC__) +#define __NO_RETURN __attribute__((__noreturn__)) +#elif defined(__ICCARM__) +#define __NO_RETURN __noreturn +#else +#define __NO_RETURN +#endif +#endif + +#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. + osKernelReady = 1, ///< Ready. + osKernelRunning = 2, ///< Running. + osKernelLocked = 3, ///< Locked. + osKernelSuspended = 4, ///< Suspended. + 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 + uint32_t attr_bits; ///< attribute bits + 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 + 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 *mq_mem; ///< 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. +/// \param[in] argument argument to the timer callback function. +/// \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. +/// \param[in] msg_prio message priority. +/// \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. +/// \param[out] msg_prio pointer to buffer for message priority or NULL. +/// \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 new file mode 100644 index 00000000..cea5017e --- /dev/null +++ b/lib/FreeRTOS-glue/freertos_mpool.h @@ -0,0 +1,63 @@ +/* -------------------------------------------------------------------------- + * 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 new file mode 100644 index 00000000..f67d2ae9 --- /dev/null +++ b/lib/FreeRTOS-glue/freertos_os2.h @@ -0,0 +1,336 @@ +/* -------------------------------------------------------------------------- + * Copyright (c) 2013-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. + * + * Name: freertos_os2.h + * Purpose: CMSIS RTOS2 wrapper for FreeRTOS + * + *---------------------------------------------------------------------------*/ + +#ifndef FREERTOS_OS2_H_ +#define FREERTOS_OS2_H_ + +#include +#include + +#include "FreeRTOS.h" // ARM.FreeRTOS::RTOS:Core + +#if defined(_RTE_) +#include "RTE_Components.h" // Component selection +#include CMSIS_device_header + +/* Configuration and component setup check */ +#if defined(RTE_Compiler_EventRecorder) + #if !defined(EVR_FREERTOS_DISABLE) + #define USE_TRACE_EVENT_RECORDER + /* + FreeRTOS provides functions and hooks to support execution tracing. This + functionality is only enabled if configUSE_TRACE_FACILITY == 1. + Set #define configUSE_TRACE_FACILITY 1 in FreeRTOSConfig.h to enable trace events. + */ + #if (configUSE_TRACE_FACILITY == 0) + #error "Definition configUSE_TRACE_FACILITY must equal 1 to enable FreeRTOS trace events." + #endif + #endif +#endif + +#if defined(RTE_RTOS_FreeRTOS_HEAP_1) + #define USE_FreeRTOS_HEAP_1 +#endif + +#if defined(RTE_RTOS_FreeRTOS_HEAP_5) + #define USE_FreeRTOS_HEAP_5 +#endif +#endif /* _RTE_ */ + +/* + CMSIS-RTOS2 FreeRTOS image size optimization definitions. + + Note: Definitions configUSE_OS2 can be used to optimize FreeRTOS image size when + certain functionality is not required when using CMSIS-RTOS2 API. + In general optimization decisions are left to the tool chain but in cases + when coding style prevents it to optimize the code following optional + definitions can be used. +*/ + +/* + Option to exclude CMSIS-RTOS2 functions osThreadSuspend and osThreadResume from + the application image. +*/ +#ifndef configUSE_OS2_THREAD_SUSPEND_RESUME +#define configUSE_OS2_THREAD_SUSPEND_RESUME 1 +#endif + +/* + Option to exclude CMSIS-RTOS2 function osThreadEnumerate from the application image. +*/ +#ifndef configUSE_OS2_THREAD_ENUMERATE +#define configUSE_OS2_THREAD_ENUMERATE 1 +#endif + +/* + Option to disable CMSIS-RTOS2 function osEventFlagsSet and osEventFlagsClear + operation from ISR. +*/ +#ifndef configUSE_OS2_EVENTFLAGS_FROM_ISR +#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 +#endif + +/* + Option to exclude CMSIS-RTOS2 Thread Flags API functions from the application image. +*/ +#ifndef configUSE_OS2_THREAD_FLAGS +#define configUSE_OS2_THREAD_FLAGS configUSE_TASK_NOTIFICATIONS +#endif + +/* + Option to exclude CMSIS-RTOS2 Timer API functions from the application image. +*/ +#ifndef configUSE_OS2_TIMER +#define configUSE_OS2_TIMER configUSE_TIMERS +#endif + +/* + Option to exclude CMSIS-RTOS2 Mutex API functions from the application image. +*/ +#ifndef configUSE_OS2_MUTEX +#define configUSE_OS2_MUTEX configUSE_MUTEXES +#endif + + +/* + CMSIS-RTOS2 FreeRTOS configuration check (FreeRTOSConfig.h). + + Note: CMSIS-RTOS API requires functions included by using following definitions. + In case if certain API function is not used compiler will optimize it away. +*/ +#if (INCLUDE_xSemaphoreGetMutexHolder == 0) + /* + CMSIS-RTOS2 function osMutexGetOwner uses FreeRTOS function xSemaphoreGetMutexHolder. In case if + osMutexGetOwner is not used in the application image, compiler will optimize it away. + Set #define INCLUDE_xSemaphoreGetMutexHolder 1 to fix this error. + */ + #error "Definition INCLUDE_xSemaphoreGetMutexHolder must equal 1 to implement Mutex Management API." +#endif +#if (INCLUDE_vTaskDelay == 0) + /* + CMSIS-RTOS2 function osDelay uses FreeRTOS function vTaskDelay. In case if + osDelay is not used in the application image, compiler will optimize it away. + Set #define INCLUDE_vTaskDelay 1 to fix this error. + */ + #error "Definition INCLUDE_vTaskDelay must equal 1 to implement Generic Wait Functions API." +#endif +#if (INCLUDE_xTaskDelayUntil == 0) + /* + CMSIS-RTOS2 function osDelayUntil uses FreeRTOS function xTaskDelayUntil. In case if + osDelayUntil is not used in the application image, compiler will optimize it away. + Set #define INCLUDE_xTaskDelayUntil 1 to fix this error. + */ + #error "Definition INCLUDE_xTaskDelayUntil must equal 1 to implement Generic Wait Functions API." +#endif +#if (INCLUDE_vTaskDelete == 0) + /* + CMSIS-RTOS2 function osThreadTerminate and osThreadExit uses FreeRTOS function + vTaskDelete. In case if they are not used in the application image, compiler + will optimize them away. + Set #define INCLUDE_vTaskDelete 1 to fix this error. + */ + #error "Definition INCLUDE_vTaskDelete must equal 1 to implement Thread Management API." +#endif +#if (INCLUDE_xTaskGetCurrentTaskHandle == 0) + /* + CMSIS-RTOS2 API uses FreeRTOS function xTaskGetCurrentTaskHandle to implement + functions osThreadGetId, osThreadFlagsClear and osThreadFlagsGet. 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. + */ + #error "Definition INCLUDE_xTaskGetCurrentTaskHandle must equal 1 to implement Thread Management API." +#endif +#if (INCLUDE_xTaskGetSchedulerState == 0) + /* + CMSIS-RTOS2 API uses FreeRTOS function xTaskGetSchedulerState to implement Kernel + tick handling and therefore it is vital that xTaskGetSchedulerState is included into + the application image. + Set #define INCLUDE_xTaskGetSchedulerState 1 to fix this error. + */ + #error "Definition INCLUDE_xTaskGetSchedulerState must equal 1 to implement Kernel Information and Control API." +#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 + optimize it away. + Set #define INCLUDE_uxTaskGetStackHighWaterMark 1 to fix this error. + */ + #error "Definition INCLUDE_uxTaskGetStackHighWaterMark must equal 1 to implement Thread Management API." +#endif +#if (INCLUDE_uxTaskPriorityGet == 0) + /* + CMSIS-RTOS2 function osThreadGetPriority uses FreeRTOS function uxTaskPriorityGet. In case if + osThreadGetPriority is not used in the application image, compiler will optimize it away. + Set #define INCLUDE_uxTaskPriorityGet 1 to fix this error. + */ + #error "Definition INCLUDE_uxTaskPriorityGet must equal 1 to implement Thread Management API." +#endif +#if (INCLUDE_vTaskPrioritySet == 0) + /* + CMSIS-RTOS2 function osThreadSetPriority uses FreeRTOS function vTaskPrioritySet. In case if + osThreadSetPriority is not used in the application image, compiler will optimize it away. + Set #define INCLUDE_vTaskPrioritySet 1 to fix this error. + */ + #error "Definition INCLUDE_vTaskPrioritySet must equal 1 to implement Thread Management API." +#endif +#if (INCLUDE_eTaskGetState == 0) + /* + CMSIS-RTOS2 API uses FreeRTOS function vTaskDelayUntil to implement functions osThreadGetState + and osThreadTerminate. In case if these functions are not used in the application image, + compiler will optimize them away. + Set #define INCLUDE_eTaskGetState 1 to fix this error. + */ + #error "Definition INCLUDE_eTaskGetState must equal 1 to implement Thread Management API." +#endif +#if (INCLUDE_vTaskSuspend == 0) + /* + CMSIS-RTOS2 API uses FreeRTOS functions vTaskSuspend and vTaskResume to implement + functions osThreadSuspend and osThreadResume. In case if these functions are not + used in the application image, compiler will optimize them away. + Set #define INCLUDE_vTaskSuspend 1 to fix this error. + + Alternatively, if the application does not use osThreadSuspend and + osThreadResume they can be excluded from the image code by setting: + #define configUSE_OS2_THREAD_SUSPEND_RESUME 0 (in FreeRTOSConfig.h) + */ + #if (configUSE_OS2_THREAD_SUSPEND_RESUME == 1) + #error "Definition INCLUDE_vTaskSuspend must equal 1 to implement Kernel Information and Control API." + #endif +#endif +#if (INCLUDE_xTimerPendFunctionCall == 0) + /* + CMSIS-RTOS2 function osEventFlagsSet and osEventFlagsClear, when called from + the ISR, call FreeRTOS functions xEventGroupSetBitsFromISR and + xEventGroupClearBitsFromISR which are only enabled if timers are operational and + xTimerPendFunctionCall in enabled. + Set #define INCLUDE_xTimerPendFunctionCall 1 and #define configUSE_TIMERS 1 + to fix this error. + + Alternatively, if the application does not use osEventFlagsSet and osEventFlagsClear + from the ISR their operation from ISR can be restricted by setting: + #define configUSE_OS2_EVENTFLAGS_FROM_ISR 0 (in FreeRTOSConfig.h) + */ + #if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 1) + #error "Definition INCLUDE_xTimerPendFunctionCall must equal 1 to implement Event Flags API." + #endif +#endif + +#if (configUSE_TIMERS == 0) + /* + CMSIS-RTOS2 Timer Management API functions use FreeRTOS timer functions to implement + timer management. In case if these functions are not used in the application image, + compiler will optimize them away. + Set #define configUSE_TIMERS 1 to fix this error. + + Alternatively, if the application does not use timer functions they can be + excluded from the image code by setting: + #define configUSE_OS2_TIMER 0 (in FreeRTOSConfig.h) + */ + #if (configUSE_OS2_TIMER == 1) + #error "Definition configUSE_TIMERS must equal 1 to implement Timer Management API." + #endif +#endif + +#if (configUSE_MUTEXES == 0) + /* + CMSIS-RTOS2 Mutex Management API functions use FreeRTOS mutex functions to implement + mutex management. In case if these functions are not used in the application image, + compiler will optimize them away. + Set #define configUSE_MUTEXES 1 to fix this error. + + Alternatively, if the application does not use mutex functions they can be + excluded from the image code by setting: + #define configUSE_OS2_MUTEX 0 (in FreeRTOSConfig.h) + */ + #if (configUSE_OS2_MUTEX == 1) + #error "Definition configUSE_MUTEXES must equal 1 to implement Mutex Management API." + #endif +#endif + +#if (configUSE_COUNTING_SEMAPHORES == 0) + /* + CMSIS-RTOS2 Memory Pool functions use FreeRTOS function xSemaphoreCreateCounting + to implement memory pools. In case if these functions are not used in the application image, + compiler will optimize them away. + Set #define configUSE_COUNTING_SEMAPHORES 1 to fix this error. + */ + #error "Definition configUSE_COUNTING_SEMAPHORES must equal 1 to implement Memory Pool API." +#endif +#if (configUSE_TASK_NOTIFICATIONS == 0) + /* + CMSIS-RTOS2 Thread Flags API functions use FreeRTOS Task Notification functions to implement + thread flag management. In case if these functions are not used in the application image, + compiler will optimize them away. + Set #define configUSE_TASK_NOTIFICATIONS 1 to fix this error. + + Alternatively, if the application does not use thread flags functions they can be + excluded from the image code by setting: + #define configUSE_OS2_THREAD_FLAGS 0 (in FreeRTOSConfig.h) + */ + #if (configUSE_OS2_THREAD_FLAGS == 1) + #error "Definition configUSE_TASK_NOTIFICATIONS must equal 1 to implement Thread Flags API." + #endif +#endif + +#if (configUSE_TRACE_FACILITY == 0) + /* + CMSIS-RTOS2 function osThreadEnumerate 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 + 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." + #endif +#endif + +#if (configUSE_16_BIT_TICKS == 1) + /* + CMSIS-RTOS2 wrapper for FreeRTOS relies on 32-bit tick timer which is also optimal on + a 32-bit CPU architectures. + Set #define configUSE_16_BIT_TICKS 0 to fix this error. + */ + #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 new file mode 100644 index 00000000..3cfd8954 --- /dev/null +++ b/lib/FreeRTOS-glue/os_tick.h @@ -0,0 +1,80 @@ +/**************************************************************************//** + * @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 5e9dd5d2..a91acf9e 100644 --- a/lib/ST25RFAL002/platform.c +++ b/lib/ST25RFAL002/platform.c @@ -39,7 +39,7 @@ void platformSetIrqCallback(PlatformIrqCallback callback) { platform_irq_callback = callback; platform_irq_thread_attr.name = "RfalIrqWorker"; platform_irq_thread_attr.stack_size = 1024; - platform_irq_thread_attr.priority = osPriorityISR; + platform_irq_thread_attr.priority = osPriorityRealtime; platform_irq_thread_id = osThreadNew(platformIrqWorker, NULL, &platform_irq_thread_attr); hal_gpio_add_int_callback(&pin, nfc_isr, NULL); // Disable interrupt callback as the pin is shared between 2 apps diff --git a/lib/STM32CubeWB b/lib/STM32CubeWB index 9c78e7f2..528461f8 160000 --- a/lib/STM32CubeWB +++ b/lib/STM32CubeWB @@ -1 +1 @@ -Subproject commit 9c78e7f25506db18c35c6be51ab5aa14c7e0a622 +Subproject commit 528461f8276f06783d46461bfb31d77aa8bac419 diff --git a/lib/lib.mk b/lib/lib.mk index 34f43bd4..98ae0d5f 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -88,7 +88,7 @@ C_SOURCES += $(wildcard $(LIB_DIR)/drivers/*.c) CFLAGS += -I$(LIB_DIR)/file_reader CPP_SOURCES += $(wildcard $(LIB_DIR)/file_reader/*.cpp) -#irda lib +# IR lib CFLAGS += -I$(LIB_DIR)/irda/encoder_decoder CFLAGS += -I$(LIB_DIR)/irda/worker C_SOURCES += $(wildcard $(LIB_DIR)/irda/encoder_decoder/*.c) @@ -123,4 +123,4 @@ C_SOURCES += $(wildcard $(LIB_DIR)/heatshrink/*.c) # Toolbox CFLAGS += -I$(LIB_DIR)/flipper_file -C_SOURCES += $(wildcard $(LIB_DIR)/flipper_file/*.c) \ No newline at end of file +C_SOURCES += $(wildcard $(LIB_DIR)/flipper_file/*.c) diff --git a/make/rules.mk b/make/rules.mk index a212f09c..abb265d4 100644 --- a/make/rules.mk +++ b/make/rules.mk @@ -108,7 +108,8 @@ blackmagic: -ex 'monitor swdp_scan' \ -ex 'monitor debug_bmp enable' \ -ex 'attach 1' \ - -ex "set confirm off" \ + -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)" \ diff --git a/scripts/flipper/copro.py b/scripts/flipper/copro.py index f5198e44..104610e9 100644 --- a/scripts/flipper/copro.py +++ b/scripts/flipper/copro.py @@ -16,10 +16,10 @@ MANIFEST_TEMPLATE = { "version": { "type": 1, "major": 1, - "minor": 12, - "sub": 1, + "minor": 13, + "sub": 0, "branch": 0, - "release": 1, + "release": 5, }, "files": [], }, @@ -51,7 +51,7 @@ class Copro: if not cube_version or not cube_version.startswith("FW.WB"): raise Exception(f"Incorrect Cube package or version info") cube_version = cube_version.replace("FW.WB.", "", 1) - if cube_version != "1.12.1": + if cube_version != "1.13.1": raise Exception(f"Unknonwn cube version") self.version = cube_version @@ -89,7 +89,7 @@ class Copro: self.addFile( manifest["copro"]["radio"]["files"], "stm32wb5x_BLE_Stack_full_fw.bin", - address="0x080CA000", + address="0x080C7000", ) # Save manifest to json.dump(manifest, open(manifest_file, "w")) diff --git a/scripts/ob.data b/scripts/ob.data index ebb716d5..423be57e 100644 --- a/scripts/ob.data +++ b/scripts/ob.data @@ -14,7 +14,7 @@ IWDGSTOP:0x1:rw IWDGSW:0x1:rw IPCCDBA:0x0:rw ESE:0x1:r -SFSA:0xCA:r +SFSA:0xC7:r FSD:0x0:r DDS:0x1:r C2OPT:0x1:r @@ -22,7 +22,7 @@ NBRSD:0x0:r SNBRSA:0xF:r BRSD:0x0:r SBRSA:0xA:r -SBRV:0x32800:r +SBRV:0x31C00:r PCROP1A_STRT:0x1FF:r PCROP1A_END:0x0:r PCROP_RDP:0x1:rw From b0f582df9950c2a1a18c4f3b8a9a4fe4da4a3613 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 21 Dec 2021 15:33:17 +0300 Subject: [PATCH 03/14] [FL-1972], [FL-1920] Mifare Ultralight and NTAG separation (#918) * nfc: rename read mifare ultralight menu * nfc: separate ntag and mifare ultralight * nfc: save Mifare Ultralight type * nfc: add valid ack and nack messages * nfc: add compatible write command implementation * nfc: support f6 target --- applications/nfc/nfc_device.c | 19 ++- applications/nfc/nfc_types.h | 20 ++- applications/nfc/nfc_worker.c | 13 +- applications/nfc/scenes/nfc_scene_delete.c | 16 +-- .../nfc/scenes/nfc_scene_device_info.c | 16 +-- .../nfc/scenes/nfc_scene_read_card_success.c | 4 +- .../scenes/nfc_scene_read_mifare_ul_success.c | 5 +- .../nfc/scenes/nfc_scene_scripts_menu.c | 2 +- firmware/targets/f6/furi-hal/furi-hal-nfc.c | 39 +++++- firmware/targets/f7/furi-hal/furi-hal-nfc.c | 39 +++++- .../targets/furi-hal-include/furi-hal-nfc.h | 2 + lib/ST25RFAL002/include/rfal_nfc.h | 2 +- lib/ST25RFAL002/include/rfal_rf.h | 2 +- lib/ST25RFAL002/source/rfal_nfc.c | 7 +- lib/nfc_protocols/mifare_ultralight.c | 125 ++++++++++++------ lib/nfc_protocols/mifare_ultralight.h | 8 +- 16 files changed, 234 insertions(+), 85 deletions(-) mode change 100644 => 100755 applications/nfc/nfc_worker.c diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index 17a261f2..cfd0db2d 100755 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -1,4 +1,5 @@ #include "nfc_device.h" +#include "nfc_types.h" #include #include @@ -29,7 +30,7 @@ void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) { } else if(dev->format == NfcDeviceSaveFormatBankCard) { string_set_str(format_string, "Bank card"); } else if(dev->format == NfcDeviceSaveFormatMifareUl) { - string_set_str(format_string, "Mifare Ultralight"); + string_set_str(format_string, nfc_mf_ul_type(dev->dev_data.mf_ul_data.type, true)); } else { string_set_str(format_string, "Unknown"); } @@ -40,14 +41,20 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { dev->format = NfcDeviceSaveFormatUid; dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown; return true; - } else if(string_start_with_str_p(format_string, "Bank card")) { + } + if(string_start_with_str_p(format_string, "Bank card")) { dev->format = NfcDeviceSaveFormatBankCard; dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV; return true; - } else if(string_start_with_str_p(format_string, "Mifare Ultralight")) { - dev->format = NfcDeviceSaveFormatMifareUl; - dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; - return true; + } + // Check Mifare Ultralight types + for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) { + if(string_start_with_str_p(format_string, nfc_mf_ul_type(type, true))) { + dev->format = NfcDeviceSaveFormatMifareUl; + dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; + dev->dev_data.mf_ul_data.type = type; + return true; + } } return false; } diff --git a/applications/nfc/nfc_types.h b/applications/nfc/nfc_types.h index 6c37076a..12bcc093 100644 --- a/applications/nfc/nfc_types.h +++ b/applications/nfc/nfc_types.h @@ -54,12 +54,28 @@ static inline const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) { } } -static inline const char* nfc_get_protocol(NfcProtocol protocol) { +static inline const char* nfc_guess_protocol(NfcProtocol protocol) { if(protocol == NfcDeviceProtocolEMV) { return "EMV bank card"; } else if(protocol == NfcDeviceProtocolMifareUl) { - return "Mifare Ultralight"; + return "Mifare Ultral/NTAG"; } else { return "Unrecognized"; } } + +static inline const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { + if(type == MfUltralightTypeNTAG213) { + return "NTAG213"; + } else if(type == MfUltralightTypeNTAG215) { + return "NTAG215"; + } else if(type == MfUltralightTypeNTAG216) { + return "NTAG216"; + } else if(type == MfUltralightTypeUL11 && full_name) { + return "Mifare Ultralight 11"; + } else if(type == MfUltralightTypeUL21 && full_name) { + return "Mifare Ultralight 21"; + } else { + return "Mifare Ultralight"; + } +} diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c old mode 100644 new mode 100755 index 5f810cf6..ad1aa6e5 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -503,7 +503,7 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { FURI_LOG_D( TAG, "Mifare Ultralight Type: %d, Pages: %d", - mf_ul_read.type, + mf_ul_read.data.type, mf_ul_read.pages_to_read); FURI_LOG_D(TAG, "Reading signature ..."); tx_len = mf_ul_prepare_read_signature(tx_buff); @@ -629,8 +629,14 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { tx_len = mf_ul_prepare_emulation_response( rx_buff, *rx_len, tx_buff, &mf_ul_emulate); if(tx_len > 0) { - err = - furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); + if(tx_len < 8) { + err = furi_hal_nfc_raw_bitstream_exchange( + tx_buff, tx_len, &rx_buff, &rx_len, false); + *rx_len /= 8; + } else { + err = furi_hal_nfc_data_exchange( + tx_buff, tx_len / 8, &rx_buff, &rx_len, false); + } if(err == ERR_NONE) { continue; } else { @@ -638,7 +644,6 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { break; } } else { - FURI_LOG_D(TAG, "Not valid command: %02X", rx_buff[0]); furi_hal_nfc_deactivate(); break; } diff --git a/applications/nfc/scenes/nfc_scene_delete.c b/applications/nfc/scenes/nfc_scene_delete.c index 498e6ecd..d67511c4 100755 --- a/applications/nfc/scenes/nfc_scene_delete.c +++ b/applications/nfc/scenes/nfc_scene_delete.c @@ -44,15 +44,15 @@ void nfc_scene_delete_on_enter(void* context) { } widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); - if(data->protocol > NfcDeviceProtocolUnknown) { + const char* protocol_name = NULL; + if(data->protocol == NfcDeviceProtocolEMV) { + protocol_name = nfc_guess_protocol(data->protocol); + } else if(data->protocol == NfcDeviceProtocolMifareUl) { + protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); + } + if(protocol_name) { widget_add_string_element( - nfc->widget, - 10, - 32, - AlignLeft, - AlignTop, - FontSecondary, - nfc_get_protocol(data->protocol)); + nfc->widget, 10, 32, AlignLeft, AlignTop, FontSecondary, protocol_name); } // TODO change dinamically widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c index 1495c127..659ced9d 100755 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -68,15 +68,15 @@ void nfc_scene_device_info_on_enter(void* context) { } widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); - if(data->protocol > NfcDeviceProtocolUnknown) { + const char* protocol_name = NULL; + if(data->protocol == NfcDeviceProtocolEMV) { + protocol_name = nfc_guess_protocol(data->protocol); + } else if(data->protocol == NfcDeviceProtocolMifareUl) { + protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); + } + if(protocol_name) { widget_add_string_element( - nfc->widget, - 10, - 32, - AlignLeft, - AlignTop, - FontSecondary, - nfc_get_protocol(data->protocol)); + nfc->widget, 10, 32, AlignLeft, AlignTop, FontSecondary, protocol_name); } // TODO change dinamically widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/nfc/scenes/nfc_scene_read_card_success.c index c70bf1b2..d03dc831 100755 --- a/applications/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/nfc/scenes/nfc_scene_read_card_success.c @@ -27,7 +27,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { nfc, NFC_SCENE_READ_SUCCESS_SHIFT "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X", - nfc_get_protocol(data->protocol), + nfc_guess_protocol(data->protocol), data->atqa[0], data->atqa[1], data->sak, @@ -41,7 +41,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { NFC_SCENE_READ_SUCCESS_SHIFT "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X", - nfc_get_protocol(data->protocol), + nfc_guess_protocol(data->protocol), data->atqa[0], data->atqa[1], data->sak, diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c index 9c8dfc78..a11af2b5 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c @@ -28,11 +28,13 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { // Setup dialog view NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; + MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_right_button_text(dialog_ex, "More"); dialog_ex_set_center_button_text(dialog_ex, "Data"); - dialog_ex_set_header(dialog_ex, "Mifare Ultralight", 22, 8, AlignLeft, AlignCenter); + dialog_ex_set_header( + dialog_ex, nfc_mf_ul_type(mf_ul_data->type, true), 64, 8, AlignCenter, AlignCenter); dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); // Display UID nfc_text_store_set( @@ -54,7 +56,6 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback); // Setup TextBox view - MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; TextBox* text_box = nfc->text_box; text_box_set_context(text_box, nfc); text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback); diff --git a/applications/nfc/scenes/nfc_scene_scripts_menu.c b/applications/nfc/scenes/nfc_scene_scripts_menu.c index c82c4564..ffb856d3 100755 --- a/applications/nfc/scenes/nfc_scene_scripts_menu.c +++ b/applications/nfc/scenes/nfc_scene_scripts_menu.c @@ -23,7 +23,7 @@ void nfc_scene_scripts_menu_on_enter(void* context) { nfc); submenu_add_item( submenu, - "Read Mifare Ultralight", + "Read Mifare Ultral/Ntag", SubmenuIndexMifareUltralight, nfc_scene_scripts_menu_submenu_callback, nfc); diff --git a/firmware/targets/f6/furi-hal/furi-hal-nfc.c b/firmware/targets/f6/furi-hal/furi-hal-nfc.c index dbe5579c..ee1138d8 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-nfc.c +++ b/firmware/targets/f6/furi-hal/furi-hal-nfc.c @@ -131,7 +131,7 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s } bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { - ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0); + ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); return ret == ERR_NONE; } @@ -141,7 +141,42 @@ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t ReturnCode ret; rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; - ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0); + ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); + if(ret != ERR_NONE) { + return ret; + } + uint32_t start = DWT->CYCCNT; + while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { + rfalNfcWorker(); + state = rfalNfcGetState(); + ret = rfalNfcDataExchangeGetStatus(); + if(ret > ERR_SLEEP_REQ) { + return ret; + } + if(ret == ERR_BUSY) { + if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { + return ERR_TIMEOUT; + } + continue; + } else { + start = DWT->CYCCNT; + } + taskYIELD(); + } + if(deactivate) { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); + } + return ERR_NONE; +} + +ReturnCode furi_hal_nfc_raw_bitstream_exchange(uint8_t* tx_buff, uint16_t tx_bit_len, uint8_t** rx_buff, uint16_t** rx_bit_len, bool deactivate) { + furi_assert(rx_buff); + furi_assert(rx_bit_len); + + ReturnCode ret; + rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; + ret = rfalNfcDataExchangeStart(tx_buff, tx_bit_len, rx_buff, rx_bit_len, 0, RFAL_TXRX_FLAGS_RAW); if(ret != ERR_NONE) { return ret; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-nfc.c b/firmware/targets/f7/furi-hal/furi-hal-nfc.c index dbe5579c..ee1138d8 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-nfc.c +++ b/firmware/targets/f7/furi-hal/furi-hal-nfc.c @@ -131,7 +131,7 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s } bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { - ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0); + ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); return ret == ERR_NONE; } @@ -141,7 +141,42 @@ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t ReturnCode ret; rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; - ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0); + ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); + if(ret != ERR_NONE) { + return ret; + } + uint32_t start = DWT->CYCCNT; + while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { + rfalNfcWorker(); + state = rfalNfcGetState(); + ret = rfalNfcDataExchangeGetStatus(); + if(ret > ERR_SLEEP_REQ) { + return ret; + } + if(ret == ERR_BUSY) { + if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { + return ERR_TIMEOUT; + } + continue; + } else { + start = DWT->CYCCNT; + } + taskYIELD(); + } + if(deactivate) { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); + } + return ERR_NONE; +} + +ReturnCode furi_hal_nfc_raw_bitstream_exchange(uint8_t* tx_buff, uint16_t tx_bit_len, uint8_t** rx_buff, uint16_t** rx_bit_len, bool deactivate) { + furi_assert(rx_buff); + furi_assert(rx_bit_len); + + ReturnCode ret; + rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; + ret = rfalNfcDataExchangeStart(tx_buff, tx_bit_len, rx_buff, rx_bit_len, 0, RFAL_TXRX_FLAGS_RAW); if(ret != ERR_NONE) { return ret; } diff --git a/firmware/targets/furi-hal-include/furi-hal-nfc.h b/firmware/targets/furi-hal-include/furi-hal-nfc.h index c05b4df9..babc7b18 100644 --- a/firmware/targets/furi-hal-include/furi-hal-nfc.h +++ b/firmware/targets/furi-hal-include/furi-hal-nfc.h @@ -87,6 +87,8 @@ bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len); */ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t** rx_buff, uint16_t** rx_len, bool deactivate); +ReturnCode furi_hal_nfc_raw_bitstream_exchange(uint8_t* tx_buff, uint16_t tx_bit_len, uint8_t** rx_buff, uint16_t** rx_bit_len, bool deactivate); + /** NFC deactivate and start sleep */ void furi_hal_nfc_deactivate(); diff --git a/lib/ST25RFAL002/include/rfal_nfc.h b/lib/ST25RFAL002/include/rfal_nfc.h index 0500659b..6147148d 100755 --- a/lib/ST25RFAL002/include/rfal_nfc.h +++ b/lib/ST25RFAL002/include/rfal_nfc.h @@ -364,7 +364,7 @@ ReturnCode rfalNfcSelect( uint8_t devIdx ); * \return ERR_NONE : No error ***************************************************************************** */ -ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt ); +ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt, uint32_t tx_flag); /*! ***************************************************************************** diff --git a/lib/ST25RFAL002/include/rfal_rf.h b/lib/ST25RFAL002/include/rfal_rf.h index 96b662a5..f7f68c4f 100755 --- a/lib/ST25RFAL002/include/rfal_rf.h +++ b/lib/ST25RFAL002/include/rfal_rf.h @@ -110,7 +110,7 @@ /*! Default TxRx flags: Tx CRC automatic, Rx CRC removed, NFCIP1 mode off, AGC On, Tx Parity automatic, Rx Parity removed */ #define RFAL_TXRX_FLAGS_DEFAULT ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) - +#define RFAL_TXRX_FLAGS_RAW ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE| (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) #define RFAL_LM_MASK_NFCA ((uint32_t)1U<<(uint8_t)RFAL_MODE_LISTEN_NFCA) /*!< Bitmask for Listen Mode enabling NFCA */ diff --git a/lib/ST25RFAL002/source/rfal_nfc.c b/lib/ST25RFAL002/source/rfal_nfc.c index f1f3ddd3..4f66f410 100755 --- a/lib/ST25RFAL002/source/rfal_nfc.c +++ b/lib/ST25RFAL002/source/rfal_nfc.c @@ -550,7 +550,7 @@ void rfalNfcWorker( void ) /*******************************************************************************/ -ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt ) +ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt, uint32_t flags) { ReturnCode err; rfalTransceiveContext ctx; @@ -588,7 +588,10 @@ ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_ /*******************************************************************************/ case RFAL_NFC_INTERFACE_RF: - rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)txData, txDataLen, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen, RFAL_TXRX_FLAGS_DEFAULT, fwt ); + rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)txData, txDataLen, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen, flags, fwt ); + if(flags == RFAL_TXRX_FLAGS_RAW) { + ctx.txBufLen = txDataLen; + } *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf; *rvdLen = (uint16_t*)&gNfcDev.rxLen; err = rfalStartTransceive( &ctx ); diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc_protocols/mifare_ultralight.c index b3678864..b1138074 100644 --- a/lib/nfc_protocols/mifare_ultralight.c +++ b/lib/nfc_protocols/mifare_ultralight.c @@ -16,23 +16,23 @@ void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) MfUltralightVersion* version = (MfUltralightVersion*) buff; memcpy(&mf_ul_read->data.version, version, sizeof(MfUltralightVersion)); if(version->storage_size == 0x0B || version->storage_size == 0x00) { - mf_ul_read->type = MfUltralightTypeUL11; + mf_ul_read->data.type = MfUltralightTypeUL11; mf_ul_read->pages_to_read = 20; mf_ul_read->support_fast_read = true; } else if(version->storage_size == 0x0E) { - mf_ul_read->type = MfUltralightTypeUL21; + mf_ul_read->data.type = MfUltralightTypeUL21; mf_ul_read->pages_to_read = 41; mf_ul_read->support_fast_read = true; } else if(version->storage_size == 0x0F) { - mf_ul_read->type = MfUltralightTypeNTAG213; + mf_ul_read->data.type = MfUltralightTypeNTAG213; mf_ul_read->pages_to_read = 45; mf_ul_read->support_fast_read = false; } else if(version->storage_size == 0x11) { - mf_ul_read->type = MfUltralightTypeNTAG215; + mf_ul_read->data.type = MfUltralightTypeNTAG215; mf_ul_read->pages_to_read = 135; mf_ul_read->support_fast_read = false; } else if(version->storage_size == 0x13) { - mf_ul_read->type = MfUltralightTypeNTAG216; + mf_ul_read->data.type = MfUltralightTypeNTAG216; mf_ul_read->pages_to_read = 231; mf_ul_read->support_fast_read = false; } else { @@ -41,7 +41,7 @@ void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) } void mf_ul_set_default_version(MifareUlDevice* mf_ul_read) { - mf_ul_read->type = MfUltralightTypeUnknown; + mf_ul_read->data.type = MfUltralightTypeUnknown; mf_ul_read->pages_to_read = 16; mf_ul_read->support_fast_read = false; } @@ -148,26 +148,26 @@ void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) mf_ul_emulate->auth_data = NULL; mf_ul_emulate->data_changed = false; if(data->version.storage_size == 0) { - mf_ul_emulate->type = MfUltralightTypeUnknown; + mf_ul_emulate->data.type = MfUltralightTypeUnknown; mf_ul_emulate->support_fast_read = false; } else if(data->version.storage_size == 0x0B) { - mf_ul_emulate->type = MfUltralightTypeUL11; + mf_ul_emulate->data.type = MfUltralightTypeUL11; mf_ul_emulate->support_fast_read = true; } else if(data->version.storage_size == 0x0E) { - mf_ul_emulate->type = MfUltralightTypeUL21; + mf_ul_emulate->data.type = MfUltralightTypeUL21; mf_ul_emulate->support_fast_read = true; } else if(data->version.storage_size == 0x0F) { - mf_ul_emulate->type = MfUltralightTypeNTAG213; + mf_ul_emulate->data.type = MfUltralightTypeNTAG213; mf_ul_emulate->support_fast_read = true; } else if(data->version.storage_size == 0x11) { - mf_ul_emulate->type = MfUltralightTypeNTAG215; + mf_ul_emulate->data.type = MfUltralightTypeNTAG215; mf_ul_emulate->support_fast_read = true; } else if(data->version.storage_size == 0x13) { - mf_ul_emulate->type = MfUltralightTypeNTAG216; + mf_ul_emulate->data.type = MfUltralightTypeNTAG216; mf_ul_emulate->support_fast_read = true; } - if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { + if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { uint16_t pwd_page = (data->data_size / 4) - 2; mf_ul_emulate->auth_data = (MifareUlAuthData*)&data->data[pwd_page * 4]; } @@ -178,7 +178,7 @@ void mf_ul_protect_auth_data_on_read_command( uint8_t start_page, uint8_t end_page, MifareUlDevice* mf_ul_emulate) { - if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { + if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { uint8_t pwd_page = (mf_ul_emulate->data.data_size / 4) - 2; uint8_t pack_page = pwd_page + 1; if((start_page <= pwd_page) && (end_page >= pwd_page)) { @@ -193,27 +193,43 @@ void mf_ul_protect_auth_data_on_read_command( uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uint8_t* buff_tx, MifareUlDevice* mf_ul_emulate) { uint8_t cmd = buff_rx[0]; uint16_t page_num = mf_ul_emulate->data.data_size / 4; - uint16_t tx_len = 0; + uint16_t tx_bytes = 0; + uint16_t tx_bits = 0; + bool command_parsed = false; - if(cmd == MF_UL_GET_VERSION_CMD) { - if(mf_ul_emulate->type != MfUltralightTypeUnknown) { - tx_len = sizeof(mf_ul_emulate->data.version); - memcpy(buff_tx, &mf_ul_emulate->data.version, tx_len); + // Check composite commands + if(mf_ul_emulate->comp_write_cmd_started) { + // Compatibility write is the only one composit command + if(len_rx == 16) { + memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4); + mf_ul_emulate->data_changed = true; + // Send ACK message + buff_tx[0] = 0x0A; + tx_bits = 4; + command_parsed = true; + } + mf_ul_emulate->comp_write_cmd_started = false; + } else if(cmd == MF_UL_GET_VERSION_CMD) { + if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) { + tx_bytes = sizeof(mf_ul_emulate->data.version); + memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes); + command_parsed = true; } } else if(cmd == MF_UL_READ_CMD) { uint8_t start_page = buff_rx[1]; if(start_page < page_num) { - tx_len = 16; + tx_bytes = 16; if(start_page + 4 > page_num) { // Handle roll-over mechanism uint8_t end_pages_num = page_num - start_page; memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], end_pages_num * 4); memcpy(&buff_tx[end_pages_num * 4], mf_ul_emulate->data.data, (4 - end_pages_num) * 4); } else { - memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len); + memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); } mf_ul_protect_auth_data_on_read_command( buff_tx, start_page, (start_page + 4), mf_ul_emulate); + command_parsed = true; } } else if(cmd == MF_UL_FAST_READ_CMD) { if(mf_ul_emulate->support_fast_read) { @@ -221,14 +237,11 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin uint8_t end_page = buff_rx[2]; if((start_page < page_num) && (end_page < page_num) && (start_page < (end_page + 1))) { - tx_len = ((end_page + 1) - start_page) * 4; - memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len); + tx_bytes = ((end_page + 1) - start_page) * 4; + memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); mf_ul_protect_auth_data_on_read_command( buff_tx, start_page, end_page, mf_ul_emulate); - } else { - // TODO make 4-bit NAK - buff_tx[0] = 0x0; - tx_len = 1; + command_parsed = true; } } } else if(cmd == MF_UL_WRITE) { @@ -236,9 +249,20 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin if((write_page > 1) && (write_page < page_num - 2)) { memcpy(&mf_ul_emulate->data.data[write_page * 4], &buff_rx[2], 4); mf_ul_emulate->data_changed = true; - // TODO make 4-bit ACK + // ACK buff_tx[0] = 0x0A; - tx_len = 1; + tx_bits = 4; + command_parsed = true; + } + } else if(cmd == MF_UL_COMP_WRITE) { + uint8_t write_page = buff_rx[1]; + if((write_page > 1) && (write_page < page_num - 2)) { + mf_ul_emulate->comp_write_cmd_started = true; + mf_ul_emulate->comp_write_page_addr = write_page; + // ACK + buff_tx[0] = 0x0A; + tx_bits = 4; + command_parsed = true; } } else if(cmd == MF_UL_READ_CNT) { uint8_t cnt_num = buff_rx[1]; @@ -246,7 +270,8 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin buff_tx[0] = mf_ul_emulate->data.counter[cnt_num] >> 16; buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8; buff_tx[2] = mf_ul_emulate->data.counter[cnt_num]; - tx_len = 3; + tx_bytes = 3; + command_parsed = true; } } else if(cmd == MF_UL_INC_CNT) { uint8_t cnt_num = buff_rx[1]; @@ -254,38 +279,52 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin if((cnt_num < 3) && (mf_ul_emulate->data.counter[cnt_num] + inc < 0x00FFFFFF)) { mf_ul_emulate->data.counter[cnt_num] += inc; mf_ul_emulate->data_changed = true; - // TODO make 4-bit ACK + // ACK buff_tx[0] = 0x0A; - tx_len = 1; + tx_bits = 4; + command_parsed = true; } } else if(cmd == MF_UL_AUTH) { - if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { + if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { if(memcmp(&buff_rx[1], mf_ul_emulate->auth_data->pwd, 4) == 0) { buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0]; buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1]; - tx_len = 2; + tx_bytes = 2; + command_parsed = true; } else if(!mf_ul_emulate->auth_data->pack.value) { buff_tx[0] = 0x80; buff_tx[1] = 0x80; - tx_len = 2; - } else { - // TODO make 4-bit NAK - buff_tx[0] = 0x0; - tx_len = 1; + tx_bytes = 2; + command_parsed = true; } } } else if(cmd == MF_UL_READ_SIG) { // Check 2nd byte = 0x00 - RFU if(buff_rx[1] == 0x00) { - tx_len = sizeof(mf_ul_emulate->data.signature); - memcpy(buff_tx, mf_ul_emulate->data.signature, tx_len); + tx_bytes = sizeof(mf_ul_emulate->data.signature); + memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes); + command_parsed = true; } } else if(cmd == MF_UL_CHECK_TEARING) { uint8_t cnt_num = buff_rx[1]; if(cnt_num < 3) { buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num]; - tx_len = 1; + tx_bytes = 1; + command_parsed = true; } + } else if(cmd == MF_UL_HALT_START) { + tx_bits = 0; + command_parsed = true; } - return tx_len; + + if(!command_parsed) { + // Send NACK + buff_tx[0] = 0x00; + tx_bits = 4; + } + // Return tx buffer size in bits + if(tx_bytes) { + tx_bits = tx_bytes * 8; + } + return tx_bits; } diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc_protocols/mifare_ultralight.h index 386850c8..6b8ec6ee 100644 --- a/lib/nfc_protocols/mifare_ultralight.h +++ b/lib/nfc_protocols/mifare_ultralight.h @@ -8,6 +8,7 @@ #define MF_UL_TEARING_FLAG_DEFAULT (0xBD) +#define MF_UL_HALT_START (0x50) #define MF_UL_GET_VERSION_CMD (0x60) #define MF_UL_READ_CMD (0x30) #define MF_UL_FAST_READ_CMD (0x3A) @@ -28,6 +29,9 @@ typedef enum { MfUltralightTypeNTAG213, MfUltralightTypeNTAG215, MfUltralightTypeNTAG216, + + // Keep last for number of types calculation + MfUltralightTypeNum, } MfUltralightType; typedef struct { @@ -52,6 +56,7 @@ typedef struct { } MfUltralightManufacturerBlock; typedef struct { + MfUltralightType type; MfUltralightVersion version; uint8_t signature[32]; uint32_t counter[3]; @@ -69,13 +74,14 @@ typedef struct { } MifareUlAuthData; typedef struct { - MfUltralightType type; uint8_t pages_to_read; uint8_t pages_readed; bool support_fast_read; bool data_changed; MifareUlData data; MifareUlAuthData* auth_data; + bool comp_write_cmd_started; + uint8_t comp_write_page_addr; } MifareUlDevice; bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); From 51b823d1cab821b54bc8b256f267791e098b00e6 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Tue, 21 Dec 2021 15:49:57 +0300 Subject: [PATCH 04/14] [FL-2115][FL-2122] BadUSB demo scripts (#915) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BadUSB: support for dual-modifier key commands, demo script for windows * BadUSB: ALT-GUI command, demo script for macOS Co-authored-by: あく --- applications/bad_usb/bad_usb_script.c | 5 ++ assets/resources/badusb/demo_macos.txt | 82 ++++++++++++++++++++++++ assets/resources/badusb/demo_windows.txt | 79 +++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 assets/resources/badusb/demo_macos.txt create mode 100644 assets/resources/badusb/demo_windows.txt diff --git a/applications/bad_usb/bad_usb_script.c b/applications/bad_usb/bad_usb_script.c index 0ac42737..4b66e933 100644 --- a/applications/bad_usb/bad_usb_script.c +++ b/applications/bad_usb/bad_usb_script.c @@ -40,6 +40,11 @@ typedef struct { } DuckyKey; static const DuckyKey ducky_keys[] = { + {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, + {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, + {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, + {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, + {"CTRL", KEY_MOD_LEFT_CTRL}, {"CONTROL", KEY_MOD_LEFT_CTRL}, {"SHIFT", KEY_MOD_LEFT_SHIFT}, diff --git a/assets/resources/badusb/demo_macos.txt b/assets/resources/badusb/demo_macos.txt new file mode 100644 index 00000000..2e33c196 --- /dev/null +++ b/assets/resources/badusb/demo_macos.txt @@ -0,0 +1,82 @@ +REM This is BadUSB demo script for macOS + +REM Open terminal window +DELAY 1000 +GUI SPACE +DELAY 500 +STRING terminal +DELAY 500 +ENTER +DELAY 750 + +REM Copy-Paste previuos string +UP +CTRL c + +REM Bigger shell script example +STRING cat > /dev/null << EOF +ENTER + +STRING Hello World! +ENTER + +DEFAULT_DELAY 50 + +STRING = +REPEAT 59 +ENTER +ENTER + +STRING _.-------.._ -, +ENTER +HOME +STRING .-"```"--..,,_/ /`-, -, \ +ENTER +HOME +STRING .:" /:/ /'\ \ ,_..., `. | | +ENTER +HOME +STRING / ,----/:/ /`\ _\~`_-"` _; +ENTER +HOME +STRING ' / /`"""'\ \ \.~`_-' ,-"'/ +ENTER +HOME +STRING | | | 0 | | .-' ,/` / +ENTER +HOME +STRING | ,..\ \ ,.-"` ,/` / +ENTER +HOME +STRING ; : `/`""\` ,/--==,/-----, +ENTER +HOME +STRING | `-...| -.___-Z:_______J...---; +ENTER +HOME +STRING : ` _-' +ENTER +HOME +STRING _L_ _ ___ ___ ___ ___ ____--"` +ENTER +HOME +STRING | __|| | |_ _|| _ \| _ \| __|| _ \ +ENTER +HOME +STRING | _| | |__ | | | _/| _/| _| | / +ENTER +HOME +STRING |_| |____||___||_| |_| |___||_|_\ +ENTER +HOME +ENTER + +STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format +ENTER +STRING More information about script synax can be found here: +ENTER +STRING https://github.com/hak5darren/USB-Rubber-Ducky/wiki/Duckyscript +ENTER + +STRING EOF +ENTER diff --git a/assets/resources/badusb/demo_windows.txt b/assets/resources/badusb/demo_windows.txt new file mode 100644 index 00000000..6b69926f --- /dev/null +++ b/assets/resources/badusb/demo_windows.txt @@ -0,0 +1,79 @@ +REM This is BadUSB demo script for windows + +REM Open windows notepad +DELAY 1000 +GUI r +DELAY 500 +STRING notepad +DELAY 500 +ENTER +DELAY 750 + +STRING Hello World! +ENTER +DEFAULT_DELAY 50 + +REM Copy-Paste previuos string +UP +HOME +SHIFT DOWN +CTRL c +RIGHT +CTRL v +CTRL v + +STRING = +REPEAT 59 +ENTER +ENTER + +STRING _.-------.._ -, +ENTER +HOME +STRING .-"```"--..,,_/ /`-, -, \ +ENTER +HOME +STRING .:" /:/ /'\ \ ,_..., `. | | +ENTER +HOME +STRING / ,----/:/ /`\ _\~`_-"` _; +ENTER +HOME +STRING ' / /`"""'\ \ \.~`_-' ,-"'/ +ENTER +HOME +STRING | | | 0 | | .-' ,/` / +ENTER +HOME +STRING | ,..\ \ ,.-"` ,/` / +ENTER +HOME +STRING ; : `/`""\` ,/--==,/-----, +ENTER +HOME +STRING | `-...| -.___-Z:_______J...---; +ENTER +HOME +STRING : ` _-' +ENTER +HOME +STRING _L_ _ ___ ___ ___ ___ ____--"` +ENTER +HOME +STRING | __|| | |_ _|| _ \| _ \| __|| _ \ +ENTER +HOME +STRING | _| | |__ | | | _/| _/| _| | / +ENTER +HOME +STRING |_| |____||___||_| |_| |___||_|_\ +ENTER +HOME +ENTER + +STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format +ENTER +STRING More information about script synax can be found here: +ENTER +STRING https://github.com/hak5darren/USB-Rubber-Ducky/wiki/Duckyscript +ENTER From b4a49cdb306866d679b5cf3c7248453956364412 Mon Sep 17 00:00:00 2001 From: Albert Kharisov Date: Tue, 21 Dec 2021 16:53:57 +0400 Subject: [PATCH 05/14] [FL-2148] Infrared - fast erase when rename (#914) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Erase whole string during renaming remote/button in Infrared app Co-authored-by: あく --- applications/irda/scene/irda-app-scene-edit-rename.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/irda/scene/irda-app-scene-edit-rename.cpp b/applications/irda/scene/irda-app-scene-edit-rename.cpp index 39fbf2ba..dab99c15 100644 --- a/applications/irda/scene/irda-app-scene-edit-rename.cpp +++ b/applications/irda/scene/irda-app-scene-edit-rename.cpp @@ -28,7 +28,7 @@ void IrdaAppSceneEditRename::on_enter(IrdaApp* app) { app, app->get_text_store(0), enter_name_length, - false); + true); view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput); } From 28537631f33f36de4cb9434589be6030d9d8cbc6 Mon Sep 17 00:00:00 2001 From: Albert Kharisov Date: Tue, 21 Dec 2021 16:58:10 +0400 Subject: [PATCH 06/14] [FL-2110] Update TV universal database (#913) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add TV power on/off signals from Knopkus and TV-B-Gone dongles Co-authored-by: あく --- assets/resources/irda/universal/tv.ir | 278 +++++++++++++++++++++++--- 1 file changed, 254 insertions(+), 24 deletions(-) diff --git a/assets/resources/irda/universal/tv.ir b/assets/resources/irda/universal/tv.ir index 6dbbf760..1e64ced2 100755 --- a/assets/resources/irda/universal/tv.ir +++ b/assets/resources/irda/universal/tv.ir @@ -1,11 +1,37 @@ +POWER SIRC A:01 C:15 +POWER SIRC A:10 C:15 + +// dexp +POWER NEC A:08 C:05 +VOL+ NEC A:08 C:00 +VOL- NEC A:08 C:01 +CH+ NEC A:08 C:02 +CH- NEC A:08 C:03 +MUTE NEC A:08 C:0B + +// another one +POWER NECext A:DF00 C:1C +VOL+ NECext A:DF00 C:4B +VOL- NECext A:DF00 C:4F +CH+ NECext A:DF00 C:09 +CH- NECext A:DF00 C:05 +MUTE NECext A:DF00 C:08 + +// Skyworth +POWER NEC A:0E C:0C +MUTE NEC A:0E C:0D +VOL+ NEC A:0E C:14 +VOL- NEC A:0E C:15 +CH+ NEC A:0E C:12 +CH- NEC A:0E C:13 + +// Knopkus +POWER RC6 A:00 C:0C POWER Samsung32 A:07 C:02 POWER NEC A:50 C:17 POWER NEC A:40 C:12 POWER NECext A:4931 C:63 POWER NEC A:AA C:1C -POWER NEC A:AA C:1C -POWER NEC A:AA C:1C -POWER NEC A:AA C:1C POWER NEC A:38 C:1C POWER NECext A:7A83 C:08 POWER NEC A:53 C:17 @@ -18,28 +44,232 @@ POWER NEC A:71 C:08 POWER NECext A:6F80 C:0A POWER NEC A:48 C:00 POWER NECext A:7B80 C:13 -#POWER Samsung32 A:0E C:14 +POWER Samsung32 A:0E C:14 POWER NECext A:7E80 C:18 POWER NEC A:50 C:08 +POWER NECext A:7580 C:0A +POWER NECext A:5780 C:0A +POWER Samsung32 A:0B C:0A +POWER NEC A:AA C:1B +POWER NECext A:4685 C:12 +POWER Samsung32 A:05 C:02 +POWER Samsung32 A:08 C:0F +POWER NEC A:00 C:01 +POWER NEC A:00 C:01 +POWER RAW F:38000 DC:33 634 2571 505 519 479 519 479 518 480 518 480 518 480 518 480 517 481 547 481 517 481 20040 590 2555 501 1007 999 997 510 548 480 486 512 486 512 486 542 485 513 516 482 116758 593 2552 504 1004 992 1004 514 514 514 483 515 513 485 483 545 482 516 482 516 +POWER RAW F:38000 DC:33 525 1955 449 1999 476 4545 446 4544 478 2032 443 2006 469 2011 444 4577 445 4545 447 4574 448 2002 473 4547 444 34913 447 2032 443 2007 478 4542 449 4541 471 2039 446 2004 471 2008 447 4574 448 4543 448 4572 450 2030 445 4545 446 +POWER RAW F:38000 DC:33 2445 582 1221 603 548 602 1191 609 572 602 1191 609 542 607 544 631 1172 603 568 606 545 605 566 608 543 26263 2414 611 1192 607 544 606 1197 602 569 606 1197 602 539 611 540 635 1168 606 565 610 541 608 563 587 564 +POWER RAW F:38000 DC:33 3461 1802 439 452 444 1283 469 448 438 453 443 447 439 452 444 419 497 448 438 425 471 419 467 451 445 445 441 450 446 1281 471 420 466 425 471 446 440 424 472 445 461 456 440 451 445 445 441 450 446 1281 471 447 439 451 445 419 467 423 473 445 441 422 494 450 436 428 468 1259 493 425 471 1256 496 1259 472 1281 471 1285 467 423 473 417 469 1286 466 452 444 1283 469 1285 467 1261 491 1263 468 423 493 1260 471 74142 3578 1713 467 423 473 1281 471 420 466 452 444 419 467 424 472 418 488 429 467 451 445 445 441 450 446 444 442 449 437 1290 472 446 440 423 473 445 441 449 467 396 490 428 468 449 447 444 442 448 438 1289 473 445 441 450 446 444 442 449 437 426 470 421 495 422 464 426 470 1257 495 450 446 1254 488 1267 464 1290 472 1282 470 421 465 453 443 1284 468 450 446 1281 471 1283 469 1259 493 1261 470 448 468 1258 473 +POWER RAW F:38000 DC:33 389 1737 280 796 253 744 295 754 274 775 274 776 273 1827 271 1828 270 805 254 1820 278 796 253 797 252 745 294 1806 302 773 245 48942 305 1821 277 798 251 746 303 747 271 778 271 1829 279 796 253 796 253 1821 277 798 251 1823 275 1824 274 1825 273 802 247 1827 271 42824 381 1745 272 804 245 752 297 753 275 773 276 774 275 1825 273 1826 272 803 246 1828 270 805 254 795 244 753 296 1804 294 781 247 48939 379 1746 271 804 245 779 270 753 275 774 275 1825 273 802 247 802 247 1827 271 804 245 1829 279 1820 278 1821 277 798 251 1823 275 +POWER RAW F:38000 DC:33 562 1721 561 594 557 597 564 617 513 615 536 618 543 1715 566 1716 566 1692 559 594 567 588 563 618 543 611 540 615 536 618 543 1715 556 623 538 617 534 621 530 624 516 638 513 642 509 1722 560 620 541 1717 565 1692 559 1724 568 1715 556 1701 560 1723 559 +POWER RAW F:38000 DC:33 8436 4189 538 1563 566 1559 539 510 559 543 516 507 542 560 509 540 509 567 512 1586 512 1562 567 1559 539 536 533 1566 542 507 562 513 536 540 509 22102 647 1478 559 1568 540 508 541 535 534 515 534 568 511 538 511 539 540 1585 513 1560 559 1567 541 534 535 1564 534 515 534 568 511 538 511 22125 644 1482 565 1561 537 511 538 564 515 508 541 535 534 541 508 516 563 1588 510 1563 556 1570 538 510 559 1567 541 534 515 535 534 541 508 +POWER RAW F:38000 DC:33 929 825 1711 934 797 930 791 909 822 932 789 938 793 934 797 930 791 1719 899 856 1711 907 824 90848 923 830 1706 912 819 908 823 931 790 910 822 933 788 912 819 935 796 1714 904 850 1707 939 792 +POWER RAW F:38000 DC:33 448 2031 444 2005 480 4540 452 4539 473 2037 438 2011 474 2006 449 4571 451 4539 453 4568 444 2036 449 4541 451 34906 527 1953 451 1998 477 4543 449 4542 480 2030 445 2004 471 2009 446 4575 447 4543 449 4572 450 1999 476 4545 446 +POWER RAW F:38000 DC:33 9021 4496 567 1664 567 1690 561 567 533 1698 563 1667 564 1693 568 1663 568 586 534 567 563 565 535 594 536 591 539 589 531 571 539 563 567 1690 541 560 560 594 536 592 538 564 536 1695 566 1664 567 1690 561 1670 561 1696 555 1675 566 562 558 596 514 562 568 559 561 594 536 565 535 593 537 591 539 1665 566 1692 559 1671 560 1697 564 1666 565 1666 565 1693 558 1672 569 23181 9013 4504 569 1689 542 1689 562 565 535 1697 564 1666 646 1610 560 1672 559 595 535 593 537 590 510 566 564 590 540 588 532 596 514 588 542 1689 542 560 560 594 536 592 538 590 510 1694 567 1664 567 1690 561 1669 562 1695 556 1675 566 561 559 596 514 588 542 585 535 593 537 591 509 593 537 591 539 1665 566 1692 559 1671 560 1697 564 1667 564 1667 564 1693 558 1672 569 +POWER RAW F:38000 DC:33 8041 3979 513 536 482 515 513 1559 509 515 514 1560 508 515 514 509 509 514 484 4000 533 1566 512 537 481 1566 512 537 481 1566 512 537 481 516 513 537 481 24150 8044 3977 505 518 510 539 479 1567 511 512 506 1568 510 539 479 543 485 538 480 3977 536 1564 514 534 484 1563 515 508 510 1563 515 508 510 540 489 534 484 +POWER RAW F:38000 DC:33 383 2027 295 2112 271 2138 266 890 271 887 294 926 235 2114 300 887 274 915 236 2145 269 887 274 884 297 923 238 920 241 917 264 895 266 26573 384 2026 296 2111 273 2136 268 889 272 886 295 924 237 2113 301 886 275 914 237 2144 270 886 275 914 267 921 240 919 242 916 265 924 237 +POWER RAW F:38000 DC:33 177 8474 175 5510 174 8476 173 8477 177 8504 171 5515 175 8476 178 8472 177 8473 176 5541 174 8476 173 45583 171 8481 178 5507 177 8473 176 8474 175 8506 173 5512 172 8478 176 8475 174 8476 178 5538 177 8474 175 +POWER RAW F:38000 DC:33 8044 3976 506 517 511 1563 505 517 511 538 480 517 511 538 460 563 455 568 460 3993 530 545 483 1564 514 1559 509 1564 514 509 509 540 488 535 483 513 505 24150 8043 3978 514 509 509 1564 514 509 509 540 478 519 509 540 458 565 464 559 459 3994 529 546 482 1565 513 1560 508 1565 513 510 508 541 487 536 482 541 477 +POWER RAW F:38000 DC:33 558 2942 450 10021 482 2989 484 10015 447 3024 449 10021 472 3100 485 2986 477 2994 500 2999 475 2996 477 2994 479 2992 482 3018 476 2995 479 6464 484 36270 477 3023 450 10020 473 2999 485 10014 448 3022 452 10019 474 3098 478 2994 480 2991 503 2996 477 2994 480 2992 482 2990 484 3015 479 2992 481 6462 485 +POWER RAW F:38000 DC:33 587 2407 476 1062 965 547 482 547 451 577 452 546 452 22108 590 2404 479 1060 967 1028 510 519 509 548 480 487 511 120791 645 2411 472 1066 961 1065 483 515 514 514 504 493 515 +POWER RAW F:38000 DC:33 172 7439 171 7441 169 7443 177 7434 176 7462 178 4887 176 4916 177 4914 169 7469 171 4920 174 4918 175 55174 176 7436 174 7437 173 7439 171 7440 175 7463 172 4894 174 4917 171 4921 172 7465 175 4916 178 4914 169 +POWER RAW F:38000 DC:33 589 2556 500 524 474 554 454 544 454 543 455 543 455 543 455 543 445 583 446 552 446 20046 584 2561 505 1033 485 514 963 518 480 1032 516 512 476 522 506 491 507 522 476 116758 586 2560 506 1033 484 513 964 548 450 1031 507 522 476 521 507 490 508 521 477 +POWER RAW F:38000 DC:33 586 2407 476 1063 964 578 450 548 450 547 481 517 481 577 451 546 452 546 472 556 452 545 453 575 453 514 484 544 484 543 455 14954 510 2483 481 1058 480 548 959 552 446 1067 481 516 512 546 482 515 992 1003 535 493 515 543 486 513 475 522 506 552 446 111671 589 2405 478 1061 477 551 967 514 484 1059 479 549 479 548 480 517 990 1036 512 516 482 546 483 515 503 525 483 544 454 +POWER RAW F:38000 DC:33 8444 4180 537 1564 565 1560 538 1561 557 1568 540 1559 539 536 533 542 517 559 510 1563 535 1564 565 1561 537 512 567 1558 540 535 534 1566 542 1557 562 23122 564 1562 557 1569 539 1560 538 1587 542 1558 540 534 535 515 534 541 538 1587 511 1563 566 1560 538 536 533 1567 541 534 515 1585 533 1566 542 23166 561 1565 564 1561 537 1563 535 1590 539 1561 537 538 541 534 515 535 534 1564 534 1566 563 1563 535 540 539 1560 538 511 538 1588 541 1559 539 +POWER RAW F:38000 DC:33 527 1923 481 1998 477 4543 449 4542 470 2040 445 2004 471 2009 446 4575 447 4543 449 4572 450 1999 476 2034 441 34899 524 1956 448 2001 474 4546 446 4545 477 2033 442 2007 478 2002 443 4578 444 4546 445 4575 447 2003 472 2037 448 +POWER RAW F:38000 DC:33 533 1356 437 3474 427 3483 429 3455 436 1454 430 1459 405 28168 510 1379 434 3477 434 3476 425 3459 432 1457 427 1462 402 +POWER RAW F:38000 DC:33 921 833 1714 932 789 938 793 934 797 903 818 909 822 905 816 938 793 1716 902 853 1714 905 816 90856 922 805 1742 931 790 937 794 933 788 939 792 935 796 930 791 937 794 1715 903 825 1742 904 817 +POWER RAW F:38000 DC:33 179 7433 177 4915 178 7434 175 7436 174 7464 176 7435 175 4916 177 4915 173 4918 170 4922 171 4920 173 55174 175 7437 173 4919 174 7437 173 7439 171 7467 173 7438 172 4920 173 4919 174 4917 176 4915 178 4914 169 +POWER RAW F:38000 DC:33 169 6731 176 6748 169 6730 177 6748 169 6755 172 4427 177 4447 178 6721 175 6749 178 4446 168 4456 169 54704 176 6723 174 6750 177 6723 173 6750 177 6747 170 4429 175 4449 176 6723 174 6751 176 4448 177 4447 178 +POWER RAW F:38000 DC:33 3506 3494 876 830 840 2576 847 2568 844 862 819 2570 842 864 816 863 818 2570 842 836 844 2572 840 866 815 865 815 2573 839 867 813 866 814 2573 850 857 813 2575 847 2568 844 834 847 2569 843 835 845 2571 872 2571 842 32654 3512 3488 872 834 847 2570 842 2573 839 867 814 2574 849 858 822 857 813 2575 848 859 821 2566 846 832 848 860 821 2567 845 833 848 860 820 2568 844 834 847 2569 843 2572 840 838 843 2574 849 829 841 2575 868 2575 837 +POWER RAW F:38000 DC:33 560 2939 453 10018 475 2996 477 10022 450 3021 452 10018 475 3097 478 6464 483 6460 477 6466 502 6469 479 2993 480 2990 484 36274 564 2936 456 10015 478 2993 481 10020 534 2936 456 10014 479 3093 482 6461 476 6466 482 6461 476 6495 473 2999 485 2986 477 +POWER RAW F:38000 DC:33 10726 41047 10727 +POWER RAW F:38000 DC:33 1617 4604 1559 1537 1560 1537 1560 4661 1533 33422 1613 4607 1566 1530 1556 1540 1536 4685 1539 +POWER RAW F:38000 DC:33 174 4972 177 4910 173 4944 170 6988 174 6984 177 6951 175 6983 174 14269 177 4969 175 4912 176 4941 178 6979 172 6986 175 6953 178 6980 171 +POWER RAW F:38000 DC:33 174 7067 176 10544 1055 719 1053 739 1054 738 953 822 1052 2566 169 3435 171 3431 175 3446 170 3432 174 3446 170 3432 174 3428 178 3442 174 3429 177 3425 171 39320 2323 4900 178 10543 1056 719 1053 739 1054 738 953 821 1053 2566 169 3435 171 3431 175 3445 171 3432 174 3446 170 3432 174 3428 178 3442 174 3428 178 3425 171 +POWER RAW F:38000 DC:33 3506 3492 868 839 841 2575 848 858 822 2566 846 832 848 859 821 858 812 2576 847 860 820 2567 845 833 847 860 821 2568 844 862 818 2570 842 864 817 2571 841 2574 849 2567 845 861 820 2568 845 834 847 2570 873 2570 842 34395 3503 3496 874 833 847 2568 845 834 847 2570 842 864 816 835 846 862 819 2569 843 835 846 2571 841 865 816 864 816 2571 841 837 844 2573 850 857 813 2575 848 2567 845 2570 842 864 816 2572 840 838 842 2574 869 2574 838 +POWER RAW F:38000 DC:33 170 8479 170 5516 178 8472 177 8474 175 8506 173 5513 171 8479 175 8476 178 8472 177 5540 175 8475 174 45584 177 8473 176 5509 175 8476 173 8477 176 8504 170 5516 178 8472 177 8474 175 8476 173 5543 172 8479 170 +POWER RAW F:38000 DC:33 178 4969 170 6958 173 4944 175 6983 173 6956 174 6984 177 6980 171 16308 180 4966 173 6955 176 4941 172 6985 176 6982 169 6960 176 6982 174 +POWER RAW F:38000 DC:33 585 2409 474 550 478 550 448 1033 994 1063 485 512 506 79916 585 2410 473 551 477 550 448 1034 993 1033 515 543 475 +POWER RAW F:38000 DC:33 1192 1012 6649 26844 1192 1013 6648 +POWER RAW F:38000 DC:33 3134 6105 6263 82963 3134 6105 6263 +POWER RAW F:38000 DC:33 588 1511 567 1533 565 589 531 597 513 589 541 587 533 1565 533 569 541 1533 565 562 568 1531 537 1537 561 593 537 591 539 1507 561 1539 569 22152 586 1513 565 1535 563 590 540 562 538 564 566 588 542 1557 531 597 513 1534 564 590 540 1533 535 1539 559 568 562 592 538 1509 569 1531 567 +POWER RAW F:38000 DC:33 923 831 1715 903 818 936 795 932 789 938 793 934 797 1713 1740 932 789 911 821 934 798 930 791 90853 928 799 1737 935 796 931 790 937 795 932 789 938 793 1717 1736 936 796 932 789 911 820 934 798 +POWER RAW F:38000 DC:33 689 1461 566 1534 564 589 531 597 513 1534 564 564 566 1533 535 620 510 1537 561 592 538 1535 543 1531 567 587 533 595 535 1511 567 1533 565 22161 588 1512 566 1534 564 564 556 598 512 1535 563 565 565 1534 534 594 536 1538 560 593 537 1536 542 1532 566 587 543 585 535 1511 567 1534 564 +POWER RAW F:38000 DC:33 588 2558 498 526 482 515 483 546 452 545 453 545 453 545 453 545 453 544 474 554 444 20047 583 2562 504 519 479 519 479 1003 515 483 1024 548 450 1001 995 1001 506 116771 593 2552 504 520 478 551 447 1004 513 514 993 549 449 1002 994 1002 516 +POWER RAW F:38000 DC:33 587 2559 507 517 481 517 481 547 451 516 482 546 452 546 452 546 452 545 473 525 483 20038 592 2553 503 521 477 552 446 521 477 1004 514 515 992 1034 483 514 484 513 485 116769 593 2552 504 520 478 550 448 520 478 1003 515 514 993 1032 486 513 475 522 476 +POWER RAW F:38000 DC:33 4558 4576 558 596 565 97881 4554 4579 565 589 562 +POWER RAW F:38000 DC:33 1039 7202 958 4713 981 4713 961 7255 956 4739 955 16077 1038 7204 956 4714 980 4715 959 7256 954 4741 954 +POWER RAW F:38000 DC:33 506 2638 510 516 482 516 482 546 452 546 452 545 453 545 453 545 453 575 443 554 444 20048 592 2554 502 1036 481 517 481 517 511 516 482 516 961 1035 513 515 483 514 484 116757 594 2552 504 1034 484 514 484 514 504 524 484 513 964 1032 506 522 476 492 506 +POWER RAW F:38000 DC:33 170 7441 169 4924 174 7437 193 7444 171 7441 174 4918 170 7441 174 4917 171 7440 195 7443 172 7439 171 55187 174 7437 173 4919 175 7437 173 7438 172 7466 175 4891 172 7439 171 4921 172 7439 171 7441 174 7464 171 +POWER RAW F:38000 DC:33 179 4967 172 4915 178 6980 171 4945 169 4948 176 4912 176 4941 178 16307 176 4969 175 4912 176 6982 174 4942 171 4945 169 4919 174 4943 176 +POWER RAW F:38000 DC:33 1042 793 898 883 869 858 924 884 878 877 875 879 873 855 928 1717 901 854 1794 878 894 887 875 1716 902 89114 985 798 903 878 874 880 902 852 900 855 897 857 905 876 896 1722 906 849 1789 883 899 855 897 1721 897 +POWER RAW F:38000 DC:33 170 8480 169 8481 178 8472 177 8474 175 8476 173 5513 176 8474 175 8476 173 8507 178 5509 175 8505 174 45558 175 8476 173 8476 173 8477 172 8478 171 8480 169 5517 177 8473 176 8474 175 8506 174 5512 172 8509 171 +POWER RAW F:38000 DC:33 628 2577 499 528 480 545 453 544 454 544 454 544 454 544 454 543 455 543 475 553 445 20047 593 2553 503 521 477 551 447 1004 514 515 992 519 479 1003 515 513 485 543 455 116768 585 2561 505 519 479 519 479 1002 516 513 994 548 450 1001 506 522 476 521 477 +POWER RAW F:38000 DC:33 8987 4505 568 586 534 594 536 591 509 567 563 591 539 563 567 587 513 1692 559 1672 559 1698 563 590 510 592 538 590 540 1664 567 1690 561 593 507 1699 562 1668 563 1694 567 1663 568 586 534 568 562 592 508 595 535 1695 536 592 538 1693 558 595 515 1690 561 593 517 585 535 567 563 39551 8994 4497 566 589 541 560 560 594 516 586 534 594 536 592 538 590 510 1695 566 1664 567 1690 561 593 507 595 535 566 564 1667 564 1693 558 596 534 1670 561 1670 561 1696 565 1666 565 589 541 587 533 595 515 587 533 1697 534 568 562 1695 556 572 538 1693 568 559 541 588 542 585 535 +POWER RAW F:38000 DC:33 8987 4504 569 559 561 593 537 565 535 567 563 591 539 588 532 597 513 1691 560 568 562 592 508 1697 564 589 511 565 565 1692 559 1672 559 569 561 1669 562 566 564 564 566 1665 566 588 542 586 534 1670 561 567 563 565 535 593 537 591 539 1692 539 589 541 586 534 594 536 592 508 40679 8987 4504 569 585 535 593 537 591 509 566 564 591 539 588 532 596 514 1691 560 594 536 592 508 1697 564 589 511 591 539 1692 559 1671 560 594 536 1669 562 592 538 590 540 1664 567 587 543 585 535 1670 561 593 537 565 535 593 537 591 539 1691 540 588 542 586 534 594 536 592 508 +POWER RAW F:38000 DC:33 298 1828 270 804 245 1829 279 1820 278 797 252 771 278 1822 276 1824 274 800 249 1825 273 802 247 776 252 771 278 1822 276 799 250 48931 388 1737 280 796 253 1821 277 1822 276 798 251 1823 275 800 249 774 275 1825 273 776 273 1801 297 1828 270 1829 279 796 253 1821 277 42813 301 1825 273 801 248 1826 272 1827 271 804 245 805 244 1830 278 1821 277 798 251 1823 275 799 250 774 244 779 280 1820 278 796 253 48926 382 1744 354 696 271 1828 270 1829 279 796 253 1821 277 797 252 746 303 1823 275 774 275 1799 299 1826 272 1827 271 804 245 1829 279 +POWER RAW F:38000 DC:33 177 5508 176 5539 176 8475 174 5542 173 8478 171 5545 170 8481 168 8482 177 8473 176 5541 174 8476 173 45573 169 5517 177 5538 177 8473 176 5541 174 8476 173 5544 171 8479 170 8481 178 8472 177 5540 175 8475 174 +POWER RAW F:38000 DC:33 175 8474 175 8475 174 8477 172 8478 171 8480 169 8481 178 5538 177 5510 174 5542 173 5543 172 5544 171 45575 177 8472 177 8474 175 8476 173 8477 172 8478 171 8481 178 5507 177 5539 176 5540 175 5542 173 5543 172 +POWER RAW F:38000 DC:33 8050 3971 511 1562 516 1558 510 539 490 1557 511 1563 515 533 485 538 490 533 485 3983 530 1569 509 1564 514 1559 509 1565 513 1560 508 515 513 536 482 541 488 24152 8042 3979 514 1560 508 1565 513 510 508 1565 513 1560 508 515 513 536 482 541 488 3980 533 1567 511 1562 516 1557 511 1563 515 1558 510 539 489 534 484 539 490 +POWER RAW F:38000 DC:33 175 8475 174 5512 177 8473 176 8475 174 8506 179 5508 176 8474 175 8475 174 8477 172 5544 171 8480 169 45587 176 8475 174 5511 173 8477 177 8473 176 8504 170 5516 178 8472 177 8473 176 8475 174 5542 173 8478 171 +POWER RAW F:38000 DC:33 176 7436 174 7438 172 7439 171 7441 174 7463 172 7440 170 4921 172 4919 174 4917 176 4916 177 4914 174 55176 175 7437 173 7439 191 7446 174 7438 177 7434 176 7435 175 4917 176 4915 179 4914 174 4917 171 4946 178 +POWER RAW F:38000 DC:33 176 7435 175 4917 177 7435 175 7436 189 7449 176 7435 175 7437 173 4918 175 7436 174 4918 175 4916 178 55171 175 7436 174 4918 170 7441 174 7438 177 7460 170 7441 174 7438 177 4914 174 7437 178 4914 169 4922 171 +POWER RAW F:38000 DC:33 8049 3973 509 1564 514 509 509 1564 514 535 483 1564 514 535 483 540 489 535 483 3980 533 1566 512 537 481 1566 512 511 507 1566 512 537 481 542 486 511 507 24149 8045 3976 516 1558 510 512 516 1557 511 512 516 1558 510 512 516 507 511 512 506 3984 539 1560 508 515 513 1560 508 541 488 1560 508 541 488 536 482 514 504 +POWER RAW F:38000 DC:33 366 202 867 527 170 130516 343 227 863 529 168 +POWER RAW F:38000 DC:33 176 5992 176 1372 176 1320 177 1345 172 1349 179 1370 178 1317 175 4444 176 1346 171 1351 177 1345 172 1349 179 1344 174 5963 175 65574 172 5995 178 1344 174 1348 175 1347 175 1347 170 1378 170 1325 172 4447 178 1344 173 1349 169 1353 175 1347 170 1351 177 5961 177 +POWER RAW F:38000 DC:33 497 1478 488 511 467 1482 494 531 447 1477 499 501 466 533 445 530 468 507 471 529 438 12857 488 1485 491 509 469 1481 495 529 448 1476 490 510 468 532 445 529 469 480 498 502 465 +POWER RAW F:38000 DC:33 982 6313 961 2662 903 2718 929 2719 907 6363 900 2722 904 6365 909 6361 903 6368 906 2742 905 46364 989 6307 906 2716 911 2712 925 2723 903 6367 907 2715 901 6369 905 6365 909 6361 903 2745 902 +POWER RAW F:38000 DC:33 599 257 975 317 177 130649 308 228 974 319 175 +POWER RAW F:38000 DC:33 176 4969 170 6958 173 6985 177 6981 171 6958 178 6980 177 6981 170 16308 180 4966 173 6955 176 6982 169 6988 174 6956 175 6983 173 6984 172 +POWER RAW F:38000 DC:33 178 5990 173 1349 174 1348 175 1348 174 4444 176 1346 171 1351 177 4416 178 1344 173 1348 169 1353 175 1347 170 1351 177 9048 177 65573 173 5995 173 1348 175 1348 174 1347 176 4444 171 1351 177 1345 173 4421 173 1348 169 1352 176 1347 170 1351 177 1345 172 9053 177 +POWER RAW F:38000 DC:33 174 4972 177 4910 173 6985 177 4940 174 6984 178 6951 175 6983 174 14269 177 4968 176 4912 176 6981 175 4941 173 6985 177 6953 178 6979 172 +POWER RAW F:38000 DC:33 1318 225 177 130305 1609 231 171 +POWER RAW F:38000 DC:33 585 2410 473 1065 962 581 447 519 479 580 448 549 449 579 449 518 480 548 480 517 481 517 481 577 451 516 482 576 452 545 453 14955 510 2483 481 1058 480 549 969 543 445 1037 511 547 481 546 482 516 482 545 484 545 483 514 484 544 963 1063 485 543 445 111612 626 2427 557 954 513 512 995 547 451 1031 507 521 508 551 477 520 478 550 478 549 479 488 510 548 969 1057 481 517 481 +POWER RAW F:38000 DC:33 203 272 1215 302 171 130229 1423 275 178 +POWER RAW F:38000 DC:33 176 7436 174 7438 192 7446 174 7437 178 7434 176 7435 175 4917 176 4915 178 4913 175 4917 197 7440 175 55130 286 7377 177 7435 175 7437 173 7438 172 7466 174 7411 178 4913 170 4921 172 4919 174 4918 175 7436 174 +POWER RAW F:38000 DC:33 175 7437 173 4918 170 7441 174 7437 178 7460 170 7441 179 7433 177 4915 178 4913 170 4922 171 4920 173 55124 291 7372 172 4921 172 7439 171 7441 174 7463 172 7440 170 7442 178 4913 170 4922 171 4920 173 4918 175 +POWER RAW F:38000 DC:33 172 8477 172 8478 171 8480 169 5516 179 8502 178 5509 175 8475 174 8476 173 8479 170 5545 170 8480 169 45588 176 8473 176 8474 175 8476 173 5513 177 8504 171 5515 174 8476 178 8472 177 8473 176 5541 174 8476 173 +POWER RAW F:38000 DC:33 177 7436 174 4918 175 7436 174 4918 175 7462 178 4887 176 4916 177 4914 174 4917 171 4921 172 4919 175 55184 175 7435 175 4918 175 7436 174 4918 175 7462 178 4914 174 4917 171 4920 173 4919 174 4917 176 4915 178 +POWER RAW F:38000 DC:33 508 2484 480 1060 967 544 485 544 454 574 454 543 455 573 445 553 445 522 506 552 446 552 446 551 477 551 447 581 447 520 478 550 478 15908 626 2427 476 1062 476 522 995 547 451 1061 477 520 508 550 478 519 479 519 999 1058 959 1037 990 582 446 1035 483 111666 590 2404 479 1059 479 549 968 543 455 1027 511 548 480 517 511 486 512 546 961 1065 962 1034 993 579 449 1032 486 +POWER RAW F:38000 DC:33 175 8475 174 8475 174 8477 172 8478 171 8480 169 5517 178 8473 175 8475 179 8501 173 5513 176 8505 169 45562 179 8472 177 8473 176 8474 175 8476 173 8478 171 5515 174 8476 178 8473 176 8505 174 5512 172 8508 171 120769 178 93377 175 7437 173 4919 174 7437 173 7439 171 7467 173 7439 171 7441 174 4918 170 4921 172 7439 171 7467 173 55167 171 7440 170 4922 171 7440 195 7443 172 7439 171 7441 174 7438 177 4915 173 4918 195 7442 173 7439 170 +POWER RAW F:38000 DC:33 295 1805 273 776 242 1808 270 754 244 1806 272 777 241 758 270 754 264 760 268 756 272 14149 297 1802 266 784 244 1805 263 762 246 1803 265 785 244 780 248 751 267 758 271 753 265 +POWER RAW F:38000 DC:33 535 1723 569 585 566 615 536 619 542 586 565 616 535 1722 539 615 536 1721 561 620 541 587 564 617 534 621 540 588 563 618 543 1714 537 617 534 621 540 615 536 618 543 612 539 615 536 1722 560 594 567 1717 534 1723 569 1714 557 1700 643 1639 643 1641 559 +POWER RAW F:38000 DC:33 502 2521 504 521 997 545 453 575 453 545 453 575 454 22097 591 2433 511 513 994 1062 476 552 476 522 476 552 476 120839 628 2455 509 515 992 1064 484 513 505 493 515 543 475 +POWER RAW F:38000 DC:33 591 2404 479 1060 967 1029 509 519 509 549 479 518 480 79926 585 2408 556 956 989 1033 515 544 484 543 475 522 476 +POWER RAW F:38000 DC:33 586 2560 506 518 480 548 450 548 450 517 481 517 481 517 481 547 451 546 482 516 482 20040 590 2556 500 1038 480 518 969 543 455 543 475 1006 511 517 481 517 511 486 481 116778 584 2561 505 1033 485 513 964 548 450 548 480 1001 506 522 476 522 506 521 446 +POWER RAW F:38000 DC:33 917 206 175 186 170 21561 170 2280 175 2274 502 1929 174 2276 169 5178 170 2261 173 3724 498 1932 171 2279 176 2273 172 3709 172 2277 178 3720 171 17223 177 7619 174 2275 170 2279 176 2256 168 2280 175 5172 176 2256 168 3729 173 2276 179 2253 171 2278 177 3703 178 2271 174 3724 177 17251 170 7627 177 2272 173 2276 169 2263 171 2277 178 5169 169 2262 172 3726 175 2256 168 2280 175 2274 171 3710 171 2278 177 3720 171 +POWER RAW F:38000 DC:33 565 233 653 313 170 130328 752 235 233 107 229 398 177 +POWER RAW F:38000 DC:33 586 2439 505 549 968 1027 511 517 511 517 481 547 481 21583 584 2439 505 520 997 1059 479 549 479 518 480 548 480 120894 593 2432 501 522 995 1061 477 521 507 520 478 550 478 +POWER RAW F:38000 DC:33 558 8032 474 8115 503 8116 482 8108 480 8141 477 5239 476 8114 504 8115 483 8107 481 5236 509 8111 477 45290 554 8036 481 8108 510 8110 478 8112 476 8145 473 5243 482 8107 511 8109 479 8111 477 5240 505 8115 473 +POWER RAW F:38000 DC:33 173 7438 172 4920 173 7438 172 4920 173 7465 175 4890 173 7439 171 4920 173 4919 174 4917 176 4915 178 55179 170 7441 169 4924 174 7437 178 4913 175 7463 172 4893 170 7441 174 4918 170 4922 171 4920 173 4918 175 +POWER RAW F:38000 DC:33 225 745 222 774 193 778 200 797 175 769 193 777 201 771 196 774 224 747 220 776 202 769 198 248 220 252 196 250 218 253 225 746 221 250 198 248 220 252 226 246 222 223 225 248 220 252 216 229 219 253 225 247 221 277 176 243 220 279 189 230 228 244 224 248 220 252 196 250 218 253 215 257 201 770 197 799 189 257 201 271 197 37716 222 749 218 778 200 771 196 801 172 772 200 771 196 774 193 777 221 750 217 780 197 773 194 251 217 255 193 279 199 273 195 749 218 254 194 252 226 245 223 275 178 242 221 277 201 245 193 253 225 247 221 250 218 254 194 252 226 272 196 223 225 248 220 251 217 255 193 253 225 247 221 251 197 773 194 803 174 297 176 244 219 +POWER RAW F:38000 DC:33 3503 2655 197 642 876 2568 844 834 846 833 848 860 821 831 839 2576 847 2569 843 2572 841 2574 849 858 823 857 813 866 815 865 815 2572 841 2575 848 2568 844 2570 842 836 844 863 818 834 847 861 820 2568 845 2571 872 2571 842 32651 3505 3495 875 2567 845 861 820 832 849 859 811 840 840 2576 847 2568 844 2571 842 2574 849 830 840 867 814 838 842 865 815 2572 840 2575 848 2568 845 2571 841 865 815 864 817 834 846 861 819 2569 843 2572 871 2572 840 +POWER RAW F:38000 DC:33 347 677 219 252 196 276 202 742 225 798 174 770 192 778 200 771 196 775 223 748 219 777 200 770 197 249 219 253 195 251 227 271 197 747 220 252 216 229 219 253 225 273 195 277 176 244 219 253 215 230 228 244 224 248 220 252 196 250 218 280 198 247 201 245 223 249 219 253 195 251 227 245 223 248 200 797 175 795 198 248 200 246 222 37666 344 678 228 245 223 222 226 771 196 800 198 747 220 750 217 753 224 773 194 776 202 769 198 799 173 246 227 245 223 249 199 247 221 749 218 280 198 247 201 245 223 249 219 253 195 251 227 244 224 248 200 272 196 250 218 254 194 252 226 245 223 249 199 274 194 251 227 245 193 253 225 273 195 251 217 753 225 746 221 251 197 275 193 +POWER RAW F:38000 DC:33 174 7437 173 7440 174 7437 178 7433 177 7461 169 7442 178 4914 174 4917 171 4921 172 4919 174 7463 177 55163 177 7435 174 7437 173 7438 172 7440 175 7463 172 7413 176 4915 178 4913 175 4917 171 4920 174 7438 172 +POWER RAW F:38000 DC:33 8042 3979 513 510 508 541 487 1559 509 515 513 1560 508 515 513 510 508 541 477 3981 532 1568 510 1563 515 1558 510 1564 514 1559 509 514 514 535 483 540 488 24151 8042 3979 513 536 482 541 487 1560 508 541 488 1560 508 541 487 536 482 541 477 3980 533 1566 512 1561 507 1566 512 1562 516 1557 511 538 491 533 485 538 490 +POWER RAW F:38000 DC:33 8989 4501 562 1696 565 1665 566 562 568 586 514 588 542 586 534 594 536 1667 564 591 539 1692 539 563 567 1690 561 1669 562 1669 562 1696 565 562 538 564 566 588 542 586 534 1670 561 568 562 592 538 590 510 592 538 590 540 561 539 563 567 561 569 585 535 593 507 595 535 593 537 39547 8987 4504 569 1689 562 1668 563 591 539 589 511 591 539 589 541 561 559 1671 560 568 562 1695 536 592 538 1693 558 1673 568 1663 568 1689 562 592 508 594 536 592 538 590 540 1664 567 561 569 559 561 567 543 585 535 593 537 591 509 593 537 591 539 589 541 587 513 589 541 587 533 +POWER RAW F:38000 DC:33 8988 4504 640 487 562 592 538 590 510 592 538 590 540 588 532 596 514 614 516 1689 562 1668 563 1695 536 1695 566 1664 567 1690 612 1618 643 1430 801 1613 648 481 558 570 540 589 541 587 533 595 535 592 508 594 536 592 538 1667 564 1693 558 1672 569 1688 563 1668 644 1586 563 1694 567 40630 8994 2265 557 96833 8987 2273 538 +POWER RAW F:38000 DC:33 173 7439 171 4922 172 7439 171 4921 172 7466 174 4917 176 4915 173 4918 170 7441 174 7438 192 7445 175 55181 174 7437 173 4918 175 7437 173 4919 175 7463 177 4888 175 4917 176 4915 178 7460 170 7440 175 7437 178 +POWER RAW F:38000 DC:33 1636 4610 1563 1533 1584 7760 1561 28769 1641 4606 1557 1539 1588 7757 1564 +POWER RAW F:38000 DC:33 590 2404 479 1059 968 575 454 544 454 574 454 543 455 543 475 522 476 552 476 552 446 551 447 581 448 520 478 581 447 519 479 549 479 15967 587 2407 476 1062 476 522 995 547 451 1030 508 520 509 550 478 519 479 519 998 1028 999 1057 481 547 960 1066 482 111641 587 2407 476 1063 485 513 994 547 451 1031 507 551 477 551 477 520 478 550 968 1059 968 1027 511 548 959 1036 512 +POWER RAW F:38000 DC:33 588 2406 477 1061 966 577 451 516 482 545 483 545 453 575 443 524 484 514 504 554 454 543 455 543 475 553 445 583 445 521 477 582 446 15969 585 2409 474 1065 483 514 993 549 449 1033 515 543 475 553 475 522 476 552 965 1030 997 576 452 1029 998 1028 479 111668 587 2407 475 1063 485 543 964 517 481 1031 507 552 476 551 477 520 478 550 968 1028 999 574 454 1027 990 1036 481 +POWER RAW F:38000 DC:33 174 7439 196 7441 174 7437 173 7439 171 7441 174 7438 177 7460 170 7442 178 7433 177 4915 173 4918 170 55186 174 7438 172 7440 170 7441 174 7438 177 7461 169 7416 173 7464 176 7435 175 7437 173 4918 175 4917 176 +POWER RAW F:38000 DC:33 173 7438 172 7441 174 7438 177 7434 176 7462 168 7443 177 7435 175 4917 176 4915 173 7438 177 4941 173 55166 174 7438 197 7441 174 7437 173 7439 171 7441 174 7438 177 7460 170 4922 171 4893 195 7443 172 4920 173 +POWER RAW F:38000 DC:33 175 7436 179 4913 175 4917 171 4920 173 4945 169 4896 177 7435 175 7436 174 7464 176 4916 177 4914 169 55180 170 7441 169 4924 169 4922 171 4920 173 4919 174 4917 176 7435 175 7463 177 7434 176 4916 177 4914 174 +POWER RAW F:38000 DC:33 927 827 1709 936 796 932 789 938 793 1717 1736 936 795 932 789 1721 927 827 1709 909 822 90851 898 829 1738 934 798 930 791 936 796 1715 1738 934 797 930 791 1719 899 828 1739 934 797 +POWER RAW F:38000 DC:33 176 5991 177 1372 176 1320 177 1344 173 1349 174 1374 169 1327 170 4449 176 1346 171 1351 177 1345 172 1349 168 1353 175 5963 175 65573 173 5995 178 1344 174 1348 175 1348 174 1347 170 1378 170 1325 172 4447 178 1344 174 1349 169 1353 175 1347 170 1352 176 5961 177 -VOL- NECext A:DF00 C:4F -CH+ NECext A:DF00 C:09 -CH- NECext A:DF00 C:05 -MUTE NECext A:DF00 C:08 -// Microlab (Not TV) -POWER NEC A:00 C:00 -MUTE NEC A:00 C:02 -VOL+ NEC A:00 C:11 -VOL- NEC A:00 C:10 - -// Skyworth -POWER Samsung32 A:0E C:0C -MUTE Samsung32 A:0E C:0D -VOL+ Samsung32 A:0E C:14 -VOL- Samsung32 A:0E C:15 -CH- Samsung32 A:0E C:12 -CH+ Samsung32 A:0E C:13 - -// LG (Goldstar) -MUTE NEC A +// TV-B-GONE, parsed doesn't repeat Knopkus. RAW can. +POWER NEC A:71 C:4A +POWER NEC A:60 C:03 +POWER NEC A:60 C:00 +POWER NEC A:42 C:01 +POWER NECext A:AD50 C:00 +POWER NECext A:AD50 C:02 +POWER NEC A:50 C:3F +POWER Samsung32 A:06 C:0F +POWER NEC A:08 C:12 +POWER Samsung32 A:08 C:0B +POWER NECext A:5583 C:C2 +POWER NEC A:00 C:51 +POWER NECext A:BD00 C:01 +POWER Samsung32 A:00 C:0F +POWER Samsung32 A:16 C:0F +POWER NEC A:01 C:01 +POWER NECext A:6880 C:49 +POWER NECext A:0286 C:49 +POWER RAW F:38000 DC:33 2383 609 1214 600 612 580 1213 608 614 583 1210 605 607 586 616 611 1192 599 613 608 614 579 613 615 607 26670 2387 601 1212 600 612 589 1214 603 609 586 1217 595 607 594 618 606 1187 602 610 609 613 588 614 610 612 +POWER RAW F:38000 DC:33 178 7761 176 11308 546 957 540 1958 538 970 537 1955 541 962 545 1953 543 964 543 962 545 957 540 970 548 960 547 1945 541 1950 546 965 542 1953 543 962 545 1945 540 970 537 1958 538 7881 172 7744 172 11318 536 971 536 1956 540 963 534 1964 542 966 541 1951 535 968 539 971 536 971 536 969 538 964 533 1965 541 1954 542 963 534 1956 540 971 536 1959 537 968 539 1951 535 +POWER RAW F:38000 DC:33 3444 1767 413 486 420 1343 419 478 418 485 411 490 416 479 417 489 417 482 414 485 421 482 414 483 413 490 416 485 411 1343 419 487 419 480 416 483 413 490 416 482 414 488 418 483 413 483 413 492 414 1345 417 482 414 489 417 480 416 487 419 482 414 481 415 491 415 484 412 1347 415 488 418 1338 414 1348 414 1347 415 1340 412 494 412 487 419 1340 412 491 415 1341 421 1341 421 1340 412 1343 419 487 419 1339 413 74311 3445 1753 437 461 445 1316 446 456 440 455 441 465 441 458 438 461 445 458 438 460 436 466 440 461 445 451 445 460 446 1313 439 460 446 457 439 459 437 465 441 460 446 450 436 469 437 462 444 456 440 1322 440 457 439 464 442 459 437 459 437 468 438 461 445 455 441 462 444 1312 440 463 443 1317 445 1310 442 1323 439 1320 442 457 439 464 442 1315 437 466 440 1320 442 1313 439 1326 446 1313 439 460 446 1317 445 +POWER RAW F:38000 DC:33 278 1845 274 808 271 806 273 812 278 805 275 805 274 1840 279 1844 275 809 281 1836 272 806 274 812 278 805 274 1842 277 802 277 44956 279 1842 277 804 275 802 277 808 271 811 279 1838 281 798 271 814 276 1844 275 806 273 1841 278 1845 274 1846 273 808 271 1843 276 44959 275 1845 274 807 272 805 275 811 279 804 275 805 274 1839 280 1844 275 808 271 1845 274 805 274 811 279 804 275 1841 278 801 278 44955 280 1841 278 802 277 801 278 807 272 810 280 1837 271 807 272 813 277 1843 276 805 274 1839 280 1843 276 1845 274 807 272 1842 277 +POWER RAW F:38000 DC:33 881 909 1750 928 875 927 876 921 872 929 874 927 876 918 875 930 873 1815 874 924 1745 937 876 88694 880 922 1747 933 880 914 879 926 877 922 871 927 876 927 876 920 873 1818 871 929 1740 934 879 +POWER RAW F:38000 DC:33 509 1717 504 629 512 631 510 627 504 633 508 633 508 1713 508 1719 512 1713 508 625 505 637 504 633 508 629 512 629 512 623 508 1719 512 626 505 628 513 631 510 627 514 623 507 632 509 1713 508 632 509 1716 505 1715 506 1724 507 1716 505 1719 512 1715 506 +POWER RAW F:38000 DC:33 506 493 505 4059 505 5051 501 506 502 4065 499 511 497 4063 501 5058 504 504 504 4060 504 5052 500 507 501 4066 498 5056 506 5042 500 515 503 119614 504 505 503 4065 499 5051 501 511 497 4069 505 499 499 4072 502 5050 502 506 502 4066 498 5053 499 512 506 4060 504 5044 498 5061 501 508 500 +POWER RAW F:38000 DC:33 8887 4470 532 1738 513 1708 533 1708 533 577 533 576 534 569 531 582 538 1705 536 571 539 1707 534 571 539 571 539 570 540 1699 532 581 539 568 532 575 535 576 534 571 539 571 539 569 541 1698 533 1717 534 1708 533 1710 531 1716 535 1706 535 1711 540 1705 536 567 533 580 540 567 533 39042 8915 2231 530 94849 8917 2256 535 +POWER RAW F:38000 DC:33 8313 4161 515 1574 514 1571 507 569 510 562 507 563 506 562 507 568 511 562 507 1580 508 1577 511 1582 506 567 513 1575 513 554 505 571 509 564 505 22604 513 1573 505 1589 509 563 506 564 505 562 507 569 511 562 507 563 506 1579 509 1584 514 1576 512 558 511 1574 514 562 507 565 515 556 513 22593 514 1581 507 1583 505 564 505 563 506 570 510 563 506 564 505 562 507 1586 512 1578 510 1577 511 557 512 1581 507 566 514 556 513 555 514 +POWER RAW F:38000 DC:33 8735 4383 558 573 557 550 560 568 562 544 566 1722 560 540 560 1732 560 544 566 1719 563 1701 560 1723 559 1704 557 574 556 1699 562 574 556 1703 559 1727 565 1698 563 1721 561 546 564 1723 559 541 559 577 564 541 559 571 560 548 562 565 566 1697 565 567 564 1693 558 1733 559 1701 560 39926 8754 2247 565 92341 8758 2243 589 +POWER RAW F:38000 DC:33 3298 3336 821 2506 825 881 820 2505 826 2529 823 856 825 2524 817 866 825 2528 813 2513 818 888 813 862 819 887 814 865 826 2522 820 864 827 2526 815 861 820 887 814 2510 821 885 816 863 818 2531 821 2512 819 2559 793 32401 3298 3349 818 2507 824 882 819 2509 822 2527 814 868 823 2530 821 855 826 2531 821 2504 827 879 822 857 824 875 816 867 824 2529 823 854 827 2530 821 853 817 889 822 2506 825 873 818 866 825 2527 814 2513 818 2564 788 +POWER RAW F:38000 DC:33 8840 4439 532 566 534 566 534 1668 532 1674 536 1669 531 562 538 566 534 563 537 1667 533 567 533 563 537 563 537 562 538 1662 538 1671 529 568 532 565 535 566 534 1668 532 1674 536 1669 531 562 538 1672 528 1675 536 1668 532 1675 535 559 531 1676 534 565 535 558 532 1678 532 565 535 562 538 563 537 1665 535 565 535 1670 530 1669 531 572 538 1666 534 1669 531 1676 534 22777 8858 4447 535 92577 8858 4413 538 +POWER RAW F:38000 DC:33 289 2112 261 2109 295 2101 262 918 294 912 259 915 297 2098 265 916 296 909 262 2107 297 905 266 913 289 918 263 910 292 909 262 918 294 24789 263 2106 298 2098 265 2110 294 913 258 916 296 905 266 2108 296 911 260 914 288 2107 266 914 298 908 263 911 291 910 261 919 293 913 258 +POWER RAW F:38000 DC:33 8898 4453 569 578 573 577 574 571 570 1745 567 1747 565 1743 569 583 568 579 572 1740 572 1744 568 1742 570 579 572 576 575 568 573 1746 566 1746 566 580 571 1745 567 577 574 576 575 1739 573 569 572 581 570 577 574 1738 574 576 575 1735 567 1748 574 574 567 1742 570 1748 574 1737 575 41005 8876 2261 571 93850 8898 2264 568 +POWER RAW F:38000 DC:33 3215 1637 410 430 405 439 406 1242 408 435 410 1242 408 428 407 440 405 435 410 1240 410 1243 407 431 404 440 405 437 408 1238 402 1254 406 434 401 439 406 438 407 431 404 440 405 437 408 428 407 439 406 434 401 439 406 438 407 1241 409 434 401 441 404 432 403 444 401 1249 401 439 406 438 407 1241 409 434 401 441 404 433 402 444 401 1249 401 439 406 1248 402 436 409 434 401 441 404 433 402 444 401 439 406 45471 3239 1614 403 435 400 444 401 1250 400 437 408 1248 402 438 407 433 402 442 403 1245 405 1248 423 420 405 431 404 443 402 1248 402 1248 422 421 404 435 400 443 402 440 405 431 404 443 402 438 407 433 402 442 403 435 400 443 402 1250 400 436 399 447 408 432 403 438 407 1246 404 434 401 443 402 1250 400 436 399 447 408 432 403 437 408 1246 404 434 401 1253 407 434 401 436 399 447 408 432 403 437 408 436 399 +POWER RAW F:38000 DC:33 7928 3948 504 515 503 518 500 1583 505 516 502 1584 504 510 508 516 502 516 502 3952 510 1579 509 507 501 1587 501 519 510 1571 507 518 500 517 501 517 501 23073 7931 3943 509 514 504 515 503 1578 500 524 505 1580 508 510 508 514 504 511 507 3951 511 1576 502 513 505 1586 502 515 503 1582 506 515 503 513 505 516 502 +POWER RAW F:38000 DC:33 8837 4464 538 610 531 619 532 613 538 1748 534 1750 532 611 540 613 538 609 532 615 536 614 537 608 533 1753 539 1745 537 606 535 618 533 614 537 609 532 619 532 613 538 611 540 609 532 611 540 1748 534 1749 533 1750 532 1754 538 1743 539 1747 535 1750 532 1747 535 618 533 613 538 44105 8864 2224 537 93399 8912 2202 538 +POWER RAW F:38000 DC:33 492 4975 496 4993 498 498 500 4056 498 504 494 4055 499 4963 497 532 496 4031 492 4996 495 502 496 4060 494 4972 499 4990 491 506 492 4063 491 511 497 4052 492 4970 490 539 500 4027 496 103358 500 4961 500 4995 496 505 493 4056 498 499 499 4057 497 4969 491 533 496 4026 497 4997 494 508 490 4059 495 4967 494 5001 490 511 497 4053 491 505 493 4063 491 4975 496 528 490 4032 491 +POWER RAW F:38000 DC:33 2357 610 1183 592 1191 614 1179 595 1188 618 584 613 1180 593 588 613 1190 612 590 605 587 613 589 605 587 25398 2355 623 1180 591 1181 627 1186 589 1183 618 584 616 1187 587 584 614 1189 615 587 605 587 615 587 609 593 +POWER RAW F:38000 DC:33 3425 3482 848 2607 846 2639 845 2608 846 2639 845 2612 852 2624 850 2613 851 911 851 885 847 919 843 891 851 915 847 890 852 907 845 897 845 917 845 891 851 915 847 887 845 2639 845 2612 852 2625 849 2613 851 2630 844 34282 3455 3478 852 2601 852 2633 851 2605 848 2629 845 2617 847 2633 851 2604 849 917 845 890 852 913 849 889 843 915 847 896 846 916 846 890 852 914 848 885 847 919 843 895 847 2630 844 2617 847 2634 850 2605 848 2636 848 +POWER RAW F:38000 DC:33 500 500 498 4066 498 5058 504 502 506 4061 503 508 500 4060 504 5055 497 5055 497 511 497 4071 503 5047 505 507 501 4065 499 5049 503 512 496 124314 501 508 500 4067 507 5043 499 513 505 4060 504 501 497 4073 501 5052 500 5052 500 512 496 4066 498 5058 504 506 502 4058 506 5053 499 509 499 +POWER RAW F:38000 DC:33 176 7763 174 8817 169 10842 544 1955 541 967 540 1952 544 959 538 972 546 962 545 1947 538 1952 544 967 540 1955 541 964 543 1947 539 972 546 1949 547 7873 170 7746 170 10350 175 11811 543 960 537 1961 535 972 535 970 537 965 542 1956 540 1956 540 965 542 1947 539 973 534 1960 536 969 538 1952 534 +POWER RAW F:38000 DC:33 2570 2682 1189 1208 1186 2665 1186 1217 1187 2668 1183 1215 1179 2671 1190 2695 1186 1187 1187 2692 1179 2671 1190 1213 1181 1193 1191 1207 1187 2663 1188 1215 1179 2676 1185 46941 2563 2685 1186 1191 1183 2698 1184 1188 1186 2691 1180 1197 1187 2694 1187 2666 1185 1210 1184 2674 1187 2695 1186 1185 1189 1206 1188 1189 1185 2696 1186 1186 1187 2689 1182 +POWER RAW F:38000 DC:33 873 916 1773 906 877 925 878 919 874 928 875 925 878 1806 1770 914 879 1809 870 928 1772 88684 870 926 1774 908 875 926 877 917 876 929 874 925 878 1809 1777 905 877 1808 871 930 1770 +POWER RAW F:38000 DC:33 874 906 877 912 1767 904 879 908 874 918 875 915 878 907 875 920 873 1795 874 914 1775 897 875 88704 879 914 868 922 1767 897 875 919 874 915 878 911 872 920 873 914 879 1792 877 914 1775 889 873 +POWER RAW F:38000 DC:33 3325 1560 406 444 401 453 402 1226 404 449 406 1226 404 443 402 454 401 449 406 1224 406 1228 402 446 409 444 401 451 404 1223 407 1230 410 440 405 445 410 443 402 446 409 444 401 451 404 442 403 453 402 448 407 443 402 451 404 1224 406 448 407 444 401 445 410 446 409 1221 409 442 403 1231 409 439 406 1227 403 450 405 441 404 452 403 1227 403 448 407 446 409 439 406 447 408 444 401 445 400 456 410 440 405 52348 3320 1553 403 445 400 454 401 1230 400 447 408 1228 402 449 406 444 401 452 403 1225 405 1229 431 421 404 442 403 454 401 1229 401 1229 431 423 402 446 399 455 400 451 404 442 403 453 402 448 407 443 402 451 404 444 401 452 403 1229 401 445 400 457 398 451 404 446 399 1235 405 443 402 1232 408 444 401 1225 405 452 403 447 398 452 403 1231 399 449 406 447 408 443 402 444 401 456 399 450 405 445 400 453 402 +POWER RAW F:38000 DC:33 990 915 980 909 986 924 981 2829 981 934 981 2823 987 923 982 2828 982 933 982 906 989 33895 989 907 988 927 988 900 985 2841 979 915 980 2851 980 909 986 2840 980 914 981 934 981 +POWER RAW F:38000 DC:33 821 5754 848 2490 841 2492 819 2524 817 5726 845 2492 839 5727 844 5757 845 5727 854 2483 848 +POWER RAW F:38000 DC:33 5092 1621 406 2599 406 2598 407 2605 1653 1616 411 2619 1609 1606 1654 1618 409 2623 382 2600 405 +POWER RAW F:38000 DC:33 8879 4446 566 1747 565 584 567 1744 568 581 570 1744 568 574 567 586 565 582 569 578 563 1753 570 575 566 1749 563 585 566 1743 569 1749 563 1748 564 582 569 1747 565 580 571 578 573 1741 571 572 569 584 567 580 571 1741 571 578 573 1738 564 1751 572 577 564 1744 568 1750 572 1740 572 41007 8906 2257 565 93855 8872 2265 567 +POWER RAW F:38000 DC:33 1144 1010 6795 26754 1151 997 6798 +POWER RAW F:38000 DC:33 1144 1009 1120 1006 1143 1991 1116 26758 1146 1006 1123 1003 1146 1988 1119 +POWER RAW F:38000 DC:33 170 46238 169 +POWER RAW F:38000 DC:33 8906 4165 572 1672 569 1678 563 640 572 637 565 643 569 633 569 643 569 1674 567 639 563 1684 567 637 565 1681 570 1675 566 1673 568 1681 570 636 566 640 572 637 565 639 563 1684 567 640 572 630 572 640 572 634 568 1675 566 1681 570 1670 571 638 564 1681 570 1669 572 1678 563 1680 571 40485 8898 2252 570 85621 8955 2194 567 +POWER RAW F:38000 DC:33 446 1191 449 1194 446 1195 445 1204 446 1200 1316 459 447 1193 447 1202 448 1197 443 1201 449 1191 449 34491 443 1204 446 1197 443 1198 442 1207 443 1202 1314 436 440 1201 449 1199 441 1205 445 1198 442 1199 441 +POWER RAW F:38000 DC:33 4268 4327 522 1593 516 1603 516 1597 522 519 520 520 519 515 514 531 518 520 519 519 520 521 518 519 520 1597 522 1595 514 1597 522 1599 520 1595 514 524 515 1604 515 521 518 523 516 524 515 519 520 525 514 524 515 1599 520 522 517 1596 513 1605 514 1602 517 1595 514 1607 522 1592 516 40481 8748 2187 523 93986 8721 2189 521 +POWER RAW F:38000 DC:33 247 3006 244 153 178 1007 251 117 637 597 381 678 218 156 175 529 382 679 217 157 174 24963 247 3038 252 117 219 994 249 119 217 483 250 117 173 531 278 779 173 167 169 569 383 679 217 156 175 126538 246 3039 251 118 218 995 247 120 195 504 249 118 172 532 277 780 172 168 178 560 382 680 216 157 174 +POWER RAW F:38000 DC:33 8872 4454 568 579 572 578 573 572 569 581 570 1744 568 575 566 587 564 582 569 1743 569 1747 565 1745 567 1748 564 584 567 1741 571 1747 565 1747 565 1747 565 1751 571 1739 563 1752 570 578 563 1745 567 1751 572 1741 571 575 566 585 566 578 573 577 564 1750 573 571 570 583 568 579 572 41007 8905 2258 574 93846 8871 2266 566 +POWER RAW F:38000 DC:33 4278 4318 521 517 522 520 519 517 522 520 519 521 518 516 513 531 518 520 519 1595 514 1605 514 1599 520 1598 521 1595 513 1598 521 1600 519 1596 513 1602 517 1601 518 1595 514 1604 515 525 514 520 519 526 513 525 514 524 515 527 522 513 516 526 513 1603 516 1595 514 1607 522 1593 516 40481 8749 2186 524 93985 8722 2189 521 +POWER RAW F:38000 DC:33 2746 8423 2744 19607 2746 19601 2742 8431 2745 8424 2742 19608 2745 8419 2747 19608 2745 19607 2746 8422 2744 +POWER RAW F:38000 DC:33 170 6683 174 4889 175 10382 372 849 821 2498 176 10378 264 2479 842 2492 839 2475 846 2483 838 2481 840 2495 836 2477 844 845 846 37009 172 6681 176 4888 175 10381 373 848 924 2395 844 2490 174 10383 248 2492 172 10386 245 2495 169 +POWER RAW F:38000 DC:33 8898 4453 569 578 573 577 574 1737 565 584 567 582 569 574 567 1751 572 1741 571 1741 571 1744 568 576 575 1741 571 1743 569 1739 573 579 572 575 566 581 570 580 571 574 567 1748 575 1739 573 570 571 582 569 578 573 1739 573 1742 570 1740 572 577 574 575 566 1742 570 1749 574 1738 574 41006 8875 2262 570 93850 8907 2256 566 +POWER RAW F:38000 DC:33 8872 4454 568 1745 567 1749 563 1746 566 584 567 1747 565 1743 569 583 568 579 572 575 566 584 567 578 563 1752 571 578 563 580 571 1747 565 1747 565 581 570 1746 566 578 573 577 564 1751 572 571 570 583 568 579 572 1740 572 578 563 1747 565 1750 573 576 565 1743 569 1749 563 1749 563 41017 8906 2257 565 93855 8872 2265 567 +POWER RAW F:38000 DC:33 179 2644 178 8174 170 2646 176 8181 173 2648 174 8177 177 2640 172 5419 174 5413 170 2649 173 2644 178 2646 176 2646 176 5409 174 28831 174 2651 171 8183 171 2648 174 8174 170 2655 177 8177 177 2642 170 5412 171 5420 173 2649 173 2646 176 2640 172 2653 169 5419 174 +POWER RAW F:38000 DC:33 174 2648 174 8178 176 2640 171 8185 169 2653 169 8182 172 2645 177 2647 557 2264 558 5027 174 5410 173 5418 175 5413 170 28837 168 2649 173 8184 170 2652 170 8181 173 2643 169 8188 176 2646 176 2643 168 2648 174 5417 176 5411 172 5413 170 5413 170 +POWER RAW F:38000 DC:33 178 706 266 139 268 137 173 173 198 234 178 126768 175 299 169 86 275 130 267 138 172 230 177 +POWER RAW F:38000 DC:33 554 1922 584 3809 582 3782 578 3821 580 1920 555 1941 544 1922 574 +POWER RAW F:38000 DC:33 476 1470 465 3479 474 3469 474 3477 475 1467 468 1471 474 27473 472 1474 472 3475 467 3478 475 3468 474 1471 475 1468 467 +POWER RAW F:38000 DC:33 301 2188 236 2169 235 2205 230 1009 234 1070 183 1064 179 2198 206 1046 207 1069 173 2207 207 1042 211 1062 201 1043 210 1032 231 1005 237 1039 234 1006 236 +POWER RAW F:38000 DC:33 8872 4453 570 1744 568 582 569 1741 571 1744 568 580 571 1738 564 1754 569 578 563 584 567 1749 563 581 570 580 571 1743 569 573 568 585 566 1746 566 580 571 580 571 1739 563 586 565 1749 563 579 572 582 569 577 564 1748 564 1752 571 574 567 1748 564 584 567 1742 570 1748 564 1747 565 41015 8898 2265 567 93853 8875 2262 570 +POWER RAW F:38000 DC:33 8904 4446 576 572 569 581 570 575 566 584 567 582 569 1739 573 579 572 575 566 1746 566 1750 572 1738 574 1741 571 1742 570 573 568 1750 572 1740 572 1740 572 578 573 572 569 581 570 1744 568 574 567 586 575 572 569 578 573 1742 570 1740 572 1743 569 579 572 1737 565 1753 570 1743 569 41010 8881 2257 565 93855 8903 2259 573 +POWER RAW F:38000 DC:33 8878 4448 564 584 567 583 568 577 564 586 565 584 567 1741 571 582 569 1743 569 1743 569 1746 566 1744 568 1747 565 1749 563 579 572 1747 565 581 570 1743 569 1746 566 578 573 1743 569 579 572 571 570 583 568 579 572 575 566 584 567 1743 569 581 570 1744 568 1740 572 1746 566 1746 566 41013 8898 2264 568 93853 8872 2265 567 +POWER RAW F:38000 DC:33 8900 4450 572 575 566 585 566 578 573 1743 569 579 572 1736 566 587 574 572 569 1743 569 1747 565 1745 567 582 569 1745 567 575 566 1753 570 1742 570 1742 570 1746 566 578 573 1742 570 578 573 570 571 582 569 578 573 574 567 583 568 1742 570 579 572 1742 570 1738 574 1744 568 1744 568 41012 8871 2266 566 93855 8903 2258 574 +POWER RAW F:38000 DC:33 8872 4454 568 1745 567 1749 563 1747 565 1750 562 1752 571 1737 565 1754 568 1743 569 578 563 587 564 581 570 580 571 577 564 579 572 581 570 576 565 1748 564 1751 572 1739 563 1752 571 1743 569 1739 563 590 571 575 566 581 570 580 571 574 567 583 568 580 571 572 569 1750 562 1749 563 41017 8905 2257 575 93846 8871 2266 566 +POWER RAW F:38000 DC:33 176 7764 173 11361 544 1951 545 1948 176 8815 171 2319 177 2322 174 2321 175 2318 178 2313 173 18281 170 7746 170 11369 536 1954 542 1957 539 969 538 1954 542 1949 536 1962 534 1960 174 2320 176 2315 170 2328 178 2317 168 +POWER RAW F:38000 DC:33 172 23035 176 2267 178 2285 170 2270 175 2288 177 11602 222 2218 216 2246 173 183 173 935 221 218 174 864 221 1250 171 1310 223 2219 216 2247 218 1244 223 216 176 869 170 1296 217 2239 216 1254 223 216 176 866 219 9127 169 7642 173 2284 171 2273 172 2290 175 2263 171 10143 178 10623 222 1245 222 217 175 1843 220 2226 219 1264 223 1237 174 183 178 952 219 2222 223 216 176 866 219 1249 172 9190 173 7637 178 2266 169 2286 169 2280 175 2284 171 10125 175 10622 224 215 177 868 216 2228 217 2238 171 1299 224 215 177 865 174 183 173 934 222 216 176 1848 215 1247 220 1265 222 762 170 +POWER RAW F:38000 DC:33 7410 1482 382 2742 375 2747 380 2751 1630 1535 400 2724 1657 1529 1629 1538 407 2720 407 2716 401 2722 4125 1549 376 2751 376 2748 379 2744 1626 1541 405 2723 1658 1530 1628 1531 404 2726 401 2726 401 2723 4124 1542 383 2747 380 2747 380 2745 1626 1534 401 2729 1652 1539 1629 1532 403 2719 408 2722 405 +POWER RAW F:38000 DC:33 4277 4319 520 518 521 521 518 518 521 1597 522 1594 515 1597 522 1599 520 1594 515 1600 519 1600 519 1594 515 526 513 527 522 512 517 528 521 517 522 516 513 1605 514 522 517 525 514 525 514 521 518 526 513 525 514 1600 519 523 516 1597 522 1596 513 1603 516 1595 514 1607 522 1593 516 40481 8749 2186 524 93986 8721 2188 522 +POWER RAW F:38000 DC:33 1325 431 445 1199 1317 455 441 1207 443 1202 1294 457 449 1190 440 1209 441 1205 445 1198 1318 454 442 93237 1320 434 442 1201 1325 448 448 1200 440 1205 1291 460 446 1193 447 1202 448 1198 442 1201 1325 447 449 +POWER RAW F:38000 DC:33 8876 4450 572 575 566 585 566 578 573 577 564 585 566 577 564 589 572 574 567 1745 567 1749 563 1747 565 1750 562 1751 571 1737 565 1754 569 1743 569 1743 569 1747 565 579 572 1743 569 579 572 571 570 583 568 579 572 575 566 584 567 1743 569 581 570 1744 568 1740 572 1746 566 1746 566 41013 8898 2265 567 93853 8873 2264 568 +POWER RAW F:38000 DC:33 300 1791 297 744 295 743 296 751 298 745 294 747 302 736 293 1837 271 745 294 747 302 1793 295 752 297 1802 296 1801 297 742 297 1806 302 31592 296 1801 297 742 297 749 300 744 295 745 294 745 294 752 297 1829 269 746 293 745 294 1809 300 744 295 1802 296 1799 299 748 301 +POWER RAW F:38000 DC:33 178 2003 177 2899 177 1996 174 2908 168 2910 177 2000 170 2004 176 +POWER RAW F:38000 DC:33 8898 4173 564 642 570 1677 564 1677 564 645 567 640 572 631 571 641 571 635 567 639 563 1683 568 1673 568 641 571 636 566 637 565 647 565 641 571 634 568 642 570 1671 570 639 563 1682 569 632 570 643 569 636 566 1677 564 1683 568 636 566 1680 571 636 566 1674 567 1682 569 1674 567 40489 8904 2246 566 85626 8902 2248 564 +POWER RAW F:38000 DC:33 8897 4454 569 578 573 1743 569 576 565 1750 572 576 575 1733 569 584 567 1745 567 1745 567 583 568 1742 570 579 572 1742 570 573 568 1750 573 574 567 580 571 580 571 573 568 582 569 580 571 572 569 584 567 1744 568 1744 568 1748 575 1735 567 1749 574 1740 572 1736 566 1752 571 576 575 41005 8878 2259 563 93858 8901 2260 572 +POWER RAW F:38000 DC:33 8880 4446 566 1747 565 585 566 578 573 577 564 1750 573 571 570 1748 564 582 569 578 573 1743 569 1741 571 1744 568 580 571 1737 565 588 563 1749 563 583 568 582 569 576 565 1750 573 576 565 578 573 580 571 576 565 1747 565 1751 571 1738 564 586 565 1749 563 1745 567 1751 572 1741 571 41008 8905 2258 574 93846 8871 2266 566 +POWER RAW F:38000 DC:33 3892 3856 525 978 529 977 530 969 528 977 530 974 523 975 532 1924 531 971 526 1924 531 975 532 1916 529 976 531 1921 524 1947 508 1925 530 1920 525 1926 529 1925 530 970 527 1927 528 976 531 1915 530 978 529 1921 1033 9201 3871 3867 524 977 530 975 522 981 526 972 525 983 524 978 529 1921 524 982 525 1923 532 973 524 1928 527 971 526 1931 524 1950 505 1922 523 1931 524 1924 531 1923 532 972 525 1922 523 985 533 1918 527 975 532 1922 1032 +POWER RAW F:38000 DC:33 8900 4451 571 576 575 1742 570 1739 573 1742 570 578 573 1736 566 1752 570 576 575 1737 575 575 566 579 572 578 573 1741 571 571 570 583 568 1745 567 579 572 578 573 1738 574 575 566 1748 575 568 573 581 570 576 575 1737 565 1751 572 573 568 1747 576 573 568 1741 571 1747 565 1747 565 41014 8878 2260 562 93858 8901 2261 571 +POWER RAW F:38000 DC:33 875 904 1745 924 879 913 880 1786 873 919 874 917 1742 922 871 1802 877 912 1747 921 872 88714 880 907 1742 930 873 917 876 1788 871 924 879 910 1749 919 874 1798 871 916 1743 928 875 +POWER RAW F:38000 DC:33 4758 1543 403 2731 407 2726 402 2739 1601 1514 401 2760 1580 1530 1577 1540 406 2758 400 2708 1602 1535 400 2740 408 2729 409 2726 401 2731 1599 1520 405 2758 1572 1540 1578 1532 403 2737 431 2706 1604 1535 411 2722 405 2734 403 2734 404 2731 1599 1512 403 2764 1576 1539 1578 1533 402 2730 428 2712 1608 1534 402 +POWER RAW F:38000 DC:33 8873 4453 570 578 563 1753 570 575 566 1749 563 585 566 1742 570 583 568 1744 568 1744 568 582 569 1741 571 578 573 1741 571 572 569 1749 563 583 568 1745 567 1748 564 1746 566 583 568 581 570 1738 564 589 572 1740 572 574 567 584 567 577 564 1752 571 1743 569 573 568 1751 572 575 566 41014 8900 2263 569 93851 8878 2259 563 +POWER RAW F:38000 DC:33 171 313 176 798 337 133 600 232 170 126777 176 65 169 496 176 200 609 +POWER RAW F:38000 DC:33 500 527 491 4033 500 4986 495 510 498 4054 500 499 499 4048 496 4974 497 530 499 4026 497 4989 492 513 495 4057 497 4967 493 4992 499 506 492 4060 494 505 493 4054 500 98563 497 529 500 4025 498 4988 493 512 496 4056 498 501 497 4050 493 4976 495 532 497 4028 495 4991 500 505 493 4059 495 4969 491 4994 497 508 490 4062 492 507 491 4056 498 +POWER RAW F:38000 DC:33 879 901 871 1796 1770 903 869 917 876 916 877 913 880 906 877 918 875 914 879 1788 1768 1784 875 87826 871 921 872 1797 1769 897 875 919 874 915 878 910 873 920 873 914 879 913 870 1800 1776 1767 871 +POWER RAW F:38000 DC:33 874 905 1774 894 878 914 879 908 875 917 876 915 878 907 876 919 874 1793 876 913 1777 895 878 88703 872 920 1769 901 872 913 870 925 878 910 873 916 877 916 877 910 873 1798 871 919 1770 894 878 +POWER RAW F:38000 DC:33 3339 1714 415 445 420 1283 418 440 415 448 418 444 422 435 420 446 420 440 415 445 421 443 412 445 421 443 412 449 416 1279 412 455 421 439 416 443 412 452 414 444 411 452 414 1287 414 442 413 453 413 1287 414 446 419 444 422 437 418 445 421 441 414 442 413 452 414 447 419 1281 420 443 412 1285 416 1287 414 1287 414 1282 419 447 419 441 414 1286 415 448 418 1280 421 1282 419 443 412 1283 418 448 418 1283 418 73871 3336 1694 414 444 411 1291 410 452 414 442 413 453 413 448 418 442 413 450 416 443 412 450 416 447 419 437 418 448 418 1282 419 441 414 449 417 442 413 449 417 446 420 436 419 1287 414 446 420 440 415 1288 413 445 410 453 413 449 417 439 416 450 416 445 421 439 416 447 419 1279 412 451 415 1287 414 1282 419 1287 414 1285 416 444 411 453 413 1285 416 447 419 1283 418 1278 413 453 413 1287 414 446 419 1284 417 +POWER RAW F:38000 DC:33 4411 4332 558 1660 561 596 565 612 559 597 564 617 565 585 566 620 561 591 560 620 561 595 566 611 560 597 564 1653 558 592 559 627 565 589 562 617 564 1630 560 617 564 592 559 22591 4439 4322 558 1639 561 618 563 590 561 622 560 592 559 624 557 597 564 612 559 600 561 618 563 590 561 622 559 1628 562 621 561 594 567 609 562 597 564 1652 559 595 566 617 564 +POWER RAW F:38000 DC:33 3444 1767 413 487 419 1274 417 481 415 1277 414 488 418 1267 414 492 414 1276 415 484 412 1282 419 478 418 1275 416 1276 415 480 416 1280 421 479 417 1272 419 1275 416 1272 419 1274 417 484 412 484 412 493 413 1277 414 485 421 1273 418 479 417 486 420 1271 420 476 420 486 420 479 417 482 414 1280 411 1276 415 488 418 1273 418 478 418 488 418 481 415 1275 416 487 419 478 418 485 411 1280 421 475 421 1275 416 1273 418 69071 3439 1759 441 456 440 1253 438 463 443 1243 438 468 438 1251 440 460 446 1247 444 454 442 1251 440 461 445 1241 440 1256 445 455 441 1248 443 461 445 1242 439 1254 447 1245 446 1240 441 465 441 458 438 462 444 1249 442 456 440 1252 439 463 443 452 444 1252 439 461 445 454 442 461 445 452 444 1249 442 1250 441 454 442 1254 437 463 443 456 440 463 443 1245 446 456 440 462 444 451 445 1251 440 460 436 1253 438 1256 445 +POWER RAW F:38000 DC:33 8705 4317 583 682 581 688 585 678 585 1721 581 1722 580 681 582 690 583 682 581 1721 581 1725 587 1713 579 689 584 683 580 1718 584 1724 588 1714 588 677 586 683 580 683 580 1726 586 680 583 678 585 687 586 679 584 1718 584 1721 581 1719 583 685 588 1716 586 1713 579 1729 583 1719 583 41145 8706 2217 585 94686 8705 2217 584 +POWER RAW F:38000 DC:33 8888 4470 532 576 534 576 534 571 539 572 538 1706 535 568 532 581 529 578 532 1711 530 581 529 1711 530 1717 534 574 536 1703 538 575 535 572 538 1705 536 1711 530 1711 530 1716 535 1709 532 571 529 585 535 571 529 579 531 579 531 574 536 574 536 573 537 1701 530 1720 531 1712 529 39045 8912 2261 540 94838 8911 2235 536 +POWER RAW F:38000 DC:33 874 915 1774 904 879 923 870 1816 1770 1800 1776 904 879 1805 874 931 1769 909 874 88698 876 927 1773 904 879 922 871 1819 1767 1796 1770 914 879 1809 870 928 1772 910 873 +POWER RAW F:38000 DC:33 178 7753 174 2308 178 2284 171 2316 170 2298 177 10228 174 10724 223 1256 221 217 175 1868 169 2293 172 1327 216 1263 178 1316 217 2245 220 218 174 887 218 1261 170 10707 174 7752 175 2296 169 2314 171 2293 172 2307 179 10216 176 6265 174 10729 219 1258 219 1272 215 1268 173 2310 221 1255 222 217 175 877 172 +POWER RAW F:38000 DC:33 532 1692 559 561 529 574 567 559 531 566 564 555 535 1694 557 568 532 1691 560 560 530 573 557 568 532 565 565 555 535 567 563 1688 533 564 567 554 536 567 563 562 538 558 562 558 532 1697 565 561 539 1683 558 1689 532 1697 564 1687 534 1689 562 1684 537 +POWER RAW F:38000 DC:33 874 915 1774 904 879 923 870 927 876 1814 876 925 1775 900 872 1821 879 920 1769 909 874 88702 871 926 1774 907 876 925 878 917 876 1817 873 927 1773 905 878 1813 876 921 1769 912 871 +POWER RAW F:38000 DC:33 8884 4474 538 569 531 1716 535 570 530 580 530 1715 536 567 533 580 530 577 533 1710 531 1715 536 1705 536 1710 531 1714 537 1702 529 1720 531 1712 529 578 532 1715 536 1705 536 1710 531 577 533 570 530 584 536 571 529 1714 537 573 537 568 532 578 532 1713 538 1701 530 1719 532 1711 530 39044 8913 2260 531 94848 8907 2239 532 +POWER RAW F:38000 DC:33 446 1694 455 1706 453 1705 424 628 452 597 452 622 458 1673 456 625 455 594 455 1706 454 590 459 621 459 591 458 616 453 591 458 622 539 22750 459 1675 454 1733 427 1712 427 622 458 588 451 622 458 1681 458 618 451 595 454 1705 455 598 451 625 454 592 457 616 453 598 451 626 535 +POWER RAW F:38000 DC:33 3429 3445 875 2555 868 875 867 871 871 2560 873 868 874 2551 872 874 868 871 871 869 873 870 872 865 867 2565 868 873 869 2556 867 2567 866 874 868 2560 873 870 872 2555 868 2564 869 2586 847 2577 846 2589 844 870 872 32983 3470 3430 869 2559 874 868 874 867 875 2550 873 873 869 2559 874 865 867 877 875 862 870 873 869 872 870 2555 868 877 875 2554 869 2559 874 869 873 2554 869 873 869 2562 871 2553 870 2590 843 2586 847 2581 842 876 866 +POWER RAW F:38000 DC:33 8873 4452 571 1743 569 580 571 574 567 583 568 1746 566 1742 570 1748 564 582 569 578 563 1753 570 1740 572 1743 569 579 572 571 570 583 568 1744 568 579 572 578 573 572 569 1746 566 582 569 574 567 586 565 582 569 1743 569 1746 566 1744 568 581 570 1745 567 1741 571 1747 565 1746 566 41014 8898 2264 568 93853 8874 2263 569 +POWER RAW F:38000 DC:33 8902 4448 574 1739 573 1742 570 575 566 584 567 581 570 573 568 585 566 1746 566 580 571 580 571 1739 573 1742 570 1743 569 1739 573 1745 567 579 572 1741 571 1744 568 1742 570 1745 567 1747 565 1743 569 1749 573 1739 573 573 568 583 568 576 575 575 566 583 568 575 566 587 574 572 569 41011 8871 2266 566 93854 8902 2260 572 +POWER RAW F:38000 DC:33 4275 4320 519 520 519 523 516 520 519 1599 520 520 519 515 524 521 518 520 519 1595 524 1595 524 1588 520 521 518 1599 520 1591 517 1603 516 1599 520 1595 524 1594 525 1588 521 1597 522 518 521 513 526 519 520 518 521 517 522 520 519 517 522 519 520 1597 522 1589 519 1601 518 1597 522 40475 8724 2186 514 93995 8752 2183 516 +POWER RAW F:38000 DC:33 10380 4892 599 620 592 605 597 620 592 604 598 623 589 2081 598 627 595 2080 599 2101 598 2105 574 2099 590 2088 591 2111 599 591 590 2116 594 599 593 626 596 2082 597 619 593 2086 593 626 596 594 598 627 595 598 594 2106 593 604 598 2100 589 607 595 2107 593 2079 590 2116 594 2082 750 41149 8722 2109 590 94682 8727 2104 596 +POWER RAW F:38000 DC:33 8879 4446 566 1747 565 1751 571 573 568 582 569 580 571 571 570 584 567 1744 568 579 572 578 573 1737 565 1751 572 1742 570 1738 564 1754 568 578 573 574 567 584 567 577 564 1752 571 577 564 580 571 582 569 577 564 1748 564 1752 571 1739 563 587 564 1750 572 1736 566 1752 571 1742 570 41009 8903 2260 572 93848 8880 2257 565 +POWER RAW F:38000 DC:33 4271 4324 515 1600 519 1600 519 1594 515 1603 516 1601 518 1593 516 1605 514 1601 518 520 519 522 517 520 519 522 517 523 516 518 521 523 516 522 517 1598 521 1597 522 1591 518 1600 519 521 518 516 523 522 517 521 518 520 519 523 516 520 519 522 517 1599 520 1591 518 1603 516 1599 520 40477 8753 2183 516 93993 8724 2185 515 +POWER RAW F:38000 DC:33 7847 3931 470 1448 467 495 472 1443 472 490 467 1451 464 491 466 499 468 491 466 4413 467 1455 470 486 471 1449 466 495 472 1441 464 501 466 492 465 494 463 22093 7851 3934 467 1454 471 490 467 1446 469 496 471 1446 469 489 468 494 473 484 473 4410 470 1449 466 489 468 1455 470 489 468 1449 466 496 471 486 471 490 467 From cdfc420ddf28f2bf7ad25491869a89ad9eb8b1f8 Mon Sep 17 00:00:00 2001 From: Albert Kharisov Date: Tue, 21 Dec 2021 18:10:34 +0400 Subject: [PATCH 07/14] Replace Laptop animation text (#919) * Fix Laptop animation bubble * Correct new animation select --- .../desktop/scenes/desktop_scene_debug.c | 3 +- assets/compiled/assets_icons.c | 664 +++++++++--------- assets/compiled/assets_icons.h | 178 ++--- .../LaptopActive_128x52/frame_02.png | Bin 2220 -> 1550 bytes .../LaptopActive_128x52/frame_03.png | Bin 2213 -> 1546 bytes .../LaptopActive_128x52/frame_04.png | Bin 2213 -> 1546 bytes .../LaptopActive_128x52/frame_05.png | Bin 2200 -> 1560 bytes .../LaptopActive_128x52/frame_06.png | Bin 2196 -> 1552 bytes .../LaptopActive_128x52/frame_07.png | Bin 2200 -> 1560 bytes .../LaptopActive_128x52/frame_08.png | Bin 2196 -> 1552 bytes 10 files changed, 423 insertions(+), 422 deletions(-) diff --git a/applications/desktop/scenes/desktop_scene_debug.c b/applications/desktop/scenes/desktop_scene_debug.c index 9e347be2..ea89fed2 100644 --- a/applications/desktop/scenes/desktop_scene_debug.c +++ b/applications/desktop/scenes/desktop_scene_debug.c @@ -33,12 +33,14 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { case DesktopDebugEventDeed: dolphin_deed(dolphin, DolphinDeedIButtonEmulate); desktop_debug_get_dolphin_data(desktop->debug_view); + desktop_start_new_idle_animation(desktop->animation); consumed = true; break; case DesktopDebugEventWrongDeed: dolphin_deed(dolphin, DolphinDeedWrong); desktop_debug_get_dolphin_data(desktop->debug_view); + desktop_start_new_idle_animation(desktop->animation); consumed = true; break; @@ -59,5 +61,4 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { void desktop_scene_debug_on_exit(void* context) { Desktop* desktop = (Desktop*)context; desktop_debug_reset_screen_idx(desktop->debug_view); - desktop_start_new_idle_animation(desktop->animation); } diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index a9ed30fa..ec424f6f 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -2,12 +2,12 @@ #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 *_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 *_I_Certification2_119x30[] = {_I_Certification2_119x30_0}; +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 *_I_Certification1_103x23[] = {_I_Certification1_103x23_0}; + const uint8_t _A_BadBattery_128x51_0[] = {0x01,0x00,0xa4,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0x1f,0xf4,0x78,0x1d,0x9e,0x0c,0x1d,0xc4,0x1f,0x93,0x08,0x05,0x00,0x1f,0x91,0xf0,0x10,0xc0,0x81,0xd5,0x80,0x8d,0x80,0xc6,0x18,0x0f,0xb0,0x19,0x46,0x01,0xf5,0xc0,0x21,0x20,0x02,0x49,0x87,0x20,0x04,0xa5,0xc0,0x27,0x16,0x00,0x2a,0x42,0x00,0xa8,0x1b,0x31,0x18,0xc7,0x22,0xf9,0x9c,0xa4,0xe3,0xdd,0xdc,0x98,0xc6,0x41,0xed,0xa0,0xda,0x69,0x72,0x94,0x8a,0x4d,0x4a,0x95,0x25,0x07,0xa7,0x82,0x01,0x98,0xaa,0x6f,0x7a,0xe0,0xf2,0xbd,0x49,0xe0,0x11,0x00,0x79,0x7c,0x03,0xe3,0x16,0xc2,0xed,0x29,0x14,0xda,0xd4,0x2a,0x4b,0x01,0x07,0xac,0x72,0x2b,0xb9,0xca,0x4c,0x29,0x5d,0x4b,0x8c,0x64,0x1e,0x9d,0x88,0x09,0xed,0xd3,0xa2,0x0f,0x19,0xfc,0x03,0xff,0x0f,0x45,0xcc,0x43,0x01,0x7f,0xf0,0x40,0x4f,0x4a,0x00,0x48,0x87,0xc3,0x66,0x04,0x1a,0x80,0x3e,0xb3,0x1f,0x75,0x03,0x83,0xd6,0x19,0x5f,0x1c,0x2c,0x70,0x1e,0xd0,0x8b,0x60,0x10,0x6f,0xc0,0x82,0x81,0x03,0xda,0x71,0x38,0x79,0x8c,0x0c,0x10,0x5c,0xeb,0x8f,0x9e,0x24,0xd5,0x3b,0x04,0x38,0x5c,0x2b,0x43,0x5e,0x0e,0x48,0x1e,0x81,0xc3,0x07,0xb4,0x79,0xea,0xd0,0x49,0x80,0x3c,0xed,0x5d,0x20,0xf9,0xab,0xcb,0x01,0x07,0xfe,0x28,0x0b,0x99,0x51,0xd1,0x03,0xd9,0xdc,0x3f,0x7f,0xfc,0x1c,0xe6,0x80,0x01,0x9f,0x83,0xca,0x61,0x80,0xf0,0xc3,0xe1,0x80,0xf5,0xc0,0x48,0x41,0xe5,0x1c,0xb0,0x0f,0xc5,0xcc,0x60,0x02,0xe0,0x48,0x01,0x07,0x30,0x2c,0x08,0x3d,0xac,0x00,0xf4,0xc0,0x13,0x84,0x1e,0xd3,0x00,0x7a,0x3c,0x06,0x01,0x18,0x07,0xac,0x62,0x40,0x7a,0x35,0x88,0xa1,0x90,0x00,0x50,0xc1,0x80,0xa4,0xd6,0x08,0x0f,0x58,0x36,0x00,0x1e,0x48,0xd3,0x83,0x03,0xd6,0x07,0x80,0xb0,0x37,0x4b,0xf0,0xa2,0x20,0x7a,0xc0,0x70,0x18,0x02,0x98,0x83,0x46,0x07,0xf1,0x78,0x98,0x3d,0x38,0x10,0x14,0xd0,0xbe,0xc6,0x1e,0xf4,0x11,0x7b,0x1a,0xc4,0x74,0x57,0x83,0x11,0x80,0x0e,0x05,0x80,0xd0,0x1e,0xc5,0x2c,0x4d,0x32,0x07,0xb4,0x80,0x1e,0x6c,0xb1,0x28,0x31,0xbc,0x81,0xeb,0x00,0x9e,0x03,0xd2,0x08,0x0f,0x51,0xe9,0x60,0x27,0xe1,0xf6,0x34,0x8f,0xc3,0xfe,0x90,0x24,0x30,0xc7,0xc0,0x85,0x0e,0xa0,0x48,0x15,0x23,0x18,0x17,0x10,0x00,0xbf,0xc4,0x21,0x3e,0x08,0x08,0x4f,0xc2,0xc4,0x12,0xe2,0xff,0x20,0xf7,0x01,0xb9,0x33,0x06,0x3c,0xec,0x60,0x80,0x8c,0x8b,0x01,0x10,0x80,0x59,0x13,0x8c,0x44,0x38,0x00,}; const uint8_t _A_BadBattery_128x51_1[] = {0x01,0x00,0xc3,0x01,0x80,0x7c,0x38,0x30,0xf0,0x7e,0x46,0x20,0x13,0x80,0x75,0xe0,0x03,0xa3,0x20,0x07,0xdf,0x82,0x0c,0x03,0x18,0x08,0x3e,0x83,0x87,0x03,0x07,0xd4,0xc0,0x06,0x42,0x22,0x00,0x44,0x40,0x06,0x50,0xc0,0x7d,0x42,0x00,0x6c,0x0f,0xb3,0x90,0x83,0xf4,0x66,0x60,0x07,0x82,0x03,0xe2,0xe0,0x0f,0x85,0x02,0x91,0x54,0x1e,0x73,0xc8,0x04,0x72,0x2f,0x99,0xca,0x4e,0x3d,0xdd,0xc9,0x8c,0x64,0x1e,0xda,0x0d,0xa6,0x97,0x29,0x48,0xa4,0xd4,0xa9,0x52,0x50,0x78,0xf0,0x18,0x03,0x76,0x80,0x66,0x2a,0x9b,0xde,0xb8,0x3c,0xaf,0x52,0x70,0x78,0xf8,0x23,0xfc,0x0f,0xfc,0x0f,0x41,0x16,0xc2,0xed,0x29,0x14,0xda,0xd4,0x2a,0x4b,0x01,0x82,0x7f,0x25,0x97,0x88,0x04,0x0a,0x39,0x15,0xdc,0xe5,0x26,0x14,0xae,0xa5,0xc6,0x32,0x0f,0x1f,0x34,0xf4,0xa8,0xa0,0x02,0xa0,0x3f,0x44,0x14,0x3c,0x38,0xba,0x82,0x01,0xe2,0x1a,0x28,0x14,0x6d,0x41,0x90,0x28,0x74,0x3a,0x01,0xf0,0x8f,0x83,0xeb,0x31,0x03,0x80,0x7f,0x01,0xf7,0xf0,0x01,0x8f,0xfa,0x7e,0x08,0x28,0xe0,0x3d,0x80,0x65,0xff,0x90,0x82,0x18,0x0c,0xbc,0x00,0xf1,0xc0,0x39,0xd7,0x1f,0x3c,0x48,0x1e,0xbf,0x08,0x39,0x7c,0xd7,0x83,0x92,0x07,0xb7,0xf2,0x01,0xf8,0x61,0x88,0x3c,0xe3,0xc0,0xf5,0x9f,0x10,0x07,0xfe,0x0f,0x2b,0x57,0x48,0x3e,0xb8,0x08,0x3e,0x03,0xff,0x81,0x80,0xc0,0x39,0x95,0x1d,0x14,0x4b,0x80,0x06,0x10,0x78,0xf8,0x20,0x3e,0x04,0x10,0x81,0x85,0x58,0x76,0x00,0x78,0xc1,0xa0,0x12,0x08,0x05,0xe8,0x4c,0x60,0xf3,0x98,0x01,0x85,0xb4,0x6b,0x11,0x3e,0xb4,0x60,0x3a,0x20,0xf2,0x20,0x08,0x0c,0x46,0x22,0x00,0x38,0x40,0x3c,0x61,0x80,0x51,0xf0,0x04,0xc8,0x70,0x20,0x03,0x86,0x09,0x8f,0xf1,0xff,0x0f,0x8e,0x01,0x58,0xb0,0x60,0x78,0xc6,0x0a,0x24,0xde,0x1e,0x03,0xf1,0xe0,0x13,0xcc,0x00,0xa8,0x6e,0x03,0x21,0x1f,0xac,0x0e,0xf1,0x00,0x9a,0x06,0x89,0x0c,0x33,0xe1,0x20,0x80,0x0e,0x02,0x0c,0x19,0xa0,0x1c,0xfc,0xf0,0x11,0xb0,0x83,0xd0,0x42,0x32,0x40,0x39,0xb4,0x46,0x60,0x2f,0x58,0x04,0x70,0x1e,0x90,0x81,0x91,0x13,0xd2,0x01,0x10,0x07,0xb4,0x01,0x26,0x40,0xf4,0xb2,0x01,0xcd,0xfc,0x44,0x04,0x4c,0x0c,0x42,0x88,0x05,0x1f,0xf7,0xfc,0x58,0x5e,0x04,0xfa,0x03,0xc7,0x90,0x9b,0x18,0x1b,0x4c,0xd8,0x86,0x37,0x28,0x86,0x21,0x36,0x47,0xc4,0x8e,0x00,0xca,0x20,0x36,0x18,0x42,0x0c,0x70,0x25,0xb4,0x18,0x19,0xd4,0x79,0x90,0x88,0x1d,0xc3,0xcc,0xbc,0x51,0x81,0x58,0x11,0x23,0x18,0x83,0x46,0x27,0x80,0xf5,0xfc,0x35,0x8e,0x09,0x10,0xce,0x1b,0x08,0x00,0xbe,0x08,0xfd,0xf0,0x84,0x60,0x0d,}; const uint8_t *_A_BadBattery_128x51[] = {_A_BadBattery_128x51_0,_A_BadBattery_128x51_1}; @@ -64,13 +64,13 @@ const uint8_t _A_Knife_128x51_1[] = {0x01,0x00,0x8c,0x01,0x00,0x78,0x02,0xbf,0x9 const uint8_t *_A_Knife_128x51[] = {_A_Knife_128x51_0,_A_Knife_128x51_1}; const uint8_t _A_LaptopActive_128x52_0[] = {0x01,0x00,0x3c,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x40,0x82,0xc8,0x05,0x07,0xf4,0x1e,0x1d,0xf8,0x7c,0x42,0xa4,0x0f,0x28,0x05,0x44,0x1e,0x30,0xa0,0x28,0xe8,0x03,0xe2,0x0f,0x22,0x30,0x80,0x06,0xa4,0x44,0x18,0x54,0x0b,0x01,0xa0,0x0f,0x8a,0xcc,0x81,0xe7,0x54,0x0b,0x8c,0x2a,0x0d,0xc1,0xd4,0x5d,0x69,0x00,0xf2,0xa0,0x03,0xcb,0xd0,0x07,0x1c,0x56,0xab,0x55,0xa4,0xbb,0xf2,0x20,0x17,0xc0,0x79,0xf8,0x2e,0xcc,0x81,0x85,0x74,0xf2,0xda,0xab,0x80,0x3c,0x70,0x40,0xf3,0xcc,0x7b,0x6e,0x30,0x0a,0x56,0x0a,0x05,0xa7,0x07,0x94,0xe6,0x02,0x0f,0x28,0x87,0xef,0x79,0x01,0xc5,0x60,0x60,0x5a,0xaf,0xfd,0xff,0x01,0x7c,0x2b,0x09,0x48,0xae,0xf1,0xe8,0x1c,0xa8,0x1e,0x3a,0x61,0x58,0xe0,0x3d,0xc0,0xf3,0xa0,0x5b,0xb1,0xe4,0xf1,0x07,0x8e,0x84,0x3e,0x5f,0xe8,0x17,0x02,0x1e,0x9f,0x1f,0xc5,0x3c,0x9e,0x3c,0x2c,0x36,0x80,0x3e,0x40,0xf1,0x98,0x28,0x0b,0xef,0x37,0x07,0x8e,0x92,0x95,0xa0,0x81,0x83,0xc4,0x7e,0x30,0xc4,0x80,0xf0,0x3f,0xd3,0xb0,0x78,0xea,0x21,0x5a,0x0b,0xf1,0x6c,0x4b,0xe3,0x03,0x07,0x8f,0x83,0xe3,0x1f,0x07,0x8e,0x42,0x25,0xa0,0xb9,0x03,0xc7,0xfd,0xe0,0x58,0x16,0x03,0xde,0x43,0x10,0x7b,0x23,0xc6,0x01,0x3e,0x52,0x0f,0xf9,0x5e,0x30,0xac,0x44,0x8b,0x41,0xf2,0xa0,0xc0,0x20,0x30,0x1c,0x04,0x86,0x01,0xc8,0xe3,0xf3,0xe0,0x70,0xa8,0x44,0x84,0x3e,0x34,0x26,0x59,0x58,0x3f,0x9f,0xf3,0xb8,0xdd,0xe0,0xc0,0xf4,0xbd,0x03,0xca,0x30,0xfb,0x13,0xb8,0xdf,0xe0,0xa2,0xf3,0xb9,0x52,0x81,0xe5,0x06,0x7d,0x89,0x80,0x6f,0xd0,0x18,0x55,0x22,0x48,0x0f,0x4c,0x04,0x04,0x1e,0x7b,0xe2,0x78,0x83,0xce,0x54,0x0a,0x1b,0xc1,0x48,0x40,0x83,0xf0,0xbf,0x83,0xe0,0x00,0x20,0xf3,0x9f,0x83,0xc6,0xa1,0x14,0x07,0xab,0x7c,0xa0,0x1f,0x8e,0xf9,0xbc,0x51,0xe7,0x1a,0x05,0x97,0x00,0x1e,0x7f,0xf2,0x78,0xe8,0x00,0x23,0xff,0x5b,0x09,0xfc,0x80,0x64,0x82,0x11,0x78,0xf0,0x20,0xee,0xf1,0x75,0x11,0xec,0x41,0xe6,0x3f,0x20,0x28,0x87,0xc5,0x8c,0x20,0x81,0x67,0x08,0x00,0x7f,0xc5,0xf1,0xfd,0x29,0x47,0x7f,0xc0,0x84,0x70,0x07,0xa2,0x0f,0x41,0xf8,0xa1,0x4b,0x01,0x20,0x82,0xcc,0x0d,0xa2,0x33,0x3f,0xcf,0xfe,0x06,0x12,0x10,0x00,0xce,0xe0,0xb0,0x88,0x04,0x08,0x1e,0x60,0xa1,0x83,0xa2,0x4e,0x49,0x03,0x65,0x8c,0x10,0x24,0x22,0x81,0xfb,0x83,0xd6,0x79,0x03,0x01,0x8c,0x20,0x1e,0x71,0x3f,0x80,0x3d,0x55,0x45,0x10,0x07,0x97,0x02,0x33,0x90,0x83,0x0b,0xd0,0x1e,0x30,0x69,0x03,0xf8,0xe3,0x9b,0x00,0x29,0x11,0x8d,0x42,0x29,0x61,0x0f,0x94,0x7f,0xa0,0x0a,0x20,0x00,0xb6,0x08,0x0e,0x93,0xff,0x04,0xbc,0x3c,0x60,0x02,0x3f,0x89,0x80,0x40,0x43,0x20,0x90,0x46,0x01,0xed,0xe0,0x0f,0xa0,0xd1,0x00,0x1e,0x00,0xf0,0x07,0x80,0x08,}; -const uint8_t _A_LaptopActive_128x52_1[] = {0x01,0x00,0x19,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xe2,0xa1,0x80,0xba,0xd2,0x01,0xe5,0x40,0x80,0x62,0x16,0xc3,0x00,0x8e,0x06,0x08,0x3e,0x3c,0x88,0x05,0xf0,0x1e,0x54,0x83,0x91,0x48,0x87,0xe8,0x0f,0x1c,0x10,0x3c,0xf0,0x95,0x48,0xcc,0x0a,0xe1,0x92,0xa4,0x83,0xce,0x73,0x01,0x17,0x96,0x1e,0xa9,0x25,0x8f,0x52,0x2a,0x54,0xac,0x07,0xfe,0xff,0x80,0xbe,0x40,0xb0,0x04,0xf1,0xc2,0xf9,0x27,0x92,0x2a,0x47,0x7a,0xd6,0x09,0x1a,0x06,0x03,0xdc,0x0f,0x18,0x7e,0x20,0x5e,0x30,0x50,0x78,0xd4,0xab,0x01,0xf3,0xff,0x40,0xac,0x11,0x02,0x78,0xd5,0xe7,0x31,0xcf,0xe6,0x4a,0x97,0x95,0x0f,0x90,0x3c,0x63,0x0f,0x82,0x30,0x16,0x10,0xbe,0x50,0x30,0x78,0x8f,0xc6,0x0d,0x20,0x06,0x8b,0xcd,0x70,0x17,0xe2,0xd8,0xce,0x70,0x30,0x19,0x02,0xd0,0x81,0xeb,0x72,0x07,0x8f,0xfa,0xc1,0x00,0x9f,0xa9,0x08,0x1f,0x08,0xf1,0xe0,0x67,0xdd,0xcf,0xff,0xf9,0x50,0x60,0x10,0x18,0x0f,0xc2,0x1f,0x00,0xe4,0x71,0xf9,0xf0,0x38,0x54,0x22,0x43,0xa0,0xb9,0x50,0x84,0xa5,0xfc,0x0c,0x15,0xfe,0xef,0x06,0x07,0xa5,0xe8,0x1e,0x5f,0xf8,0x2b,0x8c,0xaf,0xf0,0x58,0x56,0x22,0x44,0x0f,0x1a,0x50,0x28,0x78,0x1f,0xf2,0xf1,0x78,0x2f,0xd0,0x18,0x55,0x22,0x48,0x0f,0x4f,0x85,0xfc,0x1e,0x7b,0xe8,0x00,0x3d,0x25,0x40,0xa1,0xbe,0x7e,0x0d,0xc4,0x14,0x10,0x7c,0x31,0x04,0x1e,0x73,0xf0,0x78,0xd4,0x22,0x80,0xf4,0x20,0x08,0x0c,0xbf,0x1d,0xf3,0x78,0xe4,0x22,0x40,0xf1,0x8d,0x25,0x4c,0x1e,0x62,0x41,0x85,0x68,0x00,0x23,0xff,0x8f,0x82,0xc9,0x46,0x28,0x33,0x17,0x8f,0x02,0x0f,0xa0,0x80,0x44,0x03,0x44,0x0f,0x41,0xf9,0x01,0x44,0x3e,0x2a,0xa1,0x9f,0xf8,0x01,0x42,0x00,0x1f,0xf1,0x7c,0x7f,0x4a,0x51,0xdf,0xf0,0x21,0x1c,0x02,0x68,0x83,0xd0,0x7e,0x28,0x52,0xc0,0x48,0x20,0xb3,0x06,0x80,0xc6,0x01,0xe5,0xf9,0xff,0xc0,0xc2,0x42,0x00,0x19,0xdc,0x16,0x11,0x00,0x81,0x03,0xcc,0x14,0x30,0x70,0x29,0x40,0x24,0x90,0x38,0x24,0x02,0x08,0x12,0x11,0x40,0xfd,0xc1,0xeb,0x3c,0x81,0x80,0xc6,0x10,0x0f,0x38,0x9f,0xc0,0x1e,0xaa,0xa2,0x88,0x03,0xcb,0x81,0x19,0xc8,0x41,0x85,0xe8,0x0f,0x18,0x34,0x80,0x64,0x29,0x21,0x8e,0x6c,0x00,0xa4,0x46,0x35,0x08,0xa5,0x84,0x3e,0x51,0xfe,0x80,0x28,0x80,0x02,0xd8,0x20,0x3a,0x25,0x06,0x5e,0x1e,0x30,0x01,0x1f,0xc4,0xc0,0x20,0x21,0x90,0x48,0x0e,0x86,0x00,0x3f,0x00,0x7d,0x06,0x88,0x00,0xf0,0x07,0x80,0x3c,0x00,0x40,}; -const uint8_t _A_LaptopActive_128x52_2[] = {0x01,0x00,0x17,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xe2,0xa1,0x80,0xba,0xd2,0x01,0xe5,0x40,0x80,0x62,0x16,0xc3,0x00,0x8e,0x06,0x08,0x3e,0x3c,0x88,0x05,0xf0,0x1e,0x54,0x83,0x91,0x48,0x87,0xe8,0x0f,0x1c,0x10,0x3c,0xf0,0x95,0x48,0xcc,0x0a,0xe1,0x92,0xa4,0x83,0xce,0x73,0x01,0x17,0x96,0x1e,0xa9,0x25,0x8f,0x52,0x2a,0x54,0xac,0x07,0xfe,0xff,0x80,0xbe,0x40,0xb0,0x04,0xf1,0xc2,0xf9,0x27,0x92,0x2a,0x47,0x7a,0xd6,0x09,0x1a,0x06,0x03,0xdc,0x0f,0x2c,0x40,0xbc,0x60,0xa0,0xf1,0xa9,0x56,0x03,0xe7,0xfe,0x81,0x70,0x21,0xe4,0xf1,0xab,0xce,0x63,0x9f,0xcc,0x95,0x2f,0x2a,0x1f,0x20,0x78,0xcc,0x22,0x07,0xf1,0x30,0x16,0x10,0xbe,0x50,0x30,0x78,0x8f,0xc6,0x19,0x20,0x06,0x8b,0xcd,0x70,0x17,0xe2,0xd8,0x97,0xc6,0x07,0x20,0x5a,0x10,0x3d,0x6e,0x40,0xf1,0xff,0x78,0x12,0xe2,0xa4,0x20,0x7c,0x23,0xc6,0x01,0xbe,0x77,0x3f,0xff,0xe5,0x41,0x80,0x40,0x60,0x38,0x09,0x0c,0x03,0x91,0xc7,0xe7,0xc0,0xe1,0x50,0x89,0x0e,0x82,0xe5,0x42,0x12,0x95,0x83,0xf8,0x18,0x1b,0xfd,0xde,0x0c,0x0f,0x4b,0xd0,0x3c,0xa3,0x06,0xc2,0xa0,0x5f,0xe0,0xb0,0xac,0x44,0x88,0x1e,0x34,0xa0,0x79,0x41,0x8b,0xc5,0xe0,0xbf,0x40,0x61,0x54,0x89,0x20,0x3d,0x30,0x10,0x10,0x79,0xef,0xa0,0x00,0xf4,0x95,0x02,0x86,0xf0,0x52,0x10,0x20,0xfc,0x2f,0xe0,0xf8,0x00,0x08,0x3c,0xe7,0xe0,0xf1,0xa8,0x45,0x01,0xea,0xdf,0x10,0x00,0xfe,0x3b,0xe6,0xf1,0xc8,0x44,0x81,0xe3,0x1a,0x05,0x97,0x00,0x1e,0x7f,0xf2,0x78,0xe8,0x00,0x23,0xff,0x8f,0x9f,0xcc,0x06,0x48,0x21,0x17,0x8f,0x02,0x0f,0xa0,0x80,0x44,0x01,0x64,0xb3,0x10,0x79,0x0f,0xc8,0x0a,0x21,0xf1,0x87,0xc0,0x01,0x03,0x20,0x07,0x97,0xf8,0xbe,0x3f,0xa5,0x28,0xef,0xf8,0x10,0x8e,0x00,0xf4,0x41,0xe8,0x3f,0x14,0x29,0x60,0x24,0x10,0x59,0x81,0xb4,0x46,0x67,0xf9,0xff,0xc0,0xc2,0x42,0x00,0x19,0xdc,0x16,0x11,0x00,0x81,0x03,0xcc,0x14,0x30,0x74,0x49,0xc9,0x20,0x6c,0xb1,0x82,0x04,0x84,0x50,0x3f,0x70,0x7a,0xcf,0x20,0x60,0x31,0x84,0x03,0xce,0x27,0xf0,0x07,0xaa,0xa8,0xa2,0x00,0xf2,0xe0,0x46,0x72,0x10,0x61,0x7a,0x03,0xc6,0x0d,0x20,0x7f,0x1c,0x73,0x60,0x05,0x22,0x31,0xa8,0x45,0x2c,0x21,0xf2,0x8f,0xf4,0x01,0x44,0x00,0x16,0xc1,0x01,0xd2,0x7f,0xe0,0x97,0x87,0x8c,0x00,0x47,0xf1,0x30,0x08,0x08,0x64,0x12,0x08,0xc0,0x3d,0xbc,0x01,0xf4,0x1a,0x20,0x03,0xc0,0x1e,0x00,0xf0,0x01,0x00,}; -const uint8_t _A_LaptopActive_128x52_3[] = {0x01,0x00,0x17,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xe2,0xa1,0x80,0xba,0xd2,0x01,0xe5,0x40,0x80,0x62,0x16,0xc3,0x00,0x8e,0x06,0x08,0x3e,0x3c,0x88,0x05,0xf0,0x1e,0x54,0x83,0x91,0x48,0x87,0xe8,0x0f,0x1c,0x10,0x3c,0xf0,0x95,0x48,0xcc,0x0a,0xe1,0x92,0xa4,0x83,0xce,0x73,0x01,0x17,0x96,0x1e,0xa9,0x25,0x8f,0x52,0x2a,0x54,0xac,0x07,0xfe,0xff,0x80,0xbe,0x40,0xb0,0x04,0xf1,0xc2,0xf9,0x27,0x92,0x2a,0x47,0x7a,0xd6,0x09,0x1a,0x06,0x03,0xdc,0x0f,0x2c,0x40,0xbc,0x60,0xa0,0xf1,0xa9,0x56,0x03,0xe7,0xfe,0x81,0x70,0x21,0xe4,0xf1,0xab,0xce,0x63,0x9f,0xcc,0x95,0x2f,0x2a,0x1f,0x20,0x78,0xcc,0x22,0x07,0xf1,0x30,0x16,0x10,0xbe,0x50,0x30,0x78,0x8f,0xc6,0x19,0x20,0x06,0x8b,0xcd,0x70,0x17,0xe2,0xd8,0x97,0xc6,0x07,0x20,0x5a,0x10,0x3d,0x6e,0x40,0xf1,0xff,0x78,0x12,0xe2,0xa4,0x20,0x7c,0x23,0xc6,0x01,0xbe,0x77,0x3f,0xff,0xe5,0x41,0x80,0x40,0x60,0x38,0x09,0x0c,0x03,0x91,0xc7,0xe7,0xc0,0xe1,0x50,0x89,0x0e,0x82,0xe5,0x42,0x12,0x95,0x83,0xf8,0x18,0x1b,0xfd,0xde,0x0c,0x0f,0x4b,0xd0,0x3c,0xa3,0x06,0xc2,0xa0,0x5f,0xe0,0xb0,0xac,0x44,0x88,0x1e,0x34,0xa0,0x79,0x41,0x8b,0xc5,0xe0,0xbf,0x40,0x61,0x54,0x89,0x20,0x3d,0x30,0x10,0x10,0x79,0xef,0xa0,0x00,0xf4,0x95,0x02,0x86,0xf0,0x52,0x10,0x20,0xfc,0x2f,0xe0,0xf8,0x00,0x08,0x3c,0xe7,0xe0,0xf1,0xa8,0x45,0x01,0xea,0xdf,0x10,0x00,0xfe,0x3b,0xe6,0xf1,0xc8,0x44,0x81,0xe3,0x1a,0x05,0x97,0x00,0x1e,0x7f,0xf2,0x78,0xe8,0x00,0x23,0xff,0x8f,0x9f,0xcc,0x06,0x48,0x21,0x17,0x8f,0x02,0x0f,0xa0,0x80,0x44,0x01,0x64,0xb3,0x10,0x79,0x0f,0xc8,0x0a,0x21,0xf1,0x87,0xc0,0x01,0x03,0x20,0x07,0x97,0xf8,0xbe,0x3f,0xa5,0x28,0xef,0xf8,0x10,0x8e,0x00,0xf4,0x41,0xe8,0x3f,0x14,0x29,0x60,0x24,0x10,0x59,0x81,0xb4,0x46,0x67,0xf9,0xff,0xc0,0xc2,0x42,0x00,0x19,0xdc,0x16,0x11,0x00,0x81,0x03,0xcc,0x14,0x30,0x74,0x49,0xc9,0x20,0x6c,0xb1,0x82,0x04,0x84,0x50,0x3f,0x70,0x7a,0xcf,0x20,0x60,0x31,0x84,0x03,0xce,0x27,0xf0,0x07,0xaa,0xa8,0xa2,0x00,0xf2,0xe0,0x46,0x72,0x10,0x61,0x7a,0x03,0xc6,0x0d,0x20,0x7f,0x1c,0x73,0x60,0x05,0x22,0x31,0xa8,0x45,0x2c,0x21,0xf2,0x8f,0xf4,0x01,0x44,0x00,0x16,0xc1,0x01,0xd2,0x7f,0xe0,0x97,0x87,0x8c,0x00,0x47,0xf1,0x30,0x08,0x08,0x64,0x12,0x08,0xc0,0x3d,0xbc,0x01,0xf4,0x1a,0x20,0x03,0xc0,0x1e,0x00,0xf0,0x01,0x00,}; -const uint8_t _A_LaptopActive_128x52_4[] = {0x01,0x00,0x0b,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x3f,0x5c,0x88,0x05,0xf0,0x1f,0x77,0x00,0x78,0xe0,0x81,0xe7,0x80,0xa4,0xd5,0x78,0x53,0x1e,0x3e,0xe7,0x08,0x0f,0x29,0xcc,0x04,0x1e,0x54,0x0a,0x55,0x56,0x85,0x4a,0xc1,0x69,0x30,0x5f,0xfb,0xfe,0x02,0xf9,0x02,0xc0,0x03,0xca,0xd1,0x4e,0xe1,0x52,0x41,0xe3,0x81,0x15,0x8e,0x03,0xdc,0x0f,0x18,0x78,0x3c,0x6b,0x41,0xf3,0xda,0x07,0xcf,0xfd,0x02,0xb0,0x44,0x21,0x19,0x5a,0x4e,0x57,0x87,0x31,0xc1,0x6a,0x30,0x81,0xf2,0x07,0x8c,0x61,0xf0,0x40,0x01,0x4c,0x11,0x7c,0x60,0x60,0xf1,0x1f,0x8c,0x1a,0x40,0xe1,0x2c,0x02,0x20,0x80,0x83,0x7e,0x2d,0x8c,0xe7,0x03,0x01,0x90,0x06,0xcc,0xfe,0x97,0x20,0x78,0xff,0xac,0x10,0x09,0xf8,0x6c,0xc1,0xee,0x8f,0x1e,0x06,0x7d,0xdc,0xff,0xff,0x95,0x06,0x01,0x01,0x80,0xfc,0x21,0xf0,0x0e,0x47,0x1f,0x9f,0x03,0x85,0x42,0x24,0x3a,0x0b,0x95,0x08,0x4a,0x5f,0xc0,0xc1,0x5f,0xee,0xf0,0x60,0x7a,0x5e,0x81,0xe5,0xff,0x82,0xb8,0xca,0xff,0x05,0x85,0x62,0x24,0x40,0xf1,0xa5,0x02,0x87,0x81,0xff,0x2f,0x17,0x82,0xfd,0x01,0x85,0x52,0x24,0x80,0xf4,0xf8,0x5f,0xc1,0xe7,0xbe,0x80,0x03,0xd2,0x54,0x0a,0x1b,0xe7,0xe0,0xdc,0x41,0x41,0x07,0xc6,0x03,0xfe,0x0f,0x39,0xf8,0x3c,0x6a,0x11,0x40,0x7a,0x10,0x04,0x06,0x5f,0x8e,0xf9,0xbc,0x72,0x11,0x20,0x78,0xc6,0x92,0xa6,0x0f,0x31,0x20,0xc2,0xb4,0x00,0x11,0xff,0xc7,0xc1,0x64,0xa3,0x14,0x19,0x8b,0xc7,0x81,0x07,0xd0,0x40,0x22,0x01,0xa2,0x07,0xa0,0xfc,0x80,0xa2,0x1f,0x15,0x50,0xcf,0xfc,0x00,0xa1,0x00,0x0f,0xf8,0xbe,0x3f,0xa5,0x28,0xef,0xf8,0x10,0x8e,0x01,0x34,0x41,0xe8,0x3f,0x14,0x29,0x60,0x24,0x10,0x59,0x83,0x40,0x63,0x00,0xf2,0xfc,0xff,0xe0,0x61,0x21,0x00,0x0c,0xee,0x0b,0x08,0x80,0x40,0x81,0xe6,0x0a,0x18,0x38,0x14,0xa0,0x12,0x48,0x1c,0x12,0x01,0x04,0x09,0x08,0xa0,0x7e,0xe0,0xf5,0x9e,0x40,0xc0,0x63,0x08,0x07,0x9c,0x4f,0xe0,0x0f,0x55,0x51,0x44,0x01,0xe5,0xc0,0x8c,0xe4,0x20,0xc2,0xf4,0x07,0x8c,0x1a,0x40,0x32,0x14,0x90,0xc7,0x36,0x00,0x52,0x23,0x1a,0x84,0x52,0xc2,0x1f,0x28,0xff,0x40,0x14,0x40,0x01,0x6c,0x10,0x1d,0x12,0x83,0x2f,0x0f,0x18,0x00,0x8f,0xe2,0x60,0x10,0x10,0xc8,0x24,0x07,0x43,0x00,0x1f,0x80,0x3e,0x83,0x44,0x00,0x78,0x03,0xc0,0x1e,0x00,0x20,}; -const uint8_t _A_LaptopActive_128x52_5[] = {0x01,0x00,0x04,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x3f,0x5c,0x88,0x05,0xf0,0x1f,0x77,0x00,0x78,0xe0,0x81,0xe7,0x80,0xa4,0xd5,0x78,0x53,0x1e,0x3e,0xe7,0x08,0x0f,0x29,0xcc,0x04,0x1e,0x54,0x0a,0x55,0x56,0x85,0x4a,0xc1,0x69,0x30,0x5f,0xfb,0xfe,0x02,0xf9,0x02,0xc0,0x03,0xca,0xd1,0x4e,0xe1,0x52,0x41,0xe3,0x81,0x15,0x8e,0x03,0xdc,0x0f,0x4a,0xd0,0x7c,0xf6,0x81,0xf3,0xff,0x40,0xb8,0x10,0xf8,0x46,0x56,0x93,0x95,0xe1,0xcc,0x70,0x5a,0x8c,0x20,0x7c,0x81,0xe3,0x30,0x88,0x17,0xcd,0x30,0x45,0xf1,0x81,0x83,0xc4,0x7e,0x30,0xc9,0x03,0x84,0xb0,0x08,0x82,0x02,0x0d,0xf8,0xb6,0x25,0xf1,0x81,0xc8,0x03,0x66,0x7f,0x4b,0x90,0x3c,0x7f,0xde,0x05,0x80,0x86,0xcc,0x1e,0xe8,0xf1,0x80,0x6f,0x9d,0xcf,0xff,0xf9,0x50,0x60,0x10,0x18,0x0e,0x02,0x43,0x00,0xe4,0x71,0xf9,0xf0,0x38,0x54,0x22,0x43,0xa0,0xb9,0x50,0x84,0xa5,0x60,0xfe,0x06,0x06,0xff,0x77,0x83,0x03,0xd2,0xf4,0x0f,0x28,0xc1,0x78,0xa8,0x17,0xf8,0x2c,0x2b,0x11,0x22,0x07,0x8d,0x28,0x1e,0x50,0x62,0xf1,0x78,0x2f,0xd0,0x18,0x55,0x22,0x48,0x0f,0x43,0xc8,0x83,0xcf,0x7d,0x00,0x07,0xa4,0xa8,0x14,0x37,0x82,0x90,0x81,0x07,0xe1,0x7f,0x07,0xc0,0x00,0x41,0xe7,0x3f,0x07,0x8d,0x42,0x28,0x0f,0x56,0xf8,0x80,0x07,0xf1,0xdf,0x37,0x8e,0x42,0x24,0x0f,0x18,0xd0,0x2c,0xb8,0x00,0xf3,0xff,0x93,0xc7,0x40,0x01,0x1f,0xfc,0x7c,0xfe,0x60,0x32,0x41,0x08,0xbc,0x78,0x10,0x7d,0x04,0x02,0x20,0x0b,0x25,0x98,0x83,0xc8,0x7e,0x40,0x51,0x0f,0x8c,0x3e,0x00,0x08,0x19,0x00,0x3c,0xbf,0xc5,0xf1,0xfd,0x29,0x47,0x7f,0xc0,0x84,0x70,0x07,0xa2,0x0f,0x41,0xf8,0xa1,0x4b,0x01,0x20,0x82,0xcc,0x0d,0xa2,0x33,0x3f,0xcf,0xfe,0x06,0x12,0x10,0x00,0xce,0xe0,0xb0,0x88,0x04,0x08,0x1e,0x60,0xa1,0x83,0xa2,0x4e,0x49,0x03,0x65,0x8c,0x10,0x24,0x22,0x81,0xfb,0x83,0xd6,0x79,0x03,0x01,0x8c,0x20,0x1e,0x71,0x3f,0x80,0x3d,0x55,0x45,0x10,0x07,0x97,0x02,0x33,0x90,0x83,0x0b,0xd0,0x1e,0x30,0x69,0x03,0xf8,0xe3,0x9b,0x00,0x29,0x11,0x8d,0x42,0x29,0x61,0x0f,0x94,0x7f,0xa0,0x0a,0x20,0x00,0xb6,0x08,0x0e,0x93,0xff,0x04,0xbc,0x3c,0x60,0x02,0x3f,0x89,0x80,0x40,0x43,0x20,0x90,0x46,0x01,0xed,0xe0,0x0f,0xa0,0xd1,0x00,0x1e,0x00,0xf0,0x07,0x80,0x08,}; -const uint8_t _A_LaptopActive_128x52_6[] = {0x01,0x00,0x0b,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x3f,0x5c,0x88,0x05,0xf0,0x1f,0x77,0x00,0x78,0xe0,0x81,0xe7,0x80,0xa4,0xd5,0x78,0x53,0x1e,0x3e,0xe7,0x08,0x0f,0x29,0xcc,0x04,0x1e,0x54,0x0a,0x55,0x56,0x85,0x4a,0xc1,0x69,0x30,0x5f,0xfb,0xfe,0x02,0xf9,0x02,0xc0,0x03,0xca,0xd1,0x4e,0xe1,0x52,0x41,0xe3,0x81,0x15,0x8e,0x03,0xdc,0x0f,0x18,0x78,0x3c,0x6b,0x41,0xf3,0xda,0x07,0xcf,0xfd,0x02,0xb0,0x44,0x21,0x19,0x5a,0x4e,0x57,0x87,0x31,0xc1,0x6a,0x30,0x81,0xf2,0x07,0x8c,0x61,0xf0,0x40,0x01,0x4c,0x11,0x7c,0x60,0x60,0xf1,0x1f,0x8c,0x1a,0x40,0xe1,0x2c,0x02,0x20,0x80,0x83,0x7e,0x2d,0x8c,0xe7,0x03,0x01,0x90,0x06,0xcc,0xfe,0x97,0x20,0x78,0xff,0xac,0x10,0x09,0xf8,0x6c,0xc1,0xee,0x8f,0x1e,0x06,0x7d,0xdc,0xff,0xff,0x95,0x06,0x01,0x01,0x80,0xfc,0x21,0xf0,0x0e,0x47,0x1f,0x9f,0x03,0x85,0x42,0x24,0x3a,0x0b,0x95,0x08,0x4a,0x5f,0xc0,0xc1,0x5f,0xee,0xf0,0x60,0x7a,0x5e,0x81,0xe5,0xff,0x82,0xb8,0xca,0xff,0x05,0x85,0x62,0x24,0x40,0xf1,0xa5,0x02,0x87,0x81,0xff,0x2f,0x17,0x82,0xfd,0x01,0x85,0x52,0x24,0x80,0xf4,0xf8,0x5f,0xc1,0xe7,0xbe,0x80,0x03,0xd2,0x54,0x0a,0x1b,0xe7,0xe0,0xdc,0x41,0x41,0x07,0xc6,0x03,0xfe,0x0f,0x39,0xf8,0x3c,0x6a,0x11,0x40,0x7a,0x10,0x04,0x06,0x5f,0x8e,0xf9,0xbc,0x72,0x11,0x20,0x78,0xc6,0x92,0xa6,0x0f,0x31,0x20,0xc2,0xb4,0x00,0x11,0xff,0xc7,0xc1,0x64,0xa3,0x14,0x19,0x8b,0xc7,0x81,0x07,0xd0,0x40,0x22,0x01,0xa2,0x07,0xa0,0xfc,0x80,0xa2,0x1f,0x15,0x50,0xcf,0xfc,0x00,0xa1,0x00,0x0f,0xf8,0xbe,0x3f,0xa5,0x28,0xef,0xf8,0x10,0x8e,0x01,0x34,0x41,0xe8,0x3f,0x14,0x29,0x60,0x24,0x10,0x59,0x83,0x40,0x63,0x00,0xf2,0xfc,0xff,0xe0,0x61,0x21,0x00,0x0c,0xee,0x0b,0x08,0x80,0x40,0x81,0xe6,0x0a,0x18,0x38,0x14,0xa0,0x12,0x48,0x1c,0x12,0x01,0x04,0x09,0x08,0xa0,0x7e,0xe0,0xf5,0x9e,0x40,0xc0,0x63,0x08,0x07,0x9c,0x4f,0xe0,0x0f,0x55,0x51,0x44,0x01,0xe5,0xc0,0x8c,0xe4,0x20,0xc2,0xf4,0x07,0x8c,0x1a,0x40,0x32,0x14,0x90,0xc7,0x36,0x00,0x52,0x23,0x1a,0x84,0x52,0xc2,0x1f,0x28,0xff,0x40,0x14,0x40,0x01,0x6c,0x10,0x1d,0x12,0x83,0x2f,0x0f,0x18,0x00,0x8f,0xe2,0x60,0x10,0x10,0xc8,0x24,0x07,0x43,0x00,0x1f,0x80,0x3e,0x83,0x44,0x00,0x78,0x03,0xc0,0x1e,0x00,0x20,}; -const uint8_t _A_LaptopActive_128x52_7[] = {0x01,0x00,0x04,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x3f,0x5c,0x88,0x05,0xf0,0x1f,0x77,0x00,0x78,0xe0,0x81,0xe7,0x80,0xa4,0xd5,0x78,0x53,0x1e,0x3e,0xe7,0x08,0x0f,0x29,0xcc,0x04,0x1e,0x54,0x0a,0x55,0x56,0x85,0x4a,0xc1,0x69,0x30,0x5f,0xfb,0xfe,0x02,0xf9,0x02,0xc0,0x03,0xca,0xd1,0x4e,0xe1,0x52,0x41,0xe3,0x81,0x15,0x8e,0x03,0xdc,0x0f,0x4a,0xd0,0x7c,0xf6,0x81,0xf3,0xff,0x40,0xb8,0x10,0xf8,0x46,0x56,0x93,0x95,0xe1,0xcc,0x70,0x5a,0x8c,0x20,0x7c,0x81,0xe3,0x30,0x88,0x17,0xcd,0x30,0x45,0xf1,0x81,0x83,0xc4,0x7e,0x30,0xc9,0x03,0x84,0xb0,0x08,0x82,0x02,0x0d,0xf8,0xb6,0x25,0xf1,0x81,0xc8,0x03,0x66,0x7f,0x4b,0x90,0x3c,0x7f,0xde,0x05,0x80,0x86,0xcc,0x1e,0xe8,0xf1,0x80,0x6f,0x9d,0xcf,0xff,0xf9,0x50,0x60,0x10,0x18,0x0e,0x02,0x43,0x00,0xe4,0x71,0xf9,0xf0,0x38,0x54,0x22,0x43,0xa0,0xb9,0x50,0x84,0xa5,0x60,0xfe,0x06,0x06,0xff,0x77,0x83,0x03,0xd2,0xf4,0x0f,0x28,0xc1,0x78,0xa8,0x17,0xf8,0x2c,0x2b,0x11,0x22,0x07,0x8d,0x28,0x1e,0x50,0x62,0xf1,0x78,0x2f,0xd0,0x18,0x55,0x22,0x48,0x0f,0x43,0xc8,0x83,0xcf,0x7d,0x00,0x07,0xa4,0xa8,0x14,0x37,0x82,0x90,0x81,0x07,0xe1,0x7f,0x07,0xc0,0x00,0x41,0xe7,0x3f,0x07,0x8d,0x42,0x28,0x0f,0x56,0xf8,0x80,0x07,0xf1,0xdf,0x37,0x8e,0x42,0x24,0x0f,0x18,0xd0,0x2c,0xb8,0x00,0xf3,0xff,0x93,0xc7,0x40,0x01,0x1f,0xfc,0x7c,0xfe,0x60,0x32,0x41,0x08,0xbc,0x78,0x10,0x7d,0x04,0x02,0x20,0x0b,0x25,0x98,0x83,0xc8,0x7e,0x40,0x51,0x0f,0x8c,0x3e,0x00,0x08,0x19,0x00,0x3c,0xbf,0xc5,0xf1,0xfd,0x29,0x47,0x7f,0xc0,0x84,0x70,0x07,0xa2,0x0f,0x41,0xf8,0xa1,0x4b,0x01,0x20,0x82,0xcc,0x0d,0xa2,0x33,0x3f,0xcf,0xfe,0x06,0x12,0x10,0x00,0xce,0xe0,0xb0,0x88,0x04,0x08,0x1e,0x60,0xa1,0x83,0xa2,0x4e,0x49,0x03,0x65,0x8c,0x10,0x24,0x22,0x81,0xfb,0x83,0xd6,0x79,0x03,0x01,0x8c,0x20,0x1e,0x71,0x3f,0x80,0x3d,0x55,0x45,0x10,0x07,0x97,0x02,0x33,0x90,0x83,0x0b,0xd0,0x1e,0x30,0x69,0x03,0xf8,0xe3,0x9b,0x00,0x29,0x11,0x8d,0x42,0x29,0x61,0x0f,0x94,0x7f,0xa0,0x0a,0x20,0x00,0xb6,0x08,0x0e,0x93,0xff,0x04,0xbc,0x3c,0x60,0x02,0x3f,0x89,0x80,0x40,0x43,0x20,0x90,0x46,0x01,0xed,0xe0,0x0f,0xa0,0xd1,0x00,0x1e,0x00,0xf0,0x07,0x80,0x08,}; +const uint8_t _A_LaptopActive_128x52_1[] = {0x01,0x00,0x08,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x1e,0x30,0x20,0x30,0xe0,0x01,0xe5,0x81,0xbb,0xf2,0x20,0x17,0xc0,0x7d,0xdc,0x01,0xe3,0x82,0x07,0xa7,0x1e,0x4b,0xc3,0x8c,0xe7,0x36,0x38,0x30,0x79,0x4e,0x60,0x20,0xf3,0x94,0xe9,0x70,0x92,0x4a,0x24,0x2b,0x03,0xff,0xbf,0xe0,0x2f,0x90,0x21,0x48,0x83,0xcf,0x0f,0x24,0xe2,0x44,0xf0,0x22,0xb1,0xc0,0x7b,0x81,0xe3,0x0f,0x07,0x9e,0x00,0x3e,0x32,0x00,0xf9,0xff,0xa0,0x56,0x08,0x80,0x3c,0x79,0x31,0x9c,0x1c,0x63,0x09,0x19,0x0f,0x98,0x3c,0x63,0x0f,0x82,0x3f,0xb4,0x0c,0x1e,0x23,0xf1,0x83,0x48,0x1c,0x24,0x0f,0x5b,0xf1,0x6c,0x67,0x38,0x18,0x0c,0x81,0x68,0x40,0xf5,0xb9,0x03,0xc7,0xfd,0x60,0x80,0x4f,0xd4,0x84,0x0f,0x84,0x78,0xf0,0x33,0xee,0xe7,0xff,0xfc,0xa8,0x30,0x08,0x0c,0x07,0xe1,0x0f,0x80,0x72,0x38,0xfc,0xf8,0x1c,0x2a,0x11,0x21,0xd0,0x5c,0xa8,0x42,0x52,0xfe,0x06,0x0a,0xff,0x77,0x83,0x03,0xd2,0xf4,0x0f,0x2f,0xfc,0x15,0xc6,0x57,0xf8,0x2c,0x2b,0x11,0x22,0x07,0x8d,0x28,0x14,0x3c,0x0f,0xf9,0x78,0xbc,0x17,0xe8,0x0c,0x2a,0x91,0x24,0x07,0xa7,0xc2,0xfe,0x0f,0x3d,0xf4,0x00,0x1e,0x92,0xa0,0x50,0xdf,0x3f,0x06,0xe2,0x0a,0x08,0x3e,0x30,0x1f,0xf0,0x79,0xcf,0xc1,0xe3,0x50,0x8a,0x03,0xd0,0x80,0x20,0x32,0xfc,0x77,0xcd,0xe3,0x90,0x89,0x03,0xc6,0x34,0x95,0x30,0x79,0x89,0x06,0x15,0xa0,0x00,0x8f,0xfe,0x3e,0x0b,0x25,0x18,0xa0,0xcc,0x5e,0x3c,0x08,0x3e,0x82,0x01,0x10,0x0d,0x10,0x3d,0x07,0xe4,0x05,0x10,0xf8,0xaa,0x86,0x7f,0xe0,0x05,0x08,0x00,0x7f,0xc5,0xf1,0xfd,0x29,0x47,0x7f,0xc0,0x84,0x70,0x09,0xa2,0x0f,0x41,0xf8,0xa1,0x4b,0x01,0x20,0x82,0xcc,0x1a,0x03,0x18,0x07,0x97,0xe7,0xff,0x03,0x09,0x08,0x00,0x67,0x70,0x58,0x44,0x02,0x04,0x0f,0x30,0x50,0xc1,0xc0,0xa5,0x00,0x92,0x40,0xe0,0x90,0x08,0x20,0x48,0x45,0x03,0xf7,0x07,0xac,0xf2,0x06,0x03,0x18,0x40,0x3c,0xe2,0x7f,0x00,0x7a,0xaa,0x8a,0x20,0x0f,0x2e,0x04,0x67,0x21,0x06,0x17,0xa0,0x3c,0x60,0xd2,0x01,0x90,0xa4,0x86,0x39,0xb0,0x02,0x91,0x18,0xd4,0x22,0x96,0x10,0xf9,0x47,0xfa,0x00,0xa2,0x00,0x0b,0x60,0x80,0xe8,0x94,0x19,0x78,0x78,0xc0,0x04,0x7f,0x13,0x00,0x80,0x86,0x41,0x20,0x3a,0x18,0x00,0xfc,0x01,0xf4,0x1a,0x20,0x03,0xc0,0x1e,0x00,0xf0,0x01,0x00,}; +const uint8_t _A_LaptopActive_128x52_2[] = {0x01,0x00,0x01,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x1e,0x30,0x20,0x30,0xe0,0x01,0xe5,0x81,0xbb,0xf2,0x20,0x17,0xc0,0x7d,0xdc,0x01,0xe3,0x82,0x07,0xa7,0x1e,0x4b,0xc3,0x8c,0xe7,0x36,0x38,0x30,0x79,0x4e,0x60,0x20,0xf3,0x94,0xe9,0x70,0x92,0x4a,0x24,0x2b,0x03,0xff,0xbf,0xe0,0x2f,0x90,0x21,0x48,0x83,0xcf,0x0f,0x24,0xe2,0x44,0xf0,0x22,0xb1,0xc0,0x7b,0x81,0xed,0x80,0x0f,0x8c,0x80,0x3e,0x7f,0xe8,0x17,0x02,0x1e,0x0f,0x1e,0x4c,0x67,0x07,0x18,0xc2,0x46,0x43,0xe6,0x0f,0x19,0x84,0x40,0xff,0x10,0x30,0x78,0x8f,0xc6,0x19,0x20,0x70,0x90,0x3d,0x6f,0xc5,0xb1,0x2f,0x8c,0x0e,0x40,0xb4,0x20,0x7a,0xdc,0x81,0xe3,0xfe,0xf0,0x2c,0x05,0x48,0x40,0xf8,0x47,0x8c,0x03,0x7c,0xee,0x7f,0xff,0xca,0x83,0x00,0x80,0xc0,0x70,0x12,0x18,0x07,0x23,0x8f,0xcf,0x81,0xc2,0xa1,0x12,0x1d,0x05,0xca,0x84,0x25,0x2b,0x07,0xf0,0x30,0x37,0xfb,0xbc,0x18,0x1e,0x97,0xa0,0x79,0x46,0x0b,0xc5,0x40,0xbf,0xc1,0x61,0x58,0x89,0x10,0x3c,0x69,0x40,0xf2,0x83,0x17,0x8b,0xc1,0x7e,0x80,0xc2,0xa9,0x12,0x40,0x7a,0x60,0x20,0x20,0xf3,0xdf,0x40,0x01,0xe9,0x2a,0x05,0x0d,0xe0,0xa4,0x20,0x41,0xf8,0x5f,0xc1,0xf0,0x00,0x10,0x79,0xcf,0xc1,0xe3,0x50,0x8a,0x03,0xd5,0xbe,0x20,0x01,0xfc,0x77,0xcd,0xe3,0x90,0x89,0x03,0xc6,0x34,0x0b,0x2e,0x00,0x3c,0xff,0xe4,0xf1,0xd0,0x00,0x47,0xff,0x1f,0x3f,0x98,0x0c,0x90,0x42,0x2f,0x1e,0x04,0x1f,0x41,0x00,0x88,0x02,0xc9,0x66,0x20,0xf2,0x1f,0x90,0x14,0x43,0xe3,0x0f,0x80,0x02,0x06,0x40,0x0f,0x2f,0xf1,0x7c,0x7f,0x4a,0x51,0xdf,0xf0,0x21,0x1c,0x01,0xe8,0x83,0xd0,0x7e,0x28,0x52,0xc0,0x48,0x20,0xb3,0x03,0x68,0x8c,0xcf,0xf3,0xff,0x81,0x84,0x84,0x00,0x33,0xb8,0x2c,0x22,0x01,0x02,0x07,0x98,0x28,0x60,0xe8,0x93,0x92,0x40,0xd9,0x63,0x04,0x09,0x08,0xa0,0x7e,0xe0,0xf5,0x9e,0x40,0xc0,0x63,0x08,0x07,0x9c,0x4f,0xe0,0x0f,0x55,0x51,0x44,0x01,0xe5,0xc0,0x8c,0xe4,0x20,0xc2,0xf4,0x07,0x8c,0x1a,0x40,0xfe,0x38,0xe6,0xc0,0x0a,0x44,0x63,0x50,0x8a,0x58,0x43,0xe5,0x1f,0xe8,0x02,0x88,0x00,0x2d,0x82,0x03,0xa4,0xff,0xc1,0x2f,0x0f,0x18,0x00,0x8f,0xe2,0x60,0x10,0x10,0xc8,0x24,0x11,0x80,0x7b,0x78,0x03,0xe8,0x34,0x40,0x07,0x80,0x3c,0x01,0xe0,0x02,}; +const uint8_t _A_LaptopActive_128x52_3[] = {0x01,0x00,0x01,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x1e,0x30,0x20,0x30,0xe0,0x01,0xe5,0x81,0xbb,0xf2,0x20,0x17,0xc0,0x7d,0xdc,0x01,0xe3,0x82,0x07,0xa7,0x1e,0x4b,0xc3,0x8c,0xe7,0x36,0x38,0x30,0x79,0x4e,0x60,0x20,0xf3,0x94,0xe9,0x70,0x92,0x4a,0x24,0x2b,0x03,0xff,0xbf,0xe0,0x2f,0x90,0x21,0x48,0x83,0xcf,0x0f,0x24,0xe2,0x44,0xf0,0x22,0xb1,0xc0,0x7b,0x81,0xed,0x80,0x0f,0x8c,0x80,0x3e,0x7f,0xe8,0x17,0x02,0x1e,0x0f,0x1e,0x4c,0x67,0x07,0x18,0xc2,0x46,0x43,0xe6,0x0f,0x19,0x84,0x40,0xff,0x10,0x30,0x78,0x8f,0xc6,0x19,0x20,0x70,0x90,0x3d,0x6f,0xc5,0xb1,0x2f,0x8c,0x0e,0x40,0xb4,0x20,0x7a,0xdc,0x81,0xe3,0xfe,0xf0,0x2c,0x05,0x48,0x40,0xf8,0x47,0x8c,0x03,0x7c,0xee,0x7f,0xff,0xca,0x83,0x00,0x80,0xc0,0x70,0x12,0x18,0x07,0x23,0x8f,0xcf,0x81,0xc2,0xa1,0x12,0x1d,0x05,0xca,0x84,0x25,0x2b,0x07,0xf0,0x30,0x37,0xfb,0xbc,0x18,0x1e,0x97,0xa0,0x79,0x46,0x0b,0xc5,0x40,0xbf,0xc1,0x61,0x58,0x89,0x10,0x3c,0x69,0x40,0xf2,0x83,0x17,0x8b,0xc1,0x7e,0x80,0xc2,0xa9,0x12,0x40,0x7a,0x60,0x20,0x20,0xf3,0xdf,0x40,0x01,0xe9,0x2a,0x05,0x0d,0xe0,0xa4,0x20,0x41,0xf8,0x5f,0xc1,0xf0,0x00,0x10,0x79,0xcf,0xc1,0xe3,0x50,0x8a,0x03,0xd5,0xbe,0x20,0x01,0xfc,0x77,0xcd,0xe3,0x90,0x89,0x03,0xc6,0x34,0x0b,0x2e,0x00,0x3c,0xff,0xe4,0xf1,0xd0,0x00,0x47,0xff,0x1f,0x3f,0x98,0x0c,0x90,0x42,0x2f,0x1e,0x04,0x1f,0x41,0x00,0x88,0x02,0xc9,0x66,0x20,0xf2,0x1f,0x90,0x14,0x43,0xe3,0x0f,0x80,0x02,0x06,0x40,0x0f,0x2f,0xf1,0x7c,0x7f,0x4a,0x51,0xdf,0xf0,0x21,0x1c,0x01,0xe8,0x83,0xd0,0x7e,0x28,0x52,0xc0,0x48,0x20,0xb3,0x03,0x68,0x8c,0xcf,0xf3,0xff,0x81,0x84,0x84,0x00,0x33,0xb8,0x2c,0x22,0x01,0x02,0x07,0x98,0x28,0x60,0xe8,0x93,0x92,0x40,0xd9,0x63,0x04,0x09,0x08,0xa0,0x7e,0xe0,0xf5,0x9e,0x40,0xc0,0x63,0x08,0x07,0x9c,0x4f,0xe0,0x0f,0x55,0x51,0x44,0x01,0xe5,0xc0,0x8c,0xe4,0x20,0xc2,0xf4,0x07,0x8c,0x1a,0x40,0xfe,0x38,0xe6,0xc0,0x0a,0x44,0x63,0x50,0x8a,0x58,0x43,0xe5,0x1f,0xe8,0x02,0x88,0x00,0x2d,0x82,0x03,0xa4,0xff,0xc1,0x2f,0x0f,0x18,0x00,0x8f,0xe2,0x60,0x10,0x10,0xc8,0x24,0x11,0x80,0x7b,0x78,0x03,0xe8,0x34,0x40,0x07,0x80,0x3c,0x01,0xe0,0x02,}; +const uint8_t _A_LaptopActive_128x52_4[] = {0x01,0x00,0x08,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x1e,0x31,0xe0,0x98,0xd0,0x22,0x18,0x00,0xf9,0x72,0x20,0x17,0xc0,0x79,0xc8,0x81,0xed,0x70,0x07,0x8e,0x08,0x1e,0x7a,0x2b,0xa4,0xe3,0xcd,0x38,0xf1,0xd7,0x30,0x40,0xf2,0x9c,0xc0,0x41,0xe5,0x9e,0x92,0x52,0x29,0x39,0x0c,0xa5,0x4b,0x05,0xff,0xbf,0xe0,0x2f,0x90,0x21,0x38,0x87,0xc4,0x1e,0xc2,0xb1,0xc0,0x7b,0x81,0xe3,0x0f,0x07,0xc0,0x7c,0xbf,0xd0,0x2b,0x04,0x40,0xbe,0x32,0x7a,0x45,0x1a,0x21,0xe3,0xce,0x60,0xc3,0xe4,0x0f,0x18,0xc3,0xe0,0x80,0x0b,0x82,0x81,0x83,0xc4,0x7e,0x30,0x69,0x03,0x84,0x91,0xc9,0x81,0xbf,0x16,0xc6,0x73,0x81,0x80,0xc8,0x16,0x84,0x10,0x5b,0x90,0x3c,0x7f,0xd6,0x08,0x04,0xfd,0x48,0x40,0xf8,0x31,0x8f,0x03,0x3e,0xee,0x7f,0xff,0xca,0x83,0x00,0x80,0xc0,0x7e,0x10,0xf8,0x07,0x23,0x8f,0xcf,0x81,0xc2,0xa1,0x12,0x1d,0x05,0xca,0x84,0x25,0x2f,0xe0,0x60,0xaf,0xf7,0x78,0x30,0x3d,0x2f,0x40,0xf2,0xff,0xc1,0x5c,0x65,0x7f,0x82,0xc2,0xb1,0x12,0x20,0x78,0xd2,0x81,0x43,0xc0,0xff,0x97,0x8b,0xc1,0x7e,0x80,0xc2,0xa9,0x12,0x40,0x7a,0x7c,0x2f,0xe0,0xf3,0xdf,0x40,0x01,0xe9,0x2a,0x05,0x0d,0xf3,0xf0,0x6e,0x20,0xa0,0x83,0xe3,0x01,0xff,0x07,0x9c,0xfc,0x1e,0x35,0x08,0xa0,0x3d,0x08,0x02,0x03,0x2f,0xc7,0x7c,0xde,0x39,0x08,0x90,0x3c,0x63,0x49,0x53,0x07,0x98,0x90,0x61,0x5a,0x00,0x08,0xff,0xe3,0xe0,0xb2,0x51,0x8a,0x0c,0xc5,0xe3,0xc0,0x83,0xe8,0x20,0x11,0x00,0xd1,0x03,0xd0,0x7e,0x40,0x51,0x0f,0x8a,0xa8,0x67,0xfe,0x00,0x50,0x80,0x07,0xfc,0x5f,0x1f,0xd2,0x94,0x77,0xfc,0x08,0x47,0x00,0x9a,0x20,0xf4,0x1f,0x8a,0x14,0xb0,0x12,0x08,0x2c,0xc1,0xa0,0x31,0x80,0x79,0x7e,0x7f,0xf0,0x30,0x90,0x80,0x06,0x77,0x05,0x84,0x40,0x20,0x40,0xf3,0x05,0x0c,0x1c,0x0a,0x50,0x09,0x24,0x0e,0x09,0x00,0x82,0x04,0x84,0x50,0x3f,0x70,0x7a,0xcf,0x20,0x60,0x31,0x84,0x03,0xce,0x27,0xf0,0x07,0xaa,0xa8,0xa2,0x00,0xf2,0xe0,0x46,0x72,0x10,0x61,0x7a,0x03,0xc6,0x0d,0x20,0x19,0x0a,0x48,0x63,0x9b,0x00,0x29,0x11,0x8d,0x42,0x29,0x61,0x0f,0x94,0x7f,0xa0,0x0a,0x20,0x00,0xb6,0x08,0x0e,0x89,0x41,0x97,0x87,0x8c,0x00,0x47,0xf1,0x30,0x08,0x08,0x64,0x12,0x03,0xa1,0x80,0x0f,0xc0,0x1f,0x41,0xa2,0x00,0x3c,0x01,0xe0,0x0f,0x00,0x10,}; +const uint8_t _A_LaptopActive_128x52_5[] = {0x01,0x00,0x02,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x1e,0x31,0xe0,0x98,0xd0,0x22,0x18,0x00,0xf9,0x72,0x20,0x17,0xc0,0x79,0xc8,0x81,0xed,0x70,0x07,0x8e,0x08,0x1e,0x7a,0x2b,0xa4,0xe3,0xcd,0x38,0xf1,0xd7,0x30,0x40,0xf2,0x9c,0xc0,0x41,0xe5,0x9e,0x92,0x52,0x29,0x39,0x0c,0xa5,0x4b,0x05,0xff,0xbf,0xe0,0x2f,0x90,0x21,0x38,0x87,0xc4,0x1e,0xc2,0xb1,0xc0,0x7b,0x81,0xf6,0x1f,0x2f,0xf4,0x0b,0x81,0x0f,0x2f,0x8c,0x9e,0x91,0x46,0x88,0x78,0xf3,0x98,0x30,0xf9,0x03,0xc6,0x61,0x10,0x3f,0xbe,0x0a,0x06,0x0f,0x11,0xf8,0xc3,0x24,0x0e,0x12,0x47,0x26,0x06,0xfc,0x5b,0x12,0xf8,0xc0,0xe4,0x0b,0x42,0x08,0x2d,0xc8,0x1e,0x3f,0xef,0x02,0xc0,0x54,0x84,0x0f,0x83,0x18,0xc0,0x37,0xce,0xe7,0xff,0xfc,0xa8,0x30,0x08,0x0c,0x07,0x01,0x21,0x80,0x72,0x38,0xfc,0xf8,0x1c,0x2a,0x11,0x21,0xd0,0x5c,0xa8,0x42,0x52,0xb0,0x7f,0x03,0x03,0x7f,0xbb,0xc1,0x81,0xe9,0x7a,0x07,0x94,0x60,0xbc,0x54,0x0b,0xfc,0x16,0x15,0x88,0x91,0x03,0xc6,0x94,0x0f,0x28,0x31,0x78,0xbc,0x17,0xe8,0x0c,0x2a,0x91,0x24,0x07,0xa6,0x02,0x02,0x0f,0x3d,0xf4,0x00,0x1e,0x92,0xa0,0x50,0xde,0x0a,0x42,0x04,0x1f,0x85,0xfc,0x1f,0x00,0x01,0x07,0x9c,0xfc,0x1e,0x35,0x08,0xa0,0x3d,0x5b,0xe2,0x00,0x1f,0xc7,0x7c,0xde,0x39,0x08,0x90,0x3c,0x63,0x40,0xb2,0xe0,0x03,0xcf,0xfe,0x4f,0x1d,0x00,0x04,0x7f,0xf1,0xf3,0xf9,0x80,0xc9,0x04,0x22,0xf1,0xe0,0x41,0xf4,0x10,0x08,0x80,0x2c,0x96,0x62,0x0f,0x21,0xf9,0x01,0x44,0x3e,0x30,0xf8,0x00,0x20,0x64,0x00,0xf2,0xff,0x17,0xc7,0xf4,0xa5,0x1d,0xff,0x02,0x11,0xc0,0x1e,0x88,0x3d,0x07,0xe2,0x85,0x2c,0x04,0x82,0x0b,0x30,0x36,0x88,0xcc,0xff,0x3f,0xf8,0x18,0x48,0x40,0x03,0x3b,0x82,0xc2,0x20,0x10,0x20,0x79,0x82,0x86,0x0e,0x89,0x39,0x24,0x0d,0x96,0x30,0x40,0x90,0x8a,0x07,0xee,0x0f,0x59,0xe4,0x0c,0x06,0x30,0x80,0x79,0xc4,0xfe,0x00,0xf5,0x55,0x14,0x40,0x1e,0x5c,0x08,0xce,0x42,0x0c,0x2f,0x40,0x78,0xc1,0xa4,0x0f,0xe3,0x8e,0x6c,0x00,0xa4,0x46,0x35,0x08,0xa5,0x84,0x3e,0x51,0xfe,0x80,0x28,0x80,0x02,0xd8,0x20,0x3a,0x4f,0xfc,0x12,0xf0,0xf1,0x80,0x08,0xfe,0x26,0x01,0x01,0x0c,0x82,0x41,0x18,0x07,0xb7,0x80,0x3e,0x83,0x44,0x00,0x78,0x03,0xc0,0x1e,0x00,0x20,}; +const uint8_t _A_LaptopActive_128x52_6[] = {0x01,0x00,0x08,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x1e,0x31,0xe0,0x98,0xd0,0x22,0x18,0x00,0xf9,0x72,0x20,0x17,0xc0,0x79,0xc8,0x81,0xed,0x70,0x07,0x8e,0x08,0x1e,0x7a,0x2b,0xa4,0xe3,0xcd,0x38,0xf1,0xd7,0x30,0x40,0xf2,0x9c,0xc0,0x41,0xe5,0x9e,0x92,0x52,0x29,0x39,0x0c,0xa5,0x4b,0x05,0xff,0xbf,0xe0,0x2f,0x90,0x21,0x38,0x87,0xc4,0x1e,0xc2,0xb1,0xc0,0x7b,0x81,0xe3,0x0f,0x07,0xc0,0x7c,0xbf,0xd0,0x2b,0x04,0x40,0xbe,0x32,0x7a,0x45,0x1a,0x21,0xe3,0xce,0x60,0xc3,0xe4,0x0f,0x18,0xc3,0xe0,0x80,0x0b,0x82,0x81,0x83,0xc4,0x7e,0x30,0x69,0x03,0x84,0x91,0xc9,0x81,0xbf,0x16,0xc6,0x73,0x81,0x80,0xc8,0x16,0x84,0x10,0x5b,0x90,0x3c,0x7f,0xd6,0x08,0x04,0xfd,0x48,0x40,0xf8,0x31,0x8f,0x03,0x3e,0xee,0x7f,0xff,0xca,0x83,0x00,0x80,0xc0,0x7e,0x10,0xf8,0x07,0x23,0x8f,0xcf,0x81,0xc2,0xa1,0x12,0x1d,0x05,0xca,0x84,0x25,0x2f,0xe0,0x60,0xaf,0xf7,0x78,0x30,0x3d,0x2f,0x40,0xf2,0xff,0xc1,0x5c,0x65,0x7f,0x82,0xc2,0xb1,0x12,0x20,0x78,0xd2,0x81,0x43,0xc0,0xff,0x97,0x8b,0xc1,0x7e,0x80,0xc2,0xa9,0x12,0x40,0x7a,0x7c,0x2f,0xe0,0xf3,0xdf,0x40,0x01,0xe9,0x2a,0x05,0x0d,0xf3,0xf0,0x6e,0x20,0xa0,0x83,0xe3,0x01,0xff,0x07,0x9c,0xfc,0x1e,0x35,0x08,0xa0,0x3d,0x08,0x02,0x03,0x2f,0xc7,0x7c,0xde,0x39,0x08,0x90,0x3c,0x63,0x49,0x53,0x07,0x98,0x90,0x61,0x5a,0x00,0x08,0xff,0xe3,0xe0,0xb2,0x51,0x8a,0x0c,0xc5,0xe3,0xc0,0x83,0xe8,0x20,0x11,0x00,0xd1,0x03,0xd0,0x7e,0x40,0x51,0x0f,0x8a,0xa8,0x67,0xfe,0x00,0x50,0x80,0x07,0xfc,0x5f,0x1f,0xd2,0x94,0x77,0xfc,0x08,0x47,0x00,0x9a,0x20,0xf4,0x1f,0x8a,0x14,0xb0,0x12,0x08,0x2c,0xc1,0xa0,0x31,0x80,0x79,0x7e,0x7f,0xf0,0x30,0x90,0x80,0x06,0x77,0x05,0x84,0x40,0x20,0x40,0xf3,0x05,0x0c,0x1c,0x0a,0x50,0x09,0x24,0x0e,0x09,0x00,0x82,0x04,0x84,0x50,0x3f,0x70,0x7a,0xcf,0x20,0x60,0x31,0x84,0x03,0xce,0x27,0xf0,0x07,0xaa,0xa8,0xa2,0x00,0xf2,0xe0,0x46,0x72,0x10,0x61,0x7a,0x03,0xc6,0x0d,0x20,0x19,0x0a,0x48,0x63,0x9b,0x00,0x29,0x11,0x8d,0x42,0x29,0x61,0x0f,0x94,0x7f,0xa0,0x0a,0x20,0x00,0xb6,0x08,0x0e,0x89,0x41,0x97,0x87,0x8c,0x00,0x47,0xf1,0x30,0x08,0x08,0x64,0x12,0x03,0xa1,0x80,0x0f,0xc0,0x1f,0x41,0xa2,0x00,0x3c,0x01,0xe0,0x0f,0x00,0x10,}; +const uint8_t _A_LaptopActive_128x52_7[] = {0x01,0x00,0x02,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x44,0x61,0x0d,0x10,0x01,0x03,0xe2,0x15,0x20,0x78,0x88,0x49,0x02,0xa1,0xf1,0x07,0x91,0x18,0x41,0xf0,0x1f,0x15,0x99,0x03,0xea,0xeb,0x48,0x07,0x95,0x00,0x1e,0x31,0xe0,0x98,0xd0,0x22,0x18,0x00,0xf9,0x72,0x20,0x17,0xc0,0x79,0xc8,0x81,0xed,0x70,0x07,0x8e,0x08,0x1e,0x7a,0x2b,0xa4,0xe3,0xcd,0x38,0xf1,0xd7,0x30,0x40,0xf2,0x9c,0xc0,0x41,0xe5,0x9e,0x92,0x52,0x29,0x39,0x0c,0xa5,0x4b,0x05,0xff,0xbf,0xe0,0x2f,0x90,0x21,0x38,0x87,0xc4,0x1e,0xc2,0xb1,0xc0,0x7b,0x81,0xf6,0x1f,0x2f,0xf4,0x0b,0x81,0x0f,0x2f,0x8c,0x9e,0x91,0x46,0x88,0x78,0xf3,0x98,0x30,0xf9,0x03,0xc6,0x61,0x10,0x3f,0xbe,0x0a,0x06,0x0f,0x11,0xf8,0xc3,0x24,0x0e,0x12,0x47,0x26,0x06,0xfc,0x5b,0x12,0xf8,0xc0,0xe4,0x0b,0x42,0x08,0x2d,0xc8,0x1e,0x3f,0xef,0x02,0xc0,0x54,0x84,0x0f,0x83,0x18,0xc0,0x37,0xce,0xe7,0xff,0xfc,0xa8,0x30,0x08,0x0c,0x07,0x01,0x21,0x80,0x72,0x38,0xfc,0xf8,0x1c,0x2a,0x11,0x21,0xd0,0x5c,0xa8,0x42,0x52,0xb0,0x7f,0x03,0x03,0x7f,0xbb,0xc1,0x81,0xe9,0x7a,0x07,0x94,0x60,0xbc,0x54,0x0b,0xfc,0x16,0x15,0x88,0x91,0x03,0xc6,0x94,0x0f,0x28,0x31,0x78,0xbc,0x17,0xe8,0x0c,0x2a,0x91,0x24,0x07,0xa6,0x02,0x02,0x0f,0x3d,0xf4,0x00,0x1e,0x92,0xa0,0x50,0xde,0x0a,0x42,0x04,0x1f,0x85,0xfc,0x1f,0x00,0x01,0x07,0x9c,0xfc,0x1e,0x35,0x08,0xa0,0x3d,0x5b,0xe2,0x00,0x1f,0xc7,0x7c,0xde,0x39,0x08,0x90,0x3c,0x63,0x40,0xb2,0xe0,0x03,0xcf,0xfe,0x4f,0x1d,0x00,0x04,0x7f,0xf1,0xf3,0xf9,0x80,0xc9,0x04,0x22,0xf1,0xe0,0x41,0xf4,0x10,0x08,0x80,0x2c,0x96,0x62,0x0f,0x21,0xf9,0x01,0x44,0x3e,0x30,0xf8,0x00,0x20,0x64,0x00,0xf2,0xff,0x17,0xc7,0xf4,0xa5,0x1d,0xff,0x02,0x11,0xc0,0x1e,0x88,0x3d,0x07,0xe2,0x85,0x2c,0x04,0x82,0x0b,0x30,0x36,0x88,0xcc,0xff,0x3f,0xf8,0x18,0x48,0x40,0x03,0x3b,0x82,0xc2,0x20,0x10,0x20,0x79,0x82,0x86,0x0e,0x89,0x39,0x24,0x0d,0x96,0x30,0x40,0x90,0x8a,0x07,0xee,0x0f,0x59,0xe4,0x0c,0x06,0x30,0x80,0x79,0xc4,0xfe,0x00,0xf5,0x55,0x14,0x40,0x1e,0x5c,0x08,0xce,0x42,0x0c,0x2f,0x40,0x78,0xc1,0xa4,0x0f,0xe3,0x8e,0x6c,0x00,0xa4,0x46,0x35,0x08,0xa5,0x84,0x3e,0x51,0xfe,0x80,0x28,0x80,0x02,0xd8,0x20,0x3a,0x4f,0xfc,0x12,0xf0,0xf1,0x80,0x08,0xfe,0x26,0x01,0x01,0x0c,0x82,0x41,0x18,0x07,0xb7,0x80,0x3e,0x83,0x44,0x00,0x78,0x03,0xc0,0x1e,0x00,0x20,}; const uint8_t *_A_LaptopActive_128x52[] = {_A_LaptopActive_128x52_0,_A_LaptopActive_128x52_1,_A_LaptopActive_128x52_2,_A_LaptopActive_128x52_3,_A_LaptopActive_128x52_4,_A_LaptopActive_128x52_5,_A_LaptopActive_128x52_6,_A_LaptopActive_128x52_7}; const uint8_t _A_Laptop_128x52_0[] = {0x01,0x00,0x3e,0x02,0x00,0x78,0x03,0x60,0x20,0x43,0xc0,0x40,0xc1,0xce,0x09,0x2c,0x04,0x1c,0x04,0x30,0x20,0x7d,0x51,0xf1,0x10,0x1f,0xe4,0x3c,0x1e,0xf4,0x08,0x24,0x02,0xd1,0x48,0x9d,0x40,0xe6,0x00,0xf7,0x90,0x42,0x20,0x1f,0x0a,0x7f,0x3a,0x01,0xc0,0x07,0xbc,0x42,0x21,0x00,0xfb,0xd3,0xe5,0xc0,0x71,0x28,0x3c,0x22,0x41,0x00,0xba,0xde,0x23,0xc0,0x71,0x1b,0x08,0x8c,0x60,0xf3,0xc8,0x07,0xfb,0xfe,0x00,0x1b,0xbd,0x2e,0x1c,0x17,0x20,0x10,0xd8,0x21,0x11,0x38,0x01,0x9c,0xb0,0x17,0x0a,0x44,0x18,0x6e,0x40,0x82,0xc8,0x05,0x07,0xf4,0x1e,0x1d,0xf8,0x7c,0x42,0xa4,0x0f,0x28,0x05,0x44,0x1e,0x30,0xa0,0x28,0xe8,0x03,0xe2,0x0f,0x22,0x30,0x80,0x06,0xa4,0x44,0x18,0x54,0x0b,0x01,0xa0,0x0f,0x8a,0xcc,0x81,0xe7,0x54,0x0b,0x8c,0x2a,0x0d,0xc1,0xd4,0x5d,0x69,0x00,0xf2,0xa0,0x03,0xcb,0xd0,0x07,0x1c,0x56,0xab,0x55,0xa4,0xbb,0xf2,0x20,0x17,0xc0,0x79,0xf8,0x2e,0xcc,0x81,0x85,0x74,0xf2,0xda,0xab,0x80,0x3c,0x70,0x40,0xf3,0xcc,0x7b,0x6e,0x30,0x0a,0x56,0x0a,0x05,0xa7,0x07,0x94,0x06,0x02,0x0f,0x28,0x87,0xef,0x79,0x01,0xc5,0x60,0x60,0x5a,0xaf,0xfd,0xfd,0x04,0x25,0x61,0x29,0x15,0xde,0x3d,0x03,0x95,0x03,0xc7,0x4c,0x2b,0x1c,0x07,0xa0,0x1e,0x74,0x0b,0x76,0x3c,0x9e,0x20,0xf1,0xd0,0x87,0xcb,0xf9,0x03,0xe0,0x43,0xd3,0xe3,0xf8,0xa7,0x93,0xc7,0x85,0x86,0xd0,0x07,0xc8,0x1e,0x33,0x05,0x01,0x7d,0xe6,0xe0,0xf1,0xd2,0x52,0xb4,0x10,0x30,0x78,0xdf,0x20,0x50,0xc4,0x80,0xf0,0x3f,0xd3,0xb0,0x78,0xea,0x21,0x5a,0x0b,0xf1,0x6c,0x6f,0x30,0x18,0x18,0x3c,0x7c,0x1f,0x18,0xf8,0x3c,0x72,0x11,0x2d,0x05,0xc8,0x1e,0x3f,0xef,0x02,0xc0,0xb0,0x1e,0xf2,0x18,0x83,0xd9,0x1e,0x30,0x09,0xf2,0x90,0x7f,0xca,0xf1,0x85,0x62,0x24,0x5a,0x0f,0x95,0x05,0x1e,0x58,0x09,0x0c,0x03,0x91,0xc7,0xe7,0xc0,0xe1,0x50,0x89,0x08,0x7c,0x68,0x4c,0xb2,0xb0,0x7f,0x3f,0xe7,0x71,0xbb,0xc1,0x81,0xe9,0x7a,0x07,0x94,0x61,0xf6,0x27,0x71,0xbf,0xc1,0x45,0xe7,0x72,0xa5,0x13,0x0a,0x0c,0xfb,0x13,0x00,0xdf,0xa0,0x30,0xaa,0x44,0x90,0x1e,0x7c,0x0e,0x04,0x04,0x1e,0x7b,0xe2,0x78,0x83,0xce,0x54,0x0a,0x19,0xf9,0x48,0x40,0x83,0xf0,0xbf,0x83,0xe0,0x00,0x20,0xf3,0x0a,0x8c,0x2a,0xa1,0x14,0x07,0xab,0x7c,0xa0,0x1f,0x8e,0xf9,0xbc,0x51,0xe7,0x1a,0x05,0x97,0x00,0x1e,0x7f,0xf2,0x78,0xe8,0x00,0x23,0xff,0x5b,0x09,0xfc,0x80,0x65,0xfc,0xff,0x0b,0xc7,0x81,0x07,0x77,0x8b,0xa8,0x8f,0x62,0x0f,0x39,0xe0,0x3c,0x40,0xa2,0x1f,0x16,0x30,0x92,0x05,0x02,0x20,0x01,0xff,0x5f,0x20,0x1f,0xa5,0x28,0xef,0xf8,0x10,0x83,0xf0,0x83,0xd7,0xf8,0x85,0x3c,0x04,0x82,0x0b,0x30,0x36,0x88,0xcc,0xff,0x3f,0xe8,0x1f,0xf8,0x3e,0x3f,0xf9,0xdc,0x16,0x11,0x00,0x81,0x03,0xcc,0x14,0x30,0x74,0x49,0xc9,0x20,0x6c,0xb1,0x82,0x04,0x84,0x50,0x3f,0x70,0x7a,0xcf,0x20,0x60,0x31,0x84,0x03,0xce,0x27,0xf0,0x07,0xaa,0xa8,0xa2,0x00,0xf2,0xe0,0x46,0x72,0x10,0x61,0x7a,0x03,0xc6,0x0d,0x20,0x7f,0x1c,0x73,0x60,0x05,0x22,0x31,0xa8,0x45,0x2c,0x21,0xf2,0x8f,0xf4,0x01,0x44,0x00,0x16,0xc1,0x01,0xd2,0x7f,0xe0,0x97,0x87,0x8c,0x00,0x47,0xf1,0x30,0x08,0x08,0x64,0x12,0x08,0xc0,0x3d,0xbc,0x01,0xf4,0x1a,0x20,0x03,0xc0,0x1e,0x00,0xf0,0x01,0x00,}; @@ -189,45 +189,45 @@ const uint8_t *_A_Level3Lab_128x51[] = {_A_Level3Lab_128x51_0,_A_Level3Lab_128x5 const uint8_t _I_LevelUp2_04_0[] = {0x01,0x00,0x16,0x01,0x00,0x37,0xf2,0x02,0x0f,0xda,0xbc,0xfc,0x1d,0x9c,0x0f,0x5f,0xac,0x1f,0x97,0x0b,0xaf,0x54,0x61,0x9b,0x8d,0xd6,0xaa,0x06,0x0f,0xba,0xa5,0x76,0xaa,0x0f,0xcd,0x66,0xbb,0x55,0x06,0x07,0xdd,0x5b,0xef,0x5f,0x86,0x83,0xef,0x55,0xbb,0xdd,0x42,0x81,0xf7,0xd7,0xee,0xdd,0xe3,0xa0,0xfb,0xff,0xeb,0xbd,0xf1,0xa0,0x7d,0xf5,0x7a,0xf5,0xf9,0xa8,0x36,0x60,0x90,0x0d,0x5f,0xfb,0xfd,0x2a,0xb0,0x03,0xe2,0x39,0x00,0xaa,0xf5,0x7b,0xf7,0x59,0xc0,0x3e,0x26,0x10,0x0f,0x5f,0xfb,0x7f,0x6a,0x84,0x0f,0xea,0xba,0x40,0x1a,0xa9,0x3e,0xfd,0x7a,0xef,0x57,0xa9,0x3f,0x9d,0xdb,0xff,0x55,0x3f,0x9b,0xff,0x5e,0xa8,0x1f,0x7f,0xef,0xaf,0x57,0xab,0xf1,0x07,0xd3,0x78,0x40,0x03,0x01,0x06,0xc4,0x08,0x7e,0x35,0x50,0x00,0x83,0xe6,0x1c,0x9f,0x10,0xfe,0x46,0x30,0x01,0xd1,0xae,0x87,0xea,0x01,0xc0,0x0e,0x8e,0xbc,0x3f,0x50,0x0b,0x05,0x57,0xea,0x21,0x1e,0x08,0x3e,0x76,0x07,0xf1,0x10,0x8e,0x06,0x06,0x0f,0x8a,0x85,0xfc,0xbf,0x90,0x0f,0x81,0x7f,0x60,0x17,0x01,0xf9,0x83,0xe7,0x81,0xe1,0xd5,0x6f,0x83,0xf7,0x70,0xe0,0x7f,0xea,0xe3,0xfc,0x30,0x10,0xff,0x20,0x15,0x82,0xfe,0xc0,0x35,0x01,0xff,0x0f,0xf6,0xb0,0x3f,0xd5,0x40,0xff,0x87,0xc8,0x1d,0x40,0x0f,0x00,0x76,0x23,0x7d,0x24,0x82,0x57,0xfe,0x90,0x58,0xa8,0x3e,0x30,0x40,0xf1,0xa0,0xc5,0x20,0x80,0xf8,0xcc,0x03,0xfb,0x51,0x9e,0x07,0x8e,0x3f,0xe4,0x0f,0x9e,0x40,0x7c,0xb0,0x31,0x20,0x7c,0x8f,0xce,0x03,0x11,0x82,0x17,0xe6,0x7d,0x1b,0xbe,0x47,0xfe,0x37,0xd0,0xfc,0x00,0x3c,0x01,0xe0,0x0b,}; const uint8_t *_I_LevelUp2_04[] = {_I_LevelUp2_04_0}; -const uint8_t _I_LevelUp2_05_0[] = {0x01,0x00,0x1d,0x01,0x00,0x37,0xf2,0x02,0x0f,0xd8,0x3c,0xfc,0x1d,0x9c,0x0e,0x0f,0x84,0x1f,0x96,0x0b,0x86,0x00,0x61,0x91,0x88,0xc4,0x02,0x06,0x0f,0xb8,0x24,0x32,0x01,0x02,0x07,0xe4,0x1a,0x00,0x01,0x10,0x05,0x41,0xbc,0x70,0xf1,0x08,0x80,0x1e,0x80,0x02,0x18,0x14,0x66,0x21,0x08,0x36,0x48,0x08,0x70,0x7c,0xd9,0x39,0x44,0x42,0xe4,0x00,0x43,0x51,0x7f,0xf4,0x96,0xf8,0x84,0x02,0xf8,0x20,0x73,0x50,0xe0,0x7a,0xf5,0xf9,0x86,0x02,0x0e,0x4d,0x88,0x04,0x07,0xa9,0xde,0x90,0x0d,0x88,0xda,0xe0,0xf2,0xcf,0xc8,0x0d,0xf7,0x49,0x07,0x89,0x35,0xc1,0xeb,0x94,0xeb,0x83,0xf2,0x97,0x2c,0xa4,0x03,0xf2,0x05,0xd8,0xbf,0xe0,0x01,0xf9,0x3f,0xa1,0x83,0xf3,0xf5,0xf1,0xc0,0x83,0xc7,0xfd,0x0f,0x06,0x2c,0x70,0x04,0x30,0xc0,0xe9,0x29,0x44,0x00,0xd7,0x04,0x89,0x83,0xe9,0x30,0x4b,0x11,0x6f,0x08,0x3e,0x1a,0x28,0xfe,0x10,0x7d,0x08,0x49,0x98,0x20,0xfa,0x5d,0x8f,0x80,0x7f,0x40,0x01,0x75,0x8c,0x7c,0x1f,0x91,0x0b,0xf1,0x7e,0xc0,0x03,0xf0,0x2f,0x88,0x3c,0xa6,0x02,0xf9,0x1f,0xa0,0x0c,0x80,0x0d,0x60,0x80,0x4f,0x01,0xe4,0x75,0x20,0x02,0x78,0x23,0xfc,0x0f,0xf8,0xc0,0x87,0xf1,0x38,0x28,0x11,0x3f,0x60,0x11,0x80,0x7f,0x2f,0x44,0x1f,0xe0,0xfd,0x66,0x88,0x3f,0x60,0x80,0xba,0x07,0xf8,0x03,0xc0,0x1e,0x00,0x1c,0x46,0xfa,0x49,0x04,0xaf,0xfd,0x20,0xb1,0x50,0x7c,0x60,0x81,0xe3,0x41,0x8a,0x41,0x01,0xf1,0x98,0x07,0xf6,0xa3,0x3c,0x0f,0x1c,0x7f,0xc8,0x1f,0x3c,0x80,0xf9,0x60,0x62,0x40,0xf9,0x1f,0x9c,0x06,0x22,0x83,0x9c,0x44,0xfa,0x37,0x7c,0x8f,0xfc,0x6f,0xa1,0xf8,0x00,0x78,0x03,0xc0,0x16,}; -const uint8_t *_I_LevelUp2_05[] = {_I_LevelUp2_05_0}; - -const uint8_t _I_LevelUp2_01_0[] = {0x01,0x00,0xdc,0x00,0x00,0x37,0xe2,0x02,0x0f,0xd8,0x3c,0xfc,0x1d,0x9c,0x08,0x0f,0x80,0x1f,0x96,0x08,0x06,0x00,0x61,0x91,0x80,0x10,0xc0,0xc1,0xf7,0x04,0x01,0x0c,0x08,0x1f,0xd0,0x60,0x7d,0x83,0x0a,0x18,0x0f,0xb1,0x61,0x42,0x01,0xf7,0x03,0xf8,0x41,0xca,0x44,0x00,0x98,0x0f,0x62,0x09,0x10,0x07,0xe5,0xa2,0x19,0x30,0x07,0xe7,0xb2,0x11,0x20,0x07,0xe7,0x92,0x1e,0x0f,0xe8,0x5d,0x00,0x1f,0x9a,0x48,0x78,0x3f,0x20,0x7e,0xc0,0x7e,0xc0,0xbf,0x10,0x7c,0x00,0x3f,0x3c,0x10,0x30,0x7e,0x80,0x84,0x1f,0x85,0x34,0x6f,0xe8,0x3f,0x20,0x60,0xfd,0xc0,0x02,0xcc,0x1f,0x5c,0x08,0x03,0x34,0x81,0xf4,0xbb,0x18,0x70,0x3f,0x26,0x18,0x02,0x01,0x03,0xea,0x21,0x7e,0x1f,0xef,0xc2,0x07,0x10,0x17,0xec,0x02,0x3c,0x0f,0xcb,0x07,0x00,0x18,0x46,0xfb,0xbf,0xa7,0xf8,0x7c,0x40,0xfc,0x8c,0x03,0xfa,0x10,0x0f,0xf0,0x7f,0x43,0x01,0xfd,0x04,0x05,0xd0,0x3f,0xc0,0x1e,0x00,0xf0,0x00,0xe2,0x37,0xd2,0x48,0x25,0x7f,0xe9,0x05,0x8a,0x83,0xe3,0x04,0x0f,0x1a,0x0c,0x52,0x08,0x0f,0x8c,0xc0,0x3f,0xb5,0x19,0xe0,0x78,0xe3,0xfe,0x40,0xf9,0xe4,0x07,0xcb,0x03,0x12,0x07,0xc8,0xfc,0xe0,0x31,0x14,0x1c,0xe2,0x27,0xd1,0xbb,0xe4,0x7f,0xe3,0x7d,0x0f,0xc0,0x03,0xc0,0x1e,0x00,0xb0,}; -const uint8_t *_I_LevelUp2_01[] = {_I_LevelUp2_01_0}; - const uint8_t _I_LevelUp2_03_0[] = {0x01,0x00,0xa3,0x00,0x00,0x37,0xf2,0x02,0x0f,0xdf,0xfc,0xfc,0x1d,0x9c,0x0f,0xff,0xfc,0x1f,0x9f,0x00,0x78,0x8c,0x33,0xf0,0x0f,0x18,0x19,0x3b,0x01,0xfe,0x0f,0x18,0x38,0x3e,0xff,0xc0,0xf1,0x87,0x83,0xfc,0xfd,0x80,0x01,0x8f,0x83,0xfc,0x1f,0xca,0x0c,0x07,0xf8,0x3c,0xaf,0xe0,0xff,0x07,0xf8,0x3f,0x9c,0x18,0x8f,0x20,0x7f,0x83,0xff,0xff,0x01,0x07,0xf8,0x3f,0xcb,0xfc,0x0f,0xac,0x00,0x3f,0xb8,0x00,0xfe,0xf0,0x03,0xfb,0xe0,0x0f,0xf0,0x7f,0x83,0xfc,0x9f,0xe6,0xff,0x07,0xf0,0xc1,0x01,0xf7,0xf8,0x07,0xf8,0x3f,0xc1,0xfd,0xfc,0x07,0xf8,0x3f,0xc1,0xfc,0x00,0xf0,0x06,0xe2,0x37,0xd2,0x48,0x25,0x7f,0xe9,0x05,0x8a,0x83,0xe3,0x04,0x0f,0x1a,0x0c,0x52,0x08,0x0f,0x8c,0xc0,0x3f,0xb5,0x19,0xe0,0x78,0xe3,0xfe,0x40,0xf9,0xe4,0x07,0xcb,0x03,0x12,0x07,0xc8,0xfc,0xe0,0x31,0x18,0x21,0x7e,0x67,0xd1,0xbb,0xe4,0x7f,0xe3,0x7d,0x0f,0xc0,0x03,0xc0,0x1e,0x00,0xb0,}; const uint8_t *_I_LevelUp2_03[] = {_I_LevelUp2_03_0}; +const uint8_t _I_LevelUp2_07_0[] = {0x01,0x00,0xf1,0x00,0x00,0x37,0xf2,0x02,0x0f,0xd8,0x3c,0xfc,0x1d,0x9c,0x0e,0x0f,0x84,0x1f,0x96,0x0b,0x86,0x00,0x61,0x91,0x88,0xc4,0x02,0x06,0x0f,0xb8,0x24,0x32,0x01,0x02,0x07,0xe4,0x1a,0x00,0x01,0x10,0x05,0x41,0xbc,0x70,0xf1,0x08,0x80,0x2a,0x05,0x19,0x88,0x42,0x01,0xf7,0x83,0xe6,0xc9,0xca,0x22,0x00,0xaf,0xfe,0x92,0xdf,0x10,0x07,0xde,0x07,0xaf,0x5f,0x98,0x03,0xee,0x03,0xd4,0xef,0x48,0x01,0xfb,0x9f,0x07,0xe5,0x24,0x1e,0x34,0x00,0x7e,0x65,0x3a,0xe0,0xfc,0xa5,0xcb,0x29,0x00,0xfc,0x81,0x76,0x2f,0xf8,0x00,0x7e,0x4f,0xe8,0x60,0xfc,0xfd,0x7c,0x70,0x20,0xfc,0x86,0x03,0x4a,0x02,0xdf,0xb4,0x19,0x83,0xea,0x07,0x00,0x6f,0x08,0x3e,0xb0,0x00,0xb1,0x7f,0x08,0x3e,0xb8,0x00,0x21,0x83,0x83,0xed,0x76,0x3e,0x01,0xfe,0x4c,0x30,0x11,0xf0,0x7e,0x44,0x2f,0xc5,0xfd,0xf8,0x17,0xc4,0x5f,0xa3,0xfe,0xb0,0x40,0x27,0x80,0xfc,0xe0,0x7f,0xc6,0x04,0x9f,0xb8,0x82,0xbf,0xa3,0x00,0xfe,0x5e,0x88,0x3f,0xc1,0xfa,0xcd,0x10,0x7e,0xc1,0x01,0x74,0x0f,0xf0,0x07,0x80,0x3c,0x00,0x38,0x8d,0xf4,0x92,0x09,0x5f,0xfa,0x41,0x62,0xa0,0xf8,0xc1,0x03,0xc6,0x83,0x14,0x82,0x03,0xe3,0x30,0x0f,0xed,0x46,0x78,0x1e,0x38,0xff,0x90,0x3e,0x79,0x01,0xf2,0xc0,0xc4,0x81,0xf2,0x3f,0x38,0x0c,0x45,0x07,0x38,0x89,0xf4,0x6e,0xf9,0x1f,0xf8,0xdf,0x43,0xf0,0x00,0xf0,0x07,0x80,0x2c,}; +const uint8_t *_I_LevelUp2_07[] = {_I_LevelUp2_07_0}; + +const uint8_t _I_LevelUp2_05_0[] = {0x01,0x00,0x1d,0x01,0x00,0x37,0xf2,0x02,0x0f,0xd8,0x3c,0xfc,0x1d,0x9c,0x0e,0x0f,0x84,0x1f,0x96,0x0b,0x86,0x00,0x61,0x91,0x88,0xc4,0x02,0x06,0x0f,0xb8,0x24,0x32,0x01,0x02,0x07,0xe4,0x1a,0x00,0x01,0x10,0x05,0x41,0xbc,0x70,0xf1,0x08,0x80,0x1e,0x80,0x02,0x18,0x14,0x66,0x21,0x08,0x36,0x48,0x08,0x70,0x7c,0xd9,0x39,0x44,0x42,0xe4,0x00,0x43,0x51,0x7f,0xf4,0x96,0xf8,0x84,0x02,0xf8,0x20,0x73,0x50,0xe0,0x7a,0xf5,0xf9,0x86,0x02,0x0e,0x4d,0x88,0x04,0x07,0xa9,0xde,0x90,0x0d,0x88,0xda,0xe0,0xf2,0xcf,0xc8,0x0d,0xf7,0x49,0x07,0x89,0x35,0xc1,0xeb,0x94,0xeb,0x83,0xf2,0x97,0x2c,0xa4,0x03,0xf2,0x05,0xd8,0xbf,0xe0,0x01,0xf9,0x3f,0xa1,0x83,0xf3,0xf5,0xf1,0xc0,0x83,0xc7,0xfd,0x0f,0x06,0x2c,0x70,0x04,0x30,0xc0,0xe9,0x29,0x44,0x00,0xd7,0x04,0x89,0x83,0xe9,0x30,0x4b,0x11,0x6f,0x08,0x3e,0x1a,0x28,0xfe,0x10,0x7d,0x08,0x49,0x98,0x20,0xfa,0x5d,0x8f,0x80,0x7f,0x40,0x01,0x75,0x8c,0x7c,0x1f,0x91,0x0b,0xf1,0x7e,0xc0,0x03,0xf0,0x2f,0x88,0x3c,0xa6,0x02,0xf9,0x1f,0xa0,0x0c,0x80,0x0d,0x60,0x80,0x4f,0x01,0xe4,0x75,0x20,0x02,0x78,0x23,0xfc,0x0f,0xf8,0xc0,0x87,0xf1,0x38,0x28,0x11,0x3f,0x60,0x11,0x80,0x7f,0x2f,0x44,0x1f,0xe0,0xfd,0x66,0x88,0x3f,0x60,0x80,0xba,0x07,0xf8,0x03,0xc0,0x1e,0x00,0x1c,0x46,0xfa,0x49,0x04,0xaf,0xfd,0x20,0xb1,0x50,0x7c,0x60,0x81,0xe3,0x41,0x8a,0x41,0x01,0xf1,0x98,0x07,0xf6,0xa3,0x3c,0x0f,0x1c,0x7f,0xc8,0x1f,0x3c,0x80,0xf9,0x60,0x62,0x40,0xf9,0x1f,0x9c,0x06,0x22,0x83,0x9c,0x44,0xfa,0x37,0x7c,0x8f,0xfc,0x6f,0xa1,0xf8,0x00,0x78,0x03,0xc0,0x16,}; +const uint8_t *_I_LevelUp2_05[] = {_I_LevelUp2_05_0}; + const uint8_t _I_LevelUp2_02_0[] = {0x01,0x00,0xe1,0x00,0x00,0x37,0xe2,0x02,0x0f,0xda,0xbc,0xfc,0x1d,0x9c,0x0d,0x5f,0xa8,0x1f,0x97,0x0a,0xaf,0x54,0x61,0x9b,0x8d,0x56,0xaa,0x06,0x0f,0xba,0xa5,0x56,0xaa,0x0f,0xcd,0x60,0x7c,0x60,0xc0,0xfb,0xab,0x07,0xc6,0x1a,0x0f,0xb0,0xf0,0xea,0xa1,0x47,0xec,0xfa,0xd5,0xe3,0xa0,0xfb,0xd5,0xfe,0xb5,0xd1,0xa0,0x7d,0xd5,0x6f,0xb5,0xd9,0xa8,0x7f,0x3d,0xda,0xa9,0x50,0x7f,0x3e,0xb5,0xfb,0xa8,0x7f,0x75,0x76,0xa0,0xff,0x55,0x43,0xfb,0xaf,0x70,0x65,0x5b,0xfb,0x57,0xea,0xa7,0xf3,0xd5,0xab,0xd5,0x2f,0xfb,0xab,0x01,0x5f,0xee,0xa8,0x1f,0x61,0xf2,0xaa,0x83,0xec,0x7a,0x21,0xfc,0xc0,0x07,0x88,0x3f,0x7c,0x0d,0x56,0xe8,0x3f,0x96,0x0a,0xaa,0x78,0x43,0xf7,0xb0,0xd5,0x10,0x08,0x1f,0x55,0x0b,0xf8,0xff,0x7e,0x1a,0xb1,0xfe,0xdc,0x07,0xfd,0xe0,0x5f,0x10,0x7e,0xf8,0x03,0xfe,0x30,0x12,0xff,0x6b,0x01,0xfe,0xd4,0x07,0xfc,0x3f,0xda,0xc0,0xff,0x55,0x03,0xfe,0x1f,0x20,0x75,0x00,0x3c,0x01,0xd8,0x8d,0xf4,0x92,0x09,0x5f,0xfa,0x41,0x62,0xa0,0xf8,0xc1,0x03,0xc6,0x83,0x14,0x82,0x03,0xe3,0x30,0x0f,0xed,0x46,0x78,0x1e,0x38,0xff,0x90,0x3e,0x79,0x01,0xf2,0xc0,0xc4,0x81,0xf2,0x3f,0x38,0x0c,0x46,0x08,0x5f,0x99,0xf4,0x6e,0xf9,0x1f,0xf8,0xdf,0x43,0xf0,0x00,0xf0,0x07,0x80,0x2c,}; const uint8_t *_I_LevelUp2_02[] = {_I_LevelUp2_02_0}; const uint8_t _I_LevelUp2_06_0[] = {0x01,0x00,0x11,0x01,0x00,0x37,0xf2,0x02,0x0f,0xd8,0x3c,0xfc,0x1d,0x9c,0x0e,0x0f,0x84,0x17,0x18,0x00,0x19,0x58,0x2e,0x18,0x01,0x84,0xc1,0x80,0x43,0x18,0x8c,0x40,0x20,0x60,0xf8,0x86,0x00,0x86,0x08,0x03,0x18,0x10,0xfe,0xe0,0x82,0x31,0x12,0x95,0xe0,0x65,0x3e,0x38,0x78,0x94,0xa1,0xc0,0xf8,0x81,0x46,0x62,0x10,0x80,0x29,0x03,0xe3,0x07,0xcd,0x93,0x94,0x44,0x01,0x5f,0xfd,0x25,0xbe,0x20,0x0f,0xbc,0x0f,0x5e,0xbf,0x30,0x07,0xdc,0x07,0xa9,0xde,0x90,0x03,0xf7,0x3e,0x0f,0xca,0x48,0x3c,0x68,0x00,0xfc,0xca,0x75,0xc1,0xf9,0x4b,0x96,0x52,0x01,0xf9,0x02,0xec,0x5f,0xdc,0xc6,0x0f,0x99,0xfd,0x0c,0x1e,0x5c,0x00,0x7c,0x7e,0xbe,0x38,0x10,0xf9,0xac,0xc8,0x00,0x36,0x07,0x91,0x83,0x4a,0x02,0x2f,0xa7,0x61,0x03,0xe1,0xaa,0x70,0x31,0x51,0x07,0xeb,0x00,0x0b,0x17,0xf0,0x83,0xe8,0xb0,0x50,0x70,0x7d,0xae,0xc7,0xc0,0x4f,0xc9,0x86,0x02,0x3e,0x0f,0xc8,0x85,0xf8,0xbf,0x40,0x02,0xf8,0x17,0xc4,0x5f,0xa3,0xfe,0x51,0x0c,0xf0,0x1f,0x9c,0x0f,0xf8,0xc0,0x81,0xf0,0xc5,0x28,0x80,0xfd,0x19,0xc8,0x00,0x48,0xc0,0x3e,0xd8,0x04,0x09,0x31,0x7c,0x0e,0xc8,0x1e,0xaa,0x61,0x66,0x23,0xfc,0xcf,0xfb,0x00,0x82,0x02,0xe8,0x1f,0xe0,0x0f,0x00,0x78,0x00,0x71,0x1b,0xe9,0x24,0x12,0xbf,0xf4,0x82,0xc5,0x41,0xf1,0x82,0x07,0x8d,0x06,0x29,0x04,0x07,0xc6,0x60,0x1f,0xda,0x8c,0xf0,0x3c,0x71,0xff,0x20,0x7c,0xf2,0x03,0xe5,0x81,0x89,0x03,0xe4,0x7e,0x70,0x18,0x8a,0x0e,0x71,0x13,0xe8,0xdd,0xf2,0x3f,0xf1,0xbe,0x87,0xe0,0x01,0xe0,0x0f,0x00,0x58,}; const uint8_t *_I_LevelUp2_06[] = {_I_LevelUp2_06_0}; -const uint8_t _I_LevelUp2_07_0[] = {0x01,0x00,0xf1,0x00,0x00,0x37,0xf2,0x02,0x0f,0xd8,0x3c,0xfc,0x1d,0x9c,0x0e,0x0f,0x84,0x1f,0x96,0x0b,0x86,0x00,0x61,0x91,0x88,0xc4,0x02,0x06,0x0f,0xb8,0x24,0x32,0x01,0x02,0x07,0xe4,0x1a,0x00,0x01,0x10,0x05,0x41,0xbc,0x70,0xf1,0x08,0x80,0x2a,0x05,0x19,0x88,0x42,0x01,0xf7,0x83,0xe6,0xc9,0xca,0x22,0x00,0xaf,0xfe,0x92,0xdf,0x10,0x07,0xde,0x07,0xaf,0x5f,0x98,0x03,0xee,0x03,0xd4,0xef,0x48,0x01,0xfb,0x9f,0x07,0xe5,0x24,0x1e,0x34,0x00,0x7e,0x65,0x3a,0xe0,0xfc,0xa5,0xcb,0x29,0x00,0xfc,0x81,0x76,0x2f,0xf8,0x00,0x7e,0x4f,0xe8,0x60,0xfc,0xfd,0x7c,0x70,0x20,0xfc,0x86,0x03,0x4a,0x02,0xdf,0xb4,0x19,0x83,0xea,0x07,0x00,0x6f,0x08,0x3e,0xb0,0x00,0xb1,0x7f,0x08,0x3e,0xb8,0x00,0x21,0x83,0x83,0xed,0x76,0x3e,0x01,0xfe,0x4c,0x30,0x11,0xf0,0x7e,0x44,0x2f,0xc5,0xfd,0xf8,0x17,0xc4,0x5f,0xa3,0xfe,0xb0,0x40,0x27,0x80,0xfc,0xe0,0x7f,0xc6,0x04,0x9f,0xb8,0x82,0xbf,0xa3,0x00,0xfe,0x5e,0x88,0x3f,0xc1,0xfa,0xcd,0x10,0x7e,0xc1,0x01,0x74,0x0f,0xf0,0x07,0x80,0x3c,0x00,0x38,0x8d,0xf4,0x92,0x09,0x5f,0xfa,0x41,0x62,0xa0,0xf8,0xc1,0x03,0xc6,0x83,0x14,0x82,0x03,0xe3,0x30,0x0f,0xed,0x46,0x78,0x1e,0x38,0xff,0x90,0x3e,0x79,0x01,0xf2,0xc0,0xc4,0x81,0xf2,0x3f,0x38,0x0c,0x45,0x07,0x38,0x89,0xf4,0x6e,0xf9,0x1f,0xf8,0xdf,0x43,0xf0,0x00,0xf0,0x07,0x80,0x2c,}; -const uint8_t *_I_LevelUp2_07[] = {_I_LevelUp2_07_0}; - -const uint8_t _I_LevelUp3_03_0[] = {0x01,0x00,0xa3,0x00,0x00,0x37,0xf2,0x02,0x0f,0xdf,0xfc,0xfc,0x1d,0x9c,0x0f,0xff,0xfc,0x1f,0x9f,0x00,0x78,0x8c,0x33,0xf0,0x0f,0x18,0x19,0x3b,0x01,0xfe,0x0f,0x18,0x38,0x3e,0xff,0xc0,0xf1,0x87,0x83,0xfc,0xfd,0x80,0x01,0x8f,0x83,0xfc,0x1f,0xca,0x0c,0x07,0xf8,0x3c,0xaf,0xe0,0xff,0x07,0xf8,0x3f,0x9c,0x18,0x8f,0x20,0x7f,0x83,0xff,0xff,0x01,0x07,0xf8,0x3f,0xcb,0xfc,0x0f,0xac,0x00,0x3f,0xb8,0x00,0xfe,0xf0,0x03,0xfb,0xe0,0x0f,0xf0,0x7f,0x83,0xfc,0x9f,0xe6,0xff,0x07,0xf0,0xc1,0x01,0xf7,0xf8,0x07,0xf8,0x3f,0xc1,0xfd,0xfc,0x07,0xf8,0x3f,0xc1,0xfc,0x00,0xf0,0x06,0xe2,0x37,0xd2,0x48,0x25,0x7f,0xe9,0x05,0x8a,0x83,0xe3,0x04,0x0f,0x1a,0x0c,0x52,0x08,0x0f,0x8c,0xc0,0x3f,0xb5,0x19,0xe0,0x78,0xe3,0xfe,0x40,0xf9,0xe4,0x07,0xcb,0x03,0x12,0x07,0xc8,0xfc,0xe0,0x31,0x18,0x21,0x7e,0x67,0xd1,0xbb,0xe4,0x7f,0xe3,0x7d,0x0f,0xc0,0x03,0xc0,0x1e,0x00,0xb0,}; -const uint8_t *_I_LevelUp3_03[] = {_I_LevelUp3_03_0}; +const uint8_t _I_LevelUp2_01_0[] = {0x01,0x00,0xdc,0x00,0x00,0x37,0xe2,0x02,0x0f,0xd8,0x3c,0xfc,0x1d,0x9c,0x08,0x0f,0x80,0x1f,0x96,0x08,0x06,0x00,0x61,0x91,0x80,0x10,0xc0,0xc1,0xf7,0x04,0x01,0x0c,0x08,0x1f,0xd0,0x60,0x7d,0x83,0x0a,0x18,0x0f,0xb1,0x61,0x42,0x01,0xf7,0x03,0xf8,0x41,0xca,0x44,0x00,0x98,0x0f,0x62,0x09,0x10,0x07,0xe5,0xa2,0x19,0x30,0x07,0xe7,0xb2,0x11,0x20,0x07,0xe7,0x92,0x1e,0x0f,0xe8,0x5d,0x00,0x1f,0x9a,0x48,0x78,0x3f,0x20,0x7e,0xc0,0x7e,0xc0,0xbf,0x10,0x7c,0x00,0x3f,0x3c,0x10,0x30,0x7e,0x80,0x84,0x1f,0x85,0x34,0x6f,0xe8,0x3f,0x20,0x60,0xfd,0xc0,0x02,0xcc,0x1f,0x5c,0x08,0x03,0x34,0x81,0xf4,0xbb,0x18,0x70,0x3f,0x26,0x18,0x02,0x01,0x03,0xea,0x21,0x7e,0x1f,0xef,0xc2,0x07,0x10,0x17,0xec,0x02,0x3c,0x0f,0xcb,0x07,0x00,0x18,0x46,0xfb,0xbf,0xa7,0xf8,0x7c,0x40,0xfc,0x8c,0x03,0xfa,0x10,0x0f,0xf0,0x7f,0x43,0x01,0xfd,0x04,0x05,0xd0,0x3f,0xc0,0x1e,0x00,0xf0,0x00,0xe2,0x37,0xd2,0x48,0x25,0x7f,0xe9,0x05,0x8a,0x83,0xe3,0x04,0x0f,0x1a,0x0c,0x52,0x08,0x0f,0x8c,0xc0,0x3f,0xb5,0x19,0xe0,0x78,0xe3,0xfe,0x40,0xf9,0xe4,0x07,0xcb,0x03,0x12,0x07,0xc8,0xfc,0xe0,0x31,0x14,0x1c,0xe2,0x27,0xd1,0xbb,0xe4,0x7f,0xe3,0x7d,0x0f,0xc0,0x03,0xc0,0x1e,0x00,0xb0,}; +const uint8_t *_I_LevelUp2_01[] = {_I_LevelUp2_01_0}; const uint8_t _I_LevelUp3_07_0[] = {0x01,0x00,0x0b,0x01,0x00,0x37,0xf2,0x0e,0x0f,0xd8,0x3c,0xe0,0x1d,0x9c,0x08,0x6f,0xc0,0x1f,0x96,0x08,0xc6,0x42,0x02,0x0f,0xb8,0xc4,0xc2,0x21,0x03,0x07,0xdc,0x12,0x41,0x10,0x81,0x03,0xfa,0x0c,0x0f,0xb8,0x37,0x82,0x3f,0x0c,0x07,0xdc,0x0a,0x31,0x10,0x84,0x03,0xee,0x07,0xcc,0x93,0xc6,0x01,0xf7,0xff,0x92,0x5a,0x62,0x00,0xfb,0xe0,0xc5,0xea,0x33,0x00,0x7d,0xd0,0x72,0x9d,0x39,0x00,0x3f,0x3e,0x99,0xe0,0x7e,0xe5,0x32,0x74,0x00,0x7e,0x45,0x3a,0x34,0x30,0x7e,0x4b,0x29,0x34,0x40,0x7d,0xf0,0xbb,0x17,0xfe,0x40,0x3e,0xf0,0x53,0xfa,0x1f,0xa0,0x1f,0x7f,0xaf,0x9e,0x07,0x4e,0x0f,0xb8,0x66,0x0b,0x01,0x30,0x80,0xb7,0xec,0x18,0x31,0x80,0x7d,0xe0,0xe0,0x10,0x88,0x60,0x3e,0xb0,0x14,0x11,0x88,0x88,0x88,0x01,0x1c,0x0b,0x04,0x02,0x0f,0x02,0x07,0xd4,0x82,0x41,0xe0,0x80,0x03,0xee,0x61,0xa0,0x8f,0x83,0xf2,0x21,0x7e,0x31,0x20,0x02,0x3e,0x10,0x30,0x18,0xc1,0x05,0xf7,0x00,0x1f,0x89,0xbe,0xcb,0xc3,0x3c,0x80,0x43,0xcd,0xf7,0xff,0x81,0xf0,0x20,0x29,0xfb,0x88,0x40,0x2e,0x10,0x00,0x7d,0xc6,0x00,0x24,0x0f,0xb8,0x40,0x04,0x81,0xfe,0x0f,0xb8,0x60,0x3f,0xa0,0x80,0xf2,0x00,0x58,0x3f,0xc0,0x1e,0x00,0xdc,0x46,0xfa,0x49,0x04,0xaf,0xfd,0x20,0xb1,0x50,0x7c,0x60,0x81,0xe3,0x41,0x8a,0x41,0x01,0xf1,0x98,0x07,0xf6,0xa3,0x3c,0x0f,0x1c,0x7f,0xc8,0x1f,0x3c,0x80,0xf9,0x60,0x62,0x40,0xf9,0x1f,0x9c,0x06,0x22,0x83,0x10,0x7c,0x4f,0xa3,0x77,0xc8,0xff,0xc6,0xfa,0x1f,0x80,0x07,0x80,0x3c,0x01,0x60,}; const uint8_t *_I_LevelUp3_07[] = {_I_LevelUp3_07_0}; -const uint8_t _I_LevelUp3_01_0[] = {0x01,0x00,0xf1,0x00,0x00,0x37,0xf2,0x02,0x0f,0xd8,0x3c,0xfc,0x1d,0x9c,0x0e,0x0f,0x84,0x1f,0x96,0x0b,0x86,0x00,0x61,0x91,0x88,0xc4,0x02,0x06,0x0f,0xb8,0x24,0x32,0x01,0x02,0x07,0xe4,0x1a,0x00,0x01,0x10,0x05,0x41,0xbc,0x70,0xf1,0x08,0x80,0x2a,0x05,0x19,0x88,0x42,0x01,0xf7,0x83,0xe6,0xc9,0xca,0x22,0x00,0xaf,0xfe,0x92,0xdf,0x10,0x07,0xde,0x07,0xaf,0x5f,0x98,0x03,0xee,0x03,0xd4,0xef,0x48,0x01,0xfb,0x9f,0x07,0xe5,0x24,0x1e,0x34,0x00,0x7e,0x65,0x3a,0xe0,0xfc,0xa5,0xcb,0x29,0x00,0xfc,0x81,0x76,0x2f,0xf8,0x00,0x7e,0x4f,0xe8,0x60,0xfc,0xfd,0x7c,0x70,0x20,0xfc,0x86,0x03,0x4a,0x02,0xdf,0xb4,0x19,0x83,0xea,0x07,0x00,0x6f,0x08,0x3e,0xb0,0x00,0xb1,0x7f,0x08,0x3e,0xb8,0x00,0x21,0x83,0x83,0xed,0x76,0x3e,0x01,0xfe,0x4c,0x30,0x11,0xf0,0x7e,0x44,0x2f,0xc5,0xfd,0xf8,0x17,0xc4,0x5f,0xa3,0xfe,0xb0,0x40,0x27,0x80,0xfc,0xe0,0x7f,0xc6,0x04,0x9f,0xb8,0x82,0xbf,0xa3,0x00,0xfe,0x5e,0x88,0x3f,0xc1,0xfa,0xcd,0x10,0x7e,0xc1,0x01,0x74,0x0f,0xf0,0x07,0x80,0x3c,0x00,0x38,0x8d,0xf4,0x92,0x09,0x5f,0xfa,0x41,0x62,0xa0,0xf8,0xc1,0x03,0xc6,0x83,0x14,0x82,0x03,0xe3,0x30,0x0f,0xed,0x46,0x78,0x1e,0x38,0xff,0x90,0x3e,0x79,0x01,0xf2,0xc0,0xc4,0x81,0xf2,0x3f,0x38,0x0c,0x45,0x07,0x38,0x89,0xf4,0x6e,0xf9,0x1f,0xf8,0xdf,0x43,0xf0,0x00,0xf0,0x07,0x80,0x2c,}; -const uint8_t *_I_LevelUp3_01[] = {_I_LevelUp3_01_0}; - -const uint8_t _I_LevelUp3_06_0[] = {0x01,0x00,0x30,0x01,0x00,0x37,0xf2,0x0e,0x0f,0xd8,0x3c,0xe0,0x1d,0x9c,0x08,0x6f,0xc0,0x17,0x18,0x00,0x19,0x58,0x23,0x19,0x08,0x08,0x42,0x20,0xc0,0x21,0x8c,0x4c,0x22,0x10,0x30,0x7c,0x43,0x00,0x43,0x04,0x90,0x44,0x20,0x43,0xfb,0x07,0x90,0x94,0xaf,0x03,0x29,0xf0,0x47,0xc4,0xa5,0x0e,0x07,0xc4,0x0a,0x31,0x10,0x84,0x01,0x48,0x1f,0x10,0x3e,0x64,0x9e,0x30,0x3f,0xbf,0xfc,0x92,0xd3,0x10,0x07,0xdf,0x06,0x2f,0x51,0x98,0x03,0xee,0x83,0x94,0xe9,0xc8,0x01,0xf9,0xf4,0xcf,0x03,0xf7,0x29,0x93,0xa0,0x03,0xf2,0x29,0xd1,0xa1,0x83,0xf2,0x59,0x49,0xa2,0x03,0xef,0x85,0xd8,0xbf,0xf2,0x01,0xf7,0x82,0x9f,0xd0,0xfd,0x00,0x51,0xe0,0x03,0xe3,0xf5,0xf3,0xc0,0xe9,0xc0,0xc4,0xb3,0x20,0x00,0xd8,0x1e,0x47,0x82,0xc0,0x4c,0x20,0x22,0xfa,0x83,0x03,0x06,0x30,0x0f,0x76,0xa9,0xe0,0xc5,0x43,0x0c,0x0f,0xd6,0x02,0x82,0x31,0x11,0x11,0x00,0x23,0x80,0x43,0x18,0x3c,0x08,0x1f,0x52,0x09,0x07,0x80,0x6c,0x20,0xfa,0x98,0x68,0x23,0xe0,0xfc,0x88,0x5f,0x8c,0x48,0x00,0x8f,0x84,0x0c,0x06,0x30,0x41,0x7d,0xc0,0x07,0xe2,0x6f,0xb2,0xf0,0xcf,0x20,0x10,0xf3,0x7d,0xff,0xe0,0x7c,0x08,0x08,0x3e,0x18,0xa5,0x10,0x80,0x5c,0x20,0x00,0xf1,0x67,0x20,0x01,0x23,0x00,0x12,0x07,0xc3,0x00,0x81,0x22,0x01,0x11,0x7c,0x1b,0x08,0x1e,0xb2,0x06,0x62,0xbf,0xcc,0x3f,0x60,0x02,0x82,0x12,0xe8,0x1f,0xe0,0x0f,0x00,0x78,0x00,0x71,0x1b,0xe9,0x24,0x12,0xbf,0xf4,0x82,0xc5,0x41,0xf1,0x82,0x07,0x8d,0x06,0x29,0x04,0x07,0xc6,0x60,0x1f,0xda,0x8c,0xf0,0x3c,0x71,0xff,0x20,0x7c,0xf2,0x03,0xe5,0x81,0x89,0x03,0xe4,0x7e,0x70,0x18,0x8a,0x0c,0x41,0xf1,0x3e,0x8d,0xdf,0x23,0xff,0x1b,0xe8,0x7e,0x00,0x1e,0x00,0xf0,0x05,0x80,}; -const uint8_t *_I_LevelUp3_06[] = {_I_LevelUp3_06_0}; +const uint8_t _I_LevelUp3_02_0[] = {0x01,0x00,0xf4,0x00,0x00,0x37,0xf2,0x02,0x0f,0xda,0xbc,0xfc,0x1d,0x9c,0x0f,0x5f,0xac,0x1f,0x97,0x0b,0xaf,0x54,0x61,0x9b,0x8d,0xd6,0xaa,0x06,0x0f,0xba,0xa5,0x76,0xaa,0x0f,0xcd,0x66,0xbb,0x55,0x06,0x07,0xdd,0x5b,0xef,0x5f,0x86,0x83,0xef,0x55,0xbb,0xdd,0x42,0x81,0xf7,0xd7,0xee,0xdd,0xe3,0xa0,0xfb,0xff,0xeb,0xbd,0xf1,0xa0,0x7d,0xf5,0x7a,0xf5,0xf9,0xa8,0x3e,0xf5,0x7f,0xef,0xf4,0xa8,0x1f,0x75,0x5e,0xaf,0x7e,0xea,0x0f,0xbf,0x5f,0xfb,0x7f,0x6a,0x07,0xdd,0x74,0x80,0x35,0x50,0xfe,0x6b,0xbd,0x5e,0xa4,0xfe,0x77,0x6f,0xfd,0x54,0xfe,0x6f,0xfd,0x7a,0xa0,0x7d,0xff,0xbe,0xbd,0x5e,0xac,0x04,0x1f,0x4d,0xe1,0x00,0x08,0x3e,0xea,0xd5,0x50,0x00,0x83,0xef,0x56,0x1f,0xdc,0x00,0x74,0x6b,0xa1,0xfb,0xe0,0x07,0x47,0x5e,0x1f,0xbb,0x05,0x57,0xea,0x3f,0xcd,0x81,0xfc,0x47,0xf9,0x50,0xbf,0x97,0xf7,0xe0,0x5f,0xeb,0x80,0xff,0xbc,0x1a,0xad,0xf0,0x7f,0x38,0x1f,0xfa,0xba,0x7f,0x4c,0x02,0xbf,0xda,0xc2,0xff,0xb5,0x01,0xff,0x0f,0xf6,0xb0,0x3f,0xd5,0x40,0xff,0x87,0xc8,0x1d,0x40,0x0f,0x00,0x76,0x23,0x7d,0x24,0x82,0x57,0xfe,0x90,0x58,0xa8,0x3e,0x30,0x40,0xf1,0xa0,0xc5,0x20,0x80,0xf8,0xcc,0x03,0xfb,0x51,0x9e,0x07,0x8e,0x3f,0xe4,0x0f,0x9e,0x40,0x7c,0xb0,0x31,0x20,0x7c,0x8f,0xce,0x03,0x11,0x82,0x17,0xe6,0x7d,0x1b,0xbe,0x47,0xfe,0x37,0xd0,0xfc,0x00,0x3c,0x01,0xe0,0x0b,}; +const uint8_t *_I_LevelUp3_02[] = {_I_LevelUp3_02_0}; const uint8_t _I_LevelUp3_04_0[] = {0x01,0x00,0x21,0x01,0x00,0x37,0xf2,0x0e,0x0f,0xda,0xbc,0xf4,0x1d,0x9c,0x0d,0x7f,0xe8,0x1f,0x97,0x0a,0xef,0x56,0x02,0x0f,0xbd,0xc6,0xeb,0x75,0x03,0x07,0xdd,0x52,0xeb,0x55,0x07,0xe6,0xb3,0x55,0xba,0x83,0x03,0xee,0xad,0xf5,0xaf,0xc3,0x41,0xf6,0x1e,0x1d,0xd4,0x28,0xfd,0x9d,0xdb,0xbc,0x74,0x1f,0x7f,0xfd,0x77,0xae,0x34,0x0f,0xbe,0xad,0x5e,0xab,0x35,0x06,0xcc,0x12,0x01,0xeb,0xdf,0x7e,0xe5,0x56,0x00,0x7c,0x47,0x20,0x15,0x5f,0xaf,0x7e,0xeb,0x38,0x07,0xc4,0xc0,0x3e,0x5b,0xbb,0x54,0x20,0x7f,0x55,0x5a,0xa9,0x04,0x49,0xf7,0xeb,0x2f,0x8f,0xb8,0x1f,0x7d,0x6e,0xed,0xff,0xba,0x9f,0xcd,0xff,0xaf,0xd4,0x0f,0xbf,0xf7,0xdf,0xab,0xf7,0xf8,0x83,0xeb,0x5d,0xaa,0x60,0x8c,0x04,0x1b,0x10,0x26,0xf8,0x98,0x06,0xba,0x0f,0x98,0x74,0x03,0x56,0x1f,0x1d,0x70,0x3e,0x63,0x18,0x00,0xf1,0x55,0xc1,0xf3,0x00,0xe0,0x7a,0xb5,0x5a,0xfd,0x50,0x3e,0xac,0x17,0x5f,0xad,0x56,0xaf,0xc1,0x07,0xce,0xc0,0xfe,0x24,0x01,0xc0,0xc0,0xc1,0xf1,0x50,0xbf,0x90,0x04,0x7f,0x7f,0x02,0xfe,0xc0,0x2e,0x0f,0xf1,0x3f,0xdf,0x03,0xc3,0xaa,0xdf,0x18,0x04,0x1f,0x37,0x0e,0x07,0xfe,0xaf,0xd5,0xaa,0x8b,0xe8,0xc0,0x5f,0xa3,0xfd,0xc0,0x2b,0x03,0xe1,0x0f,0xe6,0xa0,0xbe,0x21,0xff,0x0f,0xe6,0xb0,0x3f,0xd5,0x40,0xff,0x87,0xc8,0x1d,0x40,0x0f,0x00,0x76,0x23,0x7d,0x24,0x82,0x57,0xfe,0x90,0x58,0xa8,0x3e,0x30,0x40,0xf1,0xa0,0xc5,0x20,0x80,0xf8,0xcc,0x03,0xfb,0x51,0x9e,0x07,0x8e,0x3f,0xe4,0x0f,0x9e,0x40,0x7c,0xb0,0x31,0x20,0x7c,0x8f,0xce,0x03,0x11,0x82,0x17,0xe6,0x7d,0x1b,0xbe,0x47,0xfe,0x37,0xd0,0xfc,0x00,0x3c,0x01,0xe0,0x0b,}; const uint8_t *_I_LevelUp3_04[] = {_I_LevelUp3_04_0}; -const uint8_t _I_LevelUp3_02_0[] = {0x01,0x00,0xf4,0x00,0x00,0x37,0xf2,0x02,0x0f,0xda,0xbc,0xfc,0x1d,0x9c,0x0f,0x5f,0xac,0x1f,0x97,0x0b,0xaf,0x54,0x61,0x9b,0x8d,0xd6,0xaa,0x06,0x0f,0xba,0xa5,0x76,0xaa,0x0f,0xcd,0x66,0xbb,0x55,0x06,0x07,0xdd,0x5b,0xef,0x5f,0x86,0x83,0xef,0x55,0xbb,0xdd,0x42,0x81,0xf7,0xd7,0xee,0xdd,0xe3,0xa0,0xfb,0xff,0xeb,0xbd,0xf1,0xa0,0x7d,0xf5,0x7a,0xf5,0xf9,0xa8,0x3e,0xf5,0x7f,0xef,0xf4,0xa8,0x1f,0x75,0x5e,0xaf,0x7e,0xea,0x0f,0xbf,0x5f,0xfb,0x7f,0x6a,0x07,0xdd,0x74,0x80,0x35,0x50,0xfe,0x6b,0xbd,0x5e,0xa4,0xfe,0x77,0x6f,0xfd,0x54,0xfe,0x6f,0xfd,0x7a,0xa0,0x7d,0xff,0xbe,0xbd,0x5e,0xac,0x04,0x1f,0x4d,0xe1,0x00,0x08,0x3e,0xea,0xd5,0x50,0x00,0x83,0xef,0x56,0x1f,0xdc,0x00,0x74,0x6b,0xa1,0xfb,0xe0,0x07,0x47,0x5e,0x1f,0xbb,0x05,0x57,0xea,0x3f,0xcd,0x81,0xfc,0x47,0xf9,0x50,0xbf,0x97,0xf7,0xe0,0x5f,0xeb,0x80,0xff,0xbc,0x1a,0xad,0xf0,0x7f,0x38,0x1f,0xfa,0xba,0x7f,0x4c,0x02,0xbf,0xda,0xc2,0xff,0xb5,0x01,0xff,0x0f,0xf6,0xb0,0x3f,0xd5,0x40,0xff,0x87,0xc8,0x1d,0x40,0x0f,0x00,0x76,0x23,0x7d,0x24,0x82,0x57,0xfe,0x90,0x58,0xa8,0x3e,0x30,0x40,0xf1,0xa0,0xc5,0x20,0x80,0xf8,0xcc,0x03,0xfb,0x51,0x9e,0x07,0x8e,0x3f,0xe4,0x0f,0x9e,0x40,0x7c,0xb0,0x31,0x20,0x7c,0x8f,0xce,0x03,0x11,0x82,0x17,0xe6,0x7d,0x1b,0xbe,0x47,0xfe,0x37,0xd0,0xfc,0x00,0x3c,0x01,0xe0,0x0b,}; -const uint8_t *_I_LevelUp3_02[] = {_I_LevelUp3_02_0}; - const uint8_t _I_LevelUp3_05_0[] = {0x01,0x00,0x34,0x01,0x00,0x37,0xf2,0x0e,0x0f,0xd8,0x3c,0xe0,0x1d,0x9c,0x08,0x6f,0xc0,0x1f,0x96,0x08,0xc6,0x42,0x02,0x0f,0xb8,0xc4,0xc2,0x21,0x03,0x07,0xdc,0x12,0x41,0x10,0x81,0x03,0xfa,0x0c,0x0f,0xb8,0x37,0x82,0x3f,0x0c,0x06,0x45,0x00,0x04,0x30,0x28,0xc4,0x42,0x10,0x6c,0x90,0x10,0xc0,0xf9,0x92,0x78,0xc0,0x5c,0xc0,0x09,0x80,0x35,0x0f,0xfe,0x49,0x69,0x88,0x40,0x2f,0x82,0x07,0x35,0x0f,0x06,0x2f,0x51,0x98,0x60,0x16,0x50,0x5a,0x1a,0x0e,0x53,0xa7,0x20,0x1b,0x11,0xb5,0xc1,0xe3,0xf4,0xcf,0x48,0x0d,0xf6,0x1f,0x1c,0x99,0x35,0xc1,0xeb,0x14,0xe8,0xd0,0xc1,0xf9,0x2c,0xa4,0xd1,0x01,0xf7,0xc2,0xec,0x5f,0xf9,0x00,0xfb,0xc1,0x4f,0xe8,0x7e,0x80,0x7d,0xfe,0xbe,0x78,0x1d,0x3c,0x03,0xfd,0x0f,0x06,0x2c,0x70,0x04,0x30,0xcc,0x16,0x02,0x60,0xa5,0x10,0x03,0x5c,0x12,0x24,0x0c,0x18,0xc0,0x3e,0x13,0x05,0x83,0x80,0x42,0x21,0x80,0xf8,0x68,0x95,0x04,0x62,0x22,0x22,0x78,0xcd,0x82,0x01,0x07,0x81,0x03,0xea,0x41,0x20,0xf0,0x40,0x01,0xf7,0x30,0xd0,0x47,0xc1,0xf9,0x10,0xbf,0x18,0x90,0x01,0x1f,0x08,0x1b,0xd0,0xa0,0x33,0x01,0x7c,0xc0,0x07,0xe2,0x6f,0x10,0x18,0x80,0x1c,0xbc,0x33,0xc8,0x04,0x3e,0x03,0x80,0x18,0xb7,0x82,0x3f,0xc0,0xff,0xc0,0xf8,0x10,0x11,0xfc,0x4e,0x0a,0x04,0xb4,0x22,0x7d,0x2f,0x04,0x02,0x40,0xfb,0x84,0x00,0x48,0x1f,0xe0,0xfb,0x86,0x03,0xfa,0x08,0x0f,0x20,0x05,0x83,0xfc,0x01,0xe0,0x0d,0xc4,0x6f,0xa4,0x90,0x4a,0xff,0xd2,0x0b,0x15,0x07,0xc6,0x08,0x1e,0x34,0x18,0xa4,0x10,0x1f,0x19,0x80,0x7f,0x6a,0x33,0xc0,0xf1,0xc7,0xfc,0x81,0xf3,0xc8,0x0f,0x96,0x06,0x24,0x0f,0x91,0xf9,0xc0,0x62,0x28,0x31,0x07,0xc4,0xfa,0x37,0x7c,0x8f,0xfc,0x6f,0xa1,0xf8,0x00,0x78,0x03,0xc0,0x16,}; const uint8_t *_I_LevelUp3_05[] = {_I_LevelUp3_05_0}; +const uint8_t _I_LevelUp3_01_0[] = {0x01,0x00,0xf1,0x00,0x00,0x37,0xf2,0x02,0x0f,0xd8,0x3c,0xfc,0x1d,0x9c,0x0e,0x0f,0x84,0x1f,0x96,0x0b,0x86,0x00,0x61,0x91,0x88,0xc4,0x02,0x06,0x0f,0xb8,0x24,0x32,0x01,0x02,0x07,0xe4,0x1a,0x00,0x01,0x10,0x05,0x41,0xbc,0x70,0xf1,0x08,0x80,0x2a,0x05,0x19,0x88,0x42,0x01,0xf7,0x83,0xe6,0xc9,0xca,0x22,0x00,0xaf,0xfe,0x92,0xdf,0x10,0x07,0xde,0x07,0xaf,0x5f,0x98,0x03,0xee,0x03,0xd4,0xef,0x48,0x01,0xfb,0x9f,0x07,0xe5,0x24,0x1e,0x34,0x00,0x7e,0x65,0x3a,0xe0,0xfc,0xa5,0xcb,0x29,0x00,0xfc,0x81,0x76,0x2f,0xf8,0x00,0x7e,0x4f,0xe8,0x60,0xfc,0xfd,0x7c,0x70,0x20,0xfc,0x86,0x03,0x4a,0x02,0xdf,0xb4,0x19,0x83,0xea,0x07,0x00,0x6f,0x08,0x3e,0xb0,0x00,0xb1,0x7f,0x08,0x3e,0xb8,0x00,0x21,0x83,0x83,0xed,0x76,0x3e,0x01,0xfe,0x4c,0x30,0x11,0xf0,0x7e,0x44,0x2f,0xc5,0xfd,0xf8,0x17,0xc4,0x5f,0xa3,0xfe,0xb0,0x40,0x27,0x80,0xfc,0xe0,0x7f,0xc6,0x04,0x9f,0xb8,0x82,0xbf,0xa3,0x00,0xfe,0x5e,0x88,0x3f,0xc1,0xfa,0xcd,0x10,0x7e,0xc1,0x01,0x74,0x0f,0xf0,0x07,0x80,0x3c,0x00,0x38,0x8d,0xf4,0x92,0x09,0x5f,0xfa,0x41,0x62,0xa0,0xf8,0xc1,0x03,0xc6,0x83,0x14,0x82,0x03,0xe3,0x30,0x0f,0xed,0x46,0x78,0x1e,0x38,0xff,0x90,0x3e,0x79,0x01,0xf2,0xc0,0xc4,0x81,0xf2,0x3f,0x38,0x0c,0x45,0x07,0x38,0x89,0xf4,0x6e,0xf9,0x1f,0xf8,0xdf,0x43,0xf0,0x00,0xf0,0x07,0x80,0x2c,}; +const uint8_t *_I_LevelUp3_01[] = {_I_LevelUp3_01_0}; + +const uint8_t _I_LevelUp3_03_0[] = {0x01,0x00,0xa3,0x00,0x00,0x37,0xf2,0x02,0x0f,0xdf,0xfc,0xfc,0x1d,0x9c,0x0f,0xff,0xfc,0x1f,0x9f,0x00,0x78,0x8c,0x33,0xf0,0x0f,0x18,0x19,0x3b,0x01,0xfe,0x0f,0x18,0x38,0x3e,0xff,0xc0,0xf1,0x87,0x83,0xfc,0xfd,0x80,0x01,0x8f,0x83,0xfc,0x1f,0xca,0x0c,0x07,0xf8,0x3c,0xaf,0xe0,0xff,0x07,0xf8,0x3f,0x9c,0x18,0x8f,0x20,0x7f,0x83,0xff,0xff,0x01,0x07,0xf8,0x3f,0xcb,0xfc,0x0f,0xac,0x00,0x3f,0xb8,0x00,0xfe,0xf0,0x03,0xfb,0xe0,0x0f,0xf0,0x7f,0x83,0xfc,0x9f,0xe6,0xff,0x07,0xf0,0xc1,0x01,0xf7,0xf8,0x07,0xf8,0x3f,0xc1,0xfd,0xfc,0x07,0xf8,0x3f,0xc1,0xfc,0x00,0xf0,0x06,0xe2,0x37,0xd2,0x48,0x25,0x7f,0xe9,0x05,0x8a,0x83,0xe3,0x04,0x0f,0x1a,0x0c,0x52,0x08,0x0f,0x8c,0xc0,0x3f,0xb5,0x19,0xe0,0x78,0xe3,0xfe,0x40,0xf9,0xe4,0x07,0xcb,0x03,0x12,0x07,0xc8,0xfc,0xe0,0x31,0x18,0x21,0x7e,0x67,0xd1,0xbb,0xe4,0x7f,0xe3,0x7d,0x0f,0xc0,0x03,0xc0,0x1e,0x00,0xb0,}; +const uint8_t *_I_LevelUp3_03[] = {_I_LevelUp3_03_0}; + +const uint8_t _I_LevelUp3_06_0[] = {0x01,0x00,0x30,0x01,0x00,0x37,0xf2,0x0e,0x0f,0xd8,0x3c,0xe0,0x1d,0x9c,0x08,0x6f,0xc0,0x17,0x18,0x00,0x19,0x58,0x23,0x19,0x08,0x08,0x42,0x20,0xc0,0x21,0x8c,0x4c,0x22,0x10,0x30,0x7c,0x43,0x00,0x43,0x04,0x90,0x44,0x20,0x43,0xfb,0x07,0x90,0x94,0xaf,0x03,0x29,0xf0,0x47,0xc4,0xa5,0x0e,0x07,0xc4,0x0a,0x31,0x10,0x84,0x01,0x48,0x1f,0x10,0x3e,0x64,0x9e,0x30,0x3f,0xbf,0xfc,0x92,0xd3,0x10,0x07,0xdf,0x06,0x2f,0x51,0x98,0x03,0xee,0x83,0x94,0xe9,0xc8,0x01,0xf9,0xf4,0xcf,0x03,0xf7,0x29,0x93,0xa0,0x03,0xf2,0x29,0xd1,0xa1,0x83,0xf2,0x59,0x49,0xa2,0x03,0xef,0x85,0xd8,0xbf,0xf2,0x01,0xf7,0x82,0x9f,0xd0,0xfd,0x00,0x51,0xe0,0x03,0xe3,0xf5,0xf3,0xc0,0xe9,0xc0,0xc4,0xb3,0x20,0x00,0xd8,0x1e,0x47,0x82,0xc0,0x4c,0x20,0x22,0xfa,0x83,0x03,0x06,0x30,0x0f,0x76,0xa9,0xe0,0xc5,0x43,0x0c,0x0f,0xd6,0x02,0x82,0x31,0x11,0x11,0x00,0x23,0x80,0x43,0x18,0x3c,0x08,0x1f,0x52,0x09,0x07,0x80,0x6c,0x20,0xfa,0x98,0x68,0x23,0xe0,0xfc,0x88,0x5f,0x8c,0x48,0x00,0x8f,0x84,0x0c,0x06,0x30,0x41,0x7d,0xc0,0x07,0xe2,0x6f,0xb2,0xf0,0xcf,0x20,0x10,0xf3,0x7d,0xff,0xe0,0x7c,0x08,0x08,0x3e,0x18,0xa5,0x10,0x80,0x5c,0x20,0x00,0xf1,0x67,0x20,0x01,0x23,0x00,0x12,0x07,0xc3,0x00,0x81,0x22,0x01,0x11,0x7c,0x1b,0x08,0x1e,0xb2,0x06,0x62,0xbf,0xcc,0x3f,0x60,0x02,0x82,0x12,0xe8,0x1f,0xe0,0x0f,0x00,0x78,0x00,0x71,0x1b,0xe9,0x24,0x12,0xbf,0xf4,0x82,0xc5,0x41,0xf1,0x82,0x07,0x8d,0x06,0x29,0x04,0x07,0xc6,0x60,0x1f,0xda,0x8c,0xf0,0x3c,0x71,0xff,0x20,0x7c,0xf2,0x03,0xe5,0x81,0x89,0x03,0xe4,0x7e,0x70,0x18,0x8a,0x0c,0x41,0xf1,0x3e,0x8d,0xdf,0x23,0xff,0x1b,0xe8,0x7e,0x00,0x1e,0x00,0xf0,0x05,0x80,}; +const uint8_t *_I_LevelUp3_06[] = {_I_LevelUp3_06_0}; + const uint8_t _A_LevelUpPending_128x51_0[] = {0x01,0x00,0xa9,0x01,0x00,0x1c,0xfc,0x1d,0xbf,0x0e,0x04,0x04,0x1f,0x90,0xc8,0x04,0x18,0x1f,0x90,0x28,0x04,0x20,0x1d,0x62,0xd2,0x98,0x03,0xfe,0x01,0x80,0xf9,0xdf,0x39,0xd8,0x7f,0x45,0x2e,0xe4,0x2b,0x18,0x04,0x80,0x04,0x34,0x00,0x08,0xc5,0x20,0xb1,0x1c,0x0c,0xa2,0x91,0x8a,0x07,0x94,0x40,0x04,0x38,0x00,0x78,0xc4,0x01,0xe5,0x29,0xa4,0x42,0x81,0xe7,0xf8,0x07,0x8c,0x06,0x81,0xf6,0x9e,0x47,0xf0,0x3e,0xaa,0x48,0xbc,0xe1,0x10,0x48,0x0e,0x02,0x07,0x40,0xaa,0x41,0x03,0xe3,0x2c,0xa4,0x60,0x81,0xe5,0x00,0xba,0x40,0xbe,0x1d,0xfa,0x06,0x50,0x1e,0x43,0xf2,0x07,0x16,0x13,0x77,0x02,0x86,0x70,0x30,0x31,0x3b,0xe8,0x3c,0x7d,0x1b,0x3b,0x88,0x7c,0xa8,0x9f,0xa8,0x14,0x0e,0x00,0xb1,0xad,0x17,0xef,0x84,0x04,0x10,0x7d,0x78,0xae,0x72,0x20,0x7f,0x83,0xf3,0xf3,0x07,0x88,0xc0,0x3f,0xe0,0xf4,0x53,0x08,0x00,0xe8,0xb8,0xc2,0xf0,0xd5,0x60,0x1f,0x09,0xe6,0x7f,0xc7,0xc0,0x07,0x1e,0x03,0x09,0x79,0x81,0xfe,0x35,0x4a,0x51,0xa2,0xd0,0x62,0x9c,0x11,0x29,0xe0,0x30,0x42,0xe1,0xae,0x07,0xc4,0x1e,0x51,0x0e,0x01,0xdc,0x41,0xe6,0x15,0x1d,0x7d,0xa8,0x5e,0x58,0xf1,0x78,0x83,0xce,0xc1,0x81,0x5f,0x0d,0x56,0x6a,0x1f,0x18,0xa4,0x06,0x08,0x2f,0x40,0x78,0xc0,0xf8,0x1a,0xa8,0xd0,0x3c,0x64,0x83,0xf2,0x27,0x9f,0x81,0xb8,0x3e,0x0a,0xbc,0x74,0x1e,0x34,0x42,0xf8,0x9b,0xd3,0xe1,0x80,0x83,0xfe,0x35,0xf1,0xf4,0x74,0xdc,0x20,0x10,0xaf,0xf7,0xfe,0x66,0x0f,0xbf,0xd7,0xfc,0x1f,0xbc,0x20,0x78,0xc8,0x41,0xf3,0x18,0x80,0x40,0xa7,0xfc,0x09,0x18,0x3f,0x2f,0xd0,0x0f,0x78,0x3f,0x3f,0x90,0x1e,0xe0,0x3e,0x61,0x00,0xf2,0x83,0xfc,0x01,0xf9,0xa8,0x8f,0xf0,0x1f,0xe8,0x0f,0x7a,0x87,0xff,0xc2,0x0f,0x98,0x20,0x3c,0x74,0x1f,0xad,0xfb,0x64,0xc1,0xed,0x80,0x80,0xd0,0x2a,0xb8,0x70,0x7e,0x60,0x35,0x70,0x60,0x7c,0xc0,0x81,0xe3,0x00,0xab,0x41,0x60,0xc0,0xfb,0x84,0x6f,0x21,0xc4,0x51,0x00,0x38,0xb4,0x60,0x37,0x0f,0x84,0x3c,0x1f,0x03,0xd2,0x27,0x8a,0x90,0x61,0x80,0xf8,0x08,0x9c,0x0e,0x18,0xb5,0x10,0x03,0x70,0x20,0x01,0xd1,0x80,0x77,0xa1,0xf1,0x00,0x7b,0x83,0x44,0x1e,0x5f,0x08,0x3c,0xc0,0x1f,0x83,0x01,0x90,0x03,0xde,0xc0,0x0f,0x33,0xa0,0x81,0x0c,0x00,0x81,0x81,0x07,0xa1,0x18,0x40,0x0c,0x38,0x11,0x51,0xc1,0x8c,0xc2,0x00,0x62,0xc0,0x83,0xcd,0x1c,0x2f,0x07,0x3c,0x08,0x3f,0x61,0x00,0xf4,0x02,0x8b,0x81,0xc0,}; const uint8_t _A_LevelUpPending_128x51_1[] = {0x01,0x00,0xad,0x01,0x00,0x1c,0xfc,0x1d,0xbf,0x0e,0x04,0x04,0x1f,0x90,0xc8,0x04,0x18,0x1f,0x90,0x28,0x04,0x20,0x1d,0x62,0xd2,0x98,0x03,0xfe,0x01,0x80,0xf9,0xdf,0x39,0xd8,0x7f,0x45,0x2e,0xe4,0x2b,0x18,0x04,0x80,0x04,0x34,0x00,0x08,0xc5,0x20,0xb1,0x1c,0x0c,0xa2,0x91,0x8a,0x07,0x94,0x40,0x04,0x38,0x00,0x78,0xc4,0x01,0xe5,0x29,0xa4,0x42,0x81,0xe7,0xf8,0x07,0x8c,0x06,0x81,0xf6,0x9e,0x47,0xf0,0x3e,0xaa,0x48,0xbc,0xe1,0x10,0x48,0x0e,0x02,0x07,0x40,0xaa,0x41,0x03,0xe3,0x2c,0xa4,0x60,0x81,0xe5,0x00,0xba,0x40,0xbe,0x1d,0xfa,0x06,0x50,0x1e,0x43,0xf2,0x07,0x16,0x13,0x75,0x02,0x86,0x70,0x30,0x31,0x3b,0xe8,0x3c,0x7d,0x1b,0x3b,0x88,0x7c,0xa8,0x9f,0xa8,0x14,0x0e,0x00,0xb1,0xad,0x17,0xeb,0x84,0x04,0x10,0x7d,0x50,0xae,0x72,0x20,0x7e,0x68,0x81,0xfd,0x81,0x83,0xc4,0x60,0x1f,0xf0,0x7a,0x29,0x84,0x00,0x74,0x1c,0x61,0x78,0x6a,0xb0,0x0f,0x84,0xf3,0x3f,0xe3,0xe0,0x03,0x8f,0x01,0x3c,0xbc,0x40,0xff,0x1a,0xa5,0x28,0xd1,0x68,0x31,0x4e,0x08,0x94,0xf0,0x16,0x26,0x00,0xd7,0x03,0xe2,0x0f,0x28,0x87,0x00,0xee,0x20,0xf2,0x36,0x96,0xbe,0xd4,0x2f,0x2c,0x78,0xbc,0x41,0xe9,0x82,0x01,0x0d,0x56,0x6a,0x1f,0x18,0xa4,0x06,0x08,0x2f,0x4e,0x00,0x3c,0x78,0x1a,0xa8,0xd0,0x3c,0x64,0x83,0xf2,0x27,0x98,0x3c,0x60,0x3e,0x0a,0xbc,0x34,0x1e,0x34,0x42,0xf8,0x9b,0xd3,0x81,0x83,0x82,0xfe,0x35,0xf0,0xf4,0x74,0xf0,0x20,0x30,0x9f,0xf7,0xfe,0x16,0x0f,0x9f,0x04,0x07,0xf3,0xff,0x07,0xe4,0x03,0x82,0x0f,0x15,0x88,0x83,0xea,0x03,0x0f,0xe0,0x24,0x84,0x01,0x17,0x00,0x78,0xcf,0xa0,0x13,0x30,0x7e,0x7c,0x20,0x13,0x60,0x7e,0x70,0x21,0xf7,0xc0,0x7c,0xca,0x01,0xe3,0x00,0xff,0x5f,0xc1,0xf3,0x38,0x07,0x97,0xc3,0xa6,0x0f,0x98,0xc0,0x3c,0xa8,0x1b,0x00,0x7c,0xc2,0x30,0x10,0x18,0x64,0x03,0x30,0x0f,0xc1,0x90,0xc4,0x1d,0x26,0x00,0x58,0x20,0x3c,0x7c,0x10,0x78,0xe0,0x3f,0x30,0x1f,0xd8,0x38,0xbe,0x60,0x40,0xf1,0x80,0x00,0x86,0x04,0x0f,0x88,0x18,0x3c,0x8c,0x43,0x04,0x07,0xc0,0xb4,0x43,0xe6,0x0f,0x80,0x50,0xd0,0x00,0x83,0xc0,0x81,0xc2,0x01,0xef,0xc0,0x46,0x08,0x10,0x64,0x10,0x20,0x7c,0x03,0x44,0x1e,0x58,0x08,0x1a,0x94,0x40,0x0d,0x60,0x07,0x99,0x90,0x66,0x00,0xf7,0x90,0x03,0xd4,0x0c,0x20,0x06,0x0c,0x08,0x28,0xe0,0xc4,0x61,0x00,0x34,0x40,0x1e,0x8a,0x41,0x77,0x48,0x3d,0x58,0x0e,0x68,0x10,0x79,0x81,0x46,0x06,0x0f,0x60,}; const uint8_t *_A_LevelUpPending_128x51[] = {_A_LevelUpPending_128x51_0,_A_LevelUpPending_128x51_1}; @@ -276,20 +276,11 @@ const uint8_t _A_Waves_128x52_0[] = {0x01,0x00,0xba,0x01,0x00,0x78,0x03,0xc0,0x0 const uint8_t _A_Waves_128x52_1[] = {0x01,0x00,0xbf,0x01,0x00,0x78,0x03,0xc0,0x0f,0xe0,0xf3,0xc0,0xc0,0x83,0xf8,0x07,0xce,0x03,0xff,0x0f,0x0a,0x10,0x4c,0x80,0x0f,0xfe,0x8e,0x01,0x08,0x1f,0x57,0xc0,0x19,0x7c,0x20,0xe0,0xf9,0xff,0xc0,0x47,0xe5,0xff,0x1f,0xce,0x7c,0x36,0x51,0xcf,0xf8,0xc2,0x30,0x11,0x92,0x79,0x61,0x23,0xe3,0x08,0xe0,0x46,0x61,0x00,0x42,0x9e,0x8b,0xe2,0x81,0x18,0x42,0x1c,0xe0,0x08,0x62,0x34,0x07,0xa7,0xc2,0xe0,0x04,0x2c,0x81,0x60,0x80,0x04,0x0f,0x3b,0x87,0x00,0x32,0x60,0xf5,0x15,0x1d,0xe3,0x00,0x0f,0xbf,0xf4,0x7e,0xf0,0x06,0x11,0xe1,0x40,0x81,0xeb,0xc0,0xff,0xff,0xc1,0xe5,0x7a,0x07,0x9f,0xf8,0x14,0x20,0x02,0x81,0xfc,0x3f,0x60,0xc1,0xea,0x88,0x06,0x05,0xff,0xaa,0x80,0x0e,0xfa,0xe3,0x20,0x78,0xea,0xa7,0xfe,0x0f,0xfe,0xa8,0x00,0x91,0xe0,0x60,0xef,0xa1,0xfe,0x0a,0xaf,0xfe,0xbe,0x1c,0x3a,0xa5,0x56,0xa2,0xaf,0x2b,0xc7,0xd6,0xbf,0xea,0x0e,0x9e,0x2b,0x55,0x2a,0xff,0x6a,0xcb,0x25,0xe0,0xd5,0xea,0x87,0x48,0x00,0x2f,0xff,0x5d,0xb4,0x5c,0x0a,0xbd,0x54,0x76,0xa0,0x01,0x81,0xef,0xd0,0xc7,0xaf,0x0f,0xa7,0x56,0xac,0x02,0x18,0x0f,0xf0,0x1e,0x75,0xe0,0xfa,0x4a,0xb5,0x1a,0xaf,0x53,0x2c,0x52,0x87,0xbc,0x0f,0x9f,0xd7,0xff,0x7f,0xaa,0xdd,0x47,0x62,0x0f,0x3b,0xc5,0x44,0x3c,0x50,0xe0,0x58,0xeb,0xed,0x48,0xc1,0x17,0x9f,0xc0,0x3e,0x34,0x5e,0xa9,0x60,0x8f,0x02,0x0d,0x16,0x31,0xd8,0x07,0xe4,0xc1,0x21,0x00,0xfb,0xcf,0xa3,0x0c,0x03,0x97,0x80,0x7e,0x49,0x72,0x10,0x10,0x34,0x66,0x01,0x73,0x43,0x8f,0xfd,0xfc,0x93,0x00,0x68,0xd0,0x01,0xe7,0xab,0x7d,0xa0,0x3c,0x8b,0xc7,0x3e,0x2a,0x0d,0x54,0x1e,0xf0,0x01,0x31,0x3b,0x85,0xe2,0x60,0x04,0xb8,0x17,0x8c,0x74,0x46,0xb2,0x00,0x27,0x82,0x01,0x04,0x3e,0x90,0x34,0x5c,0x84,0x00,0x4e,0x04,0x06,0x30,0x04,0x20,0x78,0xc1,0x81,0xed,0x80,0x81,0xc8,0x01,0xe4,0x1d,0x10,0x7b,0xff,0x20,0xe6,0x02,0xc0,0x03,0xc7,0xfc,0x1e,0x76,0x20,0x8b,0x04,0x1e,0x50,0xc2,0x82,0xde,0x20,0x11,0xc2,0x81,0x03,0xce,0xf8,0x6b,0x32,0xb1,0x4e,0x20,0x05,0x01,0x12,0x88,0x58,0x70,0x17,0xf8,0x03,0x01,0x02,0x83,0x60,0x58,0x8c,0x14,0x4c,0x49,0x26,0x40,0x0e,0x03,0x03,0xa0,0x85,0x09,0x09,0x01,0x10,0x0b,0xf0,0x7c,0x86,0xc2,0x80,0x74,0xc9,0x07,0xc8,0x1f,0x10,0x03,0x80,0x8f,0xcf,0xf0,0x0f,0x89,0xe0,0x15,0x39,0x00,0xf8,0xfe,0x7f,0xff,0xe6,0xa1,0x80,0x42,0x07,0xcf,0xff,0x4c,0x16,0x02,0x3e,0x0f,0x6f,0x84,0x07,0xf8,0x74,0x60,0xfb,0x7f,0x96,0xcb,0x00,0xbf,0xe2,0x07,0xf0,0x36,0x5b,0xf8,}; const uint8_t *_A_Waves_128x52[] = {_A_Waves_128x52_0,_A_Waves_128x52_1}; -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 *_I_Nfc_10px[] = {_I_Nfc_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 *_I_ir_10px[] = {_I_ir_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 *_I_ble_10px[] = {_I_ble_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 *_I_sub1_10px[] = {_I_sub1_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 *_I_dir_10px[] = {_I_dir_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 *_I_ir_10px[] = {_I_ir_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 *_I_unknown_10px[] = {_I_unknown_10px_0}; @@ -297,50 +288,59 @@ const uint8_t *_I_unknown_10px[] = {_I_unknown_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 *_I_ibutt_10px[] = {_I_ibutt_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 *_I_Nfc_10px[] = {_I_Nfc_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 *_I_ble_10px[] = {_I_ble_10px_0}; + 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 *_I_125_10px[] = {_I_125_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 *_I_dir_10px[] = {_I_dir_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 *_I_BLE_Pairing_128x64[] = {_I_BLE_Pairing_128x64_0}; -const uint8_t _I_Voldwn_6x6_0[] = {0x00,0x08,0x0C,0x2F,0x2F,0x0C,0x08,}; -const uint8_t *_I_Voldwn_6x6[] = {_I_Voldwn_6x6_0}; - -const uint8_t _I_Volup_8x6_0[] = {0x00,0x48,0x8C,0xAF,0xAF,0x8C,0x48,}; -const uint8_t *_I_Volup_8x6[] = {_I_Volup_8x6_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 *_I_Button_18x18[] = {_I_Button_18x18_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 *_I_Pressed_Button_13x13[] = {_I_Pressed_Button_13x13_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 *_I_Ble_disconnected_24x34[] = {_I_Ble_disconnected_24x34_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 *_I_Space_65x18[] = {_I_Space_65x18_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 *_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 *_I_Ok_btn_9x9[] = {_I_Ok_btn_9x9_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 *_I_Ble_connected_38x34[] = {_I_Ble_connected_38x34_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 *_I_Clock_18x18[] = {_I_Clock_18x18_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 *_I_Ok_btn_9x9[] = {_I_Ok_btn_9x9_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 *_I_Error_18x18[] = {_I_Error_18x18_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 *_I_Space_65x18[] = {_I_Space_65x18_0}; + +const uint8_t _I_Volup_8x6_0[] = {0x00,0x48,0x8C,0xAF,0xAF,0x8C,0x48,}; +const uint8_t *_I_Volup_8x6[] = {_I_Volup_8x6_0}; + +const uint8_t _I_Voldwn_6x6_0[] = {0x00,0x08,0x0C,0x2F,0x2F,0x0C,0x08,}; +const uint8_t *_I_Voldwn_6x6[] = {_I_Voldwn_6x6_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 *_I_Circles_47x47[] = {_I_Circles_47x47_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 *_I_Ble_disconnected_24x34[] = {_I_Ble_disconnected_24x34_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 *_I_Pressed_Button_13x13[] = {_I_Pressed_Button_13x13_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 *_I_EviWaiting1_18x21[] = {_I_EviWaiting1_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 *_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 *_I_EviWaiting1_18x21[] = {_I_EviWaiting1_18x21_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 *_I_Error_18x18[] = {_I_Error_18x18_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 *_I_Percent_10x14[] = {_I_Percent_10x14_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 *_I_EviSmile1_18x21[] = {_I_EviSmile1_18x21_0}; @@ -354,62 +354,47 @@ const uint8_t *_I_UsbTree_48x22[] = {_I_UsbTree_48x22_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 *_I_Smile_18x18[] = {_I_Smile_18x18_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 *_I_Percent_10x14[] = {_I_Percent_10x14_0}; - -const uint8_t _I_ButtonLeft_4x7_0[] = {0x00,0x08,0x0C,0x0E,0x0F,0x0E,0x0C,0x08,}; -const uint8_t *_I_ButtonLeft_4x7[] = {_I_ButtonLeft_4x7_0}; - -const uint8_t _I_ButtonRight_4x7_0[] = {0x00,0x01,0x03,0x07,0x0F,0x07,0x03,0x01,}; -const uint8_t *_I_ButtonRight_4x7[] = {_I_ButtonRight_4x7_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 *_I_Clock_18x18[] = {_I_Clock_18x18_0}; const uint8_t _I_ButtonDown_7x4_0[] = {0x00,0x7F,0x3E,0x1C,0x08,}; const uint8_t *_I_ButtonDown_7x4[] = {_I_ButtonDown_7x4_0}; +const uint8_t _I_ButtonCenter_7x7_0[] = {0x00,0x1C,0x22,0x5D,0x5D,0x5D,0x22,0x1C,}; +const uint8_t *_I_ButtonCenter_7x7[] = {_I_ButtonCenter_7x7_0}; + +const uint8_t _I_ButtonLeft_4x7_0[] = {0x00,0x08,0x0C,0x0E,0x0F,0x0E,0x0C,0x08,}; +const uint8_t *_I_ButtonLeft_4x7[] = {_I_ButtonLeft_4x7_0}; + const uint8_t _I_ButtonUp_7x4_0[] = {0x00,0x08,0x1C,0x3E,0x7F,}; const uint8_t *_I_ButtonUp_7x4[] = {_I_ButtonUp_7x4_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 *_I_Warning_30x23[] = {_I_Warning_30x23_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 *_I_DFU_128x50[] = {_I_DFU_128x50_0}; -const uint8_t _I_ButtonRightSmall_3x5_0[] = {0x00,0x01,0x03,0x07,0x03,0x01,}; -const uint8_t *_I_ButtonRightSmall_3x5[] = {_I_ButtonRightSmall_3x5_0}; - -const uint8_t _I_ButtonCenter_7x7_0[] = {0x00,0x1C,0x22,0x5D,0x5D,0x5D,0x22,0x1C,}; -const uint8_t *_I_ButtonCenter_7x7[] = {_I_ButtonCenter_7x7_0}; - const uint8_t _I_ButtonLeftSmall_3x5_0[] = {0x00,0x04,0x06,0x07,0x06,0x04,}; const uint8_t *_I_ButtonLeftSmall_3x5[] = {_I_ButtonLeftSmall_3x5_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 *_I_DolphinOkay_41x43[] = {_I_DolphinOkay_41x43_0}; +const uint8_t _I_ButtonRightSmall_3x5_0[] = {0x00,0x01,0x03,0x07,0x03,0x01,}; +const uint8_t *_I_ButtonRightSmall_3x5[] = {_I_ButtonRightSmall_3x5_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 *_I_DolphinFirstStart7_61x51[] = {_I_DolphinFirstStart7_61x51_0}; +const uint8_t _I_ButtonRight_4x7_0[] = {0x00,0x01,0x03,0x07,0x0F,0x07,0x03,0x01,}; +const uint8_t *_I_ButtonRight_4x7[] = {_I_ButtonRight_4x7_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 *_I_DolphinFirstStart4_67x53[] = {_I_DolphinFirstStart4_67x53_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 *_I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_0}; - -const uint8_t _I_Flipper_young_80x60_0[] = {0x01,0x00,0xa3,0x01,0x00,0x1e,0x03,0xff,0xff,0x87,0x82,0x57,0xf1,0x83,0x90,0xde,0x01,0x2b,0x0e,0x83,0x70,0xfb,0x10,0x10,0x41,0xf8,0x27,0x70,0xcc,0x34,0xc6,0x0e,0x09,0x3e,0x04,0x86,0x21,0x0c,0x90,0xc3,0x03,0xa9,0xe7,0xb0,0x46,0x2c,0x51,0x40,0x4a,0x63,0x38,0x31,0x0a,0x34,0x90,0x12,0x91,0x8e,0x3c,0xff,0x89,0x4c,0x04,0xa4,0x43,0xfd,0xf3,0xc3,0xf2,0x01,0x29,0xe0,0x2b,0x8e,0x72,0xa0,0x46,0x4b,0xe0,0x30,0xba,0x10,0x22,0xca,0x1c,0x0b,0x26,0x09,0x3c,0x04,0x0c,0x08,0x59,0xc8,0x21,0x64,0xc4,0x47,0x98,0x82,0x81,0x0a,0xe0,0x21,0x39,0x04,0x34,0x88,0x60,0x93,0xa0,0x45,0x4b,0x06,0xa3,0x40,0x48,0xfc,0x20,0xf0,0x82,0xa2,0x4d,0x60,0x11,0xe9,0xc2,0x19,0x64,0xd0,0x08,0x1f,0x80,0x7e,0x60,0x01,0x92,0x60,0x20,0x38,0x05,0x21,0x7c,0x3f,0xf0,0x1a,0xe6,0x00,0xe6,0x21,0x32,0x1a,0x0c,0x0e,0x91,0x80,0x8f,0xc0,0x06,0x25,0xcc,0xbf,0xc1,0xaa,0x10,0x0b,0xfc,0x02,0x60,0x2e,0x2c,0x04,0x32,0xc1,0x00,0xff,0x40,0x68,0x00,0x91,0x89,0xc0,0x21,0x20,0x51,0xfe,0x41,0xf0,0x00,0x91,0xc4,0xcf,0xe2,0x40,0x51,0xfc,0x0c,0x86,0x07,0x80,0xe2,0xdf,0xda,0x25,0xf0,0x9f,0xc0,0x21,0x98,0x0f,0x27,0xfd,0xa2,0x5e,0x01,0x90,0xc4,0x30,0x1e,0x2f,0xfc,0xa1,0x3a,0x45,0x41,0xb0,0x60,0x3e,0x5e,0x79,0x4a,0x10,0xbf,0xe2,0x61,0xc0,0x82,0x52,0x01,0xff,0x36,0x8e,0x3b,0xe5,0xff,0x04,0x9f,0xf8,0x78,0x3b,0x8f,0x97,0xf8,0x12,0x7f,0xc3,0x78,0xf8,0x3e,0x5f,0xc0,0x49,0xfe,0x08,0xc2,0x17,0x1f,0xcd,0xa5,0xac,0x5f,0x02,0x30,0xc0,0x30,0x5f,0xfd,0x23,0xbc,0xbc,0x1f,0xf0,0xc1,0x5f,0xaa,0x8e,0x52,0x28,0x10,0x10,0x6f,0x1b,0x28,0x57,0x81,0x66,0x25,0x01,0x80,0x4e,0x28,0x15,0x98,0xad,0xc3,0xfd,0xff,0xff,0x91,0x87,0xc1,0x80,0xd4,0xc2,0xb2,0x03,0xb1,0x5b,0x13,0x34,0x6a,0xf1,0x58,0x84,0x0e,0x1d,0x00,0x23,0x14,0x0f,0x55,0x0a,0x88,0x67,0x0d,0x83,0x7c,0x04,0x8c,0x0a,0xa9,0x15,0x90,0x7c,0x07,0x23,0xf8,0x80,0xc1,0xa0,0xda,0x88,0x54,0x82,0x00,0x2f,0x1f,0xe4,0x3c,0x7a,0x35,0x08,0xab,0x20,0x7f,0x03,0xc1,0x2d,0x96,0x82,0x14,0xce,0x20,0x02,0x04,0xc6,0x00,0x60,0x20,0x01,0x84,0xc4,0x6a,0x21,0x36,0x3b,0x8c,0xf0,0x3c,0xc8,0x02,0x1b,0x88,0x01,0xe1,0x80,0x98,0x2d,0x10,0x01,0xb0,0x05,0xa1,0x00,0x3d,0xf8,0x13,0x17,0x81,0x47,0x80,0x0b,0xc0,0x28,0x8e,0x02,0xa4,0x81,0x2c,0xf0,0x20,0x01,0x00,}; -const uint8_t *_I_Flipper_young_80x60[] = {_I_Flipper_young_80x60_0}; - -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 *_I_DolphinFirstStart0_70x53[] = {_I_DolphinFirstStart0_70x53_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 *_I_Warning_30x23[] = {_I_Warning_30x23_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 *_I_DolphinFirstStart2_59x51[] = {_I_DolphinFirstStart2_59x51_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 *_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 *_I_DolphinFirstStart6_58x54[] = {_I_DolphinFirstStart6_58x54_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 *_I_DolphinFirstStart5_54x49[] = {_I_DolphinFirstStart5_54x49_0}; +const uint8_t _I_Flipper_young_80x60_0[] = {0x01,0x00,0xa3,0x01,0x00,0x1e,0x03,0xff,0xff,0x87,0x82,0x57,0xf1,0x83,0x90,0xde,0x01,0x2b,0x0e,0x83,0x70,0xfb,0x10,0x10,0x41,0xf8,0x27,0x70,0xcc,0x34,0xc6,0x0e,0x09,0x3e,0x04,0x86,0x21,0x0c,0x90,0xc3,0x03,0xa9,0xe7,0xb0,0x46,0x2c,0x51,0x40,0x4a,0x63,0x38,0x31,0x0a,0x34,0x90,0x12,0x91,0x8e,0x3c,0xff,0x89,0x4c,0x04,0xa4,0x43,0xfd,0xf3,0xc3,0xf2,0x01,0x29,0xe0,0x2b,0x8e,0x72,0xa0,0x46,0x4b,0xe0,0x30,0xba,0x10,0x22,0xca,0x1c,0x0b,0x26,0x09,0x3c,0x04,0x0c,0x08,0x59,0xc8,0x21,0x64,0xc4,0x47,0x98,0x82,0x81,0x0a,0xe0,0x21,0x39,0x04,0x34,0x88,0x60,0x93,0xa0,0x45,0x4b,0x06,0xa3,0x40,0x48,0xfc,0x20,0xf0,0x82,0xa2,0x4d,0x60,0x11,0xe9,0xc2,0x19,0x64,0xd0,0x08,0x1f,0x80,0x7e,0x60,0x01,0x92,0x60,0x20,0x38,0x05,0x21,0x7c,0x3f,0xf0,0x1a,0xe6,0x00,0xe6,0x21,0x32,0x1a,0x0c,0x0e,0x91,0x80,0x8f,0xc0,0x06,0x25,0xcc,0xbf,0xc1,0xaa,0x10,0x0b,0xfc,0x02,0x60,0x2e,0x2c,0x04,0x32,0xc1,0x00,0xff,0x40,0x68,0x00,0x91,0x89,0xc0,0x21,0x20,0x51,0xfe,0x41,0xf0,0x00,0x91,0xc4,0xcf,0xe2,0x40,0x51,0xfc,0x0c,0x86,0x07,0x80,0xe2,0xdf,0xda,0x25,0xf0,0x9f,0xc0,0x21,0x98,0x0f,0x27,0xfd,0xa2,0x5e,0x01,0x90,0xc4,0x30,0x1e,0x2f,0xfc,0xa1,0x3a,0x45,0x41,0xb0,0x60,0x3e,0x5e,0x79,0x4a,0x10,0xbf,0xe2,0x61,0xc0,0x82,0x52,0x01,0xff,0x36,0x8e,0x3b,0xe5,0xff,0x04,0x9f,0xf8,0x78,0x3b,0x8f,0x97,0xf8,0x12,0x7f,0xc3,0x78,0xf8,0x3e,0x5f,0xc0,0x49,0xfe,0x08,0xc2,0x17,0x1f,0xcd,0xa5,0xac,0x5f,0x02,0x30,0xc0,0x30,0x5f,0xfd,0x23,0xbc,0xbc,0x1f,0xf0,0xc1,0x5f,0xaa,0x8e,0x52,0x28,0x10,0x10,0x6f,0x1b,0x28,0x57,0x81,0x66,0x25,0x01,0x80,0x4e,0x28,0x15,0x98,0xad,0xc3,0xfd,0xff,0xff,0x91,0x87,0xc1,0x80,0xd4,0xc2,0xb2,0x03,0xb1,0x5b,0x13,0x34,0x6a,0xf1,0x58,0x84,0x0e,0x1d,0x00,0x23,0x14,0x0f,0x55,0x0a,0x88,0x67,0x0d,0x83,0x7c,0x04,0x8c,0x0a,0xa9,0x15,0x90,0x7c,0x07,0x23,0xf8,0x80,0xc1,0xa0,0xda,0x88,0x54,0x82,0x00,0x2f,0x1f,0xe4,0x3c,0x7a,0x35,0x08,0xab,0x20,0x7f,0x03,0xc1,0x2d,0x96,0x82,0x14,0xce,0x20,0x02,0x04,0xc6,0x00,0x60,0x20,0x01,0x84,0xc4,0x6a,0x21,0x36,0x3b,0x8c,0xf0,0x3c,0xc8,0x02,0x1b,0x88,0x01,0xe1,0x80,0x98,0x2d,0x10,0x01,0xb0,0x05,0xa1,0x00,0x3d,0xf8,0x13,0x17,0x81,0x47,0x80,0x0b,0xc0,0x28,0x8e,0x02,0xa4,0x81,0x2c,0xf0,0x20,0x01,0x00,}; +const uint8_t *_I_Flipper_young_80x60[] = {_I_Flipper_young_80x60_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 *_I_DolphinFirstStart8_56x51[] = {_I_DolphinFirstStart8_56x51_0}; @@ -417,17 +402,38 @@ const uint8_t *_I_DolphinFirstStart8_56x51[] = {_I_DolphinFirstStart8_56x51_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 *_I_DolphinFirstStart1_59x53[] = {_I_DolphinFirstStart1_59x53_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 *_I_DolphinOkay_41x43[] = {_I_DolphinOkay_41x43_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 *_I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_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 *_I_DolphinFirstStart7_61x51[] = {_I_DolphinFirstStart7_61x51_0}; + +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 *_I_DolphinFirstStart0_70x53[] = {_I_DolphinFirstStart0_70x53_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 *_I_DolphinFirstStart4_67x53[] = {_I_DolphinFirstStart4_67x53_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 *_I_ArrowUpEmpty_14x15[] = {_I_ArrowUpEmpty_14x15_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 *_I_ArrowDownEmpty_14x15[] = {_I_ArrowDownEmpty_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 *_I_ArrowUpFilled_14x15[] = {_I_ArrowUpFilled_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 *_I_ArrowDownFilled_14x15[] = {_I_ArrowDownFilled_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 *_I_ArrowUpFilled_14x15[] = {_I_ArrowUpFilled_14x15_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 *_I_ArrowDownEmpty_14x15[] = {_I_ArrowDownEmpty_14x15_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 *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_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 *_I_DoorLeft_70x55[] = {_I_DoorLeft_70x55_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 *_I_DoorRight_70x55[] = {_I_DoorRight_70x55_0}; @@ -435,86 +441,74 @@ const uint8_t *_I_DoorRight_70x55[] = {_I_DoorRight_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 *_I_DoorLocked_10x56[] = {_I_DoorLocked_10x56_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 *_I_DoorLeft_70x55[] = {_I_DoorLeft_70x55_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 *_I_PassportLeft_6x47[] = {_I_PassportLeft_6x47_0}; const uint8_t _I_LockPopup_100x49_0[] = {0x01,0x00,0x37,0x01,0xfc,0x7f,0xc0,0x13,0x01,0xfe,0x03,0x2a,0x07,0x06,0x12,0xd4,0x1a,0x06,0x0c,0xa8,0x60,0x33,0xe0,0x12,0x08,0x40,0x32,0x3f,0xd0,0x70,0x64,0xe0,0x20,0x31,0x8a,0x00,0x32,0x2c,0x10,0x0b,0x00,0x32,0x62,0x10,0x0c,0x06,0x00,0x19,0x00,0x82,0xc0,0x83,0x22,0x08,0x04,0x18,0x11,0x6a,0x01,0x25,0x02,0x84,0x83,0x1e,0x02,0x04,0x10,0xe1,0x03,0x1e,0x3c,0x0c,0x9c,0x1c,0x02,0x43,0x00,0x84,0x4f,0xc1,0x8f,0x80,0xaf,0x40,0x39,0x14,0x00,0x63,0xd0,0x36,0xf0,0x09,0xc6,0x00,0x18,0xd4,0x3a,0x06,0x9c,0x08,0x20,0xc9,0xdf,0xc0,0x20,0x7f,0x00,0x65,0x40,0x3f,0x80,0xc7,0xd0,0x10,0x06,0x01,0x7f,0x06,0x34,0x8e,0xa1,0x3d,0x80,0x70,0x0b,0x4f,0x23,0xd0,0x50,0xa0,0x1f,0x08,0x78,0x66,0x11,0xe3,0xfc,0x83,0x83,0x1e,0x40,0x0c,0x1f,0xfb,0xec,0x41,0x8c,0x03,0x1e,0x07,0x00,0x4d,0x10,0x0a,0x04,0xc0,0x9b,0x30,0x0c,0x1f,0xff,0xff,0x9f,0x06,0x3e,0x01,0x80,0x48,0xe7,0x99,0x83,0x0d,0x6a,0xe0,0xc4,0x90,0x03,0x1a,0x76,0x0c,0x38,0xe0,0x34,0x45,0x25,0x02,0x06,0x0d,0xe0,0x18,0x3c,0x08,0x19,0x40,0x78,0x00,0xc1,0x81,0xc3,0x27,0xf8,0x48,0x26,0x82,0x7d,0x00,0xfc,0x40,0xfc,0x10,0xfc,0x04,0xfc,0x18,0x30,0x28,0x7d,0x02,0x3f,0x00,0x98,0x41,0x38,0x31,0x08,0x25,0x0e,0x19,0x1f,0x81,0x42,0x70,0x11,0xa2,0x08,0xe2,0x30,0x72,0x08,0x76,0x0a,0x19,0x0f,0x85,0x42,0x60,0x11,0x51,0x78,0xc2,0x20,0x32,0x08,0x26,0x00,0x18,0x91,0x00,0x60,0x91,0x44,0x08,0x34,0x08,0x64,0x1f,0xe4,0x07,0x3f,0x84,0x0d,0x58,0x44,0x01,0x83,0xdc,0x60,0x43,0xe1,0x39,0xa9,0xd0,0x60,0x70,0x16,0x78,0xca,0x01,0x8f,0x83,0x3d,0x10,0x33,0x29,0x00,0xc7,0xa1,0x83,0x3f,0x10,0x0c,0x79,0x30,0x32,0xa0,0xdf,0xc7,0xa0,0x80,0x22,0x07,0xf8,0x06,0x54,0x04,}; const uint8_t *_I_LockPopup_100x49[] = {_I_LockPopup_100x49_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 *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_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 *_I_Vol_up_25x27[] = {_I_Vol_up_25x27_0}; - -const uint8_t _I_Fill_marker_7x7_0[] = {0x00,0x1C,0x32,0x6F,0x5F,0x7F,0x3E,0x1C,}; -const uint8_t *_I_Fill_marker_7x7[] = {_I_Fill_marker_7x7_0}; - -const uint8_t _I_IrdaArrowUp_4x8_0[] = {0x00,0x18,0x3C,0x7E,0xFF,}; -const uint8_t *_I_IrdaArrowUp_4x8[] = {_I_IrdaArrowUp_4x8_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 *_I_Down_hvr_25x27[] = {_I_Down_hvr_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 *_I_Vol_up_hvr_25x27[] = {_I_Vol_up_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 *_I_Power_25x27[] = {_I_Power_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 *_I_Vol_down_25x27[] = {_I_Vol_down_25x27_0}; - -const uint8_t _I_IrdaSend_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 *_I_IrdaSend_128x64[] = {_I_IrdaSend_128x64_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 *_I_Up_hvr_25x27[] = {_I_Up_hvr_25x27_0}; - -const uint8_t _I_Back_15x10_0[] = {0x00,0x04,0x00,0x06,0x00,0xFF,0x0F,0x06,0x10,0x04,0x20,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x10,0xFE,0x0F,}; -const uint8_t *_I_Back_15x10[] = {_I_Back_15x10_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 *_I_DolphinReadingSuccess_59x63[] = {_I_DolphinReadingSuccess_59x63_0}; - -const uint8_t _I_IrdaSendShort_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 *_I_IrdaSendShort_128x34[] = {_I_IrdaSendShort_128x34_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 *_I_Mute_hvr_25x27[] = {_I_Mute_hvr_25x27_0}; - -const uint8_t _I_IrdaLearnShort_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 *_I_IrdaLearnShort_128x31[] = {_I_IrdaLearnShort_128x31_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 *_I_Down_25x27[] = {_I_Down_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 *_I_Up_25x27[] = {_I_Up_25x27_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 *_I_Mute_25x27[] = {_I_Mute_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 *_I_Vol_down_hvr_25x27[] = {_I_Vol_down_hvr_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 *_I_Power_hvr_25x27[] = {_I_Power_hvr_25x27_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 *_I_Down_25x27[] = {_I_Down_25x27_0}; -const uint8_t _I_IrdaLearn_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 *_I_IrdaLearn_128x64[] = {_I_IrdaLearn_128x64_0}; +const uint8_t _I_Fill_marker_7x7_0[] = {0x00,0x1C,0x32,0x6F,0x5F,0x7F,0x3E,0x1C,}; +const uint8_t *_I_Fill_marker_7x7[] = {_I_Fill_marker_7x7_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 *_I_Vol_down_25x27[] = {_I_Vol_down_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 *_I_Vol_up_25x27[] = {_I_Vol_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 *_I_Up_hvr_25x27[] = {_I_Up_hvr_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 *_I_Vol_up_hvr_25x27[] = {_I_Vol_up_hvr_25x27_0}; + +const uint8_t _I_IrdaLearnShort_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 *_I_IrdaLearnShort_128x31[] = {_I_IrdaLearnShort_128x31_0}; + +const uint8_t _I_IrdaSend_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 *_I_IrdaSend_128x64[] = {_I_IrdaSend_128x64_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 *_I_DolphinReadingSuccess_59x63[] = {_I_DolphinReadingSuccess_59x63_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 *_I_Mute_hvr_25x27[] = {_I_Mute_hvr_25x27_0}; + +const uint8_t _I_Back_15x10_0[] = {0x00,0x04,0x00,0x06,0x00,0xFF,0x0F,0x06,0x10,0x04,0x20,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x10,0xFE,0x0F,}; +const uint8_t *_I_Back_15x10[] = {_I_Back_15x10_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 *_I_Up_25x27[] = {_I_Up_25x27_0}; + +const uint8_t _I_IrdaArrowUp_4x8_0[] = {0x00,0x18,0x3C,0x7E,0xFF,}; +const uint8_t *_I_IrdaArrowUp_4x8[] = {_I_IrdaArrowUp_4x8_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 *_I_Mute_25x27[] = {_I_Mute_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 *_I_Power_25x27[] = {_I_Power_25x27_0}; + +const uint8_t _I_IrdaSendShort_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 *_I_IrdaSendShort_128x34[] = {_I_IrdaSendShort_128x34_0}; const uint8_t _I_IrdaArrowDown_4x8_0[] = {0x00,0xFF,0x7E,0x3C,0x18,}; const uint8_t *_I_IrdaArrowDown_4x8[] = {_I_IrdaArrowDown_4x8_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 *_I_KeyBackspaceSelected_16x9[] = {_I_KeyBackspaceSelected_16x9_0}; +const uint8_t _I_IrdaLearn_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 *_I_IrdaLearn_128x64[] = {_I_IrdaLearn_128x64_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 *_I_KeySave_24x11[] = {_I_KeySave_24x11_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 *_I_Power_hvr_25x27[] = {_I_Power_hvr_25x27_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 *_I_KeySaveSelected_24x11[] = {_I_KeySaveSelected_24x11_0}; @@ -522,6 +516,12 @@ const uint8_t *_I_KeySaveSelected_24x11[] = {_I_KeySaveSelected_24x11_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 *_I_KeyBackspace_16x9[] = {_I_KeyBackspace_16x9_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 *_I_KeyBackspaceSelected_16x9[] = {_I_KeyBackspaceSelected_16x9_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 *_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,}; @@ -671,84 +671,84 @@ const uint8_t _A_iButton_14_5[] = {0x01,0x00,0x1a,0x00,0x00,0x14,0xe2,0x01,0x24, 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 *_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_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 *_I_Medium_chip_22x21[] = {_I_Medium_chip_22x21_0}; - 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 *_I_Detailed_chip_17x13[] = {_I_Detailed_chip_17x13_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 *_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 *_I_passport_happy2_46x49[] = {_I_passport_happy2_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 *_I_passport_bad3_46x49[] = {_I_passport_bad3_46x49_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 *_I_Medium_chip_22x21[] = {_I_Medium_chip_22x21_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 *_I_passport_okay2_46x49[] = {_I_passport_okay2_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 *_I_passport_bad2_46x49[] = {_I_passport_bad2_46x49_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 *_I_passport_bad1_46x49[] = {_I_passport_bad1_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 *_I_passport_happy2_46x49[] = {_I_passport_happy2_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 *_I_passport_bottom_128x18[] = {_I_passport_bottom_128x18_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 *_I_passport_happy3_46x49[] = {_I_passport_happy3_46x49_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 *_I_passport_happy1_46x49[] = {_I_passport_happy1_46x49_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 *_I_passport_bad1_46x49[] = {_I_passport_bad1_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 *_I_passport_left_6x46[] = {_I_passport_left_6x46_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 *_I_passport_okay3_46x49[] = {_I_passport_okay3_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 *_I_passport_bad3_46x49[] = {_I_passport_bad3_46x49_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 *_I_passport_okay1_46x49[] = {_I_passport_okay1_46x49_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 *_I_Health_16x16[] = {_I_Health_16x16_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 *_I_passport_bad2_46x49[] = {_I_passport_bad2_46x49_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 *_I_FaceNopower_29x14[] = {_I_FaceNopower_29x14_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 *_I_passport_okay3_46x49[] = {_I_passport_okay3_46x49_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 *_I_Battery_16x16[] = {_I_Battery_16x16_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 *_I_passport_happy3_46x49[] = {_I_passport_happy3_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 *_I_BatteryBody_52x28[] = {_I_BatteryBody_52x28_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 *_I_FaceConfused_29x14[] = {_I_FaceConfused_29x14_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 *_I_FaceCharging_29x14[] = {_I_FaceCharging_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 *_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 *_I_Temperature_16x16[] = {_I_Temperature_16x16_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 *_I_Battery_16x16[] = {_I_Battery_16x16_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 *_I_FaceConfused_29x14[] = {_I_FaceConfused_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 *_I_FaceNormal_29x14[] = {_I_FaceNormal_29x14_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 *_I_Voltage_16x16[] = {_I_Voltage_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 *_I_Temperature_16x16[] = {_I_Temperature_16x16_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 *_I_RFIDDolphinReceive_97x61[] = {_I_RFIDDolphinReceive_97x61_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 *_I_FaceNopower_29x14[] = {_I_FaceNopower_29x14_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 *_I_RFIDDolphinSend_97x61[] = {_I_RFIDDolphinSend_97x61_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 *_I_RFIDBigChip_37x36[] = {_I_RFIDBigChip_37x36_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 *_I_RFIDDolphinSuccess_108x57[] = {_I_RFIDDolphinSuccess_108x57_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 *_I_RFIDDolphinReceive_97x61[] = {_I_RFIDDolphinReceive_97x61_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 *_I_RFIDBigChip_37x36[] = {_I_RFIDBigChip_37x36_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 *_I_SDQuestion_35x43[] = {_I_SDQuestion_35x43_0}; @@ -758,48 +758,48 @@ const uint8_t *_I_SDError_43x35[] = {_I_SDError_43x35_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 *_I_Cry_dolph_55x52[] = {_I_Cry_dolph_55x52_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 *_I_Battery_26x8[] = {_I_Battery_26x8_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 *_I_PlaceholderL_11x13[] = {_I_PlaceholderL_11x13_0}; - -const uint8_t _I_BT_Pair_9x8_0[] = {0x00,0x11,0x01,0x35,0x00,0x58,0x01,0x31,0x00,0x30,0x01,0x59,0x00,0x34,0x01,0x11,0x01,}; -const uint8_t *_I_BT_Pair_9x8[] = {_I_BT_Pair_9x8_0}; - -const uint8_t _I_Bluetooth_5x8_0[] = {0x00,0x04,0x0D,0x16,0x0C,0x0C,0x16,0x0D,0x04,}; -const uint8_t *_I_Bluetooth_5x8[] = {_I_Bluetooth_5x8_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 *_I_BadUsb_9x8[] = {_I_BadUsb_9x8_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 *_I_PlaceholderR_30x13[] = {_I_PlaceholderR_30x13_0}; - -const uint8_t _I_USBConnected_15x8_0[] = {0x00,0xF0,0x07,0x08,0x7C,0x04,0x44,0x07,0x54,0x07,0x54,0x04,0x44,0x08,0x7C,0xF0,0x07,}; -const uint8_t *_I_USBConnected_15x8[] = {_I_USBConnected_15x8_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 *_I_Battery_19x8[] = {_I_Battery_19x8_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 *_I_Background_128x11[] = {_I_Background_128x11_0}; const uint8_t _I_Lock_8x8_0[] = {0x00,0x3C,0x42,0x42,0xFF,0xFF,0xE7,0xFF,0xFF,}; const uint8_t *_I_Lock_8x8[] = {_I_Lock_8x8_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 *_I_Background_128x11[] = {_I_Background_128x11_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 *_I_Battery_26x8[] = {_I_Battery_26x8_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 *_I_Battery_19x8[] = {_I_Battery_19x8_0}; + +const uint8_t _I_USBConnected_15x8_0[] = {0x00,0xF0,0x07,0x08,0x7C,0x04,0x44,0x07,0x54,0x07,0x54,0x04,0x44,0x08,0x7C,0xF0,0x07,}; +const uint8_t *_I_USBConnected_15x8[] = {_I_USBConnected_15x8_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 *_I_BadUsb_9x8[] = {_I_BadUsb_9x8_0}; + +const uint8_t _I_BT_Pair_9x8_0[] = {0x00,0x11,0x01,0x35,0x00,0x58,0x01,0x31,0x00,0x30,0x01,0x59,0x00,0x34,0x01,0x11,0x01,}; +const uint8_t *_I_BT_Pair_9x8[] = {_I_BT_Pair_9x8_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 *_I_PlaceholderL_11x13[] = {_I_PlaceholderL_11x13_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 *_I_SDcardFail_11x8[] = {_I_SDcardFail_11x8_0}; +const uint8_t _I_Bluetooth_5x8_0[] = {0x00,0x04,0x0D,0x16,0x0C,0x0C,0x16,0x0D,0x04,}; +const uint8_t *_I_Bluetooth_5x8[] = {_I_Bluetooth_5x8_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 *_I_PlaceholderR_30x13[] = {_I_PlaceholderR_30x13_0}; + const uint8_t _I_SDcardMounted_11x8_0[] = {0x01,0x00,0x09,0x00,0xff,0xc1,0xff,0xf0,0x40,0x1c,0xd9,0xe0,0x00,}; const uint8_t *_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 *_I_Lock_7x8[] = {_I_Lock_7x8_0}; - const uint8_t _I_Quest_7x8_0[] = {0x00,0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,}; const uint8_t *_I_Quest_7x8[] = {_I_Quest_7x8_0}; +const uint8_t _I_Lock_7x8_0[] = {0x00,0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; +const uint8_t *_I_Lock_7x8[] = {_I_Lock_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 *_I_Scanning_123x52[] = {_I_Scanning_123x52_0}; @@ -809,29 +809,29 @@ const uint8_t *_I_MHz_25x11[] = {_I_MHz_25x11_0}; const uint8_t _I_Unlock_7x8_0[] = {0x00,0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_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 *_I_iButtonKey_49x44[] = {_I_iButtonKey_49x44_0}; + +const uint8_t _I_DolphinExcited_64x63_0[] = {0x01,0x00,0x36,0x01,0x00,0x25,0x00,0x0f,0xd2,0x00,0x3b,0xe0,0x00,0xeb,0x10,0x0c,0x34,0x40,0x30,0xd0,0x88,0x80,0x1d,0xa1,0x00,0x42,0xfc,0x7f,0xc0,0x63,0x04,0x01,0x0e,0x02,0x0f,0x00,0x00,0x8c,0x08,0x0e,0x37,0x00,0x10,0xc6,0x20,0x10,0x10,0xd9,0x11,0x92,0x1c,0x1a,0x3e,0x00,0x04,0x42,0x02,0x1a,0x20,0xb0,0xce,0x00,0x64,0x07,0x20,0x59,0x16,0x50,0x36,0x45,0x94,0x84,0x78,0x20,0x60,0x75,0x8e,0x43,0x06,0x63,0x3c,0x33,0x94,0x0c,0xd2,0x5c,0x30,0x38,0xe4,0x08,0x43,0x10,0xc0,0x5e,0x06,0x22,0x53,0x1a,0x02,0x08,0x7f,0xd0,0x32,0xc1,0x50,0x21,0x14,0x0e,0x70,0x1c,0x46,0xe2,0x07,0x19,0x06,0x3c,0xdc,0x20,0x91,0xae,0x01,0xcc,0xbe,0x30,0x09,0xfc,0x12,0x41,0xff,0x83,0xcc,0x0a,0xa3,0x1f,0x03,0x99,0xe8,0x7c,0x10,0xf8,0x25,0xa0,0x5e,0x50,0x0f,0x84,0x1e,0x09,0x54,0x03,0x9f,0xf2,0x07,0x02,0xd5,0x11,0xca,0x01,0xfe,0x80,0xc0,0xaa,0x9f,0xf0,0x39,0x5f,0xd0,0x43,0xaa,0x83,0x41,0x92,0xc3,0x1f,0x03,0x8d,0x52,0x02,0x2e,0x25,0xc9,0x6a,0x99,0x46,0xa6,0x2a,0xa0,0x1c,0xaf,0xca,0x62,0x94,0x28,0xcb,0x7e,0x0f,0x15,0x71,0xf8,0x3c,0x22,0x71,0x03,0x8a,0x84,0x67,0x18,0x0f,0xac,0x1c,0x0e,0x38,0x08,0x0c,0x3e,0x01,0xae,0xbd,0x13,0x0c,0x0e,0x35,0x8e,0xa8,0x1c,0xb0,0x1f,0xf8,0x06,0x83,0xf4,0x27,0x38,0x07,0xff,0xff,0x8f,0x03,0xa0,0x4c,0x80,0xed,0x60,0x03,0xb4,0x60,0x0e,0xd0,0x60,0x3a,0x87,0x84,0x0e,0xb7,0xc2,0xfa,0x18,0x05,0x44,0x20,0x73,0xff,0xf7,0xce,0xe4,0x07,0x2d,0x52,0x2c,0x80,0xe7,0x54,0xea,0x81,0xd7,0x50,0x0f,0x7a,0xaa,0x3d,0x41,0xe2,0x07,0x5a,0x80,0x3c,0xa0,0x40,0x72,0xd0,0x6a,0x80,0xa2,0x07,0x3a,0x05,0x54,0x8e,0x20,0x73,0xc0,0x03,0xd8,0x60,0x30,0x40,0x3a,0xc0,0x00,0xee,0xea,0x10,0x3b,0x80,}; +const uint8_t *_I_DolphinExcited_64x63[] = {_I_DolphinExcited_64x63_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 *_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 *_I_iButtonDolphinVerySuccess_108x52[] = {_I_iButtonDolphinVerySuccess_108x52_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 *_I_DolphinMafia_115x62[] = {_I_DolphinMafia_115x62_0}; -const uint8_t _I_iButtonDolphinSuccess_109x60_0[] = {0x01,0x00,0xac,0x01,0x00,0x17,0xfe,0x1e,0x0c,0xaf,0x04,0x02,0xe0,0x0d,0xa8,0xf4,0x03,0x01,0x03,0x06,0x46,0x02,0x02,0x03,0x18,0xe0,0x36,0x2c,0x00,0x36,0x00,0x2c,0x40,0x3e,0x60,0xd8,0x84,0x01,0x0c,0x5a,0x40,0x05,0x82,0x01,0x0e,0x04,0x0d,0x70,0x42,0x04,0x90,0x49,0x02,0xe4,0x20,0x41,0x28,0xc0,0x07,0x40,0x06,0xf8,0x00,0xa4,0x00,0xd6,0x03,0xa8,0x37,0x44,0x2a,0x31,0x74,0xd3,0x83,0x57,0x80,0x0d,0xc7,0x18,0xa9,0xa8,0x36,0x2a,0x86,0x06,0x8d,0xfc,0x36,0x60,0xd7,0xc0,0x3b,0x8c,0x36,0xf0,0x4a,0x05,0xf9,0x6e,0x5e,0x06,0x23,0x41,0x24,0x1f,0xf6,0x01,0x74,0x01,0xb1,0xe3,0x82,0x81,0x47,0x40,0x0d,0x7c,0x87,0x8e,0x12,0x05,0x1a,0x84,0x0d,0xb6,0xa0,0xd2,0x85,0x86,0xc8,0x1a,0x50,0x40,0x69,0x40,0xb2,0x1f,0xf0,0x69,0x50,0x01,0xa5,0x08,0xfc,0x03,0x5f,0x60,0x0d,0x28,0x84,0x1a,0x07,0x18,0x06,0xaf,0x00,0x1a,0x3c,0x03,0xb8,0xc3,0x20,0xd0,0x28,0x87,0xfc,0x8a,0x50,0x08,0x78,0x08,0x70,0x77,0x0c,0x44,0x06,0x05,0x30,0xff,0x18,0x4a,0x01,0x30,0x01,0x0d,0x33,0x19,0x11,0x1b,0x8c,0xa2,0xf8,0x7d,0x27,0x71,0xd0,0x20,0x51,0x20,0x68,0xd5,0x00,0x42,0x0d,0x2c,0x00,0x08,0x64,0x10,0x19,0x20,0x28,0x75,0x07,0x53,0x3d,0x18,0x35,0x2a,0x9f,0xf4,0x9a,0x41,0x90,0x23,0x00,0x94,0x43,0xe0,0x5e,0xae,0x03,0x9d,0xb4,0xe0,0xd1,0x0d,0x8c,0xd0,0x52,0xb1,0x00,0xd9,0x83,0x46,0x34,0x45,0x41,0xa8,0x9f,0x86,0x01,0x14,0x05,0x08,0x08,0x81,0xa6,0x62,0x10,0x68,0xe5,0x20,0x70,0x41,0x80,0x80,0x10,0xc4,0x34,0x48,0x04,0x2a,0x38,0x0d,0x99,0x16,0x02,0x1a,0xd5,0x10,0x6c,0x5e,0x2e,0x0b,0xa1,0x4b,0x0a,0x60,0xc1,0xa7,0x84,0xfc,0x58,0x01,0xb5,0x02,0x82,0xb4,0xc4,0x16,0x22,0xa5,0x06,0x96,0x19,0x20,0x20,0xd7,0x30,0x8c,0x0f,0x08,0x05,0x10,0x68,0xa1,0x44,0x1a,0x98,0x08,0x14,0x11,0x28,0x21,0x91,0x1d,0x8f,0x83,0xfe,0x07,0x1b,0x00,0x34,0x61,0x00,0xd3,0x1d,0x8c,0x7a,0x01,0x7e,0x80,0x56,0x30,0x06,0xb1,0x4a,0x08,0xd4,0xbf,0xc1,0x31,0xc0,0x7f,0xe8,0xf0,0x08,0x3c,0x40,0x1a,0x80,0x04,0x5a,0x8c,0x10,0x80,0x40,0xd7,0x05,0x08,0x36,0xc0,0xe2,0x0d,0xb8,0x30,0x34,0x45,0x82,0x0d,0x72,0x49,0x03,0x5a,0x41,0x55,0xf8,0x7f,0xff,0xe8,0x72,0x06,0xae,0x03,0xf4,0x0c,0x1d,0xf8,0x18,0x60,0x40,0xd2,0x4b,0x9f,0xd0,0x1a,0x35,0x71,0x48,0xc0,0x95,0x42,0x0d,0x4d,0x50,0x70,0x75,0x40,0xd1,0x80,0x83,0x5a,0xa1,0x55,0x00,0x0c,0x05,0xa4,0x20,0xd2,}; -const uint8_t *_I_iButtonDolphinSuccess_109x60[] = {_I_iButtonDolphinSuccess_109x60_0}; - -const uint8_t _I_DolphinExcited_64x63_0[] = {0x01,0x00,0x36,0x01,0x00,0x25,0x00,0x0f,0xd2,0x00,0x3b,0xe0,0x00,0xeb,0x10,0x0c,0x34,0x40,0x30,0xd0,0x88,0x80,0x1d,0xa1,0x00,0x42,0xfc,0x7f,0xc0,0x63,0x04,0x01,0x0e,0x02,0x0f,0x00,0x00,0x8c,0x08,0x0e,0x37,0x00,0x10,0xc6,0x20,0x10,0x10,0xd9,0x11,0x92,0x1c,0x1a,0x3e,0x00,0x04,0x42,0x02,0x1a,0x20,0xb0,0xce,0x00,0x64,0x07,0x20,0x59,0x16,0x50,0x36,0x45,0x94,0x84,0x78,0x20,0x60,0x75,0x8e,0x43,0x06,0x63,0x3c,0x33,0x94,0x0c,0xd2,0x5c,0x30,0x38,0xe4,0x08,0x43,0x10,0xc0,0x5e,0x06,0x22,0x53,0x1a,0x02,0x08,0x7f,0xd0,0x32,0xc1,0x50,0x21,0x14,0x0e,0x70,0x1c,0x46,0xe2,0x07,0x19,0x06,0x3c,0xdc,0x20,0x91,0xae,0x01,0xcc,0xbe,0x30,0x09,0xfc,0x12,0x41,0xff,0x83,0xcc,0x0a,0xa3,0x1f,0x03,0x99,0xe8,0x7c,0x10,0xf8,0x25,0xa0,0x5e,0x50,0x0f,0x84,0x1e,0x09,0x54,0x03,0x9f,0xf2,0x07,0x02,0xd5,0x11,0xca,0x01,0xfe,0x80,0xc0,0xaa,0x9f,0xf0,0x39,0x5f,0xd0,0x43,0xaa,0x83,0x41,0x92,0xc3,0x1f,0x03,0x8d,0x52,0x02,0x2e,0x25,0xc9,0x6a,0x99,0x46,0xa6,0x2a,0xa0,0x1c,0xaf,0xca,0x62,0x94,0x28,0xcb,0x7e,0x0f,0x15,0x71,0xf8,0x3c,0x22,0x71,0x03,0x8a,0x84,0x67,0x18,0x0f,0xac,0x1c,0x0e,0x38,0x08,0x0c,0x3e,0x01,0xae,0xbd,0x13,0x0c,0x0e,0x35,0x8e,0xa8,0x1c,0xb0,0x1f,0xf8,0x06,0x83,0xf4,0x27,0x38,0x07,0xff,0xff,0x8f,0x03,0xa0,0x4c,0x80,0xed,0x60,0x03,0xb4,0x60,0x0e,0xd0,0x60,0x3a,0x87,0x84,0x0e,0xb7,0xc2,0xfa,0x18,0x05,0x44,0x20,0x73,0xff,0xf7,0xce,0xe4,0x07,0x2d,0x52,0x2c,0x80,0xe7,0x54,0xea,0x81,0xd7,0x50,0x0f,0x7a,0xaa,0x3d,0x41,0xe2,0x07,0x5a,0x80,0x3c,0xa0,0x40,0x72,0xd0,0x6a,0x80,0xa2,0x07,0x3a,0x05,0x54,0x8e,0x20,0x73,0xc0,0x03,0xd8,0x60,0x30,0x40,0x3a,0xc0,0x00,0xee,0xea,0x10,0x3b,0x80,}; -const uint8_t *_I_DolphinExcited_64x63[] = {_I_DolphinExcited_64x63_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 *_I_DolphinNice_96x59[] = {_I_DolphinNice_96x59_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 *_I_iButtonKey_49x44[] = {_I_iButtonKey_49x44_0}; +const uint8_t _I_iButtonDolphinSuccess_109x60_0[] = {0x01,0x00,0xac,0x01,0x00,0x17,0xfe,0x1e,0x0c,0xaf,0x04,0x02,0xe0,0x0d,0xa8,0xf4,0x03,0x01,0x03,0x06,0x46,0x02,0x02,0x03,0x18,0xe0,0x36,0x2c,0x00,0x36,0x00,0x2c,0x40,0x3e,0x60,0xd8,0x84,0x01,0x0c,0x5a,0x40,0x05,0x82,0x01,0x0e,0x04,0x0d,0x70,0x42,0x04,0x90,0x49,0x02,0xe4,0x20,0x41,0x28,0xc0,0x07,0x40,0x06,0xf8,0x00,0xa4,0x00,0xd6,0x03,0xa8,0x37,0x44,0x2a,0x31,0x74,0xd3,0x83,0x57,0x80,0x0d,0xc7,0x18,0xa9,0xa8,0x36,0x2a,0x86,0x06,0x8d,0xfc,0x36,0x60,0xd7,0xc0,0x3b,0x8c,0x36,0xf0,0x4a,0x05,0xf9,0x6e,0x5e,0x06,0x23,0x41,0x24,0x1f,0xf6,0x01,0x74,0x01,0xb1,0xe3,0x82,0x81,0x47,0x40,0x0d,0x7c,0x87,0x8e,0x12,0x05,0x1a,0x84,0x0d,0xb6,0xa0,0xd2,0x85,0x86,0xc8,0x1a,0x50,0x40,0x69,0x40,0xb2,0x1f,0xf0,0x69,0x50,0x01,0xa5,0x08,0xfc,0x03,0x5f,0x60,0x0d,0x28,0x84,0x1a,0x07,0x18,0x06,0xaf,0x00,0x1a,0x3c,0x03,0xb8,0xc3,0x20,0xd0,0x28,0x87,0xfc,0x8a,0x50,0x08,0x78,0x08,0x70,0x77,0x0c,0x44,0x06,0x05,0x30,0xff,0x18,0x4a,0x01,0x30,0x01,0x0d,0x33,0x19,0x11,0x1b,0x8c,0xa2,0xf8,0x7d,0x27,0x71,0xd0,0x20,0x51,0x20,0x68,0xd5,0x00,0x42,0x0d,0x2c,0x00,0x08,0x64,0x10,0x19,0x20,0x28,0x75,0x07,0x53,0x3d,0x18,0x35,0x2a,0x9f,0xf4,0x9a,0x41,0x90,0x23,0x00,0x94,0x43,0xe0,0x5e,0xae,0x03,0x9d,0xb4,0xe0,0xd1,0x0d,0x8c,0xd0,0x52,0xb1,0x00,0xd9,0x83,0x46,0x34,0x45,0x41,0xa8,0x9f,0x86,0x01,0x14,0x05,0x08,0x08,0x81,0xa6,0x62,0x10,0x68,0xe5,0x20,0x70,0x41,0x80,0x80,0x10,0xc4,0x34,0x48,0x04,0x2a,0x38,0x0d,0x99,0x16,0x02,0x1a,0xd5,0x10,0x6c,0x5e,0x2e,0x0b,0xa1,0x4b,0x0a,0x60,0xc1,0xa7,0x84,0xfc,0x58,0x01,0xb5,0x02,0x82,0xb4,0xc4,0x16,0x22,0xa5,0x06,0x96,0x19,0x20,0x20,0xd7,0x30,0x8c,0x0f,0x08,0x05,0x10,0x68,0xa1,0x44,0x1a,0x98,0x08,0x14,0x11,0x28,0x21,0x91,0x1d,0x8f,0x83,0xfe,0x07,0x1b,0x00,0x34,0x61,0x00,0xd3,0x1d,0x8c,0x7a,0x01,0x7e,0x80,0x56,0x30,0x06,0xb1,0x4a,0x08,0xd4,0xbf,0xc1,0x31,0xc0,0x7f,0xe8,0xf0,0x08,0x3c,0x40,0x1a,0x80,0x04,0x5a,0x8c,0x10,0x80,0x40,0xd7,0x05,0x08,0x36,0xc0,0xe2,0x0d,0xb8,0x30,0x34,0x45,0x82,0x0d,0x72,0x49,0x03,0x5a,0x41,0x55,0xf8,0x7f,0xff,0xe8,0x72,0x06,0xae,0x03,0xf4,0x0c,0x1d,0xf8,0x18,0x60,0x40,0xd2,0x4b,0x9f,0xd0,0x1a,0x35,0x71,0x48,0xc0,0x95,0x42,0x0d,0x4d,0x50,0x70,0x75,0x40,0xd1,0x80,0x83,0x5a,0xa1,0x55,0x00,0x0c,0x05,0xa4,0x20,0xd2,}; +const uint8_t *_I_iButtonDolphinSuccess_109x60[] = {_I_iButtonDolphinSuccess_109x60_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 *_I_DolphinWait_61x59[] = {_I_DolphinWait_61x59_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 I_Certification1_103x23 = {.width=103,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Certification1_103x23}; const Icon A_BadBattery_128x51 = {.width=128,.height=51,.frame_count=2,.frame_rate=2,.frames=_A_BadBattery_128x51}; const Icon A_BoxActive_128x51 = {.width=128,.height=51,.frame_count=2,.frame_rate=2,.frames=_A_BoxActive_128x51}; const Icon A_Box_128x51 = {.width=128,.height=51,.frame_count=4,.frame_rate=2,.frames=_A_Box_128x51}; @@ -866,19 +866,19 @@ const Icon A_Level3Hijack_128x51 = {.width=128,.height=51,.frame_count=3,.frame_ const Icon A_Level3LabActive_128x51 = {.width=128,.height=51,.frame_count=2,.frame_rate=2,.frames=_A_Level3LabActive_128x51}; const Icon A_Level3Lab_128x51 = {.width=128,.height=51,.frame_count=3,.frame_rate=2,.frames=_A_Level3Lab_128x51}; const Icon I_LevelUp2_04 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_04}; -const Icon I_LevelUp2_05 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_05}; -const Icon I_LevelUp2_01 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_01}; const Icon I_LevelUp2_03 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_03}; +const Icon I_LevelUp2_07 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_07}; +const Icon I_LevelUp2_05 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_05}; const Icon I_LevelUp2_02 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_02}; const Icon I_LevelUp2_06 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_06}; -const Icon I_LevelUp2_07 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_07}; -const Icon I_LevelUp3_03 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_03}; +const Icon I_LevelUp2_01 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp2_01}; const Icon I_LevelUp3_07 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_07}; -const Icon I_LevelUp3_01 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_01}; -const Icon I_LevelUp3_06 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_06}; -const Icon I_LevelUp3_04 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_04}; const Icon I_LevelUp3_02 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_02}; +const Icon I_LevelUp3_04 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_04}; const Icon I_LevelUp3_05 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_05}; +const Icon I_LevelUp3_01 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_01}; +const Icon I_LevelUp3_03 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_03}; +const Icon I_LevelUp3_06 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_LevelUp3_06}; const Icon A_LevelUpPending_128x51 = {.width=128,.height=51,.frame_count=2,.frame_rate=2,.frames=_A_LevelUpPending_128x51}; const Icon A_NoSdCard_128x51 = {.width=128,.height=51,.frame_count=2,.frame_rate=2,.frames=_A_NoSdCard_128x51}; const Icon A_SleepActive_128x52 = {.width=128,.height=52,.frame_count=5,.frame_rate=2,.frames=_A_SleepActive_128x52}; @@ -887,88 +887,88 @@ const Icon A_TvActive_128x52 = {.width=128,.height=52,.frame_count=6,.frame_rate const Icon A_Tv_128x52 = {.width=128,.height=52,.frame_count=6,.frame_rate=2,.frames=_A_Tv_128x52}; const Icon A_WavesActive_128x52 = {.width=128,.height=52,.frame_count=7,.frame_rate=2,.frames=_A_WavesActive_128x52}; const Icon A_Waves_128x52 = {.width=128,.height=52,.frame_count=2,.frame_rate=2,.frames=_A_Waves_128x52}; -const Icon I_Nfc_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Nfc_10px}; -const Icon I_ir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ir_10px}; -const Icon I_ble_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ble_10px}; const Icon I_sub1_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_sub1_10px}; -const Icon I_dir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_dir_10px}; +const Icon I_ir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ir_10px}; const Icon I_unknown_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_unknown_10px}; const Icon I_ibutt_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ibutt_10px}; +const Icon I_Nfc_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Nfc_10px}; +const Icon I_ble_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ble_10px}; const Icon I_125_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_125_10px}; +const Icon I_dir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_dir_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_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_Button_18x18 = {.width=18,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Button_18x18}; -const Icon I_Pressed_Button_13x13 = {.width=13,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Pressed_Button_13x13}; -const Icon I_Ble_disconnected_24x34 = {.width=24,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_Ble_disconnected_24x34}; -const Icon I_Space_65x18 = {.width=65,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Space_65x18}; -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_Ble_connected_38x34 = {.width=38,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_Ble_connected_38x34}; -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_EviSmile2_18x21 = {.width=18,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_EviSmile2_18x21}; +const Icon I_Ok_btn_9x9 = {.width=9,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_Ok_btn_9x9}; +const Icon I_Space_65x18 = {.width=65,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Space_65x18}; +const Icon I_Volup_8x6 = {.width=8,.height=6,.frame_count=1,.frame_rate=0,.frames=_I_Volup_8x6}; +const Icon I_Voldwn_6x6 = {.width=6,.height=6,.frame_count=1,.frame_rate=0,.frames=_I_Voldwn_6x6}; +const Icon I_Circles_47x47 = {.width=47,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_Circles_47x47}; +const Icon I_Ble_disconnected_24x34 = {.width=24,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_Ble_disconnected_24x34}; +const Icon I_Pressed_Button_13x13 = {.width=13,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Pressed_Button_13x13}; const Icon I_EviWaiting1_18x21 = {.width=18,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_EviWaiting1_18x21}; +const Icon I_EviSmile2_18x21 = {.width=18,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_EviSmile2_18x21}; +const Icon I_Error_18x18 = {.width=18,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Error_18x18}; +const Icon I_Percent_10x14 = {.width=10,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_Percent_10x14}; const Icon I_EviSmile1_18x21 = {.width=18,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_EviSmile1_18x21}; const Icon I_EviWaiting2_18x21 = {.width=18,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_EviWaiting2_18x21}; const Icon I_UsbTree_48x22 = {.width=48,.height=22,.frame_count=1,.frame_rate=0,.frames=_I_UsbTree_48x22}; const Icon I_Smile_18x18 = {.width=18,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Smile_18x18}; -const Icon I_Percent_10x14 = {.width=10,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_Percent_10x14}; -const Icon I_ButtonLeft_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeft_4x7}; -const Icon I_ButtonRight_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRight_4x7}; +const Icon I_Clock_18x18 = {.width=18,.height=18,.frame_count=1,.frame_rate=0,.frames=_I_Clock_18x18}; const Icon I_ButtonDown_7x4 = {.width=7,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_ButtonDown_7x4}; -const Icon I_ButtonUp_7x4 = {.width=7,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_ButtonUp_7x4}; -const Icon I_Warning_30x23 = {.width=30,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Warning_30x23}; -const Icon I_DFU_128x50 = {.width=128,.height=50,.frame_count=1,.frame_rate=0,.frames=_I_DFU_128x50}; -const Icon I_ButtonRightSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRightSmall_3x5}; const Icon I_ButtonCenter_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonCenter_7x7}; +const Icon I_ButtonLeft_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeft_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_ButtonLeftSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeftSmall_3x5}; -const Icon I_DolphinOkay_41x43 = {.width=41,.height=43,.frame_count=1,.frame_rate=0,.frames=_I_DolphinOkay_41x43}; -const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; -const Icon I_DolphinFirstStart4_67x53 = {.width=67,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart4_67x53}; -const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48}; -const Icon I_Flipper_young_80x60 = {.width=80,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_Flipper_young_80x60}; -const Icon I_DolphinFirstStart0_70x53 = {.width=70,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart0_70x53}; +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_Warning_30x23 = {.width=30,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Warning_30x23}; const Icon I_DolphinFirstStart2_59x51 = {.width=59,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart2_59x51}; -const Icon I_DolphinFirstStart6_58x54 = {.width=58,.height=54,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart6_58x54}; 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_Flipper_young_80x60 = {.width=80,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_Flipper_young_80x60}; const Icon I_DolphinFirstStart8_56x51 = {.width=56,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart8_56x51}; const Icon I_DolphinFirstStart1_59x53 = {.width=59,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart1_59x53}; +const Icon I_DolphinOkay_41x43 = {.width=41,.height=43,.frame_count=1,.frame_rate=0,.frames=_I_DolphinOkay_41x43}; +const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48}; +const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; +const Icon I_DolphinFirstStart0_70x53 = {.width=70,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart0_70x53}; +const Icon I_DolphinFirstStart4_67x53 = {.width=67,.height=53,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart4_67x53}; const Icon I_ArrowUpEmpty_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowUpEmpty_14x15}; -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_ArrowUpFilled_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowUpFilled_14x15}; +const Icon I_ArrowDownFilled_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowDownFilled_14x15}; +const Icon I_ArrowDownEmpty_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowDownEmpty_14x15}; +const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; +const Icon I_DoorLeft_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_70x55}; const Icon I_DoorRight_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorRight_70x55}; const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; -const Icon I_DoorLeft_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_70x55}; const Icon I_PassportLeft_6x47 = {.width=6,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_PassportLeft_6x47}; const Icon I_LockPopup_100x49 = {.width=100,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_LockPopup_100x49}; -const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; -const Icon I_Vol_up_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_up_25x27}; -const Icon I_Fill_marker_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_Fill_marker_7x7}; -const Icon I_IrdaArrowUp_4x8 = {.width=8,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_IrdaArrowUp_4x8}; const Icon I_Down_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_hvr_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_Power_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_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_IrdaSend_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_IrdaSend_128x64}; -const Icon I_Up_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Up_hvr_25x27}; -const Icon I_Back_15x10 = {.width=15,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Back_15x10}; -const Icon I_DolphinReadingSuccess_59x63 = {.width=59,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinReadingSuccess_59x63}; -const Icon I_IrdaSendShort_128x34 = {.width=128,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_IrdaSendShort_128x34}; -const Icon I_Mute_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_hvr_25x27}; -const Icon I_IrdaLearnShort_128x31 = {.width=128,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_IrdaLearnShort_128x31}; -const Icon I_Down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_25x27}; -const Icon I_Up_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Up_25x27}; -const Icon I_Mute_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_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_Power_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_hvr_25x27}; -const Icon I_IrdaLearn_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_IrdaLearn_128x64}; +const Icon I_Down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_25x27}; +const Icon I_Fill_marker_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_Fill_marker_7x7}; +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_up_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_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_up_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Vol_up_hvr_25x27}; +const Icon I_IrdaLearnShort_128x31 = {.width=128,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_IrdaLearnShort_128x31}; +const Icon I_IrdaSend_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_IrdaSend_128x64}; +const Icon I_DolphinReadingSuccess_59x63 = {.width=59,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinReadingSuccess_59x63}; +const Icon I_Mute_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_hvr_25x27}; +const Icon I_Back_15x10 = {.width=15,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Back_15x10}; +const Icon I_Up_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Up_25x27}; +const Icon I_IrdaArrowUp_4x8 = {.width=8,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_IrdaArrowUp_4x8}; +const Icon I_Mute_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Mute_25x27}; +const Icon I_Power_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_25x27}; +const Icon I_IrdaSendShort_128x34 = {.width=128,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_IrdaSendShort_128x34}; const Icon I_IrdaArrowDown_4x8 = {.width=8,.height=4,.frame_count=1,.frame_rate=0,.frames=_I_IrdaArrowDown_4x8}; -const Icon I_KeyBackspaceSelected_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspaceSelected_16x9}; -const Icon I_KeySave_24x11 = {.width=24,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_KeySave_24x11}; +const Icon I_IrdaLearn_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_IrdaLearn_128x64}; +const Icon I_Power_hvr_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Power_hvr_25x27}; const Icon I_KeySaveSelected_24x11 = {.width=24,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_KeySaveSelected_24x11}; const Icon I_KeyBackspace_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspace_16x9}; +const Icon I_KeyBackspaceSelected_16x9 = {.width=16,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_KeyBackspaceSelected_16x9}; +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}; @@ -986,57 +986,57 @@ const Icon A_Sub1ghz_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.fr 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_Medium_chip_22x21 = {.width=22,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_Medium_chip_22x21}; const Icon I_Detailed_chip_17x13 = {.width=17,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Detailed_chip_17x13}; -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_bad3_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_bad3_46x49}; +const Icon I_Medium_chip_22x21 = {.width=22,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_Medium_chip_22x21}; 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_bad2_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_bad2_46x49}; -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_happy2_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_happy2_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_happy3_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_happy3_46x49}; +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_bad1_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_bad1_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_okay3_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_okay3_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_okay1_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_okay1_46x49}; -const Icon I_Health_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Health_16x16}; -const Icon I_FaceNopower_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceNopower_29x14}; -const Icon I_Battery_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Battery_16x16}; +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_okay3_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_okay3_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_BatteryBody_52x28 = {.width=52,.height=28,.frame_count=1,.frame_rate=0,.frames=_I_BatteryBody_52x28}; -const Icon I_FaceConfused_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceConfused_29x14}; const Icon I_FaceCharging_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceCharging_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_Battery_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Battery_16x16}; +const Icon I_FaceConfused_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceConfused_29x14}; const Icon I_FaceNormal_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceNormal_29x14}; const Icon I_Voltage_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Voltage_16x16}; -const Icon I_Temperature_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Temperature_16x16}; -const Icon I_RFIDDolphinReceive_97x61 = {.width=97,.height=61,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinReceive_97x61}; +const Icon I_FaceNopower_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceNopower_29x14}; const Icon I_RFIDDolphinSend_97x61 = {.width=97,.height=61,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinSend_97x61}; -const Icon I_RFIDBigChip_37x36 = {.width=37,.height=36,.frame_count=1,.frame_rate=0,.frames=_I_RFIDBigChip_37x36}; const Icon I_RFIDDolphinSuccess_108x57 = {.width=108,.height=57,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinSuccess_108x57}; +const Icon I_RFIDDolphinReceive_97x61 = {.width=97,.height=61,.frame_count=1,.frame_rate=0,.frames=_I_RFIDDolphinReceive_97x61}; +const Icon I_RFIDBigChip_37x36 = {.width=37,.height=36,.frame_count=1,.frame_rate=0,.frames=_I_RFIDBigChip_37x36}; const Icon I_SDQuestion_35x43 = {.width=35,.height=43,.frame_count=1,.frame_rate=0,.frames=_I_SDQuestion_35x43}; const Icon I_SDError_43x35 = {.width=43,.height=35,.frame_count=1,.frame_rate=0,.frames=_I_SDError_43x35}; const Icon I_Cry_dolph_55x52 = {.width=55,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Cry_dolph_55x52}; -const Icon I_Battery_26x8 = {.width=26,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Battery_26x8}; -const Icon I_PlaceholderL_11x13 = {.width=11,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderL_11x13}; -const Icon I_BT_Pair_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BT_Pair_9x8}; -const Icon I_Bluetooth_5x8 = {.width=5,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Bluetooth_5x8}; -const Icon I_BadUsb_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BadUsb_9x8}; -const Icon I_PlaceholderR_30x13 = {.width=30,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderR_30x13}; -const Icon I_USBConnected_15x8 = {.width=15,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_USBConnected_15x8}; -const Icon I_Battery_19x8 = {.width=19,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Battery_19x8}; -const Icon I_Lock_8x8 = {.width=8,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_8x8}; const Icon I_Background_128x11 = {.width=128,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_Background_128x11}; +const Icon I_Lock_8x8 = {.width=8,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_8x8}; +const Icon I_Battery_26x8 = {.width=26,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Battery_26x8}; +const Icon I_Battery_19x8 = {.width=19,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Battery_19x8}; +const Icon I_USBConnected_15x8 = {.width=15,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_USBConnected_15x8}; +const Icon I_BadUsb_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BadUsb_9x8}; +const Icon I_BT_Pair_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BT_Pair_9x8}; +const Icon I_PlaceholderL_11x13 = {.width=11,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderL_11x13}; const Icon I_SDcardFail_11x8 = {.width=11,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_SDcardFail_11x8}; +const Icon I_Bluetooth_5x8 = {.width=5,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Bluetooth_5x8}; +const Icon I_PlaceholderR_30x13 = {.width=30,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_PlaceholderR_30x13}; 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_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8}; +const Icon I_Lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_7x8}; const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52}; const Icon I_MHz_25x11 = {.width=25,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_MHz_25x11}; const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8}; +const Icon I_iButtonKey_49x44 = {.width=49,.height=44,.frame_count=1,.frame_rate=0,.frames=_I_iButtonKey_49x44}; +const Icon I_DolphinExcited_64x63 = {.width=64,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinExcited_64x63}; +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_DolphinMafia_115x62 = {.width=115,.height=62,.frame_count=1,.frame_rate=0,.frames=_I_DolphinMafia_115x62}; -const Icon I_iButtonDolphinSuccess_109x60 = {.width=109,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_iButtonDolphinSuccess_109x60}; -const Icon I_DolphinExcited_64x63 = {.width=64,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinExcited_64x63}; const Icon I_DolphinNice_96x59 = {.width=96,.height=59,.frame_count=1,.frame_rate=0,.frames=_I_DolphinNice_96x59}; -const Icon I_iButtonKey_49x44 = {.width=49,.height=44,.frame_count=1,.frame_rate=0,.frames=_I_iButtonKey_49x44}; -const Icon I_DolphinWait_61x59 = {.width=61,.height=59,.frame_count=1,.frame_rate=0,.frames=_I_DolphinWait_61x59}; +const Icon I_iButtonDolphinSuccess_109x60 = {.width=109,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_iButtonDolphinSuccess_109x60}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index fcc22147..51dbf00e 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -1,8 +1,8 @@ #pragma once #include -extern const Icon I_Certification1_103x23; extern const Icon I_Certification2_119x30; +extern const Icon I_Certification1_103x23; extern const Icon A_BadBattery_128x51; extern const Icon A_BoxActive_128x51; extern const Icon A_Box_128x51; @@ -37,19 +37,19 @@ extern const Icon A_Level3Hijack_128x51; extern const Icon A_Level3LabActive_128x51; extern const Icon A_Level3Lab_128x51; extern const Icon I_LevelUp2_04; -extern const Icon I_LevelUp2_05; -extern const Icon I_LevelUp2_01; extern const Icon I_LevelUp2_03; +extern const Icon I_LevelUp2_07; +extern const Icon I_LevelUp2_05; extern const Icon I_LevelUp2_02; extern const Icon I_LevelUp2_06; -extern const Icon I_LevelUp2_07; -extern const Icon I_LevelUp3_03; +extern const Icon I_LevelUp2_01; extern const Icon I_LevelUp3_07; -extern const Icon I_LevelUp3_01; -extern const Icon I_LevelUp3_06; -extern const Icon I_LevelUp3_04; extern const Icon I_LevelUp3_02; +extern const Icon I_LevelUp3_04; extern const Icon I_LevelUp3_05; +extern const Icon I_LevelUp3_01; +extern const Icon I_LevelUp3_03; +extern const Icon I_LevelUp3_06; extern const Icon A_LevelUpPending_128x51; extern const Icon A_NoSdCard_128x51; extern const Icon A_SleepActive_128x52; @@ -58,88 +58,88 @@ extern const Icon A_TvActive_128x52; extern const Icon A_Tv_128x52; extern const Icon A_WavesActive_128x52; extern const Icon A_Waves_128x52; -extern const Icon I_Nfc_10px; -extern const Icon I_ir_10px; -extern const Icon I_ble_10px; extern const Icon I_sub1_10px; -extern const Icon I_dir_10px; +extern const Icon I_ir_10px; extern const Icon I_unknown_10px; extern const Icon I_ibutt_10px; +extern const Icon I_Nfc_10px; +extern const Icon I_ble_10px; extern const Icon I_125_10px; +extern const Icon I_dir_10px; extern const Icon I_BLE_Pairing_128x64; -extern const Icon I_Voldwn_6x6; -extern const Icon I_Volup_8x6; extern const Icon I_Button_18x18; -extern const Icon I_Pressed_Button_13x13; -extern const Icon I_Ble_disconnected_24x34; -extern const Icon I_Space_65x18; -extern const Icon I_Circles_47x47; -extern const Icon I_Ok_btn_9x9; extern const Icon I_Ble_connected_38x34; -extern const Icon I_Clock_18x18; -extern const Icon I_Error_18x18; -extern const Icon I_EviSmile2_18x21; +extern const Icon I_Ok_btn_9x9; +extern const Icon I_Space_65x18; +extern const Icon I_Volup_8x6; +extern const Icon I_Voldwn_6x6; +extern const Icon I_Circles_47x47; +extern const Icon I_Ble_disconnected_24x34; +extern const Icon I_Pressed_Button_13x13; extern const Icon I_EviWaiting1_18x21; +extern const Icon I_EviSmile2_18x21; +extern const Icon I_Error_18x18; +extern const Icon I_Percent_10x14; extern const Icon I_EviSmile1_18x21; extern const Icon I_EviWaiting2_18x21; extern const Icon I_UsbTree_48x22; extern const Icon I_Smile_18x18; -extern const Icon I_Percent_10x14; -extern const Icon I_ButtonLeft_4x7; -extern const Icon I_ButtonRight_4x7; +extern const Icon I_Clock_18x18; extern const Icon I_ButtonDown_7x4; -extern const Icon I_ButtonUp_7x4; -extern const Icon I_Warning_30x23; -extern const Icon I_DFU_128x50; -extern const Icon I_ButtonRightSmall_3x5; extern const Icon I_ButtonCenter_7x7; +extern const Icon I_ButtonLeft_4x7; +extern const Icon I_ButtonUp_7x4; +extern const Icon I_DFU_128x50; extern const Icon I_ButtonLeftSmall_3x5; -extern const Icon I_DolphinOkay_41x43; -extern const Icon I_DolphinFirstStart7_61x51; -extern const Icon I_DolphinFirstStart4_67x53; -extern const Icon I_DolphinFirstStart3_57x48; -extern const Icon I_Flipper_young_80x60; -extern const Icon I_DolphinFirstStart0_70x53; +extern const Icon I_ButtonRightSmall_3x5; +extern const Icon I_ButtonRight_4x7; +extern const Icon I_Warning_30x23; extern const Icon I_DolphinFirstStart2_59x51; -extern const Icon I_DolphinFirstStart6_58x54; extern const Icon I_DolphinFirstStart5_54x49; +extern const Icon I_DolphinFirstStart6_58x54; +extern const Icon I_Flipper_young_80x60; extern const Icon I_DolphinFirstStart8_56x51; extern const Icon I_DolphinFirstStart1_59x53; +extern const Icon I_DolphinOkay_41x43; +extern const Icon I_DolphinFirstStart3_57x48; +extern const Icon I_DolphinFirstStart7_61x51; +extern const Icon I_DolphinFirstStart0_70x53; +extern const Icon I_DolphinFirstStart4_67x53; extern const Icon I_ArrowUpEmpty_14x15; -extern const Icon I_ArrowDownEmpty_14x15; -extern const Icon I_ArrowDownFilled_14x15; extern const Icon I_ArrowUpFilled_14x15; +extern const Icon I_ArrowDownFilled_14x15; +extern const Icon I_ArrowDownEmpty_14x15; +extern const Icon I_PassportBottom_128x17; +extern const Icon I_DoorLeft_70x55; extern const Icon I_DoorRight_70x55; extern const Icon I_DoorLocked_10x56; -extern const Icon I_DoorLeft_70x55; extern const Icon I_PassportLeft_6x47; extern const Icon I_LockPopup_100x49; -extern const Icon I_PassportBottom_128x17; -extern const Icon I_Vol_up_25x27; -extern const Icon I_Fill_marker_7x7; -extern const Icon I_IrdaArrowUp_4x8; extern const Icon I_Down_hvr_25x27; -extern const Icon I_Vol_up_hvr_25x27; -extern const Icon I_Power_25x27; -extern const Icon I_Vol_down_25x27; -extern const Icon I_IrdaSend_128x64; -extern const Icon I_Up_hvr_25x27; -extern const Icon I_Back_15x10; -extern const Icon I_DolphinReadingSuccess_59x63; -extern const Icon I_IrdaSendShort_128x34; -extern const Icon I_Mute_hvr_25x27; -extern const Icon I_IrdaLearnShort_128x31; -extern const Icon I_Down_25x27; -extern const Icon I_Up_25x27; -extern const Icon I_Mute_25x27; extern const Icon I_Vol_down_hvr_25x27; -extern const Icon I_Power_hvr_25x27; -extern const Icon I_IrdaLearn_128x64; +extern const Icon I_Down_25x27; +extern const Icon I_Fill_marker_7x7; +extern const Icon I_Vol_down_25x27; +extern const Icon I_Vol_up_25x27; +extern const Icon I_Up_hvr_25x27; +extern const Icon I_Vol_up_hvr_25x27; +extern const Icon I_IrdaLearnShort_128x31; +extern const Icon I_IrdaSend_128x64; +extern const Icon I_DolphinReadingSuccess_59x63; +extern const Icon I_Mute_hvr_25x27; +extern const Icon I_Back_15x10; +extern const Icon I_Up_25x27; +extern const Icon I_IrdaArrowUp_4x8; +extern const Icon I_Mute_25x27; +extern const Icon I_Power_25x27; +extern const Icon I_IrdaSendShort_128x34; extern const Icon I_IrdaArrowDown_4x8; -extern const Icon I_KeyBackspaceSelected_16x9; -extern const Icon I_KeySave_24x11; +extern const Icon I_IrdaLearn_128x64; +extern const Icon I_Power_hvr_25x27; extern const Icon I_KeySaveSelected_24x11; extern const Icon I_KeyBackspace_16x9; +extern const Icon I_KeyBackspaceSelected_16x9; +extern const Icon I_KeySave_24x11; extern const Icon A_125khz_14; extern const Icon A_BadUsb_14; extern const Icon A_Bluetooth_14; @@ -157,56 +157,56 @@ 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_Medium_chip_22x21; extern const Icon I_Detailed_chip_17x13; -extern const Icon I_passport_happy1_46x49; -extern const Icon I_passport_happy2_46x49; -extern const Icon I_passport_bad3_46x49; +extern const Icon I_Medium_chip_22x21; extern const Icon I_passport_okay2_46x49; -extern const Icon I_passport_bad2_46x49; -extern const Icon I_passport_bad1_46x49; +extern const Icon I_passport_happy2_46x49; extern const Icon I_passport_bottom_128x18; -extern const Icon I_passport_happy3_46x49; +extern const Icon I_passport_happy1_46x49; +extern const Icon I_passport_bad1_46x49; extern const Icon I_passport_left_6x46; -extern const Icon I_passport_okay3_46x49; +extern const Icon I_passport_bad3_46x49; extern const Icon I_passport_okay1_46x49; -extern const Icon I_Health_16x16; -extern const Icon I_FaceNopower_29x14; -extern const Icon I_Battery_16x16; +extern const Icon I_passport_bad2_46x49; +extern const Icon I_passport_okay3_46x49; +extern const Icon I_passport_happy3_46x49; extern const Icon I_BatteryBody_52x28; -extern const Icon I_FaceConfused_29x14; extern const Icon I_FaceCharging_29x14; +extern const Icon I_Health_16x16; +extern const Icon I_Temperature_16x16; +extern const Icon I_Battery_16x16; +extern const Icon I_FaceConfused_29x14; extern const Icon I_FaceNormal_29x14; extern const Icon I_Voltage_16x16; -extern const Icon I_Temperature_16x16; -extern const Icon I_RFIDDolphinReceive_97x61; +extern const Icon I_FaceNopower_29x14; extern const Icon I_RFIDDolphinSend_97x61; -extern const Icon I_RFIDBigChip_37x36; extern const Icon I_RFIDDolphinSuccess_108x57; +extern const Icon I_RFIDDolphinReceive_97x61; +extern const Icon I_RFIDBigChip_37x36; extern const Icon I_SDQuestion_35x43; extern const Icon I_SDError_43x35; extern const Icon I_Cry_dolph_55x52; -extern const Icon I_Battery_26x8; -extern const Icon I_PlaceholderL_11x13; -extern const Icon I_BT_Pair_9x8; -extern const Icon I_Bluetooth_5x8; -extern const Icon I_BadUsb_9x8; -extern const Icon I_PlaceholderR_30x13; -extern const Icon I_USBConnected_15x8; -extern const Icon I_Battery_19x8; -extern const Icon I_Lock_8x8; extern const Icon I_Background_128x11; +extern const Icon I_Lock_8x8; +extern const Icon I_Battery_26x8; +extern const Icon I_Battery_19x8; +extern const Icon I_USBConnected_15x8; +extern const Icon I_BadUsb_9x8; +extern const Icon I_BT_Pair_9x8; +extern const Icon I_PlaceholderL_11x13; extern const Icon I_SDcardFail_11x8; +extern const Icon I_Bluetooth_5x8; +extern const Icon I_PlaceholderR_30x13; extern const Icon I_SDcardMounted_11x8; -extern const Icon I_Lock_7x8; extern const Icon I_Quest_7x8; +extern const Icon I_Lock_7x8; extern const Icon I_Scanning_123x52; extern const Icon I_MHz_25x11; extern const Icon I_Unlock_7x8; +extern const Icon I_iButtonKey_49x44; +extern const Icon I_DolphinExcited_64x63; +extern const Icon I_DolphinWait_61x59; extern const Icon I_iButtonDolphinVerySuccess_108x52; extern const Icon I_DolphinMafia_115x62; -extern const Icon I_iButtonDolphinSuccess_109x60; -extern const Icon I_DolphinExcited_64x63; extern const Icon I_DolphinNice_96x59; -extern const Icon I_iButtonKey_49x44; -extern const Icon I_DolphinWait_61x59; +extern const Icon I_iButtonDolphinSuccess_109x60; diff --git a/assets/icons/Animations/LaptopActive_128x52/frame_02.png b/assets/icons/Animations/LaptopActive_128x52/frame_02.png index 5a3c3418034792575edc33de3d285ec478141953..d0b19f66a05c71fc36ca1f8df0962d0d3dfd9295 100644 GIT binary patch delta 809 zcmZ1@*vB(LMNP8AHKHUqKdq!Zu_%?nF(p4KRlzeiF+DXXH8G{K@MNkD0|RrxM4uUQ zsVRv@Nycf3$vO%~21bVZhCpPlYiMp|WNc+p`7)+LBmVqfU#HlEj*<^Ayi@vU*Nur^#fkl$8 zNs@tquCalMp>Co@QmU?LT3WJEvVpN#lChDJLUBn@YMNEb*&J93`|rt5 zR1~RaQu1_h45_&FCZgN#hyl;)|NoZ@-dcD1_r_EXPOZj-?a_N~c+Oq-^}5)u@64M& z?tOmnC(G+xhU20&o1E>A$8BagP<5K0LFRv>Vq~(wgA)&`f^}r;_?UDQ>y8IABuq4q zU=Yx<&a^YESfYIG+P`TP43D<1oA0WTp>#va>YvNr5A}}OkC_+TaWUA?!!u>K#IsjT z(-TDx@-WO~Tr;1|VU@!BJq5S9W*urhb0COo%dQXH3@vN|+s`r_*tmQ`*1d4YMRUsE zCVgjovn=L3!xMeI9D`|^tZQ^4|42A;IE0I>OM7k1zS!o^Jn8g=o02=$sY%|L>-FB_ z14F^Q*5f;@N-de0>KT+XHV9fWEMbdi^*egMFd_G*$-ZNjk0(9hl-r<)i1N^h_o_PNS9 zWs1=8bl?5Hj#o;HHy=8u&=^{7)7zQIt(JOO``OZX!Beu?Ckt%0p1HTNFmRc$d)IfN i3Bh0Y*FF3tl)z9R#rj?IxXg0~AnM4hPOY))`-y`|PE?Qf#59-DEPY$^lU8YOZ7(1RP-G!y zs06JhI_G?3VfaEc>ayvK4o#SB#^GjAm`pQys4x?wxQFX5zBadH*&ipr*O%{n-#I70 zx={z>>kU()a_2d-!{IOhV9}SCDwQS1H}~xT0I>=MB%hb}>>rXp{E z<~fVrCCfedxo(-mn2I8mlV1NC5?D~7=px5 zfm#=;RHYcqgn$`w)&z45%fh7DD8ekp5U|LSX#~L;aSSCwpQ*^8!sw&3`~o8jb|ozO zVG}Th!zk&*a2h9Q9Gi|3G>Q%<_t7~L?-tAc0W~^toF*}vq+WmuGQ%@6^IzblkBNDX z7A3!jku7?+hba^gpSMu2eP&G2ClyJ4CG)Vnzu!BuvU2^B=q^$o0t@D3Y8}~G6lSI< z7*EAQcT}h$O(Zympm>;MSq>)C1S4!V6Bvx*0)?4G45vgiWK|~y8D3%qnwK~?|Gd0D z8l^;$q$m*wWXWHqoc+8=FBDci z-4(gDkB5L}IN2?E6|qc-!0Vr0y1fB8$ap!yVYlcNqExq{;r}%789}K_P&l7A?%&;b zk~|=Zaw+2%Y=z1|S@gDH$J*Q{qZGQLN<^OO;arTjP~a_kTvXX_Bxw&Q`EhW>s^0LjA*u(Ux@{$t4o`~k4Nr| zyjP=(rEhg5cl%Rzy@LnsHOmu%XIgg;?d(g+kUd@Cs-arFZuPEjSkscE zsw&r19Z@ZeT-g)Xzi6yr+pV2cU%zI3jRpKvXKkCKi_X0yjsz{+8>VbQ#0~xSHfVX} zp#)VV$S~!4X7|Jr5e+joJW7U~ncFh(%f{O_A4yQbW{y6jYXq*ba}ykut4 z*ogRr72x2!y#p!j-J@;iK3{p5ZD6dw?pvknsC8^xajv+(bllDNkCLX0EniDG=NYrY> zi)vDL_eQ5B&fpXMncaQ&{NcMlE`H{Cr*NP5!Olb0)`x3v?TTjDv%QA-!B75HmvxQ` z3mof%Q~2unndAiRANw+V=qlgHXrNO)^=GT1mQ{A%*8G|58{#h2r)V5hYdW^@x&N#B z-t#x4^BGbFA08?)3J5cN_q8?euvU{bLk`=7`D_Lyj_dZcY&xV?xKVOKXX8AsdS-^h zjMp~pWcct#)7gCcYM#Kj`B`V>m@^i|oM-qpUCnIOsbtQO=v6>u&Lw?8ysy!PDOuO{2{f$R{81uy$w$5 z!aU%*YL(BK!0#a&PsY@yIsdwM zDS8=?f;6MT_crJ6yBGpkwlQ2QTXEso>43khq`gJd?||)G=|_x=@GrtFJZP+PKE9UH*u;%D0(0zu#yzJQ8d_ z>yTkv_IUR87|!LFBHT+YSOPBhp1feWbeU8P-a^p0v w96?x1+^Ro41Q*;t2x>ibua*dr>mdKI;Vst0LGX(+W-In delta 1314 zcmeC;St>X|MT0HCC&cyt|NjgO455cE*8wTc0*}aI1_o|n5N2eUHAjMhfsJ{h*9@7I z#H7UJq$C{$BLgEteFGDHLla#C11n=oD-)ARjCWXzOI*uJCf{e26D|&^EJ)Q4N-fSW zElN&xElbTSnS7a1&mt$U*eWI2Rw<*Tq`*pFzo4`zM=!r9T|XsRKQ$*c7pSaQ-%!s` zUrC`N7o@fzBfliSI3s`ZJw|a3IOjWK+T<8!#mRL{(vxMF)h6#|GO7n^D6n!aN=+Wl30?6PjM93;FM&mwEUvn#1dPj%-qEERQ-aybR`9tyMgY@&&e+W+6;0Yvbd+S zb3jpkT4oMVqBzLiNx{?A+04+=%uLrv&v5b^CIc1oG~?t%W3v=plcc0%T@&+EQ(a3- zV?$j7qf|3Pi!?(cvowRr4$LC;i7EL>sa7fZ$(bqe&?~SqFiT4_F*8fkO*2YO)HO3T zN!CqFG)>V>GBq+v0UB#&W?`L}b3>sfwE04_LlKi4dAipRj%_=yx5X#EQQ~<}Z zRbp~UW_}*fv594=DN0bm%)H`~$vn&!7Qj?sRi2Rwl!r$GX2?PeD$Y+UDNig)bxa2( zkyA{{`cT7?GZORCQ&Vh}^ug}ZM>s?u#f_8em>uew*H?EiFff^Ux;TbJ9DY0FVIGSj zN6XK9|Cj!LTo&%&aOc(%&+JRf_TIfL*j5SdywAl?+ zCw>S{ZSrN|uWz@jzocJNl6!~YmeQd{L6-$IC12FN2@KvCx;7N7mqMz-SlDn;Br}HY1h#ehQ3>57#>&8713b$@nk`t zq@;e2$c#-Uudj0iv=}`@U|P#z<7Jv1?{X+R z+w07G@#8j+R~Vl>rTl<##gaS@<*&{j3_da+L=Sa7o@KepQ}jStZ#iSe*(9r1PJxfF z{8DW=wO`h8 zg8|DohAeBB)3dv#^D{G?u7AMGu(PV2;Z5g#_5-`}V`dfKKP$_y;ks;vym9K``VH(0 zcGg9-EtK96df~;oYRL`HS6Ohsy1l7R{$En9W6}JR+s?mZ%7`oc!Lj68a(V6c(_R+6 z$JkaK_GYlXd*R-(g62c5>*ln&Z^-kTDxfE|VJ<^XjILoh%S`_@*Qal1I264w?CMp& zD;z>IR@ya)1;6^*`yzk&0wGx`kt@ggc(3m;$Z=gRbLNufU%tS55#G&@cTcn2ZI*ZG n%aN&%b~CIA{%T+M@CTD-6zhq�Rf|{_x!&7e8~nQ@GFjVCNxg>%+CTc11Jn*DSY+(Omc$uk9`?Fbd_&pG|;J@`mYyM334RM$1Q#1~$H62^{-2YX5 z@A(_j`3$Lo4-XX?1%w&C``Vg!SgXmJA%|_kd^Up;$8~#JHXTwc+$cGrvvD3*Ju|~$ z#%r5)GJJTW>1@7zHBVsN{H(Kb%o&Sf&NF_1Df@waVvA;P;S?Cu3^UoPXWB z6upc`L7GwFdzX^7|U8uwR)z_MCZCqp5E`LN^<=f1h-*2=U9tpOe zb;z(Sdpvu44CnGo5$>fHECH8$PhPNGx=bpbseC&B@@4@w<{N%YW_{CUs5hNZU-$U5 zCd2m-4eMJU`ED1S36XW^)O`KJ>&tfU4MMV9A~LX|MT0HCC&cyt|NjgO455cE*8wTc0*}aI1_o|n5N2eUHAjMhfsJ{h*9@7I z#H7UJq$C{$BLgEteFGDHLla#C11n=oD-)ARjCWXzOI*uJCf{e26D|&^EJ)Q4N-fSW zElN&xElbTSnS7a1&mt$U*eWI2Rw<*Tq`*pFzo4`zM=!r9T|XsRKQ$*c7pSaQ-%!s` zUrC`N7o@fzBfliSI3s`ZJw|a3IOjWK+T<8!#mRL{(vxMF)h6#|GO7n^D6n!aN=+Wl30?6PjM93;FM&mwEUvn#1dPj%-qEERQ-aybR`9tyMgY@&&e+W+6;0Yvbd+S zb3jpkT4oMVqBzLiNx{?A+04+=%uLrv&v5b^CIc1oG~?t%W3v=plcc0%T@&+EQ(a3- zV?$j7qf|3Pi!?(cvowRr4$LC;i7EL>sa7fZ$(bqe&?~SqFiT4_F*8fkO*2YO)HO3T zN!CqFG)>V>GBq+v0UB#&W?`L}b3>sfwE04_LlKi4dAipRj%_=yx5X#EQQ~<}Z zRbp~UW_}*fv594=DN0bm%)H`~$vn&!7Qj?sRi2Rwl!r$GX2?PeD$Y+UDNig)bxa2( zkyA{{`cT7?GZORCQ&Vh}^ug}ZM>s?u#f_8em>ud*XLCMeU|=%yba4!cIQ(|T!#oy6 zj+USI{xALgxGdbk;m)lkp4pd{?Y(NL$sd-~?O58sg79}MnV}?afWOW#1POmeGm)Nuh?P zNlE=4kr|szUSH=3Xfb+zqWFN)Gs)}vyU$nDh03WiJQI0fnV?*+z_gab#>+H2-sMns zw%3{W;>T?suP{D&O8EifiY0j*%3qy57<^<4z`$IL3ee^!=Z!*$sTdE?Z>^&8k1 z?5vAuTPVFD^umjE)sh>Yud?8Nb$e5t{J*4H$D;Wsx1E2-lo40>gJa3Hr@btC zkFl*f?9E_%_rkqn13VtQ&&YGO)d;mK4R1_tJWi9R#r zQd1I*l8n<5lXVn~42%r*4S~p9*U;R`$k@uzauVYm=8D{c$qyOjCeLL`P%yNxFfunX zGc+?Ybv86~b#`=ea&vPwGdFNGuyitYvY0H(ECW+yfKyQ{v&rOa7X8VV%xdh#B|)ia zRwH+9ZSh}@x`nk;2MSwHTR$rQbxWFI&+p+s`8ctaIl?|BX*${&e+SxUgb`%LU7lnkDn< zf1J3pgJFtm3-9TV4v|N1Oc%G}UCr^0VT0U)za|V5S&N?@EtOYX;#kRHdx4FuN~>qT zwLXIc--Od?91pI2h>P1{A8Q@&R9vjfcENS07?Wp$l~U!x#QRkoAyHbtEt?K9_cO5Q ziM-i-Z%&%075) z+hYId&Slk`TxSAat*N~8IctpQ@Ij7D1 z>|XW&d6B#Iv)eLmaGNqr{psyjb@A2Hxc}S21fCs%~HJQg6vJ^Of7V*`lRvoNMoy`blj| z2`Z~TTKOuxNNaN;uSK9TvB3399cf91YDoq?I*vmqNFPgjx`0}yz+ L`njxgN@xNA5+Ok} delta 1301 zcmbQiGedBKiUwPNPl)UP|Nj{n7(x$St^-n>1s;*b3=G`DAk4@xYmNj10~_;1uNg8a ziAjmcNl7{iMg~TP`UWQYh9KyqzM-C> zzLG*kE=X-bMt(_taYp{+dyL{7aL#wew8=5dij(V@q$kTTt4-d`WK<8-P+;X;l$uzQ z>H@^JN+37t8XD;un1mP_Ss9sH85?LD7+V<_fXpti^36}lOshmwY8ql>WMyJ#WonM1 zG_@o#C9xzCpW-O6!70gBY57IDi6yp5nYoGSsrm(Z=}HPPcLUv*pOaq%v>D_)WN}Yt z=YXR8w9Fi!L~)S2lY*zKvzei#nVGJUp5f#-Oa?0EX~xNk#%3wHCP_)jx+dnSrn;7v z#)i5EMyY0o7HNh?W@!eK9hgPx6I1e&Qms<*lQUD`p;usKV3w97&N}VRvwwfCHX~_Kz>n5npJRWA(WMqsQ`{+ ztHk7z%=|o{V-w3#QX;5n zBBz*?^`V9(XC&sOr>58{>4V*+k8p@SiW?`_F+0?|oGj^QU|`bpba4!cIQ(|T?Ytuj zJT8|1|6i`X;ZVc6**k1%)GDu=EiDHhpPq5;->rmlyE(D;zvWH}-@42YSN`If;Cac% zI*cy6-!N4CbyCbct}tQ8!M(w=;{VC8D7mxPFerWEV`DgWT5py6ph`%N!r-b3D%ArQVhy`~9o)yX`%rgsS=&`B$`*pz^)@AW`SN2&pOq}A)U{%d`U`Ks^hL5z!iVY#J&kH8# z?cBafM}SGeQ`fQLiRJaEhDEFzkqIeU@e?oHes_nH%cb(=dc}H{#;=WMnAjSWR?K*+ zoj8MGgI&Y&nkc!`i5@| z*$k&r^Gcg5`A^)e2719{Xf&EE7%HF&jM-RQt_K;Z472b({)Zdn(_nRR

bsMWfujgESDlAj08P-%p7Gy;UEw|ND zydYG%T~AI)@SL=PnfKLoY96ycWN~aMXKY#Sw0iN}7aMvVe6BK1u}R%$x6IS~#^Qu& zrPq^O=Q=vAUVW@JVRp%>g<&!6bw>m5O`OJceEB3xYcsuFFFTcwe&^Y+>{b1rLm!!U Xl(YWLRbY|<7I_Swu6{1-oD!M3VtQ&&YGO)d;mK4R1_tJWi9R#r zQd1I*l8n<5lXVn~42%r*4S~p9*U;R`$k@uzauVYm=8D{c$qyOjCeLL`P%v<|aCS8` zw=^>{bv86~b+&MIc6D(yGjVgYurzVDFqk$1zkK=1USW5{MB6BoD zlSucs9|jEu%&{xo-hSTYkm9Ye>c9$%3#|6%>l;`LTA#J>E!fk+obaIG?F9FaM>ktU ze%-~e>|B;H|0|X>i&rt)Cs+Q^Y&f%D*0OUdx3q`k3hf>3Lgo4q(XIEm_F68xA+jR) zvv^ZlD#K<$hG+KzO4f5T6jx+2?3C3i`G1ygsm82bIgB3XYWN$JE;BJaD}H=s&h5;1 z3=Laf9{5#1W1-ZyUQ>pnKk}rvExh0?K1H=AjInlI6nEC~O}}LJ3GTm`H2>tL^Xr&2 z;tFr@v|LLz-B)?a$71R+t5t{98fN8r$79MZef^na><)FL79KK z0?XDcJ@oO4k^A*yuCwOt2)g5aU{A>Z*W&B+8QB;v`m!E!4s>v000K`}KbLh*2~7ZG CGeh?P delta 1283 zcmbQhGevNM%H*TWg5nIE1s;*b3=G`DAk4@xYmNj10~_;1uNg8aiAjmcNl7{iMg~TP z`UWQYh9KyqzM-C>zLG*kE=X-bMt(_t zaYp{+dyL{7aL#wew8=5dij(V@q$kTTt4-d`WK<8-P+;X;l$uzQ>H@^JN+37t8XD;u zn1mP_Ss9rEovCeLY-L~oGP}UaH$NpatrAVCX^4@Lm5Gs+fgy_0)RM%M#F9jOile{= zrzBgYKEjtD=EO-4Rl|APJR*4W{~rc#XX&!1B&v~GIM|u#X;^) z3ZAacW`>q#X1YdthLhhg87P~l87C(io2BTQBqb&5nwY1W>RMVF8|oSurJ5O9q!}8S zrA@YH7OhWA$xlkPO36>oOo0bpft7(-TAGQOS(fJ zR5LRRb0vK{1sh<<`1)FTWEPj?7gYlJMJZ`k!KsB%R!*h@IEt+jlS?x5^MGzmEK5yM zf(mBl6_-rrVYaXUCIYMSj8vdJJPt4e7Gh9wep*R+Vo|DNIw*ylVp7(J8kU@qn3tZK zVymPNc9%ZFA^Iq8oLtB3P=72*?-TZq5Tysq6<{>$6NM z<7M)bJTvvux0ml74`{h0us2NI)6L=#dei!BK2O}G&g|?z)2kRiW_-RqO+-eiUc&Ut zt|fjoVR##{c(5fKx#_2+jx+}64flxP>nd}Py0 zri2$ieqZ*yX+ERQbZMW&0fDDN4fFQ$9@t?oZc=9!q>!QctY2_}-b`;%K?BAI9^H=p zN)6@{wFDQ4G%gI;{cUCH_dB|p5! zY^x6O6?1sCM($O^jmDeXtS);MW&aa!cyfQ;n8z0XqSnGcKb?TGgl&Ncrju=nO zF$$l5bHdK;KBuNIrsy&}xmS?5o|7T)fRsZ{JJ*}}R~1EEr|I=Gbi^vLD|EeNV5q!5 zV^;Cq`m?bN1=nOV6uNJv7&`G&=14Vfi!nGxnW- zaw9#QQKa9ZgeB&6q1FDVRFyeS$-Gw|DmKi@TXWCt3foG~FLPVnCYUep7Et58;mN?) zH|>Ts(|Pq{pSLe(I1{|^O~!GnoWlmer3_2GI-k3ja;Cd#cDS@VajrYo$9#Q;#I^;& zX7_>?)-4T~7vbIbc=xoM)@FLsUiK;3VtQ&&YGO)d;mK4R1_tJWi9R#r zQd1I*l8n<5lXVn~42%r*4S~p9*U;R`$k@uzauVYm=8D{c$qyOjCeLL`P%tntbarz! zv@|m^bv86~b#^i~HgGj?vNSR@vox}FGn_2TEGrLDV}VmmEVIevY!>~=mdtAG#U(+h zX;vwdUon|5>Q5GCb70wj;Z52^MUi?Y9Zwg>kcwMxW;Es={kHfoN8Q3&sRM!5A|GFj3uxI%mhJqSr#mw6Z z0v8_C1>MT1lV`C}s=F=C@PIWxnJFQntnKF!0oJ*5qW{LHF@L)HE?ihK!sUWxNzIaZ z^*>JB*}*WywT1WeM~BFxH>QhQ@vi3h#;`$d!Cw=GiLAv>kCw_SE^(~nu)V;>R;AUm z-&&tRf^Wj!+?KE%cCu#dHlcPcK{WxL?IQ;f+o!AhxeVdDKNj*uv=-1s;*b3=G`DAk4@xYmNj10~_;1uNg8a ziAjmcNl7{iMg~TP`UWQYh9KyqzM-C> zzLG*kE=X-bMt(_taYp{+dyL{7aL#wew8=5dij(V@WG2fpt4`j{WK<8-P+;X;l$uzQ z>H@^JN+37t8XD;un1mP_Ss9sHnV4%E7+V<_fXpti^36}lOshmwY8ql>WMyJxWnhA$ zG_@o#C9xzCpW-O6!70gBY57IDi6yp5nYoGSsrm(Z=}HPPcLUv*pOaq%v>D_)WN}Yt z=YXR8w9Fi!L~)S2lY*zKvzei#nVGJUp5f#-Oa?0EX~xNk#%3wHCP_)jx+dnSrn;7v z#)i5EMyY0o7HNh?W@!eK9hgPx6I1e&Qms<*lQUD`p;usKV3w97&N}VRvwwfCHX~_Kz>n5npJRWA(WMqsQ`{+ ztHk7z%=|o{V-w3#QX;5n zBBz*?^`V9(XC&sOr>58{>4V*+k8p@SiW?`_F+0>t3o5K(U|`bpba4!cIQ%xEJMV}B z&*A_7FJCTceI{G%zT8v#@{%}jX<_w)i9P$xHdxDBWZVCio1`w`&s=f$;FrFNKGSnT z4H;8~8RGUYn9!3fFrnq(-XNa*e=;mCjX!eFGdj53JIK<|xvBdZx3inos~b`IGx-IBXok4dtD)cNl15e!cR+rKvapR?NOHs6O??&5xuF$X8MEGXh{5Y^{hzD%|7 zRLOb^_49;Y{rt*#qQwhl`HSL%=^aT z1*>-LjR;JiaNt2`vhs~CKg%m!wXcjDKlN=1v9OzZ=H^C2$z|$&BKM0O{ICB1(fXKs YM>*?XRaxsIV3Eh*>FVdQ&MBb@05tOC!T3VtQ&&YGO)d;mK4R1_tJWi9R#r zQd1I*l8n<5lXVn~42%r*4S~p9*U;R`$k@uzauVYm=8D{c$qyOjCeLL`P;fIhGIVw{ zv@kO=buu(`b#^p%c5!mGbTKq^v2eDqG@mTXECW+yj#E)Av&rOa7X8VV%xdh#B|)ia zRw>G;or?E2h|ziKU{?Qiuz5WcmXanHSnr}}=(*>_Hi;k~9l!=8UmikZh1 z1TH+N3%VuoPlm-tsqVNm!voRx3Csx*-}F99JBO4M<$e8cBt2n$*?*J3CRdiZ&g-Yw zUy+u-DJ|ZxsiPplQc`2J#PeTH+Y?0(N-~%+Z<)`guq$ERo*gfhTTC?g6WMMZaPV*a zSpJ-m;V@&-O&-QOQuq4B--Ta4H~qq$m~O_Bz;#m{gl6=4?7O&Oe-&p)^r|10O^VFX z3{4{4-+mZ07%<1KbbI@GmqUuT#;OA=EH1FxpRaFVEogn#!na^g2Xn%MhPM;kKOWs| z5&3l&!?JT(#{92X(kx!ZXrEm9L$l$`ep$=Tsoc^Yk}I@#v-@T~apl{vRF z-!U|7eR<$l{fvcD-+E0Mj{eA#-nQ_9v-lL%nlQ%Nby3_|$2a|w*(bRFV$%GRo6fIe z(uga(!P9ar*>qp!DIbfe$E;QzR%@7*=aIj7hhrMkaUHx3vIVCg! E0PT-NkN^Mx delta 1297 zcmbQhGevNMiUwPNPl)UP|Nj{n7(x$St^-n>1s;*b3=G`DAk4@xYmNj10~_;1uNg8a ziAjmcNl7{iMg~TP`UWQYh9KyqzM-C> zzLG*kE=X-bMt(_taYp{+dyL{7aL#wew8=5dij(V@q$kTTt4-d`WK<8-P+;X;l$uzQ z>H@^JN+37t8XD;un1mP_Ss9sHnVM@G7+V<_fXpti^36}lOshmwY8ql>WMyJxWnhV- zG_@o#C9xzCpW-O6!70gBY57IDi6yp5nYoGSsrm(Z=}HPPcLUv*pOaq%v>D_)WN}Yt z=YXR8w9Fi!L~)S2lY*zKvzei#nVGJUp5f#-Oa?0EX~xNk#%3wHCP_)jx+dnSrn;7v z#)i5EMyY0o7HNh?W@!eK9hgPx6I1e&Qms<*lQUD`p;usKV3w97&N}VRvwwfCHX~_Kz>n5npJRWA(WMqsQ`{+ ztHk7z%=|o{V-w3#QX;5n zBBz*?^`V9(XC&sOr>58{>4V*+k8p@SiW?`_F+0?U@0SE7QYKYT7srr@!*6HY&SO^O zak2dW|8lLzjvGIYO$(VCwaDZ4-4e;1^9IYd?l-geYkOzz{c8Dh!nc+)?s<1%@n)O! zp52@WqEgupyw+!#RL0BXCwXS-rEf3aJ08$-Nnmf7x~H4PA@rv8*?gY3OP$%-f2LP4 ze$4oMdzy%hQoV%fmt9NzYQpkL7*Yiv9x_l02s3>5(dp8Lt_OS!vW&Of|Kvt`IHO3vMF~sH>q4vjQK>3(oRWF3K2&U&mAB@e+ZDEzoL}a) zx=k=&-YuZUd&84~uW#B7Yo_z+$3Aag&TuAp;hT)(Ryl_af=d~edUZZ`FXc>k)$DL- zcj8=ktdIHn42f+Eg3ay)Ev#D_FfYQp@$v3yH?7U|roHS{KAO&WBKWI)-NPSD(zopr0J7xh0{{R3 From 51aa169c3b8424eb65dca6684fe20fdbaec92da4 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 22 Dec 2021 15:05:14 +0400 Subject: [PATCH 08/14] [FL-2149] SubGhz: Additional frequencies for testing (#920) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add new frequency for testing * [FL-2149] SubGhz: power reduction for Australia Co-authored-by: あく --- applications/subghz/helpers/subghz_testing.c | 34 ++++++++++ applications/subghz/helpers/subghz_testing.h | 6 ++ .../subghz/views/subghz_test_carrier.c | 9 +-- .../subghz/views/subghz_test_packet.c | 11 ++-- .../subghz/views/subghz_test_static.c | 14 ++-- .../targets/f6/furi-hal/furi-hal-subghz.c | 64 ++++++++++++++----- .../targets/f7/furi-hal/furi-hal-subghz.c | 64 ++++++++++++++----- .../furi-hal-include/furi-hal-subghz.h | 1 + 8 files changed, 156 insertions(+), 47 deletions(-) create mode 100644 applications/subghz/helpers/subghz_testing.c create mode 100644 applications/subghz/helpers/subghz_testing.h diff --git a/applications/subghz/helpers/subghz_testing.c b/applications/subghz/helpers/subghz_testing.c new file mode 100644 index 00000000..b3dc610f --- /dev/null +++ b/applications/subghz/helpers/subghz_testing.c @@ -0,0 +1,34 @@ +#include "subghz_testing.h" + +const uint32_t subghz_frequencies_testing[] = { + /* 300 - 348 */ + 300000000, + 304500000, + 313250000, + 315000000, + 321950000, + 348000000, + /* 387 - 464 */ + 387000000, + 433075000, /* LPD433 first */ + 433825000, + 433920000, /* LPD433 mid */ + 434420000, + 434775000, /* LPD433 last channels */ + 438900000, + 464000000, + /* 779 - 928 */ + 779000000, + 868150000, + 868350000, + 868550000, + 915000000, + 925000000, + 926500000, + 927950000, + 928000000, +}; + +const uint32_t subghz_frequencies_count_testing = + sizeof(subghz_frequencies_testing) / sizeof(uint32_t); +const uint32_t subghz_frequencies_433_92_testing = 9; \ No newline at end of file diff --git a/applications/subghz/helpers/subghz_testing.h b/applications/subghz/helpers/subghz_testing.h new file mode 100644 index 00000000..3a154966 --- /dev/null +++ b/applications/subghz/helpers/subghz_testing.h @@ -0,0 +1,6 @@ +#pragma once +#include "../subghz_i.h" + +extern const uint32_t subghz_frequencies_testing[]; +extern const uint32_t subghz_frequencies_count_testing; +extern const uint32_t subghz_frequencies_433_92_testing; \ No newline at end of file diff --git a/applications/subghz/views/subghz_test_carrier.c b/applications/subghz/views/subghz_test_carrier.c index a569db1f..97bfe42b 100644 --- a/applications/subghz/views/subghz_test_carrier.c +++ b/applications/subghz/views/subghz_test_carrier.c @@ -1,5 +1,6 @@ #include "subghz_test_carrier.h" #include "../subghz_i.h" +#include "../helpers/subghz_testing.h" #include #include @@ -94,7 +95,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { if(event->key == InputKeyLeft) { if(model->frequency > 0) model->frequency--; } else if(event->key == InputKeyRight) { - if(model->frequency < subghz_frequencies_count - 1) model->frequency++; + if(model->frequency < subghz_frequencies_count_testing - 1) model->frequency++; } else if(event->key == InputKeyDown) { if(model->path > 0) model->path--; } else if(event->key == InputKeyUp) { @@ -108,7 +109,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { } model->real_frequency = - furi_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); + furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); furi_hal_subghz_set_path(model->path); if(model->status == SubghzTestCarrierModelStatusRx) { @@ -141,9 +142,9 @@ void subghz_test_carrier_enter(void* context) { with_view_model( subghz_test_carrier->view, (SubghzTestCarrierModel * model) { - model->frequency = subghz_frequencies_433_92; // 433 + model->frequency = subghz_frequencies_433_92_testing; // 433 model->real_frequency = - furi_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); + furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); model->path = FuriHalSubGhzPathIsolate; // isolate model->rssi = 0.0f; model->status = SubghzTestCarrierModelStatusRx; diff --git a/applications/subghz/views/subghz_test_packet.c b/applications/subghz/views/subghz_test_packet.c index 155d4f07..272c050e 100644 --- a/applications/subghz/views/subghz_test_packet.c +++ b/applications/subghz/views/subghz_test_packet.c @@ -1,5 +1,6 @@ #include "subghz_test_packet.h" #include "../subghz_i.h" +#include "../helpers/subghz_testing.h" #include #include @@ -144,7 +145,7 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { if(event->key == InputKeyLeft) { if(model->frequency > 0) model->frequency--; } else if(event->key == InputKeyRight) { - if(model->frequency < subghz_frequencies_count - 1) model->frequency++; + if(model->frequency < subghz_frequencies_count_testing - 1) model->frequency++; } else if(event->key == InputKeyDown) { if(model->path > 0) model->path--; } else if(event->key == InputKeyUp) { @@ -158,7 +159,7 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { } model->real_frequency = - furi_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); + furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); furi_hal_subghz_set_path(model->path); if(model->status == SubghzTestPacketModelStatusRx) { @@ -168,7 +169,7 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { instance->encoder, 0x00AABBCC, SUBGHZ_TEST_PACKET_COUNT, - subghz_frequencies[model->frequency]); + subghz_frequencies_testing[model->frequency]); if(!furi_hal_subghz_start_async_tx( subghz_encoder_princeton_yield, instance->encoder)) { model->status = SubghzTestPacketModelStatusOnlyRx; @@ -191,9 +192,9 @@ void subghz_test_packet_enter(void* context) { with_view_model( instance->view, (SubghzTestPacketModel * model) { - model->frequency = subghz_frequencies_433_92; + model->frequency = subghz_frequencies_433_92_testing; model->real_frequency = - furi_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); + furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); model->path = FuriHalSubGhzPathIsolate; // isolate model->rssi = 0.0f; model->status = SubghzTestPacketModelStatusRx; diff --git a/applications/subghz/views/subghz_test_static.c b/applications/subghz/views/subghz_test_static.c index 9e924a3f..518ccb36 100644 --- a/applications/subghz/views/subghz_test_static.c +++ b/applications/subghz/views/subghz_test_static.c @@ -1,5 +1,6 @@ #include "subghz_test_static.h" #include "../subghz_i.h" +#include "../helpers/subghz_testing.h" #include #include @@ -81,7 +82,7 @@ bool subghz_test_static_input(InputEvent* event, void* context) { if(event->key == InputKeyLeft) { if(model->frequency > 0) model->frequency--; } else if(event->key == InputKeyRight) { - if(model->frequency < subghz_frequencies_count - 1) model->frequency++; + if(model->frequency < subghz_frequencies_count_testing - 1) model->frequency++; } else if(event->key == InputKeyDown) { if(model->button > 0) model->button--; } else if(event->key == InputKeyUp) { @@ -89,13 +90,14 @@ bool subghz_test_static_input(InputEvent* event, void* context) { } } - model->real_frequency = subghz_frequencies[model->frequency]; + model->real_frequency = subghz_frequencies_testing[model->frequency]; if(event->key == InputKeyOk) { NotificationApp* notification = furi_record_open("notification"); if(event->type == InputTypePress) { furi_hal_subghz_idle(); - furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); + furi_hal_subghz_set_frequency_and_path( + subghz_frequencies_testing[model->frequency]); if(!furi_hal_subghz_tx()) { instance->callback(SubghzTestStaticEventOnlyRx, instance->context); } else { @@ -107,7 +109,7 @@ bool subghz_test_static_input(InputEvent* event, void* context) { instance->encoder, subghz_test_static_keys[model->button], 10000, - subghz_frequencies[model->frequency]); + subghz_frequencies_testing[model->frequency]); furi_hal_subghz_start_async_tx( subghz_encoder_princeton_yield, instance->encoder); @@ -145,8 +147,8 @@ void subghz_test_static_enter(void* context) { with_view_model( instance->view, (SubghzTestStaticModel * model) { - model->frequency = subghz_frequencies_433_92; - model->real_frequency = subghz_frequencies[model->frequency]; + model->frequency = subghz_frequencies_433_92_testing; + model->real_frequency = subghz_frequencies_testing[model->frequency]; model->button = 0; return true; diff --git a/firmware/targets/f6/furi-hal/furi-hal-subghz.c b/firmware/targets/f6/furi-hal/furi-hal-subghz.c index bb762d2f..a493eb49 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f6/furi-hal/furi-hal-subghz.c @@ -1,5 +1,6 @@ #include "furi-hal-subghz.h" #include "furi-hal-version.h" +#include "furi-hal-rtc.h" #include #include @@ -14,6 +15,7 @@ static volatile SubGhzState furi_hal_subghz_state = SubGhzStateInit; static volatile SubGhzRegulation furi_hal_subghz_regulation = SubGhzRegulationTxRx; +static volatile FuriHalSubGhzPreset furi_hal_subghz_preset = FuriHalSubGhzPresetIDLE; static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = { // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration @@ -296,9 +298,9 @@ static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { {CC1101_IOCFG0, 0x06}, //GDO0 Output Pin Configuration {CC1101_FIFOTHR, 0x47}, //RX FIFO and TX FIFO Thresholds - //1 : CRC calculation in TX and CRC check in RX enabled, + //1 : CRC calculation in TX and CRC check in RX enabled, //1 : Variable packet length mode. Packet length configured by the first byte after sync word - {CC1101_PKTCTRL0,0x05}, + {CC1101_PKTCTRL0, 0x05}, {CC1101_FSCTRL1, 0x06}, //Frequency Synthesizer Control @@ -314,8 +316,8 @@ static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { {CC1101_DEVIATN, 0x34}, //Deviation = 19.042969 {CC1101_MCSM0, 0x18}, //Main Radio Control State Machine Configuration {CC1101_FOCCFG, 0x16}, //Frequency Offset Compensation Configuration - - {CC1101_AGCCTRL2, 0x43 }, //AGC Control + + {CC1101_AGCCTRL2, 0x43}, //AGC Control {CC1101_AGCCTRL1, 0x40}, {CC1101_AGCCTRL0, 0x91}, @@ -333,7 +335,16 @@ static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = { 0x00, - 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; +static const uint8_t furi_hal_subghz_preset_ook_async_patable_au[8] = { + 0x00, + 0x86, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 0x00, 0x00, 0x00, @@ -371,6 +382,7 @@ static const uint8_t furi_hal_subghz_preset_gfsk_async_patable[8] = { void furi_hal_subghz_init() { furi_assert(furi_hal_subghz_state == SubGhzStateInit); furi_hal_subghz_state = SubGhzStateIdle; + furi_hal_subghz_preset = FuriHalSubGhzPresetIDLE; furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); @@ -392,7 +404,8 @@ void furi_hal_subghz_init() { ; // GD0 high - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); + cc1101_write_reg( + &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); while(hal_gpio_read(&gpio_cc1101_g0) != true) ; @@ -423,6 +436,8 @@ void furi_hal_subghz_sleep() { cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + + furi_hal_subghz_preset = FuriHalSubGhzPresetIDLE; } void furi_hal_subghz_dump_state() { @@ -453,9 +468,10 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) { } else if(preset == FuriHalSubGhzPresetGFSK9_99KbAsync) { furi_hal_subghz_load_registers(furi_hal_subghz_preset_gfsk_9_99kb_async_regs); furi_hal_subghz_load_patable(furi_hal_subghz_preset_gfsk_async_patable); - } else{ + } else { furi_crash(NULL); } + furi_hal_subghz_preset = preset; } void furi_hal_subghz_load_registers(const uint8_t data[][2]) { @@ -498,7 +514,8 @@ void furi_hal_subghz_flush_tx() { bool furi_hal_subghz_rx_pipe_not_empty() { CC1101RxBytes status[1]; furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_read_reg(&furi_hal_spi_bus_handle_subghz, (CC1101_STATUS_RXBYTES) | CC1101_BURST, (uint8_t*)status); + cc1101_read_reg( + &furi_hal_spi_bus_handle_subghz, (CC1101_STATUS_RXBYTES) | CC1101_BURST, (uint8_t*)status); furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); // TODO: you can add a buffer overflow flag if needed if(status->NUM_RXBYTES > 0) { @@ -627,6 +644,13 @@ bool furi_hal_subghz_is_tx_allowed(uint32_t value) { !(value >= 433050000 && value <= 434790000) && !(value >= 915000000 && value <= 928000000)) { } else { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + if((value >= 304100000 && value <= 315250000) && + ((furi_hal_subghz_preset == FuriHalSubGhzPresetOok270Async) || + (furi_hal_subghz_preset == FuriHalSubGhzPresetOok650Async))) { + furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable_au); + } + } is_allowed = true; } break; @@ -647,14 +671,13 @@ bool furi_hal_subghz_is_tx_allowed(uint32_t value) { } uint32_t furi_hal_subghz_set_frequency(uint32_t value) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - if(furi_hal_subghz_is_tx_allowed(value)) { furi_hal_subghz_regulation = SubGhzRegulationTxRx; } else { furi_hal_subghz_regulation = SubGhzRegulationOnlyRx; } + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); uint32_t real_frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, value); cc1101_calibrate(&furi_hal_spi_bus_handle_subghz); @@ -672,13 +695,15 @@ void furi_hal_subghz_set_path(FuriHalSubGhzPath path) { furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); if(path == FuriHalSubGhzPath433) { hal_gpio_write(&gpio_rf_sw_0, 0); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); + cc1101_write_reg( + &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); } else if(path == FuriHalSubGhzPath315) { hal_gpio_write(&gpio_rf_sw_0, 1); cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); } else if(path == FuriHalSubGhzPath868) { hal_gpio_write(&gpio_rf_sw_0, 1); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); + cc1101_write_reg( + &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); } else if(path == FuriHalSubGhzPathIsolate) { hal_gpio_write(&gpio_rf_sw_0, 0); cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); @@ -838,7 +863,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; buffer++; samples--; - if (!level) { + if(!level) { furi_hal_subghz_async_tx.duty_high += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; } else { furi_hal_subghz_async_tx.duty_low += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; @@ -851,7 +876,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { buffer++; samples--; - if (level) { + if(level) { furi_hal_subghz_async_tx.duty_high += duration; } else { furi_hal_subghz_async_tx.duty_low += duration; @@ -1014,8 +1039,15 @@ void furi_hal_subghz_stop_async_tx() { free(furi_hal_subghz_async_tx.buffer); - float duty_cycle = 100.0f * (float)furi_hal_subghz_async_tx.duty_high / ((float)furi_hal_subghz_async_tx.duty_low + (float)furi_hal_subghz_async_tx.duty_high); - FURI_LOG_D(TAG, "Async TX Radio stats: on %0.0fus, off %0.0fus, DutyCycle: %0.0f%%", (float)furi_hal_subghz_async_tx.duty_high, (float)furi_hal_subghz_async_tx.duty_low, duty_cycle); + float duty_cycle = + 100.0f * (float)furi_hal_subghz_async_tx.duty_high / + ((float)furi_hal_subghz_async_tx.duty_low + (float)furi_hal_subghz_async_tx.duty_high); + FURI_LOG_D( + TAG, + "Async TX Radio stats: on %0.0fus, off %0.0fus, DutyCycle: %0.0f%%", + (float)furi_hal_subghz_async_tx.duty_high, + (float)furi_hal_subghz_async_tx.duty_low, + duty_cycle); furi_hal_subghz_state = SubGhzStateIdle; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-subghz.c b/firmware/targets/f7/furi-hal/furi-hal-subghz.c index bb762d2f..a493eb49 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f7/furi-hal/furi-hal-subghz.c @@ -1,5 +1,6 @@ #include "furi-hal-subghz.h" #include "furi-hal-version.h" +#include "furi-hal-rtc.h" #include #include @@ -14,6 +15,7 @@ static volatile SubGhzState furi_hal_subghz_state = SubGhzStateInit; static volatile SubGhzRegulation furi_hal_subghz_regulation = SubGhzRegulationTxRx; +static volatile FuriHalSubGhzPreset furi_hal_subghz_preset = FuriHalSubGhzPresetIDLE; static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = { // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration @@ -296,9 +298,9 @@ static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { {CC1101_IOCFG0, 0x06}, //GDO0 Output Pin Configuration {CC1101_FIFOTHR, 0x47}, //RX FIFO and TX FIFO Thresholds - //1 : CRC calculation in TX and CRC check in RX enabled, + //1 : CRC calculation in TX and CRC check in RX enabled, //1 : Variable packet length mode. Packet length configured by the first byte after sync word - {CC1101_PKTCTRL0,0x05}, + {CC1101_PKTCTRL0, 0x05}, {CC1101_FSCTRL1, 0x06}, //Frequency Synthesizer Control @@ -314,8 +316,8 @@ static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { {CC1101_DEVIATN, 0x34}, //Deviation = 19.042969 {CC1101_MCSM0, 0x18}, //Main Radio Control State Machine Configuration {CC1101_FOCCFG, 0x16}, //Frequency Offset Compensation Configuration - - {CC1101_AGCCTRL2, 0x43 }, //AGC Control + + {CC1101_AGCCTRL2, 0x43}, //AGC Control {CC1101_AGCCTRL1, 0x40}, {CC1101_AGCCTRL0, 0x91}, @@ -333,7 +335,16 @@ static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = { 0x00, - 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; +static const uint8_t furi_hal_subghz_preset_ook_async_patable_au[8] = { + 0x00, + 0x86, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 0x00, 0x00, 0x00, @@ -371,6 +382,7 @@ static const uint8_t furi_hal_subghz_preset_gfsk_async_patable[8] = { void furi_hal_subghz_init() { furi_assert(furi_hal_subghz_state == SubGhzStateInit); furi_hal_subghz_state = SubGhzStateIdle; + furi_hal_subghz_preset = FuriHalSubGhzPresetIDLE; furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); @@ -392,7 +404,8 @@ void furi_hal_subghz_init() { ; // GD0 high - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); + cc1101_write_reg( + &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); while(hal_gpio_read(&gpio_cc1101_g0) != true) ; @@ -423,6 +436,8 @@ void furi_hal_subghz_sleep() { cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + + furi_hal_subghz_preset = FuriHalSubGhzPresetIDLE; } void furi_hal_subghz_dump_state() { @@ -453,9 +468,10 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) { } else if(preset == FuriHalSubGhzPresetGFSK9_99KbAsync) { furi_hal_subghz_load_registers(furi_hal_subghz_preset_gfsk_9_99kb_async_regs); furi_hal_subghz_load_patable(furi_hal_subghz_preset_gfsk_async_patable); - } else{ + } else { furi_crash(NULL); } + furi_hal_subghz_preset = preset; } void furi_hal_subghz_load_registers(const uint8_t data[][2]) { @@ -498,7 +514,8 @@ void furi_hal_subghz_flush_tx() { bool furi_hal_subghz_rx_pipe_not_empty() { CC1101RxBytes status[1]; furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_read_reg(&furi_hal_spi_bus_handle_subghz, (CC1101_STATUS_RXBYTES) | CC1101_BURST, (uint8_t*)status); + cc1101_read_reg( + &furi_hal_spi_bus_handle_subghz, (CC1101_STATUS_RXBYTES) | CC1101_BURST, (uint8_t*)status); furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); // TODO: you can add a buffer overflow flag if needed if(status->NUM_RXBYTES > 0) { @@ -627,6 +644,13 @@ bool furi_hal_subghz_is_tx_allowed(uint32_t value) { !(value >= 433050000 && value <= 434790000) && !(value >= 915000000 && value <= 928000000)) { } else { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + if((value >= 304100000 && value <= 315250000) && + ((furi_hal_subghz_preset == FuriHalSubGhzPresetOok270Async) || + (furi_hal_subghz_preset == FuriHalSubGhzPresetOok650Async))) { + furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable_au); + } + } is_allowed = true; } break; @@ -647,14 +671,13 @@ bool furi_hal_subghz_is_tx_allowed(uint32_t value) { } uint32_t furi_hal_subghz_set_frequency(uint32_t value) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - if(furi_hal_subghz_is_tx_allowed(value)) { furi_hal_subghz_regulation = SubGhzRegulationTxRx; } else { furi_hal_subghz_regulation = SubGhzRegulationOnlyRx; } + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); uint32_t real_frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, value); cc1101_calibrate(&furi_hal_spi_bus_handle_subghz); @@ -672,13 +695,15 @@ void furi_hal_subghz_set_path(FuriHalSubGhzPath path) { furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); if(path == FuriHalSubGhzPath433) { hal_gpio_write(&gpio_rf_sw_0, 0); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); + cc1101_write_reg( + &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); } else if(path == FuriHalSubGhzPath315) { hal_gpio_write(&gpio_rf_sw_0, 1); cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); } else if(path == FuriHalSubGhzPath868) { hal_gpio_write(&gpio_rf_sw_0, 1); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); + cc1101_write_reg( + &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); } else if(path == FuriHalSubGhzPathIsolate) { hal_gpio_write(&gpio_rf_sw_0, 0); cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); @@ -838,7 +863,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; buffer++; samples--; - if (!level) { + if(!level) { furi_hal_subghz_async_tx.duty_high += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; } else { furi_hal_subghz_async_tx.duty_low += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; @@ -851,7 +876,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { buffer++; samples--; - if (level) { + if(level) { furi_hal_subghz_async_tx.duty_high += duration; } else { furi_hal_subghz_async_tx.duty_low += duration; @@ -1014,8 +1039,15 @@ void furi_hal_subghz_stop_async_tx() { free(furi_hal_subghz_async_tx.buffer); - float duty_cycle = 100.0f * (float)furi_hal_subghz_async_tx.duty_high / ((float)furi_hal_subghz_async_tx.duty_low + (float)furi_hal_subghz_async_tx.duty_high); - FURI_LOG_D(TAG, "Async TX Radio stats: on %0.0fus, off %0.0fus, DutyCycle: %0.0f%%", (float)furi_hal_subghz_async_tx.duty_high, (float)furi_hal_subghz_async_tx.duty_low, duty_cycle); + float duty_cycle = + 100.0f * (float)furi_hal_subghz_async_tx.duty_high / + ((float)furi_hal_subghz_async_tx.duty_low + (float)furi_hal_subghz_async_tx.duty_high); + FURI_LOG_D( + TAG, + "Async TX Radio stats: on %0.0fus, off %0.0fus, DutyCycle: %0.0f%%", + (float)furi_hal_subghz_async_tx.duty_high, + (float)furi_hal_subghz_async_tx.duty_low, + duty_cycle); furi_hal_subghz_state = SubGhzStateIdle; } diff --git a/firmware/targets/furi-hal-include/furi-hal-subghz.h b/firmware/targets/furi-hal-include/furi-hal-subghz.h index bc69e68c..f39b98b1 100644 --- a/firmware/targets/furi-hal-include/furi-hal-subghz.h +++ b/firmware/targets/furi-hal-include/furi-hal-subghz.h @@ -16,6 +16,7 @@ extern "C" { /** Radio Presets */ typedef enum { + FuriHalSubGhzPresetIDLE, /**< default configuration */ FuriHalSubGhzPresetOok270Async, /**< OOK, bandwidth 270kHz, asynchronous */ FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */ FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */ From 3a86da5526282ff4eece5d397803c50d7b9293ec Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 22 Dec 2021 17:01:20 +0400 Subject: [PATCH 09/14] [FL-2139] SubGhz: refactoring GUI SubGhz (#910) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: refactoring GUI ReadRAW * SubGhz: replacing memcpy with strcpy * SubGhz: fix button name "Mode", fix delete scene, fix show name when loading a key * SubGhz: refactoring GUI SubGhz * scene_manager: add exit from last scene API * subghz: stop scene manager before stopping view dispatcher Co-authored-by: gornekich Co-authored-by: あく --- applications/gui/scene_manager.c | 9 + applications/gui/scene_manager.h | 6 + .../subghz/helpers/subghz_custom_event.h | 9 +- .../subghz/scenes/subghz_scene_config.h | 3 + .../subghz/scenes/subghz_scene_delete.c | 2 +- .../subghz/scenes/subghz_scene_delete_raw.c | 79 ++++++++ .../scenes/subghz_scene_delete_success.c | 7 +- .../subghz/scenes/subghz_scene_more_raw.c | 60 +++++++ .../subghz/scenes/subghz_scene_read_raw.c | 152 +++++++++------- .../subghz/scenes/subghz_scene_receiver.c | 18 +- .../subghz/scenes/subghz_scene_save_name.c | 15 +- .../subghz/scenes/subghz_scene_save_success.c | 7 +- .../subghz/scenes/subghz_scene_set_type.c | 5 +- .../subghz/scenes/subghz_scene_show_error.c | 82 ++++++--- .../scenes/subghz_scene_show_error_sub.c | 48 +++++ .../subghz/scenes/subghz_scene_start.c | 8 +- .../subghz/scenes/subghz_scene_transmitter.c | 2 +- applications/subghz/subghz.c | 42 +++-- applications/subghz/subghz_i.c | 2 +- applications/subghz/subghz_i.h | 1 + applications/subghz/views/subghz_read_raw.c | 169 ++++++++++++++---- applications/subghz/views/subghz_read_raw.h | 5 + lib/subghz/subghz_parser.c | 5 +- lib/subghz/subghz_parser.h | 3 +- 24 files changed, 580 insertions(+), 159 deletions(-) create mode 100644 applications/subghz/scenes/subghz_scene_delete_raw.c create mode 100644 applications/subghz/scenes/subghz_scene_more_raw.c create mode 100644 applications/subghz/scenes/subghz_scene_show_error_sub.c diff --git a/applications/gui/scene_manager.c b/applications/gui/scene_manager.c index f4492a58..a3aadb74 100755 --- a/applications/gui/scene_manager.c +++ b/applications/gui/scene_manager.c @@ -181,3 +181,12 @@ bool scene_manager_search_and_switch_to_another_scene( return true; } + +void scene_manager_stop(SceneManager* scene_manager) { + furi_assert(scene_manager); + + if(SceneManagerIdStack_size(scene_manager->scene_id_stack)) { + uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack); + scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context); + } +} diff --git a/applications/gui/scene_manager.h b/applications/gui/scene_manager.h index 53f8d775..69162853 100755 --- a/applications/gui/scene_manager.h +++ b/applications/gui/scene_manager.h @@ -157,6 +157,12 @@ bool scene_manager_search_and_switch_to_another_scene( SceneManager* scene_manager, uint32_t scene_id); +/** Exit from current scene + * + * @param scene_manager SceneManager instance + */ +void scene_manager_stop(SceneManager* scene_manager); + #ifdef __cplusplus } #endif diff --git a/applications/subghz/helpers/subghz_custom_event.h b/applications/subghz/helpers/subghz_custom_event.h index 65b412f8..55363c41 100644 --- a/applications/subghz/helpers/subghz_custom_event.h +++ b/applications/subghz/helpers/subghz_custom_event.h @@ -6,12 +6,17 @@ typedef enum { SubghzCustomEventSceneDeleteSuccess = 100, SubghzCustomEventSceneDelete, + SubghzCustomEventSceneDeleteRAW, + SubghzCustomEventSceneDeleteRAWBack, + SubghzCustomEventSceneReceiverInfoTxStart, SubghzCustomEventSceneReceiverInfoTxStop, SubghzCustomEventSceneReceiverInfoSave, SubghzCustomEventSceneSaveName, SubghzCustomEventSceneSaveSuccess, - SubghzCustomEventSceneShowError, + SubghzCustomEventSceneShowErrorBack, + SubghzCustomEventSceneShowErrorOk, + SubghzCustomEventSceneShowErrorSub, SubghzCustomEventSceneShowOnlyRX, SubghzCustomEventSceneExit, @@ -30,6 +35,8 @@ typedef enum { SubghzCustomEventViewReadRAWSendStop, SubghzCustomEventViewReadRAWSave, SubghzCustomEventViewReadRAWVibro, + SubghzCustomEventViewReadRAWTXRXStop, + SubghzCustomEventViewReadRAWMore, SubghzCustomEventViewTransmitterBack, SubghzCustomEventViewTransmitterSendStart, diff --git a/applications/subghz/scenes/subghz_scene_config.h b/applications/subghz/scenes/subghz_scene_config.h index d0be3c00..71cd2668 100644 --- a/applications/subghz/scenes/subghz_scene_config.h +++ b/applications/subghz/scenes/subghz_scene_config.h @@ -7,6 +7,7 @@ ADD_SCENE(subghz, save_success, SaveSuccess) ADD_SCENE(subghz, saved, Saved) ADD_SCENE(subghz, transmitter, Transmitter) ADD_SCENE(subghz, show_error, ShowError) +ADD_SCENE(subghz, show_error_sub, ShowErrorSub) ADD_SCENE(subghz, show_only_rx, ShowOnlyRx) ADD_SCENE(subghz, saved_menu, SavedMenu) ADD_SCENE(subghz, delete, Delete) @@ -18,4 +19,6 @@ ADD_SCENE(subghz, test_packet, TestPacket) ADD_SCENE(subghz, set_type, SetType) ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) ADD_SCENE(subghz, read_raw, ReadRAW) +ADD_SCENE(subghz, more_raw, MoreRAW) +ADD_SCENE(subghz, delete_raw, DeleteRAW) ADD_SCENE(subghz, need_saving, NeedSaving) \ No newline at end of file diff --git a/applications/subghz/scenes/subghz_scene_delete.c b/applications/subghz/scenes/subghz_scene_delete.c index eb8a2217..9452946e 100644 --- a/applications/subghz/scenes/subghz_scene_delete.c +++ b/applications/subghz/scenes/subghz_scene_delete.c @@ -50,7 +50,7 @@ bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubghzCustomEventSceneDelete) { - memcpy(subghz->file_name_tmp, subghz->file_name, strlen(subghz->file_name) + 1); + strcpy(subghz->file_name_tmp, subghz->file_name); if(subghz_delete_file(subghz)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); } else { diff --git a/applications/subghz/scenes/subghz_scene_delete_raw.c b/applications/subghz/scenes/subghz_scene_delete_raw.c new file mode 100644 index 00000000..5c620989 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_delete_raw.c @@ -0,0 +1,79 @@ +#include "../subghz_i.h" +#include "../helpers/subghz_custom_event.h" + +void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + SubGhz* subghz = context; + if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubghzCustomEventSceneDeleteRAW); + } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubghzCustomEventSceneDeleteRAWBack); + } +} + +void subghz_scene_delete_raw_on_enter(void* context) { + SubGhz* subghz = context; + string_t frequency_str; + string_t modulation_str; + string_t text; + + string_init(frequency_str); + string_init(modulation_str); + string_init(text); + + string_printf(text, "Delete\n%s?", subghz->file_name); + widget_add_string_multiline_element( + subghz->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, string_get_cstr(text)); + + widget_add_string_element( + subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); + subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); + widget_add_string_element( + subghz->widget, 35, 37, AlignLeft, AlignTop, FontSecondary, string_get_cstr(frequency_str)); + + widget_add_string_element( + subghz->widget, + 72, + 37, + AlignLeft, + AlignTop, + FontSecondary, + string_get_cstr(modulation_str)); + + string_clear(frequency_str); + string_clear(modulation_str); + string_clear(text); + + widget_add_button_element( + subghz->widget, GuiButtonTypeRight, "Delete", subghz_scene_delete_raw_callback, subghz); + widget_add_button_element( + subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_delete_raw_callback, subghz); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); +} + +bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubghzCustomEventSceneDeleteRAW) { + strcpy(subghz->file_name_tmp, subghz->file_name); + if(subghz_delete_file(subghz)) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); + } else { + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); + } + return true; + } else if(event.event == SubghzCustomEventSceneDeleteRAWBack) { + return scene_manager_previous_scene(subghz->scene_manager); + } + } + return false; +} + +void subghz_scene_delete_raw_on_exit(void* context) { + SubGhz* subghz = context; + widget_clear(subghz->widget); +} diff --git a/applications/subghz/scenes/subghz_scene_delete_success.c b/applications/subghz/scenes/subghz_scene_delete_success.c index 04b48531..8c67e3c5 100644 --- a/applications/subghz/scenes/subghz_scene_delete_success.c +++ b/applications/subghz/scenes/subghz_scene_delete_success.c @@ -26,8 +26,11 @@ bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubghzCustomEventSceneDeleteSuccess) { - return scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneStart); + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneSaved)) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); + } + return true; } } return false; diff --git a/applications/subghz/scenes/subghz_scene_more_raw.c b/applications/subghz/scenes/subghz_scene_more_raw.c new file mode 100644 index 00000000..c8fde230 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_more_raw.c @@ -0,0 +1,60 @@ +#include "../subghz_i.h" + +enum SubmenuIndex { + SubmenuIndexEdit, + SubmenuIndexDelete, +}; + +void subghz_scene_more_raw_submenu_callback(void* context, uint32_t index) { + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, index); +} + +void subghz_scene_more_raw_on_enter(void* context) { + SubGhz* subghz = context; + + submenu_add_item( + subghz->submenu, + "Edit name", + SubmenuIndexEdit, + subghz_scene_more_raw_submenu_callback, + subghz); + + submenu_add_item( + subghz->submenu, + "Delete", + SubmenuIndexDelete, + subghz_scene_more_raw_submenu_callback, + subghz); + + submenu_set_selected_item( + subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneMoreRAW)); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); +} + +bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexDelete) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); + return true; + } else if(event.event == SubmenuIndexEdit) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + return true; + } + } + return false; +} + +void subghz_scene_more_raw_on_exit(void* context) { + SubGhz* subghz = context; + submenu_clean(subghz->submenu); +} diff --git a/applications/subghz/scenes/subghz_scene_read_raw.c b/applications/subghz/scenes/subghz_scene_read_raw.c index 615df4cb..aaa51c76 100644 --- a/applications/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/subghz/scenes/subghz_scene_read_raw.c @@ -6,6 +6,32 @@ #define RAW_FILE_NAME "Raw_temp" +bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { + bool ret = false; + //set the path to read the file + if(strcmp( + subghz_protocol_raw_get_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result), + "")) { + string_t temp_str; + string_init_printf( + temp_str, + "%s", + subghz_protocol_raw_get_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); + path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); + strcpy(subghz->file_name, string_get_cstr(temp_str)); + string_printf( + temp_str, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); + + subghz_protocol_raw_set_last_file_name( + (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); + string_clear(temp_str); + ret = true; + } + return ret; +} + static void subghz_scene_read_raw_update_statusbar(void* context) { furi_assert(context); SubGhz* subghz = context; @@ -40,15 +66,24 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; - if(subghz->txrx->rx_key_state == SubGhzRxKeyStateBack) { + switch(subghz->txrx->rx_key_state) { + case SubGhzRxKeyStateBack: subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusIDLE, ""); - } else if(subghz->txrx->rx_key_state == SubGhzRxKeyStateRAWLoad) { + break; + case SubGhzRxKeyStateRAWLoad: subghz_read_raw_set_status( - subghz->subghz_read_raw, SubghzReadRAWStatusTX, subghz->file_name); - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; - } else { + subghz->subghz_read_raw, SubghzReadRAWStatusLoadKeyTX, subghz->file_name); + subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + break; + case SubGhzRxKeyStateRAWSave: + subghz_read_raw_set_status( + subghz->subghz_read_raw, SubghzReadRAWStatusSaveKey, subghz->file_name); + subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + break; + default: subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusStart, ""); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + break; } subghz_scene_read_raw_update_statusbar(subghz); @@ -96,53 +131,64 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { //Restore default setting subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; - scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneStart); + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneSaved)) { + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart)) { + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); + } + } } - return true; break; + + case SubghzCustomEventViewReadRAWTXRXStop: + //Stop TX + if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + subghz_tx_stop(subghz); + subghz_sleep(subghz); + } + //Stop RX + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz); + subghz_sleep(subghz); + }; + subghz->state_notifications = SubGhzNotificationStateIDLE; + return true; + break; + case SubghzCustomEventViewReadRAWConfig: scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); return true; break; + case SubghzCustomEventViewReadRAWErase: subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; return true; break; + case SubghzCustomEventViewReadRAWVibro: notification_message(subghz->notifications, &sequence_single_vibro); return true; break; - case SubghzCustomEventViewReadRAWSendStart: - //set the path to read the file - if(strcmp( - subghz_protocol_raw_get_last_file_name( - (SubGhzProtocolRAW*)subghz->txrx->protocol_result), - "")) { - string_t temp_str; - string_init_printf( - temp_str, - "%s", - subghz_protocol_raw_get_last_file_name( - (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); - path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); - strlcpy( - subghz->file_name, - string_get_cstr(temp_str), - strlen(string_get_cstr(temp_str)) + 1); - string_printf( - temp_str, - "%s/%s%s", - SUBGHZ_APP_PATH_FOLDER, - subghz->file_name, - SUBGHZ_APP_EXTENSION); - subghz_protocol_raw_set_last_file_name( - (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); - string_clear(temp_str); + case SubghzCustomEventViewReadRAWMore: + if(subghz_scene_read_raw_update_filename(subghz)) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet); + subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); + return true; + } else { + furi_crash(NULL); + } + break; + + case SubghzCustomEventViewReadRAWSendStart: + if(subghz_scene_read_raw_update_filename(subghz)) { //start send subghz->state_notifications = SubGhzNotificationStateIDLE; if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { @@ -154,12 +200,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); } else { subghz->state_notifications = SubGhzNotificationStateTX; - subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; } } } return true; break; + case SubghzCustomEventViewReadRAWSendStop: subghz->state_notifications = SubGhzNotificationStateIDLE; if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { @@ -169,6 +215,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_read_raw_stop_send(subghz->subghz_read_raw); return true; break; + case SubghzCustomEventViewReadRAWIDLE: if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); @@ -182,8 +229,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { return true; break; - case SubghzCustomEventViewReadRAWREC: + case SubghzCustomEventViewReadRAWREC: if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { @@ -199,42 +246,17 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_rx(subghz, subghz->txrx->frequency); } subghz->state_notifications = SubGhzNotificationStateRX; + subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; } else { - string_set(subghz->error_str, "No SD card"); + string_set(subghz->error_str, "Function requires\nan SD card."); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } } - return true; break; + case SubghzCustomEventViewReadRAWSave: - if(strcmp( - subghz_protocol_raw_get_last_file_name( - (SubGhzProtocolRAW*)subghz->txrx->protocol_result), - "")) { - string_t temp_str; - string_init_printf( - temp_str, - "%s", - subghz_protocol_raw_get_last_file_name( - (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); - path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); - strlcpy( - subghz->file_name, - string_get_cstr(temp_str), - strlen(string_get_cstr(temp_str)) + 1); - - //set the path to read the file - string_printf( - temp_str, - "%s/%s%s", - SUBGHZ_APP_PATH_FOLDER, - subghz->file_name, - SUBGHZ_APP_EXTENSION); - subghz_protocol_raw_set_last_file_name( - (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); - string_clear(temp_str); - + if(subghz_scene_read_raw_update_filename(subghz)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet); subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/subghz/scenes/subghz_scene_receiver.c index 53b72c1a..a2eb4af2 100644 --- a/applications/subghz/scenes/subghz_scene_receiver.c +++ b/applications/subghz/scenes/subghz_scene_receiver.c @@ -56,6 +56,7 @@ void subghz_scene_add_to_history_callback(SubGhzProtocolCommon* parser, void* co subghz_scene_receiver_update_statusbar(subghz); } string_clear(str_buff); + subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; } void subghz_scene_receiver_on_enter(void* context) { @@ -64,6 +65,10 @@ void subghz_scene_receiver_on_enter(void* context) { string_t str_buff; string_init(str_buff); + if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { + subghz_history_clean(subghz->txrx->history); + } + //Load history to receiver subghz_receiver_exit(subghz->subghz_receiver); for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { @@ -73,6 +78,7 @@ void subghz_scene_receiver_on_enter(void* context) { subghz->subghz_receiver, string_get_cstr(str_buff), subghz_history_get_type_protocol(subghz->txrx->history, i)); + subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; } string_clear(str_buff); subghz_scene_receiver_update_statusbar(subghz); @@ -99,20 +105,26 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case SubghzCustomEventViewReceverBack: + // Stop CC1101 Rx subghz->state_notifications = SubGhzNotificationStateIDLE; if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { subghz_rx_end(subghz); subghz_sleep(subghz); }; - subghz_history_clean(subghz->txrx->history); subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz->txrx->idx_menu_chosen = 0; subghz_parser_enable_dump(subghz->txrx->parser, NULL, subghz); - scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneStart); + + if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { + subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); + } else { + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); + } return true; break; case SubghzCustomEventViewReceverOK: diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index 4442d39d..40be8fea 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -20,7 +20,7 @@ void subghz_scene_save_name_on_enter(void* context) { set_random_name(subghz->file_name, sizeof(subghz->file_name)); } else { - memcpy(subghz->file_name_tmp, subghz->file_name, strlen(subghz->file_name) + 1); + strcpy(subghz->file_name_tmp, subghz->file_name); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == SubghzCustomEventManagerSet) { subghz_get_next_name_file(subghz); @@ -42,8 +42,11 @@ void subghz_scene_save_name_on_enter(void* context) { bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; - - if(event.type == SceneManagerEventTypeCustom) { + if(event.type == SceneManagerEventTypeBack) { + strcpy(subghz->file_name, subghz->file_name_tmp); + scene_manager_previous_scene(subghz->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubghzCustomEventSceneSaveName) { if(strcmp(subghz->file_name, "")) { if(strcmp(subghz->file_name_tmp, "")) { @@ -56,13 +59,15 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubghzCustomEventManagerSet) { subghz_protocol_raw_set_last_file_name( (SubGhzProtocolRAW*)subghz->txrx->protocol_result, subghz->file_name); + } else { + subghz_file_name_clear(subghz); } - subghz_file_name_clear(subghz); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); return true; } else { string_set(subghz->error_str, "No name file"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); return true; } } diff --git a/applications/subghz/scenes/subghz_scene_save_success.c b/applications/subghz/scenes/subghz_scene_save_success.c index 7509abd8..923a06b6 100644 --- a/applications/subghz/scenes/subghz_scene_save_success.c +++ b/applications/subghz/scenes/subghz_scene_save_success.c @@ -26,10 +26,13 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) if(event.event == SubghzCustomEventSceneSaveSuccess) { if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReceiver)) { + subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave; if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReadRAW)) { - scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneStart); + if(!scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneSaved)) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); + } } } return true; diff --git a/applications/subghz/scenes/subghz_scene_set_type.c b/applications/subghz/scenes/subghz_scene_set_type.c index 331b9dc2..ea88baf8 100644 --- a/applications/subghz/scenes/subghz_scene_set_type.c +++ b/applications/subghz/scenes/subghz_scene_set_type.c @@ -19,7 +19,7 @@ bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* p subghz->txrx->protocol_result = subghz_parser_get_by_name(subghz->txrx->parser, protocol_name); if(subghz->txrx->protocol_result == NULL) { string_set(subghz->error_str, "Protocol not found"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); return false; } return true; @@ -177,7 +177,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { generated_protocol = true; } else { generated_protocol = false; - string_set(subghz->error_str, "No manufactory key"); + string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } } diff --git a/applications/subghz/scenes/subghz_scene_show_error.c b/applications/subghz/scenes/subghz_scene_show_error.c index d8f2e050..1e450f1e 100644 --- a/applications/subghz/scenes/subghz_scene_show_error.c +++ b/applications/subghz/scenes/subghz_scene_show_error.c @@ -1,31 +1,74 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -void subghz_scene_show_error_popup_callback(void* context) { +void subghz_scene_show_error_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneShowError); + + if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubghzCustomEventSceneShowErrorOk); + } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubghzCustomEventSceneShowErrorBack); + } } void subghz_scene_show_error_on_enter(void* context) { SubGhz* subghz = context; - // Setup view - Popup* popup = subghz->popup; - popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51); - popup_set_header(popup, string_get_cstr(subghz->error_str), 64, 8, AlignCenter, AlignBottom); - popup_set_timeout(popup, 1500); - popup_set_context(popup, subghz); - popup_set_callback(popup, subghz_scene_show_error_popup_callback); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); + widget_add_icon_element(subghz->widget, 0, 0, &I_SDQuestion_35x43); + + widget_add_string_multiline_element( + subghz->widget, + 81, + 24, + AlignCenter, + AlignCenter, + FontSecondary, + string_get_cstr(subghz->error_str)); + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == + SubghzCustomEventManagerSet) { + widget_add_button_element( + subghz->widget, GuiButtonTypeRight, "Ok", subghz_scene_show_error_callback, subghz); + } + + widget_add_button_element( + subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_show_error_callback, subghz); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); } bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubghzCustomEventSceneShowError) { + if(event.type == SceneManagerEventTypeBack) { + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == + SubghzCustomEventManagerSet) { + return false; + } else { scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); + } + return true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubghzCustomEventSceneShowErrorOk) { + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == + SubghzCustomEventManagerSet) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); + } + return true; + } else if(event.event == SubghzCustomEventSceneShowErrorBack) { + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == + SubghzCustomEventManagerSet) { + //exit app + if(!scene_manager_previous_scene(subghz->scene_manager)) { + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); + } + } else { + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); + } return true; } } @@ -34,15 +77,8 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { void subghz_scene_show_error_on_exit(void* context) { SubGhz* subghz = context; - - // Clear view - Popup* popup = subghz->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - popup_set_callback(popup, NULL); - popup_set_context(popup, NULL); - popup_set_timeout(popup, 0); - popup_disable_timeout(popup); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneShowError, SubghzCustomEventManagerNoSet); + widget_clear(subghz->widget); string_reset(subghz->error_str); } diff --git a/applications/subghz/scenes/subghz_scene_show_error_sub.c b/applications/subghz/scenes/subghz_scene_show_error_sub.c new file mode 100644 index 00000000..566e6451 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_show_error_sub.c @@ -0,0 +1,48 @@ +#include "../subghz_i.h" +#include "../helpers/subghz_custom_event.h" + +void subghz_scene_show_error_sub_popup_callback(void* context) { + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneShowErrorSub); +} + +void subghz_scene_show_error_sub_on_enter(void* context) { + SubGhz* subghz = context; + + // Setup view + Popup* popup = subghz->popup; + popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51); + popup_set_header(popup, string_get_cstr(subghz->error_str), 64, 8, AlignCenter, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, subghz); + popup_set_callback(popup, subghz_scene_show_error_sub_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); +} + +bool subghz_scene_show_error_sub_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubghzCustomEventSceneShowErrorSub) { + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); + return true; + } + } + return false; +} + +void subghz_scene_show_error_sub_on_exit(void* context) { + SubGhz* subghz = context; + + // Clear view + Popup* popup = subghz->popup; + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + popup_set_callback(popup, NULL); + popup_set_context(popup, NULL); + popup_set_timeout(popup, 0); + popup_disable_timeout(popup); + string_reset(subghz->error_str); +} diff --git a/applications/subghz/scenes/subghz_scene_start.c b/applications/subghz/scenes/subghz_scene_start.c index 640c42ca..454b39f1 100644 --- a/applications/subghz/scenes/subghz_scene_start.c +++ b/applications/subghz/scenes/subghz_scene_start.c @@ -53,8 +53,12 @@ void subghz_scene_start_on_enter(void* context) { bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; - - if(event.type == SceneManagerEventTypeCustom) { + if(event.type == SceneManagerEventTypeBack) { + //exit app + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexReadRAW) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW); diff --git a/applications/subghz/scenes/subghz_scene_transmitter.c b/applications/subghz/scenes/subghz_scene_transmitter.c index 16617589..287e1afd 100644 --- a/applications/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/subghz/scenes/subghz_scene_transmitter.c @@ -94,7 +94,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { return true; } else if(event.event == SubghzCustomEventViewTransmitterError) { string_set(subghz->error_str, "Protocol not found"); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); } } else if(event.type == SceneManagerEventTypeTick) { if(subghz->state_notifications == SubGhzNotificationStateTX) { diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 5ae24b7b..23599739 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -1,3 +1,8 @@ +/* +* Give up hope, everyone who enters here!!! +* Оставь надежду, всяк сюда входящий!!! +*/ + #include "subghz_i.h" #include @@ -191,13 +196,6 @@ SubGhz* subghz_alloc() { //Init Error_str string_init(subghz->error_str); - subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes"); - subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes_user"); - subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/nice_flor_s_rx"); - subghz_parser_load_came_atomo_file(subghz->txrx->parser, "/ext/subghz/came_atomo"); - - //subghz_parser_enable_dump_text(subghz->protocol, subghz_text_callback, subghz); - return subghz; } @@ -285,19 +283,41 @@ void subghz_free(SubGhz* subghz) { int32_t subghz_app(void* p) { SubGhz* subghz = subghz_alloc(); + //Load database + bool load_database = + subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes"); + subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes_user"); + subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/nice_flor_s_rx"); + subghz_parser_load_came_atomo_file(subghz->txrx->parser, "/ext/subghz/came_atomo"); + // Check argument and run corresponding scene if(p && subghz_key_load(subghz, p)) { string_t filename; string_init(filename); path_extract_filename_no_ext(p, filename); - strlcpy( - subghz->file_name, string_get_cstr(filename), strlen(string_get_cstr(filename)) + 1); + strcpy(subghz->file_name, string_get_cstr(filename)); string_clear(filename); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); + if((!strcmp(subghz->txrx->protocol_result->name, "RAW"))) { + //Load Raw TX + subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); + } else { + //Load transmitter TX + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); + } } else { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); + if(load_database) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); + } else { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneShowError, SubghzCustomEventManagerSet); + string_set( + subghz->error_str, + "No SD card or\ndatabase found.\nSome app function\nmay be reduced."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } } furi_hal_power_suppress_charge_enter(); diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index ea06aae7..845eac0f 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -286,7 +286,7 @@ bool subghz_get_next_name_file(SubGhz* subghz) { storage_get_next_filename( storage, SUBGHZ_RAW_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION, temp_str); - memcpy(subghz->file_name, string_get_cstr(temp_str), strlen(string_get_cstr(temp_str))); + strcpy(subghz->file_name, string_get_cstr(temp_str)); res = true; } diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index c206f87b..733db844 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -74,6 +74,7 @@ typedef enum { SubGhzRxKeyStateAddKey, SubGhzRxKeyStateExit, SubGhzRxKeyStateRAWLoad, + SubGhzRxKeyStateRAWSave, } SubGhzRxKeyState; struct SubGhzTxRx { diff --git a/applications/subghz/views/subghz_read_raw.c b/applications/subghz/views/subghz_read_raw.c index 993ca914..cfb79ab4 100644 --- a/applications/subghz/views/subghz_read_raw.c +++ b/applications/subghz/views/subghz_read_raw.c @@ -10,6 +10,7 @@ #include #define SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE 100 +#define TAG "SubghzReadRAW" struct SubghzReadRAW { View* view; @@ -89,11 +90,22 @@ void subghz_read_raw_stop_send(SubghzReadRAW* instance) { with_view_model( instance->view, (SubghzReadRAWModel * model) { - if(model->satus == SubghzReadRAWStatusTXRepeat) { - // Start TX + switch(model->satus) { + case SubghzReadRAWStatusTXRepeat: + case SubghzReadRAWStatusLoadKeyTXRepeat: instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context); - } else { + break; + case SubghzReadRAWStatusTX: model->satus = SubghzReadRAWStatusIDLE; + break; + case SubghzReadRAWStatusLoadKeyTX: + model->satus = SubghzReadRAWStatusLoadKeyIDLE; + break; + + default: + FURI_LOG_W(TAG, "unknown status"); + model->satus = SubghzReadRAWStatusIDLE; + break; } return true; }); @@ -203,6 +215,7 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubghzReadRAWModel* model) { } void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) { + uint8_t graphics_mode = 1; canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 5, 8, string_get_cstr(model->frequency_str)); @@ -214,32 +227,47 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) { canvas_draw_line(canvas, 0, 48, 115, 48); canvas_draw_line(canvas, 115, 14, 115, 48); - if((model->satus == SubghzReadRAWStatusTX) || (model->satus == SubghzReadRAWStatusTXRepeat)) { + switch(model->satus) { + case SubghzReadRAWStatusIDLE: + elements_button_left(canvas, "Erase"); + elements_button_center(canvas, "Send"); + elements_button_right(canvas, "Save"); + break; + case SubghzReadRAWStatusLoadKeyIDLE: + elements_button_left(canvas, "New"); + elements_button_center(canvas, "Send"); + elements_button_right(canvas, "More"); + canvas_draw_str_aligned( + canvas, 58, 28, AlignCenter, AlignTop, string_get_cstr(model->file_name)); + break; + + case SubghzReadRAWStatusTX: + case SubghzReadRAWStatusTXRepeat: + case SubghzReadRAWStatusLoadKeyTX: + case SubghzReadRAWStatusLoadKeyTXRepeat: + graphics_mode = 0; + elements_button_center(canvas, "Send"); + break; + + case SubghzReadRAWStatusStart: + elements_button_left(canvas, "Config"); + elements_button_center(canvas, "REC"); + break; + + default: + elements_button_center(canvas, "Stop"); + break; + } + + if(graphics_mode == 0) { subghz_read_raw_draw_sin(canvas, model); } else { subghz_read_raw_draw_rssi(canvas, model); subghz_read_raw_draw_scale(canvas, model); + canvas_set_font_direction(canvas, CanvasDirectionBottomToTop); + canvas_draw_str(canvas, 126, 40, "RSSI"); + canvas_set_font_direction(canvas, CanvasDirectionLeftToRight); } - - if(model->satus == SubghzReadRAWStatusIDLE) { - elements_button_left(canvas, "Erase"); - elements_button_center(canvas, "Send"); - elements_button_right(canvas, "Save"); - canvas_draw_str_aligned( - canvas, 58, 28, AlignCenter, AlignTop, string_get_cstr(model->file_name)); - } else if(model->satus == SubghzReadRAWStatusStart) { - elements_button_left(canvas, "Config"); - elements_button_center(canvas, "REC"); - } else if( - (model->satus == SubghzReadRAWStatusTX) || (model->satus == SubghzReadRAWStatusTXRepeat)) { - elements_button_center(canvas, "Send"); - } else { - elements_button_center(canvas, "Stop"); - } - - canvas_set_font_direction(canvas, 3); - canvas_draw_str(canvas, 126, 40, "RSSI"); - canvas_set_font_direction(canvas, 0); } bool subghz_read_raw_input(InputEvent* event, void* context) { @@ -255,14 +283,32 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { with_view_model( instance->view, (SubghzReadRAWModel * model) { uint8_t ret = false; - if(model->satus == SubghzReadRAWStatusIDLE) { + switch(model->satus) { + case SubghzReadRAWStatusIDLE: // Start TX instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context); instance->callback(SubghzCustomEventViewReadRAWVibro, instance->context); model->satus = SubghzReadRAWStatusTXRepeat; ret = true; - } else if(model->satus == SubghzReadRAWStatusTX) { + break; + case SubghzReadRAWStatusTX: + // Start TXRepeat model->satus = SubghzReadRAWStatusTXRepeat; + break; + case SubghzReadRAWStatusLoadKeyIDLE: + // Start Load Key TX + instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context); + instance->callback(SubghzCustomEventViewReadRAWVibro, instance->context); + model->satus = SubghzReadRAWStatusLoadKeyTXRepeat; + ret = true; + break; + case SubghzReadRAWStatusLoadKeyTX: + // Start Load Key TXRepeat + model->satus = SubghzReadRAWStatusLoadKeyTXRepeat; + break; + + default: + break; } return ret; }); @@ -272,19 +318,40 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { if(model->satus == SubghzReadRAWStatusTXRepeat) { // Stop repeat TX model->satus = SubghzReadRAWStatusTX; + } else if(model->satus == SubghzReadRAWStatusLoadKeyTXRepeat) { + // Stop repeat TX + model->satus = SubghzReadRAWStatusLoadKeyTX; } return false; }); } else if(event->key == InputKeyBack && event->type == InputTypeShort) { with_view_model( instance->view, (SubghzReadRAWModel * model) { - if(model->satus == SubghzReadRAWStatusREC) { + switch(model->satus) { + case SubghzReadRAWStatusREC: //Stop REC instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context); model->satus = SubghzReadRAWStatusIDLE; - } else { + break; + case SubghzReadRAWStatusLoadKeyTX: + //Stop TxRx + instance->callback(SubghzCustomEventViewReadRAWTXRXStop, instance->context); + model->satus = SubghzReadRAWStatusLoadKeyIDLE; + break; + case SubghzReadRAWStatusTX: + //Stop TxRx + instance->callback(SubghzCustomEventViewReadRAWTXRXStop, instance->context); + model->satus = SubghzReadRAWStatusIDLE; + break; + case SubghzReadRAWStatusLoadKeyIDLE: //Exit instance->callback(SubghzCustomEventViewReadRAWBack, instance->context); + break; + + default: + //Exit + instance->callback(SubghzCustomEventViewReadRAWBack, instance->context); + break; } return true; }); @@ -294,7 +361,9 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { if(model->satus == SubghzReadRAWStatusStart) { //Config instance->callback(SubghzCustomEventViewReadRAWConfig, instance->context); - } else if(model->satus == SubghzReadRAWStatusIDLE) { + } else if( + (model->satus == SubghzReadRAWStatusIDLE) || + (model->satus == SubghzReadRAWStatusLoadKeyIDLE)) { //Erase model->satus = SubghzReadRAWStatusStart; model->rssi_history_end = false; @@ -308,9 +377,12 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { } else if(event->key == InputKeyRight && event->type == InputTypeShort) { with_view_model( instance->view, (SubghzReadRAWModel * model) { - //Save if(model->satus == SubghzReadRAWStatusIDLE) { + //Save instance->callback(SubghzCustomEventViewReadRAWSave, instance->context); + } else if(model->satus == SubghzReadRAWStatusLoadKeyIDLE) { + //More + instance->callback(SubghzCustomEventViewReadRAWMore, instance->context); } return true; }); @@ -323,9 +395,7 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { model->satus = SubghzReadRAWStatusREC; model->ind_write = 0; model->rssi_history_end = false; - } else if( - (model->satus != SubghzReadRAWStatusTX) && - (model->satus != SubghzReadRAWStatusTXRepeat)) { + } else if(model->satus == SubghzReadRAWStatusREC) { //Stop instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context); model->satus = SubghzReadRAWStatusIDLE; @@ -341,7 +411,9 @@ void subghz_read_raw_set_status( SubghzReadRAWStatus satus, const char* file_name) { furi_assert(instance); - if(satus == SubghzReadRAWStatusStart) { + + switch(satus) { + case SubghzReadRAWStatusStart: with_view_model( instance->view, (SubghzReadRAWModel * model) { model->satus = SubghzReadRAWStatusStart; @@ -351,22 +423,42 @@ void subghz_read_raw_set_status( string_set(model->sample_write, "0 spl."); return true; }); - } else if(satus == SubghzReadRAWStatusIDLE) { + break; + case SubghzReadRAWStatusIDLE: with_view_model( instance->view, (SubghzReadRAWModel * model) { model->satus = SubghzReadRAWStatusIDLE; return true; }); - } else if(satus == SubghzReadRAWStatusTX) { + break; + case SubghzReadRAWStatusLoadKeyTX: with_view_model( instance->view, (SubghzReadRAWModel * model) { - model->satus = SubghzReadRAWStatusIDLE; + model->satus = SubghzReadRAWStatusLoadKeyIDLE; model->rssi_history_end = false; model->ind_write = 0; string_set(model->file_name, file_name); string_set(model->sample_write, "RAW"); return true; }); + break; + case SubghzReadRAWStatusSaveKey: + with_view_model( + instance->view, (SubghzReadRAWModel * model) { + model->satus = SubghzReadRAWStatusLoadKeyIDLE; + if(!model->ind_write) { + string_set(model->file_name, file_name); + string_set(model->sample_write, "RAW"); + } else { + string_reset(model->file_name); + } + return true; + }); + break; + + default: + FURI_LOG_W(TAG, "unknown status"); + break; } } @@ -382,7 +474,8 @@ void subghz_read_raw_exit(void* context) { with_view_model( instance->view, (SubghzReadRAWModel * model) { if(model->satus != SubghzReadRAWStatusIDLE && - model->satus != SubghzReadRAWStatusStart) { + model->satus != SubghzReadRAWStatusStart && + model->satus != SubghzReadRAWStatusLoadKeyIDLE) { instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context); model->satus = SubghzReadRAWStatusStart; } diff --git a/applications/subghz/views/subghz_read_raw.h b/applications/subghz/views/subghz_read_raw.h index 86b69253..443d0185 100644 --- a/applications/subghz/views/subghz_read_raw.h +++ b/applications/subghz/views/subghz_read_raw.h @@ -13,6 +13,11 @@ typedef enum { SubghzReadRAWStatusREC, SubghzReadRAWStatusTX, SubghzReadRAWStatusTXRepeat, + + SubghzReadRAWStatusLoadKeyIDLE, + SubghzReadRAWStatusLoadKeyTX, + SubghzReadRAWStatusLoadKeyTXRepeat, + SubghzReadRAWStatusSaveKey, } SubghzReadRAWStatus; void subghz_read_raw_set_callback( diff --git a/lib/subghz/subghz_parser.c b/lib/subghz/subghz_parser.c index 93c48cb7..dbb2ffd8 100644 --- a/lib/subghz/subghz_parser.c +++ b/lib/subghz/subghz_parser.c @@ -215,12 +215,15 @@ void subghz_parser_load_came_atomo_file(SubGhzParser* instance, const char* file (SubGhzProtocolCameAtomo*)instance->protocols[SubGhzProtocolTypeCameAtomo], file_name); } -void subghz_parser_load_keeloq_file(SubGhzParser* instance, const char* file_name) { +bool subghz_parser_load_keeloq_file(SubGhzParser* instance, const char* file_name) { + bool ret = false; if (subghz_keystore_load(instance->keystore, file_name)) { FURI_LOG_I(SUBGHZ_PARSER_TAG, "Successfully loaded keeloq keys from %s", file_name); + ret = true; } else { FURI_LOG_W(SUBGHZ_PARSER_TAG, "Failed to load keeloq keysfrom %s", file_name); } + return ret; } void subghz_parser_reset(SubGhzParser* instance) { diff --git a/lib/subghz/subghz_parser.h b/lib/subghz/subghz_parser.h index 7e6c72b8..c5a46dd7 100644 --- a/lib/subghz/subghz_parser.h +++ b/lib/subghz/subghz_parser.h @@ -67,8 +67,9 @@ void subghz_parser_load_came_atomo_file(SubGhzParser* instance, const char* file * * @param instance - SubGhzParser instance * @param file_name - "path/file_name" + * @return bool */ -void subghz_parser_load_keeloq_file(SubGhzParser* instance, const char* file_name); +bool subghz_parser_load_keeloq_file(SubGhzParser* instance, const char* file_name); /** Restarting all parsers * From 9b62b557b442ab88206b8b44253c1dcbac35c4e3 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Wed, 22 Dec 2021 23:35:53 +0400 Subject: [PATCH 10/14] SubGhz: fix transmission frequency (#922) --- .../subghz/scenes/subghz_scene_more_raw.c | 2 +- .../subghz/scenes/subghz_scene_saved_menu.c | 2 +- .../targets/f6/furi-hal/furi-hal-subghz.c | 60 ------------------- .../targets/f7/furi-hal/furi-hal-subghz.c | 60 ------------------- 4 files changed, 2 insertions(+), 122 deletions(-) diff --git a/applications/subghz/scenes/subghz_scene_more_raw.c b/applications/subghz/scenes/subghz_scene_more_raw.c index c8fde230..10e0aad4 100644 --- a/applications/subghz/scenes/subghz_scene_more_raw.c +++ b/applications/subghz/scenes/subghz_scene_more_raw.c @@ -15,7 +15,7 @@ void subghz_scene_more_raw_on_enter(void* context) { submenu_add_item( subghz->submenu, - "Edit name", + "Rename", SubmenuIndexEdit, subghz_scene_more_raw_submenu_callback, subghz); diff --git a/applications/subghz/scenes/subghz_scene_saved_menu.c b/applications/subghz/scenes/subghz_scene_saved_menu.c index a25f8e6f..c6623c6b 100644 --- a/applications/subghz/scenes/subghz_scene_saved_menu.c +++ b/applications/subghz/scenes/subghz_scene_saved_menu.c @@ -22,7 +22,7 @@ void subghz_scene_saved_menu_on_enter(void* context) { submenu_add_item( subghz->submenu, - "Edit name", + "Rename", SubmenuIndexEdit, subghz_scene_saved_menu_submenu_callback, subghz); diff --git a/firmware/targets/f6/furi-hal/furi-hal-subghz.c b/firmware/targets/f6/furi-hal/furi-hal-subghz.c index a493eb49..b54b4845 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f6/furi-hal/furi-hal-subghz.c @@ -60,17 +60,6 @@ static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = { {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1] {CC1101_FREND1, 0xB6}, // - /* Frequency Synthesizer Calibration, valid for 433.92 */ - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - - /* Magic f4ckery */ - {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled - /* End */ {0, 0}, }; @@ -122,17 +111,6 @@ static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = { {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1] {CC1101_FREND1, 0xB6}, // - /* Frequency Synthesizer Calibration, valid for 433.92 */ - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - - /* Magic f4ckery */ - {CC1101_TEST2, 0x88}, - {CC1101_TEST1, 0x31}, - {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled - /* End */ {0, 0}, }; @@ -177,17 +155,6 @@ static const uint8_t furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs[][2] = { {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer {CC1101_FREND1, 0x56}, - /* Frequency Synthesizer Calibration, valid for 433.92 */ - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - - /* Magic f4ckery */ - {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled - /* End */ {0, 0}, }; @@ -232,17 +199,6 @@ static const uint8_t furi_hal_subghz_preset_2fsk_dev4_76khz_async_regs[][2] = { {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer {CC1101_FREND1, 0x56}, - /* Frequency Synthesizer Calibration, valid for 433.92 */ - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - - /* Magic f4ckery */ - {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled - /* End */ {0, 0}, }; @@ -279,17 +235,9 @@ static const uint8_t furi_hal_subghz_preset_msk_99_97kb_async_regs[][2] = { {CC1101_FREND0, 0x10}, {CC1101_FREND1, 0x56}, - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - {CC1101_BSCFG, 0x1C}, {CC1101_FSTEST, 0x59}, - {CC1101_TEST2, 0x81}, - {CC1101_TEST1, 0x35}, - {CC1101_TEST0, 0x09}, /* End */ {0, 0}, }; @@ -322,13 +270,6 @@ static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { {CC1101_AGCCTRL0, 0x91}, {CC1101_WORCTRL, 0xFB}, //Wake On Radio Control - {CC1101_FSCAL3, 0xE9}, //Frequency Synthesizer Calibration - {CC1101_FSCAL2, 0x2A}, //Frequency Synthesizer Calibration - {CC1101_FSCAL1, 0x00}, //Frequency Synthesizer Calibration - {CC1101_FSCAL0, 0x1F}, //Frequency Synthesizer Calibration - {CC1101_TEST2, 0x81}, //Various Test Settings - {CC1101_TEST1, 0x35}, //Various Test Settings - {CC1101_TEST0, 0x09}, //Various Test Settings /* End */ {0, 0}, }; @@ -687,7 +628,6 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) { } furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); - return real_frequency; } diff --git a/firmware/targets/f7/furi-hal/furi-hal-subghz.c b/firmware/targets/f7/furi-hal/furi-hal-subghz.c index a493eb49..b54b4845 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-subghz.c +++ b/firmware/targets/f7/furi-hal/furi-hal-subghz.c @@ -60,17 +60,6 @@ static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = { {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1] {CC1101_FREND1, 0xB6}, // - /* Frequency Synthesizer Calibration, valid for 433.92 */ - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - - /* Magic f4ckery */ - {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled - /* End */ {0, 0}, }; @@ -122,17 +111,6 @@ static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = { {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1] {CC1101_FREND1, 0xB6}, // - /* Frequency Synthesizer Calibration, valid for 433.92 */ - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - - /* Magic f4ckery */ - {CC1101_TEST2, 0x88}, - {CC1101_TEST1, 0x31}, - {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled - /* End */ {0, 0}, }; @@ -177,17 +155,6 @@ static const uint8_t furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs[][2] = { {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer {CC1101_FREND1, 0x56}, - /* Frequency Synthesizer Calibration, valid for 433.92 */ - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - - /* Magic f4ckery */ - {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled - /* End */ {0, 0}, }; @@ -232,17 +199,6 @@ static const uint8_t furi_hal_subghz_preset_2fsk_dev4_76khz_async_regs[][2] = { {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer {CC1101_FREND1, 0x56}, - /* Frequency Synthesizer Calibration, valid for 433.92 */ - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - - /* Magic f4ckery */ - {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value - {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled - /* End */ {0, 0}, }; @@ -279,17 +235,9 @@ static const uint8_t furi_hal_subghz_preset_msk_99_97kb_async_regs[][2] = { {CC1101_FREND0, 0x10}, {CC1101_FREND1, 0x56}, - {CC1101_FSCAL3, 0xE9}, - {CC1101_FSCAL2, 0x2A}, - {CC1101_FSCAL1, 0x00}, - {CC1101_FSCAL0, 0x1F}, - {CC1101_BSCFG, 0x1C}, {CC1101_FSTEST, 0x59}, - {CC1101_TEST2, 0x81}, - {CC1101_TEST1, 0x35}, - {CC1101_TEST0, 0x09}, /* End */ {0, 0}, }; @@ -322,13 +270,6 @@ static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { {CC1101_AGCCTRL0, 0x91}, {CC1101_WORCTRL, 0xFB}, //Wake On Radio Control - {CC1101_FSCAL3, 0xE9}, //Frequency Synthesizer Calibration - {CC1101_FSCAL2, 0x2A}, //Frequency Synthesizer Calibration - {CC1101_FSCAL1, 0x00}, //Frequency Synthesizer Calibration - {CC1101_FSCAL0, 0x1F}, //Frequency Synthesizer Calibration - {CC1101_TEST2, 0x81}, //Various Test Settings - {CC1101_TEST1, 0x35}, //Various Test Settings - {CC1101_TEST0, 0x09}, //Various Test Settings /* End */ {0, 0}, }; @@ -687,7 +628,6 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) { } furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); - return real_frequency; } From 9e62f08e4d6805e01a08f4def2bf4611d920046c Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Wed, 22 Dec 2021 23:04:08 +0300 Subject: [PATCH 11/14] [FL-1958] U2F prototype (#879) * U2F implementation prototype * U2F data encryption and store, user confirmation request * remove debug prints * fix notification bug in chrome * split u2f_alloc into u2f_init and u2f_alloc * typo fix, furi-hal-trng -> furi-hal-random * rand/srand redefinition * SubGhz: a little bit of Dante. * u2f_data naming fix Co-authored-by: Aleksandr Kutuzov --- applications/applications.c | 6 + applications/applications.mk | 9 +- applications/debug_tools/usb_test.c | 4 +- applications/subghz/subghz.c | 7 +- applications/u2f/scenes/u2f_scene.c | 30 + applications/u2f/scenes/u2f_scene.h | 29 + applications/u2f/scenes/u2f_scene_config.h | 1 + applications/u2f/scenes/u2f_scene_main.c | 92 + applications/u2f/u2f.c | 332 +++ applications/u2f/u2f.h | 35 + applications/u2f/u2f_app.c | 77 + applications/u2f/u2f_app.h | 11 + applications/u2f/u2f_app_i.h | 45 + applications/u2f/u2f_data.c | 382 +++ applications/u2f/u2f_data.h | 25 + applications/u2f/u2f_hid.c | 293 +++ applications/u2f/u2f_hid.h | 18 + applications/u2f/views/u2f_view.c | 91 + applications/u2f/views/u2f_view.h | 23 + assets/resources/u2f/cert.der | Bin 0 -> 365 bytes assets/resources/u2f/cert_key.u2f | 5 + .../targets/f6/furi-hal/furi-hal-crypto.c | 110 + firmware/targets/f6/furi-hal/furi-hal-info.c | 61 +- .../targets/f6/furi-hal/furi-hal-random.c | 56 + .../targets/f6/furi-hal/furi-hal-usb-u2f.c | 309 +++ firmware/targets/f6/target.mk | 3 +- .../targets/f7/furi-hal/furi-hal-crypto.c | 110 + firmware/targets/f7/furi-hal/furi-hal-info.c | 61 +- .../targets/f7/furi-hal/furi-hal-random.c | 56 + .../targets/f7/furi-hal/furi-hal-usb-u2f.c | 309 +++ .../furi-hal-include/furi-hal-crypto.h | 4 + .../furi-hal-include/furi-hal-random.h | 24 + .../furi-hal-include/furi-hal-usb-hid-u2f.h | 36 + .../targets/furi-hal-include/furi-hal-usb.h | 1 + firmware/targets/furi-hal-include/furi-hal.h | 1 + lib/lib.mk | 4 + lib/micro-ecc/LICENSE.txt | 21 + lib/micro-ecc/README.md | 41 + lib/micro-ecc/asm_arm.inc | 820 ++++++ lib/micro-ecc/asm_arm_mult_square.inc | 2311 +++++++++++++++++ lib/micro-ecc/asm_arm_mult_square_umaal.inc | 1202 +++++++++ lib/micro-ecc/curve-specific.inc | 1248 +++++++++ lib/micro-ecc/platform-specific.inc | 94 + lib/micro-ecc/types.h | 108 + lib/micro-ecc/uECC.c | 1669 ++++++++++++ lib/micro-ecc/uECC.h | 367 +++ lib/micro-ecc/uECC_vli.h | 172 ++ lib/toolbox/hmac_sha256.c | 123 + lib/toolbox/hmac_sha256.h | 29 + lib/toolbox/sha256.c | 226 ++ lib/toolbox/sha256.h | 17 + 51 files changed, 10985 insertions(+), 123 deletions(-) create mode 100644 applications/u2f/scenes/u2f_scene.c create mode 100644 applications/u2f/scenes/u2f_scene.h create mode 100644 applications/u2f/scenes/u2f_scene_config.h create mode 100644 applications/u2f/scenes/u2f_scene_main.c create mode 100644 applications/u2f/u2f.c create mode 100644 applications/u2f/u2f.h create mode 100644 applications/u2f/u2f_app.c create mode 100644 applications/u2f/u2f_app.h create mode 100644 applications/u2f/u2f_app_i.h create mode 100644 applications/u2f/u2f_data.c create mode 100644 applications/u2f/u2f_data.h create mode 100644 applications/u2f/u2f_hid.c create mode 100644 applications/u2f/u2f_hid.h create mode 100644 applications/u2f/views/u2f_view.c create mode 100644 applications/u2f/views/u2f_view.h create mode 100644 assets/resources/u2f/cert.der create mode 100644 assets/resources/u2f/cert_key.u2f create mode 100644 firmware/targets/f6/furi-hal/furi-hal-random.c create mode 100644 firmware/targets/f6/furi-hal/furi-hal-usb-u2f.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-random.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-usb-u2f.c create mode 100644 firmware/targets/furi-hal-include/furi-hal-random.h create mode 100644 firmware/targets/furi-hal-include/furi-hal-usb-hid-u2f.h create mode 100644 lib/micro-ecc/LICENSE.txt create mode 100644 lib/micro-ecc/README.md create mode 100644 lib/micro-ecc/asm_arm.inc create mode 100644 lib/micro-ecc/asm_arm_mult_square.inc create mode 100644 lib/micro-ecc/asm_arm_mult_square_umaal.inc create mode 100644 lib/micro-ecc/curve-specific.inc create mode 100644 lib/micro-ecc/platform-specific.inc create mode 100644 lib/micro-ecc/types.h create mode 100644 lib/micro-ecc/uECC.c create mode 100644 lib/micro-ecc/uECC.h create mode 100644 lib/micro-ecc/uECC_vli.h create mode 100644 lib/toolbox/hmac_sha256.c create mode 100644 lib/toolbox/hmac_sha256.h create mode 100644 lib/toolbox/sha256.c create mode 100644 lib/toolbox/sha256.h diff --git a/applications/applications.c b/applications/applications.c index 515ba33e..86f765c8 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -20,6 +20,7 @@ extern int32_t desktop_srv(void* p); 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); @@ -154,6 +155,11 @@ const FlipperApplication FLIPPER_APPS[] = { #ifdef APP_BAD_USB {.app = bad_usb_app, .name = "Bad USB", .stack_size = 2048, .icon = &A_BadUsb_14}, #endif + +#ifdef APP_U2F + {.app = u2f_app, .name = "U2F", .stack_size = 2048, .icon = &A_U2F_14}, +#endif + }; const size_t FLIPPER_APPS_COUNT = sizeof(FLIPPER_APPS) / sizeof(FlipperApplication); diff --git a/applications/applications.mk b/applications/applications.mk index 35069882..c5843fee 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -50,6 +50,7 @@ APP_DISPLAY_TEST = 1 APP_BLE_HID = 1 APP_USB_MOUSE = 1 APP_BAD_USB = 1 +APP_U2F = 1 APP_UART_ECHO = 1 endif @@ -165,7 +166,13 @@ APP_BAD_USB ?= 0 ifeq ($(APP_BAD_USB), 1) CFLAGS += -DAPP_BAD_USB SRV_GUI = 1 -endif +endif + +APP_U2F ?= 0 +ifeq ($(APP_U2F), 1) +CFLAGS += -DAPP_U2F +SRV_GUI = 1 +endif APP_BLE_HID ?=0 ifeq ($(APP_BLE_HID), 1) diff --git a/applications/debug_tools/usb_test.c b/applications/debug_tools/usb_test.c index cacd715a..d613d527 100644 --- a/applications/debug_tools/usb_test.c +++ b/applications/debug_tools/usb_test.c @@ -35,7 +35,7 @@ void usb_test_submenu_callback(void* context, uint32_t index) { } else if(index == UsbTestSubmenuIndexHid) { furi_hal_usb_set_config(&usb_hid); } else if(index == UsbTestSubmenuIndexHidU2F) { - //furi_hal_usb_set_config(UsbModeU2F); + furi_hal_usb_set_config(&usb_hid_u2f); } } @@ -67,7 +67,7 @@ UsbTestApp* usb_test_app_alloc() { submenu_add_item( app->submenu, "HID KB+Mouse", UsbTestSubmenuIndexHid, usb_test_submenu_callback, app); submenu_add_item( - app->submenu, "TODO: HID U2F", UsbTestSubmenuIndexHidU2F, usb_test_submenu_callback, app); + app->submenu, "HID U2F", UsbTestSubmenuIndexHidU2F, usb_test_submenu_callback, app); view_set_previous_callback(submenu_get_view(app->submenu), usb_test_exit); view_dispatcher_add_view(app->view_dispatcher, 0, submenu_get_view(app->submenu)); diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 23599739..884bd4a3 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -1,7 +1,4 @@ -/* -* Give up hope, everyone who enters here!!! -* Оставь надежду, всяк сюда входящий!!! -*/ +/* Abandon hope, all ye who enter here. */ #include "subghz_i.h" #include @@ -329,4 +326,4 @@ int32_t subghz_app(void* p) { subghz_free(subghz); return 0; -} \ No newline at end of file +} diff --git a/applications/u2f/scenes/u2f_scene.c b/applications/u2f/scenes/u2f_scene.c new file mode 100644 index 00000000..92739fca --- /dev/null +++ b/applications/u2f/scenes/u2f_scene.c @@ -0,0 +1,30 @@ +#include "u2f_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const u2f_scene_on_enter_handlers[])(void*) = { +#include "u2f_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 u2f_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "u2f_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 u2f_scene_on_exit_handlers[])(void* context) = { +#include "u2f_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers u2f_scene_handlers = { + .on_enter_handlers = u2f_scene_on_enter_handlers, + .on_event_handlers = u2f_scene_on_event_handlers, + .on_exit_handlers = u2f_scene_on_exit_handlers, + .scene_num = U2fSceneNum, +}; diff --git a/applications/u2f/scenes/u2f_scene.h b/applications/u2f/scenes/u2f_scene.h new file mode 100644 index 00000000..1a9dcd75 --- /dev/null +++ b/applications/u2f/scenes/u2f_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) U2fScene##id, +typedef enum { +#include "u2f_scene_config.h" + U2fSceneNum, +} U2fScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers u2f_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "u2f_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 "u2f_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 "u2f_scene_config.h" +#undef ADD_SCENE diff --git a/applications/u2f/scenes/u2f_scene_config.h b/applications/u2f/scenes/u2f_scene_config.h new file mode 100644 index 00000000..636589f2 --- /dev/null +++ b/applications/u2f/scenes/u2f_scene_config.h @@ -0,0 +1 @@ +ADD_SCENE(u2f, main, Main) diff --git a/applications/u2f/scenes/u2f_scene_main.c b/applications/u2f/scenes/u2f_scene_main.c new file mode 100644 index 00000000..6967a679 --- /dev/null +++ b/applications/u2f/scenes/u2f_scene_main.c @@ -0,0 +1,92 @@ +#include "../u2f_app_i.h" +#include "../views/u2f_view.h" +#include "furi-hal.h" +#include "../u2f.h" + +#define U2F_EVENT_TIMEOUT 500 + +static void u2f_scene_main_ok_callback(InputType type, void* context) { + furi_assert(context); + U2fApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventConfirm); +} + +static void u2f_scene_main_event_callback(U2fNotifyEvent evt, void* context) { + furi_assert(context); + U2fApp* app = context; + if(evt == U2fNotifyRegister) + view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventRegister); + else if(evt == U2fNotifyAuth) + view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventAuth); + else if(evt == U2fNotifyWink) + view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventWink); +} + +static void u2f_scene_main_timer_callback(void* context) { + furi_assert(context); + U2fApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventTimeout); +} + +bool u2f_scene_main_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + U2fApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if((event.event == U2fCustomEventRegister) || (event.event == U2fCustomEventAuth)) { + osTimerStart(app->timer, U2F_EVENT_TIMEOUT); + if(app->event_cur == U2fCustomEventNone) { + app->event_cur = event.event; + if(event.event == U2fCustomEventRegister) + u2f_view_set_state(app->u2f_view, U2fMsgRegister); + else if(event.event == U2fCustomEventAuth) + u2f_view_set_state(app->u2f_view, U2fMsgAuth); + notification_message(app->notifications, &sequence_success); + } + notification_message(app->notifications, &sequence_blink_blue_10); + } else if(event.event == U2fCustomEventWink) { + notification_message(app->notifications, &sequence_blink_green_10); + } else if(event.event == U2fCustomEventTimeout) { + app->event_cur = U2fCustomEventNone; + u2f_view_set_state(app->u2f_view, U2fMsgNone); + } else if(event.event == U2fCustomEventConfirm) { + if(app->event_cur != U2fCustomEventNone) { + u2f_confirm_user_present(app->u2f_instance); + } + } + + consumed = true; + } else if(event.type == SceneManagerEventTypeTick) { + } + return consumed; +} + +void u2f_scene_main_on_enter(void* context) { + U2fApp* app = context; + + app->timer = osTimerNew(u2f_scene_main_timer_callback, osTimerOnce, app, NULL); + + app->u2f_instance = u2f_alloc(); + app->u2f_ready = u2f_init(app->u2f_instance); + if(app->u2f_ready == true) { + u2f_set_event_callback(app->u2f_instance, u2f_scene_main_event_callback, app); + app->u2f_hid = u2f_hid_start(app->u2f_instance); + u2f_view_set_ok_callback(app->u2f_view, u2f_scene_main_ok_callback, app); + } else { + u2f_free(app->u2f_instance); + u2f_view_set_state(app->u2f_view, U2fMsgError); + } + + view_dispatcher_switch_to_view(app->view_dispatcher, U2fAppViewMain); +} + +void u2f_scene_main_on_exit(void* context) { + U2fApp* app = context; + osTimerStop(app->timer); + osTimerDelete(app->timer); + if(app->u2f_ready == true) { + u2f_hid_stop(app->u2f_hid); + u2f_free(app->u2f_instance); + } +} diff --git a/applications/u2f/u2f.c b/applications/u2f/u2f.c new file mode 100644 index 00000000..04c8e1df --- /dev/null +++ b/applications/u2f/u2f.c @@ -0,0 +1,332 @@ +#include +#include "u2f.h" +#include "u2f_hid.h" +#include "u2f_data.h" +#include +#include + +#include "toolbox/sha256.h" +#include "toolbox/hmac_sha256.h" +#include "micro-ecc/uECC.h" + +#define TAG "U2F" +#define WORKER_TAG TAG "Worker" + +#define U2F_CMD_REGISTER 0x01 +#define U2F_CMD_AUTHENTICATE 0x02 +#define U2F_CMD_VERSION 0x03 + +typedef enum { + U2fCheckOnly = 0x07, // "check-only" - only check key handle, don't send auth response + U2fEnforce = + 0x03, // "enforce-user-presence-and-sign" - send auth response only if user is present + U2fDontEnforce = + 0x08, // "dont-enforce-user-presence-and-sign" - send auth response even if user is missing +} U2fAuthMode; + +typedef struct { + uint8_t format; + uint8_t xy[64]; +} __attribute__((packed)) U2fPubKey; + +typedef struct { + uint8_t len; + uint8_t hash[32]; + uint8_t nonce[32]; +} __attribute__((packed)) U2fKeyHandle; + +typedef struct { + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t len[3]; + uint8_t challenge[32]; + uint8_t app_id[32]; +} __attribute__((packed)) U2fRegisterReq; + +typedef struct { + uint8_t reserved; + U2fPubKey pub_key; + U2fKeyHandle key_handle; + uint8_t cert[]; +} __attribute__((packed)) U2fRegisterResp; + +typedef struct { + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t len[3]; + uint8_t challenge[32]; + uint8_t app_id[32]; + U2fKeyHandle key_handle; +} __attribute__((packed)) U2fAuthReq; + +typedef struct { + uint8_t user_present; + uint32_t counter; + uint8_t signature[]; +} __attribute__((packed)) U2fAuthResp; + +static const uint8_t ver_str[] = {"U2F_V2"}; + +static const uint8_t state_no_error[] = {0x90, 0x00}; +static const uint8_t state_not_supported[] = {0x6D, 0x00}; +static const uint8_t state_user_missing[] = {0x69, 0x85}; +static const uint8_t state_wrong_data[] = {0x6A, 0x80}; + +struct U2fData { + uint8_t device_key[32]; + uint8_t cert_key[32]; + uint32_t counter; + const struct uECC_Curve_t* p_curve; + bool ready; + bool user_present; + U2fEvtCallback callback; + void* context; +}; + +static int u2f_uecc_random(uint8_t* dest, unsigned size) { + furi_hal_random_fill_buf(dest, size); + return 1; +} + +U2fData* u2f_alloc() { + return furi_alloc(sizeof(U2fData)); +} + +void u2f_free(U2fData* U2F) { + furi_assert(U2F); + free(U2F); +} + +bool u2f_init(U2fData* U2F) { + furi_assert(U2F); + + if(u2f_data_cert_check() == false) { + FURI_LOG_E(TAG, "Certificate load error"); + return false; + } + if(u2f_data_cert_key_load(U2F->cert_key) == false) { + FURI_LOG_E(TAG, "Certificate key load error"); + return false; + } + if(u2f_data_key_load(U2F->device_key) == false) { + FURI_LOG_W(TAG, "Key loading error, generating new"); + if(u2f_data_key_generate(U2F->device_key) == false) { + FURI_LOG_E(TAG, "Key write failed"); + return false; + } + } + if(u2f_data_cnt_read(&U2F->counter) == false) { + FURI_LOG_W(TAG, "Counter loading error, resetting counter"); + U2F->counter = 0; + if(u2f_data_cnt_write(0) == false) { + FURI_LOG_E(TAG, "Counter write failed"); + return false; + } + } + + U2F->p_curve = uECC_secp256r1(); + uECC_set_rng(u2f_uecc_random); + + U2F->ready = true; + return true; +} + +void u2f_set_event_callback(U2fData* U2F, U2fEvtCallback callback, void* context) { + furi_assert(U2F); + furi_assert(callback); + U2F->callback = callback; + U2F->context = context; +} + +void u2f_confirm_user_present(U2fData* U2F) { + U2F->user_present = true; +} + +static uint8_t u2f_der_encode_int(uint8_t* der, uint8_t* val, uint8_t val_len) { + der[0] = 0x02; // Integer + + uint8_t len = 2; + // Omit leading zeros + while(val[0] == 0 && val_len > 0) { + ++val; + --val_len; + } + + // Check if integer is negative + if(val[0] > 0x7f) der[len++] = 0; + + memcpy(der + len, val, val_len); + len += val_len; + + der[1] = len - 2; + return len; +} + +static uint8_t u2f_der_encode_signature(uint8_t* der, uint8_t* sig) { + der[0] = 0x30; + + uint8_t len = 2; + len += u2f_der_encode_int(der + len, sig, 32); + len += u2f_der_encode_int(der + len, sig + 32, 32); + + der[1] = len - 2; + return len; +} + +static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { + U2fRegisterReq* req = (U2fRegisterReq*)buf; + U2fRegisterResp* resp = (U2fRegisterResp*)buf; + U2fKeyHandle handle; + uint8_t private[32]; + U2fPubKey pub_key; + uint8_t hash[32]; + uint8_t signature[64]; + + if(U2F->callback != NULL) U2F->callback(U2fNotifyRegister, U2F->context); + if(U2F->user_present == false) { + memcpy(&buf[0], state_user_missing, 2); + return 2; + } + U2F->user_present = false; + + hmac_sha256_context hmac_ctx; + sha256_context sha_ctx; + + handle.len = 32 * 2; + // Generate random nonce + furi_hal_random_fill_buf(handle.nonce, 32); + + // Generate private key + hmac_sha256_init(&hmac_ctx, U2F->device_key); + hmac_sha256_update(&hmac_ctx, req->app_id, 32); + hmac_sha256_update(&hmac_ctx, handle.nonce, 32); + hmac_sha256_finish(&hmac_ctx, U2F->device_key, private); + + // Generate private key handle + hmac_sha256_init(&hmac_ctx, U2F->device_key); + hmac_sha256_update(&hmac_ctx, private, 32); + hmac_sha256_update(&hmac_ctx, req->app_id, 32); + hmac_sha256_finish(&hmac_ctx, U2F->device_key, handle.hash); + + // Generate public key + pub_key.format = 0x04; // Uncompressed point + uECC_compute_public_key(private, pub_key.xy, U2F->p_curve); + + // Generate signature + uint8_t reserved_byte = 0; + sha256_start(&sha_ctx); + sha256_update(&sha_ctx, &reserved_byte, 1); + sha256_update(&sha_ctx, req->app_id, 32); + sha256_update(&sha_ctx, req->challenge, 32); + sha256_update(&sha_ctx, handle.hash, handle.len); + sha256_update(&sha_ctx, (uint8_t*)&pub_key, 65); + sha256_finish(&sha_ctx, hash); + + uECC_sign(U2F->cert_key, hash, 32, signature, U2F->p_curve); + + // Encode response message + resp->reserved = 0x05; + memcpy(&(resp->pub_key), &pub_key, sizeof(U2fPubKey)); + memcpy(&(resp->key_handle), &handle, sizeof(U2fKeyHandle)); + uint32_t cert_len = u2f_data_cert_load(resp->cert); + uint8_t signature_len = u2f_der_encode_signature(resp->cert + cert_len, signature); + memcpy(resp->cert + cert_len + signature_len, state_no_error, 2); + + return (sizeof(U2fRegisterResp) + cert_len + signature_len + 2); +} + +static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { + U2fAuthReq* req = (U2fAuthReq*)buf; + U2fAuthResp* resp = (U2fAuthResp*)buf; + uint8_t priv_key[32]; + uint8_t mac_control[32]; + hmac_sha256_context hmac_ctx; + sha256_context sha_ctx; + uint8_t flags = 0; + uint8_t hash[32]; + uint8_t signature[64]; + + if(U2F->callback != NULL) U2F->callback(U2fNotifyAuth, U2F->context); + if(U2F->user_present == true) { + flags |= 1; + } else { + if(req->p1 == U2fEnforce) { + memcpy(&buf[0], state_user_missing, 2); + return 2; + } + } + U2F->user_present = false; + + // Generate hash + sha256_start(&sha_ctx); + sha256_update(&sha_ctx, req->app_id, 32); + sha256_update(&sha_ctx, &flags, 1); + sha256_update(&sha_ctx, (uint8_t*)&(U2F->counter), 4); + sha256_update(&sha_ctx, req->challenge, 32); + sha256_finish(&sha_ctx, hash); + + // Recover private key + hmac_sha256_init(&hmac_ctx, U2F->device_key); + hmac_sha256_update(&hmac_ctx, req->app_id, 32); + hmac_sha256_update(&hmac_ctx, req->key_handle.nonce, 32); + hmac_sha256_finish(&hmac_ctx, U2F->device_key, priv_key); + + // Generate and verify private key handle + hmac_sha256_init(&hmac_ctx, U2F->device_key); + hmac_sha256_update(&hmac_ctx, priv_key, 32); + hmac_sha256_update(&hmac_ctx, req->app_id, 32); + hmac_sha256_finish(&hmac_ctx, U2F->device_key, mac_control); + + if(memcmp(req->key_handle.hash, mac_control, 32) != 0) { + FURI_LOG_W(TAG, "Wrong handle!"); + memcpy(&buf[0], state_wrong_data, 2); + return 2; + } + + if(req->p1 == U2fCheckOnly) { // Check-only: don't need to send full response + memcpy(&buf[0], state_user_missing, 2); + return 2; + } + + uECC_sign(priv_key, hash, 32, signature, U2F->p_curve); + + resp->user_present = flags; + resp->counter = U2F->counter; + uint8_t signature_len = u2f_der_encode_signature(resp->signature, signature); + memcpy(resp->signature + signature_len, state_no_error, 2); + + FURI_LOG_I(TAG, "Counter: %lu", U2F->counter); + U2F->counter++; + u2f_data_cnt_write(U2F->counter); + + return (sizeof(U2fAuthResp) + signature_len + 2); +} + +uint16_t u2f_msg_parse(U2fData* U2F, uint8_t* buf, uint16_t len) { + furi_assert(U2F); + if(!U2F->ready) return 0; + if((buf[0] != 0x00) && (len < 5)) return 0; + if(buf[1] == U2F_CMD_REGISTER) { // Register request + return u2f_register(U2F, buf); + + } else if(buf[1] == U2F_CMD_AUTHENTICATE) { // Authenticate request + return u2f_authenticate(U2F, buf); + + } else if(buf[1] == U2F_CMD_VERSION) { // Get U2F version string + memcpy(&buf[0], ver_str, 6); + memcpy(&buf[6], state_no_error, 2); + return 8; + } else { + memcpy(&buf[0], state_not_supported, 2); + return 2; + } + return 0; +} + +void u2f_wink(U2fData* U2F) { + if(U2F->callback != NULL) U2F->callback(U2fNotifyWink, U2F->context); +} diff --git a/applications/u2f/u2f.h b/applications/u2f/u2f.h new file mode 100644 index 00000000..5e7d7b32 --- /dev/null +++ b/applications/u2f/u2f.h @@ -0,0 +1,35 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef enum { + U2fNotifyRegister, + U2fNotifyAuth, + U2fNotifyWink, +} U2fNotifyEvent; + +typedef struct U2fData U2fData; + +typedef void (*U2fEvtCallback)(U2fNotifyEvent evt, void* context); + +U2fData* u2f_alloc(); + +bool u2f_init(U2fData* instance); + +void u2f_free(U2fData* instance); + +void u2f_set_event_callback(U2fData* instance, U2fEvtCallback callback, void* context); + +void u2f_confirm_user_present(U2fData* instance); + +uint16_t u2f_msg_parse(U2fData* instance, uint8_t* buf, uint16_t len); + +void u2f_wink(U2fData* instance); + +#ifdef __cplusplus +} +#endif diff --git a/applications/u2f/u2f_app.c b/applications/u2f/u2f_app.c new file mode 100644 index 00000000..3a096b7e --- /dev/null +++ b/applications/u2f/u2f_app.c @@ -0,0 +1,77 @@ +#include "u2f_app_i.h" +#include +#include + +static bool u2f_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + U2fApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool u2f_app_back_event_callback(void* context) { + furi_assert(context); + U2fApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void u2f_app_tick_event_callback(void* context) { + furi_assert(context); + U2fApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +U2fApp* u2f_app_alloc() { + U2fApp* app = furi_alloc(sizeof(U2fApp)); + + app->gui = furi_record_open("gui"); + app->notifications = furi_record_open("notification"); + + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&u2f_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, u2f_app_tick_event_callback, 500); + + view_dispatcher_set_custom_event_callback(app->view_dispatcher, u2f_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, u2f_app_back_event_callback); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + app->u2f_view = u2f_view_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, U2fAppViewMain, u2f_view_get_view(app->u2f_view)); + + scene_manager_next_scene(app->scene_manager, U2fAppViewMain); + + return app; +} + +void u2f_app_free(U2fApp* app) { + furi_assert(app); + + // Views + view_dispatcher_remove_view(app->view_dispatcher, U2fAppViewMain); + u2f_view_free(app->u2f_view); + + // View dispatcher + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + + // Close records + furi_record_close("gui"); + furi_record_close("notification"); + + free(app); +} + +int32_t u2f_app(void* p) { + U2fApp* u2f_app = u2f_app_alloc(); + + view_dispatcher_run(u2f_app->view_dispatcher); + + u2f_app_free(u2f_app); + + return 0; +} diff --git a/applications/u2f/u2f_app.h b/applications/u2f/u2f_app.h new file mode 100644 index 00000000..b19e0cca --- /dev/null +++ b/applications/u2f/u2f_app.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct U2fApp U2fApp; + +#ifdef __cplusplus +} +#endif diff --git a/applications/u2f/u2f_app_i.h b/applications/u2f/u2f_app_i.h new file mode 100644 index 00000000..6a30286e --- /dev/null +++ b/applications/u2f/u2f_app_i.h @@ -0,0 +1,45 @@ +#pragma once + +#include "u2f_app.h" +#include "scenes/u2f_scene.h" + +#include +#include +#include +#include +#include +#include +#include +#include "views/u2f_view.h" +#include "u2f_hid.h" +#include "u2f.h" + +typedef enum { + U2fCustomEventNone, + + U2fCustomEventRegister, + U2fCustomEventAuth, + U2fCustomEventWink, + + U2fCustomEventTimeout, + + U2fCustomEventConfirm, + +} GpioCustomEvent; + +typedef enum { + U2fAppViewMain, +} U2fAppView; + +struct U2fApp { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + NotificationApp* notifications; + osTimerId_t timer; + U2fHid* u2f_hid; + U2fView* u2f_view; + U2fData* u2f_instance; + GpioCustomEvent event_cur; + bool u2f_ready; +}; diff --git a/applications/u2f/u2f_data.c b/applications/u2f/u2f_data.c new file mode 100644 index 00000000..038918a7 --- /dev/null +++ b/applications/u2f/u2f_data.c @@ -0,0 +1,382 @@ +#include +#include "u2f_hid.h" +#include +#include +#include +#include + +#define TAG "U2F" + +#define U2F_DATA_FOLDER "/any/u2f/" +#define U2F_CERT_FILE U2F_DATA_FOLDER "cert.der" +#define U2F_CERT_KEY_FILE U2F_DATA_FOLDER "cert_key.u2f" +#define U2F_KEY_FILE U2F_DATA_FOLDER "key.u2f" +#define U2F_CNT_FILE U2F_DATA_FOLDER "cnt.u2f" + +#define U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_FACTORY 2 +#define U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE 11 + +#define U2F_CERT_STOCK 0 // Stock certificate, private key is encrypted with factory key +#define U2F_CERT_USER 1 // User certificate, private key is encrypted with unique key + +#define U2F_CERT_KEY_FILE_TYPE "Flipper U2F Certificate Key File" +#define U2F_CERT_KEY_VERSION 1 + +#define U2F_DEVICE_KEY_FILE_TYPE "Flipper U2F Device Key File" +#define U2F_DEVICE_KEY_VERSION 1 + +#define U2F_COUNTER_FILE_TYPE "Flipper U2F Counter File" +#define U2F_COUNTER_VERSION 1 + +#define U2F_COUNTER_CONTROL_VAL 0xAA5500FF + +typedef struct { + uint32_t counter; + uint8_t random_salt[24]; + uint32_t control; +} __attribute__((packed)) U2fCounterData; + +bool u2f_data_cert_check() { + bool state = false; + Storage* fs_api = furi_record_open("storage"); + File* file = storage_file_alloc(fs_api); + uint8_t file_buf[8]; + + if(storage_file_open(file, U2F_CERT_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) { + do { + // Read header to check certificate size + size_t file_size = storage_file_size(file); + size_t len_cur = storage_file_read(file, file_buf, 4); + if(len_cur != 4) break; + + if(file_buf[0] != 0x30) { + FURI_LOG_E(TAG, "Wrong certificate header"); + break; + } + + size_t temp_len = ((file_buf[2] << 8) | (file_buf[3])) + 4; + if(temp_len != file_size) { + FURI_LOG_E(TAG, "Wrong certificate length"); + break; + } + state = true; + } while(0); + } + + storage_file_close(file); + storage_file_free(file); + + furi_record_close("storage"); + + return state; +} + +uint32_t u2f_data_cert_load(uint8_t* cert) { + furi_assert(cert); + + Storage* fs_api = furi_record_open("storage"); + File* file = storage_file_alloc(fs_api); + uint32_t file_size = 0; + uint32_t len_cur = 0; + + if(storage_file_open(file, U2F_CERT_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) { + file_size = storage_file_size(file); + len_cur = storage_file_read(file, cert, file_size); + if(len_cur != file_size) len_cur = 0; + } + + storage_file_close(file); + storage_file_free(file); + furi_record_close("storage"); + + return len_cur; +} + +bool u2f_data_cert_key_load(uint8_t* cert_key) { + furi_assert(cert_key); + + bool state = false; + uint8_t iv[16]; + uint8_t key[48]; + uint32_t cert_type = 0; + uint8_t key_slot = 0; + uint32_t version = 0; + + // Check if unique key exists in secure eclave and generate it if missing + if(!furi_hal_crypto_verify_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE)) return false; + + string_t filetype; + string_init(filetype); + + Storage* storage = furi_record_open("storage"); + FlipperFile* flipper_file = flipper_file_alloc(storage); + + if(flipper_file_open_existing(flipper_file, U2F_CERT_KEY_FILE)) { + do { + if(!flipper_file_read_header(flipper_file, filetype, &version)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + break; + } + + if(strcmp(string_get_cstr(filetype), U2F_CERT_KEY_FILE_TYPE) != 0 || + version != U2F_CERT_KEY_VERSION) { + FURI_LOG_E(TAG, "Type or version mismatch"); + break; + } + + if(!flipper_file_read_uint32(flipper_file, "Type", &cert_type, 1)) { + FURI_LOG_E(TAG, "Missing cert type"); + break; + } + + if(cert_type == U2F_CERT_STOCK) { + key_slot = U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_FACTORY; + } else if(cert_type == U2F_CERT_USER) { + key_slot = U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE; + } else { + FURI_LOG_E(TAG, "Unknown cert type"); + break; + } + + if(!flipper_file_read_hex(flipper_file, "IV", iv, 16)) { + FURI_LOG_E(TAG, "Missing IV"); + break; + } + + if(!flipper_file_read_hex(flipper_file, "Data", key, 48)) { + FURI_LOG_E(TAG, "Missing data"); + break; + } + + if(!furi_hal_crypto_store_load_key(key_slot, iv)) { + FURI_LOG_E(TAG, "Unable to load encryption key"); + break; + } + memset(cert_key, 0, 32); + + if(!furi_hal_crypto_decrypt(key, cert_key, 32)) { + memset(cert_key, 0, 32); + FURI_LOG_E(TAG, "Decryption failed"); + break; + } + furi_hal_crypto_store_unload_key(key_slot); + state = true; + } while(0); + } + + flipper_file_close(flipper_file); + flipper_file_free(flipper_file); + furi_record_close("storage"); + string_clear(filetype); + + return state; +} + +bool u2f_data_key_load(uint8_t* device_key) { + furi_assert(device_key); + + bool state = false; + uint8_t iv[16]; + uint8_t key[48]; + uint32_t version = 0; + + string_t filetype; + string_init(filetype); + + Storage* storage = furi_record_open("storage"); + FlipperFile* flipper_file = flipper_file_alloc(storage); + + if(flipper_file_open_existing(flipper_file, U2F_KEY_FILE)) { + do { + if(!flipper_file_read_header(flipper_file, filetype, &version)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + break; + } + if(strcmp(string_get_cstr(filetype), U2F_DEVICE_KEY_FILE_TYPE) != 0 || + version != U2F_DEVICE_KEY_VERSION) { + FURI_LOG_E(TAG, "Type or version mismatch"); + break; + } + if(!flipper_file_read_hex(flipper_file, "IV", iv, 16)) { + FURI_LOG_E(TAG, "Missing IV"); + break; + } + if(!flipper_file_read_hex(flipper_file, "Data", key, 48)) { + FURI_LOG_E(TAG, "Missing data"); + break; + } + if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) { + FURI_LOG_E(TAG, "Unable to load encryption key"); + break; + } + memset(device_key, 0, 32); + if(!furi_hal_crypto_decrypt(key, device_key, 32)) { + memset(device_key, 0, 32); + FURI_LOG_E(TAG, "Decryption failed"); + break; + } + furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE); + state = true; + } while(0); + } + flipper_file_close(flipper_file); + flipper_file_free(flipper_file); + furi_record_close("storage"); + string_clear(filetype); + return state; +} + +bool u2f_data_key_generate(uint8_t* device_key) { + furi_assert(device_key); + + bool state = false; + uint8_t iv[16]; + uint8_t key[32]; + uint8_t key_encrypted[48]; + + // Generate random IV and key + furi_hal_random_fill_buf(iv, 16); + furi_hal_random_fill_buf(key, 32); + + if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) { + FURI_LOG_E(TAG, "Unable to load encryption key"); + return false; + } + + if(!furi_hal_crypto_encrypt(key, key_encrypted, 32)) { + FURI_LOG_E(TAG, "Encryption failed"); + return false; + } + furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE); + + string_t filetype; + string_init(filetype); + + Storage* storage = furi_record_open("storage"); + FlipperFile* flipper_file = flipper_file_alloc(storage); + + if(flipper_file_open_always(flipper_file, U2F_KEY_FILE)) { + do { + if(!flipper_file_write_header_cstr( + flipper_file, U2F_DEVICE_KEY_FILE_TYPE, U2F_DEVICE_KEY_VERSION)) + break; + if(!flipper_file_write_hex(flipper_file, "IV", iv, 16)) break; + if(!flipper_file_write_hex(flipper_file, "Data", key_encrypted, 48)) break; + state = true; + memcpy(device_key, key, 32); + } while(0); + } + + flipper_file_close(flipper_file); + flipper_file_free(flipper_file); + furi_record_close("storage"); + string_clear(filetype); + + return state; +} + +bool u2f_data_cnt_read(uint32_t* cnt_val) { + furi_assert(cnt_val); + + bool state = false; + uint8_t iv[16]; + U2fCounterData cnt; + uint8_t cnt_encr[48]; + uint32_t version = 0; + + string_t filetype; + string_init(filetype); + + Storage* storage = furi_record_open("storage"); + FlipperFile* flipper_file = flipper_file_alloc(storage); + + if(flipper_file_open_existing(flipper_file, U2F_CNT_FILE)) { + do { + if(!flipper_file_read_header(flipper_file, filetype, &version)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + break; + } + if(strcmp(string_get_cstr(filetype), U2F_COUNTER_FILE_TYPE) != 0 || + version != U2F_COUNTER_VERSION) { + FURI_LOG_E(TAG, "Type or version mismatch"); + break; + } + if(!flipper_file_read_hex(flipper_file, "IV", iv, 16)) { + FURI_LOG_E(TAG, "Missing IV"); + break; + } + if(!flipper_file_read_hex(flipper_file, "Data", cnt_encr, 48)) { + FURI_LOG_E(TAG, "Missing data"); + break; + } + if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) { + FURI_LOG_E(TAG, "Unable to load encryption key"); + break; + } + memset(&cnt, 0, 32); + if(!furi_hal_crypto_decrypt(cnt_encr, (uint8_t*)&cnt, 32)) { + memset(&cnt, 0, 32); + FURI_LOG_E(TAG, "Decryption failed"); + break; + } + furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE); + if(cnt.control == U2F_COUNTER_CONTROL_VAL) { + *cnt_val = cnt.counter; + state = true; + } + } while(0); + } + flipper_file_close(flipper_file); + flipper_file_free(flipper_file); + furi_record_close("storage"); + string_clear(filetype); + return state; +} + +bool u2f_data_cnt_write(uint32_t cnt_val) { + bool state = false; + uint8_t iv[16]; + U2fCounterData cnt; + uint8_t cnt_encr[48]; + + // Generate random IV and key + furi_hal_random_fill_buf(iv, 16); + furi_hal_random_fill_buf(cnt.random_salt, 24); + cnt.control = U2F_COUNTER_CONTROL_VAL; + cnt.counter = cnt_val; + + if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) { + FURI_LOG_E(TAG, "Unable to load encryption key"); + return false; + } + + if(!furi_hal_crypto_encrypt((uint8_t*)&cnt, cnt_encr, 32)) { + FURI_LOG_E(TAG, "Encryption failed"); + return false; + } + furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE); + + string_t filetype; + string_init(filetype); + + Storage* storage = furi_record_open("storage"); + FlipperFile* flipper_file = flipper_file_alloc(storage); + + if(flipper_file_open_always(flipper_file, U2F_CNT_FILE)) { + do { + if(!flipper_file_write_header_cstr( + flipper_file, U2F_COUNTER_FILE_TYPE, U2F_COUNTER_VERSION)) + break; + if(!flipper_file_write_hex(flipper_file, "IV", iv, 16)) break; + if(!flipper_file_write_hex(flipper_file, "Data", cnt_encr, 48)) break; + state = true; + } while(0); + } + + flipper_file_close(flipper_file); + flipper_file_free(flipper_file); + furi_record_close("storage"); + string_clear(filetype); + + return state; +} diff --git a/applications/u2f/u2f_data.h b/applications/u2f/u2f_data.h new file mode 100644 index 00000000..e47e26a1 --- /dev/null +++ b/applications/u2f/u2f_data.h @@ -0,0 +1,25 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +bool u2f_data_cert_check(); + +uint32_t u2f_data_cert_load(uint8_t* cert); + +bool u2f_data_cert_key_load(uint8_t* cert_key); + +bool u2f_data_key_load(uint8_t* device_key); + +bool u2f_data_key_generate(uint8_t* device_key); + +bool u2f_data_cnt_read(uint32_t* cnt); + +bool u2f_data_cnt_write(uint32_t cnt); + +#ifdef __cplusplus +} +#endif diff --git a/applications/u2f/u2f_hid.c b/applications/u2f/u2f_hid.c new file mode 100644 index 00000000..34767c42 --- /dev/null +++ b/applications/u2f/u2f_hid.c @@ -0,0 +1,293 @@ +#include +#include "u2f_hid.h" +#include "u2f.h" +#include +#include +#include +#include +#include +#include + +#include + +#define TAG "U2FHID" +#define WORKER_TAG TAG "Worker" + +#define U2F_HID_MAX_PAYLOAD_LEN ((HID_U2F_PACKET_LEN - 7) + 128 * (HID_U2F_PACKET_LEN - 5)) + +#define U2F_HID_TYPE_MASK 0x80 // Frame type mask +#define U2F_HID_TYPE_INIT 0x80 // Initial frame identifier +#define U2F_HID_TYPE_CONT 0x00 // Continuation frame identifier + +#define U2F_HID_PING (U2F_HID_TYPE_INIT | 0x01) // Echo data through local processor only +#define U2F_HID_MSG (U2F_HID_TYPE_INIT | 0x03) // Send U2F message frame +#define U2F_HID_LOCK (U2F_HID_TYPE_INIT | 0x04) // Send lock channel command +#define U2F_HID_INIT (U2F_HID_TYPE_INIT | 0x06) // Channel initialization +#define U2F_HID_WINK (U2F_HID_TYPE_INIT | 0x08) // Send device identification wink +#define U2F_HID_ERROR (U2F_HID_TYPE_INIT | 0x3f) // Error response + +#define U2F_HID_ERR_NONE 0x00 // No error +#define U2F_HID_ERR_INVALID_CMD 0x01 // Invalid command +#define U2F_HID_ERR_INVALID_PAR 0x02 // Invalid parameter +#define U2F_HID_ERR_INVALID_LEN 0x03 // Invalid message length +#define U2F_HID_ERR_INVALID_SEQ 0x04 // Invalid message sequencing +#define U2F_HID_ERR_MSG_TIMEOUT 0x05 // Message has timed out +#define U2F_HID_ERR_CHANNEL_BUSY 0x06 // Channel busy +#define U2F_HID_ERR_LOCK_REQUIRED 0x0a // Command requires channel lock +#define U2F_HID_ERR_SYNC_FAIL 0x0b // SYNC command failed +#define U2F_HID_ERR_OTHER 0x7f // Other unspecified error + +#define U2F_HID_BROADCAST_CID 0xFFFFFFFF + +typedef enum { + WorkerEvtReserved = (1 << 0), + WorkerEvtStop = (1 << 1), + WorkerEvtConnect = (1 << 2), + WorkerEvtDisconnect = (1 << 3), + WorkerEvtRequest = (1 << 4), + WorkerEvtUnlock = (1 << 5), +} WorkerEvtFlags; + +struct U2fHid_packet { + uint32_t cid; + uint16_t len; + uint8_t cmd; + uint8_t payload[U2F_HID_MAX_PAYLOAD_LEN]; +}; + +struct U2fHid { + FuriThread* thread; + osTimerId_t lock_timer; + struct U2fHid_packet packet; + uint8_t seq_id_last; + uint16_t req_buf_ptr; + uint32_t req_len_left; + uint32_t lock_cid; + bool lock; + U2fData* u2f_instance; +}; + +static void u2f_hid_event_callback(HidU2fEvent ev, void* context) { + furi_assert(context); + U2fHid* u2f_hid = context; + + if(ev == HidU2fDisconnected) + osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtDisconnect); + else if(ev == HidU2fConnected) + osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtConnect); + else if(ev == HidU2fRequest) + osThreadFlagsSet(furi_thread_get_thread_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); +} + +static void u2f_hid_send_response(U2fHid* u2f_hid) { + uint8_t packet_buf[HID_U2F_PACKET_LEN]; + uint16_t len_remain = u2f_hid->packet.len; + uint8_t len_cur = 0; + uint8_t seq_cnt = 0; + uint16_t data_ptr = 0; + + memset(packet_buf, 0, HID_U2F_PACKET_LEN); + memcpy(packet_buf, &(u2f_hid->packet.cid), 4); + + // Init packet + packet_buf[4] = u2f_hid->packet.cmd; + packet_buf[5] = u2f_hid->packet.len >> 8; + packet_buf[6] = (u2f_hid->packet.len & 0xFF); + len_cur = (len_remain < (HID_U2F_PACKET_LEN - 7)) ? (len_remain) : (HID_U2F_PACKET_LEN - 7); + if(len_cur > 0) memcpy(&packet_buf[7], u2f_hid->packet.payload, len_cur); + furi_hal_hid_u2f_send_response(packet_buf, HID_U2F_PACKET_LEN); + data_ptr = len_cur; + len_remain -= len_cur; + + // Continuation packets + while(len_remain > 0) { + memset(&packet_buf[4], 0, HID_U2F_PACKET_LEN - 4); + packet_buf[4] = seq_cnt; + len_cur = (len_remain < (HID_U2F_PACKET_LEN - 5)) ? (len_remain) : + (HID_U2F_PACKET_LEN - 5); + memcpy(&packet_buf[5], &(u2f_hid->packet.payload[data_ptr]), len_cur); + furi_hal_hid_u2f_send_response(packet_buf, HID_U2F_PACKET_LEN); + seq_cnt++; + len_remain -= len_cur; + data_ptr += len_cur; + } +} + +static void u2f_hid_send_error(U2fHid* u2f_hid, uint8_t error) { + u2f_hid->packet.len = 1; + u2f_hid->packet.cmd = U2F_HID_ERROR; + u2f_hid->packet.payload[0] = error; + u2f_hid_send_response(u2f_hid); +} + +static bool u2f_hid_parse_request(U2fHid* u2f_hid) { + FURI_LOG_I( + WORKER_TAG, + "Req cid=%lX cmd=%x len=%u", + u2f_hid->packet.cid, + u2f_hid->packet.cmd, + u2f_hid->packet.len); + + if(u2f_hid->packet.cmd == U2F_HID_PING) { // PING - echo request back + u2f_hid_send_response(u2f_hid); + + } else if(u2f_hid->packet.cmd == U2F_HID_MSG) { // MSG - U2F message + if((u2f_hid->lock == true) && (u2f_hid->packet.cid != u2f_hid->lock_cid)) return false; + uint16_t resp_len = + u2f_msg_parse(u2f_hid->u2f_instance, u2f_hid->packet.payload, u2f_hid->packet.len); + if(resp_len > 0) { + u2f_hid->packet.len = resp_len; + u2f_hid_send_response(u2f_hid); + } else + return false; + + } else if(u2f_hid->packet.cmd == U2F_HID_LOCK) { // LOCK - lock all channels except current + if(u2f_hid->packet.len != 1) return false; + uint8_t lock_timeout = u2f_hid->packet.payload[0]; + if(lock_timeout == 0) { // Lock off + u2f_hid->lock = false; + u2f_hid->lock_cid = 0; + } else { // Lock on + u2f_hid->lock = true; + u2f_hid->lock_cid = u2f_hid->packet.cid; + osTimerStart(u2f_hid->lock_timer, lock_timeout * 1000); + } + + } else if(u2f_hid->packet.cmd == U2F_HID_INIT) { // INIT - channel initialization request + if((u2f_hid->packet.len != 8) || (u2f_hid->packet.cid != U2F_HID_BROADCAST_CID) || + (u2f_hid->lock == true)) + return false; + u2f_hid->packet.len = 17; + uint32_t random_cid = furi_hal_random_get(); + memcpy(&(u2f_hid->packet.payload[8]), &random_cid, 4); + u2f_hid->packet.payload[12] = 2; // Protocol version + u2f_hid->packet.payload[13] = 1; // Device version major + u2f_hid->packet.payload[14] = 0; // Device version minor + u2f_hid->packet.payload[15] = 1; // Device build version + u2f_hid->packet.payload[16] = 1; // Capabilities: wink + u2f_hid_send_response(u2f_hid); + + } else if(u2f_hid->packet.cmd == U2F_HID_WINK) { // WINK - notify user + if(u2f_hid->packet.len != 0) return false; + u2f_wink(u2f_hid->u2f_instance); + u2f_hid->packet.len = 0; + u2f_hid_send_response(u2f_hid); + } else + return false; + return true; +} + +static int32_t u2f_hid_worker(void* context) { + U2fHid* u2f_hid = context; + uint8_t packet_buf[HID_U2F_PACKET_LEN]; + + FURI_LOG_I(WORKER_TAG, "Init"); + + UsbInterface* usb_mode_prev = furi_hal_usb_get_config(); + furi_hal_usb_set_config(&usb_hid_u2f); + + u2f_hid->lock_timer = osTimerNew(u2f_hid_lock_timeout_callback, osTimerOnce, u2f_hid, NULL); + + furi_hal_hid_u2f_set_callback(u2f_hid_event_callback, u2f_hid); + + while(1) { + uint32_t flags = osThreadFlagsWait( + WorkerEvtStop | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtRequest, + osFlagsWaitAny, + osWaitForever); + furi_check((flags & osFlagsError) == 0); + if(flags & WorkerEvtStop) break; + if(flags & WorkerEvtConnect) FURI_LOG_I(WORKER_TAG, "Connect"); + if(flags & WorkerEvtDisconnect) FURI_LOG_I(WORKER_TAG, "Disconnect"); + if(flags & WorkerEvtRequest) { + uint32_t len_cur = furi_hal_hid_u2f_get_request(packet_buf); + if(len_cur > 0) { + if((packet_buf[4] & U2F_HID_TYPE_MASK) == U2F_HID_TYPE_INIT) { + // Init packet + u2f_hid->packet.len = (packet_buf[5] << 8) | (packet_buf[6]); + if(u2f_hid->packet.len > (len_cur - 7)) { + u2f_hid->req_len_left = u2f_hid->packet.len - (len_cur - 7); + len_cur = len_cur - 7; + } else { + u2f_hid->req_len_left = 0; + len_cur = u2f_hid->packet.len; + } + memcpy(&(u2f_hid->packet.cid), packet_buf, 4); + u2f_hid->packet.cmd = packet_buf[4]; + u2f_hid->seq_id_last = 0; + u2f_hid->req_buf_ptr = len_cur; + if(len_cur > 0) memcpy(u2f_hid->packet.payload, &packet_buf[7], len_cur); + } else { + // Continuation packet + if(u2f_hid->req_len_left > 0) { + uint32_t cid_temp = 0; + memcpy(&cid_temp, packet_buf, 4); + uint8_t seq_temp = packet_buf[4]; + if((cid_temp == u2f_hid->packet.cid) && + (seq_temp == u2f_hid->seq_id_last)) { + if(u2f_hid->req_len_left > (len_cur - 5)) { + len_cur = len_cur - 5; + u2f_hid->req_len_left -= len_cur; + } else { + len_cur = u2f_hid->req_len_left; + u2f_hid->req_len_left = 0; + } + memcpy( + &(u2f_hid->packet.payload[u2f_hid->req_buf_ptr]), + &packet_buf[5], + len_cur); + u2f_hid->req_buf_ptr += len_cur; + u2f_hid->seq_id_last++; + } + } + } + if(u2f_hid->req_len_left == 0) { + if(u2f_hid_parse_request(u2f_hid) == false) { + u2f_hid_send_error(u2f_hid, U2F_HID_ERR_INVALID_CMD); + } + } + } + } + if(flags & WorkerEvtUnlock) { + u2f_hid->lock = false; + u2f_hid->lock_cid = 0; + } + } + osTimerStop(u2f_hid->lock_timer); + osTimerDelete(u2f_hid->lock_timer); + + furi_hal_hid_u2f_set_callback(NULL, NULL); + furi_hal_usb_set_config(usb_mode_prev); + FURI_LOG_I(WORKER_TAG, "End"); + + return 0; +} + +U2fHid* u2f_hid_start(U2fData* u2f_inst) { + U2fHid* u2f_hid = furi_alloc(sizeof(U2fHid)); + + u2f_hid->u2f_instance = u2f_inst; + + u2f_hid->thread = furi_thread_alloc(); + furi_thread_set_name(u2f_hid->thread, "U2fHidWorker"); + furi_thread_set_stack_size(u2f_hid->thread, 2048); + furi_thread_set_context(u2f_hid->thread, u2f_hid); + furi_thread_set_callback(u2f_hid->thread, u2f_hid_worker); + furi_thread_start(u2f_hid->thread); + return u2f_hid; +} + +void u2f_hid_stop(U2fHid* u2f_hid) { + furi_assert(u2f_hid); + osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtStop); + furi_thread_join(u2f_hid->thread); + furi_thread_free(u2f_hid->thread); + free(u2f_hid); +} diff --git a/applications/u2f/u2f_hid.h b/applications/u2f/u2f_hid.h new file mode 100644 index 00000000..2b943007 --- /dev/null +++ b/applications/u2f/u2f_hid.h @@ -0,0 +1,18 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "u2f.h" + +typedef struct U2fHid U2fHid; + +U2fHid* u2f_hid_start(U2fData* u2f_inst); + +void u2f_hid_stop(U2fHid* u2f_hid); + +#ifdef __cplusplus +} +#endif diff --git a/applications/u2f/views/u2f_view.c b/applications/u2f/views/u2f_view.c new file mode 100644 index 00000000..b013638c --- /dev/null +++ b/applications/u2f/views/u2f_view.c @@ -0,0 +1,91 @@ +#include "u2f_view.h" +#include + +struct U2fView { + View* view; + U2fOkCallback callback; + void* context; +}; + +typedef struct { + U2fViewMsg display_msg; +} U2fModel; + +static void u2f_view_draw_callback(Canvas* canvas, void* _model) { + U2fModel* model = _model; + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "U2F Demo"); + + if(model->display_msg == U2fMsgRegister) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 0, 45, AlignLeft, AlignBottom, "Registration"); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 0, 63, AlignLeft, AlignBottom, "Press [OK] to confirm"); + } else if(model->display_msg == U2fMsgAuth) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 0, 45, AlignLeft, AlignBottom, "Authentication"); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 0, 63, AlignLeft, AlignBottom, "Press [OK] to confirm"); + } else if(model->display_msg == U2fMsgError) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignCenter, "U2F data missing"); + } +} + +static bool u2f_view_input_callback(InputEvent* event, void* context) { + furi_assert(context); + U2fView* u2f = context; + bool consumed = false; + + if(event->type == InputTypeShort) { + if(event->key == InputKeyOk) { + consumed = true; + if(u2f->callback != NULL) u2f->callback(InputTypeShort, u2f->context); + } + } + + return consumed; +} + +U2fView* u2f_view_alloc() { + U2fView* u2f = furi_alloc(sizeof(U2fView)); + + u2f->view = view_alloc(); + view_allocate_model(u2f->view, ViewModelTypeLocking, sizeof(U2fModel)); + view_set_context(u2f->view, u2f); + view_set_draw_callback(u2f->view, u2f_view_draw_callback); + view_set_input_callback(u2f->view, u2f_view_input_callback); + + return u2f; +} + +void u2f_view_free(U2fView* u2f) { + furi_assert(u2f); + view_free(u2f->view); + free(u2f); +} + +View* u2f_view_get_view(U2fView* u2f) { + furi_assert(u2f); + return u2f->view; +} + +void u2f_view_set_ok_callback(U2fView* u2f, U2fOkCallback callback, void* context) { + furi_assert(u2f); + furi_assert(callback); + with_view_model( + u2f->view, (U2fModel * model) { + u2f->callback = callback; + u2f->context = context; + return false; + }); +} + +void u2f_view_set_state(U2fView* u2f, U2fViewMsg msg) { + with_view_model( + u2f->view, (U2fModel * model) { + model->display_msg = msg; + return false; + }); +} diff --git a/applications/u2f/views/u2f_view.h b/applications/u2f/views/u2f_view.h new file mode 100644 index 00000000..a222fbc3 --- /dev/null +++ b/applications/u2f/views/u2f_view.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +typedef struct U2fView U2fView; +typedef void (*U2fOkCallback)(InputType type, void* context); + +typedef enum { + U2fMsgNone, + U2fMsgRegister, + U2fMsgAuth, + U2fMsgError, +} U2fViewMsg; + +U2fView* u2f_view_alloc(); + +void u2f_view_free(U2fView* u2f); + +View* u2f_view_get_view(U2fView* u2f); + +void u2f_view_set_ok_callback(U2fView* u2f, U2fOkCallback callback, void* context); + +void u2f_view_set_state(U2fView* u2f, U2fViewMsg msg); diff --git a/assets/resources/u2f/cert.der b/assets/resources/u2f/cert.der new file mode 100644 index 0000000000000000000000000000000000000000..73efb2312aa371701727360ebc77f83b97398f45 GIT binary patch literal 365 zcmXqLV$3vXV&q@I%*4pVB$B%9}O^V1_M_nMTQUM+?ocy%TEdJkZpFGm7KV-N?oI} y$%aQwLi>!a=KcRn3WcTL)b;q>H|f7=e6AuRrZ2~>UZZFuXu>I_r!bW{uowV;ZE3dv literal 0 HcmV?d00001 diff --git a/assets/resources/u2f/cert_key.u2f b/assets/resources/u2f/cert_key.u2f new file mode 100644 index 00000000..116d1411 --- /dev/null +++ b/assets/resources/u2f/cert_key.u2f @@ -0,0 +1,5 @@ +Filetype: Flipper U2F Certificate Key File +Version: 1 +Type: 0 +IV: E1 56 CE 83 98 FA 59 0D 45 EC 1C EB 34 FC 08 C9 +Data: E1 8C C9 9A 98 F7 B9 50 1E 85 71 8F A4 CE 76 95 87 4F AC 8B 5E D0 1F 13 BA 3B 2E E7 98 73 54 64 58 0A 00 20 55 B8 00 08 58 0A 00 20 50 4E 01 20 diff --git a/firmware/targets/f6/furi-hal/furi-hal-crypto.c b/firmware/targets/f6/furi-hal/furi-hal-crypto.c index 91875d23..f5398421 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-crypto.c +++ b/firmware/targets/f6/furi-hal/furi-hal-crypto.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -7,10 +8,119 @@ CRYP_HandleTypeDef crypt; +#define ENCLAVE_FACTORY_KEY_SLOTS 10 +#define ENCLAVE_SIGNATURE_SIZE 16 + +static const uint8_t enclave_signature_iv[ENCLAVE_FACTORY_KEY_SLOTS][16] = { + {0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a}, + {0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf}, + {0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd}, + {0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9}, + {0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7}, + {0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44}, + {0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d}, + {0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b}, + {0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8}, + {0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e}, +}; + +static const uint8_t enclave_signature_input[ENCLAVE_FACTORY_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { + {0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde}, + {0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54}, + {0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75}, + {0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf}, + {0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b}, + {0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18}, + {0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f}, + {0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b}, + {0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a}, + {0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90}, +}; + +static const uint8_t enclave_signature_expected[ENCLAVE_FACTORY_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { + {0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67}, + {0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e}, + {0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd}, + {0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0}, + {0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb}, + {0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41}, + {0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b}, + {0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b}, + {0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31}, + {0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32}, +}; + void furi_hal_crypto_init() { FURI_LOG_I(TAG, "Init OK"); } +static bool furi_hal_crypto_generate_unique_keys(uint8_t start_slot, uint8_t end_slot) { + FuriHalCryptoKey key; + uint8_t key_data[32]; + FURI_LOG_I(TAG, "Generating keys %u..%u", start_slot, end_slot); + for (uint8_t slot = start_slot; slot <= end_slot; slot++) { + key.type = FuriHalCryptoKeyTypeSimple; + key.size = FuriHalCryptoKeySize256; + key.data = key_data; + furi_hal_random_fill_buf(key_data, 32); + if (!furi_hal_crypto_store_add_key(&key, &slot)) { + FURI_LOG_E(TAG, "Error writing key to slot %u", slot); + return false; + } + } + return true; +} + +bool furi_hal_crypto_verify_key(uint8_t key_slot) { + uint8_t keys_nb = 0; + uint8_t valid_keys_nb = 0; + uint8_t last_valid_slot = ENCLAVE_FACTORY_KEY_SLOTS; + uint8_t empty_iv[16]; + furi_hal_crypto_verify_enclave(&keys_nb, &valid_keys_nb); + if (key_slot <= ENCLAVE_FACTORY_KEY_SLOTS) { // It's a factory key + if (key_slot > keys_nb) + return false; + } else { // Unique key + if (keys_nb < ENCLAVE_FACTORY_KEY_SLOTS) // Some factory keys are missing + return false; + for (uint8_t i = key_slot; i > ENCLAVE_FACTORY_KEY_SLOTS; i--) { + if(furi_hal_crypto_store_load_key(i, empty_iv)) { + last_valid_slot = i; + furi_hal_crypto_store_unload_key(i); + break; + } + } + if (last_valid_slot == key_slot) + return true; + else // Generate missing unique keys + return furi_hal_crypto_generate_unique_keys(last_valid_slot+1, key_slot); + } + return true; +} + +bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb) { + furi_assert(keys_nb); + furi_assert(valid_keys_nb); + uint8_t keys = 0; + uint8_t keys_valid = 0; + uint8_t buffer[ENCLAVE_SIGNATURE_SIZE]; + for(size_t key_slot = 0; key_slot < ENCLAVE_FACTORY_KEY_SLOTS; key_slot++) { + if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) { + keys++; + if(furi_hal_crypto_encrypt(enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) { + keys_valid += memcmp(buffer, enclave_signature_expected[key_slot], ENCLAVE_SIGNATURE_SIZE) == 0; + } + furi_hal_crypto_store_unload_key(key_slot + 1); + } + } + *keys_nb = keys; + *valid_keys_nb = keys_valid; + if (*valid_keys_nb == ENCLAVE_FACTORY_KEY_SLOTS) + return true; + else + return false; +} + bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { furi_assert(key); furi_assert(slot); diff --git a/firmware/targets/f6/furi-hal/furi-hal-info.c b/firmware/targets/f6/furi-hal/furi-hal-info.c index 783a5113..c1225ac9 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-info.c +++ b/firmware/targets/f6/furi-hal/furi-hal-info.c @@ -2,48 +2,6 @@ #include #include -#define ENCLAVE_SIGNATURE_KEY_SLOTS 10 -#define ENCLAVE_SIGNATURE_SIZE 16 - -static const uint8_t enclave_signature_iv[ENCLAVE_SIGNATURE_KEY_SLOTS][16] = { - {0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a}, - {0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf}, - {0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd}, - {0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9}, - {0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7}, - {0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44}, - {0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d}, - {0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b}, - {0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8}, - {0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e}, -}; - -static const uint8_t enclave_signature_input[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { - {0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde}, - {0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54}, - {0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75}, - {0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf}, - {0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b}, - {0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18}, - {0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f}, - {0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b}, - {0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a}, - {0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90}, -}; - -static const uint8_t enclave_signature_expected[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { - {0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67}, - {0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e}, - {0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd}, - {0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0}, - {0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb}, - {0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41}, - {0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b}, - {0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b}, - {0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31}, - {0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32}, -}; - void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { string_t value; string_init(value); @@ -164,23 +122,12 @@ void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { out("radio_ble_mac", string_get_cstr(value), false, context); // Signature verification - uint8_t buffer[ENCLAVE_SIGNATURE_SIZE]; - size_t enclave_valid_keys = 0; - for(size_t key_slot = 0; key_slot < ENCLAVE_SIGNATURE_KEY_SLOTS; key_slot++) { - if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) { - if(furi_hal_crypto_encrypt( - enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) { - enclave_valid_keys += memcmp( - buffer, - enclave_signature_expected[key_slot], - ENCLAVE_SIGNATURE_SIZE) == 0; - } - furi_hal_crypto_store_unload_key(key_slot + 1); - } - } + uint8_t enclave_keys = 0; + uint8_t enclave_valid_keys = 0; + bool enclave_valid = furi_hal_crypto_verify_enclave(&enclave_keys, &enclave_valid_keys); string_printf(value, "%d", enclave_valid_keys); out("enclave_valid_keys", string_get_cstr(value), false, context); - out("enclave_valid", (enclave_valid_keys == ENCLAVE_SIGNATURE_KEY_SLOTS) ? "true" : "false", true, context); + out("enclave_valid", enclave_valid ? "true" : "false", true, context); } else { out("radio_alive", "false", true, context); } diff --git a/firmware/targets/f6/furi-hal/furi-hal-random.c b/firmware/targets/f6/furi-hal/furi-hal-random.c new file mode 100644 index 00000000..a7bc3a31 --- /dev/null +++ b/firmware/targets/f6/furi-hal/furi-hal-random.c @@ -0,0 +1,56 @@ +#include "furi-hal-random.h" +#include +#include + +#include +#include + +#include + +uint32_t furi_hal_random_get() { + + while( LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)); + LL_RNG_Enable(RNG); + + while (!LL_RNG_IsActiveFlag_DRDY(RNG)); + + if ((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { + furi_crash("TRNG error"); + } + + uint32_t random_val = LL_RNG_ReadRandData32(RNG); + + LL_RNG_Disable(RNG); + LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); + + return random_val; +} + +void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) { + + while( LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)); + LL_RNG_Enable(RNG); + + for (uint32_t i = 0; i < len; i+= 4) { + while (!LL_RNG_IsActiveFlag_DRDY(RNG)); + + if ((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { + furi_crash("TRNG error"); + } + + uint32_t random_val = LL_RNG_ReadRandData32(RNG); + + uint8_t len_cur = ((i+4) < len) ? (4) : (len-i); + memcpy(&buf[i], &random_val, len_cur); + } + + LL_RNG_Disable(RNG); + LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); +} + +void srand(unsigned seed) { +} + +int rand() { + return (furi_hal_random_get() & RAND_MAX); +} diff --git a/firmware/targets/f6/furi-hal/furi-hal-usb-u2f.c b/firmware/targets/f6/furi-hal/furi-hal-usb-u2f.c new file mode 100644 index 00000000..a7426c82 --- /dev/null +++ b/firmware/targets/f6/furi-hal/furi-hal-usb-u2f.c @@ -0,0 +1,309 @@ +#include "furi-hal-version.h" +#include "furi-hal-usb_i.h" +#include "furi-hal-usb-hid-u2f.h" +#include "furi-hal-usb.h" +#include +#include "usb.h" +#include "usb_hid.h" + +#define HID_PAGE_FIDO 0xF1D0 +#define HID_FIDO_U2F 0x01 +#define HID_FIDO_INPUT 0x20 +#define HID_FIDO_OUTPUT 0x21 + +#define HID_EP_IN 0x81 +#define HID_EP_OUT 0x01 + +struct HidIadDescriptor { + struct usb_iad_descriptor hid_iad; + struct usb_interface_descriptor hid; + struct usb_hid_descriptor hid_desc; + struct usb_endpoint_descriptor hid_ep_in; + struct usb_endpoint_descriptor hid_ep_out; +}; + +struct HidConfigDescriptor { + struct usb_config_descriptor config; + struct HidIadDescriptor iad_0; +} __attribute__((packed)); + +/* HID report: FIDO U2F */ +static const uint8_t hid_u2f_report_desc[] = { + HID_RI_USAGE_PAGE(16, HID_PAGE_FIDO), + HID_USAGE(HID_FIDO_U2F), + HID_COLLECTION(HID_APPLICATION_COLLECTION), + HID_USAGE(HID_FIDO_INPUT), + HID_LOGICAL_MINIMUM(0x00), + HID_LOGICAL_MAXIMUM(0xFF), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(HID_U2F_PACKET_LEN), + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_USAGE(HID_FIDO_OUTPUT), + HID_LOGICAL_MINIMUM(0x00), + HID_LOGICAL_MAXIMUM(0xFF), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(HID_U2F_PACKET_LEN), + HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_END_COLLECTION, +}; + +static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); +static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("U2F Token test"); +static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("TODO: serial"); + +/* Device descriptor */ +static const struct usb_device_descriptor hid_u2f_device_desc = { + .bLength = sizeof(struct usb_device_descriptor), + .bDescriptorType = USB_DTYPE_DEVICE, + .bcdUSB = VERSION_BCD(2, 0, 0), + .bDeviceClass = USB_CLASS_IAD, + .bDeviceSubClass = USB_SUBCLASS_IAD, + .bDeviceProtocol = USB_PROTO_IAD, + .bMaxPacketSize0 = USB_EP0_SIZE, + .idVendor = 0x0483, + .idProduct = 0x5741, + .bcdDevice = VERSION_BCD(1, 0, 0), + .iManufacturer = UsbDevManuf, + .iProduct = UsbDevProduct, + .iSerialNumber = UsbDevSerial, + .bNumConfigurations = 1, +}; + +/* Device configuration descriptor */ +static const struct HidConfigDescriptor hid_u2f_cfg_desc = { + .config = + { + .bLength = sizeof(struct usb_config_descriptor), + .bDescriptorType = USB_DTYPE_CONFIGURATION, + .wTotalLength = sizeof(struct HidConfigDescriptor), + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = NO_DESCRIPTOR, + .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, + .bMaxPower = USB_CFG_POWER_MA(100), + }, + .iad_0 = + { + .hid_iad = + { + .bLength = sizeof(struct usb_iad_descriptor), + .bDescriptorType = USB_DTYPE_INTERFASEASSOC, + .bFirstInterface = 0, + .bInterfaceCount = 1, + .bFunctionClass = USB_CLASS_PER_INTERFACE, + .bFunctionSubClass = USB_SUBCLASS_NONE, + .bFunctionProtocol = USB_PROTO_NONE, + .iFunction = NO_DESCRIPTOR, + }, + .hid = + { + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DTYPE_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = USB_HID_SUBCLASS_NONBOOT, + .bInterfaceProtocol = USB_HID_PROTO_NONBOOT, + .iInterface = NO_DESCRIPTOR, + }, + .hid_desc = + { + .bLength = sizeof(struct usb_hid_descriptor), + .bDescriptorType = USB_DTYPE_HID, + .bcdHID = VERSION_BCD(1, 0, 0), + .bCountryCode = USB_HID_COUNTRY_NONE, + .bNumDescriptors = 1, + .bDescriptorType0 = USB_DTYPE_HID_REPORT, + .wDescriptorLength0 = sizeof(hid_u2f_report_desc), + }, + .hid_ep_in = + { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DTYPE_ENDPOINT, + .bEndpointAddress = HID_EP_IN, + .bmAttributes = USB_EPTYPE_INTERRUPT, + .wMaxPacketSize = HID_U2F_PACKET_LEN, + .bInterval = 5, + }, + .hid_ep_out = + { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DTYPE_ENDPOINT, + .bEndpointAddress = HID_EP_OUT, + .bmAttributes = USB_EPTYPE_INTERRUPT, + .wMaxPacketSize = HID_U2F_PACKET_LEN, + .bInterval = 5, + }, + }, +}; + +static void hid_u2f_init(usbd_device* dev, UsbInterface* intf); +static void hid_u2f_deinit(usbd_device* dev); +static void hid_u2f_on_wakeup(usbd_device* dev); +static void hid_u2f_on_suspend(usbd_device* dev); + +//static bool hid_u2f_send_report(uint8_t report_id); +static usbd_respond hid_u2f_ep_config(usbd_device* dev, uint8_t cfg); +static usbd_respond + hid_u2f_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback); +static usbd_device* usb_dev; +static osSemaphoreId_t hid_u2f_semaphore = NULL; +static bool hid_u2f_connected = false; + +static HidU2fCallback callback; +static void* cb_ctx; + +bool furi_hal_hid_u2f_is_connected() { + return hid_u2f_connected; +} + +void furi_hal_hid_u2f_set_callback(HidU2fCallback cb, void* ctx) { + if (callback != NULL) { + if (hid_u2f_connected == true) + callback(HidU2fDisconnected, cb_ctx); + } + + callback = cb; + cb_ctx = ctx; + + if (callback != NULL) { + if (hid_u2f_connected == true) + callback(HidU2fConnected, cb_ctx); + } +} + +UsbInterface usb_hid_u2f = { + .init = hid_u2f_init, + .deinit = hid_u2f_deinit, + .wakeup = hid_u2f_on_wakeup, + .suspend = hid_u2f_on_suspend, + + .dev_descr = (struct usb_device_descriptor*)&hid_u2f_device_desc, + + .str_manuf_descr = (void*)&dev_manuf_desc, + .str_prod_descr = (void*)&dev_prod_desc, + .str_serial_descr = (void*)&dev_serial_desc, + + .cfg_descr = (void*)&hid_u2f_cfg_desc, +}; + +static void hid_u2f_init(usbd_device* dev, UsbInterface* intf) { + if(hid_u2f_semaphore == NULL) hid_u2f_semaphore = osSemaphoreNew(1, 1, NULL); + usb_dev = dev; + + usbd_reg_config(dev, hid_u2f_ep_config); + usbd_reg_control(dev, hid_u2f_control); + + usbd_connect(dev, true); +} + +static void hid_u2f_deinit(usbd_device* dev) { + usbd_reg_config(dev, NULL); + usbd_reg_control(dev, NULL); +} + +static void hid_u2f_on_wakeup(usbd_device* dev) { + hid_u2f_connected = true; + if (callback != NULL) + callback(HidU2fConnected, cb_ctx); +} + +static void hid_u2f_on_suspend(usbd_device* dev) { + if(hid_u2f_connected == true) { + hid_u2f_connected = false; + osSemaphoreRelease(hid_u2f_semaphore); + if (callback != NULL) + callback(HidU2fDisconnected, cb_ctx); + } +} + +void furi_hal_hid_u2f_send_response(uint8_t* data, uint8_t len) { + if ((hid_u2f_semaphore == NULL) || (hid_u2f_connected == false)) + return; + furi_check(osSemaphoreAcquire(hid_u2f_semaphore, osWaitForever) == osOK); + if (hid_u2f_connected == true) { + usbd_ep_write(usb_dev, HID_EP_OUT, data, len); + } +} + +uint32_t furi_hal_hid_u2f_get_request(uint8_t* data) { + int32_t len = usbd_ep_read(usb_dev, HID_EP_IN, data, HID_U2F_PACKET_LEN); + return ((len < 0) ? 0 : len); +} + +static void hid_u2f_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { + if (callback != NULL) + callback(HidU2fRequest, cb_ctx); +} + +static void hid_u2f_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { + osSemaphoreRelease(hid_u2f_semaphore); +} + +static void hid_u2f_txrx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { + if (event == usbd_evt_eptx) { + hid_u2f_tx_ep_callback(dev, event, ep); + } else { + hid_u2f_rx_ep_callback(dev, event, ep); + } +} + +/* Configure endpoints */ +static usbd_respond hid_u2f_ep_config(usbd_device* dev, uint8_t cfg) { + switch(cfg) { + case 0: + /* deconfiguring device */ + usbd_ep_deconfig(dev, HID_EP_IN); + usbd_ep_deconfig(dev, HID_EP_OUT); + usbd_reg_endpoint(dev, HID_EP_IN, 0); + usbd_reg_endpoint(dev, HID_EP_OUT, 0); + return usbd_ack; + case 1: + /* configuring device */ + usbd_ep_config(dev, HID_EP_IN, USB_EPTYPE_INTERRUPT, HID_U2F_PACKET_LEN); + usbd_ep_config(dev, HID_EP_OUT, USB_EPTYPE_INTERRUPT, HID_U2F_PACKET_LEN); + usbd_reg_endpoint(dev, HID_EP_IN, hid_u2f_txrx_ep_callback); + usbd_reg_endpoint(dev, HID_EP_OUT, hid_u2f_txrx_ep_callback); + usbd_ep_write(dev, HID_U2F_PACKET_LEN, 0, 0); + return usbd_ack; + default: + return usbd_fail; + } +} + +/* Control requests handler */ +static usbd_respond hid_u2f_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) { + /* HID control requests */ + if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == + (USB_REQ_INTERFACE | USB_REQ_CLASS) && + req->wIndex == 0) { + switch(req->bRequest) { + case USB_HID_SETIDLE: + return usbd_ack; + case USB_HID_GETREPORT: + // dev->status.data_ptr = &hid_u2f_report; + // dev->status.data_count = sizeof(hid_u2f_report); + return usbd_ack; + default: + return usbd_fail; + } + } + if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == + (USB_REQ_INTERFACE | USB_REQ_STANDARD) && + req->wIndex == 0 && req->bRequest == USB_STD_GET_DESCRIPTOR) { + switch(req->wValue >> 8) { + case USB_DTYPE_HID: + dev->status.data_ptr = (uint8_t*)&(hid_u2f_cfg_desc.iad_0.hid_desc); + dev->status.data_count = sizeof(hid_u2f_cfg_desc.iad_0.hid_desc); + return usbd_ack; + case USB_DTYPE_HID_REPORT: + dev->status.data_ptr = (uint8_t*)hid_u2f_report_desc; + dev->status.data_count = sizeof(hid_u2f_report_desc); + return usbd_ack; + default: + return usbd_fail; + } + } + return usbd_fail; +} diff --git a/firmware/targets/f6/target.mk b/firmware/targets/f6/target.mk index 3b9ada6c..e60e375e 100644 --- a/firmware/targets/f6/target.mk +++ b/firmware/targets/f6/target.mk @@ -71,7 +71,8 @@ C_SOURCES += \ $(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_utils.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rng.c # FreeRTOS CFLAGS += \ diff --git a/firmware/targets/f7/furi-hal/furi-hal-crypto.c b/firmware/targets/f7/furi-hal/furi-hal-crypto.c index 91875d23..f5398421 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-crypto.c +++ b/firmware/targets/f7/furi-hal/furi-hal-crypto.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -7,10 +8,119 @@ CRYP_HandleTypeDef crypt; +#define ENCLAVE_FACTORY_KEY_SLOTS 10 +#define ENCLAVE_SIGNATURE_SIZE 16 + +static const uint8_t enclave_signature_iv[ENCLAVE_FACTORY_KEY_SLOTS][16] = { + {0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a}, + {0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf}, + {0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd}, + {0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9}, + {0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7}, + {0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44}, + {0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d}, + {0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b}, + {0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8}, + {0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e}, +}; + +static const uint8_t enclave_signature_input[ENCLAVE_FACTORY_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { + {0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde}, + {0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54}, + {0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75}, + {0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf}, + {0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b}, + {0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18}, + {0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f}, + {0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b}, + {0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a}, + {0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90}, +}; + +static const uint8_t enclave_signature_expected[ENCLAVE_FACTORY_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { + {0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67}, + {0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e}, + {0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd}, + {0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0}, + {0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb}, + {0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41}, + {0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b}, + {0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b}, + {0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31}, + {0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32}, +}; + void furi_hal_crypto_init() { FURI_LOG_I(TAG, "Init OK"); } +static bool furi_hal_crypto_generate_unique_keys(uint8_t start_slot, uint8_t end_slot) { + FuriHalCryptoKey key; + uint8_t key_data[32]; + FURI_LOG_I(TAG, "Generating keys %u..%u", start_slot, end_slot); + for (uint8_t slot = start_slot; slot <= end_slot; slot++) { + key.type = FuriHalCryptoKeyTypeSimple; + key.size = FuriHalCryptoKeySize256; + key.data = key_data; + furi_hal_random_fill_buf(key_data, 32); + if (!furi_hal_crypto_store_add_key(&key, &slot)) { + FURI_LOG_E(TAG, "Error writing key to slot %u", slot); + return false; + } + } + return true; +} + +bool furi_hal_crypto_verify_key(uint8_t key_slot) { + uint8_t keys_nb = 0; + uint8_t valid_keys_nb = 0; + uint8_t last_valid_slot = ENCLAVE_FACTORY_KEY_SLOTS; + uint8_t empty_iv[16]; + furi_hal_crypto_verify_enclave(&keys_nb, &valid_keys_nb); + if (key_slot <= ENCLAVE_FACTORY_KEY_SLOTS) { // It's a factory key + if (key_slot > keys_nb) + return false; + } else { // Unique key + if (keys_nb < ENCLAVE_FACTORY_KEY_SLOTS) // Some factory keys are missing + return false; + for (uint8_t i = key_slot; i > ENCLAVE_FACTORY_KEY_SLOTS; i--) { + if(furi_hal_crypto_store_load_key(i, empty_iv)) { + last_valid_slot = i; + furi_hal_crypto_store_unload_key(i); + break; + } + } + if (last_valid_slot == key_slot) + return true; + else // Generate missing unique keys + return furi_hal_crypto_generate_unique_keys(last_valid_slot+1, key_slot); + } + return true; +} + +bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb) { + furi_assert(keys_nb); + furi_assert(valid_keys_nb); + uint8_t keys = 0; + uint8_t keys_valid = 0; + uint8_t buffer[ENCLAVE_SIGNATURE_SIZE]; + for(size_t key_slot = 0; key_slot < ENCLAVE_FACTORY_KEY_SLOTS; key_slot++) { + if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) { + keys++; + if(furi_hal_crypto_encrypt(enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) { + keys_valid += memcmp(buffer, enclave_signature_expected[key_slot], ENCLAVE_SIGNATURE_SIZE) == 0; + } + furi_hal_crypto_store_unload_key(key_slot + 1); + } + } + *keys_nb = keys; + *valid_keys_nb = keys_valid; + if (*valid_keys_nb == ENCLAVE_FACTORY_KEY_SLOTS) + return true; + else + return false; +} + bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { furi_assert(key); furi_assert(slot); diff --git a/firmware/targets/f7/furi-hal/furi-hal-info.c b/firmware/targets/f7/furi-hal/furi-hal-info.c index 783a5113..c1225ac9 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-info.c +++ b/firmware/targets/f7/furi-hal/furi-hal-info.c @@ -2,48 +2,6 @@ #include #include -#define ENCLAVE_SIGNATURE_KEY_SLOTS 10 -#define ENCLAVE_SIGNATURE_SIZE 16 - -static const uint8_t enclave_signature_iv[ENCLAVE_SIGNATURE_KEY_SLOTS][16] = { - {0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a}, - {0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf}, - {0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd}, - {0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9}, - {0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7}, - {0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44}, - {0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d}, - {0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b}, - {0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8}, - {0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e}, -}; - -static const uint8_t enclave_signature_input[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { - {0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde}, - {0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54}, - {0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75}, - {0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf}, - {0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b}, - {0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18}, - {0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f}, - {0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b}, - {0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a}, - {0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90}, -}; - -static const uint8_t enclave_signature_expected[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { - {0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67}, - {0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e}, - {0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd}, - {0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0}, - {0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb}, - {0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41}, - {0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b}, - {0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b}, - {0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31}, - {0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32}, -}; - void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { string_t value; string_init(value); @@ -164,23 +122,12 @@ void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { out("radio_ble_mac", string_get_cstr(value), false, context); // Signature verification - uint8_t buffer[ENCLAVE_SIGNATURE_SIZE]; - size_t enclave_valid_keys = 0; - for(size_t key_slot = 0; key_slot < ENCLAVE_SIGNATURE_KEY_SLOTS; key_slot++) { - if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) { - if(furi_hal_crypto_encrypt( - enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) { - enclave_valid_keys += memcmp( - buffer, - enclave_signature_expected[key_slot], - ENCLAVE_SIGNATURE_SIZE) == 0; - } - furi_hal_crypto_store_unload_key(key_slot + 1); - } - } + uint8_t enclave_keys = 0; + uint8_t enclave_valid_keys = 0; + bool enclave_valid = furi_hal_crypto_verify_enclave(&enclave_keys, &enclave_valid_keys); string_printf(value, "%d", enclave_valid_keys); out("enclave_valid_keys", string_get_cstr(value), false, context); - out("enclave_valid", (enclave_valid_keys == ENCLAVE_SIGNATURE_KEY_SLOTS) ? "true" : "false", true, context); + out("enclave_valid", enclave_valid ? "true" : "false", true, context); } else { out("radio_alive", "false", true, context); } diff --git a/firmware/targets/f7/furi-hal/furi-hal-random.c b/firmware/targets/f7/furi-hal/furi-hal-random.c new file mode 100644 index 00000000..a7bc3a31 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-random.c @@ -0,0 +1,56 @@ +#include "furi-hal-random.h" +#include +#include + +#include +#include + +#include + +uint32_t furi_hal_random_get() { + + while( LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)); + LL_RNG_Enable(RNG); + + while (!LL_RNG_IsActiveFlag_DRDY(RNG)); + + if ((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { + furi_crash("TRNG error"); + } + + uint32_t random_val = LL_RNG_ReadRandData32(RNG); + + LL_RNG_Disable(RNG); + LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); + + return random_val; +} + +void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) { + + while( LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)); + LL_RNG_Enable(RNG); + + for (uint32_t i = 0; i < len; i+= 4) { + while (!LL_RNG_IsActiveFlag_DRDY(RNG)); + + if ((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { + furi_crash("TRNG error"); + } + + uint32_t random_val = LL_RNG_ReadRandData32(RNG); + + uint8_t len_cur = ((i+4) < len) ? (4) : (len-i); + memcpy(&buf[i], &random_val, len_cur); + } + + LL_RNG_Disable(RNG); + LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); +} + +void srand(unsigned seed) { +} + +int rand() { + return (furi_hal_random_get() & RAND_MAX); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-usb-u2f.c b/firmware/targets/f7/furi-hal/furi-hal-usb-u2f.c new file mode 100644 index 00000000..a7426c82 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-usb-u2f.c @@ -0,0 +1,309 @@ +#include "furi-hal-version.h" +#include "furi-hal-usb_i.h" +#include "furi-hal-usb-hid-u2f.h" +#include "furi-hal-usb.h" +#include +#include "usb.h" +#include "usb_hid.h" + +#define HID_PAGE_FIDO 0xF1D0 +#define HID_FIDO_U2F 0x01 +#define HID_FIDO_INPUT 0x20 +#define HID_FIDO_OUTPUT 0x21 + +#define HID_EP_IN 0x81 +#define HID_EP_OUT 0x01 + +struct HidIadDescriptor { + struct usb_iad_descriptor hid_iad; + struct usb_interface_descriptor hid; + struct usb_hid_descriptor hid_desc; + struct usb_endpoint_descriptor hid_ep_in; + struct usb_endpoint_descriptor hid_ep_out; +}; + +struct HidConfigDescriptor { + struct usb_config_descriptor config; + struct HidIadDescriptor iad_0; +} __attribute__((packed)); + +/* HID report: FIDO U2F */ +static const uint8_t hid_u2f_report_desc[] = { + HID_RI_USAGE_PAGE(16, HID_PAGE_FIDO), + HID_USAGE(HID_FIDO_U2F), + HID_COLLECTION(HID_APPLICATION_COLLECTION), + HID_USAGE(HID_FIDO_INPUT), + HID_LOGICAL_MINIMUM(0x00), + HID_LOGICAL_MAXIMUM(0xFF), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(HID_U2F_PACKET_LEN), + HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_USAGE(HID_FIDO_OUTPUT), + HID_LOGICAL_MINIMUM(0x00), + HID_LOGICAL_MAXIMUM(0xFF), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(HID_U2F_PACKET_LEN), + HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_END_COLLECTION, +}; + +static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); +static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("U2F Token test"); +static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("TODO: serial"); + +/* Device descriptor */ +static const struct usb_device_descriptor hid_u2f_device_desc = { + .bLength = sizeof(struct usb_device_descriptor), + .bDescriptorType = USB_DTYPE_DEVICE, + .bcdUSB = VERSION_BCD(2, 0, 0), + .bDeviceClass = USB_CLASS_IAD, + .bDeviceSubClass = USB_SUBCLASS_IAD, + .bDeviceProtocol = USB_PROTO_IAD, + .bMaxPacketSize0 = USB_EP0_SIZE, + .idVendor = 0x0483, + .idProduct = 0x5741, + .bcdDevice = VERSION_BCD(1, 0, 0), + .iManufacturer = UsbDevManuf, + .iProduct = UsbDevProduct, + .iSerialNumber = UsbDevSerial, + .bNumConfigurations = 1, +}; + +/* Device configuration descriptor */ +static const struct HidConfigDescriptor hid_u2f_cfg_desc = { + .config = + { + .bLength = sizeof(struct usb_config_descriptor), + .bDescriptorType = USB_DTYPE_CONFIGURATION, + .wTotalLength = sizeof(struct HidConfigDescriptor), + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = NO_DESCRIPTOR, + .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, + .bMaxPower = USB_CFG_POWER_MA(100), + }, + .iad_0 = + { + .hid_iad = + { + .bLength = sizeof(struct usb_iad_descriptor), + .bDescriptorType = USB_DTYPE_INTERFASEASSOC, + .bFirstInterface = 0, + .bInterfaceCount = 1, + .bFunctionClass = USB_CLASS_PER_INTERFACE, + .bFunctionSubClass = USB_SUBCLASS_NONE, + .bFunctionProtocol = USB_PROTO_NONE, + .iFunction = NO_DESCRIPTOR, + }, + .hid = + { + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DTYPE_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = USB_HID_SUBCLASS_NONBOOT, + .bInterfaceProtocol = USB_HID_PROTO_NONBOOT, + .iInterface = NO_DESCRIPTOR, + }, + .hid_desc = + { + .bLength = sizeof(struct usb_hid_descriptor), + .bDescriptorType = USB_DTYPE_HID, + .bcdHID = VERSION_BCD(1, 0, 0), + .bCountryCode = USB_HID_COUNTRY_NONE, + .bNumDescriptors = 1, + .bDescriptorType0 = USB_DTYPE_HID_REPORT, + .wDescriptorLength0 = sizeof(hid_u2f_report_desc), + }, + .hid_ep_in = + { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DTYPE_ENDPOINT, + .bEndpointAddress = HID_EP_IN, + .bmAttributes = USB_EPTYPE_INTERRUPT, + .wMaxPacketSize = HID_U2F_PACKET_LEN, + .bInterval = 5, + }, + .hid_ep_out = + { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DTYPE_ENDPOINT, + .bEndpointAddress = HID_EP_OUT, + .bmAttributes = USB_EPTYPE_INTERRUPT, + .wMaxPacketSize = HID_U2F_PACKET_LEN, + .bInterval = 5, + }, + }, +}; + +static void hid_u2f_init(usbd_device* dev, UsbInterface* intf); +static void hid_u2f_deinit(usbd_device* dev); +static void hid_u2f_on_wakeup(usbd_device* dev); +static void hid_u2f_on_suspend(usbd_device* dev); + +//static bool hid_u2f_send_report(uint8_t report_id); +static usbd_respond hid_u2f_ep_config(usbd_device* dev, uint8_t cfg); +static usbd_respond + hid_u2f_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback); +static usbd_device* usb_dev; +static osSemaphoreId_t hid_u2f_semaphore = NULL; +static bool hid_u2f_connected = false; + +static HidU2fCallback callback; +static void* cb_ctx; + +bool furi_hal_hid_u2f_is_connected() { + return hid_u2f_connected; +} + +void furi_hal_hid_u2f_set_callback(HidU2fCallback cb, void* ctx) { + if (callback != NULL) { + if (hid_u2f_connected == true) + callback(HidU2fDisconnected, cb_ctx); + } + + callback = cb; + cb_ctx = ctx; + + if (callback != NULL) { + if (hid_u2f_connected == true) + callback(HidU2fConnected, cb_ctx); + } +} + +UsbInterface usb_hid_u2f = { + .init = hid_u2f_init, + .deinit = hid_u2f_deinit, + .wakeup = hid_u2f_on_wakeup, + .suspend = hid_u2f_on_suspend, + + .dev_descr = (struct usb_device_descriptor*)&hid_u2f_device_desc, + + .str_manuf_descr = (void*)&dev_manuf_desc, + .str_prod_descr = (void*)&dev_prod_desc, + .str_serial_descr = (void*)&dev_serial_desc, + + .cfg_descr = (void*)&hid_u2f_cfg_desc, +}; + +static void hid_u2f_init(usbd_device* dev, UsbInterface* intf) { + if(hid_u2f_semaphore == NULL) hid_u2f_semaphore = osSemaphoreNew(1, 1, NULL); + usb_dev = dev; + + usbd_reg_config(dev, hid_u2f_ep_config); + usbd_reg_control(dev, hid_u2f_control); + + usbd_connect(dev, true); +} + +static void hid_u2f_deinit(usbd_device* dev) { + usbd_reg_config(dev, NULL); + usbd_reg_control(dev, NULL); +} + +static void hid_u2f_on_wakeup(usbd_device* dev) { + hid_u2f_connected = true; + if (callback != NULL) + callback(HidU2fConnected, cb_ctx); +} + +static void hid_u2f_on_suspend(usbd_device* dev) { + if(hid_u2f_connected == true) { + hid_u2f_connected = false; + osSemaphoreRelease(hid_u2f_semaphore); + if (callback != NULL) + callback(HidU2fDisconnected, cb_ctx); + } +} + +void furi_hal_hid_u2f_send_response(uint8_t* data, uint8_t len) { + if ((hid_u2f_semaphore == NULL) || (hid_u2f_connected == false)) + return; + furi_check(osSemaphoreAcquire(hid_u2f_semaphore, osWaitForever) == osOK); + if (hid_u2f_connected == true) { + usbd_ep_write(usb_dev, HID_EP_OUT, data, len); + } +} + +uint32_t furi_hal_hid_u2f_get_request(uint8_t* data) { + int32_t len = usbd_ep_read(usb_dev, HID_EP_IN, data, HID_U2F_PACKET_LEN); + return ((len < 0) ? 0 : len); +} + +static void hid_u2f_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { + if (callback != NULL) + callback(HidU2fRequest, cb_ctx); +} + +static void hid_u2f_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { + osSemaphoreRelease(hid_u2f_semaphore); +} + +static void hid_u2f_txrx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { + if (event == usbd_evt_eptx) { + hid_u2f_tx_ep_callback(dev, event, ep); + } else { + hid_u2f_rx_ep_callback(dev, event, ep); + } +} + +/* Configure endpoints */ +static usbd_respond hid_u2f_ep_config(usbd_device* dev, uint8_t cfg) { + switch(cfg) { + case 0: + /* deconfiguring device */ + usbd_ep_deconfig(dev, HID_EP_IN); + usbd_ep_deconfig(dev, HID_EP_OUT); + usbd_reg_endpoint(dev, HID_EP_IN, 0); + usbd_reg_endpoint(dev, HID_EP_OUT, 0); + return usbd_ack; + case 1: + /* configuring device */ + usbd_ep_config(dev, HID_EP_IN, USB_EPTYPE_INTERRUPT, HID_U2F_PACKET_LEN); + usbd_ep_config(dev, HID_EP_OUT, USB_EPTYPE_INTERRUPT, HID_U2F_PACKET_LEN); + usbd_reg_endpoint(dev, HID_EP_IN, hid_u2f_txrx_ep_callback); + usbd_reg_endpoint(dev, HID_EP_OUT, hid_u2f_txrx_ep_callback); + usbd_ep_write(dev, HID_U2F_PACKET_LEN, 0, 0); + return usbd_ack; + default: + return usbd_fail; + } +} + +/* Control requests handler */ +static usbd_respond hid_u2f_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) { + /* HID control requests */ + if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == + (USB_REQ_INTERFACE | USB_REQ_CLASS) && + req->wIndex == 0) { + switch(req->bRequest) { + case USB_HID_SETIDLE: + return usbd_ack; + case USB_HID_GETREPORT: + // dev->status.data_ptr = &hid_u2f_report; + // dev->status.data_count = sizeof(hid_u2f_report); + return usbd_ack; + default: + return usbd_fail; + } + } + if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == + (USB_REQ_INTERFACE | USB_REQ_STANDARD) && + req->wIndex == 0 && req->bRequest == USB_STD_GET_DESCRIPTOR) { + switch(req->wValue >> 8) { + case USB_DTYPE_HID: + dev->status.data_ptr = (uint8_t*)&(hid_u2f_cfg_desc.iad_0.hid_desc); + dev->status.data_count = sizeof(hid_u2f_cfg_desc.iad_0.hid_desc); + return usbd_ack; + case USB_DTYPE_HID_REPORT: + dev->status.data_ptr = (uint8_t*)hid_u2f_report_desc; + dev->status.data_count = sizeof(hid_u2f_report_desc); + return usbd_ack; + default: + return usbd_fail; + } + } + return usbd_fail; +} diff --git a/firmware/targets/furi-hal-include/furi-hal-crypto.h b/firmware/targets/furi-hal-include/furi-hal-crypto.h index 482b3d7a..3aba2ede 100644 --- a/firmware/targets/furi-hal-include/furi-hal-crypto.h +++ b/firmware/targets/furi-hal-include/furi-hal-crypto.h @@ -32,6 +32,10 @@ typedef struct { */ void furi_hal_crypto_init(); +bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb); + +bool furi_hal_crypto_verify_key(uint8_t key_slot); + /** Store key in crypto storage * * @param key FuriHalCryptoKey to store. Only Master, Simple or diff --git a/firmware/targets/furi-hal-include/furi-hal-random.h b/firmware/targets/furi-hal-include/furi-hal-random.h new file mode 100644 index 00000000..fa549d23 --- /dev/null +++ b/firmware/targets/furi-hal-include/furi-hal-random.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Get random value + * + * @return random value + */ +uint32_t furi_hal_random_get(); + +/** Fill buffer with random data + * + * @param buf buffer pointer + * @param data buffer len + */ +void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/targets/furi-hal-include/furi-hal-usb-hid-u2f.h b/firmware/targets/furi-hal-include/furi-hal-usb-hid-u2f.h new file mode 100644 index 00000000..e9bf5765 --- /dev/null +++ b/firmware/targets/furi-hal-include/furi-hal-usb-hid-u2f.h @@ -0,0 +1,36 @@ +#pragma once + +#define HID_U2F_PACKET_LEN 64 + +typedef enum { + HidU2fDisconnected, + HidU2fConnected, + HidU2fRequest, +} HidU2fEvent; + +typedef void (*HidU2fCallback)(HidU2fEvent ev, void* context); + +/** Get HID U2F connection state + * + * @return true / false + */ +bool furi_hal_hid_u2f_is_connected(); + +/** Set HID U2F event callback + * + * @param cb callback + * @param ctx callback context + */ +void furi_hal_hid_u2f_set_callback(HidU2fCallback cb, void* ctx); + +/** Get received U2F HID packet + * + */ +uint32_t furi_hal_hid_u2f_get_request(uint8_t* data); + +/** Send U2F HID response packet + * + * @param data response data + * @param len packet length + */ +void furi_hal_hid_u2f_send_response(uint8_t* data, uint8_t len); diff --git a/firmware/targets/furi-hal-include/furi-hal-usb.h b/firmware/targets/furi-hal-include/furi-hal-usb.h index b11ddcf1..a384236b 100644 --- a/firmware/targets/furi-hal-include/furi-hal-usb.h +++ b/firmware/targets/furi-hal-include/furi-hal-usb.h @@ -23,6 +23,7 @@ struct UsbInterface { extern UsbInterface usb_cdc_single; extern UsbInterface usb_cdc_dual; extern UsbInterface usb_hid; +extern UsbInterface usb_hid_u2f; /** USB device low-level initialization */ diff --git a/firmware/targets/furi-hal-include/furi-hal.h b/firmware/targets/furi-hal-include/furi-hal.h index f7613625..e0885598 100644 --- a/firmware/targets/furi-hal-include/furi-hal.h +++ b/firmware/targets/furi-hal-include/furi-hal.h @@ -40,6 +40,7 @@ template struct STOP_EXTERNING_ME {}; #include "furi-hal-compress.h" #include "furi-hal-uart.h" #include "furi-hal-info.h" +#include "furi-hal-random.h" /** Init furi-hal */ void furi_hal_init(); diff --git a/lib/lib.mk b/lib/lib.mk index 98ae0d5f..23db841c 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -124,3 +124,7 @@ C_SOURCES += $(wildcard $(LIB_DIR)/heatshrink/*.c) # Toolbox CFLAGS += -I$(LIB_DIR)/flipper_file C_SOURCES += $(wildcard $(LIB_DIR)/flipper_file/*.c) + +# Micro-ECC +CFLAGS += -I$(LIB_DIR)/micro-ecc +C_SOURCES += $(wildcard $(LIB_DIR)/micro-ecc/*.c) diff --git a/lib/micro-ecc/LICENSE.txt b/lib/micro-ecc/LICENSE.txt new file mode 100644 index 00000000..ab099ae5 --- /dev/null +++ b/lib/micro-ecc/LICENSE.txt @@ -0,0 +1,21 @@ +Copyright (c) 2014, Kenneth MacKay +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/micro-ecc/README.md b/lib/micro-ecc/README.md new file mode 100644 index 00000000..111321bf --- /dev/null +++ b/lib/micro-ecc/README.md @@ -0,0 +1,41 @@ +micro-ecc +========== + +A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors. + +The static version of micro-ecc (ie, where the curve was selected at compile-time) can be found in the "static" branch. + +Features +-------- + + * Resistant to known side-channel attacks. + * Written in C, with optional GCC inline assembly for AVR, ARM and Thumb platforms. + * Supports 8, 32, and 64-bit architectures. + * Small code size. + * No dynamic memory allocation. + * Support for 5 standard curves: secp160r1, secp192r1, secp224r1, secp256r1, and secp256k1. + * BSD 2-clause license. + +Usage Notes +----------- +### Point Representation ### +Compressed points are represented in the standard format as defined in http://www.secg.org/sec1-v2.pdf; uncompressed points are represented in standard format, but without the `0x04` prefix. All functions except `uECC_decompress()` only accept uncompressed points; use `uECC_compress()` and `uECC_decompress()` to convert between compressed and uncompressed point representations. + +Private keys are represented in the standard format. + +### Using the Code ### + +I recommend just copying (or symlink) the uECC files into your project. Then just `#include "uECC.h"` to use the micro-ecc functions. + +For use with Arduino, you can use the Library Manager to download micro-ecc (**Sketch**=>**Include Library**=>**Manage Libraries**). You can then use uECC just like any other Arduino library (uECC should show up in the **Sketch**=>**Import Library** submenu). + +See uECC.h for documentation for each function. + +### Compilation Notes ### + + * Should compile with any C/C++ compiler that supports stdint.h (this includes Visual Studio 2013). + * If you want to change the defaults for any of the uECC compile-time options (such as `uECC_OPTIMIZATION_LEVEL`), you must change them in your Makefile or similar so that uECC.c is compiled with the desired values (ie, compile uECC.c with `-DuECC_OPTIMIZATION_LEVEL=3` or whatever). + * When compiling for a Thumb-1 platform, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). + * When compiling for an ARM/Thumb-2 platform with `uECC_OPTIMIZATION_LEVEL` >= 3, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). + * When compiling for AVR, you must have optimizations enabled (compile with `-O1` or higher). + * When building for Windows, you will need to link in the `advapi32.lib` system library. diff --git a/lib/micro-ecc/asm_arm.inc b/lib/micro-ecc/asm_arm.inc new file mode 100644 index 00000000..688fdc75 --- /dev/null +++ b/lib/micro-ecc/asm_arm.inc @@ -0,0 +1,820 @@ +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_ASM_ARM_H_ +#define _UECC_ASM_ARM_H_ + +#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) + #define uECC_MIN_WORDS 8 +#endif +#if uECC_SUPPORTS_secp224r1 + #undef uECC_MIN_WORDS + #define uECC_MIN_WORDS 7 +#endif +#if uECC_SUPPORTS_secp192r1 + #undef uECC_MIN_WORDS + #define uECC_MIN_WORDS 6 +#endif +#if uECC_SUPPORTS_secp160r1 + #undef uECC_MIN_WORDS + #define uECC_MIN_WORDS 5 +#endif + +#if (uECC_PLATFORM == uECC_arm_thumb) + #define REG_RW "+l" + #define REG_WRITE "=l" +#else + #define REG_RW "+r" + #define REG_WRITE "=r" +#endif + +#if (uECC_PLATFORM == uECC_arm_thumb || uECC_PLATFORM == uECC_arm_thumb2) + #define REG_RW_LO "+l" + #define REG_WRITE_LO "=l" +#else + #define REG_RW_LO "+r" + #define REG_WRITE_LO "=r" +#endif + +#if (uECC_PLATFORM == uECC_arm_thumb2) + #define RESUME_SYNTAX +#else + #define RESUME_SYNTAX ".syntax divided \n\t" +#endif + +#if (uECC_OPTIMIZATION_LEVEL >= 2) + +uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { +#if (uECC_MAX_WORDS != uECC_MIN_WORDS) + #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2) + uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1; + #else /* ARM */ + uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4; + #endif +#endif + uint32_t carry; + uint32_t left_word; + uint32_t right_word; + + __asm__ volatile ( + ".syntax unified \n\t" + "movs %[carry], #0 \n\t" + #if (uECC_MAX_WORDS != uECC_MIN_WORDS) + "adr %[left], 1f \n\t" + ".align 4 \n\t" + "adds %[jump], %[left] \n\t" + #endif + + "ldmia %[lptr]!, {%[left]} \n\t" + "ldmia %[rptr]!, {%[right]} \n\t" + "adds %[left], %[right] \n\t" + "stmia %[dptr]!, {%[left]} \n\t" + + #if (uECC_MAX_WORDS != uECC_MIN_WORDS) + "bx %[jump] \n\t" + #endif + "1: \n\t" + REPEAT(DEC(uECC_MAX_WORDS), + "ldmia %[lptr]!, {%[left]} \n\t" + "ldmia %[rptr]!, {%[right]} \n\t" + "adcs %[left], %[right] \n\t" + "stmia %[dptr]!, {%[left]} \n\t") + + "adcs %[carry], %[carry] \n\t" + RESUME_SYNTAX + : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right), + #if (uECC_MAX_WORDS != uECC_MIN_WORDS) + [jump] REG_RW_LO (jump), + #endif + [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word), + [right] REG_WRITE_LO (right_word) + : + : "cc", "memory" + ); + return carry; +} +#define asm_add 1 + +uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { +#if (uECC_MAX_WORDS != uECC_MIN_WORDS) + #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2) + uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1; + #else /* ARM */ + uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4; + #endif +#endif + uint32_t carry; + uint32_t left_word; + uint32_t right_word; + + __asm__ volatile ( + ".syntax unified \n\t" + "movs %[carry], #0 \n\t" + #if (uECC_MAX_WORDS != uECC_MIN_WORDS) + "adr %[left], 1f \n\t" + ".align 4 \n\t" + "adds %[jump], %[left] \n\t" + #endif + + "ldmia %[lptr]!, {%[left]} \n\t" + "ldmia %[rptr]!, {%[right]} \n\t" + "subs %[left], %[right] \n\t" + "stmia %[dptr]!, {%[left]} \n\t" + + #if (uECC_MAX_WORDS != uECC_MIN_WORDS) + "bx %[jump] \n\t" + #endif + "1: \n\t" + REPEAT(DEC(uECC_MAX_WORDS), + "ldmia %[lptr]!, {%[left]} \n\t" + "ldmia %[rptr]!, {%[right]} \n\t" + "sbcs %[left], %[right] \n\t" + "stmia %[dptr]!, {%[left]} \n\t") + + "adcs %[carry], %[carry] \n\t" + RESUME_SYNTAX + : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right), + #if (uECC_MAX_WORDS != uECC_MIN_WORDS) + [jump] REG_RW_LO (jump), + #endif + [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word), + [right] REG_WRITE_LO (right_word) + : + : "cc", "memory" + ); + return !carry; /* Note that on ARM, carry flag set means "no borrow" when subtracting + (for some reason...) */ +} +#define asm_sub 1 + +#endif /* (uECC_OPTIMIZATION_LEVEL >= 2) */ + +#if (uECC_OPTIMIZATION_LEVEL >= 3) + +#if (uECC_PLATFORM != uECC_arm_thumb) + +#if uECC_ARM_USE_UMAAL + #include "asm_arm_mult_square_umaal.inc" +#else + #include "asm_arm_mult_square.inc" +#endif + +#if (uECC_OPTIMIZATION_LEVEL == 3) + +uECC_VLI_API void uECC_vli_mult(uint32_t *result, + const uint32_t *left, + const uint32_t *right, + wordcount_t num_words) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + register const uint32_t *r2 __asm__("r2") = right; + register uint32_t r3 __asm__("r3") = num_words; + + __asm__ volatile ( + ".syntax unified \n\t" +#if (uECC_MIN_WORDS == 5) + FAST_MULT_ASM_5 + #if (uECC_MAX_WORDS > 5) + FAST_MULT_ASM_5_TO_6 + #endif + #if (uECC_MAX_WORDS > 6) + FAST_MULT_ASM_6_TO_7 + #endif + #if (uECC_MAX_WORDS > 7) + FAST_MULT_ASM_7_TO_8 + #endif +#elif (uECC_MIN_WORDS == 6) + FAST_MULT_ASM_6 + #if (uECC_MAX_WORDS > 6) + FAST_MULT_ASM_6_TO_7 + #endif + #if (uECC_MAX_WORDS > 7) + FAST_MULT_ASM_7_TO_8 + #endif +#elif (uECC_MIN_WORDS == 7) + FAST_MULT_ASM_7 + #if (uECC_MAX_WORDS > 7) + FAST_MULT_ASM_7_TO_8 + #endif +#elif (uECC_MIN_WORDS == 8) + FAST_MULT_ASM_8 +#endif + "1: \n\t" + RESUME_SYNTAX + : "+r" (r0), "+r" (r1), "+r" (r2) + : "r" (r3) + : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_mult 1 + +#if uECC_SQUARE_FUNC +uECC_VLI_API void uECC_vli_square(uECC_word_t *result, + const uECC_word_t *left, + wordcount_t num_words) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + register uint32_t r2 __asm__("r2") = num_words; + + __asm__ volatile ( + ".syntax unified \n\t" +#if (uECC_MIN_WORDS == 5) + FAST_SQUARE_ASM_5 + #if (uECC_MAX_WORDS > 5) + FAST_SQUARE_ASM_5_TO_6 + #endif + #if (uECC_MAX_WORDS > 6) + FAST_SQUARE_ASM_6_TO_7 + #endif + #if (uECC_MAX_WORDS > 7) + FAST_SQUARE_ASM_7_TO_8 + #endif +#elif (uECC_MIN_WORDS == 6) + FAST_SQUARE_ASM_6 + #if (uECC_MAX_WORDS > 6) + FAST_SQUARE_ASM_6_TO_7 + #endif + #if (uECC_MAX_WORDS > 7) + FAST_SQUARE_ASM_7_TO_8 + #endif +#elif (uECC_MIN_WORDS == 7) + FAST_SQUARE_ASM_7 + #if (uECC_MAX_WORDS > 7) + FAST_SQUARE_ASM_7_TO_8 + #endif +#elif (uECC_MIN_WORDS == 8) + FAST_SQUARE_ASM_8 +#endif + + "1: \n\t" + RESUME_SYNTAX + : "+r" (r0), "+r" (r1) + : "r" (r2) + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +} +#define asm_square 1 +#endif /* uECC_SQUARE_FUNC */ + +#else /* (uECC_OPTIMIZATION_LEVEL > 3) */ + +uECC_VLI_API void uECC_vli_mult(uint32_t *result, + const uint32_t *left, + const uint32_t *right, + wordcount_t num_words) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + register const uint32_t *r2 __asm__("r2") = right; + register uint32_t r3 __asm__("r3") = num_words; + +#if uECC_SUPPORTS_secp160r1 + if (num_words == 5) { + __asm__ volatile ( + ".syntax unified \n\t" + FAST_MULT_ASM_5 + RESUME_SYNTAX + : "+r" (r0), "+r" (r1), "+r" (r2) + : "r" (r3) + : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); + return; + } +#endif +#if uECC_SUPPORTS_secp192r1 + if (num_words == 6) { + __asm__ volatile ( + ".syntax unified \n\t" + FAST_MULT_ASM_6 + RESUME_SYNTAX + : "+r" (r0), "+r" (r1), "+r" (r2) + : "r" (r3) + : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); + return; + } +#endif +#if uECC_SUPPORTS_secp224r1 + if (num_words == 7) { + __asm__ volatile ( + ".syntax unified \n\t" + FAST_MULT_ASM_7 + RESUME_SYNTAX + : "+r" (r0), "+r" (r1), "+r" (r2) + : "r" (r3) + : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); + return; + } +#endif +#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) + if (num_words == 8) { + __asm__ volatile ( + ".syntax unified \n\t" + FAST_MULT_ASM_8 + RESUME_SYNTAX + : "+r" (r0), "+r" (r1), "+r" (r2) + : "r" (r3) + : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); + return; + } +#endif +} +#define asm_mult 1 + +#if uECC_SQUARE_FUNC +uECC_VLI_API void uECC_vli_square(uECC_word_t *result, + const uECC_word_t *left, + wordcount_t num_words) { + register uint32_t *r0 __asm__("r0") = result; + register const uint32_t *r1 __asm__("r1") = left; + register uint32_t r2 __asm__("r2") = num_words; + +#if uECC_SUPPORTS_secp160r1 + if (num_words == 5) { + __asm__ volatile ( + ".syntax unified \n\t" + FAST_SQUARE_ASM_5 + RESUME_SYNTAX + : "+r" (r0), "+r" (r1) + : "r" (r2) + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); + return; + } +#endif +#if uECC_SUPPORTS_secp192r1 + if (num_words == 6) { + __asm__ volatile ( + ".syntax unified \n\t" + FAST_SQUARE_ASM_6 + RESUME_SYNTAX + : "+r" (r0), "+r" (r1) + : "r" (r2) + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); + return; + } +#endif +#if uECC_SUPPORTS_secp224r1 + if (num_words == 7) { + __asm__ volatile ( + ".syntax unified \n\t" + FAST_SQUARE_ASM_7 + RESUME_SYNTAX + : "+r" (r0), "+r" (r1) + : "r" (r2) + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); + return; + } +#endif +#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) + if (num_words == 8) { + __asm__ volatile ( + ".syntax unified \n\t" + FAST_SQUARE_ASM_8 + RESUME_SYNTAX + : "+r" (r0), "+r" (r1) + : "r" (r2) + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); + return; + } +#endif +} +#define asm_square 1 +#endif /* uECC_SQUARE_FUNC */ + +#endif /* (uECC_OPTIMIZATION_LEVEL > 3) */ + +#endif /* uECC_PLATFORM != uECC_arm_thumb */ + +#endif /* (uECC_OPTIMIZATION_LEVEL >= 3) */ + +/* ---- "Small" implementations ---- */ + +#if !asm_add +uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + uint32_t carry = 0; + uint32_t left_word; + uint32_t right_word; + + __asm__ volatile ( + ".syntax unified \n\t" + "1: \n\t" + "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ + "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ + "lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */ + "adcs %[left], %[left], %[right] \n\t" /* Add with carry. */ + "adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */ + "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ + "subs %[ctr], #1 \n\t" /* Decrement counter. */ + "bne 1b \n\t" /* Loop until counter == 0. */ + RESUME_SYNTAX + : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right), + [ctr] REG_RW (num_words), [carry] REG_RW (carry), + [left] REG_WRITE (left_word), [right] REG_WRITE (right_word) + : + : "cc", "memory" + ); + return carry; +} +#define asm_add 1 +#endif + +#if !asm_sub +uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */ + uint32_t left_word; + uint32_t right_word; + + __asm__ volatile ( + ".syntax unified \n\t" + "1: \n\t" + "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ + "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ + "lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */ + "sbcs %[left], %[left], %[right] \n\t" /* Subtract with borrow. */ + "adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */ + "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ + "subs %[ctr], #1 \n\t" /* Decrement counter. */ + "bne 1b \n\t" /* Loop until counter == 0. */ + RESUME_SYNTAX + : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right), + [ctr] REG_RW (num_words), [carry] REG_RW (carry), + [left] REG_WRITE (left_word), [right] REG_WRITE (right_word) + : + : "cc", "memory" + ); + return !carry; +} +#define asm_sub 1 +#endif + +#if !asm_mult +uECC_VLI_API void uECC_vli_mult(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { +#if (uECC_PLATFORM != uECC_arm_thumb) + uint32_t c0 = 0; + uint32_t c1 = 0; + uint32_t c2 = 0; + uint32_t k = 0; + uint32_t i; + uint32_t t0, t1; + + __asm__ volatile ( + ".syntax unified \n\t" + + "1: \n\t" /* outer loop (k < num_words) */ + "movs %[i], #0 \n\t" /* i = 0 */ + "b 3f \n\t" + + "2: \n\t" /* outer loop (k >= num_words) */ + "movs %[i], %[k] \n\t" /* i = k */ + "subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */ + + "3: \n\t" /* inner loop */ + "subs %[t0], %[k], %[i] \n\t" /* t0 = k-i */ + + "ldr %[t1], [%[right], %[t0]] \n\t" /* t1 = right[k - i] */ + "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */ + + "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ + + "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ + "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ + "adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */ + + "adds %[i], #4 \n\t" /* i += 4 */ + "cmp %[i], %[last_word] \n\t" /* i > (num_words - 1) (times 4)? */ + "bgt 4f \n\t" /* if so, exit the loop */ + "cmp %[i], %[k] \n\t" /* i <= k? */ + "ble 3b \n\t" /* if so, continue looping */ + + "4: \n\t" /* end inner loop */ + + "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ + "mov %[c0], %[c1] \n\t" /* c0 = c1 */ + "mov %[c1], %[c2] \n\t" /* c1 = c2 */ + "movs %[c2], #0 \n\t" /* c2 = 0 */ + "adds %[k], #4 \n\t" /* k += 4 */ + "cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */ + "ble 1b \n\t" /* if so, loop back, start with i = 0 */ + "cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ + "ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */ + /* end outer loop */ + + "str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */ + RESUME_SYNTAX + : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), + [k] "+r" (k), [i] "=&r" (i), [t0] "=&r" (t0), [t1] "=&r" (t1) + : [result] "r" (result), [left] "r" (left), [right] "r" (right), + [last_word] "r" ((num_words - 1) * 4) + : "cc", "memory" + ); + +#else /* Thumb-1 */ + uint32_t r4, r5, r6, r7; + + __asm__ volatile ( + ".syntax unified \n\t" + "subs %[r3], #1 \n\t" /* r3 = num_words - 1 */ + "lsls %[r3], #2 \n\t" /* r3 = (num_words - 1) * 4 */ + "mov r8, %[r3] \n\t" /* r8 = (num_words - 1) * 4 */ + "lsls %[r3], #1 \n\t" /* r3 = (num_words - 1) * 8 */ + "mov r9, %[r3] \n\t" /* r9 = (num_words - 1) * 8 */ + "movs %[r3], #0 \n\t" /* c0 = 0 */ + "movs %[r4], #0 \n\t" /* c1 = 0 */ + "movs %[r5], #0 \n\t" /* c2 = 0 */ + "movs %[r6], #0 \n\t" /* k = 0 */ + + "push {%[r0]} \n\t" /* keep result on the stack */ + + "1: \n\t" /* outer loop (k < num_words) */ + "movs %[r7], #0 \n\t" /* r7 = i = 0 */ + "b 3f \n\t" + + "2: \n\t" /* outer loop (k >= num_words) */ + "movs %[r7], %[r6] \n\t" /* r7 = k */ + "mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */ + "subs %[r7], %[r0] \n\t" /* r7 = i = k - (num_words - 1) (times 4) */ + + "3: \n\t" /* inner loop */ + "mov r10, %[r3] \n\t" + "mov r11, %[r4] \n\t" + "mov r12, %[r5] \n\t" + "mov r14, %[r6] \n\t" + "subs %[r0], %[r6], %[r7] \n\t" /* r0 = k - i */ + + "ldr %[r4], [%[r2], %[r0]] \n\t" /* r4 = right[k - i] */ + "ldr %[r0], [%[r1], %[r7]] \n\t" /* r0 = left[i] */ + + "lsrs %[r3], %[r0], #16 \n\t" /* r3 = a1 */ + "uxth %[r0], %[r0] \n\t" /* r0 = a0 */ + + "lsrs %[r5], %[r4], #16 \n\t" /* r5 = b1 */ + "uxth %[r4], %[r4] \n\t" /* r4 = b0 */ + + "movs %[r6], %[r3] \n\t" /* r6 = a1 */ + "muls %[r6], %[r5], %[r6] \n\t" /* r6 = a1 * b1 */ + "muls %[r3], %[r4], %[r3] \n\t" /* r3 = b0 * a1 */ + "muls %[r5], %[r0], %[r5] \n\t" /* r5 = a0 * b1 */ + "muls %[r0], %[r4], %[r0] \n\t" /* r0 = a0 * b0 */ + + /* Add middle terms */ + "lsls %[r4], %[r3], #16 \n\t" + "lsrs %[r3], %[r3], #16 \n\t" + "adds %[r0], %[r4] \n\t" + "adcs %[r6], %[r3] \n\t" + + "lsls %[r4], %[r5], #16 \n\t" + "lsrs %[r5], %[r5], #16 \n\t" + "adds %[r0], %[r4] \n\t" + "adcs %[r6], %[r5] \n\t" + + "mov %[r3], r10\n\t" + "mov %[r4], r11\n\t" + "mov %[r5], r12\n\t" + "adds %[r3], %[r0] \n\t" /* add low word to c0 */ + "adcs %[r4], %[r6] \n\t" /* add high word to c1, including carry */ + "movs %[r0], #0 \n\t" /* r0 = 0 (does not affect carry bit) */ + "adcs %[r5], %[r0] \n\t" /* add carry to c2 */ + + "mov %[r6], r14\n\t" /* r6 = k */ + + "adds %[r7], #4 \n\t" /* i += 4 */ + "cmp %[r7], r8 \n\t" /* i > (num_words - 1) (times 4)? */ + "bgt 4f \n\t" /* if so, exit the loop */ + "cmp %[r7], %[r6] \n\t" /* i <= k? */ + "ble 3b \n\t" /* if so, continue looping */ + + "4: \n\t" /* end inner loop */ + + "ldr %[r0], [sp, #0] \n\t" /* r0 = result */ + + "str %[r3], [%[r0], %[r6]] \n\t" /* result[k] = c0 */ + "mov %[r3], %[r4] \n\t" /* c0 = c1 */ + "mov %[r4], %[r5] \n\t" /* c1 = c2 */ + "movs %[r5], #0 \n\t" /* c2 = 0 */ + "adds %[r6], #4 \n\t" /* k += 4 */ + "cmp %[r6], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */ + "ble 1b \n\t" /* if so, loop back, start with i = 0 */ + "cmp %[r6], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ + "ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */ + /* end outer loop */ + + "str %[r3], [%[r0], %[r6]] \n\t" /* result[num_words * 2 - 1] = c0 */ + "pop {%[r0]} \n\t" /* pop result off the stack */ + + ".syntax divided \n\t" + : [r3] "+l" (num_words), [r4] "=&l" (r4), + [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) + : [r0] "l" (result), [r1] "l" (left), [r2] "l" (right) + : "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +#endif +} +#define asm_mult 1 +#endif + +#if uECC_SQUARE_FUNC +#if !asm_square +uECC_VLI_API void uECC_vli_square(uECC_word_t *result, + const uECC_word_t *left, + wordcount_t num_words) { +#if (uECC_PLATFORM != uECC_arm_thumb) + uint32_t c0 = 0; + uint32_t c1 = 0; + uint32_t c2 = 0; + uint32_t k = 0; + uint32_t i, tt; + uint32_t t0, t1; + + __asm__ volatile ( + ".syntax unified \n\t" + + "1: \n\t" /* outer loop (k < num_words) */ + "movs %[i], #0 \n\t" /* i = 0 */ + "b 3f \n\t" + + "2: \n\t" /* outer loop (k >= num_words) */ + "movs %[i], %[k] \n\t" /* i = k */ + "subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */ + + "3: \n\t" /* inner loop */ + "subs %[tt], %[k], %[i] \n\t" /* tt = k-i */ + + "ldr %[t1], [%[left], %[tt]] \n\t" /* t1 = left[k - i] */ + "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */ + + "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ + + "cmp %[i], %[tt] \n\t" /* (i < k - i) ? */ + "bge 4f \n\t" /* if i >= k - i, skip */ + "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ + "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ + "adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */ + + "4: \n\t" + "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ + "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ + "adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */ + + "adds %[i], #4 \n\t" /* i += 4 */ + "cmp %[i], %[k] \n\t" /* i >= k? */ + "bge 5f \n\t" /* if so, exit the loop */ + "subs %[tt], %[k], %[i] \n\t" /* tt = k - i */ + "cmp %[i], %[tt] \n\t" /* i <= k - i? */ + "ble 3b \n\t" /* if so, continue looping */ + + "5: \n\t" /* end inner loop */ + + "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ + "mov %[c0], %[c1] \n\t" /* c0 = c1 */ + "mov %[c1], %[c2] \n\t" /* c1 = c2 */ + "movs %[c2], #0 \n\t" /* c2 = 0 */ + "adds %[k], #4 \n\t" /* k += 4 */ + "cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */ + "ble 1b \n\t" /* if so, loop back, start with i = 0 */ + "cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ + "ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */ + /* end outer loop */ + + "str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */ + RESUME_SYNTAX + : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), + [k] "+r" (k), [i] "=&r" (i), [tt] "=&r" (tt), [t0] "=&r" (t0), [t1] "=&r" (t1) + : [result] "r" (result), [left] "r" (left), [last_word] "r" ((num_words - 1) * 4) + : "cc", "memory" + ); + +#else + uint32_t r3, r4, r5, r6, r7; + + __asm__ volatile ( + ".syntax unified \n\t" + "subs %[r2], #1 \n\t" /* r2 = num_words - 1 */ + "lsls %[r2], #2 \n\t" /* r2 = (num_words - 1) * 4 */ + "mov r8, %[r2] \n\t" /* r8 = (num_words - 1) * 4 */ + "lsls %[r2], #1 \n\t" /* r2 = (num_words - 1) * 8 */ + "mov r9, %[r2] \n\t" /* r9 = (num_words - 1) * 8 */ + "movs %[r2], #0 \n\t" /* c0 = 0 */ + "movs %[r3], #0 \n\t" /* c1 = 0 */ + "movs %[r4], #0 \n\t" /* c2 = 0 */ + "movs %[r5], #0 \n\t" /* k = 0 */ + + "push {%[r0]} \n\t" /* keep result on the stack */ + + "1: \n\t" /* outer loop (k < num_words) */ + "movs %[r6], #0 \n\t" /* r6 = i = 0 */ + "b 3f \n\t" + + "2: \n\t" /* outer loop (k >= num_words) */ + "movs %[r6], %[r5] \n\t" /* r6 = k */ + "mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */ + "subs %[r6], %[r0] \n\t" /* r6 = i = k - (num_words - 1) (times 4) */ + + "3: \n\t" /* inner loop */ + "mov r10, %[r2] \n\t" + "mov r11, %[r3] \n\t" + "mov r12, %[r4] \n\t" + "mov r14, %[r5] \n\t" + "subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */ + + "ldr %[r3], [%[r1], %[r7]] \n\t" /* r3 = left[k - i] */ + "ldr %[r0], [%[r1], %[r6]] \n\t" /* r0 = left[i] */ + + "lsrs %[r2], %[r0], #16 \n\t" /* r2 = a1 */ + "uxth %[r0], %[r0] \n\t" /* r0 = a0 */ + + "lsrs %[r4], %[r3], #16 \n\t" /* r4 = b1 */ + "uxth %[r3], %[r3] \n\t" /* r3 = b0 */ + + "movs %[r5], %[r2] \n\t" /* r5 = a1 */ + "muls %[r5], %[r4], %[r5] \n\t" /* r5 = a1 * b1 */ + "muls %[r2], %[r3], %[r2] \n\t" /* r2 = b0 * a1 */ + "muls %[r4], %[r0], %[r4] \n\t" /* r4 = a0 * b1 */ + "muls %[r0], %[r3], %[r0] \n\t" /* r0 = a0 * b0 */ + + /* Add middle terms */ + "lsls %[r3], %[r2], #16 \n\t" + "lsrs %[r2], %[r2], #16 \n\t" + "adds %[r0], %[r3] \n\t" + "adcs %[r5], %[r2] \n\t" + + "lsls %[r3], %[r4], #16 \n\t" + "lsrs %[r4], %[r4], #16 \n\t" + "adds %[r0], %[r3] \n\t" + "adcs %[r5], %[r4] \n\t" + + /* Add to acc, doubling if necessary */ + "mov %[r2], r10\n\t" + "mov %[r3], r11\n\t" + "mov %[r4], r12\n\t" + + "cmp %[r6], %[r7] \n\t" /* (i < k - i) ? */ + "bge 4f \n\t" /* if i >= k - i, skip */ + "movs %[r7], #0 \n\t" /* r7 = 0 */ + "adds %[r2], %[r0] \n\t" /* add low word to c0 */ + "adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */ + "adcs %[r4], %[r7] \n\t" /* add carry to c2 */ + "4: \n\t" + "movs %[r7], #0 \n\t" /* r7 = 0 */ + "adds %[r2], %[r0] \n\t" /* add low word to c0 */ + "adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */ + "adcs %[r4], %[r7] \n\t" /* add carry to c2 */ + + "mov %[r5], r14\n\t" /* r5 = k */ + + "adds %[r6], #4 \n\t" /* i += 4 */ + "cmp %[r6], %[r5] \n\t" /* i >= k? */ + "bge 5f \n\t" /* if so, exit the loop */ + "subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */ + "cmp %[r6], %[r7] \n\t" /* i <= k - i? */ + "ble 3b \n\t" /* if so, continue looping */ + + "5: \n\t" /* end inner loop */ + + "ldr %[r0], [sp, #0] \n\t" /* r0 = result */ + + "str %[r2], [%[r0], %[r5]] \n\t" /* result[k] = c0 */ + "mov %[r2], %[r3] \n\t" /* c0 = c1 */ + "mov %[r3], %[r4] \n\t" /* c1 = c2 */ + "movs %[r4], #0 \n\t" /* c2 = 0 */ + "adds %[r5], #4 \n\t" /* k += 4 */ + "cmp %[r5], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */ + "ble 1b \n\t" /* if so, loop back, start with i = 0 */ + "cmp %[r5], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ + "ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */ + /* end outer loop */ + + "str %[r2], [%[r0], %[r5]] \n\t" /* result[num_words * 2 - 1] = c0 */ + "pop {%[r0]} \n\t" /* pop result off the stack */ + + ".syntax divided \n\t" + : [r2] "+l" (num_words), [r3] "=&l" (r3), [r4] "=&l" (r4), + [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) + : [r0] "l" (result), [r1] "l" (left) + : "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" + ); +#endif +} +#define asm_square 1 +#endif +#endif /* uECC_SQUARE_FUNC */ + +#endif /* _UECC_ASM_ARM_H_ */ diff --git a/lib/micro-ecc/asm_arm_mult_square.inc b/lib/micro-ecc/asm_arm_mult_square.inc new file mode 100644 index 00000000..8907fc18 --- /dev/null +++ b/lib/micro-ecc/asm_arm_mult_square.inc @@ -0,0 +1,2311 @@ +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_ASM_ARM_MULT_SQUARE_H_ +#define _UECC_ASM_ARM_MULT_SQUARE_H_ + +#define FAST_MULT_ASM_5 \ + "push {r3} \n\t" \ + "add r0, 12 \n\t" \ + "add r2, 12 \n\t" \ + "ldmia r1!, {r3,r4} \n\t" \ + "ldmia r2!, {r6,r7} \n\t" \ + \ + "umull r11, r12, r3, r6 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r9, r3, r7 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r14, r4, r6 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "umull r12, r14, r4, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adc r10, r10, r14 \n\t" \ + "stmia r0!, {r9, r10} \n\t" \ + \ + "sub r0, 28 \n\t" \ + "sub r2, 20 \n\t" \ + "ldmia r2!, {r6,r7,r8} \n\t" \ + "ldmia r1!, {r5} \n\t" \ + \ + "umull r11, r12, r3, r6 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r9, r3, r7 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r14, r4, r6 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r3, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r5, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "ldmia r1!, {r3} \n\t" \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r4, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r5, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r3, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "ldmia r1!, {r4} \n\t" \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r5, r8 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r3, r7 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r4, r6 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "ldr r9, [r0] \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, #0 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "ldmia r2!, {r6} \n\t" \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r5, r6 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r3, r8 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r4, r7 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "ldr r10, [r0] \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "ldmia r2!, {r7} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r6 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "ldr r11, [r0] \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r14} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r3, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "umull r14, r9, r4, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adc r11, r11, r9 \n\t" \ + "stmia r0!, {r10, r11} \n\t" \ + "pop {r3} \n\t" + +#define FAST_MULT_ASM_5_TO_6 \ + "cmp r3, #5 \n\t" \ + "beq 1f \n\t" \ + \ + /* r4 = left high, r5 = right high */ \ + "ldr r4, [r1] \n\t" \ + "ldr r5, [r2] \n\t" \ + \ + "sub r0, #20 \n\t" \ + "sub r1, #20 \n\t" \ + "sub r2, #20 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r4, r8 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r9, r9, r6 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "str r9, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r10, r10, r6 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r9, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "str r10, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r14, r14, r6 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "str r14, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r9, r9, r6 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r14, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "str r9, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r10, r10, r6 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + /* skip past already-loaded (r4, r5) */ \ + "ldr r7, [r1], #8 \n\t" \ + "ldr r8, [r2], #8 \n\t" \ + "mov r9, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "str r10, [r0], #4 \n\t" \ + \ + "umull r11, r12, r4, r5 \n\t" \ + "adds r11, r11, r14 \n\t" \ + "adc r12, r12, r9 \n\t" \ + "stmia r0!, {r11, r12} \n\t" + +#define FAST_MULT_ASM_6 \ + "push {r3} \n\t" \ + "add r0, 12 \n\t" \ + "add r2, 12 \n\t" \ + "ldmia r1!, {r3,r4,r5} \n\t" \ + "ldmia r2!, {r6,r7,r8} \n\t" \ + \ + "umull r11, r12, r3, r6 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r9, r3, r7 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r14, r4, r6 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r3, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r5, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r4, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r5, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "umull r9, r10, r5, r8 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adc r12, r12, r10 \n\t" \ + "stmia r0!, {r11, r12} \n\t" \ + \ + "sub r0, 36 \n\t" \ + "sub r2, 24 \n\t" \ + "ldmia r2!, {r6,r7,r8} \n\t" \ + \ + "umull r11, r12, r3, r6 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r9, r3, r7 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r14, r4, r6 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r3, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r5, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "ldmia r1!, {r3} \n\t" \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r4, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r5, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r3, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "ldmia r1!, {r4} \n\t" \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r5, r8 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r3, r7 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r4, r6 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "ldr r9, [r0] \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, #0 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "ldmia r1!, {r5} \n\t" \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r3, r8 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r4, r7 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r5, r6 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "ldr r10, [r0] \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "ldmia r2!, {r6} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r3, r6 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "ldr r11, [r0] \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r14} \n\t" \ + \ + "ldmia r2!, {r7} \n\t" \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r3, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r5, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "ldr r12, [r0] \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "ldmia r2!, {r8} \n\t" \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r3, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r4, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r5, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r4, r8 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r5, r7 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "umull r10, r11, r5, r8 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adc r14, r14, r11 \n\t" \ + "stmia r0!, {r12, r14} \n\t" \ + "pop {r3} \n\t" + +#define FAST_MULT_ASM_6_TO_7 \ + "cmp r3, #6 \n\t" \ + "beq 1f \n\t" \ + \ + /* r4 = left high, r5 = right high */ \ + "ldr r4, [r1] \n\t" \ + "ldr r5, [r2] \n\t" \ + \ + "sub r0, #24 \n\t" \ + "sub r1, #24 \n\t" \ + "sub r2, #24 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r4, r8 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r9, r9, r6 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "str r9, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r10, r10, r6 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r9, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "str r10, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r14, r14, r6 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "str r14, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r9, r9, r6 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r14, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "str r9, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r10, r10, r6 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r9, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "str r10, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r14, r14, r6 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + /* skip past already-loaded (r4, r5) */ \ + "ldr r7, [r1], #8 \n\t" \ + "ldr r8, [r2], #8 \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "str r14, [r0], #4 \n\t" \ + \ + "umull r11, r12, r4, r5 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adc r12, r12, r10 \n\t" \ + "stmia r0!, {r11, r12} \n\t" + +#define FAST_MULT_ASM_7 \ + "push {r3} \n\t" \ + "add r0, 24 \n\t" \ + "add r2, 24 \n\t" \ + "ldmia r1!, {r3} \n\t" \ + "ldmia r2!, {r6} \n\t" \ + \ + "umull r9, r10, r3, r6 \n\t" \ + "stmia r0!, {r9, r10} \n\t" \ + \ + "sub r0, 20 \n\t" \ + "sub r2, 16 \n\t" \ + "ldmia r2!, {r6, r7, r8} \n\t" \ + "ldmia r1!, {r4, r5} \n\t" \ + \ + "umull r9, r10, r3, r6 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "mov r14, #0 \n\t" \ + "umull r9, r12, r3, r7 \n\t" \ + "adds r10, r10, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r9, r11, r4, r6 \n\t" \ + "adds r10, r10, r9 \n\t" \ + "adcs r12, r12, r11 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r3, r8 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r4, r7 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r5, r6 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "ldmia r1!, {r3} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r6 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "ldr r11, [r0] \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r14} \n\t" \ + \ + "ldmia r2!, {r6} \n\t" \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r4, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r5, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r3, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "ldr r12, [r0] \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r5, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r3, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "umull r9, r10, r3, r6 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adc r12, r12, r10 \n\t" \ + "stmia r0!, {r11, r12} \n\t" \ + \ + "sub r0, 44 \n\t" \ + "sub r1, 16 \n\t" \ + "sub r2, 28 \n\t" \ + "ldmia r1!, {r3,r4,r5} \n\t" \ + "ldmia r2!, {r6,r7,r8} \n\t" \ + \ + "umull r9, r10, r3, r6 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "mov r14, #0 \n\t" \ + "umull r9, r12, r3, r7 \n\t" \ + "adds r10, r10, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r9, r11, r4, r6 \n\t" \ + "adds r10, r10, r9 \n\t" \ + "adcs r12, r12, r11 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r3, r8 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r4, r7 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r5, r6 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "ldmia r1!, {r3} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r6 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "ldr r11, [r0] \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r14} \n\t" \ + \ + "ldmia r1!, {r4} \n\t" \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r5, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r3, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "ldr r12, [r0] \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "ldmia r1!, {r5} \n\t" \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r3, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r4, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r5, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "ldmia r1!, {r3} \n\t" \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r4, r8 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r5, r7 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r3, r6 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "ldr r9, [r0] \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, #0 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "ldmia r2!, {r6} \n\t" \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r4, r6 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r5, r8 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r3, r7 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "ldr r10, [r0] \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "ldmia r2!, {r7} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r4, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r6 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "ldr r11, [r0] \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r14} \n\t" \ + \ + "ldmia r2!, {r8} \n\t" \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r4, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r5, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r3, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "ldr r12, [r0] \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "ldmia r2!, {r6} \n\t" \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r4, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r5, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r3, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r5, r6 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r3, r8 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "umull r10, r11, r3, r6 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adc r14, r14, r11 \n\t" \ + "stmia r0!, {r12, r14} \n\t" \ + "pop {r3} \n\t" + +#define FAST_MULT_ASM_7_TO_8 \ + "cmp r3, #7 \n\t" \ + "beq 1f \n\t" \ + \ + /* r4 = left high, r5 = right high */ \ + "ldr r4, [r1] \n\t" \ + "ldr r5, [r2] \n\t" \ + \ + "sub r0, #28 \n\t" \ + "sub r1, #28 \n\t" \ + "sub r2, #28 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r4, r8 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r9, r9, r6 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "str r9, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r10, r10, r6 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r9, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "str r10, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r14, r14, r6 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "str r14, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r9, r9, r6 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r14, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "str r9, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r10, r10, r6 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r9, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r10, r10, r11 \n\t" \ + "adcs r14, r14, r12 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "str r10, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r14, r14, r6 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "ldr r7, [r1], #4 \n\t" \ + "ldr r8, [r2], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "str r14, [r0], #4 \n\t" \ + \ + "ldr r6, [r0] \n\t" \ + "adds r9, r9, r6 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + /* skip past already-loaded (r4, r5) */ \ + "ldr r7, [r1], #8 \n\t" \ + "ldr r8, [r2], #8 \n\t" \ + "mov r14, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r9, r9, r11 \n\t" \ + "adcs r10, r10, r12 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "str r9, [r0], #4 \n\t" \ + \ + "umull r11, r12, r4, r5 \n\t" \ + "adds r11, r11, r10 \n\t" \ + "adc r12, r12, r14 \n\t" \ + "stmia r0!, {r11, r12} \n\t" + +#define FAST_MULT_ASM_8 \ + "push {r3} \n\t" \ + "add r0, 24 \n\t" \ + "add r2, 24 \n\t" \ + "ldmia r1!, {r3,r4} \n\t" \ + "ldmia r2!, {r6,r7} \n\t" \ + \ + "umull r11, r12, r3, r6 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r9, r3, r7 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r14, r4, r6 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "umull r12, r14, r4, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adc r10, r10, r14 \n\t" \ + "stmia r0!, {r9, r10} \n\t" \ + \ + "sub r0, 28 \n\t" \ + "sub r2, 20 \n\t" \ + "ldmia r2!, {r6,r7,r8} \n\t" \ + "ldmia r1!, {r5} \n\t" \ + \ + "umull r11, r12, r3, r6 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r9, r3, r7 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r14, r4, r6 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r3, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r5, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "ldmia r1!, {r3} \n\t" \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r4, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r5, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r3, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "ldmia r1!, {r4} \n\t" \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r5, r8 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r3, r7 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r4, r6 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "ldr r9, [r0] \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, #0 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "ldmia r2!, {r6} \n\t" \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r5, r6 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r3, r8 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r4, r7 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "ldr r10, [r0] \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "ldmia r2!, {r7} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r6 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "ldr r11, [r0] \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r14} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r3, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "umull r14, r9, r4, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adc r11, r11, r9 \n\t" \ + "stmia r0!, {r10, r11} \n\t" \ + \ + "sub r0, 52 \n\t" \ + "sub r1, 20 \n\t" \ + "sub r2, 32 \n\t" \ + "ldmia r1!, {r3,r4,r5} \n\t" \ + "ldmia r2!, {r6,r7,r8} \n\t" \ + \ + "umull r11, r12, r3, r6 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r9, r3, r7 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r11, r14, r4, r6 \n\t" \ + "adds r12, r12, r11 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r3, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r5, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "ldmia r1!, {r3} \n\t" \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r4, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r5, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r3, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "ldmia r1!, {r4} \n\t" \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r5, r8 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r3, r7 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r4, r6 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "ldr r9, [r0] \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, #0 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "ldmia r1!, {r5} \n\t" \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r3, r8 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r4, r7 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r5, r6 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "ldr r10, [r0] \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "ldmia r1!, {r3} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r4, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r5, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r6 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "ldr r11, [r0] \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r14} \n\t" \ + \ + "ldmia r1!, {r4} \n\t" \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r5, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r3, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "ldr r12, [r0] \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "ldmia r2!, {r6} \n\t" \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r5, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r3, r8 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r4, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "ldmia r2!, {r7} \n\t" \ + "mov r14, #0 \n\t" \ + "umull r9, r10, r5, r7 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r3, r6 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "umull r9, r10, r4, r8 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "ldr r9, [r0] \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adcs r12, r12, #0 \n\t" \ + "adc r14, r14, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "ldmia r2!, {r8} \n\t" \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r5, r8 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r3, r7 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "umull r10, r11, r4, r6 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "ldr r10, [r0] \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r14, r14, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "ldmia r2!, {r6} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r5, r6 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r8 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r4, r7 \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "ldr r11, [r0] \n\t" \ + "adds r14, r14, r11 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r14} \n\t" \ + \ + "ldmia r2!, {r7} \n\t" \ + "mov r11, #0 \n\t" \ + "umull r12, r14, r5, r7 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r3, r6 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "umull r12, r14, r4, r8 \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, r14 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "ldr r12, [r0] \n\t" \ + "adds r9, r9, r12 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r9} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r14, r9, r3, r7 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r14, r9, r4, r6 \n\t" \ + "adds r10, r10, r14 \n\t" \ + "adcs r11, r11, r9 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r10} \n\t" \ + \ + "umull r9, r10, r4, r7 \n\t" \ + "adds r11, r11, r9 \n\t" \ + "adc r12, r12, r10 \n\t" \ + "stmia r0!, {r11, r12} \n\t" \ + "pop {r3} \n\t" + +#define FAST_SQUARE_ASM_5 \ + "push {r2} \n\t" \ + "ldmia r1!, {r2,r3,r4,r5,r6} \n\t" \ + "push {r1} \n\t" \ + \ + "umull r11, r12, r2, r2 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r2, r3 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r8, r11, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r8, r8, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r2, r4 \n\t" \ + "adds r11, r11, r11 \n\t" \ + "adcs r12, r12, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r3 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r2, r5 \n\t" \ + "umull r1, r14, r3, r4 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r14 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r2, r6 \n\t" \ + "umull r1, r14, r3, r5 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "umull r1, r14, r4, r4 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r3, r6 \n\t" \ + "umull r1, r14, r4, r5 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r14 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r8, #0 \n\t" \ + "umull r1, r10, r4, r6 \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "adds r11, r11, r1 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "umull r1, r10, r5, r5 \n\t" \ + "adds r11, r11, r1 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r1, r10, r5, r6 \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "adds r12, r12, r1 \n\t" \ + "adcs r8, r8, r10 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "umull r1, r10, r6, r6 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "stmia r0!, {r8, r11} \n\t" \ + "pop {r1, r2} \n\t" + +#define FAST_SQUARE_ASM_5_TO_6 \ + "cmp r2, #5 \n\t" \ + "beq 1f \n\t" \ + \ + "sub r0, #20 \n\t" \ + "sub r1, #20 \n\t" \ + \ + /* Do off-center multiplication */ \ + "ldmia r1!, {r6,r7,r8,r9,r10,r11} \n\t" \ + "umull r3, r4, r6, r11 \n\t" \ + "umull r6, r5, r7, r11 \n\t" \ + "adds r4, r4, r6 \n\t" \ + "umull r7, r6, r8, r11 \n\t" \ + "adcs r5, r5, r7 \n\t" \ + "umull r8, r7, r9, r11 \n\t" \ + "adcs r6, r6, r8 \n\t" \ + "umull r9, r8, r10, r11 \n\t" \ + "adcs r7, r7, r9 \n\t" \ + "adcs r8, r8, #0 \n\t" \ + \ + /* Multiply by 2 */ \ + "mov r9, #0 \n\t" \ + "adds r3, r3, r3 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + "adcs r7, r7, r7 \n\t" \ + "adcs r8, r8, r8 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + \ + /* Add into previous */ \ + "ldr r14, [r0], #4 \n\t" \ + "adds r3, r3, r14 \n\t" \ + "ldr r14, [r0], #4 \n\t" \ + "adcs r4, r4, r14 \n\t" \ + "ldr r14, [r0], #4 \n\t" \ + "adcs r5, r5, r14 \n\t" \ + "ldr r14, [r0], #4 \n\t" \ + "adcs r6, r6, r14 \n\t" \ + "ldr r14, [r0], #4 \n\t" \ + "adcs r7, r7, r14 \n\t" \ + "adcs r8, r8, #0 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "sub r0, #20 \n\t" \ + \ + /* Perform center multiplication */ \ + "umlal r8, r9, r11, r11 \n\t" \ + "stmia r0!, {r3,r4,r5,r6,r7,r8,r9} \n\t" + +#define FAST_SQUARE_ASM_6 \ + "push {r2} \n\t" \ + "ldmia r1!, {r2,r3,r4,r5,r6,r7} \n\t" \ + "push {r1} \n\t" \ + \ + "umull r11, r12, r2, r2 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r2, r3 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r8, r11, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r8, r8, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r2, r4 \n\t" \ + "adds r11, r11, r11 \n\t" \ + "adcs r12, r12, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r3 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r2, r5 \n\t" \ + "umull r1, r14, r3, r4 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r14 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r2, r6 \n\t" \ + "umull r1, r14, r3, r5 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "umull r1, r14, r4, r4 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r2, r7 \n\t" \ + "umull r1, r14, r3, r6 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r14 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "umull r1, r14, r4, r5 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r14 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r3, r7 \n\t" \ + "umull r1, r14, r4, r6 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "umull r1, r14, r5, r5 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r9, r9, r14 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r4, r7 \n\t" \ + "umull r1, r14, r5, r6 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r14 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r8, #0 \n\t" \ + "umull r1, r10, r5, r7 \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "adds r11, r11, r1 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "umull r1, r10, r6, r6 \n\t" \ + "adds r11, r11, r1 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r1, r10, r6, r7 \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "adds r12, r12, r1 \n\t" \ + "adcs r8, r8, r10 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "umull r1, r10, r7, r7 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "stmia r0!, {r8, r11} \n\t" \ + "pop {r1, r2} \n\t" + +#define FAST_SQUARE_ASM_6_TO_7 \ + "cmp r2, #6 \n\t" \ + "beq 1f \n\t" \ + \ + "sub r0, #24 \n\t" \ + "sub r1, #24 \n\t" \ + \ + /* Do off-center multiplication */ \ + "ldmia r1!, {r6,r7,r8,r9,r10,r11,r12} \n\t" \ + "umull r3, r4, r6, r12 \n\t" \ + "umull r6, r5, r7, r12 \n\t" \ + "adds r4, r4, r6 \n\t" \ + "umull r7, r6, r8, r12 \n\t" \ + "adcs r5, r5, r7 \n\t" \ + "umull r8, r7, r9, r12 \n\t" \ + "adcs r6, r6, r8 \n\t" \ + "umull r9, r8, r10, r12 \n\t" \ + "adcs r7, r7, r9 \n\t" \ + "umull r10, r9, r11, r12 \n\t" \ + "adcs r8, r8, r10 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + \ + /* Multiply by 2 */ \ + "mov r10, #0 \n\t" \ + "adds r3, r3, r3 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + "adcs r7, r7, r7 \n\t" \ + "adcs r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + \ + /* Add into previous */ \ + "ldr r14, [r0], #4 \n\t" \ + "adds r3, r3, r14 \n\t" \ + "ldr r14, [r0], #4 \n\t" \ + "adcs r4, r4, r14 \n\t" \ + "ldr r14, [r0], #4 \n\t" \ + "adcs r5, r5, r14 \n\t" \ + "ldr r14, [r0], #4 \n\t" \ + "adcs r6, r6, r14 \n\t" \ + "ldr r14, [r0], #4 \n\t" \ + "adcs r7, r7, r14 \n\t" \ + "ldr r14, [r0], #4 \n\t" \ + "adcs r8, r8, r14 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "sub r0, #24 \n\t" \ + \ + /* Perform center multiplication */ \ + "umlal r9, r10, r12, r12 \n\t" \ + "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10} \n\t" + +#define FAST_SQUARE_ASM_7 \ + "push {r2} \n\t" \ + "ldmia r1!, {r2, r3, r4, r5, r6, r7, r8} \n\t" \ + "push {r1} \n\t" \ + "sub r1, 4 \n\t" \ + \ + "add r0, 24 \n\t" \ + "umull r9, r10, r2, r8 \n\t" \ + "stmia r0!, {r9, r10} \n\t" \ + "sub r0, 32 \n\t" \ + \ + "umull r11, r12, r2, r2 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r2, r3 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r8, r11, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r8, r8, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r2, r4 \n\t" \ + "adds r11, r11, r11 \n\t" \ + "adcs r12, r12, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r3 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r2, r5 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r3, r4 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r2, r6 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r3, r5 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r4, r4 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r2, r7 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r3, r6 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r4, r5 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "ldmia r1!, {r2} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r3, r7 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r4, r6 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r8, r8, r14 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r5, r5 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r3, r2 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r4, r7 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r5, r6 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r8, r8, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r4, r2 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r5, r7 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r6, r6 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r5, r2 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r6, r7 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r8, #0 \n\t" \ + "umull r1, r10, r6, r2 \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "adds r11, r11, r1 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "umull r1, r10, r7, r7 \n\t" \ + "adds r11, r11, r1 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r1, r10, r7, r2 \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "adds r12, r12, r1 \n\t" \ + "adcs r8, r8, r10 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "umull r1, r10, r2, r2 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "stmia r0!, {r8, r11} \n\t" \ + "pop {r1, r2} \n\t" + +#define FAST_SQUARE_ASM_7_TO_8 \ + "cmp r2, #7 \n\t" \ + "beq 1f \n\t" \ + \ + "sub r0, #28 \n\t" \ + "sub r1, #28 \n\t" \ + \ + /* Do off-center multiplication */ \ + "ldmia r1!, {r6,r7,r8,r9,r10,r11,r12,r14} \n\t" \ + "umull r3, r4, r6, r14 \n\t" \ + "umull r6, r5, r7, r14 \n\t" \ + "adds r4, r4, r6 \n\t" \ + "umull r7, r6, r8, r14 \n\t" \ + "adcs r5, r5, r7 \n\t" \ + "umull r8, r7, r9, r14 \n\t" \ + "adcs r6, r6, r8 \n\t" \ + "umull r9, r8, r10, r14 \n\t" \ + "adcs r7, r7, r9 \n\t" \ + "umull r10, r9, r11, r14 \n\t" \ + "adcs r8, r8, r10 \n\t" \ + "umull r11, r10, r12, r14 \n\t" \ + "adcs r9, r9, r11 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + \ + /* Multiply by 2 */ \ + "mov r11, #0 \n\t" \ + "adds r3, r3, r3 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + "adcs r7, r7, r7 \n\t" \ + "adcs r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + \ + /* Add into previous */ \ + "ldr r12, [r0], #4 \n\t" \ + "adds r3, r3, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r4, r4, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r5, r5, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r6, r6, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r7, r7, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r8, r8, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "sub r0, #28 \n\t" \ + \ + /* Perform center multiplication */ \ + "umlal r10, r11, r14, r14 \n\t" \ + "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} \n\t" + +#define FAST_SQUARE_ASM_8 \ + "push {r2} \n\t" \ + "ldmia r1!, {r2,r3,r4,r5,r6,r7,r8,r9} \n\t" \ + "push {r1} \n\t" \ + "sub r1, 8 \n\t" \ + \ + "add r0, 24 \n\t" \ + "umull r10, r11, r2, r8 \n\t" \ + "umull r12, r14, r2, r9 \n\t" \ + "umull r8, r9, r3, r9 \n\t" \ + "adds r11, r11, r12 \n\t" \ + "adcs r12, r14, r8 \n\t" \ + "adcs r14, r9, #0 \n\t" \ + "stmia r0!, {r10, r11, r12, r14} \n\t" \ + "sub r0, 40 \n\t" \ + \ + "umull r11, r12, r2, r2 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r9, #0 \n\t" \ + "umull r10, r11, r2, r3 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r8, r11, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "adds r12, r12, r10 \n\t" \ + "adcs r8, r8, r11 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r11, r12, r2, r4 \n\t" \ + "adds r11, r11, r11 \n\t" \ + "adcs r12, r12, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "umull r11, r12, r3, r3 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r2, r5 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r3, r4 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r2, r6 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r3, r5 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r4, r4 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r2, r7 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r3, r6 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r4, r5 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "ldmia r1!, {r2} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r3, r7 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r4, r6 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r8, r8, r14 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r5, r5 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r3, r2 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r4, r7 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r5, r6 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r8, r8, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "ldmia r1!, {r3} \n\t" \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r4, r2 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r5, r7 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r8, r8, r14 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r6, r6 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r4, r3 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r5, r2 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r6, r7 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "ldr r14, [r0] \n\t" \ + "adds r8, r8, r14 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umull r8, r9, r5, r3 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r6, r2 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adc r10, r10, r10 \n\t" \ + "mov r14, r9 \n\t" \ + "umlal r8, r9, r7, r7 \n\t" \ + "cmp r14, r9 \n\t" \ + "it hi \n\t" \ + "adchi r10, r10, #0 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umull r8, r11, r6, r3 \n\t" \ + "mov r14, r11 \n\t" \ + "umlal r8, r11, r7, r2 \n\t" \ + "cmp r14, r11 \n\t" \ + "it hi \n\t" \ + "adchi r12, r12, #0 \n\t" \ + "adds r8, r8, r8 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adc r12, r12, r12 \n\t" \ + "adds r8, r8, r9 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "adc r12, r12, #0 \n\t" \ + "stmia r0!, {r8} \n\t" \ + \ + "mov r8, #0 \n\t" \ + "umull r1, r10, r7, r3 \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "adds r11, r11, r1 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "umull r1, r10, r2, r2 \n\t" \ + "adds r11, r11, r1 \n\t" \ + "adcs r12, r12, r10 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "stmia r0!, {r11} \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umull r1, r10, r2, r3 \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "adds r12, r12, r1 \n\t" \ + "adcs r8, r8, r10 \n\t" \ + "adc r11, r11, #0 \n\t" \ + "stmia r0!, {r12} \n\t" \ + \ + "umull r1, r10, r3, r3 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "adcs r11, r11, r10 \n\t" \ + "stmia r0!, {r8, r11} \n\t" \ + "pop {r1, r2} \n\t" + +#endif /* _UECC_ASM_ARM_MULT_SQUARE_H_ */ diff --git a/lib/micro-ecc/asm_arm_mult_square_umaal.inc b/lib/micro-ecc/asm_arm_mult_square_umaal.inc new file mode 100644 index 00000000..c554d20e --- /dev/null +++ b/lib/micro-ecc/asm_arm_mult_square_umaal.inc @@ -0,0 +1,1202 @@ +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_ASM_ARM_MULT_SQUARE_H_ +#define _UECC_ASM_ARM_MULT_SQUARE_H_ + +#define FAST_MULT_ASM_5 \ + "push {r3} \n\t" \ + "ldmia r2!, {r3, r4, r5, r6, r7} \n\t" \ + "push {r2} \n\t" \ + \ + "ldr r2, [r1], #4 \n\t" \ + "umull r8, r9, r3, r2 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umaal r9, r10, r4, r2 \n\t" \ + "mov r11, #0 \n\t" \ + "umaal r10, r11, r5, r2 \n\t" \ + "mov r12, #0 \n\t" \ + "umaal r11, r12, r6, r2 \n\t" \ + "mov r14, #0 \n\t" \ + "umaal r12, r14, r7, r2 \n\t" \ + \ + "ldr r2, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r3, r2 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r4, r2 \n\t" \ + "umaal r10, r11, r5, r2 \n\t" \ + "umaal r11, r12, r6, r2 \n\t" \ + "umaal r12, r14, r7, r2 \n\t" \ + \ + "ldr r2, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r3, r2 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r4, r2 \n\t" \ + "umaal r10, r11, r5, r2 \n\t" \ + "umaal r11, r12, r6, r2 \n\t" \ + "umaal r12, r14, r7, r2 \n\t" \ + \ + "ldr r2, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r3, r2 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r4, r2 \n\t" \ + "umaal r10, r11, r5, r2 \n\t" \ + "umaal r11, r12, r6, r2 \n\t" \ + "umaal r12, r14, r7, r2 \n\t" \ + \ + "ldr r2, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r3, r2 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r4, r2 \n\t" \ + "umaal r10, r11, r5, r2 \n\t" \ + "umaal r11, r12, r6, r2 \n\t" \ + "umaal r12, r14, r7, r2 \n\t" \ + \ + "str r9, [r0], #4 \n\t" \ + "str r10, [r0], #4 \n\t" \ + "str r11, [r0], #4 \n\t" \ + "str r12, [r0], #4 \n\t" \ + "str r14, [r0], #4 \n\t" \ + \ + "pop {r2, r3} \n\t" + +#define FAST_MULT_ASM_5_TO_6 \ + "cmp r3, #5 \n\t" \ + "beq 1f \n\t" \ + \ + /* r4 = left high */ \ + "ldr r4, [r1] \n\t" \ + \ + "sub r0, #20 \n\t" \ + "sub r1, #20 \n\t" \ + "sub r2, #20 \n\t" \ + \ + /* Do right side */ \ + "ldr r14, [r2], #4 \n\t" \ + "mov r5, #0 \n\t" \ + "ldr r6, [r0], #4 \n\t" \ + "umaal r5, r6, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r7, [r0], #4 \n\t" \ + "umaal r6, r7, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r8, [r0], #4 \n\t" \ + "umaal r7, r8, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r9, [r0], #4 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r10, [r0], #4 \n\t" \ + "umaal r9, r10, r4, r14 \n\t" \ + "sub r0, #20 \n\t" \ + \ + /* r4 = right high */ \ + "ldr r4, [r2], #4 \n\t" \ + \ + /* Do left side */ \ + "ldr r14, [r1], #4 \n\t" \ + "mov r12, #0 \n\t" \ + "umaal r12, r5, r4, r14 \n\t" \ + "str r12, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r5, r6, r4, r14 \n\t" \ + "str r5, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r6, r7, r4, r14 \n\t" \ + "str r6, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r7, r8, r4, r14 \n\t" \ + "str r7, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r9, r10, r4, r14 \n\t" \ + "stmia r0!, {r9, r10} \n\t" + +#define FAST_MULT_ASM_6 \ + "ldmia r2!, {r4, r5, r6} \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "umull r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "mov r11, #0 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "str r9, [r0], #4 \n\t" \ + "str r10, [r0], #4 \n\t" \ + "str r11, [r0], #4 \n\t" \ + \ + "sub r0, #24 \n\t" \ + "sub r1, #24 \n\t" \ + "ldmia r2!, {r4, r5, r6} \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "mov r9, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "mov r11, #0 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "str r9, [r0], #4 \n\t" \ + "str r10, [r0], #4 \n\t" \ + "str r11, [r0], #4 \n\t" + +#define FAST_MULT_ASM_6_TO_7 \ + "cmp r3, #6 \n\t" \ + "beq 1f \n\t" \ + \ + /* r4 = left high */ \ + "ldr r4, [r1] \n\t" \ + \ + "sub r0, #24 \n\t" \ + "sub r1, #24 \n\t" \ + "sub r2, #24 \n\t" \ + \ + /* Do right side */ \ + "ldr r14, [r2], #4 \n\t" \ + "mov r5, #0 \n\t" \ + "ldr r6, [r0], #4 \n\t" \ + "umaal r5, r6, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r7, [r0], #4 \n\t" \ + "umaal r6, r7, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r8, [r0], #4 \n\t" \ + "umaal r7, r8, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r9, [r0], #4 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r10, [r0], #4 \n\t" \ + "umaal r9, r10, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r11, [r0], #4 \n\t" \ + "umaal r10, r11, r4, r14 \n\t" \ + "sub r0, #24 \n\t" \ + \ + /* r4 = right high */ \ + "ldr r4, [r2], #4 \n\t" \ + \ + /* Do left side */ \ + "ldr r14, [r1], #4 \n\t" \ + "mov r12, #0 \n\t" \ + "umaal r12, r5, r4, r14 \n\t" \ + "str r12, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r5, r6, r4, r14 \n\t" \ + "str r5, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r6, r7, r4, r14 \n\t" \ + "str r6, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r7, r8, r4, r14 \n\t" \ + "str r7, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r9, r10, r4, r14 \n\t" \ + "str r9, [r0], #4 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r10, r11, r4, r14 \n\t" \ + "stmia r0!, {r10, r11} \n\t" + +#define FAST_MULT_ASM_7 \ + "ldmia r2!, {r4, r5, r6, r7} \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "umull r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "mov r11, #0 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "mov r12, #0 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "str r9, [r0], #4 \n\t" \ + "str r10, [r0], #4 \n\t" \ + "str r11, [r0], #4 \n\t" \ + "str r12, [r0], #4 \n\t" \ + \ + "sub r0, #28 \n\t" \ + "sub r1, #28 \n\t" \ + "ldmia r2!, {r4, r5, r6} \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "mov r9, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "mov r11, #0 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + \ + "str r9, [r0], #4 \n\t" \ + "str r10, [r0], #4 \n\t" \ + "str r11, [r0], #4 \n\t" + +#define FAST_MULT_ASM_7_TO_8 \ + "cmp r3, #7 \n\t" \ + "beq 1f \n\t" \ + "push {r3} \n\t" \ + \ + /* r4 = left high */ \ + "ldr r4, [r1] \n\t" \ + \ + "sub r0, #28 \n\t" \ + "sub r1, #28 \n\t" \ + "sub r2, #28 \n\t" \ + \ + /* Do right side */ \ + "ldr r14, [r2], #4 \n\t" \ + "mov r5, #0 \n\t" \ + "ldr r6, [r0], #4 \n\t" \ + "umaal r5, r6, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r7, [r0], #4 \n\t" \ + "umaal r6, r7, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r8, [r0], #4 \n\t" \ + "umaal r7, r8, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r9, [r0], #4 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r10, [r0], #4 \n\t" \ + "umaal r9, r10, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r11, [r0], #4 \n\t" \ + "umaal r10, r11, r4, r14 \n\t" \ + "ldr r14, [r2], #4 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "umaal r11, r12, r4, r14 \n\t" \ + "sub r0, #28 \n\t" \ + \ + /* r4 = right high */ \ + "ldr r4, [r2], #4 \n\t" \ + \ + /* Do left side */ \ + "ldr r14, [r1], #4 \n\t" \ + "mov r3, #0 \n\t" \ + "umaal r3, r5, r4, r14 \n\t" \ + "str r3, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r5, r6, r4, r14 \n\t" \ + "str r5, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r6, r7, r4, r14 \n\t" \ + "str r6, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r7, r8, r4, r14 \n\t" \ + "str r7, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r9, r10, r4, r14 \n\t" \ + "str r9, [r0], #4 \n\t" \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r10, r11, r4, r14 \n\t" \ + "str r10, [r0], #4 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "umaal r11, r12, r4, r14 \n\t" \ + "stmia r0!, {r11, r12} \n\t" \ + "pop {r3} \n\t" + +#define FAST_MULT_ASM_8 \ + "ldmia r2!, {r4, r5, r6, r7} \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "umull r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "mov r11, #0 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "mov r12, #0 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "str r9, [r0], #4 \n\t" \ + "str r10, [r0], #4 \n\t" \ + "str r11, [r0], #4 \n\t" \ + "str r12, [r0], #4 \n\t" \ + \ + "sub r0, #32 \n\t" \ + "sub r1, #32 \n\t" \ + "ldmia r2!, {r4, r5, r6, r7} \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "mov r9, #0 \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "mov r10, #0 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "mov r11, #0 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "mov r12, #0 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "ldr r14, [r1], #4 \n\t" \ + "ldr r8, [r0] \n\t" \ + "umaal r8, r9, r4, r14 \n\t" \ + "str r8, [r0], #4 \n\t" \ + "umaal r9, r10, r5, r14 \n\t" \ + "umaal r10, r11, r6, r14 \n\t" \ + "umaal r11, r12, r7, r14 \n\t" \ + \ + "str r9, [r0], #4 \n\t" \ + "str r10, [r0], #4 \n\t" \ + "str r11, [r0], #4 \n\t" \ + "str r12, [r0], #4 \n\t" + +#define FAST_SQUARE_ASM_5 \ + "ldmia r1!, {r9,r10,r11,r12,r14} \n\t" \ + "push {r1, r2} \n\t" \ + \ + "umull r1, r2, r10, r9 \n\t" \ + "mov r3, #0 \n\t" \ + "umaal r2, r3, r11, r9 \n\t" \ + "mov r4, #0 \n\t" \ + "umaal r3, r4, r12, r9 \n\t" \ + "mov r5, #0 \n\t" \ + "umaal r4, r5, r14, r9 \n\t" \ + \ + "mov r6, #0 \n\t" \ + "umaal r6, r3, r11, r10 \n\t" \ + "umaal r3, r4, r12, r10 \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r2, r2, r2 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + "adcs r3, r3, r3 \n\t" \ + \ + "umull r7, r8, r9, r9 \n\t" \ + /* Store carry in r9 */ \ + "mov r9, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + "adds r8, r8, r1 \n\t" \ + "stmia r0!, {r7,r8} \n\t" \ + \ + "umull r7, r8, r10, r10 \n\t" \ + "adcs r7, r7, r2 \n\t" \ + "adcs r8, r8, r6 \n\t" \ + "stmia r0!, {r7,r8} \n\t" \ + \ + "umaal r4, r5, r14, r10 \n\t" \ + /* Store carry in r10 */ \ + "mov r10, #0 \n\t" \ + "adc r10, r10, #0 \n\t" \ + \ + "mov r1, #0 \n\t" \ + "umaal r1, r4, r12, r11 \n\t" \ + "umaal r4, r5, r14, r11 \n\t" \ + \ + "mov r2, #0 \n\t" \ + "umaal r2, r5, r14, r12 \n\t" \ + /* Load carry from r9 */ \ + "lsrs r9, #1 \n\t" \ + "adcs r1, r1, r1 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r2, r2, r2 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + /* r9 is 0 now */ \ + "adc r9, r9, #0 \n\t" \ + \ + /* Use carry from r10 */ \ + "umaal r3, r10, r11, r11 \n\t" \ + "adds r10, r10, r1 \n\t" \ + "stmia r0!, {r3,r10} \n\t" \ + \ + "umull r6, r10, r12, r12 \n\t" \ + "adcs r6, r6, r4 \n\t" \ + "adcs r10, r10, r2 \n\t" \ + "stmia r0!, {r6,r10} \n\t" \ + \ + "umull r6, r10, r14, r14 \n\t" \ + "adcs r6, r6, r5 \n\t" \ + "adcs r10, r10, r9 \n\t" \ + "stmia r0!, {r6,r10} \n\t" \ + "pop {r1, r2} \n\t" + +#define FAST_SQUARE_ASM_5_TO_6 \ + "cmp r2, #5 \n\t" \ + "beq 1f \n\t" \ + \ + "sub r0, #20 \n\t" \ + "sub r1, #20 \n\t" \ + \ + /* Do off-center multiplication */ \ + "ldmia r1!, {r5,r6,r7,r8,r9,r14} \n\t" \ + "umull r3, r4, r5, r14 \n\t" \ + "mov r5, #0 \n\t" \ + "umaal r4, r5, r6, r14 \n\t" \ + "mov r6, #0 \n\t" \ + "umaal r5, r6, r7, r14 \n\t" \ + "mov r7, #0 \n\t" \ + "umaal r6, r7, r8, r14 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r7, r8, r9, r14 \n\t" \ + \ + /* Multiply by 2 */ \ + "mov r9, #0 \n\t" \ + "adds r3, r3, r3 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + "adcs r7, r7, r7 \n\t" \ + "adcs r8, r8, r8 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + \ + /* Add into previous */ \ + "ldr r12, [r0], #4 \n\t" \ + "adds r3, r3, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r4, r4, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r5, r5, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r6, r6, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r7, r7, r12 \n\t" \ + "adcs r8, r8, #0 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "sub r0, #20 \n\t" \ + \ + /* Perform center multiplication */ \ + "umlal r8, r9, r14, r14 \n\t" \ + "stmia r0!, {r3,r4,r5,r6,r7,r8,r9} \n\t" + +#define FAST_SQUARE_ASM_6 \ + "ldmia r1!, {r8,r9,r10,r11,r12,r14} \n\t" \ + "push {r1, r2} \n\t" \ + \ + "umull r1, r2, r9, r8 \n\t" \ + "mov r3, #0 \n\t" \ + "umaal r2, r3, r10, r8 \n\t" \ + "mov r4, #0 \n\t" \ + "umaal r3, r4, r11, r8 \n\t" \ + "mov r5, #0 \n\t" \ + "umaal r4, r5, r12, r8 \n\t" \ + "mov r6, #0 \n\t" \ + "umaal r5, r6, r14, r8 \n\t" \ + \ + "mov r7, #0 \n\t" \ + "umaal r7, r3, r10, r9 \n\t" \ + "umaal r3, r4, r11, r9 \n\t" \ + "umaal r4, r5, r12, r9 \n\t" \ + "push {r4, r5} \n\t" \ + "adds r1, r1, r1 \n\t" \ + "adcs r2, r2, r2 \n\t" \ + "adcs r7, r7, r7 \n\t" \ + "adcs r3, r3, r3 \n\t" \ + \ + "umull r4, r5, r8, r8 \n\t" \ + /* Store carry in r8 */ \ + "mov r8, #0 \n\t" \ + "adc r8, r8, #0 \n\t" \ + "adds r5, r5, r1 \n\t" \ + "stmia r0!, {r4,r5} \n\t" \ + \ + "umull r4, r5, r9, r9 \n\t" \ + "adcs r4, r4, r2 \n\t" \ + "adcs r5, r5, r7 \n\t" \ + "stmia r0!, {r4,r5} \n\t" \ + \ + "pop {r4, r5} \n\t" \ + "umaal r5, r6, r14, r9 \n\t" \ + /* Store carry in r9 */ \ + "mov r9, #0 \n\t" \ + "adc r9, r9, #0 \n\t" \ + \ + "mov r1, #0 \n\t" \ + "umaal r1, r4, r11, r10 \n\t" \ + "umaal r4, r5, r12, r10 \n\t" \ + "umaal r5, r6, r14, r10 \n\t" \ + \ + "mov r2, #0 \n\t" \ + "umaal r2, r5, r12, r11 \n\t" \ + "umaal r5, r6, r14, r11 \n\t" \ + \ + "mov r7, #0 \n\t" \ + "umaal r7, r6, r14, r12 \n\t" \ + \ + /* Load carry from r8 */ \ + "lsrs r8, #1 \n\t" \ + "adcs r1, r1, r1 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r2, r2, r2 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + "adcs r7, r7, r7 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + "adc r8, r8, #0 \n\t" \ + \ + /* Use carry from r9 */ \ + "umaal r3, r9, r10, r10 \n\t" \ + "adds r9, r9, r1 \n\t" \ + "stmia r0!, {r3,r9} \n\t" \ + \ + "umull r9, r10, r11, r11 \n\t" \ + "adcs r9, r9, r4 \n\t" \ + "adcs r10, r10, r2 \n\t" \ + "stmia r0!, {r9,r10} \n\t" \ + \ + "umull r9, r10, r12, r12 \n\t" \ + "adcs r9, r9, r5 \n\t" \ + "adcs r10, r10, r7 \n\t" \ + "stmia r0!, {r9,r10} \n\t" \ + \ + "umull r9, r10, r14, r14 \n\t" \ + "adcs r9, r9, r6 \n\t" \ + "adcs r10, r10, r8 \n\t" \ + "stmia r0!, {r9,r10} \n\t" \ + "pop {r1, r2} \n\t" + +#define FAST_SQUARE_ASM_6_TO_7 \ + "cmp r2, #6 \n\t" \ + "beq 1f \n\t" \ + \ + "sub r0, #24 \n\t" \ + "sub r1, #24 \n\t" \ + \ + /* Do off-center multiplication */ \ + "ldmia r1!, {r5,r6,r7,r8,r9,r10,r14} \n\t" \ + "umull r3, r4, r5, r14 \n\t" \ + "mov r5, #0 \n\t" \ + "umaal r4, r5, r6, r14 \n\t" \ + "mov r6, #0 \n\t" \ + "umaal r5, r6, r7, r14 \n\t" \ + "mov r7, #0 \n\t" \ + "umaal r6, r7, r8, r14 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r7, r8, r9, r14 \n\t" \ + "mov r9, #0 \n\t" \ + "umaal r8, r9, r10, r14 \n\t" \ + \ + /* Multiply by 2 */ \ + "mov r10, #0 \n\t" \ + "adds r3, r3, r3 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + "adcs r7, r7, r7 \n\t" \ + "adcs r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + \ + /* Add into previous */ \ + "ldr r12, [r0], #4 \n\t" \ + "adds r3, r3, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r4, r4, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r5, r5, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r6, r6, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r7, r7, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r8, r8, r12 \n\t" \ + "adcs r9, r9, #0 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "sub r0, #24 \n\t" \ + \ + /* Perform center multiplication */ \ + "umlal r9, r10, r14, r14 \n\t" \ + "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10} \n\t" + +#define FAST_SQUARE_ASM_7 \ + "ldmia r1!, {r9,r10,r11,r12} \n\t" \ + "push {r2} \n\t" \ + \ + "umull r14, r2, r10, r9 \n\t" \ + "mov r3, #0 \n\t" \ + "umaal r2, r3, r11, r9 \n\t" \ + "mov r4, #0 \n\t" \ + "umaal r3, r4, r12, r9 \n\t" \ + \ + "mov r5, #0 \n\t" \ + "umaal r5, r3, r11, r10 \n\t" \ + "adds r14, r14, r14 \n\t" \ + "adcs r2, r2, r2 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + /* Store carry in r7 */ \ + "mov r7, #0 \n\t" \ + "adc r7, r7, #0 \n\t" \ + \ + "umull r6, r8, r9, r9 \n\t" \ + "adds r8, r8, r14 \n\t" \ + "stmia r0!, {r6,r8} \n\t" \ + \ + "umull r6, r8, r10, r10 \n\t" \ + "adcs r6, r6, r2 \n\t" \ + "adcs r8, r8, r5 \n\t" \ + "stmia r0!, {r6,r8} \n\t" \ + /* Store carry in r8 */ \ + "mov r8, #0 \n\t" \ + "adc r8, r8, #0 \n\t" \ + \ + "ldmia r1!, {r2, r6, r14} \n\t" \ + "push {r1} \n\t" \ + "umaal r3, r4, r2, r9 \n\t" \ + "mov r5, #0 \n\t" \ + "umaal r4, r5, r6, r9 \n\t" \ + "mov r1, #0 \n\t" \ + "umaal r5, r1, r14, r9 \n\t" \ + \ + "mov r9, #0 \n\t" \ + "umaal r3, r9, r12, r10 \n\t" \ + "umaal r9, r4, r2, r10 \n\t" \ + "umaal r4, r5, r6, r10 \n\t" \ + "umaal r5, r1, r14, r10 \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umaal r10, r9, r12, r11 \n\t" \ + "umaal r9, r4, r2, r11 \n\t" \ + "umaal r4, r5, r6, r11 \n\t" \ + "umaal r5, r1, r14, r11 \n\t" \ + \ + /* Load carry from r7 */ \ + "lsrs r7, #1 \n\t" \ + "adcs r3, r3, r3 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + /* Store carry back in r7 */ \ + "adc r7, r7, #0 \n\t" \ + \ + /* Use carry from r8 */ \ + "umaal r3, r8, r11, r11 \n\t" \ + "adds r8, r8, r10 \n\t" \ + "stmia r0!, {r3,r8} \n\t" \ + /* Store carry back in r8 */ \ + "mov r8, #0 \n\t" \ + "adc r8, r8, #0 \n\t" \ + \ + "mov r3, #0 \n\t" \ + "umaal r3, r4, r2, r12 \n\t" \ + "umaal r4, r5, r6, r12 \n\t" \ + "umaal r5, r1, r14, r12 \n\t" \ + \ + "mov r10, #0 \n\t" \ + "umaal r10, r5, r6, r2 \n\t" \ + "umaal r5, r1, r14, r2 \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umaal r11, r1, r14, r6 \n\t" \ + \ + /* Load carry from r7 */ \ + "lsrs r7, #1 \n\t" \ + "adcs r3, r3, r3 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adcs r1, r1, r1 \n\t" \ + "adc r7, r7, #0 \n\t" \ + \ + /* Use carry from r8 */ \ + "umaal r8, r9, r12, r12 \n\t" \ + "adds r9, r9, r3 \n\t" \ + "stmia r0!, {r8,r9} \n\t" \ + \ + "umull r8, r9, r2, r2 \n\t" \ + "adcs r8, r8, r4 \n\t" \ + "adcs r9, r9, r10 \n\t" \ + "stmia r0!, {r8,r9} \n\t" \ + \ + "umull r8, r9, r6, r6 \n\t" \ + "adcs r8, r8, r5 \n\t" \ + "adcs r9, r9, r11 \n\t" \ + "stmia r0!, {r8,r9} \n\t" \ + \ + "umull r8, r9, r14, r14 \n\t" \ + "adcs r8, r8, r1 \n\t" \ + "adcs r9, r9, r7 \n\t" \ + "stmia r0!, {r8,r9} \n\t" \ + "pop {r1, r2} \n\t" + +#define FAST_SQUARE_ASM_7_TO_8 \ + "cmp r2, #7 \n\t" \ + "beq 1f \n\t" \ + \ + "sub r0, #28 \n\t" \ + "sub r1, #28 \n\t" \ + \ + /* Do off-center multiplication */ \ + "ldmia r1!, {r5,r6,r7,r8,r9,r10,r11,r14} \n\t" \ + "umull r3, r4, r5, r14 \n\t" \ + "mov r5, #0 \n\t" \ + "umaal r4, r5, r6, r14 \n\t" \ + "mov r6, #0 \n\t" \ + "umaal r5, r6, r7, r14 \n\t" \ + "mov r7, #0 \n\t" \ + "umaal r6, r7, r8, r14 \n\t" \ + "mov r8, #0 \n\t" \ + "umaal r7, r8, r9, r14 \n\t" \ + "mov r9, #0 \n\t" \ + "umaal r8, r9, r10, r14 \n\t" \ + "mov r10, #0 \n\t" \ + "umaal r9, r10, r11, r14 \n\t" \ + \ + /* Multiply by 2 */ \ + "mov r11, #0 \n\t" \ + "adds r3, r3, r3 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + "adcs r7, r7, r7 \n\t" \ + "adcs r8, r8, r8 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adcs r10, r10, r10 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + \ + /* Add into previous */ \ + "ldr r12, [r0], #4 \n\t" \ + "adds r3, r3, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r4, r4, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r5, r5, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r6, r6, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r7, r7, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r8, r8, r12 \n\t" \ + "ldr r12, [r0], #4 \n\t" \ + "adcs r9, r9, r12 \n\t" \ + "adcs r10, r10, #0 \n\t" \ + "adcs r11, r11, #0 \n\t" \ + "sub r0, #28 \n\t" \ + \ + /* Perform center multiplication */ \ + "umlal r10, r11, r14, r14 \n\t" \ + "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} \n\t" + +#define FAST_SQUARE_ASM_8 \ + "ldmia r1!, {r10,r11,r12,r14} \n\t" \ + "push {r2} \n\t" \ + \ + "umull r2, r3, r11, r10 \n\t" \ + "mov r4, #0 \n\t" \ + "umaal r3, r4, r12, r10 \n\t" \ + "mov r5, #0 \n\t" \ + "umaal r4, r5, r14, r10 \n\t" \ + \ + "mov r6, #0 \n\t" \ + "umaal r6, r4, r12, r11 \n\t" \ + "adds r2, r2, r2 \n\t" \ + "adcs r3, r3, r3 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + /* Store carry in r7 */ \ + "mov r7, #0 \n\t" \ + "adc r7, r7, #0 \n\t" \ + \ + "umull r8, r9, r10, r10 \n\t" \ + "adds r9, r9, r2 \n\t" \ + "stmia r0!, {r8,r9} \n\t" \ + \ + "umull r8, r9, r11, r11 \n\t" \ + "adcs r8, r8, r3 \n\t" \ + "adcs r9, r9, r6 \n\t" \ + "stmia r0!, {r8,r9} \n\t" \ + /* Store carry in r8 */ \ + "mov r8, #0 \n\t" \ + "adc r8, r8, #0 \n\t" \ + \ + "ldmia r1!, {r2, r3} \n\t" \ + "push {r1} \n\t" \ + "umaal r4, r5, r2, r10 \n\t" \ + "mov r6, #0 \n\t" \ + "umaal r5, r6, r3, r10 \n\t" \ + \ + "mov r9, #0 \n\t" \ + "umaal r9, r4, r14, r11 \n\t" \ + "umaal r4, r5, r2, r11 \n\t" \ + \ + "mov r1, #0 \n\t" \ + "umaal r1, r4, r14, r12 \n\t" \ + \ + /* Load carry from r7 */ \ + "lsrs r7, #1 \n\t" \ + "adcs r9, r9, r9 \n\t" \ + "adcs r1, r1, r1 \n\t" \ + /* Store carry back in r7 */ \ + "adc r7, r7, #0 \n\t" \ + \ + /* Use carry from r8 */ \ + "umaal r8, r9, r12, r12 \n\t" \ + "adds r9, r9, r1 \n\t" \ + "stmia r0!, {r8,r9} \n\t" \ + /* Store carry back in r8 */ \ + "mov r8, #0 \n\t" \ + "adc r8, r8, #0 \n\t" \ + \ + "pop {r1} \n\t" \ + /* TODO could fix up r1 value on stack here */ \ + /* and leave the value on the stack (rather */ \ + /* than popping) if supporting curves > 256 bits */ \ + "ldr r9, [r1], #4 \n\t" \ + "ldr r1, [r1] \n\t" \ + \ + "push {r7} \n\t" \ + "umaal r5, r6, r9, r10 \n\t" \ + "mov r7, #0 \n\t" \ + "umaal r6, r7, r1, r10 \n\t" \ + /* Carry now stored in r10 */ \ + "pop {r10} \n\t" \ + \ + "umaal r4, r5, r3, r11 \n\t" \ + "umaal r5, r6, r9, r11 \n\t" \ + "umaal r6, r7, r1, r11 \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umaal r11, r4, r2, r12 \n\t" \ + "umaal r4, r5, r3, r12 \n\t" \ + "umaal r5, r6, r9, r12 \n\t" \ + "umaal r6, r7, r1, r12 \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umaal r12, r4, r2, r14 \n\t" \ + "umaal r4, r5, r3, r14 \n\t" \ + "umaal r5, r6, r9, r14 \n\t" \ + "umaal r6, r7, r1, r14 \n\t" \ + \ + /* Load carry from r10 */ \ + "lsrs r10, #1 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adcs r12, r12, r12 \n\t" \ + "adc r10, r10, #0 \n\t" \ + \ + /* Use carry from r8 */ \ + "umaal r8, r11, r14, r14 \n\t" \ + "adds r11, r11, r12 \n\t" \ + "stmia r0!, {r8,r11} \n\t" \ + /* Store carry back in r8 */ \ + "mov r8, #0 \n\t" \ + "adc r8, r8, #0 \n\t" \ + \ + "mov r11, #0 \n\t" \ + "umaal r11, r5, r3, r2 \n\t" \ + "umaal r5, r6, r9, r2 \n\t" \ + "umaal r6, r7, r1, r2 \n\t" \ + \ + "mov r12, #0 \n\t" \ + "umaal r12, r6, r9, r3 \n\t" \ + "umaal r6, r7, r1, r3 \n\t" \ + \ + "mov r14, #0 \n\t" \ + "umaal r14, r7, r1, r9 \n\t" \ + \ + /* Load carry from r10 */ \ + "lsrs r10, #1 \n\t" \ + "adcs r4, r4, r4 \n\t" \ + "adcs r11, r11, r11 \n\t" \ + "adcs r5, r5, r5 \n\t" \ + "adcs r12, r12, r12 \n\t" \ + "adcs r6, r6, r6 \n\t" \ + "adcs r14, r14, r14 \n\t" \ + "adcs r7, r7, r7 \n\t" \ + "adc r10, r10, #0 \n\t" \ + \ + /* Use carry from r8 */ \ + "umaal r4, r8, r2, r2 \n\t" \ + "adds r8, r8, r11 \n\t" \ + "stmia r0!, {r4,r8} \n\t" \ + \ + "umull r4, r8, r3, r3 \n\t" \ + "adcs r4, r4, r5 \n\t" \ + "adcs r8, r8, r12 \n\t" \ + "stmia r0!, {r4,r8} \n\t" \ + \ + "umull r4, r8, r9, r9 \n\t" \ + "adcs r4, r4, r6 \n\t" \ + "adcs r8, r8, r14 \n\t" \ + "stmia r0!, {r4,r8} \n\t" \ + \ + "umull r4, r8, r1, r1 \n\t" \ + "adcs r4, r4, r7 \n\t" \ + "adcs r8, r8, r10 \n\t" \ + "stmia r0!, {r4,r8} \n\t" \ + /* TODO pop {r1, r2} if supporting curves > 256 bits */ \ + "pop {r2} \n\t" + +#endif /* _UECC_ASM_ARM_MULT_SQUARE_H_ */ diff --git a/lib/micro-ecc/curve-specific.inc b/lib/micro-ecc/curve-specific.inc new file mode 100644 index 00000000..0453b212 --- /dev/null +++ b/lib/micro-ecc/curve-specific.inc @@ -0,0 +1,1248 @@ +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_CURVE_SPECIFIC_H_ +#define _UECC_CURVE_SPECIFIC_H_ + +#define num_bytes_secp160r1 20 +#define num_bytes_secp192r1 24 +#define num_bytes_secp224r1 28 +#define num_bytes_secp256r1 32 +#define num_bytes_secp256k1 32 + +#if (uECC_WORD_SIZE == 1) + +#define num_words_secp160r1 20 +#define num_words_secp192r1 24 +#define num_words_secp224r1 28 +#define num_words_secp256r1 32 +#define num_words_secp256k1 32 + +#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) \ + 0x##a, 0x##b, 0x##c, 0x##d, 0x##e, 0x##f, 0x##g, 0x##h +#define BYTES_TO_WORDS_4(a, b, c, d) 0x##a, 0x##b, 0x##c, 0x##d + +#elif (uECC_WORD_SIZE == 4) + +#define num_words_secp160r1 5 +#define num_words_secp192r1 6 +#define num_words_secp224r1 7 +#define num_words_secp256r1 8 +#define num_words_secp256k1 8 + +#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e +#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a + +#elif (uECC_WORD_SIZE == 8) + +#define num_words_secp160r1 3 +#define num_words_secp192r1 3 +#define num_words_secp224r1 4 +#define num_words_secp256r1 4 +#define num_words_secp256k1 4 + +#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##h##g##f##e##d##c##b##a##ull +#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a##ull + +#endif /* uECC_WORD_SIZE */ + +#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \ + uECC_SUPPORTS_secp224r1 || uECC_SUPPORTS_secp256r1 +static void double_jacobian_default(uECC_word_t * X1, + uECC_word_t * Y1, + uECC_word_t * Z1, + uECC_Curve curve) { + /* t1 = X, t2 = Y, t3 = Z */ + uECC_word_t t4[uECC_MAX_WORDS]; + uECC_word_t t5[uECC_MAX_WORDS]; + wordcount_t num_words = curve->num_words; + + if (uECC_vli_isZero(Z1, num_words)) { + return; + } + + uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */ + uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */ + uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */ + uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */ + uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */ + + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ + uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */ + uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */ + uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */ + + uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */ + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */ + if (uECC_vli_testBit(X1, 0)) { + uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); + uECC_vli_rshift1(X1, num_words); + X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1); + } else { + uECC_vli_rshift1(X1, num_words); + } + /* t1 = 3/2*(x1^2 - z1^4) = B */ + + uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */ + uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */ + uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */ + uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */ + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */ + uECC_vli_modSub(t4, X1, t4, curve->p, num_words); /* t4 = B * (A - x3) - y1^4 = y3 */ + + uECC_vli_set(X1, Z1, num_words); + uECC_vli_set(Z1, Y1, num_words); + uECC_vli_set(Y1, t4, num_words); +} + +/* Computes result = x^3 + ax + b. result must not overlap x. */ +static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { + uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */ + wordcount_t num_words = curve->num_words; + + uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ + uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ + uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */ + uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); /* r = x^3 - 3x + b */ +} +#endif /* uECC_SUPPORTS_secp... */ + +#if uECC_SUPPORT_COMPRESSED_POINT +#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \ + uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1 +/* Compute a = sqrt(a) (mod curve_p). */ +static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) { + bitcount_t i; + uECC_word_t p1[uECC_MAX_WORDS] = {1}; + uECC_word_t l_result[uECC_MAX_WORDS] = {1}; + wordcount_t num_words = curve->num_words; + + /* When curve->p == 3 (mod 4), we can compute + sqrt(a) = a^((curve->p + 1) / 4) (mod curve->p). */ + uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */ + for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) { + uECC_vli_modSquare_fast(l_result, l_result, curve); + if (uECC_vli_testBit(p1, i)) { + uECC_vli_modMult_fast(l_result, l_result, a, curve); + } + } + uECC_vli_set(a, l_result, num_words); +} +#endif /* uECC_SUPPORTS_secp... */ +#endif /* uECC_SUPPORT_COMPRESSED_POINT */ + +#if uECC_SUPPORTS_secp160r1 + +#if (uECC_OPTIMIZATION_LEVEL > 0) +static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product); +#endif + +static const struct uECC_Curve_t curve_secp160r1 = { + num_words_secp160r1, + num_bytes_secp160r1, + 161, /* num_n_bits */ + { BYTES_TO_WORDS_8(FF, FF, FF, 7F, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_4(FF, FF, FF, FF) }, + { BYTES_TO_WORDS_8(57, 22, 75, CA, D3, AE, 27, F9), + BYTES_TO_WORDS_8(C8, F4, 01, 00, 00, 00, 00, 00), + BYTES_TO_WORDS_8(00, 00, 00, 00, 01, 00, 00, 00) }, + { BYTES_TO_WORDS_8(82, FC, CB, 13, B9, 8B, C3, 68), + BYTES_TO_WORDS_8(89, 69, 64, 46, 28, 73, F5, 8E), + BYTES_TO_WORDS_4(68, B5, 96, 4A), + + BYTES_TO_WORDS_8(32, FB, C5, 7A, 37, 51, 23, 04), + BYTES_TO_WORDS_8(12, C9, DC, 59, 7D, 94, 68, 31), + BYTES_TO_WORDS_4(55, 28, A6, 23) }, + { BYTES_TO_WORDS_8(45, FA, 65, C5, AD, D4, D4, 81), + BYTES_TO_WORDS_8(9F, F8, AC, 65, 8B, 7A, BD, 54), + BYTES_TO_WORDS_4(FC, BE, 97, 1C) }, + &double_jacobian_default, +#if uECC_SUPPORT_COMPRESSED_POINT + &mod_sqrt_default, +#endif + &x_side_default, +#if (uECC_OPTIMIZATION_LEVEL > 0) + &vli_mmod_fast_secp160r1 +#endif +}; + +uECC_Curve uECC_secp160r1(void) { return &curve_secp160r1; } + +#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) +/* Computes result = product % curve_p + see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354 + + Note that this only works if log2(omega) < log2(p) / 2 */ +static void omega_mult_secp160r1(uECC_word_t *result, const uECC_word_t *right); +#if uECC_WORD_SIZE == 8 +static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) { + uECC_word_t tmp[2 * num_words_secp160r1]; + uECC_word_t copy; + + uECC_vli_clear(tmp, num_words_secp160r1); + uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1); + + omega_mult_secp160r1(tmp, product + num_words_secp160r1 - 1); /* (Rq, q) = q * c */ + + product[num_words_secp160r1 - 1] &= 0xffffffff; + copy = tmp[num_words_secp160r1 - 1]; + tmp[num_words_secp160r1 - 1] &= 0xffffffff; + uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */ + uECC_vli_clear(product, num_words_secp160r1); + tmp[num_words_secp160r1 - 1] = copy; + omega_mult_secp160r1(product, tmp + num_words_secp160r1 - 1); /* Rq*c */ + uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */ + + while (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) { + uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); + } +} + +static void omega_mult_secp160r1(uint64_t *result, const uint64_t *right) { + uint32_t carry; + unsigned i; + + /* Multiply by (2^31 + 1). */ + carry = 0; + for (i = 0; i < num_words_secp160r1; ++i) { + uint64_t tmp = (right[i] >> 32) | (right[i + 1] << 32); + result[i] = (tmp << 31) + tmp + carry; + carry = (tmp >> 33) + (result[i] < tmp || (carry && result[i] == tmp)); + } + result[i] = carry; +} +#else +static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) { + uECC_word_t tmp[2 * num_words_secp160r1]; + uECC_word_t carry; + + uECC_vli_clear(tmp, num_words_secp160r1); + uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1); + + omega_mult_secp160r1(tmp, product + num_words_secp160r1); /* (Rq, q) = q * c */ + + carry = uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */ + uECC_vli_clear(product, num_words_secp160r1); + omega_mult_secp160r1(product, tmp + num_words_secp160r1); /* Rq*c */ + carry += uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */ + + while (carry > 0) { + --carry; + uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); + } + if (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) { + uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); + } +} +#endif + +#if uECC_WORD_SIZE == 1 +static void omega_mult_secp160r1(uint8_t *result, const uint8_t *right) { + uint8_t carry; + uint8_t i; + + /* Multiply by (2^31 + 1). */ + uECC_vli_set(result + 4, right, num_words_secp160r1); /* 2^32 */ + uECC_vli_rshift1(result + 4, num_words_secp160r1); /* 2^31 */ + result[3] = right[0] << 7; /* get last bit from shift */ + + carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */ + for (i = num_words_secp160r1; carry; ++i) { + uint16_t sum = (uint16_t)result[i] + carry; + result[i] = (uint8_t)sum; + carry = sum >> 8; + } +} +#elif uECC_WORD_SIZE == 4 +static void omega_mult_secp160r1(uint32_t *result, const uint32_t *right) { + uint32_t carry; + unsigned i; + + /* Multiply by (2^31 + 1). */ + uECC_vli_set(result + 1, right, num_words_secp160r1); /* 2^32 */ + uECC_vli_rshift1(result + 1, num_words_secp160r1); /* 2^31 */ + result[0] = right[0] << 31; /* get last bit from shift */ + + carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */ + for (i = num_words_secp160r1; carry; ++i) { + uint64_t sum = (uint64_t)result[i] + carry; + result[i] = (uint32_t)sum; + carry = sum >> 32; + } +} +#endif /* uECC_WORD_SIZE */ +#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) */ + +#endif /* uECC_SUPPORTS_secp160r1 */ + +#if uECC_SUPPORTS_secp192r1 + +#if (uECC_OPTIMIZATION_LEVEL > 0) +static void vli_mmod_fast_secp192r1(uECC_word_t *result, uECC_word_t *product); +#endif + +static const struct uECC_Curve_t curve_secp192r1 = { + num_words_secp192r1, + num_bytes_secp192r1, + 192, /* num_n_bits */ + { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, + { BYTES_TO_WORDS_8(31, 28, D2, B4, B1, C9, 6B, 14), + BYTES_TO_WORDS_8(36, F8, DE, 99, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, + { BYTES_TO_WORDS_8(12, 10, FF, 82, FD, 0A, FF, F4), + BYTES_TO_WORDS_8(00, 88, A1, 43, EB, 20, BF, 7C), + BYTES_TO_WORDS_8(F6, 90, 30, B0, 0E, A8, 8D, 18), + + BYTES_TO_WORDS_8(11, 48, 79, 1E, A1, 77, F9, 73), + BYTES_TO_WORDS_8(D5, CD, 24, 6B, ED, 11, 10, 63), + BYTES_TO_WORDS_8(78, DA, C8, FF, 95, 2B, 19, 07) }, + { BYTES_TO_WORDS_8(B1, B9, 46, C1, EC, DE, B8, FE), + BYTES_TO_WORDS_8(49, 30, 24, 72, AB, E9, A7, 0F), + BYTES_TO_WORDS_8(E7, 80, 9C, E5, 19, 05, 21, 64) }, + &double_jacobian_default, +#if uECC_SUPPORT_COMPRESSED_POINT + &mod_sqrt_default, +#endif + &x_side_default, +#if (uECC_OPTIMIZATION_LEVEL > 0) + &vli_mmod_fast_secp192r1 +#endif +}; + +uECC_Curve uECC_secp192r1(void) { return &curve_secp192r1; } + +#if (uECC_OPTIMIZATION_LEVEL > 0) +/* Computes result = product % curve_p. + See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */ +#if uECC_WORD_SIZE == 1 +static void vli_mmod_fast_secp192r1(uint8_t *result, uint8_t *product) { + uint8_t tmp[num_words_secp192r1]; + uint8_t carry; + + uECC_vli_set(result, product, num_words_secp192r1); + + uECC_vli_set(tmp, &product[24], num_words_secp192r1); + carry = uECC_vli_add(result, result, tmp, num_words_secp192r1); + + tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; + tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27]; + tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31]; + tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35]; + tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39]; + carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); + + tmp[0] = tmp[8] = product[40]; + tmp[1] = tmp[9] = product[41]; + tmp[2] = tmp[10] = product[42]; + tmp[3] = tmp[11] = product[43]; + tmp[4] = tmp[12] = product[44]; + tmp[5] = tmp[13] = product[45]; + tmp[6] = tmp[14] = product[46]; + tmp[7] = tmp[15] = product[47]; + tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; + carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); + + while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) { + carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); + } +} +#elif uECC_WORD_SIZE == 4 +static void vli_mmod_fast_secp192r1(uint32_t *result, uint32_t *product) { + uint32_t tmp[num_words_secp192r1]; + int carry; + + uECC_vli_set(result, product, num_words_secp192r1); + + uECC_vli_set(tmp, &product[6], num_words_secp192r1); + carry = uECC_vli_add(result, result, tmp, num_words_secp192r1); + + tmp[0] = tmp[1] = 0; + tmp[2] = product[6]; + tmp[3] = product[7]; + tmp[4] = product[8]; + tmp[5] = product[9]; + carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); + + tmp[0] = tmp[2] = product[10]; + tmp[1] = tmp[3] = product[11]; + tmp[4] = tmp[5] = 0; + carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); + + while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) { + carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); + } +} +#else +static void vli_mmod_fast_secp192r1(uint64_t *result, uint64_t *product) { + uint64_t tmp[num_words_secp192r1]; + int carry; + + uECC_vli_set(result, product, num_words_secp192r1); + + uECC_vli_set(tmp, &product[3], num_words_secp192r1); + carry = (int)uECC_vli_add(result, result, tmp, num_words_secp192r1); + + tmp[0] = 0; + tmp[1] = product[3]; + tmp[2] = product[4]; + carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); + + tmp[0] = tmp[1] = product[5]; + tmp[2] = 0; + carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); + + while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) { + carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); + } +} +#endif /* uECC_WORD_SIZE */ +#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */ + +#endif /* uECC_SUPPORTS_secp192r1 */ + +#if uECC_SUPPORTS_secp224r1 + +#if uECC_SUPPORT_COMPRESSED_POINT +static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve); +#endif +#if (uECC_OPTIMIZATION_LEVEL > 0) +static void vli_mmod_fast_secp224r1(uECC_word_t *result, uECC_word_t *product); +#endif + +static const struct uECC_Curve_t curve_secp224r1 = { + num_words_secp224r1, + num_bytes_secp224r1, + 224, /* num_n_bits */ + { BYTES_TO_WORDS_8(01, 00, 00, 00, 00, 00, 00, 00), + BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_4(FF, FF, FF, FF) }, + { BYTES_TO_WORDS_8(3D, 2A, 5C, 5C, 45, 29, DD, 13), + BYTES_TO_WORDS_8(3E, F0, B8, E0, A2, 16, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_4(FF, FF, FF, FF) }, + { BYTES_TO_WORDS_8(21, 1D, 5C, 11, D6, 80, 32, 34), + BYTES_TO_WORDS_8(22, 11, C2, 56, D3, C1, 03, 4A), + BYTES_TO_WORDS_8(B9, 90, 13, 32, 7F, BF, B4, 6B), + BYTES_TO_WORDS_4(BD, 0C, 0E, B7), + + BYTES_TO_WORDS_8(34, 7E, 00, 85, 99, 81, D5, 44), + BYTES_TO_WORDS_8(64, 47, 07, 5A, A0, 75, 43, CD), + BYTES_TO_WORDS_8(E6, DF, 22, 4C, FB, 23, F7, B5), + BYTES_TO_WORDS_4(88, 63, 37, BD) }, + { BYTES_TO_WORDS_8(B4, FF, 55, 23, 43, 39, 0B, 27), + BYTES_TO_WORDS_8(BA, D8, BF, D7, B7, B0, 44, 50), + BYTES_TO_WORDS_8(56, 32, 41, F5, AB, B3, 04, 0C), + BYTES_TO_WORDS_4(85, 0A, 05, B4) }, + &double_jacobian_default, +#if uECC_SUPPORT_COMPRESSED_POINT + &mod_sqrt_secp224r1, +#endif + &x_side_default, +#if (uECC_OPTIMIZATION_LEVEL > 0) + &vli_mmod_fast_secp224r1 +#endif +}; + +uECC_Curve uECC_secp224r1(void) { return &curve_secp224r1; } + + +#if uECC_SUPPORT_COMPRESSED_POINT +/* Routine 3.2.4 RS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ +static void mod_sqrt_secp224r1_rs(uECC_word_t *d1, + uECC_word_t *e1, + uECC_word_t *f1, + const uECC_word_t *d0, + const uECC_word_t *e0, + const uECC_word_t *f0) { + uECC_word_t t[num_words_secp224r1]; + + uECC_vli_modSquare_fast(t, d0, &curve_secp224r1); /* t <-- d0 ^ 2 */ + uECC_vli_modMult_fast(e1, d0, e0, &curve_secp224r1); /* e1 <-- d0 * e0 */ + uECC_vli_modAdd(d1, t, f0, curve_secp224r1.p, num_words_secp224r1); /* d1 <-- t + f0 */ + uECC_vli_modAdd(e1, e1, e1, curve_secp224r1.p, num_words_secp224r1); /* e1 <-- e1 + e1 */ + uECC_vli_modMult_fast(f1, t, f0, &curve_secp224r1); /* f1 <-- t * f0 */ + uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */ + uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */ +} + +/* Routine 3.2.5 RSS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ +static void mod_sqrt_secp224r1_rss(uECC_word_t *d1, + uECC_word_t *e1, + uECC_word_t *f1, + const uECC_word_t *d0, + const uECC_word_t *e0, + const uECC_word_t *f0, + const bitcount_t j) { + bitcount_t i; + + uECC_vli_set(d1, d0, num_words_secp224r1); /* d1 <-- d0 */ + uECC_vli_set(e1, e0, num_words_secp224r1); /* e1 <-- e0 */ + uECC_vli_set(f1, f0, num_words_secp224r1); /* f1 <-- f0 */ + for (i = 1; i <= j; i++) { + mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */ + } +} + +/* Routine 3.2.6 RM; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ +static void mod_sqrt_secp224r1_rm(uECC_word_t *d2, + uECC_word_t *e2, + uECC_word_t *f2, + const uECC_word_t *c, + const uECC_word_t *d0, + const uECC_word_t *e0, + const uECC_word_t *d1, + const uECC_word_t *e1) { + uECC_word_t t1[num_words_secp224r1]; + uECC_word_t t2[num_words_secp224r1]; + + uECC_vli_modMult_fast(t1, e0, e1, &curve_secp224r1); /* t1 <-- e0 * e1 */ + uECC_vli_modMult_fast(t1, t1, c, &curve_secp224r1); /* t1 <-- t1 * c */ + /* t1 <-- p - t1 */ + uECC_vli_modSub(t1, curve_secp224r1.p, t1, curve_secp224r1.p, num_words_secp224r1); + uECC_vli_modMult_fast(t2, d0, d1, &curve_secp224r1); /* t2 <-- d0 * d1 */ + uECC_vli_modAdd(t2, t2, t1, curve_secp224r1.p, num_words_secp224r1); /* t2 <-- t2 + t1 */ + uECC_vli_modMult_fast(t1, d0, e1, &curve_secp224r1); /* t1 <-- d0 * e1 */ + uECC_vli_modMult_fast(e2, d1, e0, &curve_secp224r1); /* e2 <-- d1 * e0 */ + uECC_vli_modAdd(e2, e2, t1, curve_secp224r1.p, num_words_secp224r1); /* e2 <-- e2 + t1 */ + uECC_vli_modSquare_fast(f2, e2, &curve_secp224r1); /* f2 <-- e2^2 */ + uECC_vli_modMult_fast(f2, f2, c, &curve_secp224r1); /* f2 <-- f2 * c */ + /* f2 <-- p - f2 */ + uECC_vli_modSub(f2, curve_secp224r1.p, f2, curve_secp224r1.p, num_words_secp224r1); + uECC_vli_set(d2, t2, num_words_secp224r1); /* d2 <-- t2 */ +} + +/* Routine 3.2.7 RP; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ +static void mod_sqrt_secp224r1_rp(uECC_word_t *d1, + uECC_word_t *e1, + uECC_word_t *f1, + const uECC_word_t *c, + const uECC_word_t *r) { + wordcount_t i; + wordcount_t pow2i = 1; + uECC_word_t d0[num_words_secp224r1]; + uECC_word_t e0[num_words_secp224r1] = {1}; /* e0 <-- 1 */ + uECC_word_t f0[num_words_secp224r1]; + + uECC_vli_set(d0, r, num_words_secp224r1); /* d0 <-- r */ + /* f0 <-- p - c */ + uECC_vli_modSub(f0, curve_secp224r1.p, c, curve_secp224r1.p, num_words_secp224r1); + for (i = 0; i <= 6; i++) { + mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */ + mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, e0); /* RM (d1,e1,f1,c,d1,e1,d0,e0) */ + uECC_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */ + uECC_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */ + uECC_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */ + pow2i *= 2; + } +} + +/* Compute a = sqrt(a) (mod curve_p). */ +/* Routine 3.2.8 mp_mod_sqrt_224; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ +static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) { + bitcount_t i; + uECC_word_t e1[num_words_secp224r1]; + uECC_word_t f1[num_words_secp224r1]; + uECC_word_t d0[num_words_secp224r1]; + uECC_word_t e0[num_words_secp224r1]; + uECC_word_t f0[num_words_secp224r1]; + uECC_word_t d1[num_words_secp224r1]; + + /* s = a; using constant instead of random value */ + mod_sqrt_secp224r1_rp(d0, e0, f0, a, a); /* RP (d0, e0, f0, c, s) */ + mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */ + for (i = 1; i <= 95; i++) { + uECC_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */ + uECC_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */ + uECC_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */ + mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */ + if (uECC_vli_isZero(d1, num_words_secp224r1)) { /* if d1 == 0 */ + break; + } + } + uECC_vli_modInv(f1, e0, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- 1 / e0 */ + uECC_vli_modMult_fast(a, d0, f1, &curve_secp224r1); /* a <-- d0 / e0 */ +} +#endif /* uECC_SUPPORT_COMPRESSED_POINT */ + +#if (uECC_OPTIMIZATION_LEVEL > 0) +/* Computes result = product % curve_p + from http://www.nsa.gov/ia/_files/nist-routines.pdf */ +#if uECC_WORD_SIZE == 1 +static void vli_mmod_fast_secp224r1(uint8_t *result, uint8_t *product) { + uint8_t tmp[num_words_secp224r1]; + int8_t carry; + + /* t */ + uECC_vli_set(result, product, num_words_secp224r1); + + /* s1 */ + tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; + tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; + tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; + tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31]; + tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35]; + tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39]; + tmp[24] = product[40]; tmp[25] = product[41]; tmp[26] = product[42]; tmp[27] = product[43]; + carry = uECC_vli_add(result, result, tmp, num_words_secp224r1); + + /* s2 */ + tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47]; + tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51]; + tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55]; + tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; + carry += uECC_vli_add(result, result, tmp, num_words_secp224r1); + + /* d1 */ + tmp[0] = product[28]; tmp[1] = product[29]; tmp[2] = product[30]; tmp[3] = product[31]; + tmp[4] = product[32]; tmp[5] = product[33]; tmp[6] = product[34]; tmp[7] = product[35]; + tmp[8] = product[36]; tmp[9] = product[37]; tmp[10] = product[38]; tmp[11] = product[39]; + tmp[12] = product[40]; tmp[13] = product[41]; tmp[14] = product[42]; tmp[15] = product[43]; + tmp[16] = product[44]; tmp[17] = product[45]; tmp[18] = product[46]; tmp[19] = product[47]; + tmp[20] = product[48]; tmp[21] = product[49]; tmp[22] = product[50]; tmp[23] = product[51]; + tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); + + /* d2 */ + tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47]; + tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51]; + tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55]; + tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; + tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; + tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; + tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); + + if (carry < 0) { + do { + carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1); + } while (carry < 0); + } else { + while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) { + carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); + } + } +} +#elif uECC_WORD_SIZE == 4 +static void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product) +{ + uint32_t tmp[num_words_secp224r1]; + int carry; + + /* t */ + uECC_vli_set(result, product, num_words_secp224r1); + + /* s1 */ + tmp[0] = tmp[1] = tmp[2] = 0; + tmp[3] = product[7]; + tmp[4] = product[8]; + tmp[5] = product[9]; + tmp[6] = product[10]; + carry = uECC_vli_add(result, result, tmp, num_words_secp224r1); + + /* s2 */ + tmp[3] = product[11]; + tmp[4] = product[12]; + tmp[5] = product[13]; + tmp[6] = 0; + carry += uECC_vli_add(result, result, tmp, num_words_secp224r1); + + /* d1 */ + tmp[0] = product[7]; + tmp[1] = product[8]; + tmp[2] = product[9]; + tmp[3] = product[10]; + tmp[4] = product[11]; + tmp[5] = product[12]; + tmp[6] = product[13]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); + + /* d2 */ + tmp[0] = product[11]; + tmp[1] = product[12]; + tmp[2] = product[13]; + tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); + + if (carry < 0) { + do { + carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1); + } while (carry < 0); + } else { + while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) { + carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); + } + } +} +#else +static void vli_mmod_fast_secp224r1(uint64_t *result, uint64_t *product) +{ + uint64_t tmp[num_words_secp224r1]; + int carry = 0; + + /* t */ + uECC_vli_set(result, product, num_words_secp224r1); + result[num_words_secp224r1 - 1] &= 0xffffffff; + + /* s1 */ + tmp[0] = 0; + tmp[1] = product[3] & 0xffffffff00000000ull; + tmp[2] = product[4]; + tmp[3] = product[5] & 0xffffffff; + uECC_vli_add(result, result, tmp, num_words_secp224r1); + + /* s2 */ + tmp[1] = product[5] & 0xffffffff00000000ull; + tmp[2] = product[6]; + tmp[3] = 0; + uECC_vli_add(result, result, tmp, num_words_secp224r1); + + /* d1 */ + tmp[0] = (product[3] >> 32) | (product[4] << 32); + tmp[1] = (product[4] >> 32) | (product[5] << 32); + tmp[2] = (product[5] >> 32) | (product[6] << 32); + tmp[3] = product[6] >> 32; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); + + /* d2 */ + tmp[0] = (product[5] >> 32) | (product[6] << 32); + tmp[1] = product[6] >> 32; + tmp[2] = tmp[3] = 0; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); + + if (carry < 0) { + do { + carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1); + } while (carry < 0); + } else { + while (uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) { + uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); + } + } +} +#endif /* uECC_WORD_SIZE */ +#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */ + +#endif /* uECC_SUPPORTS_secp224r1 */ + +#if uECC_SUPPORTS_secp256r1 + +#if (uECC_OPTIMIZATION_LEVEL > 0) +static void vli_mmod_fast_secp256r1(uECC_word_t *result, uECC_word_t *product); +#endif + +static const struct uECC_Curve_t curve_secp256r1 = { + num_words_secp256r1, + num_bytes_secp256r1, + 256, /* num_n_bits */ + { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00), + BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), + BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF) }, + { BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3), + BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF) }, + { BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4), + BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77), + BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8), + BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B), + + BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB), + BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B), + BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E), + BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F) }, + { BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B), + BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65), + BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3), + BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A) }, + &double_jacobian_default, +#if uECC_SUPPORT_COMPRESSED_POINT + &mod_sqrt_default, +#endif + &x_side_default, +#if (uECC_OPTIMIZATION_LEVEL > 0) + &vli_mmod_fast_secp256r1 +#endif +}; + +uECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; } + + +#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) +/* Computes result = product % curve_p + from http://www.nsa.gov/ia/_files/nist-routines.pdf */ +#if uECC_WORD_SIZE == 1 +static void vli_mmod_fast_secp256r1(uint8_t *result, uint8_t *product) { + uint8_t tmp[num_words_secp256r1]; + int8_t carry; + + /* t */ + uECC_vli_set(result, product, num_words_secp256r1); + + /* s1 */ + tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; + tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; + tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; + tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47]; + tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51]; + tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55]; + tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59]; + tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63]; + carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* s2 */ + tmp[12] = product[48]; tmp[13] = product[49]; tmp[14] = product[50]; tmp[15] = product[51]; + tmp[16] = product[52]; tmp[17] = product[53]; tmp[18] = product[54]; tmp[19] = product[55]; + tmp[20] = product[56]; tmp[21] = product[57]; tmp[22] = product[58]; tmp[23] = product[59]; + tmp[24] = product[60]; tmp[25] = product[61]; tmp[26] = product[62]; tmp[27] = product[63]; + tmp[28] = tmp[29] = tmp[30] = tmp[31] = 0; + carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* s3 */ + tmp[0] = product[32]; tmp[1] = product[33]; tmp[2] = product[34]; tmp[3] = product[35]; + tmp[4] = product[36]; tmp[5] = product[37]; tmp[6] = product[38]; tmp[7] = product[39]; + tmp[8] = product[40]; tmp[9] = product[41]; tmp[10] = product[42]; tmp[11] = product[43]; + tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; + tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; + tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; + tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59]; + tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63]; + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* s4 */ + tmp[0] = product[36]; tmp[1] = product[37]; tmp[2] = product[38]; tmp[3] = product[39]; + tmp[4] = product[40]; tmp[5] = product[41]; tmp[6] = product[42]; tmp[7] = product[43]; + tmp[8] = product[44]; tmp[9] = product[45]; tmp[10] = product[46]; tmp[11] = product[47]; + tmp[12] = product[52]; tmp[13] = product[53]; tmp[14] = product[54]; tmp[15] = product[55]; + tmp[16] = product[56]; tmp[17] = product[57]; tmp[18] = product[58]; tmp[19] = product[59]; + tmp[20] = product[60]; tmp[21] = product[61]; tmp[22] = product[62]; tmp[23] = product[63]; + tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55]; + tmp[28] = product[32]; tmp[29] = product[33]; tmp[30] = product[34]; tmp[31] = product[35]; + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* d1 */ + tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47]; + tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51]; + tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55]; + tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; + tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; + tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; + tmp[24] = product[32]; tmp[25] = product[33]; tmp[26] = product[34]; tmp[27] = product[35]; + tmp[28] = product[40]; tmp[29] = product[41]; tmp[30] = product[42]; tmp[31] = product[43]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + /* d2 */ + tmp[0] = product[48]; tmp[1] = product[49]; tmp[2] = product[50]; tmp[3] = product[51]; + tmp[4] = product[52]; tmp[5] = product[53]; tmp[6] = product[54]; tmp[7] = product[55]; + tmp[8] = product[56]; tmp[9] = product[57]; tmp[10] = product[58]; tmp[11] = product[59]; + tmp[12] = product[60]; tmp[13] = product[61]; tmp[14] = product[62]; tmp[15] = product[63]; + tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; + tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; + tmp[24] = product[36]; tmp[25] = product[37]; tmp[26] = product[38]; tmp[27] = product[39]; + tmp[28] = product[44]; tmp[29] = product[45]; tmp[30] = product[46]; tmp[31] = product[47]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + /* d3 */ + tmp[0] = product[52]; tmp[1] = product[53]; tmp[2] = product[54]; tmp[3] = product[55]; + tmp[4] = product[56]; tmp[5] = product[57]; tmp[6] = product[58]; tmp[7] = product[59]; + tmp[8] = product[60]; tmp[9] = product[61]; tmp[10] = product[62]; tmp[11] = product[63]; + tmp[12] = product[32]; tmp[13] = product[33]; tmp[14] = product[34]; tmp[15] = product[35]; + tmp[16] = product[36]; tmp[17] = product[37]; tmp[18] = product[38]; tmp[19] = product[39]; + tmp[20] = product[40]; tmp[21] = product[41]; tmp[22] = product[42]; tmp[23] = product[43]; + tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; + tmp[28] = product[48]; tmp[29] = product[49]; tmp[30] = product[50]; tmp[31] = product[51]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + /* d4 */ + tmp[0] = product[56]; tmp[1] = product[57]; tmp[2] = product[58]; tmp[3] = product[59]; + tmp[4] = product[60]; tmp[5] = product[61]; tmp[6] = product[62]; tmp[7] = product[63]; + tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; + tmp[12] = product[36]; tmp[13] = product[37]; tmp[14] = product[38]; tmp[15] = product[39]; + tmp[16] = product[40]; tmp[17] = product[41]; tmp[18] = product[42]; tmp[19] = product[43]; + tmp[20] = product[44]; tmp[21] = product[45]; tmp[22] = product[46]; tmp[23] = product[47]; + tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; + tmp[28] = product[52]; tmp[29] = product[53]; tmp[30] = product[54]; tmp[31] = product[55]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + if (carry < 0) { + do { + carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); + } while (carry < 0); + } else { + while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { + carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); + } + } +} +#elif uECC_WORD_SIZE == 4 +static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { + uint32_t tmp[num_words_secp256r1]; + int carry; + + /* t */ + uECC_vli_set(result, product, num_words_secp256r1); + + /* s1 */ + tmp[0] = tmp[1] = tmp[2] = 0; + tmp[3] = product[11]; + tmp[4] = product[12]; + tmp[5] = product[13]; + tmp[6] = product[14]; + tmp[7] = product[15]; + carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* s2 */ + tmp[3] = product[12]; + tmp[4] = product[13]; + tmp[5] = product[14]; + tmp[6] = product[15]; + tmp[7] = 0; + carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* s3 */ + tmp[0] = product[8]; + tmp[1] = product[9]; + tmp[2] = product[10]; + tmp[3] = tmp[4] = tmp[5] = 0; + tmp[6] = product[14]; + tmp[7] = product[15]; + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* s4 */ + tmp[0] = product[9]; + tmp[1] = product[10]; + tmp[2] = product[11]; + tmp[3] = product[13]; + tmp[4] = product[14]; + tmp[5] = product[15]; + tmp[6] = product[13]; + tmp[7] = product[8]; + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* d1 */ + tmp[0] = product[11]; + tmp[1] = product[12]; + tmp[2] = product[13]; + tmp[3] = tmp[4] = tmp[5] = 0; + tmp[6] = product[8]; + tmp[7] = product[10]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + /* d2 */ + tmp[0] = product[12]; + tmp[1] = product[13]; + tmp[2] = product[14]; + tmp[3] = product[15]; + tmp[4] = tmp[5] = 0; + tmp[6] = product[9]; + tmp[7] = product[11]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + /* d3 */ + tmp[0] = product[13]; + tmp[1] = product[14]; + tmp[2] = product[15]; + tmp[3] = product[8]; + tmp[4] = product[9]; + tmp[5] = product[10]; + tmp[6] = 0; + tmp[7] = product[12]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + /* d4 */ + tmp[0] = product[14]; + tmp[1] = product[15]; + tmp[2] = 0; + tmp[3] = product[9]; + tmp[4] = product[10]; + tmp[5] = product[11]; + tmp[6] = 0; + tmp[7] = product[13]; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + if (carry < 0) { + do { + carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); + } while (carry < 0); + } else { + while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { + carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); + } + } +} +#else +static void vli_mmod_fast_secp256r1(uint64_t *result, uint64_t *product) { + uint64_t tmp[num_words_secp256r1]; + int carry; + + /* t */ + uECC_vli_set(result, product, num_words_secp256r1); + + /* s1 */ + tmp[0] = 0; + tmp[1] = product[5] & 0xffffffff00000000ull; + tmp[2] = product[6]; + tmp[3] = product[7]; + carry = (int)uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* s2 */ + tmp[1] = product[6] << 32; + tmp[2] = (product[6] >> 32) | (product[7] << 32); + tmp[3] = product[7] >> 32; + carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* s3 */ + tmp[0] = product[4]; + tmp[1] = product[5] & 0xffffffff; + tmp[2] = 0; + tmp[3] = product[7]; + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* s4 */ + tmp[0] = (product[4] >> 32) | (product[5] << 32); + tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull); + tmp[2] = product[7]; + tmp[3] = (product[6] >> 32) | (product[4] << 32); + carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); + + /* d1 */ + tmp[0] = (product[5] >> 32) | (product[6] << 32); + tmp[1] = (product[6] >> 32); + tmp[2] = 0; + tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32); + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + /* d2 */ + tmp[0] = product[6]; + tmp[1] = product[7]; + tmp[2] = 0; + tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull); + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + /* d3 */ + tmp[0] = (product[6] >> 32) | (product[7] << 32); + tmp[1] = (product[7] >> 32) | (product[4] << 32); + tmp[2] = (product[4] >> 32) | (product[5] << 32); + tmp[3] = (product[6] << 32); + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + /* d4 */ + tmp[0] = product[7]; + tmp[1] = product[4] & 0xffffffff00000000ull; + tmp[2] = product[5]; + tmp[3] = product[6] & 0xffffffff00000000ull; + carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); + + if (carry < 0) { + do { + carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); + } while (carry < 0); + } else { + while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { + carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); + } + } +} +#endif /* uECC_WORD_SIZE */ +#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) */ + +#endif /* uECC_SUPPORTS_secp256r1 */ + +#if uECC_SUPPORTS_secp256k1 + +static void double_jacobian_secp256k1(uECC_word_t * X1, + uECC_word_t * Y1, + uECC_word_t * Z1, + uECC_Curve curve); +static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); +#if (uECC_OPTIMIZATION_LEVEL > 0) +static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product); +#endif + +static const struct uECC_Curve_t curve_secp256k1 = { + num_words_secp256k1, + num_bytes_secp256k1, + 256, /* num_n_bits */ + { BYTES_TO_WORDS_8(2F, FC, FF, FF, FE, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, + { BYTES_TO_WORDS_8(41, 41, 36, D0, 8C, 5E, D2, BF), + BYTES_TO_WORDS_8(3B, A0, 48, AF, E6, DC, AE, BA), + BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, + { BYTES_TO_WORDS_8(98, 17, F8, 16, 5B, 81, F2, 59), + BYTES_TO_WORDS_8(D9, 28, CE, 2D, DB, FC, 9B, 02), + BYTES_TO_WORDS_8(07, 0B, 87, CE, 95, 62, A0, 55), + BYTES_TO_WORDS_8(AC, BB, DC, F9, 7E, 66, BE, 79), + + BYTES_TO_WORDS_8(B8, D4, 10, FB, 8F, D0, 47, 9C), + BYTES_TO_WORDS_8(19, 54, 85, A6, 48, B4, 17, FD), + BYTES_TO_WORDS_8(A8, 08, 11, 0E, FC, FB, A4, 5D), + BYTES_TO_WORDS_8(65, C4, A3, 26, 77, DA, 3A, 48) }, + { BYTES_TO_WORDS_8(07, 00, 00, 00, 00, 00, 00, 00), + BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), + BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), + BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00) }, + &double_jacobian_secp256k1, +#if uECC_SUPPORT_COMPRESSED_POINT + &mod_sqrt_default, +#endif + &x_side_secp256k1, +#if (uECC_OPTIMIZATION_LEVEL > 0) + &vli_mmod_fast_secp256k1 +#endif +}; + +uECC_Curve uECC_secp256k1(void) { return &curve_secp256k1; } + + +/* Double in place */ +static void double_jacobian_secp256k1(uECC_word_t * X1, + uECC_word_t * Y1, + uECC_word_t * Z1, + uECC_Curve curve) { + /* t1 = X, t2 = Y, t3 = Z */ + uECC_word_t t4[num_words_secp256k1]; + uECC_word_t t5[num_words_secp256k1]; + + if (uECC_vli_isZero(Z1, num_words_secp256k1)) { + return; + } + + uECC_vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */ + uECC_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */ + uECC_vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */ + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */ + uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */ + + uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */ + uECC_vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */ + if (uECC_vli_testBit(Y1, 0)) { + uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1); + uECC_vli_rshift1(Y1, num_words_secp256k1); + Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1); + } else { + uECC_vli_rshift1(Y1, num_words_secp256k1); + } + /* t2 = 3/2*(x1^2) = B */ + + uECC_vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */ + uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */ + uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */ + + uECC_vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */ + uECC_vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */ + uECC_vli_modSub(Y1, Y1, t5, curve->p, num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */ +} + +/* Computes result = x^3 + b. result must not overlap x. */ +static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { + uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ + uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 */ + uECC_vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */ +} + +#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256k1) +static void omega_mult_secp256k1(uECC_word_t *result, const uECC_word_t *right); +static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product) { + uECC_word_t tmp[2 * num_words_secp256k1]; + uECC_word_t carry; + + uECC_vli_clear(tmp, num_words_secp256k1); + uECC_vli_clear(tmp + num_words_secp256k1, num_words_secp256k1); + + omega_mult_secp256k1(tmp, product + num_words_secp256k1); /* (Rq, q) = q * c */ + + carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q */ + uECC_vli_clear(product, num_words_secp256k1); + omega_mult_secp256k1(product, tmp + num_words_secp256k1); /* Rq*c */ + carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */ + + while (carry > 0) { + --carry; + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + } + if (uECC_vli_cmp_unsafe(result, curve_secp256k1.p, num_words_secp256k1) > 0) { + uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); + } +} + +#if uECC_WORD_SIZE == 1 +static void omega_mult_secp256k1(uint8_t * result, const uint8_t * right) { + /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ + uECC_word_t r0 = 0; + uECC_word_t r1 = 0; + uECC_word_t r2 = 0; + wordcount_t k; + + /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ + muladd(0xD1, right[0], &r0, &r1, &r2); + result[0] = r0; + r0 = r1; + r1 = r2; + /* r2 is still 0 */ + + for (k = 1; k < num_words_secp256k1; ++k) { + muladd(0x03, right[k - 1], &r0, &r1, &r2); + muladd(0xD1, right[k], &r0, &r1, &r2); + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + muladd(0x03, right[num_words_secp256k1 - 1], &r0, &r1, &r2); + result[num_words_secp256k1] = r0; + result[num_words_secp256k1 + 1] = r1; + /* add the 2^32 multiple */ + result[4 + num_words_secp256k1] = + uECC_vli_add(result + 4, result + 4, right, num_words_secp256k1); +} +#elif uECC_WORD_SIZE == 4 +static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) { + /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ + uint32_t carry = 0; + wordcount_t k; + + for (k = 0; k < num_words_secp256k1; ++k) { + uint64_t p = (uint64_t)0x3D1 * right[k] + carry; + result[k] = (uint32_t) p; + carry = p >> 32; + } + result[num_words_secp256k1] = carry; + /* add the 2^32 multiple */ + result[1 + num_words_secp256k1] = + uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1); +} +#else +static void omega_mult_secp256k1(uint64_t * result, const uint64_t * right) { + uECC_word_t r0 = 0; + uECC_word_t r1 = 0; + uECC_word_t r2 = 0; + wordcount_t k; + + /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ + for (k = 0; k < num_words_secp256k1; ++k) { + muladd(0x1000003D1ull, right[k], &r0, &r1, &r2); + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + result[num_words_secp256k1] = r0; +} +#endif /* uECC_WORD_SIZE */ +#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && && !asm_mmod_fast_secp256k1) */ + +#endif /* uECC_SUPPORTS_secp256k1 */ + +#endif /* _UECC_CURVE_SPECIFIC_H_ */ diff --git a/lib/micro-ecc/platform-specific.inc b/lib/micro-ecc/platform-specific.inc new file mode 100644 index 00000000..7e0373f5 --- /dev/null +++ b/lib/micro-ecc/platform-specific.inc @@ -0,0 +1,94 @@ +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_PLATFORM_SPECIFIC_H_ +#define _UECC_PLATFORM_SPECIFIC_H_ + +#include "types.h" + +#if (defined(_WIN32) || defined(_WIN64)) +/* Windows */ + +// use pragma syntax to prevent tweaking the linker script for getting CryptXYZ function +#pragma comment(lib, "crypt32.lib") +#pragma comment(lib, "advapi32.lib") + +#define WIN32_LEAN_AND_MEAN +#include +#include + +static int default_RNG(uint8_t *dest, unsigned size) { + HCRYPTPROV prov; + if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + return 0; + } + + CryptGenRandom(prov, size, (BYTE *)dest); + CryptReleaseContext(prov, 0); + return 1; +} +#define default_RNG_defined 1 + +#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \ + (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX) + +/* Some POSIX-like system with /dev/urandom or /dev/random. */ +#include +#include +#include + +#ifndef O_CLOEXEC + #define O_CLOEXEC 0 +#endif + +static int default_RNG(uint8_t *dest, unsigned size) { + int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd == -1) { + fd = open("/dev/random", O_RDONLY | O_CLOEXEC); + if (fd == -1) { + return 0; + } + } + + char *ptr = (char *)dest; + size_t left = size; + while (left > 0) { + ssize_t bytes_read = read(fd, ptr, left); + if (bytes_read <= 0) { // read failed + close(fd); + return 0; + } + left -= bytes_read; + ptr += bytes_read; + } + + close(fd); + return 1; +} +#define default_RNG_defined 1 + +#elif defined(RIOT_VERSION) + +#include + +static int default_RNG(uint8_t *dest, unsigned size) { + random_bytes(dest, size); + return 1; +} +#define default_RNG_defined 1 + +#elif defined(NRF52_SERIES) + +#include "app_error.h" +#include "nrf_crypto_rng.h" + +static int default_RNG(uint8_t *dest, unsigned size) +{ + // make sure to call nrf_crypto_init and nrf_crypto_rng_init first + ret_code_t ret_code = nrf_crypto_rng_vector_generate(dest, size); + return (ret_code == NRF_SUCCESS) ? 1 : 0; +} +#define default_RNG_defined 1 + +#endif /* platform */ + +#endif /* _UECC_PLATFORM_SPECIFIC_H_ */ diff --git a/lib/micro-ecc/types.h b/lib/micro-ecc/types.h new file mode 100644 index 00000000..9ee81438 --- /dev/null +++ b/lib/micro-ecc/types.h @@ -0,0 +1,108 @@ +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_TYPES_H_ +#define _UECC_TYPES_H_ + +#ifndef uECC_PLATFORM + #if __AVR__ + #define uECC_PLATFORM uECC_avr + #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */ + #define uECC_PLATFORM uECC_arm_thumb2 + #elif defined(__thumb__) + #define uECC_PLATFORM uECC_arm_thumb + #elif defined(__arm__) || defined(_M_ARM) + #define uECC_PLATFORM uECC_arm + #elif defined(__aarch64__) + #define uECC_PLATFORM uECC_arm64 + #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__) + #define uECC_PLATFORM uECC_x86 + #elif defined(__amd64__) || defined(_M_X64) + #define uECC_PLATFORM uECC_x86_64 + #else + #define uECC_PLATFORM uECC_arch_other + #endif +#endif + +#ifndef uECC_ARM_USE_UMAAL + #if (uECC_PLATFORM == uECC_arm) && (__ARM_ARCH >= 6) + #define uECC_ARM_USE_UMAAL 1 + #elif (uECC_PLATFORM == uECC_arm_thumb2) && (__ARM_ARCH >= 6) && !__ARM_ARCH_7M__ + #define uECC_ARM_USE_UMAAL 1 + #else + #define uECC_ARM_USE_UMAAL 0 + #endif +#endif + +#ifndef uECC_WORD_SIZE + #if uECC_PLATFORM == uECC_avr + #define uECC_WORD_SIZE 1 + #elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64) + #define uECC_WORD_SIZE 8 + #else + #define uECC_WORD_SIZE 4 + #endif +#endif + +#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8) + #error "Unsupported value for uECC_WORD_SIZE" +#endif + +#if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1)) + #pragma message ("uECC_WORD_SIZE must be 1 for AVR") + #undef uECC_WORD_SIZE + #define uECC_WORD_SIZE 1 +#endif + +#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \ + uECC_PLATFORM == uECC_arm_thumb2) && \ + (uECC_WORD_SIZE != 4)) + #pragma message ("uECC_WORD_SIZE must be 4 for ARM") + #undef uECC_WORD_SIZE + #define uECC_WORD_SIZE 4 +#endif + +#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302) + #define SUPPORTS_INT128 1 +#else + #define SUPPORTS_INT128 0 +#endif + +typedef int8_t wordcount_t; +typedef int16_t bitcount_t; +typedef int8_t cmpresult_t; + +#if (uECC_WORD_SIZE == 1) + +typedef uint8_t uECC_word_t; +typedef uint16_t uECC_dword_t; + +#define HIGH_BIT_SET 0x80 +#define uECC_WORD_BITS 8 +#define uECC_WORD_BITS_SHIFT 3 +#define uECC_WORD_BITS_MASK 0x07 + +#elif (uECC_WORD_SIZE == 4) + +typedef uint32_t uECC_word_t; +typedef uint64_t uECC_dword_t; + +#define HIGH_BIT_SET 0x80000000 +#define uECC_WORD_BITS 32 +#define uECC_WORD_BITS_SHIFT 5 +#define uECC_WORD_BITS_MASK 0x01F + +#elif (uECC_WORD_SIZE == 8) + +typedef uint64_t uECC_word_t; +#if SUPPORTS_INT128 +typedef unsigned __int128 uECC_dword_t; +#endif + +#define HIGH_BIT_SET 0x8000000000000000ull +#define uECC_WORD_BITS 64 +#define uECC_WORD_BITS_SHIFT 6 +#define uECC_WORD_BITS_MASK 0x03F + +#endif /* uECC_WORD_SIZE */ + +#endif /* _UECC_TYPES_H_ */ diff --git a/lib/micro-ecc/uECC.c b/lib/micro-ecc/uECC.c new file mode 100644 index 00000000..a3d502cf --- /dev/null +++ b/lib/micro-ecc/uECC.c @@ -0,0 +1,1669 @@ +/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#include "uECC.h" +#include "uECC_vli.h" + +#ifndef uECC_RNG_MAX_TRIES + #define uECC_RNG_MAX_TRIES 64 +#endif + +#if uECC_ENABLE_VLI_API + #define uECC_VLI_API +#else + #define uECC_VLI_API static +#endif + +#if (uECC_PLATFORM == uECC_avr) || \ + (uECC_PLATFORM == uECC_arm) || \ + (uECC_PLATFORM == uECC_arm_thumb) || \ + (uECC_PLATFORM == uECC_arm_thumb2) + #define CONCATX(a, ...) a ## __VA_ARGS__ + #define CONCAT(a, ...) CONCATX(a, __VA_ARGS__) + + #define STRX(a) #a + #define STR(a) STRX(a) + + #define EVAL(...) EVAL1(EVAL1(EVAL1(EVAL1(__VA_ARGS__)))) + #define EVAL1(...) EVAL2(EVAL2(EVAL2(EVAL2(__VA_ARGS__)))) + #define EVAL2(...) EVAL3(EVAL3(EVAL3(EVAL3(__VA_ARGS__)))) + #define EVAL3(...) EVAL4(EVAL4(EVAL4(EVAL4(__VA_ARGS__)))) + #define EVAL4(...) __VA_ARGS__ + + #define DEC_1 0 + #define DEC_2 1 + #define DEC_3 2 + #define DEC_4 3 + #define DEC_5 4 + #define DEC_6 5 + #define DEC_7 6 + #define DEC_8 7 + #define DEC_9 8 + #define DEC_10 9 + #define DEC_11 10 + #define DEC_12 11 + #define DEC_13 12 + #define DEC_14 13 + #define DEC_15 14 + #define DEC_16 15 + #define DEC_17 16 + #define DEC_18 17 + #define DEC_19 18 + #define DEC_20 19 + #define DEC_21 20 + #define DEC_22 21 + #define DEC_23 22 + #define DEC_24 23 + #define DEC_25 24 + #define DEC_26 25 + #define DEC_27 26 + #define DEC_28 27 + #define DEC_29 28 + #define DEC_30 29 + #define DEC_31 30 + #define DEC_32 31 + + #define DEC(N) CONCAT(DEC_, N) + + #define SECOND_ARG(_, val, ...) val + #define SOME_CHECK_0 ~, 0 + #define GET_SECOND_ARG(...) SECOND_ARG(__VA_ARGS__, SOME,) + #define SOME_OR_0(N) GET_SECOND_ARG(CONCAT(SOME_CHECK_, N)) + + #define EMPTY(...) + #define DEFER(...) __VA_ARGS__ EMPTY() + + #define REPEAT_NAME_0() REPEAT_0 + #define REPEAT_NAME_SOME() REPEAT_SOME + #define REPEAT_0(...) + #define REPEAT_SOME(N, stuff) DEFER(CONCAT(REPEAT_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), stuff) stuff + #define REPEAT(N, stuff) EVAL(REPEAT_SOME(N, stuff)) + + #define REPEATM_NAME_0() REPEATM_0 + #define REPEATM_NAME_SOME() REPEATM_SOME + #define REPEATM_0(...) + #define REPEATM_SOME(N, macro) macro(N) \ + DEFER(CONCAT(REPEATM_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), macro) + #define REPEATM(N, macro) EVAL(REPEATM_SOME(N, macro)) +#endif + +#include "platform-specific.inc" + +#if (uECC_WORD_SIZE == 1) + #if uECC_SUPPORTS_secp160r1 + #define uECC_MAX_WORDS 21 /* Due to the size of curve_n. */ + #endif + #if uECC_SUPPORTS_secp192r1 + #undef uECC_MAX_WORDS + #define uECC_MAX_WORDS 24 + #endif + #if uECC_SUPPORTS_secp224r1 + #undef uECC_MAX_WORDS + #define uECC_MAX_WORDS 28 + #endif + #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) + #undef uECC_MAX_WORDS + #define uECC_MAX_WORDS 32 + #endif +#elif (uECC_WORD_SIZE == 4) + #if uECC_SUPPORTS_secp160r1 + #define uECC_MAX_WORDS 6 /* Due to the size of curve_n. */ + #endif + #if uECC_SUPPORTS_secp192r1 + #undef uECC_MAX_WORDS + #define uECC_MAX_WORDS 6 + #endif + #if uECC_SUPPORTS_secp224r1 + #undef uECC_MAX_WORDS + #define uECC_MAX_WORDS 7 + #endif + #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) + #undef uECC_MAX_WORDS + #define uECC_MAX_WORDS 8 + #endif +#elif (uECC_WORD_SIZE == 8) + #if uECC_SUPPORTS_secp160r1 + #define uECC_MAX_WORDS 3 + #endif + #if uECC_SUPPORTS_secp192r1 + #undef uECC_MAX_WORDS + #define uECC_MAX_WORDS 3 + #endif + #if uECC_SUPPORTS_secp224r1 + #undef uECC_MAX_WORDS + #define uECC_MAX_WORDS 4 + #endif + #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) + #undef uECC_MAX_WORDS + #define uECC_MAX_WORDS 4 + #endif +#endif /* uECC_WORD_SIZE */ + +#define BITS_TO_WORDS(num_bits) ((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8)) +#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8) + +struct uECC_Curve_t { + wordcount_t num_words; + wordcount_t num_bytes; + bitcount_t num_n_bits; + uECC_word_t p[uECC_MAX_WORDS]; + uECC_word_t n[uECC_MAX_WORDS]; + uECC_word_t G[uECC_MAX_WORDS * 2]; + uECC_word_t b[uECC_MAX_WORDS]; + void (*double_jacobian)(uECC_word_t * X1, + uECC_word_t * Y1, + uECC_word_t * Z1, + uECC_Curve curve); +#if uECC_SUPPORT_COMPRESSED_POINT + void (*mod_sqrt)(uECC_word_t *a, uECC_Curve curve); +#endif + void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); +#if (uECC_OPTIMIZATION_LEVEL > 0) + void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product); +#endif +}; + +#if uECC_VLI_NATIVE_LITTLE_ENDIAN +static void bcopy(uint8_t *dst, + const uint8_t *src, + unsigned num_bytes) { + while (0 != num_bytes) { + num_bytes--; + dst[num_bytes] = src[num_bytes]; + } +} +#endif + +static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words); + +#if (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \ + uECC_PLATFORM == uECC_arm_thumb2) + #include "asm_arm.inc" +#endif + +#if (uECC_PLATFORM == uECC_avr) + #include "asm_avr.inc" +#endif + +#if default_RNG_defined +static uECC_RNG_Function g_rng_function = &default_RNG; +#else +static uECC_RNG_Function g_rng_function = 0; +#endif + +void uECC_set_rng(uECC_RNG_Function rng_function) { + g_rng_function = rng_function; +} + +uECC_RNG_Function uECC_get_rng(void) { + return g_rng_function; +} + +int uECC_curve_private_key_size(uECC_Curve curve) { + return BITS_TO_BYTES(curve->num_n_bits); +} + +int uECC_curve_public_key_size(uECC_Curve curve) { + return 2 * curve->num_bytes; +} + +#if !asm_clear +uECC_VLI_API void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) { + wordcount_t i; + for (i = 0; i < num_words; ++i) { + vli[i] = 0; + } +} +#endif /* !asm_clear */ + +/* Constant-time comparison to zero - secure way to compare long integers */ +/* Returns 1 if vli == 0, 0 otherwise. */ +uECC_VLI_API uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) { + uECC_word_t bits = 0; + wordcount_t i; + for (i = 0; i < num_words; ++i) { + bits |= vli[i]; + } + return (bits == 0); +} + +/* Returns nonzero if bit 'bit' of vli is set. */ +uECC_VLI_API uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) { + return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); +} + +/* Counts the number of words in vli. */ +static wordcount_t vli_numDigits(const uECC_word_t *vli, const wordcount_t max_words) { + wordcount_t i; + /* Search from the end until we find a non-zero digit. + We do it in reverse because we expect that most digits will be nonzero. */ + for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { + } + + return (i + 1); +} + +/* Counts the number of bits required to represent vli. */ +uECC_VLI_API bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words) { + uECC_word_t i; + uECC_word_t digit; + + wordcount_t num_digits = vli_numDigits(vli, max_words); + if (num_digits == 0) { + return 0; + } + + digit = vli[num_digits - 1]; + for (i = 0; digit; ++i) { + digit >>= 1; + } + + return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i); +} + +/* Sets dest = src. */ +#if !asm_set +uECC_VLI_API void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words) { + wordcount_t i; + for (i = 0; i < num_words; ++i) { + dest[i] = src[i]; + } +} +#endif /* !asm_set */ + +/* Returns sign of left - right. */ +static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + wordcount_t i; + for (i = num_words - 1; i >= 0; --i) { + if (left[i] > right[i]) { + return 1; + } else if (left[i] < right[i]) { + return -1; + } + } + return 0; +} + +/* Constant-time comparison function - secure way to compare long integers */ +/* Returns one if left == right, zero otherwise. */ +uECC_VLI_API uECC_word_t uECC_vli_equal(const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + uECC_word_t diff = 0; + wordcount_t i; + for (i = num_words - 1; i >= 0; --i) { + diff |= (left[i] ^ right[i]); + } + return (diff == 0); +} + +uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words); + +/* Returns sign of left - right, in constant time. */ +uECC_VLI_API cmpresult_t uECC_vli_cmp(const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + uECC_word_t tmp[uECC_MAX_WORDS]; + uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); + uECC_word_t equal = uECC_vli_isZero(tmp, num_words); + return (!equal - 2 * neg); +} + +/* Computes vli = vli >> 1. */ +#if !asm_rshift1 +uECC_VLI_API void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) { + uECC_word_t *end = vli; + uECC_word_t carry = 0; + + vli += num_words; + while (vli-- > end) { + uECC_word_t temp = *vli; + *vli = (temp >> 1) | carry; + carry = temp << (uECC_WORD_BITS - 1); + } +} +#endif /* !asm_rshift1 */ + +/* Computes result = left + right, returning carry. Can modify in place. */ +#if !asm_add +uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + uECC_word_t carry = 0; + wordcount_t i; + for (i = 0; i < num_words; ++i) { + uECC_word_t sum = left[i] + right[i] + carry; + if (sum != left[i]) { + carry = (sum < left[i]); + } + result[i] = sum; + } + return carry; +} +#endif /* !asm_add */ + +/* Computes result = left - right, returning borrow. Can modify in place. */ +#if !asm_sub +uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + uECC_word_t borrow = 0; + wordcount_t i; + for (i = 0; i < num_words; ++i) { + uECC_word_t diff = left[i] - right[i] - borrow; + if (diff != left[i]) { + borrow = (diff > left[i]); + } + result[i] = diff; + } + return borrow; +} +#endif /* !asm_sub */ + +#if !asm_mult || (uECC_SQUARE_FUNC && !asm_square) || \ + (uECC_SUPPORTS_secp256k1 && (uECC_OPTIMIZATION_LEVEL > 0) && \ + ((uECC_WORD_SIZE == 1) || (uECC_WORD_SIZE == 8))) +static void muladd(uECC_word_t a, + uECC_word_t b, + uECC_word_t *r0, + uECC_word_t *r1, + uECC_word_t *r2) { +#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128 + uint64_t a0 = a & 0xffffffffull; + uint64_t a1 = a >> 32; + uint64_t b0 = b & 0xffffffffull; + uint64_t b1 = b >> 32; + + uint64_t i0 = a0 * b0; + uint64_t i1 = a0 * b1; + uint64_t i2 = a1 * b0; + uint64_t i3 = a1 * b1; + + uint64_t p0, p1; + + i2 += (i0 >> 32); + i2 += i1; + if (i2 < i1) { /* overflow */ + i3 += 0x100000000ull; + } + + p0 = (i0 & 0xffffffffull) | (i2 << 32); + p1 = i3 + (i2 >> 32); + + *r0 += p0; + *r1 += (p1 + (*r0 < p0)); + *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0)); +#else + uECC_dword_t p = (uECC_dword_t)a * b; + uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; + r01 += p; + *r2 += (r01 < p); + *r1 = r01 >> uECC_WORD_BITS; + *r0 = (uECC_word_t)r01; +#endif +} +#endif /* muladd needed */ + +#if !asm_mult +uECC_VLI_API void uECC_vli_mult(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) { + uECC_word_t r0 = 0; + uECC_word_t r1 = 0; + uECC_word_t r2 = 0; + wordcount_t i, k; + + /* Compute each digit of result in sequence, maintaining the carries. */ + for (k = 0; k < num_words; ++k) { + for (i = 0; i <= k; ++i) { + muladd(left[i], right[k - i], &r0, &r1, &r2); + } + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + for (k = num_words; k < num_words * 2 - 1; ++k) { + for (i = (k + 1) - num_words; i < num_words; ++i) { + muladd(left[i], right[k - i], &r0, &r1, &r2); + } + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + result[num_words * 2 - 1] = r0; +} +#endif /* !asm_mult */ + +#if uECC_SQUARE_FUNC + +#if !asm_square +static void mul2add(uECC_word_t a, + uECC_word_t b, + uECC_word_t *r0, + uECC_word_t *r1, + uECC_word_t *r2) { +#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128 + uint64_t a0 = a & 0xffffffffull; + uint64_t a1 = a >> 32; + uint64_t b0 = b & 0xffffffffull; + uint64_t b1 = b >> 32; + + uint64_t i0 = a0 * b0; + uint64_t i1 = a0 * b1; + uint64_t i2 = a1 * b0; + uint64_t i3 = a1 * b1; + + uint64_t p0, p1; + + i2 += (i0 >> 32); + i2 += i1; + if (i2 < i1) + { /* overflow */ + i3 += 0x100000000ull; + } + + p0 = (i0 & 0xffffffffull) | (i2 << 32); + p1 = i3 + (i2 >> 32); + + *r2 += (p1 >> 63); + p1 = (p1 << 1) | (p0 >> 63); + p0 <<= 1; + + *r0 += p0; + *r1 += (p1 + (*r0 < p0)); + *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0)); +#else + uECC_dword_t p = (uECC_dword_t)a * b; + uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; + *r2 += (p >> (uECC_WORD_BITS * 2 - 1)); + p *= 2; + r01 += p; + *r2 += (r01 < p); + *r1 = r01 >> uECC_WORD_BITS; + *r0 = (uECC_word_t)r01; +#endif +} + +uECC_VLI_API void uECC_vli_square(uECC_word_t *result, + const uECC_word_t *left, + wordcount_t num_words) { + uECC_word_t r0 = 0; + uECC_word_t r1 = 0; + uECC_word_t r2 = 0; + + wordcount_t i, k; + + for (k = 0; k < num_words * 2 - 1; ++k) { + uECC_word_t min = (k < num_words ? 0 : (k + 1) - num_words); + for (i = min; i <= k && i <= k - i; ++i) { + if (i < k-i) { + mul2add(left[i], left[k - i], &r0, &r1, &r2); + } else { + muladd(left[i], left[k - i], &r0, &r1, &r2); + } + } + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + + result[num_words * 2 - 1] = r0; +} +#endif /* !asm_square */ + +#else /* uECC_SQUARE_FUNC */ + +#if uECC_ENABLE_VLI_API +uECC_VLI_API void uECC_vli_square(uECC_word_t *result, + const uECC_word_t *left, + wordcount_t num_words) { + uECC_vli_mult(result, left, left, num_words); +} +#endif /* uECC_ENABLE_VLI_API */ + +#endif /* uECC_SQUARE_FUNC */ + +/* Computes result = (left + right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap mod. */ +uECC_VLI_API void uECC_vli_modAdd(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod, + wordcount_t num_words) { + uECC_word_t carry = uECC_vli_add(result, left, right, num_words); + if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) { + /* result > mod (result = mod + remainder), so subtract mod to get remainder. */ + uECC_vli_sub(result, result, mod, num_words); + } +} + +/* Computes result = (left - right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap mod. */ +uECC_VLI_API void uECC_vli_modSub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod, + wordcount_t num_words) { + uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words); + if (l_borrow) { + /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x, + we can get the correct result from result + mod (with overflow). */ + uECC_vli_add(result, result, mod, num_words); + } +} + +/* Computes result = product % mod, where product is 2N words long. */ +/* Currently only designed to work for curve_p or curve_n. */ +uECC_VLI_API void uECC_vli_mmod(uECC_word_t *result, + uECC_word_t *product, + const uECC_word_t *mod, + wordcount_t num_words) { + uECC_word_t mod_multiple[2 * uECC_MAX_WORDS]; + uECC_word_t tmp[2 * uECC_MAX_WORDS]; + uECC_word_t *v[2] = {tmp, product}; + uECC_word_t index; + + /* Shift mod so its highest set bit is at the maximum position. */ + bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - uECC_vli_numBits(mod, num_words); + wordcount_t word_shift = shift / uECC_WORD_BITS; + wordcount_t bit_shift = shift % uECC_WORD_BITS; + uECC_word_t carry = 0; + uECC_vli_clear(mod_multiple, word_shift); + if (bit_shift > 0) { + for(index = 0; index < (uECC_word_t)num_words; ++index) { + mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry; + carry = mod[index] >> (uECC_WORD_BITS - bit_shift); + } + } else { + uECC_vli_set(mod_multiple + word_shift, mod, num_words); + } + + for (index = 1; shift >= 0; --shift) { + uECC_word_t borrow = 0; + wordcount_t i; + for (i = 0; i < num_words * 2; ++i) { + uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; + if (diff != v[index][i]) { + borrow = (diff > v[index][i]); + } + v[1 - index][i] = diff; + } + index = !(index ^ borrow); /* Swap the index if there was no borrow */ + uECC_vli_rshift1(mod_multiple, num_words); + mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); + uECC_vli_rshift1(mod_multiple + num_words, num_words); + } + uECC_vli_set(result, v[index], num_words); +} + +/* Computes result = (left * right) % mod. */ +uECC_VLI_API void uECC_vli_modMult(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod, + wordcount_t num_words) { + uECC_word_t product[2 * uECC_MAX_WORDS]; + uECC_vli_mult(product, left, right, num_words); + uECC_vli_mmod(result, product, mod, num_words); +} + +uECC_VLI_API void uECC_vli_modMult_fast(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + uECC_Curve curve) { + uECC_word_t product[2 * uECC_MAX_WORDS]; + uECC_vli_mult(product, left, right, curve->num_words); +#if (uECC_OPTIMIZATION_LEVEL > 0) + curve->mmod_fast(result, product); +#else + uECC_vli_mmod(result, product, curve->p, curve->num_words); +#endif +} + +#if uECC_SQUARE_FUNC + +#if uECC_ENABLE_VLI_API +/* Computes result = left^2 % mod. */ +uECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *mod, + wordcount_t num_words) { + uECC_word_t product[2 * uECC_MAX_WORDS]; + uECC_vli_square(product, left, num_words); + uECC_vli_mmod(result, product, mod, num_words); +} +#endif /* uECC_ENABLE_VLI_API */ + +uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result, + const uECC_word_t *left, + uECC_Curve curve) { + uECC_word_t product[2 * uECC_MAX_WORDS]; + uECC_vli_square(product, left, curve->num_words); +#if (uECC_OPTIMIZATION_LEVEL > 0) + curve->mmod_fast(result, product); +#else + uECC_vli_mmod(result, product, curve->p, curve->num_words); +#endif +} + +#else /* uECC_SQUARE_FUNC */ + +#if uECC_ENABLE_VLI_API +uECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *mod, + wordcount_t num_words) { + uECC_vli_modMult(result, left, left, mod, num_words); +} +#endif /* uECC_ENABLE_VLI_API */ + +uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result, + const uECC_word_t *left, + uECC_Curve curve) { + uECC_vli_modMult_fast(result, left, left, curve); +} + +#endif /* uECC_SQUARE_FUNC */ + +#define EVEN(vli) (!(vli[0] & 1)) +static void vli_modInv_update(uECC_word_t *uv, + const uECC_word_t *mod, + wordcount_t num_words) { + uECC_word_t carry = 0; + if (!EVEN(uv)) { + carry = uECC_vli_add(uv, uv, mod, num_words); + } + uECC_vli_rshift1(uv, num_words); + if (carry) { + uv[num_words - 1] |= HIGH_BIT_SET; + } +} + +/* Computes result = (1 / input) % mod. All VLIs are the same size. + See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" */ +uECC_VLI_API void uECC_vli_modInv(uECC_word_t *result, + const uECC_word_t *input, + const uECC_word_t *mod, + wordcount_t num_words) { + uECC_word_t a[uECC_MAX_WORDS], b[uECC_MAX_WORDS], u[uECC_MAX_WORDS], v[uECC_MAX_WORDS]; + cmpresult_t cmpResult; + + if (uECC_vli_isZero(input, num_words)) { + uECC_vli_clear(result, num_words); + return; + } + + uECC_vli_set(a, input, num_words); + uECC_vli_set(b, mod, num_words); + uECC_vli_clear(u, num_words); + u[0] = 1; + uECC_vli_clear(v, num_words); + while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) { + if (EVEN(a)) { + uECC_vli_rshift1(a, num_words); + vli_modInv_update(u, mod, num_words); + } else if (EVEN(b)) { + uECC_vli_rshift1(b, num_words); + vli_modInv_update(v, mod, num_words); + } else if (cmpResult > 0) { + uECC_vli_sub(a, a, b, num_words); + uECC_vli_rshift1(a, num_words); + if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) { + uECC_vli_add(u, u, mod, num_words); + } + uECC_vli_sub(u, u, v, num_words); + vli_modInv_update(u, mod, num_words); + } else { + uECC_vli_sub(b, b, a, num_words); + uECC_vli_rshift1(b, num_words); + if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) { + uECC_vli_add(v, v, mod, num_words); + } + uECC_vli_sub(v, v, u, num_words); + vli_modInv_update(v, mod, num_words); + } + } + uECC_vli_set(result, u, num_words); +} + +/* ------ Point operations ------ */ + +#include "curve-specific.inc" + +/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */ +#define EccPoint_isZero(point, curve) uECC_vli_isZero((point), (curve)->num_words * 2) + +/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates. +From http://eprint.iacr.org/2011/338.pdf +*/ + +/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ +static void apply_z(uECC_word_t * X1, + uECC_word_t * Y1, + const uECC_word_t * const Z, + uECC_Curve curve) { + uECC_word_t t1[uECC_MAX_WORDS]; + + uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */ + uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */ + uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */ + uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ +} + +/* P = (x1, y1) => 2P, (x2, y2) => P' */ +static void XYcZ_initial_double(uECC_word_t * X1, + uECC_word_t * Y1, + uECC_word_t * X2, + uECC_word_t * Y2, + const uECC_word_t * const initial_Z, + uECC_Curve curve) { + uECC_word_t z[uECC_MAX_WORDS]; + wordcount_t num_words = curve->num_words; + if (initial_Z) { + uECC_vli_set(z, initial_Z, num_words); + } else { + uECC_vli_clear(z, num_words); + z[0] = 1; + } + + uECC_vli_set(X2, X1, num_words); + uECC_vli_set(Y2, Y1, num_words); + + apply_z(X1, Y1, z, curve); + curve->double_jacobian(X1, Y1, z, curve); + apply_z(X2, Y2, z, curve); +} + +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) + Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) + or P => P', Q => P + Q +*/ +static void XYcZ_add(uECC_word_t * X1, + uECC_word_t * Y1, + uECC_word_t * X2, + uECC_word_t * Y2, + uECC_Curve curve) { + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uECC_word_t t5[uECC_MAX_WORDS]; + wordcount_t num_words = curve->num_words; + + uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ + uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ + uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */ + + uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */ + uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */ + uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */ + uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */ + uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */ + uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */ + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */ + + uECC_vli_set(X2, t5, num_words); +} + +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) + Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) + or P => P - Q, Q => P + Q +*/ +static void XYcZ_addC(uECC_word_t * X1, + uECC_word_t * Y1, + uECC_word_t * X2, + uECC_word_t * Y2, + uECC_Curve curve) { + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uECC_word_t t5[uECC_MAX_WORDS]; + uECC_word_t t6[uECC_MAX_WORDS]; + uECC_word_t t7[uECC_MAX_WORDS]; + wordcount_t num_words = curve->num_words; + + uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ + uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ + uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */ + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ + + uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */ + uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */ + uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */ + uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */ + uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */ + + uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */ + uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */ + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = (y2 - y1)*(B - x3) - E = y3 */ + + uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */ + uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */ + uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */ + uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */ + uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); /* t2 = (y2+y1)*(x3' - B) - E = y3' */ + + uECC_vli_set(X1, t7, num_words); +} + +/* result may overlap point. */ +static void EccPoint_mult(uECC_word_t * result, + const uECC_word_t * point, + const uECC_word_t * scalar, + const uECC_word_t * initial_Z, + bitcount_t num_bits, + uECC_Curve curve) { + /* R0 and R1 */ + uECC_word_t Rx[2][uECC_MAX_WORDS]; + uECC_word_t Ry[2][uECC_MAX_WORDS]; + uECC_word_t z[uECC_MAX_WORDS]; + bitcount_t i; + uECC_word_t nb; + wordcount_t num_words = curve->num_words; + + uECC_vli_set(Rx[1], point, num_words); + uECC_vli_set(Ry[1], point + num_words, num_words); + + XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve); + + for (i = num_bits - 2; i > 0; --i) { + nb = !uECC_vli_testBit(scalar, i); + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); + } + + nb = !uECC_vli_testBit(scalar, 0); + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + + /* Find final 1/Z value. */ + uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ + uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */ + uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */ + uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0)) */ + /* yP / (xP * Yb * (X1 - X0)) */ + uECC_vli_modMult_fast(z, z, point + num_words, curve); + uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */ + /* End 1/Z calculation */ + + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); + apply_z(Rx[0], Ry[0], z, curve); + + uECC_vli_set(result, Rx[0], num_words); + uECC_vli_set(result + num_words, Ry[0], num_words); +} + +static uECC_word_t regularize_k(const uECC_word_t * const k, + uECC_word_t *k0, + uECC_word_t *k1, + uECC_Curve curve) { + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + bitcount_t num_n_bits = curve->num_n_bits; + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && + uECC_vli_testBit(k0, num_n_bits)); + uECC_vli_add(k1, k0, curve->n, num_n_words); + return carry; +} + +/* Generates a random integer in the range 0 < random < top. + Both random and top have num_words words. */ +uECC_VLI_API int uECC_generate_random_int(uECC_word_t *random, + const uECC_word_t *top, + wordcount_t num_words) { + uECC_word_t mask = (uECC_word_t)-1; + uECC_word_t tries; + bitcount_t num_bits = uECC_vli_numBits(top, num_words); + + if (!g_rng_function) { + return 0; + } + + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { + return 0; + } + random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + if (!uECC_vli_isZero(random, num_words) && + uECC_vli_cmp(top, random, num_words) == 1) { + return 1; + } + } + return 0; +} + +static uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, + uECC_word_t *private_key, + uECC_Curve curve) { + uECC_word_t tmp1[uECC_MAX_WORDS]; + uECC_word_t tmp2[uECC_MAX_WORDS]; + uECC_word_t *p2[2] = {tmp1, tmp2}; + uECC_word_t *initial_Z = 0; + uECC_word_t carry; + + /* Regularize the bitcount for the private key so that attackers cannot use a side channel + attack to learn the number of leading zeros. */ + carry = regularize_k(private_key, tmp1, tmp2, curve); + + /* If an RNG function was specified, try to get a random initial Z value to improve + protection against side-channel attacks. */ + if (g_rng_function) { + if (!uECC_generate_random_int(p2[carry], curve->p, curve->num_words)) { + return 0; + } + initial_Z = p2[carry]; + } + EccPoint_mult(result, curve->G, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); + + if (EccPoint_isZero(result, curve)) { + return 0; + } + return 1; +} + +#if uECC_WORD_SIZE == 1 + +uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes, + int num_bytes, + const uint8_t *native) { + wordcount_t i; + for (i = 0; i < num_bytes; ++i) { + bytes[i] = native[(num_bytes - 1) - i]; + } +} + +uECC_VLI_API void uECC_vli_bytesToNative(uint8_t *native, + const uint8_t *bytes, + int num_bytes) { + uECC_vli_nativeToBytes(native, num_bytes, bytes); +} + +#else + +uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes, + int num_bytes, + const uECC_word_t *native) { + int i; + for (i = 0; i < num_bytes; ++i) { + unsigned b = num_bytes - 1 - i; + bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE)); + } +} + +uECC_VLI_API void uECC_vli_bytesToNative(uECC_word_t *native, + const uint8_t *bytes, + int num_bytes) { + int i; + uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); + for (i = 0; i < num_bytes; ++i) { + unsigned b = num_bytes - 1 - i; + native[b / uECC_WORD_SIZE] |= + (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); + } +} + +#endif /* uECC_WORD_SIZE */ + +int uECC_make_key(uint8_t *public_key, + uint8_t *private_key, + uECC_Curve curve) { +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + uECC_word_t *_private = (uECC_word_t *)private_key; + uECC_word_t *_public = (uECC_word_t *)public_key; +#else + uECC_word_t _private[uECC_MAX_WORDS]; + uECC_word_t _public[uECC_MAX_WORDS * 2]; +#endif + uECC_word_t tries; + + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + if (!uECC_generate_random_int(_private, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { + return 0; + } + + if (EccPoint_compute_public_key(_public, _private, curve)) { +#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 + uECC_vli_nativeToBytes(private_key, BITS_TO_BYTES(curve->num_n_bits), _private); + uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); + uECC_vli_nativeToBytes( + public_key + curve->num_bytes, curve->num_bytes, _public + curve->num_words); +#endif + return 1; + } + } + return 0; +} + +int uECC_shared_secret(const uint8_t *public_key, + const uint8_t *private_key, + uint8_t *secret, + uECC_Curve curve) { + uECC_word_t _public[uECC_MAX_WORDS * 2]; + uECC_word_t _private[uECC_MAX_WORDS]; + + uECC_word_t tmp[uECC_MAX_WORDS]; + uECC_word_t *p2[2] = {_private, tmp}; + uECC_word_t *initial_Z = 0; + uECC_word_t carry; + wordcount_t num_words = curve->num_words; + wordcount_t num_bytes = curve->num_bytes; + +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + bcopy((uint8_t *) _private, private_key, num_bytes); + bcopy((uint8_t *) _public, public_key, num_bytes*2); +#else + uECC_vli_bytesToNative(_private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + uECC_vli_bytesToNative(_public, public_key, num_bytes); + uECC_vli_bytesToNative(_public + num_words, public_key + num_bytes, num_bytes); +#endif + + /* Regularize the bitcount for the private key so that attackers cannot use a side channel + attack to learn the number of leading zeros. */ + carry = regularize_k(_private, _private, tmp, curve); + + /* If an RNG function was specified, try to get a random initial Z value to improve + protection against side-channel attacks. */ + if (g_rng_function) { + if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { + return 0; + } + initial_Z = p2[carry]; + } + + EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + bcopy((uint8_t *) secret, (uint8_t *) _public, num_bytes); +#else + uECC_vli_nativeToBytes(secret, num_bytes, _public); +#endif + return !EccPoint_isZero(_public, curve); +} + +#if uECC_SUPPORT_COMPRESSED_POINT +void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve) { + wordcount_t i; + for (i = 0; i < curve->num_bytes; ++i) { + compressed[i+1] = public_key[i]; + } +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + compressed[0] = 2 + (public_key[curve->num_bytes] & 0x01); +#else + compressed[0] = 2 + (public_key[curve->num_bytes * 2 - 1] & 0x01); +#endif +} + +void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + uECC_word_t *point = (uECC_word_t *)public_key; +#else + uECC_word_t point[uECC_MAX_WORDS * 2]; +#endif + uECC_word_t *y = point + curve->num_words; +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + bcopy(public_key, compressed+1, curve->num_bytes); +#else + uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes); +#endif + curve->x_side(y, point, curve); + curve->mod_sqrt(y, curve); + + if ((y[0] & 0x01) != (compressed[0] & 0x01)) { + uECC_vli_sub(y, curve->p, y, curve->num_words); + } + +#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 + uECC_vli_nativeToBytes(public_key, curve->num_bytes, point); + uECC_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, y); +#endif +} +#endif /* uECC_SUPPORT_COMPRESSED_POINT */ + +uECC_VLI_API int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { + uECC_word_t tmp1[uECC_MAX_WORDS]; + uECC_word_t tmp2[uECC_MAX_WORDS]; + wordcount_t num_words = curve->num_words; + + /* The point at infinity is invalid. */ + if (EccPoint_isZero(point, curve)) { + return 0; + } + + /* x and y must be smaller than p. */ + if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || + uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) { + return 0; + } + + uECC_vli_modSquare_fast(tmp1, point + num_words, curve); + curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ + + /* Make sure that y^2 == x^3 + ax + b */ + return (int)(uECC_vli_equal(tmp1, tmp2, num_words)); +} + +int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) { +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + uECC_word_t *_public = (uECC_word_t *)public_key; +#else + uECC_word_t _public[uECC_MAX_WORDS * 2]; +#endif + +#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 + uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); + uECC_vli_bytesToNative( + _public + curve->num_words, public_key + curve->num_bytes, curve->num_bytes); +#endif + return uECC_valid_point(_public, curve); +} + +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + uECC_word_t *_private = (uECC_word_t *)private_key; + uECC_word_t *_public = (uECC_word_t *)public_key; +#else + uECC_word_t _private[uECC_MAX_WORDS]; + uECC_word_t _public[uECC_MAX_WORDS * 2]; +#endif + +#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 + uECC_vli_bytesToNative(_private, private_key, BITS_TO_BYTES(curve->num_n_bits)); +#endif + + /* Make sure the private key is in the range [1, n-1]. */ + if (uECC_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) { + return 0; + } + + if (uECC_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != 1) { + return 0; + } + + /* Compute public key. */ + if (!EccPoint_compute_public_key(_public, _private, curve)) { + return 0; + } + +#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 + uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); + uECC_vli_nativeToBytes( + public_key + curve->num_bytes, curve->num_bytes, _public + curve->num_words); +#endif + return 1; +} + + +/* -------- ECDSA code -------- */ + +static void bits2int(uECC_word_t *native, + const uint8_t *bits, + unsigned bits_size, + uECC_Curve curve) { + unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); + unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); + int shift; + uECC_word_t carry; + uECC_word_t *ptr; + + if (bits_size > num_n_bytes) { + bits_size = num_n_bytes; + } + + uECC_vli_clear(native, num_n_words); +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + bcopy((uint8_t *) native, bits, bits_size); +#else + uECC_vli_bytesToNative(native, bits, bits_size); +#endif + if (bits_size * 8 <= (unsigned)curve->num_n_bits) { + return; + } + shift = bits_size * 8 - curve->num_n_bits; + carry = 0; + ptr = native + num_n_words; + while (ptr-- > native) { + uECC_word_t temp = *ptr; + *ptr = (temp >> shift) | carry; + carry = temp << (uECC_WORD_BITS - shift); + } + + /* Reduce mod curve_n */ + if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) { + uECC_vli_sub(native, native, curve->n, num_n_words); + } +} + +static int uECC_sign_with_k_internal(const uint8_t *private_key, + const uint8_t *message_hash, + unsigned hash_size, + uECC_word_t *k, + uint8_t *signature, + uECC_Curve curve) { + + uECC_word_t tmp[uECC_MAX_WORDS]; + uECC_word_t s[uECC_MAX_WORDS]; + uECC_word_t *k2[2] = {tmp, s}; + uECC_word_t *initial_Z = 0; +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + uECC_word_t *p = (uECC_word_t *)signature; +#else + uECC_word_t p[uECC_MAX_WORDS * 2]; +#endif + uECC_word_t carry; + wordcount_t num_words = curve->num_words; + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + bitcount_t num_n_bits = curve->num_n_bits; + + /* Make sure 0 < k < curve_n */ + if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { + return 0; + } + + carry = regularize_k(k, tmp, s, curve); + /* If an RNG function was specified, try to get a random initial Z value to improve + protection against side-channel attacks. */ + if (g_rng_function) { + if (!uECC_generate_random_int(k2[carry], curve->p, num_words)) { + return 0; + } + initial_Z = k2[carry]; + } + EccPoint_mult(p, curve->G, k2[!carry], initial_Z, num_n_bits + 1, curve); + if (uECC_vli_isZero(p, num_words)) { + return 0; + } + + /* If an RNG function was specified, get a random number + to prevent side channel analysis of k. */ + if (!g_rng_function) { + uECC_vli_clear(tmp, num_n_words); + tmp[0] = 1; + } else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) { + return 0; + } + + /* Prevent side channel analysis of uECC_vli_modInv() to determine + bits of k / the private key by premultiplying by a random number */ + uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ + uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */ + uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */ + +#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 + uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */ +#endif + +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + bcopy((uint8_t *) tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); +#else + uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); /* tmp = d */ +#endif + + s[num_n_words - 1] = 0; + uECC_vli_set(s, p, num_words); + uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ + + bits2int(tmp, message_hash, hash_size, curve); + uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ + uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ + if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) { + return 0; + } +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + bcopy((uint8_t *) signature + curve->num_bytes, (uint8_t *) s, curve->num_bytes); +#else + uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s); +#endif + return 1; +} + +/* For testing - sign with an explicitly specified k value */ +int uECC_sign_with_k(const uint8_t *private_key, + const uint8_t *message_hash, + unsigned hash_size, + const uint8_t *k, + uint8_t *signature, + uECC_Curve curve) { + uECC_word_t k2[uECC_MAX_WORDS]; + bits2int(k2, k, BITS_TO_BYTES(curve->num_n_bits), curve); + return uECC_sign_with_k_internal(private_key, message_hash, hash_size, k2, signature, curve); +} + +int uECC_sign(const uint8_t *private_key, + const uint8_t *message_hash, + unsigned hash_size, + uint8_t *signature, + uECC_Curve curve) { + uECC_word_t k[uECC_MAX_WORDS]; + uECC_word_t tries; + + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { + return 0; + } + + if (uECC_sign_with_k_internal(private_key, message_hash, hash_size, k, signature, curve)) { + return 1; + } + } + return 0; +} + +/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always + the same size as the hash result size. */ +static void HMAC_init(const uECC_HashContext *hash_context, const uint8_t *K) { + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + unsigned i; + for (i = 0; i < hash_context->result_size; ++i) + pad[i] = K[i] ^ 0x36; + for (; i < hash_context->block_size; ++i) + pad[i] = 0x36; + + hash_context->init_hash(hash_context); + hash_context->update_hash(hash_context, pad, hash_context->block_size); +} + +static void HMAC_update(const uECC_HashContext *hash_context, + const uint8_t *message, + unsigned message_size) { + hash_context->update_hash(hash_context, message, message_size); +} + +static void HMAC_finish(const uECC_HashContext *hash_context, + const uint8_t *K, + uint8_t *result) { + uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; + unsigned i; + for (i = 0; i < hash_context->result_size; ++i) + pad[i] = K[i] ^ 0x5c; + for (; i < hash_context->block_size; ++i) + pad[i] = 0x5c; + + hash_context->finish_hash(hash_context, result); + + hash_context->init_hash(hash_context); + hash_context->update_hash(hash_context, pad, hash_context->block_size); + hash_context->update_hash(hash_context, result, hash_context->result_size); + hash_context->finish_hash(hash_context, result); +} + +/* V = HMAC_K(V) */ +static void update_V(const uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) { + HMAC_init(hash_context, K); + HMAC_update(hash_context, V, hash_context->result_size); + HMAC_finish(hash_context, K, V); +} + +/* Deterministic signing, similar to RFC 6979. Differences are: + * We just use H(m) directly rather than bits2octets(H(m)) + (it is not reduced modulo curve_n). + * We generate a value for k (aka T) directly rather than converting endianness. + + Layout of hash_context->tmp: | | (1 byte overlapped 0x00 or 0x01) / */ +int uECC_sign_deterministic(const uint8_t *private_key, + const uint8_t *message_hash, + unsigned hash_size, + const uECC_HashContext *hash_context, + uint8_t *signature, + uECC_Curve curve) { + uint8_t *K = hash_context->tmp; + uint8_t *V = K + hash_context->result_size; + wordcount_t num_bytes = curve->num_bytes; + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + bitcount_t num_n_bits = curve->num_n_bits; + uECC_word_t tries; + unsigned i; + for (i = 0; i < hash_context->result_size; ++i) { + V[i] = 0x01; + K[i] = 0; + } + + /* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */ + HMAC_init(hash_context, K); + V[hash_context->result_size] = 0x00; + HMAC_update(hash_context, V, hash_context->result_size + 1); + HMAC_update(hash_context, private_key, num_bytes); + HMAC_update(hash_context, message_hash, hash_size); + HMAC_finish(hash_context, K, K); + + update_V(hash_context, K, V); + + /* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */ + HMAC_init(hash_context, K); + V[hash_context->result_size] = 0x01; + HMAC_update(hash_context, V, hash_context->result_size + 1); + HMAC_update(hash_context, private_key, num_bytes); + HMAC_update(hash_context, message_hash, hash_size); + HMAC_finish(hash_context, K, K); + + update_V(hash_context, K, V); + + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + uECC_word_t T[uECC_MAX_WORDS]; + uint8_t *T_ptr = (uint8_t *)T; + wordcount_t T_bytes = 0; + for (;;) { + update_V(hash_context, K, V); + for (i = 0; i < hash_context->result_size; ++i) { + T_ptr[T_bytes++] = V[i]; + if (T_bytes >= num_n_words * uECC_WORD_SIZE) { + goto filled; + } + } + } + filled: + if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) { + uECC_word_t mask = (uECC_word_t)-1; + T[num_n_words - 1] &= + mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits)); + } + + if (uECC_sign_with_k_internal(private_key, message_hash, hash_size, T, signature, curve)) { + return 1; + } + + /* K = HMAC_K(V || 0x00) */ + HMAC_init(hash_context, K); + V[hash_context->result_size] = 0x00; + HMAC_update(hash_context, V, hash_context->result_size + 1); + HMAC_finish(hash_context, K, K); + + update_V(hash_context, K, V); + } + return 0; +} + +static bitcount_t smax(bitcount_t a, bitcount_t b) { + return (a > b ? a : b); +} + +int uECC_verify(const uint8_t *public_key, + const uint8_t *message_hash, + unsigned hash_size, + const uint8_t *signature, + uECC_Curve curve) { + uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS]; + uECC_word_t z[uECC_MAX_WORDS]; + uECC_word_t sum[uECC_MAX_WORDS * 2]; + uECC_word_t rx[uECC_MAX_WORDS]; + uECC_word_t ry[uECC_MAX_WORDS]; + uECC_word_t tx[uECC_MAX_WORDS]; + uECC_word_t ty[uECC_MAX_WORDS]; + uECC_word_t tz[uECC_MAX_WORDS]; + const uECC_word_t *points[4]; + const uECC_word_t *point; + bitcount_t num_bits; + bitcount_t i; +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + uECC_word_t *_public = (uECC_word_t *)public_key; +#else + uECC_word_t _public[uECC_MAX_WORDS * 2]; +#endif + uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS]; + wordcount_t num_words = curve->num_words; + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + + rx[num_n_words - 1] = 0; + r[num_n_words - 1] = 0; + s[num_n_words - 1] = 0; + +#if uECC_VLI_NATIVE_LITTLE_ENDIAN + bcopy((uint8_t *) r, signature, curve->num_bytes); + bcopy((uint8_t *) s, signature + curve->num_bytes, curve->num_bytes); +#else + uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); + uECC_vli_bytesToNative( + _public + num_words, public_key + curve->num_bytes, curve->num_bytes); + uECC_vli_bytesToNative(r, signature, curve->num_bytes); + uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes); +#endif + + /* r, s must not be 0. */ + if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) { + return 0; + } + + /* r, s must be < n. */ + if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || + uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { + return 0; + } + + /* Calculate u1 and u2. */ + uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ + u1[num_n_words - 1] = 0; + bits2int(u1, message_hash, hash_size, curve); + uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ + uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ + + /* Calculate sum = G + Q. */ + uECC_vli_set(sum, _public, num_words); + uECC_vli_set(sum + num_words, _public + num_words, num_words); + uECC_vli_set(tx, curve->G, num_words); + uECC_vli_set(ty, curve->G + num_words, num_words); + uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */ + XYcZ_add(tx, ty, sum, sum + num_words, curve); + uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */ + apply_z(sum, sum + num_words, z, curve); + + /* Use Shamir's trick to calculate u1*G + u2*Q */ + points[0] = 0; + points[1] = curve->G; + points[2] = _public; + points[3] = sum; + num_bits = smax(uECC_vli_numBits(u1, num_n_words), + uECC_vli_numBits(u2, num_n_words)); + + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; + uECC_vli_set(rx, point, num_words); + uECC_vli_set(ry, point + num_words, num_words); + uECC_vli_clear(z, num_words); + z[0] = 1; + + for (i = num_bits - 2; i >= 0; --i) { + uECC_word_t index; + curve->double_jacobian(rx, ry, z, curve); + + index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1); + point = points[index]; + if (point) { + uECC_vli_set(tx, point, num_words); + uECC_vli_set(ty, point + num_words, num_words); + apply_z(tx, ty, z, curve); + uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */ + XYcZ_add(tx, ty, rx, ry, curve); + uECC_vli_modMult_fast(z, z, tz, curve); + } + } + + uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */ + apply_z(rx, ry, z, curve); + + /* v = x1 (mod n) */ + if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) { + uECC_vli_sub(rx, rx, curve->n, num_n_words); + } + + /* Accept only if v == r. */ + return (int)(uECC_vli_equal(rx, r, num_words)); +} + +#if uECC_ENABLE_VLI_API + +unsigned uECC_curve_num_words(uECC_Curve curve) { + return curve->num_words; +} + +unsigned uECC_curve_num_bytes(uECC_Curve curve) { + return curve->num_bytes; +} + +unsigned uECC_curve_num_bits(uECC_Curve curve) { + return curve->num_bytes * 8; +} + +unsigned uECC_curve_num_n_words(uECC_Curve curve) { + return BITS_TO_WORDS(curve->num_n_bits); +} + +unsigned uECC_curve_num_n_bytes(uECC_Curve curve) { + return BITS_TO_BYTES(curve->num_n_bits); +} + +unsigned uECC_curve_num_n_bits(uECC_Curve curve) { + return curve->num_n_bits; +} + +const uECC_word_t *uECC_curve_p(uECC_Curve curve) { + return curve->p; +} + +const uECC_word_t *uECC_curve_n(uECC_Curve curve) { + return curve->n; +} + +const uECC_word_t *uECC_curve_G(uECC_Curve curve) { + return curve->G; +} + +const uECC_word_t *uECC_curve_b(uECC_Curve curve) { + return curve->b; +} + +#if uECC_SUPPORT_COMPRESSED_POINT +void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve) { + curve->mod_sqrt(a, curve); +} +#endif + +void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve) { +#if (uECC_OPTIMIZATION_LEVEL > 0) + curve->mmod_fast(result, product); +#else + uECC_vli_mmod(result, product, curve->p, curve->num_words); +#endif +} + +void uECC_point_mult(uECC_word_t *result, + const uECC_word_t *point, + const uECC_word_t *scalar, + uECC_Curve curve) { + uECC_word_t tmp1[uECC_MAX_WORDS]; + uECC_word_t tmp2[uECC_MAX_WORDS]; + uECC_word_t *p2[2] = {tmp1, tmp2}; + uECC_word_t carry = regularize_k(scalar, tmp1, tmp2, curve); + + EccPoint_mult(result, point, p2[!carry], 0, curve->num_n_bits + 1, curve); +} + +#endif /* uECC_ENABLE_VLI_API */ diff --git a/lib/micro-ecc/uECC.h b/lib/micro-ecc/uECC.h new file mode 100644 index 00000000..dcbdbfa8 --- /dev/null +++ b/lib/micro-ecc/uECC.h @@ -0,0 +1,367 @@ +/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_H_ +#define _UECC_H_ + +#include + +/* Platform selection options. +If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros. +Possible values for uECC_PLATFORM are defined below: */ +#define uECC_arch_other 0 +#define uECC_x86 1 +#define uECC_x86_64 2 +#define uECC_arm 3 +#define uECC_arm_thumb 4 +#define uECC_arm_thumb2 5 +#define uECC_arm64 6 +#define uECC_avr 7 + +/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes). +If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your +platform. */ + +/* Optimization level; trade speed for code size. + Larger values produce code that is faster but larger. + Currently supported values are 0 - 4; 0 is unusably slow for most applications. + Optimization level 4 currently only has an effect ARM platforms where more than one + curve is enabled. */ +#ifndef uECC_OPTIMIZATION_LEVEL + #define uECC_OPTIMIZATION_LEVEL 2 +#endif + +/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be +used for (scalar) squaring instead of the generic multiplication function. This can make things +faster somewhat faster, but increases the code size. */ +#ifndef uECC_SQUARE_FUNC + #define uECC_SQUARE_FUNC 0 +#endif + +/* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will switch to native +little-endian format for *all* arrays passed in and out of the public API. This includes public +and private keys, shared secrets, signatures and message hashes. +Using this switch reduces the amount of call stack memory used by uECC, since less intermediate +translations are required. +Note that this will *only* work on native little-endian processors and it will treat the uint8_t +arrays passed into the public API as word arrays, therefore requiring the provided byte arrays +to be word aligned on architectures that do not support unaligned accesses. +IMPORTANT: Keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible +with keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use +the same endianness. */ +#ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN + #define uECC_VLI_NATIVE_LITTLE_ENDIAN 0 +#endif + +/* Curve support selection. Set to 0 to remove that curve. */ +#ifndef uECC_SUPPORTS_secp160r1 + #define uECC_SUPPORTS_secp160r1 1 +#endif +#ifndef uECC_SUPPORTS_secp192r1 + #define uECC_SUPPORTS_secp192r1 1 +#endif +#ifndef uECC_SUPPORTS_secp224r1 + #define uECC_SUPPORTS_secp224r1 1 +#endif +#ifndef uECC_SUPPORTS_secp256r1 + #define uECC_SUPPORTS_secp256r1 1 +#endif +#ifndef uECC_SUPPORTS_secp256k1 + #define uECC_SUPPORTS_secp256k1 1 +#endif + +/* Specifies whether compressed point format is supported. + Set to 0 to disable point compression/decompression functions. */ +#ifndef uECC_SUPPORT_COMPRESSED_POINT + #define uECC_SUPPORT_COMPRESSED_POINT 1 +#endif + +struct uECC_Curve_t; +typedef const struct uECC_Curve_t * uECC_Curve; + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if uECC_SUPPORTS_secp160r1 +uECC_Curve uECC_secp160r1(void); +#endif +#if uECC_SUPPORTS_secp192r1 +uECC_Curve uECC_secp192r1(void); +#endif +#if uECC_SUPPORTS_secp224r1 +uECC_Curve uECC_secp224r1(void); +#endif +#if uECC_SUPPORTS_secp256r1 +uECC_Curve uECC_secp256r1(void); +#endif +#if uECC_SUPPORTS_secp256k1 +uECC_Curve uECC_secp256k1(void); +#endif + +/* uECC_RNG_Function type +The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if +'dest' was filled with random data, or 0 if the random data could not be generated. +The filled-in values should be either truly random, or from a cryptographically-secure PRNG. + +A correctly functioning RNG function must be set (using uECC_set_rng()) before calling +uECC_make_key() or uECC_sign(). + +Setting a correctly functioning RNG function improves the resistance to side-channel attacks +for uECC_shared_secret() and uECC_sign_deterministic(). + +A correct RNG function is set by default when building for Windows, Linux, or OS X. +If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom, +you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined +RNG function; you must provide your own. +*/ +typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size); + +/* uECC_set_rng() function. +Set the function that will be used to generate random bytes. The RNG function should +return 1 if the random data was generated, or 0 if the random data could not be generated. + +On platforms where there is no predefined RNG function (eg embedded platforms), this must +be called before uECC_make_key() or uECC_sign() are used. + +Inputs: + rng_function - The function that will be used to generate random bytes. +*/ +void uECC_set_rng(uECC_RNG_Function rng_function); + +/* uECC_get_rng() function. + +Returns the function that will be used to generate random bytes. +*/ +uECC_RNG_Function uECC_get_rng(void); + +/* uECC_curve_private_key_size() function. + +Returns the size of a private key for the curve in bytes. +*/ +int uECC_curve_private_key_size(uECC_Curve curve); + +/* uECC_curve_public_key_size() function. + +Returns the size of a public key for the curve in bytes. +*/ +int uECC_curve_public_key_size(uECC_Curve curve); + +/* uECC_make_key() function. +Create a public/private key pair. + +Outputs: + public_key - Will be filled in with the public key. Must be at least 2 * the curve size + (in bytes) long. For example, if the curve is secp256r1, public_key must be 64 + bytes long. + private_key - Will be filled in with the private key. Must be as long as the curve order; this + is typically the same as the curve size, except for secp160r1. For example, if the + curve is secp256r1, private_key must be 32 bytes long. + + For secp160r1, private_key must be 21 bytes long! Note that the first byte will + almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero). + +Returns 1 if the key pair was generated successfully, 0 if an error occurred. +*/ +int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve); + +/* uECC_shared_secret() function. +Compute a shared secret given your secret key and someone else's public key. If the public key +is not from a trusted source and has not been previously verified, you should verify it first +using uECC_valid_public_key(). +Note: It is recommended that you hash the result of uECC_shared_secret() before using it for +symmetric encryption or HMAC. + +Inputs: + public_key - The public key of the remote party. + private_key - Your private key. + +Outputs: + secret - Will be filled in with the shared secret value. Must be the same size as the + curve size; for example, if the curve is secp256r1, secret must be 32 bytes long. + +Returns 1 if the shared secret was generated successfully, 0 if an error occurred. +*/ +int uECC_shared_secret(const uint8_t *public_key, + const uint8_t *private_key, + uint8_t *secret, + uECC_Curve curve); + +#if uECC_SUPPORT_COMPRESSED_POINT +/* uECC_compress() function. +Compress a public key. + +Inputs: + public_key - The public key to compress. + +Outputs: + compressed - Will be filled in with the compressed public key. Must be at least + (curve size + 1) bytes long; for example, if the curve is secp256r1, + compressed must be 33 bytes long. +*/ +void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve); + +/* uECC_decompress() function. +Decompress a compressed public key. + +Inputs: + compressed - The compressed public key. + +Outputs: + public_key - Will be filled in with the decompressed public key. +*/ +void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve); +#endif /* uECC_SUPPORT_COMPRESSED_POINT */ + +/* uECC_valid_public_key() function. +Check to see if a public key is valid. + +Note that you are not required to check for a valid public key before using any other uECC +functions. However, you may wish to avoid spending CPU time computing a shared secret or +verifying a signature using an invalid public key. + +Inputs: + public_key - The public key to check. + +Returns 1 if the public key is valid, 0 if it is invalid. +*/ +int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve); + +/* uECC_compute_public_key() function. +Compute the corresponding public key for a private key. + +Inputs: + private_key - The private key to compute the public key for + +Outputs: + public_key - Will be filled in with the corresponding public key + +Returns 1 if the key was computed successfully, 0 if an error occurred. +*/ +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve); + +/* uECC_sign() function. +Generate an ECDSA signature for a given hash value. + +Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to +this function along with your private key. + +Inputs: + private_key - Your private key. + message_hash - The hash of the message to sign. + hash_size - The size of message_hash in bytes. + +Outputs: + signature - Will be filled in with the signature value. Must be at least 2 * curve size long. + For example, if the curve is secp256r1, signature must be 64 bytes long. + +Returns 1 if the signature generated successfully, 0 if an error occurred. +*/ +int uECC_sign(const uint8_t *private_key, + const uint8_t *message_hash, + unsigned hash_size, + uint8_t *signature, + uECC_Curve curve); + +/* uECC_HashContext structure. +This is used to pass in an arbitrary hash function to uECC_sign_deterministic(). +The structure will be used for multiple hash computations; each time a new hash +is computed, init_hash() will be called, followed by one or more calls to +update_hash(), and finally a call to finish_hash() to produce the resulting hash. + +The intention is that you will create a structure that includes uECC_HashContext +followed by any hash-specific data. For example: + +typedef struct SHA256_HashContext { + uECC_HashContext uECC; + SHA256_CTX ctx; +} SHA256_HashContext; + +void init_SHA256(uECC_HashContext *base) { + SHA256_HashContext *context = (SHA256_HashContext *)base; + SHA256_Init(&context->ctx); +} + +void update_SHA256(uECC_HashContext *base, + const uint8_t *message, + unsigned message_size) { + SHA256_HashContext *context = (SHA256_HashContext *)base; + SHA256_Update(&context->ctx, message, message_size); +} + +void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) { + SHA256_HashContext *context = (SHA256_HashContext *)base; + SHA256_Final(hash_result, &context->ctx); +} + +... when signing ... +{ + uint8_t tmp[32 + 32 + 64]; + SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}}; + uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature); +} +*/ +typedef struct uECC_HashContext { + void (*init_hash)(const struct uECC_HashContext *context); + void (*update_hash)(const struct uECC_HashContext *context, + const uint8_t *message, + unsigned message_size); + void (*finish_hash)(const struct uECC_HashContext *context, uint8_t *hash_result); + unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ + unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ + uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */ +} uECC_HashContext; + +/* uECC_sign_deterministic() function. +Generate an ECDSA signature for a given hash value, using a deterministic algorithm +(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling +this function; however, if the RNG is defined it will improve resistance to side-channel +attacks. + +Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to +this function along with your private key and a hash context. Note that the message_hash +does not need to be computed with the same hash function used by hash_context. + +Inputs: + private_key - Your private key. + message_hash - The hash of the message to sign. + hash_size - The size of message_hash in bytes. + hash_context - A hash context to use. + +Outputs: + signature - Will be filled in with the signature value. + +Returns 1 if the signature generated successfully, 0 if an error occurred. +*/ +int uECC_sign_deterministic(const uint8_t *private_key, + const uint8_t *message_hash, + unsigned hash_size, + const uECC_HashContext *hash_context, + uint8_t *signature, + uECC_Curve curve); + +/* uECC_verify() function. +Verify an ECDSA signature. + +Usage: Compute the hash of the signed data using the same hash as the signer and +pass it to this function along with the signer's public key and the signature values (r and s). + +Inputs: + public_key - The signer's public key. + message_hash - The hash of the signed data. + hash_size - The size of message_hash in bytes. + signature - The signature value. + +Returns 1 if the signature is valid, 0 if it is invalid. +*/ +int uECC_verify(const uint8_t *public_key, + const uint8_t *message_hash, + unsigned hash_size, + const uint8_t *signature, + uECC_Curve curve); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _UECC_H_ */ diff --git a/lib/micro-ecc/uECC_vli.h b/lib/micro-ecc/uECC_vli.h new file mode 100644 index 00000000..864cc333 --- /dev/null +++ b/lib/micro-ecc/uECC_vli.h @@ -0,0 +1,172 @@ +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_VLI_H_ +#define _UECC_VLI_H_ + +#include "uECC.h" +#include "types.h" + +/* Functions for raw large-integer manipulation. These are only available + if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */ +#ifndef uECC_ENABLE_VLI_API + #define uECC_ENABLE_VLI_API 0 +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if uECC_ENABLE_VLI_API + +void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words); + +/* Constant-time comparison to zero - secure way to compare long integers */ +/* Returns 1 if vli == 0, 0 otherwise. */ +uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words); + +/* Returns nonzero if bit 'bit' of vli is set. */ +uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit); + +/* Counts the number of bits required to represent vli. */ +bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words); + +/* Sets dest = src. */ +void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words); + +/* Constant-time comparison function - secure way to compare long integers */ +/* Returns one if left == right, zero otherwise */ +uECC_word_t uECC_vli_equal(const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words); + +/* Constant-time comparison function - secure way to compare long integers */ +/* Returns sign of left - right, in constant time. */ +cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words); + +/* Computes vli = vli >> 1. */ +void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words); + +/* Computes result = left + right, returning carry. Can modify in place. */ +uECC_word_t uECC_vli_add(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words); + +/* Computes result = left - right, returning borrow. Can modify in place. */ +uECC_word_t uECC_vli_sub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words); + +/* Computes result = left * right. Result must be 2 * num_words long. */ +void uECC_vli_mult(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words); + +/* Computes result = left^2. Result must be 2 * num_words long. */ +void uECC_vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words); + +/* Computes result = (left + right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap mod. */ +void uECC_vli_modAdd(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod, + wordcount_t num_words); + +/* Computes result = (left - right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap mod. */ +void uECC_vli_modSub(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod, + wordcount_t num_words); + +/* Computes result = product % mod, where product is 2N words long. + Currently only designed to work for mod == curve->p or curve_n. */ +void uECC_vli_mmod(uECC_word_t *result, + uECC_word_t *product, + const uECC_word_t *mod, + wordcount_t num_words); + +/* Calculates result = product (mod curve->p), where product is up to + 2 * curve->num_words long. */ +void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve); + +/* Computes result = (left * right) % mod. + Currently only designed to work for mod == curve->p or curve_n. */ +void uECC_vli_modMult(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + const uECC_word_t *mod, + wordcount_t num_words); + +/* Computes result = (left * right) % curve->p. */ +void uECC_vli_modMult_fast(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *right, + uECC_Curve curve); + +/* Computes result = left^2 % mod. + Currently only designed to work for mod == curve->p or curve_n. */ +void uECC_vli_modSquare(uECC_word_t *result, + const uECC_word_t *left, + const uECC_word_t *mod, + wordcount_t num_words); + +/* Computes result = left^2 % curve->p. */ +void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left, uECC_Curve curve); + +/* Computes result = (1 / input) % mod.*/ +void uECC_vli_modInv(uECC_word_t *result, + const uECC_word_t *input, + const uECC_word_t *mod, + wordcount_t num_words); + +#if uECC_SUPPORT_COMPRESSED_POINT +/* Calculates a = sqrt(a) (mod curve->p) */ +void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve); +#endif + +/* Converts an integer in uECC native format to big-endian bytes. */ +void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, const uECC_word_t *native); +/* Converts big-endian bytes to an integer in uECC native format. */ +void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes, int num_bytes); + +unsigned uECC_curve_num_words(uECC_Curve curve); +unsigned uECC_curve_num_bytes(uECC_Curve curve); +unsigned uECC_curve_num_bits(uECC_Curve curve); +unsigned uECC_curve_num_n_words(uECC_Curve curve); +unsigned uECC_curve_num_n_bytes(uECC_Curve curve); +unsigned uECC_curve_num_n_bits(uECC_Curve curve); + +const uECC_word_t *uECC_curve_p(uECC_Curve curve); +const uECC_word_t *uECC_curve_n(uECC_Curve curve); +const uECC_word_t *uECC_curve_G(uECC_Curve curve); +const uECC_word_t *uECC_curve_b(uECC_Curve curve); + +int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve); + +/* Multiplies a point by a scalar. Points are represented by the X coordinate followed by + the Y coordinate in the same array, both coordinates are curve->num_words long. Note + that scalar must be curve->num_n_words long (NOT curve->num_words). */ +void uECC_point_mult(uECC_word_t *result, + const uECC_word_t *point, + const uECC_word_t *scalar, + uECC_Curve curve); + +/* Generates a random integer in the range 0 < random < top. + Both random and top have num_words words. */ +int uECC_generate_random_int(uECC_word_t *random, + const uECC_word_t *top, + wordcount_t num_words); + +#endif /* uECC_ENABLE_VLI_API */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _UECC_VLI_H_ */ diff --git a/lib/toolbox/hmac_sha256.c b/lib/toolbox/hmac_sha256.c new file mode 100644 index 00000000..93570216 --- /dev/null +++ b/lib/toolbox/hmac_sha256.c @@ -0,0 +1,123 @@ +/* + * hmac.c - HMAC + * + * Copyright (C) 2017 Sergei Glushchenko + * Author: Sergei Glushchenko + * + * This file is a part of U2F firmware for STM32 + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * As additional permission under GNU GPL version 3 section 7, you may + * distribute non-source form of the Program without the copy of the + * GNU GPL normally required by section 4, provided you inform the + * recipients of GNU GPL by a written offer. + * + */ +#include + +#include "sha256.h" +#include "hmac_sha256.h" + +static void +_hmac_sha256_init (const hmac_context *ctx) +{ + hmac_sha256_context *context = (hmac_sha256_context *)ctx; + sha256_start(&context->sha_ctx); +} + +static void +_hmac_sha256_update (const hmac_context *ctx, const uint8_t *message, + unsigned message_size) +{ + hmac_sha256_context *context = (hmac_sha256_context *)ctx; + sha256_update(&context->sha_ctx, message, message_size); +} + +static void +_hmac_sha256_finish (const hmac_context *ctx, uint8_t *hash_result) +{ + hmac_sha256_context *context = (hmac_sha256_context *)ctx; + sha256_finish(&context->sha_ctx, hash_result); +} + +/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always + the same size as the hash result size. */ +static void +hmac_init(const hmac_context *ctx, const uint8_t *K) +{ + uint8_t *pad = ctx->tmp + 2 * ctx->result_size; + unsigned i; + for (i = 0; i < ctx->result_size; ++i) + pad[i] = K[i] ^ 0x36; + for (; i < ctx->block_size; ++i) + pad[i] = 0x36; + + ctx->init_hash (ctx); + ctx->update_hash (ctx, pad, ctx->block_size); +} + +static void +hmac_update(const hmac_context *ctx, + const uint8_t *message, + unsigned message_size) +{ + ctx->update_hash (ctx, message, message_size); +} + +static void +hmac_finish(const hmac_context *ctx, + const uint8_t *K, + uint8_t *result) +{ + uint8_t *pad = ctx->tmp + 2 * ctx->result_size; + unsigned i; + for (i = 0; i < ctx->result_size; ++i) + pad[i] = K[i] ^ 0x5c; + for (; i < ctx->block_size; ++i) + pad[i] = 0x5c; + + ctx->finish_hash (ctx, result); + + ctx->init_hash (ctx); + ctx->update_hash (ctx, pad, ctx->block_size); + ctx->update_hash (ctx, result, ctx->result_size); + ctx->finish_hash (ctx, result); +} + +void +hmac_sha256_init (hmac_sha256_context *ctx, const uint8_t *K) +{ + ctx->hmac_ctx.init_hash = _hmac_sha256_init; + ctx->hmac_ctx.update_hash = _hmac_sha256_update; + ctx->hmac_ctx.finish_hash = _hmac_sha256_finish; + ctx->hmac_ctx.block_size = 64; + ctx->hmac_ctx.result_size = 32; + ctx->hmac_ctx.tmp = ctx->tmp; + hmac_init (&ctx->hmac_ctx, K); +} + +void +hmac_sha256_update (const hmac_sha256_context *ctx, const uint8_t *message, + unsigned message_size) +{ + hmac_update (&ctx->hmac_ctx, message, message_size); +} + +void +hmac_sha256_finish (const hmac_sha256_context *ctx, const uint8_t *K, + uint8_t *hash_result) +{ + hmac_finish (&ctx->hmac_ctx, K, hash_result); +} diff --git a/lib/toolbox/hmac_sha256.h b/lib/toolbox/hmac_sha256.h new file mode 100644 index 00000000..c4c8d98a --- /dev/null +++ b/lib/toolbox/hmac_sha256.h @@ -0,0 +1,29 @@ + +typedef struct hmac_context { + void (*init_hash)(const struct hmac_context *context); + void (*update_hash)(const struct hmac_context *context, + const uint8_t *message, + unsigned message_size); + void (*finish_hash)(const struct hmac_context *context, uint8_t *hash_result); + unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ + unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ + uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */ +} hmac_context; + + +typedef struct hmac_sha256_context { + hmac_context hmac_ctx; + sha256_context sha_ctx; + uint8_t tmp[32 * 2 + 64]; +} hmac_sha256_context; + +void +hmac_sha256_init (hmac_sha256_context *ctx, const uint8_t *K); + +void +hmac_sha256_update (const hmac_sha256_context *ctx, const uint8_t *message, + unsigned message_size); + +void +hmac_sha256_finish (const hmac_sha256_context *ctx, const uint8_t *K, + uint8_t *hash_result); diff --git a/lib/toolbox/sha256.c b/lib/toolbox/sha256.c new file mode 100644 index 00000000..a44e22e1 --- /dev/null +++ b/lib/toolbox/sha256.c @@ -0,0 +1,226 @@ +/* + * sha256.c -- Compute SHA-256 hash + * + * Just for little endian architecture. + * + * Code taken from: + * http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php + * + * File names are sha2.c, sha2.h, brg_types.h, brg_endian.h + * in the archive sha2-07-01-07.zip. + * + * Code is modified in the style of PolarSSL API. + * + * See original copyright notice below. + */ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 01/08/2005 +*/ + +#include +#include +#include +#include "sha256.h" + +#define SHA256_MASK (SHA256_BLOCK_SIZE - 1) + +static void memcpy_output_bswap32 (unsigned char *dst, const uint32_t *p) +{ + int i; + uint32_t q = 0; + + for (i = 0; i < 32; i++) + { + if ((i & 3) == 0) + q = __builtin_bswap32 (p[i >> 2]); /* bswap32 is GCC extention */ + dst[i] = q >> ((i & 3) * 8); + } +} + +#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) + +#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) + +/* round transforms for SHA256 compression functions */ +#define vf(n,i) v[(n - i) & 7] + +#define hf(i) (p[i & 15] += \ + g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15])) + +#define v_cycle0(i) \ + p[i] = __builtin_bswap32 (p[i]); \ + vf(7,i) += p[i] + k_0[i] \ + + s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \ + vf(3,i) += vf(7,i); \ + vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i)) + +#define v_cycle(i, j) \ + vf(7,i) += hf(i) + k_0[i+j] \ + + s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \ + vf(3,i) += vf(7,i); \ + vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i)) + +#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22)) +#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25)) +#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3)) +#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) +#define k_0 k256 + +static const uint32_t k256[64] = { + 0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5, + 0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5, + 0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3, + 0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174, + 0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC, + 0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA, + 0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7, + 0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967, + 0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13, + 0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85, + 0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3, + 0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070, + 0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5, + 0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3, + 0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208, + 0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2, +}; + +void +sha256_process (sha256_context *ctx) +{ + uint32_t i; + uint32_t *p = ctx->wbuf; + uint32_t v[8]; + + memcpy (v, ctx->state, 8 * sizeof (uint32_t)); + + v_cycle0 ( 0); v_cycle0 ( 1); v_cycle0 ( 2); v_cycle0 ( 3); + v_cycle0 ( 4); v_cycle0 ( 5); v_cycle0 ( 6); v_cycle0 ( 7); + v_cycle0 ( 8); v_cycle0 ( 9); v_cycle0 (10); v_cycle0 (11); + v_cycle0 (12); v_cycle0 (13); v_cycle0 (14); v_cycle0 (15); + + for (i = 16; i < 64; i += 16) + { + v_cycle ( 0, i); v_cycle ( 1, i); v_cycle ( 2, i); v_cycle ( 3, i); + v_cycle ( 4, i); v_cycle ( 5, i); v_cycle ( 6, i); v_cycle ( 7, i); + v_cycle ( 8, i); v_cycle ( 9, i); v_cycle (10, i); v_cycle (11, i); + v_cycle (12, i); v_cycle (13, i); v_cycle (14, i); v_cycle (15, i); + } + + ctx->state[0] += v[0]; + ctx->state[1] += v[1]; + ctx->state[2] += v[2]; + ctx->state[3] += v[3]; + ctx->state[4] += v[4]; + ctx->state[5] += v[5]; + ctx->state[6] += v[6]; + ctx->state[7] += v[7]; +} + +void +sha256_update (sha256_context *ctx, const unsigned char *input, + unsigned int ilen) +{ + uint32_t left = (ctx->total[0] & SHA256_MASK); + uint32_t fill = SHA256_BLOCK_SIZE - left; + + ctx->total[0] += ilen; + if (ctx->total[0] < ilen) + ctx->total[1]++; + + while (ilen >= fill) + { + memcpy (((unsigned char*)ctx->wbuf) + left, input, fill); + sha256_process (ctx); + input += fill; + ilen -= fill; + left = 0; + fill = SHA256_BLOCK_SIZE; + } + + memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen); +} + +void +sha256_finish (sha256_context *ctx, unsigned char output[32]) +{ + uint32_t last = (ctx->total[0] & SHA256_MASK); + + ctx->wbuf[last >> 2] = __builtin_bswap32 (ctx->wbuf[last >> 2]); + ctx->wbuf[last >> 2] &= 0xffffff80 << (8 * (~last & 3)); + ctx->wbuf[last >> 2] |= 0x00000080 << (8 * (~last & 3)); + ctx->wbuf[last >> 2] = __builtin_bswap32 (ctx->wbuf[last >> 2]); + + if (last > SHA256_BLOCK_SIZE - 9) + { + if (last < 60) + ctx->wbuf[15] = 0; + sha256_process (ctx); + last = 0; + } + else + last = (last >> 2) + 1; + + while (last < 14) + ctx->wbuf[last++] = 0; + + ctx->wbuf[14] = __builtin_bswap32 ((ctx->total[0] >> 29) | (ctx->total[1] << 3)); + ctx->wbuf[15] = __builtin_bswap32 (ctx->total[0] << 3); + sha256_process (ctx); + + memcpy_output_bswap32 (output, ctx->state); + memset (ctx, 0, sizeof (sha256_context)); +} + +static const uint32_t initial_state[8] = +{ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +void +sha256_start (sha256_context *ctx) +{ + ctx->total[0] = ctx->total[1] = 0; + memcpy (ctx->state, initial_state, 8 * sizeof(uint32_t)); +} + +void +sha256 (const unsigned char *input, unsigned int ilen, + unsigned char output[32]) +{ + sha256_context ctx; + + sha256_start (&ctx); + sha256_update (&ctx, input, ilen); + sha256_finish (&ctx, output); +} diff --git a/lib/toolbox/sha256.h b/lib/toolbox/sha256.h new file mode 100644 index 00000000..1454c3f5 --- /dev/null +++ b/lib/toolbox/sha256.h @@ -0,0 +1,17 @@ +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 + +typedef struct +{ + uint32_t total[2]; + uint32_t state[8]; + uint32_t wbuf[16]; +} sha256_context; + +void sha256 (const unsigned char *input, unsigned int ilen, + unsigned char output[32]); +void sha256_start (sha256_context *ctx); +void sha256_finish (sha256_context *ctx, unsigned char output[32]); +void sha256_update (sha256_context *ctx, const unsigned char *input, + unsigned int ilen); +void sha256_process (sha256_context *ctx); From 0c7a38b99fcf51c0733e080b71d613926cb787c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 23 Dec 2021 19:24:09 +0300 Subject: [PATCH 12/14] [FL-2156] Switch to smaller radio stack. (#923) * Switch to smaller radio stack. BleGlue: update params to match new stack. Update scripts * Git: set eol to lf --- .gitattributes | 2 +- Makefile | 2 +- firmware/targets/f6/ble-glue/app_conf.h | 38 ++++++++++++++++++----- firmware/targets/f6/ble-glue/ble_app.c | 40 ++++++++++++++----------- firmware/targets/f7/ble-glue/app_conf.h | 38 ++++++++++++++++++----- firmware/targets/f7/ble-glue/ble_app.c | 40 ++++++++++++++----------- scripts/flipper/copro.py | 6 ++-- 7 files changed, 109 insertions(+), 57 deletions(-) diff --git a/.gitattributes b/.gitattributes index 176a458f..6313b56c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -* text=auto +* text=auto eol=lf diff --git a/Makefile b/Makefile index 062f10a3..41bb98ae 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ endif .PHONY: flash_radio flash_radio: - @$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080C7000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_full_fw.bin + @$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080D7000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_light_fw.bin @$(PROJECT_ROOT)/scripts/ob.py set .PHONY: flash_radio_fus diff --git a/firmware/targets/f6/ble-glue/app_conf.h b/firmware/targets/f6/ble-glue/app_conf.h index 059e8e4f..ec8fc604 100644 --- a/firmware/targets/f6/ble-glue/app_conf.h +++ b/firmware/targets/f6/ble-glue/app_conf.h @@ -139,7 +139,7 @@ /** * Maximum supported ATT_MTU size */ -#define CFG_BLE_MAX_ATT_MTU (489) +#define CFG_BLE_MAX_ATT_MTU (256+128+16+8+4+2) /** * Size of the storage area for Attribute values @@ -211,14 +211,36 @@ #define CFG_BLE_VITERBI_MODE 1 /** - * LL Only Mode - * 1 : LL Only - * 0 : LL + Host + * BLE stack Options flags to be configured with: + * - SHCI_C2_BLE_INIT_OPTIONS_LL_ONLY + * - SHCI_C2_BLE_INIT_OPTIONS_LL_HOST + * - SHCI_C2_BLE_INIT_OPTIONS_NO_SVC_CHANGE_DESC + * - SHCI_C2_BLE_INIT_OPTIONS_WITH_SVC_CHANGE_DESC + * - SHCI_C2_BLE_INIT_OPTIONS_DEVICE_NAME_RO + * - SHCI_C2_BLE_INIT_OPTIONS_DEVICE_NAME_RW + * - SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV + * - SHCI_C2_BLE_INIT_OPTIONS_NO_EXT_ADV + * - SHCI_C2_BLE_INIT_OPTIONS_CS_ALGO2 + * - SHCI_C2_BLE_INIT_OPTIONS_NO_CS_ALGO2 + * - SHCI_C2_BLE_INIT_OPTIONS_POWER_CLASS_1 + * - SHCI_C2_BLE_INIT_OPTIONS_POWER_CLASS_2_3 + * which are used to set following configuration bits: + * (bit 0): 1: LL only + * 0: LL + host + * (bit 1): 1: no service change desc. + * 0: with service change desc. + * (bit 2): 1: device name Read-Only + * 0: device name R/W + * (bit 3): 1: extended advertizing supported [NOT SUPPORTED] + * 0: extended advertizing not supported [NOT SUPPORTED] + * (bit 4): 1: CS Algo #2 supported + * 0: CS Algo #2 not supported + * (bit 7): 1: LE Power Class 1 + * 0: LE Power Class 2-3 + * other bits: reserved (shall be set to 0) */ -#define CFG_BLE_LL_ONLY 0 -/****************************************************************************** - * Transport Layer - ******************************************************************************/ +#define CFG_BLE_OPTIONS (SHCI_C2_BLE_INIT_OPTIONS_LL_HOST | SHCI_C2_BLE_INIT_OPTIONS_WITH_SVC_CHANGE_DESC | SHCI_C2_BLE_INIT_OPTIONS_DEVICE_NAME_RW | SHCI_C2_BLE_INIT_OPTIONS_NO_EXT_ADV | SHCI_C2_BLE_INIT_OPTIONS_NO_CS_ALGO2 | SHCI_C2_BLE_INIT_OPTIONS_POWER_CLASS_2_3) + /** * Queue length of BLE Event * This parameter defines the number of asynchronous events that can be stored in the HCI layer before diff --git a/firmware/targets/f6/ble-glue/ble_app.c b/firmware/targets/f6/ble-glue/ble_app.c index 3ceecbbc..989cea32 100644 --- a/firmware/targets/f6/ble-glue/ble_app.c +++ b/firmware/targets/f6/ble-glue/ble_app.c @@ -67,24 +67,28 @@ bool ble_app_init() { SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { .Header = {{0,0,0}}, // Header unused .Param = { - 0, // pBleBufferAddress not used - 0, // BleBufferSize not used - CFG_BLE_NUM_GATT_ATTRIBUTES, - CFG_BLE_NUM_GATT_SERVICES, - CFG_BLE_ATT_VALUE_ARRAY_SIZE, - CFG_BLE_NUM_LINK, - CFG_BLE_DATA_LENGTH_EXTENSION, - CFG_BLE_PREPARE_WRITE_LIST_SIZE, - CFG_BLE_MBLOCK_COUNT, - CFG_BLE_MAX_ATT_MTU, - CFG_BLE_SLAVE_SCA, - CFG_BLE_MASTER_SCA, - CFG_BLE_LSE_SOURCE, - CFG_BLE_MAX_CONN_EVENT_LENGTH, - CFG_BLE_HSE_STARTUP_TIME, - CFG_BLE_VITERBI_MODE, - CFG_BLE_LL_ONLY, - 0, + .pBleBufferAddress = 0, // pBleBufferAddress not used + .BleBufferSize = 0, // BleBufferSize not used + .NumAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES, + .NumAttrServ = CFG_BLE_NUM_GATT_SERVICES, + .AttrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE, + .NumOfLinks = CFG_BLE_NUM_LINK, + .ExtendedPacketLengthEnable = CFG_BLE_DATA_LENGTH_EXTENSION, + .PrWriteListSize = CFG_BLE_PREPARE_WRITE_LIST_SIZE, + .MblockCount = CFG_BLE_MBLOCK_COUNT, + .AttMtu = CFG_BLE_MAX_ATT_MTU, + .SlaveSca = CFG_BLE_SLAVE_SCA, + .MasterSca = CFG_BLE_MASTER_SCA, + .LsSource = CFG_BLE_LSE_SOURCE, + .MaxConnEventLength = CFG_BLE_MAX_CONN_EVENT_LENGTH, + .HsStartupTime = CFG_BLE_HSE_STARTUP_TIME, + .ViterbiEnable = CFG_BLE_VITERBI_MODE, + .Options = CFG_BLE_OPTIONS, + .HwVersion = 0, + .max_coc_initiator_nbr = 32, + .min_tx_power = 0, + .max_tx_power = 0, + .rx_model_config = 1, } }; status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); diff --git a/firmware/targets/f7/ble-glue/app_conf.h b/firmware/targets/f7/ble-glue/app_conf.h index 059e8e4f..ec8fc604 100644 --- a/firmware/targets/f7/ble-glue/app_conf.h +++ b/firmware/targets/f7/ble-glue/app_conf.h @@ -139,7 +139,7 @@ /** * Maximum supported ATT_MTU size */ -#define CFG_BLE_MAX_ATT_MTU (489) +#define CFG_BLE_MAX_ATT_MTU (256+128+16+8+4+2) /** * Size of the storage area for Attribute values @@ -211,14 +211,36 @@ #define CFG_BLE_VITERBI_MODE 1 /** - * LL Only Mode - * 1 : LL Only - * 0 : LL + Host + * BLE stack Options flags to be configured with: + * - SHCI_C2_BLE_INIT_OPTIONS_LL_ONLY + * - SHCI_C2_BLE_INIT_OPTIONS_LL_HOST + * - SHCI_C2_BLE_INIT_OPTIONS_NO_SVC_CHANGE_DESC + * - SHCI_C2_BLE_INIT_OPTIONS_WITH_SVC_CHANGE_DESC + * - SHCI_C2_BLE_INIT_OPTIONS_DEVICE_NAME_RO + * - SHCI_C2_BLE_INIT_OPTIONS_DEVICE_NAME_RW + * - SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV + * - SHCI_C2_BLE_INIT_OPTIONS_NO_EXT_ADV + * - SHCI_C2_BLE_INIT_OPTIONS_CS_ALGO2 + * - SHCI_C2_BLE_INIT_OPTIONS_NO_CS_ALGO2 + * - SHCI_C2_BLE_INIT_OPTIONS_POWER_CLASS_1 + * - SHCI_C2_BLE_INIT_OPTIONS_POWER_CLASS_2_3 + * which are used to set following configuration bits: + * (bit 0): 1: LL only + * 0: LL + host + * (bit 1): 1: no service change desc. + * 0: with service change desc. + * (bit 2): 1: device name Read-Only + * 0: device name R/W + * (bit 3): 1: extended advertizing supported [NOT SUPPORTED] + * 0: extended advertizing not supported [NOT SUPPORTED] + * (bit 4): 1: CS Algo #2 supported + * 0: CS Algo #2 not supported + * (bit 7): 1: LE Power Class 1 + * 0: LE Power Class 2-3 + * other bits: reserved (shall be set to 0) */ -#define CFG_BLE_LL_ONLY 0 -/****************************************************************************** - * Transport Layer - ******************************************************************************/ +#define CFG_BLE_OPTIONS (SHCI_C2_BLE_INIT_OPTIONS_LL_HOST | SHCI_C2_BLE_INIT_OPTIONS_WITH_SVC_CHANGE_DESC | SHCI_C2_BLE_INIT_OPTIONS_DEVICE_NAME_RW | SHCI_C2_BLE_INIT_OPTIONS_NO_EXT_ADV | SHCI_C2_BLE_INIT_OPTIONS_NO_CS_ALGO2 | SHCI_C2_BLE_INIT_OPTIONS_POWER_CLASS_2_3) + /** * Queue length of BLE Event * This parameter defines the number of asynchronous events that can be stored in the HCI layer before diff --git a/firmware/targets/f7/ble-glue/ble_app.c b/firmware/targets/f7/ble-glue/ble_app.c index 3ceecbbc..989cea32 100644 --- a/firmware/targets/f7/ble-glue/ble_app.c +++ b/firmware/targets/f7/ble-glue/ble_app.c @@ -67,24 +67,28 @@ bool ble_app_init() { SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { .Header = {{0,0,0}}, // Header unused .Param = { - 0, // pBleBufferAddress not used - 0, // BleBufferSize not used - CFG_BLE_NUM_GATT_ATTRIBUTES, - CFG_BLE_NUM_GATT_SERVICES, - CFG_BLE_ATT_VALUE_ARRAY_SIZE, - CFG_BLE_NUM_LINK, - CFG_BLE_DATA_LENGTH_EXTENSION, - CFG_BLE_PREPARE_WRITE_LIST_SIZE, - CFG_BLE_MBLOCK_COUNT, - CFG_BLE_MAX_ATT_MTU, - CFG_BLE_SLAVE_SCA, - CFG_BLE_MASTER_SCA, - CFG_BLE_LSE_SOURCE, - CFG_BLE_MAX_CONN_EVENT_LENGTH, - CFG_BLE_HSE_STARTUP_TIME, - CFG_BLE_VITERBI_MODE, - CFG_BLE_LL_ONLY, - 0, + .pBleBufferAddress = 0, // pBleBufferAddress not used + .BleBufferSize = 0, // BleBufferSize not used + .NumAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES, + .NumAttrServ = CFG_BLE_NUM_GATT_SERVICES, + .AttrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE, + .NumOfLinks = CFG_BLE_NUM_LINK, + .ExtendedPacketLengthEnable = CFG_BLE_DATA_LENGTH_EXTENSION, + .PrWriteListSize = CFG_BLE_PREPARE_WRITE_LIST_SIZE, + .MblockCount = CFG_BLE_MBLOCK_COUNT, + .AttMtu = CFG_BLE_MAX_ATT_MTU, + .SlaveSca = CFG_BLE_SLAVE_SCA, + .MasterSca = CFG_BLE_MASTER_SCA, + .LsSource = CFG_BLE_LSE_SOURCE, + .MaxConnEventLength = CFG_BLE_MAX_CONN_EVENT_LENGTH, + .HsStartupTime = CFG_BLE_HSE_STARTUP_TIME, + .ViterbiEnable = CFG_BLE_VITERBI_MODE, + .Options = CFG_BLE_OPTIONS, + .HwVersion = 0, + .max_coc_initiator_nbr = 32, + .min_tx_power = 0, + .max_tx_power = 0, + .rx_model_config = 1, } }; status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); diff --git a/scripts/flipper/copro.py b/scripts/flipper/copro.py index 104610e9..065fc33e 100644 --- a/scripts/flipper/copro.py +++ b/scripts/flipper/copro.py @@ -14,7 +14,7 @@ MANIFEST_TEMPLATE = { "fus": {"version": {"major": 1, "minor": 2, "sub": 0}, "files": []}, "radio": { "version": { - "type": 1, + "type": 3, "major": 1, "minor": 13, "sub": 0, @@ -88,8 +88,8 @@ class Copro: # BLE Full Stack self.addFile( manifest["copro"]["radio"]["files"], - "stm32wb5x_BLE_Stack_full_fw.bin", - address="0x080C7000", + "stm32wb5x_BLE_Stack_light_fw.bin", + address="0x080D7000", ) # Save manifest to json.dump(manifest, open(manifest_file, "w")) From 79e0aed1e6be9e8670595219a5e1567e92ab183b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Fri, 24 Dec 2021 14:19:46 +0300 Subject: [PATCH 13/14] Scripts: update ob.data to match current radio stack (#927) --- scripts/ob.data | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/ob.data b/scripts/ob.data index 423be57e..5276a510 100644 --- a/scripts/ob.data +++ b/scripts/ob.data @@ -14,15 +14,15 @@ IWDGSTOP:0x1:rw IWDGSW:0x1:rw IPCCDBA:0x0:rw ESE:0x1:r -SFSA:0xC7:r +SFSA:0xD7:r FSD:0x0:r DDS:0x1:r C2OPT:0x1:r NBRSD:0x0:r -SNBRSA:0xF:r +SNBRSA:0xD:r BRSD:0x0:r -SBRSA:0xA:r -SBRV:0x31C00:r +SBRSA:0x12:r +SBRV:0x35C00:r PCROP1A_STRT:0x1FF:r PCROP1A_END:0x0:r PCROP_RDP:0x1:rw From 7cea359be84cb8bf72879f1264faf9b088b054f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Fri, 24 Dec 2021 17:33:58 +0300 Subject: [PATCH 14/14] Storage: lfs config fingerprinting. RTC: fix data collision in lock register, refactor and cleanup. (#928) --- applications/desktop/desktop.c | 5 +-- .../desktop/helpers/desktop_animation.c | 2 +- .../desktop/scenes/desktop_scene_lock_menu.c | 3 +- .../desktop/scenes/desktop_scene_locked.c | 3 +- applications/dolphin/passport/passport.c | 3 +- applications/storage/storages/storage-int.c | 28 +++++++++++- .../targets/f6/furi-hal/furi-hal-bootloader.c | 8 ++-- firmware/targets/f6/furi-hal/furi-hal-lock.c | 17 ------- firmware/targets/f6/furi-hal/furi-hal-rtc.c | 45 ++++++++++++------- .../targets/f6/furi-hal/furi-hal-version.c | 6 ++- .../targets/f7/furi-hal/furi-hal-bootloader.c | 8 ++-- firmware/targets/f7/furi-hal/furi-hal-lock.c | 17 ------- firmware/targets/f7/furi-hal/furi-hal-rtc.c | 45 ++++++++++++------- .../targets/f7/furi-hal/furi-hal-version.c | 6 ++- .../targets/furi-hal-include/furi-hal-lock.h | 5 --- .../targets/furi-hal-include/furi-hal-rtc.h | 13 ++++++ 16 files changed, 119 insertions(+), 95 deletions(-) delete mode 100644 firmware/targets/f6/furi-hal/furi-hal-lock.c delete mode 100644 firmware/targets/f7/furi-hal/furi-hal-lock.c delete mode 100644 firmware/targets/furi-hal-include/furi-hal-lock.h diff --git a/applications/desktop/desktop.c b/applications/desktop/desktop.c index aa82cdbb..9d4df2a7 100644 --- a/applications/desktop/desktop.c +++ b/applications/desktop/desktop.c @@ -8,7 +8,6 @@ #include "portmacro.h" #include "storage/filesystem-api-defines.h" #include "storage/storage.h" -#include #include #include #include "helpers/desktop_animation.h" @@ -155,14 +154,14 @@ int32_t desktop_srv(void* p) { bool loaded = LOAD_DESKTOP_SETTINGS(&desktop->settings); if(!loaded) { - furi_hal_lock_set(false); + furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); memset(&desktop->settings, 0, sizeof(desktop->settings)); SAVE_DESKTOP_SETTINGS(&desktop->settings); } scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); - if(furi_hal_lock_get()) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { furi_hal_usb_disable(); scene_manager_set_scene_state( desktop->scene_manager, DesktopSceneLocked, DesktopLockedWithPin); diff --git a/applications/desktop/helpers/desktop_animation.c b/applications/desktop/helpers/desktop_animation.c index 40f3b7e4..5fb26512 100644 --- a/applications/desktop/helpers/desktop_animation.c +++ b/applications/desktop/helpers/desktop_animation.c @@ -82,7 +82,7 @@ void desktop_start_new_idle_animation(DesktopAnimation* animation) { DolphinStats stats = dolphin_stats(dolphin); furi_record_close("dolphin"); - furi_assert((stats.level >= 1) && (stats.level <= 3)); + furi_check((stats.level >= 1) && (stats.level <= 3)); AnimationList_t animation_list; AnimationList_init(animation_list); diff --git a/applications/desktop/scenes/desktop_scene_lock_menu.c b/applications/desktop/scenes/desktop_scene_lock_menu.c index 8a73739f..ee7ff9b4 100644 --- a/applications/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/desktop/scenes/desktop_scene_lock_menu.c @@ -2,7 +2,6 @@ #include "../views/desktop_lock_menu.h" #include #include -#include void desktop_scene_lock_menu_callback(DesktopLockMenuEvent event, void* context) { Desktop* desktop = (Desktop*)context; @@ -33,7 +32,7 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { break; case DesktopLockMenuEventPinLock: if(desktop->settings.pincode.length > 0) { - furi_hal_lock_set(true); + furi_hal_rtc_set_flag(FuriHalRtcFlagLock); furi_hal_usb_disable(); scene_manager_set_scene_state( desktop->scene_manager, DesktopSceneLocked, DesktopLockedWithPin); diff --git a/applications/desktop/scenes/desktop_scene_locked.c b/applications/desktop/scenes/desktop_scene_locked.c index 78000acf..c6f73b6a 100644 --- a/applications/desktop/scenes/desktop_scene_locked.c +++ b/applications/desktop/scenes/desktop_scene_locked.c @@ -2,7 +2,6 @@ #include "../views/desktop_locked.h" #include "desktop/helpers/desktop_animation.h" #include "desktop/views/desktop_main.h" -#include void desktop_scene_locked_callback(DesktopLockedEvent event, void* context) { Desktop* desktop = (Desktop*)context; @@ -56,7 +55,7 @@ static bool desktop_scene_locked_check_pin(Desktop* desktop, DesktopMainEvent ev if(match) { desktop->pincode_buffer.length = 0; furi_hal_usb_enable(); - furi_hal_lock_set(false); + furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); desktop_main_unlocked(desktop->main_view); } diff --git a/applications/dolphin/passport/passport.c b/applications/dolphin/passport/passport.c index 4be35566..17cba7fd 100644 --- a/applications/dolphin/passport/passport.c +++ b/applications/dolphin/passport/passport.c @@ -103,8 +103,7 @@ int32_t passport_app(void* p) { gui_add_view_port(gui, view_port, GuiLayerFullscreen); view_port_update(view_port); - osStatus_t status = osSemaphoreAcquire(semaphore, osWaitForever); - furi_assert(status == osOK); + furi_check(osSemaphoreAcquire(semaphore, osWaitForever) == osOK); gui_remove_view_port(gui, view_port); view_port_free(view_port); diff --git a/applications/storage/storages/storage-int.c b/applications/storage/storages/storage-int.c index 097934b6..3351be3b 100644 --- a/applications/storage/storages/storage-int.c +++ b/applications/storage/storages/storage-int.c @@ -161,12 +161,36 @@ static LFSData* storage_int_lfs_data_alloc() { return lfs_data; }; +static bool storage_int_is_fingerprint_valid(LFSData* lfs_data) { + bool value = true; + + uint32_t os_fingerprint = 0; + os_fingerprint |= ((lfs_data->start_page & 0xFF) << 0); + os_fingerprint |= ((lfs_data->config.block_count & 0xFF) << 8); + os_fingerprint |= ((LFS_DISK_VERSION_MAJOR & 0xFFFF) << 16); + + uint32_t rtc_fingerprint = furi_hal_rtc_get_register(FuriHalRtcRegisterLfsFingerprint); + if(rtc_fingerprint == 0) { + FURI_LOG_I(TAG, "Storing LFS fingerprint in RTC"); + furi_hal_rtc_set_register(FuriHalRtcRegisterLfsFingerprint, os_fingerprint); + } else if(rtc_fingerprint != os_fingerprint) { + FURI_LOG_E(TAG, "LFS fingerprint mismatch"); + furi_hal_rtc_set_register(FuriHalRtcRegisterLfsFingerprint, os_fingerprint); + value = false; + } + + return value; +} + static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) { int err; lfs_t* lfs = &lfs_data->lfs; - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagFactoryReset)) { - // Factory reset + bool need_format = furi_hal_rtc_is_flag_set(FuriHalRtcFlagFactoryReset) || + !storage_int_is_fingerprint_valid(lfs_data); + + if(need_format) { + // Format storage err = lfs_format(lfs, &lfs_data->config); if(err == 0) { FURI_LOG_I(TAG, "Factory reset: Format successful, trying to mount"); diff --git a/firmware/targets/f6/furi-hal/furi-hal-bootloader.c b/firmware/targets/f6/furi-hal/furi-hal-bootloader.c index b5e7cb5c..eca6f947 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-bootloader.c +++ b/firmware/targets/f6/furi-hal/furi-hal-bootloader.c @@ -1,5 +1,5 @@ #include -#include +#include #include #define TAG "FuriHalBoot" @@ -11,15 +11,15 @@ void furi_hal_bootloader_init() { #ifndef DEBUG - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_TAINTED); + furi_hal_rtc_set_register(FuriHalRtcRegisterBoot, BOOT_REQUEST_TAINTED); #endif FURI_LOG_I(TAG, "Init OK"); } void furi_hal_bootloader_set_mode(FuriHalBootloaderMode mode) { if (mode == FuriHalBootloaderModeNormal) { - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_CLEAN); + furi_hal_rtc_set_register(FuriHalRtcRegisterBoot, BOOT_REQUEST_CLEAN); } else if (mode == FuriHalBootloaderModeDFU) { - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_DFU); + furi_hal_rtc_set_register(FuriHalRtcRegisterBoot, BOOT_REQUEST_DFU); } } diff --git a/firmware/targets/f6/furi-hal/furi-hal-lock.c b/firmware/targets/f6/furi-hal/furi-hal-lock.c deleted file mode 100644 index 0f519380..00000000 --- a/firmware/targets/f6/furi-hal/furi-hal-lock.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "furi-hal-lock.h" -#include - -#define FLIPPER_LOCKED_VALUE 0x5432FAFA - -bool furi_hal_lock_get() { - return FLIPPER_LOCKED_VALUE == LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR3); -} - -void furi_hal_lock_set(bool locked) { - if (locked) { - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR3, FLIPPER_LOCKED_VALUE); - } else { - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR3, 0); - } -} - diff --git a/firmware/targets/f6/furi-hal/furi-hal-rtc.c b/firmware/targets/f6/furi-hal/furi-hal-rtc.c index 20e77e13..45498077 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-rtc.c +++ b/firmware/targets/f6/furi-hal/furi-hal-rtc.c @@ -6,10 +6,6 @@ #define TAG "FuriHalRtc" -#define FURI_HAL_RTC_BOOT_FLAGS_REG LL_RTC_BKP_DR0 -#define FURI_HAL_RTC_BOOT_VERSION_REG LL_RTC_BKP_DR1 -#define FURI_HAL_RTC_SYSTEM_REG LL_RTC_BKP_DR2 - typedef struct { uint8_t log_level:4; uint8_t log_reserved:4; @@ -17,6 +13,8 @@ typedef struct { uint16_t reserved; } DeveloperReg; +_Static_assert(sizeof(DeveloperReg) == 4, "DeveloperReg size mismatch"); + void furi_hal_rtc_init() { if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) { LL_RCC_ForceBackupDomainReset(); @@ -38,33 +36,46 @@ void furi_hal_rtc_init() { FURI_LOG_I(TAG, "Init OK"); } +uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg) { + return LL_RTC_BAK_GetRegister(RTC, reg); +} + +void furi_hal_rtc_set_register(FuriHalRtcRegister reg, uint32_t value) { + LL_RTC_BAK_SetRegister(RTC, reg, value); +} + void furi_hal_rtc_set_log_level(uint8_t level) { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - ((DeveloperReg*)&data)->log_level = level; - LL_RTC_BAK_SetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG, data); + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + data->log_level = level; + furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg); furi_log_set_level(level); } uint8_t furi_hal_rtc_get_log_level() { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - return ((DeveloperReg*)&data)->log_level; + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + return data->log_level; } void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - ((DeveloperReg*)&data)->flags |= flag; - LL_RTC_BAK_SetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG, data); + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + data->flags |= flag; + furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg); } void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - ((DeveloperReg*)&data)->flags &= ~flag; - LL_RTC_BAK_SetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG, data); + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + data->flags &= ~flag; + furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg); } bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag) { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - return ((DeveloperReg*)&data)->flags & flag; + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + return data->flags & flag; } void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) { diff --git a/firmware/targets/f6/furi-hal/furi-hal-version.c b/firmware/targets/f6/furi-hal/furi-hal-version.c index 8f5f26d9..218a6be4 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-version.c +++ b/firmware/targets/f6/furi-hal/furi-hal-version.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -193,6 +194,9 @@ void furi_hal_version_init() { break; default: furi_crash(NULL); } + + furi_hal_rtc_set_register(FuriHalRtcRegisterSystemVersion, (uint32_t)version_get()); + FURI_LOG_I(TAG, "Init OK"); } @@ -283,7 +287,7 @@ const struct Version* furi_hal_version_get_bootloader_version(void) { return 0; #else /* Backup register which points to structure in flash memory */ - return (const struct Version*)LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR1); + return (const struct Version*)furi_hal_rtc_get_register(FuriHalRtcRegisterBootVersion); #endif } diff --git a/firmware/targets/f7/furi-hal/furi-hal-bootloader.c b/firmware/targets/f7/furi-hal/furi-hal-bootloader.c index b5e7cb5c..eca6f947 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-bootloader.c +++ b/firmware/targets/f7/furi-hal/furi-hal-bootloader.c @@ -1,5 +1,5 @@ #include -#include +#include #include #define TAG "FuriHalBoot" @@ -11,15 +11,15 @@ void furi_hal_bootloader_init() { #ifndef DEBUG - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_TAINTED); + furi_hal_rtc_set_register(FuriHalRtcRegisterBoot, BOOT_REQUEST_TAINTED); #endif FURI_LOG_I(TAG, "Init OK"); } void furi_hal_bootloader_set_mode(FuriHalBootloaderMode mode) { if (mode == FuriHalBootloaderModeNormal) { - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_CLEAN); + furi_hal_rtc_set_register(FuriHalRtcRegisterBoot, BOOT_REQUEST_CLEAN); } else if (mode == FuriHalBootloaderModeDFU) { - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_DFU); + furi_hal_rtc_set_register(FuriHalRtcRegisterBoot, BOOT_REQUEST_DFU); } } diff --git a/firmware/targets/f7/furi-hal/furi-hal-lock.c b/firmware/targets/f7/furi-hal/furi-hal-lock.c deleted file mode 100644 index 0f519380..00000000 --- a/firmware/targets/f7/furi-hal/furi-hal-lock.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "furi-hal-lock.h" -#include - -#define FLIPPER_LOCKED_VALUE 0x5432FAFA - -bool furi_hal_lock_get() { - return FLIPPER_LOCKED_VALUE == LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR3); -} - -void furi_hal_lock_set(bool locked) { - if (locked) { - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR3, FLIPPER_LOCKED_VALUE); - } else { - LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR3, 0); - } -} - diff --git a/firmware/targets/f7/furi-hal/furi-hal-rtc.c b/firmware/targets/f7/furi-hal/furi-hal-rtc.c index 20e77e13..45498077 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-rtc.c +++ b/firmware/targets/f7/furi-hal/furi-hal-rtc.c @@ -6,10 +6,6 @@ #define TAG "FuriHalRtc" -#define FURI_HAL_RTC_BOOT_FLAGS_REG LL_RTC_BKP_DR0 -#define FURI_HAL_RTC_BOOT_VERSION_REG LL_RTC_BKP_DR1 -#define FURI_HAL_RTC_SYSTEM_REG LL_RTC_BKP_DR2 - typedef struct { uint8_t log_level:4; uint8_t log_reserved:4; @@ -17,6 +13,8 @@ typedef struct { uint16_t reserved; } DeveloperReg; +_Static_assert(sizeof(DeveloperReg) == 4, "DeveloperReg size mismatch"); + void furi_hal_rtc_init() { if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) { LL_RCC_ForceBackupDomainReset(); @@ -38,33 +36,46 @@ void furi_hal_rtc_init() { FURI_LOG_I(TAG, "Init OK"); } +uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg) { + return LL_RTC_BAK_GetRegister(RTC, reg); +} + +void furi_hal_rtc_set_register(FuriHalRtcRegister reg, uint32_t value) { + LL_RTC_BAK_SetRegister(RTC, reg, value); +} + void furi_hal_rtc_set_log_level(uint8_t level) { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - ((DeveloperReg*)&data)->log_level = level; - LL_RTC_BAK_SetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG, data); + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + data->log_level = level; + furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg); furi_log_set_level(level); } uint8_t furi_hal_rtc_get_log_level() { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - return ((DeveloperReg*)&data)->log_level; + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + return data->log_level; } void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - ((DeveloperReg*)&data)->flags |= flag; - LL_RTC_BAK_SetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG, data); + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + data->flags |= flag; + furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg); } void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - ((DeveloperReg*)&data)->flags &= ~flag; - LL_RTC_BAK_SetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG, data); + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + data->flags &= ~flag; + furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg); } bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag) { - uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG); - return ((DeveloperReg*)&data)->flags & flag; + uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem); + DeveloperReg* data = (DeveloperReg*)&data_reg; + return data->flags & flag; } void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) { diff --git a/firmware/targets/f7/furi-hal/furi-hal-version.c b/firmware/targets/f7/furi-hal/furi-hal-version.c index f38e6cdc..bd561c72 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-version.c +++ b/firmware/targets/f7/furi-hal/furi-hal-version.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -193,6 +194,9 @@ void furi_hal_version_init() { break; default: furi_crash(NULL); } + + furi_hal_rtc_set_register(FuriHalRtcRegisterSystemVersion, (uint32_t)version_get()); + FURI_LOG_I(TAG, "Init OK"); } @@ -283,7 +287,7 @@ const struct Version* furi_hal_version_get_bootloader_version(void) { return 0; #else /* Backup register which points to structure in flash memory */ - return (const struct Version*)LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR1); + return (const struct Version*)furi_hal_rtc_get_register(FuriHalRtcRegisterBootVersion); #endif } diff --git a/firmware/targets/furi-hal-include/furi-hal-lock.h b/firmware/targets/furi-hal-include/furi-hal-lock.h deleted file mode 100644 index d07ce571..00000000 --- a/firmware/targets/furi-hal-include/furi-hal-lock.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -#include - -bool furi_hal_lock_get(); -void furi_hal_lock_set(bool locked); diff --git a/firmware/targets/furi-hal-include/furi-hal-rtc.h b/firmware/targets/furi-hal-include/furi-hal-rtc.h index cc2f56f5..36bf218c 100644 --- a/firmware/targets/furi-hal-include/furi-hal-rtc.h +++ b/firmware/targets/furi-hal-include/furi-hal-rtc.h @@ -28,11 +28,24 @@ typedef struct { typedef enum { FuriHalRtcFlagDebug = (1<<0), FuriHalRtcFlagFactoryReset = (1<<1), + FuriHalRtcFlagLock = (1<<2), } FuriHalRtcFlag; +typedef enum { + FuriHalRtcRegisterBoot, + FuriHalRtcRegisterBootVersion, + FuriHalRtcRegisterSystem, + FuriHalRtcRegisterSystemVersion, + FuriHalRtcRegisterLfsFingerprint, +} FuriHalRtcRegister; + /** Initialize RTC subsystem */ void furi_hal_rtc_init(); +uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg); + +void furi_hal_rtc_set_register(FuriHalRtcRegister reg, uint32_t value); + void furi_hal_rtc_set_log_level(uint8_t level); uint8_t furi_hal_rtc_get_log_level();