Diff of /PlcOpenXmlLadderToAsciiLadder.py [000000] .. [9bc435]  Maximize  Restore

Switch to unified view

a b/PlcOpenXmlLadderToAsciiLadder.py
1
# PlcOpenXmlLadderToAsciiLadder
2
import sys
3
import xml.dom.minidom
4
5
def howCloseAmIToLeftPowerRail(num, ladder, element):
6
    # Function to work out how close an element is to the left...
7
    # element is a dom element of contact, coil, block
8
    # ladder is the whole ladder
9
    # num is the current distance, initially zero
10
    if element.tagName == "contact" or element.tagName == "coil" or element.tagName == "leftPowerRail":
11
        _num = num + 1
12
    else: # "block", maybe "execute"?
13
        _num = num + 3
14
    highestnum = _num
15
    for conny in element.getElementsByTagName("connection"):
16
        for _elly in ladder.childNodes:
17
            if _elly.nodeType != _elly.TEXT_NODE:
18
                if _elly.getAttribute("localId") == conny.getAttribute("refLocalId"):
19
                    # pass how close this element is
20
                    connysNum = howCloseAmIToLeftPowerRail(_num, ladder, _elly)
21
        if connysNum > highestnum:
22
            highestnum = connysNum
23
    return highestnum
24
25
# main
26
if len(sys.argv) == 2:
27
    filepathin = sys.argv[1]
28
    print(filepathin)
29
    doc = xml.dom.minidom.parse(filepathin)
30
    # get the first (currently only) entire declaration header as a string
31
    declarationheader = doc.getElementsByTagName("InterfaceAsPlainText")[0].getElementsByTagName("xhtml")[0].childNodes[0].data
32
    
33
    # get the first (currently only) ladder element
34
    ladder = doc.getElementsByTagName("LD")[0]
35
    widthOfLadder = 4 # will grow by itself if the ladder needs it
36
    foundANewLabel = False
37
    networkNumber = 0
38
    rowId = 0
39
  
40
    gridladder = xml.dom.minidom.Document()
41
    gridladder.appendChild(gridladder.createElement("gridLD"))
42
  
43
    for elly in ladder.childNodes:
44
        #Close a branch
45
        #     <contact>
46
        #        <connectionPointIn>
47
        #          <connection refLocalId="39" />
48
        #          <connection refLocalId="40" />
49
        #        </connectionPointIn>
50
        #Open a branch
51
        #      <contact >        
52
        #        <connectionPointIn>
53
        #          <connection refLocalId="0" />
54
        #        </connectionPointIn>
55
        #      </contact>
56
        #      <contact >
57
        #        <connectionPointIn>
58
        #          <connection refLocalId="0" />
59
        #        </connectionPointIn>
60
        #leftPowerRail
61
        #comment
62
        #label
63
        if elly.nodeName == "label":
64
            print(elly.getAttribute("label"))
65
            # create new <row>, add this label to the zeroth column
66
            networkNumber += 1
67
            gridladder.firstChild.appendChild(gridladder.createElement("row"))
68
            gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
69
            rowId += 1
70
            gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
71
            gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","0")
72
            gridladder.firstChild.lastChild.lastChild.setAttribute("networkId",str(networkNumber))
73
            gridladder.firstChild.lastChild.lastChild.setAttribute("label",elly.getAttribute("label"))
74
            foundANewLabel = True
75
        #vendorElement  (both new network and parallel branches)
76
        if elly.nodeName == "vendorElement":
77
            if elly.getElementsByTagName("ElementType").length > 0:
78
                print("NewNetwork")
79
                if foundANewLabel:# already found a label
80
                    foundANewLabel = False
81
                else:
82
                    networkNumber += 1
83
                    gridladder.firstChild.appendChild(gridladder.createElement("row"))
84
                    gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
85
                    rowId += 1
86
                    
87
                    gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
88
                    gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","0")
89
                    gridladder.firstChild.lastChild.lastChild.setAttribute("networkId",str(networkNumber))
90
            elif elly.getElementsByTagName("ParallelBranch"):
91
                print("New ParallelBranch Short Circuit")
92
        #inVariable (these are your inputs to blocks)
93
        if elly.nodeName == "inVariable":
94
            print("NewInvariable")
95
        #block (FB, F etc)
96
        if elly.nodeName == "block":
97
            print("NewBlock")
98
            mydistance = howCloseAmIToLeftPowerRail(0,ladder,elly)
99
            if mydistance > widthOfLadder:
100
                widthOfLadder = mydistance
101
  
102
            if elly.getElementsByTagName("connection")[0].getAttribute("refLocalId") == "0":
103
                # that means it's leftmost object
104
                if gridladder.firstChild.lastChild.lastChild.getAttribute("columnId") != "0":
