From 852dd684ad7e52786e5d75b701a89116c52b7060 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Sun, 30 Nov 2025 14:25:54 -0600 Subject: [PATCH] Added Settings.csv. --- Settings/Settings.csv | 11 ++ Settings/generate_settings_code.py | 220 +++++++++++++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 Settings/Settings.csv create mode 100644 Settings/generate_settings_code.py diff --git a/Settings/Settings.csv b/Settings/Settings.csv new file mode 100644 index 0000000..3fbf3a6 --- /dev/null +++ b/Settings/Settings.csv @@ -0,0 +1,11 @@ +Setting ID,Type,Key,Default Value,Description +SYSTEMK_SETTING_IS_RIGHT_HANDED,uint8_t,"Is_Right_Handed",1,"1 if this device is configured for a right-handed player, 0 otherwise." +SYSTEMK_SETTING_AUDIO_VOLUME,uint8_t,"Audio_Volume",CONFIG_KTAG_MAX_AUDIO_VOLUME,"Value from CONFIG_KTAG_MIN_AUDIO_VOLUME to CONFIG_KTAG_MAX_AUDIO_VOLUME representing the current volume." +SYSTEMK_SETTING_TEAMID,uint8_t,"Team_ID",BASIC_TEAMS_MINIMUM,"Selected team." +SYSTEMK_SETTING_PLAYERID,uint8_t,"Player_ID",0,"Unique-per-team identification of a player." +SYSTEMK_SETTING_WEAPONID,uint8_t,"Weapon_ID",DUBUQUE_PROTOCOL_ID,"Selected weapon." +SYSTEMK_SETTING_MAX_HEALTH,uint8_t,"Max_Health",100,"Maximum health for the game." +SYSTEMK_SETTING_N_SPECIAL_WEAPONS_ON_REENTRY,uint8_t,"N_Special_Weapons_On_Reentry",1,"Number of special weapons (currently only bombs) obtained when reentering after being tagged out." +SYSTEMK_SETTING_T_START_GAME_in_ms,uint32_t,"T_Start_Game_in_ms",30000,"Time (in milliseconds) after starting a game before the countdown begins." +SYSTEMK_SETTING_T_GAME_LENGTH_in_ms,uint32_t,"T_Game_Length_in_ms",600000,"Duration of a game (in milliseconds). If this is zero or UINT32_MAX, the game is untimed." +SYSTEMK_SETTING_SECONDARY_COLOR,uint32_t,"Secondary_Color",0xFE000000,"Color in addition to the team color used to identify a player's device. The format is Brightness-Red-Green-Blue, where a brightness of 0xFF indicates a false flag." \ No newline at end of file diff --git a/Settings/generate_settings_code.py b/Settings/generate_settings_code.py new file mode 100644 index 0000000..f78e9a4 --- /dev/null +++ b/Settings/generate_settings_code.py @@ -0,0 +1,220 @@ +#!/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()