ladder_drive 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/Gemfile +8 -0
  4. data/Gemfile.lock +41 -0
  5. data/LICENSE +21 -0
  6. data/README.md +191 -0
  7. data/README_jp.md +193 -0
  8. data/Rakefile +9 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/exe/ladder_drive +28 -0
  12. data/ladder_drive.gemspec +33 -0
  13. data/lib/ladder_drive/asm.rb +211 -0
  14. data/lib/ladder_drive/cli.rb +55 -0
  15. data/lib/ladder_drive/config.rb +107 -0
  16. data/lib/ladder_drive/config_target.rb +93 -0
  17. data/lib/ladder_drive/console.rb +113 -0
  18. data/lib/ladder_drive/intel_hex.rb +79 -0
  19. data/lib/ladder_drive/ladder_drive.rb +36 -0
  20. data/lib/ladder_drive/plc_define.rb +35 -0
  21. data/lib/ladder_drive/plc_device.rb +171 -0
  22. data/lib/ladder_drive/protocol/emulator/emu_protocol.rb +54 -0
  23. data/lib/ladder_drive/protocol/emulator/emulator.rb +29 -0
  24. data/lib/ladder_drive/protocol/keyence/keyence.rb +31 -0
  25. data/lib/ladder_drive/protocol/keyence/kv_device.rb +51 -0
  26. data/lib/ladder_drive/protocol/keyence/kv_protocol.rb +187 -0
  27. data/lib/ladder_drive/protocol/mitsubishi/mc_protocol.rb +268 -0
  28. data/lib/ladder_drive/protocol/mitsubishi/mitsubishi.rb +30 -0
  29. data/lib/ladder_drive/protocol/mitsubishi/qdevice.rb +114 -0
  30. data/lib/ladder_drive/protocol/protocol.rb +107 -0
  31. data/lib/ladder_drive/tasks/build.rb +101 -0
  32. data/lib/ladder_drive/uploader.rb +101 -0
  33. data/lib/ladder_drive/version.rb +26 -0
  34. data/lib/ladder_drive.rb +32 -0
  35. data/lib/plc/LICENSE +21 -0
  36. data/lib/plc/emulator/emu_device.rb +121 -0
  37. data/lib/plc/emulator/emu_plc.rb +482 -0
  38. data/lib/plc/emulator/emu_plc_server.rb +71 -0
  39. data/lib/plc/emulator/emulator.rb +28 -0
  40. data/lib/plc/keyence/kv/kv-5000/DocumentWindowInfo.xml +91 -0
  41. data/lib/plc/keyence/kv/kv-5000/KvsMon.ini +0 -0
  42. data/lib/plc/keyence/kv/kv-5000/LadderDrive.mod +0 -0
  43. data/lib/plc/keyence/kv/kv-5000/LbkMdm.ini +0 -0
  44. data/lib/plc/keyence/kv/kv-5000/Main.mod +0 -0
  45. data/lib/plc/keyence/kv/kv-5000/MonEnv.kmu +1 -0
  46. data/lib/plc/keyence/kv/kv-5000/PlcSended.dky +0 -0
  47. data/lib/plc/keyence/kv/kv-5000/SensorMonitorInfo.xml +4 -0
  48. data/lib/plc/keyence/kv/kv-5000/TransInfo.tif +0 -0
  49. data/lib/plc/keyence/kv/kv-5000/UnitSet.ue2 +0 -0
  50. data/lib/plc/keyence/kv/kv-5000/UnitSet.ue2.old +0 -0
  51. data/lib/plc/keyence/kv/kv-5000/WsTreeEnv.xml +28 -0
  52. data/lib/plc/keyence/kv/kv-5000/kv-5000.cm1 +0 -0
  53. data/lib/plc/keyence/kv/kv-5000/kv-5000.cm2 +0 -0
  54. data/lib/plc/keyence/kv/kv-5000/kv-5000.ftc +0 -0
  55. data/lib/plc/keyence/kv/kv-5000/kv-5000.kpr +0 -0
  56. data/lib/plc/keyence/kv/kv-5000/kv-5000.lbl +0 -0
  57. data/lib/plc/keyence/kv/kv-5000/kv-5000.mil +0 -0
  58. data/lib/plc/keyence/kv/kv-5000/kv-5000.spl +0 -0
  59. data/lib/plc/keyence/kv/kv-5000/operand-history.txt +16 -0
  60. data/lib/plc/keyence/kv/kv-5000/sample.al2 +2 -0
  61. data/lib/plc/mitsubishi/iq-r/r08/r08.gx3 +0 -0
  62. data/lib/plc/plc.rb +27 -0
  63. data/sample/ladder_drive/sample1.esc +4 -0
  64. data/sample/ladder_drive/sample2.esc +28 -0
  65. data/sample/ladder_drive/sample2.png +0 -0
  66. data/template/escalator/config/plc.yml +27 -0
  67. data/template/ladder_drive/Rakefile +1 -0
  68. data/template/ladder_drive/asm/main.esc +70 -0
  69. data/template/ladder_drive/config/plc.yml +27 -0
  70. metadata +174 -0
