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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +41 -0
- data/LICENSE +21 -0
- data/README.md +191 -0
- data/README_jp.md +193 -0
- data/Rakefile +9 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/ladder_drive +28 -0
- data/ladder_drive.gemspec +33 -0
- data/lib/ladder_drive/asm.rb +211 -0
- data/lib/ladder_drive/cli.rb +55 -0
- data/lib/ladder_drive/config.rb +107 -0
- data/lib/ladder_drive/config_target.rb +93 -0
- data/lib/ladder_drive/console.rb +113 -0
- data/lib/ladder_drive/intel_hex.rb +79 -0
- data/lib/ladder_drive/ladder_drive.rb +36 -0
- data/lib/ladder_drive/plc_define.rb +35 -0
- data/lib/ladder_drive/plc_device.rb +171 -0
- data/lib/ladder_drive/protocol/emulator/emu_protocol.rb +54 -0
- data/lib/ladder_drive/protocol/emulator/emulator.rb +29 -0
- data/lib/ladder_drive/protocol/keyence/keyence.rb +31 -0
- data/lib/ladder_drive/protocol/keyence/kv_device.rb +51 -0
- data/lib/ladder_drive/protocol/keyence/kv_protocol.rb +187 -0
- data/lib/ladder_drive/protocol/mitsubishi/mc_protocol.rb +268 -0
- data/lib/ladder_drive/protocol/mitsubishi/mitsubishi.rb +30 -0
- data/lib/ladder_drive/protocol/mitsubishi/qdevice.rb +114 -0
- data/lib/ladder_drive/protocol/protocol.rb +107 -0
- data/lib/ladder_drive/tasks/build.rb +101 -0
- data/lib/ladder_drive/uploader.rb +101 -0
- data/lib/ladder_drive/version.rb +26 -0
- data/lib/ladder_drive.rb +32 -0
- data/lib/plc/LICENSE +21 -0
- data/lib/plc/emulator/emu_device.rb +121 -0
- data/lib/plc/emulator/emu_plc.rb +482 -0
- data/lib/plc/emulator/emu_plc_server.rb +71 -0
- data/lib/plc/emulator/emulator.rb +28 -0
- data/lib/plc/keyence/kv/kv-5000/DocumentWindowInfo.xml +91 -0
- data/lib/plc/keyence/kv/kv-5000/KvsMon.ini +0 -0
- data/lib/plc/keyence/kv/kv-5000/LadderDrive.mod +0 -0
- data/lib/plc/keyence/kv/kv-5000/LbkMdm.ini +0 -0
- data/lib/plc/keyence/kv/kv-5000/Main.mod +0 -0
- data/lib/plc/keyence/kv/kv-5000/MonEnv.kmu +1 -0
- data/lib/plc/keyence/kv/kv-5000/PlcSended.dky +0 -0
- data/lib/plc/keyence/kv/kv-5000/SensorMonitorInfo.xml +4 -0
- data/lib/plc/keyence/kv/kv-5000/TransInfo.tif +0 -0
- data/lib/plc/keyence/kv/kv-5000/UnitSet.ue2 +0 -0
- data/lib/plc/keyence/kv/kv-5000/UnitSet.ue2.old +0 -0
- data/lib/plc/keyence/kv/kv-5000/WsTreeEnv.xml +28 -0
- data/lib/plc/keyence/kv/kv-5000/kv-5000.cm1 +0 -0
- data/lib/plc/keyence/kv/kv-5000/kv-5000.cm2 +0 -0
- data/lib/plc/keyence/kv/kv-5000/kv-5000.ftc +0 -0
- data/lib/plc/keyence/kv/kv-5000/kv-5000.kpr +0 -0
- data/lib/plc/keyence/kv/kv-5000/kv-5000.lbl +0 -0
- data/lib/plc/keyence/kv/kv-5000/kv-5000.mil +0 -0
- data/lib/plc/keyence/kv/kv-5000/kv-5000.spl +0 -0
- data/lib/plc/keyence/kv/kv-5000/operand-history.txt +16 -0
- data/lib/plc/keyence/kv/kv-5000/sample.al2 +2 -0
- data/lib/plc/mitsubishi/iq-r/r08/r08.gx3 +0 -0
- data/lib/plc/plc.rb +27 -0
- data/sample/ladder_drive/sample1.esc +4 -0
- data/sample/ladder_drive/sample2.esc +28 -0
- data/sample/ladder_drive/sample2.png +0 -0
- data/template/escalator/config/plc.yml +27 -0
- data/template/ladder_drive/Rakefile +1 -0
- data/template/ladder_drive/asm/main.esc +70 -0
- data/template/ladder_drive/config/plc.yml +27 -0
- 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
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
��
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|