Module: ModBus::RTU

Included in:
RTUClient, RTUServer, RTUSlave, RTUViaTCPClient, RTUViaTCPServer, RTUViaTCPSlave
Defined in:
lib/rmodbus/rtu.rb

Constant Summary

CrcHiTable =
[
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40]
CrcLoTable =
[
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40]

Instance Method Summary collapse

Instance Method Details

#clean_input_buffObject (private)



47
48
49
50
# File 'lib/rmodbus/rtu.rb', line 47

def clean_input_buff
  # empty the input buffer
  @io.flush_input
end

#crc16(msg) ⇒ Object (private)

Calc CRC16 for massage



122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rmodbus/rtu.rb', line 122

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_pduObject (private)



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/rmodbus/rtu.rb', line 62

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) ⇒ Object (private)



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/rmodbus/rtu.rb', line 79

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) ⇒ Object (private)

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



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/rmodbus/rtu.rb', line 21

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) ⇒ Object (private)



52
53
54
55
56
57
58
59
60
# File 'lib/rmodbus/rtu.rb', line 52

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, &blk) ⇒ Object (private)



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/rmodbus/rtu.rb', line 104

def serv_rtu_requests(io, &blk)
  loop do
    # read the RTU message
    msg = read_rtu_request(io)
    # If there is no RTU message, we're done serving this client
    break 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