rmodbus 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/NEWS.md CHANGED
@@ -1,6 +1,23 @@
1
+ 2011-10-29 Release 1.1.0
2
+ ===================================
3
+ 1. Fixed issue [#12](https://github.com/flipback/rmodbus/issues/12). Added option Slave#raise_exception_on_mismatch to turn to check response and raise exception
4
+ if it's mismatch.
5
+ 2. Added pass options :debug, :raise_exception_on_mismatch, :read_retry_timeout, :read_retries from clients to slaves
6
+ `ruby
7
+ @cl.debug = true
8
+ @cl.with_slave(1) do |slave_1|
9
+ slave_1.debug #=> true
10
+ end
11
+ @cl.with_slave(2) do |slave_2|
12
+ slave_2.debug = false
13
+ slave_2.debug #=> false
14
+ end
15
+ `
16
+ 3. Deleted dependency with `serialport` gem. Install it manual for using RTU
17
+
1
18
  2011-08-10 Release 1.0.4
2
19
  ====================================
3
- 1. Fixed issue [#11](https://github.com/flipback/rmodbus/issues/9)
20
+ 1. Fixed issue [#11](https://github.com/flipback/rmodbus/issues/11)
4
21
 
5
22
 
6
23
  2011-07-17 Release 1.0.3
@@ -27,7 +44,7 @@ New API for client part of library
27
44
  ---------------------------------------
28
45
 
29
46
  Example:
30
-
47
+ `ruby
31
48
  require 'rmodbus'
32
49
 
33
50
  ModBus::TCPClient.new('127.0.0.1', 8502) do |cl|
@@ -45,7 +62,7 @@ Example:
45
62
  slave.holding_registers[16..20] = [1, 2, 3, 4, 5]
46
63
  end
47
64
  end
48
-
65
+ `
49
66
  for more information [see](http://rdoc.info/gems/rmodbus/1.0.0/frames)
50
67
 
51
68
  Conversion to/from 32bit registers
@@ -54,7 +71,7 @@ Conversion to/from 32bit registers
54
71
  Some modbus devices use two registers to store 32bit values.
55
72
  RModbus provides some helper functions to go back and forth between these two things when reading/writing.
56
73
  The built-in examples assume registers in a particular order but it's trivial to change.
57
-
74
+ `ruby
58
75
  # Reading values in multiple registers (you can read more than 2 and convert them all so long as they are in multiples of 2)
59
76
  res = slave.holding_registers[0..1]
60
77
  res.inspect => [20342, 17344]
@@ -66,7 +83,7 @@ The built-in examples assume registers in a particular order but it's trivial to
66
83
  cl.holding_registers[0..1] => [20342, 17344]
67
84
  cl.holding_registers[2..3] = [384.620788574219].from_32f
68
85
  cl.holding_registers[2..3] => [20342, 17344]
69
-
86
+ `
70
87
  Support JRuby
71
88
  --------------------------------------
72
89
  Now you could use RModBus on JRuby without RTU implementation.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- RModBus
1
+ RModBus [![Build Status](https://secure.travis-ci.org/flipback/rmodbus.png)](http://travis-ci.org/flipback/rmodbus)
2
2
  ==========================
3
3
 
4
4
  **RModBus** - free implementation of protocol ModBus.
@@ -50,26 +50,6 @@ Example
50
50
  end
51
51
  end
52
52
 
53
-
54
- Conversion to/from 32bit registers
55
- -----------------------------------
56
-
57
- Some modbus devices use two registers to store 32bit values.
58
- RModbus provides some helper functions to go back and forth between these two things when reading/writing.
59
- The built-in examples assume registers in a particular order but it's trivial to change.
60
-
61
- # Reading values in multiple registers (you can read more than 2 and convert them all so long as they are in multiples of 2)
62
- res = slave.holding_registers[0..1]
63
- res.inspect => [20342, 17344]
64
- res.to_32i => [1136676726]
65
- res.to_32f => [384.620788574219]
66
-
67
- # Writing 32b values to multiple registers
68
- cl.holding_registers[0..1] = [1136676726].from_32i
69
- cl.holding_registers[0..1] => [20342, 17344]
70
- cl.holding_registers[2..3] = [384.620788574219].from_32f
71
- cl.holding_registers[2..3] => [20342, 17344]
72
-
73
53
  GitHub
74
54
  ----------------------------------
75
55
 
@@ -80,8 +60,8 @@ You can checkout source code from GitHub repositry
80
60
  Reference
81
61
  ----------------------------------
82
62
 
83
- Home page: http://rmodbus.heroku.com
63
+ Home page: http://rmodbus.flipback.net
84
64
 
85
65
  RModBud on GitHub: http://github.com/flipback/RModBus
86
66
 
87
- ModBus community: http://www.modbus-ida.org
67
+ ModBus community: http://www.modbus-ida.org
data/Rakefile CHANGED
@@ -15,7 +15,9 @@ require 'rspec/core'
15
15
  require 'rspec/core/rake_task'
16
16
  RSpec::Core::RakeTask.new(:spec) do |spec|
17
17
  spec.pattern = FileList['spec/**/*_spec.rb']
18
- if RUBY_PLATFORM == "java"
18
+ begin
19
+ require 'serialport'
20
+ rescue LoadError => e
19
21
  spec.pattern.exclude("spec/rtu_client_spec.rb", "spec/rtu_server_spec.rb")
20
22
  end
21
23
  end
@@ -16,6 +16,8 @@ module ModBus
16
16
  # @abstract
17
17
  class Client
18
18
  include Errors
19
+ include Debug
20
+ include Options
19
21
 
20
22
  # Initialized client (alias :connect)
21
23
  # @example
@@ -26,6 +28,12 @@ module ModBus
26
28
  # @yield return client object and close it before exit
27
29
  # @return [Client] client object
28
30
  def initialize(*args, &block)
31
+ # Defaults
32
+ @debug = false
33
+ @raise_exception_on_mismatch = false
34
+ @read_retry_timeout = 1
35
+ @read_retries = 10
36
+
29
37
  @io = open_connection(*args)
30
38
  if block_given?
31
39
  yield self
@@ -50,6 +58,10 @@ module ModBus
50
58
  # @return [Slave] slave object
51
59
  def with_slave(uid, &block)
52
60
  slave = get_slave(uid, @io)
61
+ slave.debug = debug
62
+ slave.raise_exception_on_mismatch = raise_exception_on_mismatch
63
+ slave.read_retries = read_retries
64
+ slave.read_retry_timeout = read_retry_timeout
53
65
  if block_given?
54
66
  yield slave
55
67
  else
@@ -1,6 +1,6 @@
1
1
  # RModBus - free implementation of ModBus protocol in Ruby.
2
2
  #
3
- # Copyright (C) 2010 Timin Aleksey
3
+ # Copyright (C) 2010-2011 Timin Aleksey
4
4
  # Copyright (C) 2010 Kelley Reynolds
5
5
  #
6
6
  # This program is free software: you can redistribute it and/or modify
@@ -14,12 +14,10 @@
14
14
  # GNU General Public License for more details.
15
15
 
16
16
  module ModBus
17
- module Common
18
- # @return [Boolean] debug mode
19
- # default false
20
- attr_accessor :debug
17
+ module Debug
18
+ attr_accessor :debug, :raise_exception_on_mismatch,
19
+ :read_retries, :read_retry_timeout
21
20
 
22
- @debug = false
23
21
 
24
22
  private
25
23
  # Put log message on standart output
@@ -1,6 +1,6 @@
1
1
  # RModBus - free implementation of ModBus protocol on Ruby.
2
2
  #
3
- # Copyright (C) 2008 Timin Aleksey
3
+ # Copyright (C) 2008-2011 Timin Aleksey
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -14,7 +14,6 @@
14
14
  module ModBus
15
15
 
16
16
  module Errors
17
-
18
17
  class ProxyException < StandardError
19
18
  end
20
19
 
@@ -45,6 +44,13 @@ module ModBus
45
44
  class ModBusTimeout < ModBusException
46
45
  end
47
46
 
47
+ class ResponseMismatch < ModBusException
48
+ attr_reader :request, :response
49
+ def initialize(msg, request, response)
50
+ super(msg)
51
+ @request = request
52
+ @response = response
53
+ end
54
+ end
48
55
  end
49
-
50
56
  end
data/lib/rmodbus/ext.rb CHANGED
@@ -27,7 +27,13 @@ class String
27
27
  end
28
28
  array_bit
29
29
  end
30
-
30
+
31
+ # Get word by index
32
+ # @param [Integer] i index first bytes of word
33
+ # @return unpacked word
34
+ def getword(i)
35
+ self[i,2].unpack('n')[0]
36
+ end
31
37
  end
32
38
 
33
39
  class Integer
@@ -0,0 +1,21 @@
1
+ # RModBus - free implementation of ModBus protocol in Ruby.
2
+ #
3
+ # Copyright (C) 2011 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ module ModBus
16
+ module Options
17
+ attr_accessor :raise_exception_on_mismatch,
18
+ :read_retries, :read_retry_timeout
19
+ end
20
+ end
21
+
data/lib/rmodbus/rtu.rb CHANGED
@@ -23,6 +23,7 @@ module ModBus
23
23
  msg = nil
24
24
  while msg.nil?
25
25
  msg = io.read(2)
26
+ sleep(0.01)
26
27
  end
27
28
 
28
29
  function_code = msg.getbyte(1)
@@ -44,6 +45,32 @@ module ModBus
44
45
  end
45
46
  end
46
47
 
48
+ def send_rtu_pdu(pdu)
49
+ msg = @uid.chr + pdu
50
+ msg << crc16(msg).to_word
51
+ @io.write msg
52
+
53
+ log "Tx (#{msg.size} bytes): " + logging_bytes(msg)
54
+ end
55
+
56
+ def read_rtu_pdu
57
+ msg = read_rtu_response(@io)
58
+
59
+ log "Rx (#{msg.size} bytes): " + logging_bytes(msg)
60
+
61
+ if msg.getbyte(0) == @uid
62
+ return msg[1..-3] if msg[-2,2].unpack('n')[0] == crc16(msg[0..-3])
63
+ log "Ignore package: don't match CRC"
64
+ else
65
+ log "Ignore package: don't match uid ID"
66
+ end
67
+ loop do
68
+ #waite timeout
69
+ sleep(0.1)
70
+ end
71
+ end
72
+
73
+
47
74
  def read_rtu_request(io)
48
75
  # Read the slave_id and function code
49
76
  msg = io.read(2)
@@ -83,6 +110,7 @@ module ModBus
83
110
  log "Server TX (#{resp.size} bytes): #{logging_bytes(resp)}"
84
111
  io.write resp
85
112
  end
113
+ sleep(0.01)
86
114
  end
87
115
  end
88
116
 
@@ -11,8 +11,7 @@
11
11
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
  # GNU General Public License for more details.
14
- require 'serialport'
15
-
14
+ #
16
15
  module ModBus
17
16
  # RTU server implementation
18
17
  # @example
@@ -24,7 +23,7 @@ module ModBus
24
23
  # srv.debug = true
25
24
  # srv.start
26
25
  class RTUServer
27
- include Common
26
+ include Debug
28
27
  include Server
29
28
  include RTU
30
29
  include SP
@@ -26,34 +26,17 @@ module ModBus
26
26
  class RTUSlave < Slave
27
27
  include RTU
28
28
 
29
- protected
30
-
29
+ private
31
30
  # overide method for RTU implamentaion
32
31
  # @see Slave#query
33
32
  def send_pdu(pdu)
34
- msg = @uid.chr + pdu
35
- msg << crc16(msg).to_word
36
- @io.write msg
37
-
38
- log "Tx (#{msg.size} bytes): " + logging_bytes(msg)
33
+ send_rtu_pdu(pdu)
39
34
  end
40
35
 
41
36
  # overide method for RTU implamentaion
42
37
  # @see Slave#query
43
38
  def read_pdu
44
- msg = read_rtu_response(@io)
45
-
46
- log "Rx (#{msg.size} bytes): " + logging_bytes(msg)
47
-
48
- if msg.getbyte(0) == @uid
49
- return msg[1..-3] if msg[-2,2].unpack('n')[0] == crc16(msg[0..-3])
50
- log "Ignore package: don't match CRC"
51
- else
52
- log "Ignore package: don't match uid ID"
53
- end
54
- loop do
55
- #waite timeout
56
- end
39
+ read_rtu_pdu
57
40
  end
58
41
  end
59
42
  end
@@ -26,7 +26,7 @@ module ModBus
26
26
  # srv.debug = true
27
27
  # srv.start
28
28
  class RTUViaTCPServer < GServer
29
- include Common
29
+ include Debug
30
30
  include RTU
31
31
  include Server
32
32
 
@@ -26,33 +26,17 @@ module ModBus
26
26
  class RTUViaTCPSlave < Slave
27
27
  include RTU
28
28
 
29
- protected
30
- # overide method for RTU over TCP implamentaion
29
+ private
30
+ # overide method for RTU implamentaion
31
31
  # @see Slave#query
32
- def send_pdu(pdu)
33
- msg = @uid.chr + pdu
34
- msg << crc16(msg).to_word
35
- @io.write msg
32
+ def send_pdu(pdu)
33
+ send_rtu_pdu(pdu)
34
+ end
36
35
 
37
- log "Tx (#{msg.size} bytes): " + logging_bytes(msg)
38
- end
39
-
40
- # overide method for RTU over TCP implamentaion
36
+ # overide method for RTU implamentaion
41
37
  # @see Slave#query
42
- def read_pdu
43
- # Read the response appropriately
44
- msg = read_rtu_response(@io)
45
-
46
- log "Rx (#{msg.size} bytes): " + logging_bytes(msg)
47
- if msg.getbyte(0) == @uid
48
- return msg[1..-3] if msg[-2,2].unpack('n')[0] == crc16(msg[0..-3])
49
- log "Ignore package: don't match CRC"
50
- else
51
- log "Ignore package: don't match uid ID"
52
- end
53
- loop do
54
- #waite timeout
55
- end
56
- end
38
+ def read_pdu
39
+ read_rtu_pdu
40
+ end
57
41
  end
58
42
  end
data/lib/rmodbus/slave.rb CHANGED
@@ -16,10 +16,10 @@
16
16
  module ModBus
17
17
  class Slave
18
18
  include Errors
19
- include Common
19
+ include Debug
20
+ include Options
20
21
  # Number of times to retry on read and read timeouts
21
- attr_accessor :read_retries, :read_retry_timeout, :uid
22
-
22
+ attr_accessor :uid
23
23
  Exceptions = {
24
24
  1 => IllegalFunction.new("The function code received in the query is not an allowable action for the server"),
25
25
  2 => IllegalDataAddress.new("The data address received in the query is not an allowable address for the server"),
@@ -31,8 +31,6 @@ module ModBus
31
31
  }
32
32
  def initialize(uid, io)
33
33
  @uid = uid
34
- @read_retries = 10
35
- @read_retry_timeout = 1
36
34
  @io = io
37
35
  end
38
36
 
@@ -231,6 +229,7 @@ module ModBus
231
229
  # @param [String] pdu request to slave
232
230
  # @return [String] received data
233
231
  #
232
+ # @raise [ResponseMismatch] the received echo response differs from the request
234
233
  # @raise [ModBusTimeout] timed out during read attempt
235
234
  # @raise [ModBusException] unknown error
236
235
  # @raise [IllegalFunction] function code received in the query is not an allowable action for the server
@@ -240,12 +239,13 @@ module ModBus
240
239
  # @raise [Acknowledge] server has accepted the request and is processing it, but a long duration of time will be required to do so
241
240
  # @raise [SlaveDeviceBus] server is engaged in processing a long duration program command
242
241
  # @raise [MemoryParityError] extended file area failed to pass a consistency check
243
- def query(pdu)
242
+ def query(request)
244
243
  tried = 0
244
+ response = ""
245
245
  begin
246
246
  timeout(@read_retry_timeout, ModBusTimeout) do
247
- send_pdu(pdu)
248
- pdu = read_pdu
247
+ send_pdu(request)
248
+ response = read_pdu
249
249
  end
250
250
  rescue ModBusTimeout => err
251
251
  log "Timeout of read operation: (#{@read_retries - tried})"
@@ -254,15 +254,70 @@ module ModBus
254
254
  raise ModBusTimeout.new, "Timed out during read attempt"
255
255
  end
256
256
 
257
- return nil if pdu.size == 0
257
+ return nil if response.size == 0
258
258
 
259
- if pdu.getbyte(0) >= 0x80
260
- exc_id = pdu.getbyte(1)
259
+ read_func = response.getbyte(0)
260
+ if read_func >= 0x80
261
+ exc_id = response.getbyte(1)
261
262
  raise Exceptions[exc_id] unless Exceptions[exc_id].nil?
262
263
 
263
264
  raise ModBusException.new, "Unknown error"
264
265
  end
265
- pdu[2..-1]
266
+
267
+ check_response_mismatch(request, response) if raise_exception_on_mismatch
268
+ response[2..-1]
269
+ end
270
+
271
+ private
272
+ def check_response_mismatch(request, response)
273
+ read_func = response.getbyte(0)
274
+ data = response[2..-1]
275
+ #Mismatch functional code
276
+ send_func = request.getbyte(0)
277
+ if read_func != send_func
278
+ msg = "Function code is mismatch (expected #{send_func}, got #{read_func})"
279
+ end
280
+
281
+ case read_func
282
+ when 1,2
283
+ bc = request.getword(3)/8 + 1
284
+ if data.size != bc
285
+ msg = "Byte count is mismatch (expected #{bc}, got #{data.size} bytes)"
286
+ end
287
+ when 3,4
288
+ rc = request.getword(3)
289
+ if data.size/2 != rc
290
+ msg = "Register count is mismatch (expected #{rc}, got #{data.size/2} regs)"
291
+ end
292
+ when 5,6
293
+ exp_addr = request.getword(1)
294
+ got_addr = response.getword(1)
295
+ if exp_addr != got_addr
296
+ msg = "Address is mismatch (expected #{exp_addr}, got #{got_addr})"
297
+ end
298
+
299
+ exp_val = request.getword(3)
300
+ got_val = response.getword(3)
301
+ if exp_val != got_val
302
+ msg = "Value is mismatch (expected 0x#{exp_val.to_s(16)}, got 0x#{got_val.to_s(16)})"
303
+ end
304
+ when 15,16
305
+ exp_addr = request.getword(1)
306
+ got_addr = response.getword(1)
307
+ if exp_addr != got_addr
308
+ msg = "Address is mismatch (expected #{exp_addr}, got #{got_addr})"
309
+ end
310
+
311
+ exp_quant = request.getword(3)
312
+ got_quant = response.getword(3)
313
+ if exp_quant != got_quant
314
+ msg = "Quantity is mismatch (expected #{exp_quant}, got #{got_quant})"
315
+ end
316
+ else
317
+ warn "Fuiction (#{read_func}) is not supported raising response mismatch"
318
+ end
319
+
320
+ raise ResponseMismatch.new(msg, request, response) if msg
266
321
  end
267
322
  end
268
323
  end
data/lib/rmodbus/sp.rb CHANGED
@@ -12,8 +12,6 @@
12
12
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
  # GNU General Public License for more details.
14
14
 
15
- require 'serialport'
16
-
17
15
  module ModBus
18
16
  module SP
19
17
  attr_reader :port, :baud, :data_bits, :stop_bits, :parity, :read_timeout
@@ -42,4 +40,5 @@ module ModBus
42
40
  io
43
41
  end
44
42
  end
45
- end
43
+ end
44
+
@@ -1,19 +1,19 @@
1
- # RModBus - free implementation of ModBus protocol on Ruby.
2
- #
3
- # Copyright (C) 2008 Timin Aleksey
4
- #
5
- # This program is free software: you can redistribute it and/or modify
6
- # it under the terms of the GNU General Public License as published by
7
- # the Free Software Foundation, either version 3 of the License, or
8
- # (at your option) any later version.
9
- #
10
- # This program is distributed in the hope that it will be useful,
11
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- # GNU General Public License for more details.
14
- require 'gserver'
15
-
16
- module ModBus
1
+ # RModBus - free implementation of ModBus protocol on Ruby.
2
+ #
3
+ # Copyright (C) 2008-2011 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ require 'gserver'
15
+
16
+ module ModBus
17
17
  # TCP server implementation
18
18
  # @example
19
19
  # srv = TCPServer.new(10002, 1)
@@ -22,45 +22,43 @@ module ModBus
22
22
  # srv.holding_registers = [1,2,3,4]
23
23
  # srv.input_registers = [1,2,3,4]
24
24
  # srv.debug = true
25
- # srv.start
26
- class TCPServer < GServer
27
- include Common
28
- include Server
29
-
25
+ # srv.start
26
+ class TCPServer < GServer
27
+ include Debug
28
+ include Server
29
+
30
30
  # Init server
31
31
  # @param [Integer] port listen port
32
- # @param [Integer] uid slave device
33
- # @param [Hash] opts options of server
32
+ # @param [Integer] uid slave device
33
+ # @param [Hash] opts options of server
34
34
  # @option opts [String] :host host of server default '127.0.0.1'
35
- # @option opts [Float, Integer] :max_connection max of TCP connection with server default 4
36
- def initialize(port = 502, uid = 1, opts = {})
37
- @uid = uid
38
- opts[:host] = DEFAULT_HOST unless opts[:host]
39
- opts[:max_connection] = 4 unless opts[:max_connection]
40
- super(port, host = opts[:host], maxConnection = opts[:max_connection])
41
- end
42
-
35
+ # @option opts [Float, Integer] :max_connection max of TCP connection with server default 4
36
+ def initialize(port = 502, uid = 1, opts = {})
37
+ @uid = uid
38
+ opts[:host] = DEFAULT_HOST unless opts[:host]
39
+ opts[:max_connection] = 4 unless opts[:max_connection]
40
+ super(port, host = opts[:host], maxConnection = opts[:max_connection])
41
+ end
42
+
43
43
  # Serve requests
44
- # @param [TCPSocket] io socket
45
- def serve(io)
46
- loop do
47
- req = io.read(7)
48
- if req[2,2] != "\x00\x00" or req.getbyte(6) != @uid
49
- io.close
50
- break
51
- end
52
-
53
- tr = req[0,2]
54
- len = req[4,2].unpack('n')[0]
55
- req = io.read(len - 1)
56
- log "Server RX (#{req.size} bytes): #{logging_bytes(req)}"
57
-
58
- pdu = exec_req(req, @coils, @discrete_inputs, @holding_registers, @input_registers)
59
-
60
- resp = tr + "\0\0" + (pdu.size + 1).to_word + @uid.chr + pdu
61
- log "Server TX (#{resp.size} bytes): #{logging_bytes(resp)}"
62
- io.write resp
63
- end
64
- end
65
- end
66
- end
44
+ # @param [TCPSocket] io socket
45
+ def serve(io)
46
+ while not stopped?
47
+ req = io.read(7)
48
+ if req[2,2] == "\x00\x00" or req.getbyte(6) == @uid
49
+ tr = req[0,2]
50
+ len = req[4,2].unpack('n')[0]
51
+ req = io.read(len - 1)
52
+ log "Server RX (#{req.size} bytes): #{logging_bytes(req)}"
53
+
54
+ pdu = exec_req(req, @coils, @discrete_inputs, @holding_registers, @input_registers)
55
+
56
+ resp = tr + "\0\0" + (pdu.size + 1).to_word + @uid.chr + pdu
57
+ log "Server TX (#{resp.size} bytes): #{logging_bytes(resp)}"
58
+ io.write resp
59
+ end
60
+ sleep(0.01)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -13,5 +13,5 @@
13
13
  # GNU General Public License for more details.
14
14
  module ModBus
15
15
  # Package version
16
- VERSION = '1.0.4'
17
- end
16
+ VERSION = '1.1.0'
17
+ end