Class: PlcAccess::Protocol::Omron::FinsTcpProtocol

Inherits:
Protocol
  • Object
show all
Defined in:
lib/plc_access/protocol/omron/fins_tcp_protocol.rb

Constant Summary collapse

IOFINS_DESTINATION_NODE_FROM_IP =
0
IOFINS_SOURCE_AUTO_NODE =
0
ETHERNET_ETN21 =

Available ethernet module.

0
ETHERNET_CP1E =
1
ETHERNET_CP1L =
2
ETHERNET_CP1H =
3
TIMEOUT =
5.0

Instance Attribute Summary collapse

Attributes inherited from Protocol

#host, #log_level, #port

Instance Method Summary collapse

Methods inherited from Protocol

#[], #[]=, #destination_ipv4, #get_bit_from_device, #get_from_devices, #get_word_from_device, #self_ipv4, #set_bit_to_device, #set_to_devices, #set_word_to_device

Constructor Details

#initialize(options = {}) ⇒ FinsTcpProtocol

Returns a new instance of FinsTcpProtocol.


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 44

def initialize(options = {})
  super
  @socket = nil
  @host = options[:host] || '192.168.250.1'
  @port = options[:port] || 9600
  @gateway_count = 3
  @destination_network = 0
  @destination_node = 0
  @destination_unit = 0
  @source_network = 0
  @source_node = IOFINS_SOURCE_AUTO_NODE
  @source_unit = 0
  @ethernet_module = ETHERNET_ETN21

  @tcp_error_code = 0
end

Instance Attribute Details

#destination_networkObject

Returns the value of attribute destination_network.


30
31
32
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 30

def destination_network
  @destination_network
end

#destination_nodeObject

Returns the value of attribute destination_node.


30
31
32
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 30

def destination_node
  @destination_node
end

#destination_unitObject

Returns the value of attribute destination_unit.


30
31
32
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 30

def destination_unit
  @destination_unit
end

#ethernet_moduleObject

Returns the value of attribute ethernet_module.


30
31
32
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 30

def ethernet_module
  @ethernet_module
end

#gateway_countObject

Returns the value of attribute gateway_count.


30
31
32
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 30

def gateway_count
  @gateway_count
end

#source_networkObject

Returns the value of attribute source_network.


30
31
32
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 30

def source_network
  @source_network
end

#source_nodeObject

Returns the value of attribute source_node.


30
31
32
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 30

def source_node
  @source_node
end

#source_unitObject

Returns the value of attribute source_unit.


30
31
32
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 30

def source_unit
  @source_unit
end

#tcp_error_codeObject

Returns the value of attribute tcp_error_code.


30
31
32
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 30

def tcp_error_code
  @tcp_error_code
end

Instance Method Details

#available_bits_range(_device = nil) ⇒ Object

max length:

CS1W-ETN21, CJ1W-ETN21   : 2012
CP1W-CIF41 option board  : 540 (1004 if cpu is CP1L/H)

235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 235

def available_bits_range(_device = nil)
  case ethernet_module
  when ETHERNET_ETN21
    1..(2012 - 8)
  when ETHERNET_CP1E
    1..(540 - 8)
  when ETHERNET_CP1L, ETHERNET_CP1H
    1..(1004 - 8)
  else
    0..0
  end
end

#available_words_range(_device = nil) ⇒ Object


248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 248

def available_words_range(_device = nil)
  case ethernet_module
  when ETHERNET_ETN21
    1..((2012 - 8) / 2)
  when ETHERNET_CP1E
    1..((540 - 8) / 2)
  when ETHERNET_CP1L, ETHERNET_CP1H
    1..((1004 - 8) / 2)
  else
    0..0
  end
end

#closeObject


79
80
81
82
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 79

def close
  @socket&.close
  @socket = nil
end

#create_fins_frame(packet) ⇒ Object


94
95
96
97
98
99
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 94

def create_fins_frame(packet)
  packet = packet.flatten
  header = ['FINS'.bytes.to_a, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0].flatten
  header[4, 4] = int_to_a(packet.length + 8, 4)
  header + packet
end

#create_query_nodeObject


88
89
90
91
92
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 88

def create_query_node
  header = ['FINS'.bytes.to_a, 0, 0, 0, 0xc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].flatten
  header[19] = source_node == IOFINS_SOURCE_AUTO_NODE ? 0 : source_node
  header
end

#device_by_name(name) ⇒ Object


261
262
263
264
265
266
267
268
269
270
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 261