@@ -0,0 +1,482 @@
1
+ #
2
+ # Copyright (c) 2016 ITO SOFT DESIGN Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'ladder_drive/plc_device'
24
+
25
+ include LadderDrive
26
+
27
+ module Plc
28
+ module Emulator
29
+
30
+ class EmuPlc
31
+
32
+ attr_accessor :program_data
33
+ attr_reader :program_pointer
34
+ attr_reader :device_dict
35
+ attr_reader :errors
36
+
37
+ SUFFIXES = %w(x y m c t l sc cc tc d cs ts h sd)
38
+
39
+ SUFFIXES.each do |k|
40
+ attr_reader :"#{k}_devices"
41
+ end
42
+
43
+ STOP_PLC_FLAG = 2 # bit 1
44
+ CLEAR_PROGRAM_FLAG = 4 # bit 2 require bit 1 on
45
+
46
+ CYCLE_RUN_FLAG = 2
47
+
48
+ INDEX_BIT_STACK_COUNT = 4
49
+ INDEX_BIT_STACK = 5
50
+ SIZE_OF_BIT_STACK = 3
51
+
52
+ def initialize
53
+ SUFFIXES.each do |k|
54
+ eval "@#{k}_devices = []"
55
+ end
56
+ @lock = Mutex.new
57
+ reset
58
+ end
59
+
60
+ def device_by_name name
61
+ @lock.synchronize {
62
+ d = device_dict[name]
63
+ unless d
64
+ d = EmuDevice.new name
65
+ device_dict[name] = d
66
+ end
67
+ d
68
+ }
69
+ end
70
+
71
+ def device_by_type_and_number type, number
72
+ d = EmuDevice.new type, number
73
+ device_by_name d.name
74
+ end
75
+
76
+ def reset
77
+ @word = 0
78
+ @program_data = []
79
+ @device_dict ||= {}
80
+ @lock.synchronize {
81
+ @device_dict.values.each do |d|
82
+ d.reset
83
+ end
84
+ }
85
+ end
86
+
87
+ def run_cycle
88
+ status_to_plc = device_by_name "SD0"
89
+ status_form_plc = device_by_name "SD1"
90
+ sync_input
91
+ case status_to_plc.value & (STOP_PLC_FLAG | CLEAR_PROGRAM_FLAG)
92
+ when STOP_PLC_FLAG
93
+ status_form_plc.value = 0
94
+ sleep 0.1
95
+ when STOP_PLC_FLAG | CLEAR_PROGRAM_FLAG
96
+ reset
97
+ status_form_plc.value = CLEAR_PROGRAM_FLAG
98
+ sleep 0.1
99
+ when 0
100
+ status_form_plc.value = CYCLE_RUN_FLAG
101
+ @program_pointer = 0
102
+ clear_stacks
103
+ while fetch_and_execution; end
104
+ sleep 0.0001
105
+ else
106
+ sleep 0.1
107
+ end
108
+ sync_output
109
+ end
110
+
111
+ def bool
112
+ (stack_device.word & 1) != 0 ? true : false
113
+ end
114
+
115
+ def bool= value
116
+ if value
117
+ stack_device.word |= 1
118
+ else
119
+ stack_device.word &= 0xfffe;
120
+ end
121
+ end
122
+
123
+ def run
124
+ Thread.new do
125
+ loop do
126
+ run_cycle
127
+ end
128
+ end
129
+ end
130
+
131
+ def execute_console_commands line
132
+ a = line.chomp.split(/\s+/)
133
+ case a.first
134
+ when /^ST/i
135
+ d = device_by_name a[1]
136
+ d.set_value true, :in
137
+ "OK\r"
138
+ when /^RS/i
139
+ d = device_by_name a[1]
140
+ d.set_value false, :in
141
+ "OK\r"
142
+ when /^RDS/i
143
+ d = device_by_name a[1]
144
+ c = a[2].to_i
145
+ r = []
146
+ if d.bit_device?
147
+ c.times do
148
+ r << (d.bool(:out) ? 1 : 0)
149
+ d = device_by_name (d+1).name
150
+ end
151
+ else
152
+ case d.suffix
153
+ when "PRG"
154
+ c.times do
155
+ r << program_data[d.number * 2, 2].pack("c*").unpack("n").first
156
+ d = device_by_name (d+1).name
157
+ end
158
+ else
159
+ c.times do
160
+ r << d.word(:out)
161
+ d = device_by_name (d+1).name
162
+ end
163
+ end
164
+ end
165
+ r.map{|e| e.to_s}.join(" ") + "\r"
166
+ when /^WRS/i
167
+ d = device_by_name a[1]
168
+ c = a[2].to_i
169
+ case d.suffix
170
+ when "PRG"
171
+ a[3, c].each do |v|
172
+ program_data[d.number * 2, 2] = [v.to_i].pack("n").unpack("c*")
173
+ d = device_by_name (d+1).name
174
+ end
175
+ else
176
+ if d.bit_device?
177
+ a[3, c].each do |v|
178
+ d.set_value v == "0" ? false : true, :in
179
+ d = device_by_name (d+1).name
180
+ end
181
+ else
182
+ a[3, c].each do |v|
183
+ d.word = v.to_i
184
+ d.set_value v.to_i, :in
185
+ d = device_by_name (d+1).name
186
+ end
187
+ end
188
+ end
189
+ "OK\r"
190
+ when /E/
191
+ eval(a[1..-1].join(" ")).inspect
192
+ else
193
+ raise "Unknown command #{a.first}"
194
+ end
195
+ end
196
+
197
+ private
198
+
199
+ # ----------------
200
+ # stack operations
201
+ def stack_device index=0
202
+ device_by_name (device_by_name("SD0") + INDEX_BIT_STACK + index).name
203
+ end
204
+
205
+ def stack_count_device
206
+ device_by_name (device_by_name("SD0") + INDEX_BIT_STACK_COUNT).name
207
+ end
208
+
209
+ def push_stack flag = false
210
+ stack_device.word <<= 1
211
+ if flag
212
+ stack_device.word |= 1
213
+ else
214
+ stack_device.word &= 0xfffe
215
+ end
216
+ stack_device.word &= 0xffff
217
+ end
218
+
219
+ def pop_stack
220
+ stack_device.word >>= 1
221
+ stack_device.word |= 0x8000
222
+ end
223
+
224
+ def clear_stacks
225
+ stack_device.word = 0xffff
226
+ stack_count_device.word = 0
227
+ end
228
+
229
+ def push_stacks
230
+ if stack_count_device.word > SIZE_OF_BIT_STACK
231
+ puts "ERROR: stacks overflow pc: H#{program_pointer.to_s(16).rjust(4, "0")}"
232
+ return
233
+ end
234
+ values = []
235
+ (SIZE_OF_BIT_STACK - 1).downto 0 do |i|
236
+ values << stack_device(i).word
237
+ end
238
+ values.shift
239
+ values << 0xffff
240
+ SIZE_OF_BIT_STACK.times do |i|
241
+ stack_device(i).word = values.pop
242
+ end
243
+ stack_count_device.word += 1
244
+ end
245
+
246
+ def pop_stacks
247
+ if stack_count_device.word <= 0
248
+ puts "ERROR: stacks underflow pc: H#{program_pointer.to_s(16).rjust(4, "0")}"
249
+ return
250
+ end
251
+ values = []
252
+ (SIZE_OF_BIT_STACK - 1).downto 0 do |i|
253
+ values << stack_device(i).word
254
+ end
255
+ v = values.pop
256
+ values.each_with_index do |v, i|
257
+ stack_device(i).word = v
258
+ end
259
+ stack_count_device.word -= 1
260
+ v
261
+ end
262
+ # ----------------
263
+
264
+ def sync_input
265
+ @lock.synchronize {
266
+ device_dict.values.each do |d|
267
+ d.sync_input
268
+ end
269
+ }
270
+ end
271
+
272
+ def sync_output
273
+ @lock.synchronize {
274
+ device_dict.values.each do |d|
275
+ d.sync_output
276
+ end
277
+ }
278
+ end
279
+
280
+ def and_join_stack
281
+ d = stack_device
282
+ b = d.word == 0xffff
283
+ d.word = 0xffff
284
+ push_stack b
285
+ end
286
+
287
+ def mnenonic_table
288
+ @mnemonic_table ||= begin
289
+ s = <<EOB
290
+ |00|END|INV|MEP|ANB|MEF|ORB|FEND|NOP|
291
+ |10|LD|LDI|LDP|LDPI|LDF|LDFI|MC|MCR|
292
+ |20|AND|ANI|ANDP|ANPI|ANDF|ANFI|
293
+ |30|OR|ORI|ORP|ORPI|ORF|ORFI|
294
+ |40|OUT|OUTI|MPS|MRD|MPP| |
295
+ |50|SET|RST|PLS| |PLF||
296
+ |60|FF||||||
297
+ |70|
298
+ |80|SFT|SFTP|SFL|SFLP|SFR|SFRP|
299
+ |90|BSFL|BSFLP|DSFL|DSFLP|BSFR|BSFRP|DSFR|DSFRP|
300
+ |A0|SFTL|SFTLP|WSFL|WSFLP|SFTR|SFTRP|WFSR|WSFRP|
301
+ EOB
302
+ table = {}
303
+ s.lines.each_with_index do |line, h|
304
+ line.chomp.split("|")[2..-1].each_with_index do |mnemonic, l|
305
+ unless mnemonic.length == 0
306
+ table[h << 4 | l] = mnemonic.downcase.to_sym
307
+ end
308
+ end
309
+ end
310
+ table
311
+ end
312
+ end
313
+
314
+ def fetch_and_execution
315
+ code = fetch_1_byte
316
+ return false unless code
317
+ mnemonic = mnenonic_table[code]
318
+ if mnemonic && respond_to?(mnemonic, true)
319
+ r = send mnemonic
320
+ r
321
+ else
322
+ nil
323
+ end
324
+ end
325
+
326
+ def fetch_1_byte
327
+ if @program_pointer < program_data.size
328
+ program_data[@program_pointer].tap do
329
+ @program_pointer += 1
330
+ end
331
+ else
332
+ nil
333
+ end
334
+ end
335
+
336
+ def fetch_device_or_value
337
+ c = fetch_1_byte
338
+ return false unless c
339
+
340
+ # check value type
341
+ case c & 0xe0
342
+ when 0x80
343
+ # bit device
344
+ when 0x00
345
+ # immediate number
346
+ return c
347
+ else
348
+ add_error "invalidate value type #{c.to_h(16)}"
349
+ return false
350
+ end
351
+
352
+ # device type
353
+ device_type = c & 0x0f
354
+
355
+ # number
356
+ number = 0
357
+ if (c & 0x10) == 0
358
+ number = fetch_1_byte
359
+ else
360
+ number = fetch_2_byte
361
+ end
362
+
363
+ # make device
364
+ d = device_by_type_and_number device_type, number
365
+ unless d
366
+ add_error "invalid device type #{c&0x3} and number #{number}"
367
+ return false
368
+ end
369
+ d
370
+ end
371
+
372
+ def fetch_bool_value inverse=false
373
+ d = fetch_device_or_value
374
+ return false unless d
375
+ unless d.is_a? EmuDevice
376
+ add_error "ld must be specify a device nor number #{d}"
377
+ return false
378
+ end
379
+ inverse ? !d.bool : d.bool
380
+ end
381
+
382
+ def add_error reason
383
+ @errors << {pc:@program_pointer, reason:reason}
384
+ end
385
+
386
+
387
+ # --- mnenonic ---
388
+ def ld inverse=false
389
+ b = fetch_bool_value inverse
390
+ return false if b.nil?
391
+ push_stack b
392
+ true
393
+ end
394
+ def ldi; ld true; end
395
+
396
+ def inv
397
+ and_join_stack
398
+ self.bool = !self.bool
399
+ true
400
+ end
401
+
402
+ def and inverse=false
403
+ b = fetch_bool_value inverse
404
+ return false if b.nil?
405
+ self.bool &= b
406
+ true
407
+ end
408
+ def ani; send :and, true; end
409
+
410
+ def or inverse=false
411
+ b = fetch_bool_value inverse
412
+ return false if b.nil?
413
+ self.bool |= b
414
+ true
415
+ end
416
+ def ori; send :or, true; end
417
+
418
+ def anb
419
+ b = self.bool
420
+ pop_stack
421
+ self.bool &= b
422
+ true
423
+ end
424
+
425
+ def orb
426
+ b = self.bool
427
+ pop_stack
428
+ self.bool |= b
429
+ true
430
+ end
431
+
432
+ def nop; true; end
433
+
434
+ def mps
435
+ and_join_stack
436
+ b = self.bool
437
+ push_stacks
438
+ push_stack b
439
+ true
440
+ end
441
+
442
+ def mrd
443
+ b = self.bool
444
+ pop_stacks
445
+ push_stacks
446
+ push_stack b
447
+ true
448
+ end
449
+ def mpp; mrd; end
450
+
451
+ def out inverse=false
452
+ and_join_stack
453
+ d = fetch_device_or_value
454
+ unless d.is_a? EmuDevice
455
+ add_error "ld must be specify a device nor number #{d}"
456
+ return false
457
+ end
458
+ d.bool = inverse ? !self.bool : self.bool unless d.input?
459
+ pop_stack
460
+ true
461
+ end
462
+ def outi; out true; end
463
+
464
+ def set inverse=false
465
+ and_join_stack
466
+ d = fetch_device_or_value
467
+ unless d.is_a? EmuDevice
468
+ add_error "ld must be specify a device nor number #{d}"
469
+ return false
470
+ end
471
+ d.bool = !inverse if self.bool unless d.input?
472
+ pop_stack
473
+ true
474
+ end
475
+ def rst; set true; end
476
+
477
+
478
+
479
+ end
480
+
481
+ end
482
+ end
@@ -0,0 +1,71 @@
1
+ #
2
+ # Copyright (c) 2016 ITO SOFT DESIGN Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'socket'
24
+ require 'ladder_drive/plc_device'
25
+
26
+ module Plc
27
+ module Emulator
28
+
29
+ class EmuPlcServer
30
+
31
+ class << self
32
+
33
+ def launch
34
+ @server ||= begin
35
+ server = new
36
+ server.run
37
+ server
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ def initialize config = {}
44
+ @port = config[:port] || 5555
45
+ @plc = EmuPlc.new
46
+ end
47
+
48
+ def run
49
+ @plc.run
50
+ Thread.new do
51
+ server = TCPServer.open @port
52
+ puts "launching emulator ... "
53
+ loop do
54
+ socket = server.accept
55
+ puts "done launching"
56
+ while line = socket.gets
57
+ begin
58
+ r = @plc.execute_console_commands line
59
+ socket.puts r
60
+ rescue => e
61
+ socket.puts "E0 #{e}\r"
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,28 @@
1
+ #
2
+ # Copyright (c) 2016 ITO SOFT DESIGN Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ dir = File.expand_path(File.dirname(__FILE__))
24
+ $:.unshift dir unless $:.include? dir
25
+
26
+ require 'emu_device'
27
+ require 'emu_plc'
28
+ require 'emu_plc_server'
@@ -0,0 +1,91 @@
1
+ <?xml version="1.0"?>
2
+ <DocumentWindowInfoForTab xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3
+ <All>
4
+ <DocumentWindowInfoForTabElement>
5
+ <Name>Main</Name>
6
+ <SaveKey>[Ladder]Main</SaveKey>
7
+ <DockingBarState>
8
+ <Key>Document@Ladder-275297072</Key>
9
+ <Usable>true</Usable>
10
+ <IsFloating>false</IsFloating>
11
+ <DockingInfo>
12
+ <IsCenter>true</IsCenter>
13
+ <DockingSide>Left</DockingSide>
14
+ <IsAutoHide>false</IsAutoHide>
15
+ <Size>
16
+ <Width>1012</Width>
17
+ <Height>370</Height>
18
+ </Size>
19
+ <LeftIndex>-1</LeftIndex>
20
+ <TopIndex>-1</TopIndex>
21
+ <RightIndex>-1</RightIndex>
22
+ <BottomIndex>-1</BottomIndex>
23
+ <MergeInfo>
24
+ <TabIndex>1</TabIndex>
25
+ <IsTabSelected>false</IsTabSelected>
26
+ <TilePosition />
27
+ </MergeInfo>
28
+ </DockingInfo>
29
+ <FloatingInfo>
30
+ <DockingKey>0</DockingKey>
31
+ <Location>
32
+ <X>0</X>
33
+ <Y>0</Y>
34
+ </Location>
35
+ <Size>
36
+ <Width>624</Width>
37
+ <Height>326</Height>
38
+ </Size>
39
+ <MergeInfo>
40
+ <TabIndex>-1</TabIndex>
41
+ <IsTabSelected>false</IsTabSelected>
42
+ <TilePosition />
43
+ </MergeInfo>
44
+ </FloatingInfo>
45
+ </DockingBarState>
46
+ </DocumentWindowInfoForTabElement>
47
+ <DocumentWindowInfoForTabElement>
48
+ <Name>LadderDrive</Name>
49
+ <SaveKey>[Ladder]LadderDrive</SaveKey>
50
+ <DockingBarState>
51
+ <Key>Document@Ladder-270352072</Key>
52
+ <Usable>true</Usable>
53
+ <IsFloating>false</IsFloating>
54
+ <DockingInfo>
55
+ <IsCenter>true</IsCenter>
56
+ <DockingSide>Left</DockingSide>
57
+ <IsAutoHide>false</IsAutoHide>
58
+ <Size>
59
+ <Width>1012</Width>
60
+ <Height>370</Height>
61
+ </Size>
62
+ <LeftIndex>-1</LeftIndex>
63
+ <TopIndex>-1</TopIndex>
64
+ <RightIndex>-1</RightIndex>
65
+ <BottomIndex>-1</BottomIndex>
66
+ <MergeInfo>
67
+ <TabIndex>0</TabIndex>
68
+ <IsTabSelected>true</IsTabSelected>
69
+ <TilePosition />
70
+ </MergeInfo>
71
+ </DockingInfo>
72
+ <FloatingInfo>
73
+ <DockingKey>0</DockingKey>
74
+ <Location>
75
+ <X>0</X>
76
+ <Y>0</Y>
77
+ </Location>
78
+ <Size>
79
+ <Width>624</Width>
80
+ <Height>326</Height>
81
+ </Size>
82
+ <MergeInfo>
83
+ <TabIndex>-1</TabIndex>
84
+ <IsTabSelected>false</IsTabSelected>
85
+ <TilePosition />
86
+ </MergeInfo>
87
+ </FloatingInfo>
88
+ </DockingBarState>
89
+ </DocumentWindowInfoForTabElement>
90
+ </All>
91
+ </DocumentWindowInfoForTab>
Binary file
@@ -0,0 +1 @@
1
+ ��
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0"?>
2
+ <SensorSpecialMonitorFileData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3
+ <XG />
4
+ </SensorSpecialMonitorFileData>