ladder_drive 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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>