Compare commits
10 Commits
1b727fa4bb
...
75cd67c446
Author | SHA1 | Date |
---|---|---|
|
75cd67c446 | |
|
3f3dd1ed29 | |
|
48467ac7ea | |
|
a35f891eb7 | |
|
c62ce45987 | |
|
3787411cf5 | |
|
94163baee0 | |
|
f090305574 | |
|
5e4f351d29 | |
|
d173278ce8 |
|
@ -0,0 +1 @@
|
|||
<WorkspaceLanguage>en-US</WorkspaceLanguage>
|
|
@ -0,0 +1,477 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Document>
|
||||
<Engineering version="V18" />
|
||||
<SW.Blocks.FC ID="0">
|
||||
<AttributeList>
|
||||
<AutoNumber>false</AutoNumber>
|
||||
<HeaderFamily>TASK2</HeaderFamily>
|
||||
<Interface><Sections xmlns="http://www.siemens.com/automation/Openness/SW/Interface/v5">
|
||||
<Section Name="Input" />
|
||||
<Section Name="Output" />
|
||||
<Section Name="InOut" />
|
||||
<Section Name="Temp" />
|
||||
<Section Name="Constant" />
|
||||
<Section Name="Return">
|
||||
<Member Name="Ret_Val" Datatype="Void" />
|
||||
</Section>
|
||||
</Sections></Interface>
|
||||
<MemoryLayout>Standard</MemoryLayout>
|
||||
<Name>BlenderCtrl_ProdModeInit</Name>
|
||||
<Namespace />
|
||||
<Number>2012</Number>
|
||||
<ProgrammingLanguage>LAD</ProgrammingLanguage>
|
||||
<SetENOAutomatically>false</SetENOAutomatically>
|
||||
</AttributeList>
|
||||
<ObjectList>
|
||||
<MultilingualText ID="1" CompositionName="Comment">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="2" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="4" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="5" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="6" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="7" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="8" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
<SW.Blocks.CompileUnit ID="9" CompositionName="CompileUnits">
|
||||
<AttributeList>
|
||||
<NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
|
||||
<Parts>
|
||||
<Call UId="21">
|
||||
<CallInfo Name="BlenderPID_PIDResInteg" BlockType="FC" />
|
||||
</Call>
|
||||
</Parts>
|
||||
<Wires>
|
||||
<Wire UId="22">
|
||||
<Powerrail />
|
||||
<NameCon UId="21" Name="en" />
|
||||
</Wire>
|
||||
</Wires>
|
||||
</FlgNet></NetworkSource>
|
||||
<ProgrammingLanguage>LAD</ProgrammingLanguage>
|
||||
</AttributeList>
|
||||
<ObjectList>
|
||||
<MultilingualText ID="A" CompositionName="Comment">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="B" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="C" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="D" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="E" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="F" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="10" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="11" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
<MultilingualText ID="12" CompositionName="Title">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="13" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text>PID Reset Integral</Text>
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="14" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="15" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="16" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="17" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="18" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="19" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
</ObjectList>
|
||||
</SW.Blocks.CompileUnit>
|
||||
<SW.Blocks.CompileUnit ID="1A" CompositionName="CompileUnits">
|
||||
<AttributeList>
|
||||
<NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
|
||||
<Parts>
|
||||
<Call UId="21">
|
||||
<CallInfo Name="BlenderCtrl_InitErrors" BlockType="FC" />
|
||||
</Call>
|
||||
</Parts>
|
||||
<Wires>
|
||||
<Wire UId="22">
|
||||
<Powerrail />
|
||||
<NameCon UId="21" Name="en" />
|
||||
</Wire>
|
||||
</Wires>
|
||||
</FlgNet></NetworkSource>
|
||||
<ProgrammingLanguage>LAD</ProgrammingLanguage>
|
||||
</AttributeList>
|
||||
<ObjectList>
|
||||
<MultilingualText ID="1B" CompositionName="Comment">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="1C" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="1D" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="1E" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="1F" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="20" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="21" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="22" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
<MultilingualText ID="23" CompositionName="Title">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="24" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text>Ctrl Init Errors</Text>
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="25" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="26" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="27" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="28" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="29" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="2A" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
</ObjectList>
|
||||
</SW.Blocks.CompileUnit>
|
||||
<SW.Blocks.CompileUnit ID="2B" CompositionName="CompileUnits">
|
||||
<AttributeList>
|
||||
<NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
|
||||
<Parts>
|
||||
<Access Scope="LiteralConstant" UId="21">
|
||||
<Constant>
|
||||
<ConstantType>Real</ConstantType>
|
||||
<ConstantValue>0.0</ConstantValue>
|
||||
</Constant>
|
||||
</Access>
|
||||
<Access Scope="GlobalVariable" UId="22">
|
||||
<Symbol>
|
||||
<Component Name="HMI_Variables_Status" />
|
||||
<Component Name="Analog_Values" />
|
||||
<Component Name="TP301RunOutCount" />
|
||||
</Symbol>
|
||||
</Access>
|
||||
<Part Name="Move" UId="23" DisabledENO="false">
|
||||
<TemplateValue Name="Card" Type="Cardinality">1</TemplateValue>
|
||||
</Part>
|
||||
</Parts>
|
||||
<Wires>
|
||||
<Wire UId="24">
|
||||
<IdentCon UId="21" />
|
||||
<NameCon UId="23" Name="in" />
|
||||
</Wire>
|
||||
<Wire UId="25">
|
||||
<NameCon UId="23" Name="out1" />
|
||||
<IdentCon UId="22" />
|
||||
</Wire>
|
||||
<Wire UId="26">
|
||||
<Powerrail />
|
||||
<NameCon UId="23" Name="en" />
|
||||
</Wire>
|
||||
</Wires>
|
||||
</FlgNet></NetworkSource>
|
||||
<ProgrammingLanguage>LAD</ProgrammingLanguage>
|
||||
</AttributeList>
|
||||
<ObjectList>
|
||||
<MultilingualText ID="2C" CompositionName="Comment">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="2D" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="2E" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="2F" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="30" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="31" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="32" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="33" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
<MultilingualText ID="34" CompositionName="Title">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="35" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text>RunOut Counter</Text>
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="36" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="37" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="38" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="39" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3A" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3B" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
</ObjectList>
|
||||
</SW.Blocks.CompileUnit>
|
||||
<MultilingualText ID="3C" CompositionName="Title">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="3D" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text>Prode Mode Init</Text>
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3E" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3F" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="40" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="41" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="42" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="43" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
</ObjectList>
|
||||
</SW.Blocks.FC>
|
||||
</Document>
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"block_name": "BlenderCtrl_ProdModeInit",
|
||||
"block_number": 2012,
|
||||
"language": "LAD",
|
||||
"block_comment": "",
|
||||
"interface": {
|
||||
"Return": [
|
||||
{
|
||||
"name": "Ret_Val",
|
||||
"datatype": "Void"
|
||||
}
|
||||
]
|
||||
},
|
||||
"networks": [
|
||||
{
|
||||
"id": "9",
|
||||
"title": "PID Reset Integral",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "21",
|
||||
"uid": "21",
|
||||
"type": "Call",
|
||||
"block_name": "BlenderPID_PIDResInteg",
|
||||
"block_type": "FC",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1A",
|
||||
"title": "Ctrl Init Errors",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "21",
|
||||
"uid": "21",
|
||||
"type": "Call",
|
||||
"block_name": "BlenderCtrl_InitErrors",
|
||||
"block_type": "FC",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2B",
|
||||
"title": "RunOut Counter",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Move",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in": {
|
||||
"uid": "21",
|
||||
"scope": "LiteralConstant",
|
||||
"type": "constant",
|
||||
"datatype": "Real",
|
||||
"value": 0.0
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
"out1": [
|
||||
{
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"HMI_Variables_Status\".\"Analog_Values\".\"TP301RunOutCount\""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"block_name": "BlenderCtrl_ProdModeInit",
|
||||
"block_number": 2012,
|
||||
"language": "LAD",
|
||||
"block_comment": "",
|
||||
"interface": {
|
||||
"Return": [
|
||||
{
|
||||
"name": "Ret_Val",
|
||||
"datatype": "Void"
|
||||
}
|
||||
]
|
||||
},
|
||||
"networks": [
|
||||
{
|
||||
"id": "9",
|
||||
"title": "PID Reset Integral",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "21",
|
||||
"uid": "21",
|
||||
"type": "Call_FC_scl",
|
||||
"block_name": "BlenderPID_PIDResInteg",
|
||||
"block_type": "FC",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "BlenderPID_PIDResInteg();"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1A",
|
||||
"title": "Ctrl Init Errors",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "21",
|
||||
"uid": "21",
|
||||
"type": "Call_FC_scl",
|
||||
"block_name": "BlenderCtrl_InitErrors",
|
||||
"block_type": "FC",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "BlenderCtrl_InitErrors();"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2B",
|
||||
"title": "RunOut Counter",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Move_scl",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in": {
|
||||
"uid": "21",
|
||||
"scope": "LiteralConstant",
|
||||
"type": "constant",
|
||||
"datatype": "Real",
|
||||
"value": 0.0
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
"out1": [
|
||||
{
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"HMI_Variables_Status\".\"Analog_Values\".\"TP301RunOutCount\""
|
||||
}
|
||||
]
|
||||
},
|
||||
"scl": "\"HMI_Variables_Status\".\"Analog_Values\".\"TP301RunOutCount\" := 0.0;"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Block Name (Original): BlenderCtrl_ProdModeInit
|
||||
// Block Number: 2012
|
||||
// Original Language: LAD
|
||||
|
||||
FUNCTION_BLOCK "BlenderCtrl_ProdModeInit"
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
VERSION : 0.1
|
||||
|
||||
VAR_INPUT
|
||||
END_VAR
|
||||
|
||||
VAR_OUTPUT
|
||||
END_VAR
|
||||
|
||||
VAR_IN_OUT
|
||||
END_VAR
|
||||
|
||||
VAR_TEMP
|
||||
END_VAR
|
||||
|
||||
BEGIN
|
||||
|
||||
// Network 1: PID Reset Integral
|
||||
|
||||
BlenderPID_PIDResInteg();
|
||||
|
||||
// Network 2: Ctrl Init Errors
|
||||
|
||||
BlenderCtrl_InitErrors();
|
||||
|
||||
// Network 3: RunOut Counter
|
||||
|
||||
"HMI_Variables_Status"."Analog_Values"."TP301RunOutCount" := 0.0;
|
||||
|
||||
END_FUNCTION_BLOCK
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,392 @@
|
|||
// Block Name (Original): BlenderCtrl__Main
|
||||
// Block Number: 2000
|
||||
// Original Language: LAD
|
||||
|
||||
FUNCTION_BLOCK "BlenderCtrl__Main"
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
VERSION : 0.1
|
||||
|
||||
VAR_INPUT
|
||||
END_VAR
|
||||
|
||||
VAR_OUTPUT
|
||||
END_VAR
|
||||
|
||||
VAR_IN_OUT
|
||||
END_VAR
|
||||
|
||||
VAR_TEMP
|
||||
All_Auto_RETVAL : Int;
|
||||
Reset_SP_Word_RETVAL : Int;
|
||||
mResetWaterTot : Bool;
|
||||
mResetSyrupTot : Bool;
|
||||
mResetCO2Tot : Bool;
|
||||
mResetProductTot : Bool;
|
||||
Block_Move_Err : Int;
|
||||
END_VAR
|
||||
|
||||
BEGIN
|
||||
|
||||
// Network 1: Clock Generation
|
||||
|
||||
Clock Signal();
|
||||
|
||||
// Network 2: Machine Init
|
||||
|
||||
BlenderCtrl_MachineInit();
|
||||
|
||||
// Network 3: Filler Head
|
||||
|
||||
// RLO: "AUX FALSE"
|
||||
|
||||
// Network 4: Emergency Pressed
|
||||
|
||||
// RLO: "gIN_VoltageOk"
|
||||
|
||||
// Network 5: Air and CO2 pressure ok and auxiliary ok
|
||||
|
||||
// RLO: "gIN_LinePressCO2Ok"
|
||||
// RLO: "gWorkshopTest"
|
||||
// RLO: "gWorkshopTest" AND "gWorkshop_Co2_Presence"
|
||||
// RLO: ("gWorkshopTest" AND "gWorkshop_Co2_Presence") AND "gWorkshop_CIP_Signals"
|
||||
// RLO: ("gIN_LinePressCO2Ok" OR (("gWorkshopTest" AND "gWorkshop_Co2_Presence") AND "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered"
|
||||
// RLO: "Disable_Bit"
|
||||
// RLO: ((("gIN_LinePressCO2Ok" OR (("gWorkshopTest" AND "gWorkshop_Co2_Presence") AND "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered") OR "Disable_Bit") AND "gIN_VoltageOk"
|
||||
"gBlenderSuppliesOk" := ((("gIN_LinePressCO2Ok" OR (("gWorkshopTest" AND "gWorkshop_Co2_Presence") AND "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered") OR "Disable_Bit") AND "gIN_VoltageOk";
|
||||
|
||||
// Network 6: Blender State Num
|
||||
|
||||
"HMI_Variables_Status"."Procedures"."BlenderStateNum" := 0;
|
||||
|
||||
// Network 7: Delay Power On
|
||||
|
||||
// RLO: "FirstScan"
|
||||
|
||||
// Network 8: Production Mode
|
||||
|
||||
// RLO: "HMI_Variables_Status"."System"."Blender_Prod_CIP"
|
||||
"gBlenderProdMode" := "HMI_Variables_Status"."System"."Blender_Prod_CIP";
|
||||
|
||||
// Network 9: CIp Mode
|
||||
|
||||
// RLO: "HMI_Variables_Status"."System"."Blender_Prod_CIP"
|
||||
"gBlenderCIPMode" := "HMI_Variables_Status"."System"."Blender_Prod_CIP";
|
||||
IF "HMI_Variables_Status"."System"."Blender_Prod_CIP" THEN
|
||||
"HMI_Variables_Status"."Procedures"."BlenderStateNum" := 19;
|
||||
END_IF;
|
||||
|
||||
// Network 10: Error Faults
|
||||
|
||||
// RLO: "AUX FALSE"
|
||||
|
||||
// Network 11: Filler Bottle Count Used to push Product
|
||||
|
||||
// RLO: "System_RunOut_Variables"."ProdPipeRunOutWaterCount"
|
||||
"System_RunOut_Variables"."ProdPipeRunOutFillerBott" := "System_RunOut_Variables"."ProdPipeRunOutWaterCount";
|
||||
|
||||
// Network 12: Water Bypass Enable
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass"
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair"
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation"
|
||||
// RLO: ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation")) AND "Blender_Variables_Pers"."gWaterRecipe"
|
||||
// RLO: (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation")) AND "Blender_Variables_Pers"."gWaterRecipe") AND "Blender_Variables_Pers"."gCarboStillRecipe"
|
||||
"gStillWaterByPassEn" := (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation")) AND "Blender_Variables_Pers"."gWaterRecipe") AND "Blender_Variables_Pers"."gCarboStillRecipe";
|
||||
|
||||
// Network 13: Still Water Bypass
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem"
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass"
|
||||
// RLO: ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass") AND "Blender_Variables_Pers"."gWaterRecipe"
|
||||
// RLO: (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass") AND "Blender_Variables_Pers"."gWaterRecipe") AND "Blender_Variables_Pers"."gCarboStillRecipe"
|
||||
"gBlendFiStillWaterByPass" := (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass") AND "Blender_Variables_Pers"."gWaterRecipe") AND "Blender_Variables_Pers"."gCarboStillRecipe";
|
||||
|
||||
// Network 14: Manual Syrup Drain Valve Open - Operator Alarm
|
||||
|
||||
// RLO: "gSyrupRoomEn"
|
||||
// RLO: "gSyrupRoomEn" AND "gIN_HVP301_Aux"
|
||||
// RLO: ("gSyrupRoomEn" AND "gIN_HVP301_Aux") AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled"
|
||||
// RLO: (("gSyrupRoomEn" AND "gIN_HVP301_Aux") AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled") AND "Procedure_Variables"."FTP302Line_Preparation"."Done"
|
||||
// RLO: ((("gSyrupRoomEn" AND "gIN_HVP301_Aux") AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled") AND "Procedure_Variables"."FTP302Line_Preparation"."Done") AND "Procedure_Variables"."Syr_RunOut"."Done"
|
||||
// RLO: "gBlenderCIPMode"
|
||||
// RLO: "gBlenderCIPMode" AND "gIN_CIP_CIPRunning"
|
||||
// RLO: ("gBlenderCIPMode" AND "gIN_CIP_CIPRunning") AND "Procedure_Variables"."Blender_Run"."Running"
|
||||
"gHVP301_Open" := (((("gSyrupRoomEn" AND "gIN_HVP301_Aux") AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled") AND "Procedure_Variables"."FTP302Line_Preparation"."Done") AND "Procedure_Variables"."Syr_RunOut"."Done") OR (("gBlenderCIPMode" AND "gIN_CIP_CIPRunning") AND "Procedure_Variables"."Blender_Run"."Running");
|
||||
|
||||
// Network 15: Manual Syrup Drain Valve Open - Operator Alarm
|
||||
|
||||
// RLO: "gIN_HVM302_Aux"
|
||||
|
||||
// Network 16: Maselli Control
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BrixMeter"
|
||||
// Cond: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 6
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 6 THEN
|
||||
Maselli_PA_Control();
|
||||
END_IF;
|
||||
|
||||
// Network 17: mPDS Control
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BrixMeter"
|
||||
// Cond: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 5
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 5 THEN
|
||||
mPDS_PA_Control();
|
||||
END_IF;
|
||||
|
||||
// Network 18: mPDS Syrup Control
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter" THEN
|
||||
mPDS_SYR_PA_Control();
|
||||
END_IF;
|
||||
|
||||
// Network 19: Co2 Analog Input
|
||||
// GetProdBrixCO2_FromAnalogIn
|
||||
// CALL "GetProdBrixCO2_FromAn"
|
||||
// NOP 0
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BrixMeter"
|
||||
// Cond: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 3
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 3 THEN
|
||||
GetProdBrixCO2_Anal_Inpt();
|
||||
END_IF;
|
||||
|
||||
// Network 20: Quality
|
||||
|
||||
ProductQuality();
|
||||
|
||||
// Network 21: Input Data
|
||||
|
||||
// ERROR: Call a bloque no soportado: Input
|
||||
|
||||
// Network 22: Sel Brix Source Check
|
||||
|
||||
SelCheckBrixSource();
|
||||
|
||||
// Network 23: Check Water Cooling System Temperature
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_InverterRecirPumpPPM306"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_InverterRecirPumpPPM306" THEN
|
||||
CTRLCoolingSystem();
|
||||
END_IF;
|
||||
|
||||
// Network 24: Tank Level
|
||||
|
||||
TankLevel();
|
||||
|
||||
// Network 25: Production ONS
|
||||
|
||||
// RLO: "gBlenderProdMode"
|
||||
// PBox 26 - Passing bit: "M19001"
|
||||
// RLO: "M19001" AND "mDelayPowerOnTmr"
|
||||
"gProductionONS" := "M19001" AND "mDelayPowerOnTmr";
|
||||
|
||||
// Network 26: Blender Prod Mode Init
|
||||
|
||||
// RLO: "gProductionONS"
|
||||
// RLO: "Procedure_Variables"."Blender_Rinse"."ONS_Done"
|
||||
// RLO: ("gProductionONS" OR "Procedure_Variables"."Blender_Rinse"."ONS_Done") AND "Blender_Variables_Pers"."gBlenderStarted"
|
||||
IF ("gProductionONS" OR "Procedure_Variables"."Blender_Rinse"."ONS_Done") AND "Blender_Variables_Pers"."gBlenderStarted" THEN
|
||||
BlenderCtrl_ProdModeInit();
|
||||
END_IF;
|
||||
|
||||
// Network 27: Rinse ONS
|
||||
|
||||
// RLO: "HMI_Variables_Status"."System"."Blender_Prod_CIP"
|
||||
// PBox 26 - Passing bit: "M19002"
|
||||
// RLO: "M19002" AND "mDelayPowerOnTmr"
|
||||
"gRinseONS" := "M19002" AND "mDelayPowerOnTmr";
|
||||
|
||||
// Network 28: CIP ONS
|
||||
|
||||
// RLO: "gBlenderCIPMode"
|
||||
// PBox 26 - Passing bit: "M19003"
|
||||
// RLO: "M19003" AND "mDelayPowerOnTmr"
|
||||
"gCIPONS" := "M19003" AND "mDelayPowerOnTmr";
|
||||
|
||||
// Network 29: CIp Mode Init
|
||||
|
||||
// RLO: "gCIPONS"
|
||||
IF "gCIPONS" THEN
|
||||
BlenderCtrl_CIPModeInit();
|
||||
END_IF;
|
||||
|
||||
// Network 30: Reset SPWords
|
||||
|
||||
BlenderCtrl_ResetSPWord();
|
||||
|
||||
// Network 31: Blender Run Control
|
||||
|
||||
BlenderRun__Control();
|
||||
|
||||
// Network 32: Tank Pressure Control
|
||||
|
||||
Prod Tank PressCtrl();
|
||||
|
||||
// Network 33: Balaiage
|
||||
|
||||
Baialage();
|
||||
|
||||
// Network 34: First Production
|
||||
|
||||
// ERROR: Call a bloque no soportado: ProcedureFirstProduction
|
||||
|
||||
// Network 35: CIP MAIN Calling
|
||||
|
||||
CIPMain();
|
||||
|
||||
// Network 36: Blender Rinse
|
||||
|
||||
BlenderRinse();
|
||||
|
||||
// Network 37: Safeties
|
||||
|
||||
Safeties();
|
||||
|
||||
// Network 38: Instrument Scanner
|
||||
|
||||
Instrument_Scanner();
|
||||
|
||||
// Network 39: Vacuum Control
|
||||
|
||||
VacuumCtrl();
|
||||
|
||||
// Network 40: Syrup Room Control
|
||||
|
||||
SyrupRoomCtrl();
|
||||
|
||||
// Network 41: Blend Procedure Data
|
||||
|
||||
// RLO: "mDelayPowerOnTmr"
|
||||
IF "mDelayPowerOnTmr" THEN
|
||||
// ERROR: Call a bloque no soportado: Procedure
|
||||
END_IF;
|
||||
|
||||
// Network 42: Pneumatic Valve Control
|
||||
|
||||
Pneumatic Valve Ctrl();
|
||||
|
||||
// Network 43: Pumps Control
|
||||
|
||||
PumpsControl();
|
||||
|
||||
// Network 44: Prod Report Manager
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Report"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Report" THEN
|
||||
ProdReportManager();
|
||||
END_IF;
|
||||
|
||||
// Network 45: Outputs
|
||||
|
||||
Output();
|
||||
|
||||
// Network 46: SLIM BLOCK
|
||||
|
||||
SLIM_Block();
|
||||
|
||||
// Network 47: Interlocking Panel 1
|
||||
|
||||
Interlocking_Panel_1();
|
||||
|
||||
// Network 48: Filler Control
|
||||
|
||||
FillerControl();
|
||||
|
||||
// Network 49: Blender Ctrl Update PWORD
|
||||
|
||||
BlenderCtrl_UpdatePWord();
|
||||
|
||||
// Network 50: ResetTotalizer
|
||||
|
||||
// RLO: "gBlendResetTotalizer"
|
||||
|
||||
// Network 51: ResetWaterTot
|
||||
|
||||
// RLO: "gFTN301_ResetTot"
|
||||
// RLO: "mResetTotalizerTmr"
|
||||
|
||||
// Network 52: Water VFM Reset Totalizer
|
||||
|
||||
// RLO: "gFTN301_ResetTot"
|
||||
|
||||
// Network 53: ResetCO2Tot
|
||||
|
||||
// RLO: "gFTP302_ResetTot"
|
||||
// RLO: "mResetTotalizerTmr"
|
||||
|
||||
// Network 54: Syrup MFM Reset Totalizer
|
||||
|
||||
// RLO: "gFTP302_ResetTot"
|
||||
|
||||
// Network 55: ResetProductTot
|
||||
|
||||
// RLO: "gFTM303_ResetTot"
|
||||
// RLO: "mResetTotalizerTmr"
|
||||
|
||||
// Network 56: CO2 MFM Reset Tot
|
||||
|
||||
// RLO: "gFTM303_ResetTot"
|
||||
|
||||
// Network 57: ResetCO2Tot
|
||||
|
||||
// RLO: "gProductMFMResetTot"
|
||||
// RLO: "mResetTotalizerTmr"
|
||||
|
||||
// Network 58: Reset Totalizer
|
||||
|
||||
// RLO: "gProductMFMResetTot"
|
||||
|
||||
// Network 59: Reset Totalizer
|
||||
|
||||
// RLO: "gBlendResetTotalizer"
|
||||
|
||||
// Network 60: Blender Ctrl Command
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Simulation"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Simulation" THEN
|
||||
BlenderCtrl_MFM Command();
|
||||
END_IF;
|
||||
|
||||
// Network 61: DP Global Diag
|
||||
|
||||
CPU_DP Global Diag();
|
||||
|
||||
// Network 62: Profibus
|
||||
|
||||
Profibus Network();
|
||||
|
||||
// Network 63: Valve Fault
|
||||
|
||||
ModValveFault();
|
||||
|
||||
// Network 64: All Auto
|
||||
|
||||
// RLO: "HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Command"
|
||||
// RLO: "HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Command" AND "HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Enable"
|
||||
|
||||
// Network 65: Ctrl HMI Manual Active
|
||||
|
||||
BlenderCtrl_ManualActive();
|
||||
|
||||
// Network 66: Mod Copy Recipe
|
||||
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."Main_Page"
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."Main_Page" AND "mFP_Recip_Main_Page"
|
||||
"mAux_FP_M700_1" := "HMI_Variables_Cmd"."Recipe"."Main_Page" AND "mFP_Recip_Main_Page";
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."Main_Page"
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."Main_Page" AND "HMI_Variables_Cmd"."Recipe"."Edit"
|
||||
// RLO: "mAux_FP_M700_1"
|
||||
|
||||
// Network 67: to HMI - Recipe Management
|
||||
|
||||
// RLO: "AUX TRUE"
|
||||
IF "AUX TRUE" THEN
|
||||
// ERROR: Call a bloque no soportado: RecipeManagement - Prod
|
||||
END_IF;
|
||||
|
||||
// Network 68: Recipe Calculation
|
||||
|
||||
RecipeCalculation();
|
||||
|
||||
END_FUNCTION_BLOCK
|
Binary file not shown.
|
@ -53,7 +53,9 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "26",
|
||||
"uid": "26",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -69,7 +71,9 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "27",
|
||||
"uid": "27",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -79,8 +83,8 @@
|
|||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "26",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "26",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -88,14 +92,13 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
"uid": "28",
|
||||
"type": "Add",
|
||||
"template_values": {
|
||||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "23",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gSLIM_Sec\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
"scope": "LiteralConstant",
|
||||
|
@ -105,9 +108,15 @@
|
|||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "27",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "27",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"in1": {
|
||||
"uid": "23",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gSLIM_Sec\""
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -130,7 +139,9 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -146,7 +157,11 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "25",
|
||||
"uid": "25",
|
||||
"type": "Move",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "22",
|
||||
|
@ -157,8 +172,8 @@
|
|||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "24",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "24",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -182,7 +197,9 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "26",
|
||||
"uid": "26",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -198,7 +215,9 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "27",
|
||||
"uid": "27",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -208,8 +227,8 @@
|
|||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "26",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "26",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -217,14 +236,13 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
"uid": "28",
|
||||
"type": "Add",
|
||||
"template_values": {
|
||||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "23",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
"scope": "LiteralConstant",
|
||||
|
@ -234,9 +252,15 @@
|
|||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "27",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "27",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"in1": {
|
||||
"uid": "23",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -259,13 +283,14 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Eq",
|
||||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "22",
|
||||
|
@ -274,27 +299,32 @@
|
|||
"datatype": "Int",
|
||||
"value": 60
|
||||
},
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
"in1": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
{
|
||||
"instruction_uid": "25",
|
||||
"uid": "25",
|
||||
"type": "Coil",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "24",
|
||||
"source_instruction_type": "Eq",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "23",
|
||||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"m1MinONS\""
|
||||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Eq",
|
||||
"source_instruction_uid": "24",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
|
@ -308,7 +338,9 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "27",
|
||||
"uid": "27",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -324,7 +356,11 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
"uid": "28",
|
||||
"type": "Move",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "22",
|
||||
|
@ -335,8 +371,8 @@
|
|||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "27",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "27",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -353,20 +389,31 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "29",
|
||||
"uid": "29",
|
||||
"type": "Add",
|
||||
"template_values": {
|
||||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "24",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
"scope": "LiteralConstant",
|
||||
"type": "constant",
|
||||
"datatype": "Int",
|
||||
"value": 1
|
||||
},
|
||||
"in1": {
|
||||
"uid": "24",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
|
||||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "27",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -389,13 +436,14 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Eq",
|
||||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "22",
|
||||
|
@ -404,27 +452,32 @@
|
|||
"datatype": "Int",
|
||||
"value": 60
|
||||
},
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
"in1": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
{
|
||||
"instruction_uid": "25",
|
||||
"uid": "25",
|
||||
"type": "Coil",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "24",
|
||||
"source_instruction_type": "Eq",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "23",
|
||||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"m1HourONS\""
|
||||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Eq",
|
||||
"source_instruction_uid": "24",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
|
@ -438,7 +491,9 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "30",
|
||||
"uid": "30",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -454,7 +509,11 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "31",
|
||||
"uid": "31",
|
||||
"type": "Move",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "22",
|
||||
|
@ -465,8 +524,8 @@
|
|||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "30",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "30",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -483,20 +542,31 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "32",
|
||||
"uid": "32",
|
||||
"type": "Add",
|
||||
"template_values": {
|
||||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "24",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdHour\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
"scope": "LiteralConstant",
|
||||
"type": "constant",
|
||||
"datatype": "Int",
|
||||
"value": 1
|
||||
},
|
||||
"in1": {
|
||||
"uid": "24",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdHour\""
|
||||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "30",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -512,20 +582,31 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "33",
|
||||
"uid": "33",
|
||||
"type": "Add",
|
||||
"template_values": {
|
||||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "27",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gBlendingMaintHour\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "28",
|
||||
"scope": "LiteralConstant",
|
||||
"type": "constant",
|
||||
"datatype": "Int",
|
||||
"value": 1
|
||||
},
|
||||
"in1": {
|
||||
"uid": "27",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gBlendingMaintHour\""
|
||||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "30",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -548,7 +629,9 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "29",
|
||||
"uid": "29",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -564,7 +647,9 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "30",
|
||||
"uid": "30",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -577,18 +662,22 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "31",
|
||||
"uid": "31",
|
||||
"type": "O",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "29",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"in2": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "30",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "30",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"in1": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "29",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -596,7 +685,11 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "32",
|
||||
"uid": "32",
|
||||
"type": "Move",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "23",
|
||||
|
@ -607,8 +700,8 @@
|
|||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "31",
|
||||
"source_instruction_type": "O",
|
||||
"source_instruction_uid": "31",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -625,7 +718,11 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "33",
|
||||
"uid": "33",
|
||||
"type": "Move",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "25",
|
||||
|
@ -633,6 +730,12 @@
|
|||
"type": "constant",
|
||||
"datatype": "Int",
|
||||
"value": 0
|
||||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "31",
|
||||
"source_instruction_type": "O",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -648,7 +751,11 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "34",
|
||||
"uid": "34",
|
||||
"type": "Move",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "27",
|
||||
|
@ -656,6 +763,12 @@
|
|||
"type": "constant",
|
||||
"datatype": "Int",
|
||||
"value": 0
|
||||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "31",
|
||||
"source_instruction_type": "O",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -678,7 +791,9 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "26",
|
||||
"uid": "26",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -694,7 +809,9 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "27",
|
||||
"uid": "27",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -704,8 +821,8 @@
|
|||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "26",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "26",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -713,14 +830,13 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
"uid": "28",
|
||||
"type": "Add",
|
||||
"template_values": {
|
||||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "23",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
"scope": "LiteralConstant",
|
||||
|
@ -730,9 +846,15 @@
|
|||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "27",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "27",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"in1": {
|
||||
"uid": "23",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -755,7 +877,12 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "35",
|
||||
"uid": "35",
|
||||
"type": "Convert",
|
||||
"template_values": {
|
||||
"SrcType": "Type",
|
||||
"DestType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "21",
|
||||
|
@ -780,12 +907,23 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "36",
|
||||
"uid": "36",
|
||||
"type": "Mod",
|
||||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
"scope": "TypedConstant",
|
||||
"type": "constant",
|
||||
"datatype": "TypedConstant",
|
||||
"value": "DINT#60"
|
||||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "35",
|
||||
"source_instruction_type": "Convert",
|
||||
"source_instruction_uid": "35",
|
||||
"source_pin": "eno"
|
||||
},
|
||||
"in1": {
|
||||
|
@ -793,13 +931,6 @@
|
|||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"I_DIRunning_sec\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
"scope": "TypedConstant",
|
||||
"type": "constant",
|
||||
"datatype": "TypedConstant",
|
||||
"value": "DINT#60"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -823,52 +954,60 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "37",
|
||||
"uid": "37",
|
||||
"type": "Eq",
|
||||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "36",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "36",
|
||||
"source_pin": "eno"
|
||||
},
|
||||
"in1": {
|
||||
"uid": "26",
|
||||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"MOD60\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "27",
|
||||
"scope": "TypedConstant",
|
||||
"type": "constant",
|
||||
"datatype": "TypedConstant",
|
||||
"value": "DINT#0"
|
||||
},
|
||||
"in1": {
|
||||
"uid": "26",
|
||||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"MOD60\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
{
|
||||
"instruction_uid": "38",
|
||||
"uid": "38",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "37",
|
||||
"source_instruction_type": "Eq",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "28",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Procedure_Variables\".\"Blender_Run\".\"Running\""
|
||||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Eq",
|
||||
"source_instruction_uid": "37",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
{
|
||||
"instruction_uid": "39",
|
||||
"uid": "39",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "29",
|
||||
|
@ -878,8 +1017,8 @@
|
|||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "38",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "38",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -887,14 +1026,13 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "40",
|
||||
"uid": "40",
|
||||
"type": "Add",
|
||||
"template_values": {
|
||||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "30",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "31",
|
||||
"scope": "LiteralConstant",
|
||||
|
@ -904,9 +1042,15 @@
|
|||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "39",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "39",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"in1": {
|
||||
"uid": "30",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -922,7 +1066,9 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "41",
|
||||
"uid": "41",
|
||||
"type": "PBox",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"bit": {
|
||||
"uid": "33",
|
||||
|
@ -935,19 +1081,21 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "42",
|
||||
"uid": "42",
|
||||
"type": "Coil",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "41",
|
||||
"source_instruction_type": "PBox",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "34",
|
||||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"mRunMin\""
|
||||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "PBox",
|
||||
"source_instruction_uid": "41",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
|
@ -961,7 +1109,9 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "32",
|
||||
"uid": "32",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -977,7 +1127,12 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "33",
|
||||
"uid": "33",
|
||||
"type": "Convert",
|
||||
"template_values": {
|
||||
"SrcType": "Type",
|
||||
"DestType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "22",
|
||||
|
@ -987,8 +1142,8 @@
|
|||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "32",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "32",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
|
@ -1005,12 +1160,23 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "34",
|
||||
"uid": "34",
|
||||
"type": "Mod",
|
||||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
"scope": "TypedConstant",
|
||||
"type": "constant",
|
||||
"datatype": "TypedConstant",
|
||||
"value": "DINT#60"
|
||||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "33",
|
||||
"source_instruction_type": "Convert",
|
||||
"source_instruction_uid": "33",
|
||||
"source_pin": "eno"
|
||||
},
|
||||
"in1": {
|
||||
|
@ -1018,13 +1184,6 @@
|
|||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"I_DIRunning_min\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
"scope": "TypedConstant",
|
||||
"type": "constant",
|
||||
"datatype": "TypedConstant",
|
||||
"value": "DINT#60"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -1048,38 +1207,54 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "35",
|
||||
"uid": "35",
|
||||
"type": "Eq",
|
||||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "34",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "34",
|
||||
"source_pin": "eno"
|
||||
},
|
||||
"in1": {
|
||||
"uid": "27",
|
||||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"MOD60\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "28",
|
||||
"scope": "TypedConstant",
|
||||
"type": "constant",
|
||||
"datatype": "TypedConstant",
|
||||
"value": "DINT#0"
|
||||
},
|
||||
"in1": {
|
||||
"uid": "27",
|
||||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"MOD60\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
{
|
||||
"instruction_uid": "36",
|
||||
"uid": "36",
|
||||
"type": "Add",
|
||||
"template_values": {
|
||||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "30",
|
||||
"scope": "LiteralConstant",
|
||||
"type": "constant",
|
||||
"datatype": "Int",
|
||||
"value": 1
|
||||
},
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": "35",
|
||||
"source_instruction_type": "Eq",
|
||||
"source_instruction_uid": "35",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"in1": {
|
||||
|
@ -1087,13 +1262,6 @@
|
|||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gRunningMaintHour\""
|
||||
},
|
||||
"in2": {
|
||||
"uid": "30",
|
||||
"scope": "LiteralConstant",
|
||||
"type": "constant",
|
||||
"datatype": "Int",
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -1116,7 +1284,11 @@
|
|||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Move",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "21",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,120 @@
|
|||
// Block Name (Original): BlenderRun_ProdTime
|
||||
// Block Number: 2040
|
||||
// Original Language: LAD
|
||||
|
||||
FUNCTION_BLOCK "BlenderRun_ProdTime"
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
VERSION : 0.1
|
||||
|
||||
VAR_INPUT
|
||||
END_VAR
|
||||
|
||||
VAR_OUTPUT
|
||||
END_VAR
|
||||
|
||||
VAR_IN_OUT
|
||||
END_VAR
|
||||
|
||||
VAR_TEMP
|
||||
m1MinONS : Bool;
|
||||
m1HourONS : Bool;
|
||||
Buffer : Bool;
|
||||
mRunMin : Bool;
|
||||
mRunHr : Bool;
|
||||
I_DIRunning_sec : DInt;
|
||||
I_DIRunning_min : DInt;
|
||||
MOD60 : DInt;
|
||||
END_VAR
|
||||
|
||||
BEGIN
|
||||
|
||||
// Network 1: Seconds
|
||||
|
||||
IF "Procedure_Variables"."Blender_Run"."Running" AND "CLK_1.0S" THEN
|
||||
"Blender_Variables_Pers"."gSLIM_Sec" := "Blender_Variables_Pers"."gSLIM_Sec" + 1;
|
||||
END_IF;
|
||||
|
||||
// Network 2: Reset Hours
|
||||
|
||||
IF "SLIM_Variables"."ResetHour" THEN
|
||||
"Blender_Variables_Pers"."gSLIM_Sec" := 0;
|
||||
END_IF;
|
||||
|
||||
// Network 3: Seconds Counter
|
||||
|
||||
IF "gBlenderBlending" AND "CLK_1.0S" THEN
|
||||
"Blender_Variables_Pers"."gProdSec" := "Blender_Variables_Pers"."gProdSec" + 1;
|
||||
END_IF;
|
||||
|
||||
// Network 4: Minute
|
||||
|
||||
"m1MinONS" := "Blender_Variables_Pers"."gProdSec" = 60;
|
||||
|
||||
// Network 5: Minute Counter
|
||||
|
||||
IF "m1MinONS" THEN
|
||||
"Blender_Variables_Pers"."gProdSec" := 0;
|
||||
"Blender_Variables_Pers"."gProdMin" := "Blender_Variables_Pers"."gProdMin" + 1;
|
||||
END_IF;
|
||||
// Logic included in grouped IF (by UID 27)
|
||||
// Logic included in grouped IF (by UID 27)
|
||||
|
||||
// Network 6: Hour
|
||||
|
||||
"m1HourONS" := "Blender_Variables_Pers"."gProdMin" = 60;
|
||||
|
||||
// Network 7: Hour Counter
|
||||
|
||||
IF "m1HourONS" THEN
|
||||
"Blender_Variables_Pers"."gProdMin" := 0;
|
||||
"Blender_Variables_Pers"."gProdHour" := "Blender_Variables_Pers"."gProdHour" + 1;
|
||||
"Blender_Variables_Pers"."gBlendingMaintHour" := "Blender_Variables_Pers"."gBlendingMaintHour" + 1;
|
||||
END_IF;
|
||||
// Logic included in grouped IF (by UID 30)
|
||||
// Logic included in grouped IF (by UID 30)
|
||||
// Logic included in grouped IF (by UID 30)
|
||||
|
||||
// Network 8: Counter reset
|
||||
|
||||
IF "gBlenderCIPMode" OR "gBlenderRinseMode" THEN
|
||||
"Blender_Variables_Pers"."gProdSec" := 0;
|
||||
"Blender_Variables_Pers"."gProdMin" := 0;
|
||||
"Blender_Variables_Pers"."gProdHour" := 0;
|
||||
END_IF;
|
||||
// Logic included in grouped IF (by UID 31)
|
||||
// Logic included in grouped IF (by UID 31)
|
||||
// Logic included in grouped IF (by UID 31)
|
||||
|
||||
// Network 9: Running Seconds
|
||||
|
||||
IF "Procedure_Variables"."Blender_Run"."Running" AND "CLK_1.0S" THEN
|
||||
"Blender_Variables_Pers"."gRunningSeconds" := "Blender_Variables_Pers"."gRunningSeconds" + 1;
|
||||
END_IF;
|
||||
|
||||
// Network 10: Running Minutes
|
||||
|
||||
"I_DIRunning_sec" := "Blender_Variables_Pers"."gRunningSeconds";
|
||||
"MOD60" := "I_DIRunning_sec" MOD DINT#60;
|
||||
IF ("MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running") AND "CLK_1.0S" THEN
|
||||
"Blender_Variables_Pers"."gRunningMinutes" := "Blender_Variables_Pers"."gRunningMinutes" + 1;
|
||||
END_IF;
|
||||
"M19012" := (("MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running") AND "CLK_1.0S"); // Update edge memory bit
|
||||
"mRunMin" := (("MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running") AND "CLK_1.0S") AND NOT "M19012";
|
||||
|
||||
// Network 11: Running Hours for Maintenance
|
||||
|
||||
IF "mRunMin" THEN
|
||||
"I_DIRunning_min" := "Blender_Variables_Pers"."gRunningMinutes";
|
||||
END_IF;
|
||||
IF "mRunMin" THEN
|
||||
"MOD60" := "I_DIRunning_min" MOD DINT#60;
|
||||
END_IF;
|
||||
IF "MOD60" = DINT#0 THEN
|
||||
"Blender_Variables_Pers"."gRunningMaintHour" := "Blender_Variables_Pers"."gRunningMaintHour" + 1;
|
||||
END_IF;
|
||||
|
||||
// Network 12: Running Hours for Maintenance
|
||||
|
||||
"HMI_Variables_Status"."System"."BlendingMaintHour" := "Blender_Variables_Pers"."gRunningMaintHour";
|
||||
|
||||
END_FUNCTION_BLOCK
|
|
@ -0,0 +1,486 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Document>
|
||||
<Engineering version="V18" />
|
||||
<SW.Blocks.FC ID="0">
|
||||
<AttributeList>
|
||||
<Interface><Sections xmlns="http://www.siemens.com/automation/Openness/SW/Interface/v5">
|
||||
<Section Name="Input" />
|
||||
<Section Name="Output" />
|
||||
<Section Name="InOut" />
|
||||
<Section Name="Temp" />
|
||||
<Section Name="Constant" />
|
||||
<Section Name="Return">
|
||||
<Member Name="Ret_Val" Datatype="Void" />
|
||||
</Section>
|
||||
</Sections></Interface>
|
||||
<MemoryLayout>Optimized</MemoryLayout>
|
||||
<Name>TestLAD</Name>
|
||||
<Namespace />
|
||||
<Number>2</Number>
|
||||
<ProgrammingLanguage>LAD</ProgrammingLanguage>
|
||||
<SetENOAutomatically>false</SetENOAutomatically>
|
||||
</AttributeList>
|
||||
<ObjectList>
|
||||
<MultilingualText ID="1" CompositionName="Comment">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="2" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="4" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="5" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="6" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="7" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="8" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
<SW.Blocks.CompileUnit ID="9" CompositionName="CompileUnits">
|
||||
<AttributeList>
|
||||
<NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
|
||||
<Parts>
|
||||
<Access Scope="GlobalVariable" UId="21">
|
||||
<Symbol>
|
||||
<Component Name="Clock_10Hz" />
|
||||
</Symbol>
|
||||
</Access>
|
||||
<Access Scope="GlobalVariable" UId="22">
|
||||
<Symbol>
|
||||
<Component Name="Clock_5Hz" />
|
||||
</Symbol>
|
||||
</Access>
|
||||
<Part Name="Contact" UId="23" />
|
||||
<Part Name="Coil" UId="24" />
|
||||
</Parts>
|
||||
<Wires>
|
||||
<Wire UId="25">
|
||||
<Powerrail />
|
||||
<NameCon UId="23" Name="in" />
|
||||
</Wire>
|
||||
<Wire UId="26">
|
||||
<IdentCon UId="21" />
|
||||
<NameCon UId="23" Name="operand" />
|
||||
</Wire>
|
||||
<Wire UId="27">
|
||||
<NameCon UId="23" Name="out" />
|
||||
<NameCon UId="24" Name="in" />
|
||||
</Wire>
|
||||
<Wire UId="28">
|
||||
<IdentCon UId="22" />
|
||||
<NameCon UId="24" Name="operand" />
|
||||
</Wire>
|
||||
</Wires>
|
||||
</FlgNet></NetworkSource>
|
||||
<ProgrammingLanguage>LAD</ProgrammingLanguage>
|
||||
</AttributeList>
|
||||
<ObjectList>
|
||||
<MultilingualText ID="A" CompositionName="Comment">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="B" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="C" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="D" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="E" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="F" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="10" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="11" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
<MultilingualText ID="12" CompositionName="Title">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="13" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text>Clock Bit</Text>
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="14" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="15" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="16" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="17" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="18" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="19" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
</ObjectList>
|
||||
</SW.Blocks.CompileUnit>
|
||||
<SW.Blocks.CompileUnit ID="1A" CompositionName="CompileUnits">
|
||||
<AttributeList>
|
||||
<NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
|
||||
<Parts>
|
||||
<Access Scope="GlobalVariable" UId="21">
|
||||
<Symbol>
|
||||
<Component Name="Clock_10Hz" />
|
||||
</Symbol>
|
||||
</Access>
|
||||
<Access Scope="GlobalVariable" UId="22">
|
||||
<Symbol>
|
||||
<Component Name="Clock_5Hz" />
|
||||
</Symbol>
|
||||
</Access>
|
||||
<Part Name="Contact" UId="23">
|
||||
<Negated Name="operand" />
|
||||
</Part>
|
||||
<Part Name="Coil" UId="24" />
|
||||
</Parts>
|
||||
<Wires>
|
||||
<Wire UId="25">
|
||||
<Powerrail />
|
||||
<NameCon UId="23" Name="in" />
|
||||
</Wire>
|
||||
<Wire UId="26">
|
||||
<IdentCon UId="21" />
|
||||
<NameCon UId="23" Name="operand" />
|
||||
</Wire>
|
||||
<Wire UId="27">
|
||||
<NameCon UId="23" Name="out" />
|
||||
<NameCon UId="24" Name="in" />
|
||||
</Wire>
|
||||
<Wire UId="28">
|
||||
<IdentCon UId="22" />
|
||||
<NameCon UId="24" Name="operand" />
|
||||
</Wire>
|
||||
</Wires>
|
||||
</FlgNet></NetworkSource>
|
||||
<ProgrammingLanguage>LAD</ProgrammingLanguage>
|
||||
</AttributeList>
|
||||
<ObjectList>
|
||||
<MultilingualText ID="1B" CompositionName="Comment">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="1C" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="1D" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="1E" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="1F" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="20" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="21" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="22" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
<MultilingualText ID="23" CompositionName="Title">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="24" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text>Clock Bit</Text>
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="25" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="26" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="27" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="28" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="29" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="2A" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
</ObjectList>
|
||||
</SW.Blocks.CompileUnit>
|
||||
<SW.Blocks.CompileUnit ID="2B" CompositionName="CompileUnits">
|
||||
<AttributeList>
|
||||
<NetworkSource />
|
||||
<ProgrammingLanguage>LAD</ProgrammingLanguage>
|
||||
</AttributeList>
|
||||
<ObjectList>
|
||||
<MultilingualText ID="2C" CompositionName="Comment">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="2D" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="2E" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="2F" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="30" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="31" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="32" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="33" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
<MultilingualText ID="34" CompositionName="Title">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="35" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="36" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="37" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="38" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="39" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3A" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3B" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
</ObjectList>
|
||||
</SW.Blocks.CompileUnit>
|
||||
<MultilingualText ID="3C" CompositionName="Title">
|
||||
<ObjectList>
|
||||
<MultilingualTextItem ID="3D" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>it-IT</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3E" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>de-DE</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="3F" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>en-US</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="40" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>es-ES</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="41" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>fr-FR</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="42" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>zh-CN</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
<MultilingualTextItem ID="43" CompositionName="Items">
|
||||
<AttributeList>
|
||||
<Culture>ja-JP</Culture>
|
||||
<Text />
|
||||
</AttributeList>
|
||||
</MultilingualTextItem>
|
||||
</ObjectList>
|
||||
</MultilingualText>
|
||||
</ObjectList>
|
||||
</SW.Blocks.FC>
|
||||
</Document>
|
|
@ -0,0 +1,121 @@
|
|||
{
|
||||
"block_name": "TestLAD",
|
||||
"block_number": 2,
|
||||
"language": "LAD",
|
||||
"block_comment": "",
|
||||
"interface": {
|
||||
"Return": [
|
||||
{
|
||||
"name": "Ret_Val",
|
||||
"datatype": "Void"
|
||||
}
|
||||
]
|
||||
},
|
||||
"networks": [
|
||||
{
|
||||
"id": "9",
|
||||
"title": "Clock Bit",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_10Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Coil",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "23",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_5Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1A",
|
||||
"title": "Clock Bit",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {
|
||||
"operand": true
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_10Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Coil",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "23",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_5Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2B",
|
||||
"title": "",
|
||||
"comment": "",
|
||||
"logic": [],
|
||||
"error": "FlgNet not found"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
{
|
||||
"block_name": "TestLAD",
|
||||
"block_number": 2,
|
||||
"language": "LAD",
|
||||
"block_comment": "",
|
||||
"interface": {
|
||||
"Return": [
|
||||
{
|
||||
"name": "Ret_Val",
|
||||
"datatype": "Void"
|
||||
}
|
||||
]
|
||||
},
|
||||
"networks": [
|
||||
{
|
||||
"id": "9",
|
||||
"title": "Clock Bit",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_10Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO: \"Clock_10Hz\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Coil_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "23",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_5Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "\"Clock_5Hz\" := \"Clock_10Hz\";"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1A",
|
||||
"title": "Clock Bit",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {
|
||||
"operand": true
|
||||
},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_10Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO: (NOT \"Clock_10Hz\")"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Coil_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "23",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_5Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "\"Clock_5Hz\" := (NOT \"Clock_10Hz\");"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2B",
|
||||
"title": "",
|
||||
"comment": "",
|
||||
"logic": [],
|
||||
"error": "FlgNet not found"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Block Name (Original): TestLAD
|
||||
// Block Number: 2
|
||||
// Original Language: LAD
|
||||
|
||||
FUNCTION_BLOCK "TestLAD"
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
VERSION : 0.1
|
||||
|
||||
VAR_INPUT
|
||||
END_VAR
|
||||
|
||||
VAR_OUTPUT
|
||||
END_VAR
|
||||
|
||||
VAR_IN_OUT
|
||||
END_VAR
|
||||
|
||||
VAR_TEMP
|
||||
END_VAR
|
||||
|
||||
BEGIN
|
||||
|
||||
// Network 1: Clock Bit
|
||||
|
||||
// RLO: "Clock_10Hz"
|
||||
"Clock_5Hz" := "Clock_10Hz";
|
||||
|
||||
// Network 2: Clock Bit
|
||||
|
||||
// RLO: (NOT "Clock_10Hz")
|
||||
"Clock_5Hz" := (NOT "Clock_10Hz");
|
||||
|
||||
// Network 3:
|
||||
|
||||
END_FUNCTION_BLOCK
|
|
@ -0,0 +1,33 @@
|
|||
// Block Name (Original): TestLAD
|
||||
// Block Number: 2
|
||||
// Original Language: LAD
|
||||
|
||||
FUNCTION_BLOCK "TestLAD"
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
VERSION : 0.1
|
||||
|
||||
VAR_INPUT
|
||||
END_VAR
|
||||
|
||||
VAR_OUTPUT
|
||||
END_VAR
|
||||
|
||||
VAR_IN_OUT
|
||||
END_VAR
|
||||
|
||||
VAR_TEMP
|
||||
END_VAR
|
||||
|
||||
BEGIN
|
||||
|
||||
// Network 1: Clock Bit
|
||||
|
||||
"Clock_5Hz" := "Clock_10Hz";
|
||||
|
||||
// Network 2: Clock Bit
|
||||
|
||||
"Clock_5Hz" := "Clock_10Hz";
|
||||
|
||||
// Network 3:
|
||||
|
||||
END_FUNCTION_BLOCK
|
259
json_to_scl.py
259
json_to_scl.py
|
@ -1,259 +0,0 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
# --- Funciones Procesadoras por Tipo de Instrucción ---
|
||||
# Cada función recibe el diccionario de la instrucción del JSON.
|
||||
# Por ahora, solo imprimen información.
|
||||
|
||||
def process_contact(instruction):
|
||||
"""Procesa una instrucción 'Contact'."""
|
||||
print(f" [Contact] UID: {instruction['instruction_uid']}")
|
||||
operand = instruction['inputs'].get('operand', {})
|
||||
print(f" - Checks: {operand.get('scope', '?')} UID: {operand.get('uid', '?')}") # Adaptar si 'unknown_access' se resuelve
|
||||
in_source = instruction['inputs'].get('in', {})
|
||||
if in_source.get('type') == 'powerrail':
|
||||
print(" - Input: Power Rail")
|
||||
elif in_source.get('type') == 'connection':
|
||||
print(f" - Input: From instruction {in_source.get('source_instruction_uid', '?')} (Pin: {in_source.get('source_pin', '?')})")
|
||||
else:
|
||||
print(f" - Input: {in_source}")
|
||||
|
||||
def process_coil(instruction):
|
||||
"""Procesa una instrucción 'Coil'."""
|
||||
print(f" [Coil] UID: {instruction['instruction_uid']}")
|
||||
operand = instruction['inputs'].get('operand', {})
|
||||
print(f" - Assigns to: {operand.get('scope', '?')} UID: {operand.get('uid', '?')}")
|
||||
in_source = instruction['inputs'].get('in', {})
|
||||
if in_source.get('type') == 'connection':
|
||||
print(f" - Condition from: instruction {in_source.get('source_instruction_uid', '?')} (Pin: {in_source.get('source_pin', '?')})")
|
||||
else:
|
||||
print(f" - Condition: {in_source}")
|
||||
|
||||
def process_add(instruction):
|
||||
"""Procesa una instrucción 'Add'."""
|
||||
print(f" [Add] UID: {instruction['instruction_uid']}")
|
||||
in1 = instruction['inputs'].get('in1', {})
|
||||
in2 = instruction['inputs'].get('in2', {})
|
||||
en = instruction['inputs'].get('en', {})
|
||||
outputs = instruction['outputs'].get('out', [])
|
||||
|
||||
print(f" - Input 1: {in1.get('scope', '?')} UID: {in1.get('uid', '?')}")
|
||||
print(f" - Input 2: {in2.get('scope', '?')} UID: {in2.get('uid', '?')}")
|
||||
if en.get('type') == 'powerrail':
|
||||
print(" - Enabled by: Power Rail (Direct)") # Si Add pudiera conectarse directo
|
||||
elif en.get('type') == 'connection':
|
||||
print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})")
|
||||
elif en: # Si 'en' no está presente o no es conexión/powerrail (poco común en Add)
|
||||
print(f" - Enabled by: {en}")
|
||||
else:
|
||||
print(" - Enabled by: Power Rail (Implícito, sin EN)") # Asumir si no hay pin 'en'
|
||||
|
||||
for output in outputs:
|
||||
print(f" - Output to: {output.get('scope', '?')} UID: {output.get('uid', '?')}")
|
||||
|
||||
def process_move(instruction):
|
||||
"""Procesa una instrucción 'Move'."""
|
||||
print(f" [Move] UID: {instruction['instruction_uid']}")
|
||||
in_val = instruction['inputs'].get('in', {})
|
||||
en = instruction['inputs'].get('en', {})
|
||||
outputs = instruction['outputs'].get('out1', []) # Asumiendo pin 'out1' para Move
|
||||
|
||||
print(f" - Input Value: {in_val.get('scope', '?')} UID: {in_val.get('uid', '?')}")
|
||||
if en.get('type') == 'powerrail':
|
||||
print(" - Enabled by: Power Rail")
|
||||
elif en.get('type') == 'connection':
|
||||
print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})")
|
||||
elif en:
|
||||
print(f" - Enabled by: {en}")
|
||||
else:
|
||||
print(" - Enabled by: Power Rail (Implícito, sin EN)")
|
||||
|
||||
for output in outputs:
|
||||
print(f" - Output to: {output.get('scope', '?')} UID: {output.get('uid', '?')}")
|
||||
|
||||
def process_eq(instruction):
|
||||
"""Procesa una instrucción 'Eq' (Equal)."""
|
||||
print(f" [Compare EQ] UID: {instruction['instruction_uid']}")
|
||||
in1 = instruction['inputs'].get('in1', {})
|
||||
in2 = instruction['inputs'].get('in2', {})
|
||||
pre = instruction['inputs'].get('pre', {}) # Condición previa (usualmente PowerRail o conexión)
|
||||
|
||||
print(f" - Input 1: {in1.get('scope', '?')} UID: {in1.get('uid', '?')}")
|
||||
print(f" - Input 2: {in2.get('scope', '?')} UID: {in2.get('uid', '?')}")
|
||||
if pre.get('type') == 'powerrail':
|
||||
print(" - Pre-condition: Power Rail")
|
||||
elif pre.get('type') == 'connection':
|
||||
print(f" - Pre-condition: instruction {pre.get('source_instruction_uid', '?')} (Pin: {pre.get('source_pin', '?')})")
|
||||
else:
|
||||
print(f" - Pre-condition: {pre}")
|
||||
|
||||
# La salida 'out' de Eq usualmente va a otra instrucción (Contact, Coil, Enable pin)
|
||||
# Lo veremos cuando procesemos la instrucción destino
|
||||
|
||||
def process_mod(instruction):
|
||||
"""Procesa una instrucción 'Mod' (Modulo)."""
|
||||
print(f" [Modulo] UID: {instruction['instruction_uid']}")
|
||||
in1 = instruction['inputs'].get('in1', {})
|
||||
in2 = instruction['inputs'].get('in2', {})
|
||||
en = instruction['inputs'].get('en', {})
|
||||
outputs = instruction['outputs'].get('out', [])
|
||||
eno_outputs = instruction['outputs'].get('eno', []) # Mod también puede tener ENO
|
||||
|
||||
print(f" - Input 1 (Dividend): {in1.get('scope', '?')} UID: {in1.get('uid', '?')}")
|
||||
print(f" - Input 2 (Divisor): {in2.get('scope', '?')} UID: {in2.get('uid', '?')}")
|
||||
if en.get('type') == 'powerrail':
|
||||
print(" - Enabled by: Power Rail")
|
||||
elif en.get('type') == 'connection':
|
||||
print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})")
|
||||
elif en:
|
||||
print(f" - Enabled by: {en}")
|
||||
else:
|
||||
print(" - Enabled by: Power Rail (Implícito, sin EN)")
|
||||
|
||||
for output in outputs:
|
||||
print(f" - Output (Remainder) to: {output.get('scope', '?')} UID: {output.get('uid', '?')}")
|
||||
# ENO normalmente se conecta a pines 'en' o 'pre' de la siguiente instrucción
|
||||
|
||||
def process_convert(instruction):
|
||||
"""Procesa una instrucción 'Convert'."""
|
||||
print(f" [Convert] UID: {instruction['instruction_uid']}")
|
||||
in_val = instruction['inputs'].get('in', {})
|
||||
en = instruction['inputs'].get('en', {})
|
||||
outputs = instruction['outputs'].get('out', [])
|
||||
# Podríamos extraer los tipos de datos de TemplateValue si estuvieran en el JSON
|
||||
# template_vals = instruction.get('template_values', {})
|
||||
|
||||
print(f" - Input Value: {in_val.get('scope', '?')} UID: {in_val.get('uid', '?')}")
|
||||
if en.get('type') == 'powerrail':
|
||||
print(" - Enabled by: Power Rail")
|
||||
elif en.get('type') == 'connection':
|
||||
print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})")
|
||||
elif en:
|
||||
print(f" - Enabled by: {en}")
|
||||
else:
|
||||
print(" - Enabled by: Power Rail (Implícito, sin EN)")
|
||||
|
||||
for output in outputs:
|
||||
print(f" - Output to: {output.get('scope', '?')} UID: {output.get('uid', '?')}")
|
||||
# print(f" (Expected DestType: {template_vals.get('DestType', '?')})")
|
||||
|
||||
|
||||
def process_or(instruction):
|
||||
"""Procesa una instrucción 'O' (OR)."""
|
||||
# Las instrucciones 'O' en LAD suelen representar la unión de ramas paralelas.
|
||||
# Este parser simple solo muestra las entradas directas. Reconstruir la lógica OR completa requeriría más análisis.
|
||||
print(f" [OR Logic] UID: {instruction['instruction_uid']}")
|
||||
in1 = instruction['inputs'].get('in1', {})
|
||||
in2 = instruction['inputs'].get('in2', {})
|
||||
# Podría haber in3, in4... si Cardinality > 2
|
||||
|
||||
if in1.get('type') == 'connection':
|
||||
print(f" - Input 1 from: instruction {in1.get('source_instruction_uid', '?')} (Pin: {in1.get('source_pin', '?')})")
|
||||
else:
|
||||
print(f" - Input 1: {in1}")
|
||||
if in2.get('type') == 'connection':
|
||||
print(f" - Input 2 from: instruction {in2.get('source_instruction_uid', '?')} (Pin: {in2.get('source_pin', '?')})")
|
||||
else:
|
||||
print(f" - Input 2: {in2}")
|
||||
|
||||
# La salida 'out' de O usualmente va a otra instrucción (Contact, Coil, Enable pin)
|
||||
|
||||
def process_pbox(instruction):
|
||||
"""Procesa una instrucción 'PBox'."""
|
||||
# PBox puede ser muchas cosas (Rising Edge, Falling Edge, Set, Reset, etc.)
|
||||
# Necesitaríamos más información o convenciones para saber qué hace exactamente.
|
||||
print(f" [PBox - Special?] UID: {instruction['instruction_uid']}")
|
||||
inputs = instruction.get('inputs', {})
|
||||
outputs = instruction.get('outputs', {})
|
||||
for pin, source in inputs.items():
|
||||
if source.get('type') == 'connection':
|
||||
print(f" - Input Pin '{pin}' from: instruction {source.get('source_instruction_uid', '?')} (Pin: {source.get('source_pin', '?')})")
|
||||
elif source.get('type') == 'powerrail':
|
||||
print(f" - Input Pin '{pin}': Power Rail")
|
||||
else:
|
||||
print(f" - Input Pin '{pin}': {source.get('scope', '?')} UID: {source.get('uid', '?')}")
|
||||
|
||||
# La salida de PBox la veremos en el destino
|
||||
|
||||
def process_unknown(instruction):
|
||||
"""Procesa una instrucción de tipo desconocido."""
|
||||
print(f" [Unknown Type: {instruction.get('type', 'N/A')}] UID: {instruction['instruction_uid']}")
|
||||
print(f" - Inputs: {instruction.get('inputs')}")
|
||||
print(f" - Outputs: {instruction.get('outputs')}")
|
||||
|
||||
# --- Mapeo de Tipos a Funciones ---
|
||||
instruction_handlers = {
|
||||
"Contact": process_contact,
|
||||
"Coil": process_coil,
|
||||
"Add": process_add,
|
||||
"Move": process_move,
|
||||
"Eq": process_eq,
|
||||
"Mod": process_mod,
|
||||
"Convert": process_convert,
|
||||
"O": process_or, # 'O' representa un OR lógico en FlgNet
|
||||
"PBox": process_pbox, # Tipo genérico, tratar como desconocido por ahora
|
||||
# Añade más tipos aquí si aparecen
|
||||
}
|
||||
|
||||
# --- Función Principal de Procesamiento ---
|
||||
|
||||
def process_logic_data(data):
|
||||
"""Itera sobre el JSON cargado y procesa cada instrucción."""
|
||||
print("=" * 40)
|
||||
print(f"Processing Block: {data.get('block_name')} ({data.get('block_number')})")
|
||||
print(f"Language: {data.get('language')}")
|
||||
print("-" * 40)
|
||||
|
||||
# Opcional: Imprimir interfaz
|
||||
print("Interface:")
|
||||
for section, members in data.get('interface', {}).items():
|
||||
if members:
|
||||
print(f" {section}:")
|
||||
for member in members:
|
||||
print(f" - {member['name']} ({member['datatype']})")
|
||||
print("-" * 40)
|
||||
|
||||
# Procesar Redes
|
||||
print("Networks:")
|
||||
for network in data.get('networks', []):
|
||||
print(f"\nNetwork ID: {network.get('id')} - Title: '{network.get('title', '')}'")
|
||||
if 'error' in network:
|
||||
print(f" ERROR en esta red: {network['error']}")
|
||||
continue
|
||||
if not network.get('logic'):
|
||||
print(" (No logic instructions found in JSON for this network)")
|
||||
continue
|
||||
|
||||
for instruction in network.get('logic', []):
|
||||
instruction_type = instruction.get('type')
|
||||
# Obtener el handler adecuado, o el default si no se encuentra
|
||||
handler = instruction_handlers.get(instruction_type, process_unknown)
|
||||
try:
|
||||
handler(instruction)
|
||||
except Exception as e:
|
||||
print(f" ERROR procesando instrucción UID {instruction.get('instruction_uid')} (Tipo: {instruction_type}): {e}")
|
||||
# Considerar imprimir más detalles del error o de la instrucción
|
||||
# import traceback
|
||||
# traceback.print_exc()
|
||||
|
||||
|
||||
# --- Ejecución ---
|
||||
if __name__ == "__main__":
|
||||
json_file = 'BlenderRun_ProdTime_simplified.json' # El archivo generado por el script anterior
|
||||
|
||||
if not os.path.exists(json_file):
|
||||
print(f"Error: Archivo JSON no encontrado en {json_file}")
|
||||
print("Asegúrate de haber ejecutado el script de conversión XML a JSON primero.")
|
||||
else:
|
||||
try:
|
||||
with open(json_file, 'r', encoding='utf-8') as f:
|
||||
logic_data = json.load(f)
|
||||
|
||||
process_logic_data(logic_data)
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Error: El archivo JSON ({json_file}) no es válido: {e}")
|
||||
except Exception as e:
|
||||
print(f"Ocurrió un error inesperado al cargar o procesar el JSON: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
|
@ -0,0 +1,160 @@
|
|||
# LAD-to-SCL Conversion Pipeline: Documentación de Referencia
|
||||
|
||||
## 1. Visión General
|
||||
|
||||
Este documento describe un pipeline de scripts de Python diseñado para convertir bloques de función o funciones (FC/FB) escritos en Ladder Logic (LAD) desde archivos XML de TIA Portal Openness a un código SCL (Structured Control Language) semánticamente equivalente.
|
||||
|
||||
El proceso se divide en tres etapas principales, cada una manejada por un script específico:
|
||||
|
||||
1. **XML a JSON Enriquecido (`x1_to_json.py`):** Parsea el XML de Openness, extrae la estructura lógica y las conexiones explícitas, e **infiere conexiones implícitas** (especialmente las habilitaciones EN) para crear un archivo JSON detallado.
|
||||
2. **Procesamiento Semántico (`process.py`):** Lee el JSON enriquecido y, de forma iterativa, traduce cada instrucción LAD a su equivalente SCL, manejando dependencias, propagando el estado lógico (RLO), y agrupando lógica paralela. El SCL generado se almacena *dentro* del propio JSON.
|
||||
3. **Generación de SCL Final (`generate_scl.py`):** Lee el JSON completamente procesado y ensambla el código SCL final en un archivo `.scl` formateado, incluyendo declaraciones de variables y el cuerpo del programa.
|
||||
|
||||
## 2. Etapas del Pipeline
|
||||
|
||||
### Etapa 1: XML a JSON Enriquecido (`x1_to_json.py`)
|
||||
|
||||
* **Propósito:** Transformar la compleja y a veces ambigua estructura XML de Openness en un formato JSON estructurado y más fácil de procesar, añadiendo información clave que está implícita en el LAD visual pero no siempre explícita en el XML.
|
||||
* **Entrada:** Archivo `.xml` exportado desde TIA Portal Openness para un FC o FB.
|
||||
* **Salida:** Archivo `_simplified.json`.
|
||||
* **Proceso Clave:**
|
||||
1. **Parseo XML:** Utiliza `lxml` para leer el archivo XML.
|
||||
2. **Extracción de Metadatos:** Obtiene nombre del bloque, número, lenguaje original, comentario del bloque.
|
||||
3. **Extracción de Interfaz:** Parsea las secciones `Input`, `Output`, `InOut`, `Temp`, `Constant`, `Return` para obtener la declaración de variables.
|
||||
4. **Parseo de Redes (`CompileUnit`):** Itera sobre cada red lógica.
|
||||
* **`parse_network`:**
|
||||
* **Parseo de Componentes:**
|
||||
* `Access`: Identifica variables globales/locales, constantes literales y tipadas (`parse_access`).
|
||||
* `Part`: Identifica instrucciones estándar LAD como `Contact`, `Coil`, `Move`, `Add`, etc. **Importante:** Detecta pines negados (`<Negated>`) y los almacena en `negated_pins` (`parse_part`).
|
||||
* `Call`: Identifica llamadas a otros FCs o FBs, extrayendo el nombre del bloque llamado, tipo (FC/FB) e información de instancia DB si aplica (`parse_call`).
|
||||
* Crea `access_map` y `parts_and_calls_map` para referencia rápida.
|
||||
* **Parseo de Conexiones (`Wire`):**
|
||||
* Construye `wire_connections`: Un mapa `(dest_uid, dest_pin) -> [(src_uid, src_pin), ...]`.
|
||||
* Construye `source_connections`: Un mapa `(src_uid, src_pin) -> [(dest_uid, dest_pin), ...]`.
|
||||
* Construye `eno_outputs`: Un mapa `src_uid -> [(dest_uid, dest_pin), ...]` para conexiones que *salen* de un pin `eno`.
|
||||
* **Construcción Lógica Inicial:** Crea una lista de diccionarios (`all_logic_steps`), uno por cada `Part` o `Call`, rellenando `inputs` y `outputs` **solo con las conexiones explícitas** encontradas en los `Wire`.
|
||||
* **Inferencia de Conexión `EN` (¡Paso Crucial!):**
|
||||
* Itera sobre los bloques funcionales (`Move`, `Add`, `Call`, etc.) que *no* tienen una entrada `en` explícita definida después del paso anterior.
|
||||
* Utiliza una **heurística** (buscar hacia atrás en la lista ordenada por UID) para encontrar la fuente de RLO más probable que precede a este bloque (la salida `out` de un bloque lógico como `Contact`/`O`/`Eq` o la salida `eno` de un bloque funcional anterior).
|
||||
* Si se encuentra una fuente inferida, **añade la conexión `en`** al diccionario `inputs` del bloque funcional actual. Esto enriquece el JSON con la dependencia lógica implícita.
|
||||
* **Adición de Lógica ENO Interesante:** Identifica las conexiones que salen de un pin `eno` y *no* van directamente al pin `en` de la siguiente instrucción, almacenándolas en el campo `eno_logic`.
|
||||
* **Ordenamiento:** Ordena las instrucciones en la lista `logic` final (generalmente por UID).
|
||||
5. **Escritura JSON:** Guarda la estructura de datos completa en el archivo `_simplified.json`.
|
||||
|
||||
### Etapa 2: Procesamiento Semántico (`process.py`)
|
||||
|
||||
* **Propósito:** Traducir la lógica LAD (representada en el JSON enriquecido) a código SCL embebido, resolviendo dependencias entre instrucciones y aplicando optimizaciones de agrupación.
|
||||
* **Entrada:** Archivo `_simplified.json` (generado por la Etapa 1).
|
||||
* **Salida:** Archivo `_simplified_scl_processed.json`.
|
||||
* **Proceso Clave:**
|
||||
1. **Carga de JSON y Preparación:** Lee el JSON de entrada y reconstruye mapas de acceso por red. Inicializa el `scl_map` global (o por red).
|
||||
2. **Bucle Iterativo:** Repite los siguientes pasos hasta que no se realicen cambios en un pase completo o se alcance un límite máximo de pases.
|
||||
* **Fase 1: Procesadores Base:**
|
||||
* Itera sobre cada instrucción en cada red.
|
||||
* Si la instrucción no ha sido procesada (`_scl` o `_error`) ni agrupada (`grouped`), busca el procesador adecuado (`process_xxx`) basado en su `type`.
|
||||
* **`process_xxx` (Ejecución):**
|
||||
* Llama a `get_scl_representation` para obtener el SCL de sus pines de entrada, buscándolos en `scl_map` o directamente en `access_map`.
|
||||
* Si alguna dependencia no está resuelta (devuelve `None`), el procesador retorna `False`.
|
||||
* Si las dependencias están resueltas:
|
||||
* **Generadores RLO (`Contact`, `O`, `Eq`, `PBox`):** Calculan la expresión booleana SCL resultante y la almacenan en `scl_map` bajo la clave `(network_id, instr_uid, 'out')`. También almacenan el estado `EN` en `scl_map` para `eno` si aplica. Guardan un comentario en `instruction['scl']`.
|
||||
* **Bloques Funcionales (`Move`, `Add`, `Convert`, `Mod`, `Call`):**
|
||||
* Obtienen la condición `EN` (explícita o inferida por el JSON enriquecido).
|
||||
* Generan el código SCL *core* (la asignación o cálculo).
|
||||
* Generan el SCL final, **siempre incluyendo `IF en_scl THEN ... END_IF;`** si `en_scl` no es exactamente `"TRUE"`.
|
||||
* Almacenan el SCL final en `instruction['scl']`.
|
||||
* Almacenan el nombre de la variable de salida (o temporal) en `scl_map` para `out`/`out1`.
|
||||
* Almacenan el `en_scl` en `scl_map` para `eno`.
|
||||
* **Bobinas (`Coil`):** Obtienen el RLO de entrada (`in`), obtienen el operando destino, generan la asignación `destino := rlo;` y la guardan en `instruction['scl']`.
|
||||
* Marcan la instrucción como procesada añadiendo `_scl` a `instruction['type']`.
|
||||
* Retornan `True`.
|
||||
* Se registra si hubo algún cambio en esta fase (`made_change_in_base_pass`).
|
||||
* **Fase 2: Agrupación de IFs (`process_group_ifs`):**
|
||||
* Itera sobre las instrucciones *ya procesadas* (`_scl`) que son generadoras de condición (`Contact`, `O`, `Eq`, etc.).
|
||||
* Obtiene la `condition_scl` de `scl_map`.
|
||||
* Busca todos los bloques funcionales (`Move_scl`, `Add_scl`, etc.) cuyo pin `EN` esté conectado a la salida de esta instrucción generadora.
|
||||
* Verifica si el SCL de estos consumidores *ya* contiene un `IF condition_scl THEN...`.
|
||||
* Si encuentra **más de uno** con la misma condición `IF`:
|
||||
* Extrae el código *core* (lo que está dentro del `IF...END_IF;`) de cada consumidor.
|
||||
* Construye un **único bloque `IF condition_scl THEN ... END_IF;`** que contiene todos los cores extraídos.
|
||||
* **Sobrescribe** el campo `scl` de la instrucción *generadora de condición* con este nuevo bloque `IF` agrupado.
|
||||
* Marca cada instrucción consumidora con `grouped = True` y cambia su `scl` a un comentario (`GROUPED_COMMENT`) para evitar que `generate_scl.py` lo use.
|
||||
* Se registra si hubo algún cambio en esta fase (`made_change_in_group_pass`).
|
||||
* **Condición de Salida:** El bucle termina si `made_change_in_base_pass` y `made_change_in_group_pass` son ambos `False`.
|
||||
3. **Escritura JSON:** Guarda el JSON modificado (con SCL embebido y marcas de agrupación) en el archivo `_simplified_scl_processed.json`.
|
||||
|
||||
### Etapa 3: Generación de SCL Final (`generate_scl.py`)
|
||||
|
||||
* **Propósito:** Ensamblar un archivo `.scl` completo y formateado a partir del JSON procesado.
|
||||
* **Entrada:** Archivo `_simplified_scl_processed.json` (generado por la Etapa 2).
|
||||
* **Salida:** Archivo `.scl`.
|
||||
* **Proceso Clave:**
|
||||
1. **Carga de JSON:** Lee el archivo JSON procesado.
|
||||
2. **Generación de Cabecera:** Escribe el encabezado del bloque (`FUNCTION_BLOCK name`, `VERSION`, etc.).
|
||||
3. **Generación de Declaraciones VAR:**
|
||||
* Escribe las secciones `VAR_INPUT`, `VAR_OUTPUT`, `VAR_IN_OUT`, `VAR_TEMP`, `VAR_STAT`.
|
||||
* Rellena cada sección con las variables definidas en la `interface` del JSON.
|
||||
* **Detecta y declara** variables temporales (`_temp_...`) y estáticas (`stat_...`) encontradas en el SCL generado (requiere inferencia de tipo básica o usar `Variant`).
|
||||
4. **Generación del Cuerpo (`BEGIN`/`END_FUNCTION_BLOCK`):**
|
||||
* Itera sobre las `networks` en el JSON.
|
||||
* Añade comentarios de red.
|
||||
* Itera sobre la `logic` de cada red.
|
||||
* Para cada `instruction`:
|
||||
* **Verifica el flag `grouped`:** Si `instruction.get('grouped', False)` es `True`, **ignora** esta instrucción (su lógica ya está en otro lugar).
|
||||
* Si no está agrupada, obtiene el valor del campo `scl`.
|
||||
* **Limpia comentarios internos:** Opcionalmente, elimina comentarios como `// RLO:` o `// Cond:` que fueron útiles para depurar `process.py` pero no son necesarios en el SCL final (excepto quizás los de PBox/flancos).
|
||||
* Indenta y añade las líneas del SCL al output.
|
||||
* Añade líneas en blanco entre redes si contienen código.
|
||||
5. **Escritura de Archivo:** Escribe el string SCL completo al archivo `.scl`.
|
||||
|
||||
## 3. Cómo Extender para Nuevas Instrucciones LAD/FBD
|
||||
|
||||
Añadir soporte para un nuevo tipo de instrucción (p.ej., un temporizador `TON`, un comparador `GT`, o una función matemática `SQRT`) requiere modificar los scripts `x1_to_json.py` y `process.py`.
|
||||
|
||||
**Pasos:**
|
||||
|
||||
1. **Analizar el XML:** Exporta un bloque simple que use la nueva instrucción y examina el XML de Openness. Identifica:
|
||||
* Si se representa como `<Part Name="NombreInstruccion">` o `<Call Name="NombreInstruccion">`.
|
||||
* Sus pines de entrada y salida (`NameCon`/`IdentCon` en los `Wire`).
|
||||
* Cualquier atributo o `TemplateValue` relevante.
|
||||
* Si tiene pines negados (`<Negated>`).
|
||||
|
||||
2. **Modificar `x1_to_json.py` (`parse_network`):**
|
||||
* **Parseo:** Asegúrate de que `parse_part` o `parse_call` (o una nueva función si es muy diferente) capture correctamente la nueva instrucción y sus atributos específicos. Añade su `type` al `parts_and_calls_map`.
|
||||
* **Clasificación:** Decide si la nueva instrucción es un `functional_block_type` (tiene EN/ENO implícito/explícito) o un `rlo_generator` (modifica el flujo lógico principal). Actualiza estas listas si es necesario.
|
||||
* **Inferencia EN:** Si es un bloque funcional, revisa si la lógica de inferencia EN necesita ajustes para manejar este nuevo tipo correctamente (aunque si tiene un `EN` explícito en el XML, la inferencia no debería ser necesaria).
|
||||
* **Salidas:** Asegúrate de que sus pines de salida relevantes (`out`, `Q`, etc.) sean considerados por otros bloques y por la lógica `eno_outputs` si tiene `ENO`.
|
||||
|
||||
3. **Modificar `process.py`:**
|
||||
* **Crear Procesador:** Escribe una nueva función `process_nombre_instruccion(instruction, network_id, scl_map, access_map, ...)`.
|
||||
* **Lógica SCL:** Implementa la traducción:
|
||||
* Obtén las representaciones SCL de las entradas necesarias usando `get_scl_representation`.
|
||||
* Verifica que todas las dependencias estén resueltas.
|
||||
* Genera el SCL core equivalente.
|
||||
* Maneja la habilitación `EN`: Obtén `en_scl`. Si `en_scl` no es `"TRUE"`, envuelve el SCL core en `IF en_scl THEN ... END_IF;`.
|
||||
* Almacena el SCL final en `instruction['scl']`.
|
||||
* Actualiza `instruction['type']` con el sufijo `_scl`.
|
||||
* **Actualiza `scl_map`:** Añade entradas para los pines de salida (`out`, `Q`, etc.) con su representación SCL (puede ser un nombre de variable temporal o el resultado de una expresión). Añade la entrada para `eno` si el bloque lo tiene (generalmente `scl_map[key_eno] = en_scl`).
|
||||
* Retorna `True`.
|
||||
* **Añadir a la Lista:** Inserta la nueva función `process_nombre_instruccion` en la lista `base_processors` en el orden de prioridad correcto (generalmente, generadores de valores/condiciones antes que consumidores).
|
||||
* **Agrupación:** Considera si este nuevo bloque debería ser parte de la lógica de agrupación (¿es un bloque funcional que puede ser habilitado en paralelo?). Si es así, no necesita cambios especiales aquí si se usa el enfoque de `process_group_ifs`. Si se usa el enfoque integrado, el generador de condición necesitaría saber cómo obtener el SCL core de este nuevo tipo.
|
||||
|
||||
4. **Modificar `generate_scl.py` (Menos Frecuente):**
|
||||
* **Declaraciones:** Si la nueva instrucción introduce la necesidad de tipos específicos de variables temporales o estáticas, ajusta la lógica de detección y declaración en `generate_scl.py`.
|
||||
* **Limpieza de Comentarios:** Si el nuevo procesador genera comentarios específicos que no quieres en el SCL final, ajusta el filtro en `generate_scl.py`.
|
||||
|
||||
5. **Probar:** Ejecuta el pipeline completo con un XML que contenga la nueva instrucción y verifica los JSON intermedios y el SCL final.
|
||||
|
||||
## 4. Futuras Mejoras y Consideraciones
|
||||
|
||||
* **Manejo de Tipos de Datos:** Implementar un seguimiento y conversión de tipos más robusto. Inferir tipos para variables temporales. Usar funciones de conversión SCL explícitas (`INT_TO_DINT`, etc.).
|
||||
* **Lógica de Flancos Completa:** Implementar correctamente la lógica de variables estáticas para `P_TRIG`/`N_TRIG` (o generar instancias de FB `FP`/`FN`).
|
||||
* **Soporte para FBs:** Manejar correctamente las llamadas a FBs con sus DBs de instancia y parámetros complejos.
|
||||
* **Optimización SCL:** Además de agrupar IFs, implementar otras optimizaciones (eliminación de código muerto, simplificación de expresiones).
|
||||
* **Estructuras LAD Complejas:** Mejorar la inferencia de EN para manejar bifurcaciones y uniones más complejas, o idealmente, rediseñar `x1_to_json.py` para un análisis topológico completo. Manejar saltos (`JMP`).
|
||||
* **Manejo de Errores:** Mejorar el reporte de errores y la resiliencia ante XMLs inesperados.
|
||||
* **Interfaz Gráfica/Configuración:** Crear una interfaz más amigable o archivos de configuración para gestionar el proceso.
|
||||
* **Soporte para otros lenguajes (FBD/SCL):** Extender el parser para manejar otros lenguajes de origen.
|
||||
|
||||
## 5. Conclusión
|
||||
|
||||
Este pipeline proporciona una base sólida para la conversión automática de LAD a SCL. Siguiendo los pasos de extensión, se puede añadir soporte para más instrucciones y mejorar la calidad y completitud de la conversión. La clave es el enfoque iterativo y la separación de responsabilidades entre el parseo/enriquecimiento del JSON y el procesamiento semántico/generación de SCL.
|
461
to_json.py
461
to_json.py
|
@ -1,461 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import os
|
||||
from lxml import etree
|
||||
import traceback
|
||||
|
||||
# --- Namespaces ---
|
||||
ns = {
|
||||
'iface': 'http://www.siemens.com/automation/Openness/SW/Interface/v5',
|
||||
'flg': 'http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4'
|
||||
}
|
||||
|
||||
# --- Helper Functions ---
|
||||
# (get_multilingual_text, get_symbol_name, parse_access, parse_part sin cambios)
|
||||
def get_multilingual_text(element, default_lang='en-US', fallback_lang='it-IT'):
|
||||
"""
|
||||
Intenta extraer texto de un elemento MultilingualText, priorizando idiomas.
|
||||
Busca directamente los Text dentro de Items/AttributeList/Text bajo las Culture especificadas.
|
||||
"""
|
||||
if element is None:
|
||||
return ""
|
||||
try:
|
||||
# Intenta encontrar el idioma por defecto
|
||||
xpath_expr = f".//*[local-name()='MultilingualTextItem'][*[local-name()='AttributeList']/*[local-name()='Culture' and text()='{default_lang}']]" \
|
||||
f"/*[local-name()='AttributeList']/*[local-name()='Text']"
|
||||
text_items = element.xpath(xpath_expr)
|
||||
if text_items and text_items[0].text is not None:
|
||||
return text_items[0].text.strip()
|
||||
|
||||
# Si no, intenta encontrar el idioma de fallback
|
||||
xpath_expr = f".//*[local-name()='MultilingualTextItem'][*[local-name()='AttributeList']/*[local-name()='Culture' and text()='{fallback_lang}']]" \
|
||||
f"/*[local-name()='AttributeList']/*[local-name()='Text']"
|
||||
text_items = element.xpath(xpath_expr)
|
||||
if text_items and text_items[0].text is not None:
|
||||
return text_items[0].text.strip()
|
||||
|
||||
# Si no, toma el primer texto que encuentre
|
||||
xpath_expr = f".//*[local-name()='MultilingualTextItem']/*[local-name()='AttributeList']/*[local-name()='Text']"
|
||||
text_items = element.xpath(xpath_expr)
|
||||
if text_items and text_items[0].text is not None:
|
||||
return text_items[0].text.strip()
|
||||
|
||||
return "" # Devuelve cadena vacía si no se encuentra nada
|
||||
except Exception as e:
|
||||
print(f"Advertencia: Error extrayendo MultilingualText desde {etree.tostring(element, encoding='unicode')[:100]}...: {e}")
|
||||
return ""
|
||||
|
||||
def get_symbol_name(symbol_element):
|
||||
"""
|
||||
Construye el nombre completo del símbolo (variable) a partir de sus elementos Component.
|
||||
Encapsula cada componente entre comillas dobles y los une con puntos.
|
||||
"""
|
||||
if symbol_element is None:
|
||||
return None
|
||||
try:
|
||||
# Selecciona el atributo 'Name' de cada elemento 'Component' hijo directo del Symbol
|
||||
components = symbol_element.xpath("./*[local-name()='Component']/@Name")
|
||||
if components:
|
||||
# Une los componentes, asegurándose de que cada uno esté entre comillas dobles
|
||||
full_name = ".".join(f'"{c}"' for c in components)
|
||||
return full_name
|
||||
else:
|
||||
return None # Indica que no se pudo formar un nombre
|
||||
except Exception as e:
|
||||
print(f"Advertencia: Excepción en get_symbol_name para {etree.tostring(symbol_element, encoding='unicode')[:100]}...: {e}")
|
||||
return None
|
||||
|
||||
def parse_access(access_element):
|
||||
"""
|
||||
Parsea un elemento Access (acceso a operando) para obtener información
|
||||
detallada sobre si es una variable (Symbol) o una constante (Constant).
|
||||
Devuelve un diccionario con la información o None si hay un error crítico.
|
||||
"""
|
||||
if access_element is None:
|
||||
return None
|
||||
|
||||
uid = access_element.get('UId')
|
||||
scope = access_element.get('Scope')
|
||||
|
||||
info = {'uid': uid, 'scope': scope, 'type': 'unknown'} # Inicializa info
|
||||
|
||||
symbol = access_element.xpath("./*[local-name()='Symbol']")
|
||||
constant = access_element.xpath("./*[local-name()='Constant']")
|
||||
|
||||
if symbol:
|
||||
info['type'] = 'variable'
|
||||
info['name'] = get_symbol_name(symbol[0])
|
||||
if info['name'] is None:
|
||||
info['type'] = 'error_parsing_symbol'
|
||||
print(f"Error: No se pudo parsear el nombre del símbolo para Access UID={uid}")
|
||||
return info
|
||||
|
||||
elif constant:
|
||||
info['type'] = 'constant'
|
||||
const_type_elem = constant[0].xpath("./*[local-name()='ConstantType']")
|
||||
const_val_elem = constant[0].xpath("./*[local-name()='ConstantValue']")
|
||||
info['datatype'] = const_type_elem[0].text if const_type_elem and const_type_elem[0].text is not None else 'Unknown'
|
||||
value_str = const_val_elem[0].text if const_val_elem and const_val_elem[0].text is not None else None
|
||||
|
||||
if value_str is None:
|
||||
info['type'] = 'error_parsing_constant'
|
||||
info['value'] = None
|
||||
print(f"Error: Constante sin valor encontrada para Access UID={uid}")
|
||||
return info
|
||||
|
||||
if info['datatype'] == 'Unknown':
|
||||
val_lower = value_str.lower()
|
||||
if val_lower in ['true', 'false']: info['datatype'] = 'Bool'
|
||||
elif value_str.isdigit() or (value_str.startswith('-') and value_str[1:].isdigit()): info['datatype'] = 'Int'
|
||||
elif '.' in value_str:
|
||||
try: float(value_str); info['datatype'] = 'Real'
|
||||
except ValueError: pass
|
||||
elif '#' in value_str: info['datatype'] = 'TypedConstant'
|
||||
|
||||
info['value'] = value_str
|
||||
dtype_lower = info['datatype'].lower()
|
||||
val_str_processed = value_str.split('#')[-1] if '#' in value_str else value_str
|
||||
try:
|
||||
if dtype_lower in ['int', 'dint', 'udint', 'sint', 'usint', 'lint', 'ulint', 'word', 'dword', 'lword', 'byte']:
|
||||
info['value'] = int(val_str_processed)
|
||||
elif dtype_lower == 'bool':
|
||||
info['value'] = val_str_processed.lower() == 'true' or val_str_processed == '1'
|
||||
elif dtype_lower in ['real', 'lreal']:
|
||||
info['value'] = float(val_str_processed)
|
||||
elif dtype_lower == 'typedconstant':
|
||||
info['value'] = value_str
|
||||
except (ValueError, TypeError) as e:
|
||||
print(f"Advertencia: No se pudo convertir el valor '{val_str_processed}' a tipo {dtype_lower} para UID={uid}. Se mantiene como string. Error: {e}")
|
||||
info['value'] = value_str
|
||||
|
||||
else:
|
||||
info['type'] = 'unknown_structure'
|
||||
print(f"Advertencia: Access UID={uid} no es ni Symbol ni Constant.")
|
||||
return info
|
||||
|
||||
if info['type'] == 'variable' and info.get('name') is None:
|
||||
print(f"Error Interno: parse_access terminó con tipo 'variable' pero sin nombre para UID {uid}.")
|
||||
info['type'] = 'error_no_name'
|
||||
return info
|
||||
|
||||
return info
|
||||
|
||||
def parse_part(part_element):
|
||||
"""
|
||||
Parsea un elemento Part (representa una instrucción como Add, Move, Contact, Coil)
|
||||
y extrae su UID, nombre y valores de plantilla (TemplateValue).
|
||||
Devuelve un diccionario con la información o None si el elemento es inválido.
|
||||
"""
|
||||
if part_element is None:
|
||||
return None
|
||||
|
||||
uid = part_element.get('UId')
|
||||
name = part_element.get('Name')
|
||||
|
||||
if not uid or not name:
|
||||
print(f"Error: Part encontrado sin UID o Name: {etree.tostring(part_element, encoding='unicode')}")
|
||||
return None
|
||||
|
||||
template_values = {}
|
||||
try:
|
||||
for tv in part_element.xpath("./*[local-name()='TemplateValue']"):
|
||||
tv_name = tv.get('Name')
|
||||
tv_type = tv.get('Type')
|
||||
if tv_name and tv_type:
|
||||
template_values[tv_name] = tv_type
|
||||
except Exception as e:
|
||||
print(f"Advertencia: Error extrayendo TemplateValues para Part UID={uid}: {e}")
|
||||
|
||||
return {
|
||||
'uid': uid,
|
||||
'name': name,
|
||||
'template_values': template_values # Mantenemos esto por si acaso, aunque no se use prominentemente
|
||||
}
|
||||
|
||||
# --- Main Parsing Logic ---
|
||||
|
||||
def parse_network(network_element):
|
||||
"""
|
||||
Parsea un elemento SW.Blocks.CompileUnit (representa una red de lógica)
|
||||
y extrae su ID, título, comentario y la lógica interna simplificada en formato JSON,
|
||||
incluyendo la lógica conectada a ENO si no es un simple EN->ENO.
|
||||
"""
|
||||
if network_element is None:
|
||||
print("Error: parse_network llamado con network_element=None")
|
||||
return {'id': 'ERROR', 'title': 'Invalid Network Element', 'comment': '', 'logic': [], 'error': 'Input element was None'}
|
||||
|
||||
network_id = network_element.get('ID')
|
||||
|
||||
# Extrae el título de la red
|
||||
title_element = network_element.xpath(".//*[local-name()='MultilingualText'][@CompositionName='Title']")
|
||||
network_title = get_multilingual_text(title_element[0]) if title_element else f"Network {network_id}"
|
||||
|
||||
# *** NUEVO: Extrae el comentario de la red ***
|
||||
network_comment = ""
|
||||
comment_title_element = network_element.xpath("./*[local-name()='ObjectList']/*[local-name()='MultilingualText'][@CompositionName='Comment']")
|
||||
if comment_title_element:
|
||||
network_comment = get_multilingual_text(comment_title_element[0])
|
||||
# print(f"DEBUG: Comentario Red {network_id}: '{network_comment[:50]}...'")
|
||||
|
||||
|
||||
flgnet_list = network_element.xpath(".//flg:FlgNet", namespaces=ns)
|
||||
if not flgnet_list:
|
||||
print(f"Error: No se encontró FlgNet en la red ID={network_id}")
|
||||
return {'id': network_id, 'title': network_title, 'comment': network_comment, 'logic': [], 'error': 'FlgNet not found'}
|
||||
flgnet = flgnet_list[0]
|
||||
|
||||
# 1. Parsear Access y Parts
|
||||
access_map = {}
|
||||
for acc in flgnet.xpath(".//flg:Access", namespaces=ns):
|
||||
acc_info = parse_access(acc)
|
||||
if acc_info and 'uid' in acc_info:
|
||||
access_map[acc_info['uid']] = acc_info
|
||||
|
||||
parts_map = {}
|
||||
for part in flgnet.xpath(".//flg:Part", namespaces=ns):
|
||||
part_info = parse_part(part)
|
||||
if part_info and 'uid' in part_info:
|
||||
parts_map[part_info['uid']] = part_info
|
||||
|
||||
# 2. Parsear Wires y construir mapa de conexiones de entrada y *salida ENO*
|
||||
wire_connections = {} # Clave=(dest_uid, dest_pin), Valor=lista de (source_uid, source_pin)
|
||||
eno_outputs = {} # Clave=source_part_uid, Valor=lista de (dest_uid, dest_pin)
|
||||
flg_ns_uri = ns['flg']
|
||||
|
||||
for wire in flgnet.xpath(".//flg:Wire", namespaces=ns):
|
||||
source_uid, source_pin, dest_uid, dest_pin = None, None, None, None
|
||||
children = wire.getchildren()
|
||||
if len(children) < 2: continue
|
||||
|
||||
source_elem, dest_elem = children[0], children[1]
|
||||
|
||||
# Determina la fuente
|
||||
if source_elem.tag == etree.QName(flg_ns_uri, 'Powerrail'): source_uid, source_pin = 'POWERRAIL', 'out'
|
||||
elif source_elem.tag == etree.QName(flg_ns_uri, 'IdentCon'): source_uid, source_pin = source_elem.get('UId'), 'value'
|
||||
elif source_elem.tag == etree.QName(flg_ns_uri, 'NameCon'): source_uid, source_pin = source_elem.get('UId'), source_elem.get('Name')
|
||||
|
||||
# Determina el destino
|
||||
if dest_elem.tag == etree.QName(flg_ns_uri, 'IdentCon'): dest_uid, dest_pin = dest_elem.get('UId'), 'value'
|
||||
elif dest_elem.tag == etree.QName(flg_ns_uri, 'NameCon'): dest_uid, dest_pin = dest_elem.get('UId'), dest_elem.get('Name')
|
||||
|
||||
# Registrar conexión de entrada normal
|
||||
if dest_uid and dest_pin and source_uid is not None:
|
||||
dest_key = (dest_uid, dest_pin)
|
||||
source_info = (source_uid, source_pin)
|
||||
if dest_key not in wire_connections: wire_connections[dest_key] = []
|
||||
if source_info not in wire_connections[dest_key]: wire_connections[dest_key].append(source_info)
|
||||
|
||||
# *** NUEVO: Registrar conexiones que SALEN de un pin ENO ***
|
||||
if source_pin == 'eno' and source_uid in parts_map:
|
||||
if source_uid not in eno_outputs: eno_outputs[source_uid] = []
|
||||
eno_dest_info = (dest_uid, dest_pin)
|
||||
if eno_dest_info not in eno_outputs[source_uid]:
|
||||
eno_outputs[source_uid].append(eno_dest_info)
|
||||
# print(f"DEBUG: Red {network_id} - ENO de {source_uid} conectado a ({dest_uid}, {dest_pin})")
|
||||
|
||||
|
||||
# 3. Construir la representación lógica principal
|
||||
all_logic_steps = {}
|
||||
for part_uid, part_info in parts_map.items():
|
||||
instruction_repr = {'instruction_uid': part_uid, 'type': part_info['name'], 'inputs': {}, 'outputs': {}}
|
||||
|
||||
# Procesar Entradas (igual que antes)
|
||||
for (conn_dest_uid, conn_dest_pin), sources_list in wire_connections.items():
|
||||
if conn_dest_uid == part_uid:
|
||||
input_sources_repr = []
|
||||
for source_uid, source_pin in sources_list:
|
||||
if source_uid == 'POWERRAIL': input_sources_repr.append({'type': 'powerrail'})
|
||||
elif source_uid in access_map: input_sources_repr.append(access_map[source_uid])
|
||||
elif source_uid in parts_map:
|
||||
input_sources_repr.append({'type': 'connection', 'source_instruction_uid': source_uid,
|
||||
'source_instruction_type': parts_map[source_uid]['name'], 'source_pin': source_pin})
|
||||
else: input_sources_repr.append({'type': 'unknown_source', 'uid': source_uid})
|
||||
|
||||
if len(input_sources_repr) == 1: instruction_repr['inputs'][conn_dest_pin] = input_sources_repr[0]
|
||||
elif len(input_sources_repr) > 1: instruction_repr['inputs'][conn_dest_pin] = input_sources_repr
|
||||
|
||||
# Procesar Salidas (igual que antes)
|
||||
for (conn_dest_uid, conn_dest_pin), sources_list in wire_connections.items():
|
||||
for source_uid, source_pin in sources_list:
|
||||
if source_uid == part_uid and conn_dest_uid in access_map:
|
||||
if source_pin not in instruction_repr['outputs']: instruction_repr['outputs'][source_pin] = []
|
||||
if access_map[conn_dest_uid] not in instruction_repr['outputs'][source_pin]:
|
||||
instruction_repr['outputs'][source_pin].append(access_map[conn_dest_uid])
|
||||
|
||||
all_logic_steps[part_uid] = instruction_repr
|
||||
|
||||
|
||||
# *** NUEVO: Procesar y añadir lógica ENO "interesante" ***
|
||||
for source_instr_uid, eno_destinations in eno_outputs.items():
|
||||
if source_instr_uid not in all_logic_steps: continue # Seguridad
|
||||
|
||||
interesting_eno_logic = []
|
||||
for dest_uid, dest_pin in eno_destinations:
|
||||
# Determinar si es una conexión directa a EN de otra instrucción
|
||||
is_direct_en_connection = (dest_uid in parts_map and dest_pin == 'en')
|
||||
|
||||
if not is_direct_en_connection:
|
||||
# Si NO es directa a EN, es "interesante"
|
||||
target_info = {'target_pin': dest_pin}
|
||||
if dest_uid in parts_map:
|
||||
target_info['target_type'] = 'instruction'
|
||||
target_info['target_uid'] = dest_uid
|
||||
target_info['target_name'] = parts_map[dest_uid]['name']
|
||||
elif dest_uid in access_map:
|
||||
# El destino es una variable o constante
|
||||
target_info['target_type'] = 'operand'
|
||||
target_info['target_details'] = access_map[dest_uid] # Incluye toda la info del Access
|
||||
else:
|
||||
target_info['target_type'] = 'unknown'
|
||||
target_info['target_uid'] = dest_uid
|
||||
|
||||
interesting_eno_logic.append(target_info)
|
||||
# print(f"DEBUG: Red {network_id} - ENO de {source_instr_uid}: Lógica interesante -> {target_info}")
|
||||
|
||||
# Añadir la lista de lógica ENO interesante a la instrucción fuente, si existe
|
||||
if interesting_eno_logic:
|
||||
all_logic_steps[source_instr_uid]['eno_logic'] = interesting_eno_logic
|
||||
|
||||
|
||||
# 4. Ordenar y finalizar
|
||||
try:
|
||||
sorted_uids = sorted(all_logic_steps.keys(), key=lambda x: int(x) if x.isdigit() else float('inf'))
|
||||
except ValueError:
|
||||
print(f"Advertencia: UIDs no puramente numéricos en red {network_id}. Ordenando alfabéticamente.")
|
||||
sorted_uids = sorted(all_logic_steps.keys())
|
||||
|
||||
network_logic = [all_logic_steps[uid] for uid in sorted_uids if uid in all_logic_steps]
|
||||
|
||||
# Devolver estructura de red con ID, título, comentario y lógica
|
||||
return {'id': network_id, 'title': network_title, 'comment': network_comment, 'logic': network_logic}
|
||||
|
||||
|
||||
def convert_xml_to_json(xml_filepath, json_filepath):
|
||||
"""
|
||||
Función principal que orquesta la conversión del archivo XML de Openness
|
||||
a un archivo JSON simplificado que representa la estructura del bloque FC,
|
||||
incluyendo comentarios y lógica ENO no trivial.
|
||||
"""
|
||||
print(f"Iniciando conversión de '{xml_filepath}' a '{json_filepath}'...")
|
||||
|
||||
if not os.path.exists(xml_filepath):
|
||||
print(f"Error Crítico: Archivo XML no encontrado en '{xml_filepath}'")
|
||||
return
|
||||
|
||||
try:
|
||||
print("Paso 1: Parseando archivo XML...")
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(xml_filepath, parser)
|
||||
root = tree.getroot()
|
||||
print("Paso 1: Parseo XML completado.")
|
||||
|
||||
print("Paso 2: Buscando el bloque SW.Blocks.FC...")
|
||||
fc_block_list = root.xpath("//*[local-name()='SW.Blocks.FC']")
|
||||
if not fc_block_list:
|
||||
print("Error Crítico: No se encontró el elemento <SW.Blocks.FC> en el archivo.")
|
||||
return
|
||||
fc_block = fc_block_list[0]
|
||||
print(f"Paso 2: Bloque SW.Blocks.FC encontrado (ID={fc_block.get('ID')}).")
|
||||
|
||||
print("Paso 3: Extrayendo atributos del bloque...")
|
||||
attribute_list_node = fc_block.xpath("./*[local-name()='AttributeList']")
|
||||
block_name_val = "Unknown"
|
||||
block_number_val = None
|
||||
block_lang_val = "Unknown"
|
||||
if attribute_list_node:
|
||||
attr_list = attribute_list_node[0]
|
||||
name_node = attr_list.xpath("./*[local-name()='Name']/text()")
|
||||
if name_node: block_name_val = name_node[0].strip()
|
||||
num_node = attr_list.xpath("./*[local-name()='Number']/text()")
|
||||
if num_node and num_node[0].isdigit(): block_number_val = int(num_node[0])
|
||||
lang_node = attr_list.xpath("./*[local-name()='ProgrammingLanguage']/text()")
|
||||
if lang_node: block_lang_val = lang_node[0].strip()
|
||||
print(f"Paso 3: Atributos extraídos: Nombre='{block_name_val}', Número={block_number_val}, Lenguaje='{block_lang_val}'")
|
||||
else: print("Advertencia: No se encontró AttributeList para el bloque FC.")
|
||||
|
||||
# *** NUEVO: Extraer comentario del bloque ***
|
||||
block_comment_val = ""
|
||||
# El comentario del bloque suele estar en ObjectList > MultilingualText[@CompositionName='Comment']
|
||||
comment_node_list = fc_block.xpath("./*[local-name()='ObjectList']/*[local-name()='MultilingualText'][@CompositionName='Comment']")
|
||||
if comment_node_list:
|
||||
block_comment_val = get_multilingual_text(comment_node_list[0])
|
||||
print(f"Paso 3b: Comentario del bloque extraído: '{block_comment_val[:50]}...'")
|
||||
|
||||
|
||||
result = {
|
||||
"block_name": block_name_val,
|
||||
"block_number": block_number_val,
|
||||
"language": block_lang_val,
|
||||
"block_comment": block_comment_val, # Añadido comentario del bloque
|
||||
"interface": {},
|
||||
"networks": []
|
||||
}
|
||||
|
||||
print("Paso 4: Extrayendo la interfaz del bloque...")
|
||||
interface_found = False
|
||||
if attribute_list_node:
|
||||
interface_node_list = attribute_list_node[0].xpath("./*[local-name()='Interface']")
|
||||
if interface_node_list:
|
||||
interface_node = interface_node_list[0]
|
||||
interface_found = True
|
||||
print("Paso 4: Nodo Interface encontrado dentro de AttributeList.")
|
||||
for section in interface_node.xpath(".//iface:Section", namespaces=ns):
|
||||
section_name = section.get('Name')
|
||||
members = []
|
||||
for member in section.xpath("./iface:Member", namespaces=ns):
|
||||
member_name = member.get('Name')
|
||||
member_dtype = member.get('Datatype')
|
||||
if member_name and member_dtype: members.append({"name": member_name, "datatype": member_dtype})
|
||||
if members: result["interface"][section_name] = members
|
||||
if not result["interface"]: print("Advertencia: Nodo Interface encontrado, pero no contenía secciones iface:Section válidas.")
|
||||
else: print("Advertencia: No se encontró el nodo <Interface> DENTRO de <AttributeList>.")
|
||||
|
||||
if not interface_found and not result["interface"]: print("Advertencia: No se pudo extraer ninguna información de la interfaz.")
|
||||
|
||||
print("Paso 5: Extrayendo la lógica de las redes (CompileUnits)...")
|
||||
networks_processed_count = 0
|
||||
object_list_node = fc_block.xpath("./*[local-name()='ObjectList']")
|
||||
if object_list_node:
|
||||
compile_units = object_list_node[0].xpath("./*[local-name()='SW.Blocks.CompileUnit']")
|
||||
print(f"Paso 5: Se encontraron {len(compile_units)} elementos SW.Blocks.CompileUnit.")
|
||||
for network_elem in compile_units:
|
||||
networks_processed_count += 1
|
||||
print(f"DEBUG: Procesando red #{networks_processed_count} (ID={network_elem.get('ID')})...")
|
||||
parsed_network = parse_network(network_elem) # Ahora parse_network incluye comentario
|
||||
if parsed_network and parsed_network.get('error') is None: result["networks"].append(parsed_network)
|
||||
elif parsed_network:
|
||||
print(f"Error: Falló el parseo de la red ID={parsed_network.get('id')}: {parsed_network.get('error')}")
|
||||
result["networks"].append(parsed_network)
|
||||
else: print(f"Error: parse_network devolvió None para un CompileUnit (ID={network_elem.get('ID')}).")
|
||||
if networks_processed_count == 0: print("Advertencia: ObjectList encontrado, pero no contenía SW.Blocks.CompileUnit.")
|
||||
else: print("Advertencia: No se encontró ObjectList para el bloque FC.")
|
||||
|
||||
print("Paso 6: Escribiendo el resultado en el archivo JSON...")
|
||||
# Chequeos finales
|
||||
if not result["interface"]: print("ADVERTENCIA FINAL: La sección 'interface' está vacía.")
|
||||
if not result["networks"]: print("ADVERTENCIA FINAL: La sección 'networks' está vacía.")
|
||||
else:
|
||||
# Chequea si alguna instrucción tiene lógica ENO interesante
|
||||
eno_logic_found = any(instr.get('eno_logic') for net in result.get('networks', []) if net.get('error') is None for instr in net.get('logic', []))
|
||||
if eno_logic_found: print("INFO FINAL: Se detectó lógica ENO interesante en al menos una instrucción.")
|
||||
else: print("INFO FINAL: No se detectó lógica ENO interesante (solo conexiones directas ENO->EN o ENO no conectado).")
|
||||
|
||||
try:
|
||||
with open(json_filepath, 'w', encoding='utf-8') as f:
|
||||
json.dump(result, f, indent=4, ensure_ascii=False)
|
||||
print(f"Paso 6: Escritura completada.")
|
||||
print(f"Conversión finalizada con éxito. Archivo JSON guardado en: '{json_filepath}'")
|
||||
except IOError as e: print(f"Error Crítico: No se pudo escribir el archivo JSON en '{json_filepath}'. Error: {e}")
|
||||
except TypeError as e: print(f"Error Crítico: Problema al serializar datos a JSON. Error: {e}")
|
||||
|
||||
except etree.XMLSyntaxError as e:
|
||||
print(f"Error Crítico: Error de sintaxis en el archivo XML '{xml_filepath}'. Detalles: {e}")
|
||||
except Exception as e:
|
||||
print(f"Error Crítico: Ocurrió un error inesperado durante el procesamiento: {e}")
|
||||
print("--- Traceback ---"); traceback.print_exc(); print("--- Fin Traceback ---")
|
||||
|
||||
# --- Punto de Entrada Principal ---
|
||||
if __name__ == "__main__":
|
||||
xml_file = 'BlenderRun_ProdTime.xml'
|
||||
json_file = 'BlenderRun_ProdTime_simplified.json'
|
||||
convert_xml_to_json(xml_file, json_file)
|
|
@ -0,0 +1,720 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import os
|
||||
from lxml import etree
|
||||
import traceback
|
||||
from collections import defaultdict
|
||||
|
||||
# --- Namespaces ---
|
||||
ns = {
|
||||
"iface": "http://www.siemens.com/automation/Openness/SW/Interface/v5",
|
||||
"flg": "http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4",
|
||||
}
|
||||
|
||||
|
||||
# --- Helper Functions ---
|
||||
# (get_multilingual_text, get_symbol_name, parse_access, parse_part - sin cambios)
|
||||
# ... (código de estas funciones aquí) ...
|
||||
def get_multilingual_text(element, default_lang="en-US", fallback_lang="it-IT"):
|
||||
if element is None:
|
||||
return ""
|
||||
try:
|
||||
xpath_expr = (
|
||||
f".//*[local-name()='MultilingualTextItem'][*[local-name()='AttributeList']/*[local-name()='Culture' and text()='{default_lang}']]"
|
||||
f"/*[local-name()='AttributeList']/*[local-name()='Text']"
|
||||
)
|
||||
text_items = element.xpath(xpath_expr)
|
||||
if text_items and text_items[0].text is not None:
|
||||
return text_items[0].text.strip()
|
||||
xpath_expr = (
|
||||
f".//*[local-name()='MultilingualTextItem'][*[local-name()='AttributeList']/*[local-name()='Culture' and text()='{fallback_lang}']]"
|
||||
f"/*[local-name()='AttributeList']/*[local-name()='Text']"
|
||||
)
|
||||
text_items = element.xpath(xpath_expr)
|
||||
if text_items and text_items[0].text is not None:
|
||||
return text_items[0].text.strip()
|
||||
xpath_expr = f".//*[local-name()='MultilingualTextItem']/*[local-name()='AttributeList']/*[local-name()='Text']"
|
||||
text_items = element.xpath(xpath_expr)
|
||||
if text_items and text_items[0].text is not None:
|
||||
return text_items[0].text.strip()
|
||||
return ""
|
||||
except Exception as e:
|
||||
print(f"Advertencia: Error extrayendo MultilingualText: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
def get_symbol_name(symbol_element):
|
||||
if symbol_element is None:
|
||||
return None
|
||||
try:
|
||||
components = symbol_element.xpath("./*[local-name()='Component']/@Name")
|
||||
return ".".join(f'"{c}"' for c in components) if components else None
|
||||
except Exception as e:
|
||||
print(f"Advertencia: Excepción en get_symbol_name: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def parse_access(access_element):
|
||||
if access_element is None:
|
||||
return None
|
||||
uid = access_element.get("UId")
|
||||
scope = access_element.get("Scope")
|
||||
info = {"uid": uid, "scope": scope, "type": "unknown"}
|
||||
symbol = access_element.xpath("./*[local-name()='Symbol']")
|
||||
constant = access_element.xpath("./*[local-name()='Constant']")
|
||||
if symbol:
|
||||
info["type"] = "variable"
|
||||
info["name"] = get_symbol_name(symbol[0])
|
||||
if info["name"] is None:
|
||||
info["type"] = "error_parsing_symbol"
|
||||
print(f"Error: No se pudo parsear nombre símbolo Access UID={uid}")
|
||||
return info
|
||||
elif constant:
|
||||
info["type"] = "constant"
|
||||
const_type_elem = constant[0].xpath("./*[local-name()='ConstantType']")
|
||||
const_val_elem = constant[0].xpath("./*[local-name()='ConstantValue']")
|
||||
info["datatype"] = (
|
||||
const_type_elem[0].text
|
||||
if const_type_elem and const_type_elem[0].text is not None
|
||||
else "Unknown"
|
||||
)
|
||||
value_str = (
|
||||
const_val_elem[0].text
|
||||
if const_val_elem and const_val_elem[0].text is not None
|
||||
else None
|
||||
)
|
||||
if value_str is None:
|
||||
info["type"] = "error_parsing_constant"
|
||||
info["value"] = None
|
||||
print(f"Error: Constante sin valor Access UID={uid}")
|
||||
return info
|
||||
if info["datatype"] == "Unknown":
|
||||
val_lower = value_str.lower()
|
||||
if val_lower in ["true", "false"]:
|
||||
info["datatype"] = "Bool"
|
||||
elif value_str.isdigit() or (
|
||||
value_str.startswith("-") and value_str[1:].isdigit()
|
||||
):
|
||||
info["datatype"] = "Int"
|
||||
elif "." in value_str:
|
||||
try:
|
||||
float(value_str)
|
||||
info["datatype"] = "Real"
|
||||
except ValueError:
|
||||
pass
|
||||
elif "#" in value_str:
|
||||
info["datatype"] = "TypedConstant"
|
||||
info["value"] = value_str
|
||||
dtype_lower = info["datatype"].lower()
|
||||
val_str_processed = value_str.split("#")[-1] if "#" in value_str else value_str
|
||||
try:
|
||||
if dtype_lower in [
|
||||
"int",
|
||||
"dint",
|
||||
"udint",
|
||||
"sint",
|
||||
"usint",
|
||||
"lint",
|
||||
"ulint",
|
||||
"word",
|
||||
"dword",
|
||||
"lword",
|
||||
"byte",
|
||||
]:
|
||||
info["value"] = int(val_str_processed)
|
||||
elif dtype_lower == "bool":
|
||||
info["value"] = (
|
||||
val_str_processed.lower() == "true" or val_str_processed == "1"
|
||||
)
|
||||
elif dtype_lower in ["real", "lreal"]:
|
||||
info["value"] = float(val_str_processed)
|
||||
elif dtype_lower == "typedconstant":
|
||||
info["value"] = value_str
|
||||
except (ValueError, TypeError) as e:
|
||||
print(
|
||||
f"Advertencia: No se pudo convertir valor '{val_str_processed}' a {dtype_lower} UID={uid}. Error: {e}"
|
||||
)
|
||||
info["value"] = value_str
|
||||
else:
|
||||
info["type"] = "unknown_structure"
|
||||
print(f"Advertencia: Access UID={uid} no es Symbol ni Constant.")
|
||||
return info
|
||||
if info["type"] == "variable" and info.get("name") is None:
|
||||
print(f"Error Interno: parse_access var sin nombre UID {uid}.")
|
||||
info["type"] = "error_no_name"
|
||||
return info
|
||||
return info
|
||||
|
||||
|
||||
def parse_part(part_element):
|
||||
"""
|
||||
Parsea un elemento Part (instrucción) y extrae UID, nombre,
|
||||
valores de plantilla y pines negados.
|
||||
"""
|
||||
if part_element is None: return None
|
||||
uid = part_element.get('UId'); name = part_element.get('Name')
|
||||
if not uid or not name: print(f"Error: Part sin UID o Name: {etree.tostring(part_element, encoding='unicode')}"); return None
|
||||
|
||||
template_values = {}
|
||||
try:
|
||||
for tv in part_element.xpath("./*[local-name()='TemplateValue']"):
|
||||
tv_name = tv.get('Name'); tv_type = tv.get('Type')
|
||||
if tv_name and tv_type: template_values[tv_name] = tv_type
|
||||
except Exception as e: print(f"Advertencia: Error extrayendo TemplateValues Part UID={uid}: {e}")
|
||||
|
||||
# --- INICIO NUEVA LÓGICA PARA NEGACIÓN ---
|
||||
negated_pins = {} # Diccionario para pines negados: {pin_name: True}
|
||||
try:
|
||||
for negated_elem in part_element.xpath("./*[local-name()='Negated']"):
|
||||
negated_pin_name = negated_elem.get('Name')
|
||||
if negated_pin_name:
|
||||
negated_pins[negated_pin_name] = True
|
||||
# print(f"DEBUG: Pin negado detectado: {name} UID {uid}, Pin: {negated_pin_name}") # Debug
|
||||
except Exception as e: print(f"Advertencia: Error extrayendo Negated Pins Part UID={uid}: {e}")
|
||||
return {
|
||||
'uid': uid,
|
||||
'type': name, # Usar 'type' para consistencia
|
||||
'template_values': template_values,
|
||||
'negated_pins': negated_pins # Añadir diccionario de pines negados
|
||||
}
|
||||
|
||||
|
||||
# --- NUEVA FUNCIÓN parse_call ---
|
||||
def parse_call(call_element):
|
||||
"""
|
||||
Parsea un elemento Call (llamada a FC/FB) y extrae su información.
|
||||
"""
|
||||
if call_element is None:
|
||||
return None
|
||||
uid = call_element.get("UId")
|
||||
if not uid:
|
||||
print(
|
||||
f"Error: Call encontrado sin UID: {etree.tostring(call_element, encoding='unicode')}"
|
||||
)
|
||||
return None
|
||||
|
||||
call_info_elem = call_element.xpath("./*[local-name()='CallInfo']")
|
||||
if not call_info_elem:
|
||||
print(f"Error: Call UID {uid} sin elemento CallInfo.")
|
||||
return None
|
||||
call_info = call_info_elem[0]
|
||||
|
||||
block_name = call_info.get("Name")
|
||||
block_type = call_info.get("BlockType") # FC, FB, etc.
|
||||
instance_name = None
|
||||
instance_scope = None
|
||||
|
||||
# Si es una llamada a FB, puede tener información de instancia
|
||||
instance_elem = call_info.xpath("./*[local-name()='Instance']")
|
||||
if instance_elem:
|
||||
instance = instance_elem[0]
|
||||
instance_scope = instance.get("Scope") # Ej: GlobalVariable, InstanceDB
|
||||
# El nombre de la instancia DB suele estar en Component dentro de Symbol
|
||||
symbol_elem = instance.xpath("./*[local-name()='Symbol']")
|
||||
if symbol_elem:
|
||||
instance_name = get_symbol_name(symbol_elem[0])
|
||||
|
||||
if not block_name or not block_type:
|
||||
print(f"Error: CallInfo para UID {uid} sin Name o BlockType.")
|
||||
return None
|
||||
|
||||
call_data = {
|
||||
"uid": uid,
|
||||
"type": "Call", # Tipo genérico para nuestra estructura JSON
|
||||
"block_name": block_name,
|
||||
"block_type": block_type,
|
||||
}
|
||||
if instance_name:
|
||||
call_data["instance_db"] = instance_name
|
||||
if instance_scope:
|
||||
call_data["instance_scope"] = instance_scope
|
||||
|
||||
return call_data
|
||||
|
||||
|
||||
# --- FIN NUEVA FUNCIÓN ---
|
||||
|
||||
|
||||
# --- Función parse_network MODIFICADA ---
|
||||
def parse_network(network_element):
|
||||
"""
|
||||
Parsea una red, extrae lógica (incluyendo Calls) y añade conexiones EN implícitas.
|
||||
"""
|
||||
if network_element is None:
|
||||
return {
|
||||
"id": "ERROR",
|
||||
"title": "Invalid Network Element",
|
||||
"comment": "",
|
||||
"logic": [],
|
||||
"error": "Input element was None",
|
||||
}
|
||||
network_id = network_element.get("ID")
|
||||
title_element = network_element.xpath(
|
||||
".//*[local-name()='MultilingualText'][@CompositionName='Title']"
|
||||
)
|
||||
network_title = (
|
||||
get_multilingual_text(title_element[0])
|
||||
if title_element
|
||||
else f"Network {network_id}"
|
||||
)
|
||||
comment_title_element = network_element.xpath(
|
||||
"./*[local-name()='ObjectList']/*[local-name()='MultilingualText'][@CompositionName='Comment']"
|
||||
)
|
||||
network_comment = (
|
||||
get_multilingual_text(comment_title_element[0]) if comment_title_element else ""
|
||||
)
|
||||
|
||||
flgnet_list = network_element.xpath(".//flg:FlgNet", namespaces=ns)
|
||||
if not flgnet_list:
|
||||
return {
|
||||
"id": network_id,
|
||||
"title": network_title,
|
||||
"comment": network_comment,
|
||||
"logic": [],
|
||||
"error": "FlgNet not found",
|
||||
}
|
||||
flgnet = flgnet_list[0]
|
||||
|
||||
# 1. Parsear Access, Parts y Calls
|
||||
access_map = {
|
||||
acc_info["uid"]: acc_info
|
||||
for acc in flgnet.xpath(".//flg:Access", namespaces=ns)
|
||||
if (acc_info := parse_access(acc))
|
||||
}
|
||||
|
||||
# --- MODIFICADO: Unir Parts y Calls en un solo mapa ---
|
||||
parts_and_calls_map = {}
|
||||
instruction_elements = flgnet.xpath(
|
||||
".//flg:Part | .//flg:Call", namespaces=ns
|
||||
) # Buscar ambos tipos
|
||||
|
||||
for element in instruction_elements:
|
||||
parsed_info = None
|
||||
if element.tag.endswith("Part"):
|
||||
parsed_info = parse_part(element)
|
||||
elif element.tag.endswith("Call"):
|
||||
parsed_info = parse_call(element)
|
||||
|
||||
if parsed_info and "uid" in parsed_info:
|
||||
parts_and_calls_map[parsed_info["uid"]] = parsed_info
|
||||
else:
|
||||
print(
|
||||
f"Advertencia: Se ignoró un Part/Call inválido en la red {network_id}"
|
||||
)
|
||||
# --- FIN MODIFICADO ---
|
||||
|
||||
# 2. Parsear Wires y construir mapas de conexiones
|
||||
wire_connections = defaultdict(list)
|
||||
source_connections = defaultdict(list)
|
||||
eno_outputs = defaultdict(list)
|
||||
flg_ns_uri = ns["flg"]
|
||||
for wire in flgnet.xpath(".//flg:Wire", namespaces=ns):
|
||||
source_uid, source_pin, dest_uid, dest_pin = None, None, None, None
|
||||
children = wire.getchildren()
|
||||
if len(children) < 2:
|
||||
continue
|
||||
source_elem, dest_elem = children[0], children[1]
|
||||
if source_elem.tag == etree.QName(flg_ns_uri, "Powerrail"):
|
||||
source_uid, source_pin = "POWERRAIL", "out"
|
||||
elif source_elem.tag == etree.QName(flg_ns_uri, "IdentCon"):
|
||||
source_uid, source_pin = source_elem.get("UId"), "value"
|
||||
elif source_elem.tag == etree.QName(flg_ns_uri, "NameCon"):
|
||||
source_uid, source_pin = source_elem.get("UId"), source_elem.get("Name")
|
||||
if dest_elem.tag == etree.QName(flg_ns_uri, "IdentCon"):
|
||||
dest_uid, dest_pin = dest_elem.get("UId"), "value"
|
||||
elif dest_elem.tag == etree.QName(flg_ns_uri, "NameCon"):
|
||||
dest_uid, dest_pin = dest_elem.get("UId"), dest_elem.get("Name")
|
||||
if dest_uid and dest_pin and source_uid is not None:
|
||||
dest_key = (dest_uid, dest_pin)
|
||||
source_key = (source_uid, source_pin)
|
||||
source_info = (source_uid, source_pin)
|
||||
dest_info = (dest_uid, dest_pin)
|
||||
if source_info not in wire_connections[dest_key]:
|
||||
wire_connections[dest_key].append(source_info)
|
||||
if dest_info not in source_connections[source_key]:
|
||||
source_connections[source_key].append(dest_info)
|
||||
if (
|
||||
source_pin == "eno" and source_uid in parts_and_calls_map
|
||||
): # Usar mapa combinado
|
||||
if dest_info not in eno_outputs[source_uid]:
|
||||
eno_outputs[source_uid].append(dest_info)
|
||||
|
||||
# 3. Construir la representación lógica INICIAL
|
||||
all_logic_steps = {}
|
||||
functional_block_types = [
|
||||
"Move",
|
||||
"Add",
|
||||
"Sub",
|
||||
"Mul",
|
||||
"Div",
|
||||
"Mod",
|
||||
"Convert",
|
||||
"Call",
|
||||
] # Añadir Call
|
||||
rlo_generators = [
|
||||
"Contact",
|
||||
"O",
|
||||
"Eq",
|
||||
"Ne",
|
||||
"Gt",
|
||||
"Lt",
|
||||
"Ge",
|
||||
"Le",
|
||||
"And",
|
||||
"Xor",
|
||||
"PBox",
|
||||
]
|
||||
|
||||
# --- MODIFICADO: Iterar sobre el mapa combinado ---
|
||||
for instruction_uid, instruction_info in parts_and_calls_map.items():
|
||||
# Usar directamente la info parseada (part_info o call_info)
|
||||
instruction_repr = {
|
||||
"instruction_uid": instruction_uid,
|
||||
**instruction_info,
|
||||
} # Copiar datos base
|
||||
instruction_repr["inputs"] = {}
|
||||
instruction_repr["outputs"] = {}
|
||||
# --- FIN MODIFICADO ---
|
||||
|
||||
# Rellenar inputs explícitos
|
||||
# Añadir más pines si las llamadas a FB los usan (ej: parámetros FC/FB)
|
||||
possible_pins = set(
|
||||
["en", "in", "in1", "in2", "in3", "in4", "bit", "operand", "pre", "clk"]
|
||||
)
|
||||
# Añadir pines específicos de la llamada si es un FB? Más complejo.
|
||||
for dest_pin_name in possible_pins:
|
||||
dest_key = (instruction_uid, dest_pin_name)
|
||||
if dest_key in wire_connections:
|
||||
sources_list = wire_connections[dest_key]
|
||||
input_sources_repr = []
|
||||
for source_uid, source_pin in sources_list:
|
||||
if source_uid == "POWERRAIL":
|
||||
input_sources_repr.append({"type": "powerrail"})
|
||||
elif source_uid in access_map:
|
||||
input_sources_repr.append(access_map[source_uid])
|
||||
elif source_uid in parts_and_calls_map: # Usar mapa combinado
|
||||
input_sources_repr.append(
|
||||
{
|
||||
"type": "connection",
|
||||
# Usar el tipo del mapa combinado
|
||||
"source_instruction_type": parts_and_calls_map[
|
||||
source_uid
|
||||
]["type"],
|
||||
"source_instruction_uid": source_uid,
|
||||
"source_pin": source_pin,
|
||||
}
|
||||
)
|
||||
else:
|
||||
input_sources_repr.append(
|
||||
{"type": "unknown_source", "uid": source_uid}
|
||||
)
|
||||
if len(input_sources_repr) == 1:
|
||||
instruction_repr["inputs"][dest_pin_name] = input_sources_repr[0]
|
||||
elif len(input_sources_repr) > 1:
|
||||
instruction_repr["inputs"][dest_pin_name] = input_sources_repr
|
||||
|
||||
# Rellenar outputs explícitos (hacia Access)
|
||||
for source_pin_name in [
|
||||
"out",
|
||||
"out1",
|
||||
"Q",
|
||||
"eno",
|
||||
]: # Añadir salidas comunes de FC/FB si es necesario
|
||||
source_key = (instruction_uid, source_pin_name)
|
||||
if source_key in source_connections:
|
||||
for dest_uid, dest_pin in source_connections[source_key]:
|
||||
if dest_uid in access_map:
|
||||
if source_pin_name not in instruction_repr["outputs"]:
|
||||
instruction_repr["outputs"][source_pin_name] = []
|
||||
if (
|
||||
access_map[dest_uid]
|
||||
not in instruction_repr["outputs"][source_pin_name]
|
||||
):
|
||||
instruction_repr["outputs"][source_pin_name].append(
|
||||
access_map[dest_uid]
|
||||
)
|
||||
|
||||
all_logic_steps[instruction_uid] = instruction_repr
|
||||
|
||||
# --- 4. INFERENCIA Y PROPAGACIÓN DE CONEXIONES 'EN' IMPLÍCITAS ---
|
||||
# (Esta lógica probablemente necesite ajustes para considerar 'Call' como bloque funcional)
|
||||
# print(f"DEBUG: Iniciando inferencia EN para Red {network_id}...")
|
||||
processed_blocks_en_inference = set()
|
||||
something_changed = True
|
||||
inference_passes = 0
|
||||
max_inference_passes = len(all_logic_steps) + 5
|
||||
while something_changed and inference_passes < max_inference_passes:
|
||||
something_changed = False
|
||||
inference_passes += 1
|
||||
try:
|
||||
sorted_uids_for_pass = sorted(
|
||||
all_logic_steps.keys(),
|
||||
key=lambda x: int(x) if x.isdigit() else float("inf"),
|
||||
)
|
||||
except ValueError:
|
||||
sorted_uids_for_pass = sorted(all_logic_steps.keys())
|
||||
|
||||
current_logic_list = [
|
||||
all_logic_steps[uid]
|
||||
for uid in sorted_uids_for_pass
|
||||
if uid in all_logic_steps
|
||||
]
|
||||
|
||||
for i, instruction in enumerate(
|
||||
current_logic_list
|
||||
): # Usar enumerate para obtener índice
|
||||
part_uid = instruction["instruction_uid"]
|
||||
part_type = instruction["type"] # Ahora puede ser 'Call'
|
||||
|
||||
# Si es un bloque funcional (incluyendo Call) sin 'en' explícito
|
||||
if (
|
||||
part_type in functional_block_types
|
||||
and "en" not in instruction["inputs"]
|
||||
and part_uid not in processed_blocks_en_inference
|
||||
):
|
||||
inferred_en_source = None
|
||||
my_index = i # Ya tenemos el índice
|
||||
|
||||
if my_index > 0:
|
||||
for j in range(my_index - 1, -1, -1): # Buscar hacia atrás
|
||||
prev_instr = current_logic_list[j]
|
||||
prev_uid = prev_instr["instruction_uid"]
|
||||
prev_type = prev_instr["type"]
|
||||
if prev_type in rlo_generators:
|
||||
inferred_en_source = {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": prev_uid,
|
||||
"source_instruction_type": prev_type,
|
||||
"source_pin": "out",
|
||||
}
|
||||
break
|
||||
elif prev_type in functional_block_types:
|
||||
source_key_eno = (prev_uid, "eno")
|
||||
if source_key_eno in source_connections:
|
||||
inferred_en_source = {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": prev_uid,
|
||||
"source_instruction_type": prev_type,
|
||||
"source_pin": "eno",
|
||||
}
|
||||
break
|
||||
|
||||
if inferred_en_source:
|
||||
# Asegurarse de que 'instruction' se refiera al diccionario original
|
||||
all_logic_steps[part_uid]["inputs"]["en"] = inferred_en_source
|
||||
processed_blocks_en_inference.add(part_uid)
|
||||
something_changed = True
|
||||
|
||||
# --- 5. Añadir lógica ENO interesante ---
|
||||
# (Necesita usar parts_and_calls_map ahora)
|
||||
for source_instr_uid, eno_destinations in eno_outputs.items():
|
||||
if source_instr_uid not in all_logic_steps:
|
||||
continue
|
||||
interesting_eno_logic = []
|
||||
for dest_uid, dest_pin in eno_destinations:
|
||||
is_direct_en_connection = (
|
||||
dest_uid in parts_and_calls_map and dest_pin == "en"
|
||||
) # Check en mapa combinado
|
||||
if not is_direct_en_connection:
|
||||
target_info = {"target_pin": dest_pin}
|
||||
if dest_uid in parts_and_calls_map:
|
||||
target_info.update(
|
||||
{
|
||||
"target_type": "instruction",
|
||||
"target_uid": dest_uid,
|
||||
"target_name": parts_and_calls_map[dest_uid].get(
|
||||
"name", parts_and_calls_map[dest_uid].get("type")
|
||||
),
|
||||
}
|
||||
) # Usar 'name' si existe (Part) o 'type' (Call)
|
||||
elif dest_uid in access_map:
|
||||
target_info.update(
|
||||
{
|
||||
"target_type": "operand",
|
||||
"target_details": access_map[dest_uid],
|
||||
}
|
||||
)
|
||||
else:
|
||||
target_info.update(
|
||||
{"target_type": "unknown", "target_uid": dest_uid}
|
||||
)
|
||||
interesting_eno_logic.append(target_info)
|
||||
if interesting_eno_logic:
|
||||
all_logic_steps[source_instr_uid]["eno_logic"] = interesting_eno_logic
|
||||
|
||||
# --- 6. Ordenar Lógica Final y Devolver ---
|
||||
try:
|
||||
sorted_uids = sorted(
|
||||
all_logic_steps.keys(),
|
||||
key=lambda x: int(x) if x.isdigit() else float("inf"),
|
||||
)
|
||||
except ValueError:
|
||||
print(f"Advertencia: UIDs no numéricos red {network_id}. Orden alfabético.")
|
||||
sorted_uids = sorted(all_logic_steps.keys())
|
||||
network_logic = [
|
||||
all_logic_steps[uid] for uid in sorted_uids if uid in all_logic_steps
|
||||
]
|
||||
|
||||
return {
|
||||
"id": network_id,
|
||||
"title": network_title,
|
||||
"comment": network_comment,
|
||||
"logic": network_logic,
|
||||
}
|
||||
|
||||
|
||||
# --- Función Principal convert_xml_to_json (sin cambios) ---
|
||||
def convert_xml_to_json(xml_filepath, json_filepath):
|
||||
print(f"Iniciando conversión de '{xml_filepath}' a '{json_filepath}'...")
|
||||
if not os.path.exists(xml_filepath):
|
||||
print(f"Error Crítico: Archivo XML no encontrado: '{xml_filepath}'")
|
||||
return
|
||||
try:
|
||||
print("Paso 1: Parseando archivo XML...")
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(xml_filepath, parser)
|
||||
root = tree.getroot()
|
||||
print("Paso 1: Parseo XML completado.")
|
||||
print("Paso 2: Buscando el bloque SW.Blocks.FC...")
|
||||
fc_block_list = root.xpath("//*[local-name()='SW.Blocks.FC']")
|
||||
if not fc_block_list:
|
||||
print("Error Crítico: No se encontró <SW.Blocks.FC>.")
|
||||
return
|
||||
fc_block = fc_block_list[0]
|
||||
print(f"Paso 2: Bloque SW.Blocks.FC encontrado (ID={fc_block.get('ID')}).")
|
||||
print("Paso 3: Extrayendo atributos del bloque...")
|
||||
attribute_list_node = fc_block.xpath("./*[local-name()='AttributeList']")
|
||||
block_name_val, block_number_val, block_lang_val = "Unknown", None, "Unknown"
|
||||
if attribute_list_node:
|
||||
attr_list = attribute_list_node[0]
|
||||
name_node = attr_list.xpath("./*[local-name()='Name']/text()")
|
||||
block_name_val = name_node[0].strip() if name_node else block_name_val
|
||||
num_node = attr_list.xpath("./*[local-name()='Number']/text()")
|
||||
block_number_val = (
|
||||
int(num_node[0])
|
||||
if num_node and num_node[0].isdigit()
|
||||
else block_number_val
|
||||
)
|
||||
lang_node = attr_list.xpath(
|
||||
"./*[local-name()='ProgrammingLanguage']/text()"
|
||||
)
|
||||
block_lang_val = lang_node[0].strip() if lang_node else block_lang_val
|
||||
print(
|
||||
f"Paso 3: Atributos: Nombre='{block_name_val}', Número={block_number_val}, Lenguaje='{block_lang_val}'"
|
||||
)
|
||||
else:
|
||||
print("Advertencia: No se encontró AttributeList para el bloque FC.")
|
||||
block_comment_val = ""
|
||||
comment_node_list = fc_block.xpath(
|
||||
"./*[local-name()='ObjectList']/*[local-name()='MultilingualText'][@CompositionName='Comment']"
|
||||
)
|
||||
if comment_node_list:
|
||||
block_comment_val = get_multilingual_text(comment_node_list[0])
|
||||
print(f"Paso 3b: Comentario bloque: '{block_comment_val[:50]}...'")
|
||||
result = {
|
||||
"block_name": block_name_val,
|
||||
"block_number": block_number_val,
|
||||
"language": block_lang_val,
|
||||
"block_comment": block_comment_val,
|
||||
"interface": {},
|
||||
"networks": [],
|
||||
}
|
||||
print("Paso 4: Extrayendo la interfaz del bloque...")
|
||||
if attribute_list_node:
|
||||
interface_node_list = attribute_list_node[0].xpath(
|
||||
"./*[local-name()='Interface']"
|
||||
)
|
||||
if interface_node_list:
|
||||
interface_node = interface_node_list[0]
|
||||
print("Paso 4: Nodo Interface encontrado.")
|
||||
for section in interface_node.xpath(".//iface:Section", namespaces=ns):
|
||||
section_name = section.get("Name")
|
||||
members = []
|
||||
for member in section.xpath("./iface:Member", namespaces=ns):
|
||||
member_name = member.get("Name")
|
||||
member_dtype = member.get("Datatype")
|
||||
if member_name and member_dtype:
|
||||
members.append(
|
||||
{"name": member_name, "datatype": member_dtype}
|
||||
)
|
||||
if members:
|
||||
result["interface"][section_name] = members
|
||||
if not result["interface"]:
|
||||
print("Advertencia: Interface sin secciones iface:Section válidas.")
|
||||
else:
|
||||
print(
|
||||
"Advertencia: No se encontró <Interface> DENTRO de <AttributeList>."
|
||||
)
|
||||
if not result["interface"]:
|
||||
print("Advertencia: No se pudo extraer información de la interfaz.")
|
||||
|
||||
print("Paso 5: Extrayendo y PROCESANDO lógica de redes (CompileUnits)...")
|
||||
networks_processed_count = 0
|
||||
object_list_node = fc_block.xpath("./*[local-name()='ObjectList']")
|
||||
if object_list_node:
|
||||
compile_units = object_list_node[0].xpath(
|
||||
"./*[local-name()='SW.Blocks.CompileUnit']"
|
||||
)
|
||||
print(
|
||||
f"Paso 5: Se encontraron {len(compile_units)} elementos SW.Blocks.CompileUnit."
|
||||
)
|
||||
for network_elem in compile_units:
|
||||
networks_processed_count += 1
|
||||
# print(f"DEBUG: Procesando red #{networks_processed_count} (ID={network_elem.get('ID')})...")
|
||||
parsed_network = parse_network(
|
||||
network_elem
|
||||
) # Llamada a la función modificada
|
||||
if parsed_network and parsed_network.get("error") is None:
|
||||
result["networks"].append(parsed_network)
|
||||
elif parsed_network:
|
||||
print(
|
||||
f"Error: Falló parseo red ID={parsed_network.get('id')}: {parsed_network.get('error')}"
|
||||
)
|
||||
result["networks"].append(parsed_network)
|
||||
else:
|
||||
print(
|
||||
f"Error: parse_network devolvió None para CompileUnit (ID={network_elem.get('ID')})."
|
||||
)
|
||||
if networks_processed_count == 0:
|
||||
print("Advertencia: ObjectList sin SW.Blocks.CompileUnit.")
|
||||
else:
|
||||
print("Advertencia: No se encontró ObjectList.")
|
||||
|
||||
print("Paso 6: Escribiendo el resultado en el archivo JSON...")
|
||||
if not result["interface"]:
|
||||
print("ADVERTENCIA FINAL: 'interface' está vacía.")
|
||||
if not result["networks"]:
|
||||
print("ADVERTENCIA FINAL: 'networks' está vacía.")
|
||||
# else: # Chequeo ENO logic
|
||||
# eno_logic_found = any(instr.get('eno_logic') for net in result.get('networks', []) if net.get('error') is None for instr in net.get('logic', []))
|
||||
# if eno_logic_found: print("INFO FINAL: Lógica ENO interesante detectada.")
|
||||
# else: print("INFO FINAL: No se detectó lógica ENO interesante.")
|
||||
|
||||
try:
|
||||
with open(json_filepath, "w", encoding="utf-8") as f:
|
||||
json.dump(result, f, indent=4, ensure_ascii=False)
|
||||
print(f"Paso 6: Escritura completada.")
|
||||
print(f"Conversión finalizada. JSON guardado en: '{json_filepath}'")
|
||||
except IOError as e:
|
||||
print(
|
||||
f"Error Crítico: No se pudo escribir JSON en '{json_filepath}'. Error: {e}"
|
||||
)
|
||||
except TypeError as e:
|
||||
print(f"Error Crítico: Problema al serializar a JSON. Error: {e}")
|
||||
|
||||
except etree.XMLSyntaxError as e:
|
||||
print(f"Error Crítico: Sintaxis XML en '{xml_filepath}'. Detalles: {e}")
|
||||
except Exception as e:
|
||||
print(f"Error Crítico: Error inesperado: {e}")
|
||||
print("--- Traceback ---")
|
||||
traceback.print_exc()
|
||||
print("--- Fin Traceback ---")
|
||||
|
||||
|
||||
# --- Punto de Entrada Principal ---
|
||||
if __name__ == "__main__":
|
||||
xml_file = "BlenderCtrl__Main.xml" # CAMBIAR AL NUEVO ARCHIVO XML
|
||||
json_file = xml_file.replace(
|
||||
".xml", "_simplified.json"
|
||||
) # Nombre de salida dinámico
|
||||
convert_xml_to_json(xml_file, json_file)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,208 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
# --- Helper Functions ---
|
||||
|
||||
def format_variable_name(name):
|
||||
"""Limpia el nombre de la variable quitando comillas y espacios."""
|
||||
if not name:
|
||||
return "_INVALID_NAME_"
|
||||
# Quita comillas dobles iniciales/finales
|
||||
name = name.strip('"')
|
||||
# Reemplaza comillas dobles internas y puntos por guión bajo
|
||||
name = name.replace('"."', '_').replace('.', '_')
|
||||
# Quita comillas restantes (si las hubiera)
|
||||
name = name.replace('"', '')
|
||||
# Asegurarse de que no empiece con número (aunque raro con comillas iniciales)
|
||||
if name and name[0].isdigit():
|
||||
name = "_" + name
|
||||
return name
|
||||
|
||||
def generate_scl(processed_json_filepath, output_scl_filepath):
|
||||
"""Genera un archivo SCL a partir del JSON procesado."""
|
||||
|
||||
if not os.path.exists(processed_json_filepath):
|
||||
print(f"Error: Archivo JSON procesado no encontrado en '{processed_json_filepath}'")
|
||||
return
|
||||
|
||||
print(f"Cargando JSON procesado desde: {processed_json_filepath}")
|
||||
try:
|
||||
with open(processed_json_filepath, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"Error al cargar o parsear JSON: {e}")
|
||||
return
|
||||
|
||||
# --- Extracción de Información del Bloque ---
|
||||
block_name = data.get('block_name', 'UnknownBlock')
|
||||
block_number = data.get('block_number')
|
||||
block_lang = data.get('language', 'LAD') # Lenguaje original
|
||||
block_comment = data.get('block_comment', '')
|
||||
|
||||
# Limpiar nombre del bloque para usarlo en SCL
|
||||
scl_block_name = format_variable_name(block_name)
|
||||
print(f"Generando SCL para el bloque: {scl_block_name} (Original: {block_name})")
|
||||
|
||||
# --- Identificación de Variables Temporales y Estáticas ---
|
||||
temp_vars = set()
|
||||
stat_vars = set() # Para flancos, si se implementan completamente
|
||||
# Usar regex para encontrar variables _temp_... y stat_...
|
||||
temp_pattern = re.compile(r'"?(_temp_[a-zA-Z0-9_]+)"?')
|
||||
stat_pattern = re.compile(r'"?(stat_[a-zA-Z0-9_]+)"?')
|
||||
|
||||
for network in data.get('networks', []):
|
||||
for instruction in network.get('logic', []):
|
||||
scl_code = instruction.get('scl', '')
|
||||
if scl_code:
|
||||
# Buscar temporales en el código SCL generado
|
||||
found_temps = temp_pattern.findall(scl_code)
|
||||
for temp_name in found_temps:
|
||||
temp_vars.add(temp_name) # Añadir al set (evita duplicados)
|
||||
# Buscar estáticas (para flancos)
|
||||
found_stats = stat_pattern.findall(scl_code)
|
||||
for stat_name in found_stats:
|
||||
stat_vars.add(stat_name)
|
||||
|
||||
print(f"Variables temporales detectadas: {len(temp_vars)}")
|
||||
# print(f"Variables estáticas detectadas (para flancos): {len(stat_vars)}")
|
||||
|
||||
# --- Construcción del String SCL ---
|
||||
scl_output = []
|
||||
|
||||
# Cabecera del Bloque
|
||||
scl_output.append(f"// Block Name (Original): {block_name}")
|
||||
if block_number:
|
||||
scl_output.append(f"// Block Number: {block_number}")
|
||||
scl_output.append(f"// Original Language: {block_lang}")
|
||||
if block_comment:
|
||||
scl_output.append(f"// Block Comment: {block_comment}")
|
||||
scl_output.append("")
|
||||
scl_output.append(f"FUNCTION_BLOCK \"{scl_block_name}\"") # Asumir FB por variables Temp/Stat
|
||||
scl_output.append("{ S7_Optimized_Access := 'TRUE' }") # Opcional, común
|
||||
scl_output.append("VERSION : 0.1") # Opcional
|
||||
scl_output.append("")
|
||||
|
||||
# Declaraciones de Interfaz
|
||||
scl_output.append("VAR_INPUT")
|
||||
# Iterar sobre data['interface']['Input'] si existe
|
||||
# for var in data.get('interface', {}).get('Input', []):
|
||||
# scl_output.append(f" {format_variable_name(var['name'])} : {var['datatype']};")
|
||||
scl_output.append("END_VAR")
|
||||
scl_output.append("")
|
||||
|
||||
scl_output.append("VAR_OUTPUT")
|
||||
# Iterar sobre data['interface']['Output'] si existe
|
||||
# for var in data.get('interface', {}).get('Output', []):
|
||||
# scl_output.append(f" {format_variable_name(var['name'])} : {var['datatype']};")
|
||||
scl_output.append("END_VAR")
|
||||
scl_output.append("")
|
||||
|
||||
scl_output.append("VAR_IN_OUT")
|
||||
# Iterar sobre data['interface']['InOut'] si existe
|
||||
# for var in data.get('interface', {}).get('InOut', []):
|
||||
# scl_output.append(f" {format_variable_name(var['name'])} : {var['datatype']};")
|
||||
scl_output.append("END_VAR")
|
||||
scl_output.append("")
|
||||
|
||||
# Declaraciones Estáticas (para flancos)
|
||||
if stat_vars:
|
||||
scl_output.append("VAR_STAT")
|
||||
# Asumir Bool para flancos, se podría inferir mejor si PBox lo indicara
|
||||
for var_name in sorted(list(stat_vars)):
|
||||
scl_output.append(f" \"{var_name}\" : Bool; // Memory for edge detection")
|
||||
scl_output.append("END_VAR")
|
||||
scl_output.append("")
|
||||
|
||||
# Declaraciones Temporales
|
||||
# Incluir las variables de la sección Temp del JSON original
|
||||
# y las generadas automáticamente (_temp_...)
|
||||
scl_output.append("VAR_TEMP")
|
||||
declared_temps = set()
|
||||
interface_temps = data.get('interface', {}).get('Temp', [])
|
||||
if interface_temps:
|
||||
for var in interface_temps:
|
||||
formatted_name = format_variable_name(var['name'])
|
||||
# Añadir comillas si el nombre original las tenía o si contiene caracteres especiales
|
||||
scl_name = f'"{formatted_name}"' if '"' in var['name'] or '.' in var['name'] else formatted_name
|
||||
scl_output.append(f" {scl_name} : {var['datatype']};")
|
||||
declared_temps.add(scl_name) # Marcar como declarada
|
||||
|
||||
# Declarar las _temp_ generadas si no estaban ya en la interfaz Temp
|
||||
if temp_vars:
|
||||
# Intentar inferir tipo (difícil sin más info), por ahora usar Variant o Bool/DInt
|
||||
for var_name in sorted(list(temp_vars)):
|
||||
scl_name = f'"{var_name}"' # Asegurar comillas para _temp_
|
||||
if scl_name not in declared_temps:
|
||||
# Inferencia básica de tipo por nombre de pin (muy heurístico)
|
||||
inferred_type = "Variant" # Tipo seguro por defecto
|
||||
if var_name.endswith("_out"): # Salida de bloque lógico/comparación?
|
||||
inferred_type = "Bool"
|
||||
elif var_name.endswith("_out_num"): # Salida de bloque numérico?
|
||||
inferred_type = "DInt" # O Real? O Int? Difícil saber
|
||||
# Se podría mejorar si los procesadores añadieran info de tipo
|
||||
scl_output.append(f" {scl_name} : {inferred_type}; // Auto-generated temporary")
|
||||
declared_temps.add(scl_name) # Marcar como declarada
|
||||
scl_output.append("END_VAR")
|
||||
scl_output.append("")
|
||||
|
||||
# Cuerpo del Bloque
|
||||
scl_output.append("BEGIN")
|
||||
scl_output.append("")
|
||||
|
||||
# Iterar por redes y lógica
|
||||
for i, network in enumerate(data.get('networks', [])):
|
||||
network_title = network.get('title', f'Network {network.get("id")}')
|
||||
network_comment = network.get('comment', '')
|
||||
scl_output.append(f" // Network {i+1}: {network_title}")
|
||||
if network_comment:
|
||||
# Añadir comentario de red indentado
|
||||
for line in network_comment.splitlines():
|
||||
scl_output.append(f" // {line}")
|
||||
scl_output.append("") # Línea en blanco antes del código de la red
|
||||
|
||||
network_has_code = False
|
||||
for instruction in network.get('logic', []):
|
||||
scl_code = instruction.get('scl')
|
||||
if scl_code:
|
||||
network_has_code = True
|
||||
# Indentar y añadir el código SCL de la instrucción
|
||||
# Quitar comentarios "// RLO updated..." o "// Comparison..."
|
||||
# ya que el código SCL resultante es la representación final.
|
||||
# Mantener comentarios de PBox por claridad.
|
||||
is_rlo_update_comment = scl_code.strip().startswith("// RLO updated")
|
||||
is_comparison_comment = scl_code.strip().startswith("// Comparison")
|
||||
is_logic_o_comment = scl_code.strip().startswith("// Logic O")
|
||||
|
||||
if not (is_rlo_update_comment or is_comparison_comment or is_logic_o_comment) or "PBox" in scl_code :
|
||||
for line in scl_code.splitlines():
|
||||
scl_output.append(f" {line}") # Indentación de 2 espacios
|
||||
|
||||
if network_has_code:
|
||||
scl_output.append("") # Añadir línea en blanco después del código de la red
|
||||
|
||||
scl_output.append("END_FUNCTION_BLOCK")
|
||||
|
||||
# --- Escritura del Archivo SCL ---
|
||||
print(f"Escribiendo archivo SCL en: {output_scl_filepath}")
|
||||
try:
|
||||
with open(output_scl_filepath, 'w', encoding='utf-8') as f:
|
||||
for line in scl_output:
|
||||
f.write(line + '\n')
|
||||
print("Generación de SCL completada.")
|
||||
except Exception as e:
|
||||
print(f"Error al escribir el archivo SCL: {e}")
|
||||
|
||||
# --- Ejecución ---
|
||||
if __name__ == "__main__":
|
||||
|
||||
xml_file = "BlenderCtrl__Main.xml" # CAMBIAR AL NUEVO ARCHIVO XML
|
||||
input_json_file = xml_file.replace(
|
||||
".xml", "_simplified_processed.json"
|
||||
) # Nombre de salida dinámico
|
||||
output_scl_file = input_json_file.replace(
|
||||
".json", ".scl"
|
||||
) # Nombre de salida dinámico
|
||||
|
||||
generate_scl(input_json_file, output_scl_file)
|
Loading…
Reference in New Issue