ladder_drive 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ebbe6a801c62fb7bf390b50e904186de6c8a54d4
4
- data.tar.gz: 65bc6883680145868f3bec1b333d76760fee2eb0
3
+ metadata.gz: 78f994329616c81aa08af6f821851a9cfa302382
4
+ data.tar.gz: cdd5b03d754155febbc0e0b77f4e23a09910a447
5
5
  SHA512:
6
- metadata.gz: 2a78ed56aecb16bb8a4bdf5275acdf6b5f551cc62bce2efd6512160e79aa5c0d9757eb9eed6419f419bb5eba4f13fcc44e6ead4d4b9cc6cdb4cb4277b8ad150b
7
- data.tar.gz: 885041e935159cc775be45f6f8d0d46a148f74739c7b24fea1ccf8c4f4e5627f3be0b0b1cbbdd2fb92c6176defefadb949e55cf8e25848a76d10dde54c577f49
6
+ metadata.gz: c92d94494040f7d972110d07d116df9fdea309c979fde59a58da644e4f9d41a775ec680c16a8e82be9267705f6dae9f6ca7967b4c595c03dcbf1cbd41158081f
7
+ data.tar.gz: d5343de39d9760831bda75adb6dfc7e6f30cb485f7c6f137a67dcd651583ecc517c415de040963cbe6cab29f5a968d1fdd7a9837fc9ebdc69ace1dfedbc8b07d
data/Gemfile CHANGED
@@ -3,9 +3,13 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in ladder_drive.gemspec
4
4
  gemspec
5
5
 
6
- gem "test-unit"
6
+ group :test do
7
+ gem "test-unit"
8
+ gem "test-unit-rr"
9
+ #gem "test-unit-notify"
10
+ end
7
11
 
8
- gem "activesupport", '~> 5.0'
12
+ gem "activesupport", '>= 4.0'
9
13
 
10
14
  gem 'pi_piper', ">= 2.0.0"
11
15
  gem "ffi", "~> 1.9.24"
@@ -13,3 +17,4 @@ gem "ffi", "~> 1.9.24"
13
17
  gem 'serialport'
14
18
  gem 'google_drive'
15
19
  gem "ruby-trello"
20
+ gem 'ambient_iot', ">= 0.1.1"
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_runtime_dependency 'google_drive', '~> 3.0'
23
23
  spec.add_runtime_dependency 'ruby-trello', '~>2.1'
24
24
 
25
+ spec.required_ruby_version = '>= 2.3.3'
25
26
 
26
27
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
28
  spec.bindir = "exe"
@@ -28,6 +28,7 @@ require 'protocol/protocol'
28
28
 
29
29
  include LadderDrive::Protocol::Mitsubishi
30
30
  include LadderDrive::Protocol::Keyence
31
+ include LadderDrive::Protocol::Omron
31
32
  include LadderDrive::Protocol::Emulator
32
33
 
33
34
  module LadderDrive
@@ -27,6 +27,7 @@ require 'protocol/protocol'
27
27
 
28
28
  include LadderDrive::Protocol::Mitsubishi
29
29
  include LadderDrive::Protocol::Keyence
30
+ include LadderDrive::Protocol::Omron
30
31
  include LadderDrive::Protocol::Emulator
31
32
 
32
33
  module LadderDrive
@@ -125,6 +125,17 @@ module LadderDrive
125
125
  suffixes_for_input.include? @suffix
126
126
  end
127
127
 
128
+ def value
129
+ case @value
130
+ when true
131
+ 1
132
+ when false, nil
133
+ 0
134
+ else
135
+ @value
136
+ end
137
+ end
138
+
128
139
  def bool
129
140
  case @value
130
141
  when Integer
@@ -50,11 +50,6 @@ module Keyence
50
50
  @socket = nil
51
51
  end
52
52
 
53
- def get_bit_from_device device
54
- device = device_by_name device
55
- get_bits_from_device(1, device).first
56
- end
57
-
58
53
  def get_bits_from_device count, device
59
54
  c = (count + 15) / 16
60
55
  words = get_words_from_device c, device
