Primera version

This commit is contained in:
Miguel 2025-04-18 10:24:50 +02:00
commit 06da71cd46
6 changed files with 4056 additions and 0 deletions

174
.gitignore vendored Normal file
View File

@ -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

2359
BlenderRun_ProdTime.xml Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -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"
}
]
}
}
]
}
]
}

259
json_to_scl.py Normal file
View File

@ -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()

283
to_jason.py Normal file
View File

@ -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 <Constant> 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 <SW.Blocks.FC>")
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)