105
                    # that means we parallel branch and need a new row
106
                    gridladder.firstChild.appendChild(gridladder.createElement("row"))
107
                    gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
108
                    rowId += 1
109
                gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
110
                gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","1")
111
                gridladder.firstChild.lastChild.lastChild.setAttribute("localId",elly.getAttribute("localId"))
112
                gridladder.firstChild.lastChild.lastChild.setAttribute("width","3")
113
            else: # that means it points behind another object
114
                highestRowId = "65535"
115
                widestColumn = "0"
116
                for ellysUpstream in elly.getElementsByTagName("connection"):
117
                    # may be more than one upstream. 
118
                    # The first downstream will be in the highest row of the upstream and one column back from the furthest back upstream
119
                    ellysUpstreamId = ellysUpstream.getAttribute("refLocalId")
120
                    for gridellys in gridladder.firstChild.getElementsByTagName("Column"):
121
                        if gridellys.getAttribute("localId") == ellysUpstreamId:
122
                            if highestRowId > gridellys.parentNode.getAttribute("rowId"):
123
                                highestRowId = gridellys.parentNode.getAttribute("rowId")
124
                                highestRow = gridellys.parentNode
125
                            widestColumn = max(widestColumn, str(int(gridellys.getAttribute("columnId")) + int(gridellys.getAttribute("width"))))
126
                # Is there anyone at that RowColumn?
127
                someoneIsThereAlready = False
128
                for existingColumns in highestRow.getElementsByTagName("Column"):
129
                    if existingColumns.getAttribute("columnId") >= widestColumn:
130
                        someoneIsThereAlready = True
131
                if not someoneIsThereAlready :
132
                    highestRow.appendChild(gridladder.createElement("Column"))
133
                    highestRow.lastChild.setAttribute("columnId",widestColumn)
134
                    highestRow.lastChild.setAttribute("localId",elly.getAttribute("localId"))
135
                    highestRow.lastChild.setAttribute("width","3")
136
                # TODO Do something else if someone is already there
137
                # TODO You will have to flag that it is parallel
138
        #contact
139
        if elly.nodeName == "contact":
140
            if elly.getAttribute("negated") == "true":
141
                print("NewNegatedContact")
142
            else:
143
                print("NewContact")
144
  
145
            mydistance = howCloseAmIToLeftPowerRail(0,ladder,elly)
146
            if mydistance > widthOfLadder:
147
                widthOfLadder = mydistance
148
  
149
            if elly.getElementsByTagName("connection")[0].getAttribute("refLocalId") == "0":
150
                # that means it's leftmost object
151
                if gridladder.firstChild.lastChild.lastChild.getAttribute("columnId") != "0":
152
                    # that means we parallel branch and need a new row
153
                    gridladder.firstChild.appendChild(gridladder.createElement("row"))
154
                    gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
155
                    rowId += 1
156
                gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
157
                gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","1")
158
                gridladder.firstChild.lastChild.lastChild.setAttribute("localId",elly.getAttribute("localId"))
159
                gridladder.firstChild.lastChild.lastChild.setAttribute("width","1")
160
            else: # that means it points behind another object
161
                highestRowId = "65535"
162
                widestColumn = "0"
163
                for ellysUpstream in elly.getElementsByTagName("connection"):
164
                    # may be more than one upstream. 
165
                    # The first downstream will be in the highest row of the upstream and one column back from the furthest back upstream
166
                    ellysUpstreamId = ellysUpstream.getAttribute("refLocalId")
167
                    for gridellys in gridladder.firstChild.getElementsByTagName("Column"):
168
                        if gridellys.getAttribute("localId") == ellysUpstreamId:
169
                            if highestRowId > gridellys.parentNode.getAttribute("rowId"):
170
                                highestRowId = gridellys.parentNode.getAttribute("rowId")
171
                                highestRow = gridellys.parentNode
172
                            widestColumn = max(widestColumn, str(int(gridellys.getAttribute("columnId")) + int(gridellys.getAttribute("width"))))
173
                # Is there anyone at that RowColumn?
174
                someoneIsThereAlready = False
175
                for existingColumns in highestRow.getElementsByTagName("Column"):
176
                    if existingColumns.getAttribute("columnId") >= widestColumn:
177
                        someoneIsThereAlready = True
178
                if not someoneIsThereAlready :
179
                    highestRow.appendChild(gridladder.createElement("Column"))
180
                    highestRow.lastChild.setAttribute("columnId",widestColumn)
181
                    highestRow.lastChild.setAttribute("localId",elly.getAttribute("localId"))
182
                    highestRow.lastChild.setAttribute("width","1")
183
                # TODO Do something else if someone is already there
184
                # TODO You will have to flag that it is parallel
185
186
187
  
