Class: LadderDrive::Protocol::Mitsubishi::FxProtocol

Inherits:
Protocol
  • Object
show all
Defined in:
lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb

Constant Summary collapse

STX =
"\u0002"
ETX =
"\u0003"
EOT =
"\u0004"
ENQ =
"\u0005"
ACK =
"\u0006"
LF =
"\u000a"
CR =
"\u000d"
NAK =
"\u0015"
DELIMITER =
"\r\n"

Constants inherited from Protocol

Protocol::TIMEOUT

Instance Attribute Summary collapse

Attributes inherited from Protocol

#host, #port

Instance Method Summary collapse

Methods inherited from Protocol

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

Constructor Details

#initialize(options = {}) ⇒ FxProtocol

Returns a new instance of FxProtocol.



46
47
48
49
50
51
52
53
54
55
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 46

def initialize options={}
  super
  @port = options[:port] || `ls /dev/tty.usb*`.split("\n").map{|l| l.chomp}.first
  @pc_no = 0xff
  @baudrate = 19200
  @station_no = 0
  @wait_time = 0
  @comm = nil
  #prepare_device_map
end

Instance Attribute Details

#baudrateObject

Returns the value of attribute baudrate.



31
32
33
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 31

def baudrate
  @baudrate
end

#pc_noObject

Returns the value of attribute pc_no.



30
31
32
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 30

def pc_no
  @pc_no
end

#station_noObject

Returns the value of attribute station_no.



32
33
34
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 32

def station_no
  @station_no
end

#wait_timeObject

Returns the value of attribute wait_time.



33
34
35
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 33

def wait_time
  @wait_time
end

Instance Method Details

#available_bits_range(device = nil) ⇒ Object



201
202
203
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 201

def available_bits_range device=nil
  1..256
end

#available_words_range(device = nil) ⇒ Object



205
206
207
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 205

def available_words_range device=nil
  1..64
end

#body_for_get_bit_from_deivce(device) ⇒ Object



209
210
211
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 209

def body_for_get_bit_from_deivce device
  body_for_get_bits_from_device 1, device
end

#body_for_get_bits_from_device(count, device) ⇒ Object



213
214
215
216
217
218
219
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 213

def body_for_get_bits_from_device count, device
  body = header_with_command "BR"
  body += "#{device.name}#{count.to_s(16).rjust(2, '0')}"
  body += check_sum(body)
  body += DELIMITER
  body.upcase
end

#body_for_get_words_from_device(count, device) ⇒ Object



221
222
223
224
225
226
227
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 221

def body_for_get_words_from_device count, device
  body = header_with_command "WR"
  body += "#{device.name}#{count.to_s(16).rjust(2, '0')}"
  body += check_sum(body)
  body += DELIMITER
  body.upcase
end

#body_for_set_bits_to_device(bits, device) ⇒ Object Also known as: body_for_set_bit_to_device



229
230
231
232
233
234
235
236
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 229

def body_for_set_bits_to_device bits, device
  body = header_with_command "BW"
  body += "#{device.name}#{bits.count.to_s(16).rjust(2, '0')}"
  body += bits.map{|b| b ? "1" : "0"}.join("")
  body += check_sum(body)
  body += DELIMITER
  body.upcase
end

#body_for_set_words_to_device(words, device) ⇒ Object



239
240
241
242
243
244
245
246
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 239

def body_for_set_words_to_device words, device
  body = header_with_command "WW"
  body += "#{device.name}#{words.count.to_s(16).rjust(2, '0')}"
  body += words.map{|w| w.to_s(16).rjust(4, "0")}.join("")
  body += check_sum(body)
  body += DELIMITER
  body.upcase
end

#closeObject



76
77
78
79
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 76

def close
  @comm.close if @comm
  @comm = nil
end

#device_by_name(name) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 173

def device_by_name name
  case name
  when String
    d = FxDevice.new name
    d.valid? ? d : nil
  when EscDevice
    local_device_of name
  else
    # it may be already QDevice
    name
  end
end

#dump_packet(packet) ⇒ Object

def data_for_device device

  a = data_for_int device.number
  a[3] = device.suffix_code
  a
end

def data_for_short value
  [value].pack("v").unpack("C*")
end

def data_for_int value
  [value].pack("V").unpack("C*")
end


265
266
267
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 265

def dump_packet packet
  packet.inspect
end

#get_bits_from_device(count, device) ⇒ Object

Raises:

  • (ArgumentError)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 81

def get_bits_from_device count, device
  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

  device = device_by_name device
  packet = body_for_get_bits_from_device(count, device) + DELIMITER
  @logger.debug("> #{dump_packet packet}")
  open
  @comm.write(packet)
  @comm.flush
  res = receive
  bits = []

  if res
    if check_sum(res[0..-5]) == res[-4,2]
      bits =
        res[5..-6].each_char.map do |c|
          c == "1" ? true : false
        end
    else
    end
  end
  @logger.debug("> #{dump_packet ack_packet}")
  @comm.write(ack_packet)
  @logger.debug("get #{device.name} => #{bits}")

  bits
end

#get_words_from_device(count, device) ⇒ Object

Raises:

  • (ArgumentError)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 127

def get_words_from_device(count, device)
  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

  device = device_by_name device
  packet = body_for_get_words_from_device(count, device) + DELIMITER
  @logger.debug("> #{dump_packet packet}")
  open
  @comm.write(packet)
  @comm.flush
  res = receive
  words = []

  if res
    if check_sum(res[0..-5]) == res[-4,2]
      words =
        res[5..-6].scan(/.{4}/).map do |v|
          v.to_i(16)
        end
    else
    end
  end
  @logger.debug("> #{dump_packet ack_packet}")
  @comm.write(ack_packet)
  @logger.debug("get #{device.name} => #{words}")

  words
end

#openObject



57
58
59
60
61
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 57

def open
  open!
rescue
  nil
end

#open!Object



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 63

def open!
  return false unless @port
  begin
    # port, baudrate, bits, stop bits, parity(0:none, 1:even, 2:odd)
    @comm ||= SerialPort.new(@port, @baudrate, 7, 1, 2).tap do |s|
      s.read_timeout = (TIMEOUT * 1000.0).to_i
    end
  rescue => e
    p e
    nil
  end
end

#receiveObject



187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 187

def receive
  res = ""
  begin
    Timeout.timeout(TIMEOUT) do
      res = @comm.gets
    end
    res
  rescue Timeout::Error
    puts "*** ERROR: TIME OUT : #{res} ***"
  end
  @logger.debug("< #{dump_packet res}")
  res
end

#set_bits_to_device(bits, device) ⇒ Object

Raises:

  • (ArgumentError)


109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 109

def set_bits_to_device bits, device
  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? bits.size

  device = device_by_name device
  packet = body_for_set_bits_to_device(bits, device)
  @logger.debug("> #{dump_packet packet}")
  open
  @comm.write(packet)
  @comm.flush
  res = receive
  @logger.debug("set #{bits} to:#{device.name}")

  # error checking
  unless res == ack_packet
    raise "ERROR: return #{res} for set_bits_to_device(#{bits}, #{device.name})"
  end
end

#set_words_to_device(words, device) ⇒ Object

Raises:

  • (ArgumentError)


155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb', line 155

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

  device = device_by_name device
  packet = body_for_set_words_to_device(words, device)
  @logger.debug("> #{dump_packet packet}")
  open
  @comm.write(packet)
  @comm.flush
  res = receive
  @logger.debug("set #{words} to: #{device.name}")

  # error checking
  unless res == ack_packet
    raise "ERROR: return #{res} for set_bits_to_device(#{words}, #{device.name})"
  end
end