Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions GlueGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ 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):
def generate_glue_variables(self, located_vars_lines, template_file):
"""
Generate glue variables from the LOCATED_VARIABLES content.
"""
Expand All @@ -93,6 +93,11 @@ 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(os.path.basename(template_file))
else:
env = Environment(loader=self.__loader)
template = env.get_template("glueVars.c.j2")
return template.render(vars=parsed)
77 changes: 77 additions & 0 deletions PatchFiles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
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, ...) _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) \
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



'''
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lxml
jinja2
49 changes: 33 additions & 16 deletions xml2st.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from ProjectController import ProjectController
from ComplexParser import ComplexParser
from GlueGenerator import GlueGenerator
from SerialPortList import SerialPortList
#from SerialPortList import SerialPortList
from PatchFiles import PatchFiles


def compile_xml_to_st(xml_file_path):
Expand Down Expand Up @@ -84,7 +85,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"
):
Expand All @@ -100,14 +101,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)

Expand Down Expand Up @@ -138,6 +142,14 @@ 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")

args = parser.parse_args()

Expand All @@ -150,8 +162,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)

Expand All @@ -177,18 +191,21 @@ 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()
# 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)

else:
print(
Expand Down