Buscando el problema de los Offsets Fuera de Orden
This commit is contained in:
parent
fa6b7573c7
commit
ee112f5e77
|
@ -0,0 +1,160 @@
|
|||
# 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
|
||||
|
||||
# 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/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# 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/
|
44
CopyPaste.py
44
CopyPaste.py
|
@ -1,28 +1,24 @@
|
|||
def calculate_offsets(db_struct, current_offset=0):
|
||||
def handle_array_types(db_struct):
|
||||
"""
|
||||
Recursively calculate byte offsets for each field in the DB structure,
|
||||
applying general alignment rules except inside arrays.
|
||||
Handle array types once all UDTs are expanded.
|
||||
This function modifies the structure in place.
|
||||
"""
|
||||
if isinstance(db_struct, dict):
|
||||
for key, value in db_struct.items():
|
||||
if isinstance(value, dict) and 'type' in value:
|
||||
is_array_element = value.get('is_array_element', False)
|
||||
type_name = value['type']
|
||||
size = type_sizes.get(type_name, 1)
|
||||
|
||||
if 'String' in type_name:
|
||||
match = re.match(r'String\[(\d+)\]', type_name)
|
||||
if match:
|
||||
size = int(match.group(1)) + 2 # String length + 2 for the null terminator and length prefix
|
||||
|
||||
if not is_array_element and current_offset % 2 != 0:
|
||||
current_offset += 1 # Align to the next even offset if it's not an array element
|
||||
|
||||
value['offset'] = current_offset
|
||||
current_offset += size
|
||||
|
||||
# Recursively handle nested structures
|
||||
for key, value in list(db_struct.items()):
|
||||
if isinstance(value, dict):
|
||||
current_offset = calculate_offsets(value, current_offset)
|
||||
|
||||
return current_offset
|
||||
handle_array_types(value)
|
||||
elif isinstance(value, str):
|
||||
# Parsing array definitions, e.g., "Array[1..3] of Real"
|
||||
match = re.match(r"Array\[(\d+)\.\.(\d+)\] of (\w+)", value)
|
||||
if match:
|
||||
lower_bound, upper_bound, base_type = (
|
||||
int(match.group(1)),
|
||||
int(match.group(2)),
|
||||
match.group(3),
|
||||
)
|
||||
# Expand this field into multiple fields
|
||||
db_struct.pop(key) # Remove the original field
|
||||
for i in range(lower_bound, upper_bound + 1):
|
||||
db_struct[f"{key}_{i}"] = {"type": base_type, 'is_array_element': True}
|
||||
print(
|
||||
f"Expanded field '{key}' into array fields: {key}_{lower_bound} to {key}_{upper_bound} of type {base_type}
|
354
DB_Structure.csv
354
DB_Structure.csv
|
@ -1,176 +1,178 @@
|
|||
Nombre,Tipo,Offset,Comentario
|
||||
MAIN,"""UDT SIPA SV Main""",0,
|
||||
MAIN.N1,DInt,0,.DB_IOT.USERLEVEL
|
||||
MAIN.N2,String[81],4,.DB_IOT.USERNAME
|
||||
MAIN.N3,String[81],88,.DB_IOT.NOME_RICETTA
|
||||
MAIN.N4,Int,172,.DB_IOT.NEXT_MAINT_CYCLES
|
||||
MAIN.N5.V1,String[254],174,
|
||||
MAIN.N5.V2,String[254],430,
|
||||
MAIN.N5.V3,String[254],686,
|
||||
MAIN.N5.V4,String[254],942,
|
||||
MAIN.N5.V5,String[8],1198,
|
||||
MAIN.N6.type_1,Real,1208,N/A
|
||||
MAIN.N6.type_2,Real,1212,N/A
|
||||
MAIN.N6.type_3,Real,1216,N/A
|
||||
MAIN.N7.type_1,Real,1220,N/A
|
||||
MAIN.N7.type_2,Real,1224,N/A
|
||||
MAIN.N7.type_3,Real,1228,N/A
|
||||
MAIN.N8,Real,1232,.DB_IOT.ELECTRIC_POWER_D
|
||||
MAIN.N9,Real,1236,.DB_IOT.ELECTRIC_POWER_FACTOR_D
|
||||
MAIN.N10,Real,1240,.DB_IOT.ELECTRIC_POWER_HOUR_D
|
||||
MAIN.N11,Real,1244,.DB_IOT.ELECTRIC_POWER_WH
|
||||
SECT1,"""UDT SIPA SV Section""",1248,
|
||||
SECT1.N1,DInt,1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT1.N2,DInt,1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT1.N3,DInt,1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT1.N4,Int,1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT1.N5,Int,1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT1.N6,DInt,1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT1.N7.V1,DInt,1684,PIECES_TOT
|
||||
SECT1.N7.V2,DInt,1688,PIECES_OK
|
||||
SECT1.N7.V3,DInt,1692,PIECES_KO_1
|
||||
SECT1.N7.V4,DInt,1696,PIECES_KO_2
|
||||
SECT1.N7.V5,DInt,1700,PIECES_KO_3
|
||||
SECT1.N7.V6,DInt,1704,PIECES_KO_4
|
||||
SECT1.N7.V7,DInt,1708,PIECES_KO_5
|
||||
SECT1.N7.V8,DInt,1712,PIECES_KO_6
|
||||
SECT1.N7.V9,DInt,1716,PIECES_KO_7
|
||||
SECT1.N7.V10,DInt,1720,PIECES_KO_8
|
||||
SECT1.N7.V11,DInt,1724,PIECES_KO_9
|
||||
SECT1.N7.V12,DInt,1728,PIECES_KO_10
|
||||
SECT1.N7.V13,DInt,1732,T_ALARM_HOURS
|
||||
SECT1.N7.V14,DInt,1736,T_DRY_CYCLE_HOURS
|
||||
SECT1.N7.V15,DInt,1740,T_POWERED_HOURS
|
||||
SECT1.N7.V16,DInt,1744,T_PRODUCT_100_HOURS
|
||||
SECT1.N7.V17,DInt,1748,T_PRODUCT_0_HOURS
|
||||
SECT1.N7.V18,DInt,1752,T_STOP_HOURS
|
||||
SECT1.N7.V19,Int,1756,T_ALARM_MINUTES
|
||||
SECT1.N7.V20,Int,1758,T_DRY_CYCLE_MINUTES
|
||||
SECT1.N7.V21,Int,1760,T_POWERED_MINUTES
|
||||
SECT1.N7.V22,Int,1762,T_PRODUCT_100_MINUTES
|
||||
SECT1.N7.V23,Int,1764,T_PRODUCT_0_MINUTES
|
||||
SECT1.N7.V24,Int,1766,T_STOP_MINUTES
|
||||
SECT2,"""UDT SIPA SV Section""",1352,
|
||||
SECT2.N1,DInt,1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT2.N2,DInt,1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT2.N3,DInt,1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT2.N4,Int,1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT2.N5,Int,1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT2.N6,DInt,1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT2.N7.V1,DInt,1684,PIECES_TOT
|
||||
SECT2.N7.V2,DInt,1688,PIECES_OK
|
||||
SECT2.N7.V3,DInt,1692,PIECES_KO_1
|
||||
SECT2.N7.V4,DInt,1696,PIECES_KO_2
|
||||
SECT2.N7.V5,DInt,1700,PIECES_KO_3
|
||||
SECT2.N7.V6,DInt,1704,PIECES_KO_4
|
||||
SECT2.N7.V7,DInt,1708,PIECES_KO_5
|
||||
SECT2.N7.V8,DInt,1712,PIECES_KO_6
|
||||
SECT2.N7.V9,DInt,1716,PIECES_KO_7
|
||||
SECT2.N7.V10,DInt,1720,PIECES_KO_8
|
||||
SECT2.N7.V11,DInt,1724,PIECES_KO_9
|
||||
SECT2.N7.V12,DInt,1728,PIECES_KO_10
|
||||
SECT2.N7.V13,DInt,1732,T_ALARM_HOURS
|
||||
SECT2.N7.V14,DInt,1736,T_DRY_CYCLE_HOURS
|
||||
SECT2.N7.V15,DInt,1740,T_POWERED_HOURS
|
||||
SECT2.N7.V16,DInt,1744,T_PRODUCT_100_HOURS
|
||||
SECT2.N7.V17,DInt,1748,T_PRODUCT_0_HOURS
|
||||
SECT2.N7.V18,DInt,1752,T_STOP_HOURS
|
||||
SECT2.N7.V19,Int,1756,T_ALARM_MINUTES
|
||||
SECT2.N7.V20,Int,1758,T_DRY_CYCLE_MINUTES
|
||||
SECT2.N7.V21,Int,1760,T_POWERED_MINUTES
|
||||
SECT2.N7.V22,Int,1762,T_PRODUCT_100_MINUTES
|
||||
SECT2.N7.V23,Int,1764,T_PRODUCT_0_MINUTES
|
||||
SECT2.N7.V24,Int,1766,T_STOP_MINUTES
|
||||
SECT3,"""UDT SIPA SV Section""",1456,
|
||||
SECT3.N1,DInt,1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT3.N2,DInt,1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT3.N3,DInt,1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT3.N4,Int,1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT3.N5,Int,1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT3.N6,DInt,1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT3.N7.V1,DInt,1684,PIECES_TOT
|
||||
SECT3.N7.V2,DInt,1688,PIECES_OK
|
||||
SECT3.N7.V3,DInt,1692,PIECES_KO_1
|
||||
SECT3.N7.V4,DInt,1696,PIECES_KO_2
|
||||
SECT3.N7.V5,DInt,1700,PIECES_KO_3
|
||||
SECT3.N7.V6,DInt,1704,PIECES_KO_4
|
||||
SECT3.N7.V7,DInt,1708,PIECES_KO_5
|
||||
SECT3.N7.V8,DInt,1712,PIECES_KO_6
|
||||
SECT3.N7.V9,DInt,1716,PIECES_KO_7
|
||||
SECT3.N7.V10,DInt,1720,PIECES_KO_8
|
||||
SECT3.N7.V11,DInt,1724,PIECES_KO_9
|
||||
SECT3.N7.V12,DInt,1728,PIECES_KO_10
|
||||
SECT3.N7.V13,DInt,1732,T_ALARM_HOURS
|
||||
SECT3.N7.V14,DInt,1736,T_DRY_CYCLE_HOURS
|
||||
SECT3.N7.V15,DInt,1740,T_POWERED_HOURS
|
||||
SECT3.N7.V16,DInt,1744,T_PRODUCT_100_HOURS
|
||||
SECT3.N7.V17,DInt,1748,T_PRODUCT_0_HOURS
|
||||
SECT3.N7.V18,DInt,1752,T_STOP_HOURS
|
||||
SECT3.N7.V19,Int,1756,T_ALARM_MINUTES
|
||||
SECT3.N7.V20,Int,1758,T_DRY_CYCLE_MINUTES
|
||||
SECT3.N7.V21,Int,1760,T_POWERED_MINUTES
|
||||
SECT3.N7.V22,Int,1762,T_PRODUCT_100_MINUTES
|
||||
SECT3.N7.V23,Int,1764,T_PRODUCT_0_MINUTES
|
||||
SECT3.N7.V24,Int,1766,T_STOP_MINUTES
|
||||
SECT4,"""UDT SIPA SV Section""",1560,
|
||||
SECT4.N1,DInt,1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT4.N2,DInt,1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT4.N3,DInt,1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT4.N4,Int,1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT4.N5,Int,1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT4.N6,DInt,1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT4.N7.V1,DInt,1684,PIECES_TOT
|
||||
SECT4.N7.V2,DInt,1688,PIECES_OK
|
||||
SECT4.N7.V3,DInt,1692,PIECES_KO_1
|
||||
SECT4.N7.V4,DInt,1696,PIECES_KO_2
|
||||
SECT4.N7.V5,DInt,1700,PIECES_KO_3
|
||||
SECT4.N7.V6,DInt,1704,PIECES_KO_4
|
||||
SECT4.N7.V7,DInt,1708,PIECES_KO_5
|
||||
SECT4.N7.V8,DInt,1712,PIECES_KO_6
|
||||
SECT4.N7.V9,DInt,1716,PIECES_KO_7
|
||||
SECT4.N7.V10,DInt,1720,PIECES_KO_8
|
||||
SECT4.N7.V11,DInt,1724,PIECES_KO_9
|
||||
SECT4.N7.V12,DInt,1728,PIECES_KO_10
|
||||
SECT4.N7.V13,DInt,1732,T_ALARM_HOURS
|
||||
SECT4.N7.V14,DInt,1736,T_DRY_CYCLE_HOURS
|
||||
SECT4.N7.V15,DInt,1740,T_POWERED_HOURS
|
||||
SECT4.N7.V16,DInt,1744,T_PRODUCT_100_HOURS
|
||||
SECT4.N7.V17,DInt,1748,T_PRODUCT_0_HOURS
|
||||
SECT4.N7.V18,DInt,1752,T_STOP_HOURS
|
||||
SECT4.N7.V19,Int,1756,T_ALARM_MINUTES
|
||||
SECT4.N7.V20,Int,1758,T_DRY_CYCLE_MINUTES
|
||||
SECT4.N7.V21,Int,1760,T_POWERED_MINUTES
|
||||
SECT4.N7.V22,Int,1762,T_PRODUCT_100_MINUTES
|
||||
SECT4.N7.V23,Int,1764,T_PRODUCT_0_MINUTES
|
||||
SECT4.N7.V24,Int,1766,T_STOP_MINUTES
|
||||
SECT5,"""UDT SIPA SV Section""",1664,
|
||||
SECT5.N1,DInt,1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT5.N2,DInt,1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT5.N3,DInt,1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT5.N4,Int,1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT5.N5,Int,1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT5.N6,DInt,1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT5.N7.V1,DInt,1684,PIECES_TOT
|
||||
SECT5.N7.V2,DInt,1688,PIECES_OK
|
||||
SECT5.N7.V3,DInt,1692,PIECES_KO_1
|
||||
SECT5.N7.V4,DInt,1696,PIECES_KO_2
|
||||
SECT5.N7.V5,DInt,1700,PIECES_KO_3
|
||||
SECT5.N7.V6,DInt,1704,PIECES_KO_4
|
||||
SECT5.N7.V7,DInt,1708,PIECES_KO_5
|
||||
SECT5.N7.V8,DInt,1712,PIECES_KO_6
|
||||
SECT5.N7.V9,DInt,1716,PIECES_KO_7
|
||||
SECT5.N7.V10,DInt,1720,PIECES_KO_8
|
||||
SECT5.N7.V11,DInt,1724,PIECES_KO_9
|
||||
SECT5.N7.V12,DInt,1728,PIECES_KO_10
|
||||
SECT5.N7.V13,DInt,1732,T_ALARM_HOURS
|
||||
SECT5.N7.V14,DInt,1736,T_DRY_CYCLE_HOURS
|
||||
SECT5.N7.V15,DInt,1740,T_POWERED_HOURS
|
||||
SECT5.N7.V16,DInt,1744,T_PRODUCT_100_HOURS
|
||||
SECT5.N7.V17,DInt,1748,T_PRODUCT_0_HOURS
|
||||
SECT5.N7.V18,DInt,1752,T_STOP_HOURS
|
||||
SECT5.N7.V19,Int,1756,T_ALARM_MINUTES
|
||||
SECT5.N7.V20,Int,1758,T_DRY_CYCLE_MINUTES
|
||||
SECT5.N7.V21,Int,1760,T_POWERED_MINUTES
|
||||
SECT5.N7.V22,Int,1762,T_PRODUCT_100_MINUTES
|
||||
SECT5.N7.V23,Int,1764,T_PRODUCT_0_MINUTES
|
||||
SECT5.N7.V24,Int,1766,T_STOP_MINUTES
|
||||
Nombre,Tipo,Offset,Dirección PLC,Comentario
|
||||
MAIN,"""UDT SIPA SV Main""",0,DBX0.0,
|
||||
MAIN.N1,DInt,0,DBD0,.DB_IOT.USERLEVEL
|
||||
MAIN.N2,String[81],4,DBX4.0,.DB_IOT.USERNAME
|
||||
MAIN.N3,String[81],88,DBX88.0,.DB_IOT.NOME_RICETTA
|
||||
MAIN.N4,Int,172,DBW172,.DB_IOT.NEXT_MAINT_CYCLES
|
||||
MAIN.N5.V1,String[254],174,DBX174.0,
|
||||
MAIN.N5.V2,String[254],430,DBX430.0,
|
||||
MAIN.N5.V3,String[254],686,DBX686.0,
|
||||
MAIN.N5.V4,String[254],942,DBX942.0,
|
||||
MAIN.N5.V5,String[8],1198,DBX1198.0,
|
||||
MAIN.N6,Array[1..3] of Real,1208,DBX1208.0,.DB_IOT.ELECTRIC_VOLTAGE_PHASE_D
|
||||
MAIN.N6[1],Real,1208,DBD1208,.DB_IOT.ELECTRIC_VOLTAGE_PHASE_D
|
||||
MAIN.N6[2],Real,1212,DBD1212,.DB_IOT.ELECTRIC_VOLTAGE_PHASE_D
|
||||
MAIN.N6[3],Real,1216,DBD1216,.DB_IOT.ELECTRIC_VOLTAGE_PHASE_D
|
||||
MAIN.N7,Array[1..3] of Real,1220,DBX1220.0,.DB_IOT.ELECTRIC_CURRENT_PHASE_D
|
||||
MAIN.N7[1],Real,1220,DBD1220,.DB_IOT.ELECTRIC_CURRENT_PHASE_D
|
||||
MAIN.N7[2],Real,1224,DBD1224,.DB_IOT.ELECTRIC_CURRENT_PHASE_D
|
||||
MAIN.N7[3],Real,1228,DBD1228,.DB_IOT.ELECTRIC_CURRENT_PHASE_D
|
||||
MAIN.N8,Real,1232,DBD1232,.DB_IOT.ELECTRIC_POWER_D
|
||||
MAIN.N9,Real,1236,DBD1236,.DB_IOT.ELECTRIC_POWER_FACTOR_D
|
||||
MAIN.N10,Real,1240,DBD1240,.DB_IOT.ELECTRIC_POWER_HOUR_D
|
||||
MAIN.N11,Real,1244,DBD1244,.DB_IOT.ELECTRIC_POWER_WH
|
||||
SECT1,"""UDT SIPA SV Section""",1248,DBX1248.0,
|
||||
SECT1.N1,DInt,1664,DBD1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT1.N2,DInt,1668,DBD1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT1.N3,DInt,1672,DBD1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT1.N4,Int,1676,DBW1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT1.N5,Int,1678,DBW1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT1.N6,DInt,1680,DBD1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT1.N7.V1,DInt,1684,DBD1684,PIECES_TOT
|
||||
SECT1.N7.V2,DInt,1688,DBD1688,PIECES_OK
|
||||
SECT1.N7.V3,DInt,1692,DBD1692,PIECES_KO_1
|
||||
SECT1.N7.V4,DInt,1696,DBD1696,PIECES_KO_2
|
||||
SECT1.N7.V5,DInt,1700,DBD1700,PIECES_KO_3
|
||||
SECT1.N7.V6,DInt,1704,DBD1704,PIECES_KO_4
|
||||
SECT1.N7.V7,DInt,1708,DBD1708,PIECES_KO_5
|
||||
SECT1.N7.V8,DInt,1712,DBD1712,PIECES_KO_6
|
||||
SECT1.N7.V9,DInt,1716,DBD1716,PIECES_KO_7
|
||||
SECT1.N7.V10,DInt,1720,DBD1720,PIECES_KO_8
|
||||
SECT1.N7.V11,DInt,1724,DBD1724,PIECES_KO_9
|
||||
SECT1.N7.V12,DInt,1728,DBD1728,PIECES_KO_10
|
||||
SECT1.N7.V13,DInt,1732,DBD1732,T_ALARM_HOURS
|
||||
SECT1.N7.V14,DInt,1736,DBD1736,T_DRY_CYCLE_HOURS
|
||||
SECT1.N7.V15,DInt,1740,DBD1740,T_POWERED_HOURS
|
||||
SECT1.N7.V16,DInt,1744,DBD1744,T_PRODUCT_100_HOURS
|
||||
SECT1.N7.V17,DInt,1748,DBD1748,T_PRODUCT_0_HOURS
|
||||
SECT1.N7.V18,DInt,1752,DBD1752,T_STOP_HOURS
|
||||
SECT1.N7.V19,Int,1756,DBW1756,T_ALARM_MINUTES
|
||||
SECT1.N7.V20,Int,1758,DBW1758,T_DRY_CYCLE_MINUTES
|
||||
SECT1.N7.V21,Int,1760,DBW1760,T_POWERED_MINUTES
|
||||
SECT1.N7.V22,Int,1762,DBW1762,T_PRODUCT_100_MINUTES
|
||||
SECT1.N7.V23,Int,1764,DBW1764,T_PRODUCT_0_MINUTES
|
||||
SECT1.N7.V24,Int,1766,DBW1766,T_STOP_MINUTES
|
||||
SECT2,"""UDT SIPA SV Section""",1352,DBX1352.0,
|
||||
SECT2.N1,DInt,1664,DBD1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT2.N2,DInt,1668,DBD1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT2.N3,DInt,1672,DBD1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT2.N4,Int,1676,DBW1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT2.N5,Int,1678,DBW1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT2.N6,DInt,1680,DBD1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT2.N7.V1,DInt,1684,DBD1684,PIECES_TOT
|
||||
SECT2.N7.V2,DInt,1688,DBD1688,PIECES_OK
|
||||
SECT2.N7.V3,DInt,1692,DBD1692,PIECES_KO_1
|
||||
SECT2.N7.V4,DInt,1696,DBD1696,PIECES_KO_2
|
||||
SECT2.N7.V5,DInt,1700,DBD1700,PIECES_KO_3
|
||||
SECT2.N7.V6,DInt,1704,DBD1704,PIECES_KO_4
|
||||
SECT2.N7.V7,DInt,1708,DBD1708,PIECES_KO_5
|
||||
SECT2.N7.V8,DInt,1712,DBD1712,PIECES_KO_6
|
||||
SECT2.N7.V9,DInt,1716,DBD1716,PIECES_KO_7
|
||||
SECT2.N7.V10,DInt,1720,DBD1720,PIECES_KO_8
|
||||
SECT2.N7.V11,DInt,1724,DBD1724,PIECES_KO_9
|
||||
SECT2.N7.V12,DInt,1728,DBD1728,PIECES_KO_10
|
||||
SECT2.N7.V13,DInt,1732,DBD1732,T_ALARM_HOURS
|
||||
SECT2.N7.V14,DInt,1736,DBD1736,T_DRY_CYCLE_HOURS
|
||||
SECT2.N7.V15,DInt,1740,DBD1740,T_POWERED_HOURS
|
||||
SECT2.N7.V16,DInt,1744,DBD1744,T_PRODUCT_100_HOURS
|
||||
SECT2.N7.V17,DInt,1748,DBD1748,T_PRODUCT_0_HOURS
|
||||
SECT2.N7.V18,DInt,1752,DBD1752,T_STOP_HOURS
|
||||
SECT2.N7.V19,Int,1756,DBW1756,T_ALARM_MINUTES
|
||||
SECT2.N7.V20,Int,1758,DBW1758,T_DRY_CYCLE_MINUTES
|
||||
SECT2.N7.V21,Int,1760,DBW1760,T_POWERED_MINUTES
|
||||
SECT2.N7.V22,Int,1762,DBW1762,T_PRODUCT_100_MINUTES
|
||||
SECT2.N7.V23,Int,1764,DBW1764,T_PRODUCT_0_MINUTES
|
||||
SECT2.N7.V24,Int,1766,DBW1766,T_STOP_MINUTES
|
||||
SECT3,"""UDT SIPA SV Section""",1456,DBX1456.0,
|
||||
SECT3.N1,DInt,1664,DBD1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT3.N2,DInt,1668,DBD1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT3.N3,DInt,1672,DBD1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT3.N4,Int,1676,DBW1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT3.N5,Int,1678,DBW1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT3.N6,DInt,1680,DBD1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT3.N7.V1,DInt,1684,DBD1684,PIECES_TOT
|
||||
SECT3.N7.V2,DInt,1688,DBD1688,PIECES_OK
|
||||
SECT3.N7.V3,DInt,1692,DBD1692,PIECES_KO_1
|
||||
SECT3.N7.V4,DInt,1696,DBD1696,PIECES_KO_2
|
||||
SECT3.N7.V5,DInt,1700,DBD1700,PIECES_KO_3
|
||||
SECT3.N7.V6,DInt,1704,DBD1704,PIECES_KO_4
|
||||
SECT3.N7.V7,DInt,1708,DBD1708,PIECES_KO_5
|
||||
SECT3.N7.V8,DInt,1712,DBD1712,PIECES_KO_6
|
||||
SECT3.N7.V9,DInt,1716,DBD1716,PIECES_KO_7
|
||||
SECT3.N7.V10,DInt,1720,DBD1720,PIECES_KO_8
|
||||
SECT3.N7.V11,DInt,1724,DBD1724,PIECES_KO_9
|
||||
SECT3.N7.V12,DInt,1728,DBD1728,PIECES_KO_10
|
||||
SECT3.N7.V13,DInt,1732,DBD1732,T_ALARM_HOURS
|
||||
SECT3.N7.V14,DInt,1736,DBD1736,T_DRY_CYCLE_HOURS
|
||||
SECT3.N7.V15,DInt,1740,DBD1740,T_POWERED_HOURS
|
||||
SECT3.N7.V16,DInt,1744,DBD1744,T_PRODUCT_100_HOURS
|
||||
SECT3.N7.V17,DInt,1748,DBD1748,T_PRODUCT_0_HOURS
|
||||
SECT3.N7.V18,DInt,1752,DBD1752,T_STOP_HOURS
|
||||
SECT3.N7.V19,Int,1756,DBW1756,T_ALARM_MINUTES
|
||||
SECT3.N7.V20,Int,1758,DBW1758,T_DRY_CYCLE_MINUTES
|
||||
SECT3.N7.V21,Int,1760,DBW1760,T_POWERED_MINUTES
|
||||
SECT3.N7.V22,Int,1762,DBW1762,T_PRODUCT_100_MINUTES
|
||||
SECT3.N7.V23,Int,1764,DBW1764,T_PRODUCT_0_MINUTES
|
||||
SECT3.N7.V24,Int,1766,DBW1766,T_STOP_MINUTES
|
||||
SECT4,"""UDT SIPA SV Section""",1560,DBX1560.0,
|
||||
SECT4.N1,DInt,1664,DBD1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT4.N2,DInt,1668,DBD1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT4.N3,DInt,1672,DBD1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT4.N4,Int,1676,DBW1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT4.N5,Int,1678,DBW1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT4.N6,DInt,1680,DBD1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT4.N7.V1,DInt,1684,DBD1684,PIECES_TOT
|
||||
SECT4.N7.V2,DInt,1688,DBD1688,PIECES_OK
|
||||
SECT4.N7.V3,DInt,1692,DBD1692,PIECES_KO_1
|
||||
SECT4.N7.V4,DInt,1696,DBD1696,PIECES_KO_2
|
||||
SECT4.N7.V5,DInt,1700,DBD1700,PIECES_KO_3
|
||||
SECT4.N7.V6,DInt,1704,DBD1704,PIECES_KO_4
|
||||
SECT4.N7.V7,DInt,1708,DBD1708,PIECES_KO_5
|
||||
SECT4.N7.V8,DInt,1712,DBD1712,PIECES_KO_6
|
||||
SECT4.N7.V9,DInt,1716,DBD1716,PIECES_KO_7
|
||||
SECT4.N7.V10,DInt,1720,DBD1720,PIECES_KO_8
|
||||
SECT4.N7.V11,DInt,1724,DBD1724,PIECES_KO_9
|
||||
SECT4.N7.V12,DInt,1728,DBD1728,PIECES_KO_10
|
||||
SECT4.N7.V13,DInt,1732,DBD1732,T_ALARM_HOURS
|
||||
SECT4.N7.V14,DInt,1736,DBD1736,T_DRY_CYCLE_HOURS
|
||||
SECT4.N7.V15,DInt,1740,DBD1740,T_POWERED_HOURS
|
||||
SECT4.N7.V16,DInt,1744,DBD1744,T_PRODUCT_100_HOURS
|
||||
SECT4.N7.V17,DInt,1748,DBD1748,T_PRODUCT_0_HOURS
|
||||
SECT4.N7.V18,DInt,1752,DBD1752,T_STOP_HOURS
|
||||
SECT4.N7.V19,Int,1756,DBW1756,T_ALARM_MINUTES
|
||||
SECT4.N7.V20,Int,1758,DBW1758,T_DRY_CYCLE_MINUTES
|
||||
SECT4.N7.V21,Int,1760,DBW1760,T_POWERED_MINUTES
|
||||
SECT4.N7.V22,Int,1762,DBW1762,T_PRODUCT_100_MINUTES
|
||||
SECT4.N7.V23,Int,1764,DBW1764,T_PRODUCT_0_MINUTES
|
||||
SECT4.N7.V24,Int,1766,DBW1766,T_STOP_MINUTES
|
||||
SECT5,"""UDT SIPA SV Section""",1664,DBX1664.0,
|
||||
SECT5.N1,DInt,1664,DBD1664,.DB_IOT.STATO_MACCHINA
|
||||
SECT5.N2,DInt,1668,DBD1668,.DB_IOT.ALLARME_FERMO
|
||||
SECT5.N3,DInt,1672,DBD1672,.DB_IOT.WARNING_ATTIVO (che compromette produzione)
|
||||
SECT5.N4,Int,1676,DBW1676,.DB_IOT.STATO_OPERATIVO (Semaforo)
|
||||
SECT5.N5,Int,1678,DBW1678,".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)"
|
||||
SECT5.N6,DInt,1680,DBD1680,.DB_IOT.ALARM_STOP_NO
|
||||
SECT5.N7.V1,DInt,1684,DBD1684,PIECES_TOT
|
||||
SECT5.N7.V2,DInt,1688,DBD1688,PIECES_OK
|
||||
SECT5.N7.V3,DInt,1692,DBD1692,PIECES_KO_1
|
||||
SECT5.N7.V4,DInt,1696,DBD1696,PIECES_KO_2
|
||||
SECT5.N7.V5,DInt,1700,DBD1700,PIECES_KO_3
|
||||
SECT5.N7.V6,DInt,1704,DBD1704,PIECES_KO_4
|
||||
SECT5.N7.V7,DInt,1708,DBD1708,PIECES_KO_5
|
||||
SECT5.N7.V8,DInt,1712,DBD1712,PIECES_KO_6
|
||||
SECT5.N7.V9,DInt,1716,DBD1716,PIECES_KO_7
|
||||
SECT5.N7.V10,DInt,1720,DBD1720,PIECES_KO_8
|
||||
SECT5.N7.V11,DInt,1724,DBD1724,PIECES_KO_9
|
||||
SECT5.N7.V12,DInt,1728,DBD1728,PIECES_KO_10
|
||||
SECT5.N7.V13,DInt,1732,DBD1732,T_ALARM_HOURS
|
||||
SECT5.N7.V14,DInt,1736,DBD1736,T_DRY_CYCLE_HOURS
|
||||
SECT5.N7.V15,DInt,1740,DBD1740,T_POWERED_HOURS
|
||||
SECT5.N7.V16,DInt,1744,DBD1744,T_PRODUCT_100_HOURS
|
||||
SECT5.N7.V17,DInt,1748,DBD1748,T_PRODUCT_0_HOURS
|
||||
SECT5.N7.V18,DInt,1752,DBD1752,T_STOP_HOURS
|
||||
SECT5.N7.V19,Int,1756,DBW1756,T_ALARM_MINUTES
|
||||
SECT5.N7.V20,Int,1758,DBW1758,T_DRY_CYCLE_MINUTES
|
||||
SECT5.N7.V21,Int,1760,DBW1760,T_POWERED_MINUTES
|
||||
SECT5.N7.V22,Int,1762,DBW1762,T_PRODUCT_100_MINUTES
|
||||
SECT5.N7.V23,Int,1764,DBW1764,T_PRODUCT_0_MINUTES
|
||||
SECT5.N7.V24,Int,1766,DBW1766,T_STOP_MINUTES
|
||||
|
|
|
Binary file not shown.
251
DB_Structure.xml
251
DB_Structure.xml
File diff suppressed because it is too large
Load Diff
76
ExpandDB.py
76
ExpandDB.py
|
@ -29,29 +29,41 @@ def expand_udt_references(db_struct, udts):
|
|||
|
||||
def handle_array_types(db_struct):
|
||||
"""
|
||||
Handle array types once all UDTs are expanded.
|
||||
This function modifies the structure in place.
|
||||
Handle array types to expand them into multiple fields as sub-elements while preserving comments.
|
||||
Modifies the structure in place by expanding array definitions within their original field.
|
||||
"""
|
||||
if isinstance(db_struct, dict):
|
||||
for key, value in list(db_struct.items()):
|
||||
if isinstance(value, dict):
|
||||
# Recursively process nested dictionaries
|
||||
handle_array_types(value)
|
||||
elif isinstance(value, str):
|
||||
# Parsing array definitions, e.g., "Array[1..3] of Real"
|
||||
match = re.match(r"Array\[(\d+)\.\.(\d+)\] of (\w+)", value)
|
||||
|
||||
if isinstance(value, dict) and 'type' in value:
|
||||
match = re.match(r"Array\[(\d+)\.\.(\d+)\] of (\w+)", value['type'])
|
||||
if match:
|
||||
lower_bound, upper_bound, base_type = (
|
||||
int(match.group(1)),
|
||||
int(match.group(2)),
|
||||
match.group(3),
|
||||
)
|
||||
# Expand this field into multiple fields
|
||||
db_struct.pop(key) # Remove the original field
|
||||
lower_bound, upper_bound, base_type = int(match.group(1)), int(match.group(2)), match.group(3)
|
||||
comment = value.get('comment', '')
|
||||
|
||||
# Instead of popping the original key, initialize a sub-dictionary
|
||||
value['Array'] = {} # Initialize a sub-dictionary for array elements
|
||||
|
||||
for i in range(lower_bound, upper_bound + 1):
|
||||
db_struct[f"{key}_{i}"] = {"type": base_type, 'is_array_element': True}
|
||||
print(
|
||||
f"Expanded field '{key}' into array fields: {key}_{lower_bound} to {key}_{upper_bound} of type {base_type}"
|
||||
)
|
||||
element_key = f"[{i}]"
|
||||
value['Array'][element_key] = {
|
||||
'type': base_type,
|
||||
'comment': comment,
|
||||
'is_array_element': True
|
||||
}
|
||||
|
||||
# Optionally, modify or remove the original type designation if necessary
|
||||
# value.pop('type', None) # Uncomment this if you want to remove the 'type' from the original
|
||||
|
||||
# Continue the recursive handling if it's not an array definition
|
||||
elif isinstance(value, dict):
|
||||
handle_array_types(value)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
type_sizes = {
|
||||
|
@ -64,11 +76,31 @@ type_sizes = {
|
|||
}
|
||||
|
||||
|
||||
def calculate_plc_address(type_name, byte_offset, bit_offset=None):
|
||||
"""
|
||||
Calculate the PLC address notation based on byte size, byte offset and bit offset.
|
||||
"""
|
||||
byte_size = type_sizes.get(
|
||||
type_name, 0
|
||||
)
|
||||
if type_name == "Bool":
|
||||
if bit_offset is not None:
|
||||
return f"DBX{byte_offset}.{bit_offset}" # Address for single bits
|
||||
return f"DBB{byte_offset}" # Address for single bytes
|
||||
elif byte_size == 2:
|
||||
return f"DBW{byte_offset}" # Address for two-byte words
|
||||
elif byte_size == 4:
|
||||
return f"DBD{byte_offset}" # Address for four-byte double words
|
||||
else:
|
||||
return f"DBX{byte_offset}.0" # Default to bit address for types longer than 4 bytes (e.g., strings)
|
||||
|
||||
|
||||
def calculate_offsets(db_struct, current_offset=0, parent=None):
|
||||
"""
|
||||
Recursively calculate byte offsets for each field in the DB structure considering special types.
|
||||
"""
|
||||
last_key_was_bool = False
|
||||
last_bit_offset = 0 # To track bit offsets within a byte
|
||||
if isinstance(db_struct, dict):
|
||||
for key, value in list(db_struct.items()):
|
||||
if isinstance(value, dict):
|
||||
|
@ -81,10 +113,18 @@ def calculate_offsets(db_struct, current_offset=0, parent=None):
|
|||
|
||||
if not is_array_element and current_offset % 2 != 0:
|
||||
current_offset += 1 # Align to the next even offset if it's not an array element
|
||||
last_bit_offset = 0
|
||||
|
||||
plc_address = value.get('plc_address', False)
|
||||
if plc_address is not False:
|
||||
print("Address Already Calcolated!")
|
||||
|
||||
plc_address = calculate_plc_address(type_name, current_offset, last_bit_offset)
|
||||
|
||||
# Special handling for String types
|
||||
if "String" in type_name:
|
||||
match = re.match(r"String\[(\d+)\]", type_name)
|
||||
last_bit_offset = 0
|
||||
if match:
|
||||
length = int(match.group(1))
|
||||
size = length + 2 # Account for null-termination and string length prefix
|
||||
|
@ -94,14 +134,16 @@ def calculate_offsets(db_struct, current_offset=0, parent=None):
|
|||
# Adjusting Bool sizes based on grouping
|
||||
if type_name == "Bool":
|
||||
if last_key_was_bool: # This is a grouped bool
|
||||
size = 0.125 # One bit per Bool if grouped
|
||||
last_bit_offset += 1 # One bit per Bool if grouped
|
||||
else:
|
||||
size = 2 # Bools use a full byte if not grouped
|
||||
last_bit_offset = 0
|
||||
last_key_was_bool = True
|
||||
else:
|
||||
last_key_was_bool = False
|
||||
|
||||
value["offset"] = current_offset
|
||||
value['plc_address'] = plc_address # Store the calculated PLC address
|
||||
current_offset += size
|
||||
|
||||
current_offset = calculate_offsets(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import xmltodict
|
||||
import pandas as pd
|
||||
|
||||
|
||||
def save_json_to_xml(json_data, filename="DB_Structure.xml"):
|
||||
"""
|
||||
Convert JSON data to XML and save it to a file.
|
||||
|
@ -32,20 +33,30 @@ def collect_data_for_table(db_struct, parent_prefix="", collected_data=[]):
|
|||
Recursively collect data from the DB structure to display in a tabular format,
|
||||
omitting 'fields' and 'Struct' in the names.
|
||||
"""
|
||||
is_array_element = False
|
||||
if isinstance(db_struct, dict):
|
||||
for key, value in db_struct.items():
|
||||
# Skip 'fields' and 'Struct' keys in the name path
|
||||
if key == 'fields' or key == 'Struct':
|
||||
#
|
||||
if key == "fields" or key == "Struct" or key == "Array":
|
||||
next_prefix = parent_prefix # Continue with the current prefix
|
||||
else:
|
||||
next_prefix = f"{parent_prefix}.{key}" if parent_prefix else key
|
||||
if isinstance(value, dict):
|
||||
is_array_element = value.get('is_array_element', False)
|
||||
if not is_array_element:
|
||||
next_prefix = f"{parent_prefix}.{key}" if parent_prefix else key
|
||||
else:
|
||||
next_prefix = f"{parent_prefix}{key}" if parent_prefix else key
|
||||
|
||||
if isinstance(value, dict) and 'type' in value: # Directly a field with 'type'
|
||||
if (
|
||||
isinstance(value, dict) and "type" in value
|
||||
): # Directly a field with 'type'
|
||||
field_data = {
|
||||
"Nombre": next_prefix,
|
||||
"Tipo": value.get('type', 'N/A'),
|
||||
"Offset": value.get('offset', 'N/A'),
|
||||
"Comentario": value.get('comment', 'N/A')
|
||||
"Tipo": value.get("type", "N/A"),
|
||||
"Offset": value.get("offset", "N/A"),
|
||||
"Dirección PLC": value.get("plc_address", "N/A"),
|
||||
"Comentario": value.get("comment", "N/A"),
|
||||
}
|
||||
collected_data.append(field_data)
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue