From bd1fba9d20103359e0013883a640f60b579dcb20 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Mon, 12 Sep 2022 22:31:14 +0200 Subject: [PATCH] littlefs-do: Generate list_settings.cpp from Settings.h Add and use the python script `parse_infinitime_settings.py` to generate the file `list_settings.cpp` with helper function `list_settings()` to reduce the maintenance burden by not having to manually handle changes in `Settings.h`. Fixes: https://github.com/InfiniTimeOrg/InfiniSim/issues/54 --- CMakeLists.txt | 22 ++++++ littlefs-do-main.cpp | 83 +------------------- parse_infinitime_settings.py | 148 +++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 79 deletions(-) create mode 100755 parse_infinitime_settings.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 88bb28e..fac613c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -337,6 +337,28 @@ target_link_libraries(littlefs-do PUBLIC littlefs) target_link_libraries(littlefs-do PRIVATE SDL2::SDL2) target_link_libraries(littlefs-do PRIVATE infinitime_fonts) +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) + # FindPython3 module introduces with CMake 3.12 + # https://cmake.org/cmake/help/latest/module/FindPython3.html + find_package(Python3 REQUIRED) +else() + set(Python3_EXECUTABLE "python") +endif() +message(STATUS "calling ${CMAKE_CURRENT_SOURCE_DIR}/parse_infinitime_settings.py generating ${CMAKE_CURRENT_BINARY_DIR}/list_settings.cpp") +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/list_settings.cpp + COMMAND "${Python3_EXECUTABLE}" ${CMAKE_CURRENT_SOURCE_DIR}/parse_infinitime_settings.py + "${InfiniTime_DIR}/src/components/settings/Settings.h" + --output "${CMAKE_CURRENT_BINARY_DIR}/list_settings.cpp" + DEPENDS "${InfiniTime_DIR}/src/components/settings/Settings.h" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) +add_custom_target(list_settings + DEPENDS "${InfiniTime_DIR}/src/components/settings/Settings.h" +) +target_sources(littlefs-do PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/list_settings.cpp") +add_dependencies(littlefs-do list_settings) + add_subdirectory(external/miniz) add_subdirectory(external/nlohmann_json) target_link_libraries(littlefs-do PRIVATE miniz) diff --git a/littlefs-do-main.cpp b/littlefs-do-main.cpp index 780e561..2099875 100644 --- a/littlefs-do-main.cpp +++ b/littlefs-do-main.cpp @@ -515,6 +515,9 @@ int command_cp(const std::string &program_name, const std::vector & return 0; } +// generated into ${CMAKE_BUILD_DIR}/list_settings.cpp +void list_settings(const Pinetime::Controllers::Settings &settingsController); + int command_settings(const std::string &program_name, const std::vector &args, bool verbose) { if (verbose) { @@ -533,85 +536,7 @@ int command_settings(const std::string &program_name, const std::vector(clockface) << " " << clockface_str << std::endl; - } - { - auto chimes = settingsController.GetChimeOption(); - auto chimes_str = [](auto val) { - if (val == Settings::ChimesOption::None) return "None"; - if (val == Settings::ChimesOption::Hours) return "Hours"; - if (val == Settings::ChimesOption::HalfHours) return "HalfHours"; - return "unknown"; - }(chimes); - std::cout << "Chimes: " << static_cast(chimes) << " " << chimes_str << std::endl; - } - auto color_str = [](auto c) { - if (c == Settings::Colors::White) return "White"; - if (c == Settings::Colors::Silver) return "Silver"; - if (c == Settings::Colors::Gray) return "Gray"; - if (c == Settings::Colors::Black) return "Black"; - if (c == Settings::Colors::Red) return "Red"; - if (c == Settings::Colors::Maroon) return "Maroon"; - if (c == Settings::Colors::Yellow) return "Yellow"; - if (c == Settings::Colors::Olive) return "Olive"; - if (c == Settings::Colors::Lime) return "Lime"; - if (c == Settings::Colors::Green) return "Cyan"; - if (c == Settings::Colors::Teal) return "Teal"; - if (c == Settings::Colors::Blue) return "Blue"; - if (c == Settings::Colors::Navy) return "Navy"; - if (c == Settings::Colors::Magenta) return "Magenta"; - if (c == Settings::Colors::Purple) return "Purple"; - if (c == Settings::Colors::Orange) return "Orange"; - return "unknown"; - }; - std::cout << "PTSColorTime: " << color_str(settingsController.GetPTSColorTime()) << std::endl; - std::cout << "PTSColorBar: " << color_str(settingsController.GetPTSColorBar()) << std::endl; - std::cout << "PTSColorBG: " << color_str(settingsController.GetPTSColorBG()) << std::endl; - std::cout << "AppMenu: " << static_cast(settingsController.GetAppMenu()) << std::endl; - std::cout << "SettingsMenu: " << static_cast(settingsController.GetSettingsMenu()) << std::endl; - std::cout << "ClockType: " << (settingsController.GetClockType() == Settings::ClockType::H24 ? "H24" : "H12") << std::endl; - { - auto notif = settingsController.GetNotificationStatus(); - auto notif_str = [](auto val) { - if (val == Settings::Notification::On) return "On"; - if (val == Settings::Notification::Off) return "Off"; - if (val == Settings::Notification::Sleep) return "Sleep"; - return "unknown"; - }(notif); - std::cout << "NotificationStatus: " << static_cast(notif) << " " << notif_str << std::endl; - } - std::cout << "ScreenTimeOut: " << settingsController.GetScreenTimeOut() << " ms" << std::endl; - std::cout << "ShakeThreshold: " << settingsController.GetShakeThreshold() << std::endl; - { - std::cout << "WakeUpModes: " << std::endl; - std::cout << "- SingleTap: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::SingleTap) ? "ON" : "OFF") << std::endl; - std::cout << "- DoubleTap: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::DoubleTap) ? "ON" : "OFF") << std::endl; - std::cout << "- RaiseWrist: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::RaiseWrist) ? "ON" : "OFF") << std::endl; - std::cout << "- Shake: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::Shake) ? "ON" : "OFF") << std::endl; - } - { - auto brightness = settingsController.GetBrightness(); - auto brightness_str = [](auto val) { - if (val == BrightnessController::Levels::Off) return "Off"; - if (val == BrightnessController::Levels::Low) return "Low"; - if (val == BrightnessController::Levels::Medium) return "Medium"; - if (val == BrightnessController::Levels::High) return "High"; - return "unknown"; - }(brightness); - std::cout << "Brightness: " << static_cast(brightness) << " " << brightness_str << std::endl; - } - std::cout << "StepsGoal: " << settingsController.GetStepsGoal() << std::endl; - std::cout << "BleRadioEnabled: " << (settingsController.GetBleRadioEnabled() ? "true" : "false") << std::endl; + list_settings(settingsController); return 0; } diff --git a/parse_infinitime_settings.py b/parse_infinitime_settings.py new file mode 100755 index 0000000..3457576 --- /dev/null +++ b/parse_infinitime_settings.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +import argparse +import pathlib +import re +import sys + +def main(): + parser = argparse.ArgumentParser(description="Parse settings.h and create a status printing c++ file") + parser.add_argument("settings_h_file", type=str, + help="path to 'settings.h' file to parse") + parser.add_argument("-o", "--output", type=str, + help="file to generated write c++ code into", + default="-") + args = parser.parse_args() + + with open(args.settings_h_file, encoding="utf-8") as f: + settings = f.read() + enum_matcher = re.compile(r"enum class ([a-zA-Z]+) : uint8_t \{[ \n]*([^}]*)\}\;") + enum_matches = enum_matcher.findall(settings) + + # get all enums + def match_to_enum(match): + enum_name = match[0] + entries_str = match[1] + entries = [e.strip() for e in entries_str.split(",")] + entries_filtered = [e.split("=")[0].strip() if "=" in e else e for e in entries if e] + return (enum_name, entries_filtered) + enum_list = [match_to_enum(e) for e in enum_matches] + enums = {key: entries for key, entries in enum_list} + print("extracted enums:") + for e in enums: + print(" ", e, enums[e]) + print("") + #print(enums) + + # get all Getters + m_getters = re.findall(r"([a-zA-Z_0-9<>]+) ([gG]et[a-zA-Z]+)\(\) const", settings) + print("extracted getter:") + for m in m_getters: + print(" ", m) + print("") + + def getter_to_cpp(m_getter, enums): + getter_ret, getter_call = m_getter + setting_name = getter_call[3:] + kwargs = { + "getter_ret": getter_ret, + "getter_call": getter_call, + "setting_name": setting_name, + } + out = "" + + if getter_ret in enums: + out += """ + {{ + auto {setting_name}_str = [](auto val) {{""".format(**kwargs) + enum_items = enums[getter_ret] + for enum_entry in enum_items: + out += """ + if (val == Settings::{getter_ret}::{enum_entry}) return "{enum_entry}";""".format(**kwargs, enum_entry=enum_entry) + out += """ + return "unknown"; + }}; + std::cout << "{setting_name}: " << static_cast(settingsController.{getter_call}()) << " " << {setting_name}_str(settingsController.{getter_call}()) << std::endl; + }}""".format(**kwargs) + + elif setting_name == "ClockFace": + out += """ + {{ + auto clockface = settingsController.GetClockFace(); + auto clockface_str = [](auto val) {{ + if (val == 0) return "Digital"; + if (val == 1) return "Analog"; + if (val == 2) return "PineTimeStyle"; + if (val == 3) return "Terminal"; + return "unknown"; + }}(clockface); + std::cout << "ClockFace: " << static_cast(clockface) << " " << clockface_str << std::endl; + }}""".format(getter_ret=getter_ret, getter_call=getter_call, setting_name=setting_name) + + elif setting_name == "ScreenTimeOut": + out += """ + {{ + {getter_ret} val = settingsController.{getter_call}(); + std::cout << "{setting_name}: " << static_cast(settingsController.{getter_call}()) << " ms" << std::endl; + }}""".format(getter_ret=getter_ret, getter_call=getter_call, setting_name=setting_name) + + elif setting_name == "WakeUpModes": + out += """ + {{ + std::cout << "WakeUpModes: " << std::endl; + std::cout << "- SingleTap: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::SingleTap) ? "ON" : "OFF") << std::endl; + std::cout << "- DoubleTap: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::DoubleTap) ? "ON" : "OFF") << std::endl; + std::cout << "- RaiseWrist: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::RaiseWrist) ? "ON" : "OFF") << std::endl; + std::cout << "- Shake: " << (settingsController.isWakeUpModeOn(Settings::WakeUpMode::Shake) ? "ON" : "OFF") << std::endl; + }}""".format(getter_ret=getter_ret, getter_call=getter_call, setting_name=setting_name) + + elif setting_name == "Brightness": + # Brightness levels are stored in components/brightness/BrightnessController.h + # create special handling + out += """ + { + auto brightness = settingsController.GetBrightness(); + auto brightness_str = [](auto val) { + if (val == BrightnessController::Levels::Off) return "Off"; + if (val == BrightnessController::Levels::Low) return "Low"; + if (val == BrightnessController::Levels::Medium) return "Medium"; + if (val == BrightnessController::Levels::High) return "High"; + return "unknown"; + }(brightness); + std::cout << "Brightness: " << static_cast(brightness) << " " << brightness_str << std::endl; + }""" + + elif getter_ret == "bool": + out += """ + {{ + {getter_ret} val = settingsController.{getter_call}(); + std::cout << "{setting_name}: " << (settingsController.{getter_call}() ? "true" : "false") << std::endl; + }}""".format(getter_ret=getter_ret, getter_call=getter_call, setting_name=setting_name) + + else: # just output non-enum entry + out += """ + {{ + {getter_ret} val = settingsController.{getter_call}(); + std::cout << "{setting_name}: " << static_cast(settingsController.{getter_call}()) << std::endl; + }}""".format(getter_ret=getter_ret, getter_call=getter_call, setting_name=setting_name) + + return out + + list_settings_function = """ +#include +#include "components/settings/Settings.h" +void list_settings(const Pinetime::Controllers::Settings &settingsController) { + using namespace Pinetime::Controllers;""" + for m in m_getters: + list_settings_function += getter_to_cpp(m, enums) + + list_settings_function += """ +}""" + if args.output == "" or args.output == "-": + print(list_settings_function) + else: + with open(args.output, "w", encoding="utf-8") as f: + f.write(list_settings_function) + return 0 + +if __name__ == '__main__': + sys.exit(main())