rmodbus 1.2.6 → 1.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 32a45f98ff103499e6446a926f9819928716602a
4
- data.tar.gz: 0f883902d6eb8a80330769ca519e69915343d857
3
+ metadata.gz: 72ada248b0d55d8dfecb8cb022e30e0dbd4e50b3
4
+ data.tar.gz: 8de3ae040a26b173faa3bb1eca98b6d9bdba37c8
5
5
  SHA512:
6
- metadata.gz: e050abe8430ef0b8f58bc953c249b6b8143d90e673889c3ec91723deba0888d8ddf081ba7efcfbba7a3517a1287bce028386e203505156c5cb00a40005fa2ad2
7
- data.tar.gz: 0badca7a5158d6ab27d094c27f3c1b030a14c70e50079fedf4533041d5f340e6fa871d8383ab3e3f5cfb53fa8dea413efca44bb217e8525b2bec602b01dd81d7
6
+ metadata.gz: 52ba64f23e37297732981cfb7a21f0633b4959b813a20005903148539cb341086250135ff7607c68d7c204e5c71d93be428ea6bf78253409ef7bce153d1e1008
7
+ data.tar.gz: acc3b11d3b438c2af0ed52dcb2126f1e7360523efb6135ecd933999550869b57a5820d034ee6907277a0ca6b879084f7b0bdf5b0b04d4ebc26deab72edad18af
data/NEWS.md CHANGED
@@ -1,3 +1,10 @@
1
+ ###2015-07-30 Release 1.2.7
2
+
3
+ 1. RTUServer doesn't stop serving when there is no RTU messages. Pull request [#37](https://github.com/flipback/rmodbus/pull/37).
4
+ 2. Fixed a bug with flushing buffer in RTUviaTCPClient.
5
+ 3. Added validation for UDI in TCPServer. See request [#38](https://github.com/flipback/rmodbus/pull/38).
6
+ 4. Added a warning message to ask use UID=255 for TCP Server according to the protocol specification.
7
+
1
8
  ###2015-03-21 Release 1.2.6
2
9
 
3
10
  1. Fixed issue [#35](https://github.com/flipback/rmodbus/issues/35).
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  RModBus [![Build Status](https://secure.travis-ci.org/flipback/rmodbus.png)](http://travis-ci.org/flipback/rmodbus)
2
2
  ==========================
3
3
 
4
- **RModBus** - free implementation of protocol ModBus written in pure Ruby.
4
+ **RModBus** - free implementation of ModBus protocol in pure Ruby.
5
5
 
6
6
  Features
7
7
  ---------------------------
@@ -25,9 +25,11 @@ Support functions
25
25
  Installation
26
26
  ------------------------------------
27
27
 
28
- Download and install RModBus with the following
28
+ Download and install RModBus with the following:
29
29
 
30
- **$ gem install rmodbus**
30
+ ```
31
+ gem install rmodbus
32
+ ```
31
33
 
32
34
  Example
33
35
  ------------------------------------
@@ -55,15 +57,17 @@ Example
55
57
  GitHub
56
58
  ----------------------------------
57
59
 
58
- You can checkout source code from GitHub repositry
60
+ You can checkout source code from GitHub repository:
59
61
 
60
- **$ git clone git://github.com/flipback/RModBus.git**
62
+ ```
63
+ git clone git://github.com/flipback/RModBus.git
64
+ ```
61
65
 
62
66
  Reference
63
67
  ----------------------------------
64
68
 
65
69
  Home page: http://rmodbus.flipback.net
66
70
 
67
- RModBud on GitHub: http://github.com/flipback/RModBus
71
+ RModBus on GitHub: http://github.com/flipback/RModBus
68
72
 
69
- ModBus community: http://www.modbus-ida.org
73
+ ModBus specifications: http://www.modbus.org/specs.php
@@ -46,7 +46,11 @@ module ModBus
46
46
 
47
47
  def clean_input_buff
48
48
  # empty the input buffer
49
- @io.flush_input
49
+ if @io.class.public_method_defined? :flush_input
50
+ @io.flush_input
51
+ else
52
+ @io.flush
53
+ end
50
54
  end
51
55
 
52
56
  def send_rtu_pdu(pdu)
@@ -105,8 +109,8 @@ module ModBus
105
109
  loop do
106
110
  # read the RTU message
107
111
  msg = read_rtu_request(io)
108
- # If there is no RTU message, we're done serving this client
109
- break if msg.nil?
112
+
113
+ next if msg.nil?
110
114
 
111
115
  if msg.getbyte(0) == @uid and msg[-2,2].unpack('n')[0] == crc16(msg[0..-3])
112
116
  pdu = yield msg
@@ -25,8 +25,8 @@ module ModBus
25
25
  # srv.start
26
26
  class TCPServer < GServer
27
27
  include Debug
28
- include Server
29
-
28
+ include Server
29
+
30
30
  # Init server
31
31
  # @param [Integer] port listen port
32
32
  # @param [Integer] uid slave device
@@ -35,6 +35,9 @@ module ModBus
35
35
  # @option opts [Float, Integer] :max_connection max of TCP connection with server default 4
36
36
  def initialize(port = 502, uid = 1, opts = {})
37
37
  @uid = uid
38
+
39
+ warn "[WARNING] Please, use UID = 255. It will be fixed in the next release." if @uid != 0xff
40
+
38
41
  opts[:host] = DEFAULT_HOST unless opts[:host]
39
42
  opts[:max_connection] = 4 unless opts[:max_connection]
40
43
  super(port, host = opts[:host], maxConnection = opts[:max_connection])
@@ -42,22 +45,28 @@ module ModBus
42
45
 
43
46
  # Serve requests
44
47
  # @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]
48
+ def serve(io)
49
+ while not stopped?
50
+ header = io.read(7)
51
+ tx_id = header[0,2]
52
+ proto_id = header[2,2]
53
+ len = header[4,2].unpack('n')[0]
54
+ unit_id = header.getbyte(6)
55
+ if proto_id == "\x00\x00"
51
56
  req = io.read(len - 1)
52
- log "Server RX (#{req.size} bytes): #{logging_bytes(req)}"
57
+ if unit_id == @uid || unit_id == 0
58
+ log "Server RX (#{req.size} bytes): #{logging_bytes(req)}"
53
59
 
54
- pdu = exec_req(req, @coils, @discrete_inputs, @holding_registers, @input_registers)
60
+ pdu = exec_req(req, @coils, @discrete_inputs, @holding_registers, @input_registers)
55
61
 
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
62
+ resp = tx_id + "\0\0" + (pdu.size + 1).to_word + @uid.chr + pdu
63
+ log "Server TX (#{resp.size} bytes): #{logging_bytes(resp)}"
64
+ io.write resp
65
+ else
66
+ log "Ignored server RX (invalid unit ID #{unit_id}, #{req.size} bytes): #{logging_bytes(req)}"
67
+ end
59
68
  end
60
- end
61
- end
69
+ end
70
+ end
62
71
  end
63
72
  end
@@ -1,6 +1,6 @@
1
1
  # RModBus - free implementation of ModBus protocol on Ruby.
2
2
  #
3
- # Copyright (C) 2012 Timin Aleksey
3
+ # Copyright (C) 2012-2015 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
@@ -13,5 +13,5 @@
13
13
  # GNU General Public License for more details.
14
14
  module ModBus
15
15
  # Package version
16
- VERSION = '1.2.6'
16
+ VERSION = '1.2.7'
17
17
  end
@@ -41,23 +41,23 @@ describe ModBus::Client do
41
41
  it 'should common for all slaves :debug flag' do
42
42
  @cl.debug = true
43
43
  @cl.with_slave(1) do |slave_1|
44
- slave_1.debug.should be_true
44
+ slave_1.debug.should be_truthy
45
45
  end
46
46
  @cl.with_slave(2) do |slave_2|
47
47
  slave_2.debug = false
48
- slave_2.debug.should be_false
48
+ slave_2.debug.should be_falsey
49
49
  end
50
50
  end
51
51
 
52
52
  it 'should common for all slaves :raise_exception_on_mismatch flag' do
53
53
  @cl.raise_exception_on_mismatch = true
54
54
  @cl.with_slave(1) do |slave_1|
55
- slave_1.raise_exception_on_mismatch.should be_true
55
+ slave_1.raise_exception_on_mismatch.should be_truthy
56
56
  end
57
57
 
58
58
  @cl.with_slave(2) do |slave_2|
59
59
  slave_2.raise_exception_on_mismatch = false
60
- slave_2.raise_exception_on_mismatch.should be_false
60
+ slave_2.raise_exception_on_mismatch.should be_falsey
61
61
  end
62
62
  end
63
63
 
@@ -4,11 +4,11 @@ require 'rmodbus'
4
4
  describe ModBus::TCPClient do
5
5
  before(:each) do
6
6
  @uid = 1
7
- @sock = mock("Socket")
7
+ @sock = double('Socket')
8
8
  @adu = "\000\001\000\000\000\001\001"
9
9
 
10
10
  TCPSocket.should_receive(:new).with('127.0.0.1', 1502).and_return(@sock)
11
- @sock.stub!(:read).with(0).and_return('')
11
+ @sock.stub(:read).with(0).and_return('')
12
12
 
13
13
  @slave = ModBus::TCPClient.new('127.0.0.1', 1502).with_slave(@uid)
14
14
  @slave.debug = true
@@ -55,14 +55,19 @@ begin
55
55
  require "serialport"
56
56
  describe ModBus::RTUClient do
57
57
  before do
58
- @sp = mock('Serial port')
59
- SerialPort.should_receive(:new).with("/dev/port1", 9600, 7, 2, SerialPort::ODD).and_return(@sp)
60
-
58
+ @sp = double('Serial port')
59
+
60
+ SerialPort.should_receive(:new).with("/dev/port1", 9600, 7, 2, SerialPort::ODD).and_return(@sp)
61
+ SerialPort.stub(:public_method_defined?).with(:flush_input).and_return(true)
62
+
63
+ @sp.stub(:class).and_return(SerialPort)
61
64
  @sp.should_receive(:flow_control=).with(SerialPort::NONE)
62
- @sp.stub!(:read_timeout=)
63
-
65
+ @sp.stub(:read_timeout=)
66
+ @sp.stub(:flush_input)
67
+
64
68
  @slave = ModBus::RTUClient.new("/dev/port1", 9600, :data_bits => 7, :stop_bits => 2, :parity => SerialPort::ODD).with_slave(1)
65
69
  @slave.read_retries = 0
70
+
66
71
  end
67
72
 
68
73
  it 'should log rec\send bytes' do
@@ -3,7 +3,7 @@ require 'rmodbus'
3
3
 
4
4
  describe Array do
5
5
  before do
6
- @slave = mock('ModBus Slave')
6
+ @slave = double('ModBus Slave')
7
7
  @coil_proxy = ModBus::ReadWriteProxy.new(@slave, :coil)
8
8
  @discrete_input_proxy = ModBus::ReadOnlyProxy.new(@slave, :discrete_input)
9
9
  @holding_register_proxy = ModBus::ReadWriteProxy.new(@slave, :holding_register)
@@ -3,11 +3,15 @@ require 'rmodbus'
3
3
 
4
4
  describe ModBus::RTUClient do
5
5
  before do
6
- @sp = mock('Serial port')
6
+ @sp = double('Serial port')
7
+
7
8
  SerialPort.should_receive(:new).with("/dev/port1", 9600, 8, 1, 0).and_return(@sp)
8
- @sp.stub!(:read_timeout=)
9
+ SerialPort.stub(:public_method_defined?).with(:flush_input).and_return(true)
10
+
11
+ @sp.stub(:read_timeout=)
12
+ @sp.stub(:class).and_return(SerialPort)
9
13
  @sp.should_receive(:flow_control=).with(SerialPort::NONE)
10
- @sp.stub!(:flush_input)
14
+ @sp.stub(:flush_input)
11
15
 
12
16
  @cl = ModBus::RTUClient.new("/dev/port1", 9600, :data_bits => 8, :stop_bits => 1, :parity => SerialPort::NONE)
13
17
  @slave = @cl.with_slave(1)
@@ -3,9 +3,9 @@ require 'rmodbus'
3
3
 
4
4
  describe ModBus::RTUServer do
5
5
  before do
6
- @sp = mock "SerialPort"
6
+ @sp = double('SerialPort')
7
7
  SerialPort.should_receive(:new).with('/dev/ttyS0', 4800, 7, 2, SerialPort::NONE).and_return(@sp)
8
- @sp.stub!(:read_timeout=)
8
+ @sp.stub(:read_timeout=)
9
9
  @sp.should_receive(:flow_control=).with(SerialPort::NONE)
10
10
 
11
11
  @server = ModBus::RTUServer.new('/dev/ttyS0', 4800, 1, :data_bits => 7, :stop_bits => 2)
@@ -4,10 +4,10 @@ require 'rmodbus'
4
4
  describe ModBus::RTUViaTCPClient do
5
5
  describe "method 'query'" do
6
6
  before do
7
- @sock = mock('Socked')
7
+ @sock = double('Socket')
8
8
  TCPSocket.should_receive(:new).with("127.0.0.1", 10002).and_return(@sock)
9
- @sock.stub!(:read_timeout=)
10
- @sock.stub!(:flush_input)
9
+ @sock.stub(:read_timeout=)
10
+ @sock.stub(:flush)
11
11
 
12
12
  @cl = ModBus::RTUViaTCPClient.new("127.0.0.1")
13
13
  @slave = @cl.with_slave(1)
@@ -5,7 +5,7 @@ describe ModBus::Slave do
5
5
  before do
6
6
  @slave = ModBus::Client.new.with_slave(1)
7
7
 
8
- @slave.stub!(:query).and_return('')
8
+ @slave.stub(:query).and_return('')
9
9
  end
10
10
 
11
11
  it "should support function 'read coils'" do
@@ -5,11 +5,11 @@ describe ModBus::TCPClient do
5
5
  describe "method 'query'" do
6
6
  before(:each) do
7
7
  @uid = 1
8
- @sock = mock("Socket")
8
+ @sock = double('Socket')
9
9
  @adu = "\000\001\000\000\000\001\001"
10
10
 
11
11
  TCPSocket.should_receive(:new).with('127.0.0.1', 1502).and_return(@sock)
12
- @sock.stub!(:read).with(0).and_return('')
12
+ @sock.stub(:read).with(0).and_return('')
13
13
  @cl = ModBus::TCPClient.new('127.0.0.1', 1502)
14
14
  @slave = @cl.with_slave(@uid)
15
15
  end
@@ -33,8 +33,8 @@ describe ModBus::TCPClient do
33
33
  it 'should throw timeout exception if do not get own transaction' do
34
34
  @slave.read_retries = 2
35
35
  @adu[0,2] = @slave.transaction.next.to_word
36
- @sock.should_receive(:write).any_number_of_times.with(/\.*/)
37
- @sock.should_receive(:read).any_number_of_times.with(7).and_return("\000\x3\000\000\000\001" + @uid.chr)
36
+ @sock.should_receive(:write).at_least(1).times.with(/\.*/)
37
+ @sock.should_receive(:read).at_least(1).times.with(7).and_return("\000\x3\000\000\000\001" + @uid.chr)
38
38
 
39
39
  expect{ @slave.query('') }.to raise_error(ModBus::Errors::ModBusTimeout, "Timed out during read attempt")
40
40
  end
@@ -3,23 +3,28 @@ require "rmodbus"
3
3
 
4
4
  describe ModBus::TCPServer do
5
5
  before :all do
6
- @server = ModBus::TCPServer.new(8502,1)
6
+ unit_ids = (1..247).to_a.shuffle
7
+ valid_unit_id = unit_ids.first
8
+ @invalid_unit_id = unit_ids.last
9
+ @server = ModBus::TCPServer.new(8502, valid_unit_id)
7
10
  @server.coils = [1,0,1,1]
8
11
  @server.discrete_inputs = [1,1,0,0]
9
12
  @server.holding_registers = [1,2,3,4]
10
13
  @server.input_registers = [1,2,3,4]
11
14
  @server.start
12
15
  @cl = ModBus::TCPClient.new('127.0.0.1', 8502)
13
- @slave = @cl.with_slave(1)
14
- @slave.read_retries = 1
16
+ @cl.read_retries = 1
17
+ @slave = @cl.with_slave(valid_unit_id)
15
18
  end
16
19
 
17
- it "should silent if UID has mismatched" do
18
- @cl.with_slave(2).read_coils(1,3)
19
- #lambda { @cl.with_slave(2).read_coils(1,3) }.should raise_exception(
20
- # ModBus::Errors::ModBusException,
21
- # "Server did not respond"
22
- #)
20
+ it "should succeed if UID is broadcast" do
21
+ @cl.with_slave(0).read_coils(1,3)
22
+ end
23
+
24
+ it "should fail if UID is mismatched" do
25
+ lambda { @cl.with_slave(@invalid_unit_id).read_coils(1,3) }.should raise_exception(
26
+ ModBus::Errors::ModBusTimeout
27
+ )
23
28
  end
24
29
 
25
30
  it "should send exception if function not supported" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rmodbus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.6
4
+ version: 1.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - A.Timin, J. Sanders, K. Reynolds
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-21 00:00:00.000000000 Z
11
+ date: 2015-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '2.9'
47
+ version: '2.99'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '2.9'
54
+ version: '2.99'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: guard-rspec
57
57
  requirement: !ruby/object:Gem::Requirement