Class: Modbus::Transaction::Client

Inherits:
Base
  • Object
show all
Includes:
EM::Deferrable
Defined in:
lib/modbus/transaction/client.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(conn, timeout) ⇒ Client

Returns a new instance of Client.



14
15
16
17
# File 'lib/modbus/transaction/client.rb', line 14

def initialize(conn, timeout)
  super conn
  @timeout = timeout
end

Class Method Details

.recv_adu(buffer, conn) ⇒ true, false

Try to decode a response ADU from some recevied bytes and handle the ADU if decoding was successful.

Parameters:

Returns:

  • (true, false)

    True, if there where enough bytes in the buffer and decoding was successful.



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/modbus/transaction/client.rb', line 26

def self.recv_adu(buffer, conn)
  adu = Modbus::TCPADU.new

  if adu.decode :response, buffer, conn
    transaction = conn.pick_pending_transaction adu.transaction_ident
    fail ClientError, "Transaction ident #{adu.transaction_ident} not found!" unless transaction
    transaction.handle_response adu
    return true
  else
    return false
  end
end

Instance Method Details

#handle_read_bitsObject



166
167
168
# File 'lib/modbus/transaction/client.rb', line 166

def handle_read_bits
  @response_adu.pdu.bit_values
end

#handle_read_registersObject



176
177
178
# File 'lib/modbus/transaction/client.rb', line 176

def handle_read_registers
  @response_adu.pdu.reg_values
end

#handle_response(adu) ⇒ Object

Handles a recevied ADU and calls the relevant callback. The corresponding request ADU is matched and cleaned up.

Parameters:

  • adu (Modbus::ADU)

    The ADU to handle.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/modbus/transaction/client.rb', line 149

def handle_response(adu)
  @response_adu = adu
  fail Modbus.find_exception(@response_adu.pdu.exception_code), "Request PDU: #{@request_adu.pdu.inspect}" if @response_adu.pdu.is_a? PDU::Exception

  transaction = TRANSACTIONS.find { |t| @response_adu.pdu.is_a? t[:response] }
  fail "Unknown PDU #{@response_adu.pdu.inspect}" unless transaction
  fail "Unexpected last sent PDU: #{@request_adu.pdu.inspect}" unless @request_adu.pdu.is_a? transaction[:request]

  value = send transaction[:handler]
  EM.cancel_timer @timeout_timer
  set_deferred_success @request_adu.pdu.start_addr, value

rescue => e
  set_deferred_failure "#{e.class} - #{e.message}"
end

#handle_write_multiple_registersObject



181
182
183
# File 'lib/modbus/transaction/client.rb', line 181

def handle_write_multiple_registers
  @response_adu.pdu.reg_count
end

#handle_write_single_coilObject



171
172
173
# File 'lib/modbus/transaction/client.rb', line 171

def handle_write_single_coil
  @response_adu.pdu.value
end

#read_coils(start_addr, bit_count) ⇒ Object

Sends a request for the modbus function 1 “read coils” asynchronusly. This method is non-blocking.

Parameters:

  • start_addr (Integer)

    The starting modbus register address to read registers from.

  • bit_count (Integer)

    The number of input bits to read.



45
46
47
48
49
50
51
# File 'lib/modbus/transaction/client.rb', line 45

def read_coils(start_addr, bit_count)
  pdu            = PDU::ReadCoilsRequest.new
  pdu.start_addr = start_addr
  pdu.bit_count  = bit_count

  send_pdu pdu
end

#read_holding_registers(start_addr, reg_count) ⇒ Object

Sends a request for the modbus function “read holding registers” asynchronusly. This method is non-blocking.

Parameters:

  • start_addr (Integer)

    The starting modbus register address to read registers from.

  • reg_count (Integer)

    The number of registers to read.



101
102
103
104
105
106
107
# File 'lib/modbus/transaction/client.rb', line 101

