commit 06da71cd46dc112ab3cdedbe1039d9bd970eb71f Author: Miguel Date: Fri Apr 18 10:24:50 2025 +0200 Primera version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a19790 --- /dev/null +++ b/.gitignore @@ -0,0 +1,174 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc diff --git a/BlenderRun_ProdTime.xml b/BlenderRun_ProdTime.xml new file mode 100644 index 0000000..6365fe2 --- /dev/null +++ b/BlenderRun_ProdTime.xml @@ -0,0 +1,2359 @@ + + + + + + false + TASK2 + +
+
+
+
+ + + + + + + + +
+
+
+ +
+ + Standard + BlenderRun_ProdTime + + 2040 + LAD + false + + + + + + + it-IT + + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Seconds + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + Int + 0 + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Reset Hours + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Seconds Counter + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + Int + 60 + + + + + + + + + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Minute + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + Int + 0 + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + 1 + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Minute Counter + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + Int + 60 + + + + + + + + + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Hour + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + Int + 0 + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + 1 + + + 2 + Int + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Hour Counter + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + Int + 0 + + + + + + + + + + + Int + 0 + + + + + + + + + + + Int + 0 + + + + + + + + + + + + 2 + + + 1 + + + 1 + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Counter reset + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Running Seconds + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DINT#60 + + + + + + + + + + + + + + + DINT#0 + + + + + + + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + + + + + + + + + Int + DInt + + + DInt + + + DInt + + + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Running Minutes + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DINT#60 + + + + + + + + + + + + + + + DINT#0 + + + + + + + + + + + Int + 1 + + + + + + + + + + + Int + DInt + + + DInt + + + DInt + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Running Hours for Maintenance + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Running Hours for Maintenance + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + it-IT + Run Prod Time + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + \ No newline at end of file diff --git a/BlenderRun_ProdTime_parsed.pas b/BlenderRun_ProdTime_parsed.pas new file mode 100644 index 0000000..acdf0cf Binary files /dev/null and b/BlenderRun_ProdTime_parsed.pas differ diff --git a/BlenderRun_ProdTime_simplified.json b/BlenderRun_ProdTime_simplified.json new file mode 100644 index 0000000..715cb3c --- /dev/null +++ b/BlenderRun_ProdTime_simplified.json @@ -0,0 +1,981 @@ +{ + "block_name": "BlenderRun_ProdTime", + "block_number": 2040, + "language": "LAD", + "interface": {}, + "networks": [ + { + "id": "9", + "title": "", + "logic": [ + { + "instruction_uid": "26", + "type": "Contact", + "inputs": { + "operand": { + "uid": "21", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "27", + "type": "Contact", + "inputs": { + "operand": { + "uid": "22", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in": { + "type": "connection", + "source_instruction_uid": "26", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": {} + }, + { + "instruction_uid": "28", + "type": "Add", + "inputs": { + "in1": { + "uid": "23", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "24", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "en": { + "type": "connection", + "source_instruction_uid": "27", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": { + "out": [ + { + "uid": "25", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + } + ] + }, + { + "id": "1A", + "title": "", + "logic": [ + { + "instruction_uid": "24", + "type": "Contact", + "inputs": { + "operand": { + "uid": "21", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "25", + "type": "Move", + "inputs": { + "in": { + "uid": "22", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "en": { + "type": "connection", + "source_instruction_uid": "24", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": { + "out1": [ + { + "uid": "23", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + } + ] + }, + { + "id": "2B", + "title": "", + "logic": [ + { + "instruction_uid": "26", + "type": "Contact", + "inputs": { + "operand": { + "uid": "21", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "27", + "type": "Contact", + "inputs": { + "operand": { + "uid": "22", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in": { + "type": "connection", + "source_instruction_uid": "26", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": {} + }, + { + "instruction_uid": "28", + "type": "Add", + "inputs": { + "in1": { + "uid": "23", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "24", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "en": { + "type": "connection", + "source_instruction_uid": "27", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": { + "out": [ + { + "uid": "25", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + } + ] + }, + { + "id": "3C", + "title": "", + "logic": [ + { + "instruction_uid": "24", + "type": "Eq", + "inputs": { + "in1": { + "uid": "21", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "22", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "pre": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "25", + "type": "Coil", + "inputs": { + "in": { + "type": "connection", + "source_instruction_uid": "24", + "source_instruction_type": "Eq", + "source_pin": "out" + }, + "operand": { + "uid": "23", + "scope": "LocalVariable", + "type": "unknown_access" + } + }, + "outputs": {} + } + ] + }, + { + "id": "4D", + "title": "", + "logic": [ + { + "instruction_uid": "27", + "type": "Contact", + "inputs": { + "operand": { + "uid": "21", + "scope": "LocalVariable", + "type": "unknown_access" + }, + "in": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "28", + "type": "Move", + "inputs": { + "in": { + "uid": "22", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "en": { + "type": "connection", + "source_instruction_uid": "27", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": { + "out1": [ + { + "uid": "23", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "29", + "type": "Add", + "inputs": { + "in1": { + "uid": "24", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "25", + "scope": "LiteralConstant", + "type": "unknown_access" + } + }, + "outputs": { + "out": [ + { + "uid": "26", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + } + ] + }, + { + "id": "5E", + "title": "", + "logic": [ + { + "instruction_uid": "24", + "type": "Eq", + "inputs": { + "in1": { + "uid": "21", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "22", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "pre": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "25", + "type": "Coil", + "inputs": { + "in": { + "type": "connection", + "source_instruction_uid": "24", + "source_instruction_type": "Eq", + "source_pin": "out" + }, + "operand": { + "uid": "23", + "scope": "LocalVariable", + "type": "unknown_access" + } + }, + "outputs": {} + } + ] + }, + { + "id": "6F", + "title": "", + "logic": [ + { + "instruction_uid": "30", + "type": "Contact", + "inputs": { + "operand": { + "uid": "21", + "scope": "LocalVariable", + "type": "unknown_access" + }, + "in": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "31", + "type": "Move", + "inputs": { + "in": { + "uid": "22", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "en": { + "type": "connection", + "source_instruction_uid": "30", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": { + "out1": [ + { + "uid": "23", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "32", + "type": "Add", + "inputs": { + "in1": { + "uid": "24", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "25", + "scope": "LiteralConstant", + "type": "unknown_access" + } + }, + "outputs": { + "out": [ + { + "uid": "26", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "33", + "type": "Add", + "inputs": { + "in1": { + "uid": "27", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "28", + "scope": "LiteralConstant", + "type": "unknown_access" + } + }, + "outputs": { + "out": [ + { + "uid": "29", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + } + ] + }, + { + "id": "80", + "title": "", + "logic": [ + { + "instruction_uid": "29", + "type": "Contact", + "inputs": { + "operand": { + "uid": "21", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "30", + "type": "Contact", + "inputs": { + "operand": { + "uid": "22", + "scope": "GlobalVariable", + "type": "unknown_access" + } + }, + "outputs": {} + }, + { + "instruction_uid": "31", + "type": "O", + "inputs": { + "in1": { + "type": "connection", + "source_instruction_uid": "29", + "source_instruction_type": "Contact", + "source_pin": "out" + }, + "in2": { + "type": "connection", + "source_instruction_uid": "30", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": {} + }, + { + "instruction_uid": "32", + "type": "Move", + "inputs": { + "in": { + "uid": "23", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "en": { + "type": "connection", + "source_instruction_uid": "31", + "source_instruction_type": "O", + "source_pin": "out" + } + }, + "outputs": { + "out1": [ + { + "uid": "24", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "33", + "type": "Move", + "inputs": { + "in": { + "uid": "25", + "scope": "LiteralConstant", + "type": "unknown_access" + } + }, + "outputs": { + "out1": [ + { + "uid": "26", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "34", + "type": "Move", + "inputs": { + "in": { + "uid": "27", + "scope": "LiteralConstant", + "type": "unknown_access" + } + }, + "outputs": { + "out1": [ + { + "uid": "28", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + } + ] + }, + { + "id": "91", + "title": "", + "logic": [ + { + "instruction_uid": "26", + "type": "Contact", + "inputs": { + "operand": { + "uid": "21", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "27", + "type": "Contact", + "inputs": { + "operand": { + "uid": "22", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in": { + "type": "connection", + "source_instruction_uid": "26", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": {} + }, + { + "instruction_uid": "28", + "type": "Add", + "inputs": { + "in1": { + "uid": "23", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "24", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "en": { + "type": "connection", + "source_instruction_uid": "27", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": { + "out": [ + { + "uid": "25", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + } + ] + }, + { + "id": "A2", + "title": "", + "logic": [ + { + "instruction_uid": "35", + "type": "Convert", + "inputs": { + "in": { + "uid": "21", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "en": { + "type": "powerrail" + } + }, + "outputs": { + "out": [ + { + "uid": "22", + "scope": "LocalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "36", + "type": "Mod", + "inputs": { + "en": { + "type": "connection", + "source_instruction_uid": "35", + "source_instruction_type": "Convert", + "source_pin": "eno" + }, + "in1": { + "uid": "23", + "scope": "LocalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "24", + "scope": "TypedConstant", + "type": "unknown_access" + } + }, + "outputs": { + "out": [ + { + "uid": "25", + "scope": "LocalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "37", + "type": "Eq", + "inputs": { + "pre": { + "type": "connection", + "source_instruction_uid": "36", + "source_instruction_type": "Mod", + "source_pin": "eno" + }, + "in1": { + "uid": "26", + "scope": "LocalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "27", + "scope": "TypedConstant", + "type": "unknown_access" + } + }, + "outputs": {} + }, + { + "instruction_uid": "38", + "type": "Contact", + "inputs": { + "in": { + "type": "connection", + "source_instruction_uid": "37", + "source_instruction_type": "Eq", + "source_pin": "out" + }, + "operand": { + "uid": "28", + "scope": "GlobalVariable", + "type": "unknown_access" + } + }, + "outputs": {} + }, + { + "instruction_uid": "39", + "type": "Contact", + "inputs": { + "operand": { + "uid": "29", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in": { + "type": "connection", + "source_instruction_uid": "38", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": {} + }, + { + "instruction_uid": "40", + "type": "Add", + "inputs": { + "in1": { + "uid": "30", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "31", + "scope": "LiteralConstant", + "type": "unknown_access" + }, + "en": { + "type": "connection", + "source_instruction_uid": "39", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": { + "out": [ + { + "uid": "32", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "41", + "type": "PBox", + "inputs": { + "bit": { + "uid": "33", + "scope": "GlobalVariable", + "type": "unknown_access" + } + }, + "outputs": {} + }, + { + "instruction_uid": "42", + "type": "Coil", + "inputs": { + "in": { + "type": "connection", + "source_instruction_uid": "41", + "source_instruction_type": "PBox", + "source_pin": "out" + }, + "operand": { + "uid": "34", + "scope": "LocalVariable", + "type": "unknown_access" + } + }, + "outputs": {} + } + ] + }, + { + "id": "B3", + "title": "", + "logic": [ + { + "instruction_uid": "32", + "type": "Contact", + "inputs": { + "operand": { + "uid": "21", + "scope": "LocalVariable", + "type": "unknown_access" + }, + "in": { + "type": "powerrail" + } + }, + "outputs": {} + }, + { + "instruction_uid": "33", + "type": "Convert", + "inputs": { + "in": { + "uid": "22", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "en": { + "type": "connection", + "source_instruction_uid": "32", + "source_instruction_type": "Contact", + "source_pin": "out" + } + }, + "outputs": { + "out": [ + { + "uid": "23", + "scope": "LocalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "34", + "type": "Mod", + "inputs": { + "en": { + "type": "connection", + "source_instruction_uid": "33", + "source_instruction_type": "Convert", + "source_pin": "eno" + }, + "in1": { + "uid": "24", + "scope": "LocalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "25", + "scope": "TypedConstant", + "type": "unknown_access" + } + }, + "outputs": { + "out": [ + { + "uid": "26", + "scope": "LocalVariable", + "type": "unknown_access" + } + ] + } + }, + { + "instruction_uid": "35", + "type": "Eq", + "inputs": { + "pre": { + "type": "connection", + "source_instruction_uid": "34", + "source_instruction_type": "Mod", + "source_pin": "eno" + }, + "in1": { + "uid": "27", + "scope": "LocalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "28", + "scope": "TypedConstant", + "type": "unknown_access" + } + }, + "outputs": {} + }, + { + "instruction_uid": "36", + "type": "Add", + "inputs": { + "en": { + "type": "connection", + "source_instruction_uid": "35", + "source_instruction_type": "Eq", + "source_pin": "out" + }, + "in1": { + "uid": "29", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "in2": { + "uid": "30", + "scope": "LiteralConstant", + "type": "unknown_access" + } + }, + "outputs": { + "out": [ + { + "uid": "31", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + } + ] + }, + { + "id": "C4", + "title": "", + "logic": [ + { + "instruction_uid": "23", + "type": "Move", + "inputs": { + "in": { + "uid": "21", + "scope": "GlobalVariable", + "type": "unknown_access" + }, + "en": { + "type": "powerrail" + } + }, + "outputs": { + "out1": [ + { + "uid": "22", + "scope": "GlobalVariable", + "type": "unknown_access" + } + ] + } + } + ] + } + ] +} \ No newline at end of file diff --git a/json_to_scl.py b/json_to_scl.py new file mode 100644 index 0000000..c0db9e9 --- /dev/null +++ b/json_to_scl.py @@ -0,0 +1,259 @@ +import json +import os + +# --- Funciones Procesadoras por Tipo de Instrucción --- +# Cada función recibe el diccionario de la instrucción del JSON. +# Por ahora, solo imprimen información. + +def process_contact(instruction): + """Procesa una instrucción 'Contact'.""" + print(f" [Contact] UID: {instruction['instruction_uid']}") + operand = instruction['inputs'].get('operand', {}) + print(f" - Checks: {operand.get('scope', '?')} UID: {operand.get('uid', '?')}") # Adaptar si 'unknown_access' se resuelve + in_source = instruction['inputs'].get('in', {}) + if in_source.get('type') == 'powerrail': + print(" - Input: Power Rail") + elif in_source.get('type') == 'connection': + print(f" - Input: From instruction {in_source.get('source_instruction_uid', '?')} (Pin: {in_source.get('source_pin', '?')})") + else: + print(f" - Input: {in_source}") + +def process_coil(instruction): + """Procesa una instrucción 'Coil'.""" + print(f" [Coil] UID: {instruction['instruction_uid']}") + operand = instruction['inputs'].get('operand', {}) + print(f" - Assigns to: {operand.get('scope', '?')} UID: {operand.get('uid', '?')}") + in_source = instruction['inputs'].get('in', {}) + if in_source.get('type') == 'connection': + print(f" - Condition from: instruction {in_source.get('source_instruction_uid', '?')} (Pin: {in_source.get('source_pin', '?')})") + else: + print(f" - Condition: {in_source}") + +def process_add(instruction): + """Procesa una instrucción 'Add'.""" + print(f" [Add] UID: {instruction['instruction_uid']}") + in1 = instruction['inputs'].get('in1', {}) + in2 = instruction['inputs'].get('in2', {}) + en = instruction['inputs'].get('en', {}) + outputs = instruction['outputs'].get('out', []) + + print(f" - Input 1: {in1.get('scope', '?')} UID: {in1.get('uid', '?')}") + print(f" - Input 2: {in2.get('scope', '?')} UID: {in2.get('uid', '?')}") + if en.get('type') == 'powerrail': + print(" - Enabled by: Power Rail (Direct)") # Si Add pudiera conectarse directo + elif en.get('type') == 'connection': + print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})") + elif en: # Si 'en' no está presente o no es conexión/powerrail (poco común en Add) + print(f" - Enabled by: {en}") + else: + print(" - Enabled by: Power Rail (Implícito, sin EN)") # Asumir si no hay pin 'en' + + for output in outputs: + print(f" - Output to: {output.get('scope', '?')} UID: {output.get('uid', '?')}") + +def process_move(instruction): + """Procesa una instrucción 'Move'.""" + print(f" [Move] UID: {instruction['instruction_uid']}") + in_val = instruction['inputs'].get('in', {}) + en = instruction['inputs'].get('en', {}) + outputs = instruction['outputs'].get('out1', []) # Asumiendo pin 'out1' para Move + + print(f" - Input Value: {in_val.get('scope', '?')} UID: {in_val.get('uid', '?')}") + if en.get('type') == 'powerrail': + print(" - Enabled by: Power Rail") + elif en.get('type') == 'connection': + print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})") + elif en: + print(f" - Enabled by: {en}") + else: + print(" - Enabled by: Power Rail (Implícito, sin EN)") + + for output in outputs: + print(f" - Output to: {output.get('scope', '?')} UID: {output.get('uid', '?')}") + +def process_eq(instruction): + """Procesa una instrucción 'Eq' (Equal).""" + print(f" [Compare EQ] UID: {instruction['instruction_uid']}") + in1 = instruction['inputs'].get('in1', {}) + in2 = instruction['inputs'].get('in2', {}) + pre = instruction['inputs'].get('pre', {}) # Condición previa (usualmente PowerRail o conexión) + + print(f" - Input 1: {in1.get('scope', '?')} UID: {in1.get('uid', '?')}") + print(f" - Input 2: {in2.get('scope', '?')} UID: {in2.get('uid', '?')}") + if pre.get('type') == 'powerrail': + print(" - Pre-condition: Power Rail") + elif pre.get('type') == 'connection': + print(f" - Pre-condition: instruction {pre.get('source_instruction_uid', '?')} (Pin: {pre.get('source_pin', '?')})") + else: + print(f" - Pre-condition: {pre}") + + # La salida 'out' de Eq usualmente va a otra instrucción (Contact, Coil, Enable pin) + # Lo veremos cuando procesemos la instrucción destino + +def process_mod(instruction): + """Procesa una instrucción 'Mod' (Modulo).""" + print(f" [Modulo] UID: {instruction['instruction_uid']}") + in1 = instruction['inputs'].get('in1', {}) + in2 = instruction['inputs'].get('in2', {}) + en = instruction['inputs'].get('en', {}) + outputs = instruction['outputs'].get('out', []) + eno_outputs = instruction['outputs'].get('eno', []) # Mod también puede tener ENO + + print(f" - Input 1 (Dividend): {in1.get('scope', '?')} UID: {in1.get('uid', '?')}") + print(f" - Input 2 (Divisor): {in2.get('scope', '?')} UID: {in2.get('uid', '?')}") + if en.get('type') == 'powerrail': + print(" - Enabled by: Power Rail") + elif en.get('type') == 'connection': + print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})") + elif en: + print(f" - Enabled by: {en}") + else: + print(" - Enabled by: Power Rail (Implícito, sin EN)") + + for output in outputs: + print(f" - Output (Remainder) to: {output.get('scope', '?')} UID: {output.get('uid', '?')}") + # ENO normalmente se conecta a pines 'en' o 'pre' de la siguiente instrucción + +def process_convert(instruction): + """Procesa una instrucción 'Convert'.""" + print(f" [Convert] UID: {instruction['instruction_uid']}") + in_val = instruction['inputs'].get('in', {}) + en = instruction['inputs'].get('en', {}) + outputs = instruction['outputs'].get('out', []) + # Podríamos extraer los tipos de datos de TemplateValue si estuvieran en el JSON + # template_vals = instruction.get('template_values', {}) + + print(f" - Input Value: {in_val.get('scope', '?')} UID: {in_val.get('uid', '?')}") + if en.get('type') == 'powerrail': + print(" - Enabled by: Power Rail") + elif en.get('type') == 'connection': + print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})") + elif en: + print(f" - Enabled by: {en}") + else: + print(" - Enabled by: Power Rail (Implícito, sin EN)") + + for output in outputs: + print(f" - Output to: {output.get('scope', '?')} UID: {output.get('uid', '?')}") + # print(f" (Expected DestType: {template_vals.get('DestType', '?')})") + + +def process_or(instruction): + """Procesa una instrucción 'O' (OR).""" + # Las instrucciones 'O' en LAD suelen representar la unión de ramas paralelas. + # Este parser simple solo muestra las entradas directas. Reconstruir la lógica OR completa requeriría más análisis. + print(f" [OR Logic] UID: {instruction['instruction_uid']}") + in1 = instruction['inputs'].get('in1', {}) + in2 = instruction['inputs'].get('in2', {}) + # Podría haber in3, in4... si Cardinality > 2 + + if in1.get('type') == 'connection': + print(f" - Input 1 from: instruction {in1.get('source_instruction_uid', '?')} (Pin: {in1.get('source_pin', '?')})") + else: + print(f" - Input 1: {in1}") + if in2.get('type') == 'connection': + print(f" - Input 2 from: instruction {in2.get('source_instruction_uid', '?')} (Pin: {in2.get('source_pin', '?')})") + else: + print(f" - Input 2: {in2}") + + # La salida 'out' de O usualmente va a otra instrucción (Contact, Coil, Enable pin) + +def process_pbox(instruction): + """Procesa una instrucción 'PBox'.""" + # PBox puede ser muchas cosas (Rising Edge, Falling Edge, Set, Reset, etc.) + # Necesitaríamos más información o convenciones para saber qué hace exactamente. + print(f" [PBox - Special?] UID: {instruction['instruction_uid']}") + inputs = instruction.get('inputs', {}) + outputs = instruction.get('outputs', {}) + for pin, source in inputs.items(): + if source.get('type') == 'connection': + print(f" - Input Pin '{pin}' from: instruction {source.get('source_instruction_uid', '?')} (Pin: {source.get('source_pin', '?')})") + elif source.get('type') == 'powerrail': + print(f" - Input Pin '{pin}': Power Rail") + else: + print(f" - Input Pin '{pin}': {source.get('scope', '?')} UID: {source.get('uid', '?')}") + + # La salida de PBox la veremos en el destino + +def process_unknown(instruction): + """Procesa una instrucción de tipo desconocido.""" + print(f" [Unknown Type: {instruction.get('type', 'N/A')}] UID: {instruction['instruction_uid']}") + print(f" - Inputs: {instruction.get('inputs')}") + print(f" - Outputs: {instruction.get('outputs')}") + +# --- Mapeo de Tipos a Funciones --- +instruction_handlers = { + "Contact": process_contact, + "Coil": process_coil, + "Add": process_add, + "Move": process_move, + "Eq": process_eq, + "Mod": process_mod, + "Convert": process_convert, + "O": process_or, # 'O' representa un OR lógico en FlgNet + "PBox": process_pbox, # Tipo genérico, tratar como desconocido por ahora + # Añade más tipos aquí si aparecen +} + +# --- Función Principal de Procesamiento --- + +def process_logic_data(data): + """Itera sobre el JSON cargado y procesa cada instrucción.""" + print("=" * 40) + print(f"Processing Block: {data.get('block_name')} ({data.get('block_number')})") + print(f"Language: {data.get('language')}") + print("-" * 40) + + # Opcional: Imprimir interfaz + print("Interface:") + for section, members in data.get('interface', {}).items(): + if members: + print(f" {section}:") + for member in members: + print(f" - {member['name']} ({member['datatype']})") + print("-" * 40) + + # Procesar Redes + print("Networks:") + for network in data.get('networks', []): + print(f"\nNetwork ID: {network.get('id')} - Title: '{network.get('title', '')}'") + if 'error' in network: + print(f" ERROR en esta red: {network['error']}") + continue + if not network.get('logic'): + print(" (No logic instructions found in JSON for this network)") + continue + + for instruction in network.get('logic', []): + instruction_type = instruction.get('type') + # Obtener el handler adecuado, o el default si no se encuentra + handler = instruction_handlers.get(instruction_type, process_unknown) + try: + handler(instruction) + except Exception as e: + print(f" ERROR procesando instrucción UID {instruction.get('instruction_uid')} (Tipo: {instruction_type}): {e}") + # Considerar imprimir más detalles del error o de la instrucción + # import traceback + # traceback.print_exc() + + +# --- Ejecución --- +if __name__ == "__main__": + json_file = 'BlenderRun_ProdTime_simplified.json' # El archivo generado por el script anterior + + if not os.path.exists(json_file): + print(f"Error: Archivo JSON no encontrado en {json_file}") + print("Asegúrate de haber ejecutado el script de conversión XML a JSON primero.") + else: + try: + with open(json_file, 'r', encoding='utf-8') as f: + logic_data = json.load(f) + + process_logic_data(logic_data) + + except json.JSONDecodeError as e: + print(f"Error: El archivo JSON ({json_file}) no es válido: {e}") + except Exception as e: + print(f"Ocurrió un error inesperado al cargar o procesar el JSON: {e}") + import traceback + traceback.print_exc() \ No newline at end of file diff --git a/to_jason.py b/to_jason.py new file mode 100644 index 0000000..9d72d43 --- /dev/null +++ b/to_jason.py @@ -0,0 +1,283 @@ +import json +import os +from lxml import etree + +# --- Namespaces --- +# Define los namespaces con prefijos explícitos. Quitamos 'default'. +ns = { + 'sw': 'http://www.siemens.com/automation/Openness/SW/Interface/v5', + 'flg': 'http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4' + # No incluimos un prefijo para elementos sin namespace o en el namespace por defecto +} + +# --- Helper Functions --- + +def get_multilingual_text(element, default_lang='en-US', fallback_lang='it-IT'): + """Intenta extraer texto de un MultilingualText, priorizando idiomas.""" + if element is None: + return "" + try: + # Accedemos a los elementos sin prefijo directamente + text_item = element.xpath(f".//MultilingualTextItem[AttributeList/Culture='{default_lang}']/AttributeList/Text", namespaces=ns) + if text_item: + return text_item[0].text.strip() if text_item[0].text else "" + + text_item = element.xpath(f".//MultilingualTextItem[AttributeList/Culture='{fallback_lang}']/AttributeList/Text", namespaces=ns) + if text_item: + return text_item[0].text.strip() if text_item[0].text else "" + + text_item = element.xpath(".//MultilingualTextItem/AttributeList/Text", namespaces=ns) + if text_item: + return text_item[0].text.strip() if text_item[0].text else "" + + except Exception as e: + print(f"Advertencia: Error extrayendo MultilingualText: {e}") + pass + return "" + +def get_symbol_name(symbol_element): + """Construye el nombre completo del símbolo a partir de sus componentes.""" + if symbol_element is None: + return None + # Accedemos a Component sin prefijo + components = symbol_element.xpath("./Component/@Name") + return ".".join(f'"{c}"' if ' ' in c else c for c in components) + +def parse_access(access_element): + """Parsea un elemento Access para obtener información de variable o constante.""" + info = { + 'uid': access_element.get('UId'), + 'scope': access_element.get('Scope') + } + # Accedemos a Symbol y Constant sin prefijo + symbol = access_element.xpath("./Symbol", namespaces=ns) + constant = access_element.xpath("./Constant", namespaces=ns) + + if symbol: + info['type'] = 'variable' + info['name'] = get_symbol_name(symbol[0]) + elif constant: + # Los hijos de Constant tampoco tienen prefijo aparente + const_type_elem = constant[0].xpath("./ConstantType", namespaces=ns) + const_val_elem = constant[0].xpath("./ConstantValue", namespaces=ns) + info['datatype'] = const_type_elem[0].text if const_type_elem else 'Unknown' + info['value_str'] = const_val_elem[0].text if const_val_elem else None # Guardamos original + info['value'] = info['value_str'] # Valor procesado + info['type'] = 'constant' + + # Intenta convertir el valor si es numérico o booleano + if info['value'] is not None: + if info['datatype'].lower() in ['int', 'dint', 'udint', 'sint', 'usint', 'lint', 'ulint', 'word', 'dword', 'lword']: + # Manejar DINT#60, etc. + val_str = info['value'].split('#')[-1] if '#' in info['value'] else info['value'] + try: + info['value'] = int(val_str) + except (ValueError, TypeError): + info['value'] = info['value_str'] # Mantener como string si falla + elif info['datatype'].lower() == 'bool': + info['value'] = info['value'].lower() == 'true' or info['value'] == '1' + elif info['datatype'].lower() in ['real', 'lreal']: + try: + info['value'] = float(info['value']) + except (ValueError, TypeError): + info['value'] = info['value_str'] # Mantener como string si falla + # Añadir más conversiones de tipos si es necesario + else: + # Podría ser TypedConstant, que también tiene un dentro + # Si llegamos aquí, es algo inesperado + info['type'] = 'unknown_access' + + return info + + +def parse_part(part_element): + """Parsea un elemento Part (instrucción).""" + return { + 'uid': part_element.get('UId'), + 'name': part_element.get('Name'), + # TemplateValue no parece tener prefijo + 'template_values': {tv.get('Name'): tv.get('Type') + for tv in part_element.xpath("./TemplateValue", namespaces=ns)} + } + +# --- Main Parsing Logic --- + +def parse_network(network_element): + """Parsea una red (CompileUnit) y extrae su lógica simplificada.""" + network_logic = [] + network_id = network_element.get('ID') + # Accedemos a ObjectList y MultilingualText sin prefijo + title_element = network_element.xpath("./ObjectList/MultilingualText[@CompositionName='Title']", namespaces=ns) + network_title = get_multilingual_text(title_element[0]) if title_element else f"Network {network_id}" + + # Usamos el prefijo 'flg' para FlgNet + flgnet = network_element.xpath(".//flg:FlgNet", namespaces=ns) + if not flgnet: + return {'id': network_id, 'title': network_title, 'logic': [], 'error': 'FlgNet not found'} + + flgnet = flgnet[0] + + # 1. Mapear todos los Access y Parts por su UId + # Usamos prefijo flg: para Access y Part dentro de FlgNet + access_map = {} + for acc in flgnet.xpath(".//flg:Access", namespaces=ns): + acc_info = parse_access(acc) + access_map[acc_info['uid']] = acc_info + + parts_map = {} + for part in flgnet.xpath(".//flg:Part", namespaces=ns): + part_info = parse_part(part) + parts_map[part_info['uid']] = part_info + + # 2. Construir mapa de conexiones (destino -> fuente) + wire_connections = {} + # Usamos prefijo flg: para Wire y sus hijos + for wire in flgnet.xpath(".//flg:Wire", namespaces=ns): + source_uid, source_pin = None, None + dest_uid, dest_pin = None, None + + children = wire.getchildren() + if not children: continue # Ignorar wires vacíos si los hubiera + + source_elem = children[0] + dest_elem = children[1] if len(children) > 1 else None + + # Usamos QName para comparar tags con namespace correctamente + flg_ns_uri = ns['flg'] + if source_elem.tag == etree.QName(flg_ns_uri, 'Powerrail'): + source_uid, source_pin = 'POWERRAIL', 'out' + elif source_elem.tag == etree.QName(flg_ns_uri, 'IdentCon'): + source_uid = source_elem.get('UId') + source_pin = 'value' # Pin implícito para Access + elif source_elem.tag == etree.QName(flg_ns_uri, 'NameCon'): + source_uid = source_elem.get('UId') + source_pin = source_elem.get('Name') + + if dest_elem is not None: + if dest_elem.tag == etree.QName(flg_ns_uri, 'IdentCon'): + dest_uid = dest_elem.get('UId') + dest_pin = 'value' + elif dest_elem.tag == etree.QName(flg_ns_uri, 'NameCon'): + dest_uid = dest_elem.get('UId') + dest_pin = dest_elem.get('Name') + + if dest_uid and dest_pin and (source_uid is not None or source_pin == 'out'): + wire_connections[(dest_uid, dest_pin)] = (source_uid, source_pin) + + + # 3. Iterar sobre las instrucciones (Parts) y encontrar sus conexiones + for part_uid, part_info in parts_map.items(): + instruction_repr = { + 'instruction_uid': part_uid, + 'type': part_info['name'], + 'inputs': {}, + 'outputs': {} + } + + connected_inputs = {k[1]: v for k, v in wire_connections.items() if k[0] == part_uid} + + for dest_pin, (source_uid, source_pin) in connected_inputs.items(): + if source_uid == 'POWERRAIL': + instruction_repr['inputs'][dest_pin] = {'type': 'powerrail'} + elif source_uid in access_map: + instruction_repr['inputs'][dest_pin] = access_map[source_uid] + elif source_uid in parts_map: + instruction_repr['inputs'][dest_pin] = { + 'type': 'connection', + 'source_instruction_uid': source_uid, + 'source_instruction_type': parts_map[source_uid]['name'], + 'source_pin': source_pin + } + else: + # Podría ser una conexión rota o no encontrada + instruction_repr['inputs'][dest_pin] = {'type': 'unknown_source', 'uid': source_uid} + + # Encontrar salidas conectadas a Access + for (conn_dest_uid, conn_dest_pin), (conn_source_uid, conn_source_pin) in wire_connections.items(): + if conn_source_uid == part_uid and conn_dest_uid in access_map: + if conn_source_pin not in instruction_repr['outputs']: + instruction_repr['outputs'][conn_source_pin] = [] + # Añadimos la info del Access que es el destino + instruction_repr['outputs'][conn_source_pin].append(access_map[conn_dest_uid]) + + network_logic.append(instruction_repr) + + return {'id': network_id, 'title': network_title, 'logic': network_logic} + + +def convert_xml_to_json(xml_filepath, json_filepath): + """Función principal para convertir el XML a JSON.""" + if not os.path.exists(xml_filepath): + print(f"Error: Archivo XML no encontrado en {xml_filepath}") + return + + try: + tree = etree.parse(xml_filepath) + root = tree.getroot() + + # Buscar SW.Blocks.FC usando local-name() para robustez inicial + # O asumir que no tiene namespace si está bajo Document/Engineering + fc_block = root.xpath("//*[local-name()='SW.Blocks.FC']") + if not fc_block: + print("Error: No se encontró el elemento ") + return + fc_block = fc_block[0] + + # --- Extraer Info General (sin prefijos) --- + block_name = fc_block.xpath("./AttributeList/Name/text()") + block_number = fc_block.xpath("./AttributeList/Number/text()") + block_lang = fc_block.xpath("./AttributeList/ProgrammingLanguage/text()") + + result = { + "block_name": block_name[0].strip() if block_name else "Unknown", + "block_number": int(block_number[0]) if block_number and block_number[0].isdigit() else None, + "language": block_lang[0].strip() if block_lang else "Unknown", + "interface": {}, + "networks": [] + } + + # --- Extraer Interfaz (con prefijo sw:) --- + interface_sections = fc_block.xpath(".//sw:Interface/sw:Sections/sw:Section", namespaces=ns) + for section in interface_sections: + section_name = section.get('Name') + members = [] + for member in section.xpath("./sw:Member", namespaces=ns): + members.append({ + "name": member.get('Name'), + "datatype": member.get('Datatype') + }) + result["interface"][section_name] = members + + # --- Extraer Lógica de Redes (CompileUnit sin prefijo, contenido con flg:) --- + # Buscamos SW.Blocks.CompileUnit sin prefijo, asumiendo que es hijo directo de ObjectList + networks = fc_block.xpath("./ObjectList/SW.Blocks.CompileUnit", namespaces=ns) + network_count = 0 + for network_elem in networks: + network_count += 1 + parsed_network = parse_network(network_elem) + result["networks"].append(parsed_network) + + if network_count == 0: + print("Advertencia: No se encontraron redes (SW.Blocks.CompileUnit). Verifica la estructura del XML.") + + + # --- Escribir resultado a JSON --- + with open(json_filepath, 'w', encoding='utf-8') as f: + json.dump(result, f, indent=4, ensure_ascii=False) + + print(f"Conversión completada. Archivo JSON guardado en: {json_filepath}") + + except etree.XMLSyntaxError as e: + print(f"Error de sintaxis XML: {e}") + except Exception as e: + print(f"Ocurrió un error inesperado durante el procesamiento: {e}") + import traceback + traceback.print_exc() + + +# --- Ejecución --- +if __name__ == "__main__": + xml_file = 'BlenderRun_ProdTime.xml' + json_file = 'BlenderRun_ProdTime_simplified.json' + + convert_xml_to_json(xml_file, json_file) \ No newline at end of file