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)
32 33 34 35 36 37 38 39 |
# 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) ⇒ Object (private)
Calc CRC16 for massage
117 118 119 |
# File 'lib/rmodbus/rtu.rb', line 117 def crc16(msg) Digest::CRC16Modbus.checksum(msg) end |
#read(io, len) ⇒ Object (private)
41 42 43 44 45 46 47 48 49 |
# File 'lib/rmodbus/rtu.rb', line 41 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)
51 52 53 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 |
# File 'lib/rmodbus/rtu.rb', line 51 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].unpack("S<").first # 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 = is_response ? parse_response(msg.getbyte(offset + 1), msg[(offset + 1)..-3]) : parse_request(msg.getbyte(offset + 1), msg[(offset + 1)..-3]) 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
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/rmodbus/rtu.rb', line 9 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 then # 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 then # We just read in an additional 6 bytes msg += read(io, 6) when 22 then msg += read(io, 8) when 0x80..0xff then msg += read(io, 3) else raise ModBus::Errors::IllegalFunction, "Illegal function: #{function_code}" end end |
#serve(io) ⇒ Object (private)
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/rmodbus/rtu.rb', line 98 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 |