@@ -89,11 +84,6 @@ module Keyence
89
84
  alias :set_bit_to_device :set_bits_to_device
90
85
 
91
86
 
92
- def get_word_from_device device
93
- device = device_by_name device
94
- get_words_from_device(1, device).first
95
- end
96
-
97
87
  def get_words_from_device(count, device)
98
88
  device = local_device device
99
89
  packet = "RDS #{device.name}.H #{count}\r\n"
@@ -79,11 +79,6 @@ module Mitsubishi
79
79
  @comm = nil
80
80
  end
81
81
 
82
- def get_bit_from_device device
83
- device = device_by_name device
84
- get_bits_from_device(1, device).first
85
- end
86
-
87
82
  def get_bits_from_device count, device
88
83
  raise ArgumentError.new("A count #{count} must be between #{available_bits_range.first} and #{available_bits_range.last} for #{__method__}") unless available_bits_range.include? count
89
84
 
@@ -130,11 +125,6 @@ module Mitsubishi
130
125
  end
131
126
  end
132
127
 
133
- def get_word_from_device device
134
- device = device_by_name device
135
- get_words_from_device(1, device).first
136
- end
137
-
138
128
  def get_words_from_device(count, device)
139
129
  raise ArgumentError.new("A count #{count} must be between #{available_words_range.first} and #{available_words_range.last} for #{__method__}") unless available_words_range.include? count
140
130
 
@@ -50,11 +50,6 @@ module Mitsubishi
50
50
  @socket = nil
51
51
  end
52
52
 
53
- def get_bit_from_device device
54
- device = device_by_name device
55
- get_bits_from_device(1, device).first
56
- end
57
-
58
53
  def get_bits_from_device count, device
59
54
  raise ArgumentError.new("A count #{count} must be between #{available_bits_range.first} and #{available_bits_range.last} for #{__method__}") unless available_bits_range.include? count
60
55
 
@@ -108,11 +103,6 @@ module Mitsubishi
108
103
  end
109
104
 
110
105
 
111
- def get_word_from_device device
112
- device = device_by_name device
113
- get_words_from_device(1, device).first
114
- end
115
-
116
106
  def get_words_from_device(count, device)
117
107
  raise ArgumentError.new("A count #{count} must be between #{available_words_range.first} and #{available_words_range.last} for #{__method__}") unless available_bits_range.include? count
118
108
 
