Skip to content

Commit

Permalink
littlefs-do: Generate list_settings.cpp from Settings.h
Browse files Browse the repository at this point in the history
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: #54
  • Loading branch information
NeroBurner committed Sep 12, 2022
1 parent 0fe5b87 commit bba1758
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 79 deletions.
22 changes: 22 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
83 changes: 4 additions & 79 deletions littlefs-do-main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,9 @@ int command_cp(const std::string &program_name, const std::vector<std::string> &
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<std::string> &args, bool verbose)
{
if (verbose) {
Expand All @@ -533,85 +536,7 @@ int command_settings(const std::string &program_name, const std::vector<std::str
std::cout << "calling Settings::Init()" << std::endl;
}
settingsController.Init();
using namespace Pinetime::Controllers;
{
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<int>(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<int>(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<int>(settingsController.GetAppMenu()) << std::endl;
std::cout << "SettingsMenu: " << static_cast<int>(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<int>(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<int>(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;
}

Expand Down
148 changes: 148 additions & 0 deletions parse_infinitime_settings.py
Original file line number Diff line number Diff line change
@@ -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<int>(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<int>(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<int>(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<int>(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<int>(settingsController.{getter_call}()) << std::endl;
}}""".format(getter_ret=getter_ret, getter_call=getter_call, setting_name=setting_name)

return out

list_settings_function = """
#include <iostream>
#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())

0 comments on commit bba1758

Please sign in to comment.