diff --git a/BlenderRun_ProdTime.xml b/BlenderRun_ProdTime.xml new file mode 100644 index 0000000..6365fe2 --- /dev/null +++ b/BlenderRun_ProdTime.xml @@ -0,0 +1,2359 @@ + + + + + + false + TASK2 + +
+
+
+
+ + + + + + + + +
+
+
+ +
+ + Standard + BlenderRun_ProdTime + + 2040 + LAD + false + + + + + + + it-IT + + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Seconds + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + Int + 0 + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Reset Hours + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Seconds Counter + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + Int + 60 + + + + + + + + + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Minute + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + Int + 0 + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + 1 + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Minute Counter + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + Int + 60 + + + + + + + + + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Hour + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + Int + 0 + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + 1 + + + 2 + Int + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Hour Counter + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + Int + 0 + + + + + + + + + + + Int + 0 + + + + + + + + + + + Int + 0 + + + + + + + + + + + + 2 + + + 1 + + + 1 + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Counter reset + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Running Seconds + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DINT#60 + + + + + + + + + + + + + + + DINT#0 + + + + + + + + + + + + + + + + + + + + + + + Int + 1 + + + + + + + + + + + + + + + + + + + + Int + DInt + + + DInt + + + DInt + + + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Running Minutes + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DINT#60 + + + + + + + + + + + + + + + DINT#0 + + + + + + + + + + + Int + 1 + + + + + + + + + + + Int + DInt + + + DInt + + + DInt + + + 2 + Int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Running Hours for Maintenance + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + LAD + + + + + + + it-IT + + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + it-IT + Running Hours for Maintenance + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + + + + + it-IT + Run Prod Time + + + + + de-DE + + + + + + en-US + + + + + + es-ES + + + + + + fr-FR + + + + + + zh-CN + + + + + + ja-JP + + + + + + + + \ No newline at end of file diff --git a/FC2040.txt b/FC2040.txt new file mode 100644 index 0000000..db65012 Binary files /dev/null and b/FC2040.txt differ diff --git a/LadderToPython.py b/LadderToPython.py index cde0701..759ab63 100644 --- a/LadderToPython.py +++ b/LadderToPython.py @@ -91,7 +91,47 @@ def parse_siemens_lad_to_scl(xml_file, debug=True): scl_code.append(f"// Title: {text_elem.text}") break - # Generate block header + # Initialize variable lists + input_vars = [] + output_vars = [] + inout_vars = [] + temp_vars = [] + static_vars = [] + + # Extract interface information + interface_elem = block.find(".//Interface") + if interface_elem is not None: + interface_text = interface_elem.text + if interface_text: + try: + # Parse interface definition to extract variables + interface_xml = etree.fromstring(interface_text) + + # Process each section in the interface + sections = interface_xml.findall(".//Section") + for section in sections: + section_name = section.get("Name") + members = section.findall("Member") + + # Store variables by section + for member in members: + var_name = member.get("Name") + var_type = member.get("Datatype") + + if section_name == "Input": + input_vars.append((var_name, var_type)) + elif section_name == "Output": + output_vars.append((var_name, var_type)) + elif section_name == "InOut": + inout_vars.append((var_name, var_type)) + elif section_name == "Temp": + temp_vars.append((var_name, var_type)) + elif section_name == "Static": + static_vars.append((var_name, var_type)) + except Exception as e: + debug_print(f"Error parsing interface: {str(e)}", debug) + + # Generate block header with interface if block_type == "FC": scl_code.append(f'FUNCTION "{block_name}" : VOID') elif block_type == "FB": @@ -99,6 +139,37 @@ def parse_siemens_lad_to_scl(xml_file, debug=True): elif block_type == "OB": scl_code.append(f'ORGANIZATION_BLOCK "{block_name}"') + # Add variable declarations + if input_vars: + scl_code.append("VAR_INPUT") + for name, dtype in input_vars: + scl_code.append(f" {name} : {dtype};") + scl_code.append("END_VAR") + + if output_vars: + scl_code.append("VAR_OUTPUT") + for name, dtype in output_vars: + scl_code.append(f" {name} : {dtype};") + scl_code.append("END_VAR") + + if inout_vars: + scl_code.append("VAR_IN_OUT") + for name, dtype in inout_vars: + scl_code.append(f" {name} : {dtype};") + scl_code.append("END_VAR") + + if temp_vars: + scl_code.append("VAR_TEMP") + for name, dtype in temp_vars: + scl_code.append(f" {name} : {dtype};") + scl_code.append("END_VAR") + + if static_vars and block_type == "FB": + scl_code.append("VAR") + for name, dtype in static_vars: + scl_code.append(f" {name} : {dtype};") + scl_code.append("END_VAR") + # Add BEGIN marker scl_code.append("BEGIN") @@ -208,472 +279,505 @@ def parse_siemens_lad_to_scl(xml_file, debug=True): debug_print(f"Successfully found Parts and Wires elements", debug) - # Get all wire elements - wire_elements = [] - wire_elements.extend(wires.findall("Wire")) + # Build dictionaries for Parts and Access elements + parts_dict = {} + access_dict = {} + + # Process all Parts elements (including MOVE, Add, Contact, etc) + for part in parts.findall("*"): + if part.tag.endswith("Access"): + uid = part.get("UId") + if uid: + access_dict[uid] = part + else: + uid = part.get("UId") + if uid: + parts_dict[uid] = part + + # Process all FlgNet namespace elements too if flgnet_ns: - wire_elements.extend(wires.findall("flg:Wire", namespaces=flgnet_ns)) + for part in parts.findall("flg:*", namespaces=flgnet_ns): + if part.tag.endswith("Access"): + uid = part.get("UId") + if uid: + access_dict[uid] = part + else: + uid = part.get("UId") + if uid: + parts_dict[uid] = part - # Try XPath with any namespace - if not wire_elements: - for child in wires: - if child.tag.endswith("Wire"): - wire_elements.append(child) - - # Process function calls (CALL instructions) - call_elements = [] - # Try both direct and with namespace - call_elements.extend(parts.findall("Call")) - if flgnet_ns: - call_elements.extend(parts.findall("flg:Call", namespaces=flgnet_ns)) - - # Try XPath with any namespace - if not call_elements: - for child in parts: - if child.tag.endswith("Call"): - call_elements.append(child) - - debug_print(f"Found {len(call_elements)} function calls", debug) - - for call in call_elements: - call_uid = call.get("UId") - # Try both direct and with namespace for CallInfo - call_info = call.find("CallInfo") or ( - call.find("flg:CallInfo", namespaces=flgnet_ns) - if flgnet_ns - else None - ) - - # Try XPath with any namespace if still not found - if call_info is None: - for child in call: - if child.tag.endswith("CallInfo"): - call_info = child - break - - if call_info is None: - debug_print( - f"No CallInfo found for call with UId {call_uid}", debug - ) + # Process wires to build connection map + wire_connections = {} + for wire in wires.findall("Wire"): + wire_id = wire.get("UId") + if not wire_id: continue - function_name = call_info.get("Name") - block_type = call_info.get("BlockType") - debug_print(f"Found call to {function_name} ({block_type})", debug) + connections = [] - # Check if this call is connected to a powerrail (unconditional execution) - is_enabled = False + # Check for powerrail + has_powerrail = any(child.tag.endswith("Powerrail") for child in wire) - for wire in wire_elements: - # Check if wire has a powerrail source - powerrail = wire.find("Powerrail") or ( - wire.find("flg:Powerrail", namespaces=flgnet_ns) - if flgnet_ns - else None - ) + # Get all connections in this wire + for child in wire: + if child.tag.endswith("NameCon"): + connections.append( + { + "type": "NameCon", + "uid": child.get("UId"), + "name": child.get("Name"), + "has_powerrail": has_powerrail, + } + ) + elif child.tag.endswith("IdentCon"): + connections.append( + { + "type": "IdentCon", + "uid": child.get("UId"), + "has_powerrail": has_powerrail, + } + ) - # Try XPath with any namespace - if powerrail is None: - for child in wire: - if child.tag.endswith("Powerrail"): - powerrail = child - break + wire_connections[wire_id] = connections - if powerrail is None: + # Also process FlgNet namespace wires + if flgnet_ns: + for wire in wires.findall("flg:Wire", namespaces=flgnet_ns): + wire_id = wire.get("UId") + if not wire_id: continue - # Check if wire connects to this call's enable input - name_con = wire.find(f"NameCon[@UId='{call_uid}'][@Name='en']") or ( - wire.find( - f"flg:NameCon[@UId='{call_uid}'][@Name='en']", - namespaces=flgnet_ns, - ) - if flgnet_ns - else None - ) - - # Try XPath with any namespace - if name_con is None: - for child in wire: - if ( - child.tag.endswith("NameCon") - and child.get("UId") == call_uid - and child.get("Name") == "en" - ): - name_con = child - break - - if name_con is not None: - is_enabled = True - debug_print( - f"Call to {function_name} is directly enabled by powerrail", - debug, - ) - break - - if is_enabled: - # Generate code for function call - scl_code.append(f" {function_name}();") - - # Process MOVE operations - move_elements = [] - move_elements.extend(parts.findall("Part[@Name='Move']")) - if flgnet_ns: - move_elements.extend( - parts.findall("flg:Part[@Name='Move']", namespaces=flgnet_ns) - ) - - # Try XPath with any namespace - if not move_elements: - for child in parts: - if child.tag.endswith("Part") and child.get("Name") == "Move": - move_elements.append(child) - - debug_print(f"Found {len(move_elements)} MOVE operations", debug) - - for move in move_elements: - move_uid = move.get("UId") - debug_print(f"Processing MOVE with UId {move_uid}", debug) - - # Check if MOVE is directly enabled - is_enabled = False - - # Debug all wires to find the one connected to this move - for wire_idx, wire in enumerate(wire_elements): - debug_print(f"Checking wire {wire_idx} for MOVE {move_uid}", debug) + connections = [] # Check for powerrail - powerrail = None - for child in wire: - if child.tag.endswith("Powerrail"): - powerrail = child - debug_print(f" Found powerrail in wire {wire_idx}", debug) - break + has_powerrail = any( + child.tag.endswith("Powerrail") for child in wire + ) - if powerrail is None: - continue - - # Check for connection to this move - name_con = None + # Get all connections in this wire for child in wire: if child.tag.endswith("NameCon"): - debug_print( - f" Found NameCon: UId={child.get('UId')}, Name={child.get('Name')}", - debug, + connections.append( + { + "type": "NameCon", + "uid": child.get("UId"), + "name": child.get("Name"), + "has_powerrail": has_powerrail, + } ) - if ( - child.get("UId") == move_uid - and child.get("Name") == "en" - ): - name_con = child - break - - if name_con is not None: - is_enabled = True - debug_print( - f"MOVE with UId {move_uid} is directly enabled by powerrail in wire {wire_idx}", - debug, - ) - break - - if not is_enabled: - debug_print( - f"MOVE with UId {move_uid} is not directly enabled, trying alternative search", - debug, - ) - - # Try a more direct XML search - for wire in wire_elements: - wire_str = etree.tostring(wire).decode("utf-8") - if ( - f'UId="{move_uid}"' in wire_str - and 'Name="en"' in wire_str - and "