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,268 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
#
|
3
|
+
# Copyright (c) 2016 ITO SOFT DESIGN Inc.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
module LadderDrive
|
25
|
+
module Protocol
|
26
|
+
module Mitsubishi
|
27
|
+
|
28
|
+
class McProtocol < Protocol
|
29
|
+
|
30
|
+
def initialize options={}
|
31
|
+
super
|
32
|
+
@host = options[:host] || "192.168.0.10"
|
33
|
+
@port = options[:port] || 5010
|
34
|
+
prepare_device_map
|
35
|
+
end
|
36
|
+
|
37
|
+
def open
|
38
|
+
open!
|
39
|
+
rescue
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def open!
|
44
|
+
@socket ||= TCPSocket.open(@host, @port)
|
45
|
+
end
|
46
|
+
|
47
|
+
def close
|
48
|
+
@socket.close if @socket
|
49
|
+
@socket = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_bit_from_device device
|
53
|
+
device = device_by_name device
|
54
|
+
get_bits_from_device(1, device).first
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_bits_from_device count, device
|
58
|
+
device = device_by_name device
|
59
|
+
packet = make_packet(body_for_get_bits_from_deivce(count, device))
|
60
|
+
@logger.debug("> #{dump_packet packet}")
|
61
|
+
open
|
62
|
+
@socket.write(packet.pack("c*"))
|
63
|
+
@socket.flush
|
64
|
+
res = receive
|
65
|
+
bits = []
|
66
|
+
count.times do |i|
|
67
|
+
v = res[11 + i / 2]
|
68
|
+
if i % 2 == 0
|
69
|
+
bits << ((v >> 4) != 0)
|
70
|
+
else
|
71
|
+
bits << ((v & 0xf) != 0)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
@logger.debug("get #{device.name} => #{bits}")
|
75
|
+
bits
|
76
|
+
end
|
77
|
+
|
78
|
+
def set_bits_to_device bits, device
|
79
|
+
device = device_by_name device
|
80
|
+
packet = make_packet(body_for_set_bits_to_device(bits, device))
|
81
|
+
@logger.debug("> #{dump_packet packet}")
|
82
|
+
open
|
83
|
+
@socket.write(packet.pack("c*"))
|
84
|
+
@socket.flush
|
85
|
+
res = receive
|
86
|
+
@logger.debug("set #{bits} to:#{device.name}")
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def get_word_from_device device
|
91
|
+
device = device_by_name device
|
92
|
+
get_words_from_device(1, device).first
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_words_from_device(count, device)
|
96
|
+
device = device_by_name device
|
97
|
+
packet = make_packet(body_for_get_words_from_deivce(count, device))
|
98
|
+
@logger.debug("> #{dump_packet packet}")
|
99
|
+
open
|
100
|
+
@socket.write(packet.pack("c*"))
|
101
|
+
@socket.flush
|
102
|
+
res = receive
|
103
|
+
words = []
|
104
|
+
res[11, 2 * count].each_slice(2) do |pair|
|
105
|
+
words << pair.pack("c*").unpack("v").first
|
106
|
+
end
|
107
|
+
@logger.debug("get from: #{device.name} => #{words}")
|
108
|
+
words
|
109
|
+
end
|
110
|
+
|
111
|
+
def set_words_to_device words, device
|
112
|
+
device = device_by_name device
|
113
|
+
packet = make_packet(body_for_set_words_to_device(words, device))
|
114
|
+
@logger.debug("> #{dump_packet packet}")
|
115
|
+
open
|
116
|
+
@socket.write(packet.pack("c*"))
|
117
|
+
@socket.flush
|
118
|
+
res = receive
|
119
|
+
@logger.debug("set #{words} to: #{device.name}")
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
def device_by_name name
|
124
|
+
case name
|
125
|
+
when String
|
126
|
+
QDevice.new name
|
127
|
+
when EscDevice
|
128
|
+
local_device_of name
|
129
|
+
else
|
130
|
+
# it may be already QDevice
|
131
|
+
name
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def receive
|
137
|
+
res = []
|
138
|
+
len = 0
|
139
|
+
begin
|
140
|
+
Timeout.timeout(1.0) do
|
141
|
+
loop do
|
142
|
+
c = @socket.read(1)
|
143
|
+
next if c.nil? || c == ""
|
144
|
+
|
145
|
+
res << c.bytes.first
|
146
|
+
len = res[7,2].pack("c*").unpack("v*").first if res.length >= 9
|
147
|
+
break if (len + 9 == res.length)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
rescue Timeout::Error
|
151
|
+
puts "*** ERROR: TIME OUT ***"
|
152
|
+
end
|
153
|
+
@logger.debug("< #{dump_packet res}")
|
154
|
+
res
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def make_packet body
|
160
|
+
header = [0x50, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00]
|
161
|
+
header[7..8] = data_for_short(body.length + 2)
|
162
|
+
header + body
|
163
|
+
end
|
164
|
+
|
165
|
+
def body_for_get_bit_from_deivce device
|
166
|
+
body_for_get_bits_from_deivce 1, device
|
167
|
+
end
|
168
|
+
|
169
|
+
def body_for_get_bits_from_deivce count, device
|
170
|
+
body_for_get_words_from_deivce count, device, false
|
171
|
+
end
|
172
|
+
|
173
|
+
def body_for_get_words_from_deivce count, device, word = true
|
174
|
+
body = [0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00]
|
175
|
+
body[2] = 1 unless word
|
176
|
+
body[4..7] = data_for_device(device)
|
177
|
+
body[8..9] = data_for_short count
|
178
|
+
body
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
def body_for_set_bits_to_device bits, device
|
183
|
+
body = [0x01, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00]
|
184
|
+
d = device
|
185
|
+
bits = [bits] unless bits.is_a? Array
|
186
|
+
bits.each_slice(2) do |pair|
|
187
|
+
body << (pair.first ? 0x10 : 0x00)
|
188
|
+
body[-1] |= (pair.last ? 0x1 : 0x00) if pair.size == 2
|
189
|
+
d = d.next_device
|
190
|
+
end
|
191
|
+
body[4..7] = data_for_device(device)
|
192
|
+
body[8..9] = data_for_short bits.size
|
193
|
+
body
|
194
|
+
end
|
195
|
+
alias :body_for_set_bit_to_device :body_for_set_bits_to_device
|
196
|
+
|
197
|
+
def body_for_set_words_to_device words, device
|
198
|
+
body = [0x01, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00]
|
199
|
+
d = device
|
200
|
+
words = [words] unless words.is_a? Array
|
201
|
+
words.each do |v|
|
202
|
+
body += data_for_short v
|
203
|
+
d = d.next_device
|
204
|
+
end
|
205
|
+
body[4..7] = data_for_device(device)
|
206
|
+
body[8..9] = data_for_short words.size
|
207
|
+
body
|
208
|
+
end
|
209
|
+
|
210
|
+
def data_for_device device
|
211
|
+
a = data_for_int device.number
|
212
|
+
a[3] = device.suffix_code
|
213
|
+
a
|
214
|
+
end
|
215
|
+
|
216
|
+
def data_for_short value
|
217
|
+
[value].pack("v").unpack("c*")
|
218
|
+
end
|
219
|
+
|
220
|
+
def data_for_int value
|
221
|
+
[value].pack("V").unpack("c*")
|
222
|
+
end
|
223
|
+
|
224
|
+
def dump_packet packet
|
225
|
+
a = []
|
226
|
+
len = packet.length
|
227
|
+
bytes = packet.dup
|
228
|
+
len.times do |i|
|
229
|
+
a << ("0" + bytes[i].to_s(16))[-2, 2]
|
230
|
+
end
|
231
|
+
"[" + a.join(", ") + "]"
|
232
|
+
end
|
233
|
+
|
234
|
+
def prepare_device_map
|
235
|
+
@conv_dev_dict ||= begin
|
236
|
+
h = {}
|
237
|
+
[
|
238
|
+
["X", "X0", 1024],
|
239
|
+
["Y", "Y0", 1024],
|
240
|
+
["M", "M0", 1024],
|
241
|
+
["C", "C0", 256],
|
242
|
+
["T", "T0", 256],
|
243
|
+
["L", "L0", 1024],
|
244
|
+
["SC", "M1024", 1024],
|
245
|
+
["D", "D0", 1024],
|
246
|
+
["H", "D1024", 1024],
|
247
|
+
["SD", "D2048", 1024],
|
248
|
+
["PRG", "D3072", 1024] # ..D4095
|
249
|
+
].each do |s,d,c|
|
250
|
+
h[s] = [QDevice.new(d), c]
|
251
|
+
end
|
252
|
+
h
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def local_device_of device
|
257
|
+
return device if device.is_a? QDevice
|
258
|
+
d, c = @conv_dev_dict[device.suffix]
|
259
|
+
return nil unless device.number < c
|
260
|
+
ld = QDevice.new(d.suffix, d.number + device.number)
|
261
|
+
device_by_name ld.name
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
#
|
3
|
+
# Copyright (c) 2016 ITO SOFT DESIGN Inc.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
$:.unshift File.dirname(__FILE__)
|
25
|
+
|
26
|
+
require 'socket'
|
27
|
+
require 'logger'
|
28
|
+
require 'timeout'
|
29
|
+
require 'qdevice'
|
30
|
+
require 'mc_protocol'
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
#
|
3
|
+
# Copyright (c) 2016 ITO SOFT DESIGN Inc.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
module LadderDrive
|
25
|
+
module Protocol
|
26
|
+
module Mitsubishi
|
27
|
+
|
28
|
+
class QDevice
|
29
|
+
|
30
|
+
attr_reader :suffix, :number
|
31
|
+
|
32
|
+
SUFFIXES = %w(SM SD X Y M L F V B D W TS TC TN SS SC SN CS CC CN SB SW S DX DY Z R ZR)
|
33
|
+
SUFFIX_CODES = [0x91, 0xa9, 0x9c, 0x9d, 0x90, 0x92, 0x93, 0x94, 0xa0, 0xa8, 0xb4, 0xc1, 0xc0, 0xc2, 0xc7, 0xc6, 0xc8, 0xc4, 0xc3, 0xc5, 0xa1, 0xb5, 0x98, 0xa2, 0xa3, 0xcc ,0xaf, 0xb0]
|
34
|
+
|
35
|
+
def initialize a, b = nil
|
36
|
+
case a
|
37
|
+
when Array
|
38
|
+
case a.size
|
39
|
+
when 4
|
40
|
+
@suffix = suffix_for_code(a[3])
|
41
|
+
@number = ((a[2] << 8 | a[1]) << 8) | a[0]
|
42
|
+
end
|
43
|
+
when String
|
44
|
+
if b
|
45
|
+
@suffix = a.upcase
|
46
|
+
@number = b
|
47
|
+
else
|
48
|
+
if a.length == 12
|
49
|
+
@suffix = [a[0,2].to_i(16), a[2,2].to_i(16)].pack "c*"
|
50
|
+
@suffix.strip!
|
51
|
+
@number = a[4,8].to_i(16)
|
52
|
+
elsif /(X|Y)(.+)/i =~ a
|
53
|
+
@suffix = $1.upcase
|
54
|
+
@number = $2.to_i(p_adic_number)
|
55
|
+
else
|
56
|
+
/(M|L|S|B|F|T|C|D|W|R)(.+)/i =~ a
|
57
|
+
@suffix = $1.upcase
|
58
|
+
@number = $2.to_i(p_adic_number)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def p_adic_number
|
65
|
+
case @suffix
|
66
|
+
when "X", "Y", "B", "W", "SB", "SW", "DX", "DY", "ZR"
|
67
|
+
16
|
68
|
+
else
|
69
|
+
10
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def name
|
74
|
+
@suffix + @number.to_s(p_adic_number).upcase
|
75
|
+
end
|
76
|
+
|
77
|
+
def next_device
|
78
|
+
d = self.class.new @suffix, @number + 1
|
79
|
+
d
|
80
|
+
end
|
81
|
+
|
82
|
+
def bit_device?
|
83
|
+
case @suffix
|
84
|
+
when "SM", "X", "Y", "M", "L", "F", "V", "B",
|
85
|
+
"TS", "TC", "SS", "SC","CS", "CC", "SB", "S", "DX", "DY"
|
86
|
+
true
|
87
|
+
else
|
88
|
+
false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def suffix_for_code code
|
93
|
+
index = SUFFIX_CODES.index code
|
94
|
+
index ? SUFFIXES[index] : nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def suffix_code
|
98
|
+
index = SUFFIXES.index suffix
|
99
|
+
index ? SUFFIX_CODES[index] : 0
|
100
|
+
end
|
101
|
+
|
102
|
+
def + value
|
103
|
+
self.class.new self.suffix, self.number + value
|
104
|
+
end
|
105
|
+
|
106
|
+
def - value
|
107
|
+
self.class.new self.suffix, [self.number - value, 0].max
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
#
|
3
|
+
# Copyright (c) 2016 ITO SOFT DESIGN Inc.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
25
|
+
$:.unshift dir unless $:.include? dir
|
26
|
+
|
27
|
+
module LadderDrive
|
28
|
+
module Protocol
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module LadderDrive
|
33
|
+
module Protocol
|
34
|
+
|
35
|
+
class Protocol
|
36
|
+
|
37
|
+
attr_accessor :host, :port, :log_level
|
38
|
+
|
39
|
+
def initialize options={}
|
40
|
+
@logger = Logger.new(STDOUT)
|
41
|
+
self.log_level = options[:log_level] || :info
|
42
|
+
end
|
43
|
+
|
44
|
+
def log_level= level
|
45
|
+
@log_level = level.is_a?(String) ? level.to_sym : level
|
46
|
+
case @log_level
|
47
|
+
when :debug
|
48
|
+
@logger.level = Logger::DEBUG
|
49
|
+
when :error
|
50
|
+
@logger.level = Logger::ERROR
|
51
|
+
when :fatal
|
52
|
+
@logger.level = Logger::FATAL
|
53
|
+
when :info
|
54
|
+
@logger.level = Logger::INFO
|
55
|
+
when :unknown
|
56
|
+
@logger.level = Logger::UNKNOWN
|
57
|
+
when :warn
|
58
|
+
@logger.level = Logger::WARN
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# abstract methods
|
63
|
+
|
64
|
+
def open; end
|
65
|
+
def close; end
|
66
|
+
|
67
|
+
def get_bit_from_device device; end
|
68
|
+
def get_bits_from_device count, device; end
|
69
|
+
def set_bits_to_device bits, device; end
|
70
|
+
def set_bit_to_device bit, device; set_bits_to_device bit, device; end
|
71
|
+
|
72
|
+
def get_word_from_device device; end
|
73
|
+
def get_words_from_device(count, device); end
|
74
|
+
def set_words_to_device words, device; end
|
75
|
+
def set_word_to_device word, device; set_words_to_device word, device; end
|
76
|
+
|
77
|
+
def device_by_name name; nil; end
|
78
|
+
|
79
|
+
def get_from_devices device, count = 1
|
80
|
+
d = device_by_name device
|
81
|
+
if d.bit_device?
|
82
|
+
get_bits_from_device count, d
|
83
|
+
else
|
84
|
+
get_words_from_device count, d
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_to_devices device, values
|
89
|
+
values = [values] unless values.is_a? Array
|
90
|
+
d = device_by_name device
|
91
|
+
if d.bit_device?
|
92
|
+
values = values.map{|v| case v; when 1; true; when 0; false; else; v; end}
|
93
|
+
set_bits_to_device values, d
|
94
|
+
else
|
95
|
+
set_words_to_device values, d
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
require 'keyence/keyence'
|
105
|
+
# Use load instead require, because there are two emulator files.
|
106
|
+
load File.join(dir, 'emulator/emulator.rb')
|
107
|
+
require 'mitsubishi/mitsubishi'
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
#
|
3
|
+
# Copyright (c) 2016 ITO SOFT DESIGN Inc.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
dir = File.expand_path(File.join(File.dirname(__FILE__), "../../../lib"))
|
25
|
+
$:.unshift dir unless $:.include? dir
|
26
|
+
|
27
|
+
require 'rake/loaders/makefile'
|
28
|
+
require 'fileutils'
|
29
|
+
require "ladder_drive"
|
30
|
+
|
31
|
+
directory "build"
|
32
|
+
|
33
|
+
desc "Assemble codes"
|
34
|
+
rule %r{^build/.+\.lst} => ['%{^build,asm}X.esc'] do |t|
|
35
|
+
Rake::Task["build"].invoke
|
36
|
+
begin
|
37
|
+
$stderr = File.open('hb.log', 'w')
|
38
|
+
$stdout = $stderr
|
39
|
+
ensure
|
40
|
+
$stdout = STDOUT
|
41
|
+
$stderr = STDERR
|
42
|
+
end
|
43
|
+
#dir = "./asm"
|
44
|
+
stream = StringIO.new
|
45
|
+
#filename = "asm/#{t.source}"
|
46
|
+
puts "asm #{t.source}"
|
47
|
+
asm = LadderDrive::Asm.new File.read(t.source)
|
48
|
+
#dst = File.join("build", t.name)
|
49
|
+
File.write(t.name, asm.dump_line)
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Make hex codes"
|
53
|
+
rule %r{^build/.+\.hex} => ['%{^build,asm}X.esc'] do |t|
|
54
|
+
Rake::Task["build"].invoke
|
55
|
+
begin
|
56
|
+
$stderr = File.open('hb.log', 'w')
|
57
|
+
$stdout = $stderr
|
58
|
+
ensure
|
59
|
+
$stdout = STDOUT
|
60
|
+
$stderr = STDERR
|
61
|
+
end
|
62
|
+
stream = StringIO.new
|
63
|
+
puts "hex #{t.source}"
|
64
|
+
asm = LadderDrive::Asm.new File.read(t.source)
|
65
|
+
hex = LadderDrive::IntelHex.new asm.codes
|
66
|
+
File.write(t.name, hex.dump)
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "Clean all generated files."
|
70
|
+
task :clean do
|
71
|
+
FileUtils.rm_r "build"
|
72
|
+
end
|
73
|
+
|
74
|
+
@config = LadderDrive::LadderDriveConfig.default
|
75
|
+
|
76
|
+
desc "Install program to PLCs."
|
77
|
+
task :upload => @config.output do
|
78
|
+
t = @config.target ENV['target']
|
79
|
+
t.run
|
80
|
+
u = t.uploader
|
81
|
+
u.source = @config.output
|
82
|
+
puts "uploading #{u.source} ..."
|
83
|
+
u.upload
|
84
|
+
puts "done uploading"
|
85
|
+
end
|
86
|
+
|
87
|
+
desc "Launch emulator."
|
88
|
+
task :emulator do
|
89
|
+
t = @config.target :emulator
|
90
|
+
t.run
|
91
|
+
puts "launch emulator"
|
92
|
+
LadderDrive::Console.instance.run
|
93
|
+
end
|
94
|
+
|
95
|
+
task :console => :upload do
|
96
|
+
c = LadderDrive::Console.instance
|
97
|
+
c.target = @config.target ENV['target']
|
98
|
+
c.run
|
99
|
+
end
|
100
|
+
|
101
|
+
task :default => :console
|