def device_by_name(name)
  case name
  when String
    d = OmronDevice.new name
    d.valid? ? d : nil
  else
    # it may be already OmronDevice
    name
  end
end

#get_bits_from_device(count, device) ⇒ Object

Raises:

  • (ArgumentError)

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 101

def get_bits_from_device(count, device)
  open
  unless available_bits_range.include? count
    raise ArgumentError,
          "A count #{count} must be between #{available_bits_range.first} and #{available_bits_range.last} for #{__method__}"
  end

  device = device_by_name device
  raise ArgumentError, "#{device.name} is not bit device!" unless device.bit_device?

  command = [1, 1]
  command << device_to_a(device)
  command << int_to_a(count, 2)

  send_packet create_fins_frame(fins_header + command)
  res = receive

  count.times.each_with_object([]) do |i, a|
    a << (res[16 + 10 + 4 + i] != 0)
  end
end

#get_words_from_device(count, device) ⇒ Object


123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 123

def get_words_from_device(count, device)
  open
  unless available_words_range.include? count
    raise ArgumentError,
          "A count #{count} must be between #{available_words_range.first} and #{available_words_range.last} for #{__method__}"
  end

  device = device_by_name device
  device = device.channel_device

  command = [1, 1]
  command << device_to_a(device)
  command << int_to_a(count, 2)

  send_packet create_fins_frame(fins_header + command)
  res = receive
  count.times.each_with_object([]) do |i, a|
    a << to_int(res[16 + 10 + 4 + i * 2, 2])
  end
end

#openObject


61
62
63
64
65
66
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 61

def open
  open!
rescue StandardError => e
  p e
  nil
end

#open!Object


68
69
70
71
72
73
74
75
76
77
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 68

def open!
  if @socket.nil?
    @socket = TCPSocket.open(@host, @port)
    if @socket
      self.source_node = IOFINS_SOURCE_AUTO_NODE
      query_node
    end
  end
  @socket
end

#query_nodeObject


188
189
190
191
192
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 188

def query_node
  send_packet create_query_node
  res = receive
  self.source_node = res[19]
end

#receiveObject


200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 200

def receive
  res = []
  len = 0
  begin
    Timeout.timeout(TIMEOUT) do
      loop do
        c = @socket.getc
        next if c.nil? || c == ''

        res << c.bytes.first
        next if res.length < 8

        len = to_int(res[4, 4])
        next if res.length < 8 + len

        tcp_command = to_int(res[8, 4])
        case tcp_command
        when 3 # ERROR
          raise "Invalidate tcp header: #{res}"
        end
        break
      end
    end
    raise "Response error code: #{res[15]}" unless (res[15]).zero?

    res
  end
  @logger.debug("< #{dump_packet res}")
  res
end

#send_packet(packet) ⇒ Object


194
195
196
197
198
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 194

def send_packet(packet)
  @socket.write(packet.flatten.pack('c*'))
  @socket.flush
  @logger.debug("> #{dump_packet packet}")
end

#set_bits_to_device(bits, device) ⇒ Object

Raises:

  • (ArgumentError)

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 144

def set_bits_to_device(bits, device)
  open
  count = bits.size
  unless available_bits_range.include? count
    raise ArgumentError,
          "A count #{count} must be between #{available_bits_range.first} and #{available_bits_range.last} for #{__method__}"
  end

  device = device_by_name device
  raise ArgumentError, "#{device.name} is not bit device!" unless device.bit_device?

  command = [1, 2]
  command << device_to_a(device)
  command << int_to_a(count, 2)
  bits.each do |b|
    command << (b ? 1 : 0)
  end

  send_packet create_fins_frame(fins_header + command)
  receive
end

#set_words_to_device(words, device) ⇒ Object


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 166

def set_words_to_device(words, device)
  open
  count = words.size
  unless available_words_range.include? count
    raise ArgumentError,
          "A count #{count} must be between #{available_words_range.first} and #{available_words_range.last} for #{__method__}"
  end

  device = device_by_name device
  device = device.channel_device

  command = [1, 2]
  command << device_to_a(device)
  command << int_to_a(count, 2)
  words.each do |w|
    command << int_to_a(w, 2)
  end

  send_packet create_fins_frame(fins_header + command)
  receive
end

#tcp_error?Boolean

Returns:

  • (Boolean)

84
85
86
# File 'lib/plc_access/protocol/omron/fins_tcp_protocol.rb', line 84

def tcp_error?
  tcp_error_code != 0
end