rmodbus 1.2.6 → 1.2.7

Sign up to get free protection for your applications and to get access to all the features.
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