From 5c904b7a0568a639706f90c70d78e82d0e2fd6f2 Mon Sep 17 00:00:00 2001 From: Miguel Date: Mon, 22 Apr 2024 22:13:43 +0200 Subject: [PATCH] modified: .gitignore modified: CopyPaste.py new file: CreateTable.py deleted: DB_SIPA_Supervision_Excel.xlsx modified: DB_Structure.csv new file: DB_Structure.jon modified: DB_Structure.xlsx modified: DB_Structure.xml modified: DB_to_Excel.py new file: Data_block_1.db modified: ExpandDB.py deleted: ExportData.py modified: __pycache__/ExpandDB.cpython-310.pyc modified: __pycache__/ExportData.cpython-310.pyc deleted: db_definitions.json new file: manejoArchivos.py deleted: udt_definitions.json --- .gitignore | 2 + CopyPaste.py | 51 +- CreateTable.py | 244 ++ DB_SIPA_Supervision_Excel.xlsx | Bin 9180 -> 0 bytes DB_Structure.csv | 440 ++-- DB_Structure.jon | 780 ++++++ DB_Structure.xlsx | Bin 11669 -> 14396 bytes DB_Structure.xml | 3180 ++++++++++++++++-------- DB_to_Excel.py | 50 +- Data_block_1.db | 73 + ExpandDB.py | 102 +- ExportData.py | 85 - __pycache__/ExpandDB.cpython-310.pyc | Bin 3783 -> 2321 bytes __pycache__/ExportData.cpython-310.pyc | Bin 2393 -> 4027 bytes db_definitions.json | 30 - manejoArchivos.py | 37 + udt_definitions.json | 194 -- 17 files changed, 3550 insertions(+), 1718 deletions(-) create mode 100644 CreateTable.py delete mode 100644 DB_SIPA_Supervision_Excel.xlsx create mode 100644 DB_Structure.jon create mode 100644 Data_block_1.db delete mode 100644 ExportData.py delete mode 100644 db_definitions.json create mode 100644 manejoArchivos.py delete mode 100644 udt_definitions.json diff --git a/.gitignore b/.gitignore index 68bc17f..6352b51 100644 --- a/.gitignore +++ b/.gitignore @@ -158,3 +158,5 @@ cython_debug/ # 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/ + +CopyPaste.py \ No newline at end of file diff --git a/CopyPaste.py b/CopyPaste.py index 7ab7b55..d1faf1a 100644 --- a/CopyPaste.py +++ b/CopyPaste.py @@ -1,19 +1,36 @@ -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): - if "type" in value and not "offset" in value: +import os +import subprocess +import tkinter as tk +from tkinter import filedialog - current_offset = calculate_offsets( - value, current_offset, value - ) # Recurse into nested structs +def select_file(): + """ + Opens a file dialog to select a .db file and returns the selected file path. + """ + root = tk.Tk() + root.withdraw() # Use to hide the tkinter root window - elif isinstance(db_struct, list): - for item in db_struct: - current_offset = calculate_offsets(item, current_offset, parent) - return current_offset \ No newline at end of file + # Open file dialog and return the selected file path + file_path = filedialog.askopenfilename( + title="Select a .db file", + filetypes=(("DB files", "*.db"), ("All files", "*.*")) + ) + return file_path + + + +if __name__ == "__main__": + file_path = select_file() + if file_path: # Proceed only if a file was selected + with open(file_path, "r", encoding="utf-8-sig") as file: + lines = file.readlines() + + udt_json = parse_udts(lines) + # Assume processing and file generation happens here, e.g., creating `output.txt` + output_file_path = os.path.join(os.path.dirname(file_path), "output.txt") + # Save or manipulate output files as needed + + # Open the directory containing the new file in Explorer + open_file_explorer(os.path.dirname(output_file_path)) + else: + print("No file was selected.") diff --git a/CreateTable.py b/CreateTable.py new file mode 100644 index 0000000..9484242 --- /dev/null +++ b/CreateTable.py @@ -0,0 +1,244 @@ +import xmltodict +import pandas as pd +import re +import sys + +def save_json_to_xml(json_data, filename="DB_Structure.xml"): + """ + Convert JSON data to XML and save it to a file. + """ + xml_data = xmltodict.unparse({"root": json_data}, pretty=True) + with open(filename, "w") as xml_file: + xml_file.write(xml_data) + print(f"XML data saved to {filename}") + + +def save_dataframe_to_excel(df, filename="DB_Structure.xlsx"): + """ + Save the provided DataFrame to an Excel file. + """ + df.to_excel(filename, index=False) + print(f"Data saved to {filename}") + + +def save_dataframe_to_file(df, filename="DB_Structure.csv"): + """ + Save the provided DataFrame to a CSV file. + """ + df.to_csv(filename, index=False) + print(f"Data saved to {filename}") + + +type_sizes = { + "Byte": 1, + "Char": 1, + "Int": 2, + "DInt": 4, + "Word": 2, + "DWord": 4, + "Real": 4, + "Date": 2, + "Time": 4, + "Time_Of_Day": 4, + "S5Time": 2, + "Bool": 0.125, # Recuerda, esto significa 1 bit, pero es comúnmente agrupado en 8 bits = 1 Byte + "String": 256, # Especificar si es necesario como String[256] que serían 258 bytes (256 caracteres + 2 de longitud) + "WString": 512, + "LReal": 8, # Doble precisión de punto flotante + "UDInt": 4, # Entero sin signo de 32 bits + "USInt": 1, # Entero sin signo de 8 bits (Byte) + "UInt": 2, # Entero sin signo de 16 bits (Word) + "ULInt": 8, # Entero sin signo de 64 bits (Doble DWord) + "LWord": 8, # Entero sin signo de 64 bits (Doble DWord) + "LInt": 8, # Entero con signo de 64 bits + "Date_And_Time": 8, # Fecha y hora combinadas, 8 bytes + "DTL": 12, # Date and time long (fecha, hora y precisión a microsegundos, 12 bytes) +} + + +def calculate_plc_address(type_name, byte_offset): + """ + Calculate the PLC address notation based on byte size, byte offset and bit offset. + """ + byte_size = type_sizes.get(type_name, 0) + bit_offset = int((byte_offset - int(byte_offset)) * 8) + byte_offset = int(byte_offset) + 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 type_name == "Byte": + return f"DBB{byte_offset}" # Address for two-byte words + 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_plc_size(size): + byte_size = size + bit_offset = int((size - int(size)) * 8) + size = int(size) + if bit_offset > 0: + return f"{size}.{bit_offset}" + else: + return f"{size}" + + +class OffsetState: + last_key_was_bool = False + last_bit_offset = 0 # To track bit offsets within a byte + current_offset = 0 + + +def calculate_offsets(value, state): + + type_name = value["type"] + is_array_element = value.get("is_array_element", False) + is_array_definition = value.get("array_definition", False) + is_udt_definition = value.get("is_udt_definition", False) + + if state.last_key_was_bool: + is_array_element = True + size = 0 + + if not is_array_element: + if state.current_offset % 2 != 0: + state.current_offset += ( + 1 # Align to the next even offset if it's not an array element + ) + + # Adjusting Bool sizes based on grouping + if type_name == "Bool": + state.last_key_was_bool = True + size += 1 / 8 + + else: + if state.last_key_was_bool: # After bools + state.last_key_was_bool = False ## Not Bool + if ( + state.last_bit_offset > 0 + or int(state.current_offset) != state.current_offset + ): + state.last_bit_offset = 0 + state.current_offset = int(state.current_offset) + 1 + if state.current_offset % 2 != 0: + state.current_offset += ( + 1 # Align to the next even offset if it's not an array element + ) + + # Special handling for String types + if type_name.startswith("String"): + match = re.match(r"String\[(\d+)\]", type_name) + state.last_bit_offset = 0 + if match: + length = int(match.group(1)) + size = ( + length + 2 + ) # Account for null-termination and string length prefix + else: + size = type_sizes.get(type_name, 0) ## Standar size for strings + + else: ## Other Data Types + if is_array_definition: + size = 0 + if state.current_offset % 2 != 0: + state.current_offset += ( + 1 # Align to the next even offset if it's not an array element + ) + else: + size = type_sizes.get( + type_name, -1 + ) # Default to 1 byte if type is not recognized + + if size == -1 and not is_udt_definition: + print(f"UDT o DataType '{type_name}' no encontrado. Abortando.") + sys.exit() + + plc_address = calculate_plc_address(type_name, state.current_offset) + value["offset"] = int(state.current_offset) + value["plc_address"] = plc_address # Store the calculated PLC address + value["size"] = calculate_plc_size(size) + # print(f"Offset '{state.current_offset}' at field '{key}' ") + state.current_offset += size + return state + + +def collect_data_for_table( + db_struct, offset_state, level=0, 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 + increase_level = 0 + + 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" or key == "Array": + next_prefix = parent_prefix # Continue with the current prefix + else: + 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' + offset_state = calculate_offsets(value, offset_state) + field_data = { + "Nombre": next_prefix, + "Tipo": value.get("type", "N/A"), + "Offset": value.get("offset", "N/A"), + "Size": value.get("size", "N/A"), + "Level": level, + "Dirección PLC": value.get("plc_address", "N/A"), + "Comentario": value.get("comment", "N/A"), + } + collected_data.append(field_data) + increase_level = 1 + + # Recursively handle nested dictionaries and lists + if isinstance(value, dict) or isinstance(value, list): + collect_data_for_table( + value, + offset_state, + level + increase_level, + next_prefix, + collected_data, + ) + elif isinstance(db_struct, list): + for index, item in enumerate(db_struct): + item_prefix = f"{parent_prefix}[{index}]" if parent_prefix else f"[{index}]" + collect_data_for_table( + item, offset_state, level + increase_level, item_prefix, collected_data + ) + + return collected_data + + +def convert_to_table(db_struct): + offset_state = OffsetState() + return collect_data_for_table(db_struct, offset_state) + + +def display_as_table(dbs): + """ + Convert collected DB data into a pandas DataFrame and display it. + """ + all_data = [] + for db_name, db_content in dbs.items(): + print(f"Processing DB: {db_name}") + db_data = convert_to_table(db_content) + all_data.extend(db_data) + + df = pd.DataFrame(all_data) + return df diff --git a/DB_SIPA_Supervision_Excel.xlsx b/DB_SIPA_Supervision_Excel.xlsx deleted file mode 100644 index 48e46d637fab00c463b03cbb90b1e5000078a87a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9180 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 diff --git a/DB_Structure.xml b/DB_Structure.xml index 68c2727..090ec87 100644 --- a/DB_Structure.xml +++ b/DB_Structure.xml @@ -1,1115 +1,2097 @@ - + -
- "UDT SIPA SV Main" + + Array[1..8] of Byte - - - - DInt - .DB_IOT.USERLEVEL - 0 - DBD0 - - - String[81] - .DB_IOT.USERNAME - 4 - DBX4.0 - - - String[81] - .DB_IOT.NOME_RICETTA - 88 - DBX88.0 - - - Int - .DB_IOT.NEXT_MAINT_CYCLES - 172 - DBW172 - - - - String[254] - - 174 - DBX174.0 - - - String[254] - - 430 - DBX430.0 - - - String[254] - - 686 - DBX686.0 - - - String[254] - - 942 - DBX942.0 - - - String[8] - - 1198 - DBX1198.0 - - - - Array[1..3] of Real - .DB_IOT.ELECTRIC_VOLTAGE_PHASE_D - - <[1]> - Real - .DB_IOT.ELECTRIC_VOLTAGE_PHASE_D - true - 1208 - DBD1208 - - <[2]> - Real - .DB_IOT.ELECTRIC_VOLTAGE_PHASE_D - true - 1212 - DBD1212 - - <[3]> - Real - .DB_IOT.ELECTRIC_VOLTAGE_PHASE_D - true - 1216 - DBD1216 - - - 1208 - DBX1208.0 - - - Array[1..3] of Real - .DB_IOT.ELECTRIC_CURRENT_PHASE_D - - <[1]> - Real - .DB_IOT.ELECTRIC_CURRENT_PHASE_D - true - 1220 - DBD1220 - - <[2]> - Real - .DB_IOT.ELECTRIC_CURRENT_PHASE_D - true - 1224 - DBD1224 - - <[3]> - Real - .DB_IOT.ELECTRIC_CURRENT_PHASE_D - true - 1228 - DBD1228 - - - 1220 - DBX1220.0 - - - Real - .DB_IOT.ELECTRIC_POWER_D - 1232 - DBD1232 - - - Real - .DB_IOT.ELECTRIC_POWER_FACTOR_D - 1236 - DBD1236 - - - Real - .DB_IOT.ELECTRIC_POWER_HOUR_D - 1240 - DBD1240 - - - Real - .DB_IOT.ELECTRIC_POWER_WH - 1244 - DBD1244 - - - + true + + <[1]> + Byte + + true + 0 + DBB0 + 1 + + <[2]> + Byte + + true + 1 + DBB1 + 1 + + <[3]> + Byte + + true + 2 + DBB2 + 1 + + <[4]> + Byte + + true + 3 + DBB3 + 1 + + <[5]> + Byte + + true + 4 + DBB4 + 1 + + <[6]> + Byte + + true + 5 + DBB5 + 1 + + <[7]> + Byte + + true + 6 + DBB6 + 1 + + <[8]> + Byte + + true + 7 + DBB7 + 1 + + 0 DBX0.0 -
- - "UDT SIPA SV Section" + 0 + + + Bool + 8 + DBX8.0 + 0.1 + + + Bool + + 8 + DBX8.1 + 0.1 + + + S5Time + + 10 + DBW10 + 2 + + + LInt + + 12 + DBX12.0 + 8 + + + WString + + 20 + DBX20.0 + 512 + + + UInt + + 532 + DBW532 + 2 + + + LReal + + 534 + DBX534.0 + 8 + + + Int + + 542 + DBW542 + 2 + + + Array[0..15] of Bool + + true + + <[0]> + Bool + + true + 544 + DBX544.0 + 0.1 + + <[1]> + Bool + + true + 544 + DBX544.1 + 0.1 + + <[2]> + Bool + + true + 544 + DBX544.2 + 0.1 + + <[3]> + Bool + + true + 544 + DBX544.3 + 0.1 + + <[4]> + Bool + + true + 544 + DBX544.4 + 0.1 + + <[5]> + Bool + + true + 544 + DBX544.5 + 0.1 + + <[6]> + Bool + + true + 544 + DBX544.6 + 0.1 + + <[7]> + Bool + + true + 544 + DBX544.7 + 0.1 + + <[8]> + Bool + + true + 545 + DBX545.0 + 0.1 + + <[9]> + Bool + + true + 545 + DBX545.1 + 0.1 + + <[10]> + Bool + + true + 545 + DBX545.2 + 0.1 + + <[11]> + Bool + + true + 545 + DBX545.3 + 0.1 + + <[12]> + Bool + + true + 545 + DBX545.4 + 0.1 + + <[13]> + Bool + + true + 545 + DBX545.5 + 0.1 + + <[14]> + Bool + + true + 545 + DBX545.6 + 0.1 + + <[15]> + Bool + + true + 545 + DBX545.7 + 0.1 + + + 544 + DBX544.0 + 0 + + + Array[0..11] of Bool + + true + + <[0]> + Bool + + true + 546 + DBX546.0 + 0.1 + + <[1]> + Bool + + true + 546 + DBX546.1 + 0.1 + + <[2]> + Bool + + true + 546 + DBX546.2 + 0.1 + + <[3]> + Bool + + true + 546 + DBX546.3 + 0.1 + + <[4]> + Bool + + true + 546 + DBX546.4 + 0.1 + + <[5]> + Bool + + true + 546 + DBX546.5 + 0.1 + + <[6]> + Bool + + true + 546 + DBX546.6 + 0.1 + + <[7]> + Bool + + true + 546 + DBX546.7 + 0.1 + + <[8]> + Bool + + true + 547 + DBX547.0 + 0.1 + + <[9]> + Bool + + true + 547 + DBX547.1 + 0.1 + + <[10]> + Bool + + true + 547 + DBX547.2 + 0.1 + + <[11]> + Bool + + true + 547 + DBX547.3 + 0.1 + + + 546 + DBX546.0 + 0 + + <"Udt"> + "UDT Complicada" + + true - - DInt - .DB_IOT.STATO_MACCHINA - 1248 - DBD1248 - - - DInt - .DB_IOT.ALLARME_FERMO - 1252 - DBD1252 - - - DInt - .DB_IOT.WARNING_ATTIVO (che compromette produzione) - 1256 - DBD1256 - - + <"String"> + String + + 548 + DBX548.0 + 256 + + + String[60] + + 804 + DBX804.0 + 62 + + <"Bool"> + Bool + + 866 + DBX866.0 + 0.1 + + + Array[0..1] of Bool + + true + + <[0]> + Bool + + true + 868 + DBX868.0 + 0.1 + + <[1]> + Bool + + true + 868 + DBX868.1 + 0.1 + + + 868 + DBX868.0 + 0 + + + Array[0..51] of Bool + + true + + <[0]> + Bool + + true + 870 + DBX870.0 + 0.1 + + <[1]> + Bool + + true + 870 + DBX870.1 + 0.1 + + <[2]> + Bool + + true + 870 + DBX870.2 + 0.1 + + <[3]> + Bool + + true + 870 + DBX870.3 + 0.1 + + <[4]> + Bool + + true + 870 + DBX870.4 + 0.1 + + <[5]> + Bool + + true + 870 + DBX870.5 + 0.1 + + <[6]> + Bool + + true + 870 + DBX870.6 + 0.1 + + <[7]> + Bool + + true + 870 + DBX870.7 + 0.1 + + <[8]> + Bool + + true + 871 + DBX871.0 + 0.1 + + <[9]> + Bool + + true + 871 + DBX871.1 + 0.1 + + <[10]> + Bool + + true + 871 + DBX871.2 + 0.1 + + <[11]> + Bool + + true + 871 + DBX871.3 + 0.1 + + <[12]> + Bool + + true + 871 + DBX871.4 + 0.1 + + <[13]> + Bool + + true + 871 + DBX871.5 + 0.1 + + <[14]> + Bool + + true + 871 + DBX871.6 + 0.1 + + <[15]> + Bool + + true + 871 + DBX871.7 + 0.1 + + <[16]> + Bool + + true + 872 + DBX872.0 + 0.1 + + <[17]> + Bool + + true + 872 + DBX872.1 + 0.1 + + <[18]> + Bool + + true + 872 + DBX872.2 + 0.1 + + <[19]> + Bool + + true + 872 + DBX872.3 + 0.1 + + <[20]> + Bool + + true + 872 + DBX872.4 + 0.1 + + <[21]> + Bool + + true + 872 + DBX872.5 + 0.1 + + <[22]> + Bool + + true + 872 + DBX872.6 + 0.1 + + <[23]> + Bool + + true + 872 + DBX872.7 + 0.1 + + <[24]> + Bool + + true + 873 + DBX873.0 + 0.1 + + <[25]> + Bool + + true + 873 + DBX873.1 + 0.1 + + <[26]> + Bool + + true + 873 + DBX873.2 + 0.1 + + <[27]> + Bool + + true + 873 + DBX873.3 + 0.1 + + <[28]> + Bool + + true + 873 + DBX873.4 + 0.1 + + <[29]> + Bool + + true + 873 + DBX873.5 + 0.1 + + <[30]> + Bool + + true + 873 + DBX873.6 + 0.1 + + <[31]> + Bool + + true + 873 + DBX873.7 + 0.1 + + <[32]> + Bool + + true + 874 + DBX874.0 + 0.1 + + <[33]> + Bool + + true + 874 + DBX874.1 + 0.1 + + <[34]> + Bool + + true + 874 + DBX874.2 + 0.1 + + <[35]> + Bool + + true + 874 + DBX874.3 + 0.1 + + <[36]> + Bool + + true + 874 + DBX874.4 + 0.1 + + <[37]> + Bool + + true + 874 + DBX874.5 + 0.1 + + <[38]> + Bool + + true + 874 + DBX874.6 + 0.1 + + <[39]> + Bool + + true + 874 + DBX874.7 + 0.1 + + <[40]> + Bool + + true + 875 + DBX875.0 + 0.1 + + <[41]> + Bool + + true + 875 + DBX875.1 + 0.1 + + <[42]> + Bool + + true + 875 + DBX875.2 + 0.1 + + <[43]> + Bool + + true + 875 + DBX875.3 + 0.1 + + <[44]> + Bool + + true + 875 + DBX875.4 + 0.1 + + <[45]> + Bool + + true + 875 + DBX875.5 + 0.1 + + <[46]> + Bool + + true + 875 + DBX875.6 + 0.1 + + <[47]> + Bool + + true + 875 + DBX875.7 + 0.1 + + <[48]> + Bool + + true + 876 + DBX876.0 + 0.1 + + <[49]> + Bool + + true + 876 + DBX876.1 + 0.1 + + <[50]> + Bool + + true + 876 + DBX876.2 + 0.1 + + <[51]> + Bool + + true + 876 + DBX876.3 + 0.1 + + + 870 + DBX870.0 + 0 + + <"Int"> Int - .DB_IOT.STATO_OPERATIVO (Semaforo) - 1260 - DBW1260 - - + + 878 + DBW878 + 2 + + <"Hola como Estas"> Int - .DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc) - 1262 - DBW1262 - - - DInt - .DB_IOT.ALARM_STOP_NO + + 880 + DBW880 + 2 + + <"No se"> + Int + + 882 + DBW882 + 2 + + <"Real"> + Array[0..10] of Real + + true + + <[0]> + Real + + true + 884 + DBD884 + 4 + + <[1]> + Real + + true + 888 + DBD888 + 4 + + <[2]> + Real + + true + 892 + DBD892 + 4 + + <[3]> + Real + + true + 896 + DBD896 + 4 + + <[4]> + Real + + true + 900 + DBD900 + 4 + + <[5]> + Real + + true + 904 + DBD904 + 4 + + <[6]> + Real + + true + 908 + DBD908 + 4 + + <[7]> + Real + + true + 912 + DBD912 + 4 + + <[8]> + Real + + true + 916 + DBD916 + 4 + + <[9]> + Real + + true + 920 + DBD920 + 4 + + <[10]> + Real + + true + 924 + DBD924 + 4 + + + 884 + DBX884.0 + 0 + + + Bool + + 928 + DBX928.0 + 0.1 + + + Bool + + 928 + DBX928.1 + 0.1 + + + Array[0..7] of Bool + + true + + <[0]> + Bool + + true + 930 + DBX930.0 + 0.1 + + <[1]> + Bool + + true + 930 + DBX930.1 + 0.1 + + <[2]> + Bool + + true + 930 + DBX930.2 + 0.1 + + <[3]> + Bool + + true + 930 + DBX930.3 + 0.1 + + <[4]> + Bool + + true + 930 + DBX930.4 + 0.1 + + <[5]> + Bool + + true + 930 + DBX930.5 + 0.1 + + <[6]> + Bool + + true + 930 + DBX930.6 + 0.1 + + <[7]> + Bool + + true + 930 + DBX930.7 + 0.1 + + + 930 + DBX930.0 + 0 + + + Array[0..15] of Bool + + true + + <[0]> + Bool + + true + 932 + DBX932.0 + 0.1 + + <[1]> + Bool + + true + 932 + DBX932.1 + 0.1 + + <[2]> + Bool + + true + 932 + DBX932.2 + 0.1 + + <[3]> + Bool + + true + 932 + DBX932.3 + 0.1 + + <[4]> + Bool + + true + 932 + DBX932.4 + 0.1 + + <[5]> + Bool + + true + 932 + DBX932.5 + 0.1 + + <[6]> + Bool + + true + 932 + DBX932.6 + 0.1 + + <[7]> + Bool + + true + 932 + DBX932.7 + 0.1 + + <[8]> + Bool + + true + 933 + DBX933.0 + 0.1 + + <[9]> + Bool + + true + 933 + DBX933.1 + 0.1 + + <[10]> + Bool + + true + 933 + DBX933.2 + 0.1 + + <[11]> + Bool + + true + 933 + DBX933.3 + 0.1 + + <[12]> + Bool + + true + 933 + DBX933.4 + 0.1 + + <[13]> + Bool + + true + 933 + DBX933.5 + 0.1 + + <[14]> + Bool + + true + 933 + DBX933.6 + 0.1 + + <[15]> + Bool + + true + 933 + DBX933.7 + 0.1 + + + 932 + DBX932.0 + 0 + + + Int + + 934 + DBW934 + 2 + + <"Time"> + Time + + 936 + DBD936 + 4 + + + Time_Of_Day + + 940 + DBD940 + 4 + + <"Word"> + Word + + 944 + DBW944 + 2 + + + + 548 + DBX548.0 + -1 + + + "UDTComp" + + true + + + <"String"> + String + + 946 + DBX946.0 + 256 + + + String[60] + + 1202 + DBX1202.0 + 62 + + <"Bool"> + Bool + 1264 - DBD1264 - - - - DInt - PIECES_TOT - 1268 - DBD1268 - - - DInt - PIECES_OK - 1272 - DBD1272 - - - DInt - PIECES_KO_1 - 1276 - DBD1276 - - - DInt - PIECES_KO_2 - 1280 - DBD1280 - - - DInt - PIECES_KO_3 - 1284 - DBD1284 - - - DInt - PIECES_KO_4 - 1288 - DBD1288 - - - DInt - PIECES_KO_5 - 1292 - DBD1292 - - - DInt - PIECES_KO_6 - 1296 - DBD1296 - - - DInt - PIECES_KO_7 - 1300 - DBD1300 - - - DInt - PIECES_KO_8 - 1304 - DBD1304 - - - DInt - PIECES_KO_9 - 1308 - DBD1308 - - - DInt - PIECES_KO_10 - 1312 - DBD1312 - - - DInt - T_ALARM_HOURS - 1316 - DBD1316 - - - DInt - T_DRY_CYCLE_HOURS - 1320 - DBD1320 - - - DInt - T_POWERED_HOURS - 1324 - DBD1324 - - - DInt - T_PRODUCT_100_HOURS - 1328 - DBD1328 - - - DInt - T_PRODUCT_0_HOURS - 1332 - DBD1332 - - - DInt - T_STOP_HOURS - 1336 - DBD1336 - - - Int - T_ALARM_MINUTES - 1340 - DBW1340 - - - Int - T_DRY_CYCLE_MINUTES - 1342 - DBW1342 - - - Int - T_POWERED_MINUTES - 1344 - DBW1344 - - - Int - T_PRODUCT_100_MINUTES - 1346 - DBW1346 - - - Int - T_PRODUCT_0_MINUTES - 1348 - DBW1348 - - - Int - T_STOP_MINUTES - 1350 - DBW1350 - - + DBX1264.0 + 0.1 + + + Array[0..1] of Bool + + true + + <[0]> + Bool + + true + 1266 + DBX1266.0 + 0.1 + + <[1]> + Bool + + true + 1266 + DBX1266.1 + 0.1 + + + 1266 + DBX1266.0 + 0 + + + Array[0..51] of Bool + + true + + <[0]> + Bool + + true + 1268 + DBX1268.0 + 0.1 + + <[1]> + Bool + + true + 1268 + DBX1268.1 + 0.1 + + <[2]> + Bool + + true + 1268 + DBX1268.2 + 0.1 + + <[3]> + Bool + + true + 1268 + DBX1268.3 + 0.1 + + <[4]> + Bool + + true + 1268 + DBX1268.4 + 0.1 + + <[5]> + Bool + + true + 1268 + DBX1268.5 + 0.1 + + <[6]> + Bool + + true + 1268 + DBX1268.6 + 0.1 + + <[7]> + Bool + + true + 1268 + DBX1268.7 + 0.1 + + <[8]> + Bool + + true + 1269 + DBX1269.0 + 0.1 + + <[9]> + Bool + + true + 1269 + DBX1269.1 + 0.1 + + <[10]> + Bool + + true + 1269 + DBX1269.2 + 0.1 + + <[11]> + Bool + + true + 1269 + DBX1269.3 + 0.1 + + <[12]> + Bool + + true + 1269 + DBX1269.4 + 0.1 + + <[13]> + Bool + + true + 1269 + DBX1269.5 + 0.1 + + <[14]> + Bool + + true + 1269 + DBX1269.6 + 0.1 + + <[15]> + Bool + + true + 1269 + DBX1269.7 + 0.1 + + <[16]> + Bool + + true + 1270 + DBX1270.0 + 0.1 + + <[17]> + Bool + + true + 1270 + DBX1270.1 + 0.1 + + <[18]> + Bool + + true + 1270 + DBX1270.2 + 0.1 + + <[19]> + Bool + + true + 1270 + DBX1270.3 + 0.1 + + <[20]> + Bool + + true + 1270 + DBX1270.4 + 0.1 + + <[21]> + Bool + + true + 1270 + DBX1270.5 + 0.1 + + <[22]> + Bool + + true + 1270 + DBX1270.6 + 0.1 + + <[23]> + Bool + + true + 1270 + DBX1270.7 + 0.1 + + <[24]> + Bool + + true + 1271 + DBX1271.0 + 0.1 + + <[25]> + Bool + + true + 1271 + DBX1271.1 + 0.1 + + <[26]> + Bool + + true + 1271 + DBX1271.2 + 0.1 + + <[27]> + Bool + + true + 1271 + DBX1271.3 + 0.1 + + <[28]> + Bool + + true + 1271 + DBX1271.4 + 0.1 + + <[29]> + Bool + + true + 1271 + DBX1271.5 + 0.1 + + <[30]> + Bool + + true + 1271 + DBX1271.6 + 0.1 + + <[31]> + Bool + + true + 1271 + DBX1271.7 + 0.1 + + <[32]> + Bool + + true + 1272 + DBX1272.0 + 0.1 + + <[33]> + Bool + + true + 1272 + DBX1272.1 + 0.1 + + <[34]> + Bool + + true + 1272 + DBX1272.2 + 0.1 + + <[35]> + Bool + + true + 1272 + DBX1272.3 + 0.1 + + <[36]> + Bool + + true + 1272 + DBX1272.4 + 0.1 + + <[37]> + Bool + + true + 1272 + DBX1272.5 + 0.1 + + <[38]> + Bool + + true + 1272 + DBX1272.6 + 0.1 + + <[39]> + Bool + + true + 1272 + DBX1272.7 + 0.1 + + <[40]> + Bool + + true + 1273 + DBX1273.0 + 0.1 + + <[41]> + Bool + + true + 1273 + DBX1273.1 + 0.1 + + <[42]> + Bool + + true + 1273 + DBX1273.2 + 0.1 + + <[43]> + Bool + + true + 1273 + DBX1273.3 + 0.1 + + <[44]> + Bool + + true + 1273 + DBX1273.4 + 0.1 + + <[45]> + Bool + + true + 1273 + DBX1273.5 + 0.1 + + <[46]> + Bool + + true + 1273 + DBX1273.6 + 0.1 + + <[47]> + Bool + + true + 1273 + DBX1273.7 + 0.1 + + <[48]> + Bool + + true + 1274 + DBX1274.0 + 0.1 + + <[49]> + Bool + + true + 1274 + DBX1274.1 + 0.1 + + <[50]> + Bool + + true + 1274 + DBX1274.2 + 0.1 + + <[51]> + Bool + + true + 1274 + DBX1274.3 + 0.1 + + + 1268 + DBX1268.0 + 0 + + <"Int"> + Int + + 1276 + DBW1276 + 2 + + <"Hola como Estas"> + Int + + 1278 + DBW1278 + 2 + + <"No se"> + Int + + 1280 + DBW1280 + 2 + + <"Real"> + Array[0..10] of Real + + true + + <[0]> + Real + + true + 1282 + DBD1282 + 4 + + <[1]> + Real + + true + 1286 + DBD1286 + 4 + + <[2]> + Real + + true + 1290 + DBD1290 + 4 + + <[3]> + Real + + true + 1294 + DBD1294 + 4 + + <[4]> + Real + + true + 1298 + DBD1298 + 4 + + <[5]> + Real + + true + 1302 + DBD1302 + 4 + + <[6]> + Real + + true + 1306 + DBD1306 + 4 + + <[7]> + Real + + true + 1310 + DBD1310 + 4 + + <[8]> + Real + + true + 1314 + DBD1314 + 4 + + <[9]> + Real + + true + 1318 + DBD1318 + 4 + + <[10]> + Real + + true + 1322 + DBD1322 + 4 + + + 1282 + DBX1282.0 + 0 + + + Bool + + 1326 + DBX1326.0 + 0.1 + + + Bool + + 1326 + DBX1326.1 + 0.1 + + + Array[0..7] of Bool + + true + + <[0]> + Bool + + true + 1328 + DBX1328.0 + 0.1 + + <[1]> + Bool + + true + 1328 + DBX1328.1 + 0.1 + + <[2]> + Bool + + true + 1328 + DBX1328.2 + 0.1 + + <[3]> + Bool + + true + 1328 + DBX1328.3 + 0.1 + + <[4]> + Bool + + true + 1328 + DBX1328.4 + 0.1 + + <[5]> + Bool + + true + 1328 + DBX1328.5 + 0.1 + + <[6]> + Bool + + true + 1328 + DBX1328.6 + 0.1 + + <[7]> + Bool + + true + 1328 + DBX1328.7 + 0.1 + + + 1328 + DBX1328.0 + 0 + + + Array[0..15] of Bool + + true + + <[0]> + Bool + + true + 1330 + DBX1330.0 + 0.1 + + <[1]> + Bool + + true + 1330 + DBX1330.1 + 0.1 + + <[2]> + Bool + + true + 1330 + DBX1330.2 + 0.1 + + <[3]> + Bool + + true + 1330 + DBX1330.3 + 0.1 + + <[4]> + Bool + + true + 1330 + DBX1330.4 + 0.1 + + <[5]> + Bool + + true + 1330 + DBX1330.5 + 0.1 + + <[6]> + Bool + + true + 1330 + DBX1330.6 + 0.1 + + <[7]> + Bool + + true + 1330 + DBX1330.7 + 0.1 + + <[8]> + Bool + + true + 1331 + DBX1331.0 + 0.1 + + <[9]> + Bool + + true + 1331 + DBX1331.1 + 0.1 + + <[10]> + Bool + + true + 1331 + DBX1331.2 + 0.1 + + <[11]> + Bool + + true + 1331 + DBX1331.3 + 0.1 + + <[12]> + Bool + + true + 1331 + DBX1331.4 + 0.1 + + <[13]> + Bool + + true + 1331 + DBX1331.5 + 0.1 + + <[14]> + Bool + + true + 1331 + DBX1331.6 + 0.1 + + <[15]> + Bool + + true + 1331 + DBX1331.7 + 0.1 + + + 1330 + DBX1330.0 + 0 + + + Int + + 1332 + DBW1332 + 2 + + <"Time"> + Time + + 1334 + DBD1334 + 4 + + + Time_Of_Day + + 1338 + DBD1338 + 4 + + <"Word"> + Word + + 1342 + DBW1342 + 2 + - 1248 - DBX1248.0 - - - "UDT SIPA SV Section" - - - - - DInt - .DB_IOT.STATO_MACCHINA - 1352 - DBD1352 - - - DInt - .DB_IOT.ALLARME_FERMO - 1356 - DBD1356 - - - DInt - .DB_IOT.WARNING_ATTIVO (che compromette produzione) - 1360 - DBD1360 - - - Int - .DB_IOT.STATO_OPERATIVO (Semaforo) - 1364 - DBW1364 - - - Int - .DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc) - 1366 - DBW1366 - - - DInt - .DB_IOT.ALARM_STOP_NO - 1368 - DBD1368 - - - - DInt - PIECES_TOT - 1372 - DBD1372 - - - DInt - PIECES_OK - 1376 - DBD1376 - - - DInt - PIECES_KO_1 - 1380 - DBD1380 - - - DInt - PIECES_KO_2 - 1384 - DBD1384 - - - DInt - PIECES_KO_3 - 1388 - DBD1388 - - - DInt - PIECES_KO_4 - 1392 - DBD1392 - - - DInt - PIECES_KO_5 - 1396 - DBD1396 - - - DInt - PIECES_KO_6 - 1400 - DBD1400 - - - DInt - PIECES_KO_7 - 1404 - DBD1404 - - - DInt - PIECES_KO_8 - 1408 - DBD1408 - - - DInt - PIECES_KO_9 - 1412 - DBD1412 - - - DInt - PIECES_KO_10 - 1416 - DBD1416 - - - DInt - T_ALARM_HOURS - 1420 - DBD1420 - - - DInt - T_DRY_CYCLE_HOURS - 1424 - DBD1424 - - - DInt - T_POWERED_HOURS - 1428 - DBD1428 - - - DInt - T_PRODUCT_100_HOURS - 1432 - DBD1432 - - - DInt - T_PRODUCT_0_HOURS - 1436 - DBD1436 - - - DInt - T_STOP_HOURS - 1440 - DBD1440 - - - Int - T_ALARM_MINUTES - 1444 - DBW1444 - - - Int - T_DRY_CYCLE_MINUTES - 1446 - DBW1446 - - - Int - T_POWERED_MINUTES - 1448 - DBW1448 - - - Int - T_PRODUCT_100_MINUTES - 1450 - DBW1450 - - - Int - T_PRODUCT_0_MINUTES - 1452 - DBW1452 - - - Int - T_STOP_MINUTES - 1454 - DBW1454 - - - - - 1352 - DBX1352.0 - - - "UDT SIPA SV Section" - - - - - DInt - .DB_IOT.STATO_MACCHINA - 1456 - DBD1456 - - - DInt - .DB_IOT.ALLARME_FERMO - 1460 - DBD1460 - - - DInt - .DB_IOT.WARNING_ATTIVO (che compromette produzione) - 1464 - DBD1464 - - - Int - .DB_IOT.STATO_OPERATIVO (Semaforo) - 1468 - DBW1468 - - - Int - .DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc) - 1470 - DBW1470 - - - DInt - .DB_IOT.ALARM_STOP_NO - 1472 - DBD1472 - - - - DInt - PIECES_TOT - 1476 - DBD1476 - - - DInt - PIECES_OK - 1480 - DBD1480 - - - DInt - PIECES_KO_1 - 1484 - DBD1484 - - - DInt - PIECES_KO_2 - 1488 - DBD1488 - - - DInt - PIECES_KO_3 - 1492 - DBD1492 - - - DInt - PIECES_KO_4 - 1496 - DBD1496 - - - DInt - PIECES_KO_5 - 1500 - DBD1500 - - - DInt - PIECES_KO_6 - 1504 - DBD1504 - - - DInt - PIECES_KO_7 - 1508 - DBD1508 - - - DInt - PIECES_KO_8 - 1512 - DBD1512 - - - DInt - PIECES_KO_9 - 1516 - DBD1516 - - - DInt - PIECES_KO_10 - 1520 - DBD1520 - - - DInt - T_ALARM_HOURS - 1524 - DBD1524 - - - DInt - T_DRY_CYCLE_HOURS - 1528 - DBD1528 - - - DInt - T_POWERED_HOURS - 1532 - DBD1532 - - - DInt - T_PRODUCT_100_HOURS - 1536 - DBD1536 - - - DInt - T_PRODUCT_0_HOURS - 1540 - DBD1540 - - - DInt - T_STOP_HOURS - 1544 - DBD1544 - - - Int - T_ALARM_MINUTES - 1548 - DBW1548 - - - Int - T_DRY_CYCLE_MINUTES - 1550 - DBW1550 - - - Int - T_POWERED_MINUTES - 1552 - DBW1552 - - - Int - T_PRODUCT_100_MINUTES - 1554 - DBW1554 - - - Int - T_PRODUCT_0_MINUTES - 1556 - DBW1556 - - - Int - T_STOP_MINUTES - 1558 - DBW1558 - - - - - 1456 - DBX1456.0 - - - "UDT SIPA SV Section" - - - - - DInt - .DB_IOT.STATO_MACCHINA - 1560 - DBD1560 - - - DInt - .DB_IOT.ALLARME_FERMO - 1564 - DBD1564 - - - DInt - .DB_IOT.WARNING_ATTIVO (che compromette produzione) - 1568 - DBD1568 - - - Int - .DB_IOT.STATO_OPERATIVO (Semaforo) - 1572 - DBW1572 - - - Int - .DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc) - 1574 - DBW1574 - - - DInt - .DB_IOT.ALARM_STOP_NO - 1576 - DBD1576 - - - - DInt - PIECES_TOT - 1580 - DBD1580 - - - DInt - PIECES_OK - 1584 - DBD1584 - - - DInt - PIECES_KO_1 - 1588 - DBD1588 - - - DInt - PIECES_KO_2 - 1592 - DBD1592 - - - DInt - PIECES_KO_3 - 1596 - DBD1596 - - - DInt - PIECES_KO_4 - 1600 - DBD1600 - - - DInt - PIECES_KO_5 - 1604 - DBD1604 - - - DInt - PIECES_KO_6 - 1608 - DBD1608 - - - DInt - PIECES_KO_7 - 1612 - DBD1612 - - - DInt - PIECES_KO_8 - 1616 - DBD1616 - - - DInt - PIECES_KO_9 - 1620 - DBD1620 - - - DInt - PIECES_KO_10 - 1624 - DBD1624 - - - DInt - T_ALARM_HOURS - 1628 - DBD1628 - - - DInt - T_DRY_CYCLE_HOURS - 1632 - DBD1632 - - - DInt - T_POWERED_HOURS - 1636 - DBD1636 - - - DInt - T_PRODUCT_100_HOURS - 1640 - DBD1640 - - - DInt - T_PRODUCT_0_HOURS - 1644 - DBD1644 - - - DInt - T_STOP_HOURS - 1648 - DBD1648 - - - Int - T_ALARM_MINUTES - 1652 - DBW1652 - - - Int - T_DRY_CYCLE_MINUTES - 1654 - DBW1654 - - - Int - T_POWERED_MINUTES - 1656 - DBW1656 - - - Int - T_PRODUCT_100_MINUTES - 1658 - DBW1658 - - - Int - T_PRODUCT_0_MINUTES - 1660 - DBW1660 - - - Int - T_STOP_MINUTES - 1662 - DBW1662 - - - - - 1560 - DBX1560.0 - - - "UDT SIPA SV Section" - - - - - DInt - .DB_IOT.STATO_MACCHINA - 1664 - DBD1664 - - - DInt - .DB_IOT.ALLARME_FERMO - 1668 - DBD1668 - - - DInt - .DB_IOT.WARNING_ATTIVO (che compromette produzione) - 1672 - DBD1672 - - - Int - .DB_IOT.STATO_OPERATIVO (Semaforo) - 1676 - DBW1676 - - - Int - .DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc) - 1678 - DBW1678 - - - DInt - .DB_IOT.ALARM_STOP_NO - 1680 - DBD1680 - - - - DInt - PIECES_TOT - 1684 - DBD1684 - - - DInt - PIECES_OK - 1688 - DBD1688 - - - DInt - PIECES_KO_1 - 1692 - DBD1692 - - - DInt - PIECES_KO_2 - 1696 - DBD1696 - - - DInt - PIECES_KO_3 - 1700 - DBD1700 - - - DInt - PIECES_KO_4 - 1704 - DBD1704 - - - DInt - PIECES_KO_5 - 1708 - DBD1708 - - - DInt - PIECES_KO_6 - 1712 - DBD1712 - - - DInt - PIECES_KO_7 - 1716 - DBD1716 - - - DInt - PIECES_KO_8 - 1720 - DBD1720 - - - DInt - PIECES_KO_9 - 1724 - DBD1724 - - - DInt - PIECES_KO_10 - 1728 - DBD1728 - - - DInt - T_ALARM_HOURS - 1732 - DBD1732 - - - DInt - T_DRY_CYCLE_HOURS - 1736 - DBD1736 - - - DInt - T_POWERED_HOURS - 1740 - DBD1740 - - - DInt - T_PRODUCT_100_HOURS - 1744 - DBD1744 - - - DInt - T_PRODUCT_0_HOURS - 1748 - DBD1748 - - - DInt - T_STOP_HOURS - 1752 - DBD1752 - - - Int - T_ALARM_MINUTES - 1756 - DBW1756 - - - Int - T_DRY_CYCLE_MINUTES - 1758 - DBW1758 - - - Int - T_POWERED_MINUTES - 1760 - DBW1760 - - - Int - T_PRODUCT_100_MINUTES - 1762 - DBW1762 - - - Int - T_PRODUCT_0_MINUTES - 1764 - DBW1764 - - - Int - T_STOP_MINUTES - 1766 - DBW1766 - - - - - 1664 - DBX1664.0 - + 946 + DBX946.0 + -1 +
-
+
\ No newline at end of file diff --git a/DB_to_Excel.py b/DB_to_Excel.py index a4eb88c..16f3609 100644 --- a/DB_to_Excel.py +++ b/DB_to_Excel.py @@ -1,9 +1,6 @@ import re +import os import json -import pandas as pd -from ExportData import * -from ExpandDB import * - def clean_line(line): """Clean line from BOM and extra spaces or quotes.""" @@ -12,8 +9,15 @@ def clean_line(line): # Standardize TYPE and DATA_BLOCK definitions to ensure they're properly captured line = re.sub(r'\s*TYPE\s+"?', 'TYPE "', line) line = re.sub(r'\s*DATA_BLOCK\s+"?', 'DATA_BLOCK "', line) + line = remove_text_inside_brackets(line) return line +def remove_text_inside_brackets(text): + # Define the pattern to find text inside brackets + pattern = r"\{.*?\}" + # Use re.sub to replace the found text with an empty string + cleaned_text = re.sub(pattern, '', text) + return cleaned_text def extract_name(line): """Extract the name from TYPE or DATA_BLOCK definition line.""" @@ -147,21 +151,35 @@ def parse_dbs(lines, udts): return db_json +def save_data_as_json(file_path, data): + with open(file_path, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=4) + +from CreateTable import * +from ExpandDB import * +from manejoArchivos import * if __name__ == "__main__": - file_path = "DB SIPA Supervision.db" - with open(file_path, "r", encoding="utf-8-sig") as file: - lines = file.readlines() + file_path = "Data_block_1.db" ## select_file() + if file_path: # Proceed only if a file was selected + with open(file_path, "r", encoding="utf-8-sig") as file: + lines = file.readlines() - udt_json = parse_udts(lines) - db_json = parse_dbs(lines, udt_json) + udt_json = parse_udts(lines) + db_json = parse_dbs(lines, udt_json) - expand_dbs(udt_json, db_json) # Expand DBs with UDT definitions + expand_dbs(udt_json, db_json) # Expand DBs with UDT definitions + save_data_as_json("DB_Structure.jon", db_json) - # Display the expanded DBs as a table - df = display_as_table(db_json) - save_dataframe_to_file(df) # Save the DataFrame to a CSV file - save_dataframe_to_excel(df) # Optionally, save the DataFrame to an Excel file + # Display the expanded DBs as a table + df = display_as_table(db_json) + save_dataframe_to_file(df) # Save the DataFrame to a CSV file + save_dataframe_to_excel(df,"DB_Structure.xlsx") # Optionally, save the DataFrame to an Excel file - # Save JSON data to an XML file - save_json_to_xml(db_json) + # Save JSON data to an XML file + save_json_to_xml(db_json) + + # Open the directory containing the new file in Explorer + ##open_file_explorer(os.path.dirname(file_path)) + else: + print("No file was selected.") diff --git a/Data_block_1.db b/Data_block_1.db new file mode 100644 index 0000000..ece905d --- /dev/null +++ b/Data_block_1.db @@ -0,0 +1,73 @@ +TYPE "UDT Complicada" +VERSION : 0.1 + STRUCT + "String" : String; + String_1 : String[60]; + "Bool" : Bool; + Bool_1 : Array[0..1] of Bool; + Bool_2 : Array[0..51] of Bool; + "Int" : Int; + "Hola como Estas" : Int; + "No se" : Int; + "Real" : Array[0..10] of Real; + Bool_3 : Bool; + Bool_4 : Bool; + Bool_5 : Array[0..7] of Bool; + Bool_6 : Array[0..15] of Bool; + Int_1 : Int; + "Time" : Time; + Time_of : Time_Of_Day; + "Word" : Word; + END_STRUCT; + +END_TYPE + +TYPE "UDTComp" +VERSION : 0.1 + STRUCT + "String" : String; + String_1 : String[60]; + "Bool" : Bool; + Bool_1 : Array[0..1] of Bool; + Bool_2 : Array[0..51] of Bool; + "Int" : Int; + "Hola como Estas" : Int; + "No se" : Int; + "Real" : Array[0..10] of Real; + Bool_3 : Bool; + Bool_4 : Bool; + Bool_5 : Array[0..7] of Bool; + Bool_6 : Array[0..15] of Bool; + Int_1 : Int; + "Time" : Time; + Time_of : Time_Of_Day; + "Word" : Word; + END_STRUCT; + +END_TYPE + +DATA_BLOCK "Data_block_1" +{ S7_Optimized_Access := 'FALSE' } +VERSION : 0.1 +NON_RETAIN + STRUCT + asa : Array[1..8] of Byte; + b0 : Bool; + b1 : Bool; + s5 : S5Time; + s : LInt; + s_1 : WString; + s_2 : UInt; + ss : LReal; + b2 : Int; + b3 : Array[0..15] of Bool; + b4 : Array[0..11] of Bool; + "Udt" { S7_SetPoint := 'False'} : "UDTd Complicada"; + udt_1 : "UDTComp"; + END_STRUCT; + + +BEGIN + +END_DATA_BLOCK + diff --git a/ExpandDB.py b/ExpandDB.py index 16eddfa..4dddaa8 100644 --- a/ExpandDB.py +++ b/ExpandDB.py @@ -27,7 +27,9 @@ def expand_udt_references(db_struct, udts): ) # Remove quotes which may wrap UDT names with spaces if type_name in udts: # Replace the UDT reference with its deeply copied definition + db_struct["is_udt_definition"] = True db_struct["fields"] = deepcopy(udts[type_name]) + print(f"Expanded UDT '{type_name}' at field '{key}'") elif isinstance(db_struct, list): for item in db_struct: @@ -54,7 +56,7 @@ def handle_array_types(db_struct): match.group(3), ) comment = value.get("comment", "") - + value["array_definition"] = True # Instead of popping the original key, initialize a sub-dictionary value["Array"] = ( {} @@ -76,103 +78,6 @@ def handle_array_types(db_struct): handle_array_types(value) -type_sizes = { - "Int": 2, - "DInt": 4, - "Word": 2, - "Real": 4, - "Bool": 2, # We'll adjust this dynamically based on context (1 byte if alone, 1 bit if grouped) - "String": 1, # This will be multiplied by the specified size in brackets [n] -} - - -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): - """ - Recursively calculate byte offsets for each field in the DB structure considering special types. - """ - is_array_element = False - 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 db_struct.items(): - # Skip 'fields' and 'Struct' keys in the name path - # - if ( - isinstance(value, dict) and "type" in value - ): # Directly a field with 'type' - type_name = value["type"] - is_array_element = value.get("is_array_element", False) - size = type_sizes.get( - type_name, 0 - ) # Default to 1 byte if type is not recognized - - 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 = 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 - else: - size = type_sizes.get( - type_name, 1 - ) # Default to generic size if not an array - - # Adjusting Bool sizes based on grouping - if type_name == "Bool": - if last_key_was_bool: # This is a grouped bool - 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 - # print(f"Offset '{current_offset}' at field '{key}' ") - current_offset += size - - # Recursively handle nested dictionaries and lists - if isinstance(value, dict) or isinstance(value, list): - current_offset = calculate_offsets(value, current_offset) - elif isinstance(db_struct, list): - for index, item in enumerate(db_struct): - for item in db_struct: - current_offset = calculate_offsets(item, current_offset) - - return current_offset - def expand_dbs(udts, dbs): """ @@ -182,5 +87,4 @@ def expand_dbs(udts, dbs): print(f"Expanding DB: {db_name}") expand_udt_references(db_content, udts) handle_array_types(db_content) - calculate_offsets(db_content) print(f"Completed expansion for DB: {db_name}") diff --git a/ExportData.py b/ExportData.py deleted file mode 100644 index a597ebb..0000000 --- a/ExportData.py +++ /dev/null @@ -1,85 +0,0 @@ -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. - """ - xml_data = xmltodict.unparse({"root": json_data}, pretty=True) - with open(filename, "w") as xml_file: - xml_file.write(xml_data) - print(f"XML data saved to {filename}") - - -def save_dataframe_to_excel(df, filename="DB_Structure.xlsx"): - """ - Save the provided DataFrame to an Excel file. - """ - df.to_excel(filename, index=False) - print(f"Data saved to {filename}") - - -def save_dataframe_to_file(df, filename="DB_Structure.csv"): - """ - Save the provided DataFrame to a CSV file. - """ - df.to_csv(filename, index=False) - print(f"Data saved to {filename}") - - -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" or key == "Array": - next_prefix = parent_prefix # Continue with the current prefix - else: - 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' - field_data = { - "Nombre": next_prefix, - "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) - - # Recursively handle nested dictionaries and lists - if isinstance(value, dict) or isinstance(value, list): - collect_data_for_table(value, next_prefix, collected_data) - elif isinstance(db_struct, list): - for index, item in enumerate(db_struct): - item_prefix = f"{parent_prefix}[{index}]" if parent_prefix else f"[{index}]" - collect_data_for_table(item, item_prefix, collected_data) - - return collected_data - - -def display_as_table(dbs): - """ - Convert collected DB data into a pandas DataFrame and display it. - """ - all_data = [] - for db_name, db_content in dbs.items(): - print(f"Processing DB: {db_name}") - db_data = collect_data_for_table(db_content) - all_data.extend(db_data) - - df = pd.DataFrame(all_data) - return df diff --git a/__pycache__/ExpandDB.cpython-310.pyc b/__pycache__/ExpandDB.cpython-310.pyc index 6376c1a0b3a285a90faee3df3ba5f844d6fd678e..6cea9d1ec682bba82765a67d073296b802648251 100644 GIT binary patch delta 662 zcmY+A&ubGw6vyA2ncYk_yK5R^ZAcF3^V9X~l!e!XJY(L?J$6dn| z-eL~_ZBIM3J<@gs=sPu{G3pG6(~hnm_e;#^%TG>pJ><~dXc zUV#Z4a>I3MABv7rl8X5yNP*sfNCVQsQ~V5!7}1o5QWcCO=J1FQ^TszhB~|o_yXguT z+U#%i3#2#uqqin@_D`Fb$jOsaA0jWt#r0{ir*&_ChIr~-ca_KLL%d~maAgZ9*6aKnK}l?FmZBM?YFRLtI_k4&}C}q1s6`c(6nEot7li~ vI|wNhMNE21ETZ_O+f+yj`l4;emwb0hx9xu1m@m;+f}}BtA(G_2tc0!K(m;|9 delta 2120 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 delta 1110 zcmYjQL2nc{6!x<{v$LMr%@RVBg49H+inK(4RDs$?P^dsE>LG`6saCC4!`hpUGMNqb zBuyf(wo>4LIH9>zqEyKd#D!iF_x^=is(R?Df1w=c^K6LnMt<*m&+|UNH}m{@@z2@G zsMQh#<;}_`!_N~!{_)O9Vd&h%W$vJoL_$t_Qwu#RJCaHM0D4TGlA&xM;&N6tr9c$O zc#RCHOk@kaP`2gF1JY|qxJ$aH|3x;k`roV9mtes~I~#dlre)fz(J;%^bE1<9Xa?@6-m1`{eNVTf#>;lYJKeEfvseWPCFP!pwr%|nTsSA-} zV76-ledai;&Tm!k*wSRd2hX8$WZ?ULFEIjt>@8g8Cg68~F)N8BCG1nZXUPFQB)7>A z`S*0p$ARUNu2XXkEjzM&o$8M)jKkt%%nRzgt_=>D3?v-VF|*8kHnE_uSa?cgX!%p} zj1^!xrU;DR@bNlIr_p1YHQBJiHqmP~tO*-3I;1sf9wTv#Vvl6e*(kB+UYT^DSp`IhR%h1x0mn_3OC9VdpF%4I!|dbYaJn*Z*^h+(F_h-wj+ zSwY1E0UcOiAqbiPhXt6U5u@)SpiIE@3Ezsw97}-y%tP_E153~bPW8p=_tqbA*HilG zLjPg=%6TW`z5ZZSl-N4nmV47eKJYJ`sH6J3eP;3v22C3k=N+VsAi*Ly=r1tT1x=@B zW@oomM diff --git a/db_definitions.json b/db_definitions.json deleted file mode 100644 index 9273b31..0000000 --- a/db_definitions.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "DB SIPA Supervision": { - "root": { - "MAIN": { - "type": "\"UDT SIPA SV Main\";", - "comment": "" - }, - "SECT1": { - "type": "\"UDT SIPA SV Section\";", - "comment": "" - }, - "SECT2": { - "type": "\"UDT SIPA SV Section\";", - "comment": "" - }, - "SECT3": { - "type": "\"UDT SIPA SV Section\";", - "comment": "" - }, - "SECT4": { - "type": "\"UDT SIPA SV Section\";", - "comment": "" - }, - "SECT5": { - "type": "\"UDT SIPA SV Section\";", - "comment": "" - } - } - } -} \ No newline at end of file diff --git a/manejoArchivos.py b/manejoArchivos.py new file mode 100644 index 0000000..16d1f73 --- /dev/null +++ b/manejoArchivos.py @@ -0,0 +1,37 @@ +import pandas as pd +import tkinter as tk +from tkinter import filedialog +import os +import subprocess + +def select_file(): + """ + Opens a file dialog to select a .db file and returns the selected file path. + """ + root = tk.Tk() + root.withdraw() # Use to hide the tkinter root window + + # Open file dialog and return the selected file path + file_path = filedialog.askopenfilename( + title="Select a .db file", + filetypes=(("DB files", "*.db"), ("All files", "*.*")) + ) + return file_path + +def open_file_explorer(path): + """ + Opens the file explorer at the given path, correctly handling paths with spaces. + """ + # Normalize the path to ensure it's in the correct format + normalized_path = os.path.normpath(path) + + # Check if the path is a directory or a file and format the command accordingly + if os.path.isdir(normalized_path): + # If it's a directory, use the 'explorer' command directly + command = f'explorer "{normalized_path}"' + else: + # If it's a file, use the 'explorer /select,' command to highlight the file in its folder + command = f'explorer /select,"{normalized_path}"' + + # Execute the command using subprocess.run, with shell=True to handle paths with spaces correctly + subprocess.run(command, shell=True) \ No newline at end of file diff --git a/udt_definitions.json b/udt_definitions.json deleted file mode 100644 index 27c3c5c..0000000 --- a/udt_definitions.json +++ /dev/null @@ -1,194 +0,0 @@ -{ - "UDT SIPA SV Main": { - "root": { - "N1": { - "type": "DInt;", - "comment": ".DB_IOT.USERLEVEL" - }, - "N2": { - "type": "String[81];", - "comment": ".DB_IOT.USERNAME" - }, - "N3": { - "type": "String[81];", - "comment": ".DB_IOT.NOME_RICETTA" - }, - "N4": { - "type": "Int;", - "comment": ".DB_IOT.NEXT_MAINT_CYCLES" - }, - "N5": { - "V1": { - "type": "String[254];", - "comment": "" - }, - "V2": { - "type": "String[254];", - "comment": "" - }, - "V3": { - "type": "String[254];", - "comment": "" - }, - "V4": { - "type": "String[254];", - "comment": "" - }, - "V5": { - "type": "String[8];", - "comment": "" - } - }, - "N6": { - "type": "Array[1..3] of Real;", - "comment": ".DB_IOT.ELECTRIC_VOLTAGE_PHASE_D" - }, - "N7": { - "type": "Array[1..3] of Real;", - "comment": ".DB_IOT.ELECTRIC_CURRENT_PHASE_D" - }, - "N8": { - "type": "Real;", - "comment": ".DB_IOT.ELECTRIC_POWER_D" - }, - "N9": { - "type": "Real;", - "comment": ".DB_IOT.ELECTRIC_POWER_FACTOR_D" - }, - "N10": { - "type": "Real;", - "comment": ".DB_IOT.ELECTRIC_POWER_HOUR_D" - }, - "N11": { - "type": "Real;", - "comment": ".DB_IOT.ELECTRIC_POWER_WH" - } - } - }, - "UDT SIPA SV Section": { - "root": { - "N1": { - "type": "DInt;", - "comment": ".DB_IOT.STATO_MACCHINA" - }, - "N2": { - "type": "DInt;", - "comment": ".DB_IOT.ALLARME_FERMO" - }, - "N3": { - "type": "DInt;", - "comment": ".DB_IOT.WARNING_ATTIVO (che compromette produzione)" - }, - "N4": { - "type": "Int;", - "comment": ".DB_IOT.STATO_OPERATIVO (Semaforo)" - }, - "N5": { - "type": "Int;", - "comment": ".DB_IOT.MODO_OPERATIVO (Prod,Simula,Man, ecc)" - }, - "N6": { - "type": "DInt;", - "comment": ".DB_IOT.ALARM_STOP_NO" - }, - "N7": { - "V1": { - "type": "DInt;", - "comment": "PIECES_TOT" - }, - "V2": { - "type": "DInt;", - "comment": "PIECES_OK" - }, - "V3": { - "type": "DInt;", - "comment": "PIECES_KO_1" - }, - "V4": { - "type": "DInt;", - "comment": "PIECES_KO_2" - }, - "V5": { - "type": "DInt;", - "comment": "PIECES_KO_3" - }, - "V6": { - "type": "DInt;", - "comment": "PIECES_KO_4" - }, - "V7": { - "type": "DInt;", - "comment": "PIECES_KO_5" - }, - "V8": { - "type": "DInt;", - "comment": "PIECES_KO_6" - }, - "V9": { - "type": "DInt;", - "comment": "PIECES_KO_7" - }, - "V10": { - "type": "DInt;", - "comment": "PIECES_KO_8" - }, - "V11": { - "type": "DInt;", - "comment": "PIECES_KO_9" - }, - "V12": { - "type": "DInt;", - "comment": "PIECES_KO_10" - }, - "V13": { - "type": "DInt;", - "comment": "T_ALARM_HOURS" - }, - "V14": { - "type": "DInt;", - "comment": "T_DRY_CYCLE_HOURS" - }, - "V15": { - "type": "DInt;", - "comment": "T_POWERED_HOURS" - }, - "V16": { - "type": "DInt;", - "comment": "T_PRODUCT_100_HOURS" - }, - "V17": { - "type": "DInt;", - "comment": "T_PRODUCT_0_HOURS" - }, - "V18": { - "type": "DInt;", - "comment": "T_STOP_HOURS" - }, - "V19": { - "type": "Int;", - "comment": "T_ALARM_MINUTES" - }, - "V20": { - "type": "Int;", - "comment": "T_DRY_CYCLE_MINUTES" - }, - "V21": { - "type": "Int;", - "comment": "T_POWERED_MINUTES" - }, - "V22": { - "type": "Int;", - "comment": "T_PRODUCT_100_MINUTES" - }, - "V23": { - "type": "Int;", - "comment": "T_PRODUCT_0_MINUTES" - }, - "V24": { - "type": "Int;", - "comment": "T_STOP_MINUTES" - } - } - } - } -} \ No newline at end of file