class LadderDrive::Protocol::Mitsubishi::FxProtocol

Constants

ACK
CR
DELIMITER
ENQ
EOT
ETX
LF
NAK
STX

Attributes

baudrate[RW]
pc_no[RW]
station_no[RW]
wait_time[RW]

Public Class Methods

new(options={}) click to toggle source
Calls superclass method
# 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

Public Instance Methods

available_bits_range(device=nil) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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_bit_to_device(bits, device)
body_for_set_bits_to_device(bits, device) click to toggle source
# 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
Also aliased as: body_for_set_bit_to_device
body_for_set_words_to_device(words, device) click to toggle source
# 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
close() click to toggle source
# File lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb, line 76
def close
  @comm.close if @comm
  @comm = nil
end
device_by_name(name) click to toggle source
# 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) click to toggle source

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

# File lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb, line 265
def dump_packet packet
  packet.inspect
end
get_bits_from_device(count, device) click to toggle source
# 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) click to toggle source
# 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
open() click to toggle source
# File lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb, line 57
def open
  open!
rescue
  nil
end
open!() click to toggle source
# 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
receive() click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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

Private Instance Methods

ack_packet() click to toggle source
# File lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb, line 313
def ack_packet
  "#{ACK}#{station_no.to_s.rjust(2,'0')}#{pc_no.to_s(16).rjust(2, '0')}#{DELIMITER}".upcase
end
check_sum(packet) click to toggle source

def local_device_of device

return device if device.is_a? QDevice
d, c = @conv_dev_dict[device.suffix]
return nil unless device.number < c
ld = QDevice.new(d.suffix, d.number + device.number)
device_by_name ld.name

end

# File lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb, line 305
def check_sum packet
  packet[1..-1].upcase.unpack("C*").inject(0){|s,c| s + c}.to_s(16).rjust(2, "0")[-2, 2].upcase
end
header_with_command(command) click to toggle source
# File lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb, line 309
def header_with_command command
  "#{ENQ}#{station_no.to_s.rjust(2,'0')}#{pc_no.to_s(16).rjust(2, '0')}#{command}#{wait_time.to_s}".upcase
end