Module: ModBus::Server
- Included in:
- RTUServer, RTUViaTCPServer, TCPServer
- Defined in:
- lib/rmodbus/server.rb,
lib/rmodbus/server/slave.rb
Overview
Module for implementation ModBus server
Defined Under Namespace
Classes: Slave
Constant Summary collapse
- Funcs =
[1,2,3,4,5,6,15,16,22,23]
Instance Attribute Summary collapse
-
#promiscuous ⇒ Object
Returns the value of attribute promiscuous.
-
#request_callback ⇒ Object
Returns the value of attribute request_callback.
-
#response_callback ⇒ Object
Returns the value of attribute response_callback.
Instance Method Summary collapse
- #exec_req(uid, func, params, pdu, is_response: false) ⇒ Object private
- #parse_mask_write_register_func(req) ⇒ Object private
- #parse_read_func(req, expected_length = 5) ⇒ Object private
- #parse_read_write_multiple_registers_func(req) ⇒ Object private
- #parse_request(func, req) ⇒ Object private
- #parse_response(func, res) ⇒ Object private
- #parse_write_coil_func(req) ⇒ Object private
- #parse_write_multiple_coils_func(req) ⇒ Object private
- #parse_write_multiple_registers_func(req) ⇒ Object private
- #parse_write_register_func(req) ⇒ Object private
- #process_func(func, slave, req, params) ⇒ Object private
- #slaves ⇒ Object private
- #validate_read_func(params, field, quant_max = 0x7d) ⇒ Object private
- #validate_read_write_multiple_registers_func(params, slave) ⇒ Object private
- #validate_write_coil_func(params, slave) ⇒ Object private
- #validate_write_multiple_coils_func(params, slave) ⇒ Object private
- #validate_write_multiple_registers_func(params, slave) ⇒ Object private
- #validate_write_register_func(params, slave) ⇒ Object private
- #with_slave(uid) ⇒ Object
Instance Attribute Details
#promiscuous ⇒ Object
Returns the value of attribute promiscuous.
6 7 8 |
# File 'lib/rmodbus/server.rb', line 6 def promiscuous @promiscuous end |
#request_callback ⇒ Object
Returns the value of attribute request_callback.
6 7 8 |
# File 'lib/rmodbus/server.rb', line 6 def request_callback @request_callback end |
#response_callback ⇒ Object
Returns the value of attribute response_callback.
6 7 8 |
# File 'lib/rmodbus/server.rb', line 6 def response_callback @response_callback end |
Instance Method Details
#exec_req(uid, func, params, pdu, is_response: false) ⇒ Object (private)
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/rmodbus/server.rb', line 25 def exec_req(uid, func, params, pdu, is_response: false) if is_response log("Server RX response #{func & 0x7f} from #{uid}: #{params.inspect}") else log("Server RX function #{func} to #{uid}: #{params.inspect}") end request_callback&.call(uid, func, params) unless is_response if uid == 0 slaves.each_key { |specific_uid| exec_req(specific_uid, func, params, pdu) } return end slave = slaves[uid] return nil if !slave && !promiscuous if promiscuous && !slave && is_response # we saw a request to a slave that we don't own; try # and parse this as a response, not a request response_callback&.call(uid, func, params, @pending_response_req) @pending_response_req = nil return end unless Funcs.include?(func) log("Server RX unrecognized function #{func} to #{uid}") return unless slave return (func | 0x80).chr + 1.chr end # keep track of the request so that promiscuous printing of the response can have context if necessary @pending_response_req = params return unless slave pdu = process_func(func, slave, pdu, params) if response_callback res = parse_response(pdu.getbyte(0), pdu) response_callback.call(uid, pdu.getbyte(0), res, params) end pdu end |
#parse_mask_write_register_func(req) ⇒ Object (private)
223 224 225 226 227 228 229 230 |
# File 'lib/rmodbus/server.rb', line 223 def parse_mask_write_register_func(req) return nil if req.length != 7 { addr: req[1,2].unpack('n')[0], and_mask: req[3,2].unpack('n')[0], or_mask: req[5,2].unpack('n')[0] } end |
#parse_read_func(req, expected_length = 5) ⇒ Object (private)
170 171 172 173 |
# File 'lib/rmodbus/server.rb', line 170 def parse_read_func(req, expected_length = 5) return nil if expected_length && req.length != expected_length { quant: req[3,2].unpack('n')[0], addr: req[1,2].unpack('n')[0] } end |
#parse_read_write_multiple_registers_func(req) ⇒ Object (private)
232 233 234 235 236 237 238 |
# File 'lib/rmodbus/server.rb', line 232 def parse_read_write_multiple_registers_func(req) return nil if req.length < 12 params = { read: parse_read_func(req, nil), write: parse_write_multiple_registers_func(req[4..-1])} return nil if params[:write].nil? params end |
#parse_request(func, req) ⇒ Object (private)
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/rmodbus/server.rb', line 67 def parse_request(func, req) case func when 1, 2, 3, 4 parse_read_func(req) when 5 parse_write_coil_func(req) when 6 parse_write_register_func(req) when 15 parse_write_multiple_coils_func(req) when 16 parse_write_multiple_registers_func(req) when 22 parse_mask_write_register_func(req) when 23 parse_read_write_multiple_registers_func(req) end end |
#parse_response(func, res) ⇒ Object (private)
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/rmodbus/server.rb', line 86 def parse_response(func, res) if func & 0x80 == 0x80 && Funcs.include?(func & 0x7f) return nil unless res.length == 2 return { err: res[1].ord } end case func when 1, 2 return nil unless res.length == res[1].ord + 2 res[2..-1].unpack_bits when 3, 4, 23 return nil unless res.length == res[1].ord + 2 res[2..-1].unpack('n*') when 5, 6, 15, 16 return nil unless res.length == 5 {} when 22 return nil unless res.length == 7 {} end end |
#parse_write_coil_func(req) ⇒ Object (private)
180 181 182 183 |
# File 'lib/rmodbus/server.rb', line 180 def parse_write_coil_func(req) return nil unless req.length == 5 { addr: req[1,2].unpack('n')[0], val: req[3,2].unpack('n')[0] } end |
#parse_write_multiple_coils_func(req) ⇒ Object (private)
199 200 201 202 203 204 205 |
# File 'lib/rmodbus/server.rb', line 199 def parse_write_multiple_coils_func(req) return nil if req.length < 7 params = parse_read_func(req, nil) return nil if req.length != 6 + (params[:quant] + 7) / 8 params[:val] = req[6,params[:quant]].unpack_bits params end |
#parse_write_multiple_registers_func(req) ⇒ Object (private)
211 212 213 214 215 216 217 |
# File 'lib/rmodbus/server.rb', line 211 def parse_write_multiple_registers_func(req) return nil if req.length < 8 params = parse_read_func(req, nil) return nil if req.length != 6 + params[:quant] * 2 params[:val] = req[6,params[:quant] * 2].unpack('n*') params end |
#parse_write_register_func(req) ⇒ Object (private)
190 191 192 193 |
# File 'lib/rmodbus/server.rb', line 190 def parse_write_register_func(req) return nil unless req.length == 5 { addr: req[1,2].unpack('n')[0], val: req[3,2].unpack('n')[0] } end |
#process_func(func, slave, req, params) ⇒ Object (private)
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/rmodbus/server.rb', line 108 def process_func(func, slave, req, params) case func when 1 unless (err = validate_read_func(params, slave.coils, 2000)) val = slave.coils[params[:addr],params[:quant]].pack_to_word pdu = func.chr + val.size.chr + val end when 2 unless (err = validate_read_func(params, slave.discrete_inputs, 2000)) val = slave.discrete_inputs[params[:addr],params[:quant]].pack_to_word pdu = func.chr + val.size.chr + val end when 3 unless (err = validate_read_func(params, slave.holding_registers)) pdu = func.chr + (params[:quant] * 2).chr + slave.holding_registers[params[:addr],params[:quant]].pack('n*') end when 4 unless (err = validate_read_func(params, slave.input_registers)) pdu = func.chr + (params[:quant] * 2).chr + slave.input_registers[params[:addr],params[:quant]].pack('n*') end when 5 unless (err = validate_write_coil_func(params, slave)) params[:val] = 1 if params[:val] == 0xff00 slave.coils[params[:addr]] = params[:val] pdu = req end when 6 unless (err = validate_write_register_func(params, slave)) slave.holding_registers[params[:addr]] = params[:val] pdu = req end when 15 unless (err = validate_write_multiple_coils_func(params, slave)) slave.coils[params[:addr],params[:quant]] = params[:val][0,params[:quant]] pdu = req[0,5] end when 16 unless (err = validate_write_multiple_registers_func(params, slave)) slave.holding_registers[params[:addr],params[:quant]] = params[:val] pdu = req[0,5] end when 22 unless (err = validate_write_register_func(params, slave)) addr = params[:addr] and_mask = params[:and_mask] slave.holding_registers[addr] = (slave.holding_registers[addr] & and_mask) | (params[:or_mask] & ~and_mask) pdu = req end when 23 unless (err = validate_read_write_multiple_registers_func(params, slave)) slave.holding_registers[params[:write][:addr],params[:write][:quant]] = params[:write][:val] pdu = func.chr + (params[:read][:quant] * 2).chr + slave.holding_registers[params[:read][:addr],params[:read][:quant]].pack('n*') end end if err (func | 0x80).chr + err.chr else pdu end end |
#slaves ⇒ Object (private)
21 22 23 |
# File 'lib/rmodbus/server.rb', line 21 def slaves @slaves ||= {} end |
#validate_read_func(params, field, quant_max = 0x7d) ⇒ Object (private)
175 176 177 178 |
# File 'lib/rmodbus/server.rb', line 175 def validate_read_func(params, field, quant_max=0x7d) return 3 unless params[:quant] <= quant_max return 2 unless params[:addr] + params[:quant] <= field.size end |
#validate_read_write_multiple_registers_func(params, slave) ⇒ Object (private)
240 241 242 243 244 |
# File 'lib/rmodbus/server.rb', line 240 def validate_read_write_multiple_registers_func(params, slave) result = validate_read_func(params[:read], slave.holding_registers) return result if result validate_write_multiple_registers_func(params[:write], slave) end |
#validate_write_coil_func(params, slave) ⇒ Object (private)
185 186 187 188 |
# File 'lib/rmodbus/server.rb', line 185 def validate_write_coil_func(params, slave) return 2 unless params[:addr] <= slave.coils.size return 3 unless params[:val] == 0 or params[:val] == 0xff00 end |
#validate_write_multiple_coils_func(params, slave) ⇒ Object (private)
207 208 209 |
# File 'lib/rmodbus/server.rb', line 207 def validate_write_multiple_coils_func(params, slave) validate_read_func(params, slave.coils) end |
#validate_write_multiple_registers_func(params, slave) ⇒ Object (private)
219 220 221 |
# File 'lib/rmodbus/server.rb', line 219 def validate_write_multiple_registers_func(params, slave) validate_read_func(params, slave.holding_registers) end |
#validate_write_register_func(params, slave) ⇒ Object (private)
195 196 197 |
# File 'lib/rmodbus/server.rb', line 195 def validate_write_register_func(params, slave) return 2 unless params[:addr] <= slave.holding_registers.size end |