Class: ModBus::Client::Slave

Inherits:
Object
  • Object
show all
Includes:
Debug, Errors, Options
Defined in:
lib/rmodbus/client/slave.rb

Direct Known Subclasses

RTUSlave, TCPSlave

Constant Summary collapse

Exceptions =
{
      1 => IllegalFunction.new("The function code received in the query is not an allowable action for the server"),
      2 => IllegalDataAddress.new("The data address received in the query is not an allowable address for the server"),
      3 => IllegalDataValue.new("A value contained in the query data field is not an allowable value for server"),
      4 => SlaveDeviceFailure.new("An unrecoverable error occurred while the server was attempting to perform the requested action"),
      5 => Acknowledge.new("The server has accepted the request and is processing it, but a long duration of time will be required to do so"),
      6 => SlaveDeviceBus.new("The server is engaged in processing a long duration program command"),
      8 => MemoryParityError.new("The extended file area failed to pass a consistency check")
}

Instance Attribute Summary collapse

Attributes included from Options

#raise_exception_on_mismatch, #read_retries, #read_retry_timeout

Attributes included from Debug

#debug, #raise_exception_on_mismatch, #read_retries, #read_retry_timeout

Instance Method Summary collapse

Constructor Details

#initialize(uid, io) ⇒ Slave

Returns a new instance of Slave.



20
21
22
23
# File 'lib/rmodbus/client/slave.rb', line 20

def initialize(uid, io)
  @uid = uid
  @io = io
end

Instance Attribute Details

#uidObject

Number of times to retry on read and read timeouts



10
11
12
# File 'lib/rmodbus/client/slave.rb', line 10

def uid
  @uid
end

Instance Method Details

#coilsReadWriteProxy

Returns a ModBus::ReadWriteProxy hash interface for coils

Examples:

coils[addr] => [1]
coils[addr1..addr2] => [1, 0, ..]
coils[addr] = 0 => [0]
coils[addr1..addr2] = [1, 0, ..] => [1, 0, ..]

Returns:



34
35
36
# File 'lib/rmodbus/client/slave.rb', line 34

def coils
  ModBus::ReadWriteProxy.new(self, :coil)
end

#discrete_inputsReadOnlyProxy

Returns a ModBus::ReadOnlyProxy hash interface for discrete inputs

Examples:

discrete_inputs[addr] => [1]
discrete_inputs[addr1..addr2] => [1, 0, ..]

Returns:



105
106
107
# File 'lib/rmodbus/client/slave.rb', line 105

def discrete_inputs
  ModBus::ReadOnlyProxy.new(self, :discrete_input)
end

#holding_registersReadWriteProxy

Returns a ModBus::ReadWriteProxy hash interface for holding registers

Examples:

holding_registers[addr] => [123]
holding_registers[addr1..addr2] => [123, 234, ..]
holding_registers[addr] = 123 => 123
holding_registers[addr1..addr2] = [234, 345, ..] => [234, 345, ..]

Returns:



161
162
163
# File 'lib/rmodbus/client/slave.rb', line 161

def holding_registers
  ModBus::ReadWriteProxy.new(self, :holding_register)
end

#input_registersReadOnlyProxy

Returns a read/write ModBus::ReadOnlyProxy hash interface for coils

Examples:

input_registers[addr] => [1]
input_registers[addr1..addr2] => [1, 0, ..]

Returns:



132
133
134
# File 'lib/rmodbus/client/slave.rb', line 132

def input_registers
  ModBus::ReadOnlyProxy.new(self, :input_register)
end

#mask_write_register(addr, and_mask, or_mask) ⇒ Object

Mask a holding register

Examples:

mask_write_register(1, 0xAAAA, 0x00FF) => self

Parameters:

  • addr (Integer)

    address registers

  • and_mask (Integer)

    mask for AND operation

  • or_mask (Integer)

    mask for OR operation



222
223
224
225
# File 'lib/rmodbus/client/slave.rb', line 222

def mask_write_register(addr, and_mask, or_mask)
  query("\x16" + addr.to_word + and_mask.to_word + or_mask.to_word)
  self
