module ModBus::Server
Module for implementation ModBus
server
Constants
- Funcs
Attributes
promiscuous[RW]
request_callback[RW]
response_callback[RW]
Public Instance Methods
with_slave(uid) { |slave| ... }
click to toggle source
# File lib/rmodbus/server.rb, line 10 def with_slave(uid) slave = slaves[uid] ||= Server::Slave.new if block_given? yield slave else slave end end
Private Instance Methods
exec_req(uid, func, params, pdu, is_response: false)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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()
click to toggle source
# File lib/rmodbus/server.rb, line 21 def slaves @slaves ||= {} end
validate_read_func(params, field, quant_max=0x7d)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# File lib/rmodbus/server.rb, line 195 def validate_write_register_func(params, slave) return 2 unless params[:addr] <= slave.holding_registers.size end