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,211 @@
|
|
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
|
+
|
26
|
+
class Asm
|
27
|
+
|
28
|
+
attr_reader :codes
|
29
|
+
attr_reader :endian
|
30
|
+
|
31
|
+
LITTLE_ENDIAN = 0
|
32
|
+
BIG_ENDIAN = 1
|
33
|
+
|
34
|
+
def initialize source, endian = nil
|
35
|
+
@endian = endian || BIG_ENDIAN
|
36
|
+
@lines = []
|
37
|
+
address = 0
|
38
|
+
source.each_line do |line|
|
39
|
+
@lines << AsmLine.new(line, address, @endian)
|
40
|
+
address = @lines.last.next_address
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def dump
|
45
|
+
@codes.map do |c|
|
46
|
+
c.to_s(16).rjust(2, "0")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def dump_line
|
51
|
+
@lines.map do |line|
|
52
|
+
"#{line.address.to_s(16).rjust(4, "0")} #{line.dump_line}"
|
53
|
+
end
|
54
|
+
.join("\n") << "\n"
|
55
|
+
end
|
56
|
+
|
57
|
+
def codes
|
58
|
+
@lines.map do |line|
|
59
|
+
line.codes
|
60
|
+
end.flatten
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def parse line
|
66
|
+
@lines << AsmLine.new(line)
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
class AsmLine
|
73
|
+
attr_reader :line
|
74
|
+
attr_reader :codes
|
75
|
+
attr_reader :address
|
76
|
+
attr_reader :endian
|
77
|
+
|
78
|
+
def initialize line, address = 0, endian = nil
|
79
|
+
@endian = endian || Asm::LITTLE_ENDIAN
|
80
|
+
@line = line.upcase.chomp
|
81
|
+
@codes = []
|
82
|
+
@address = address
|
83
|
+
parse
|
84
|
+
end
|
85
|
+
|
86
|
+
def dump_line
|
87
|
+
"#{dump}\t#{line}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def dump
|
91
|
+
@codes.map do |c|
|
92
|
+
c.to_s(16).rjust(2, "0")
|
93
|
+
end
|
94
|
+
.join(" ")
|
95
|
+
.ljust(12)
|
96
|
+
end
|
97
|
+
|
98
|
+
def next_address
|
99
|
+
address + codes.size
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
OPERAND_TYPE_NONE = 0
|
105
|
+
OPERAND_TYPE_TYPE_AND_NUMBER = 1
|
106
|
+
OPERAND_TYPE_TYPE_AND_NUMBER_NUMBER = 2
|
107
|
+
|
108
|
+
def parse
|
109
|
+
/([^#]*)/ =~ line
|
110
|
+
a = $1.split(/\s+/)
|
111
|
+
mnemonic, operand1, operand2 = a
|
112
|
+
if mnemonic
|
113
|
+
@codes << encode_mnemonic(mnemonic)
|
114
|
+
case operand_type(mnemonic)
|
115
|
+
when OPERAND_TYPE_TYPE_AND_NUMBER
|
116
|
+
@codes += parse_type_and_number(operand1)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def operand_type mnemonic
|
122
|
+
case mnemonic
|
123
|
+
when /LD/, /AND/, /ANI/, /OR[^B]?$/, /OUT/, "SET", "RST", "PLS", "PLF", "FF", /SF(L|R)/
|
124
|
+
OPERAND_TYPE_TYPE_AND_NUMBER
|
125
|
+
else
|
126
|
+
OPERAND_TYPE_NONE
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
MNEMONIC_DEF = <<EOB
|
131
|
+
| |00|10|20|30|40|50|60|70|80|90|A0|B0|C0|D0|E0|F0|
|
132
|
+
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|
133
|
+
|00|END|INV|MEP|ANB|MEF|ORB|FEND|NOP|
|
134
|
+
|01|LD|LDI|LDP|LDPI|LDF|LDFI|MC|MCR|
|
135
|
+
|02|AND|ANI|ANDP|ANPI|ANDF|ANFI|
|
136
|
+
|03|OR|ORI|ORP|ORPI|ORF|ORFI|
|
137
|
+
|04|OUT|OUTI|MPS|MRD|MPP| |
|
138
|
+
|05|SET|RST|PLS| |PLF||
|
139
|
+
|06|FF||| |||
|
140
|
+
|07|
|
141
|
+
|08|SFT|SFTP|SFL|SFLP|SFR|SFRP|
|
142
|
+
|09|BSFL|BSFLP|DSFL|DSFLP|BSFR|BSFRP|DSFR|DSFRP|
|
143
|
+
|0A|SFTL|SFTLP|WSFL|WSFLP|SFTR|SFTRP|WFSR|WSFRP|
|
144
|
+
|0B|
|
145
|
+
|0C|
|
146
|
+
|0D|
|
147
|
+
|0E|
|
148
|
+
|0F|
|
149
|
+
EOB
|
150
|
+
def mnemonic_dict
|
151
|
+
@@mnemonic_dict ||= begin
|
152
|
+
h = {}
|
153
|
+
MNEMONIC_DEF.dup.split(/\n/)[2..-1].each_with_index do |line, upper|
|
154
|
+
line.split(/\|/)[2..-1].each_with_index do |mnemonic, lower|
|
155
|
+
mnemonic.strip!
|
156
|
+
next if mnemonic.nil? || mnemonic.length == 0
|
157
|
+
code = (upper << 4) | lower
|
158
|
+
h[mnemonic] = code
|
159
|
+
end
|
160
|
+
end
|
161
|
+
h
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def encode_mnemonic mnemonic
|
166
|
+
mnemonic_dict[mnemonic]
|
167
|
+
end
|
168
|
+
|
169
|
+
def parse_type_and_number operand
|
170
|
+
/([[:alpha:]]*)(\d+[0-9A-Fa-f]*)\.?(\d*)?/ =~ operand
|
171
|
+
suffix = $1
|
172
|
+
number = $2
|
173
|
+
bit = $3
|
174
|
+
len = 16
|
175
|
+
case suffix
|
176
|
+
when "X", "Y"
|
177
|
+
number = number.to_i(16)
|
178
|
+
else
|
179
|
+
number = number.to_i
|
180
|
+
end
|
181
|
+
type_code = %W(X Y M - C T L SC CC TC D NOP - CS TS H SD).index(suffix)
|
182
|
+
raise "undefind suffix: #{suffix}" if type_code.nil?
|
183
|
+
|
184
|
+
case (type_code & 0xc) >> 2
|
185
|
+
when 0, 1
|
186
|
+
type_code |= 0x80
|
187
|
+
else
|
188
|
+
type_code |= 0xa0
|
189
|
+
end
|
190
|
+
|
191
|
+
if number < 256
|
192
|
+
[type_code, number]
|
193
|
+
else
|
194
|
+
case endian
|
195
|
+
when Asm::LITTLE_ENDIAN
|
196
|
+
[type_code | 0x10, number & 0xff, (number & 0xff00) >> 8]
|
197
|
+
when Asm::BIG_ENDIAN
|
198
|
+
[type_code | 0x10, (number & 0xff00) >> 8, number & 0xff]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
if $0 == __FILE__
|
209
|
+
asm = LadderDrive::Asm.new ARGF
|
210
|
+
puts asm.dump_line
|
211
|
+
end
|
@@ -0,0 +1,55 @@
|
|
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
|
+
require 'thor'
|
25
|
+
require 'fileutils'
|
26
|
+
|
27
|
+
include FileUtils
|
28
|
+
|
29
|
+
module LadderDrive
|
30
|
+
class CLI < Thor
|
31
|
+
|
32
|
+
desc "create", "Create a new project"
|
33
|
+
def create(name)
|
34
|
+
if File.exist? name
|
35
|
+
puts "ERROR: #{name} already exists."
|
36
|
+
exit -1
|
37
|
+
end
|
38
|
+
|
39
|
+
# copy from template file
|
40
|
+
root_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
|
41
|
+
template_path = File.join(root_dir, "template", "ladder_drive")
|
42
|
+
cp_r template_path, name
|
43
|
+
|
44
|
+
# copy plc directory
|
45
|
+
temlate_plc_path = File.join(root_dir, "lib", "plc")
|
46
|
+
cp_r temlate_plc_path, name
|
47
|
+
# remove unnecessary file from plc directory
|
48
|
+
%w(plc.rb emulator).each do |fn|
|
49
|
+
rm_r File.join(name, "plc", fn)
|
50
|
+
end
|
51
|
+
puts "#{name} was successfully created."
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
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
|
+
require 'active_support/core_ext/string/inflections'
|
25
|
+
require 'yaml'
|
26
|
+
require 'json'
|
27
|
+
require 'protocol/protocol'
|
28
|
+
|
29
|
+
include LadderDrive::Protocol::Mitsubishi
|
30
|
+
include LadderDrive::Protocol::Keyence
|
31
|
+
include LadderDrive::Protocol::Emulator
|
32
|
+
|
33
|
+
module LadderDrive
|
34
|
+
|
35
|
+
class LadderDriveConfig
|
36
|
+
|
37
|
+
class << self
|
38
|
+
|
39
|
+
def default
|
40
|
+
@config ||= begin
|
41
|
+
load File.join("config", "plc.yml")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def load path
|
46
|
+
h = {}
|
47
|
+
if File.exist?(path)
|
48
|
+
h = YAML.load(File.read(path))
|
49
|
+
h = JSON.parse(h.to_json, symbolize_names: true)
|
50
|
+
end
|
51
|
+
new h || {}
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize options={}
|
57
|
+
default = {
|
58
|
+
input: "asm/main.asm",
|
59
|
+
output: "build/main.hex",
|
60
|
+
}
|
61
|
+
emulator_default = {
|
62
|
+
host: "localhost",
|
63
|
+
port: 5555,
|
64
|
+
protocol: "emu_protocol",
|
65
|
+
}
|
66
|
+
|
67
|
+
@config = default.merge options
|
68
|
+
@config[:plc] ||= {}
|
69
|
+
@config[:plc][:emulator] = @config[:plc][:emulator] ? emulator_default.merge(@config[:plc][:emulator]) : emulator_default
|
70
|
+
|
71
|
+
@config[:default] ||= {}
|
72
|
+
|
73
|
+
@targets = {}
|
74
|
+
end
|
75
|
+
|
76
|
+
def [] key
|
77
|
+
@config[key]
|
78
|
+
end
|
79
|
+
|
80
|
+
def target name=nil
|
81
|
+
name ||= (@config[:default][:target] || :emulator)
|
82
|
+
name = name.to_sym if name.is_a? String
|
83
|
+
target = @targets[name]
|
84
|
+
unless target
|
85
|
+
h = @config[:plc][name]
|
86
|
+
unless h.nil? || h.empty?
|
87
|
+
h = {name:name}.merge h
|
88
|
+
target = LadderDriveConfigTarget.new h
|
89
|
+
@targets[name] = target
|
90
|
+
end
|
91
|
+
end
|
92
|
+
target
|
93
|
+
end
|
94
|
+
|
95
|
+
def method_missing(name, *args)
|
96
|
+
name = name.to_s unless name.is_a? String
|
97
|
+
case name.to_s
|
98
|
+
when /(.*)=$/
|
99
|
+
@config[$1.to_sym] = args.first
|
100
|
+
else
|
101
|
+
@config[name.to_sym]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,93 @@
|
|
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 'active_support/core_ext/string/inflections'
|
24
|
+
require 'yaml'
|
25
|
+
require 'json'
|
26
|
+
require 'protocol/protocol'
|
27
|
+
|
28
|
+
include LadderDrive::Protocol::Mitsubishi
|
29
|
+
include LadderDrive::Protocol::Keyence
|
30
|
+
include LadderDrive::Protocol::Emulator
|
31
|
+
|
32
|
+
module LadderDrive
|
33
|
+
|
34
|
+
class LadderDriveConfigTarget
|
35
|
+
|
36
|
+
class << self
|
37
|
+
|
38
|
+
def finalize
|
39
|
+
proc {
|
40
|
+
EmuPlcServer.terminate
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize options={}
|
47
|
+
@target_info = options
|
48
|
+
ObjectSpace.define_finalizer(self, self.class.finalize)
|
49
|
+
end
|
50
|
+
|
51
|
+
def protocol
|
52
|
+
@protocol ||= begin
|
53
|
+
p = eval("#{@target_info[:protocol].camelize}.new")
|
54
|
+
p.host = @target_info[:host] if @target_info[:host]
|
55
|
+
p.port = @target_info[:port] if @target_info[:port]
|
56
|
+
p.log_level = @target_info[:log_level] if @target_info[:log_level]
|
57
|
+
p
|
58
|
+
rescue
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def uploader
|
64
|
+
@uploader ||= begin
|
65
|
+
u = Uploader.new
|
66
|
+
u.protocol = self.protocol
|
67
|
+
u
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def method_missing(name, *args)
|
72
|
+
name = name.to_s unless name.is_a? String
|
73
|
+
case name.to_s
|
74
|
+
when /(.*)=$/
|
75
|
+
@target_info[$1.to_sym] = args.first
|
76
|
+
else
|
77
|
+
@target_info[name.to_sym]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def run
|
82
|
+
case self.name
|
83
|
+
when :emulator
|
84
|
+
Plc::Emulator::EmuPlcServer.launch
|
85
|
+
else
|
86
|
+
# DO NOTHIN
|
87
|
+
# Actual device is running independently.
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,113 @@
|
|
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 'singleton'
|
24
|
+
|
25
|
+
module LadderDrive
|
26
|
+
|
27
|
+
attr_accessor :target
|
28
|
+
|
29
|
+
class Console
|
30
|
+
include Singleton
|
31
|
+
|
32
|
+
def run
|
33
|
+
l = true
|
34
|
+
trap(:INT) { puts "\n> " }
|
35
|
+
|
36
|
+
display_title
|
37
|
+
|
38
|
+
loop do
|
39
|
+
begin
|
40
|
+
print "> "
|
41
|
+
line = STDIN.gets
|
42
|
+
case line.chomp
|
43
|
+
when /^\s*exit\s*$/, /^\s*quit\s*$/, /^\s*q\s*$/
|
44
|
+
break
|
45
|
+
when /^r\s+(\w+)(\s+(\d+))?/
|
46
|
+
d = protocol.device_by_name EscDevice.new($1)
|
47
|
+
c = $2 ? $2.to_i : 1
|
48
|
+
values = protocol.get_from_devices d, c
|
49
|
+
values = values.map{|v| case v; when true; 1; when false; 0; else; v; end}
|
50
|
+
puts values.join(" ")
|
51
|
+
when /^p\s+(\w+)(\s+(\d+))?/
|
52
|
+
d = protocol.device_by_name EscDevice.new($1)
|
53
|
+
t = $2 ? $2.to_f : 0.1
|
54
|
+
protocol.set_to_devices d, true
|
55
|
+
sleep t
|
56
|
+
protocol.set_to_devices d, false
|
57
|
+
when /^w\s+(\w+)/
|
58
|
+
d = protocol.device_by_name EscDevice.new($1)
|
59
|
+
v = $'.scan(/\d+/).map{|e| e.to_i}
|
60
|
+
protocol.set_to_devices d, v
|
61
|
+
when /^E\s+/
|
62
|
+
puts protocol.execute(line)
|
63
|
+
when /^help/, /^h/
|
64
|
+
display_help
|
65
|
+
end
|
66
|
+
rescue => e
|
67
|
+
puts "*** ERROR: #{e} ***"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def protocol
|
75
|
+
target.protocol
|
76
|
+
end
|
77
|
+
|
78
|
+
def display_title
|
79
|
+
puts <<EOB
|
80
|
+
|
81
|
+
LadderDrive is an abstract PLC.
|
82
|
+
This is a console to communicate with PLC.
|
83
|
+
|
84
|
+
EOB
|
85
|
+
end
|
86
|
+
|
87
|
+
def display_help
|
88
|
+
puts <<EOB
|
89
|
+
Commands:
|
90
|
+
|
91
|
+
r: Read values from device.
|
92
|
+
r device [count]
|
93
|
+
e.g.) it reads values from M0 to M7.
|
94
|
+
> r m0 8
|
95
|
+
w: Write values to device.
|
96
|
+
w device value1 value2 ...
|
97
|
+
e.g.) it write values from D0 to D7.
|
98
|
+
> w d0 1 2 3 4 5 6 7 8
|
99
|
+
e.g.) it write values from M0 to M7.
|
100
|
+
> w m0 0 0 0 1 1 0 1 1
|
101
|
+
p: Pulse out on device. Default duration is 0.1 sec
|
102
|
+
p device [duration]
|
103
|
+
e.g.) it write 1 to m0, then write 0 after 0.5 sec.
|
104
|
+
> w m0 0.5
|
105
|
+
q: Quit this. You can use quit and exit instead of q.
|
106
|
+
h: Show help. You can use help instead of h.
|
107
|
+
|
108
|
+
EOB
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,79 @@
|
|
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
|
+
|
26
|
+
class IntelHex
|
27
|
+
|
28
|
+
attr_reader :offset, :codes
|
29
|
+
|
30
|
+
def self.load path
|
31
|
+
offset = 0
|
32
|
+
codes = []
|
33
|
+
File.read(path).lines.each do |l|
|
34
|
+
case l[7,2]
|
35
|
+
when "00"
|
36
|
+
address = l[3,4].to_i(16)
|
37
|
+
offset ||= address
|
38
|
+
l.chomp[9..-3].each_char.each_slice(2).each_with_index do |pair, i|
|
39
|
+
codes[address - offset + i] = pair.join("").to_i(16)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
new codes, offset
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize codes, offset = 0
|
47
|
+
@offset = offset
|
48
|
+
@codes = codes
|
49
|
+
end
|
50
|
+
|
51
|
+
def write_to path
|
52
|
+
File.write(path, dump)
|
53
|
+
end
|
54
|
+
|
55
|
+
def dump
|
56
|
+
addr = offset
|
57
|
+
lines = []
|
58
|
+
@codes.each_slice(16) do |line_codes|
|
59
|
+
c = line_codes.size
|
60
|
+
s = ":#{c.to_s(16).rjust(2, '0')}"
|
61
|
+
s << "#{addr.to_s(16).rjust(4, '0')}"
|
62
|
+
s << "00"
|
63
|
+
line_codes.each do |code|
|
64
|
+
s << "#{code.to_s(16).rjust(2, '0')}"
|
65
|
+
end
|
66
|
+
check_sum = 256 - (s[1..-1].scan(/.{2}/).inject(0){|sum, code| sum += code.to_i(16)} & 0xff)
|
67
|
+
s << "#{check_sum.to_s(16).rjust(2, '0')}"
|
68
|
+
lines << s
|
69
|
+
addr += c
|
70
|
+
end
|
71
|
+
|
72
|
+
lines << ":00000001FF"
|
73
|
+
lines << ""
|
74
|
+
lines.join("\n")
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,36 @@
|
|
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 "version"
|
27
|
+
require "cli"
|
28
|
+
require "asm"
|
29
|
+
require "intel_hex"
|
30
|
+
require "plc_define"
|
31
|
+
require "uploader"
|
32
|
+
require "config"
|
33
|
+
require "config_target"
|
34
|
+
require "plc_device"
|
35
|
+
require "protocol/protocol"
|
36
|
+
require "console"
|