From 9b5ae7359d4d585c5501d192bbc6665ad568ce03 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sat, 27 Dec 2025 17:18:24 +0100 Subject: [PATCH 01/26] Add pawn library and app --- src/CMakeLists.txt | 22 +- src/displayapp/UserApps.h | 1 + src/displayapp/apps/Apps.h.in | 1 + src/displayapp/apps/CMakeLists.txt | 1 + src/displayapp/screens/Pawn.cpp | 119 + src/displayapp/screens/Pawn.h | 42 + src/displayapp/screens/program.h | 57 + src/pawn/amx.c | 3871 ++++++++++++++++++++++++++++ src/pawn/amx.h | 569 ++++ src/pawn/osdefs.h | 159 ++ 10 files changed, 4840 insertions(+), 2 deletions(-) create mode 100644 src/displayapp/screens/Pawn.cpp create mode 100644 src/displayapp/screens/Pawn.h create mode 100644 src/displayapp/screens/program.h create mode 100644 src/pawn/amx.c create mode 100644 src/pawn/amx.h create mode 100644 src/pawn/osdefs.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4a354df64..18b16c05e5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -355,6 +355,10 @@ set(LVGL_SRC libs/lvgl/src/lv_widgets/lv_win.c ) +list(APPEND PAWN_SRC + pawn/amx.c +) + list(APPEND IMAGE_FILES displayapp/icons/battery/batteryicon.c ) @@ -398,6 +402,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Alarm.cpp displayapp/screens/Styles.cpp displayapp/screens/WeatherSymbols.cpp + displayapp/screens/Pawn.cpp displayapp/Colors.cpp displayapp/widgets/Counter.cpp displayapp/widgets/PageIndicator.cpp @@ -900,6 +905,19 @@ target_compile_options(lvgl PRIVATE $<$: ${ASM_FLAGS}> ) +# pawn +add_library(pawn STATIC ${PAWN_SRC}) +target_include_directories(pawn SYSTEM PUBLIC . ../) +target_include_directories(pawn SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) +target_compile_options(pawn PRIVATE + ${COMMON_FLAGS} + -DAMX_ANSIONLY + $<$: ${DEBUG_FLAGS}> + $<$: ${RELEASE_FLAGS}> + $<$: ${CXX_FLAGS}> + $<$: ${ASM_FLAGS}> + ) + # LITTLEFS_SRC add_library(littlefs STATIC ${LITTLEFS_SRC}) target_include_directories(littlefs SYSTEM PUBLIC . ../) @@ -918,7 +936,7 @@ set(EXECUTABLE_FILE_NAME ${EXECUTABLE_NAME}-${pinetime_VERSION_MAJOR}.${pinetime set(NRF5_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/gcc_nrf52.ld") add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES}) set_target_properties(${EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_FILE_NAME}) -target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl pawn littlefs infinitime_fonts infinitime_apps) target_compile_options(${EXECUTABLE_NAME} PUBLIC ${COMMON_FLAGS} ${WARNING_FLAGS} @@ -952,7 +970,7 @@ set(IMAGE_MCUBOOT_FILE_NAME_BIN ${EXECUTABLE_MCUBOOT_NAME}-image-${pinetime_VERS set(DFU_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip) set(NRF5_LINKER_SCRIPT_MCUBOOT "${CMAKE_SOURCE_DIR}/gcc_nrf52-mcuboot.ld") add_executable(${EXECUTABLE_MCUBOOT_NAME} ${SOURCE_FILES}) -target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl pawn littlefs infinitime_fonts infinitime_apps) set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_MCUBOOT_FILE_NAME}) target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC ${COMMON_FLAGS} diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index 25926edc40..de1b35120a 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -4,6 +4,7 @@ #include "displayapp/screens/Alarm.h" #include "displayapp/screens/Dice.h" +#include "displayapp/screens/Pawn.h" #include "displayapp/screens/Timer.h" #include "displayapp/screens/Twos.h" #include "displayapp/screens/Tile.h" diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index d440b598d1..93928c28eb 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -31,6 +31,7 @@ namespace Pinetime { Dice, Weather, PassKey, + Pawn, QuickSettings, Settings, SettingWatchFace, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 93196ed6a0..3dcfb7a5eb 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -2,6 +2,7 @@ if(DEFINED ENABLE_USERAPPS) set(USERAPP_TYPES ${ENABLE_USERAPPS} CACHE STRING "List of user apps to build into the firmware") else () set(DEFAULT_USER_APP_TYPES "Apps::StopWatch") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Pawn") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Alarm") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Timer") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Steps") diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp new file mode 100644 index 0000000000..4b615ee5f4 --- /dev/null +++ b/src/displayapp/screens/Pawn.cpp @@ -0,0 +1,119 @@ +#include "Pawn.h" +#include + +using namespace Pinetime::Applications::Screens; + +#include "program.h" + +static cell AMX_NATIVE_CALL F_lv_label_create(AMX*, const cell*) { + lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); + + return (cell) label; +} + +static cell AMX_NATIVE_CALL F_lv_obj_set_pos(AMX*, const cell* params) { + lv_obj_t* label = (lv_obj_t*) params[1]; + lv_obj_set_pos(label, params[2], params[3]); + + return 0; +} + +static cell AMX_NATIVE_CALL F_lv_label_set_text(AMX* amx, const cell* params) { + lv_obj_t* label = (lv_obj_t*) params[1]; + + char* text; + amx_StrParam_Type(amx, params[2], text, char*); + if (text != NULL) + lv_label_set_text(label, text); + else + lv_label_set_text(label, ""); + + return 0; +} + +static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { + // param[0] is the number of total parameter bytes, divide it by cell size and subtract 3 to account for the fixed parameters + int args_count = params[0] / sizeof(cell) - 3; + + cell *output = amx_Address(amx, params[1]); + cell output_size = params[2]; + + char buf[output_size]; + + char *fmt; + amx_StrParam_Type(amx, params[3], fmt, char*); + if (fmt == NULL) + return 0; + + cell ret = 0; + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + switch (args_count) + { + case 0: + strcpy(buf, fmt); + ret = strlen(fmt) + 1; + break; + case 1: + ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4])); + break; + case 2: + ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5])); + break; + case 3: + ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5]), *amx_Address(amx, params[6])); + break; + case 4: + ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5]), *amx_Address(amx, params[6]), *amx_Address(amx, params[7])); + break; + case 5: + ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5]), *amx_Address(amx, params[6]), *amx_Address(amx, params[7]), *amx_Address(amx, params[8])); + break; + default: + return 0; + } +#pragma GCC diagnostic warning "-Wformat-nonliteral" + + amx_SetString(output, buf, 1, 0, output_size); + + return ret; +} + +Pawn::Pawn() { + uint8_t* prog = new uint8_t[program_len]; + memcpy(prog, program, program_len); + + memset(&amx, 0, sizeof(amx)); + amx_Init(&amx, prog); + + amx.userdata[0] = this; + + static AMX_NATIVE_INFO natives[] = { + {"sprintf", F_sprintf}, + {"lv_label_create", F_lv_label_create}, + {"lv_obj_set_pos", F_lv_obj_set_pos}, + {"lv_label_set_text", F_lv_label_set_text}, + {0, 0} /* terminator */ + }; + amx_Register(&amx, natives, -1); + + amx_Exec(&amx, NULL, AMX_EXEC_MAIN); + + if (amx_FindPublic(&amx, "@refresh", &refresh_index) == AMX_ERR_NONE) + { + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); + } +} + +Pawn::~Pawn() { + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); + + amx_Cleanup(&amx); + delete amx.base; +} + +void Pawn::Refresh() { + amx_Exec(&amx, NULL, refresh_index); +} diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h new file mode 100644 index 0000000000..3e1410fdaf --- /dev/null +++ b/src/displayapp/screens/Pawn.h @@ -0,0 +1,42 @@ +#pragma once + +#include "displayapp/apps/Apps.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/Controllers.h" + +#include "pawn/amx.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + + class Pawn : public Screen { + public: + Pawn(); + ~Pawn() override; + + void Refresh() override; + + private: + AMX amx; + int refresh_index; + + lv_task_t* taskRefresh; + }; + } + + template <> + struct AppTraits { + static constexpr Apps app = Apps::Pawn; + static constexpr const char* icon = "P"; + + static Screens::Screen* Create(AppControllers& /*controllers*/) { + return new Screens::Pawn(); + }; + + static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { + return true; + }; + }; + } +} diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h new file mode 100644 index 0000000000..9ee24c7a06 --- /dev/null +++ b/src/displayapp/screens/program.h @@ -0,0 +1,57 @@ +unsigned char program[] = { + 0x84, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x08, 0x00, + 0xa8, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, + 0x84, 0x42, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x84, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x96, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, + 0x73, 0x68, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, + 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x00, 0x73, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x66, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, + 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x68, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x68, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x65, 0x6d, 0x69, 0x54, 0x61, 0x6c, 0x65, 0x20, 0x64, 0x65, 0x73, 0x70, + 0x6c, 0x25, 0x20, 0x3a, 0x00, 0x00, 0x00, 0x64 +}; +unsigned int program_len = 644; diff --git a/src/pawn/amx.c b/src/pawn/amx.c new file mode 100644 index 0000000000..635316da8d --- /dev/null +++ b/src/pawn/amx.c @@ -0,0 +1,3871 @@ +/* Pawn Abstract Machine (for the Pawn language) + * + * Copyright (c) CompuPhase, 1997-2023 + * + * 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 + * + * http://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. + * + * Version: $Id: amx.c 7487 2025-08-21 18:37:33Z thiadmer $ + */ + +#define WIN32_LEAN_AND_MEAN +#if defined _UNICODE || defined __UNICODE__ || defined UNICODE +# if !defined UNICODE /* for Windows API */ +# define UNICODE +# endif +# if !defined _UNICODE /* for C library */ +# define _UNICODE +# endif +#endif + +#include +#include +#include /* for wchar_t */ +#include /* for getenv() */ +#include +#include "osdefs.h" +#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + #include + #if !defined AMX_NODYNALOAD + #include + #endif + #if defined AMX_JIT + #include + #include + #endif + #if defined __APPLE__ + #include + #include + #include + #endif +#endif +#if !defined AMX_ANSIONLY && (defined __LCC__ || defined __LINUX__ || defined __APPLE__) + #include /* for wcslen() */ +#endif + +#if defined __ECOS__ + /* eCos puts include files in cyg/package_name */ + #include +#else + #include "amx.h" +#endif + +#if (defined _Windows && !defined AMX_NODYNALOAD) || (defined AMX_JIT && __WIN32__) + #include +#endif + + +/* When one or more of the AMX_funcname macros are defined, we want + * to compile only those functions. However, when none of these macros + * is present, we want to compile everything. + */ +#if defined AMX_ALIGN || defined AMX_ALLOT || defined AMX_CLEANUP + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_CLONE || defined AMX_DEFCALLBACK || defined AMX_EXEC + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_FLAGS || defined AMX_INIT || defined AMX_MEMINFO + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_NAMELENGTH || defined AMX_NATIVEINFO || defined AMX_PUSHXXX + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_RAISEERROR || defined AMX_REGISTER || defined AMX_SETCALLBACK + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_SETDEBUGHOOK || defined AMX_UTF8XXX || defined AMX_XXXNATIVES + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_XXXPUBLICS || defined AMX_XXXPUBVARS || defined AMX_XXXSTRING + #define AMX_EXPLIT_FUNCTIONS +#endif +#if defined AMX_XXXTAGS || defined AMX_XXXUSERDATA || defined AMX_VERIFYADDR + #define AMX_EXPLIT_FUNCTIONS +#endif +#if !defined AMX_EXPLIT_FUNCTIONS + /* no constant set, set them all (except amx_InitJIT() and other JIT support) */ + #define AMX_ALIGN /* amx_Align16(), amx_Align32() and amx_Align64() */ + #define AMX_ALLOT /* amx_Allot() and amx_Release() */ + #define AMX_DEFCALLBACK /* amx_Callback() */ + #define AMX_CLEANUP /* amx_Cleanup() */ + #define AMX_CLONE /* amx_Clone() */ + #define AMX_EXEC /* amx_Exec() */ + #define AMX_FLAGS /* amx_Flags() */ + #define AMX_INIT /* amx_Init() */ + #define AMX_MEMINFO /* amx_MemInfo() */ + #define AMX_NAMELENGTH /* amx_NameLength() */ + #define AMX_NATIVEINFO /* amx_NativeInfo() */ + #define AMX_PUSHXXX /* amx_Push(), amx_PushAddress(), amx_PushArray() and amx_PushString() */ + #define AMX_RAISEERROR /* amx_RaiseError() */ + #define AMX_REGISTER /* amx_Register() */ + #define AMX_SETCALLBACK /* amx_SetCallback() */ + #define AMX_SETDEBUGHOOK /* amx_SetDebugHook() */ + #define AMX_UTF8XXX /* amx_UTF8Check(), amx_UTF8Get(), amx_UTF8Len() and amx_UTF8Put() */ + #define AMX_XXXNATIVES /* amx_NumNatives(), amx_GetNative() and amx_FindNative() */ + #define AMX_XXXPUBLICS /* amx_NumPublics(), amx_GetPublic() and amx_FindPublic() */ + #define AMX_XXXPUBVARS /* amx_NumPubVars(), amx_GetPubVar() and amx_FindPubVar() */ + #define AMX_XXXSTRING /* amx_StrLen(), amx_GetString() and amx_SetString() */ + #define AMX_XXXTAGS /* amx_NumTags(), amx_GetTag() and amx_FindTagId() */ + #define AMX_XXXUSERDATA /* amx_GetUserData() and amx_SetUserData() */ + #define AMX_VERIFYADDR /* amx_VerifyAddress() */ +#endif +#undef AMX_EXPLIT_FUNCTIONS +#if defined AMX_ANSIONLY + #undef AMX_UTF8XXX /* no UTF-8 support in ANSI/ASCII-only version */ +#endif +#if defined AMX_NO_NATIVEINFO + #undef AMX_NATIVEINFO +#endif +#if AMX_USERNUM <= 0 + #undef AMX_XXXUSERDATA +#endif +#if defined AMX_JIT + /* JIT is incompatible with macro instructions, packed opcodes and overlays */ + #if !defined AMX_NO_MACRO_INSTR + #define AMX_NO_MACRO_INSTR + #endif + #if !defined AMX_NO_PACKED_OPC + #define AMX_NO_PACKED_OPC + #endif + #if !defined AMX_NO_OVERLAY + #define AMX_NO_OVERLAY + #endif +#endif +#if (defined AMX_ASM || defined AMX_JIT) && !defined AMX_ALTCORE + /* do not use the standard ANSI-C amx_Exec() function */ + #define AMX_ALTCORE +#endif +#if !defined AMX_NO_PACKED_OPC && !defined AMX_TOKENTHREADING + #define AMX_TOKENTHREADING /* packed opcodes require token threading (or switch threading) */ +#endif +#if defined AMX_DONT_RELOCATE + #define AMX_TOKENTHREADING /* direct threading cannot be used when opcodes cannot be relocated */ +#endif + +#if defined __64BIT__ + #define NATIVEADDR(addr,high) (AMX_NATIVE)((intptr_t)(addr) | ((intptr_t)((uint64_t)high<<32))) +#else + #define NATIVEADDR(addr,high) (AMX_NATIVE)(intptr_t)(addr) +#endif + +#if defined AMX_ALTCORE + #if defined __WIN32__ + /* For Watcom C/C++ use register calling convention (faster); for + * Microsoft C/C++ (and most other C compilers) use "cdecl". + * The important point is that you assemble AMXEXEC.ASM with the matching + * calling convention, or the right JIT, respectively. + * AMXJITR.ASM is for Watcom's register calling convention, AMXJITS.ASM and + * AMXJITSN.ASM are for "cdecl". + */ + #if defined __WATCOMC__ && !defined STACKARGS + /* register calling convention; the #pragma tells the compiler into which + * registers the parameters should go + */ + extern cell amx_exec_run(AMX *amx,cell *retval,unsigned char *data); + #pragma aux amx_exec_run parm [eax] [edx] [ebx]; + extern int amx_exec_list(const AMX *amx,const cell **opcodelist,int *numopcodes); + #pragma aux amx_exec_run parm [eax] [edx] [ebx]; + extern cell amx_jit_compile(void *pcode, void *jumparray, void *nativecode); + #pragma aux amx_exec_run parm [eax] [edx] [ebx]; + extern cell amx_jit_run(AMX *amx,cell *retval,unsigned char *data); + #pragma aux amx_jit_run parm [eax] [edx] [ebx]; + extern int amx_jit_list(const AMX *amx,const cell **opcodelist,int *numopcodes); + #pragma aux amx_exec_run parm [eax] [edx] [ebx]; + #elif defined __GNUC__ + /* force "cdecl" by adding an "attribute" to the declaration */ + extern cell amx_exec_run(AMX *amx,cell *retval,unsigned char *data) __attribute__((cdecl)); + extern int amx_exec_list(const AMX *amx,const cell **opcodelist,int *numopcodes) __attribute__((cdecl)); + extern cell amx_jit_compile(void *pcode, void *jumparray, void *nativecode) __attribute__((cdecl)); + extern cell amx_jit_run(AMX *amx,cell *retval,unsigned char *data) __attribute__((cdecl)); + extern int amx_jit_list(const AMX *amx,const cell **opcodelist,int *numopcodes) __attribute__((cdecl)); + #else + /* force "cdecl" by specifying it as a "function class" with the "__cdecl" keyword */ + extern cell __cdecl amx_exec_run(AMX *amx,cell *retval,unsigned char *data); + extern int __cdecl amx_exec_list(const AMX *amx,const cell **opcodelist,int *numopcodes); + extern cell __cdecl amx_jit_compile(void *pcode, void *jumparray, void *nativecode); + extern cell __cdecl amx_jit_run(AMX *amx,cell *retval,unsigned char *data); + extern int __cdecl amx_jit_list(const AMX *amx,const cell **opcodelist,int *numopcodes); + #endif + #else /* __WIN32__ */ + /* assume no specific calling conventions for other platforms than Windows */ + extern cell amx_exec_run(AMX *amx,cell *retval,unsigned char *data); + extern int amx_exec_list(const AMX *amx,const cell **opcodelist,int *numopcodes); + extern cell amx_jit_compile(void *pcode, void *jumparray, void *nativecode); + extern cell amx_jit_run(AMX *amx,cell *retval,unsigned char *data); + extern int amx_jit_list(const AMX *amx,const cell **opcodelist,int *numopcodes); + #endif /* __WIN32__ */ +#else + int amx_exec_list(AMX *amx,const cell **opcodelist,int *numopcodes); +#endif /* AMX_ALTCORE */ + +typedef enum { + OP_NOP, + OP_LOAD_PRI, + OP_LOAD_ALT, + OP_LOAD_S_PRI, + OP_LOAD_S_ALT, + OP_LREF_S_PRI, + OP_LREF_S_ALT, + OP_LOAD_I, + OP_LODB_I, + OP_CONST_PRI, + OP_CONST_ALT, + OP_ADDR_PRI, + OP_ADDR_ALT, + OP_STOR, + OP_STOR_S, + OP_SREF_S, + OP_STOR_I, + OP_STRB_I, + OP_ALIGN_PRI, + OP_LCTRL, + OP_SCTRL, + OP_XCHG, + OP_PUSH_PRI, + OP_PUSH_ALT, + OP_PUSHR_PRI, + OP_POP_PRI, + OP_POP_ALT, + OP_PICK, + OP_STACK, + OP_HEAP, + OP_PROC, + OP_RET, + OP_RETN, + OP_CALL, + OP_JUMP, + OP_JZER, + OP_JNZ, + OP_SHL, + OP_SHR, + OP_SSHR, + OP_SHL_C_PRI, + OP_SHL_C_ALT, + OP_SMUL, + OP_SDIV, + OP_ADD, + OP_SUB, + OP_AND, + OP_OR, + OP_XOR, + OP_NOT, + OP_NEG, + OP_INVERT, + OP_EQ, + OP_NEQ, + OP_SLESS, + OP_SLEQ, + OP_SGRTR, + OP_SGEQ, + OP_INC_PRI, + OP_INC_ALT, + OP_INC_I, + OP_DEC_PRI, + OP_DEC_ALT, + OP_DEC_I, + OP_MOVS, + OP_CMPS, + OP_FILL, + OP_HALT, + OP_BOUNDS, + OP_SYSREQ, + OP_SWITCH, + OP_SWAP_PRI, + OP_SWAP_ALT, + OP_BREAK, + OP_CASETBL, + /* patched instructions */ + OP_SYSREQ_D, + OP_SYSREQ_ND, + /* overlay instructions */ + OP_CALL_OVL, + OP_RETN_OVL, + OP_SWITCH_OVL, + OP_CASETBL_OVL, +#if !defined AMX_NO_MACRO_INSTR + /* supplemental & macro instructions */ + OP_LIDX, + OP_LIDX_B, + OP_IDXADDR, + OP_IDXADDR_B, + OP_PUSH_C, + OP_PUSH, + OP_PUSH_S, + OP_PUSH_ADR, + OP_PUSHR_C, + OP_PUSHR_S, + OP_PUSHR_ADR, + OP_JEQ, + OP_JNEQ, + OP_JSLESS, + OP_JSLEQ, + OP_JSGRTR, + OP_JSGEQ, + OP_SDIV_INV, + OP_SUB_INV, + OP_ADD_C, + OP_SMUL_C, + OP_ZERO_PRI, + OP_ZERO_ALT, + OP_ZERO, + OP_ZERO_S, + OP_EQ_C_PRI, + OP_EQ_C_ALT, + OP_INC, + OP_INC_S, + OP_DEC, + OP_DEC_S, + /* macro instructions */ + OP_SYSREQ_N, + OP_PUSHM_C, + OP_PUSHM, + OP_PUSHM_S, + OP_PUSHM_ADR, + OP_PUSHRM_C, + OP_PUSHRM_S, + OP_PUSHRM_ADR, + OP_LOAD2, + OP_LOAD2_S, + OP_CONST, + OP_CONST_S, +#endif +#if !defined AMX_NO_PACKED_OPC + /* packed instructions */ + OP_LOAD_P_PRI, + OP_LOAD_P_ALT, + OP_LOAD_P_S_PRI, + OP_LOAD_P_S_ALT, + OP_LREF_P_S_PRI, + OP_LREF_P_S_ALT, + OP_LODB_P_I, + OP_CONST_P_PRI, + OP_CONST_P_ALT, + OP_ADDR_P_PRI, + OP_ADDR_P_ALT, + OP_STOR_P, + OP_STOR_P_S, + OP_SREF_P_S, + OP_STRB_P_I, + OP_LIDX_P_B, + OP_IDXADDR_P_B, + OP_ALIGN_P_PRI, + OP_PUSH_P_C, + OP_PUSH_P, + OP_PUSH_P_S, + OP_PUSH_P_ADR, + OP_PUSHR_P_C, + OP_PUSHR_P_S, + OP_PUSHR_P_ADR, + OP_PUSHM_P_C, + OP_PUSHM_P, + OP_PUSHM_P_S, + OP_PUSHM_P_ADR, + OP_PUSHRM_P_C, + OP_PUSHRM_P_S, + OP_PUSHRM_P_ADR, + OP_STACK_P, + OP_HEAP_P, + OP_SHL_P_C_PRI, + OP_SHL_P_C_ALT, + OP_ADD_P_C, + OP_SMUL_P_C, + OP_ZERO_P, + OP_ZERO_P_S, + OP_EQ_P_C_PRI, + OP_EQ_P_C_ALT, + OP_INC_P, + OP_INC_P_S, + OP_DEC_P, + OP_DEC_P_S, + OP_MOVS_P, + OP_CMPS_P, + OP_FILL_P, + OP_HALT_P, + OP_BOUNDS_P, +#endif + /* ----- */ + OP_NUM_OPCODES +} OPCODE; + +#define NUMENTRIES(hdr,field,nextfield) \ + (unsigned)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize) +#define GETENTRY(hdr,table,index) \ + (AMX_FUNCSTUB *)((unsigned char*)(hdr) + (unsigned)(hdr)->table + (unsigned)index*(hdr)->defsize) +#define GETENTRYNAME(hdr,entry) \ + (char *)((unsigned char*)(hdr) + (unsigned)((AMX_FUNCSTUB*)(entry))->nameofs) + +#if !defined NDEBUG + static int check_endian(void) + { + uint16_t val=0x00ff; + unsigned char *ptr=(unsigned char *)&val; + /* "ptr" points to the starting address of "val". If that address + * holds the byte "0xff", the computer stored the low byte of "val" + * at the lower address, and so the memory lay out is Little Endian. + */ + assert(*ptr==0xff || *ptr==0x00); + #if BYTE_ORDER==BIG_ENDIAN + return *ptr==0x00; /* return "true" if big endian */ + #else + return *ptr==0xff; /* return "true" if little endian */ + #endif + } +#endif + +#if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==16 + void amx_Swap16(uint16_t *v) + { + unsigned char *s = (unsigned char *)v; + unsigned char t; + + assert_static(sizeof(*v)==2); + /* swap two bytes */ + t=s[0]; + s[0]=s[1]; + s[1]=t; + } +#endif + +#if BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==32 + void amx_Swap32(uint32_t *v) + { + unsigned char *s = (unsigned char *)v; + unsigned char t; + + assert_static(sizeof(*v)==4); + /* swap outer two bytes */ + t=s[0]; + s[0]=s[3]; + s[3]=t; + /* swap inner two bytes */ + t=s[1]; + s[1]=s[2]; + s[2]=t; + } +#endif + +#if (BYTE_ORDER==BIG_ENDIAN || PAWN_CELL_SIZE==64) && (defined _I64_MAX || defined __x86_64__ || defined HAVE_I64) + void amx_Swap64(uint64_t *v) + { + unsigned char *s = (unsigned char *)v; + unsigned char t; + + assert(sizeof(*v)==8); + + t=s[0]; + s[0]=s[7]; + s[7]=t; + + t=s[1]; + s[1]=s[6]; + s[6]=t; + + t=s[2]; + s[2]=s[5]; + s[5]=t; + + t=s[3]; + s[3]=s[4]; + s[4]=t; + } +#endif + +#if defined AMX_ALIGN || defined AMX_INIT +uint16_t * AMXAPI amx_Align16(uint16_t *v) +{ + assert_static(sizeof(*v)==2); + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN + amx_Swap16(v); + #endif + return v; +} + +uint32_t * AMXAPI amx_Align32(uint32_t *v) +{ + assert_static(sizeof(*v)==4); + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN + amx_Swap32(v); + #endif + return v; +} + +#if defined _I64_MAX || defined __x86_64__ || defined HAVE_I64 +uint64_t * AMXAPI amx_Align64(uint64_t *v) +{ + assert(sizeof(*v)==8); + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN + amx_Swap64(v); + #endif + return v; +} +#endif /* _I64_MAX || __x86_64__ || HAVE_I64 */ +#endif /* AMX_ALIGN || AMX_INIT */ + +#if defined AMX_FLAGS +int AMXAPI amx_Flags(AMX *amx,uint16_t *flags) +{ + AMX_HEADER *hdr; + + *flags=0; + if (amx==NULL) + return AMX_ERR_FORMAT; + hdr=(AMX_HEADER *)amx->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionflags; + return AMX_ERR_NONE; +} +#endif /* AMX_FLAGS */ + +#if defined AMX_DEFCALLBACK +int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, const cell *params) +{ +#if defined AMX_NATIVETABLE + extern AMX_NATIVE const AMX_NATIVETABLE[]; +#endif + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + AMX_NATIVE f; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->natives<=hdr->libraries); +#if defined AMX_NATIVETABLE + if (index<0) { + /* size of AMX_NATIVETABLE is unknown here, so we cannot verify index */ + f=(AMX_NATIVETABLE)[-(index+1)]; + } else { +#endif + assert(index>=0 && index<(cell)NUMENTRIES(hdr,natives,libraries)); + func=GETENTRY(hdr,natives,index); + f=NATIVEADDR(func->address,func->nameofs); +#if defined AMX_NATIVETABLE + } /* if */ +#endif + assert(f!=NULL); + + /* Now that we have found the function, patch the program so that any + * subsequent call will call the function directly (bypassing this + * callback). + * This trick cannot work in the JIT, because the program would need to + * be re-JIT-compiled after patching a P-code instruction. + */ + #if !defined AMX_DONT_RELOCATE + assert((amx->flags & AMX_FLAG_JITC)==0 || amx->sysreq_d==0); + if (amx->sysreq_d!=0) { + /* at the point of the call, the CIP pseudo-register points directly + * behind the SYSREQ(.N) instruction and its parameter(s) + */ + unsigned char *code=amx->code+(int)amx->cip-sizeof(cell); + if (amx->flags & AMX_FLAG_SYSREQN) /* SYSREQ.N has 2 parameters */ + code-=sizeof(cell); + assert(amx->code!=NULL); + assert(amx->cip>=4 && amx->cip<(hdr->dat - hdr->cod)); + assert(sizeof(f)<=sizeof(cell)); /* function pointer must fit in a cell */ + assert(*(cell*)code==index); + #if defined AMX_TOKENTHREADING || !(defined __GNUC__ || defined __ICC || defined AMX_ASM || defined AMX_JIT) + assert(!(amx->flags & AMX_FLAG_SYSREQN) && *(cell*)(code-sizeof(cell))==OP_SYSREQ + || (amx->flags & AMX_FLAG_SYSREQN) && *(cell*)(code-sizeof(cell))==OP_SYSREQ_N); + #endif + *(cell*)(code-sizeof(cell))=amx->sysreq_d; + *(cell*)code=(cell)(intptr_t)f; + } /* if */ + #endif + + /* Note: + * params[0] == number of bytes for the additional parameters passed to the native function + * params[1] == first argument + * etc. + */ + + amx->error=AMX_ERR_NONE; + *result = f(amx,params); + return amx->error; +} +#endif /* defined AMX_DEFCALLBACK */ + + +#if defined AMX_JIT + /* convert from relative addresses to absolute physical addresses */ + #define RELOC_ABS(base,off) (*(ucell *)((base)+(int)(off)) += (ucell)(base)+(int)(off)-sizeof(cell)) +#else + #define JUMPREL(ip) ((cell*)((intptr_t)(ip)+*(cell*)(ip)-sizeof(cell))) +#endif +#if defined AMX_ASM || defined AMX_JIT + #define RELOCATE_ADDR(base,v) ((v)+((ucell)(base))) +#else + #define RELOCATE_ADDR(base,v) (v) +#endif + +#define DBGPARAM(v) ( (v)=*(cell *)(amx->code+(int)cip), cip+=sizeof(cell) ) + +#if !defined GETOPCODE + #if defined AMX_NO_PACKED_OPC + #define GETOPCODE(c) (OPCODE)(c) + #else + #define GETOPCODE(c) (OPCODE)((c) & ((1UL << sizeof(cell)*4)-1)) + #endif +#endif +#if !defined GETPARAM_P + #define GETPARAM_P(v,o) ( v=((cell)(o) >> (int)(sizeof(cell)*4)) ) +#endif + +#if defined AMX_INIT + +static int VerifyPcode(AMX *amx) +{ + AMX_HEADER *hdr; + cell cip,tgt,opmask; + int sysreq_flg,max_opcode; + int datasize,stacksize; + const cell *opcode_list; + #if defined AMX_JIT + int opcode_count=0; + int reloc_count=0; + int jit_codesize=0; + #endif + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + amx->flags|=AMX_FLAG_VERIFY; + datasize=hdr->hea-hdr->dat; + stacksize=hdr->stp-hdr->hea; + + #if defined AMX_ASM && defined AMX_JIT + if ((amx->flags & AMX_FLAG_JITC)!=0) + jit_codesize=amx_jit_list(amx,&opcode_list,&max_opcode); + else + amx_exec_list(amx,&opcode_list,&max_opcode); + #elif defined AMX_JIT + jit_codesize=amx_jit_list(amx,&opcode_list,&max_opcode); + #else + amx_exec_list(amx,&opcode_list,&max_opcode); + #endif + #if defined AMX_TOKENTHREADING + opcode_list=NULL; /* avoid token translation if token threading is in effect */ + #endif + #if defined AMX_NO_PACKED_OPC + opmask= ~0; + #else + opmask=(1UL << sizeof(cell)*4)-1; + #endif + + /* sanity checks */ + assert_static(OP_XCHG==21); + assert_static(OP_SMUL==42); + assert_static(OP_MOVS==64); + #if !defined AMX_NO_MACRO_INSTR + assert_static(OP_LIDX==81); + assert_static(OP_ZERO_PRI==102); + assert_static(OP_LOAD2==120); + #endif + #if !defined AMX_NO_PACKED_OPC + assert_static(OP_LOAD_P_PRI==124); + assert_static(OP_ALIGN_P_PRI==141); + assert_static(OP_BOUNDS_P==174); + #endif + + sysreq_flg=0; + if (opcode_list!=NULL) { + if (amx->sysreq_d==opcode_list[OP_SYSREQ_D]) + sysreq_flg=0x01; + else if (amx->sysreq_d==opcode_list[OP_SYSREQ_ND]) + sysreq_flg=0x02; + } else { + if (amx->sysreq_d==OP_SYSREQ_D) + sysreq_flg=0x01; + else if (amx->sysreq_d==OP_SYSREQ_ND) + sysreq_flg=0x02; + } /* if */ + amx->sysreq_d=0; /* preset */ + + /* start browsing code */ + assert(amx->code!=NULL); /* should already have been set in amx_Init() */ + for (cip=0; cipcodesize; ) { + cell op=*(cell *)(amx->code+(int)cip); + if ((op & opmask)>=max_opcode) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_INVINSTR; + } /* if */ + /* relocate opcode (only works if the size of an opcode is at least + * as big as the size of a pointer (jump address); so basically we + * rely on the opcode and a pointer being 32-bit + */ + if (opcode_list!=NULL) { + /* verify that opcode_list[op]!=NULL, if it is, this instruction + * is unsupported + */ + if (opcode_list[op & opmask]==0) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_INVINSTR; + } /* if */ + *(cell *)(amx->code+(int)cip)=opcode_list[op & opmask]; + } /* if */ + #if defined AMX_JIT + opcode_count++; + #endif + cip+=sizeof(cell); + switch (op & opmask) { +#if !defined AMX_NO_MACRO_INSTR + case OP_PUSHM_C: /* instructions with variable number of parameters */ + case OP_PUSHM: + case OP_PUSHM_S: + case OP_PUSHM_ADR: + case OP_PUSHRM_C: + case OP_PUSHRM_S: + case OP_PUSHRM_ADR: + tgt=*(cell*)(amx->code+(int)cip); /* get count */ + cip+=sizeof(cell)*(tgt+1); + break; + + case OP_LOAD2: + tgt=*(cell*)(amx->code+(int)cip); /* verify both addresses */ + if (tgt<0 || tgt>=datasize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + tgt=*(cell*)(amx->code+(int)cip+(int)sizeof(cell)); + if (tgt<0 || tgt>=datasize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + cip+=sizeof(cell)*2; + break; + + case OP_LOAD2_S: + tgt=*(cell*)(amx->code+(int)cip); /* verify both addresses */ + if (tgt<-stacksize || tgt>stacksize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + tgt=*(cell*)(amx->code+(int)cip+(int)sizeof(cell)); + if (tgt<-stacksize || tgt>stacksize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + cip+=sizeof(cell)*2; + break; + + case OP_CONST: + tgt=*(cell*)(amx->code+(int)cip); /* verify address */ + if (tgt<0 || tgt>=datasize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + cip+=sizeof(cell)*2; + break; + + case OP_CONST_S: + tgt=*(cell*)(amx->code+(int)cip); /* verify both addresses */ + if (tgt<-stacksize || tgt>stacksize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + cip+=sizeof(cell)*2; + break; +#endif /* !defined AMX_NO_MACRO_INSTR */ + +#if !defined AMX_NO_PACKED_OPC + case OP_LODB_P_I: /* instructions with 1 parameter packed inside the same cell */ + case OP_CONST_P_PRI: + case OP_CONST_P_ALT: + case OP_ADDR_P_PRI: + case OP_ADDR_P_ALT: + case OP_STRB_P_I: + case OP_LIDX_P_B: + case OP_IDXADDR_P_B: + case OP_ALIGN_P_PRI: + case OP_PUSH_P_C: + case OP_PUSH_P: + case OP_PUSH_P_S: + case OP_PUSH_P_ADR: + case OP_PUSHR_P_C: + case OP_PUSHR_P_S: + case OP_PUSHR_P_ADR: + case OP_STACK_P: + case OP_HEAP_P: + case OP_SHL_P_C_PRI: + case OP_SHL_P_C_ALT: + case OP_ADD_P_C: + case OP_SMUL_P_C: + case OP_ZERO_P: + case OP_ZERO_P_S: + case OP_EQ_P_C_PRI: + case OP_EQ_P_C_ALT: + case OP_MOVS_P: + case OP_CMPS_P: + case OP_FILL_P: + case OP_HALT_P: + case OP_BOUNDS_P: + break; + + case OP_LOAD_P_PRI: /* data instructions with 1 parameter packed inside the same cell */ + case OP_LOAD_P_ALT: + case OP_STOR_P: + case OP_INC_P: + case OP_DEC_P: + GETPARAM_P(tgt,op); /* verify address */ + if (tgt<0 || tgt>=datasize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + break; + + case OP_LOAD_P_S_PRI: /* stack instructions with 1 parameter packed inside the same cell */ + case OP_LOAD_P_S_ALT: + case OP_LREF_P_S_PRI: + case OP_LREF_P_S_ALT: + case OP_STOR_P_S: + case OP_SREF_P_S: + case OP_INC_P_S: + case OP_DEC_P_S: + GETPARAM_P(tgt,op); /* verify address */ + if (tgt<-stacksize || tgt>stacksize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + break; + + case OP_PUSHM_P_C: /* instructions with variable number of parameters */ + case OP_PUSHM_P: + case OP_PUSHM_P_S: + case OP_PUSHM_P_ADR: + case OP_PUSHRM_P_C: + case OP_PUSHRM_P_S: + case OP_PUSHRM_P_ADR: + GETPARAM_P(tgt,op); /* verify address */ + cip+=sizeof(cell)*tgt; + break; +#endif /* !defined AMX_NO_PACKED_OPC */ + + case OP_LODB_I: /* instructions with 1 parameter (not packed) */ + case OP_CONST_PRI: + case OP_CONST_ALT: + case OP_ADDR_PRI: + case OP_ADDR_ALT: + case OP_STRB_I: + case OP_ALIGN_PRI: + case OP_LCTRL: + case OP_SCTRL: + case OP_PICK: + case OP_STACK: + case OP_HEAP: + case OP_SHL_C_PRI: + case OP_SHL_C_ALT: + case OP_MOVS: + case OP_CMPS: + case OP_FILL: + case OP_HALT: + case OP_BOUNDS: +#if !defined AMX_NO_MACRO_INSTR + case OP_LIDX_B: + case OP_IDXADDR_B: + case OP_PUSH_C: + case OP_PUSH_ADR: + case OP_PUSHR_C: + case OP_PUSHR_ADR: + case OP_ADD_C: + case OP_SMUL_C: + case OP_ZERO: + case OP_ZERO_S: + case OP_EQ_C_PRI: + case OP_EQ_C_ALT: +#endif + cip+=sizeof(cell); + break; + + case OP_LOAD_PRI: + case OP_LOAD_ALT: + case OP_STOR: +#if !defined AMX_NO_MACRO_INSTR + case OP_PUSH: + case OP_INC: + case OP_DEC: +#endif + tgt=*(cell*)(amx->code+(int)cip); /* verify address */ + if (tgt<0 || tgt>=datasize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + cip+=sizeof(cell); + break; + + case OP_LOAD_S_PRI: + case OP_LOAD_S_ALT: + case OP_LREF_S_PRI: + case OP_LREF_S_ALT: + case OP_STOR_S: + case OP_SREF_S: +#if !defined AMX_NO_MACRO_INSTR + case OP_PUSH_S: + case OP_PUSHR_S: + case OP_INC_S: + case OP_DEC_S: +#endif + tgt=*(cell*)(amx->code+(int)cip); /* verify address */ + if (tgt<-stacksize || tgt>stacksize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + cip+=sizeof(cell); + break; + + case OP_NOP: /* instructions without parameters */ + case OP_LOAD_I: + case OP_STOR_I: + case OP_XCHG: + case OP_PUSH_PRI: + case OP_PUSH_ALT: + case OP_PUSHR_PRI: + case OP_POP_PRI: + case OP_POP_ALT: + case OP_PROC: + case OP_RET: + case OP_RETN: + case OP_SHL: + case OP_SHR: + case OP_SSHR: + case OP_SMUL: + case OP_SDIV: + case OP_ADD: + case OP_SUB: + case OP_AND: + case OP_OR: + case OP_XOR: + case OP_NOT: + case OP_NEG: + case OP_INVERT: + case OP_EQ: + case OP_NEQ: + case OP_SLESS: + case OP_SLEQ: + case OP_SGRTR: + case OP_SGEQ: + case OP_INC_PRI: + case OP_INC_ALT: + case OP_INC_I: + case OP_DEC_PRI: + case OP_DEC_ALT: + case OP_DEC_I: + case OP_SWAP_PRI: + case OP_SWAP_ALT: + case OP_BREAK: +#if !defined AMX_NO_MACRO_INSTR + case OP_LIDX: + case OP_IDXADDR: + case OP_SDIV_INV: + case OP_SUB_INV: + case OP_ZERO_PRI: + case OP_ZERO_ALT: +#endif + break; + + case OP_CALL: /* opcodes that need relocation (JIT only), or conversion to position-independent code */ + case OP_JUMP: + case OP_JZER: + case OP_JNZ: + case OP_SWITCH: +#if !defined AMX_NO_MACRO_INSTR + case OP_JEQ: + case OP_JNEQ: + case OP_JSLESS: + case OP_JSLEQ: + case OP_JSGRTR: + case OP_JSGEQ: +#endif + tgt=*(cell*)(amx->code+(int)cip)+cip-sizeof(cell); + if (tgt<0 || tgt>amx->codesize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + #if defined AMX_JIT + reloc_count++; + RELOC_ABS(amx->code, cip); /* change to absolute physical address */ + #endif + cip+=sizeof(cell); + break; + +#if !defined AMX_NO_OVERLAY + /* overlay opcodes (overlays must be enabled) */ + case OP_SWITCH_OVL: + assert(hdr->file_version>=10); + tgt=*(cell*)(amx->code+(int)cip)+cip-sizeof(cell); + if (tgt<0 || tgt>amx->codesize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + /* fall through */ + case OP_CALL_OVL: + cip+=sizeof(cell); + /* fall through */ + case OP_RETN_OVL: + assert(hdr->overlays!=0 && hdr->overlays!=hdr->nametable); + #if defined AMX_JIT + if ((amx->flags & AMX_FLAG_JITC)!=0) + return AMX_ERR_OVERLAY; /* JIT does not support overlays */ + #endif + if (amx->overlay==NULL) + return AMX_ERR_OVERLAY; /* no overlay callback */ + break; + case OP_CASETBL_OVL: { + cell num; + DBGPARAM(num); /* number of records follows the opcode */ + cip+=(2*num + 1)*sizeof(cell); + if (amx->overlay==NULL) + return AMX_ERR_OVERLAY; /* no overlay callback */ + break; + } /* case */ +#endif + + case OP_SYSREQ: + cip+=sizeof(cell); + sysreq_flg|=0x01; /* mark SYSREQ found */ + break; +#if !defined AMX_NO_MACRO_INSTR + case OP_SYSREQ_N: + cip+=sizeof(cell)*2; + sysreq_flg|=0x02; /* mark SYSREQ.N found */ + break; +#endif + + case OP_CASETBL: { + cell num,offs; + int i; + DBGPARAM(num); /* number of records follows the opcode */ + for (i=0; i<=num; i++) { + offs=cip+2*i*sizeof(cell); + tgt=*(cell*)(amx->code+(int)offs)+offs-sizeof(cell); + if (tgt<0 || tgt>amx->codesize) { + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_BOUNDS; + } /* if */ + #if defined AMX_JIT + RELOC_ABS(amx->code, cip+2*i*sizeof(cell)); + reloc_count++; + #endif + } /* for */ + cip+=(2*num + 1)*sizeof(cell); + break; + } /* case */ + + default: + amx->flags &= ~AMX_FLAG_VERIFY; + return AMX_ERR_INVINSTR; + } /* switch */ + } /* for */ + + #if !defined AMX_DONT_RELOCATE + /* only either type of system request opcode should be found (otherwise, + * we probably have a non-conforming compiler + */ + if ((sysreq_flg==0x01 || sysreq_flg==0x02) && (amx->flags & AMX_FLAG_JITC)==0) { + /* to use direct system requests, a function pointer must fit in a cell; + * because the native function's address will be stored as the parameter + * of SYSREQ.(N)D + */ + if (sizeof(AMX_NATIVE)<=sizeof(cell)) { + if (opcode_list!=NULL) + amx->sysreq_d=(sysreq_flg==0x01) ? opcode_list[OP_SYSREQ_D] : opcode_list[OP_SYSREQ_ND]; + else + amx->sysreq_d=(sysreq_flg==0x01) ? OP_SYSREQ_D : OP_SYSREQ_ND; + } /* if */ + } /* if */ + #endif + + #if defined AMX_JIT + /* adjust the code size to mean: estimated code size of the native code + * (instead of the size of the P-code) + */ + amx->codesize=jit_codesize*opcode_count + hdr->cod + (hdr->stp - hdr->dat); + amx->reloc_size=2*sizeof(cell)*reloc_count; + #endif + + amx->flags &= ~AMX_FLAG_VERIFY; + amx->flags |= AMX_FLAG_INIT; + if (sysreq_flg & 0x02) + amx->flags |= AMX_FLAG_SYSREQN; + + return AMX_ERR_NONE; +} + +/* definitions used for amx_Init() and amx_Cleanup() */ +#if (defined _Windows || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__) && !defined AMX_NODYNALOAD + typedef int AMXEXPORT (AMXAPI _FAR *AMX_ENTRY)(AMX _FAR *amx); + + static void getlibname(char *libname,const char *source) + { + #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + char *root=getenv("AMXLIB"); + #endif + + assert(libname!=NULL && source!=NULL); + libname[0]='\0'; + #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + if (root!=NULL && *root!='\0') { + strcpy(libname,root); + if (libname[strlen(libname)-1]!='/') + strcat(libname,"/"); + } /* if */ + #endif + strcat(libname,"amx"); + strcat(libname,source); + #if defined _Windows + strcat(libname,".dll"); + #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ + strcat(libname,".so"); + #elif defined __APPLE__ + strcat(libname,".dylib"); + #endif + } +#endif + +int AMXAPI amx_Init(AMX *amx,void *program) +{ + AMX_HEADER *hdr; + int err; + uint16_t *namelength; + unsigned char *data; + + if ((amx->flags & AMX_FLAG_INIT)!=0) + return AMX_ERR_INIT; /* already initialized (may not do so twice) */ + + hdr=(AMX_HEADER *)program; + /* the header is in Little Endian, on a Big Endian machine, swap all + * multi-byte words + */ + assert(check_endian()); + #if BYTE_ORDER==BIG_ENDIAN + amx_Align32((uint32_t*)&hdr->size); + amx_Align16(&hdr->magic); + amx_Align16((uint16_t*)&hdr->flags); + amx_Align16((uint16_t*)&hdr->defsize); + amx_Align32((uint32_t*)&hdr->cod); + amx_Align32((uint32_t*)&hdr->dat); + amx_Align32((uint32_t*)&hdr->hea); + amx_Align32((uint32_t*)&hdr->stp); + amx_Align32((uint32_t*)&hdr->cip); + amx_Align32((uint32_t*)&hdr->publics); + amx_Align32((uint32_t*)&hdr->natives); + amx_Align32((uint32_t*)&hdr->libraries); + amx_Align32((uint32_t*)&hdr->pubvars); + amx_Align32((uint32_t*)&hdr->tags); + if (hdr->file_version>=10) + amx_Align32((uint32_t*)&hdr->overlays); + #endif + + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versiondefsize!=sizeof(AMX_FUNCSTUB)) + return AMX_ERR_FORMAT; + /* check the maximum name length in the separate name table */ + #if BYTE_ORDER==BIG_ENDIAN + amx_Align32((uint32_t*)&hdr->nametable); + #endif + namelength=(uint16_t*)((unsigned char*)program + (unsigned)hdr->nametable); + amx_Align16(namelength); + if (*namelength>sNAMEMAX) + return AMX_ERR_FORMAT; + if (hdr->stp<=0) + return AMX_ERR_FORMAT; + assert(hdr->hea == hdr->size); + #if BYTE_ORDER==BIG_ENDIAN + { + ucell *code=(ucell *)((unsigned char *)program+(int)hdr->cod); + while (code<(ucell *)((unsigned char *)program+(int)hdr->hea)) + amx_SwapCell(code++); + } + #endif + + amx->base=(unsigned char *)program; + + /* set initial values */ + amx->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ + amx->stp=hdr->stp - hdr->dat - sizeof(cell); + amx->hea=amx->hlw; + amx->stk=amx->stp; + #if defined AMX_DEFCALLBACK + if (amx->callback==NULL) + amx->callback=amx_Callback; + #endif + + /* when running P-code from ROM (with the header with the native function + * table in RAM), the "code" field must be set to a non-NULL value on + * initialization, before calling amx_Init(); in an overlay scheme, the + * code field is modified dynamically by the overlay callback + */ + if (amx->code==NULL) + amx->code=amx->base+(int)hdr->cod; + if (amx->codesize==0) + amx->codesize=hdr->dat-hdr->cod; + + /* to split the data segment off the code segment, the "data" field must + * be set to a non-NULL value on initialization, before calling amx_Init(); + * you may also need to explicitly initialize the data section with the + * contents read from the AMX file + */ + if (amx->data!=NULL) { + data=amx->data; + if ((amx->flags & AMX_FLAG_DSEG_INIT)==0 && amx->overlay==NULL) + memcpy(data,amx->base+(int)hdr->dat,(size_t)(hdr->hea-hdr->dat)); + } else { + data=amx->base+(int)hdr->dat; + } /* if */ + + /* Set a zero cell at the top of the stack, which functions + * as a sentinel for strings. + */ + * (cell *)(data+(int)(hdr->stp-hdr->dat-sizeof(cell)))=0; + + /* also align all addresses in the public function, public variable, + * public tag and native function tables --offsets into the name table + * (if present) must also be swapped. + */ + #if BYTE_ORDER==BIG_ENDIAN + { /* local */ + AMX_FUNCSTUB *fs; + int i,num; + + fs=GETENTRY(hdr,natives,0); + num=NUMENTRIES(hdr,natives,libraries); + for (i=0; iaddress); /* redundant, because it should be zero */ + amx_Align32(&fs->nameofs); + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); + } /* for */ + + fs=GETENTRY(hdr,publics,0); + assert(hdr->publics<=hdr->natives); + num=NUMENTRIES(hdr,publics,natives); + for (i=0; iaddress); + amx_Align32(&fs->nameofs); + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); + } /* for */ + + fs=GETENTRY(hdr,pubvars,0); + assert(hdr->pubvars<=hdr->tags); + num=NUMENTRIES(hdr,pubvars,tags); + for (i=0; iaddress); + amx_Align32(&fs->nameofs); + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); + } /* for */ + + fs=GETENTRY(hdr,tags,0); + if (hdr->file_version<7) { /* file version 7 introduced the name table */ + assert(hdr->tags<=hdr->cod); + num=NUMENTRIES(hdr,tags,cod); + } else { + assert(hdr->tags<=hdr->nametable); + num=NUMENTRIES(hdr,tags,nametable); + } /* if */ + for (i=0; iaddress); + amx_Align32(&fs->nameofs); + fs=(AMX_FUNCSTUB*)((unsigned char *)fs+hdr->defsize); + } /* for */ + } /* local */ + #endif + + /* verify P-code and relocate address in the case of the JIT */ + if ((hdr->flags & AMX_FLAG_OVERLAY)==0) { + err=VerifyPcode(amx); + } else { + int i; + err=(amx->overlay==NULL) ? AMX_ERR_OVERLAY : AMX_ERR_NONE; + /* load every overlay on initialization and verify explicitly; we must + * do this to know whether to use new or old system requests + */ + for (i=0; err==AMX_ERR_NONE && i<(int)((hdr->nametable - hdr->overlays)/sizeof(AMX_OVERLAYINFO)); i++) { + err=amx->overlay(amx, i); + if (err==AMX_ERR_NONE) + err=VerifyPcode(amx); + } /* for */ + } /* if */ + if (err!=AMX_ERR_NONE) + return err; + + /* load any extension modules that the AMX refers to */ + #if (defined _Windows || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__) && !defined AMX_NODYNALOAD + { /* local */ + #if defined _Windows + char libname[sNAMEMAX+8]; /* +1 for '\0', +3 for 'amx' prefix, +4 for extension */ + HINSTANCE hlib; + #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + char libname[_MAX_PATH]; + void *hlib; + #endif + int numlibraries,i; + AMX_FUNCSTUB *lib; + AMX_ENTRY libinit; + hdr=(AMX_HEADER *)amx->base; + numlibraries=NUMENTRIES(hdr,libraries,pubvars); + for (i=0; i0) { + char ptr=strrchr(pathbuf,'/'); + assert(ptr!=NULL); + *ptr='\0'; + asprintf(&ptr,"%s/%s",pathbuf,libname); + assert(ptr!=NULL); + hlib=dlopen(ptr,RTLD_NOW); + free(ptr); + } + if (hlib==NULL) { + /* if failed, try to search elsewhere */ + hlib=dlopen(libname,RTLD_NOW); + } + #endif + if (hlib!=NULL) { + /* a library that cannot be loaded or that does not have the required + * initialization function is simply ignored + */ + char funcname[sNAMEMAX+9]; /* +1 for '\0', +4 for 'amx_', +4 for 'Init' */ + strcpy(funcname,"amx_"); + strcat(funcname,GETENTRYNAME(hdr,lib)); + strcat(funcname,"Init"); + #if defined _Windows + libinit=(AMX_ENTRY)GetProcAddress(hlib,funcname); + #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + libinit=(AMX_ENTRY)dlsym(hlib,funcname); + #endif + if (libinit!=NULL) + libinit(amx); + } /* if */ + lib->address=(ucell)(intptr_t)hlib; + } /* for */ + } /* local */ + #endif + + return AMX_ERR_NONE; +} + +#if defined AMX_JIT + + #define CODESIZE_JIT 8192 /* approximate size of the code for the JIT */ + + #if defined __WIN32__ /* this also applies to Win32 "console" applications */ + + #define ALIGN(addr) (addr) + + #define PROT_READ 0x1 /* page can be read */ + #define PROT_WRITE 0x2 /* page can be written */ + #define PROT_EXEC 0x4 /* page can be executed */ + #define PROT_NONE 0x0 /* page can not be accessed */ + + static int mprotect(void *addr, size_t len, int prot) + { + DWORD prev, p = 0; + if ((prot & PROT_WRITE)!=0) + p = PAGE_EXECUTE_READWRITE; + else + p |= PAGE_EXECUTE_READ; + return !VirtualProtect(addr, len, p, &prev); + } + + #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + + /* Linux, BSD and OSX already have mprotect() */ + #define ALIGN(addr) (char *)(((long)addr + sysconf(_SC_PAGESIZE)-1) & ~(sysconf(_SC_PAGESIZE)-1)) + + #else + + // TODO: Add cases for Mac OS/X and other operating systems + + /* DOS32 has no imposed limits on its segments */ + #define ALIGN(addr) (addr) + #define mprotect(addr, len, prot) (0) + + #endif /* #if defined __WIN32 __ */ + +int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code) +{ + int res; + AMX_HEADER *hdr; + + if ((amx->flags & AMX_FLAG_JITC)==0) + return AMX_ERR_INIT_JIT; /* flag not set, this AMX is not prepared for JIT */ + + /* copy the prefix */ + memcpy(native_code, amx->base, ((AMX_HEADER *)(amx->base))->cod); + hdr = native_code; + if (hdr->file_version>MAX_FILE_VER_JIT) + return AMX_ERR_VERSION; /* JIT may not support the newest file version(s) */ + /* the JIT does not support overlays, but this is already checked in VerifyPcode() + * the same goes for macro instructions: not supported in the JIT, but already + * checked in VerifyPcode() + */ + + /* Patching SYSREQ(.N) opcodes to SYSREQ.(N)D cannot work in the JIT, because + * the program would need to be re-JIT-compiled after patching a P-code + * instruction. If this field is not zero, something went wrong in + * VerifyPcode(). + */ + assert(amx->sysreq_d==0); + + if (mprotect(ALIGN(amx_jit_compile), CODESIZE_JIT, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + return AMX_ERR_INIT_JIT; + + /* MP: added check for correct compilation */ + if ((res = amx_jit_compile(amx->base, reloc_table, native_code)) == 0) { + /* update the required memory size (the previous value was a + * conservative estimate, now we know the exact size) + */ + amx->codesize = (hdr->dat + hdr->stp + sizeof(cell)) & ~(sizeof(cell)-1); + /* The compiled code is relocatable, since only relative jumps are + * used for destinations within the generated code, and absolute + * addresses are only for jumps into the runtime, which is fixed + * in memory. + */ + /* set the new pointers */ + amx->base = (unsigned char*)native_code; + amx->code = amx->base + (int)hdr->cod; + amx->cip = hdr->cip; + } /* if */ + + return (res == 0) ? AMX_ERR_NONE : AMX_ERR_INIT_JIT; +} + +#endif /* #if defined AMX_JIT */ + +#endif /* AMX_INIT */ + +#if defined AMX_CLEANUP +int AMXAPI amx_Cleanup(AMX *amx) +{ + #if (defined _Windows || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__) && !defined AMX_NODYNALOAD + #if defined _Windows + char libname[sNAMEMAX+8]; /* +1 for '\0', +3 for 'amx' prefix, +4 for extension */ + HINSTANCE hlib; + #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + char libname[_MAX_PATH]; + void *hlib; + #endif + AMX_HEADER *hdr; + AMX_FUNCSTUB *lib; + AMX_ENTRY libcleanup; + int numlibraries,i; + #endif + + /* unload all extension modules */ + #if (defined _Windows || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__) && !defined AMX_NODYNALOAD + hdr=(AMX_HEADER *)amx->base; + assert(hdr->magic==AMX_MAGIC); + numlibraries=NUMENTRIES(hdr,libraries,pubvars); + for (i=0; iaddress!=0) { + getlibname(libname,GETENTRYNAME(hdr,lib)); + #if defined _Windows + #if defined __WIN32__ + hlib=GetModuleHandleA(libname); + #else + hlib=GetModuleHandle(libname); + if (hlib<=HINSTANCE_ERROR) + hlib=NULL; + #endif + #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + hlib=dlopen(libname,RTLD_NOLOAD); + #endif + if (hlib!=NULL) { + char funcname[sNAMEMAX+12]; /* +1 for '\0', +4 for 'amx_', +7 for 'Cleanup' */ + strcpy(funcname,"amx_"); + strcat(funcname,GETENTRYNAME(hdr,lib)); + strcat(funcname,"Cleanup"); + #if defined _Windows + libcleanup=(AMX_ENTRY)GetProcAddress(hlib,funcname); + #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + libcleanup=(AMX_ENTRY)dlsym(hlib,funcname); + #endif + if (libcleanup!=NULL) + libcleanup(amx); + #if defined _Windows + FreeLibrary(hlib); + #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + dlclose(hlib); + #endif + } /* if (hlib!=NULL) */ + } /* if (lib->address!=0) */ + } /* for */ + #else + (void)amx; + #endif + return AMX_ERR_NONE; +} +#endif /* AMX_CLEANUP */ + +#if defined AMX_CLONE +int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data) +{ + AMX_HEADER *hdr; + unsigned char _FAR *dataSource; + + if (amxSource==NULL) + return AMX_ERR_FORMAT; + if (amxClone==NULL) + return AMX_ERR_PARAMS; + if ((amxSource->flags & AMX_FLAG_INIT)==0) + return AMX_ERR_INIT; + hdr=(AMX_HEADER *)amxSource->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versionbase=amxSource->base; + amxClone->code=amxSource->code; + amxClone->codesize=amxSource->codesize; + amxClone->hlw=hdr->hea - hdr->dat; /* stack and heap relative to data segment */ + amxClone->stp=hdr->stp - hdr->dat - sizeof(cell); + amxClone->hea=amxClone->hlw; + amxClone->stk=amxClone->stp; + if (amxClone->callback==NULL) + amxClone->callback=amxSource->callback; + if (amxClone->debug==NULL) + amxClone->debug=amxSource->debug; + amxClone->flags=amxSource->flags; + + /* copy the data segment; the stack and the heap can be left uninitialized */ + assert(data!=NULL); + amxClone->data=(unsigned char _FAR *)data; + dataSource=(amxSource->data!=NULL) ? amxSource->data : amxSource->base+(int)hdr->dat; + memcpy(amxClone->data,dataSource,(size_t)(hdr->hea-hdr->dat)); + + /* Set a zero cell at the top of the stack, which functions + * as a sentinel for strings. + */ + * (cell *)(amxClone->data+(int)amxClone->stp) = 0; + + return AMX_ERR_NONE; +} +#endif /* AMX_CLONE */ + +#if defined AMX_MEMINFO +int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap) +{ + AMX_HEADER *hdr; + + if (amx==NULL) + return AMX_ERR_FORMAT; + hdr=(AMX_HEADER *)amx->base; + if (hdr->magic!=AMX_MAGIC) + return AMX_ERR_FORMAT; + if (hdr->file_version>CUR_FILE_VERSION || hdr->amx_versioncodesize; + if (datasize!=NULL) + *datasize=hdr->hea - hdr->dat; + if (stackheap!=NULL) + *stackheap=hdr->stp - hdr->hea; + + return AMX_ERR_NONE; +} +#endif /* AMX_MEMINFO */ + +#if defined AMX_NAMELENGTH +int AMXAPI amx_NameLength(AMX *amx, int *length) +{ + AMX_HEADER *hdr; + uint16_t *namelength; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + namelength=(uint16_t*)(amx->base + (unsigned)hdr->nametable); + *length=*namelength; + return AMX_ERR_NONE; +} +#endif /* AMX_NAMELENGTH */ + +#if defined AMX_XXXNATIVES +int AMXAPI amx_NumNatives(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->natives<=hdr->libraries); + *number=NUMENTRIES(hdr,natives,libraries); + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetNative(AMX *amx, int index, char *name) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->natives<=hdr->libraries); + if (index>=(cell)NUMENTRIES(hdr,natives,libraries)) + return AMX_ERR_INDEX; + + func=GETENTRY(hdr,natives,index); + strcpy(name,GETENTRYNAME(hdr,func)); + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index) +{ + int idx,last; + char pname[sNAMEMAX+1]; + + amx_NumNatives(amx, &last); + /* linear search, the natives table is not sorted alphabetically */ + for (idx=0; idxbase; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->publics<=hdr->natives); + *number=NUMENTRIES(hdr,publics,natives); + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetPublic(AMX *amx, int index, char *name, ucell *address) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->publics<=hdr->natives); + if (index>=(cell)NUMENTRIES(hdr,publics,natives)) + return AMX_ERR_INDEX; + + func=GETENTRY(hdr,publics,index); + if (name!=NULL) + strcpy(name,GETENTRYNAME(hdr,func)); + if (address!=NULL) + *address=func->address; + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindPublic(AMX *amx, const char *name, int *index) +{ + int first,last,result; + char pname[sNAMEMAX+1]; + + amx_NumPublics(amx, &last); + last--; /* last valid index is 1 less than the number of functions */ + first=0; + /* binary search */ + while (first<=last) { + int mid=(first+last)/2; + amx_GetPublic(amx,mid,pname,NULL); + result=strcmp(pname,name); + if (result>0) { + last=mid-1; + } else if (result<0) { + first=mid+1; + } else { + *index=mid; + return AMX_ERR_NONE; + } /* if */ + } /* while */ + /* not found, set to an invalid index, so amx_Exec() on this index will fail + * with an error + */ + *index=INT_MAX; + return AMX_ERR_NOTFOUND; +} +#endif /* AMX_XXXPUBLICS */ + +#if defined AMX_XXXPUBVARS +int AMXAPI amx_NumPubVars(AMX *amx, int *number) +{ + AMX_HEADER *hdr; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->pubvars<=hdr->tags); + *number=NUMENTRIES(hdr,pubvars,tags); + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetPubVar(AMX *amx, int index, char *name, cell **address) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *var; + unsigned char *data; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->pubvars<=hdr->tags); + if (index>=(cell)NUMENTRIES(hdr,pubvars,tags)) + return AMX_ERR_INDEX; + + var=GETENTRY(hdr,pubvars,index); + strcpy(name,GETENTRYNAME(hdr,var)); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + assert(address!=NULL); + *address=(cell *)(data+(int)var->address); + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindPubVar(AMX *amx, const char *name, cell **address) +{ + int first,last,result; + char pname[sNAMEMAX+1]; + + amx_NumPubVars(amx,&last); + last--; /* last valid index is 1 less than the number of functions */ + first=0; + /* binary search */ + while (first<=last) { + int mid=(first+last)/2; + amx_GetPubVar(amx,mid,pname,address); + result=strcmp(pname,name); + if (result>0) + last=mid-1; + else if (result<0) + first=mid+1; + else + return AMX_ERR_NONE; + } /* while */ + /* not found */ + assert(address!=NULL); + *address=NULL; + return AMX_ERR_NOTFOUND; +} +#endif /* AMX_XXXPUBVARS */ + +#if defined AMX_XXXTAGS +int AMXAPI amx_NumTags(AMX *amx, int *number) +{ + AMX_HEADER *hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + if (hdr->file_version<5) { /* the tagname table appeared in file format 5 */ + *number=0; + return AMX_ERR_VERSION; + } /* if */ + if (hdr->file_version<7) { /* file version 7 introduced the name table */ + assert(hdr->tags<=hdr->cod); + *number=NUMENTRIES(hdr,tags,cod); + } else { + assert(hdr->tags<=hdr->nametable); + *number=NUMENTRIES(hdr,tags,nametable); + } /* if */ + return AMX_ERR_NONE; +} + +int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *tag; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + if (hdr->file_version<5) { /* the tagname table appeared in file format 5 */ + *tagname='\0'; + *tag_id=0; + return AMX_ERR_VERSION; + } /* if */ + + if (hdr->file_version<7) { /* file version 7 introduced the name table */ + assert(hdr->tags<=hdr->cod); + if (index>=(cell)NUMENTRIES(hdr,tags,cod)) + return AMX_ERR_INDEX; + } else { + assert(hdr->tags<=hdr->nametable); + if (index>=(cell)NUMENTRIES(hdr,tags,nametable)) + return AMX_ERR_INDEX; + } /* if */ + + tag=GETENTRY(hdr,tags,index); + strcpy(tagname,GETENTRYNAME(hdr,tag)); + *tag_id=tag->address; + + return AMX_ERR_NONE; +} + +int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname) +{ + int first,last; + cell mid_id; + + #if !defined NDEBUG + /* verify that the tagname table is sorted on the tag_id */ + amx_NumTags(amx, &last); + if (last>0) { + cell cur_id; + amx_GetTag(amx,0,tagname,&cur_id); + for (first=1; firsttag_id) + last=mid-1; + else if (mid_idusertags[index]!=tag; index++) + /* nothing */; + if (index>=AMX_USERNUM) + return AMX_ERR_USERDATA; + *ptr=amx->userdata[index]; + return AMX_ERR_NONE; +} + +int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr) +{ + int index; + + assert(amx!=NULL); + assert(tag!=0); + /* try to find existing tag */ + for (index=0; indexusertags[index]!=tag; index++) + /* nothing */; + /* if not found, try to find empty tag */ + if (index>=AMX_USERNUM) + for (index=0; indexusertags[index]!=0; index++) + /* nothing */; + /* if still not found, quit with error */ + if (index>=AMX_USERNUM) + return AMX_ERR_INDEX; + /* set the tag and the value */ + amx->usertags[index]=tag; + amx->userdata[index]=ptr; + return AMX_ERR_NONE; +} +#endif /* AMX_XXXUSERDATA */ + +#if defined AMX_REGISTER +static AMX_NATIVE findfunction(char *name, const AMX_NATIVE_INFO *list, int number) +{ + int i; + + assert(list!=NULL); + for (i=0; (ibase; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + assert(hdr->natives<=hdr->libraries); + numnatives=NUMENTRIES(hdr,natives,libraries); + + err=AMX_ERR_NONE; + func=GETENTRY(hdr,natives,0); + for (i=0; iaddress==0) { + /* this function is not yet located */ + funcptr=(list!=NULL) ? findfunction(GETENTRYNAME(hdr,func),list,number) : NULL; + if (funcptr!=NULL) { + func->address=(uint32_t)(intptr_t)funcptr; + #if defined __64BIT__ + /* for 64-bit version the high part of the pointer must be stored too */ + func->nameofs=(uint32_t)((intptr_t)funcptr >> 32); + #endif + } else { + err=AMX_ERR_NOTFOUND; + } + } /* if */ + func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize); + } /* for */ + if (err==AMX_ERR_NONE) + amx->flags|=AMX_FLAG_NTVREG; + return err; +} +#endif /* AMX_REGISTER */ + +#if defined AMX_NATIVEINFO +AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func) +{ + static AMX_NATIVE_INFO n; + n.name=name; + n.func=func; + return &n; +} +#endif /* AMX_NATIVEINFO */ + + +#define STKMARGIN ((cell)(16*sizeof(cell))) + +#if defined AMX_PUSHXXX + +int AMXAPI amx_Push(AMX *amx, cell value) +{ + AMX_HEADER *hdr; + unsigned char *data; + + if (amx->hea+STKMARGIN>amx->stk) + return AMX_ERR_STACKERR; + hdr=(AMX_HEADER *)amx->base; + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + amx->stk-=sizeof(cell); + amx->paramcount+=1; + *(cell *)(data+(int)amx->stk)=value; + return AMX_ERR_NONE; +} + +int AMXAPI amx_PushAddress(AMX *amx, cell *address) +{ + AMX_HEADER *hdr; + unsigned char *data; + cell xaddr; + + /* reverse relocate the address */ + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + xaddr=(cell)((unsigned char*)address-data); + if ((ucell)xaddr>=(ucell)amx->stp) + return AMX_ERR_MEMACCESS; + return amx_Push(amx,xaddr); +} + +int AMXAPI amx_PushArray(AMX *amx, cell **address, const cell array[], int numcells) +{ + cell xaddr,*paddr; + int err; + + assert(amx!=NULL); + assert(array!=NULL); + + xaddr=amx->hea; /* save, before it is modified by amx_Allot() */ + err=amx_Allot(amx,numcells,&paddr); + if (err==AMX_ERR_NONE) { + memcpy(paddr,array,numcells*sizeof(cell)); + err=amx_Push(amx,xaddr); + } /* if */ + if (address!=NULL) + *address=paddr; + return err; +} + +int AMXAPI amx_PushString(AMX *amx, cell **address, const char *string, int pack, int use_wchar) +{ + cell xaddr,*paddr; + int numcells,err; + + assert(amx!=NULL); + assert(string!=NULL); + + #if defined AMX_ANSIONLY + numcells=strlen(string) + 1; + #else + numcells= (int)(use_wchar ? wcslen((const wchar_t*)string) : strlen(string)) + 1; + #endif + if (pack) + numcells=(numcells+sizeof(cell)-1)/sizeof(cell); + xaddr=amx->hea; /* save, before it is modified by amx_Allot() */ + err=amx_Allot(amx,numcells,&paddr); + if (err==AMX_ERR_NONE) { + amx_SetString(paddr,string,pack,use_wchar,numcells); + err=amx_Push(amx,xaddr); + } /* if */ + if (address!=NULL) + *address=paddr; + return err; +} +#endif /* AMX_PUSHXXX */ + +#if defined AMX_EXEC + +/* It is assumed that the abstract machine can simply access the memory area + * for the global data and the stack. If this is not the case, you need to + * define the macro sets _R() and _W(), for reading and writing to memory. + */ +#if !defined _R + #define _R_DEFAULT /* mark default memory access */ + #define _R(base,addr) (* (cell *)((unsigned char*)(base)+(int)(addr))) + #define _R8(base,addr) (* (unsigned char *)((unsigned char*)(base)+(int)(addr))) + #define _R16(base,addr) (* (uint16_t *)((unsigned char*)(base)+(int)(addr))) + #define _R32(base,addr) (* (uint32_t *)((unsigned char*)(base)+(int)(addr))) +#endif +#if !defined _W + #define _W_DEFAULT /* mark default memory access */ + #define _W(base,addr,value) ((*(cell *)((unsigned char*)(base)+(int)(addr)))=(cell)(value)) + #define _W8(base,addr,value) ((*(unsigned char *)((unsigned char*)(base)+(int)(addr)))=(unsigned char)(value)) + #define _W16(base,addr,value) ((*(uint16_t *)((unsigned char*)(base)+(int)(addr)))=(uint16_t)(value)) + #define _W32(base,addr,value) ((*(uint32_t *)((unsigned char*)(base)+(int)(addr)))=(uint32_t)(value)) +#endif + +#if -8/3==-2 && 8/-3==-2 + #define TRUNC_SDIV /* signed divisions are truncated on this platform */ +#else + #define IABS(a) ((a)>=0 ? (a) : (-a)) +#endif + +/* The pseudo-instructions come from the code stream. Normally, these are just + * accessed from memory. When the instructions must be fetched in some other + * way, the definition below must be pre-defined. + * N.B.: + * - reading from a code address should increment the instruction pointer + * (called "cip") + * - only cell-sized accesses occur in code memory + */ +#if !defined _RCODE + #define _RCODE() ( *cip++ ) +#endif + +#if !defined GETPARAM + #define GETPARAM(v) ( v=_RCODE() ) /* read a parameter from the opcode stream */ +#endif +#if !defined SKIPPARAM + #define SKIPPARAM(n) ( cip=(cell *)cip+(n) ) /* for obsolete opcodes */ +#endif + +#define AMXPUSH(v) ( amx->stk-=sizeof(cell), *(cell*)(data+amx->stk)=(v) ) +#define ABORT(amx,v) { (amx)->stk=reset_stk; (amx)->hea=reset_hea; return v; } + + +#if !defined AMX_ALTCORE +int amx_exec_list(AMX *amx,const cell **opcodelist,int *numopcodes) +{ + (void)amx; + assert(opcodelist!=NULL); + *opcodelist=NULL; + assert(numopcodes!=NULL); + *numopcodes=OP_NUM_OPCODES; + return 0; +} +#endif + +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index) +{ + AMX_HEADER *hdr; + AMX_FUNCSTUB *func; + unsigned char *data; + cell reset_stk,reset_hea; + int i; +#if !defined AMX_ALTCORE + cell pri,alt,stk,frm,hea; + cell *cip,op,offs,val; +#endif + + assert(amx!=NULL); + if ((amx->flags & AMX_FLAG_INIT)==0) + return AMX_ERR_INIT; + if (amx->callback==NULL) + return AMX_ERR_CALLBACK; + + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + + if ((amx->flags & AMX_FLAG_NTVREG)==0) { + /* verify that all native functions have been registered (or do not + * need registering) + */ + int numnatives; + assert(hdr->natives<=hdr->libraries); + numnatives=NUMENTRIES(hdr,natives,libraries); + func=GETENTRY(hdr,natives,0); + for (i=0; iaddress!=0; i++) + func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize); + if (iflags|=AMX_FLAG_NTVREG; /* no need to check this again */ + } /* if */ + assert((amx->flags & AMX_FLAG_VERIFY)==0); + + /* set up the registers */ + assert(hdr!=NULL && hdr->magic==AMX_MAGIC); + assert(amx->code!=NULL || hdr->overlays!=hdr->nametable); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + reset_stk=amx->stk; + reset_hea=amx->hea; + amx->error=AMX_ERR_NONE; + + /* get the start address */ + if (index==AMX_EXEC_MAIN) { + if (hdr->cip<0) + return AMX_ERR_INDEX; + amx->cip=hdr->cip; + if (hdr->overlays!=hdr->nametable) { + assert(hdr->overlays!=0); + assert(amx->overlay!=NULL); + amx->ovl_index=(int)hdr->cip; + if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) + return i; + amx->cip=0; + } /* if */ + } else if (index==AMX_EXEC_CONT) { + /* restore registers reset_stk & reset_hea */ + reset_stk=amx->reset_stk; + reset_hea=amx->reset_hea; + if (hdr->overlays!=hdr->nametable) { + assert(hdr->overlays!=0); + assert(amx->overlay!=NULL); + if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) + return i; + } /* if */ + } else if (index<0) { + return AMX_ERR_INDEX; + } else { + if (index>=(int)NUMENTRIES(hdr,publics,natives)) + return AMX_ERR_INDEX; + func=GETENTRY(hdr,publics,index); + amx->cip=func->address; + if (hdr->overlays!=hdr->nametable) { + assert(hdr->overlays!=0); + assert(amx->overlay!=NULL); + amx->ovl_index=func->address; + if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) + return i; + amx->cip=0; + } /* if */ + } /* if */ + /* check values just copied */ + if (amx->stk>amx->stp) + return AMX_ERR_STACKLOW; + if (amx->heahlw) + return AMX_ERR_HEAPLOW; + assert(check_endian()); + + /* sanity checks */ + assert_static(OP_XCHG==21); + assert_static(OP_SMUL==42); + assert_static(OP_MOVS==64); + #if !defined AMX_NO_MACRO_INSTR + assert_static(OP_LIDX==81); + assert_static(OP_ZERO_PRI==102); + assert_static(OP_LOAD2==120); + #endif + #if !defined AMX_NO_PACKED_OPC + assert_static(OP_LOAD_P_PRI==124); + assert_static(OP_ALIGN_P_PRI==141); + assert_static(OP_BOUNDS_P==174); + #endif + #if PAWN_CELL_SIZE==16 + assert_static(sizeof(cell)==2); + #elif PAWN_CELL_SIZE==32 + assert_static(sizeof(cell)==4); + #elif PAWN_CELL_SIZE==64 + assert_static(sizeof(cell)==8); + #else + #error Unsupported cell size + #endif + + if (index!=AMX_EXEC_CONT) { + reset_stk+=amx->paramcount*sizeof(cell); + AMXPUSH(amx->paramcount*sizeof(cell)); + amx->paramcount=0; /* push the parameter count to the stack & reset */ + AMXPUSH(0); /* return address (for overlays: overlay 0, offset 0) */ + } /* if */ + /* check stack/heap before starting to run */ + if (amx->hea+STKMARGIN>amx->stk) + return AMX_ERR_STACKERR; + +#if defined AMX_ALTCORE + + /* start running either the ARM or 80x86 assembler abstract machine or the JIT */ + #if defined AMX_ASM && defined AMX_JIT + if ((amx->flags & AMX_FLAG_JITC)!=0) + i = amx_jit_run(amx,retval,data); + else + i = amx_exec_run(amx,retval,data); + #elif defined AMX_JIT + i = amx_jit_run(amx,retval,data); + #else + /* also for GNU GCC and Intel C/C++ versions */ + i = amx_exec_run(amx,retval,data); + #endif + if (i == AMX_ERR_SLEEP) { + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + } else { + /* remove parameters from the stack; do this the "hard" way, because + * the assembler version has no internal knowledge of the local + * variables, so any "clean" way would be a kludge anyway. + */ + amx->stk=reset_stk; + amx->hea=reset_hea; + } /* if */ + return i; + +#else + + #define CHKMARGIN() if (hea+STKMARGIN>stk) return AMX_ERR_STACKERR + #define CHKSTACK() if (stk>amx->stp) return AMX_ERR_STACKLOW + #define CHKHEAP() if (heahlw) return AMX_ERR_HEAPLOW + + /* PUSH() and POP() are defined in terms of the _R() and _W() macros */ + #define PUSH(v) ( stk-=sizeof(cell), _W(data,stk,v) ) + #define POP(v) ( v=_R(data,stk), stk+=sizeof(cell) ) + + /* set up registers for ANSI-C core: pri, alt, frm, cip, hea, stk */ + pri=amx->pri; + alt=amx->alt; + frm=amx->frm; + cip=(cell *)(amx->code+(int)amx->cip); + hea=amx->hea; + stk=amx->stk; + + /* start running */ + for ( ;; ) { + op=_RCODE(); + switch (GETOPCODE(op)) { + /* core instruction set */ + case OP_NOP: + break; + case OP_LOAD_PRI: + GETPARAM(offs); + pri=_R(data,offs); + break; + case OP_LOAD_ALT: + GETPARAM(offs); + alt=_R(data,offs); + break; + case OP_LOAD_S_PRI: + GETPARAM(offs); + pri=_R(data,frm+offs); + break; + case OP_LOAD_S_ALT: + GETPARAM(offs); + alt=_R(data,frm+offs); + break; + case OP_LREF_S_PRI: + GETPARAM(offs); + offs=_R(data,frm+offs); + pri=_R(data,offs); + break; + case OP_LREF_S_ALT: + GETPARAM(offs); + offs=_R(data,frm+offs); + alt=_R(data,offs); + break; + case OP_LOAD_I: + /* verify address */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri=_R(data,pri); + break; + case OP_LODB_I: + GETPARAM(offs); + __lodb_i: + /* verify address */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch ((int)offs) { + case 1: + pri=_R8(data,pri); + break; + case 2: + pri=_R16(data,pri); + break; + case 4: + pri=_R32(data,pri); + break; + } /* switch */ + break; + case OP_CONST_PRI: + GETPARAM(pri); + break; + case OP_CONST_ALT: + GETPARAM(alt); + break; + case OP_ADDR_PRI: + GETPARAM(pri); + pri+=frm; + break; + case OP_ADDR_ALT: + GETPARAM(alt); + alt+=frm; + break; + case OP_STOR: + GETPARAM(offs); + _W(data,offs,pri); + break; + case OP_STOR_S: + GETPARAM(offs); + _W(data,frm+offs,pri); + break; + case OP_SREF_S: + GETPARAM(offs); + offs=_R(data,frm+offs); + _W(data,offs,pri); + break; + case OP_STOR_I: + /* verify address */ + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + _W(data,alt,pri); + break; + case OP_STRB_I: + GETPARAM(offs); + __strb_i: + /* verify address */ + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + switch ((int)offs) { + case 1: + _W8(data,alt,pri); + break; + case 2: + _W16(data,alt,pri); + break; + case 4: + _W32(data,alt,pri); + break; + } /* switch */ + break; + case OP_ALIGN_PRI: + GETPARAM(offs); + #if BYTE_ORDER==LITTLE_ENDIAN + if ((size_t)offscod; + break; + case 1: + pri=hdr->dat; + break; + case 2: + pri=hea; + break; + case 3: + pri=amx->stp; + break; + case 4: + pri=stk; + break; + case 5: + pri=frm; + break; + case 6: + pri=(cell)((unsigned char *)cip-amx->code); + break; + } /* switch */ + break; + case OP_SCTRL: + GETPARAM(offs); + switch ((int)offs) { + case 0: + case 1: + case 3: + /* cannot change these parameters */ + break; + case 2: + hea=pri; + break; + case 4: + stk=pri; + break; + case 5: + frm=pri; + break; + case 6: + cip=(cell *)(amx->code + (int)pri); + break; + } /* switch */ + break; + case OP_XCHG: + offs=pri; /* offs is a temporary variable */ + pri=alt; + alt=offs; + break; + case OP_PUSH_PRI: + PUSH(pri); + break; + case OP_PUSH_ALT: + PUSH(alt); + break; + case OP_PUSHR_PRI: + PUSH((intptr_t)data+pri); + break; + case OP_POP_PRI: + POP(pri); + break; + case OP_POP_ALT: + POP(alt); + break; + case OP_PICK: + GETPARAM(offs); + pri=_R(data,stk+offs); + break; + case OP_STACK: + GETPARAM(offs); + stk+=offs; + alt=stk; + CHKMARGIN(); + CHKSTACK(); + break; + case OP_HEAP: + GETPARAM(offs); + alt=hea; + hea+=offs; + CHKMARGIN(); + CHKHEAP(); + break; + case OP_PROC: + PUSH(frm); + frm=stk; + CHKMARGIN(); + break; + case OP_RET: + POP(frm); + POP(offs); + /* verify the return address */ + if ((long)offs>=amx->codesize) + ABORT(amx,AMX_ERR_MEMACCESS); + cip=(cell *)(amx->code+(int)offs); + break; + case OP_RETN: + POP(frm); + POP(offs); + /* verify the return address */ + if ((long)offs>=amx->codesize) + ABORT(amx,AMX_ERR_MEMACCESS); + cip=(cell *)(amx->code+(int)offs); + stk+=_R(data,stk)+sizeof(cell); /* remove parameters from the stack */ + break; + case OP_CALL: + PUSH(((unsigned char *)cip-amx->code)+sizeof(cell));/* skip address */ + cip=JUMPREL(cip); /* jump to the address */ + break; + case OP_JUMP: + /* since the GETPARAM() macro modifies cip, you cannot + * do GETPARAM(cip) directly */ + cip=JUMPREL(cip); + break; + case OP_JZER: + if (pri==0) + cip=JUMPREL(cip); + else + SKIPPARAM(1); + break; + case OP_JNZ: + if (pri!=0) + cip=JUMPREL(cip); + else + SKIPPARAM(1); + break; + case OP_SHL: + pri<<=alt; + break; + case OP_SHR: + pri=(ucell)pri >> (int)alt; + break; + case OP_SSHR: + pri>>=alt; + break; + case OP_SHL_C_PRI: + GETPARAM(offs); + pri<<=offs; + break; + case OP_SHL_C_ALT: + GETPARAM(offs); + alt<<=offs; + break; + case OP_SMUL: + pri*=alt; + break; + case OP_SDIV: + if (pri==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* use floored division and matching remainder */ + offs=pri; + #if defined TRUNC_SDIV + pri=alt/offs; + alt=alt%offs; + #else + val=alt; /* portable routine for truncated division */ + pri=IABS(alt)/IABS(offs); + if ((cell)(val ^ offs)<0) + pri=-pri; + alt=val-pri*offs; /* calculate the matching remainder */ + #endif + /* now "fiddle" with the values to get floored division */ + if (alt!=0 && (cell)(alt ^ offs)<0) { + pri--; + alt+=offs; + } /* if */ + break; + case OP_ADD: + pri+=alt; + break; + case OP_SUB: + pri=alt-pri; + break; + case OP_AND: + pri&=alt; + break; + case OP_OR: + pri|=alt; + break; + case OP_XOR: + pri^=alt; + break; + case OP_NOT: + pri=!pri; + break; + case OP_NEG: + pri=-pri; + break; + case OP_INVERT: + pri=~pri; + break; + case OP_EQ: + pri= pri==alt ? 1 : 0; + break; + case OP_NEQ: + pri= pri!=alt ? 1 : 0; + break; + case OP_SLESS: + pri= prialt ? 1 : 0; + break; + case OP_SGEQ: + pri= pri>=alt ? 1 : 0; + break; + case OP_INC_PRI: + pri++; + break; + case OP_INC_ALT: + alt++; + break; + case OP_INC_I: + #if defined _R_DEFAULT + *(cell *)(data+(int)pri) += 1; + #else + val=_R(data,pri); + _W(data,pri,val+1); + #endif + break; + case OP_DEC_PRI: + pri--; + break; + case OP_DEC_ALT: + alt--; + break; + case OP_DEC_I: + #if defined _R_DEFAULT + *(cell *)(data+(int)pri) -= 1; + #else + val=_R(data,pri); + _W(data,pri,val-1); + #endif + break; + case OP_MOVS: + GETPARAM(offs); + __movs: + /* verify top & bottom memory addresses, for both source and destination + * addresses + */ + if (pri>=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + #if defined _R_DEFAULT + memcpy(data+(int)alt, data+(int)pri, (int)offs); + #else + for (i=0; i+4=hea && pri=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((pri+offs)>hea && (pri+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if (alt>=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + #if defined _R_DEFAULT + pri=memcmp(data+(int)alt, data+(int)pri, (int)offs); + #else + val=0; + for (i=0; i+4=hea && alt=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + if ((alt+offs)>hea && (alt+offs)(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + for (i=(int)alt; (size_t)offs>=sizeof(cell); i+=sizeof(cell), offs-=sizeof(cell)) + _W32(data,i,pri); + break; + case OP_HALT: + GETPARAM(offs); + __halt: + if (retval!=NULL) + *retval=pri; + /* store complete status (stk and hea are already set in the ABORT macro) */ + amx->frm=frm; + amx->pri=pri; + amx->alt=alt; + amx->cip=(cell)((unsigned char*)cip-amx->code); + if (offs==AMX_ERR_SLEEP) { + amx->stk=stk; + amx->hea=hea; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return (int)offs; + } /* if */ + ABORT(amx,(int)offs); + case OP_BOUNDS: + GETPARAM(offs); + if ((ucell)pri>(ucell)offs) { + amx->cip=(cell)((unsigned char *)cip-amx->code); + ABORT(amx,AMX_ERR_BOUNDS); + } /* if */ + break; + case OP_SYSREQ: + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-amx->code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + i=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); + if (i!=AMX_ERR_NONE) { + if (i==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return i; + } /* if */ + ABORT(amx,i); + } /* if */ + break; + case OP_SWITCH: { + cell *cptr=JUMPREL(cip)+1;/* +1, to skip the "casetbl" opcode */ + assert(*JUMPREL(cip)==OP_CASETBL); + cip=JUMPREL(cptr+1); /* preset to "none-matched" case */ + i=(int)*cptr; /* number of records in the case table */ + for (cptr+=2; i>0 && *cptr!=pri; i--,cptr+=2) + /* nothing */; + if (i>0) + cip=JUMPREL(cptr+1); /* case found */ + break; + } /* case */ + case OP_SWAP_PRI: + offs=_R(data,stk); + _W32(data,stk,pri); + pri=offs; + break; + case OP_SWAP_ALT: + offs=_R(data,stk); + _W32(data,stk,alt); + alt=offs; + break; + case OP_BREAK: + assert((amx->flags & AMX_FLAG_VERIFY)==0); + if (amx->debug!=NULL) { + /* store status */ + amx->frm=frm; + amx->stk=stk; + amx->hea=hea; + amx->cip=(cell)((unsigned char*)cip-amx->code); + i=amx->debug(amx); + if (i!=AMX_ERR_NONE) { + if (i==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return i; + } /* if */ + ABORT(amx,i); + } /* if */ + } /* if */ + break; +#if !defined AMX_DONT_RELOCATE + case OP_SYSREQ_D: /* see SYSREQ */ + GETPARAM(offs); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-amx->code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + pri=((AMX_NATIVE)(intptr_t)offs)(amx,(cell*)(data+(int)stk)); + if (amx->error!=AMX_ERR_NONE) { + if (amx->error==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return AMX_ERR_SLEEP; + } /* if */ + ABORT(amx,amx->error); + } /* if */ + break; +#endif +#if !defined AMX_NO_MACRO_INSTR && !defined AMX_DONT_RELOCATE + case OP_SYSREQ_ND: /* see SYSREQ_N */ + GETPARAM(offs); + GETPARAM(val); + PUSH(val); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-amx->code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + pri=((AMX_NATIVE)(intptr_t)offs)(amx,(cell*)(data+(int)stk)); + stk+=val+4; + if (amx->error!=AMX_ERR_NONE) { + if (amx->error==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->stk=stk; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return AMX_ERR_SLEEP; + } /* if */ + ABORT(amx,amx->error); + } /* if */ + break; +#endif + + /* overlay instructions */ +#if !defined AMX_NO_OVERLAY + case OP_CALL_OVL: + offs=(cell)((unsigned char *)cip-amx->code+sizeof(cell)); /* skip address */ + assert(offs>=0 && offs<(1L<<(sizeof(cell)*4))); + PUSH((offs<<(sizeof(cell)*4)) | amx->ovl_index); + amx->ovl_index=(int)*cip; + assert(amx->overlay!=NULL); + if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) + ABORT(amx,i); + cip=(cell*)amx->code; + break; + case OP_RETN_OVL: + assert(amx->overlay!=NULL); + POP(frm); + POP(offs); + amx->ovl_index=offs & (((ucell)~0)>>4*sizeof(cell)); + offs=(ucell)offs >> (sizeof(cell)*4); + /* verify the index */ + stk+=_R(data,stk)+sizeof(cell); /* remove parameters from the stack */ + i=amx->overlay(amx,amx->ovl_index); /* reload overlay */ + if (i!=AMX_ERR_NONE || (long)offs>=amx->codesize) + ABORT(amx,AMX_ERR_MEMACCESS); + cip=(cell *)(amx->code+(int)offs); + break; + case OP_SWITCH_OVL: { + cell *cptr=JUMPREL(cip)+1; /* +1, to skip the "icasetbl" opcode */ + assert(*JUMPREL(cip)==OP_CASETBL_OVL); + amx->ovl_index=*(cptr+1); /* preset to "none-matched" case */ + i=(int)*cptr; /* number of records in the case table */ + for (cptr+=2; i>0 && *cptr!=pri; i--,cptr+=2) + /* nothing */; + if (i>0) + amx->ovl_index=*(cptr+1); /* case found */ + assert(amx->overlay!=NULL); + if ((i=amx->overlay(amx,amx->ovl_index))!=AMX_ERR_NONE) + ABORT(amx,i); + cip=(cell*)amx->code; + break; + } /* case */ +#endif + + /* supplemental and macro instructions */ +#if !defined AMX_NO_MACRO_INSTR + case OP_LIDX: + offs=pri*sizeof(cell)+alt; + /* verify address */ + if (offs>=hea && offs=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri=_R(data,offs); + break; + case OP_LIDX_B: + GETPARAM(offs); + offs=(pri << (int)offs)+alt; + /* verify address */ + if (offs>=hea && offs=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri=_R(data,offs); + break; + case OP_IDXADDR: + pri=pri*sizeof(cell)+alt; + break; + case OP_IDXADDR_B: + GETPARAM(offs); + pri=(pri << (int)offs)+alt; + break; + case OP_PUSH_C: + GETPARAM(offs); + PUSH(offs); + break; + case OP_PUSH: + GETPARAM(offs); + PUSH(_R(data,offs)); + break; + case OP_PUSH_S: + GETPARAM(offs); + PUSH(_R(data,frm+offs)); + break; + case OP_PUSH_ADR: + GETPARAM(offs); + PUSH(frm+offs); + break; + case OP_PUSHR_C: + GETPARAM(offs); + PUSH((intptr_t)data+offs); + break; + case OP_PUSHR_S: + GETPARAM(offs); + PUSH((intptr_t)data+_R(data,frm+offs)); + break; + case OP_PUSHR_ADR: + GETPARAM(offs); + PUSH((intptr_t)data+frm+offs); + break; + case OP_JEQ: + if (pri==alt) + cip=JUMPREL(cip); + else + SKIPPARAM(1); + break; + case OP_JNEQ: + if (pri!=alt) + cip=JUMPREL(cip); + else + SKIPPARAM(1); + break; + case OP_JSLESS: + if (prialt) + cip=JUMPREL(cip); + else + SKIPPARAM(1); + break; + case OP_JSGEQ: + if (pri>=alt) + cip=JUMPREL(cip); + else + SKIPPARAM(1); + break; + case OP_SDIV_INV: + if (alt==0) + ABORT(amx,AMX_ERR_DIVIDE); + /* use floored division and matching remainder */ + offs=alt; + #if defined TRUNC_SDIV + pri=pri/offs; + alt=pri%offs; + #else + val=pri; /* portable routine for truncated division */ + pri=IABS(pri)/IABS(offs); + if ((cell)(val ^ offs)<0) + pri=-pri; + alt=val-pri*offs; /* calculate the matching remainder */ + #endif + /* now "fiddle" with the values to get floored division */ + if (alt!=0 && (cell)(alt ^ offs)<0) { + pri--; + alt+=offs; + } /* if */ + break; + case OP_SUB_INV: + pri-=alt; + break; + case OP_ADD_C: + GETPARAM(offs); + pri+=offs; + break; + case OP_SMUL_C: + GETPARAM(offs); + pri*=offs; + break; + case OP_ZERO_PRI: + pri=0; + break; + case OP_ZERO_ALT: + alt=0; + break; + case OP_ZERO: + GETPARAM(offs); + _W(data,offs,0); + break; + case OP_ZERO_S: + GETPARAM(offs); + _W(data,frm+offs,0); + break; + case OP_EQ_C_PRI: + GETPARAM(offs); + pri= pri==offs ? 1 : 0; + break; + case OP_EQ_C_ALT: + GETPARAM(offs); + pri= alt==offs ? 1 : 0; + break; + case OP_INC: + GETPARAM(offs); + #if defined _R_DEFAULT + *(cell *)(data+(int)offs) += 1; + #else + val=_R(data,offs); + _W(data,offs,val+1); + #endif + break; + case OP_INC_S: + GETPARAM(offs); + #if defined _R_DEFAULT + *(cell *)(data+(int)(frm+offs)) += 1; + #else + val=_R(data,frm+offs); + _W(data,frm+offs,val+1); + #endif + break; + case OP_DEC: + GETPARAM(offs); + #if defined _R_DEFAULT + *(cell *)(data+(int)offs) -= 1; + #else + val=_R(data,offs); + _W(data,offs,val-1); + #endif + break; + case OP_DEC_S: + GETPARAM(offs); + #if defined _R_DEFAULT + *(cell *)(data+(int)(frm+offs)) -= 1; + #else + val=_R(data,frm+offs); + _W(data,frm+offs,val-1); + #endif + break; + case OP_SYSREQ_N: + GETPARAM(offs); + GETPARAM(val); + PUSH(val); + /* save a few registers */ + amx->cip=(cell)((unsigned char *)cip-amx->code); + amx->hea=hea; + amx->frm=frm; + amx->stk=stk; + i=amx->callback(amx,offs,&pri,(cell *)(data+(int)stk)); + stk+=val+4; + if (i!=AMX_ERR_NONE) { + if (i==AMX_ERR_SLEEP) { + amx->pri=pri; + amx->alt=alt; + amx->stk=stk; + amx->reset_stk=reset_stk; + amx->reset_hea=reset_hea; + return i; + } /* if */ + ABORT(amx,i); + } /* if */ + break; + case OP_PUSHM_C: + GETPARAM(val); + while (val--) { + GETPARAM(offs); + PUSH(offs); + } /* while */ + break; + case OP_PUSHM: + GETPARAM(val); + while (val--) { + GETPARAM(offs); + PUSH(_R(data,offs)); + } /* while */ + break; + case OP_PUSHM_S: + GETPARAM(val); + while (val--) { + GETPARAM(offs); + PUSH(_R(data,frm+offs)); + } /* while */ + break; + case OP_PUSHM_ADR: + GETPARAM(val); + while (val--) { + GETPARAM(offs); + PUSH(frm+offs); + } /* while */ + break; + case OP_PUSHRM_C: + GETPARAM(val); + while (val--) { + GETPARAM(offs); + PUSH((intptr_t)data+offs); + } /* while */ + break; + case OP_PUSHRM_S: + GETPARAM(val); + while (val--) { + GETPARAM(offs); + PUSH((intptr_t)data+_R(data,frm+offs)); + } /* while */ + break; + case OP_PUSHRM_ADR: + GETPARAM(val); + while (val--) { + GETPARAM(offs); + PUSH((intptr_t)data+frm+offs); + } /* while */ + break; + case OP_LOAD2: + GETPARAM(offs); + pri=_R(data,offs); + GETPARAM(offs); + alt=_R(data,offs); + break; + case OP_LOAD2_S: + GETPARAM(offs); + pri=_R(data,frm+offs); + GETPARAM(offs); + alt=_R(data,frm+offs); + break; + case OP_CONST: + GETPARAM(offs); + GETPARAM(val); + _W32(data,offs,val); + break; + case OP_CONST_S: + GETPARAM(offs); + GETPARAM(val); + _W32(data,frm+offs,val); + break; +#endif /* AMX_NO_MACRO_INSTR */ + +#if !defined AMX_NO_PACKED_OPC + case OP_LOAD_P_PRI: + GETPARAM_P(offs,op); + pri=_R(data,offs); + break; + case OP_LOAD_P_ALT: + GETPARAM_P(offs,op); + alt=_R(data,offs); + break; + case OP_LOAD_P_S_PRI: + GETPARAM_P(offs,op); + pri=_R(data,frm+offs); + break; + case OP_LOAD_P_S_ALT: + GETPARAM_P(offs,op); + alt=_R(data,frm+offs); + break; + case OP_LREF_P_S_PRI: + GETPARAM_P(offs,op); + offs=_R(data,frm+offs); + pri=_R(data,offs); + break; + case OP_LREF_P_S_ALT: + GETPARAM_P(offs,op); + offs=_R(data,frm+offs); + alt=_R(data,offs); + break; + case OP_LODB_P_I: + GETPARAM_P(offs,op); + goto __lodb_i; + case OP_CONST_P_PRI: + GETPARAM_P(pri,op); + break; + case OP_CONST_P_ALT: + GETPARAM_P(alt,op); + break; + case OP_ADDR_P_PRI: + GETPARAM_P(pri,op); + pri+=frm; + break; + case OP_ADDR_P_ALT: + GETPARAM_P(alt,op); + alt+=frm; + break; + case OP_STOR_P: + GETPARAM_P(offs,op); + _W(data,offs,pri); + break; + case OP_STOR_P_S: + GETPARAM_P(offs,op); + _W(data,frm+offs,pri); + break; + case OP_SREF_P_S: + GETPARAM_P(offs,op); + offs=_R(data,frm+offs); + _W(data,offs,pri); + break; + case OP_STRB_P_I: + GETPARAM_P(offs,op); + goto __strb_i; + case OP_LIDX_P_B: + GETPARAM_P(offs,op); + offs=(pri << (int)offs)+alt; + /* verify address */ + if (offs>=hea && offs=(ucell)amx->stp) + ABORT(amx,AMX_ERR_MEMACCESS); + pri=_R(data,offs); + break; + case OP_IDXADDR_P_B: + GETPARAM_P(offs,op); + pri=(pri << (int)offs)+alt; + break; + case OP_ALIGN_P_PRI: + GETPARAM_P(offs,op); + #if BYTE_ORDER==LITTLE_ENDIAN + if ((size_t)offs(ucell)offs) { + amx->cip=(cell)((unsigned char *)cip-amx->code); + ABORT(amx,AMX_ERR_BOUNDS); + } /* if */ + break; +#endif /* AMX_NO_PACKED_OPC */ + default: + assert(0); /* invalid instructions should already have been caught in VerifyPcode() */ + ABORT(amx,AMX_ERR_INVINSTR); + } /* switch */ + } /* for */ +#endif /* AMX_ALTCORE */ +} + +#endif /* AMX_EXEC */ + +#if defined AMX_SETCALLBACK +int AMXAPI amx_SetCallback(AMX *amx,AMX_CALLBACK callback) +{ + assert(amx!=NULL); + assert(callback!=NULL); + amx->callback=callback; + return AMX_ERR_NONE; +} +#endif /* AMX_SETCALLBACK */ + +#if defined AMX_SETDEBUGHOOK +int AMXAPI amx_SetDebugHook(AMX *amx,AMX_DEBUG debug) +{ + assert(amx!=NULL); + amx->debug=debug; + return AMX_ERR_NONE; +} +#endif /* AMX_SETDEBUGHOOK */ + +#if defined AMX_RAISEERROR +int AMXAPI amx_RaiseError(AMX *amx, int error) +{ + assert(error>0); + amx->error=error; + return AMX_ERR_NONE; +} +#endif /* AMX_RAISEERROR */ + +#if defined AMX_ALLOT || defined AMX_PUSHXXX +int AMXAPI amx_Allot(AMX *amx,int cells,cell **address) +{ + AMX_HEADER *hdr; + unsigned char *data; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + + if (amx->stk - amx->hea - cells*sizeof(cell) < STKMARGIN) + return AMX_ERR_MEMORY; + if (address!=NULL) + *address=(cell *)(data+(int)amx->hea); + amx->hea+=cells*sizeof(cell); + return AMX_ERR_NONE; +} + +int AMXAPI amx_Release(AMX *amx,cell *address) +{ + AMX_HEADER *hdr; + unsigned char *data; + cell amx_addr; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + amx_addr=(cell)((unsigned char*)address-data); + if (amx->hea>amx_addr) + amx->hea=amx_addr; + return AMX_ERR_NONE; +} +#endif /* AMX_ALLOT || AMX_PUSHXXX */ + +#if defined AMX_VERIFYADDR +int AMXAPI amx_VerifyAddress(AMX *amx,cell *address) +{ + AMX_HEADER *hdr; + unsigned char *data; + + assert(amx!=NULL); + hdr=(AMX_HEADER *)amx->base; + assert(hdr!=NULL); + assert(hdr->magic==AMX_MAGIC); + data=(amx->data!=NULL) ? amx->data : amx->base+(int)hdr->dat; + + return (unsigned char*)address>=data && (unsigned char*)addressstp; +} +#endif /* AMX_VERIFYADDR */ + +#if defined AMX_XXXSTRING || defined AMX_UTF8XXX + +#define CHARBITS (8*sizeof(char)) +#if PAWN_CELL_SIZE==16 + #define CHARMASK (0xffffu << 8*(2-sizeof(char))) +#elif PAWN_CELL_SIZE==32 + #define CHARMASK (0xffffffffuL << 8*(4-sizeof(char))) +#elif PAWN_CELL_SIZE==64 + #define CHARMASK (0xffffffffffffffffuLL << 8*(8-sizeof(char))) +#else + #error Unsupported cell size +#endif + +int AMXAPI amx_StrLen(const cell *cstr, int *length) +{ + int len; + #if BYTE_ORDER==LITTLE_ENDIAN + cell c; + #endif + + assert(length!=NULL); + if (cstr==NULL) { + *length=0; + return AMX_ERR_PARAMS; + } /* if */ + + if ((ucell)*cstr>UNPACKEDMAX) { + /* packed string */ + assert_static(sizeof(char)==1); + len=(int)strlen((char *)cstr); /* find '\0' */ + assert(check_endian()); + #if BYTE_ORDER==LITTLE_ENDIAN + /* on Little Endian machines, toggle the last bytes */ + c=cstr[len/sizeof(cell)]; /* get last cell */ + len=len - len % sizeof(cell); /* len = multiple of "cell" bytes */ + while ((c & CHARMASK)!=0) { + len++; + c=(ucell)c << 8*sizeof(char); + } /* if */ + #endif + } else { + for (len=0; cstr[len]!=0; len++) + /* nothing */; + } /* if */ + *length = len; + return AMX_ERR_NONE; +} +#endif + +#if defined AMX_XXXSTRING || defined AMX_PUSHXXX +int AMXAPI amx_SetString(cell *dest,const char *source,int pack,int use_wchar,size_t size) +{ /* the memory blocks should not overlap */ + int i; + size_t len; + + assert_static(UNLIMITED>0); + #if defined AMX_ANSIONLY + (void)use_wchar; + len=strlen(source); + #else + len= use_wchar ? wcslen((const wchar_t*)source) : strlen(source); + #endif + if (pack) { + /* create a packed string */ + if (size=size*sizeof(cell)) + len=size*sizeof(cell)-1; + dest[len/sizeof(cell)]=0; /* clear last bytes of last (semi-filled) cell*/ + #if defined AMX_ANSIONLY + memcpy(dest,source,len); + #else + if (use_wchar) { + for (i=0; i<(int)len; i++) + ((char*)dest)[i]=(char)(((wchar_t*)source)[i]); + } else { + memcpy(dest,source,len); + } /* if */ + #endif + /* On Big Endian machines, the characters are well aligned in the + * cells; on Little Endian machines, we must swap all cells. + */ + assert(check_endian()); + #if BYTE_ORDER==LITTLE_ENDIAN + for (i=(int)(len/sizeof(cell)); i>=0; i--) + amx_SwapCell((ucell *)&dest[i]); + #endif + } else { + /* create an unpacked string */ + if (size=size) + len=size-1; + #if defined AMX_ANSIONLY + for (i=0; i<(int)len; i++) + dest[i]=(cell)source[i]; + #else + if (use_wchar) { + for (i=0; i<(int)len; i++) + dest[i]=(cell)(((wchar_t*)source)[i]); + } else { + for (i=0; i<(int)len; i++) + dest[i]=(cell)source[i]; + } /* if */ + #endif + dest[len]=0; + } /* if */ + return AMX_ERR_NONE; +} +#endif + +#if defined AMX_XXXSTRING +int AMXAPI amx_GetString(char *dest,const cell *source,int use_wchar,size_t size) +{ + int len=0; + #if defined AMX_ANSIONLY + (void)use_wchar; /* unused parameter (if ANSI only) */ + #endif + if ((ucell)*source>UNPACKEDMAX) { + /* source string is packed */ + cell c=0; /* initialize to 0 to avoid a compiler warning */ + int i=sizeof(cell)-1; + char ch; + while ((size_t)len> i*CHARBITS); + if (ch=='\0') + break; /* terminating zero character found */ + #if defined AMX_ANSIONLY + dest[len++]=ch; + #else + if (use_wchar) + ((wchar_t*)dest)[len++]=ch; + else + dest[len++]=ch; + #endif + i=(i+sizeof(cell)-1) % sizeof(cell); + } /* while */ + } else { + /* source string is unpacked */ + #if defined AMX_ANSIONLY + while (*source!=0 && (size_t)len=size) + len=(int)size-1; + if (len>=0) { + #if defined AMX_ANSIONLY + dest[len]='\0'; + #else + if (use_wchar) + ((wchar_t*)dest)[len]=0; + else + dest[len]='\0'; + #endif + } /* IF */ + return AMX_ERR_NONE; +} +#endif /* AMX_XXXSTRING */ + +#if defined AMX_UTF8XXX + #if defined __BORLANDC__ + #pragma warn -amb -8000 /* ambiguous operators need parentheses */ + #endif +/* amx_UTF8Get() + * Extract a single UTF-8 encoded character from a string and return a pointer + * to the character just behind that UTF-8 character. The parameters "endptr" + * and "value" may be NULL. + * If the code is not valid UTF-8, "endptr" has the value of the input + * parameter "string" and "value" is zero. + */ +int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value) +{ +static const char utf8_count[16]={ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4 }; +static const long utf8_lowmark[5] = { 0x80, 0x800, 0x10000L, 0x200000L, 0x4000000L }; + unsigned char c; + cell result; + int followup; + + assert(string!=NULL); + if (value!=NULL) /* preset, in case of an error */ + *value=0; + if (endptr!=NULL) + *endptr=string; + + c = *(const unsigned char*)string++; + if (c<0x80) { + /* ASCII */ + result=c; + } else { + if (c<0xc0 || c>=0xfe) + return AMX_ERR_PARAMS; /* invalid or "follower" code, quit with error */ + /* At this point we know that the two top bits of c are ones. The two + * bottom bits are always part of the code. We only need to consider + * the 4 remaining bits; i.e., a 16-byte table. This is "utf8_count[]". + * (Actually the utf8_count[] table records the number of follow-up + * bytes minus 1. This is just for convenience.) + */ + assert((c & 0xc0)==0xc0); + followup=(int)utf8_count[(c >> 2) & 0x0f]; + /* The mask depends on the code length; this is just a very simple + * relation. + */ + #define utf8_mask (0x1f >> followup) + result= c & utf8_mask; + /* Collect the follow-up codes using a drop-through switch statement; + * this avoids a loop. In each case, verify the two leading bits. + */ + assert(followup>=0 && followup<=4); + switch (followup) { + case 4: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + case 3: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + case 2: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + case 1: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + case 0: + if (((c=*string++) & 0xc0) != 0x80) goto error; + result = (result << 6) | c & 0x3f; + } /* switch */ + /* Do additional checks: shortest encoding & reserved positions. The + * lowmark limits also depends on the code length; it can be read from + * a table with 5 elements. This is "utf8_lowmark[]". + */ + if (result=0xd800 && result<=0xdfff || result==0xfffe || result==0xffff) + goto error; + } /* if */ + + if (value!=NULL) + *value=result; + if (endptr!=NULL) + *endptr=string; + + return AMX_ERR_NONE; + +error: + return AMX_ERR_PARAMS; +} + +/* amx_UTF8Put() + * Encode a single character into a byte string. The character may result in + * a string of up to 6 bytes. The function returns an error code if "maxchars" + * is lower than the required number of characters; in this case nothing is + * stored. + * The function does not zero-terminate the string. + */ +int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value) +{ + assert(string!=NULL); + if (endptr!=NULL) /* preset, in case of an error */ + *endptr=string; + + if (value<0x80) { + /* 0xxxxxxx */ + if (maxchars < 1) goto error; + *string++ = (char)value; + } else if (value<0x800) { + /* 110xxxxx 10xxxxxx */ + if (maxchars < 2) goto error; + *string++ = (char)((value>>6) & 0x1f | 0xc0); + *string++ = (char)(value & 0x3f | 0x80); + } else if (value<0x10000) { + /* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */ + if (maxchars < 3) goto error; + if (value>=0xd800 && value<=0xdfff || value==0xfffe || value==0xffff) + goto error; /* surrogate pairs and invalid characters */ + *string++ = (char)((value>>12) & 0x0f | 0xe0); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); + } else if (value<0x200000) { + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (maxchars < 4) goto error; + *string++ = (char)((value>>18) & 0x07 | 0xf0); + *string++ = (char)((value>>12) & 0x3f | 0x80); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); + } else if (value<0x4000000) { + /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (maxchars < 5) goto error; + *string++ = (char)((value>>24) & 0x03 | 0xf8); + *string++ = (char)((value>>18) & 0x3f | 0x80); + *string++ = (char)((value>>12) & 0x3f | 0x80); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); + } else { + /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */ + if (maxchars < 6) goto error; + *string++ = (char)((value>>30) & 0x01 | 0xfc); + *string++ = (char)((value>>24) & 0x3f | 0x80); + *string++ = (char)((value>>18) & 0x3f | 0x80); + *string++ = (char)((value>>12) & 0x3f | 0x80); + *string++ = (char)((value>>6) & 0x3f | 0x80); + *string++ = (char)(value & 0x3f | 0x80); + } /* if */ + + if (endptr!=NULL) + *endptr=string; + return AMX_ERR_NONE; + +error: + return AMX_ERR_PARAMS; +} + +/* amx_UTF8Check() + * Run through a zero-terminated string and check the validity of the UTF-8 + * encoding. The function returns an error code, it is AMX_ERR_NONE if the + * string is valid UTF-8 (or valid ASCII for that matter). + */ +int AMXAPI amx_UTF8Check(const char *string, int *length) +{ + int err=AMX_ERR_NONE; + int len=0; + while (err==AMX_ERR_NONE && *string!='\0') { + err=amx_UTF8Get(string,&string,NULL); + len++; + } /* while */ + if (length!=NULL) + *length=len; + return err; +} + +/* amx_UTF8Len() + * Run through a wide string and return how many 8-bit characters are needed to + * store the string in UTF-8 format. The returned cound excludes the terminating + * zero byte. The function returns an error code. + */ +int AMXAPI amx_UTF8Len(const cell *cstr, int *length) +{ + int err; + + assert(length!=NULL); + err=amx_StrLen(cstr, length); + if (err==AMX_ERR_NONE && (ucell)*cstr<=UNPACKEDMAX) { + char buffer[10]; /* maximum UTF-8 code is 6 characters */ + char *endptr; + int len=*length, count=0; + while (len-->0) { + amx_UTF8Put(buffer, &endptr, sizeof buffer, *cstr++); + count+=(int)(endptr-buffer); + } /* while */ + *length=count; + } /* while */ + return err; +} +#endif /* AMX_UTF8XXX */ diff --git a/src/pawn/amx.h b/src/pawn/amx.h new file mode 100644 index 0000000000..e4a633a873 --- /dev/null +++ b/src/pawn/amx.h @@ -0,0 +1,569 @@ +/* Pawn Abstract Machine (for the Pawn language) + * + * Copyright (c) CompuPhase, 1997-2023 + * + * 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 + * + * http://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. + * + * Version: $Id: amx.h 7491 2025-08-25 09:14:23Z thiadmer $ + */ + +#ifndef AMX_H_INCLUDED +#define AMX_H_INCLUDED + +#include /* for size_t */ +#include + +#if (defined __linux || defined __linux__) && !defined __LINUX__ + #define __LINUX__ +#endif +#if defined FREEBSD && !defined __FreeBSD__ + #define __FreeBSD__ +#endif +#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + #include +#endif + +#if defined __GNUC__ + #define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#endif + +#if !defined HAVE_STDINT_H + #if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) \ + || defined __cplusplus \ + || defined __GNUC__ || defined __LCC__ || defined __DMC__ \ + || (defined __WATCOMC__ && __WATCOMC__ >= 1200) + #define HAVE_STDINT_H 1 + #endif +#endif +#if !defined HAVE_INTTYPES_H + #if defined __FreeBSD__ || defined __APPLE__ + #define HAVE_INTTYPES_H 1 + #endif +#endif +#if defined HAVE_STDINT_H + #include +#elif defined HAVE_INTTYPES_H + #include +#else + #if defined __MACH__ + #include + #endif + typedef short int int16_t; + typedef unsigned short int uint16_t; + #if defined SN_TARGET_PS2 + typedef int int32_t; + typedef unsigned int uint32_t; + #else + typedef long int int32_t; + typedef unsigned long int uint32_t; + #endif + #if defined __WIN32__ || defined _WIN32 || defined WIN32 + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + #define HAVE_I64 + #endif + #if !defined _INTPTR_T_DEFINED + #if defined _LP64 || defined WIN64 || defined _WIN64 + typedef __int64 intptr_t; + #else + typedef int32_t intptr_t; + #endif + #endif +#endif +#if defined _LP64 || defined WIN64 || defined _WIN64 + #if !defined __64BIT__ + #define __64BIT__ + #endif +#endif +#if defined INTPTR_MAX + #if INTPTR_MAX == INT64_MAX + #if !defined __64BIT__ + #define __64BIT__ + #endif + #elif INTPTR_MAX == INT32_MAX + #if !defined __32BIT__ + #define __32BIT__ + #endif + #endif +#endif + +#if !defined HAVE_ALLOCA_H + #if defined __MINGW32__ + #define HAVE_ALLOCA_H 0 + #elif defined __FreeBSD__ + #undef HAVE_ALLOCA_H + #elif defined __GNUC__ || defined __LCC__ || defined __DMC__ || defined __ARMCC_VERSION + #define HAVE_ALLOCA_H 1 + #elif defined __WATCOMC__ && __WATCOMC__ >= 1200 + #define HAVE_ALLOCA_H 1 + #endif +#endif +#if defined HAVE_ALLOCA_H && HAVE_ALLOCA_H + #include +#elif defined __BORLANDC__ + #include +#endif +#if defined __WIN32__ || defined _WIN32 || defined WIN32 /* || defined __MSDOS__ */ + #if !defined alloca + #define alloca(n) _alloca(n) + #endif +#endif + +#if !defined assert_static + #if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112) || GCC_VERSION >= 40600 + #define assert_static(test) _Static_assert(test, "assert") + #else + /* see "Compile-Time Assertions" by Greg Miller, + * (with modifications to port it to C) + */ + #define _ASSERT_STATIC_SYMBOL_INNER(line) __ASSERT_STATIC_ ## line + #define _ASSERT_STATIC_SYMBOL(line) _ASSERT_STATIC_SYMBOL_INNER(line) + #define assert_static(test) \ + do { \ + typedef char _ASSERT_STATIC_SYMBOL(__LINE__)[ ((test) ? 1 : -1) ]; \ + } while (0) + #endif +#endif + +#if defined __cplusplus +extern "C" { +#endif + +#if defined PAWN_DLL + #if !defined AMX_NATIVE_CALL + #define AMX_NATIVE_CALL __stdcall + #endif + #if !defined AMXAPI + #define AMXAPI __stdcall + #endif + #if !defined AMXEXPORT + #define AMXEXPORT __declspec(dllexport) + #endif +#endif + +/* calling convention for native functions */ +#if !defined AMX_NATIVE_CALL + #define AMX_NATIVE_CALL +#endif +/* calling convention for all interface functions and callback functions */ +#if !defined AMXAPI + #if defined STDECL + #define AMXAPI __stdcall + #elif defined CDECL + #define AMXAPI __cdecl + #elif defined GCC_HASCLASSVISIBILITY && defined __cplusplus + #define AMXAPI __attribute__((visibility("default"))) + #else + #define AMXAPI + #endif +#endif +#if !defined AMXEXPORT + #define AMXEXPORT +#endif + +/* File format version (in CUR_FILE_VERSION) + * 0 original version + * 1 opcodes JUMP.pri, SWITCH and CASETBL + * 2 compressed files + * 3 public variables + * 4 opcodes SWAP.pri/alt and PUSHADDR + * 5 tagnames table + * 6 reformatted header + * 7 name table, opcodes SYMTAG & SYSREQ.D + * 8 opcode BREAK, renewed debug interface + * 9 macro opcodes + * 10 position-independent code, overlays, packed instructions + * 11 relocating instructions for the native interface, reorganized instruction set + * MIN_FILE_VERSION is the lowest file version number that the current AMX + * implementation supports. If the AMX file header gets new fields, this number + * often needs to be incremented. MIN_AMX_VERSION is the lowest AMX version that + * is needed to support the current file version. When there are new opcodes, + * this number needs to be incremented. + * The file version supported by the JIT may run behind MIN_AMX_VERSION. So + * there is an extra constant for it: MAX_FILE_VER_JIT. + */ +#define CUR_FILE_VERSION 11 /* current file version; also the current AMX version */ +#define MIN_FILE_VERSION 11 /* lowest supported file format version for the current AMX version */ +#define MIN_AMX_VERSION 11 /* minimum AMX version needed to support the current file format */ +#define MAX_FILE_VER_JIT 11 /* file version supported by the JIT */ +#define MIN_AMX_VER_JIT 11 /* AMX version supported by the JIT */ + +#if !defined PAWN_CELL_SIZE +# if __SIZEOF_POINTER__==8 + #define PAWN_CELL_SIZE 64 /* use 64-bit cells for 64-bit systems */ +# else + #define PAWN_CELL_SIZE 32 /* by default, use 32-bit cells */ +# endif +#endif +#if PAWN_CELL_SIZE==16 + typedef uint16_t ucell; + typedef int16_t cell; +#elif PAWN_CELL_SIZE==32 + typedef uint32_t ucell; + typedef int32_t cell; +#elif PAWN_CELL_SIZE==64 + typedef uint64_t ucell; + typedef int64_t cell; +#else + #error Unsupported cell size (PAWN_CELL_SIZE) +#endif + +#define UNPACKEDMAX (((cell)1 << (sizeof(cell)-1)*8) - 1) +#define UNLIMITED (~1u >> 1) + +struct tagAMX; +typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, const cell *params); +typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index, + cell *result, const cell *params); +typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx); +typedef int (AMXAPI *AMX_OVERLAY)(struct tagAMX *amx, int index); +typedef int (AMXAPI *AMX_IDLE)(struct tagAMX *amx, int AMXAPI Exec(struct tagAMX *, cell *, int)); +#if !defined _FAR + #define _FAR +#endif + +#if defined _MSC_VER + #pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */ + #pragma warning(disable:4103) /* disable warning message 4103 that complains about pragma pack in a header file */ + #pragma warning(disable:4127) /* "conditional expression is constant" (needed for static_assert) */ + #pragma warning(disable:4996) /* POSIX name is deprecated */ +#elif defined __GNUC__ + #pragma GCC diagnostic ignored "-Waddress-of-packed-member" +#elif defined __clang__ + #pragma GCC diagnostic ignored "-Wlogical-op-parentheses" + #pragma GCC diagnostic ignored "-Wbitwise-op-parentheses" + #pragma clang diagnostic ignored "-Wint-to-pointer-cast" +#endif + +/* Some compilers do not support the #pragma align, which should be fine. Some + * compilers give a warning on unknown #pragmas, which is not so fine... + */ +#if (defined SN_TARGET_PS2 || defined __GNUC__) && !defined AMX_NO_ALIGN + #define AMX_NO_ALIGN +#endif + +#if defined __GNUC__ + #define PACKED __attribute__((packed)) +#else + #define PACKED +#endif + +#if !defined AMX_NO_ALIGN + #if defined __LINUX__ || defined __FreeBSD__ || defined __APPLE__ + #pragma pack(1) /* structures must be packed (byte-aligned) */ + #elif defined MACOS && defined __MWERKS__ + #pragma options align=mac68k + #else + #pragma pack(push) + #pragma pack(1) /* structures must be packed (byte-aligned) */ + #if defined __BORLANDC__ + #pragma option -a- /* "pack" pragma for older Borland compilers */ + #endif + #endif +#endif + +typedef struct tagAMX_NATIVE_INFO { + const char _FAR *name; + AMX_NATIVE func; +} PACKED AMX_NATIVE_INFO; + +#if !defined AMX_USERNUM +#define AMX_USERNUM 4 +#endif +#define sEXPMAX 19 /* maximum name length for file version <= 6 */ +#define sNAMEMAX 31 /* maximum name length of symbol name */ + +typedef struct tagFUNCSTUB { + uint32_t address; + uint32_t nameofs; +} PACKED AMX_FUNCSTUB; + +typedef struct tagOVERLAYINFO { + int32_t offset; /* offset relative to the start of the code block */ + int32_t size; /* size in bytes */ +} PACKED AMX_OVERLAYINFO; + +/* The AMX structure is the internal structure for many functions. Not all + * fields are valid at all times; many fields are cached in local variables. + */ +typedef struct tagAMX { + unsigned char _FAR *base; /* points to the AMX header, perhaps followed by P-code and data */ + unsigned char _FAR *code; /* points to P-code block, possibly in ROM or in an overlay pool */ + unsigned char _FAR *data; /* points to separate data+stack+heap, may be NULL */ + AMX_CALLBACK callback; /* native function callback */ + AMX_DEBUG debug; /* debug callback */ + AMX_OVERLAY overlay; /* overlay reader callback */ + /* for external functions a few registers must be accessible from the outside */ + cell cip; /* instruction pointer: relative to base + amxhdr->cod */ + cell frm; /* stack frame base: relative to base + amxhdr->dat */ + cell hea; /* top of the heap: relative to base + amxhdr->dat */ + cell hlw; /* bottom of the heap: relative to base + amxhdr->dat */ + cell stk; /* stack pointer: relative to base + amxhdr->dat */ + cell stp; /* top of the stack: relative to base + amxhdr->dat */ + int flags; /* current status, see amx_Flags() */ + /* user data */ + #if AMX_USERNUM > 0 + long usertags[AMX_USERNUM]; + void _FAR *userdata[AMX_USERNUM]; + #endif + /* native functions can raise an error */ + int error; + /* passing parameters requires a "count" field */ + int paramcount; + /* the sleep opcode needs to store the full AMX status */ + cell pri; + cell alt; + cell reset_stk; + cell reset_hea; + /* extra fields for increased performance */ + cell sysreq_d; /* relocated address/value for the SYSREQ.D opcode */ + /* fields for overlay support and JIT support */ + int ovl_index; /* current overlay index */ + long codesize; /* size of the overlay, or estimated memory footprint of the native code */ + #if defined AMX_JIT + /* support variables for the JIT */ + int reloc_size; /* required temporary buffer for relocations */ + #endif +} PACKED AMX; + +/* The AMX_HEADER structure is both the memory format as the file format. The + * structure is used internaly. + */ +typedef struct tagAMX_HEADER { + int32_t size; /* size of the "file" */ + uint16_t magic; /* signature */ + char file_version; /* file format version */ + char amx_version; /* required version of the AMX */ + int16_t flags; + int16_t defsize; /* size of a definition record */ + int32_t cod; /* initial value of COD - code block */ + int32_t dat; /* initial value of DAT - data block */ + int32_t hea; /* initial value of HEA - start of the heap */ + int32_t stp; /* initial value of STP - stack top */ + int32_t cip; /* initial value of CIP - the instruction pointer */ + int32_t publics; /* offset to the "public functions" table */ + int32_t natives; /* offset to the "native functions" table */ + int32_t libraries; /* offset to the table of libraries */ + int32_t pubvars; /* offset to the "public variables" table */ + int32_t tags; /* offset to the "public tagnames" table */ + int32_t nametable; /* offset to the name table */ + int32_t overlays; /* offset to the overlay table */ +} PACKED AMX_HEADER; + +#define AMX_MAGIC_16 0xf1e2 +#define AMX_MAGIC_32 0xf1e0 +#define AMX_MAGIC_64 0xf1e1 +#if PAWN_CELL_SIZE==16 + #define AMX_MAGIC AMX_MAGIC_16 +#elif PAWN_CELL_SIZE==32 + #define AMX_MAGIC AMX_MAGIC_32 +#elif PAWN_CELL_SIZE==64 + #define AMX_MAGIC AMX_MAGIC_64 +#endif + +enum { + AMX_ERR_NONE, + /* reserve the first 15 error codes for exit codes of the abstract machine */ + AMX_ERR_EXIT, /* forced exit */ + AMX_ERR_ASSERT, /* assertion failed */ + AMX_ERR_STACKERR, /* stack/heap collision */ + AMX_ERR_BOUNDS, /* index out of bounds */ + AMX_ERR_MEMACCESS, /* invalid memory access */ + AMX_ERR_INVINSTR, /* invalid instruction */ + AMX_ERR_STACKLOW, /* stack underflow */ + AMX_ERR_HEAPLOW, /* heap underflow */ + AMX_ERR_CALLBACK, /* no callback, or invalid callback */ + AMX_ERR_NATIVE, /* native function failed */ + AMX_ERR_DIVIDE, /* divide by zero */ + AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */ + AMX_ERR_INVSTATE, /* no implementation for this state, no fall-back */ + + AMX_ERR_MEMORY = 16, /* out of memory */ + AMX_ERR_FORMAT, /* invalid file format */ + AMX_ERR_VERSION, /* file is for a newer version of the AMX */ + AMX_ERR_NOTFOUND, /* function not found */ + AMX_ERR_INDEX, /* invalid index parameter (bad entry point) */ + AMX_ERR_DEBUG, /* debugger cannot run */ + AMX_ERR_INIT, /* AMX not initialized (or doubly initialized) */ + AMX_ERR_USERDATA, /* unable to set user data field (table full) */ + AMX_ERR_INIT_JIT, /* cannot initialize the JIT */ + AMX_ERR_PARAMS, /* parameter error */ + AMX_ERR_DOMAIN, /* domain error, expression result does not fit in range */ + AMX_ERR_GENERAL, /* general error (unknown or unspecific error) */ + AMX_ERR_OVERLAY /* overlays are unsupported (JIT) or uninitialized */ +}; + +#define AMX_FLAG_OVERLAY 0x01 /* all function calls use overlays */ +#define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */ +#define AMX_FLAG_NOCHECKS 0x04 /* no array bounds checking; no BREAK opcodes */ +#define AMX_FLAG_SLEEP 0x08 /* script uses the sleep instruction (possible re-entry or power-down mode) */ +#define AMX_FLAG_CRYPT 0x10 /* file is encrypted */ +#define AMX_FLAG_DSEG_INIT 0x20 /* data section is explicitly initialized */ +#define AMX_FLAG_SYSREQN 0x800 /* script uses new (optimized) version of SYSREQ opcode */ +#define AMX_FLAG_NTVREG 0x1000 /* all native functions are registered */ +#define AMX_FLAG_JITC 0x2000 /* abstract machine is JIT compiled */ +#define AMX_FLAG_VERIFY 0x4000 /* busy verifying P-code */ +#define AMX_FLAG_INIT 0x8000 /* AMX has been initialized */ + +#define AMX_EXEC_MAIN (-1) /* start at program entry point */ +#define AMX_EXEC_CONT (-2) /* continue from last address */ + +#define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24)) + +/* for native functions that use floating point parameters, the following + * two macros are convenient for casting a "cell" into a "float" type _without_ + * changing the bit pattern + */ +#if PAWN_CELL_SIZE==32 + #define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */ + #define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */ +#elif PAWN_CELL_SIZE==64 + #define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */ + #define amx_ctof(c) ( * ((double*)&c) ) /* cell to float */ +#else + // amx_ftoc() and amx_ctof() cannot be used +#endif + +/* when a pointer cannot be stored in a cell, cells that hold relocated + * addresses need to be expanded + */ +#if defined __64BIT__ && PAWN_CELL_SIZE<64 + #define CELLMASK (((int64_t)1 << PAWN_CELL_SIZE) - 1) + #define amx_Address(amx,addr) \ + (cell*)(((int64_t)((amx)->data ? (amx)->data : (amx)->code) & ~CELLMASK) | ((int64_t)(addr) & CELLMASK)) +#elif defined __32BIT__ && PAWN_CELL_SIZE<32 + #define CELLMASK ((1L << PAWN_CELL_SIZE) - 1) + #define amx_Address(amx,addr) \ + (cell*)(((int32_t)((amx)->data ? (amx)->data : (amx)->code) & ~CELLMASK) | ((int32_t)(addr) & CELLMASK)) +#else + #define amx_Address(amx,addr) ((void)(amx),(cell*)(addr)) +#endif + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L + /* C99: use variable-length arrays */ + #define amx_StrParam_Type(amx,param,result,type) \ + int result##_length_; \ + amx_StrLen(amx_Address(amx,param),&result##_length_); \ + char result##_vla_[(result##_length_+1)*sizeof(*(result))]; \ + (result)=(type)result##_vla_; \ + amx_GetString((char*)(result),amx_Address(amx,param), \ + sizeof(*(result))>1,result##_length_+1) + #define amx_StrParam(amx,param,result) \ + amx_StrParam_Type(amx,param,result,void*) +#else + /* macro using alloca() */ + #define amx_StrParam_Type(amx,param,result,type) \ + do { \ + int result##_length_; \ + amx_StrLen(amx_Address(amx,param),&result##_length_); \ + if (result##_length_>0 && \ + ((result)=(type)alloca((result##_length_+1)*sizeof(*(result))))!=NULL) \ + amx_GetString((char*)(result),amx_Address(amx,param), \ + sizeof(*(result))>1,result##_length_+1); \ + else (result) = NULL; \ + } while (0) + #define amx_StrParam(amx,param,result) \ + amx_StrParam_Type(amx,param,result,void*) +#endif + +uint16_t * AMXAPI amx_Align16(uint16_t *v); +uint32_t * AMXAPI amx_Align32(uint32_t *v); +#if defined _I64_MAX || defined INT64_MAX || defined HAVE_I64 + uint64_t * AMXAPI amx_Align64(uint64_t *v); +#endif +int AMXAPI amx_Allot(AMX *amx, int cells, cell **address); +int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, const cell *params); +int AMXAPI amx_Cleanup(AMX *amx); +int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data); +int AMXAPI amx_Exec(AMX *amx, cell *retval, int index); +int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index); +int AMXAPI amx_FindPublic(AMX *amx, const char *name, int *index); +int AMXAPI amx_FindPubVar(AMX *amx, const char *name, cell **address); +int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname); +int AMXAPI amx_Flags(AMX *amx,uint16_t *flags); +int AMXAPI amx_GetNative(AMX *amx, int index, char *name); +int AMXAPI amx_GetPublic(AMX *amx, int index, char *name, ucell *address); +int AMXAPI amx_GetPubVar(AMX *amx, int index, char *name, cell **address); +int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar, size_t size); +int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id); +int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr); +int AMXAPI amx_Init(AMX *amx, void *program); +int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code); +int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap); +int AMXAPI amx_NameLength(AMX *amx, int *length); +AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func); +int AMXAPI amx_NumNatives(AMX *amx, int *number); +int AMXAPI amx_NumPublics(AMX *amx, int *number); +int AMXAPI amx_NumPubVars(AMX *amx, int *number); +int AMXAPI amx_NumTags(AMX *amx, int *number); +int AMXAPI amx_Push(AMX *amx, cell value); +int AMXAPI amx_PushAddress(AMX *amx, cell *address); +int AMXAPI amx_PushArray(AMX *amx, cell **address, const cell array[], int numcells); +int AMXAPI amx_PushString(AMX *amx, cell **address, const char *string, int pack, int use_wchar); +int AMXAPI amx_RaiseError(AMX *amx, int error); +int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number); +int AMXAPI amx_Release(AMX *amx, cell *address); +int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback); +int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug); +int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar, size_t size); +int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr); +int AMXAPI amx_StrLen(const cell *cstring, int *length); +int AMXAPI amx_UTF8Check(const char *string, int *length); +int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value); +int AMXAPI amx_UTF8Len(const cell *cstr, int *length); +int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value); +int AMXAPI amx_VerifyAddress(AMX *amx, cell *address); + +#if PAWN_CELL_SIZE==16 + void amx_Swap16(uint16_t *v); +#endif +#if PAWN_CELL_SIZE==32 + void amx_Swap32(uint32_t *v); +#endif +#if PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined INT64_MAX || defined HAVE_I64) + void amx_Swap64(uint64_t *v); +#endif + +#if PAWN_CELL_SIZE==16 + #define amx_AlignCell(v) amx_Align16((uint16_t*)(v)) + #define amx_SwapCell(v) amx_Swap16((uint16_t*)(v)) +#elif PAWN_CELL_SIZE==32 + #define amx_AlignCell(v) amx_Align32((uint32_t*)(v)) + #define amx_SwapCell(v) amx_Swap32((uint32_t*)(v)) +#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined INT64_MAX || defined HAVE_I64) + #define amx_AlignCell(v) amx_Align64((uint64_t*)(v)) + #define amx_SwapCell(v) amx_Swap64((uint64_t*)(v)) +#else + #error Unsupported cell size +#endif + +#define amx_RegisterFunc(amx, name, func) \ + amx_Register((amx), amx_NativeInfo((name),(func)), 1); + +#if !defined AMX_NO_ALIGN + #if defined __LINUX__ || defined __FreeBSD__ || defined __APPLE__ + #pragma pack() /* reset default packing */ + #elif defined MACOS && defined __MWERKS__ + #pragma options align=reset + #else + #pragma pack(pop) /* reset previous packing */ + #endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* AMX_H_INCLUDED */ diff --git a/src/pawn/osdefs.h b/src/pawn/osdefs.h new file mode 100644 index 0000000000..72b4d89dc9 --- /dev/null +++ b/src/pawn/osdefs.h @@ -0,0 +1,159 @@ +/* + * Platform + * __MSDOS__ set when compiling for DOS (not Windows) + * _Windows set when compiling for any version of Microsoft Windows + * __WIN32__ set when compiling for Windows95 or WindowsNT (32 bit mode) + * __32BIT__ set when compiling in 32-bit "flat" mode (DOS, Windows, ARM) + * __64BIT__ set when compiling in 64-bit mode + * __ECOS__ set if Pawn was included with the eCos with configtool + * __LINUX__ set when compiling for Linux + * + * Copyright 1998-2020, CompuPhase, The Netherlands. + * No usage restrictions, no warranties. + */ + +#ifndef _OSDEFS_H +#define _OSDEFS_H + +/* Every compiler uses different "default" macros to indicate the mode + * it is in. Throughout the source, we use the Borland C++ macros, so + * the macros of Watcom C/C++ and Microsoft Visual C/C++ are mapped to + * those of Borland C++. + */ +#if defined(__WATCOMC__) + #if defined(__WINDOWS__) || defined(__NT__) + #define _Windows 1 + #endif + #if defined(__386__) || defined(__NT__) + #define __32BIT__ 1 + #endif + #if defined(_Windows) && defined(__32BIT__) + #define __WIN32__ 1 + #endif +#elif defined(_MSC_VER) + #if defined(_WINDOWS) || defined(_WIN32) + #define _Windows 1 + #endif + #if defined(_WIN32) + #define __WIN32__ 1 + #define __32BIT__ 1 + #endif +#elif defined __arm__ + #define __32BIT__ 1 +#elif defined __AVR__ + #define __16BIT__ 1 +#endif +#if !defined __16BIT__ && !defined __32BIT__ && !defined __64BIT__ + #define __32BIT__ 1 +#endif + + +#if (defined __linux || defined __linux__) && !defined __LINUX__ + #define __LINUX__ +#endif +/* To be able to eventually set __ECOS__, we have to find a symbol + * defined in a common place (so including the header file won't break + * anything for other platforms). includes + * and in this later file we can find CYGPKG_PAWN + * if the Pawn package was included with configtool and so we know + * that we are compiling for eCos. + */ +#if defined CCSINFO + #include +#endif +#if defined CYGPKG_PAWN + #define __ECOS__ 1 + #define HAVE_ALLOCA_H 0 +#endif + + +#if defined __FreeBSD__ + #include +#elif defined __LINUX__ + #include +#elif defined __ECOS__ + #include + #define BIG_ENDIAN 4321 + #define LITTLE_ENDIAN 1234 + #if (CYG_BYTEORDER == CYG_LSBFIRST) + #define BYTE_ORDER LITTLE_ENDIAN + #else + #define BYTE_ORDER BIG_ENDIAN + #endif + /* + * eCos option management. + */ + #include + #if defined CYGPKG_PAWN_AMX_ANSIONLY && CYGPKG_PAWN_AMX_ANSIONLY==1 + #define AMX_ANSIONLY + #endif + #define PAWN_CELL_SIZE CYGPKG_PAWN_AMX_CELLSIZE + #if defined CYGPKG_PAWN_CORE_RANDOM && CYGPKG_PAWN_CORE_RANDOM==0 + #define AMX_NORANDOM + #endif + #if defined CYGPKG_PAWN_CORE_PROPERTY && CYGPKG_PAWN_CORE_PROPERTY==0 + #define AMX_NOPROPLIST + #endif + #if defined CYGPKG_PAWN_AMX_CONS_FIXEDPOINT && CYGPKG_PAWN_AMX_CONS_FIXEDPOINT==1 + #define FIXEDPOINT + #endif + #if defined CYGPKG_PAWN_AMX_CONS_FLOATPOINT && CYGPKG_PAWN_AMX_CONS_FLOATPOINT==1 + #define FLOATPOINT + #endif +#endif + +/* Linux now has these */ +#if !defined BIG_ENDIAN + #define BIG_ENDIAN 4321 +#endif +#if !defined LITTLE_ENDIAN + #define LITTLE_ENDIAN 1234 +#endif + +/* educated guess, BYTE_ORDER is undefined, i386 is common => little endian */ +#if !defined BYTE_ORDER + #if defined UCLINUX + #define BYTE_ORDER BIG_ENDIAN + #else + #define BYTE_ORDER LITTLE_ENDIAN + #endif +#endif + +#if defined __MSDOS__ || defined __WIN32__ || defined _Windows + #define DIRSEP_CHAR '\\' +#elif defined macintosh /* only the original Macintosh uses ':', OSX uses the '/' */ + #define DIRSEP_CHAR ':' +#else + #define DIRSEP_CHAR '/' +#endif + +/* _MAX_PATH is sometimes called differently and it may be in limits.h or + * stdlib.h instead of stdio.h. + */ +#if !defined _MAX_PATH + /* not defined, perhaps stdio.h was not included */ + #if !defined PATH_MAX + #include + #endif + #if !defined _MAX_PATH && !defined PATH_MAX + /* no _MAX_PATH and no MAX_PATH, perhaps it is in limits.h */ + #include + #endif + #if !defined _MAX_PATH && !defined PATH_MAX + /* no _MAX_PATH and no MAX_PATH, perhaps it is in stdlib.h */ + #include + #endif + /* if _MAX_PATH is undefined, try common alternative names */ + #if !defined _MAX_PATH + #if defined MAX_PATH + #define _MAX_PATH MAX_PATH + #elif defined _POSIX_PATH_MAX + #define _MAX_PATH _POSIX_PATH_MAX + #else + /* everything failed, actually we have a problem here... */ + #define _MAX_PATH 1024 + #endif + #endif +#endif + +#endif /* _OSDEFS_H */ From 1f666e59525b52c795294843b3ca61c71710cbcf Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 28 Dec 2025 15:46:17 +0100 Subject: [PATCH 02/26] Add support for event handlers --- src/displayapp/screens/Pawn.cpp | 116 ++++++++++++++++++------- src/displayapp/screens/program.h | 142 ++++++++++++++++++++----------- 2 files changed, 176 insertions(+), 82 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 4b615ee5f4..d935429ac4 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -5,15 +5,48 @@ using namespace Pinetime::Applications::Screens; #include "program.h" -static cell AMX_NATIVE_CALL F_lv_label_create(AMX*, const cell*) { - lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); +static void event_handler(lv_obj_t* obj, lv_event_t event) { + AMX* amx = (AMX*) lv_obj_get_user_data(lv_scr_act()); + int handler_index = (int) lv_obj_get_user_data(obj); - return (cell) label; + amx_Push(amx, event); + amx_Exec(amx, nullptr, handler_index); +} + +static cell AMX_NATIVE_CALL F_lv_scr_act(AMX*, const cell*) { + return (cell) lv_scr_act(); +} + +static cell AMX_NATIVE_CALL F_lv_label_create(AMX*, const cell* params) { + return (cell) lv_label_create((lv_obj_t*) params[1] ?: lv_scr_act(), (lv_obj_t*) params[2]); +} + +static cell AMX_NATIVE_CALL F_lv_btn_create(AMX*, const cell* params) { + return (cell) lv_btn_create((lv_obj_t*) params[1] ?: lv_scr_act(), (lv_obj_t*) params[2]); } static cell AMX_NATIVE_CALL F_lv_obj_set_pos(AMX*, const cell* params) { - lv_obj_t* label = (lv_obj_t*) params[1]; - lv_obj_set_pos(label, params[2], params[3]); + lv_obj_set_pos((lv_obj_t*) params[1], params[2], params[3]); + return 0; +} + +static cell AMX_NATIVE_CALL F_lv_obj_set_size(AMX*, const cell* params) { + lv_obj_set_size((lv_obj_t*) params[1], params[2], params[3]); + return 0; +} + +static cell AMX_NATIVE_CALL F_lv_obj_set_event_cb(AMX* amx, const cell* params) { + lv_obj_t* obj = (lv_obj_t*) params[1]; + + char* name; + amx_StrParam_Type(amx, params[2], name, char*); + if (name != NULL) { + int index; + if (amx_FindPublic(amx, name, &index) == AMX_ERR_NONE) { + lv_obj_set_user_data(obj, (void*) index); + lv_obj_set_event_cb(obj, event_handler); + } + } return 0; } @@ -35,12 +68,12 @@ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { // param[0] is the number of total parameter bytes, divide it by cell size and subtract 3 to account for the fixed parameters int args_count = params[0] / sizeof(cell) - 3; - cell *output = amx_Address(amx, params[1]); - cell output_size = params[2]; + cell* output = amx_Address(amx, params[1]); + cell output_size = params[2] * sizeof(cell); // We assume the output array is packed, TODO: add a separate sprintf_unpacked function? char buf[output_size]; - char *fmt; + char* fmt; amx_StrParam_Type(amx, params[3], fmt, char*); if (fmt == NULL) return 0; @@ -48,29 +81,41 @@ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { cell ret = 0; #pragma GCC diagnostic ignored "-Wformat-nonliteral" - switch (args_count) - { - case 0: - strcpy(buf, fmt); - ret = strlen(fmt) + 1; - break; - case 1: - ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4])); - break; - case 2: - ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5])); - break; - case 3: - ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5]), *amx_Address(amx, params[6])); - break; - case 4: - ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5]), *amx_Address(amx, params[6]), *amx_Address(amx, params[7])); - break; - case 5: - ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5]), *amx_Address(amx, params[6]), *amx_Address(amx, params[7]), *amx_Address(amx, params[8])); - break; - default: - return 0; + switch (args_count) { + case 0: + strcpy(buf, fmt); + ret = strlen(fmt) + 1; + break; + case 1: + ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4])); + break; + case 2: + ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5])); + break; + case 3: + ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5]), *amx_Address(amx, params[6])); + break; + case 4: + ret = snprintf(buf, + output_size, + fmt, + *amx_Address(amx, params[4]), + *amx_Address(amx, params[5]), + *amx_Address(amx, params[6]), + *amx_Address(amx, params[7])); + break; + case 5: + ret = snprintf(buf, + output_size, + fmt, + *amx_Address(amx, params[4]), + *amx_Address(amx, params[5]), + *amx_Address(amx, params[6]), + *amx_Address(amx, params[7]), + *amx_Address(amx, params[8])); + break; + default: + return 0; } #pragma GCC diagnostic warning "-Wformat-nonliteral" @@ -88,19 +133,24 @@ Pawn::Pawn() { amx.userdata[0] = this; + lv_obj_set_user_data(lv_scr_act(), &amx); + static AMX_NATIVE_INFO natives[] = { {"sprintf", F_sprintf}, + {"lv_scr_act", F_lv_scr_act}, {"lv_label_create", F_lv_label_create}, + {"lv_btn_create", F_lv_btn_create}, {"lv_obj_set_pos", F_lv_obj_set_pos}, + {"lv_obj_set_size", F_lv_obj_set_size}, {"lv_label_set_text", F_lv_label_set_text}, + {"lv_obj_set_event_cb", F_lv_obj_set_event_cb}, {0, 0} /* terminator */ }; amx_Register(&amx, natives, -1); amx_Exec(&amx, NULL, AMX_EXEC_MAIN); - if (amx_FindPublic(&amx, "@refresh", &refresh_index) == AMX_ERR_NONE) - { + if (amx_FindPublic(&amx, "@refresh", &refresh_index) == AMX_ERR_NONE) { taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); Refresh(); } diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index 9ee24c7a06..ca507c3e2b 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,57 +1,101 @@ unsigned char program[] = { - 0x84, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x08, 0x00, - 0xa8, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, - 0x84, 0x42, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x96, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, - 0x73, 0x68, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, + 0x90, 0x04, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x08, 0x00, + 0xf4, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x00, 0x90, 0x04, 0x00, 0x00, + 0x90, 0x44, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x64, 0x02, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x63, 0x6c, 0x69, 0x63, 0x6b, + 0x65, 0x64, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, - 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x00, 0x73, 0x70, - 0x72, 0x69, 0x6e, 0x74, 0x66, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x00, 0x6c, 0x76, + 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x74, + 0x65, 0x78, 0x74, 0x00, 0x6c, 0x76, 0x5f, 0x62, 0x74, 0x6e, 0x5f, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, + 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x6c, 0x76, + 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x5f, 0x63, 0x62, 0x00, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x66, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0xfc, 0xff, 0xff, 0xff, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x65, 0x6d, 0x69, 0x54, 0x61, 0x6c, 0x65, 0x20, 0x64, 0x65, 0x73, 0x70, - 0x6c, 0x25, 0x20, 0x3a, 0x00, 0x00, 0x00, 0x64 + 0x63, 0x69, 0x6c, 0x43, 0x20, 0x3a, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x30, + 0x69, 0x6c, 0x63, 0x40, 0x64, 0x65, 0x6b, 0x63, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x69, 0x6c, 0x43, 0x68, 0x74, 0x20, 0x6b, 0x00, 0x21, 0x73, 0x69, + 0x01, 0x00, 0x00, 0x00, 0x63, 0x69, 0x6c, 0x43, 0x20, 0x3a, 0x73, 0x6b, + 0x00, 0x64, 0x6c, 0x25 }; -unsigned int program_len = 644; +unsigned int program_len = 1168; From f52443ff3bde0dfa26a9749a883a1ee9e3d9ae07 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 28 Dec 2025 16:32:24 +0100 Subject: [PATCH 03/26] Move program data array to function This is just to remove the erroneous data segment size change, there's no functional change --- src/displayapp/screens/Pawn.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index d935429ac4..255f5ae7ce 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -3,8 +3,6 @@ using namespace Pinetime::Applications::Screens; -#include "program.h" - static void event_handler(lv_obj_t* obj, lv_event_t event) { AMX* amx = (AMX*) lv_obj_get_user_data(lv_scr_act()); int handler_index = (int) lv_obj_get_user_data(obj); @@ -125,6 +123,8 @@ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { } Pawn::Pawn() { +#include "program.h" + uint8_t* prog = new uint8_t[program_len]; memcpy(prog, program, program_len); From ee46e43a94014e7602589c0ebc739c20c451fc9c Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 28 Dec 2025 17:49:25 +0100 Subject: [PATCH 04/26] Assert parameter count; set style properties --- src/displayapp/screens/Pawn.cpp | 74 ++++++++++++++- src/displayapp/screens/program.h | 154 ++++++++++++++++--------------- 2 files changed, 151 insertions(+), 77 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 255f5ae7ce..daa6456871 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -3,6 +3,14 @@ using namespace Pinetime::Applications::Screens; +#define AMX_ERR_PARAMCOUNT 32 + +#define ASSERT_PARAMS(n) \ + if (params[0] != n * sizeof(cell)) { \ + amx_RaiseError(amx, AMX_ERR_PARAMCOUNT); \ + return 0; \ + } + static void event_handler(lv_obj_t* obj, lv_event_t event) { AMX* amx = (AMX*) lv_obj_get_user_data(lv_scr_act()); int handler_index = (int) lv_obj_get_user_data(obj); @@ -11,29 +19,41 @@ static void event_handler(lv_obj_t* obj, lv_event_t event) { amx_Exec(amx, nullptr, handler_index); } -static cell AMX_NATIVE_CALL F_lv_scr_act(AMX*, const cell*) { +static cell AMX_NATIVE_CALL F_lv_scr_act(AMX* amx, const cell* params) { + ASSERT_PARAMS(0); + return (cell) lv_scr_act(); } -static cell AMX_NATIVE_CALL F_lv_label_create(AMX*, const cell* params) { +static cell AMX_NATIVE_CALL F_lv_label_create(AMX* amx, const cell* params) { + ASSERT_PARAMS(2); + return (cell) lv_label_create((lv_obj_t*) params[1] ?: lv_scr_act(), (lv_obj_t*) params[2]); } -static cell AMX_NATIVE_CALL F_lv_btn_create(AMX*, const cell* params) { +static cell AMX_NATIVE_CALL F_lv_btn_create(AMX* amx, const cell* params) { + ASSERT_PARAMS(2); + return (cell) lv_btn_create((lv_obj_t*) params[1] ?: lv_scr_act(), (lv_obj_t*) params[2]); } -static cell AMX_NATIVE_CALL F_lv_obj_set_pos(AMX*, const cell* params) { +static cell AMX_NATIVE_CALL F_lv_obj_set_pos(AMX* amx, const cell* params) { + ASSERT_PARAMS(3); + lv_obj_set_pos((lv_obj_t*) params[1], params[2], params[3]); return 0; } -static cell AMX_NATIVE_CALL F_lv_obj_set_size(AMX*, const cell* params) { +static cell AMX_NATIVE_CALL F_lv_obj_set_size(AMX* amx, const cell* params) { + ASSERT_PARAMS(3); + lv_obj_set_size((lv_obj_t*) params[1], params[2], params[3]); return 0; } static cell AMX_NATIVE_CALL F_lv_obj_set_event_cb(AMX* amx, const cell* params) { + ASSERT_PARAMS(2); + lv_obj_t* obj = (lv_obj_t*) params[1]; char* name; @@ -50,6 +70,8 @@ static cell AMX_NATIVE_CALL F_lv_obj_set_event_cb(AMX* amx, const cell* params) } static cell AMX_NATIVE_CALL F_lv_label_set_text(AMX* amx, const cell* params) { + ASSERT_PARAMS(2); + lv_obj_t* label = (lv_obj_t*) params[1]; char* text; @@ -62,6 +84,45 @@ static cell AMX_NATIVE_CALL F_lv_label_set_text(AMX* amx, const cell* params) { return 0; } +static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_int(AMX* amx, const cell* params) { + ASSERT_PARAMS(5); + + lv_obj_t* obj = (lv_obj_t*) params[1]; + cell prop = params[2]; + cell value = params[3]; + cell part = params[4]; + cell state = params[5]; + + _lv_obj_set_style_local_int(obj, part, prop | (state << LV_STYLE_STATE_POS), value); + return 0; +} + +static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_color(AMX* amx, const cell* params) { + ASSERT_PARAMS(5); + + lv_obj_t* obj = (lv_obj_t*) params[1]; + cell prop = params[2]; + cell value = params[3]; + cell part = params[4]; + cell state = params[5]; + + _lv_obj_set_style_local_color(obj, part, prop | (state << LV_STYLE_STATE_POS), lv_color_hex(value)); + return 0; +} + +static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_opa(AMX* amx, const cell* params) { + ASSERT_PARAMS(5); + + lv_obj_t* obj = (lv_obj_t*) params[1]; + cell prop = params[2]; + cell value = params[3]; + cell part = params[4]; + cell state = params[5]; + + _lv_obj_set_style_local_opa(obj, part, prop | (state << LV_STYLE_STATE_POS), value); + return 0; +} + static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { // param[0] is the number of total parameter bytes, divide it by cell size and subtract 3 to account for the fixed parameters int args_count = params[0] / sizeof(cell) - 3; @@ -144,6 +205,9 @@ Pawn::Pawn() { {"lv_obj_set_size", F_lv_obj_set_size}, {"lv_label_set_text", F_lv_label_set_text}, {"lv_obj_set_event_cb", F_lv_obj_set_event_cb}, + {"lv_obj_set_style_local_int", F_lv_obj_set_style_local_int}, + {"lv_obj_set_style_local_color", F_lv_obj_set_style_local_color}, + {"lv_obj_set_style_local_opa", F_lv_obj_set_style_local_opa}, {0, 0} /* terminator */ }; amx_Register(&amx, natives, -1); diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index ca507c3e2b..2523c20ed0 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,25 +1,28 @@ unsigned char program[] = { - 0x90, 0x04, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x08, 0x00, - 0xf4, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x00, 0x90, 0x04, 0x00, 0x00, - 0x90, 0x44, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, - 0x64, 0x02, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x63, 0x6c, 0x69, 0x63, 0x6b, - 0x65, 0x64, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, + 0x10, 0x05, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x08, 0x00, + 0x18, 0x01, 0x00, 0x00, 0xbc, 0x04, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, + 0x10, 0x45, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, + 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, + 0xc0, 0x02, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, + 0x1f, 0x00, 0x40, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x00, 0x6c, + 0x76, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, + 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, + 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x73, + 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x6c, 0x76, 0x5f, 0x62, 0x74, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, - 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x00, 0x6c, 0x76, - 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x74, - 0x65, 0x78, 0x74, 0x00, 0x6c, 0x76, 0x5f, 0x62, 0x74, 0x6e, 0x5f, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, - 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x6c, 0x76, - 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x5f, 0x63, 0x62, 0x00, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x74, - 0x66, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x6c, + 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x62, 0x00, 0x73, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x66, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, @@ -36,66 +39,73 @@ unsigned char program[] = { 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x63, 0x69, 0x6c, 0x43, 0x20, 0x3a, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x30, - 0x69, 0x6c, 0x63, 0x40, 0x64, 0x65, 0x6b, 0x63, 0x00, 0x00, 0x00, 0x00, - 0x63, 0x69, 0x6c, 0x43, 0x68, 0x74, 0x20, 0x6b, 0x00, 0x21, 0x73, 0x69, - 0x01, 0x00, 0x00, 0x00, 0x63, 0x69, 0x6c, 0x43, 0x20, 0x3a, 0x73, 0x6b, - 0x00, 0x64, 0x6c, 0x25 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x69, 0x6c, 0x43, + 0x20, 0x3a, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x30, 0x69, 0x6c, 0x63, 0x40, + 0x64, 0x65, 0x6b, 0x63, 0x00, 0x00, 0x00, 0x00, 0x63, 0x69, 0x6c, 0x43, + 0x68, 0x74, 0x20, 0x6b, 0x00, 0x21, 0x73, 0x69, 0x01, 0x00, 0x00, 0x00, + 0x63, 0x69, 0x6c, 0x43, 0x20, 0x3a, 0x73, 0x6b, 0x00, 0x64, 0x6c, 0x25 }; -unsigned int program_len = 1168; +unsigned int program_len = 1296; From 70e3ec12c7076af7cec644e5d5f4daa6f94b7216 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 28 Dec 2025 18:22:07 +0100 Subject: [PATCH 05/26] Fix task cleanup --- src/displayapp/screens/Pawn.cpp | 4 +++- src/displayapp/screens/Pawn.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index daa6456871..6029d422e0 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -221,7 +221,9 @@ Pawn::Pawn() { } Pawn::~Pawn() { - lv_task_del(taskRefresh); + if (taskRefresh) + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); amx_Cleanup(&amx); diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index 3e1410fdaf..99d7e98e03 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -21,7 +21,7 @@ namespace Pinetime { AMX amx; int refresh_index; - lv_task_t* taskRefresh; + lv_task_t* taskRefresh = 0; }; } From da76720673d8fc4b07cceae5f971d3644308900b Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 28 Dec 2025 19:14:05 +0100 Subject: [PATCH 06/26] Set fonts and alignment --- src/displayapp/screens/Pawn.cpp | 54 +++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 6029d422e0..211edcbbe3 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -11,6 +11,8 @@ using namespace Pinetime::Applications::Screens; return 0; \ } +#define PARAMS_OBJ(i) ((lv_obj_t*) params[i]) + static void event_handler(lv_obj_t* obj, lv_event_t event) { AMX* amx = (AMX*) lv_obj_get_user_data(lv_scr_act()); int handler_index = (int) lv_obj_get_user_data(obj); @@ -28,33 +30,33 @@ static cell AMX_NATIVE_CALL F_lv_scr_act(AMX* amx, const cell* params) { static cell AMX_NATIVE_CALL F_lv_label_create(AMX* amx, const cell* params) { ASSERT_PARAMS(2); - return (cell) lv_label_create((lv_obj_t*) params[1] ?: lv_scr_act(), (lv_obj_t*) params[2]); + return (cell) lv_label_create(PARAMS_OBJ(1) ?: lv_scr_act(), PARAMS_OBJ(2)); } static cell AMX_NATIVE_CALL F_lv_btn_create(AMX* amx, const cell* params) { ASSERT_PARAMS(2); - return (cell) lv_btn_create((lv_obj_t*) params[1] ?: lv_scr_act(), (lv_obj_t*) params[2]); + return (cell) lv_btn_create(PARAMS_OBJ(1) ?: lv_scr_act(), PARAMS_OBJ(2)); } static cell AMX_NATIVE_CALL F_lv_obj_set_pos(AMX* amx, const cell* params) { ASSERT_PARAMS(3); - lv_obj_set_pos((lv_obj_t*) params[1], params[2], params[3]); + lv_obj_set_pos(PARAMS_OBJ(1), params[2], params[3]); return 0; } static cell AMX_NATIVE_CALL F_lv_obj_set_size(AMX* amx, const cell* params) { ASSERT_PARAMS(3); - lv_obj_set_size((lv_obj_t*) params[1], params[2], params[3]); + lv_obj_set_size(PARAMS_OBJ(1), params[2], params[3]); return 0; } static cell AMX_NATIVE_CALL F_lv_obj_set_event_cb(AMX* amx, const cell* params) { ASSERT_PARAMS(2); - lv_obj_t* obj = (lv_obj_t*) params[1]; + lv_obj_t* obj = PARAMS_OBJ(1); char* name; amx_StrParam_Type(amx, params[2], name, char*); @@ -72,7 +74,7 @@ static cell AMX_NATIVE_CALL F_lv_obj_set_event_cb(AMX* amx, const cell* params) static cell AMX_NATIVE_CALL F_lv_label_set_text(AMX* amx, const cell* params) { ASSERT_PARAMS(2); - lv_obj_t* label = (lv_obj_t*) params[1]; + lv_obj_t* label = PARAMS_OBJ(1); char* text; amx_StrParam_Type(amx, params[2], text, char*); @@ -87,7 +89,7 @@ static cell AMX_NATIVE_CALL F_lv_label_set_text(AMX* amx, const cell* params) { static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_int(AMX* amx, const cell* params) { ASSERT_PARAMS(5); - lv_obj_t* obj = (lv_obj_t*) params[1]; + lv_obj_t* obj = PARAMS_OBJ(1); cell prop = params[2]; cell value = params[3]; cell part = params[4]; @@ -100,7 +102,7 @@ static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_int(AMX* amx, const cell* p static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_color(AMX* amx, const cell* params) { ASSERT_PARAMS(5); - lv_obj_t* obj = (lv_obj_t*) params[1]; + lv_obj_t* obj = PARAMS_OBJ(1); cell prop = params[2]; cell value = params[3]; cell part = params[4]; @@ -113,7 +115,7 @@ static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_color(AMX* amx, const cell* static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_opa(AMX* amx, const cell* params) { ASSERT_PARAMS(5); - lv_obj_t* obj = (lv_obj_t*) params[1]; + lv_obj_t* obj = PARAMS_OBJ(1); cell prop = params[2]; cell value = params[3]; cell part = params[4]; @@ -123,6 +125,32 @@ static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_opa(AMX* amx, const cell* p return 0; } +static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_ptr(AMX* amx, const cell* params) { + ASSERT_PARAMS(5); + + lv_obj_t* obj = PARAMS_OBJ(1); + cell prop = params[2]; + cell* value = amx_Address(amx, params[3]); + cell part = params[4]; + cell state = params[5]; + + _lv_obj_set_style_local_ptr(obj, part, prop | (state << LV_STYLE_STATE_POS), (void*) value); + return 0; +} + +static cell AMX_NATIVE_CALL F_lv_obj_align(AMX* amx, const cell* params) { + ASSERT_PARAMS(5) + + lv_obj_t* obj = PARAMS_OBJ(1); + lv_obj_t* base = PARAMS_OBJ(2); + cell align = params[3]; + cell x_ofs = params[4]; + cell y_ofs = params[5]; + + lv_obj_align(obj, base, align, x_ofs, y_ofs); + return 0; +} + static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { // param[0] is the number of total parameter bytes, divide it by cell size and subtract 3 to account for the fixed parameters int args_count = params[0] / sizeof(cell) - 3; @@ -196,7 +224,11 @@ Pawn::Pawn() { lv_obj_set_user_data(lv_scr_act(), &amx); - static AMX_NATIVE_INFO natives[] = { + cell* font; + if (amx_FindPubVar(&amx, "font_jmec", &font) == AMX_ERR_NONE) + *font = (cell) &jetbrains_mono_extrabold_compressed; + + const AMX_NATIVE_INFO natives[] = { {"sprintf", F_sprintf}, {"lv_scr_act", F_lv_scr_act}, {"lv_label_create", F_lv_label_create}, @@ -208,6 +240,8 @@ Pawn::Pawn() { {"lv_obj_set_style_local_int", F_lv_obj_set_style_local_int}, {"lv_obj_set_style_local_color", F_lv_obj_set_style_local_color}, {"lv_obj_set_style_local_opa", F_lv_obj_set_style_local_opa}, + {"lv_obj_set_style_local_ptr", F_lv_obj_set_style_local_ptr}, + {"lv_obj_align", F_lv_obj_align}, {0, 0} /* terminator */ }; amx_Register(&amx, natives, -1); From 2bf5a2db7ea0f536179728f1ca17fd11475cd418 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 28 Dec 2025 20:10:03 +0100 Subject: [PATCH 07/26] Proper program loading --- src/displayapp/screens/Pawn.cpp | 36 ++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 211edcbbe3..a0ba5ce481 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -211,14 +211,36 @@ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { return ret; } -Pawn::Pawn() { -#include "program.h" - uint8_t* prog = new uint8_t[program_len]; - memcpy(prog, program, program_len); +static int load_program(AMX* amx, const uint8_t* data) { + AMX_HEADER hdr; + memcpy(&hdr, data, sizeof(hdr)); + + if (hdr.magic != AMX_MAGIC) + return AMX_ERR_FORMAT; + + void* memblock = malloc(hdr.stp); + if (memblock == NULL) + return AMX_ERR_MEMORY; + + memcpy(memblock, data, hdr.size); + + memset(amx, 0, sizeof(*amx)); + + int result = amx_Init(amx, memblock); + if (result != AMX_ERR_NONE) { + free(memblock); + amx->base = NULL; + } + + return result; +} + +Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { +#include "program.h" - memset(&amx, 0, sizeof(amx)); - amx_Init(&amx, prog); + load_program(&amx, program); + (void) program_len; amx.userdata[0] = this; @@ -261,7 +283,7 @@ Pawn::~Pawn() { lv_obj_clean(lv_scr_act()); amx_Cleanup(&amx); - delete amx.base; + free(amx.base); } void Pawn::Refresh() { From 59b222c2d35273e93eb70c8a0d4c84b2805caf43 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 02:28:20 +0100 Subject: [PATCH 08/26] Add sprintf implementation and watchface stuff --- src/displayapp/screens/Pawn.cpp | 186 +++++++++++++++------ src/displayapp/screens/Pawn.h | 14 +- src/displayapp/screens/program.h | 273 ++++++++++++++++++++----------- 3 files changed, 327 insertions(+), 146 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index a0ba5ce481..a8db43fdd8 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -1,5 +1,6 @@ #include "Pawn.h" #include +#include using namespace Pinetime::Applications::Screens; @@ -81,7 +82,7 @@ static cell AMX_NATIVE_CALL F_lv_label_set_text(AMX* amx, const cell* params) { if (text != NULL) lv_label_set_text(label, text); else - lv_label_set_text(label, ""); + lv_label_set_text_static(label, ""); return 0; } @@ -151,66 +152,154 @@ static cell AMX_NATIVE_CALL F_lv_obj_align(AMX* amx, const cell* params) { return 0; } +static cell AMX_NATIVE_CALL F_lv_obj_realign(AMX* amx, const cell* params) { + ASSERT_PARAMS(1) + lv_obj_realign(PARAMS_OBJ(1)); + return 0; +} + +/** + * Hand-written implementation of sprintf with limited functionality in order to support reading strings from parameters. + * Supported interpolations: + * %% + * %d and %x, including padding flags + * %s with packed strings + */ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { - // param[0] is the number of total parameter bytes, divide it by cell size and subtract 3 to account for the fixed parameters - int args_count = params[0] / sizeof(cell) - 3; + // param[0] is the number of total parameter bytes, divide it by cell size to get the parameter count + int args_count = params[0] / sizeof(cell); + if (args_count < 4) { + amx_RaiseError(amx, AMX_ERR_PARAMCOUNT); + return 0; + } cell* output = amx_Address(amx, params[1]); - cell output_size = params[2] * sizeof(cell); // We assume the output array is packed, TODO: add a separate sprintf_unpacked function? + cell max_size = params[2] * sizeof(cell); // We assume the output array is packed so each cell contains one character per byte + // TODO: add a separate sprintf_unpacked function? - char buf[output_size]; + char buf[max_size]; + char* bufc = buf; + char* bufmax = buf + max_size - 1; char* fmt; amx_StrParam_Type(amx, params[3], fmt, char*); if (fmt == NULL) return 0; - cell ret = 0; - -#pragma GCC diagnostic ignored "-Wformat-nonliteral" - switch (args_count) { - case 0: - strcpy(buf, fmt); - ret = strlen(fmt) + 1; - break; - case 1: - ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4])); - break; - case 2: - ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5])); - break; - case 3: - ret = snprintf(buf, output_size, fmt, *amx_Address(amx, params[4]), *amx_Address(amx, params[5]), *amx_Address(amx, params[6])); - break; - case 4: - ret = snprintf(buf, - output_size, - fmt, - *amx_Address(amx, params[4]), - *amx_Address(amx, params[5]), - *amx_Address(amx, params[6]), - *amx_Address(amx, params[7])); - break; - case 5: - ret = snprintf(buf, - output_size, - fmt, - *amx_Address(amx, params[4]), - *amx_Address(amx, params[5]), - *amx_Address(amx, params[6]), - *amx_Address(amx, params[7]), - *amx_Address(amx, params[8])); - break; - default: - return 0; + size_t paramc = 4; + + size_t fmt_len = strlen(fmt); + bool in_pc = false; + + char flags[4]; + size_t flagc = 0; + + for (size_t i = 0; i < fmt_len; i++) { + char c = fmt[i]; + + if (c == '%') { + if (in_pc) { + *bufc++ = '%'; + in_pc = false; + } else { + flagc = 0; + in_pc = true; + } + } else if (in_pc) { + switch (c) { + case 'x': + case 'd': { + int padding = 0; + char pad = ' '; + + if (flagc == 1) { + padding = flags[0] - '0'; + } else if (flagc == 2) { + pad = flags[0]; + padding = flags[1] - '0'; + } + + std::to_chars_result result = std::to_chars(bufc, bufmax, (int) *amx_Address(amx, params[paramc++]), c == 'x' ? 16 : 10); + + int padlen = padding - (result.ptr - bufc); + for (int n = 0; n < padlen && bufc < bufmax; n++) { + bufc[1] = bufc[0]; + bufc[0] = pad; + bufc++; + } + + bufc = result.ptr + (padlen > 0 ? padlen : 0); + in_pc = false; + break; + } + + case 's': { + cell param = params[paramc++]; + int len; + amx_StrLen(amx_Address(amx, param), &len); + + if (len > 0 && bufc + len < bufmax - 1) { + amx_GetString(bufc, amx_Address(amx, param), 0, len + 1); + bufc += len; + } + in_pc = false; + break; + } + + default: + if (flagc < sizeof(flags)) + flags[flagc++] = c; + break; + } + } else { + *bufc++ = c; + } } -#pragma GCC diagnostic warning "-Wformat-nonliteral" + *bufc = 0; - amx_SetString(output, buf, 1, 0, output_size); + amx_SetString(output, buf, 1, 0, max_size); - return ret; + return bufc - buf; } +static cell AMX_NATIVE_CALL F_get_datetime(AMX* amx, const cell* params) { + ASSERT_PARAMS(1); + + Pawn* pawn = (Pawn*) amx->userdata[0]; + + pawn->currentDateTime = std::chrono::time_point_cast(pawn->dateTimeController.CurrentDateTime()); + + cell* ret = amx_Address(amx, params[1]); + + ret[0] = pawn->currentDateTime.IsUpdated(); + ret[1] = pawn->dateTimeController.Seconds(); + ret[2] = pawn->dateTimeController.Minutes(); + ret[3] = pawn->dateTimeController.Hours(); + ret[4] = pawn->dateTimeController.Day(); + ret[5] = pawn->dateTimeController.Year(); + + return 0; +} + +static cell AMX_NATIVE_CALL F_get_datetime_short_str(AMX* amx, const cell* params) { + ASSERT_PARAMS(2); + + Pawn* pawn = (Pawn*) amx->userdata[0]; + + cell* ret_day = amx_Address(amx, params[1]); + cell* ret_month = amx_Address(amx, params[2]); + + if (ret_day != NULL) { + const char* day = pawn->dateTimeController.DayOfWeekShortToString(); + amx_SetString(ret_day, day, true, false, 4); + } + if (ret_month != NULL) { + const char* month = pawn->dateTimeController.MonthShortToString(); + amx_SetString(ret_month, month, true, false, 4); + } + + return 0; +} static int load_program(AMX* amx, const uint8_t* data) { AMX_HEADER hdr; @@ -236,9 +325,9 @@ static int load_program(AMX* amx, const uint8_t* data) { return result; } -Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { #include "program.h" +Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { load_program(&amx, program); (void) program_len; @@ -252,6 +341,8 @@ Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateT const AMX_NATIVE_INFO natives[] = { {"sprintf", F_sprintf}, + {"get_datetime", F_get_datetime}, + {"get_datetime_short_str", F_get_datetime_short_str}, {"lv_scr_act", F_lv_scr_act}, {"lv_label_create", F_lv_label_create}, {"lv_btn_create", F_lv_btn_create}, @@ -264,6 +355,7 @@ Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateT {"lv_obj_set_style_local_opa", F_lv_obj_set_style_local_opa}, {"lv_obj_set_style_local_ptr", F_lv_obj_set_style_local_ptr}, {"lv_obj_align", F_lv_obj_align}, + {"lv_obj_realign", F_lv_obj_realign}, {0, 0} /* terminator */ }; amx_Register(&amx, natives, -1); diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index 99d7e98e03..0fd005879f 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -3,6 +3,9 @@ #include "displayapp/apps/Apps.h" #include "displayapp/screens/Screen.h" #include "displayapp/Controllers.h" +#include "components/datetime/DateTimeController.h" +#include "utility/DirtyValue.h" +#include #include "pawn/amx.h" @@ -12,15 +15,18 @@ namespace Pinetime { class Pawn : public Screen { public: - Pawn(); + Pawn(Controllers::DateTime& dateTimeController); ~Pawn() override; void Refresh() override; + + Utility::DirtyValue> currentDateTime {}; + Controllers::DateTime& dateTimeController; + private: AMX amx; int refresh_index; - lv_task_t* taskRefresh = 0; }; } @@ -30,8 +36,8 @@ namespace Pinetime { static constexpr Apps app = Apps::Pawn; static constexpr const char* icon = "P"; - static Screens::Screen* Create(AppControllers& /*controllers*/) { - return new Screens::Pawn(); + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::Pawn(controllers.dateTimeController); }; static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index 2523c20ed0..9d5c86cfcc 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,111 +1,194 @@ unsigned char program[] = { - 0x10, 0x05, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x08, 0x00, - 0x18, 0x01, 0x00, 0x00, 0xbc, 0x04, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, - 0x10, 0x45, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, - 0xc0, 0x02, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, - 0x1f, 0x00, 0x40, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x00, 0x6c, + 0xb0, 0x06, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x02, 0x00, 0x08, 0x00, + 0x60, 0x01, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0xb0, 0x06, 0x00, 0x00, + 0x78, 0x07, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, + 0x9c, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, + 0xa4, 0x02, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, + 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, - 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, - 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x73, - 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, - 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x6c, 0x76, 0x5f, 0x62, 0x74, 0x6e, 0x5f, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, - 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x6c, - 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x62, 0x00, 0x73, 0x70, 0x72, 0x69, 0x6e, - 0x74, 0x66, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, + 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x6c, 0x76, 0x5f, + 0x73, 0x63, 0x72, 0x5f, 0x61, 0x63, 0x74, 0x00, 0x6c, 0x76, 0x5f, 0x6f, + 0x62, 0x6a, 0x5f, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x00, 0x6c, 0x76, 0x5f, + 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x79, 0x6c, + 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, + 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x5f, 0x70, 0x74, 0x72, 0x00, 0x67, 0x65, 0x74, 0x5f, 0x64, 0x61, 0x74, + 0x65, 0x74, 0x69, 0x6d, 0x65, 0x00, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x66, 0x00, 0x67, 0x65, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x74, 0x69, + 0x6d, 0x65, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x74, 0x72, + 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x72, 0x65, 0x61, 0x6c, + 0x69, 0x67, 0x6e, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, + 0x63, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0xfc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0xe8, 0x01, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x35, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x5c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x3a, 0x30, 0x30, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x69, 0x6c, 0x43, - 0x20, 0x3a, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x30, 0x69, 0x6c, 0x63, 0x40, - 0x64, 0x65, 0x6b, 0x63, 0x00, 0x00, 0x00, 0x00, 0x63, 0x69, 0x6c, 0x43, - 0x68, 0x74, 0x20, 0x6b, 0x00, 0x21, 0x73, 0x69, 0x01, 0x00, 0x00, 0x00, - 0x63, 0x69, 0x6c, 0x43, 0x20, 0x3a, 0x73, 0x6b, 0x00, 0x64, 0x6c, 0x25 + 0x64, 0x32, 0x30, 0x25, 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, + 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20, 0x24, 0x02, 0x00, 0x00, + 0xef, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x16, 0x00, 0x09, 0x00, + 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x77, 0x61, + 0x74, 0x63, 0x68, 0x66, 0x61, 0x63, 0x65, 0x2e, 0x70, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x88, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x94, 0x01, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x0d, 0x00, + 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xa8, 0x02, + 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0xac, 0x02, 0x00, 0x00, 0x12, 0x00, + 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x02, + 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xf4, 0x02, 0x00, 0x00, 0x16, 0x00, + 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6c, 0x03, + 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x1b, 0x00, + 0x00, 0x00, 0xa8, 0x03, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xac, 0x03, + 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x1f, 0x00, + 0x00, 0x00, 0x70, 0x04, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xa8, 0x04, + 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xac, 0x03, 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x00, 0xdb, 0x0f, 0x01, 0x00, 0x00, 0x00, + 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x03, 0x00, 0x00, 0xd4, 0x04, + 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x64, 0x61, 0x79, 0x00, 0xdb, 0x0f, + 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, + 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x62, 0x75, + 0x66, 0x66, 0x65, 0x72, 0x00, 0xdb, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0xd4, 0x04, 0x00, + 0x00, 0x03, 0x02, 0x01, 0x00, 0x64, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, + 0x65, 0x00, 0xdb, 0x0f, 0x06, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x00, + 0x00, 0x00, 0xa4, 0x02, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x40, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe0, 0x04, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, + 0x6d, 0x65, 0x63, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x01, 0x00, 0x62, 0x6f, 0x6f, 0x6c, + 0x00, 0x02, 0x00, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x00, 0x03, 0x00, 0x46, + 0x69, 0x78, 0x65, 0x64, 0x00, 0x04, 0x00, 0x4c, 0x56, 0x5f, 0x4f, 0x42, + 0x4a, 0x00, 0x05, 0x00, 0x6c, 0x76, 0x5f, 0x61, 0x6c, 0x69, 0x67, 0x6e, + 0x00, 0x06, 0x00, 0x70, 0x74, 0x72, 0x00, 0x07, 0x00, 0x6c, 0x76, 0x5f, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x00, 0x08, 0x00, 0x6c, 0x76, 0x5f, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x00, 0x09, 0x00, 0x6c, 0x76, 0x5f, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; -unsigned int program_len = 1296; +unsigned int program_len = 2284; From 3aebf4beaff09f0f5e59f5447727ccbe88c7be59 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 02:41:05 +0100 Subject: [PATCH 09/26] Use numbered natives instead of named --- src/CMakeLists.txt | 1 + src/displayapp/screens/Pawn.cpp | 40 ++++--- src/displayapp/screens/program.h | 172 ++++++++++++++----------------- 3 files changed, 96 insertions(+), 117 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 18b16c05e5..7fc6355ed5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -912,6 +912,7 @@ target_include_directories(pawn SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) target_compile_options(pawn PRIVATE ${COMMON_FLAGS} -DAMX_ANSIONLY + -DAMX_NATIVETABLE=pawn_natives $<$: ${DEBUG_FLAGS}> $<$: ${RELEASE_FLAGS}> $<$: ${CXX_FLAGS}> diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index a8db43fdd8..cd2b59317b 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -325,6 +325,25 @@ static int load_program(AMX* amx, const uint8_t* data) { return result; } +extern "C" const AMX_NATIVE pawn_natives[] = { + F_sprintf, + F_lv_scr_act, + F_lv_label_create, + F_lv_btn_create, + F_lv_obj_set_pos, + F_lv_obj_set_size, + F_lv_obj_set_event_cb, + F_lv_obj_align, + F_lv_obj_realign, + F_lv_label_set_text, + F_lv_obj_set_style_local_int, + F_lv_obj_set_style_local_color, + F_lv_obj_set_style_local_opa, + F_lv_obj_set_style_local_ptr, + F_get_datetime, + F_get_datetime_short_str, +}; + #include "program.h" Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { @@ -339,27 +358,6 @@ Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateT if (amx_FindPubVar(&amx, "font_jmec", &font) == AMX_ERR_NONE) *font = (cell) &jetbrains_mono_extrabold_compressed; - const AMX_NATIVE_INFO natives[] = { - {"sprintf", F_sprintf}, - {"get_datetime", F_get_datetime}, - {"get_datetime_short_str", F_get_datetime_short_str}, - {"lv_scr_act", F_lv_scr_act}, - {"lv_label_create", F_lv_label_create}, - {"lv_btn_create", F_lv_btn_create}, - {"lv_obj_set_pos", F_lv_obj_set_pos}, - {"lv_obj_set_size", F_lv_obj_set_size}, - {"lv_label_set_text", F_lv_label_set_text}, - {"lv_obj_set_event_cb", F_lv_obj_set_event_cb}, - {"lv_obj_set_style_local_int", F_lv_obj_set_style_local_int}, - {"lv_obj_set_style_local_color", F_lv_obj_set_style_local_color}, - {"lv_obj_set_style_local_opa", F_lv_obj_set_style_local_opa}, - {"lv_obj_set_style_local_ptr", F_lv_obj_set_style_local_ptr}, - {"lv_obj_align", F_lv_obj_align}, - {"lv_obj_realign", F_lv_obj_realign}, - {0, 0} /* terminator */ - }; - amx_Register(&amx, natives, -1); - amx_Exec(&amx, NULL, AMX_EXEC_MAIN); if (amx_FindPublic(&amx, "@refresh", &refresh_index) == AMX_ERR_NONE) { diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index 9d5c86cfcc..f0cc819008 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,66 +1,45 @@ unsigned char program[] = { - 0xb0, 0x06, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x02, 0x00, 0x08, 0x00, - 0x60, 0x01, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0xb0, 0x06, 0x00, 0x00, - 0x78, 0x07, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, - 0xa4, 0x02, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x19, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, - 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x6c, - 0x76, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x00, 0x6c, 0x76, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, - 0x73, 0x65, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x6c, 0x76, 0x5f, - 0x73, 0x63, 0x72, 0x5f, 0x61, 0x63, 0x74, 0x00, 0x6c, 0x76, 0x5f, 0x6f, - 0x62, 0x6a, 0x5f, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x00, 0x6c, 0x76, 0x5f, - 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x79, 0x6c, - 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, - 0x72, 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x73, 0x65, 0x74, - 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x5f, 0x70, 0x74, 0x72, 0x00, 0x67, 0x65, 0x74, 0x5f, 0x64, 0x61, 0x74, - 0x65, 0x74, 0x69, 0x6d, 0x65, 0x00, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x74, - 0x66, 0x00, 0x67, 0x65, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x74, 0x69, - 0x6d, 0x65, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x74, 0x72, - 0x00, 0x6c, 0x76, 0x5f, 0x6f, 0x62, 0x6a, 0x5f, 0x72, 0x65, 0x61, 0x6c, - 0x69, 0x67, 0x6e, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, - 0x63, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb4, 0x05, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x02, 0x00, 0x08, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x44, 0x05, 0x00, 0x00, 0xb4, 0x05, 0x00, 0x00, + 0x7c, 0x06, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0xa4, 0x02, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x57, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, + 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -68,27 +47,27 @@ unsigned char program[] = { 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xe8, 0x01, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, @@ -100,17 +79,17 @@ unsigned char program[] = { 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, @@ -122,15 +101,15 @@ unsigned char program[] = { 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x3a, 0x30, 0x30, @@ -141,54 +120,55 @@ unsigned char program[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, - 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20, 0x24, 0x02, 0x00, 0x00, - 0xef, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x16, 0x00, 0x09, 0x00, - 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x77, 0x61, - 0x74, 0x63, 0x68, 0x66, 0x61, 0x63, 0x65, 0x2e, 0x70, 0x00, 0x0c, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, - 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x88, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x94, 0x01, - 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x0d, 0x00, - 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xa8, 0x02, - 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0xac, 0x02, 0x00, 0x00, 0x12, 0x00, - 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x02, - 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xf4, 0x02, 0x00, 0x00, 0x16, 0x00, - 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6c, 0x03, - 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x1b, 0x00, - 0x00, 0x00, 0xa8, 0x03, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xac, 0x03, - 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x1f, 0x00, - 0x00, 0x00, 0x70, 0x04, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xa8, 0x04, - 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xac, 0x03, 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, - 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x00, 0xdb, 0x0f, 0x01, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x03, 0x00, 0x00, 0xd4, 0x04, - 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x64, 0x61, 0x79, 0x00, 0xdb, 0x0f, - 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, - 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x62, 0x75, - 0x66, 0x66, 0x65, 0x72, 0x00, 0xdb, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x18, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0xd4, 0x04, 0x00, - 0x00, 0x03, 0x02, 0x01, 0x00, 0x64, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, - 0x65, 0x00, 0xdb, 0x0f, 0x06, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x00, - 0x00, 0x00, 0xa4, 0x02, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x09, 0x00, - 0x00, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, - 0x00, 0x09, 0x00, 0x00, 0x00, 0x40, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe0, 0x04, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, - 0x6d, 0x65, 0x63, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20, 0x37, 0x02, 0x00, 0x00, + 0xef, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x16, 0x00, 0x09, 0x00, + 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x69, 0x6e, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x63, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x61, 0x74, 0x63, 0x68, 0x66, 0x61, + 0x63, 0x65, 0x2e, 0x70, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, + 0x00, 0xf0, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x11, 0x00, 0x00, + 0x00, 0xac, 0x02, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, + 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x15, 0x00, 0x00, + 0x00, 0xf4, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, + 0x00, 0x17, 0x00, 0x00, 0x00, 0x6c, 0x03, 0x00, 0x00, 0x19, 0x00, 0x00, + 0x00, 0xa4, 0x03, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0xa8, 0x03, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0xac, 0x03, 0x00, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0xe4, 0x03, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x70, 0x04, 0x00, + 0x00, 0x21, 0x00, 0x00, 0x00, 0xa8, 0x04, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x03, 0x00, 0x00, 0xd4, + 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x6d, 0x6f, 0x6e, 0x74, 0x68, + 0x00, 0xdb, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa8, 0x03, 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, + 0x00, 0x64, 0x61, 0x79, 0x00, 0xdb, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0xd4, 0x04, 0x00, + 0x00, 0x03, 0x02, 0x01, 0x00, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x00, + 0xdb, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb0, 0x02, 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + 0x64, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x00, 0xdb, 0x0f, 0x06, + 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, + 0x00, 0xe0, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x40, 0x72, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x40, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x08, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x64, + 0x61, 0x74, 0x65, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x01, 0x00, 0x62, 0x6f, 0x6f, 0x6c, - 0x00, 0x02, 0x00, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x00, 0x03, 0x00, 0x46, - 0x69, 0x78, 0x65, 0x64, 0x00, 0x04, 0x00, 0x4c, 0x56, 0x5f, 0x4f, 0x42, - 0x4a, 0x00, 0x05, 0x00, 0x6c, 0x76, 0x5f, 0x61, 0x6c, 0x69, 0x67, 0x6e, - 0x00, 0x06, 0x00, 0x70, 0x74, 0x72, 0x00, 0x07, 0x00, 0x6c, 0x76, 0x5f, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x00, 0x08, 0x00, 0x6c, 0x76, 0x5f, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x00, 0x09, 0x00, 0x6c, 0x76, 0x5f, 0x73, 0x74, - 0x79, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 + 0x62, 0x65, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x5f, + 0x00, 0x01, 0x00, 0x62, 0x6f, 0x6f, 0x6c, 0x00, 0x02, 0x00, 0x46, 0x6c, + 0x6f, 0x61, 0x74, 0x00, 0x03, 0x00, 0x46, 0x69, 0x78, 0x65, 0x64, 0x00, + 0x04, 0x00, 0x4c, 0x56, 0x5f, 0x4f, 0x42, 0x4a, 0x00, 0x05, 0x00, 0x6c, + 0x76, 0x5f, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x00, 0x06, 0x00, 0x70, 0x74, + 0x72, 0x00, 0x07, 0x00, 0x6c, 0x76, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x00, 0x08, 0x00, 0x6c, 0x76, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x00, + 0x09, 0x00, 0x6c, 0x76, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x70, + 0x72, 0x6f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -unsigned int program_len = 2284; +unsigned int program_len = 2051; From 09d053889084beb5910f6de819b4a8edd4c50269 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 02:46:05 +0100 Subject: [PATCH 10/26] Put program in flash --- src/displayapp/screens/program.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index f0cc819008..2f8fe8420c 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,4 +1,4 @@ -unsigned char program[] = { +const unsigned char program[] = { 0xb4, 0x05, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x02, 0x00, 0x08, 0x00, 0x64, 0x00, 0x00, 0x00, 0x44, 0x05, 0x00, 0x00, 0xb4, 0x05, 0x00, 0x00, 0x7c, 0x06, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, From e8f97d27a5641ad0cfc5b480e7e8c15586425acf Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 13:05:37 +0100 Subject: [PATCH 11/26] Make watchface program smaller Compiled with pawncc -O3 -d0 -S:50 --- src/CMakeLists.txt | 3 + src/displayapp/screens/program.h | 216 ++++++++----------------------- 2 files changed, 55 insertions(+), 164 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7fc6355ed5..27d8fe9960 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -911,7 +911,10 @@ target_include_directories(pawn SYSTEM PUBLIC . ../) target_include_directories(pawn SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) target_compile_options(pawn PRIVATE ${COMMON_FLAGS} + -DNDEBUG -DAMX_ANSIONLY + -DAMX_NODYNALOAD + -DAMX_DONT_RELOCATE -DAMX_NATIVETABLE=pawn_natives $<$: ${DEBUG_FLAGS}> $<$: ${RELEASE_FLAGS}> diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index 2f8fe8420c..b793fb8516 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,174 +1,62 @@ const unsigned char program[] = { - 0xb4, 0x05, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x02, 0x00, 0x08, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x44, 0x05, 0x00, 0x00, 0xb4, 0x05, 0x00, 0x00, - 0x7c, 0x06, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0xbc, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0xbc, 0x02, 0x00, 0x00, + 0x84, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0xa4, 0x02, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, - 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0xfe, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xe8, 0x01, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0xf6, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x3a, 0x30, 0x30, - 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x08, 0x00, + 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x3c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, 0x89, 0x80, 0x00, 0x00, + 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x87, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, + 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x92, 0x00, 0x18, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x18, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0xbc, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x08, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x0c, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x60, 0x00, 0x92, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, + 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x60, 0x00, + 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x5c, 0x00, 0x92, 0x00, 0x64, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x08, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x3a, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x64, 0x32, 0x30, 0x25, 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, - 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20, 0x37, 0x02, 0x00, 0x00, - 0xef, 0xf1, 0x0b, 0x0b, 0x00, 0x00, 0x02, 0x00, 0x16, 0x00, 0x09, 0x00, - 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x69, 0x6e, - 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x63, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x61, 0x74, 0x63, 0x68, 0x66, 0x61, - 0x63, 0x65, 0x2e, 0x70, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, - 0x00, 0xf8, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, - 0x00, 0x0b, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, - 0x00, 0xf0, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, - 0x00, 0x0e, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x11, 0x00, 0x00, - 0x00, 0xac, 0x02, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, - 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x15, 0x00, 0x00, - 0x00, 0xf4, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, - 0x00, 0x17, 0x00, 0x00, 0x00, 0x6c, 0x03, 0x00, 0x00, 0x19, 0x00, 0x00, - 0x00, 0xa4, 0x03, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0xa8, 0x03, 0x00, - 0x00, 0x1c, 0x00, 0x00, 0x00, 0xac, 0x03, 0x00, 0x00, 0x1d, 0x00, 0x00, - 0x00, 0xe4, 0x03, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x70, 0x04, 0x00, - 0x00, 0x21, 0x00, 0x00, 0x00, 0xa8, 0x04, 0x00, 0x00, 0x22, 0x00, 0x00, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x03, 0x00, 0x00, 0xd4, - 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x6d, 0x6f, 0x6e, 0x74, 0x68, - 0x00, 0xdb, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xa8, 0x03, 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, - 0x00, 0x64, 0x61, 0x79, 0x00, 0xdb, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0xd4, 0x04, 0x00, - 0x00, 0x03, 0x02, 0x01, 0x00, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x00, - 0xdb, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb0, 0x02, 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, - 0x64, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x00, 0xdb, 0x0f, 0x06, - 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, - 0x00, 0xe0, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x40, 0x72, 0x65, - 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x40, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, - 0x00, 0x08, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x64, - 0x61, 0x74, 0x65, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, - 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x5f, - 0x00, 0x01, 0x00, 0x62, 0x6f, 0x6f, 0x6c, 0x00, 0x02, 0x00, 0x46, 0x6c, - 0x6f, 0x61, 0x74, 0x00, 0x03, 0x00, 0x46, 0x69, 0x78, 0x65, 0x64, 0x00, - 0x04, 0x00, 0x4c, 0x56, 0x5f, 0x4f, 0x42, 0x4a, 0x00, 0x05, 0x00, 0x6c, - 0x76, 0x5f, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x00, 0x06, 0x00, 0x70, 0x74, - 0x72, 0x00, 0x07, 0x00, 0x6c, 0x76, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x00, 0x08, 0x00, 0x6c, 0x76, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x00, - 0x09, 0x00, 0x6c, 0x76, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x70, - 0x72, 0x6f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, + 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, + 0x00, 0x64, 0x25, 0x20 }; -unsigned int program_len = 2051; +unsigned int program_len = 700; From a96de3c6a586cb99ca226331370a46a9d075ddd1 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 17:26:32 +0100 Subject: [PATCH 12/26] Load program using overlays --- src/CMakeLists.txt | 1 + src/displayapp/screens/Pawn.cpp | 47 +++++- src/displayapp/screens/program.h | 112 +++++++------ src/pawn/amxpool.c | 268 +++++++++++++++++++++++++++++++ src/pawn/amxpool.h | 30 ++++ 5 files changed, 403 insertions(+), 55 deletions(-) create mode 100644 src/pawn/amxpool.c create mode 100644 src/pawn/amxpool.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 27d8fe9960..f0fd2746e7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -357,6 +357,7 @@ set(LVGL_SRC list(APPEND PAWN_SRC pawn/amx.c + pawn/amxpool.c ) list(APPEND IMAGE_FILES diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index cd2b59317b..5a5889f33b 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -2,6 +2,12 @@ #include #include +extern "C" { +#include "pawn/amxpool.h" +} + +#include "program.h" + using namespace Pinetime::Applications::Screens; #define AMX_ERR_PARAMCOUNT 32 @@ -301,6 +307,26 @@ static cell AMX_NATIVE_CALL F_get_datetime_short_str(AMX* amx, const cell* param return 0; } +static int AMXAPI prun_Overlay(AMX* amx, int index) { + AMX_HEADER* hdr; + AMX_OVERLAYINFO* tbl; + + hdr = (AMX_HEADER*) amx->base; + tbl = (AMX_OVERLAYINFO*) (amx->base + hdr->overlays) + index; + + amx->codesize = tbl->size; + amx->code = (unsigned char*) amx_poolfind(index); + + if (amx->code == NULL) { + if ((amx->code = (unsigned char*) amx_poolalloc(tbl->size, index)) == NULL) + return AMX_ERR_OVERLAY; + + memcpy(amx->code, program + hdr->cod + tbl->offset, tbl->size); + } + + return AMX_ERR_NONE; +} + static int load_program(AMX* amx, const uint8_t* data) { AMX_HEADER hdr; memcpy(&hdr, data, sizeof(hdr)); @@ -308,17 +334,24 @@ static int load_program(AMX* amx, const uint8_t* data) { if (hdr.magic != AMX_MAGIC) return AMX_ERR_FORMAT; - void* memblock = malloc(hdr.stp); - if (memblock == NULL) - return AMX_ERR_MEMORY; + void* header = malloc(hdr.cod); + memcpy(header, data, hdr.cod); - memcpy(memblock, data, hdr.size); + void* datablock = malloc(hdr.stp - hdr.dat); // This block contains data, heap and stack + memcpy(datablock, data + hdr.dat, hdr.hea - hdr.dat); + + constexpr int poolsize = 512; + void* overlaypool = malloc(poolsize + 8); + + amx_poolinit(overlaypool, poolsize + 8); memset(amx, 0, sizeof(*amx)); + amx->data = (unsigned char*) datablock; + amx->overlay = prun_Overlay; - int result = amx_Init(amx, memblock); + int result = amx_Init(amx, header); if (result != AMX_ERR_NONE) { - free(memblock); + free(datablock); amx->base = NULL; } @@ -344,8 +377,6 @@ extern "C" const AMX_NATIVE pawn_natives[] = { F_get_datetime_short_str, }; -#include "program.h" - Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { load_program(&amx, program); (void) program_len; diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index b793fb8516..7e53ea0342 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,53 +1,71 @@ const unsigned char program[] = { - 0xbc, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0xbc, 0x02, 0x00, 0x00, - 0x84, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x94, 0x03, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x05, 0x00, 0x08, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, 0x00, 0x94, 0x03, 0x00, 0x00, + 0x5c, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x08, 0x01, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, + 0x4c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x64, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x5c, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, - 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x08, 0x00, - 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x3c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, 0x89, 0x80, 0x00, 0x00, - 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, - 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x8f, 0x00, 0x04, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x92, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x71, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x71, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x18, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xbc, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x08, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x0c, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x04, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x60, 0x00, 0x92, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, - 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x60, 0x00, - 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x5c, 0x00, 0x92, 0x00, 0x64, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x08, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x55, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x3a, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -59,4 +77,4 @@ const unsigned char program[] = { 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20 }; -unsigned int program_len = 700; +unsigned int program_len = 916; diff --git a/src/pawn/amxpool.c b/src/pawn/amxpool.c new file mode 100644 index 0000000000..9423e226fb --- /dev/null +++ b/src/pawn/amxpool.c @@ -0,0 +1,268 @@ +/* Simple allocation from a memory pool, with automatic release of + * least-recently used blocks (LRU blocks). + * + * These routines are as simple as possible, and they are neither re-entrant + * nor thread-safe. Their purpose is to have a standard implementation for + * systems where overlays are used and malloc() is not available. + * + * The algorithm uses a first-fit strategy. It keeps all blocks in a single + * list (both used blocks and free blocks are in the same list). Every memory + * block must have a unique number that identifies the block. This unique + * number allows to search for the presence of the block in the pool and for + * "conditional allocation". + * + * + * Copyright (c) CompuPhase, 2007-2020 + * + * 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 + * + * http://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. + * + * Version: $Id: amxpool.c 6131 2020-04-29 19:47:15Z thiadmer $ + */ +#include +#include "amx.h" +#include "amxpool.h" + +#if !defined NULL + #define NULL ((void*)0) +#endif + +#define MIN_BLOCKSIZE 32 +#define PROTECT_LRU 0xffff + +typedef struct tagARENA { + unsigned blocksize; + short index; /* overlay index, -1 if free */ + unsigned short lru; +} ARENA; + +static void *pool_base; +static unsigned pool_size; +static unsigned short pool_lru; + +static void touchblock(ARENA *hdr); +static ARENA *findblock(int index); + +/* amx_poolinit() initializes the memory pool for the allocated blocks. + * If parameter pool is NULL, the existing pool is cleared (without changing + * its position or size). + */ +void amx_poolinit(void *pool, unsigned size) +{ + assert(pool!=NULL || pool_base!=NULL); + if (pool!=NULL) { + assert(size>sizeof(ARENA)); + /* save parameters in global variables, then "free" the entire pool */ + pool_base=pool; + pool_size=size; + } /* if */ + pool_lru=0; + amx_poolfree(NULL); +} + +/* amx_poolfree() releases a block allocated earlier. The parameter must have + * the same value as that returned by an earlier call to amx_poolalloc(). That + * is, the "block" parameter must point directly behind the arena header of the + * block. + * When parameter "block" is NULL, the pool is re-initialized (meaning that + * all blocks are freed). + */ +void amx_poolfree(void *block) +{ + ARENA *hdr,*hdr2; + unsigned sz; + + assert(pool_base!=NULL); + assert(pool_size>sizeof(ARENA)); + + /* special case: if "block" is NULL, create a single free space */ + if (block==NULL) { + /* store an arena header at the start of the pool */ + hdr=(ARENA*)pool_base; + hdr->blocksize=pool_size-sizeof(ARENA); + hdr->index=-1; + hdr->lru=0; + } else { + hdr=(ARENA*)((char*)block-sizeof(ARENA)); + assert((char*)hdr>=(char*)pool_base && (char*)hdr<(char*)pool_base+pool_size); + assert(hdr->blocksizeindex=-1; + + /* try to coalesce with the next block */ + hdr2=(ARENA*)((char*)hdr+hdr->blocksize+sizeof(ARENA)); + if (hdr2->index==-1) + hdr->blocksize+=hdr2->blocksize+sizeof(ARENA); + + /* try to coalesce with the previous block */ + if ((void*)hdr!=pool_base) { + sz=pool_size; + hdr2=(ARENA*)pool_base; + while (sz>0 && (char*)hdr2+hdr2->blocksize+sizeof(ARENA)!=(char*)hdr) { + assert(sz<=pool_size); + sz-=hdr2->blocksize+sizeof(ARENA); + hdr2=(ARENA*)((char*)hdr2+hdr2->blocksize+sizeof(ARENA)); + } /* while */ + assert((char*)hdr2+hdr2->blocksize+sizeof(ARENA)==(char*)hdr); + if (hdr2->index==-1) + hdr2->blocksize+=hdr->blocksize+sizeof(ARENA); + } /* if */ + } /* if */ +} + +/* amx_poolalloc() allocates the requested number of bytes from the pool and + * returns a header to the start of it. Every block in the pool is prefixed + * with an "arena header"; the return value of this function points just + * behind this arena header. + * + * The block with the specified "index" should not already exist in the pool. + * In other words, parameter "index" should be unique for every of memory block, + * and the block should not change in size. Use amx_poolfind() to verify whether + * a block is already in the pool (and optionally amx_poolfree() to remove it). + * + * If no block of sufficient size is available, the routine frees blocks until + * the requested amount of memory can be allocated. There is no intelligent + * algorithm involved: the routine just frees the least-recently used block at + * every iteration (without considering the size of the block or whether that + * block is adjacent to a free block). + */ +void *amx_poolalloc(unsigned size,int index) +{ + ARENA *hdr,*hdrlru; + unsigned sz; + unsigned short minlru; + + assert(size>0); + assert(index>=0 && index<=SHRT_MAX); + assert(findblock(index)==NULL); + + /* align the size to a cell boundary */ + if ((size % sizeof(cell))!=0) + size+=sizeof(cell)-(size % sizeof(cell)); + if (size+sizeof(ARENA)>pool_size) + return NULL; /* requested block does not fit in the pool */ + + /* find a block large enough to get the size plus an arena header; at + * the same time, detect the block with the lowest LRU + * if no block of sufficient size can be found, the routine then frees + * the block with the lowest LRU count and tries again + */ + do { + sz=pool_size; + hdr=(ARENA*)pool_base; + hdrlru=hdr; + minlru=USHRT_MAX; + while (sz>0) { + assert(sz<=pool_size); + assert((char*)hdr>=(char*)pool_base && (char*)hdr<(char*)pool_base+pool_size); + if (hdr->index==-1 && hdr->blocksize>=size) + break; + if (hdr->index!=-1 && hdr->lrulru; + hdrlru=hdr; + } /* if */ + sz-=hdr->blocksize+sizeof(ARENA); + hdr=(ARENA*)((char*)hdr+hdr->blocksize+sizeof(ARENA)); + } /* while */ + assert(sz<=pool_size); + if (sz==0) { + /* free up memory and try again */ + assert(hdrlru->index!=-1); + amx_poolfree((char*)hdrlru+sizeof(ARENA)); + } /* if */ + } while (sz==0); + + /* see whether to allocate the entire free block, or to cut it in two blocks */ + if (hdr->blocksize>size+MIN_BLOCKSIZE+sizeof(ARENA)) { + /* cut the block in two */ + ARENA *next=(ARENA*)((char*)hdr+size+sizeof(ARENA)); + next->blocksize=hdr->blocksize-size-sizeof(ARENA); + next->index=-1; + next->lru=0; + } else { + size=hdr->blocksize; + } /* if */ + hdr->blocksize=size; + hdr->index=(short)index; + touchblock(hdr); /* set LRU field */ + + return (void*)((char*)hdr+sizeof(ARENA)); +} + +/* amx_poolfind() returns the address of the memory block with the given index, + * or NULL if no such block exists. Parameter "index" should not be -1, because + * -1 represents a free block (actually, only positive values are valid). + * When amx_poolfind() finds the block, it increments its LRU count. + */ +void *amx_poolfind(int index) +{ + ARENA *hdr=findblock(index); + if (hdr==NULL) + return NULL; + touchblock(hdr); + return (void*)((char*)hdr+sizeof(ARENA)); +} + +int amx_poolprotect(int index) +{ + ARENA *hdr=findblock(index); + if (hdr==NULL) + return AMX_ERR_GENERAL; + hdr->lru=PROTECT_LRU; + return AMX_ERR_NONE; +} + +static ARENA *findblock(int index) +{ + ARENA *hdr; + unsigned sz; + + assert(index>=0); + sz=pool_size; + hdr=(ARENA*)pool_base; + while (sz>0 && hdr->index!=index) { + assert(sz<=pool_size); + assert((char*)hdr>=(char*)pool_base && (char*)hdr<(char*)pool_base+pool_size); + sz-=hdr->blocksize+sizeof(ARENA); + hdr=(ARENA*)((char*)hdr+hdr->blocksize+sizeof(ARENA)); + } /* while */ + assert(sz<=pool_size); + return (sz>0 && hdr->index==index) ? hdr : NULL; +} + +static void touchblock(ARENA *hdr) +{ + assert(hdr!=NULL); + if (++pool_lru >= PROTECT_LRU) + pool_lru=0; + hdr->lru=pool_lru; + + /* special case: if the overlay LRU count wrapped back to zero, set the + * LRU count of all blocks to zero, but set the count of the block just + * touched to 1 (skip blocks marked as protected, too) + */ + if (pool_lru==0) { + ARENA *hdr2; + unsigned sz=pool_size; + hdr2=(ARENA*)pool_base; + while (sz>0) { + assert(sz<=pool_size); + if (hdr2->lru!=PROTECT_LRU) + hdr2->lru=0; + sz-=hdr2->blocksize+sizeof(ARENA); + hdr2=(ARENA*)((char*)hdr2+hdr2->blocksize+sizeof(ARENA)); + } /* while */ + assert(sz==0); + hdr->lru=++pool_lru; + } /* if */ +} diff --git a/src/pawn/amxpool.h b/src/pawn/amxpool.h new file mode 100644 index 0000000000..f375515d0f --- /dev/null +++ b/src/pawn/amxpool.h @@ -0,0 +1,30 @@ +/* Simple allocation from a memory pool, with automatic release of + * least-recently used blocks (LRU blocks). + * + * Copyright (c) CompuPhase, 2007-2020 + * + * 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 + * + * http://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. + * + * Version: $Id: amxpool.h 6131 2020-04-29 19:47:15Z thiadmer $ + */ +#ifndef AMXPOOL_H_INCLUDED +#define AMXPOOL_H_INCLUDED + +void amx_poolinit(void *pool, unsigned size); +void *amx_poolalloc(unsigned size, int index); +void amx_poolfree(void *block); +void *amx_poolfind(int index); +int amx_poolprotect(int index); + + +#endif /* AMXPOOL_H_INCLUDED */ From 8cdc948488f8c643ae34cf450ddf18baa6b5197d Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 17:41:08 +0100 Subject: [PATCH 13/26] Load non-overlayed programs --- src/displayapp/screens/Pawn.cpp | 75 +++++++++++++++------ src/displayapp/screens/Pawn.h | 5 +- src/displayapp/screens/program.h | 108 +++++++++++++------------------ 3 files changed, 106 insertions(+), 82 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 5a5889f33b..49987bd9cc 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -327,32 +327,64 @@ static int AMXAPI prun_Overlay(AMX* amx, int index) { return AMX_ERR_NONE; } -static int load_program(AMX* amx, const uint8_t* data) { +int Pawn::LoadProgram() { + (void) program_len; + + int result; AMX_HEADER hdr; - memcpy(&hdr, data, sizeof(hdr)); + memcpy(&hdr, program, sizeof(hdr)); if (hdr.magic != AMX_MAGIC) return AMX_ERR_FORMAT; - void* header = malloc(hdr.cod); - memcpy(header, data, hdr.cod); + memset(&amx, 0, sizeof(amx)); - void* datablock = malloc(hdr.stp - hdr.dat); // This block contains data, heap and stack - memcpy(datablock, data + hdr.dat, hdr.hea - hdr.dat); + header = malloc(hdr.cod); + if (header == NULL) + return AMX_ERR_MEMORY; - constexpr int poolsize = 512; - void* overlaypool = malloc(poolsize + 8); + memcpy(header, program, hdr.cod); - amx_poolinit(overlaypool, poolsize + 8); + if (hdr.flags & AMX_FLAG_OVERLAY) { + datablock = malloc(hdr.stp - hdr.dat); // This block contains data, heap and stack + if (datablock == NULL) + return AMX_ERR_MEMORY; - memset(amx, 0, sizeof(*amx)); - amx->data = (unsigned char*) datablock; - amx->overlay = prun_Overlay; + memcpy(datablock, program + hdr.dat, hdr.hea - hdr.dat); - int result = amx_Init(amx, header); - if (result != AMX_ERR_NONE) { - free(datablock); - amx->base = NULL; + constexpr int poolsize = 512; + overlaypool = malloc(poolsize + 8); + if (overlaypool == NULL) + return AMX_ERR_MEMORY; + + amx_poolinit(overlaypool, poolsize + 8); + + amx.data = (unsigned char*) datablock; + amx.overlay = prun_Overlay; + + result = amx_Init(&amx, header); + if (result != AMX_ERR_NONE) { + free(header); + header = NULL; + free(datablock); + datablock = NULL; + free(overlaypool); + overlaypool = NULL; + } + } else { + datablock = malloc(hdr.stp); // This block contains code, data, heap and stack + if (datablock == NULL) + return AMX_ERR_MEMORY; + + memcpy(datablock, program, hdr.size); + + result = amx_Init(&amx, datablock); + if (result != AMX_ERR_NONE) { + free(header); + header = NULL; + free(datablock); + datablock = NULL; + } } return result; @@ -378,8 +410,7 @@ extern "C" const AMX_NATIVE pawn_natives[] = { }; Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { - load_program(&amx, program); - (void) program_len; + LoadProgram(); amx.userdata[0] = this; @@ -404,7 +435,13 @@ Pawn::~Pawn() { lv_obj_clean(lv_scr_act()); amx_Cleanup(&amx); - free(amx.base); + + if (header) + free(header); + if (datablock) + free(datablock); + if (overlaypool) + free(overlaypool); } void Pawn::Refresh() { diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index 0fd005879f..db11640c81 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -20,7 +20,6 @@ namespace Pinetime { void Refresh() override; - Utility::DirtyValue> currentDateTime {}; Controllers::DateTime& dateTimeController; @@ -28,6 +27,10 @@ namespace Pinetime { AMX amx; int refresh_index; lv_task_t* taskRefresh = 0; + + void *header = nullptr, *datablock = nullptr, *overlaypool = nullptr; + + int LoadProgram(); }; } diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index 7e53ea0342..742c49a88f 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,70 +1,54 @@ const unsigned char program[] = { - 0x94, 0x03, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x05, 0x00, 0x08, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, 0x00, 0x94, 0x03, 0x00, 0x00, - 0x5c, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0xd4, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x05, 0x00, 0x08, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, + 0x9c, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x64, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x5c, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, + 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, - 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x08, 0x00, + 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x3c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, 0x89, 0x80, 0x00, 0x00, + 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x87, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, + 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x4e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x92, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, + 0x83, 0x00, 0x18, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0xbc, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x08, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x0c, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x60, 0x00, 0x92, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, + 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x60, 0x00, + 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x5c, 0x00, 0x92, 0x00, 0x64, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x08, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x3a, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, @@ -77,4 +61,4 @@ const unsigned char program[] = { 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20 }; -unsigned int program_len = 916; +unsigned int program_len = 724; From dc0923c1ef3c915cecea905398b56e9a5ef73857 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 19:57:02 +0100 Subject: [PATCH 14/26] Show status icons --- src/displayapp/screens/Pawn.cpp | 49 +++++++++++++++++++++++++------- src/displayapp/screens/Pawn.h | 10 +++++-- src/displayapp/screens/program.h | 31 ++++++++++---------- 3 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 49987bd9cc..467531e990 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -20,6 +20,8 @@ using namespace Pinetime::Applications::Screens; #define PARAMS_OBJ(i) ((lv_obj_t*) params[i]) +#define PAWN_INST ((Pawn*) amx->userdata[0]) + static void event_handler(lv_obj_t* obj, lv_event_t event) { AMX* amx = (AMX*) lv_obj_get_user_data(lv_scr_act()); int handler_index = (int) lv_obj_get_user_data(obj); @@ -271,18 +273,18 @@ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { static cell AMX_NATIVE_CALL F_get_datetime(AMX* amx, const cell* params) { ASSERT_PARAMS(1); - Pawn* pawn = (Pawn*) amx->userdata[0]; + Pawn* pawn = PAWN_INST; - pawn->currentDateTime = std::chrono::time_point_cast(pawn->dateTimeController.CurrentDateTime()); + pawn->currentDateTime = std::chrono::time_point_cast(pawn->controllers.dateTimeController.CurrentDateTime()); cell* ret = amx_Address(amx, params[1]); ret[0] = pawn->currentDateTime.IsUpdated(); - ret[1] = pawn->dateTimeController.Seconds(); - ret[2] = pawn->dateTimeController.Minutes(); - ret[3] = pawn->dateTimeController.Hours(); - ret[4] = pawn->dateTimeController.Day(); - ret[5] = pawn->dateTimeController.Year(); + ret[1] = pawn->controllers.dateTimeController.Seconds(); + ret[2] = pawn->controllers.dateTimeController.Minutes(); + ret[3] = pawn->controllers.dateTimeController.Hours(); + ret[4] = pawn->controllers.dateTimeController.Day(); + ret[5] = pawn->controllers.dateTimeController.Year(); return 0; } @@ -290,23 +292,43 @@ static cell AMX_NATIVE_CALL F_get_datetime(AMX* amx, const cell* params) { static cell AMX_NATIVE_CALL F_get_datetime_short_str(AMX* amx, const cell* params) { ASSERT_PARAMS(2); - Pawn* pawn = (Pawn*) amx->userdata[0]; + Pawn* pawn = PAWN_INST; cell* ret_day = amx_Address(amx, params[1]); cell* ret_month = amx_Address(amx, params[2]); if (ret_day != NULL) { - const char* day = pawn->dateTimeController.DayOfWeekShortToString(); + const char* day = pawn->controllers.dateTimeController.DayOfWeekShortToString(); amx_SetString(ret_day, day, true, false, 4); } if (ret_month != NULL) { - const char* month = pawn->dateTimeController.MonthShortToString(); + const char* month = pawn->controllers.dateTimeController.MonthShortToString(); amx_SetString(ret_month, month, true, false, 4); } return 0; } +static cell AMX_NATIVE_CALL F_status_icons_create(AMX* amx, const cell*) { + Pawn* pawn = PAWN_INST; + + if (pawn->statusIcons == nullptr) { + pawn->statusIcons = new Pinetime::Applications::Widgets::StatusIcons(pawn->controllers.batteryController, pawn->controllers.bleController, pawn->controllers.alarmController); + pawn->statusIcons->Create(); + } + + return 0; +} + +static cell AMX_NATIVE_CALL F_status_icons_update(AMX* amx, const cell*) { + Pawn* pawn = PAWN_INST; + + if (pawn->statusIcons != nullptr) + pawn->statusIcons->Update(); + + return 0; +} + static int AMXAPI prun_Overlay(AMX* amx, int index) { AMX_HEADER* hdr; AMX_OVERLAYINFO* tbl; @@ -407,9 +429,11 @@ extern "C" const AMX_NATIVE pawn_natives[] = { F_lv_obj_set_style_local_ptr, F_get_datetime, F_get_datetime_short_str, + F_status_icons_create, + F_status_icons_update, }; -Pawn::Pawn(Controllers::DateTime& dateTimeController) : dateTimeController(dateTimeController) { +Pawn::Pawn(AppControllers& controllers) : controllers(controllers) { LoadProgram(); amx.userdata[0] = this; @@ -432,6 +456,9 @@ Pawn::~Pawn() { if (taskRefresh) lv_task_del(taskRefresh); + if (statusIcons) + delete statusIcons; + lv_obj_clean(lv_scr_act()); amx_Cleanup(&amx); diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index db11640c81..fca8eae742 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -5,6 +5,7 @@ #include "displayapp/Controllers.h" #include "components/datetime/DateTimeController.h" #include "utility/DirtyValue.h" +#include "displayapp/widgets/StatusIcons.h" #include #include "pawn/amx.h" @@ -15,13 +16,15 @@ namespace Pinetime { class Pawn : public Screen { public: - Pawn(Controllers::DateTime& dateTimeController); + Pawn(AppControllers& controllers); ~Pawn() override; void Refresh() override; Utility::DirtyValue> currentDateTime {}; - Controllers::DateTime& dateTimeController; + AppControllers& controllers; + + Widgets::StatusIcons* statusIcons = nullptr; private: AMX amx; @@ -40,7 +43,8 @@ namespace Pinetime { static constexpr const char* icon = "P"; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Pawn(controllers.dateTimeController); + // sizeof(Pawn) + return new Screens::Pawn(controllers); }; static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index 742c49a88f..f4f6335596 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,15 +1,14 @@ const unsigned char program[] = { - 0xd4, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x05, 0x00, 0x08, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, - 0x9c, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0xc8, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x00, + 0x90, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, + 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x14, 0x01, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x57, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x08, 0x00, 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, @@ -31,34 +30,34 @@ const unsigned char program[] = { 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x4e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x92, 0x00, 0x18, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xee, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x0c, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x44, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x60, 0x00, 0x92, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x54, 0x00, 0x92, 0x00, 0x50, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, - 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x60, 0x00, + 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x54, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x5c, 0x00, 0x92, 0x00, 0x64, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x92, 0x00, 0x50, 0x00, 0x92, 0x00, 0x58, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x3a, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20 }; -unsigned int program_len = 724; +unsigned int program_len = 712; From 4ad16fd0d775114b1c47c649a989a6a8ea40ac82 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 19:58:29 +0100 Subject: [PATCH 15/26] Move overlay max size constant to top --- src/displayapp/screens/Pawn.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 467531e990..290075e04e 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -22,6 +22,8 @@ using namespace Pinetime::Applications::Screens; #define PAWN_INST ((Pawn*) amx->userdata[0]) +constexpr int max_overlay_size = 512; + static void event_handler(lv_obj_t* obj, lv_event_t event) { AMX* amx = (AMX*) lv_obj_get_user_data(lv_scr_act()); int handler_index = (int) lv_obj_get_user_data(obj); @@ -374,12 +376,12 @@ int Pawn::LoadProgram() { memcpy(datablock, program + hdr.dat, hdr.hea - hdr.dat); - constexpr int poolsize = 512; - overlaypool = malloc(poolsize + 8); + constexpr int overlaypool_overhead = 8; + overlaypool = malloc(max_overlay_size + overlaypool_overhead); if (overlaypool == NULL) return AMX_ERR_MEMORY; - amx_poolinit(overlaypool, poolsize + 8); + amx_poolinit(overlaypool, max_overlay_size + overlaypool_overhead); amx.data = (unsigned char*) datablock; amx.overlay = prun_Overlay; From e4148e703cb30481ba10d30f2be612dca1f44634 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 21:39:11 +0100 Subject: [PATCH 16/26] Add error handling --- src/displayapp/screens/Pawn.cpp | 124 +++++++++++++++++++++++++++---- src/displayapp/screens/Pawn.h | 6 ++ src/displayapp/screens/program.h | 95 ++++++++++++----------- 3 files changed, 170 insertions(+), 55 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 290075e04e..094a84b99d 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -10,11 +10,17 @@ extern "C" { using namespace Pinetime::Applications::Screens; -#define AMX_ERR_PARAMCOUNT 32 +enum { + PAWN_ERR_PARAMCOUNT = 100, + PAWN_ERR_MISSINGHANDLER, + PAWN_ERR_INVALIDSTRING, + + PAWN_ERR_FIRST = PAWN_ERR_PARAMCOUNT, +}; #define ASSERT_PARAMS(n) \ if (params[0] != n * sizeof(cell)) { \ - amx_RaiseError(amx, AMX_ERR_PARAMCOUNT); \ + amx_RaiseError(amx, PAWN_ERR_PARAMCOUNT); \ return 0; \ } @@ -25,11 +31,17 @@ using namespace Pinetime::Applications::Screens; constexpr int max_overlay_size = 512; static void event_handler(lv_obj_t* obj, lv_event_t event) { + if (event == LV_EVENT_DELETE) + return; + AMX* amx = (AMX*) lv_obj_get_user_data(lv_scr_act()); int handler_index = (int) lv_obj_get_user_data(obj); amx_Push(amx, event); - amx_Exec(amx, nullptr, handler_index); + int result = amx_Exec(amx, nullptr, handler_index); + if (result != AMX_ERR_NONE) { + PAWN_INST->QueueError(result); + } } static cell AMX_NATIVE_CALL F_lv_scr_act(AMX* amx, const cell* params) { @@ -76,6 +88,8 @@ static cell AMX_NATIVE_CALL F_lv_obj_set_event_cb(AMX* amx, const cell* params) if (amx_FindPublic(amx, name, &index) == AMX_ERR_NONE) { lv_obj_set_user_data(obj, (void*) index); lv_obj_set_event_cb(obj, event_handler); + } else { + amx_RaiseError(amx, PAWN_ERR_MISSINGHANDLER); } } @@ -92,7 +106,7 @@ static cell AMX_NATIVE_CALL F_lv_label_set_text(AMX* amx, const cell* params) { if (text != NULL) lv_label_set_text(label, text); else - lv_label_set_text_static(label, ""); + amx_RaiseError(amx, PAWN_ERR_INVALIDSTRING); return 0; } @@ -179,7 +193,7 @@ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { // param[0] is the number of total parameter bytes, divide it by cell size to get the parameter count int args_count = params[0] / sizeof(cell); if (args_count < 4) { - amx_RaiseError(amx, AMX_ERR_PARAMCOUNT); + amx_RaiseError(amx, PAWN_ERR_PARAMCOUNT); return 0; } @@ -193,8 +207,10 @@ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { char* fmt; amx_StrParam_Type(amx, params[3], fmt, char*); - if (fmt == NULL) + if (fmt == NULL) { + amx_RaiseError(amx, PAWN_ERR_INVALIDSTRING); return 0; + } size_t paramc = 4; @@ -315,7 +331,9 @@ static cell AMX_NATIVE_CALL F_status_icons_create(AMX* amx, const cell*) { Pawn* pawn = PAWN_INST; if (pawn->statusIcons == nullptr) { - pawn->statusIcons = new Pinetime::Applications::Widgets::StatusIcons(pawn->controllers.batteryController, pawn->controllers.bleController, pawn->controllers.alarmController); + pawn->statusIcons = new Pinetime::Applications::Widgets::StatusIcons(pawn->controllers.batteryController, + pawn->controllers.bleController, + pawn->controllers.alarmController); pawn->statusIcons->Create(); } @@ -331,6 +349,14 @@ static cell AMX_NATIVE_CALL F_status_icons_update(AMX* amx, const cell*) { return 0; } +static cell AMX_NATIVE_CALL F_raise_error(AMX* amx, const cell* params) { + ASSERT_PARAMS(1); + + amx_RaiseError(amx, params[1]); + + return 0; +} + static int AMXAPI prun_Overlay(AMX* amx, int index) { AMX_HEADER* hdr; AMX_OVERLAYINFO* tbl; @@ -433,10 +459,15 @@ extern "C" const AMX_NATIVE pawn_natives[] = { F_get_datetime_short_str, F_status_icons_create, F_status_icons_update, + F_raise_error, }; Pawn::Pawn(AppControllers& controllers) : controllers(controllers) { - LoadProgram(); + int result = LoadProgram(); + if (result != AMX_ERR_NONE) { + ShowError(result); + return; + } amx.userdata[0] = this; @@ -446,7 +477,11 @@ Pawn::Pawn(AppControllers& controllers) : controllers(controllers) { if (amx_FindPubVar(&amx, "font_jmec", &font) == AMX_ERR_NONE) *font = (cell) &jetbrains_mono_extrabold_compressed; - amx_Exec(&amx, NULL, AMX_EXEC_MAIN); + result = amx_Exec(&amx, NULL, AMX_EXEC_MAIN); + if (result != AMX_ERR_NONE) { + ShowError(result); + return; + } if (amx_FindPublic(&amx, "@refresh", &refresh_index) == AMX_ERR_NONE) { taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); @@ -454,14 +489,22 @@ Pawn::Pawn(AppControllers& controllers) : controllers(controllers) { } } -Pawn::~Pawn() { - if (taskRefresh) +void Pawn::CleanUI() { + if (taskRefresh) { lv_task_del(taskRefresh); + taskRefresh = nullptr; + } - if (statusIcons) + if (statusIcons) { delete statusIcons; + statusIcons = nullptr; + } lv_obj_clean(lv_scr_act()); +} + +Pawn::~Pawn() { + CleanUI(); amx_Cleanup(&amx); @@ -474,5 +517,60 @@ Pawn::~Pawn() { } void Pawn::Refresh() { - amx_Exec(&amx, NULL, refresh_index); + int result = amx_Exec(&amx, NULL, refresh_index); + if (result != AMX_ERR_NONE) { + ShowError(result); + } +} + +void Pawn::ShowError(unsigned int amx_err) { + static const char* amx_err_msgs[] = { + nullptr, "EXIT", "ASSERT", "STACKERR", "BOUNDS", "MEMACCESS", "INVINSTR", "STACKLOW", "HEAPLOW", "CALLBACK", + "NATIVE", "DIVIDE", "SLEEP", "INVSTATE", nullptr, nullptr, "MEMORY", "FORMAT", "VERSION", "NOTFOUND", + "INDEX", "DEBUG", "INIT", "USERDATA", "INIT_JIT", "PARAMS", "DOMAIN", "GENERAL", "OVERLAY", + }; + static const char* pawn_err_msgs[] = { + "invalid parameter count", // PAWN_ERR_PARAMCOUNT + "missing event handler", // PAWN_ERR_MISSINGHANDLER + }; + + if (amx_err == AMX_ERR_EXIT) { + running = false; + return; + } + + if (amx_err > 0 && amx_err < PAWN_ERR_FIRST && amx_err < sizeof(amx_err_msgs) / sizeof(*amx_err_msgs)) { + ShowError(amx_err_msgs[amx_err]); + } else if (amx_err >= PAWN_ERR_FIRST && amx_err - PAWN_ERR_FIRST < sizeof(pawn_err_msgs) / sizeof(*amx_err_msgs)) { + ShowError(pawn_err_msgs[amx_err - PAWN_ERR_FIRST]); + } else { + char msg[25]; + snprintf(msg, sizeof(msg), "unknown error %d", amx_err); + ShowError(msg); + } +} + +void Pawn::ShowError(const char* msg) { + CleanUI(); + + lv_obj_t* msglbl = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(msglbl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(255, 0, 0)); + lv_label_set_long_mode(msglbl, LV_LABEL_LONG_BREAK); + lv_label_set_text_fmt(msglbl, "Execution aborted:\n%s\n\nCIP: 0x%X", msg, amx.cip); + lv_obj_set_width(msglbl, 240); + lv_label_set_align(msglbl, LV_LABEL_ALIGN_CENTER); + lv_obj_align(msglbl, NULL, LV_ALIGN_CENTER, 0, 0); +} + +void Pawn::QueueError(unsigned int amx_err) { + if (this->queued_error != 0) + return; + + this->queued_error = amx_err; + lv_async_call( + [](void* user_data) { + Pawn* pawn = static_cast(user_data); + pawn->ShowError(pawn->queued_error); + }, + this); } diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index fca8eae742..58d3f4222f 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -21,6 +21,10 @@ namespace Pinetime { void Refresh() override; + void QueueError(unsigned int amx_err); + void ShowError(unsigned int amx_err); + void ShowError(const char* msg); + Utility::DirtyValue> currentDateTime {}; AppControllers& controllers; @@ -30,10 +34,12 @@ namespace Pinetime { AMX amx; int refresh_index; lv_task_t* taskRefresh = 0; + unsigned int queued_error = 0; void *header = nullptr, *datablock = nullptr, *overlaypool = nullptr; int LoadProgram(); + void CleanUI(); }; } diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index f4f6335596..3de4974d4e 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,57 +1,68 @@ const unsigned char program[] = { - 0xc8, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x00, - 0x90, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x4c, 0x03, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, + 0x74, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x4c, 0x03, 0x00, 0x00, + 0x14, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x14, 0x01, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, - 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, - 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x08, 0x00, - 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x3c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, 0x89, 0x80, 0x00, 0x00, - 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x60, 0x01, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, + 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x40, 0x62, 0x74, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, 0x6f, + 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, 0x00, 0xad, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, - 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x87, 0x00, 0x08, 0x00, 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x8e, 0x00, 0x3c, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, + 0x8e, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf2, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, + 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x9c, 0x00, 0xfc, 0xff, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x88, 0x00, 0xfc, 0xff, 0x8e, 0x00, 0x1e, 0x00, 0x8e, 0x00, 0x28, 0x00, + 0x90, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x18, 0x00, 0x90, 0x00, 0xfc, 0xff, + 0x70, 0x00, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x9c, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xed, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xee, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x18, 0x00, + 0xee, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x18, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xbc, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x08, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x0c, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x44, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x83, 0x00, 0x24, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0xbc, 0x00, 0x00, 0x00, 0x83, 0x00, 0x24, 0x00, 0xa0, 0x00, 0x08, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x24, 0x00, 0xa0, 0x00, 0x0c, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x3c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x3c, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x54, 0x00, 0x92, 0x00, 0x50, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x18, 0x00, - 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x54, 0x00, - 0x83, 0x00, 0x18, 0x00, 0xa0, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x50, 0x00, 0x92, 0x00, 0x58, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x08, 0x00, + 0x92, 0x00, 0x60, 0x00, 0x92, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x24, 0x00, + 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x60, 0x00, + 0x83, 0x00, 0x24, 0x00, 0xa0, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x5c, 0x00, 0x92, 0x00, 0x64, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x3c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x3c, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x3a, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, + 0x6e, 0x74, 0x62, 0x40, 0x72, 0x72, 0x65, 0x5f, 0x00, 0x00, 0x72, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -60,4 +71,4 @@ const unsigned char program[] = { 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20 }; -unsigned int program_len = 712; +unsigned int program_len = 844; From 8544ad706c1380ffb76d3b28f30bda56c417c61a Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Mon, 29 Dec 2025 23:47:40 +0100 Subject: [PATCH 17/26] Handle touch gestures --- src/displayapp/screens/Pawn.cpp | 41 +++++++++++++++++++++++++++++++++ src/displayapp/screens/Pawn.h | 5 +++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 094a84b99d..cf87db0cfb 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -487,6 +487,12 @@ Pawn::Pawn(AppControllers& controllers) : controllers(controllers) { taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); Refresh(); } + if (amx_FindPublic(&amx, "@touch", &touch_index) != AMX_ERR_NONE) { + touch_index = -1; + } + if (amx_FindPublic(&amx, "@gesture", &gesture_index) != AMX_ERR_NONE) { + gesture_index = -1; + } } void Pawn::CleanUI() { @@ -574,3 +580,38 @@ void Pawn::QueueError(unsigned int amx_err) { }, this); } + +bool Pawn::OnTouchEvent(TouchEvents event) { + if (gesture_index < 0) + return false; + + cell ret; + + amx_Push(&amx, (cell)event); + + int result = amx_Exec(&amx, &ret, gesture_index); + if (result != AMX_ERR_NONE) { + ShowError(result); + return true; + } + + return ret != 0; +} + +bool Pawn::OnTouchEvent(uint16_t x, uint16_t y) { + if (touch_index < 0) + return false; + + cell ret; + + amx_Push(&amx, y); + amx_Push(&amx, x); + + int result = amx_Exec(&amx, &ret, touch_index); + if (result != AMX_ERR_NONE) { + ShowError(result); + return true; + } + + return ret != 0; +} diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index 58d3f4222f..79cbbd4cac 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -25,6 +25,9 @@ namespace Pinetime { void ShowError(unsigned int amx_err); void ShowError(const char* msg); + bool OnTouchEvent(TouchEvents event) override; + bool OnTouchEvent(uint16_t x, uint16_t y) override; + Utility::DirtyValue> currentDateTime {}; AppControllers& controllers; @@ -32,7 +35,7 @@ namespace Pinetime { private: AMX amx; - int refresh_index; + int refresh_index, touch_index, gesture_index; lv_task_t* taskRefresh = 0; unsigned int queued_error = 0; From 2a7e5eda8e2fcb9d6dea0476ec314db83e5f1748 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 30 Dec 2025 01:00:38 +0100 Subject: [PATCH 18/26] Modify amxpool to use a struct rather than global vars --- src/displayapp/screens/Pawn.cpp | 9 ++- src/displayapp/screens/Pawn.h | 4 ++ src/pawn/amxpool.c | 104 +++++++++++++++----------------- src/pawn/amxpool.h | 23 +++++-- 4 files changed, 76 insertions(+), 64 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index cf87db0cfb..d22ce0b5df 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -365,10 +365,10 @@ static int AMXAPI prun_Overlay(AMX* amx, int index) { tbl = (AMX_OVERLAYINFO*) (amx->base + hdr->overlays) + index; amx->codesize = tbl->size; - amx->code = (unsigned char*) amx_poolfind(index); + amx->code = (unsigned char*) amx_poolfind(&PAWN_INST->amx_pool, index); if (amx->code == NULL) { - if ((amx->code = (unsigned char*) amx_poolalloc(tbl->size, index)) == NULL) + if ((amx->code = (unsigned char*) amx_poolalloc(&PAWN_INST->amx_pool, tbl->size, index)) == NULL) return AMX_ERR_OVERLAY; memcpy(amx->code, program + hdr->cod + tbl->offset, tbl->size); @@ -388,6 +388,7 @@ int Pawn::LoadProgram() { return AMX_ERR_FORMAT; memset(&amx, 0, sizeof(amx)); + amx.userdata[0] = this; header = malloc(hdr.cod); if (header == NULL) @@ -407,7 +408,7 @@ int Pawn::LoadProgram() { if (overlaypool == NULL) return AMX_ERR_MEMORY; - amx_poolinit(overlaypool, max_overlay_size + overlaypool_overhead); + amx_poolinit(&amx_pool, overlaypool, max_overlay_size + overlaypool_overhead); amx.data = (unsigned char*) datablock; amx.overlay = prun_Overlay; @@ -469,8 +470,6 @@ Pawn::Pawn(AppControllers& controllers) : controllers(controllers) { return; } - amx.userdata[0] = this; - lv_obj_set_user_data(lv_scr_act(), &amx); cell* font; diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index 79cbbd4cac..2e952e39eb 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -9,6 +9,7 @@ #include #include "pawn/amx.h" +#include "pawn/amxpool.h" namespace Pinetime { namespace Applications { @@ -33,8 +34,11 @@ namespace Pinetime { Widgets::StatusIcons* statusIcons = nullptr; + amxPool amx_pool; + private: AMX amx; + int refresh_index, touch_index, gesture_index; lv_task_t* taskRefresh = 0; unsigned int queued_error = 0; diff --git a/src/pawn/amxpool.c b/src/pawn/amxpool.c index 9423e226fb..e710f34e0f 100644 --- a/src/pawn/amxpool.c +++ b/src/pawn/amxpool.c @@ -45,28 +45,24 @@ typedef struct tagARENA { unsigned short lru; } ARENA; -static void *pool_base; -static unsigned pool_size; -static unsigned short pool_lru; - -static void touchblock(ARENA *hdr); -static ARENA *findblock(int index); +static void touchblock(amxPool *pool, ARENA *hdr); +static ARENA *findblock(amxPool *pool, int index); /* amx_poolinit() initializes the memory pool for the allocated blocks. * If parameter pool is NULL, the existing pool is cleared (without changing * its position or size). */ -void amx_poolinit(void *pool, unsigned size) +void amx_poolinit(amxPool *pool, void *buffer, unsigned size) { - assert(pool!=NULL || pool_base!=NULL); - if (pool!=NULL) { + assert(buffer!=NULL || pool->base!=NULL); + if (buffer!=NULL) { assert(size>sizeof(ARENA)); /* save parameters in global variables, then "free" the entire pool */ - pool_base=pool; - pool_size=size; + pool->base=buffer; + pool->size=size; } /* if */ - pool_lru=0; - amx_poolfree(NULL); + pool->lru=0; + amx_poolfree(pool, NULL); } /* amx_poolfree() releases a block allocated earlier. The parameter must have @@ -76,25 +72,25 @@ void amx_poolinit(void *pool, unsigned size) * When parameter "block" is NULL, the pool is re-initialized (meaning that * all blocks are freed). */ -void amx_poolfree(void *block) +void amx_poolfree(amxPool *pool, void *block) { ARENA *hdr,*hdr2; unsigned sz; - assert(pool_base!=NULL); - assert(pool_size>sizeof(ARENA)); + assert(pool->base!=NULL); + assert(pool->size>sizeof(ARENA)); /* special case: if "block" is NULL, create a single free space */ if (block==NULL) { /* store an arena header at the start of the pool */ - hdr=(ARENA*)pool_base; - hdr->blocksize=pool_size-sizeof(ARENA); + hdr=(ARENA*)pool->base; + hdr->blocksize=pool->size-sizeof(ARENA); hdr->index=-1; hdr->lru=0; } else { hdr=(ARENA*)((char*)block-sizeof(ARENA)); - assert((char*)hdr>=(char*)pool_base && (char*)hdr<(char*)pool_base+pool_size); - assert(hdr->blocksize=(char*)pool->base && (char*)hdr<(char*)pool->base+pool->size); + assert(hdr->blocksizesize); /* free this block */ hdr->index=-1; @@ -105,11 +101,11 @@ void amx_poolfree(void *block) hdr->blocksize+=hdr2->blocksize+sizeof(ARENA); /* try to coalesce with the previous block */ - if ((void*)hdr!=pool_base) { - sz=pool_size; - hdr2=(ARENA*)pool_base; + if ((void*)hdr!=pool->base) { + sz=pool->size; + hdr2=(ARENA*)pool->base; while (sz>0 && (char*)hdr2+hdr2->blocksize+sizeof(ARENA)!=(char*)hdr) { - assert(sz<=pool_size); + assert(sz<=pool->size); sz-=hdr2->blocksize+sizeof(ARENA); hdr2=(ARENA*)((char*)hdr2+hdr2->blocksize+sizeof(ARENA)); } /* while */ @@ -136,7 +132,7 @@ void amx_poolfree(void *block) * every iteration (without considering the size of the block or whether that * block is adjacent to a free block). */ -void *amx_poolalloc(unsigned size,int index) +void *amx_poolalloc(amxPool *pool, unsigned size,int index) { ARENA *hdr,*hdrlru; unsigned sz; @@ -144,12 +140,12 @@ void *amx_poolalloc(unsigned size,int index) assert(size>0); assert(index>=0 && index<=SHRT_MAX); - assert(findblock(index)==NULL); + assert(findblock(pool, index)==NULL); /* align the size to a cell boundary */ if ((size % sizeof(cell))!=0) size+=sizeof(cell)-(size % sizeof(cell)); - if (size+sizeof(ARENA)>pool_size) + if (size+sizeof(ARENA)>pool->size) return NULL; /* requested block does not fit in the pool */ /* find a block large enough to get the size plus an arena header; at @@ -158,13 +154,13 @@ void *amx_poolalloc(unsigned size,int index) * the block with the lowest LRU count and tries again */ do { - sz=pool_size; - hdr=(ARENA*)pool_base; + sz=pool->size; + hdr=(ARENA*)pool->base; hdrlru=hdr; minlru=USHRT_MAX; while (sz>0) { - assert(sz<=pool_size); - assert((char*)hdr>=(char*)pool_base && (char*)hdr<(char*)pool_base+pool_size); + assert(sz<=pool->size); + assert((char*)hdr>=(char*)pool->base && (char*)hdr<(char*)pool->base+pool->size); if (hdr->index==-1 && hdr->blocksize>=size) break; if (hdr->index!=-1 && hdr->lrublocksize+sizeof(ARENA); hdr=(ARENA*)((char*)hdr+hdr->blocksize+sizeof(ARENA)); } /* while */ - assert(sz<=pool_size); + assert(sz<=pool->size); if (sz==0) { /* free up memory and try again */ assert(hdrlru->index!=-1); - amx_poolfree((char*)hdrlru+sizeof(ARENA)); + amx_poolfree(pool, (char*)hdrlru+sizeof(ARENA)); } /* if */ } while (sz==0); @@ -194,7 +190,7 @@ void *amx_poolalloc(unsigned size,int index) } /* if */ hdr->blocksize=size; hdr->index=(short)index; - touchblock(hdr); /* set LRU field */ + touchblock(pool, hdr); /* set LRU field */ return (void*)((char*)hdr+sizeof(ARENA)); } @@ -204,65 +200,65 @@ void *amx_poolalloc(unsigned size,int index) * -1 represents a free block (actually, only positive values are valid). * When amx_poolfind() finds the block, it increments its LRU count. */ -void *amx_poolfind(int index) +void *amx_poolfind(amxPool *pool, int index) { - ARENA *hdr=findblock(index); + ARENA *hdr=findblock(pool, index); if (hdr==NULL) return NULL; - touchblock(hdr); + touchblock(pool, hdr); return (void*)((char*)hdr+sizeof(ARENA)); } -int amx_poolprotect(int index) +int amx_poolprotect(amxPool *pool, int index) { - ARENA *hdr=findblock(index); + ARENA *hdr=findblock(pool, index); if (hdr==NULL) return AMX_ERR_GENERAL; hdr->lru=PROTECT_LRU; return AMX_ERR_NONE; } -static ARENA *findblock(int index) +static ARENA *findblock(amxPool *pool, int index) { ARENA *hdr; unsigned sz; assert(index>=0); - sz=pool_size; - hdr=(ARENA*)pool_base; + sz=pool->size; + hdr=(ARENA*)pool->base; while (sz>0 && hdr->index!=index) { - assert(sz<=pool_size); - assert((char*)hdr>=(char*)pool_base && (char*)hdr<(char*)pool_base+pool_size); + assert(sz<=pool->size); + assert((char*)hdr>=(char*)pool->base && (char*)hdr<(char*)pool->base+pool->size); sz-=hdr->blocksize+sizeof(ARENA); hdr=(ARENA*)((char*)hdr+hdr->blocksize+sizeof(ARENA)); } /* while */ - assert(sz<=pool_size); + assert(sz<=pool->size); return (sz>0 && hdr->index==index) ? hdr : NULL; } -static void touchblock(ARENA *hdr) +static void touchblock(amxPool *pool, ARENA *hdr) { assert(hdr!=NULL); - if (++pool_lru >= PROTECT_LRU) - pool_lru=0; - hdr->lru=pool_lru; + if (++pool->lru >= PROTECT_LRU) + pool->lru=0; + hdr->lru=pool->lru; /* special case: if the overlay LRU count wrapped back to zero, set the * LRU count of all blocks to zero, but set the count of the block just * touched to 1 (skip blocks marked as protected, too) */ - if (pool_lru==0) { + if (pool->lru==0) { ARENA *hdr2; - unsigned sz=pool_size; - hdr2=(ARENA*)pool_base; + unsigned sz=pool->size; + hdr2=(ARENA*)pool->base; while (sz>0) { - assert(sz<=pool_size); + assert(sz<=pool->size); if (hdr2->lru!=PROTECT_LRU) hdr2->lru=0; sz-=hdr2->blocksize+sizeof(ARENA); hdr2=(ARENA*)((char*)hdr2+hdr2->blocksize+sizeof(ARENA)); } /* while */ assert(sz==0); - hdr->lru=++pool_lru; + hdr->lru=++pool->lru; } /* if */ } diff --git a/src/pawn/amxpool.h b/src/pawn/amxpool.h index f375515d0f..eace865eba 100644 --- a/src/pawn/amxpool.h +++ b/src/pawn/amxpool.h @@ -20,11 +20,24 @@ #ifndef AMXPOOL_H_INCLUDED #define AMXPOOL_H_INCLUDED -void amx_poolinit(void *pool, unsigned size); -void *amx_poolalloc(unsigned size, int index); -void amx_poolfree(void *block); -void *amx_poolfind(int index); -int amx_poolprotect(int index); +#if defined(__cplusplus) +extern "C" { +#endif +typedef struct amxPool { + void *base; + unsigned size; + unsigned short lru; +} amxPool; + +void amx_poolinit(amxPool *pool, void *buffer, unsigned size); +void *amx_poolalloc(amxPool *pool, unsigned size, int index); +void amx_poolfree(amxPool *pool, void *block); +void *amx_poolfind(amxPool *pool, int index); +int amx_poolprotect(amxPool *pool, int index); + +#if defined(__cplusplus) +} +#endif #endif /* AMXPOOL_H_INCLUDED */ From fbbe598757dda6222e5c1b328b79cf2a6b7faa0d Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 30 Dec 2025 01:59:50 +0100 Subject: [PATCH 19/26] Replace watchface --- src/displayapp/screens/Pawn.cpp | 27 ++- src/displayapp/screens/Pawn.h | 3 +- src/displayapp/screens/WatchFaceDigital.cpp | 191 +------------------- src/displayapp/screens/WatchFaceDigital.h | 75 +------- src/displayapp/screens/program.h | 90 ++------- src/displayapp/screens/watchface_digital.h | 63 +++++++ 6 files changed, 102 insertions(+), 347 deletions(-) create mode 100644 src/displayapp/screens/watchface_digital.h diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index d22ce0b5df..483de847fb 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -2,12 +2,6 @@ #include #include -extern "C" { -#include "pawn/amxpool.h" -} - -#include "program.h" - using namespace Pinetime::Applications::Screens; enum { @@ -288,7 +282,7 @@ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { return bufc - buf; } -static cell AMX_NATIVE_CALL F_get_datetime(AMX* amx, const cell* params) { +cell AMX_NATIVE_CALL F_get_datetime(AMX* amx, const cell* params) { ASSERT_PARAMS(1); Pawn* pawn = PAWN_INST; @@ -371,18 +365,16 @@ static int AMXAPI prun_Overlay(AMX* amx, int index) { if ((amx->code = (unsigned char*) amx_poolalloc(&PAWN_INST->amx_pool, tbl->size, index)) == NULL) return AMX_ERR_OVERLAY; - memcpy(amx->code, program + hdr->cod + tbl->offset, tbl->size); + memcpy(amx->code, PAWN_INST->file + hdr->cod + tbl->offset, tbl->size); } return AMX_ERR_NONE; } int Pawn::LoadProgram() { - (void) program_len; - int result; AMX_HEADER hdr; - memcpy(&hdr, program, sizeof(hdr)); + memcpy(&hdr, file, sizeof(hdr)); if (hdr.magic != AMX_MAGIC) return AMX_ERR_FORMAT; @@ -394,14 +386,14 @@ int Pawn::LoadProgram() { if (header == NULL) return AMX_ERR_MEMORY; - memcpy(header, program, hdr.cod); + memcpy(header, file, hdr.cod); if (hdr.flags & AMX_FLAG_OVERLAY) { datablock = malloc(hdr.stp - hdr.dat); // This block contains data, heap and stack if (datablock == NULL) return AMX_ERR_MEMORY; - memcpy(datablock, program + hdr.dat, hdr.hea - hdr.dat); + memcpy(datablock, file + hdr.dat, hdr.hea - hdr.dat); constexpr int overlaypool_overhead = 8; overlaypool = malloc(max_overlay_size + overlaypool_overhead); @@ -427,7 +419,7 @@ int Pawn::LoadProgram() { if (datablock == NULL) return AMX_ERR_MEMORY; - memcpy(datablock, program, hdr.size); + memcpy(datablock, file, hdr.size); result = amx_Init(&amx, datablock); if (result != AMX_ERR_NONE) { @@ -463,7 +455,12 @@ extern "C" const AMX_NATIVE pawn_natives[] = { F_raise_error, }; -Pawn::Pawn(AppControllers& controllers) : controllers(controllers) { +#include "program.h" +Pawn::Pawn(AppControllers& controllers) : Pawn(program, controllers) { + (void) program_len; +} + +Pawn::Pawn(const uint8_t *file, AppControllers& controllers) : controllers(controllers), file(file) { int result = LoadProgram(); if (result != AMX_ERR_NONE) { ShowError(result); diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index 2e952e39eb..38ef071aa0 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -18,6 +18,7 @@ namespace Pinetime { class Pawn : public Screen { public: Pawn(AppControllers& controllers); + Pawn(const uint8_t *file, AppControllers& controllers); ~Pawn() override; void Refresh() override; @@ -35,6 +36,7 @@ namespace Pinetime { Widgets::StatusIcons* statusIcons = nullptr; amxPool amx_pool; + const uint8_t *file; private: AMX amx; @@ -56,7 +58,6 @@ namespace Pinetime { static constexpr const char* icon = "P"; static Screens::Screen* Create(AppControllers& controllers) { - // sizeof(Pawn) return new Screens::Pawn(controllers); }; diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 3163c6e750..8605231b95 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -1,194 +1,9 @@ #include "displayapp/screens/WatchFaceDigital.h" -#include -#include - -#include "displayapp/screens/NotificationIcon.h" -#include "displayapp/screens/Symbols.h" -#include "displayapp/screens/WeatherSymbols.h" -#include "components/battery/BatteryController.h" -#include "components/ble/BleController.h" -#include "components/ble/NotificationManager.h" -#include "components/heartrate/HeartRateController.h" -#include "components/motion/MotionController.h" -#include "components/ble/SimpleWeatherService.h" -#include "components/settings/Settings.h" +#include "watchface_digital.h" +#include "WatchFaceDigital.h" using namespace Pinetime::Applications::Screens; -WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController, - const Controllers::Battery& batteryController, - const Controllers::Ble& bleController, - const Controllers::AlarmController& alarmController, - Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController, - Controllers::SimpleWeatherService& weatherService) - : currentDateTime {{}}, - dateTimeController {dateTimeController}, - notificationManager {notificationManager}, - settingsController {settingsController}, - heartRateController {heartRateController}, - motionController {motionController}, - weatherService {weatherService}, - statusIcons(batteryController, bleController, alarmController) { - - statusIcons.Create(); - - notificationIcon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME); - lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); - lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); - - weatherIcon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); - lv_label_set_text(weatherIcon, ""); - lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_MID, -20, 50); - lv_obj_set_auto_realign(weatherIcon, true); - - temperature = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - lv_label_set_text(temperature, ""); - lv_obj_align(temperature, nullptr, LV_ALIGN_IN_TOP_MID, 20, 50); - - label_date = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); - lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - - label_time = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); - - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); - - label_time_ampm = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(label_time_ampm, ""); - lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -30, -55); - - heartbeatIcon = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat); - lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); - lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); - - heartbeatValue = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); - lv_label_set_text_static(heartbeatValue, ""); - lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0); - - stepValue = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); - lv_label_set_text_static(stepValue, "0"); - lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - - stepIcon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); - lv_label_set_text_static(stepIcon, Symbols::shoe); - lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); - - taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); - Refresh(); -} - -WatchFaceDigital::~WatchFaceDigital() { - lv_task_del(taskRefresh); - lv_obj_clean(lv_scr_act()); -} - -void WatchFaceDigital::Refresh() { - statusIcons.Update(); - - notificationState = notificationManager.AreNewNotificationsAvailable(); - if (notificationState.IsUpdated()) { - lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); - } - - currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); - - if (currentDateTime.IsUpdated()) { - uint8_t hour = dateTimeController.Hours(); - uint8_t minute = dateTimeController.Minutes(); - - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - char ampmChar[3] = "AM"; - if (hour == 0) { - hour = 12; - } else if (hour == 12) { - ampmChar[0] = 'P'; - } else if (hour > 12) { - hour = hour - 12; - ampmChar[0] = 'P'; - } - lv_label_set_text(label_time_ampm, ampmChar); - lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute); - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); - } else { - lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute); - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); - } - - currentDate = std::chrono::time_point_cast(currentDateTime.Get()); - if (currentDate.IsUpdated()) { - uint16_t year = dateTimeController.Year(); - uint8_t day = dateTimeController.Day(); - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - lv_label_set_text_fmt(label_date, - "%s %d %s %d", - dateTimeController.DayOfWeekShortToString(), - day, - dateTimeController.MonthShortToString(), - year); - } else { - lv_label_set_text_fmt(label_date, - "%s %s %d %d", - dateTimeController.DayOfWeekShortToString(), - dateTimeController.MonthShortToString(), - day, - year); - } - lv_obj_realign(label_date); - } - } - - heartbeat = heartRateController.HeartRate(); - heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; - if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) { - if (heartbeatRunning.Get()) { - lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); - lv_label_set_text_fmt(heartbeatValue, "%d", heartbeat.Get()); - } else { - lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B)); - lv_label_set_text_static(heartbeatValue, ""); - } - - lv_obj_realign(heartbeatIcon); - lv_obj_realign(heartbeatValue); - } - - stepCount = motionController.NbSteps(); - if (stepCount.IsUpdated()) { - lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get()); - lv_obj_realign(stepValue); - lv_obj_realign(stepIcon); - } - - currentWeather = weatherService.Current(); - if (currentWeather.IsUpdated()) { - auto optCurrentWeather = currentWeather.Get(); - if (optCurrentWeather) { - int16_t temp = optCurrentWeather->temperature.Celsius(); - char tempUnit = 'C'; - if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { - temp = optCurrentWeather->temperature.Fahrenheit(); - tempUnit = 'F'; - } - lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); - lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); - } else { - lv_label_set_text_static(temperature, ""); - lv_label_set_text(weatherIcon, ""); - } - lv_obj_realign(temperature); - lv_obj_realign(weatherIcon); - } +WatchFaceDigital::WatchFaceDigital(AppControllers& controllers) : Pawn(watchface_digital, controllers) { } diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index e3a1ac649a..5a073881a3 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -4,76 +4,17 @@ #include #include #include -#include "displayapp/screens/Screen.h" -#include "components/datetime/DateTimeController.h" -#include "components/ble/SimpleWeatherService.h" -#include "components/ble/BleController.h" -#include "displayapp/widgets/StatusIcons.h" +#include "displayapp/screens/Pawn.h" #include "utility/DirtyValue.h" #include "displayapp/apps/Apps.h" namespace Pinetime { - namespace Controllers { - class Settings; - class Battery; - class Ble; - class AlarmController; - class NotificationManager; - class HeartRateController; - class MotionController; - } - namespace Applications { namespace Screens { - class WatchFaceDigital : public Screen { + class WatchFaceDigital : public Pawn { public: - WatchFaceDigital(Controllers::DateTime& dateTimeController, - const Controllers::Battery& batteryController, - const Controllers::Ble& bleController, - const Controllers::AlarmController& alarmController, - Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController, - Controllers::SimpleWeatherService& weather); - ~WatchFaceDigital() override; - - void Refresh() override; - - private: - uint8_t displayedHour = -1; - uint8_t displayedMinute = -1; - - Utility::DirtyValue> currentDateTime {}; - Utility::DirtyValue stepCount {}; - Utility::DirtyValue heartbeat {}; - Utility::DirtyValue heartbeatRunning {}; - Utility::DirtyValue notificationState {}; - Utility::DirtyValue> currentWeather {}; - - Utility::DirtyValue> currentDate; - - lv_obj_t* label_time; - lv_obj_t* label_time_ampm; - lv_obj_t* label_date; - lv_obj_t* heartbeatIcon; - lv_obj_t* heartbeatValue; - lv_obj_t* stepIcon; - lv_obj_t* stepValue; - lv_obj_t* notificationIcon; - lv_obj_t* weatherIcon; - lv_obj_t* temperature; - - Controllers::DateTime& dateTimeController; - Controllers::NotificationManager& notificationManager; - Controllers::Settings& settingsController; - Controllers::HeartRateController& heartRateController; - Controllers::MotionController& motionController; - Controllers::SimpleWeatherService& weatherService; - - lv_task_t* taskRefresh; - Widgets::StatusIcons statusIcons; + WatchFaceDigital(AppControllers& controllers); }; } @@ -83,15 +24,7 @@ namespace Pinetime { static constexpr const char* name = "Digital"; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::WatchFaceDigital(controllers.dateTimeController, - controllers.batteryController, - controllers.bleController, - controllers.alarmController, - controllers.notificationManager, - controllers.settingsController, - controllers.heartRateController, - controllers.motionController, - *controllers.weatherController); + return new Screens::WatchFaceDigital(controllers); }; static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index 3de4974d4e..305a797534 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,74 +1,20 @@ const unsigned char program[] = { - 0x4c, 0x03, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, - 0x74, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x4c, 0x03, 0x00, 0x00, - 0x14, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x60, 0x01, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x40, 0x62, 0x74, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, 0x6f, - 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, 0x00, 0xad, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x08, 0x00, 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x08, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x3c, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x8e, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf2, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, - 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0xfc, 0xff, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x88, 0x00, 0xfc, 0xff, 0x8e, 0x00, 0x1e, 0x00, 0x8e, 0x00, 0x28, 0x00, - 0x90, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x18, 0x00, 0x90, 0x00, 0xfc, 0xff, - 0x70, 0x00, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xed, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xee, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x24, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x24, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xbc, 0x00, 0x00, 0x00, 0x83, 0x00, 0x24, 0x00, 0xa0, 0x00, 0x08, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x24, 0x00, 0xa0, 0x00, 0x0c, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x3c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x3c, 0x00, 0x8f, 0x00, 0x04, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x60, 0x00, 0x92, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x24, 0x00, - 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x60, 0x00, - 0x83, 0x00, 0x24, 0x00, 0xa0, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x5c, 0x00, 0x92, 0x00, 0x64, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x3c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x3c, 0x00, 0x8f, 0x00, 0x08, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x3a, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, - 0x6e, 0x74, 0x62, 0x40, 0x72, 0x72, 0x65, 0x5f, 0x00, 0x00, 0x72, 0x6f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, - 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, - 0x00, 0x64, 0x25, 0x20 + 0xc8, 0x00, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, + 0x90, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x14, 0x00, 0x8e, 0x00, 0x14, 0x00, 0x8f, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x04, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x69, 0x6c, 0x43, + 0x20, 0x3a, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x30 }; -unsigned int program_len = 844; +unsigned int program_len = 200; diff --git a/src/displayapp/screens/watchface_digital.h b/src/displayapp/screens/watchface_digital.h new file mode 100644 index 0000000000..f27257e4a7 --- /dev/null +++ b/src/displayapp/screens/watchface_digital.h @@ -0,0 +1,63 @@ +const unsigned char watchface_digital[] = { + 0xc8, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x00, + 0x90, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x14, 0x01, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x57, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, + 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, + 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x08, 0x00, + 0x92, 0x00, 0x20, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x3c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, 0x89, 0x80, 0x00, 0x00, + 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x87, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, + 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x24, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xee, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x2c, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0xbc, 0x00, 0x00, 0x00, 0x83, 0x00, 0x2c, 0x00, 0xa0, 0x00, 0x08, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x2c, 0x00, 0xa0, 0x00, 0x0c, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x44, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x0c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x54, 0x00, 0x92, 0x00, 0x50, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x2c, 0x00, + 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x54, 0x00, + 0x83, 0x00, 0x2c, 0x00, 0xa0, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x50, 0x00, 0x92, 0x00, 0x58, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x0c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x08, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, + 0x30, 0x3a, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, + 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, + 0x00, 0x64, 0x25, 0x20 +}; +unsigned int watchface_digital_len = 712; From 56fa587634f7ab90ff40516c43757e8869686820 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 30 Dec 2025 04:33:18 +0100 Subject: [PATCH 20/26] Rewrite digital watchface in pawn and add pawn scripts --- src/displayapp/screens/Pawn.cpp | 112 ++++++++--- src/displayapp/screens/program.h | 28 ++- src/displayapp/screens/watchface_digital.h | 212 ++++++++++++++++----- src/pawn/programs/include/infinitime.inc | 66 +++++++ src/pawn/programs/include/lvgl.inc | 196 +++++++++++++++++++ src/pawn/programs/include/symbols.inc | 54 ++++++ src/pawn/programs/program.p | 7 + src/pawn/programs/watchface_digital.p | 118 ++++++++++++ 8 files changed, 708 insertions(+), 85 deletions(-) create mode 100644 src/pawn/programs/include/infinitime.inc create mode 100644 src/pawn/programs/include/lvgl.inc create mode 100644 src/pawn/programs/include/symbols.inc create mode 100644 src/pawn/programs/program.p create mode 100644 src/pawn/programs/watchface_digital.p diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 483de847fb..835eb8bf90 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -2,12 +2,15 @@ #include #include +#include "components/heartrate/HeartRateController.h" + using namespace Pinetime::Applications::Screens; enum { PAWN_ERR_PARAMCOUNT = 100, PAWN_ERR_MISSINGHANDLER, PAWN_ERR_INVALIDSTRING, + PAWN_ERR_INVALIDSETTING, PAWN_ERR_FIRST = PAWN_ERR_PARAMCOUNT, }; @@ -24,6 +27,15 @@ enum { constexpr int max_overlay_size = 512; +static void label_set_text(AMX* amx, lv_obj_t* label, cell str) { + char* text; + amx_StrParam_Type(amx, str, text, char*); + if (text != NULL) + lv_label_set_text(label, text); + else + lv_label_set_text_static(label, ""); +} + static void event_handler(lv_obj_t* obj, lv_event_t event) { if (event == LV_EVENT_DELETE) return; @@ -45,9 +57,12 @@ static cell AMX_NATIVE_CALL F_lv_scr_act(AMX* amx, const cell* params) { } static cell AMX_NATIVE_CALL F_lv_label_create(AMX* amx, const cell* params) { - ASSERT_PARAMS(2); + ASSERT_PARAMS(3); + + lv_obj_t* label = lv_label_create(PARAMS_OBJ(1) ?: lv_scr_act(), PARAMS_OBJ(2)); + label_set_text(amx, label, params[3]); - return (cell) lv_label_create(PARAMS_OBJ(1) ?: lv_scr_act(), PARAMS_OBJ(2)); + return (cell) label; } static cell AMX_NATIVE_CALL F_lv_btn_create(AMX* amx, const cell* params) { @@ -93,15 +108,7 @@ static cell AMX_NATIVE_CALL F_lv_obj_set_event_cb(AMX* amx, const cell* params) static cell AMX_NATIVE_CALL F_lv_label_set_text(AMX* amx, const cell* params) { ASSERT_PARAMS(2); - lv_obj_t* label = PARAMS_OBJ(1); - - char* text; - amx_StrParam_Type(amx, params[2], text, char*); - if (text != NULL) - lv_label_set_text(label, text); - else - amx_RaiseError(amx, PAWN_ERR_INVALIDSTRING); - + label_set_text(amx, PARAMS_OBJ(1), params[2]); return 0; } @@ -282,7 +289,7 @@ static cell AMX_NATIVE_CALL F_sprintf(AMX* amx, const cell* params) { return bufc - buf; } -cell AMX_NATIVE_CALL F_get_datetime(AMX* amx, const cell* params) { +cell AMX_NATIVE_CALL F_read_datetime(AMX* amx, const cell* params) { ASSERT_PARAMS(1); Pawn* pawn = PAWN_INST; @@ -290,18 +297,21 @@ cell AMX_NATIVE_CALL F_get_datetime(AMX* amx, const cell* params) { pawn->currentDateTime = std::chrono::time_point_cast(pawn->controllers.dateTimeController.CurrentDateTime()); cell* ret = amx_Address(amx, params[1]); + cell data[] = { + pawn->controllers.dateTimeController.Minutes(), + pawn->controllers.dateTimeController.Hours(), + pawn->controllers.dateTimeController.Day(), + pawn->controllers.dateTimeController.Year(), + }; - ret[0] = pawn->currentDateTime.IsUpdated(); - ret[1] = pawn->controllers.dateTimeController.Seconds(); - ret[2] = pawn->controllers.dateTimeController.Minutes(); - ret[3] = pawn->controllers.dateTimeController.Hours(); - ret[4] = pawn->controllers.dateTimeController.Day(); - ret[5] = pawn->controllers.dateTimeController.Year(); - - return 0; + if (memcmp(ret, data, sizeof(data)) == 0) { + return 0; + } + memcpy(ret, data, sizeof(data)); + return 1; } -static cell AMX_NATIVE_CALL F_get_datetime_short_str(AMX* amx, const cell* params) { +static cell AMX_NATIVE_CALL F_read_datetime_short_str(AMX* amx, const cell* params) { ASSERT_PARAMS(2); Pawn* pawn = PAWN_INST; @@ -343,6 +353,46 @@ static cell AMX_NATIVE_CALL F_status_icons_update(AMX* amx, const cell*) { return 0; } +static cell AMX_NATIVE_CALL F_has_new_notifications(AMX* amx, const cell*) { + return PAWN_INST->controllers.notificationManager.AreNewNotificationsAvailable(); +} + +static cell AMX_NATIVE_CALL F_get_setting(AMX* amx, const cell* params) { + ASSERT_PARAMS(1); + +#define SETTING(n, m) \ + case n: \ + return (cell) PAWN_INST->controllers.settingsController.m(); + + switch (params[1]) { + SETTING(0, GetWatchFace) + SETTING(1, GetChimeOption) + SETTING(2, GetPrideFlag) + SETTING(3, GetClockType) + SETTING(4, GetWeatherFormat) + SETTING(5, GetNotificationStatus) + SETTING(6, GetStepsGoal) + + default: + amx_RaiseError(amx, PAWN_ERR_INVALIDSETTING); + return 0; + } + +#undef SETTING +} + +static cell AMX_NATIVE_CALL F_get_heartrate(AMX* amx, const cell*) { + return PAWN_INST->controllers.heartRateController.HeartRate(); +} + +static cell AMX_NATIVE_CALL F_get_heartrate_state(AMX* amx, const cell*) { + return (cell) PAWN_INST->controllers.heartRateController.State(); +} + +static cell AMX_NATIVE_CALL F_get_step_number(AMX* amx, const cell*) { + return PAWN_INST->controllers.motionController.NbSteps(); +} + static cell AMX_NATIVE_CALL F_raise_error(AMX* amx, const cell* params) { ASSERT_PARAMS(1); @@ -448,19 +498,25 @@ extern "C" const AMX_NATIVE pawn_natives[] = { F_lv_obj_set_style_local_color, F_lv_obj_set_style_local_opa, F_lv_obj_set_style_local_ptr, - F_get_datetime, - F_get_datetime_short_str, + F_read_datetime, + F_read_datetime_short_str, F_status_icons_create, F_status_icons_update, + F_has_new_notifications, + F_get_setting, + F_get_heartrate, + F_get_heartrate_state, + F_get_step_number, F_raise_error, }; #include "program.h" + Pawn::Pawn(AppControllers& controllers) : Pawn(program, controllers) { (void) program_len; } -Pawn::Pawn(const uint8_t *file, AppControllers& controllers) : controllers(controllers), file(file) { +Pawn::Pawn(const uint8_t* file, AppControllers& controllers) : controllers(controllers), file(file) { int result = LoadProgram(); if (result != AMX_ERR_NONE) { ShowError(result); @@ -532,8 +588,10 @@ void Pawn::ShowError(unsigned int amx_err) { "INDEX", "DEBUG", "INIT", "USERDATA", "INIT_JIT", "PARAMS", "DOMAIN", "GENERAL", "OVERLAY", }; static const char* pawn_err_msgs[] = { - "invalid parameter count", // PAWN_ERR_PARAMCOUNT - "missing event handler", // PAWN_ERR_MISSINGHANDLER + "parameter count mismatch", // PAWN_ERR_PARAMCOUNT + "missing event handler", // PAWN_ERR_MISSINGHANDLER + "invalid string", // PAWN_ERR_INVALIDSTRING + "invalid setting", // PAWN_ERR_INVALIDSETTING }; if (amx_err == AMX_ERR_EXIT) { @@ -583,7 +641,7 @@ bool Pawn::OnTouchEvent(TouchEvents event) { cell ret; - amx_Push(&amx, (cell)event); + amx_Push(&amx, (cell) event); int result = amx_Exec(&amx, &ret, gesture_index); if (result != AMX_ERR_NONE) { diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index 305a797534..c7935463e3 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,20 +1,18 @@ const unsigned char program[] = { - 0xc8, 0x00, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, - 0x40, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, - 0x90, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0xb0, 0x00, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, + 0x78, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x14, 0x00, 0x8e, 0x00, 0x14, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x04, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x69, 0x6c, 0x43, - 0x20, 0x3a, 0x73, 0x6b, 0x00, 0x00, 0x00, 0x30 + 0x9c, 0x00, 0xfc, 0xff, 0x92, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, 0x8e, 0x00, 0x14, 0x00, + 0x8e, 0x00, 0x14, 0x00, 0x90, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, + 0xfb, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x04, 0x00, + 0x90, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x65, 0x48, + 0x6f, 0x77, 0x20, 0x6f, 0x00, 0x64, 0x6c, 0x72 }; -unsigned int program_len = 200; +unsigned int program_len = 176; diff --git a/src/displayapp/screens/watchface_digital.h b/src/displayapp/screens/watchface_digital.h index f27257e4a7..459ba68a3f 100644 --- a/src/displayapp/screens/watchface_digital.h +++ b/src/displayapp/screens/watchface_digital.h @@ -1,63 +1,189 @@ const unsigned char watchface_digital[] = { - 0xc8, 0x02, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x00, - 0x90, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0xb8, 0x08, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, + 0x64, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xb8, 0x08, 0x00, 0x00, + 0x80, 0x09, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x14, 0x01, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x03, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x9c, 0x00, 0xfc, 0xff, 0x80, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x7e, 0x00, 0x10, 0x00, 0x35, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, + 0x7e, 0x00, 0x10, 0x00, 0x89, 0x00, 0x0c, 0x00, 0x7e, 0x00, 0xfc, 0xff, + 0x9c, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0xec, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x87, 0x00, 0x30, 0x00, 0x92, 0x00, 0x48, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x08, 0x00, - 0x92, 0x00, 0x20, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x3c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, 0x89, 0x80, 0x00, 0x00, - 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, - 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x24, 0x00, 0x8f, 0x00, 0x04, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x1c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x04, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x20, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, + 0x1b, 0x1b, 0x1b, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x48, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x24, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, + 0x1b, 0x1b, 0xce, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x8e, 0x00, 0x13, 0x00, + 0x8f, 0x00, 0x20, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x2c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, + 0xe7, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x06, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x08, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x28, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, + 0xe7, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xfb, 0xff, 0x8e, 0x00, 0x10, 0x00, + 0x8f, 0x00, 0x2c, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x48, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x18, 0x00, + 0x8e, 0x00, 0x3c, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x48, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x10, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, + 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x10, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x10, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x48, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x14, 0x00, + 0x8e, 0x00, 0xc9, 0xff, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xee, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x2c, 0x00, + 0xee, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xbc, 0x00, 0x00, 0x00, 0x83, 0x00, 0x2c, 0x00, 0xa0, 0x00, 0x08, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x2c, 0x00, 0xa0, 0x00, 0x0c, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x44, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x0c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x23, 0x00, 0x00, 0x00, 0xd4, 0x01, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, + 0x83, 0x00, 0x50, 0x00, 0xa0, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x88, 0x00, 0xfc, 0xff, 0x7c, 0x00, 0x30, 0x00, 0xa4, 0x00, 0x01, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, + 0x84, 0x00, 0x0c, 0x00, 0x61, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x60, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x64, 0x00, 0x18, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x54, 0x00, 0x92, 0x00, 0x50, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x2c, 0x00, - 0xa0, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x54, 0x00, - 0x83, 0x00, 0x2c, 0x00, 0xa0, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x50, 0x00, 0x92, 0x00, 0x58, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x0c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0c, 0x00, 0x8f, 0x00, 0x08, 0x00, + 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x24, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x7e, 0x00, 0xfc, 0xff, 0x84, 0x00, 0x0c, 0x00, 0x5f, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0xa0, 0x00, 0xf4, 0xff, + 0x88, 0x00, 0xfc, 0xff, 0x92, 0x00, 0x50, 0x00, 0x94, 0x00, 0xfc, 0xff, + 0x7c, 0x00, 0x30, 0x00, 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x68, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x74, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x34, 0x00, + 0x8f, 0x00, 0x10, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x10, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x92, 0x00, 0x84, 0x00, + 0x92, 0x00, 0x80, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x30, 0x00, 0xa4, 0x00, 0x01, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x83, 0x00, 0x50, 0x00, + 0xa0, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x50, 0x00, + 0xa0, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x84, 0x00, + 0x92, 0x00, 0x80, 0x00, 0x92, 0x00, 0x88, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x50, 0x00, 0xa0, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x84, 0x00, 0x83, 0x00, 0x50, 0x00, 0xa0, 0x00, 0x08, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x80, 0x00, 0x92, 0x00, 0x94, 0x00, + 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x34, 0x00, + 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xed, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xa0, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x74, 0xfa, 0xff, 0xff, 0x23, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xa0, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x0c, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0xa4, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, + 0xeb, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0xa8, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x18, 0xfa, 0xff, 0xff, 0x88, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, + 0xea, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0xac, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x21, 0x00, 0x00, 0x00, + 0xf4, 0xf9, 0xff, 0xff, 0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x7e, 0x00, 0xfc, 0xff, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x66, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x01, 0x00, 0x88, 0x00, 0xfc, 0xff, 0x7e, 0x00, 0xfc, 0xff, + 0x23, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xac, 0x00, + 0xa4, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, + 0x1b, 0x1b, 0xce, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x92, 0x00, 0xa8, 0x00, 0x92, 0x00, 0xb0, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x34, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0x1b, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0xb4, 0x00, + 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xe9, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xb8, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x21, 0x00, 0x00, 0x00, 0xdc, 0xf8, 0xff, 0xff, 0x23, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x92, 0x00, 0xb8, 0x00, 0x92, 0x00, 0xbc, 0x00, + 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x34, 0x00, + 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x9c, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x88, 0xef, 0x00, 0x8b, 0x95, 0xef, + 0x00, 0xa9, 0x84, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, - 0x30, 0x3a, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, + 0x00, 0x00, 0x4d, 0x41, 0x00, 0x00, 0x4d, 0x50, 0x3a, 0x64, 0x32, 0x25, + 0x64, 0x32, 0x30, 0x25, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, - 0x00, 0x64, 0x25, 0x20 + 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x64, 0x25, 0x20, 0x73, + 0x00, 0x64, 0x25, 0x20, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, + 0x00, 0x64, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x25, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x25 }; -unsigned int watchface_digital_len = 712; +unsigned int watchface_digital_len = 2232; diff --git a/src/pawn/programs/include/infinitime.inc b/src/pawn/programs/include/infinitime.inc new file mode 100644 index 0000000000..12bd3b89a4 --- /dev/null +++ b/src/pawn/programs/include/infinitime.inc @@ -0,0 +1,66 @@ +#pragma library - + +#include "lvgl" + +#define DATETIME[.minute, .hour, .day, .year] + +native sprintf(out[], size=sizeof out, const fmt[], const ...) = -1 + +#define jetbrains_mono_extrabold_compressed font_jmec // Name truncated because symbols have a max length of 31 characters +public stock const ptr:jetbrains_mono_extrabold_compressed + +const touch_event: { + TOUCH_None = 0, + TOUCH_TAP, + TOUCH_SWIPE_LEFT, + TOUCH_SWIPE_RIGHT, + TOUCH_SWIPE_UP, + TOUCH_SWIPE_DOWN, + TOUCH_LONG_TAP, + TOUCH_DOUBLE_TAP, +} + +native bool: read_datetime(out[DATETIME]) = -15 +native read_datetime_short_str(day_of_week{4} = 0, month_of_year{4} = 0) = -16 + +native status_icons_create() = -17 +native status_icons_update() = -18 +native bool: has_new_notifications() = -19 + +const setting: { + SETTING_WATCHFACE = 0, + SETTING_CHIME_OPTION, + SETTING_PRIDE_FLAG, + SETTING_CLOCK_TYPE, + SETTING_WEATHER_FORMAT, + SETTING_NOTIFICATION_STATUS, + SETTING_STEPS_GOAL, +} +const { + CLOCK_TYPE_H24 = 0, + CLOCK_TYPE_H12 +} +native get_setting(setting: s) = -20 + +const heartrate_state: { + HEARTRATE_STOPPED = 0, + HEARTRATE_NOT_ENOUGH_DATA + HEARTRATE_NO_TOUCH + HEARTRATE_RUNNING +} +native get_heartrate() = -21 +native heartrate_state: get_heartrate_state() = -22 + +native get_step_number() = -23 + +native raise_error(err) = -24 + +forward @refresh() +forward @touch(x, y) +forward @gesture(touch_event: ev) + +stock swap(&old_val, new_val) { + var changed = old_val != new_val + old_val = new_val + return changed +} diff --git a/src/pawn/programs/include/lvgl.inc b/src/pawn/programs/include/lvgl.inc new file mode 100644 index 0000000000..ddfd72b045 --- /dev/null +++ b/src/pawn/programs/include/lvgl.inc @@ -0,0 +1,196 @@ +// Make the lv_obj tag be a strong tag without making the code ugly +#define lv_obj: LV_OBJ: + +const lv_state: { + LV_STATE_DEFAULT = 0x00, + LV_STATE_CHECKED = 0x01, + LV_STATE_FOCUSED = 0x02, + LV_STATE_EDITED = 0x04, + LV_STATE_HOVERED = 0x08, + LV_STATE_PRESSED = 0x10, + LV_STATE_DISABLED = 0x20, +} + +const lv_event: { + LV_EVENT_PRESSED = 0, + LV_EVENT_PRESSING, + LV_EVENT_PRESS_LOST, + LV_EVENT_SHORT_CLICKED, + LV_EVENT_LONG_PRESSED, + LV_EVENT_LONG_PRESSED_REPEAT, + LV_EVENT_CLICKED, + LV_EVENT_RELEASED, + LV_EVENT_DRAG_BEGIN, + LV_EVENT_DRAG_END, + LV_EVENT_DRAG_THROW_BEGIN, + LV_EVENT_GESTURE, + LV_EVENT_KEY, + LV_EVENT_FOCUSED, + LV_EVENT_DEFOCUSED, + LV_EVENT_LEAVE, + LV_EVENT_VALUE_CHANGED, + LV_EVENT_INSERT, + LV_EVENT_REFRESH, + LV_EVENT_APPLY, + LV_EVENT_CANCEL, + LV_EVENT_DELETE, +} + +const lv_align: { + LV_ALIGN_CENTER = 0, + LV_ALIGN_IN_TOP_LEFT, + LV_ALIGN_IN_TOP_MID, + LV_ALIGN_IN_TOP_RIGHT, + LV_ALIGN_IN_BOTTOM_LEFT, + LV_ALIGN_IN_BOTTOM_MID, + LV_ALIGN_IN_BOTTOM_RIGHT, + LV_ALIGN_IN_LEFT_MID, + LV_ALIGN_IN_RIGHT_MID, + LV_ALIGN_OUT_TOP_LEFT, + LV_ALIGN_OUT_TOP_MID, + LV_ALIGN_OUT_TOP_RIGHT, + LV_ALIGN_OUT_BOTTOM_LEFT, + LV_ALIGN_OUT_BOTTOM_MID, + LV_ALIGN_OUT_BOTTOM_RIGHT, + LV_ALIGN_OUT_LEFT_TOP, + LV_ALIGN_OUT_LEFT_MID, + LV_ALIGN_OUT_LEFT_BOTTOM, + LV_ALIGN_OUT_RIGHT_TOP, + LV_ALIGN_OUT_RIGHT_MID, + LV_ALIGN_OUT_RIGHT_BOTTOM, +} + +#define LV_STYLE_PROP_INIT(%1,%2,%3,%4) %1 = (((%2 << 4) + %3) | ((%4) << 8)) + +#define LV_STYLE_ATTR_NONE 0 +#define LV_STYLE_ATTR_INHERIT (1 << 7) + +#define LV_STYLE_ID_VALUE 0x0 +#define LV_STYLE_ID_COLOR 0x9 +#define LV_STYLE_ID_OPA 0xC +#define LV_STYLE_ID_PTR 0xE + +const lv_style_prop: { + // These lines are copied verbatim from lv_style.h + + LV_STYLE_PROP_INIT(LV_STYLE_RADIUS, 0x0, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_CLIP_CORNER, 0x0, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SIZE, 0x0, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_WIDTH, 0x0, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_HEIGHT, 0x0, LV_STYLE_ID_VALUE + 5, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_ANGLE, 0x0, LV_STYLE_ID_VALUE + 6, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_ZOOM, 0x0, LV_STYLE_ID_VALUE + 7, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_OPA_SCALE, 0x0, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_INHERIT), + + LV_STYLE_PROP_INIT(LV_STYLE_PAD_TOP, 0x1, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_PAD_BOTTOM, 0x1, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_PAD_LEFT, 0x1, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_PAD_RIGHT, 0x1, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_PAD_INNER, 0x1, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_MARGIN_TOP, 0x1, LV_STYLE_ID_VALUE + 5, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_MARGIN_BOTTOM, 0x1, LV_STYLE_ID_VALUE + 6, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_MARGIN_LEFT, 0x1, LV_STYLE_ID_VALUE + 7, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_MARGIN_RIGHT, 0x1, LV_STYLE_ID_VALUE + 8, LV_STYLE_ATTR_NONE), + + LV_STYLE_PROP_INIT(LV_STYLE_BG_BLEND_MODE, 0x2, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BG_MAIN_STOP, 0x2, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BG_GRAD_STOP, 0x2, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BG_GRAD_DIR, 0x2, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BG_COLOR, 0x2, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BG_GRAD_COLOR, 0x2, LV_STYLE_ID_COLOR + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BG_OPA, 0x2, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE), + + LV_STYLE_PROP_INIT(LV_STYLE_BORDER_WIDTH, 0x3, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BORDER_SIDE, 0x3, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BORDER_BLEND_MODE, 0x3, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BORDER_POST, 0x3, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BORDER_COLOR, 0x3, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_BORDER_OPA, 0x3, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE), + + LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_WIDTH, 0x4, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_PAD, 0x4, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_BLEND_MODE, 0x4, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_COLOR, 0x4, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_OPA, 0x4, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE), + + LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_WIDTH, 0x5, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_OFS_X, 0x5, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_OFS_Y, 0x5, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_SPREAD, 0x5, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_BLEND_MODE, 0x5, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_COLOR, 0x5, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_OPA, 0x5, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE), + + LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_BLEND_MODE, 0x6, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_REPEAT, 0x6, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_RECOLOR, 0x6, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_OPA, 0x6, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_RECOLOR_OPA, 0x6, LV_STYLE_ID_OPA + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_IMAGE, 0x6, LV_STYLE_ID_PTR + 0, LV_STYLE_ATTR_NONE), + + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_LETTER_SPACE, 0x7, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_LINE_SPACE, 0x7, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_BLEND_MODE, 0x7, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_OFS_X, 0x7, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_OFS_Y, 0x7, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_ALIGN, 0x7, LV_STYLE_ID_VALUE + 5, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_COLOR, 0x7, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_OPA, 0x7, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_FONT, 0x7, LV_STYLE_ID_PTR + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_VALUE_STR, 0x7, LV_STYLE_ID_PTR + 1, LV_STYLE_ATTR_NONE), + + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_LETTER_SPACE, 0x8, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_LINE_SPACE, 0x8, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_DECOR, 0x8, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_BLEND_MODE, 0x8, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_COLOR, 0x8, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_SEL_COLOR, 0x8, LV_STYLE_ID_COLOR + 1, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_SEL_BG_COLOR, 0x8, LV_STYLE_ID_COLOR + 2, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_OPA, 0x8, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_TEXT_FONT, 0x8, LV_STYLE_ID_PTR + 0, LV_STYLE_ATTR_INHERIT), + + LV_STYLE_PROP_INIT(LV_STYLE_LINE_WIDTH, 0x9, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_LINE_BLEND_MODE, 0x9, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_LINE_DASH_WIDTH, 0x9, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_LINE_DASH_GAP, 0x9, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_LINE_ROUNDED, 0x9, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_LINE_COLOR, 0x9, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_LINE_OPA, 0x9, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE), + + LV_STYLE_PROP_INIT(LV_STYLE_IMAGE_BLEND_MODE, 0xA, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_IMAGE_RECOLOR, 0xA, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_IMAGE_OPA, 0xA, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_INHERIT), + LV_STYLE_PROP_INIT(LV_STYLE_IMAGE_RECOLOR_OPA, 0xA, LV_STYLE_ID_OPA + 1, LV_STYLE_ATTR_INHERIT), + + LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_TIME, 0xB, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_DELAY, 0xB, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_1, 0xB, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_2, 0xB, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_3, 0xB, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_4, 0xB, LV_STYLE_ID_VALUE + 5, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_5, 0xB, LV_STYLE_ID_VALUE + 6, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_6, 0xB, LV_STYLE_ID_VALUE + 7, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PATH, 0xB, LV_STYLE_ID_PTR + 0, LV_STYLE_ATTR_NONE), + + LV_STYLE_PROP_INIT(LV_STYLE_SCALE_WIDTH, 0xC, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SCALE_BORDER_WIDTH, 0xC, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SCALE_END_BORDER_WIDTH, 0xC, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SCALE_END_LINE_WIDTH, 0xC, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SCALE_GRAD_COLOR, 0xC, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE), + LV_STYLE_PROP_INIT(LV_STYLE_SCALE_END_COLOR, 0xC, LV_STYLE_ID_COLOR + 1, LV_STYLE_ATTR_NONE), +}; + +native lv_obj: lv_scr_act() = -2 +native lv_obj: lv_label_create(lv_obj:par = lv_obj:0, lv_obj:copy = lv_obj:0, const text{} = 0) = -3 +native lv_obj: lv_btn_create (lv_obj:par = lv_obj:0, lv_obj:copy = lv_obj:0) = -4 +native lv_obj_set_pos(lv_obj:obj, x, y) = -5 +native lv_obj_set_size(lv_obj:obj, w, h) = -6 +native lv_obj_set_event_cb(lv_obj:obj, const cb_name[]) = -7 +native lv_obj_align(lv_obj:obj, lv_obj:base = lv_obj:0, lv_align:align, x_ofs = 0, y_ofs = 0) = -8 +native lv_obj_realign(lv_obj:obj) = -9 +native lv_label_set_text(lv_obj:obj, const text[]) = -10 + +native lv_obj_set_style_local_int (lv_obj:obj, lv_style_prop:prop, value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -11 +native lv_obj_set_style_local_color(lv_obj:obj, lv_style_prop:prop, value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -12 +native lv_obj_set_style_local_opa (lv_obj:obj, lv_style_prop:prop, value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -13 +native lv_obj_set_style_local_ptr (lv_obj:obj, lv_style_prop:prop, ptr:value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -14 diff --git a/src/pawn/programs/include/symbols.inc b/src/pawn/programs/include/symbols.inc new file mode 100644 index 0000000000..567228527e --- /dev/null +++ b/src/pawn/programs/include/symbols.inc @@ -0,0 +1,54 @@ +stock const symbol_batteryHalf{} = "\xEF\x89\x82" +stock const symbol_heartBeat{} = "\xEF\x88\x9E" +stock const symbol_bluetooth{} = "\xEF\x8A\x94" +stock const symbol_shieldAlt{} = "\xEF\x8F\xAD" +stock const symbol_plug{} = "\xEF\x87\xA6" +stock const symbol_shoe{} = "\xEF\x95\x8B" +stock const symbol_clock{} = "\xEF\x80\x97" +stock const symbol_bell{} = "\xEF\x83\xB3" +stock const symbol_info{} = "\xEF\x84\xA9" +stock const symbol_list{} = "\xEF\x80\xBA" +stock const symbol_sun{} = "\xEF\x86\x85" +stock const symbol_check{} = "\xEF\x95\xA0" +stock const symbol_music{} = "\xEF\x80\x81" +stock const symbol_tachometer{} = "\xEF\x8F\xBD" +stock const symbol_paintbrush{} = "\xEF\x87\xBC" +stock const symbol_paddle{} = "\xEF\x91\x9D" +stock const symbol_map{} = "\xEF\x96\xa0" +stock const symbol_phone{} = "\xEF\x82\x95" +stock const symbol_phoneSlash{} = "\xEF\x8F\x9D" +stock const symbol_volumMute{} = "\xEF\x9A\xA9" +stock const symbol_volumUp{} = "\xEF\x80\xA8" +stock const symbol_volumDown{} = "\xEF\x80\xA7" +stock const symbol_stepForward{} = "\xEF\x81\x91" +stock const symbol_stepBackward{} = "\xEF\x81\x88" +stock const symbol_play{} = "\xEF\x81\x8B" +stock const symbol_pause{} = "\xEF\x81\x8C" +stock const symbol_stop{} = "\xEF\x81\x8D" +stock const symbol_stopWatch{} = "\xEF\x8B\xB2" +stock const symbol_hourGlass{} = "\xEF\x89\x92" +stock const symbol_lapsFlag{} = "\xEF\x80\xA4" +stock const symbol_drum{} = "\xEF\x95\xA9" +stock const symbol_dice{} = "\xEF\x94\xA2" +stock const symbol_eye{} = "\xEF\x81\xAE" +stock const symbol_home{} = "\xEF\x80\x95" +stock const symbol_sleep{} = "\xEE\xBD\x84" +stock const symbol_calculator{} = "\xEF\x87\xAC" +stock const symbol_backspace{} = "\xEF\x95\x9A" +stock const symbol_cloudSun{} = "\xEF\x9B\x84" +stock const symbol_cloudSunRain{} = "\xEF\x9D\x83" +stock const symbol_cloudShowersHeavy{} = "\xEF\x9D\x80" +stock const symbol_smog{} = "\xEF\x9D\x9F" +stock const symbol_cloud{} = "\xEF\x83\x82" +stock const symbol_cloudMeatball{} = "\xEF\x9C\xBB" +stock const symbol_bolt{} = "\xEF\x83\xA7" +stock const symbol_snowflake{} = "\xEF\x8B\x9C" +stock const symbol_ban{} = "\xEF\x81\x9E" +stock const symbol_settings{} = "\xEE\xA2\xB8" +stock const symbol_brightnessLow{} = "\xEE\x8E\xAA" +stock const symbol_brightnessMedium{} = "\xEE\x8E\xAB" +stock const symbol_brightnessHigh{} = "\xEE\x8E\xAC" +stock const symbol_notificationsOff{} = "\xEE\x9F\xB6" +stock const symbol_notificationsOn{} = "\xEE\x9F\xB7" +stock const symbol_flashlight{} = "\xEF\x80\x8B" +stock const symbol_paintbrushLg{} = "\xEE\x90\x8A" diff --git a/src/pawn/programs/program.p b/src/pawn/programs/program.p new file mode 100644 index 0000000000..95a9382edd --- /dev/null +++ b/src/pawn/programs/program.p @@ -0,0 +1,7 @@ +#include "infinitime" + +@start() { + var lv_obj: label = lv_label_create() + lv_obj_set_pos(label, 20, 20) + lv_label_set_text(label, "Hello world") +} diff --git a/src/pawn/programs/watchface_digital.p b/src/pawn/programs/watchface_digital.p new file mode 100644 index 0000000000..1b31146b6f --- /dev/null +++ b/src/pawn/programs/watchface_digital.p @@ -0,0 +1,118 @@ +#include "infinitime" +#include "symbols" + +var lv_obj: label_time +var lv_obj: label_time_ampm +var lv_obj: label_date +var lv_obj: notification_icon +var lv_obj: heartbeat_icon +var lv_obj: heartbeat_value +var lv_obj: step_icon +var lv_obj: step_value + +var clock_type + +var buffer{20} + +@start() { + status_icons_create(); + clock_type = get_setting(SETTING_CLOCK_TYPE) + + notification_icon = lv_label_create() + lv_obj_set_style_local_color(notification_icon, LV_STYLE_TEXT_COLOR, 0x00FF00) + lv_obj_align(notification_icon, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT); + + heartbeat_icon = lv_label_create(.text = symbol_heartBeat) + lv_obj_set_style_local_color(heartbeat_icon, LV_STYLE_TEXT_COLOR, 0x1B1B1B) + lv_obj_align(heartbeat_icon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT) + + heartbeat_value = lv_label_create() + lv_obj_set_style_local_color(heartbeat_value, LV_STYLE_TEXT_COLOR, 0xCE1B1B) + lv_obj_align(heartbeat_value, heartbeat_icon, LV_ALIGN_OUT_RIGHT_MID, 5, 0) + + step_value = lv_label_create(.text = "0") + lv_obj_set_style_local_color(step_value, LV_STYLE_TEXT_COLOR, 0x00FFE7) + lv_obj_align(step_value, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT) + + step_icon = lv_label_create(.text = symbol_shoe) + lv_obj_set_style_local_color(step_icon, LV_STYLE_TEXT_COLOR, 0x00FFE7) + lv_obj_align(step_icon, step_value, LV_ALIGN_OUT_LEFT_MID, -5, 0) + + label_date = lv_label_create() + lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60) + lv_obj_set_style_local_color(label_date, LV_STYLE_TEXT_COLOR, 0x999999) + + label_time = lv_label_create() + lv_obj_set_style_local_ptr(label_time, LV_STYLE_TEXT_FONT, jetbrains_mono_extrabold_compressed) + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID) + + label_time_ampm = lv_label_create() + lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, -55) +} + +@refresh() { + status_icons_update(); + + static datetime[DATETIME] + + // Returns true if changed + if (read_datetime(datetime)) { + var hour = datetime.hour + + if (clock_type == CLOCK_TYPE_H12) { + lv_label_set_text(label_time_ampm, hour < 12 ? "AM" : "PM") + lv_obj_realign(label_time_ampm) + + if (hour == 0) hour = 12 + else if (hour > 12) hour -= 12 + } + sprintf(buffer, _, clock_type == CLOCK_TYPE_H12 ? "%2d:%02d" : "%02d:%02d", hour, datetime.minute) + lv_label_set_text(label_time, buffer) + lv_obj_realign(label_time) + + static day{4} + static month{4} + read_datetime_short_str(day, month) + + if (clock_type == CLOCK_TYPE_H12) + sprintf(buffer, _, "%s %s %d %d", day, month, datetime.year, datetime.day) + else + sprintf(buffer, _, "%s %d %s %d", day, datetime.day, month, datetime.year) + + lv_label_set_text(label_date, buffer) + lv_obj_realign(label_date) + } + + static new_notifs + if (swap(new_notifs, has_new_notifications())) { + lv_label_set_text(notification_icon, new_notifs ? symbol_info : "") + } + + static heartrate + static heartrate_state: heartrate_state + + var updated = swap(heartrate, get_heartrate()) + updated = swap(heartrate_state, get_heartrate_state()) || updated // Circumvent short-circuiting + + if (updated) { + if (heartrate_state == HEARTRATE_RUNNING) { + lv_obj_set_style_local_color(heartbeat_icon, LV_STYLE_TEXT_COLOR, 0xCE1B1B) + sprintf(buffer, _, "%d", heartrate) + lv_label_set_text(heartbeat_value, buffer) + } else { + lv_obj_set_style_local_color(heartbeat_icon, LV_STYLE_TEXT_COLOR, 0x1B1B1B) + lv_label_set_text(heartbeat_value, "") + } + + lv_obj_realign(heartbeat_icon) + lv_obj_realign(heartbeat_value) + } + + static steps + if (swap(steps, get_step_number())) { + sprintf(buffer, _, "%d", steps) + lv_label_set_text(step_value, buffer) + lv_obj_realign(step_value) + lv_obj_realign(step_icon) + } +} From ac0b81e154f9968e4719643b3459c9f8899d861b Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 30 Dec 2025 17:07:37 +0100 Subject: [PATCH 21/26] Add assembly trampoline to handle native functions more compactly --- src/CMakeLists.txt | 1 - src/displayapp/screens/Pawn.cpp | 190 ++++++++------ src/displayapp/screens/program.h | 32 +-- src/displayapp/screens/watchface_digital.h | 282 ++++++++++----------- src/pawn/programs/include/infinitime.inc | 22 +- src/pawn/programs/include/lvgl.inc | 29 ++- src/pawn/programs/watchface_digital.p | 28 +- 7 files changed, 311 insertions(+), 273 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f0fd2746e7..e86e410980 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -916,7 +916,6 @@ target_compile_options(pawn PRIVATE -DAMX_ANSIONLY -DAMX_NODYNALOAD -DAMX_DONT_RELOCATE - -DAMX_NATIVETABLE=pawn_natives $<$: ${DEBUG_FLAGS}> $<$: ${RELEASE_FLAGS}> $<$: ${CXX_FLAGS}> diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 835eb8bf90..af63c5878e 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -11,6 +11,7 @@ enum { PAWN_ERR_MISSINGHANDLER, PAWN_ERR_INVALIDSTRING, PAWN_ERR_INVALIDSETTING, + PAWN_ERR_INVALIDTRAMPOLINE, PAWN_ERR_FIRST = PAWN_ERR_PARAMCOUNT, }; @@ -50,12 +51,6 @@ static void event_handler(lv_obj_t* obj, lv_event_t event) { } } -static cell AMX_NATIVE_CALL F_lv_scr_act(AMX* amx, const cell* params) { - ASSERT_PARAMS(0); - - return (cell) lv_scr_act(); -} - static cell AMX_NATIVE_CALL F_lv_label_create(AMX* amx, const cell* params) { ASSERT_PARAMS(3); @@ -65,26 +60,6 @@ static cell AMX_NATIVE_CALL F_lv_label_create(AMX* amx, const cell* params) { return (cell) label; } -static cell AMX_NATIVE_CALL F_lv_btn_create(AMX* amx, const cell* params) { - ASSERT_PARAMS(2); - - return (cell) lv_btn_create(PARAMS_OBJ(1) ?: lv_scr_act(), PARAMS_OBJ(2)); -} - -static cell AMX_NATIVE_CALL F_lv_obj_set_pos(AMX* amx, const cell* params) { - ASSERT_PARAMS(3); - - lv_obj_set_pos(PARAMS_OBJ(1), params[2], params[3]); - return 0; -} - -static cell AMX_NATIVE_CALL F_lv_obj_set_size(AMX* amx, const cell* params) { - ASSERT_PARAMS(3); - - lv_obj_set_size(PARAMS_OBJ(1), params[2], params[3]); - return 0; -} - static cell AMX_NATIVE_CALL F_lv_obj_set_event_cb(AMX* amx, const cell* params) { ASSERT_PARAMS(2); @@ -164,25 +139,6 @@ static cell AMX_NATIVE_CALL F_lv_obj_set_style_local_ptr(AMX* amx, const cell* p return 0; } -static cell AMX_NATIVE_CALL F_lv_obj_align(AMX* amx, const cell* params) { - ASSERT_PARAMS(5) - - lv_obj_t* obj = PARAMS_OBJ(1); - lv_obj_t* base = PARAMS_OBJ(2); - cell align = params[3]; - cell x_ofs = params[4]; - cell y_ofs = params[5]; - - lv_obj_align(obj, base, align, x_ofs, y_ofs); - return 0; -} - -static cell AMX_NATIVE_CALL F_lv_obj_realign(AMX* amx, const cell* params) { - ASSERT_PARAMS(1) - lv_obj_realign(PARAMS_OBJ(1)); - return 0; -} - /** * Hand-written implementation of sprintf with limited functionality in order to support reading strings from parameters. * Supported interpolations: @@ -401,6 +357,99 @@ static cell AMX_NATIVE_CALL F_raise_error(AMX* amx, const cell* params) { return 0; } +static const uintptr_t natives[] = { // Indices start at -1000 + (uintptr_t) lv_label_create, + (uintptr_t) lv_btn_create, + (uintptr_t) lv_obj_set_pos, + (uintptr_t) lv_obj_set_size, + (uintptr_t) lv_obj_align, + (uintptr_t) lv_obj_realign, +}; + +static const AMX_NATIVE lvgl_proxys[] = { // Indices start at -3000 + F_lv_label_create, + F_lv_obj_set_event_cb, + F_lv_label_set_text, + F_lv_obj_set_style_local_int, + F_lv_obj_set_style_local_color, + F_lv_obj_set_style_local_opa, + F_lv_obj_set_style_local_ptr, +}; + +static const AMX_NATIVE pawn_proxys[] = { // Indices start at -2000 + F_sprintf, + F_read_datetime, + F_read_datetime_short_str, + F_status_icons_create, + F_status_icons_update, + F_has_new_notifications, + F_get_setting, + F_get_heartrate, + F_get_heartrate_state, + F_get_step_number, + F_raise_error, +}; + +static cell trampoline(unsigned int index, const cell* params) { + int param_count = params[0] / sizeof(cell); + + if (index >= sizeof(natives) / sizeof(natives[0])) + return PAWN_ERR_INVALIDTRAMPOLINE; + + uintptr_t addr = natives[index] | 1; // Set lowest bit to enable thumb mode (always must be enabled on ARMv7-M) + + cell ret; + + params++; // Skip parameter count + + asm volatile(".syntax unified\n" + ".thumb\n" + + // Save stack pointer in case we push excess arguments into stack + "mov r5, sp\n" + + // Load first argument into R0 or jump out + "subs %[count], #1\n" + "bmi call\n" + "ldr r0, [%[params]]\n" + "add %[params], #4\n" + + // Load second argument into R1 or jump out + "subs %[count], #1\n" + "bmi call\n" + "ldr r1, [%[params]]\n" + "add %[params], #4\n" + + // Load third argument into R2 or jump out + "subs %[count], #1\n" + "bmi call\n" + "ldr r2, [%[params]]\n" + "add %[params], #4\n" + + // Load fourth argument into R3 or jump out + "subs %[count], #1\n" + "bmi call\n" + "ldr r3, [%[params]]\n" + "add %[params], #4\n" + + // Push remaining argument into stack in reverse order + "loop: subs %[count], #1\n" + " bmi call\n" + " ldr r12, [%[params], +%[count], LSL 2]\n" + " push {r12}\n" + " b loop\n" + + "call: blx %[addr]\n" // Call function + " mov sp, r5\n" // Restore stack + " mov %[ret], r0\n" // Move returned value into ret + + : [ret] "=r"(ret), [count] "+r"(param_count), [params] "+r"(params) + : [addr] "r"(addr) + : "r0", "r1", "r2", "r3", "r5", "r12", "lr", "memory"); + + return ret; +} + static int AMXAPI prun_Overlay(AMX* amx, int index) { AMX_HEADER* hdr; AMX_OVERLAYINFO* tbl; @@ -421,6 +470,20 @@ static int AMXAPI prun_Overlay(AMX* amx, int index) { return AMX_ERR_NONE; } +static int AMXAPI prun_Callback(struct tagAMX* amx, cell index, cell* result, const cell* params) { + amx->error = AMX_ERR_NONE; + + if (index <= -3000) { // LVGL proxys + *result = lvgl_proxys[-(index + 3000)](amx, params); + } else if (index <= -2000) { // InfiniTime proxys + *result = pawn_proxys[-(index + 2000)](amx, params); + } else { // Direct trampolines + *result = trampoline(-(index + 1000), params); + } + + return amx->error; +} + int Pawn::LoadProgram() { int result; AMX_HEADER hdr; @@ -483,33 +546,6 @@ int Pawn::LoadProgram() { return result; } -extern "C" const AMX_NATIVE pawn_natives[] = { - F_sprintf, - F_lv_scr_act, - F_lv_label_create, - F_lv_btn_create, - F_lv_obj_set_pos, - F_lv_obj_set_size, - F_lv_obj_set_event_cb, - F_lv_obj_align, - F_lv_obj_realign, - F_lv_label_set_text, - F_lv_obj_set_style_local_int, - F_lv_obj_set_style_local_color, - F_lv_obj_set_style_local_opa, - F_lv_obj_set_style_local_ptr, - F_read_datetime, - F_read_datetime_short_str, - F_status_icons_create, - F_status_icons_update, - F_has_new_notifications, - F_get_setting, - F_get_heartrate, - F_get_heartrate_state, - F_get_step_number, - F_raise_error, -}; - #include "program.h" Pawn::Pawn(AppControllers& controllers) : Pawn(program, controllers) { @@ -525,9 +561,13 @@ Pawn::Pawn(const uint8_t* file, AppControllers& controllers) : controllers(contr lv_obj_set_user_data(lv_scr_act(), &amx); - cell* font; - if (amx_FindPubVar(&amx, "font_jmec", &font) == AMX_ERR_NONE) - *font = (cell) &jetbrains_mono_extrabold_compressed; + amx_SetCallback(&amx, prun_Callback); + + cell* var; + if (amx_FindPubVar(&amx, "font_jmec", &var) == AMX_ERR_NONE) + *var = (cell) &jetbrains_mono_extrabold_compressed; + if (amx_FindPubVar(&amx, "screen", &var) == AMX_ERR_NONE) + *var = (cell) lv_scr_act(); result = amx_Exec(&amx, NULL, AMX_EXEC_MAIN); if (result != AMX_ERR_NONE) { diff --git a/src/displayapp/screens/program.h b/src/displayapp/screens/program.h index c7935463e3..3b5cf68e35 100644 --- a/src/displayapp/screens/program.h +++ b/src/displayapp/screens/program.h @@ -1,18 +1,20 @@ const unsigned char program[] = { - 0xb0, 0x00, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, - 0x40, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, - 0x78, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0xc4, 0x00, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, + 0x50, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, + 0x8c, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0xfc, 0xff, 0x92, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, 0x8e, 0x00, 0x14, 0x00, - 0x8e, 0x00, 0x14, 0x00, 0x90, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, - 0xfb, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x04, 0x00, - 0x90, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x65, 0x48, - 0x6f, 0x77, 0x20, 0x6f, 0x00, 0x64, 0x6c, 0x72 + 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x73, 0x63, + 0x72, 0x65, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, 0x92, 0x00, 0x04, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, + 0x8e, 0x00, 0x14, 0x00, 0x8e, 0x00, 0x14, 0x00, 0x90, 0x00, 0xfc, 0xff, + 0x70, 0x00, 0x00, 0x00, 0x16, 0xfc, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x08, 0x00, 0x90, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, + 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, + 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x65, 0x48, 0x6f, 0x77, 0x20, 0x6f, + 0x00, 0x64, 0x6c, 0x72 }; -unsigned int program_len = 176; +unsigned int program_len = 196; diff --git a/src/displayapp/screens/watchface_digital.h b/src/displayapp/screens/watchface_digital.h index 459ba68a3f..8512ee8400 100644 --- a/src/displayapp/screens/watchface_digital.h +++ b/src/displayapp/screens/watchface_digital.h @@ -1,189 +1,185 @@ const unsigned char watchface_digital[] = { - 0xb8, 0x08, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, - 0x64, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xb8, 0x08, 0x00, 0x00, - 0x80, 0x09, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x80, 0x08, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, + 0x70, 0x00, 0x00, 0x00, 0xbc, 0x07, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, + 0x48, 0x09, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x84, 0x03, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, - 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, - 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x3c, 0x03, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, + 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, 0x00, 0x73, 0x63, 0x72, + 0x65, 0x65, 0x6e, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, 0x80, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x10, 0x00, 0x35, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, 0x7e, 0x00, 0x10, 0x00, 0x89, 0x00, 0x0c, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x9c, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0xec, 0xff, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x87, 0x00, 0x30, 0x00, 0x92, 0x00, 0x48, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x1c, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x2d, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2a, 0xf8, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x87, 0x00, 0x34, 0x00, 0x92, 0x00, 0x4c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x20, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0x00, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x04, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x20, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x08, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x24, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0x1b, 0x1b, 0x1b, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x1b, 0x1b, 0x1b, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x04, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x48, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x24, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x28, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0x1b, 0x1b, 0xce, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x1b, 0x1b, 0xce, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x8e, 0x00, 0x13, 0x00, - 0x8f, 0x00, 0x20, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x2c, 0x00, + 0x8f, 0x00, 0x24, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x30, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0xe7, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0xe7, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x30, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x06, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x08, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x28, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x2c, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0xe7, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0xe7, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xfb, 0xff, 0x8e, 0x00, 0x10, 0x00, - 0x8f, 0x00, 0x2c, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x48, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x18, 0x00, + 0x8f, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x1c, 0x00, 0x8e, 0x00, 0x3c, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x48, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x10, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x10, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x14, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, + 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x42, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x10, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x48, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xfd, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x14, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x18, 0x00, 0x8e, 0x00, 0xc9, 0xff, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xee, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x2c, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x54, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x2f, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd4, 0x01, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, - 0x83, 0x00, 0x50, 0x00, 0xa0, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x88, 0x00, 0xfc, 0xff, 0x7c, 0x00, 0x30, 0x00, 0xa4, 0x00, 0x01, 0x00, + 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x88, 0x00, 0xfc, 0xff, 0x7c, 0x00, 0x34, 0x00, 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x84, 0x00, 0x0c, 0x00, 0x61, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x60, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x64, 0x00, 0x18, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, + 0x83, 0x00, 0x64, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x68, 0x00, 0x18, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x84, 0x00, 0x0c, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0xa0, 0x00, 0xf4, 0xff, - 0x88, 0x00, 0xfc, 0xff, 0x92, 0x00, 0x50, 0x00, 0x94, 0x00, 0xfc, 0xff, - 0x7c, 0x00, 0x30, 0x00, 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x68, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x74, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x34, 0x00, - 0x8f, 0x00, 0x10, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x10, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x92, 0x00, 0x84, 0x00, - 0x92, 0x00, 0x80, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x30, 0x00, 0xa4, 0x00, 0x01, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x83, 0x00, 0x50, 0x00, - 0xa0, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x50, 0x00, - 0xa0, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x84, 0x00, - 0x92, 0x00, 0x80, 0x00, 0x92, 0x00, 0x88, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x88, 0x00, 0xfc, 0xff, 0x92, 0x00, 0x54, 0x00, 0x94, 0x00, 0xfc, 0xff, + 0x7c, 0x00, 0x34, 0x00, 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x6c, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x78, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x30, 0xf8, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, + 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x92, 0x00, 0x88, 0x00, + 0x92, 0x00, 0x84, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2e, 0xf8, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x34, 0x00, 0xa4, 0x00, 0x01, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, + 0xa0, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, + 0xa0, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x88, 0x00, + 0x92, 0x00, 0x84, 0x00, 0x92, 0x00, 0x8c, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x50, 0x00, 0xa0, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x84, 0x00, 0x83, 0x00, 0x50, 0x00, 0xa0, 0x00, 0x08, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x80, 0x00, 0x92, 0x00, 0x94, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x34, 0x00, - 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xed, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xa0, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x74, 0xfa, 0xff, 0xff, 0x23, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xa0, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x0c, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0xa4, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x88, 0x00, 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x08, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x84, 0x00, 0x92, 0x00, 0x98, 0x00, + 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x30, 0xf8, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, + 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x2b, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xa4, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x21, 0x00, 0x00, 0x00, 0xbc, 0xfa, 0xff, 0xff, 0x23, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xa4, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x10, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0xa8, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, - 0xeb, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0xa8, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x18, 0xfa, 0xff, 0xff, 0x88, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, - 0xea, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x29, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xac, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x21, 0x00, 0x00, 0x00, - 0xf4, 0xf9, 0xff, 0xff, 0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x60, 0xfa, 0xff, 0xff, 0x88, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, + 0x28, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0xb0, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x3c, 0xfa, 0xff, 0xff, 0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x01, 0x00, 0x88, 0x00, 0xfc, 0xff, 0x7e, 0x00, 0xfc, 0xff, - 0x23, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xac, 0x00, + 0x23, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xb0, 0x00, 0xa4, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0x1b, 0x1b, 0xce, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x92, 0x00, 0xa8, 0x00, 0x92, 0x00, 0xb0, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x34, 0x00, 0x8f, 0x00, 0x24, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x1b, 0x1b, 0xce, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x92, 0x00, 0xac, 0x00, 0x92, 0x00, 0xb4, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x28, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0x1b, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf4, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0xb4, 0x00, - 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xe9, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xb8, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x21, 0x00, 0x00, 0x00, 0xdc, 0xf8, 0xff, 0xff, 0x23, 0x00, 0x00, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x92, 0x00, 0xb8, 0x00, 0x92, 0x00, 0xbc, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x34, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x34, 0x00, - 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0xb8, 0x00, + 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x27, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xbc, 0x00, 0x8e, 0x00, 0x08, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x24, 0xf9, 0xff, 0xff, 0x23, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x92, 0x00, 0xbc, 0x00, 0x92, 0x00, 0xc0, 0x00, + 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x30, 0xf8, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, + 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x88, 0xef, 0x00, 0x8b, 0x95, 0xef, - 0x00, 0xa9, 0x84, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x88, 0xef, + 0x00, 0x8b, 0x95, 0xef, 0x00, 0xa9, 0x84, 0xef, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x41, 0x00, 0x00, 0x4d, 0x50, + 0x3a, 0x64, 0x32, 0x25, 0x64, 0x32, 0x30, 0x25, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x32, 0x30, 0x25, 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, + 0x64, 0x25, 0x20, 0x73, 0x00, 0x64, 0x25, 0x20, 0x25, 0x20, 0x73, 0x25, + 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x4d, 0x41, 0x00, 0x00, 0x4d, 0x50, 0x3a, 0x64, 0x32, 0x25, - 0x64, 0x32, 0x30, 0x25, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, - 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x64, 0x25, 0x20, 0x73, - 0x00, 0x64, 0x25, 0x20, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, - 0x00, 0x64, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x25, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x25 + 0x00, 0x00, 0x64, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0x25 }; -unsigned int watchface_digital_len = 2232; +unsigned int watchface_digital_len = 2176; diff --git a/src/pawn/programs/include/infinitime.inc b/src/pawn/programs/include/infinitime.inc index 12bd3b89a4..9f7ec6f920 100644 --- a/src/pawn/programs/include/infinitime.inc +++ b/src/pawn/programs/include/infinitime.inc @@ -4,7 +4,7 @@ #define DATETIME[.minute, .hour, .day, .year] -native sprintf(out[], size=sizeof out, const fmt[], const ...) = -1 +native sprintf(out[], size=sizeof out, const fmt[], const ...) = -2000 #define jetbrains_mono_extrabold_compressed font_jmec // Name truncated because symbols have a max length of 31 characters public stock const ptr:jetbrains_mono_extrabold_compressed @@ -20,12 +20,12 @@ const touch_event: { TOUCH_DOUBLE_TAP, } -native bool: read_datetime(out[DATETIME]) = -15 -native read_datetime_short_str(day_of_week{4} = 0, month_of_year{4} = 0) = -16 +native bool: read_datetime(out[DATETIME]) = -2001 +native read_datetime_short_str(day_of_week{4} = 0, month_of_year{4} = 0) = -2002 -native status_icons_create() = -17 -native status_icons_update() = -18 -native bool: has_new_notifications() = -19 +native status_icons_create() = -2003 +native status_icons_update() = -2004 +native bool: has_new_notifications() = -2005 const setting: { SETTING_WATCHFACE = 0, @@ -40,7 +40,7 @@ const { CLOCK_TYPE_H24 = 0, CLOCK_TYPE_H12 } -native get_setting(setting: s) = -20 +native get_setting(setting: s) = -2006 const heartrate_state: { HEARTRATE_STOPPED = 0, @@ -48,12 +48,12 @@ const heartrate_state: { HEARTRATE_NO_TOUCH HEARTRATE_RUNNING } -native get_heartrate() = -21 -native heartrate_state: get_heartrate_state() = -22 +native get_heartrate() = -2007 +native heartrate_state: get_heartrate_state() = -2008 -native get_step_number() = -23 +native get_step_number() = -2009 -native raise_error(err) = -24 +native raise_error(err) = -2010 forward @refresh() forward @touch(x, y) diff --git a/src/pawn/programs/include/lvgl.inc b/src/pawn/programs/include/lvgl.inc index ddfd72b045..38018ba28c 100644 --- a/src/pawn/programs/include/lvgl.inc +++ b/src/pawn/programs/include/lvgl.inc @@ -180,17 +180,18 @@ const lv_style_prop: { LV_STYLE_PROP_INIT(LV_STYLE_SCALE_END_COLOR, 0xC, LV_STYLE_ID_COLOR + 1, LV_STYLE_ATTR_NONE), }; -native lv_obj: lv_scr_act() = -2 -native lv_obj: lv_label_create(lv_obj:par = lv_obj:0, lv_obj:copy = lv_obj:0, const text{} = 0) = -3 -native lv_obj: lv_btn_create (lv_obj:par = lv_obj:0, lv_obj:copy = lv_obj:0) = -4 -native lv_obj_set_pos(lv_obj:obj, x, y) = -5 -native lv_obj_set_size(lv_obj:obj, w, h) = -6 -native lv_obj_set_event_cb(lv_obj:obj, const cb_name[]) = -7 -native lv_obj_align(lv_obj:obj, lv_obj:base = lv_obj:0, lv_align:align, x_ofs = 0, y_ofs = 0) = -8 -native lv_obj_realign(lv_obj:obj) = -9 -native lv_label_set_text(lv_obj:obj, const text[]) = -10 - -native lv_obj_set_style_local_int (lv_obj:obj, lv_style_prop:prop, value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -11 -native lv_obj_set_style_local_color(lv_obj:obj, lv_style_prop:prop, value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -12 -native lv_obj_set_style_local_opa (lv_obj:obj, lv_style_prop:prop, value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -13 -native lv_obj_set_style_local_ptr (lv_obj:obj, lv_style_prop:prop, ptr:value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -14 +public stock const lv_obj: screen + +native lv_obj: lv_label_create(lv_obj:par, lv_obj:copy = lv_obj:0, const text{} = 0) = -3000 +native lv_obj: lv_btn_create (lv_obj:par, lv_obj:copy = lv_obj:0) = -1001 +native lv_obj_set_pos(lv_obj:obj, x, y) = -1002 +native lv_obj_set_size(lv_obj:obj, w, h) = -1003 +native lv_obj_set_event_cb(lv_obj:obj, const cb_name[]) = -3001 +native lv_obj_align(lv_obj:obj, lv_obj:base = lv_obj:0, lv_align:align, x_ofs = 0, y_ofs = 0) = -1004 +native lv_obj_realign(lv_obj:obj) = -1005 +native lv_label_set_text(lv_obj:obj, const text[]) = -3002 + +native lv_obj_set_style_local_int (lv_obj:obj, lv_style_prop:prop, value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -3003 +native lv_obj_set_style_local_color(lv_obj:obj, lv_style_prop:prop, value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -3004 +native lv_obj_set_style_local_opa (lv_obj:obj, lv_style_prop:prop, value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -3005 +native lv_obj_set_style_local_ptr (lv_obj:obj, lv_style_prop:prop, ptr:value, part = 0, lv_state:state_=LV_STATE_DEFAULT) = -3006 diff --git a/src/pawn/programs/watchface_digital.p b/src/pawn/programs/watchface_digital.p index 1b31146b6f..caaa20a8bc 100644 --- a/src/pawn/programs/watchface_digital.p +++ b/src/pawn/programs/watchface_digital.p @@ -18,36 +18,36 @@ var buffer{20} status_icons_create(); clock_type = get_setting(SETTING_CLOCK_TYPE) - notification_icon = lv_label_create() + notification_icon = lv_label_create(screen) lv_obj_set_style_local_color(notification_icon, LV_STYLE_TEXT_COLOR, 0x00FF00) - lv_obj_align(notification_icon, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT); + lv_obj_align(notification_icon, screen, LV_ALIGN_IN_TOP_LEFT); - heartbeat_icon = lv_label_create(.text = symbol_heartBeat) + heartbeat_icon = lv_label_create(screen, .text = symbol_heartBeat) lv_obj_set_style_local_color(heartbeat_icon, LV_STYLE_TEXT_COLOR, 0x1B1B1B) - lv_obj_align(heartbeat_icon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT) + lv_obj_align(heartbeat_icon, screen, LV_ALIGN_IN_BOTTOM_LEFT) - heartbeat_value = lv_label_create() + heartbeat_value = lv_label_create(screen) lv_obj_set_style_local_color(heartbeat_value, LV_STYLE_TEXT_COLOR, 0xCE1B1B) lv_obj_align(heartbeat_value, heartbeat_icon, LV_ALIGN_OUT_RIGHT_MID, 5, 0) - step_value = lv_label_create(.text = "0") + step_value = lv_label_create(screen, .text = "0") lv_obj_set_style_local_color(step_value, LV_STYLE_TEXT_COLOR, 0x00FFE7) - lv_obj_align(step_value, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT) + lv_obj_align(step_value, screen, LV_ALIGN_IN_BOTTOM_RIGHT) - step_icon = lv_label_create(.text = symbol_shoe) + step_icon = lv_label_create(screen, .text = symbol_shoe) lv_obj_set_style_local_color(step_icon, LV_STYLE_TEXT_COLOR, 0x00FFE7) lv_obj_align(step_icon, step_value, LV_ALIGN_OUT_LEFT_MID, -5, 0) - label_date = lv_label_create() - lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60) + label_date = lv_label_create(screen) + lv_obj_align(label_date, screen, LV_ALIGN_CENTER, 0, 60) lv_obj_set_style_local_color(label_date, LV_STYLE_TEXT_COLOR, 0x999999) - label_time = lv_label_create() + label_time = lv_label_create(screen) lv_obj_set_style_local_ptr(label_time, LV_STYLE_TEXT_FONT, jetbrains_mono_extrabold_compressed) - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID) + lv_obj_align(label_time, screen, LV_ALIGN_IN_RIGHT_MID) - label_time_ampm = lv_label_create() - lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, -55) + label_time_ampm = lv_label_create(screen) + lv_obj_align(label_time_ampm, screen, LV_ALIGN_IN_RIGHT_MID, 0, -55) } @refresh() { From 3716c9b5115021df71ad83e16c04d490d507eeae Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Tue, 30 Dec 2025 18:33:23 +0100 Subject: [PATCH 22/26] Run program directly from ROM --- src/CMakeLists.txt | 25 +++++++++++++++++++++++++ src/displayapp/screens/Pawn.cpp | 29 ++++++++++++++--------------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e86e410980..8a91ffce15 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -916,6 +916,31 @@ target_compile_options(pawn PRIVATE -DAMX_ANSIONLY -DAMX_NODYNALOAD -DAMX_DONT_RELOCATE + + # -DAMX_ALIGN + # -DAMX_ALLOT + # -DAMX_DEFCALLBACK + -DAMX_CLEANUP + # -DAMX_CLONE + -DAMX_EXEC + # -DAMX_FLAGS + -DAMX_INIT + # -DAMX_MEMINFO + # -DAMX_NAMELENGTH + # -DAMX_NATIVEINFO + -DAMX_PUSHXXX + -DAMX_RAISEERROR + # -DAMX_REGISTER + -DAMX_SETCALLBACK + # -DAMX_SETDEBUGHOOK + # -DAMX_UTF8XXX + # -DAMX_XXXNATIVES + -DAMX_XXXPUBLICS + -DAMX_XXXPUBVARS + -DAMX_XXXSTRING + # -DAMX_XXXTAGS + # -DAMX_XXXUSERDATA + # -DAMX_VERIFYADDR $<$: ${DEBUG_FLAGS}> $<$: ${RELEASE_FLAGS}> $<$: ${CXX_FLAGS}> diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index af63c5878e..08a2055d73 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -357,7 +357,8 @@ static cell AMX_NATIVE_CALL F_raise_error(AMX* amx, const cell* params) { return 0; } -static const uintptr_t natives[] = { // Indices start at -1000 +static const uintptr_t natives[] = { + // Indices start at -1000 (uintptr_t) lv_label_create, (uintptr_t) lv_btn_create, (uintptr_t) lv_obj_set_pos, @@ -366,7 +367,8 @@ static const uintptr_t natives[] = { // Indices start at -1000 (uintptr_t) lv_obj_realign, }; -static const AMX_NATIVE lvgl_proxys[] = { // Indices start at -3000 +static const AMX_NATIVE lvgl_proxys[] = { + // Indices start at -3000 F_lv_label_create, F_lv_obj_set_event_cb, F_lv_label_set_text, @@ -376,7 +378,8 @@ static const AMX_NATIVE lvgl_proxys[] = { // Indices start at -3000 F_lv_obj_set_style_local_ptr, }; -static const AMX_NATIVE pawn_proxys[] = { // Indices start at -2000 +static const AMX_NATIVE pawn_proxys[] = { + // Indices start at -2000 F_sprintf, F_read_datetime, F_read_datetime_short_str, @@ -501,13 +504,14 @@ int Pawn::LoadProgram() { memcpy(header, file, hdr.cod); - if (hdr.flags & AMX_FLAG_OVERLAY) { - datablock = malloc(hdr.stp - hdr.dat); // This block contains data, heap and stack - if (datablock == NULL) - return AMX_ERR_MEMORY; + datablock = malloc(hdr.stp - hdr.dat); // This block contains data, heap and stack + if (datablock == NULL) + return AMX_ERR_MEMORY; - memcpy(datablock, file + hdr.dat, hdr.hea - hdr.dat); + memcpy(datablock, file + hdr.dat, hdr.hea - hdr.dat); + amx.data = (unsigned char*) datablock; + if (hdr.flags & AMX_FLAG_OVERLAY) { constexpr int overlaypool_overhead = 8; overlaypool = malloc(max_overlay_size + overlaypool_overhead); if (overlaypool == NULL) @@ -515,7 +519,6 @@ int Pawn::LoadProgram() { amx_poolinit(&amx_pool, overlaypool, max_overlay_size + overlaypool_overhead); - amx.data = (unsigned char*) datablock; amx.overlay = prun_Overlay; result = amx_Init(&amx, header); @@ -528,13 +531,9 @@ int Pawn::LoadProgram() { overlaypool = NULL; } } else { - datablock = malloc(hdr.stp); // This block contains code, data, heap and stack - if (datablock == NULL) - return AMX_ERR_MEMORY; - - memcpy(datablock, file, hdr.size); + amx.flags |= AMX_FLAG_DSEG_INIT; - result = amx_Init(&amx, datablock); + result = amx_Init(&amx, (void*) file); if (result != AMX_ERR_NONE) { free(header); header = NULL; From bf82df3029f4e109a68c62136b86391647493701 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Wed, 31 Dec 2025 02:04:09 +0100 Subject: [PATCH 23/26] Load programs from external flash files --- src/displayapp/screens/Pawn.cpp | 82 +++-- src/displayapp/screens/Pawn.h | 60 +++- src/displayapp/screens/WatchFaceDigital.cpp | 2 +- src/displayapp/screens/watchface_digital.h | 344 ++++++++++---------- 4 files changed, 278 insertions(+), 210 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 08a2055d73..150900b20e 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -6,12 +6,15 @@ using namespace Pinetime::Applications::Screens; +#define LOG_PREFIX "[Pawn] " + enum { PAWN_ERR_PARAMCOUNT = 100, PAWN_ERR_MISSINGHANDLER, PAWN_ERR_INVALIDSTRING, PAWN_ERR_INVALIDSETTING, PAWN_ERR_INVALIDTRAMPOLINE, + PAWN_ERR_FILE, PAWN_ERR_FIRST = PAWN_ERR_PARAMCOUNT, }; @@ -26,7 +29,7 @@ enum { #define PAWN_INST ((Pawn*) amx->userdata[0]) -constexpr int max_overlay_size = 512; +constexpr int max_overlay_size = 2048; static void label_set_text(AMX* amx, lv_obj_t* label, cell str) { char* text; @@ -464,10 +467,13 @@ static int AMXAPI prun_Overlay(AMX* amx, int index) { amx->code = (unsigned char*) amx_poolfind(&PAWN_INST->amx_pool, index); if (amx->code == NULL) { + NRF_LOG_INFO(LOG_PREFIX "Reading overlay %d, %d bytes", index, tbl->size); + if ((amx->code = (unsigned char*) amx_poolalloc(&PAWN_INST->amx_pool, tbl->size, index)) == NULL) return AMX_ERR_OVERLAY; - memcpy(amx->code, PAWN_INST->file + hdr->cod + tbl->offset, tbl->size); + if (PAWN_INST->file->Read(amx->code, tbl->size, hdr->cod + tbl->offset) < (size_t) tbl->size) + return PAWN_ERR_FILE; } return AMX_ERR_NONE; @@ -488,9 +494,12 @@ static int AMXAPI prun_Callback(struct tagAMX* amx, cell index, cell* result, co } int Pawn::LoadProgram() { + NRF_LOG_INFO(LOG_PREFIX "Loading program"); + int result; AMX_HEADER hdr; - memcpy(&hdr, file, sizeof(hdr)); + if (file->Read((uint8_t*) &hdr, sizeof(hdr), 0) < sizeof(hdr)) + return PAWN_ERR_FILE; if (hdr.magic != AMX_MAGIC) return AMX_ERR_FORMAT; @@ -498,48 +507,57 @@ int Pawn::LoadProgram() { memset(&amx, 0, sizeof(amx)); amx.userdata[0] = this; - header = malloc(hdr.cod); + header = std::make_unique(hdr.cod); if (header == NULL) return AMX_ERR_MEMORY; - memcpy(header, file, hdr.cod); + if (file->Read((uint8_t*) header.get(), hdr.cod, 0) < (size_t) hdr.cod) + return PAWN_ERR_FILE; - datablock = malloc(hdr.stp - hdr.dat); // This block contains data, heap and stack + datablock = std::make_unique(hdr.stp - hdr.dat); // This block contains data, heap and stack if (datablock == NULL) return AMX_ERR_MEMORY; - memcpy(datablock, file + hdr.dat, hdr.hea - hdr.dat); - amx.data = (unsigned char*) datablock; + if (file->Read((uint8_t*) datablock.get(), hdr.hea - hdr.dat, hdr.dat) < (size_t) hdr.hea - hdr.dat) + return PAWN_ERR_FILE; + + amx.data = (unsigned char*) datablock.get(); if (hdr.flags & AMX_FLAG_OVERLAY) { + NRF_LOG_INFO(LOG_PREFIX "Program has overlays"); + constexpr int overlaypool_overhead = 8; - overlaypool = malloc(max_overlay_size + overlaypool_overhead); + overlaypool = std::make_unique(max_overlay_size + overlaypool_overhead); if (overlaypool == NULL) return AMX_ERR_MEMORY; - amx_poolinit(&amx_pool, overlaypool, max_overlay_size + overlaypool_overhead); + amx_poolinit(&amx_pool, overlaypool.get(), max_overlay_size + overlaypool_overhead); amx.overlay = prun_Overlay; - result = amx_Init(&amx, header); - if (result != AMX_ERR_NONE) { - free(header); - header = NULL; - free(datablock); - datablock = NULL; - free(overlaypool); - overlaypool = NULL; - } + result = amx_Init(&amx, header.get()); } else { + NRF_LOG_INFO(LOG_PREFIX "Program doesn't have overlays"); + amx.flags |= AMX_FLAG_DSEG_INIT; - result = amx_Init(&amx, (void*) file); - if (result != AMX_ERR_NONE) { - free(header); - header = NULL; - free(datablock); - datablock = NULL; + // Happy path: the file is backed by a const array and we can reference it directly + const uint8_t* code = file->GetConst(); + + if (code == nullptr || true) { + // Slow path: we must read the whole file into memory + NRF_LOG_INFO(LOG_PREFIX "Loading program into RAM"); + + filecode = std::make_unique(hdr.size); + if (file->Read(filecode.get(), hdr.size, 0) < (size_t) hdr.size) + return PAWN_ERR_FILE; + + code = filecode.get(); + } else { + NRF_LOG_INFO(LOG_PREFIX "Loaded program from constant") } + + result = amx_Init(&amx, (void*) code); } return result; @@ -547,11 +565,10 @@ int Pawn::LoadProgram() { #include "program.h" -Pawn::Pawn(AppControllers& controllers) : Pawn(program, controllers) { - (void) program_len; +Pawn::Pawn(AppControllers& controllers) : Pawn(controllers, std::make_unique(controllers.filesystem, "/flash.amx")) { } -Pawn::Pawn(const uint8_t* file, AppControllers& controllers) : controllers(controllers), file(file) { +Pawn::Pawn(AppControllers& controllers, std::unique_ptr file) : controllers(controllers), file(std::move(file)) { int result = LoadProgram(); if (result != AMX_ERR_NONE) { ShowError(result); @@ -604,13 +621,6 @@ Pawn::~Pawn() { CleanUI(); amx_Cleanup(&amx); - - if (header) - free(header); - if (datablock) - free(datablock); - if (overlaypool) - free(overlaypool); } void Pawn::Refresh() { @@ -631,6 +641,8 @@ void Pawn::ShowError(unsigned int amx_err) { "missing event handler", // PAWN_ERR_MISSINGHANDLER "invalid string", // PAWN_ERR_INVALIDSTRING "invalid setting", // PAWN_ERR_INVALIDSETTING + "invalid trampoline", // PAWN_ERR_INVALIDTRAMPOLINE + "file read error", // PAWN_ERR_FILE }; if (amx_err == AMX_ERR_EXIT) { diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index 38ef071aa0..478726f0b2 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -17,8 +17,62 @@ namespace Pinetime { class Pawn : public Screen { public: + struct File { + virtual ~File() = default; + + virtual const uint8_t* GetConst() { + return nullptr; + } + + virtual size_t Read(uint8_t* buffer, size_t size, size_t offset) = 0; + }; + + class ConstFile : public File { + const uint8_t* backing; + size_t size; + + public: + ConstFile(const uint8_t* backing, size_t size) : backing(backing), size(size) { + } + + const uint8_t* GetConst() override { + return backing; + } + + size_t Read(uint8_t* buffer, size_t size, size_t offset) override { + if (size + offset > this->size) + return 0; + memcpy(buffer, backing + offset, size); + return size; + } + }; + + class LfsFile : public File { + Controllers::FS& fs; + lfs_file_t file; + bool ok; + + public: + LfsFile(Controllers::FS& fs, const char* path) : fs(fs) { + ok = fs.FileOpen(&file, path, LFS_O_RDONLY) == LFS_ERR_OK; + } + + ~LfsFile() override { + if (ok) + fs.FileClose(&file); + } + + size_t Read(uint8_t* buffer, size_t size, size_t offset) override { + if (!ok) + return 0; + + fs.FileSeek(&file, offset); + return fs.FileRead(&file, buffer, size); + } + }; + Pawn(AppControllers& controllers); - Pawn(const uint8_t *file, AppControllers& controllers); + Pawn(AppControllers& controllers, std::unique_ptr file); ~Pawn() override; void Refresh() override; @@ -36,7 +90,7 @@ namespace Pinetime { Widgets::StatusIcons* statusIcons = nullptr; amxPool amx_pool; - const uint8_t *file; + std::unique_ptr file; private: AMX amx; @@ -45,7 +99,7 @@ namespace Pinetime { lv_task_t* taskRefresh = 0; unsigned int queued_error = 0; - void *header = nullptr, *datablock = nullptr, *overlaypool = nullptr; + std::unique_ptr header, datablock, overlaypool, filecode; int LoadProgram(); void CleanUI(); diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 8605231b95..a6ca85ec33 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -5,5 +5,5 @@ using namespace Pinetime::Applications::Screens; -WatchFaceDigital::WatchFaceDigital(AppControllers& controllers) : Pawn(watchface_digital, controllers) { +WatchFaceDigital::WatchFaceDigital(AppControllers& controllers) : Pawn(controllers, std::make_unique(watchface_digital, watchface_digital_len)) { } diff --git a/src/displayapp/screens/watchface_digital.h b/src/displayapp/screens/watchface_digital.h index 8512ee8400..1ccb23cc17 100644 --- a/src/displayapp/screens/watchface_digital.h +++ b/src/displayapp/screens/watchface_digital.h @@ -1,185 +1,187 @@ const unsigned char watchface_digital[] = { - 0x80, 0x08, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x04, 0x00, 0x08, 0x00, - 0x70, 0x00, 0x00, 0x00, 0xbc, 0x07, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, - 0x48, 0x09, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0xa0, 0x08, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x05, 0x00, 0x08, 0x00, + 0x90, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, + 0x68, 0x09, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x3c, 0x03, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x40, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, - 0x6f, 0x6e, 0x74, 0x5f, 0x6a, 0x6d, 0x65, 0x63, 0x00, 0x73, 0x63, 0x72, - 0x65, 0x65, 0x6e, 0x00, 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0xfc, 0xff, 0x80, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0x10, 0x00, 0x35, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, - 0x7e, 0x00, 0x10, 0x00, 0x89, 0x00, 0x0c, 0x00, 0x7e, 0x00, 0xfc, 0xff, - 0x9c, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x2d, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2a, 0xf8, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x87, 0x00, 0x34, 0x00, 0x92, 0x00, 0x4c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x20, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0x00, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x08, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x24, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0x1b, 0x1b, 0x1b, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x04, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x28, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0x1b, 0x1b, 0xce, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x8e, 0x00, 0x13, 0x00, - 0x8f, 0x00, 0x24, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x30, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0xe7, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x30, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x06, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x2c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0xe7, 0xff, 0x00, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xfb, 0xff, 0x8e, 0x00, 0x10, 0x00, - 0x8f, 0x00, 0x30, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x1c, 0x00, - 0x8e, 0x00, 0x3c, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x14, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x8e, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x42, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x48, 0xf4, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x18, 0x00, - 0x8e, 0x00, 0xc9, 0xff, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x14, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x2c, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x54, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x2f, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0xd4, 0x01, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, - 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x88, 0x00, 0xfc, 0xff, 0x7c, 0x00, 0x34, 0x00, 0xa4, 0x00, 0x01, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, - 0x84, 0x00, 0x0c, 0x00, 0x61, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x64, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x68, 0x00, 0x18, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x00, + 0x10, 0x04, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, + 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, + 0x6a, 0x6d, 0x65, 0x63, 0x00, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x00, + 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, + 0x80, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x10, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, 0x7e, 0x00, 0x10, 0x00, + 0x89, 0x00, 0x0c, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x9c, 0x00, 0x04, 0x00, + 0x4e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x2d, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x2a, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x87, 0x00, 0x34, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x20, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x00, 0x8f, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x08, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x24, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0x1b, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x8f, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x28, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0xce, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x05, 0x00, 0x8e, 0x00, 0x13, 0x00, 0x8f, 0x00, 0x24, 0x00, + 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x30, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0xe7, 0xff, 0x00, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x06, 0x00, 0x8f, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0c, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x2c, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0xe7, 0xff, 0x00, 0x00, + 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0xfb, 0xff, 0x8e, 0x00, 0x10, 0x00, 0x8f, 0x00, 0x30, 0x00, + 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x1c, 0x00, 0x8e, 0x00, 0x3c, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, 0x89, 0x80, 0x00, 0x00, + 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x14, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x55, 0x00, 0x00, 0x00, + 0x8e, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x42, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x8f, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x18, 0x00, 0x8e, 0x00, 0xc9, 0xff, + 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x8f, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2c, 0xf8, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x54, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x2f, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0xd4, 0x01, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, 0x83, 0x00, 0x54, 0x00, + 0xa0, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, + 0x7c, 0x00, 0x34, 0x00, 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x88, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x84, 0x00, 0x0c, 0x00, + 0x61, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x64, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x68, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x7e, 0x00, 0xfc, 0xff, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x7b, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, + 0x84, 0x00, 0x0c, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x7e, 0x00, 0xfc, 0xff, 0xa0, 0x00, 0xf4, 0xff, 0x88, 0x00, 0xfc, 0xff, + 0x92, 0x00, 0x54, 0x00, 0x94, 0x00, 0xfc, 0xff, 0x7c, 0x00, 0x34, 0x00, + 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x6c, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x78, 0x00, 0x18, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x24, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0xfc, 0xff, 0x84, 0x00, 0x0c, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0xa0, 0x00, 0xf4, 0xff, - 0x88, 0x00, 0xfc, 0xff, 0x92, 0x00, 0x54, 0x00, 0x94, 0x00, 0xfc, 0xff, + 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x92, 0x00, 0x88, 0x00, 0x92, 0x00, 0x84, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x2e, 0xf8, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x34, 0x00, 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x6c, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x78, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x30, 0xf8, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, - 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x92, 0x00, 0x88, 0x00, - 0x92, 0x00, 0x84, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2e, 0xf8, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x34, 0x00, 0xa4, 0x00, 0x01, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, - 0xa0, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x08, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x0c, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x88, 0x00, 0x92, 0x00, 0x84, 0x00, + 0x92, 0x00, 0x8c, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x88, 0x00, - 0x92, 0x00, 0x84, 0x00, 0x92, 0x00, 0x8c, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x88, 0x00, 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x08, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x84, 0x00, 0x92, 0x00, 0x98, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x30, 0xf8, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, - 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x2b, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xa4, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x21, 0x00, 0x00, 0x00, 0xbc, 0xfa, 0xff, 0xff, 0x23, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xa4, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x10, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0xa8, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, - 0x29, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0xac, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x60, 0xfa, 0xff, 0xff, 0x88, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, - 0x28, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0xb0, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x3c, 0xfa, 0xff, 0xff, 0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0xfc, 0xff, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x01, 0x00, 0x88, 0x00, 0xfc, 0xff, 0x7e, 0x00, 0xfc, 0xff, - 0x23, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xb0, 0x00, - 0xa4, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, - 0x1b, 0x1b, 0xce, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x92, 0x00, 0xac, 0x00, 0x92, 0x00, 0xb4, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x84, 0x00, 0x92, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, - 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x28, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0x1b, 0x00, + 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x2b, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0xa4, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x4d, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0xa4, 0x00, 0x23, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x10, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x83, 0x00, 0xa8, 0x00, 0x18, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x9c, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, 0x29, 0xf8, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xac, 0x00, + 0x8e, 0x00, 0x08, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x88, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, 0x28, 0xf8, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xb0, 0x00, + 0x8e, 0x00, 0x08, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, + 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x01, 0x00, + 0x88, 0x00, 0xfc, 0xff, 0x7e, 0x00, 0xfc, 0xff, 0x23, 0x00, 0x00, 0x00, + 0xcc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xb0, 0x00, 0xa4, 0x00, 0x03, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0xce, 0x00, 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0xb8, 0x00, - 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x27, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xbc, 0x00, 0x8e, 0x00, 0x08, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x24, 0xf9, 0xff, 0xff, 0x23, 0x00, 0x00, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x92, 0x00, 0xbc, 0x00, 0x92, 0x00, 0xc0, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x30, 0xf8, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, - 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x88, 0xef, - 0x00, 0x8b, 0x95, 0xef, 0x00, 0xa9, 0x84, 0xef, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0xac, 0x00, + 0x92, 0x00, 0xb4, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0x1b, 0x00, 0x89, 0x80, 0x00, 0x00, + 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0xb8, 0x00, 0x8f, 0x00, 0x28, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x27, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0xbc, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x4d, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x92, 0x00, 0xbc, 0x00, 0x92, 0x00, 0xc0, 0x00, 0x8e, 0x00, 0x05, 0x00, + 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x30, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, + 0x66, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x88, 0xef, 0x00, 0x8b, 0x95, 0xef, + 0x00, 0xa9, 0x84, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x41, 0x00, 0x00, 0x4d, 0x50, - 0x3a, 0x64, 0x32, 0x25, 0x64, 0x32, 0x30, 0x25, 0x00, 0x00, 0x00, 0x00, - 0x64, 0x32, 0x30, 0x25, 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, - 0x64, 0x25, 0x20, 0x73, 0x00, 0x64, 0x25, 0x20, 0x25, 0x20, 0x73, 0x25, - 0x73, 0x25, 0x20, 0x64, 0x00, 0x64, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x64, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x64, 0x25 + 0x00, 0x00, 0x4d, 0x41, 0x00, 0x00, 0x4d, 0x50, 0x3a, 0x64, 0x32, 0x25, + 0x64, 0x32, 0x30, 0x25, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, + 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x64, 0x25, 0x20, 0x73, + 0x00, 0x64, 0x25, 0x20, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, + 0x00, 0x64, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x25, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x25 }; -unsigned int watchface_digital_len = 2176; +unsigned int watchface_digital_len = 2208; From d6b16fb76c9604b6b198aa38925bc9a382eda79e Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Wed, 31 Dec 2025 02:42:45 +0100 Subject: [PATCH 24/26] Guard execution if errored --- src/displayapp/screens/Pawn.cpp | 8 ++++++-- src/displayapp/screens/Pawn.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 150900b20e..3c5a598f75 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -47,6 +47,9 @@ static void event_handler(lv_obj_t* obj, lv_event_t event) { AMX* amx = (AMX*) lv_obj_get_user_data(lv_scr_act()); int handler_index = (int) lv_obj_get_user_data(obj); + if (PAWN_INST->is_errored) + return; + amx_Push(amx, event); int result = amx_Exec(amx, nullptr, handler_index); if (result != AMX_ERR_NONE) { @@ -662,6 +665,7 @@ void Pawn::ShowError(unsigned int amx_err) { } void Pawn::ShowError(const char* msg) { + is_errored = true; CleanUI(); lv_obj_t* msglbl = lv_label_create(lv_scr_act(), nullptr); @@ -687,7 +691,7 @@ void Pawn::QueueError(unsigned int amx_err) { } bool Pawn::OnTouchEvent(TouchEvents event) { - if (gesture_index < 0) + if (gesture_index < 0 || is_errored) return false; cell ret; @@ -704,7 +708,7 @@ bool Pawn::OnTouchEvent(TouchEvents event) { } bool Pawn::OnTouchEvent(uint16_t x, uint16_t y) { - if (touch_index < 0) + if (touch_index < 0 || is_errored) return false; cell ret; diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index 478726f0b2..afdb38ad47 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -92,6 +92,8 @@ namespace Pinetime { amxPool amx_pool; std::unique_ptr file; + bool is_errored = false; + private: AMX amx; From db17adf7b7cf2dc23e2b8c38cbe26c22c487bc96 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Wed, 31 Dec 2025 04:24:08 +0100 Subject: [PATCH 25/26] Use unique_ptr for status icons --- src/displayapp/screens/Pawn.cpp | 13 +++++-------- src/displayapp/screens/Pawn.h | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/displayapp/screens/Pawn.cpp b/src/displayapp/screens/Pawn.cpp index 3c5a598f75..5266ae2303 100644 --- a/src/displayapp/screens/Pawn.cpp +++ b/src/displayapp/screens/Pawn.cpp @@ -296,10 +296,10 @@ static cell AMX_NATIVE_CALL F_read_datetime_short_str(AMX* amx, const cell* para static cell AMX_NATIVE_CALL F_status_icons_create(AMX* amx, const cell*) { Pawn* pawn = PAWN_INST; - if (pawn->statusIcons == nullptr) { - pawn->statusIcons = new Pinetime::Applications::Widgets::StatusIcons(pawn->controllers.batteryController, - pawn->controllers.bleController, - pawn->controllers.alarmController); + if (!pawn->statusIcons) { + pawn->statusIcons = std::make_unique(pawn->controllers.batteryController, + pawn->controllers.bleController, + pawn->controllers.alarmController); pawn->statusIcons->Create(); } @@ -612,10 +612,7 @@ void Pawn::CleanUI() { taskRefresh = nullptr; } - if (statusIcons) { - delete statusIcons; - statusIcons = nullptr; - } + statusIcons.reset(); lv_obj_clean(lv_scr_act()); } diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index afdb38ad47..b316e92ae7 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -87,7 +87,7 @@ namespace Pinetime { Utility::DirtyValue> currentDateTime {}; AppControllers& controllers; - Widgets::StatusIcons* statusIcons = nullptr; + std::unique_ptr statusIcons; amxPool amx_pool; std::unique_ptr file; From 5c4d580110066afc7f42ce203c1d76e57f39b53a Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Thu, 8 Jan 2026 20:43:56 +0100 Subject: [PATCH 26/26] Add heatshrink compression Not sure if this is worth it or not, it adds a couple KBs of program size and more RAM usage but it does reduce Pawn program size by more than half so it could be worth it in the long run. The Seek method is very inefficient for obvious reasons, ideally we would compress each Pawn overlay independently instead of the whole amx file. We should also probably move the heatshrink source files to a different folder. --- src/CMakeLists.txt | 1 + src/displayapp/screens/Pawn.h | 91 ++++- src/displayapp/screens/WatchFaceDigital.cpp | 2 +- src/displayapp/screens/watchface_digital.h | 260 ++++---------- src/pawn/heatshrink_common.h | 20 ++ src/pawn/heatshrink_config.h | 26 ++ src/pawn/heatshrink_decoder.c | 367 ++++++++++++++++++++ src/pawn/heatshrink_decoder.h | 108 ++++++ 8 files changed, 681 insertions(+), 194 deletions(-) create mode 100644 src/pawn/heatshrink_common.h create mode 100644 src/pawn/heatshrink_config.h create mode 100644 src/pawn/heatshrink_decoder.c create mode 100644 src/pawn/heatshrink_decoder.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8a91ffce15..41147bbb57 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -358,6 +358,7 @@ set(LVGL_SRC list(APPEND PAWN_SRC pawn/amx.c pawn/amxpool.c + pawn/heatshrink_decoder.c ) list(APPEND IMAGE_FILES diff --git a/src/displayapp/screens/Pawn.h b/src/displayapp/screens/Pawn.h index b316e92ae7..5af495066b 100644 --- a/src/displayapp/screens/Pawn.h +++ b/src/displayapp/screens/Pawn.h @@ -10,6 +10,7 @@ #include "pawn/amx.h" #include "pawn/amxpool.h" +#include "pawn/heatshrink_decoder.h" namespace Pinetime { namespace Applications { @@ -24,12 +25,18 @@ namespace Pinetime { return nullptr; } - virtual size_t Read(uint8_t* buffer, size_t size, size_t offset) = 0; + virtual void Seek(size_t position) = 0; + virtual size_t Read(uint8_t* buffer, size_t size) = 0; + + size_t Read(uint8_t* buffer, size_t size, size_t position) { + Seek(position); + return Read(buffer, size); + } }; class ConstFile : public File { const uint8_t* backing; - size_t size; + size_t size, position; public: ConstFile(const uint8_t* backing, size_t size) : backing(backing), size(size) { @@ -39,10 +46,17 @@ namespace Pinetime { return backing; } - size_t Read(uint8_t* buffer, size_t size, size_t offset) override { - if (size + offset > this->size) + void Seek(size_t position) override { + this->position = position; + } + + size_t Read(uint8_t* buffer, size_t size) override { + if (position >= this->size) return 0; - memcpy(buffer, backing + offset, size); + if (position + size > this->size) + size = this->size - position; + memcpy(buffer, backing + position, size); + position += size; return size; } }; @@ -62,15 +76,76 @@ namespace Pinetime { fs.FileClose(&file); } - size_t Read(uint8_t* buffer, size_t size, size_t offset) override { + void Seek(size_t position) override { + fs.FileSeek(&file, position); + } + + size_t Read(uint8_t* buffer, size_t size) override { if (!ok) return 0; - - fs.FileSeek(&file, offset); return fs.FileRead(&file, buffer, size); } }; + class HeatshrinkFile : public File { + std::unique_ptr inner; + heatshrink_decoder decoder; + + size_t real_pos; + uint8_t pending_inner_read[100]; + size_t pending_pos = 0, pending_size = 0; + + void Reset() { + heatshrink_decoder_reset(&decoder); + pending_size = 0; + pending_pos = 0; + real_pos = 0; + inner->Seek(0); + } + + public: + HeatshrinkFile(std::unique_ptr inner) : inner(std::move(inner)) { + Reset(); + } + + /** + * Seek to a specified position in the *uncompressed* file. + */ + void Seek(size_t position) override { + if (position < this->real_pos) // We have to rewind + Reset(); + + uint8_t discard[50]; + while (this->real_pos < position) { + size_t remaining = position - this->real_pos; + Read(discard, remaining > sizeof(discard) ? sizeof(discard) : remaining); + } + } + + size_t Read(uint8_t* buffer, size_t size) override { + size_t actual_read, total_read = 0; + + while (total_read < size) { + HSD_poll_res res = heatshrink_decoder_poll(&decoder, buffer + total_read, size - total_read, &actual_read); + total_read += actual_read; + real_pos += actual_read; + + if (res == HSDR_POLL_EMPTY) { + if (pending_size == 0) { + pending_size = inner->Read(pending_inner_read, sizeof(pending_inner_read)); + pending_pos = 0; + } + + heatshrink_decoder_sink(&decoder, pending_inner_read + pending_pos, pending_size, &actual_read); + pending_size -= actual_read; + pending_pos += actual_read; + } + } + + return total_read; + } + }; + Pawn(AppControllers& controllers); Pawn(AppControllers& controllers, std::unique_ptr file); ~Pawn() override; diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index a6ca85ec33..4903909c56 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -5,5 +5,5 @@ using namespace Pinetime::Applications::Screens; -WatchFaceDigital::WatchFaceDigital(AppControllers& controllers) : Pawn(controllers, std::make_unique(watchface_digital, watchface_digital_len)) { +WatchFaceDigital::WatchFaceDigital(AppControllers& controllers) : Pawn(controllers, std::make_unique(std::make_unique(watchface_digital, watchface_digital_len))) { } diff --git a/src/displayapp/screens/watchface_digital.h b/src/displayapp/screens/watchface_digital.h index 1ccb23cc17..238a4c1db5 100644 --- a/src/displayapp/screens/watchface_digital.h +++ b/src/displayapp/screens/watchface_digital.h @@ -1,187 +1,77 @@ const unsigned char watchface_digital[] = { - 0xa0, 0x08, 0x00, 0x00, 0xe0, 0xf1, 0x0b, 0x0b, 0x05, 0x00, 0x08, 0x00, - 0x90, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, - 0x68, 0x09, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x00, - 0x10, 0x04, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x72, - 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x5f, - 0x6a, 0x6d, 0x65, 0x63, 0x00, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x00, - 0xad, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, - 0x80, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x10, 0x00, - 0x35, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, 0x7e, 0x00, 0x10, 0x00, - 0x89, 0x00, 0x0c, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x9c, 0x00, 0x04, 0x00, - 0x4e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x2d, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x03, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x2a, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x34, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x20, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x00, 0xff, 0x00, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x08, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x24, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0x1b, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x28, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0xce, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x8e, 0x00, 0x13, 0x00, 0x8f, 0x00, 0x24, 0x00, - 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x50, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x30, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0xe7, 0xff, 0x00, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x06, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0c, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x2c, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0xe7, 0xff, 0x00, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0xfb, 0xff, 0x8e, 0x00, 0x10, 0x00, 0x8f, 0x00, 0x30, 0x00, - 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x1c, 0x00, 0x8e, 0x00, 0x3c, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x95, 0x00, 0x02, 0x00, 0x99, 0x99, 0x99, 0x00, 0x89, 0x80, 0x00, 0x00, - 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x14, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x8e, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x42, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x4c, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x48, 0xf4, 0xff, 0xff, - 0x0c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x18, 0x00, 0x8e, 0x00, 0xc9, 0xff, - 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, 0x14, 0xfc, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2c, 0xf8, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x54, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x2f, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xd4, 0x01, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, 0x83, 0x00, 0x54, 0x00, - 0xa0, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x88, 0x00, 0xfc, 0xff, - 0x7c, 0x00, 0x34, 0x00, 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, 0x84, 0x00, 0x0c, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x83, 0x00, 0x64, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x68, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x18, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0xfc, 0xff, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x7b, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, - 0x84, 0x00, 0x0c, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0xfc, 0xff, 0xa0, 0x00, 0xf4, 0xff, 0x88, 0x00, 0xfc, 0xff, - 0x92, 0x00, 0x54, 0x00, 0x94, 0x00, 0xfc, 0xff, 0x7c, 0x00, 0x34, 0x00, - 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x6c, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x78, 0x00, 0x18, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x14, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x92, 0x00, 0x88, 0x00, 0x92, 0x00, 0x84, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x2e, 0xf8, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x34, 0x00, 0xa4, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x08, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x0c, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x88, 0x00, 0x92, 0x00, 0x84, 0x00, - 0x92, 0x00, 0x8c, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x83, 0x00, 0x54, 0x00, - 0xa0, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x92, 0x00, 0x88, 0x00, - 0x83, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x84, 0x00, 0x92, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, - 0x1c, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x1c, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x2b, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0xa4, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x4d, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0xa4, 0x00, 0x23, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x10, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x83, 0x00, 0xa8, 0x00, 0x18, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x20, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, 0x29, 0xf8, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xac, 0x00, - 0x8e, 0x00, 0x08, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x88, 0x00, 0xfc, 0xff, 0x70, 0x00, 0x00, 0x00, 0x28, 0xf8, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x8e, 0x00, 0xb0, 0x00, - 0x8e, 0x00, 0x08, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xfc, 0xff, - 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x01, 0x00, - 0x88, 0x00, 0xfc, 0xff, 0x7e, 0x00, 0xfc, 0xff, 0x23, 0x00, 0x00, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xb0, 0x00, 0xa4, 0x00, 0x03, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x00, 0x00, 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0xce, 0x00, - 0x89, 0x80, 0x00, 0x00, 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x44, 0xf4, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0xac, 0x00, - 0x92, 0x00, 0xb4, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x92, 0x00, 0x38, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, - 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x95, 0x00, 0x02, 0x00, 0x1b, 0x1b, 0x1b, 0x00, 0x89, 0x80, 0x00, 0x00, - 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0x44, 0xf4, 0xff, 0xff, - 0x14, 0x00, 0x00, 0x00, 0x92, 0x00, 0xb8, 0x00, 0x8f, 0x00, 0x28, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x24, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x28, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x27, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0xbc, 0x00, 0x8e, 0x00, 0x08, 0x00, 0x4d, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x92, 0x00, 0xbc, 0x00, 0x92, 0x00, 0xc0, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x92, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xff, 0xff, - 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x38, 0x00, 0x8f, 0x00, 0x30, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x46, 0xf4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0xfc, 0xff, 0xff, - 0x04, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x2c, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x13, 0xfc, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x04, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x88, 0xef, 0x00, 0x8b, 0x95, 0xef, - 0x00, 0xa9, 0x84, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x4d, 0x41, 0x00, 0x00, 0x4d, 0x50, 0x3a, 0x64, 0x32, 0x25, - 0x64, 0x32, 0x30, 0x25, 0x00, 0x00, 0x00, 0x00, 0x64, 0x32, 0x30, 0x25, - 0x32, 0x30, 0x25, 0x3a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x73, 0x25, 0x64, 0x25, 0x20, 0x73, - 0x00, 0x64, 0x25, 0x20, 0x25, 0x20, 0x73, 0x25, 0x73, 0x25, 0x20, 0x64, - 0x00, 0x64, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x25, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x25 + 0xd0, 0x42, 0x00, 0x63, 0xe0, 0xf8, 0xc2, 0xe1, 0x70, 0x58, 0x00, 0x20, + 0x72, 0x00, 0xf2, 0xee, 0x41, 0xc2, 0x6b, 0x68, 0x84, 0x80, 0xc6, 0x04, + 0x0f, 0x29, 0xe0, 0x0c, 0xa8, 0x80, 0x3a, 0xaa, 0x00, 0xca, 0xe8, 0x07, + 0x68, 0x08, 0x0c, 0xae, 0xc0, 0x32, 0x82, 0x00, 0xca, 0xfe, 0x4f, 0x6c, + 0x48, 0x1d, 0x82, 0x67, 0x3c, 0x81, 0x80, 0xc6, 0x20, 0x08, 0x29, 0xa0, + 0x2c, 0xa1, 0x00, 0xb2, 0x09, 0x9c, 0xc0, 0x06, 0x51, 0xf8, 0x05, 0x02, + 0xe5, 0x65, 0xb3, 0x00, 0x86, 0xe7, 0x68, 0x80, 0x59, 0xad, 0xf6, 0xeb, + 0xa5, 0x7e, 0xd5, 0x6d, 0xb2, 0xd8, 0xe0, 0x17, 0x3b, 0x18, 0x40, 0x6c, + 0xb6, 0xe8, 0x06, 0xb4, 0x3e, 0x51, 0xe0, 0x19, 0x67, 0x20, 0x1f, 0xcf, + 0xfe, 0x02, 0x01, 0x0c, 0x80, 0x45, 0x41, 0x65, 0x7e, 0x22, 0x8c, 0x02, + 0x6a, 0x07, 0x2c, 0x40, 0x4c, 0x81, 0x66, 0x63, 0x10, 0xb8, 0x81, 0xc4, + 0x16, 0x22, 0x31, 0x28, 0x8d, 0x38, 0x5e, 0xd7, 0x00, 0x19, 0x4b, 0x7f, + 0x1f, 0xff, 0xf9, 0xec, 0xf1, 0xd0, 0x03, 0x60, 0x83, 0xce, 0x54, 0x0f, + 0x23, 0x99, 0xe1, 0xd0, 0x25, 0x92, 0x80, 0x53, 0x02, 0xe4, 0x00, 0x1c, + 0x78, 0xad, 0xa9, 0x1f, 0x40, 0xd8, 0x91, 0x44, 0x36, 0x72, 0x00, 0xba, + 0x00, 0xcf, 0x2a, 0xf1, 0x32, 0x09, 0x62, 0x4f, 0x02, 0x27, 0x20, 0xb8, + 0x89, 0xce, 0x88, 0x27, 0x28, 0xa0, 0x7d, 0x80, 0x6a, 0xf5, 0x12, 0x19, + 0x87, 0xde, 0x28, 0x86, 0x10, 0xfa, 0x17, 0xc6, 0x10, 0x5f, 0xf2, 0xfb, + 0x49, 0x0b, 0xf9, 0x1b, 0x00, 0x09, 0x7d, 0x82, 0xe2, 0x5f, 0xf0, 0x1a, + 0xac, 0x44, 0xbe, 0xa1, 0xf5, 0x2f, 0xca, 0xff, 0xcb, 0xef, 0x28, 0x2f, + 0xf7, 0x38, 0xbe, 0xc1, 0x71, 0x2f, 0xf8, 0x0c, 0x60, 0xa0, 0x32, 0x89, + 0x96, 0xd0, 0x3e, 0xe5, 0xf9, 0xa8, 0x17, 0xfc, 0xbe, 0xd3, 0x02, 0xfe, + 0x79, 0xff, 0xe0, 0x71, 0x2f, 0xa8, 0x5c, 0x4b, 0xfe, 0x03, 0x58, 0x32, + 0xfd, 0x83, 0xea, 0x5f, 0x92, 0x68, 0x97, 0xfc, 0xbe, 0xb2, 0xc2, 0xff, + 0x97, 0xd8, 0x2e, 0x25, 0xff, 0x01, 0x8f, 0xef, 0xfe, 0x03, 0x18, 0x81, + 0x6d, 0x03, 0xee, 0x5f, 0x9a, 0x61, 0x7f, 0xcb, 0xed, 0x1c, 0x0b, 0x94, + 0xf0, 0xc7, 0x09, 0xb5, 0x09, 0x88, 0xee, 0xcf, 0xf7, 0x99, 0x00, 0x09, + 0xfd, 0x84, 0x6a, 0x7f, 0x72, 0xff, 0x97, 0xe4, 0x3a, 0x25, 0xb9, 0x82, + 0x40, 0x2a, 0xa0, 0xb3, 0x1f, 0xa0, 0x5c, 0x44, 0xe7, 0x42, 0x5f, 0xe0, + 0x0c, 0xe1, 0x08, 0x36, 0x0f, 0xaa, 0xff, 0xcb, 0xfe, 0x5f, 0x18, 0xc0, + 0x5c, 0xb9, 0x2f, 0x72, 0x1d, 0xd8, 0x4c, 0x47, 0x77, 0x66, 0x01, 0x95, + 0x38, 0x06, 0x51, 0xe1, 0xdb, 0x4b, 0x3f, 0x01, 0x71, 0x03, 0x11, 0x4c, + 0xaa, 0x80, 0xf4, 0x97, 0x83, 0xc9, 0x32, 0x20, 0x01, 0x91, 0x80, 0xcb, + 0xa9, 0x01, 0x01, 0x8e, 0x72, 0x00, 0x38, 0x1c, 0x18, 0x6c, 0xb4, 0x0a, + 0xf2, 0x83, 0x84, 0xcb, 0x10, 0x0f, 0x2b, 0xe4, 0x02, 0x69, 0x00, 0xd2, + 0x40, 0x03, 0x82, 0x23, 0x30, 0x78, 0x80, 0x06, 0xfc, 0x13, 0x2c, 0x24, + 0x01, 0x02, 0x36, 0x13, 0x39, 0x80, 0xc8, 0x5e, 0x36, 0x48, 0x04, 0x88, + 0x0e, 0x49, 0x33, 0x05, 0x8d, 0xa1, 0x02, 0x48, 0x79, 0xa3, 0x2a, 0xc9, + 0x32, 0x20, 0xf9, 0x89, 0xa5, 0xc8, 0xde, 0x64, 0x33, 0x92, 0x01, 0xca, + 0x38, 0x03, 0x2b, 0xd8, 0x0c, 0x82, 0xc4, 0xd3, 0x42, 0x39, 0x85, 0xcc, + 0xc6, 0xf5, 0xf3, 0x1b, 0x03, 0xcd, 0x26, 0x24, 0xc1, 0x47, 0x9a, 0xec, + 0xf2, 0x89, 0x7e, 0x43, 0xad, 0xb1, 0x0f, 0x57, 0x84, 0x3a, 0x63, 0xa0, + 0x10, 0x57, 0x59, 0x4e, 0x0f, 0x69, 0x30, 0x75, 0x90, 0x9c, 0xc1, 0xe6, + 0x8f, 0x10, 0x48, 0xa7, 0xf4, 0x1e, 0xa9, 0xf7, 0x11, 0x89, 0xa4, 0x40, + 0x62, 0x81, 0x10, 0x99, 0xcb, 0x86, 0xe4, 0x23, 0x33, 0x7d, 0xd2, 0x0c, + 0x68, 0x87, 0x14, 0x98, 0x86, 0x44, 0xce, 0x60, 0xb5, 0x3c, 0x88, 0x2c, + 0xc7, 0x6e, 0x03, 0x1c, 0x61, 0xff, 0xff, 0xee, 0xf3, 0x51, 0x9d, 0x00, + 0x67, 0xe3, 0x32, 0x27, 0xd8, 0xfd, 0x73, 0x03, 0xff, 0x1f, 0xa2, 0xfd, + 0x41, 0x22, 0xbf, 0xd0, 0x7a, 0xaf, 0xdf, 0x39, 0x00, 0x02, 0x88, 0x3c, + 0xe5, 0x63, 0x32, 0x03, 0x14, 0x02, 0x2c, 0x03, 0x22, 0x58, 0xaf, 0x44, + 0x06, 0x22, 0xd1, 0xa6, 0x82, 0xca, 0x06, 0x03, 0x26, 0x39, 0x92, 0x45, + 0xae, 0x61, 0x71, 0x05, 0x9c, 0x51, 0x26, 0x91, 0x04, 0xfa, 0x25, 0x44, + 0x16, 0x7a, 0x84, 0x5a, 0x16, 0xc6, 0x40, 0x6b, 0xc2, 0xd8, 0x99, 0x04, + 0x1e, 0x72, 0x92, 0xde, 0x6b, 0x0b, 0x78, 0xcd, 0x11, 0x1a, 0xca, 0x04, + 0x79, 0xb0, 0x11, 0xe4, 0x90, 0x06, 0x45, 0x91, 0x00, 0x0d, 0xf8, 0x56, + 0x40, 0xb3, 0x3f, 0x9d, 0x98, 0x06, 0x47, 0xf9, 0x80, 0x91, 0xd0, 0x3e, + 0x69, 0xf3, 0xe6, 0x2a, 0xd0, 0x86, 0x2a, 0xd1, 0x1e, 0x88, 0x3c, 0xec, + 0x85, 0x34, 0x01, 0xae, 0x56, 0x01, 0x02, 0x80, 0x46, 0xe3, 0x7c, 0xe8, + 0x06, 0x27, 0x00, 0xaf, 0x32, 0x68, 0x9e, 0xce, 0x88, 0xaf, 0x22, 0x99, + 0xe4, 0x93, 0x64, 0x03, 0x1d, 0xa0, 0x9c, 0xa0, 0xa0, 0x72, 0x78, 0x88, + 0x6c, 0xe6, 0x09, 0x72, 0x74, 0x88, 0x6c, 0xc1, 0xe2, 0x2f, 0x19, 0x43, + 0x7f, 0x0f, 0xe7, 0x40, 0x2d, 0xf8, 0x00, 0x4b, 0x7e, 0x5b, 0x6d, 0xc0, + 0xff, 0xc4, 0x71, 0x13, 0x5b, 0x0f, 0xfe, 0x08, 0x0f, 0x40, 0xfa, 0x83, + 0xdc, 0x16, 0x72, 0x73, 0xf9, 0x01, 0x8a, 0x01, 0x16, 0x31, 0xa6, 0xf0, + 0x06, 0x43, 0x91, 0xa6, 0x82, 0xc9, 0xb2, 0x20, 0x01, 0x6d, 0x9d, 0x60, + 0xb6, 0x81, 0x71, 0x01, 0x8f, 0x01, 0x6f, 0xeb, 0x7a, 0x98, 0x1d, 0xf8, + 0x1e, 0xa7, 0x79, 0x96, 0x03, 0xf3, 0x39, 0x00, 0x02, 0x8d, 0x98, 0x0e, + 0x54, 0xe3, 0xc1, 0x80, 0x1f, 0x3d, 0x88, 0xf7, 0xc0, 0x31, 0x79, 0x50, + 0x18, 0xea, 0x70, 0x80, 0x31, 0x00, 0x78, 0x03, 0xc0, 0x1e, 0x00, 0xd3, + 0xe0, 0x80, 0x3d, 0xa2, 0x34, 0x10, 0x19, 0x54, 0x27, 0x56, 0x49, 0x94, + 0x94, 0x04, 0x33, 0x09, 0x28, 0x44, 0xc0, 0xe6, 0x02, 0x29, 0xd0, 0x28, + 0xc4, 0xaf, 0x25, 0x90, 0x5c, 0xc3, 0xe2, 0x04, 0x20, 0x88, 0x81, 0x04, + 0x16, 0x60, 0x11, 0x90, 0x06, 0xc4, 0x16, 0x44, 0xdf, 0x19, 0x11, 0x0d, + 0x01, 0x6e }; -unsigned int watchface_digital_len = 2208; +unsigned int watchface_digital_len = 878; diff --git a/src/pawn/heatshrink_common.h b/src/pawn/heatshrink_common.h new file mode 100644 index 0000000000..243f447029 --- /dev/null +++ b/src/pawn/heatshrink_common.h @@ -0,0 +1,20 @@ +#ifndef HEATSHRINK_H +#define HEATSHRINK_H + +#define HEATSHRINK_AUTHOR "Scott Vokes " +#define HEATSHRINK_URL "https://github.com/atomicobject/heatshrink" + +/* Version 0.4.1 */ +#define HEATSHRINK_VERSION_MAJOR 0 +#define HEATSHRINK_VERSION_MINOR 4 +#define HEATSHRINK_VERSION_PATCH 1 + +#define HEATSHRINK_MIN_WINDOW_BITS 4 +#define HEATSHRINK_MAX_WINDOW_BITS 15 + +#define HEATSHRINK_MIN_LOOKAHEAD_BITS 3 + +#define HEATSHRINK_LITERAL_MARKER 0x01 +#define HEATSHRINK_BACKREF_MARKER 0x00 + +#endif diff --git a/src/pawn/heatshrink_config.h b/src/pawn/heatshrink_config.h new file mode 100644 index 0000000000..69ee3adcd1 --- /dev/null +++ b/src/pawn/heatshrink_config.h @@ -0,0 +1,26 @@ +#ifndef HEATSHRINK_CONFIG_H +#define HEATSHRINK_CONFIG_H + +/* Should functionality assuming dynamic allocation be used? */ +#ifndef HEATSHRINK_DYNAMIC_ALLOC +#define HEATSHRINK_DYNAMIC_ALLOC 0 +#endif + +#if HEATSHRINK_DYNAMIC_ALLOC + /* Optional replacement of malloc/free */ + #define HEATSHRINK_MALLOC(SZ) malloc(SZ) + #define HEATSHRINK_FREE(P, SZ) free(P) +#else + /* Required parameters for static configuration */ + #define HEATSHRINK_STATIC_INPUT_BUFFER_SIZE 32 + #define HEATSHRINK_STATIC_WINDOW_BITS 8 + #define HEATSHRINK_STATIC_LOOKAHEAD_BITS 4 +#endif + +/* Turn on logging for debugging. */ +#define HEATSHRINK_DEBUGGING_LOGS 0 + +/* Use indexing for faster compression. (This requires additional space.) */ +#define HEATSHRINK_USE_INDEX 1 + +#endif diff --git a/src/pawn/heatshrink_decoder.c b/src/pawn/heatshrink_decoder.c new file mode 100644 index 0000000000..0f118cf98a --- /dev/null +++ b/src/pawn/heatshrink_decoder.c @@ -0,0 +1,367 @@ +#include +#include +#include "heatshrink_decoder.h" + +/* States for the polling state machine. */ +typedef enum { + HSDS_TAG_BIT, /* tag bit */ + HSDS_YIELD_LITERAL, /* ready to yield literal byte */ + HSDS_BACKREF_INDEX_MSB, /* most significant byte of index */ + HSDS_BACKREF_INDEX_LSB, /* least significant byte of index */ + HSDS_BACKREF_COUNT_MSB, /* most significant byte of count */ + HSDS_BACKREF_COUNT_LSB, /* least significant byte of count */ + HSDS_YIELD_BACKREF, /* ready to yield back-reference */ +} HSD_state; + +#if HEATSHRINK_DEBUGGING_LOGS +#include +#include +#include +#define LOG(...) fprintf(stderr, __VA_ARGS__) +#define ASSERT(X) assert(X) +static const char *state_names[] = { + "tag_bit", + "yield_literal", + "backref_index_msb", + "backref_index_lsb", + "backref_count_msb", + "backref_count_lsb", + "yield_backref", +}; +#else +#define LOG(...) /* no-op */ +#define ASSERT(X) /* no-op */ +#endif + +typedef struct { + uint8_t *buf; /* output buffer */ + size_t buf_size; /* buffer size */ + size_t *output_size; /* bytes pushed to buffer, so far */ +} output_info; + +#define NO_BITS ((uint16_t)-1) + +/* Forward references. */ +static uint16_t get_bits(heatshrink_decoder *hsd, uint8_t count); +static void push_byte(heatshrink_decoder *hsd, output_info *oi, uint8_t byte); + +#if HEATSHRINK_DYNAMIC_ALLOC +heatshrink_decoder *heatshrink_decoder_alloc(uint16_t input_buffer_size, + uint8_t window_sz2, + uint8_t lookahead_sz2) { + if ((window_sz2 < HEATSHRINK_MIN_WINDOW_BITS) || + (window_sz2 > HEATSHRINK_MAX_WINDOW_BITS) || + (input_buffer_size == 0) || + (lookahead_sz2 < HEATSHRINK_MIN_LOOKAHEAD_BITS) || + (lookahead_sz2 >= window_sz2)) { + return NULL; + } + size_t buffers_sz = (1 << window_sz2) + input_buffer_size; + size_t sz = sizeof(heatshrink_decoder) + buffers_sz; + heatshrink_decoder *hsd = HEATSHRINK_MALLOC(sz); + if (hsd == NULL) { return NULL; } + hsd->input_buffer_size = input_buffer_size; + hsd->window_sz2 = window_sz2; + hsd->lookahead_sz2 = lookahead_sz2; + heatshrink_decoder_reset(hsd); + LOG("-- allocated decoder with buffer size of %zu (%zu + %u + %u)\n", + sz, sizeof(heatshrink_decoder), (1 << window_sz2), input_buffer_size); + return hsd; +} + +void heatshrink_decoder_free(heatshrink_decoder *hsd) { + size_t buffers_sz = (1 << hsd->window_sz2) + hsd->input_buffer_size; + size_t sz = sizeof(heatshrink_decoder) + buffers_sz; + HEATSHRINK_FREE(hsd, sz); + (void)sz; /* may not be used by free */ +} +#endif + +void heatshrink_decoder_reset(heatshrink_decoder *hsd) { + size_t buf_sz = 1 << HEATSHRINK_DECODER_WINDOW_BITS(hsd); + size_t input_sz = HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd); + memset(hsd->buffers, 0, buf_sz + input_sz); + hsd->state = HSDS_TAG_BIT; + hsd->input_size = 0; + hsd->input_index = 0; + hsd->bit_index = 0x00; + hsd->current_byte = 0x00; + hsd->output_count = 0; + hsd->output_index = 0; + hsd->head_index = 0; +} + +/* Copy SIZE bytes into the decoder's input buffer, if it will fit. */ +HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd, + uint8_t *in_buf, size_t size, size_t *input_size) { + if ((hsd == NULL) || (in_buf == NULL) || (input_size == NULL)) { + return HSDR_SINK_ERROR_NULL; + } + + size_t rem = HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd) - hsd->input_size; + if (rem == 0) { + *input_size = 0; + return HSDR_SINK_FULL; + } + + size = rem < size ? rem : size; + LOG("-- sinking %zd bytes\n", size); + /* copy into input buffer (at head of buffers) */ + memcpy(&hsd->buffers[hsd->input_size], in_buf, size); + hsd->input_size += size; + *input_size = size; + return HSDR_SINK_OK; +} + + +/***************** + * Decompression * + *****************/ + +#define BACKREF_COUNT_BITS(HSD) (HEATSHRINK_DECODER_LOOKAHEAD_BITS(HSD)) +#define BACKREF_INDEX_BITS(HSD) (HEATSHRINK_DECODER_WINDOW_BITS(HSD)) + +// States +static HSD_state st_tag_bit(heatshrink_decoder *hsd); +static HSD_state st_yield_literal(heatshrink_decoder *hsd, + output_info *oi); +static HSD_state st_backref_index_msb(heatshrink_decoder *hsd); +static HSD_state st_backref_index_lsb(heatshrink_decoder *hsd); +static HSD_state st_backref_count_msb(heatshrink_decoder *hsd); +static HSD_state st_backref_count_lsb(heatshrink_decoder *hsd); +static HSD_state st_yield_backref(heatshrink_decoder *hsd, + output_info *oi); + +HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd, + uint8_t *out_buf, size_t out_buf_size, size_t *output_size) { + if ((hsd == NULL) || (out_buf == NULL) || (output_size == NULL)) { + return HSDR_POLL_ERROR_NULL; + } + *output_size = 0; + + output_info oi; + oi.buf = out_buf; + oi.buf_size = out_buf_size; + oi.output_size = output_size; + + while (1) { + LOG("-- poll, state is %d (%s), input_size %d\n", + hsd->state, state_names[hsd->state], hsd->input_size); + uint8_t in_state = hsd->state; + switch (in_state) { + case HSDS_TAG_BIT: + hsd->state = st_tag_bit(hsd); + break; + case HSDS_YIELD_LITERAL: + hsd->state = st_yield_literal(hsd, &oi); + break; + case HSDS_BACKREF_INDEX_MSB: + hsd->state = st_backref_index_msb(hsd); + break; + case HSDS_BACKREF_INDEX_LSB: + hsd->state = st_backref_index_lsb(hsd); + break; + case HSDS_BACKREF_COUNT_MSB: + hsd->state = st_backref_count_msb(hsd); + break; + case HSDS_BACKREF_COUNT_LSB: + hsd->state = st_backref_count_lsb(hsd); + break; + case HSDS_YIELD_BACKREF: + hsd->state = st_yield_backref(hsd, &oi); + break; + default: + return HSDR_POLL_ERROR_UNKNOWN; + } + + /* If the current state cannot advance, check if input or output + * buffer are exhausted. */ + if (hsd->state == in_state) { + if (*output_size == out_buf_size) { return HSDR_POLL_MORE; } + return HSDR_POLL_EMPTY; + } + } +} + +static HSD_state st_tag_bit(heatshrink_decoder *hsd) { + uint32_t bits = get_bits(hsd, 1); // get tag bit + if (bits == NO_BITS) { + return HSDS_TAG_BIT; + } else if (bits) { + return HSDS_YIELD_LITERAL; + } else if (HEATSHRINK_DECODER_WINDOW_BITS(hsd) > 8) { + return HSDS_BACKREF_INDEX_MSB; + } else { + hsd->output_index = 0; + return HSDS_BACKREF_INDEX_LSB; + } +} + +static HSD_state st_yield_literal(heatshrink_decoder *hsd, + output_info *oi) { + /* Emit a repeated section from the window buffer, and add it (again) + * to the window buffer. (Note that the repetition can include + * itself.)*/ + if (*oi->output_size < oi->buf_size) { + uint16_t byte = get_bits(hsd, 8); + if (byte == NO_BITS) { return HSDS_YIELD_LITERAL; } /* out of input */ + uint8_t *buf = &hsd->buffers[HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd)]; + uint16_t mask = (1 << HEATSHRINK_DECODER_WINDOW_BITS(hsd)) - 1; + uint8_t c = byte & 0xFF; + LOG("-- emitting literal byte 0x%02x ('%c')\n", c, isprint(c) ? c : '.'); + buf[hsd->head_index++ & mask] = c; + push_byte(hsd, oi, c); + return HSDS_TAG_BIT; + } else { + return HSDS_YIELD_LITERAL; + } +} + +static HSD_state st_backref_index_msb(heatshrink_decoder *hsd) { + uint8_t bit_ct = BACKREF_INDEX_BITS(hsd); + ASSERT(bit_ct > 8); + uint16_t bits = get_bits(hsd, bit_ct - 8); + LOG("-- backref index (msb), got 0x%04x (+1)\n", bits); + if (bits == NO_BITS) { return HSDS_BACKREF_INDEX_MSB; } + hsd->output_index = bits << 8; + return HSDS_BACKREF_INDEX_LSB; +} + +static HSD_state st_backref_index_lsb(heatshrink_decoder *hsd) { + uint8_t bit_ct = BACKREF_INDEX_BITS(hsd); + uint16_t bits = get_bits(hsd, bit_ct < 8 ? bit_ct : 8); + LOG("-- backref index (lsb), got 0x%04x (+1)\n", bits); + if (bits == NO_BITS) { return HSDS_BACKREF_INDEX_LSB; } + hsd->output_index |= bits; + hsd->output_index++; + uint8_t br_bit_ct = BACKREF_COUNT_BITS(hsd); + hsd->output_count = 0; + return (br_bit_ct > 8) ? HSDS_BACKREF_COUNT_MSB : HSDS_BACKREF_COUNT_LSB; +} + +static HSD_state st_backref_count_msb(heatshrink_decoder *hsd) { + uint8_t br_bit_ct = BACKREF_COUNT_BITS(hsd); + ASSERT(br_bit_ct > 8); + uint16_t bits = get_bits(hsd, br_bit_ct - 8); + LOG("-- backref count (msb), got 0x%04x (+1)\n", bits); + if (bits == NO_BITS) { return HSDS_BACKREF_COUNT_MSB; } + hsd->output_count = bits << 8; + return HSDS_BACKREF_COUNT_LSB; +} + +static HSD_state st_backref_count_lsb(heatshrink_decoder *hsd) { + uint8_t br_bit_ct = BACKREF_COUNT_BITS(hsd); + uint16_t bits = get_bits(hsd, br_bit_ct < 8 ? br_bit_ct : 8); + LOG("-- backref count (lsb), got 0x%04x (+1)\n", bits); + if (bits == NO_BITS) { return HSDS_BACKREF_COUNT_LSB; } + hsd->output_count |= bits; + hsd->output_count++; + return HSDS_YIELD_BACKREF; +} + +static HSD_state st_yield_backref(heatshrink_decoder *hsd, + output_info *oi) { + size_t count = oi->buf_size - *oi->output_size; + if (count > 0) { + size_t i = 0; + if (hsd->output_count < count) count = hsd->output_count; + uint8_t *buf = &hsd->buffers[HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd)]; + uint16_t mask = (1 << HEATSHRINK_DECODER_WINDOW_BITS(hsd)) - 1; + uint16_t neg_offset = hsd->output_index; + LOG("-- emitting %zu bytes from -%u bytes back\n", count, neg_offset); + ASSERT(neg_offset <= mask + 1); + ASSERT(count <= (size_t)(1 << BACKREF_COUNT_BITS(hsd))); + + for (i=0; ihead_index - neg_offset) & mask]; + push_byte(hsd, oi, c); + buf[hsd->head_index & mask] = c; + hsd->head_index++; + LOG(" -- ++ 0x%02x\n", c); + } + hsd->output_count -= count; + if (hsd->output_count == 0) { return HSDS_TAG_BIT; } + } + return HSDS_YIELD_BACKREF; +} + +/* Get the next COUNT bits from the input buffer, saving incremental progress. + * Returns NO_BITS on end of input, or if more than 15 bits are requested. */ +static uint16_t get_bits(heatshrink_decoder *hsd, uint8_t count) { + uint16_t accumulator = 0; + int i = 0; + if (count > 15) { return NO_BITS; } + LOG("-- popping %u bit(s)\n", count); + + /* If we aren't able to get COUNT bits, suspend immediately, because we + * don't track how many bits of COUNT we've accumulated before suspend. */ + if (hsd->input_size == 0) { + if (hsd->bit_index < (1 << (count - 1))) { return NO_BITS; } + } + + for (i = 0; i < count; i++) { + if (hsd->bit_index == 0x00) { + if (hsd->input_size == 0) { + LOG(" -- out of bits, suspending w/ accumulator of %u (0x%02x)\n", + accumulator, accumulator); + return NO_BITS; + } + hsd->current_byte = hsd->buffers[hsd->input_index++]; + LOG(" -- pulled byte 0x%02x\n", hsd->current_byte); + if (hsd->input_index == hsd->input_size) { + hsd->input_index = 0; /* input is exhausted */ + hsd->input_size = 0; + } + hsd->bit_index = 0x80; + } + accumulator <<= 1; + if (hsd->current_byte & hsd->bit_index) { + accumulator |= 0x01; + if (0) { + LOG(" -- got 1, accumulator 0x%04x, bit_index 0x%02x\n", + accumulator, hsd->bit_index); + } + } else { + if (0) { + LOG(" -- got 0, accumulator 0x%04x, bit_index 0x%02x\n", + accumulator, hsd->bit_index); + } + } + hsd->bit_index >>= 1; + } + + if (count > 1) { LOG(" -- accumulated %08x\n", accumulator); } + return accumulator; +} + +HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd) { + if (hsd == NULL) { return HSDR_FINISH_ERROR_NULL; } + switch (hsd->state) { + case HSDS_TAG_BIT: + return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE; + + /* If we want to finish with no input, but are in these states, it's + * because the 0-bit padding to the last byte looks like a backref + * marker bit followed by all 0s for index and count bits. */ + case HSDS_BACKREF_INDEX_LSB: + case HSDS_BACKREF_INDEX_MSB: + case HSDS_BACKREF_COUNT_LSB: + case HSDS_BACKREF_COUNT_MSB: + return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE; + + /* If the output stream is padded with 0xFFs (possibly due to being in + * flash memory), also explicitly check the input size rather than + * uselessly returning MORE but yielding 0 bytes when polling. */ + case HSDS_YIELD_LITERAL: + return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE; + + default: + return HSDR_FINISH_MORE; + } +} + +static void push_byte(heatshrink_decoder *hsd, output_info *oi, uint8_t byte) { + LOG(" -- pushing byte: 0x%02x ('%c')\n", byte, isprint(byte) ? byte : '.'); + oi->buf[(*oi->output_size)++] = byte; + (void)hsd; +} diff --git a/src/pawn/heatshrink_decoder.h b/src/pawn/heatshrink_decoder.h new file mode 100644 index 0000000000..63211e417e --- /dev/null +++ b/src/pawn/heatshrink_decoder.h @@ -0,0 +1,108 @@ +#ifndef HEATSHRINK_DECODER_H +#define HEATSHRINK_DECODER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "heatshrink_common.h" +#include "heatshrink_config.h" + +typedef enum { + HSDR_SINK_OK, /* data sunk, ready to poll */ + HSDR_SINK_FULL, /* out of space in internal buffer */ + HSDR_SINK_ERROR_NULL=-1, /* NULL argument */ +} HSD_sink_res; + +typedef enum { + HSDR_POLL_EMPTY, /* input exhausted */ + HSDR_POLL_MORE, /* more data remaining, call again w/ fresh output buffer */ + HSDR_POLL_ERROR_NULL=-1, /* NULL arguments */ + HSDR_POLL_ERROR_UNKNOWN=-2, +} HSD_poll_res; + +typedef enum { + HSDR_FINISH_DONE, /* output is done */ + HSDR_FINISH_MORE, /* more output remains */ + HSDR_FINISH_ERROR_NULL=-1, /* NULL arguments */ +} HSD_finish_res; + +#if HEATSHRINK_DYNAMIC_ALLOC +#define HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(BUF) \ + ((BUF)->input_buffer_size) +#define HEATSHRINK_DECODER_WINDOW_BITS(BUF) \ + ((BUF)->window_sz2) +#define HEATSHRINK_DECODER_LOOKAHEAD_BITS(BUF) \ + ((BUF)->lookahead_sz2) +#else +#define HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(_) \ + HEATSHRINK_STATIC_INPUT_BUFFER_SIZE +#define HEATSHRINK_DECODER_WINDOW_BITS(_) \ + (HEATSHRINK_STATIC_WINDOW_BITS) +#define HEATSHRINK_DECODER_LOOKAHEAD_BITS(BUF) \ + (HEATSHRINK_STATIC_LOOKAHEAD_BITS) +#endif + +typedef struct { + uint16_t input_size; /* bytes in input buffer */ + uint16_t input_index; /* offset to next unprocessed input byte */ + uint16_t output_count; /* how many bytes to output */ + uint16_t output_index; /* index for bytes to output */ + uint16_t head_index; /* head of window buffer */ + uint8_t state; /* current state machine node */ + uint8_t current_byte; /* current byte of input */ + uint8_t bit_index; /* current bit index */ + +#if HEATSHRINK_DYNAMIC_ALLOC + /* Fields that are only used if dynamically allocated. */ + uint8_t window_sz2; /* window buffer bits */ + uint8_t lookahead_sz2; /* lookahead bits */ + uint16_t input_buffer_size; /* input buffer size */ + + /* Input buffer, then expansion window buffer */ + uint8_t buffers[]; +#else + /* Input buffer, then expansion window buffer */ + uint8_t buffers[(1 << HEATSHRINK_DECODER_WINDOW_BITS(_)) + + HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(_)]; +#endif +} heatshrink_decoder; + +#if HEATSHRINK_DYNAMIC_ALLOC +/* Allocate a decoder with an input buffer of INPUT_BUFFER_SIZE bytes, + * an expansion buffer size of 2^WINDOW_SZ2, and a lookahead + * size of 2^lookahead_sz2. (The window buffer and lookahead sizes + * must match the settings used when the data was compressed.) + * Returns NULL on error. */ +heatshrink_decoder *heatshrink_decoder_alloc(uint16_t input_buffer_size, + uint8_t expansion_buffer_sz2, uint8_t lookahead_sz2); + +/* Free a decoder. */ +void heatshrink_decoder_free(heatshrink_decoder *hsd); +#endif + +/* Reset a decoder. */ +void heatshrink_decoder_reset(heatshrink_decoder *hsd); + +/* Sink at most SIZE bytes from IN_BUF into the decoder. *INPUT_SIZE is set to + * indicate how many bytes were actually sunk (in case a buffer was filled). */ +HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd, + uint8_t *in_buf, size_t size, size_t *input_size); + +/* Poll for output from the decoder, copying at most OUT_BUF_SIZE bytes into + * OUT_BUF (setting *OUTPUT_SIZE to the actual amount copied). */ +HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd, + uint8_t *out_buf, size_t out_buf_size, size_t *output_size); + +/* Notify the dencoder that the input stream is finished. + * If the return value is HSDR_FINISH_MORE, there is still more output, so + * call heatshrink_decoder_poll and repeat. */ +HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd); + +#ifdef __cplusplus +} +#endif + +#endif