# app/lib/modbus/operations.rb module Modbus module Operations # write method def write_toggle_coil(slave) with_timeout do target_value = slave.read_coils(@start_address, 1).first == 0 ? 1 : 0 slave.coils[@start_address] = (target_value == 1) loop do break if slave.read_coils(@start_address, 1).first == target_value sleep 0.1 end end end def write_coil(slave) with_timeout do slave.coils[@start_address] = @value loop do break if slave.read_coils(@start_address, 1).first == @value sleep 0.1 end end end def write_int(slave, bits) with_timeout do regs = slave.holding_registers if bits == 16 value = @value.present? ? @value.to_i : 123 regs[@start_address] = value end end end def write_float(slave) with_timeout do regs = slave.holding_registers value = @value.present? ? @value.to_f : 123.45 regs[@start_address], regs[@start_address + 1] = [ value ].pack("f").unpack("v*") end end # read method def read_bit(slave, type) with_timeout do value = case type when :read_coils slave.read_coils(@start_address, @end_address - @start_address + 1) when :discrete_inputs slave.discrete_inputs[@start_address..@end_address] else # type code here end Rails.logger.info "[#{Time.current}] Read Bit (#{type}): #{value}" value end end def read_int(slave, bits, type) with_timeout do result = slave.send(type) values = (@start_address..@end_address).map { |i| result[i] } Rails.logger.info "[#{Time.current}] Read Float#{bits} (#{type}): #{values}" values end end def read_float(slave, type) with_timeout do result = slave.send(type) values = [] (@start_address..@end_address).step(2) do |i| raw = [ result[i], result[i + 1] ] packed = raw.pack("v*") float = packed.unpack("f")[0].round(2) values << float end Rails.logger.info "[#{Time.current}] Read Float32 (#{type}): #{values.inspect}" values end end def with_timeout seconds = ENV.fetch("OPERATION_TIME_OUT", 1).to_i Timeout.timeout(seconds) do yield end rescue Timeout::Error Rails.logger.error "[#{Time.current}] TimeOut (#{seconds}s)" end end end