From c47fe8ba799a824091f241dbf1dfd914f4c87a30 Mon Sep 17 00:00:00 2001 From: Henry HEI Date: Tue, 14 Oct 2025 13:09:29 +0800 Subject: [PATCH 1/4] feat: add -o and -t option to give user the ability to choose file path --- GlueGenerator.py | 12 +++++++++--- xml2st.py | 29 ++++++++++++++++++----------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/GlueGenerator.py b/GlueGenerator.py index fedcf6f9e..9efd82d48 100644 --- a/GlueGenerator.py +++ b/GlueGenerator.py @@ -83,7 +83,7 @@ def __parse_line(self, line): "glue_code": self.__glue_logic(varName), } - def generate_glue_variables(self, located_vars_lines): + def generate_glue_variables(self, located_vars_lines, template_file): """ Generate glue variables from the LOCATED_VARIABLES content. """ @@ -93,6 +93,12 @@ def generate_glue_variables(self, located_vars_lines): if entry is not None: parsed.append(entry) - env = Environment(loader=self.__loader) - template = env.get_template("glueVars.c.j2") + if template_file: + abs_template_file = os.path.abspath(template_file) + env = Environment(loader=FileSystemLoader(os.path.dirname(abs_template_file))) + template = env.get_template(template_file) + print(template) + else: + env = Environment(loader=self.__loader) + template = env.get_template("glueVars.c.j2") return template.render(vars=parsed) diff --git a/xml2st.py b/xml2st.py index 71b70c884..6a4c992b5 100755 --- a/xml2st.py +++ b/xml2st.py @@ -84,7 +84,7 @@ def append_debugger_to_st(st_file, debug_text): f.write(c_debug) -def generate_gluevars(located_vars_file): +def generate_gluevars(located_vars_file, template_file, output): if not os.path.isfile(located_vars_file) or not located_vars_file.lower().endswith( ".h" ): @@ -100,14 +100,17 @@ def generate_gluevars(located_vars_file): # Create an instance of GlueGenerator generator = GlueGenerator() - glueVars = generator.generate_glue_variables(located_vars) + glueVars = generator.generate_glue_variables(located_vars, template_file) if glueVars is None: print("Error: Failed to generate glue variables.", file=sys.stderr) return None # Save the generated glue variables to a file - glue_vars_file = os.path.join(os.path.dirname(located_vars_file), "glueVars.c") + if output: + glue_vars_file = os.path.abspath(output) + else: + glue_vars_file = os.path.join(os.path.dirname(located_vars_file), "glueVars.c") with open(glue_vars_file, "w") as f: f.write(glueVars) @@ -140,6 +143,8 @@ def main(): action="store_true", help="List all available serial ports" ) + parser.add_argument("-o","--output", metavar=("OUTPUT_FILE"), type=str, help="The path to the output file") + parser.add_argument("-t","--template-file", metavar=("TEMPLATE_FILE"), type=str, help="The path to the template file for glue variables generation") args = parser.parse_args() @@ -152,8 +157,10 @@ def main(): raise Exception("Compilation failed, no program text generated.") print("Saving ST file...") - - st_file = os.path.abspath(args.generate_st).replace("plc.xml", "program.st") + if args.output: + st_file = os.path.abspath(args.output) + else: + st_file = os.path.abspath(args.generate_st).replace("plc.xml", "program.st") with open(st_file, "w") as file: file.write(program_text) @@ -184,13 +191,13 @@ def main(): sys.exit(1) elif args.generate_gluevars: - try: - print("Generating glue variables...") - generate_gluevars(args.generate_gluevars) + # try: + print("Generating glue variables...") + generate_gluevars(args.generate_gluevars, args.template_file, args.output) - except Exception as e: - print(f"Error generating glue variables: {e}", file=sys.stderr) - sys.exit(1) + # except Exception as e: + # print(f"Error generating glue variables: {e}", file=sys.stderr) + # sys.exit(1) elif args.list_ports: port_list = SerialPortList() From 61a601d26e5378f008c266dbed808b7975ae9c82 Mon Sep 17 00:00:00 2001 From: mythay Date: Wed, 19 Nov 2025 11:07:48 +0800 Subject: [PATCH 2/4] Fix template loading by using basename --- GlueGenerator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/GlueGenerator.py b/GlueGenerator.py index 9efd82d48..20800eb6e 100644 --- a/GlueGenerator.py +++ b/GlueGenerator.py @@ -96,8 +96,7 @@ def generate_glue_variables(self, located_vars_lines, template_file): if template_file: abs_template_file = os.path.abspath(template_file) env = Environment(loader=FileSystemLoader(os.path.dirname(abs_template_file))) - template = env.get_template(template_file) - print(template) + template = env.get_template(os.path.basename(template_file)) else: env = Environment(loader=self.__loader) template = env.get_template("glueVars.c.j2") From ff9d0ea62e4b3f24f69628e2e58e02dd4b1b018b Mon Sep 17 00:00:00 2001 From: Henry HEI Date: Wed, 26 Nov 2025 13:27:31 +0800 Subject: [PATCH 3/4] feat: for overlap memory --- GlueGenerator.py | 2 +- PatchFiles.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ xml2st.py | 10 +++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 PatchFiles.py diff --git a/GlueGenerator.py b/GlueGenerator.py index 20800eb6e..7096319f3 100644 --- a/GlueGenerator.py +++ b/GlueGenerator.py @@ -80,7 +80,7 @@ def __parse_line(self, line): return { "type": varType, "name": varName, - "glue_code": self.__glue_logic(varName), + # "glue_code": self.__glue_logic(varName), } def generate_glue_variables(self, located_vars_lines, template_file): diff --git a/PatchFiles.py b/PatchFiles.py new file mode 100644 index 000000000..6d583333c --- /dev/null +++ b/PatchFiles.py @@ -0,0 +1,76 @@ +import os +import re +def PatchFiles(source_dir): + PatchLoacatedBit(source_dir) + PatchConfigHeader(source_dir) + + +def PatchLoacatedBit(source_dir): + file_path = os.path.join(source_dir, 'POUS.c') + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + # 正则替换 __INIT_LOCATED(BOOL,__IX..,...) 为 __INIT_LOCATED_BOOL(BOOL,__IX..,bit,...) + def replacer(match): + ix = match.group(1) + bit = match.group(2) + var = match.group(3) + var2 = match.group(4) + return f'__INIT_LOCATED_BOOL(BOOL, {ix}, {int(bit)+1}, {var}, {var2})' + # replacer = r'__INIT_LOCATED_BOOL(BOOL, \1, \2, \3, \4)' + pattern = r'__INIT_LOCATED\(\s*BOOL,\s*(__\wX\d+_(\d+)),\s*([^,]+),\s*(\w+)\)' + new_content = re.sub(pattern, replacer, content) + # print(new_content) + with open(file_path, 'w', encoding='utf-8') as f: + f.write(new_content) + +def PatchConfigHeader(source_dir): + file_path = os.path.join(source_dir, 'Config0.h') + with open(file_path, 'w', encoding='utf-8') as f: + f.write(config_header) + +config_header=r''' + +#ifndef __CONFIG_0_H +#define __CONFIG_0_H + +#define __INIT_LOCATED_BOOL(type, location, bit, name, retained) \ + { \ + extern type *location; \ + name.value = location; \ + name.flags = (bit << 4); \ + __INIT_RETAIN(name, retained) \ + } + +#undef __INIT_LOCATED_VALUE +// not init bool located value to false automatically +#define __INIT_LOCATED_VALUE(name, initial) _Generic(name.value, \ + BOOL *: ((initial && (name.flags & 0xf0)) && (*(name.value) |= (1 << ((name.flags >> 4) - 1)))), \ + default: *(name.value) = initial); + +#undef __GET_LOCATED +// #define __GET_LOCATED(name, ...) _Generic((name.value), \ +// BOOL *: (name.flags & __IEC_FORCE_FLAG) ? name.fvalue __VA_ARGS__ : ((name.flags & 0xf0) ? ((*(name.value))__VA_ARGS__) >> ((name.flags >> 4) - 1) & 1 : (*(name.value))__VA_ARGS__), \ +// default: ((name.flags & __IEC_FORCE_FLAG) ? name.fvalue __VA_ARGS__ : (*(name.value))__VA_ARGS__)) + +#define __GET_LOCATED(name, ...) \ + ((name.flags & __IEC_FORCE_FLAG) ? name.fvalue __VA_ARGS__ : ((name.flags & 0xf0) ? ((*(name.value))__VA_ARGS__) >> ((name.flags >> 4) - 1) & 1 : (*(name.value))__VA_ARGS__)) + +#undef __SET_LOCATED +#define __SET_LOCATED(prefix, name, suffix, new_value) \ + if (!(prefix name.flags & __IEC_FORCE_FLAG)) \ + { \ + if (prefix name.flags & 0xf0) \ + { \ + *(prefix name.value)suffix = (*(prefix name.value)suffix & ~(1 << ((prefix name.flags >> 4) - 1))) | ((new_value & 1) << ((prefix name.flags >> 4) - 1)); \ + } \ + else \ + { \ + *(prefix name.value)suffix = new_value; \ + } \ + } + +#endif + + + +''' \ No newline at end of file diff --git a/xml2st.py b/xml2st.py index 3b3246d2f..eb02d4d3d 100755 --- a/xml2st.py +++ b/xml2st.py @@ -9,6 +9,7 @@ from ComplexParser import ComplexParser from GlueGenerator import GlueGenerator from SerialPortList import SerialPortList +from PatchFiles import PatchFiles def compile_xml_to_st(xml_file_path): @@ -141,6 +142,12 @@ def main(): parser.add_argument( "--list-ports", action="store_true", help="List all available serial ports" ) + parser.add_argument( + "--patch-files", + metavar=("SOURCE_DIR"), + type=str, + help="The path to the source directory containing files to patch", + ) parser.add_argument("-o","--output", metavar=("OUTPUT_FILE"), type=str, help="The path to the output file") parser.add_argument("-t","--template-file", metavar=("TEMPLATE_FILE"), type=str, help="The path to the template file for glue variables generation") @@ -197,6 +204,9 @@ def main(): ports = port_list.get_ports() print(json.dumps(ports, indent=2)) + elif args.patch_files: + PatchFiles(args.patch_files) + else: print( "Error: No valid arguments provided. Use --help for usage information.", From 2a7c043f1a8d048572917a9b5b7b6892b303b80d Mon Sep 17 00:00:00 2001 From: Henry HEI Date: Thu, 27 Nov 2025 13:55:09 +0800 Subject: [PATCH 4/4] feat: add located bool patch --- PatchFiles.py | 5 +++-- requirements.txt | 2 ++ xml2st.py | 10 +++++----- 3 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 requirements.txt diff --git a/PatchFiles.py b/PatchFiles.py index 6d583333c..d6dbb3022 100644 --- a/PatchFiles.py +++ b/PatchFiles.py @@ -52,8 +52,9 @@ def PatchConfigHeader(source_dir): // BOOL *: (name.flags & __IEC_FORCE_FLAG) ? name.fvalue __VA_ARGS__ : ((name.flags & 0xf0) ? ((*(name.value))__VA_ARGS__) >> ((name.flags >> 4) - 1) & 1 : (*(name.value))__VA_ARGS__), \ // default: ((name.flags & __IEC_FORCE_FLAG) ? name.fvalue __VA_ARGS__ : (*(name.value))__VA_ARGS__)) -#define __GET_LOCATED(name, ...) \ - ((name.flags & __IEC_FORCE_FLAG) ? name.fvalue __VA_ARGS__ : ((name.flags & 0xf0) ? ((*(name.value))__VA_ARGS__) >> ((name.flags >> 4) - 1) & 1 : (*(name.value))__VA_ARGS__)) +#define __GET_LOCATED(name, ...) _Generic((name.value), \ + BOOL *: ((name.flags & __IEC_FORCE_FLAG) ? name.fvalue __VA_ARGS__ : ((name.flags & 0xf0) ? ((*(name.value))__VA_ARGS__) >> ((name.flags >> 4) - 1) & 1 : (*(name.value))__VA_ARGS__)), \ + default: ((name.flags & __IEC_FORCE_FLAG) ? name.fvalue __VA_ARGS__ : (*(name.value))__VA_ARGS__)) #undef __SET_LOCATED #define __SET_LOCATED(prefix, name, suffix, new_value) \ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..02e8fc908 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +lxml +jinja2 \ No newline at end of file diff --git a/xml2st.py b/xml2st.py index eb02d4d3d..0299d4da1 100755 --- a/xml2st.py +++ b/xml2st.py @@ -8,7 +8,7 @@ from ProjectController import ProjectController from ComplexParser import ComplexParser from GlueGenerator import GlueGenerator -from SerialPortList import SerialPortList +#from SerialPortList import SerialPortList from PatchFiles import PatchFiles @@ -199,10 +199,10 @@ def main(): # print(f"Error generating glue variables: {e}", file=sys.stderr) # sys.exit(1) - elif args.list_ports: - port_list = SerialPortList() - ports = port_list.get_ports() - print(json.dumps(ports, indent=2)) +# elif args.list_ports: +# port_list = SerialPortList() +# ports = port_list.get_ports() +# print(json.dumps(ports, indent=2)) elif args.patch_files: PatchFiles(args.patch_files)