From db33811ed27573e3fae6b817c184bc8533e2fae7 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 24 May 2022 14:55:42 +0400 Subject: [PATCH 001/184] Initial SCons-powered build impl --- .gitignore | 3 + SConstruct | 5 ++ firmware.scons | 141 +++++++++++++++++++++++++++++++++++++++ scons/cc.scons | 70 +++++++++++++++++++ scons/environ.scons | 74 ++++++++++++++++++++ scons/git.scons | 13 ++++ scripts/requirements.txt | 1 + 7 files changed, 307 insertions(+) create mode 100644 SConstruct create mode 100644 firmware.scons create mode 100644 scons/cc.scons create mode 100644 scons/environ.scons create mode 100644 scons/git.scons create mode 100644 scripts/requirements.txt diff --git a/.gitignore b/.gitignore index 6577101d6baf..fbc6163fa0e9 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ dist # kde .directory + +# SCons +.sconsign.dblite \ No newline at end of file diff --git a/SConstruct b/SConstruct new file mode 100644 index 000000000000..71322c29b224 --- /dev/null +++ b/SConstruct @@ -0,0 +1,5 @@ +SConscript("scons/environ.scons") +SConscript("scons/cc.scons") +SConscript("scons/git.scons") +# Import("env") +SConscript("firmware.scons", variant_dir="build", duplicate=0) diff --git a/firmware.scons b/firmware.scons new file mode 100644 index 000000000000..9e0bd4aad9b1 --- /dev/null +++ b/firmware.scons @@ -0,0 +1,141 @@ +Import("env") +SConscript("lib/lib.scons") + +env.Append(FLIPPER_TARGET="f7") + +env.Append( + CCFLAGS=[ + "-DAPP_ABOUT", + "-DAPP_ACCESSOR", + "-DAPP_ARCHIVE", + "-DAPP_BAD_USB", + "-DAPP_BLE_HID", + "-DAPP_BLINK", + "-DAPP_DISPLAY_TEST", + "-DAPP_GPIO", + "-DAPP_IBUTTON", + "-DAPP_INFRARED", + "-DAPP_INFRARED_MONITOR", + "-DAPP_KEYPAD_TEST", + "-DAPP_LF_RFID", + "-DAPP_MUSIC_PLAYER", + "-DAPP_NFC", + "-DAPP_PASSPORT", + "-DAPP_SNAKE_GAME", + "-DAPP_SUBGHZ", + "-DAPP_U2F", + "-DAPP_UART_ECHO", + "-DAPP_UPDATER", + "-DAPP_USB_MOUSE", + "-DAPP_USB_TEST", + "-DAPP_VIBRO_TEST", + "-DSRV_BT", + "-DSRV_CLI", + "-DSRV_DESKTOP", + "-DSRV_DIALOGS", + "-DSRV_DOLPHIN", + "-DSRV_GUI", + "-DSRV_INPUT", + "-DSRV_LOADER", + "-DSRV_NOTIFICATION", + "-DSRV_POWER", + "-DSRV_RPC", + "-DSRV_STORAGE", + ] +) + +env.Append( + CPPPATH=[ + ".", + "./applications", + "./assets/compiled", + "./core", + "./firmware/targets/${FLIPPER_TARGET}/ble_glue", + "./firmware/targets/${FLIPPER_TARGET}/fatfs", + "./firmware/targets/${FLIPPER_TARGET}/furi_hal", + "./firmware/targets/${FLIPPER_TARGET}/Inc", + "./firmware/targets/furi_hal_include", + ] +) + + +sources = env.GlobRecursive("*.c", "core") +sources += env.GlobRecursive("*.c", "firmware") +sources += env.GlobRecursive("*.c*", "applications") + +libs_recurse = [ + "assets/compiled", + "lib/app-scened-template", + "lib/drivers", + "lib/flipper_format", + "lib/nfc_protocols", + "lib/microtar/src", + "lib/update_util", + "lib/subghz", + "lib/toolbox", + "lib/micro-ecc", + "lib/one_wire", + "lib/infrared", + "lib/ST25RFAL002/source", + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/", + "lib/u8g2", +] + +for lib in libs_recurse: + sources += env.GlobRecursive("*.c*", lib) + + +libs_plain = [ + "lib/fatfs", + "lib/heatshrink", + "lib/littlefs", + "lib/nanopb", + "lib/libusb_stm32/src", + "lib/ST25RFAL002", +] + +for lib in libs_plain: + sources += Glob(lib + "/*.c*", source=True) + + +sources += [ + "lib/fatfs/option/unicode.c", + "lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c", +] + +sources += Glob( + "lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/*.c", source=True +) +sources += Glob( + "lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/*.c", + source=True, +) + + +sources += env.GlobRecursive( + "*_ll_*.c", "lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/", exclude="*usb.c" +) + +sources += Glob( + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/*.c", + source=True, +) +sources += Glob( + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/*_tl*.c", + source=True, +) + +sources += [ + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c", + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/svc/Src/svc_ctl.c", + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c", + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c", + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c", + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hci_le.c", + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c", + "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", +] + +sources += ["firmware/targets/${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] + +env.Program("flipperfw", sources) diff --git a/scons/cc.scons b/scons/cc.scons new file mode 100644 index 000000000000..9729ad6a04d6 --- /dev/null +++ b/scons/cc.scons @@ -0,0 +1,70 @@ +Import("env") + + +env.Append( + CCFLAGS=[ + "-O2", + "-g", + "-DNDEBUG", + "-DFURI_NDEBUG", + "-DTARGET=7", + ] +) + +env.Append( + CFLAGS=[ + "-std=gnu17", + ], + CCFLAGS=[ + "--specs=nosys.specs", + "--specs=nano.specs", + "-mcpu=cortex-m4", + "-mfloat-abi=hard", + "-mfpu=fpv4-sp-d16", + "-MMD", + "-MP", + "-mthumb", + "-Wall", + # "-Werror", + "-Wextra", + "-Wno-address-of-packed-member", + "-Wredundant-decls", + "-fdata-sections", + "-ffunction-sections", + "-fno-diagnostics-show-caret", + "-fno-math-errno", + "-fstack-usage", + "-D_GNU_SOURCE", + # STM32WB + "-D__STM32WB55_SUBFAMILY", + "-D__STM32WBxx_FAMILY", + "-DSTM32WB", + "-DSTM32WB55xx", + ], +) + + +env.Append( + LINKFLAGS=[ + "-u _printf_float", + "-Wl,--wrap,_malloc_r", + "-Wl,--wrap,_free_r", + "-Wl,--wrap,_calloc_r", + "-Wl,--wrap,_realloc_r", + "-mcpu=cortex-m4", + "-mfloat-abi=hard", + "-mfpu=fpv4-sp-d16", + "-mlittle-endian", + "-mthumb", + "-specs=nano.specs", + "-specs=nosys.specs", + "-Wl,--start-group", + "-lstdc++", + "-lsupc++", + "-Wl,--end-group", + "-Tfirmware/targets/f7/stm32wb55xx_flash.ld", + "-Wl,--gc-sections", + "-Wl,--undefined=uxTopUsedPriority", + "-n", + ] +) diff --git a/scons/environ.scons b/scons/environ.scons new file mode 100644 index 000000000000..b10ddd670af3 --- /dev/null +++ b/scons/environ.scons @@ -0,0 +1,74 @@ +from SCons.Subst import quote_spaces +from SCons.Platform import TempFileMunge + +import SCons +import os +import sys +import re + +env = Environment( + tools=["gcc", "g++", "ar", "gnulink"], + # CC="arm-none-eabi-gcc", + # CXX="arm-none-eabi-g++", + # LINK="arm-none-eabi-g++", + # CCFLAGS=[], + # LINKFLAGS=[], + TEMPFILE=TempFileMunge, + MAXLINELENGTH=2048, + PROGSUFFIX=".elf", + ENV={"PATH": os.environ["PATH"]}, +) + + +# Setting up temp file parameters + +WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") + + +def tempfile_arg_esc_func(arg): + arg = quote_spaces(arg) + if sys.platform != "win32": + return arg + # GCC requires double Windows slashes, let's use UNIX separator + return WINPATHSEP_RE.sub(r"/\1", arg) + + +env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func + +# Set up cross-compile tools +toolchain_prefix = "arm-none-eabi-" +for binary in [ + "AR", + # "AS", + "CC", + "CXX", + # "LINK", + # "RANLIB", + # "OBJCOPY", + # "OBJDUMP", + # "OBJSYMBOLS", +]: + env[binary] = toolchain_prefix + env[binary] + +# Commandline length limit hack +env["LINKCOM"] = '${TEMPFILE("' + env["LINKCOM"] + '","$LINKCOMSTR")}' + +# Recursive glob +def GlobRecursive(pattern, node=".", exclude=None): + results = [] + for f in Glob(str(node) + "/*", source=True, exclude=exclude): + if type(f) is SCons.Node.FS.Dir: + # print(f"recursing into {f}") + results += GlobRecursive(pattern, f, exclude) + current_node_str = str(node) + "/" + results += Glob( + current_node_str + pattern, + source=True, + exclude=exclude and current_node_str + exclude or exclude, + ) + return results + + +env.GlobRecursive = GlobRecursive + +Export("env") diff --git a/scons/git.scons b/scons/git.scons new file mode 100644 index 000000000000..39d3a9eb174f --- /dev/null +++ b/scons/git.scons @@ -0,0 +1,13 @@ +Import("env") + + +env.Append( + CCFLAGS=[ + '-DGIT_COMMIT=\\"DUMMY\\"', + '-DGIT_BRANCH=\\"unknown\\"', + '-DGIT_BRANCH_NUM=\\"1337\\"', + '-DVERSION=\\"unknown\\"', + '-DBUILD_DATE=\\"2021-06-28\\"', + "-DBUILD_DIRTY=1", + ] +) diff --git a/scripts/requirements.txt b/scripts/requirements.txt new file mode 100644 index 000000000000..6f3368595207 --- /dev/null +++ b/scripts/requirements.txt @@ -0,0 +1 @@ +pyserial >= 3.5 From fa7e1059771128e774ee70bbf4f617657e0c40cc Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 24 May 2022 15:18:00 +0400 Subject: [PATCH 002/184] Using CPPDEFINES for definitions --- .gitignore | 2 +- SConstruct | 6 +-- firmware.scons | 87 ++++++++++++++++--------------- scons/git.scons | 13 ----- {scons => sconscfg}/cc.scons | 25 +++++---- {scons => sconscfg}/environ.scons | 0 sconscfg/git.scons | 13 +++++ 7 files changed, 77 insertions(+), 69 deletions(-) delete mode 100644 scons/git.scons rename {scons => sconscfg}/cc.scons (81%) rename {scons => sconscfg}/environ.scons (100%) create mode 100644 sconscfg/git.scons diff --git a/.gitignore b/.gitignore index fbc6163fa0e9..9fcb47dbd001 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,4 @@ dist .directory # SCons -.sconsign.dblite \ No newline at end of file +.sconsign.dblite diff --git a/SConstruct b/SConstruct index 71322c29b224..bdccbce5bcec 100644 --- a/SConstruct +++ b/SConstruct @@ -1,5 +1,5 @@ -SConscript("scons/environ.scons") -SConscript("scons/cc.scons") -SConscript("scons/git.scons") +SConscript("sconscfg/environ.scons") +SConscript("sconscfg/cc.scons") +SConscript("sconscfg/git.scons") # Import("env") SConscript("firmware.scons", variant_dir="build", duplicate=0) diff --git a/firmware.scons b/firmware.scons index 9e0bd4aad9b1..a5d5ae3b147b 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,46 +1,47 @@ Import("env") SConscript("lib/lib.scons") -env.Append(FLIPPER_TARGET="f7") +env.Append(FLIPPER_TARGET="7") env.Append( - CCFLAGS=[ - "-DAPP_ABOUT", - "-DAPP_ACCESSOR", - "-DAPP_ARCHIVE", - "-DAPP_BAD_USB", - "-DAPP_BLE_HID", - "-DAPP_BLINK", - "-DAPP_DISPLAY_TEST", - "-DAPP_GPIO", - "-DAPP_IBUTTON", - "-DAPP_INFRARED", - "-DAPP_INFRARED_MONITOR", - "-DAPP_KEYPAD_TEST", - "-DAPP_LF_RFID", - "-DAPP_MUSIC_PLAYER", - "-DAPP_NFC", - "-DAPP_PASSPORT", - "-DAPP_SNAKE_GAME", - "-DAPP_SUBGHZ", - "-DAPP_U2F", - "-DAPP_UART_ECHO", - "-DAPP_UPDATER", - "-DAPP_USB_MOUSE", - "-DAPP_USB_TEST", - "-DAPP_VIBRO_TEST", - "-DSRV_BT", - "-DSRV_CLI", - "-DSRV_DESKTOP", - "-DSRV_DIALOGS", - "-DSRV_DOLPHIN", - "-DSRV_GUI", - "-DSRV_INPUT", - "-DSRV_LOADER", - "-DSRV_NOTIFICATION", - "-DSRV_POWER", - "-DSRV_RPC", - "-DSRV_STORAGE", + CPPDEFINES=[ + ("TARGET", "${FLIPPER_TARGET}"), + "APP_ABOUT", + "APP_ACCESSOR", + "APP_ARCHIVE", + "APP_BAD_USB", + "APP_BLE_HID", + "APP_BLINK", + "APP_DISPLAY_TEST", + "APP_GPIO", + "APP_IBUTTON", + "APP_INFRARED", + "APP_INFRARED_MONITOR", + "APP_KEYPAD_TEST", + "APP_LF_RFID", + "APP_MUSIC_PLAYER", + "APP_NFC", + "APP_PASSPORT", + "APP_SNAKE_GAME", + "APP_SUBGHZ", + "APP_U2F", + "APP_UART_ECHO", + "APP_UPDATER", + "APP_USB_MOUSE", + "APP_USB_TEST", + "APP_VIBRO_TEST", + "SRV_BT", + "SRV_CLI", + "SRV_DESKTOP", + "SRV_DIALOGS", + "SRV_DOLPHIN", + "SRV_GUI", + "SRV_INPUT", + "SRV_LOADER", + "SRV_NOTIFICATION", + "SRV_POWER", + "SRV_RPC", + "SRV_STORAGE", ] ) @@ -50,10 +51,10 @@ env.Append( "./applications", "./assets/compiled", "./core", - "./firmware/targets/${FLIPPER_TARGET}/ble_glue", - "./firmware/targets/${FLIPPER_TARGET}/fatfs", - "./firmware/targets/${FLIPPER_TARGET}/furi_hal", - "./firmware/targets/${FLIPPER_TARGET}/Inc", + "./firmware/targets/f${FLIPPER_TARGET}/ble_glue", + "./firmware/targets/f${FLIPPER_TARGET}/fatfs", + "./firmware/targets/f${FLIPPER_TARGET}/furi_hal", + "./firmware/targets/f${FLIPPER_TARGET}/Inc", "./firmware/targets/furi_hal_include", ] ) @@ -136,6 +137,6 @@ sources += [ "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", ] -sources += ["firmware/targets/${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] +sources += ["firmware/targets/f${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] env.Program("flipperfw", sources) diff --git a/scons/git.scons b/scons/git.scons deleted file mode 100644 index 39d3a9eb174f..000000000000 --- a/scons/git.scons +++ /dev/null @@ -1,13 +0,0 @@ -Import("env") - - -env.Append( - CCFLAGS=[ - '-DGIT_COMMIT=\\"DUMMY\\"', - '-DGIT_BRANCH=\\"unknown\\"', - '-DGIT_BRANCH_NUM=\\"1337\\"', - '-DVERSION=\\"unknown\\"', - '-DBUILD_DATE=\\"2021-06-28\\"', - "-DBUILD_DIRTY=1", - ] -) diff --git a/scons/cc.scons b/sconscfg/cc.scons similarity index 81% rename from scons/cc.scons rename to sconscfg/cc.scons index 9729ad6a04d6..053b919f0bad 100644 --- a/scons/cc.scons +++ b/sconscfg/cc.scons @@ -5,16 +5,21 @@ env.Append( CCFLAGS=[ "-O2", "-g", - "-DNDEBUG", - "-DFURI_NDEBUG", - "-DTARGET=7", - ] + ], + CPPDEFINES=[ + "NDEBUG", + "FURI_NDEBUG", + ("TARGET", "7"), + ], ) env.Append( CFLAGS=[ "-std=gnu17", ], + CXXFLAGS=[ + "-std=c++17", + ], CCFLAGS=[ "--specs=nosys.specs", "--specs=nano.specs", @@ -34,12 +39,14 @@ env.Append( "-fno-diagnostics-show-caret", "-fno-math-errno", "-fstack-usage", - "-D_GNU_SOURCE", + ], + CPPDEFINES=[ + "_GNU_SOURCE", # STM32WB - "-D__STM32WB55_SUBFAMILY", - "-D__STM32WBxx_FAMILY", - "-DSTM32WB", - "-DSTM32WB55xx", + "__STM32WB55_SUBFAMILY", + "__STM32WBxx_FAMILY", + "STM32WB", + "STM32WB55xx", ], ) diff --git a/scons/environ.scons b/sconscfg/environ.scons similarity index 100% rename from scons/environ.scons rename to sconscfg/environ.scons diff --git a/sconscfg/git.scons b/sconscfg/git.scons new file mode 100644 index 000000000000..e71e173f353b --- /dev/null +++ b/sconscfg/git.scons @@ -0,0 +1,13 @@ +Import("env") + + +env.Append( + CPPDEFINES=[ + ("GIT_COMMIT", '\\"DUMMY\\"'), + ("GIT_BRANCH", '\\"unknown\\"'), + ("GIT_BRANCH_NUM", '\\"1337\\"'), + ("VERSION", '\\"unknown\\"'), + ("BUILD_DATE", '\\"2021-06)-28\\"'), + ("BUILD_DIRTY", "1"), + ] +) From d33d1dc8dd4719fdf72b455890c28fa4c6d42079 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 24 May 2022 15:32:08 +0400 Subject: [PATCH 003/184] Added SCons as submodule. Call `python3 scons/scripts/scons.py -j 8` from project root --- .gitmodules | 4 ++++ scons | 1 + 2 files changed, 5 insertions(+) create mode 160000 scons diff --git a/.gitmodules b/.gitmodules index c4649fdca92c..ad15a5c4e736 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,7 @@ [submodule "lib/microtar"] path = lib/microtar url = https://github.com/amachronic/microtar.git +[submodule "scons"] + path = scons + url = https://github.com/SCons/scons.git + diff --git a/scons b/scons new file mode 160000 index 000000000000..c2d1f09f615a --- /dev/null +++ b/scons @@ -0,0 +1 @@ +Subproject commit c2d1f09f615a9ef3fb5497a7e8e5ee2c900d21a7 From 6ca5f1bfa2184b4b25777063431575b33e7f4243 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 24 May 2022 15:40:00 +0400 Subject: [PATCH 004/184] Removed duplicate target def --- firmware.scons | 3 +-- sconscfg/cc.scons | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/firmware.scons b/firmware.scons index a5d5ae3b147b..0ba224a16134 100644 --- a/firmware.scons +++ b/firmware.scons @@ -62,6 +62,7 @@ env.Append( sources = env.GlobRecursive("*.c", "core") sources += env.GlobRecursive("*.c", "firmware") +sources += ["firmware/targets/f${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] sources += env.GlobRecursive("*.c*", "applications") libs_recurse = [ @@ -137,6 +138,4 @@ sources += [ "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", ] -sources += ["firmware/targets/f${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] - env.Program("flipperfw", sources) diff --git a/sconscfg/cc.scons b/sconscfg/cc.scons index 053b919f0bad..61a68245fb37 100644 --- a/sconscfg/cc.scons +++ b/sconscfg/cc.scons @@ -9,7 +9,6 @@ env.Append( CPPDEFINES=[ "NDEBUG", "FURI_NDEBUG", - ("TARGET", "7"), ], ) From b8b8bf8330cc5ae73ff2585cab04a7ffaddc6dfb Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 24 May 2022 15:43:41 +0400 Subject: [PATCH 005/184] Fixed quoting for bash --- lib/lib.scons | 56 ++++++++++++++++++++++++++++++++++++++++++++++ sconscfg/git.scons | 2 +- 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 lib/lib.scons diff --git a/lib/lib.scons b/lib/lib.scons new file mode 100644 index 000000000000..21d302c5697a --- /dev/null +++ b/lib/lib.scons @@ -0,0 +1,56 @@ +Import("env") + + +env.Append( + CPPPATH=[ + "./lib", + "./lib/app-scened-template", + "./lib/app-template", + "./lib/callback-connector", + "./lib/common-api", + "./lib/drivers", + "./lib/file_reader", + "./lib/flipper_format", + "./lib/fnv1a_hash", + "./lib/FreeRTOS-glue", + "./lib/heatshrink", + "./lib/infrared/encoder_decoder", + "./lib/infrared/worker", + "./lib/libusb_stm32/inc", + "./lib/littlefs", + "./lib/micro-ecc", + "./lib/microtar/src", + "./lib/mlib", + "./lib/nanopb", + "./lib/nfc_protocols", + "./lib/ST25RFAL002", + "./lib/ST25RFAL002/include", + "./lib/ST25RFAL002/source/st25r3916", + "./lib/STM32CubeWB/Drivers/CMSIS/Device/ST", + "./lib/STM32CubeWB/Drivers/CMSIS/Device/ST/STM32WBxx/Include", + "./lib/STM32CubeWB/Drivers/CMSIS/Include", + "./lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc", + "./lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy", + "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN", + "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble", + "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core", + "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template", + "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread", + "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci", + "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl", + "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities", + "./lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2", + "./lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include", + "./lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F", + "./lib/u8g2", + ], + CPPDEFINES=[ + '"M_MEMORY_FULL(x)=abort()"', + ("USB_PMASIZE", "0x400"), + ("LFS_CONFIG", "lfs_config.h"), + "USE_FULL_ASSERT", + "USE_FULL_LL_DRIVER", + "HAVE_FREERTOS", + "PB_ENABLE_MALLOC", + ], +) diff --git a/sconscfg/git.scons b/sconscfg/git.scons index e71e173f353b..e4c4d0b05f0e 100644 --- a/sconscfg/git.scons +++ b/sconscfg/git.scons @@ -7,7 +7,7 @@ env.Append( ("GIT_BRANCH", '\\"unknown\\"'), ("GIT_BRANCH_NUM", '\\"1337\\"'), ("VERSION", '\\"unknown\\"'), - ("BUILD_DATE", '\\"2021-06)-28\\"'), + ("BUILD_DATE", '\\"2021-06-28\\"'), ("BUILD_DIRTY", "1"), ] ) From 5cfa236eba7ab1ec06916c998617b26ee05bae57 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 24 May 2022 18:17:36 +0400 Subject: [PATCH 006/184] Added hex + bin builders --- SConstruct | 1 + firmware.scons | 3 +++ sconscfg/builders.scons | 25 +++++++++++++++++++++++++ sconscfg/environ.scons | 12 ++++++++---- 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 sconscfg/builders.scons diff --git a/SConstruct b/SConstruct index bdccbce5bcec..4c1cac25f60f 100644 --- a/SConstruct +++ b/SConstruct @@ -1,5 +1,6 @@ SConscript("sconscfg/environ.scons") SConscript("sconscfg/cc.scons") SConscript("sconscfg/git.scons") +SConscript("sconscfg/builders.scons") # Import("env") SConscript("firmware.scons", variant_dir="build", duplicate=0) diff --git a/firmware.scons b/firmware.scons index 0ba224a16134..8ac84551b8e6 100644 --- a/firmware.scons +++ b/firmware.scons @@ -138,4 +138,7 @@ sources += [ "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", ] +# print(dir(env)) env.Program("flipperfw", sources) +env.HEXBuilder(target="flipperfw.hex", source="flipperfw.elf") +env.BINBuilder(target="flipperfw.bin", source="flipperfw.elf") diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons new file mode 100644 index 000000000000..2412083d5dc8 --- /dev/null +++ b/sconscfg/builders.scons @@ -0,0 +1,25 @@ +Import("env") + + +def generate_hex(source, target, env, for_signature): + return "$OBJCOPY -O ihex %s %s" % (source[0], target[0]) + + +def generate_bin(source, target, env, for_signature): + return "$OBJCOPY -O binary -S '%s' '%s'" % (source[0], target[0]) + + +env.Append( + BUILDERS={ + "HEXBuilder": Builder( + generator=generate_hex, + suffix=".hex", + src_suffix=".elf", + ), + "BINBuilder": Builder( + generator=generate_bin, + suffix=".bin", + src_suffix=".elf", + ), + } +) diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index b10ddd670af3..b633ba54cb53 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -6,6 +6,8 @@ import os import sys import re +TOOLCHAIN_PREFIX = "arm-none-eabi-" + env = Environment( tools=["gcc", "g++", "ar", "gnulink"], # CC="arm-none-eabi-gcc", @@ -13,10 +15,13 @@ env = Environment( # LINK="arm-none-eabi-g++", # CCFLAGS=[], # LINKFLAGS=[], + OBJCOPY="objcopy", TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", - ENV={"PATH": os.environ["PATH"]}, + ENV={ + "PATH": os.environ["PATH"], + }, ) @@ -36,7 +41,6 @@ def tempfile_arg_esc_func(arg): env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func # Set up cross-compile tools -toolchain_prefix = "arm-none-eabi-" for binary in [ "AR", # "AS", @@ -44,11 +48,11 @@ for binary in [ "CXX", # "LINK", # "RANLIB", - # "OBJCOPY", + "OBJCOPY", # "OBJDUMP", # "OBJSYMBOLS", ]: - env[binary] = toolchain_prefix + env[binary] + env[binary] = TOOLCHAIN_PREFIX + env[binary] # Commandline length limit hack env["LINKCOM"] = '${TEMPFILE("' + env["LINKCOM"] + '","$LINKCOMSTR")}' From f5f82ebdb5ba6cfa9a4438e224e26b03d853383d Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 24 May 2022 18:59:06 +0400 Subject: [PATCH 007/184] Added dfu builder --- firmware.scons | 12 ++++++++---- sconscfg/builders.scons | 23 +++++++++++++++++++++-- sconscfg/environ.scons | 3 ++- sconscfg/git.scons | 20 +++++++++++++------- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/firmware.scons b/firmware.scons index 8ac84551b8e6..cc39f769ea72 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,7 +1,10 @@ Import("env") SConscript("lib/lib.scons") -env.Append(FLIPPER_TARGET="7") +env.Append( + FLIPPER_TARGET="7", + IMAGE_BASE_ADDRESS="0x8000000", +) env.Append( CPPDEFINES=[ @@ -138,7 +141,8 @@ sources += [ "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", ] -# print(dir(env)) +print(env.Dump()) env.Program("flipperfw", sources) -env.HEXBuilder(target="flipperfw.hex", source="flipperfw.elf") -env.BINBuilder(target="flipperfw.bin", source="flipperfw.elf") +env.HEXBuilder("flipperfw") +env.BINBuilder("flipperfw") +env.DFUBuilder("flipperfw") diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons index 2412083d5dc8..7250786a5bf7 100644 --- a/sconscfg/builders.scons +++ b/sconscfg/builders.scons @@ -2,11 +2,25 @@ Import("env") def generate_hex(source, target, env, for_signature): - return "$OBJCOPY -O ihex %s %s" % (source[0], target[0]) + return '${OBJCOPY} -O ihex "%s" "%s"' % (source[0], target[0]) def generate_bin(source, target, env, for_signature): - return "$OBJCOPY -O binary -S '%s' '%s'" % (source[0], target[0]) + return '${OBJCOPY} -O binary -S "%s" "%s"' % (source[0], target[0]) + + +def generate_dfu(source, target, env, for_signature): + return ( + '${PYTHON3} ./scripts/bin2dfu.py -i "%s" -o "%s" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${FLIPPER_TARGET}"' + % (source[0], target[0]) + ) + + +# def generate_json(source, target, env, for_signature): +# return '${PYTHON3} scripts/meta.py generate -p firmware ${} "%s" > "%s"' % ( +# source[0], +# target[0], +# ) env.Append( @@ -21,5 +35,10 @@ env.Append( suffix=".bin", src_suffix=".elf", ), + "DFUBuilder": Builder( + generator=generate_dfu, + suffix=".dfu", + src_suffix=".bin", + ), } ) diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index b633ba54cb53..44ac7ae3190c 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -9,13 +9,14 @@ import re TOOLCHAIN_PREFIX = "arm-none-eabi-" env = Environment( - tools=["gcc", "g++", "ar", "gnulink"], + tools=["gcc", "g++", "ar", "gnulink", "python"], # CC="arm-none-eabi-gcc", # CXX="arm-none-eabi-g++", # LINK="arm-none-eabi-g++", # CCFLAGS=[], # LINKFLAGS=[], OBJCOPY="objcopy", + PYTHON3="python", TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", diff --git a/sconscfg/git.scons b/sconscfg/git.scons index e4c4d0b05f0e..8c9bd5418185 100644 --- a/sconscfg/git.scons +++ b/sconscfg/git.scons @@ -2,12 +2,18 @@ Import("env") env.Append( + BUILD_META_COMMIT="DUMMY", + BUILD_META_BRANCH="unknown", + BUILD_META_BRANCH_NUM="1337", + BUILD_META_VERSION="unknown", + BUILD_META_DATE="2021-06-28", + BUILD_META_DIRTY="1", CPPDEFINES=[ - ("GIT_COMMIT", '\\"DUMMY\\"'), - ("GIT_BRANCH", '\\"unknown\\"'), - ("GIT_BRANCH_NUM", '\\"1337\\"'), - ("VERSION", '\\"unknown\\"'), - ("BUILD_DATE", '\\"2021-06-28\\"'), - ("BUILD_DIRTY", "1"), - ] + ("GIT_COMMIT", '\\"${BUILD_META_COMMIT}\\"'), + ("GIT_BRANCH", '\\"${BUILD_META_BRANCH}\\"'), + ("GIT_BRANCH_NUM", '\\"${BUILD_META_BRANCH_NUM}\\"'), + ("VERSION", '\\"${BUILD_META_VERSION}\\"'), + ("BUILD_DATE", '\\"${BUILD_META_DATE}\\"'), + ("BUILD_DIRTY", "${BUILD_META_DIRTY}"), + ], ) From 6bf671ac8e94a9de579208ad22f3086b3bfae046 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 24 May 2022 20:00:02 +0400 Subject: [PATCH 008/184] Updates for latest dev; added compilation db --- firmware.scons | 16 +++++++++------- lib/lib.scons | 1 + sconscfg/environ.scons | 3 ++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/firmware.scons b/firmware.scons index cc39f769ea72..a3d62ae9e2a3 100644 --- a/firmware.scons +++ b/firmware.scons @@ -71,19 +71,20 @@ sources += env.GlobRecursive("*.c*", "applications") libs_recurse = [ "assets/compiled", "lib/app-scened-template", + "lib/digital_signal", "lib/drivers", "lib/flipper_format", - "lib/nfc_protocols", - "lib/microtar/src", - "lib/update_util", - "lib/subghz", - "lib/toolbox", + "lib/infrared", "lib/micro-ecc", + "lib/microtar/src", + "lib/nfc_protocols", "lib/one_wire", - "lib/infrared", "lib/ST25RFAL002/source", "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/", + "lib/subghz", + "lib/toolbox", "lib/u8g2", + "lib/update_util", ] for lib in libs_recurse: @@ -93,9 +94,9 @@ for lib in libs_recurse: libs_plain = [ "lib/fatfs", "lib/heatshrink", + "lib/libusb_stm32/src", "lib/littlefs", "lib/nanopb", - "lib/libusb_stm32/src", "lib/ST25RFAL002", ] @@ -142,6 +143,7 @@ sources += [ ] print(env.Dump()) +env.CompilationDatabase() env.Program("flipperfw", sources) env.HEXBuilder("flipperfw") env.BINBuilder("flipperfw") diff --git a/lib/lib.scons b/lib/lib.scons index 21d302c5697a..deb72ddf651f 100644 --- a/lib/lib.scons +++ b/lib/lib.scons @@ -8,6 +8,7 @@ env.Append( "./lib/app-template", "./lib/callback-connector", "./lib/common-api", + "./lib/digital_signal", "./lib/drivers", "./lib/file_reader", "./lib/flipper_format", diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 44ac7ae3190c..6708425daa26 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -9,7 +9,7 @@ import re TOOLCHAIN_PREFIX = "arm-none-eabi-" env = Environment( - tools=["gcc", "g++", "ar", "gnulink", "python"], + tools=["gcc", "g++", "ar", "gnulink", "python", "compilation_db"], # CC="arm-none-eabi-gcc", # CXX="arm-none-eabi-g++", # LINK="arm-none-eabi-g++", @@ -20,6 +20,7 @@ env = Environment( TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", + COMPILATIONDB_USE_ABSPATH=True, ENV={ "PATH": os.environ["PATH"], }, From 65474a91435224c418cb9e006e4dc9806b6e85ad Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 25 May 2022 00:57:46 +0400 Subject: [PATCH 009/184] Added command line parsing & updater build --- SConstruct | 12 ++++- firmware.scons | 99 +++++++++++++++++++++---------------- sconscfg/cc.scons | 12 ----- sconscfg/environ.scons | 16 +++++- sconscfg/firmwareopts.scons | 72 +++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 57 deletions(-) create mode 100644 sconscfg/firmwareopts.scons diff --git a/SConstruct b/SConstruct index 4c1cac25f60f..30ca9d23a9ea 100644 --- a/SConstruct +++ b/SConstruct @@ -2,5 +2,13 @@ SConscript("sconscfg/environ.scons") SConscript("sconscfg/cc.scons") SConscript("sconscfg/git.scons") SConscript("sconscfg/builders.scons") -# Import("env") -SConscript("firmware.scons", variant_dir="build", duplicate=0) +SConscript("sconscfg/firmwareopts.scons") + +Import("env") +# Progress(["-\r", "\\\r", "|\r", "/\r"], interval=5) + +SConscript( + "firmware.scons", + variant_dir=f"build/f{env.subst('$FLIPPER_TARGET')}-{env.subst('$FIRMWARE_BUILD_CFG')}", + duplicate=0, +) diff --git a/firmware.scons b/firmware.scons index a3d62ae9e2a3..6b1714c3f5b0 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,53 +1,66 @@ Import("env") SConscript("lib/lib.scons") -env.Append( - FLIPPER_TARGET="7", - IMAGE_BASE_ADDRESS="0x8000000", -) env.Append( CPPDEFINES=[ ("TARGET", "${FLIPPER_TARGET}"), - "APP_ABOUT", - "APP_ACCESSOR", - "APP_ARCHIVE", - "APP_BAD_USB", - "APP_BLE_HID", - "APP_BLINK", - "APP_DISPLAY_TEST", - "APP_GPIO", - "APP_IBUTTON", - "APP_INFRARED", - "APP_INFRARED_MONITOR", - "APP_KEYPAD_TEST", - "APP_LF_RFID", - "APP_MUSIC_PLAYER", - "APP_NFC", - "APP_PASSPORT", - "APP_SNAKE_GAME", - "APP_SUBGHZ", - "APP_U2F", - "APP_UART_ECHO", - "APP_UPDATER", - "APP_USB_MOUSE", - "APP_USB_TEST", - "APP_VIBRO_TEST", - "SRV_BT", - "SRV_CLI", - "SRV_DESKTOP", - "SRV_DIALOGS", - "SRV_DOLPHIN", - "SRV_GUI", - "SRV_INPUT", - "SRV_LOADER", - "SRV_NOTIFICATION", - "SRV_POWER", - "SRV_RPC", - "SRV_STORAGE", ] ) +if env["FIRMWARE_BUILD_CFG"] == "updater": + env.Append( + CPPDEFINES=[ + "SRV_GUI", + "SRV_INPUT", + "SRV_NOTIFICATION", + "SRV_STORAGE", + "SRV_UPDATER", + ] + ) +else: + env.Append( + CPPDEFINES=[ + "APP_ABOUT", + "APP_ACCESSOR", + "APP_ARCHIVE", + "APP_BAD_USB", + "APP_BLE_HID", + "APP_BLINK", + "APP_DISPLAY_TEST", + "APP_GPIO", + "APP_IBUTTON", + "APP_INFRARED", + "APP_INFRARED_MONITOR", + "APP_KEYPAD_TEST", + "APP_LF_RFID", + "APP_MUSIC_PLAYER", + "APP_NFC", + "APP_PASSPORT", + "APP_SNAKE_GAME", + "APP_SUBGHZ", + "APP_U2F", + "APP_UART_ECHO", + "APP_UPDATER", + "APP_USB_MOUSE", + "APP_USB_TEST", + "APP_VIBRO_TEST", + "SRV_BT", + "SRV_CLI", + "SRV_DESKTOP", + "SRV_DIALOGS", + "SRV_DOLPHIN", + "SRV_GUI", + "SRV_INPUT", + "SRV_LOADER", + "SRV_NOTIFICATION", + "SRV_POWER", + "SRV_RPC", + "SRV_STORAGE", + ] + ) + + env.Append( CPPPATH=[ ".", @@ -142,8 +155,10 @@ sources += [ "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", ] -print(env.Dump()) -env.CompilationDatabase() +# print(env.Dump()) +cdb = env.CompilationDatabase("compile_database.json") +Alias("cdb", cdb) + env.Program("flipperfw", sources) env.HEXBuilder("flipperfw") env.BINBuilder("flipperfw") diff --git a/sconscfg/cc.scons b/sconscfg/cc.scons index 61a68245fb37..dbc30fcccb09 100644 --- a/sconscfg/cc.scons +++ b/sconscfg/cc.scons @@ -1,17 +1,6 @@ Import("env") -env.Append( - CCFLAGS=[ - "-O2", - "-g", - ], - CPPDEFINES=[ - "NDEBUG", - "FURI_NDEBUG", - ], -) - env.Append( CFLAGS=[ "-std=gnu17", @@ -68,7 +57,6 @@ env.Append( "-lstdc++", "-lsupc++", "-Wl,--end-group", - "-Tfirmware/targets/f7/stm32wb55xx_flash.ld", "-Wl,--gc-sections", "-Wl,--undefined=uxTopUsedPriority", "-n", diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 6708425daa26..6bda8fcaf056 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -5,10 +5,19 @@ import SCons import os import sys import re +import multiprocessing TOOLCHAIN_PREFIX = "arm-none-eabi-" +vars = Variables(None, ARGUMENTS) +vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) +vars.Add(BoolVariable("COMPACT", help="Optimize for size", default=0)) +vars.Add( + BoolVariable("RAM_EXEC", help="Build updater image for RAM exection", default=0) +) + env = Environment( + variables=vars, tools=["gcc", "g++", "ar", "gnulink", "python", "compilation_db"], # CC="arm-none-eabi-gcc", # CXX="arm-none-eabi-g++", @@ -16,7 +25,7 @@ env = Environment( # CCFLAGS=[], # LINKFLAGS=[], OBJCOPY="objcopy", - PYTHON3="python", + PYTHON3="python3", TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", @@ -25,6 +34,11 @@ env = Environment( "PATH": os.environ["PATH"], }, ) +Help(vars.GenerateHelpText(env)) + +# Default value for -j + +SetOption("num_jobs", multiprocessing.cpu_count()) # Setting up temp file parameters diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons new file mode 100644 index 000000000000..6d3308199645 --- /dev/null +++ b/sconscfg/firmwareopts.scons @@ -0,0 +1,72 @@ +Import("env") + +env.Append( + FLIPPER_TARGET="7", +) + +# vars = Variables(None, ARGUMENTS) +# vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) +# vars.Add(BoolVariable("COMPACT", help="Otimize for size", default=0)) +# vars.Add( +# BoolVariable("RAM_EXEC", help="Build updater image for RAM exection", default=0) +# ) +# env.Append(variables=vars) +# Help(vars.GenerateHelpText(env)) + +print(env.Dump()) + +if env["DEBUG"]: + env.Append( + CPPDEFINES=[ + "FURI_DEBUG", + "NDEBUG", + ], + CCFLAGS=[ + "-Og", + "-g", + ], + ) +elif env["COMPACT"]: + env.Append( + CPPDEFINES=[ + "FURI_NDEBUG", + "NDEBUG", + ], + CCFLAGS=[ + "-Os", + "-g", + ], + ) +else: + env.Append( + CPPDEFINES=[ + "FURI_NDEBUG", + "NDEBUG", + ], + CCFLAGS=[ + "-Og", + "-g", + ], + ) + +if env["RAM_EXEC"]: + env.Append( + CPPDEFINES=[ + "FURI_RAM_EXEC", + "VECT_TAB_SRAM", + "FLIPPER_STREAM_LITE", + ], + IMAGE_BASE_ADDRESS="0x20000000", + LINKFLAGS=[ + "-Tfirmware/targets/f7/stm32wb55xx_ram_fw.ld", + ], + FIRMWARE_BUILD_CFG="updater", + ) +else: + env.Append( + IMAGE_BASE_ADDRESS="0x8000000", + LINKFLAGS=[ + "-Tfirmware/targets/f7/stm32wb55xx_flash.ld", + ], + FIRMWARE_BUILD_CFG="firmware", + ) From ef5bbd2219d5be100fe80d920b295f7bdb455138 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 25 May 2022 01:00:31 +0400 Subject: [PATCH 010/184] Renamed output files to match configuration --- firmware.scons | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware.scons b/firmware.scons index 6b1714c3f5b0..b7d04f707e83 100644 --- a/firmware.scons +++ b/firmware.scons @@ -159,7 +159,7 @@ sources += [ cdb = env.CompilationDatabase("compile_database.json") Alias("cdb", cdb) -env.Program("flipperfw", sources) -env.HEXBuilder("flipperfw") -env.BINBuilder("flipperfw") -env.DFUBuilder("flipperfw") +env.Program("${FIRMWARE_BUILD_CFG}", sources) +env.HEXBuilder("${FIRMWARE_BUILD_CFG}") +env.BINBuilder("${FIRMWARE_BUILD_CFG}") +env.DFUBuilder("${FIRMWARE_BUILD_CFG}") From d29c552ea49f24f91926ff9c3de5de5b0ea46762 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 26 May 2022 11:34:01 +0400 Subject: [PATCH 011/184] Generation of version header --- .../targets/f7/ble_glue/dev_info_service.h | 6 -- lib/toolbox/version.c | 4 + scripts/version.py | 91 +++++++++++++++++++ 3 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 scripts/version.py diff --git a/firmware/targets/f7/ble_glue/dev_info_service.h b/firmware/targets/f7/ble_glue/dev_info_service.h index 2faac8a66546..8cce20a6ccac 100644 --- a/firmware/targets/f7/ble_glue/dev_info_service.h +++ b/firmware/targets/f7/ble_glue/dev_info_service.h @@ -7,12 +7,6 @@ extern "C" { #endif -#define DEV_INFO_MANUFACTURER_NAME "Flipper Devices Inc." -#define DEV_INFO_SERIAL_NUMBER "1.0" -#define DEV_INFO_FIRMWARE_REVISION_NUMBER TARGET -#define DEV_INFO_SOFTWARE_REVISION_NUMBER \ - GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE - void dev_info_svc_start(); void dev_info_svc_stop(); diff --git a/lib/toolbox/version.c b/lib/toolbox/version.c index 40c48370b380..d02bebba4950 100644 --- a/lib/toolbox/version.c +++ b/lib/toolbox/version.c @@ -1,5 +1,9 @@ #include "version.h" +#ifndef GIT_COMMIT +#include "version.inc.h" +#endif + struct Version { const char* git_hash; const char* git_branch; diff --git a/scripts/version.py b/scripts/version.py new file mode 100644 index 000000000000..e76bf715ea65 --- /dev/null +++ b/scripts/version.py @@ -0,0 +1,91 @@ +#!/usb/bin/env python3 + +from flipper.app import App + +import subprocess +import os +from datetime import date + + +class GitVersion: + def __init__(self, source_dir): + self.source_dir = source_dir + + def get_version_info(self): + commit = self._exec_git("rev-parse --short HEAD") or "unknown" + + dirty = False + try: + self._exec_git("diff --quiet") + except subprocess.CalledProcessError as e: + if e.returncode == 1: + dirty = True + + branch = self._exec_git("rev-parse --abbrev-ref HEAD") or "unknown" + branch_num = self._exec_git("rev-list --count HEAD") or "n/a" + build_date = date.today().isoformat() + + try: + version = self._exec_git("describe --tags --abbrev=0 --exact-match") + except subprocess.CalledProcessError: + version = "unknown" + + return { + "GIT_COMMIT": f'"{commit}"', + "GIT_BRANCH": f'"{branch}"', + "GIT_BRANCH_NUM": f'"{branch_num}"', + "VERSION": f'"{version}"', + "BUILD_DATE": f'"{build_date}"', + "BUILD_DIRTY": dirty and 1 or 0, + } + + def _exec_git(self, args): + cmd = ["git"] + cmd.extend(args.split(" ")) + return ( + subprocess.check_output(cmd, cwd=self.source_dir, stderr=subprocess.STDOUT) + .strip() + .decode() + ) + + +class Main(App): + def init(self): + self.subparsers = self.parser.add_subparsers(help="sub-command help") + + # generate + self.parser_generate = self.subparsers.add_parser( + "generate", help="Generate version header" + ) + + self.parser_generate.add_argument("-o", dest="output", required=True) + self.parser_generate.add_argument("--dir", dest="sourcedir", required=True) + self.parser_generate.set_defaults(func=self.generate) + + def generate(self): + current_info = GitVersion(self.args.sourcedir).get_version_info() + new_version_info_fmt = "\n".join( + f"#define {key} {current_info[key]}" for key in current_info + ) + + current_version_info = None + + try: + with open(self.args.output, "r") as file: + current_version_info = file.read() + except EnvironmentError: + pass + + if current_version_info != new_version_info_fmt: + with open(self.args.output, "w") as file: + file.write(new_version_info_fmt) + # os.utime("../lib/toolbox/version.c", None) + print("Version information updated") + else: + print("Version information hasn't changed") + + return 0 + + +if __name__ == "__main__": + Main()() From 1a4d7b0f768049b81852c4d672e3e19e7ea910d0 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 2 Jun 2022 19:04:59 +0400 Subject: [PATCH 012/184] Modular build wip --- .gitignore | 6 + SConstruct | 7 +- firmware.scons | 195 +++++++++--------- firmware/SConscript | 18 ++ .../targets/f7/ble_glue/dev_info_service.c | 18 +- firmware/targets/f7/ble_glue/tl_dbg_conf.h | 2 +- lib/SConscript | 60 ++++++ lib/ST25RFAL002/SConscript | 20 ++ lib/STM32CubeWB.scons | 57 +++++ lib/appframe.scons | 30 +++ lib/drivers/SConscript | 18 ++ lib/fatfs/SConscript | 12 ++ lib/flipper_format/SConscript | 18 ++ lib/freertos.scons | 27 +++ lib/heatshrink/SConscript | 1 + lib/infrared/SConscript | 19 ++ lib/lib.scons | 57 ----- lib/libusb_stm32.scons | 23 +++ lib/littlefs.scons | 20 ++ lib/misc.scons | 47 +++++ lib/nanopb.scons | 1 + lib/subghz/SConscript | 17 ++ lib/toolbox/SConscript | 21 ++ sconscfg/environ.scons | 67 +++++- sconscfg/firmwareopts.scons | 28 +-- sconscfg/git.scons | 32 +-- scripts/version.py | 13 +- 27 files changed, 635 insertions(+), 199 deletions(-) create mode 100644 firmware/SConscript create mode 100644 lib/SConscript create mode 100644 lib/ST25RFAL002/SConscript create mode 100644 lib/STM32CubeWB.scons create mode 100644 lib/appframe.scons create mode 100644 lib/drivers/SConscript create mode 100644 lib/fatfs/SConscript create mode 100644 lib/flipper_format/SConscript create mode 100644 lib/freertos.scons create mode 100644 lib/heatshrink/SConscript create mode 100644 lib/infrared/SConscript delete mode 100644 lib/lib.scons create mode 100644 lib/libusb_stm32.scons create mode 100644 lib/littlefs.scons create mode 100644 lib/misc.scons create mode 100644 lib/nanopb.scons create mode 100644 lib/subghz/SConscript create mode 100644 lib/toolbox/SConscript diff --git a/.gitignore b/.gitignore index 9fcb47dbd001..8b505f6f3093 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,9 @@ dist # SCons .sconsign.dblite + +# Build objects +*.d +*.o +*.su +*.a diff --git a/SConstruct b/SConstruct index 30ca9d23a9ea..ea146fab4450 100644 --- a/SConstruct +++ b/SConstruct @@ -2,13 +2,14 @@ SConscript("sconscfg/environ.scons") SConscript("sconscfg/cc.scons") SConscript("sconscfg/git.scons") SConscript("sconscfg/builders.scons") -SConscript("sconscfg/firmwareopts.scons") Import("env") # Progress(["-\r", "\\\r", "|\r", "/\r"], interval=5) - +# variant_dir_name = f"build/f{env.subst('$FLIPPER_TARGET')}-{env.subst('$FIRMWARE_BUILD_CFG')}" +variant_dir_name = "build/fw" SConscript( "firmware.scons", - variant_dir=f"build/f{env.subst('$FLIPPER_TARGET')}-{env.subst('$FIRMWARE_BUILD_CFG')}", + variant_dir=variant_dir_name, + exports="variant_dir_name", duplicate=0, ) diff --git a/firmware.scons b/firmware.scons index b7d04f707e83..f77d91af4215 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,15 +1,47 @@ -Import("env") -SConscript("lib/lib.scons") +Import("env", "variant_dir_name") +env.Append( + FLIPPER_TARGET="7", + BUILD_DIR=variant_dir_name, +) env.Append( + LIBPATH=[ + "#/${BUILD_DIR}/lib", + ], CPPDEFINES=[ ("TARGET", "${FLIPPER_TARGET}"), + ], +) + +env.Append( + CPPPATH=[ + "#/core", + "#/applications", + "#/firmware/targets/f${FLIPPER_TARGET}/ble_glue", + "#/firmware/targets/f${FLIPPER_TARGET}/fatfs", + "#/firmware/targets/f${FLIPPER_TARGET}/furi_hal", + "#/firmware/targets/f${FLIPPER_TARGET}/Inc", + "#/firmware/targets/furi_hal_include", ] ) -if env["FIRMWARE_BUILD_CFG"] == "updater": - env.Append( +depends = env.BuildModules( + env, + [ + "#/lib", + "#/firmware", + ], +) + +fwenv = env.Clone() +Export("fwenv") + +SConscript("sconscfg/firmwareopts.scons") + + +if fwenv["FIRMWARE_BUILD_CFG"] == "updater": + fwenv.Append( CPPDEFINES=[ "SRV_GUI", "SRV_INPUT", @@ -19,7 +51,7 @@ if env["FIRMWARE_BUILD_CFG"] == "updater": ] ) else: - env.Append( + fwenv.Append( CPPDEFINES=[ "APP_ABOUT", "APP_ACCESSOR", @@ -61,105 +93,74 @@ else: ) -env.Append( - CPPPATH=[ - ".", - "./applications", - "./assets/compiled", - "./core", - "./firmware/targets/f${FLIPPER_TARGET}/ble_glue", - "./firmware/targets/f${FLIPPER_TARGET}/fatfs", - "./firmware/targets/f${FLIPPER_TARGET}/furi_hal", - "./firmware/targets/f${FLIPPER_TARGET}/Inc", - "./firmware/targets/furi_hal_include", - ] -) +sources = fwenv.GlobRecursive("*.c*", "applications") +sources += Glob("assets/compiled/*.c*", source=True) -sources = env.GlobRecursive("*.c", "core") -sources += env.GlobRecursive("*.c", "firmware") -sources += ["firmware/targets/f${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] -sources += env.GlobRecursive("*.c*", "applications") - -libs_recurse = [ - "assets/compiled", - "lib/app-scened-template", - "lib/digital_signal", - "lib/drivers", - "lib/flipper_format", - "lib/infrared", - "lib/micro-ecc", - "lib/microtar/src", - "lib/nfc_protocols", - "lib/one_wire", - "lib/ST25RFAL002/source", - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/", - "lib/subghz", - "lib/toolbox", - "lib/u8g2", - "lib/update_util", -] - -for lib in libs_recurse: - sources += env.GlobRecursive("*.c*", lib) - - -libs_plain = [ - "lib/fatfs", - "lib/heatshrink", - "lib/libusb_stm32/src", - "lib/littlefs", - "lib/nanopb", - "lib/ST25RFAL002", -] - -for lib in libs_plain: - sources += Glob(lib + "/*.c*", source=True) - - -sources += [ - "lib/fatfs/option/unicode.c", - "lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c", -] - -sources += Glob( - "lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/*.c", source=True -) -sources += Glob( - "lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/*.c", - source=True, -) +# print(fwenv.Dump()) +cdb = fwenv.CompilationDatabase("compile_database.json") +Alias("cdb", cdb) -sources += env.GlobRecursive( - "*_ll_*.c", "lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/", exclude="*usb.c" +build_version = fwenv.Command( + "#lib/toolbox/version.inc.h", + [], + "${PYTHON3} scripts/version.py generate -o ${TARGET} --dir .", ) +# fwenv.AlwaysBuild(build_version) -sources += Glob( - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/*.c", - source=True, +build_version_noarg = fwenv.Command( + [], + [], + "${PYTHON3} scripts/version .py generate -o lib/toolbox/version.inc.h --dir .", ) -sources += Glob( - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/*_tl*.c", - source=True, +fwenv.AlwaysBuild(build_version_noarg) + + +def version_action(target, source, fwenv): + """ + Generate the version file with the current version in it + """ + contents = version_build_template % (fwenv["VERSION"].toString()) + fd = open(target[0].path, "w") + fd.write(contents) + fd.close() + return 0 + + +fwenv.Append( + # LIBPATH=[ + # "#/lib", + # ], + LIBS=[ + "flipper${FLIPPER_TARGET}", + "freertos", + "STM32CubeWB", + "hwdrivers", + "fatfs", + "littlefs", + "subghz", + "toolbox", + "usb_stm32", + "ST25RFAL002", + "flipperformat", + "misc", + "infrared", + "appframe", + ], ) -sources += [ - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c", - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/svc/Src/svc_ctl.c", - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c", - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c", - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c", - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hci_le.c", - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c", - "lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", -] - -# print(env.Dump()) -cdb = env.CompilationDatabase("compile_database.json") -Alias("cdb", cdb) +firmware_elf = fwenv.Program("${FIRMWARE_BUILD_CFG}", sources) +# fwenv.AddPreAction( +# firmware_elf, +# Action( +# build_version_noarg +# # "${PYTHON3} scripts/version.py generate -o lib/toolbox/version.inc.h --dir .", +# ), +# ) +Requires(firmware_elf, depends) + -env.Program("${FIRMWARE_BUILD_CFG}", sources) -env.HEXBuilder("${FIRMWARE_BUILD_CFG}") -env.BINBuilder("${FIRMWARE_BUILD_CFG}") -env.DFUBuilder("${FIRMWARE_BUILD_CFG}") +fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") +fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") +fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") diff --git a/firmware/SConscript b/firmware/SConscript new file mode 100644 index 000000000000..a38bb8dd90a5 --- /dev/null +++ b/firmware/SConscript @@ -0,0 +1,18 @@ +Import("env", "lib_flags") + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +libenv.Append( + CPPPATH=[ + "#/assets/compiled", + ], +) + +sources = libenv.GlobRecursive("*.c", "#/core") +sources += libenv.GlobRecursive("*.c", ".") +sources += ["targets/f${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] + +lib = libenv.Library("flipper${FLIPPER_TARGET}", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/firmware/targets/f7/ble_glue/dev_info_service.c b/firmware/targets/f7/ble_glue/dev_info_service.c index 4adfce59cd8b..766c4b40f4ac 100755 --- a/firmware/targets/f7/ble_glue/dev_info_service.c +++ b/firmware/targets/f7/ble_glue/dev_info_service.c @@ -5,6 +5,7 @@ #include #include #include +#include #define TAG "BtDevInfoSvc" @@ -15,6 +16,7 @@ typedef struct { uint16_t firmware_rev_char_handle; uint16_t software_rev_char_handle; uint16_t rpc_version_char_handle; + string_t version_string; } DevInfoSvc; static DevInfoSvc* dev_info_svc = NULL; @@ -22,8 +24,6 @@ static DevInfoSvc* dev_info_svc = NULL; static const char dev_info_man_name[] = "Flipper Devices Inc."; static const char dev_info_serial_num[] = "1.0"; static const char dev_info_firmware_rev_num[] = TOSTRING(TARGET); -static const char dev_info_software_rev_num[] = GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM - " " BUILD_DATE; static const char dev_info_rpc_version[] = TOSTRING(PROTOBUF_MAJOR_VERSION.PROTOBUF_MINOR_VERSION); static const uint8_t dev_info_rpc_version_uuid[] = @@ -31,6 +31,13 @@ static const uint8_t dev_info_rpc_version_uuid[] = void dev_info_svc_start() { dev_info_svc = malloc(sizeof(DevInfoSvc)); + string_init_printf( + dev_info_svc->version_string, + "%s %s %s %s", + version_get_githash(NULL), + version_get_gitbranch(NULL), + version_get_gitbranchnum(NULL), + version_get_builddate(NULL)); tBleStatus status; // Add Device Information Service @@ -92,7 +99,7 @@ void dev_info_svc_start() { dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(dev_info_software_rev_num), + string_size(dev_info_svc->version_string), CHAR_PROP_READ, ATTR_PERMISSION_AUTHEN_READ, GATT_DONT_NOTIFY_EVENTS, @@ -149,8 +156,8 @@ void dev_info_svc_start() { dev_info_svc->service_handle, dev_info_svc->software_rev_char_handle, 0, - strlen(dev_info_software_rev_num), - (uint8_t*)dev_info_software_rev_num); + string_size(dev_info_svc->version_string), + (uint8_t*)string_get_cstr(dev_info_svc->version_string)); if(status) { FURI_LOG_E(TAG, "Failed to update software revision char: %d", status); } @@ -168,6 +175,7 @@ void dev_info_svc_start() { void dev_info_svc_stop() { tBleStatus status; if(dev_info_svc) { + string_clear(dev_info_svc->version_string); // Delete service characteristics status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->man_name_char_handle); diff --git a/firmware/targets/f7/ble_glue/tl_dbg_conf.h b/firmware/targets/f7/ble_glue/tl_dbg_conf.h index 1f09b7e4d10b..6a96aa6e126c 100644 --- a/firmware/targets/f7/ble_glue/tl_dbg_conf.h +++ b/firmware/targets/f7/ble_glue/tl_dbg_conf.h @@ -33,7 +33,7 @@ extern "C" { #include "app_conf.h" /* required as some configuration used in dbg_trace.h are set there */ #include "dbg_trace.h" #include "hw_if.h" -#include +//#include /** * Enable or Disable traces diff --git a/lib/SConscript b/lib/SConscript new file mode 100644 index 000000000000..6d4838230a4a --- /dev/null +++ b/lib/SConscript @@ -0,0 +1,60 @@ +Import("env") + + +env.Append( + CPPPATH=[ + "#/", + "#/lib", # TODO: remove! + "#/lib/mlib", + ], + CPPDEFINES=[ + '"M_MEMORY_FULL(x)=abort()"', + ], +) + + +# drivers +# fatfs +# flipper_format +# infrared +# littlefs +# subghz +# toolbox +# misc +# digital_signal +# fnv1a-hash +# micro-ecc +# microtar +# nfc_protocols +# one_wire +# qrcode +# u8g2 +# update_util +# heatshrink +# nanopb +# apps +# app-scened-template +# callback-connector +# app-template + + +libs = env.BuildModules( + env, + [ + "STM32CubeWB", + "freertos", + "toolbox", + "ST25RFAL002", + "libusb_stm32", + "drivers", + "fatfs", + "flipper_format", + "infrared", + "littlefs", + "subghz", + "appframe", + "misc", + ], +) + +Return("libs") diff --git a/lib/ST25RFAL002/SConscript b/lib/ST25RFAL002/SConscript new file mode 100644 index 000000000000..7bab73717f3c --- /dev/null +++ b/lib/ST25RFAL002/SConscript @@ -0,0 +1,20 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/ST25RFAL002", + "#/lib/ST25RFAL002/include", + "#/lib/ST25RFAL002/source/st25r3916", + ], + CPPDEFINES=[], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = libenv.GlobRecursive("*.c", ".") + +lib = libenv.StaticLibrary("ST25RFAL002", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons new file mode 100644 index 000000000000..1b73b6b7cd73 --- /dev/null +++ b/lib/STM32CubeWB.scons @@ -0,0 +1,57 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/STM32CubeWB/Drivers/CMSIS/Device/ST", + "#/lib/STM32CubeWB/Drivers/CMSIS/Device/ST/STM32WBxx/Include", + "#/lib/STM32CubeWB/Drivers/CMSIS/Include", + "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc", + "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl", + "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities", + ], + CPPDEFINES=[ + "USE_FULL_ASSERT", + "USE_FULL_LL_DRIVER", + ], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = libenv.GlobRecursive( + "*_ll_*.c", "STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/", exclude="*usb.c" +) + +sources += Glob( + "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/*.c", + source=True, +) +sources += Glob( + "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/*_tl*.c", + source=True, +) +sources += [ + "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/svc/Src/svc_ctl.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hci_le.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/dbg_trace.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/otp.c", + "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/stm_list.c", +] + +lib = libenv.StaticLibrary("STM32CubeWB", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/appframe.scons b/lib/appframe.scons new file mode 100644 index 000000000000..3d2335ad654c --- /dev/null +++ b/lib/appframe.scons @@ -0,0 +1,30 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/app-scened-template", + "#/lib/app-template", + "#/lib/callback-connector", + "#/assets/compiled", + ], + CPPDEFINES=[], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = [] + +recurse_dirs = [ + "app-scened-template", + "callback-connector", + "app-template", +] + +for recurse_dir in recurse_dirs: + sources += libenv.GlobRecursive("*.c*", recurse_dir) + +lib = libenv.StaticLibrary("appframe", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript new file mode 100644 index 000000000000..fc65f0423417 --- /dev/null +++ b/lib/drivers/SConscript @@ -0,0 +1,18 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/drivers", + ], + CPPDEFINES=[], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = Glob("*.c", source=True) # libenv.GlobRecursive("*.c", ".") + +lib = libenv.StaticLibrary("hwdrivers", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/fatfs/SConscript b/lib/fatfs/SConscript new file mode 100644 index 000000000000..f3ee24e09b50 --- /dev/null +++ b/lib/fatfs/SConscript @@ -0,0 +1,12 @@ +Import("env", "lib_flags") + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = Glob("*.c", source=True) +sources += ["option/unicode.c"] + +lib = libenv.StaticLibrary("fatfs", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript new file mode 100644 index 000000000000..76a7e11bad49 --- /dev/null +++ b/lib/flipper_format/SConscript @@ -0,0 +1,18 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/flipper_format", + ], + CPPDEFINES=[], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = libenv.GlobRecursive("*.c", ".") + +lib = libenv.StaticLibrary("flipperformat", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/freertos.scons b/lib/freertos.scons new file mode 100644 index 000000000000..1ca0eee33b03 --- /dev/null +++ b/lib/freertos.scons @@ -0,0 +1,27 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/drivers", + "#/lib/FreeRTOS-Kernel/include", + "#/lib/FreeRTOS-Kernel/portable/GCC/ARM_CM4F", + "#/lib/FreeRTOS-glue", + ], + CPPDEFINES=[ + "HAVE_FREERTOS", + ], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = libenv.Glob("FreeRTOS-Kernel/*.c", source=True) +sources += [ + "FreeRTOS-Kernel/portable/GCC/ARM_CM4F/port.c", + "FreeRTOS-glue/cmsis_os2.c", +] + +lib = libenv.StaticLibrary("freertos", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/heatshrink/SConscript b/lib/heatshrink/SConscript new file mode 100644 index 000000000000..1ad04d93fa76 --- /dev/null +++ b/lib/heatshrink/SConscript @@ -0,0 +1 @@ +Import("env") diff --git a/lib/infrared/SConscript b/lib/infrared/SConscript new file mode 100644 index 000000000000..b0ddde6cb513 --- /dev/null +++ b/lib/infrared/SConscript @@ -0,0 +1,19 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/infrared/encoder_decoder", + "#/lib/infrared/worker", + ], + CPPDEFINES=[], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = libenv.GlobRecursive("*.c", ".") + +lib = libenv.StaticLibrary("infrared", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/lib.scons b/lib/lib.scons deleted file mode 100644 index deb72ddf651f..000000000000 --- a/lib/lib.scons +++ /dev/null @@ -1,57 +0,0 @@ -Import("env") - - -env.Append( - CPPPATH=[ - "./lib", - "./lib/app-scened-template", - "./lib/app-template", - "./lib/callback-connector", - "./lib/common-api", - "./lib/digital_signal", - "./lib/drivers", - "./lib/file_reader", - "./lib/flipper_format", - "./lib/fnv1a_hash", - "./lib/FreeRTOS-glue", - "./lib/heatshrink", - "./lib/infrared/encoder_decoder", - "./lib/infrared/worker", - "./lib/libusb_stm32/inc", - "./lib/littlefs", - "./lib/micro-ecc", - "./lib/microtar/src", - "./lib/mlib", - "./lib/nanopb", - "./lib/nfc_protocols", - "./lib/ST25RFAL002", - "./lib/ST25RFAL002/include", - "./lib/ST25RFAL002/source/st25r3916", - "./lib/STM32CubeWB/Drivers/CMSIS/Device/ST", - "./lib/STM32CubeWB/Drivers/CMSIS/Device/ST/STM32WBxx/Include", - "./lib/STM32CubeWB/Drivers/CMSIS/Include", - "./lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc", - "./lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy", - "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN", - "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble", - "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core", - "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/ble/core/template", - "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread", - "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci", - "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl", - "./lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities", - "./lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2", - "./lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include", - "./lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F", - "./lib/u8g2", - ], - CPPDEFINES=[ - '"M_MEMORY_FULL(x)=abort()"', - ("USB_PMASIZE", "0x400"), - ("LFS_CONFIG", "lfs_config.h"), - "USE_FULL_ASSERT", - "USE_FULL_LL_DRIVER", - "HAVE_FREERTOS", - "PB_ENABLE_MALLOC", - ], -) diff --git a/lib/libusb_stm32.scons b/lib/libusb_stm32.scons new file mode 100644 index 000000000000..32c04dede8eb --- /dev/null +++ b/lib/libusb_stm32.scons @@ -0,0 +1,23 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/libusb_stm32/inc", + ], + CPPDEFINES=[ + ("USB_PMASIZE", "0x400"), + ], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = [ + "libusb_stm32/src/usbd_core.c", + "libusb_stm32/src/usbd_stm32wb55_devfs.c", +] + +lib = libenv.StaticLibrary("usb_stm32", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/littlefs.scons b/lib/littlefs.scons new file mode 100644 index 000000000000..4ecb34933a18 --- /dev/null +++ b/lib/littlefs.scons @@ -0,0 +1,20 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/littlefs", + ], + CPPDEFINES=[ + ("LFS_CONFIG", "lfs_config.h"), + ], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = Glob("littlefs/*.c", source=True) + +lib = libenv.StaticLibrary("littlefs", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/misc.scons b/lib/misc.scons new file mode 100644 index 000000000000..85ac0b71c41c --- /dev/null +++ b/lib/misc.scons @@ -0,0 +1,47 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/digital_signal", + "#/lib/fnv1a_hash", + "#/lib/heatshrink", + "#/lib/micro-ecc", + "#/lib/nanopb", + "#/lib/nfc_protocols", + "#/lib/u8g2", + ], + CPPDEFINES=[ + "PB_ENABLE_MALLOC", + ], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + + +sources = [] + +libs_recurse = [ + "digital_signal", + "micro-ecc", + "nfc_protocols", + "one_wire", + "u8g2", + "update_util", +] + +for lib in libs_recurse: + sources += libenv.GlobRecursive("*.c*", lib) + +libs_plain = [ + "heatshrink", + "nanopb", +] + +for lib in libs_plain: + sources += Glob(lib + "/*.c*", source=True) + +lib = libenv.StaticLibrary("misc", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/nanopb.scons b/lib/nanopb.scons new file mode 100644 index 000000000000..1ad04d93fa76 --- /dev/null +++ b/lib/nanopb.scons @@ -0,0 +1 @@ +Import("env") diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript new file mode 100644 index 000000000000..5f68e75e3cd9 --- /dev/null +++ b/lib/subghz/SConscript @@ -0,0 +1,17 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/subghz", + ], + CPPDEFINES=[], +) + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +sources = libenv.GlobRecursive("*.c*", ".") + +lib = libenv.StaticLibrary("subghz", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript new file mode 100644 index 000000000000..f0d5e62e7699 --- /dev/null +++ b/lib/toolbox/SConscript @@ -0,0 +1,21 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/microtar/src", + "#/lib/toolbox", + ], + CPPDEFINES=[], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) +# TODO: consider adding optimization flags for microtar here + +sources = libenv.GlobRecursive("*.c", ".") +sources += libenv.GlobRecursive("*.c", "../microtar/src") + +lib = libenv.StaticLibrary("toolbox", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 6bda8fcaf056..09a2b96906df 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -18,7 +18,7 @@ vars.Add( env = Environment( variables=vars, - tools=["gcc", "g++", "ar", "gnulink", "python", "compilation_db"], + tools=["as", "gcc", "g++", "ar", "gnulink", "python", "compilation_db"], # CC="arm-none-eabi-gcc", # CXX="arm-none-eabi-g++", # LINK="arm-none-eabi-g++", @@ -34,11 +34,17 @@ env = Environment( "PATH": os.environ["PATH"], }, ) + +if env["PLATFORM"] == "win32": + # On Windows, python 3 executable is usually just "python" + env["PYTHON3"] = env["PYTHON3"][:-1] + Help(vars.GenerateHelpText(env)) # Default value for -j SetOption("num_jobs", multiprocessing.cpu_count()) +SetOption("implicit_cache", True) # Setting up temp file parameters @@ -59,7 +65,7 @@ env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func # Set up cross-compile tools for binary in [ "AR", - # "AS", + "AS", "CC", "CXX", # "LINK", @@ -91,4 +97,59 @@ def GlobRecursive(pattern, node=".", exclude=None): env.GlobRecursive = GlobRecursive -Export("env") + +def check_exists(path): + # print("checking", File(path).abspath) + return os.path.exists(File(path).abspath) + + +def build_module(env, module): + print("module") + module_sconscript = f"{module}/SConscript" + if not check_exists(module_sconscript): + module_sconscript = f"{module}.scons" + if not check_exists(module_sconscript): + print(f"Cannot build module {module}: scons file not found") + Exit(2) + + # # module_sconscript = os.path.join(module, "SConscript") + # print("check for ", module_sconscript) + # if not os.path.exists(module_sconscript): + # module_sconscript = f"{module}.scons" + + print("sub-building", module_sconscript) + return env.SConscript( + module_sconscript, + # variant_dir=module + "/obj", + # variant_dir=env["BUILD_DIR"], + duplicate=0, + ) + + +def BuildModules(env, modules): + print("build list", modules) + result = [] + for module in modules: + build_res = build_module(env, module) + # print("module ", module, build_res) + if build_res is None: + continue + elif isinstance(build_res, list): + result.extend(build_res) + else: + result.append(build_res[0]) # ??? + return result + + +env.BuildModules = BuildModules + +lib_flags = { + "CCFLAGS": [ + "-Os", + ], + "CPPDEFINES": [ + "NDEBUG", + ], +} + +Export("env", "lib_flags") diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 6d3308199645..8189c9ecdf16 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -1,8 +1,8 @@ -Import("env") +Import("fwenv") -env.Append( - FLIPPER_TARGET="7", -) +# fwenv.Append( +# FLIPPER_TARGET="7", +# ) # vars = Variables(None, ARGUMENTS) # vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) @@ -10,13 +10,13 @@ env.Append( # vars.Add( # BoolVariable("RAM_EXEC", help="Build updater image for RAM exection", default=0) # ) -# env.Append(variables=vars) +# fwenv.Append(variables=vars) # Help(vars.GenerateHelpText(env)) -print(env.Dump()) +# print(fwenv.Dump()) -if env["DEBUG"]: - env.Append( +if fwenv["DEBUG"]: + fwenv.Append( CPPDEFINES=[ "FURI_DEBUG", "NDEBUG", @@ -26,8 +26,8 @@ if env["DEBUG"]: "-g", ], ) -elif env["COMPACT"]: - env.Append( +elif fwenv["COMPACT"]: + fwenv.Append( CPPDEFINES=[ "FURI_NDEBUG", "NDEBUG", @@ -38,7 +38,7 @@ elif env["COMPACT"]: ], ) else: - env.Append( + fwenv.Append( CPPDEFINES=[ "FURI_NDEBUG", "NDEBUG", @@ -49,8 +49,8 @@ else: ], ) -if env["RAM_EXEC"]: - env.Append( +if fwenv["RAM_EXEC"]: + fwenv.Append( CPPDEFINES=[ "FURI_RAM_EXEC", "VECT_TAB_SRAM", @@ -63,7 +63,7 @@ if env["RAM_EXEC"]: FIRMWARE_BUILD_CFG="updater", ) else: - env.Append( + fwenv.Append( IMAGE_BASE_ADDRESS="0x8000000", LINKFLAGS=[ "-Tfirmware/targets/f7/stm32wb55xx_flash.ld", diff --git a/sconscfg/git.scons b/sconscfg/git.scons index 8c9bd5418185..10be6053f1e2 100644 --- a/sconscfg/git.scons +++ b/sconscfg/git.scons @@ -1,19 +1,19 @@ Import("env") -env.Append( - BUILD_META_COMMIT="DUMMY", - BUILD_META_BRANCH="unknown", - BUILD_META_BRANCH_NUM="1337", - BUILD_META_VERSION="unknown", - BUILD_META_DATE="2021-06-28", - BUILD_META_DIRTY="1", - CPPDEFINES=[ - ("GIT_COMMIT", '\\"${BUILD_META_COMMIT}\\"'), - ("GIT_BRANCH", '\\"${BUILD_META_BRANCH}\\"'), - ("GIT_BRANCH_NUM", '\\"${BUILD_META_BRANCH_NUM}\\"'), - ("VERSION", '\\"${BUILD_META_VERSION}\\"'), - ("BUILD_DATE", '\\"${BUILD_META_DATE}\\"'), - ("BUILD_DIRTY", "${BUILD_META_DIRTY}"), - ], -) +# env.Append( +# BUILD_META_COMMIT="DUMMY", +# BUILD_META_BRANCH="unknown", +# BUILD_META_BRANCH_NUM="1337", +# BUILD_META_VERSION="unknown", +# BUILD_META_DATE="2021-06-28", +# BUILD_META_DIRTY="1", +# CPPDEFINES=[ +# ("GIT_COMMIT", '\\"${BUILD_META_COMMIT}\\"'), +# ("GIT_BRANCH", '\\"${BUILD_META_BRANCH}\\"'), +# ("GIT_BRANCH_NUM", '\\"${BUILD_META_BRANCH_NUM}\\"'), +# ("VERSION", '\\"${BUILD_META_VERSION}\\"'), +# ("BUILD_DATE", '\\"${BUILD_META_DATE}\\"'), +# ("BUILD_DIRTY", "${BUILD_META_DIRTY}"), +# ], +# ) diff --git a/scripts/version.py b/scripts/version.py index e76bf715ea65..4cdcf68a98aa 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -64,19 +64,26 @@ def init(self): def generate(self): current_info = GitVersion(self.args.sourcedir).get_version_info() - new_version_info_fmt = "\n".join( - f"#define {key} {current_info[key]}" for key in current_info + new_version_info_fmt = ( + "\n".join(f"#define {key} {current_info[key]}" for key in current_info) + + "\n" ) current_version_info = None try: + print(f"cwd: '{os.getcwd()}'") + print(f"path: '{self.args.output}'") + os.system("ls lib/toolbox/version*") with open(self.args.output, "r") as file: current_version_info = file.read() - except EnvironmentError: + except EnvironmentError as e: + print(e) pass if current_version_info != new_version_info_fmt: + print("old: ", current_version_info) + print("new: ", new_version_info_fmt) with open(self.args.output, "w") as file: file.write(new_version_info_fmt) # os.utime("../lib/toolbox/version.c", None) From e99f0d2372a885c9733080b5581432a69a82741d Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Thu, 2 Jun 2022 19:49:29 +0300 Subject: [PATCH 013/184] Add python3 wrapper --- scripts/python3.sh | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100755 scripts/python3.sh diff --git a/scripts/python3.sh b/scripts/python3.sh new file mode 100755 index 000000000000..bdb73bc28ab2 --- /dev/null +++ b/scripts/python3.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +# function return values +FALSE=1 +TRUE=0 + +is_flipper_toolchain_installed() +{ + TOOLCHAIN_GDB="$(which arm-none-eabi-gdb-py)" + if test -z "$TOOLCHAIN_GDB"; then + return "$FALSE"; + fi + TOOLCHAIN_DIR="$(/usr/bin/dirname -- "$(readlink -f -- "$TOOLCHAIN_GDB")")"; + FLIPPER_PY_DIR="$(cd "$TOOLCHAIN_DIR/../python/bin/" && pwd)"; + if ! test -d "$FLIPPER_PY_DIR"; then + return "$FALSE"; + fi + if ! test -f "$FLIPPER_PY_DIR/python3"; then + return "$FALSE"; + fi + return "$TRUE"; +} + +py3_host() +{ + /usr/bin/env python3 "$@" +} + +py3_flipper() +{ + "$FLIPPER_PY_DIR/python3" "$@" +} + +if is_flipper_toolchain_installed; then + py3_flipper "$@"; +else + py3_host "$@"; +fi From 8313c0febfd799289a6055938639f91ff881d502 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Fri, 3 Jun 2022 13:30:38 +0300 Subject: [PATCH 014/184] Moving python3 wrapper to Makefile, work logic changed - overriding PATH variable --- Makefile | 3 ++- make/python.mk | 11 +++++++++++ scripts/python3.sh | 38 -------------------------------------- 3 files changed, 13 insertions(+), 39 deletions(-) create mode 100644 make/python.mk delete mode 100755 scripts/python3.sh diff --git a/Makefile b/Makefile index 5304cfa54653..84cb08345584 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ NPROCS := $(shell sysctl -n hw.ncpu) endif include $(PROJECT_ROOT)/make/defaults.mk +include $(PROJECT_ROOT)/make/python.mk .PHONY: all all: firmware_all @@ -151,4 +152,4 @@ guruguru: .PHONY: generate_compile_db generate_compile_db: - @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) generate_compile_db \ No newline at end of file + @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) generate_compile_db diff --git a/make/python.mk b/make/python.mk new file mode 100644 index 000000000000..88a289da1eca --- /dev/null +++ b/make/python.mk @@ -0,0 +1,11 @@ +TOOLCHAIN_GDB_SYM := $(shell which arm-none-eabi-gdb) +ifneq ($(TOOLCHAIN_GDB_SYM),) + TOOLCHAIN_GDB := $(shell readlink -f -- $(TOOLCHAIN_GDB_SYM)) + TOOLCHAIN_DIR := $(shell dirname -- $(TOOLCHAIN_GDB)) + FLIPPER_PY_REL_DIR := $(TOOLCHAIN_DIR)/../python/bin + FLIPPER_PY_DIR := $(shell test -d $(FLIPPER_PY_REL_DIR) && cd $(FLIPPER_PY_REL_DIR) && pwd) +endif +ifneq ($(FLIPPER_PY_DIR),) + PATH := $(FLIPPER_PY_DIR):$(PATH) + export PATH +endif diff --git a/scripts/python3.sh b/scripts/python3.sh deleted file mode 100755 index bdb73bc28ab2..000000000000 --- a/scripts/python3.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -# function return values -FALSE=1 -TRUE=0 - -is_flipper_toolchain_installed() -{ - TOOLCHAIN_GDB="$(which arm-none-eabi-gdb-py)" - if test -z "$TOOLCHAIN_GDB"; then - return "$FALSE"; - fi - TOOLCHAIN_DIR="$(/usr/bin/dirname -- "$(readlink -f -- "$TOOLCHAIN_GDB")")"; - FLIPPER_PY_DIR="$(cd "$TOOLCHAIN_DIR/../python/bin/" && pwd)"; - if ! test -d "$FLIPPER_PY_DIR"; then - return "$FALSE"; - fi - if ! test -f "$FLIPPER_PY_DIR/python3"; then - return "$FALSE"; - fi - return "$TRUE"; -} - -py3_host() -{ - /usr/bin/env python3 "$@" -} - -py3_flipper() -{ - "$FLIPPER_PY_DIR/python3" "$@" -} - -if is_flipper_toolchain_installed; then - py3_flipper "$@"; -else - py3_host "$@"; -fi From c98511ceda83e360e2f7515056fd06cb9c823119 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 3 Jun 2022 19:13:59 +0400 Subject: [PATCH 015/184] Assets as module --- assets/SConscript | 16 ++++++++++++++++ firmware.scons | 7 +++++-- sconscfg/environ.scons | 37 ++++++++++++++++++++++++++----------- 3 files changed, 47 insertions(+), 13 deletions(-) create mode 100644 assets/SConscript diff --git a/assets/SConscript b/assets/SConscript new file mode 100644 index 000000000000..14c81d36c048 --- /dev/null +++ b/assets/SConscript @@ -0,0 +1,16 @@ +Import("env", "lib_flags") + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +# libenv.Append( +# CPPPATH=[ +# "#/assets/compiled", +# ], +# ) + +sources = Glob("compiled/*.c", source=True) + +lib = libenv.Library("assets", sources) +libenv.Install("#/${BUILD_DIR}/lib", lib) +Return("lib") diff --git a/firmware.scons b/firmware.scons index f77d91af4215..6b76eb9f4495 100644 --- a/firmware.scons +++ b/firmware.scons @@ -31,6 +31,7 @@ depends = env.BuildModules( [ "#/lib", "#/firmware", + "#/assets", ], ) @@ -97,7 +98,7 @@ sources = fwenv.GlobRecursive("*.c*", "applications") sources += Glob("assets/compiled/*.c*", source=True) -# print(fwenv.Dump()) +print(fwenv.Dump()) cdb = fwenv.CompilationDatabase("compile_database.json") Alias("cdb", cdb) @@ -147,6 +148,7 @@ fwenv.Append( "misc", "infrared", "appframe", + "assets", ], ) @@ -158,7 +160,8 @@ firmware_elf = fwenv.Program("${FIRMWARE_BUILD_CFG}", sources) # # "${PYTHON3} scripts/version.py generate -o lib/toolbox/version.inc.h --dir .", # ), # ) -Requires(firmware_elf, depends) +# Requires(firmware_elf, depends) +Depends(firmware_elf, depends) fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 09a2b96906df..7737ba89c477 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -19,11 +19,6 @@ vars.Add( env = Environment( variables=vars, tools=["as", "gcc", "g++", "ar", "gnulink", "python", "compilation_db"], - # CC="arm-none-eabi-gcc", - # CXX="arm-none-eabi-g++", - # LINK="arm-none-eabi-g++", - # CCFLAGS=[], - # LINKFLAGS=[], OBJCOPY="objcopy", PYTHON3="python3", TEMPFILE=TempFileMunge, @@ -69,10 +64,7 @@ for binary in [ "CC", "CXX", # "LINK", - # "RANLIB", "OBJCOPY", - # "OBJDUMP", - # "OBJSYMBOLS", ]: env[binary] = TOOLCHAIN_PREFIX + env[binary] @@ -99,10 +91,33 @@ env.GlobRecursive = GlobRecursive def check_exists(path): - # print("checking", File(path).abspath) + print("checking", File(path).abspath) return os.path.exists(File(path).abspath) +def build_module1(env, module): + print("module") + module_sconscript = f"{module}/SConscript" + if not check_exists(module_sconscript): + module_sconscript = f"{module}.scons" + if not check_exists(module_sconscript): + print(f"Cannot build module {module}: scons file not found") + Exit(2) + + # # module_sconscript = os.path.join(module, "SConscript") + # print("check for ", module_sconscript) + # if not os.path.exists(module_sconscript): + # module_sconscript = f"{module}.scons" + + print("sub-building", module_sconscript) + return env.SConscript( + module_sconscript, + # variant_dir="obj", + # variant_dir=env["BUILD_DIR"]+"/"+module, + duplicate=0, + ) + + def build_module(env, module): print("module") module_sconscript = f"{module}/SConscript" @@ -120,8 +135,8 @@ def build_module(env, module): print("sub-building", module_sconscript) return env.SConscript( module_sconscript, - # variant_dir=module + "/obj", - # variant_dir=env["BUILD_DIR"], + # variant_dir="obj", + # variant_dir=env["BUILD_DIR"]+"/"+module, duplicate=0, ) From ffaedc3b94df9d8fd7f2b46a13ff9c2049b68c48 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 03:20:55 +0400 Subject: [PATCH 016/184] functional out-of-tree build --- SConstruct | 13 +++++++--- assets/SConscript | 2 +- firmware.scons | 14 +++++------ firmware/SConscript | 2 +- lib/SConscript | 1 + lib/ST25RFAL002/SConscript | 2 +- lib/STM32CubeWB.scons | 2 +- lib/appframe.scons | 2 +- lib/drivers/SConscript | 2 +- lib/fatfs/SConscript | 2 +- lib/flipper_format/SConscript | 2 +- lib/freertos.scons | 2 +- lib/infrared/SConscript | 2 +- lib/libusb_stm32.scons | 2 +- lib/littlefs.scons | 2 +- lib/microtar.scons | 19 +++++++++++++++ lib/misc.scons | 2 +- lib/subghz/SConscript | 2 +- lib/toolbox/SConscript | 2 +- sconscfg/environ.scons | 45 +++++++---------------------------- 20 files changed, 60 insertions(+), 62 deletions(-) create mode 100644 lib/microtar.scons diff --git a/SConstruct b/SConstruct index ea146fab4450..6a1e30b7f2fa 100644 --- a/SConstruct +++ b/SConstruct @@ -1,15 +1,22 @@ +import os + SConscript("sconscfg/environ.scons") SConscript("sconscfg/cc.scons") SConscript("sconscfg/git.scons") SConscript("sconscfg/builders.scons") Import("env") + # Progress(["-\r", "\\\r", "|\r", "/\r"], interval=5) # variant_dir_name = f"build/f{env.subst('$FLIPPER_TARGET')}-{env.subst('$FIRMWARE_BUILD_CFG')}" -variant_dir_name = "build/fw" + +root_path = Dir(".").abspath +env["ROOT_DIR"] = root_path +build_path = os.path.join(root_path, "build", "fw") +env["BUILD_DIR"] = build_path + SConscript( "firmware.scons", - variant_dir=variant_dir_name, - exports="variant_dir_name", + variant_dir=build_path, duplicate=0, ) diff --git a/assets/SConscript b/assets/SConscript index 14c81d36c048..a961c39a2a9e 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -12,5 +12,5 @@ libenv.MergeFlags(lib_flags) sources = Glob("compiled/*.c", source=True) lib = libenv.Library("assets", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/firmware.scons b/firmware.scons index 6b76eb9f4495..4333b7e6d4d6 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,13 +1,13 @@ -Import("env", "variant_dir_name") +Import("env") env.Append( FLIPPER_TARGET="7", - BUILD_DIR=variant_dir_name, + LIB_DIST_DIR="${BUILD_DIR}/lib", ) env.Append( LIBPATH=[ - "#/${BUILD_DIR}/lib", + "${LIB_DIST_DIR}", ], CPPDEFINES=[ ("TARGET", "${FLIPPER_TARGET}"), @@ -29,9 +29,9 @@ env.Append( depends = env.BuildModules( env, [ - "#/lib", - "#/firmware", - "#/assets", + "lib", + "firmware", + "assets", ], ) @@ -95,7 +95,6 @@ else: sources = fwenv.GlobRecursive("*.c*", "applications") -sources += Glob("assets/compiled/*.c*", source=True) print(fwenv.Dump()) @@ -142,6 +141,7 @@ fwenv.Append( "littlefs", "subghz", "toolbox", + "microtar", "usb_stm32", "ST25RFAL002", "flipperformat", diff --git a/firmware/SConscript b/firmware/SConscript index a38bb8dd90a5..131a3f698aa0 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -14,5 +14,5 @@ sources += libenv.GlobRecursive("*.c", ".") sources += ["targets/f${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] lib = libenv.Library("flipper${FLIPPER_TARGET}", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/SConscript b/lib/SConscript index 6d4838230a4a..6ee918a1c764 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -43,6 +43,7 @@ libs = env.BuildModules( [ "STM32CubeWB", "freertos", + "microtar", "toolbox", "ST25RFAL002", "libusb_stm32", diff --git a/lib/ST25RFAL002/SConscript b/lib/ST25RFAL002/SConscript index 7bab73717f3c..f28386ec96f3 100644 --- a/lib/ST25RFAL002/SConscript +++ b/lib/ST25RFAL002/SConscript @@ -16,5 +16,5 @@ libenv.MergeFlags(lib_flags) sources = libenv.GlobRecursive("*.c", ".") lib = libenv.StaticLibrary("ST25RFAL002", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons index 1b73b6b7cd73..09d06a2692ba 100644 --- a/lib/STM32CubeWB.scons +++ b/lib/STM32CubeWB.scons @@ -53,5 +53,5 @@ sources += [ ] lib = libenv.StaticLibrary("STM32CubeWB", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/appframe.scons b/lib/appframe.scons index 3d2335ad654c..e9576bb6a041 100644 --- a/lib/appframe.scons +++ b/lib/appframe.scons @@ -26,5 +26,5 @@ for recurse_dir in recurse_dirs: sources += libenv.GlobRecursive("*.c*", recurse_dir) lib = libenv.StaticLibrary("appframe", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript index fc65f0423417..12450163f3bd 100644 --- a/lib/drivers/SConscript +++ b/lib/drivers/SConscript @@ -14,5 +14,5 @@ libenv.MergeFlags(lib_flags) sources = Glob("*.c", source=True) # libenv.GlobRecursive("*.c", ".") lib = libenv.StaticLibrary("hwdrivers", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/fatfs/SConscript b/lib/fatfs/SConscript index f3ee24e09b50..b0fb559ea11a 100644 --- a/lib/fatfs/SConscript +++ b/lib/fatfs/SConscript @@ -8,5 +8,5 @@ sources = Glob("*.c", source=True) sources += ["option/unicode.c"] lib = libenv.StaticLibrary("fatfs", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript index 76a7e11bad49..ae27b4af0aba 100644 --- a/lib/flipper_format/SConscript +++ b/lib/flipper_format/SConscript @@ -14,5 +14,5 @@ libenv.MergeFlags(lib_flags) sources = libenv.GlobRecursive("*.c", ".") lib = libenv.StaticLibrary("flipperformat", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/freertos.scons b/lib/freertos.scons index 1ca0eee33b03..1b28d72c474a 100644 --- a/lib/freertos.scons +++ b/lib/freertos.scons @@ -23,5 +23,5 @@ sources += [ ] lib = libenv.StaticLibrary("freertos", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/infrared/SConscript b/lib/infrared/SConscript index b0ddde6cb513..9200638f6f94 100644 --- a/lib/infrared/SConscript +++ b/lib/infrared/SConscript @@ -15,5 +15,5 @@ libenv.MergeFlags(lib_flags) sources = libenv.GlobRecursive("*.c", ".") lib = libenv.StaticLibrary("infrared", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/libusb_stm32.scons b/lib/libusb_stm32.scons index 32c04dede8eb..8f92e17f6db2 100644 --- a/lib/libusb_stm32.scons +++ b/lib/libusb_stm32.scons @@ -19,5 +19,5 @@ sources = [ ] lib = libenv.StaticLibrary("usb_stm32", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/littlefs.scons b/lib/littlefs.scons index 4ecb34933a18..8b563064eda9 100644 --- a/lib/littlefs.scons +++ b/lib/littlefs.scons @@ -16,5 +16,5 @@ libenv.MergeFlags(lib_flags) sources = Glob("littlefs/*.c", source=True) lib = libenv.StaticLibrary("littlefs", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/microtar.scons b/lib/microtar.scons new file mode 100644 index 000000000000..83bfa548d5f5 --- /dev/null +++ b/lib/microtar.scons @@ -0,0 +1,19 @@ +Import("env", "lib_flags") + +env.Append( + CPPPATH=[ + "#/lib/microtar/src", + ], + CPPDEFINES=[], +) + + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) +# TODO: consider adding optimization flags for microtar here + +sources = libenv.GlobRecursive("*.c", "microtar/src") + +lib = libenv.StaticLibrary("microtar", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/misc.scons b/lib/misc.scons index 85ac0b71c41c..7267112294bc 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -43,5 +43,5 @@ for lib in libs_plain: sources += Glob(lib + "/*.c*", source=True) lib = libenv.StaticLibrary("misc", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 5f68e75e3cd9..81502c5f3abb 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -13,5 +13,5 @@ libenv.MergeFlags(lib_flags) sources = libenv.GlobRecursive("*.c*", ".") lib = libenv.StaticLibrary("subghz", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index f0d5e62e7699..bb9afb358a94 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -17,5 +17,5 @@ sources = libenv.GlobRecursive("*.c", ".") sources += libenv.GlobRecursive("*.c", "../microtar/src") lib = libenv.StaticLibrary("toolbox", sources) -libenv.Install("#/${BUILD_DIR}/lib", lib) +libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 7737ba89c477..20b64e0c98b4 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -95,54 +95,25 @@ def check_exists(path): return os.path.exists(File(path).abspath) -def build_module1(env, module): - print("module") - module_sconscript = f"{module}/SConscript" - if not check_exists(module_sconscript): - module_sconscript = f"{module}.scons" - if not check_exists(module_sconscript): - print(f"Cannot build module {module}: scons file not found") - Exit(2) - - # # module_sconscript = os.path.join(module, "SConscript") - # print("check for ", module_sconscript) - # if not os.path.exists(module_sconscript): - # module_sconscript = f"{module}.scons" - - print("sub-building", module_sconscript) - return env.SConscript( - module_sconscript, - # variant_dir="obj", - # variant_dir=env["BUILD_DIR"]+"/"+module, - duplicate=0, - ) - - def build_module(env, module): - print("module") - module_sconscript = f"{module}/SConscript" - if not check_exists(module_sconscript): - module_sconscript = f"{module}.scons" - if not check_exists(module_sconscript): + # print("cwd", os.getcwd()) + # print(type(Dir(".").srcdir), dir(Dir(".").srcdir)) + src_dir = str(Dir(".").srcdir or os.getcwd()) + module_sconscript = os.path.join(src_dir, module, "SConscript") + if not os.path.exists(module_sconscript): + module_sconscript = os.path.join(src_dir, f"{module}.scons") + if not os.path.exists(module_sconscript): print(f"Cannot build module {module}: scons file not found") Exit(2) - # # module_sconscript = os.path.join(module, "SConscript") - # print("check for ", module_sconscript) - # if not os.path.exists(module_sconscript): - # module_sconscript = f"{module}.scons" - - print("sub-building", module_sconscript) return env.SConscript( module_sconscript, - # variant_dir="obj", - # variant_dir=env["BUILD_DIR"]+"/"+module, + variant_dir=env["BUILD_DIR"] + "/" + module, duplicate=0, ) def BuildModules(env, modules): - print("build list", modules) result = [] for module in modules: build_res = build_module(env, module) From a59c7af118fc89a70b76e9def69be6b36036d0e0 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 03:59:01 +0400 Subject: [PATCH 017/184] Core as a lib --- core/SConscript | 16 ++++++++++++++++ firmware.scons | 2 ++ firmware/SConscript | 3 +-- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 core/SConscript diff --git a/core/SConscript b/core/SConscript new file mode 100644 index 000000000000..21f2e8a3fa0e --- /dev/null +++ b/core/SConscript @@ -0,0 +1,16 @@ +Import("env", "lib_flags") + +libenv = env.Clone() +libenv.MergeFlags(lib_flags) + +libenv.Append( + CPPPATH=[ + "#/core", + ], +) + +sources = libenv.GlobRecursive("*.c", ".") + +lib = libenv.Library("core", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/firmware.scons b/firmware.scons index 4333b7e6d4d6..eaa4fdb7be92 100644 --- a/firmware.scons +++ b/firmware.scons @@ -32,6 +32,7 @@ depends = env.BuildModules( "lib", "firmware", "assets", + "core", ], ) @@ -134,6 +135,7 @@ fwenv.Append( # ], LIBS=[ "flipper${FLIPPER_TARGET}", + "core", "freertos", "STM32CubeWB", "hwdrivers", diff --git a/firmware/SConscript b/firmware/SConscript index 131a3f698aa0..c458358187ae 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -9,8 +9,7 @@ libenv.Append( ], ) -sources = libenv.GlobRecursive("*.c", "#/core") -sources += libenv.GlobRecursive("*.c", ".") +sources = libenv.GlobRecursive("*.c", ".") sources += ["targets/f${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] lib = libenv.Library("flipper${FLIPPER_TARGET}", sources) From ecce4956a947be536260e20871594e553dbf8c09 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 14:04:04 +0400 Subject: [PATCH 018/184] Fixed version.inc.h generation on build --- core/SConscript | 2 +- firmware.scons | 39 ++++++--------------------------------- scripts/version.py | 3 --- 3 files changed, 7 insertions(+), 37 deletions(-) diff --git a/core/SConscript b/core/SConscript index 21f2e8a3fa0e..2dc557a70046 100644 --- a/core/SConscript +++ b/core/SConscript @@ -5,7 +5,7 @@ libenv.MergeFlags(lib_flags) libenv.Append( CPPPATH=[ - "#/core", + # "#/core", ], ) diff --git a/firmware.scons b/firmware.scons index eaa4fdb7be92..f055e8c4eda3 100644 --- a/firmware.scons +++ b/firmware.scons @@ -106,33 +106,15 @@ Alias("cdb", cdb) build_version = fwenv.Command( "#lib/toolbox/version.inc.h", [], - "${PYTHON3} scripts/version.py generate -o ${TARGET} --dir .", + "${PYTHON3} scripts/version.py generate -o ${TARGET} --dir ${ROOT_DIR}", ) -# fwenv.AlwaysBuild(build_version) - -build_version_noarg = fwenv.Command( - [], - [], - "${PYTHON3} scripts/version .py generate -o lib/toolbox/version.inc.h --dir .", -) -fwenv.AlwaysBuild(build_version_noarg) - - -def version_action(target, source, fwenv): - """ - Generate the version file with the current version in it - """ - contents = version_build_template % (fwenv["VERSION"].toString()) - fd = open(target[0].path, "w") - fd.write(contents) - fd.close() - return 0 +fwenv.Precious(build_version) +fwenv.AlwaysBuild(build_version) -fwenv.Append( - # LIBPATH=[ - # "#/lib", - # ], +firmware_elf = fwenv.Program( + "${FIRMWARE_BUILD_CFG}", + sources, LIBS=[ "flipper${FLIPPER_TARGET}", "core", @@ -154,15 +136,6 @@ fwenv.Append( ], ) -firmware_elf = fwenv.Program("${FIRMWARE_BUILD_CFG}", sources) -# fwenv.AddPreAction( -# firmware_elf, -# Action( -# build_version_noarg -# # "${PYTHON3} scripts/version.py generate -o lib/toolbox/version.inc.h --dir .", -# ), -# ) -# Requires(firmware_elf, depends) Depends(firmware_elf, depends) diff --git a/scripts/version.py b/scripts/version.py index 4cdcf68a98aa..0ea9276b2e5b 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -72,9 +72,6 @@ def generate(self): current_version_info = None try: - print(f"cwd: '{os.getcwd()}'") - print(f"path: '{self.args.output}'") - os.system("ls lib/toolbox/version*") with open(self.args.output, "r") as file: current_version_info = file.read() except EnvironmentError as e: From d7c24b079fb4fc77acc338ab667818ecca6a13c2 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 14:58:04 +0400 Subject: [PATCH 019/184] Smarter build dir naming --- SConstruct | 20 ++++++++++++++++++-- firmware.scons | 13 ++++++------- firmware/SConscript | 4 ++-- sconscfg/builders.scons | 2 +- sconscfg/environ.scons | 10 ++++++++++ sconscfg/firmwareopts.scons | 4 ---- 6 files changed, 37 insertions(+), 16 deletions(-) diff --git a/SConstruct b/SConstruct index 6a1e30b7f2fa..1b1c2db2389b 100644 --- a/SConstruct +++ b/SConstruct @@ -7,12 +7,28 @@ SConscript("sconscfg/builders.scons") Import("env") +if env["RAM_EXEC"]: + env.Append( + FIRMWARE_BUILD_CFG="updater", + ) +else: + env.Append( + FIRMWARE_BUILD_CFG="firmware", + ) + # Progress(["-\r", "\\\r", "|\r", "/\r"], interval=5) -# variant_dir_name = f"build/f{env.subst('$FLIPPER_TARGET')}-{env.subst('$FIRMWARE_BUILD_CFG')}" +variant_dir_name = f"f{env.subst('$TARGET_HW')}-{env.subst('$FIRMWARE_BUILD_CFG')}" +suffix = "" +if env["DEBUG"]: + suffix += "D" +if env["COMPACT"]: + suffix += "C" +if suffix: + variant_dir_name += "_" + suffix root_path = Dir(".").abspath env["ROOT_DIR"] = root_path -build_path = os.path.join(root_path, "build", "fw") +build_path = os.path.join(root_path, "build", variant_dir_name) env["BUILD_DIR"] = build_path SConscript( diff --git a/firmware.scons b/firmware.scons index f055e8c4eda3..0c8c89396e2c 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,7 +1,6 @@ Import("env") env.Append( - FLIPPER_TARGET="7", LIB_DIST_DIR="${BUILD_DIR}/lib", ) @@ -10,7 +9,7 @@ env.Append( "${LIB_DIST_DIR}", ], CPPDEFINES=[ - ("TARGET", "${FLIPPER_TARGET}"), + ("TARGET", "${TARGET_HW}"), ], ) @@ -18,10 +17,10 @@ env.Append( CPPPATH=[ "#/core", "#/applications", - "#/firmware/targets/f${FLIPPER_TARGET}/ble_glue", - "#/firmware/targets/f${FLIPPER_TARGET}/fatfs", - "#/firmware/targets/f${FLIPPER_TARGET}/furi_hal", - "#/firmware/targets/f${FLIPPER_TARGET}/Inc", + "#/firmware/targets/f${TARGET_HW}/ble_glue", + "#/firmware/targets/f${TARGET_HW}/fatfs", + "#/firmware/targets/f${TARGET_HW}/furi_hal", + "#/firmware/targets/f${TARGET_HW}/Inc", "#/firmware/targets/furi_hal_include", ] ) @@ -116,7 +115,7 @@ firmware_elf = fwenv.Program( "${FIRMWARE_BUILD_CFG}", sources, LIBS=[ - "flipper${FLIPPER_TARGET}", + "flipper${TARGET_HW}", "core", "freertos", "STM32CubeWB", diff --git a/firmware/SConscript b/firmware/SConscript index c458358187ae..dcba3c93513d 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -10,8 +10,8 @@ libenv.Append( ) sources = libenv.GlobRecursive("*.c", ".") -sources += ["targets/f${FLIPPER_TARGET}/startup_stm32wb55xx_cm4.s"] +sources += ["targets/f${TARGET_HW}/startup_stm32wb55xx_cm4.s"] -lib = libenv.Library("flipper${FLIPPER_TARGET}", sources) +lib = libenv.Library("flipper${TARGET_HW}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons index 7250786a5bf7..8fb5607e9d2c 100644 --- a/sconscfg/builders.scons +++ b/sconscfg/builders.scons @@ -11,7 +11,7 @@ def generate_bin(source, target, env, for_signature): def generate_dfu(source, target, env, for_signature): return ( - '${PYTHON3} ./scripts/bin2dfu.py -i "%s" -o "%s" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${FLIPPER_TARGET}"' + '${PYTHON3} ./scripts/bin2dfu.py -i "%s" -o "%s" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"' % (source[0], target[0]) ) diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 20b64e0c98b4..f5043fd76b72 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -12,6 +12,16 @@ TOOLCHAIN_PREFIX = "arm-none-eabi-" vars = Variables(None, ARGUMENTS) vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) vars.Add(BoolVariable("COMPACT", help="Optimize for size", default=0)) +vars.Add( + EnumVariable( + "TARGET_HW", + help="Hardware target", + default="7", + allowed_values=[ + "7", + ], + ) +) vars.Add( BoolVariable("RAM_EXEC", help="Build updater image for RAM exection", default=0) ) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 8189c9ecdf16..807c0d245fec 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -1,9 +1,5 @@ Import("fwenv") -# fwenv.Append( -# FLIPPER_TARGET="7", -# ) - # vars = Variables(None, ARGUMENTS) # vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) # vars.Add(BoolVariable("COMPACT", help="Otimize for size", default=0)) From 11ee83357ec43d75086cc76cf0d07d3c0c926218 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 15:24:06 +0400 Subject: [PATCH 020/184] Fixed updater builds --- .gitignore | 8 ++------ sconscfg/firmwareopts.scons | 4 +--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 8b505f6f3093..e37db891908e 100644 --- a/.gitignore +++ b/.gitignore @@ -42,9 +42,5 @@ dist # SCons .sconsign.dblite - -# Build objects -*.d -*.o -*.su -*.a +# SCons build dir +build/ \ No newline at end of file diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 807c0d245fec..9cbf13c79253 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -45,7 +45,7 @@ else: ], ) -if fwenv["RAM_EXEC"]: +if fwenv["FIRMWARE_BUILD_CFG"] == "updater": fwenv.Append( CPPDEFINES=[ "FURI_RAM_EXEC", @@ -56,7 +56,6 @@ if fwenv["RAM_EXEC"]: LINKFLAGS=[ "-Tfirmware/targets/f7/stm32wb55xx_ram_fw.ld", ], - FIRMWARE_BUILD_CFG="updater", ) else: fwenv.Append( @@ -64,5 +63,4 @@ else: LINKFLAGS=[ "-Tfirmware/targets/f7/stm32wb55xx_flash.ld", ], - FIRMWARE_BUILD_CFG="firmware", ) From 0426f844e7584aa66b267fdb7ed7fca5c738914b Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 15:46:47 +0400 Subject: [PATCH 021/184] Fixed hardcoded linker script path --- sconscfg/firmwareopts.scons | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 9cbf13c79253..f1840a1943bc 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -54,13 +54,13 @@ if fwenv["FIRMWARE_BUILD_CFG"] == "updater": ], IMAGE_BASE_ADDRESS="0x20000000", LINKFLAGS=[ - "-Tfirmware/targets/f7/stm32wb55xx_ram_fw.ld", + "-Tfirmware/targets/f${TARGET_HW}/stm32wb55xx_ram_fw.ld", ], ) else: fwenv.Append( IMAGE_BASE_ADDRESS="0x8000000", LINKFLAGS=[ - "-Tfirmware/targets/f7/stm32wb55xx_flash.ld", + "-Tfirmware/targets/f${TARGET_HW}/stm32wb55xx_flash.ld", ], ) From e586b084dca40612f0e5bcd46ce84e0e70754e82 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 17:36:56 +0400 Subject: [PATCH 022/184] Using ranlib from toolchain --- sconscfg/environ.scons | 1 + 1 file changed, 1 insertion(+) diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index f5043fd76b72..485c53c8c140 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -75,6 +75,7 @@ for binary in [ "CXX", # "LINK", "OBJCOPY", + "RANLIB", ]: env[binary] = TOOLCHAIN_PREFIX + env[binary] From f64f20d3f3d3e7918eba76ce41d7506836e353bb Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 18:11:51 +0400 Subject: [PATCH 023/184] Removed scons from root --- .gitmodules | 4 ---- scons | 1 - 2 files changed, 5 deletions(-) delete mode 160000 scons diff --git a/.gitmodules b/.gitmodules index ad15a5c4e736..c4649fdca92c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,7 +22,3 @@ [submodule "lib/microtar"] path = lib/microtar url = https://github.com/amachronic/microtar.git -[submodule "scons"] - path = scons - url = https://github.com/SCons/scons.git - diff --git a/scons b/scons deleted file mode 160000 index c2d1f09f615a..000000000000 --- a/scons +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c2d1f09f615a9ef3fb5497a7e8e5ee2c900d21a7 From d9c8762e496c31f0a4db946cb92562566534468c Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 18:13:45 +0400 Subject: [PATCH 024/184] Added scons to /lib --- .gitmodules | 3 +++ lib/scons | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/scons diff --git a/.gitmodules b/.gitmodules index c4649fdca92c..5846b70595e6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "lib/microtar"] path = lib/microtar url = https://github.com/amachronic/microtar.git +[submodule "lib/scons"] + path = lib/scons + url = https://github.com/SCons/scons.git diff --git a/lib/scons b/lib/scons new file mode 160000 index 000000000000..c2d1f09f615a --- /dev/null +++ b/lib/scons @@ -0,0 +1 @@ +Subproject commit c2d1f09f615a9ef3fb5497a7e8e5ee2c900d21a7 From 23c5ed8331ce86c1987c8cf7987cd9f4ca42db54 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 18:42:19 +0400 Subject: [PATCH 025/184] Formatting & cleanup --- sconscfg/environ.scons | 16 ++++++++++------ sconscfg/firmwareopts.scons | 11 +---------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 485c53c8c140..3b76c98c414f 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -7,7 +7,6 @@ import sys import re import multiprocessing -TOOLCHAIN_PREFIX = "arm-none-eabi-" vars = Variables(None, ARGUMENTS) vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) @@ -26,6 +25,7 @@ vars.Add( BoolVariable("RAM_EXEC", help="Build updater image for RAM exection", default=0) ) + env = Environment( variables=vars, tools=["as", "gcc", "g++", "ar", "gnulink", "python", "compilation_db"], @@ -46,6 +46,7 @@ if env["PLATFORM"] == "win32": Help(vars.GenerateHelpText(env)) + # Default value for -j SetOption("num_jobs", multiprocessing.cpu_count()) @@ -67,7 +68,11 @@ def tempfile_arg_esc_func(arg): env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func + # Set up cross-compile tools + +TOOLCHAIN_PREFIX = "arm-none-eabi-" + for binary in [ "AR", "AS", @@ -79,8 +84,12 @@ for binary in [ ]: env[binary] = TOOLCHAIN_PREFIX + env[binary] + # Commandline length limit hack + env["LINKCOM"] = '${TEMPFILE("' + env["LINKCOM"] + '","$LINKCOMSTR")}' +env["ARCOM"] = '${TEMPFILE("' + env["ARCOM"] + '","$ARCOMSTR")}' + # Recursive glob def GlobRecursive(pattern, node=".", exclude=None): @@ -101,11 +110,6 @@ def GlobRecursive(pattern, node=".", exclude=None): env.GlobRecursive = GlobRecursive -def check_exists(path): - print("checking", File(path).abspath) - return os.path.exists(File(path).abspath) - - def build_module(env, module): # print("cwd", os.getcwd()) # print(type(Dir(".").srcdir), dir(Dir(".").srcdir)) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index f1840a1943bc..14fd4e0e98b0 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -1,15 +1,5 @@ Import("fwenv") -# vars = Variables(None, ARGUMENTS) -# vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) -# vars.Add(BoolVariable("COMPACT", help="Otimize for size", default=0)) -# vars.Add( -# BoolVariable("RAM_EXEC", help="Build updater image for RAM exection", default=0) -# ) -# fwenv.Append(variables=vars) -# Help(vars.GenerateHelpText(env)) - -# print(fwenv.Dump()) if fwenv["DEBUG"]: fwenv.Append( @@ -45,6 +35,7 @@ else: ], ) + if fwenv["FIRMWARE_BUILD_CFG"] == "updater": fwenv.Append( CPPDEFINES=[ From 6cd4facb9340ee2591ce7576a9d1882fd5c620f2 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 4 Jun 2022 19:30:30 +0400 Subject: [PATCH 026/184] Using AddMethod for methods --- firmware.scons | 1 - lib/SConscript | 1 - sconscfg/environ.scons | 16 ++++++++-------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/firmware.scons b/firmware.scons index 0c8c89396e2c..13ce41c0d047 100644 --- a/firmware.scons +++ b/firmware.scons @@ -26,7 +26,6 @@ env.Append( ) depends = env.BuildModules( - env, [ "lib", "firmware", diff --git a/lib/SConscript b/lib/SConscript index 6ee918a1c764..24c813f3e848 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -39,7 +39,6 @@ env.Append( libs = env.BuildModules( - env, [ "STM32CubeWB", "freertos", diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 3b76c98c414f..0e2985a816d6 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -92,12 +92,12 @@ env["ARCOM"] = '${TEMPFILE("' + env["ARCOM"] + '","$ARCOMSTR")}' # Recursive glob -def GlobRecursive(pattern, node=".", exclude=None): +def GlobRecursive(env, pattern, node=".", exclude=None): results = [] for f in Glob(str(node) + "/*", source=True, exclude=exclude): if type(f) is SCons.Node.FS.Dir: # print(f"recursing into {f}") - results += GlobRecursive(pattern, f, exclude) + results += env.GlobRecursive(pattern, f, exclude) current_node_str = str(node) + "/" results += Glob( current_node_str + pattern, @@ -107,10 +107,7 @@ def GlobRecursive(pattern, node=".", exclude=None): return results -env.GlobRecursive = GlobRecursive - - -def build_module(env, module): +def BuildModule(env, module): # print("cwd", os.getcwd()) # print(type(Dir(".").srcdir), dir(Dir(".").srcdir)) src_dir = str(Dir(".").srcdir or os.getcwd()) @@ -131,7 +128,7 @@ def build_module(env, module): def BuildModules(env, modules): result = [] for module in modules: - build_res = build_module(env, module) + build_res = env.BuildModule(module) # print("module ", module, build_res) if build_res is None: continue @@ -142,7 +139,10 @@ def BuildModules(env, modules): return result -env.BuildModules = BuildModules +env.AddMethod(GlobRecursive) +env.AddMethod(BuildModule) +env.AddMethod(BuildModules) + lib_flags = { "CCFLAGS": [ From df5723b14fd04d9ddbd09624fa13a1a357904a53 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 00:52:21 +0400 Subject: [PATCH 027/184] Enabled implicit_deps_unchanged by default - experimental --- .gitignore | 2 +- firmware.scons | 12 +++++++++--- lib/STM32CubeWB.scons | 1 - sconscfg/environ.scons | 16 ++++++++++++---- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index e37db891908e..83b69c277c39 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,4 @@ dist # SCons .sconsign.dblite # SCons build dir -build/ \ No newline at end of file +build/ diff --git a/firmware.scons b/firmware.scons index 13ce41c0d047..da1bb0da4e3c 100644 --- a/firmware.scons +++ b/firmware.scons @@ -96,10 +96,10 @@ else: sources = fwenv.GlobRecursive("*.c*", "applications") -print(fwenv.Dump()) -cdb = fwenv.CompilationDatabase("compile_database.json") -Alias("cdb", cdb) +# Debug +# print(fwenv.Dump()) +# Git Version management build_version = fwenv.Command( "#lib/toolbox/version.inc.h", @@ -110,6 +110,8 @@ fwenv.Precious(build_version) fwenv.AlwaysBuild(build_version) +# Full firmware definition + firmware_elf = fwenv.Program( "${FIRMWARE_BUILD_CFG}", sources, @@ -140,3 +142,7 @@ Depends(firmware_elf, depends) fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") + +# Compile DB generation +cdb = fwenv.CompilationDatabase("compile_database.json") +Alias("cdb", cdb) diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons index 09d06a2692ba..e0ea38775c2d 100644 --- a/lib/STM32CubeWB.scons +++ b/lib/STM32CubeWB.scons @@ -29,7 +29,6 @@ libenv.MergeFlags(lib_flags) sources = libenv.GlobRecursive( "*_ll_*.c", "STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/", exclude="*usb.c" ) - sources += Glob( "STM32CubeWB/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/*.c", source=True, diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 0e2985a816d6..9d1d61fc366a 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -39,9 +39,10 @@ env = Environment( "PATH": os.environ["PATH"], }, ) +# env.Decider("content-timestamp") if env["PLATFORM"] == "win32": - # On Windows, python 3 executable is usually just "python" + # On Windows, Python 3 executable is usually just "python" env["PYTHON3"] = env["PYTHON3"][:-1] Help(vars.GenerateHelpText(env)) @@ -51,6 +52,8 @@ Help(vars.GenerateHelpText(env)) SetOption("num_jobs", multiprocessing.cpu_count()) SetOption("implicit_cache", True) +SetOption("implicit_deps_unchanged", True) +SetOption("max_drift", 1) # Setting up temp file parameters @@ -60,7 +63,7 @@ WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") def tempfile_arg_esc_func(arg): arg = quote_spaces(arg) - if sys.platform != "win32": + if env["PLATFORM"] != "win32": return arg # GCC requires double Windows slashes, let's use UNIX separator return WINPATHSEP_RE.sub(r"/\1", arg) @@ -82,7 +85,8 @@ for binary in [ "OBJCOPY", "RANLIB", ]: - env[binary] = TOOLCHAIN_PREFIX + env[binary] + if binary in env: + env[binary] = TOOLCHAIN_PREFIX + env[binary] # Commandline length limit hack @@ -91,7 +95,9 @@ env["LINKCOM"] = '${TEMPFILE("' + env["LINKCOM"] + '","$LINKCOMSTR")}' env["ARCOM"] = '${TEMPFILE("' + env["ARCOM"] + '","$ARCOMSTR")}' -# Recursive glob +# Build env extensions + + def GlobRecursive(env, pattern, node=".", exclude=None): results = [] for f in Glob(str(node) + "/*", source=True, exclude=exclude): @@ -144,6 +150,8 @@ env.AddMethod(BuildModule) env.AddMethod(BuildModules) +# Specific flags for building libraries - always do optimized builds + lib_flags = { "CCFLAGS": [ "-Os", From 3da23dd43e9e831d20a8b09aabda05799215d1a2 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 03:41:49 +0400 Subject: [PATCH 028/184] App manifests + manifest loader --- applications/about/application.fam | 9 +++ applications/accessor/application.fam | 9 +++ applications/archive/application.fam | 10 +++ applications/bad_usb/application.fam | 10 +++ applications/bt/application.fam | 41 ++++++++++ applications/cli/application.fam | 9 +++ applications/crypto/application.fam | 6 ++ applications/debug_tools/application.fam | 79 +++++++++++++++++++ applications/desktop/application.fam | 20 +++++ applications/dialogs/application.fam | 9 +++ applications/dolphin/application.fam | 20 +++++ applications/gpio/application.fam | 10 +++ applications/gui/application.fam | 9 +++ applications/ibutton/application.fam | 18 +++++ applications/infrared/application.fam | 18 +++++ applications/infrared_monitor/application.fam | 9 +++ applications/input/application.fam | 9 +++ applications/lfrfid/application.fam | 18 +++++ applications/lfrfid_debug/application.fam | 8 ++ applications/loader/application.fam | 9 +++ applications/music_player/application.fam | 17 ++++ applications/nfc/application.fam | 18 +++++ applications/notification/application.fam | 19 +++++ applications/power/application.fam | 29 +++++++ applications/rpc/application.fam | 9 +++ .../scened_app_example/application.fam | 9 +++ applications/snake_game/application.fam | 10 +++ applications/storage/application.fam | 18 +++++ applications/storage_settings/application.fam | 9 +++ applications/subghz/application.fam | 18 +++++ applications/system/application.fam | 9 +++ applications/u2f/application.fam | 10 +++ applications/unit_tests/application.fam | 17 ++++ applications/updater/application.fam | 21 +++++ sconscfg/firmwareopts.scons | 68 ++++++++++++++++ 35 files changed, 611 insertions(+) create mode 100644 applications/about/application.fam create mode 100644 applications/accessor/application.fam create mode 100644 applications/archive/application.fam create mode 100644 applications/bad_usb/application.fam create mode 100644 applications/bt/application.fam create mode 100644 applications/cli/application.fam create mode 100644 applications/crypto/application.fam create mode 100644 applications/debug_tools/application.fam create mode 100644 applications/desktop/application.fam create mode 100644 applications/dialogs/application.fam create mode 100644 applications/dolphin/application.fam create mode 100644 applications/gpio/application.fam create mode 100644 applications/gui/application.fam create mode 100644 applications/ibutton/application.fam create mode 100644 applications/infrared/application.fam create mode 100644 applications/infrared_monitor/application.fam create mode 100644 applications/input/application.fam create mode 100644 applications/lfrfid/application.fam create mode 100644 applications/lfrfid_debug/application.fam create mode 100644 applications/loader/application.fam create mode 100644 applications/music_player/application.fam create mode 100644 applications/nfc/application.fam create mode 100644 applications/notification/application.fam create mode 100644 applications/power/application.fam create mode 100644 applications/rpc/application.fam create mode 100644 applications/scened_app_example/application.fam create mode 100644 applications/snake_game/application.fam create mode 100644 applications/storage/application.fam create mode 100644 applications/storage_settings/application.fam create mode 100644 applications/subghz/application.fam create mode 100644 applications/system/application.fam create mode 100644 applications/u2f/application.fam create mode 100644 applications/unit_tests/application.fam create mode 100644 applications/updater/application.fam diff --git a/applications/about/application.fam b/applications/about/application.fam new file mode 100644 index 000000000000..a8173b59037c --- /dev/null +++ b/applications/about/application.fam @@ -0,0 +1,9 @@ +App( + appid="about", + name="About", + apptype=FlipperAppType.SETTINGS, + entry_point="about_settings_app", + cdefines=["APP_ABOUT"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/accessor/application.fam b/applications/accessor/application.fam new file mode 100644 index 000000000000..e242c44a193a --- /dev/null +++ b/applications/accessor/application.fam @@ -0,0 +1,9 @@ +App( + appid="accessor", + name="Accessor", + apptype=FlipperAppType.DEBUG, + entry_point="accessor_app", + cdefines=["APP_ACCESSOR"], + stack_size=4 * 1024, + order=0, +) diff --git a/applications/archive/application.fam b/applications/archive/application.fam new file mode 100644 index 000000000000..121d950dc38e --- /dev/null +++ b/applications/archive/application.fam @@ -0,0 +1,10 @@ +App( + appid="archive", + name="Archive", + apptype=FlipperAppType.ARCHIVE, + entry_point="archive_app", + cdefines=["APP_ARCHIVE"], + stack_size=4 * 1024, + icon="A_FileManager_14", + order=0, +) diff --git a/applications/bad_usb/application.fam b/applications/bad_usb/application.fam new file mode 100644 index 000000000000..c1cebfb4ba5b --- /dev/null +++ b/applications/bad_usb/application.fam @@ -0,0 +1,10 @@ +App( + appid="bad_usb", + name="Bad USB", + apptype=FlipperAppType.APP, + entry_point="bad_usb_app", + cdefines=["APP_BAD_USB"], + stack_size=2 * 1024, + icon="A_BadUsb_14", + order=0, +) diff --git a/applications/bt/application.fam b/applications/bt/application.fam new file mode 100644 index 000000000000..c8afe3ce3069 --- /dev/null +++ b/applications/bt/application.fam @@ -0,0 +1,41 @@ +App( + appid="bt_srv", + name="BtSrv", + apptype=FlipperAppType.SERVICE, + entry_point="bt_srv", + cdefines=["SRV_BT"], + provides=[ + "bt_start", + "bt_settings", + "bt_debug_app", + ], + stack_size=1 * 1024, + order=0, +) + +App( + appid="bt_start", + apptype=FlipperAppType.STARTUP, + entry_point="bt_on_system_start", + order=0, +) + +App( + appid="bt_settings", + name="Bluetooth", + apptype=FlipperAppType.SETTINGS, + entry_point="bt_settings_app", + stack_size=1 * 1024, + requires=["bt_srv"], + order=0, +) + +App( + appid="bt_debug_app", + name="Bluetooth Debug", + apptype=FlipperAppType.DEBUG, + entry_point="bt_debug_app", + stack_size=1 * 1024, + requires=["bt_srv"], + order=0, +) diff --git a/applications/cli/application.fam b/applications/cli/application.fam new file mode 100644 index 000000000000..fab9b4321e68 --- /dev/null +++ b/applications/cli/application.fam @@ -0,0 +1,9 @@ +App( + appid="cli", + name="CliSrv", + apptype=FlipperAppType.SERVICE, + entry_point="cli_srv", + cdefines=["SRV_CLI"], + stack_size=4 * 1024, + order=0, +) diff --git a/applications/crypto/application.fam b/applications/crypto/application.fam new file mode 100644 index 000000000000..7014f48cf77f --- /dev/null +++ b/applications/crypto/application.fam @@ -0,0 +1,6 @@ +App( + appid="crypto", + apptype=FlipperAppType.STARTUP, + entry_point="crypto_on_system_start", + order=0, +) diff --git a/applications/debug_tools/application.fam b/applications/debug_tools/application.fam new file mode 100644 index 000000000000..7335d9903634 --- /dev/null +++ b/applications/debug_tools/application.fam @@ -0,0 +1,79 @@ +App( + appid="blink_test", + name="Blink Test", + apptype=FlipperAppType.DEBUG, + entry_point="blink_test_app", + cdefines=["APP_BLINK"], + stack_size=1 * 1024, + order=0, +) + +App( + appid="vibro_test", + name="Vibro Test", + apptype=FlipperAppType.DEBUG, + entry_point="vibro_test_app", + cdefines=["APP_VIBRO_TEST"], + stack_size=1 * 1024, + order=0, +) + +App( + appid="keypad_test", + name="Keypad Test", + apptype=FlipperAppType.DEBUG, + entry_point="keypad_test_app", + cdefines=["APP_KEYPAD_TEST"], + stack_size=1 * 1024, + order=0, +) + +App( + appid="usb_test", + name="USB Test", + apptype=FlipperAppType.DEBUG, + entry_point="usb_test_app", + cdefines=["APP_USB_TEST"], + stack_size=1 * 1024, + order=0, +) + +App( + appid="usb_mouse", + name="USB Mouse Demo", + apptype=FlipperAppType.DEBUG, + entry_point="usb_mouse_app", + cdefines=["APP_USB_MOUSE"], + stack_size=1 * 1024, + order=0, +) + +App( + appid="uart_echo", + name="UART Echo", + apptype=FlipperAppType.DEBUG, + entry_point="uart_echo_app", + cdefines=["APP_UART_ECHO"], + stack_size=2 * 1024, + order=0, +) + +App( + appid="text_box_test", + name="Text Box Test", + apptype=FlipperAppType.DEBUG, + entry_point="text_box_test_app", + cdefines=["APP_TEXT_BOX_TEST"], + stack_size=1 * 1024, + order=0, +) + +App( + appid="display_test", + name="Display Test", + apptype=FlipperAppType.DEBUG, + entry_point="display_test_app", + cdefines=["APP_DISPLAY_TEST"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/desktop/application.fam b/applications/desktop/application.fam new file mode 100644 index 000000000000..8c69651d4719 --- /dev/null +++ b/applications/desktop/application.fam @@ -0,0 +1,20 @@ +App( + appid="desktop", + name="DesktopSrv", + apptype=FlipperAppType.SERVICE, + entry_point="desktop_srv", + cdefines=["SRV_DESKTOP"], + stack_size=2 * 1024, + conflicts=["updater"], + order=0, +) + +App( + appid="desktop_settings", + name="Desktop", + apptype=FlipperAppType.SETTINGS, + entry_point="desktop_settings_app", + requires=["desktop"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/dialogs/application.fam b/applications/dialogs/application.fam new file mode 100644 index 000000000000..12ca8fb1a2e2 --- /dev/null +++ b/applications/dialogs/application.fam @@ -0,0 +1,9 @@ +App( + appid="dialogs", + name="DialogsSrv", + apptype=FlipperAppType.SERVICE, + entry_point="dialogs_srv", + cdefines=["SRV_DIALOGS"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/dolphin/application.fam b/applications/dolphin/application.fam new file mode 100644 index 000000000000..88caaa0f159d --- /dev/null +++ b/applications/dolphin/application.fam @@ -0,0 +1,20 @@ +App( + appid="dolphin", + name="DolphinSrv", + apptype=FlipperAppType.SERVICE, + entry_point="dolphin_srv", + cdefines=["SRV_DOLPHIN"], + stack_size=1 * 1024, + order=0, +) + +App( + appid="passport", + name="Passport", + apptype=FlipperAppType.SETTINGS, + entry_point="passport_app", + cdefines=["APP_PASSPORT"], + requires=["dolphin"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/gpio/application.fam b/applications/gpio/application.fam new file mode 100644 index 000000000000..cb4b28f76e13 --- /dev/null +++ b/applications/gpio/application.fam @@ -0,0 +1,10 @@ +App( + appid="gpio", + name="GPIO", + apptype=FlipperAppType.APP, + entry_point="gpio_app", + cdefines=["APP_GPIO"], + stack_size=1 * 1024, + icon="A_GPIO_14", + order=0, +) diff --git a/applications/gui/application.fam b/applications/gui/application.fam new file mode 100644 index 000000000000..3e75e8d5322b --- /dev/null +++ b/applications/gui/application.fam @@ -0,0 +1,9 @@ +App( + appid="gui", + name="GuiSrv", + apptype=FlipperAppType.SERVICE, + entry_point="gui_srv", + cdefines=["SRV_GUI"], + stack_size=2 * 1024, + order=0, +) diff --git a/applications/ibutton/application.fam b/applications/ibutton/application.fam new file mode 100644 index 000000000000..6ab26829d643 --- /dev/null +++ b/applications/ibutton/application.fam @@ -0,0 +1,18 @@ +App( + appid="ibutton", + name="iButton", + apptype=FlipperAppType.APP, + entry_point="ibutton_app", + cdefines=["APP_IBUTTON"], + provides=["ibutton_start"], + icon="A_iButton_14", + stack_size=2 * 1024, + order=0, +) + +App( + appid="ibutton_start", + apptype=FlipperAppType.STARTUP, + entry_point="ibutton_on_system_start", + order=0, +) diff --git a/applications/infrared/application.fam b/applications/infrared/application.fam new file mode 100644 index 000000000000..29cf4156189a --- /dev/null +++ b/applications/infrared/application.fam @@ -0,0 +1,18 @@ +App( + appid="infrared", + name="Infrared", + apptype=FlipperAppType.APP, + entry_point="infrared_app", + cdefines=["APP_INFRARED"], + provides=["infrared_start"], + icon="A_Infrared_14", + stack_size=3 * 1024, + order=0, +) + +App( + appid="infrared_start", + apptype=FlipperAppType.STARTUP, + entry_point="infrared_on_system_start", + order=0, +) diff --git a/applications/infrared_monitor/application.fam b/applications/infrared_monitor/application.fam new file mode 100644 index 000000000000..759b6b9968d9 --- /dev/null +++ b/applications/infrared_monitor/application.fam @@ -0,0 +1,9 @@ +App( + appid="infrared_monitor", + name="Infrared Monitor", + apptype=FlipperAppType.DEBUG, + entry_point="infrared_monitor_app", + cdefines=["APP_INFRARED_MONITOR"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/input/application.fam b/applications/input/application.fam new file mode 100644 index 000000000000..d44886950509 --- /dev/null +++ b/applications/input/application.fam @@ -0,0 +1,9 @@ +App( + appid="input", + name="InputSrv", + apptype=FlipperAppType.SERVICE, + entry_point="input_srv", + cdefines=["SRV_INPUT"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/lfrfid/application.fam b/applications/lfrfid/application.fam new file mode 100644 index 000000000000..f9ae64c7a630 --- /dev/null +++ b/applications/lfrfid/application.fam @@ -0,0 +1,18 @@ +App( + appid="lfrfid", + name="125 kHz RFID", + apptype=FlipperAppType.APP, + entry_point="lfrfid_app", + cdefines=["APP_LF_RFID"], + provides=["lfrfid_start"], + icon="A_125khz_14", + stack_size=2 * 1024, + order=0, +) + +App( + appid="lfrfid_start", + apptype=FlipperAppType.STARTUP, + entry_point="lfrfid_on_system_start", + order=0, +) diff --git a/applications/lfrfid_debug/application.fam b/applications/lfrfid_debug/application.fam new file mode 100644 index 000000000000..155f517558e9 --- /dev/null +++ b/applications/lfrfid_debug/application.fam @@ -0,0 +1,8 @@ +App( + appid="lfrfid_debug", + name="LF-RFID Debug", + apptype=FlipperAppType.DEBUG, + entry_point="lfrfid_debug_app", + stack_size=1 * 1024, + order=0, +) diff --git a/applications/loader/application.fam b/applications/loader/application.fam new file mode 100644 index 000000000000..bddaa82ab07f --- /dev/null +++ b/applications/loader/application.fam @@ -0,0 +1,9 @@ +App( + appid="loader", + name="LoaderSrv", + apptype=FlipperAppType.SERVICE, + entry_point="loader_srv", + cdefines=["SRV_LOADER"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/music_player/application.fam b/applications/music_player/application.fam new file mode 100644 index 000000000000..765afdf06e3d --- /dev/null +++ b/applications/music_player/application.fam @@ -0,0 +1,17 @@ +App( + appid="music_player", + name="Music Player", + apptype=FlipperAppType.PLUGIN, + entry_point="music_player_app", + cdefines=["APP_MUSIC_PLAYER"], + provides=["music_player_start"], + stack_size=2 * 1024, + order=0, +) + +App( + appid="music_player_start", + apptype=FlipperAppType.STARTUP, + entry_point="music_player_on_system_start", + order=0, +) diff --git a/applications/nfc/application.fam b/applications/nfc/application.fam new file mode 100644 index 000000000000..4fc83c2a6d52 --- /dev/null +++ b/applications/nfc/application.fam @@ -0,0 +1,18 @@ +App( + appid="nfc", + name="NFC", + apptype=FlipperAppType.APP, + entry_point="nfc_app", + cdefines=["APP_NFC"], + provides=["nfc_start"], + icon="A_NFC_14", + stack_size=4 * 1024, + order=0, +) + +App( + appid="nfc_start", + apptype=FlipperAppType.STARTUP, + entry_point="nfc_on_system_start", + order=0, +) diff --git a/applications/notification/application.fam b/applications/notification/application.fam new file mode 100644 index 000000000000..9da741d5e4c4 --- /dev/null +++ b/applications/notification/application.fam @@ -0,0 +1,19 @@ +App( + appid="notification", + name="NotificationSrv", + apptype=FlipperAppType.SERVICE, + entry_point="notification_srv", + cdefines=["SRV_NOTIFICATION"], + provides=["notification_settings"], + stack_size=1536, + order=0, +) + +App( + appid="notification_settings", + name="LCD and Notifications", + apptype=FlipperAppType.SETTINGS, + entry_point="notification_settings_app", + stack_size=1 * 1024, + order=0, +) diff --git a/applications/power/application.fam b/applications/power/application.fam new file mode 100644 index 000000000000..e30c7dfaeb58 --- /dev/null +++ b/applications/power/application.fam @@ -0,0 +1,29 @@ +App( + appid="power", + name="PowerSrv", + apptype=FlipperAppType.SERVICE, + entry_point="power_srv", + cdefines=["SRV_POWER"], + provides=[ + "power_settings", + "power_start", + ], + stack_size=1 * 1024, + order=0, +) + +App( + appid="power_settings", + name="Power", + apptype=FlipperAppType.SETTINGS, + entry_point="power_settings_app", + stack_size=1 * 1024, + order=0, +) + +App( + appid="power_start", + apptype=FlipperAppType.STARTUP, + entry_point="power_on_system_start", + order=0, +) diff --git a/applications/rpc/application.fam b/applications/rpc/application.fam new file mode 100644 index 000000000000..93a44da5c1cc --- /dev/null +++ b/applications/rpc/application.fam @@ -0,0 +1,9 @@ +App( + appid="rpc", + name="RpcSrv", + apptype=FlipperAppType.SERVICE, + entry_point="rpc_srv", + cdefines=["SRV_RPC"], + stack_size=4 * 1024, + order=0, +) diff --git a/applications/scened_app_example/application.fam b/applications/scened_app_example/application.fam new file mode 100644 index 000000000000..77414e82154e --- /dev/null +++ b/applications/scened_app_example/application.fam @@ -0,0 +1,9 @@ +App( + appid="scened", + name="Templated Scene", + apptype=FlipperAppType.DEBUG, + entry_point="scened_app", + cdefines=["APP_SCENED"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/snake_game/application.fam b/applications/snake_game/application.fam new file mode 100644 index 000000000000..049998897f47 --- /dev/null +++ b/applications/snake_game/application.fam @@ -0,0 +1,10 @@ +App( + appid="snake_game", + name="Snake Game", + apptype=FlipperAppType.PLUGIN, + entry_point="snake_game_app", + cdefines=["APP_SNAKE_GAME"], + stack_size=1 * 1024, + icon="A_Plugins_14", + order=0, +) diff --git a/applications/storage/application.fam b/applications/storage/application.fam new file mode 100644 index 000000000000..4a39592660c4 --- /dev/null +++ b/applications/storage/application.fam @@ -0,0 +1,18 @@ +App( + appid="storage", + name="StorageSrv", + apptype=FlipperAppType.SERVICE, + entry_point="storage_srv", + cdefines=["SRV_STORAGE"], + requires=["storage_settings"], + provides=["storage_start"], + stack_size=3 * 1024, + order=0, +) + +App( + appid="storage_start", + apptype=FlipperAppType.STARTUP, + entry_point="storage_on_system_start", + order=0, +) diff --git a/applications/storage_settings/application.fam b/applications/storage_settings/application.fam new file mode 100644 index 000000000000..d09c9a578258 --- /dev/null +++ b/applications/storage_settings/application.fam @@ -0,0 +1,9 @@ +App( + appid="storage_settings", + name="Storage", + apptype=FlipperAppType.SETTINGS, + entry_point="storage_settings_app", + requires=["storage"], + stack_size=2 * 1024, + order=0, +) diff --git a/applications/subghz/application.fam b/applications/subghz/application.fam new file mode 100644 index 000000000000..15a5627d9517 --- /dev/null +++ b/applications/subghz/application.fam @@ -0,0 +1,18 @@ +App( + appid="subghz", + name="Sub-GHz", + apptype=FlipperAppType.APP, + entry_point="subghz_app", + cdefines=["APP_SUBGHZ"], + provides=["subghz_start"], + icon="A_Sub1ghz_14", + stack_size=2 * 1024, + order=0, +) + +App( + appid="subghz_start", + apptype=FlipperAppType.STARTUP, + entry_point="subghz_on_system_start", + order=0, +) diff --git a/applications/system/application.fam b/applications/system/application.fam new file mode 100644 index 000000000000..abc3e0b83f7b --- /dev/null +++ b/applications/system/application.fam @@ -0,0 +1,9 @@ +App( + appid="system_settings", + name="System", + apptype=FlipperAppType.SETTINGS, + entry_point="system_settings_app", + requires=["gui"], + stack_size=1 * 1024, + order=0, +) diff --git a/applications/u2f/application.fam b/applications/u2f/application.fam new file mode 100644 index 000000000000..708f2d83159c --- /dev/null +++ b/applications/u2f/application.fam @@ -0,0 +1,10 @@ +App( + appid="u2f", + name="U2F", + apptype=FlipperAppType.APP, + entry_point="u2f_app", + cdefines=["APP_U2F"], + icon="A_U2F_14", + stack_size=2 * 1024, + order=0, +) diff --git a/applications/unit_tests/application.fam b/applications/unit_tests/application.fam new file mode 100644 index 000000000000..7a98bfea170a --- /dev/null +++ b/applications/unit_tests/application.fam @@ -0,0 +1,17 @@ +App( + appid="unit_tests", + apptype=FlipperAppType.STARTUP, + entry_point="unit_tests_on_system_start", + cdefines=["APP_UNIT_TESTS"], + provides=["delay_test"], + order=0, +) + +App( + appid="delay_test", + name="Delay Test", + apptype=FlipperAppType.DEBUG, + entry_point="delay_test_app", + stack_size=1 * 1024, + order=0, +) diff --git a/applications/updater/application.fam b/applications/updater/application.fam new file mode 100644 index 000000000000..857a0e7a6118 --- /dev/null +++ b/applications/updater/application.fam @@ -0,0 +1,21 @@ +App( + appid="updater", + name="UpdaterSrv", + apptype=FlipperAppType.SERVICE, + cdefines=["SRV_UPDATER"], + conflicts=["desktop"], + entry_point="updater_srv", + stack_size=2 * 1024, + order=0, +) + +App( + appid="updater_app", + name="UpdaterApp", + apptype=FlipperAppType.SYSTEM, + cdefines=["APP_UPDATER"], + conflicts=["updater"], + entry_point="updater_srv", + stack_size=2 * 1024, + order=0, +) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 14fd4e0e98b0..f02959c820e0 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -55,3 +55,71 @@ else: "-Tfirmware/targets/f${TARGET_HW}/stm32wb55xx_flash.ld", ], ) + + +from dataclasses import dataclass, field +from typing import List, Set, Dict, Tuple, Optional +from enum import Enum +import os +import SCons + + +class FlipperAppType(Enum): + SERVICE = "Service" + SYSTEM = "System" + APP = "App" + PLUGIN = "Plugin" + DEBUG = "Debug" + ARCHIVE = "Archive" + SETTINGS = "Settings" + STARTUP = "StartupHook" + + +@dataclass +class FlipperApplication: + appid: str + apptype: FlipperAppType + name: Optional[str] = None + entry_point: Optional[str] = None + flags: List[str] = field(default_factory=lambda: ["Default"]) + cdefines: List[str] = field(default_factory=list) + requires: List[str] = field(default_factory=list) + conflicts: List[str] = field(default_factory=list) + provides: List[str] = field(default_factory=list) + stack_size: int = 2048 + icon: Optional[str] = None + order: int = 0 + + +def LoadApplicationManifest(env, appdir): + # app_manifest = File("#/applications/" + appid + "/application.fam").abspath + app_manifest_path = appdir.File("application.fam").abspath + if not os.path.exists(app_manifest_path): + Exit(f"App manifest for '{appdir}' not found at path {app_manifest_path}") + # print("Loading", app_manifest_path) + + app_manifests = [] + + def App(*args, **kw): + nonlocal app_manifests + app_manifests.append(FlipperApplication(*args, **kw)) + + with open(app_manifest_path, "rt") as manifest_file: + exec(manifest_file.read()) + + if len(app_manifests) == 0: + Exit(f"App manifest for '{appdir}' is malformed") + + # print("Built", app_manifests) + return app_manifests + + +fwenv.AddMethod(LoadApplicationManifest) + +manifests = [] +for entry in Glob("#/applications/*"): + if isinstance(entry, SCons.Node.FS.Dir): + manifests.extend(fwenv.LoadApplicationManifest(entry)) + +# print(manifests) +# Exit(1) From 71c39389237cd2573e28a834327f7fcf09ff35a0 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 04:34:36 +0400 Subject: [PATCH 029/184] Manifest fixes & filled missing entries --- applications/bt/application.fam | 15 +++++++++++++-- applications/ibutton/application.fam | 1 + applications/infrared/application.fam | 1 + applications/lfrfid/application.fam | 1 + applications/music_player/application.fam | 1 + applications/nfc/application.fam | 1 + applications/notification/application.fam | 1 + applications/power/application.fam | 13 +++++++++++++ applications/storage/application.fam | 1 + applications/subghz/application.fam | 1 + applications/unit_tests/application.fam | 1 + applications/updater/application.fam | 9 +++++++++ 12 files changed, 44 insertions(+), 2 deletions(-) diff --git a/applications/bt/application.fam b/applications/bt/application.fam index c8afe3ce3069..cb4c5a37be87 100644 --- a/applications/bt/application.fam +++ b/applications/bt/application.fam @@ -1,5 +1,5 @@ App( - appid="bt_srv", + appid="bt", name="BtSrv", apptype=FlipperAppType.SERVICE, entry_point="bt_srv", @@ -31,7 +31,7 @@ App( ) App( - appid="bt_debug_app", + appid="bt_debug", name="Bluetooth Debug", apptype=FlipperAppType.DEBUG, entry_point="bt_debug_app", @@ -39,3 +39,14 @@ App( requires=["bt_srv"], order=0, ) + +App( + appid="bt_hid", + name="Bluetooth Remote", + apptype=FlipperAppType.PLUGIN, + entry_point="bt_hid_app", + stack_size=1 * 1024, + cdefines=["APP_BLE_HID"], + requires=["bt_srv"], + order=0, +) diff --git a/applications/ibutton/application.fam b/applications/ibutton/application.fam index 6ab26829d643..e638d1c344e9 100644 --- a/applications/ibutton/application.fam +++ b/applications/ibutton/application.fam @@ -14,5 +14,6 @@ App( appid="ibutton_start", apptype=FlipperAppType.STARTUP, entry_point="ibutton_on_system_start", + requires=["ibutton"], order=0, ) diff --git a/applications/infrared/application.fam b/applications/infrared/application.fam index 29cf4156189a..599eed2b8c17 100644 --- a/applications/infrared/application.fam +++ b/applications/infrared/application.fam @@ -14,5 +14,6 @@ App( appid="infrared_start", apptype=FlipperAppType.STARTUP, entry_point="infrared_on_system_start", + requires=["infrared"], order=0, ) diff --git a/applications/lfrfid/application.fam b/applications/lfrfid/application.fam index f9ae64c7a630..1688466c0432 100644 --- a/applications/lfrfid/application.fam +++ b/applications/lfrfid/application.fam @@ -14,5 +14,6 @@ App( appid="lfrfid_start", apptype=FlipperAppType.STARTUP, entry_point="lfrfid_on_system_start", + requires=["lfrfid"], order=0, ) diff --git a/applications/music_player/application.fam b/applications/music_player/application.fam index 765afdf06e3d..47f22465b501 100644 --- a/applications/music_player/application.fam +++ b/applications/music_player/application.fam @@ -13,5 +13,6 @@ App( appid="music_player_start", apptype=FlipperAppType.STARTUP, entry_point="music_player_on_system_start", + requires=["music_player"], order=0, ) diff --git a/applications/nfc/application.fam b/applications/nfc/application.fam index 4fc83c2a6d52..7c1cd4ca8603 100644 --- a/applications/nfc/application.fam +++ b/applications/nfc/application.fam @@ -14,5 +14,6 @@ App( appid="nfc_start", apptype=FlipperAppType.STARTUP, entry_point="nfc_on_system_start", + requires=["nfc"], order=0, ) diff --git a/applications/notification/application.fam b/applications/notification/application.fam index 9da741d5e4c4..74a534646625 100644 --- a/applications/notification/application.fam +++ b/applications/notification/application.fam @@ -14,6 +14,7 @@ App( name="LCD and Notifications", apptype=FlipperAppType.SETTINGS, entry_point="notification_settings_app", + requires=["notification"], stack_size=1 * 1024, order=0, ) diff --git a/applications/power/application.fam b/applications/power/application.fam index e30c7dfaeb58..90ff26a2dfc8 100644 --- a/applications/power/application.fam +++ b/applications/power/application.fam @@ -17,6 +17,7 @@ App( name="Power", apptype=FlipperAppType.SETTINGS, entry_point="power_settings_app", + requires=["power"], stack_size=1 * 1024, order=0, ) @@ -25,5 +26,17 @@ App( appid="power_start", apptype=FlipperAppType.STARTUP, entry_point="power_on_system_start", + requires=["power"], + order=0, +) + +App( + appid="battery_test", + name="Battery Test", + apptype=FlipperAppType.DEBUG, + entry_point="battery_test_app", + cdefines=["APP_BATTERY_TEST"], + requires=["power"], + stack_size=1 * 1024, order=0, ) diff --git a/applications/storage/application.fam b/applications/storage/application.fam index 4a39592660c4..309c933f9f15 100644 --- a/applications/storage/application.fam +++ b/applications/storage/application.fam @@ -14,5 +14,6 @@ App( appid="storage_start", apptype=FlipperAppType.STARTUP, entry_point="storage_on_system_start", + requires=["storage"], order=0, ) diff --git a/applications/subghz/application.fam b/applications/subghz/application.fam index 15a5627d9517..ced714c513c1 100644 --- a/applications/subghz/application.fam +++ b/applications/subghz/application.fam @@ -14,5 +14,6 @@ App( appid="subghz_start", apptype=FlipperAppType.STARTUP, entry_point="subghz_on_system_start", + requires=["subghz"], order=0, ) diff --git a/applications/unit_tests/application.fam b/applications/unit_tests/application.fam index 7a98bfea170a..b53867acdd5c 100644 --- a/applications/unit_tests/application.fam +++ b/applications/unit_tests/application.fam @@ -13,5 +13,6 @@ App( apptype=FlipperAppType.DEBUG, entry_point="delay_test_app", stack_size=1 * 1024, + requires=["unit_tests"], order=0, ) diff --git a/applications/updater/application.fam b/applications/updater/application.fam index 857a0e7a6118..2b8bf857a6a0 100644 --- a/applications/updater/application.fam +++ b/applications/updater/application.fam @@ -15,7 +15,16 @@ App( apptype=FlipperAppType.SYSTEM, cdefines=["APP_UPDATER"], conflicts=["updater"], + provides=["updater_start"], entry_point="updater_srv", stack_size=2 * 1024, order=0, ) + +App( + appid="updater_start", + apptype=FlipperAppType.STARTUP, + entry_point="updater_on_system_start", + requires=["updater_app"], + order=0, +) From 26d7749845c4f6c6eccd8ea54a639925f6a8aed1 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 04:47:24 +0400 Subject: [PATCH 030/184] Added Insomnia to power settings --- applications/power/application.fam | 1 + sconscfg/firmwareopts.scons | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/applications/power/application.fam b/applications/power/application.fam index 90ff26a2dfc8..0dabbf6f1419 100644 --- a/applications/power/application.fam +++ b/applications/power/application.fam @@ -18,6 +18,7 @@ App( apptype=FlipperAppType.SETTINGS, entry_point="power_settings_app", requires=["power"], + flags=["InsomniaSafe"], stack_size=1 * 1024, order=0, ) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index f02959c820e0..b2005909736b 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -91,7 +91,7 @@ class FlipperApplication: order: int = 0 -def LoadApplicationManifest(env, appdir): +def LoadApplicationManifests(env, appdir): # app_manifest = File("#/applications/" + appid + "/application.fam").abspath app_manifest_path = appdir.File("application.fam").abspath if not os.path.exists(app_manifest_path): @@ -114,12 +114,12 @@ def LoadApplicationManifest(env, appdir): return app_manifests -fwenv.AddMethod(LoadApplicationManifest) +fwenv.AddMethod(LoadApplicationManifests) manifests = [] for entry in Glob("#/applications/*"): if isinstance(entry, SCons.Node.FS.Dir): - manifests.extend(fwenv.LoadApplicationManifest(entry)) + manifests.extend(fwenv.LoadApplicationManifests(entry)) # print(manifests) # Exit(1) From 4997764f5629446dbd49fb9c58dd07411d29f468 Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Sun, 5 Jun 2022 10:22:55 +0900 Subject: [PATCH 031/184] Build: fbt entry point to scons and flash rule --- fbt | 5 +++++ firmware.scons | 3 +++ sconscfg/builders.scons | 11 +++++++++++ sconscfg/firmwareopts.scons | 3 +++ 4 files changed, 22 insertions(+) create mode 100755 fbt diff --git a/fbt b/fbt new file mode 100755 index 000000000000..ba167dd638f1 --- /dev/null +++ b/fbt @@ -0,0 +1,5 @@ +#!/bin/bash + +set +x + +/usr/bin/env python3 lib/scons/scripts/scons.py "$@" diff --git a/firmware.scons b/firmware.scons index da1bb0da4e3c..fb70239cda05 100644 --- a/firmware.scons +++ b/firmware.scons @@ -143,6 +143,9 @@ fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") +flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") +Alias("flash", flash) + # Compile DB generation cdb = fwenv.CompilationDatabase("compile_database.json") Alias("cdb", cdb) diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons index 8fb5607e9d2c..bd7c56b35360 100644 --- a/sconscfg/builders.scons +++ b/sconscfg/builders.scons @@ -15,6 +15,12 @@ def generate_dfu(source, target, env, for_signature): % (source[0], target[0]) ) +def flash_bin(source, target, env, for_signature): + return ( + 'openocd ${OPENOCD_OPTS} -c "program %s reset exit ${IMAGE_BASE_ADDRESS}" && touch %s' + % (source[0], target[0]) + ) + # def generate_json(source, target, env, for_signature): # return '${PYTHON3} scripts/meta.py generate -p firmware ${} "%s" > "%s"' % ( @@ -40,5 +46,10 @@ env.Append( suffix=".dfu", src_suffix=".bin", ), + "Flasher": Builder( + generator=flash_bin, + suffix=".flash", + src_suffix=".bin", + ), } ) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index b2005909736b..2622828e3909 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -35,6 +35,9 @@ else: ], ) +fwenv.Append( + OPENOCD_OPTS='-f interface/stlink.cfg -c "transport select hla_swd" -f debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init"', +) if fwenv["FIRMWARE_BUILD_CFG"] == "updater": fwenv.Append( From 85017ab9778f7dabdb0b227448316e060a4b030f Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 13:38:49 +0400 Subject: [PATCH 032/184] Changed flash target from builder to command --- firmware.scons | 12 ++++++++++-- sconscfg/builders.scons | 11 ----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/firmware.scons b/firmware.scons index fb70239cda05..1ba73fd4d37b 100644 --- a/firmware.scons +++ b/firmware.scons @@ -141,11 +141,19 @@ Depends(firmware_elf, depends) fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") -fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") +dfu = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") +Default(dfu) +Alias("dfu", dfu) -flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") + +flash = fwenv.Command( + target="flash", + source="${FIRMWARE_BUILD_CFG}.bin", + action='openocd ${OPENOCD_OPTS} -c "program $SOURCES reset exit ${IMAGE_BASE_ADDRESS}"', +) Alias("flash", flash) + # Compile DB generation cdb = fwenv.CompilationDatabase("compile_database.json") Alias("cdb", cdb) diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons index bd7c56b35360..8fb5607e9d2c 100644 --- a/sconscfg/builders.scons +++ b/sconscfg/builders.scons @@ -15,12 +15,6 @@ def generate_dfu(source, target, env, for_signature): % (source[0], target[0]) ) -def flash_bin(source, target, env, for_signature): - return ( - 'openocd ${OPENOCD_OPTS} -c "program %s reset exit ${IMAGE_BASE_ADDRESS}" && touch %s' - % (source[0], target[0]) - ) - # def generate_json(source, target, env, for_signature): # return '${PYTHON3} scripts/meta.py generate -p firmware ${} "%s" > "%s"' % ( @@ -46,10 +40,5 @@ env.Append( suffix=".dfu", src_suffix=".bin", ), - "Flasher": Builder( - generator=flash_bin, - suffix=".flash", - src_suffix=".bin", - ), } ) From 8eabf82fd3d4854774de76f447857673358051c7 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 15:45:56 +0400 Subject: [PATCH 033/184] Ported app deps from makefile; inital deps solver impl --- applications/about/application.fam | 1 + applications/accessor/application.fam | 1 + applications/archive/application.fam | 1 + applications/bad_usb/application.fam | 1 + applications/bt/application.fam | 18 ++- applications/debug_tools/application.fam | 8 ++ applications/desktop/application.fam | 13 +- applications/dialogs/application.fam | 1 + applications/dolphin/application.fam | 5 +- applications/gpio/application.fam | 1 + applications/gui/application.fam | 4 + applications/ibutton/application.fam | 1 + applications/infrared/application.fam | 1 + applications/infrared_monitor/application.fam | 1 + applications/lfrfid/application.fam | 1 + applications/lfrfid_debug/application.fam | 1 + applications/loader/application.fam | 1 + applications/music_player/application.fam | 1 + applications/nfc/application.fam | 1 + applications/notification/application.fam | 2 +- applications/power/application.fam | 14 +- applications/rpc/application.fam | 3 + applications/snake_game/application.fam | 1 + applications/subghz/application.fam | 4 + applications/u2f/application.fam | 3 +- applications/updater/application.fam | 8 ++ firmware.scons | 3 +- sconscfg/firmwareopts.scons | 136 ++++++++++++++---- 28 files changed, 197 insertions(+), 39 deletions(-) diff --git a/applications/about/application.fam b/applications/about/application.fam index a8173b59037c..a3fcde26b4dc 100644 --- a/applications/about/application.fam +++ b/applications/about/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.SETTINGS, entry_point="about_settings_app", cdefines=["APP_ABOUT"], + requires=["gui"], stack_size=1 * 1024, order=0, ) diff --git a/applications/accessor/application.fam b/applications/accessor/application.fam index e242c44a193a..668f0436f3bb 100644 --- a/applications/accessor/application.fam +++ b/applications/accessor/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="accessor_app", cdefines=["APP_ACCESSOR"], + requires=["gui"], stack_size=4 * 1024, order=0, ) diff --git a/applications/archive/application.fam b/applications/archive/application.fam index 121d950dc38e..f0a980ab01e2 100644 --- a/applications/archive/application.fam +++ b/applications/archive/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.ARCHIVE, entry_point="archive_app", cdefines=["APP_ARCHIVE"], + requires=["gui"], stack_size=4 * 1024, icon="A_FileManager_14", order=0, diff --git a/applications/bad_usb/application.fam b/applications/bad_usb/application.fam index c1cebfb4ba5b..af1a7e4e11c0 100644 --- a/applications/bad_usb/application.fam +++ b/applications/bad_usb/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.APP, entry_point="bad_usb_app", cdefines=["APP_BAD_USB"], + requires=["gui"], stack_size=2 * 1024, icon="A_BadUsb_14", order=0, diff --git a/applications/bt/application.fam b/applications/bt/application.fam index cb4c5a37be87..accffaa54515 100644 --- a/applications/bt/application.fam +++ b/applications/bt/application.fam @@ -4,10 +4,11 @@ App( apptype=FlipperAppType.SERVICE, entry_point="bt_srv", cdefines=["SRV_BT"], + requires=["cli"], provides=[ "bt_start", "bt_settings", - "bt_debug_app", + "bt_debug", ], stack_size=1 * 1024, order=0, @@ -26,7 +27,10 @@ App( apptype=FlipperAppType.SETTINGS, entry_point="bt_settings_app", stack_size=1 * 1024, - requires=["bt_srv"], + requires=[ + "bt", + "gui", + ], order=0, ) @@ -36,7 +40,10 @@ App( apptype=FlipperAppType.DEBUG, entry_point="bt_debug_app", stack_size=1 * 1024, - requires=["bt_srv"], + requires=[ + "bt", + "gui", + ], order=0, ) @@ -47,6 +54,9 @@ App( entry_point="bt_hid_app", stack_size=1 * 1024, cdefines=["APP_BLE_HID"], - requires=["bt_srv"], + requires=[ + "bt", + "gui", + ], order=0, ) diff --git a/applications/debug_tools/application.fam b/applications/debug_tools/application.fam index 7335d9903634..592953ac20d8 100644 --- a/applications/debug_tools/application.fam +++ b/applications/debug_tools/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="blink_test_app", cdefines=["APP_BLINK"], + requires=["gui"], stack_size=1 * 1024, order=0, ) @@ -14,6 +15,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="vibro_test_app", cdefines=["APP_VIBRO_TEST"], + requires=["gui"], stack_size=1 * 1024, order=0, ) @@ -24,6 +26,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="keypad_test_app", cdefines=["APP_KEYPAD_TEST"], + requires=["gui"], stack_size=1 * 1024, order=0, ) @@ -34,6 +37,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="usb_test_app", cdefines=["APP_USB_TEST"], + requires=["gui"], stack_size=1 * 1024, order=0, ) @@ -44,6 +48,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="usb_mouse_app", cdefines=["APP_USB_MOUSE"], + requires=["gui"], stack_size=1 * 1024, order=0, ) @@ -54,6 +59,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="uart_echo_app", cdefines=["APP_UART_ECHO"], + requires=["gui"], stack_size=2 * 1024, order=0, ) @@ -64,6 +70,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="text_box_test_app", cdefines=["APP_TEXT_BOX_TEST"], + requires=["gui"], stack_size=1 * 1024, order=0, ) @@ -74,6 +81,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="display_test_app", cdefines=["APP_DISPLAY_TEST"], + requires=["gui"], stack_size=1 * 1024, order=0, ) diff --git a/applications/desktop/application.fam b/applications/desktop/application.fam index 8c69651d4719..41886fd84858 100644 --- a/applications/desktop/application.fam +++ b/applications/desktop/application.fam @@ -4,8 +4,14 @@ App( apptype=FlipperAppType.SERVICE, entry_point="desktop_srv", cdefines=["SRV_DESKTOP"], - stack_size=2 * 1024, + requires=[ + "gui", + "dolphin", + "storage", + ], + provides=["desktop_settings"], conflicts=["updater"], + stack_size=2 * 1024, order=0, ) @@ -14,7 +20,10 @@ App( name="Desktop", apptype=FlipperAppType.SETTINGS, entry_point="desktop_settings_app", - requires=["desktop"], + requires=[ + "desktop", + "gui", + ], stack_size=1 * 1024, order=0, ) diff --git a/applications/dialogs/application.fam b/applications/dialogs/application.fam index 12ca8fb1a2e2..17535b94c989 100644 --- a/applications/dialogs/application.fam +++ b/applications/dialogs/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.SERVICE, entry_point="dialogs_srv", cdefines=["SRV_DIALOGS"], + requires=["gui"], stack_size=1 * 1024, order=0, ) diff --git a/applications/dolphin/application.fam b/applications/dolphin/application.fam index 88caaa0f159d..acb0fe1ce336 100644 --- a/applications/dolphin/application.fam +++ b/applications/dolphin/application.fam @@ -14,7 +14,10 @@ App( apptype=FlipperAppType.SETTINGS, entry_point="passport_app", cdefines=["APP_PASSPORT"], - requires=["dolphin"], + requires=[ + "gui", + "dolphin", + ], stack_size=1 * 1024, order=0, ) diff --git a/applications/gpio/application.fam b/applications/gpio/application.fam index cb4b28f76e13..c1ecfc78fc6e 100644 --- a/applications/gpio/application.fam +++ b/applications/gpio/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.APP, entry_point="gpio_app", cdefines=["APP_GPIO"], + requires=["gui"], stack_size=1 * 1024, icon="A_GPIO_14", order=0, diff --git a/applications/gui/application.fam b/applications/gui/application.fam index 3e75e8d5322b..a6651f85e3ff 100644 --- a/applications/gui/application.fam +++ b/applications/gui/application.fam @@ -4,6 +4,10 @@ App( apptype=FlipperAppType.SERVICE, entry_point="gui_srv", cdefines=["SRV_GUI"], + requires=[ + "input", + "notification", + ], stack_size=2 * 1024, order=0, ) diff --git a/applications/ibutton/application.fam b/applications/ibutton/application.fam index e638d1c344e9..90618ded0a7e 100644 --- a/applications/ibutton/application.fam +++ b/applications/ibutton/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.APP, entry_point="ibutton_app", cdefines=["APP_IBUTTON"], + requires=["gui"], provides=["ibutton_start"], icon="A_iButton_14", stack_size=2 * 1024, diff --git a/applications/infrared/application.fam b/applications/infrared/application.fam index 599eed2b8c17..3118b338af97 100644 --- a/applications/infrared/application.fam +++ b/applications/infrared/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.APP, entry_point="infrared_app", cdefines=["APP_INFRARED"], + requires=["gui"], provides=["infrared_start"], icon="A_Infrared_14", stack_size=3 * 1024, diff --git a/applications/infrared_monitor/application.fam b/applications/infrared_monitor/application.fam index 759b6b9968d9..ea84ebebce6c 100644 --- a/applications/infrared_monitor/application.fam +++ b/applications/infrared_monitor/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="infrared_monitor_app", cdefines=["APP_INFRARED_MONITOR"], + requires=["gui"], stack_size=1 * 1024, order=0, ) diff --git a/applications/lfrfid/application.fam b/applications/lfrfid/application.fam index 1688466c0432..9aba9ced6082 100644 --- a/applications/lfrfid/application.fam +++ b/applications/lfrfid/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.APP, entry_point="lfrfid_app", cdefines=["APP_LF_RFID"], + requires=["gui"], provides=["lfrfid_start"], icon="A_125khz_14", stack_size=2 * 1024, diff --git a/applications/lfrfid_debug/application.fam b/applications/lfrfid_debug/application.fam index 155f517558e9..2d646cf621b8 100644 --- a/applications/lfrfid_debug/application.fam +++ b/applications/lfrfid_debug/application.fam @@ -3,6 +3,7 @@ App( name="LF-RFID Debug", apptype=FlipperAppType.DEBUG, entry_point="lfrfid_debug_app", + requires=["gui"], stack_size=1 * 1024, order=0, ) diff --git a/applications/loader/application.fam b/applications/loader/application.fam index bddaa82ab07f..d06c0578fbb7 100644 --- a/applications/loader/application.fam +++ b/applications/loader/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.SERVICE, entry_point="loader_srv", cdefines=["SRV_LOADER"], + requires=["gui"], stack_size=1 * 1024, order=0, ) diff --git a/applications/music_player/application.fam b/applications/music_player/application.fam index 47f22465b501..938d46f5e785 100644 --- a/applications/music_player/application.fam +++ b/applications/music_player/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="music_player_app", cdefines=["APP_MUSIC_PLAYER"], + requires=["gui"], provides=["music_player_start"], stack_size=2 * 1024, order=0, diff --git a/applications/nfc/application.fam b/applications/nfc/application.fam index 7c1cd4ca8603..d60a3a7983f3 100644 --- a/applications/nfc/application.fam +++ b/applications/nfc/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.APP, entry_point="nfc_app", cdefines=["APP_NFC"], + requires=["gui"], provides=["nfc_start"], icon="A_NFC_14", stack_size=4 * 1024, diff --git a/applications/notification/application.fam b/applications/notification/application.fam index 74a534646625..7722aa86c76a 100644 --- a/applications/notification/application.fam +++ b/applications/notification/application.fam @@ -5,7 +5,7 @@ App( entry_point="notification_srv", cdefines=["SRV_NOTIFICATION"], provides=["notification_settings"], - stack_size=1536, + stack_size=int(1.5 * 1024), order=0, ) diff --git a/applications/power/application.fam b/applications/power/application.fam index 0dabbf6f1419..6cba8d91e2b3 100644 --- a/applications/power/application.fam +++ b/applications/power/application.fam @@ -4,6 +4,10 @@ App( apptype=FlipperAppType.SERVICE, entry_point="power_srv", cdefines=["SRV_POWER"], + requires=[ + "gui", + "cli", + ], provides=[ "power_settings", "power_start", @@ -17,7 +21,10 @@ App( name="Power", apptype=FlipperAppType.SETTINGS, entry_point="power_settings_app", - requires=["power"], + requires=[ + "gui", + "power", + ], flags=["InsomniaSafe"], stack_size=1 * 1024, order=0, @@ -37,7 +44,10 @@ App( apptype=FlipperAppType.DEBUG, entry_point="battery_test_app", cdefines=["APP_BATTERY_TEST"], - requires=["power"], + requires=[ + "gui", + "power", + ], stack_size=1 * 1024, order=0, ) diff --git a/applications/rpc/application.fam b/applications/rpc/application.fam index 93a44da5c1cc..55b94b1070bf 100644 --- a/applications/rpc/application.fam +++ b/applications/rpc/application.fam @@ -4,6 +4,9 @@ App( apptype=FlipperAppType.SERVICE, entry_point="rpc_srv", cdefines=["SRV_RPC"], + requires=[ + "cli", + ], stack_size=4 * 1024, order=0, ) diff --git a/applications/snake_game/application.fam b/applications/snake_game/application.fam index 049998897f47..c1900d54f8ff 100644 --- a/applications/snake_game/application.fam +++ b/applications/snake_game/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="snake_game_app", cdefines=["APP_SNAKE_GAME"], + requires=["gui"], stack_size=1 * 1024, icon="A_Plugins_14", order=0, diff --git a/applications/subghz/application.fam b/applications/subghz/application.fam index ced714c513c1..d149d116d9d9 100644 --- a/applications/subghz/application.fam +++ b/applications/subghz/application.fam @@ -4,6 +4,10 @@ App( apptype=FlipperAppType.APP, entry_point="subghz_app", cdefines=["APP_SUBGHZ"], + requires=[ + "gui", + "cli", + ], provides=["subghz_start"], icon="A_Sub1ghz_14", stack_size=2 * 1024, diff --git a/applications/u2f/application.fam b/applications/u2f/application.fam index 708f2d83159c..7cc8d76cc410 100644 --- a/applications/u2f/application.fam +++ b/applications/u2f/application.fam @@ -4,7 +4,8 @@ App( apptype=FlipperAppType.APP, entry_point="u2f_app", cdefines=["APP_U2F"], - icon="A_U2F_14", + requires=["gui"], stack_size=2 * 1024, + icon="A_U2F_14", order=0, ) diff --git a/applications/updater/application.fam b/applications/updater/application.fam index 2b8bf857a6a0..8ab1f177ea46 100644 --- a/applications/updater/application.fam +++ b/applications/updater/application.fam @@ -3,6 +3,10 @@ App( name="UpdaterSrv", apptype=FlipperAppType.SERVICE, cdefines=["SRV_UPDATER"], + requires=[ + "gui", + "storage", + ], conflicts=["desktop"], entry_point="updater_srv", stack_size=2 * 1024, @@ -14,6 +18,10 @@ App( name="UpdaterApp", apptype=FlipperAppType.SYSTEM, cdefines=["APP_UPDATER"], + requires=[ + "gui", + "storage", + ], conflicts=["updater"], provides=["updater_start"], entry_point="updater_srv", diff --git a/firmware.scons b/firmware.scons index 1ba73fd4d37b..e10f2d620263 100644 --- a/firmware.scons +++ b/firmware.scons @@ -149,7 +149,7 @@ Alias("dfu", dfu) flash = fwenv.Command( target="flash", source="${FIRMWARE_BUILD_CFG}.bin", - action='openocd ${OPENOCD_OPTS} -c "program $SOURCES reset exit ${IMAGE_BASE_ADDRESS}"', + action='openocd ${OPENOCD_OPTS} -c "program ${SOURCES} reset exit ${IMAGE_BASE_ADDRESS}"', ) Alias("flash", flash) @@ -157,3 +157,4 @@ Alias("flash", flash) # Compile DB generation cdb = fwenv.CompilationDatabase("compile_database.json") Alias("cdb", cdb) +# Depends(firmware_elf, cdb) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 2622828e3909..7e987e9b6fab 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -94,35 +94,117 @@ class FlipperApplication: order: int = 0 -def LoadApplicationManifests(env, appdir): - # app_manifest = File("#/applications/" + appid + "/application.fam").abspath - app_manifest_path = appdir.File("application.fam").abspath - if not os.path.exists(app_manifest_path): - Exit(f"App manifest for '{appdir}' not found at path {app_manifest_path}") - # print("Loading", app_manifest_path) - - app_manifests = [] - - def App(*args, **kw): - nonlocal app_manifests - app_manifests.append(FlipperApplication(*args, **kw)) - - with open(app_manifest_path, "rt") as manifest_file: - exec(manifest_file.read()) - - if len(app_manifests) == 0: - Exit(f"App manifest for '{appdir}' is malformed") - - # print("Built", app_manifests) - return app_manifests +class AppManager: + def __init__(self): + self.known_apps = {} + + def get(self, appname): + return self.known_apps[appname] + + def load_manifest(self, app_manifest_path): + if not os.path.exists(app_manifest_path): + raise Exception(f"App manifest not found at path {app_manifest_path}") + # print("Loading", app_manifest_path) + + app_manifests = [] + + def App(*args, **kw): + nonlocal app_manifests + app_manifests.append(FlipperApplication(*args, **kw)) + + with open(app_manifest_path, "rt") as manifest_file: + exec(manifest_file.read()) + + if len(app_manifests) == 0: + Exit(f"App manifest '{app_manifest_path}' is malformed") + + # print("Built", app_manifests) + for app in app_manifests: + self._add_known_app(app) + + def _add_known_app(self, app): + if self.known_apps.get(app.appid, None): + raise Exception(f"Duplicate app declaration: {app.appid}") + self.known_apps[app.appid] = app + + def filter_apps(self, applist): + return AppBuiltset(self, applist) + + +class AppBuiltset: + def __init__(self, appmgr, appnames): + self.appmgr = appmgr + self.appnames = set(appnames) + self._orig_appnames = appnames + self._process_deps() + self._check_conflicts() + # print("apps_to_build", self.appnames) + + def _is_missing_dep(self, dep_name): + return dep_name not in self.appnames + + def _process_deps(self): + while True: + provided = [] + for app in self.appnames: + provided.extend( + filter( + self._is_missing_dep, + self.appmgr.get(app).provides + self.appmgr.get(app).requires, + ) + ) + print("provides round", provided) + if len(provided) == 0: + break + self.appnames.update(provided) + + def _check_conflicts(self): + conflicts = [] + for app in self.appnames: + if conflict_app_name := list( + filter( + lambda dep_name: dep_name in self.appnames, + self.appmgr.get(app).conflicts, + ) + ): + conflicts.append((app, conflict_app_name)) + + if len(conflicts): + raise Exception( + f"App conflicts for {', '.join(f'{conflict_dep[0]}: {conflict_dep[1]}' for conflict_dep in conflicts)}" + ) + + def _check_unsatisfied(self): + unsatisfied = [] + for app in self.appnames: + if missing_dep := list( + filter(self._is_missing_dep, self.appmgr.get(app).requires) + ): + unsatisfied.append((app, missing_dep)) + + if len(unsatisfied): + raise Exception( + f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" + ) + + def apps(self): + return list(self.appmgr.get(appname) for appname in self.appnames) + + +def LoadApplicationManifests(env): + appmgr = env["APPMGR"] = AppManager() + for entry in Glob("#/applications/*"): + if isinstance(entry, SCons.Node.FS.Dir): + appmgr.load_manifest( + app_manifest_path=entry.File("application.fam").abspath + ) + + print(f"Loaded {len(appmgr.known_apps)} app definitions.") fwenv.AddMethod(LoadApplicationManifests) +fwenv.LoadApplicationManifests() -manifests = [] -for entry in Glob("#/applications/*"): - if isinstance(entry, SCons.Node.FS.Dir): - manifests.extend(fwenv.LoadApplicationManifests(entry)) - -# print(manifests) +# apps_buildlist = fwenv["APPMGR"].filter_apps(["updater_app", "bt", "desktop"]) +# print("apps_buildlist", apps_buildlist.apps()) # Exit(1) From fc2e631733e401394b61c7ff3baf6c664ed243db Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 16:47:10 +0400 Subject: [PATCH 034/184] Added order values to apps; added app sorting --- applications/about/application.fam | 2 +- applications/accessor/application.fam | 2 +- applications/bad_usb/application.fam | 2 +- applications/bt/application.fam | 10 ++--- applications/cli/application.fam | 2 +- applications/crypto/application.fam | 2 +- applications/debug_tools/application.fam | 32 ++++++------- applications/desktop/application.fam | 4 +- applications/dialogs/application.fam | 2 +- applications/dolphin/application.fam | 4 +- applications/gpio/application.fam | 2 +- applications/gui/application.fam | 2 +- applications/ibutton/application.fam | 4 +- applications/infrared/application.fam | 4 +- applications/infrared_monitor/application.fam | 2 +- applications/input/application.fam | 2 +- applications/lfrfid/application.fam | 4 +- applications/lfrfid_debug/application.fam | 2 +- applications/loader/application.fam | 2 +- applications/music_player/application.fam | 4 +- applications/nfc/application.fam | 2 +- applications/notification/application.fam | 4 +- applications/power/application.fam | 8 ++-- applications/rpc/application.fam | 2 +- .../scened_app_example/application.fam | 2 +- applications/snake_game/application.fam | 2 +- applications/storage/application.fam | 4 +- applications/storage_settings/application.fam | 2 +- applications/subghz/application.fam | 4 +- applications/system/application.fam | 2 +- applications/u2f/application.fam | 2 +- applications/unit_tests/application.fam | 4 +- applications/updater/application.fam | 6 +-- sconscfg/firmwareopts.scons | 45 ++++++++++++------- 34 files changed, 95 insertions(+), 84 deletions(-) diff --git a/applications/about/application.fam b/applications/about/application.fam index a3fcde26b4dc..ea03dc7b9eef 100644 --- a/applications/about/application.fam +++ b/applications/about/application.fam @@ -6,5 +6,5 @@ App( cdefines=["APP_ABOUT"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=1000, ) diff --git a/applications/accessor/application.fam b/applications/accessor/application.fam index 668f0436f3bb..8a94049e14a0 100644 --- a/applications/accessor/application.fam +++ b/applications/accessor/application.fam @@ -6,5 +6,5 @@ App( cdefines=["APP_ACCESSOR"], requires=["gui"], stack_size=4 * 1024, - order=0, + order=40, ) diff --git a/applications/bad_usb/application.fam b/applications/bad_usb/application.fam index af1a7e4e11c0..d39a012dc715 100644 --- a/applications/bad_usb/application.fam +++ b/applications/bad_usb/application.fam @@ -7,5 +7,5 @@ App( requires=["gui"], stack_size=2 * 1024, icon="A_BadUsb_14", - order=0, + order=70, ) diff --git a/applications/bt/application.fam b/applications/bt/application.fam index accffaa54515..727e02c00926 100644 --- a/applications/bt/application.fam +++ b/applications/bt/application.fam @@ -11,14 +11,14 @@ App( "bt_debug", ], stack_size=1 * 1024, - order=0, + order=20, ) App( appid="bt_start", apptype=FlipperAppType.STARTUP, entry_point="bt_on_system_start", - order=0, + order=70, ) App( @@ -31,7 +31,7 @@ App( "bt", "gui", ], - order=0, + order=10, ) App( @@ -44,7 +44,7 @@ App( "bt", "gui", ], - order=0, + order=110, ) App( @@ -58,5 +58,5 @@ App( "bt", "gui", ], - order=0, + order=10, ) diff --git a/applications/cli/application.fam b/applications/cli/application.fam index fab9b4321e68..73c70aa44eda 100644 --- a/applications/cli/application.fam +++ b/applications/cli/application.fam @@ -5,5 +5,5 @@ App( entry_point="cli_srv", cdefines=["SRV_CLI"], stack_size=4 * 1024, - order=0, + order=30, ) diff --git a/applications/crypto/application.fam b/applications/crypto/application.fam index 7014f48cf77f..2dec27475ccf 100644 --- a/applications/crypto/application.fam +++ b/applications/crypto/application.fam @@ -2,5 +2,5 @@ App( appid="crypto", apptype=FlipperAppType.STARTUP, entry_point="crypto_on_system_start", - order=0, + order=10, ) diff --git a/applications/debug_tools/application.fam b/applications/debug_tools/application.fam index 592953ac20d8..9058fca56a52 100644 --- a/applications/debug_tools/application.fam +++ b/applications/debug_tools/application.fam @@ -6,7 +6,7 @@ App( cdefines=["APP_BLINK"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=10, ) App( @@ -17,7 +17,7 @@ App( cdefines=["APP_VIBRO_TEST"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=20, ) App( @@ -28,7 +28,7 @@ App( cdefines=["APP_KEYPAD_TEST"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=30, ) App( @@ -39,7 +39,7 @@ App( cdefines=["APP_USB_TEST"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=50, ) App( @@ -50,7 +50,7 @@ App( cdefines=["APP_USB_MOUSE"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=60, ) App( @@ -61,27 +61,27 @@ App( cdefines=["APP_UART_ECHO"], requires=["gui"], stack_size=2 * 1024, - order=0, + order=70, ) App( - appid="text_box_test", - name="Text Box Test", + appid="display_test", + name="Display Test", apptype=FlipperAppType.DEBUG, - entry_point="text_box_test_app", - cdefines=["APP_TEXT_BOX_TEST"], + entry_point="display_test_app", + cdefines=["APP_DISPLAY_TEST"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=120, ) App( - appid="display_test", - name="Display Test", + appid="text_box_test", + name="Text Box Test", apptype=FlipperAppType.DEBUG, - entry_point="display_test_app", - cdefines=["APP_DISPLAY_TEST"], + entry_point="text_box_test_app", + cdefines=["APP_TEXT_BOX_TEST"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=140, ) diff --git a/applications/desktop/application.fam b/applications/desktop/application.fam index 41886fd84858..e80db01f8e60 100644 --- a/applications/desktop/application.fam +++ b/applications/desktop/application.fam @@ -12,7 +12,7 @@ App( provides=["desktop_settings"], conflicts=["updater"], stack_size=2 * 1024, - order=0, + order=60, ) App( @@ -25,5 +25,5 @@ App( "gui", ], stack_size=1 * 1024, - order=0, + order=50, ) diff --git a/applications/dialogs/application.fam b/applications/dialogs/application.fam index 17535b94c989..0a18c79a3ba8 100644 --- a/applications/dialogs/application.fam +++ b/applications/dialogs/application.fam @@ -6,5 +6,5 @@ App( cdefines=["SRV_DIALOGS"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=40, ) diff --git a/applications/dolphin/application.fam b/applications/dolphin/application.fam index acb0fe1ce336..1ee0e3cfe4af 100644 --- a/applications/dolphin/application.fam +++ b/applications/dolphin/application.fam @@ -5,7 +5,7 @@ App( entry_point="dolphin_srv", cdefines=["SRV_DOLPHIN"], stack_size=1 * 1024, - order=0, + order=50, ) App( @@ -19,5 +19,5 @@ App( "dolphin", ], stack_size=1 * 1024, - order=0, + order=60, ) diff --git a/applications/gpio/application.fam b/applications/gpio/application.fam index c1ecfc78fc6e..64f8db5b098e 100644 --- a/applications/gpio/application.fam +++ b/applications/gpio/application.fam @@ -7,5 +7,5 @@ App( requires=["gui"], stack_size=1 * 1024, icon="A_GPIO_14", - order=0, + order=50, ) diff --git a/applications/gui/application.fam b/applications/gui/application.fam index a6651f85e3ff..0116f5b88a34 100644 --- a/applications/gui/application.fam +++ b/applications/gui/application.fam @@ -9,5 +9,5 @@ App( "notification", ], stack_size=2 * 1024, - order=0, + order=70, ) diff --git a/applications/ibutton/application.fam b/applications/ibutton/application.fam index 90618ded0a7e..3c189e64f39e 100644 --- a/applications/ibutton/application.fam +++ b/applications/ibutton/application.fam @@ -8,7 +8,7 @@ App( provides=["ibutton_start"], icon="A_iButton_14", stack_size=2 * 1024, - order=0, + order=60, ) App( @@ -16,5 +16,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="ibutton_on_system_start", requires=["ibutton"], - order=0, + order=60, ) diff --git a/applications/infrared/application.fam b/applications/infrared/application.fam index 3118b338af97..e18c16c9bd6e 100644 --- a/applications/infrared/application.fam +++ b/applications/infrared/application.fam @@ -8,7 +8,7 @@ App( provides=["infrared_start"], icon="A_Infrared_14", stack_size=3 * 1024, - order=0, + order=40, ) App( @@ -16,5 +16,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="infrared_on_system_start", requires=["infrared"], - order=0, + order=20, ) diff --git a/applications/infrared_monitor/application.fam b/applications/infrared_monitor/application.fam index ea84ebebce6c..8ab72309221b 100644 --- a/applications/infrared_monitor/application.fam +++ b/applications/infrared_monitor/application.fam @@ -6,5 +6,5 @@ App( cdefines=["APP_INFRARED_MONITOR"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=80, ) diff --git a/applications/input/application.fam b/applications/input/application.fam index d44886950509..545630e6ef3a 100644 --- a/applications/input/application.fam +++ b/applications/input/application.fam @@ -5,5 +5,5 @@ App( entry_point="input_srv", cdefines=["SRV_INPUT"], stack_size=1 * 1024, - order=0, + order=80, ) diff --git a/applications/lfrfid/application.fam b/applications/lfrfid/application.fam index 9aba9ced6082..31cdffb076dc 100644 --- a/applications/lfrfid/application.fam +++ b/applications/lfrfid/application.fam @@ -8,7 +8,7 @@ App( provides=["lfrfid_start"], icon="A_125khz_14", stack_size=2 * 1024, - order=0, + order=20, ) App( @@ -16,5 +16,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="lfrfid_on_system_start", requires=["lfrfid"], - order=0, + order=50, ) diff --git a/applications/lfrfid_debug/application.fam b/applications/lfrfid_debug/application.fam index 2d646cf621b8..c88ef5a70645 100644 --- a/applications/lfrfid_debug/application.fam +++ b/applications/lfrfid_debug/application.fam @@ -5,5 +5,5 @@ App( entry_point="lfrfid_debug_app", requires=["gui"], stack_size=1 * 1024, - order=0, + order=100, ) diff --git a/applications/loader/application.fam b/applications/loader/application.fam index d06c0578fbb7..16351f8d1cb9 100644 --- a/applications/loader/application.fam +++ b/applications/loader/application.fam @@ -6,5 +6,5 @@ App( cdefines=["SRV_LOADER"], requires=["gui"], stack_size=1 * 1024, - order=0, + order=90, ) diff --git a/applications/music_player/application.fam b/applications/music_player/application.fam index 938d46f5e785..30fc4d19c8ce 100644 --- a/applications/music_player/application.fam +++ b/applications/music_player/application.fam @@ -7,7 +7,7 @@ App( requires=["gui"], provides=["music_player_start"], stack_size=2 * 1024, - order=0, + order=20, ) App( @@ -15,5 +15,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="music_player_on_system_start", requires=["music_player"], - order=0, + order=30, ) diff --git a/applications/nfc/application.fam b/applications/nfc/application.fam index d60a3a7983f3..72f845d52bc1 100644 --- a/applications/nfc/application.fam +++ b/applications/nfc/application.fam @@ -8,7 +8,7 @@ App( provides=["nfc_start"], icon="A_NFC_14", stack_size=4 * 1024, - order=0, + order=30, ) App( diff --git a/applications/notification/application.fam b/applications/notification/application.fam index 7722aa86c76a..fec6bd13ad46 100644 --- a/applications/notification/application.fam +++ b/applications/notification/application.fam @@ -6,7 +6,7 @@ App( cdefines=["SRV_NOTIFICATION"], provides=["notification_settings"], stack_size=int(1.5 * 1024), - order=0, + order=100, ) App( @@ -16,5 +16,5 @@ App( entry_point="notification_settings_app", requires=["notification"], stack_size=1 * 1024, - order=0, + order=20, ) diff --git a/applications/power/application.fam b/applications/power/application.fam index 6cba8d91e2b3..1e503749a21a 100644 --- a/applications/power/application.fam +++ b/applications/power/application.fam @@ -13,7 +13,7 @@ App( "power_start", ], stack_size=1 * 1024, - order=0, + order=110, ) App( @@ -27,7 +27,7 @@ App( ], flags=["InsomniaSafe"], stack_size=1 * 1024, - order=0, + order=40, ) App( @@ -35,7 +35,7 @@ App( apptype=FlipperAppType.STARTUP, entry_point="power_on_system_start", requires=["power"], - order=0, + order=80, ) App( @@ -49,5 +49,5 @@ App( "power", ], stack_size=1 * 1024, - order=0, + order=130, ) diff --git a/applications/rpc/application.fam b/applications/rpc/application.fam index 55b94b1070bf..683396e32cb5 100644 --- a/applications/rpc/application.fam +++ b/applications/rpc/application.fam @@ -8,5 +8,5 @@ App( "cli", ], stack_size=4 * 1024, - order=0, + order=10, ) diff --git a/applications/scened_app_example/application.fam b/applications/scened_app_example/application.fam index 77414e82154e..adf9b6b8020f 100644 --- a/applications/scened_app_example/application.fam +++ b/applications/scened_app_example/application.fam @@ -5,5 +5,5 @@ App( entry_point="scened_app", cdefines=["APP_SCENED"], stack_size=1 * 1024, - order=0, + order=90, ) diff --git a/applications/snake_game/application.fam b/applications/snake_game/application.fam index c1900d54f8ff..5d6ad5276314 100644 --- a/applications/snake_game/application.fam +++ b/applications/snake_game/application.fam @@ -7,5 +7,5 @@ App( requires=["gui"], stack_size=1 * 1024, icon="A_Plugins_14", - order=0, + order=30, ) diff --git a/applications/storage/application.fam b/applications/storage/application.fam index 309c933f9f15..21089635bd85 100644 --- a/applications/storage/application.fam +++ b/applications/storage/application.fam @@ -7,7 +7,7 @@ App( requires=["storage_settings"], provides=["storage_start"], stack_size=3 * 1024, - order=0, + order=120, ) App( @@ -15,5 +15,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="storage_on_system_start", requires=["storage"], - order=0, + order=90, ) diff --git a/applications/storage_settings/application.fam b/applications/storage_settings/application.fam index d09c9a578258..1ba0ccd4433f 100644 --- a/applications/storage_settings/application.fam +++ b/applications/storage_settings/application.fam @@ -5,5 +5,5 @@ App( entry_point="storage_settings_app", requires=["storage"], stack_size=2 * 1024, - order=0, + order=30, ) diff --git a/applications/subghz/application.fam b/applications/subghz/application.fam index d149d116d9d9..543e8b906eb9 100644 --- a/applications/subghz/application.fam +++ b/applications/subghz/application.fam @@ -11,7 +11,7 @@ App( provides=["subghz_start"], icon="A_Sub1ghz_14", stack_size=2 * 1024, - order=0, + order=10, ) App( @@ -19,5 +19,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="subghz_on_system_start", requires=["subghz"], - order=0, + order=40, ) diff --git a/applications/system/application.fam b/applications/system/application.fam index abc3e0b83f7b..0fc456b2f88a 100644 --- a/applications/system/application.fam +++ b/applications/system/application.fam @@ -5,5 +5,5 @@ App( entry_point="system_settings_app", requires=["gui"], stack_size=1 * 1024, - order=0, + order=70, ) diff --git a/applications/u2f/application.fam b/applications/u2f/application.fam index 7cc8d76cc410..5a01421a9d4c 100644 --- a/applications/u2f/application.fam +++ b/applications/u2f/application.fam @@ -7,5 +7,5 @@ App( requires=["gui"], stack_size=2 * 1024, icon="A_U2F_14", - order=0, + order=80, ) diff --git a/applications/unit_tests/application.fam b/applications/unit_tests/application.fam index b53867acdd5c..54e6feaee08a 100644 --- a/applications/unit_tests/application.fam +++ b/applications/unit_tests/application.fam @@ -4,7 +4,7 @@ App( entry_point="unit_tests_on_system_start", cdefines=["APP_UNIT_TESTS"], provides=["delay_test"], - order=0, + order=100, ) App( @@ -14,5 +14,5 @@ App( entry_point="delay_test_app", stack_size=1 * 1024, requires=["unit_tests"], - order=0, + order=110, ) diff --git a/applications/updater/application.fam b/applications/updater/application.fam index 8ab1f177ea46..ab6be965604f 100644 --- a/applications/updater/application.fam +++ b/applications/updater/application.fam @@ -10,7 +10,7 @@ App( conflicts=["desktop"], entry_point="updater_srv", stack_size=2 * 1024, - order=0, + order=130, ) App( @@ -26,7 +26,7 @@ App( provides=["updater_start"], entry_point="updater_srv", stack_size=2 * 1024, - order=0, + order=10, ) App( @@ -34,5 +34,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="updater_on_system_start", requires=["updater_app"], - order=0, + order=110, ) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 7e987e9b6fab..7a3f2f84bfbf 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -92,16 +92,17 @@ class FlipperApplication: stack_size: int = 2048 icon: Optional[str] = None order: int = 0 + _appdir: Optional[str] = None class AppManager: def __init__(self): self.known_apps = {} - def get(self, appname): + def get(self, appname: str): return self.known_apps[appname] - def load_manifest(self, app_manifest_path): + def load_manifest(self, app_manifest_path: str, app_dir_name: str): if not os.path.exists(app_manifest_path): raise Exception(f"App manifest not found at path {app_manifest_path}") # print("Loading", app_manifest_path) @@ -110,7 +111,7 @@ class AppManager: def App(*args, **kw): nonlocal app_manifests - app_manifests.append(FlipperApplication(*args, **kw)) + app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name)) with open(app_manifest_path, "rt") as manifest_file: exec(manifest_file.read()) @@ -122,23 +123,24 @@ class AppManager: for app in app_manifests: self._add_known_app(app) - def _add_known_app(self, app): + def _add_known_app(self, app: FlipperApplication): if self.known_apps.get(app.appid, None): raise Exception(f"Duplicate app declaration: {app.appid}") self.known_apps[app.appid] = app - def filter_apps(self, applist): - return AppBuiltset(self, applist) + def filter_apps(self, applist: List[str]): + return AppBuildset(self, applist) -class AppBuiltset: - def __init__(self, appmgr, appnames): +class AppBuildset: + def __init__(self, appmgr: AppManager, appnames: List[str]): self.appmgr = appmgr self.appnames = set(appnames) self._orig_appnames = appnames self._process_deps() self._check_conflicts() - # print("apps_to_build", self.appnames) + self._check_unsatisfied() # unneeded? + self.apps = list(self.appmgr.get(appname) for appname in self.appnames) def _is_missing_dep(self, dep_name): return dep_name not in self.appnames @@ -153,7 +155,7 @@ class AppBuiltset: self.appmgr.get(app).provides + self.appmgr.get(app).requires, ) ) - print("provides round", provided) + # print("provides round", provided) if len(provided) == 0: break self.appnames.update(provided) @@ -187,17 +189,18 @@ class AppBuiltset: f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" ) - def apps(self): - return list(self.appmgr.get(appname) for appname in self.appnames) + def get_apps_of_type(self, apptype: FlipperAppType): + return sorted( + filter(lambda app: app.apptype == apptype, self.apps), + key=lambda app: app.order, + ) def LoadApplicationManifests(env): appmgr = env["APPMGR"] = AppManager() for entry in Glob("#/applications/*"): if isinstance(entry, SCons.Node.FS.Dir): - appmgr.load_manifest( - app_manifest_path=entry.File("application.fam").abspath - ) + appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) print(f"Loaded {len(appmgr.known_apps)} app definitions.") @@ -205,6 +208,14 @@ def LoadApplicationManifests(env): fwenv.AddMethod(LoadApplicationManifests) fwenv.LoadApplicationManifests() -# apps_buildlist = fwenv["APPMGR"].filter_apps(["updater_app", "bt", "desktop"]) -# print("apps_buildlist", apps_buildlist.apps()) +apps_buildlist = fwenv["APPMGR"].filter_apps(["updater_app", "bt", "desktop"]) +# print("apps_buildlist", apps_buildlist.apps) +for apptype in FlipperAppType: + print( + apptype, + ":", + ", ".join(app.appid for app in apps_buildlist.get_apps_of_type(apptype)), + ) + # print +# print("svc", apps_buildlist.get_apps_of_type(FlipperAppType.SERVICE)) # Exit(1) From b307211327071436eaf02693552529f8bf79008c Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 17:43:14 +0400 Subject: [PATCH 035/184] Additional deps fixes --- applications/about/application.fam | 5 ++++- applications/bad_usb/application.fam | 5 ++++- applications/bt/application.fam | 6 +++++- applications/crypto/application.fam | 2 +- applications/desktop/application.fam | 1 + applications/ibutton/application.fam | 5 ++++- applications/infrared/application.fam | 5 ++++- applications/lfrfid/application.fam | 10 ++++++++-- applications/lfrfid_debug/application.fam | 5 ++++- applications/music_player/application.fam | 5 ++++- applications/nfc/application.fam | 7 +++++-- applications/notification/application.fam | 1 + applications/subghz/application.fam | 1 + applications/subghz/scenes/subghz_scene_save_success.c | 2 +- applications/u2f/application.fam | 5 ++++- applications/updater/application.fam | 1 + 16 files changed, 52 insertions(+), 14 deletions(-) diff --git a/applications/about/application.fam b/applications/about/application.fam index ea03dc7b9eef..d97817b43765 100644 --- a/applications/about/application.fam +++ b/applications/about/application.fam @@ -4,7 +4,10 @@ App( apptype=FlipperAppType.SETTINGS, entry_point="about_settings_app", cdefines=["APP_ABOUT"], - requires=["gui"], + requires=[ + "gui", + "dialogs", + ], stack_size=1 * 1024, order=1000, ) diff --git a/applications/bad_usb/application.fam b/applications/bad_usb/application.fam index d39a012dc715..4da34f0de1b7 100644 --- a/applications/bad_usb/application.fam +++ b/applications/bad_usb/application.fam @@ -4,7 +4,10 @@ App( apptype=FlipperAppType.APP, entry_point="bad_usb_app", cdefines=["APP_BAD_USB"], - requires=["gui"], + requires=[ + "gui", + "dialogs", + ], stack_size=2 * 1024, icon="A_BadUsb_14", order=70, diff --git a/applications/bt/application.fam b/applications/bt/application.fam index 727e02c00926..248386ff305b 100644 --- a/applications/bt/application.fam +++ b/applications/bt/application.fam @@ -4,7 +4,10 @@ App( apptype=FlipperAppType.SERVICE, entry_point="bt_srv", cdefines=["SRV_BT"], - requires=["cli"], + requires=[ + "cli", + "dialogs", + ], provides=[ "bt_start", "bt_settings", @@ -43,6 +46,7 @@ App( requires=[ "bt", "gui", + "dialogs", ], order=110, ) diff --git a/applications/crypto/application.fam b/applications/crypto/application.fam index 2dec27475ccf..7771c5ed2fee 100644 --- a/applications/crypto/application.fam +++ b/applications/crypto/application.fam @@ -1,5 +1,5 @@ App( - appid="crypto", + appid="crypto_start", apptype=FlipperAppType.STARTUP, entry_point="crypto_on_system_start", order=10, diff --git a/applications/desktop/application.fam b/applications/desktop/application.fam index e80db01f8e60..5f3dcdfdac9b 100644 --- a/applications/desktop/application.fam +++ b/applications/desktop/application.fam @@ -8,6 +8,7 @@ App( "gui", "dolphin", "storage", + "input", ], provides=["desktop_settings"], conflicts=["updater"], diff --git a/applications/ibutton/application.fam b/applications/ibutton/application.fam index 3c189e64f39e..0bc6f8a9b657 100644 --- a/applications/ibutton/application.fam +++ b/applications/ibutton/application.fam @@ -4,7 +4,10 @@ App( apptype=FlipperAppType.APP, entry_point="ibutton_app", cdefines=["APP_IBUTTON"], - requires=["gui"], + requires=[ + "gui", + "dialogs", + ], provides=["ibutton_start"], icon="A_iButton_14", stack_size=2 * 1024, diff --git a/applications/infrared/application.fam b/applications/infrared/application.fam index e18c16c9bd6e..6f76ed429a61 100644 --- a/applications/infrared/application.fam +++ b/applications/infrared/application.fam @@ -4,7 +4,10 @@ App( apptype=FlipperAppType.APP, entry_point="infrared_app", cdefines=["APP_INFRARED"], - requires=["gui"], + requires=[ + "gui", + "dialogs", + ], provides=["infrared_start"], icon="A_Infrared_14", stack_size=3 * 1024, diff --git a/applications/lfrfid/application.fam b/applications/lfrfid/application.fam index 31cdffb076dc..8722bb4f8cd7 100644 --- a/applications/lfrfid/application.fam +++ b/applications/lfrfid/application.fam @@ -4,8 +4,14 @@ App( apptype=FlipperAppType.APP, entry_point="lfrfid_app", cdefines=["APP_LF_RFID"], - requires=["gui"], - provides=["lfrfid_start"], + requires=[ + "gui", + "dialogs", + ], + provides=[ + "lfrfid_start", + "lfrfid_debug", + ], icon="A_125khz_14", stack_size=2 * 1024, order=20, diff --git a/applications/lfrfid_debug/application.fam b/applications/lfrfid_debug/application.fam index c88ef5a70645..910f65cf3cb5 100644 --- a/applications/lfrfid_debug/application.fam +++ b/applications/lfrfid_debug/application.fam @@ -3,7 +3,10 @@ App( name="LF-RFID Debug", apptype=FlipperAppType.DEBUG, entry_point="lfrfid_debug_app", - requires=["gui"], + requires=[ + "gui", + "lfrfid", + ], stack_size=1 * 1024, order=100, ) diff --git a/applications/music_player/application.fam b/applications/music_player/application.fam index 30fc4d19c8ce..70e2974323a6 100644 --- a/applications/music_player/application.fam +++ b/applications/music_player/application.fam @@ -4,7 +4,10 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="music_player_app", cdefines=["APP_MUSIC_PLAYER"], - requires=["gui"], + requires=[ + "gui", + "dialogs", + ], provides=["music_player_start"], stack_size=2 * 1024, order=20, diff --git a/applications/nfc/application.fam b/applications/nfc/application.fam index 72f845d52bc1..f43ed314421f 100644 --- a/applications/nfc/application.fam +++ b/applications/nfc/application.fam @@ -4,7 +4,10 @@ App( apptype=FlipperAppType.APP, entry_point="nfc_app", cdefines=["APP_NFC"], - requires=["gui"], + requires=[ + "gui", + "dialogs", + ], provides=["nfc_start"], icon="A_NFC_14", stack_size=4 * 1024, @@ -16,5 +19,5 @@ App( apptype=FlipperAppType.STARTUP, entry_point="nfc_on_system_start", requires=["nfc"], - order=0, + order=30, ) diff --git a/applications/notification/application.fam b/applications/notification/application.fam index fec6bd13ad46..be730d510002 100644 --- a/applications/notification/application.fam +++ b/applications/notification/application.fam @@ -4,6 +4,7 @@ App( apptype=FlipperAppType.SERVICE, entry_point="notification_srv", cdefines=["SRV_NOTIFICATION"], + requires=["input"], provides=["notification_settings"], stack_size=int(1.5 * 1024), order=100, diff --git a/applications/subghz/application.fam b/applications/subghz/application.fam index 543e8b906eb9..7d31ecae50e9 100644 --- a/applications/subghz/application.fam +++ b/applications/subghz/application.fam @@ -7,6 +7,7 @@ App( requires=[ "gui", "cli", + "dialogs", ], provides=["subghz_start"], icon="A_Sub1ghz_14", diff --git a/applications/subghz/scenes/subghz_scene_save_success.c b/applications/subghz/scenes/subghz_scene_save_success.c index 53cd93ce134b..3d5c16ca3dbf 100644 --- a/applications/subghz/scenes/subghz_scene_save_success.c +++ b/applications/subghz/scenes/subghz_scene_save_success.c @@ -1,6 +1,6 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -#include "dolphin/helpers/dolphin_deed.h" +#include #include void subghz_scene_save_success_popup_callback(void* context) { diff --git a/applications/u2f/application.fam b/applications/u2f/application.fam index 5a01421a9d4c..6b32e0225307 100644 --- a/applications/u2f/application.fam +++ b/applications/u2f/application.fam @@ -4,7 +4,10 @@ App( apptype=FlipperAppType.APP, entry_point="u2f_app", cdefines=["APP_U2F"], - requires=["gui"], + requires=[ + "gui", + "dialogs", + ], stack_size=2 * 1024, icon="A_U2F_14", order=80, diff --git a/applications/updater/application.fam b/applications/updater/application.fam index ab6be965604f..a693fa6f52a4 100644 --- a/applications/updater/application.fam +++ b/applications/updater/application.fam @@ -21,6 +21,7 @@ App( requires=[ "gui", "storage", + "bt", ], conflicts=["updater"], provides=["updater_start"], From 71d267c08750d1e69397c0625baa27069f305f70 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 17:44:34 +0400 Subject: [PATCH 036/184] +Apps dump to console --- sconscfg/firmwareopts.scons | 54 +++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 7a3f2f84bfbf..92d9f3c07bb7 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -149,6 +149,7 @@ class AppBuildset: while True: provided = [] for app in self.appnames: + # print(app) provided.extend( filter( self._is_missing_dep, @@ -163,6 +164,7 @@ class AppBuildset: def _check_conflicts(self): conflicts = [] for app in self.appnames: + # print(app) if conflict_app_name := list( filter( lambda dep_name: dep_name in self.appnames, @@ -189,6 +191,12 @@ class AppBuildset: f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" ) + def get_apps_cdefs(self): + cdefs = set() + for app in self.apps: + cdefs.update(app.cdefines) + return sorted(list(cdefs)) + def get_apps_of_type(self, apptype: FlipperAppType): return sorted( filter(lambda app: app.apptype == apptype, self.apps), @@ -208,7 +216,48 @@ def LoadApplicationManifests(env): fwenv.AddMethod(LoadApplicationManifests) fwenv.LoadApplicationManifests() -apps_buildlist = fwenv["APPMGR"].filter_apps(["updater_app", "bt", "desktop"]) +# "updater_app", "bt", "desktop"" +apps_buildlist = fwenv["APPMGR"].filter_apps( + [ + "crypto_start", + # Svc + "rpc", + "bt", + "desktop", + "loader", + "power", + # Arch + "archive", + # Apps + "gpio", + "ibutton", + "infrared", + "lfrfid", + "nfc", + "subghz", + "bad_usb", + "u2f", + "updater_app", + # Settings + "passport", + "system_settings", + "about", + # Plugins + "music_player", + "snake_game", + "bt_hid", + # Debug + "blink_test", + "vibro_test", + "keypad_test", + "usb_test", + "usb_mouse", + "uart_echo", + "display_test", + "text_box_test", + "infrared_monitor", + ] +) # print("apps_buildlist", apps_buildlist.apps) for apptype in FlipperAppType: print( @@ -216,6 +265,7 @@ for apptype in FlipperAppType: ":", ", ".join(app.appid for app in apps_buildlist.get_apps_of_type(apptype)), ) - # print +print("cdefs", apps_buildlist.get_apps_cdefs()) +# print # print("svc", apps_buildlist.get_apps_of_type(FlipperAppType.SERVICE)) # Exit(1) From c9ab2dc7ccb5578cf6774a67e93b8767fde7c077 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 17:55:03 +0400 Subject: [PATCH 037/184] Integrated upstream changes --- applications/debug_tools/application.fam | 11 +++++++++++ applications/scened_app_example/application.fam | 9 --------- sconscfg/firmwareopts.scons | 1 + 3 files changed, 12 insertions(+), 9 deletions(-) delete mode 100644 applications/scened_app_example/application.fam diff --git a/applications/debug_tools/application.fam b/applications/debug_tools/application.fam index 9058fca56a52..f9390f5ed000 100644 --- a/applications/debug_tools/application.fam +++ b/applications/debug_tools/application.fam @@ -85,3 +85,14 @@ App( stack_size=1 * 1024, order=140, ) + +App( + appid="file_browser_test", + name="File Browser Test", + apptype=FlipperAppType.DEBUG, + entry_point="file_browser_app", + cdefines=["APP_FILE_BROWSER_TEST"], + requires=["gui"], + stack_size=2 * 1024, + order=150, +) diff --git a/applications/scened_app_example/application.fam b/applications/scened_app_example/application.fam deleted file mode 100644 index adf9b6b8020f..000000000000 --- a/applications/scened_app_example/application.fam +++ /dev/null @@ -1,9 +0,0 @@ -App( - appid="scened", - name="Templated Scene", - apptype=FlipperAppType.DEBUG, - entry_point="scened_app", - cdefines=["APP_SCENED"], - stack_size=1 * 1024, - order=90, -) diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 92d9f3c07bb7..99f94d828764 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -256,6 +256,7 @@ apps_buildlist = fwenv["APPMGR"].filter_apps( "display_test", "text_box_test", "infrared_monitor", + "file_browser_test", ] ) # print("apps_buildlist", apps_buildlist.apps) From 5e846765f085cb52da5af67e4b84d3244517839a Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 21:19:13 +0400 Subject: [PATCH 038/184] Dynamic applications.c generation --- firmware.scons | 114 +++++++++------- sconscfg/appmanifests.scons | 253 ++++++++++++++++++++++++++++++++++++ sconscfg/firmwareopts.scons | 212 ------------------------------ 3 files changed, 321 insertions(+), 258 deletions(-) create mode 100644 sconscfg/appmanifests.scons diff --git a/firmware.scons b/firmware.scons index e10f2d620263..0d15edbffb45 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,5 +1,7 @@ Import("env") +import os + env.Append( LIB_DIST_DIR="${BUILD_DIR}/lib", ) @@ -38,63 +40,80 @@ fwenv = env.Clone() Export("fwenv") SConscript("sconscfg/firmwareopts.scons") +SConscript("sconscfg/appmanifests.scons") if fwenv["FIRMWARE_BUILD_CFG"] == "updater": fwenv.Append( - CPPDEFINES=[ - "SRV_GUI", - "SRV_INPUT", - "SRV_NOTIFICATION", - "SRV_STORAGE", - "SRV_UPDATER", + APPS=[ + "updater", ] ) else: fwenv.Append( - CPPDEFINES=[ - "APP_ABOUT", - "APP_ACCESSOR", - "APP_ARCHIVE", - "APP_BAD_USB", - "APP_BLE_HID", - "APP_BLINK", - "APP_DISPLAY_TEST", - "APP_GPIO", - "APP_IBUTTON", - "APP_INFRARED", - "APP_INFRARED_MONITOR", - "APP_KEYPAD_TEST", - "APP_LF_RFID", - "APP_MUSIC_PLAYER", - "APP_NFC", - "APP_PASSPORT", - "APP_SNAKE_GAME", - "APP_SUBGHZ", - "APP_U2F", - "APP_UART_ECHO", - "APP_UPDATER", - "APP_USB_MOUSE", - "APP_USB_TEST", - "APP_VIBRO_TEST", - "SRV_BT", - "SRV_CLI", - "SRV_DESKTOP", - "SRV_DIALOGS", - "SRV_DOLPHIN", - "SRV_GUI", - "SRV_INPUT", - "SRV_LOADER", - "SRV_NOTIFICATION", - "SRV_POWER", - "SRV_RPC", - "SRV_STORAGE", + APPS=[ + "crypto_start", + # Svc + "rpc", + "bt", + "desktop", + "loader", + "power", + # Arch + "archive", + # Apps + "gpio", + "ibutton", + "infrared", + "lfrfid", + "nfc", + "subghz", + "bad_usb", + "u2f", + "updater_app", + # Settings + "passport", + "system_settings", + "about", + # Plugins + "music_player", + "snake_game", + "bt_hid", + # Debug + "blink_test", + "vibro_test", + "keypad_test", + "usb_test", + "usb_mouse", + "uart_echo", + "display_test", + "text_box_test", + "infrared_monitor", + "file_browser_test", ] ) +fwenv.LoadApplicationManifests() +fwenv.PrepareApplicationsBuild() + +fwenv.Append( + CPPDEFINES=fwenv["APPBUILD"].get_apps_cdefs(), +) + +Import("build_apps_c") + +apps_c = fwenv.Command( + "applications/applications.c", + [], + action=build_apps_c, +) +fwenv.Precious(apps_c) +fwenv.AlwaysBuild(apps_c) -sources = fwenv.GlobRecursive("*.c*", "applications") +sources = [apps_c] +for app_folder in fwenv["APPBUILD"].get_app_folders(): + sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder)) # Debug # print(fwenv.Dump()) @@ -124,15 +143,18 @@ firmware_elf = fwenv.Program( "fatfs", "littlefs", "subghz", + "flipperformat", "toolbox", "microtar", "usb_stm32", "ST25RFAL002", - "flipperformat", - "misc", "infrared", "appframe", "assets", + "misc", + # 2nd round + "flipperformat", + "toolbox", ], ) diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons new file mode 100644 index 000000000000..84a9063ff2da --- /dev/null +++ b/sconscfg/appmanifests.scons @@ -0,0 +1,253 @@ +Import("fwenv") + +from dataclasses import dataclass, field +from typing import List, Set, Dict, Tuple, Optional +from enum import Enum +import os +import SCons + + +class FlipperAppType(Enum): + SERVICE = "Service" + SYSTEM = "System" + APP = "App" + PLUGIN = "Plugin" + DEBUG = "Debug" + ARCHIVE = "Archive" + SETTINGS = "Settings" + STARTUP = "StartupHook" + + +@dataclass +class FlipperApplication: + appid: str + apptype: FlipperAppType + name: Optional[str] = None + entry_point: Optional[str] = None + flags: List[str] = field(default_factory=lambda: ["Default"]) + cdefines: List[str] = field(default_factory=list) + requires: List[str] = field(default_factory=list) + conflicts: List[str] = field(default_factory=list) + provides: List[str] = field(default_factory=list) + stack_size: int = 2048 + icon: Optional[str] = None + order: int = 0 + _appdir: Optional[str] = None + + +class AppManager: + def __init__(self): + self.known_apps = {} + + def get(self, appname: str): + return self.known_apps[appname] + + def load_manifest(self, app_manifest_path: str, app_dir_name: str): + if not os.path.exists(app_manifest_path): + raise Exception(f"App manifest not found at path {app_manifest_path}") + # print("Loading", app_manifest_path) + + app_manifests = [] + + def App(*args, **kw): + nonlocal app_manifests + app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name)) + + with open(app_manifest_path, "rt") as manifest_file: + exec(manifest_file.read()) + + if len(app_manifests) == 0: + Exit(f"App manifest '{app_manifest_path}' is malformed") + + # print("Built", app_manifests) + for app in app_manifests: + self._add_known_app(app) + + def _add_known_app(self, app: FlipperApplication): + if self.known_apps.get(app.appid, None): + raise Exception(f"Duplicate app declaration: {app.appid}") + self.known_apps[app.appid] = app + + def filter_apps(self, applist: List[str]): + return AppBuildset(self, applist) + + +class AppBuildset: + def __init__(self, appmgr: AppManager, appnames: List[str]): + self.appmgr = appmgr + self.appnames = set(appnames) + self._orig_appnames = appnames + self._process_deps() + self._check_conflicts() + self._check_unsatisfied() # unneeded? + self.apps = sorted( + list(self.appmgr.get(appname) for appname in self.appnames), + key=lambda app: app.appid, + ) + + def _is_missing_dep(self, dep_name): + return dep_name not in self.appnames + + def _process_deps(self): + while True: + provided = [] + for app in self.appnames: + # print(app) + provided.extend( + filter( + self._is_missing_dep, + self.appmgr.get(app).provides + self.appmgr.get(app).requires, + ) + ) + # print("provides round", provided) + if len(provided) == 0: + break + self.appnames.update(provided) + + def _check_conflicts(self): + conflicts = [] + for app in self.appnames: + # print(app) + if conflict_app_name := list( + filter( + lambda dep_name: dep_name in self.appnames, + self.appmgr.get(app).conflicts, + ) + ): + conflicts.append((app, conflict_app_name)) + + if len(conflicts): + raise Exception( + f"App conflicts for {', '.join(f'{conflict_dep[0]}: {conflict_dep[1]}' for conflict_dep in conflicts)}" + ) + + def _check_unsatisfied(self): + unsatisfied = [] + for app in self.appnames: + if missing_dep := list( + filter(self._is_missing_dep, self.appmgr.get(app).requires) + ): + unsatisfied.append((app, missing_dep)) + + if len(unsatisfied): + raise Exception( + f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" + ) + + def get_apps_cdefs(self): + cdefs = set() + for app in self.apps: + cdefs.update(app.cdefines) + return sorted(list(cdefs)) + + def get_apps_of_type(self, apptype: FlipperAppType): + return sorted( + filter(lambda app: app.apptype == apptype, self.apps), + key=lambda app: app.order, + ) + + def get_app_folders(self): + return sorted(set(app._appdir for app in self.apps)) + + +class ApplicationsCGenerator: + APP_TYPE_MAP = { + FlipperAppType.SERVICE: ("FlipperApplication", "FLIPPER_SERVICES"), + FlipperAppType.SYSTEM: ("FlipperApplication", "FLIPPER_SYSTEM_APPS"), + FlipperAppType.APP: ("FlipperApplication", "FLIPPER_APPS"), + FlipperAppType.PLUGIN: ("FlipperApplication", "FLIPPER_PLUGINS"), + FlipperAppType.DEBUG: ("FlipperApplication", "FLIPPER_DEBUG_APPS"), + FlipperAppType.SETTINGS: ("FlipperApplication", "FLIPPER_SETTINGS_APPS"), + FlipperAppType.STARTUP: ("FlipperOnStartHook", "FLIPPER_ON_SYSTEM_START"), + } + + def __init__(self, buildset: AppBuildset): + self.buildset = buildset + + def get_app_ep_forward(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return f"extern void {app.entry_point}();" + return f"extern int32_t {app.entry_point}(void* p);" + + def get_app_descr(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return app.entry_point + return f""" + {{.app = {app.entry_point}, + .name = "{app.name}", + .stack_size = {app.stack_size}, + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" + + def generate(self): + contents = ['#include "applications.h"', "#include "] + contents.extend(map(self.get_app_ep_forward, self.buildset.apps)) + for apptype in self.APP_TYPE_MAP: + entry_type, entry_block = self.APP_TYPE_MAP[apptype] + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append( + ",\n".join( + map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) + ) + ) + contents.append("};") + contents.append( + f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" + ) + + archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) + if archive_app: + contents.append( + f"const FlipperApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};" + ) + + return "\n".join(contents) + + +def LoadApplicationManifests(env): + appmgr = env["APPMGR"] = AppManager() + for entry in Glob("#/applications/*"): + if isinstance(entry, SCons.Node.FS.Dir): + appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) + + print(f"Loaded {len(appmgr.known_apps)} app definitions.") + + +def PrepareApplicationsBuild(env): + apps = fwenv["APPS"] + apps_buildlist = fwenv["APPBUILD"] = fwenv["APPMGR"].filter_apps(apps) + for apptype in FlipperAppType: + print( + apptype, + ":", + ", ".join(app.appid for app in apps_buildlist.get_apps_of_type(apptype)), + ) + # print("CDefs", apps_buildlist.get_apps_cdefs()) + + +fwenv.AddMethod(LoadApplicationManifests) +fwenv.AddMethod(PrepareApplicationsBuild) + + +def build_apps_c(target, source, env): + target_file_name = target[0].path + print("target_file_name", target_file_name) + + gen = ApplicationsCGenerator(fwenv["APPBUILD"]) + new_apps_def = gen.generate() + + current_apps_def = None + try: + with open(target_file_name, "r") as file: + current_apps_def = file.read() + except EnvironmentError as e: + print(e) + + if current_apps_def != new_apps_def: + # print("Saving to ", target_file_name) + print("Application definitions were updated") + with open(target_file_name, "w") as file: + file.write(new_apps_def) + + +Export("build_apps_c") diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 99f94d828764..84c2a68c1508 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -58,215 +58,3 @@ else: "-Tfirmware/targets/f${TARGET_HW}/stm32wb55xx_flash.ld", ], ) - - -from dataclasses import dataclass, field -from typing import List, Set, Dict, Tuple, Optional -from enum import Enum -import os -import SCons - - -class FlipperAppType(Enum): - SERVICE = "Service" - SYSTEM = "System" - APP = "App" - PLUGIN = "Plugin" - DEBUG = "Debug" - ARCHIVE = "Archive" - SETTINGS = "Settings" - STARTUP = "StartupHook" - - -@dataclass -class FlipperApplication: - appid: str - apptype: FlipperAppType - name: Optional[str] = None - entry_point: Optional[str] = None - flags: List[str] = field(default_factory=lambda: ["Default"]) - cdefines: List[str] = field(default_factory=list) - requires: List[str] = field(default_factory=list) - conflicts: List[str] = field(default_factory=list) - provides: List[str] = field(default_factory=list) - stack_size: int = 2048 - icon: Optional[str] = None - order: int = 0 - _appdir: Optional[str] = None - - -class AppManager: - def __init__(self): - self.known_apps = {} - - def get(self, appname: str): - return self.known_apps[appname] - - def load_manifest(self, app_manifest_path: str, app_dir_name: str): - if not os.path.exists(app_manifest_path): - raise Exception(f"App manifest not found at path {app_manifest_path}") - # print("Loading", app_manifest_path) - - app_manifests = [] - - def App(*args, **kw): - nonlocal app_manifests - app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name)) - - with open(app_manifest_path, "rt") as manifest_file: - exec(manifest_file.read()) - - if len(app_manifests) == 0: - Exit(f"App manifest '{app_manifest_path}' is malformed") - - # print("Built", app_manifests) - for app in app_manifests: - self._add_known_app(app) - - def _add_known_app(self, app: FlipperApplication): - if self.known_apps.get(app.appid, None): - raise Exception(f"Duplicate app declaration: {app.appid}") - self.known_apps[app.appid] = app - - def filter_apps(self, applist: List[str]): - return AppBuildset(self, applist) - - -class AppBuildset: - def __init__(self, appmgr: AppManager, appnames: List[str]): - self.appmgr = appmgr - self.appnames = set(appnames) - self._orig_appnames = appnames - self._process_deps() - self._check_conflicts() - self._check_unsatisfied() # unneeded? - self.apps = list(self.appmgr.get(appname) for appname in self.appnames) - - def _is_missing_dep(self, dep_name): - return dep_name not in self.appnames - - def _process_deps(self): - while True: - provided = [] - for app in self.appnames: - # print(app) - provided.extend( - filter( - self._is_missing_dep, - self.appmgr.get(app).provides + self.appmgr.get(app).requires, - ) - ) - # print("provides round", provided) - if len(provided) == 0: - break - self.appnames.update(provided) - - def _check_conflicts(self): - conflicts = [] - for app in self.appnames: - # print(app) - if conflict_app_name := list( - filter( - lambda dep_name: dep_name in self.appnames, - self.appmgr.get(app).conflicts, - ) - ): - conflicts.append((app, conflict_app_name)) - - if len(conflicts): - raise Exception( - f"App conflicts for {', '.join(f'{conflict_dep[0]}: {conflict_dep[1]}' for conflict_dep in conflicts)}" - ) - - def _check_unsatisfied(self): - unsatisfied = [] - for app in self.appnames: - if missing_dep := list( - filter(self._is_missing_dep, self.appmgr.get(app).requires) - ): - unsatisfied.append((app, missing_dep)) - - if len(unsatisfied): - raise Exception( - f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" - ) - - def get_apps_cdefs(self): - cdefs = set() - for app in self.apps: - cdefs.update(app.cdefines) - return sorted(list(cdefs)) - - def get_apps_of_type(self, apptype: FlipperAppType): - return sorted( - filter(lambda app: app.apptype == apptype, self.apps), - key=lambda app: app.order, - ) - - -def LoadApplicationManifests(env): - appmgr = env["APPMGR"] = AppManager() - for entry in Glob("#/applications/*"): - if isinstance(entry, SCons.Node.FS.Dir): - appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) - - print(f"Loaded {len(appmgr.known_apps)} app definitions.") - - -fwenv.AddMethod(LoadApplicationManifests) -fwenv.LoadApplicationManifests() - -# "updater_app", "bt", "desktop"" -apps_buildlist = fwenv["APPMGR"].filter_apps( - [ - "crypto_start", - # Svc - "rpc", - "bt", - "desktop", - "loader", - "power", - # Arch - "archive", - # Apps - "gpio", - "ibutton", - "infrared", - "lfrfid", - "nfc", - "subghz", - "bad_usb", - "u2f", - "updater_app", - # Settings - "passport", - "system_settings", - "about", - # Plugins - "music_player", - "snake_game", - "bt_hid", - # Debug - "blink_test", - "vibro_test", - "keypad_test", - "usb_test", - "usb_mouse", - "uart_echo", - "display_test", - "text_box_test", - "infrared_monitor", - "file_browser_test", - ] -) -# print("apps_buildlist", apps_buildlist.apps) -for apptype in FlipperAppType: - print( - apptype, - ":", - ", ".join(app.appid for app in apps_buildlist.get_apps_of_type(apptype)), - ) -print("cdefs", apps_buildlist.get_apps_cdefs()) -# print -# print("svc", apps_buildlist.get_apps_of_type(FlipperAppType.SERVICE)) -# Exit(1) From 77a4ced77e735a6259eb3d7ab68255942eee705b Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 22:09:51 +0400 Subject: [PATCH 039/184] Build: Fixed RAM_EXEC processing & related flags --- lib/STM32CubeWB.scons | 7 +++++++ lib/flipper_format/SConscript | 8 ++++++++ sconscfg/environ.scons | 7 +++++++ sconscfg/firmwareopts.scons | 5 ----- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons index e0ea38775c2d..4e9ea95cd71d 100644 --- a/lib/STM32CubeWB.scons +++ b/lib/STM32CubeWB.scons @@ -22,6 +22,13 @@ env.Append( ], ) +if env["RAM_EXEC"]: + env.Append( + CPPDEFINES=[ + "VECT_TAB_SRAM", + ], + ) + libenv = env.Clone() libenv.MergeFlags(lib_flags) diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript index ae27b4af0aba..788feae7f6ca 100644 --- a/lib/flipper_format/SConscript +++ b/lib/flipper_format/SConscript @@ -11,6 +11,14 @@ env.Append( libenv = env.Clone() libenv.MergeFlags(lib_flags) +if libenv["RAM_EXEC"]: + libenv.Append( + CPPDEFINES=[ + "FLIPPER_STREAM_LITE", + ], + ) + + sources = libenv.GlobRecursive("*.c", ".") lib = libenv.StaticLibrary("flipperformat", sources) diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 9d1d61fc366a..fce59586befa 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -161,4 +161,11 @@ lib_flags = { ], } +if env["RAM_EXEC"]: + env.Append( + CPPDEFINES=[ + "FURI_RAM_EXEC", + ] + ) + Export("env", "lib_flags") diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index 84c2a68c1508..b1fe7c88f09d 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -41,11 +41,6 @@ fwenv.Append( if fwenv["FIRMWARE_BUILD_CFG"] == "updater": fwenv.Append( - CPPDEFINES=[ - "FURI_RAM_EXEC", - "VECT_TAB_SRAM", - "FLIPPER_STREAM_LITE", - ], IMAGE_BASE_ADDRESS="0x20000000", LINKFLAGS=[ "-Tfirmware/targets/f${TARGET_HW}/stm32wb55xx_ram_fw.ld", From e97c26ddbc789026b527796d0b083a3420c3be77 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 5 Jun 2022 22:20:30 +0400 Subject: [PATCH 040/184] Build: always regenerating apps.c --- firmware.scons | 2 +- sconscfg/appmanifests.scons | 16 ++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/firmware.scons b/firmware.scons index 0d15edbffb45..9ea18e888edf 100644 --- a/firmware.scons +++ b/firmware.scons @@ -15,6 +15,7 @@ env.Append( ], ) + env.Append( CPPPATH=[ "#/core", @@ -107,7 +108,6 @@ apps_c = fwenv.Command( [], action=build_apps_c, ) -fwenv.Precious(apps_c) fwenv.AlwaysBuild(apps_c) diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index 84a9063ff2da..18f83ff7578d 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -234,20 +234,8 @@ def build_apps_c(target, source, env): print("target_file_name", target_file_name) gen = ApplicationsCGenerator(fwenv["APPBUILD"]) - new_apps_def = gen.generate() - - current_apps_def = None - try: - with open(target_file_name, "r") as file: - current_apps_def = file.read() - except EnvironmentError as e: - print(e) - - if current_apps_def != new_apps_def: - # print("Saving to ", target_file_name) - print("Application definitions were updated") - with open(target_file_name, "w") as file: - file.write(new_apps_def) + with open(target_file_name, "w") as file: + file.write(gen.generate()) Export("build_apps_c") From 1887bb2e80d57418d92d55f034b3348f0f3bffc7 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 01:05:07 +0400 Subject: [PATCH 041/184] Build: added missing c++-related flags; added optimization flag to mtar --- lib/microtar.scons | 5 ++++- sconscfg/cc.scons | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/microtar.scons b/lib/microtar.scons index 83bfa548d5f5..10d378cd0d50 100644 --- a/lib/microtar.scons +++ b/lib/microtar.scons @@ -10,7 +10,10 @@ env.Append( libenv = env.Clone() libenv.MergeFlags(lib_flags) -# TODO: consider adding optimization flags for microtar here + +libenv.Append( + CPPDEFINES=["MICROTAR_DISABLE_API_CHECKS"], +) sources = libenv.GlobRecursive("*.c", "microtar/src") diff --git a/sconscfg/cc.scons b/sconscfg/cc.scons index dbc30fcccb09..1a55bb058396 100644 --- a/sconscfg/cc.scons +++ b/sconscfg/cc.scons @@ -7,6 +7,10 @@ env.Append( ], CXXFLAGS=[ "-std=c++17", + "-fno-rtti", + "-fno-use-cxa-atexit", + "-fno-exceptions", + "-fno-threadsafe-statics", ], CCFLAGS=[ "--specs=nosys.specs", From a9a697931604d4b0b438bc804e702f052e7f548c Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 14:09:20 +0400 Subject: [PATCH 042/184] Build: Compile flags reorg --- firmware.scons | 23 +++++++++++++++++++++++ sconscfg/cc.scons | 27 ++++----------------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/firmware.scons b/firmware.scons index 9ea18e888edf..b39a9e6ae4d9 100644 --- a/firmware.scons +++ b/firmware.scons @@ -131,6 +131,29 @@ fwenv.AlwaysBuild(build_version) # Full firmware definition +fwenv.Append( + CCFLAGS=[ + # "--specs=nosys.specs", + # "--specs=nano.specs", + ], + LINKFLAGS=[ + "-specs=nano.specs", + "-specs=nosys.specs", + "-Wl,--start-group", + "-lstdc++", + "-lsupc++", + "-Wl,--end-group", + "-Wl,--gc-sections", + "-Wl,--undefined=uxTopUsedPriority", + "-Wl,--wrap,_malloc_r", + "-Wl,--wrap,_free_r", + "-Wl,--wrap,_calloc_r", + "-Wl,--wrap,_realloc_r", + "-u _printf_float", + "-n", + ], +) + firmware_elf = fwenv.Program( "${FIRMWARE_BUILD_CFG}", sources, diff --git a/sconscfg/cc.scons b/sconscfg/cc.scons index 1a55bb058396..d11fdeecd1f5 100644 --- a/sconscfg/cc.scons +++ b/sconscfg/cc.scons @@ -13,30 +13,25 @@ env.Append( "-fno-threadsafe-statics", ], CCFLAGS=[ - "--specs=nosys.specs", - "--specs=nano.specs", "-mcpu=cortex-m4", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", - "-MMD", - "-MP", "-mthumb", + "-MMD", + # "-MP", "-Wall", - # "-Werror", + "-Werror", "-Wextra", "-Wno-address-of-packed-member", "-Wredundant-decls", "-fdata-sections", "-ffunction-sections", - "-fno-diagnostics-show-caret", + # "-fno-diagnostics-show-caret", "-fno-math-errno", "-fstack-usage", ], CPPDEFINES=[ "_GNU_SOURCE", - # STM32WB - "__STM32WB55_SUBFAMILY", - "__STM32WBxx_FAMILY", "STM32WB", "STM32WB55xx", ], @@ -45,24 +40,10 @@ env.Append( env.Append( LINKFLAGS=[ - "-u _printf_float", - "-Wl,--wrap,_malloc_r", - "-Wl,--wrap,_free_r", - "-Wl,--wrap,_calloc_r", - "-Wl,--wrap,_realloc_r", "-mcpu=cortex-m4", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", "-mlittle-endian", "-mthumb", - "-specs=nano.specs", - "-specs=nosys.specs", - "-Wl,--start-group", - "-lstdc++", - "-lsupc++", - "-Wl,--end-group", - "-Wl,--gc-sections", - "-Wl,--undefined=uxTopUsedPriority", - "-n", ] ) From ea5eb56c3f9603a96bdbfdaa49351da0209c6c22 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 14:49:46 +0400 Subject: [PATCH 043/184] Build: lowercase libs; moved around more flags --- firmware.scons | 4 ++-- lib/ST25RFAL002/SConscript | 2 +- lib/STM32CubeWB.scons | 4 +++- lib/appframe.scons | 2 -- sconscfg/cc.scons | 8 +------- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/firmware.scons b/firmware.scons index b39a9e6ae4d9..98880183c9e8 100644 --- a/firmware.scons +++ b/firmware.scons @@ -161,7 +161,7 @@ firmware_elf = fwenv.Program( "flipper${TARGET_HW}", "core", "freertos", - "STM32CubeWB", + "stm32cubewb", "hwdrivers", "fatfs", "littlefs", @@ -170,7 +170,7 @@ firmware_elf = fwenv.Program( "toolbox", "microtar", "usb_stm32", - "ST25RFAL002", + "st25rfal002", "infrared", "appframe", "assets", diff --git a/lib/ST25RFAL002/SConscript b/lib/ST25RFAL002/SConscript index f28386ec96f3..39d8728bb27f 100644 --- a/lib/ST25RFAL002/SConscript +++ b/lib/ST25RFAL002/SConscript @@ -15,6 +15,6 @@ libenv.MergeFlags(lib_flags) sources = libenv.GlobRecursive("*.c", ".") -lib = libenv.StaticLibrary("ST25RFAL002", sources) +lib = libenv.StaticLibrary("st25rfal002", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons index 4e9ea95cd71d..5b472d559ed3 100644 --- a/lib/STM32CubeWB.scons +++ b/lib/STM32CubeWB.scons @@ -17,6 +17,8 @@ env.Append( "#/lib/STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities", ], CPPDEFINES=[ + "STM32WB", + "STM32WB55xx", "USE_FULL_ASSERT", "USE_FULL_LL_DRIVER", ], @@ -58,6 +60,6 @@ sources += [ "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/stm_list.c", ] -lib = libenv.StaticLibrary("STM32CubeWB", sources) +lib = libenv.StaticLibrary("stm32cubewb", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/appframe.scons b/lib/appframe.scons index e9576bb6a041..e76d4c11125d 100644 --- a/lib/appframe.scons +++ b/lib/appframe.scons @@ -3,7 +3,6 @@ Import("env", "lib_flags") env.Append( CPPPATH=[ "#/lib/app-scened-template", - "#/lib/app-template", "#/lib/callback-connector", "#/assets/compiled", ], @@ -19,7 +18,6 @@ sources = [] recurse_dirs = [ "app-scened-template", "callback-connector", - "app-template", ] for recurse_dir in recurse_dirs: diff --git a/sconscfg/cc.scons b/sconscfg/cc.scons index d11fdeecd1f5..34aea1cc13da 100644 --- a/sconscfg/cc.scons +++ b/sconscfg/cc.scons @@ -32,18 +32,12 @@ env.Append( ], CPPDEFINES=[ "_GNU_SOURCE", - "STM32WB", - "STM32WB55xx", ], -) - - -env.Append( LINKFLAGS=[ "-mcpu=cortex-m4", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", "-mlittle-endian", "-mthumb", - ] + ], ) From bc69d3e7b30ce84ef5b2bf95b60787abcde73546 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 15:42:34 +0400 Subject: [PATCH 044/184] Build: Added app metapackages --- applications/debug_tools/application.fam | 17 ++++++++++ applications/meta/application.fam | 41 ++++++++++++++++++++++++ firmware.scons | 32 +++--------------- sconscfg/appmanifests.scons | 2 ++ 4 files changed, 65 insertions(+), 27 deletions(-) create mode 100644 applications/meta/application.fam diff --git a/applications/debug_tools/application.fam b/applications/debug_tools/application.fam index f9390f5ed000..8cb495b0c4af 100644 --- a/applications/debug_tools/application.fam +++ b/applications/debug_tools/application.fam @@ -1,3 +1,20 @@ +App( + appid="debug_apps", + name="Basic debug apps bundle", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "blink_test", + "vibro_test", + "keypad_test", + "usb_test", + "usb_mouse", + "uart_echo", + "display_test", + "text_box_test", + "file_browser_test", + ], +) + App( appid="blink_test", name="Blink Test", diff --git a/applications/meta/application.fam b/applications/meta/application.fam new file mode 100644 index 000000000000..a447b94ae4d4 --- /dev/null +++ b/applications/meta/application.fam @@ -0,0 +1,41 @@ +App( + appid="basic_services", + name="Basic services", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "rpc", + "bt", + "desktop", + "loader", + "power", + ], +) + + +App( + appid="basic_apps", + name="Basic applications for main menu", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "gpio", + "ibutton", + "infrared", + "lfrfid", + "nfc", + "subghz", + "bad_usb", + "u2f", + ], +) + + +App( + appid="basic_plugins", + name="Basic applications for plug-in menu", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "music_player", + "snake_game", + "bt_hid", + ], +) diff --git a/firmware.scons b/firmware.scons index 98880183c9e8..e76240b9f099 100644 --- a/firmware.scons +++ b/firmware.scons @@ -55,42 +55,20 @@ else: APPS=[ "crypto_start", # Svc - "rpc", - "bt", - "desktop", - "loader", - "power", - # Arch - "archive", + "basic_services", # Apps - "gpio", - "ibutton", - "infrared", - "lfrfid", - "nfc", - "subghz", - "bad_usb", - "u2f", + "basic_apps", "updater_app", + "archive", # Settings "passport", "system_settings", "about", # Plugins - "music_player", - "snake_game", - "bt_hid", + "basic_plugins", # Debug - "blink_test", - "vibro_test", - "keypad_test", - "usb_test", - "usb_mouse", - "uart_echo", - "display_test", - "text_box_test", + "debug_apps", "infrared_monitor", - "file_browser_test", ] ) diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index 18f83ff7578d..77bf77427710 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -16,6 +16,8 @@ class FlipperAppType(Enum): ARCHIVE = "Archive" SETTINGS = "Settings" STARTUP = "StartupHook" + EXTMODULE = "External" + METAPACKAGE = "Package" @dataclass From 09f3e2af2632d0b433f76a7fe4974473ac7b1121 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 16:11:38 +0400 Subject: [PATCH 045/184] Build: Filtering metapackages from apps.c --- sconscfg/appmanifests.scons | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index 77bf77427710..3b53dd6d3bf5 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -75,6 +75,17 @@ class AppManager: class AppBuildset: + BUILTIN_APP_TYPES = ( + FlipperAppType.SERVICE, + FlipperAppType.SYSTEM, + FlipperAppType.APP, + FlipperAppType.PLUGIN, + FlipperAppType.DEBUG, + FlipperAppType.ARCHIVE, + FlipperAppType.SETTINGS, + FlipperAppType.STARTUP, + ) + def __init__(self, appmgr: AppManager, appnames: List[str]): self.appmgr = appmgr self.appnames = set(appnames) @@ -83,7 +94,12 @@ class AppBuildset: self._check_conflicts() self._check_unsatisfied() # unneeded? self.apps = sorted( - list(self.appmgr.get(appname) for appname in self.appnames), + list( + filter( + lambda app: app.apptype in self.BUILTIN_APP_TYPES, + map(self.appmgr.get, self.appnames), + ) + ), key=lambda app: app.appid, ) @@ -218,7 +234,7 @@ def LoadApplicationManifests(env): def PrepareApplicationsBuild(env): apps = fwenv["APPS"] apps_buildlist = fwenv["APPBUILD"] = fwenv["APPMGR"].filter_apps(apps) - for apptype in FlipperAppType: + for apptype in AppBuildset.BUILTIN_APP_TYPES: print( apptype, ":", From 605926a7e955e29ffe49b71dad6a77f071a42b8e Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 16:17:49 +0400 Subject: [PATCH 046/184] Build: better app banner formatting --- sconscfg/appmanifests.scons | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index 3b53dd6d3bf5..d70dbda4120e 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -234,10 +234,10 @@ def LoadApplicationManifests(env): def PrepareApplicationsBuild(env): apps = fwenv["APPS"] apps_buildlist = fwenv["APPBUILD"] = fwenv["APPMGR"].filter_apps(apps) + print("Building firmware with modules:") for apptype in AppBuildset.BUILTIN_APP_TYPES: print( - apptype, - ":", + f"\n{apptype.value}:\n\t", ", ".join(app.appid for app in apps_buildlist.get_apps_of_type(apptype)), ) # print("CDefs", apps_buildlist.get_apps_cdefs()) From 107de40a07d9ebd05282ecc2d93ee6ffb13caa03 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 16:33:51 +0400 Subject: [PATCH 047/184] Build: skip empty banner categories --- sconscfg/appmanifests.scons | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index d70dbda4120e..dad010c8f47e 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -236,10 +236,12 @@ def PrepareApplicationsBuild(env): apps_buildlist = fwenv["APPBUILD"] = fwenv["APPMGR"].filter_apps(apps) print("Building firmware with modules:") for apptype in AppBuildset.BUILTIN_APP_TYPES: - print( - f"\n{apptype.value}:\n\t", - ", ".join(app.appid for app in apps_buildlist.get_apps_of_type(apptype)), - ) + app_sublist = apps_buildlist.get_apps_of_type(apptype) + if app_sublist: + print( + f"{apptype.value}:\n\t", + ", ".join(app.appid for app in app_sublist), + ) # print("CDefs", apps_buildlist.get_apps_cdefs()) From 26aa97cbed3eda28102b7241b018d5fd32a8934f Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 17:47:43 +0400 Subject: [PATCH 048/184] Build: Added support for external applications; invoke with build "appext" target --- applications/snake_game_ext/application.fam | 8 + applications/snake_game_ext/main.c | 9 + applications/snake_game_ext/snake_game.c | 420 ++++++++++++++++++++ applications/snake_game_ext/start.c | 5 + firmware.scons | 40 +- sconscfg/appmanifests.scons | 38 +- sconscfg/firmwareopts.scons | 11 +- 7 files changed, 509 insertions(+), 22 deletions(-) create mode 100644 applications/snake_game_ext/application.fam create mode 100644 applications/snake_game_ext/main.c create mode 100644 applications/snake_game_ext/snake_game.c create mode 100644 applications/snake_game_ext/start.c diff --git a/applications/snake_game_ext/application.fam b/applications/snake_game_ext/application.fam new file mode 100644 index 000000000000..edfa20e2e5be --- /dev/null +++ b/applications/snake_game_ext/application.fam @@ -0,0 +1,8 @@ +App( + appid="snake_game_ext", + name="Snake Game Ext", + apptype=FlipperAppType.EXTERNAL, + entry_point="_start", + requires=[], + stack_size=1 * 1024, +) diff --git a/applications/snake_game_ext/main.c b/applications/snake_game_ext/main.c new file mode 100644 index 000000000000..1a93d9f11088 --- /dev/null +++ b/applications/snake_game_ext/main.c @@ -0,0 +1,9 @@ +#include +#include + +extern int32_t snake_game_app(void* p); + +int main(void) { + snake_game_app(NULL); + return 0; +} \ No newline at end of file diff --git a/applications/snake_game_ext/snake_game.c b/applications/snake_game_ext/snake_game.c new file mode 100644 index 000000000000..bb9e207de255 --- /dev/null +++ b/applications/snake_game_ext/snake_game.c @@ -0,0 +1,420 @@ +#include +#include +#include +#include + +typedef struct { + // +-----x + // | + // | + // y + uint8_t x; + uint8_t y; +} Point; + +typedef enum { + GameStateLife, + + // https://melmagazine.com/en-us/story/snake-nokia-6110-oral-history-taneli-armanto + // Armanto: While testing the early versions of the game, I noticed it was hard + // to control the snake upon getting close to and edge but not crashing — especially + // in the highest speed levels. I wanted the highest level to be as fast as I could + // possibly make the device "run," but on the other hand, I wanted to be friendly + // and help the player manage that level. Otherwise it might not be fun to play. So + // I implemented a little delay. A few milliseconds of extra time right before + // the player crashes, during which she can still change the directions. And if + // she does, the game continues. + GameStateLastChance, + + GameStateGameOver, +} GameState; + +typedef enum { + DirectionUp, + DirectionRight, + DirectionDown, + DirectionLeft, +} Direction; + +#define MAX_SNAKE_LEN 253 + +typedef struct { + Point points[MAX_SNAKE_LEN]; + uint16_t len; + Direction currentMovement; + Direction nextMovement; // if backward of currentMovement, ignore + Point fruit; + GameState state; +} SnakeState; + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + EventType type; + InputEvent input; +} SnakeEvent; + +static void snake_game_render_callback(Canvas* const canvas, void* ctx) { + const SnakeState* snake_state = acquire_mutex((ValueMutex*)ctx, 25); + if(snake_state == NULL) { + return; + } + + // Before the function is called, the state is set with the canvas_reset(canvas) + + // Frame + canvas_draw_frame(canvas, 0, 0, 128, 64); + + // Fruit + Point f = snake_state->fruit; + f.x = f.x * 4 + 1; + f.y = f.y * 4 + 1; + canvas_draw_rframe(canvas, f.x, f.y, 6, 6, 2); + + // Snake + for(uint16_t i = 0; i < snake_state->len; i++) { + Point p = snake_state->points[i]; + p.x = p.x * 4 + 2; + p.y = p.y * 4 + 2; + canvas_draw_box(canvas, p.x, p.y, 4, 4); + } + + // Game Over banner + if(snake_state->state == GameStateGameOver) { + // Screen is 128x64 px + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 34, 20, 62, 24); + + canvas_set_color(canvas, ColorBlack); + canvas_draw_frame(canvas, 34, 20, 62, 24); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 37, 31, "Game Over"); + + canvas_set_font(canvas, FontSecondary); + char buffer[12]; + snprintf(buffer, sizeof(buffer), "Score: %u", snake_state->len - 7); + canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); + } + + release_mutex((ValueMutex*)ctx, snake_state); +} + +static void snake_game_input_callback(InputEvent* input_event, osMessageQueueId_t event_queue) { + furi_assert(event_queue); + + SnakeEvent event = {.type = EventTypeKey, .input = *input_event}; + osMessageQueuePut(event_queue, &event, 0, osWaitForever); +} + +static void snake_game_update_timer_callback(osMessageQueueId_t event_queue) { + furi_assert(event_queue); + + SnakeEvent event = {.type = EventTypeTick}; + osMessageQueuePut(event_queue, &event, 0, 0); +} + +static void snake_game_init_game(SnakeState* const snake_state) { + Point p[] = {{8, 6}, {7, 6}, {6, 6}, {5, 6}, {4, 6}, {3, 6}, {2, 6}}; + memcpy(snake_state->points, p, sizeof(p)); + + snake_state->len = 7; + + snake_state->currentMovement = DirectionRight; + + snake_state->nextMovement = DirectionRight; + + Point f = {18, 6}; + snake_state->fruit = f; + + snake_state->state = GameStateLife; +} + +static Point snake_game_get_new_fruit(SnakeState const* const snake_state) { + // 1 bit for each point on the playing field where the snake can turn + // and where the fruit can appear + uint16_t buffer[8]; + memset(buffer, 0, sizeof(buffer)); + uint8_t empty = 8 * 16; + + for(uint16_t i = 0; i < snake_state->len; i++) { + Point p = snake_state->points[i]; + + if(p.x % 2 != 0 || p.y % 2 != 0) { + continue; + } + p.x /= 2; + p.y /= 2; + + buffer[p.y] |= 1 << p.x; + empty--; + } + // Bit set if snake use that playing field + + uint16_t newFruit = rand() % empty; + + // Skip random number of _empty_ fields + for(uint8_t y = 0; y < 8; y++) { + for(uint16_t x = 0, mask = 1; x < 16; x += 1, mask <<= 1) { + if((buffer[y] & mask) == 0) { + if(newFruit == 0) { + Point p = { + .x = x * 2, + .y = y * 2, + }; + return p; + } + newFruit--; + } + } + } + // We will never be here + Point p = {0, 0}; + return p; +} + +static bool snake_game_collision_with_frame(Point const next_step) { + // if x == 0 && currentMovement == left then x - 1 == 255 , + // so check only x > right border + return next_step.x > 30 || next_step.y > 14; +} + +static bool + snake_game_collision_with_tail(SnakeState const* const snake_state, Point const next_step) { + for(uint16_t i = 0; i < snake_state->len; i++) { + Point p = snake_state->points[i]; + if(p.x == next_step.x && p.y == next_step.y) { + return true; + } + } + + return false; +} + +static Direction snake_game_get_turn_snake(SnakeState const* const snake_state) { + switch(snake_state->currentMovement) { + case DirectionUp: + switch(snake_state->nextMovement) { + case DirectionRight: + return DirectionRight; + case DirectionLeft: + return DirectionLeft; + default: + return snake_state->currentMovement; + } + case DirectionRight: + switch(snake_state->nextMovement) { + case DirectionUp: + return DirectionUp; + case DirectionDown: + return DirectionDown; + default: + return snake_state->currentMovement; + } + case DirectionDown: + switch(snake_state->nextMovement) { + case DirectionRight: + return DirectionRight; + case DirectionLeft: + return DirectionLeft; + default: + return snake_state->currentMovement; + } + default: // case DirectionLeft: + switch(snake_state->nextMovement) { + case DirectionUp: + return DirectionUp; + case DirectionDown: + return DirectionDown; + default: + return snake_state->currentMovement; + } + } +} + +static Point snake_game_get_next_step(SnakeState const* const snake_state) { + Point next_step = snake_state->points[0]; + switch(snake_state->currentMovement) { + // +-----x + // | + // | + // y + case DirectionUp: + next_step.y--; + break; + case DirectionRight: + next_step.x++; + break; + case DirectionDown: + next_step.y++; + break; + case DirectionLeft: + next_step.x--; + break; + } + return next_step; +} + +static void snake_game_move_snake(SnakeState* const snake_state, Point const next_step) { + memmove(snake_state->points + 1, snake_state->points, snake_state->len * sizeof(Point)); + snake_state->points[0] = next_step; +} + +static void snake_game_process_game_step(SnakeState* const snake_state) { + if(snake_state->state == GameStateGameOver) { + return; + } + + bool can_turn = (snake_state->points[0].x % 2 == 0) && (snake_state->points[0].y % 2 == 0); + if(can_turn) { + snake_state->currentMovement = snake_game_get_turn_snake(snake_state); + } + + Point next_step = snake_game_get_next_step(snake_state); + + bool crush = snake_game_collision_with_frame(next_step); + if(crush) { + if(snake_state->state == GameStateLife) { + snake_state->state = GameStateLastChance; + return; + } else if(snake_state->state == GameStateLastChance) { + snake_state->state = GameStateGameOver; + return; + } + } else { + if(snake_state->state == GameStateLastChance) { + snake_state->state = GameStateLife; + } + } + + crush = snake_game_collision_with_tail(snake_state, next_step); + if(crush) { + snake_state->state = GameStateGameOver; + return; + } + + bool eatFruit = (next_step.x == snake_state->fruit.x) && (next_step.y == snake_state->fruit.y); + if(eatFruit) { + snake_state->len++; + if(snake_state->len >= MAX_SNAKE_LEN) { + snake_state->state = GameStateGameOver; + return; + } + } + + snake_game_move_snake(snake_state, next_step); + + if(eatFruit) { + snake_state->fruit = snake_game_get_new_fruit(snake_state); + } +} + +int32_t snake_game_app(void* p) { + UNUSED(p); + srand(DWT->CYCCNT); + + osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(SnakeEvent), NULL); + + SnakeState* snake_state = malloc(sizeof(SnakeState)); + snake_game_init_game(snake_state); + + ValueMutex state_mutex; + if(!init_mutex(&state_mutex, snake_state, sizeof(SnakeState))) { + FURI_LOG_E("SnakeGame", "cannot create mutex\r\n"); + free(snake_state); + return 255; + } + + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, snake_game_render_callback, &state_mutex); + view_port_input_callback_set(view_port, snake_game_input_callback, event_queue); + + osTimerId_t timer = + osTimerNew(snake_game_update_timer_callback, osTimerPeriodic, event_queue, NULL); + osTimerStart(timer, osKernelGetTickFreq() / 4); + + // Open GUI and register view_port + Gui* gui = furi_record_open("gui"); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + SnakeEvent event; + for(bool processing = true; processing;) { + osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100); + + SnakeState* snake_state = (SnakeState*)acquire_mutex_block(&state_mutex); + + if(event_status == osOK) { + // press events + if(event.type == EventTypeKey) { + if(event.input.type == InputTypePress) { + switch(event.input.key) { + case InputKeyUp: + snake_state->nextMovement = DirectionUp; + break; + case InputKeyDown: + snake_state->nextMovement = DirectionDown; + break; + case InputKeyRight: + snake_state->nextMovement = DirectionRight; + break; + case InputKeyLeft: + snake_state->nextMovement = DirectionLeft; + break; + case InputKeyOk: + if(snake_state->state == GameStateGameOver) { + snake_game_init_game(snake_state); + } + break; + case InputKeyBack: + processing = false; + break; + } + } + } else if(event.type == EventTypeTick) { + snake_game_process_game_step(snake_state); + } + } else { + // event timeout + } + + view_port_update(view_port); + release_mutex(&state_mutex, snake_state); + } + + osTimerDelete(timer); + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + furi_record_close("gui"); + view_port_free(view_port); + osMessageQueueDelete(event_queue); + delete_mutex(&state_mutex); + free(snake_state); + + return 0; +} + +// Screen is 128x64 px +// (4 + 4) * 16 - 4 + 2 + 2border == 128 +// (4 + 4) * 8 - 4 + 2 + 2border == 64 +// Game field from point{x: 0, y: 0} to point{x: 30, y: 14}. +// The snake turns only in even cells - intersections. +// ┌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┐ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ +// └╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┘ diff --git a/applications/snake_game_ext/start.c b/applications/snake_game_ext/start.c new file mode 100644 index 000000000000..d31aae381499 --- /dev/null +++ b/applications/snake_game_ext/start.c @@ -0,0 +1,5 @@ +extern int main(void); + +void _start(void) { + main(); +} \ No newline at end of file diff --git a/firmware.scons b/firmware.scons index e76240b9f099..83fb72e61c5f 100644 --- a/firmware.scons +++ b/firmware.scons @@ -69,6 +69,8 @@ else: # Debug "debug_apps", "infrared_monitor", + # Test + "snake_game_ext", ] ) @@ -79,7 +81,7 @@ fwenv.Append( CPPDEFINES=fwenv["APPBUILD"].get_apps_cdefs(), ) -Import("build_apps_c") +Import("build_apps_c", "FlipperAppType") apps_c = fwenv.Command( "applications/applications.c", @@ -90,9 +92,43 @@ fwenv.AlwaysBuild(apps_c) sources = [apps_c] -for app_folder in fwenv["APPBUILD"].get_app_folders(): +for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder)) + +# Building external applications + +appenv = fwenv.Clone() +appenv["LINKER_SCRIPT"] = "application-ext" +appenv.Append( + CCFLAGS=[ + "-O0", + "-ggdb3", + "-mword-relocations", + "-mlong-calls", + "-fno-common", + "-nostdlib", + ], + LINKFLAGS=[ + "-r", + "-s", + "-Bsymbolic", + "-nostartfiles", + "-mlong-calls", + "-fno-common", + "-nostdlib", + ], +) +extapps = [] +for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.EXTERNAL): + app_elf = appenv.Program( + app.appid, + appenv.GlobRecursive("*.c*", os.path.join("applications", app._appdir)), + ) + extapps.append(app_elf) +Alias("extapps", extapps) + + # Debug # print(fwenv.Dump()) diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index dad010c8f47e..4d8cb3170417 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -16,10 +16,13 @@ class FlipperAppType(Enum): ARCHIVE = "Archive" SETTINGS = "Settings" STARTUP = "StartupHook" - EXTMODULE = "External" + EXTERNAL = "External" METAPACKAGE = "Package" +Export("FlipperAppType") + + @dataclass class FlipperApplication: appid: str @@ -94,16 +97,11 @@ class AppBuildset: self._check_conflicts() self._check_unsatisfied() # unneeded? self.apps = sorted( - list( - filter( - lambda app: app.apptype in self.BUILTIN_APP_TYPES, - map(self.appmgr.get, self.appnames), - ) - ), + list(map(self.appmgr.get, self.appnames)), key=lambda app: app.appid, ) - def _is_missing_dep(self, dep_name): + def _is_missing_dep(self, dep_name: str): return dep_name not in self.appnames def _process_deps(self): @@ -164,8 +162,15 @@ class AppBuildset: key=lambda app: app.order, ) - def get_app_folders(self): - return sorted(set(app._appdir for app in self.apps)) + def get_builtin_app_folders(self): + return sorted( + set( + app._appdir + for app in filter( + lambda app: app.apptype in self.BUILTIN_APP_TYPES, self.apps + ) + ) + ) class ApplicationsCGenerator: @@ -199,8 +204,10 @@ class ApplicationsCGenerator: def generate(self): contents = ['#include "applications.h"', "#include "] - contents.extend(map(self.get_app_ep_forward, self.buildset.apps)) for apptype in self.APP_TYPE_MAP: + contents.extend( + map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) + ) entry_type, entry_block = self.APP_TYPE_MAP[apptype] contents.append(f"const {entry_type} {entry_block}[] = {{") contents.append( @@ -215,8 +222,11 @@ class ApplicationsCGenerator: archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) if archive_app: - contents.append( - f"const FlipperApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};" + contents.extend( + [ + self.get_app_ep_forward(archive_app[0]), + f"const FlipperApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", + ] ) return "\n".join(contents) @@ -235,7 +245,7 @@ def PrepareApplicationsBuild(env): apps = fwenv["APPS"] apps_buildlist = fwenv["APPBUILD"] = fwenv["APPMGR"].filter_apps(apps) print("Building firmware with modules:") - for apptype in AppBuildset.BUILTIN_APP_TYPES: + for apptype in FlipperAppType: app_sublist = apps_buildlist.get_apps_of_type(apptype) if app_sublist: print( diff --git a/sconscfg/firmwareopts.scons b/sconscfg/firmwareopts.scons index b1fe7c88f09d..fc461c329ff0 100644 --- a/sconscfg/firmwareopts.scons +++ b/sconscfg/firmwareopts.scons @@ -37,19 +37,18 @@ else: fwenv.Append( OPENOCD_OPTS='-f interface/stlink.cfg -c "transport select hla_swd" -f debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init"', + LINKFLAGS=[ + "-Tfirmware/targets/f${TARGET_HW}/${LINKER_SCRIPT}.ld", + ], ) if fwenv["FIRMWARE_BUILD_CFG"] == "updater": fwenv.Append( IMAGE_BASE_ADDRESS="0x20000000", - LINKFLAGS=[ - "-Tfirmware/targets/f${TARGET_HW}/stm32wb55xx_ram_fw.ld", - ], + LINKER_SCRIPT="stm32wb55xx_ram_fw", ) else: fwenv.Append( IMAGE_BASE_ADDRESS="0x8000000", - LINKFLAGS=[ - "-Tfirmware/targets/f${TARGET_HW}/stm32wb55xx_flash.ld", - ], + LINKER_SCRIPT="stm32wb55xx_flash", ) From 320698ff51e0fd4de9a52f4c6180d2c5c548777c Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 18:01:29 +0400 Subject: [PATCH 049/184] Build: minor cleanup --- SConstruct | 1 - firmware/SConscript | 4 ++-- sconscfg/environ.scons | 2 +- sconscfg/git.scons | 19 ------------------- 4 files changed, 3 insertions(+), 23 deletions(-) delete mode 100644 sconscfg/git.scons diff --git a/SConstruct b/SConstruct index 1b1c2db2389b..15325acff340 100644 --- a/SConstruct +++ b/SConstruct @@ -2,7 +2,6 @@ import os SConscript("sconscfg/environ.scons") SConscript("sconscfg/cc.scons") -SConscript("sconscfg/git.scons") SConscript("sconscfg/builders.scons") Import("env") diff --git a/firmware/SConscript b/firmware/SConscript index dcba3c93513d..32d587b844b7 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -9,8 +9,8 @@ libenv.Append( ], ) -sources = libenv.GlobRecursive("*.c", ".") -sources += ["targets/f${TARGET_HW}/startup_stm32wb55xx_cm4.s"] +sources = ["targets/f${TARGET_HW}/startup_stm32wb55xx_cm4.s"] +sources += libenv.GlobRecursive("*.c", ".") lib = libenv.Library("flipper${TARGET_HW}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index fce59586befa..70d81dd54f25 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -52,7 +52,7 @@ Help(vars.GenerateHelpText(env)) SetOption("num_jobs", multiprocessing.cpu_count()) SetOption("implicit_cache", True) -SetOption("implicit_deps_unchanged", True) +# SetOption("implicit_deps_unchanged", True) SetOption("max_drift", 1) diff --git a/sconscfg/git.scons b/sconscfg/git.scons deleted file mode 100644 index 10be6053f1e2..000000000000 --- a/sconscfg/git.scons +++ /dev/null @@ -1,19 +0,0 @@ -Import("env") - - -# env.Append( -# BUILD_META_COMMIT="DUMMY", -# BUILD_META_BRANCH="unknown", -# BUILD_META_BRANCH_NUM="1337", -# BUILD_META_VERSION="unknown", -# BUILD_META_DATE="2021-06-28", -# BUILD_META_DIRTY="1", -# CPPDEFINES=[ -# ("GIT_COMMIT", '\\"${BUILD_META_COMMIT}\\"'), -# ("GIT_BRANCH", '\\"${BUILD_META_BRANCH}\\"'), -# ("GIT_BRANCH_NUM", '\\"${BUILD_META_BRANCH_NUM}\\"'), -# ("VERSION", '\\"${BUILD_META_VERSION}\\"'), -# ("BUILD_DATE", '\\"${BUILD_META_DATE}\\"'), -# ("BUILD_DIRTY", "${BUILD_META_DIRTY}"), -# ], -# ) From 60f8b3b1df1d342be55ff0527a629214e73c3c5c Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 18:08:17 +0400 Subject: [PATCH 050/184] Build: added missing app link script --- firmware/targets/f7/application-ext.ld | 33 ++++++++++++++++++++++++++ sconscfg/appmanifests.scons | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 firmware/targets/f7/application-ext.ld diff --git a/firmware/targets/f7/application-ext.ld b/firmware/targets/f7/application-ext.ld new file mode 100644 index 000000000000..f5bba33fc88f --- /dev/null +++ b/firmware/targets/f7/application-ext.ld @@ -0,0 +1,33 @@ +ENTRY(_start) + +SECTIONS +{ + .text 0x00000000 : + { + *(.text) + *(.text.*) + } + + .rodata : + { + *(.rodata) + *(.rodata1) + *(.rodata.*) + } + + .data : + { + *(.data) + *(.data1) + *(.data.*) + } + + .bss : + { + *(.bss) + *(.bss.*) + *(.sbss) + *(.sbss.*) + *(COMMON) + } +} diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index 4d8cb3170417..c28543eaa944 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -49,7 +49,7 @@ class AppManager: def load_manifest(self, app_manifest_path: str, app_dir_name: str): if not os.path.exists(app_manifest_path): - raise Exception(f"App manifest not found at path {app_manifest_path}") + raise Exception(f"App manifest not found at path {app_manifest_path}") # print("Loading", app_manifest_path) app_manifests = [] From 5f8818f576853ea25c73767622b215a158972202 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Mon, 6 Jun 2022 19:39:17 +0300 Subject: [PATCH 051/184] Add our protobuf to PATH --- assets/Makefile | 1 + make/python.mk | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/assets/Makefile b/assets/Makefile index 2c743601cf09..8c77d8769a8f 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -2,6 +2,7 @@ PROJECT_ROOT = $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..) include $(PROJECT_ROOT)/assets/assets.mk include $(PROJECT_ROOT)/assets/copro.mk +include $(PROJECT_ROOT)/make/python.mk .PHONY: all all: icons protobuf dolphin manifest diff --git a/make/python.mk b/make/python.mk index 88a289da1eca..bc4bc9b5e1c4 100644 --- a/make/python.mk +++ b/make/python.mk @@ -4,8 +4,14 @@ ifneq ($(TOOLCHAIN_GDB_SYM),) TOOLCHAIN_DIR := $(shell dirname -- $(TOOLCHAIN_GDB)) FLIPPER_PY_REL_DIR := $(TOOLCHAIN_DIR)/../python/bin FLIPPER_PY_DIR := $(shell test -d $(FLIPPER_PY_REL_DIR) && cd $(FLIPPER_PY_REL_DIR) && pwd) + FLIPPER_PROTO_REL_DIR := $(TOOLCHAIN_DIR)/../protobuf/bin + FLIPPER_PROTO_DIR := $(shell test -d $(FLIPPER_PROTO_REL_DIR) && cd $(FLIPPER_PROTO_REL_DIR) && pwd) endif ifneq ($(FLIPPER_PY_DIR),) PATH := $(FLIPPER_PY_DIR):$(PATH) export PATH endif +ifneq ($(FLIPPER_PROTO_DIR),) + PATH := $(FLIPPER_PROTO_DIR):$(PATH) + export PATH +endif From 1acf139f3af82fe217175805f219394ebdd218b8 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Mon, 6 Jun 2022 20:07:04 +0300 Subject: [PATCH 052/184] Add out ImageMagick to PATH --- make/python.mk | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/make/python.mk b/make/python.mk index bc4bc9b5e1c4..6a9a17cd4958 100644 --- a/make/python.mk +++ b/make/python.mk @@ -6,6 +6,9 @@ ifneq ($(TOOLCHAIN_GDB_SYM),) FLIPPER_PY_DIR := $(shell test -d $(FLIPPER_PY_REL_DIR) && cd $(FLIPPER_PY_REL_DIR) && pwd) FLIPPER_PROTO_REL_DIR := $(TOOLCHAIN_DIR)/../protobuf/bin FLIPPER_PROTO_DIR := $(shell test -d $(FLIPPER_PROTO_REL_DIR) && cd $(FLIPPER_PROTO_REL_DIR) && pwd) + FLIPPER_IMAGEMAGICK_REL_DIR := $(TOOLCHAIN_DIR)/../image-magick/bin + FLIPPER_IMAGEMAGICK_DIR := $(shell test -d $(FLIPPER_IMAGEMAGICK_REL_DIR) && cd $(FLIPPER_IMAGEMAGICK_REL_DIR) && pwd) + image-magick endif ifneq ($(FLIPPER_PY_DIR),) PATH := $(FLIPPER_PY_DIR):$(PATH) @@ -15,3 +18,7 @@ ifneq ($(FLIPPER_PROTO_DIR),) PATH := $(FLIPPER_PROTO_DIR):$(PATH) export PATH endif +ifneq ($(FLIPPER_IMAGEMAGICK_DIR),) + PATH := $(FLIPPER_IMAGEMAGICK_DIR):$(PATH) + export PATH +endif From c943d9e352598bb2278a92a55957231fc64a652a Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Mon, 6 Jun 2022 20:08:36 +0300 Subject: [PATCH 053/184] FIX: Add out ImageMagick to PATH --- make/python.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/make/python.mk b/make/python.mk index 6a9a17cd4958..1476f430bc38 100644 --- a/make/python.mk +++ b/make/python.mk @@ -8,7 +8,6 @@ ifneq ($(TOOLCHAIN_GDB_SYM),) FLIPPER_PROTO_DIR := $(shell test -d $(FLIPPER_PROTO_REL_DIR) && cd $(FLIPPER_PROTO_REL_DIR) && pwd) FLIPPER_IMAGEMAGICK_REL_DIR := $(TOOLCHAIN_DIR)/../image-magick/bin FLIPPER_IMAGEMAGICK_DIR := $(shell test -d $(FLIPPER_IMAGEMAGICK_REL_DIR) && cd $(FLIPPER_IMAGEMAGICK_REL_DIR) && pwd) - image-magick endif ifneq ($(FLIPPER_PY_DIR),) PATH := $(FLIPPER_PY_DIR):$(PATH) From d376f38150df46b1cfdac094ab3bdf88aace43b1 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 21:57:16 +0400 Subject: [PATCH 054/184] Build: external apps: direct jump to EP --- applications/snake_game_ext/application.fam | 2 +- applications/snake_game_ext/main.c | 9 --------- applications/snake_game_ext/start.c | 5 ----- firmware.scons | 4 +++- 4 files changed, 4 insertions(+), 16 deletions(-) delete mode 100644 applications/snake_game_ext/main.c delete mode 100644 applications/snake_game_ext/start.c diff --git a/applications/snake_game_ext/application.fam b/applications/snake_game_ext/application.fam index edfa20e2e5be..0b0f88aff3ad 100644 --- a/applications/snake_game_ext/application.fam +++ b/applications/snake_game_ext/application.fam @@ -2,7 +2,7 @@ App( appid="snake_game_ext", name="Snake Game Ext", apptype=FlipperAppType.EXTERNAL, - entry_point="_start", + entry_point="snake_game_app", requires=[], stack_size=1 * 1024, ) diff --git a/applications/snake_game_ext/main.c b/applications/snake_game_ext/main.c deleted file mode 100644 index 1a93d9f11088..000000000000 --- a/applications/snake_game_ext/main.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -extern int32_t snake_game_app(void* p); - -int main(void) { - snake_game_app(NULL); - return 0; -} \ No newline at end of file diff --git a/applications/snake_game_ext/start.c b/applications/snake_game_ext/start.c deleted file mode 100644 index d31aae381499..000000000000 --- a/applications/snake_game_ext/start.c +++ /dev/null @@ -1,5 +0,0 @@ -extern int main(void); - -void _start(void) { - main(); -} \ No newline at end of file diff --git a/firmware.scons b/firmware.scons index 83fb72e61c5f..de1a394c736a 100644 --- a/firmware.scons +++ b/firmware.scons @@ -102,7 +102,7 @@ appenv = fwenv.Clone() appenv["LINKER_SCRIPT"] = "application-ext" appenv.Append( CCFLAGS=[ - "-O0", + "-O2", "-ggdb3", "-mword-relocations", "-mlong-calls", @@ -117,6 +117,7 @@ appenv.Append( "-mlong-calls", "-fno-common", "-nostdlib", + "-Wl,-e${APP_ENTRY}", ], ) extapps = [] @@ -124,6 +125,7 @@ for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.EXTERNAL): app_elf = appenv.Program( app.appid, appenv.GlobRecursive("*.c*", os.path.join("applications", app._appdir)), + APP_ENTRY=app.entry_point, ) extapps.append(app_elf) Alias("extapps", extapps) From 514e3e06611c59be9b73ec8a21206bd921e04de9 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 6 Jun 2022 22:39:12 +0400 Subject: [PATCH 055/184] Build: dropped snake_game_ext; scons extapps now builds all PLUGINS as separate elfs --- applications/snake_game_ext/application.fam | 8 - applications/snake_game_ext/snake_game.c | 420 -------------------- firmware.scons | 10 +- firmware/targets/f7/application-ext.ld | 2 - sconscfg/appmanifests.scons | 5 +- 5 files changed, 10 insertions(+), 435 deletions(-) delete mode 100644 applications/snake_game_ext/application.fam delete mode 100644 applications/snake_game_ext/snake_game.c diff --git a/applications/snake_game_ext/application.fam b/applications/snake_game_ext/application.fam deleted file mode 100644 index 0b0f88aff3ad..000000000000 --- a/applications/snake_game_ext/application.fam +++ /dev/null @@ -1,8 +0,0 @@ -App( - appid="snake_game_ext", - name="Snake Game Ext", - apptype=FlipperAppType.EXTERNAL, - entry_point="snake_game_app", - requires=[], - stack_size=1 * 1024, -) diff --git a/applications/snake_game_ext/snake_game.c b/applications/snake_game_ext/snake_game.c deleted file mode 100644 index bb9e207de255..000000000000 --- a/applications/snake_game_ext/snake_game.c +++ /dev/null @@ -1,420 +0,0 @@ -#include -#include -#include -#include - -typedef struct { - // +-----x - // | - // | - // y - uint8_t x; - uint8_t y; -} Point; - -typedef enum { - GameStateLife, - - // https://melmagazine.com/en-us/story/snake-nokia-6110-oral-history-taneli-armanto - // Armanto: While testing the early versions of the game, I noticed it was hard - // to control the snake upon getting close to and edge but not crashing — especially - // in the highest speed levels. I wanted the highest level to be as fast as I could - // possibly make the device "run," but on the other hand, I wanted to be friendly - // and help the player manage that level. Otherwise it might not be fun to play. So - // I implemented a little delay. A few milliseconds of extra time right before - // the player crashes, during which she can still change the directions. And if - // she does, the game continues. - GameStateLastChance, - - GameStateGameOver, -} GameState; - -typedef enum { - DirectionUp, - DirectionRight, - DirectionDown, - DirectionLeft, -} Direction; - -#define MAX_SNAKE_LEN 253 - -typedef struct { - Point points[MAX_SNAKE_LEN]; - uint16_t len; - Direction currentMovement; - Direction nextMovement; // if backward of currentMovement, ignore - Point fruit; - GameState state; -} SnakeState; - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} SnakeEvent; - -static void snake_game_render_callback(Canvas* const canvas, void* ctx) { - const SnakeState* snake_state = acquire_mutex((ValueMutex*)ctx, 25); - if(snake_state == NULL) { - return; - } - - // Before the function is called, the state is set with the canvas_reset(canvas) - - // Frame - canvas_draw_frame(canvas, 0, 0, 128, 64); - - // Fruit - Point f = snake_state->fruit; - f.x = f.x * 4 + 1; - f.y = f.y * 4 + 1; - canvas_draw_rframe(canvas, f.x, f.y, 6, 6, 2); - - // Snake - for(uint16_t i = 0; i < snake_state->len; i++) { - Point p = snake_state->points[i]; - p.x = p.x * 4 + 2; - p.y = p.y * 4 + 2; - canvas_draw_box(canvas, p.x, p.y, 4, 4); - } - - // Game Over banner - if(snake_state->state == GameStateGameOver) { - // Screen is 128x64 px - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 34, 20, 62, 24); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 34, 20, 62, 24); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 37, 31, "Game Over"); - - canvas_set_font(canvas, FontSecondary); - char buffer[12]; - snprintf(buffer, sizeof(buffer), "Score: %u", snake_state->len - 7); - canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); - } - - release_mutex((ValueMutex*)ctx, snake_state); -} - -static void snake_game_input_callback(InputEvent* input_event, osMessageQueueId_t event_queue) { - furi_assert(event_queue); - - SnakeEvent event = {.type = EventTypeKey, .input = *input_event}; - osMessageQueuePut(event_queue, &event, 0, osWaitForever); -} - -static void snake_game_update_timer_callback(osMessageQueueId_t event_queue) { - furi_assert(event_queue); - - SnakeEvent event = {.type = EventTypeTick}; - osMessageQueuePut(event_queue, &event, 0, 0); -} - -static void snake_game_init_game(SnakeState* const snake_state) { - Point p[] = {{8, 6}, {7, 6}, {6, 6}, {5, 6}, {4, 6}, {3, 6}, {2, 6}}; - memcpy(snake_state->points, p, sizeof(p)); - - snake_state->len = 7; - - snake_state->currentMovement = DirectionRight; - - snake_state->nextMovement = DirectionRight; - - Point f = {18, 6}; - snake_state->fruit = f; - - snake_state->state = GameStateLife; -} - -static Point snake_game_get_new_fruit(SnakeState const* const snake_state) { - // 1 bit for each point on the playing field where the snake can turn - // and where the fruit can appear - uint16_t buffer[8]; - memset(buffer, 0, sizeof(buffer)); - uint8_t empty = 8 * 16; - - for(uint16_t i = 0; i < snake_state->len; i++) { - Point p = snake_state->points[i]; - - if(p.x % 2 != 0 || p.y % 2 != 0) { - continue; - } - p.x /= 2; - p.y /= 2; - - buffer[p.y] |= 1 << p.x; - empty--; - } - // Bit set if snake use that playing field - - uint16_t newFruit = rand() % empty; - - // Skip random number of _empty_ fields - for(uint8_t y = 0; y < 8; y++) { - for(uint16_t x = 0, mask = 1; x < 16; x += 1, mask <<= 1) { - if((buffer[y] & mask) == 0) { - if(newFruit == 0) { - Point p = { - .x = x * 2, - .y = y * 2, - }; - return p; - } - newFruit--; - } - } - } - // We will never be here - Point p = {0, 0}; - return p; -} - -static bool snake_game_collision_with_frame(Point const next_step) { - // if x == 0 && currentMovement == left then x - 1 == 255 , - // so check only x > right border - return next_step.x > 30 || next_step.y > 14; -} - -static bool - snake_game_collision_with_tail(SnakeState const* const snake_state, Point const next_step) { - for(uint16_t i = 0; i < snake_state->len; i++) { - Point p = snake_state->points[i]; - if(p.x == next_step.x && p.y == next_step.y) { - return true; - } - } - - return false; -} - -static Direction snake_game_get_turn_snake(SnakeState const* const snake_state) { - switch(snake_state->currentMovement) { - case DirectionUp: - switch(snake_state->nextMovement) { - case DirectionRight: - return DirectionRight; - case DirectionLeft: - return DirectionLeft; - default: - return snake_state->currentMovement; - } - case DirectionRight: - switch(snake_state->nextMovement) { - case DirectionUp: - return DirectionUp; - case DirectionDown: - return DirectionDown; - default: - return snake_state->currentMovement; - } - case DirectionDown: - switch(snake_state->nextMovement) { - case DirectionRight: - return DirectionRight; - case DirectionLeft: - return DirectionLeft; - default: - return snake_state->currentMovement; - } - default: // case DirectionLeft: - switch(snake_state->nextMovement) { - case DirectionUp: - return DirectionUp; - case DirectionDown: - return DirectionDown; - default: - return snake_state->currentMovement; - } - } -} - -static Point snake_game_get_next_step(SnakeState const* const snake_state) { - Point next_step = snake_state->points[0]; - switch(snake_state->currentMovement) { - // +-----x - // | - // | - // y - case DirectionUp: - next_step.y--; - break; - case DirectionRight: - next_step.x++; - break; - case DirectionDown: - next_step.y++; - break; - case DirectionLeft: - next_step.x--; - break; - } - return next_step; -} - -static void snake_game_move_snake(SnakeState* const snake_state, Point const next_step) { - memmove(snake_state->points + 1, snake_state->points, snake_state->len * sizeof(Point)); - snake_state->points[0] = next_step; -} - -static void snake_game_process_game_step(SnakeState* const snake_state) { - if(snake_state->state == GameStateGameOver) { - return; - } - - bool can_turn = (snake_state->points[0].x % 2 == 0) && (snake_state->points[0].y % 2 == 0); - if(can_turn) { - snake_state->currentMovement = snake_game_get_turn_snake(snake_state); - } - - Point next_step = snake_game_get_next_step(snake_state); - - bool crush = snake_game_collision_with_frame(next_step); - if(crush) { - if(snake_state->state == GameStateLife) { - snake_state->state = GameStateLastChance; - return; - } else if(snake_state->state == GameStateLastChance) { - snake_state->state = GameStateGameOver; - return; - } - } else { - if(snake_state->state == GameStateLastChance) { - snake_state->state = GameStateLife; - } - } - - crush = snake_game_collision_with_tail(snake_state, next_step); - if(crush) { - snake_state->state = GameStateGameOver; - return; - } - - bool eatFruit = (next_step.x == snake_state->fruit.x) && (next_step.y == snake_state->fruit.y); - if(eatFruit) { - snake_state->len++; - if(snake_state->len >= MAX_SNAKE_LEN) { - snake_state->state = GameStateGameOver; - return; - } - } - - snake_game_move_snake(snake_state, next_step); - - if(eatFruit) { - snake_state->fruit = snake_game_get_new_fruit(snake_state); - } -} - -int32_t snake_game_app(void* p) { - UNUSED(p); - srand(DWT->CYCCNT); - - osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(SnakeEvent), NULL); - - SnakeState* snake_state = malloc(sizeof(SnakeState)); - snake_game_init_game(snake_state); - - ValueMutex state_mutex; - if(!init_mutex(&state_mutex, snake_state, sizeof(SnakeState))) { - FURI_LOG_E("SnakeGame", "cannot create mutex\r\n"); - free(snake_state); - return 255; - } - - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, snake_game_render_callback, &state_mutex); - view_port_input_callback_set(view_port, snake_game_input_callback, event_queue); - - osTimerId_t timer = - osTimerNew(snake_game_update_timer_callback, osTimerPeriodic, event_queue, NULL); - osTimerStart(timer, osKernelGetTickFreq() / 4); - - // Open GUI and register view_port - Gui* gui = furi_record_open("gui"); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - SnakeEvent event; - for(bool processing = true; processing;) { - osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100); - - SnakeState* snake_state = (SnakeState*)acquire_mutex_block(&state_mutex); - - if(event_status == osOK) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - snake_state->nextMovement = DirectionUp; - break; - case InputKeyDown: - snake_state->nextMovement = DirectionDown; - break; - case InputKeyRight: - snake_state->nextMovement = DirectionRight; - break; - case InputKeyLeft: - snake_state->nextMovement = DirectionLeft; - break; - case InputKeyOk: - if(snake_state->state == GameStateGameOver) { - snake_game_init_game(snake_state); - } - break; - case InputKeyBack: - processing = false; - break; - } - } - } else if(event.type == EventTypeTick) { - snake_game_process_game_step(snake_state); - } - } else { - // event timeout - } - - view_port_update(view_port); - release_mutex(&state_mutex, snake_state); - } - - osTimerDelete(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close("gui"); - view_port_free(view_port); - osMessageQueueDelete(event_queue); - delete_mutex(&state_mutex); - free(snake_state); - - return 0; -} - -// Screen is 128x64 px -// (4 + 4) * 16 - 4 + 2 + 2border == 128 -// (4 + 4) * 8 - 4 + 2 + 2border == 64 -// Game field from point{x: 0, y: 0} to point{x: 30, y: 14}. -// The snake turns only in even cells - intersections. -// ┌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┐ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// ╎ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ▪ ╎ -// └╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┘ diff --git a/firmware.scons b/firmware.scons index de1a394c736a..4248912c8ed4 100644 --- a/firmware.scons +++ b/firmware.scons @@ -69,8 +69,6 @@ else: # Debug "debug_apps", "infrared_monitor", - # Test - "snake_game_ext", ] ) @@ -99,6 +97,7 @@ for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): # Building external applications appenv = fwenv.Clone() +appenv.VariantDir("plugins", "applications", duplicate=False) appenv["LINKER_SCRIPT"] = "application-ext" appenv.Append( CCFLAGS=[ @@ -108,6 +107,7 @@ appenv.Append( "-mlong-calls", "-fno-common", "-nostdlib", + # "-fvisibility=hidden", ], LINKFLAGS=[ "-r", @@ -117,14 +117,16 @@ appenv.Append( "-mlong-calls", "-fno-common", "-nostdlib", + "-Wl,--gc-sections", + # "-fvisibility=hidden", "-Wl,-e${APP_ENTRY}", ], ) extapps = [] -for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.EXTERNAL): +for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): app_elf = appenv.Program( app.appid, - appenv.GlobRecursive("*.c*", os.path.join("applications", app._appdir)), + appenv.GlobRecursive("*.c*", os.path.join("plugins", app._appdir)), APP_ENTRY=app.entry_point, ) extapps.append(app_elf) diff --git a/firmware/targets/f7/application-ext.ld b/firmware/targets/f7/application-ext.ld index f5bba33fc88f..a914b6fa1776 100644 --- a/firmware/targets/f7/application-ext.ld +++ b/firmware/targets/f7/application-ext.ld @@ -1,5 +1,3 @@ -ENTRY(_start) - SECTIONS { .text 0x00000000 : diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index c28543eaa944..74d318edf1d1 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -45,7 +45,10 @@ class AppManager: self.known_apps = {} def get(self, appname: str): - return self.known_apps[appname] + try: + return self.known_apps[appname] + except KeyError as _: + raise Exception(f"Missing application manifest for '{appname}'") def load_manifest(self, app_manifest_path: str, app_dir_name: str): if not os.path.exists(app_manifest_path): From 7fac29de33d557c3487ef564d468fde1417068b9 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 7 Jun 2022 00:44:27 +0400 Subject: [PATCH 056/184] Build: Added stripper :p for extapps --- firmware.scons | 24 +++++++++--------------- firmware/targets/f7/application-ext.ld | 6 ++++++ sconscfg/builders.scons | 9 +++++++++ sconscfg/cc.scons | 2 +- sconscfg/environ.scons | 3 +++ 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/firmware.scons b/firmware.scons index 4248912c8ed4..34e2b8a1fc38 100644 --- a/firmware.scons +++ b/firmware.scons @@ -97,45 +97,43 @@ for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): # Building external applications appenv = fwenv.Clone() -appenv.VariantDir("plugins", "applications", duplicate=False) +appenv.VariantDir("extapps", "applications", duplicate=False) appenv["LINKER_SCRIPT"] = "application-ext" appenv.Append( CCFLAGS=[ - "-O2", + "-Os", "-ggdb3", "-mword-relocations", "-mlong-calls", "-fno-common", "-nostdlib", - # "-fvisibility=hidden", + "-fvisibility=hidden", ], LINKFLAGS=[ "-r", "-s", - "-Bsymbolic", + # "-Bsymbolic", "-nostartfiles", "-mlong-calls", "-fno-common", "-nostdlib", "-Wl,--gc-sections", - # "-fvisibility=hidden", + "-Wl,--no-export-dynamic", + "-fvisibility=hidden", "-Wl,-e${APP_ENTRY}", ], ) extapps = [] for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): app_elf = appenv.Program( - app.appid, - appenv.GlobRecursive("*.c*", os.path.join("plugins", app._appdir)), + os.path.join("extapps", app.appid), + appenv.GlobRecursive("*.c*", os.path.join("extapps", app._appdir)), APP_ENTRY=app.entry_point, ) - extapps.append(app_elf) + extapps.append(appenv.ELFStripper(app.appid, app_elf)) Alias("extapps", extapps) -# Debug -# print(fwenv.Dump()) - # Git Version management build_version = fwenv.Command( @@ -150,10 +148,6 @@ fwenv.AlwaysBuild(build_version) # Full firmware definition fwenv.Append( - CCFLAGS=[ - # "--specs=nosys.specs", - # "--specs=nano.specs", - ], LINKFLAGS=[ "-specs=nano.specs", "-specs=nosys.specs", diff --git a/firmware/targets/f7/application-ext.ld b/firmware/targets/f7/application-ext.ld index a914b6fa1776..45fe431cdd35 100644 --- a/firmware/targets/f7/application-ext.ld +++ b/firmware/targets/f7/application-ext.ld @@ -28,4 +28,10 @@ SECTIONS *(.sbss.*) *(COMMON) } + + /DISCARD/ : + { + *(.comment) + *(.comment.*) + } } diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons index 8fb5607e9d2c..ffc3c1720e4c 100644 --- a/sconscfg/builders.scons +++ b/sconscfg/builders.scons @@ -16,6 +16,10 @@ def generate_dfu(source, target, env, for_signature): ) +def strip_elf(source, target, env, for_signature): + return '${STRIP} ${STRIPFLAGS} "%s" -o "%s"' % (source[0], target[0]) + + # def generate_json(source, target, env, for_signature): # return '${PYTHON3} scripts/meta.py generate -p firmware ${} "%s" > "%s"' % ( # source[0], @@ -40,5 +44,10 @@ env.Append( suffix=".dfu", src_suffix=".bin", ), + "ELFStripper": Builder( + generator=strip_elf, + suffix=".elf", + src_suffix=".elf", + ), } ) diff --git a/sconscfg/cc.scons b/sconscfg/cc.scons index 34aea1cc13da..37456759d87c 100644 --- a/sconscfg/cc.scons +++ b/sconscfg/cc.scons @@ -20,8 +20,8 @@ env.Append( "-MMD", # "-MP", "-Wall", - "-Werror", "-Wextra", + # "-Werror", "-Wno-address-of-packed-member", "-Wredundant-decls", "-fdata-sections", diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 70d81dd54f25..d592cb1e3d8c 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -31,6 +31,8 @@ env = Environment( tools=["as", "gcc", "g++", "ar", "gnulink", "python", "compilation_db"], OBJCOPY="objcopy", PYTHON3="python3", + STRIP="strip", + STRIPFLAGS="-g -S -d --strip-debug --strip-unneeded", TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", @@ -84,6 +86,7 @@ for binary in [ # "LINK", "OBJCOPY", "RANLIB", + "STRIP", ]: if binary in env: env[binary] = TOOLCHAIN_PREFIX + env[binary] From 2228be749c124fd17d6b64225228eb3da2dde40d Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 7 Jun 2022 00:57:19 +0400 Subject: [PATCH 057/184] Build: added Windows entrypoint fbt.cmd --- fbt.cmd | 1 + 1 file changed, 1 insertion(+) create mode 100644 fbt.cmd diff --git a/fbt.cmd b/fbt.cmd new file mode 100644 index 000000000000..3cee132f2fae --- /dev/null +++ b/fbt.cmd @@ -0,0 +1 @@ +@python lib/scons/scripts/scons.py %* From 743fd4a3c3cfe0db19beca133be35052637d3308 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 7 Jun 2022 01:32:34 +0400 Subject: [PATCH 058/184] Build: restored 'flash' command behavior; added path processing for openocd; renamed build dirs --- SConstruct | 2 +- firmware.scons | 6 +----- sconscfg/builders.scons | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/SConstruct b/SConstruct index 15325acff340..736886428119 100644 --- a/SConstruct +++ b/SConstruct @@ -23,7 +23,7 @@ if env["DEBUG"]: if env["COMPACT"]: suffix += "C" if suffix: - variant_dir_name += "_" + suffix + variant_dir_name += "-" + suffix root_path = Dir(".").abspath env["ROOT_DIR"] = root_path diff --git a/firmware.scons b/firmware.scons index 34e2b8a1fc38..aabac7b9379e 100644 --- a/firmware.scons +++ b/firmware.scons @@ -203,11 +203,7 @@ Default(dfu) Alias("dfu", dfu) -flash = fwenv.Command( - target="flash", - source="${FIRMWARE_BUILD_CFG}.bin", - action='openocd ${OPENOCD_OPTS} -c "program ${SOURCES} reset exit ${IMAGE_BASE_ADDRESS}"', -) +flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") Alias("flash", flash) diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons index ffc3c1720e4c..06091fdf09d1 100644 --- a/sconscfg/builders.scons +++ b/sconscfg/builders.scons @@ -1,5 +1,8 @@ Import("env") +import os +import posixpath + def generate_hex(source, target, env, for_signature): return '${OBJCOPY} -O ihex "%s" "%s"' % (source[0], target[0]) @@ -20,6 +23,20 @@ def strip_elf(source, target, env, for_signature): return '${STRIP} ${STRIPFLAGS} "%s" -o "%s"' % (source[0], target[0]) +def flash_bin(target, source, env): + command = f'openocd {env["OPENOCD_OPTS"]} -c "program {source[0].path.replace(os.sep, posixpath.sep)} reset exit {env["IMAGE_BASE_ADDRESS"]}"' + print(command) + retcode = os.system(command) + if retcode != 0: + return "Failed to call openocd" + + fname = target[0].abspath + if os.path.exists(fname): + os.utime(fname, None) + else: + open(fname, "a").close() + + # def generate_json(source, target, env, for_signature): # return '${PYTHON3} scripts/meta.py generate -p firmware ${} "%s" > "%s"' % ( # source[0], @@ -49,5 +66,10 @@ env.Append( suffix=".elf", src_suffix=".elf", ), + "Flasher": Builder( + action=flash_bin, + suffix=".flash", + src_suffix=".bin", + ), } ) From b3b8c15c179284600ca6b7c36932993f087c8dc6 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 7 Jun 2022 02:31:09 +0400 Subject: [PATCH 059/184] Build: reworked strip init; added compact build output (set VERBOSE=1 for full logs) --- firmware.scons | 15 ++++++++++++++- sconscfg/builders.scons | 2 +- sconscfg/environ.scons | 15 ++++++++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/firmware.scons b/firmware.scons index aabac7b9379e..3ed56cb788f2 100644 --- a/firmware.scons +++ b/firmware.scons @@ -98,7 +98,16 @@ for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): appenv = fwenv.Clone() appenv.VariantDir("extapps", "applications", duplicate=False) -appenv["LINKER_SCRIPT"] = "application-ext" +appenv.Replace( + LINKER_SCRIPT="application-ext", + STRIPFLAGS=[ + "--strip-debug", + "--strip-unneeded", + "-d", + "-g", + "-S", + ], +) appenv.Append( CCFLAGS=[ "-Os", @@ -123,6 +132,7 @@ appenv.Append( "-Wl,-e${APP_ENTRY}", ], ) + extapps = [] for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): app_elf = appenv.Program( @@ -166,6 +176,9 @@ fwenv.Append( ], ) +# Debug +# print(fwenv.Dump()) + firmware_elf = fwenv.Program( "${FIRMWARE_BUILD_CFG}", sources, diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons index 06091fdf09d1..cc41fed7b8a1 100644 --- a/sconscfg/builders.scons +++ b/sconscfg/builders.scons @@ -62,7 +62,7 @@ env.Append( src_suffix=".bin", ), "ELFStripper": Builder( - generator=strip_elf, + action=env["STRIPCOM"], suffix=".elf", src_suffix=".elf", ), diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index d592cb1e3d8c..3b8b09c5a352 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -9,6 +9,7 @@ import multiprocessing vars = Variables(None, ARGUMENTS) +vars.Add(BoolVariable("VERBOSE", help="Print full commands", default=0)) vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) vars.Add(BoolVariable("COMPACT", help="Optimize for size", default=0)) vars.Add( @@ -32,7 +33,8 @@ env = Environment( OBJCOPY="objcopy", PYTHON3="python3", STRIP="strip", - STRIPFLAGS="-g -S -d --strip-debug --strip-unneeded", + STRIPFLAGS=[], + STRIPCOM="$STRIP $STRIPFLAGS $SOURCES -o $TARGET", TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", @@ -41,6 +43,17 @@ env = Environment( "PATH": os.environ["PATH"], }, ) + +if not env["VERBOSE"]: + env.Replace( + CCCOMSTR="\tCC\t${SOURCE}", + CXXCOMSTR="\tCPP\t${SOURCE}", + ASCOMSTR="\tASM\t${SOURCE}", + ARCOMSTR="\tAR\t${TARGET}", + RANLIBCOMSTR="\tRAN\t${TARGET}", + LINKCOMSTR="\tLINK\t${TARGET}", + # STRIPCOMSTR="\tSTRIP\t${TARGET}", + ) # env.Decider("content-timestamp") if env["PLATFORM"] == "win32": From 425fda8692df0a5835a2e1f79153da2290939231 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 7 Jun 2022 03:29:26 +0400 Subject: [PATCH 060/184] Build: moved lib flags to csconscfg/cc.scons --- sconscfg/cc.scons | 21 +++++++++++++++++++++ sconscfg/environ.scons | 24 ++---------------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/sconscfg/cc.scons b/sconscfg/cc.scons index 37456759d87c..e9c201a12381 100644 --- a/sconscfg/cc.scons +++ b/sconscfg/cc.scons @@ -41,3 +41,24 @@ env.Append( "-mthumb", ], ) + + +# Specific flags for building libraries - always do optimized builds + +lib_flags = { + "CCFLAGS": [ + "-Os", + ], + "CPPDEFINES": [ + "NDEBUG", + ], +} + +if env["RAM_EXEC"]: + env.Append( + CPPDEFINES=[ + "FURI_RAM_EXEC", + ] + ) + +Export("lib_flags") diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 3b8b09c5a352..dc9f76905101 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -54,7 +54,6 @@ if not env["VERBOSE"]: LINKCOMSTR="\tLINK\t${TARGET}", # STRIPCOMSTR="\tSTRIP\t${TARGET}", ) -# env.Decider("content-timestamp") if env["PLATFORM"] == "win32": # On Windows, Python 3 executable is usually just "python" @@ -69,6 +68,7 @@ SetOption("num_jobs", multiprocessing.cpu_count()) SetOption("implicit_cache", True) # SetOption("implicit_deps_unchanged", True) SetOption("max_drift", 1) +# env.Decider("content-timestamp") # Setting up temp file parameters @@ -96,7 +96,6 @@ for binary in [ "AS", "CC", "CXX", - # "LINK", "OBJCOPY", "RANLIB", "STRIP", @@ -165,23 +164,4 @@ env.AddMethod(GlobRecursive) env.AddMethod(BuildModule) env.AddMethod(BuildModules) - -# Specific flags for building libraries - always do optimized builds - -lib_flags = { - "CCFLAGS": [ - "-Os", - ], - "CPPDEFINES": [ - "NDEBUG", - ], -} - -if env["RAM_EXEC"]: - env.Append( - CPPDEFINES=[ - "FURI_RAM_EXEC", - ] - ) - -Export("env", "lib_flags") +Export("env") From 48261f1e86110417962363f771eace4816911a44 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 7 Jun 2022 03:34:46 +0400 Subject: [PATCH 061/184] Build: added generated version file to .gitignore --- lib/toolbox/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/toolbox/.gitignore diff --git a/lib/toolbox/.gitignore b/lib/toolbox/.gitignore new file mode 100644 index 000000000000..411cd0e721f2 --- /dev/null +++ b/lib/toolbox/.gitignore @@ -0,0 +1 @@ +version.inc.h \ No newline at end of file From db6d4cb325c6a6145f43d188adfc98daffafd51d Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Tue, 7 Jun 2022 18:05:55 +0900 Subject: [PATCH 062/184] Scons: add INSTALLSTR override --- sconscfg/environ.scons | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index dc9f76905101..d3fd6996d643 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -50,8 +50,9 @@ if not env["VERBOSE"]: CXXCOMSTR="\tCPP\t${SOURCE}", ASCOMSTR="\tASM\t${SOURCE}", ARCOMSTR="\tAR\t${TARGET}", - RANLIBCOMSTR="\tRAN\t${TARGET}", + RANLIBCOMSTR="\tRANLIB\t${TARGET}", LINKCOMSTR="\tLINK\t${TARGET}", + INSTALLSTR="\tINSTALL\t${SOURCE}", # STRIPCOMSTR="\tSTRIP\t${TARGET}", ) From 61f01d81baab3c33c34a6ca469e690094967800a Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 7 Jun 2022 18:43:34 +0400 Subject: [PATCH 063/184] Build: additional aliases and less verbose default build --- firmware.scons | 5 ++++- sconscfg/appmanifests.scons | 2 +- sconscfg/environ.scons | 2 ++ scripts/version.py | 9 +++++---- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/firmware.scons b/firmware.scons index 3ed56cb788f2..8c24e9527b7f 100644 --- a/firmware.scons +++ b/firmware.scons @@ -149,7 +149,10 @@ Alias("extapps", extapps) build_version = fwenv.Command( "#lib/toolbox/version.inc.h", [], - "${PYTHON3} scripts/version.py generate -o ${TARGET} --dir ${ROOT_DIR}", + Action( + "${PYTHON3} scripts/version.py generate -o ${TARGET} --dir ${ROOT_DIR}", + "${VERSIONCOMSTR}", + ), ) fwenv.Precious(build_version) fwenv.AlwaysBuild(build_version) diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index 74d318edf1d1..1ca5684555b2 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -264,11 +264,11 @@ fwenv.AddMethod(PrepareApplicationsBuild) def build_apps_c(target, source, env): target_file_name = target[0].path - print("target_file_name", target_file_name) gen = ApplicationsCGenerator(fwenv["APPBUILD"]) with open(target_file_name, "w") as file: file.write(gen.generate()) +build_apps_c = Action(build_apps_c, "${APPSCOMSTR}") Export("build_apps_c") diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index d3fd6996d643..a9bdaede096b 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -53,6 +53,8 @@ if not env["VERBOSE"]: RANLIBCOMSTR="\tRANLIB\t${TARGET}", LINKCOMSTR="\tLINK\t${TARGET}", INSTALLSTR="\tINSTALL\t${SOURCE}", + APPSCOMSTR="\tAPPS\t${TARGET}", + VERSIONCOMSTR="\tVERSION\t${TARGET}", # STRIPCOMSTR="\tSTRIP\t${TARGET}", ) diff --git a/scripts/version.py b/scripts/version.py index 0ea9276b2e5b..3c9c19448f7f 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -75,12 +75,13 @@ def generate(self): with open(self.args.output, "r") as file: current_version_info = file.read() except EnvironmentError as e: - print(e) - pass + if self.args.debug: + print(e) if current_version_info != new_version_info_fmt: - print("old: ", current_version_info) - print("new: ", new_version_info_fmt) + if self.args.debug: + print("old: ", current_version_info) + print("new: ", new_version_info_fmt) with open(self.args.output, "w") as file: file.write(new_version_info_fmt) # os.utime("../lib/toolbox/version.c", None) From f242ccb7f1edd946113d6a7489e33466b2434a56 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Wed, 8 Jun 2022 12:37:49 +0300 Subject: [PATCH 064/184] Replacing ImageMagick's convert call to out png2xmb --- make/python.mk | 6 ------ scripts/assets.py | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/make/python.mk b/make/python.mk index 1476f430bc38..bc4bc9b5e1c4 100644 --- a/make/python.mk +++ b/make/python.mk @@ -6,8 +6,6 @@ ifneq ($(TOOLCHAIN_GDB_SYM),) FLIPPER_PY_DIR := $(shell test -d $(FLIPPER_PY_REL_DIR) && cd $(FLIPPER_PY_REL_DIR) && pwd) FLIPPER_PROTO_REL_DIR := $(TOOLCHAIN_DIR)/../protobuf/bin FLIPPER_PROTO_DIR := $(shell test -d $(FLIPPER_PROTO_REL_DIR) && cd $(FLIPPER_PROTO_REL_DIR) && pwd) - FLIPPER_IMAGEMAGICK_REL_DIR := $(TOOLCHAIN_DIR)/../image-magick/bin - FLIPPER_IMAGEMAGICK_DIR := $(shell test -d $(FLIPPER_IMAGEMAGICK_REL_DIR) && cd $(FLIPPER_IMAGEMAGICK_REL_DIR) && pwd) endif ifneq ($(FLIPPER_PY_DIR),) PATH := $(FLIPPER_PY_DIR):$(PATH) @@ -17,7 +15,3 @@ ifneq ($(FLIPPER_PROTO_DIR),) PATH := $(FLIPPER_PROTO_DIR):$(PATH) export PATH endif -ifneq ($(FLIPPER_IMAGEMAGICK_DIR),) - PATH := $(FLIPPER_IMAGEMAGICK_DIR):$(PATH) - export PATH -endif diff --git a/scripts/assets.py b/scripts/assets.py index 1363900f0210..0ffd2b1614df 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -90,7 +90,7 @@ def init(self): self.parser_dolphin.set_defaults(func=self.dolphin) def _icon2header(self, file): - output = subprocess.check_output(["convert", file, "xbm:-"]) + output = subprocess.check_output(["png2xmb", file]) assert output f = io.StringIO(output.decode().strip()) width = int(f.readline().strip().split(" ")[2]) From f25c347c9aecd603b8673c6ac78d25b4f6d00693 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Wed, 8 Jun 2022 14:07:47 +0300 Subject: [PATCH 065/184] png2xbm call fix --- scripts/assets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/assets.py b/scripts/assets.py index 0ffd2b1614df..481d276730cf 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -90,7 +90,7 @@ def init(self): self.parser_dolphin.set_defaults(func=self.dolphin) def _icon2header(self, file): - output = subprocess.check_output(["png2xmb", file]) + output = subprocess.check_output(["png2xbm", file]) assert output f = io.StringIO(output.decode().strip()) width = int(f.readline().strip().split(" ")[2]) From 23bd0f00ab493d01b473cb1476524a83be011a8c Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Wed, 8 Jun 2022 14:10:58 +0300 Subject: [PATCH 066/184] fully replacing ImageMagick's convert call to our png2xmb --- scripts/flipper/assets/icon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/flipper/assets/icon.py b/scripts/flipper/assets/icon.py index 44943e7d7a2d..0b5c076bba3b 100644 --- a/scripts/flipper/assets/icon.py +++ b/scripts/flipper/assets/icon.py @@ -25,7 +25,7 @@ def is_file_an_icon(filename): def file2image(file): - output = subprocess.check_output(["convert", file, "xbm:-"]) + output = subprocess.check_output(["png2xbm", file]) assert output # Extract data from text From 8dbc0426ada6c6dacc05c062aaee1f93c9f6dcfb Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 9 Jun 2022 03:50:28 +0400 Subject: [PATCH 067/184] Scripts: changed open() calls to with ..: idiom --- scripts/bin2dfu.py | 3 +- scripts/compile_db.py | 18 +++++------ scripts/flipper/assets/copro.py | 3 +- scripts/flipper/assets/dolphin.py | 3 +- scripts/flipper/assets/icon.py | 4 +-- scripts/flipper/assets/manifest.py | 23 +++++++------- scripts/flipper/storage.py | 50 +++++++++++++++--------------- scripts/flipper/utils/__init__.py | 14 ++++----- scripts/ob.py | 8 ++--- scripts/otp.py | 26 +++++++++------- scripts/storage.py | 3 +- 11 files changed, 80 insertions(+), 75 deletions(-) diff --git a/scripts/bin2dfu.py b/scripts/bin2dfu.py index 62554f69976f..abd538288b28 100755 --- a/scripts/bin2dfu.py +++ b/scripts/bin2dfu.py @@ -62,7 +62,8 @@ def convert(self): data += struct.pack(" 0: - h.update(data) - else: - break + with open(path, "rb") as fd: + while True: + data = fd.read(block_size) + if len(data) > 0: + h.update(data) + else: + break return h.hexdigest() diff --git a/scripts/ob.py b/scripts/ob.py index 17de08fd0e40..722549d69a77 100755 --- a/scripts/ob.py +++ b/scripts/ob.py @@ -40,10 +40,10 @@ def _getCubeParams(self): def before(self): self.logger.info(f"Loading Option Bytes data") file_path = os.path.join(os.path.dirname(sys.argv[0]), "ob.data") - file = open(file_path, "r") - for line in file.readlines(): - k, v, o = line.split(":") - self.ob[k.strip()] = v.strip(), o.strip() + with open(file_path, "r") as file: + for line in file.readlines(): + k, v, o = line.split(":") + self.ob[k.strip()] = v.strip(), o.strip() def check(self): self.logger.info(f"Checking Option Bytes") diff --git a/scripts/otp.py b/scripts/otp.py index 54714961029d..7b2378d12053 100755 --- a/scripts/otp.py +++ b/scripts/otp.py @@ -149,8 +149,10 @@ def generate_all(self): self.logger.info(f"Generating OTP") self._processFirstArgs() self._processSecondArgs() - open(f"{self.args.file}_first.bin", "wb").write(self._packFirst()) - open(f"{self.args.file}_second.bin", "wb").write(self._packSecond()) + with open(f"{self.args.file}_first.bin", "wb") as file: + file.write(self._packFirst()) + with open(f"{self.args.file}_second.bin", "wb") as file: + file.write(self._packSecond()) self.logger.info( f"Generated files: {self.args.file}_first.bin and {self.args.file}_second.bin" ) @@ -166,9 +168,9 @@ def flash_first(self): try: self.logger.info(f"Packing binary data") - file = open(filename, "wb") - file.write(self._packFirst()) - file.close() + with open(filename, "wb") as file: + file.write(self._packFirst()) + self.logger.info(f"Flashing OTP") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x1FFF7000", filename) @@ -190,9 +192,9 @@ def flash_second(self): try: self.logger.info(f"Packing binary data") - file = open(filename, "wb") - file.write(self._packSecond()) - file.close() + with open(filename, "wb") as file: + file.write(self._packSecond()) + self.logger.info(f"Flashing OTP") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x1FFF7010", filename) @@ -215,10 +217,10 @@ def flash_all(self): try: self.logger.info(f"Packing binary data") - file = open(filename, "wb") - file.write(self._packFirst()) - file.write(self._packSecond()) - file.close() + with open(filename, "wb") as file: + file.write(self._packFirst()) + file.write(self._packSecond()) + self.logger.info(f"Flashing OTP") cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x1FFF7000", filename) diff --git a/scripts/storage.py b/scripts/storage.py index a56dcd8b9b9e..4364eb28a2b8 100755 --- a/scripts/storage.py +++ b/scripts/storage.py @@ -293,7 +293,8 @@ def stress(self): with tempfile.TemporaryDirectory() as tmpdirname: send_file_name = os.path.join(tmpdirname, "send") receive_file_name = os.path.join(tmpdirname, "receive") - open(send_file_name, "w").write("A" * self.args.file_size) + with open(send_file_name, "w") as fout: + fout.write("A" * self.args.file_size) storage = FlipperStorage(self.args.port) storage.start() if storage.exist_file(self.args.flipper_path): From 4f6942aaf68dfe4292c8ed7a4e753b161bdfcf22 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 9 Jun 2022 04:06:18 +0400 Subject: [PATCH 068/184] Scripts: Added support for pillow + heatshrink in icon processing for speed up --- scripts/assets.py | 48 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/scripts/assets.py b/scripts/assets.py index 1363900f0210..5e502d19cb9d 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -89,8 +89,45 @@ def init(self): ) self.parser_dolphin.set_defaults(func=self.dolphin) + __have_no_pil = False + + def __png2xbm(self, file): + if self.__have_no_pil: + return subprocess.check_output(["convert", file, "xbm:-"]) + + try: + from PIL import Image, ImageOps + except ImportError as e: + self.__have_no_pil = True + self.logger.info("pillow module is missing, using convert cli util") + return self.__png2xbm(file) + + with Image.open(file) as im: + with io.BytesIO() as output: + bw = im.convert("1") + bw = ImageOps.invert(bw) + bw.save(output, format="XBM") + return output.getvalue() + + __have_no_hs2 = False + + def __xbm2hs(self, data): + if self.__have_no_hs2: + return subprocess.check_output( + ["heatshrink", "-e", "-w8", "-l4"], input=data + ) + + try: + import heatshrink2 + except ImportError as e: + self.__have_no_hs2 = True + self.logger.info("heatshrink2 module is missing, using heatshrink cli util") + return self.__xbm2hs(data) + + return heatshrink2.compress(data, window_sz2=8, lookahead_sz2=4) + def _icon2header(self, file): - output = subprocess.check_output(["convert", file, "xbm:-"]) + output = self.__png2xbm(file) assert output f = io.StringIO(output.decode().strip()) width = int(f.readline().strip().split(" ")[2]) @@ -98,10 +135,10 @@ def _icon2header(self, file): data = f.read().strip().replace("\n", "").replace(" ", "").split("=")[1][:-1] data_bin_str = data[1:-1].replace(",", " ").replace("0x", "") data_bin = bytearray.fromhex(data_bin_str) + # Encode icon data with LZSS - data_encoded_str = subprocess.check_output( - ["heatshrink", "-e", "-w8", "-l4"], input=data_bin - ) + data_encoded_str = self.__xbm2hs(data_bin) + assert data_encoded_str data_enc = bytearray(data_encoded_str) data_enc = bytearray([len(data_enc) & 0xFF, len(data_enc) >> 8]) + data_enc @@ -204,12 +241,15 @@ def icons(self): ) ) icons_c.write("\n") + icons_c.close() + # Create Public Header self.logger.debug(f"Creating header") icons_h = open(os.path.join(self.args.output_directory, "assets_icons.h"), "w") icons_h.write(ICONS_TEMPLATE_H_HEADER) for name, width, height, frame_rate, frame_count in icons: icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name)) + icons_h.close() self.logger.debug(f"Done") return 0 From 57d0f9ca58a2031187dc05d5c90ae82877fddae2 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 9 Jun 2022 04:30:34 +0400 Subject: [PATCH 069/184] Build: buider for icons; refactored basic builders to use plain Action() --- assets/SConscript | 52 ++++++++++++++++++++++++------ sconscfg/builders.scons | 71 +++++++++++++---------------------------- scripts/version.py | 3 +- 3 files changed, 67 insertions(+), 59 deletions(-) diff --git a/assets/SConscript b/assets/SConscript index a961c39a2a9e..3c55582f0fa1 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -1,16 +1,48 @@ Import("env", "lib_flags") -libenv = env.Clone() -libenv.MergeFlags(lib_flags) -# libenv.Append( -# CPPPATH=[ -# "#/assets/compiled", -# ], -# ) +assetsenv = env.Clone() +assetsenv.MergeFlags(lib_flags) + +assetsenv.Append( + ASSETS_COMPILER="scripts/assets.py", +) + + +def icons_emitter(target, source, env): + print("icons_emitter", target, source) + target = [ + "#assets/compiled/assets_icons.c", + "#assets/compiled/assets_icons.h", + ] + return target, source + + +assetsenv.Append( + BUILDERS={ + "IconBuilder": Builder( + action=Action( + "${PYTHON3} ${ASSETS_COMPILER} icons --debug ${SOURCE} ${TARGET.dir}", + "\tICONS\t${TARGET}", + ), + emitter=icons_emitter, + ), + "ProtobufBuilder": Builder(), + } +) + + +icons_src = assetsenv.GlobRecursive("*.png", "icons") +icons_src += assetsenv.GlobRecursive("frame_rate", "icons") + +icons = assetsenv.IconBuilder(Dir("#/assets/compiled"), Dir("#/assets/icons")) +Depends(icons, icons_src) +Alias("icons", icons) + sources = Glob("compiled/*.c", source=True) -lib = libenv.Library("assets", sources) -libenv.Install("${LIB_DIST_DIR}", lib) -Return("lib") +assetslib = assetsenv.Library("assets", sources) +Depends(assetslib, icons) +assetsenv.Install("${LIB_DIST_DIR}", assetslib) +Return("assetslib") diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons index cc41fed7b8a1..128f3eea0722 100644 --- a/sconscfg/builders.scons +++ b/sconscfg/builders.scons @@ -1,73 +1,48 @@ Import("env") -import os -import posixpath - - -def generate_hex(source, target, env, for_signature): - return '${OBJCOPY} -O ihex "%s" "%s"' % (source[0], target[0]) - - -def generate_bin(source, target, env, for_signature): - return '${OBJCOPY} -O binary -S "%s" "%s"' % (source[0], target[0]) - - -def generate_dfu(source, target, env, for_signature): - return ( - '${PYTHON3} ./scripts/bin2dfu.py -i "%s" -o "%s" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"' - % (source[0], target[0]) - ) - - -def strip_elf(source, target, env, for_signature): - return '${STRIP} ${STRIPFLAGS} "%s" -o "%s"' % (source[0], target[0]) - - -def flash_bin(target, source, env): - command = f'openocd {env["OPENOCD_OPTS"]} -c "program {source[0].path.replace(os.sep, posixpath.sep)} reset exit {env["IMAGE_BASE_ADDRESS"]}"' - print(command) - retcode = os.system(command) - if retcode != 0: - return "Failed to call openocd" - - fname = target[0].abspath - if os.path.exists(fname): - os.utime(fname, None) - else: - open(fname, "a").close() - - -# def generate_json(source, target, env, for_signature): -# return '${PYTHON3} scripts/meta.py generate -p firmware ${} "%s" > "%s"' % ( -# source[0], -# target[0], -# ) - env.Append( BUILDERS={ "HEXBuilder": Builder( - generator=generate_hex, + action=Action( + '${OBJCOPY} -O ihex "${SOURCE}" "${TARGET}"', + "\tHEX\t${TARGET}", + ), suffix=".hex", src_suffix=".elf", ), "BINBuilder": Builder( - generator=generate_bin, + action=Action( + '${OBJCOPY} -O binary -S "${SOURCE}" "${TARGET}"', + "\tBIN\t${TARGET}", + ), suffix=".bin", src_suffix=".elf", ), "DFUBuilder": Builder( - generator=generate_dfu, + action=Action( + '${PYTHON3} ./scripts/bin2dfu.py -i "${SOURCE}" -o "${TARGET}" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"', + "\tDFU\t${TARGET}", + ), suffix=".dfu", src_suffix=".bin", ), "ELFStripper": Builder( - action=env["STRIPCOM"], + action=Action( + env["STRIPCOM"], + "\tSTRIP\t${TARGET}", + ), suffix=".elf", src_suffix=".elf", ), "Flasher": Builder( - action=flash_bin, + action=[ + Action( + 'openocd ${OPENOCD_OPTS} -c "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}"', + "\tFLASH\t${SOURCE}", + ), + Touch("${TARGET}"), + ], suffix=".flash", src_suffix=".bin", ), diff --git a/scripts/version.py b/scripts/version.py index 3c9c19448f7f..cc717ba07587 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -87,7 +87,8 @@ def generate(self): # os.utime("../lib/toolbox/version.c", None) print("Version information updated") else: - print("Version information hasn't changed") + if self.args.debug: + print("Version information hasn't changed") return 0 From c9ca9fade444c498096aa68e2f28846359519b8f Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 9 Jun 2022 17:58:14 +0400 Subject: [PATCH 070/184] Scripts: removed duplicate image handling logic --- scripts/assets.py | 65 ++-------------------------------- scripts/flipper/assets/icon.py | 55 +++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 66 deletions(-) diff --git a/scripts/assets.py b/scripts/assets.py index 5e502d19cb9d..1d22e1160deb 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from flipper.app import App +from flipper.assets.icon import file2image import logging import argparse @@ -89,69 +90,9 @@ def init(self): ) self.parser_dolphin.set_defaults(func=self.dolphin) - __have_no_pil = False - - def __png2xbm(self, file): - if self.__have_no_pil: - return subprocess.check_output(["convert", file, "xbm:-"]) - - try: - from PIL import Image, ImageOps - except ImportError as e: - self.__have_no_pil = True - self.logger.info("pillow module is missing, using convert cli util") - return self.__png2xbm(file) - - with Image.open(file) as im: - with io.BytesIO() as output: - bw = im.convert("1") - bw = ImageOps.invert(bw) - bw.save(output, format="XBM") - return output.getvalue() - - __have_no_hs2 = False - - def __xbm2hs(self, data): - if self.__have_no_hs2: - return subprocess.check_output( - ["heatshrink", "-e", "-w8", "-l4"], input=data - ) - - try: - import heatshrink2 - except ImportError as e: - self.__have_no_hs2 = True - self.logger.info("heatshrink2 module is missing, using heatshrink cli util") - return self.__xbm2hs(data) - - return heatshrink2.compress(data, window_sz2=8, lookahead_sz2=4) - def _icon2header(self, file): - output = self.__png2xbm(file) - assert output - f = io.StringIO(output.decode().strip()) - width = int(f.readline().strip().split(" ")[2]) - height = int(f.readline().strip().split(" ")[2]) - data = f.read().strip().replace("\n", "").replace(" ", "").split("=")[1][:-1] - data_bin_str = data[1:-1].replace(",", " ").replace("0x", "") - data_bin = bytearray.fromhex(data_bin_str) - - # Encode icon data with LZSS - data_encoded_str = self.__xbm2hs(data_bin) - - assert data_encoded_str - data_enc = bytearray(data_encoded_str) - data_enc = bytearray([len(data_enc) & 0xFF, len(data_enc) >> 8]) + data_enc - # Use encoded data only if its lenght less than original, including header - if len(data_enc) < len(data_bin) + 1: - data = ( - "{0x01,0x00," - + "".join("0x{:02x},".format(byte) for byte in data_enc) - + "}" - ) - else: - data = "{0x00," + data[1:] - return width, height, data + image = file2image(file) + return image.width, image.height, image.data_as_carray() def _iconIsSupported(self, filename): extension = filename.lower().split(".")[-1] diff --git a/scripts/flipper/assets/icon.py b/scripts/flipper/assets/icon.py index 7d0c4a74b9b6..5854d15c0e46 100644 --- a/scripts/flipper/assets/icon.py +++ b/scripts/flipper/assets/icon.py @@ -18,14 +18,63 @@ def write(self, filename): with open(filename, "wb") as file: file.write(self.data) + def data_as_carray(self): + return ( + "{" + "".join("0x{:02x},".format(img_byte) for img_byte in self.data) + "}" + ) + def is_file_an_icon(filename): extension = filename.lower().split(".")[-1] return extension in ICONS_SUPPORTED_FORMATS +class ImageTools: + __pil_unavailable = False + __hs2_unavailable = False + + def __init__(self): + self.logger = logging.getLogger() + + def png2xbm(self, file): + if self.__pil_unavailable: + return subprocess.check_output(["convert", file, "xbm:-"]) + + try: + from PIL import Image, ImageOps + except ImportError as e: + self.__pil_unavailable = True + self.logger.info("pillow module is missing, using convert cli util") + return self.__png2xbm(file) + + with Image.open(file) as im: + with io.BytesIO() as output: + bw = im.convert("1") + bw = ImageOps.invert(bw) + bw.save(output, format="XBM") + return output.getvalue() + + def xbm2hs(self, data): + if self.__hs2_unavailable: + return subprocess.check_output( + ["heatshrink", "-e", "-w8", "-l4"], input=data + ) + + try: + import heatshrink2 + except ImportError as e: + self.__hs2_unavailable = True + self.logger.info("heatshrink2 module is missing, using heatshrink cli util") + return self.__xbm2hs(data) + + return heatshrink2.compress(data, window_sz2=8, lookahead_sz2=4) + + +__tools = ImageTools() + + def file2image(file): - output = subprocess.check_output(["convert", file, "xbm:-"]) + output = __tools.png2xbm(file) assert output # Extract data from text @@ -38,9 +87,7 @@ def file2image(file): data_bin = bytearray.fromhex(data_str) # Encode icon data with LZSS - data_encoded_str = subprocess.check_output( - ["heatshrink", "-e", "-w8", "-l4"], input=data_bin - ) + data_encoded_str = __tools.xbm2hs(data_bin) assert data_encoded_str From 29232625204d0f0c1efabfe4e5d4d153bf660a74 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 9 Jun 2022 20:36:31 +0400 Subject: [PATCH 071/184] Build: assets tooling, initial impl --- assets/SConscript | 134 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/assets/SConscript b/assets/SConscript index 3c55582f0fa1..da11f4726643 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -1,16 +1,18 @@ Import("env", "lib_flags") +import os +import subprocess assetsenv = env.Clone() assetsenv.MergeFlags(lib_flags) assetsenv.Append( ASSETS_COMPILER="scripts/assets.py", + NANOPB_COMPILER="lib/nanopb/generator/nanopb_generator.py", ) def icons_emitter(target, source, env): - print("icons_emitter", target, source) target = [ "#assets/compiled/assets_icons.c", "#assets/compiled/assets_icons.h", @@ -18,16 +20,100 @@ def icons_emitter(target, source, env): return target, source +def proto_emitter(target, source, env): + # target = list() + # print(target[0].path, source) + out_path = target[0].path + # print("out_path", out_path) + target = list() + for src in source: + basename = os.path.splitext(src.name)[0] + # print("!! ", os.path.join("#", out_path, basename + ".pb.h")) + target.append(File(os.path.join("#", out_path, basename + ".pb.c"))) + target.append(File(os.path.join("#", out_path, basename + ".pb.h"))) + # print(list(t.path for t in target)) + return target, source + + +def dolphin_emitter(target, source, env): + # target.append(target[0]) + out_path = target[0].path + # print("dolphin_emitter", out_path) + asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" + target = [ + File(os.path.join("#", out_path, asset_basename + ".c")), + File(os.path.join("#", out_path, asset_basename + ".h")), + ] + return target, source + + +def _invoke_git(args, source_dir): + cmd = ["git"] + cmd.extend(args) + return ( + subprocess.check_output(cmd, cwd=source_dir, stderr=subprocess.STDOUT) + .strip() + .decode() + ) + + +def proto_ver_generator(target, source, env): + target_file = target[0].abspath + src_dir = source[0].dir.abspath + try: + git_fetch = _invoke_git( + ["fetch", "--tags"], + source_dir=src_dir, + ) + except (subprocess.CalledProcessError, EnvironmentError) as e: + # Not great, not terrible + print("Git: fetch failed") + + try: + git_describe = _invoke_git( + ["describe", "--tags", "--abbrev=0"], + source_dir=src_dir, + ) + except (subprocess.CalledProcessError, EnvironmentError) as e: + print("Git: describe failed") + Exit("git error") + + # print("describe=", git_describe) + git_major, git_minor = git_describe.split(".") + version_file_data = ( + "#pragma once", + f"#define PROTOBUF_MAJOR_VERSION {git_major}", + f"#define PROTOBUF_MINOR_VERSION {git_minor}", + "", + ) + with open(target_file, "wt") as file: + file.write("\n".join(version_file_data)) + + assetsenv.Append( BUILDERS={ "IconBuilder": Builder( action=Action( - "${PYTHON3} ${ASSETS_COMPILER} icons --debug ${SOURCE} ${TARGET.dir}", + "${PYTHON3} ${ASSETS_COMPILER} icons ${SOURCE} ${TARGET.dir}", "\tICONS\t${TARGET}", ), emitter=icons_emitter, ), - "ProtobufBuilder": Builder(), + "ProtoBuilder": Builder( + action=Action( + "${PYTHON3} ${NANOPB_COMPILER} -q -I${SOURCE.dir} -D${TARGET.dir} ${SOURCES}", + # "\tPROTO\t${SOURCE}", + ), + emitter=proto_emitter, + src_suffix=".proto", + ), + "DolphinBuilder": Builder( + action=Action( + '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${TARGET.dir}"', + "\tDOLPHIN\t${SOURCE}", + ), + emitter=dolphin_emitter, + ), } ) @@ -40,9 +126,47 @@ Depends(icons, icons_src) Alias("icons", icons) -sources = Glob("compiled/*.c", source=True) +proto_src = Glob("protobuf/*.proto", source=True) +proto_options = Glob("protobuf/*.options", source=True) +proto = assetsenv.ProtoBuilder(Dir("#/assets/compiled"), proto_src) +Depends(proto, proto_options) +# Precious(proto) +Alias("proto", proto) + + +dolphin_internal_src = assetsenv.GlobRecursive("*", "dolphin/internal") +dolphin_internal = assetsenv.DolphinBuilder( + Dir("#/assets/compiled"), + Dir("#/assets/dolphin/internal"), + DOLPHIN_RES_TYPE="internal", +) +Depends(dolphin_internal, dolphin_internal_src) +Alias("dolphin_internal", dolphin_internal) + + +dolphin_blocking_src = assetsenv.GlobRecursive("*", "dolphin/blocking") +dolphin_blocking = assetsenv.DolphinBuilder( + Dir("#/assets/compiled"), + Dir("#/assets/dolphin/blocking"), + DOLPHIN_RES_TYPE="blocking", +) +Depends(dolphin_blocking, dolphin_blocking_src) +Alias("dolphin_blocking", dolphin_blocking) + +proto_ver = assetsenv.Command( + "#/assets/compiled/protobuf_version.h", + "#/assets/protobuf/Changelog", + action=Action( + proto_ver_generator, + "\tPBVER\t${TARGET}", + ), +) +Depends(proto_ver, proto) +Alias("proto_ver", proto_ver) + +sources = Glob("#/assets/compiled/*.c", source=True) assetslib = assetsenv.Library("assets", sources) -Depends(assetslib, icons) +Depends(assetslib, [icons, proto, dolphin_blocking, dolphin_internal, proto_ver]) assetsenv.Install("${LIB_DIST_DIR}", assetslib) Return("assetslib") From 5486650337bb7e1ee562b1113a7f34124df0b731 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 9 Jun 2022 20:38:56 +0400 Subject: [PATCH 072/184] UI: show Radio Stack version & type in about & desktop debug view --- applications/about/about.c | 9 ++++++++- applications/desktop/views/desktop_view_debug.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/applications/about/about.c b/applications/about/about.c index 7c8a4c6970ee..92ca64eca2db 100644 --- a/applications/about/about.c +++ b/applications/about/about.c @@ -5,6 +5,7 @@ #include #include #include +#include typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message); @@ -111,18 +112,24 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* string_t buffer; string_init(buffer); const Version* ver = furi_hal_version_get_firmware_version(); + const BleGlueC2Info* c2_ver = ble_glue_get_c2_info(); if(!ver) { string_cat_printf(buffer, "No info\n"); } else { string_cat_printf( buffer, - "%s [%s]\n%s%s [%s]\n[%d] %s", + "%s [%s]\n%s%s [%s] %d.%d.%d.%d.%d\n[%d] %s", version_get_version(ver), version_get_builddate(ver), version_get_dirty_flag(ver) ? "[!] " : "", version_get_githash(ver), version_get_gitbranchnum(ver), + c2_ver->VersionMajor, + c2_ver->VersionMinor, + c2_ver->VersionBranch, + c2_ver->VersionSub, + c2_ver->VersionReleaseType, version_get_target(ver), version_get_gitbranch(ver)); } diff --git a/applications/desktop/views/desktop_view_debug.c b/applications/desktop/views/desktop_view_debug.c index 6ac62b49bc12..955f523adf3c 100644 --- a/applications/desktop/views/desktop_view_debug.c +++ b/applications/desktop/views/desktop_view_debug.c @@ -46,6 +46,7 @@ void desktop_debug_render(Canvas* canvas, void* model) { canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); ver = furi_hal_version_get_firmware_version(); + const BleGlueC2Info* c2_ver = ble_glue_get_c2_info(); if(!ver) { canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, "No info"); @@ -63,10 +64,15 @@ void desktop_debug_render(Canvas* canvas, void* model) { snprintf( buffer, sizeof(buffer), - "%s%s [%s]", + "%s%s [%s] %d.%d.%d.%d.%d", version_get_dirty_flag(ver) ? "[!] " : "", version_get_githash(ver), - version_get_gitbranchnum(ver)); + version_get_gitbranchnum(ver), + c2_ver->VersionMajor, + c2_ver->VersionMinor, + c2_ver->VersionBranch, + c2_ver->VersionSub, + c2_ver->VersionReleaseType); canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer); snprintf( From 2356f3c2083d5802c1d70ccdb076d79eb57934e8 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 10 Jun 2022 00:15:39 +0400 Subject: [PATCH 073/184] Assets: fixed orange icon backgrounds to transparent/white --- assets/icons/Archive/back_10px.png | Bin 154 -> 154 bytes assets/icons/Common/Loading_24/frame_01.png | Bin 233 -> 194 bytes assets/icons/Common/Loading_24/frame_02.png | Bin 245 -> 194 bytes assets/icons/Common/Loading_24/frame_03.png | Bin 239 -> 192 bytes assets/icons/Common/Loading_24/frame_04.png | Bin 234 -> 190 bytes assets/icons/Common/Loading_24/frame_05.png | Bin 246 -> 203 bytes assets/icons/Common/Loading_24/frame_06.png | Bin 234 -> 184 bytes assets/icons/Common/Loading_24/frame_07.png | Bin 249 -> 203 bytes .../Dolphin/DolphinFirstStart5_54x49.png | Bin 1856 -> 1721 bytes 9 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/icons/Archive/back_10px.png b/assets/icons/Archive/back_10px.png index 008efe82fa129f55c8efa77688dd507f31398896..f9c615a99e69c0100b03a9ae7b2df903da4ecd66 100644 GIT binary patch delta 117 zcmbQmIE!(Dgasor0|UeMKe7LS6k~CayA#8@b22Z19F}xPUq=Rpjs4tz5?O(Kwg8_H z*Z=?j1DTdV}-0?)(p`($JL8^l(qG4Ox QDWC=hPgg&ebxsLQ0KZ@&0{{R3 delta 117 zcmbQmIE!(D1Sba*0|Nt7K*Xzw0TPMqC7!;n?9W(vdBwyRURZV!C}rvC;us=vIr-21 zvkmM9ip3J%h2G9jE`%5)zH&}8PBazPJH$~g6~l3JqYqC7Blj|aO@=Hb#*g^L7~BqW Vzv1mptp*yx;OXk;vd$@?2>@J;C1U^p diff --git a/assets/icons/Common/Loading_24/frame_01.png b/assets/icons/Common/Loading_24/frame_01.png index 438f971f174e7b2e3327d009ec6099fe6a426fb7..d1f35692590a934aa850a77b71c7923fc1b1b360 100644 GIT binary patch delta 157 zcmaFKc!+U=gasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`C=uoA>Eak7aXFcR@!NlSi3kZ6i5dUx6B1Gi5)yb=lXMlt3KJ4u zWF#aMuxMRkN)prvV@mQ@$jfM0;eJTL*deX)OiDrm14Ca2ZOd;zB)j)8m322!%tQf3 zH#TkoL=Z+Pz&6`Uj$qJ%2Vs*_01Fx8{XN(r8ZcHpGwJl8_2fM<3xNRpzwH@8QUEd2 zOa!^7$=3oT+Q~;3&dj8uci~3+v-lxkrTR!8a{5v~DbMiz00000NkvXXu0mjfk;YV( diff --git a/assets/icons/Common/Loading_24/frame_02.png b/assets/icons/Common/Loading_24/frame_02.png index 3455cd4043ff7ac84d67b36e625f47e95a500710..b1617692131bd61a713453f0a025810acb8e446b 100644 GIT binary patch delta 157 zcmey$c!+U=gasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`C=uoA>Eak7aXFcR@!NlSi3kZ6i5dUx6B1Gi8WMCB#0nD1YyN#fQ4-9!H!66)8RUE(kZ|!K7?6F2(b0G?-4y@ z2|&%Xf)OO$Eak7aXFcR@!NlSi3kZ6i5dUx6B1Gi91;ZC+1mQp*x1|` zD5)xlH74n@bw~v8t?^^%*xF!mg)xWigwBMSJUl!Mr3SoRnZ1h@fW|U-y85}Sb4q9e E0GClOoB#j- delta 203 zcmV;+05t!=0q+5j7zqdl0002scRl!#P#AxqNklF$m~Q>jIf_JFv=i;_bUwcdGsc7`bHf zaRF=CD3>Uwumc2Pi&FpuVT;p%6~Y!z0aVd|;d)*_1I)i%Q={*;6Yb654*`n%ogNxtPCID?lqLWG002ovPDHLk FV1oH}SFHd5 diff --git a/assets/icons/Common/Loading_24/frame_04.png b/assets/icons/Common/Loading_24/frame_04.png index 12d127e0cc5fb78c4735b8d647cdefddc84bc50d..7f55b0df457223e99a1eefbb4fbc5d1ad75dd431 100644 GIT binary patch delta 153 zcmaFGxQ}sygasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`C=ur9>Eak7aXFcR@!NlSi3kZ6i5dUx6B1Gi91imE^78QXIkHl3ah9v0ZlAPbnZf{>+0tKq}f@Y z(gYC%c?8fESrGJv!9CCr)Vu`f3I^z^E0YcZwD~edAt~T(u8k2$2=L4+kkS=-kajYH zCC~h`IoL@+-cCNca4M6U{pW79oyDI5I@No60EE9*J3{~X-T(jq07*qoM6N<$g0Lb~ Av>Eak7aap%#Bj*7H5mtZ2nvIhZ$_jd}tdu#aD5DU2?bqTb zoMOjKk00c| R(pR7j44$rjF6*2UngH6`K5PI0 delta 210 zcmV;@04@K^0rmlq7zqdl0002scRl!#P#AxxNklgg-dRQRf}Bv~~g{r3ZS4YcM&fM&2u$?vGkP7<9Lul!pGAniV> zk%+ICqXa8+dX|!4bruF#&D{VxK#RE>z#*1rn>yq)fM-F56VSTT3xYL+uIKrC$p8QV M07*qoM6N<$g1B8-pa1{> diff --git a/assets/icons/Common/Loading_24/frame_06.png b/assets/icons/Common/Loading_24/frame_06.png index a876adc541e72d22b13829e4888c44645ea092e7..3354ecda423dfc60a6836f8541f78b8f0bdde6bf 100644 GIT binary patch delta 147 zcmaFGxPx(mgasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`C=p=o>Eak7aXI+_n~=l}2_}gh5|1S73|UNy3|TA~H*yJhyBM+< wtWDyWz;a2;;g%+s4u2SX2>+#aCJ6}!?gZ{W-rKQZK;sxZUHx3vIVCg!0KWAq_y7O^ delta 198 zcmV;%06G7-0qOye7zqdl0002scRl!#P#AxlNklHNbP4FglEgAC zXswJ&aKwD-WXtbG?PM+HPWCj9CVVvII+K4FoVVsvGrbTfGXMYp07*qoM6N<$f@V%t A3;+NC diff --git a/assets/icons/Common/Loading_24/frame_07.png b/assets/icons/Common/Loading_24/frame_07.png index 04049ebd2b4b66a1dc3f8190b215bb3bc4dd9e4a..70bb37f699a73101bf7a6eabb14418a9eeafec35 100644 GIT binary patch delta 166 zcmey#c$#s7gasor0|UdYo$Gf4DaPU;cPEB*=VV?2IV|apzK#qG8~eHcB(eheYymzY zuK)l42QotsU9Ov`D3R>v>Eak7aas1vM&1Sk9+!*$OHPPQZB1zJnK(;JIhBKLL9%ZD zA;*tjR$FT{c+L#4{=sXw0r>%t7zqdl0002scRl!#P#Ax!NklkjlCH5cma>+=HY6`tKu<6u@e%2Z6q5j1>e1 zj7pk8wl>+?gJtSLq>ybdkmi3>W?98da-KC;M1%fy~fDm+K}fiZik5PPFo8;^msymB-A>r7-b_6DyEXP}pq6c!0?i%mngmDsl^a zeXTq)i%as0D(zsxK#8K1G^^m$LL?!D$s#Pf>lO5oglzQDmD%WHGZCWBCAB!YD6^m> zGd~Y(21GQ-#SO><>azms%uOvx1o7-E3KEmEQ%e+5^HOY;ij?f_e6KQ*jJQ;u3cWdg^O zza5XX16CNTh!&(StIpZ<`Ay!pY_=Qu5nE1$wzW6jY))`{F@sfS=2N|MQ=H$vh-l92 ze)@mjwa;2}=kkeF?cLZsdEPO;xJAbf)VKAV&FOnGKkKnXoN&$FGjC_x%KzA>P?o-9 zy?Rpo2YK})xhLi=KO%bK`76FRPfZJX>s~wXTr{uR!lAg{XVa}onjR-rPKS9`O?ti7 z{^ZrpnP+#c&-$;n+d4G9WwrYao6G!Jo1))GsjoelF~{aY65H(VtHBo6^21&U@_2t` j)N{Qrwg0&9f|? zmrwuLFz*m^mCSed`ZQ%nyL$||sWR!;**>)hEVy~^e0B8nw;!F_j`kSe3>USMvG^Y0 z*;aaZ>huR%rGi_}u$=Kb(9tikIXdHQSl-2H-#_!oZRKxvO!%OB{@|rkp)RxYZMb$z zhEFktarA?oq2R^ILHA5tF{s z)>Zaz|E+Rl(SDMp_||(cXQ{KW@or)#=C`d0u~N2H)4DIj`^cS?v8W#qX{1v&a5Ep=O4Qzw~!M zb5+rm7T*1t?`CpVFN-zP^v>iJyCmLo=AD-jGZBlmT;aO>ckpGmD_q_4=R5a^9JuUq zI`6vjuItXz6(5Pd-V>3sH|GDu(p!sC_I7OVDZ4+_X^ZYI@d+h8cg3@|dbzq-SvoKC zE|uK0HaY#HoWI+ZA4ywXay%z$yjc`?ueMq*{`H#;m*>69jf?p?+beE|IRDe`y|D#H zntxR3mGE{|>&93={h1Yg>twfTzLxh?=1n)BEt&8n`@mbKr1n)G_DDQlJTEz=QvV;L Y{&7Qo$7 Date: Fri, 10 Jun 2022 00:17:11 +0400 Subject: [PATCH 074/184] Build: constructing assets in variant dir & copying to compiled/ --- assets/SConscript | 50 ++++---- assets/compiled/assets_icons.c | 206 ++++++++++++++++----------------- 2 files changed, 133 insertions(+), 123 deletions(-) diff --git a/assets/SConscript b/assets/SConscript index da11f4726643..fc7d755bf1b1 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -14,8 +14,8 @@ assetsenv.Append( def icons_emitter(target, source, env): target = [ - "#assets/compiled/assets_icons.c", - "#assets/compiled/assets_icons.h", + "assets_icons.c", + "assets_icons.h", ] return target, source @@ -29,20 +29,19 @@ def proto_emitter(target, source, env): for src in source: basename = os.path.splitext(src.name)[0] # print("!! ", os.path.join("#", out_path, basename + ".pb.h")) - target.append(File(os.path.join("#", out_path, basename + ".pb.c"))) - target.append(File(os.path.join("#", out_path, basename + ".pb.h"))) + target.append(File(basename + ".pb.c")) + target.append(File(basename + ".pb.h")) # print(list(t.path for t in target)) return target, source def dolphin_emitter(target, source, env): # target.append(target[0]) - out_path = target[0].path # print("dolphin_emitter", out_path) asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" target = [ - File(os.path.join("#", out_path, asset_basename + ".c")), - File(os.path.join("#", out_path, asset_basename + ".h")), + File(asset_basename + ".c"), + File(asset_basename + ".h"), ] return target, source @@ -94,22 +93,23 @@ assetsenv.Append( BUILDERS={ "IconBuilder": Builder( action=Action( - "${PYTHON3} ${ASSETS_COMPILER} icons ${SOURCE} ${TARGET.dir}", - "\tICONS\t${TARGET}", + "${PYTHON3} ${ASSETS_COMPILER} icons ${SOURCE.posix} ${TARGET.dir.posix}", + "\tICONS\t${TARGET}", ), emitter=icons_emitter, ), "ProtoBuilder": Builder( action=Action( - "${PYTHON3} ${NANOPB_COMPILER} -q -I${SOURCE.dir} -D${TARGET.dir} ${SOURCES}", - # "\tPROTO\t${SOURCE}", + "${PYTHON3} ${NANOPB_COMPILER} -q -I${SOURCE.dir.posix} -D${TARGET.dir.posix} ${SOURCES.posix}", + "\tPROTO\t${SOURCE}", ), emitter=proto_emitter, + suffix=".pb.c", src_suffix=".proto", ), "DolphinBuilder": Builder( action=Action( - '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${TARGET.dir}"', + '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${TARGET.dir.posix}"', "\tDOLPHIN\t${SOURCE}", ), emitter=dolphin_emitter, @@ -121,14 +121,14 @@ assetsenv.Append( icons_src = assetsenv.GlobRecursive("*.png", "icons") icons_src += assetsenv.GlobRecursive("frame_rate", "icons") -icons = assetsenv.IconBuilder(Dir("#/assets/compiled"), Dir("#/assets/icons")) +icons = assetsenv.IconBuilder(Dir("compiled"), Dir("#/assets/icons")) Depends(icons, icons_src) Alias("icons", icons) proto_src = Glob("protobuf/*.proto", source=True) proto_options = Glob("protobuf/*.options", source=True) -proto = assetsenv.ProtoBuilder(Dir("#/assets/compiled"), proto_src) +proto = assetsenv.ProtoBuilder(Dir("compiled"), proto_src) Depends(proto, proto_options) # Precious(proto) Alias("proto", proto) @@ -136,7 +136,7 @@ Alias("proto", proto) dolphin_internal_src = assetsenv.GlobRecursive("*", "dolphin/internal") dolphin_internal = assetsenv.DolphinBuilder( - Dir("#/assets/compiled"), + Dir("compiled"), Dir("#/assets/dolphin/internal"), DOLPHIN_RES_TYPE="internal", ) @@ -146,7 +146,7 @@ Alias("dolphin_internal", dolphin_internal) dolphin_blocking_src = assetsenv.GlobRecursive("*", "dolphin/blocking") dolphin_blocking = assetsenv.DolphinBuilder( - Dir("#/assets/compiled"), + Dir("compiled"), Dir("#/assets/dolphin/blocking"), DOLPHIN_RES_TYPE="blocking", ) @@ -154,7 +154,7 @@ Depends(dolphin_blocking, dolphin_blocking_src) Alias("dolphin_blocking", dolphin_blocking) proto_ver = assetsenv.Command( - "#/assets/compiled/protobuf_version.h", + "protobuf_version.h", "#/assets/protobuf/Changelog", action=Action( proto_ver_generator, @@ -165,8 +165,18 @@ Depends(proto_ver, proto) Alias("proto_ver", proto_ver) -sources = Glob("#/assets/compiled/*.c", source=True) -assetslib = assetsenv.Library("assets", sources) -Depends(assetslib, [icons, proto, dolphin_blocking, dolphin_internal, proto_ver]) +assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) + +assetsenv.Install("#/assets/compiled", assets_parts) + +assetslib = assetsenv.Library("assets", assets_parts) + +# sources = Glob("compiled/*.c", source=True) +# assetslib = assetsenv.Library("assets", sources) +# assetsenv.Depends( +# assetslib, (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) +# ) assetsenv.Install("${LIB_DIST_DIR}", assetslib) + + Return("assetslib") diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index fb125095a6c1..bb286df70dec 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -34,31 +34,31 @@ const uint8_t _A_Levelup2_128x64_9[] = {0x01,0x00,0xfb,0x01,0xff,0x80,0x3c,0x01, const uint8_t _A_Levelup2_128x64_10[] = {0x01,0x00,0x06,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x09,0xef,0x06,0xe4,0x07,0xe0,0x0f,0xc9,0xff,0xfb,0x9f,0xc7,0x07,0xdf,0x7e,0x03,0x38,0x0f,0xe5,0x9e,0x01,0xc6,0xf7,0x03,0xee,0xb7,0x00,0x80,0xff,0x4a,0x27,0xcf,0x84,0xcc,0xbe,0x60,0x51,0xbf,0xff,0xe8,0xb8,0x08,0x07,0xe8,0x2e,0x78,0xfe,0x4c,0xcc,0x1e,0x98,0x2a,0x04,0x03,0x88,0x1f,0x30,0x7a,0xcf,0xef,0xd8,0x10,0x78,0xee,0x01,0xe7,0x4f,0x84,0xc9,0xbf,0x21,0xf2,0xdf,0xe0,0x24,0x10,0x0a,0x37,0xfc,0xe2,0x54,0xfe,0x4c,0x9c,0x1e,0x90,0x09,0x0c,0x03,0x03,0xfe,0xd5,0x93,0xcb,0x91,0x07,0xfc,0x11,0x8a,0xbf,0x00,0x9f,0xe0,0x30,0x17,0xe8,0x89,0x88,0x41,0xe3,0xcf,0xfe,0x03,0xcf,0x80,0x00,0x18,0x07,0xf4,0x3e,0x70,0x9e,0x70,0x3c,0xe5,0xf2,0x08,0xf4,0x85,0x00,0x2b,0x19,0x97,0xe4,0x2c,0x31,0x28,0x17,0x09,0x63,0x1f,0xe9,0x7f,0x43,0x81,0x0e,0x81,0x4e,0x95,0xd3,0x17,0xa4,0x68,0x61,0x90,0x46,0x09,0x73,0xf0,0x79,0xc9,0x05,0x3f,0xe4,0x1f,0x18,0xbc,0xa2,0x3d,0x05,0xc2,0x30,0x4b,0x9f,0xf3,0xce,0x4f,0x01,0xeb,0x12,0x82,0xd2,0x18,0x24,0x0f,0x1e,0x48,0x3e,0x3f,0x00,0xf3,0xc1,0xf2,0x45,0xe5,0x5f,0xfa,0x0b,0xce,0x19,0xc1,0xfd,0x87,0xd2,0xde,0x06,0x1f,0xf4,0xec,0x9e,0x30,0x4b,0xff,0xc8,0x1e,0x7e,0x30,0x7a,0x52,0xfa,0x1f,0x0e,0x16,0x03,0xf8,0x4f,0x30,0x78,0x9b,0xcf,0x17,0x90,0x86,0xcf,0xe0,0x01,0x61,0xff,0xc3,0xf0,0x5f,0x79,0x05,0x20,0x9e,0x50,0xb9,0x0c,0x0a,0x09,0x00,0xbf,0xa3,0xe6,0x17,0xc2,0x80,0xc0,0x30,0x1b,0xf0,0x7d,0x41,0x01,0xe3,0xe0,0xef,0x83,0xea,0x10,0x0f,0x1f,0xc3,0x3a,0x01,0xe7,0x40,0x80,0x73,0xa0,0x64,0xf1,0x00,0x37,0xdc,0x1e,0x38,0x0e,0x0c,0x0f,0xfe,0x6f,0x10,0x03,0xc3,0x4b,0xa3,0xfe,0x80,0xfc,0x11,0x02,0x70,0x18,0x01,0x5c,0x41,0xe5,0x12,0x81,0x01,0xc7,0xfd,0x0f,0x5f,0x8f,0xff,0xe6,0x02,0x13,0xb1,0xc8,0x89,0xc2,0x00,0x20,0x79,0x43,0x43,0xe4,0x46,0x2e,0x10,0x38,0xe0,0x02,0xf2,0x83,0x01,0x88,0x8c,0x50,0x28,0x18,0x1c,0xb8,0x1f,0xc0,0x7c,0xc3,0x00,0xe5,0x30,0x1c,0x94,0x1b,0x39,0x88,0x07,0xa4,0xc0,0x1e,0x5c,0xe0,0x79,0xe8,0xb0,0x90,0x10,0x79,0xf0,0x05,0xc5,0xfb,0x9f,0x92,0x44,0x1e,0x38,0x28,0x18,0x3c,0xe0,0x04,0x01,0xfe,0x7e,0xc3,0xe9,0x81,0x83,0x83,0xd2,0x1c,0xbf,0x10,0x7a,0x87,0xda,0x24,0xdf,0x1f,0xaa,0x20,0x87,0xee,0x0f,0x28,0x07,0xd0,0x1e,0x65,0xf5,0x9d,0x40,0x21,0x20,0xf1,0xf6,0x03,0xcc,0xfe,0xb4,0x60,0x7e,0xdf,0xf0,0x30,0x08,0x28,0x1c,0x7b,0x00,0xf2,0x2b,0x0a,0xfc,0xef,0xf0,0x1c,0x0b,0xc0,0x41,0xe8,0x2b,0x23,0x29,0x6f,0xe0,0x18,0x27,0x81,0x6a,0x01,0xe4,0xd2,0x2d,0xf8,0x3c,0xe8,0x80,0xf6,0x83,0xa9,0xc8,0x0a,0x35,0xf0,0x78,0xc0,0x41,0x03,0x48,0x07,0x90,0x01,0x65,0xf0,0x09,0x40,0x3c,0xb1,0x04,0x81,0x00,0x34,0x5c,0x56,0x26,0x72,0x84,0x13,0x08,0x00,0x80,}; const uint8_t* const _A_Levelup2_128x64[] = {_A_Levelup2_128x64_0,_A_Levelup2_128x64_1,_A_Levelup2_128x64_2,_A_Levelup2_128x64_3,_A_Levelup2_128x64_4,_A_Levelup2_128x64_5,_A_Levelup2_128x64_6,_A_Levelup2_128x64_7,_A_Levelup2_128x64_8,_A_Levelup2_128x64_9,_A_Levelup2_128x64_10}; -const uint8_t _I_125_10px_0[] = {0x00,0xE0,0x00,0x00,0x01,0x0E,0x02,0x31,0x02,0x45,0x02,0x91,0x00,0xAA,0x00,0x92,0x00,0x44,0x00,0x38,0x00,}; +const uint8_t _I_125_10px_0[] = {0x00,0xe0,0x00,0x00,0x01,0x0e,0x02,0x31,0x02,0x45,0x02,0x91,0x00,0xaa,0x00,0x92,0x00,0x44,0x00,0x38,0x00,}; const uint8_t* const _I_125_10px[] = {_I_125_10px_0}; const uint8_t _I_Nfc_10px_0[] = {0x00,0x80,0x00,0x00,0x01,0x22,0x02,0x43,0x02,0x45,0x02,0x49,0x02,0x31,0x02,0x22,0x02,0x00,0x01,0x80,0x00,}; const uint8_t* const _I_Nfc_10px[] = {_I_Nfc_10px_0}; -const uint8_t _I_back_10px_0[] = {0x00,0x00,0x00,0x10,0x00,0x38,0x00,0x7C,0x00,0xFE,0x00,0x38,0x00,0x38,0x00,0xF8,0x01,0xF8,0x01,0x00,0x00,}; +const uint8_t _I_back_10px_0[] = {0x00,0x00,0x00,0x10,0x00,0x38,0x00,0x7c,0x00,0xfe,0x00,0x38,0x00,0x38,0x00,0xf8,0x01,0xf8,0x01,0x00,0x00,}; const uint8_t* const _I_back_10px[] = {_I_back_10px_0}; const uint8_t _I_badusb_10px_0[] = {0x01,0x00,0x11,0x00,0x00,0x0f,0xe2,0x01,0xfc,0x80,0xdd,0x20,0x32,0x48,0x08,0x14,0x40,0x23,0xa8,0x08,0xa0,}; const uint8_t* const _I_badusb_10px[] = {_I_badusb_10px_0}; -const uint8_t _I_ble_10px_0[] = {0x00,0x04,0x00,0x8C,0x00,0x15,0x01,0x56,0x02,0x8C,0x02,0x8C,0x02,0x56,0x02,0x15,0x01,0x8C,0x00,0x04,0x00,}; +const uint8_t _I_ble_10px_0[] = {0x00,0x04,0x00,0x8c,0x00,0x15,0x01,0x56,0x02,0x8c,0x02,0x8c,0x02,0x56,0x02,0x15,0x01,0x8c,0x00,0x04,0x00,}; const uint8_t* const _I_ble_10px[] = {_I_ble_10px_0}; const uint8_t _I_dir_10px_0[] = {0x01,0x00,0x11,0x00,0x00,0x0c,0xfe,0x01,0x41,0x80,0x7f,0xe0,0x70,0x18,0x10,0x05,0x7f,0xd0,0x10,0x88,0x80,}; const uint8_t* const _I_dir_10px[] = {_I_dir_10px_0}; -const uint8_t _I_ibutt_10px_0[] = {0x00,0x80,0x03,0x40,0x02,0x20,0x02,0x10,0x01,0x8E,0x00,0x41,0x00,0x2D,0x00,0x2D,0x00,0x21,0x00,0x1E,0x00,}; +const uint8_t _I_ibutt_10px_0[] = {0x00,0x80,0x03,0x40,0x02,0x20,0x02,0x10,0x01,0x8e,0x00,0x41,0x00,0x2d,0x00,0x2d,0x00,0x21,0x00,0x1e,0x00,}; const uint8_t* const _I_ibutt_10px[] = {_I_ibutt_10px_0}; -const uint8_t _I_ir_10px_0[] = {0x00,0xFC,0x00,0x02,0x01,0x79,0x02,0x84,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x58,0x00,0x78,0x00,0xFF,0x03,}; +const uint8_t _I_ir_10px_0[] = {0x00,0xfc,0x00,0x02,0x01,0x79,0x02,0x84,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x58,0x00,0x78,0x00,0xff,0x03,}; const uint8_t* const _I_ir_10px[] = {_I_ir_10px_0}; -const uint8_t _I_loading_10px_0[] = {0x00,0xFE,0x00,0x82,0x00,0xBA,0x00,0x54,0x00,0x28,0x00,0x28,0x00,0x44,0x00,0x92,0x00,0xBA,0x00,0xFE,0x00,}; +const uint8_t _I_loading_10px_0[] = {0x00,0xfe,0x02,0xcb,0x00,0xba,0x01,0x56,0x02,0xaa,0x00,0xbc,0x02,0x65,0x01,0x9a,0x02,0xfa,0x00,0xff,0x01,}; const uint8_t* const _I_loading_10px[] = {_I_loading_10px_0}; const uint8_t _I_music_10px_0[] = {0x01,0x00,0x10,0x00,0xf0,0x00,0x46,0x03,0x20,0x80,0x00,0x4e,0x7d,0x00,0x9f,0x80,0x4a,0x3c,0x13,0x20,}; @@ -67,13 +67,13 @@ const uint8_t* const _I_music_10px[] = {_I_music_10px_0}; const uint8_t _I_sub1_10px_0[] = {0x01,0x00,0x12,0x00,0x81,0x40,0x69,0x30,0x2c,0x2c,0x0b,0x6a,0x01,0x28,0x0c,0x0a,0x65,0x01,0x98,0x40,0x00,0x26,}; const uint8_t* const _I_sub1_10px[] = {_I_sub1_10px_0}; -const uint8_t _I_u2f_10px_0[] = {0x00,0x00,0x00,0xFE,0x01,0x01,0x02,0x0C,0x00,0xF2,0x03,0x92,0x02,0x0C,0x00,0x01,0x02,0xFE,0x01,0x00,0x00,}; +const uint8_t _I_u2f_10px_0[] = {0x00,0x00,0x00,0xfe,0x01,0x01,0x02,0x0c,0x00,0xf2,0x03,0x92,0x02,0x0c,0x00,0x01,0x02,0xfe,0x01,0x00,0x00,}; const uint8_t* const _I_u2f_10px[] = {_I_u2f_10px_0}; const uint8_t _I_unknown_10px_0[] = {0x01,0x00,0x12,0x00,0xbc,0x40,0x39,0x90,0x0c,0x24,0x03,0x81,0x00,0xb0,0x40,0x26,0x00,0x12,0x00,0x08,0x14,0xc0,}; const uint8_t* const _I_unknown_10px[] = {_I_unknown_10px_0}; -const uint8_t _I_update_10px_0[] = {0x00,0xFE,0x01,0x01,0x02,0xFF,0x03,0x01,0x02,0x31,0x02,0x79,0x02,0xFD,0x02,0x31,0x02,0x31,0x02,0xFF,0x03,}; +const uint8_t _I_update_10px_0[] = {0x00,0xfe,0x01,0x01,0x02,0xff,0x03,0x01,0x02,0x31,0x02,0x79,0x02,0xfd,0x02,0x31,0x02,0x31,0x02,0xff,0x03,}; const uint8_t* const _I_update_10px[] = {_I_update_10px_0}; const uint8_t _I_BLE_Pairing_128x64_0[] = {0x01,0x00,0xb7,0x01,0x00,0x6c,0x38,0x1f,0xd0,0x10,0x76,0xe0,0x03,0xdd,0x40,0x07,0xf4,0x82,0x01,0x08,0x07,0xf4,0xc0,0x1f,0x91,0x08,0x07,0x00,0x1f,0xc0,0x0d,0x1e,0xe8,0x3f,0xc0,0x03,0x58,0x80,0xcf,0x11,0xd9,0xaf,0x85,0x77,0x01,0xf7,0x60,0xf8,0x45,0xff,0x05,0xed,0x9e,0x7c,0x09,0xdb,0xe0,0x2f,0x78,0x03,0x3c,0x8e,0xee,0x8a,0x43,0x81,0xfb,0x0c,0x66,0xe8,0xfc,0x59,0xba,0x6f,0x28,0x1b,0xfb,0xa3,0x80,0xfc,0xa0,0x1f,0xc6,0x86,0xbf,0xc3,0x78,0xce,0x04,0x19,0x26,0x77,0xfa,0x43,0xbe,0x12,0xa0,0x7e,0xf8,0x2a,0xa2,0x02,0xff,0x89,0x27,0x01,0xbf,0x99,0x38,0x8a,0xfc,0x0f,0x8e,0x07,0xfe,0x0e,0x94,0x2c,0x07,0xfc,0x7f,0x1f,0xf5,0x00,0xc3,0x00,0xe4,0x31,0x13,0xd1,0x00,0x0a,0xb8,0x19,0x25,0x91,0xc0,0x81,0xe2,0xb9,0x4d,0x5d,0x78,0x64,0x2e,0x84,0x80,0x61,0x07,0x02,0x3e,0x2a,0xa4,0xa2,0x00,0xf2,0x40,0x20,0xe3,0x21,0xa0,0x62,0x9f,0x60,0x05,0x02,0x3e,0x36,0x41,0x66,0x23,0x20,0x51,0xfc,0x40,0x68,0x0f,0x15,0x90,0x60,0x20,0x1b,0x09,0x89,0x70,0x46,0x42,0x07,0x14,0x99,0x41,0xe8,0x1f,0x18,0x0c,0x07,0xc1,0x19,0xff,0xc3,0xce,0x6b,0x54,0x8f,0xe0,0x3f,0x90,0x78,0x17,0x02,0x1a,0x70,0x39,0x01,0xa0,0xb1,0x53,0xb5,0x88,0xc7,0xe0,0x98,0x08,0x3a,0xd5,0xe8,0x97,0xd0,0x78,0xcf,0xe1,0x07,0xf1,0x0d,0x08,0x00,0x74,0x10,0x80,0x18,0xe8,0x97,0xc3,0xf2,0xff,0xc4,0x03,0xe3,0x04,0x8c,0x19,0xcc,0x00,0x35,0x0c,0x3c,0x03,0xf9,0x3f,0xb0,0x8f,0xc6,0x31,0x0e,0x0f,0x90,0x90,0xb5,0x45,0xc1,0xf8,0x4f,0xf0,0xde,0x18,0xcc,0x82,0x08,0x1f,0x22,0x20,0xd0,0x3a,0xab,0xd1,0xe0,0x5f,0xa1,0x1b,0x19,0x8d,0x02,0x04,0x9a,0x1d,0x04,0x28,0x26,0x36,0xa8,0x05,0xf0,0xe0,0x3f,0x04,0xf8,0xd0,0x30,0x55,0xfa,0xad,0x54,0x3e,0x35,0x09,0xab,0xac,0xbf,0x2b,0xf2,0x0a,0x0e,0xfb,0x55,0xaa,0x0f,0x94,0x68,0x04,0x30,0x6f,0xd3,0x7c,0xb0,0x15,0x0f,0xfd,0x7f,0xeb,0x05,0x4f,0x0b,0x60,0xa3,0x1f,0x28,0x0b,0xfc,0xbc,0x30,0x1f,0xf7,0xfe,0x54,0x2c,0x18,0x30,0x3c,0x6f,0x00,0xf2,0x1c,0x8c,0xf8,0x10,0x3c,0x00,0xf8,0xd5,0x5c,0x05,0xb8,0xb0,0xaa,0xdb,0x01,0x2b,0x31,0x0a,0xdc,0xa7,0x00,0xe6,0x00,0x0c,0x56,0x00,0x7e,0x10,0x00,0xcc,0x01,0xf0,0x1f,0x1b,0x40,0x2e,0x00,0x07,0x16,0x10,0x90,0x02,0xe5,0x90,0x06,0x29,0x00,0x2a,0xa9,0x00,0x2f,0x10,0x02,0xa5,0x10,0x02,0xf1,0x00,0x2a,0xa0,0x0d,0xc0,0x00,0xec,0x01,0xfd,0x60,0x17,0x6a,0xc0,0x60,0x40,0xfd,0xc0,0x30,0x04,0x01,0xb0,0xb0,0x7f,0x45,0x80,}; @@ -100,10 +100,10 @@ const uint8_t* const _I_Pressed_Button_13x13[] = {_I_Pressed_Button_13x13_0}; const uint8_t _I_Space_65x18_0[] = {0x01,0x00,0x26,0x00,0xfc,0x7f,0xc0,0x09,0x7f,0x80,0x41,0x81,0xeb,0x80,0x80,0x40,0xc3,0x2d,0x01,0x04,0x78,0x23,0xc1,0x1e,0x08,0xf0,0x47,0x82,0x3c,0x11,0x70,0x73,0xeb,0x40,0x7f,0xc8,0xf5,0xff,0xc0,0x3f,0x89,0x87,}; const uint8_t* const _I_Space_65x18[] = {_I_Space_65x18_0}; -const uint8_t _I_Voldwn_6x6_0[] = {0x00,0x08,0x0C,0x2F,0x2F,0x0C,0x08,}; +const uint8_t _I_Voldwn_6x6_0[] = {0x00,0x08,0x0c,0x2f,0x2f,0x0c,0x08,}; const uint8_t* const _I_Voldwn_6x6[] = {_I_Voldwn_6x6_0}; -const uint8_t _I_Volup_8x6_0[] = {0x00,0x48,0x8C,0xAF,0xAF,0x8C,0x48,}; +const uint8_t _I_Volup_8x6_0[] = {0x00,0x48,0x8c,0xaf,0xaf,0x8c,0x48,}; const uint8_t* const _I_Volup_8x6[] = {_I_Volup_8x6_0}; const uint8_t _I_Clock_18x18_0[] = {0x01,0x00,0x31,0x00,0xe0,0x43,0xe0,0x1f,0x09,0xfc,0x03,0xf1,0x7f,0x80,0x47,0x3c,0x10,0x0d,0xf7,0xde,0x02,0x02,0x2d,0xff,0xde,0x07,0x7f,0xfd,0xc0,0xff,0xff,0xc0,0x11,0xdf,0xff,0x30,0x3d,0xff,0xca,0x07,0x3e,0xfa,0x85,0xc7,0xe5,0x01,0x10,0x10,0x98,0x85,0x84,0x32,0x20,}; @@ -124,7 +124,7 @@ const uint8_t* const _I_EviWaiting1_18x21[] = {_I_EviWaiting1_18x21_0}; const uint8_t _I_EviWaiting2_18x21_0[] = {0x01,0x00,0x31,0x00,0x86,0x70,0x20,0x10,0x6c,0x04,0x06,0x0f,0x80,0x81,0xf3,0xf9,0xf0,0x3f,0xff,0xfc,0x04,0x7f,0xef,0xfc,0x04,0x04,0xa0,0xb2,0xeb,0xed,0xe0,0x7f,0x7f,0xb8,0x08,0xf1,0xf8,0xf0,0xd4,0xff,0x3f,0xf0,0x0f,0xc5,0xfe,0x01,0xf0,0x9f,0xc0,0x38,0x10,0xf8,0x00,}; const uint8_t* const _I_EviWaiting2_18x21[] = {_I_EviWaiting2_18x21_0}; -const uint8_t _I_Percent_10x14_0[] = {0x00,0x0C,0x03,0x1E,0x03,0x33,0x03,0xB3,0x03,0xDE,0x01,0xEC,0x00,0x70,0x00,0x38,0x00,0xDC,0x00,0xEE,0x01,0x37,0x03,0x33,0x03,0xE3,0x01,0xC3,0x00,}; +const uint8_t _I_Percent_10x14_0[] = {0x00,0x0c,0x03,0x1e,0x03,0x33,0x03,0xb3,0x03,0xde,0x01,0xec,0x00,0x70,0x00,0x38,0x00,0xdc,0x00,0xee,0x01,0x37,0x03,0x33,0x03,0xe3,0x01,0xc3,0x00,}; const uint8_t* const _I_Percent_10x14[] = {_I_Percent_10x14_0}; const uint8_t _I_Smile_18x18_0[] = {0x01,0x00,0x2d,0x00,0xe0,0x43,0xe0,0x1f,0x09,0xfc,0x03,0xf1,0x7f,0x80,0x7f,0x3f,0xf0,0x0f,0xf7,0xfe,0x02,0x02,0x2f,0xff,0xfe,0x07,0xcf,0xe7,0xc0,0xf0,0xf8,0x70,0x11,0x82,0x08,0x1c,0x41,0x42,0xdf,0x7d,0xe0,0x37,0xcf,0xc0,0x98,0xc5,0x84,0x32,0x20,}; @@ -133,25 +133,25 @@ const uint8_t* const _I_Smile_18x18[] = {_I_Smile_18x18_0}; const uint8_t _I_UsbTree_48x22_0[] = {0x01,0x00,0x3c,0x00,0x00,0x14,0x3c,0x08,0x78,0x08,0xf8,0x10,0xff,0xe0,0x59,0xb0,0x04,0x52,0xc0,0x1d,0x48,0xc0,0x9d,0x00,0xa7,0x02,0x80,0x41,0x80,0xa5,0x0e,0x02,0xa4,0xfb,0xfe,0x00,0xa1,0x49,0x04,0x48,0x0a,0x81,0xd1,0xc0,0x40,0x45,0x26,0x05,0x30,0x01,0x41,0xbe,0x10,0x30,0x2c,0x7e,0x3f,0xe0,0x59,0x80,0x04,0x50,0x0a,0x60,}; const uint8_t* const _I_UsbTree_48x22[] = {_I_UsbTree_48x22_0}; -const uint8_t _I_ButtonCenter_7x7_0[] = {0x00,0x1C,0x22,0x5D,0x5D,0x5D,0x22,0x1C,}; +const uint8_t _I_ButtonCenter_7x7_0[] = {0x00,0x1c,0x22,0x5d,0x5d,0x5d,0x22,0x1c,}; const uint8_t* const _I_ButtonCenter_7x7[] = {_I_ButtonCenter_7x7_0}; -const uint8_t _I_ButtonDown_7x4_0[] = {0x00,0x7F,0x3E,0x1C,0x08,}; +const uint8_t _I_ButtonDown_7x4_0[] = {0x00,0x7f,0x3e,0x1c,0x08,}; const uint8_t* const _I_ButtonDown_7x4[] = {_I_ButtonDown_7x4_0}; const uint8_t _I_ButtonLeftSmall_3x5_0[] = {0x00,0x04,0x06,0x07,0x06,0x04,}; const uint8_t* const _I_ButtonLeftSmall_3x5[] = {_I_ButtonLeftSmall_3x5_0}; -const uint8_t _I_ButtonLeft_4x7_0[] = {0x00,0x08,0x0C,0x0E,0x0F,0x0E,0x0C,0x08,}; +const uint8_t _I_ButtonLeft_4x7_0[] = {0x00,0x08,0x0c,0x0e,0x0f,0x0e,0x0c,0x08,}; const uint8_t* const _I_ButtonLeft_4x7[] = {_I_ButtonLeft_4x7_0}; const uint8_t _I_ButtonRightSmall_3x5_0[] = {0x00,0x01,0x03,0x07,0x03,0x01,}; const uint8_t* const _I_ButtonRightSmall_3x5[] = {_I_ButtonRightSmall_3x5_0}; -const uint8_t _I_ButtonRight_4x7_0[] = {0x00,0x01,0x03,0x07,0x0F,0x07,0x03,0x01,}; +const uint8_t _I_ButtonRight_4x7_0[] = {0x00,0x01,0x03,0x07,0x0f,0x07,0x03,0x01,}; const uint8_t* const _I_ButtonRight_4x7[] = {_I_ButtonRight_4x7_0}; -const uint8_t _I_ButtonUp_7x4_0[] = {0x00,0x08,0x1C,0x3E,0x7F,}; +const uint8_t _I_ButtonUp_7x4_0[] = {0x00,0x08,0x1c,0x3e,0x7f,}; const uint8_t* const _I_ButtonUp_7x4[] = {_I_ButtonUp_7x4_0}; const uint8_t _I_DFU_128x50_0[] = {0x01,0x00,0x2e,0x02,0x00,0x57,0xfe,0x0e,0x0e,0xcf,0x84,0x02,0x70,0x0f,0xc8,0x74,0x03,0x80,0x0e,0xbc,0x7c,0x04,0x06,0x30,0x30,0x74,0xe0,0x2f,0xe0,0x42,0x82,0x03,0xe7,0x81,0xff,0x02,0x14,0x20,0x1f,0x3e,0x00,0x79,0xc4,0x01,0xfd,0x20,0x07,0xd5,0xd4,0xe2,0x53,0xf2,0x74,0xff,0xe1,0x40,0x41,0x87,0xd8,0x01,0xf1,0x60,0xf0,0x43,0xca,0x43,0xe0,0xa7,0x83,0xe2,0x30,0x01,0x29,0x84,0x7b,0x20,0x0f,0x88,0x30,0x3c,0xb1,0x90,0x1d,0x00,0xfa,0x30,0x3f,0xf8,0xcc,0x02,0xc6,0x31,0x1f,0x83,0x49,0xa8,0x16,0x0a,0xf4,0x7f,0x00,0x21,0x1f,0x04,0x38,0x06,0x20,0x04,0x90,0x46,0x35,0xf0,0xfa,0x00,0xcc,0x7f,0x10,0x14,0x0b,0x46,0x20,0xd5,0x70,0x50,0xb4,0x06,0xf1,0x00,0x9f,0x03,0xd7,0x09,0x81,0xd7,0xc0,0x8b,0x85,0x38,0xc0,0x50,0x41,0xeb,0x63,0xc0,0x07,0xc6,0x90,0xbf,0x2b,0x05,0x01,0xb8,0xb1,0x0c,0x06,0xae,0x01,0x24,0x6f,0x94,0x42,0x80,0xb2,0x49,0xc4,0x33,0x80,0x1f,0x18,0x93,0xfc,0xa1,0x14,0x0e,0x02,0x9c,0x43,0xc3,0x07,0x81,0xfc,0x03,0xe2,0xc0,0x28,0x14,0x10,0x5e,0x3f,0x03,0xc0,0xcf,0xf8,0x10,0x0f,0xe5,0x56,0x03,0x05,0xf0,0x40,0x20,0x20,0xf2,0x42,0x0d,0xfd,0x72,0x30,0x0f,0xf8,0x7c,0x41,0xe3,0x80,0x10,0x0d,0x00,0x5c,0x4a,0xd1,0x87,0xf8,0x39,0xf5,0x5c,0x0c,0x0b,0xe0,0x1c,0x10,0x78,0xfc,0x02,0x04,0x20,0x1f,0xf7,0x0f,0x57,0x80,0x81,0x5e,0x13,0x83,0x01,0x1f,0x97,0xff,0xfe,0x03,0x2e,0x07,0x57,0x03,0x01,0xbf,0x1d,0x45,0x70,0x27,0xe4,0xff,0x8c,0x07,0xf5,0x83,0xe0,0xcf,0xe1,0x00,0xf6,0x10,0x8c,0x07,0xb1,0x07,0xc1,0xfc,0x63,0xe5,0xd2,0x07,0x8f,0x80,0x1a,0x21,0xe1,0xc0,0x71,0xe0,0x20,0xf1,0x24,0x88,0x34,0x62,0x00,0xe3,0x3f,0x8d,0xfe,0x81,0x80,0xc1,0xf8,0x5b,0xe2,0x0f,0x18,0xc7,0xf0,0x1e,0x50,0x35,0xa0,0xc8,0x3f,0x98,0x30,0x70,0x87,0x44,0x1e,0x21,0xe3,0xf8,0x02,0x4b,0xaf,0x01,0x81,0xb3,0xca,0x01,0x1c,0x25,0x94,0x01,0x04,0x58,0x8d,0x5c,0x0b,0xc6,0x08,0x10,0x78,0xc3,0x3f,0xf0,0x72,0x88,0x98,0x8b,0x89,0x55,0x82,0xc7,0x9b,0xe5,0x00,0x87,0x26,0xc4,0x46,0x20,0xf2,0xd1,0x87,0xc6,0x0c,0xdf,0x21,0x50,0x8a,0xc7,0x00,0x38,0x2e,0x04,0x42,0xaf,0x05,0x06,0x0a,0xb8,0x70,0x0f,0x91,0x80,0x5c,0x03,0xc5,0x30,0x84,0x6a,0xe1,0x40,0xf1,0x7b,0x0f,0x00,0x7a,0x24,0x21,0x07,0x94,0x33,0x09,0x57,0x8a,0x93,0x85,0xec,0x3e,0x00,0x79,0x0b,0x88,0x06,0x3c,0x3f,0xfc,0xa8,0x1e,0x21,0x91,0x76,0x90,0x90,0x40,0x03,0xe0,0xe0,0x78,0x3f,0xd5,0x58,0x0e,0x08,0x32,0x3f,0x88,0xa8,0x90,0x8c,0x25,0x30,0xbc,0x7f,0xb5,0x50,0x1b,0xe0,0x20,0x7f,0x92,0x33,0x88,0x97,0x4a,0x07,0x0c,0x9e,0x5f,0xeb,0xaa,0xf2,0x74,0x8d,0x17,0x80,0x06,0x29,0xf1,0xe0,0x71,0xfb,0xfd,0x71,0xd8,0xff,0xf8,0x21,0x71,0x04,0x87,0x01,0xc1,0xa1,0xff,0x83,0xe7,0xf0,0xff,0xc1,0x51,0xe4,0xdd,0x1b,0x07,0xc2,0x63,0xf6,0x0f,0x9f,0xeb,0x5f,0x02,0x77,0x8a,0xc4,0xa3,0x17,0xc8,0x44,0x8c,0x34,0x20,0x71,0xfe,0x99,0x04,0x88,0x40,0x01,0xc3,0x47,0xf0,0x93,0x0f,0xf4,0x28,0x0e,0x3a,0xad,0x50,0x39,0x30,0x1f,0x18,0x3d,0x0e,0x31,0xff,0x3d,0x0c,0x02,0xa8,0x03,0x20,0x01,0x7e,0x3f,0xf8,0x09,0x06,0x33,0xfe,0x1b,0x50,}; @@ -202,13 +202,13 @@ const uint8_t* const _I_DolphinOkay_41x43[] = {_I_DolphinOkay_41x43_0}; const uint8_t _I_ArrowDownEmpty_14x15_0[] = {0x01,0x00,0x17,0x00,0xfc,0x41,0xe1,0x10,0x40,0x0c,0xc3,0xe7,0x90,0x19,0x04,0x0a,0x20,0x08,0x10,0x48,0xc4,0x20,0x52,0x08,0x0f,0x02,0x00,}; const uint8_t* const _I_ArrowDownEmpty_14x15[] = {_I_ArrowDownEmpty_14x15_0}; -const uint8_t _I_ArrowDownFilled_14x15_0[] = {0x00,0xF8,0x07,0x08,0x04,0xE8,0x05,0x68,0x05,0xA8,0x05,0x68,0x05,0xA8,0x05,0x6F,0x3D,0xA1,0x21,0xFA,0x17,0xF4,0x0B,0xE8,0x05,0xD0,0x02,0x20,0x01,0xC0,0x00,}; +const uint8_t _I_ArrowDownFilled_14x15_0[] = {0x00,0xf8,0x07,0x08,0x04,0xe8,0x05,0x68,0x05,0xa8,0x05,0x68,0x05,0xa8,0x05,0x6f,0x3d,0xa1,0x21,0xfa,0x17,0xf4,0x0b,0xe8,0x05,0xd0,0x02,0x20,0x01,0xc0,0x00,}; const uint8_t* const _I_ArrowDownFilled_14x15[] = {_I_ArrowDownFilled_14x15_0}; const uint8_t _I_ArrowUpEmpty_14x15_0[] = {0x01,0x00,0x18,0x00,0xe0,0x40,0x24,0x10,0x18,0x84,0x0a,0x11,0x04,0x82,0x42,0x20,0x51,0x08,0x0c,0x82,0x1f,0x3c,0x04,0x88,0x06,0x7f,0x10,0x70,}; const uint8_t* const _I_ArrowUpEmpty_14x15[] = {_I_ArrowUpEmpty_14x15_0}; -const uint8_t _I_ArrowUpFilled_14x15_0[] = {0x00,0xC0,0x00,0x20,0x01,0xD0,0x02,0xE8,0x05,0xF4,0x0B,0xFA,0x17,0x61,0x21,0xAF,0x3D,0x68,0x05,0xA8,0x05,0x68,0x05,0xA8,0x05,0xE8,0x05,0x08,0x04,0xF8,0x07,}; +const uint8_t _I_ArrowUpFilled_14x15_0[] = {0x00,0xc0,0x00,0x20,0x01,0xd0,0x02,0xe8,0x05,0xf4,0x0b,0xfa,0x17,0x61,0x21,0xaf,0x3d,0x68,0x05,0xa8,0x05,0x68,0x05,0xa8,0x05,0xe8,0x05,0x08,0x04,0xf8,0x07,}; const uint8_t* const _I_ArrowUpFilled_14x15[] = {_I_ArrowUpFilled_14x15_0}; const uint8_t _I_DolphinReadingSuccess_59x63_0[] = {0x01,0x00,0x19,0x01,0x00,0x1d,0x00,0x0f,0xd2,0x00,0x21,0xe0,0x3f,0xf0,0xf9,0x00,0x40,0xee,0x00,0x11,0x88,0x04,0x0e,0x18,0x11,0x18,0x8c,0x40,0x0e,0x50,0x30,0x10,0xc0,0xa1,0x01,0xe2,0x05,0x14,0x12,0x08,0x33,0x58,0x44,0x08,0x66,0xa1,0xe3,0x01,0x9c,0x83,0x00,0x24,0x11,0x11,0x06,0xc4,0x76,0x20,0x75,0x15,0x99,0x48,0xc0,0xe9,0x0f,0x03,0x95,0xfc,0x86,0x3c,0x09,0x80,0x1c,0x7c,0x00,0x91,0x81,0x48,0x2f,0xc1,0x41,0x8c,0xc0,0x20,0x30,0x1c,0x87,0xfc,0x0e,0x30,0x70,0x70,0x81,0xc7,0xe6,0x07,0x18,0x08,0x1c,0xb9,0x1e,0x38,0x0f,0x02,0x01,0xf0,0x03,0xa0,0xa4,0x7f,0x90,0x30,0x38,0xff,0xe0,0x28,0x21,0xff,0x06,0x44,0x0e,0x46,0xe1,0x01,0x8c,0x03,0x34,0x2f,0x25,0x18,0x80,0xc7,0x2a,0x03,0x2e,0x01,0x3c,0x70,0x12,0xa2,0x39,0x78,0x27,0xe0,0x31,0xea,0x82,0xc4,0x6c,0x31,0xf0,0x78,0xea,0xb0,0x22,0x31,0xfc,0x1a,0xc6,0x01,0x55,0x25,0x88,0xf8,0x4b,0x02,0x1f,0x13,0xe1,0x7f,0x97,0x85,0x15,0x03,0x90,0xf8,0xa0,0x10,0xa1,0xb1,0x0e,0x88,0x00,0x7f,0x0f,0xc0,0x7c,0x57,0x27,0x3c,0xb0,0x7f,0x5f,0xa9,0x1f,0xc0,0x6a,0xc5,0x05,0xc0,0xf0,0x11,0x46,0xac,0x18,0x3f,0xf9,0x54,0x75,0x00,0x73,0x1f,0x0f,0xfe,0xfe,0xc6,0x30,0x01,0xbc,0x48,0x00,0x84,0x82,0x00,0x1b,0x64,0xc0,0x07,0x60,0x03,0xb4,0x70,0x0c,0xbf,0x82,0x31,0x01,0x8d,0x0c,0x40,0x02,0x37,0x08,0x1d,0x74,0x00,0x76,0xa0,0x01,0xdb,0x01,0xfe,0x85,0x8b,0x96,0xaa,0x9b,0x30,0x01,0x6a,0xa3,0x40,0x75,0xaa,0x03,0xdb,0x50,0xbb,0x30,0x01,0x54,0x24,0x25,0xe6,0x51,0x08,0x1f,0x68,0x00,0x7f,0x03,0xf2,0x79,0xc0,0xf4,}; @@ -220,10 +220,10 @@ const uint8_t* const _I_Down_25x27[] = {_I_Down_25x27_0}; const uint8_t _I_Down_hvr_25x27_0[] = {0x01,0x00,0x3a,0x00,0xfc,0x7f,0xe7,0xf0,0x0f,0xe7,0xfe,0xff,0x00,0xff,0x7f,0xff,0xf0,0x00,0x10,0xff,0xe0,0x20,0x3f,0x01,0x9c,0x3e,0x01,0xe0,0x01,0xa4,0x7e,0x01,0xf0,0x80,0x8b,0x47,0xf1,0x01,0x16,0x8f,0xf0,0x2e,0x23,0x11,0x01,0x88,0x04,0xf0,0x60,0x32,0xe3,0x80,0xcb,0xde,0x37,0xf0,0x1a,0x95,0xcc,0xbe,0x66,0x73,}; const uint8_t* const _I_Down_hvr_25x27[] = {_I_Down_hvr_25x27_0}; -const uint8_t _I_InfraredArrowDown_4x8_0[] = {0x00,0xFF,0x7E,0x3C,0x18,}; +const uint8_t _I_InfraredArrowDown_4x8_0[] = {0x00,0xff,0x7e,0x3c,0x18,}; const uint8_t* const _I_InfraredArrowDown_4x8[] = {_I_InfraredArrowDown_4x8_0}; -const uint8_t _I_InfraredArrowUp_4x8_0[] = {0x00,0x18,0x3C,0x7E,0xFF,}; +const uint8_t _I_InfraredArrowUp_4x8_0[] = {0x00,0x18,0x3c,0x7e,0xff,}; const uint8_t* const _I_InfraredArrowUp_4x8[] = {_I_InfraredArrowUp_4x8_0}; const uint8_t _I_InfraredLearnShort_128x31_0[] = {0x01,0x00,0x10,0x01,0x00,0x47,0xfb,0xfe,0x00,0x38,0x38,0x3e,0x20,0x20,0x54,0x84,0x03,0x9f,0xc0,0x06,0x58,0x80,0x3d,0xf2,0x00,0x65,0x90,0x03,0xde,0x90,0x06,0x5a,0x07,0xc0,0x8a,0x70,0x1a,0x04,0x02,0x51,0x80,0x03,0x94,0x02,0x3f,0x40,0x20,0x24,0x0b,0x01,0x00,0x92,0x70,0x35,0x40,0x01,0xe0,0xdf,0xf0,0x10,0x40,0x71,0x58,0x20,0x90,0x88,0x0c,0x4a,0x81,0x55,0x00,0x0f,0x87,0xf7,0x00,0x82,0x43,0x36,0x16,0xdc,0x9c,0x12,0x21,0x01,0x85,0x70,0x3f,0xc1,0xf1,0xf8,0xfc,0x60,0x20,0xf5,0x90,0x40,0xa1,0x34,0x08,0x18,0x7c,0x7e,0x24,0x91,0x07,0x8c,0xc0,0x5e,0x52,0x28,0x14,0x17,0x81,0x01,0x0f,0x8f,0xe7,0xe3,0x03,0x1f,0x8e,0x02,0xdb,0x03,0x8e,0x49,0x20,0x50,0x2e,0x04,0x72,0xbd,0x55,0xdc,0xeb,0xa0,0x7c,0x4f,0x68,0xbc,0x60,0x72,0x40,0x79,0x50,0x23,0x9a,0x6d,0x56,0x66,0x5c,0x0f,0x21,0x78,0x9b,0x04,0x1e,0x28,0x21,0x8e,0x5c,0x43,0xe6,0x2f,0x10,0xf9,0x0b,0xc7,0x04,0x99,0x18,0x06,0xe0,0x7e,0x56,0x32,0x78,0x8f,0xc4,0x08,0x32,0x20,0x79,0x48,0x2b,0x85,0xf2,0xf8,0x83,0xc4,0x5c,0x3f,0x03,0x78,0xd0,0x81,0xe3,0xc0,0xdf,0x9f,0xcb,0xf3,0x04,0xc6,0x7d,0xfb,0xdf,0x34,0x78,0xd0,0x45,0xe5,0x7e,0x4f,0x97,0xe2,0x09,0x80,0x07,0x88,0xbc,0x61,0x00,0xf3,0xd8,0x2f,0xcb,0xe0,0xcf,0x60,0x68,0xd0,0x30,0x15,0xfa,0xac,0x36,0x3f,0x60,0x77,0xb3,0x80,0x5d,0xe6,0x4b,0x20,0x03,0x03,0xc4,0x01,0xd0,0x10,0x7f,0x40,0x81,0xfc,0xa7,0x10,0x06,0x99,0xd0,0x01,0x51,0x00,0x7f,0x48,0x01,0xfd,0xc0,0x43,0x98,0x00,0x8e,0xfe,0x00,0xf0,}; @@ -286,10 +286,10 @@ const uint8_t* const _I_PassportLeft_6x47[] = {_I_PassportLeft_6x47_0}; const uint8_t _I_WarningDolphin_45x42_0[] = {0x01,0x00,0xc6,0x00,0x00,0x1c,0x22,0x04,0x05,0x7f,0xfc,0x1e,0x20,0x05,0x1e,0x04,0x02,0x30,0x05,0x29,0x84,0x02,0xc1,0x20,0x02,0x8c,0x22,0x01,0x80,0x02,0x94,0x10,0x32,0x30,0x10,0x10,0x87,0xca,0x84,0x03,0x10,0x42,0x81,0x48,0x28,0x38,0x08,0x04,0x3e,0x01,0x84,0x83,0xe0,0x30,0x11,0x08,0x05,0xa2,0x11,0x40,0xa0,0x4b,0xc6,0xc5,0x40,0xd0,0x56,0xe0,0x10,0x60,0x29,0x54,0xf0,0x10,0x18,0xf0,0x14,0x6b,0xf6,0x0c,0x04,0x3e,0x40,0x05,0x12,0x80,0xc1,0xe4,0x01,0xd2,0xf8,0x40,0xe4,0x18,0x09,0xf4,0x03,0xf1,0x01,0x90,0x40,0x28,0x30,0x0f,0xe4,0x00,0x16,0x24,0x11,0xbf,0x01,0x44,0xee,0x53,0xf0,0x29,0xf0,0x3e,0x02,0x91,0x3b,0x8c,0xc3,0x81,0x13,0x90,0x48,0x20,0x3f,0xf9,0xfc,0x42,0x60,0x05,0x10,0x98,0x81,0x56,0x11,0x38,0x02,0x9c,0x1a,0x31,0x1e,0x02,0x8f,0x02,0x03,0x1c,0x90,0xc0,0x7c,0x02,0xf1,0xce,0x02,0x07,0x01,0x1f,0x80,0x63,0xa8,0x08,0x71,0x3c,0x8e,0x39,0x24,0x40,0x51,0xc7,0x81,0x53,0x0f,0x3c,0x02,0x9d,0x1e,0x38,0x29,0x10,0x29,0x17,0xc8,0x0a,0x32,0x3a,0x00,0x14,0x4b,0xa2,0x05,0x58,0x98,0x15,0x22,0x20,0x54,0x84,0x81,0x50,}; const uint8_t* const _I_WarningDolphin_45x42[] = {_I_WarningDolphin_45x42_0}; -const uint8_t _I_KeyBackspaceSelected_16x9_0[] = {0x00,0xFE,0x7F,0xFF,0xFF,0xEF,0xFF,0xE7,0xFF,0x03,0xC0,0xE7,0xFF,0xEF,0xFF,0xFF,0xFF,0xFE,0x7F,}; +const uint8_t _I_KeyBackspaceSelected_16x9_0[] = {0x00,0xfe,0x7f,0xff,0xff,0xef,0xff,0xe7,0xff,0x03,0xc0,0xe7,0xff,0xef,0xff,0xff,0xff,0xfe,0x7f,}; const uint8_t* const _I_KeyBackspaceSelected_16x9[] = {_I_KeyBackspaceSelected_16x9_0}; -const uint8_t _I_KeyBackspace_16x9_0[] = {0x00,0xFE,0x7F,0x01,0x80,0x11,0x80,0x19,0x80,0xFD,0xBF,0x19,0x80,0x11,0x80,0x01,0x80,0xFE,0x7F,}; +const uint8_t _I_KeyBackspace_16x9_0[] = {0x00,0xfe,0x7f,0x01,0x80,0x11,0x80,0x19,0x80,0xfd,0xbf,0x19,0x80,0x11,0x80,0x01,0x80,0xfe,0x7f,}; const uint8_t* const _I_KeyBackspace_16x9[] = {_I_KeyBackspace_16x9_0}; const uint8_t _I_KeySaveSelected_24x11_0[] = {0x01,0x00,0x1a,0x00,0xff,0x7f,0xc0,0x0d,0xcf,0xb4,0x7c,0xee,0xf6,0xbf,0x6d,0xbe,0xd7,0xe1,0xaf,0xda,0xff,0xbe,0x7c,0xc7,0xcc,0x28,0xa1,0xd1,0xbf,0x80,}; @@ -298,23 +298,23 @@ const uint8_t* const _I_KeySaveSelected_24x11[] = {_I_KeySaveSelected_24x11_0}; const uint8_t _I_KeySave_24x11_0[] = {0x01,0x00,0x1e,0x00,0xff,0x7f,0xff,0xf0,0x18,0x06,0x00,0x04,0x53,0x1c,0xbe,0x33,0x13,0x94,0xc9,0x64,0x72,0x99,0xed,0x0e,0x53,0x05,0x19,0xb3,0xe3,0x02,0x8a,0x1d,0x1b,0xf8,}; const uint8_t* const _I_KeySave_24x11[] = {_I_KeySave_24x11_0}; -const uint8_t _A_125khz_14_0[] = {0x00,0x80,0x07,0x00,0x08,0x00,0x13,0x00,0x24,0x0E,0x28,0x71,0x28,0x85,0x21,0x01,0x02,0x62,0x02,0x92,0x02,0x92,0x02,0x64,0x02,0x04,0x01,0xF8,0x00,}; -const uint8_t _A_125khz_14_1[] = {0x00,0x80,0x07,0x00,0x08,0x00,0x10,0x00,0x20,0x0E,0x20,0x71,0x20,0x85,0x21,0x01,0x02,0x62,0x02,0x92,0x02,0x92,0x02,0x64,0x02,0x04,0x01,0xF8,0x00,}; +const uint8_t _A_125khz_14_0[] = {0x00,0x80,0x07,0x00,0x08,0x00,0x13,0x00,0x24,0x0e,0x28,0x71,0x28,0x85,0x21,0x01,0x02,0x62,0x02,0x92,0x02,0x92,0x02,0x64,0x02,0x04,0x01,0xf8,0x00,}; +const uint8_t _A_125khz_14_1[] = {0x00,0x80,0x07,0x00,0x08,0x00,0x10,0x00,0x20,0x0e,0x20,0x71,0x20,0x85,0x21,0x01,0x02,0x62,0x02,0x92,0x02,0x92,0x02,0x64,0x02,0x04,0x01,0xf8,0x00,}; const uint8_t _A_125khz_14_2[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3a,0x01,0x71,0x80,0x61,0x60,0x30,0x18,0x15,0x8a,0x05,0x92,0x00,0x95,0x92,0x05,0x04,0x80,0xfe,0x20,0x00,}; const uint8_t _A_125khz_14_3[] = {0x01,0x00,0x1a,0x00,0x00,0x24,0x0e,0x01,0x04,0x87,0x42,0x2e,0x30,0x8c,0x2c,0x06,0x03,0x02,0xb1,0x40,0xb2,0x40,0x12,0xb2,0x40,0xa0,0x90,0x1f,0xc4,0x00,}; const uint8_t* const _A_125khz_14[] = {_A_125khz_14_0,_A_125khz_14_1,_A_125khz_14_2,_A_125khz_14_3}; -const uint8_t _A_BadUsb_14_0[] = {0x00,0xFF,0x1F,0x01,0x10,0x01,0x10,0xF1,0x11,0xF9,0x13,0xE9,0x12,0x49,0x12,0xF9,0x13,0xF1,0x11,0x51,0x11,0x01,0x10,0xFF,0x1F,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_1[] = {0x00,0x01,0x10,0x01,0x10,0xE1,0x13,0xFD,0x10,0xF9,0x13,0x01,0x17,0xF9,0x13,0x3D,0x10,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x06,0x0C,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_2[] = {0x00,0x01,0x10,0xF1,0x11,0xF9,0x13,0x59,0x13,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB6,0x0D,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_3[] = {0x00,0xF1,0x11,0xF9,0x13,0x59,0x13,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x06,0x0C,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_4[] = {0x00,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x04,0x04,0xFC,0x07,0xFC,0x07,0xFE,0x0F,0xFE,0x0F,0x02,0x08,}; -const uint8_t _A_BadUsb_14_5[] = {0x00,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x04,0x04,0xFC,0x07,0xFC,0x07,0x04,0x04,0xFC,0x07,0x00,0x00,0xFE,0x0F,0xFE,0x0F,0x02,0x08,}; -const uint8_t _A_BadUsb_14_6[] = {0x00,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x04,0x04,0xFC,0x07,0xFC,0x07,0xFE,0x0F,0xFE,0x0F,0x02,0x08,}; -const uint8_t _A_BadUsb_14_7[] = {0x00,0xF1,0x11,0xF9,0x13,0x59,0x13,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB4,0x05,0x06,0x0C,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_8[] = {0x00,0x01,0x10,0xF1,0x11,0xF9,0x13,0x59,0x13,0xF9,0x13,0xE9,0x12,0x19,0x13,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x04,0x04,0xB6,0x0D,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_9[] = {0x00,0x01,0x10,0x01,0x10,0xE1,0x13,0xFD,0x10,0xF9,0x13,0x01,0x17,0xF9,0x13,0x3D,0x10,0xF1,0x11,0x01,0x10,0xFF,0x1F,0x06,0x0C,0xFE,0x0F,0xFE,0x0F,}; -const uint8_t _A_BadUsb_14_10[] = {0x00,0xFF,0x1F,0x01,0x10,0x01,0x10,0xF1,0x11,0xF9,0x13,0xE9,0x12,0x49,0x12,0xF9,0x13,0xF1,0x11,0x51,0x11,0x01,0x10,0xFF,0x1F,0xFE,0x0F,0xFE,0x0F,}; +const uint8_t _A_BadUsb_14_0[] = {0x00,0xff,0x1f,0x01,0x10,0x01,0x10,0xf1,0x11,0xf9,0x13,0xe9,0x12,0x49,0x12,0xf9,0x13,0xf1,0x11,0x51,0x11,0x01,0x10,0xff,0x1f,0xfe,0x0f,0xfe,0x0f,}; +const uint8_t _A_BadUsb_14_1[] = {0x00,0x01,0x10,0x01,0x10,0xe1,0x13,0xfd,0x10,0xf9,0x13,0x01,0x17,0xf9,0x13,0x3d,0x10,0xf1,0x11,0x01,0x10,0xff,0x1f,0x06,0x0c,0xfe,0x0f,0xfe,0x0f,}; +const uint8_t _A_BadUsb_14_2[] = {0x00,0x01,0x10,0xf1,0x11,0xf9,0x13,0x59,0x13,0xf9,0x13,0xe9,0x12,0x19,0x13,0xf1,0x11,0x01,0x10,0xff,0x1f,0x04,0x04,0xb6,0x0d,0xfe,0x0f,0xfe,0x0f,}; +const uint8_t _A_BadUsb_14_3[] = {0x00,0xf1,0x11,0xf9,0x13,0x59,0x13,0xf9,0x13,0xe9,0x12,0x19,0x13,0xf1,0x11,0x01,0x10,0xff,0x1f,0x04,0x04,0xb4,0x05,0x06,0x0c,0xfe,0x0f,0xfe,0x0f,}; +const uint8_t _A_BadUsb_14_4[] = {0x00,0xf9,0x13,0xe9,0x12,0x19,0x13,0xf1,0x11,0x01,0x10,0xff,0x1f,0x04,0x04,0xb4,0x05,0x04,0x04,0xfc,0x07,0xfc,0x07,0xfe,0x0f,0xfe,0x0f,0x02,0x08,}; +const uint8_t _A_BadUsb_14_5[] = {0x00,0xf1,0x11,0x01,0x10,0xff,0x1f,0x04,0x04,0xb4,0x05,0x04,0x04,0xfc,0x07,0xfc,0x07,0x04,0x04,0xfc,0x07,0x00,0x00,0xfe,0x0f,0xfe,0x0f,0x02,0x08,}; +const uint8_t _A_BadUsb_14_6[] = {0x00,0xf9,0x13,0xe9,0x12,0x19,0x13,0xf1,0x11,0x01,0x10,0xff,0x1f,0x04,0x04,0xb4,0x05,0x04,0x04,0xfc,0x07,0xfc,0x07,0xfe,0x0f,0xfe,0x0f,0x02,0x08,}; +const uint8_t _A_BadUsb_14_7[] = {0x00,0xf1,0x11,0xf9,0x13,0x59,0x13,0xf9,0x13,0xe9,0x12,0x19,0x13,0xf1,0x11,0x01,0x10,0xff,0x1f,0x04,0x04,0xb4,0x05,0x06,0x0c,0xfe,0x0f,0xfe,0x0f,}; +const uint8_t _A_BadUsb_14_8[] = {0x00,0x01,0x10,0xf1,0x11,0xf9,0x13,0x59,0x13,0xf9,0x13,0xe9,0x12,0x19,0x13,0xf1,0x11,0x01,0x10,0xff,0x1f,0x04,0x04,0xb6,0x0d,0xfe,0x0f,0xfe,0x0f,}; +const uint8_t _A_BadUsb_14_9[] = {0x00,0x01,0x10,0x01,0x10,0xe1,0x13,0xfd,0x10,0xf9,0x13,0x01,0x17,0xf9,0x13,0x3d,0x10,0xf1,0x11,0x01,0x10,0xff,0x1f,0x06,0x0c,0xfe,0x0f,0xfe,0x0f,}; +const uint8_t _A_BadUsb_14_10[] = {0x00,0xff,0x1f,0x01,0x10,0x01,0x10,0xf1,0x11,0xf9,0x13,0xe9,0x12,0x49,0x12,0xf9,0x13,0xf1,0x11,0x51,0x11,0x01,0x10,0xff,0x1f,0xfe,0x0f,0xfe,0x0f,}; const uint8_t* const _A_BadUsb_14[] = {_A_BadUsb_14_0,_A_BadUsb_14_1,_A_BadUsb_14_2,_A_BadUsb_14_3,_A_BadUsb_14_4,_A_BadUsb_14_5,_A_BadUsb_14_6,_A_BadUsb_14_7,_A_BadUsb_14_8,_A_BadUsb_14_9,_A_BadUsb_14_10}; const uint8_t _A_Bluetooth_14_0[] = {0x00,0x10,0x00,0x30,0x00,0x51,0x08,0x92,0x10,0x94,0x24,0x58,0x28,0x30,0x29,0x30,0x29,0x58,0x28,0x94,0x24,0x92,0x10,0x51,0x08,0x30,0x00,0x10,0x00,}; @@ -325,14 +325,14 @@ const uint8_t _A_Bluetooth_14_4[] = {0x00,0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x0 const uint8_t _A_Bluetooth_14_5[] = {0x00,0x10,0x00,0x30,0x00,0x51,0x00,0x92,0x00,0x94,0x04,0x58,0x08,0x30,0x09,0x30,0x09,0x58,0x08,0x94,0x04,0x92,0x00,0x51,0x00,0x30,0x00,0x10,0x00,}; const uint8_t* const _A_Bluetooth_14[] = {_A_Bluetooth_14_0,_A_Bluetooth_14_1,_A_Bluetooth_14_2,_A_Bluetooth_14_3,_A_Bluetooth_14_4,_A_Bluetooth_14_5}; -const uint8_t _A_Debug_14_0[] = {0x00,0x20,0x01,0xC1,0x20,0x22,0x11,0x24,0x09,0xD9,0x26,0x16,0x1A,0xD8,0x06,0xD8,0x06,0xD6,0x1A,0x19,0x26,0xE4,0x09,0xC2,0x10,0x01,0x20,0x00,0x00,}; -const uint8_t _A_Debug_14_1[] = {0x00,0x20,0x01,0xC0,0x00,0x22,0x11,0x25,0x29,0xD8,0x06,0x16,0x1A,0xD9,0x26,0xD8,0x06,0xD4,0x0A,0x12,0x12,0xEA,0x15,0xC5,0x28,0x02,0x10,0x02,0x10,}; -const uint8_t _A_Debug_14_2[] = {0x00,0x20,0x01,0xC0,0x00,0x20,0x01,0x24,0x09,0xDA,0x16,0x11,0x22,0xDC,0x0E,0xDA,0x16,0xD9,0x26,0x14,0x0A,0xF2,0x13,0xD1,0x22,0x08,0x04,0x06,0x18,}; -const uint8_t _A_Debug_14_3[] = {0x00,0x22,0x11,0xC4,0x08,0x24,0x09,0x25,0x29,0xD9,0x26,0x12,0x12,0xDC,0x0E,0xD8,0x06,0xD8,0x06,0x14,0x0A,0xF4,0x0B,0xD2,0x12,0x19,0x26,0x06,0x18,}; +const uint8_t _A_Debug_14_0[] = {0x00,0x20,0x01,0xc1,0x20,0x22,0x11,0x24,0x09,0xd9,0x26,0x16,0x1a,0xd8,0x06,0xd8,0x06,0xd6,0x1a,0x19,0x26,0xe4,0x09,0xc2,0x10,0x01,0x20,0x00,0x00,}; +const uint8_t _A_Debug_14_1[] = {0x00,0x20,0x01,0xc0,0x00,0x22,0x11,0x25,0x29,0xd8,0x06,0x16,0x1a,0xd9,0x26,0xd8,0x06,0xd4,0x0a,0x12,0x12,0xea,0x15,0xc5,0x28,0x02,0x10,0x02,0x10,}; +const uint8_t _A_Debug_14_2[] = {0x00,0x20,0x01,0xc0,0x00,0x20,0x01,0x24,0x09,0xda,0x16,0x11,0x22,0xdc,0x0e,0xda,0x16,0xd9,0x26,0x14,0x0a,0xf2,0x13,0xd1,0x22,0x08,0x04,0x06,0x18,}; +const uint8_t _A_Debug_14_3[] = {0x00,0x22,0x11,0xc4,0x08,0x24,0x09,0x25,0x29,0xd9,0x26,0x12,0x12,0xdc,0x0e,0xd8,0x06,0xd8,0x06,0x14,0x0a,0xf4,0x0b,0xd2,0x12,0x19,0x26,0x06,0x18,}; const uint8_t* const _A_Debug_14[] = {_A_Debug_14_0,_A_Debug_14_1,_A_Debug_14_2,_A_Debug_14_3}; -const uint8_t _A_FileManager_14_0[] = {0x00,0xFC,0x07,0x04,0x04,0xF4,0x05,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,}; -const uint8_t _A_FileManager_14_1[] = {0x00,0x00,0x00,0x00,0x00,0xFC,0x07,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,}; +const uint8_t _A_FileManager_14_0[] = {0x00,0xfc,0x07,0x04,0x04,0xf4,0x05,0x04,0x04,0xf7,0x05,0x05,0x04,0xf5,0x3f,0x15,0x20,0x0d,0x20,0x0d,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xfe,0x07,}; +const uint8_t _A_FileManager_14_1[] = {0x00,0x00,0x00,0x00,0x00,0xfc,0x07,0x04,0x04,0xf7,0x05,0x05,0x04,0xf5,0x3f,0x15,0x20,0x0d,0x20,0x0d,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xfe,0x07,}; const uint8_t _A_FileManager_14_2[] = {0x01,0x00,0x17,0x00,0x00,0x3f,0xfe,0x0f,0x05,0x82,0x7d,0x67,0xf1,0x59,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; const uint8_t _A_FileManager_14_3[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3e,0x01,0x11,0x80,0x7f,0x67,0xf1,0x59,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; const uint8_t _A_FileManager_14_4[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3e,0x01,0x11,0x80,0x7c,0x67,0xf1,0x19,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; @@ -340,7 +340,7 @@ const uint8_t _A_FileManager_14_5[] = {0x01,0x00,0x0f,0x00,0x00,0x3c,0x3e,0x01,0 const uint8_t _A_FileManager_14_6[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3e,0x01,0x11,0x80,0x7c,0x67,0xf1,0x19,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; const uint8_t _A_FileManager_14_7[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x3e,0x01,0x11,0x80,0x7f,0x67,0xf1,0x59,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; const uint8_t _A_FileManager_14_8[] = {0x01,0x00,0x17,0x00,0x00,0x3f,0xfe,0x0f,0x05,0x82,0x7d,0x67,0xf1,0x59,0x04,0x34,0x02,0x31,0x08,0x28,0x04,0x61,0x10,0x38,0x47,0xfa,0x0e,}; -const uint8_t _A_FileManager_14_9[] = {0x00,0x00,0x00,0x00,0x00,0xFC,0x07,0x04,0x04,0xF7,0x05,0x05,0x04,0xF5,0x3F,0x15,0x20,0x0D,0x20,0x0D,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xFE,0x07,}; +const uint8_t _A_FileManager_14_9[] = {0x00,0x00,0x00,0x00,0x00,0xfc,0x07,0x04,0x04,0xf7,0x05,0x05,0x04,0xf5,0x3f,0x15,0x20,0x0d,0x20,0x0d,0x10,0x05,0x10,0x05,0x08,0x03,0x08,0xfe,0x07,}; const uint8_t* const _A_FileManager_14[] = {_A_FileManager_14_0,_A_FileManager_14_1,_A_FileManager_14_2,_A_FileManager_14_3,_A_FileManager_14_4,_A_FileManager_14_5,_A_FileManager_14_6,_A_FileManager_14_7,_A_FileManager_14_8,_A_FileManager_14_9}; const uint8_t _A_GPIO_14_0[] = {0x01,0x00,0x15,0x00,0xa2,0x41,0x00,0x23,0xee,0x87,0x00,0x54,0x16,0x60,0x11,0x09,0x8f,0xfe,0x3f,0x11,0x88,0xd5,0x62,0xa0,0x31,}; @@ -355,13 +355,13 @@ const uint8_t* const _A_GPIO_14[] = {_A_GPIO_14_0,_A_GPIO_14_1,_A_GPIO_14_2,_A_G const uint8_t _A_Games_14_0[] = {0x01,0x00,0x17,0x00,0x00,0x3c,0x62,0x0d,0xfc,0x87,0xc0,0xa2,0x10,0x99,0x24,0x76,0x54,0x03,0x1f,0x0c,0x86,0x23,0x22,0x02,0x8c,0x1a,0x30,}; const uint8_t _A_Games_14_1[] = {0x01,0x00,0x1a,0x00,0x00,0x2c,0x62,0x0d,0xfc,0x87,0xc0,0xa2,0x10,0x99,0x24,0x76,0x54,0x03,0x1f,0x0c,0x87,0x23,0x22,0x02,0x8c,0x5a,0x35,0x01,0x90,0x00,}; -const uint8_t _A_Games_14_2[] = {0x00,0x00,0x00,0x00,0x00,0x18,0x06,0xFC,0x0F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x91,0x22,0x89,0x24,0x16,0x1A,0x11,0x22,0x01,0x20,}; -const uint8_t _A_Games_14_3[] = {0x00,0x00,0x00,0x18,0x06,0xFC,0x0F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x91,0x22,0x89,0x24,0x96,0x1A,0x11,0x22,0x11,0x22,0x01,0x20,}; -const uint8_t _A_Games_14_4[] = {0x00,0x18,0x06,0xFC,0x0F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x91,0x22,0x89,0x24,0x16,0x1A,0x11,0x22,0x01,0x20,0x00,0x00,0x00,0x00,}; -const uint8_t _A_Games_14_5[] = {0x00,0x84,0x08,0x18,0x06,0xFD,0x2F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x91,0x22,0x09,0x24,0x16,0x1A,0x01,0x20,0x00,0x00,0x00,0x00,}; -const uint8_t _A_Games_14_6[] = {0x00,0x84,0x08,0x84,0x08,0x19,0x26,0xFD,0x2F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x11,0x22,0x09,0x24,0x06,0x18,0x00,0x00,0x00,0x00,}; -const uint8_t _A_Games_14_7[] = {0x00,0x84,0x08,0x84,0x08,0x85,0x28,0x19,0x26,0xFD,0x2F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x11,0x22,0x09,0x24,0x06,0x18,0x00,0x00,}; -const uint8_t _A_Games_14_8[] = {0x00,0x00,0x00,0x00,0x00,0x84,0x08,0x84,0x08,0x19,0x26,0xFD,0x2F,0x02,0x10,0x09,0x24,0x1D,0x2A,0x09,0x24,0xE1,0x21,0x11,0x22,0x09,0x24,0x06,0x18,}; +const uint8_t _A_Games_14_2[] = {0x00,0x00,0x00,0x00,0x00,0x18,0x06,0xfc,0x0f,0x02,0x10,0x09,0x24,0x1d,0x2a,0x09,0x24,0xe1,0x21,0x91,0x22,0x89,0x24,0x16,0x1a,0x11,0x22,0x01,0x20,}; +const uint8_t _A_Games_14_3[] = {0x00,0x00,0x00,0x18,0x06,0xfc,0x0f,0x02,0x10,0x09,0x24,0x1d,0x2a,0x09,0x24,0xe1,0x21,0x91,0x22,0x89,0x24,0x96,0x1a,0x11,0x22,0x11,0x22,0x01,0x20,}; +const uint8_t _A_Games_14_4[] = {0x00,0x18,0x06,0xfc,0x0f,0x02,0x10,0x09,0x24,0x1d,0x2a,0x09,0x24,0xe1,0x21,0x91,0x22,0x89,0x24,0x16,0x1a,0x11,0x22,0x01,0x20,0x00,0x00,0x00,0x00,}; +const uint8_t _A_Games_14_5[] = {0x00,0x84,0x08,0x18,0x06,0xfd,0x2f,0x02,0x10,0x09,0x24,0x1d,0x2a,0x09,0x24,0xe1,0x21,0x91,0x22,0x09,0x24,0x16,0x1a,0x01,0x20,0x00,0x00,0x00,0x00,}; +const uint8_t _A_Games_14_6[] = {0x00,0x84,0x08,0x84,0x08,0x19,0x26,0xfd,0x2f,0x02,0x10,0x09,0x24,0x1d,0x2a,0x09,0x24,0xe1,0x21,0x11,0x22,0x09,0x24,0x06,0x18,0x00,0x00,0x00,0x00,}; +const uint8_t _A_Games_14_7[] = {0x00,0x84,0x08,0x84,0x08,0x85,0x28,0x19,0x26,0xfd,0x2f,0x02,0x10,0x09,0x24,0x1d,0x2a,0x09,0x24,0xe1,0x21,0x11,0x22,0x09,0x24,0x06,0x18,0x00,0x00,}; +const uint8_t _A_Games_14_8[] = {0x00,0x00,0x00,0x00,0x00,0x84,0x08,0x84,0x08,0x19,0x26,0xfd,0x2f,0x02,0x10,0x09,0x24,0x1d,0x2a,0x09,0x24,0xe1,0x21,0x11,0x22,0x09,0x24,0x06,0x18,}; const uint8_t* const _A_Games_14[] = {_A_Games_14_0,_A_Games_14_1,_A_Games_14_2,_A_Games_14_3,_A_Games_14_4,_A_Games_14_5,_A_Games_14_6,_A_Games_14_7,_A_Games_14_8}; const uint8_t _A_Infrared_14_0[] = {0x01,0x00,0x1a,0x00,0xfc,0x41,0xe0,0xd1,0x88,0x0c,0x83,0xe1,0x03,0x84,0x41,0x01,0x63,0xe0,0x80,0x84,0x4c,0x0a,0x20,0xd1,0x0a,0x88,0x04,0x7f,0xf3,0xf0,}; @@ -372,13 +372,13 @@ const uint8_t _A_Infrared_14_4[] = {0x01,0x00,0x0e,0x00,0x00,0x5f,0x82,0x02,0x05 const uint8_t _A_Infrared_14_5[] = {0x01,0x00,0x15,0x00,0x00,0x2f,0xc2,0x07,0x08,0x82,0x01,0x47,0xc1,0x01,0x05,0x98,0x14,0x41,0xa3,0xf8,0x83,0x80,0x47,0xff,0x3f,}; const uint8_t* const _A_Infrared_14[] = {_A_Infrared_14_0,_A_Infrared_14_1,_A_Infrared_14_2,_A_Infrared_14_3,_A_Infrared_14_4,_A_Infrared_14_5}; -const uint8_t _A_NFC_14_0[] = {0x00,0x00,0x08,0x00,0x10,0x00,0x12,0x00,0x22,0x42,0x24,0x87,0x24,0x8D,0x24,0x99,0x24,0xF1,0x24,0x62,0x24,0x00,0x22,0x00,0x12,0x00,0x10,0x00,0x08,}; +const uint8_t _A_NFC_14_0[] = {0x00,0x00,0x08,0x00,0x10,0x00,0x12,0x00,0x22,0x42,0x24,0x87,0x24,0x8d,0x24,0x99,0x24,0xf1,0x24,0x62,0x24,0x00,0x22,0x00,0x12,0x00,0x10,0x00,0x08,}; const uint8_t _A_NFC_14_1[] = {0x01,0x00,0x1a,0x00,0x80,0x42,0x20,0x11,0x00,0x09,0x48,0x28,0x52,0x0c,0x3c,0x83,0x1b,0x20,0xcc,0xc8,0x3e,0x32,0x0b,0x14,0x80,0x1a,0x21,0x34,0x84,0x00,}; const uint8_t _A_NFC_14_2[] = {0x01,0x00,0x10,0x00,0x00,0x3d,0x0a,0x01,0x87,0x80,0x63,0x60,0x19,0x98,0x07,0xc6,0x01,0x62,0x09,0xc0,}; const uint8_t _A_NFC_14_3[] = {0x01,0x00,0x16,0x00,0x00,0x24,0x08,0x02,0x34,0x28,0x26,0x1e,0x09,0x8d,0x82,0x66,0x60,0x9f,0x18,0x25,0x8a,0x08,0x0f,0x30,0xb1,0x80,}; const uint8_t* const _A_NFC_14[] = {_A_NFC_14_0,_A_NFC_14_1,_A_NFC_14_2,_A_NFC_14_3}; -const uint8_t _A_Passport_14_0[] = {0x00,0xC0,0x00,0x20,0x01,0x20,0x01,0xFE,0x1F,0x01,0x20,0x39,0x2F,0x39,0x20,0x39,0x2F,0x11,0x20,0x39,0x2B,0x45,0x20,0x7D,0x25,0x01,0x20,0xFE,0x1F,}; +const uint8_t _A_Passport_14_0[] = {0x00,0xc0,0x00,0x20,0x01,0x20,0x01,0xfe,0x1f,0x01,0x20,0x39,0x2f,0x39,0x20,0x39,0x2f,0x11,0x20,0x39,0x2b,0x45,0x20,0x7d,0x25,0x01,0x20,0xfe,0x1f,}; const uint8_t _A_Passport_14_1[] = {0x01,0x00,0x0e,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x42,0x00,0xf0,0x4c,0x40,}; const uint8_t _A_Passport_14_2[] = {0x01,0x00,0x13,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x42,0x90,0x42,0x40,0x24,0x07,0x30,0x0a,0x84,0xc4,}; const uint8_t _A_Passport_14_3[] = {0x01,0x00,0x14,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0xc8,0x21,0x20,0x12,0x06,0x10,0x05,0x82,0x62,}; @@ -386,34 +386,34 @@ const uint8_t _A_Passport_14_4[] = {0x01,0x00,0x13,0x00,0xe0,0x40,0x24,0x10,0x10 const uint8_t _A_Passport_14_5[] = {0x01,0x00,0x18,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0x80,0x52,0x23,0x20,0x84,0xc8,0x20,0xa0,0x12,0x07,0x88,0x4c,0x40,}; const uint8_t _A_Passport_14_6[] = {0x01,0x00,0x18,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0x80,0x52,0x23,0x20,0x84,0xc8,0x20,0xb2,0x0b,0xe8,0x50,0x82,0x62,}; const uint8_t _A_Passport_14_7[] = {0x01,0x00,0x1a,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0xc8,0xe7,0x20,0x31,0x90,0x44,0x40,0x65,0x45,0x90,0x5f,0x42,0x84,0x13,0x10,}; -const uint8_t _A_Passport_14_8[] = {0x00,0xC0,0x00,0x20,0x01,0x20,0x01,0xFE,0x1F,0x01,0x20,0x39,0x2F,0x39,0x20,0x39,0x23,0x11,0x20,0x39,0x20,0x45,0x20,0x7D,0x20,0x01,0x20,0xFE,0x1F,}; +const uint8_t _A_Passport_14_8[] = {0x00,0xc0,0x00,0x20,0x01,0x20,0x01,0xfe,0x1f,0x01,0x20,0x39,0x2f,0x39,0x20,0x39,0x23,0x11,0x20,0x39,0x20,0x45,0x20,0x7d,0x20,0x01,0x20,0xfe,0x1f,}; const uint8_t _A_Passport_14_9[] = {0x01,0x00,0x1a,0x00,0xe0,0x40,0x24,0x10,0x10,0x08,0xff,0xa3,0xe0,0x41,0x9c,0xcb,0xe7,0x20,0x32,0x88,0x80,0xc6,0x47,0x45,0x90,0x5f,0x42,0x84,0x13,0x10,}; const uint8_t* const _A_Passport_14[] = {_A_Passport_14_0,_A_Passport_14_1,_A_Passport_14_2,_A_Passport_14_3,_A_Passport_14_4,_A_Passport_14_5,_A_Passport_14_6,_A_Passport_14_7,_A_Passport_14_8,_A_Passport_14_9}; -const uint8_t _A_Plugins_14_0[] = {0x00,0xE7,0x00,0xA5,0x00,0x99,0x01,0x01,0x02,0x01,0x02,0x81,0x01,0x81,0x0E,0xE7,0x08,0x24,0x18,0x58,0x20,0x40,0x20,0x30,0x18,0x10,0x08,0xF0,0x0F,}; -const uint8_t _A_Plugins_14_1[] = {0x00,0x70,0x0E,0x50,0x0A,0x90,0x19,0x10,0x20,0x10,0x20,0x18,0x18,0x1E,0x08,0x72,0x0E,0x46,0x02,0x88,0x05,0x08,0x04,0x06,0x03,0x02,0x01,0xFE,0x01,}; -const uint8_t _A_Plugins_14_2[] = {0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xE4,0x1C,0xA7,0x14,0x21,0x33,0x23,0x00,0x24,0x00,0x24,0x30,0x23,0x10,0xE1,0x1C,0xFF,0x04,0x00,0x03,0x00,0x00,}; -const uint8_t _A_Plugins_14_3[] = {0x00,0x30,0x00,0x48,0x00,0xCE,0x01,0x02,0x01,0x3E,0x07,0x28,0x05,0xC8,0x0C,0x0E,0x10,0x0A,0x10,0x0E,0x0C,0x08,0x04,0x38,0x07,0x20,0x01,0xC0,0x00,}; -const uint8_t _A_Plugins_14_4[] = {0x00,0x40,0x02,0x70,0x0E,0x10,0x08,0x30,0x18,0xCE,0x21,0x4A,0x21,0x32,0x1B,0x02,0x0C,0x02,0x0C,0x02,0x03,0x02,0x01,0xCE,0x01,0x48,0x00,0x30,0x00,}; -const uint8_t _A_Plugins_14_5[] = {0x00,0x00,0x0C,0x00,0x12,0x80,0x33,0x80,0x00,0xB9,0x01,0x29,0x02,0x66,0x02,0x80,0x01,0x80,0x00,0x60,0x3F,0x20,0x00,0x39,0x00,0x09,0x00,0x06,0x00,}; -const uint8_t _A_Plugins_14_6[] = {0x00,0x00,0x00,0x00,0x06,0x00,0x09,0xF3,0x39,0x52,0x20,0xCC,0x20,0x00,0x01,0x00,0x01,0xC0,0x20,0x40,0x20,0xF3,0x3F,0x12,0x00,0x0C,0x00,0x00,0x00,}; -const uint8_t _A_Plugins_14_7[] = {0x00,0x00,0x00,0x00,0x0C,0x00,0x12,0xB9,0x33,0xA9,0x00,0x66,0x01,0x80,0x02,0x80,0x02,0x60,0x01,0xA0,0x00,0xB9,0x3F,0x09,0x00,0x06,0x00,0x00,0x00,}; -const uint8_t _A_Plugins_14_8[] = {0x00,0x00,0x00,0x39,0x00,0x29,0x00,0x66,0x06,0x80,0x09,0x80,0x39,0x60,0x20,0xE0,0x20,0x39,0x01,0x09,0x01,0xC6,0x20,0x40,0x20,0xC0,0x3F,0x00,0x00,}; +const uint8_t _A_Plugins_14_0[] = {0x00,0xe7,0x00,0xa5,0x00,0x99,0x01,0x01,0x02,0x01,0x02,0x81,0x01,0x81,0x0e,0xe7,0x08,0x24,0x18,0x58,0x20,0x40,0x20,0x30,0x18,0x10,0x08,0xf0,0x0f,}; +const uint8_t _A_Plugins_14_1[] = {0x00,0x70,0x0e,0x50,0x0a,0x90,0x19,0x10,0x20,0x10,0x20,0x18,0x18,0x1e,0x08,0x72,0x0e,0x46,0x02,0x88,0x05,0x08,0x04,0x06,0x03,0x02,0x01,0xfe,0x01,}; +const uint8_t _A_Plugins_14_2[] = {0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xe4,0x1c,0xa7,0x14,0x21,0x33,0x23,0x00,0x24,0x00,0x24,0x30,0x23,0x10,0xe1,0x1c,0xff,0x04,0x00,0x03,0x00,0x00,}; +const uint8_t _A_Plugins_14_3[] = {0x00,0x30,0x00,0x48,0x00,0xce,0x01,0x02,0x01,0x3e,0x07,0x28,0x05,0xc8,0x0c,0x0e,0x10,0x0a,0x10,0x0e,0x0c,0x08,0x04,0x38,0x07,0x20,0x01,0xc0,0x00,}; +const uint8_t _A_Plugins_14_4[] = {0x00,0x40,0x02,0x70,0x0e,0x10,0x08,0x30,0x18,0xce,0x21,0x4a,0x21,0x32,0x1b,0x02,0x0c,0x02,0x0c,0x02,0x03,0x02,0x01,0xce,0x01,0x48,0x00,0x30,0x00,}; +const uint8_t _A_Plugins_14_5[] = {0x00,0x00,0x0c,0x00,0x12,0x80,0x33,0x80,0x00,0xb9,0x01,0x29,0x02,0x66,0x02,0x80,0x01,0x80,0x00,0x60,0x3f,0x20,0x00,0x39,0x00,0x09,0x00,0x06,0x00,}; +const uint8_t _A_Plugins_14_6[] = {0x00,0x00,0x00,0x00,0x06,0x00,0x09,0xf3,0x39,0x52,0x20,0xcc,0x20,0x00,0x01,0x00,0x01,0xc0,0x20,0x40,0x20,0xf3,0x3f,0x12,0x00,0x0c,0x00,0x00,0x00,}; +const uint8_t _A_Plugins_14_7[] = {0x00,0x00,0x00,0x00,0x0c,0x00,0x12,0xb9,0x33,0xa9,0x00,0x66,0x01,0x80,0x02,0x80,0x02,0x60,0x01,0xa0,0x00,0xb9,0x3f,0x09,0x00,0x06,0x00,0x00,0x00,}; +const uint8_t _A_Plugins_14_8[] = {0x00,0x00,0x00,0x39,0x00,0x29,0x00,0x66,0x06,0x80,0x09,0x80,0x39,0x60,0x20,0xe0,0x20,0x39,0x01,0x09,0x01,0xc6,0x20,0x40,0x20,0xc0,0x3f,0x00,0x00,}; const uint8_t* const _A_Plugins_14[] = {_A_Plugins_14_0,_A_Plugins_14_1,_A_Plugins_14_2,_A_Plugins_14_3,_A_Plugins_14_4,_A_Plugins_14_5,_A_Plugins_14_6,_A_Plugins_14_7,_A_Plugins_14_8}; const uint8_t _A_Power_14_0[] = {0x01,0x00,0x17,0x00,0xa0,0x00,0x4a,0x99,0x06,0xa1,0x42,0x00,0x23,0x41,0x88,0x00,0x56,0x05,0x08,0x00,0x8c,0x32,0x0d,0xf0,0x80,0x86,0xc4,}; const uint8_t* const _A_Power_14[] = {_A_Power_14_0}; -const uint8_t _A_Settings_14_0[] = {0x00,0x03,0x07,0x87,0x04,0x8E,0x02,0x9C,0x32,0xF8,0x2C,0x50,0x20,0x30,0x1E,0x1E,0x03,0x81,0x04,0xCD,0x09,0x53,0x13,0x50,0x26,0x48,0x2C,0x38,0x18,}; -const uint8_t _A_Settings_14_1[] = {0x00,0x03,0x00,0x87,0x03,0x4E,0x02,0x7C,0x01,0x48,0x19,0x58,0x16,0x30,0x10,0x10,0x0F,0x8F,0x04,0xC0,0x09,0x26,0x13,0x29,0x16,0x28,0x0C,0x24,0x00,}; -const uint8_t _A_Settings_14_2[] = {0x00,0x03,0x00,0x07,0x00,0xDE,0x01,0x24,0x01,0xAC,0x00,0xB8,0x0C,0x30,0x0B,0x10,0x08,0x88,0x07,0xC7,0x09,0x20,0x0B,0x13,0x06,0x14,0x00,0x14,0x00,}; -const uint8_t _A_Settings_14_3[] = {0x00,0x04,0x0C,0x09,0x00,0x13,0x20,0x26,0x20,0x4C,0x00,0xB8,0x00,0xA4,0x00,0x74,0x00,0x94,0x01,0x64,0x01,0x02,0x01,0xF1,0x18,0x08,0x38,0x04,0x30,}; -const uint8_t _A_Settings_14_4[] = {0x00,0x04,0x0F,0x89,0x00,0x93,0x26,0xA6,0x29,0x2C,0x28,0x18,0x24,0x00,0x1C,0x0E,0x00,0x09,0x00,0x05,0x06,0x65,0x0E,0x59,0x1C,0x40,0x38,0x3C,0x30,}; -const uint8_t _A_Settings_14_5[] = {0x00,0x04,0x08,0x05,0x04,0xC3,0x23,0x20,0x10,0xA0,0x09,0x60,0x0A,0x00,0x0A,0x80,0x09,0x80,0x07,0x03,0x07,0x02,0x0E,0x01,0x3C,0x19,0x08,0x16,0x18,}; -const uint8_t _A_Settings_14_6[] = {0x00,0x00,0x14,0x00,0x24,0x00,0x02,0x18,0x31,0xF8,0x08,0x08,0x04,0x68,0x02,0xD8,0x02,0x80,0x06,0xC0,0x0A,0xC0,0x13,0x00,0x26,0x00,0x0C,0x00,0x18,}; -const uint8_t _A_Settings_14_7[] = {0x00,0x00,0x0A,0x00,0x0A,0x0C,0x32,0x1C,0x01,0xB8,0x38,0x78,0x04,0x04,0x02,0x34,0x03,0x4C,0x05,0x40,0x09,0x20,0x13,0xE0,0x26,0x00,0x0C,0x00,0x18,}; -const uint8_t _A_Settings_14_8[] = {0x00,0x00,0x09,0x06,0x05,0x0E,0x25,0x1C,0x19,0xB8,0x00,0x70,0x3C,0x3C,0x02,0x02,0x03,0x9A,0x04,0xA6,0x09,0xA0,0x13,0x90,0x26,0x70,0x0C,0x00,0x18,}; -const uint8_t _A_Settings_14_9[] = {0x00,0x03,0x07,0x87,0x04,0x8E,0x02,0x9C,0x32,0xF8,0x2C,0x50,0x20,0x30,0x1E,0x1E,0x03,0x81,0x04,0xCD,0x09,0x53,0x13,0x50,0x26,0x48,0x2C,0x38,0x18,}; +const uint8_t _A_Settings_14_0[] = {0x00,0x03,0x07,0x87,0x04,0x8e,0x02,0x9c,0x32,0xf8,0x2c,0x50,0x20,0x30,0x1e,0x1e,0x03,0x81,0x04,0xcd,0x09,0x53,0x13,0x50,0x26,0x48,0x2c,0x38,0x18,}; +const uint8_t _A_Settings_14_1[] = {0x00,0x03,0x00,0x87,0x03,0x4e,0x02,0x7c,0x01,0x48,0x19,0x58,0x16,0x30,0x10,0x10,0x0f,0x8f,0x04,0xc0,0x09,0x26,0x13,0x29,0x16,0x28,0x0c,0x24,0x00,}; +const uint8_t _A_Settings_14_2[] = {0x00,0x03,0x00,0x07,0x00,0xde,0x01,0x24,0x01,0xac,0x00,0xb8,0x0c,0x30,0x0b,0x10,0x08,0x88,0x07,0xc7,0x09,0x20,0x0b,0x13,0x06,0x14,0x00,0x14,0x00,}; +const uint8_t _A_Settings_14_3[] = {0x00,0x04,0x0c,0x09,0x00,0x13,0x20,0x26,0x20,0x4c,0x00,0xb8,0x00,0xa4,0x00,0x74,0x00,0x94,0x01,0x64,0x01,0x02,0x01,0xf1,0x18,0x08,0x38,0x04,0x30,}; +const uint8_t _A_Settings_14_4[] = {0x00,0x04,0x0f,0x89,0x00,0x93,0x26,0xa6,0x29,0x2c,0x28,0x18,0x24,0x00,0x1c,0x0e,0x00,0x09,0x00,0x05,0x06,0x65,0x0e,0x59,0x1c,0x40,0x38,0x3c,0x30,}; +const uint8_t _A_Settings_14_5[] = {0x00,0x04,0x08,0x05,0x04,0xc3,0x23,0x20,0x10,0xa0,0x09,0x60,0x0a,0x00,0x0a,0x80,0x09,0x80,0x07,0x03,0x07,0x02,0x0e,0x01,0x3c,0x19,0x08,0x16,0x18,}; +const uint8_t _A_Settings_14_6[] = {0x00,0x00,0x14,0x00,0x24,0x00,0x02,0x18,0x31,0xf8,0x08,0x08,0x04,0x68,0x02,0xd8,0x02,0x80,0x06,0xc0,0x0a,0xc0,0x13,0x00,0x26,0x00,0x0c,0x00,0x18,}; +const uint8_t _A_Settings_14_7[] = {0x00,0x00,0x0a,0x00,0x0a,0x0c,0x32,0x1c,0x01,0xb8,0x38,0x78,0x04,0x04,0x02,0x34,0x03,0x4c,0x05,0x40,0x09,0x20,0x13,0xe0,0x26,0x00,0x0c,0x00,0x18,}; +const uint8_t _A_Settings_14_8[] = {0x00,0x00,0x09,0x06,0x05,0x0e,0x25,0x1c,0x19,0xb8,0x00,0x70,0x3c,0x3c,0x02,0x02,0x03,0x9a,0x04,0xa6,0x09,0xa0,0x13,0x90,0x26,0x70,0x0c,0x00,0x18,}; +const uint8_t _A_Settings_14_9[] = {0x00,0x03,0x07,0x87,0x04,0x8e,0x02,0x9c,0x32,0xf8,0x2c,0x50,0x20,0x30,0x1e,0x1e,0x03,0x81,0x04,0xcd,0x09,0x53,0x13,0x50,0x26,0x48,0x2c,0x38,0x18,}; const uint8_t* const _A_Settings_14[] = {_A_Settings_14_0,_A_Settings_14_1,_A_Settings_14_2,_A_Settings_14_3,_A_Settings_14_4,_A_Settings_14_5,_A_Settings_14_6,_A_Settings_14_7,_A_Settings_14_8,_A_Settings_14_9}; const uint8_t _A_Sub1ghz_14_0[] = {0x01,0x00,0x1a,0x00,0x82,0x42,0x20,0x51,0x08,0x4c,0x92,0x0b,0x28,0xea,0xca,0x80,0x22,0x05,0x1e,0x4c,0x93,0x85,0x10,0xe2,0x42,0x38,0x10,0x00,0x0a,0x80,}; @@ -424,27 +424,27 @@ const uint8_t _A_Sub1ghz_14_4[] = {0x01,0x00,0x0a,0x00,0x00,0x3f,0x42,0x04,0x01, const uint8_t _A_Sub1ghz_14_5[] = {0x01,0x00,0x12,0x00,0x00,0x1c,0x22,0x09,0x04,0x84,0x75,0x21,0x40,0x11,0x02,0x8f,0x22,0x09,0xc0,0x80,0x00,0x64,}; const uint8_t* const _A_Sub1ghz_14[] = {_A_Sub1ghz_14_0,_A_Sub1ghz_14_1,_A_Sub1ghz_14_2,_A_Sub1ghz_14_3,_A_Sub1ghz_14_4,_A_Sub1ghz_14_5}; -const uint8_t _A_Tamagotchi_14_0[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x2A,0x1A,0x19,0x33,0x89,0x32,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_1[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x1A,0x1B,0xA9,0x32,0x19,0x33,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_2[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x8A,0x1A,0x19,0x33,0x29,0x32,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_3[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x4A,0x1B,0xA9,0x32,0x59,0x32,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_4[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0xAA,0x1A,0x49,0x32,0xA9,0x32,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; -const uint8_t _A_Tamagotchi_14_5[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x5A,0x1A,0xA9,0x32,0x49,0x33,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; +const uint8_t _A_Tamagotchi_14_0[] = {0x00,0xf0,0x03,0x08,0x06,0x04,0x0c,0x04,0x0c,0xf2,0x19,0x2a,0x1a,0x19,0x33,0x89,0x32,0xf1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0c,0x0e,0xf0,0x07,}; +const uint8_t _A_Tamagotchi_14_1[] = {0x00,0xf0,0x03,0x08,0x06,0x04,0x0c,0x04,0x0c,0xf2,0x19,0x1a,0x1b,0xa9,0x32,0x19,0x33,0xf1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0c,0x0e,0xf0,0x07,}; +const uint8_t _A_Tamagotchi_14_2[] = {0x00,0xf0,0x03,0x08,0x06,0x04,0x0c,0x04,0x0c,0xf2,0x19,0x8a,0x1a,0x19,0x33,0x29,0x32,0xf1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0c,0x0e,0xf0,0x07,}; +const uint8_t _A_Tamagotchi_14_3[] = {0x00,0xf0,0x03,0x08,0x06,0x04,0x0c,0x04,0x0c,0xf2,0x19,0x4a,0x1b,0xa9,0x32,0x59,0x32,0xf1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0c,0x0e,0xf0,0x07,}; +const uint8_t _A_Tamagotchi_14_4[] = {0x00,0xf0,0x03,0x08,0x06,0x04,0x0c,0x04,0x0c,0xf2,0x19,0xaa,0x1a,0x49,0x32,0xa9,0x32,0xf1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0c,0x0e,0xf0,0x07,}; +const uint8_t _A_Tamagotchi_14_5[] = {0x00,0xf0,0x03,0x08,0x06,0x04,0x0c,0x04,0x0c,0xf2,0x19,0x5a,0x1a,0xa9,0x32,0x49,0x33,0xf1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0c,0x0e,0xf0,0x07,}; const uint8_t* const _A_Tamagotchi_14[] = {_A_Tamagotchi_14_0,_A_Tamagotchi_14_1,_A_Tamagotchi_14_2,_A_Tamagotchi_14_3,_A_Tamagotchi_14_4,_A_Tamagotchi_14_5}; -const uint8_t _A_U2F_14_0[] = {0x00,0x00,0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; -const uint8_t _A_U2F_14_1[] = {0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; -const uint8_t _A_U2F_14_2[] = {0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0x08,0x00,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; -const uint8_t _A_U2F_14_3[] = {0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; +const uint8_t _A_U2F_14_0[] = {0x00,0x00,0x00,0x00,0x00,0xe0,0x01,0x10,0x02,0x08,0x04,0xfe,0x1f,0x01,0x20,0xd5,0x2d,0x55,0x25,0x15,0x2d,0x95,0x24,0xdd,0x25,0x01,0x20,0xfe,0x1f,}; +const uint8_t _A_U2F_14_1[] = {0x00,0x00,0x00,0xe0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0xfe,0x1f,0x01,0x20,0xd5,0x2d,0x55,0x25,0x15,0x2d,0x95,0x24,0xdd,0x25,0x01,0x20,0xfe,0x1f,}; +const uint8_t _A_U2F_14_2[] = {0x00,0xe0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0x08,0x00,0xfe,0x1f,0x01,0x20,0xd5,0x2d,0x55,0x25,0x15,0x2d,0x95,0x24,0xdd,0x25,0x01,0x20,0xfe,0x1f,}; +const uint8_t _A_U2F_14_3[] = {0x00,0x00,0x00,0xe0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0xfe,0x1f,0x01,0x20,0xd5,0x2d,0x55,0x25,0x15,0x2d,0x95,0x24,0xdd,0x25,0x01,0x20,0xfe,0x1f,}; const uint8_t* const _A_U2F_14[] = {_A_U2F_14_0,_A_U2F_14_1,_A_U2F_14_2,_A_U2F_14_3}; -const uint8_t _A_iButton_14_0[] = {0x00,0x00,0x1C,0x00,0x3E,0x00,0x35,0x80,0x3A,0x78,0x15,0x84,0x0A,0x32,0x05,0x49,0x02,0x85,0x02,0x85,0x02,0x49,0x02,0x32,0x01,0x84,0x00,0x78,0x00,}; -const uint8_t _A_iButton_14_1[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x26,0x80,0x21,0xE0,0x10,0x38,0x0D,0x6C,0x03,0x56,0x01,0x2B,0x01,0x97,0x00,0x4D,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,}; +const uint8_t _A_iButton_14_0[] = {0x00,0x00,0x1c,0x00,0x3e,0x00,0x35,0x80,0x3a,0x78,0x15,0x84,0x0a,0x32,0x05,0x49,0x02,0x85,0x02,0x85,0x02,0x49,0x02,0x32,0x01,0x84,0x00,0x78,0x00,}; +const uint8_t _A_iButton_14_1[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x26,0x80,0x21,0xe0,0x10,0x38,0x0d,0x6c,0x03,0x56,0x01,0x2b,0x01,0x97,0x00,0x4d,0x00,0x21,0x00,0x1e,0x00,0x00,0x00,}; const uint8_t _A_iButton_14_2[] = {0x01,0x00,0x1a,0x00,0x00,0x24,0xc2,0x01,0x2c,0x80,0x48,0xfb,0x11,0x89,0x64,0x1b,0x2d,0x01,0xa5,0xc0,0x24,0xb0,0x08,0x94,0x02,0x13,0x00,0x83,0x85,0x88,}; -const uint8_t _A_iButton_14_3[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x26,0x80,0x21,0x60,0x18,0x98,0x06,0x04,0x01,0x02,0x01,0x01,0x01,0x81,0x00,0x41,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,}; +const uint8_t _A_iButton_14_3[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x26,0x80,0x21,0x60,0x18,0x98,0x06,0x04,0x01,0x02,0x01,0x01,0x01,0x81,0x00,0x41,0x00,0x21,0x00,0x1e,0x00,0x00,0x00,}; const uint8_t _A_iButton_14_4[] = {0x01,0x00,0x1a,0x00,0x80,0x47,0x20,0x13,0xe8,0x04,0xd7,0x01,0x3a,0xbc,0x45,0x70,0x90,0xa8,0x14,0x16,0x03,0x02,0x00,0xa8,0x08,0x70,0x90,0x0b,0xc4,0x00,}; const uint8_t _A_iButton_14_5[] = {0x01,0x00,0x1a,0x00,0x00,0x14,0xe2,0x01,0x24,0x80,0x48,0xb0,0x11,0x1f,0x04,0x22,0x31,0x05,0x83,0x40,0xa0,0x20,0x13,0x80,0xf0,0x60,0x13,0xe0,0xc1,0x00,}; -const uint8_t _A_iButton_14_6[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x24,0x00,0x23,0x80,0x20,0xF0,0x10,0x0C,0x0D,0xE2,0x02,0x91,0x01,0x69,0x01,0x15,0x01,0x8D,0x00,0x4D,0x00,0x3E,0x00,}; +const uint8_t _A_iButton_14_6[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x24,0x00,0x23,0x80,0x20,0xf0,0x10,0x0c,0x0d,0xe2,0x02,0x91,0x01,0x69,0x01,0x15,0x01,0x8d,0x00,0x4d,0x00,0x3e,0x00,}; const uint8_t* const _A_iButton_14[] = {_A_iButton_14_0,_A_iButton_14_1,_A_iButton_14_2,_A_iButton_14_3,_A_iButton_14_4,_A_iButton_14_5,_A_iButton_14_6}; const uint8_t _I_Detailed_chip_17x13_0[] = {0x01,0x00,0x1e,0x00,0xfe,0x5f,0xe0,0x10,0x2c,0x04,0x02,0x23,0x11,0x80,0xe4,0x62,0x50,0x1a,0xff,0xc2,0x03,0x21,0x84,0x00,0x9a,0xbf,0xf4,0x08,0x98,0x5c,0x83,0xa4,0x23,0x20,}; @@ -453,22 +453,22 @@ const uint8_t* const _I_Detailed_chip_17x13[] = {_I_Detailed_chip_17x13_0}; const uint8_t _I_Medium_chip_22x21_0[] = {0x01,0x00,0x35,0x00,0xfe,0x7f,0xe1,0xf0,0x28,0x04,0x43,0xf3,0xff,0x93,0xe1,0x6a,0x52,0x8e,0x2f,0xfe,0x51,0x25,0x80,0x4a,0x72,0xb6,0x79,0x55,0x76,0xc1,0x2e,0xaa,0xc0,0x25,0x51,0xdc,0x00,0x14,0x70,0x00,0x56,0xae,0x81,0x47,0x2b,0x7d,0x95,0x07,0x48,0x46,0x42,0x92,0x17,0x90,0xd4,0x87,0x64,}; const uint8_t* const _I_Medium_chip_22x21[] = {_I_Medium_chip_22x21_0}; -const uint8_t _I_Pin_arrow_down_7x9_0[] = {0x00,0x1C,0x1C,0x1C,0x1C,0x1C,0x7F,0x3E,0x1C,0x08,}; +const uint8_t _I_Pin_arrow_down_7x9_0[] = {0x00,0x1c,0x1c,0x1c,0x1c,0x1c,0x7f,0x3e,0x1c,0x08,}; const uint8_t* const _I_Pin_arrow_down_7x9[] = {_I_Pin_arrow_down_7x9_0}; -const uint8_t _I_Pin_arrow_left_9x7_0[] = {0x00,0x08,0x00,0x0C,0x00,0xFE,0x01,0xFF,0x01,0xFE,0x01,0x0C,0x00,0x08,0x00,}; +const uint8_t _I_Pin_arrow_left_9x7_0[] = {0x00,0x08,0x00,0x0c,0x00,0xfe,0x01,0xff,0x01,0xfe,0x01,0x0c,0x00,0x08,0x00,}; const uint8_t* const _I_Pin_arrow_left_9x7[] = {_I_Pin_arrow_left_9x7_0}; -const uint8_t _I_Pin_arrow_right_9x7_0[] = {0x00,0x20,0x00,0x60,0x00,0xFF,0x00,0xFF,0x01,0xFF,0x00,0x60,0x00,0x20,0x00,}; +const uint8_t _I_Pin_arrow_right_9x7_0[] = {0x00,0x20,0x00,0x60,0x00,0xff,0x00,0xff,0x01,0xff,0x00,0x60,0x00,0x20,0x00,}; const uint8_t* const _I_Pin_arrow_right_9x7[] = {_I_Pin_arrow_right_9x7_0}; -const uint8_t _I_Pin_arrow_up7x9_0[] = {0x00,0x08,0x1C,0x3E,0x7F,0x1C,0x1C,0x1C,0x1C,0x1C,}; +const uint8_t _I_Pin_arrow_up7x9_0[] = {0x00,0x08,0x1c,0x3e,0x7f,0x1c,0x1c,0x1c,0x1c,0x1c,}; const uint8_t* const _I_Pin_arrow_up7x9[] = {_I_Pin_arrow_up7x9_0}; const uint8_t _I_Pin_attention_dpad_29x29_0[] = {0x01,0x00,0x56,0x00,0x80,0x7f,0x20,0xe0,0x31,0x81,0xc6,0x20,0x1c,0x08,0x05,0x82,0x01,0x20,0xa0,0x60,0x20,0x11,0x0f,0x04,0x02,0x03,0x08,0xf8,0x40,0x60,0x50,0x4f,0xc4,0x0e,0x09,0x04,0x05,0x8c,0x12,0x04,0x03,0x18,0x44,0x08,0x42,0x30,0x88,0x08,0x0c,0x62,0x14,0x18,0x05,0x02,0x21,0x61,0x14,0x8c,0x43,0xe3,0x01,0xf8,0x44,0x7f,0x20,0x31,0x89,0x81,0xcc,0x1e,0x61,0x73,0x0f,0x98,0x9c,0xc5,0xe6,0x37,0x31,0xf9,0x91,0xcc,0x9e,0x65,0x73,0x2f,0x99,0x9c,0xcd,0xe6,}; const uint8_t* const _I_Pin_attention_dpad_29x29[] = {_I_Pin_attention_dpad_29x29_0}; -const uint8_t _I_Pin_back_arrow_10x8_0[] = {0x00,0x04,0x00,0x06,0x00,0xFF,0x00,0x06,0x01,0x04,0x02,0x00,0x02,0x00,0x01,0xF8,0x00,}; +const uint8_t _I_Pin_back_arrow_10x8_0[] = {0x00,0x04,0x00,0x06,0x00,0xff,0x00,0x06,0x01,0x04,0x02,0x00,0x02,0x00,0x01,0xf8,0x00,}; const uint8_t* const _I_Pin_back_arrow_10x8[] = {_I_Pin_back_arrow_10x8_0}; const uint8_t _I_Pin_back_full_40x8_0[] = {0x01,0x00,0x26,0x00,0x82,0x01,0x0e,0x0c,0x02,0x18,0x14,0x03,0xfe,0x04,0x38,0x37,0xc6,0xc3,0x32,0xf7,0x41,0x20,0x59,0x0a,0x54,0xa6,0x01,0xf2,0x88,0xde,0x80,0x83,0x01,0xc8,0x42,0xa5,0x3f,0x88,0x05,0x82,0x65,0x2e,}; @@ -477,10 +477,10 @@ const uint8_t* const _I_Pin_back_full_40x8[] = {_I_Pin_back_full_40x8_0}; const uint8_t _I_Pin_cell_13x13_0[] = {0x01,0x00,0x0a,0x00,0xff,0xc7,0xe0,0x31,0x00,0x0f,0x80,0x4c,0x2e,0x20,}; const uint8_t* const _I_Pin_cell_13x13[] = {_I_Pin_cell_13x13_0}; -const uint8_t _I_Pin_pointer_5x3_0[] = {0x00,0x04,0x0E,0x1F,}; +const uint8_t _I_Pin_pointer_5x3_0[] = {0x00,0x04,0x0e,0x1f,}; const uint8_t* const _I_Pin_pointer_5x3[] = {_I_Pin_pointer_5x3_0}; -const uint8_t _I_Pin_star_7x7_0[] = {0x00,0x49,0x2A,0x1C,0x7F,0x1C,0x2A,0x49,}; +const uint8_t _I_Pin_star_7x7_0[] = {0x00,0x49,0x2a,0x1c,0x7f,0x1c,0x2a,0x49,}; const uint8_t* const _I_Pin_star_7x7[] = {_I_Pin_star_7x7_0}; const uint8_t _I_passport_bad1_46x49_0[] = {0x01,0x00,0xd2,0x00,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7e,0x02,0x18,0x0f,0xe0,0x0a,0x57,0xff,0xf7,0x9c,0x0a,0x59,0xf8,0x0e,0x60,0x0a,0x56,0xf8,0x05,0x83,0xfc,0x05,0x18,0xbc,0x03,0x01,0xfd,0x02,0x8c,0x2c,0x5a,0x3f,0xa0,0x28,0xc1,0x40,0xa3,0xf4,0x02,0x8c,0x08,0x0a,0x77,0xf8,0x08,0x14,0x7d,0x13,0xfd,0xf9,0x14,0x80,0xab,0xd0,0x9f,0xd7,0xe0,0x10,0x60,0x2a,0x42,0x20,0x1a,0x09,0xfc,0xbe,0x01,0x10,0x02,0xa5,0x9c,0x0a,0x78,0x0e,0x74,0x04,0x0a,0x31,0x7a,0x06,0x7a,0x06,0x05,0x39,0xb0,0x44,0x80,0xa3,0x7e,0x02,0xa5,0xf0,0x0a,0x78,0x0a,0x00,0x14,0xf8,0x13,0xf0,0x29,0xc8,0x07,0x66,0x70,0x11,0xd8,0xea,0xa7,0xf1,0xb2,0x99,0x4c,0x00,0xa9,0xc0,0x9f,0x01,0x4e,0x01,0x3d,0x02,0x8c,0x38,0x0a,0x33,0xa8,0x6c,0x02,0x62,0x05,0x19,0xa0,0x14,0x78,0x00,0x51,0x94,0x01,0x46,0x01,0x03,0x02,0xa4,0x30,0x0a,0x2a,0x02,0x98,0x7c,0x25,0x60,0x52,0xe0,0x43,0xe5,0x80,0x51,0xc0,0x27,0x46,0x51,0x09,0x05,0x88,0xc0,0x66,0x80,0x52,0xfe,0x40,0x27,0x60,0x52,0xf8,0x7f,0xe7,0xa0,0x52,0xe0,0x5f,0xe7,0xc0,0x52,0x80,0x6f,0xe7,0xe0,0x53,0xde,0x01,0x50,0xe2,0x20,0x5f,0x02,0xbf,0xfb,0xfe,0x00,0x28,0xf8,}; @@ -561,13 +561,13 @@ const uint8_t* const _I_SDQuestion_35x43[] = {_I_SDQuestion_35x43_0}; const uint8_t _I_Cry_dolph_55x52_0[] = {0x01,0x00,0xe8,0x00,0x00,0x0f,0xe3,0xff,0x01,0x03,0x1f,0xfb,0xff,0x0f,0x02,0x96,0x02,0x0f,0x00,0x9f,0x01,0x8b,0xc0,0x12,0x1f,0x80,0x18,0xae,0x00,0x21,0xe0,0x07,0x0a,0x30,0x0a,0x28,0x18,0x08,0x61,0x80,0x62,0x83,0x00,0x90,0x14,0x61,0x02,0x0c,0x16,0x00,0x76,0x60,0x66,0x98,0x0b,0x04,0x90,0x60,0x66,0xb0,0x00,0x48,0x0d,0x21,0x21,0x03,0x30,0x74,0x40,0xd3,0x80,0x03,0x34,0x04,0xc0,0x52,0x00,0x32,0xc7,0xa0,0x18,0x80,0x31,0x80,0x07,0xe1,0x01,0x37,0x18,0x50,0x80,0xc2,0x92,0x10,0x31,0xe8,0x23,0xe9,0x63,0x86,0x54,0x3f,0xe0,0xe1,0x0d,0x96,0x83,0xfc,0x06,0x40,0x69,0x6c,0x3c,0x60,0xd2,0xfc,0xc0,0x60,0x58,0x48,0x0c,0x1b,0x81,0x08,0x14,0x9c,0x1a,0x81,0x04,0x03,0x46,0x80,0x0c,0x50,0x26,0x21,0xc1,0x94,0x26,0x14,0x27,0x8a,0x40,0xc0,0xc2,0xe7,0x26,0x40,0x81,0x86,0xc0,0x6b,0x28,0x64,0x0f,0x01,0x10,0x4e,0x14,0x60,0x0c,0x29,0x02,0x48,0x8b,0x5c,0x45,0x22,0x01,0x10,0x31,0x3a,0x4c,0x0c,0x34,0x06,0xf1,0xd8,0x00,0xc5,0x1a,0x64,0x94,0x0c,0xc0,0x37,0x52,0x20,0x81,0x84,0x26,0x3e,0x88,0x0c,0x38,0x28,0x54,0x0e,0xac,0x1f,0xe1,0x3f,0x06,0x96,0x82,0x7e,0x29,0x4a,0xaf,0xfd,0x76,0x30,0x3a,0x41,0x14,0x7f,0xd0,0xf8,0x78,0x18,0xaa,0x9f,0xd4,0xe0,0x83,0x4f,0xf5,0xf7,0x38,0x0b,0x9c,0x6a,0x1f,0x5b,0x5c,0x00,}; const uint8_t* const _I_Cry_dolph_55x52[] = {_I_Cry_dolph_55x52_0}; -const uint8_t _I_Attention_5x8_0[] = {0x00,0x0E,0x0A,0x0A,0x0A,0x0E,0x04,0x00,0x0E,}; +const uint8_t _I_Attention_5x8_0[] = {0x00,0x0e,0x0a,0x0a,0x0a,0x0e,0x04,0x00,0x0e,}; const uint8_t* const _I_Attention_5x8[] = {_I_Attention_5x8_0}; const uint8_t _I_Background_128x11_0[] = {0x01,0x00,0x70,0x00,0xff,0x40,0x40,0xc9,0xe0,0xff,0x80,0x06,0x1e,0x08,0x38,0x0c,0x0c,0x1e,0x93,0x00,0x19,0x46,0x01,0x07,0x7d,0x83,0x03,0xd2,0x31,0xff,0xdb,0xd5,0x66,0x20,0x83,0xc0,0xff,0x05,0x24,0x00,0x1c,0x78,0x28,0xbc,0x40,0x72,0xbf,0xcf,0x47,0xeb,0x40,0xdb,0x7a,0xbf,0xf0,0x40,0x39,0x60,0x28,0x3f,0xe0,0xa0,0xea,0x80,0x63,0x3f,0x0b,0x17,0xe4,0x3e,0x5a,0xbc,0xf9,0x99,0x70,0x1f,0x81,0x50,0xc0,0x80,0xe7,0x3e,0x1e,0x9d,0x57,0xfb,0x7f,0x23,0x15,0xb0,0x12,0x5b,0x5b,0x02,0x1d,0x8c,0xc3,0x80,0x24,0x9e,0x03,0x80,0x5e,0x40,0x00,0xa1,0x88,0x0e,0x98,0x00,0x7b,0x07,0x08,0xb2,0x44,0x41,}; const uint8_t* const _I_Background_128x11[] = {_I_Background_128x11_0}; -const uint8_t _I_BadUsb_9x8_0[] = {0x00,0x01,0x01,0xBB,0x01,0xFE,0x00,0xFE,0x00,0xD6,0x00,0xD6,0x00,0x7C,0x00,0x38,0x00,}; +const uint8_t _I_BadUsb_9x8_0[] = {0x00,0x01,0x01,0xbb,0x01,0xfe,0x00,0xfe,0x00,0xd6,0x00,0xd6,0x00,0x7c,0x00,0x38,0x00,}; const uint8_t* const _I_BadUsb_9x8[] = {_I_BadUsb_9x8_0}; const uint8_t _I_Battery_19x8_0[] = {0x01,0x00,0x0f,0x00,0xff,0x7f,0xe0,0x30,0x18,0x04,0x08,0x04,0x90,0x60,0x12,0x02,0xcc,0x28,0x40,}; @@ -576,19 +576,19 @@ const uint8_t* const _I_Battery_19x8[] = {_I_Battery_19x8_0}; const uint8_t _I_Battery_26x8_0[] = {0x01,0x00,0x13,0x00,0xff,0x7f,0xef,0xf0,0x08,0x0c,0x03,0x00,0x03,0x38,0x18,0x0c,0xa0,0x40,0x36,0x05,0x98,0x6d,0x00,}; const uint8_t* const _I_Battery_26x8[] = {_I_Battery_26x8_0}; -const uint8_t _I_Bluetooth_Connected_16x8_0[] = {0x00,0x04,0x00,0x0D,0x00,0x16,0x60,0x4C,0x97,0x4C,0x97,0x16,0x60,0x0D,0x00,0x04,0x00,}; +const uint8_t _I_Bluetooth_Connected_16x8_0[] = {0x00,0x04,0x00,0x0d,0x00,0x16,0x60,0x4c,0x97,0x4c,0x97,0x16,0x60,0x0d,0x00,0x04,0x00,}; const uint8_t* const _I_Bluetooth_Connected_16x8[] = {_I_Bluetooth_Connected_16x8_0}; -const uint8_t _I_Bluetooth_Idle_5x8_0[] = {0x00,0x04,0x0D,0x16,0x0C,0x0C,0x16,0x0D,0x04,}; +const uint8_t _I_Bluetooth_Idle_5x8_0[] = {0x00,0x04,0x0d,0x16,0x0c,0x0c,0x16,0x0d,0x04,}; const uint8_t* const _I_Bluetooth_Idle_5x8[] = {_I_Bluetooth_Idle_5x8_0}; -const uint8_t _I_Charging_lightning_9x10_0[] = {0x00,0x40,0x01,0xA0,0x00,0x50,0x00,0xE8,0x01,0x84,0x00,0x42,0x00,0x2F,0x00,0x14,0x00,0x0A,0x00,0x05,0x00,}; +const uint8_t _I_Charging_lightning_9x10_0[] = {0x00,0x40,0x01,0xa0,0x00,0x50,0x00,0xe8,0x01,0x84,0x00,0x42,0x00,0x2f,0x00,0x14,0x00,0x0a,0x00,0x05,0x00,}; const uint8_t* const _I_Charging_lightning_9x10[] = {_I_Charging_lightning_9x10_0}; -const uint8_t _I_Charging_lightning_mask_9x10_0[] = {0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x10,0x00,0x78,0x00,0x3C,0x00,0x10,0x00,0x08,0x00,0x04,0x00,0x02,0x00,}; +const uint8_t _I_Charging_lightning_mask_9x10_0[] = {0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x10,0x00,0x78,0x00,0x3c,0x00,0x10,0x00,0x08,0x00,0x04,0x00,0x02,0x00,}; const uint8_t* const _I_Charging_lightning_mask_9x10[] = {_I_Charging_lightning_mask_9x10_0}; -const uint8_t _I_Lock_8x8_0[] = {0x00,0x3C,0x42,0x42,0xFF,0xFF,0xE7,0xFF,0xFF,}; +const uint8_t _I_Lock_8x8_0[] = {0x00,0x3c,0x42,0x42,0xff,0xff,0xe7,0xff,0xff,}; const uint8_t* const _I_Lock_8x8[] = {_I_Lock_8x8_0}; const uint8_t _I_PlaceholderL_11x13_0[] = {0x01,0x00,0x10,0x00,0xfe,0x40,0x60,0x50,0x28,0x0c,0x10,0x03,0xb0,0x38,0x37,0xfe,0x07,0xfe,0x80,0x80,}; @@ -597,25 +597,25 @@ const uint8_t* const _I_PlaceholderL_11x13[] = {_I_PlaceholderL_11x13_0}; const uint8_t _I_PlaceholderR_30x13_0[] = {0x01,0x00,0x19,0x00,0xfe,0x7f,0xff,0xf0,0xf8,0x10,0x18,0x62,0x10,0x10,0x18,0xc8,0x00,0x7e,0x03,0xb8,0x18,0x0c,0x66,0x1f,0xe1,0x58,0xc7,0xc5,0xe6,}; const uint8_t* const _I_PlaceholderR_30x13[] = {_I_PlaceholderR_30x13_0}; -const uint8_t _I_SDcardFail_11x8_0[] = {0x00,0xFF,0x07,0xB7,0x07,0xFF,0x07,0x87,0x07,0x7B,0x07,0xFF,0x07,0xFF,0x07,0x67,0x00,}; +const uint8_t _I_SDcardFail_11x8_0[] = {0x00,0xff,0x07,0xb7,0x07,0xff,0x07,0x87,0x07,0x7b,0x07,0xff,0x07,0xff,0x07,0x67,0x00,}; const uint8_t* const _I_SDcardFail_11x8[] = {_I_SDcardFail_11x8_0}; const uint8_t _I_SDcardMounted_11x8_0[] = {0x01,0x00,0x09,0x00,0xff,0xc1,0xff,0xf0,0x40,0x1c,0xd9,0xe0,0x00,}; const uint8_t* const _I_SDcardMounted_11x8[] = {_I_SDcardMounted_11x8_0}; -const uint8_t _I_Lock_7x8_0[] = {0x00,0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; +const uint8_t _I_Lock_7x8_0[] = {0x00,0x1c,0x22,0x22,0x7f,0x7f,0x77,0x7f,0x3e,}; const uint8_t* const _I_Lock_7x8[] = {_I_Lock_7x8_0}; const uint8_t _I_MHz_25x11_0[] = {0x01,0x00,0x21,0x00,0xe1,0xe1,0xa0,0x30,0x0f,0x38,0x0c,0xbf,0xe0,0x34,0xfe,0xc0,0x7b,0x7f,0xe0,0x19,0xf0,0x60,0x1d,0xbc,0x35,0x84,0x36,0x53,0x10,0x19,0x46,0x40,0x64,0x13,0x10,0x19,0x80,}; const uint8_t* const _I_MHz_25x11[] = {_I_MHz_25x11_0}; -const uint8_t _I_Quest_7x8_0[] = {0x00,0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,}; +const uint8_t _I_Quest_7x8_0[] = {0x00,0x1e,0x33,0x33,0x30,0x18,0x0c,0x00,0x0c,}; const uint8_t* const _I_Quest_7x8[] = {_I_Quest_7x8_0}; const uint8_t _I_Scanning_123x52_0[] = {0x01,0x00,0xd3,0x01,0x00,0x78,0x03,0xc0,0x1f,0x00,0xe0,0x7f,0xc1,0xfb,0xf0,0x80,0x41,0xc0,0xc7,0x03,0x07,0xbe,0xb2,0x07,0x18,0x07,0xc4,0x40,0x06,0x55,0x68,0x2d,0x80,0x0a,0x58,0x08,0x10,0x3c,0xe1,0x00,0x32,0xc0,0xc2,0xb0,0x00,0xf8,0x82,0x02,0x0a,0x01,0x15,0x80,0x40,0x40,0xc3,0x40,0x07,0xa0,0x10,0xa8,0x10,0x09,0xc0,0x19,0x01,0xe9,0x82,0x01,0x0c,0x82,0x01,0x74,0x13,0x1d,0x03,0x04,0x24,0x28,0x05,0x04,0x1e,0x76,0x80,0x79,0xc8,0x30,0x50,0x28,0x30,0x14,0x64,0x26,0x23,0xe8,0x78,0x21,0xe0,0xf4,0x85,0x43,0x30,0x12,0x03,0x00,0x83,0xc7,0x41,0x1c,0x3b,0x10,0x3c,0xe2,0x98,0x08,0x80,0xa4,0x61,0x1e,0x0e,0x9c,0x0c,0x1e,0x51,0x00,0x7a,0x95,0x46,0x11,0x90,0xd3,0xd0,0x24,0x80,0xfb,0xe4,0x5f,0xf0,0x92,0x80,0x79,0x61,0x01,0xe3,0xff,0x07,0x9e,0x22,0xcf,0x3e,0xc4,0x03,0xd3,0xf5,0xff,0x07,0xa5,0x12,0xc9,0x2e,0x07,0xa7,0xf3,0x5f,0xff,0x8a,0x93,0xce,0x89,0xe4,0x97,0xe2,0x25,0x40,0xf1,0x8c,0x75,0x3b,0xf1,0xf1,0xf8,0x9b,0xc8,0x1e,0x55,0x0f,0xfc,0x03,0xfd,0x1f,0xf6,0x4f,0xc9,0xe2,0x8f,0x3a,0x27,0x12,0x5f,0xea,0x68,0x0c,0x06,0x35,0xfc,0x2f,0x92,0xbc,0xf0,0x98,0x89,0x7c,0x75,0x8e,0x37,0xd8,0xf1,0x7c,0xa3,0x0c,0xf3,0xc3,0x47,0xf8,0xcb,0x81,0xc2,0x5f,0x62,0xc0,0xf2,0x77,0xa5,0x1b,0xeb,0xc3,0x6c,0x8d,0x12,0x03,0x22,0x07,0x8c,0x30,0x18,0x2d,0x82,0xc3,0xc2,0xaf,0x84,0x42,0x81,0xc8,0xb1,0x01,0xb2,0x4e,0x08,0x08,0x68,0xb0,0x50,0x20,0xdf,0xb4,0x90,0x3a,0x10,0x3d,0x19,0x05,0x86,0x1e,0x8f,0x03,0x03,0xa5,0x83,0xd0,0xa1,0x10,0x30,0x79,0x00,0x0a,0x0a,0x02,0x19,0x84,0x03,0xa5,0xff,0xc0,0x8a,0x88,0x00,0x81,0xe1,0x80,0x12,0x07,0xa5,0x1f,0xc0,0x03,0xde,0x0b,0x80,0x80,0x0a,0x47,0xa3,0x1f,0x80,0x42,0x43,0xf1,0xe1,0x80,0x60,0x3d,0x30,0xf8,0x04,0x48,0x3e,0xf0,0x08,0xf1,0x40,0x7d,0x00,0xf1,0x56,0x08,0xfe,0x20,0x17,0x0f,0x70,0x3c,0x55,0x82,0x00,0x58,0x38,0x0c,0xa7,0x9f,0x90,0x78,0x80,0x1c,0xec,0x5a,0xac,0xff,0xc0,0x1f,0x30,0x1a,0x05,0x57,0xfb,0x5f,0xf8,0x45,0xc3,0xf3,0x80,0xf5,0x7f,0xe7,0xfe,0x00,0x7c,0x87,0xc7,0xab,0xff,0x8f,0x83,0xea,0x05,0x80,0xd5,0x7f,0xe1,0xfe,0x08,0x98,0x7e,0x60,0x15,0x5a,0xac,0x0f,0xe1,0x15,0x0f,0xc9,0x78,0x75,0x50,0x0d,0x84,0x28,0x3f,0x55,0x4b,0xac,0x02,0xb1,0x0d,0x0f,0xd6,0xa0,0xf8,0x3a,0x85,0x29,0xaf,0xde,0xf8,0x04,0x1a,0xe2,0x54,0x83,0xf0,0x00,0x2d,0x70,0xd4,0x43,0xf2,0x00,0x2e,0xb8,0x3a,0x20,0x05,0x93,0xc0,0x5e,0xc1,0xf2,0x79,0x3e,0x04,0x7c,0x1f,0x32,0xa0,0x19,0x7c,0x1e,0x86,0x00,0x6a,0xa8,0x0c,0xbf,0x84,0xe9,0x4e,0x88,0x0c,0x85,0xd5,0x00,}; const uint8_t* const _I_Scanning_123x52[] = {_I_Scanning_123x52_0}; -const uint8_t _I_Unlock_7x8_0[] = {0x00,0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; +const uint8_t _I_Unlock_7x8_0[] = {0x00,0x1c,0x22,0x02,0x4f,0x67,0x73,0x79,0x3c,}; const uint8_t* const _I_Unlock_7x8[] = {_I_Unlock_7x8_0}; const uint8_t _I_Auth_62x31_0[] = {0x01,0x00,0xaf,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x02,0x1b,0x04,0x02,0x40,0x04,0x10,0x11,0x01,0xc4,0x18,0x40,0x72,0xf0,0x40,0x40,0xe4,0x1a,0x20,0x38,0xc2,0x3e,0x00,0x71,0xbc,0x05,0xca,0x11,0x08,0x80,0xe0,0x30,0xc0,0x72,0x82,0x7d,0x20,0x44,0x81,0x80,0x81,0xcb,0x75,0x05,0x02,0x08,0x1c,0xe7,0x50,0x58,0xc0,0x94,0x40,0xe5,0xfa,0x82,0xc1,0xbf,0x06,0xc1,0x80,0x40,0x80,0xe3,0x00,0xbe,0x40,0x3f,0x10,0x18,0x17,0xd0,0xd0,0x33,0xf3,0xa0,0xc0,0xe0,0x52,0x88,0x26,0x02,0x3e,0x1d,0x18,0x14,0x08,0xa0,0x3c,0x08,0x78,0x3c,0xc0,0xe3,0xe0,0x83,0x87,0xcd,0x32,0x42,0x11,0x17,0x90,0x04,0x61,0x9f,0xf8,0x06,0x20,0x0e,0x41,0xb1,0x9e,0x1b,0x44,0x2e,0x5f,0x0f,0xfc,0x0c,0x0e,0x80,0x02,0x80,0xc1,0x00,0xe8,0xab,0x11,0xf9,0x01,0xca,0xe0,0x07,0x68,0x60,0xb4,0x40,0xe7,0xfe,0x1f,0x88,0x1d,0x09,0x82,0x28,0x10,0xba,0x01,0xcc,}; From aa066645b076fce20bc285427544734627e2a7c0 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 10 Jun 2022 01:44:15 +0400 Subject: [PATCH 075/184] Build: added "resources" target for rebuilding SD card resources Manifest; fixed manifest processing on Windows --- assets/SConscript | 17 +++++++++++++++-- sconscfg/appmanifests.scons | 2 +- scripts/flipper/assets/manifest.py | 12 ++++++++---- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/assets/SConscript b/assets/SConscript index fc7d755bf1b1..2e4433d1fa62 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -94,7 +94,7 @@ assetsenv.Append( "IconBuilder": Builder( action=Action( "${PYTHON3} ${ASSETS_COMPILER} icons ${SOURCE.posix} ${TARGET.dir.posix}", - "\tICONS\t${TARGET}", + "\tICONS\t${TARGET}", ), emitter=icons_emitter, ), @@ -164,7 +164,6 @@ proto_ver = assetsenv.Command( Depends(proto_ver, proto) Alias("proto_ver", proto_ver) - assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) assetsenv.Install("#/assets/compiled", assets_parts) @@ -179,4 +178,18 @@ assetslib = assetsenv.Library("assets", assets_parts) assetsenv.Install("${LIB_DIST_DIR}", assetslib) +resources_src = assetsenv.GlobRecursive("*", "resources", exclude="Manifest") +resources = assetsenv.Command( + "#/assets/resources/Manifest", + "", + action=Action( + '${PYTHON3} ${ASSETS_COMPILER} manifest "${TARGET.dir.posix}"', + "\tRES\t${TARGET}", + ), +) +Depends(resources, resources_src) +Precious(resources) +NoClean(resources) +Alias("resources", resources) + Return("assetslib") diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index 1ca5684555b2..78aa096c8975 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -247,7 +247,7 @@ def LoadApplicationManifests(env): def PrepareApplicationsBuild(env): apps = fwenv["APPS"] apps_buildlist = fwenv["APPBUILD"] = fwenv["APPMGR"].filter_apps(apps) - print("Building firmware with modules:") + print("Firmware modules configuration:") for apptype in FlipperAppType: app_sublist = apps_buildlist.get_apps_of_type(apptype) if app_sublist: diff --git a/scripts/flipper/assets/manifest.py b/scripts/flipper/assets/manifest.py index 97a0af022a06..7eba46c99164 100644 --- a/scripts/flipper/assets/manifest.py +++ b/scripts/flipper/assets/manifest.py @@ -1,6 +1,8 @@ import datetime import logging import os +import posixpath +from pathlib import Path from flipper.utils import * from flipper.utils.fstree import * @@ -137,20 +139,22 @@ def create(self, directory_path, ignore_files=["Manifest"]): dirs.sort() files.sort() relative_root = root.replace(directory_path, "", 1) + if relative_root: + relative_root = Path(relative_root).as_posix() if relative_root.startswith("/"): relative_root = relative_root[1:] # process directories - for dir in dirs: - relative_dir_path = os.path.join(relative_root, dir) + for dirname in dirs: + relative_dir_path = posixpath.join(relative_root, dirname) self.logger.debug(f'Adding directory: "{relative_dir_path}"') self.addDirectory(relative_dir_path) # Process files for file in files: - relative_file_path = os.path.join(relative_root, file) + relative_file_path = posixpath.join(relative_root, file) if file in ignore_files: self.logger.info(f'Skipping file "{relative_file_path}"') continue - full_file_path = os.path.join(root, file) + full_file_path = posixpath.join(root, file) self.logger.debug(f'Adding file: "{relative_file_path}"') self.addFile( relative_file_path, From 66e982a8b1bbdb106ca08506115b2ffb8ea277cf Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 10 Jun 2022 02:57:41 +0400 Subject: [PATCH 076/184] Scripts: fixed ImportError handling for pillow/heatshrink2 --- scripts/flipper/assets/icon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/flipper/assets/icon.py b/scripts/flipper/assets/icon.py index 5854d15c0e46..db56a0a90719 100644 --- a/scripts/flipper/assets/icon.py +++ b/scripts/flipper/assets/icon.py @@ -45,7 +45,7 @@ def png2xbm(self, file): except ImportError as e: self.__pil_unavailable = True self.logger.info("pillow module is missing, using convert cli util") - return self.__png2xbm(file) + return self.png2xbm(file) with Image.open(file) as im: with io.BytesIO() as output: @@ -65,7 +65,7 @@ def xbm2hs(self, data): except ImportError as e: self.__hs2_unavailable = True self.logger.info("heatshrink2 module is missing, using heatshrink cli util") - return self.__xbm2hs(data) + return self.xbm2hs(data) return heatshrink2.compress(data, window_sz2=8, lookahead_sz2=4) From 1d985f7b57054977ddeee4088d0e4e6e149c9cd7 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 10 Jun 2022 13:51:50 +0400 Subject: [PATCH 077/184] Build: better, faster & stronger GlobRecursive impl(); added FORCE flag to rebuild 'flash' target; better deps handling for dolphin assets --- assets/SConscript | 49 +++++++++++++++++++++++++++--------------- firmware.scons | 2 ++ lib/toolbox/SConscript | 2 +- sconscfg/environ.scons | 16 ++++++++------ 4 files changed, 44 insertions(+), 25 deletions(-) diff --git a/assets/SConscript b/assets/SConscript index 2e4433d1fa62..6d46d6ff8f1a 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -36,13 +36,25 @@ def proto_emitter(target, source, env): def dolphin_emitter(target, source, env): - # target.append(target[0]) - # print("dolphin_emitter", out_path) - asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" - target = [ - File(asset_basename + ".c"), - File(asset_basename + ".h"), - ] + fixed_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) + source = [fixed_root_dir] + source.extend( + env.GlobRecursive("*.*", fixed_root_dir), + ) + + if env["DOLPHIN_RES_TYPE"] == "external": + pass + else: + asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" + target = [ + File(asset_basename + ".c"), + File(asset_basename + ".h"), + ] + # print( + # "dolphin_emitter OUT", + # list(n.relpath for n in target), + # list(n.relpath for n in source), + # ) return target, source @@ -107,10 +119,17 @@ assetsenv.Append( suffix=".pb.c", src_suffix=".proto", ), - "DolphinBuilder": Builder( + "DolphinSymBuilder": Builder( action=Action( '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${TARGET.dir.posix}"', - "\tDOLPHIN\t${SOURCE}", + "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", + ), + emitter=dolphin_emitter, + ), + "DolphinExtBuilder": Builder( + action=Action( + '${PYTHON3} ${ASSETS_COMPILER} dolphin "${SOURCE}" "${TARGET.dir.posix}"', + "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", ), emitter=dolphin_emitter, ), @@ -134,23 +153,19 @@ Depends(proto, proto_options) Alias("proto", proto) -dolphin_internal_src = assetsenv.GlobRecursive("*", "dolphin/internal") -dolphin_internal = assetsenv.DolphinBuilder( +dolphin_internal = assetsenv.DolphinSymBuilder( Dir("compiled"), - Dir("#/assets/dolphin/internal"), + Dir("#/assets/dolphin"), DOLPHIN_RES_TYPE="internal", ) -Depends(dolphin_internal, dolphin_internal_src) Alias("dolphin_internal", dolphin_internal) -dolphin_blocking_src = assetsenv.GlobRecursive("*", "dolphin/blocking") -dolphin_blocking = assetsenv.DolphinBuilder( +dolphin_blocking = assetsenv.DolphinSymBuilder( Dir("compiled"), - Dir("#/assets/dolphin/blocking"), + Dir("#/assets/dolphin"), DOLPHIN_RES_TYPE="blocking", ) -Depends(dolphin_blocking, dolphin_blocking_src) Alias("dolphin_blocking", dolphin_blocking) proto_ver = assetsenv.Command( diff --git a/firmware.scons b/firmware.scons index 8c24e9527b7f..b25d7a5db6aa 100644 --- a/firmware.scons +++ b/firmware.scons @@ -220,6 +220,8 @@ Alias("dfu", dfu) flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") +if fwenv["FORCE"]: + AlwaysBuild(flash) Alias("flash", flash) diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index bb9afb358a94..521f406e56e3 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -13,7 +13,7 @@ libenv = env.Clone() libenv.MergeFlags(lib_flags) # TODO: consider adding optimization flags for microtar here -sources = libenv.GlobRecursive("*.c", ".") +sources = libenv.GlobRecursive("*.c") sources += libenv.GlobRecursive("*.c", "../microtar/src") lib = libenv.StaticLibrary("toolbox", sources) diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index a9bdaede096b..91691be96e05 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -10,6 +10,7 @@ import multiprocessing vars = Variables(None, ARGUMENTS) vars.Add(BoolVariable("VERBOSE", help="Print full commands", default=0)) +vars.Add(BoolVariable("FORCE", help="Force target action", default=0)) vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) vars.Add(BoolVariable("COMPACT", help="Optimize for size", default=0)) vars.Add( @@ -118,16 +119,17 @@ env["ARCOM"] = '${TEMPFILE("' + env["ARCOM"] + '","$ARCOMSTR")}' def GlobRecursive(env, pattern, node=".", exclude=None): results = [] - for f in Glob(str(node) + "/*", source=True, exclude=exclude): - if type(f) is SCons.Node.FS.Dir: - # print(f"recursing into {f}") + if isinstance(node, str): + node = Dir(node) + for f in node.glob("*", source=True, exclude=exclude): + if isinstance(f, SCons.Node.FS.Dir): results += env.GlobRecursive(pattern, f, exclude) - current_node_str = str(node) + "/" - results += Glob( - current_node_str + pattern, + results += node.glob( + pattern, source=True, - exclude=exclude and current_node_str + exclude or exclude, + exclude=exclude, ) + # print(f"Glob for {pattern} from {node}: {results}") return results From 81395e5af101b7afc72f0a9308b180bb99f5386c Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 10 Jun 2022 14:09:08 +0400 Subject: [PATCH 078/184] UI: experimental radio stack display --- applications/about/about.c | 15 ++++---- .../desktop/views/desktop_view_debug.c | 14 ++++---- firmware/targets/f7/ble_glue/ble_glue.c | 34 +++++++++++++++++-- firmware/targets/f7/ble_glue/ble_glue.h | 2 ++ 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/applications/about/about.c b/applications/about/about.c index 92ca64eca2db..beaf3e3efa72 100644 --- a/applications/about/about.c +++ b/applications/about/about.c @@ -112,24 +112,23 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* string_t buffer; string_init(buffer); const Version* ver = furi_hal_version_get_firmware_version(); - const BleGlueC2Info* c2_ver = ble_glue_get_c2_info(); + const BleGlueC2Info* c2_ver = NULL; +#ifdef SRV_BT + c2_ver = ble_glue_get_c2_info(); +#endif if(!ver) { string_cat_printf(buffer, "No info\n"); } else { string_cat_printf( buffer, - "%s [%s]\n%s%s [%s] %d.%d.%d.%d.%d\n[%d] %s", + "%s [%s]\n%s%s [%s] %s\n[%d] %s", version_get_version(ver), version_get_builddate(ver), version_get_dirty_flag(ver) ? "[!] " : "", version_get_githash(ver), version_get_gitbranchnum(ver), - c2_ver->VersionMajor, - c2_ver->VersionMinor, - c2_ver->VersionBranch, - c2_ver->VersionSub, - c2_ver->VersionReleaseType, + c2_ver ? c2_ver->StackTypeString : "", version_get_target(ver), version_get_gitbranch(ver)); } @@ -207,4 +206,4 @@ int32_t about_settings_app(void* p) { furi_record_close("gui"); return 0; -} +} \ No newline at end of file diff --git a/applications/desktop/views/desktop_view_debug.c b/applications/desktop/views/desktop_view_debug.c index 955f523adf3c..3a6c87f13b0e 100644 --- a/applications/desktop/views/desktop_view_debug.c +++ b/applications/desktop/views/desktop_view_debug.c @@ -46,8 +46,10 @@ void desktop_debug_render(Canvas* canvas, void* model) { canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); ver = furi_hal_version_get_firmware_version(); - const BleGlueC2Info* c2_ver = ble_glue_get_c2_info(); - + const BleGlueC2Info* c2_ver = NULL; +#ifdef SRV_BT + c2_ver = ble_glue_get_c2_info(); +#endif if(!ver) { canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, "No info"); return; @@ -64,15 +66,11 @@ void desktop_debug_render(Canvas* canvas, void* model) { snprintf( buffer, sizeof(buffer), - "%s%s [%s] %d.%d.%d.%d.%d", + "%s%s [%s] %s", version_get_dirty_flag(ver) ? "[!] " : "", version_get_githash(ver), version_get_gitbranchnum(ver), - c2_ver->VersionMajor, - c2_ver->VersionMinor, - c2_ver->VersionBranch, - c2_ver->VersionSub, - c2_ver->VersionReleaseType); + c2_ver ? c2_ver->StackTypeString : ""); canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer); snprintf( diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 6a100bea2dd6..de086ea53982 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -113,13 +113,34 @@ BleGlueStatus ble_glue_get_c2_status() { return ble_glue->status; } +static const char* ble_glue_get_reltype_str(const uint8_t reltype) { + static char relcode[3] = {0}; + switch(reltype) { + case INFO_STACK_TYPE_BLE_FULL: + return "F"; + case INFO_STACK_TYPE_BLE_HCI: + return "H"; + case INFO_STACK_TYPE_BLE_LIGHT: + return "L"; + case INFO_STACK_TYPE_BLE_BEACON: + return "Ba"; + case INFO_STACK_TYPE_BLE_BASIC: + return "Be"; + case INFO_STACK_TYPE_BLE_FULL_EXT_ADV: + return "F+"; + case INFO_STACK_TYPE_BLE_HCI_EXT_ADV: + return "H+"; + default: + snprintf(relcode, sizeof(relcode), "%X", reltype); + return relcode; + } +} + static void ble_glue_update_c2_fw_info() { WirelessFwInfo_t wireless_info; SHCI_GetWirelessFwInfo(&wireless_info); BleGlueC2Info* local_info = &ble_glue->c2_info; - local_info->VersionMajor = wireless_info.VersionMajor; - local_info->VersionMinor = wireless_info.VersionMinor; local_info->VersionMajor = wireless_info.VersionMajor; local_info->VersionMinor = wireless_info.VersionMinor; local_info->VersionSub = wireless_info.VersionSub; @@ -132,6 +153,15 @@ static void ble_glue_update_c2_fw_info() { local_info->MemorySizeFlash = wireless_info.MemorySizeFlash; local_info->StackType = wireless_info.StackType; + snprintf( + local_info->StackTypeString, + BLE_GLUE_MAX_VERSION_STRING_LEN, + "%d.%d.%d.%d.%s", + local_info->VersionMajor, + local_info->VersionMinor, + local_info->VersionSub, + local_info->VersionBranch, + ble_glue_get_reltype_str(local_info->VersionReleaseType)); local_info->FusVersionMajor = wireless_info.FusVersionMajor; local_info->FusVersionMinor = wireless_info.FusVersionMinor; diff --git a/firmware/targets/f7/ble_glue/ble_glue.h b/firmware/targets/f7/ble_glue/ble_glue.h index fe43ae09d78b..bd2588a02630 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.h +++ b/firmware/targets/f7/ble_glue/ble_glue.h @@ -13,6 +13,7 @@ typedef enum { BleGlueC2ModeStack, } BleGlueC2Mode; +#define BLE_GLUE_MAX_VERSION_STRING_LEN 20 typedef struct { BleGlueC2Mode mode; /** @@ -28,6 +29,7 @@ typedef struct { uint8_t MemorySizeSram1; /*< Multiple of 1K */ uint8_t MemorySizeFlash; /*< Multiple of 4K */ uint8_t StackType; + char StackTypeString[BLE_GLUE_MAX_VERSION_STRING_LEN]; /** * Fus Info */ From 13c0635012691e76705905950ed609bab19f7b2f Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 10 Jun 2022 16:18:31 +0400 Subject: [PATCH 079/184] Scripts: enforcing Unix newlines in FFF; not using multiprocessing if Python speed-ups are available; Build: better 'resources` & `dolphin_ext' dependency processing --- assets/SConscript | 65 ++++++++++++++++++------------- scripts/flipper/assets/dolphin.py | 15 +++++-- scripts/flipper/assets/icon.py | 10 +++++ scripts/flipper/utils/fff.py | 2 +- 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/assets/SConscript b/assets/SConscript index 6d46d6ff8f1a..7831f6b8738b 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -2,6 +2,7 @@ Import("env", "lib_flags") import os import subprocess +import SCons assetsenv = env.Clone() assetsenv.MergeFlags(lib_flags) @@ -21,40 +22,42 @@ def icons_emitter(target, source, env): def proto_emitter(target, source, env): - # target = list() - # print(target[0].path, source) out_path = target[0].path - # print("out_path", out_path) target = list() for src in source: basename = os.path.splitext(src.name)[0] - # print("!! ", os.path.join("#", out_path, basename + ".pb.h")) target.append(File(basename + ".pb.c")) target.append(File(basename + ".pb.h")) - # print(list(t.path for t in target)) return target, source def dolphin_emitter(target, source, env): - fixed_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) - source = [fixed_root_dir] + res_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) + source = [res_root_dir] source.extend( - env.GlobRecursive("*.*", fixed_root_dir), + env.GlobRecursive("*.*", res_root_dir), ) + target_base_dir = target[0] + env.Replace(_DOLPHIN_OUT_DIR=target[0]) + if env["DOLPHIN_RES_TYPE"] == "external": - pass + target = [] + target.extend( + map( + lambda node: target_base_dir.File( + res_root_dir.rel_path(node).replace(".png", ".bm") + ), + filter(lambda node: isinstance(node, SCons.Node.FS.File), source), + ) + ) else: asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" target = [ - File(asset_basename + ".c"), - File(asset_basename + ".h"), + target_base_dir.File(asset_basename + ".c"), + target_base_dir.File(asset_basename + ".h"), ] - # print( - # "dolphin_emitter OUT", - # list(n.relpath for n in target), - # list(n.relpath for n in source), - # ) + return target, source @@ -121,14 +124,14 @@ assetsenv.Append( ), "DolphinSymBuilder": Builder( action=Action( - '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${TARGET.dir.posix}"', + '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", ), emitter=dolphin_emitter, ), "DolphinExtBuilder": Builder( action=Action( - '${PYTHON3} ${ASSETS_COMPILER} dolphin "${SOURCE}" "${TARGET.dir.posix}"', + '${PYTHON3} ${ASSETS_COMPILER} dolphin "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", ), emitter=dolphin_emitter, @@ -180,31 +183,37 @@ Depends(proto_ver, proto) Alias("proto_ver", proto_ver) assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) - assetsenv.Install("#/assets/compiled", assets_parts) assetslib = assetsenv.Library("assets", assets_parts) - -# sources = Glob("compiled/*.c", source=True) -# assetslib = assetsenv.Library("assets", sources) -# assetsenv.Depends( -# assetslib, (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) -# ) assetsenv.Install("${LIB_DIST_DIR}", assetslib) +# Resources for SD card + +dolphin_external = assetsenv.DolphinExtBuilder( + Dir("#/assets/resources/dolphin"), + Dir("#/assets/dolphin"), + DOLPHIN_RES_TYPE="external", +) +NoClean(dolphin_external) +if assetsenv["FORCE"]: + AlwaysBuild(dolphin_external) +Alias("dolphin_ext", dolphin_external) + -resources_src = assetsenv.GlobRecursive("*", "resources", exclude="Manifest") resources = assetsenv.Command( "#/assets/resources/Manifest", - "", + assetsenv.GlobRecursive("*", "resources", exclude="Manifest"), action=Action( '${PYTHON3} ${ASSETS_COMPILER} manifest "${TARGET.dir.posix}"', "\tRES\t${TARGET}", ), ) -Depends(resources, resources_src) +# Depends(resources, dolphin_external) Precious(resources) NoClean(resources) +if assetsenv["FORCE"]: + AlwaysBuild(resources) Alias("resources", resources) Return("assetslib") diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index b0211d29dc66..99bd8d7aefdf 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -227,12 +227,19 @@ def save(self, output_directory: str): (frame, os.path.join(animation_directory, f"frame_{index}.bm")) ) - pool = multiprocessing.Pool() - pool.map(_convert_image_to_bm, to_pack) + if ImageTools.is_processing_slow(): + pool = multiprocessing.Pool() + pool.map(_convert_image_to_bm, to_pack) + else: + for image in to_pack: + _convert_image_to_bm(image) def process(self): - pool = multiprocessing.Pool() - self.frames = pool.map(_convert_image, self.frames) + if ImageTools.is_processing_slow(): + pool = multiprocessing.Pool() + self.frames = pool.map(_convert_image, self.frames) + else: + self.frames = list(_convert_image(frame) for frame in self.frames) class DolphinManifest: diff --git a/scripts/flipper/assets/icon.py b/scripts/flipper/assets/icon.py index db56a0a90719..235af7b05ecb 100644 --- a/scripts/flipper/assets/icon.py +++ b/scripts/flipper/assets/icon.py @@ -33,6 +33,16 @@ class ImageTools: __pil_unavailable = False __hs2_unavailable = False + @staticmethod + def is_processing_slow(): + try: + from PIL import Image, ImageOps + import heatshrink2 + + return False + except ImportError as e: + return True + def __init__(self): self.logger = logging.getLogger() diff --git a/scripts/flipper/utils/fff.py b/scripts/flipper/utils/fff.py index b7f89321a56a..fa689b0168d4 100644 --- a/scripts/flipper/utils/fff.py +++ b/scripts/flipper/utils/fff.py @@ -99,5 +99,5 @@ def load(self, filename: str): self.lines = file.readlines() def save(self, filename: str): - with open(filename, "w") as file: + with open(filename, "w", newline="\n") as file: file.write("\n".join(self.lines)) From ef158fde12e9aa400e2e1a9059f193e553679a18 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 10 Jun 2022 17:05:42 +0400 Subject: [PATCH 080/184] Scripts: enforcing Unix line breaks across platforms --- scripts/assets.py | 12 ++++++++++-- scripts/flipper/assets/copro.py | 2 +- scripts/flipper/assets/dolphin.py | 2 +- scripts/flipper/assets/manifest.py | 2 +- scripts/version.py | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/scripts/assets.py b/scripts/assets.py index 1d22e1160deb..b27b29efd057 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -100,7 +100,11 @@ def _iconIsSupported(self, filename): def icons(self): self.logger.debug(f"Converting icons") - icons_c = open(os.path.join(self.args.output_directory, "assets_icons.c"), "w") + icons_c = open( + os.path.join(self.args.output_directory, "assets_icons.c"), + "w", + newline="\n", + ) icons_c.write(ICONS_TEMPLATE_C_HEADER) icons = [] # Traverse icons tree, append image data to source file @@ -186,7 +190,11 @@ def icons(self): # Create Public Header self.logger.debug(f"Creating header") - icons_h = open(os.path.join(self.args.output_directory, "assets_icons.h"), "w") + icons_h = open( + os.path.join(self.args.output_directory, "assets_icons.h"), + "w", + newline="\n", + ) icons_h.write(ICONS_TEMPLATE_H_HEADER) for name, width, height, frame_rate, frame_count in icons: icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name)) diff --git a/scripts/flipper/assets/copro.py b/scripts/flipper/assets/copro.py index f8750ec324ec..0c78e889d2e8 100644 --- a/scripts/flipper/assets/copro.py +++ b/scripts/flipper/assets/copro.py @@ -106,5 +106,5 @@ def bundle(self, output_dir, stack_file_name, stack_type, stack_addr=None): address=f"0x{stack_addr:X}", ) # Save manifest to - with open(manifest_file, "w") as file: + with open(manifest_file, "w", newline="\n") as file: json.dump(manifest, file) diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index 99bd8d7aefdf..096d31629f35 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -302,7 +302,7 @@ def load(self, source_directory: str): def _renderTemplate(self, template_filename: str, output_filename: str, **kwargs): template = Templite(filename=template_filename) output = template.render(**kwargs) - with open(output_filename, "w") as file: + with open(output_filename, "w", newline="\n") as file: file.write(output) def save2code(self, output_directory: str, symbol_name: str): diff --git a/scripts/flipper/assets/manifest.py b/scripts/flipper/assets/manifest.py index 7eba46c99164..840761d729dd 100644 --- a/scripts/flipper/assets/manifest.py +++ b/scripts/flipper/assets/manifest.py @@ -124,7 +124,7 @@ def load(self, filename): self.records.append(record) def save(self, filename): - with open(filename, "w+") as manifest: + with open(filename, "w+", newline="\n") as manifest: for record in self.records: manifest.write(record.toLine()) diff --git a/scripts/version.py b/scripts/version.py index cc717ba07587..82737a119748 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -82,7 +82,7 @@ def generate(self): if self.args.debug: print("old: ", current_version_info) print("new: ", new_version_info_fmt) - with open(self.args.output, "w") as file: + with open(self.args.output, "w", newline="\n") as file: file.write(new_version_info_fmt) # os.utime("../lib/toolbox/version.c", None) print("Version information updated") From 4c55f1a20e574e7688e6a6981f11809f59c4ae84 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 00:41:15 +0400 Subject: [PATCH 081/184] Build: virtual object dependency for version.inc.h and applications.c generators --- firmware.scons | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/firmware.scons b/firmware.scons index b25d7a5db6aa..7ce94f88318c 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,6 +1,8 @@ Import("env") import os +import subprocess +import datetime env.Append( LIB_DIST_DIR="${BUILD_DIR}/lib", @@ -81,13 +83,12 @@ fwenv.Append( Import("build_apps_c", "FlipperAppType") +# Depends on virtual value-only node, so it only gets rebuilt when set of apps changes apps_c = fwenv.Command( "applications/applications.c", - [], + Value(fwenv["APPS"]), action=build_apps_c, ) -fwenv.AlwaysBuild(apps_c) - sources = [apps_c] for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): @@ -145,17 +146,39 @@ Alias("extapps", extapps) # Git Version management +version_depends = [] +try: + version = ( + subprocess.check_output( + [ + "git", + "describe", + "--always", + "--dirty", + "--all", + "--long", + ] + ) + .strip() + .decode() + ) + version_depends = Value((version, datetime.date.today())) +except Exception as e: + print("Failed to check for git changes", e) +# Only invoke version generator if preliminary check (version_depends) triggers build_version = fwenv.Command( "#lib/toolbox/version.inc.h", - [], + version_depends, Action( "${PYTHON3} scripts/version.py generate -o ${TARGET} --dir ${ROOT_DIR}", "${VERSIONCOMSTR}", ), ) -fwenv.Precious(build_version) -fwenv.AlwaysBuild(build_version) + +if not version_depends: + fwenv.Precious(build_version) + fwenv.AlwaysBuild(build_version) # Full firmware definition From efba73e007de2254d0f723684b2491aab58d34ec Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 01:11:08 +0400 Subject: [PATCH 082/184] Build: minor cleanup + comments --- assets/SConscript | 20 +++++- core/SConscript | 8 +-- firmware.scons | 126 ++++++++++++++++++---------------- firmware/SConscript | 2 +- lib/ST25RFAL002/SConscript | 3 +- lib/appframe.scons | 1 - lib/drivers/SConscript | 3 +- lib/flipper_format/SConscript | 3 +- lib/infrared/SConscript | 3 +- lib/microtar.scons | 1 - lib/nanopb.scons | 1 - lib/subghz/SConscript | 3 +- lib/toolbox/.gitignore | 2 +- lib/toolbox/SConscript | 4 -- 14 files changed, 91 insertions(+), 89 deletions(-) delete mode 100644 lib/nanopb.scons diff --git a/assets/SConscript b/assets/SConscript index 7831f6b8738b..e5af5da02750 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -12,6 +12,8 @@ assetsenv.Append( NANOPB_COMPILER="lib/nanopb/generator/nanopb_generator.py", ) +# Setting up emitters for scripts + def icons_emitter(target, source, env): target = [ @@ -23,7 +25,7 @@ def icons_emitter(target, source, env): def proto_emitter(target, source, env): out_path = target[0].path - target = list() + target = [] for src in source: basename = os.path.splitext(src.name)[0] target.append(File(basename + ".pb.c")) @@ -139,6 +141,7 @@ assetsenv.Append( } ) +# Gathering icons sources icons_src = assetsenv.GlobRecursive("*.png", "icons") icons_src += assetsenv.GlobRecursive("frame_rate", "icons") @@ -148,6 +151,8 @@ Depends(icons, icons_src) Alias("icons", icons) +# Protobuf .proto -> .c + .h + proto_src = Glob("protobuf/*.proto", source=True) proto_options = Glob("protobuf/*.options", source=True) proto = assetsenv.ProtoBuilder(Dir("compiled"), proto_src) @@ -156,6 +161,8 @@ Depends(proto, proto_options) Alias("proto", proto) +# Internal animations + dolphin_internal = assetsenv.DolphinSymBuilder( Dir("compiled"), Dir("#/assets/dolphin"), @@ -164,6 +171,8 @@ dolphin_internal = assetsenv.DolphinSymBuilder( Alias("dolphin_internal", dolphin_internal) +# Blocking animations + dolphin_blocking = assetsenv.DolphinSymBuilder( Dir("compiled"), Dir("#/assets/dolphin"), @@ -171,6 +180,9 @@ dolphin_blocking = assetsenv.DolphinSymBuilder( ) Alias("dolphin_blocking", dolphin_blocking) + +# Protobuf version meta + proto_ver = assetsenv.Command( "protobuf_version.h", "#/assets/protobuf/Changelog", @@ -182,14 +194,18 @@ proto_ver = assetsenv.Command( Depends(proto_ver, proto) Alias("proto_ver", proto_ver) +# Gather everything into a static lib assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) assetsenv.Install("#/assets/compiled", assets_parts) assetslib = assetsenv.Library("assets", assets_parts) assetsenv.Install("${LIB_DIST_DIR}", assetslib) + # Resources for SD card +# External dolphin animations + dolphin_external = assetsenv.DolphinExtBuilder( Dir("#/assets/resources/dolphin"), Dir("#/assets/dolphin"), @@ -200,6 +216,7 @@ if assetsenv["FORCE"]: AlwaysBuild(dolphin_external) Alias("dolphin_ext", dolphin_external) +# Resources manifest resources = assetsenv.Command( "#/assets/resources/Manifest", @@ -209,7 +226,6 @@ resources = assetsenv.Command( "\tRES\t${TARGET}", ), ) -# Depends(resources, dolphin_external) Precious(resources) NoClean(resources) if assetsenv["FORCE"]: diff --git a/core/SConscript b/core/SConscript index 2dc557a70046..2c7b01490290 100644 --- a/core/SConscript +++ b/core/SConscript @@ -3,13 +3,7 @@ Import("env", "lib_flags") libenv = env.Clone() libenv.MergeFlags(lib_flags) -libenv.Append( - CPPPATH=[ - # "#/core", - ], -) - -sources = libenv.GlobRecursive("*.c", ".") +sources = libenv.GlobRecursive("*.c") lib = libenv.Library("core", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/firmware.scons b/firmware.scons index 7ce94f88318c..4841a206ab9e 100644 --- a/firmware.scons +++ b/firmware.scons @@ -4,21 +4,17 @@ import os import subprocess import datetime -env.Append( - LIB_DIST_DIR="${BUILD_DIR}/lib", -) + +# Building initial C environment for libs env.Append( + LIB_DIST_DIR="${BUILD_DIR}/lib", LIBPATH=[ "${LIB_DIST_DIR}", ], CPPDEFINES=[ ("TARGET", "${TARGET_HW}"), ], -) - - -env.Append( CPPPATH=[ "#/core", "#/applications", @@ -27,9 +23,10 @@ env.Append( "#/firmware/targets/f${TARGET_HW}/furi_hal", "#/firmware/targets/f${TARGET_HW}/Inc", "#/firmware/targets/furi_hal_include", - ] + ], ) +# Invoke child SCopscripts to populate global `env` + build their own part of the code depends = env.BuildModules( [ "lib", @@ -39,13 +36,17 @@ depends = env.BuildModules( ], ) + +# Now, env is fully set up with everything to build apps src fwenv = env.Clone() Export("fwenv") +# Set up additional app-specific build flags SConscript("sconscfg/firmwareopts.scons") +# Prepare manifest-related env methods SConscript("sconscfg/appmanifests.scons") - +# Set up app configuration if fwenv["FIRMWARE_BUILD_CFG"] == "updater": fwenv.Append( APPS=[ @@ -77,10 +78,13 @@ else: fwenv.LoadApplicationManifests() fwenv.PrepareApplicationsBuild() +# Add preprocessor definitions for current set of apps fwenv.Append( CPPDEFINES=fwenv["APPBUILD"].get_apps_cdefs(), ) +# Build applications.c for selected services & apps + Import("build_apps_c", "FlipperAppType") # Depends on virtual value-only node, so it only gets rebuilt when set of apps changes @@ -91,59 +95,12 @@ apps_c = fwenv.Command( ) sources = [apps_c] +# Gather sources only from selected app folders for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder)) - -# Building external applications - +# Clone current environment to build external apps with its current state appenv = fwenv.Clone() -appenv.VariantDir("extapps", "applications", duplicate=False) -appenv.Replace( - LINKER_SCRIPT="application-ext", - STRIPFLAGS=[ - "--strip-debug", - "--strip-unneeded", - "-d", - "-g", - "-S", - ], -) -appenv.Append( - CCFLAGS=[ - "-Os", - "-ggdb3", - "-mword-relocations", - "-mlong-calls", - "-fno-common", - "-nostdlib", - "-fvisibility=hidden", - ], - LINKFLAGS=[ - "-r", - "-s", - # "-Bsymbolic", - "-nostartfiles", - "-mlong-calls", - "-fno-common", - "-nostdlib", - "-Wl,--gc-sections", - "-Wl,--no-export-dynamic", - "-fvisibility=hidden", - "-Wl,-e${APP_ENTRY}", - ], -) - -extapps = [] -for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): - app_elf = appenv.Program( - os.path.join("extapps", app.appid), - appenv.GlobRecursive("*.c*", os.path.join("extapps", app._appdir)), - APP_ENTRY=app.entry_point, - ) - extapps.append(appenv.ELFStripper(app.appid, app_elf)) -Alias("extapps", extapps) - # Git Version management version_depends = [] @@ -180,7 +137,6 @@ if not version_depends: fwenv.Precious(build_version) fwenv.AlwaysBuild(build_version) - # Full firmware definition fwenv.Append( @@ -241,7 +197,7 @@ dfu = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") Default(dfu) Alias("dfu", dfu) - +# Additional FW-related pseudotargets flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") if fwenv["FORCE"]: AlwaysBuild(flash) @@ -251,4 +207,52 @@ Alias("flash", flash) # Compile DB generation cdb = fwenv.CompilationDatabase("compile_database.json") Alias("cdb", cdb) -# Depends(firmware_elf, cdb) + + +# Building external applications + +appenv.VariantDir("extapps", "applications", duplicate=False) +appenv.Replace( + LINKER_SCRIPT="application-ext", + STRIPFLAGS=[ + "--strip-debug", + "--strip-unneeded", + "-d", + "-g", + "-S", + ], +) +appenv.Append( + CCFLAGS=[ + "-Os", + "-ggdb3", + "-mword-relocations", + "-mlong-calls", + "-fno-common", + "-nostdlib", + "-fvisibility=hidden", + ], + LINKFLAGS=[ + "-r", + "-s", + # "-Bsymbolic", + "-nostartfiles", + "-mlong-calls", + "-fno-common", + "-nostdlib", + "-Wl,--gc-sections", + "-Wl,--no-export-dynamic", + "-fvisibility=hidden", + "-Wl,-e${APP_ENTRY}", + ], +) + +extapps = [] +for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): + app_elf = appenv.Program( + os.path.join("extapps", app.appid), + appenv.GlobRecursive("*.c*", os.path.join("extapps", app._appdir)), + APP_ENTRY=app.entry_point, + ) + extapps.append(appenv.ELFStripper(app.appid, app_elf)) +Alias("extapps", extapps) diff --git a/firmware/SConscript b/firmware/SConscript index 32d587b844b7..fea3149427cf 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -10,7 +10,7 @@ libenv.Append( ) sources = ["targets/f${TARGET_HW}/startup_stm32wb55xx_cm4.s"] -sources += libenv.GlobRecursive("*.c", ".") +sources += libenv.GlobRecursive("*.c") lib = libenv.Library("flipper${TARGET_HW}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/ST25RFAL002/SConscript b/lib/ST25RFAL002/SConscript index 39d8728bb27f..c1c00254b7c3 100644 --- a/lib/ST25RFAL002/SConscript +++ b/lib/ST25RFAL002/SConscript @@ -6,14 +6,13 @@ env.Append( "#/lib/ST25RFAL002/include", "#/lib/ST25RFAL002/source/st25r3916", ], - CPPDEFINES=[], ) libenv = env.Clone() libenv.MergeFlags(lib_flags) -sources = libenv.GlobRecursive("*.c", ".") +sources = libenv.GlobRecursive("*.c") lib = libenv.StaticLibrary("st25rfal002", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/appframe.scons b/lib/appframe.scons index e76d4c11125d..745f55aa4fc5 100644 --- a/lib/appframe.scons +++ b/lib/appframe.scons @@ -6,7 +6,6 @@ env.Append( "#/lib/callback-connector", "#/assets/compiled", ], - CPPDEFINES=[], ) diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript index 12450163f3bd..de20a7c65e76 100644 --- a/lib/drivers/SConscript +++ b/lib/drivers/SConscript @@ -4,14 +4,13 @@ env.Append( CPPPATH=[ "#/lib/drivers", ], - CPPDEFINES=[], ) libenv = env.Clone() libenv.MergeFlags(lib_flags) -sources = Glob("*.c", source=True) # libenv.GlobRecursive("*.c", ".") +sources = Glob("*.c", source=True) lib = libenv.StaticLibrary("hwdrivers", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript index 788feae7f6ca..6513d8245b0e 100644 --- a/lib/flipper_format/SConscript +++ b/lib/flipper_format/SConscript @@ -4,7 +4,6 @@ env.Append( CPPPATH=[ "#/lib/flipper_format", ], - CPPDEFINES=[], ) @@ -19,7 +18,7 @@ if libenv["RAM_EXEC"]: ) -sources = libenv.GlobRecursive("*.c", ".") +sources = libenv.GlobRecursive("*.c") lib = libenv.StaticLibrary("flipperformat", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/infrared/SConscript b/lib/infrared/SConscript index 9200638f6f94..b8169d97586e 100644 --- a/lib/infrared/SConscript +++ b/lib/infrared/SConscript @@ -5,14 +5,13 @@ env.Append( "#/lib/infrared/encoder_decoder", "#/lib/infrared/worker", ], - CPPDEFINES=[], ) libenv = env.Clone() libenv.MergeFlags(lib_flags) -sources = libenv.GlobRecursive("*.c", ".") +sources = libenv.GlobRecursive("*.c") lib = libenv.StaticLibrary("infrared", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/microtar.scons b/lib/microtar.scons index 10d378cd0d50..05b351774048 100644 --- a/lib/microtar.scons +++ b/lib/microtar.scons @@ -4,7 +4,6 @@ env.Append( CPPPATH=[ "#/lib/microtar/src", ], - CPPDEFINES=[], ) diff --git a/lib/nanopb.scons b/lib/nanopb.scons deleted file mode 100644 index 1ad04d93fa76..000000000000 --- a/lib/nanopb.scons +++ /dev/null @@ -1 +0,0 @@ -Import("env") diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 81502c5f3abb..1337af40427f 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -4,13 +4,12 @@ env.Append( CPPPATH=[ "#/lib/subghz", ], - CPPDEFINES=[], ) libenv = env.Clone() libenv.MergeFlags(lib_flags) -sources = libenv.GlobRecursive("*.c*", ".") +sources = libenv.GlobRecursive("*.c*") lib = libenv.StaticLibrary("subghz", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/toolbox/.gitignore b/lib/toolbox/.gitignore index 411cd0e721f2..912c1405c7de 100644 --- a/lib/toolbox/.gitignore +++ b/lib/toolbox/.gitignore @@ -1 +1 @@ -version.inc.h \ No newline at end of file +version.inc.h diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 521f406e56e3..c10738af6750 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -2,19 +2,15 @@ Import("env", "lib_flags") env.Append( CPPPATH=[ - "#/lib/microtar/src", "#/lib/toolbox", ], - CPPDEFINES=[], ) libenv = env.Clone() libenv.MergeFlags(lib_flags) -# TODO: consider adding optimization flags for microtar here sources = libenv.GlobRecursive("*.c") -sources += libenv.GlobRecursive("*.c", "../microtar/src") lib = libenv.StaticLibrary("toolbox", sources) libenv.Install("${LIB_DIST_DIR}", lib) From 069bc487137ecfdce89e9d5fa86eb11fc19ab396 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 15:42:50 +0400 Subject: [PATCH 083/184] Build: * reworked firmware/updater target aliases * moved version generation to toolbox/SConscript; version header is now built in variant dir * added updater to SConstruct * added default options for scons on ./fbt invocation * added --with-updater scons option to include updater-related target & env processing on-demand only (to speed up base firmware build startup) Scripts: updated requirements.txt --- SConstruct | 54 +++++++++++++++--------- assets/SConscript | 57 ++++++++++++------------- fbt | 3 +- fbt.cmd | 4 +- firmware.scons | 84 ++++++++++++++++--------------------- lib/toolbox/SConscript | 41 ++++++++++++++++++ sconscfg/appmanifests.scons | 18 +++++--- sconscfg/builders.scons | 6 +-- sconscfg/cc.scons | 14 ++----- sconscfg/environ.scons | 50 ++++++++++------------ scripts/requirements.txt | 6 ++- 11 files changed, 192 insertions(+), 145 deletions(-) diff --git a/SConstruct b/SConstruct index 736886428119..d1d17088ded6 100644 --- a/SConstruct +++ b/SConstruct @@ -1,37 +1,53 @@ import os +AddOption( + "--with-updater", + dest="fullenv", + action="store_true", + help="Full firmware environment", +) + SConscript("sconscfg/environ.scons") SConscript("sconscfg/cc.scons") SConscript("sconscfg/builders.scons") -Import("env") - -if env["RAM_EXEC"]: - env.Append( - FIRMWARE_BUILD_CFG="updater", - ) -else: - env.Append( - FIRMWARE_BUILD_CFG="firmware", - ) +Import("coreenv") # Progress(["-\r", "\\\r", "|\r", "/\r"], interval=5) -variant_dir_name = f"f{env.subst('$TARGET_HW')}-{env.subst('$FIRMWARE_BUILD_CFG')}" +variant_dir_name = f"f{coreenv.subst('$TARGET_HW')}-FWTYPE" suffix = "" -if env["DEBUG"]: +if coreenv["DEBUG"]: suffix += "D" -if env["COMPACT"]: +if coreenv["COMPACT"]: suffix += "C" if suffix: variant_dir_name += "-" + suffix -root_path = Dir(".").abspath -env["ROOT_DIR"] = root_path -build_path = os.path.join(root_path, "build", variant_dir_name) -env["BUILD_DIR"] = build_path +coreenv["ROOT_DIR"] = Dir(".") +build_path = os.path.join(Dir(".").abspath, "build", variant_dir_name) -SConscript( +firmware = SConscript( "firmware.scons", - variant_dir=build_path, + variant_dir=build_path.replace("FWTYPE", "firmware"), duplicate=0, + exports={ + "fw_build_meta": { + "type": "firmware", + "build_dir": build_path.replace("FWTYPE", "firmware"), + }, + }, ) +Default(firmware) + +if GetOption("fullenv"): + updater = SConscript( + "firmware.scons", + variant_dir=build_path.replace("FWTYPE", "updater"), + duplicate=0, + exports={ + "fw_build_meta": { + "type": "updater", + "build_dir": build_path.replace("FWTYPE", "updater"), + }, + }, + ) diff --git a/assets/SConscript b/assets/SConscript index e5af5da02750..21a90a3b2807 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -196,7 +196,8 @@ Alias("proto_ver", proto_ver) # Gather everything into a static lib assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) -assetsenv.Install("#/assets/compiled", assets_parts) +if assetsenv["FIRMWARE_BUILD_CFG"] != "updater": + assetsenv.Install("#/assets/compiled", assets_parts) assetslib = assetsenv.Library("assets", assets_parts) assetsenv.Install("${LIB_DIST_DIR}", assetslib) @@ -204,32 +205,32 @@ assetsenv.Install("${LIB_DIST_DIR}", assetslib) # Resources for SD card -# External dolphin animations - -dolphin_external = assetsenv.DolphinExtBuilder( - Dir("#/assets/resources/dolphin"), - Dir("#/assets/dolphin"), - DOLPHIN_RES_TYPE="external", -) -NoClean(dolphin_external) -if assetsenv["FORCE"]: - AlwaysBuild(dolphin_external) -Alias("dolphin_ext", dolphin_external) - -# Resources manifest - -resources = assetsenv.Command( - "#/assets/resources/Manifest", - assetsenv.GlobRecursive("*", "resources", exclude="Manifest"), - action=Action( - '${PYTHON3} ${ASSETS_COMPILER} manifest "${TARGET.dir.posix}"', - "\tRES\t${TARGET}", - ), -) -Precious(resources) -NoClean(resources) -if assetsenv["FORCE"]: - AlwaysBuild(resources) -Alias("resources", resources) +if assetsenv["FIRMWARE_BUILD_CFG"] != "updater": + # External dolphin animations + dolphin_external = assetsenv.DolphinExtBuilder( + Dir("#/assets/resources/dolphin"), + Dir("#/assets/dolphin"), + DOLPHIN_RES_TYPE="external", + ) + NoClean(dolphin_external) + if assetsenv["FORCE"]: + AlwaysBuild(dolphin_external) + Alias("dolphin_ext", dolphin_external) + + # Resources manifest + + resources = assetsenv.Command( + "#/assets/resources/Manifest", + assetsenv.GlobRecursive("*", "resources", exclude="Manifest"), + action=Action( + '${PYTHON3} ${ASSETS_COMPILER} manifest "${TARGET.dir.posix}"', + "\tRES\t${TARGET}", + ), + ) + Precious(resources) + NoClean(resources) + if assetsenv["FORCE"]: + AlwaysBuild(resources) + Alias("resources", resources) Return("assetslib") diff --git a/fbt b/fbt index ba167dd638f1..9ab37fe61aff 100755 --- a/fbt +++ b/fbt @@ -2,4 +2,5 @@ set +x -/usr/bin/env python3 lib/scons/scripts/scons.py "$@" +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" +/usr/bin/env python3 lib/scons/scripts/scons.py ${SCONS_DEFAULT_FLAGS} "$@" diff --git a/fbt.cmd b/fbt.cmd index 3cee132f2fae..95e72a8a5dc8 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -1 +1,3 @@ -@python lib/scons/scripts/scons.py %* +@echo off +set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" +python lib/scons/scripts/scons.py %SCONS_DEFAULT_FLAGS% %* diff --git a/firmware.scons b/firmware.scons index 4841a206ab9e..58a5891b0ffc 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,13 +1,14 @@ -Import("env") +Import("coreenv", "fw_build_meta") import os -import subprocess -import datetime # Building initial C environment for libs +env = coreenv.Clone() +Export("env") env.Append( + BUILD_DIR=fw_build_meta["build_dir"], LIB_DIST_DIR="${BUILD_DIR}/lib", LIBPATH=[ "${LIB_DIST_DIR}", @@ -26,6 +27,22 @@ env.Append( ], ) +if fw_build_meta["type"] == "updater": + env.Append( + FIRMWARE_BUILD_CFG="updater", + RAM_EXEC=True, + CPPDEFINES=[ + "FURI_RAM_EXEC", + ], + ) +else: + env.Append( + FIRMWARE_BUILD_CFG="firmware", + RAM_EXEC=False, + ) +# print(env.Dump()) + + # Invoke child SCopscripts to populate global `env` + build their own part of the code depends = env.BuildModules( [ @@ -47,7 +64,7 @@ SConscript("sconscfg/firmwareopts.scons") SConscript("sconscfg/appmanifests.scons") # Set up app configuration -if fwenv["FIRMWARE_BUILD_CFG"] == "updater": +if env["FIRMWARE_BUILD_CFG"] == "updater": fwenv.Append( APPS=[ "updater", @@ -95,50 +112,13 @@ apps_c = fwenv.Command( ) sources = [apps_c] -# Gather sources only from selected app folders +# Gather sources only from app folders from current configuration for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder)) -# Clone current environment to build external apps with its current state +# Clone current environment to build external apps later with its current state appenv = fwenv.Clone() -# Git Version management -version_depends = [] -try: - version = ( - subprocess.check_output( - [ - "git", - "describe", - "--always", - "--dirty", - "--all", - "--long", - ] - ) - .strip() - .decode() - ) - version_depends = Value((version, datetime.date.today())) -except Exception as e: - print("Failed to check for git changes", e) - -# Only invoke version generator if preliminary check (version_depends) triggers -build_version = fwenv.Command( - "#lib/toolbox/version.inc.h", - version_depends, - Action( - "${PYTHON3} scripts/version.py generate -o ${TARGET} --dir ${ROOT_DIR}", - "${VERSIONCOMSTR}", - ), -) - -if not version_depends: - fwenv.Precious(build_version) - fwenv.AlwaysBuild(build_version) - -# Full firmware definition - fwenv.Append( LINKFLAGS=[ "-specs=nano.specs", @@ -161,6 +141,8 @@ fwenv.Append( # Debug # print(fwenv.Dump()) +# Full firmware definition + firmware_elf = fwenv.Program( "${FIRMWARE_BUILD_CFG}", sources, @@ -188,25 +170,28 @@ firmware_elf = fwenv.Program( ], ) +AddPreAction(firmware_elf, fwenv["APPBUILD_DUMP"]) + +# Make it depend on everything child builders returned Depends(firmware_elf, depends) fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") dfu = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") -Default(dfu) -Alias("dfu", dfu) +# Default(dfu) +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", dfu) # Additional FW-related pseudotargets flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") if fwenv["FORCE"]: AlwaysBuild(flash) -Alias("flash", flash) +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) # Compile DB generation cdb = fwenv.CompilationDatabase("compile_database.json") -Alias("cdb", cdb) +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", cdb) # Building external applications @@ -255,4 +240,7 @@ for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): APP_ENTRY=app.entry_point, ) extapps.append(appenv.ELFStripper(app.appid, app_elf)) -Alias("extapps", extapps) +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) + + +Return("dfu") diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index c10738af6750..fb0980f5db59 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -1,5 +1,8 @@ Import("env", "lib_flags") +import subprocess +import datetime + env.Append( CPPPATH=[ "#/lib/toolbox", @@ -10,8 +13,46 @@ env.Append( libenv = env.Clone() libenv.MergeFlags(lib_flags) +# Git Version management +version_depends = [] +try: + version = ( + subprocess.check_output( + [ + "git", + "describe", + "--always", + "--dirty", + "--all", + "--long", + ] + ) + .strip() + .decode() + ) + version_depends = Value((version, datetime.date.today())) + # print(version_depends) +except Exception as e: + print("Failed to check for git changes", e) + +# Only invoke version generator if preliminary check target (version_depends) has changed +build_version = libenv.Command( + "version.inc.h", + version_depends, + Action( + "${PYTHON3} ${ROOT_DIR.abspath}/scripts/version.py generate -o ${TARGET} --dir ${ROOT_DIR}", + "${VERSIONCOMSTR}", + ), +) + +if not version_depends: + libenv.Precious(build_version) + libenv.AlwaysBuild(build_version) + sources = libenv.GlobRecursive("*.c") +libenv.Append(CPPPATH=["."]) + lib = libenv.StaticLibrary("toolbox", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index 78aa096c8975..db63391a9b5d 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -241,21 +241,27 @@ def LoadApplicationManifests(env): if isinstance(entry, SCons.Node.FS.Dir): appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) - print(f"Loaded {len(appmgr.known_apps)} app definitions.") + # -def PrepareApplicationsBuild(env): - apps = fwenv["APPS"] - apps_buildlist = fwenv["APPBUILD"] = fwenv["APPMGR"].filter_apps(apps) +def DumpApplicationConfig(target, source, env): + print(f"Loaded {len(env["APPMGR"].known_apps)} app definitions.") print("Firmware modules configuration:") for apptype in FlipperAppType: - app_sublist = apps_buildlist.get_apps_of_type(apptype) + app_sublist = env["APPBUILD"].get_apps_of_type(apptype) if app_sublist: print( f"{apptype.value}:\n\t", ", ".join(app.appid for app in app_sublist), ) - # print("CDefs", apps_buildlist.get_apps_cdefs()) + + +def PrepareApplicationsBuild(env): + fwenv["APPBUILD"] = fwenv["APPMGR"].filter_apps(fwenv["APPS"]) + fwenv["APPBUILD_DUMP"] = Action( + DumpApplicationConfig, + "\tINFO\t", + ) fwenv.AddMethod(LoadApplicationManifests) diff --git a/sconscfg/builders.scons b/sconscfg/builders.scons index 128f3eea0722..b0de50208dc2 100644 --- a/sconscfg/builders.scons +++ b/sconscfg/builders.scons @@ -1,7 +1,7 @@ -Import("env") +Import("coreenv") -env.Append( +coreenv.Append( BUILDERS={ "HEXBuilder": Builder( action=Action( @@ -29,7 +29,7 @@ env.Append( ), "ELFStripper": Builder( action=Action( - env["STRIPCOM"], + coreenv["STRIPCOM"], "\tSTRIP\t${TARGET}", ), suffix=".elf", diff --git a/sconscfg/cc.scons b/sconscfg/cc.scons index e9c201a12381..6bdbe168de04 100644 --- a/sconscfg/cc.scons +++ b/sconscfg/cc.scons @@ -1,7 +1,7 @@ -Import("env") +Import("coreenv") -env.Append( +coreenv.Append( CFLAGS=[ "-std=gnu17", ], @@ -17,7 +17,7 @@ env.Append( "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", "-mthumb", - "-MMD", + # "-MMD", # "-MP", "-Wall", "-Wextra", @@ -51,14 +51,8 @@ lib_flags = { ], "CPPDEFINES": [ "NDEBUG", + "FURI_NDEBUG", ], } -if env["RAM_EXEC"]: - env.Append( - CPPDEFINES=[ - "FURI_RAM_EXEC", - ] - ) - Export("lib_flags") diff --git a/sconscfg/environ.scons b/sconscfg/environ.scons index 91691be96e05..519e0b47ee15 100644 --- a/sconscfg/environ.scons +++ b/sconscfg/environ.scons @@ -23,12 +23,9 @@ vars.Add( ], ) ) -vars.Add( - BoolVariable("RAM_EXEC", help="Build updater image for RAM exection", default=0) -) -env = Environment( +coreenv = Environment( variables=vars, tools=["as", "gcc", "g++", "ar", "gnulink", "python", "compilation_db"], OBJCOPY="objcopy", @@ -45,8 +42,8 @@ env = Environment( }, ) -if not env["VERBOSE"]: - env.Replace( +if not coreenv["VERBOSE"]: + coreenv.Replace( CCCOMSTR="\tCC\t${SOURCE}", CXXCOMSTR="\tCPP\t${SOURCE}", ASCOMSTR="\tASM\t${SOURCE}", @@ -59,20 +56,20 @@ if not env["VERBOSE"]: # STRIPCOMSTR="\tSTRIP\t${TARGET}", ) -if env["PLATFORM"] == "win32": +if coreenv["PLATFORM"] == "win32": # On Windows, Python 3 executable is usually just "python" - env["PYTHON3"] = env["PYTHON3"][:-1] + coreenv["PYTHON3"] = coreenv["PYTHON3"][:-1] -Help(vars.GenerateHelpText(env)) +Help(vars.GenerateHelpText(coreenv)) -# Default value for -j +# Default value for commandline options SetOption("num_jobs", multiprocessing.cpu_count()) SetOption("implicit_cache", True) -# SetOption("implicit_deps_unchanged", True) +SetOption("implicit_deps_unchanged", True) SetOption("max_drift", 1) -# env.Decider("content-timestamp") +# coreenv.Decider("content-timestamp") # Setting up temp file parameters @@ -82,13 +79,13 @@ WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") def tempfile_arg_esc_func(arg): arg = quote_spaces(arg) - if env["PLATFORM"] != "win32": + if coreenv["PLATFORM"] != "win32": return arg # GCC requires double Windows slashes, let's use UNIX separator return WINPATHSEP_RE.sub(r"/\1", arg) -env["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func +coreenv["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func # Set up cross-compile tools @@ -104,14 +101,14 @@ for binary in [ "RANLIB", "STRIP", ]: - if binary in env: - env[binary] = TOOLCHAIN_PREFIX + env[binary] + if binary in coreenv: + coreenv[binary] = TOOLCHAIN_PREFIX + coreenv[binary] # Commandline length limit hack -env["LINKCOM"] = '${TEMPFILE("' + env["LINKCOM"] + '","$LINKCOMSTR")}' -env["ARCOM"] = '${TEMPFILE("' + env["ARCOM"] + '","$ARCOMSTR")}' +coreenv["LINKCOM"] = '${TEMPFILE("' + coreenv["LINKCOM"] + '","$LINKCOMSTR")}' +coreenv["ARCOM"] = '${TEMPFILE("' + coreenv["ARCOM"] + '","$ARCOMSTR")}' # Build env extensions @@ -123,7 +120,7 @@ def GlobRecursive(env, pattern, node=".", exclude=None): node = Dir(node) for f in node.glob("*", source=True, exclude=exclude): if isinstance(f, SCons.Node.FS.Dir): - results += env.GlobRecursive(pattern, f, exclude) + results += coreenv.GlobRecursive(pattern, f, exclude) results += node.glob( pattern, source=True, @@ -146,7 +143,7 @@ def BuildModule(env, module): return env.SConscript( module_sconscript, - variant_dir=env["BUILD_DIR"] + "/" + module, + variant_dir=os.path.join(env["BUILD_DIR"], module), duplicate=0, ) @@ -158,15 +155,12 @@ def BuildModules(env, modules): # print("module ", module, build_res) if build_res is None: continue - elif isinstance(build_res, list): - result.extend(build_res) - else: - result.append(build_res[0]) # ??? + result.append(build_res) return result -env.AddMethod(GlobRecursive) -env.AddMethod(BuildModule) -env.AddMethod(BuildModules) +coreenv.AddMethod(GlobRecursive) +coreenv.AddMethod(BuildModule) +coreenv.AddMethod(BuildModules) -Export("env") +Export("coreenv") diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 6f3368595207..410537c6ec82 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1 +1,5 @@ -pyserial >= 3.5 +pyserial==3.5 +heatshrink2==0.11.0 +Pillow==9.1.1 +protobuf==3.19.4 +python3-protobuf==2.5.0 From b151423de70f91f6b93e024ec28f92a882076c9a Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 15:48:46 +0400 Subject: [PATCH 084/184] Typo fix --- sconscfg/appmanifests.scons | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sconscfg/appmanifests.scons b/sconscfg/appmanifests.scons index db63391a9b5d..f69d2723c1fe 100644 --- a/sconscfg/appmanifests.scons +++ b/sconscfg/appmanifests.scons @@ -241,11 +241,9 @@ def LoadApplicationManifests(env): if isinstance(entry, SCons.Node.FS.Dir): appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) - # - def DumpApplicationConfig(target, source, env): - print(f"Loaded {len(env["APPMGR"].known_apps)} app definitions.") + print(f"Loaded {len(env['APPMGR'].known_apps)} app definitions.") print("Firmware modules configuration:") for apptype in FlipperAppType: app_sublist = env["APPBUILD"].get_apps_of_type(apptype) From b793a58972f61a2cc96af25aa390da3e1a8c7f13 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 16:06:31 +0400 Subject: [PATCH 085/184] Build: moved sconscfg->site_scons --- SConstruct | 6 +++--- firmware.scons | 12 ++++++------ {sconscfg => site_scons}/appmanifests.scons | 3 +-- {sconscfg => site_scons}/builders.scons | 0 {sconscfg => site_scons}/cc.scons | 0 {sconscfg => site_scons}/environ.scons | 0 {sconscfg => site_scons}/firmwareopts.scons | 0 7 files changed, 10 insertions(+), 11 deletions(-) rename {sconscfg => site_scons}/appmanifests.scons (99%) rename {sconscfg => site_scons}/builders.scons (100%) rename {sconscfg => site_scons}/cc.scons (100%) rename {sconscfg => site_scons}/environ.scons (100%) rename {sconscfg => site_scons}/firmwareopts.scons (100%) diff --git a/SConstruct b/SConstruct index d1d17088ded6..04030f6523cf 100644 --- a/SConstruct +++ b/SConstruct @@ -7,9 +7,9 @@ AddOption( help="Full firmware environment", ) -SConscript("sconscfg/environ.scons") -SConscript("sconscfg/cc.scons") -SConscript("sconscfg/builders.scons") +SConscript("site_scons/environ.scons") +SConscript("site_scons/cc.scons") +SConscript("site_scons/builders.scons") Import("coreenv") diff --git a/firmware.scons b/firmware.scons index 58a5891b0ffc..3f2e7a946bae 100644 --- a/firmware.scons +++ b/firmware.scons @@ -59,9 +59,9 @@ fwenv = env.Clone() Export("fwenv") # Set up additional app-specific build flags -SConscript("sconscfg/firmwareopts.scons") +SConscript("site_scons/firmwareopts.scons") # Prepare manifest-related env methods -SConscript("sconscfg/appmanifests.scons") +SConscript("site_scons/appmanifests.scons") # Set up app configuration if env["FIRMWARE_BUILD_CFG"] == "updater": @@ -102,14 +102,16 @@ fwenv.Append( # Build applications.c for selected services & apps -Import("build_apps_c", "FlipperAppType") +Import("FlipperAppType") # Depends on virtual value-only node, so it only gets rebuilt when set of apps changes apps_c = fwenv.Command( "applications/applications.c", Value(fwenv["APPS"]), - action=build_apps_c, + action=fwenv["APPS_C_ACTION"], ) +AddPreAction(apps_c, fwenv["APPBUILD_DUMP"]) + sources = [apps_c] # Gather sources only from app folders from current configuration @@ -170,8 +172,6 @@ firmware_elf = fwenv.Program( ], ) -AddPreAction(firmware_elf, fwenv["APPBUILD_DUMP"]) - # Make it depend on everything child builders returned Depends(firmware_elf, depends) diff --git a/sconscfg/appmanifests.scons b/site_scons/appmanifests.scons similarity index 99% rename from sconscfg/appmanifests.scons rename to site_scons/appmanifests.scons index f69d2723c1fe..ee3a748de899 100644 --- a/sconscfg/appmanifests.scons +++ b/site_scons/appmanifests.scons @@ -274,5 +274,4 @@ def build_apps_c(target, source, env): file.write(gen.generate()) -build_apps_c = Action(build_apps_c, "${APPSCOMSTR}") -Export("build_apps_c") +fwenv["APPS_C_ACTION"] = Action(build_apps_c, "${APPSCOMSTR}") diff --git a/sconscfg/builders.scons b/site_scons/builders.scons similarity index 100% rename from sconscfg/builders.scons rename to site_scons/builders.scons diff --git a/sconscfg/cc.scons b/site_scons/cc.scons similarity index 100% rename from sconscfg/cc.scons rename to site_scons/cc.scons diff --git a/sconscfg/environ.scons b/site_scons/environ.scons similarity index 100% rename from sconscfg/environ.scons rename to site_scons/environ.scons diff --git a/sconscfg/firmwareopts.scons b/site_scons/firmwareopts.scons similarity index 100% rename from sconscfg/firmwareopts.scons rename to site_scons/firmwareopts.scons From 96e3678b3b677807d4c8610d862db53686245a99 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 16:20:15 +0400 Subject: [PATCH 086/184] Build: moved app manifest-related code to site_scons --- firmware.scons | 4 +- site_scons/appmanifests.scons | 233 +-------------------------------- site_scons/fbt/__init__.py | 0 site_scons/fbt/appmanifest.py | 239 ++++++++++++++++++++++++++++++++++ site_scons/site_init.py | 4 + 5 files changed, 246 insertions(+), 234 deletions(-) create mode 100644 site_scons/fbt/__init__.py create mode 100644 site_scons/fbt/appmanifest.py create mode 100644 site_scons/site_init.py diff --git a/firmware.scons b/firmware.scons index 3f2e7a946bae..be3fd533bd74 100644 --- a/firmware.scons +++ b/firmware.scons @@ -2,6 +2,7 @@ Import("coreenv", "fw_build_meta") import os +from fbt.appmanifest import FlipperAppType # Building initial C environment for libs env = coreenv.Clone() @@ -100,9 +101,8 @@ fwenv.Append( CPPDEFINES=fwenv["APPBUILD"].get_apps_cdefs(), ) -# Build applications.c for selected services & apps -Import("FlipperAppType") +# Build applications.c for selected services & apps # Depends on virtual value-only node, so it only gets rebuilt when set of apps changes apps_c = fwenv.Command( diff --git a/site_scons/appmanifests.scons b/site_scons/appmanifests.scons index ee3a748de899..c13dfa5a3de2 100644 --- a/site_scons/appmanifests.scons +++ b/site_scons/appmanifests.scons @@ -1,238 +1,7 @@ Import("fwenv") -from dataclasses import dataclass, field -from typing import List, Set, Dict, Tuple, Optional -from enum import Enum -import os import SCons - - -class FlipperAppType(Enum): - SERVICE = "Service" - SYSTEM = "System" - APP = "App" - PLUGIN = "Plugin" - DEBUG = "Debug" - ARCHIVE = "Archive" - SETTINGS = "Settings" - STARTUP = "StartupHook" - EXTERNAL = "External" - METAPACKAGE = "Package" - - -Export("FlipperAppType") - - -@dataclass -class FlipperApplication: - appid: str - apptype: FlipperAppType - name: Optional[str] = None - entry_point: Optional[str] = None - flags: List[str] = field(default_factory=lambda: ["Default"]) - cdefines: List[str] = field(default_factory=list) - requires: List[str] = field(default_factory=list) - conflicts: List[str] = field(default_factory=list) - provides: List[str] = field(default_factory=list) - stack_size: int = 2048 - icon: Optional[str] = None - order: int = 0 - _appdir: Optional[str] = None - - -class AppManager: - def __init__(self): - self.known_apps = {} - - def get(self, appname: str): - try: - return self.known_apps[appname] - except KeyError as _: - raise Exception(f"Missing application manifest for '{appname}'") - - def load_manifest(self, app_manifest_path: str, app_dir_name: str): - if not os.path.exists(app_manifest_path): - raise Exception(f"App manifest not found at path {app_manifest_path}") - # print("Loading", app_manifest_path) - - app_manifests = [] - - def App(*args, **kw): - nonlocal app_manifests - app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name)) - - with open(app_manifest_path, "rt") as manifest_file: - exec(manifest_file.read()) - - if len(app_manifests) == 0: - Exit(f"App manifest '{app_manifest_path}' is malformed") - - # print("Built", app_manifests) - for app in app_manifests: - self._add_known_app(app) - - def _add_known_app(self, app: FlipperApplication): - if self.known_apps.get(app.appid, None): - raise Exception(f"Duplicate app declaration: {app.appid}") - self.known_apps[app.appid] = app - - def filter_apps(self, applist: List[str]): - return AppBuildset(self, applist) - - -class AppBuildset: - BUILTIN_APP_TYPES = ( - FlipperAppType.SERVICE, - FlipperAppType.SYSTEM, - FlipperAppType.APP, - FlipperAppType.PLUGIN, - FlipperAppType.DEBUG, - FlipperAppType.ARCHIVE, - FlipperAppType.SETTINGS, - FlipperAppType.STARTUP, - ) - - def __init__(self, appmgr: AppManager, appnames: List[str]): - self.appmgr = appmgr - self.appnames = set(appnames) - self._orig_appnames = appnames - self._process_deps() - self._check_conflicts() - self._check_unsatisfied() # unneeded? - self.apps = sorted( - list(map(self.appmgr.get, self.appnames)), - key=lambda app: app.appid, - ) - - def _is_missing_dep(self, dep_name: str): - return dep_name not in self.appnames - - def _process_deps(self): - while True: - provided = [] - for app in self.appnames: - # print(app) - provided.extend( - filter( - self._is_missing_dep, - self.appmgr.get(app).provides + self.appmgr.get(app).requires, - ) - ) - # print("provides round", provided) - if len(provided) == 0: - break - self.appnames.update(provided) - - def _check_conflicts(self): - conflicts = [] - for app in self.appnames: - # print(app) - if conflict_app_name := list( - filter( - lambda dep_name: dep_name in self.appnames, - self.appmgr.get(app).conflicts, - ) - ): - conflicts.append((app, conflict_app_name)) - - if len(conflicts): - raise Exception( - f"App conflicts for {', '.join(f'{conflict_dep[0]}: {conflict_dep[1]}' for conflict_dep in conflicts)}" - ) - - def _check_unsatisfied(self): - unsatisfied = [] - for app in self.appnames: - if missing_dep := list( - filter(self._is_missing_dep, self.appmgr.get(app).requires) - ): - unsatisfied.append((app, missing_dep)) - - if len(unsatisfied): - raise Exception( - f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" - ) - - def get_apps_cdefs(self): - cdefs = set() - for app in self.apps: - cdefs.update(app.cdefines) - return sorted(list(cdefs)) - - def get_apps_of_type(self, apptype: FlipperAppType): - return sorted( - filter(lambda app: app.apptype == apptype, self.apps), - key=lambda app: app.order, - ) - - def get_builtin_app_folders(self): - return sorted( - set( - app._appdir - for app in filter( - lambda app: app.apptype in self.BUILTIN_APP_TYPES, self.apps - ) - ) - ) - - -class ApplicationsCGenerator: - APP_TYPE_MAP = { - FlipperAppType.SERVICE: ("FlipperApplication", "FLIPPER_SERVICES"), - FlipperAppType.SYSTEM: ("FlipperApplication", "FLIPPER_SYSTEM_APPS"), - FlipperAppType.APP: ("FlipperApplication", "FLIPPER_APPS"), - FlipperAppType.PLUGIN: ("FlipperApplication", "FLIPPER_PLUGINS"), - FlipperAppType.DEBUG: ("FlipperApplication", "FLIPPER_DEBUG_APPS"), - FlipperAppType.SETTINGS: ("FlipperApplication", "FLIPPER_SETTINGS_APPS"), - FlipperAppType.STARTUP: ("FlipperOnStartHook", "FLIPPER_ON_SYSTEM_START"), - } - - def __init__(self, buildset: AppBuildset): - self.buildset = buildset - - def get_app_ep_forward(self, app: FlipperApplication): - if app.apptype == FlipperAppType.STARTUP: - return f"extern void {app.entry_point}();" - return f"extern int32_t {app.entry_point}(void* p);" - - def get_app_descr(self, app: FlipperApplication): - if app.apptype == FlipperAppType.STARTUP: - return app.entry_point - return f""" - {{.app = {app.entry_point}, - .name = "{app.name}", - .stack_size = {app.stack_size}, - .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" - - def generate(self): - contents = ['#include "applications.h"', "#include "] - for apptype in self.APP_TYPE_MAP: - contents.extend( - map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) - ) - entry_type, entry_block = self.APP_TYPE_MAP[apptype] - contents.append(f"const {entry_type} {entry_block}[] = {{") - contents.append( - ",\n".join( - map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) - ) - ) - contents.append("};") - contents.append( - f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" - ) - - archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) - if archive_app: - contents.extend( - [ - self.get_app_ep_forward(archive_app[0]), - f"const FlipperApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", - ] - ) - - return "\n".join(contents) +from fbt.appmanifest import FlipperAppType, AppManager, ApplicationsCGenerator def LoadApplicationManifests(env): diff --git a/site_scons/fbt/__init__.py b/site_scons/fbt/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/site_scons/fbt/appmanifest.py b/site_scons/fbt/appmanifest.py new file mode 100644 index 000000000000..ce3e46def4a2 --- /dev/null +++ b/site_scons/fbt/appmanifest.py @@ -0,0 +1,239 @@ +from dataclasses import dataclass, field +from typing import List, Set, Dict, Tuple, Optional +from enum import Enum +import os + + +class FlipperManifestException(Exception): + pass + + +class FlipperAppType(Enum): + SERVICE = "Service" + SYSTEM = "System" + APP = "App" + PLUGIN = "Plugin" + DEBUG = "Debug" + ARCHIVE = "Archive" + SETTINGS = "Settings" + STARTUP = "StartupHook" + EXTERNAL = "External" + METAPACKAGE = "Package" + + +@dataclass +class FlipperApplication: + appid: str + apptype: FlipperAppType + name: Optional[str] = None + entry_point: Optional[str] = None + flags: List[str] = field(default_factory=lambda: ["Default"]) + cdefines: List[str] = field(default_factory=list) + requires: List[str] = field(default_factory=list) + conflicts: List[str] = field(default_factory=list) + provides: List[str] = field(default_factory=list) + stack_size: int = 2048 + icon: Optional[str] = None + order: int = 0 + _appdir: Optional[str] = None + + +class AppManager: + def __init__(self): + self.known_apps = {} + + def get(self, appname: str): + try: + return self.known_apps[appname] + except KeyError as _: + raise FlipperManifestException( + f"Missing application manifest for '{appname}'" + ) + + def load_manifest(self, app_manifest_path: str, app_dir_name: str): + if not os.path.exists(app_manifest_path): + raise FlipperManifestException( + f"App manifest not found at path {app_manifest_path}" + ) + # print("Loading", app_manifest_path) + + app_manifests = [] + + def App(*args, **kw): + nonlocal app_manifests + app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name)) + + with open(app_manifest_path, "rt") as manifest_file: + exec(manifest_file.read()) + + if len(app_manifests) == 0: + raise FlipperManifestException( + f"App manifest '{app_manifest_path}' is malformed" + ) + + # print("Built", app_manifests) + for app in app_manifests: + self._add_known_app(app) + + def _add_known_app(self, app: FlipperApplication): + if self.known_apps.get(app.appid, None): + raise Exception(f"Duplicate app declaration: {app.appid}") + self.known_apps[app.appid] = app + + def filter_apps(self, applist: List[str]): + return AppBuildset(self, applist) + + +class AppBuildset: + BUILTIN_APP_TYPES = ( + FlipperAppType.SERVICE, + FlipperAppType.SYSTEM, + FlipperAppType.APP, + FlipperAppType.PLUGIN, + FlipperAppType.DEBUG, + FlipperAppType.ARCHIVE, + FlipperAppType.SETTINGS, + FlipperAppType.STARTUP, + ) + + def __init__(self, appmgr: AppManager, appnames: List[str]): + self.appmgr = appmgr + self.appnames = set(appnames) + self._orig_appnames = appnames + self._process_deps() + self._check_conflicts() + self._check_unsatisfied() # unneeded? + self.apps = sorted( + list(map(self.appmgr.get, self.appnames)), + key=lambda app: app.appid, + ) + + def _is_missing_dep(self, dep_name: str): + return dep_name not in self.appnames + + def _process_deps(self): + while True: + provided = [] + for app in self.appnames: + # print(app) + provided.extend( + filter( + self._is_missing_dep, + self.appmgr.get(app).provides + self.appmgr.get(app).requires, + ) + ) + # print("provides round", provided) + if len(provided) == 0: + break + self.appnames.update(provided) + + def _check_conflicts(self): + conflicts = [] + for app in self.appnames: + # print(app) + if conflict_app_name := list( + filter( + lambda dep_name: dep_name in self.appnames, + self.appmgr.get(app).conflicts, + ) + ): + conflicts.append((app, conflict_app_name)) + + if len(conflicts): + raise Exception( + f"App conflicts for {', '.join(f'{conflict_dep[0]}: {conflict_dep[1]}' for conflict_dep in conflicts)}" + ) + + def _check_unsatisfied(self): + unsatisfied = [] + for app in self.appnames: + if missing_dep := list( + filter(self._is_missing_dep, self.appmgr.get(app).requires) + ): + unsatisfied.append((app, missing_dep)) + + if len(unsatisfied): + raise Exception( + f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" + ) + + def get_apps_cdefs(self): + cdefs = set() + for app in self.apps: + cdefs.update(app.cdefines) + return sorted(list(cdefs)) + + def get_apps_of_type(self, apptype: FlipperAppType): + return sorted( + filter(lambda app: app.apptype == apptype, self.apps), + key=lambda app: app.order, + ) + + def get_builtin_app_folders(self): + return sorted( + set( + app._appdir + for app in filter( + lambda app: app.apptype in self.BUILTIN_APP_TYPES, self.apps + ) + ) + ) + + +class ApplicationsCGenerator: + APP_TYPE_MAP = { + FlipperAppType.SERVICE: ("FlipperApplication", "FLIPPER_SERVICES"), + FlipperAppType.SYSTEM: ("FlipperApplication", "FLIPPER_SYSTEM_APPS"), + FlipperAppType.APP: ("FlipperApplication", "FLIPPER_APPS"), + FlipperAppType.PLUGIN: ("FlipperApplication", "FLIPPER_PLUGINS"), + FlipperAppType.DEBUG: ("FlipperApplication", "FLIPPER_DEBUG_APPS"), + FlipperAppType.SETTINGS: ("FlipperApplication", "FLIPPER_SETTINGS_APPS"), + FlipperAppType.STARTUP: ("FlipperOnStartHook", "FLIPPER_ON_SYSTEM_START"), + } + + def __init__(self, buildset: AppBuildset): + self.buildset = buildset + + def get_app_ep_forward(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return f"extern void {app.entry_point}();" + return f"extern int32_t {app.entry_point}(void* p);" + + def get_app_descr(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return app.entry_point + return f""" + {{.app = {app.entry_point}, + .name = "{app.name}", + .stack_size = {app.stack_size}, + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" + + def generate(self): + contents = ['#include "applications.h"', "#include "] + for apptype in self.APP_TYPE_MAP: + contents.extend( + map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) + ) + entry_type, entry_block = self.APP_TYPE_MAP[apptype] + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append( + ",\n".join( + map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) + ) + ) + contents.append("};") + contents.append( + f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" + ) + + archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) + if archive_app: + contents.extend( + [ + self.get_app_ep_forward(archive_app[0]), + f"const FlipperApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", + ] + ) + + return "\n".join(contents) diff --git a/site_scons/site_init.py b/site_scons/site_init.py new file mode 100644 index 000000000000..f29968bb431d --- /dev/null +++ b/site_scons/site_init.py @@ -0,0 +1,4 @@ +import sys +import os + +sys.path.insert(0, os.path.join(os.getcwd(), "scripts")) From 5a5e814b1057982077a2679540fc52f78bb3c7d6 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 17:31:49 +0400 Subject: [PATCH 087/184] Build: moved python code fragments out of sconsipt files to site_scons --- assets/SConscript | 134 +-------------------------- lib/heatshrink/SConscript | 1 - site_scons/environ.scons | 53 ++++------- site_scons/fbt/builders/__init__.py | 0 site_scons/fbt/builders/assets.py | 136 ++++++++++++++++++++++++++++ site_scons/sutils.py | 25 +++++ 6 files changed, 185 insertions(+), 164 deletions(-) delete mode 100644 lib/heatshrink/SConscript create mode 100644 site_scons/fbt/builders/__init__.py create mode 100644 site_scons/fbt/builders/assets.py create mode 100644 site_scons/sutils.py diff --git a/assets/SConscript b/assets/SConscript index 21a90a3b2807..a0eeb6f1d7c5 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -1,8 +1,7 @@ Import("env", "lib_flags") -import os -import subprocess -import SCons +from fbt.builders.assets import add_assets_builders, proto_ver_generator + assetsenv = env.Clone() assetsenv.MergeFlags(lib_flags) @@ -12,134 +11,9 @@ assetsenv.Append( NANOPB_COMPILER="lib/nanopb/generator/nanopb_generator.py", ) -# Setting up emitters for scripts - - -def icons_emitter(target, source, env): - target = [ - "assets_icons.c", - "assets_icons.h", - ] - return target, source - - -def proto_emitter(target, source, env): - out_path = target[0].path - target = [] - for src in source: - basename = os.path.splitext(src.name)[0] - target.append(File(basename + ".pb.c")) - target.append(File(basename + ".pb.h")) - return target, source - - -def dolphin_emitter(target, source, env): - res_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) - source = [res_root_dir] - source.extend( - env.GlobRecursive("*.*", res_root_dir), - ) - - target_base_dir = target[0] - env.Replace(_DOLPHIN_OUT_DIR=target[0]) - - if env["DOLPHIN_RES_TYPE"] == "external": - target = [] - target.extend( - map( - lambda node: target_base_dir.File( - res_root_dir.rel_path(node).replace(".png", ".bm") - ), - filter(lambda node: isinstance(node, SCons.Node.FS.File), source), - ) - ) - else: - asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" - target = [ - target_base_dir.File(asset_basename + ".c"), - target_base_dir.File(asset_basename + ".h"), - ] - - return target, source - - -def _invoke_git(args, source_dir): - cmd = ["git"] - cmd.extend(args) - return ( - subprocess.check_output(cmd, cwd=source_dir, stderr=subprocess.STDOUT) - .strip() - .decode() - ) - - -def proto_ver_generator(target, source, env): - target_file = target[0].abspath - src_dir = source[0].dir.abspath - try: - git_fetch = _invoke_git( - ["fetch", "--tags"], - source_dir=src_dir, - ) - except (subprocess.CalledProcessError, EnvironmentError) as e: - # Not great, not terrible - print("Git: fetch failed") - - try: - git_describe = _invoke_git( - ["describe", "--tags", "--abbrev=0"], - source_dir=src_dir, - ) - except (subprocess.CalledProcessError, EnvironmentError) as e: - print("Git: describe failed") - Exit("git error") - - # print("describe=", git_describe) - git_major, git_minor = git_describe.split(".") - version_file_data = ( - "#pragma once", - f"#define PROTOBUF_MAJOR_VERSION {git_major}", - f"#define PROTOBUF_MINOR_VERSION {git_minor}", - "", - ) - with open(target_file, "wt") as file: - file.write("\n".join(version_file_data)) +# Setting up builders for scripts - -assetsenv.Append( - BUILDERS={ - "IconBuilder": Builder( - action=Action( - "${PYTHON3} ${ASSETS_COMPILER} icons ${SOURCE.posix} ${TARGET.dir.posix}", - "\tICONS\t${TARGET}", - ), - emitter=icons_emitter, - ), - "ProtoBuilder": Builder( - action=Action( - "${PYTHON3} ${NANOPB_COMPILER} -q -I${SOURCE.dir.posix} -D${TARGET.dir.posix} ${SOURCES.posix}", - "\tPROTO\t${SOURCE}", - ), - emitter=proto_emitter, - suffix=".pb.c", - src_suffix=".proto", - ), - "DolphinSymBuilder": Builder( - action=Action( - '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', - "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", - ), - emitter=dolphin_emitter, - ), - "DolphinExtBuilder": Builder( - action=Action( - '${PYTHON3} ${ASSETS_COMPILER} dolphin "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', - "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", - ), - emitter=dolphin_emitter, - ), - } -) +add_assets_builders(assetsenv) # Gathering icons sources diff --git a/lib/heatshrink/SConscript b/lib/heatshrink/SConscript deleted file mode 100644 index 1ad04d93fa76..000000000000 --- a/lib/heatshrink/SConscript +++ /dev/null @@ -1 +0,0 @@ -Import("env") diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 519e0b47ee15..259e45b8bf8a 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -1,10 +1,9 @@ -from SCons.Subst import quote_spaces from SCons.Platform import TempFileMunge - import SCons +import sutils + import os import sys -import re import multiprocessing @@ -69,46 +68,34 @@ SetOption("num_jobs", multiprocessing.cpu_count()) SetOption("implicit_cache", True) SetOption("implicit_deps_unchanged", True) SetOption("max_drift", 1) +SetOption("random", 1) # coreenv.Decider("content-timestamp") -# Setting up temp file parameters - -WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") - - -def tempfile_arg_esc_func(arg): - arg = quote_spaces(arg) - if coreenv["PLATFORM"] != "win32": - return arg - # GCC requires double Windows slashes, let's use UNIX separator - return WINPATHSEP_RE.sub(r"/\1", arg) - - -coreenv["TEMPFILEARGESCFUNC"] = tempfile_arg_esc_func - - # Set up cross-compile tools -TOOLCHAIN_PREFIX = "arm-none-eabi-" +sutils.prefix_commands( + coreenv, + "arm-none-eabi-", + [ + "AR", + "AS", + "CC", + "CXX", + "OBJCOPY", + "RANLIB", + "STRIP", + ], +) -for binary in [ - "AR", - "AS", - "CC", - "CXX", - "OBJCOPY", - "RANLIB", - "STRIP", -]: - if binary in coreenv: - coreenv[binary] = TOOLCHAIN_PREFIX + coreenv[binary] +# Setting up temp file parameters +coreenv["TEMPFILEARGESCFUNC"] = sutils.tempfile_arg_esc_func # Commandline length limit hack -coreenv["LINKCOM"] = '${TEMPFILE("' + coreenv["LINKCOM"] + '","$LINKCOMSTR")}' -coreenv["ARCOM"] = '${TEMPFILE("' + coreenv["ARCOM"] + '","$ARCOMSTR")}' +sutils.wrap_tempfile(coreenv, "LINKCOM") +sutils.wrap_tempfile(coreenv, "ARCOM") # Build env extensions diff --git a/site_scons/fbt/builders/__init__.py b/site_scons/fbt/builders/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/site_scons/fbt/builders/assets.py b/site_scons/fbt/builders/assets.py new file mode 100644 index 000000000000..c54ba11aa366 --- /dev/null +++ b/site_scons/fbt/builders/assets.py @@ -0,0 +1,136 @@ +import SCons + +from SCons.Builder import Builder +from SCons.Action import Action +from SCons.Node.FS import File + +import os +import subprocess + + +def icons_emitter(target, source, env): + target = [ + "assets_icons.c", + "assets_icons.h", + ] + return target, source + + +def proto_emitter(target, source, env): + out_path = target[0].path + target = [] + for src in source: + basename = os.path.splitext(src.name)[0] + target.append(env.File(basename + ".pb.c")) + target.append(env.File(basename + ".pb.h")) + return target, source + + +def dolphin_emitter(target, source, env): + res_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) + source = [res_root_dir] + source.extend( + env.GlobRecursive("*.*", res_root_dir), + ) + + target_base_dir = target[0] + env.Replace(_DOLPHIN_OUT_DIR=target[0]) + + if env["DOLPHIN_RES_TYPE"] == "external": + target = [] + target.extend( + map( + lambda node: target_base_dir.File( + res_root_dir.rel_path(node).replace(".png", ".bm") + ), + filter(lambda node: isinstance(node, SCons.Node.FS.File), source), + ) + ) + else: + asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" + target = [ + target_base_dir.File(asset_basename + ".c"), + target_base_dir.File(asset_basename + ".h"), + ] + + return target, source + + +def _invoke_git(args, source_dir): + cmd = ["git"] + cmd.extend(args) + return ( + subprocess.check_output(cmd, cwd=source_dir, stderr=subprocess.STDOUT) + .strip() + .decode() + ) + + +def proto_ver_generator(target, source, env): + target_file = target[0].abspath + src_dir = source[0].dir.abspath + try: + git_fetch = _invoke_git( + ["fetch", "--tags"], + source_dir=src_dir, + ) + except (subprocess.CalledProcessError, EnvironmentError) as e: + # Not great, not terrible + print("Git: fetch failed") + + try: + git_describe = _invoke_git( + ["describe", "--tags", "--abbrev=0"], + source_dir=src_dir, + ) + except (subprocess.CalledProcessError, EnvironmentError) as e: + print("Git: describe failed") + Exit("git error") + + # print("describe=", git_describe) + git_major, git_minor = git_describe.split(".") + version_file_data = ( + "#pragma once", + f"#define PROTOBUF_MAJOR_VERSION {git_major}", + f"#define PROTOBUF_MINOR_VERSION {git_minor}", + "", + ) + with open(target_file, "wt") as file: + file.write("\n".join(version_file_data)) + + +def add_assets_builders(env): + env.Append( + BUILDERS={ + "IconBuilder": Builder( + action=Action( + "${PYTHON3} ${ASSETS_COMPILER} icons ${SOURCE.posix} ${TARGET.dir.posix}", + "\tICONS\t${TARGET}", + ), + emitter=icons_emitter, + ), + "ProtoBuilder": Builder( + action=Action( + "${PYTHON3} ${NANOPB_COMPILER} -q -I${SOURCE.dir.posix} -D${TARGET.dir.posix} ${SOURCES.posix}", + "\tPROTO\t${SOURCE}", + ), + emitter=proto_emitter, + suffix=".pb.c", + src_suffix=".proto", + ), + "DolphinSymBuilder": Builder( + action=Action( + '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', + "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", + ), + emitter=dolphin_emitter, + ), + "DolphinExtBuilder": Builder( + action=Action( + '${PYTHON3} ${ASSETS_COMPILER} dolphin "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', + "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", + ), + emitter=dolphin_emitter, + ), + } + ) diff --git a/site_scons/sutils.py b/site_scons/sutils.py new file mode 100644 index 000000000000..a9b667e40e6a --- /dev/null +++ b/site_scons/sutils.py @@ -0,0 +1,25 @@ +import SCons +from SCons.Subst import quote_spaces + +import re + + +WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") + + +def tempfile_arg_esc_func(arg): + arg = quote_spaces(arg) + if SCons.Platform.platform_default() != "win32": + return arg + # GCC requires double Windows slashes, let's use UNIX separator + return WINPATHSEP_RE.sub(r"/\1", arg) + + +def wrap_tempfile(env, command): + env[command] = '${TEMPFILE("' + env[command] + '","$' + command + 'STR")}' + + +def prefix_commands(env, command_prefix, cmd_list): + for command in cmd_list: + if command in env: + env[command] = command_prefix + env[command] From f6b06bc2d268af5e9bafde947a40636f7942abe9 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 17:58:00 +0400 Subject: [PATCH 088/184] Build: cleaner *COMSTR setup respecting global VERBOSE=1 --- assets/SConscript | 23 ++++++++++++++++------- site_scons/builders.scons | 21 +++++++++++++++------ site_scons/fbt/builders/assets.py | 8 ++++---- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/assets/SConscript b/assets/SConscript index a0eeb6f1d7c5..8a3ec7b09c24 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -6,15 +6,24 @@ from fbt.builders.assets import add_assets_builders, proto_ver_generator assetsenv = env.Clone() assetsenv.MergeFlags(lib_flags) -assetsenv.Append( - ASSETS_COMPILER="scripts/assets.py", - NANOPB_COMPILER="lib/nanopb/generator/nanopb_generator.py", -) - # Setting up builders for scripts add_assets_builders(assetsenv) +assetsenv.Append( + ASSETS_COMPILER="${ROOT_DIR.abspath}/scripts/assets.py", + NANOPB_COMPILER="${ROOT_DIR.abspath}/lib/nanopb/generator/nanopb_generator.py", +) + +if not assetsenv["VERBOSE"]: + assetsenv.Replace( + ICONSCOMSTR="\tICONS\t${TARGET}", + PROTOCOMSTR="\tPROTO\t${SOURCE}", + DOLPHINCOMSTR="\tDOLPHIN\t${DOLPHIN_RES_TYPE}", + RESMANIFESTCOMSTR="\tMANIFEST\t${TARGET}", + PBVERCOMSTR="\tPBVER\t${TARGET}", + ) + # Gathering icons sources icons_src = assetsenv.GlobRecursive("*.png", "icons") @@ -62,7 +71,7 @@ proto_ver = assetsenv.Command( "#/assets/protobuf/Changelog", action=Action( proto_ver_generator, - "\tPBVER\t${TARGET}", + "${PBVERCOMSTR}", ), ) Depends(proto_ver, proto) @@ -98,7 +107,7 @@ if assetsenv["FIRMWARE_BUILD_CFG"] != "updater": assetsenv.GlobRecursive("*", "resources", exclude="Manifest"), action=Action( '${PYTHON3} ${ASSETS_COMPILER} manifest "${TARGET.dir.posix}"', - "\tRES\t${TARGET}", + "${RESMANIFESTCOMSTR}", ), ) Precious(resources) diff --git a/site_scons/builders.scons b/site_scons/builders.scons index b0de50208dc2..b3ec270f251f 100644 --- a/site_scons/builders.scons +++ b/site_scons/builders.scons @@ -6,7 +6,7 @@ coreenv.Append( "HEXBuilder": Builder( action=Action( '${OBJCOPY} -O ihex "${SOURCE}" "${TARGET}"', - "\tHEX\t${TARGET}", + "${HEXCOMSTR}", ), suffix=".hex", src_suffix=".elf", @@ -14,7 +14,7 @@ coreenv.Append( "BINBuilder": Builder( action=Action( '${OBJCOPY} -O binary -S "${SOURCE}" "${TARGET}"', - "\tBIN\t${TARGET}", + "${BINCOMSTR}", ), suffix=".bin", src_suffix=".elf", @@ -22,15 +22,15 @@ coreenv.Append( "DFUBuilder": Builder( action=Action( '${PYTHON3} ./scripts/bin2dfu.py -i "${SOURCE}" -o "${TARGET}" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"', - "\tDFU\t${TARGET}", + "${DFUCOMSTR}", ), suffix=".dfu", src_suffix=".bin", ), "ELFStripper": Builder( action=Action( - coreenv["STRIPCOM"], - "\tSTRIP\t${TARGET}", + "${STRIPCOM}", + "${STRIPCOMSTR}", ), suffix=".elf", src_suffix=".elf", @@ -39,7 +39,7 @@ coreenv.Append( action=[ Action( 'openocd ${OPENOCD_OPTS} -c "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}"', - "\tFLASH\t${SOURCE}", + "${FLASHCOMSTR}", ), Touch("${TARGET}"), ], @@ -48,3 +48,12 @@ coreenv.Append( ), } ) + +if not coreenv["VERBOSE"]: + coreenv.Replace( + HEXCOMSTR="\tHEX\t${TARGET}", + BINCOMSTR="\tBIN\t${TARGET}", + DFUCOMSTR="\tDFU\t${TARGET}", + STRIPCOMSTR="\tSTRIP\t${TARGET}", + FLASHCOMSTR="\tFLASH\t${SOURCE}", + ) diff --git a/site_scons/fbt/builders/assets.py b/site_scons/fbt/builders/assets.py index c54ba11aa366..70cdb75c2bd1 100644 --- a/site_scons/fbt/builders/assets.py +++ b/site_scons/fbt/builders/assets.py @@ -105,14 +105,14 @@ def add_assets_builders(env): "IconBuilder": Builder( action=Action( "${PYTHON3} ${ASSETS_COMPILER} icons ${SOURCE.posix} ${TARGET.dir.posix}", - "\tICONS\t${TARGET}", + "${ICONSCOMSTR}", ), emitter=icons_emitter, ), "ProtoBuilder": Builder( action=Action( "${PYTHON3} ${NANOPB_COMPILER} -q -I${SOURCE.dir.posix} -D${TARGET.dir.posix} ${SOURCES.posix}", - "\tPROTO\t${SOURCE}", + "${PROTOCOMSTR}", ), emitter=proto_emitter, suffix=".pb.c", @@ -121,14 +121,14 @@ def add_assets_builders(env): "DolphinSymBuilder": Builder( action=Action( '${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', - "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", + "${DOLPHINCOMSTR}", ), emitter=dolphin_emitter, ), "DolphinExtBuilder": Builder( action=Action( '${PYTHON3} ${ASSETS_COMPILER} dolphin "${SOURCE}" "${_DOLPHIN_OUT_DIR}"', - "\tDOLPHIN\t${DOLPHIN_RES_TYPE}", + "${DOLPHINCOMSTR}", ), emitter=dolphin_emitter, ), From 785f673b16a09aadb1b0bd5fc7a6abd8f3a1a58e Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 18:38:28 +0400 Subject: [PATCH 089/184] Build: dumping app configuration post-link --- firmware.scons | 17 ++++++++--------- site_scons/environ.scons | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/firmware.scons b/firmware.scons index be3fd533bd74..08a3411a9e4e 100644 --- a/firmware.scons +++ b/firmware.scons @@ -110,8 +110,6 @@ apps_c = fwenv.Command( Value(fwenv["APPS"]), action=fwenv["APPS_C_ACTION"], ) -AddPreAction(apps_c, fwenv["APPBUILD_DUMP"]) - sources = [apps_c] # Gather sources only from app folders from current configuration @@ -145,7 +143,7 @@ fwenv.Append( # Full firmware definition -firmware_elf = fwenv.Program( +fwelf = fwenv.Program( "${FIRMWARE_BUILD_CFG}", sources, LIBS=[ @@ -173,14 +171,15 @@ firmware_elf = fwenv.Program( ) # Make it depend on everything child builders returned -Depends(firmware_elf, depends) +Depends(fwelf, depends) +AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) -fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") -fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") -dfu = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") +fwhex = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") +fwbin = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") +fwdfu = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") # Default(dfu) -Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", dfu) +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu) # Additional FW-related pseudotargets flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") @@ -243,4 +242,4 @@ for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) -Return("dfu") +Return("fwhex fwelf fwbin") diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 259e45b8bf8a..ccc0f5720083 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -49,7 +49,7 @@ if not coreenv["VERBOSE"]: ARCOMSTR="\tAR\t${TARGET}", RANLIBCOMSTR="\tRANLIB\t${TARGET}", LINKCOMSTR="\tLINK\t${TARGET}", - INSTALLSTR="\tINSTALL\t${SOURCE}", + INSTALLSTR="\tINSTALL\t${TARGET}", APPSCOMSTR="\tAPPS\t${TARGET}", VERSIONCOMSTR="\tVERSION\t${TARGET}", # STRIPCOMSTR="\tSTRIP\t${TARGET}", From 5f7660d645a1bfa420a6af08adc55bc254f7ebb5 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Sat, 11 Jun 2022 11:14:04 -0400 Subject: [PATCH 090/184] Start to develop universal UNIX/Windows toolchain downaload script --- .gitattributes | 1 + toolchain-download.sh.bat | 14 ++++++++++++++ .../scripts/generate-toolchain-download.sh | 19 +++++++++++++++++++ toolchain/scripts/unix-toolchain-download.sh | 9 +++++++++ 4 files changed, 43 insertions(+) create mode 100755 toolchain-download.sh.bat create mode 100755 toolchain/scripts/generate-toolchain-download.sh create mode 100755 toolchain/scripts/unix-toolchain-download.sh diff --git a/.gitattributes b/.gitattributes index 6313b56c5784..b3faf6d84f72 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ * text=auto eol=lf +*.sh.bat binary diff --git a/toolchain-download.sh.bat b/toolchain-download.sh.bat new file mode 100755 index 000000000000..79f6e7d37e7b --- /dev/null +++ b/toolchain-download.sh.bat @@ -0,0 +1,14 @@ +echo >/dev/null # >nul & GOTO WINDOWS & rem ^ +# *********************************************************** +# * NOTE: If you modify this content, be sure to remove carriage returns (\r)\n +# * from the Linux part and leave them in together with the line feeds +# * (\n) for the Windows part. In summary: +# * New lines in Linux: \n\n +# * New lines in Windows: \r\n +# *********************************************************** +toolchain/scripts/unix-toolchain-download.sh +exit 0 +:WINDOWS +@echo off +cls +powershell -ExecutionPolicy Bypass -File toolchain\scripts\windows-toolchain-download.ps1 diff --git a/toolchain/scripts/generate-toolchain-download.sh b/toolchain/scripts/generate-toolchain-download.sh new file mode 100755 index 000000000000..e9e5ad580098 --- /dev/null +++ b/toolchain/scripts/generate-toolchain-download.sh @@ -0,0 +1,19 @@ +#!/bin/bash +SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; +PROJECT_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; +printf "echo >/dev/null # >nul & GOTO WINDOWS & rem ^\r\n" > "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "# ***********************************************************\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "# * NOTE: If you modify this content, be sure to remove carriage returns (\\\r)\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "# * from the Linux part and leave them in together with the line feeds\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "# * (\\\n) for the Windows part. In summary:\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "# * New lines in Linux: \\\n\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "# * New lines in Windows: \\\r\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "# ***********************************************************\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "toolchain/scripts/unix-toolchain-download.sh\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "exit 0\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf ":WINDOWS\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "@echo off\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "cls\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "powershell -ExecutionPolicy Bypass -File toolchain\\\scripts\\\windows-toolchain-download.ps1\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" + +chmod +x "$PROJECT_ROOT/toolchain-download.sh.bat" diff --git a/toolchain/scripts/unix-toolchain-download.sh b/toolchain/scripts/unix-toolchain-download.sh new file mode 100755 index 000000000000..d163b410ae41 --- /dev/null +++ b/toolchain/scripts/unix-toolchain-download.sh @@ -0,0 +1,9 @@ +#!/bin/sh +SYS_TYPE="$(uname -s)" +if [ "$SYS_TYPE" = "Darwin" ]; then + printf "Downloading Mac OS toolchain.."; +else + printf "Downloading Linux toolchain.."; +fi + +echo "done!" From 33480444d10e4fad8555a11e80cc03a74026fb44 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 19:30:02 +0400 Subject: [PATCH 091/184] Build: reduced number of global variables; added per-lib optimization flag customization --- SConstruct | 9 +++++---- assets/SConscript | 10 +++++----- core/SConscript | 8 ++++---- firmware.scons | 30 +++++++++++++++++++++--------- firmware/SConscript | 8 ++++---- lib/ST25RFAL002/SConscript | 8 ++++---- lib/STM32CubeWB.scons | 9 +++++---- lib/appframe.scons | 9 +++++---- lib/drivers/SConscript | 8 ++++---- lib/fatfs/SConscript | 13 +++++++------ lib/flipper_format/SConscript | 8 ++++---- lib/freertos.scons | 9 +++++---- lib/infrared/SConscript | 8 ++++---- lib/libusb_stm32.scons | 9 +++++---- lib/littlefs.scons | 8 ++++---- lib/microtar.scons | 8 ++++---- lib/misc.scons | 9 ++++----- lib/subghz/SConscript | 8 ++++---- lib/toolbox/SConscript | 8 ++++---- site_scons/appmanifests.scons | 12 ++++++------ site_scons/builders.scons | 9 ++++----- site_scons/cc.scons | 19 ++----------------- site_scons/environ.scons | 23 +++++++++++++++++------ site_scons/firmwareopts.scons | 20 ++++++++++---------- 24 files changed, 141 insertions(+), 129 deletions(-) diff --git a/SConstruct b/SConstruct index 04030f6523cf..2cedceaffbb6 100644 --- a/SConstruct +++ b/SConstruct @@ -7,11 +7,10 @@ AddOption( help="Full firmware environment", ) -SConscript("site_scons/environ.scons") -SConscript("site_scons/cc.scons") -SConscript("site_scons/builders.scons") +coreenv = SConscript("site_scons/environ.scons") +SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) +SConscript("site_scons/builders.scons", exports={"ENV": coreenv}) -Import("coreenv") # Progress(["-\r", "\\\r", "|\r", "/\r"], interval=5) variant_dir_name = f"f{coreenv.subst('$TARGET_HW')}-FWTYPE" @@ -31,6 +30,7 @@ firmware = SConscript( variant_dir=build_path.replace("FWTYPE", "firmware"), duplicate=0, exports={ + "ENV": coreenv, "fw_build_meta": { "type": "firmware", "build_dir": build_path.replace("FWTYPE", "firmware"), @@ -45,6 +45,7 @@ if GetOption("fullenv"): variant_dir=build_path.replace("FWTYPE", "updater"), duplicate=0, exports={ + "ENV": coreenv, "fw_build_meta": { "type": "updater", "build_dir": build_path.replace("FWTYPE", "updater"), diff --git a/assets/SConscript b/assets/SConscript index 8a3ec7b09c24..36244e21178d 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -1,10 +1,10 @@ -Import("env", "lib_flags") +Import("env") from fbt.builders.assets import add_assets_builders, proto_ver_generator -assetsenv = env.Clone() -assetsenv.MergeFlags(lib_flags) +assetsenv = env.Clone(FW_LIB_NAME="assets") +assetsenv.ApplyLibFlags() # Setting up builders for scripts @@ -16,7 +16,7 @@ assetsenv.Append( ) if not assetsenv["VERBOSE"]: - assetsenv.Replace( + assetsenv.SetDefault( ICONSCOMSTR="\tICONS\t${TARGET}", PROTOCOMSTR="\tPROTO\t${SOURCE}", DOLPHINCOMSTR="\tDOLPHIN\t${DOLPHIN_RES_TYPE}", @@ -82,7 +82,7 @@ assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) if assetsenv["FIRMWARE_BUILD_CFG"] != "updater": assetsenv.Install("#/assets/compiled", assets_parts) -assetslib = assetsenv.Library("assets", assets_parts) +assetslib = assetsenv.Library("${FW_LIB_NAME}", assets_parts) assetsenv.Install("${LIB_DIST_DIR}", assetslib) diff --git a/core/SConscript b/core/SConscript index 2c7b01490290..dcd613fac691 100644 --- a/core/SConscript +++ b/core/SConscript @@ -1,10 +1,10 @@ -Import("env", "lib_flags") +Import("env") -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="core") +libenv.ApplyLibFlags() sources = libenv.GlobRecursive("*.c") -lib = libenv.Library("core", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/firmware.scons b/firmware.scons index 08a3411a9e4e..5b538243b110 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,11 +1,11 @@ -Import("coreenv", "fw_build_meta") +Import("ENV", "fw_build_meta") import os from fbt.appmanifest import FlipperAppType # Building initial C environment for libs -env = coreenv.Clone() +env = ENV.Clone() Export("env") env.Append( @@ -26,8 +26,21 @@ env.Append( "#/firmware/targets/f${TARGET_HW}/Inc", "#/firmware/targets/furi_hal_include", ], + # Specific flags for building libraries - always do optimized builds + FW_LIB_OPTS={ + "Default": { + "CCFLAGS": [ + "-Os", + ], + "CPPDEFINES": [ + "NDEBUG", + "FURI_NDEBUG", + ], + } + }, ) + if fw_build_meta["type"] == "updater": env.Append( FIRMWARE_BUILD_CFG="updater", @@ -55,14 +68,13 @@ depends = env.BuildModules( ) -# Now, env is fully set up with everything to build apps src +# Now, env is fully set up with everything to build apps fwenv = env.Clone() -Export("fwenv") # Set up additional app-specific build flags -SConscript("site_scons/firmwareopts.scons") +SConscript("site_scons/firmwareopts.scons", exports={"ENV": fwenv}) # Prepare manifest-related env methods -SConscript("site_scons/appmanifests.scons") +SConscript("site_scons/appmanifests.scons", exports={"ENV": fwenv}) # Set up app configuration if env["FIRMWARE_BUILD_CFG"] == "updater": @@ -196,7 +208,7 @@ Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", cdb) # Building external applications appenv.VariantDir("extapps", "applications", duplicate=False) -appenv.Replace( +appenv.SetDefault( LINKER_SCRIPT="application-ext", STRIPFLAGS=[ "--strip-debug", @@ -232,14 +244,14 @@ appenv.Append( ) extapps = [] -for app in fwenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): +for app in appenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): app_elf = appenv.Program( os.path.join("extapps", app.appid), appenv.GlobRecursive("*.c*", os.path.join("extapps", app._appdir)), APP_ENTRY=app.entry_point, ) extapps.append(appenv.ELFStripper(app.appid, app_elf)) -Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) +Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) Return("fwhex fwelf fwbin") diff --git a/firmware/SConscript b/firmware/SConscript index fea3149427cf..d6502a8caed7 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -1,7 +1,7 @@ -Import("env", "lib_flags") +Import("env") -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="flipper${TARGET_HW}") +libenv.ApplyLibFlags() libenv.Append( CPPPATH=[ @@ -12,6 +12,6 @@ libenv.Append( sources = ["targets/f${TARGET_HW}/startup_stm32wb55xx_cm4.s"] sources += libenv.GlobRecursive("*.c") -lib = libenv.Library("flipper${TARGET_HW}", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/ST25RFAL002/SConscript b/lib/ST25RFAL002/SConscript index c1c00254b7c3..d86d2d002e8c 100644 --- a/lib/ST25RFAL002/SConscript +++ b/lib/ST25RFAL002/SConscript @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -9,11 +9,11 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="st25rfal002") +libenv.ApplyLibFlags() sources = libenv.GlobRecursive("*.c") -lib = libenv.StaticLibrary("st25rfal002", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons index 5b472d559ed3..02618ae73a33 100644 --- a/lib/STM32CubeWB.scons +++ b/lib/STM32CubeWB.scons @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -32,8 +32,8 @@ if env["RAM_EXEC"]: ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="stm32cubewb") +libenv.ApplyLibFlags() sources = libenv.GlobRecursive( "*_ll_*.c", "STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/", exclude="*usb.c" @@ -60,6 +60,7 @@ sources += [ "STM32CubeWB/Middlewares/ST/STM32_WPAN/utilities/stm_list.c", ] -lib = libenv.StaticLibrary("stm32cubewb", sources) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/appframe.scons b/lib/appframe.scons index 745f55aa4fc5..72ca5b282d45 100644 --- a/lib/appframe.scons +++ b/lib/appframe.scons @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -9,8 +9,9 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="appframe") +libenv.ApplyLibFlags() + sources = [] @@ -22,6 +23,6 @@ recurse_dirs = [ for recurse_dir in recurse_dirs: sources += libenv.GlobRecursive("*.c*", recurse_dir) -lib = libenv.StaticLibrary("appframe", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript index de20a7c65e76..3b7ee2401e63 100644 --- a/lib/drivers/SConscript +++ b/lib/drivers/SConscript @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -7,11 +7,11 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="hwdrivers") +libenv.ApplyLibFlags() sources = Glob("*.c", source=True) -lib = libenv.StaticLibrary("hwdrivers", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/fatfs/SConscript b/lib/fatfs/SConscript index b0fb559ea11a..c20e29363e4e 100644 --- a/lib/fatfs/SConscript +++ b/lib/fatfs/SConscript @@ -1,12 +1,13 @@ -Import("env", "lib_flags") +Import("env") -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="fatfs") +libenv.ApplyLibFlags() -sources = Glob("*.c", source=True) -sources += ["option/unicode.c"] -lib = libenv.StaticLibrary("fatfs", sources) +sources = ["option/unicode.c"] +sources += Glob("*.c", source=True) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript index 6513d8245b0e..e5d61a075aa6 100644 --- a/lib/flipper_format/SConscript +++ b/lib/flipper_format/SConscript @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -7,8 +7,8 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="flipperformat") +libenv.ApplyLibFlags() if libenv["RAM_EXEC"]: libenv.Append( @@ -20,6 +20,6 @@ if libenv["RAM_EXEC"]: sources = libenv.GlobRecursive("*.c") -lib = libenv.StaticLibrary("flipperformat", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/freertos.scons b/lib/freertos.scons index 1b28d72c474a..992c4f873b39 100644 --- a/lib/freertos.scons +++ b/lib/freertos.scons @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -13,8 +13,9 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="freertos") +libenv.ApplyLibFlags() + sources = libenv.Glob("FreeRTOS-Kernel/*.c", source=True) sources += [ @@ -22,6 +23,6 @@ sources += [ "FreeRTOS-glue/cmsis_os2.c", ] -lib = libenv.StaticLibrary("freertos", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/infrared/SConscript b/lib/infrared/SConscript index b8169d97586e..35db75f879d4 100644 --- a/lib/infrared/SConscript +++ b/lib/infrared/SConscript @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -8,11 +8,11 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="infrared") +libenv.ApplyLibFlags() sources = libenv.GlobRecursive("*.c") -lib = libenv.StaticLibrary("infrared", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/libusb_stm32.scons b/lib/libusb_stm32.scons index 8f92e17f6db2..cb867fdbc9c0 100644 --- a/lib/libusb_stm32.scons +++ b/lib/libusb_stm32.scons @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -10,14 +10,15 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="usb_stm32") +libenv.ApplyLibFlags() + sources = [ "libusb_stm32/src/usbd_core.c", "libusb_stm32/src/usbd_stm32wb55_devfs.c", ] -lib = libenv.StaticLibrary("usb_stm32", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/littlefs.scons b/lib/littlefs.scons index 8b563064eda9..792142c32f05 100644 --- a/lib/littlefs.scons +++ b/lib/littlefs.scons @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -10,11 +10,11 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="littlefs") +libenv.ApplyLibFlags() sources = Glob("littlefs/*.c", source=True) -lib = libenv.StaticLibrary("littlefs", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/microtar.scons b/lib/microtar.scons index 05b351774048..6ee36d403cd9 100644 --- a/lib/microtar.scons +++ b/lib/microtar.scons @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -7,8 +7,8 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="microtar") +libenv.ApplyLibFlags() libenv.Append( CPPDEFINES=["MICROTAR_DISABLE_API_CHECKS"], @@ -16,6 +16,6 @@ libenv.Append( sources = libenv.GlobRecursive("*.c", "microtar/src") -lib = libenv.StaticLibrary("microtar", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/misc.scons b/lib/misc.scons index 7267112294bc..91a11ff64090 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -16,9 +16,8 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) - +libenv = env.Clone(FW_LIB_NAME="misc") +libenv.ApplyLibFlags() sources = [] @@ -42,6 +41,6 @@ libs_plain = [ for lib in libs_plain: sources += Glob(lib + "/*.c*", source=True) -lib = libenv.StaticLibrary("misc", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 1337af40427f..3c6728afe676 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") env.Append( CPPPATH=[ @@ -6,11 +6,11 @@ env.Append( ], ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="subghz") +libenv.ApplyLibFlags() sources = libenv.GlobRecursive("*.c*") -lib = libenv.StaticLibrary("subghz", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index fb0980f5db59..2bfce7bec262 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -1,4 +1,4 @@ -Import("env", "lib_flags") +Import("env") import subprocess import datetime @@ -10,8 +10,8 @@ env.Append( ) -libenv = env.Clone() -libenv.MergeFlags(lib_flags) +libenv = env.Clone(FW_LIB_NAME="toolbox") +libenv.ApplyLibFlags() # Git Version management version_depends = [] @@ -53,6 +53,6 @@ sources = libenv.GlobRecursive("*.c") libenv.Append(CPPPATH=["."]) -lib = libenv.StaticLibrary("toolbox", sources) +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/site_scons/appmanifests.scons b/site_scons/appmanifests.scons index c13dfa5a3de2..8e36f4b132ff 100644 --- a/site_scons/appmanifests.scons +++ b/site_scons/appmanifests.scons @@ -1,4 +1,4 @@ -Import("fwenv") +Import("ENV") import SCons from fbt.appmanifest import FlipperAppType, AppManager, ApplicationsCGenerator @@ -24,15 +24,15 @@ def DumpApplicationConfig(target, source, env): def PrepareApplicationsBuild(env): - fwenv["APPBUILD"] = fwenv["APPMGR"].filter_apps(fwenv["APPS"]) - fwenv["APPBUILD_DUMP"] = Action( + env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"]) + env["APPBUILD_DUMP"] = Action( DumpApplicationConfig, "\tINFO\t", ) -fwenv.AddMethod(LoadApplicationManifests) -fwenv.AddMethod(PrepareApplicationsBuild) +ENV.AddMethod(LoadApplicationManifests) +ENV.AddMethod(PrepareApplicationsBuild) def build_apps_c(target, source, env): @@ -43,4 +43,4 @@ def build_apps_c(target, source, env): file.write(gen.generate()) -fwenv["APPS_C_ACTION"] = Action(build_apps_c, "${APPSCOMSTR}") +ENV["APPS_C_ACTION"] = Action(build_apps_c, "${APPSCOMSTR}") diff --git a/site_scons/builders.scons b/site_scons/builders.scons index b3ec270f251f..c23786c3b0bd 100644 --- a/site_scons/builders.scons +++ b/site_scons/builders.scons @@ -1,7 +1,7 @@ -Import("coreenv") +Import("ENV") -coreenv.Append( +ENV.Append( BUILDERS={ "HEXBuilder": Builder( action=Action( @@ -49,11 +49,10 @@ coreenv.Append( } ) -if not coreenv["VERBOSE"]: - coreenv.Replace( +if not ENV["VERBOSE"]: + ENV.SetDefault( HEXCOMSTR="\tHEX\t${TARGET}", BINCOMSTR="\tBIN\t${TARGET}", DFUCOMSTR="\tDFU\t${TARGET}", - STRIPCOMSTR="\tSTRIP\t${TARGET}", FLASHCOMSTR="\tFLASH\t${SOURCE}", ) diff --git a/site_scons/cc.scons b/site_scons/cc.scons index 6bdbe168de04..2f6417aa7e0e 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -1,7 +1,7 @@ -Import("coreenv") +Import("ENV") -coreenv.Append( +ENV.Append( CFLAGS=[ "-std=gnu17", ], @@ -41,18 +41,3 @@ coreenv.Append( "-mthumb", ], ) - - -# Specific flags for building libraries - always do optimized builds - -lib_flags = { - "CCFLAGS": [ - "-Os", - ], - "CPPDEFINES": [ - "NDEBUG", - "FURI_NDEBUG", - ], -} - -Export("lib_flags") diff --git a/site_scons/environ.scons b/site_scons/environ.scons index ccc0f5720083..9298991717cd 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -3,13 +3,14 @@ import SCons import sutils import os -import sys import multiprocessing vars = Variables(None, ARGUMENTS) vars.Add(BoolVariable("VERBOSE", help="Print full commands", default=0)) -vars.Add(BoolVariable("FORCE", help="Force target action", default=0)) +vars.Add( + BoolVariable("FORCE", help="Force target action (for supported targets)", default=0) +) vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) vars.Add(BoolVariable("COMPACT", help="Optimize for size", default=0)) vars.Add( @@ -42,7 +43,7 @@ coreenv = Environment( ) if not coreenv["VERBOSE"]: - coreenv.Replace( + coreenv.SetDefault( CCCOMSTR="\tCC\t${SOURCE}", CXXCOMSTR="\tCPP\t${SOURCE}", ASCOMSTR="\tASM\t${SOURCE}", @@ -52,7 +53,7 @@ if not coreenv["VERBOSE"]: INSTALLSTR="\tINSTALL\t${TARGET}", APPSCOMSTR="\tAPPS\t${TARGET}", VERSIONCOMSTR="\tVERSION\t${TARGET}", - # STRIPCOMSTR="\tSTRIP\t${TARGET}", + STRIPCOMSTR="\tSTRIP\t${TARGET}", ) if coreenv["PLATFORM"] == "win32": @@ -107,7 +108,7 @@ def GlobRecursive(env, pattern, node=".", exclude=None): node = Dir(node) for f in node.glob("*", source=True, exclude=exclude): if isinstance(f, SCons.Node.FS.Dir): - results += coreenv.GlobRecursive(pattern, f, exclude) + results += env.GlobRecursive(pattern, f, exclude) results += node.glob( pattern, source=True, @@ -146,8 +147,18 @@ def BuildModules(env, modules): return result +def ApplyLibFlags(env): + flags_to_apply = env["FW_LIB_OPTS"].get( + env.get("FW_LIB_NAME"), + env["FW_LIB_OPTS"]["Default"], + ) + # print("Flags for ", env.get("FW_LIB_NAME", "Default"), flags_to_apply) + env.MergeFlags(flags_to_apply) + + coreenv.AddMethod(GlobRecursive) +coreenv.AddMethod(ApplyLibFlags) coreenv.AddMethod(BuildModule) coreenv.AddMethod(BuildModules) -Export("coreenv") +Return("coreenv") diff --git a/site_scons/firmwareopts.scons b/site_scons/firmwareopts.scons index fc461c329ff0..d0b0fb95c483 100644 --- a/site_scons/firmwareopts.scons +++ b/site_scons/firmwareopts.scons @@ -1,8 +1,8 @@ -Import("fwenv") +Import("ENV") -if fwenv["DEBUG"]: - fwenv.Append( +if ENV["DEBUG"]: + ENV.Append( CPPDEFINES=[ "FURI_DEBUG", "NDEBUG", @@ -12,8 +12,8 @@ if fwenv["DEBUG"]: "-g", ], ) -elif fwenv["COMPACT"]: - fwenv.Append( +elif ENV["COMPACT"]: + ENV.Append( CPPDEFINES=[ "FURI_NDEBUG", "NDEBUG", @@ -24,7 +24,7 @@ elif fwenv["COMPACT"]: ], ) else: - fwenv.Append( + ENV.Append( CPPDEFINES=[ "FURI_NDEBUG", "NDEBUG", @@ -35,20 +35,20 @@ else: ], ) -fwenv.Append( +ENV.Append( OPENOCD_OPTS='-f interface/stlink.cfg -c "transport select hla_swd" -f debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init"', LINKFLAGS=[ "-Tfirmware/targets/f${TARGET_HW}/${LINKER_SCRIPT}.ld", ], ) -if fwenv["FIRMWARE_BUILD_CFG"] == "updater": - fwenv.Append( +if ENV["FIRMWARE_BUILD_CFG"] == "updater": + ENV.Append( IMAGE_BASE_ADDRESS="0x20000000", LINKER_SCRIPT="stm32wb55xx_ram_fw", ) else: - fwenv.Append( + ENV.Append( IMAGE_BASE_ADDRESS="0x8000000", LINKER_SCRIPT="stm32wb55xx_flash", ) From 6cd97cf348c44c4109fb20b86f5b36df2b112101 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 19:47:54 +0400 Subject: [PATCH 092/184] Build: comments in main SConstruct --- SConstruct | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index 2cedceaffbb6..24a0e50c8016 100644 --- a/SConstruct +++ b/SConstruct @@ -1,5 +1,13 @@ +# Main Fipper Build System entry point. +# +# This file is evaluated every time every time scons is invoked. +# scons bulds all referenced environments & their targets' dependency trees +# on startup. So, to keep startup time as low as possible, we're hiding +# construction of certain targets behind command-line options. + import os +# To build updater-related targets, we need to set this option AddOption( "--with-updater", dest="fullenv", @@ -7,12 +15,16 @@ AddOption( help="Full firmware environment", ) +# Building basic environment - tools, utility methods, cross-compilation +# settings, gcc flags for Cortex-M4, basic builders and more coreenv = SConscript("site_scons/environ.scons") SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) SConscript("site_scons/builders.scons", exports={"ENV": coreenv}) -# Progress(["-\r", "\\\r", "|\r", "/\r"], interval=5) +Progress(["-\r", "\\\r", "|\r", "/\r"], interval=5) + +# Variant dir setup variant_dir_name = f"f{coreenv.subst('$TARGET_HW')}-FWTYPE" suffix = "" if coreenv["DEBUG"]: @@ -22,9 +34,12 @@ if coreenv["COMPACT"]: if suffix: variant_dir_name += "-" + suffix +# Store root dir in environment for certain tools coreenv["ROOT_DIR"] = Dir(".") +# Prepare variant dir for current configuration build_path = os.path.join(Dir(".").abspath, "build", variant_dir_name) +# Configure basic firmware targets firmware = SConscript( "firmware.scons", variant_dir=build_path.replace("FWTYPE", "firmware"), @@ -39,6 +54,7 @@ firmware = SConscript( ) Default(firmware) +# If enabled, configure updater-related targets if GetOption("fullenv"): updater = SConscript( "firmware.scons", From 3528da2a90daaadc7487c28da337d9dcf821c2bb Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 19:55:36 +0400 Subject: [PATCH 093/184] Build: fixed typos --- SConstruct | 7 ++++--- site_scons/appmanifests.scons | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/SConstruct b/SConstruct index 24a0e50c8016..e2a0fec6d151 100644 --- a/SConstruct +++ b/SConstruct @@ -1,13 +1,13 @@ # Main Fipper Build System entry point. # # This file is evaluated every time every time scons is invoked. -# scons bulds all referenced environments & their targets' dependency trees +# scons builds all referenced environments & their targets' dependency trees # on startup. So, to keep startup time as low as possible, we're hiding # construction of certain targets behind command-line options. import os -# To build updater-related targets, we need to set this option +# To build updater-related targets, you need to set this option AddOption( "--with-updater", dest="fullenv", @@ -15,6 +15,7 @@ AddOption( help="Full firmware environment", ) + # Building basic environment - tools, utility methods, cross-compilation # settings, gcc flags for Cortex-M4, basic builders and more coreenv = SConscript("site_scons/environ.scons") @@ -22,7 +23,7 @@ SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) SConscript("site_scons/builders.scons", exports={"ENV": coreenv}) -Progress(["-\r", "\\\r", "|\r", "/\r"], interval=5) +Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) # Variant dir setup variant_dir_name = f"f{coreenv.subst('$TARGET_HW')}-FWTYPE" diff --git a/site_scons/appmanifests.scons b/site_scons/appmanifests.scons index 8e36f4b132ff..d974e1393570 100644 --- a/site_scons/appmanifests.scons +++ b/site_scons/appmanifests.scons @@ -38,7 +38,7 @@ ENV.AddMethod(PrepareApplicationsBuild) def build_apps_c(target, source, env): target_file_name = target[0].path - gen = ApplicationsCGenerator(fwenv["APPBUILD"]) + gen = ApplicationsCGenerator(env["APPBUILD"]) with open(target_file_name, "w") as file: file.write(gen.generate()) From e2cc0ce8565b5adaae1b31445e61e4eb8aa56802 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 20:01:20 +0400 Subject: [PATCH 094/184] Build: disabled progress indicator for speed-up --- SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index e2a0fec6d151..b4da5aab44bb 100644 --- a/SConstruct +++ b/SConstruct @@ -23,7 +23,7 @@ SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) SConscript("site_scons/builders.scons", exports={"ENV": coreenv}) -Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) +# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) # Variant dir setup variant_dir_name = f"f{coreenv.subst('$TARGET_HW')}-FWTYPE" From 8655ea560a53ee5e1ee1ab4c343d7ebd5a7b8afa Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Sat, 11 Jun 2022 13:19:45 -0400 Subject: [PATCH 095/184] Add windows toolchain download part --- .gitattributes | 1 + .../generate-toolchain-download.sh | 6 ++--- .../unix-toolchain-download.sh | 0 scripts/windows-toolchain-download.ps1 | 25 +++++++++++++++++++ toolchain-download.sh.bat | 4 +-- 5 files changed, 31 insertions(+), 5 deletions(-) rename {toolchain/scripts => scripts}/generate-toolchain-download.sh (81%) rename {toolchain/scripts => scripts}/unix-toolchain-download.sh (100%) create mode 100644 scripts/windows-toolchain-download.ps1 diff --git a/.gitattributes b/.gitattributes index b3faf6d84f72..88971893a741 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ * text=auto eol=lf *.sh.bat binary +*.ps1 eol=crlf diff --git a/toolchain/scripts/generate-toolchain-download.sh b/scripts/generate-toolchain-download.sh similarity index 81% rename from toolchain/scripts/generate-toolchain-download.sh rename to scripts/generate-toolchain-download.sh index e9e5ad580098..e19ec3de9b42 100755 --- a/toolchain/scripts/generate-toolchain-download.sh +++ b/scripts/generate-toolchain-download.sh @@ -1,6 +1,6 @@ #!/bin/bash SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; -PROJECT_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; +PROJECT_ROOT="$(cd "$SCRIPT_PATH/../" && pwd)"; printf "echo >/dev/null # >nul & GOTO WINDOWS & rem ^\r\n" > "$PROJECT_ROOT/toolchain-download.sh.bat" printf "# ***********************************************************\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "# * NOTE: If you modify this content, be sure to remove carriage returns (\\\r)\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" @@ -9,11 +9,11 @@ printf "# * (\\\n) for the Windows part. In summary:\n" >> "$PROJECT_ROOT/ printf "# * New lines in Linux: \\\n\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "# * New lines in Windows: \\\r\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "# ***********************************************************\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "toolchain/scripts/unix-toolchain-download.sh\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "scripts/unix-toolchain-download.sh\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "exit 0\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf ":WINDOWS\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "@echo off\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "cls\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "powershell -ExecutionPolicy Bypass -File toolchain\\\scripts\\\windows-toolchain-download.ps1\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "powershell -ExecutionPolicy Bypass -File scripts\\\windows-toolchain-download.ps1\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" chmod +x "$PROJECT_ROOT/toolchain-download.sh.bat" diff --git a/toolchain/scripts/unix-toolchain-download.sh b/scripts/unix-toolchain-download.sh similarity index 100% rename from toolchain/scripts/unix-toolchain-download.sh rename to scripts/unix-toolchain-download.sh diff --git a/scripts/windows-toolchain-download.ps1 b/scripts/windows-toolchain-download.ps1 new file mode 100644 index 000000000000..38b45477410a --- /dev/null +++ b/scripts/windows-toolchain-download.ps1 @@ -0,0 +1,25 @@ +Set-StrictMode -Version 2.0 +$ErrorActionPreference = "Stop" +[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" +$repo_root = (Get-Item "$PSScriptRoot\..").FullName +$toolchain_url = "https://github.com/flipperdevices/flipperzero-firmware/archive/refs/tags/0.60.0-rc.zip" +$toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-win32.zip" + +if (Test-Path -LiteralPath "$repo_root\toolchain") { + Write-Host -NoNewline "Removing old Windows toolchain.." + Remove-Item -LiteralPath "$repo_root\toolchain" -Force -Recurse + Write-Host "done!" +} + +Write-Host -NoNewline "Downloading Windows toolchain.." +Invoke-WebRequest -Uri "$toolchain_url" -OutFile "$repo_root\$toolchain_zip" +Write-Host "done!" + +Write-Host -NoNewline "Unziping Windows toolchain.." +Expand-Archive -LiteralPath "$toolchain_zip" -DestinationPath "$repo_root\" -Force +Rename-Item "$repo_root\flipperzero-firmware-0.60.0-rc" "$repo_root\toolchain" +Write-Host "done!" + +Write-Host -NoNewline "Clearing temporary files.." +Remove-Item -LiteralPath "$repo_root\$toolchain_zip" -Force +Write-Host "done!" \ No newline at end of file diff --git a/toolchain-download.sh.bat b/toolchain-download.sh.bat index 79f6e7d37e7b..292d71b571fd 100755 --- a/toolchain-download.sh.bat +++ b/toolchain-download.sh.bat @@ -6,9 +6,9 @@ echo >/dev/null # >nul & GOTO WINDOWS & rem ^ # * New lines in Linux: \n\n # * New lines in Windows: \r\n # *********************************************************** -toolchain/scripts/unix-toolchain-download.sh +scripts/unix-toolchain-download.sh exit 0 :WINDOWS @echo off cls -powershell -ExecutionPolicy Bypass -File toolchain\scripts\windows-toolchain-download.ps1 +powershell -ExecutionPolicy Bypass -File scripts\windows-toolchain-download.ps1 From ab25ec0973357a22594a2ac4a752cca180e80372 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Sat, 11 Jun 2022 13:23:06 -0400 Subject: [PATCH 096/184] restructuring toolchain scripts --- scripts/{ => toolchain}/generate-toolchain-download.sh | 6 +++--- scripts/{ => toolchain}/unix-toolchain-download.sh | 0 scripts/{ => toolchain}/windows-toolchain-download.ps1 | 0 toolchain-download.sh.bat | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) rename scripts/{ => toolchain}/generate-toolchain-download.sh (81%) rename scripts/{ => toolchain}/unix-toolchain-download.sh (100%) rename scripts/{ => toolchain}/windows-toolchain-download.ps1 (100%) diff --git a/scripts/generate-toolchain-download.sh b/scripts/toolchain/generate-toolchain-download.sh similarity index 81% rename from scripts/generate-toolchain-download.sh rename to scripts/toolchain/generate-toolchain-download.sh index e19ec3de9b42..8498ba825740 100755 --- a/scripts/generate-toolchain-download.sh +++ b/scripts/toolchain/generate-toolchain-download.sh @@ -1,6 +1,6 @@ #!/bin/bash SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; -PROJECT_ROOT="$(cd "$SCRIPT_PATH/../" && pwd)"; +PROJECT_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; printf "echo >/dev/null # >nul & GOTO WINDOWS & rem ^\r\n" > "$PROJECT_ROOT/toolchain-download.sh.bat" printf "# ***********************************************************\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "# * NOTE: If you modify this content, be sure to remove carriage returns (\\\r)\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" @@ -9,11 +9,11 @@ printf "# * (\\\n) for the Windows part. In summary:\n" >> "$PROJECT_ROOT/ printf "# * New lines in Linux: \\\n\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "# * New lines in Windows: \\\r\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "# ***********************************************************\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "scripts/unix-toolchain-download.sh\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "scripts/toolchain/unix-toolchain-download.sh\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "exit 0\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf ":WINDOWS\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "@echo off\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" printf "cls\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "powershell -ExecutionPolicy Bypass -File scripts\\\windows-toolchain-download.ps1\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +printf "powershell -ExecutionPolicy Bypass -File scripts\\\toolchain\\\windows-toolchain-download.ps1\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" chmod +x "$PROJECT_ROOT/toolchain-download.sh.bat" diff --git a/scripts/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh similarity index 100% rename from scripts/unix-toolchain-download.sh rename to scripts/toolchain/unix-toolchain-download.sh diff --git a/scripts/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 similarity index 100% rename from scripts/windows-toolchain-download.ps1 rename to scripts/toolchain/windows-toolchain-download.ps1 diff --git a/toolchain-download.sh.bat b/toolchain-download.sh.bat index 292d71b571fd..21dd1684f508 100755 --- a/toolchain-download.sh.bat +++ b/toolchain-download.sh.bat @@ -6,9 +6,9 @@ echo >/dev/null # >nul & GOTO WINDOWS & rem ^ # * New lines in Linux: \n\n # * New lines in Windows: \r\n # *********************************************************** -scripts/unix-toolchain-download.sh +scripts/toolchain/unix-toolchain-download.sh exit 0 :WINDOWS @echo off cls -powershell -ExecutionPolicy Bypass -File scripts\windows-toolchain-download.ps1 +powershell -ExecutionPolicy Bypass -File scripts\toolchain\windows-toolchain-download.ps1 From ac27b039f22df594a09870abd9de795842d9c5ac Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Sat, 11 Jun 2022 13:27:03 -0400 Subject: [PATCH 097/184] Fix toolchain windows script path --- scripts/toolchain/windows-toolchain-download.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index 38b45477410a..cd9bbcdf84c0 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -1,7 +1,7 @@ Set-StrictMode -Version 2.0 $ErrorActionPreference = "Stop" [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" -$repo_root = (Get-Item "$PSScriptRoot\..").FullName +$repo_root = (Get-Item "$PSScriptRoot\..\..").FullName $toolchain_url = "https://github.com/flipperdevices/flipperzero-firmware/archive/refs/tags/0.60.0-rc.zip" $toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-win32.zip" From 1111503bd272f488c638266c56c2a3a95f0a7367 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 21:29:35 +0400 Subject: [PATCH 098/184] Build: generating version.json with version.inc.h; removed hardware target from global definitions; fixed dev_info_service.c to use version API --- firmware.scons | 2 +- .../targets/f7/ble_glue/dev_info_service.c | 13 +++-- lib/toolbox/SConscript | 41 +++++---------- scripts/version.py | 51 ++++++++++++++----- site_scons/fbt/builders/version.py | 50 ++++++++++++++++++ 5 files changed, 113 insertions(+), 44 deletions(-) create mode 100644 site_scons/fbt/builders/version.py diff --git a/firmware.scons b/firmware.scons index 5b538243b110..92bac11f746e 100644 --- a/firmware.scons +++ b/firmware.scons @@ -15,7 +15,7 @@ env.Append( "${LIB_DIST_DIR}", ], CPPDEFINES=[ - ("TARGET", "${TARGET_HW}"), + # ("TARGET", "${TARGET_HW}"), ], CPPPATH=[ "#/core", diff --git a/firmware/targets/f7/ble_glue/dev_info_service.c b/firmware/targets/f7/ble_glue/dev_info_service.c index 766c4b40f4ac..d6d1e479ef88 100755 --- a/firmware/targets/f7/ble_glue/dev_info_service.c +++ b/firmware/targets/f7/ble_glue/dev_info_service.c @@ -17,13 +17,13 @@ typedef struct { uint16_t software_rev_char_handle; uint16_t rpc_version_char_handle; string_t version_string; + char hardware_revision[4]; } DevInfoSvc; static DevInfoSvc* dev_info_svc = NULL; static const char dev_info_man_name[] = "Flipper Devices Inc."; static const char dev_info_serial_num[] = "1.0"; -static const char dev_info_firmware_rev_num[] = TOSTRING(TARGET); static const char dev_info_rpc_version[] = TOSTRING(PROTOBUF_MAJOR_VERSION.PROTOBUF_MINOR_VERSION); static const uint8_t dev_info_rpc_version_uuid[] = @@ -38,6 +38,11 @@ void dev_info_svc_start() { version_get_gitbranch(NULL), version_get_gitbranchnum(NULL), version_get_builddate(NULL)); + snprintf( + dev_info_svc->hardware_revision, + sizeof(dev_info_svc->hardware_revision), + "%d", + version_get_target(NULL)); tBleStatus status; // Add Device Information Service @@ -84,7 +89,7 @@ void dev_info_svc_start() { dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(dev_info_firmware_rev_num), + strlen(dev_info_svc->hardware_revision), CHAR_PROP_READ, ATTR_PERMISSION_AUTHEN_READ, GATT_DONT_NOTIFY_EVENTS, @@ -147,8 +152,8 @@ void dev_info_svc_start() { dev_info_svc->service_handle, dev_info_svc->firmware_rev_char_handle, 0, - strlen(dev_info_firmware_rev_num), - (uint8_t*)dev_info_firmware_rev_num); + strlen(dev_info_svc->hardware_revision), + (uint8_t*)dev_info_svc->hardware_revision); if(status) { FURI_LOG_E(TAG, "Failed to update firmware revision char: %d", status); } diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 2bfce7bec262..0066ff4aa81a 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -1,7 +1,7 @@ Import("env") -import subprocess -import datetime +from fbt.builders.version import add_version_builders, get_fast_git_version_id + env.Append( CPPPATH=[ @@ -13,38 +13,25 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="toolbox") libenv.ApplyLibFlags() +add_version_builders(libenv) + # Git Version management version_depends = [] -try: - version = ( - subprocess.check_output( - [ - "git", - "describe", - "--always", - "--dirty", - "--all", - "--long", - ] - ) - .strip() - .decode() - ) - version_depends = Value((version, datetime.date.today())) - # print(version_depends) -except Exception as e: - print("Failed to check for git changes", e) +version_id_data = get_fast_git_version_id() +if version_id_data: + version_depends = Value(version_id_data) # Only invoke version generator if preliminary check target (version_depends) has changed -build_version = libenv.Command( - "version.inc.h", +build_version = libenv.VersionBuilder( + Dir("."), version_depends, - Action( - "${PYTHON3} ${ROOT_DIR.abspath}/scripts/version.py generate -o ${TARGET} --dir ${ROOT_DIR}", - "${VERSIONCOMSTR}", - ), ) +# AddPostAction(build_version, libenv.Install("${BUILD_DIR}", "version.json")) +libenv.Install("${BUILD_DIR}", "version.json") + + +# if True: if not version_depends: libenv.Precious(build_version) libenv.AlwaysBuild(build_version) diff --git a/scripts/version.py b/scripts/version.py index 82737a119748..bc12fbb02ff3 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -4,6 +4,7 @@ import subprocess import os +import json from datetime import date @@ -23,7 +24,6 @@ def get_version_info(self): branch = self._exec_git("rev-parse --abbrev-ref HEAD") or "unknown" branch_num = self._exec_git("rev-list --count HEAD") or "n/a" - build_date = date.today().isoformat() try: version = self._exec_git("describe --tags --abbrev=0 --exact-match") @@ -31,11 +31,10 @@ def get_version_info(self): version = "unknown" return { - "GIT_COMMIT": f'"{commit}"', - "GIT_BRANCH": f'"{branch}"', - "GIT_BRANCH_NUM": f'"{branch_num}"', - "VERSION": f'"{version}"', - "BUILD_DATE": f'"{build_date}"', + "GIT_COMMIT": commit, + "GIT_BRANCH": branch, + "GIT_BRANCH_NUM": branch_num, + "VERSION": version, "BUILD_DIRTY": dirty and 1 or 0, } @@ -58,21 +57,41 @@ def init(self): "generate", help="Generate version header" ) - self.parser_generate.add_argument("-o", dest="output", required=True) + self.parser_generate.add_argument("-o", dest="outdir", required=True) + self.parser_generate.add_argument( + "-t", + dest="target", + type=int, + help="hardware target", + required=True, + ) self.parser_generate.add_argument("--dir", dest="sourcedir", required=True) self.parser_generate.set_defaults(func=self.generate) def generate(self): current_info = GitVersion(self.args.sourcedir).get_version_info() - new_version_info_fmt = ( - "\n".join(f"#define {key} {current_info[key]}" for key in current_info) - + "\n" + current_info.update( + { + "BUILD_DATE": date.today().strftime("%d-%m-%Y"), + "TARGET": self.args.target, + } ) + version_values = [] + for key in current_info: + val = current_info[key] + if isinstance(val, str): + val = f'"{val}"' + version_values.append(f"#define {key} {val}") + + new_version_info_fmt = "\n".join(version_values) + "\n" + current_version_info = None + version_header_name = os.path.join(self.args.outdir, "version.inc.h") + version_json_name = os.path.join(self.args.outdir, "version.json") try: - with open(self.args.output, "r") as file: + with open(version_header_name, "r") as file: current_version_info = file.read() except EnvironmentError as e: if self.args.debug: @@ -82,7 +101,7 @@ def generate(self): if self.args.debug: print("old: ", current_version_info) print("new: ", new_version_info_fmt) - with open(self.args.output, "w", newline="\n") as file: + with open(version_header_name, "w", newline="\n") as file: file.write(new_version_info_fmt) # os.utime("../lib/toolbox/version.c", None) print("Version information updated") @@ -90,6 +109,14 @@ def generate(self): if self.args.debug: print("Version information hasn't changed") + version_json = { + "firmware_build_date": current_info["BUILD_DATE"], + "firmware_commit": current_info["GIT_COMMIT"], + "firmware_branch": current_info["GIT_BRANCH"], + "firmware_target": current_info["TARGET"], + } + with open(version_json_name, "w", newline="\n") as file: + json.dump(version_json, file, indent=4) return 0 diff --git a/site_scons/fbt/builders/version.py b/site_scons/fbt/builders/version.py new file mode 100644 index 000000000000..82a028ee3229 --- /dev/null +++ b/site_scons/fbt/builders/version.py @@ -0,0 +1,50 @@ +import SCons +from SCons.Builder import Builder +from SCons.Action import Action + +import subprocess +import datetime + + +def get_fast_git_version_id(): + try: + version = ( + subprocess.check_output( + [ + "git", + "describe", + "--always", + "--dirty", + "--all", + "--long", + ] + ) + .strip() + .decode() + ) + return (version, datetime.date.today()) + except Exception as e: + print("Failed to check for git changes", e) + + +def version_emitter(target, source, env): + target_dir = target[0] + target = [ + target_dir.File("version.inc.h"), + target_dir.File("version.json"), + ] + return target, source + + +def add_version_builders(env): + env.Append( + BUILDERS={ + "VersionBuilder": Builder( + action=Action( + "${PYTHON3} ${ROOT_DIR.abspath}/scripts/version.py generate -t ${TARGET_HW} -o ${TARGET.dir.posix} --dir ${ROOT_DIR}", + "${VERSIONCOMSTR}", + ), + emitter=version_emitter, + ), + } + ) From ff22b7fa67bcf5d081d80c14529431e96e257032 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 21:38:32 +0400 Subject: [PATCH 099/184] Build: always copying version.json to build dir --- lib/toolbox/SConscript | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 0066ff4aa81a..5e2f807edf33 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -27,11 +27,9 @@ build_version = libenv.VersionBuilder( version_depends, ) -# AddPostAction(build_version, libenv.Install("${BUILD_DIR}", "version.json")) -libenv.Install("${BUILD_DIR}", "version.json") +Default(libenv.InstallAs("${BUILD_DIR}/${FIRMWARE_BUILD_CFG}.json", "version.json")) -# if True: if not version_depends: libenv.Precious(build_version) libenv.AlwaysBuild(build_version) From f2f34c12755478609e26b0e6a0919fb8e4c73726 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 22:00:25 +0400 Subject: [PATCH 100/184] Build: reverted broken firmware_extapps build --- firmware.scons | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/firmware.scons b/firmware.scons index 92bac11f746e..4bfa6e08574a 100644 --- a/firmware.scons +++ b/firmware.scons @@ -108,6 +108,10 @@ else: fwenv.LoadApplicationManifests() fwenv.PrepareApplicationsBuild() +# Clone current environment to build external apps later with its current state +appenv = fwenv.Clone() + + # Add preprocessor definitions for current set of apps fwenv.Append( CPPDEFINES=fwenv["APPBUILD"].get_apps_cdefs(), @@ -128,8 +132,6 @@ sources = [apps_c] for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder)) -# Clone current environment to build external apps later with its current state -appenv = fwenv.Clone() fwenv.Append( LINKFLAGS=[ @@ -208,7 +210,7 @@ Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", cdb) # Building external applications appenv.VariantDir("extapps", "applications", duplicate=False) -appenv.SetDefault( +appenv.Replace( LINKER_SCRIPT="application-ext", STRIPFLAGS=[ "--strip-debug", @@ -218,6 +220,7 @@ appenv.SetDefault( "-S", ], ) + appenv.Append( CCFLAGS=[ "-Os", From 928f703373653177dc33ebea51b6e58730f1870c Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 11 Jun 2022 23:19:24 +0400 Subject: [PATCH 101/184] Build: added version.json to firmware output targets; minor SConstruct refactoring --- SConstruct | 54 ++++++++++++----------------------- firmware.scons | 9 +++--- lib/toolbox/SConscript | 7 ++++- site_scons/cc.scons | 2 +- site_scons/fbt/appmanifest.py | 12 +++++--- site_scons/sutils.py | 12 ++++++++ 6 files changed, 51 insertions(+), 45 deletions(-) diff --git a/SConstruct b/SConstruct index b4da5aab44bb..3c2b8ce67dbe 100644 --- a/SConstruct +++ b/SConstruct @@ -5,6 +5,8 @@ # on startup. So, to keep startup time as low as possible, we're hiding # construction of certain targets behind command-line options. +from sutils import get_variant_dirname + import os # To build updater-related targets, you need to set this option @@ -22,50 +24,32 @@ coreenv = SConscript("site_scons/environ.scons") SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) SConscript("site_scons/builders.scons", exports={"ENV": coreenv}) +# Store root dir in environment for certain tools +coreenv["ROOT_DIR"] = Dir(".") # Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) -# Variant dir setup -variant_dir_name = f"f{coreenv.subst('$TARGET_HW')}-FWTYPE" -suffix = "" -if coreenv["DEBUG"]: - suffix += "D" -if coreenv["COMPACT"]: - suffix += "C" -if suffix: - variant_dir_name += "-" + suffix -# Store root dir in environment for certain tools -coreenv["ROOT_DIR"] = Dir(".") # Prepare variant dir for current configuration -build_path = os.path.join(Dir(".").abspath, "build", variant_dir_name) - -# Configure basic firmware targets -firmware = SConscript( - "firmware.scons", - variant_dir=build_path.replace("FWTYPE", "firmware"), - duplicate=0, - exports={ - "ENV": coreenv, - "fw_build_meta": { - "type": "firmware", - "build_dir": build_path.replace("FWTYPE", "firmware"), - }, - }, -) -Default(firmware) - -# If enabled, configure updater-related targets -if GetOption("fullenv"): - updater = SConscript( +def create_fw_build_targets(env, configuration_name): + build_dir = Dir("build").Dir(get_variant_dirname(env, "firmware")).abspath + return SConscript( "firmware.scons", - variant_dir=build_path.replace("FWTYPE", "updater"), + variant_dir=build_dir, duplicate=0, exports={ - "ENV": coreenv, + "ENV": env, "fw_build_meta": { - "type": "updater", - "build_dir": build_path.replace("FWTYPE", "updater"), + "type": "firmware", + "build_dir": build_dir, }, }, ) + + +firmware = create_fw_build_targets(coreenv, "firmware") +Default(firmware) + +# If enabled, configure updater-related targets +if GetOption("fullenv"): + updater = create_fw_build_targets(coreenv, "updater") diff --git a/firmware.scons b/firmware.scons index 4bfa6e08574a..d52a1f76978e 100644 --- a/firmware.scons +++ b/firmware.scons @@ -113,7 +113,7 @@ appenv = fwenv.Clone() # Add preprocessor definitions for current set of apps -fwenv.Append( +fwenv.AppendUnique( CPPDEFINES=fwenv["APPBUILD"].get_apps_cdefs(), ) @@ -133,7 +133,7 @@ for app_folder in fwenv["APPBUILD"].get_builtin_app_folders(): sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder)) -fwenv.Append( +fwenv.AppendUnique( LINKFLAGS=[ "-specs=nano.specs", "-specs=nosys.specs", @@ -221,7 +221,7 @@ appenv.Replace( ], ) -appenv.Append( +appenv.AppendUnique( CCFLAGS=[ "-Os", "-ggdb3", @@ -257,4 +257,5 @@ for app in appenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) -Return("fwhex fwelf fwbin") +fw_version_json = env["FW_VERSION_JSON"] +Return("fwhex fwelf fwbin fw_version_json") diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 5e2f807edf33..809a7f92ee74 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -27,7 +27,12 @@ build_version = libenv.VersionBuilder( version_depends, ) -Default(libenv.InstallAs("${BUILD_DIR}/${FIRMWARE_BUILD_CFG}.json", "version.json")) +fw_version_json = libenv.InstallAs( + "${BUILD_DIR}/${FIRMWARE_BUILD_CFG}.json", "version.json" +) +env.Append(FW_VERSION_JSON=fw_version_json) + +# Default(fw_version_json) if not version_depends: diff --git a/site_scons/cc.scons b/site_scons/cc.scons index 2f6417aa7e0e..144e5c8464bb 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -1,7 +1,7 @@ Import("ENV") -ENV.Append( +ENV.AppendUnique( CFLAGS=[ "-std=gnu17", ], diff --git a/site_scons/fbt/appmanifest.py b/site_scons/fbt/appmanifest.py index ce3e46def4a2..218b139f3edb 100644 --- a/site_scons/fbt/appmanifest.py +++ b/site_scons/fbt/appmanifest.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import List, Set, Dict, Tuple, Optional +from typing import List, Optional from enum import Enum import os @@ -77,13 +77,17 @@ def App(*args, **kw): def _add_known_app(self, app: FlipperApplication): if self.known_apps.get(app.appid, None): - raise Exception(f"Duplicate app declaration: {app.appid}") + raise FlipperManifestException(f"Duplicate app declaration: {app.appid}") self.known_apps[app.appid] = app def filter_apps(self, applist: List[str]): return AppBuildset(self, applist) +class AppBuilderException(Exception): + pass + + class AppBuildset: BUILTIN_APP_TYPES = ( FlipperAppType.SERVICE, @@ -140,7 +144,7 @@ def _check_conflicts(self): conflicts.append((app, conflict_app_name)) if len(conflicts): - raise Exception( + raise AppBuilderException( f"App conflicts for {', '.join(f'{conflict_dep[0]}: {conflict_dep[1]}' for conflict_dep in conflicts)}" ) @@ -153,7 +157,7 @@ def _check_unsatisfied(self): unsatisfied.append((app, missing_dep)) if len(unsatisfied): - raise Exception( + raise AppBuilderException( f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" ) diff --git a/site_scons/sutils.py b/site_scons/sutils.py index a9b667e40e6a..22d19c455cc7 100644 --- a/site_scons/sutils.py +++ b/site_scons/sutils.py @@ -23,3 +23,15 @@ def prefix_commands(env, command_prefix, cmd_list): for command in cmd_list: if command in env: env[command] = command_prefix + env[command] + + +def get_variant_dirname(env, project): + dir_name = f"f{env['TARGET_HW']}-{project}" + suffix = "" + if env["DEBUG"]: + suffix += "D" + if env["COMPACT"]: + suffix += "C" + if suffix: + dir_name += "-" + suffix + return dir_name From 02c300fc3c9ee7df2eaaf0f70a8aa89182db989b Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 12 Jun 2022 17:35:35 +0400 Subject: [PATCH 102/184] Build: fixed updater configuration; moved external apps-related code to extapps.scons; minor refactoring --- SConstruct | 22 +++++---- applications/extapps.scons | 62 ++++++++++++++++++++++++ firmware.scons | 67 ++++++-------------------- site_scons/appmanifests.scons | 2 +- site_scons/environ.scons | 10 ++-- site_scons/fbt/fwbuild.py | 18 +++++++ site_scons/{sutils.py => fbt/utils.py} | 12 +++-- 7 files changed, 121 insertions(+), 72 deletions(-) create mode 100644 applications/extapps.scons create mode 100644 site_scons/fbt/fwbuild.py rename site_scons/{sutils.py => fbt/utils.py} (80%) diff --git a/SConstruct b/SConstruct index 3c2b8ce67dbe..dd84b10d414c 100644 --- a/SConstruct +++ b/SConstruct @@ -1,11 +1,13 @@ +# # Main Fipper Build System entry point. # -# This file is evaluated every time every time scons is invoked. -# scons builds all referenced environments & their targets' dependency trees -# on startup. So, to keep startup time as low as possible, we're hiding +# This file is evaluated every time scons is invoked. +# Scons constructs all referenced environments & their targets' dependency +# trees on startup. So, to keep startup time as low as possible, we're hiding # construction of certain targets behind command-line options. -from sutils import get_variant_dirname +from fbt.utils import get_variant_dirname +from SCons.Action import CommandGeneratorAction import os @@ -30,9 +32,9 @@ coreenv["ROOT_DIR"] = Dir(".") # Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) -# Prepare variant dir for current configuration +# Prepare variant dir for given fw configuration & current options def create_fw_build_targets(env, configuration_name): - build_dir = Dir("build").Dir(get_variant_dirname(env, "firmware")).abspath + build_dir = Dir("build").Dir(get_variant_dirname(env, configuration_name)).abspath return SConscript( "firmware.scons", variant_dir=build_dir, @@ -40,16 +42,16 @@ def create_fw_build_targets(env, configuration_name): exports={ "ENV": env, "fw_build_meta": { - "type": "firmware", + "type": configuration_name, "build_dir": build_dir, }, }, ) -firmware = create_fw_build_targets(coreenv, "firmware") -Default(firmware) +firmware_out = create_fw_build_targets(coreenv, "firmware") +Default(firmware_out.artifacts) # If enabled, configure updater-related targets if GetOption("fullenv"): - updater = create_fw_build_targets(coreenv, "updater") + updater_out = create_fw_build_targets(coreenv, "updater") diff --git a/applications/extapps.scons b/applications/extapps.scons new file mode 100644 index 000000000000..6eca822ed4fc --- /dev/null +++ b/applications/extapps.scons @@ -0,0 +1,62 @@ +Import("ENV") + + +from fbt.appmanifest import FlipperAppType +import os + +appenv = ENV.Clone() + +EXT_APPS_WORK_DIR = ".extapps" + +appenv.VariantDir(EXT_APPS_WORK_DIR, ".", duplicate=False) +appenv.Replace( + LINKER_SCRIPT="application-ext", + STRIPFLAGS=[ + "--strip-debug", + "--strip-unneeded", + "-d", + "-g", + "-S", + ], +) + +appenv.AppendUnique( + CCFLAGS=[ + "-Os", + "-ggdb3", + "-mword-relocations", + "-mlong-calls", + "-fno-common", + "-nostdlib", + "-fvisibility=hidden", + ], + LINKFLAGS=[ + "-r", + "-s", + # "-Bsymbolic", + "-nostartfiles", + "-mlong-calls", + "-fno-common", + "-nostdlib", + "-Wl,--gc-sections", + "-Wl,--no-export-dynamic", + "-fvisibility=hidden", + "-Wl,-e${APP_ENTRY}", + ], +) + +extapps = [] +for app in appenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): + app_elf = appenv.Program( + os.path.join(EXT_APPS_WORK_DIR, app.appid), + appenv.GlobRecursive("*.c*", os.path.join(EXT_APPS_WORK_DIR, app._appdir)), + APP_ENTRY=app.entry_point, + ) + app_stripped_elf = appenv.ELFStripper( + os.path.join(appenv["PLUGIN_ELF_DIR"], app.appid), app_elf + ) + extapps.append(app_stripped_elf) + Alias(f"{appenv['FIRMWARE_BUILD_CFG']}_{app.appid}", app_stripped_elf) + +Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) +Return("extapps") diff --git a/firmware.scons b/firmware.scons index d52a1f76978e..5166f6142fcd 100644 --- a/firmware.scons +++ b/firmware.scons @@ -2,7 +2,7 @@ Import("ENV", "fw_build_meta") import os -from fbt.appmanifest import FlipperAppType +from fbt.fwbuild import FirmwareOutput # Building initial C environment for libs env = ENV.Clone() @@ -10,6 +10,7 @@ Export("env") env.Append( BUILD_DIR=fw_build_meta["build_dir"], + PLUGIN_ELF_DIR="${BUILD_DIR}", LIB_DIST_DIR="${BUILD_DIR}/lib", LIBPATH=[ "${LIB_DIST_DIR}", @@ -108,8 +109,8 @@ else: fwenv.LoadApplicationManifests() fwenv.PrepareApplicationsBuild() -# Clone current environment to build external apps later with its current state -appenv = fwenv.Clone() +# Build external apps +extapps = SConscript("applications/extapps.scons", exports={"ENV": fwenv}) # Add preprocessor definitions for current set of apps @@ -206,56 +207,18 @@ Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) cdb = fwenv.CompilationDatabase("compile_database.json") Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", cdb) +# fw_version_json = env["FW_VERSION_JSON"] +# Return("fwhex fwelf fwbin fw_version_json") -# Building external applications - -appenv.VariantDir("extapps", "applications", duplicate=False) -appenv.Replace( - LINKER_SCRIPT="application-ext", - STRIPFLAGS=[ - "--strip-debug", - "--strip-unneeded", - "-d", - "-g", - "-S", - ], -) - -appenv.AppendUnique( - CCFLAGS=[ - "-Os", - "-ggdb3", - "-mword-relocations", - "-mlong-calls", - "-fno-common", - "-nostdlib", - "-fvisibility=hidden", - ], - LINKFLAGS=[ - "-r", - "-s", - # "-Bsymbolic", - "-nostartfiles", - "-mlong-calls", - "-fno-common", - "-nostdlib", - "-Wl,--gc-sections", - "-Wl,--no-export-dynamic", - "-fvisibility=hidden", - "-Wl,-e${APP_ENTRY}", - ], +fw_output = FirmwareOutput( + project=fwenv["FIRMWARE_BUILD_CFG"], + dfu=fwdfu[0], + elf=fwelf[0], + bin=fwbin[0], + json=env["FW_VERSION_JSON"][0], + extapps=extapps, ) -extapps = [] -for app in appenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): - app_elf = appenv.Program( - os.path.join("extapps", app.appid), - appenv.GlobRecursive("*.c*", os.path.join("extapps", app._appdir)), - APP_ENTRY=app.entry_point, - ) - extapps.append(appenv.ELFStripper(app.appid, app_elf)) -Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) - +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", fw_output.artifacts) -fw_version_json = env["FW_VERSION_JSON"] -Return("fwhex fwelf fwbin fw_version_json") +Return("fw_output") diff --git a/site_scons/appmanifests.scons b/site_scons/appmanifests.scons index d974e1393570..31a7cb103d25 100644 --- a/site_scons/appmanifests.scons +++ b/site_scons/appmanifests.scons @@ -7,7 +7,7 @@ from fbt.appmanifest import FlipperAppType, AppManager, ApplicationsCGenerator def LoadApplicationManifests(env): appmgr = env["APPMGR"] = AppManager() for entry in Glob("#/applications/*"): - if isinstance(entry, SCons.Node.FS.Dir): + if isinstance(entry, SCons.Node.FS.Dir) and not str(entry).startswith("."): appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 9298991717cd..e6fc81c21a0d 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -1,6 +1,6 @@ from SCons.Platform import TempFileMunge import SCons -import sutils +from fbt import utils import os import multiprocessing @@ -75,7 +75,7 @@ SetOption("random", 1) # Set up cross-compile tools -sutils.prefix_commands( +utils.prefix_commands( coreenv, "arm-none-eabi-", [ @@ -91,12 +91,12 @@ sutils.prefix_commands( # Setting up temp file parameters -coreenv["TEMPFILEARGESCFUNC"] = sutils.tempfile_arg_esc_func +coreenv["TEMPFILEARGESCFUNC"] = utils.tempfile_arg_esc_func # Commandline length limit hack -sutils.wrap_tempfile(coreenv, "LINKCOM") -sutils.wrap_tempfile(coreenv, "ARCOM") +utils.wrap_tempfile(coreenv, "LINKCOM") +utils.wrap_tempfile(coreenv, "ARCOM") # Build env extensions diff --git a/site_scons/fbt/fwbuild.py b/site_scons/fbt/fwbuild.py new file mode 100644 index 000000000000..8a85ec2baf6e --- /dev/null +++ b/site_scons/fbt/fwbuild.py @@ -0,0 +1,18 @@ +from dataclasses import dataclass +from typing import List, Optional, Any + + +@dataclass +class FirmwareOutput: + project: str + dfu: Optional[Any] + elf: Optional[Any] + bin: Optional[Any] + json: Optional[Any] + extapps: Optional[List[Any]] + + @property + def artifacts(self): + return list( + filter(lambda o: o is not None, (self.dfu, self.elf, self.bin, self.json)) + ) diff --git a/site_scons/sutils.py b/site_scons/fbt/utils.py similarity index 80% rename from site_scons/sutils.py rename to site_scons/fbt/utils.py index 22d19c455cc7..3ab7be8312c4 100644 --- a/site_scons/sutils.py +++ b/site_scons/fbt/utils.py @@ -25,13 +25,17 @@ def prefix_commands(env, command_prefix, cmd_list): env[command] = command_prefix + env[command] -def get_variant_dirname(env, project): - dir_name = f"f{env['TARGET_HW']}-{project}" +def get_variant_dirname(env, project=None): + parts = [f"f{env['TARGET_HW']}"] + if project: + parts.append(project) + suffix = "" if env["DEBUG"]: suffix += "D" if env["COMPACT"]: suffix += "C" if suffix: - dir_name += "-" + suffix - return dir_name + parts.append(suffix) + + return "-".join(parts) From 1a5cb396eed95a57dec80aa7d87b64c28e798f7e Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 12 Jun 2022 20:28:34 +0400 Subject: [PATCH 103/184] Build: loading options from file; added sconsdist.py script --- SConstruct | 14 ++-- assets/SConscript | 4 +- fbt_options.py | 18 +++++ firmware.scons | 10 ++- scripts/sconsdist.py | 137 +++++++++++++++++++++++++++++++++++ site_scons/commandline.scons | 87 ++++++++++++++++++++++ site_scons/environ.scons | 47 +++++------- site_scons/site_init.py | 36 +++++++++ 8 files changed, 308 insertions(+), 45 deletions(-) create mode 100644 fbt_options.py create mode 100644 scripts/sconsdist.py create mode 100644 site_scons/commandline.scons diff --git a/SConstruct b/SConstruct index dd84b10d414c..4be6e5c871ef 100644 --- a/SConstruct +++ b/SConstruct @@ -11,18 +11,14 @@ from SCons.Action import CommandGeneratorAction import os -# To build updater-related targets, you need to set this option -AddOption( - "--with-updater", - dest="fullenv", - action="store_true", - help="Full firmware environment", -) - +cmd_vars = SConscript("site_scons/commandline.scons") # Building basic environment - tools, utility methods, cross-compilation # settings, gcc flags for Cortex-M4, basic builders and more -coreenv = SConscript("site_scons/environ.scons") +coreenv = SConscript( + "site_scons/environ.scons", + exports={"VARIABLES": cmd_vars}, +) SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) SConscript("site_scons/builders.scons", exports={"ENV": coreenv}) diff --git a/assets/SConscript b/assets/SConscript index 36244e21178d..3439469225be 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -79,7 +79,7 @@ Alias("proto_ver", proto_ver) # Gather everything into a static lib assets_parts = (icons, proto, dolphin_blocking, dolphin_internal, proto_ver) -if assetsenv["FIRMWARE_BUILD_CFG"] != "updater": +if assetsenv["IS_BASE_FIRMWARE"]: assetsenv.Install("#/assets/compiled", assets_parts) assetslib = assetsenv.Library("${FW_LIB_NAME}", assets_parts) @@ -88,7 +88,7 @@ assetsenv.Install("${LIB_DIST_DIR}", assetslib) # Resources for SD card -if assetsenv["FIRMWARE_BUILD_CFG"] != "updater": +if assetsenv["IS_BASE_FIRMWARE"]: # External dolphin animations dolphin_external = assetsenv.DolphinExtBuilder( Dir("#/assets/resources/dolphin"), diff --git a/fbt_options.py b/fbt_options.py new file mode 100644 index 000000000000..a22f41fa6331 --- /dev/null +++ b/fbt_options.py @@ -0,0 +1,18 @@ +import os + +COMPACT = 1 + +COPRO_OB_DATA = "ob.data" + +COPRO_CUBE_VERSION = "1.13.3" +COPRO_MCU_FAMILY = "STM32WB5x" +COPRO_CUBE_DIR = "lib/STM32CubeWB" + +COPRO_STACK_BIN = "stm32wb5x_BLE_Stack_light_fw.bin" +COPRO_STACK_TYPE = "ble_light" +COPRO_STACK_ADDR = 0 + +COPRO_FIRMWARE_DIR = ( + f"{COPRO_CUBE_DIR}/Projects/STM32WB_Copro_Wireless_Binaries/{COPRO_MCU_FAMILY}" +) +COPRO_STACK_BIN_PATH = os.path.join(COPRO_FIRMWARE_DIR, COPRO_STACK_BIN) diff --git a/firmware.scons b/firmware.scons index 5166f6142fcd..1b00f3192b3c 100644 --- a/firmware.scons +++ b/firmware.scons @@ -12,6 +12,7 @@ env.Append( BUILD_DIR=fw_build_meta["build_dir"], PLUGIN_ELF_DIR="${BUILD_DIR}", LIB_DIST_DIR="${BUILD_DIR}/lib", + IS_BASE_FIRMWARE=fw_build_meta["type"] == "firmware", LIBPATH=[ "${LIB_DIST_DIR}", ], @@ -197,10 +198,11 @@ fwdfu = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu) # Additional FW-related pseudotargets -flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") -if fwenv["FORCE"]: - AlwaysBuild(flash) -Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) +if fwenv["IS_BASE_FIRMWARE"]: + flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") + if fwenv["FORCE"]: + AlwaysBuild(flash) + Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) # Compile DB generation diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py new file mode 100644 index 000000000000..cdcb82db11f0 --- /dev/null +++ b/scripts/sconsdist.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 + +from flipper.app import App +from os.path import join, exists +from os import makedirs +from update import Main as UpdateMain +import shutil + + +class ProjectDir: + def __init__(self, project_dir): + self.dir = project_dir + parts = project_dir.split("-") + self.target = parts[0] + self.project = parts[1] + if len(parts) > 2: + self.flavor = parts[2] + + +class Main(App): + def init(self): + self.subparsers = self.parser.add_subparsers(help="sub-command help") + + self.parser_copy = self.subparsers.add_parser( + "copy", help="Copy firmware binaries & metadata" + ) + + self.parser_copy.add_argument("-p", dest="project", nargs="+", required=True) + self.parser_copy.add_argument("-s", dest="suffix", required=True) + self.parser_copy.add_argument("-r", dest="resources", required=False) + self.parser_copy.add_argument( + "--bundlever", + dest="version", + help="If set, bundle update package for self-update", + required=False, + ) + self.parser_copy.add_argument( + "--noclean", + dest="noclean", + action="store_true", + help="Don't clean output directory", + required=False, + ) + self.parser_copy.set_defaults(func=self.copy) + + def get_project_filename(self, project, filetype): + # Temporary fix + project_name = project.project + if project_name == "firmware" and filetype != "elf": + project_name = "full" + return f"flipper-z-{self.target}-{project_name}-{self.args.suffix}.{filetype}" + + def get_dist_filepath(self, filename): + return join(self.output_dir_path, filename) + + def copy_single_project(self, project): + obj_directory = join("build", project.dir) + + for filetype in ("elf", "bin", "dfu", "json"): + shutil.copyfile( + join(obj_directory, f"{project.project}.{filetype}"), + self.get_dist_filepath(self.get_project_filename(project, filetype)), + ) + + def copy(self): + self.projects = dict( + map( + lambda pd: (pd.project, pd), + map(ProjectDir, self.args.project), + ) + ) + + project_targets = set(map(lambda p: p.target, self.projects.values())) + if len(project_targets) != 1: + self.logger.error(f"Cannot mix targets {project_targets}!") + return 1 + self.target = project_targets.pop() + + project_flavors = set(map(lambda p: p.flavor, self.projects.values())) + if len(project_flavors) != 1: + self.logger.error(f"Cannot mix flavors {project_flavors}!") + return 1 + self.flavor = project_flavors.pop() + + self.output_dir_path = join("dist", f"{self.target}-{self.flavor}") + if exists(self.output_dir_path) and not self.args.noclean: + shutil.rmtree(self.output_dir_path) + + if not exists(self.output_dir_path): + makedirs(self.output_dir_path) + + for project in self.projects.values(): + self.copy_single_project(project) + + self.logger.info( + f"Firmware binaries can be found at:\n\t{self.output_dir_path}" + ) + + if self.args.version: + bundle_dir = join( + self.output_dir_path, f"{self.target}-update-{self.args.suffix}" + ) + bundle_args = [ + "generate", + "-d", + bundle_dir, + "-v", + self.args.version, + "-t", + self.target, + "--dfu", + self.get_dist_filepath( + self.get_project_filename(self.projects["firmware"], "dfu") + ), + "--stage", + self.get_dist_filepath( + self.get_project_filename(self.projects["updater"], "bin") + ), + ] + if self.args.resources: + bundle_args.extend( + ( + "-r", + self.args.resources, + ) + ) + bundle_args.extend(self.other_args) + self.logger.info( + f"Use this directory to self-update your Flipper:\n\t{bundle_dir}" + ) + return UpdateMain(no_exit=True)(bundle_args) + + return 0 + + +if __name__ == "__main__": + Main()() diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons new file mode 100644 index 000000000000..6faf5519bba4 --- /dev/null +++ b/site_scons/commandline.scons @@ -0,0 +1,87 @@ +# To build updater-related targets, you need to set this option +AddOption( + "--with-updater", + dest="fullenv", + action="store_true", + help="Full firmware environment", +) + +AddOption( + "--options", + dest="optionfile", + type="string", + nargs=1, + action="store", + default="fbt_options.py", + help="Enviroment option file", +) + +# Construction environment variables + +vars = Variables(GetOption("optionfile"), ARGUMENTS) +vars.Add(BoolVariable("VERBOSE", help="Print full commands", default=0)) +vars.Add( + BoolVariable("FORCE", help="Force target action (for supported targets)", default=0) +) +vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) +vars.Add(BoolVariable("COMPACT", help="Optimize for size", default=0)) + +vars.Add( + EnumVariable( + "TARGET_HW", + help="Hardware target", + default="7", + allowed_values=[ + "7", + ], + ) +) +vars.Add( + "COPRO_CUBE_VERSION", + help="Cube version", + default="", +) + +vars.Add( + "COPRO_MCU_FAMILY", + help="Cube MCU family", + default="", +) + +vars.Add( + "COPRO_STACK_ADDR", + help="Core2 Firmware address", + default=0, +) + +vars.Add( + PathVariable( + "COPRO_STACK_BIN_PATH", + help="Path to configuration file", + validator=PathVariable.PathIsFile, + default="", + ) +) +vars.Add( + PathVariable( + "COPRO_CUBE_DIR", + help="Path to Cube root", + validator=PathVariable.PathIsDir, + default="", + ) +) +vars.Add( + EnumVariable( + "COPRO_STACK_TYPE", + help="Core2 stack type", + default="ble_light", + allowed_values=[ + "ble_full", + "ble_light", + "ble_basic", + ], + ) +) + + +Return("vars") diff --git a/site_scons/environ.scons b/site_scons/environ.scons index e6fc81c21a0d..fff2a408e681 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -1,32 +1,19 @@ -from SCons.Platform import TempFileMunge import SCons +from SCons.Platform import TempFileMunge from fbt import utils import os import multiprocessing +Import("VARIABLES") -vars = Variables(None, ARGUMENTS) -vars.Add(BoolVariable("VERBOSE", help="Print full commands", default=0)) -vars.Add( - BoolVariable("FORCE", help="Force target action (for supported targets)", default=0) -) -vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) -vars.Add(BoolVariable("COMPACT", help="Optimize for size", default=0)) -vars.Add( - EnumVariable( - "TARGET_HW", - help="Hardware target", - default="7", - allowed_values=[ - "7", - ], - ) -) - +# Dirty hack to construct environment with PathVariable paths relative to +# upper dir +_cwd = os.getcwd() +os.chdir("..") coreenv = Environment( - variables=vars, + variables=VARIABLES, tools=["as", "gcc", "g++", "ar", "gnulink", "python", "compilation_db"], OBJCOPY="objcopy", PYTHON3="python3", @@ -38,10 +25,13 @@ coreenv = Environment( PROGSUFFIX=".elf", COMPILATIONDB_USE_ABSPATH=True, ENV={ + # Import PATH from OS env - scons doesn't do that by default "PATH": os.environ["PATH"], }, ) +os.chdir(_cwd) +# print(coreenv.Dump()) if not coreenv["VERBOSE"]: coreenv.SetDefault( CCCOMSTR="\tCC\t${SOURCE}", @@ -60,21 +50,22 @@ if coreenv["PLATFORM"] == "win32": # On Windows, Python 3 executable is usually just "python" coreenv["PYTHON3"] = coreenv["PYTHON3"][:-1] -Help(vars.GenerateHelpText(coreenv)) +Help(VARIABLES.GenerateHelpText(coreenv)) # Default value for commandline options SetOption("num_jobs", multiprocessing.cpu_count()) +# Avoiding re-scan of all sources on every startup SetOption("implicit_cache", True) SetOption("implicit_deps_unchanged", True) +# More aggressive caching SetOption("max_drift", 1) +# Random task queue - to discover isses with build logic faster SetOption("random", 1) -# coreenv.Decider("content-timestamp") - -# Set up cross-compile tools +# Setting up cross-compile tools utils.prefix_commands( coreenv, "arm-none-eabi-", @@ -89,12 +80,8 @@ utils.prefix_commands( ], ) -# Setting up temp file parameters - +# Setting up temp file parameters - to overcome command line length limits coreenv["TEMPFILEARGESCFUNC"] = utils.tempfile_arg_esc_func - -# Commandline length limit hack - utils.wrap_tempfile(coreenv, "LINKCOM") utils.wrap_tempfile(coreenv, "ARCOM") @@ -131,7 +118,7 @@ def BuildModule(env, module): return env.SConscript( module_sconscript, - variant_dir=os.path.join(env["BUILD_DIR"], module), + variant_dir=os.path.join(env.subst("$BUILD_DIR"), module), duplicate=0, ) diff --git a/site_scons/site_init.py b/site_scons/site_init.py index f29968bb431d..b9743578df43 100644 --- a/site_scons/site_init.py +++ b/site_scons/site_init.py @@ -1,4 +1,40 @@ +from SCons.Script import GetBuildFailures + import sys import os +import atexit sys.path.insert(0, os.path.join(os.getcwd(), "scripts")) + + +def bf_to_str(bf): + """Convert an element of GetBuildFailures() to a string + in a useful way.""" + import SCons.Errors + + if bf is None: # unknown targets product None in list + return "(unknown tgt)" + elif isinstance(bf, SCons.Errors.StopError): + return str(bf) + elif bf.node: + return str(bf.node) + ": " + bf.errstr + elif bf.filename: + return bf.filename + ": " + bf.errstr + return "unknown failure: " + bf.errstr + + +def display_build_status(): + """Display the build status. Called by atexit. + Here you could do all kinds of complicated things.""" + bf = GetBuildFailures() + if bf: + # bf is normally a list of build failures; if an element is None, + # it's because of a target that scons doesn't know anything about. + failures_message = "\n".join( + ["Failed building %s" % bf_to_str(x) for x in bf if x is not None] + ) + + print(failures_message) + + +atexit.register(display_build_status) From 38abd80a31385c94b1567715f21f0efc468ed554 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 12 Jun 2022 22:12:29 +0400 Subject: [PATCH 104/184] Build: Functional do_dist target --- SConstruct | 36 ++++++++++++++++++++++++++++---- fbt_options.py | 18 +++++++++++++++- firmware.scons | 40 +++++++++++++++++++++--------------- site_scons/commandline.scons | 12 ++++++++++- site_scons/fbt/fwbuild.py | 18 ---------------- site_scons/site_init.py | 2 +- 6 files changed, 84 insertions(+), 42 deletions(-) delete mode 100644 site_scons/fbt/fwbuild.py diff --git a/SConstruct b/SConstruct index 4be6e5c871ef..4bb1bf44f0b0 100644 --- a/SConstruct +++ b/SConstruct @@ -30,7 +30,8 @@ coreenv["ROOT_DIR"] = Dir(".") # Prepare variant dir for given fw configuration & current options def create_fw_build_targets(env, configuration_name): - build_dir = Dir("build").Dir(get_variant_dirname(env, configuration_name)).abspath + flavor = get_variant_dirname(env, configuration_name) + build_dir = Dir("build").Dir(flavor).abspath return SConscript( "firmware.scons", variant_dir=build_dir, @@ -39,15 +40,42 @@ def create_fw_build_targets(env, configuration_name): "ENV": env, "fw_build_meta": { "type": configuration_name, + "flavor": flavor, "build_dir": build_dir, }, }, ) -firmware_out = create_fw_build_targets(coreenv, "firmware") -Default(firmware_out.artifacts) +def add_project_to_distenv(distenv, fw_type, fw_env_key): + project_env = distenv[fw_env_key] = create_fw_build_targets(coreenv, fw_type) + distenv.Append( + DIST_PROJECTS=[ + project_env["FW_FLAVOR"], + ], + DIST_DEPENDS=[ + project_env["FW_ARTIFACTS"], + ], + ) + return project_env + + +distenv = coreenv.Clone() +firmware_out = add_project_to_distenv(distenv, "firmware", "FW_ENV") +Default(firmware_out["FW_ARTIFACTS"]) + # If enabled, configure updater-related targets if GetOption("fullenv"): - updater_out = create_fw_build_targets(coreenv, "updater") + updater_out = add_project_to_distenv(distenv, "updater", "UPD_ENV") + + +# Everything needs a target. So, we're using a dir for that +dist = distenv.Command( + Dir("dist"), + [], + '${PYTHON3} ${ROOT_DIR.abspath}/scripts/sconsdist.py copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}"', +) +Depends(dist, distenv["DIST_DEPENDS"]) +AlwaysBuild(dist) +Alias("do_dist", dist) diff --git a/fbt_options.py b/fbt_options.py index a22f41fa6331..5cdfef00a14c 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -1,16 +1,32 @@ import os +# Default hardware target +TARGET_HW = 7 + +# Optimization flags +## Optimize for size COMPACT = 1 +## Optimize for debugging +DEBUG = 0 + +DIST_SUFFIX = "local" +# Coprocessor firmware COPRO_OB_DATA = "ob.data" +# Must match lib/STM32CubeWB version COPRO_CUBE_VERSION = "1.13.3" + COPRO_MCU_FAMILY = "STM32WB5x" COPRO_CUBE_DIR = "lib/STM32CubeWB" +# Default radio stack COPRO_STACK_BIN = "stm32wb5x_BLE_Stack_light_fw.bin" +# Firmware also supports "ble_full", but it might not fit into debug builds COPRO_STACK_TYPE = "ble_light" -COPRO_STACK_ADDR = 0 + +# Leave 0 to lets scripts automatically calculate it +COPRO_STACK_ADDR = "0x0" COPRO_FIRMWARE_DIR = ( f"{COPRO_CUBE_DIR}/Projects/STM32WB_Copro_Wireless_Binaries/{COPRO_MCU_FAMILY}" diff --git a/firmware.scons b/firmware.scons index 1b00f3192b3c..d1041d8d3204 100644 --- a/firmware.scons +++ b/firmware.scons @@ -2,7 +2,6 @@ Import("ENV", "fw_build_meta") import os -from fbt.fwbuild import FirmwareOutput # Building initial C environment for libs env = ENV.Clone() @@ -13,6 +12,7 @@ env.Append( PLUGIN_ELF_DIR="${BUILD_DIR}", LIB_DIST_DIR="${BUILD_DIR}/lib", IS_BASE_FIRMWARE=fw_build_meta["type"] == "firmware", + FW_FLAVOR=fw_build_meta["flavor"], LIBPATH=[ "${LIB_DIST_DIR}", ], @@ -191,36 +191,42 @@ Depends(fwelf, depends) AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) -fwhex = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") -fwbin = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") -fwdfu = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") +fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") +fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") +fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") # Default(dfu) Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu) # Additional FW-related pseudotargets if fwenv["IS_BASE_FIRMWARE"]: - flash = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") + flash = fwenv["FW_FLASH"] = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") if fwenv["FORCE"]: AlwaysBuild(flash) Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) # Compile DB generation -cdb = fwenv.CompilationDatabase("compile_database.json") -Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", cdb) +fwcdb = fwenv["FW_CDB"] = fwenv.CompilationDatabase("compile_database.json") +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb) # fw_version_json = env["FW_VERSION_JSON"] # Return("fwhex fwelf fwbin fw_version_json") -fw_output = FirmwareOutput( - project=fwenv["FIRMWARE_BUILD_CFG"], - dfu=fwdfu[0], - elf=fwelf[0], - bin=fwbin[0], - json=env["FW_VERSION_JSON"][0], - extapps=extapps, -) +# fw_output = FirmwareOutput( +# project=fwenv["FIRMWARE_BUILD_CFG"], +# dfu=fwdfu[0], +# elf=fwelf[0], +# bin=fwbin[0], +# json=env["FW_VERSION_JSON"][0], +# extapps=extapps, +# ) + +# Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", fw_output.artifacts) +# Return("fw_output") + +artifacts = [fwhex, fwbin, fwdfu, env["FW_VERSION_JSON"]] +fwenv["FW_ARTIFACTS"] = artifacts -Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", fw_output.artifacts) +Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", artifacts) -Return("fw_output") +Return("fwenv") diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 6faf5519bba4..4675d9f83747 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -1,3 +1,5 @@ +# Commandline options + # To build updater-related targets, you need to set this option AddOption( "--with-updater", @@ -16,6 +18,7 @@ AddOption( help="Enviroment option file", ) + # Construction environment variables vars = Variables(GetOption("optionfile"), ARGUMENTS) @@ -36,6 +39,13 @@ vars.Add( ], ) ) + +vars.Add( + "DIST_SUFFIX", + help="Dist suffix", + default="local", +) + vars.Add( "COPRO_CUBE_VERSION", help="Cube version", @@ -51,7 +61,7 @@ vars.Add( vars.Add( "COPRO_STACK_ADDR", help="Core2 Firmware address", - default=0, + default="0", ) vars.Add( diff --git a/site_scons/fbt/fwbuild.py b/site_scons/fbt/fwbuild.py deleted file mode 100644 index 8a85ec2baf6e..000000000000 --- a/site_scons/fbt/fwbuild.py +++ /dev/null @@ -1,18 +0,0 @@ -from dataclasses import dataclass -from typing import List, Optional, Any - - -@dataclass -class FirmwareOutput: - project: str - dfu: Optional[Any] - elf: Optional[Any] - bin: Optional[Any] - json: Optional[Any] - extapps: Optional[List[Any]] - - @property - def artifacts(self): - return list( - filter(lambda o: o is not None, (self.dfu, self.elf, self.bin, self.json)) - ) diff --git a/site_scons/site_init.py b/site_scons/site_init.py index b9743578df43..817269e286ab 100644 --- a/site_scons/site_init.py +++ b/site_scons/site_init.py @@ -33,7 +33,7 @@ def display_build_status(): failures_message = "\n".join( ["Failed building %s" % bf_to_str(x) for x in bf if x is not None] ) - + print("*" * 10, "ERRORS", "*" * 10) print(failures_message) From f3fb26420e75c38e734ec24d3bb19ff61e70a6e1 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 02:41:06 +0400 Subject: [PATCH 105/184] Build: added dist wrappers; call ./fbt fw_dist for simple copy or ./fbt --with-updater updater_package for OTA bundle --- SConstruct | 77 ++++++++++++++------------------- assets/SConscript | 3 ++ fbt_options.py | 23 ++++++---- firmware.scons | 2 + scripts/sconsdist.py | 2 +- site_scons/appmanifests.scons | 23 ++++++---- site_scons/commandline.scons | 15 +++++++ site_scons/environ.scons | 6 +-- site_scons/fbt/builders/dist.py | 49 +++++++++++++++++++++ 9 files changed, 135 insertions(+), 65 deletions(-) create mode 100644 site_scons/fbt/builders/dist.py diff --git a/SConstruct b/SConstruct index 4bb1bf44f0b0..fa23e2807b01 100644 --- a/SConstruct +++ b/SConstruct @@ -6,10 +6,8 @@ # trees on startup. So, to keep startup time as low as possible, we're hiding # construction of certain targets behind command-line options. -from fbt.utils import get_variant_dirname -from SCons.Action import CommandGeneratorAction +from fbt.builders.dist import add_dist_builders, add_project_to_distenv -import os cmd_vars = SConscript("site_scons/commandline.scons") @@ -29,53 +27,44 @@ coreenv["ROOT_DIR"] = Dir(".") # Prepare variant dir for given fw configuration & current options -def create_fw_build_targets(env, configuration_name): - flavor = get_variant_dirname(env, configuration_name) - build_dir = Dir("build").Dir(flavor).abspath - return SConscript( - "firmware.scons", - variant_dir=build_dir, - duplicate=0, - exports={ - "ENV": env, - "fw_build_meta": { - "type": configuration_name, - "flavor": flavor, - "build_dir": build_dir, - }, - }, - ) - - -def add_project_to_distenv(distenv, fw_type, fw_env_key): - project_env = distenv[fw_env_key] = create_fw_build_targets(coreenv, fw_type) - distenv.Append( - DIST_PROJECTS=[ - project_env["FW_FLAVOR"], - ], - DIST_DEPENDS=[ - project_env["FW_ARTIFACTS"], - ], - ) - return project_env distenv = coreenv.Clone() -firmware_out = add_project_to_distenv(distenv, "firmware", "FW_ENV") +add_dist_builders(distenv) + +firmware_out = add_project_to_distenv(distenv, coreenv, "firmware", "FW_ENV") Default(firmware_out["FW_ARTIFACTS"]) -# If enabled, configure updater-related targets +# If enabled, construct updater-related targets if GetOption("fullenv"): - updater_out = add_project_to_distenv(distenv, "updater", "UPD_ENV") + updater_out = add_project_to_distenv(distenv, coreenv, "updater", "UPD_ENV") + + # Target producing self-update package + selfupdate_dist = distenv.DistBuilder( + "pseudo", + (distenv["DIST_DEPENDS"], firmware_out["FW_RESOURCES"]), + DIST_EXTRA=[ + "-r", + "${ROOT_DIR.abspath}/assets/resources", + "--bundlever", + "${UPDATE_VERSION_STRING}", + "--radio", + "${ROOT_DIR.abspath}/${COPRO_STACK_BIN_PATH}", + "--radiotype", + "${COPRO_STACK_TYPE}", + "${COPRO_DISCLAIMER}", + "--obdata", + "${ROOT_DIR.abspath}/${COPRO_OB_DATA}", + ], + ) + distenv.Pseudo("pseudo") + AlwaysBuild(selfupdate_dist) + Alias("updater_package", selfupdate_dist) +# Just copy binaries to dist folder +basic_dist = distenv.DistBuilder("pseudo2", distenv["DIST_DEPENDS"]) -# Everything needs a target. So, we're using a dir for that -dist = distenv.Command( - Dir("dist"), - [], - '${PYTHON3} ${ROOT_DIR.abspath}/scripts/sconsdist.py copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}"', -) -Depends(dist, distenv["DIST_DEPENDS"]) -AlwaysBuild(dist) -Alias("do_dist", dist) +distenv.Pseudo("pseudo2") +AlwaysBuild(basic_dist) +Alias("fw_dist", basic_dist) diff --git a/assets/SConscript b/assets/SConscript index 3439469225be..0e5b9c0d8f52 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -114,6 +114,9 @@ if assetsenv["IS_BASE_FIRMWARE"]: NoClean(resources) if assetsenv["FORCE"]: AlwaysBuild(resources) + + # Exporting resources node to external environment + env["FW_RESOURCES"] = resources Alias("resources", resources) Return("assetslib") diff --git a/fbt_options.py b/fbt_options.py index 5cdfef00a14c..031c5991ebee 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -1,18 +1,22 @@ import os +# Variables starting with _ are not consumed by scons and are introduced only +# for ease of editing. If you want to override them on the commandline, +# use final variables (without _) + # Default hardware target TARGET_HW = 7 # Optimization flags ## Optimize for size -COMPACT = 1 -## Optimize for debugging -DEBUG = 0 +COMPACT = 0 +## Optimize for debugging experience +DEBUG = 1 DIST_SUFFIX = "local" # Coprocessor firmware -COPRO_OB_DATA = "ob.data" +COPRO_OB_DATA = "scripts/ob.data" # Must match lib/STM32CubeWB version COPRO_CUBE_VERSION = "1.13.3" @@ -21,14 +25,17 @@ COPRO_CUBE_DIR = "lib/STM32CubeWB" # Default radio stack -COPRO_STACK_BIN = "stm32wb5x_BLE_Stack_light_fw.bin" +_COPRO_STACK_BIN = "stm32wb5x_BLE_Stack_light_fw.bin" # Firmware also supports "ble_full", but it might not fit into debug builds COPRO_STACK_TYPE = "ble_light" # Leave 0 to lets scripts automatically calculate it COPRO_STACK_ADDR = "0x0" -COPRO_FIRMWARE_DIR = ( - f"{COPRO_CUBE_DIR}/Projects/STM32WB_Copro_Wireless_Binaries/{COPRO_MCU_FAMILY}" +COPRO_STACK_BIN_PATH = os.path.join( + COPRO_CUBE_DIR, + "Projects", + "STM32WB_Copro_Wireless_Binaries", + COPRO_MCU_FAMILY, + _COPRO_STACK_BIN, ) -COPRO_STACK_BIN_PATH = os.path.join(COPRO_FIRMWARE_DIR, COPRO_STACK_BIN) diff --git a/firmware.scons b/firmware.scons index d1041d8d3204..539666b584fe 100644 --- a/firmware.scons +++ b/firmware.scons @@ -38,6 +38,8 @@ env.Append( "NDEBUG", "FURI_NDEBUG", ], + # You can add other entries named after libraries + # If they are present, they have precedence over Default } }, ) diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index cdcb82db11f0..c4549d3cfa6b 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -79,7 +79,7 @@ def copy(self): project_flavors = set(map(lambda p: p.flavor, self.projects.values())) if len(project_flavors) != 1: self.logger.error(f"Cannot mix flavors {project_flavors}!") - return 1 + return 2 self.flavor = project_flavors.pop() self.output_dir_path = join("dist", f"{self.target}-{self.flavor}") diff --git a/site_scons/appmanifests.scons b/site_scons/appmanifests.scons index 31a7cb103d25..0d48c9d882a3 100644 --- a/site_scons/appmanifests.scons +++ b/site_scons/appmanifests.scons @@ -3,14 +3,26 @@ Import("ENV") import SCons from fbt.appmanifest import FlipperAppType, AppManager, ApplicationsCGenerator +# Adding objects for application management to env +# AppManager env["APPMGR"] - loads all manifests; manages list of known apps +# AppBuildset env["APPBUILD"] - contains subset of apps, filtered for current config + def LoadApplicationManifests(env): appmgr = env["APPMGR"] = AppManager() - for entry in Glob("#/applications/*"): + for entry in env.Glob("#/applications/*"): if isinstance(entry, SCons.Node.FS.Dir) and not str(entry).startswith("."): appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) +def PrepareApplicationsBuild(env): + env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"]) + env["APPBUILD_DUMP"] = env.Action( + DumpApplicationConfig, + "\tINFO\t", + ) + + def DumpApplicationConfig(target, source, env): print(f"Loaded {len(env['APPMGR'].known_apps)} app definitions.") print("Firmware modules configuration:") @@ -23,14 +35,6 @@ def DumpApplicationConfig(target, source, env): ) -def PrepareApplicationsBuild(env): - env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"]) - env["APPBUILD_DUMP"] = Action( - DumpApplicationConfig, - "\tINFO\t", - ) - - ENV.AddMethod(LoadApplicationManifests) ENV.AddMethod(PrepareApplicationsBuild) @@ -43,4 +47,5 @@ def build_apps_c(target, source, env): file.write(gen.generate()) +# Exports apps.c generation action to environment ENV["APPS_C_ACTION"] = Action(build_apps_c, "${APPSCOMSTR}") diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 4675d9f83747..639875bbb32d 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -46,6 +46,13 @@ vars.Add( default="local", ) +vars.Add( + "UPDATE_VERSION_STRING", + help="Version string for updater package", + default="${DIST_SUFFIX}", +) + + vars.Add( "COPRO_CUBE_VERSION", help="Cube version", @@ -64,6 +71,14 @@ vars.Add( default="0", ) +vars.Add( + PathVariable( + "COPRO_OB_DATA", + help="Path to OB reference data", + validator=PathVariable.PathIsFile, + default="", + ) +) vars.Add( PathVariable( "COPRO_STACK_BIN_PATH", diff --git a/site_scons/environ.scons b/site_scons/environ.scons index fff2a408e681..fddf43ead458 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -62,7 +62,7 @@ SetOption("implicit_deps_unchanged", True) # More aggressive caching SetOption("max_drift", 1) # Random task queue - to discover isses with build logic faster -SetOption("random", 1) +# SetOption("random", 1) # Setting up cross-compile tools @@ -92,7 +92,7 @@ utils.wrap_tempfile(coreenv, "ARCOM") def GlobRecursive(env, pattern, node=".", exclude=None): results = [] if isinstance(node, str): - node = Dir(node) + node = env.Dir(node) for f in node.glob("*", source=True, exclude=exclude): if isinstance(f, SCons.Node.FS.Dir): results += env.GlobRecursive(pattern, f, exclude) @@ -108,7 +108,7 @@ def GlobRecursive(env, pattern, node=".", exclude=None): def BuildModule(env, module): # print("cwd", os.getcwd()) # print(type(Dir(".").srcdir), dir(Dir(".").srcdir)) - src_dir = str(Dir(".").srcdir or os.getcwd()) + src_dir = str(env.Dir(".").srcdir or os.getcwd()) module_sconscript = os.path.join(src_dir, module, "SConscript") if not os.path.exists(module_sconscript): module_sconscript = os.path.join(src_dir, f"{module}.scons") diff --git a/site_scons/fbt/builders/dist.py b/site_scons/fbt/builders/dist.py new file mode 100644 index 000000000000..95362cb99eb2 --- /dev/null +++ b/site_scons/fbt/builders/dist.py @@ -0,0 +1,49 @@ +from fbt.utils import get_variant_dirname + +import SCons +from SCons.Builder import Builder +from SCons.Action import Action + + +def create_fw_build_targets(env, configuration_name): + flavor = get_variant_dirname(env, configuration_name) + build_dir = env.Dir("build").Dir(flavor).abspath + return env.SConscript( + "firmware.scons", + variant_dir=build_dir, + duplicate=0, + exports={ + "ENV": env, + "fw_build_meta": { + "type": configuration_name, + "flavor": flavor, + "build_dir": build_dir, + }, + }, + ) + + +def add_project_to_distenv(dist_env, core_env, fw_type, fw_env_key): + project_env = dist_env[fw_env_key] = create_fw_build_targets(core_env, fw_type) + dist_env.Append( + DIST_PROJECTS=[ + project_env["FW_FLAVOR"], + ], + DIST_DEPENDS=[ + project_env["FW_ARTIFACTS"], + ], + ) + return project_env + + +def add_dist_builders(env): + env.Append( + BUILDERS={ + "DistBuilder": Builder( + action=Action( + '${PYTHON3} ${ROOT_DIR.abspath}/scripts/sconsdist.py copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}" ${DIST_EXTRA}', + "${DISTCOMSTR}", + ), + ), + } + ) From d61220bb3a0d161b23ec40a484d8f7a27c494a34 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 03:09:20 +0400 Subject: [PATCH 106/184] Build: added ./fbt copro_dist target for bundling c2 firmware for qFlipper --- SConstruct | 15 +++++++++++---- fbt_options.py | 5 ++--- site_scons/commandline.scons | 13 ++++++++++--- site_scons/fbt/builders/dist.py | 16 ++++++++++++++++ 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/SConstruct b/SConstruct index fa23e2807b01..2de2eb298dd2 100644 --- a/SConstruct +++ b/SConstruct @@ -46,16 +46,16 @@ if GetOption("fullenv"): (distenv["DIST_DEPENDS"], firmware_out["FW_RESOURCES"]), DIST_EXTRA=[ "-r", - "${ROOT_DIR.abspath}/assets/resources", + '"${ROOT_DIR.abspath}/assets/resources"', "--bundlever", - "${UPDATE_VERSION_STRING}", + '"${UPDATE_VERSION_STRING}"', "--radio", - "${ROOT_DIR.abspath}/${COPRO_STACK_BIN_PATH}", + '"${ROOT_DIR.abspath}/${COPRO_STACK_BIN_DIR}/${COPRO_STACK_BIN}"', "--radiotype", "${COPRO_STACK_TYPE}", "${COPRO_DISCLAIMER}", "--obdata", - "${ROOT_DIR.abspath}/${COPRO_OB_DATA}", + '"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"', ], ) distenv.Pseudo("pseudo") @@ -68,3 +68,10 @@ basic_dist = distenv.DistBuilder("pseudo2", distenv["DIST_DEPENDS"]) distenv.Pseudo("pseudo2") AlwaysBuild(basic_dist) Alias("fw_dist", basic_dist) + +copro_dist = distenv.CoproBuilder( + Dir("assets/core2_firmware"), + [], +) +AlwaysBuild(copro_dist) +Alias("copro_dist", copro_dist) diff --git a/fbt_options.py b/fbt_options.py index 031c5991ebee..76a2ab9b727c 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -25,17 +25,16 @@ COPRO_CUBE_DIR = "lib/STM32CubeWB" # Default radio stack -_COPRO_STACK_BIN = "stm32wb5x_BLE_Stack_light_fw.bin" +COPRO_STACK_BIN = "stm32wb5x_BLE_Stack_light_fw.bin" # Firmware also supports "ble_full", but it might not fit into debug builds COPRO_STACK_TYPE = "ble_light" # Leave 0 to lets scripts automatically calculate it COPRO_STACK_ADDR = "0x0" -COPRO_STACK_BIN_PATH = os.path.join( +COPRO_STACK_BIN_DIR = os.path.join( COPRO_CUBE_DIR, "Projects", "STM32WB_Copro_Wireless_Binaries", COPRO_MCU_FAMILY, - _COPRO_STACK_BIN, ) diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 639875bbb32d..fb33cc63ddd1 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -71,6 +71,13 @@ vars.Add( default="0", ) + +vars.Add( + "COPRO_STACK_BIN", + help="Core2 Firmware file name", + default="", +) + vars.Add( PathVariable( "COPRO_OB_DATA", @@ -81,9 +88,9 @@ vars.Add( ) vars.Add( PathVariable( - "COPRO_STACK_BIN_PATH", - help="Path to configuration file", - validator=PathVariable.PathIsFile, + "COPRO_STACK_BIN_DIR", + help="Path to ST-provided stacks", + validator=PathVariable.PathIsDir, default="", ) ) diff --git a/site_scons/fbt/builders/dist.py b/site_scons/fbt/builders/dist.py index 95362cb99eb2..fbba9e0f9631 100644 --- a/site_scons/fbt/builders/dist.py +++ b/site_scons/fbt/builders/dist.py @@ -3,6 +3,7 @@ import SCons from SCons.Builder import Builder from SCons.Action import Action +from SCons.Script import Mkdir def create_fw_build_targets(env, configuration_name): @@ -45,5 +46,20 @@ def add_dist_builders(env): "${DISTCOMSTR}", ), ), + "CoproBuilder": Builder( + action=Action( + [ + Mkdir("$TARGET"), + "${PYTHON3} ${ROOT_DIR.abspath}/scripts/assets.py " + "copro ${COPRO_CUBE_DIR} " + "${TARGET} ${COPRO_MCU_FAMILY} " + "--cube_ver=${COPRO_CUBE_VERSION} " + "--stack_type=${COPRO_STACK_TYPE} " + '--stack_file="${COPRO_STACK_BIN}" ' + "--stack_addr=${COPRO_STACK_ADDR}", + ], + "", + ) + ), } ) From b414dda35aba05a41d32b8d6880786acce00a489 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 03:15:09 +0400 Subject: [PATCH 107/184] CI: trying scons integration --- .github/workflows/build.yml | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0c161866542d..7c971d1e8787 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,22 +71,15 @@ jobs: run: | tar czpf artifacts/flipper-z-any-scripts-${{steps.names.outputs.suffix}}.tgz scripts - - name: 'Rebuild Assets' - uses: ./.github/actions/docker - with: - run: | - set -e - make assets_rebuild assets_manifest - git diff --quiet || ( echo "Assets recompilation required."; exit 255 ) - - name: 'Build the firmware in docker' uses: ./.github/actions/docker with: run: | set -e + pip3 install -r scripts/requirements.txt for TARGET in ${TARGETS} do - make updater_package TARGET=${TARGET} ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} + ./fbt TARGET_HW=${TARGET} --with-updater updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} done - name: 'Move upload files' @@ -97,7 +90,7 @@ jobs: set -e for TARGET in ${TARGETS} do - mv dist/${TARGET}/* artifacts/ + mv dist/${TARGET}-*/* artifacts/ done - name: 'Bundle self-update package' @@ -124,7 +117,7 @@ jobs: uses: ./.github/actions/docker with: run: | - make -C assets copro_bundle + ./fbt copro_dist tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz -C assets core2_firmware - name: 'Upload artifacts to update server' @@ -208,20 +201,13 @@ jobs: echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV - - name: 'Rebuild Assets' - uses: ./.github/actions/docker - with: - run: | - set -e - make assets_rebuild assets_manifest - git diff --quiet || ( echo "Assets recompilation required."; exit 255 ) - - name: 'Build the firmware in docker' uses: ./.github/actions/docker with: run: | set -e + pip3 install -r scripts/requirements.txt for TARGET in ${TARGETS} do - make TARGET=${TARGET} DEBUG=0 COMPACT=1 + ./fbt TARGET_HW=${TARGET} --with-updater updater_package DEBUG=0 COMPACT=1 done From 5aaf87890cdd647c5f10a057039f223ea1781563 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 03:17:41 +0400 Subject: [PATCH 108/184] CI: calling pip with python --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c971d1e8787..933a6a7ba74d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,7 +76,7 @@ jobs: with: run: | set -e - pip3 install -r scripts/requirements.txt + /usr/bin/env python3 -m pip install -r scripts/requirements.txt for TARGET in ${TARGETS} do ./fbt TARGET_HW=${TARGET} --with-updater updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} @@ -206,7 +206,7 @@ jobs: with: run: | set -e - pip3 install -r scripts/requirements.txt + /usr/bin/env python3 -m pip install -r scripts/requirements.txt for TARGET in ${TARGETS} do ./fbt TARGET_HW=${TARGET} --with-updater updater_package DEBUG=0 COMPACT=1 From 7dab13525ea8f26da87b01653b6f02fd1b71a7fd Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 03:19:14 +0400 Subject: [PATCH 109/184] CI: removed pip calls; stripping f from target --- .github/workflows/build.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 933a6a7ba74d..8cc0bd9b4f3a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,10 +76,9 @@ jobs: with: run: | set -e - /usr/bin/env python3 -m pip install -r scripts/requirements.txt for TARGET in ${TARGETS} do - ./fbt TARGET_HW=${TARGET} --with-updater updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} + ./fbt TARGET_HW=`echo ${TARGET} |sed 's/f//'` --with-updater updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} done - name: 'Move upload files' @@ -206,8 +205,7 @@ jobs: with: run: | set -e - /usr/bin/env python3 -m pip install -r scripts/requirements.txt for TARGET in ${TARGETS} do - ./fbt TARGET_HW=${TARGET} --with-updater updater_package DEBUG=0 COMPACT=1 + ./fbt TARGET_HW=`echo ${TARGET} |sed 's/f//'` --with-updater updater_package DEBUG=0 COMPACT=1 done From fbaba14b3a4b5c52ced5ba443c430cf2653200ef Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 03:50:11 +0400 Subject: [PATCH 110/184] Build: comments cleanup --- SConstruct | 11 +++++------ assets/SConscript | 1 - fbt_options.py | 8 +++----- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/SConstruct b/SConstruct index 2de2eb298dd2..7e447ac50b42 100644 --- a/SConstruct +++ b/SConstruct @@ -6,6 +6,7 @@ # trees on startup. So, to keep startup time as low as possible, we're hiding # construction of certain targets behind command-line options. + from fbt.builders.dist import add_dist_builders, add_project_to_distenv @@ -26,9 +27,7 @@ coreenv["ROOT_DIR"] = Dir(".") # Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) -# Prepare variant dir for given fw configuration & current options - - +# Create a separate "dist" environment and add construction envs to it distenv = coreenv.Clone() add_dist_builders(distenv) @@ -40,7 +39,7 @@ Default(firmware_out["FW_ARTIFACTS"]) if GetOption("fullenv"): updater_out = add_project_to_distenv(distenv, coreenv, "updater", "UPD_ENV") - # Target producing self-update package + # Target for self-update package selfupdate_dist = distenv.DistBuilder( "pseudo", (distenv["DIST_DEPENDS"], firmware_out["FW_RESOURCES"]), @@ -62,13 +61,13 @@ if GetOption("fullenv"): AlwaysBuild(selfupdate_dist) Alias("updater_package", selfupdate_dist) -# Just copy binaries to dist folder +# Target for copying & renaming binaries to dist folder basic_dist = distenv.DistBuilder("pseudo2", distenv["DIST_DEPENDS"]) - distenv.Pseudo("pseudo2") AlwaysBuild(basic_dist) Alias("fw_dist", basic_dist) +# Target for bundling core2 package for qFlipper copro_dist = distenv.CoproBuilder( Dir("assets/core2_firmware"), [], diff --git a/assets/SConscript b/assets/SConscript index 0e5b9c0d8f52..c34198ab0a27 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -65,7 +65,6 @@ Alias("dolphin_blocking", dolphin_blocking) # Protobuf version meta - proto_ver = assetsenv.Command( "protobuf_version.h", "#/assets/protobuf/Changelog", diff --git a/fbt_options.py b/fbt_options.py index 76a2ab9b727c..ba7409edb6c9 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -1,8 +1,5 @@ -import os +import posixpath -# Variables starting with _ are not consumed by scons and are introduced only -# for ease of editing. If you want to override them on the commandline, -# use final variables (without _) # Default hardware target TARGET_HW = 7 @@ -32,7 +29,8 @@ # Leave 0 to lets scripts automatically calculate it COPRO_STACK_ADDR = "0x0" -COPRO_STACK_BIN_DIR = os.path.join( +# If you override COPRO_CUBE_DIR on commandline, override this aswell +COPRO_STACK_BIN_DIR = posixpath.join( COPRO_CUBE_DIR, "Projects", "STM32WB_Copro_Wireless_Binaries", From a48e832825fc11da8eee455b0915e51635837cec Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 04:03:44 +0400 Subject: [PATCH 111/184] Build: respecting DIST_SUFFIX from OS environment --- site_scons/environ.scons | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/site_scons/environ.scons b/site_scons/environ.scons index fddf43ead458..0230dbdc7545 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -29,6 +29,12 @@ coreenv = Environment( "PATH": os.environ["PATH"], }, ) + +if os_suffix := os.environ.get("DIST_SUFFIX", None): + coreenv.Replace( + DIST_SUFFIX=os_suffix, + ) + os.chdir(_cwd) # print(coreenv.Dump()) From fb14e1346ac18490b850d116eee2b5afc4fe020c Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 13:26:42 +0400 Subject: [PATCH 112/184] Ble: fixed stack type string --- firmware/targets/f7/ble_glue/ble_glue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index de086ea53982..712db1208176 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -161,7 +161,7 @@ static void ble_glue_update_c2_fw_info() { local_info->VersionMinor, local_info->VersionSub, local_info->VersionBranch, - ble_glue_get_reltype_str(local_info->VersionReleaseType)); + ble_glue_get_reltype_str(local_info->StackType)); local_info->FusVersionMajor = wireless_info.FusVersionMajor; local_info->FusVersionMinor = wireless_info.FusVersionMinor; From 4f87860960a25cd99c878d4b50d51d1f4a60f864 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 13:40:44 +0400 Subject: [PATCH 113/184] Build: using WORKFLOW_BRANCH_OR_TAG from environment if present for branch name --- scripts/version.py | 8 +++++++- site_scons/environ.scons | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/version.py b/scripts/version.py index bc12fbb02ff3..edf4851cf99c 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -22,7 +22,13 @@ def get_version_info(self): if e.returncode == 1: dirty = True - branch = self._exec_git("rev-parse --abbrev-ref HEAD") or "unknown" + # If WORKFLOW_BRANCH_OR_TAG is set in environment, is has precedence + # (set by CI) + branch = ( + os.environ.get("WORKFLOW_BRANCH_OR_TAG", None) + or self._exec_git("rev-parse --abbrev-ref HEAD") + or "unknown" + ) branch_num = self._exec_git("rev-list --count HEAD") or "n/a" try: diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 0230dbdc7545..806169a1d515 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -30,13 +30,14 @@ coreenv = Environment( }, ) +os.chdir(_cwd) + +# If DIST_SUFFIX is set in environment, is has precedence (set by CI) if os_suffix := os.environ.get("DIST_SUFFIX", None): coreenv.Replace( DIST_SUFFIX=os_suffix, ) -os.chdir(_cwd) - # print(coreenv.Dump()) if not coreenv["VERBOSE"]: coreenv.SetDefault( From 07f6000cf09150e8047f1405cbe9d865575fbc5f Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 13:56:51 +0400 Subject: [PATCH 114/184] Build: debugging version.py environment on CI --- scripts/version.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/version.py b/scripts/version.py index edf4851cf99c..c56462232194 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -24,6 +24,7 @@ def get_version_info(self): # If WORKFLOW_BRANCH_OR_TAG is set in environment, is has precedence # (set by CI) + print("OS env: ", os.environ) branch = ( os.environ.get("WORKFLOW_BRANCH_OR_TAG", None) or self._exec_git("rev-parse --abbrev-ref HEAD") From a6ecf929bec10c8ed3ad47a3fc2ca4d980295305 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 14:12:55 +0400 Subject: [PATCH 115/184] Build: forwarding CI environment variable to child processed --- scripts/version.py | 1 - site_scons/environ.scons | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/version.py b/scripts/version.py index c56462232194..edf4851cf99c 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -24,7 +24,6 @@ def get_version_info(self): # If WORKFLOW_BRANCH_OR_TAG is set in environment, is has precedence # (set by CI) - print("OS env: ", os.environ) branch = ( os.environ.get("WORKFLOW_BRANCH_OR_TAG", None) or self._exec_git("rev-parse --abbrev-ref HEAD") diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 806169a1d515..6751bf3b37d4 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -27,6 +27,9 @@ coreenv = Environment( ENV={ # Import PATH from OS env - scons doesn't do that by default "PATH": os.environ["PATH"], + # Proxying CI environment to child scripts + "DIST_SUFFIX": os.environ.get("DIST_SUFFIX", None), + "WORKFLOW_BRANCH_OR_TAG": os.environ.get("WORKFLOW_BRANCH_OR_TAG", None), }, ) From 9716b1b82ffb2187dccc53396b541acad57c4f78 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Mon, 13 Jun 2022 07:36:59 -0400 Subject: [PATCH 116/184] Add UNIX toolchain downloader script --- scripts/toolchain/unix-toolchain-download.sh | 124 +++++++++++++++++-- 1 file changed, 116 insertions(+), 8 deletions(-) diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index d163b410ae41..4736b008478d 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -1,9 +1,117 @@ #!/bin/sh -SYS_TYPE="$(uname -s)" -if [ "$SYS_TYPE" = "Darwin" ]; then - printf "Downloading Mac OS toolchain.."; -else - printf "Downloading Linux toolchain.."; -fi - -echo "done!" + +# unofficial strict mode +set -eu; + +check_system() +{ + printf "Checking kernel type.."; + SYS_TYPE="$(uname -s)" + if [ "$SYS_TYPE" = "Darwin" ]; then + echo "darwin"; + TOOLCHAIN_URL="https://github.com/flipperdevices/flipperzero-firmware/archive/refs/tags/0.60.1-rc.tar.gz" + elif [ "$SYS_TYPE" = "Linux" ]; then + echo "linux"; + TOOLCHAIN_URL="https://github.com/flipperdevices/flipperzero-firmware/archive/refs/tags/0.60.1-rc.tar.gz" + else + echo "unsupported."; + echo "Your system is unsupported.. sorry.."; + exit 1; + fi +} + +check_tar() +{ + printf "Checking tar.."; + if ! tar --version > /dev/null 2>&1; then + echo "no"; + exit 1; + fi + echo "yes"; +} + + +curl_wget_check() +{ + printf "Checking curl.."; + if ! curll --version > /dev/null 2>&1; then + echo "no"; + printf "Checking wget.."; + if ! wget --version > /dev/null 2>&1; then + echo "no"; + echo "No curl or wget found in your PATH."; + echo "Please provide it or download this file:"; + echo; + echo "$TOOLCHAIN_URL"; + echo; + echo "And place in repo root dir mannualy."; + exit 1; + fi + echo "yes" + DOWNLOADER="wget"; + DOWNLOADER_ARGS="-qO"; + return; + fi + echo "yes" + DOWNLOADER="curl"; + DOWNLOADER_ARGS="-sSLo"; +} + +check_downloaded_toolchain() +{ + printf "Checking downloaded toolchain tgz.."; + if [ -f "$REPO_ROOT/$TOOLCHAIN_TAR" ]; then + echo "yes"; + return 0; + fi + echo "no"; + return 1; +} + +download_toolchain() +{ + printf "Checkin..oops Downloading toolchain.."; + "$DOWNLOADER" "$DOWNLOADER_ARGS" "$REPO_ROOT/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL"; + echo "done"; +} + +remove_old_tooclhain() +{ + printf "Removing old toolchain (if exist).."; + rm -rf "$REPO_ROOT/toolchain"; + echo "done"; +} + +unpack_toolchain() +{ + printf "Unpacking toolchain.."; + TOOLCHAIN_DIR="$(tar -tf "$REPO_ROOT/$TOOLCHAIN_TAR" | head -n 1 | tr -d '/')"; + tar -xf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/"; + mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/toolchain"; + echo "done"; +} + +clearing() +{ + printf "Clearing.."; + rm -rf "$REPO_ROOT/$TOOLCHAIN_TAR"; + echo "done"; +} + +main() +{ + SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; + REPO_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; + check_system; # defines $TOOLCHAIN_URL + check_tar; + TOOLCHAIN_TAR="$(basename "$TOOLCHAIN_URL")"; + if ! check_downloaded_toolchain; then + curl_wget_check; + download_toolchain; + fi + remove_old_tooclhain; + unpack_toolchain; + clearing; +} + +main; From a2b5eb92345fc15837989ca8253b973bc9f89954 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Mon, 13 Jun 2022 07:38:09 -0400 Subject: [PATCH 117/184] UNIX toolchain downloader script fix --- scripts/toolchain/unix-toolchain-download.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 4736b008478d..5aca7bd96fed 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -34,7 +34,7 @@ check_tar() curl_wget_check() { printf "Checking curl.."; - if ! curll --version > /dev/null 2>&1; then + if ! curl --version > /dev/null 2>&1; then echo "no"; printf "Checking wget.."; if ! wget --version > /dev/null 2>&1; then From b3f31ecc6a39b6ec9eb8e084ae70ca46a29e3a8f Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 15:41:15 +0400 Subject: [PATCH 118/184] Build: added initial fbt.md --- fbt.md | 46 ++++++++++++++++++++++++++++++++++++ site_scons/commandline.scons | 32 +++++++++++++++++++++---- 2 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 fbt.md diff --git a/fbt.md b/fbt.md new file mode 100644 index 000000000000..e0aecea2a83d --- /dev/null +++ b/fbt.md @@ -0,0 +1,46 @@ +# Flipper Build Tool + +FBT is the entry point for most firmware-related commands and utilities. +It is invoked by `./fbt` in firmware project root directory. Internally, it is a wrapper around scons build system. + +## NB +FBT constructs all referenced environments & their targets' dependency trees on startup. So, to keep startup time as low as possible, we're hiding construction of certain targets behind command-line options. + +## Invoking FBT +To build with FBT, call it specifying configuration options & targets to build. For example, + +`./fbt --with-updater COMPACT=1 DEBUG=0 VERBOSE=1 updater_package copro_dist` + +## FBT targets +FBT keeps track of internal dependencies, so you only need to build the highest-level target you need, and FBT will make sure everything it needs is up-to-date. + +### High-level (what you most likely need) +- `fw_dist` - build & publish firmware to `dist` folder +- `updater_package` - build self-update package. _Requires `--with-updater` option_ +- `copro_dist` - bundle Core2 FUS+stack binaries for qFlipper + +### Firmware targets +- `firmware_extapps` - build all plug-ins as separate .elf files + - `firmware_snake_game`, etc - build single plug-in as .elf by its name +- `firmware_flash` - flash current version to attached device with OpenOCD +- `firmware_cdb` - generate compilation database +- `firmware_all`, `updater_all` - build basic set of binaries + +### Assets +- `resources` - build resources and their Manifest + - `dolphin_ext` - process dolphin animations for SD card +- `icons` - generate .c+.h for icons from png assets +- `proto` - generate .pb.c+.pb.h for .proto sources +- `proto_ver` - generate .h with protobuf version +- `dolphin_internal`, `dolphin_blocking` - generate .c+.h for corresponding dolphin assets + +## Command-line parameters + +- `--options optionfile.py` (default value `fbt_options.py`) - load file with multiple configuration values +- `--with-updater` - enables updater-related targets and dependency tracking. Enabling this options introduces extra startup time costs, so use it when bundling update packages. Or if you have a fast computer and don't care about a few extra seconds of startup time. + +## Configuration +Default configuration variables are set in configuration file `fbt_options.py`. +Values set on command-line have higher precedence over configuration file. + +You can find out available options with `./fbt -h`. diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index fb33cc63ddd1..0c65f34ff882 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -22,12 +22,34 @@ AddOption( # Construction environment variables vars = Variables(GetOption("optionfile"), ARGUMENTS) -vars.Add(BoolVariable("VERBOSE", help="Print full commands", default=0)) vars.Add( - BoolVariable("FORCE", help="Force target action (for supported targets)", default=0) + BoolVariable( + "VERBOSE", + help="Print full commands", + default=False, + ) +) +vars.Add( + BoolVariable( + "FORCE", + help="Force target action (for supported targets)", + default=False, + ) +) +vars.Add( + BoolVariable( + "DEBUG", + help="Enable debug build", + default=True, + ) +) +vars.Add( + BoolVariable( + "COMPACT", + help="Optimize for size", + default=False, + ) ) -vars.Add(BoolVariable("DEBUG", help="Enable debug build", default=1)) -vars.Add(BoolVariable("COMPACT", help="Optimize for size", default=0)) vars.Add( EnumVariable( @@ -42,7 +64,7 @@ vars.Add( vars.Add( "DIST_SUFFIX", - help="Dist suffix", + help="Suffix for binaries in build output for dist targets", default="local", ) From 90049faee8428c253ba477bb2622928ac9ddf4bd Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 15:55:42 +0400 Subject: [PATCH 119/184] Docker: added pip + pillow + heatshrink --- docker/Dockerfile | 9 ++++++--- fbt.md | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 5aec3aae328d..ce80c9ccbb9a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,9 +16,10 @@ RUN apt-get update \ libxslt1-dev \ zlib1g-dev \ wget \ - imagemagick \ +# imagemagick \ python3-protobuf \ protobuf-compiler \ + python3-pip \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* @@ -30,8 +31,10 @@ RUN wget --progress=dot:giga "https://developer.arm.com/-/media/Files/downloads/ for file in * ; do ln -s "${PWD}/${file}" "/usr/bin/${file}" ; done && \ cd / && arm-none-eabi-gcc -v && arm-none-eabi-gdb -v -RUN git clone --depth 1 --branch v0.4.1 https://github.com/atomicobject/heatshrink.git && \ - cd heatshrink && make && mv ./heatshrink /usr/local/bin/heatshrink +RUN pip3 install heatshrink2==0.11.0 Pillow==9.1.1 + +#RUN git clone --depth 1 --branch v0.4.1 https://github.com/atomicobject/heatshrink.git && \ +# cd heatshrink && make && mv ./heatshrink /usr/local/bin/heatshrink RUN ln -s `which clang-format-12` /usr/local/bin/clang-format diff --git a/fbt.md b/fbt.md index e0aecea2a83d..3fd129c0bc72 100644 --- a/fbt.md +++ b/fbt.md @@ -1,7 +1,7 @@ # Flipper Build Tool FBT is the entry point for most firmware-related commands and utilities. -It is invoked by `./fbt` in firmware project root directory. Internally, it is a wrapper around scons build system. +It is invoked by `./fbt` in firmware project root directory. Internally, it is a wrapper around [scons](https://scons.org/) build system. ## NB FBT constructs all referenced environments & their targets' dependency trees on startup. So, to keep startup time as low as possible, we're hiding construction of certain targets behind command-line options. From 264e070d732d9bbd71f7d62203e0ff7ce8eeda33 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 16:01:43 +0400 Subject: [PATCH 120/184] Docker: added libpython3-dev --- docker/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index ce80c9ccbb9a..4a52f6a2b8c4 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,6 +20,7 @@ RUN apt-get update \ python3-protobuf \ protobuf-compiler \ python3-pip \ + libpython3-dev \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* From 51cd7f3914cbd00c95fdaa327e68107ea3831ac8 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 16:13:15 +0400 Subject: [PATCH 121/184] Docker: removed unused tools --- docker/Dockerfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 4a52f6a2b8c4..d581965fa7cb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,7 +16,6 @@ RUN apt-get update \ libxslt1-dev \ zlib1g-dev \ wget \ -# imagemagick \ python3-protobuf \ protobuf-compiler \ python3-pip \ @@ -34,9 +33,6 @@ RUN wget --progress=dot:giga "https://developer.arm.com/-/media/Files/downloads/ RUN pip3 install heatshrink2==0.11.0 Pillow==9.1.1 -#RUN git clone --depth 1 --branch v0.4.1 https://github.com/atomicobject/heatshrink.git && \ -# cd heatshrink && make && mv ./heatshrink /usr/local/bin/heatshrink - RUN ln -s `which clang-format-12` /usr/local/bin/clang-format COPY entrypoint.sh / From 926527d8bbc7468c869ace2dd7d207ea04c94d77 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 16:44:09 +0400 Subject: [PATCH 122/184] CI: attempt to fix web updater links --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8cc0bd9b4f3a..aafdb2fa28cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -153,7 +153,7 @@ jobs: comment-id: ${{ steps.fc.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} body: | - [Install with web updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}}) + [Install](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}}) with web updater edit-mode: replace compact: From ce93298dfc13627070dd651d64b73903827f555d Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 16:50:55 +0400 Subject: [PATCH 123/184] triggering CI rebuild --- fbt.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fbt.md b/fbt.md index 3fd129c0bc72..ff33462e4885 100644 --- a/fbt.md +++ b/fbt.md @@ -11,6 +11,7 @@ To build with FBT, call it specifying configuration options & targets to build. `./fbt --with-updater COMPACT=1 DEBUG=0 VERBOSE=1 updater_package copro_dist` + ## FBT targets FBT keeps track of internal dependencies, so you only need to build the highest-level target you need, and FBT will make sure everything it needs is up-to-date. @@ -34,11 +35,13 @@ FBT keeps track of internal dependencies, so you only need to build the highest- - `proto_ver` - generate .h with protobuf version - `dolphin_internal`, `dolphin_blocking` - generate .c+.h for corresponding dolphin assets + ## Command-line parameters - `--options optionfile.py` (default value `fbt_options.py`) - load file with multiple configuration values - `--with-updater` - enables updater-related targets and dependency tracking. Enabling this options introduces extra startup time costs, so use it when bundling update packages. Or if you have a fast computer and don't care about a few extra seconds of startup time. + ## Configuration Default configuration variables are set in configuration file `fbt_options.py`. Values set on command-line have higher precedence over configuration file. From 7a8ab4d11cec5dc45127cb8585d7fbbbedc47f91 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 17:58:32 +0400 Subject: [PATCH 124/184] Build: fixed malformed dist dir in certain configurations; Github: fixed updater links --- .github/workflows/build.yml | 8 ++++---- firmware/targets/f7/ble_glue/tl_dbg_conf.h | 1 - scripts/sconsdist.py | 9 ++++++--- site_scons/cc.scons | 1 + 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aafdb2fa28cc..5fd3724dea0a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,7 +78,7 @@ jobs: set -e for TARGET in ${TARGETS} do - ./fbt TARGET_HW=`echo ${TARGET} |sed 's/f//'` --with-updater updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} + ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` --with-updater updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} done - name: 'Move upload files' @@ -144,7 +144,7 @@ jobs: with: issue-number: ${{ github.event.pull_request.number }} comment-author: 'github-actions[bot]' - body-includes: 'to flash the' + body-includes: 'web updater' - name: 'Create or update comment' if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request}} @@ -153,7 +153,7 @@ jobs: comment-id: ${{ steps.fc.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} body: | - [Install](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}}) with web updater + [Install with web updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}}) edit-mode: replace compact: @@ -207,5 +207,5 @@ jobs: set -e for TARGET in ${TARGETS} do - ./fbt TARGET_HW=`echo ${TARGET} |sed 's/f//'` --with-updater updater_package DEBUG=0 COMPACT=1 + ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` --with-updater updater_package DEBUG=0 COMPACT=1 done diff --git a/firmware/targets/f7/ble_glue/tl_dbg_conf.h b/firmware/targets/f7/ble_glue/tl_dbg_conf.h index 6a96aa6e126c..ce58af32b8ac 100644 --- a/firmware/targets/f7/ble_glue/tl_dbg_conf.h +++ b/firmware/targets/f7/ble_glue/tl_dbg_conf.h @@ -33,7 +33,6 @@ extern "C" { #include "app_conf.h" /* required as some configuration used in dbg_trace.h are set there */ #include "dbg_trace.h" #include "hw_if.h" -//#include /** * Enable or Disable traces diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index c4549d3cfa6b..fcf679391f6e 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -13,8 +13,7 @@ def __init__(self, project_dir): parts = project_dir.split("-") self.target = parts[0] self.project = parts[1] - if len(parts) > 2: - self.flavor = parts[2] + self.flavor = parts[2] if len(parts) > 2 else "" class Main(App): @@ -82,7 +81,11 @@ def copy(self): return 2 self.flavor = project_flavors.pop() - self.output_dir_path = join("dist", f"{self.target}-{self.flavor}") + dist_dir_components = [self.target] + if self.flavor: + dist_dir_components.append(self.flavor) + + self.output_dir_path = join("dist", "-".join(dist_dir_components)) if exists(self.output_dir_path) and not self.args.noclean: shutil.rmtree(self.output_dir_path) diff --git a/site_scons/cc.scons b/site_scons/cc.scons index 144e5c8464bb..6e8ece9400df 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -14,6 +14,7 @@ ENV.AppendUnique( ], CCFLAGS=[ "-mcpu=cortex-m4", + # "-mtune=cortex-m4", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", "-mthumb", From f2f2581dec05c4f788e162a872e14f5dcf60c1ab Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 19:29:00 +0400 Subject: [PATCH 125/184] Build: migrating .scons files to proper tools --- SConstruct | 2 +- applications/extapps.scons | 2 +- firmware.scons | 53 +++++++------ site_scons/builders.scons | 58 -------------- site_scons/cc.scons | 1 - site_scons/environ.scons | 79 +++---------------- .../fbt_apps.py} | 24 ++++-- site_scons/site_tools/fwbin.py | 53 +++++++++++++ site_scons/site_tools/openocd.py | 39 +++++++++ site_scons/site_tools/sconsmodular.py | 38 +++++++++ site_scons/site_tools/sconsrecursiveglob.py | 25 ++++++ site_scons/site_tools/strip.py | 27 +++++++ 12 files changed, 239 insertions(+), 162 deletions(-) delete mode 100644 site_scons/builders.scons rename site_scons/{appmanifests.scons => site_tools/fbt_apps.py} (79%) create mode 100644 site_scons/site_tools/fwbin.py create mode 100644 site_scons/site_tools/openocd.py create mode 100644 site_scons/site_tools/sconsmodular.py create mode 100644 site_scons/site_tools/sconsrecursiveglob.py create mode 100644 site_scons/site_tools/strip.py diff --git a/SConstruct b/SConstruct index 7e447ac50b42..2b5d48f98522 100644 --- a/SConstruct +++ b/SConstruct @@ -9,6 +9,7 @@ from fbt.builders.dist import add_dist_builders, add_project_to_distenv +DefaultEnvironment(tools=[]) cmd_vars = SConscript("site_scons/commandline.scons") @@ -19,7 +20,6 @@ coreenv = SConscript( exports={"VARIABLES": cmd_vars}, ) SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) -SConscript("site_scons/builders.scons", exports={"ENV": coreenv}) # Store root dir in environment for certain tools coreenv["ROOT_DIR"] = Dir(".") diff --git a/applications/extapps.scons b/applications/extapps.scons index 6eca822ed4fc..1cb15c8522c0 100644 --- a/applications/extapps.scons +++ b/applications/extapps.scons @@ -4,7 +4,7 @@ Import("ENV") from fbt.appmanifest import FlipperAppType import os -appenv = ENV.Clone() +appenv = ENV.Clone(tools=["strip"]) EXT_APPS_WORK_DIR = ".extapps" diff --git a/firmware.scons b/firmware.scons index 539666b584fe..2214623c1926 100644 --- a/firmware.scons +++ b/firmware.scons @@ -4,10 +4,9 @@ import os # Building initial C environment for libs -env = ENV.Clone() -Export("env") - -env.Append( +env = ENV.Clone( + tools=["compilation_db", "fwbin", "openocd", "fbt_apps"], + COMPILATIONDB_USE_ABSPATH=True, BUILD_DIR=fw_build_meta["build_dir"], PLUGIN_ELF_DIR="${BUILD_DIR}", LIB_DIST_DIR="${BUILD_DIR}/lib", @@ -16,9 +15,6 @@ env.Append( LIBPATH=[ "${LIB_DIST_DIR}", ], - CPPDEFINES=[ - # ("TARGET", "${TARGET_HW}"), - ], CPPPATH=[ "#/core", "#/applications", @@ -45,6 +41,28 @@ env.Append( ) +def ApplyLibFlags(env): + flags_to_apply = env["FW_LIB_OPTS"].get( + env.get("FW_LIB_NAME"), + env["FW_LIB_OPTS"]["Default"], + ) + # print("Flags for ", env.get("FW_LIB_NAME", "Default"), flags_to_apply) + env.MergeFlags(flags_to_apply) + + +env.AddMethod(ApplyLibFlags) + +Export("env") + +if not env["VERBOSE"]: + env.SetDefault( + HEXCOMSTR="\tHEX\t${TARGET}", + BINCOMSTR="\tBIN\t${TARGET}", + DFUCOMSTR="\tDFU\t${TARGET}", + FLASHCOMSTR="\tFLASH\t${SOURCE}", + ) + + if fw_build_meta["type"] == "updater": env.Append( FIRMWARE_BUILD_CFG="updater", @@ -77,8 +95,6 @@ fwenv = env.Clone() # Set up additional app-specific build flags SConscript("site_scons/firmwareopts.scons", exports={"ENV": fwenv}) -# Prepare manifest-related env methods -SConscript("site_scons/appmanifests.scons", exports={"ENV": fwenv}) # Set up app configuration if env["FIRMWARE_BUILD_CFG"] == "updater": @@ -125,10 +141,9 @@ fwenv.AppendUnique( # Build applications.c for selected services & apps # Depends on virtual value-only node, so it only gets rebuilt when set of apps changes -apps_c = fwenv.Command( +apps_c = fwenv.ApplicationsC( "applications/applications.c", Value(fwenv["APPS"]), - action=fwenv["APPS_C_ACTION"], ) sources = [apps_c] @@ -201,7 +216,7 @@ Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu) # Additional FW-related pseudotargets if fwenv["IS_BASE_FIRMWARE"]: - flash = fwenv["FW_FLASH"] = fwenv.Flasher("${FIRMWARE_BUILD_CFG}") + flash = fwenv["FW_FLASH"] = fwenv.OOCDFlash("${FIRMWARE_BUILD_CFG}") if fwenv["FORCE"]: AlwaysBuild(flash) Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) @@ -211,20 +226,6 @@ if fwenv["IS_BASE_FIRMWARE"]: fwcdb = fwenv["FW_CDB"] = fwenv.CompilationDatabase("compile_database.json") Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb) -# fw_version_json = env["FW_VERSION_JSON"] -# Return("fwhex fwelf fwbin fw_version_json") - -# fw_output = FirmwareOutput( -# project=fwenv["FIRMWARE_BUILD_CFG"], -# dfu=fwdfu[0], -# elf=fwelf[0], -# bin=fwbin[0], -# json=env["FW_VERSION_JSON"][0], -# extapps=extapps, -# ) - -# Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", fw_output.artifacts) -# Return("fw_output") artifacts = [fwhex, fwbin, fwdfu, env["FW_VERSION_JSON"]] fwenv["FW_ARTIFACTS"] = artifacts diff --git a/site_scons/builders.scons b/site_scons/builders.scons deleted file mode 100644 index c23786c3b0bd..000000000000 --- a/site_scons/builders.scons +++ /dev/null @@ -1,58 +0,0 @@ -Import("ENV") - - -ENV.Append( - BUILDERS={ - "HEXBuilder": Builder( - action=Action( - '${OBJCOPY} -O ihex "${SOURCE}" "${TARGET}"', - "${HEXCOMSTR}", - ), - suffix=".hex", - src_suffix=".elf", - ), - "BINBuilder": Builder( - action=Action( - '${OBJCOPY} -O binary -S "${SOURCE}" "${TARGET}"', - "${BINCOMSTR}", - ), - suffix=".bin", - src_suffix=".elf", - ), - "DFUBuilder": Builder( - action=Action( - '${PYTHON3} ./scripts/bin2dfu.py -i "${SOURCE}" -o "${TARGET}" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"', - "${DFUCOMSTR}", - ), - suffix=".dfu", - src_suffix=".bin", - ), - "ELFStripper": Builder( - action=Action( - "${STRIPCOM}", - "${STRIPCOMSTR}", - ), - suffix=".elf", - src_suffix=".elf", - ), - "Flasher": Builder( - action=[ - Action( - 'openocd ${OPENOCD_OPTS} -c "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}"', - "${FLASHCOMSTR}", - ), - Touch("${TARGET}"), - ], - suffix=".flash", - src_suffix=".bin", - ), - } -) - -if not ENV["VERBOSE"]: - ENV.SetDefault( - HEXCOMSTR="\tHEX\t${TARGET}", - BINCOMSTR="\tBIN\t${TARGET}", - DFUCOMSTR="\tDFU\t${TARGET}", - FLASHCOMSTR="\tFLASH\t${SOURCE}", - ) diff --git a/site_scons/cc.scons b/site_scons/cc.scons index 6e8ece9400df..144e5c8464bb 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -14,7 +14,6 @@ ENV.AppendUnique( ], CCFLAGS=[ "-mcpu=cortex-m4", - # "-mtune=cortex-m4", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16", "-mthumb", diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 6751bf3b37d4..bf32e596f5d1 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -14,16 +14,21 @@ os.chdir("..") coreenv = Environment( variables=VARIABLES, - tools=["as", "gcc", "g++", "ar", "gnulink", "python", "compilation_db"], - OBJCOPY="objcopy", + tools=[ + "as", + "gcc", + "g++", + "ar", + "gnulink", + "python", + "sconsmodular", + "sconsrecursiveglob", + ], + # OBJCOPY="objcopy", PYTHON3="python3", - STRIP="strip", - STRIPFLAGS=[], - STRIPCOM="$STRIP $STRIPFLAGS $SOURCES -o $TARGET", TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", - COMPILATIONDB_USE_ABSPATH=True, ENV={ # Import PATH from OS env - scons doesn't do that by default "PATH": os.environ["PATH"], @@ -96,66 +101,4 @@ utils.wrap_tempfile(coreenv, "LINKCOM") utils.wrap_tempfile(coreenv, "ARCOM") -# Build env extensions - - -def GlobRecursive(env, pattern, node=".", exclude=None): - results = [] - if isinstance(node, str): - node = env.Dir(node) - for f in node.glob("*", source=True, exclude=exclude): - if isinstance(f, SCons.Node.FS.Dir): - results += env.GlobRecursive(pattern, f, exclude) - results += node.glob( - pattern, - source=True, - exclude=exclude, - ) - # print(f"Glob for {pattern} from {node}: {results}") - return results - - -def BuildModule(env, module): - # print("cwd", os.getcwd()) - # print(type(Dir(".").srcdir), dir(Dir(".").srcdir)) - src_dir = str(env.Dir(".").srcdir or os.getcwd()) - module_sconscript = os.path.join(src_dir, module, "SConscript") - if not os.path.exists(module_sconscript): - module_sconscript = os.path.join(src_dir, f"{module}.scons") - if not os.path.exists(module_sconscript): - print(f"Cannot build module {module}: scons file not found") - Exit(2) - - return env.SConscript( - module_sconscript, - variant_dir=os.path.join(env.subst("$BUILD_DIR"), module), - duplicate=0, - ) - - -def BuildModules(env, modules): - result = [] - for module in modules: - build_res = env.BuildModule(module) - # print("module ", module, build_res) - if build_res is None: - continue - result.append(build_res) - return result - - -def ApplyLibFlags(env): - flags_to_apply = env["FW_LIB_OPTS"].get( - env.get("FW_LIB_NAME"), - env["FW_LIB_OPTS"]["Default"], - ) - # print("Flags for ", env.get("FW_LIB_NAME", "Default"), flags_to_apply) - env.MergeFlags(flags_to_apply) - - -coreenv.AddMethod(GlobRecursive) -coreenv.AddMethod(ApplyLibFlags) -coreenv.AddMethod(BuildModule) -coreenv.AddMethod(BuildModules) - Return("coreenv") diff --git a/site_scons/appmanifests.scons b/site_scons/site_tools/fbt_apps.py similarity index 79% rename from site_scons/appmanifests.scons rename to site_scons/site_tools/fbt_apps.py index 0d48c9d882a3..cbeae2d0a623 100644 --- a/site_scons/appmanifests.scons +++ b/site_scons/site_tools/fbt_apps.py @@ -1,4 +1,5 @@ -Import("ENV") +from SCons.Builder import Builder +from SCons.Action import Action import SCons from fbt.appmanifest import FlipperAppType, AppManager, ApplicationsCGenerator @@ -35,10 +36,6 @@ def DumpApplicationConfig(target, source, env): ) -ENV.AddMethod(LoadApplicationManifests) -ENV.AddMethod(PrepareApplicationsBuild) - - def build_apps_c(target, source, env): target_file_name = target[0].path @@ -47,5 +44,18 @@ def build_apps_c(target, source, env): file.write(gen.generate()) -# Exports apps.c generation action to environment -ENV["APPS_C_ACTION"] = Action(build_apps_c, "${APPSCOMSTR}") +def generate(env): + env.AddMethod(LoadApplicationManifests) + env.AddMethod(PrepareApplicationsBuild) + + env.Append( + BUILDERS={ + "ApplicationsC": Builder( + action=Action(build_apps_c, "${APPSCOMSTR}"), + ), + } + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/fwbin.py b/site_scons/site_tools/fwbin.py new file mode 100644 index 000000000000..d72996172197 --- /dev/null +++ b/site_scons/site_tools/fwbin.py @@ -0,0 +1,53 @@ +from SCons.Builder import Builder +from SCons.Action import Action +import SCons + +__OBJCOPY_ARM_BIN = "arm-none-eabi-objcopy" + + +def generate(env): + # print("strip generate", env.Dump()) + env.SetDefault( + BIN2DFU="${ROOT_DIR.abspath}/scripts/bin2dfu.py", + OBJCOPY=__OBJCOPY_ARM_BIN, # FIXME + ) + env.Append( + BUILDERS={ + "HEXBuilder": Builder( + action=Action( + '${OBJCOPY} -O ihex "${SOURCE}" "${TARGET}"', + "${HEXCOMSTR}", + ), + suffix=".hex", + src_suffix=".elf", + ), + "BINBuilder": Builder( + action=Action( + '${OBJCOPY} -O binary -S "${SOURCE}" "${TARGET}"', + "${BINCOMSTR}", + ), + suffix=".bin", + src_suffix=".elf", + ), + "DFUBuilder": Builder( + action=Action( + '${PYTHON3} ${BIN2DFU} -i "${SOURCE}" -o "${TARGET}" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"', + "${DFUCOMSTR}", + ), + suffix=".dfu", + src_suffix=".bin", + ), + } + ) + + +def exists(env): + try: + return env["OBJCOPY"] + except KeyError: + pass + + if objcopy := env.WhereIs(__OBJCOPY_ARM_BIN): + return objcopy + + raise SCons.Errors.StopError("Could not detect objcopy for arm") diff --git a/site_scons/site_tools/openocd.py b/site_scons/site_tools/openocd.py new file mode 100644 index 000000000000..598bb90c6f76 --- /dev/null +++ b/site_scons/site_tools/openocd.py @@ -0,0 +1,39 @@ +from SCons.Builder import Builder +from SCons.Action import Action +from SCons.Defaults import Touch +import SCons + +__OPENOCD_BIN = "openocd" + + +def generate(env): + env.SetDefault( + OPENOCD=__OPENOCD_BIN, + ) + env.Append( + BUILDERS={ + "OOCDFlash": Builder( + action=[ + Action( + '${OPENOCD} ${OPENOCD_OPTS} -c "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}"', + "${FLASHCOMSTR}", + ), + Touch("${TARGET}"), + ], + suffix=".flash", + src_suffix=".bin", + ), + } + ) + + +def exists(env): + try: + return env["OPENOCD"] + except KeyError: + pass + + if openocd := env.WhereIs(__OPENOCD_BIN): + return openocd + + raise SCons.Errors.StopError("Could not detect openocd") diff --git a/site_scons/site_tools/sconsmodular.py b/site_scons/site_tools/sconsmodular.py new file mode 100644 index 000000000000..eeb900229c98 --- /dev/null +++ b/site_scons/site_tools/sconsmodular.py @@ -0,0 +1,38 @@ +import posixpath +import os + + +def BuildModule(env, module): + src_dir = str(env.Dir(".").srcdir or os.getcwd()) + module_sconscript = posixpath.join(src_dir, module, "SConscript") + if not os.path.exists(module_sconscript): + module_sconscript = posixpath.join(src_dir, f"{module}.scons") + if not os.path.exists(module_sconscript): + print(f"Cannot build module {module}: scons file not found") + Exit(2) + + return env.SConscript( + module_sconscript, + variant_dir=posixpath.join(env.subst("$BUILD_DIR"), module), + duplicate=0, + ) + + +def BuildModules(env, modules): + result = [] + for module in modules: + build_res = env.BuildModule(module) + # print("module ", module, build_res) + if build_res is None: + continue + result.append(build_res) + return result + + +def generate(env): + env.AddMethod(BuildModule) + env.AddMethod(BuildModules) + + +def exists(env): + return True diff --git a/site_scons/site_tools/sconsrecursiveglob.py b/site_scons/site_tools/sconsrecursiveglob.py new file mode 100644 index 000000000000..32ff55ea10ce --- /dev/null +++ b/site_scons/site_tools/sconsrecursiveglob.py @@ -0,0 +1,25 @@ +import SCons + + +def GlobRecursive(env, pattern, node=".", exclude=None): + results = [] + if isinstance(node, str): + node = env.Dir(node) + for f in node.glob("*", source=True, exclude=exclude): + if isinstance(f, SCons.Node.FS.Dir): + results += env.GlobRecursive(pattern, f, exclude) + results += node.glob( + pattern, + source=True, + exclude=exclude, + ) + # print(f"Glob for {pattern} from {node}: {results}") + return results + + +def generate(env): + env.AddMethod(GlobRecursive) + + +def exists(env): + return True diff --git a/site_scons/site_tools/strip.py b/site_scons/site_tools/strip.py new file mode 100644 index 000000000000..e4ca2fb6224f --- /dev/null +++ b/site_scons/site_tools/strip.py @@ -0,0 +1,27 @@ +from SCons.Builder import Builder +from SCons.Action import Action + + +def generate(env): + # print("strip generate", env.Dump()) + env.SetDefault( + STRIP="strip", + STRIPFLAGS=[], + STRIPCOM="$STRIP $STRIPFLAGS $SOURCES -o $TARGET", + ) + env.Append( + BUILDERS={ + "ELFStripper": Builder( + action=Action( + "${STRIPCOM}", + "${STRIPCOMSTR}", + ), + suffix=".elf", + src_suffix=".elf", + ), + } + ) + + +def exists(env): + return True From d1a6594c78ff2933ddc919462951d242e956ebfa Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 21:53:12 +0400 Subject: [PATCH 126/184] Build: wrapped toolchain+python3 in separate tools --- SConstruct | 8 ++++-- applications/extapps.scons | 2 +- firmware.scons | 8 +++--- site_scons/environ.scons | 47 ++++---------------------------- site_scons/site_tools/crosscc.py | 32 ++++++++++++++++++++++ site_scons/site_tools/python3.py | 13 +++++++++ site_scons/site_tools/strip.py | 1 - 7 files changed, 62 insertions(+), 49 deletions(-) create mode 100644 site_scons/site_tools/crosscc.py create mode 100644 site_scons/site_tools/python3.py diff --git a/SConstruct b/SConstruct index 2b5d48f98522..55ad2ce9e119 100644 --- a/SConstruct +++ b/SConstruct @@ -11,13 +11,17 @@ from fbt.builders.dist import add_dist_builders, add_project_to_distenv DefaultEnvironment(tools=[]) -cmd_vars = SConscript("site_scons/commandline.scons") +# This environment exists only for loading options & validating file/dir existance +fbt_variables = SConscript("site_scons/commandline.scons") +cmd_environment = Environment(tools=[], variables=fbt_variables) +Help(fbt_variables.GenerateHelpText(cmd_environment)) + # Building basic environment - tools, utility methods, cross-compilation # settings, gcc flags for Cortex-M4, basic builders and more coreenv = SConscript( "site_scons/environ.scons", - exports={"VARIABLES": cmd_vars}, + exports={"VAR_ENV": cmd_environment}, ) SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) diff --git a/applications/extapps.scons b/applications/extapps.scons index 1cb15c8522c0..6eca822ed4fc 100644 --- a/applications/extapps.scons +++ b/applications/extapps.scons @@ -4,7 +4,7 @@ Import("ENV") from fbt.appmanifest import FlipperAppType import os -appenv = ENV.Clone(tools=["strip"]) +appenv = ENV.Clone() EXT_APPS_WORK_DIR = ".extapps" diff --git a/firmware.scons b/firmware.scons index 2214623c1926..e996a0770c27 100644 --- a/firmware.scons +++ b/firmware.scons @@ -8,10 +8,10 @@ env = ENV.Clone( tools=["compilation_db", "fwbin", "openocd", "fbt_apps"], COMPILATIONDB_USE_ABSPATH=True, BUILD_DIR=fw_build_meta["build_dir"], - PLUGIN_ELF_DIR="${BUILD_DIR}", - LIB_DIST_DIR="${BUILD_DIR}/lib", IS_BASE_FIRMWARE=fw_build_meta["type"] == "firmware", FW_FLAVOR=fw_build_meta["flavor"], + PLUGIN_ELF_DIR="${BUILD_DIR}", + LIB_DIST_DIR="${BUILD_DIR}/lib", LIBPATH=[ "${LIB_DIST_DIR}", ], @@ -80,7 +80,7 @@ else: # Invoke child SCopscripts to populate global `env` + build their own part of the code -depends = env.BuildModules( +lib_targets = env.BuildModules( [ "lib", "firmware", @@ -204,7 +204,7 @@ fwelf = fwenv.Program( ) # Make it depend on everything child builders returned -Depends(fwelf, depends) +Depends(fwelf, lib_targets) AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) diff --git a/site_scons/environ.scons b/site_scons/environ.scons index bf32e596f5d1..3e01eb0fcabd 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -5,41 +5,28 @@ from fbt import utils import os import multiprocessing -Import("VARIABLES") +Import("VAR_ENV") -# Dirty hack to construct environment with PathVariable paths relative to -# upper dir -_cwd = os.getcwd() -os.chdir("..") - -coreenv = Environment( - variables=VARIABLES, +coreenv = VAR_ENV.Clone( tools=[ - "as", - "gcc", - "g++", - "ar", - "gnulink", - "python", + "crosscc", + "python3", "sconsmodular", "sconsrecursiveglob", ], - # OBJCOPY="objcopy", - PYTHON3="python3", + TOOLCHAIN_PREFIX="arm-none-eabi-", TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", ENV={ # Import PATH from OS env - scons doesn't do that by default "PATH": os.environ["PATH"], - # Proxying CI environment to child scripts + # Proxying CI environment to child processes & scripts "DIST_SUFFIX": os.environ.get("DIST_SUFFIX", None), "WORKFLOW_BRANCH_OR_TAG": os.environ.get("WORKFLOW_BRANCH_OR_TAG", None), }, ) -os.chdir(_cwd) - # If DIST_SUFFIX is set in environment, is has precedence (set by CI) if os_suffix := os.environ.get("DIST_SUFFIX", None): coreenv.Replace( @@ -61,13 +48,6 @@ if not coreenv["VERBOSE"]: STRIPCOMSTR="\tSTRIP\t${TARGET}", ) -if coreenv["PLATFORM"] == "win32": - # On Windows, Python 3 executable is usually just "python" - coreenv["PYTHON3"] = coreenv["PYTHON3"][:-1] - -Help(VARIABLES.GenerateHelpText(coreenv)) - - # Default value for commandline options SetOption("num_jobs", multiprocessing.cpu_count()) @@ -80,21 +60,6 @@ SetOption("max_drift", 1) # SetOption("random", 1) -# Setting up cross-compile tools -utils.prefix_commands( - coreenv, - "arm-none-eabi-", - [ - "AR", - "AS", - "CC", - "CXX", - "OBJCOPY", - "RANLIB", - "STRIP", - ], -) - # Setting up temp file parameters - to overcome command line length limits coreenv["TEMPFILEARGESCFUNC"] = utils.tempfile_arg_esc_func utils.wrap_tempfile(coreenv, "LINKCOM") diff --git a/site_scons/site_tools/crosscc.py b/site_scons/site_tools/crosscc.py new file mode 100644 index 000000000000..e8608cd9a5da --- /dev/null +++ b/site_scons/site_tools/crosscc.py @@ -0,0 +1,32 @@ +from SCons.Tool import asm +from SCons.Tool import gcc +from SCons.Tool import gxx +from SCons.Tool import ar +from SCons.Tool import gnulink +import strip + +from fbt import utils + + +def generate(env): + for orig_tool in (asm, gcc, gxx, ar, gnulink, strip): + orig_tool.generate(env) + env.SetDefault(TOOLCHAIN_PREFIX="arm-none-eabi-") + + utils.prefix_commands( + env, + env.subst("$TOOLCHAIN_PREFIX"), + [ + "AR", + "AS", + "CC", + "CXX", + "OBJCOPY", + "RANLIB", + "STRIP", + ], + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/python3.py b/site_scons/site_tools/python3.py new file mode 100644 index 000000000000..8ac5490ddaf5 --- /dev/null +++ b/site_scons/site_tools/python3.py @@ -0,0 +1,13 @@ +def generate(env): + py_name = "python3" + if env["PLATFORM"] == "win32": + # On Windows, Python 3 executable is usually just "python" + py_name = "python" + + env.SetDefault( + PYTHON3=py_name, + ) + + +def exists(env): + return True diff --git a/site_scons/site_tools/strip.py b/site_scons/site_tools/strip.py index e4ca2fb6224f..053956f22e04 100644 --- a/site_scons/site_tools/strip.py +++ b/site_scons/site_tools/strip.py @@ -3,7 +3,6 @@ def generate(env): - # print("strip generate", env.Dump()) env.SetDefault( STRIP="strip", STRIPFLAGS=[], From 7226f28d02ea8ed4b408908e78151c91a0ed527f Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 22:24:05 +0400 Subject: [PATCH 127/184] Build: eliminated fbt/builders; moved to site_tools --- SConstruct | 8 ++-- assets/SConscript | 24 +++-------- lib/toolbox/SConscript | 5 +-- site_scons/cc.scons | 2 +- site_scons/fbt/builders/__init__.py | 0 site_scons/fbt/utils.py | 31 ++++++++++++++ site_scons/fbt/version.py | 23 ++++++++++ .../assets.py => site_tools/fbt_assets.py} | 17 +++++++- .../dist.py => site_tools/fbt_dist.py} | 42 +++---------------- .../version.py => site_tools/fbt_version.py} | 31 +++----------- 10 files changed, 93 insertions(+), 90 deletions(-) delete mode 100644 site_scons/fbt/builders/__init__.py create mode 100644 site_scons/fbt/version.py rename site_scons/{fbt/builders/assets.py => site_tools/fbt_assets.py} (90%) rename site_scons/{fbt/builders/dist.py => site_tools/fbt_dist.py} (50%) rename site_scons/{fbt/builders/version.py => site_tools/fbt_version.py} (52%) diff --git a/SConstruct b/SConstruct index 55ad2ce9e119..2a49c66ece3f 100644 --- a/SConstruct +++ b/SConstruct @@ -7,11 +7,12 @@ # construction of certain targets behind command-line options. -from fbt.builders.dist import add_dist_builders, add_project_to_distenv +from fbt.utils import add_project_to_distenv + DefaultEnvironment(tools=[]) -# This environment exists only for loading options & validating file/dir existance +# This environment is created only for loading options & validating file/dir existance fbt_variables = SConscript("site_scons/commandline.scons") cmd_environment = Environment(tools=[], variables=fbt_variables) Help(fbt_variables.GenerateHelpText(cmd_environment)) @@ -32,8 +33,7 @@ coreenv["ROOT_DIR"] = Dir(".") # Create a separate "dist" environment and add construction envs to it -distenv = coreenv.Clone() -add_dist_builders(distenv) +distenv = coreenv.Clone(tools=["fbt_dist"]) firmware_out = add_project_to_distenv(distenv, coreenv, "firmware", "FW_ENV") Default(firmware_out["FW_ARTIFACTS"]) diff --git a/assets/SConscript b/assets/SConscript index c34198ab0a27..a0a96a9627bf 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -1,19 +1,10 @@ Import("env") -from fbt.builders.assets import add_assets_builders, proto_ver_generator - - -assetsenv = env.Clone(FW_LIB_NAME="assets") -assetsenv.ApplyLibFlags() - -# Setting up builders for scripts - -add_assets_builders(assetsenv) - -assetsenv.Append( - ASSETS_COMPILER="${ROOT_DIR.abspath}/scripts/assets.py", - NANOPB_COMPILER="${ROOT_DIR.abspath}/lib/nanopb/generator/nanopb_generator.py", +assetsenv = env.Clone( + tools=["fbt_assets"], + FW_LIB_NAME="assets", ) +assetsenv.ApplyLibFlags() if not assetsenv["VERBOSE"]: assetsenv.SetDefault( @@ -25,7 +16,6 @@ if not assetsenv["VERBOSE"]: ) # Gathering icons sources - icons_src = assetsenv.GlobRecursive("*.png", "icons") icons_src += assetsenv.GlobRecursive("frame_rate", "icons") @@ -65,13 +55,9 @@ Alias("dolphin_blocking", dolphin_blocking) # Protobuf version meta -proto_ver = assetsenv.Command( +proto_ver = assetsenv.ProtoVerBuilder( "protobuf_version.h", "#/assets/protobuf/Changelog", - action=Action( - proto_ver_generator, - "${PBVERCOMSTR}", - ), ) Depends(proto_ver, proto) Alias("proto_ver", proto_ver) diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 809a7f92ee74..26c233d98b5a 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -1,6 +1,6 @@ Import("env") -from fbt.builders.version import add_version_builders, get_fast_git_version_id +from fbt.version import get_fast_git_version_id env.Append( @@ -10,10 +10,9 @@ env.Append( ) -libenv = env.Clone(FW_LIB_NAME="toolbox") +libenv = env.Clone(tools=["fbt_version"], FW_LIB_NAME="toolbox") libenv.ApplyLibFlags() -add_version_builders(libenv) # Git Version management version_depends = [] diff --git a/site_scons/cc.scons b/site_scons/cc.scons index 144e5c8464bb..f4096613ace5 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -21,7 +21,7 @@ ENV.AppendUnique( # "-MP", "-Wall", "-Wextra", - # "-Werror", + "-Werror", "-Wno-address-of-packed-member", "-Wredundant-decls", "-fdata-sections", diff --git a/site_scons/fbt/builders/__init__.py b/site_scons/fbt/builders/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/site_scons/fbt/utils.py b/site_scons/fbt/utils.py index 3ab7be8312c4..69e75876de64 100644 --- a/site_scons/fbt/utils.py +++ b/site_scons/fbt/utils.py @@ -39,3 +39,34 @@ def get_variant_dirname(env, project=None): parts.append(suffix) return "-".join(parts) + + +def create_fw_build_targets(env, configuration_name): + flavor = get_variant_dirname(env, configuration_name) + build_dir = env.Dir("build").Dir(flavor).abspath + return env.SConscript( + "firmware.scons", + variant_dir=build_dir, + duplicate=0, + exports={ + "ENV": env, + "fw_build_meta": { + "type": configuration_name, + "flavor": flavor, + "build_dir": build_dir, + }, + }, + ) + + +def add_project_to_distenv(dist_env, core_env, fw_type, fw_env_key): + project_env = dist_env[fw_env_key] = create_fw_build_targets(core_env, fw_type) + dist_env.Append( + DIST_PROJECTS=[ + project_env["FW_FLAVOR"], + ], + DIST_DEPENDS=[ + project_env["FW_ARTIFACTS"], + ], + ) + return project_env diff --git a/site_scons/fbt/version.py b/site_scons/fbt/version.py new file mode 100644 index 000000000000..4745c7002ca0 --- /dev/null +++ b/site_scons/fbt/version.py @@ -0,0 +1,23 @@ +import subprocess +import datetime + + +def get_fast_git_version_id(): + try: + version = ( + subprocess.check_output( + [ + "git", + "describe", + "--always", + "--dirty", + "--all", + "--long", + ] + ) + .strip() + .decode() + ) + return (version, datetime.date.today()) + except Exception as e: + print("Failed to check for git changes", e) diff --git a/site_scons/fbt/builders/assets.py b/site_scons/site_tools/fbt_assets.py similarity index 90% rename from site_scons/fbt/builders/assets.py rename to site_scons/site_tools/fbt_assets.py index 70cdb75c2bd1..e52660847a0c 100644 --- a/site_scons/fbt/builders/assets.py +++ b/site_scons/site_tools/fbt_assets.py @@ -99,7 +99,12 @@ def proto_ver_generator(target, source, env): file.write("\n".join(version_file_data)) -def add_assets_builders(env): +def generate(env): + env.SetDefault( + ASSETS_COMPILER="${ROOT_DIR.abspath}/scripts/assets.py", + NANOPB_COMPILER="${ROOT_DIR.abspath}/lib/nanopb/generator/nanopb_generator.py", + ) + env.Append( BUILDERS={ "IconBuilder": Builder( @@ -132,5 +137,15 @@ def add_assets_builders(env): ), emitter=dolphin_emitter, ), + "ProtoVerBuilder": Builder( + action=Action( + proto_ver_generator, + "${PBVERCOMSTR}", + ), + ), } ) + + +def exists(env): + return True diff --git a/site_scons/fbt/builders/dist.py b/site_scons/site_tools/fbt_dist.py similarity index 50% rename from site_scons/fbt/builders/dist.py rename to site_scons/site_tools/fbt_dist.py index fbba9e0f9631..e8d1cd473feb 100644 --- a/site_scons/fbt/builders/dist.py +++ b/site_scons/site_tools/fbt_dist.py @@ -1,43 +1,9 @@ -from fbt.utils import get_variant_dirname - -import SCons from SCons.Builder import Builder from SCons.Action import Action from SCons.Script import Mkdir -def create_fw_build_targets(env, configuration_name): - flavor = get_variant_dirname(env, configuration_name) - build_dir = env.Dir("build").Dir(flavor).abspath - return env.SConscript( - "firmware.scons", - variant_dir=build_dir, - duplicate=0, - exports={ - "ENV": env, - "fw_build_meta": { - "type": configuration_name, - "flavor": flavor, - "build_dir": build_dir, - }, - }, - ) - - -def add_project_to_distenv(dist_env, core_env, fw_type, fw_env_key): - project_env = dist_env[fw_env_key] = create_fw_build_targets(core_env, fw_type) - dist_env.Append( - DIST_PROJECTS=[ - project_env["FW_FLAVOR"], - ], - DIST_DEPENDS=[ - project_env["FW_ARTIFACTS"], - ], - ) - return project_env - - -def add_dist_builders(env): +def generate(env): env.Append( BUILDERS={ "DistBuilder": Builder( @@ -56,10 +22,14 @@ def add_dist_builders(env): "--cube_ver=${COPRO_CUBE_VERSION} " "--stack_type=${COPRO_STACK_TYPE} " '--stack_file="${COPRO_STACK_BIN}" ' - "--stack_addr=${COPRO_STACK_ADDR}", + "--stack_addr=${COPRO_STACK_ADDR} ", ], "", ) ), } ) + + +def exists(env): + return True diff --git a/site_scons/fbt/builders/version.py b/site_scons/site_tools/fbt_version.py similarity index 52% rename from site_scons/fbt/builders/version.py rename to site_scons/site_tools/fbt_version.py index 82a028ee3229..5073c55d919a 100644 --- a/site_scons/fbt/builders/version.py +++ b/site_scons/site_tools/fbt_version.py @@ -1,31 +1,6 @@ -import SCons from SCons.Builder import Builder from SCons.Action import Action -import subprocess -import datetime - - -def get_fast_git_version_id(): - try: - version = ( - subprocess.check_output( - [ - "git", - "describe", - "--always", - "--dirty", - "--all", - "--long", - ] - ) - .strip() - .decode() - ) - return (version, datetime.date.today()) - except Exception as e: - print("Failed to check for git changes", e) - def version_emitter(target, source, env): target_dir = target[0] @@ -36,7 +11,7 @@ def version_emitter(target, source, env): return target, source -def add_version_builders(env): +def generate(env): env.Append( BUILDERS={ "VersionBuilder": Builder( @@ -48,3 +23,7 @@ def add_version_builders(env): ), } ) + + +def exists(env): + return True From 078f2a5664551a8998ec1291a46c707a76882fbd Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 22:26:39 +0400 Subject: [PATCH 128/184] Ble: typo fix in stack type enum --- firmware/targets/f7/ble_glue/ble_glue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 712db1208176..1546b58e4b47 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -123,9 +123,9 @@ static const char* ble_glue_get_reltype_str(const uint8_t reltype) { case INFO_STACK_TYPE_BLE_LIGHT: return "L"; case INFO_STACK_TYPE_BLE_BEACON: - return "Ba"; - case INFO_STACK_TYPE_BLE_BASIC: return "Be"; + case INFO_STACK_TYPE_BLE_BASIC: + return "Ba"; case INFO_STACK_TYPE_BLE_FULL_EXT_ADV: return "F+"; case INFO_STACK_TYPE_BLE_HCI_EXT_ADV: From 94d9a3ec9950f6018c2b97cd22c6a4160072b73a Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 22:53:16 +0400 Subject: [PATCH 129/184] Build: dist tools refactoring --- SConstruct | 22 ++++++---- site_scons/environ.scons | 8 ++-- site_scons/fbt/util.py | 19 ++++++++ site_scons/fbt/utils.py | 72 ------------------------------- site_scons/site_tools/crosscc.py | 8 +++- site_scons/site_tools/fbt_dist.py | 48 +++++++++++++++++++++ 6 files changed, 90 insertions(+), 87 deletions(-) create mode 100644 site_scons/fbt/util.py delete mode 100644 site_scons/fbt/utils.py diff --git a/SConstruct b/SConstruct index 2a49c66ece3f..325e1f00c060 100644 --- a/SConstruct +++ b/SConstruct @@ -7,10 +7,9 @@ # construction of certain targets behind command-line options. -from fbt.utils import add_project_to_distenv - - DefaultEnvironment(tools=[]) +# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) + # This environment is created only for loading options & validating file/dir existance fbt_variables = SConscript("site_scons/commandline.scons") @@ -29,19 +28,24 @@ SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) # Store root dir in environment for certain tools coreenv["ROOT_DIR"] = Dir(".") -# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) - - # Create a separate "dist" environment and add construction envs to it distenv = coreenv.Clone(tools=["fbt_dist"]) -firmware_out = add_project_to_distenv(distenv, coreenv, "firmware", "FW_ENV") +firmware_out = distenv.AddFwProject( + base_env=coreenv, + fw_type="firmware", + fw_env_key="FW_ENV", +) Default(firmware_out["FW_ARTIFACTS"]) -# If enabled, construct updater-related targets +# If enabled, initialize updater-related targets if GetOption("fullenv"): - updater_out = add_project_to_distenv(distenv, coreenv, "updater", "UPD_ENV") + updater_out = distenv.AddFwProject( + base_env=coreenv, + fw_type="updater", + fw_env_key="UPD_ENV", + ) # Target for self-update package selfupdate_dist = distenv.DistBuilder( diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 3e01eb0fcabd..67c3f22f17d3 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -1,6 +1,6 @@ import SCons from SCons.Platform import TempFileMunge -from fbt import utils +from fbt import util import os import multiprocessing @@ -61,9 +61,9 @@ SetOption("max_drift", 1) # Setting up temp file parameters - to overcome command line length limits -coreenv["TEMPFILEARGESCFUNC"] = utils.tempfile_arg_esc_func -utils.wrap_tempfile(coreenv, "LINKCOM") -utils.wrap_tempfile(coreenv, "ARCOM") +coreenv["TEMPFILEARGESCFUNC"] = util.tempfile_arg_esc_func +util.wrap_tempfile(coreenv, "LINKCOM") +util.wrap_tempfile(coreenv, "ARCOM") Return("coreenv") diff --git a/site_scons/fbt/util.py b/site_scons/fbt/util.py new file mode 100644 index 000000000000..9de24a9aa528 --- /dev/null +++ b/site_scons/fbt/util.py @@ -0,0 +1,19 @@ +import SCons +from SCons.Subst import quote_spaces + +import re + + +WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") + + +def tempfile_arg_esc_func(arg): + arg = quote_spaces(arg) + if SCons.Platform.platform_default() != "win32": + return arg + # GCC requires double Windows slashes, let's use UNIX separator + return WINPATHSEP_RE.sub(r"/\1", arg) + + +def wrap_tempfile(env, command): + env[command] = '${TEMPFILE("' + env[command] + '","$' + command + 'STR")}' diff --git a/site_scons/fbt/utils.py b/site_scons/fbt/utils.py deleted file mode 100644 index 69e75876de64..000000000000 --- a/site_scons/fbt/utils.py +++ /dev/null @@ -1,72 +0,0 @@ -import SCons -from SCons.Subst import quote_spaces - -import re - - -WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") - - -def tempfile_arg_esc_func(arg): - arg = quote_spaces(arg) - if SCons.Platform.platform_default() != "win32": - return arg - # GCC requires double Windows slashes, let's use UNIX separator - return WINPATHSEP_RE.sub(r"/\1", arg) - - -def wrap_tempfile(env, command): - env[command] = '${TEMPFILE("' + env[command] + '","$' + command + 'STR")}' - - -def prefix_commands(env, command_prefix, cmd_list): - for command in cmd_list: - if command in env: - env[command] = command_prefix + env[command] - - -def get_variant_dirname(env, project=None): - parts = [f"f{env['TARGET_HW']}"] - if project: - parts.append(project) - - suffix = "" - if env["DEBUG"]: - suffix += "D" - if env["COMPACT"]: - suffix += "C" - if suffix: - parts.append(suffix) - - return "-".join(parts) - - -def create_fw_build_targets(env, configuration_name): - flavor = get_variant_dirname(env, configuration_name) - build_dir = env.Dir("build").Dir(flavor).abspath - return env.SConscript( - "firmware.scons", - variant_dir=build_dir, - duplicate=0, - exports={ - "ENV": env, - "fw_build_meta": { - "type": configuration_name, - "flavor": flavor, - "build_dir": build_dir, - }, - }, - ) - - -def add_project_to_distenv(dist_env, core_env, fw_type, fw_env_key): - project_env = dist_env[fw_env_key] = create_fw_build_targets(core_env, fw_type) - dist_env.Append( - DIST_PROJECTS=[ - project_env["FW_FLAVOR"], - ], - DIST_DEPENDS=[ - project_env["FW_ARTIFACTS"], - ], - ) - return project_env diff --git a/site_scons/site_tools/crosscc.py b/site_scons/site_tools/crosscc.py index e8608cd9a5da..ace174c8a121 100644 --- a/site_scons/site_tools/crosscc.py +++ b/site_scons/site_tools/crosscc.py @@ -5,7 +5,11 @@ from SCons.Tool import gnulink import strip -from fbt import utils + +def prefix_commands(env, command_prefix, cmd_list): + for command in cmd_list: + if command in env: + env[command] = command_prefix + env[command] def generate(env): @@ -13,7 +17,7 @@ def generate(env): orig_tool.generate(env) env.SetDefault(TOOLCHAIN_PREFIX="arm-none-eabi-") - utils.prefix_commands( + prefix_commands( env, env.subst("$TOOLCHAIN_PREFIX"), [ diff --git a/site_scons/site_tools/fbt_dist.py b/site_scons/site_tools/fbt_dist.py index e8d1cd473feb..27ddec35a38f 100644 --- a/site_scons/site_tools/fbt_dist.py +++ b/site_scons/site_tools/fbt_dist.py @@ -3,7 +3,55 @@ from SCons.Script import Mkdir +def get_variant_dirname(env, project=None): + parts = [f"f{env['TARGET_HW']}"] + if project: + parts.append(project) + + suffix = "" + if env["DEBUG"]: + suffix += "D" + if env["COMPACT"]: + suffix += "C" + if suffix: + parts.append(suffix) + + return "-".join(parts) + + +def create_fw_build_targets(env, configuration_name): + flavor = get_variant_dirname(env, configuration_name) + build_dir = env.Dir("build").Dir(flavor).abspath + return env.SConscript( + "firmware.scons", + variant_dir=build_dir, + duplicate=0, + exports={ + "ENV": env, + "fw_build_meta": { + "type": configuration_name, + "flavor": flavor, + "build_dir": build_dir, + }, + }, + ) + + +def AddFwProject(env, base_env, fw_type, fw_env_key): + project_env = env[fw_env_key] = create_fw_build_targets(base_env, fw_type) + env.Append( + DIST_PROJECTS=[ + project_env["FW_FLAVOR"], + ], + DIST_DEPENDS=[ + project_env["FW_ARTIFACTS"], + ], + ) + return project_env + + def generate(env): + env.AddMethod(AddFwProject) env.Append( BUILDERS={ "DistBuilder": Builder( From 700d4cde63a51ee8a7c90beb334478069cc5404a Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 22:56:16 +0400 Subject: [PATCH 130/184] Docs: moved fbt.md to documentation/fbt.md --- fbt.md => documentation/fbt.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename fbt.md => documentation/fbt.md (100%) diff --git a/fbt.md b/documentation/fbt.md similarity index 100% rename from fbt.md rename to documentation/fbt.md From 8051fa3eacb651d781f98e0da5a950e09fed5014 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 13 Jun 2022 23:08:52 +0400 Subject: [PATCH 131/184] Scripts: fixed rare FS race on cleanup --- scripts/sconsdist.py | 5 ++++- site_scons/site_tools/fwbin.py | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index fcf679391f6e..1e95ee2f23f9 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -87,7 +87,10 @@ def copy(self): self.output_dir_path = join("dist", "-".join(dist_dir_components)) if exists(self.output_dir_path) and not self.args.noclean: - shutil.rmtree(self.output_dir_path) + try: + shutil.rmtree(self.output_dir_path) + except Exception as ex: + pass if not exists(self.output_dir_path): makedirs(self.output_dir_path) diff --git a/site_scons/site_tools/fwbin.py b/site_scons/site_tools/fwbin.py index d72996172197..848571e34e21 100644 --- a/site_scons/site_tools/fwbin.py +++ b/site_scons/site_tools/fwbin.py @@ -6,7 +6,6 @@ def generate(env): - # print("strip generate", env.Dump()) env.SetDefault( BIN2DFU="${ROOT_DIR.abspath}/scripts/bin2dfu.py", OBJCOPY=__OBJCOPY_ARM_BIN, # FIXME From b9a0b9dd8b8b4b3af2ef7583899b6ba9d37ed4fc Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 14 Jun 2022 12:41:57 +0400 Subject: [PATCH 132/184] Build: added toolchain whitelist --- fbt_options.py | 3 +++ site_scons/commandline.scons | 43 +++++++++++++------------------- site_scons/environ.scons | 9 +++++-- site_scons/site_tools/crosscc.py | 37 ++++++++++++++++++++++++--- 4 files changed, 61 insertions(+), 31 deletions(-) diff --git a/fbt_options.py b/fbt_options.py index ba7409edb6c9..32bae11f8484 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -36,3 +36,6 @@ "STM32WB_Copro_Wireless_Binaries", COPRO_MCU_FAMILY, ) + +# Supported toolchain versions +FBT_TOOLCHAIN_VERSIONS = (" 10.3.",) diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 0c65f34ff882..ad2028625f0d 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -22,36 +22,28 @@ AddOption( # Construction environment variables vars = Variables(GetOption("optionfile"), ARGUMENTS) -vars.Add( + +vars.AddVariables( BoolVariable( "VERBOSE", help="Print full commands", default=False, - ) -) -vars.Add( + ), BoolVariable( "FORCE", help="Force target action (for supported targets)", default=False, - ) -) -vars.Add( + ), BoolVariable( "DEBUG", help="Enable debug build", default=True, - ) -) -vars.Add( + ), BoolVariable( "COMPACT", help="Optimize for size", default=False, - ) -) - -vars.Add( + ), EnumVariable( "TARGET_HW", help="Hardware target", @@ -59,7 +51,7 @@ vars.Add( allowed_values=[ "7", ], - ) + ), ) vars.Add( @@ -100,31 +92,25 @@ vars.Add( default="", ) -vars.Add( +vars.AddVariables( PathVariable( "COPRO_OB_DATA", help="Path to OB reference data", validator=PathVariable.PathIsFile, default="", - ) -) -vars.Add( + ), PathVariable( "COPRO_STACK_BIN_DIR", help="Path to ST-provided stacks", validator=PathVariable.PathIsDir, default="", - ) -) -vars.Add( + ), PathVariable( "COPRO_CUBE_DIR", help="Path to Cube root", validator=PathVariable.PathIsDir, default="", - ) -) -vars.Add( + ), EnumVariable( "COPRO_STACK_TYPE", help="Core2 stack type", @@ -134,8 +120,13 @@ vars.Add( "ble_light", "ble_basic", ], - ) + ), ) +vars.Add( + "FBT_TOOLCHAIN_VERSIONS", + help="Whitelisted toolchain versions (leave empty for no check)", + default=tuple(), +) Return("vars") diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 67c3f22f17d3..581ad8d72a85 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -9,12 +9,17 @@ Import("VAR_ENV") coreenv = VAR_ENV.Clone( tools=[ - "crosscc", + ( + "crosscc", + { + "toolchain_prefix": "arm-none-eabi-", + "versions": VAR_ENV["FBT_TOOLCHAIN_VERSIONS"], + }, + ), "python3", "sconsmodular", "sconsrecursiveglob", ], - TOOLCHAIN_PREFIX="arm-none-eabi-", TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", diff --git a/site_scons/site_tools/crosscc.py b/site_scons/site_tools/crosscc.py index ace174c8a121..017b742e205b 100644 --- a/site_scons/site_tools/crosscc.py +++ b/site_scons/site_tools/crosscc.py @@ -5,6 +5,9 @@ from SCons.Tool import gnulink import strip +from SCons.Action import _subproc +import subprocess + def prefix_commands(env, command_prefix, cmd_list): for command in cmd_list: @@ -12,11 +15,30 @@ def prefix_commands(env, command_prefix, cmd_list): env[command] = command_prefix + env[command] -def generate(env): +def _get_tool_version(env, tool): + verstr = "version unknown" + proc = _subproc( + env, + env.subst("${%s} --version" % tool), + stdout=subprocess.PIPE, + stderr="devnull", + stdin="devnull", + universal_newlines=True, + error="raise", + shell=True, + ) + if proc: + verstr = proc.stdout.readline() + proc.communicate() + return verstr + + +def generate(env, **kw): for orig_tool in (asm, gcc, gxx, ar, gnulink, strip): orig_tool.generate(env) - env.SetDefault(TOOLCHAIN_PREFIX="arm-none-eabi-") - + env.SetDefault( + TOOLCHAIN_PREFIX=kw.get("toolchain_prefix"), + ) prefix_commands( env, env.subst("$TOOLCHAIN_PREFIX"), @@ -30,6 +52,15 @@ def generate(env): "STRIP", ], ) + # Call CC to check version + if whitelisted_versions := kw.get("versions", ()): + cc_version = _get_tool_version(env, "CC") + # print("CC version =", cc_version) + # print(list(filter(lambda v: v in cc_version, whitelisted_versions))) + if not any(filter(lambda v: v in cc_version, whitelisted_versions)): + raise Exception( + f"Toolchain version is not supported. Allowed: {whitelisted_versions}, toolchain: {cc_version} " + ) def exists(env): From da7ff9b48ee2f3840758dc68f7441010cb476248 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 14 Jun 2022 13:05:00 +0400 Subject: [PATCH 133/184] Build: removed COPRO_MCU_FAMILY from configurable options --- fbt_options.py | 5 +++-- site_scons/commandline.scons | 7 ------- site_scons/site_tools/fbt_dist.py | 3 +++ 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/fbt_options.py b/fbt_options.py index 32bae11f8484..6e7093d01a09 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -10,6 +10,8 @@ ## Optimize for debugging experience DEBUG = 1 +# Suffix to add to files when building distribution. +# If OS environment has DIST_SUFFIX set, it will be used instead.. DIST_SUFFIX = "local" # Coprocessor firmware @@ -18,7 +20,6 @@ # Must match lib/STM32CubeWB version COPRO_CUBE_VERSION = "1.13.3" -COPRO_MCU_FAMILY = "STM32WB5x" COPRO_CUBE_DIR = "lib/STM32CubeWB" # Default radio stack @@ -34,7 +35,7 @@ COPRO_CUBE_DIR, "Projects", "STM32WB_Copro_Wireless_Binaries", - COPRO_MCU_FAMILY, + "STM32WB5x", ) # Supported toolchain versions diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index ad2028625f0d..11f553f09c33 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -73,19 +73,12 @@ vars.Add( default="", ) -vars.Add( - "COPRO_MCU_FAMILY", - help="Cube MCU family", - default="", -) - vars.Add( "COPRO_STACK_ADDR", help="Core2 Firmware address", default="0", ) - vars.Add( "COPRO_STACK_BIN", help="Core2 Firmware file name", diff --git a/site_scons/site_tools/fbt_dist.py b/site_scons/site_tools/fbt_dist.py index 27ddec35a38f..c1db6eb3b7d3 100644 --- a/site_scons/site_tools/fbt_dist.py +++ b/site_scons/site_tools/fbt_dist.py @@ -52,6 +52,9 @@ def AddFwProject(env, base_env, fw_type, fw_env_key): def generate(env): env.AddMethod(AddFwProject) + env.SetDefault( + COPRO_MCU_FAMILY="STM32WB5x", + ) env.Append( BUILDERS={ "DistBuilder": Builder( From 773c73d84482f2c67d92809e19953bdb3e60b415 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 14 Jun 2022 13:52:34 +0400 Subject: [PATCH 134/184] Build: added FlipperAppType.EXTERNAL apps to firmware_extapps target --- applications/extapps.scons | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/applications/extapps.scons b/applications/extapps.scons index 6eca822ed4fc..785796b5c70c 100644 --- a/applications/extapps.scons +++ b/applications/extapps.scons @@ -46,17 +46,18 @@ appenv.AppendUnique( ) extapps = [] -for app in appenv["APPBUILD"].get_apps_of_type(FlipperAppType.PLUGIN): - app_elf = appenv.Program( - os.path.join(EXT_APPS_WORK_DIR, app.appid), - appenv.GlobRecursive("*.c*", os.path.join(EXT_APPS_WORK_DIR, app._appdir)), - APP_ENTRY=app.entry_point, - ) - app_stripped_elf = appenv.ELFStripper( - os.path.join(appenv["PLUGIN_ELF_DIR"], app.appid), app_elf - ) - extapps.append(app_stripped_elf) - Alias(f"{appenv['FIRMWARE_BUILD_CFG']}_{app.appid}", app_stripped_elf) +for apptype in (FlipperAppType.PLUGIN, FlipperAppType.EXTERNAL): + for app in appenv["APPBUILD"].get_apps_of_type(apptype): + app_elf = appenv.Program( + os.path.join(EXT_APPS_WORK_DIR, app.appid), + appenv.GlobRecursive("*.c*", os.path.join(EXT_APPS_WORK_DIR, app._appdir)), + APP_ENTRY=app.entry_point, + ) + app_stripped_elf = appenv.ELFStripper( + os.path.join(appenv["PLUGIN_ELF_DIR"], app.appid), app_elf + ) + extapps.append(app_stripped_elf) + Alias(f"{appenv['FIRMWARE_BUILD_CFG']}_{app.appid}", app_stripped_elf) Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) Return("extapps") From a887a2af0a91aa05fdc48fd3d19040e30060be40 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Thu, 16 Jun 2022 05:04:10 -0400 Subject: [PATCH 135/184] Add real toolchain link from linux and win --- scripts/toolchain/unix-toolchain-download.sh | 7 ++++--- scripts/toolchain/windows-toolchain-download.ps1 | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 5aca7bd96fed..39cb13b06417 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -12,7 +12,7 @@ check_system() TOOLCHAIN_URL="https://github.com/flipperdevices/flipperzero-firmware/archive/refs/tags/0.60.1-rc.tar.gz" elif [ "$SYS_TYPE" = "Linux" ]; then echo "linux"; - TOOLCHAIN_URL="https://github.com/flipperdevices/flipperzero-firmware/archive/refs/tags/0.60.1-rc.tar.gz" + TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux.tar.gz" else echo "unsupported."; echo "Your system is unsupported.. sorry.."; @@ -85,7 +85,7 @@ remove_old_tooclhain() unpack_toolchain() { printf "Unpacking toolchain.."; - TOOLCHAIN_DIR="$(tar -tf "$REPO_ROOT/$TOOLCHAIN_TAR" | head -n 1 | tr -d '/')"; + TOOLCHAIN_DIR="$(dirname -- "$(tar -tf "$REPO_ROOT/$TOOLCHAIN_TAR" | head -n 1)")"; tar -xf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/"; mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/toolchain"; echo "done"; @@ -111,7 +111,8 @@ main() fi remove_old_tooclhain; unpack_toolchain; - clearing; } +trap clearing EXIT; +trap clearing 2; # SIGINT not coverable by EXIT main; diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index cd9bbcdf84c0..5d5fd5077ace 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -2,7 +2,7 @@ Set-StrictMode -Version 2.0 $ErrorActionPreference = "Stop" [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" $repo_root = (Get-Item "$PSScriptRoot\..\..").FullName -$toolchain_url = "https://github.com/flipperdevices/flipperzero-firmware/archive/refs/tags/0.60.0-rc.zip" +$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-win32.zip" $toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-win32.zip" if (Test-Path -LiteralPath "$repo_root\toolchain") { @@ -17,9 +17,9 @@ Write-Host "done!" Write-Host -NoNewline "Unziping Windows toolchain.." Expand-Archive -LiteralPath "$toolchain_zip" -DestinationPath "$repo_root\" -Force -Rename-Item "$repo_root\flipperzero-firmware-0.60.0-rc" "$repo_root\toolchain" +Rename-Item "$repo_root\gcc-arm-none-eabi-10.3-2022.06-win32.zip" "$repo_root\toolchain" Write-Host "done!" Write-Host -NoNewline "Clearing temporary files.." Remove-Item -LiteralPath "$repo_root\$toolchain_zip" -Force -Write-Host "done!" \ No newline at end of file +Write-Host "done!" From 2dcf03aada083ed9f79b8a8553c61aa918c1bb29 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Thu, 16 Jun 2022 05:17:23 -0400 Subject: [PATCH 136/184] Fix toolchain archive name --- scripts/toolchain/unix-toolchain-download.sh | 4 ++-- scripts/toolchain/windows-toolchain-download.ps1 | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 39cb13b06417..055fadc4b6dd 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -9,10 +9,10 @@ check_system() SYS_TYPE="$(uname -s)" if [ "$SYS_TYPE" = "Darwin" ]; then echo "darwin"; - TOOLCHAIN_URL="https://github.com/flipperdevices/flipperzero-firmware/archive/refs/tags/0.60.1-rc.tar.gz" + TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz" elif [ "$SYS_TYPE" = "Linux" ]; then echo "linux"; - TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux.tar.gz" + TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz" else echo "unsupported."; echo "Your system is unsupported.. sorry.."; diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index 5d5fd5077ace..5b3a2491dab7 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -2,8 +2,8 @@ Set-StrictMode -Version 2.0 $ErrorActionPreference = "Stop" [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" $repo_root = (Get-Item "$PSScriptRoot\..\..").FullName -$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-win32.zip" -$toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-win32.zip" +$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" +$toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" if (Test-Path -LiteralPath "$repo_root\toolchain") { Write-Host -NoNewline "Removing old Windows toolchain.." @@ -17,7 +17,7 @@ Write-Host "done!" Write-Host -NoNewline "Unziping Windows toolchain.." Expand-Archive -LiteralPath "$toolchain_zip" -DestinationPath "$repo_root\" -Force -Rename-Item "$repo_root\gcc-arm-none-eabi-10.3-2022.06-win32.zip" "$repo_root\toolchain" +Rename-Item "$repo_root\gcc-arm-none-eabi-10.3-2022.06" "$repo_root\toolchain" Write-Host "done!" Write-Host -NoNewline "Clearing temporary files.." From c06dd09123d31326473defaadd35e11399bedff3 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 16 Jun 2022 14:12:23 +0400 Subject: [PATCH 137/184] Build: changed default target to fw_dist; renamed cdb file to compile_commands.json --- SConstruct | 3 ++- firmware.scons | 2 +- site_scons/cc.scons | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/SConstruct b/SConstruct index 325e1f00c060..e3a57ec5fafb 100644 --- a/SConstruct +++ b/SConstruct @@ -36,7 +36,7 @@ firmware_out = distenv.AddFwProject( fw_type="firmware", fw_env_key="FW_ENV", ) -Default(firmware_out["FW_ARTIFACTS"]) +# Default(firmware_out["FW_ARTIFACTS"]) # If enabled, initialize updater-related targets @@ -74,6 +74,7 @@ basic_dist = distenv.DistBuilder("pseudo2", distenv["DIST_DEPENDS"]) distenv.Pseudo("pseudo2") AlwaysBuild(basic_dist) Alias("fw_dist", basic_dist) +Default(basic_dist) # Target for bundling core2 package for qFlipper copro_dist = distenv.CoproBuilder( diff --git a/firmware.scons b/firmware.scons index e996a0770c27..06a4e2404584 100644 --- a/firmware.scons +++ b/firmware.scons @@ -223,7 +223,7 @@ if fwenv["IS_BASE_FIRMWARE"]: # Compile DB generation -fwcdb = fwenv["FW_CDB"] = fwenv.CompilationDatabase("compile_database.json") +fwcdb = fwenv["FW_CDB"] = fwenv.CompilationDatabase("compile_commands.json") Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb) diff --git a/site_scons/cc.scons b/site_scons/cc.scons index f4096613ace5..f6e2f2ed9771 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -26,9 +26,10 @@ ENV.AppendUnique( "-Wredundant-decls", "-fdata-sections", "-ffunction-sections", - # "-fno-diagnostics-show-caret", "-fno-math-errno", "-fstack-usage", + # "-Wno-stringop-overread", + # "-Wno-stringop-overflow", ], CPPDEFINES=[ "_GNU_SOURCE", From 17f7e5c6c3cad4f817226f9778c3b51e3f92660f Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 16 Jun 2022 15:20:30 +0400 Subject: [PATCH 138/184] Build: Added --extra-ext-apps argument for firmware_extapps target with list of apps to build as external .elfs --- applications/extapps.scons | 22 +++++++--------------- documentation/fbt.md | 9 ++++++--- site_scons/commandline.scons | 10 ++++++++++ site_scons/site_tools/fbt_extapps.py | 25 +++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 site_scons/site_tools/fbt_extapps.py diff --git a/applications/extapps.scons b/applications/extapps.scons index 785796b5c70c..aee9c29031a5 100644 --- a/applications/extapps.scons +++ b/applications/extapps.scons @@ -2,13 +2,9 @@ Import("ENV") from fbt.appmanifest import FlipperAppType -import os -appenv = ENV.Clone() +appenv = ENV.Clone(tools=["fbt_extapps"]) -EXT_APPS_WORK_DIR = ".extapps" - -appenv.VariantDir(EXT_APPS_WORK_DIR, ".", duplicate=False) appenv.Replace( LINKER_SCRIPT="application-ext", STRIPFLAGS=[ @@ -45,19 +41,15 @@ appenv.AppendUnique( ], ) + extapps = [] for apptype in (FlipperAppType.PLUGIN, FlipperAppType.EXTERNAL): for app in appenv["APPBUILD"].get_apps_of_type(apptype): - app_elf = appenv.Program( - os.path.join(EXT_APPS_WORK_DIR, app.appid), - appenv.GlobRecursive("*.c*", os.path.join(EXT_APPS_WORK_DIR, app._appdir)), - APP_ENTRY=app.entry_point, - ) - app_stripped_elf = appenv.ELFStripper( - os.path.join(appenv["PLUGIN_ELF_DIR"], app.appid), app_elf - ) - extapps.append(app_stripped_elf) - Alias(f"{appenv['FIRMWARE_BUILD_CFG']}_{app.appid}", app_stripped_elf) + extapps.append(appenv.BuildAppElf(app)) + +# Ugly access to global option +for extra_app in GetOption("extraextapps").split(","): + extapps.append(appenv.BuildAppElf(appenv["APPMGR"].get(extra_app))) Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) Return("extapps") diff --git a/documentation/fbt.md b/documentation/fbt.md index ff33462e4885..1cc1f2c346e1 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -11,9 +11,10 @@ To build with FBT, call it specifying configuration options & targets to build. `./fbt --with-updater COMPACT=1 DEBUG=0 VERBOSE=1 updater_package copro_dist` +To run cleanup (think of `make clean`) for specified targets, all `-c` option. ## FBT targets -FBT keeps track of internal dependencies, so you only need to build the highest-level target you need, and FBT will make sure everything it needs is up-to-date. +FBT keeps track of internal dependencies, so you only need to build the highest-level target you need, and FBT will make sure everything it needs is up-to-date. ### High-level (what you most likely need) - `fw_dist` - build & publish firmware to `dist` folder @@ -23,9 +24,10 @@ FBT keeps track of internal dependencies, so you only need to build the highest- ### Firmware targets - `firmware_extapps` - build all plug-ins as separate .elf files - `firmware_snake_game`, etc - build single plug-in as .elf by its name + - Check out `--extra-ext-apps` for force adding extra apps to external build - `firmware_flash` - flash current version to attached device with OpenOCD - `firmware_cdb` - generate compilation database -- `firmware_all`, `updater_all` - build basic set of binaries +- `firmware_all`, `updater_all` - build basic set of binaries ### Assets - `resources` - build resources and their Manifest @@ -39,7 +41,8 @@ FBT keeps track of internal dependencies, so you only need to build the highest- ## Command-line parameters - `--options optionfile.py` (default value `fbt_options.py`) - load file with multiple configuration values -- `--with-updater` - enables updater-related targets and dependency tracking. Enabling this options introduces extra startup time costs, so use it when bundling update packages. Or if you have a fast computer and don't care about a few extra seconds of startup time. +- `--with-updater` - enables updater-related targets and dependency tracking. Enabling this options introduces extra startup time costs, so use it when bundling update packages. Or if you have a fast computer and don't care about a few extra seconds of startup time +- `--extra-ext-apps=app1,app2,appn` - when building `firmware_extapps` ## Configuration diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 11f553f09c33..e6e5802b8c35 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -18,6 +18,16 @@ AddOption( help="Enviroment option file", ) +AddOption( + "--extra-ext-apps", + action="store", + dest="extraextapps", + default="", + # type=str, + # nargs="+", + help="List of applications to forcefully build as standalone .elf", +) + # Construction environment variables diff --git a/site_scons/site_tools/fbt_extapps.py b/site_scons/site_tools/fbt_extapps.py new file mode 100644 index 000000000000..e2b93f7bff44 --- /dev/null +++ b/site_scons/site_tools/fbt_extapps.py @@ -0,0 +1,25 @@ +import os + + +def BuildAppElf(env, app): + work_dir = env.subst("$EXT_APPS_WORK_DIR") + app_elf = env.Program( + os.path.join(work_dir, app.appid), + env.GlobRecursive("*.c*", os.path.join(work_dir, app._appdir)), + APP_ENTRY=app.entry_point, + ) + app_stripped_elf = env.ELFStripper( + os.path.join(env.subst("$PLUGIN_ELF_DIR"), app.appid), app_elf + ) + env.Alias(f"{env['FIRMWARE_BUILD_CFG']}_{app.appid}", app_stripped_elf) + return app_stripped_elf + + +def generate(env, **kw): + env.SetDefault(EXT_APPS_WORK_DIR=kw.get("EXT_APPS_WORK_DIR", ".extapps")) + env.VariantDir(env.subst("$EXT_APPS_WORK_DIR"), ".", duplicate=False) + env.AddMethod(BuildAppElf) + + +def exists(env): + return True From 1f2aa7878c482686cb3d85e58ab31c99c07f1346 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Thu, 16 Jun 2022 09:10:42 -0400 Subject: [PATCH 139/184] Start writing fbt.sh.bat --- fbt | 6 --- fbt.sh.bat | 22 ++++++++++ .../toolchain/generate-toolchain-download.sh | 41 ++++++++++++------- toolchain-download.sh.bat | 14 ------- 4 files changed, 48 insertions(+), 35 deletions(-) delete mode 100755 fbt create mode 100755 fbt.sh.bat delete mode 100755 toolchain-download.sh.bat diff --git a/fbt b/fbt deleted file mode 100755 index 9ab37fe61aff..000000000000 --- a/fbt +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -set +x - -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" -/usr/bin/env python3 lib/scons/scripts/scons.py ${SCONS_DEFAULT_FLAGS} "$@" diff --git a/fbt.sh.bat b/fbt.sh.bat new file mode 100755 index 000000000000..9210baaf58b1 --- /dev/null +++ b/fbt.sh.bat @@ -0,0 +1,22 @@ +echo >/dev/null # >nul & GOTO WINDOWS & rem ^ +# *********************************************************** +# * NOTE: Generated by scripts/toolchain/generate-toolchain-download.sh +# * If you modify this file, use script or remove carriage returns (\r)\n +# * from the Unix part and leave them in Windows part. In summary: +# * New lines in Unix: \n\n +# * New lines in Windows: \r\n +# *********************************************************** +SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" +if [ ! -d "$SCRIPT_PATH/toolchain" ]; then + scripts/toolchain/unix-toolchain-download.sh +fi +PATH="$SCRIPT_PATH/toolchain/python/bin:$PATH" +PATH="$SCRIPT_PATH/toolchain/bin:$PATH" +PATH="$SCRIPT_PATH/toolchain/protobuf/bin:$PATH" +python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS "$@" +exit 0 +:WINDOWS +@echo off +cls +powershell -ExecutionPolicy Bypass -File scripts\toolchain\windows-toolchain-download.ps1 diff --git a/scripts/toolchain/generate-toolchain-download.sh b/scripts/toolchain/generate-toolchain-download.sh index 8498ba825740..886f953a0ef0 100755 --- a/scripts/toolchain/generate-toolchain-download.sh +++ b/scripts/toolchain/generate-toolchain-download.sh @@ -1,19 +1,30 @@ #!/bin/bash SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; PROJECT_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; -printf "echo >/dev/null # >nul & GOTO WINDOWS & rem ^\r\n" > "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "# ***********************************************************\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "# * NOTE: If you modify this content, be sure to remove carriage returns (\\\r)\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "# * from the Linux part and leave them in together with the line feeds\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "# * (\\\n) for the Windows part. In summary:\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "# * New lines in Linux: \\\n\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "# * New lines in Windows: \\\r\\\n\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "# ***********************************************************\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "scripts/toolchain/unix-toolchain-download.sh\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "exit 0\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf ":WINDOWS\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "@echo off\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "cls\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" -printf "powershell -ExecutionPolicy Bypass -File scripts\\\toolchain\\\windows-toolchain-download.ps1\r\n" >> "$PROJECT_ROOT/toolchain-download.sh.bat" +OUT_FILE="$PROJECT_ROOT/fbt.sh.bat"; +UNIX_END="\n"; +WIN_END="\r\n"; +printf "echo >/dev/null # >nul & GOTO WINDOWS & rem ^$WIN_END" > "$OUT_FILE" +printf "# ***********************************************************$UNIX_END" >> "$OUT_FILE" +printf "# * NOTE: Generated by scripts/toolchain/generate-toolchain-download.sh$UNIX_END" >> "$OUT_FILE" +printf "# * If you modify this file, use script or remove carriage returns (\\\r)\\\n$UNIX_END" >> "$OUT_FILE" +printf "# * from the Unix part and leave them in Windows part. In summary:$UNIX_END" >> "$OUT_FILE" +printf "# * New lines in Unix: \\\n\\\n$UNIX_END" >> "$OUT_FILE" +printf "# * New lines in Windows: \\\r\\\n$UNIX_END" >> "$OUT_FILE" +printf "# ***********************************************************$UNIX_END" >> "$OUT_FILE" +printf "SCRIPT_PATH=\"\$(dirname -- \"\$(readlink -f -- \"\$0\")\")\";$UNIX_END" >> "$OUT_FILE" +printf "SCONS_DEFAULT_FLAGS=\"-Q --warn=target-not-built\"$UNIX_END" >> "$OUT_FILE" +printf "if [ ! -d \"\$SCRIPT_PATH/toolchain\" ]; then$UNIX_END" >> "$OUT_FILE" +printf " scripts/toolchain/unix-toolchain-download.sh$UNIX_END" >> "$OUT_FILE" +printf "fi$UNIX_END" >> "$OUT_FILE" +printf "PATH=\"\$SCRIPT_PATH/toolchain/python/bin:\$PATH\"$UNIX_END" >> "$OUT_FILE" +printf "PATH=\"\$SCRIPT_PATH/toolchain/bin:\$PATH\"$UNIX_END" >> "$OUT_FILE" +printf "PATH=\"\$SCRIPT_PATH/toolchain/protobuf/bin:\$PATH\"$UNIX_END" >> "$OUT_FILE" +printf "python3 lib/scons/scripts/scons.py \$SCONS_DEFAULT_FLAGS \"\$@\"$UNIX_END" >> "$OUT_FILE" +printf "exit 0$UNIX_END" >> "$OUT_FILE" +printf ":WINDOWS$WIN_END" >> "$OUT_FILE" +printf "@echo off$WIN_END" >> "$OUT_FILE" +printf "cls$WIN_END" >> "$OUT_FILE" +printf "powershell -ExecutionPolicy Bypass -File scripts\\\toolchain\\\windows-toolchain-download.ps1$WIN_END" >> "$OUT_FILE" -chmod +x "$PROJECT_ROOT/toolchain-download.sh.bat" +chmod +x "$OUT_FILE" diff --git a/toolchain-download.sh.bat b/toolchain-download.sh.bat deleted file mode 100755 index 21dd1684f508..000000000000 --- a/toolchain-download.sh.bat +++ /dev/null @@ -1,14 +0,0 @@ -echo >/dev/null # >nul & GOTO WINDOWS & rem ^ -# *********************************************************** -# * NOTE: If you modify this content, be sure to remove carriage returns (\r)\n -# * from the Linux part and leave them in together with the line feeds -# * (\n) for the Windows part. In summary: -# * New lines in Linux: \n\n -# * New lines in Windows: \r\n -# *********************************************************** -scripts/toolchain/unix-toolchain-download.sh -exit 0 -:WINDOWS -@echo off -cls -powershell -ExecutionPolicy Bypass -File scripts\toolchain\windows-toolchain-download.ps1 From cadbe552f8709c60fc40c5c7969f519c458cd07e Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Thu, 16 Jun 2022 10:43:57 -0400 Subject: [PATCH 140/184] add windows part to fbt.sh.bat --- fbt.sh.bat | 23 ++++++------- scripts/toolchain/generate-fbt.sh | 32 +++++++++++++++++++ .../toolchain/generate-toolchain-download.sh | 30 ----------------- 3 files changed, 44 insertions(+), 41 deletions(-) create mode 100755 scripts/toolchain/generate-fbt.sh delete mode 100755 scripts/toolchain/generate-toolchain-download.sh diff --git a/fbt.sh.bat b/fbt.sh.bat index 9210baaf58b1..9ba63e7a7143 100755 --- a/fbt.sh.bat +++ b/fbt.sh.bat @@ -1,22 +1,23 @@ -echo >/dev/null # >nul & GOTO WINDOWS & rem ^ +echo >/dev/null # >nul & @echo off & GOTO WINDOWS & rem ^ # *********************************************************** -# * NOTE: Generated by scripts/toolchain/generate-toolchain-download.sh +# * NOTE: Generated by scripts/toolchain/generate-fbt.sh # * If you modify this file, use script or remove carriage returns (\r)\n # * from the Unix part and leave them in Windows part. In summary: # * New lines in Unix: \n\n # * New lines in Windows: \r\n # *********************************************************** SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; if [ ! -d "$SCRIPT_PATH/toolchain" ]; then - scripts/toolchain/unix-toolchain-download.sh + scripts/toolchain/unix-toolchain-download.sh || exit 1; fi -PATH="$SCRIPT_PATH/toolchain/python/bin:$PATH" -PATH="$SCRIPT_PATH/toolchain/bin:$PATH" -PATH="$SCRIPT_PATH/toolchain/protobuf/bin:$PATH" +PATH="$SCRIPT_PATH/toolchain/python/bin:$PATH"; +PATH="$SCRIPT_PATH/toolchain/bin:$PATH"; +PATH="$SCRIPT_PATH/toolchain/protobuf/bin:$PATH"; python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS "$@" -exit 0 +exit 0; :WINDOWS -@echo off -cls -powershell -ExecutionPolicy Bypass -File scripts\toolchain\windows-toolchain-download.ps1 +set "toolchainRoot=%~dp0toolchain" +set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" +if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) +cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/scripts/toolchain/generate-fbt.sh b/scripts/toolchain/generate-fbt.sh new file mode 100755 index 000000000000..eb30af7bfa9d --- /dev/null +++ b/scripts/toolchain/generate-fbt.sh @@ -0,0 +1,32 @@ +#!/bin/bash +SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; +PROJECT_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; +OUT_FILE="$PROJECT_ROOT/fbt.sh.bat"; +UNIX_END="\n"; +WIN_END="\r\n"; + +printf "echo >/dev/null # >nul & @echo off & GOTO WINDOWS & rem ^$WIN_END" > "$OUT_FILE" +printf "# ***********************************************************$UNIX_END" >> "$OUT_FILE" +printf "# * NOTE: Generated by scripts/toolchain/generate-fbt.sh$UNIX_END" >> "$OUT_FILE" +printf "# * If you modify this file, use script or remove carriage returns (\\\r)\\\n$UNIX_END" >> "$OUT_FILE" +printf "# * from the Unix part and leave them in Windows part. In summary:$UNIX_END" >> "$OUT_FILE" +printf "# * New lines in Unix: \\\n\\\n$UNIX_END" >> "$OUT_FILE" +printf "# * New lines in Windows: \\\r\\\n$UNIX_END" >> "$OUT_FILE" +printf "# ***********************************************************$UNIX_END" >> "$OUT_FILE" +printf "SCRIPT_PATH=\"\$(dirname -- \"\$(readlink -f -- \"\$0\")\")\";$UNIX_END" >> "$OUT_FILE" +printf "SCONS_DEFAULT_FLAGS=\"-Q --warn=target-not-built\";$UNIX_END" >> "$OUT_FILE" +printf "if [ ! -d \"\$SCRIPT_PATH/toolchain\" ]; then$UNIX_END" >> "$OUT_FILE" +printf " scripts/toolchain/unix-toolchain-download.sh || exit 1;$UNIX_END" >> "$OUT_FILE" +printf "fi$UNIX_END" >> "$OUT_FILE" +printf "PATH=\"\$SCRIPT_PATH/toolchain/python/bin:\$PATH\";$UNIX_END" >> "$OUT_FILE" +printf "PATH=\"\$SCRIPT_PATH/toolchain/bin:\$PATH\";$UNIX_END" >> "$OUT_FILE" +printf "PATH=\"\$SCRIPT_PATH/toolchain/protobuf/bin:\$PATH\";$UNIX_END" >> "$OUT_FILE" +printf "python3 lib/scons/scripts/scons.py \$SCONS_DEFAULT_FLAGS \"\$@\"$UNIX_END" >> "$OUT_FILE" +printf "exit 0;$UNIX_END" >> "$OUT_FILE" +printf ":WINDOWS$WIN_END" >> "$OUT_FILE" +printf "set \"toolchainRoot=%%~dp0toolchain\"$WIN_END" >> "$OUT_FILE" +printf "set \"SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built\"$WIN_END" >> "$OUT_FILE" +printf "if not exist \"%%toolchainRoot%%\" (powershell -ExecutionPolicy Bypass -File %%~dp0scripts\\\toolchain\\\windows-toolchain-download.ps1)$WIN_END" >> "$OUT_FILE" +printf "cmd /V /C \"set \"PATH=%%toolchainRoot%%\\\python;%%toolchainRoot%%\\\bin;%%toolchainRoot%%\\\protoc\\\bin;%%PATH%%\" && python lib\\\scons\\\scripts\\\scons.py %%SCONS_DEFAULT_FLAGS%% %%*\"$WIN_END" >> "$OUT_FILE" + +chmod +x "$OUT_FILE" diff --git a/scripts/toolchain/generate-toolchain-download.sh b/scripts/toolchain/generate-toolchain-download.sh deleted file mode 100755 index 886f953a0ef0..000000000000 --- a/scripts/toolchain/generate-toolchain-download.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; -PROJECT_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; -OUT_FILE="$PROJECT_ROOT/fbt.sh.bat"; -UNIX_END="\n"; -WIN_END="\r\n"; -printf "echo >/dev/null # >nul & GOTO WINDOWS & rem ^$WIN_END" > "$OUT_FILE" -printf "# ***********************************************************$UNIX_END" >> "$OUT_FILE" -printf "# * NOTE: Generated by scripts/toolchain/generate-toolchain-download.sh$UNIX_END" >> "$OUT_FILE" -printf "# * If you modify this file, use script or remove carriage returns (\\\r)\\\n$UNIX_END" >> "$OUT_FILE" -printf "# * from the Unix part and leave them in Windows part. In summary:$UNIX_END" >> "$OUT_FILE" -printf "# * New lines in Unix: \\\n\\\n$UNIX_END" >> "$OUT_FILE" -printf "# * New lines in Windows: \\\r\\\n$UNIX_END" >> "$OUT_FILE" -printf "# ***********************************************************$UNIX_END" >> "$OUT_FILE" -printf "SCRIPT_PATH=\"\$(dirname -- \"\$(readlink -f -- \"\$0\")\")\";$UNIX_END" >> "$OUT_FILE" -printf "SCONS_DEFAULT_FLAGS=\"-Q --warn=target-not-built\"$UNIX_END" >> "$OUT_FILE" -printf "if [ ! -d \"\$SCRIPT_PATH/toolchain\" ]; then$UNIX_END" >> "$OUT_FILE" -printf " scripts/toolchain/unix-toolchain-download.sh$UNIX_END" >> "$OUT_FILE" -printf "fi$UNIX_END" >> "$OUT_FILE" -printf "PATH=\"\$SCRIPT_PATH/toolchain/python/bin:\$PATH\"$UNIX_END" >> "$OUT_FILE" -printf "PATH=\"\$SCRIPT_PATH/toolchain/bin:\$PATH\"$UNIX_END" >> "$OUT_FILE" -printf "PATH=\"\$SCRIPT_PATH/toolchain/protobuf/bin:\$PATH\"$UNIX_END" >> "$OUT_FILE" -printf "python3 lib/scons/scripts/scons.py \$SCONS_DEFAULT_FLAGS \"\$@\"$UNIX_END" >> "$OUT_FILE" -printf "exit 0$UNIX_END" >> "$OUT_FILE" -printf ":WINDOWS$WIN_END" >> "$OUT_FILE" -printf "@echo off$WIN_END" >> "$OUT_FILE" -printf "cls$WIN_END" >> "$OUT_FILE" -printf "powershell -ExecutionPolicy Bypass -File scripts\\\toolchain\\\windows-toolchain-download.ps1$WIN_END" >> "$OUT_FILE" - -chmod +x "$OUT_FILE" From 3a6cca89c06e5480388fa3bfd45b26bd091d5d9c Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Thu, 16 Jun 2022 10:45:20 -0400 Subject: [PATCH 141/184] remove old fbt script --- fbt.cmd | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 fbt.cmd diff --git a/fbt.cmd b/fbt.cmd deleted file mode 100644 index 95e72a8a5dc8..000000000000 --- a/fbt.cmd +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" -python lib/scons/scripts/scons.py %SCONS_DEFAULT_FLAGS% %* From 5a9a3b307440dced5472f3d622c5fff2a9b68223 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 17 Jun 2022 05:32:36 +0400 Subject: [PATCH 142/184] Build: Moved OpenOCD options to config file --- applications/extapps.scons | 5 +++-- fbt_options.py | 2 ++ site_scons/commandline.scons | 6 ++++++ site_scons/firmwareopts.scons | 1 - 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/applications/extapps.scons b/applications/extapps.scons index aee9c29031a5..e106540e6b29 100644 --- a/applications/extapps.scons +++ b/applications/extapps.scons @@ -48,8 +48,9 @@ for apptype in (FlipperAppType.PLUGIN, FlipperAppType.EXTERNAL): extapps.append(appenv.BuildAppElf(app)) # Ugly access to global option -for extra_app in GetOption("extraextapps").split(","): - extapps.append(appenv.BuildAppElf(appenv["APPMGR"].get(extra_app))) +if extra_app_list := GetOption("extraextapps"): + for extra_app in extra_app_list.split(","): + extapps.append(appenv.BuildAppElf(appenv["APPMGR"].get(extra_app))) Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps) Return("extapps") diff --git a/fbt_options.py b/fbt_options.py index 6e7093d01a09..ebd57461af15 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -40,3 +40,5 @@ # Supported toolchain versions FBT_TOOLCHAIN_VERSIONS = (" 10.3.",) + +OPENOCD_OPTS = '-f interface/stlink.cfg -c "transport select hla_swd" -f debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init"' diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index e6e5802b8c35..aeae44ef3f83 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -132,4 +132,10 @@ vars.Add( default=tuple(), ) +vars.Add( + "OPENOCD_OPTS", + help="Options to pass to OpenOCD", + default="", +) + Return("vars") diff --git a/site_scons/firmwareopts.scons b/site_scons/firmwareopts.scons index d0b0fb95c483..b77be9d85cad 100644 --- a/site_scons/firmwareopts.scons +++ b/site_scons/firmwareopts.scons @@ -36,7 +36,6 @@ else: ) ENV.Append( - OPENOCD_OPTS='-f interface/stlink.cfg -c "transport select hla_swd" -f debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init"', LINKFLAGS=[ "-Tfirmware/targets/f${TARGET_HW}/${LINKER_SCRIPT}.ld", ], From 8312b56051538ba921f1fef74212e0fab0895175 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 17 Jun 2022 14:45:17 +0400 Subject: [PATCH 143/184] Build: fixed fbt.md; added SVD file to options --- documentation/fbt.md | 2 +- fbt_options.py | 2 ++ site_scons/commandline.scons | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/documentation/fbt.md b/documentation/fbt.md index 1cc1f2c346e1..374d9e94910f 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -42,7 +42,7 @@ FBT keeps track of internal dependencies, so you only need to build the highest- - `--options optionfile.py` (default value `fbt_options.py`) - load file with multiple configuration values - `--with-updater` - enables updater-related targets and dependency tracking. Enabling this options introduces extra startup time costs, so use it when bundling update packages. Or if you have a fast computer and don't care about a few extra seconds of startup time -- `--extra-ext-apps=app1,app2,appn` - when building `firmware_extapps` +- `--extra-ext-apps=app1,app2,appn` - forces listed apps to be built as external with `firmware_extapps` target ## Configuration diff --git a/fbt_options.py b/fbt_options.py index ebd57461af15..b8a0d8d28395 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -42,3 +42,5 @@ FBT_TOOLCHAIN_VERSIONS = (" 10.3.",) OPENOCD_OPTS = '-f interface/stlink.cfg -c "transport select hla_swd" -f debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init"' + +SVD_FILE = "debug/STM32WB55_CM4.svd" diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index aeae44ef3f83..bdfa9064854d 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -124,6 +124,12 @@ vars.AddVariables( "ble_basic", ], ), + PathVariable( + "SVD_FILE", + help="Path to SVD file", + validator=PathVariable.PathIsFile, + default="", + ), ) vars.Add( From aea345b2e6422e795257f18772f140e743006d9e Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Fri, 17 Jun 2022 07:31:20 -0400 Subject: [PATCH 144/184] bye bye universal entrypoint.. --- .gitattributes | 2 +- fbt.bat | 4 ++++ fbt.sh | 14 ++++++++++++++ fbt.sh.bat | 23 ---------------------- scripts/toolchain/generate-fbt.sh | 32 ------------------------------- 5 files changed, 19 insertions(+), 56 deletions(-) create mode 100644 fbt.bat create mode 100755 fbt.sh delete mode 100755 fbt.sh.bat delete mode 100755 scripts/toolchain/generate-fbt.sh diff --git a/.gitattributes b/.gitattributes index 88971893a741..c821603a8af3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,3 @@ * text=auto eol=lf -*.sh.bat binary +*.bat eol=crlf *.ps1 eol=crlf diff --git a/fbt.bat b/fbt.bat new file mode 100644 index 000000000000..1d34b5daf732 --- /dev/null +++ b/fbt.bat @@ -0,0 +1,4 @@ +set "toolchainRoot=%~dp0toolchain" +set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" +if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) +cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/fbt.sh b/fbt.sh new file mode 100755 index 000000000000..1d5a54ae4749 --- /dev/null +++ b/fbt.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +# unofficial strict mode +set -eu; + +SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; +if [ ! -d "$SCRIPT_PATH/toolchain" ]; then + scripts/toolchain/unix-toolchain-download.sh || exit 1; +fi +PATH="$SCRIPT_PATH/toolchain/python/bin:$PATH"; +PATH="$SCRIPT_PATH/toolchain/bin:$PATH"; +PATH="$SCRIPT_PATH/toolchain/protobuf/bin:$PATH"; +python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS "$*" diff --git a/fbt.sh.bat b/fbt.sh.bat deleted file mode 100755 index 9ba63e7a7143..000000000000 --- a/fbt.sh.bat +++ /dev/null @@ -1,23 +0,0 @@ -echo >/dev/null # >nul & @echo off & GOTO WINDOWS & rem ^ -# *********************************************************** -# * NOTE: Generated by scripts/toolchain/generate-fbt.sh -# * If you modify this file, use script or remove carriage returns (\r)\n -# * from the Unix part and leave them in Windows part. In summary: -# * New lines in Unix: \n\n -# * New lines in Windows: \r\n -# *********************************************************** -SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; -if [ ! -d "$SCRIPT_PATH/toolchain" ]; then - scripts/toolchain/unix-toolchain-download.sh || exit 1; -fi -PATH="$SCRIPT_PATH/toolchain/python/bin:$PATH"; -PATH="$SCRIPT_PATH/toolchain/bin:$PATH"; -PATH="$SCRIPT_PATH/toolchain/protobuf/bin:$PATH"; -python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS "$@" -exit 0; -:WINDOWS -set "toolchainRoot=%~dp0toolchain" -set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" -if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) -cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/scripts/toolchain/generate-fbt.sh b/scripts/toolchain/generate-fbt.sh deleted file mode 100755 index eb30af7bfa9d..000000000000 --- a/scripts/toolchain/generate-fbt.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; -PROJECT_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; -OUT_FILE="$PROJECT_ROOT/fbt.sh.bat"; -UNIX_END="\n"; -WIN_END="\r\n"; - -printf "echo >/dev/null # >nul & @echo off & GOTO WINDOWS & rem ^$WIN_END" > "$OUT_FILE" -printf "# ***********************************************************$UNIX_END" >> "$OUT_FILE" -printf "# * NOTE: Generated by scripts/toolchain/generate-fbt.sh$UNIX_END" >> "$OUT_FILE" -printf "# * If you modify this file, use script or remove carriage returns (\\\r)\\\n$UNIX_END" >> "$OUT_FILE" -printf "# * from the Unix part and leave them in Windows part. In summary:$UNIX_END" >> "$OUT_FILE" -printf "# * New lines in Unix: \\\n\\\n$UNIX_END" >> "$OUT_FILE" -printf "# * New lines in Windows: \\\r\\\n$UNIX_END" >> "$OUT_FILE" -printf "# ***********************************************************$UNIX_END" >> "$OUT_FILE" -printf "SCRIPT_PATH=\"\$(dirname -- \"\$(readlink -f -- \"\$0\")\")\";$UNIX_END" >> "$OUT_FILE" -printf "SCONS_DEFAULT_FLAGS=\"-Q --warn=target-not-built\";$UNIX_END" >> "$OUT_FILE" -printf "if [ ! -d \"\$SCRIPT_PATH/toolchain\" ]; then$UNIX_END" >> "$OUT_FILE" -printf " scripts/toolchain/unix-toolchain-download.sh || exit 1;$UNIX_END" >> "$OUT_FILE" -printf "fi$UNIX_END" >> "$OUT_FILE" -printf "PATH=\"\$SCRIPT_PATH/toolchain/python/bin:\$PATH\";$UNIX_END" >> "$OUT_FILE" -printf "PATH=\"\$SCRIPT_PATH/toolchain/bin:\$PATH\";$UNIX_END" >> "$OUT_FILE" -printf "PATH=\"\$SCRIPT_PATH/toolchain/protobuf/bin:\$PATH\";$UNIX_END" >> "$OUT_FILE" -printf "python3 lib/scons/scripts/scons.py \$SCONS_DEFAULT_FLAGS \"\$@\"$UNIX_END" >> "$OUT_FILE" -printf "exit 0;$UNIX_END" >> "$OUT_FILE" -printf ":WINDOWS$WIN_END" >> "$OUT_FILE" -printf "set \"toolchainRoot=%%~dp0toolchain\"$WIN_END" >> "$OUT_FILE" -printf "set \"SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built\"$WIN_END" >> "$OUT_FILE" -printf "if not exist \"%%toolchainRoot%%\" (powershell -ExecutionPolicy Bypass -File %%~dp0scripts\\\toolchain\\\windows-toolchain-download.ps1)$WIN_END" >> "$OUT_FILE" -printf "cmd /V /C \"set \"PATH=%%toolchainRoot%%\\\python;%%toolchainRoot%%\\\bin;%%toolchainRoot%%\\\protoc\\\bin;%%PATH%%\" && python lib\\\scons\\\scripts\\\scons.py %%SCONS_DEFAULT_FLAGS%% %%*\"$WIN_END" >> "$OUT_FILE" - -chmod +x "$OUT_FILE" From 819c4b81e234dcf6ee11f60e31cb77b31d304fdf Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 17 Jun 2022 15:41:22 +0400 Subject: [PATCH 145/184] Build: removed quotes for passed arguments --- fbt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fbt.sh b/fbt.sh index 1d5a54ae4749..90c55f86b92d 100755 --- a/fbt.sh +++ b/fbt.sh @@ -11,4 +11,4 @@ fi PATH="$SCRIPT_PATH/toolchain/python/bin:$PATH"; PATH="$SCRIPT_PATH/toolchain/bin:$PATH"; PATH="$SCRIPT_PATH/toolchain/protobuf/bin:$PATH"; -python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS "$*" +python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS $* From 234a23091152e95a20acaccb2e1347277e59d72d Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 17 Jun 2022 20:51:51 +0400 Subject: [PATCH 146/184] Build: Fixed debugging information missing for libs; added toolchain dir to .gitignore; gdb-py WIP --- .gitignore | 3 +++ SConstruct | 17 ++++++++++++++++ firmware.scons | 2 +- site_scons/cc.scons | 1 + site_scons/commandline.scons | 6 ++++++ site_scons/environ.scons | 2 ++ site_scons/firmwareopts.scons | 3 --- site_scons/site_tools/crosscc.py | 5 ++++- site_scons/site_tools/gdb.py | 33 ++++++++++++++++++++++++++++++++ 9 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 site_scons/site_tools/gdb.py diff --git a/.gitignore b/.gitignore index 83b69c277c39..2d66413bbcf3 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,6 @@ dist .sconsign.dblite # SCons build dir build/ + +# Toolchain +toolchain*/ \ No newline at end of file diff --git a/SConstruct b/SConstruct index e3a57ec5fafb..08b5754e81cc 100644 --- a/SConstruct +++ b/SConstruct @@ -83,3 +83,20 @@ copro_dist = distenv.CoproBuilder( ) AlwaysBuild(copro_dist) Alias("copro_dist", copro_dist) + + +# Debugging firmware +debug = distenv.GDBPy( + "pseudo3", + # firmware_out["FW_ELF"], + firmware_out["FW_FLASH"], + GDBFLAGS="-ex 'target extended-remote | openocd.exe -c \"gdb_port pipe\" ${OPENOCD_OPTS}' " + '-ex "set confirm off" ' + '-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' + '-ex "source ${ROOT_DIR.abspath}/debug/PyCortexMDebug/PyCortexMDebug.py" ' + '-ex "svd_load ${SVD_FILE}" ' + '-ex "compare-sections"', +) +# distenv.Depends(debug, firmware_out["FW_FLASH"]) +# distenv.Pseudo("pseudo3") +Alias("debug", debug) diff --git a/firmware.scons b/firmware.scons index 06a4e2404584..ee0f851ad308 100644 --- a/firmware.scons +++ b/firmware.scons @@ -176,7 +176,7 @@ fwenv.AppendUnique( # Full firmware definition -fwelf = fwenv.Program( +fwelf = fwenv["FW_ELF"] = fwenv.Program( "${FIRMWARE_BUILD_CFG}", sources, LIBS=[ diff --git a/site_scons/cc.scons b/site_scons/cc.scons index f6e2f2ed9771..8103344196ae 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -28,6 +28,7 @@ ENV.AppendUnique( "-ffunction-sections", "-fno-math-errno", "-fstack-usage", + "-g", # "-Wno-stringop-overread", # "-Wno-stringop-overflow", ], diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index bdfa9064854d..f69b9f5826d1 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -95,6 +95,12 @@ vars.Add( default="", ) +vars.Add( + "COPRO_DISCLAIMER", + help="Value to pass to bundling script to confirm dangerous operations", + default="", +) + vars.AddVariables( PathVariable( "COPRO_OB_DATA", diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 581ad8d72a85..264e2fb092ac 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -51,6 +51,8 @@ if not coreenv["VERBOSE"]: APPSCOMSTR="\tAPPS\t${TARGET}", VERSIONCOMSTR="\tVERSION\t${TARGET}", STRIPCOMSTR="\tSTRIP\t${TARGET}", + GDBCOMSTR="\tGDB\t${TARGET}", + GDBPYCOMSTR="\tGDB-PY\t${TARGET}", ) # Default value for commandline options diff --git a/site_scons/firmwareopts.scons b/site_scons/firmwareopts.scons index b77be9d85cad..f04b55cdd205 100644 --- a/site_scons/firmwareopts.scons +++ b/site_scons/firmwareopts.scons @@ -9,7 +9,6 @@ if ENV["DEBUG"]: ], CCFLAGS=[ "-Og", - "-g", ], ) elif ENV["COMPACT"]: @@ -20,7 +19,6 @@ elif ENV["COMPACT"]: ], CCFLAGS=[ "-Os", - "-g", ], ) else: @@ -31,7 +29,6 @@ else: ], CCFLAGS=[ "-Og", - "-g", ], ) diff --git a/site_scons/site_tools/crosscc.py b/site_scons/site_tools/crosscc.py index 017b742e205b..7540e1482c02 100644 --- a/site_scons/site_tools/crosscc.py +++ b/site_scons/site_tools/crosscc.py @@ -4,6 +4,7 @@ from SCons.Tool import ar from SCons.Tool import gnulink import strip +import gdb from SCons.Action import _subproc import subprocess @@ -34,7 +35,7 @@ def _get_tool_version(env, tool): def generate(env, **kw): - for orig_tool in (asm, gcc, gxx, ar, gnulink, strip): + for orig_tool in (asm, gcc, gxx, ar, gnulink, strip, gdb): orig_tool.generate(env) env.SetDefault( TOOLCHAIN_PREFIX=kw.get("toolchain_prefix"), @@ -50,6 +51,8 @@ def generate(env, **kw): "OBJCOPY", "RANLIB", "STRIP", + "GDB", + "GDBPY", ], ) # Call CC to check version diff --git a/site_scons/site_tools/gdb.py b/site_scons/site_tools/gdb.py new file mode 100644 index 000000000000..fa92ca08ee8a --- /dev/null +++ b/site_scons/site_tools/gdb.py @@ -0,0 +1,33 @@ +from SCons.Builder import Builder +from SCons.Action import Action + + +def generate(env): + env.SetDefault( + GDB="gdb", + GDBPY="gdb-py", + GDBFLAGS=[], + GDBPYFLAGS=[], + GDBCOM="$GDB $GDBFLAGS $SOURCES $TARGET", + GDBPYCOM="$GDBPY $GDBFLAGS $GDBPYFLAGS $SOURCES", + ) + env.Append( + BUILDERS={ + "GDB": Builder( + action=Action( + "${GDBCOM}", + "${GDBCOMSTR}", + ), + ), + "GDBPy": Builder( + action=Action( + "${GDBPYCOM}", + "${GDBPYCOMSTR}", + ), + ), + } + ) + + +def exists(env): + return True From fc9591a9a52bfb1ccb2f4c290ef917f30f7d4a05 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 17 Jun 2022 21:34:11 +0400 Subject: [PATCH 147/184] Build: added debug_other target requiring OTHER_ELF=blabla.elf to debug external elfs; updated docs --- SConstruct | 45 ++++++++++++++++++++++++------------ documentation/fbt.md | 2 ++ fbt_options.py | 2 ++ site_scons/commandline.scons | 6 +++++ site_scons/site_tools/gdb.py | 8 +++---- 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/SConstruct b/SConstruct index 08b5754e81cc..da8b0b2dff86 100644 --- a/SConstruct +++ b/SConstruct @@ -29,7 +29,11 @@ SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) coreenv["ROOT_DIR"] = Dir(".") # Create a separate "dist" environment and add construction envs to it -distenv = coreenv.Clone(tools=["fbt_dist"]) +distenv = coreenv.Clone( + tools=["fbt_dist"], + GDBOPTS="-ex 'target extended-remote | openocd.exe -c \"gdb_port pipe\" ${OPENOCD_OPTS}' " + '-ex "set confirm off" ', +) firmware_out = distenv.AddFwProject( base_env=coreenv, @@ -49,7 +53,7 @@ if GetOption("fullenv"): # Target for self-update package selfupdate_dist = distenv.DistBuilder( - "pseudo", + "selfupdate.pseudo", (distenv["DIST_DEPENDS"], firmware_out["FW_RESOURCES"]), DIST_EXTRA=[ "-r", @@ -65,13 +69,13 @@ if GetOption("fullenv"): '"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"', ], ) - distenv.Pseudo("pseudo") + distenv.Pseudo("selfupdate.pseudo") AlwaysBuild(selfupdate_dist) Alias("updater_package", selfupdate_dist) # Target for copying & renaming binaries to dist folder -basic_dist = distenv.DistBuilder("pseudo2", distenv["DIST_DEPENDS"]) -distenv.Pseudo("pseudo2") +basic_dist = distenv.DistBuilder("dist.pseudo", distenv["DIST_DEPENDS"]) +distenv.Pseudo("dist.pseudo") AlwaysBuild(basic_dist) Alias("fw_dist", basic_dist) Default(basic_dist) @@ -86,17 +90,28 @@ Alias("copro_dist", copro_dist) # Debugging firmware -debug = distenv.GDBPy( - "pseudo3", - # firmware_out["FW_ELF"], - firmware_out["FW_FLASH"], - GDBFLAGS="-ex 'target extended-remote | openocd.exe -c \"gdb_port pipe\" ${OPENOCD_OPTS}' " - '-ex "set confirm off" ' - '-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' +debug_elf = distenv.GDBPy( + "debug.pseudo", + firmware_out["FW_ELF"], + GDBPYOPTS='-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' '-ex "source ${ROOT_DIR.abspath}/debug/PyCortexMDebug/PyCortexMDebug.py" ' '-ex "svd_load ${SVD_FILE}" ' '-ex "compare-sections"', ) -# distenv.Depends(debug, firmware_out["FW_FLASH"]) -# distenv.Pseudo("pseudo3") -Alias("debug", debug) +distenv.Depends(debug_elf, firmware_out["FW_FLASH"]) +distenv.Pseudo("debug.pseudo") +AlwaysBuild(debug_elf) +Alias("debug", debug_elf) + + +debug_other = distenv.GDBPy( + "debugother.pseudo", + distenv.subst("$OTHER_ELF"), + GDBPYOPTS= + # '-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' + '-ex "source ${ROOT_DIR.abspath}/debug/PyCortexMDebug/PyCortexMDebug.py" ' + '-ex "svd_load ${SVD_FILE}" ', +) +distenv.Pseudo("debugother.pseudo") +AlwaysBuild(debug_other) +Alias("debug_other", debug_other) diff --git a/documentation/fbt.md b/documentation/fbt.md index 374d9e94910f..4895a275dbe1 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -20,6 +20,8 @@ FBT keeps track of internal dependencies, so you only need to build the highest- - `fw_dist` - build & publish firmware to `dist` folder - `updater_package` - build self-update package. _Requires `--with-updater` option_ - `copro_dist` - bundle Core2 FUS+stack binaries for qFlipper +- `debug` - build and flash firmware, then attach with gdb with firmware's .elf loaded +- `debug_other` - attach gdb loading an externally-built .elf. Specify .elf to debug with `OTHER_ELF=path/to/other.elf` ### Firmware targets - `firmware_extapps` - build all plug-ins as separate .elf files diff --git a/fbt_options.py b/fbt_options.py index b8a0d8d28395..d065a9542bff 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -44,3 +44,5 @@ OPENOCD_OPTS = '-f interface/stlink.cfg -c "transport select hla_swd" -f debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init"' SVD_FILE = "debug/STM32WB55_CM4.svd" + +OTHER_ELF = "" diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index f69b9f5826d1..eaa16b05122e 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -136,6 +136,12 @@ vars.AddVariables( validator=PathVariable.PathIsFile, default="", ), + PathVariable( + "OTHER_ELF", + help="Path to prebuilt ELF file to debug", + validator=PathVariable.PathAccept, + default="", + ), ) vars.Add( diff --git a/site_scons/site_tools/gdb.py b/site_scons/site_tools/gdb.py index fa92ca08ee8a..e7b6bdd68758 100644 --- a/site_scons/site_tools/gdb.py +++ b/site_scons/site_tools/gdb.py @@ -6,10 +6,10 @@ def generate(env): env.SetDefault( GDB="gdb", GDBPY="gdb-py", - GDBFLAGS=[], - GDBPYFLAGS=[], - GDBCOM="$GDB $GDBFLAGS $SOURCES $TARGET", - GDBPYCOM="$GDBPY $GDBFLAGS $GDBPYFLAGS $SOURCES", + GDBOPTS="", + GDBPYOPTS="", + GDBCOM="$GDB $GDBOPTS $SOURCES", # no $TARGET + GDBPYCOM="$GDBPY $GDBOPTS $GDBPYOPTS $SOURCES", # no $TARGET ) env.Append( BUILDERS={ From 0105faef13d4ca89d584113358afa46534183c13 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 17 Jun 2022 21:38:33 +0400 Subject: [PATCH 148/184] Build: fixed debug target without external elf specified --- SConstruct | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/SConstruct b/SConstruct index da8b0b2dff86..7d944a6aafe3 100644 --- a/SConstruct +++ b/SConstruct @@ -104,14 +104,15 @@ AlwaysBuild(debug_elf) Alias("debug", debug_elf) -debug_other = distenv.GDBPy( - "debugother.pseudo", - distenv.subst("$OTHER_ELF"), - GDBPYOPTS= - # '-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' - '-ex "source ${ROOT_DIR.abspath}/debug/PyCortexMDebug/PyCortexMDebug.py" ' - '-ex "svd_load ${SVD_FILE}" ', -) -distenv.Pseudo("debugother.pseudo") -AlwaysBuild(debug_other) -Alias("debug_other", debug_other) +if other_elf_specified := distenv.subst("$OTHER_ELF"): + debug_other = distenv.GDBPy( + "debugother.pseudo", + other_elf_specified, + GDBPYOPTS= + # '-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' + '-ex "source ${ROOT_DIR.abspath}/debug/PyCortexMDebug/PyCortexMDebug.py" ' + '-ex "svd_load ${SVD_FILE}" ', + ) + distenv.Pseudo("debugother.pseudo") + AlwaysBuild(debug_other) + Alias("debug_other", debug_other) From 2dbd97ca5ae02707c284db9ce4f568b23c042a16 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 17 Jun 2022 21:43:40 +0400 Subject: [PATCH 149/184] Build: temporarily disabled COMSTR for gdb --- site_scons/environ.scons | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 264e2fb092ac..899b86ff1117 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -51,8 +51,8 @@ if not coreenv["VERBOSE"]: APPSCOMSTR="\tAPPS\t${TARGET}", VERSIONCOMSTR="\tVERSION\t${TARGET}", STRIPCOMSTR="\tSTRIP\t${TARGET}", - GDBCOMSTR="\tGDB\t${TARGET}", - GDBPYCOMSTR="\tGDB-PY\t${TARGET}", + # GDBCOMSTR="\tGDB\t${SOURCE}", + # GDBPYCOMSTR="\tGDB-PY\t${SOURCE}", ) # Default value for commandline options From e8c92a7ad0b713d2a08743fdff2d6ee32e193576 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 17 Jun 2022 23:18:51 +0400 Subject: [PATCH 150/184] Build: added openocd target --- SConstruct | 16 ++++++++++++---- documentation/fbt.md | 1 + fbt.bat | 1 + firmware.scons | 7 +++++-- site_scons/site_tools/openocd.py | 19 ++++++++++++++----- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/SConstruct b/SConstruct index 7d944a6aafe3..64f8f481552f 100644 --- a/SConstruct +++ b/SConstruct @@ -30,7 +30,7 @@ coreenv["ROOT_DIR"] = Dir(".") # Create a separate "dist" environment and add construction envs to it distenv = coreenv.Clone( - tools=["fbt_dist"], + tools=["fbt_dist", "openocd"], GDBOPTS="-ex 'target extended-remote | openocd.exe -c \"gdb_port pipe\" ${OPENOCD_OPTS}' " '-ex "set confirm off" ', ) @@ -93,8 +93,8 @@ Alias("copro_dist", copro_dist) debug_elf = distenv.GDBPy( "debug.pseudo", firmware_out["FW_ELF"], - GDBPYOPTS='-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' - '-ex "source ${ROOT_DIR.abspath}/debug/PyCortexMDebug/PyCortexMDebug.py" ' + GDBPYOPTS='-ex "source debug/FreeRTOS/FreeRTOS.py" ' + '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ' '-ex "svd_load ${SVD_FILE}" ' '-ex "compare-sections"', ) @@ -104,15 +104,23 @@ AlwaysBuild(debug_elf) Alias("debug", debug_elf) +# Debug alien elf if other_elf_specified := distenv.subst("$OTHER_ELF"): debug_other = distenv.GDBPy( "debugother.pseudo", other_elf_specified, GDBPYOPTS= # '-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' - '-ex "source ${ROOT_DIR.abspath}/debug/PyCortexMDebug/PyCortexMDebug.py" ' + '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ' '-ex "svd_load ${SVD_FILE}" ', ) distenv.Pseudo("debugother.pseudo") AlwaysBuild(debug_other) Alias("debug_other", debug_other) + + +# Just start OpenOCD +openocd = distenv.OOCDCommand("openocd.pseudo", []) +distenv.Pseudo("openocd.pseudo") +AlwaysBuild(openocd) +Alias("openocd", openocd) diff --git a/documentation/fbt.md b/documentation/fbt.md index 4895a275dbe1..6205bd9b8a41 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -22,6 +22,7 @@ FBT keeps track of internal dependencies, so you only need to build the highest- - `copro_dist` - bundle Core2 FUS+stack binaries for qFlipper - `debug` - build and flash firmware, then attach with gdb with firmware's .elf loaded - `debug_other` - attach gdb loading an externally-built .elf. Specify .elf to debug with `OTHER_ELF=path/to/other.elf` +- `openocd` - just start OpenOCD ### Firmware targets - `firmware_extapps` - build all plug-ins as separate .elf files diff --git a/fbt.bat b/fbt.bat index 1d34b5daf732..81ebcd3ff5a2 100644 --- a/fbt.bat +++ b/fbt.bat @@ -1,3 +1,4 @@ +@echo off set "toolchainRoot=%~dp0toolchain" set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) diff --git a/firmware.scons b/firmware.scons index ee0f851ad308..462c87036797 100644 --- a/firmware.scons +++ b/firmware.scons @@ -59,7 +59,7 @@ if not env["VERBOSE"]: HEXCOMSTR="\tHEX\t${TARGET}", BINCOMSTR="\tBIN\t${TARGET}", DFUCOMSTR="\tDFU\t${TARGET}", - FLASHCOMSTR="\tFLASH\t${SOURCE}", + OOCDCOMSTR="\tFLASH\t${SOURCE}", ) @@ -216,7 +216,10 @@ Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu) # Additional FW-related pseudotargets if fwenv["IS_BASE_FIRMWARE"]: - flash = fwenv["FW_FLASH"] = fwenv.OOCDFlash("${FIRMWARE_BUILD_CFG}") + flash = fwenv["FW_FLASH"] = fwenv.OOCDFlashCommand( + "${FIRMWARE_BUILD_CFG}", + OPENOCD_COMMAND='-c "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}"', + ) if fwenv["FORCE"]: AlwaysBuild(flash) Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) diff --git a/site_scons/site_tools/openocd.py b/site_scons/site_tools/openocd.py index 598bb90c6f76..135e1100a9ee 100644 --- a/site_scons/site_tools/openocd.py +++ b/site_scons/site_tools/openocd.py @@ -5,24 +5,33 @@ __OPENOCD_BIN = "openocd" +_oocd_action = Action( + "${OPENOCD} ${OPENOCD_OPTS} ${OPENOCD_COMMAND}", + "${OOCDCOMSTR}", +) + def generate(env): env.SetDefault( OPENOCD=__OPENOCD_BIN, + OPENOCD_OPTS="", + OPENOCD_COMMAND="", + OOCDCOMSTR="", ) + env.Append( BUILDERS={ - "OOCDFlash": Builder( + "OOCDFlashCommand": Builder( action=[ - Action( - '${OPENOCD} ${OPENOCD_OPTS} -c "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}"', - "${FLASHCOMSTR}", - ), + _oocd_action, Touch("${TARGET}"), ], suffix=".flash", src_suffix=".bin", ), + "OOCDCommand": Builder( + action=_oocd_action, + ), } ) From 45d51154f39d4c81ab8c5aa3f0bcb23a2f150a87 Mon Sep 17 00:00:00 2001 From: hedger Date: Sat, 18 Jun 2022 06:48:02 +0400 Subject: [PATCH 151/184] Revert "Merge remote-tracking branch 'remotes/origin/hedger/sconsbuild' into drunkbatya/python3-wrapper" This reverts commit ba2af4137b220a24e45da36444413a84d8d05de2, reversing changes made to 8312b56051538ba921f1fef74212e0fab0895175. # Conflicts: # fbt.bat # fbt.sh --- .gitattributes | 2 - Makefile | 3 +- assets/Makefile | 1 - fbt | 6 + fbt.bat | 5 - fbt.cmd | 3 + fbt.sh | 14 --- make/python.mk | 17 --- scripts/toolchain/unix-toolchain-download.sh | 118 ------------------ .../toolchain/windows-toolchain-download.ps1 | 25 ---- 10 files changed, 10 insertions(+), 184 deletions(-) create mode 100755 fbt delete mode 100644 fbt.bat create mode 100644 fbt.cmd delete mode 100755 fbt.sh delete mode 100644 make/python.mk delete mode 100755 scripts/toolchain/unix-toolchain-download.sh delete mode 100644 scripts/toolchain/windows-toolchain-download.ps1 diff --git a/.gitattributes b/.gitattributes index c821603a8af3..6313b56c5784 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1 @@ * text=auto eol=lf -*.bat eol=crlf -*.ps1 eol=crlf diff --git a/Makefile b/Makefile index 2b7a75872ff0..8834cba6cebf 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,6 @@ NPROCS := $(shell sysctl -n hw.ncpu) endif include $(PROJECT_ROOT)/make/defaults.mk -include $(PROJECT_ROOT)/make/python.mk .PHONY: all all: firmware_all @@ -153,4 +152,4 @@ guruguru: .PHONY: generate_compile_db generate_compile_db: - @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) generate_compile_db + @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) generate_compile_db \ No newline at end of file diff --git a/assets/Makefile b/assets/Makefile index 8c77d8769a8f..2c743601cf09 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -2,7 +2,6 @@ PROJECT_ROOT = $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..) include $(PROJECT_ROOT)/assets/assets.mk include $(PROJECT_ROOT)/assets/copro.mk -include $(PROJECT_ROOT)/make/python.mk .PHONY: all all: icons protobuf dolphin manifest diff --git a/fbt b/fbt new file mode 100755 index 000000000000..9ab37fe61aff --- /dev/null +++ b/fbt @@ -0,0 +1,6 @@ +#!/bin/bash + +set +x + +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" +/usr/bin/env python3 lib/scons/scripts/scons.py ${SCONS_DEFAULT_FLAGS} "$@" diff --git a/fbt.bat b/fbt.bat deleted file mode 100644 index 81ebcd3ff5a2..000000000000 --- a/fbt.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -set "toolchainRoot=%~dp0toolchain" -set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" -if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) -cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/fbt.cmd b/fbt.cmd new file mode 100644 index 000000000000..95e72a8a5dc8 --- /dev/null +++ b/fbt.cmd @@ -0,0 +1,3 @@ +@echo off +set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" +python lib/scons/scripts/scons.py %SCONS_DEFAULT_FLAGS% %* diff --git a/fbt.sh b/fbt.sh deleted file mode 100755 index 90c55f86b92d..000000000000 --- a/fbt.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -# unofficial strict mode -set -eu; - -SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; -if [ ! -d "$SCRIPT_PATH/toolchain" ]; then - scripts/toolchain/unix-toolchain-download.sh || exit 1; -fi -PATH="$SCRIPT_PATH/toolchain/python/bin:$PATH"; -PATH="$SCRIPT_PATH/toolchain/bin:$PATH"; -PATH="$SCRIPT_PATH/toolchain/protobuf/bin:$PATH"; -python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS $* diff --git a/make/python.mk b/make/python.mk deleted file mode 100644 index bc4bc9b5e1c4..000000000000 --- a/make/python.mk +++ /dev/null @@ -1,17 +0,0 @@ -TOOLCHAIN_GDB_SYM := $(shell which arm-none-eabi-gdb) -ifneq ($(TOOLCHAIN_GDB_SYM),) - TOOLCHAIN_GDB := $(shell readlink -f -- $(TOOLCHAIN_GDB_SYM)) - TOOLCHAIN_DIR := $(shell dirname -- $(TOOLCHAIN_GDB)) - FLIPPER_PY_REL_DIR := $(TOOLCHAIN_DIR)/../python/bin - FLIPPER_PY_DIR := $(shell test -d $(FLIPPER_PY_REL_DIR) && cd $(FLIPPER_PY_REL_DIR) && pwd) - FLIPPER_PROTO_REL_DIR := $(TOOLCHAIN_DIR)/../protobuf/bin - FLIPPER_PROTO_DIR := $(shell test -d $(FLIPPER_PROTO_REL_DIR) && cd $(FLIPPER_PROTO_REL_DIR) && pwd) -endif -ifneq ($(FLIPPER_PY_DIR),) - PATH := $(FLIPPER_PY_DIR):$(PATH) - export PATH -endif -ifneq ($(FLIPPER_PROTO_DIR),) - PATH := $(FLIPPER_PROTO_DIR):$(PATH) - export PATH -endif diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh deleted file mode 100755 index 055fadc4b6dd..000000000000 --- a/scripts/toolchain/unix-toolchain-download.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/sh - -# unofficial strict mode -set -eu; - -check_system() -{ - printf "Checking kernel type.."; - SYS_TYPE="$(uname -s)" - if [ "$SYS_TYPE" = "Darwin" ]; then - echo "darwin"; - TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz" - elif [ "$SYS_TYPE" = "Linux" ]; then - echo "linux"; - TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz" - else - echo "unsupported."; - echo "Your system is unsupported.. sorry.."; - exit 1; - fi -} - -check_tar() -{ - printf "Checking tar.."; - if ! tar --version > /dev/null 2>&1; then - echo "no"; - exit 1; - fi - echo "yes"; -} - - -curl_wget_check() -{ - printf "Checking curl.."; - if ! curl --version > /dev/null 2>&1; then - echo "no"; - printf "Checking wget.."; - if ! wget --version > /dev/null 2>&1; then - echo "no"; - echo "No curl or wget found in your PATH."; - echo "Please provide it or download this file:"; - echo; - echo "$TOOLCHAIN_URL"; - echo; - echo "And place in repo root dir mannualy."; - exit 1; - fi - echo "yes" - DOWNLOADER="wget"; - DOWNLOADER_ARGS="-qO"; - return; - fi - echo "yes" - DOWNLOADER="curl"; - DOWNLOADER_ARGS="-sSLo"; -} - -check_downloaded_toolchain() -{ - printf "Checking downloaded toolchain tgz.."; - if [ -f "$REPO_ROOT/$TOOLCHAIN_TAR" ]; then - echo "yes"; - return 0; - fi - echo "no"; - return 1; -} - -download_toolchain() -{ - printf "Checkin..oops Downloading toolchain.."; - "$DOWNLOADER" "$DOWNLOADER_ARGS" "$REPO_ROOT/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL"; - echo "done"; -} - -remove_old_tooclhain() -{ - printf "Removing old toolchain (if exist).."; - rm -rf "$REPO_ROOT/toolchain"; - echo "done"; -} - -unpack_toolchain() -{ - printf "Unpacking toolchain.."; - TOOLCHAIN_DIR="$(dirname -- "$(tar -tf "$REPO_ROOT/$TOOLCHAIN_TAR" | head -n 1)")"; - tar -xf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/"; - mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/toolchain"; - echo "done"; -} - -clearing() -{ - printf "Clearing.."; - rm -rf "$REPO_ROOT/$TOOLCHAIN_TAR"; - echo "done"; -} - -main() -{ - SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; - REPO_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; - check_system; # defines $TOOLCHAIN_URL - check_tar; - TOOLCHAIN_TAR="$(basename "$TOOLCHAIN_URL")"; - if ! check_downloaded_toolchain; then - curl_wget_check; - download_toolchain; - fi - remove_old_tooclhain; - unpack_toolchain; -} - -trap clearing EXIT; -trap clearing 2; # SIGINT not coverable by EXIT -main; diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 deleted file mode 100644 index 5b3a2491dab7..000000000000 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ /dev/null @@ -1,25 +0,0 @@ -Set-StrictMode -Version 2.0 -$ErrorActionPreference = "Stop" -[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" -$repo_root = (Get-Item "$PSScriptRoot\..\..").FullName -$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" -$toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" - -if (Test-Path -LiteralPath "$repo_root\toolchain") { - Write-Host -NoNewline "Removing old Windows toolchain.." - Remove-Item -LiteralPath "$repo_root\toolchain" -Force -Recurse - Write-Host "done!" -} - -Write-Host -NoNewline "Downloading Windows toolchain.." -Invoke-WebRequest -Uri "$toolchain_url" -OutFile "$repo_root\$toolchain_zip" -Write-Host "done!" - -Write-Host -NoNewline "Unziping Windows toolchain.." -Expand-Archive -LiteralPath "$toolchain_zip" -DestinationPath "$repo_root\" -Force -Rename-Item "$repo_root\gcc-arm-none-eabi-10.3-2022.06" "$repo_root\toolchain" -Write-Host "done!" - -Write-Host -NoNewline "Clearing temporary files.." -Remove-Item -LiteralPath "$repo_root\$toolchain_zip" -Force -Write-Host "done!" From 9c88b07b590a97b40ff826ea214d9162647c7f60 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 20 Jun 2022 15:06:32 +0400 Subject: [PATCH 152/184] Build: added updater debug handling --- SConstruct | 20 ++++++++------------ documentation/fbt.md | 1 + fbt | 3 ++- site_scons/site_tools/fbt_dist.py | 18 ++++++++++++++++++ 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/SConstruct b/SConstruct index 64f8f481552f..d225a7e8068a 100644 --- a/SConstruct +++ b/SConstruct @@ -73,6 +73,11 @@ if GetOption("fullenv"): AlwaysBuild(selfupdate_dist) Alias("updater_package", selfupdate_dist) + # Updater debug + debug_updater_elf = distenv.AddDebugTarget(updater_out, False) + Alias("updater_debug", debug_updater_elf) + + # Target for copying & renaming binaries to dist folder basic_dist = distenv.DistBuilder("dist.pseudo", distenv["DIST_DEPENDS"]) distenv.Pseudo("dist.pseudo") @@ -90,18 +95,9 @@ Alias("copro_dist", copro_dist) # Debugging firmware -debug_elf = distenv.GDBPy( - "debug.pseudo", - firmware_out["FW_ELF"], - GDBPYOPTS='-ex "source debug/FreeRTOS/FreeRTOS.py" ' - '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ' - '-ex "svd_load ${SVD_FILE}" ' - '-ex "compare-sections"', -) -distenv.Depends(debug_elf, firmware_out["FW_FLASH"]) -distenv.Pseudo("debug.pseudo") -AlwaysBuild(debug_elf) -Alias("debug", debug_elf) + +debug_fw_elf = distenv.AddDebugTarget(firmware_out) +Alias("debug", debug_fw_elf) # Debug alien elf diff --git a/documentation/fbt.md b/documentation/fbt.md index 6205bd9b8a41..3b7ded0828e6 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -21,6 +21,7 @@ FBT keeps track of internal dependencies, so you only need to build the highest- - `updater_package` - build self-update package. _Requires `--with-updater` option_ - `copro_dist` - bundle Core2 FUS+stack binaries for qFlipper - `debug` - build and flash firmware, then attach with gdb with firmware's .elf loaded +- `debug_updater` - attach gdb with updater's .elf loaded. _Requires `--with-updater` option_ - `debug_other` - attach gdb loading an externally-built .elf. Specify .elf to debug with `OTHER_ELF=path/to/other.elf` - `openocd` - just start OpenOCD diff --git a/fbt b/fbt index 9ab37fe61aff..d6c09ff8bccc 100755 --- a/fbt +++ b/fbt @@ -2,5 +2,6 @@ set +x +SCRIPTDIR="$( dirname -- "$0"; )"; SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" -/usr/bin/env python3 lib/scons/scripts/scons.py ${SCONS_DEFAULT_FLAGS} "$@" +/usr/bin/env python3 ${SCRIPTDIR}/lib/scons/scripts/scons.py ${SCONS_DEFAULT_FLAGS} "$@" diff --git a/site_scons/site_tools/fbt_dist.py b/site_scons/site_tools/fbt_dist.py index c1db6eb3b7d3..c39f724259f7 100644 --- a/site_scons/site_tools/fbt_dist.py +++ b/site_scons/site_tools/fbt_dist.py @@ -50,8 +50,26 @@ def AddFwProject(env, base_env, fw_type, fw_env_key): return project_env +def AddDebugTarget(env, targetenv, force_flash=True): + pseudo_name = f"debug.{targetenv.subst('$FIRMWARE_BUILD_CFG')}.pseudo" + debug_target = env.GDBPy( + pseudo_name, + targetenv["FW_ELF"], + GDBPYOPTS='-ex "source debug/FreeRTOS/FreeRTOS.py" ' + '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ' + '-ex "svd_load ${SVD_FILE}" ' + '-ex "compare-sections"', + ) + if force_flash: + env.Depends(debug_target, targetenv["FW_FLASH"]) + env.Pseudo(pseudo_name) + env.AlwaysBuild(debug_target) + return debug_target + + def generate(env): env.AddMethod(AddFwProject) + env.AddMethod(AddDebugTarget) env.SetDefault( COPRO_MCU_FAMILY="STM32WB5x", ) From 2e425c907f448a8a4593ce2c20e255c438388289 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Mon, 20 Jun 2022 12:40:07 -0400 Subject: [PATCH 153/184] Make possible to have multiply toolchains --- fbt.bat | 2 +- fbt.sh | 32 +++++++++++++++---- scripts/toolchain/unix-toolchain-download.sh | 12 ++++--- .../toolchain/windows-toolchain-download.ps1 | 6 ++-- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/fbt.bat b/fbt.bat index 1d34b5daf732..0189dc2d3834 100644 --- a/fbt.bat +++ b/fbt.bat @@ -1,4 +1,4 @@ -set "toolchainRoot=%~dp0toolchain" +set "toolchainRoot=%~dp0toolchain\win32" set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/fbt.sh b/fbt.sh index 90c55f86b92d..663e662dcc55 100755 --- a/fbt.sh +++ b/fbt.sh @@ -3,12 +3,32 @@ # unofficial strict mode set -eu; +get_kernel_type() +{ + SYS_TYPE="$(uname -s)" + if [ "$SYS_TYPE" = "Darwin" ]; then + TOOLCHAIN_PATH="toolchain/darwin"; + elif [ "$SYS_TYPE" = "Linux" ]; then + TOOLCHAIN_PATH="toolchain/linux"; + else + echo "Your system is unsupported.. sorry.."; + exit 1; + fi +} + +download_toolchain() +{ + if [ ! -d "$SCRIPT_PATH/$TOOLCHAIN_PATH" ]; then + scripts/toolchain/unix-toolchain-download.sh || exit 1; + fi +} + SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; -if [ ! -d "$SCRIPT_PATH/toolchain" ]; then - scripts/toolchain/unix-toolchain-download.sh || exit 1; -fi -PATH="$SCRIPT_PATH/toolchain/python/bin:$PATH"; -PATH="$SCRIPT_PATH/toolchain/bin:$PATH"; -PATH="$SCRIPT_PATH/toolchain/protobuf/bin:$PATH"; +get_kernel_type; +download_toolchain; +PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin:$PATH"; +PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH"; +PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; + python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS $* diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 055fadc4b6dd..3cbda133fb6b 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -9,10 +9,12 @@ check_system() SYS_TYPE="$(uname -s)" if [ "$SYS_TYPE" = "Darwin" ]; then echo "darwin"; - TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz" + TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz"; + TOOLCHAIN_PATH="toolchain/darwin"; elif [ "$SYS_TYPE" = "Linux" ]; then echo "linux"; - TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz" + TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz"; + TOOLCHAIN_PATH="toolchain/linux"; else echo "unsupported."; echo "Your system is unsupported.. sorry.."; @@ -78,7 +80,7 @@ download_toolchain() remove_old_tooclhain() { printf "Removing old toolchain (if exist).."; - rm -rf "$REPO_ROOT/toolchain"; + rm -rf "$REPO_ROOT/$TOOLCHAIN_PATH"; echo "done"; } @@ -87,7 +89,7 @@ unpack_toolchain() printf "Unpacking toolchain.."; TOOLCHAIN_DIR="$(dirname -- "$(tar -tf "$REPO_ROOT/$TOOLCHAIN_TAR" | head -n 1)")"; tar -xf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/"; - mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/toolchain"; + mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/$TOOLCHAIN_PATH/"; echo "done"; } @@ -102,7 +104,7 @@ main() { SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; REPO_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; - check_system; # defines $TOOLCHAIN_URL + check_system; # defines $TOOLCHAIN_URl and $TOOLCHAIN_PATH check_tar; TOOLCHAIN_TAR="$(basename "$TOOLCHAIN_URL")"; if ! check_downloaded_toolchain; then diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index 5b3a2491dab7..d469ceb10484 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -5,9 +5,9 @@ $repo_root = (Get-Item "$PSScriptRoot\..\..").FullName $toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" $toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" -if (Test-Path -LiteralPath "$repo_root\toolchain") { +if (Test-Path -LiteralPath "$repo_root\toolchain\win32") { Write-Host -NoNewline "Removing old Windows toolchain.." - Remove-Item -LiteralPath "$repo_root\toolchain" -Force -Recurse + Remove-Item -LiteralPath "$repo_root\toolchain\win32" -Force -Recurse Write-Host "done!" } @@ -17,7 +17,7 @@ Write-Host "done!" Write-Host -NoNewline "Unziping Windows toolchain.." Expand-Archive -LiteralPath "$toolchain_zip" -DestinationPath "$repo_root\" -Force -Rename-Item "$repo_root\gcc-arm-none-eabi-10.3-2022.06" "$repo_root\toolchain" +Rename-Item "$repo_root\gcc-arm-none-eabi-10.3-2022.06" "$repo_root\toolchain\win32" Write-Host "done!" Write-Host -NoNewline "Clearing temporary files.." From 43aee63e230420d79b9f1df987cab15e199493e2 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Tue, 21 Jun 2022 03:25:20 -0400 Subject: [PATCH 154/184] Make possible to have multiply toolchains fix --- fbt.bat | 2 +- fbt.sh | 4 ++-- scripts/toolchain/unix-toolchain-download.sh | 5 +++-- scripts/toolchain/windows-toolchain-download.ps1 | 10 +++++++--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/fbt.bat b/fbt.bat index 0189dc2d3834..592d17e6acbe 100644 --- a/fbt.bat +++ b/fbt.bat @@ -1,4 +1,4 @@ -set "toolchainRoot=%~dp0toolchain\win32" +set "toolchainRoot=%~dp0toolchain\i686-windows" set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/fbt.sh b/fbt.sh index 663e662dcc55..1bfab2b73388 100755 --- a/fbt.sh +++ b/fbt.sh @@ -7,9 +7,9 @@ get_kernel_type() { SYS_TYPE="$(uname -s)" if [ "$SYS_TYPE" = "Darwin" ]; then - TOOLCHAIN_PATH="toolchain/darwin"; + TOOLCHAIN_PATH="toolchain/x86_64-darwin"; elif [ "$SYS_TYPE" = "Linux" ]; then - TOOLCHAIN_PATH="toolchain/linux"; + TOOLCHAIN_PATH="toolchain/x86_64-linux"; else echo "Your system is unsupported.. sorry.."; exit 1; diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 3cbda133fb6b..4704127358dd 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -10,11 +10,11 @@ check_system() if [ "$SYS_TYPE" = "Darwin" ]; then echo "darwin"; TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz"; - TOOLCHAIN_PATH="toolchain/darwin"; + TOOLCHAIN_PATH="toolchain/x86_64-darwin"; elif [ "$SYS_TYPE" = "Linux" ]; then echo "linux"; TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz"; - TOOLCHAIN_PATH="toolchain/linux"; + TOOLCHAIN_PATH="toolchain/x86_64-linux"; else echo "unsupported."; echo "Your system is unsupported.. sorry.."; @@ -89,6 +89,7 @@ unpack_toolchain() printf "Unpacking toolchain.."; TOOLCHAIN_DIR="$(dirname -- "$(tar -tf "$REPO_ROOT/$TOOLCHAIN_TAR" | head -n 1)")"; tar -xf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/"; + mkdir -p "$REPO_ROOT/toolchain"; mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/$TOOLCHAIN_PATH/"; echo "done"; } diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index d469ceb10484..d14a9dd8a6a8 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -5,9 +5,9 @@ $repo_root = (Get-Item "$PSScriptRoot\..\..").FullName $toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" $toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" -if (Test-Path -LiteralPath "$repo_root\toolchain\win32") { +if (Test-Path -LiteralPath "$repo_root\toolchain\i686-windows") { Write-Host -NoNewline "Removing old Windows toolchain.." - Remove-Item -LiteralPath "$repo_root\toolchain\win32" -Force -Recurse + Remove-Item -LiteralPath "$repo_root\toolchain\i686-windows" -Force -Recurse Write-Host "done!" } @@ -15,9 +15,13 @@ Write-Host -NoNewline "Downloading Windows toolchain.." Invoke-WebRequest -Uri "$toolchain_url" -OutFile "$repo_root\$toolchain_zip" Write-Host "done!" +if (!(Test-Path -LiteralPath "$repo_root\toolchain")) { + New-Item "$repo_root\toolchain" -ItemType Directory +} + Write-Host -NoNewline "Unziping Windows toolchain.." Expand-Archive -LiteralPath "$toolchain_zip" -DestinationPath "$repo_root\" -Force -Rename-Item "$repo_root\gcc-arm-none-eabi-10.3-2022.06" "$repo_root\toolchain\win32" +Rename-Item "$repo_root\gcc-arm-none-eabi-10.3-2022.06" "$repo_root\toolchain\i686-windows" Write-Host "done!" Write-Host -NoNewline "Clearing temporary files.." From 2d45231acb644f8bd5dc320b985095bad3228aa4 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Tue, 21 Jun 2022 06:17:23 -0400 Subject: [PATCH 155/184] new toolchain achive naming --- scripts/toolchain/windows-toolchain-download.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index d14a9dd8a6a8..64a9c94db0cc 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -2,8 +2,8 @@ Set-StrictMode -Version 2.0 $ErrorActionPreference = "Stop" [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" $repo_root = (Get-Item "$PSScriptRoot\..\..").FullName -$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" -$toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-win32-flipper.zip" +$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-i686-windows-flipper.zip" +$toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-i686-windows-flipper.zip" if (Test-Path -LiteralPath "$repo_root\toolchain\i686-windows") { Write-Host -NoNewline "Removing old Windows toolchain.." From efd6fa4b32b5ca1307cb6db7d1980ca683765c6e Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Tue, 21 Jun 2022 07:01:27 -0400 Subject: [PATCH 156/184] win toolchain fix --- fbt.bat | 1 + scripts/toolchain/windows-toolchain-download.ps1 | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/fbt.bat b/fbt.bat index 592d17e6acbe..38b9f75c9f54 100644 --- a/fbt.bat +++ b/fbt.bat @@ -1,3 +1,4 @@ +@echo off set "toolchainRoot=%~dp0toolchain\i686-windows" set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index 64a9c94db0cc..c2f4b0555d2a 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -10,10 +10,11 @@ if (Test-Path -LiteralPath "$repo_root\toolchain\i686-windows") { Remove-Item -LiteralPath "$repo_root\toolchain\i686-windows" -Force -Recurse Write-Host "done!" } - -Write-Host -NoNewline "Downloading Windows toolchain.." -Invoke-WebRequest -Uri "$toolchain_url" -OutFile "$repo_root\$toolchain_zip" -Write-Host "done!" +if (!(Test-Path -Path "$repo_root\$toolchain_zip" -PathType Leaf)) { + Write-Host -NoNewline "Downloading Windows toolchain.." + Invoke-WebRequest -Uri "$toolchain_url" -OutFile "$repo_root\$toolchain_zip" + Write-Host "done!" +} if (!(Test-Path -LiteralPath "$repo_root\toolchain")) { New-Item "$repo_root\toolchain" -ItemType Directory @@ -21,7 +22,7 @@ if (!(Test-Path -LiteralPath "$repo_root\toolchain")) { Write-Host -NoNewline "Unziping Windows toolchain.." Expand-Archive -LiteralPath "$toolchain_zip" -DestinationPath "$repo_root\" -Force -Rename-Item "$repo_root\gcc-arm-none-eabi-10.3-2022.06" "$repo_root\toolchain\i686-windows" +Move-Item -Path "$repo_root\gcc-arm-none-eabi-10.3-2022.06" -Destination "$repo_root\toolchain\i686-windows" Write-Host "done!" Write-Host -NoNewline "Clearing temporary files.." From 76075bc669afd33f127e72e4d45dd25bce108f4c Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Tue, 21 Jun 2022 21:10:28 +0900 Subject: [PATCH 157/184] Build: check git submodules in fbt --- fbt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fbt b/fbt index d6c09ff8bccc..0c55f877059a 100755 --- a/fbt +++ b/fbt @@ -2,6 +2,11 @@ set +x +if [[ -d .git ]]; then + git submodule init + git submodule update +fi + SCRIPTDIR="$( dirname -- "$0"; )"; SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" /usr/bin/env python3 ${SCRIPTDIR}/lib/scons/scripts/scons.py ${SCONS_DEFAULT_FLAGS} "$@" From c7e4512e72508acb21715b53d51b7ed700f73990 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 21 Jun 2022 15:45:50 +0300 Subject: [PATCH 158/184] [FL-2568] Infrared C port (#1326) * Add skeleton for infrared C port, rename old app * Add scene stubs * Add more views * Misc changes * Add remote and signal class stubs * Complete infrared signal class * Add remote button class stub * Check if button contains a signal during destruction * Complete infrared signal class more * Implement remote storing * Implement remote loading * Fix error handling * Implement remote transmitting * Rename scene * Canonise event consumption * Implement remote learning (stub) * Implement learn success screen (stub) * Implement AskBack scene * Improve remote saving&loading * Fix remote file name * Add LearnDone scene * Switch from Remote scene correctly * Add SceneButtonSelect * Remove unneeded assert * Add new SceneManager method * Use new SceneManager method in Infrared * Implement renaming of buttons and remotes * Implement deleting of buttons and remotes * Add universal remotes list * Add brute force code * Brute force code improvements * Partially implement Universal Remote GUI * Fix wrong singnal handling * Fully implement Universal Remote * Use standard custom events everywhere * Return infrared CLI * Remove old Infrared app * Change container name * Fix scene order * Put ButtonPanel into stack only when needed * Show loading animation during slow operations * Do not hardcode Loading widget coordinates * Switch Loading widget orientation as needed * Save Start scene state * Save Remote scene state * Save Edit scene state * Save EditButtonSelect scene state * Do not use scene state * Use string_t instead of const char* for brevity * Fix memory leak * Fix saving raw remotes * Add Infrared debug menu * Add debug view * Move Infrared monitor into Infrared application * Remove old Infrared monitor app * Use common signal received callback everywhere --- applications/applications.c | 9 - applications/applications.mk | 9 - applications/gui/modules/loading.c | 4 +- applications/gui/scene_manager.c | 19 + applications/gui/scene_manager.h | 14 + .../infrared/helpers/infrared_parser.cpp | 157 ------- .../infrared/helpers/infrared_parser.h | 48 --- applications/infrared/infrared.c | 397 ++++++++++++++++++ applications/infrared/infrared.h | 3 + applications/infrared/infrared_app.cpp | 250 ----------- applications/infrared/infrared_app.h | 326 -------------- .../infrared/infrared_app_brute_force.cpp | 93 ---- .../infrared/infrared_app_brute_force.h | 67 --- applications/infrared/infrared_app_event.h | 48 --- .../infrared/infrared_app_remote_manager.cpp | 266 ------------ .../infrared/infrared_app_remote_manager.h | 189 --------- applications/infrared/infrared_app_signal.cpp | 116 ----- applications/infrared/infrared_app_signal.h | 134 ------ .../infrared/infrared_app_view_manager.cpp | 163 ------- .../infrared/infrared_app_view_manager.h | 164 -------- applications/infrared/infrared_brute_force.c | 153 +++++++ applications/infrared/infrared_brute_force.h | 22 + .../{cli/infrared_cli.cpp => infrared_cli.c} | 105 +++-- applications/infrared/infrared_custom_event.h | 51 +++ applications/infrared/infrared_i.h | 132 ++++++ applications/infrared/infrared_remote.c | 176 ++++++++ applications/infrared/infrared_remote.h | 28 ++ .../infrared/infrared_remote_button.c | 38 ++ .../infrared/infrared_remote_button.h | 14 + applications/infrared/infrared_runner.cpp | 9 - applications/infrared/infrared_signal.c | 264 ++++++++++++ applications/infrared/infrared_signal.h | 41 ++ .../infrared/scene/infrared_app_scene.h | 305 -------------- .../scene/infrared_app_scene_ask_back.cpp | 73 ---- .../scene/infrared_app_scene_edit.cpp | 79 ---- .../scene/infrared_app_scene_edit_delete.cpp | 100 ----- .../infrared_app_scene_edit_delete_done.cpp | 38 -- .../infrared_app_scene_edit_key_select.cpp | 58 --- .../scene/infrared_app_scene_edit_rename.cpp | 83 ---- .../infrared_app_scene_edit_rename_done.cpp | 30 -- .../scene/infrared_app_scene_learn.cpp | 76 ---- .../scene/infrared_app_scene_learn_done.cpp | 41 -- .../infrared_app_scene_learn_enter_name.cpp | 60 --- .../infrared_app_scene_learn_success.cpp | 142 ------- .../scene/infrared_app_scene_remote.cpp | 131 ------ .../scene/infrared_app_scene_remote_list.cpp | 45 -- .../scene/infrared_app_scene_start.cpp | 68 --- .../scene/infrared_app_scene_universal.cpp | 57 --- .../infrared_app_scene_universal_common.cpp | 107 ----- .../scene/infrared_app_scene_universal_tv.cpp | 123 ------ .../common/infrared_scene_universal_common.c | 92 ++++ .../common/infrared_scene_universal_common.h | 8 + applications/infrared/scenes/infrared_scene.c | 30 ++ applications/infrared/scenes/infrared_scene.h | 29 ++ .../infrared/scenes/infrared_scene_ask_back.c | 59 +++ .../infrared/scenes/infrared_scene_config.h | 17 + .../infrared/scenes/infrared_scene_debug.c | 68 +++ .../infrared/scenes/infrared_scene_edit.c | 101 +++++ .../infrared_scene_edit_button_select.c | 63 +++ .../scenes/infrared_scene_edit_delete.c | 112 +++++ .../scenes/infrared_scene_edit_delete_done.c | 46 ++ .../scenes/infrared_scene_edit_rename.c | 107 +++++ .../scenes/infrared_scene_edit_rename_done.c | 35 ++ .../infrared/scenes/infrared_scene_learn.c | 46 ++ .../scenes/infrared_scene_learn_done.c | 44 ++ .../scenes/infrared_scene_learn_enter_name.c | 66 +++ .../scenes/infrared_scene_learn_success.c | 131 ++++++ .../infrared/scenes/infrared_scene_remote.c | 119 ++++++ .../scenes/infrared_scene_remote_list.c | 44 ++ .../infrared/scenes/infrared_scene_start.c | 83 ++++ .../scenes/infrared_scene_universal.c | 53 +++ .../scenes/infrared_scene_universal_tv.c | 111 +++++ .../infrared/views/infrared_debug_view.c | 59 +++ .../infrared/views/infrared_debug_view.h | 11 + .../{view => views}/infrared_progress_view.c | 0 .../{view => views}/infrared_progress_view.h | 0 .../infrared_monitor/infrared_monitor.c | 140 ------ 77 files changed, 2940 insertions(+), 3859 deletions(-) delete mode 100644 applications/infrared/helpers/infrared_parser.cpp delete mode 100644 applications/infrared/helpers/infrared_parser.h create mode 100644 applications/infrared/infrared.c create mode 100644 applications/infrared/infrared.h delete mode 100644 applications/infrared/infrared_app.cpp delete mode 100644 applications/infrared/infrared_app.h delete mode 100644 applications/infrared/infrared_app_brute_force.cpp delete mode 100644 applications/infrared/infrared_app_brute_force.h delete mode 100644 applications/infrared/infrared_app_event.h delete mode 100644 applications/infrared/infrared_app_remote_manager.cpp delete mode 100644 applications/infrared/infrared_app_remote_manager.h delete mode 100644 applications/infrared/infrared_app_signal.cpp delete mode 100644 applications/infrared/infrared_app_signal.h delete mode 100644 applications/infrared/infrared_app_view_manager.cpp delete mode 100644 applications/infrared/infrared_app_view_manager.h create mode 100644 applications/infrared/infrared_brute_force.c create mode 100644 applications/infrared/infrared_brute_force.h rename applications/infrared/{cli/infrared_cli.cpp => infrared_cli.c} (72%) create mode 100644 applications/infrared/infrared_custom_event.h create mode 100644 applications/infrared/infrared_i.h create mode 100644 applications/infrared/infrared_remote.c create mode 100644 applications/infrared/infrared_remote.h create mode 100644 applications/infrared/infrared_remote_button.c create mode 100644 applications/infrared/infrared_remote_button.h delete mode 100644 applications/infrared/infrared_runner.cpp create mode 100644 applications/infrared/infrared_signal.c create mode 100644 applications/infrared/infrared_signal.h delete mode 100644 applications/infrared/scene/infrared_app_scene.h delete mode 100644 applications/infrared/scene/infrared_app_scene_ask_back.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_delete.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_delete_done.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_key_select.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_rename.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_edit_rename_done.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_learn.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_learn_done.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_learn_success.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_remote.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_remote_list.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_start.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_universal.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_universal_common.cpp delete mode 100644 applications/infrared/scene/infrared_app_scene_universal_tv.cpp create mode 100644 applications/infrared/scenes/common/infrared_scene_universal_common.c create mode 100644 applications/infrared/scenes/common/infrared_scene_universal_common.h create mode 100644 applications/infrared/scenes/infrared_scene.c create mode 100644 applications/infrared/scenes/infrared_scene.h create mode 100644 applications/infrared/scenes/infrared_scene_ask_back.c create mode 100644 applications/infrared/scenes/infrared_scene_config.h create mode 100644 applications/infrared/scenes/infrared_scene_debug.c create mode 100644 applications/infrared/scenes/infrared_scene_edit.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_button_select.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_delete.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_delete_done.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_rename.c create mode 100644 applications/infrared/scenes/infrared_scene_edit_rename_done.c create mode 100644 applications/infrared/scenes/infrared_scene_learn.c create mode 100644 applications/infrared/scenes/infrared_scene_learn_done.c create mode 100644 applications/infrared/scenes/infrared_scene_learn_enter_name.c create mode 100644 applications/infrared/scenes/infrared_scene_learn_success.c create mode 100644 applications/infrared/scenes/infrared_scene_remote.c create mode 100644 applications/infrared/scenes/infrared_scene_remote_list.c create mode 100644 applications/infrared/scenes/infrared_scene_start.c create mode 100644 applications/infrared/scenes/infrared_scene_universal.c create mode 100644 applications/infrared/scenes/infrared_scene_universal_tv.c create mode 100644 applications/infrared/views/infrared_debug_view.c create mode 100644 applications/infrared/views/infrared_debug_view.h rename applications/infrared/{view => views}/infrared_progress_view.c (100%) rename applications/infrared/{view => views}/infrared_progress_view.h (100%) delete mode 100644 applications/infrared_monitor/infrared_monitor.c diff --git a/applications/applications.c b/applications/applications.c index dccab589fcf3..22f9520ecf4a 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -29,7 +29,6 @@ extern int32_t display_test_app(void* p); extern int32_t gpio_app(void* p); extern int32_t ibutton_app(void* p); extern int32_t infrared_app(void* p); -extern int32_t infrared_monitor_app(void* p); extern int32_t keypad_test_app(void* p); extern int32_t lfrfid_app(void* p); extern int32_t lfrfid_debug_app(void* p); @@ -412,14 +411,6 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { .flags = FlipperApplicationFlagDefault}, #endif -#ifdef APP_INFRARED_MONITOR - {.app = infrared_monitor_app, - .name = "Infrared Monitor", - .stack_size = 1024, - .icon = NULL, - .flags = FlipperApplicationFlagDefault}, -#endif - #ifdef APP_LF_RFID {.app = lfrfid_debug_app, .name = "LF-RFID Debug", diff --git a/applications/applications.mk b/applications/applications.mk index e7a9ebfc056d..d2272efb1138 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -51,7 +51,6 @@ APP_SNAKE_GAME = 1 # Debug APP_ACCESSOR = 1 APP_BLINK = 1 -APP_INFRARED_MONITOR = 1 APP_KEYPAD_TEST = 1 APP_SD_TEST = 1 APP_VIBRO_TEST = 1 @@ -70,14 +69,6 @@ endif # that will be shown in menu # Prefix with APP_* - -APP_INFRARED_MONITOR ?= 0 -ifeq ($(APP_INFRARED_MONITOR), 1) -CFLAGS += -DAPP_INFRARED_MONITOR -SRV_GUI = 1 -endif - - APP_UNIT_TESTS ?= 0 ifeq ($(APP_UNIT_TESTS), 1) CFLAGS += -DAPP_UNIT_TESTS diff --git a/applications/gui/modules/loading.c b/applications/gui/modules/loading.c index 60dc8338d1a2..575126972771 100644 --- a/applications/gui/modules/loading.c +++ b/applications/gui/modules/loading.c @@ -20,10 +20,10 @@ typedef struct { static void loading_draw_callback(Canvas* canvas, void* _model) { LoadingModel* model = (LoadingModel*)_model; - uint8_t x = 7; - uint8_t y = 40; uint8_t width = 49; uint8_t height = 47; + uint8_t x = (canvas_width(canvas) - width) / 2; + uint8_t y = (canvas_height(canvas) - height) / 2; elements_bold_rounded_frame(canvas, x, y, width, height); diff --git a/applications/gui/scene_manager.c b/applications/gui/scene_manager.c index a8c40320908d..590145e1e7b6 100755 --- a/applications/gui/scene_manager.c +++ b/applications/gui/scene_manager.c @@ -165,6 +165,25 @@ bool scene_manager_search_and_switch_to_previous_scene( } } +bool scene_manager_search_and_switch_to_previous_scene_one_of( + SceneManager* scene_manager, + const uint32_t* scene_ids, + size_t scene_ids_size) { + furi_assert(scene_manager); + furi_assert(scene_ids); + bool scene_found = false; + + for(size_t i = 0; i < scene_ids_size; ++i) { + const uint32_t scene_id = scene_ids[i]; + if(scene_manager_has_previous_scene(scene_manager, scene_id)) { + scene_manager_search_and_switch_to_previous_scene(scene_manager, scene_id); + scene_found = true; + break; + } + } + return scene_found; +} + bool scene_manager_has_previous_scene(SceneManager* scene_manager, uint32_t scene_id) { furi_assert(scene_manager); bool scene_found = false; diff --git a/applications/gui/scene_manager.h b/applications/gui/scene_manager.h index 6916285302c8..5b833e5de205 100755 --- a/applications/gui/scene_manager.h +++ b/applications/gui/scene_manager.h @@ -5,6 +5,7 @@ #pragma once +#include #include #include @@ -146,6 +147,19 @@ bool scene_manager_search_and_switch_to_previous_scene( SceneManager* scene_manager, uint32_t scene_id); +/** Search and switch to previous Scene, multiple choice + * + * @param scene_manager SceneManager instance + * @param scene_ids Array of scene IDs + * @param scene_ids_size Array of scene IDs size + * + * @return true if one of previous scenes was found, false otherwise + */ +bool scene_manager_search_and_switch_to_previous_scene_one_of( + SceneManager* scene_manager, + const uint32_t* scene_ids, + size_t scene_ids_size); + /** Clear Scene stack and switch to another Scene * * @param scene_manager SceneManager instance diff --git a/applications/infrared/helpers/infrared_parser.cpp b/applications/infrared/helpers/infrared_parser.cpp deleted file mode 100644 index d85a7269b968..000000000000 --- a/applications/infrared/helpers/infrared_parser.cpp +++ /dev/null @@ -1,157 +0,0 @@ - -#include "../infrared_app_signal.h" -#include "infrared.h" -#include "infrared/helpers/infrared_parser.h" -#include "infrared_worker.h" -#include "m-string.h" -#include -#include -#include -#include - -#define TAG "InfraredParser" - -bool infrared_parser_save_signal( - FlipperFormat* ff, - const InfraredAppSignal& signal, - const std::string& name) { - furi_assert(ff); - furi_assert(!name.empty()); - - bool result = false; - - do { - if(!flipper_format_write_comment_cstr(ff, "")) break; - if(!flipper_format_write_string_cstr(ff, "name", name.c_str())) break; - if(signal.is_raw()) { - furi_assert(signal.get_raw_signal().timings_cnt <= MAX_TIMINGS_AMOUNT); - auto raw_signal = signal.get_raw_signal(); - if(!flipper_format_write_string_cstr(ff, "type", "raw")) break; - if(!flipper_format_write_uint32(ff, "frequency", &raw_signal.frequency, 1)) break; - if(!flipper_format_write_float(ff, "duty_cycle", &raw_signal.duty_cycle, 1)) break; - if(!flipper_format_write_uint32(ff, "data", raw_signal.timings, raw_signal.timings_cnt)) - break; - } else { - auto parsed_signal = signal.get_message(); - const char* protocol_name = infrared_get_protocol_name(parsed_signal.protocol); - if(!flipper_format_write_string_cstr(ff, "type", "parsed")) break; - if(!flipper_format_write_string_cstr(ff, "protocol", protocol_name)) break; - if(!flipper_format_write_hex(ff, "address", (uint8_t*)&parsed_signal.address, 4)) - break; - if(!flipper_format_write_hex(ff, "command", (uint8_t*)&parsed_signal.command, 4)) - break; - } - result = true; - } while(0); - - return result; -} - -bool infrared_parser_read_signal(FlipperFormat* ff, InfraredAppSignal& signal, std::string& name) { - furi_assert(ff); - - bool result = false; - string_t read_string; - string_init(read_string); - - do { - if(!flipper_format_read_string(ff, "name", read_string)) break; - name = string_get_cstr(read_string); - if(!flipper_format_read_string(ff, "type", read_string)) break; - if(!string_cmp_str(read_string, "raw")) { - uint32_t* timings = nullptr; - uint32_t timings_cnt = 0; - uint32_t frequency = 0; - float duty_cycle = 0; - - if(!flipper_format_read_uint32(ff, "frequency", &frequency, 1)) break; - if(!flipper_format_read_float(ff, "duty_cycle", &duty_cycle, 1)) break; - if(!flipper_format_get_value_count(ff, "data", &timings_cnt)) break; - if(timings_cnt > MAX_TIMINGS_AMOUNT) break; - timings = (uint32_t*)malloc(sizeof(uint32_t) * timings_cnt); - if(flipper_format_read_uint32(ff, "data", timings, timings_cnt)) { - signal.set_raw_signal(timings, timings_cnt, frequency, duty_cycle); - result = true; - } - free(timings); - } else if(!string_cmp_str(read_string, "parsed")) { - InfraredMessage parsed_signal; - if(!flipper_format_read_string(ff, "protocol", read_string)) break; - parsed_signal.protocol = infrared_get_protocol_by_name(string_get_cstr(read_string)); - if(!flipper_format_read_hex(ff, "address", (uint8_t*)&parsed_signal.address, 4)) break; - if(!flipper_format_read_hex(ff, "command", (uint8_t*)&parsed_signal.command, 4)) break; - if(!infrared_parser_is_parsed_signal_valid(&parsed_signal)) break; - signal.set_message(&parsed_signal); - result = true; - } else { - FURI_LOG_E(TAG, "Unknown type of signal (allowed - raw/parsed) "); - } - } while(0); - - string_clear(read_string); - return result; -} - -bool infrared_parser_is_parsed_signal_valid(const InfraredMessage* signal) { - furi_assert(signal); - bool result = true; - - if(!infrared_is_protocol_valid(signal->protocol)) { - FURI_LOG_E(TAG, "Unknown protocol"); - result = false; - } - - if(result) { - uint32_t address_length = infrared_get_protocol_address_length(signal->protocol); - uint32_t address_mask = (1LU << address_length) - 1; - if(signal->address != (signal->address & address_mask)) { - FURI_LOG_E( - TAG, - "Address is out of range (mask 0x%08lX): 0x%lX\r\n", - address_mask, - signal->address); - result = false; - } - } - - if(result) { - uint32_t command_length = infrared_get_protocol_command_length(signal->protocol); - uint32_t command_mask = (1LU << command_length) - 1; - if(signal->command != (signal->command & command_mask)) { - FURI_LOG_E( - TAG, - "Command is out of range (mask 0x%08lX): 0x%lX\r\n", - command_mask, - signal->command); - result = false; - } - } - - return result; -} - -bool infrared_parser_is_raw_signal_valid( - uint32_t frequency, - float duty_cycle, - uint32_t timings_cnt) { - bool result = true; - - if((frequency > INFRARED_MAX_FREQUENCY) || (frequency < INFRARED_MIN_FREQUENCY)) { - FURI_LOG_E( - TAG, - "Frequency is out of range (%lX - %lX): %lX", - INFRARED_MIN_FREQUENCY, - INFRARED_MAX_FREQUENCY, - frequency); - result = false; - } else if((duty_cycle <= 0) || (duty_cycle > 1)) { - FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", (double)duty_cycle); - result = false; - } else if((timings_cnt <= 0) || (timings_cnt > MAX_TIMINGS_AMOUNT)) { - FURI_LOG_E( - TAG, "Timings amount is out of range (0 - %lX): %lX", MAX_TIMINGS_AMOUNT, timings_cnt); - result = false; - } - - return result; -} diff --git a/applications/infrared/helpers/infrared_parser.h b/applications/infrared/helpers/infrared_parser.h deleted file mode 100644 index 2e790c38188d..000000000000 --- a/applications/infrared/helpers/infrared_parser.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file infrared_parser.h - * Infrared: Helper file for conversion Flipper File Format - * to Infrared signal class, and backwards - */ -#pragma once - -#include "../infrared_app_signal.h" -#include -#include - -/** Save Infrared signal into file - * - * @param ff - Flipper File Format instance - * @param signal - Infrared signal to save - * @param name - name for saved signal. Every - * signal on disk has name. - */ -bool infrared_parser_save_signal( - FlipperFormat* ff, - const InfraredAppSignal& signal, - const std::string& name); - -/** Read Infrared signal from file - * - * @param ff - Flipper File Format instance - * @param signal - Infrared signal to read to - * @param name - name for saved signal. Every - * signal in file has name. - */ -bool infrared_parser_read_signal(FlipperFormat* ff, InfraredAppSignal& signal, std::string& name); - -/** Validate parsed signal - * - * @signal - signal to validate - * @retval true if valid, false otherwise - */ -bool infrared_parser_is_parsed_signal_valid(const InfraredMessage* signal); - -/** Validate raw signal - * - * @signal - signal to validate - * @retval true if valid, false otherwise - */ -bool infrared_parser_is_raw_signal_valid( - uint32_t frequency, - float duty_cycle, - uint32_t timings_cnt); diff --git a/applications/infrared/infrared.c b/applications/infrared/infrared.c new file mode 100644 index 000000000000..ee6b931eddef --- /dev/null +++ b/applications/infrared/infrared.c @@ -0,0 +1,397 @@ +#include "infrared_i.h" + +#include +#include + +static const NotificationSequence* infrared_notification_sequences[] = { + &sequence_success, + &sequence_set_only_green_255, + &sequence_reset_green, + &sequence_blink_cyan_10, + &sequence_blink_magenta_10}; + +static void infrared_make_app_folder(Infrared* infrared) { + if(!storage_simply_mkdir(infrared->storage, INFRARED_APP_FOLDER)) { + dialog_message_show_storage_error(infrared->dialogs, "Cannot create\napp folder"); + } +} + +static bool infrared_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + Infrared* infrared = context; + return scene_manager_handle_custom_event(infrared->scene_manager, event); +} + +static bool infrared_back_event_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + return scene_manager_handle_back_event(infrared->scene_manager); +} + +static void infrared_tick_event_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + scene_manager_handle_tick_event(infrared->scene_manager); +} + +static void infrared_find_vacant_remote_name(string_t name, const char* path) { + Storage* storage = furi_record_open("storage"); + + string_t base_path; + string_init_set_str(base_path, path); + + if(string_end_with_str_p(base_path, INFRARED_APP_EXTENSION)) { + size_t filename_start = string_search_rchar(base_path, '/'); + string_left(base_path, filename_start); + } + + string_printf(base_path, "%s/%s%s", path, string_get_cstr(name), INFRARED_APP_EXTENSION); + + FS_Error status = storage_common_stat(storage, string_get_cstr(base_path), NULL); + + if(status == FSE_OK) { + /* If the suggested name is occupied, try another one (name2, name3, etc) */ + size_t dot = string_search_rchar(base_path, '.'); + string_left(base_path, dot); + + string_t path_temp; + string_init(path_temp); + + uint32_t i = 1; + do { + string_printf( + path_temp, "%s%u%s", string_get_cstr(base_path), ++i, INFRARED_APP_EXTENSION); + status = storage_common_stat(storage, string_get_cstr(path_temp), NULL); + } while(status == FSE_OK); + + string_clear(path_temp); + + if(status == FSE_NOT_EXIST) { + string_cat_printf(name, "%u", i); + } + } + + string_clear(base_path); + furi_record_close("storage"); +} + +static Infrared* infrared_alloc() { + Infrared* infrared = malloc(sizeof(Infrared)); + + string_init(infrared->file_path); + + InfraredAppState* app_state = &infrared->app_state; + app_state->is_learning_new_remote = false; + app_state->is_debug_enabled = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); + app_state->edit_target = InfraredEditTargetNone; + app_state->edit_mode = InfraredEditModeNone; + app_state->current_button_index = InfraredButtonIndexNone; + + infrared->scene_manager = scene_manager_alloc(&infrared_scene_handlers, infrared); + infrared->view_dispatcher = view_dispatcher_alloc(); + + infrared->gui = furi_record_open("gui"); + + ViewDispatcher* view_dispatcher = infrared->view_dispatcher; + view_dispatcher_attach_to_gui(view_dispatcher, infrared->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_enable_queue(view_dispatcher); + view_dispatcher_set_event_callback_context(view_dispatcher, infrared); + view_dispatcher_set_custom_event_callback(view_dispatcher, infrared_custom_event_callback); + view_dispatcher_set_navigation_event_callback(view_dispatcher, infrared_back_event_callback); + view_dispatcher_set_tick_event_callback(view_dispatcher, infrared_tick_event_callback, 100); + + infrared->storage = furi_record_open("storage"); + infrared->dialogs = furi_record_open("dialogs"); + infrared->notifications = furi_record_open("notification"); + + infrared->worker = infrared_worker_alloc(); + infrared->remote = infrared_remote_alloc(); + infrared->received_signal = infrared_signal_alloc(); + infrared->brute_force = infrared_brute_force_alloc(); + + infrared->submenu = submenu_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewSubmenu, submenu_get_view(infrared->submenu)); + + infrared->text_input = text_input_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewTextInput, text_input_get_view(infrared->text_input)); + + infrared->dialog_ex = dialog_ex_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewDialogEx, dialog_ex_get_view(infrared->dialog_ex)); + + infrared->button_menu = button_menu_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewButtonMenu, button_menu_get_view(infrared->button_menu)); + + infrared->popup = popup_alloc(); + view_dispatcher_add_view(view_dispatcher, InfraredViewPopup, popup_get_view(infrared->popup)); + + infrared->view_stack = view_stack_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewStack, view_stack_get_view(infrared->view_stack)); + + if(app_state->is_debug_enabled) { + infrared->debug_view = infrared_debug_view_alloc(); + view_dispatcher_add_view( + view_dispatcher, + InfraredViewDebugView, + infrared_debug_view_get_view(infrared->debug_view)); + } + + infrared->button_panel = button_panel_alloc(); + infrared->loading = loading_alloc(); + infrared->progress = infrared_progress_view_alloc(); + + return infrared; +} + +static void infrared_free(Infrared* infrared) { + furi_assert(infrared); + ViewDispatcher* view_dispatcher = infrared->view_dispatcher; + InfraredAppState* app_state = &infrared->app_state; + + view_dispatcher_remove_view(view_dispatcher, InfraredViewSubmenu); + submenu_free(infrared->submenu); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewTextInput); + text_input_free(infrared->text_input); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewDialogEx); + dialog_ex_free(infrared->dialog_ex); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewButtonMenu); + button_menu_free(infrared->button_menu); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewPopup); + popup_free(infrared->popup); + + view_dispatcher_remove_view(view_dispatcher, InfraredViewStack); + view_stack_free(infrared->view_stack); + + if(app_state->is_debug_enabled) { + view_dispatcher_remove_view(view_dispatcher, InfraredViewDebugView); + infrared_debug_view_free(infrared->debug_view); + } + + button_panel_free(infrared->button_panel); + loading_free(infrared->loading); + infrared_progress_view_free(infrared->progress); + + view_dispatcher_free(view_dispatcher); + scene_manager_free(infrared->scene_manager); + + infrared_brute_force_free(infrared->brute_force); + infrared_signal_free(infrared->received_signal); + infrared_remote_free(infrared->remote); + infrared_worker_free(infrared->worker); + + furi_record_close("gui"); + infrared->gui = NULL; + + furi_record_close("notification"); + infrared->notifications = NULL; + + furi_record_close("dialogs"); + infrared->dialogs = NULL; + + furi_record_close("gui"); + infrared->gui = NULL; + + string_clear(infrared->file_path); + + free(infrared); +} + +bool infrared_add_remote_with_button( + Infrared* infrared, + const char* button_name, + InfraredSignal* signal) { + InfraredRemote* remote = infrared->remote; + + string_t new_name, new_path; + string_init_set_str(new_name, INFRARED_DEFAULT_REMOTE_NAME); + string_init_set_str(new_path, INFRARED_APP_FOLDER); + + infrared_find_vacant_remote_name(new_name, string_get_cstr(new_path)); + string_cat_printf(new_path, "/%s%s", string_get_cstr(new_name), INFRARED_APP_EXTENSION); + + infrared_remote_reset(remote); + infrared_remote_set_name(remote, string_get_cstr(new_name)); + infrared_remote_set_path(remote, string_get_cstr(new_path)); + + string_clear(new_name); + string_clear(new_path); + return infrared_remote_add_button(remote, button_name, signal); +} + +bool infrared_rename_current_remote(Infrared* infrared, const char* name) { + InfraredRemote* remote = infrared->remote; + const char* remote_path = infrared_remote_get_path(remote); + + if(!strcmp(infrared_remote_get_name(remote), name)) { + return true; + } + + string_t new_name; + string_init_set_str(new_name, name); + + infrared_find_vacant_remote_name(new_name, remote_path); + + string_t new_path; + string_init_set(new_path, infrared_remote_get_path(remote)); + if(string_end_with_str_p(new_path, INFRARED_APP_EXTENSION)) { + size_t filename_start = string_search_rchar(new_path, '/'); + string_left(new_path, filename_start); + } + string_cat_printf(new_path, "/%s%s", string_get_cstr(new_name), INFRARED_APP_EXTENSION); + + Storage* storage = furi_record_open("storage"); + + FS_Error status = storage_common_rename( + storage, infrared_remote_get_path(remote), string_get_cstr(new_path)); + infrared_remote_set_name(remote, string_get_cstr(new_name)); + + string_clear(new_name); + string_clear(new_path); + + furi_record_close("storage"); + return (status == FSE_OK || status == FSE_EXIST); +} + +void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { + if(infrared_signal_is_raw(signal)) { + InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size); + } else { + InfraredMessage* message = infrared_signal_get_message(signal); + infrared_worker_set_decoded_signal(infrared->worker, message); + } + + DOLPHIN_DEED(DolphinDeedIrSend); + infrared_worker_tx_start(infrared->worker); +} + +void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { + furi_assert(button_index < infrared_remote_get_button_count(infrared->remote)); + + InfraredRemoteButton* button = infrared_remote_get_button(infrared->remote, button_index); + InfraredSignal* signal = infrared_remote_button_get_signal(button); + + infrared_tx_start_signal(infrared, signal); +} + +void infrared_tx_start_received(Infrared* infrared) { + infrared_tx_start_signal(infrared, infrared->received_signal); +} + +void infrared_tx_stop(Infrared* infrared) { + infrared_worker_tx_stop(infrared->worker); +} + +void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) { + va_list args; + va_start(args, text); + + vsnprintf(infrared->text_store[bank], INFRARED_TEXT_STORE_SIZE, text, args); + + va_end(args); +} + +void infrared_text_store_clear(Infrared* infrared, uint32_t bank) { + memset(infrared->text_store[bank], 0, INFRARED_TEXT_STORE_SIZE); +} + +void infrared_play_notification_message(Infrared* infrared, uint32_t message) { + furi_assert(message < sizeof(infrared_notification_sequences) / sizeof(NotificationSequence*)); + notification_message(infrared->notifications, infrared_notification_sequences[message]); +} + +void infrared_show_loading_popup(Infrared* infrared, bool show) { + TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + ViewStack* view_stack = infrared->view_stack; + Loading* loading = infrared->loading; + + if(show) { + // Raise timer priority so that animations can play + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + view_stack_add_view(view_stack, loading_get_view(loading)); + } else { + view_stack_remove_view(view_stack, loading_get_view(loading)); + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + +void infrared_signal_sent_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend); +} + +void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { + furi_assert(context); + Infrared* infrared = context; + + if(infrared_worker_signal_is_decoded(received_signal)) { + infrared_signal_set_message( + infrared->received_signal, infrared_worker_get_decoded_signal(received_signal)); + } else { + const uint32_t* timings; + size_t timings_size; + infrared_worker_get_raw_signal(received_signal, &timings, &timings_size); + infrared_signal_set_raw_signal( + infrared->received_signal, + timings, + timings_size, + INFRARED_COMMON_CARRIER_FREQUENCY, + INFRARED_COMMON_DUTY_CYCLE); + } + + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeSignalReceived); +} + +void infrared_text_input_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeTextEditDone); +} + +void infrared_popup_timeout_callback(void* context) { + furi_assert(context); + Infrared* infrared = context; + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypePopupTimeout); +} + +int32_t infrared_app(void* p) { + Infrared* infrared = infrared_alloc(); + + infrared_make_app_folder(infrared); + + bool is_remote_loaded = false; + + if(p) { + string_set_str(infrared->file_path, (const char*)p); + is_remote_loaded = infrared_remote_load(infrared->remote, infrared->file_path); + if(!is_remote_loaded) { + dialog_message_show_storage_error( + infrared->dialogs, "Failed to load\nselected remote"); + return -1; + } + } + + if(is_remote_loaded) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); + } else { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneStart); + } + + view_dispatcher_run(infrared->view_dispatcher); + + infrared_free(infrared); + return 0; +} diff --git a/applications/infrared/infrared.h b/applications/infrared/infrared.h new file mode 100644 index 000000000000..e5eeb11772f8 --- /dev/null +++ b/applications/infrared/infrared.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct Infrared Infrared; diff --git a/applications/infrared/infrared_app.cpp b/applications/infrared/infrared_app.cpp deleted file mode 100644 index 1ac859d10799..000000000000 --- a/applications/infrared/infrared_app.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "infrared_app.h" -#include "m-string.h" -#include -#include -#include -#include -#include -#include - -int32_t InfraredApp::run(void* args) { - InfraredAppEvent event; - bool consumed; - bool exit = false; - - if(args) { - string_t path; - string_init_set_str(path, (char*)args); - if(string_end_with_str_p(path, InfraredApp::infrared_extension)) { - bool result = remote_manager.load(path); - if(result) { - current_scene = InfraredApp::Scene::Remote; - } else { - printf("Failed to load remote \'%s\'\r\n", string_get_cstr(path)); - return -1; - } - } - string_clear(path); - } - - scenes[current_scene]->on_enter(this); - - while(!exit) { - view_manager.receive_event(&event); - - if(event.type == InfraredAppEvent::Type::Exit) break; - - consumed = scenes[current_scene]->on_event(this, &event); - - if(!consumed) { - if(event.type == InfraredAppEvent::Type::Back) { - exit = switch_to_previous_scene(); - } - } - }; - - scenes[current_scene]->on_exit(this); - - return 0; -}; - -InfraredApp::InfraredApp() { - furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size()); - string_init_set_str(file_path, InfraredApp::infrared_directory); - notification = static_cast(furi_record_open("notification")); - dialogs = static_cast(furi_record_open("dialogs")); - infrared_worker = infrared_worker_alloc(); -} - -InfraredApp::~InfraredApp() { - infrared_worker_free(infrared_worker); - furi_record_close("notification"); - furi_record_close("dialogs"); - string_clear(file_path); - for(auto& [key, scene] : scenes) delete scene; -} - -InfraredAppViewManager* InfraredApp::get_view_manager() { - return &view_manager; -} - -void InfraredApp::set_learn_new_remote(bool value) { - learn_new_remote = value; -} - -bool InfraredApp::get_learn_new_remote() { - return learn_new_remote; -} - -void InfraredApp::switch_to_next_scene(Scene next_scene) { - previous_scenes_list.push_front(current_scene); - switch_to_next_scene_without_saving(next_scene); -} - -void InfraredApp::switch_to_next_scene_without_saving(Scene next_scene) { - if(next_scene != Scene::Exit) { - scenes[current_scene]->on_exit(this); - current_scene = next_scene; - scenes[current_scene]->on_enter(this); - view_manager.clear_events(); - } -} - -void InfraredApp::search_and_switch_to_previous_scene( - const std::initializer_list& scenes_list) { - Scene previous_scene = Scene::Start; - bool scene_found = false; - - while(!scene_found) { - previous_scene = get_previous_scene(); - - if(previous_scene == Scene::Exit) break; - - for(Scene element : scenes_list) { - if(previous_scene == element) { - scene_found = true; - break; - } - } - } - - if(previous_scene == Scene::Exit) { - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::Exit; - view_manager.send_event(&event); - } else { - scenes[current_scene]->on_exit(this); - current_scene = previous_scene; - scenes[current_scene]->on_enter(this); - view_manager.clear_events(); - } -} - -bool InfraredApp::switch_to_previous_scene(uint8_t count) { - Scene previous_scene = Scene::Start; - - for(uint8_t i = 0; i < count; i++) previous_scene = get_previous_scene(); - - if(previous_scene == Scene::Exit) return true; - - scenes[current_scene]->on_exit(this); - current_scene = previous_scene; - scenes[current_scene]->on_enter(this); - view_manager.clear_events(); - return false; -} - -InfraredApp::Scene InfraredApp::get_previous_scene() { - Scene scene = Scene::Exit; - - if(!previous_scenes_list.empty()) { - scene = previous_scenes_list.front(); - previous_scenes_list.pop_front(); - } - - return scene; -} - -InfraredAppRemoteManager* InfraredApp::get_remote_manager() { - return &remote_manager; -} - -void InfraredApp::set_text_store(uint8_t index, const char* text...) { - furi_check(index < text_store_max); - - va_list args; - va_start(args, text); - - vsnprintf(text_store[index], text_store_size, text, args); - - va_end(args); -} - -char* InfraredApp::get_text_store(uint8_t index) { - furi_check(index < text_store_max); - - return text_store[index]; -} - -uint8_t InfraredApp::get_text_store_size() { - return text_store_size; -} - -void InfraredApp::text_input_callback(void* context) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::TextEditDone; - app->get_view_manager()->send_event(&event); -} - -void InfraredApp::popup_callback(void* context) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::PopupTimer; - app->get_view_manager()->send_event(&event); -} - -void InfraredApp::set_edit_element(InfraredApp::EditElement value) { - element = value; -} - -InfraredApp::EditElement InfraredApp::get_edit_element(void) { - return element; -} - -void InfraredApp::set_edit_action(InfraredApp::EditAction value) { - action = value; -} - -InfraredApp::EditAction InfraredApp::get_edit_action(void) { - return action; -} - -void InfraredApp::set_current_button(int value) { - current_button = value; -} - -int InfraredApp::get_current_button() { - return current_button; -} - -void InfraredApp::notify_success() { - notification_message(notification, &sequence_success); -} - -void InfraredApp::notify_blink_read() { - notification_message(notification, &sequence_blink_cyan_10); -} - -void InfraredApp::notify_blink_send() { - notification_message(notification, &sequence_blink_magenta_10); -} - -DialogsApp* InfraredApp::get_dialogs() { - return dialogs; -} - -void InfraredApp::notify_green_on() { - notification_message(notification, &sequence_set_only_green_255); -} - -void InfraredApp::notify_green_off() { - notification_message(notification, &sequence_reset_green); -} - -InfraredWorker* InfraredApp::get_infrared_worker() { - return infrared_worker; -} - -const InfraredAppSignal& InfraredApp::get_received_signal() const { - return received_signal; -} - -void InfraredApp::set_received_signal(const InfraredAppSignal& signal) { - received_signal = signal; -} - -void InfraredApp::signal_sent_callback(void* context) { - InfraredApp* app = static_cast(context); - app->notify_blink_send(); -} diff --git a/applications/infrared/infrared_app.h b/applications/infrared/infrared_app.h deleted file mode 100644 index 1cb8b6617a0c..000000000000 --- a/applications/infrared/infrared_app.h +++ /dev/null @@ -1,326 +0,0 @@ -/** - * @file infrared_app.h - * Infrared: Main infrared application class - */ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scene/infrared_app_scene.h" -#include "scene/infrared_app_scene.h" -#include "infrared_app_view_manager.h" -#include "infrared_app_remote_manager.h" -#include "infrared_app_view_manager.h" - -/** Main Infrared application class */ -class InfraredApp { -public: - /** Enum to save scene state: edit element */ - enum class EditElement : uint8_t { - Button, - Remote, - }; - /** Enum to save scene state: edit action */ - enum class EditAction : uint8_t { - Rename, - Delete, - }; - /** List of scenes for Infrared application */ - enum class Scene : uint8_t { - Exit, - Start, - Universal, - UniversalTV, - UniversalAudio, - UniversalAirConditioner, - Learn, - LearnSuccess, - LearnEnterName, - LearnDone, - AskBack, - Remote, - RemoteList, - Edit, - EditKeySelect, - EditRename, - EditDelete, - EditRenameDone, - EditDeleteDone, - }; - - /** Start application - * - * @param args - application arguments. - * Allowed argument is path to remote file. - * @retval 0 on success, error code otherwise - */ - int32_t run(void* args); - - /** Switch to next scene. Put current scene number on stack. - * Doesn't save scene state. - * - * @param index - next scene index - */ - void switch_to_next_scene(Scene index); - - /** Switch to next scene, but don't put current scene on - * stack. Thus calling switch_to_previous_scene() doesn't return - * to current scene. - * - * @param index - next scene index - */ - void switch_to_next_scene_without_saving(Scene index); - - /** Switch to previous scene. Pop scenes from stack and switch to last one. - * - * @param count - how many scenes should be popped - * @retval false on failed, true on success - */ - bool switch_to_previous_scene(uint8_t count = 1); - - /** Get previous scene in scene stack - * - * @retval previous scene - */ - Scene get_previous_scene(); - - /** Get view manager instance - * - * @retval view manager instance - */ - InfraredAppViewManager* get_view_manager(); - - /** Set one of text stores - * - * @param index - index of text store - * @param text - text to set - */ - void set_text_store(uint8_t index, const char* text...); - - /** Get value in text store - * - * @param index - index of text store - * @retval value in text_store - */ - char* get_text_store(uint8_t index); - - /** Get text store size - * - * @retval size of text store - */ - uint8_t get_text_store_size(); - - /** Get remote manager instance - * - * @retval remote manager instance - */ - InfraredAppRemoteManager* get_remote_manager(); - - /** Get infrared worker instance - * - * @retval infrared worker instance - */ - InfraredWorker* get_infrared_worker(); - - /** Get signal, previously got on Learn scene - * - * @retval received signal - */ - const InfraredAppSignal& get_received_signal() const; - - /** Set received signal - * - * @param signal - signal - */ - void set_received_signal(const InfraredAppSignal& signal); - - /** Switch to previous scene in one of provided in list. - * Pop scene stack, and find first scene from list. - * - * @param scenes_list - list of scenes - */ - void search_and_switch_to_previous_scene(const std::initializer_list& scenes_list); - - /** Set edit element value. It is used on edit scene to determine - * what should be deleted - remote or button. - * - * @param value - value to set - */ - void set_edit_element(EditElement value); - - /** Get edit element - * - * @retval edit element value - */ - EditElement get_edit_element(void); - - /** Set edit action value. It is used on edit scene to determine - * what action to perform - deletion or renaming. - * - * @param value - value to set - */ - void set_edit_action(EditAction value); - - /** Get edit action - * - * @retval edit action value - */ - EditAction get_edit_action(void); - - /** Get state of learning new signal. - * Adding new remote with 1 button from start scene and - * learning 1 additional button to remote have very similar - * flow, so they are joined. Difference in flow is handled - * by this boolean flag. - * - * @retval false if flow is in learning new remote, true if - * adding signal to created remote - * - */ - bool get_learn_new_remote(); - - /** Set state of learning new signal. - * Adding new remote with 1 button from start scene and - * learning 1 additional button to remote have very similar - * flow, so they are joined. Difference in flow is handled - * by this boolean flag. - * - * @param value - false if flow is in learning new remote, true if - * adding signal to created remote - */ - void set_learn_new_remote(bool value); - - /** Button is not assigned value - */ - enum : int { - ButtonNA = -1, - }; - - /** Get current button index - * - * @retval current button index - */ - int get_current_button(); - - /** Set current button index - * - * @param current button index - */ - void set_current_button(int value); - - /** Play success notification */ - void notify_success(); - /** Play red blink notification */ - void notify_blink_read(); - /** Light green */ - void notify_green_on(); - /** Disable green light */ - void notify_green_off(); - /** Blink on send */ - void notify_blink_send(); - - /** Get Dialogs instance */ - DialogsApp* get_dialogs(); - - /** Text input callback - * - * @param context - context to pass to callback - */ - static void text_input_callback(void* context); - - /** Popup callback - * - * @param context - context to pass to callback - */ - static void popup_callback(void* context); - - /** Signal sent callback - * - * @param context - context to pass to callback - */ - static void signal_sent_callback(void* context); - - /** Main class constructor, initializes all critical objects */ - InfraredApp(); - /** Main class destructor, deinitializes all critical objects */ - ~InfraredApp(); - - string_t file_path; - - /** Path to Infrared directory */ - static constexpr const char* infrared_directory = "/any/infrared"; - /** Infrared files extension (remote files and universal databases) */ - static constexpr const char* infrared_extension = ".ir"; - /** Max Raw timings in signal */ - static constexpr const uint32_t max_raw_timings_in_signal = 512; - /** Max line length in Infrared file */ - static constexpr const uint32_t max_line_length = - (9 + 1) * InfraredApp::max_raw_timings_in_signal + 100; - -private: - /** Text store size */ - static constexpr const uint8_t text_store_size = 128; - /** Amount of text stores */ - static constexpr const uint8_t text_store_max = 2; - /** Store text here, for some views, because they doesn't - * hold ownership of text */ - char text_store[text_store_max][text_store_size + 1]; - /** - * Flag to control adding new signal flow. - * Adding new remote with 1 button from start scene and - * learning 1 additional button to remote have very similar - * flow, so they are joined. Difference in flow is handled - * by this boolean flag. - */ - bool learn_new_remote; - /** Value to control edit scene */ - EditElement element; - /** Value to control edit scene */ - EditAction action; - /** Selected button index */ - uint32_t current_button; - - /** Notification instance */ - NotificationApp* notification; - /** Dialogs instance */ - DialogsApp* dialogs; - /** View manager instance */ - InfraredAppViewManager view_manager; - /** Remote manager instance */ - InfraredAppRemoteManager remote_manager; - /** Infrared worker instance */ - InfraredWorker* infrared_worker; - /** Signal received on Learn scene */ - InfraredAppSignal received_signal; - - /** Stack of previous scenes */ - std::forward_list previous_scenes_list; - /** Now acting scene */ - Scene current_scene = Scene::Start; - - /** Map of index/scene objects */ - std::map scenes = { - {Scene::Start, new InfraredAppSceneStart()}, - {Scene::Universal, new InfraredAppSceneUniversal()}, - {Scene::UniversalTV, new InfraredAppSceneUniversalTV()}, - {Scene::Learn, new InfraredAppSceneLearn()}, - {Scene::LearnSuccess, new InfraredAppSceneLearnSuccess()}, - {Scene::LearnEnterName, new InfraredAppSceneLearnEnterName()}, - {Scene::LearnDone, new InfraredAppSceneLearnDone()}, - {Scene::AskBack, new InfraredAppSceneAskBack()}, - {Scene::Remote, new InfraredAppSceneRemote()}, - {Scene::RemoteList, new InfraredAppSceneRemoteList()}, - {Scene::Edit, new InfraredAppSceneEdit()}, - {Scene::EditKeySelect, new InfraredAppSceneEditKeySelect()}, - {Scene::EditRename, new InfraredAppSceneEditRename()}, - {Scene::EditDelete, new InfraredAppSceneEditDelete()}, - {Scene::EditRenameDone, new InfraredAppSceneEditRenameDone()}, - {Scene::EditDeleteDone, new InfraredAppSceneEditDeleteDone()}, - }; -}; diff --git a/applications/infrared/infrared_app_brute_force.cpp b/applications/infrared/infrared_app_brute_force.cpp deleted file mode 100644 index 2910a3998d97..000000000000 --- a/applications/infrared/infrared_app_brute_force.cpp +++ /dev/null @@ -1,93 +0,0 @@ - -#include "helpers/infrared_parser.h" -#include "infrared_app_brute_force.h" -#include "infrared_app_signal.h" -#include -#include -#include - -void InfraredAppBruteForce::add_record(int index, const char* name) { - records[name].index = index; - records[name].amount = 0; -} - -bool InfraredAppBruteForce::calculate_messages() { - bool result = false; - - Storage* storage = static_cast(furi_record_open("storage")); - FlipperFormat* ff = flipper_format_file_alloc(storage); - result = flipper_format_file_open_existing(ff, universal_db_filename); - - if(result) { - InfraredAppSignal signal; - - string_t signal_name; - string_init(signal_name); - while(flipper_format_read_string(ff, "name", signal_name)) { - auto element = records.find(string_get_cstr(signal_name)); - if(element != records.cend()) { - ++element->second.amount; - } - } - string_clear(signal_name); - } - - flipper_format_free(ff); - furi_record_close("storage"); - return result; -} - -void InfraredAppBruteForce::stop_bruteforce() { - furi_assert((current_record.size())); - - if(current_record.size()) { - furi_assert(ff); - current_record.clear(); - flipper_format_free(ff); - furi_record_close("storage"); - } -} - -bool InfraredAppBruteForce::send_next_bruteforce(void) { - furi_assert(current_record.size()); - furi_assert(ff); - - InfraredAppSignal signal; - std::string signal_name; - bool result = false; - do { - result = infrared_parser_read_signal(ff, signal, signal_name); - } while(result && current_record.compare(signal_name)); - - if(result) { - signal.transmit(); - } - return result; -} - -bool InfraredAppBruteForce::start_bruteforce(int index, int& record_amount) { - bool result = false; - record_amount = 0; - - for(const auto& it : records) { - if(it.second.index == index) { - record_amount = it.second.amount; - if(record_amount) { - current_record = it.first; - } - break; - } - } - - if(record_amount) { - Storage* storage = static_cast(furi_record_open("storage")); - ff = flipper_format_file_alloc(storage); - result = flipper_format_file_open_existing(ff, universal_db_filename); - if(!result) { - flipper_format_free(ff); - furi_record_close("storage"); - } - } - - return result; -} diff --git a/applications/infrared/infrared_app_brute_force.h b/applications/infrared/infrared_app_brute_force.h deleted file mode 100644 index 2dd3ade9c111..000000000000 --- a/applications/infrared/infrared_app_brute_force.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file infrared_app_brute_force.h - * Infrared: Brute Force class description - */ -#pragma once - -#include -#include -#include - -/** Class handles brute force mechanic */ -class InfraredAppBruteForce { - /** Universal database filename */ - const char* universal_db_filename; - - /** Current record name (POWER, MUTE, VOL+, etc). - * This is the name of signal to brute force. */ - std::string current_record; - - /** Flipper File Format instance */ - FlipperFormat* ff; - - /** Data about every record - index in button panel view - * and amount of signals, which is need for correct - * progress bar displaying. */ - typedef struct { - /** Index of record in button panel view model */ - int index; - /** Amount of signals of that type (POWER, MUTE, etc) */ - int amount; - } Record; - - /** Container to hold Record info. - * 'key' is record name, because we have to search by both, index and name, - * but index search has place once per button press, and should not be - * noticed, but name search should occur during entering universal menu, - * and will go through container for every record in file, that's why - * more critical to have faster search by record name. - */ - std::unordered_map records; - -public: - /** Calculate messages. Walk through the file ('universal_db_name') - * and calculate amount of records of certain type. */ - bool calculate_messages(); - - /** Start brute force */ - bool start_bruteforce(int index, int& record_amount); - - /** Stop brute force */ - void stop_bruteforce(); - - /** Send next signal during brute force */ - bool send_next_bruteforce(); - - /** Add record to container of records */ - void add_record(int index, const char* name); - - /** Initialize class, set db file */ - InfraredAppBruteForce(const char* filename) - : universal_db_filename(filename) { - } - - /** Deinitialize class */ - ~InfraredAppBruteForce() { - } -}; diff --git a/applications/infrared/infrared_app_event.h b/applications/infrared/infrared_app_event.h deleted file mode 100644 index 168ba0b1cbbf..000000000000 --- a/applications/infrared/infrared_app_event.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file infrared_app_event.h - * Infrared: Scene events description - */ -#pragma once -#include -#include - -/** Infrared events class */ -class InfraredAppEvent { -public: - /** Type of event enum */ - enum class Type : uint8_t { - /** Tick event come after no other events came in 100 ms */ - Tick, - /** Exit application event */ - Exit, - /** Back event */ - Back, - /** Menu selected event type. Provided with payload value. */ - MenuSelected, - /** Button press event. Need for continuous signal sending. */ - MenuSelectedPress, - /** Button release event. Need for continuous signal sending. */ - MenuSelectedRelease, - /** Events from DialogEx view module */ - DialogExSelected, - /** Infrared signal received event */ - InfraredMessageReceived, - /** Text edit done event */ - TextEditDone, - /** Popup timer finished event */ - PopupTimer, - /** Button panel pressed event */ - ButtonPanelPressed, - }; - - union { - int32_t dummy; - /** Menu selected event type payload. Selected index. */ - int32_t menu_index; - /** DialogEx view module event type payload */ - DialogExResult dialog_ex_result; - } payload; - - /** Type of event */ - Type type; -}; diff --git a/applications/infrared/infrared_app_remote_manager.cpp b/applications/infrared/infrared_app_remote_manager.cpp deleted file mode 100644 index faeccb39e532..000000000000 --- a/applications/infrared/infrared_app_remote_manager.cpp +++ /dev/null @@ -1,266 +0,0 @@ -#include "m-string.h" -#include "storage/filesystem_api_defines.h" -#include -#include "infrared_app_remote_manager.h" -#include "infrared/helpers/infrared_parser.h" -#include "infrared/infrared_app_signal.h" - -#include - -#include -#include -#include -#include -#include -#include "infrared_app.h" -#include - -static const char* default_remote_name = "remote"; - -void InfraredAppRemoteManager::find_vacant_remote_name(string_t name, string_t path) { - Storage* storage = static_cast(furi_record_open("storage")); - - string_t base_path; - string_init_set(base_path, path); - - if(string_end_with_str_p(base_path, InfraredApp::infrared_extension)) { - size_t filename_start = string_search_rchar(base_path, '/'); - string_left(base_path, filename_start); - } - - string_printf( - base_path, - "%s/%s%s", - string_get_cstr(path), - string_get_cstr(name), - InfraredApp::infrared_extension); - - FS_Error error = storage_common_stat(storage, string_get_cstr(base_path), NULL); - - if(error == FSE_OK) { - /* if suggested name is occupied, try another one (name2, name3, etc) */ - size_t dot = string_search_rchar(base_path, '.'); - string_left(base_path, dot); - - string_t path_temp; - string_init(path_temp); - - uint32_t i = 1; - do { - string_printf( - path_temp, - "%s%u%s", - string_get_cstr(base_path), - ++i, - InfraredApp::infrared_extension); - error = storage_common_stat(storage, string_get_cstr(path_temp), NULL); - } while(error == FSE_OK); - - string_clear(path_temp); - - if(error == FSE_NOT_EXIST) { - string_cat_printf(name, "%u", i); - } - } - - string_clear(base_path); - furi_record_close("storage"); -} - -bool InfraredAppRemoteManager::add_button(const char* button_name, const InfraredAppSignal& signal) { - remote->buttons.emplace_back(button_name, signal); - return store(); -} - -bool InfraredAppRemoteManager::add_remote_with_button( - const char* button_name, - const InfraredAppSignal& signal) { - furi_check(button_name != nullptr); - - string_t new_name; - string_init_set_str(new_name, default_remote_name); - - string_t new_path; - string_init_set_str(new_path, InfraredApp::infrared_directory); - - find_vacant_remote_name(new_name, new_path); - - string_cat_printf( - new_path, "/%s%s", string_get_cstr(new_name), InfraredApp::infrared_extension); - - remote = std::make_unique(new_path); - remote->name = std::string(string_get_cstr(new_name)); - - string_clear(new_path); - string_clear(new_name); - - return add_button(button_name, signal); -} - -std::vector InfraredAppRemoteManager::get_button_list(void) const { - std::vector name_vector; - name_vector.reserve(remote->buttons.size()); - - for(const auto& it : remote->buttons) { - name_vector.emplace_back(it.name); - } - - // copy elision - return name_vector; -} - -const InfraredAppSignal& InfraredAppRemoteManager::get_button_data(size_t index) const { - furi_check(remote.get() != nullptr); - auto& buttons = remote->buttons; - furi_check(index < buttons.size()); - - return buttons.at(index).signal; -} - -bool InfraredAppRemoteManager::delete_remote() { - Storage* storage = static_cast(furi_record_open("storage")); - - FS_Error error = storage_common_remove(storage, string_get_cstr(remote->path)); - reset_remote(); - - furi_record_close("storage"); - return (error == FSE_OK || error == FSE_NOT_EXIST); -} - -void InfraredAppRemoteManager::reset_remote() { - remote.reset(); -} - -bool InfraredAppRemoteManager::delete_button(uint32_t index) { - furi_check(remote.get() != nullptr); - auto& buttons = remote->buttons; - furi_check(index < buttons.size()); - - buttons.erase(buttons.begin() + index); - return store(); -} - -std::string InfraredAppRemoteManager::get_button_name(uint32_t index) { - furi_check(remote.get() != nullptr); - auto& buttons = remote->buttons; - furi_check(index < buttons.size()); - return buttons[index].name.c_str(); -} - -std::string InfraredAppRemoteManager::get_remote_name() { - return remote.get() ? remote->name : std::string(); -} - -bool InfraredAppRemoteManager::rename_remote(const char* str) { - furi_check(str != nullptr); - furi_check(remote.get() != nullptr); - furi_check(!string_empty_p(remote->path)); - - if(!remote->name.compare(str)) { - return true; - } - - string_t new_name; - string_init_set_str(new_name, str); - find_vacant_remote_name(new_name, remote->path); - - string_t new_path; - string_init_set(new_path, remote->path); - if(string_end_with_str_p(new_path, InfraredApp::infrared_extension)) { - size_t filename_start = string_search_rchar(new_path, '/'); - string_left(new_path, filename_start); - } - string_cat_printf( - new_path, "/%s%s", string_get_cstr(new_name), InfraredApp::infrared_extension); - - Storage* storage = static_cast(furi_record_open("storage")); - - FS_Error error = - storage_common_rename(storage, string_get_cstr(remote->path), string_get_cstr(new_path)); - remote->name = std::string(string_get_cstr(new_name)); - - string_clear(new_name); - string_clear(new_path); - - furi_record_close("storage"); - return (error == FSE_OK || error == FSE_EXIST); -} - -bool InfraredAppRemoteManager::rename_button(uint32_t index, const char* str) { - furi_check(remote.get() != nullptr); - auto& buttons = remote->buttons; - furi_check(index < buttons.size()); - - buttons[index].name = str; - return store(); -} - -size_t InfraredAppRemoteManager::get_number_of_buttons() { - furi_check(remote.get() != nullptr); - return remote->buttons.size(); -} - -bool InfraredAppRemoteManager::store(void) { - bool result = false; - Storage* storage = static_cast(furi_record_open("storage")); - - if(!storage_simply_mkdir(storage, InfraredApp::infrared_directory)) return false; - - FlipperFormat* ff = flipper_format_file_alloc(storage); - - FURI_LOG_I("RemoteManager", "store file: \'%s\'", string_get_cstr(remote->path)); - result = flipper_format_file_open_always(ff, string_get_cstr(remote->path)); - if(result) { - result = flipper_format_write_header_cstr(ff, "IR signals file", 1); - } - if(result) { - for(const auto& button : remote->buttons) { - result = infrared_parser_save_signal(ff, button.signal, button.name.c_str()); - if(!result) { - break; - } - } - } - - flipper_format_free(ff); - furi_record_close("storage"); - return result; -} - -bool InfraredAppRemoteManager::load(string_t path) { - bool result = false; - Storage* storage = static_cast(furi_record_open("storage")); - FlipperFormat* ff = flipper_format_file_alloc(storage); - - FURI_LOG_I("RemoteManager", "load file: \'%s\'", string_get_cstr(path)); - result = flipper_format_file_open_existing(ff, string_get_cstr(path)); - if(result) { - string_t header; - string_init(header); - uint32_t version; - result = flipper_format_read_header(ff, header, &version); - if(result) { - result = !string_cmp_str(header, "IR signals file") && (version == 1); - } - string_clear(header); - } - if(result) { - string_t new_name; - string_init(new_name); - - remote = std::make_unique(path); - path_extract_filename(path, new_name, true); - remote->name = std::string(string_get_cstr(new_name)); - - string_clear(new_name); - InfraredAppSignal signal; - std::string signal_name; - while(infrared_parser_read_signal(ff, signal, signal_name)) { - remote->buttons.emplace_back(signal_name.c_str(), std::move(signal)); - } - } - - flipper_format_free(ff); - furi_record_close("storage"); - return result; -} diff --git a/applications/infrared/infrared_app_remote_manager.h b/applications/infrared/infrared_app_remote_manager.h deleted file mode 100644 index b6f0b170f99f..000000000000 --- a/applications/infrared/infrared_app_remote_manager.h +++ /dev/null @@ -1,189 +0,0 @@ -/** - * @file infrared_app_remote_manager.h - * Infrared: Remote manager class. - * It holds remote, can load/save/rename remote, - * add/remove/rename buttons. - */ -#pragma once - -#include "infrared_app_signal.h" - -#include "m-string.h" -#include -#include - -#include -#include -#include -#include - -/** Class to handle remote button */ -class InfraredAppRemoteButton { - /** Allow field access */ - friend class InfraredAppRemoteManager; - /** Name of signal */ - std::string name; - /** Signal data */ - InfraredAppSignal signal; - -public: - /** Initialize remote button - * - * @param name - button name - * @param signal - signal to copy for remote button - */ - InfraredAppRemoteButton(const char* name, const InfraredAppSignal& signal) - : name(name) - , signal(signal) { - } - - /** Initialize remote button - * - * @param name - button name - * @param signal - signal to move for remote button - */ - InfraredAppRemoteButton(const char* name, InfraredAppSignal&& signal) - : name(name) - , signal(std::move(signal)) { - } - - /** Deinitialize remote button */ - ~InfraredAppRemoteButton() { - } -}; - -/** Class to handle remote */ -class InfraredAppRemote { - /** Allow field access */ - friend class InfraredAppRemoteManager; - /** Button container */ - std::vector buttons; - /** Name of remote */ - std::string name; - /** Path to remote file */ - string_t path; - -public: - /** Initialize new remote - * - * @param path - remote file path - */ - InfraredAppRemote(string_t file_path) { - string_init_set(path, file_path); - } - - ~InfraredAppRemote() { - string_clear(path); - } -}; - -/** Class to handle remote manager */ -class InfraredAppRemoteManager { - /** Remote instance. There can be 1 remote loaded at a time. */ - std::unique_ptr remote; - -public: - /** Restriction to button name length. Buttons larger are ignored. */ - static constexpr const uint32_t max_button_name_length = 22; - - /** Restriction to remote name length. Remotes larger are ignored. */ - static constexpr const uint32_t max_remote_name_length = 22; - - /** Construct button from signal, and create remote - * - * @param button_name - name of button to create - * @param signal - signal to create button from - * @retval true for success, false otherwise - * */ - bool add_remote_with_button(const char* button_name, const InfraredAppSignal& signal); - - /** Add button to current remote - * - * @param button_name - name of button to create - * @param signal - signal to create button from - * @retval true for success, false otherwise - * */ - bool add_button(const char* button_name, const InfraredAppSignal& signal); - - /** Rename button in current remote - * - * @param index - index of button to rename - * @param str - new button name - */ - bool rename_button(uint32_t index, const char* str); - - /** Rename current remote - * - * @param str - new remote name - */ - bool rename_remote(const char* str); - - /** Find vacant remote name. If suggested name is occupied, - * incremented digit(2,3,4,etc) added to name and check repeated. - * - * @param name - suggested remote name - * @param path - remote file path - */ - void find_vacant_remote_name(string_t name, string_t path); - - /** Get button list - * - * @retval container of button names - */ - std::vector get_button_list() const; - - /** Get button name by index - * - * @param index - index of button to get name from - * @retval button name - */ - std::string get_button_name(uint32_t index); - - /** Get remote name - * - * @retval remote name - */ - std::string get_remote_name(); - - /** Get number of buttons - * - * @retval number of buttons - */ - size_t get_number_of_buttons(); - - /** Get button's signal - * - * @param index - index of interested button - * @retval signal - */ - const InfraredAppSignal& get_button_data(size_t index) const; - - /** Delete button - * - * @param index - index of interested button - * @retval true if success, false otherwise - */ - bool delete_button(uint32_t index); - - /** Delete remote - * - * @retval true if success, false otherwise - */ - bool delete_remote(); - - /** Clean all loaded info in current remote */ - void reset_remote(); - - /** Store current remote data on disk - * - * @retval true if success, false otherwise - */ - bool store(); - - /** Load data from disk into current remote - * - * @param path - path to remote file - * @retval true if success, false otherwise - */ - bool load(string_t path); -}; diff --git a/applications/infrared/infrared_app_signal.cpp b/applications/infrared/infrared_app_signal.cpp deleted file mode 100644 index 3344b3ca4531..000000000000 --- a/applications/infrared/infrared_app_signal.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "infrared_app_signal.h" -#include - -void InfraredAppSignal::copy_raw_signal( - const uint32_t* timings, - size_t size, - uint32_t frequency, - float duty_cycle) { - furi_assert(size); - furi_assert(timings); - - payload.raw.frequency = frequency; - payload.raw.duty_cycle = duty_cycle; - payload.raw.timings_cnt = size; - if(size) { - payload.raw.timings = new uint32_t[size]; - memcpy(payload.raw.timings, timings, size * sizeof(uint32_t)); - } -} - -void InfraredAppSignal::clear_timings() { - if(raw_signal) { - delete[] payload.raw.timings; - payload.raw.timings_cnt = 0; - payload.raw.timings = nullptr; - } -} - -InfraredAppSignal::InfraredAppSignal( - const uint32_t* timings, - size_t timings_cnt, - uint32_t frequency, - float duty_cycle) { - raw_signal = true; - copy_raw_signal(timings, timings_cnt, frequency, duty_cycle); -} - -InfraredAppSignal::InfraredAppSignal(const InfraredMessage* infrared_message) { - raw_signal = false; - payload.message = *infrared_message; -} - -InfraredAppSignal& InfraredAppSignal::operator=(const InfraredAppSignal& other) { - clear_timings(); - raw_signal = other.raw_signal; - if(!raw_signal) { - payload.message = other.payload.message; - } else { - copy_raw_signal( - other.payload.raw.timings, - other.payload.raw.timings_cnt, - other.payload.raw.frequency, - other.payload.raw.duty_cycle); - } - - return *this; -} - -InfraredAppSignal::InfraredAppSignal(const InfraredAppSignal& other) { - raw_signal = other.raw_signal; - if(!raw_signal) { - payload.message = other.payload.message; - } else { - copy_raw_signal( - other.payload.raw.timings, - other.payload.raw.timings_cnt, - other.payload.raw.frequency, - other.payload.raw.duty_cycle); - } -} - -InfraredAppSignal::InfraredAppSignal(InfraredAppSignal&& other) { - raw_signal = other.raw_signal; - if(!raw_signal) { - payload.message = other.payload.message; - } else { - furi_assert(other.payload.raw.timings_cnt > 0); - - payload.raw.timings = other.payload.raw.timings; - payload.raw.timings_cnt = other.payload.raw.timings_cnt; - payload.raw.frequency = other.payload.raw.frequency; - payload.raw.duty_cycle = other.payload.raw.duty_cycle; - other.payload.raw.timings = nullptr; - other.payload.raw.timings_cnt = 0; - other.raw_signal = false; - } -} - -void InfraredAppSignal::set_message(const InfraredMessage* infrared_message) { - clear_timings(); - raw_signal = false; - payload.message = *infrared_message; -} - -void InfraredAppSignal::set_raw_signal( - uint32_t* timings, - size_t timings_cnt, - uint32_t frequency, - float duty_cycle) { - clear_timings(); - raw_signal = true; - copy_raw_signal(timings, timings_cnt, frequency, duty_cycle); -} - -void InfraredAppSignal::transmit() const { - if(!raw_signal) { - infrared_send(&payload.message, 1); - } else { - infrared_send_raw_ext( - payload.raw.timings, - payload.raw.timings_cnt, - true, - payload.raw.frequency, - payload.raw.duty_cycle); - } -} diff --git a/applications/infrared/infrared_app_signal.h b/applications/infrared/infrared_app_signal.h deleted file mode 100644 index 7b0b491b131f..000000000000 --- a/applications/infrared/infrared_app_signal.h +++ /dev/null @@ -1,134 +0,0 @@ -/** - * @file infrared_app_signal.h - * Infrared: Signal class - */ -#pragma once -#include -#include -#include -#include - -/** Infrared application signal class */ -class InfraredAppSignal { -public: - /** Raw signal structure */ - typedef struct { - /** Timings amount */ - size_t timings_cnt; - /** Samples of raw signal in ms */ - uint32_t* timings; - /** PWM Frequency of raw signal */ - uint32_t frequency; - /** PWM Duty cycle of raw signal */ - float duty_cycle; - } RawSignal; - -private: - /** if true - signal is raw, if false - signal is parsed */ - bool raw_signal; - /** signal data, either raw or parsed */ - union { - /** signal data for parsed signal */ - InfraredMessage message; - /** raw signal data */ - RawSignal raw; - } payload; - - /** Copy raw signal into object - * - * @param timings - timings (samples) of raw signal - * @param size - number of timings - * @frequency - PWM frequency of raw signal - * @duty_cycle - PWM duty cycle - */ - void - copy_raw_signal(const uint32_t* timings, size_t size, uint32_t frequency, float duty_cycle); - /** Clear and free timings data */ - void clear_timings(); - -public: - /** Construct Infrared signal class */ - InfraredAppSignal() { - raw_signal = false; - payload.message.protocol = InfraredProtocolUnknown; - } - - /** Destruct signal class and free all allocated data */ - ~InfraredAppSignal() { - clear_timings(); - } - - /** Construct object with raw signal - * - * @param timings - timings (samples) of raw signal - * @param size - number of timings - * @frequency - PWM frequency of raw signal - * @duty_cycle - PWM duty cycle - */ - InfraredAppSignal( - const uint32_t* timings, - size_t timings_cnt, - uint32_t frequency, - float duty_cycle); - - /** Construct object with parsed signal - * - * @param infrared_message - parsed_signal to construct from - */ - InfraredAppSignal(const InfraredMessage* infrared_message); - - /** Copy constructor */ - InfraredAppSignal(const InfraredAppSignal& other); - /** Move constructor */ - InfraredAppSignal(InfraredAppSignal&& other); - - /** Assignment operator */ - InfraredAppSignal& operator=(const InfraredAppSignal& signal); - - /** Set object to parsed signal - * - * @param infrared_message - parsed_signal to construct from - */ - void set_message(const InfraredMessage* infrared_message); - - /** Set object to raw signal - * - * @param timings - timings (samples) of raw signal - * @param size - number of timings - * @frequency - PWM frequency of raw signal - * @duty_cycle - PWM duty cycle - */ - void - set_raw_signal(uint32_t* timings, size_t timings_cnt, uint32_t frequency, float duty_cycle); - - /** Transmit held signal (???) */ - void transmit() const; - - /** Show is held signal raw - * - * @retval true if signal is raw, false if signal is parsed - */ - bool is_raw(void) const { - return raw_signal; - } - - /** Get parsed signal. - * User must check is_raw() signal before calling this function. - * - * @retval parsed signal pointer - */ - const InfraredMessage& get_message(void) const { - furi_assert(!raw_signal); - return payload.message; - } - - /** Get raw signal. - * User must check is_raw() signal before calling this function. - * - * @retval raw signal - */ - const RawSignal& get_raw_signal(void) const { - furi_assert(raw_signal); - return payload.raw; - } -}; diff --git a/applications/infrared/infrared_app_view_manager.cpp b/applications/infrared/infrared_app_view_manager.cpp deleted file mode 100644 index f1e48ed4aba9..000000000000 --- a/applications/infrared/infrared_app_view_manager.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "infrared/infrared_app_view_manager.h" -#include "infrared/view/infrared_progress_view.h" -#include "infrared_app.h" -#include "infrared/infrared_app_event.h" - -InfraredAppViewManager::InfraredAppViewManager() { - event_queue = osMessageQueueNew(10, sizeof(InfraredAppEvent), NULL); - - view_dispatcher = view_dispatcher_alloc(); - auto callback = cbc::obtain_connector(this, &InfraredAppViewManager::previous_view_callback); - - gui = static_cast(furi_record_open("gui")); - view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); - - button_menu = button_menu_alloc(); - submenu = submenu_alloc(); - popup = popup_alloc(); - dialog_ex = dialog_ex_alloc(); - text_input = text_input_alloc(); - button_panel = button_panel_alloc(); - progress_view = infrared_progress_view_alloc(); - loading_view = loading_alloc(); - universal_view_stack = view_stack_alloc(); - view_stack_add_view(universal_view_stack, button_panel_get_view(button_panel)); - view_set_orientation(view_stack_get_view(universal_view_stack), ViewOrientationVertical); - - add_view(ViewId::UniversalRemote, view_stack_get_view(universal_view_stack)); - add_view(ViewId::ButtonMenu, button_menu_get_view(button_menu)); - add_view(ViewId::Submenu, submenu_get_view(submenu)); - add_view(ViewId::Popup, popup_get_view(popup)); - add_view(ViewId::DialogEx, dialog_ex_get_view(dialog_ex)); - add_view(ViewId::TextInput, text_input_get_view(text_input)); - - view_set_previous_callback(view_stack_get_view(universal_view_stack), callback); - view_set_previous_callback(button_menu_get_view(button_menu), callback); - view_set_previous_callback(submenu_get_view(submenu), callback); - view_set_previous_callback(popup_get_view(popup), callback); - view_set_previous_callback(dialog_ex_get_view(dialog_ex), callback); - view_set_previous_callback(text_input_get_view(text_input), callback); -} - -InfraredAppViewManager::~InfraredAppViewManager() { - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::UniversalRemote)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::ButtonMenu)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::TextInput)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::DialogEx)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::Submenu)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(InfraredAppViewManager::ViewId::Popup)); - - view_stack_remove_view(universal_view_stack, button_panel_get_view(button_panel)); - view_stack_free(universal_view_stack); - button_panel_free(button_panel); - submenu_free(submenu); - popup_free(popup); - button_menu_free(button_menu); - dialog_ex_free(dialog_ex); - text_input_free(text_input); - infrared_progress_view_free(progress_view); - loading_free(loading_view); - - view_dispatcher_free(view_dispatcher); - furi_record_close("gui"); - osMessageQueueDelete(event_queue); -} - -void InfraredAppViewManager::switch_to(ViewId type) { - view_dispatcher_switch_to_view(view_dispatcher, static_cast(type)); -} - -TextInput* InfraredAppViewManager::get_text_input() { - return text_input; -} - -DialogEx* InfraredAppViewManager::get_dialog_ex() { - return dialog_ex; -} - -Submenu* InfraredAppViewManager::get_submenu() { - return submenu; -} - -Popup* InfraredAppViewManager::get_popup() { - return popup; -} - -ButtonMenu* InfraredAppViewManager::get_button_menu() { - return button_menu; -} - -ButtonPanel* InfraredAppViewManager::get_button_panel() { - return button_panel; -} - -InfraredProgressView* InfraredAppViewManager::get_progress() { - return progress_view; -} - -Loading* InfraredAppViewManager::get_loading() { - return loading_view; -} - -ViewStack* InfraredAppViewManager::get_universal_view_stack() { - return universal_view_stack; -} - -osMessageQueueId_t InfraredAppViewManager::get_event_queue() { - return event_queue; -} - -void InfraredAppViewManager::clear_events() { - InfraredAppEvent event; - while(osMessageQueueGet(event_queue, &event, NULL, 0) == osOK) - ; -} - -void InfraredAppViewManager::receive_event(InfraredAppEvent* event) { - if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) { - event->type = InfraredAppEvent::Type::Tick; - } -} - -void InfraredAppViewManager::send_event(InfraredAppEvent* event) { - uint32_t timeout = 0; - /* Rapid button hammering on signal send scenes causes queue overflow - ignore it, - * but try to keep button release event - it switches off INFRARED DMA sending. */ - if(event->type == InfraredAppEvent::Type::MenuSelectedRelease) { - timeout = 200; - } - if((event->type == InfraredAppEvent::Type::DialogExSelected) && - (event->payload.dialog_ex_result == DialogExReleaseCenter)) { - timeout = 200; - } - - osMessageQueuePut(event_queue, event, 0, timeout); -} - -uint32_t InfraredAppViewManager::previous_view_callback(void*) { - if(event_queue != NULL) { - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::Back; - send_event(&event); - } - - return VIEW_IGNORE; -} - -void InfraredAppViewManager::add_view(ViewId view_type, View* view) { - view_dispatcher_add_view(view_dispatcher, static_cast(view_type), view); -} diff --git a/applications/infrared/infrared_app_view_manager.h b/applications/infrared/infrared_app_view_manager.h deleted file mode 100644 index 106d2660e989..000000000000 --- a/applications/infrared/infrared_app_view_manager.h +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @file infrared_app_view_manager.h - * Infrared: Scene events description - */ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "infrared_app_event.h" -#include "view/infrared_progress_view.h" - -/** Infrared View manager class */ -class InfraredAppViewManager { -public: - /** Infrared View Id enum, it is used - * to identify added views */ - enum class ViewId : uint8_t { - DialogEx, - TextInput, - Submenu, - ButtonMenu, - UniversalRemote, - Popup, - }; - - /** Class constructor */ - InfraredAppViewManager(); - /** Class destructor */ - ~InfraredAppViewManager(); - - /** Switch to another view - * - * @param id - view id to switch to - */ - void switch_to(ViewId id); - - /** Receive event from queue - * - * @param event - received event - */ - void receive_event(InfraredAppEvent* event); - - /** Send event to queue - * - * @param event - event to send - */ - void send_event(InfraredAppEvent* event); - - /** Clear events that already in queue - * - * @param event - event to send - */ - void clear_events(); - - /** Get dialog_ex view module - * - * @retval dialog_ex view module - */ - DialogEx* get_dialog_ex(); - - /** Get submenu view module - * - * @retval submenu view module - */ - Submenu* get_submenu(); - - /** Get popup view module - * - * @retval popup view module - */ - Popup* get_popup(); - - /** Get text_input view module - * - * @retval text_input view module - */ - TextInput* get_text_input(); - - /** Get button_menu view module - * - * @retval button_menu view module - */ - ButtonMenu* get_button_menu(); - - /** Get button_panel view module - * - * @retval button_panel view module - */ - ButtonPanel* get_button_panel(); - - /** Get view_stack view module used in universal remote - * - * @retval view_stack view module - */ - ViewStack* get_universal_view_stack(); - - /** Get progress view module - * - * @retval progress view module - */ - InfraredProgressView* get_progress(); - - /** Get loading view module - * - * @retval loading view module - */ - Loading* get_loading(); - - /** Get event queue - * - * @retval event queue - */ - osMessageQueueId_t get_event_queue(); - - /** Callback to handle back button - * - * @param context - context to pass to callback - * @retval always returns VIEW_IGNORE - */ - uint32_t previous_view_callback(void* context); - -private: - /** View Dispatcher instance. - * It handles view switching */ - ViewDispatcher* view_dispatcher; - /** Gui instance */ - Gui* gui; - /** Text input view module instance */ - TextInput* text_input; - /** DialogEx view module instance */ - DialogEx* dialog_ex; - /** Submenu view module instance */ - Submenu* submenu; - /** Popup view module instance */ - Popup* popup; - /** ButtonMenu view module instance */ - ButtonMenu* button_menu; - /** ButtonPanel view module instance */ - ButtonPanel* button_panel; - /** ViewStack view module instance */ - ViewStack* universal_view_stack; - /** ProgressView view module instance */ - InfraredProgressView* progress_view; - /** Loading view module instance */ - Loading* loading_view; - - /** Queue to handle events, which are processed in scenes */ - osMessageQueueId_t event_queue; - - /** Add View to pull of views - * - * @param view_id - id to identify view - * @param view - view to add - */ - void add_view(ViewId view_id, View* view); -}; diff --git a/applications/infrared/infrared_brute_force.c b/applications/infrared/infrared_brute_force.c new file mode 100644 index 000000000000..872a76376420 --- /dev/null +++ b/applications/infrared/infrared_brute_force.c @@ -0,0 +1,153 @@ +#include "infrared_brute_force.h" + +#include +#include +#include +#include + +#include "infrared_signal.h" + +typedef struct { + uint32_t index; + uint32_t count; +} InfraredBruteForceRecord; + +DICT_DEF2( + InfraredBruteForceRecordDict, + string_t, + STRING_OPLIST, + InfraredBruteForceRecord, + M_POD_OPLIST); + +struct InfraredBruteForce { + FlipperFormat* ff; + const char* db_filename; + string_t current_record_name; + InfraredBruteForceRecordDict_t records; +}; + +InfraredBruteForce* infrared_brute_force_alloc() { + InfraredBruteForce* brute_force = malloc(sizeof(InfraredBruteForce)); + brute_force->ff = NULL; + brute_force->db_filename = NULL; + string_init(brute_force->current_record_name); + InfraredBruteForceRecordDict_init(brute_force->records); + return brute_force; +} + +void infrared_brute_force_free(InfraredBruteForce* brute_force) { + furi_assert(!brute_force->ff); + InfraredBruteForceRecordDict_clear(brute_force->records); + string_clear(brute_force->current_record_name); + free(brute_force); +} + +void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename) { + brute_force->db_filename = db_filename; +} + +bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) { + furi_assert(brute_force->db_filename); + bool success = false; + + Storage* storage = furi_record_open("storage"); + FlipperFormat* ff = flipper_format_file_alloc(storage); + + success = flipper_format_file_open_existing(ff, brute_force->db_filename); + if(success) { + string_t signal_name; + string_init(signal_name); + while(flipper_format_read_string(ff, "name", signal_name)) { + InfraredBruteForceRecord* record = + InfraredBruteForceRecordDict_get(brute_force->records, signal_name); + if(record) { + ++(record->count); + } + } + string_clear(signal_name); + } + + flipper_format_free(ff); + furi_record_close("storage"); + return success; +} + +bool infrared_brute_force_start( + InfraredBruteForce* brute_force, + uint32_t index, + uint32_t* record_count) { + bool success = false; + *record_count = 0; + + InfraredBruteForceRecordDict_it_t it; + for(InfraredBruteForceRecordDict_it(it, brute_force->records); + !InfraredBruteForceRecordDict_end_p(it); + InfraredBruteForceRecordDict_next(it)) { + const InfraredBruteForceRecordDict_itref_t* record = InfraredBruteForceRecordDict_cref(it); + if(record->value.index == index) { + *record_count = record->value.count; + if(*record_count) { + string_set(brute_force->current_record_name, record->key); + } + break; + } + } + + if(*record_count) { + Storage* storage = furi_record_open("storage"); + brute_force->ff = flipper_format_file_alloc(storage); + success = flipper_format_file_open_existing(brute_force->ff, brute_force->db_filename); + if(!success) { + flipper_format_free(brute_force->ff); + furi_record_close("storage"); + } + } + return success; +} + +bool infrared_brute_force_is_started(InfraredBruteForce* brute_force) { + return brute_force->ff; +} + +void infrared_brute_force_stop(InfraredBruteForce* brute_force) { + furi_assert(string_size(brute_force->current_record_name)); + furi_assert(brute_force->ff); + + string_reset(brute_force->current_record_name); + flipper_format_free(brute_force->ff); + furi_record_close("storage"); + brute_force->ff = NULL; +} + +bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) { + furi_assert(string_size(brute_force->current_record_name)); + furi_assert(brute_force->ff); + bool success = false; + + string_t signal_name; + string_init(signal_name); + InfraredSignal* signal = infrared_signal_alloc(); + + do { + success = infrared_signal_read(signal, brute_force->ff, signal_name); + } while(success && !string_equal_p(brute_force->current_record_name, signal_name)); + + if(success) { + infrared_signal_transmit(signal); + } + + infrared_signal_free(signal); + string_clear(signal_name); + return success; +} + +void infrared_brute_force_add_record( + InfraredBruteForce* brute_force, + uint32_t index, + const char* name) { + InfraredBruteForceRecord value = {.index = index, .count = 0}; + string_t key; + string_init_set_str(key, name); + InfraredBruteForceRecordDict_set_at(brute_force->records, key, value); + string_clear(key); +} diff --git a/applications/infrared/infrared_brute_force.h b/applications/infrared/infrared_brute_force.h new file mode 100644 index 000000000000..acf0d7b6e123 --- /dev/null +++ b/applications/infrared/infrared_brute_force.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +typedef struct InfraredBruteForce InfraredBruteForce; + +InfraredBruteForce* infrared_brute_force_alloc(); +void infrared_brute_force_free(InfraredBruteForce* brute_force); +void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename); +bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force); +bool infrared_brute_force_start( + InfraredBruteForce* brute_force, + uint32_t index, + uint32_t* record_count); +bool infrared_brute_force_is_started(InfraredBruteForce* brute_force); +void infrared_brute_force_stop(InfraredBruteForce* brute_force); +bool infrared_brute_force_send_next(InfraredBruteForce* brute_force); +void infrared_brute_force_add_record( + InfraredBruteForce* brute_force, + uint32_t index, + const char* name); diff --git a/applications/infrared/cli/infrared_cli.cpp b/applications/infrared/infrared_cli.c similarity index 72% rename from applications/infrared/cli/infrared_cli.cpp rename to applications/infrared/infrared_cli.c index 79ab987dd45c..1b3ec4b31672 100644 --- a/applications/infrared/cli/infrared_cli.cpp +++ b/applications/infrared/infrared_cli.c @@ -1,16 +1,12 @@ -#include -#include +#include #include -#include +#include #include -#include #include -#include -#include -#include -#include -#include -#include "../helpers/infrared_parser.h" + +#include "infrared_signal.h" + +#define INFRARED_CLI_BUF_SIZE 10 static void infrared_cli_start_ir_rx(Cli* cli, string_t args); static void infrared_cli_start_ir_tx(Cli* cli, string_t args); @@ -92,79 +88,83 @@ static void infrared_cli_print_usage(void) { INFRARED_MAX_FREQUENCY); } -static bool parse_message(const char* str, InfraredMessage* message) { +static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) { char protocol_name[32]; - int parsed = sscanf(str, "%31s %lX %lX", protocol_name, &message->address, &message->command); + InfraredMessage message; + int parsed = sscanf(str, "%31s %lX %lX", protocol_name, &message.address, &message.command); if(parsed != 3) { return false; } - message->protocol = infrared_get_protocol_by_name(protocol_name); - message->repeat = false; - - return infrared_parser_is_parsed_signal_valid(message); + message.repeat = false; + infrared_signal_set_message(signal, &message); + return infrared_signal_is_valid(signal); } -static bool parse_signal_raw( - const char* str, - uint32_t* timings, - uint32_t* timings_cnt, - float* duty_cycle, - uint32_t* frequency) { - char frequency_str[10]; - char duty_cycle_str[10]; +static bool infrared_cli_parse_raw(const char* str, InfraredSignal* signal) { + char frequency_str[INFRARED_CLI_BUF_SIZE]; + char duty_cycle_str[INFRARED_CLI_BUF_SIZE]; int parsed = sscanf(str, "RAW F:%9s DC:%9s", frequency_str, duty_cycle_str); - if(parsed != 2) return false; - *frequency = atoi(frequency_str); - *duty_cycle = (float)atoi(duty_cycle_str) / 100; - str += strlen(frequency_str) + strlen(duty_cycle_str) + 10; + if(parsed != 2) { + return false; + } + + uint32_t* timings = malloc(sizeof(uint32_t) * MAX_TIMINGS_AMOUNT); + uint32_t frequency = atoi(frequency_str); + float duty_cycle = (float)atoi(duty_cycle_str) / 100; - uint32_t timings_cnt_max = *timings_cnt; - *timings_cnt = 0; + str += strlen(frequency_str) + strlen(duty_cycle_str) + INFRARED_CLI_BUF_SIZE; + size_t timings_size = 0; while(1) { - char timing_str[10]; - for(; *str == ' '; ++str) - ; - if(1 != sscanf(str, "%9s", timing_str)) break; + while(*str == ' ') { + ++str; + } + + char timing_str[INFRARED_CLI_BUF_SIZE]; + if(sscanf(str, "%9s", timing_str) != 1) { + break; + } + str += strlen(timing_str); uint32_t timing = atoi(timing_str); - if(timing <= 0) break; - if(*timings_cnt >= timings_cnt_max) break; - timings[*timings_cnt] = timing; - ++*timings_cnt; + + if((timing <= 0) || (timings_size >= MAX_TIMINGS_AMOUNT)) { + break; + } + + timings[timings_size] = timing; + ++timings_size; } - return infrared_parser_is_raw_signal_valid(*frequency, *duty_cycle, *timings_cnt); + infrared_signal_set_raw_signal(signal, timings, timings_size, frequency, duty_cycle); + free(timings); + + return infrared_signal_is_valid(signal); } static void infrared_cli_start_ir_tx(Cli* cli, string_t args) { UNUSED(cli); - InfraredMessage message; const char* str = string_get_cstr(args); - uint32_t frequency; - float duty_cycle; - uint32_t timings_cnt = MAX_TIMINGS_AMOUNT; - uint32_t* timings = (uint32_t*)malloc(sizeof(uint32_t) * timings_cnt); - - if(parse_message(str, &message)) { - infrared_send(&message, 1); - } else if(parse_signal_raw(str, timings, &timings_cnt, &duty_cycle, &frequency)) { - infrared_send_raw_ext(timings, timings_cnt, true, frequency, duty_cycle); + InfraredSignal* signal = infrared_signal_alloc(); + + bool success = infrared_cli_parse_message(str, signal) || infrared_cli_parse_raw(str, signal); + if(success) { + infrared_signal_transmit(signal); } else { printf("Wrong arguments.\r\n"); infrared_cli_print_usage(); } - free(timings); + infrared_signal_free(signal); } static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { UNUSED(context); if(furi_hal_infrared_is_busy()) { - printf("INFRARED is busy. Exit."); + printf("INFRARED is busy. Exiting."); return; } @@ -189,8 +189,7 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) { infrared_cli_print_usage(); } } - -extern "C" void infrared_on_system_start() { +void infrared_on_system_start() { #ifdef SRV_CLI Cli* cli = (Cli*)furi_record_open("cli"); cli_add_command(cli, "ir", CliCommandFlagDefault, infrared_cli_start_ir, NULL); diff --git a/applications/infrared/infrared_custom_event.h b/applications/infrared/infrared_custom_event.h new file mode 100644 index 000000000000..d991afb9c1a8 --- /dev/null +++ b/applications/infrared/infrared_custom_event.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +enum InfraredCustomEventType { + // Reserve first 100 events for button types and indexes, starting from 0 + InfraredCustomEventTypeReserved = 100, + InfraredCustomEventTypeMenuSelected, + InfraredCustomEventTypeTransmitStarted, + InfraredCustomEventTypeTransmitStopped, + InfraredCustomEventTypeSignalReceived, + InfraredCustomEventTypeTextEditDone, + InfraredCustomEventTypePopupTimeout, + InfraredCustomEventTypeButtonSelected, + InfraredCustomEventTypeBackPressed, +}; + +#pragma pack(push, 1) +typedef union { + uint32_t packed_value; + struct { + uint16_t type; + int16_t value; + } content; +} InfraredCustomEvent; +#pragma pack(pop) + +static inline uint32_t infrared_custom_event_pack(uint16_t type, int16_t value) { + InfraredCustomEvent event = {.content = {.type = type, .value = value}}; + return event.packed_value; +} + +static inline void + infrared_custom_event_unpack(uint32_t packed_value, uint16_t* type, int16_t* value) { + InfraredCustomEvent event = {.packed_value = packed_value}; + if(type) *type = event.content.type; + if(value) *value = event.content.value; +} + +static inline uint16_t infrared_custom_event_get_type(uint32_t packed_value) { + uint16_t type; + infrared_custom_event_unpack(packed_value, &type, NULL); + return type; +} + +static inline int16_t infrared_custom_event_get_value(uint32_t packed_value) { + int16_t value; + infrared_custom_event_unpack(packed_value, NULL, &value); + return value; +} diff --git a/applications/infrared/infrared_i.h b/applications/infrared/infrared_i.h new file mode 100644 index 000000000000..06c6a5f7ea3a --- /dev/null +++ b/applications/infrared/infrared_i.h @@ -0,0 +1,132 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include "infrared.h" +#include "infrared_remote.h" +#include "infrared_brute_force.h" +#include "infrared_custom_event.h" + +#include "scenes/infrared_scene.h" +#include "views/infrared_progress_view.h" +#include "views/infrared_debug_view.h" + +#define INFRARED_FILE_NAME_SIZE 100 +#define INFRARED_TEXT_STORE_NUM 2 +#define INFRARED_TEXT_STORE_SIZE 128 + +#define INFRARED_MAX_BUTTON_NAME_LENGTH 22 +#define INFRARED_MAX_REMOTE_NAME_LENGTH 22 + +#define INFRARED_APP_FOLDER "/any/infrared" +#define INFRARED_APP_EXTENSION ".ir" + +#define INFRARED_DEFAULT_REMOTE_NAME "Remote" + +typedef enum { + InfraredButtonIndexNone = -1, +} InfraredButtonIndex; + +typedef enum { + InfraredEditTargetNone, + InfraredEditTargetRemote, + InfraredEditTargetButton, +} InfraredEditTarget; + +typedef enum { + InfraredEditModeNone, + InfraredEditModeRename, + InfraredEditModeDelete, +} InfraredEditMode; + +typedef struct { + bool is_learning_new_remote; + bool is_debug_enabled; + InfraredEditTarget edit_target : 8; + InfraredEditMode edit_mode : 8; + int32_t current_button_index; +} InfraredAppState; + +struct Infrared { + SceneManager* scene_manager; + ViewDispatcher* view_dispatcher; + + Gui* gui; + Storage* storage; + DialogsApp* dialogs; + NotificationApp* notifications; + InfraredWorker* worker; + InfraredRemote* remote; + InfraredSignal* received_signal; + InfraredBruteForce* brute_force; + + Submenu* submenu; + TextInput* text_input; + DialogEx* dialog_ex; + ButtonMenu* button_menu; + Popup* popup; + + ViewStack* view_stack; + InfraredDebugView* debug_view; + + ButtonPanel* button_panel; + Loading* loading; + InfraredProgressView* progress; + + string_t file_path; + char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1]; + InfraredAppState app_state; +}; + +typedef enum { + InfraredViewSubmenu, + InfraredViewTextInput, + InfraredViewDialogEx, + InfraredViewButtonMenu, + InfraredViewPopup, + InfraredViewStack, + InfraredViewDebugView, +} InfraredView; + +typedef enum { + InfraredNotificationMessageSuccess, + InfraredNotificationMessageGreenOn, + InfraredNotificationMessageGreenOff, + InfraredNotificationMessageBlinkRead, + InfraredNotificationMessageBlinkSend, +} InfraredNotificationMessage; + +bool infrared_add_remote_with_button(Infrared* infrared, const char* name, InfraredSignal* signal); +bool infrared_rename_current_remote(Infrared* infrared, const char* name); +void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal); +void infrared_tx_start_button_index(Infrared* infrared, size_t button_index); +void infrared_tx_start_received(Infrared* infrared); +void infrared_tx_stop(Infrared* infrared); +void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...); +void infrared_text_store_clear(Infrared* infrared, uint32_t bank); +void infrared_play_notification_message(Infrared* infrared, uint32_t message); +void infrared_show_loading_popup(Infrared* infrared, bool show); + +void infrared_signal_sent_callback(void* context); +void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal); +void infrared_text_input_callback(void* context); +void infrared_popup_timeout_callback(void* context); diff --git a/applications/infrared/infrared_remote.c b/applications/infrared/infrared_remote.c new file mode 100644 index 000000000000..ad75efe7fabf --- /dev/null +++ b/applications/infrared/infrared_remote.c @@ -0,0 +1,176 @@ +#include "infrared_remote.h" + +#include +#include +#include +#include +#include +#include + +#define TAG "InfraredRemote" + +ARRAY_DEF(InfraredButtonArray, InfraredRemoteButton*, M_PTR_OPLIST); + +struct InfraredRemote { + InfraredButtonArray_t buttons; + string_t name; + string_t path; +}; + +static void infrared_remote_clear_buttons(InfraredRemote* remote) { + InfraredButtonArray_it_t it; + for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it); + InfraredButtonArray_next(it)) { + infrared_remote_button_free(*InfraredButtonArray_cref(it)); + } + InfraredButtonArray_reset(remote->buttons); +} + +InfraredRemote* infrared_remote_alloc() { + InfraredRemote* remote = malloc(sizeof(InfraredRemote)); + InfraredButtonArray_init(remote->buttons); + string_init(remote->name); + string_init(remote->path); + return remote; +} + +void infrared_remote_free(InfraredRemote* remote) { + infrared_remote_clear_buttons(remote); + InfraredButtonArray_clear(remote->buttons); + string_clear(remote->path); + string_clear(remote->name); + free(remote); +} + +void infrared_remote_reset(InfraredRemote* remote) { + infrared_remote_clear_buttons(remote); + string_reset(remote->name); + string_reset(remote->path); +} + +void infrared_remote_set_name(InfraredRemote* remote, const char* name) { + string_set_str(remote->name, name); +} + +const char* infrared_remote_get_name(InfraredRemote* remote) { + return string_get_cstr(remote->name); +} + +void infrared_remote_set_path(InfraredRemote* remote, const char* path) { + string_set_str(remote->path, path); +} + +const char* infrared_remote_get_path(InfraredRemote* remote) { + return string_get_cstr(remote->path); +} + +size_t infrared_remote_get_button_count(InfraredRemote* remote) { + return InfraredButtonArray_size(remote->buttons); +} + +InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t index) { + furi_assert(index < InfraredButtonArray_size(remote->buttons)); + return *InfraredButtonArray_get(remote->buttons, index); +} + +bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal) { + InfraredRemoteButton* button = infrared_remote_button_alloc(); + infrared_remote_button_set_name(button, name); + infrared_remote_button_set_signal(button, signal); + InfraredButtonArray_push_back(remote->buttons, button); + return infrared_remote_store(remote); +} + +bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index) { + furi_assert(index < InfraredButtonArray_size(remote->buttons)); + InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, index); + infrared_remote_button_set_name(button, new_name); + return infrared_remote_store(remote); +} + +bool infrared_remote_delete_button(InfraredRemote* remote, size_t index) { + furi_assert(index < InfraredButtonArray_size(remote->buttons)); + InfraredRemoteButton* button; + InfraredButtonArray_pop_at(&button, remote->buttons, index); + infrared_remote_button_free(button); + return infrared_remote_store(remote); +} + +bool infrared_remote_store(InfraredRemote* remote) { + Storage* storage = furi_record_open("storage"); + FlipperFormat* ff = flipper_format_file_alloc(storage); + const char* path = string_get_cstr(remote->path); + + FURI_LOG_I(TAG, "store file: \'%s\'", path); + + bool success = flipper_format_file_open_always(ff, path) && + flipper_format_write_header_cstr(ff, "IR signals file", 1); + if(success) { + InfraredButtonArray_it_t it; + for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it); + InfraredButtonArray_next(it)) { + InfraredRemoteButton* button = *InfraredButtonArray_cref(it); + success = infrared_signal_save( + infrared_remote_button_get_signal(button), + ff, + infrared_remote_button_get_name(button)); + if(!success) { + break; + } + } + } + + flipper_format_free(ff); + furi_record_close("storage"); + return success; +} + +bool infrared_remote_load(InfraredRemote* remote, string_t path) { + Storage* storage = furi_record_open("storage"); + FlipperFormat* ff = flipper_format_file_alloc(storage); + + string_t buf; + string_init(buf); + + FURI_LOG_I(TAG, "load file: \'%s\'", string_get_cstr(path)); + bool success = flipper_format_file_open_existing(ff, string_get_cstr(path)); + + if(success) { + uint32_t version; + success = flipper_format_read_header(ff, buf, &version) && + !string_cmp_str(buf, "IR signals file") && (version == 1); + } + + if(success) { + path_extract_filename(path, buf, true); + infrared_remote_clear_buttons(remote); + infrared_remote_set_name(remote, string_get_cstr(buf)); + infrared_remote_set_path(remote, string_get_cstr(path)); + + for(bool can_read = true; can_read;) { + InfraredRemoteButton* button = infrared_remote_button_alloc(); + can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf); + if(can_read) { + infrared_remote_button_set_name(button, string_get_cstr(buf)); + InfraredButtonArray_push_back(remote->buttons, button); + } else { + infrared_remote_button_free(button); + } + } + } + + string_clear(buf); + flipper_format_free(ff); + furi_record_close("storage"); + return success; +} + +bool infrared_remote_remove(InfraredRemote* remote) { + Storage* storage = furi_record_open("storage"); + + FS_Error status = storage_common_remove(storage, string_get_cstr(remote->path)); + infrared_remote_reset(remote); + + furi_record_close("storage"); + return (status == FSE_OK || status == FSE_NOT_EXIST); +} diff --git a/applications/infrared/infrared_remote.h b/applications/infrared/infrared_remote.h new file mode 100644 index 000000000000..1336383f219a --- /dev/null +++ b/applications/infrared/infrared_remote.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "infrared_remote_button.h" + +typedef struct InfraredRemote InfraredRemote; + +InfraredRemote* infrared_remote_alloc(); +void infrared_remote_free(InfraredRemote* remote); +void infrared_remote_reset(InfraredRemote* remote); + +void infrared_remote_set_name(InfraredRemote* remote, const char* name); +const char* infrared_remote_get_name(InfraredRemote* remote); + +void infrared_remote_set_path(InfraredRemote* remote, const char* path); +const char* infrared_remote_get_path(InfraredRemote* remote); + +size_t infrared_remote_get_button_count(InfraredRemote* remote); +InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t index); + +bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal); +bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index); +bool infrared_remote_delete_button(InfraredRemote* remote, size_t index); + +bool infrared_remote_store(InfraredRemote* remote); +bool infrared_remote_load(InfraredRemote* remote, string_t path); +bool infrared_remote_remove(InfraredRemote* remote); diff --git a/applications/infrared/infrared_remote_button.c b/applications/infrared/infrared_remote_button.c new file mode 100644 index 000000000000..7525ce48f7e7 --- /dev/null +++ b/applications/infrared/infrared_remote_button.c @@ -0,0 +1,38 @@ +#include "infrared_remote_button.h" + +#include +#include + +struct InfraredRemoteButton { + string_t name; + InfraredSignal* signal; +}; + +InfraredRemoteButton* infrared_remote_button_alloc() { + InfraredRemoteButton* button = malloc(sizeof(InfraredRemoteButton)); + string_init(button->name); + button->signal = infrared_signal_alloc(); + return button; +} + +void infrared_remote_button_free(InfraredRemoteButton* button) { + string_clear(button->name); + infrared_signal_free(button->signal); + free(button); +} + +void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name) { + string_set_str(button->name, name); +} + +const char* infrared_remote_button_get_name(InfraredRemoteButton* button) { + return string_get_cstr(button->name); +} + +void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal) { + infrared_signal_set_signal(button->signal, signal); +} + +InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button) { + return button->signal; +} diff --git a/applications/infrared/infrared_remote_button.h b/applications/infrared/infrared_remote_button.h new file mode 100644 index 000000000000..f25b759b566c --- /dev/null +++ b/applications/infrared/infrared_remote_button.h @@ -0,0 +1,14 @@ +#pragma once + +#include "infrared_signal.h" + +typedef struct InfraredRemoteButton InfraredRemoteButton; + +InfraredRemoteButton* infrared_remote_button_alloc(); +void infrared_remote_button_free(InfraredRemoteButton* button); + +void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name); +const char* infrared_remote_button_get_name(InfraredRemoteButton* button); + +void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal); +InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button); diff --git a/applications/infrared/infrared_runner.cpp b/applications/infrared/infrared_runner.cpp deleted file mode 100644 index 650b0fcd9f05..000000000000 --- a/applications/infrared/infrared_runner.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "infrared_app.h" - -extern "C" int32_t infrared_app(void* p) { - InfraredApp* app = new InfraredApp(); - int32_t result = app->run(p); - delete app; - - return result; -} diff --git a/applications/infrared/infrared_signal.c b/applications/infrared/infrared_signal.c new file mode 100644 index 000000000000..79eafb3086e6 --- /dev/null +++ b/applications/infrared/infrared_signal.c @@ -0,0 +1,264 @@ +#include "infrared_signal.h" + +#include +#include +#include +#include +#include + +#define TAG "InfraredSignal" + +struct InfraredSignal { + bool is_raw; + union { + InfraredMessage message; + InfraredRawSignal raw; + } payload; +}; + +static void infrared_signal_clear_timings(InfraredSignal* signal) { + if(signal->is_raw) { + free(signal->payload.raw.timings); + signal->payload.raw.timings_size = 0; + signal->payload.raw.timings = NULL; + } +} + +static bool infrared_signal_is_message_valid(InfraredMessage* message) { + if(!infrared_is_protocol_valid(message->protocol)) { + FURI_LOG_E(TAG, "Unknown protocol"); + return false; + } + + uint32_t address_length = infrared_get_protocol_address_length(message->protocol); + uint32_t address_mask = (1UL << address_length) - 1; + + if(message->address != (message->address & address_mask)) { + FURI_LOG_E( + TAG, + "Address is out of range (mask 0x%08lX): 0x%lX\r\n", + address_mask, + message->address); + return false; + } + + uint32_t command_length = infrared_get_protocol_command_length(message->protocol); + uint32_t command_mask = (1UL << command_length) - 1; + + if(message->command != (message->command & command_mask)) { + FURI_LOG_E( + TAG, + "Command is out of range (mask 0x%08lX): 0x%lX\r\n", + command_mask, + message->command); + return false; + } + + return true; +} + +static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) { + if((raw->frequency > INFRARED_MAX_FREQUENCY) || (raw->frequency < INFRARED_MIN_FREQUENCY)) { + FURI_LOG_E( + TAG, + "Frequency is out of range (%lX - %lX): %lX", + INFRARED_MIN_FREQUENCY, + INFRARED_MAX_FREQUENCY, + raw->frequency); + return false; + + } else if((raw->duty_cycle <= 0) || (raw->duty_cycle > 1)) { + FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", (double)raw->duty_cycle); + return false; + + } else if((raw->timings_size <= 0) || (raw->timings_size > MAX_TIMINGS_AMOUNT)) { + FURI_LOG_E( + TAG, + "Timings amount is out of range (0 - %lX): %lX", + MAX_TIMINGS_AMOUNT, + raw->timings_size); + return false; + } + + return true; +} + +static inline bool infrared_signal_save_message(InfraredMessage* message, FlipperFormat* ff) { + const char* protocol_name = infrared_get_protocol_name(message->protocol); + return flipper_format_write_string_cstr(ff, "type", "parsed") && + flipper_format_write_string_cstr(ff, "protocol", protocol_name) && + flipper_format_write_hex(ff, "address", (uint8_t*)&message->address, 4) && + flipper_format_write_hex(ff, "command", (uint8_t*)&message->command, 4); +} + +static inline bool infrared_signal_save_raw(InfraredRawSignal* raw, FlipperFormat* ff) { + furi_assert(raw->timings_size <= MAX_TIMINGS_AMOUNT); + return flipper_format_write_string_cstr(ff, "type", "raw") && + flipper_format_write_uint32(ff, "frequency", &raw->frequency, 1) && + flipper_format_write_float(ff, "duty_cycle", &raw->duty_cycle, 1) && + flipper_format_write_uint32(ff, "data", raw->timings, raw->timings_size); +} + +static inline bool infrared_signal_read_message(InfraredSignal* signal, FlipperFormat* ff) { + string_t buf; + string_init(buf); + bool success = false; + + do { + if(!flipper_format_read_string(ff, "protocol", buf)) break; + + InfraredMessage message; + message.protocol = infrared_get_protocol_by_name(string_get_cstr(buf)); + + success = flipper_format_read_hex(ff, "address", (uint8_t*)&message.address, 4) && + flipper_format_read_hex(ff, "command", (uint8_t*)&message.command, 4) && + infrared_signal_is_message_valid(&message); + + if(!success) break; + + infrared_signal_set_message(signal, &message); + } while(0); + + string_clear(buf); + return success; +} + +static inline bool infrared_signal_read_raw(InfraredSignal* signal, FlipperFormat* ff) { + uint32_t timings_size, frequency; + float duty_cycle; + + bool success = flipper_format_read_uint32(ff, "frequency", &frequency, 1) && + flipper_format_read_float(ff, "duty_cycle", &duty_cycle, 1) && + flipper_format_get_value_count(ff, "data", &timings_size); + + if(!success || timings_size > MAX_TIMINGS_AMOUNT) { + return false; + } + + uint32_t* timings = malloc(sizeof(uint32_t) * timings_size); + success = flipper_format_read_uint32(ff, "data", timings, timings_size); + + if(success) { + infrared_signal_set_raw_signal(signal, timings, timings_size, frequency, duty_cycle); + } + + free(timings); + return success; +} + +InfraredSignal* infrared_signal_alloc() { + InfraredSignal* signal = malloc(sizeof(InfraredSignal)); + + signal->is_raw = false; + signal->payload.message.protocol = InfraredProtocolUnknown; + + return signal; +} + +void infrared_signal_free(InfraredSignal* signal) { + infrared_signal_clear_timings(signal); + free(signal); +} + +bool infrared_signal_is_raw(InfraredSignal* signal) { + return signal->is_raw; +} + +bool infrared_signal_is_valid(InfraredSignal* signal) { + return signal->is_raw ? infrared_signal_is_raw_valid(&signal->payload.raw) : + infrared_signal_is_message_valid(&signal->payload.message); +} + +void infrared_signal_set_signal(InfraredSignal* signal, const InfraredSignal* other) { + if(other->is_raw) { + const InfraredRawSignal* raw = &other->payload.raw; + infrared_signal_set_raw_signal( + signal, raw->timings, raw->timings_size, raw->frequency, raw->duty_cycle); + } else { + const InfraredMessage* message = &other->payload.message; + infrared_signal_set_message(signal, message); + } +} + +void infrared_signal_set_raw_signal( + InfraredSignal* signal, + const uint32_t* timings, + size_t timings_size, + uint32_t frequency, + float duty_cycle) { + infrared_signal_clear_timings(signal); + + signal->is_raw = true; + + signal->payload.raw.timings_size = timings_size; + signal->payload.raw.frequency = frequency; + signal->payload.raw.duty_cycle = duty_cycle; + + signal->payload.raw.timings = malloc(timings_size * sizeof(uint32_t)); + memcpy(signal->payload.raw.timings, timings, timings_size * sizeof(uint32_t)); +} + +InfraredRawSignal* infrared_signal_get_raw_signal(InfraredSignal* signal) { + furi_assert(signal->is_raw); + return &signal->payload.raw; +} + +void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* message) { + infrared_signal_clear_timings(signal); + + signal->is_raw = false; + signal->payload.message = *message; +} + +InfraredMessage* infrared_signal_get_message(InfraredSignal* signal) { + furi_assert(!signal->is_raw); + return &signal->payload.message; +} + +bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name) { + if(!flipper_format_write_comment_cstr(ff, "") || + !flipper_format_write_string_cstr(ff, "name", name)) { + return false; + } else if(signal->is_raw) { + return infrared_signal_save_raw(&signal->payload.raw, ff); + } else { + return infrared_signal_save_message(&signal->payload.message, ff); + } +} + +bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name) { + string_t buf; + string_init(buf); + bool success = false; + + do { + if(!flipper_format_read_string(ff, "name", buf)) break; + string_set(name, buf); + if(!flipper_format_read_string(ff, "type", buf)) break; + if(!string_cmp_str(buf, "raw")) { + success = infrared_signal_read_raw(signal, ff); + } else if(!string_cmp_str(buf, "parsed")) { + success = infrared_signal_read_message(signal, ff); + } else { + FURI_LOG_E(TAG, "Unknown type of signal (allowed - raw/parsed) "); + } + } while(0); + + string_clear(buf); + return success; +} + +void infrared_signal_transmit(InfraredSignal* signal) { + if(signal->is_raw) { + InfraredRawSignal* raw_signal = &signal->payload.raw; + infrared_send_raw_ext( + raw_signal->timings, + raw_signal->timings_size, + true, + raw_signal->frequency, + raw_signal->duty_cycle); + } else { + InfraredMessage* message = &signal->payload.message; + infrared_send(message, 1); + } +} diff --git a/applications/infrared/infrared_signal.h b/applications/infrared/infrared_signal.h new file mode 100644 index 000000000000..2dbaa75faab0 --- /dev/null +++ b/applications/infrared/infrared_signal.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include + +#include +#include + +typedef struct InfraredSignal InfraredSignal; + +typedef struct { + size_t timings_size; + uint32_t* timings; + uint32_t frequency; + float duty_cycle; +} InfraredRawSignal; + +InfraredSignal* infrared_signal_alloc(); +void infrared_signal_free(InfraredSignal* signal); + +bool infrared_signal_is_raw(InfraredSignal* signal); +bool infrared_signal_is_valid(InfraredSignal* signal); + +void infrared_signal_set_signal(InfraredSignal* signal, const InfraredSignal* other); + +void infrared_signal_set_raw_signal( + InfraredSignal* signal, + const uint32_t* timings, + size_t timings_size, + uint32_t frequency, + float duty_cycle); +InfraredRawSignal* infrared_signal_get_raw_signal(InfraredSignal* signal); + +void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* message); +InfraredMessage* infrared_signal_get_message(InfraredSignal* signal); + +bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name); +bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name); + +void infrared_signal_transmit(InfraredSignal* signal); diff --git a/applications/infrared/scene/infrared_app_scene.h b/applications/infrared/scene/infrared_app_scene.h deleted file mode 100644 index 9c2e20e925a5..000000000000 --- a/applications/infrared/scene/infrared_app_scene.h +++ /dev/null @@ -1,305 +0,0 @@ -/** - * @file infrared_app_scene.h - * Infrared: Application scenes - */ -#pragma once -#include "../infrared_app_event.h" -#include -#include "infrared.h" -#include -#include -#include "../infrared_app_brute_force.h" - -/** Anonymous class */ -class InfraredApp; - -/** Base Scene class */ -class InfraredAppScene { -public: - /** Called when enter scene */ - virtual void on_enter(InfraredApp* app) = 0; - /** Events handler callback */ - virtual bool on_event(InfraredApp* app, InfraredAppEvent* event) = 0; - /** Called when exit scene */ - virtual void on_exit(InfraredApp* app) = 0; - /** Virtual destructor of base class */ - virtual ~InfraredAppScene(){}; - -private: -}; - -/** Start scene - * Main Infrared application menu - */ -class InfraredAppSceneStart : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Save previously selected submenu index - * to highlight it when get back */ - uint32_t submenu_item_selected = 0; -}; - -/** Universal menu scene - * Scene to select universal remote - */ -class InfraredAppSceneUniversal : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Save previously selected submenu index - * to highlight it when get back */ - uint32_t submenu_item_selected = 0; -}; - -/** Learn new signal scene - * On this scene catching new IR signal performed. - */ -class InfraredAppSceneLearn : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -/** New signal learn succeeded scene - */ -class InfraredAppSceneLearnSuccess : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - bool button_pressed = false; -}; - -/** Scene to enter name for new button in remote - */ -class InfraredAppSceneLearnEnterName : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -/** Scene where signal is learnt - */ -class InfraredAppSceneLearnDone : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -/** Remote interface scene - * On this scene you can send IR signals from selected remote - */ -class InfraredAppSceneRemote : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** container of button names in current remote. */ - std::vector buttons_names; - /** Save previously selected index - * to highlight it when get back */ - uint32_t buttonmenu_item_selected = 0; - /** state flag to show button is pressed. - * As long as send-signal button pressed no other button - * events are handled. */ - bool button_pressed = false; -}; - -/** List of remotes scene - * Every remote is a file, located on internal/external storage. - * Every file has same format, and same extension. - * Files are parsed as you enter 'Remote scene' and showed - * as a buttons. - */ -class InfraredAppSceneRemoteList : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Save previously selected index - * to highlight it when get back */ - uint32_t submenu_item_selected = 0; - /** Remote names to show them in submenu */ - std::vector remote_names; -}; - -class InfraredAppSceneAskBack : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneEdit : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Save previously selected index - * to highlight it when get back */ - uint32_t submenu_item_selected = 0; -}; - -class InfraredAppSceneEditKeySelect : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - -private: - /** Button names to show them in submenu */ - std::vector buttons_names; -}; - -class InfraredAppSceneEditRename : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneEditDelete : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneEditRenameDone : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneEditDeleteDone : public InfraredAppScene { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; -}; - -class InfraredAppSceneUniversalCommon : public InfraredAppScene { - /** Brute force started flag */ - bool brute_force_started = false; - -protected: - /** Events handler callback */ - bool on_event(InfraredApp* app, InfraredAppEvent* event) final; - /** Called when exit scene */ - void on_exit(InfraredApp* app) final; - - /** Show popup window - * - * @param app - application instance - */ - void show_popup(InfraredApp* app, int record_amount); - - /** Hide popup window - * - * @param app - application instance - */ - void hide_popup(InfraredApp* app); - - /** Propagate progress in popup window - * - * @param app - application instance - */ - bool progress_popup(InfraredApp* app); - - /** Item selected callback - * - * @param context - context - * @param index - selected item index - */ - static void infrared_app_item_callback(void* context, uint32_t index); - - /** Brute Force instance */ - InfraredAppBruteForce brute_force; - - /** Constructor */ - InfraredAppSceneUniversalCommon(const char* filename) - : brute_force(filename) { - } - - /** Destructor */ - ~InfraredAppSceneUniversalCommon() { - } -}; - -class InfraredAppSceneUniversalTV : public InfraredAppSceneUniversalCommon { -public: - /** Called when enter scene */ - void on_enter(InfraredApp* app) final; - - /** Constructor - * Specifies path to brute force db library */ - InfraredAppSceneUniversalTV() - : InfraredAppSceneUniversalCommon("/ext/infrared/assets/tv.ir") { - } - - /** Destructor */ - ~InfraredAppSceneUniversalTV() { - } -}; diff --git a/applications/infrared/scene/infrared_app_scene_ask_back.cpp b/applications/infrared/scene/infrared_app_scene_ask_back.cpp deleted file mode 100644 index 65d7ca578ceb..000000000000 --- a/applications/infrared/scene/infrared_app_scene_ask_back.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "../infrared_app.h" -#include "gui/modules/dialog_ex.h" -#include "infrared.h" -#include "infrared/scene/infrared_app_scene.h" -#include - -static void dialog_result_callback(DialogExResult result, void* context) { - auto app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::DialogExSelected; - event.payload.dialog_ex_result = result; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneAskBack::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - - if(app->get_learn_new_remote()) { - dialog_ex_set_header(dialog_ex, "Exit to Infrared menu?", 64, 0, AlignCenter, AlignTop); - } else { - dialog_ex_set_header(dialog_ex, "Exit to remote menu?", 64, 0, AlignCenter, AlignTop); - } - - dialog_ex_set_text( - dialog_ex, "All unsaved data\nwill be lost", 64, 31, AlignCenter, AlignCenter); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, "Exit"); - dialog_ex_set_center_button_text(dialog_ex, nullptr); - dialog_ex_set_right_button_text(dialog_ex, "Stay"); - dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); - dialog_ex_set_context(dialog_ex, app); - - view_manager->switch_to(InfraredAppViewManager::ViewId::DialogEx); -} - -bool InfraredAppSceneAskBack::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::DialogExSelected) { - switch(event->payload.dialog_ex_result) { - case DialogExResultLeft: - consumed = true; - if(app->get_learn_new_remote()) { - app->search_and_switch_to_previous_scene({InfraredApp::Scene::Start}); - } else { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Edit, InfraredApp::Scene::Remote}); - } - break; - case DialogExResultCenter: - furi_assert(0); - break; - case DialogExResultRight: - app->switch_to_previous_scene(); - consumed = true; - break; - default: - break; - } - } - - if(event->type == InfraredAppEvent::Type::Back) { - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneAskBack::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_edit.cpp b/applications/infrared/scene/infrared_app_scene_edit.cpp deleted file mode 100644 index 5a2ae72fff89..000000000000 --- a/applications/infrared/scene/infrared_app_scene_edit.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "../infrared_app.h" -#include "gui/modules/submenu.h" - -typedef enum { - SubmenuIndexAddKey, - SubmenuIndexRenameKey, - SubmenuIndexDeleteKey, - SubmenuIndexRenameRemote, - SubmenuIndexDeleteRemote, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::MenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneEdit::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item(submenu, "Add Button", SubmenuIndexAddKey, submenu_callback, app); - submenu_add_item(submenu, "Rename Button", SubmenuIndexRenameKey, submenu_callback, app); - submenu_add_item(submenu, "Delete Button", SubmenuIndexDeleteKey, submenu_callback, app); - submenu_add_item(submenu, "Rename Remote", SubmenuIndexRenameRemote, submenu_callback, app); - submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app); - submenu_set_selected_item(submenu, submenu_item_selected); - submenu_item_selected = 0; - - view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu); -} - -bool InfraredAppSceneEdit::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuIndexAddKey: - app->set_learn_new_remote(false); - app->switch_to_next_scene(InfraredApp::Scene::Learn); - break; - case SubmenuIndexRenameKey: - app->set_edit_action(InfraredApp::EditAction::Rename); - app->set_edit_element(InfraredApp::EditElement::Button); - app->switch_to_next_scene(InfraredApp::Scene::EditKeySelect); - break; - case SubmenuIndexDeleteKey: - app->set_edit_action(InfraredApp::EditAction::Delete); - app->set_edit_element(InfraredApp::EditElement::Button); - app->switch_to_next_scene(InfraredApp::Scene::EditKeySelect); - break; - case SubmenuIndexRenameRemote: - app->set_edit_action(InfraredApp::EditAction::Rename); - app->set_edit_element(InfraredApp::EditElement::Remote); - app->switch_to_next_scene(InfraredApp::Scene::EditRename); - break; - case SubmenuIndexDeleteRemote: - app->set_edit_action(InfraredApp::EditAction::Delete); - app->set_edit_element(InfraredApp::EditElement::Remote); - app->switch_to_next_scene(InfraredApp::Scene::EditDelete); - break; - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneEdit::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_delete.cpp b/applications/infrared/scene/infrared_app_scene_edit_delete.cpp deleted file mode 100644 index e17cfee076ee..000000000000 --- a/applications/infrared/scene/infrared_app_scene_edit_delete.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "../infrared_app.h" -#include "infrared.h" -#include "infrared/scene/infrared_app_scene.h" -#include - -static void dialog_result_callback(DialogExResult result, void* context) { - auto app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::DialogExSelected; - event.payload.dialog_ex_result = result; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneEditDelete::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - - auto remote_manager = app->get_remote_manager(); - - if(app->get_edit_element() == InfraredApp::EditElement::Button) { - auto signal = remote_manager->get_button_data(app->get_current_button()); - dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop); - if(!signal.is_raw()) { - auto message = &signal.get_message(); - app->set_text_store( - 0, - "%s\n%s\nA=0x%0*lX C=0x%0*lX", - remote_manager->get_button_name(app->get_current_button()).c_str(), - infrared_get_protocol_name(message->protocol), - ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), - message->address, - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), - message->command); - } else { - app->set_text_store( - 0, - "%s\nRAW\n%ld samples", - remote_manager->get_button_name(app->get_current_button()).c_str(), - signal.get_raw_signal().timings_cnt); - } - } else { - dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 0, AlignCenter, AlignTop); - app->set_text_store( - 0, - "%s\n with %lu buttons", - remote_manager->get_remote_name().c_str(), - remote_manager->get_number_of_buttons()); - } - - dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, "Cancel"); - dialog_ex_set_right_button_text(dialog_ex, "Delete"); - dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); - dialog_ex_set_context(dialog_ex, app); - - view_manager->switch_to(InfraredAppViewManager::ViewId::DialogEx); -} - -bool InfraredAppSceneEditDelete::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::DialogExSelected) { - switch(event->payload.dialog_ex_result) { - case DialogExResultLeft: - app->switch_to_previous_scene(); - break; - case DialogExResultCenter: - furi_assert(0); - break; - case DialogExResultRight: { - auto remote_manager = app->get_remote_manager(); - bool result = false; - if(app->get_edit_element() == InfraredApp::EditElement::Remote) { - result = remote_manager->delete_remote(); - } else { - result = remote_manager->delete_button(app->get_current_button()); - app->set_current_button(InfraredApp::ButtonNA); - } - - if(!result) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::RemoteList, InfraredApp::Scene::Start}); - } else { - app->switch_to_next_scene(InfraredApp::Scene::EditDeleteDone); - } - break; - } - default: - break; - } - } - - return consumed; -} - -void InfraredAppSceneEditDelete::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_delete_done.cpp b/applications/infrared/scene/infrared_app_scene_edit_delete_done.cpp deleted file mode 100644 index 3f9800e1a251..000000000000 --- a/applications/infrared/scene/infrared_app_scene_edit_delete_done.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "../infrared_app.h" - -void InfraredAppSceneEditDeleteDone::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - - popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); - - popup_set_callback(popup, InfraredApp::popup_callback); - popup_set_context(popup, app); - popup_set_timeout(popup, 1500); - popup_enable_timeout(popup); - - view_manager->switch_to(InfraredAppViewManager::ViewId::Popup); -} - -bool InfraredAppSceneEditDeleteDone::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::PopupTimer) { - if(app->get_edit_element() == InfraredApp::EditElement::Remote) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList}); - } else { - app->search_and_switch_to_previous_scene({InfraredApp::Scene::Remote}); - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneEditDeleteDone::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop); -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp b/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp deleted file mode 100644 index 49142c212bea..000000000000 --- a/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "../infrared_app.h" -#include "gui/modules/submenu.h" - -static void submenu_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::MenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneEditKeySelect::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - int item_number = 0; - - const char* header = app->get_edit_action() == InfraredApp::EditAction::Rename ? - "Rename Button:" : - "Delete Button:"; - submenu_set_header(submenu, header); - - auto remote_manager = app->get_remote_manager(); - buttons_names = remote_manager->get_button_list(); - for(const auto& it : buttons_names) { - submenu_add_item(submenu, it.c_str(), item_number++, submenu_callback, app); - } - if((item_number > 0) && (app->get_current_button() != InfraredApp::ButtonNA)) { - submenu_set_selected_item(submenu, app->get_current_button()); - app->set_current_button(InfraredApp::ButtonNA); - } - - view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu); -} - -bool InfraredAppSceneEditKeySelect::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::MenuSelected) { - app->set_current_button(event->payload.menu_index); - consumed = true; - if(app->get_edit_action() == InfraredApp::EditAction::Rename) { - app->switch_to_next_scene(InfraredApp::Scene::EditRename); - } else { - app->switch_to_next_scene(InfraredApp::Scene::EditDelete); - } - } - - return consumed; -} - -void InfraredAppSceneEditKeySelect::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_rename.cpp b/applications/infrared/scene/infrared_app_scene_edit_rename.cpp deleted file mode 100644 index 761da49f3b3f..000000000000 --- a/applications/infrared/scene/infrared_app_scene_edit_rename.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "../infrared_app.h" -#include "m-string.h" -#include "toolbox/path.h" - -void InfraredAppSceneEditRename::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - TextInput* text_input = view_manager->get_text_input(); - size_t enter_name_length = 0; - - auto remote_manager = app->get_remote_manager(); - if(app->get_edit_element() == InfraredApp::EditElement::Button) { - furi_assert(app->get_current_button() != InfraredApp::ButtonNA); - auto button_name = remote_manager->get_button_name(app->get_current_button()); - char* buffer_str = app->get_text_store(0); - size_t max_len = InfraredAppRemoteManager::max_button_name_length; - strncpy(buffer_str, button_name.c_str(), max_len); - buffer_str[max_len + 1] = 0; - enter_name_length = max_len; - text_input_set_header_text(text_input, "Name the button"); - } else { - auto remote_name = remote_manager->get_remote_name(); - strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size()); - enter_name_length = InfraredAppRemoteManager::max_remote_name_length; - text_input_set_header_text(text_input, "Name the remote"); - - string_t folder_path; - string_init(folder_path); - - if(string_end_with_str_p(app->file_path, InfraredApp::infrared_extension)) { - path_extract_dirname(string_get_cstr(app->file_path), folder_path); - } - - ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( - string_get_cstr(folder_path), app->infrared_extension, remote_name.c_str()); - text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); - - string_clear(folder_path); - } - - text_input_set_result_callback( - text_input, - InfraredApp::text_input_callback, - app, - app->get_text_store(0), - enter_name_length, - false); - - view_manager->switch_to(InfraredAppViewManager::ViewId::TextInput); -} - -bool InfraredAppSceneEditRename::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::TextEditDone) { - auto remote_manager = app->get_remote_manager(); - bool result = false; - if(app->get_edit_element() == InfraredApp::EditElement::Button) { - result = - remote_manager->rename_button(app->get_current_button(), app->get_text_store(0)); - app->set_current_button(InfraredApp::ButtonNA); - } else { - result = remote_manager->rename_remote(app->get_text_store(0)); - } - if(!result) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList}); - } else { - app->switch_to_next_scene_without_saving(InfraredApp::Scene::EditRenameDone); - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneEditRename::on_exit(InfraredApp* app) { - TextInput* text_input = app->get_view_manager()->get_text_input(); - - void* validator_context = text_input_get_validator_callback_context(text_input); - text_input_set_validator(text_input, NULL, NULL); - - if(validator_context != NULL) validator_is_file_free((ValidatorIsFile*)validator_context); -} diff --git a/applications/infrared/scene/infrared_app_scene_edit_rename_done.cpp b/applications/infrared/scene/infrared_app_scene_edit_rename_done.cpp deleted file mode 100644 index 803481f6b3c3..000000000000 --- a/applications/infrared/scene/infrared_app_scene_edit_rename_done.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "../infrared_app.h" - -void InfraredAppSceneEditRenameDone::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); - - popup_set_callback(popup, InfraredApp::popup_callback); - popup_set_context(popup, app); - popup_set_timeout(popup, 1500); - popup_enable_timeout(popup); - - view_manager->switch_to(InfraredAppViewManager::ViewId::Popup); -} - -bool InfraredAppSceneEditRenameDone::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::PopupTimer) { - app->switch_to_next_scene(InfraredApp::Scene::Remote); - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneEditRenameDone::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_learn.cpp b/applications/infrared/scene/infrared_app_scene_learn.cpp deleted file mode 100644 index 3ad152cff213..000000000000 --- a/applications/infrared/scene/infrared_app_scene_learn.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "../infrared_app.h" -#include "../infrared_app_event.h" -#include "infrared.h" -#include - -static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { - furi_assert(context); - furi_assert(received_signal); - - InfraredApp* app = static_cast(context); - - if(infrared_worker_signal_is_decoded(received_signal)) { - InfraredAppSignal signal(infrared_worker_get_decoded_signal(received_signal)); - app->set_received_signal(signal); - } else { - const uint32_t* timings; - size_t timings_cnt; - infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt); - InfraredAppSignal signal( - timings, timings_cnt, INFRARED_COMMON_CARRIER_FREQUENCY, INFRARED_COMMON_DUTY_CYCLE); - app->set_received_signal(signal); - } - - infrared_worker_rx_set_received_signal_callback(app->get_infrared_worker(), NULL, NULL); - InfraredAppEvent event; - event.type = InfraredAppEvent::Type::InfraredMessageReceived; - auto view_manager = app->get_view_manager(); - view_manager->send_event(&event); -} - -void InfraredAppSceneLearn::on_enter(InfraredApp* app) { - auto view_manager = app->get_view_manager(); - auto popup = view_manager->get_popup(); - - auto worker = app->get_infrared_worker(); - infrared_worker_rx_set_received_signal_callback(worker, signal_received_callback, app); - infrared_worker_rx_start(worker); - - popup_set_icon(popup, 0, 32, &I_InfraredLearnShort_128x31); - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignCenter); - popup_set_text( - popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter); - popup_set_callback(popup, NULL); - - view_manager->switch_to(InfraredAppViewManager::ViewId::Popup); -} - -bool InfraredAppSceneLearn::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - switch(event->type) { - case InfraredAppEvent::Type::Tick: - consumed = true; - app->notify_blink_read(); - break; - case InfraredAppEvent::Type::InfraredMessageReceived: - app->notify_success(); - app->switch_to_next_scene_without_saving(InfraredApp::Scene::LearnSuccess); - break; - case InfraredAppEvent::Type::Back: - consumed = true; - app->switch_to_previous_scene(); - break; - default: - furi_assert(0); - } - - return consumed; -} - -void InfraredAppSceneLearn::on_exit(InfraredApp* app) { - infrared_worker_rx_stop(app->get_infrared_worker()); - auto view_manager = app->get_view_manager(); - auto popup = view_manager->get_popup(); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter); -} diff --git a/applications/infrared/scene/infrared_app_scene_learn_done.cpp b/applications/infrared/scene/infrared_app_scene_learn_done.cpp deleted file mode 100644 index 6ee13b432225..000000000000 --- a/applications/infrared/scene/infrared_app_scene_learn_done.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "../infrared_app.h" -#include - -void InfraredAppSceneLearnDone::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - DOLPHIN_DEED(DolphinDeedIrSave); - - if(app->get_learn_new_remote()) { - popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); - } else { - popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); - } - - popup_set_callback(popup, InfraredApp::popup_callback); - popup_set_context(popup, app); - popup_set_timeout(popup, 1500); - popup_enable_timeout(popup); - - view_manager->switch_to(InfraredAppViewManager::ViewId::Popup); -} - -bool InfraredAppSceneLearnDone::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::PopupTimer) { - app->switch_to_next_scene(InfraredApp::Scene::Remote); - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneLearnDone::on_exit(InfraredApp* app) { - app->set_learn_new_remote(false); - InfraredAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop); -} diff --git a/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp b/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp deleted file mode 100644 index 7d15a7c56601..000000000000 --- a/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "../infrared_app.h" -#include "gui/modules/text_input.h" - -void InfraredAppSceneLearnEnterName::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - TextInput* text_input = view_manager->get_text_input(); - - auto signal = app->get_received_signal(); - - if(!signal.is_raw()) { - auto message = &signal.get_message(); - app->set_text_store( - 0, - "%.4s_%0*lX", - infrared_get_protocol_name(message->protocol), - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), - message->command); - } else { - auto raw_signal = signal.get_raw_signal(); - app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt); - } - - text_input_set_header_text(text_input, "Name the button"); - text_input_set_result_callback( - text_input, - InfraredApp::text_input_callback, - app, - app->get_text_store(0), - InfraredAppRemoteManager::max_button_name_length, - true); - - view_manager->switch_to(InfraredAppViewManager::ViewId::TextInput); -} - -bool InfraredAppSceneLearnEnterName::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::TextEditDone) { - auto remote_manager = app->get_remote_manager(); - bool result = false; - if(app->get_learn_new_remote()) { - result = remote_manager->add_remote_with_button( - app->get_text_store(0), app->get_received_signal()); - } else { - result = - remote_manager->add_button(app->get_text_store(0), app->get_received_signal()); - } - - if(!result) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList}); - } else { - app->switch_to_next_scene_without_saving(InfraredApp::Scene::LearnDone); - } - } - return consumed; -} - -void InfraredAppSceneLearnEnterName::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_learn_success.cpp b/applications/infrared/scene/infrared_app_scene_learn_success.cpp deleted file mode 100644 index a7f7c4cd7f1a..000000000000 --- a/applications/infrared/scene/infrared_app_scene_learn_success.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include - -#include "../infrared_app.h" -#include "infrared.h" - -static void dialog_result_callback(DialogExResult result, void* context) { - auto app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::DialogExSelected; - event.payload.dialog_ex_result = result; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneLearnSuccess::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - - DOLPHIN_DEED(DolphinDeedIrLearnSuccess); - app->notify_green_on(); - - infrared_worker_tx_set_get_signal_callback( - app->get_infrared_worker(), infrared_worker_tx_get_signal_steady_callback, app); - infrared_worker_tx_set_signal_sent_callback( - app->get_infrared_worker(), InfraredApp::signal_sent_callback, app); - - auto signal = app->get_received_signal(); - - if(!signal.is_raw()) { - auto message = &signal.get_message(); - uint8_t adr_digits = - ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4); - uint8_t cmd_digits = - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4); - uint8_t max_digits = MAX(adr_digits, cmd_digits); - max_digits = MIN(max_digits, 7); - size_t label_x_offset = 63 + (7 - max_digits) * 3; - - app->set_text_store(0, "%s", infrared_get_protocol_name(message->protocol)); - app->set_text_store( - 1, - "A: 0x%0*lX\nC: 0x%0*lX\n", - adr_digits, - message->address, - cmd_digits, - message->command); - - dialog_ex_set_header(dialog_ex, app->get_text_store(0), 95, 7, AlignCenter, AlignCenter); - dialog_ex_set_text( - dialog_ex, app->get_text_store(1), label_x_offset, 34, AlignLeft, AlignCenter); - } else { - dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); - app->set_text_store(0, "%d samples", signal.get_raw_signal().timings_cnt); - dialog_ex_set_text(dialog_ex, app->get_text_store(0), 75, 23, AlignLeft, AlignTop); - } - - dialog_ex_set_left_button_text(dialog_ex, "Retry"); - dialog_ex_set_right_button_text(dialog_ex, "Save"); - dialog_ex_set_center_button_text(dialog_ex, "Send"); - dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63); - dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); - dialog_ex_set_context(dialog_ex, app); - dialog_ex_enable_extended_events(dialog_ex); - - view_manager->switch_to(InfraredAppViewManager::ViewId::DialogEx); -} - -bool InfraredAppSceneLearnSuccess::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - if(event->type == InfraredAppEvent::Type::Tick) { - /* Send event every tick to suppress any switching off green light */ - if(!button_pressed) { - app->notify_green_on(); - } - } - - if(event->type == InfraredAppEvent::Type::DialogExSelected) { - switch(event->payload.dialog_ex_result) { - case DialogExResultLeft: - consumed = true; - if(!button_pressed) { - app->switch_to_next_scene_without_saving(InfraredApp::Scene::Learn); - } - break; - case DialogExResultRight: { - consumed = true; - if(!button_pressed) { - app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName); - } - break; - } - case DialogExPressCenter: - if(!button_pressed) { - button_pressed = true; - - auto signal = app->get_received_signal(); - if(signal.is_raw()) { - infrared_worker_set_raw_signal( - app->get_infrared_worker(), - signal.get_raw_signal().timings, - signal.get_raw_signal().timings_cnt); - } else { - infrared_worker_set_decoded_signal( - app->get_infrared_worker(), &signal.get_message()); - } - - infrared_worker_tx_start(app->get_infrared_worker()); - } - break; - case DialogExReleaseCenter: - if(button_pressed) { - button_pressed = false; - infrared_worker_tx_stop(app->get_infrared_worker()); - app->notify_green_off(); - } - break; - default: - break; - } - } - - if(event->type == InfraredAppEvent::Type::Back) { - if(!button_pressed) { - app->switch_to_next_scene(InfraredApp::Scene::AskBack); - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneLearnSuccess::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - dialog_ex_reset(dialog_ex); - app->notify_green_off(); - infrared_worker_tx_set_get_signal_callback(app->get_infrared_worker(), nullptr, nullptr); - infrared_worker_tx_set_signal_sent_callback(app->get_infrared_worker(), nullptr, nullptr); -} diff --git a/applications/infrared/scene/infrared_app_scene_remote.cpp b/applications/infrared/scene/infrared_app_scene_remote.cpp deleted file mode 100644 index ac87b58148b9..000000000000 --- a/applications/infrared/scene/infrared_app_scene_remote.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include -#include -#include -#include "../infrared_app.h" -#include "../infrared_app_view_manager.h" - -typedef enum { - ButtonIndexPlus = -2, - ButtonIndexEdit = -1, - ButtonIndexNA = 0, -} ButtonIndex; - -static void button_menu_callback(void* context, int32_t index, InputType type) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - if(type == InputTypePress) { - event.type = InfraredAppEvent::Type::MenuSelectedPress; - } else if(type == InputTypeRelease) { - event.type = InfraredAppEvent::Type::MenuSelectedRelease; - } else if(type == InputTypeShort) { - event.type = InfraredAppEvent::Type::MenuSelected; - } else { - furi_assert(0); - } - - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneRemote::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonMenu* button_menu = view_manager->get_button_menu(); - auto remote_manager = app->get_remote_manager(); - int i = 0; - button_pressed = false; - - infrared_worker_tx_set_get_signal_callback( - app->get_infrared_worker(), infrared_worker_tx_get_signal_steady_callback, app); - infrared_worker_tx_set_signal_sent_callback( - app->get_infrared_worker(), InfraredApp::signal_sent_callback, app); - buttons_names = remote_manager->get_button_list(); - - i = 0; - for(auto& name : buttons_names) { - button_menu_add_item( - button_menu, name.c_str(), i++, button_menu_callback, ButtonMenuItemTypeCommon, app); - } - - button_menu_add_item( - button_menu, "+", ButtonIndexPlus, button_menu_callback, ButtonMenuItemTypeControl, app); - button_menu_add_item( - button_menu, "Edit", ButtonIndexEdit, button_menu_callback, ButtonMenuItemTypeControl, app); - - app->set_text_store(0, "%s", remote_manager->get_remote_name().c_str()); - button_menu_set_header(button_menu, app->get_text_store(0)); - if(buttonmenu_item_selected != ButtonIndexNA) { - button_menu_set_selected_item(button_menu, buttonmenu_item_selected); - buttonmenu_item_selected = ButtonIndexNA; - } - view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu); -} - -bool InfraredAppSceneRemote::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = true; - - if((event->type == InfraredAppEvent::Type::MenuSelected) || - (event->type == InfraredAppEvent::Type::MenuSelectedPress) || - (event->type == InfraredAppEvent::Type::MenuSelectedRelease)) { - switch(event->payload.menu_index) { - case ButtonIndexPlus: - furi_assert(event->type == InfraredAppEvent::Type::MenuSelected); - buttonmenu_item_selected = event->payload.menu_index; - app->set_learn_new_remote(false); - app->switch_to_next_scene(InfraredApp::Scene::Learn); - break; - case ButtonIndexEdit: - furi_assert(event->type == InfraredAppEvent::Type::MenuSelected); - buttonmenu_item_selected = event->payload.menu_index; - app->switch_to_next_scene(InfraredApp::Scene::Edit); - break; - default: - furi_assert(event->type != InfraredAppEvent::Type::MenuSelected); - bool pressed = (event->type == InfraredAppEvent::Type::MenuSelectedPress); - - if(pressed && !button_pressed) { - button_pressed = true; - - auto button_signal = - app->get_remote_manager()->get_button_data(event->payload.menu_index); - if(button_signal.is_raw()) { - infrared_worker_set_raw_signal( - app->get_infrared_worker(), - button_signal.get_raw_signal().timings, - button_signal.get_raw_signal().timings_cnt); - } else { - infrared_worker_set_decoded_signal( - app->get_infrared_worker(), &button_signal.get_message()); - } - - DOLPHIN_DEED(DolphinDeedIrSend); - infrared_worker_tx_start(app->get_infrared_worker()); - } else if(!pressed && button_pressed) { - button_pressed = false; - infrared_worker_tx_stop(app->get_infrared_worker()); - app->notify_green_off(); - } - break; - } - } else if(event->type == InfraredAppEvent::Type::Back) { - if(!button_pressed) { - app->search_and_switch_to_previous_scene( - {InfraredApp::Scene::Start, InfraredApp::Scene::RemoteList}); - } - } else { - consumed = false; - } - - return consumed; -} - -void InfraredAppSceneRemote::on_exit(InfraredApp* app) { - infrared_worker_tx_set_get_signal_callback(app->get_infrared_worker(), nullptr, nullptr); - infrared_worker_tx_set_signal_sent_callback(app->get_infrared_worker(), nullptr, nullptr); - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonMenu* button_menu = view_manager->get_button_menu(); - - button_menu_reset(button_menu); -} diff --git a/applications/infrared/scene/infrared_app_scene_remote_list.cpp b/applications/infrared/scene/infrared_app_scene_remote_list.cpp deleted file mode 100644 index c72acb6e874c..000000000000 --- a/applications/infrared/scene/infrared_app_scene_remote_list.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "../infrared_app.h" -#include "assets_icons.h" -#include "infrared/infrared_app_event.h" -#include - -void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) { - furi_assert(app); - - bool result = false; - bool file_select_result; - auto remote_manager = app->get_remote_manager(); - DialogsApp* dialogs = app->get_dialogs(); - - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonMenu* button_menu = view_manager->get_button_menu(); - button_menu_reset(button_menu); - view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu); - - file_select_result = dialog_file_browser_show( - dialogs, - app->file_path, - app->file_path, - InfraredApp::infrared_extension, - true, - &I_ir_10px, - true); - - if(file_select_result) { - if(remote_manager->load(app->file_path)) { - app->switch_to_next_scene(InfraredApp::Scene::Remote); - result = true; - } - } - - if(!result) { - app->switch_to_previous_scene(); - } -} - -bool InfraredAppSceneRemoteList::on_event(InfraredApp*, InfraredAppEvent*) { - return false; -} - -void InfraredAppSceneRemoteList::on_exit(InfraredApp*) { -} diff --git a/applications/infrared/scene/infrared_app_scene_start.cpp b/applications/infrared/scene/infrared_app_scene_start.cpp deleted file mode 100644 index 5efdce7a054a..000000000000 --- a/applications/infrared/scene/infrared_app_scene_start.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "../infrared_app.h" - -typedef enum { - SubmenuIndexUniversalLibrary, - SubmenuIndexLearnNewRemote, - SubmenuIndexSavedRemotes, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::MenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneStart::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item( - submenu, "Universal Library", SubmenuIndexUniversalLibrary, submenu_callback, app); - submenu_add_item( - submenu, "Learn New Remote", SubmenuIndexLearnNewRemote, submenu_callback, app); - submenu_add_item(submenu, "Saved Remotes", SubmenuIndexSavedRemotes, submenu_callback, app); - submenu_set_selected_item(submenu, submenu_item_selected); - - string_set_str(app->file_path, InfraredApp::infrared_directory); - submenu_item_selected = 0; - - view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu); -} - -bool InfraredAppSceneStart::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuIndexUniversalLibrary: - app->switch_to_next_scene(InfraredApp::Scene::Universal); - break; - case SubmenuIndexLearnNewRemote: - app->set_learn_new_remote(true); - app->switch_to_next_scene(InfraredApp::Scene::Learn); - break; - case SubmenuIndexSavedRemotes: - app->switch_to_next_scene(InfraredApp::Scene::RemoteList); - break; - default: - furi_assert(0); - break; - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneStart::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - app->get_remote_manager()->reset_remote(); - submenu_reset(submenu); -} diff --git a/applications/infrared/scene/infrared_app_scene_universal.cpp b/applications/infrared/scene/infrared_app_scene_universal.cpp deleted file mode 100644 index 57b5653a0f1c..000000000000 --- a/applications/infrared/scene/infrared_app_scene_universal.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "../infrared_app.h" - -typedef enum { - SubmenuIndexUniversalTV, - SubmenuIndexUniversalAudio, - SubmenuIndexUniversalAirConditioner, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::MenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void InfraredAppSceneUniversal::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item(submenu, "TVs", SubmenuIndexUniversalTV, submenu_callback, app); - submenu_set_selected_item(submenu, submenu_item_selected); - submenu_item_selected = 0; - - view_manager->switch_to(InfraredAppViewManager::ViewId::Submenu); -} - -bool InfraredAppSceneUniversal::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(event->type == InfraredAppEvent::Type::MenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuIndexUniversalTV: - app->switch_to_next_scene(InfraredApp::Scene::UniversalTV); - break; - case SubmenuIndexUniversalAudio: - // app->switch_to_next_scene(InfraredApp::Scene::UniversalAudio); - break; - case SubmenuIndexUniversalAirConditioner: - // app->switch_to_next_scene(InfraredApp::Scene::UniversalAirConditioner); - break; - } - consumed = true; - } - - return consumed; -} - -void InfraredAppSceneUniversal::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/infrared/scene/infrared_app_scene_universal_common.cpp b/applications/infrared/scene/infrared_app_scene_universal_common.cpp deleted file mode 100644 index 9e7a18f40c11..000000000000 --- a/applications/infrared/scene/infrared_app_scene_universal_common.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include -#include -#include -#include - -#include "../infrared_app.h" -#include "infrared/infrared_app_event.h" -#include "infrared/infrared_app_view_manager.h" -#include "infrared/scene/infrared_app_scene.h" -#include "../view/infrared_progress_view.h" - -void InfraredAppSceneUniversalCommon::infrared_app_item_callback(void* context, uint32_t index) { - InfraredApp* app = static_cast(context); - InfraredAppEvent event; - - event.type = InfraredAppEvent::Type::ButtonPanelPressed; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -static void infrared_progress_back_callback(void* context) { - furi_assert(context); - auto app = static_cast(context); - - InfraredAppEvent infrared_event = { - .payload = {.dummy = 0}, - .type = InfraredAppEvent::Type::Back, - }; - app->get_view_manager()->clear_events(); - app->get_view_manager()->send_event(&infrared_event); -} - -void InfraredAppSceneUniversalCommon::hide_popup(InfraredApp* app) { - auto stack_view = app->get_view_manager()->get_universal_view_stack(); - auto progress_view = app->get_view_manager()->get_progress(); - view_stack_remove_view(stack_view, infrared_progress_view_get_view(progress_view)); -} - -void InfraredAppSceneUniversalCommon::show_popup(InfraredApp* app, int record_amount) { - auto stack_view = app->get_view_manager()->get_universal_view_stack(); - auto progress_view = app->get_view_manager()->get_progress(); - infrared_progress_view_set_progress_total(progress_view, record_amount); - infrared_progress_view_set_back_callback(progress_view, infrared_progress_back_callback, app); - view_stack_add_view(stack_view, infrared_progress_view_get_view(progress_view)); -} - -bool InfraredAppSceneUniversalCommon::progress_popup(InfraredApp* app) { - auto progress_view = app->get_view_manager()->get_progress(); - return infrared_progress_view_increase_progress(progress_view); -} - -bool InfraredAppSceneUniversalCommon::on_event(InfraredApp* app, InfraredAppEvent* event) { - bool consumed = false; - - if(brute_force_started) { - if(event->type == InfraredAppEvent::Type::Tick) { - auto view_manager = app->get_view_manager(); - app->notify_blink_send(); - InfraredAppEvent tick_event = { - .payload = {.dummy = 0}, - .type = InfraredAppEvent::Type::Tick, - }; - view_manager->send_event(&tick_event); - bool result = brute_force.send_next_bruteforce(); - if(result) { - result = progress_popup(app); - } - if(!result) { - brute_force.stop_bruteforce(); - brute_force_started = false; - hide_popup(app); - } - consumed = true; - } else if(event->type == InfraredAppEvent::Type::Back) { - brute_force_started = false; - brute_force.stop_bruteforce(); - hide_popup(app); - consumed = true; - } - } else { - if(event->type == InfraredAppEvent::Type::ButtonPanelPressed) { - int record_amount = 0; - if(brute_force.start_bruteforce(event->payload.menu_index, record_amount)) { - DOLPHIN_DEED(DolphinDeedIrBruteForce); - brute_force_started = true; - show_popup(app, record_amount); - app->notify_blink_send(); - } else { - app->switch_to_previous_scene(); - } - consumed = true; - } else if(event->type == InfraredAppEvent::Type::Back) { - app->switch_to_previous_scene(); - consumed = true; - } - } - - return consumed; -} - -void InfraredAppSceneUniversalCommon::on_exit(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonPanel* button_panel = view_manager->get_button_panel(); - button_panel_reset(button_panel); -} diff --git a/applications/infrared/scene/infrared_app_scene_universal_tv.cpp b/applications/infrared/scene/infrared_app_scene_universal_tv.cpp deleted file mode 100644 index a12481ec975f..000000000000 --- a/applications/infrared/scene/infrared_app_scene_universal_tv.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include -#include -#include -#include "infrared/scene/infrared_app_scene.h" -#include "infrared/infrared_app.h" - -void InfraredAppSceneUniversalTV::on_enter(InfraredApp* app) { - InfraredAppViewManager* view_manager = app->get_view_manager(); - ButtonPanel* button_panel = view_manager->get_button_panel(); - button_panel_reserve(button_panel, 2, 3); - - int i = 0; - button_panel_add_item( - button_panel, - i, - 0, - 0, - 3, - 19, - &I_Power_25x27, - &I_Power_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "POWER"); - ++i; - button_panel_add_item( - button_panel, - i, - 1, - 0, - 36, - 19, - &I_Mute_25x27, - &I_Mute_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "MUTE"); - ++i; - button_panel_add_item( - button_panel, - i, - 0, - 1, - 3, - 66, - &I_Vol_up_25x27, - &I_Vol_up_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "VOL+"); - ++i; - button_panel_add_item( - button_panel, - i, - 1, - 1, - 36, - 66, - &I_Up_25x27, - &I_Up_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "CH+"); - ++i; - button_panel_add_item( - button_panel, - i, - 0, - 2, - 3, - 98, - &I_Vol_down_25x27, - &I_Vol_down_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "VOL-"); - ++i; - button_panel_add_item( - button_panel, - i, - 1, - 2, - 36, - 98, - &I_Down_25x27, - &I_Down_hvr_25x27, - infrared_app_item_callback, - app); - brute_force.add_record(i, "CH-"); - - button_panel_add_label(button_panel, 6, 11, FontPrimary, "TV remote"); - button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol"); - button_panel_add_label(button_panel, 43, 64, FontSecondary, "Ch"); - - view_manager->switch_to(InfraredAppViewManager::ViewId::UniversalRemote); - - auto stack_view = app->get_view_manager()->get_universal_view_stack(); - auto loading_view = app->get_view_manager()->get_loading(); - view_stack_add_view(stack_view, loading_get_view(loading_view)); - - /** - * Problem: Update events are not handled in Loading View, because: - * 1) Timer task has least prio - * 2) Storage service uses drivers that capture whole CPU time - * to handle SD communication - * - * Ugly workaround, but it works for current situation: - * raise timer task prio for DB scanning period. - */ - TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); - TaskHandle_t storage_task = xTaskGetHandle("StorageSrv"); - uint32_t timer_prio = uxTaskPriorityGet(timer_task); - uint32_t storage_prio = uxTaskPriorityGet(storage_task); - vTaskPrioritySet(timer_task, storage_prio + 1); - bool result = brute_force.calculate_messages(); - vTaskPrioritySet(timer_task, timer_prio); - - view_stack_remove_view(stack_view, loading_get_view(loading_view)); - - if(!result) { - app->switch_to_previous_scene(); - } -} diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.c b/applications/infrared/scenes/common/infrared_scene_universal_common.c new file mode 100644 index 000000000000..f0e690308d97 --- /dev/null +++ b/applications/infrared/scenes/common/infrared_scene_universal_common.c @@ -0,0 +1,92 @@ +#include "../../infrared_i.h" + +#include + +void infrared_scene_universal_common_item_callback(void* context, uint32_t index) { + Infrared* infrared = context; + uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeButtonSelected, index); + view_dispatcher_send_custom_event(infrared->view_dispatcher, event); +} + +static void infrared_scene_universal_common_progress_back_callback(void* context) { + Infrared* infrared = context; + uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeBackPressed, -1); + view_dispatcher_send_custom_event(infrared->view_dispatcher, event); +} + +static void infrared_scene_universal_common_show_popup(Infrared* infrared, uint32_t record_count) { + ViewStack* view_stack = infrared->view_stack; + InfraredProgressView* progress = infrared->progress; + infrared_progress_view_set_progress_total(progress, record_count); + infrared_progress_view_set_back_callback( + progress, infrared_scene_universal_common_progress_back_callback, infrared); + view_stack_add_view(view_stack, infrared_progress_view_get_view(progress)); +} + +static void infrared_scene_universal_common_hide_popup(Infrared* infrared) { + ViewStack* view_stack = infrared->view_stack; + InfraredProgressView* progress = infrared->progress; + view_stack_remove_view(view_stack, infrared_progress_view_get_view(progress)); +} + +void infrared_scene_universal_common_on_enter(void* context) { + Infrared* infrared = context; + view_stack_add_view(infrared->view_stack, button_panel_get_view(infrared->button_panel)); +} + +bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + InfraredBruteForce* brute_force = infrared->brute_force; + bool consumed = false; + + if(infrared_brute_force_is_started(brute_force)) { + if(event.type == SceneManagerEventTypeTick) { + infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend); + bool success = infrared_brute_force_send_next(brute_force); + if(success) { + success = infrared_progress_view_increase_progress(infrared->progress); + } + if(!success) { + infrared_brute_force_stop(brute_force); + infrared_scene_universal_common_hide_popup(infrared); + } + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(infrared_custom_event_get_type(event.event) == InfraredCustomEventTypeBackPressed) { + infrared_brute_force_stop(brute_force); + infrared_scene_universal_common_hide_popup(infrared); + consumed = true; + } + } + } else { + if(event.type == SceneManagerEventTypeBack) { + scene_manager_previous_scene(scene_manager); + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(infrared_custom_event_get_type(event.event) == + InfraredCustomEventTypeButtonSelected) { + uint32_t record_count; + if(infrared_brute_force_start( + brute_force, infrared_custom_event_get_value(event.event), &record_count)) { + DOLPHIN_DEED(DolphinDeedIrBruteForce); + infrared_scene_universal_common_show_popup(infrared, record_count); + infrared_play_notification_message( + infrared, InfraredNotificationMessageBlinkSend); + } else { + scene_manager_previous_scene(scene_manager); + } + consumed = true; + } + } + } + + return consumed; +} + +void infrared_scene_universal_common_on_exit(void* context) { + Infrared* infrared = context; + ButtonPanel* button_panel = infrared->button_panel; + view_stack_remove_view(infrared->view_stack, button_panel_get_view(button_panel)); + button_panel_reset(button_panel); +} diff --git a/applications/infrared/scenes/common/infrared_scene_universal_common.h b/applications/infrared/scenes/common/infrared_scene_universal_common.h new file mode 100644 index 000000000000..a6c697d7742c --- /dev/null +++ b/applications/infrared/scenes/common/infrared_scene_universal_common.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +void infrared_scene_universal_common_on_enter(void* context); +bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent event); +void infrared_scene_universal_common_on_exit(void* context); +void infrared_scene_universal_common_item_callback(void* context, uint32_t index); diff --git a/applications/infrared/scenes/infrared_scene.c b/applications/infrared/scenes/infrared_scene.c new file mode 100644 index 000000000000..b0f298e69be3 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene.c @@ -0,0 +1,30 @@ +#include "infrared_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const infrared_on_enter_handlers[])(void*) = { +#include "infrared_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const infrared_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "infrared_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const infrared_on_exit_handlers[])(void* context) = { +#include "infrared_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers infrared_scene_handlers = { + .on_enter_handlers = infrared_on_enter_handlers, + .on_event_handlers = infrared_on_event_handlers, + .on_exit_handlers = infrared_on_exit_handlers, + .scene_num = InfraredSceneNum, +}; diff --git a/applications/infrared/scenes/infrared_scene.h b/applications/infrared/scenes/infrared_scene.h new file mode 100644 index 000000000000..e9d499a7acf6 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) InfraredScene##id, +typedef enum { +#include "infrared_scene_config.h" + InfraredSceneNum, +} InfraredScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers infrared_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "infrared_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "infrared_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "infrared_scene_config.h" +#undef ADD_SCENE diff --git a/applications/infrared/scenes/infrared_scene_ask_back.c b/applications/infrared/scenes/infrared_scene_ask_back.c new file mode 100644 index 000000000000..11cfcb04d7a7 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_ask_back.c @@ -0,0 +1,59 @@ +#include "../infrared_i.h" + +static void infrared_scene_dialog_result_callback(DialogExResult result, void* context) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, result); +} + +void infrared_scene_ask_back_on_enter(void* context) { + Infrared* infrared = context; + DialogEx* dialog_ex = infrared->dialog_ex; + + if(infrared->app_state.is_learning_new_remote) { + dialog_ex_set_header(dialog_ex, "Exit to Infrared menu?", 64, 0, AlignCenter, AlignTop); + } else { + dialog_ex_set_header(dialog_ex, "Exit to remote menu?", 64, 0, AlignCenter, AlignTop); + } + + dialog_ex_set_text( + dialog_ex, "All unsaved data\nwill be lost", 64, 31, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 0, 0, NULL); + dialog_ex_set_left_button_text(dialog_ex, "Exit"); + dialog_ex_set_center_button_text(dialog_ex, NULL); + dialog_ex_set_right_button_text(dialog_ex, "Stay"); + dialog_ex_set_result_callback(dialog_ex, infrared_scene_dialog_result_callback); + dialog_ex_set_context(dialog_ex, context); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); +} + +bool infrared_scene_ask_back_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultLeft) { + if(infrared->app_state.is_learning_new_remote) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneStart); + } else { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneRemote); + } + consumed = true; + } else if(event.event == DialogExResultRight) { + scene_manager_previous_scene(scene_manager); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_ask_back_on_exit(void* context) { + Infrared* infrared = context; + dialog_ex_reset(infrared->dialog_ex); +} diff --git a/applications/infrared/scenes/infrared_scene_config.h b/applications/infrared/scenes/infrared_scene_config.h new file mode 100644 index 000000000000..3677ab3c9fcb --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_config.h @@ -0,0 +1,17 @@ +ADD_SCENE(infrared, start, Start) +ADD_SCENE(infrared, ask_back, AskBack) +ADD_SCENE(infrared, edit, Edit) +ADD_SCENE(infrared, edit_delete, EditDelete) +ADD_SCENE(infrared, edit_delete_done, EditDeleteDone) +ADD_SCENE(infrared, edit_button_select, EditButtonSelect) +ADD_SCENE(infrared, edit_rename, EditRename) +ADD_SCENE(infrared, edit_rename_done, EditRenameDone) +ADD_SCENE(infrared, learn, Learn) +ADD_SCENE(infrared, learn_done, LearnDone) +ADD_SCENE(infrared, learn_enter_name, LearnEnterName) +ADD_SCENE(infrared, learn_success, LearnSuccess) +ADD_SCENE(infrared, remote, Remote) +ADD_SCENE(infrared, remote_list, RemoteList) +ADD_SCENE(infrared, universal, Universal) +ADD_SCENE(infrared, universal_tv, UniversalTV) +ADD_SCENE(infrared, debug, Debug) diff --git a/applications/infrared/scenes/infrared_scene_debug.c b/applications/infrared/scenes/infrared_scene_debug.c new file mode 100644 index 000000000000..ddb85644b03c --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_debug.c @@ -0,0 +1,68 @@ +#include "../infrared_i.h" + +void infrared_scene_debug_on_enter(void* context) { + Infrared* infrared = context; + InfraredWorker* worker = infrared->worker; + + infrared_worker_rx_set_received_signal_callback( + worker, infrared_signal_received_callback, context); + infrared_worker_rx_enable_blink_on_receiving(worker, true); + infrared_worker_rx_start(worker); + + infrared_debug_view_set_text(infrared->debug_view, "Received signals\nwill appear here"); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDebugView); +} + +bool infrared_scene_debug_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypeSignalReceived) { + InfraredDebugView* debug_view = infrared->debug_view; + InfraredSignal* signal = infrared->received_signal; + + if(infrared_signal_is_raw(signal)) { + InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + infrared_debug_view_set_text(debug_view, "RAW\n%d samples\n", raw->timings_size); + + printf("RAW, %d samples:\r\n", raw->timings_size); + for(size_t i = 0; i < raw->timings_size; ++i) { + printf("%lu ", raw->timings[i]); + } + printf("\r\n"); + + } else { + InfraredMessage* message = infrared_signal_get_message(signal); + infrared_debug_view_set_text( + debug_view, + "%s\nA:0x%0*lX\nC:0x%0*lX\n%s\n", + infrared_get_protocol_name(message->protocol), + ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), + message->address, + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), + message->command, + message->repeat ? " R" : ""); + + printf( + "== %s, A:0x%0*lX, C:0x%0*lX%s ==\r\n", + infrared_get_protocol_name(message->protocol), + ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), + message->address, + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), + message->command, + message->repeat ? " R" : ""); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_debug_on_exit(void* context) { + Infrared* infrared = context; + InfraredWorker* worker = infrared->worker; + infrared_worker_rx_stop(worker); + infrared_worker_rx_enable_blink_on_receiving(worker, false); +} diff --git a/applications/infrared/scenes/infrared_scene_edit.c b/applications/infrared/scenes/infrared_scene_edit.c new file mode 100644 index 000000000000..360ed49b351e --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit.c @@ -0,0 +1,101 @@ +#include "../infrared_i.h" + +typedef enum { + SubmenuIndexAddButton, + SubmenuIndexRenameButton, + SubmenuIndexDeleteButton, + SubmenuIndexRenameRemote, + SubmenuIndexDeleteRemote, +} SubmenuIndex; + +static void infrared_scene_edit_submenu_callback(void* context, uint32_t index) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, index); +} + +void infrared_scene_edit_on_enter(void* context) { + Infrared* infrared = context; + Submenu* submenu = infrared->submenu; + SceneManager* scene_manager = infrared->scene_manager; + + submenu_add_item( + submenu, + "Add Button", + SubmenuIndexAddButton, + infrared_scene_edit_submenu_callback, + context); + submenu_add_item( + submenu, + "Rename Button", + SubmenuIndexRenameButton, + infrared_scene_edit_submenu_callback, + context); + submenu_add_item( + submenu, + "Delete Button", + SubmenuIndexDeleteButton, + infrared_scene_edit_submenu_callback, + context); + submenu_add_item( + submenu, + "Rename Remote", + SubmenuIndexRenameRemote, + infrared_scene_edit_submenu_callback, + context); + submenu_add_item( + submenu, + "Delete Remote", + SubmenuIndexDeleteRemote, + infrared_scene_edit_submenu_callback, + context); + + const uint32_t submenu_index = scene_manager_get_scene_state(scene_manager, InfraredSceneEdit); + submenu_set_selected_item(submenu, submenu_index); + scene_manager_set_scene_state(scene_manager, InfraredSceneEdit, SubmenuIndexAddButton); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); +} + +bool infrared_scene_edit_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + const uint32_t submenu_index = event.event; + scene_manager_set_scene_state(scene_manager, InfraredSceneEdit, submenu_index); + + if(submenu_index == SubmenuIndexAddButton) { + infrared->app_state.is_learning_new_remote = false; + scene_manager_next_scene(scene_manager, InfraredSceneLearn); + consumed = true; + } else if(submenu_index == SubmenuIndexRenameButton) { + infrared->app_state.edit_target = InfraredEditTargetButton; + infrared->app_state.edit_mode = InfraredEditModeRename; + scene_manager_next_scene(scene_manager, InfraredSceneEditButtonSelect); + consumed = true; + } else if(submenu_index == SubmenuIndexDeleteButton) { + infrared->app_state.edit_target = InfraredEditTargetButton; + infrared->app_state.edit_mode = InfraredEditModeDelete; + scene_manager_next_scene(scene_manager, InfraredSceneEditButtonSelect); + consumed = true; + } else if(submenu_index == SubmenuIndexRenameRemote) { + infrared->app_state.edit_target = InfraredEditTargetRemote; + infrared->app_state.edit_mode = InfraredEditModeRename; + scene_manager_next_scene(scene_manager, InfraredSceneEditRename); + consumed = true; + } else if(submenu_index == SubmenuIndexDeleteRemote) { + infrared->app_state.edit_target = InfraredEditTargetRemote; + infrared->app_state.edit_mode = InfraredEditModeDelete; + scene_manager_next_scene(scene_manager, InfraredSceneEditDelete); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_on_exit(void* context) { + Infrared* infrared = context; + submenu_reset(infrared->submenu); +} diff --git a/applications/infrared/scenes/infrared_scene_edit_button_select.c b/applications/infrared/scenes/infrared_scene_edit_button_select.c new file mode 100644 index 000000000000..a7f8a2bf7aac --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_button_select.c @@ -0,0 +1,63 @@ +#include "../infrared_i.h" + +static void infrared_scene_edit_button_select_submenu_callback(void* context, uint32_t index) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, index); +} + +void infrared_scene_edit_button_select_on_enter(void* context) { + Infrared* infrared = context; + Submenu* submenu = infrared->submenu; + InfraredRemote* remote = infrared->remote; + InfraredAppState* app_state = &infrared->app_state; + + const char* header = infrared->app_state.edit_mode == InfraredEditModeRename ? + "Rename Button:" : + "Delete Button:"; + submenu_set_header(submenu, header); + + const size_t button_count = infrared_remote_get_button_count(remote); + for(size_t i = 0; i < button_count; ++i) { + InfraredRemoteButton* button = infrared_remote_get_button(remote, i); + submenu_add_item( + submenu, + infrared_remote_button_get_name(button), + i, + infrared_scene_edit_button_select_submenu_callback, + context); + } + + if(button_count && app_state->current_button_index != InfraredButtonIndexNone) { + submenu_set_selected_item(submenu, app_state->current_button_index); + app_state->current_button_index = InfraredButtonIndexNone; + } + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); +} + +bool infrared_scene_edit_button_select_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + InfraredAppState* app_state = &infrared->app_state; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + app_state->current_button_index = event.event; + const InfraredEditMode edit_mode = app_state->edit_mode; + if(edit_mode == InfraredEditModeRename) { + scene_manager_next_scene(scene_manager, InfraredSceneEditRename); + } else if(edit_mode == InfraredEditModeDelete) { + scene_manager_next_scene(scene_manager, InfraredSceneEditDelete); + } else { + furi_assert(0); + } + consumed = true; + } + + return consumed; +} + +void infrared_scene_edit_button_select_on_exit(void* context) { + Infrared* infrared = context; + submenu_reset(infrared->submenu); +} diff --git a/applications/infrared/scenes/infrared_scene_edit_delete.c b/applications/infrared/scenes/infrared_scene_edit_delete.c new file mode 100644 index 000000000000..0842cd613c06 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_delete.c @@ -0,0 +1,112 @@ +#include "../infrared_i.h" + +static void + infrared_scene_edit_delete_dialog_result_callback(DialogExResult result, void* context) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, result); +} + +void infrared_scene_edit_delete_on_enter(void* context) { + Infrared* infrared = context; + DialogEx* dialog_ex = infrared->dialog_ex; + InfraredRemote* remote = infrared->remote; + + const InfraredEditTarget edit_target = infrared->app_state.edit_target; + if(edit_target == InfraredEditTargetButton) { + int32_t current_button_index = infrared->app_state.current_button_index; + furi_assert(current_button_index != InfraredButtonIndexNone); + + dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop); + InfraredRemoteButton* current_button = + infrared_remote_get_button(remote, current_button_index); + InfraredSignal* signal = infrared_remote_button_get_signal(current_button); + + if(infrared_signal_is_raw(signal)) { + const InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + infrared_text_store_set( + infrared, + 0, + "%s\nRAW\n%ld samples", + infrared_remote_button_get_name(current_button), + raw->timings_size); + + } else { + const InfraredMessage* message = infrared_signal_get_message(signal); + infrared_text_store_set( + infrared, + 0, + "%s\n%s\nA=0x%0*lX C=0x%0*lX", + infrared_remote_button_get_name(current_button), + infrared_get_protocol_name(message->protocol), + ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), + message->address, + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), + message->command); + } + + } else if(edit_target == InfraredEditTargetRemote) { + dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 0, AlignCenter, AlignTop); + infrared_text_store_set( + infrared, + 0, + "%s\n with %lu buttons", + infrared_remote_get_name(remote), + infrared_remote_get_button_count(remote)); + } else { + furi_assert(0); + } + + dialog_ex_set_text(dialog_ex, infrared->text_store[0], 64, 31, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 0, 0, NULL); + dialog_ex_set_left_button_text(dialog_ex, "Cancel"); + dialog_ex_set_right_button_text(dialog_ex, "Delete"); + dialog_ex_set_result_callback(dialog_ex, infrared_scene_edit_delete_dialog_result_callback); + dialog_ex_set_context(dialog_ex, context); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); +} + +bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultLeft) { + scene_manager_previous_scene(scene_manager); + consumed = true; + } else if(event.event == DialogExResultRight) { + bool success = false; + InfraredRemote* remote = infrared->remote; + InfraredAppState* app_state = &infrared->app_state; + const InfraredEditTarget edit_target = app_state->edit_target; + + if(edit_target == InfraredEditTargetButton) { + furi_assert(app_state->current_button_index != InfraredButtonIndexNone); + success = infrared_remote_delete_button(remote, app_state->current_button_index); + app_state->current_button_index = InfraredButtonIndexNone; + } else if(edit_target == InfraredEditTargetRemote) { + success = infrared_remote_remove(remote); + app_state->current_button_index = InfraredButtonIndexNone; + } else { + furi_assert(0); + } + + if(success) { + scene_manager_next_scene(scene_manager, InfraredSceneEditDeleteDone); + } else { + const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; + scene_manager_search_and_switch_to_previous_scene_one_of( + scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_delete_on_exit(void* context) { + Infrared* infrared = context; + UNUSED(infrared); +} diff --git a/applications/infrared/scenes/infrared_scene_edit_delete_done.c b/applications/infrared/scenes/infrared_scene_edit_delete_done.c new file mode 100644 index 000000000000..688c3a45701e --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_delete_done.c @@ -0,0 +1,46 @@ +#include "../infrared_i.h" + +void infrared_scene_edit_delete_done_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + + popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + + popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_context(popup, context); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_edit_delete_done_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypePopupTimeout) { + const InfraredEditTarget edit_target = infrared->app_state.edit_target; + if(edit_target == InfraredEditTargetButton) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneRemote); + } else if(edit_target == InfraredEditTargetRemote) { + const uint32_t possible_scenes[] = {InfraredSceneStart, InfraredSceneRemoteList}; + scene_manager_search_and_switch_to_previous_scene_one_of( + scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); + } else { + furi_assert(0); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_delete_done_on_exit(void* context) { + Infrared* infrared = context; + UNUSED(infrared); +} diff --git a/applications/infrared/scenes/infrared_scene_edit_rename.c b/applications/infrared/scenes/infrared_scene_edit_rename.c new file mode 100644 index 000000000000..ebe7c2a96d42 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_rename.c @@ -0,0 +1,107 @@ +#include "../infrared_i.h" + +#include +#include + +void infrared_scene_edit_rename_on_enter(void* context) { + Infrared* infrared = context; + InfraredRemote* remote = infrared->remote; + TextInput* text_input = infrared->text_input; + size_t enter_name_length = 0; + + const InfraredEditTarget edit_target = infrared->app_state.edit_target; + if(edit_target == InfraredEditTargetButton) { + text_input_set_header_text(text_input, "Name the button"); + + const int32_t current_button_index = infrared->app_state.current_button_index; + furi_assert(current_button_index != InfraredButtonIndexNone); + + InfraredRemoteButton* current_button = + infrared_remote_get_button(remote, current_button_index); + enter_name_length = INFRARED_MAX_BUTTON_NAME_LENGTH; + strncpy( + infrared->text_store[0], + infrared_remote_button_get_name(current_button), + enter_name_length); + + } else if(edit_target == InfraredEditTargetRemote) { + text_input_set_header_text(text_input, "Name the remote"); + enter_name_length = INFRARED_MAX_REMOTE_NAME_LENGTH; + strncpy(infrared->text_store[0], infrared_remote_get_name(remote), enter_name_length); + + string_t folder_path; + string_init(folder_path); + + if(string_end_with_str_p(infrared->file_path, INFRARED_APP_EXTENSION)) { + path_extract_dirname(string_get_cstr(infrared->file_path), folder_path); + } + + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + string_get_cstr(folder_path), + INFRARED_APP_EXTENSION, + infrared_remote_get_name(remote)); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + string_clear(folder_path); + } else { + furi_assert(0); + } + + text_input_set_result_callback( + text_input, + infrared_text_input_callback, + context, + infrared->text_store[0], + enter_name_length, + false); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewTextInput); +} + +bool infrared_scene_edit_rename_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + InfraredRemote* remote = infrared->remote; + SceneManager* scene_manager = infrared->scene_manager; + InfraredAppState* app_state = &infrared->app_state; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypeTextEditDone) { + bool success = false; + const InfraredEditTarget edit_target = app_state->edit_target; + if(edit_target == InfraredEditTargetButton) { + const int32_t current_button_index = app_state->current_button_index; + furi_assert(current_button_index != InfraredButtonIndexNone); + success = infrared_remote_rename_button( + remote, infrared->text_store[0], current_button_index); + app_state->current_button_index = InfraredButtonIndexNone; + } else if(edit_target == InfraredEditTargetRemote) { + success = infrared_rename_current_remote(infrared, infrared->text_store[0]); + } else { + furi_assert(0); + } + + if(success) { + scene_manager_next_scene(scene_manager, InfraredSceneEditRenameDone); + } else { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneRemoteList); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_rename_on_exit(void* context) { + Infrared* infrared = context; + TextInput* text_input = infrared->text_input; + + void* validator_context = text_input_get_validator_callback_context(text_input); + text_input_set_validator(text_input, NULL, NULL); + + if(validator_context) { + validator_is_file_free((ValidatorIsFile*)validator_context); + } +} diff --git a/applications/infrared/scenes/infrared_scene_edit_rename_done.c b/applications/infrared/scenes/infrared_scene_edit_rename_done.c new file mode 100644 index 000000000000..60a26954d725 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_edit_rename_done.c @@ -0,0 +1,35 @@ +#include "../infrared_i.h" + +void infrared_scene_edit_rename_done_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + + popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_context(popup, context); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_edit_rename_done_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypePopupTimeout) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_edit_rename_done_on_exit(void* context) { + Infrared* infrared = context; + UNUSED(infrared); +} diff --git a/applications/infrared/scenes/infrared_scene_learn.c b/applications/infrared/scenes/infrared_scene_learn.c new file mode 100644 index 000000000000..d91b8676a956 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_learn.c @@ -0,0 +1,46 @@ +#include "../infrared_i.h" + +void infrared_scene_learn_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + InfraredWorker* worker = infrared->worker; + + infrared_worker_rx_set_received_signal_callback( + worker, infrared_signal_received_callback, context); + infrared_worker_rx_start(worker); + + popup_set_icon(popup, 0, 32, &I_InfraredLearnShort_128x31); + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignCenter); + popup_set_text( + popup, "Point the remote at IR port\nand push the button", 5, 10, AlignLeft, AlignCenter); + popup_set_callback(popup, NULL); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkRead); + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypeSignalReceived) { + infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL); + infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); + scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_learn_on_exit(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + infrared_worker_rx_stop(infrared->worker); + popup_set_icon(popup, 0, 0, NULL); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter); +} diff --git a/applications/infrared/scenes/infrared_scene_learn_done.c b/applications/infrared/scenes/infrared_scene_learn_done.c new file mode 100644 index 000000000000..a24bb9184007 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_learn_done.c @@ -0,0 +1,44 @@ +#include "../infrared_i.h" + +#include + +void infrared_scene_learn_done_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + DOLPHIN_DEED(DolphinDeedIrSave); + + if(infrared->app_state.is_learning_new_remote) { + popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); + } else { + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + } + + popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_context(popup, context); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_learn_done_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypePopupTimeout) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_learn_done_on_exit(void* context) { + Infrared* infrared = context; + infrared->app_state.is_learning_new_remote = false; + popup_set_header(infrared->popup, NULL, 0, 0, AlignLeft, AlignTop); +} diff --git a/applications/infrared/scenes/infrared_scene_learn_enter_name.c b/applications/infrared/scenes/infrared_scene_learn_enter_name.c new file mode 100644 index 000000000000..b7f4179ea2d7 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_learn_enter_name.c @@ -0,0 +1,66 @@ +#include "../infrared_i.h" + +void infrared_scene_learn_enter_name_on_enter(void* context) { + Infrared* infrared = context; + TextInput* text_input = infrared->text_input; + InfraredSignal* signal = infrared->received_signal; + + if(infrared_signal_is_raw(signal)) { + InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + infrared_text_store_set(infrared, 0, "RAW_%d", raw->timings_size); + } else { + InfraredMessage* message = infrared_signal_get_message(signal); + infrared_text_store_set( + infrared, + 0, + "%.4s_%0*lX", + infrared_get_protocol_name(message->protocol), + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), + message->command); + } + + text_input_set_header_text(text_input, "Name the button"); + text_input_set_result_callback( + text_input, + infrared_text_input_callback, + context, + infrared->text_store[0], + INFRARED_MAX_BUTTON_NAME_LENGTH, + true); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewTextInput); +} + +bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + InfraredSignal* signal = infrared->received_signal; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypeTextEditDone) { + bool success = false; + if(infrared->app_state.is_learning_new_remote) { + success = + infrared_add_remote_with_button(infrared, infrared->text_store[0], signal); + } else { + success = + infrared_remote_add_button(infrared->remote, infrared->text_store[0], signal); + } + + if(success) { + scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); + } else { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneRemoteList); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_learn_enter_name_on_exit(void* context) { + Infrared* infrared = context; + UNUSED(infrared); +} diff --git a/applications/infrared/scenes/infrared_scene_learn_success.c b/applications/infrared/scenes/infrared_scene_learn_success.c new file mode 100644 index 000000000000..ec950ca71720 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_learn_success.c @@ -0,0 +1,131 @@ +#include "../infrared_i.h" + +#include + +typedef enum { + InfraredSceneLearnSuccessStateIdle = 0, + InfraredSceneLearnSuccessStateSending = 1, +} InfraredSceneLearnSuccessState; + +static void + infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, result); +} + +void infrared_scene_learn_success_on_enter(void* context) { + Infrared* infrared = context; + DialogEx* dialog_ex = infrared->dialog_ex; + InfraredSignal* signal = infrared->received_signal; + + DOLPHIN_DEED(DolphinDeedIrLearnSuccess); + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); + + infrared_worker_tx_set_get_signal_callback( + infrared->worker, infrared_worker_tx_get_signal_steady_callback, context); + infrared_worker_tx_set_signal_sent_callback( + infrared->worker, infrared_signal_sent_callback, context); + + if(infrared_signal_is_raw(signal)) { + InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); + infrared_text_store_set(infrared, 0, "%d samples", raw->timings_size); + dialog_ex_set_text(dialog_ex, infrared->text_store[0], 75, 23, AlignLeft, AlignTop); + + } else { + InfraredMessage* message = infrared_signal_get_message(signal); + uint8_t addr_digits = + ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4); + uint8_t cmd_digits = + ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4); + uint8_t max_digits = MAX(addr_digits, cmd_digits); + max_digits = MIN(max_digits, 7); + size_t label_x_offset = 63 + (7 - max_digits) * 3; + + infrared_text_store_set(infrared, 0, "%s", infrared_get_protocol_name(message->protocol)); + infrared_text_store_set( + infrared, + 1, + "A: 0x%0*lX\nC: 0x%0*lX\n", + addr_digits, + message->address, + cmd_digits, + message->command); + + dialog_ex_set_header(dialog_ex, infrared->text_store[0], 95, 7, AlignCenter, AlignCenter); + dialog_ex_set_text( + dialog_ex, infrared->text_store[1], label_x_offset, 34, AlignLeft, AlignCenter); + } + + dialog_ex_set_left_button_text(dialog_ex, "Retry"); + dialog_ex_set_right_button_text(dialog_ex, "Save"); + dialog_ex_set_center_button_text(dialog_ex, "Send"); + dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63); + dialog_ex_set_result_callback(dialog_ex, infrared_scene_learn_success_dialog_result_callback); + dialog_ex_set_context(dialog_ex, context); + dialog_ex_enable_extended_events(dialog_ex); + + scene_manager_set_scene_state( + infrared->scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); +} + +bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + uint32_t scene_state = scene_manager_get_scene_state(scene_manager, InfraredSceneLearnSuccess); + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); + } + consumed = true; + } else if(event.type == SceneManagerEventTypeBack) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + scene_manager_next_scene(scene_manager, InfraredSceneAskBack); + } + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultLeft) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + scene_manager_search_and_switch_to_previous_scene( + scene_manager, InfraredSceneLearn); + } + consumed = true; + } else if(event.event == DialogExResultRight) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + scene_manager_next_scene(scene_manager, InfraredSceneLearnEnterName); + } + consumed = true; + } else if(event.event == DialogExPressCenter) { + if(scene_state == InfraredSceneLearnSuccessStateIdle) { + scene_manager_set_scene_state( + scene_manager, + InfraredSceneLearnSuccess, + InfraredSceneLearnSuccessStateSending); + infrared_tx_start_received(infrared); + } + consumed = true; + } else if(event.event == DialogExReleaseCenter) { + if(scene_state == InfraredSceneLearnSuccessStateSending) { + scene_manager_set_scene_state( + scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle); + infrared_tx_stop(infrared); + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); + } + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_learn_success_on_exit(void* context) { + Infrared* infrared = context; + InfraredWorker* worker = infrared->worker; + dialog_ex_reset(infrared->dialog_ex); + infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); + infrared_worker_tx_set_get_signal_callback(worker, NULL, NULL); + infrared_worker_tx_set_signal_sent_callback(worker, NULL, NULL); +} diff --git a/applications/infrared/scenes/infrared_scene_remote.c b/applications/infrared/scenes/infrared_scene_remote.c new file mode 100644 index 000000000000..0b7a1ad939d0 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_remote.c @@ -0,0 +1,119 @@ +#include "../infrared_i.h" + +typedef enum { + ButtonIndexPlus = -2, + ButtonIndexEdit = -1, + ButtonIndexNA = 0, +} ButtonIndex; + +static void + infrared_scene_remote_button_menu_callback(void* context, int32_t index, InputType type) { + Infrared* infrared = context; + + uint16_t custom_type; + if(type == InputTypePress) { + custom_type = InfraredCustomEventTypeTransmitStarted; + } else if(type == InputTypeRelease) { + custom_type = InfraredCustomEventTypeTransmitStopped; + } else if(type == InputTypeShort) { + custom_type = InfraredCustomEventTypeMenuSelected; + } else { + furi_crash("Unexpected input type"); + } + + view_dispatcher_send_custom_event( + infrared->view_dispatcher, infrared_custom_event_pack(custom_type, index)); +} + +void infrared_scene_remote_on_enter(void* context) { + Infrared* infrared = context; + InfraredRemote* remote = infrared->remote; + ButtonMenu* button_menu = infrared->button_menu; + SceneManager* scene_manager = infrared->scene_manager; + + infrared_worker_tx_set_get_signal_callback( + infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); + infrared_worker_tx_set_signal_sent_callback( + infrared->worker, infrared_signal_sent_callback, infrared); + + size_t button_count = infrared_remote_get_button_count(remote); + for(size_t i = 0; i < button_count; ++i) { + InfraredRemoteButton* button = infrared_remote_get_button(remote, i); + button_menu_add_item( + button_menu, + infrared_remote_button_get_name(button), + i, + infrared_scene_remote_button_menu_callback, + ButtonMenuItemTypeCommon, + context); + } + + button_menu_add_item( + button_menu, + "+", + ButtonIndexPlus, + infrared_scene_remote_button_menu_callback, + ButtonMenuItemTypeControl, + context); + button_menu_add_item( + button_menu, + "Edit", + ButtonIndexEdit, + infrared_scene_remote_button_menu_callback, + ButtonMenuItemTypeControl, + context); + + button_menu_set_header(button_menu, infrared_remote_get_name(remote)); + const int16_t button_index = + (signed)scene_manager_get_scene_state(scene_manager, InfraredSceneRemote); + button_menu_set_selected_item(button_menu, button_index); + scene_manager_set_scene_state(scene_manager, InfraredSceneRemote, ButtonIndexNA); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewButtonMenu); +} + +bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; + scene_manager_search_and_switch_to_previous_scene_one_of( + scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); + consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + const uint16_t custom_type = infrared_custom_event_get_type(event.event); + const int16_t button_index = infrared_custom_event_get_value(event.event); + + if(custom_type == InfraredCustomEventTypeTransmitStarted) { + furi_assert(button_index >= 0); + infrared_tx_start_button_index(infrared, button_index); + consumed = true; + } else if(custom_type == InfraredCustomEventTypeTransmitStopped) { + infrared_tx_stop(infrared); + consumed = true; + } else if(custom_type == InfraredCustomEventTypeMenuSelected) { + furi_assert(button_index < 0); + scene_manager_set_scene_state( + scene_manager, InfraredSceneRemote, (unsigned)button_index); + if(button_index == ButtonIndexPlus) { + infrared->app_state.is_learning_new_remote = false; + scene_manager_next_scene(scene_manager, InfraredSceneLearn); + consumed = true; + } else if(button_index == ButtonIndexEdit) { + scene_manager_next_scene(scene_manager, InfraredSceneEdit); + consumed = true; + } + } + } + + return consumed; +} + +void infrared_scene_remote_on_exit(void* context) { + Infrared* infrared = context; + infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL); + infrared_worker_tx_set_signal_sent_callback(infrared->worker, NULL, NULL); + button_menu_reset(infrared->button_menu); +} diff --git a/applications/infrared/scenes/infrared_scene_remote_list.c b/applications/infrared/scenes/infrared_scene_remote_list.c new file mode 100644 index 000000000000..25b37759c31f --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_remote_list.c @@ -0,0 +1,44 @@ +#include "../infrared_i.h" + +void infrared_scene_remote_list_on_enter(void* context) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + ViewDispatcher* view_dispatcher = infrared->view_dispatcher; + + string_set_str(infrared->file_path, INFRARED_APP_FOLDER); + bool success = dialog_file_browser_show( + infrared->dialogs, + infrared->file_path, + infrared->file_path, + INFRARED_APP_EXTENSION, + true, + &I_ir_10px, + true); + + if(success) { + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationHorizontal); + view_dispatcher_switch_to_view(view_dispatcher, InfraredViewStack); + + infrared_show_loading_popup(infrared, true); + success = infrared_remote_load(infrared->remote, infrared->file_path); + infrared_show_loading_popup(infrared, false); + } + + if(success) { + scene_manager_next_scene(scene_manager, InfraredSceneRemote); + } else { + scene_manager_previous_scene(scene_manager); + } +} + +bool infrared_scene_remote_list_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + + return consumed; +} + +void infrared_scene_remote_list_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/infrared/scenes/infrared_scene_start.c b/applications/infrared/scenes/infrared_scene_start.c new file mode 100644 index 000000000000..6b874a3ad4d2 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_start.c @@ -0,0 +1,83 @@ +#include "../infrared_i.h" + +enum SubmenuIndex { + SubmenuIndexUniversalRemotes, + SubmenuIndexLearnNewRemote, + SubmenuIndexSavedRemotes, + SubmenuIndexDebug +}; + +static void infrared_scene_start_submenu_callback(void* context, uint32_t index) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, index); +} + +void infrared_scene_start_on_enter(void* context) { + Infrared* infrared = context; + Submenu* submenu = infrared->submenu; + SceneManager* scene_manager = infrared->scene_manager; + + submenu_add_item( + submenu, + "Universal Remotes", + SubmenuIndexUniversalRemotes, + infrared_scene_start_submenu_callback, + infrared); + submenu_add_item( + submenu, + "Learn New Remote", + SubmenuIndexLearnNewRemote, + infrared_scene_start_submenu_callback, + infrared); + submenu_add_item( + submenu, + "Saved Remotes", + SubmenuIndexSavedRemotes, + infrared_scene_start_submenu_callback, + infrared); + + if(infrared->app_state.is_debug_enabled) { + submenu_add_item( + submenu, "Debug", SubmenuIndexDebug, infrared_scene_start_submenu_callback, infrared); + } + + const uint32_t submenu_index = + scene_manager_get_scene_state(scene_manager, InfraredSceneStart); + submenu_set_selected_item(submenu, submenu_index); + scene_manager_set_scene_state(scene_manager, InfraredSceneStart, SubmenuIndexUniversalRemotes); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); +} + +bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + const uint32_t submenu_index = event.event; + scene_manager_set_scene_state(scene_manager, InfraredSceneStart, submenu_index); + if(submenu_index == SubmenuIndexUniversalRemotes) { + scene_manager_next_scene(scene_manager, InfraredSceneUniversal); + consumed = true; + } else if(submenu_index == SubmenuIndexLearnNewRemote) { + infrared->app_state.is_learning_new_remote = true; + scene_manager_next_scene(scene_manager, InfraredSceneLearn); + consumed = true; + } else if(submenu_index == SubmenuIndexSavedRemotes) { + scene_manager_next_scene(scene_manager, InfraredSceneRemoteList); + consumed = true; + } else if(submenu_index == SubmenuIndexDebug) { + scene_manager_next_scene(scene_manager, InfraredSceneDebug); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_start_on_exit(void* context) { + Infrared* infrared = context; + submenu_reset(infrared->submenu); +} diff --git a/applications/infrared/scenes/infrared_scene_universal.c b/applications/infrared/scenes/infrared_scene_universal.c new file mode 100644 index 000000000000..cc6568834cc1 --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_universal.c @@ -0,0 +1,53 @@ +#include "../infrared_i.h" + +typedef enum { + SubmenuIndexUniversalTV, + SubmenuIndexUniversalAudio, + SubmenuIndexUniversalAirConditioner, +} SubmenuIndex; + +static void infrared_scene_universal_submenu_callback(void* context, uint32_t index) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, index); +} + +void infrared_scene_universal_on_enter(void* context) { + Infrared* infrared = context; + Submenu* submenu = infrared->submenu; + + submenu_add_item( + submenu, + "TVs", + SubmenuIndexUniversalTV, + infrared_scene_universal_submenu_callback, + context); + submenu_set_selected_item(submenu, 0); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); +} + +bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + SceneManager* scene_manager = infrared->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexUniversalTV) { + scene_manager_next_scene(scene_manager, InfraredSceneUniversalTV); + consumed = true; + } else if(event.event == SubmenuIndexUniversalAudio) { + //TODO Implement Audio universal remote + consumed = true; + } else if(event.event == SubmenuIndexUniversalAirConditioner) { + //TODO Implement A/C universal remote + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_universal_on_exit(void* context) { + Infrared* infrared = context; + submenu_reset(infrared->submenu); +} diff --git a/applications/infrared/scenes/infrared_scene_universal_tv.c b/applications/infrared/scenes/infrared_scene_universal_tv.c new file mode 100644 index 000000000000..f3a9a06bce9d --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_universal_tv.c @@ -0,0 +1,111 @@ +#include "../infrared_i.h" + +#include "common/infrared_scene_universal_common.h" + +void infrared_scene_universal_tv_on_enter(void* context) { + infrared_scene_universal_common_on_enter(context); + + Infrared* infrared = context; + ButtonPanel* button_panel = infrared->button_panel; + InfraredBruteForce* brute_force = infrared->brute_force; + + infrared_brute_force_set_db_filename(brute_force, "/ext/infrared/assets/tv.ir"); + + button_panel_reserve(button_panel, 2, 3); + uint32_t i = 0; + button_panel_add_item( + button_panel, + i, + 0, + 0, + 3, + 19, + &I_Power_25x27, + &I_Power_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "POWER"); + button_panel_add_item( + button_panel, + i, + 1, + 0, + 36, + 19, + &I_Mute_25x27, + &I_Mute_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "MUTE"); + button_panel_add_item( + button_panel, + i, + 0, + 1, + 3, + 66, + &I_Vol_up_25x27, + &I_Vol_up_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "VOL+"); + button_panel_add_item( + button_panel, + i, + 1, + 1, + 36, + 66, + &I_Up_25x27, + &I_Up_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "CH+"); + button_panel_add_item( + button_panel, + i, + 0, + 2, + 3, + 98, + &I_Vol_down_25x27, + &I_Vol_down_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "VOL-"); + button_panel_add_item( + button_panel, + i, + 1, + 2, + 36, + 98, + &I_Down_25x27, + &I_Down_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "CH-"); + + button_panel_add_label(button_panel, 6, 11, FontPrimary, "TV remote"); + button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol"); + button_panel_add_label(button_panel, 43, 64, FontSecondary, "Ch"); + + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); + + infrared_show_loading_popup(infrared, true); + bool success = infrared_brute_force_calculate_messages(brute_force); + infrared_show_loading_popup(infrared, false); + + if(!success) { + scene_manager_previous_scene(infrared->scene_manager); + } +} + +bool infrared_scene_universal_tv_on_event(void* context, SceneManagerEvent event) { + return infrared_scene_universal_common_on_event(context, event); +} + +void infrared_scene_universal_tv_on_exit(void* context) { + infrared_scene_universal_common_on_exit(context); +} diff --git a/applications/infrared/views/infrared_debug_view.c b/applications/infrared/views/infrared_debug_view.c new file mode 100644 index 000000000000..ab2c679c4d02 --- /dev/null +++ b/applications/infrared/views/infrared_debug_view.c @@ -0,0 +1,59 @@ +#include "infrared_debug_view.h" + +#include +#include + +#include +#include + +#define INFRARED_DEBUG_TEXT_LENGTH 64 + +struct InfraredDebugView { + View* view; +}; + +typedef struct { + char text[INFRARED_DEBUG_TEXT_LENGTH]; +} InfraredDebugViewModel; + +static void infrared_debug_view_draw_callback(Canvas* canvas, void* model) { + InfraredDebugViewModel* debug_view_model = model; + + canvas_clear(canvas); + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "INFRARED monitor\n"); + canvas_set_font(canvas, FontKeyboard); + + if(strlen(debug_view_model->text)) { + elements_multiline_text_aligned( + canvas, 64, 43, AlignCenter, AlignCenter, debug_view_model->text); + } +} + +InfraredDebugView* infrared_debug_view_alloc() { + InfraredDebugView* debug_view = malloc(sizeof(InfraredDebugView)); + debug_view->view = view_alloc(); + view_allocate_model(debug_view->view, ViewModelTypeLocking, sizeof(InfraredDebugViewModel)); + view_set_draw_callback(debug_view->view, infrared_debug_view_draw_callback); + view_set_context(debug_view->view, debug_view); + return debug_view; +} +void infrared_debug_view_free(InfraredDebugView* debug_view) { + view_free(debug_view->view); + free(debug_view); +} + +View* infrared_debug_view_get_view(InfraredDebugView* debug_view) { + return debug_view->view; +} + +void infrared_debug_view_set_text(InfraredDebugView* debug_view, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + + InfraredDebugViewModel* model = view_get_model(debug_view->view); + vsnprintf(model->text, INFRARED_DEBUG_TEXT_LENGTH, fmt, args); + view_commit_model(debug_view->view, true); + + va_end(args); +} diff --git a/applications/infrared/views/infrared_debug_view.h b/applications/infrared/views/infrared_debug_view.h new file mode 100644 index 000000000000..722850f8d4db --- /dev/null +++ b/applications/infrared/views/infrared_debug_view.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +typedef struct InfraredDebugView InfraredDebugView; + +InfraredDebugView* infrared_debug_view_alloc(); +void infrared_debug_view_free(InfraredDebugView* debug_view); + +View* infrared_debug_view_get_view(InfraredDebugView* debug_view); +void infrared_debug_view_set_text(InfraredDebugView* debug_view, const char* fmt, ...); diff --git a/applications/infrared/view/infrared_progress_view.c b/applications/infrared/views/infrared_progress_view.c similarity index 100% rename from applications/infrared/view/infrared_progress_view.c rename to applications/infrared/views/infrared_progress_view.c diff --git a/applications/infrared/view/infrared_progress_view.h b/applications/infrared/views/infrared_progress_view.h similarity index 100% rename from applications/infrared/view/infrared_progress_view.h rename to applications/infrared/views/infrared_progress_view.h diff --git a/applications/infrared_monitor/infrared_monitor.c b/applications/infrared_monitor/infrared_monitor.c deleted file mode 100644 index 08691dfa2ed1..000000000000 --- a/applications/infrared_monitor/infrared_monitor.c +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define INFRARED_TIMINGS_SIZE 700 - -typedef struct { - uint32_t timing_cnt; - struct { - uint8_t level; - uint32_t duration; - } timing[INFRARED_TIMINGS_SIZE]; -} InfraredDelaysArray; - -typedef struct { - char display_text[64]; - osMessageQueueId_t event_queue; - InfraredDelaysArray delays; - InfraredWorker* worker; - ViewPort* view_port; -} InfraredMonitor; - -void infrared_monitor_input_callback(InputEvent* input_event, void* ctx) { - furi_assert(ctx); - InfraredMonitor* infrared_monitor = (InfraredMonitor*)ctx; - - if((input_event->type == InputTypeShort) && (input_event->key == InputKeyBack)) { - osMessageQueuePut(infrared_monitor->event_queue, input_event, 0, 0); - } -} - -static void infrared_monitor_draw_callback(Canvas* canvas, void* ctx) { - furi_assert(canvas); - furi_assert(ctx); - InfraredMonitor* infrared_monitor = (InfraredMonitor*)ctx; - - canvas_clear(canvas); - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "INFRARED monitor\n"); - canvas_set_font(canvas, FontKeyboard); - if(strlen(infrared_monitor->display_text)) { - elements_multiline_text_aligned( - canvas, 64, 43, AlignCenter, AlignCenter, infrared_monitor->display_text); - } -} - -static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { - furi_assert(context); - furi_assert(received_signal); - InfraredMonitor* infrared_monitor = context; - - if(infrared_worker_signal_is_decoded(received_signal)) { - const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal); - snprintf( - infrared_monitor->display_text, - sizeof(infrared_monitor->display_text), - "%s\nA:0x%0*lX\nC:0x%0*lX\n%s\n", - infrared_get_protocol_name(message->protocol), - ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), - message->address, - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), - message->command, - message->repeat ? " R" : ""); - view_port_update(infrared_monitor->view_port); - printf( - "== %s, A:0x%0*lX, C:0x%0*lX%s ==\r\n", - infrared_get_protocol_name(message->protocol), - ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), - message->address, - ROUND_UP_TO(infrared_get_protocol_command_length(message->protocol), 4), - message->command, - message->repeat ? " R" : ""); - } else { - const uint32_t* timings; - size_t timings_cnt; - infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt); - snprintf( - infrared_monitor->display_text, - sizeof(infrared_monitor->display_text), - "RAW\n%d samples\n", - timings_cnt); - view_port_update(infrared_monitor->view_port); - printf("RAW, %d samples:\r\n", timings_cnt); - for(size_t i = 0; i < timings_cnt; ++i) { - printf("%lu ", timings[i]); - } - printf("\r\n"); - } -} - -int32_t infrared_monitor_app(void* p) { - (void)p; - - InfraredMonitor* infrared_monitor = malloc(sizeof(InfraredMonitor)); - infrared_monitor->display_text[0] = 0; - infrared_monitor->event_queue = osMessageQueueNew(1, sizeof(InputEvent), NULL); - infrared_monitor->view_port = view_port_alloc(); - Gui* gui = furi_record_open("gui"); - - view_port_draw_callback_set( - infrared_monitor->view_port, infrared_monitor_draw_callback, infrared_monitor); - view_port_input_callback_set( - infrared_monitor->view_port, infrared_monitor_input_callback, infrared_monitor); - - gui_add_view_port(gui, infrared_monitor->view_port, GuiLayerFullscreen); - - infrared_monitor->worker = infrared_worker_alloc(); - infrared_worker_rx_start(infrared_monitor->worker); - infrared_worker_rx_set_received_signal_callback( - infrared_monitor->worker, signal_received_callback, infrared_monitor); - infrared_worker_rx_enable_blink_on_receiving(infrared_monitor->worker, true); - - while(1) { - InputEvent event; - if(osOK == osMessageQueueGet(infrared_monitor->event_queue, &event, NULL, 50)) { - if((event.type == InputTypeShort) && (event.key == InputKeyBack)) { - break; - } - } - } - - infrared_worker_rx_stop(infrared_monitor->worker); - infrared_worker_free(infrared_monitor->worker); - osMessageQueueDelete(infrared_monitor->event_queue); - view_port_enabled_set(infrared_monitor->view_port, false); - gui_remove_view_port(gui, infrared_monitor->view_port); - view_port_free(infrared_monitor->view_port); - furi_record_close("gui"); - free(infrared_monitor); - - return 0; -} From 94a18a4c1924884046a21955fe7e16c7ed16a5b7 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 21 Jun 2022 16:25:05 +0300 Subject: [PATCH 159/184] [FL-2511] Updater: fixed long update descriptions overlapping UI elements #1327 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/updater/scenes/updater_scene_loadcfg.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/applications/updater/scenes/updater_scene_loadcfg.c b/applications/updater/scenes/updater_scene_loadcfg.c index 8e477b14a6b3..1fd87d002a99 100644 --- a/applications/updater/scenes/updater_scene_loadcfg.c +++ b/applications/updater/scenes/updater_scene_loadcfg.c @@ -29,14 +29,16 @@ void updater_scene_loadcfg_on_enter(void* context) { widget_add_string_element( updater->widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, "Update"); - widget_add_string_multiline_element( + widget_add_text_box_element( updater->widget, - 64, + 5, + 20, + 118, 32, AlignCenter, AlignCenter, - FontSecondary, - string_get_cstr(pending_upd->manifest->version)); + string_get_cstr(pending_upd->manifest->version), + true); widget_add_button_element( updater->widget, From b25cdd15c5a81978a14db72a5a8e5c0fc81b3282 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Tue, 21 Jun 2022 17:30:30 +0400 Subject: [PATCH 160/184] SubGhz: frequency analyzer combined frequency detection method (#1321) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../subghz_frequency_analyzer_worker.c | 68 ++++++++++++------- .../subghz_frequency_analyzer_worker.h | 6 +- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/applications/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/subghz/helpers/subghz_frequency_analyzer_worker.c index 69e597595b29..43acf0341b51 100644 --- a/applications/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -67,7 +67,8 @@ static uint32_t subghz_frequency_analyzer_worker_expRunningAverageAdaptive( static int32_t subghz_frequency_analyzer_worker_thread(void* context) { SubGhzFrequencyAnalyzerWorker* instance = context; - FrequencyRSSI frequency_rssi = {.frequency = 0, .rssi = 0}; + FrequencyRSSI frequency_rssi = { + .frequency_coarse = 0, .rssi_coarse = 0, .frequency_fine = 0, .rssi_fine = 0}; float rssi = 0; uint32_t frequency = 0; CC1101Status status; @@ -105,7 +106,8 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { float rssi_avg = 0; size_t rssi_avg_samples = 0; - frequency_rssi.rssi = -127.0f; + frequency_rssi.rssi_coarse = -127.0f; + frequency_rssi.rssi_fine = -127.0f; furi_hal_subghz_idle(); subghz_frequency_analyzer_worker_load_registers(subghz_preset_ook_650khz); @@ -137,9 +139,9 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { if(rssi < rssi_min) rssi_min = rssi; - if(frequency_rssi.rssi < rssi) { - frequency_rssi.rssi = rssi; - frequency_rssi.frequency = frequency; + if(frequency_rssi.rssi_coarse < rssi) { + frequency_rssi.rssi_coarse = rssi; + frequency_rssi.frequency_coarse = frequency; } } } @@ -148,20 +150,17 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { TAG, "RSSI: avg %f, max %f at %u, min %f", (double)(rssi_avg / rssi_avg_samples), - (double)frequency_rssi.rssi, - frequency_rssi.frequency, + (double)frequency_rssi.rssi_coarse, + frequency_rssi.frequency_coarse, (double)rssi_min); // Second stage: fine scan - if(frequency_rssi.rssi > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) { - FURI_LOG_D(TAG, "~:%u:%f", frequency_rssi.frequency, (double)frequency_rssi.rssi); - - frequency_rssi.rssi = -127.0; + if(frequency_rssi.rssi_coarse > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) { furi_hal_subghz_idle(); subghz_frequency_analyzer_worker_load_registers(subghz_preset_ook_58khz); - //-0.3 ... 433.92 ... +0.3 step 10KHz - for(uint32_t i = frequency_rssi.frequency - 300000; - i < frequency_rssi.frequency + 300000; + //for example -0.3 ... 433.92 ... +0.3 step 20KHz + for(uint32_t i = frequency_rssi.frequency_coarse - 300000; + i < frequency_rssi.frequency_coarse + 300000; i += 20000) { if(furi_hal_subghz_is_frequency_valid(i)) { furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); @@ -183,28 +182,51 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { FURI_LOG_T(TAG, "#:%u:%f", frequency, (double)rssi); - if(frequency_rssi.rssi < rssi) { - frequency_rssi.rssi = rssi; - frequency_rssi.frequency = frequency; + if(frequency_rssi.rssi_fine < rssi) { + frequency_rssi.rssi_fine = rssi; + frequency_rssi.frequency_fine = frequency; } } } } - // Deliver results - if(frequency_rssi.rssi > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) { - FURI_LOG_D(TAG, "=:%u:%f", frequency_rssi.frequency, (double)frequency_rssi.rssi); + // Deliver results fine + if(frequency_rssi.rssi_fine > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) { + FURI_LOG_D( + TAG, "=:%u:%f", frequency_rssi.frequency_fine, (double)frequency_rssi.rssi_fine); + + instance->sample_hold_counter = 20; + if(instance->filVal) { + frequency_rssi.frequency_fine = + subghz_frequency_analyzer_worker_expRunningAverageAdaptive( + instance, frequency_rssi.frequency_fine); + } + // Deliver callback + if(instance->pair_callback) { + instance->pair_callback( + instance->context, frequency_rssi.frequency_fine, frequency_rssi.rssi_fine); + } + } else if( // Deliver results coarse + (frequency_rssi.rssi_coarse > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) && + (instance->sample_hold_counter < 10)) { + FURI_LOG_D( + TAG, + "~:%u:%f", + frequency_rssi.frequency_coarse, + (double)frequency_rssi.rssi_coarse); instance->sample_hold_counter = 20; if(instance->filVal) { - frequency_rssi.frequency = + frequency_rssi.frequency_coarse = subghz_frequency_analyzer_worker_expRunningAverageAdaptive( - instance, frequency_rssi.frequency); + instance, frequency_rssi.frequency_coarse); } // Deliver callback if(instance->pair_callback) { instance->pair_callback( - instance->context, frequency_rssi.frequency, frequency_rssi.rssi); + instance->context, + frequency_rssi.frequency_coarse, + frequency_rssi.rssi_coarse); } } else { if(instance->sample_hold_counter > 0) { diff --git a/applications/subghz/helpers/subghz_frequency_analyzer_worker.h b/applications/subghz/helpers/subghz_frequency_analyzer_worker.h index 424270a0395f..50687c76da2d 100644 --- a/applications/subghz/helpers/subghz_frequency_analyzer_worker.h +++ b/applications/subghz/helpers/subghz_frequency_analyzer_worker.h @@ -9,8 +9,10 @@ typedef void ( *SubGhzFrequencyAnalyzerWorkerPairCallback)(void* context, uint32_t frequency, float rssi); typedef struct { - uint32_t frequency; - float rssi; + uint32_t frequency_coarse; + float rssi_coarse; + uint32_t frequency_fine; + float rssi_fine; } FrequencyRSSI; /** Allocate SubGhzFrequencyAnalyzerWorker From dad13b916c2ae60210894a83a48e4203c2b5ac77 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Tue, 21 Jun 2022 16:46:39 +0300 Subject: [PATCH 161/184] [FL-2588] RPC storage: Ignore incorrect file names #1318 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/rpc/rpc_storage.c | 95 +++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 20 deletions(-) diff --git a/applications/rpc/rpc_storage.c b/applications/rpc/rpc_storage.c index e6a59ea8de3c..624d7c7b82a8 100644 --- a/applications/rpc/rpc_storage.c +++ b/applications/rpc/rpc_storage.c @@ -100,6 +100,35 @@ static PB_CommandStatus rpc_system_storage_get_file_error(File* file) { return rpc_system_storage_get_error(storage_file_get_error(file)); } +static bool rpc_system_storage_is_filename_correct(const char* path) { + const char* name_pos = strrchr(path, '/'); + if(name_pos == NULL) { + name_pos = path; + } else { + name_pos++; + } + + while(*name_pos != '\0') { + if((*name_pos >= '0') && (*name_pos <= '9')) { + name_pos++; + continue; + } else if((*name_pos >= 'A') && (*name_pos <= 'Z')) { + name_pos++; + continue; + } else if((*name_pos >= 'a') && (*name_pos <= 'z')) { + name_pos++; + continue; + } else if(strchr(".!#\\$%&'()-@^_`{}~", *name_pos) != NULL) { + name_pos++; + continue; + } + + return false; + } + + return true; +} + static void rpc_system_storage_info_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(context); @@ -245,18 +274,23 @@ static void rpc_system_storage_list_process(const PB_Main* request, void* contex FileInfo fileinfo; char* name = malloc(MAX_NAME_LENGTH + 1); if(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) { - if(i == COUNT_OF(list->file)) { - list->file_count = i; - response.has_next = true; - rpc_send_and_release(session, &response); - i = 0; + if(rpc_system_storage_is_filename_correct(name)) { + if(i == COUNT_OF(list->file)) { + list->file_count = i; + response.has_next = true; + rpc_send_and_release(session, &response); + i = 0; + } + list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? + PB_Storage_File_FileType_DIR : + PB_Storage_File_FileType_FILE; + list->file[i].size = fileinfo.size; + list->file[i].data = NULL; + list->file[i].name = name; + ++i; + } else { + free(name); } - list->file[i].type = (fileinfo.flags & FSF_DIRECTORY) ? PB_Storage_File_FileType_DIR : - PB_Storage_File_FileType_FILE; - list->file[i].size = fileinfo.size; - list->file[i].data = NULL; - list->file[i].name = name; - ++i; } else { list->file_count = i; finish = true; @@ -345,6 +379,14 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte bool result = true; + if(!rpc_system_storage_is_filename_correct(request->content.storage_write_request.path)) { + rpc_storage->current_command_id = request->command_id; + rpc_send_and_release_empty( + session, rpc_storage->current_command_id, PB_CommandStatus_ERROR_STORAGE_INVALID_NAME); + rpc_system_storage_reset_state(rpc_storage, session, false); + return; + } + if((request->command_id != rpc_storage->current_command_id) && (rpc_storage->state == RpcStorageStateWriting)) { rpc_system_storage_reset_state(rpc_storage, session, true); @@ -384,13 +426,18 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte static bool rpc_system_storage_is_dir_is_empty(Storage* fs_api, const char* path) { FileInfo fileinfo; - bool is_dir_is_empty = false; + bool is_dir_is_empty = true; FS_Error error = storage_common_stat(fs_api, path, &fileinfo); if((error == FSE_OK) && (fileinfo.flags & FSF_DIRECTORY)) { File* dir = storage_file_alloc(fs_api); if(storage_dir_open(dir, path)) { char* name = malloc(MAX_NAME_LENGTH); - is_dir_is_empty = !storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH); + while(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) { + if(rpc_system_storage_is_filename_correct(name)) { + is_dir_is_empty = false; + break; + } + } free(name); } storage_dir_close(dir); @@ -458,8 +505,12 @@ static void rpc_system_storage_mkdir_process(const PB_Main* request, void* conte Storage* fs_api = furi_record_open("storage"); char* path = request->content.storage_mkdir_request.path; if(path) { - FS_Error error = storage_common_mkdir(fs_api, path); - status = rpc_system_storage_get_error(error); + if(rpc_system_storage_is_filename_correct(path)) { + FS_Error error = storage_common_mkdir(fs_api, path); + status = rpc_system_storage_get_error(error); + } else { + status = PB_CommandStatus_ERROR_STORAGE_INVALID_NAME; + } } else { status = PB_CommandStatus_ERROR_INVALID_PARAMETERS; } @@ -551,11 +602,15 @@ static void rpc_system_storage_rename_process(const PB_Main* request, void* cont Storage* fs_api = furi_record_open("storage"); - FS_Error error = storage_common_rename( - fs_api, - request->content.storage_rename_request.old_path, - request->content.storage_rename_request.new_path); - status = rpc_system_storage_get_error(error); + if(rpc_system_storage_is_filename_correct(request->content.storage_rename_request.new_path)) { + FS_Error error = storage_common_rename( + fs_api, + request->content.storage_rename_request.old_path, + request->content.storage_rename_request.new_path); + status = rpc_system_storage_get_error(error); + } else { + status = PB_CommandStatus_ERROR_STORAGE_INVALID_NAME; + } furi_record_close("storage"); rpc_send_and_release_empty(session, request->command_id, status); From 1e93be4336270f9c11f382443256d8f77aa4a916 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 21 Jun 2022 17:11:34 +0300 Subject: [PATCH 162/184] [FL-2556] Update complete screen (#1332) * Desktop: slideshow implementation * Updater: handling splashscreen installation; added format version field to slideshow binary * Desktop: added bidirectional slideshow navigation + instant cancel by "back" button; Updater: rebalanced update stages weights * Updater: fixed missing field init; fixed potential loop when baking slideshows * Assets: fixed "update complete" image to match original * Desktop: added check for slideshow file version * Scripts: slideshow.py cleanup * Desktop: removed first start intro sequence * Desktop: removed first start remnants --- Makefile | 4 +- applications/desktop/desktop.c | 20 +-- applications/desktop/desktop_i.h | 6 +- applications/desktop/helpers/slideshow.c | 115 ++++++++++++ applications/desktop/helpers/slideshow.h | 13 ++ .../desktop/scenes/desktop_scene_config.h | 2 +- .../scenes/desktop_scene_first_start.c | 54 ------ .../desktop/scenes/desktop_scene_slideshow.c | 45 +++++ applications/desktop/views/desktop_events.h | 5 +- .../desktop/views/desktop_view_first_start.c | 166 ------------------ .../desktop/views/desktop_view_first_start.h | 20 --- .../desktop/views/desktop_view_slideshow.c | 108 ++++++++++++ .../desktop/views/desktop_view_slideshow.h | 20 +++ applications/updater/util/update_task.c | 15 +- applications/updater/util/update_task.h | 2 + .../updater/util/update_task_worker_backup.c | 13 ++ assets/slideshow/update_default/frame_00.png | Bin 0 -> 2211 bytes assets/splash.mk | 3 + lib/update_util/update_manifest.c | 6 + lib/update_util/update_manifest.h | 1 + scripts/bin2dfu.py | 4 +- scripts/slideshow.py | 61 +++++++ scripts/update.py | 20 +++ 23 files changed, 437 insertions(+), 266 deletions(-) create mode 100644 applications/desktop/helpers/slideshow.c create mode 100644 applications/desktop/helpers/slideshow.h delete mode 100644 applications/desktop/scenes/desktop_scene_first_start.c create mode 100644 applications/desktop/scenes/desktop_scene_slideshow.c delete mode 100644 applications/desktop/views/desktop_view_first_start.c delete mode 100644 applications/desktop/views/desktop_view_first_start.h create mode 100644 applications/desktop/views/desktop_view_slideshow.c create mode 100644 applications/desktop/views/desktop_view_slideshow.h create mode 100644 assets/slideshow/update_default/frame_00.png create mode 100644 assets/splash.mk create mode 100644 scripts/slideshow.py diff --git a/Makefile b/Makefile index 8834cba6cebf..a48ed6135551 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ PROJECT_ROOT := $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))) include $(PROJECT_ROOT)/make/git.mk include $(PROJECT_ROOT)/assets/copro.mk +include $(PROJECT_ROOT)/assets/splash.mk PROJECT_SOURCE_DIRECTORIES := \ $(PROJECT_ROOT)/applications \ @@ -103,7 +104,8 @@ updater_package: firmware_all updater assets_manifest --radio $(COPRO_STACK_BIN_PATH) \ --radiotype $(COPRO_STACK_TYPE) \ $(COPRO_DISCLAIMER) \ - --obdata $(PROJECT_ROOT)/scripts/$(COPRO_OB_DATA) + --obdata $(PROJECT_ROOT)/scripts/$(COPRO_OB_DATA) \ + --splash $(UPDATER_SPLASH_DIR) .PHONY: assets_manifest assets_manifest: diff --git a/applications/desktop/desktop.c b/applications/desktop/desktop.c index 34c169e07a97..520917535c71 100644 --- a/applications/desktop/desktop.c +++ b/applications/desktop/desktop.c @@ -158,11 +158,11 @@ Desktop* desktop_alloc() { desktop->lock_menu = desktop_lock_menu_alloc(); desktop->debug_view = desktop_debug_alloc(); - desktop->first_start_view = desktop_first_start_alloc(); desktop->hw_mismatch_popup = popup_alloc(); desktop->locked_view = desktop_view_locked_alloc(); desktop->pin_input_view = desktop_view_pin_input_alloc(); desktop->pin_timeout_view = desktop_view_pin_timeout_alloc(); + desktop->slideshow_view = desktop_view_slideshow_alloc(); desktop->main_view_stack = view_stack_alloc(); desktop->main_view = desktop_main_alloc(); @@ -193,10 +193,6 @@ Desktop* desktop_alloc() { desktop_lock_menu_get_view(desktop->lock_menu)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdDebug, desktop_debug_get_view(desktop->debug_view)); - view_dispatcher_add_view( - desktop->view_dispatcher, - DesktopViewIdFirstStart, - desktop_first_start_get_view(desktop->first_start_view)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewIdHwMismatch, @@ -209,6 +205,10 @@ Desktop* desktop_alloc() { desktop->view_dispatcher, DesktopViewIdPinInput, desktop_view_pin_input_get_view(desktop->pin_input_view)); + view_dispatcher_add_view( + desktop->view_dispatcher, + DesktopViewIdSlideshow, + desktop_view_slideshow_get_view(desktop->slideshow_view)); // Lock icon desktop->lock_viewport = view_port_alloc(); @@ -258,7 +258,6 @@ void desktop_free(Desktop* desktop) { view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLocked); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdDebug); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdFirstStart); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdHwMismatch); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinInput); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinTimeout); @@ -274,7 +273,6 @@ void desktop_free(Desktop* desktop) { desktop_lock_menu_free(desktop->lock_menu); desktop_view_locked_free(desktop->locked_view); desktop_debug_free(desktop->debug_view); - desktop_first_start_free(desktop->first_start_view); popup_free(desktop->hw_mismatch_popup); desktop_view_pin_timeout_free(desktop->pin_timeout_view); @@ -290,9 +288,9 @@ void desktop_free(Desktop* desktop) { free(desktop); } -static bool desktop_is_first_start() { +static bool desktop_check_file_flag(const char* flag_path) { Storage* storage = furi_record_open("storage"); - bool exists = storage_common_stat(storage, "/int/first_start", NULL) == FSE_OK; + bool exists = storage_common_stat(storage, flag_path, NULL) == FSE_OK; furi_record_close("storage"); return exists; @@ -320,8 +318,8 @@ int32_t desktop_srv(void* p) { desktop_lock(desktop); } - if(desktop_is_first_start()) { - scene_manager_next_scene(desktop->scene_manager, DesktopSceneFirstStart); + if(desktop_check_file_flag("/int/slideshow")) { + scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow); } if(!furi_hal_version_do_i_belong_here()) { diff --git a/applications/desktop/desktop_i.h b/applications/desktop/desktop_i.h index 2888f0998e89..8dc92e849ccf 100644 --- a/applications/desktop/desktop_i.h +++ b/applications/desktop/desktop_i.h @@ -6,9 +6,9 @@ #include "views/desktop_view_pin_input.h" #include "views/desktop_view_locked.h" #include "views/desktop_view_main.h" -#include "views/desktop_view_first_start.h" #include "views/desktop_view_lock_menu.h" #include "views/desktop_view_debug.h" +#include "views/desktop_view_slideshow.h" #include "desktop/desktop_settings/desktop_settings.h" #include @@ -28,10 +28,10 @@ typedef enum { DesktopViewIdLockMenu, DesktopViewIdLocked, DesktopViewIdDebug, - DesktopViewIdFirstStart, DesktopViewIdHwMismatch, DesktopViewIdPinInput, DesktopViewIdPinTimeout, + DesktopViewIdSlideshow, DesktopViewIdTotal, } DesktopViewId; @@ -43,13 +43,13 @@ struct Desktop { ViewDispatcher* view_dispatcher; SceneManager* scene_manager; - DesktopFirstStartView* first_start_view; Popup* hw_mismatch_popup; DesktopLockMenuView* lock_menu; DesktopDebugView* debug_view; DesktopViewLocked* locked_view; DesktopMainView* main_view; DesktopViewPinTimeout* pin_timeout_view; + DesktopSlideshowView* slideshow_view; ViewStack* main_view_stack; ViewStack* locked_view_stack; diff --git a/applications/desktop/helpers/slideshow.c b/applications/desktop/helpers/slideshow.c new file mode 100644 index 000000000000..37f66cf35d1e --- /dev/null +++ b/applications/desktop/helpers/slideshow.c @@ -0,0 +1,115 @@ +#include "slideshow.h" + +#include +#include +#include +#include +#include + +#define SLIDESHOW_MAGIC 0x72676468 +#define SLIDESHOW_MAX_SUPPORTED_VERSION 1 + +struct Slideshow { + Icon icon; + uint32_t current_frame; +}; + +#pragma pack(push, 1) + +typedef struct { + uint32_t magic; + uint8_t version; + uint8_t width; + uint8_t height; + uint8_t frame_count; +} SlideshowFileHeader; +_Static_assert(sizeof(SlideshowFileHeader) == 8, "Incorrect SlideshowFileHeader size"); + +typedef struct { + uint16_t size; +} SlideshowFrameHeader; +_Static_assert(sizeof(SlideshowFrameHeader) == 2, "Incorrect SlideshowFrameHeader size"); + +#pragma pack(pop) + +Slideshow* slideshow_alloc() { + Slideshow* ret = malloc(sizeof(Slideshow)); + return ret; +} + +void slideshow_free(Slideshow* slideshow) { + Icon* icon = &slideshow->icon; + if(icon) { + for(int frame_idx = 0; frame_idx < icon->frame_count; ++frame_idx) { + uint8_t* frame_data = (uint8_t*)icon->frames[frame_idx]; + free(frame_data); + } + free((uint8_t**)icon->frames); + } + free(slideshow); +} + +bool slideshow_load(Slideshow* slideshow, const char* fspath) { + Storage* storage = furi_record_open("storage"); + File* slideshow_file = storage_file_alloc(storage); + bool load_success = false; + do { + if(!storage_file_open(slideshow_file, fspath, FSAM_READ, FSOM_OPEN_EXISTING)) { + break; + } + SlideshowFileHeader header; + if((storage_file_read(slideshow_file, &header, sizeof(header)) != sizeof(header)) || + (header.magic != SLIDESHOW_MAGIC) || + (header.version > SLIDESHOW_MAX_SUPPORTED_VERSION)) { + break; + } + Icon* icon = &slideshow->icon; + FURI_CONST_ASSIGN(icon->frame_count, header.frame_count); + FURI_CONST_ASSIGN(icon->width, header.width); + FURI_CONST_ASSIGN(icon->height, header.height); + icon->frames = malloc(header.frame_count * sizeof(uint8_t*)); + for(int frame_idx = 0; frame_idx < header.frame_count; ++frame_idx) { + SlideshowFrameHeader frame_header; + if(storage_file_read(slideshow_file, &frame_header, sizeof(frame_header)) != + sizeof(frame_header)) { + break; + } + FURI_CONST_ASSIGN_PTR(icon->frames[frame_idx], malloc(frame_header.size)); + uint8_t* frame_data = (uint8_t*)icon->frames[frame_idx]; + if(storage_file_read(slideshow_file, frame_data, frame_header.size) != + frame_header.size) { + break; + } + load_success = (frame_idx + 1) == header.frame_count; + } + } while(false); + storage_file_free(slideshow_file); + furi_record_close("storage"); + return load_success; +} + +bool slideshow_advance(Slideshow* slideshow) { + uint8_t next_frame = slideshow->current_frame + 1; + if(next_frame < slideshow->icon.frame_count) { + slideshow->current_frame = next_frame; + return true; + } + return false; +} + +void slideshow_goback(Slideshow* slideshow) { + if(slideshow->current_frame > 0) { + slideshow->current_frame--; + } +} + +void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y) { + furi_assert(slideshow->current_frame < slideshow->icon.frame_count); + canvas_draw_bitmap( + canvas, + x, + y, + slideshow->icon.width, + slideshow->icon.height, + slideshow->icon.frames[slideshow->current_frame]); +} \ No newline at end of file diff --git a/applications/desktop/helpers/slideshow.h b/applications/desktop/helpers/slideshow.h new file mode 100644 index 000000000000..db19779a327a --- /dev/null +++ b/applications/desktop/helpers/slideshow.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct Slideshow Slideshow; + +Slideshow* slideshow_alloc(); + +void slideshow_free(Slideshow* slideshow); +bool slideshow_load(Slideshow* slideshow, const char* fspath); +void slideshow_goback(Slideshow* slideshow); +bool slideshow_advance(Slideshow* slideshow); +void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y); diff --git a/applications/desktop/scenes/desktop_scene_config.h b/applications/desktop/scenes/desktop_scene_config.h index c84d6ff89f72..c153972b290b 100644 --- a/applications/desktop/scenes/desktop_scene_config.h +++ b/applications/desktop/scenes/desktop_scene_config.h @@ -1,9 +1,9 @@ ADD_SCENE(desktop, main, Main) ADD_SCENE(desktop, lock_menu, LockMenu) ADD_SCENE(desktop, debug, Debug) -ADD_SCENE(desktop, first_start, FirstStart) ADD_SCENE(desktop, hw_mismatch, HwMismatch) ADD_SCENE(desktop, fault, Fault) ADD_SCENE(desktop, locked, Locked) ADD_SCENE(desktop, pin_input, PinInput) ADD_SCENE(desktop, pin_timeout, PinTimeout) +ADD_SCENE(desktop, slideshow, Slideshow) diff --git a/applications/desktop/scenes/desktop_scene_first_start.c b/applications/desktop/scenes/desktop_scene_first_start.c deleted file mode 100644 index dbdf8919e851..000000000000 --- a/applications/desktop/scenes/desktop_scene_first_start.c +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include - -#include "../desktop_i.h" -#include "../views/desktop_view_first_start.h" -#include "../views/desktop_events.h" - -void desktop_scene_first_start_callback(DesktopEvent event, void* context) { - Desktop* desktop = (Desktop*)context; - view_dispatcher_send_custom_event(desktop->view_dispatcher, event); -} - -void desktop_scene_first_start_on_enter(void* context) { - Desktop* desktop = (Desktop*)context; - DesktopFirstStartView* first_start_view = desktop->first_start_view; - - desktop_first_start_set_callback( - first_start_view, desktop_scene_first_start_callback, desktop); - - view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdFirstStart); -} - -bool desktop_scene_first_start_on_event(void* context, SceneManagerEvent event) { - Desktop* desktop = (Desktop*)context; - bool consumed = false; - Storage* storage = NULL; - Power* power = NULL; - - if(event.type == SceneManagerEventTypeCustom) { - switch(event.event) { - case DesktopFirstStartCompleted: - storage = furi_record_open("storage"); - storage_common_remove(storage, "/int/first_start"); - furi_record_close("storage"); - scene_manager_previous_scene(desktop->scene_manager); - consumed = true; - break; - case DesktopFirstStartPoweroff: - power = furi_record_open("power"); - power_off(power); - furi_record_close("power"); - consumed = true; - break; - - default: - break; - } - } - return consumed; -} - -void desktop_scene_first_start_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/desktop/scenes/desktop_scene_slideshow.c b/applications/desktop/scenes/desktop_scene_slideshow.c new file mode 100644 index 000000000000..700801276b40 --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_slideshow.c @@ -0,0 +1,45 @@ +#include + +#include "../desktop_i.h" +#include "../views/desktop_view_slideshow.h" +#include "../views/desktop_events.h" + +void desktop_scene_slideshow_callback(DesktopEvent event, void* context) { + Desktop* desktop = (Desktop*)context; + view_dispatcher_send_custom_event(desktop->view_dispatcher, event); +} + +void desktop_scene_slideshow_on_enter(void* context) { + Desktop* desktop = (Desktop*)context; + DesktopSlideshowView* slideshow_view = desktop->slideshow_view; + + desktop_view_slideshow_set_callback(slideshow_view, desktop_scene_slideshow_callback, desktop); + + view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdSlideshow); +} + +bool desktop_scene_slideshow_on_event(void* context, SceneManagerEvent event) { + Desktop* desktop = (Desktop*)context; + bool consumed = false; + Storage* storage = NULL; + + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case DesktopSlideshowCompleted: + storage = furi_record_open("storage"); + storage_common_remove(storage, "/int/slideshow"); + furi_record_close("storage"); + scene_manager_previous_scene(desktop->scene_manager); + consumed = true; + break; + + default: + break; + } + } + return consumed; +} + +void desktop_scene_slideshow_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/desktop/views/desktop_events.h b/applications/desktop/views/desktop_events.h index bbb6ff62df2e..4ff5f79500bd 100644 --- a/applications/desktop/views/desktop_events.h +++ b/applications/desktop/views/desktop_events.h @@ -26,9 +26,6 @@ typedef enum { DesktopDebugEventSaveState, DesktopDebugEventExit, - DesktopFirstStartCompleted, - DesktopFirstStartPoweroff, - DesktopLockMenuEventLock, DesktopLockMenuEventPinLock, DesktopLockMenuEventExit, @@ -37,6 +34,8 @@ typedef enum { DesktopAnimationEventNewIdleAnimation, DesktopAnimationEventInteractAnimation, + DesktopSlideshowCompleted, + // Global events DesktopGlobalBeforeAppStarted, DesktopGlobalAfterAppFinished, diff --git a/applications/desktop/views/desktop_view_first_start.c b/applications/desktop/views/desktop_view_first_start.c deleted file mode 100644 index 87c07ad2dc84..000000000000 --- a/applications/desktop/views/desktop_view_first_start.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include - -#include "../desktop_i.h" -#include "desktop_view_first_start.h" - -#define DESKTOP_FIRST_START_POWEROFF_SHORT 5000 -#define DESKTOP_FIRST_START_POWEROFF_LONG (60 * 60 * 1000) - -struct DesktopFirstStartView { - View* view; - DesktopFirstStartViewCallback callback; - void* context; - osTimerId_t timer; -}; - -typedef struct { - uint8_t page; -} DesktopFirstStartViewModel; - -static void desktop_first_start_draw(Canvas* canvas, void* model) { - DesktopFirstStartViewModel* m = model; - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - uint8_t width = canvas_width(canvas); - uint8_t height = canvas_height(canvas); - const char* my_name = furi_hal_version_get_name_ptr(); - if(m->page == 0) { - canvas_draw_icon(canvas, 0, height - 51, &I_DolphinFirstStart0_70x53); - elements_multiline_text_framed( - canvas, 75, 16 + STATUS_BAR_Y_SHIFT, "Hey m8,\npress > to\ncontinue"); - } else if(m->page == 1) { - canvas_draw_icon(canvas, 0, height - 51, &I_DolphinFirstStart1_59x53); - elements_multiline_text_framed( - canvas, 64, 16 + STATUS_BAR_Y_SHIFT, "First Of All,\n... >"); - } else if(m->page == 2) { - canvas_draw_icon(canvas, 0, height - 51, &I_DolphinFirstStart2_59x51); - elements_multiline_text_framed( - canvas, 64, 16 + STATUS_BAR_Y_SHIFT, "Thank you\nfor your\nsupport! >"); - } else if(m->page == 3) { - canvas_draw_icon(canvas, width - 57, height - 45, &I_DolphinFirstStart3_57x48); - elements_multiline_text_framed( - canvas, 0, 16 + STATUS_BAR_Y_SHIFT, "Kickstarter\ncampaign\nwas INSANE! >"); - } else if(m->page == 4) { - canvas_draw_icon(canvas, width - 67, height - 51, &I_DolphinFirstStart4_67x53); - elements_multiline_text_framed( - canvas, 0, 13 + STATUS_BAR_Y_SHIFT, "Now\nallow me\nto introduce\nmyself >"); - } else if(m->page == 5) { - char buf[64]; - snprintf( - buf, - 64, - "%s %s%s", - "I am", - my_name ? my_name : "Unknown", - ",\ncyberdolphin\nliving in your\npocket >"); - canvas_draw_icon(canvas, 0, height - 49, &I_DolphinFirstStart5_54x49); - elements_multiline_text_framed(canvas, 60, 13 + STATUS_BAR_Y_SHIFT, buf); - } else if(m->page == 6) { - canvas_draw_icon(canvas, 0, height - 51, &I_DolphinFirstStart6_58x54); - elements_multiline_text_framed( - canvas, - 63, - 13 + STATUS_BAR_Y_SHIFT, - "I can grow\nsmart'n'cool\nif you use me\noften >"); - } else if(m->page == 7) { - canvas_draw_icon(canvas, width - 61, height - 51, &I_DolphinFirstStart7_61x51); - elements_multiline_text_framed( - canvas, 0, 13 + STATUS_BAR_Y_SHIFT, "As long as\nyou read, write\nand emulate >"); - } else if(m->page == 8) { - canvas_draw_icon(canvas, width - 56, height - 51, &I_DolphinFirstStart8_56x51); - elements_multiline_text_framed( - canvas, - 0, - 13 + STATUS_BAR_Y_SHIFT, - "You can check\nmy level and\nmood in the\nPassport menu"); - } -} - -static bool desktop_first_start_input(InputEvent* event, void* context) { - furi_assert(event); - DesktopFirstStartView* instance = context; - - if(event->type == InputTypeShort) { - DesktopFirstStartViewModel* model = view_get_model(instance->view); - if(event->key == InputKeyLeft) { - if(model->page > 0) model->page--; - } else if(event->key == InputKeyRight) { - uint32_t page = ++model->page; - if(page > 8) { - instance->callback(DesktopFirstStartCompleted, instance->context); - } - } - view_commit_model(instance->view, true); - } - - if(event->key == InputKeyOk) { - if(event->type == InputTypePress) { - osTimerStart(instance->timer, DESKTOP_FIRST_START_POWEROFF_SHORT); - } else if(event->type == InputTypeRelease) { - osTimerStop(instance->timer); - } - } - - return true; -} - -static void desktop_first_start_timer_callback(void* context) { - DesktopFirstStartView* instance = context; - instance->callback(DesktopFirstStartPoweroff, instance->context); -} - -static void desktop_first_start_enter(void* context) { - DesktopFirstStartView* instance = context; - - furi_assert(instance->timer == NULL); - instance->timer = osTimerNew(desktop_first_start_timer_callback, osTimerOnce, instance, NULL); - - osTimerStart(instance->timer, DESKTOP_FIRST_START_POWEROFF_LONG); -} - -static void desktop_first_start_exit(void* context) { - DesktopFirstStartView* instance = context; - - osTimerStop(instance->timer); - osTimerDelete(instance->timer); - instance->timer = NULL; -} - -DesktopFirstStartView* desktop_first_start_alloc() { - DesktopFirstStartView* instance = malloc(sizeof(DesktopFirstStartView)); - instance->view = view_alloc(); - view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(DesktopFirstStartViewModel)); - view_set_context(instance->view, instance); - view_set_draw_callback(instance->view, (ViewDrawCallback)desktop_first_start_draw); - view_set_input_callback(instance->view, desktop_first_start_input); - view_set_enter_callback(instance->view, desktop_first_start_enter); - view_set_exit_callback(instance->view, desktop_first_start_exit); - - return instance; -} - -void desktop_first_start_free(DesktopFirstStartView* instance) { - furi_assert(instance); - - view_free(instance->view); - free(instance); -} - -View* desktop_first_start_get_view(DesktopFirstStartView* instance) { - furi_assert(instance); - return instance->view; -} - -void desktop_first_start_set_callback( - DesktopFirstStartView* instance, - DesktopFirstStartViewCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - instance->callback = callback; - instance->context = context; -} diff --git a/applications/desktop/views/desktop_view_first_start.h b/applications/desktop/views/desktop_view_first_start.h deleted file mode 100644 index 9b7b3c93df4f..000000000000 --- a/applications/desktop/views/desktop_view_first_start.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -#include "desktop_events.h" - -typedef struct DesktopFirstStartView DesktopFirstStartView; - -typedef void (*DesktopFirstStartViewCallback)(DesktopEvent event, void* context); - -DesktopFirstStartView* desktop_first_start_alloc(); - -void desktop_first_start_free(DesktopFirstStartView* main_view); - -View* desktop_first_start_get_view(DesktopFirstStartView* main_view); - -void desktop_first_start_set_callback( - DesktopFirstStartView* main_view, - DesktopFirstStartViewCallback callback, - void* context); diff --git a/applications/desktop/views/desktop_view_slideshow.c b/applications/desktop/views/desktop_view_slideshow.c new file mode 100644 index 000000000000..97f779b58977 --- /dev/null +++ b/applications/desktop/views/desktop_view_slideshow.c @@ -0,0 +1,108 @@ +#include +#include +#include + +#include "../desktop_i.h" +#include "desktop_view_slideshow.h" +#include "../helpers/slideshow.h" + +struct DesktopSlideshowView { + View* view; + DesktopSlideshowViewCallback callback; + void* context; +}; + +typedef struct { + uint8_t page; + Slideshow* slideshow; +} DesktopSlideshowViewModel; + +static void desktop_view_slideshow_draw(Canvas* canvas, void* model) { + DesktopSlideshowViewModel* m = model; + + canvas_clear(canvas); + slideshow_draw(m->slideshow, canvas, 0, 0); +} + +static bool desktop_view_slideshow_input(InputEvent* event, void* context) { + furi_assert(event); + DesktopSlideshowView* instance = context; + + if(event->type == InputTypeShort) { + DesktopSlideshowViewModel* model = view_get_model(instance->view); + bool end_slideshow = false; + switch(event->key) { + case InputKeyLeft: + slideshow_goback(model->slideshow); + break; + case InputKeyRight: + case InputKeyOk: + end_slideshow = !slideshow_advance(model->slideshow); + break; + case InputKeyBack: + end_slideshow = true; + default: + break; + } + if(end_slideshow) { + instance->callback(DesktopSlideshowCompleted, instance->context); + } + view_commit_model(instance->view, true); + } + + return true; +} + +static void desktop_view_slideshow_enter(void* context) { + DesktopSlideshowView* instance = context; + + DesktopSlideshowViewModel* model = view_get_model(instance->view); + model->slideshow = slideshow_alloc(); + if(!slideshow_load(model->slideshow, "/int/slideshow")) { + instance->callback(DesktopSlideshowCompleted, instance->context); + } + view_commit_model(instance->view, false); +} + +static void desktop_view_slideshow_exit(void* context) { + DesktopSlideshowView* instance = context; + + DesktopSlideshowViewModel* model = view_get_model(instance->view); + slideshow_free(model->slideshow); + view_commit_model(instance->view, false); +} + +DesktopSlideshowView* desktop_view_slideshow_alloc() { + DesktopSlideshowView* instance = malloc(sizeof(DesktopSlideshowView)); + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(DesktopSlideshowViewModel)); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, (ViewDrawCallback)desktop_view_slideshow_draw); + view_set_input_callback(instance->view, desktop_view_slideshow_input); + view_set_enter_callback(instance->view, desktop_view_slideshow_enter); + view_set_exit_callback(instance->view, desktop_view_slideshow_exit); + + return instance; +} + +void desktop_view_slideshow_free(DesktopSlideshowView* instance) { + furi_assert(instance); + + view_free(instance->view); + free(instance); +} + +View* desktop_view_slideshow_get_view(DesktopSlideshowView* instance) { + furi_assert(instance); + return instance->view; +} + +void desktop_view_slideshow_set_callback( + DesktopSlideshowView* instance, + DesktopSlideshowViewCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + instance->callback = callback; + instance->context = context; +} \ No newline at end of file diff --git a/applications/desktop/views/desktop_view_slideshow.h b/applications/desktop/views/desktop_view_slideshow.h new file mode 100644 index 000000000000..5b45a6b7029b --- /dev/null +++ b/applications/desktop/views/desktop_view_slideshow.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "desktop_events.h" + +typedef struct DesktopSlideshowView DesktopSlideshowView; + +typedef void (*DesktopSlideshowViewCallback)(DesktopEvent event, void* context); + +DesktopSlideshowView* desktop_view_slideshow_alloc(); + +void desktop_view_slideshow_free(DesktopSlideshowView* main_view); + +View* desktop_view_slideshow_get_view(DesktopSlideshowView* main_view); + +void desktop_view_slideshow_set_callback( + DesktopSlideshowView* main_view, + DesktopSlideshowViewCallback callback, + void* context); diff --git a/applications/updater/util/update_task.c b/applications/updater/util/update_task.c index 58b0c975ec8e..316fe6802e53 100644 --- a/applications/updater/util/update_task.c +++ b/applications/updater/util/update_task.c @@ -24,6 +24,7 @@ static const char* update_task_stage_descr[] = { [UpdateTaskStageLfsBackup] = "Backing up LFS", [UpdateTaskStageLfsRestore] = "Restoring LFS", [UpdateTaskStageResourcesUpdate] = "Updating resources", + [UpdateTaskStageSplashscreenInstall] = "Installing splashscreen", [UpdateTaskStageCompleted] = "Restarting...", [UpdateTaskStageError] = "Error", [UpdateTaskStageOBError] = "OB, report", @@ -41,13 +42,13 @@ static const UpdateTaskStageGroupMap update_task_stage_progress[] = { [UpdateTaskStageProgress] = STAGE_DEF(UpdateTaskStageGroupMisc, 0), [UpdateTaskStageReadManifest] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 5), - [UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 30), + [UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 15), - [UpdateTaskStageRadioImageValidate] = STAGE_DEF(UpdateTaskStageGroupRadio, 30), + [UpdateTaskStageRadioImageValidate] = STAGE_DEF(UpdateTaskStageGroupRadio, 10), [UpdateTaskStageRadioErase] = STAGE_DEF(UpdateTaskStageGroupRadio, 50), - [UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 100), - [UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 5), - [UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 70), + [UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 90), + [UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 15), + [UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 60), [UpdateTaskStageOBValidation] = STAGE_DEF(UpdateTaskStageGroupOptionBytes, 10), @@ -58,6 +59,7 @@ static const UpdateTaskStageGroupMap update_task_stage_progress[] = { [UpdateTaskStageLfsRestore] = STAGE_DEF(UpdateTaskStageGroupPostUpdate, 30), [UpdateTaskStageResourcesUpdate] = STAGE_DEF(UpdateTaskStageGroupResources, 255), + [UpdateTaskStageSplashscreenInstall] = STAGE_DEF(UpdateTaskStageGroupSplashscreen, 5), [UpdateTaskStageCompleted] = STAGE_DEF(UpdateTaskStageGroupMisc, 1), [UpdateTaskStageError] = STAGE_DEF(UpdateTaskStageGroupMisc, 1), @@ -79,6 +81,9 @@ static UpdateTaskStageGroup update_task_get_task_groups(UpdateTask* update_task) if(!string_empty_p(manifest->resource_bundle)) { ret |= UpdateTaskStageGroupResources; } + if(!string_empty_p(manifest->splash_file)) { + ret |= UpdateTaskStageGroupSplashscreen; + } return ret; } diff --git a/applications/updater/util/update_task.h b/applications/updater/util/update_task.h index ac9dadd6f197..1f2915568527 100644 --- a/applications/updater/util/update_task.h +++ b/applications/updater/util/update_task.h @@ -33,6 +33,7 @@ typedef enum { UpdateTaskStageLfsRestore, UpdateTaskStageResourcesUpdate, + UpdateTaskStageSplashscreenInstall, UpdateTaskStageCompleted, UpdateTaskStageError, @@ -52,6 +53,7 @@ typedef enum { UpdateTaskStageGroupRadio = 1 << 4, UpdateTaskStageGroupPostUpdate = 1 << 5, UpdateTaskStageGroupResources = 1 << 6, + UpdateTaskStageGroupSplashscreen = 1 << 7, } UpdateTaskStageGroup; typedef struct { diff --git a/applications/updater/util/update_task_worker_backup.c b/applications/updater/util/update_task_worker_backup.c index 011510ed9612..f1ce52817991 100644 --- a/applications/updater/util/update_task_worker_backup.c +++ b/applications/updater/util/update_task_worker_backup.c @@ -93,6 +93,19 @@ static bool update_task_post_update(UpdateTask* update_task) { CHECK_RESULT(tar_archive_unpack_to(archive, EXT_PATH)); } } + + if(update_task->state.groups & UpdateTaskStageGroupSplashscreen) { + update_task_set_progress(update_task, UpdateTaskStageSplashscreenInstall, 0); + string_t tmp_path; + string_init_set(tmp_path, update_task->update_path); + path_append(tmp_path, string_get_cstr(update_task->manifest->splash_file)); + if(storage_common_copy( + update_task->storage, string_get_cstr(tmp_path), "/int/slideshow") != FSE_OK) { + // actually, not critical + } + string_clear(tmp_path); + update_task_set_progress(update_task, UpdateTaskStageSplashscreenInstall, 100); + } success = true; } while(false); diff --git a/assets/slideshow/update_default/frame_00.png b/assets/slideshow/update_default/frame_00.png new file mode 100644 index 0000000000000000000000000000000000000000..385fbbe061539ecd682922a07996d5b5ad23bfd9 GIT binary patch literal 2211 zcmbVOdrT8|94~D{53CHZTNM2Sf&>Bq zML?34G?C%CzBNQk_SP~j&` zJVS~cZ|6AANV;t!Rv=udK%u!-l45<5-FZ?-VHL(qii`o4k`K}j4m+kJaFBoXJE)RC z(Gb+i(X6vF0>$MhCdW}brY6)n0#&{Q1*J!mBKay{tCg_$1d;SnjKyq#fl~^WrNQ2M zm6LShat(!RxoJx`!_6z8nIjUSDa73R5`f78Q7R}I@)k>Wf z!!k{JbC%MKXKGL^OM_DF#TMF}gshjM*O;G`EQL(Of_P-4Rlv+@#ON zfH@5M@&yGTEJT`Eqk~OHLdklWmk@5$qzg^aVQnx*!3yY&3~^}{`4BKZuqzM7e2IE{ z3-|!_SZphzO)Yp7P zRX@MbICGh{rX{812W?#OKy=3EdrFFD0l|KGh1HCvNv_IiT*b z9oW11DeITjdI>}qxIJJEgp(Xlo|aLs33KX>lF_2)p>_1V2iYo07@J#u8nwT0c+ zi)s#J#mU=>n&;?ZHF1~gOo!sQ)+X22lUhn|%(3)e-FRy0)f?m~Z+35O>ifQNoYXxAO6^L@uaeCaI5|7?9P(*-2NkV&sN#j zu|gwpcCr27*-5w7AKvoSv%!+WyhApsF5#P>mc-7Qu|K%LnD}=xT1zKB8@v~r*p**# zXaDJ=71RH^-SEb&cY9hcSEn8PcyM2v_jb)&+Z6TP{+m0NSSMExbl+U|MJYP*!p*f4 zR=s{6y&Lxl);;m)y2f@(QhdXQrp3#@Pxe5kR?LZd98)+o`Z(EVX=;45HLm@Ve2?!u zotm4r2&t~W6qDLC)hSGv_F&%g>^)7oGbzeIrOT#W2{$|}JpE5GYPpq@e^+<>arVyV z=QPKX{oJp;GinPCMm^d1X%!Tc%bg+mH*ZqB`Q2n=c3@ztY$$41{C3;v^{SQ9{{l;9 Kp1C=rwB}#tL-H*E literal 0 HcmV?d00001 diff --git a/assets/splash.mk b/assets/splash.mk new file mode 100644 index 000000000000..6b01b5c3bca0 --- /dev/null +++ b/assets/splash.mk @@ -0,0 +1,3 @@ +ASSETS_DIR ?= $(PROJECT_ROOT)/assets +UPDATER_SPLASH ?= update_default +UPDATER_SPLASH_DIR := $(ASSETS_DIR)/slideshow/$(UPDATER_SPLASH) diff --git a/lib/update_util/update_manifest.c b/lib/update_util/update_manifest.c index 2fe0a1ef35f0..d1ac0d7d0735 100644 --- a/lib/update_util/update_manifest.c +++ b/lib/update_util/update_manifest.c @@ -17,6 +17,7 @@ #define MANIFEST_KEY_OB_REFERENCE "OB reference" #define MANIFEST_KEY_OB_MASK "OB mask" #define MANIFEST_KEY_OB_WRITE_MASK "OB write mask" +#define MANIFEST_KEY_SPLASH_FILE "Splashscreen" UpdateManifest* update_manifest_alloc() { UpdateManifest* update_manifest = malloc(sizeof(UpdateManifest)); @@ -25,6 +26,7 @@ UpdateManifest* update_manifest_alloc() { string_init(update_manifest->radio_image); string_init(update_manifest->staged_loader_file); string_init(update_manifest->resource_bundle); + string_init(update_manifest->splash_file); update_manifest->target = 0; update_manifest->manifest_version = 0; memset(update_manifest->ob_reference.bytes, 0, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES); @@ -41,6 +43,7 @@ void update_manifest_free(UpdateManifest* update_manifest) { string_clear(update_manifest->radio_image); string_clear(update_manifest->staged_loader_file); string_clear(update_manifest->resource_bundle); + string_clear(update_manifest->splash_file); free(update_manifest); } @@ -107,6 +110,9 @@ static bool update_manifest->ob_write_mask.bytes, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES); + flipper_format_read_string( + flipper_file, MANIFEST_KEY_SPLASH_FILE, update_manifest->splash_file); + update_manifest->valid = (!string_empty_p(update_manifest->firmware_dfu_image) || !string_empty_p(update_manifest->radio_image) || diff --git a/lib/update_util/update_manifest.h b/lib/update_util/update_manifest.h index 2b1e6857b9ff..2b0c91794777 100644 --- a/lib/update_util/update_manifest.h +++ b/lib/update_util/update_manifest.h @@ -42,6 +42,7 @@ typedef struct { FuriHalFlashRawOptionByteData ob_reference; FuriHalFlashRawOptionByteData ob_compare_mask; FuriHalFlashRawOptionByteData ob_write_mask; + string_t splash_file; bool valid; } UpdateManifest; diff --git a/scripts/bin2dfu.py b/scripts/bin2dfu.py index abd538288b28..7484738f1f84 100755 --- a/scripts/bin2dfu.py +++ b/scripts/bin2dfu.py @@ -38,9 +38,9 @@ def convert(self): return 1 with open(self.args.input, mode="rb") as file: - bin = file.read() + bindata = file.read() - data = struct.pack(" Date: Tue, 21 Jun 2022 17:45:55 +0300 Subject: [PATCH 163/184] [FL-2548] Infrared: show error if no SD card/databases (#1337) * Add Database error scene * More general popup callback name --- applications/infrared/infrared.c | 8 ++-- applications/infrared/infrared_custom_event.h | 2 +- applications/infrared/infrared_i.h | 4 +- .../infrared/scenes/infrared_scene_config.h | 1 + .../scenes/infrared_scene_edit_delete_done.c | 4 +- .../scenes/infrared_scene_edit_rename_done.c | 4 +- .../scenes/infrared_scene_error_databases.c | 37 +++++++++++++++++++ .../scenes/infrared_scene_learn_done.c | 4 +- .../scenes/infrared_scene_universal_tv.c | 2 +- .../notification/notification_messages.c | 9 +++++ .../notification/notification_messages.h | 3 ++ 11 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 applications/infrared/scenes/infrared_scene_error_databases.c diff --git a/applications/infrared/infrared.c b/applications/infrared/infrared.c index ee6b931eddef..e641302cd835 100644 --- a/applications/infrared/infrared.c +++ b/applications/infrared/infrared.c @@ -8,7 +8,9 @@ static const NotificationSequence* infrared_notification_sequences[] = { &sequence_set_only_green_255, &sequence_reset_green, &sequence_blink_cyan_10, - &sequence_blink_magenta_10}; + &sequence_blink_magenta_10, + &sequence_solid_yellow, + &sequence_reset_rgb}; static void infrared_make_app_folder(Infrared* infrared) { if(!storage_simply_mkdir(infrared->storage, INFRARED_APP_FOLDER)) { @@ -360,11 +362,11 @@ void infrared_text_input_callback(void* context) { infrared->view_dispatcher, InfraredCustomEventTypeTextEditDone); } -void infrared_popup_timeout_callback(void* context) { +void infrared_popup_closed_callback(void* context) { furi_assert(context); Infrared* infrared = context; view_dispatcher_send_custom_event( - infrared->view_dispatcher, InfraredCustomEventTypePopupTimeout); + infrared->view_dispatcher, InfraredCustomEventTypePopupClosed); } int32_t infrared_app(void* p) { diff --git a/applications/infrared/infrared_custom_event.h b/applications/infrared/infrared_custom_event.h index d991afb9c1a8..46d75a9e9577 100644 --- a/applications/infrared/infrared_custom_event.h +++ b/applications/infrared/infrared_custom_event.h @@ -11,7 +11,7 @@ enum InfraredCustomEventType { InfraredCustomEventTypeTransmitStopped, InfraredCustomEventTypeSignalReceived, InfraredCustomEventTypeTextEditDone, - InfraredCustomEventTypePopupTimeout, + InfraredCustomEventTypePopupClosed, InfraredCustomEventTypeButtonSelected, InfraredCustomEventTypeBackPressed, }; diff --git a/applications/infrared/infrared_i.h b/applications/infrared/infrared_i.h index 06c6a5f7ea3a..5c447adc34fd 100644 --- a/applications/infrared/infrared_i.h +++ b/applications/infrared/infrared_i.h @@ -113,6 +113,8 @@ typedef enum { InfraredNotificationMessageGreenOff, InfraredNotificationMessageBlinkRead, InfraredNotificationMessageBlinkSend, + InfraredNotificationMessageYellowOn, + InfraredNotificationMessageYellowOff, } InfraredNotificationMessage; bool infrared_add_remote_with_button(Infrared* infrared, const char* name, InfraredSignal* signal); @@ -129,4 +131,4 @@ void infrared_show_loading_popup(Infrared* infrared, bool show); void infrared_signal_sent_callback(void* context); void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal); void infrared_text_input_callback(void* context); -void infrared_popup_timeout_callback(void* context); +void infrared_popup_closed_callback(void* context); diff --git a/applications/infrared/scenes/infrared_scene_config.h b/applications/infrared/scenes/infrared_scene_config.h index 3677ab3c9fcb..c4e083c1772c 100644 --- a/applications/infrared/scenes/infrared_scene_config.h +++ b/applications/infrared/scenes/infrared_scene_config.h @@ -15,3 +15,4 @@ ADD_SCENE(infrared, remote_list, RemoteList) ADD_SCENE(infrared, universal, Universal) ADD_SCENE(infrared, universal_tv, UniversalTV) ADD_SCENE(infrared, debug, Debug) +ADD_SCENE(infrared, error_databases, ErrorDatabases) diff --git a/applications/infrared/scenes/infrared_scene_edit_delete_done.c b/applications/infrared/scenes/infrared_scene_edit_delete_done.c index 688c3a45701e..4502abbdbc25 100644 --- a/applications/infrared/scenes/infrared_scene_edit_delete_done.c +++ b/applications/infrared/scenes/infrared_scene_edit_delete_done.c @@ -7,7 +7,7 @@ void infrared_scene_edit_delete_done_on_enter(void* context) { popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); - popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -21,7 +21,7 @@ bool infrared_scene_edit_delete_done_on_event(void* context, SceneManagerEvent e bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == InfraredCustomEventTypePopupTimeout) { + if(event.event == InfraredCustomEventTypePopupClosed) { const InfraredEditTarget edit_target = infrared->app_state.edit_target; if(edit_target == InfraredEditTargetButton) { scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/infrared/scenes/infrared_scene_edit_rename_done.c b/applications/infrared/scenes/infrared_scene_edit_rename_done.c index 60a26954d725..54b18ab6108b 100644 --- a/applications/infrared/scenes/infrared_scene_edit_rename_done.c +++ b/applications/infrared/scenes/infrared_scene_edit_rename_done.c @@ -7,7 +7,7 @@ void infrared_scene_edit_rename_done_on_enter(void* context) { popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); - popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -20,7 +20,7 @@ bool infrared_scene_edit_rename_done_on_event(void* context, SceneManagerEvent e bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == InfraredCustomEventTypePopupTimeout) { + if(event.event == InfraredCustomEventTypePopupClosed) { scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); consumed = true; } diff --git a/applications/infrared/scenes/infrared_scene_error_databases.c b/applications/infrared/scenes/infrared_scene_error_databases.c new file mode 100644 index 000000000000..4ed4dee583be --- /dev/null +++ b/applications/infrared/scenes/infrared_scene_error_databases.c @@ -0,0 +1,37 @@ +#include "../infrared_i.h" + +void infrared_scene_error_databases_on_enter(void* context) { + Infrared* infrared = context; + Popup* popup = infrared->popup; + + popup_set_icon(popup, 5, 11, &I_SDQuestion_35x43); + popup_set_text( + popup, "Function requires\nSD card with fresh\ndatabases.", 47, 17, AlignLeft, AlignTop); + + popup_set_context(popup, context); + popup_set_callback(popup, infrared_popup_closed_callback); + + infrared_play_notification_message(infrared, InfraredNotificationMessageYellowOn); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); +} + +bool infrared_scene_error_databases_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypePopupClosed) { + scene_manager_search_and_switch_to_previous_scene( + infrared->scene_manager, InfraredSceneUniversal); + consumed = true; + } + } + + return consumed; +} + +void infrared_scene_error_databases_on_exit(void* context) { + Infrared* infrared = context; + popup_reset(infrared->popup); + infrared_play_notification_message(infrared, InfraredNotificationMessageYellowOff); +} diff --git a/applications/infrared/scenes/infrared_scene_learn_done.c b/applications/infrared/scenes/infrared_scene_learn_done.c index a24bb9184007..eb6cced841d9 100644 --- a/applications/infrared/scenes/infrared_scene_learn_done.c +++ b/applications/infrared/scenes/infrared_scene_learn_done.c @@ -15,7 +15,7 @@ void infrared_scene_learn_done_on_enter(void* context) { popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); } - popup_set_callback(popup, infrared_popup_timeout_callback); + popup_set_callback(popup, infrared_popup_closed_callback); popup_set_context(popup, context); popup_set_timeout(popup, 1500); popup_enable_timeout(popup); @@ -28,7 +28,7 @@ bool infrared_scene_learn_done_on_event(void* context, SceneManagerEvent event) bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == InfraredCustomEventTypePopupTimeout) { + if(event.event == InfraredCustomEventTypePopupClosed) { scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); consumed = true; } diff --git a/applications/infrared/scenes/infrared_scene_universal_tv.c b/applications/infrared/scenes/infrared_scene_universal_tv.c index f3a9a06bce9d..83b084c37c43 100644 --- a/applications/infrared/scenes/infrared_scene_universal_tv.c +++ b/applications/infrared/scenes/infrared_scene_universal_tv.c @@ -98,7 +98,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { infrared_show_loading_popup(infrared, false); if(!success) { - scene_manager_previous_scene(infrared->scene_manager); + scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases); } } diff --git a/applications/notification/notification_messages.c b/applications/notification/notification_messages.c index b14c08e3b463..b469cb5f11fc 100644 --- a/applications/notification/notification_messages.c +++ b/applications/notification/notification_messages.c @@ -335,6 +335,15 @@ const NotificationSequence sequence_set_blue_255 = { NULL, }; +// Solid colors +const NotificationSequence sequence_solid_yellow = { + &message_red_255, + &message_green_255, + &message_blue_0, + &message_do_not_reset, + NULL, +}; + // Blink const NotificationSequence sequence_blink_blue_10 = { &message_blue_255, diff --git a/applications/notification/notification_messages.h b/applications/notification/notification_messages.h index a0ef654e7c7e..92a105f6a523 100644 --- a/applications/notification/notification_messages.h +++ b/applications/notification/notification_messages.h @@ -103,6 +103,9 @@ extern const NotificationSequence sequence_set_red_255; extern const NotificationSequence sequence_set_green_255; extern const NotificationSequence sequence_set_blue_255; +// Solid colors +extern const NotificationSequence sequence_solid_yellow; + // Blink extern const NotificationSequence sequence_blink_blue_10; extern const NotificationSequence sequence_blink_red_10; From 62b61e1c73e0b98e74884b06342d88e2e482f06a Mon Sep 17 00:00:00 2001 From: Kevin Wallace <184975+kevinwallace@users.noreply.github.com> Date: Tue, 21 Jun 2022 07:58:22 -0700 Subject: [PATCH 164/184] nfc: DESFire fixes (#1334) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: don't give up on reading DESFire card if GET_KEY_SETTINGS fails Some cards are configured to refuse to provide key settings, but still provide other info. For example, Ubiquiti UniFi Protect access cards won't list keys or applications, but will still answer GET_FREE_MEMORY. * nfc: don't show error when saving DESFire card with no applications * nfc: fix DESFire load with 0 applications or no PICC key settings Co-authored-by: Kevin Wallace Co-authored-by: gornekich Co-authored-by: あく --- applications/nfc/nfc_device.c | 67 +++++++++++++++++++---------------- applications/nfc/nfc_worker.c | 41 +++++++++++---------- 2 files changed, 56 insertions(+), 52 deletions(-) diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index 51e14a6c1947..d5cc422f9a9f 100644 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -495,16 +495,17 @@ static bool nfc_device_save_mifare_df_data(FlipperFormat* file, NfcDevice* dev) n_apps++; } if(!flipper_format_write_uint32(file, "Application Count", &n_apps, 1)) break; - if(n_apps == 0) break; - tmp = malloc(n_apps * 3); - int i = 0; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - memcpy(tmp + i, app->id, 3); - i += 3; - } - if(!flipper_format_write_hex(file, "Application IDs", tmp, n_apps * 3)) break; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - if(!nfc_device_save_mifare_df_app(file, app)) break; + if(n_apps) { + tmp = malloc(n_apps * 3); + int i = 0; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + memcpy(tmp + i, app->id, 3); + i += 3; + } + if(!flipper_format_write_hex(file, "Application IDs", tmp, n_apps * 3)) break; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + if(!nfc_device_save_mifare_df_app(file, app)) break; + } } saved = true; } while(false); @@ -532,32 +533,36 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { break; } } - data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); - memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); - if(!nfc_device_load_mifare_df_key_settings(file, data->master_key_settings, "PICC")) { - free(data->master_key_settings); - data->master_key_settings = NULL; - break; + if(flipper_format_key_exist(file, "PICC Change Key ID")) { + data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); + memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); + if(!nfc_device_load_mifare_df_key_settings(file, data->master_key_settings, "PICC")) { + free(data->master_key_settings); + data->master_key_settings = NULL; + break; + } } uint32_t n_apps; if(!flipper_format_read_uint32(file, "Application Count", &n_apps, 1)) break; - tmp = malloc(n_apps * 3); - if(!flipper_format_read_hex(file, "Application IDs", tmp, n_apps * 3)) break; - bool parsed_apps = true; - MifareDesfireApplication** app_head = &data->app_head; - for(uint32_t i = 0; i < n_apps; i++) { - MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication)); - memset(app, 0, sizeof(MifareDesfireApplication)); - memcpy(app->id, &tmp[i * 3], 3); - if(!nfc_device_load_mifare_df_app(file, app)) { - free(app); - parsed_apps = false; - break; + if(n_apps) { + tmp = malloc(n_apps * 3); + if(!flipper_format_read_hex(file, "Application IDs", tmp, n_apps * 3)) break; + bool parsed_apps = true; + MifareDesfireApplication** app_head = &data->app_head; + for(uint32_t i = 0; i < n_apps; i++) { + MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication)); + memset(app, 0, sizeof(MifareDesfireApplication)); + memcpy(app->id, &tmp[i * 3], 3); + if(!nfc_device_load_mifare_df_app(file, app)) { + free(app); + parsed_apps = false; + break; + } + *app_head = app; + app_head = &app->next; } - *app_head = app; - app_head = &app->next; + if(!parsed_apps) break; } - if(!parsed_apps) break; parsed = true; } while(false); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 8c8512f322fc..11b6b51ef126 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -576,28 +576,27 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); free(data->master_key_settings); data->master_key_settings = NULL; - continue; - } - - MifareDesfireKeyVersion** key_version_head = - &data->master_key_settings->key_version_head; - for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { - tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); - if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { - FURI_LOG_W(TAG, "Bad exchange getting key version"); - continue; - } - MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); - memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); - key_version->id = key_id; - if(!mf_df_parse_get_key_version_response( - tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { - FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); - free(key_version); - continue; + } else { + MifareDesfireKeyVersion** key_version_head = + &data->master_key_settings->key_version_head; + for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { + tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); + if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { + FURI_LOG_W(TAG, "Bad exchange getting key version"); + continue; + } + MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); + memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); + key_version->id = key_id; + if(!mf_df_parse_get_key_version_response( + tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) { + FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); + free(key_version); + continue; + } + *key_version_head = key_version; + key_version_head = &key_version->next; } - *key_version_head = key_version; - key_version_head = &key_version->next; } } From d06e61f501be5c45fa0aafe4e243ef5ba912ee3e Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Tue, 21 Jun 2022 09:04:35 -0600 Subject: [PATCH 165/184] nfc: NTAG21x complete emulation (#1313) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: Refactor Mifare Ultralight feature flags Unify them in both reader and emulator to make handling easier * nfc: Refactor MFUL PWD_AUTH and add AUTHLIM counter * nfc: Add MFUL EV1 VCSL command emulation * nfc: Enforce message size check in MFUL emulation Also fix READ_CNT byte order, but it's not fully working * nfc: Add MFUL auth counter serialization Also fill counter on successful read from tag * nfc: Fix MFUL INCR_CNT emulation * nfc: Fix MFUL READ_CNT emulation * nfc: Refactor MFUL emulation and implement full write support * nfc: Fix Mifare Ultralight serialization * nfc: Add MFUL OTP/CC handling * nfc: Make sure MF0UL21 dynamic lock byte 3 also reads 0xBD * nfc: Small MFUL refactor and fix CFGLCK behavior * WIP: nfc: MFUL read support with ASCII mirror and auth roll-over This is too complex and I don't like it * nfc: Simplify MFUL read emulation, fix mirror range check * nfc: Implement MFUL auth and ASCII mirror for FAST_READ * nfc: Fix MFUL read roll-over with AUTH0 set * nfc: Implement MFUL read counter increment * nfc: Align ASCII mirror to NTAG21x behavior * nfc: Handle invalid command in MFUL emulation * nfc: Fix MFUL static lock check * nfc: Refactor MFUL emulation to use cached config pages * nfc: Refactor MFUL auth counter to count up instead of down * nfc: Add missing NULL check * WIP: nfc: Various MFUL emulation behavior tweaks * WIP: nfc: More MFUL emulation behavior adjustments * nfc: Match AUTHLIM emulation to NTAG21x behavior * nfc: Fix MFUL dynamic lock emulation * nfc: Fix typo in MFUL read counters * nfc: Fix typo in MFUL FAST_READ emulation * nfc: Increase emulation TX buffer size Enough space for if someone requests FAST_READ of all pages of an NTAG * nfc: Fix MFUL negative verification counter overflow * nfc: Change auth counter kv name * nfc: Fix NTAG I2C FAST_READ emulation * nfc: Fix NTAG21x config reload behavior Co-authored-by: あく --- applications/nfc/nfc_device.c | 12 + applications/nfc/nfc_worker.c | 6 +- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 2 +- lib/nfc_protocols/mifare_ultralight.c | 1167 ++++++++++++++----- lib/nfc_protocols/mifare_ultralight.h | 85 +- 5 files changed, 951 insertions(+), 321 deletions(-) diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index d5cc422f9a9f..092d00896179 100644 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -120,6 +120,12 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) } } if(!pages_saved) break; + + // Write authentication counter + uint32_t auth_counter = data->curr_authlim; + if(!flipper_format_write_uint32(file, "Failed authentication attempts", &auth_counter, 1)) + break; + saved = true; } while(false); @@ -169,6 +175,12 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { } } if(!pages_parsed) break; + + // Read authentication counter + uint32_t auth_counter; + if(!flipper_format_read_uint32(file, "Failed authentication attempts", &auth_counter, 1)) + auth_counter = 0; + parsed = true; } while(false); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 11b6b51ef126..176b15c62240 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -319,11 +319,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { MfUltralightEmulator emulator = {}; mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data); while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) { - emulator.auth_success = false; - if(emulator.data.type >= MfUltralightTypeNTAGI2C1K) { - // Sector index needs to be reset - emulator.curr_sector = 0; - } + mf_ul_reset_emulation(&emulator, true); furi_hal_nfc_emulate_nfca( nfc_data->uid, nfc_data->uid_len, diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 3e6d18eb85c0..cba2a7030978 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -277,7 +277,7 @@ bool furi_hal_nfc_emulate_nfca( uint8_t buff_rx[256]; uint16_t buff_rx_size = 256; uint16_t buff_rx_len = 0; - uint8_t buff_tx[256]; + uint8_t buff_tx[1040]; uint16_t buff_tx_len = 0; uint32_t data_type = FURI_HAL_NFC_TXRX_DEFAULT; diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc_protocols/mifare_ultralight.c index fb425ea7a0d1..21dbd9c4c580 100644 --- a/lib/nfc_protocols/mifare_ultralight.c +++ b/lib/nfc_protocols/mifare_ultralight.c @@ -12,13 +12,38 @@ bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { return false; } +static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { + switch(type) { + case MfUltralightTypeUL11: + case MfUltralightTypeUL21: + return MfUltralightSupportFastRead | MfUltralightSupportCompatWrite | + MfUltralightSupportReadCounter | MfUltralightSupportIncrCounter | + MfUltralightSupportAuth | MfUltralightSupportSignature | + MfUltralightSupportTearingFlags | MfUltralightSupportVcsl; + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + return MfUltralightSupportFastRead | MfUltralightSupportCompatWrite | + MfUltralightSupportReadCounter | MfUltralightSupportAuth | + MfUltralightSupportSignature | MfUltralightSupportSingleCounter | + MfUltralightSupportAsciiMirror; + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2C2K: + return MfUltralightSupportFastRead | MfUltralightSupportSectorSelect; + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + return MfUltralightSupportFastRead | MfUltralightSupportAuth | + MfUltralightSupportFastWrite | MfUltralightSupportSignature | + MfUltralightSupportSectorSelect; + default: + // Assumed original MFUL 512-bit + return MfUltralightSupportNone; + } +} + static void mf_ul_set_default_version(MfUltralightReader* reader, MfUltralightData* data) { data->type = MfUltralightTypeUnknown; reader->pages_to_read = 16; - reader->support_fast_read = false; - reader->support_tearing_flags = false; - reader->support_counters = false; - reader->support_signature = false; } bool mf_ultralight_read_version( @@ -44,31 +69,15 @@ bool mf_ultralight_read_version( if(version->storage_size == 0x0B || version->storage_size == 0x00) { data->type = MfUltralightTypeUL11; reader->pages_to_read = 20; - reader->support_fast_read = true; - reader->support_tearing_flags = true; - reader->support_counters = true; - reader->support_signature = true; } else if(version->storage_size == 0x0E) { data->type = MfUltralightTypeUL21; reader->pages_to_read = 41; - reader->support_fast_read = true; - reader->support_tearing_flags = true; - reader->support_counters = true; - reader->support_signature = true; } else if(version->storage_size == 0x0F) { data->type = MfUltralightTypeNTAG213; reader->pages_to_read = 45; - reader->support_fast_read = true; - reader->support_tearing_flags = false; - reader->support_counters = false; - reader->support_signature = true; } else if(version->storage_size == 0x11) { data->type = MfUltralightTypeNTAG215; reader->pages_to_read = 135; - reader->support_fast_read = true; - reader->support_tearing_flags = false; - reader->support_counters = false; - reader->support_signature = true; } else if(version->prod_subtype == 5 && version->prod_ver_major == 2) { // NTAG I2C bool known = false; @@ -76,42 +85,30 @@ bool mf_ultralight_read_version( if(version->storage_size == 0x13) { data->type = MfUltralightTypeNTAGI2C1K; reader->pages_to_read = 231; - reader->support_signature = false; known = true; } else if(version->storage_size == 0x15) { data->type = MfUltralightTypeNTAGI2C2K; reader->pages_to_read = 485; - reader->support_signature = false; known = true; } } else if(version->prod_ver_minor == 2) { if(version->storage_size == 0x13) { data->type = MfUltralightTypeNTAGI2CPlus1K; reader->pages_to_read = 236; - reader->support_signature = true; known = true; } else if(version->storage_size == 0x15) { data->type = MfUltralightTypeNTAGI2CPlus2K; reader->pages_to_read = 492; - reader->support_signature = true; known = true; } } - if(known) { - reader->support_fast_read = true; - reader->support_tearing_flags = false; - reader->support_counters = false; - } else { + if(!known) { mf_ul_set_default_version(reader, data); } } else if(version->storage_size == 0x13) { data->type = MfUltralightTypeNTAG216; reader->pages_to_read = 231; - reader->support_fast_read = true; - reader->support_tearing_flags = false; - reader->support_counters = false; - reader->support_signature = true; } else { mf_ul_set_default_version(reader, data); break; @@ -119,9 +116,14 @@ bool mf_ultralight_read_version( version_read = true; } while(false); + reader->supported_features = mf_ul_get_features(data->type); return version_read; } +static int16_t mf_ultralight_page_addr_to_tag_addr(uint8_t sector, uint8_t page) { + return sector * 256 + page; +} + static int16_t mf_ultralight_ntag_i2c_addr_lin_to_tag_1k( int16_t linear_address, uint8_t* sector, @@ -404,6 +406,41 @@ static int16_t mf_ultralight_ntag_i2c_addr_tag_to_lin( } } +static MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data) { + if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) { + return (MfUltralightConfigPages*)&data->data[data->data_size - 4 * 4]; + } else if( + data->type >= MfUltralightTypeNTAGI2CPlus1K && + data->type <= MfUltralightTypeNTAGI2CPlus2K) { + return (MfUltralightConfigPages*)&data->data[0xe3 * 4]; + } else { + return NULL; + } +} + +static uint16_t mf_ultralight_calc_auth_count(MfUltralightData* data) { + if(mf_ul_get_features(data->type) & MfUltralightSupportAuth) { + MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data); + uint16_t scaled_authlim = config->access.authlim; + // NTAG I2C Plus uses 2^AUTHLIM attempts rather than the direct number + if(scaled_authlim > 0 && data->type >= MfUltralightTypeNTAGI2CPlus1K && + data->type <= MfUltralightTypeNTAGI2CPlus2K) { + scaled_authlim = 1 << scaled_authlim; + } + return scaled_authlim; + } + + return 0; +} + +// NTAG21x will NAK if NFC_CNT_EN unset, so preempt +static bool mf_ultralight_should_read_counters(MfUltralightData* data) { + if(data->type < MfUltralightTypeNTAG213 || data->type > MfUltralightTypeNTAG216) return true; + + MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data); + return config->access.nfc_cnt_en; +} + static bool mf_ultralight_sector_select(FuriHalNfcTxRxContext* tx_rx, uint8_t sector) { FURI_LOG_D(TAG, "Selecting sector %u", sector); tx_rx->tx_data[0] = MF_UL_SECTOR_SELECT; @@ -455,7 +492,7 @@ bool mf_ultralight_read_pages( tx_rx->tx_data[1] = tag_page; tx_rx->tx_bits = 16; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; - if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { + if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits < 16 * 8) { FURI_LOG_D( TAG, "Failed to read pages %d - %d", @@ -540,9 +577,11 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* uint8_t counter_read = 0; FURI_LOG_D(TAG, "Reading counters"); - for(size_t i = 0; i < 3; i++) { + bool is_single_counter = (mf_ul_get_features(data->type) & MfUltralightSupportSingleCounter) != + 0; + for(size_t i = is_single_counter ? 2 : 0; i < 3; i++) { tx_rx->tx_data[0] = MF_UL_READ_CNT; - tx_rx->rx_data[1] = i; + tx_rx->tx_data[1] = i; tx_rx->tx_bits = 16; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { @@ -554,7 +593,7 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* counter_read++; } - return counter_read == 2; + return counter_read == (is_single_counter ? 1 : 3); } bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) { @@ -589,38 +628,26 @@ bool mf_ul_read_card( // Read Mifare Ultralight version if(mf_ultralight_read_version(tx_rx, reader, data)) { - if(reader->support_signature) { + if(reader->supported_features & MfUltralightSupportSignature) { // Read Signature mf_ultralight_read_signature(tx_rx, data); } } - if(reader->support_counters) { - mf_ultralight_read_counters(tx_rx, data); - } - if(reader->support_tearing_flags) { - mf_ultralight_read_tearing_flags(tx_rx, data); - } - card_read = mf_ultralight_read_pages(tx_rx, reader, data); - return card_read; -} + card_read = mf_ultralight_read_pages(tx_rx, reader, data); -// TODO rework -static void mf_ul_protect_auth_data_on_read_command( - uint8_t* tx_buff, - uint8_t start_page, - uint8_t end_page, - MfUltralightEmulator* emulator) { - if(emulator->data.type >= MfUltralightTypeNTAG213) { - uint8_t pwd_page = (emulator->data.data_size / 4) - 2; - uint8_t pack_page = pwd_page + 1; - if((start_page <= pwd_page) && (end_page >= pwd_page)) { - memset(&tx_buff[(pwd_page - start_page) * 4], 0, 4); + if(card_read) { + if(reader->supported_features & MfUltralightSupportReadCounter && + mf_ultralight_should_read_counters(data)) { + mf_ultralight_read_counters(tx_rx, data); } - if((start_page <= pack_page) && (end_page >= pack_page)) { - memset(&tx_buff[(pack_page - start_page) * 4], 0, 2); + if(reader->supported_features & MfUltralightSupportTearingFlags) { + mf_ultralight_read_tearing_flags(tx_rx, data); } + data->curr_authlim = 0; } + + return card_read; } static void mf_ul_protect_auth_data_on_read_command_i2c( @@ -639,9 +666,8 @@ static void mf_ul_protect_auth_data_on_read_command_i2c( // Handle AUTH0 for sector 0 if(!emulator->auth_success) { - uint8_t access = emulator->data.data[228 * 4]; - if(access & 0x80) { - uint8_t auth0 = emulator->data.data[227 * 4 + 3]; + if(emulator->config_cache.access.prot) { + uint8_t auth0 = emulator->config_cache.auth0; if(auth0 < end_page) { // start_page is always < auth0; otherwise is NAK'd already uint8_t page_offset = auth0 - start_page; @@ -704,16 +730,29 @@ static void mf_ul_ntag_i2c_fill_cross_area_read( } } +static bool mf_ul_check_auth(MfUltralightEmulator* emulator, uint8_t start_page, bool is_write) { + if(!emulator->auth_success) { + if(start_page >= emulator->config_cache.auth0 && + (emulator->config_cache.access.prot || is_write)) + return false; + } + + if(is_write && emulator->config_cache.access.cfglck) { + uint16_t config_start_page = emulator->page_num - 4; + if(start_page == config_start_page || start_page == config_start_page + 1) return false; + } + + return true; +} + static bool mf_ul_ntag_i2c_plus_check_auth( MfUltralightEmulator* emulator, uint8_t start_page, bool is_write) { if(!emulator->auth_success) { - uint8_t access = emulator->data.data[228 * 4]; // Check NFC_PROT - if(emulator->curr_sector == 0 && ((access & 0x80) || is_write)) { - uint8_t auth0 = emulator->data.data[227 * 4 + 3]; - if(start_page >= auth0) return false; + if(emulator->curr_sector == 0 && (emulator->config_cache.access.prot || is_write)) { + if(start_page >= emulator->config_cache.auth0) return false; } else if(emulator->curr_sector == 1) { // We don't have to specifically check for type because this is done // by address translator @@ -725,43 +764,288 @@ static bool mf_ul_ntag_i2c_plus_check_auth( if(emulator->curr_sector == 1) { // Check NFC_DIS_SEC1 - uint8_t access = emulator->data.data[228 * 4]; - if(access & 0x20) return false; + if(emulator->config_cache.access.nfc_dis_sec1) return false; } return true; } +static int16_t mf_ul_get_dynamic_lock_page_addr(MfUltralightData* data) { + switch(data->type) { + case MfUltralightTypeUL21: + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + return data->data_size / 4 - 5; + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + return 0xe2; + case MfUltralightTypeNTAGI2C2K: + return 0x1e0; + default: + return -1; // No dynamic lock bytes + } +} + +// Returns true if page not locked +// write_page is tag address +static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) { + if(write_page < 2) return false; // Page 0-1 is always locked + if(write_page == 2) return true; // Page 2 does not have a lock flag + + // Check static lock bytes + if(write_page <= 15) { + uint16_t static_lock_bytes = emulator->data.data[10] | (emulator->data.data[11] << 8); + return (static_lock_bytes & (1 << write_page)) == 0; + } + + // Check dynamic lock bytes + + // Check max page + switch(emulator->data.type) { + case MfUltralightTypeUL21: + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + if(write_page >= emulator->page_num - 5) return true; + break; + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2CPlus1K: + if(write_page > 225) return true; + break; + case MfUltralightTypeNTAGI2C2K: + if(write_page > 479) return true; + break; + case MfUltralightTypeNTAGI2CPlus2K: + if(write_page >= 226 && write_page <= 255) return true; + if(write_page >= 512) return true; + break; + default: + furi_assert(false); + return true; + } + + int16_t dynamic_lock_index = mf_ul_get_dynamic_lock_page_addr(&emulator->data); + if(dynamic_lock_index == -1) return true; + // Run address through converter because NTAG I2C 2K is special + uint16_t valid_pages; // unused + dynamic_lock_index = + mf_ultralight_ntag_i2c_addr_tag_to_lin( + &emulator->data, dynamic_lock_index & 0xff, dynamic_lock_index >> 8, &valid_pages) * + 4; + + uint16_t dynamic_lock_bytes = emulator->data.data[dynamic_lock_index] | + (emulator->data.data[dynamic_lock_index + 1] << 8); + uint8_t shift; + + switch(emulator->data.type) { + // low byte LSB range, MSB range + case MfUltralightTypeUL21: + case MfUltralightTypeNTAG213: + // 16-17, 30-31 + shift = (write_page - 16) / 2; + break; + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2CPlus1K: + // 16-31, 128-129 + // 16-31, 128-143 + shift = (write_page - 16) / 16; + break; + case MfUltralightTypeNTAGI2C2K: + // 16-47, 240-271 + shift = (write_page - 16) / 32; + break; + case MfUltralightTypeNTAGI2CPlus2K: + // 16-47, 256-271 + if(write_page >= 208 && write_page <= 225) + shift = 6; + else if(write_page >= 256 && write_page <= 271) + shift = 7; + else + shift = (write_page - 16) / 32; + break; + default: + furi_assert(false); + shift = 0; + break; + } + + return (dynamic_lock_bytes & (1 << shift)) == 0; +} + +static void mf_ul_make_ascii_mirror(MfUltralightEmulator* emulator, string_t str) { + // Locals to improve readability + uint8_t mirror_page = emulator->config->mirror_page; + uint8_t mirror_byte = emulator->config->mirror.mirror_byte; + MfUltralightMirrorConf mirror_conf = emulator->config_cache.mirror.mirror_conf; + uint16_t last_user_page_index = emulator->page_num - 6; + bool uid_printed = false; + + if(mirror_conf == MfUltralightMirrorUid || mirror_conf == MfUltralightMirrorUidCounter) { + // UID range check + if(mirror_page < 4 || mirror_page > last_user_page_index - 3 || + (mirror_page == last_user_page_index - 3 && mirror_byte > 2)) { + if(mirror_conf == MfUltralightMirrorUid) return; + // NTAG21x has the peculiar behavior when UID+counter selected, if UID does not fit but + // counter will fit, it will actually mirror the counter + string_cat_str(str, " "); + } else { + for(int i = 0; i < 3; ++i) { + string_cat_printf(str, "%02X", emulator->data.data[i]); + } + // Skip BCC0 + for(int i = 4; i < 8; ++i) { + string_cat_printf(str, "%02X", emulator->data.data[i]); + } + uid_printed = true; + } + + uint16_t next_byte_offset = mirror_page * 4 + mirror_byte + 14; + if(mirror_conf == MfUltralightMirrorUidCounter) ++next_byte_offset; + mirror_page = next_byte_offset / 4; + mirror_byte = next_byte_offset % 4; + } + + if(mirror_conf == MfUltralightMirrorCounter || mirror_conf == MfUltralightMirrorUidCounter) { + // Counter is only printed if counter enabled + if(emulator->config_cache.access.nfc_cnt_en) { + // Counter protection check + if(emulator->config_cache.access.nfc_cnt_pwd_prot && !emulator->auth_success) return; + // Counter range check + if(mirror_page < 4) return; + if(mirror_page > last_user_page_index - 1) return; + if(mirror_page == last_user_page_index - 1 && mirror_byte > 2) return; + + if(mirror_conf == MfUltralightMirrorUidCounter) + string_cat_str(str, uid_printed ? "x" : " "); + + string_cat_printf(str, "%06X", emulator->data.counter[2]); + } + } +} + +static void mf_ul_increment_single_counter(MfUltralightEmulator* emulator) { + if(!emulator->read_counter_incremented && emulator->config_cache.access.nfc_cnt_en) { + if(emulator->data.counter[2] < 0xFFFFFF) { + ++emulator->data.counter[2]; + emulator->data_changed = true; + } + emulator->read_counter_incremented = true; + } +} + +static void mf_ul_emulate_write( + MfUltralightEmulator* emulator, + int16_t tag_addr, + int16_t write_page, + uint8_t* page_buff) { + // Assumption: all access checks have been completed + + if(tag_addr == 2) { + // Handle static locks + uint16_t orig_static_locks = emulator->data.data[write_page * 4 + 2] | + (emulator->data.data[write_page * 4 + 3] << 8); + uint16_t new_static_locks = page_buff[2] | (page_buff[3] << 8); + if(orig_static_locks & 1) new_static_locks &= ~0x08; + if(orig_static_locks & 2) new_static_locks &= ~0xF0; + if(orig_static_locks & 4) new_static_locks &= 0xFF; + new_static_locks |= orig_static_locks; + page_buff[0] = emulator->data.data[write_page * 4]; + page_buff[1] = emulator->data.data[write_page * 4 + 1]; + page_buff[2] = new_static_locks & 0xff; + page_buff[3] = new_static_locks >> 8; + } else if(tag_addr == 3) { + // Handle OTP/capability container + *(uint32_t*)page_buff |= *(uint32_t*)&emulator->data.data[write_page * 4]; + } else if(tag_addr == mf_ul_get_dynamic_lock_page_addr(&emulator->data)) { + // Handle dynamic locks + uint16_t orig_locks = emulator->data.data[write_page * 4] | + (emulator->data.data[write_page * 4 + 1] << 8); + uint8_t orig_block_locks = emulator->data.data[write_page * 4 + 2]; + uint16_t new_locks = page_buff[0] | (page_buff[1] << 8); + uint8_t new_block_locks = page_buff[2]; + + int block_lock_count; + switch(emulator->data.type) { + case MfUltralightTypeUL21: + block_lock_count = 5; + break; + case MfUltralightTypeNTAG213: + block_lock_count = 6; + break; + case MfUltralightTypeNTAG215: + block_lock_count = 4; + break; + case MfUltralightTypeNTAG216: + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2CPlus1K: + block_lock_count = 7; + break; + case MfUltralightTypeNTAGI2C2K: + case MfUltralightTypeNTAGI2CPlus2K: + block_lock_count = 8; + break; + default: + furi_assert(false); + block_lock_count = 0; + break; + } + + for(int i = 0; i < block_lock_count; ++i) { + if(orig_block_locks & (1 << i)) new_locks &= ~(3 << (2 * i)); + } + + new_locks |= orig_locks; + new_block_locks |= orig_block_locks; + + page_buff[0] = new_locks & 0xff; + page_buff[1] = new_locks >> 8; + page_buff[2] = new_block_locks; + if(emulator->data.type >= MfUltralightTypeUL21 && + emulator->data.type <= MfUltralightTypeNTAG216) + page_buff[3] = MF_UL_TEARING_FLAG_DEFAULT; + else + page_buff[3] = 0; + } + + memcpy(&emulator->data.data[write_page * 4], page_buff, 4); + emulator->data_changed = true; +} + +void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) { + emulator->curr_sector = 0; + emulator->ntag_i2c_plus_sector3_lockout = false; + emulator->auth_success = false; + if(is_power_cycle) { + if(emulator->config != NULL) emulator->config_cache = *emulator->config; + + if(emulator->supported_features & MfUltralightSupportSingleCounter) { + emulator->read_counter_incremented = false; + } + } else { + if(emulator->config != NULL) { + // ACCESS (less CFGLCK) and AUTH0 are updated when reactivated + // MIRROR_CONF is not; don't know about STRG_MOD_EN, but we're not using that anyway + emulator->config_cache.access.value = (emulator->config->access.value & 0xBF) | + (emulator->config_cache.access.value & 0x40); + emulator->config_cache.auth0 = emulator->config->auth0; + } + } +} + void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) { FURI_LOG_D(TAG, "Prepare emulation"); emulator->data = *data; - emulator->auth_data = NULL; + emulator->supported_features = mf_ul_get_features(data->type); + emulator->config = mf_ultralight_get_config_pages(&emulator->data); + emulator->page_num = emulator->data.data_size / 4; emulator->data_changed = false; emulator->comp_write_cmd_started = false; emulator->sector_select_cmd_started = false; - emulator->ntag_i2c_plus_sector3_lockout = false; - if(data->type == MfUltralightTypeUnknown) { - emulator->support_fast_read = false; - } else if(data->type == MfUltralightTypeUL11) { - emulator->support_fast_read = true; - } else if(data->type == MfUltralightTypeUL21) { - emulator->support_fast_read = true; - } else if(data->type == MfUltralightTypeNTAG213) { - emulator->support_fast_read = true; - } else if(data->type == MfUltralightTypeNTAG215) { - emulator->support_fast_read = true; - } else if(data->type == MfUltralightTypeNTAG216) { - emulator->support_fast_read = true; - } else if(data->type >= MfUltralightTypeNTAGI2C1K) { - emulator->support_fast_read = true; - } - - if(data->type >= MfUltralightTypeNTAG213 && data->type < MfUltralightTypeNTAGI2C1K) { - uint16_t pwd_page = (data->data_size / 4) - 2; - emulator->auth_data = (MfUltralightAuth*)&data->data[pwd_page * 4]; - } else if(data->type >= MfUltralightTypeNTAGI2CPlus1K) { - emulator->auth_data = (MfUltralightAuth*)&data->data[229 * 4]; - } + mf_ul_reset_emulation(emulator, true); } bool mf_ul_prepare_emulation_response( @@ -773,13 +1057,12 @@ bool mf_ul_prepare_emulation_response( void* context) { furi_assert(context); MfUltralightEmulator* emulator = context; - uint8_t cmd = buff_rx[0]; - uint16_t page_num = emulator->data.data_size / 4; uint16_t tx_bytes = 0; uint16_t tx_bits = 0; bool command_parsed = false; bool send_ack = false; bool respond_nothing = false; + bool reset_idle = false; #ifdef FURI_DEBUG string_t debug_buf; @@ -795,118 +1078,138 @@ bool mf_ul_prepare_emulation_response( // Check composite commands if(emulator->comp_write_cmd_started) { // Compatibility write is the only one composit command - if(buff_rx_len == 16) { - memcpy(&emulator->data.data[emulator->comp_write_page_addr * 4], buff_rx, 4); - emulator->data_changed = true; - // Send ACK message - buff_tx[0] = 0x0A; - tx_bits = 4; - *data_type = FURI_HAL_NFC_TXRX_RAW; + if(buff_rx_len == 16 * 8) { + mf_ul_emulate_write( + emulator, emulator->comp_write_page_addr, emulator->comp_write_page_addr, buff_rx); + send_ack = true; command_parsed = true; } emulator->comp_write_cmd_started = false; } else if(emulator->sector_select_cmd_started) { - if(buff_rx[0] <= 0xFE) { - emulator->curr_sector = buff_rx[0] > 3 ? 0 : buff_rx[0]; - emulator->ntag_i2c_plus_sector3_lockout = false; - command_parsed = true; - respond_nothing = true; - FURI_LOG_D(TAG, "Changing sector to %d", emulator->curr_sector); - } - emulator->sector_select_cmd_started = false; - } else if(cmd == MF_UL_GET_VERSION_CMD) { - if(emulator->data.type != MfUltralightTypeUnknown) { - tx_bytes = sizeof(emulator->data.version); - memcpy(buff_tx, &emulator->data.version, tx_bytes); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; - } - } else if(cmd == MF_UL_READ_CMD) { - int16_t start_page = buff_rx[1]; - tx_bytes = 16; - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - if(start_page < page_num) { - if(start_page + 4 > page_num) { - // Handle roll-over mechanism - uint8_t end_pages_num = page_num - start_page; - memcpy(buff_tx, &emulator->data.data[start_page * 4], end_pages_num * 4); - memcpy( - &buff_tx[end_pages_num * 4], emulator->data.data, (4 - end_pages_num) * 4); - } else { - memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes); - } - mf_ul_protect_auth_data_on_read_command( - buff_tx, start_page, (start_page + 4), emulator); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + if(buff_rx_len == 4 * 8) { + if(buff_rx[0] <= 0xFE) { + emulator->curr_sector = buff_rx[0] > 3 ? 0 : buff_rx[0]; + emulator->ntag_i2c_plus_sector3_lockout = false; command_parsed = true; + respond_nothing = true; + FURI_LOG_D(TAG, "Changing sector to %d", emulator->curr_sector); } - } else { - uint16_t valid_pages; - start_page = mf_ultralight_ntag_i2c_addr_tag_to_lin( - &emulator->data, start_page, emulator->curr_sector, &valid_pages); - if(start_page != -1) { - if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K || - mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], false)) { - if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K && - emulator->curr_sector == 3 && valid_pages == 1) { - // Rewind back a sector to match behavior on a real tag - --start_page; - ++valid_pages; - } - - uint16_t copy_count = (valid_pages > 4 ? 4 : valid_pages) * 4; - FURI_LOG_D( - TAG, - "NTAG I2C Emu: page valid, %02x:%02x -> %d, %d", - emulator->curr_sector, - buff_rx[1], - start_page, - valid_pages); - memcpy(buff_tx, &emulator->data.data[start_page * 4], copy_count); - // For NTAG I2C, there's no roll-over; remainder is filled by null bytes - if(copy_count < tx_bytes) - memset(&buff_tx[copy_count], 0, tx_bytes - copy_count); - // Special case: NTAG I2C Plus sector 0 page 233 read crosses into page 236 - if(start_page == 233) - memcpy(&buff_tx[12], &emulator->data.data[(start_page + 1) * 4], 4); - mf_ul_protect_auth_data_on_read_command_i2c( - buff_tx, start_page, start_page + copy_count / 4 - 1, emulator); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; - } - } else { - FURI_LOG_D( - TAG, - "NTAG I2C Emu: page invalid, %02x:%02x", - emulator->curr_sector, - buff_rx[1]); - if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K && - emulator->curr_sector == 3 && !emulator->ntag_i2c_plus_sector3_lockout) { - // NTAG I2C Plus has a weird behavior where if you read sector 3 - // at an invalid address, it responds with zeroes then locks - // the read out, while if you read the mirrored session registers, - // it returns both session registers on either pages - memset(buff_tx, 0, tx_bytes); + } + emulator->sector_select_cmd_started = false; + } else if(buff_rx_len >= 8) { + uint8_t cmd = buff_rx[0]; + if(cmd == MF_UL_GET_VERSION_CMD) { + if(emulator->data.type != MfUltralightTypeUnknown) { + if(buff_rx_len == 1 * 8) { + tx_bytes = sizeof(emulator->data.version); + memcpy(buff_tx, &emulator->data.version, tx_bytes); *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; - emulator->ntag_i2c_plus_sector3_lockout = true; } } - } - if(!command_parsed) tx_bytes = 0; - } else if(cmd == MF_UL_FAST_READ_CMD) { - if(emulator->support_fast_read) { - int16_t start_page = buff_rx[1]; - uint8_t end_page = buff_rx[2]; - if(start_page <= end_page) { - tx_bytes = ((end_page + 1) - start_page) * 4; + } else if(cmd == MF_UL_READ_CMD) { + if(buff_rx_len == (1 + 1) * 8) { + int16_t start_page = buff_rx[1]; + tx_bytes = 16; if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - if((start_page < page_num) && (end_page < page_num)) { - memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes); - mf_ul_protect_auth_data_on_read_command( - buff_tx, start_page, end_page, emulator); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; + if(start_page < emulator->page_num) { + do { + uint8_t copied_pages = 0; + uint8_t src_page = start_page; + uint8_t last_page_plus_one = start_page + 4; + uint8_t pwd_page = emulator->page_num - 2; + string_t ascii_mirror; + size_t ascii_mirror_len = 0; + const char* ascii_mirror_cptr = NULL; + uint8_t ascii_mirror_curr_page = 0; + uint8_t ascii_mirror_curr_byte = 0; + if(last_page_plus_one > emulator->page_num) + last_page_plus_one = emulator->page_num; + if(emulator->supported_features & MfUltralightSupportAuth) { + if(!mf_ul_check_auth(emulator, start_page, false)) break; + if(!emulator->auth_success && emulator->config_cache.access.prot && + emulator->config_cache.auth0 < last_page_plus_one) + last_page_plus_one = emulator->config_cache.auth0; + } + if(emulator->supported_features & MfUltralightSupportSingleCounter) + mf_ul_increment_single_counter(emulator); + if(emulator->supported_features & MfUltralightSupportAsciiMirror && + emulator->config_cache.mirror.mirror_conf != + MfUltralightMirrorNone) { + ascii_mirror_curr_byte = emulator->config->mirror.mirror_byte; + ascii_mirror_curr_page = emulator->config->mirror_page; + // Try to avoid wasting time making mirror if we won't copy it + // Conservatively check with UID+counter mirror size + if(last_page_plus_one > ascii_mirror_curr_page && + start_page + 3 >= ascii_mirror_curr_page && + start_page <= ascii_mirror_curr_page + 6) { + string_init(ascii_mirror); + mf_ul_make_ascii_mirror(emulator, ascii_mirror); + ascii_mirror_len = string_length_u(ascii_mirror); + ascii_mirror_cptr = string_get_cstr(ascii_mirror); + // Move pointer to where it should be to start copying + if(ascii_mirror_len > 0 && + ascii_mirror_curr_page < start_page && + ascii_mirror_curr_byte != 0) { + uint8_t diff = 4 - ascii_mirror_curr_byte; + ascii_mirror_len -= diff; + ascii_mirror_cptr += diff; + ascii_mirror_curr_byte = 0; + ++ascii_mirror_curr_page; + } + while(ascii_mirror_len > 0 && + ascii_mirror_curr_page < start_page) { + uint8_t diff = ascii_mirror_len > 4 ? 4 : ascii_mirror_len; + ascii_mirror_len -= diff; + ascii_mirror_cptr += diff; + ++ascii_mirror_curr_page; + } + } + } + + uint8_t* dest_ptr = buff_tx; + while(copied_pages < 4) { + // Copy page + memcpy(dest_ptr, &emulator->data.data[src_page * 4], 4); + + // Note: don't have to worry about roll-over with ASCII mirror because + // lowest valid page for it is 4, while roll-over will at best read + // pages 0-2 + if(ascii_mirror_len > 0 && src_page == ascii_mirror_curr_page) { + // Copy ASCII mirror + size_t copy_len = 4 - ascii_mirror_curr_byte; + if(copy_len > ascii_mirror_len) copy_len = ascii_mirror_len; + for(size_t i = 0; i < copy_len; ++i) { + if(*ascii_mirror_cptr != ' ') + dest_ptr[ascii_mirror_curr_byte] = + (uint8_t)*ascii_mirror_cptr; + ++ascii_mirror_curr_byte; + ++ascii_mirror_cptr; + } + ascii_mirror_len -= copy_len; + // Don't care if this is inaccurate after ascii_mirror_len = 0 + ascii_mirror_curr_byte = 0; + ++ascii_mirror_curr_page; + } + + if(emulator->supported_features & MfUltralightSupportAuth) { + if(src_page == pwd_page || src_page == pwd_page + 1) { + // Blank out PWD and PACK pages + memset(dest_ptr, 0, 4); + } + } + + dest_ptr += 4; + ++copied_pages; + ++src_page; + if(src_page >= last_page_plus_one) src_page = 0; + } + if(ascii_mirror_cptr != NULL) { + string_clear(ascii_mirror); + } + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } while(false); } } else { uint16_t valid_pages; @@ -915,151 +1218,401 @@ bool mf_ul_prepare_emulation_response( if(start_page != -1) { if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K || mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], false)) { + if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K && + emulator->curr_sector == 3 && valid_pages == 1) { + // Rewind back a sector to match behavior on a real tag + --start_page; + ++valid_pages; + } + uint16_t copy_count = (valid_pages > 4 ? 4 : valid_pages) * 4; + FURI_LOG_D( + TAG, + "NTAG I2C Emu: page valid, %02x:%02x -> %d, %d", + emulator->curr_sector, + buff_rx[1], + start_page, + valid_pages); memcpy(buff_tx, &emulator->data.data[start_page * 4], copy_count); + // For NTAG I2C, there's no roll-over; remainder is filled by null bytes if(copy_count < tx_bytes) memset(&buff_tx[copy_count], 0, tx_bytes - copy_count); - mf_ul_ntag_i2c_fill_cross_area_read( - buff_tx, buff_rx[1], buff_rx[2], emulator); + // Special case: NTAG I2C Plus sector 0 page 233 read crosses into page 236 + if(start_page == 233) + memcpy( + &buff_tx[12], &emulator->data.data[(start_page + 1) * 4], 4); mf_ul_protect_auth_data_on_read_command_i2c( buff_tx, start_page, start_page + copy_count / 4 - 1, emulator); *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; } + } else { + FURI_LOG_D( + TAG, + "NTAG I2C Emu: page invalid, %02x:%02x", + emulator->curr_sector, + buff_rx[1]); + if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K && + emulator->curr_sector == 3 && + !emulator->ntag_i2c_plus_sector3_lockout) { + // NTAG I2C Plus has a weird behavior where if you read sector 3 + // at an invalid address, it responds with zeroes then locks + // the read out, while if you read the mirrored session registers, + // it returns both session registers on either pages + memset(buff_tx, 0, tx_bytes); + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + emulator->ntag_i2c_plus_sector3_lockout = true; + } } } if(!command_parsed) tx_bytes = 0; } - } - } else if(cmd == MF_UL_WRITE) { - int16_t write_page = buff_rx[1]; - if(write_page > 1) { - uint16_t valid_pages; - write_page = mf_ultralight_ntag_i2c_addr_tag_to_lin( - &emulator->data, write_page, emulator->curr_sector, &valid_pages); - if(write_page != -1 && - (emulator->data.type >= MfUltralightTypeNTAGI2C1K || (write_page < page_num - 2))) { - if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K || - mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], true)) { - memcpy(&emulator->data.data[write_page * 4], &buff_rx[2], 4); - emulator->data_changed = true; + } else if(cmd == MF_UL_FAST_READ_CMD) { + if(emulator->supported_features & MfUltralightSupportFastRead) { + if(buff_rx_len == (1 + 2) * 8) { + int16_t start_page = buff_rx[1]; + uint8_t end_page = buff_rx[2]; + if(start_page <= end_page) { + tx_bytes = ((end_page + 1) - start_page) * 4; + if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { + if((start_page < emulator->page_num) && + (end_page < emulator->page_num)) { + do { + if(emulator->supported_features & MfUltralightSupportAuth) { + // NAK if not authenticated and requested pages cross over AUTH0 + if(!emulator->auth_success && + emulator->config_cache.access.prot && + (start_page >= emulator->config_cache.auth0 || + end_page >= emulator->config_cache.auth0)) + break; + } + if(emulator->supported_features & + MfUltralightSupportSingleCounter) + mf_ul_increment_single_counter(emulator); + + // Copy requested pages + memcpy( + buff_tx, &emulator->data.data[start_page * 4], tx_bytes); + + if(emulator->supported_features & + MfUltralightSupportAsciiMirror && + emulator->config_cache.mirror.mirror_conf != + MfUltralightMirrorNone) { + // Copy ASCII mirror + // Less stringent check here, because expecting FAST_READ to + // only be issued once rather than repeatedly + string_t ascii_mirror; + string_init(ascii_mirror); + mf_ul_make_ascii_mirror(emulator, ascii_mirror); + size_t ascii_mirror_len = string_length_u(ascii_mirror); + const char* ascii_mirror_cptr = + string_get_cstr(ascii_mirror); + int16_t mirror_start_offset = + (emulator->config->mirror_page - start_page) * 4 + + emulator->config->mirror.mirror_byte; + if(mirror_start_offset < 0) { + if(mirror_start_offset < -(int16_t)ascii_mirror_len) { + // Past ASCII mirror, don't copy + ascii_mirror_len = 0; + } else { + ascii_mirror_cptr += -mirror_start_offset; + ascii_mirror_len -= -mirror_start_offset; + mirror_start_offset = 0; + } + } + if(ascii_mirror_len > 0) { + int16_t mirror_end_offset = + mirror_start_offset + ascii_mirror_len; + if(mirror_end_offset > (end_page + 1) * 4) { + mirror_end_offset = (end_page + 1) * 4; + ascii_mirror_len = + mirror_end_offset - mirror_start_offset; + } + for(size_t i = 0; i < ascii_mirror_len; ++i) { + if(*ascii_mirror_cptr != ' ') + buff_tx[mirror_start_offset] = + (uint8_t)*ascii_mirror_cptr; + ++mirror_start_offset; + ++ascii_mirror_cptr; + } + } + string_clear(ascii_mirror); + } + + if(emulator->supported_features & MfUltralightSupportAuth) { + // Clear PWD and PACK pages + uint8_t pwd_page = emulator->page_num - 2; + int16_t pwd_page_offset = pwd_page - start_page; + // PWD page + if(pwd_page_offset >= 0 && pwd_page <= end_page) { + memset(&buff_tx[pwd_page_offset * 4], 0, 4); + // PACK page + if(pwd_page + 1 <= end_page) + memset(&buff_tx[(pwd_page_offset + 1) * 4], 0, 4); + } + } + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } while(false); + } + } else { + uint16_t valid_pages; + start_page = mf_ultralight_ntag_i2c_addr_tag_to_lin( + &emulator->data, start_page, emulator->curr_sector, &valid_pages); + if(start_page != -1) { + if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K || + mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], false)) { + uint16_t copy_count = tx_bytes; + if(copy_count > valid_pages * 4) copy_count = valid_pages * 4; + memcpy( + buff_tx, &emulator->data.data[start_page * 4], copy_count); + if(copy_count < tx_bytes) + memset(&buff_tx[copy_count], 0, tx_bytes - copy_count); + mf_ul_ntag_i2c_fill_cross_area_read( + buff_tx, buff_rx[1], buff_rx[2], emulator); + mf_ul_protect_auth_data_on_read_command_i2c( + buff_tx, + start_page, + start_page + copy_count / 4 - 1, + emulator); + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } + } + } + if(!command_parsed) tx_bytes = 0; + } + } + } + } else if(cmd == MF_UL_WRITE) { + if(buff_rx_len == (1 + 5) * 8) { + do { + uint8_t orig_write_page = buff_rx[1]; + int16_t write_page = orig_write_page; + uint16_t valid_pages; // unused + write_page = mf_ultralight_ntag_i2c_addr_tag_to_lin( + &emulator->data, write_page, emulator->curr_sector, &valid_pages); + if(write_page == -1) // NTAG I2C range check + break; + else if(write_page < 2 || write_page >= emulator->page_num) // Other MFUL/NTAG range check + break; + + if(emulator->supported_features & MfUltralightSupportAuth) { + if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K) { + if(!mf_ul_ntag_i2c_plus_check_auth(emulator, orig_write_page, true)) + break; + } else { + if(!mf_ul_check_auth(emulator, orig_write_page, true)) break; + } + } + int16_t tag_addr = mf_ultralight_page_addr_to_tag_addr( + emulator->curr_sector, orig_write_page); + if(!mf_ul_check_lock(emulator, tag_addr)) break; + mf_ul_emulate_write(emulator, tag_addr, write_page, &buff_rx[2]); send_ack = true; command_parsed = true; + } while(false); + } + } else if(cmd == MF_UL_FAST_WRITE) { + if(emulator->supported_features & MfUltralightSupportFastWrite) { + if(buff_rx_len == (1 + 66) * 8) { + if(buff_rx[1] == 0xF0 && buff_rx[2] == 0xFF) { + // TODO: update when SRAM emulation implemented + send_ack = true; + command_parsed = true; + } } } - } - } else if(cmd == MF_UL_FAST_WRITE) { - if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K) { - if(buff_rx[1] == 0xF0 && buff_rx[2] == 0xFF) { - // TODO: update when SRAM emulation implemented - send_ack = true; - command_parsed = true; + } else if(cmd == MF_UL_COMP_WRITE) { + if(emulator->supported_features & MfUltralightSupportCompatWrite) { + if(buff_rx_len == (1 + 1) * 8) { + uint8_t write_page = buff_rx[1]; + do { + if(write_page < 2 || write_page >= emulator->page_num) break; + if(emulator->supported_features & MfUltralightSupportAuth && + !mf_ul_check_auth(emulator, write_page, true)) + break; + // Note we don't convert to tag addr here because there's only one sector + if(!mf_ul_check_lock(emulator, write_page)) break; + + emulator->comp_write_cmd_started = true; + emulator->comp_write_page_addr = write_page; + send_ack = true; + command_parsed = true; + } while(false); + } } - } - } else if(cmd == MF_UL_COMP_WRITE) { - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - uint8_t write_page = buff_rx[1]; - if((write_page > 1) && (write_page < page_num - 2)) { - emulator->comp_write_cmd_started = true; - emulator->comp_write_page_addr = write_page; - // ACK - buff_tx[0] = 0x0A; - tx_bits = 4; - *data_type = FURI_HAL_NFC_TXRX_RAW; - command_parsed = true; + } else if(cmd == MF_UL_READ_CNT) { + if(emulator->supported_features & MfUltralightSupportReadCounter) { + if(buff_rx_len == (1 + 1) * 8) { + do { + uint8_t cnt_num = buff_rx[1]; + + // NTAG21x checks + if(emulator->supported_features & MfUltralightSupportSingleCounter) { + if(cnt_num != 2) break; // Only counter 2 is available + if(!emulator->config_cache.access.nfc_cnt_en) + break; // NAK if counter not enabled + if(emulator->config_cache.access.nfc_cnt_pwd_prot && + !emulator->auth_success) + break; + } + + if(cnt_num < 3) { + buff_tx[0] = emulator->data.counter[cnt_num] & 0xFF; + buff_tx[1] = (emulator->data.counter[cnt_num] >> 8) & 0xFF; + buff_tx[2] = (emulator->data.counter[cnt_num] >> 16) & 0xFF; + tx_bytes = 3; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } + } while(false); + } } - } - } else if(cmd == MF_UL_READ_CNT) { - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - uint8_t cnt_num = buff_rx[1]; - if(cnt_num < 3) { - buff_tx[0] = emulator->data.counter[cnt_num] >> 16; - buff_tx[1] = emulator->data.counter[cnt_num] >> 8; - buff_tx[2] = emulator->data.counter[cnt_num]; - tx_bytes = 3; - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; + } else if(cmd == MF_UL_INC_CNT) { + if(emulator->supported_features & MfUltralightSupportIncrCounter) { + if(buff_rx_len == (1 + 5) * 8) { + uint8_t cnt_num = buff_rx[1]; + uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16)); + // TODO: can you increment by 0 when counter is at 0xffffff? + if((cnt_num < 3) && (emulator->data.counter[cnt_num] != 0x00FFFFFF) && + (emulator->data.counter[cnt_num] + inc <= 0x00FFFFFF)) { + emulator->data.counter[cnt_num] += inc; + // We're RAM-backed, so tearing never happens + emulator->data.tearing[cnt_num] = MF_UL_TEARING_FLAG_DEFAULT; + emulator->data_changed = true; + send_ack = true; + command_parsed = true; + } + } } - } - } else if(cmd == MF_UL_INC_CNT) { - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - uint8_t cnt_num = buff_rx[1]; - uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16)); - if((cnt_num < 3) && (emulator->data.counter[cnt_num] + inc < 0x00FFFFFF)) { - emulator->data.counter[cnt_num] += inc; - emulator->data_changed = true; - // ACK - buff_tx[0] = 0x0A; - tx_bits = 4; - *data_type = FURI_HAL_NFC_TXRX_RAW; - command_parsed = true; + } else if(cmd == MF_UL_AUTH) { + if(emulator->supported_features & MfUltralightSupportAuth) { + if(buff_rx_len == (1 + 4) * 8) { + uint16_t scaled_authlim = mf_ultralight_calc_auth_count(&emulator->data); + if(scaled_authlim != 0 && emulator->data.curr_authlim >= scaled_authlim) { + if(emulator->data.curr_authlim != UINT16_MAX) { + // Handle case where AUTHLIM has been lowered or changed from 0 + emulator->data.curr_authlim = UINT16_MAX; + emulator->data_changed = true; + } + // AUTHLIM reached, always fail + buff_tx[0] = MF_UL_NAK_AUTHLIM_REACHED; + tx_bits = 4; + *data_type = FURI_HAL_NFC_TX_RAW_RX_DEFAULT; + mf_ul_reset_emulation(emulator, false); + command_parsed = true; + } else { + if(memcmp(&buff_rx[1], emulator->config->auth_data.pwd.raw, 4) == 0) { + // Correct password + buff_tx[0] = emulator->config->auth_data.pack.raw[0]; + buff_tx[1] = emulator->config->auth_data.pack.raw[1]; + tx_bytes = 2; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + emulator->auth_success = true; + command_parsed = true; + if(emulator->data.curr_authlim != 0) { + // Reset current AUTHLIM + emulator->data.curr_authlim = 0; + emulator->data_changed = true; + } + } else if(!emulator->config->auth_data.pwd.value) { + // Unknown password, pretend to be an Amiibo + buff_tx[0] = 0x80; + buff_tx[1] = 0x80; + tx_bytes = 2; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + emulator->auth_success = true; + command_parsed = true; + } else { + // Wrong password, increase negative verification count + if(emulator->data.curr_authlim < UINT16_MAX) { + ++emulator->data.curr_authlim; + emulator->data_changed = true; + } + if(scaled_authlim != 0 && + emulator->data.curr_authlim >= scaled_authlim) { + emulator->data.curr_authlim = UINT16_MAX; + buff_tx[0] = MF_UL_NAK_AUTHLIM_REACHED; + tx_bits = 4; + *data_type = FURI_HAL_NFC_TX_RAW_RX_DEFAULT; + mf_ul_reset_emulation(emulator, false); + command_parsed = true; + } else { + // Should delay here to slow brute forcing + } + } + } + } } - } - } else if(cmd == MF_UL_AUTH) { - if(emulator->data.type >= MfUltralightTypeNTAG213 && - emulator->data.type != MfUltralightTypeNTAGI2C1K && - emulator->data.type != MfUltralightTypeNTAGI2C2K) { - if(memcmp(&buff_rx[1], emulator->auth_data->pwd, 4) == 0) { - buff_tx[0] = emulator->auth_data->pack.raw[0]; - buff_tx[1] = emulator->auth_data->pack.raw[1]; - tx_bytes = 2; - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - emulator->auth_success = true; - command_parsed = true; - } else if(!emulator->auth_data->pack.value) { - buff_tx[0] = 0x80; - buff_tx[1] = 0x80; - tx_bytes = 2; - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; + } else if(cmd == MF_UL_READ_SIG) { + if(emulator->supported_features & MfUltralightSupportSignature) { + // Check 2nd byte = 0x00 - RFU + if(buff_rx_len == (1 + 1) * 8 && buff_rx[1] == 0x00) { + tx_bytes = sizeof(emulator->data.signature); + memcpy(buff_tx, emulator->data.signature, tx_bytes); + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } } - } - } else if(cmd == MF_UL_READ_SIG) { - if(emulator->data.type != MfUltralightTypeNTAGI2C1K && - emulator->data.type != MfUltralightTypeNTAGI2C2K) { - // Check 2nd byte = 0x00 - RFU - if(buff_rx[1] == 0x00) { - tx_bytes = sizeof(emulator->data.signature); - memcpy(buff_tx, emulator->data.signature, tx_bytes); - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; + } else if(cmd == MF_UL_CHECK_TEARING) { + if(emulator->supported_features & MfUltralightSupportTearingFlags) { + if(buff_rx_len == (1 + 1) * 8) { + uint8_t cnt_num = buff_rx[1]; + if(cnt_num < 3) { + buff_tx[0] = emulator->data.tearing[cnt_num]; + tx_bytes = 1; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } + } } - } - } else if(cmd == MF_UL_CHECK_TEARING) { - if(emulator->data.type < MfUltralightTypeNTAGI2C1K) { - uint8_t cnt_num = buff_rx[1]; - if(cnt_num < 3) { - buff_tx[0] = emulator->data.tearing[cnt_num]; - tx_bytes = 1; - *data_type = FURI_HAL_NFC_TXRX_DEFAULT; - command_parsed = true; + } else if(cmd == MF_UL_HALT_START) { + reset_idle = true; + FURI_LOG_D(TAG, "Received HLTA"); + } else if(cmd == MF_UL_SECTOR_SELECT) { + if(emulator->supported_features & MfUltralightSupportSectorSelect) { + if(buff_rx_len == (1 + 1) * 8 && buff_rx[1] == 0xFF) { + // Send ACK + emulator->sector_select_cmd_started = true; + send_ack = true; + command_parsed = true; + } } + } else if(cmd == MF_UL_READ_VCSL) { + if(emulator->supported_features & MfUltralightSupportVcsl) { + if(buff_rx_len == (1 + 20) * 8) { + buff_tx[0] = emulator->config_cache.vctid; + tx_bytes = 1; + *data_type = FURI_HAL_NFC_TXRX_DEFAULT; + command_parsed = true; + } + } + } else { + reset_idle = true; + FURI_LOG_D(TAG, "Received invalid command"); } - } else if(cmd == MF_UL_HALT_START) { + } else { + reset_idle = true; + FURI_LOG_D(TAG, "Received invalid buffer less than 8 bits in length"); + } + + if(reset_idle) { + mf_ul_reset_emulation(emulator, false); tx_bits = 0; - emulator->curr_sector = 0; - emulator->ntag_i2c_plus_sector3_lockout = false; - emulator->auth_success = false; command_parsed = true; - FURI_LOG_D(TAG, "Received HLTA"); - } else if(cmd == MF_UL_SECTOR_SELECT) { - if(emulator->data.type >= MfUltralightTypeNTAGI2C1K) { - if(buff_rx[1] == 0xFF) { - // Send ACK - emulator->sector_select_cmd_started = true; - send_ack = true; - command_parsed = true; - } - } } if(!command_parsed) { // Send NACK - buff_tx[0] = 0x00; + buff_tx[0] = MF_UL_NAK_INVALID_ARGUMENT; tx_bits = 4; *data_type = FURI_HAL_NFC_TX_RAW_RX_DEFAULT; + // Every NAK should cause reset to IDLE + mf_ul_reset_emulation(emulator, false); } else if(send_ack) { - buff_tx[0] = 0x0A; + buff_tx[0] = MF_UL_ACK; tx_bits = 4; *data_type = FURI_HAL_NFC_TX_RAW_RX_DEFAULT; } diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc_protocols/mifare_ultralight.h index 76dc2edbd8d4..36b81fdf15f4 100644 --- a/lib/nfc_protocols/mifare_ultralight.h +++ b/lib/nfc_protocols/mifare_ultralight.h @@ -22,6 +22,10 @@ #define MF_UL_READ_VCSL (0x4B) #define MF_UL_SECTOR_SELECT (0xC2) +#define MF_UL_ACK (0xa) +#define MF_UL_NAK_INVALID_ARGUMENT (0x0) +#define MF_UL_NAK_AUTHLIM_REACHED (0x4) + typedef enum { MfUltralightTypeUnknown, MfUltralightTypeUL11, @@ -38,6 +42,31 @@ typedef enum { MfUltralightTypeNum, } MfUltralightType; +typedef enum { + MfUltralightSupportNone = 0, + MfUltralightSupportFastRead = 1 << 0, + MfUltralightSupportTearingFlags = 1 << 1, + MfUltralightSupportReadCounter = 1 << 2, + MfUltralightSupportIncrCounter = 1 << 3, + MfUltralightSupportSignature = 1 << 4, + MfUltralightSupportFastWrite = 1 << 5, + MfUltralightSupportCompatWrite = 1 << 6, + MfUltralightSupportAuth = 1 << 7, + MfUltralightSupportVcsl = 1 << 8, + MfUltralightSupportSectorSelect = 1 << 9, + // NTAG21x only has counter 2 + MfUltralightSupportSingleCounter = 1 << 10, + // ASCII mirror is not a command, but handy to have as a flag + MfUltralightSupportAsciiMirror = 1 << 11, +} MfUltralightFeatures; + +typedef enum { + MfUltralightMirrorNone, + MfUltralightMirrorUid, + MfUltralightMirrorCounter, + MfUltralightMirrorUidCounter, +} MfUltralightMirrorConf; + typedef struct { uint8_t header; uint8_t vendor_id; @@ -65,38 +94,76 @@ typedef struct { uint8_t signature[32]; uint32_t counter[3]; uint8_t tearing[3]; + uint16_t curr_authlim; uint16_t data_size; uint8_t data[MF_UL_MAX_DUMP_SIZE]; } MfUltralightData; -typedef struct { - uint8_t pwd[4]; +typedef struct __attribute__((packed)) { + union { + uint8_t raw[4]; + uint32_t value; + } pwd; union { uint8_t raw[2]; uint16_t value; } pack; } MfUltralightAuth; +// Common configuration pages for MFUL EV1, NTAG21x, and NTAG I2C Plus +typedef struct __attribute__((packed)) { + union { + uint8_t value; + struct { + uint8_t rfui1 : 2; + bool strg_mod_en : 1; + bool rfui2 : 1; + uint8_t mirror_byte : 2; + MfUltralightMirrorConf mirror_conf : 2; + }; + } mirror; + uint8_t rfui1; + uint8_t mirror_page; + uint8_t auth0; + union { + uint8_t value; + struct { + uint8_t authlim : 3; + bool nfc_cnt_pwd_prot : 1; + bool nfc_cnt_en : 1; + bool nfc_dis_sec1 : 1; // NTAG I2C Plus only + bool cfglck : 1; + bool prot : 1; + }; + } access; + uint8_t vctid; + uint8_t rfui2[2]; + MfUltralightAuth auth_data; + uint8_t rfui3[2]; +} MfUltralightConfigPages; + typedef struct { uint16_t pages_to_read; int16_t pages_read; - bool support_fast_read; - bool support_tearing_flags; - bool support_counters; - bool support_signature; + MfUltralightFeatures supported_features; } MfUltralightReader; typedef struct { MfUltralightData data; - bool support_fast_read; + MfUltralightConfigPages* config; + // Most config values don't apply until power cycle, so cache config pages + // for correct behavior + MfUltralightConfigPages config_cache; + MfUltralightFeatures supported_features; + uint16_t page_num; bool data_changed; bool comp_write_cmd_started; uint8_t comp_write_page_addr; - MfUltralightAuth* auth_data; bool auth_success; uint8_t curr_sector; bool sector_select_cmd_started; bool ntag_i2c_plus_sector3_lockout; + bool read_counter_incremented; } MfUltralightEmulator; bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); @@ -127,6 +194,8 @@ bool mf_ul_read_card( MfUltralightReader* reader, MfUltralightData* data); +void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle); + void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data); bool mf_ul_prepare_emulation_response( From fc96fd49d170e59c95c2dd091b23169b5cf0bebf Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 21 Jun 2022 20:52:22 +0400 Subject: [PATCH 166/184] Build: removed infrared_monitor/application.fam; fixed git branch id; added update complete splashscreen to packages; UI: removed radio stack branch --- SConstruct | 32 +++++++++++-------- applications/ReadMe.md | 1 - applications/infrared_monitor/application.fam | 10 ------ firmware.scons | 1 - firmware/targets/f7/ble_glue/ble_glue.c | 3 +- scripts/version.py | 1 + site_scons/commandline.scons | 6 ++++ site_scons/environ.scons | 22 ++++++++----- 8 files changed, 41 insertions(+), 35 deletions(-) delete mode 100644 applications/infrared_monitor/application.fam diff --git a/SConstruct b/SConstruct index d225a7e8068a..2719852d6472 100644 --- a/SConstruct +++ b/SConstruct @@ -52,22 +52,28 @@ if GetOption("fullenv"): ) # Target for self-update package + dist_arguments = [ + "-r", + '"${ROOT_DIR.abspath}/assets/resources"', + "--bundlever", + '"${UPDATE_VERSION_STRING}"', + "--radio", + '"${ROOT_DIR.abspath}/${COPRO_STACK_BIN_DIR}/${COPRO_STACK_BIN}"', + "--radiotype", + "${COPRO_STACK_TYPE}", + "${COPRO_DISCLAIMER}", + "--obdata", + '"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"', + ] + if distenv["UPDATE_SPLASH"]: + dist_arguments += [ + "--splash", + distenv.subst("assets/slideshow/$UPDATE_SPLASH"), + ] selfupdate_dist = distenv.DistBuilder( "selfupdate.pseudo", (distenv["DIST_DEPENDS"], firmware_out["FW_RESOURCES"]), - DIST_EXTRA=[ - "-r", - '"${ROOT_DIR.abspath}/assets/resources"', - "--bundlever", - '"${UPDATE_VERSION_STRING}"', - "--radio", - '"${ROOT_DIR.abspath}/${COPRO_STACK_BIN_DIR}/${COPRO_STACK_BIN}"', - "--radiotype", - "${COPRO_STACK_TYPE}", - "${COPRO_DISCLAIMER}", - "--obdata", - '"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"', - ], + DIST_EXTRA=dist_arguments, ) distenv.Pseudo("selfupdate.pseudo") AlwaysBuild(selfupdate_dist) diff --git a/applications/ReadMe.md b/applications/ReadMe.md index 2c78dfa2631a..0f1d629dbc3e 100644 --- a/applications/ReadMe.md +++ b/applications/ReadMe.md @@ -16,7 +16,6 @@ - `ibutton` - iButton application, onewire keys and more - `input` - Input service - `infrared` - Infrared application, controls your IR devices -- `infrared_monitor` - Infrared debug tool - `lfrfid` - LF RFID application - `lfrfid_debug` - LF RFID debug tool - `loader` - Application loader service diff --git a/applications/infrared_monitor/application.fam b/applications/infrared_monitor/application.fam deleted file mode 100644 index 8ab72309221b..000000000000 --- a/applications/infrared_monitor/application.fam +++ /dev/null @@ -1,10 +0,0 @@ -App( - appid="infrared_monitor", - name="Infrared Monitor", - apptype=FlipperAppType.DEBUG, - entry_point="infrared_monitor_app", - cdefines=["APP_INFRARED_MONITOR"], - requires=["gui"], - stack_size=1 * 1024, - order=80, -) diff --git a/firmware.scons b/firmware.scons index 462c87036797..74b889bb2190 100644 --- a/firmware.scons +++ b/firmware.scons @@ -121,7 +121,6 @@ else: "basic_plugins", # Debug "debug_apps", - "infrared_monitor", ] ) diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 1aa0c0a480ba..6fa3dbd0d967 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -156,11 +156,10 @@ static void ble_glue_update_c2_fw_info() { snprintf( local_info->StackTypeString, BLE_GLUE_MAX_VERSION_STRING_LEN, - "%d.%d.%d.%d.%s", + "%d.%d.%d.%s", local_info->VersionMajor, local_info->VersionMinor, local_info->VersionSub, - local_info->VersionBranch, ble_glue_get_reltype_str(local_info->StackType)); local_info->FusVersionMajor = wireless_info.FusVersionMajor; diff --git a/scripts/version.py b/scripts/version.py index edf4851cf99c..87bf7ed8829b 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -29,6 +29,7 @@ def get_version_info(self): or self._exec_git("rev-parse --abbrev-ref HEAD") or "unknown" ) + branch_num = self._exec_git("rev-list --count HEAD") or "n/a" try: diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index eaa16b05122e..a126b091d579 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -156,4 +156,10 @@ vars.Add( default="", ) +vars.Add( + "UPDATE_SPLASH", + help="Directory name with slideshow frames to render after installing update package", + default="update_default", +) + Return("vars") diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 899b86ff1117..3494290ccc04 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -7,6 +7,17 @@ import multiprocessing Import("VAR_ENV") +forward_os_env = { + # Import PATH from OS env - scons doesn't do that by default + "PATH": os.environ["PATH"], +} +# Proxying CI environment to child processes & scripts +if WORKFLOW_BRANCH_OR_TAG := os.environ.get("WORKFLOW_BRANCH_OR_TAG", None): + forward_os_env["WORKFLOW_BRANCH_OR_TAG"] = WORKFLOW_BRANCH_OR_TAG +if DIST_SUFFIX := os.environ.get("DIST_SUFFIX", None): + forward_os_env["DIST_SUFFIX"] = DIST_SUFFIX + + coreenv = VAR_ENV.Clone( tools=[ ( @@ -23,18 +34,13 @@ coreenv = VAR_ENV.Clone( TEMPFILE=TempFileMunge, MAXLINELENGTH=2048, PROGSUFFIX=".elf", - ENV={ - # Import PATH from OS env - scons doesn't do that by default - "PATH": os.environ["PATH"], - # Proxying CI environment to child processes & scripts - "DIST_SUFFIX": os.environ.get("DIST_SUFFIX", None), - "WORKFLOW_BRANCH_OR_TAG": os.environ.get("WORKFLOW_BRANCH_OR_TAG", None), - }, + ENV=forward_os_env, ) # If DIST_SUFFIX is set in environment, is has precedence (set by CI) if os_suffix := os.environ.get("DIST_SUFFIX", None): - coreenv.Replace( + print("overriding DIST_SUFFIX to ", os_suffix) + coreenv.SetDefault( DIST_SUFFIX=os_suffix, ) From 452514f04c7eb9c507f5bea5bdf808143845a003 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 21 Jun 2022 21:01:05 +0400 Subject: [PATCH 167/184] Build: better environment forward --- site_scons/environ.scons | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 3494290ccc04..eb525d212dae 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -12,10 +12,9 @@ forward_os_env = { "PATH": os.environ["PATH"], } # Proxying CI environment to child processes & scripts -if WORKFLOW_BRANCH_OR_TAG := os.environ.get("WORKFLOW_BRANCH_OR_TAG", None): - forward_os_env["WORKFLOW_BRANCH_OR_TAG"] = WORKFLOW_BRANCH_OR_TAG -if DIST_SUFFIX := os.environ.get("DIST_SUFFIX", None): - forward_os_env["DIST_SUFFIX"] = DIST_SUFFIX +for env_value_name in ("WORKFLOW_BRANCH_OR_TAG", "DIST_SUFFIX"): + if environ_value := os.environ.get(env_value_name, None): + forward_os_env[env_value_name] = environ_value coreenv = VAR_ENV.Clone( @@ -39,8 +38,7 @@ coreenv = VAR_ENV.Clone( # If DIST_SUFFIX is set in environment, is has precedence (set by CI) if os_suffix := os.environ.get("DIST_SUFFIX", None): - print("overriding DIST_SUFFIX to ", os_suffix) - coreenv.SetDefault( + coreenv.Replace( DIST_SUFFIX=os_suffix, ) From 1495a07a7aa81fe6eb9d4ce4297bb24545964def Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Wed, 22 Jun 2022 05:51:05 -0400 Subject: [PATCH 168/184] rstoring missed files, openocd fbt add --- .gitattributes | 2 ++ fbt | 12 ------------ fbt.bat | 2 +- fbt.cmd | 3 --- fbt.sh | 10 ++++++++++ 5 files changed, 13 insertions(+), 16 deletions(-) delete mode 100755 fbt delete mode 100644 fbt.cmd diff --git a/.gitattributes b/.gitattributes index 6313b56c5784..c821603a8af3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ * text=auto eol=lf +*.bat eol=crlf +*.ps1 eol=crlf diff --git a/fbt b/fbt deleted file mode 100755 index 0c55f877059a..000000000000 --- a/fbt +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set +x - -if [[ -d .git ]]; then - git submodule init - git submodule update -fi - -SCRIPTDIR="$( dirname -- "$0"; )"; -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" -/usr/bin/env python3 ${SCRIPTDIR}/lib/scons/scripts/scons.py ${SCONS_DEFAULT_FLAGS} "$@" diff --git a/fbt.bat b/fbt.bat index 38b9f75c9f54..50892d320d86 100644 --- a/fbt.bat +++ b/fbt.bat @@ -2,4 +2,4 @@ set "toolchainRoot=%~dp0toolchain\i686-windows" set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) -cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" +cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%toolchainRoot%\openocd\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/fbt.cmd b/fbt.cmd deleted file mode 100644 index 95e72a8a5dc8..000000000000 --- a/fbt.cmd +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" -python lib/scons/scripts/scons.py %SCONS_DEFAULT_FLAGS% %* diff --git a/fbt.sh b/fbt.sh index 1bfab2b73388..870c48df902f 100755 --- a/fbt.sh +++ b/fbt.sh @@ -23,12 +23,22 @@ download_toolchain() fi } +download_submodules() +{ + if [ -d .git ]; then + git submodule init + git submodule update + fi +} + SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; get_kernel_type; download_toolchain; +download_submodules; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin:$PATH"; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH"; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; +PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/openocd/bin:$PATH"; python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS $* From 6b98e3bc12ba2be05dfd0b57d552b8536c4f09c6 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Tue, 28 Jun 2022 14:48:36 +0300 Subject: [PATCH 169/184] make toolchain-download works on mac --- .gitignore | 2 +- fbt.sh | 2 +- scripts/toolchain/unix-toolchain-download.sh | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 2d66413bbcf3..86b6c2e84b69 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,4 @@ dist build/ # Toolchain -toolchain*/ \ No newline at end of file +/toolchain diff --git a/fbt.sh b/fbt.sh index 870c48df902f..e608a11c2e7c 100755 --- a/fbt.sh +++ b/fbt.sh @@ -31,7 +31,7 @@ download_submodules() fi } -SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; +SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)" SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; get_kernel_type; download_toolchain; diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 4704127358dd..426ea4f59817 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -9,7 +9,7 @@ check_system() SYS_TYPE="$(uname -s)" if [ "$SYS_TYPE" = "Darwin" ]; then echo "darwin"; - TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz"; + TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-darwin-flipper.tar.gz"; TOOLCHAIN_PATH="toolchain/x86_64-darwin"; elif [ "$SYS_TYPE" = "Linux" ]; then echo "linux"; @@ -103,7 +103,7 @@ clearing() main() { - SCRIPT_PATH="$(dirname -- "$(readlink -f -- "$0")")"; + SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)" REPO_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; check_system; # defines $TOOLCHAIN_URl and $TOOLCHAIN_PATH check_tar; From 4ed92d10cd2f0041171987e480c4e58ead663432 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Wed, 29 Jun 2022 10:54:13 -0400 Subject: [PATCH 170/184] change fbt naming, add MinGW crutch --- .gitattributes | 1 + fbt | 54 +++++++++++++++++++++++++++++++++++++++++--------- fbt.bat | 5 ----- fbt.cmd | 10 ++++------ fbt.sh | 44 ---------------------------------------- 5 files changed, 50 insertions(+), 64 deletions(-) delete mode 100644 fbt.bat delete mode 100755 fbt.sh diff --git a/.gitattributes b/.gitattributes index c821603a8af3..bd82ecaa960d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ * text=auto eol=lf *.bat eol=crlf *.ps1 eol=crlf +*.cmd eol=crlf diff --git a/fbt b/fbt index 81193a468970..6cb2ca897db4 100755 --- a/fbt +++ b/fbt @@ -1,12 +1,48 @@ -#!/bin/bash +#!/bin/sh +# shellcheck disable=SC2086 -set -e +# unofficial strict mode +set -eu; -if [[ -d .git ]]; then - echo "Updating git submodules" - git submodule update --init -fi +get_kernel_type() +{ + SYS_TYPE="$(uname -s)" + if [ "$SYS_TYPE" = "Darwin" ]; then + TOOLCHAIN_PATH="toolchain/x86_64-darwin"; + elif [ "$SYS_TYPE" = "Linux" ]; then + TOOLCHAIN_PATH="toolchain/x86_64-linux"; + elif echo "$SYS_TYPE" | grep -q "MINGW"; then + echo "In MinGW shell use \"fbt.cmd\" instead of \"fbt\""; + exit 1; + else + echo "Your system is unsupported.. sorry.."; + exit 1; + fi +} -SCRIPTDIR="$( dirname -- "$0"; )"; -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built" -python3 ${SCRIPTDIR}/lib/scons/scripts/scons.py ${SCONS_DEFAULT_FLAGS} "$@" +download_toolchain() +{ + if [ ! -d "$SCRIPT_PATH/$TOOLCHAIN_PATH" ]; then + scripts/toolchain/unix-toolchain-download.sh || exit 1; + fi +} + +download_submodules() +{ + if [ -d .git ]; then + git submodule init + git submodule update + fi +} + +SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)" +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; +get_kernel_type; +download_toolchain; +download_submodules; +PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin:$PATH"; +PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH"; +PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; +PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/openocd/bin:$PATH"; + +python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS "$@" diff --git a/fbt.bat b/fbt.bat deleted file mode 100644 index 50892d320d86..000000000000 --- a/fbt.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -set "toolchainRoot=%~dp0toolchain\i686-windows" -set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" -if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) -cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%toolchainRoot%\openocd\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/fbt.cmd b/fbt.cmd index 7711e44b5947..ab0d3a81a415 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -1,8 +1,6 @@ @echo off -if exist ".git" ( - echo Prepairing git submodules - git submodule update --init -) - +set "toolchainRoot=%~dp0toolchain\i686-windows" set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" -python lib/scons/scripts/scons.py %SCONS_DEFAULT_FLAGS% %* +if exist ".git" (git submodule update --init) +if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) +cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%toolchainRoot%\openocd\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/fbt.sh b/fbt.sh deleted file mode 100755 index e608a11c2e7c..000000000000 --- a/fbt.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -# unofficial strict mode -set -eu; - -get_kernel_type() -{ - SYS_TYPE="$(uname -s)" - if [ "$SYS_TYPE" = "Darwin" ]; then - TOOLCHAIN_PATH="toolchain/x86_64-darwin"; - elif [ "$SYS_TYPE" = "Linux" ]; then - TOOLCHAIN_PATH="toolchain/x86_64-linux"; - else - echo "Your system is unsupported.. sorry.."; - exit 1; - fi -} - -download_toolchain() -{ - if [ ! -d "$SCRIPT_PATH/$TOOLCHAIN_PATH" ]; then - scripts/toolchain/unix-toolchain-download.sh || exit 1; - fi -} - -download_submodules() -{ - if [ -d .git ]; then - git submodule init - git submodule update - fi -} - -SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)" -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; -get_kernel_type; -download_toolchain; -download_submodules; -PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin:$PATH"; -PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH"; -PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; -PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/openocd/bin:$PATH"; - -python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS $* From 28dd5d43c3f520701651238d47d432429db095d8 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Thu, 30 Jun 2022 10:26:50 -0400 Subject: [PATCH 171/184] add checking .git directory --- fbt | 12 +++++++----- fbt.cmd | 10 ++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/fbt b/fbt index 6cb2ca897db4..d92428be8269 100755 --- a/fbt +++ b/fbt @@ -23,23 +23,25 @@ get_kernel_type() download_toolchain() { if [ ! -d "$SCRIPT_PATH/$TOOLCHAIN_PATH" ]; then + chmod 755 "scripts/toolchain/unix-toolchain-download.sh"; scripts/toolchain/unix-toolchain-download.sh || exit 1; fi } -download_submodules() +check_git() { - if [ -d .git ]; then - git submodule init - git submodule update + if [ ! -d "$SCRIPT_PATH/.git" ]; then + echo "\".git\" directory not found, please clone repo via \"git clone\""; + exit 1; fi } SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)" SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; get_kernel_type; +check_git; download_toolchain; -download_submodules; +git submodule update --init; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin:$PATH"; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH"; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; diff --git a/fbt.cmd b/fbt.cmd index ab0d3a81a415..ed24e3d5b315 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -1,6 +1,12 @@ @echo off set "toolchainRoot=%~dp0toolchain\i686-windows" set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" -if exist ".git" (git submodule update --init) -if not exist "%toolchainRoot%" (powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1) +if not exist "%~dp0.git" ( + echo ".git" directory not found, please clone repo via "git clone" + exit /B 1 +) +git submodule update --init +if not exist "%toolchainRoot%" ( + powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 +) cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%toolchainRoot%\openocd\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" From 1bab50a23ddce4d8b5e1a4babbe38770b97a253e Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Thu, 30 Jun 2022 10:46:15 -0400 Subject: [PATCH 172/184] add full path to python and libs --- fbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fbt b/fbt index d92428be8269..8e1e5d4c5b22 100755 --- a/fbt +++ b/fbt @@ -47,4 +47,4 @@ PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH"; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/openocd/bin:$PATH"; -python3 lib/scons/scripts/scons.py $SCONS_DEFAULT_FLAGS "$@" +"$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin/python3" "$SCRIPT_PATH/lib/scons/scripts/scons.py" $SCONS_DEFAULT_FLAGS "$@" From 2221e9f331b5be1604fd62835242ed88b565c350 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Fri, 1 Jul 2022 06:01:36 -0400 Subject: [PATCH 173/184] Add progressbar while downloading and extracting toolchain --- scripts/toolchain/unix-toolchain-download.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 426ea4f59817..7fd0ccd4cb94 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -1,4 +1,5 @@ #!/bin/sh +# shellcheck disable=SC2086 # unofficial strict mode set -eu; @@ -51,12 +52,12 @@ curl_wget_check() fi echo "yes" DOWNLOADER="wget"; - DOWNLOADER_ARGS="-qO"; + DOWNLOADER_ARGS="--show-progress --progress=bar:force -qO"; return; fi echo "yes" DOWNLOADER="curl"; - DOWNLOADER_ARGS="-sSLo"; + DOWNLOADER_ARGS="--progress-bar -SLo"; } check_downloaded_toolchain() @@ -72,15 +73,15 @@ check_downloaded_toolchain() download_toolchain() { - printf "Checkin..oops Downloading toolchain.."; - "$DOWNLOADER" "$DOWNLOADER_ARGS" "$REPO_ROOT/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL"; + echo "Downloading toolchain:"; + "$DOWNLOADER" $DOWNLOADER_ARGS "$REPO_ROOT/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL"; echo "done"; } remove_old_tooclhain() { printf "Removing old toolchain (if exist).."; - rm -rf "$REPO_ROOT/$TOOLCHAIN_PATH"; + rm -rf "${REPO_ROOT:?}/$TOOLCHAIN_PATH"; echo "done"; } @@ -88,7 +89,7 @@ unpack_toolchain() { printf "Unpacking toolchain.."; TOOLCHAIN_DIR="$(dirname -- "$(tar -tf "$REPO_ROOT/$TOOLCHAIN_TAR" | head -n 1)")"; - tar -xf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/"; + tar --checkpoint=.2000 -xf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/"; mkdir -p "$REPO_ROOT/toolchain"; mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/$TOOLCHAIN_PATH/"; echo "done"; @@ -97,7 +98,7 @@ unpack_toolchain() clearing() { printf "Clearing.."; - rm -rf "$REPO_ROOT/$TOOLCHAIN_TAR"; + rm -rf "${REPO_ROOT:?}/$TOOLCHAIN_TAR"; echo "done"; } From c9074a21c9ef70239ff2d29d418a8882d7fdc0b6 Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Fri, 1 Jul 2022 08:53:00 -0400 Subject: [PATCH 174/184] fix progressbar on MacOS --- scripts/toolchain/unix-toolchain-download.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 7fd0ccd4cb94..59a907b8b204 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -85,11 +85,22 @@ remove_old_tooclhain() echo "done"; } +show_unpack_percentage() +{ + while read -r line; do + LINE=$(( LINE + 1 )); + if [ $(( LINE % 300 )) -eq 0 ]; then + printf "#"; + fi + done + echo " 100.0%"; +} + unpack_toolchain() { - printf "Unpacking toolchain.."; + echo "Unpacking toolchain:"; TOOLCHAIN_DIR="$(dirname -- "$(tar -tf "$REPO_ROOT/$TOOLCHAIN_TAR" | head -n 1)")"; - tar --checkpoint=.2000 -xf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/"; + tar -xvf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/" 2>&1 | show_unpack_percentage; mkdir -p "$REPO_ROOT/toolchain"; mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/$TOOLCHAIN_PATH/"; echo "done"; From 0ad49e92b069adc269e22a24bd032c45f95b318a Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Fri, 1 Jul 2022 17:10:20 +0300 Subject: [PATCH 175/184] fixed progressbar on MacOS againg --- scripts/toolchain/unix-toolchain-download.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 59a907b8b204..90578326d2dd 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -87,6 +87,7 @@ remove_old_tooclhain() show_unpack_percentage() { + LINE=0; while read -r line; do LINE=$(( LINE + 1 )); if [ $(( LINE % 300 )) -eq 0 ]; then From ba2442522da8585f54fff9fe28103f73c1b7cf1a Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Sat, 2 Jul 2022 07:05:46 -0400 Subject: [PATCH 176/184] add toolchain versioning --- fbt | 25 +++++++++++++------ fbt.cmd | 10 +++++++- scripts/toolchain/unix-toolchain-download.sh | 13 +++++----- .../toolchain/windows-toolchain-download.ps1 | 14 +++++++---- 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/fbt b/fbt index 2c07365bc13e..c6811a4613f8 100755 --- a/fbt +++ b/fbt @@ -4,6 +4,10 @@ # unofficial strict mode set -eu; +FLIPPER_TOOLCHAIN_VERSION="2"; +SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)" +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; + get_kernel_type() { SYS_TYPE="$(uname -s)" @@ -20,14 +24,23 @@ get_kernel_type() fi } -download_toolchain() +check_download_toolchain() { if [ ! -d "$SCRIPT_PATH/$TOOLCHAIN_PATH" ]; then - chmod 755 "scripts/toolchain/unix-toolchain-download.sh"; - scripts/toolchain/unix-toolchain-download.sh || exit 1; + download_toolchain; + elif [ ! -f "$SCRIPT_PATH/$TOOLCHAIN_PATH/VERSION" ]; then + download_toolchain; + elif [ "$(cat "$SCRIPT_PATH/$TOOLCHAIN_PATH/VERSION")" -ne "$FLIPPER_TOOLCHAIN_VERSION" ]; then + download_toolchain; fi } +download_toolchain() +{ + chmod 755 "$SCRIPT_PATH/scripts/toolchain/unix-toolchain-download.sh"; + "$SCRIPT_PATH/scripts/toolchain/unix-toolchain-download.sh" "$FLIPPER_TOOLCHAIN_VERSION" || exit 1; +} + check_git() { if [ ! -d "$SCRIPT_PATH/.git" ]; then @@ -36,11 +49,9 @@ check_git() fi } -SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)" -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; -get_kernel_type; +get_kernel_type; # sets TOOLCHAIN_PATH check_git; -download_toolchain; +check_download_toolchain; git submodule update --init; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin:$PATH"; PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH"; diff --git a/fbt.cmd b/fbt.cmd index eefcf81891e2..5ca4e397087c 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -1,4 +1,5 @@ @echo off +set "flipper_toolchain_version=2" set "toolchainRoot=%~dp0toolchain\i686-windows" set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" if not exist "%~dp0.git" ( @@ -7,6 +8,13 @@ if not exist "%~dp0.git" ( ) git submodule update --init if not exist "%toolchainRoot%" ( - powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 + powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%" +) +if not exist "%toolchainRoot%\VERSION" ( + powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%" +) +set /p real_toolchain_version=<%toolchainRoot%\VERSION +if not "%real_toolchain_version%" == "%flipper_toolchain_version%" ( + powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%" ) cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%toolchainRoot%\openocd\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" diff --git a/scripts/toolchain/unix-toolchain-download.sh b/scripts/toolchain/unix-toolchain-download.sh index 90578326d2dd..386be2a3ca97 100755 --- a/scripts/toolchain/unix-toolchain-download.sh +++ b/scripts/toolchain/unix-toolchain-download.sh @@ -1,20 +1,21 @@ #!/bin/sh -# shellcheck disable=SC2086 +# shellcheck disable=SC2086,SC2034 # unofficial strict mode set -eu; check_system() { + VER="$1"; # toolchain version printf "Checking kernel type.."; SYS_TYPE="$(uname -s)" if [ "$SYS_TYPE" = "Darwin" ]; then echo "darwin"; - TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-darwin-flipper.tar.gz"; + TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-x86_64-darwin-flipper-$VER.tar.gz"; TOOLCHAIN_PATH="toolchain/x86_64-darwin"; elif [ "$SYS_TYPE" = "Linux" ]; then echo "linux"; - TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-x86_64-linux-flipper.tar.gz"; + TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-x86_64-linux-flipper-$VER.tar.gz"; TOOLCHAIN_PATH="toolchain/x86_64-linux"; else echo "unsupported."; @@ -100,7 +101,6 @@ show_unpack_percentage() unpack_toolchain() { echo "Unpacking toolchain:"; - TOOLCHAIN_DIR="$(dirname -- "$(tar -tf "$REPO_ROOT/$TOOLCHAIN_TAR" | head -n 1)")"; tar -xvf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/" 2>&1 | show_unpack_percentage; mkdir -p "$REPO_ROOT/toolchain"; mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/$TOOLCHAIN_PATH/"; @@ -118,9 +118,10 @@ main() { SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)" REPO_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)"; - check_system; # defines $TOOLCHAIN_URl and $TOOLCHAIN_PATH + check_system "$1"; # recives TOOLCHAIN_VERSION, defines TOOLCHAIN_URL and TOOLCHAIN_PATH check_tar; TOOLCHAIN_TAR="$(basename "$TOOLCHAIN_URL")"; + TOOLCHAIN_DIR="$(echo "$TOOLCHAIN_TAR" | sed "s/-$VER.tar.gz//g")"; if ! check_downloaded_toolchain; then curl_wget_check; download_toolchain; @@ -131,4 +132,4 @@ main() trap clearing EXIT; trap clearing 2; # SIGINT not coverable by EXIT -main; +main "$1"; # toochain version diff --git a/scripts/toolchain/windows-toolchain-download.ps1 b/scripts/toolchain/windows-toolchain-download.ps1 index c2f4b0555d2a..bcb8f998f251 100644 --- a/scripts/toolchain/windows-toolchain-download.ps1 +++ b/scripts/toolchain/windows-toolchain-download.ps1 @@ -2,8 +2,10 @@ Set-StrictMode -Version 2.0 $ErrorActionPreference = "Stop" [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" $repo_root = (Get-Item "$PSScriptRoot\..\..").FullName -$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-2022.06-i686-windows-flipper.zip" -$toolchain_zip = "gcc-arm-none-eabi-10.3-2022.06-i686-windows-flipper.zip" +$toolchain_version = $args[0] +$toolchain_url = "https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-i686-windows-flipper-$toolchain_version.zip" +$toolchain_zip = "gcc-arm-none-eabi-10.3-i686-windows-flipper-$toolchain_version.zip" +$toolchain_dir = "gcc-arm-none-eabi-10.3-i686-windows-flipper" if (Test-Path -LiteralPath "$repo_root\toolchain\i686-windows") { Write-Host -NoNewline "Removing old Windows toolchain.." @@ -12,7 +14,8 @@ if (Test-Path -LiteralPath "$repo_root\toolchain\i686-windows") { } if (!(Test-Path -Path "$repo_root\$toolchain_zip" -PathType Leaf)) { Write-Host -NoNewline "Downloading Windows toolchain.." - Invoke-WebRequest -Uri "$toolchain_url" -OutFile "$repo_root\$toolchain_zip" + $wc = New-Object net.webclient + $wc.Downloadfile("$toolchain_url", "$repo_root\$toolchain_zip") Write-Host "done!" } @@ -21,8 +24,9 @@ if (!(Test-Path -LiteralPath "$repo_root\toolchain")) { } Write-Host -NoNewline "Unziping Windows toolchain.." -Expand-Archive -LiteralPath "$toolchain_zip" -DestinationPath "$repo_root\" -Force -Move-Item -Path "$repo_root\gcc-arm-none-eabi-10.3-2022.06" -Destination "$repo_root\toolchain\i686-windows" +Add-Type -Assembly "System.IO.Compression.Filesystem" +[System.IO.Compression.ZipFile]::ExtractToDirectory("$toolchain_zip", "$repo_root\") +Move-Item -Path "$repo_root\$toolchain_dir" -Destination "$repo_root\toolchain\i686-windows" Write-Host "done!" Write-Host -NoNewline "Clearing temporary files.." From e84a6c413ba5fdf5ae4de1d72e8b7edb45d9ed7e Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 3 Jul 2022 01:22:43 +0300 Subject: [PATCH 177/184] fbt: added separate script for Windows env setup; moved flash targets from firmware.scons to SConstruct; added Blackmagic support with automatic probe port resolution; added apps.c rebuild on any manifest.fam changes; fixed simultaneous flash & debug ops --- SConstruct | 101 ++++++++++++++++++++++---- fbt.cmd | 21 ++---- fbt_options.py | 16 +++- firmware.scons | 31 ++++---- scripts/toolchain/fbtenv.cmd | 34 +++++++++ site_scons/commandline.scons | 6 ++ site_scons/environ.scons | 1 + site_scons/fbt/util.py | 5 ++ site_scons/site_tools/blackmagic.py | 50 +++++++++++++ site_scons/site_tools/fbt_dist.py | 29 ++++---- site_scons/site_tools/sconsmodular.py | 7 +- 11 files changed, 240 insertions(+), 61 deletions(-) create mode 100644 scripts/toolchain/fbtenv.cmd create mode 100644 site_scons/site_tools/blackmagic.py diff --git a/SConstruct b/SConstruct index 7e8fc896223a..bc3e2bb9e24e 100644 --- a/SConstruct +++ b/SConstruct @@ -28,15 +28,41 @@ SConscript("site_scons/cc.scons", exports={"ENV": coreenv}) # Store root dir in environment for certain tools coreenv["ROOT_DIR"] = Dir(".") + # Create a separate "dist" environment and add construction envs to it distenv = coreenv.Clone( - tools=["fbt_dist", "openocd"], - GDBOPTS="-ex 'target extended-remote | ${OPENOCD} -c \"gdb_port pipe\" ${OPENOCD_OPTS}' " - '-ex "set confirm off" ', + tools=["fbt_dist", "openocd", "blackmagic"], + OPENOCD_GDB_PIPE=["|openocd -c 'gdb_port pipe' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"], + GDBOPTS_BASE=[ + "-ex", + "target extended-remote ${GDBREMOTE}", + "-ex", + "set confirm off", + ], + GDBOPTS_BLACKMAGIC=[ + "-ex", + "monitor swdp_scan", + "-ex", + "monitor debug_bmp enable", + "-ex", + "attach 1", + "-ex", + "set mem inaccessible-by-default off", + ], + GDBPYOPTS=[ + "-ex", + "source debug/FreeRTOS/FreeRTOS.py", + "-ex", + "source debug/PyCortexMDebug/PyCortexMDebug.py", + "-ex", + "svd_load ${SVD_FILE}", + "-ex", + "compare-sections", + ], ENV=os.environ, ) -firmware_out = distenv.AddFwProject( +firmware_env = distenv.AddFwProject( base_env=coreenv, fw_type="firmware", fw_env_key="FW_ENV", @@ -44,7 +70,7 @@ firmware_out = distenv.AddFwProject( # If enabled, initialize updater-related targets if GetOption("fullenv"): - updater_out = distenv.AddFwProject( + updater_env = distenv.AddFwProject( base_env=coreenv, fw_type="updater", fw_env_key="UPD_ENV", @@ -72,19 +98,32 @@ if GetOption("fullenv"): selfupdate_dist = distenv.DistCommand( "updater_package", - (distenv["DIST_DEPENDS"], firmware_out["FW_RESOURCES"]), + (distenv["DIST_DEPENDS"], firmware_env["FW_RESOURCES"]), DIST_EXTRA=dist_arguments, ) # Updater debug - distenv.AddDebugTarget("updater_debug", updater_out, False) + distenv.PhonyTarget( + "updater_debug", + "${GDBPYCOM}", + source=updater_env["FW_ELF"], + GDBREMOTE="${OPENOCD_GDB_PIPE}", + ) + + distenv.PhonyTarget( + "updater_blackmagic", + "${GDBPYCOM}", + source=updater_env["FW_ELF"], + GDBOPTS=distenv.subst("$GDBOPTS_BLACKMAGIC"), + GDBREMOTE="${BLACKMAGIC_ADDR}", + ) # Installation over USB & CLI usb_update_package = distenv.UsbInstall( "#build/usbinstall.flag", ( distenv["DIST_DEPENDS"], - firmware_out["FW_RESOURCES"], + firmware_env["FW_RESOURCES"], selfupdate_dist, ), ) @@ -104,15 +143,47 @@ copro_dist = distenv.CoproBuilder( ) distenv.Alias("copro_dist", copro_dist) +firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env) +distenv.Alias("flash", firmware_flash) + +firmware_bm_flash = distenv.PhonyTarget( + "flash_blackmagic", + "$GDB $GDBOPTS $SOURCES $GDBFLASH", + source=firmware_env["FW_ELF"], + GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", + GDBREMOTE="${BLACKMAGIC_ADDR}", + GDBFLASH=[ + "-ex", + "load", + "-ex", + "quit", + ], +) + # Debugging firmware -distenv.AddDebugTarget("debug", firmware_out) +firmware_debug = distenv.PhonyTarget( + "debug", + "${GDBPYCOM}", + source=firmware_env["FW_ELF"], + GDBOPTS="${GDBOPTS_BASE}", + GDBREMOTE="${OPENOCD_GDB_PIPE}", +) +distenv.Depends(firmware_debug, firmware_flash) + +distenv.PhonyTarget( + "blackmagic", + "${GDBPYCOM}", + source=firmware_env["FW_ELF"], + GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", + GDBREMOTE="${BLACKMAGIC_ADDR}", +) + # Debug alien elf distenv.PhonyTarget( "debug_other", - "$GDBPYCOM", - GDBPYOPTS= - # '-ex "source ${ROOT_DIR.abspath}/debug/FreeRTOS/FreeRTOS.py" ' - '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ', + "${GDBPYCOM}", + GDBPYOPTS='-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ', + GDBREMOTE="${OPENOCD_GDB_PIPE}", ) # Just start OpenOCD @@ -125,11 +196,11 @@ distenv.PhonyTarget( distenv.PhonyTarget( "lint", "${PYTHON3} scripts/lint.py check ${LINT_SOURCES}", - LINT_SOURCES=firmware_out["LINT_SOURCES"], + LINT_SOURCES=firmware_env["LINT_SOURCES"], ) distenv.PhonyTarget( "format", "${PYTHON3} scripts/lint.py format ${LINT_SOURCES}", - LINT_SOURCES=firmware_out["LINT_SOURCES"], + LINT_SOURCES=firmware_env["LINT_SOURCES"], ) diff --git a/fbt.cmd b/fbt.cmd index 5ca4e397087c..bffafb6a61a4 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -1,20 +1,11 @@ @echo off -set "flipper_toolchain_version=2" -set "toolchainRoot=%~dp0toolchain\i686-windows" -set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" -if not exist "%~dp0.git" ( +call %~dp0scripts\toolchain\fbtenv.cmd env + +if not exist "%FBT_ROOT%\.git" ( echo ".git" directory not found, please clone repo via "git clone --recursive" exit /B 1 ) git submodule update --init -if not exist "%toolchainRoot%" ( - powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%" -) -if not exist "%toolchainRoot%\VERSION" ( - powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%" -) -set /p real_toolchain_version=<%toolchainRoot%\VERSION -if not "%real_toolchain_version%" == "%flipper_toolchain_version%" ( - powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%" -) -cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%toolchainRoot%\openocd\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*" + +set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" +python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %* diff --git a/fbt_options.py b/fbt_options.py index 3cad7e58ce33..1c9f9c82b521 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -41,10 +41,24 @@ # Supported toolchain versions FBT_TOOLCHAIN_VERSIONS = (" 10.3.",) -OPENOCD_OPTS = '-f interface/stlink.cfg -c "transport select hla_swd" -f debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init"' +OPENOCD_OPTS = [ + "-f", + "interface/stlink.cfg", + "-c", + "transport select hla_swd", + "-f", + "debug/stm32wbx.cfg", + "-c", + "stm32wbx.cpu configure -rtos auto", + "-c", + "init", +] SVD_FILE = "debug/STM32WB55_CM4.svd" +# Look for blackmagic probe on serial ports +BLACKMAGIC = "auto" + FIRMWARE_APPS = { "default": [ "crypto_start", diff --git a/firmware.scons b/firmware.scons index 4c9988ba83cd..364838d4def9 100644 --- a/firmware.scons +++ b/firmware.scons @@ -6,7 +6,7 @@ from fbt.util import link_dir # Building initial C environment for libs env = ENV.Clone( - tools=["compilation_db", "fwbin", "openocd", "fbt_apps"], + tools=["compilation_db", "fwbin", "fbt_apps"], COMPILATIONDB_USE_ABSPATH=True, BUILD_DIR=fw_build_meta["build_dir"], IS_BASE_FIRMWARE=fw_build_meta["type"] == "firmware", @@ -139,6 +139,8 @@ apps_c = fwenv.ApplicationsC( "applications/applications.c", Value(fwenv["APPS"]), ) +# Adding dependency on manifest files so apps.c is rebuilt when any manifest is changed +fwenv.Depends(apps_c, fwenv.GlobRecursive("*.fam", "applications")) sources = [apps_c] # Gather sources only from app folders from current configuration @@ -233,7 +235,7 @@ AddPostAction(fwelf, Action("@$SIZECOM")) AddPostAction(fwelf, Action(link_latest_dir, None)) link_dir_command = fwenv["LINK_DIR_CMD"] = fwenv.PhonyTarget( - "${FIRMWARE_BUILD_CFG}" + "_latest", + fwenv.subst("${FIRMWARE_BUILD_CFG}_latest"), Action(lambda target, source, env: link_elf_dir_as_latest(env, source[0]), None), source=fwelf, ) @@ -247,17 +249,20 @@ Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu) fwdump = fwenv.ObjDump("${FIRMWARE_BUILD_CFG}") Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_list", fwdump) -# Additional FW-related pseudotargets -flash = fwenv["FW_FLASH"] = fwenv.OpenOCDFlash( - "#build/oocd-${FIRMWARE_BUILD_CFG}-flash.flag", - "${FIRMWARE_BUILD_CFG}", - OPENOCD_COMMAND='-c "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}"', -) -if fwenv["FORCE"]: - fwenv.AlwaysBuild(flash) -fwenv.Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) -if fwenv["IS_BASE_FIRMWARE"]: - fwenv.Alias("flash", flash) +# # Additional FW-related pseudotargets +# flash = fwenv["FW_FLASH"] = fwenv.OpenOCDFlash( +# "#build/oocd-${FIRMWARE_BUILD_CFG}-flash.flag", +# "${FIRMWARE_BUILD_CFG}", +# OPENOCD_COMMAND=[ +# "-c", +# "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}", +# ], +# ) +# if fwenv["FORCE"]: +# fwenv.AlwaysBuild(flash) +# fwenv.Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) +# if fwenv["IS_BASE_FIRMWARE"]: +# fwenv.Alias("flash", flash) # Compile DB generation diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd new file mode 100644 index 000000000000..5807274e7baa --- /dev/null +++ b/scripts/toolchain/fbtenv.cmd @@ -0,0 +1,34 @@ +@echo off + +set "FBT_ROOT=%~dp0\..\..\" +pushd %FBT_ROOT% +set "FBT_ROOT=%cd%" +popd + +set "FLIPPER_TOOLCHAIN_VERSION=2" +set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\i686-windows" + + +if not exist "%FBT_TOOLCHAIN_ROOT%" ( + powershell -ExecutionPolicy Bypass -File %FBT_ROOT%\scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%" +) +if not exist "%FBT_TOOLCHAIN_ROOT%\VERSION" ( + powershell -ExecutionPolicy Bypass -File %FBT_ROOT%\scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%" +) +set /p REAL_TOOLCHAIN_VERSION=<%FBT_TOOLCHAIN_ROOT%\VERSION +if not "%REAL_TOOLCHAIN_VERSION%" == "%FLIPPER_TOOLCHAIN_VERSION%" ( + powershell -ExecutionPolicy Bypass -File %FBT_ROOT%\scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%" +) + + +set "HOME=%USERPROFILE%" +set "PYTHONHOME=%FBT_TOOLCHAIN_ROOT%\python" +set "PATH=%FBT_TOOLCHAIN_ROOT%\python;%FBT_TOOLCHAIN_ROOT%\bin;%FBT_TOOLCHAIN_ROOT%\protoc\bin;%FBT_TOOLCHAIN_ROOT%\openocd\bin;%PATH%" +set "PROMPT=(fbt) %PROMPT%" + +echo fbt build environment setup complete + +if not "%1" == "env" ( + cd %FBT_ROOT% + cmd +) diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 06e836578fca..5a7a0dd2d557 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -162,6 +162,12 @@ vars.Add( default="", ) +vars.Add( + "BLACKMAGIC", + help="Blackmagic probe location", + default="auto", +) + vars.Add( "UPDATE_SPLASH", help="Directory name with slideshow frames to render after installing update package", diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 9e49e8b601d8..99d4cc0b5625 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -78,5 +78,6 @@ coreenv["TEMPFILEARGESCFUNC"] = util.tempfile_arg_esc_func util.wrap_tempfile(coreenv, "LINKCOM") util.wrap_tempfile(coreenv, "ARCOM") +coreenv["SINGLEQUOTEFUNC"] = util.single_quote Return("coreenv") diff --git a/site_scons/fbt/util.py b/site_scons/fbt/util.py index 11509b2d1899..41aea52447cd 100644 --- a/site_scons/fbt/util.py +++ b/site_scons/fbt/util.py @@ -42,3 +42,8 @@ def random_alnum(length): return "".join( random.choice(string.ascii_letters + string.digits) for _ in range(length) ) + + +def single_quote(arg_list): + # print("single_quote: ", arg_list) + return " ".join(f"'{arg}'" if " " in arg else str(arg) for arg in arg_list) diff --git a/site_scons/site_tools/blackmagic.py b/site_scons/site_tools/blackmagic.py new file mode 100644 index 000000000000..b3e95b012fce --- /dev/null +++ b/site_scons/site_tools/blackmagic.py @@ -0,0 +1,50 @@ +import serial.tools.list_ports as list_ports + + +class BlackmagicResolver: + def __init__(self, env): + self.list_ports = list_ports + self.env = env + + # On Win: + # 'location': '1-5:x.0', 'name': 'COM4', + # 'location': '1-5:x.2', 'name': 'COM13', + # On Linux: + # 'location': '1-1.2:1.0', 'name': 'ttyACM0', + # 'location': '1-1.2:1.2', 'name': 'ttyACM1', + # On MacOS: + # 'location': '0-1.3', 'name': 'cu.usbmodemblackmagic1', + # 'location': '0-1.3', 'name': 'cu.usbmodemblackmagic3', + def _find_probe(self): + ports = list(self.list_ports.grep("blackmagic")) + if len(ports) == 0: + print("Blackmagic probe not found") + elif len(ports) > 2: + print("More than one Blackmagic probe found") + else: + # print("\n".join([f"{p.device} {vars(p)}" for p in ports])) + return sorted(ports, key=lambda p: p.location + p.name)[0] + + def get_port(self): + if not (probe := self._find_probe()): + raise Exception("Please specify BLACKMAGIC=...") + # print(f"Found Blackmagic probe on {probe.device}") + if self.env.subst("$PLATFORM") == "win32": + return f"\\\\.\\{probe.device}" + return probe.device + + def __str__(self): + # print("distenv blackmagic", self.env.subst("$BLACKMAGIC")) + if (blackmagic := self.env.subst("$BLACKMAGIC")) != "auto": + return blackmagic + + # print("Looking for Blackmagic...") + return self.get_port() + + +def generate(env): + env.SetDefault(BLACKMAGIC_ADDR=BlackmagicResolver(env)) + + +def exists(env): + return True diff --git a/site_scons/site_tools/fbt_dist.py b/site_scons/site_tools/fbt_dist.py index fcfecbcbf290..37fbf74b3d05 100644 --- a/site_scons/site_tools/fbt_dist.py +++ b/site_scons/site_tools/fbt_dist.py @@ -54,20 +54,20 @@ def AddFwProject(env, base_env, fw_type, fw_env_key): return project_env -def AddDebugTarget(env, alias, targetenv, force_flash=True): - debug_target = env.PhonyTarget( - alias, - "$GDBPYCOM", - source=targetenv["FW_ELF"], - GDBPYOPTS='-ex "source debug/FreeRTOS/FreeRTOS.py" ' - '-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ' - '-ex "svd_load ${SVD_FILE}" ' - '-ex "compare-sections"', +def AddOpenOCDFlashTarget(env, targetenv, **kw): + openocd_target = env.OpenOCDFlash( + "#build/oocd-${BUILD_CFG}-flash.flag", + targetenv["FW_BIN"], + OPENOCD_COMMAND=[ + "-c", + "program ${SOURCE.posix} reset exit ${BASE_ADDRESS}", + ], + BUILD_CFG=targetenv.subst("$FIRMWARE_BUILD_CFG"), + BASE_ADDRESS=targetenv.subst("$IMAGE_BASE_ADDRESS"), + **kw, ) - if force_flash: - env.Depends(debug_target, targetenv["FW_FLASH"]) - - return debug_target + env.Alias(targetenv.subst("${FIRMWARE_BUILD_CFG}_flash"), openocd_target) + return openocd_target def DistCommand(env, name, source, **kw): @@ -85,8 +85,9 @@ def DistCommand(env, name, source, **kw): def generate(env): env.AddMethod(AddFwProject) - env.AddMethod(AddDebugTarget) env.AddMethod(DistCommand) + env.AddMethod(AddOpenOCDFlashTarget) + env.SetDefault( COPRO_MCU_FAMILY="STM32WB5x", ) diff --git a/site_scons/site_tools/sconsmodular.py b/site_scons/site_tools/sconsmodular.py index a4bb9f65af64..193a2aed7191 100644 --- a/site_scons/site_tools/sconsmodular.py +++ b/site_scons/site_tools/sconsmodular.py @@ -34,9 +34,10 @@ def PhonyTarget(env, name, action, source=None, **kw): source = [] phony_name = "phony_" + name env.Pseudo(phony_name) - return env.AlwaysBuild( - env.Alias(name, env.Command(phony_name, source, action, **kw)) - ) + # print(f"phony target {phony_name}: action {action}, kw {kw}") + command = env.Command(phony_name, source, action, **kw) + env.AlwaysBuild(env.Alias(name, command)) + return command def generate(env): From 5ee5aa67731572c33a5eb319c351b5d8adbdd1da Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 3 Jul 2022 13:26:06 +0300 Subject: [PATCH 178/184] fbt: added networked BlackmagicResolver mode; added `get_blackmagic` target for IDE integration --- SConstruct | 18 ++++++++++++----- scripts/toolchain/fbtenv.cmd | 7 ++++--- site_scons/site_tools/blackmagic.py | 30 +++++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/SConstruct b/SConstruct index bc3e2bb9e24e..33463cdcea44 100644 --- a/SConstruct +++ b/SConstruct @@ -111,11 +111,11 @@ if GetOption("fullenv"): ) distenv.PhonyTarget( - "updater_blackmagic", - "${GDBPYCOM}", - source=updater_env["FW_ELF"], - GDBOPTS=distenv.subst("$GDBOPTS_BLACKMAGIC"), - GDBREMOTE="${BLACKMAGIC_ADDR}", + "updater_blackmagic", + "${GDBPYCOM}", + source=updater_env["FW_ELF"], + GDBOPTS=distenv.subst("$GDBOPTS_BLACKMAGIC"), + GDBREMOTE="${BLACKMAGIC_ADDR}", ) # Installation over USB & CLI @@ -204,3 +204,11 @@ distenv.PhonyTarget( "${PYTHON3} scripts/lint.py format ${LINT_SOURCES}", LINT_SOURCES=firmware_env["LINT_SOURCES"], ) + + +# Find blackmagic probe + +distenv.PhonyTarget( + "get_blackmagic", + "@echo $( ${BLACKMAGIC_ADDR} $)", +) diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 5807274e7baa..7f61224e605d 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -26,9 +26,10 @@ set "PYTHONHOME=%FBT_TOOLCHAIN_ROOT%\python" set "PATH=%FBT_TOOLCHAIN_ROOT%\python;%FBT_TOOLCHAIN_ROOT%\bin;%FBT_TOOLCHAIN_ROOT%\protoc\bin;%FBT_TOOLCHAIN_ROOT%\openocd\bin;%PATH%" set "PROMPT=(fbt) %PROMPT%" -echo fbt build environment setup complete - if not "%1" == "env" ( + echo ********************************* + echo * fbt build environment * + echo ********************************* cd %FBT_ROOT% - cmd + cmd /k ) diff --git a/site_scons/site_tools/blackmagic.py b/site_scons/site_tools/blackmagic.py index b3e95b012fce..7175506d2bde 100644 --- a/site_scons/site_tools/blackmagic.py +++ b/site_scons/site_tools/blackmagic.py @@ -2,6 +2,8 @@ class BlackmagicResolver: + BLACKMAGIC_HOSTNAME = "blackmagic.local" + def __init__(self, env): self.list_ports = list_ports self.env = env @@ -18,28 +20,48 @@ def __init__(self, env): def _find_probe(self): ports = list(self.list_ports.grep("blackmagic")) if len(ports) == 0: - print("Blackmagic probe not found") + # print("Blackmagic probe serial port not found") + pass elif len(ports) > 2: print("More than one Blackmagic probe found") else: # print("\n".join([f"{p.device} {vars(p)}" for p in ports])) return sorted(ports, key=lambda p: p.location + p.name)[0] - def get_port(self): + # Look up blackmagic probe hostname with dns + def _resolve_hostname(self): + import socket + + try: + return socket.gethostbyname(self.BLACKMAGIC_HOSTNAME) + except socket.gaierror: + print("Failed to resolve Blackmagic hostname") + return None + + def get_serial(self): if not (probe := self._find_probe()): - raise Exception("Please specify BLACKMAGIC=...") + return None # print(f"Found Blackmagic probe on {probe.device}") if self.env.subst("$PLATFORM") == "win32": return f"\\\\.\\{probe.device}" return probe.device + def get_networked(self): + if not (probe := self._resolve_hostname()): + return None + + return f"tcp:{probe}:2345" + def __str__(self): # print("distenv blackmagic", self.env.subst("$BLACKMAGIC")) if (blackmagic := self.env.subst("$BLACKMAGIC")) != "auto": return blackmagic # print("Looking for Blackmagic...") - return self.get_port() + if probe := self.get_serial() or self.get_networked(): + return probe + + raise Exception("Please specify BLACKMAGIC=...") def generate(env): From 7f37c6ba837b13d495db42a67296b65256483bb5 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 3 Jul 2022 13:32:08 +0300 Subject: [PATCH 179/184] fbt: BlackmagicResolver minor fixes --- site_scons/site_tools/blackmagic.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/site_scons/site_tools/blackmagic.py b/site_scons/site_tools/blackmagic.py index 7175506d2bde..5277692f869c 100644 --- a/site_scons/site_tools/blackmagic.py +++ b/site_scons/site_tools/blackmagic.py @@ -1,11 +1,12 @@ import serial.tools.list_ports as list_ports +import socket class BlackmagicResolver: BLACKMAGIC_HOSTNAME = "blackmagic.local" + BLACKMAGIC_PORT = 2345 def __init__(self, env): - self.list_ports = list_ports self.env = env # On Win: @@ -18,7 +19,7 @@ def __init__(self, env): # 'location': '0-1.3', 'name': 'cu.usbmodemblackmagic1', # 'location': '0-1.3', 'name': 'cu.usbmodemblackmagic3', def _find_probe(self): - ports = list(self.list_ports.grep("blackmagic")) + ports = list(list_ports.grep("blackmagic")) if len(ports) == 0: # print("Blackmagic probe serial port not found") pass @@ -30,8 +31,6 @@ def _find_probe(self): # Look up blackmagic probe hostname with dns def _resolve_hostname(self): - import socket - try: return socket.gethostbyname(self.BLACKMAGIC_HOSTNAME) except socket.gaierror: @@ -50,7 +49,7 @@ def get_networked(self): if not (probe := self._resolve_hostname()): return None - return f"tcp:{probe}:2345" + return f"tcp:{probe}:{self.BLACKMAGIC_PORT}" def __str__(self): # print("distenv blackmagic", self.env.subst("$BLACKMAGIC")) From 07b9eee7ccb53b7fa1e15be102cc13c4d3d58ca0 Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 3 Jul 2022 14:10:35 +0300 Subject: [PATCH 180/184] fbt: wrapped exceptions and eliminated stacktrace leaks; added check for min Python version --- SConstruct | 2 ++ fbt_options.py | 8 ++++---- site_scons/fbt/appmanifest.py | 9 +++++++-- site_scons/fbt/util.py | 3 ++- site_scons/site_tools/blackmagic.py | 4 +++- site_scons/site_tools/crosscc.py | 3 ++- site_scons/site_tools/fbt_apps.py | 13 +++++++++++-- 7 files changed, 31 insertions(+), 11 deletions(-) diff --git a/SConstruct b/SConstruct index 33463cdcea44..728cd98d91f0 100644 --- a/SConstruct +++ b/SConstruct @@ -8,6 +8,8 @@ import os +EnsurePythonVersion(3, 8) + DefaultEnvironment(tools=[]) # Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15) diff --git a/fbt_options.py b/fbt_options.py index 1c9f9c82b521..fb06cecd0f01 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -10,8 +10,8 @@ ## Optimize for debugging experience DEBUG = 1 -# Suffix to add to files when building distribution. -# If OS environment has DIST_SUFFIX set, it will be used instead.. +# Suffix to add to files when building distribution +# If OS environment has DIST_SUFFIX set, it will be used instead DIST_SUFFIX = "local" # Coprocessor firmware @@ -27,7 +27,7 @@ # Firmware also supports "ble_full", but it might not fit into debug builds COPRO_STACK_TYPE = "ble_light" -# Leave 0 to lets scripts automatically calculate it +# Leave 0 to let scripts automatically calculate it COPRO_STACK_ADDR = "0x0" # If you override COPRO_CUBE_DIR on commandline, override this aswell @@ -56,7 +56,7 @@ SVD_FILE = "debug/STM32WB55_CM4.svd" -# Look for blackmagic probe on serial ports +# Look for blackmagic probe on serial ports and local network BLACKMAGIC = "auto" FIRMWARE_APPS = { diff --git a/site_scons/fbt/appmanifest.py b/site_scons/fbt/appmanifest.py index 218b139f3edb..990bd5b3b0c7 100644 --- a/site_scons/fbt/appmanifest.py +++ b/site_scons/fbt/appmanifest.py @@ -63,8 +63,13 @@ def App(*args, **kw): nonlocal app_manifests app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name)) - with open(app_manifest_path, "rt") as manifest_file: - exec(manifest_file.read()) + try: + with open(app_manifest_path, "rt") as manifest_file: + exec(manifest_file.read()) + except Exception as e: + raise FlipperManifestException( + f"Failed parsing manifest '{app_manifest_path}' : {e}" + ) if len(app_manifests) == 0: raise FlipperManifestException( diff --git a/site_scons/fbt/util.py b/site_scons/fbt/util.py index 41aea52447cd..4b5629abc617 100644 --- a/site_scons/fbt/util.py +++ b/site_scons/fbt/util.py @@ -1,5 +1,6 @@ import SCons from SCons.Subst import quote_spaces +from SCons.Errors import StopError import re import os @@ -30,7 +31,7 @@ def link_dir(target_path, source_path, is_windows): import _winapi if not os.path.isdir(source_path): - raise Exception(f"Source directory {source_path} is not a directory") + raise StopError(f"Source directory {source_path} is not a directory") if not os.path.exists(target_path): _winapi.CreateJunction(source_path, target_path) diff --git a/site_scons/site_tools/blackmagic.py b/site_scons/site_tools/blackmagic.py index 5277692f869c..f037ce99c35d 100644 --- a/site_scons/site_tools/blackmagic.py +++ b/site_scons/site_tools/blackmagic.py @@ -1,5 +1,6 @@ import serial.tools.list_ports as list_ports import socket +from SCons.Errors import SConsEnvironmentError class BlackmagicResolver: @@ -23,6 +24,7 @@ def _find_probe(self): if len(ports) == 0: # print("Blackmagic probe serial port not found") pass + # Blackmagic has 2 usb interfaces with same serial elif len(ports) > 2: print("More than one Blackmagic probe found") else: @@ -60,7 +62,7 @@ def __str__(self): if probe := self.get_serial() or self.get_networked(): return probe - raise Exception("Please specify BLACKMAGIC=...") + raise SConsEnvironmentError("Please specify BLACKMAGIC=...") def generate(env): diff --git a/site_scons/site_tools/crosscc.py b/site_scons/site_tools/crosscc.py index 8d6b4a61879a..dbedf5c07956 100644 --- a/site_scons/site_tools/crosscc.py +++ b/site_scons/site_tools/crosscc.py @@ -1,3 +1,4 @@ +from SCons.Errors import StopError from SCons.Tool import asm from SCons.Tool import gcc from SCons.Tool import gxx @@ -65,7 +66,7 @@ def generate(env, **kw): # print("CC version =", cc_version) # print(list(filter(lambda v: v in cc_version, whitelisted_versions))) if not any(filter(lambda v: v in cc_version, whitelisted_versions)): - raise Exception( + raise StopError( f"Toolchain version is not supported. Allowed: {whitelisted_versions}, toolchain: {cc_version} " ) diff --git a/site_scons/site_tools/fbt_apps.py b/site_scons/site_tools/fbt_apps.py index bdccccf7b5cf..1c2e0167aae7 100644 --- a/site_scons/site_tools/fbt_apps.py +++ b/site_scons/site_tools/fbt_apps.py @@ -1,8 +1,14 @@ from SCons.Builder import Builder from SCons.Action import Action +from SCons.Errors import UserError import SCons -from fbt.appmanifest import FlipperAppType, AppManager, ApplicationsCGenerator +from fbt.appmanifest import ( + FlipperAppType, + AppManager, + ApplicationsCGenerator, + FlipperManifestException, +) # Adding objects for application management to env # AppManager env["APPMGR"] - loads all manifests; manages list of known apps @@ -13,7 +19,10 @@ def LoadApplicationManifests(env): appmgr = env["APPMGR"] = AppManager() for entry in env.Glob("#/applications/*"): if isinstance(entry, SCons.Node.FS.Dir) and not str(entry).startswith("."): - appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) + try: + appmgr.load_manifest(entry.File("application.fam").abspath, entry.name) + except FlipperManifestException as e: + raise UserError(e) def PrepareApplicationsBuild(env): From 3abf2f3d53beaed3a6a799472a6c2f76da520c1f Mon Sep 17 00:00:00 2001 From: hedger Date: Sun, 3 Jul 2022 21:11:42 +0300 Subject: [PATCH 181/184] fbt: fixed linking updater as latest build dir for "flash_usb" --- firmware.scons | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/firmware.scons b/firmware.scons index 364838d4def9..959b5a1f82b9 100644 --- a/firmware.scons +++ b/firmware.scons @@ -205,7 +205,7 @@ def link_elf_dir_as_latest(env, elf_target): # Ugly way to check if updater-related targets were requested elf_dir = elf_target.Dir(".") explicitly_building_updater = False - # print("BUILD_TARGETS:", ','.join(BUILD_TARGETS)) + # print("BUILD_TARGETS:", ",".join(BUILD_TARGETS)) for build_target in BUILD_TARGETS: # print(">>> ", str(build_target)) if "updater" in str(build_target): @@ -213,11 +213,12 @@ def link_elf_dir_as_latest(env, elf_target): latest_dir = env.Dir("#build/latest") - link_this_dir = True - if explicitly_building_updater: - # If updater is explicitly requested, link to the latest updater - # Otherwise, link to the latest firmware - link_this_dir = not env["IS_BASE_FIRMWARE"] + is_updater = not env["IS_BASE_FIRMWARE"] + # If updater is explicitly requested, link to the latest updater + # Otherwise, link to the latest firmware + link_this_dir = (is_updater and explicitly_building_updater) or ( + not is_updater and not explicitly_building_updater + ) if link_this_dir: print(f"Setting {elf_dir} as latest built dir") @@ -249,21 +250,6 @@ Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu) fwdump = fwenv.ObjDump("${FIRMWARE_BUILD_CFG}") Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_list", fwdump) -# # Additional FW-related pseudotargets -# flash = fwenv["FW_FLASH"] = fwenv.OpenOCDFlash( -# "#build/oocd-${FIRMWARE_BUILD_CFG}-flash.flag", -# "${FIRMWARE_BUILD_CFG}", -# OPENOCD_COMMAND=[ -# "-c", -# "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}", -# ], -# ) -# if fwenv["FORCE"]: -# fwenv.AlwaysBuild(flash) -# fwenv.Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash) -# if fwenv["IS_BASE_FIRMWARE"]: -# fwenv.Alias("flash", flash) - # Compile DB generation fwcdb = fwenv["FW_CDB"] = fwenv.CompilationDatabase("compile_commands.json") @@ -274,7 +260,7 @@ artifacts = [ fwhex, fwbin, fwdfu, - env["FW_VERSION_JSON"], + fwenv["FW_VERSION_JSON"], fwcdb, ] fwenv["FW_ARTIFACTS"] = artifacts From e033fbe38e80890ecb116386bf0e84fc8d3735c2 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 4 Jul 2022 15:18:51 +0300 Subject: [PATCH 182/184] scripts: fbtenv.cmd: not setting env variables if already set --- scripts/toolchain/fbtenv.cmd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 7f61224e605d..f6e5e975e7a7 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -1,5 +1,6 @@ @echo off +if not [%FBT_ROOT%] == [] goto already_set set "FBT_ROOT=%~dp0\..\..\" pushd %FBT_ROOT% set "FBT_ROOT=%cd%" @@ -26,6 +27,8 @@ set "PYTHONHOME=%FBT_TOOLCHAIN_ROOT%\python" set "PATH=%FBT_TOOLCHAIN_ROOT%\python;%FBT_TOOLCHAIN_ROOT%\bin;%FBT_TOOLCHAIN_ROOT%\protoc\bin;%FBT_TOOLCHAIN_ROOT%\openocd\bin;%PATH%" set "PROMPT=(fbt) %PROMPT%" +:already_set + if not "%1" == "env" ( echo ********************************* echo * fbt build environment * From bd94e6ebc3f6ae718c05c2fbe2cad6b2a6f928fa Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 4 Jul 2022 18:28:57 +0300 Subject: [PATCH 183/184] fbt: moved environment init to scripts/toolchain; skipping environment init if FBT_NOENV is set in environment --- fbt | 64 +++++------------------------------- scripts/toolchain/fbtenv.cmd | 9 ++++- scripts/toolchain/fbtenv.sh | 64 ++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 57 deletions(-) create mode 100755 scripts/toolchain/fbtenv.sh diff --git a/fbt b/fbt index c6811a4613f8..095723816a3c 100755 --- a/fbt +++ b/fbt @@ -1,61 +1,13 @@ #!/bin/sh -# shellcheck disable=SC2086 +SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)"; +. $SCRIPT_PATH/scripts/toolchain/fbtenv.sh; -# unofficial strict mode -set -eu; +if [ ! -d "${FBT_ROOT:-.}/.git" ]; then + echo "\".git\" directory not found, please clone repo via \"git clone --recursive\""; + exit 1; +fi -FLIPPER_TOOLCHAIN_VERSION="2"; -SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)" -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; - -get_kernel_type() -{ - SYS_TYPE="$(uname -s)" - if [ "$SYS_TYPE" = "Darwin" ]; then - TOOLCHAIN_PATH="toolchain/x86_64-darwin"; - elif [ "$SYS_TYPE" = "Linux" ]; then - TOOLCHAIN_PATH="toolchain/x86_64-linux"; - elif echo "$SYS_TYPE" | grep -q "MINGW"; then - echo "In MinGW shell use \"fbt.cmd\" instead of \"fbt\""; - exit 1; - else - echo "Your system is not supported. Sorry. Please report us your configuration."; - exit 1; - fi -} - -check_download_toolchain() -{ - if [ ! -d "$SCRIPT_PATH/$TOOLCHAIN_PATH" ]; then - download_toolchain; - elif [ ! -f "$SCRIPT_PATH/$TOOLCHAIN_PATH/VERSION" ]; then - download_toolchain; - elif [ "$(cat "$SCRIPT_PATH/$TOOLCHAIN_PATH/VERSION")" -ne "$FLIPPER_TOOLCHAIN_VERSION" ]; then - download_toolchain; - fi -} - -download_toolchain() -{ - chmod 755 "$SCRIPT_PATH/scripts/toolchain/unix-toolchain-download.sh"; - "$SCRIPT_PATH/scripts/toolchain/unix-toolchain-download.sh" "$FLIPPER_TOOLCHAIN_VERSION" || exit 1; -} - -check_git() -{ - if [ ! -d "$SCRIPT_PATH/.git" ]; then - echo "\".git\" directory not found, please clone repo via \"git clone --recursive\""; - exit 1; - fi -} - -get_kernel_type; # sets TOOLCHAIN_PATH -check_git; -check_download_toolchain; git submodule update --init; -PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin:$PATH"; -PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH"; -PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; -PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/openocd/bin:$PATH"; -"$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin/python3" "$SCRIPT_PATH/lib/scons/scripts/scons.py" $SCONS_DEFAULT_FLAGS "$@" +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; +python3 "$SCRIPT_PATH/lib/scons/scripts/scons.py" $SCONS_DEFAULT_FLAGS "$@" diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index f6e5e975e7a7..7be8b52fb75f 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -1,6 +1,13 @@ @echo off -if not [%FBT_ROOT%] == [] goto already_set +if not [%FBT_NOENV%] == [] ( + exit /b 0 +) + +if not [%FBT_ROOT%] == [] ( + goto already_set +) + set "FBT_ROOT=%~dp0\..\..\" pushd %FBT_ROOT% set "FBT_ROOT=%cd%" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh new file mode 100755 index 000000000000..c61db496fadf --- /dev/null +++ b/scripts/toolchain/fbtenv.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# shellcheck disable=SC2086 + +# unofficial strict mode +set -eu; + +FLIPPER_TOOLCHAIN_VERSION="2"; +export FBT_ROOT="$(cd "$(dirname "$0")" && pwd -P)"; + +get_kernel_type() +{ + SYS_TYPE="$(uname -s)" + if [ "$SYS_TYPE" = "Darwin" ]; then + TOOLCHAIN_PATH="toolchain/x86_64-darwin"; + elif [ "$SYS_TYPE" = "Linux" ]; then + TOOLCHAIN_PATH="toolchain/x86_64-linux"; + elif echo "$SYS_TYPE" | grep -q "MINGW"; then + echo "In MinGW shell use \"fbt.cmd\" instead of \"fbt\""; + exit 1; + else + echo "Your system is not supported. Sorry. Please report us your configuration."; + exit 1; + fi +} + +check_download_toolchain() +{ + if [ ! -d "$FBT_ROOT/$TOOLCHAIN_PATH" ]; then + download_toolchain; + elif [ ! -f "$FBT_ROOT/$TOOLCHAIN_PATH/VERSION" ]; then + download_toolchain; + elif [ "$(cat "$FBT_ROOT/$TOOLCHAIN_PATH/VERSION")" -ne "$FLIPPER_TOOLCHAIN_VERSION" ]; then + download_toolchain; + fi +} + +download_toolchain() +{ + chmod 755 "$FBT_ROOT/scripts/toolchain/unix-toolchain-download.sh"; + "$FBT_ROOT/scripts/toolchain/unix-toolchain-download.sh" "$FLIPPER_TOOLCHAIN_VERSION" || exit 1; +} + +check_git() +{ + if [ ! -d "$FBT_ROOT/.git" ]; then + echo "\".git\" directory not found, please clone repo via \"git clone --recursive\""; + exit 1; + fi +} + +setup_env() +{ + get_kernel_type; # sets TOOLCHAIN_PATH + check_git; + check_download_toolchain; + PATH="$FBT_ROOT/$TOOLCHAIN_PATH/python/bin:$PATH"; + PATH="$FBT_ROOT/$TOOLCHAIN_PATH/bin:$PATH"; + PATH="$FBT_ROOT/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; + PATH="$FBT_ROOT/$TOOLCHAIN_PATH/openocd/bin:$PATH"; +} + +if [ -z "${FBT_NOENV:-}" ]; then + setup_env; +fi From 714d0de23342135ef9d003b92742095300d477bf Mon Sep 17 00:00:00 2001 From: DrunkBatya Date: Tue, 5 Jul 2022 07:23:24 -0400 Subject: [PATCH 184/184] fix merge conflicts --- fbt | 21 +++++++++++++++------ scripts/toolchain/fbtenv.sh | 36 +++++++++++++----------------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/fbt b/fbt index 095723816a3c..cbd7d04725ac 100755 --- a/fbt +++ b/fbt @@ -1,13 +1,22 @@ #!/bin/sh + +# shellcheck disable=SC2086 source=/dev/null +# unofficial strict mode +set -eu; + +SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)"; -. $SCRIPT_PATH/scripts/toolchain/fbtenv.sh; -if [ ! -d "${FBT_ROOT:-.}/.git" ]; then - echo "\".git\" directory not found, please clone repo via \"git clone --recursive\""; - exit 1; +if [ -z "${FBT_NOENV:-}" ]; then + . "$SCRIPT_PATH/scripts/toolchain/fbtenv.sh"; fi -git submodule update --init; +if [ -z "${FBT_NO_SYNC:-}" ]; then + if [ ! -d "$SCRIPT_PATH/.git" ]; then + echo "\".git\" directory not found, please clone repo via \"git clone --recursive\""; + exit 1; + fi + git submodule update --init; +fi -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; python3 "$SCRIPT_PATH/lib/scons/scripts/scons.py" $SCONS_DEFAULT_FLAGS "$@" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index c61db496fadf..765548ed64f9 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -1,11 +1,9 @@ #!/bin/sh -# shellcheck disable=SC2086 # unofficial strict mode set -eu; FLIPPER_TOOLCHAIN_VERSION="2"; -export FBT_ROOT="$(cd "$(dirname "$0")" && pwd -P)"; get_kernel_type() { @@ -25,40 +23,32 @@ get_kernel_type() check_download_toolchain() { - if [ ! -d "$FBT_ROOT/$TOOLCHAIN_PATH" ]; then + if [ ! -d "$SCRIPT_PATH/$TOOLCHAIN_PATH" ]; then download_toolchain; - elif [ ! -f "$FBT_ROOT/$TOOLCHAIN_PATH/VERSION" ]; then + elif [ ! -f "$SCRIPT_PATH/$TOOLCHAIN_PATH/VERSION" ]; then download_toolchain; - elif [ "$(cat "$FBT_ROOT/$TOOLCHAIN_PATH/VERSION")" -ne "$FLIPPER_TOOLCHAIN_VERSION" ]; then + elif [ "$(cat "$SCRIPT_PATH/$TOOLCHAIN_PATH/VERSION")" -ne "$FLIPPER_TOOLCHAIN_VERSION" ]; then download_toolchain; fi } download_toolchain() { - chmod 755 "$FBT_ROOT/scripts/toolchain/unix-toolchain-download.sh"; - "$FBT_ROOT/scripts/toolchain/unix-toolchain-download.sh" "$FLIPPER_TOOLCHAIN_VERSION" || exit 1; + chmod 755 "$SCRIPT_PATH/scripts/toolchain/unix-toolchain-download.sh"; + "$SCRIPT_PATH/scripts/toolchain/unix-toolchain-download.sh" "$FLIPPER_TOOLCHAIN_VERSION" || exit 1; } -check_git() +main() { - if [ ! -d "$FBT_ROOT/.git" ]; then - echo "\".git\" directory not found, please clone repo via \"git clone --recursive\""; + if [ -z "${SCRIPT_PATH:-}" ]; then + echo "Mannual running this script is now allowed."; exit 1; fi -} - -setup_env() -{ get_kernel_type; # sets TOOLCHAIN_PATH - check_git; check_download_toolchain; - PATH="$FBT_ROOT/$TOOLCHAIN_PATH/python/bin:$PATH"; - PATH="$FBT_ROOT/$TOOLCHAIN_PATH/bin:$PATH"; - PATH="$FBT_ROOT/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; - PATH="$FBT_ROOT/$TOOLCHAIN_PATH/openocd/bin:$PATH"; + PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin:$PATH"; + PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH"; + PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/protobuf/bin:$PATH"; + PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/openocd/bin:$PATH"; } - -if [ -z "${FBT_NOENV:-}" ]; then - setup_env; -fi +main;