94 lines
2.5 KiB
Ruby
94 lines
2.5 KiB
Ruby
# 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
|