end

#query(request) ⇒ String

Request pdu to slave device

Parameters:

  • pdu (String)

    request to slave

Returns:

Raises:

  • (ResponseMismatch)

    the received echo response differs from the request

  • (ModBusTimeout)

    timed out during read attempt

  • (ModBusException)

    unknown error

  • (IllegalFunction)

    function code received in the query is not an allowable action for the server

  • (IllegalDataAddress)

    data address received in the query is not an allowable address for the server

  • (IllegalDataValue)

    value contained in the query data field is not an allowable value for server

  • (SlaveDeviceFailure)

    unrecoverable error occurred while the server was attempting to perform the requested action

  • (Acknowledge)

    server has accepted the request and is processing it, but a long duration of time will be required to do so

  • (SlaveDeviceBus)

    server is engaged in processing a long duration program command

  • (MemoryParityError)

    extended file area failed to pass a consistency check



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/rmodbus/client/slave.rb', line 263

def query(request)
  tried = 0
  response = ""
  begin
    ::Timeout.timeout(@read_retry_timeout, ModBusTimeout) do
      send_pdu(request)
      response = read_pdu unless uid == 0
    end
  rescue ModBusTimeout => err
    log "Timeout of read operation: (#{@read_retries - tried})"
    tried += 1
    retry unless tried >= @read_retries
    raise ModBusTimeout.new, "Timed out during read attempt"
  end

  return nil if response.size == 0

  read_func = response.getbyte(0)
  if read_func >= 0x80
    exc_id = response.getbyte(1)
    raise Exceptions[exc_id] unless Exceptions[exc_id].nil?

    raise ModBusException.new, "Unknown error"
  end

  check_response_mismatch(request, response) if raise_exception_on_mismatch
  response[2..-1]
end

#read_coil(addr) ⇒ Object



50
51
52
# File 'lib/rmodbus/client/slave.rb', line 50

def read_coil(addr)
  read_coils(addr, 1).first
end

#read_coils(addr, ncoils = 1) ⇒ Array

Read coils

Examples:

read_coils(addr, ncoils) => [1, 0, ..]

Parameters:

  • addr (Integer)

    address first coil

  • ncoils (Integer) (defaults to: 1)

    number coils

Returns:



46
47
48
# File 'lib/rmodbus/client/slave.rb', line 46

def read_coils(addr, ncoils = 1)
  query("\x1" + addr.to_word + ncoils.to_word).unpack_bits[0..ncoils-1]
end

#read_discrete_input(addr) ⇒ Object



121
122
123
# File 'lib/rmodbus/client/slave.rb', line 121

def read_discrete_input(addr)
  read_discrete_inputs(addr, 1).first
end

#read_discrete_inputs(addr, ninputs = 1) ⇒ Array

Read discrete inputs

@param ninputs number inputs

Examples:

read_discrete_inputs(addr, ninputs) => [1, 0, ..]

Parameters:

  • addr (Integer)

    address first input

Returns:



117
118
119
# File 'lib/rmodbus/client/slave.rb', line 117

def read_discrete_inputs(addr, ninputs = 1)
  query("\x2" + addr.to_word + ninputs.to_word).unpack_bits[0..ninputs-1]
end

#read_holding_register(addr) ⇒ Object



177
178
179
# File 'lib/rmodbus/client/slave.rb', line 177

def read_holding_register(addr)
  read_holding_registers(addr, 1).first
end

#read_holding_registers(addr, nregs = 1) ⇒ Array

Read holding registers

Examples:

read_holding_registers(1, 5) => [1, 0, ..]

Parameters:

  • addr (Integer)

    address first registers

  • nregs (Integer) (defaults to: 1)

    number registers

Returns:



173
174
175
# File 'lib/rmodbus/client/slave.rb', line 173

def read_holding_registers(addr, nregs = 1)
  query("\x3" + addr.to_word + nregs.to_word).unpack('n*')
end

#read_input_register(addr) ⇒ Object