@@ -0,0 +1,224 @@
1
+ # The MIT License (MIT)
2
+ #
3
+ # Copyright (c) 2019 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 Omron
27
+
28
+ class CModeProtocol < Protocol
29
+
30
+ attr_accessor :baudrate
31
+ attr_accessor :unit_no
32
+
33
+ DELIMITER = "\r"
34
+ TERMINATOR = "*\r"
35
+ TIMEOUT = 1.0
36
+
37
+ def initialize options={}
38
+ super
39
+ @port = options[:port] || `ls /dev/tty.usb*`.split("\n").map{|l| l.chomp}.first
40
+ @baudrate = 38400
41
+ @unit_no = 0
42
+ @comm = nil
43
+ #prepare_device_map
44
+ end
45
+
46
+ def open
47
+ open!
48
+ rescue
49
+ nil
50
+ end
51
+
52
+ def open!
53
+ return false unless @port
54
+ begin
55
+ # port, baudrate, bits, stop bits, parity(0:none, 1:even, 2:odd)
56
+ @comm ||= SerialPort.new(@port, @baudrate, 7, 2, 1).tap do |s|
57
+ s.read_timeout = (TIMEOUT * 1000.0).to_i
58
+ end
59
+ rescue => e
60
+ p e
61
+ nil
62
+ end
63
+ end
64
+
65
+ def close
66
+ @comm.close if @comm
67
+ @comm = nil
68
+ end
69
+
70
+ def unit_no= no
71
+ @unit_no = [[no, 0].max, 31].min
72
+ end
73
+
74
+ def get_bits_from_device count, device
75
+ device = device_by_name device
76
+
77
+ # convert to the channel device
78
+ from = device.channel_device
79
+ to = (device + count).channel_device
80
+ c = [to - from, 1].max
81
+
82
+ # get value as words
83
+ words = get_words_from_device(c, device)
84
+
85
+ # convert to bit devices
86
+ index = device.bit
87
+ bits = []
88
+ count.times do
89
+ i = index / 16
90
+ b = index % 16
91
+ f = 1 << b
92
+ bits << ((words[i] & f) == f)
93
+ index += 1
94
+ end
95
+ bits
96
+ end
97
+
98
+ def get_words_from_device(count, device)
99
+ device = device_by_name(device).channel_device
100
+
101
+ # make read packet
102
+ packet = read_packet_with device
103
+ packet << "#{device.channel.to_s.rjust(4, '0')}#{count.to_s.rjust(4, '0')}"
104
+ packet << fcs_for(packet).to_s(16).upcase.rjust(2, "0")
105
+ packet << TERMINATOR
106
+ @logger.debug("> #{dump_packet packet}")
107
+
108
+ # send command
109
+ open
110
+ send packet
111
+
112
+ # receive response
113
+ words = []
114
+ terminated = false
115
+ loop do
116
+ res = receive
117
+ data = ""
118
+ if res
119
+ ec = error_code(res)
120
+ raise "Error response: #{ec.to_i(16).rjust(2, '0')}" unless ec == 0
121
+ if res[-2,2] == TERMINATOR
122
+ fcs = fcs_for(res[0..-5])
123
+ raise "Not matched FCS expected #{fcs.to_s(16).rjust(2,'0')}" unless fcs == res[-4,2].to_i(16)
124
+ data = res[7..-5]
125
+ terminated = true
126
+ else res[-1,1] == DELIMITER
127
+ fcs = fcs_for(res[0..-4])
128
+ raise "Not matched FCS expected #{fcs.to_s(16).rjust(2,'0')}" unless fcs == res[-3,2].to_i(16)
129
+ data = res[7..-4]
130
+ end
131
+ len = data.length
132
+ index = 0
133
+ while index < len
134
+ words << data[index,4].to_i(16)
135
+ index += 4
136
+ end
137
+ return words if terminated
138
+ else
139
+ break
140
+ end
141
+ end
142
+ []
143
+ end
144
+
145
+ private
146
+
147
+ def device_by_name name
148
+ case name
149
+ when String
150
+ d = OmronDevice.new name
151
+ d.valid? ? d : nil
152
+ when EscDevice
153
+ local_device_of name
154
+ else
155
+ # it may be already OmronDevice
156
+ name
157
+ end
158
+ end
159
+
160
+ def send packet
161
+ @comm.write(packet)
162
+ @comm.flush
163
+ end
164
+
165
+ def receive
166
+ res = ""
167
+ begin
168
+ Timeout.timeout(TIMEOUT) do
169
+ res = @comm.gets DELIMITER
170
+ =begin
171
+ loop do
172
+ res << @comm.getc# '\r' #gets
173
+ break if res[-1] == '\r'
174
+ end
175
+ =end
176
+ end
177
+ # res
178
+ rescue Timeout::Error
179
+ puts "*** ERROR: TIME OUT : #{res} ***"
180
+ end
181
+ @logger.debug("< #{dump_packet res}")
182
+ res
183
+ end
184
+
185
+
186
+ def read_packet_with device
187
+ packet = "@#{unit_no.to_s.rjust(2, '0')}R"
188
+ case device.suffix
189
+ when "HR"
190
+ packet << "H"
191
+ when "AL"
192
+ packet << "L"
193
+ when "DM", "D"
194
+ packet << "D"
195
+ when "AR"
196
+ packet << "J"
197
+ when "EM", "E"
198
+ packet << "E"
199
+ else
200
+ packet << "R"
201
+ end
202
+ end
203
+
204
+ def fcs_for packet
205
+ fcs = packet.bytes.inject(0) do |a, b|
206
+ a = a ^ b
207
+ end
208
+ fcs = fcs & 0xff
209
+ fcs
210
+ end
211
+
212
+ def error_code packet
213
+ packet[1 + 2 + 2, 2].to_i(16)
214
+ end
215
+
216
+ def dump_packet packet
217
+ packet.inspect
218
+ end
219
+
220
+ end
221
+
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,378 @@
1
+ # The MIT License (MIT)
2
+ #
3
+ # Copyright (c) 2019 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 Omron
27
+
28
+ class FinsTcpProtocol < Protocol
29
+
30
+ attr_accessor :gateway_count
31
+ attr_accessor :destination_network
32
+ attr_accessor :destination_node
33
+ attr_accessor :destination_unit
34
+ attr_accessor :source_network
35
+ attr_accessor :source_node
36
+ attr_accessor :source_unit
37
+
38
+ attr_accessor :ethernet_module
39
+
40
+ attr_accessor :tcp_error_code
41
+
42
+ IOFINS_DESTINATION_NODE_FROM_IP = 0
43
+ IOFINS_SOURCE_AUTO_NODE = 0
44
+
45
+ # Available ethernet module.
46
+ ETHERNET_ETN21 = 0
47
+ ETHERNET_CP1E = 1
48
+ ETHERNET_CP1L = 2
49
+ ETHERNET_CP1H = 3
50
+
51
+ def initialize options={}
52
+ super
53
+ @socket = nil
54
+ @host = options[:host] || "192.168.250.1"
55
+ @port = options[:port] || 9600
56
+ @gateway_count = 3
57
+ @destination_network = 0
58
+ @destination_node = 0
59
+ @destination_unit = 0
60
+ @source_network = 0
61
+ @source_node = IOFINS_SOURCE_AUTO_NODE
62
+ @source_unit = 0
63
+ @ethernet_module = ETHERNET_ETN21
64
+
65
+ @tcp_error_code = 0
66
+
67
+ prepare_device_map
68
+ end
69
+
70
+ def open
71
+ open!
72
+ rescue =>e
73
+ p e
74
+ nil
75
+ end
76
+
77
+ def open!
78
+ if @socket.nil?
79
+ @socket = TCPSocket.open(@host, @port)
80
+ if @socket
81
+ source_node = IOFINS_SOURCE_AUTO_NODE
82
+ query_node
83
+ end
84
+ end
85
+ @socket
86
+ end
87
+
88
+ def close
89
+ @socket.close if @socket
90
+ @socket = nil
91
+ end
92
+
93
+ def tcp_error?
94
+ tcp_error_code != 0
95
+ end
96
+
97
+ def create_query_node
98
+ header = [ "FINS".bytes.to_a, 0, 0, 0, 0xc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].flatten
99
+ header[19] = source_node == IOFINS_SOURCE_AUTO_NODE ? 0 : source_node
100
+ header
101
+ end
102
+
103
+ def create_fins_frame packet
104
+ packet = packet.flatten
105
+ header = [ "FINS".bytes.to_a, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0].flatten
106
+ header[4, 4] = int_to_a(packet.length + 8, 4)
107
+ header + packet
108
+ end
109
+
110
+ def get_bits_from_device(count, device)
111
+ open
112
+ raise ArgumentError.new("A count #{count} must be between #{available_bits_range.first} and #{available_bits_range.last} for #{__method__}") unless available_bits_range.include? count
113
+
114
+ device = device_by_name device
115
+ raise ArgumentError.new("#{device.name} is not bit device!") unless device.bit_device?
116
+
117
+ command = [1, 1]
118
+ command << device_to_a(device)
119
+ command << int_to_a(count, 2)
120
+
121
+ send_packet create_fins_frame(fins_header + command)
122
+ res = receive
123
+
124
+ count.times.inject([]) do |a, i|
125
+ a << (res[16 + 10 + 4 + i] == 0 ? false : true)
126
+ a
127
+ end
128
+ end
129
+
130
+ def get_words_from_device(count, device)
131
+ open
132
+ raise ArgumentError.new("A count #{count} must be between #{available_words_range.first} and #{available_words_range.last} for #{__method__}") unless available_words_range.include? count
133
+
134
+ device = device_by_name device
135
+ device = device.channel_device
136
+
137
+ command = [1, 1]
138
+ command << device_to_a(device)
139
+ command << int_to_a(count, 2)
140
+
141
+ send_packet create_fins_frame(fins_header + command)
142
+ res = receive
143
+ count.times.inject([]) do |a, i|
144
+ a << to_int(res[16 + 10 + 4 + i * 2, 2])
145
+ a
146
+ end
147
+ end
148
+
149
+ def set_bits_to_device(bits, device)
150
+ open
151
+ count = bits.size
152
+ raise ArgumentError.new("A count #{count} must be between #{available_bits_range.first} and #{available_bits_range.last} for #{__method__}") unless available_bits_range.include? count
153
+
154
+ device = device_by_name device
155
+ raise ArgumentError.new("#{device.name} is not bit device!") unless device.bit_device?
156
+
157
+ command = [1, 2]
158
+ command << device_to_a(device)
159
+ command << int_to_a(count, 2)
160
+ bits.each do |b|
161
+ command << (b ? 1 : 0)
162
+ end
163
+
164
+ send_packet create_fins_frame(fins_header + command)
165
+ res = receive
166
+ end
167
+
168
+ def set_words_to_device(words, device)
169
+ open
170
+ count = words.size
171
+ raise ArgumentError.new("A count #{count} must be between #{available_words_range.first} and #{available_words_range.last} for #{__method__}") unless available_words_range.include? count
172
+
173
+ device = device_by_name device
174
+ device = device.channel_device
175
+
176
+ command = [1, 2]
177
+ command << device_to_a(device)
178
+ command << int_to_a(count, 2)
179
+ words.each do |w|
180
+ command << int_to_a(w, 2)
181
+ end
182
+
183
+ send_packet create_fins_frame(fins_header + command)
184
+ res = receive
185
+ end
186
+
187
+ def query_node
188
+ send_packet create_query_node
189
+ res = receive
190
+ self.source_node = res[19]
191
+ end
192
+
193
+
194
+ def send_packet packet
195
+ @socket.write(packet.flatten.pack("c*"))
196
+ @socket.flush
197
+ @logger.debug("> #{dump_packet packet}")
198
+ end
199
+
200
+ def receive
201
+ res = []
202
+ len = 0
203
+ begin
204
+ Timeout.timeout(5.0) do
205
+ loop do
206
+ c = @socket.getc
207
+ next if c.nil? || c == ""
208
+
209
+ res << c.bytes.first
210
+ next if res.length < 8
211
+
212
+ len = to_int(res[4, 4])
213
+ next if res.length < 8 + len
214
+
215
+ tcp_command = to_int(res[8, 4])
216
+ case tcp_command
217
+ when 3 # ERROR
218
+ raise "Invalidate tcp header: #{res}"
219
+ end
220
+ break
221
+ end
222
+ end
223
+ raise "Response error code: #{res[15]}" unless res[15] == 0
224
+ res
225
+ end
226
+ @logger.debug("< #{dump_packet res}")
227
+ res
228
+ end
229
+
230
+ # max length:
231
+ # CS1W-ETN21, CJ1W-ETN21 : 2012
232
+ # CP1W-CIF41 option board : 540 (1004 if cpu is CP1L/H)
233
+
234
+ def available_bits_range device=nil
235
+ case ethernet_module
236
+ when ETHERNET_ETN21
237
+ 1..(2012 - 8)
238
+ when ETHERNET_CP1E
239
+ 1..(540 - 8)
240
+ when ETHERNET_CP1L, ETHERNET_CP1H
241
+ 1..(1004 - 8)
242
+ else
243
+ 0..0
244
+ end
245
+ end
246
+
247
+ def available_words_range device=nil
248
+ case ethernet_module
249
+ when ETHERNET_ETN21
250
+ 1..((2012 - 8) / 2)
251
+ when ETHERNET_CP1E
252
+ 1..((540 - 8) / 2)
253
+ when ETHERNET_CP1L, ETHERNET_CP1H
254
+ 1..((1004 - 8) / 2)
255
+ else
256
+ 0..0
257
+ end
258
+ end
259
+
260
+ def device_by_name name
261
+ case name
262
+ when String
263
+ d = OmronDevice.new name
264
+ d.valid? ? d : nil
265
+ when EscDevice
266
+ local_device_of name
267
+ else
268
+ # it may be already OmronDevice
269
+ name
270
+ end
271
+ end
272
+
273
+ private
274
+
275
+ def fins_header
276
+ buf = [
277
+ 0x80, # ICF
278
+ 0x00, # RSV
279
+ 0x02, # GCT
280
+ 0x00, # DNA
281
+ 0x01, # DA1
282
+ 0x00, # DA2
283
+ 0x00, # SNA
284
+ 0x01, # SA1
285
+ 0x00, # SA2
286
+ 0x00, # SID
287
+ ]
288
+ buf[2] = gateway_count - 1
289
+ buf[3] = destination_network
290
+ if destination_node == IOFINS_DESTINATION_NODE_FROM_IP
291
+ buf[4] = destination_ipv4.split(".").last.to_i
292
+ else
293
+ buf[4] = destination_node
294
+ end
295
+ buf[7] = source_node
296
+ buf[8] = source_unit
297
+
298
+ buf
299
+ end
300
+
301
+ def fins_tcp_cmnd_header
302
+ header = [ "FINS".bytes.to_a, 0, 0, 0, 0xc, 0, 0, 0, 2, 0, 0, 0, 0].flatten
303
+ header[19] = source_node == IOFINS_SOURCE_AUTO_NODE ? 0 : source_node
304
+ header
305
+ end
306
+
307
+ def device_code_of device
308
+ @@bit_codes ||= { nil => 0x30, "" => 0x30, "W" => 0x31, "H" => 0x32, "A" => 0x33, "T" => 0x09, "C" => 0x09, "D" => 0x02, "E" => 0x0a, "TK" => 0x06 }
309
+ @@word_codes ||= { nil => 0xB0, "" => 0xB0, "W" => 0xB1, "H" => 0xB2, "A" => 0xB3, "TIM" => 0x89, "CNT" => 0x89, "D" => 0x82, "E" => 0x98, "DR" => 0xbc }
310
+ if device.bit_device?
311
+ @@bit_codes[device.suffix]
312
+ else
313
+ @@word_codes[device.suffix]
314
+ end
315
+ end
316
+
317
+ def device_to_a device
318
+ a = []
319
+ a << device_code_of(device)
320
+ a << int_to_a(device.channel, 2)
321
+ a << (device.bit_device? ? (device.bit || 0) : 0)
322
+ a.flatten
323
+ end
324
+
325
+
326
+ # FIXME: It's dummy currently.
327
+ def prepare_device_map
328
+ @conv_dev_dict ||= begin
329
+ h = {}
330
+ [
331
+ ["X", "0.0", 1024],
332
+ ["Y", "400.0", 1024],
333
+ ["M", "M0.0", 1024],
334
+ ["C", "C0", 256],
335
+ ["T", "T0", 256],
336
+ ["L", "H0.0", 1024],
337
+ ["SC", "M400.0", 1024],
338
+ ["D", "D0", 1024],
339
+ ["H", "D1024", 1024],
340
+ ["SD", "D2048", 1024],
341
+ ["PRG", "D3072", 1024] # ..D4095
342
+ ].each do |s,d,c|
343
+ h[s] = [OmronDevice.new(d), c]
344
+ end
345
+ h
346
+ end
347
+ end
348
+
349
+ def int_to_a value, size
350
+ a = []
351
+ (size - 1).downto 0 do |i|
352
+ a << ((value >> (i * 8)) & 0xff)
353
+ end
354
+ a
355
+ end
356
+
357
+ def to_int a
358
+ v = 0
359
+ a.each do |e|
360
+ v <<= 8
361
+ v += e
362
+ end
363
+ v
364
+ end
365
+
366
+ def dump_packet packet
367
+ a =
368
+ packet.map{|e|
369
+ e.to_s(16).rjust(2, '0')
370
+ }
371
+ "[#{a.join(', ')}]"
372
+ end
373
+
374
+ end
375
+
376
+ end
377
+ end
378
+ end