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 +4 -4
- data/NEWS.md +7 -0
- data/README.md +11 -7
- data/lib/rmodbus/rtu.rb +7 -3
- data/lib/rmodbus/tcp_server.rb +24 -15
- data/lib/rmodbus/version.rb +2 -2
- data/spec/client_spec.rb +4 -4
- data/spec/logging_spec.rb +12 -7
- data/spec/proxy_spec.rb +1 -1
- data/spec/rtu_client_spec.rb +7 -3
- data/spec/rtu_server_spec.rb +2 -2
- data/spec/rtu_via_tcp_client_spec.rb +3 -3
- data/spec/slave_spec.rb +1 -1
- data/spec/tcp_client_spec.rb +4 -4
- data/spec/tcp_server_spec.rb +14 -9
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72ada248b0d55d8dfecb8cb022e30e0dbd4e50b3
|
4
|
+
data.tar.gz: 8de3ae040a26b173faa3bb1eca98b6d9bdba37c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
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
|
60
|
+
You can checkout source code from GitHub repository:
|
59
61
|
|
60
|
-
|
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
|
-
|
71
|
+
RModBus on GitHub: http://github.com/flipback/RModBus
|
68
72
|
|
69
|
-
ModBus
|
73
|
+
ModBus specifications: http://www.modbus.org/specs.php
|
data/lib/rmodbus/rtu.rb
CHANGED
@@ -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
|
-
|
109
|
-
|
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
|
data/lib/rmodbus/tcp_server.rb
CHANGED
@@ -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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
57
|
+
if unit_id == @uid || unit_id == 0
|
58
|
+
log "Server RX (#{req.size} bytes): #{logging_bytes(req)}"
|
53
59
|
|
54
|
-
|
60
|
+
pdu = exec_req(req, @coils, @discrete_inputs, @holding_registers, @input_registers)
|
55
61
|
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
61
|
-
|
69
|
+
end
|
70
|
+
end
|
62
71
|
end
|
63
72
|
end
|
data/lib/rmodbus/version.rb
CHANGED
@@ -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.
|
16
|
+
VERSION = '1.2.7'
|
17
17
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
60
|
+
slave_2.raise_exception_on_mismatch.should be_falsey
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
data/spec/logging_spec.rb
CHANGED
@@ -4,11 +4,11 @@ require 'rmodbus'
|
|
4
4
|
describe ModBus::TCPClient do
|
5
5
|
before(:each) do
|
6
6
|
@uid = 1
|
7
|
-
@sock =
|
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
|
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 =
|
59
|
-
|
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
|
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
|
data/spec/proxy_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require 'rmodbus'
|
|
3
3
|
|
4
4
|
describe Array do
|
5
5
|
before do
|
6
|
-
@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)
|
data/spec/rtu_client_spec.rb
CHANGED
@@ -3,11 +3,15 @@ require 'rmodbus'
|
|
3
3
|
|
4
4
|
describe ModBus::RTUClient do
|
5
5
|
before do
|
6
|
-
@sp =
|
6
|
+
@sp = double('Serial port')
|
7
|
+
|
7
8
|
SerialPort.should_receive(:new).with("/dev/port1", 9600, 8, 1, 0).and_return(@sp)
|
8
|
-
|
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
|
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)
|
data/spec/rtu_server_spec.rb
CHANGED
@@ -3,9 +3,9 @@ require 'rmodbus'
|
|
3
3
|
|
4
4
|
describe ModBus::RTUServer do
|
5
5
|
before do
|
6
|
-
@sp =
|
6
|
+
@sp = double('SerialPort')
|
7
7
|
SerialPort.should_receive(:new).with('/dev/ttyS0', 4800, 7, 2, SerialPort::NONE).and_return(@sp)
|
8
|
-
@sp.stub
|
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 =
|
7
|
+
@sock = double('Socket')
|
8
8
|
TCPSocket.should_receive(:new).with("127.0.0.1", 10002).and_return(@sock)
|
9
|
-
@sock.stub
|
10
|
-
@sock.stub
|
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)
|
data/spec/slave_spec.rb
CHANGED
data/spec/tcp_client_spec.rb
CHANGED
@@ -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 =
|
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
|
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).
|
37
|
-
@sock.should_receive(:read).
|
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
|
data/spec/tcp_server_spec.rb
CHANGED
@@ -3,23 +3,28 @@ require "rmodbus"
|
|
3
3
|
|
4
4
|
describe ModBus::TCPServer do
|
5
5
|
before :all do
|
6
|
-
|
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
|
-
@
|
14
|
-
@slave
|
16
|
+
@cl.read_retries = 1
|
17
|
+
@slave = @cl.with_slave(valid_unit_id)
|
15
18
|
end
|
16
19
|
|
17
|
-
it "should
|
18
|
-
@cl.with_slave(
|
19
|
-
|
20
|
-
|
21
|
-
|
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.
|
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-
|
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.
|
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.
|
54
|
+
version: '2.99'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: guard-rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|