From 053bf174b7a286cb49a4a410fa7e3cc411bbf20e Mon Sep 17 00:00:00 2001 From: jdmarmen Date: Sun, 5 Jan 2025 23:25:06 +0100 Subject: [PATCH 1/7] Added template_sm file + python script for generating code --- Core/Inc/template_state_machine.hpp | 14 ++ state_machine_gen.py | 270 ++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+) create mode 100644 Core/Inc/template_state_machine.hpp create mode 100644 state_machine_gen.py diff --git a/Core/Inc/template_state_machine.hpp b/Core/Inc/template_state_machine.hpp new file mode 100644 index 00000000..49cd5513 --- /dev/null +++ b/Core/Inc/template_state_machine.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "ST-LIB.hpp" +using namespace std::chrono_literals; + +class GeneratedStateMachine{ + + public: + %FUNCTION_HEADERS% + %STATE_DEFINITION% + %TRANSITION_DEFINITION% + %ACTION_DEFINITION% + +}; + diff --git a/state_machine_gen.py b/state_machine_gen.py new file mode 100644 index 00000000..f68db9de --- /dev/null +++ b/state_machine_gen.py @@ -0,0 +1,270 @@ +import json + +######################################################## +# OPEN THE JSON FILE +######################################################## + +with open("state_machine.json","r") as file: + data=json.load(file) + +######################################################## +# ENUM + STATE MACHINE + STATES +######################################################## + +states=data["states"] + +enum_code = "enum GeneralStates {\n" +for state in states: + if isinstance(state,str): + enum_code += f" {state.upper()},\n" +enum_code +=" };\n\n" + +state_machine_code =" GeneratedStateMachine(){\n" +state_machine_code += f"\n StateMachine general_state_machine = StateMachine(GeneralStates::{states[0].upper()});\n" + +for i in range (1,len(states)): + if isinstance(states[i],str): + state_machine_code += f" general_state_machine.add_state(GeneralStates::{states[i].upper()});\n" + elif isinstance(states[i], dict): + nested_sm_name=states[i]["name"] + nested_sm_states=states[i]["sub-states"] + + enum_code += f" enum {nested_sm_name}" + enum_code += "{\n" + for state in nested_sm_states: + enum_code += f" {state.upper()},\n" + + enum_code +=" };\n\n" + + state_machine_code += f"\n StateMachine {nested_sm_name} = StateMachine({nested_sm_states[0].upper()});\n" + state_machine_code += f" general_state_machine.add_state_machine({nested_sm_name},{nested_sm_states[0].upper()});\n" + for j in range (1,len(nested_sm_states)): + state_machine_code += f" {nested_sm_name}.add_state({nested_sm_states[j].upper()});\n" + + +######################################################## +# TRANSITIONS +######################################################## + +transitions=data["transitions"] + +function_header_code="\n" +transitions_code="\n" +for transition in transitions: + old_state=transition["old_state"] + new_state=transition["new_state"] + transition_name=transition["transition_name"] + description=transition.get("description") + + if(isinstance(old_state,dict)): + if description: + transitions_code+=f" // {description}\n" + transitions_code+=f" general_state_machine.add_transition({old_state["name"]}::{old_state["sub-state"].upper()},GeneralStates::{new_state.upper()},{transition_name});\n" + function_header_code+=f" static bool {transition_name}();\n" + elif(isinstance(new_state,dict)): + if description: + transitions_code+=f" // {description}\n" + transitions_code+=f" general_state_machine.add_transition(GeneralStates::{old_state.upper()},{new_state["name"]}::{new_state["sub-state"].upper()},{transition_name});\n" + function_header_code+=f" static bool {transition_name}();\n" + elif(isinstance(old_state,dict) and isinstance(new_state,dict)): + if description: + transitions_code+=f" // {description}\n" + transitions_code+=f" general_state_machine.add_transition({old_state["name"]}::{old_state["sub-state"].upper()},GeneralStates::{new_state.upper()},{transition_name});\n" + function_header_code+=f" static bool {transition_name}();\n" + else: + if description: + transitions_code+=f" // {description}\n" + transitions_code+=f" general_state_machine.add_transition(GeneralStates::{old_state.upper()},GeneralStates::{new_state.upper()},{transition_name});\n" + function_header_code+=f" static bool {transition_name}();\n" + + + +######################################################## +# ACTIONS +######################################################## + +actions=data["actions"] + +enter_actions=actions["enter"] +low_precision_cyclic_actions=actions["cyclic"]["low_precision"] +mid_precision_cyclic_actions=actions["cyclic"]["mid_precision"] +high_precision_cyclic_actions=actions["cyclic"]["high_precision"] +exit_actions=actions["exit"] + +actions_code="\n" +function_header_code+="\n" + +# ENTER ACTIONS + +for enter_action in enter_actions: + state=enter_action["state"] + state_actions=enter_action["state_actions"] + + if(isinstance(state,dict)): + for state_action in state_actions: + if(isinstance(state_action,dict)): + actions_code+=f" // {state_action[description]}\n" + actions_code+=f" general_state_machine.add_enter_action({state_action["name"]},{state["name"]}::{state["sub-state"].upper()});\n" + function_header_code+=f" static void {state_action["name"]}();\n" + else: + actions_code+=f" general_state_machine.add_enter_action({state_action},{state["name"]}::{state["sub-state"].upper()});\n" + function_header_code+=f" static void {state_action}();\n" + else: + for state_action in state_actions: + if(isinstance(state_action,dict)): + actions_code+=f" // {state_action["description"]}\n" + actions_code+=f" general_state_machine.add_enter_action({state_action["name"]},GeneralStates::{state.upper()});\n" + function_header_code+=f" static void {state_action["name"]}();\n" + else: + actions_code+=f" general_state_machine.add_enter_action({state_action},GeneralStates::{state.upper()});\n" + function_header_code+=f" static void {state_action}();\n" + +actions_code+="\n" +function_header_code+="\n" + +# LOW PRECISION CYCLIC ACTIONS + +for low_precision_cyclic_action in low_precision_cyclic_actions : + states=low_precision_cyclic_action["states"] + state_actions=low_precision_cyclic_action["state_actions"] + description=low_precision_cyclic_action.get("description") + + + for state in states: + if(isinstance(state,dict)): + for state_action in state_actions: + description=state_action.get("description") + if(description): + actions_code+=f" // {description}\n" + actions_code+=f" general_state_machine.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + function_header_code+=f" static void {state_action["action_name"]}();\n" + else: + actions_code+=f" general_state_machine.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + function_header_code+=f" static void {state_action["action_name"]}();\n" + else: + for state_action in state_actions : + description=state_action.get("description") + if(description): + actions_code+=f" // {description}\n" + actions_code+=f" general_state_machine.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + function_header_code+=f" static void {state_action["action_name"]}();\n" + else: + actions_code+=f" general_state_machine.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + function_header_code+=f" static void {state_action["action_name"]}();\n" + +actions_code+="\n" +function_header_code+="\n" + +# MID PRECISION CYCLIC ACTIONS + +for mid_precision_cyclic_action in mid_precision_cyclic_actions: + states = mid_precision_cyclic_action["states"] + state_actions = mid_precision_cyclic_action["state_actions"] + description = mid_precision_cyclic_action.get("description") + + for state in states: + if(isinstance(state,dict)): + for state_action in state_actions: + description = state_action.get("description") + if(description): + actions_code += f" // {description}\n" + actions_code += f" general_state_machine.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + function_header_code += f" static void {state_action["action_name"]}();\n" + else: + actions_code += f" general_state_machine.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + function_header_code += f" static void {state_action["action_name"]}();\n" + else: + for state_action in state_actions: + description = state_action.get("description") + if(description): + actions_code += f" // {description}\n" + actions_code += f" general_state_machine.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + function_header_code += f" static void {state_action["action_name"]}();\n" + else: + actions_code += f" general_state_machine.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + function_header_code += f" static void {state_action["action_name"]}();\n" + +actions_code += "\n" +function_header_code += "\n" + +# HIGH PRECISION CYCLIC ACTIONS + +for high_precision_cyclic_action in high_precision_cyclic_actions: + states = high_precision_cyclic_action["states"] + state_actions = high_precision_cyclic_action["state_actions"] + description = high_precision_cyclic_action.get("description") + + for state in states: + if(isinstance(state,dict)): + for state_action in state_actions: + description = state_action.get("description") + if(description): + actions_code += f" // {description}\n" + actions_code += f" general_state_machine.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + function_header_code += f" static void {state_action["action_name"]}();\n" + else: + actions_code += f" general_state_machine.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + function_header_code += f" static void {state_action["action_name"]}();\n" + else: + for state_action in state_actions: + description = state_action.get("description") + if(description): + actions_code += f" // {description}\n" + actions_code += f" general_state_machine.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + function_header_code += f" static void {state_action["action_name"]}();\n" + else: + actions_code += f" general_state_machine.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + function_header_code += f" static void {state_action["action_name"]}();\n" + +actions_code += "\n" +function_header_code += "\n" + +# EXIT ACTIONS +for exit_action in exit_actions: + state = exit_action["state"] + state_actions = exit_action["state_actions"] + + if(isinstance(state, dict)): + for state_action in state_actions: + if(isinstance(state_action, dict)): + actions_code += f" // {state_action['description']}\n" + actions_code += f" general_state_machine.add_exit_action({state_action['name']},{state['name']}::{state['sub-state'].upper()});\n" + function_header_code += f" static void {state_action['name']}();\n" + else: + actions_code += f" general_state_machine.add_exit_action({state_action},{state['name']}::{state['sub-state'].upper()});\n" + function_header_code += f" static void {state_action}();\n" + else: + for state_action in state_actions: + if(isinstance(state_action, dict)): + actions_code += f" // {state_action['description']}\n" + actions_code += f" general_state_machine.add_exit_action({state_action['name']},GeneralStates::{state.upper()});\n" + function_header_code += f" static void {state_action['name']}();\n" + else: + actions_code += f" general_state_machine.add_exit_action({state_action},GeneralStates::{state.upper()});\n" + function_header_code += f" static void {state_action}();\n" + +actions_code += "\n" +function_header_code += "\n" + +actions_code += "\n }\n" +function_header_code+="\n" + + +######################################################## +# REPLACE THE TEMPLATE +######################################################## + +with open('Core/Inc/template_state_machine.hpp', "r") as template: + template_content = template.read() + +final_content=template_content.replace("%STATE_DEFINITION%", enum_code + state_machine_code) +final_content=final_content.replace("%TRANSITION_DEFINITION%",transitions_code) +final_content=final_content.replace("%ACTION_DEFINITION%",actions_code) +final_content=final_content.replace("%FUNCTION_HEADERS%",function_header_code) + +######################################################## +# REWRITE THE .HPP FILE +######################################################## + +with open('Core/Inc/state_machine.hpp', "w") as destination: + destination.write(final_content) \ No newline at end of file From 6e54422c712ff3d36d3d2e2b2708b494d71784e6 Mon Sep 17 00:00:00 2001 From: jdmarmen Date: Sun, 5 Jan 2025 23:27:07 +0100 Subject: [PATCH 2/7] Added warning comment --- Core/Inc/template_state_machine.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/Inc/template_state_machine.hpp b/Core/Inc/template_state_machine.hpp index 49cd5513..20ab73b6 100644 --- a/Core/Inc/template_state_machine.hpp +++ b/Core/Inc/template_state_machine.hpp @@ -2,6 +2,8 @@ #include "ST-LIB.hpp" using namespace std::chrono_literals; +// AUTOGENERATED CODE, DO NOT EDIT MANUALLY + class GeneratedStateMachine{ public: From 759c7d2bb40f6e0c7370b5134e22f62b3c506485 Mon Sep 17 00:00:00 2001 From: jdmarmen Date: Sun, 5 Jan 2025 23:52:55 +0100 Subject: [PATCH 3/7] Added template json with examples + small fix --- Core/Inc/template_state_machine.hpp | 8 +- state_machine.json | 122 ++++++++++++++++++++++++++++ state_machine_gen.py | 8 +- 3 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 state_machine.json diff --git a/Core/Inc/template_state_machine.hpp b/Core/Inc/template_state_machine.hpp index 20ab73b6..3db41a3f 100644 --- a/Core/Inc/template_state_machine.hpp +++ b/Core/Inc/template_state_machine.hpp @@ -7,10 +7,10 @@ using namespace std::chrono_literals; class GeneratedStateMachine{ public: - %FUNCTION_HEADERS% - %STATE_DEFINITION% - %TRANSITION_DEFINITION% - %ACTION_DEFINITION% + //%FUNCTION_HEADERS% + //%STATE_DEFINITION% + //%TRANSITION_DEFINITION% + //%ACTION_DEFINITION% }; diff --git a/state_machine.json b/state_machine.json new file mode 100644 index 00000000..931ab4b3 --- /dev/null +++ b/state_machine.json @@ -0,0 +1,122 @@ +{ + "states" : [ + "name_1", + { + "name" : "Nested_sm", + "sub-states":[ + "nested_name_1", + "nested_name_2" + ] + }, + "name_2" + + ], + + "transitions" : [ + { + "old_state" : "name_1", + "new_state" : "name_2", + "transition_name": "from_1_to_2" + }, + { + "old_state" : "name_1", + "new_state" : "name_2", + "transition_name": "from_1_to_2", + "description" : "Transitioning from 1 to 2" + }, + { + "old_state" : "name_1", + "new_state" : { + "name" : "Nested_sm", + "sub-state" : "nested_name_1" + }, + "transition_name": "from_1_to_nested_1" + } + + + ], + + "actions" : { + "enter" : [ + { + "state" : "name_1", + "state_actions" : [ + "enter_action_1", + "enter_action_2" + ] + }, + { + "state" : "name_2", + "state_actions" : [ + { + "name" : "enter_action_3", + "description" : "Description of enter_action_3" + }, + "enter_action_4" + ] + } + ], + + "cyclic" : { + "low_precision" : [ + { + "states" : [ + "name_1", + "name_2" + ], + "state_actions" : [ + { + "action_name" : "low_precision_action", + "action_period" : "30ms" + } + ] + } + ], + "mid_precision" : [ + { + "states" : [ + "name_1", + { + "name" : "Nested_sm", + "sub-state" : "nested_name_1" + } + ], + "state_actions" : [ + { + "action_name" : "mid_precision_action_to_nested_state", + "action_period" : "60ms" + } + ] + } + ], + "high_precision" : [ + { + "states" : [ + "name_1", + "name_2" + ], + "state_actions" : [ + { + "action_name" : "high_precision_action_with_description", + "action_period" : "90ms", + "description" : "Cyclic action example with description" + } + ] + } + ] + }, + + "exit" : [ + { + "state" : { + "name" : "Nested_sm", + "sub-state" : "nested_name_2" + }, + "state_actions" : [ + "exit_action_1", + "exit_action_2" + ] + } + ] + } +} \ No newline at end of file diff --git a/state_machine_gen.py b/state_machine_gen.py index f68db9de..362abaee 100644 --- a/state_machine_gen.py +++ b/state_machine_gen.py @@ -257,10 +257,10 @@ with open('Core/Inc/template_state_machine.hpp', "r") as template: template_content = template.read() -final_content=template_content.replace("%STATE_DEFINITION%", enum_code + state_machine_code) -final_content=final_content.replace("%TRANSITION_DEFINITION%",transitions_code) -final_content=final_content.replace("%ACTION_DEFINITION%",actions_code) -final_content=final_content.replace("%FUNCTION_HEADERS%",function_header_code) +final_content=template_content.replace("//%STATE_DEFINITION%", enum_code + state_machine_code) +final_content=final_content.replace("//%TRANSITION_DEFINITION%",transitions_code) +final_content=final_content.replace("//%ACTION_DEFINITION%",actions_code) +final_content=final_content.replace("//%FUNCTION_HEADERS%",function_header_code) ######################################################## # REWRITE THE .HPP FILE From b6300c244540b045ea3a6877299bbdbea8be7c44 Mon Sep 17 00:00:00 2001 From: jdmarmen Date: Tue, 7 Jan 2025 01:45:08 +0100 Subject: [PATCH 4/7] Added the code generated with the examples on state_machine.json --- Core/Inc/state_machine.hpp | 84 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 Core/Inc/state_machine.hpp diff --git a/Core/Inc/state_machine.hpp b/Core/Inc/state_machine.hpp new file mode 100644 index 00000000..4e42aa5f --- /dev/null +++ b/Core/Inc/state_machine.hpp @@ -0,0 +1,84 @@ +#pragma once +#include "ST-LIB.hpp" +using namespace std::chrono_literals; + +// AUTOGENERATED CODE, DO NOT EDIT MANUALLY + +class GeneratedStateMachine{ + + public: + + static bool from_1_to_2(); + static bool from_1_to_2(); + static bool from_1_to_nested_1(); + + static void enter_action_1(); + static void enter_action_2(); + static void enter_action_3(); + static void enter_action_4(); + + static void low_precision_action(); + static void low_precision_action(); + + static void mid_precision_action_to_nested_state(); + static void mid_precision_action_to_nested_state(); + + static void high_precision_action_with_description(); + static void high_precision_action_with_description(); + + static void exit_action_1(); + static void exit_action_2(); + + + + enum GeneralStates { + NAME_1, + NAME_2, + }; + + enum Nested_sm{ + NESTED_NAME_1, + NESTED_NAME_2, + }; + + GeneratedStateMachine(){ + + StateMachine general_state_machine = StateMachine(GeneralStates::NAME_1); + + StateMachine Nested_sm = StateMachine(NESTED_NAME_1); + general_state_machine.add_state_machine(Nested_sm,NESTED_NAME_1); + Nested_sm.add_state(NESTED_NAME_2); + general_state_machine.add_state(GeneralStates::NAME_2); + + + general_state_machine.add_transition(GeneralStates::NAME_1,GeneralStates::NAME_2,from_1_to_2); + // Transitioning from 1 to 2 + general_state_machine.add_transition(GeneralStates::NAME_1,GeneralStates::NAME_2,from_1_to_2); + + + general_state_machine.add_enter_action(enter_action_1,GeneralStates::NAME_1); + general_state_machine.add_enter_action(enter_action_2,GeneralStates::NAME_1); + // Description of enter_action_3 + general_state_machine.add_enter_action(enter_action_3,GeneralStates::NAME_2); + general_state_machine.add_enter_action(enter_action_4,GeneralStates::NAME_2); + + general_state_machine.add_low_precision_cyclic_action(low_precision_action,30ms,GeneralStates::NAME_1); + general_state_machine.add_low_precision_cyclic_action(low_precision_action,30ms,GeneralStates::NAME_2); + + general_state_machine.add_mid_precision_cyclic_action(mid_precision_action_to_nested_state,60ms,GeneralStates::NAME_1); + general_state_machine.add_mid_precision_cyclic_action(mid_precision_action_to_nested_state,60ms,Nested_sm::NESTED_NAME_1); + + // Cyclic action example with description + general_state_machine.add_high_precision_cyclic_action(high_precision_action_with_description,90ms,GeneralStates::NAME_1); + // Cyclic action example with description + general_state_machine.add_high_precision_cyclic_action(high_precision_action_with_description,90ms,GeneralStates::NAME_2); + + general_state_machine.add_exit_action(exit_action_1,Nested_sm::NESTED_NAME_2); + general_state_machine.add_exit_action(exit_action_2,Nested_sm::NESTED_NAME_2); + + + } + + +}; + From e5a62130ea87f740d32c3f2de2989a06d0b4ad4b Mon Sep 17 00:00:00 2001 From: jdmarmen Date: Tue, 7 Jan 2025 20:18:21 +0100 Subject: [PATCH 5/7] Added to the json a field for customizing the class name --- Core/Inc/state_machine.hpp | 40 ++++++++++++------------ state_machine.json | 2 ++ state_machine_gen.py | 63 ++++++++++++++++++++------------------ 3 files changed, 56 insertions(+), 49 deletions(-) diff --git a/Core/Inc/state_machine.hpp b/Core/Inc/state_machine.hpp index 4e42aa5f..7b7e010d 100644 --- a/Core/Inc/state_machine.hpp +++ b/Core/Inc/state_machine.hpp @@ -4,7 +4,7 @@ using namespace std::chrono_literals; // AUTOGENERATED CODE, DO NOT EDIT MANUALLY -class GeneratedStateMachine{ +class ExampleStateMachine{ public: @@ -31,7 +31,7 @@ class GeneratedStateMachine{ - enum GeneralStates { + enum ExampleStateMachineStates { NAME_1, NAME_2, }; @@ -41,40 +41,40 @@ class GeneratedStateMachine{ NESTED_NAME_2, }; - GeneratedStateMachine(){ + ExampleStateMachine(){ - StateMachine general_state_machine = StateMachine(GeneralStates::NAME_1); + StateMachine ExampleStateMachine = StateMachine(ExampleStateMachineStates::NAME_1); StateMachine Nested_sm = StateMachine(NESTED_NAME_1); - general_state_machine.add_state_machine(Nested_sm,NESTED_NAME_1); + ExampleStateMachine.add_state_machine(Nested_sm,NESTED_NAME_1); Nested_sm.add_state(NESTED_NAME_2); - general_state_machine.add_state(GeneralStates::NAME_2); + ExampleStateMachine.add_state(ExampleStateMachineStates::NAME_2); - general_state_machine.add_transition(GeneralStates::NAME_1,GeneralStates::NAME_2,from_1_to_2); + ExampleStateMachine.add_transition(ExampleStateMachineStates::NAME_1,ExampleStateMachineStates::NAME_2,from_1_to_2); // Transitioning from 1 to 2 - general_state_machine.add_transition(GeneralStates::NAME_1,GeneralStates::NAME_2,from_1_to_2); + ExampleStateMachine.add_transition(ExampleStateMachineStates::NAME_1,ExampleStateMachineStates::NAME_2,from_1_to_2); - general_state_machine.add_enter_action(enter_action_1,GeneralStates::NAME_1); - general_state_machine.add_enter_action(enter_action_2,GeneralStates::NAME_1); + ExampleStateMachine.add_enter_action(enter_action_1,ExampleStateMachineStates::NAME_1); + ExampleStateMachine.add_enter_action(enter_action_2,ExampleStateMachineStates::NAME_1); // Description of enter_action_3 - general_state_machine.add_enter_action(enter_action_3,GeneralStates::NAME_2); - general_state_machine.add_enter_action(enter_action_4,GeneralStates::NAME_2); + ExampleStateMachine.add_enter_action(enter_action_3,ExampleStateMachineStates::NAME_2); + ExampleStateMachine.add_enter_action(enter_action_4,ExampleStateMachineStates::NAME_2); - general_state_machine.add_low_precision_cyclic_action(low_precision_action,30ms,GeneralStates::NAME_1); - general_state_machine.add_low_precision_cyclic_action(low_precision_action,30ms,GeneralStates::NAME_2); + ExampleStateMachine.add_low_precision_cyclic_action(low_precision_action,30ms,ExampleStateMachineStates::NAME_1); + ExampleStateMachine.add_low_precision_cyclic_action(low_precision_action,30ms,ExampleStateMachineStates::NAME_2); - general_state_machine.add_mid_precision_cyclic_action(mid_precision_action_to_nested_state,60ms,GeneralStates::NAME_1); - general_state_machine.add_mid_precision_cyclic_action(mid_precision_action_to_nested_state,60ms,Nested_sm::NESTED_NAME_1); + ExampleStateMachine.add_mid_precision_cyclic_action(mid_precision_action_to_nested_state,60ms,ExampleStateMachineStates::NAME_1); + ExampleStateMachine.add_mid_precision_cyclic_action(mid_precision_action_to_nested_state,60ms,Nested_sm::NESTED_NAME_1); // Cyclic action example with description - general_state_machine.add_high_precision_cyclic_action(high_precision_action_with_description,90ms,GeneralStates::NAME_1); + ExampleStateMachine.add_high_precision_cyclic_action(high_precision_action_with_description,90ms,ExampleStateMachineStates::NAME_1); // Cyclic action example with description - general_state_machine.add_high_precision_cyclic_action(high_precision_action_with_description,90ms,GeneralStates::NAME_2); + ExampleStateMachine.add_high_precision_cyclic_action(high_precision_action_with_description,90ms,ExampleStateMachineStates::NAME_2); - general_state_machine.add_exit_action(exit_action_1,Nested_sm::NESTED_NAME_2); - general_state_machine.add_exit_action(exit_action_2,Nested_sm::NESTED_NAME_2); + ExampleStateMachine.add_exit_action(exit_action_1,Nested_sm::NESTED_NAME_2); + ExampleStateMachine.add_exit_action(exit_action_2,Nested_sm::NESTED_NAME_2); } diff --git a/state_machine.json b/state_machine.json index 931ab4b3..843171a5 100644 --- a/state_machine.json +++ b/state_machine.json @@ -1,4 +1,6 @@ { + "name" : "ExampleStateMachine", + "states" : [ "name_1", { diff --git a/state_machine_gen.py b/state_machine_gen.py index 362abaee..d7d46faa 100644 --- a/state_machine_gen.py +++ b/state_machine_gen.py @@ -11,20 +11,24 @@ # ENUM + STATE MACHINE + STATES ######################################################## +name=data["name"] states=data["states"] -enum_code = "enum GeneralStates {\n" +enum_code = f"enum {name}States" +enum_code+=" {\n" + for state in states: if isinstance(state,str): enum_code += f" {state.upper()},\n" enum_code +=" };\n\n" -state_machine_code =" GeneratedStateMachine(){\n" -state_machine_code += f"\n StateMachine general_state_machine = StateMachine(GeneralStates::{states[0].upper()});\n" +state_machine_code =f" {name}()" +state_machine_code+="{\n" +state_machine_code += f"\n StateMachine {name} = StateMachine({name}States::{states[0].upper()});\n" for i in range (1,len(states)): if isinstance(states[i],str): - state_machine_code += f" general_state_machine.add_state(GeneralStates::{states[i].upper()});\n" + state_machine_code += f" {name}.add_state({name}States::{states[i].upper()});\n" elif isinstance(states[i], dict): nested_sm_name=states[i]["name"] nested_sm_states=states[i]["sub-states"] @@ -37,7 +41,7 @@ enum_code +=" };\n\n" state_machine_code += f"\n StateMachine {nested_sm_name} = StateMachine({nested_sm_states[0].upper()});\n" - state_machine_code += f" general_state_machine.add_state_machine({nested_sm_name},{nested_sm_states[0].upper()});\n" + state_machine_code += f" {name}.add_state_machine({nested_sm_name},{nested_sm_states[0].upper()});\n" for j in range (1,len(nested_sm_states)): state_machine_code += f" {nested_sm_name}.add_state({nested_sm_states[j].upper()});\n" @@ -59,22 +63,22 @@ if(isinstance(old_state,dict)): if description: transitions_code+=f" // {description}\n" - transitions_code+=f" general_state_machine.add_transition({old_state["name"]}::{old_state["sub-state"].upper()},GeneralStates::{new_state.upper()},{transition_name});\n" + transitions_code+=f" {name}.add_transition({old_state["name"]}::{old_state["sub-state"].upper()},{name}States::{new_state.upper()},{transition_name});\n" function_header_code+=f" static bool {transition_name}();\n" elif(isinstance(new_state,dict)): if description: transitions_code+=f" // {description}\n" - transitions_code+=f" general_state_machine.add_transition(GeneralStates::{old_state.upper()},{new_state["name"]}::{new_state["sub-state"].upper()},{transition_name});\n" + transitions_code+=f" {name}.add_transition({name}States::{old_state.upper()},{new_state["name"]}::{new_state["sub-state"].upper()},{transition_name});\n" function_header_code+=f" static bool {transition_name}();\n" elif(isinstance(old_state,dict) and isinstance(new_state,dict)): if description: transitions_code+=f" // {description}\n" - transitions_code+=f" general_state_machine.add_transition({old_state["name"]}::{old_state["sub-state"].upper()},GeneralStates::{new_state.upper()},{transition_name});\n" + transitions_code+=f" {name}.add_transition({old_state["name"]}::{old_state["sub-state"].upper()},{name}States::{new_state.upper()},{transition_name});\n" function_header_code+=f" static bool {transition_name}();\n" else: if description: transitions_code+=f" // {description}\n" - transitions_code+=f" general_state_machine.add_transition(GeneralStates::{old_state.upper()},GeneralStates::{new_state.upper()},{transition_name});\n" + transitions_code+=f" {name}.add_transition({name}States::{old_state.upper()},{name}States::{new_state.upper()},{transition_name});\n" function_header_code+=f" static bool {transition_name}();\n" @@ -104,19 +108,19 @@ for state_action in state_actions: if(isinstance(state_action,dict)): actions_code+=f" // {state_action[description]}\n" - actions_code+=f" general_state_machine.add_enter_action({state_action["name"]},{state["name"]}::{state["sub-state"].upper()});\n" + actions_code+=f" {name}.add_enter_action({state_action["name"]},{state["name"]}::{state["sub-state"].upper()});\n" function_header_code+=f" static void {state_action["name"]}();\n" else: - actions_code+=f" general_state_machine.add_enter_action({state_action},{state["name"]}::{state["sub-state"].upper()});\n" + actions_code+=f" {name}.add_enter_action({state_action},{state["name"]}::{state["sub-state"].upper()});\n" function_header_code+=f" static void {state_action}();\n" else: for state_action in state_actions: if(isinstance(state_action,dict)): actions_code+=f" // {state_action["description"]}\n" - actions_code+=f" general_state_machine.add_enter_action({state_action["name"]},GeneralStates::{state.upper()});\n" + actions_code+=f" {name}.add_enter_action({state_action["name"]},{name}States::{state.upper()});\n" function_header_code+=f" static void {state_action["name"]}();\n" else: - actions_code+=f" general_state_machine.add_enter_action({state_action},GeneralStates::{state.upper()});\n" + actions_code+=f" {name}.add_enter_action({state_action},{name}States::{state.upper()});\n" function_header_code+=f" static void {state_action}();\n" actions_code+="\n" @@ -136,20 +140,20 @@ description=state_action.get("description") if(description): actions_code+=f" // {description}\n" - actions_code+=f" general_state_machine.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + actions_code+=f" {name}.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" function_header_code+=f" static void {state_action["action_name"]}();\n" else: - actions_code+=f" general_state_machine.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + actions_code+=f" {name}.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" function_header_code+=f" static void {state_action["action_name"]}();\n" else: for state_action in state_actions : description=state_action.get("description") if(description): actions_code+=f" // {description}\n" - actions_code+=f" general_state_machine.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + actions_code+=f" {name}.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" function_header_code+=f" static void {state_action["action_name"]}();\n" else: - actions_code+=f" general_state_machine.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + actions_code+=f" {name}.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" function_header_code+=f" static void {state_action["action_name"]}();\n" actions_code+="\n" @@ -168,20 +172,20 @@ description = state_action.get("description") if(description): actions_code += f" // {description}\n" - actions_code += f" general_state_machine.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + actions_code += f" {name}.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" function_header_code += f" static void {state_action["action_name"]}();\n" else: - actions_code += f" general_state_machine.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + actions_code += f" {name}.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" function_header_code += f" static void {state_action["action_name"]}();\n" else: for state_action in state_actions: description = state_action.get("description") if(description): actions_code += f" // {description}\n" - actions_code += f" general_state_machine.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + actions_code += f" {name}.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" function_header_code += f" static void {state_action["action_name"]}();\n" else: - actions_code += f" general_state_machine.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + actions_code += f" {name}.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" function_header_code += f" static void {state_action["action_name"]}();\n" actions_code += "\n" @@ -200,20 +204,20 @@ description = state_action.get("description") if(description): actions_code += f" // {description}\n" - actions_code += f" general_state_machine.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + actions_code += f" {name}.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" function_header_code += f" static void {state_action["action_name"]}();\n" else: - actions_code += f" general_state_machine.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" + actions_code += f" {name}.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" function_header_code += f" static void {state_action["action_name"]}();\n" else: for state_action in state_actions: description = state_action.get("description") if(description): actions_code += f" // {description}\n" - actions_code += f" general_state_machine.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + actions_code += f" {name}.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" function_header_code += f" static void {state_action["action_name"]}();\n" else: - actions_code += f" general_state_machine.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},GeneralStates::{state.upper()});\n" + actions_code += f" {name}.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" function_header_code += f" static void {state_action["action_name"]}();\n" actions_code += "\n" @@ -228,19 +232,19 @@ for state_action in state_actions: if(isinstance(state_action, dict)): actions_code += f" // {state_action['description']}\n" - actions_code += f" general_state_machine.add_exit_action({state_action['name']},{state['name']}::{state['sub-state'].upper()});\n" + actions_code += f" {name}.add_exit_action({state_action['name']},{state['name']}::{state['sub-state'].upper()});\n" function_header_code += f" static void {state_action['name']}();\n" else: - actions_code += f" general_state_machine.add_exit_action({state_action},{state['name']}::{state['sub-state'].upper()});\n" + actions_code += f" {name}.add_exit_action({state_action},{state['name']}::{state['sub-state'].upper()});\n" function_header_code += f" static void {state_action}();\n" else: for state_action in state_actions: if(isinstance(state_action, dict)): actions_code += f" // {state_action['description']}\n" - actions_code += f" general_state_machine.add_exit_action({state_action['name']},GeneralStates::{state.upper()});\n" + actions_code += f" {name}.add_exit_action({state_action['name']},{name}States::{state.upper()});\n" function_header_code += f" static void {state_action['name']}();\n" else: - actions_code += f" general_state_machine.add_exit_action({state_action},GeneralStates::{state.upper()});\n" + actions_code += f" {name}.add_exit_action({state_action},{name}States::{state.upper()});\n" function_header_code += f" static void {state_action}();\n" actions_code += "\n" @@ -261,6 +265,7 @@ final_content=final_content.replace("//%TRANSITION_DEFINITION%",transitions_code) final_content=final_content.replace("//%ACTION_DEFINITION%",actions_code) final_content=final_content.replace("//%FUNCTION_HEADERS%",function_header_code) +final_content=final_content.replace("GeneratedStateMachine",name) ######################################################## # REWRITE THE .HPP FILE From 987128c47c1d5b64b3f39e58ff315170ba173125 Mon Sep 17 00:00:00 2001 From: jdmarmen Date: Thu, 16 Jan 2025 19:40:28 +0100 Subject: [PATCH 6/7] "Adressed requested changes" --- Core/Inc/state_machine.hpp | 26 +- Core/Inc/template_state_machine.hpp | 16 -- state_machine.json | 14 +- state_machine_gen.py | 372 ++++++++------------------- state_machine_object_descriptions.py | 196 ++++++++++++++ 5 files changed, 310 insertions(+), 314 deletions(-) delete mode 100644 Core/Inc/template_state_machine.hpp create mode 100644 state_machine_object_descriptions.py diff --git a/Core/Inc/state_machine.hpp b/Core/Inc/state_machine.hpp index 7b7e010d..9f686a89 100644 --- a/Core/Inc/state_machine.hpp +++ b/Core/Inc/state_machine.hpp @@ -7,7 +7,7 @@ using namespace std::chrono_literals; class ExampleStateMachine{ public: - + static bool from_1_to_2(); static bool from_1_to_2(); static bool from_1_to_nested_1(); @@ -16,21 +16,16 @@ class ExampleStateMachine{ static void enter_action_2(); static void enter_action_3(); static void enter_action_4(); - static void low_precision_action(); static void low_precision_action(); - static void mid_precision_action_to_nested_state(); static void mid_precision_action_to_nested_state(); - static void high_precision_action_with_description(); static void high_precision_action_with_description(); - static void exit_action_1(); static void exit_action_2(); - enum ExampleStateMachineStates { NAME_1, NAME_2, @@ -45,40 +40,33 @@ class ExampleStateMachine{ StateMachine ExampleStateMachine = StateMachine(ExampleStateMachineStates::NAME_1); - StateMachine Nested_sm = StateMachine(NESTED_NAME_1); - ExampleStateMachine.add_state_machine(Nested_sm,NESTED_NAME_1); - Nested_sm.add_state(NESTED_NAME_2); + StateMachine Nested_sm = StateMachine(Nested_sm::NESTED_NAME_1); + ExampleStateMachine.add_state_machine(Nested_sm,Nested_sm::NESTED_NAME_1); + Nested_sm.add_state(Nested_sm::NESTED_NAME_2); + ExampleStateMachine.add_state(ExampleStateMachineStates::NAME_2); - ExampleStateMachine.add_transition(ExampleStateMachineStates::NAME_1,ExampleStateMachineStates::NAME_2,from_1_to_2); // Transitioning from 1 to 2 ExampleStateMachine.add_transition(ExampleStateMachineStates::NAME_1,ExampleStateMachineStates::NAME_2,from_1_to_2); + ExampleStateMachine.add_transition(ExampleStateMachineStates::NAME_1,Nested_sm::NESTED_NAME_1,from_1_to_nested_1); - ExampleStateMachine.add_enter_action(enter_action_1,ExampleStateMachineStates::NAME_1); ExampleStateMachine.add_enter_action(enter_action_2,ExampleStateMachineStates::NAME_1); // Description of enter_action_3 ExampleStateMachine.add_enter_action(enter_action_3,ExampleStateMachineStates::NAME_2); ExampleStateMachine.add_enter_action(enter_action_4,ExampleStateMachineStates::NAME_2); - ExampleStateMachine.add_low_precision_cyclic_action(low_precision_action,30ms,ExampleStateMachineStates::NAME_1); ExampleStateMachine.add_low_precision_cyclic_action(low_precision_action,30ms,ExampleStateMachineStates::NAME_2); - ExampleStateMachine.add_mid_precision_cyclic_action(mid_precision_action_to_nested_state,60ms,ExampleStateMachineStates::NAME_1); ExampleStateMachine.add_mid_precision_cyclic_action(mid_precision_action_to_nested_state,60ms,Nested_sm::NESTED_NAME_1); - // Cyclic action example with description ExampleStateMachine.add_high_precision_cyclic_action(high_precision_action_with_description,90ms,ExampleStateMachineStates::NAME_1); // Cyclic action example with description ExampleStateMachine.add_high_precision_cyclic_action(high_precision_action_with_description,90ms,ExampleStateMachineStates::NAME_2); - ExampleStateMachine.add_exit_action(exit_action_1,Nested_sm::NESTED_NAME_2); ExampleStateMachine.add_exit_action(exit_action_2,Nested_sm::NESTED_NAME_2); - } - -}; - +}; \ No newline at end of file diff --git a/Core/Inc/template_state_machine.hpp b/Core/Inc/template_state_machine.hpp deleted file mode 100644 index 3db41a3f..00000000 --- a/Core/Inc/template_state_machine.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "ST-LIB.hpp" -using namespace std::chrono_literals; - -// AUTOGENERATED CODE, DO NOT EDIT MANUALLY - -class GeneratedStateMachine{ - - public: - //%FUNCTION_HEADERS% - //%STATE_DEFINITION% - //%TRANSITION_DEFINITION% - //%ACTION_DEFINITION% - -}; - diff --git a/state_machine.json b/state_machine.json index 843171a5..0393c577 100644 --- a/state_machine.json +++ b/state_machine.json @@ -16,26 +16,24 @@ "transitions" : [ { - "old_state" : "name_1", - "new_state" : "name_2", + "from_state" : "name_1", + "to_state" : "name_2", "transition_name": "from_1_to_2" }, { - "old_state" : "name_1", - "new_state" : "name_2", + "from_state" : "name_1", + "to_state" : "name_2", "transition_name": "from_1_to_2", "description" : "Transitioning from 1 to 2" }, { - "old_state" : "name_1", - "new_state" : { + "from_state" : "name_1", + "to_state" : { "name" : "Nested_sm", "sub-state" : "nested_name_1" }, "transition_name": "from_1_to_nested_1" } - - ], "actions" : { diff --git a/state_machine_gen.py b/state_machine_gen.py index d7d46faa..414f1e2e 100644 --- a/state_machine_gen.py +++ b/state_machine_gen.py @@ -1,275 +1,105 @@ import json +from state_machine_object_descriptions import* -######################################################## -# OPEN THE JSON FILE -######################################################## - -with open("state_machine.json","r") as file: - data=json.load(file) - -######################################################## -# ENUM + STATE MACHINE + STATES -######################################################## - -name=data["name"] -states=data["states"] - -enum_code = f"enum {name}States" -enum_code+=" {\n" - -for state in states: - if isinstance(state,str): - enum_code += f" {state.upper()},\n" -enum_code +=" };\n\n" - -state_machine_code =f" {name}()" -state_machine_code+="{\n" -state_machine_code += f"\n StateMachine {name} = StateMachine({name}States::{states[0].upper()});\n" - -for i in range (1,len(states)): - if isinstance(states[i],str): - state_machine_code += f" {name}.add_state({name}States::{states[i].upper()});\n" - elif isinstance(states[i], dict): - nested_sm_name=states[i]["name"] - nested_sm_states=states[i]["sub-states"] - - enum_code += f" enum {nested_sm_name}" - enum_code += "{\n" - for state in nested_sm_states: - enum_code += f" {state.upper()},\n" - - enum_code +=" };\n\n" - - state_machine_code += f"\n StateMachine {nested_sm_name} = StateMachine({nested_sm_states[0].upper()});\n" - state_machine_code += f" {name}.add_state_machine({nested_sm_name},{nested_sm_states[0].upper()});\n" - for j in range (1,len(nested_sm_states)): - state_machine_code += f" {nested_sm_name}.add_state({nested_sm_states[j].upper()});\n" - - -######################################################## -# TRANSITIONS -######################################################## - -transitions=data["transitions"] - -function_header_code="\n" -transitions_code="\n" -for transition in transitions: - old_state=transition["old_state"] - new_state=transition["new_state"] - transition_name=transition["transition_name"] - description=transition.get("description") - - if(isinstance(old_state,dict)): - if description: - transitions_code+=f" // {description}\n" - transitions_code+=f" {name}.add_transition({old_state["name"]}::{old_state["sub-state"].upper()},{name}States::{new_state.upper()},{transition_name});\n" - function_header_code+=f" static bool {transition_name}();\n" - elif(isinstance(new_state,dict)): - if description: - transitions_code+=f" // {description}\n" - transitions_code+=f" {name}.add_transition({name}States::{old_state.upper()},{new_state["name"]}::{new_state["sub-state"].upper()},{transition_name});\n" - function_header_code+=f" static bool {transition_name}();\n" - elif(isinstance(old_state,dict) and isinstance(new_state,dict)): - if description: - transitions_code+=f" // {description}\n" - transitions_code+=f" {name}.add_transition({old_state["name"]}::{old_state["sub-state"].upper()},{name}States::{new_state.upper()},{transition_name});\n" - function_header_code+=f" static bool {transition_name}();\n" - else: - if description: - transitions_code+=f" // {description}\n" - transitions_code+=f" {name}.add_transition({name}States::{old_state.upper()},{name}States::{new_state.upper()},{transition_name});\n" - function_header_code+=f" static bool {transition_name}();\n" +def generate_code(state_machine): + content = [] + content.extend([ + "#pragma once", + '#include "ST-LIB.hpp"', + "using namespace std::chrono_literals;", + "", + "// AUTOGENERATED CODE, DO NOT EDIT MANUALLY", + "", + f"class {state_machine.name}{{", + "", + " public:", + "" + ]) + + for t in state_machine.transitions: + content.append(f" static bool {t.name}();") + content.append("") + + for action in state_machine.actions: + for sa in action.state_actions: + content.append(f" static void {sa.name}();") + content.append("\n") + + content.append(f" enum {state_machine.name}States {{") + for state in state_machine.states: + if isinstance(state, State): + content.append(f" {state.name.upper()},") + content.append(" };") + content.append("") + + for nested_sm in state_machine.nested_state_machines: + content.append(f" enum {nested_sm.name}{{") + for state in nested_sm.states: + content.append(f" {state.name.upper()},") + content.append(" };") + content.append("") + + content.append(f" {state_machine.name}(){{") + content.append("") + + if state_machine.states: + first_state = state_machine.states[0] + content.append(f" StateMachine {state_machine.name} = StateMachine({state_machine.name}States::{first_state.name.upper()});") + content.append("") + + for nested_sm in state_machine.nested_state_machines: + if nested_sm.states: + first_nested = nested_sm.states[0] + content.extend([ + f" StateMachine {nested_sm.name} = StateMachine({nested_sm.name}::{first_nested.name.upper()});", + f" {state_machine.name}.add_state_machine({nested_sm.name},{nested_sm.name}::{first_nested.name.upper()});", + ]) + for state in nested_sm.states[1:]: + content.append(f" {nested_sm.name}.add_state({nested_sm.name}::{state.name.upper()});") + content.append("") + + for state in state_machine.states[1:]: + if isinstance(state, State): + content.append(f" {state_machine.name}.add_state({state_machine.name}States::{state.name.upper()});") + content.append("") + + for t in state_machine.transitions: + if t.comment: + content.append(f" // {t.comment}") + from_state = get_state_reference(t.from_state, state_machine.name) + to_state = get_state_reference(t.to_state, state_machine.name) + content.append(f" {state_machine.name}.add_transition({from_state},{to_state},{t.name});") + content.append("") + + for action in state_machine.actions: + for sa in action.state_actions: + if sa.description: + content.append(f" // {sa.description}") + + state_ref = get_state_reference(action.state, state_machine.name) + + if action.type == "enter": + content.append(f" {state_machine.name}.add_enter_action({sa.name},{state_ref});") + elif action.type == "exit": + content.append(f" {state_machine.name}.add_exit_action({sa.name},{state_ref});") + elif action.type.startswith("cyclic"): + precision = action.type.split("_")[1] + content.append(f" {state_machine.name}.add_{precision}_precision_cyclic_action({sa.name},{sa.period},{state_ref});") + content.append("") + + content.extend([ + " }", + "", + "};" + ]) + + with open("Core/Inc/state_machine.hpp", "w") as f: + f.write("\n".join(content)) + +if __name__ == "__main__": + with open("state_machine.json","r") as file: + data = json.load(file) + sm = parse_state_machine(data) + generate_code(sm) - -######################################################## -# ACTIONS -######################################################## - -actions=data["actions"] - -enter_actions=actions["enter"] -low_precision_cyclic_actions=actions["cyclic"]["low_precision"] -mid_precision_cyclic_actions=actions["cyclic"]["mid_precision"] -high_precision_cyclic_actions=actions["cyclic"]["high_precision"] -exit_actions=actions["exit"] - -actions_code="\n" -function_header_code+="\n" - -# ENTER ACTIONS - -for enter_action in enter_actions: - state=enter_action["state"] - state_actions=enter_action["state_actions"] - - if(isinstance(state,dict)): - for state_action in state_actions: - if(isinstance(state_action,dict)): - actions_code+=f" // {state_action[description]}\n" - actions_code+=f" {name}.add_enter_action({state_action["name"]},{state["name"]}::{state["sub-state"].upper()});\n" - function_header_code+=f" static void {state_action["name"]}();\n" - else: - actions_code+=f" {name}.add_enter_action({state_action},{state["name"]}::{state["sub-state"].upper()});\n" - function_header_code+=f" static void {state_action}();\n" - else: - for state_action in state_actions: - if(isinstance(state_action,dict)): - actions_code+=f" // {state_action["description"]}\n" - actions_code+=f" {name}.add_enter_action({state_action["name"]},{name}States::{state.upper()});\n" - function_header_code+=f" static void {state_action["name"]}();\n" - else: - actions_code+=f" {name}.add_enter_action({state_action},{name}States::{state.upper()});\n" - function_header_code+=f" static void {state_action}();\n" - -actions_code+="\n" -function_header_code+="\n" - -# LOW PRECISION CYCLIC ACTIONS - -for low_precision_cyclic_action in low_precision_cyclic_actions : - states=low_precision_cyclic_action["states"] - state_actions=low_precision_cyclic_action["state_actions"] - description=low_precision_cyclic_action.get("description") - - - for state in states: - if(isinstance(state,dict)): - for state_action in state_actions: - description=state_action.get("description") - if(description): - actions_code+=f" // {description}\n" - actions_code+=f" {name}.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" - function_header_code+=f" static void {state_action["action_name"]}();\n" - else: - actions_code+=f" {name}.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" - function_header_code+=f" static void {state_action["action_name"]}();\n" - else: - for state_action in state_actions : - description=state_action.get("description") - if(description): - actions_code+=f" // {description}\n" - actions_code+=f" {name}.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" - function_header_code+=f" static void {state_action["action_name"]}();\n" - else: - actions_code+=f" {name}.add_low_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" - function_header_code+=f" static void {state_action["action_name"]}();\n" - -actions_code+="\n" -function_header_code+="\n" - -# MID PRECISION CYCLIC ACTIONS - -for mid_precision_cyclic_action in mid_precision_cyclic_actions: - states = mid_precision_cyclic_action["states"] - state_actions = mid_precision_cyclic_action["state_actions"] - description = mid_precision_cyclic_action.get("description") - - for state in states: - if(isinstance(state,dict)): - for state_action in state_actions: - description = state_action.get("description") - if(description): - actions_code += f" // {description}\n" - actions_code += f" {name}.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" - function_header_code += f" static void {state_action["action_name"]}();\n" - else: - actions_code += f" {name}.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" - function_header_code += f" static void {state_action["action_name"]}();\n" - else: - for state_action in state_actions: - description = state_action.get("description") - if(description): - actions_code += f" // {description}\n" - actions_code += f" {name}.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" - function_header_code += f" static void {state_action["action_name"]}();\n" - else: - actions_code += f" {name}.add_mid_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" - function_header_code += f" static void {state_action["action_name"]}();\n" - -actions_code += "\n" -function_header_code += "\n" - -# HIGH PRECISION CYCLIC ACTIONS - -for high_precision_cyclic_action in high_precision_cyclic_actions: - states = high_precision_cyclic_action["states"] - state_actions = high_precision_cyclic_action["state_actions"] - description = high_precision_cyclic_action.get("description") - - for state in states: - if(isinstance(state,dict)): - for state_action in state_actions: - description = state_action.get("description") - if(description): - actions_code += f" // {description}\n" - actions_code += f" {name}.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" - function_header_code += f" static void {state_action["action_name"]}();\n" - else: - actions_code += f" {name}.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{state["name"]}::{state["sub-state"].upper()});\n" - function_header_code += f" static void {state_action["action_name"]}();\n" - else: - for state_action in state_actions: - description = state_action.get("description") - if(description): - actions_code += f" // {description}\n" - actions_code += f" {name}.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" - function_header_code += f" static void {state_action["action_name"]}();\n" - else: - actions_code += f" {name}.add_high_precision_cyclic_action({state_action["action_name"]},{state_action["action_period"]},{name}States::{state.upper()});\n" - function_header_code += f" static void {state_action["action_name"]}();\n" - -actions_code += "\n" -function_header_code += "\n" - -# EXIT ACTIONS -for exit_action in exit_actions: - state = exit_action["state"] - state_actions = exit_action["state_actions"] - - if(isinstance(state, dict)): - for state_action in state_actions: - if(isinstance(state_action, dict)): - actions_code += f" // {state_action['description']}\n" - actions_code += f" {name}.add_exit_action({state_action['name']},{state['name']}::{state['sub-state'].upper()});\n" - function_header_code += f" static void {state_action['name']}();\n" - else: - actions_code += f" {name}.add_exit_action({state_action},{state['name']}::{state['sub-state'].upper()});\n" - function_header_code += f" static void {state_action}();\n" - else: - for state_action in state_actions: - if(isinstance(state_action, dict)): - actions_code += f" // {state_action['description']}\n" - actions_code += f" {name}.add_exit_action({state_action['name']},{name}States::{state.upper()});\n" - function_header_code += f" static void {state_action['name']}();\n" - else: - actions_code += f" {name}.add_exit_action({state_action},{name}States::{state.upper()});\n" - function_header_code += f" static void {state_action}();\n" - -actions_code += "\n" -function_header_code += "\n" - -actions_code += "\n }\n" -function_header_code+="\n" - - -######################################################## -# REPLACE THE TEMPLATE -######################################################## - -with open('Core/Inc/template_state_machine.hpp', "r") as template: - template_content = template.read() - -final_content=template_content.replace("//%STATE_DEFINITION%", enum_code + state_machine_code) -final_content=final_content.replace("//%TRANSITION_DEFINITION%",transitions_code) -final_content=final_content.replace("//%ACTION_DEFINITION%",actions_code) -final_content=final_content.replace("//%FUNCTION_HEADERS%",function_header_code) -final_content=final_content.replace("GeneratedStateMachine",name) - -######################################################## -# REWRITE THE .HPP FILE -######################################################## - -with open('Core/Inc/state_machine.hpp', "w") as destination: - destination.write(final_content) \ No newline at end of file diff --git a/state_machine_object_descriptions.py b/state_machine_object_descriptions.py new file mode 100644 index 00000000..72c3d206 --- /dev/null +++ b/state_machine_object_descriptions.py @@ -0,0 +1,196 @@ +class State: + def __init__(self, name:str): + self.name=name + +class Transition: + def __init__(self, name:str,from_state:str,to_state:str,description:str=None): + self.name=name + self.from_state=from_state + self.to_state=to_state + self.comment=description + +class Enter: + def __init__(self, state: str, state_actions: list): + self.state = state + self.state_actions = state_actions + +class CyclicLowPrecision: + def __init__(self, states: list, state_actions: list): + self.states = states + self.state_actions = state_actions + +class CyclicMidPrecision: + def __init__(self, states: list, state_actions: list): + self.states = states + self.state_actions = state_actions + +class CyclicHighPrecision: + def __init__(self, states: list, state_actions: list): + self.states = states + self.state_actions = state_actions + +class Exit: + def __init__(self, state: str, state_actions: list): + self.state = state + self.state_actions = state_actions + +class StateReference: + def __init__(self, state_data): + if isinstance(state_data, str): + self.state_name = state_data + self.nested_machine = None + self.sub_state = None + else: + self.state_name = None + self.nested_machine = state_data["name"] + self.sub_state = state_data["sub-state"] + + def __str__(self): + if self.nested_machine: + return f"{self.nested_machine}.{self.sub_state}" + return self.state_name + +class ActionDefinition: + def __init__(self, action_data): + if isinstance(action_data, str): + self.name = action_data + self.description = None + self.period = None + else: + self.name = action_data.get("name") or action_data.get("action_name") + self.description = action_data.get("description") + self.period = action_data.get("action_period") + +class Action: + def __init__(self): + self.type = None + self.state = None + self.state_actions = [] + + @classmethod + def create_enter_exit(cls, action_type, state_data, actions_data): + action = cls() + action.type = action_type + action.state = StateReference(state_data) + action.state_actions = [ActionDefinition(a) for a in actions_data] + return action + + @classmethod + def create_cyclic(cls, precision, states_data, actions_data): + actions = [] + for state in states_data: + for action_data in actions_data: + action = cls() + action.type = f"cyclic_{precision}" + action.state = StateReference(state) + action.state_actions = [ActionDefinition(action_data)] + actions.append(action) + return actions + + def describe(self): + states_str = ", ".join(str(s) for s in self.states) + actions_str = ", ".join( + f"{a.name}" + (f"({a.period})" if a.period else "") + + (f" - {a.description}" if a.description else "") + for a in self.actions + ) + return f"{self.type} action on {states_str}: {actions_str}" + +class StateMachine: + def __init__(self,name:str): + self.name=name + self.states=[] + self.transitions=[] + self.actions=[] + self.nested_state_machines=[] + + def add_state(self,state:State): + self.states.append(state) + + def add_transition(self,transition:Transition): + self.transitions.append(transition) + + def add_action(self, action:Action): + self.actions.append(action) + + def add_nested_state_machine(self, state_machine:'StateMachine'): + self.nested_state_machines.append(state_machine) + + +def parse_state(data): + if isinstance(data, str): + return State(data) + elif isinstance(data, dict): + nested_sm = StateMachine(data["name"]) + for sub_state in data["sub-states"]: + nested_sm.add_state(State(sub_state)) + return nested_sm + +def parse_transition(data): + name = data["transition_name"] + description = data.get("description") + + from_state = StateReference(data["from_state"]) + to_state = StateReference(data["to_state"]) + + return Transition(name, from_state, to_state, description) + +def parse_actions(data): + actions_list = [] + + actions_data = data.get("actions", {}) + + for enter_data in actions_data.get("enter", []): + action = Action.create_enter_exit( + "enter", + enter_data["state"], + enter_data["state_actions"] + ) + actions_list.append(action) + + cyclic_data = actions_data.get("cyclic", {}) + for precision in ["low_precision", "mid_precision", "high_precision"]: + for cyclic_item in cyclic_data.get(precision, []): + actions = Action.create_cyclic( + precision, + cyclic_item["states"], + cyclic_item["state_actions"] + ) + actions_list.extend(actions) + + for exit_data in actions_data.get("exit", []): + action = Action.create_enter_exit( + "exit", + exit_data["state"], + exit_data["state_actions"] + ) + actions_list.append(action) + + return actions_list + +def parse_state_machine(data): + sm = StateMachine(data["name"]) + + for st_data in data["states"]: + parsed = parse_state(st_data) + if isinstance(parsed, State): + sm.add_state(parsed) + else: + sm.add_nested_state_machine(parsed) + + for tr_data in data["transitions"]: + tr = parse_transition(tr_data) + sm.add_transition(tr) + + parsed_actions = parse_actions(data) + sm.actions = parsed_actions + + return sm + +def get_state_reference(state_ref, state_machine_name): + if isinstance(state_ref, str): + return f"{state_machine_name}States::{state_ref.upper()}" + + if state_ref.nested_machine: + return f"{state_ref.nested_machine}::{state_ref.sub_state.upper()}" + return f"{state_machine_name}States::{state_ref.state_name.upper()}" \ No newline at end of file From 3a0b2fc9daa105c6226e749acdf534cc5cd26360 Mon Sep 17 00:00:00 2001 From: jdmarmen Date: Wed, 22 Jan 2025 18:25:33 +0100 Subject: [PATCH 7/7] Added literally a line to check the checks --- state_machine_gen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/state_machine_gen.py b/state_machine_gen.py index 414f1e2e..3afea1a0 100644 --- a/state_machine_gen.py +++ b/state_machine_gen.py @@ -102,4 +102,5 @@ def generate_code(state_machine): data = json.load(file) sm = parse_state_machine(data) generate_code(sm) +