188
        #coil
189
        if elly.nodeName == "coil":
190
            if elly.getAttribute("storage") == "none":
191
                print("NewCoil")
192
            elif elly.getAttribute("storage") == "set":
193
                print("NewSetCoil")
194
            elif elly.getAttribute("storage") == "reset":
195
                print("NewResetCoil")
196
            
197
            mydistance = howCloseAmIToLeftPowerRail(0,ladder,elly)
198
            if mydistance > widthOfLadder:
199
                widthOfLadder = mydistance
200
  
201
            if elly.getElementsByTagName("connection")[0].getAttribute("refLocalId") == "0":
202
                # that means it's leftmost object
203
                if gridladder.firstChild.lastChild.lastChild.getAttribute("columnId") != "0":
204
                    # that means we parallel branch and need a new row
205
                    gridladder.firstChild.appendChild(gridladder.createElement("row"))
206
                    gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
207
                    rowId += 1
208
                gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
209
                gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","1")
210
                gridladder.firstChild.lastChild.lastChild.setAttribute("localId",elly.getAttribute("localId"))
211
                gridladder.firstChild.lastChild.lastChild.setAttribute("width","1")
212
            else: # that means it points behind another object
213
                highestRowId = "65535"
214
                widestColumn = "0"
215
                for ellysUpstream in elly.getElementsByTagName("connection"):
216
                    # may be more than one upstream. 
217
                    # The first downstream will be in the highest row of the upstream and one column back from the furthest back upstream
218
                    ellysUpstreamId = ellysUpstream.getAttribute("refLocalId")
219
                    for gridellys in gridladder.firstChild.getElementsByTagName("Column"):
220
                        if gridellys.getAttribute("localId") == ellysUpstreamId:
221
                            if highestRowId > gridellys.parentNode.getAttribute("rowId"):
222
                                highestRowId = gridellys.parentNode.getAttribute("rowId")
223
                                highestRow = gridellys.parentNode
224
                            widestColumn = max(widestColumn, str(int(gridellys.getAttribute("columnId")) + int(gridellys.getAttribute("width"))))
225
                # Is there anyone at that RowColumn?
226
                someoneIsThereAlready = False
227
                for existingColumns in highestRow.getElementsByTagName("Column"):
228
                    if existingColumns.getAttribute("columnId") >= widestColumn:
229
                        someoneIsThereAlready = True
230
                if not someoneIsThereAlready :
231
                    highestRow.appendChild(gridladder.createElement("Column"))
232
                    highestRow.lastChild.setAttribute("columnId",widestColumn)
233
                    highestRow.lastChild.setAttribute("localId",elly.getAttribute("localId"))
234
                    highestRow.lastChild.setAttribute("width","1")
235
                # TODO Do something else if someone is already there
236
                # TODO You will have to flag that it is parallel
237
238
        #rightPowerRail (think CODESYS were having a laugh)
239
    # How wide to make network? well:
240
    # 1. contacts and coils = 1
241
    # 2. blocks and executes = 3
242
    # 3. branches themselves don't take up additional room
243
    # 4. but... you have to work out the longest path on each branch
244
    # Data is presented localId + refLocalId [+ refLocalId + ...]
245
    # So I guess it is easiest to work our way backwards.  (from right to left)
246
    # We will naïvely look at every localId and how long it takes to get back to refLocalId=0
247
    # We also naïvely look at every possible localId, even if we've already found him
248
    # We've actually already calculated that above, yay for me!
249
    print(widthOfLadder)
250
  
251
    # Array of networks
252
    # Network is an array of Contact / Block / Coil
253
    # So we know it is (widthOfLadder) wide... so we could have an array.. no that's not right
254
    # 1. Pass through every element
255
    # 2. hmm, lets make a new ladder xml, which is the rows... input variables and labels can be added last
256
    # 3. <Row>
257
    #       <Column columnId="0" refLocalId=(localID of vendorElement new network) />
258
    #       <Column columnId="1" refLocalId=(localID of next contact/block/coil) />
259
    # 4. The next element comes in. It asks if anybody already has the row right behind its refLocalId
260
    #     If someone is already there, it starts a new Row, starting at the columnId just behind
261
    # 5. If it has two refLocalIds, it tries to get the furthest back column
262
    print (str(gridladder.toprettyxml()))
263
  
264
    # should now have a declaration section
265
    # a bunch of inputs
266
    # a bunch of outputs
267
    # and a bunch of blocks
268
    # convert them all to a nice easy format
269
    print ("{Declaration}")
270
    print (declarationheader)
271
    print ("{/Declaration}")
272
else:
273
    print("Maybe I want one argument, whch is the PLCOPEN XML.")
274
    print("Will output to current directory as Ladder0.ladder")
275