Module: ModBus::RTU
- Included in:
- RTUClient, RTUServer, RTUSlave, RTUViaTCPServer
- Defined in:
- lib/rmodbus/rtu.rb
Instance Method Summary collapse
- #clean_input_buff ⇒ Object private
-
#crc16(msg) ⇒ Object
private
Calc CRC16 for massage.
- #read(io, len) ⇒ Object private
- #read_rtu_request(io) ⇒ Object private
-
#read_rtu_response(io) ⇒ Object
private
We have to read specific amounts of numbers of bytes from the network depending on the function code and content.
- #serve(io) ⇒ Object private
Instance Method Details
#clean_input_buff ⇒ Object (private)
34 35 36 37 38 39 40 41 |
# File 'lib/rmodbus/rtu.rb', line 34 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) ⇒ Object (private)
Calc CRC16 for massage
124 125 126 |
# File 'lib/rmodbus/rtu.rb', line 124 def crc16(msg) Digest::CRC16Modbus.checksum(msg) end |
#read(io, len) ⇒ Object (private)
43 44 45 46 47 48 49 50 51 52 |
# File 'lib/rmodbus/rtu.rb', line 43 def read(io, len) result = +"" loop do this_iter = io.read(len - result.length) result.concat(this_iter) if this_iter return result if result.length == len io.wait_readable end end |
#read_rtu_request(io) ⇒ Object (private)
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/rmodbus/rtu.rb', line 54 def read_rtu_request(io) # Every message is a minimum of 4 bytes (slave id, function code, crc16) msg = read(io, 4) # If msg is nil, then our client never sent us anything and it's time to disconnect return if msg.nil? loop do offset = 0 crc = msg[-2..-1].unpack1("S<") # scan the bytestream for a valid CRC loop do break if offset >= msg.length - 3 calculated_crc = Digest::CRC16Modbus.checksum(msg[offset..-3]) if crc == calculated_crc is_response = (msg.getbyte(offset + 1) & 0x80 == 0x80) || (msg.getbyte(offset) == @last_req_uid && msg.getbyte(offset + 1) == @last_req_func && @last_req_timestamp && Time.now.to_f - @last_req_timestamp < 5) params = if is_response parse_response(msg.getbyte(offset + 1), msg[(offset + 1)..-3]) else parse_request(msg.getbyte(offset + 1), msg[(offset + 1)..-3]) end unless params.nil? if is_response @last_req_uid = @last_req_func = @last_req_timestamp = nil else @last_req_uid = msg.getbyte(offset) @last_req_func = msg.getbyte(offset + 1) @last_req_timestamp = Time.now.to_f end log "Server RX discarding #{offset} bytes: #{logging_bytes(msg[0...offset])}" if offset != 0 log "Server RX (#{msg.size - offset} bytes): #{logging_bytes(msg[offset..-1])}" return [msg.getbyte(offset), msg.getbyte(offset + 1), params, msg[offset + 1..-3], is_response] end end offset += 1 end msg.concat(read(io, 1)) # maximum message size is 256, so that's as far as we have to # be able to see at once msg = msg[1..-1] if msg.length > 256 end end |
#read_rtu_response(io) ⇒ Object (private)
We have to read specific amounts of numbers of bytes from the network depending on the function code and content
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/rmodbus/rtu.rb', line 11 def read_rtu_response(io) # Read the slave_id and function code msg = read(io, 2) function_code = msg.getbyte(1) case function_code when 1, 2, 3, 4 # read the third byte to find out how much more # we need to read + CRC msg += read(io, 1) msg + read(io, msg.getbyte(2) + 2) when 5, 6, 15, 16 # We just read in an additional 6 bytes msg + read(io, 6) when 22 msg + read(io, 8) when 0x80..0xff msg + read(io, 3) else raise ModBus::Errors::IllegalFunction, "Illegal function: #{function_code}" end end |
#serve(io) ⇒ Object (private)
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/rmodbus/rtu.rb', line 105 def serve(io) loop do # read the RTU message uid, func, params, pdu, is_response = read_rtu_request(io) next if uid.nil? pdu = exec_req(uid, func, params, pdu, is_response: is_response) next unless pdu @last_req_uid = @last_req_func = @last_req_timestamp = nil resp = uid.chr + pdu resp << [crc16(resp)].pack("S<") log "Server TX (#{resp.size} bytes): #{logging_bytes(resp)}" io.write resp end end |