148
149
150
# File 'lib/rmodbus/client/slave.rb', line 148

def read_input_register(addr)
  read_input_registers(addr, 1).first
end

#read_input_registers(addr, nregs = 1) ⇒ Array

Read input registers

Examples:

read_input_registers(1, 5) => [1, 0, ..]

Parameters:

  • addr (Integer)

    address first registers

  • nregs (Integer) (defaults to: 1)

    number registers

Returns:



144
145
146
# File 'lib/rmodbus/client/slave.rb', line 144

def read_input_registers(addr, nregs = 1)
  query("\x4" + addr.to_word + nregs.to_word).unpack('n*')
end

#read_write_multiple_registers(addr_r, nregs, addr_w, vals) ⇒ Array Also known as: read_write_holding_registers

Read/write multiple holding registers

Examples:

read_write_multiple_registers(1, 5, 1, [0xaa, 0]) => [1, 0, ..]

Parameters:

  • addr_r (Integer)

    address first registers to read

  • nregs (Integer)

    number registers to read

  • addr_w (Integer)

    address first registers to write

  • vals (Array)

    written registers

Returns:



237
238
239
240
241
242
243
244
245
# File 'lib/rmodbus/client/slave.rb', line 237

def read_write_multiple_registers(addr_r, nregs, addr_w, vals)
  s_val = ""
  vals.each do |reg|
    s_val << reg.to_word
  end

  query("\x17" + addr_r.to_word + nregs.to_word +
            addr_w.to_word + vals.size.to_word + (vals.size * 2).chr + s_val).unpack('n*')
end

#write_multiple_coils(addr, vals) ⇒ Object Also known as: write_coils

Write multiple coils

Examples:

write_multiple_coils(1, [0,1,0,1]) => self

Parameters:

  • addr (Integer)

    address first coil

  • vals (Array)

    written coils



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/rmodbus/client/slave.rb', line 79

def write_multiple_coils(addr, vals)
  nbyte = ((vals.size-1) >> 3) + 1
  sum = 0
  (vals.size - 1).downto(0) do |i|
    sum = sum << 1
    sum |= 1 if vals[i] > 0
  end

  s_val = ""
  nbyte.times do
    s_val << (sum & 0xff).chr
    sum >>= 8
  end

  query("\xf" + addr.to_word + vals.size.to_word + nbyte.chr + s_val)
  self
end

#write_multiple_registers(addr, vals) ⇒ Object Also known as: write_holding_registers

Write multiple holding registers

Examples:

write_multiple_registers(1, [0xaa, 0]) => self

Parameters:

  • addr (Integer)

    address first registers

  • val (Array)

    written registers

Returns:

  • self



204
205
206
207
208
209
210
211
212
# File 'lib/rmodbus/client/slave.rb', line 204

def write_multiple_registers(addr, vals)
  s_val = ""
  vals.each do |reg|
    s_val << reg.to_word
  end

  query("\x10" + addr.to_word + vals.size.to_word + (vals.size * 2).chr + s_val)
  self
end

#write_single_coil(addr, val) ⇒ Object Also known as: write_coil

Write a single coil

Examples:

write_single_coil(1, 0) => self

Parameters:

  • addr (Integer)

    address coil

  • val (Integer)

    value coil (0 or other)

Returns:

  • self



62
63
64
65
66
67
68
69
# File 'lib/rmodbus/client/slave.rb', line 62

def write_single_coil(addr, val)
  if val == 0
    query("\x5" + addr.to_word + 0.to_word)
  else
    query("\x5" + addr.to_word + 0xff00.to_word)
  end
  self
end

#write_single_register(addr, val) ⇒ Object Also known as: write_holding_register

Write a single holding register

Examples:

write_single_register(1, 0xaa) => self

Parameters:

  • addr (Integer)

    address registers

  • val (Integer)

    written to register

Returns:

  • self



189
190
191
192
# File 'lib/rmodbus/client/slave.rb', line 189

def write_single_register(addr, val)
  query("\x6" + addr.to_word + val.to_word)
  self
end