initial commit
This commit is contained in:
parent
f9965a3b90
commit
ec5c21552a
2
.gitignore
vendored
2
.gitignore
vendored
@ -160,3 +160,5 @@ cython_debug/
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
config.json
|
||||
out/
|
203
XFTGenerator.py
Normal file
203
XFTGenerator.py
Normal file
@ -0,0 +1,203 @@
|
||||
# XF Template Generator
|
||||
__author__ = "Louis Heredero"
|
||||
__copyright__ = "Copyright 2023, Louis Heredero"
|
||||
__license__ = "GPL3.0"
|
||||
__version__ = "1.0.0"
|
||||
|
||||
import json
|
||||
import locale
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
def get_input(title, default=None, non_null=False):
|
||||
"""Prompts user for an input
|
||||
|
||||
Args:
|
||||
title (str): Name of value
|
||||
default (Any, optional): Default value. Defaults to None.
|
||||
non_null (bool, optional): Whether the can be null. Defaults to False.
|
||||
|
||||
Returns:
|
||||
str|None: The value
|
||||
"""
|
||||
|
||||
while True:
|
||||
txt = title
|
||||
if default is not None:
|
||||
txt += f" [{default}]"
|
||||
txt += ": "
|
||||
value = input(txt).strip()
|
||||
if value:
|
||||
return value
|
||||
|
||||
elif default:
|
||||
return default
|
||||
|
||||
elif not non_null:
|
||||
return ""
|
||||
|
||||
def fill_template(dir_, variables, filename):
|
||||
"""Replaces values in a template file
|
||||
|
||||
Args:
|
||||
dir_ (str): Path of src directory
|
||||
variables (dict): Dictionary of values to replace
|
||||
filename (str): Template file name
|
||||
|
||||
Returns:
|
||||
str: Template content with replaced values
|
||||
"""
|
||||
|
||||
with open(os.path.join(dir_, "templates", filename), "r") as f:
|
||||
content = f.read()
|
||||
|
||||
def replace(m):
|
||||
indent = m.group(1)
|
||||
key = m.group(2)
|
||||
txt = variables[key]
|
||||
|
||||
if indent:
|
||||
lines = txt.split("\n")
|
||||
lines = [indent+line for line in lines]
|
||||
txt = "\n".join(lines)
|
||||
|
||||
return txt
|
||||
|
||||
return re.sub("([ \t]*)\$\{(.+?)\}", replace, content)
|
||||
|
||||
def output_file(dir_, filename, content):
|
||||
"""Writes content to a given file. Checks before overwriting
|
||||
|
||||
Args:
|
||||
dir_ (str): Path of src directory
|
||||
filename (str): Output file name
|
||||
content (str): Content to write
|
||||
"""
|
||||
|
||||
outdir = os.path.join(dir_, "out")
|
||||
if not os.path.isdir(outdir):
|
||||
os.mkdir(outdir)
|
||||
|
||||
outpath = os.path.join(outdir, filename)
|
||||
if os.path.exists(outpath):
|
||||
replace = input(f"The file {filename} already exists. Overwrite it ? y/N: ")
|
||||
if replace.lower() != "y":
|
||||
return
|
||||
|
||||
with open(outpath, "w") as f:
|
||||
f.write(content)
|
||||
|
||||
def main():
|
||||
locale.setlocale(locale.LC_TIME, "en_GB.utf8")
|
||||
dir_ = os.path.dirname(__file__)
|
||||
|
||||
conf_path = os.path.join(dir_, "config.json")
|
||||
if os.path.exists(conf_path):
|
||||
with open(conf_path, "r") as f:
|
||||
variables = json.load(f)
|
||||
|
||||
else:
|
||||
variables = {}
|
||||
|
||||
variables["date"] = time.strftime("%B %Y")
|
||||
|
||||
variables["author"] = get_input("Author", variables.get("author", ""), True)
|
||||
variables["filename"] = get_input("Filename", None, True).upper()
|
||||
variables["filename_lc"] = variables["filename"].lower()
|
||||
variables["fn"] = get_input("Filename (short)", None, True).upper()
|
||||
|
||||
##########
|
||||
# States #
|
||||
##########
|
||||
|
||||
states = []
|
||||
|
||||
print("States (leave empty to end):")
|
||||
print("> INIT")
|
||||
while True:
|
||||
state = input("> ").upper()
|
||||
if state:
|
||||
states.append(state)
|
||||
else:
|
||||
break
|
||||
|
||||
states = ["ST"+variables["fn"]+"_"+s for s in states]
|
||||
variables["STATES_ENUM"] = ",\n".join(states)
|
||||
|
||||
states_cases = []
|
||||
|
||||
for i, state in enumerate(states):
|
||||
case_ = f"case {state}:\n"
|
||||
case_ += " break;"
|
||||
states_cases.append(case_)
|
||||
|
||||
variables["STATES_CASES"] = "\n\n".join(states_cases)
|
||||
|
||||
##########
|
||||
# Events #
|
||||
##########
|
||||
|
||||
events = ["init = 100"]
|
||||
|
||||
print("Events (leave empty to end):")
|
||||
print("> init")
|
||||
while True:
|
||||
event = input("> ").lower()
|
||||
if event:
|
||||
events.append(event)
|
||||
|
||||
else:
|
||||
break
|
||||
|
||||
events_enum = ["ev"+variables["fn"]+e for e in events]
|
||||
events_enum = ",\n".join(events_enum).split("\n")
|
||||
events_enum[0] += " // TODO change this number (< 256)"
|
||||
variables["EVENTS_ENUM"] = "\n".join(events_enum)
|
||||
|
||||
events_emits = []
|
||||
|
||||
emit_def = ""
|
||||
emit_def += "void {filename}_emit{Event}({filename}* me, uint16_t t) {\n"
|
||||
emit_def += " POST(me, &{filename}_processEvent, ev{fn}{event}, t, 0);\n"
|
||||
emit_def += "}"
|
||||
emit_def = emit_def.replace("{filename}", variables["filename"]).replace("{fn}", variables["fn"])
|
||||
|
||||
for event in events[1:]:
|
||||
events_emits.append(
|
||||
emit_def.replace("{event}", event).replace("{Event}", event.capitalize())
|
||||
)
|
||||
|
||||
variables["EVENTS_EMITS_DEF"] = "\n\n".join(events_emits)
|
||||
|
||||
events_emits = []
|
||||
emit_dec = ""
|
||||
emit_dec += "/**\n"
|
||||
emit_dec += " * Emit the {event} event\n"
|
||||
emit_dec += " * @param me the {filename} itself\n"
|
||||
emit_dec += " * @param t time to wait in ms before triggering event\n"
|
||||
emit_dec += " */"
|
||||
emit_dec += "void {filename}_emit{Event}({filename}* me, uint16_t t);"
|
||||
emit_dec = emit_dec.replace("{filename}", variables["filename"])
|
||||
|
||||
for event in events[1:]:
|
||||
events_emits.append(
|
||||
emit_dec.replace("{event}", event).replace("{Event}", event.capitalize())
|
||||
)
|
||||
|
||||
variables["EVENTS_EMITS_DEC"] = "\n\n".join(events_emits)
|
||||
|
||||
file_c = fill_template(dir_, variables, "file.c")
|
||||
file_h = fill_template(dir_, variables, "file.h")
|
||||
|
||||
output_file(dir_, variables["filename_lc"]+".c", file_c)
|
||||
output_file(dir_, variables["filename_lc"]+".h", file_h)
|
||||
|
||||
with open(conf_path, "w") as f:
|
||||
conf = {
|
||||
"author": variables["author"]
|
||||
}
|
||||
json.dump(conf, f)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
55
templates/file.c
Normal file
55
templates/file.c
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @author ${author}
|
||||
* @version 1.0.0
|
||||
* @date ${date}
|
||||
* @file ${filename_lc}.c
|
||||
*/
|
||||
|
||||
#include "${filename_lc}.h"
|
||||
|
||||
void ${filename}_init(${filename}* me){
|
||||
me->state = ST${fn}_INIT;
|
||||
}
|
||||
|
||||
void ${filename}_startBehaviour(${filename}* me){
|
||||
POST(me, &${filename}_processEvent, ev${fn}init, 0, 0);
|
||||
}
|
||||
|
||||
bool ${filename}_processEvent(Event* ev) {
|
||||
bool processed = false;
|
||||
${filename}* me = (${filename}*)Event_getTarget(ev);
|
||||
switch (me->state) { // onState
|
||||
case ST${fn}_INIT:
|
||||
if (ev->id == ev${fn}init) {
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
${STATES_CASES}
|
||||
}
|
||||
|
||||
if(oldState != me->state){
|
||||
switch (oldState) { // onExit
|
||||
case ST${fn}_INIT:
|
||||
break;
|
||||
|
||||
${STATES_CASES}
|
||||
}
|
||||
|
||||
switch (me->state) { // onEntry
|
||||
case ST${fn}_INIT:
|
||||
break;
|
||||
|
||||
${STATES_CASES}
|
||||
}
|
||||
|
||||
processed = true;
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
/************
|
||||
* EMITTERS *
|
||||
************/
|
||||
|
||||
${EVENTS_EMITS_DEF}
|
49
templates/file.h
Normal file
49
templates/file.h
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @author ${author}
|
||||
* @version 1.0.0
|
||||
* @date ${date}
|
||||
* @file ${filename_lc}.h
|
||||
*/
|
||||
#ifndef ${filename}_H
|
||||
#define ${filename}_H
|
||||
|
||||
#include "../xf/xf.h"
|
||||
|
||||
typedef enum {
|
||||
${STATES_ENUM}
|
||||
} ${filename}_STATES;
|
||||
|
||||
typedef enum {
|
||||
${EVENTS_ENUM}
|
||||
} ${filename}_EVENTS;
|
||||
|
||||
typedef struct {
|
||||
${filename}_STATES state;
|
||||
} ${filename};
|
||||
|
||||
/**
|
||||
* Initialize the ${filename}
|
||||
* @param me the ${filename} itself
|
||||
*/
|
||||
void ${filename}_init(${filename}* me);
|
||||
|
||||
/**
|
||||
* Start the ${filename} state machine
|
||||
* @param me the ${filename} itself
|
||||
*/
|
||||
void ${filename}_startBehaviour(${filename}* me);
|
||||
|
||||
/**
|
||||
* Process the event
|
||||
* @param ev the event to process
|
||||
* @return true if the event is processed
|
||||
*/
|
||||
bool ${filename}_processEvent(Event* ev);
|
||||
|
||||
/************
|
||||
* EMITTERS *
|
||||
************/
|
||||
|
||||
${EVENTS_EMITS_DEC}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user