This change cleans up the final bits before the release of SystemK version 1.00. It implements the [KTag Beacon Specification v0.12](https://ktag.clubk.club/Technology/BLE/KTag%20Beacon%20Specification%20v0.12.pdf). Co-authored-by: Joe Kearney <joe@clubk.club> Reviewed-on: #9
220 lines
6.1 KiB
Python
220 lines
6.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
SystemK settings code generator.
|
|
|
|
This program source code file is part of SystemK, a library in the KTag project.
|
|
|
|
🛡️ https://ktag.clubk.club
|
|
|
|
Copyright © 2025 Joseph P. Kearney and the KTag developers.
|
|
|
|
This program is free software: you can redistribute it and/or modify it under
|
|
the terms of the GNU Affero General Public License as published by the Free
|
|
Software Foundation, either version 3 of the License, or (at your option) any
|
|
later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
details.
|
|
|
|
A copy of the GNU Affero General Public License should be available in the
|
|
LICENSE file in the root of this repository. If not, see http://www.gnu.org/licenses/.
|
|
"""
|
|
|
|
import csv
|
|
from typing import List, Dict
|
|
|
|
|
|
def parse_csv(filename: str) -> List[Dict[str, str]]:
|
|
"""Parse the settings CSV file."""
|
|
settings = []
|
|
with open(filename, "r") as f:
|
|
reader = csv.DictReader(f)
|
|
for row in reader:
|
|
settings.append(row)
|
|
return settings
|
|
|
|
|
|
def generate_get_function(settings: List[Dict[str, str]], datatype: str) -> str:
|
|
"""Generate the SETTINGS_get function for a specific datatype."""
|
|
func_name = f"SETTINGS_get_{datatype}"
|
|
|
|
code = f"""SystemKResult_T {func_name}(SystemKSettingID_T id, {datatype} *value)
|
|
{{
|
|
SystemKResult_T result = SYSTEMK_RESULT_UNSPECIFIED_FAILURE;
|
|
|
|
switch (id)
|
|
{{
|
|
"""
|
|
|
|
for setting in settings:
|
|
if setting["Type"] != datatype:
|
|
continue
|
|
|
|
setting_id = setting["Setting ID"]
|
|
key = setting["Key"]
|
|
cache_var = f"Cached_{key}"
|
|
|
|
code += f""" case {setting_id}:
|
|
*value = {cache_var};
|
|
result = SYSTEMK_RESULT_SUCCESS;
|
|
break;
|
|
|
|
"""
|
|
|
|
code += """ default:
|
|
result = SYSTEMK_RESULT_WRONG_DATATYPE;
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
"""
|
|
return code
|
|
|
|
|
|
def generate_set_function(settings: List[Dict[str, str]], datatype: str) -> str:
|
|
"""Generate the SETTINGS_set function for a specific datatype."""
|
|
func_name = f"SETTINGS_set_{datatype}"
|
|
kv_func = f"KV_Set_Value_{datatype.replace('_t', '')}"
|
|
|
|
code = f"""SystemKResult_T {func_name}(SystemKSettingID_T id, {datatype} value)
|
|
{{
|
|
SystemKResult_T result = SYSTEMK_RESULT_SUCCESS;
|
|
|
|
switch (id)
|
|
{{
|
|
"""
|
|
|
|
for setting in settings:
|
|
if setting["Type"] != datatype:
|
|
continue
|
|
|
|
setting_id = setting["Setting ID"]
|
|
key = setting["Key"]
|
|
|
|
cache_var = f"Cached_{key}"
|
|
code += f""" case {setting_id}:
|
|
{cache_var} = value;
|
|
result = {kv_func}(CONFIG_FILE, "{key}", &value);
|
|
break;
|
|
|
|
"""
|
|
|
|
code += """ default:
|
|
result = SYSTEMK_RESULT_WRONG_DATATYPE;
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
"""
|
|
return code
|
|
|
|
|
|
def generate_initialize_function(settings: List[Dict[str, str]]) -> str:
|
|
"""Generate the Initialize_Settings function."""
|
|
code = """SystemKResult_T Initialize_Settings(void)
|
|
{
|
|
SystemKResult_T result = SYSTEMK_RESULT_SUCCESS;
|
|
SystemKResult_T temp_result;
|
|
"""
|
|
|
|
# Group settings by datatype.
|
|
datatypes = set(s["Type"] for s in settings)
|
|
|
|
for datatype in sorted(datatypes):
|
|
code += f" {datatype} value_{datatype};\n"
|
|
|
|
code += """
|
|
KLOG_INFO(TAG, "Initializing settings...");
|
|
|
|
"""
|
|
|
|
# Generate initialization code for each setting.
|
|
for setting in settings:
|
|
setting_id = setting["Setting ID"]
|
|
datatype = setting["Type"]
|
|
key = setting["Key"]
|
|
default_value = setting["Default Value"]
|
|
|
|
code += f""" // Initialize {key}
|
|
temp_result = KV_Get_Value_{datatype.replace('_t', '')}(CONFIG_FILE, "{key}", &value_{datatype});
|
|
if (temp_result != SYSTEMK_RESULT_SUCCESS)
|
|
{{
|
|
// Try to get from default config
|
|
temp_result = KV_Get_Value_{datatype.replace('_t', '')}(DEFAULT_CONFIG_FILE, "{key}", &value_{datatype});
|
|
if (temp_result != SYSTEMK_RESULT_SUCCESS)
|
|
{{
|
|
// Use hardcoded default
|
|
value_{datatype} = {default_value};
|
|
KLOG_WARN(TAG, "{key} not found in config files; using default value of {default_value}.");
|
|
}}
|
|
// Save to config file
|
|
temp_result = KV_Set_Value_{datatype.replace('_t', '')}(CONFIG_FILE, "{key}", &value_{datatype});
|
|
if (temp_result != SYSTEMK_RESULT_SUCCESS)
|
|
{{
|
|
result = temp_result;
|
|
KLOG_ERROR(TAG, "Failed to set {key} in config file.");
|
|
}}
|
|
}}
|
|
"""
|
|
|
|
# Initialize the cache variable
|
|
cache_var = f"Cached_{key}"
|
|
code += f" {cache_var} = value_{datatype};\n"
|
|
|
|
code += "\n"
|
|
|
|
code += """ xEventGroupSetBits(Get_System_Events(), SYS_SETTINGS_READY);
|
|
KLOG_INFO(TAG, "Settings initialized.");
|
|
|
|
return result;
|
|
}
|
|
"""
|
|
return code
|
|
|
|
|
|
def generate_cache_declarations(settings: List[Dict[str, str]]) -> str:
|
|
"""Generate static cache variable declarations initialized to defaults."""
|
|
code = ""
|
|
|
|
# Generate cache variable declarations for all settings
|
|
for setting in settings:
|
|
datatype = setting["Type"]
|
|
key = setting["Key"]
|
|
description = setting["Description"]
|
|
default_value = setting["Default Value"]
|
|
cache_var = f"Cached_{key}"
|
|
|
|
code += f"// {description}\n"
|
|
code += f"static {datatype} {cache_var} = {default_value};\n"
|
|
|
|
return code
|
|
|
|
|
|
def main():
|
|
"""Main function to generate all settings code."""
|
|
settings = parse_csv("Settings.csv")
|
|
|
|
# Get unique datatypes
|
|
datatypes = sorted(set(s["Type"] for s in settings))
|
|
|
|
print("// Cache variable declarations")
|
|
print(generate_cache_declarations(settings))
|
|
print()
|
|
|
|
# Generate get and set functions for each datatype
|
|
for datatype in datatypes:
|
|
print(generate_get_function(settings, datatype))
|
|
print()
|
|
print(generate_set_function(settings, datatype))
|
|
print()
|
|
|
|
# Generate initialize function
|
|
print(generate_initialize_function(settings))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|