ladder_drive 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|