class Modbus
Constants
- ADU
TCP
ADU
are sent via TCP to registered port 502- CODES
- EXCEPTIONS
- MULTIPLE_CODES
- READ_CODES
- WRITE_CODES
Public Class Methods
new()
click to toggle source
# File lib/modbus.rb, line 43 def initialize @transaction = 0 end
Public Instance Methods
read(data, serial: false) { |adu header, function_code, response| ... }
click to toggle source
Decodes an ADU
from wire format and sets the attributes of this object.
@param data [String] The bytes to decode.
# File lib/modbus.rb, line 50 def read(data, serial: false) @buffer ||= String.new # add mock TCP header if serial @buffer << "\x0\x0\x0\x0\x0" @buffer << (data.bytesize - 2) end @buffer << data error = nil loop do # not enough data in buffer to know the length break if @buffer.bytesize < 6 header = TCPHeader.new header.read(@buffer[0..5]) # the headers unit identifier is included in the length total_length = header.request_length + 6 # Extract just the request from the buffer break if @buffer.bytesize < total_length request = @buffer.slice!(0...total_length) function_code = request.getbyte(7) # Yield the complete responses begin if function_code <= 0x80 response = ResponsePDU.new response.read(request[6..-1]) else # Error response response = ExceptionPDU.new response.read(request[6..-1]) function_code = function_code - 0x80 end yield ADU.new header, function_code, response rescue => e error = e end end raise error if error end
write_coils(address, *values)
click to toggle source
# File lib/modbus.rb, line 106 def write_coils(address, *values) values = values.flatten if values.length > 1 write_multiple_coils(address, *values) else adu = request_adu :write_coil request = adu.pdu request.put.address = address.to_i request.put.data = values.first ? 0xFF00 : 0x0 adu end end
write_registers(address, *values)
click to toggle source
# File lib/modbus.rb, line 120 def write_registers(address, *values) values = values.flatten.map! { |value| value.to_i } if values.length > 1 adu = request_adu :write_multiple_registers request = adu.pdu request.put_multiple.address = address.to_i request.put_multiple.quantity = values.length request.put_multiple.data = values.pack('n*') adu else adu = request_adu :write_register request = adu.pdu request.put.address = address.to_i request.put.data = values.first adu end end
Protected Instance Methods
new_header()
click to toggle source
# File lib/modbus.rb, line 177 def new_header header = TCPHeader.new header.transaction_identifier = next_id header.protocol_identifier = 0 header end
next_id()
click to toggle source
# File lib/modbus.rb, line 170 def next_id id = @transaction @transaction += 1 @transaction = 0 if @transaction > 0xFFFF id end
request_adu(function)
click to toggle source
# File lib/modbus.rb, line 192 def request_adu(function) code = CODES[function] ADU.new(new_header, code, request_pdu(code)) end
request_pdu(code)
click to toggle source
# File lib/modbus.rb, line 184 def request_pdu(code) request = RequestPDU.new # This seems to be the default request.unit_identifier = 0xFF request.function_code = code request end
write_multiple_coils(address, *values)
click to toggle source
# File lib/modbus.rb, line 141 def write_multiple_coils(address, *values) size = values.length bytes = [] byte = 0 bit = 0 loop do value = values.shift if value byte = byte | (1 << bit) end break if values.empty? bit += 1 if bit >= 8 bytes << byte byte = 0 bit = 0 end end bytes << byte adu = request_adu :write_multiple_coils request = adu.pdu request.put_multiple.address = address.to_i request.put_multiple.quantity = size request.put_multiple.data = bytes.pack('C*') adu end