def read_holding_registers(start_addr, reg_count)
  pdu            = PDU::ReadHoldingRegistersRequest.new
  pdu.start_addr = start_addr
  pdu.reg_count  = reg_count

  send_pdu pdu
end

#read_input_registers(start_addr, reg_count) ⇒ Object

Sends a request for the modbus function 4 “read input registers” asynchronusly. This method is non-blocking.

Parameters:

  • start_addr (Integer)

    The starting modbus register address to read registers from.

  • reg_count (Integer)

    The number of registers to read.



87
88
89
90
91
92
93
# File 'lib/modbus/transaction/client.rb', line 87

def read_input_registers(start_addr, reg_count)
  pdu            = PDU::ReadInputRegistersRequest.new
  pdu.start_addr = start_addr
  pdu.reg_count  = reg_count

  send_pdu pdu
end

#read_input_status(start_addr, bit_count) ⇒ Object

Sends a request for the modbus function 2 “read input status” asynchronusly. This method is non-blocking.

Parameters:

  • start_addr (Integer)

    The starting modbus register address to read registers from.

  • bit_count (Integer)

    The number of input bits to read.



59
60
61
62
63
64
65
# File 'lib/modbus/transaction/client.rb', line 59

def read_input_status(start_addr, bit_count)
  pdu            = PDU::ReadInputStatusRequest.new
  pdu.start_addr = start_addr
  pdu.bit_count  = bit_count

  send_pdu pdu
end

#send_pdu(pdu) ⇒ Modbus::TCPADU

Constructs a ADU using a PDU and send it asynchronusly to the server. The created ADU is stored internally and is matched to the response when the response is available.

Parameters:

Returns:



130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/modbus/transaction/client.rb', line 130

def send_pdu(pdu)
  @request_adu = TCPADU.new pdu, @conn.next_transaction_ident
  @conn.track_transaction self
  @conn.send_data @request_adu.encode

  @timeout_timer = EM.add_timer @timeout do
    @conn.pick_pending_transaction @request_adu.transaction_ident
    set_deferred_failure "Timeout #{@timeout}s expired"
  end

  self
end

#transaction_identInteger

Returns the transaction ident of this transaction which is consistent to the ident of the request PDU.

Returns:

  • (Integer)

    The transaction ident.



190
191
192
# File 'lib/modbus/transaction/client.rb', line 190

def transaction_ident
  @request_adu.transaction_ident
end

#transaction_timeFloat

Returns the duration of a transaction.

Returns:

  • (Float)

    Time time in seconds.



199
200
201
202
# File 'lib/modbus/transaction/client.rb', line 199

def transaction_time
  fail ClientError, 'Response ADU unknown. Can not calcluate transaction time.' unless @response_adu
  ((@response_adu.pdu.creation_time - @request_adu.pdu.creation_time) * 1000).round
end

#write_multiple_registers(start_addr, reg_values) ⇒ Object

Sends a request for the modbus function “write mutliple registers” asynchronusly. This method is non-blocking.

Parameters:

  • start_addr (Integer)

    The starting modbus register address to read registers from.

  • reg_values (Integer)

    The register values to write.



115
116
117
118
119
120
121
# File 'lib/modbus/transaction/client.rb', line 115

def write_multiple_registers(start_addr, reg_values)
  pdu            = PDU::WriteMultipleRegistersRequest.new
  pdu.start_addr = start_addr
  pdu.reg_values = reg_values

  send_pdu pdu
end

#write_single_coil(start_addr, value) ⇒ Object

Sends a request for the modbus function 5 “write single coil” asynchronusly. This method is non-blocking.

Parameters:

  • start_addr (Integer)

    The address of the coil to write.

  • value (Integer)

    The value to write.



73
74
75
76
77
78
79
# File 'lib/modbus/transaction/client.rb', line 73

def write_single_coil(start_addr, value)
  pdu            = PDU::WriteSingleCoilRequest.new
  pdu.start_addr = start_addr
  pdu.value      = value

  send_pdu pdu
end