module ModBus::RTU

Constants

CrcHiTable
CrcLoTable

Private Instance Methods

clean_input_buff() click to toggle source
# File lib/rmodbus/rtu.rb, line 32
def clean_input_buff
  # empty the input buffer
  if @io.class.public_method_defined? :flush_input
    @io.flush_input
  else
    @io.flush
  end
end
crc16(msg) click to toggle source

Calc CRC16 for massage

# File lib/rmodbus/rtu.rb, line 111
def crc16(msg)
  crc_lo = 0xff
  crc_hi = 0xff

  msg.unpack('c*').each do |byte|
    i = crc_hi ^ byte
    crc_hi = crc_lo ^ CrcHiTable[i]
    crc_lo = CrcLoTable[i]
  end

  return ((crc_hi << 8) + crc_lo)
end
read_rtu_pdu() click to toggle source
# File lib/rmodbus/rtu.rb, line 51
def read_rtu_pdu
  msg = read_rtu_response(@io)

  log "Rx (#{msg.size} bytes): " + logging_bytes(msg)

  if msg.getbyte(0) == @uid
    return msg[1..-3] if msg[-2,2].unpack('n')[0] == crc16(msg[0..-3])
    log "Ignore package: don't match CRC"
  else
    log "Ignore package: don't match uid ID"
  end
  loop do
    #waite timeout
    sleep(0.1)
  end
end
read_rtu_request(io) click to toggle source
# File lib/rmodbus/rtu.rb, line 68
def read_rtu_request(io)
                    # Read the slave_id and function code
                    msg = io.read(2)

                    # If msg is nil, then our client never sent us anything and it's time to disconnect
                    return if msg.nil?

                    function_code = msg.getbyte(1)
                    if [1, 2, 3, 4, 5, 6].include?(function_code)
                            # read 6 more bytes and return the message total message
                            msg += io.read(6)
                    elsif [15, 16].include?(function_code)
                            # Read in first register, register count, and data bytes
                            msg += io.read(5)
                            # Read in however much data we need to + 2 CRC bytes
                            msg += io.read(msg.getbyte(6) + 2)
                    else
                            raise ModBus::Errors::IllegalFunction, "Illegal function: #{function_code}"
                    end

                    log "Server RX (#{msg.size} bytes): #{logging_bytes(msg)}"

                    msg
            end
read_rtu_response(io) click to toggle source

We have to read specific amounts of numbers of bytes from the network depending on the function code and content

# File lib/rmodbus/rtu.rb, line 6
def read_rtu_response(io)
        # Read the slave_id and function code
  msg = nil
  while msg.nil?
          msg = io.read(2)
  end

  function_code = msg.getbyte(1)
  case function_code
    when 1,2,3,4 then
      # read the third byte to find out how much more
      # we need to read + CRC
      msg += io.read(1)
      msg += io.read(msg.getbyte(2)+2)
    when 5,6,15,16 then
      # We just read in an additional 6 bytes
      msg += io.read(6)
    when 22 then
      msg += io.read(8)
    when 0x80..0xff then
      msg += io.read(3)
    else
      raise ModBus::Errors::IllegalFunction, "Illegal function: #{function_code}"
  end
end
send_rtu_pdu(pdu) click to toggle source
# File lib/rmodbus/rtu.rb, line 41
def send_rtu_pdu(pdu)
  msg = @uid.chr + pdu
  msg << crc16(msg).to_word

  clean_input_buff
  @io.write msg

  log "Tx (#{msg.size} bytes): " + logging_bytes(msg)
end
serv_rtu_requests(io) { |msg| ... } click to toggle source
# File lib/rmodbus/rtu.rb, line 93
def serv_rtu_requests(io, &blk)
  loop do
    # read the RTU message
    msg = read_rtu_request(io)

    next if msg.nil?

    if msg.getbyte(0) == @uid and msg[-2,2].unpack('n')[0] == crc16(msg[0..-3])
      pdu = yield msg
      resp = @uid.chr + pdu
      resp << crc16(resp).to_word
      log "Server TX (#{resp.size} bytes): #{logging_bytes(resp)}"
      io.write resp
                end
        end
end