rmodbus-ccutrer 2.0.0 → 2.1.1
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 +4 -4
- data/NEWS.md +14 -7
- data/README.md +8 -8
- data/examples/perfomance_rtu.rb +55 -56
- data/examples/perfomance_rtu_via_tcp.rb +54 -55
- data/examples/perfomance_tcp.rb +54 -55
- data/examples/simple_xpca_gateway.rb +85 -0
- data/examples/use_rtu_via_tcp_modbus.rb +14 -11
- data/examples/use_tcp_modbus.rb +14 -11
- data/lib/rmodbus/client/slave.rb +58 -70
- data/lib/rmodbus/client.rb +13 -10
- data/lib/rmodbus/debug.rb +10 -6
- data/lib/rmodbus/errors.rb +26 -2
- data/lib/rmodbus/ext.rb +72 -51
- data/lib/rmodbus/options.rb +4 -1
- data/lib/rmodbus/proxy.rb +14 -9
- data/lib/rmodbus/rtu.rb +38 -32
- data/lib/rmodbus/rtu_client.rb +5 -2
- data/lib/rmodbus/rtu_server.rb +9 -7
- data/lib/rmodbus/rtu_slave.rb +6 -2
- data/lib/rmodbus/rtu_via_tcp_server.rb +7 -5
- data/lib/rmodbus/server/slave.rb +4 -2
- data/lib/rmodbus/server.rb +97 -73
- data/lib/rmodbus/sp.rb +10 -12
- data/lib/rmodbus/tcp.rb +5 -2
- data/lib/rmodbus/tcp_client.rb +3 -0
- data/lib/rmodbus/tcp_server.rb +28 -26
- data/lib/rmodbus/tcp_slave.rb +17 -16
- data/lib/rmodbus/version.rb +3 -1
- data/lib/rmodbus.rb +20 -18
- metadata +50 -49
- data/Rakefile +0 -29
- data/examples/simple-xpca-gateway.rb +0 -84
- data/spec/client_spec.rb +0 -88
- data/spec/exception_spec.rb +0 -120
- data/spec/ext_spec.rb +0 -52
- data/spec/logging_spec.rb +0 -89
- data/spec/proxy_spec.rb +0 -74
- data/spec/read_rtu_response_spec.rb +0 -92
- data/spec/response_mismach_spec.rb +0 -163
- data/spec/rtu_client_spec.rb +0 -86
- data/spec/rtu_server_spec.rb +0 -31
- data/spec/rtu_via_tcp_client_spec.rb +0 -76
- data/spec/rtu_via_tcp_server_spec.rb +0 -89
- data/spec/slave_spec.rb +0 -55
- data/spec/spec_helper.rb +0 -54
- data/spec/tcp_client_spec.rb +0 -88
- data/spec/tcp_server_spec.rb +0 -158
data/spec/exception_spec.rb
DELETED
@@ -1,120 +0,0 @@
|
|
1
|
-
# -*- coding: ascii
|
2
|
-
require 'rmodbus'
|
3
|
-
|
4
|
-
describe ModBus::TCPClient do
|
5
|
-
before(:all) do
|
6
|
-
@srv = ModBus::TCPServer.new(1502)
|
7
|
-
srv_slave = @srv.with_slave(1)
|
8
|
-
srv_slave.coils = [0] * 8
|
9
|
-
srv_slave.discrete_inputs = [0] * 8
|
10
|
-
srv_slave.holding_registers = [0] * 8
|
11
|
-
srv_slave.input_registers = [0] * 8
|
12
|
-
@srv.start
|
13
|
-
|
14
|
-
@cl = ModBus::TCPClient.new('127.0.0.1', 1502)
|
15
|
-
@slave = @cl.with_slave(1)
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should raise ProxException" do
|
19
|
-
lambda { @slave.holding_registers[0..2] = [0,0] }.should raise_error(ModBus::Errors::ProxyException)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Read coil status
|
23
|
-
it "should read coil status" do
|
24
|
-
@slave.read_coils(0, 4).should == [0] * 4
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should raise exception if illegal data address" do
|
28
|
-
lambda { @slave.read_coils(501, 34) }.should raise_error(ModBus::Errors::IllegalDataAddress)
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should raise exception if too many data" do
|
32
|
-
lambda { @slave.read_coils(0, 0x07D1) }.should raise_error(ModBus::Errors::IllegalDataValue)
|
33
|
-
end
|
34
|
-
|
35
|
-
# Read input status
|
36
|
-
it "should read discrete inputs" do
|
37
|
-
@slave.read_discrete_inputs(0, 4).should == [0] * 4
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should raise exception if illegal data address" do
|
41
|
-
lambda { @slave.read_discrete_inputs(50, 23) }.should raise_error(ModBus::Errors::IllegalDataAddress)
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should raise exception if too many data" do
|
45
|
-
lambda { @slave.read_discrete_inputs(0, 0x07D1) }.should raise_error(ModBus::Errors::IllegalDataValue)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Read holding registers
|
49
|
-
it "should read discrete inputs" do
|
50
|
-
@slave.read_holding_registers(0, 4).should == [0, 0, 0, 0]
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should raise exception if illegal data address" do
|
54
|
-
lambda { @slave.read_holding_registers(402, 99) }.should raise_error(ModBus::Errors::IllegalDataAddress)
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
it "should raise exception if too many data" do
|
59
|
-
lambda { @slave.read_holding_registers(0, 0x007E) }.should raise_error(ModBus::Errors::IllegalDataValue)
|
60
|
-
end
|
61
|
-
|
62
|
-
# Read input registers
|
63
|
-
it "should read discrete inputs" do
|
64
|
-
@slave.read_input_registers(0, 4).should == [0, 0, 0, 0]
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should raise exception if illegal data address" do
|
68
|
-
lambda { @slave.read_input_registers(402, 9) }.should raise_error(ModBus::Errors::IllegalDataAddress)
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should raise exception if too many data" do
|
72
|
-
lambda { @slave.read_input_registers(0, 0x007E) }.should raise_error(ModBus::Errors::IllegalDataValue)
|
73
|
-
end
|
74
|
-
|
75
|
-
# Force single coil
|
76
|
-
it "should force single coil" do
|
77
|
-
@slave.write_single_coil(4, 1).should == @slave
|
78
|
-
@slave.read_coils(4, 4).should == [1, 0, 0, 0]
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should raise exception if illegal data address" do
|
82
|
-
lambda { @slave.write_single_coil(501, true) }.should raise_error(ModBus::Errors::IllegalDataAddress)
|
83
|
-
end
|
84
|
-
|
85
|
-
# Preset single register
|
86
|
-
it "should preset single register" do
|
87
|
-
@slave.write_single_register(4, 0x0AA0).should == @slave
|
88
|
-
@slave.read_holding_registers(4, 1).should == [0x0AA0]
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should raise exception if illegal data address" do
|
92
|
-
lambda { @slave.write_single_register(501, 0x0AA0) }.should raise_error(ModBus::Errors::IllegalDataAddress)
|
93
|
-
end
|
94
|
-
|
95
|
-
# Force multiple coils
|
96
|
-
it "should force multiple coils" do
|
97
|
-
@slave.write_multiple_coils(4, [0,1,0,1]).should == @slave
|
98
|
-
@slave.read_coils(3, 5).should == [0,0,1,0,1]
|
99
|
-
end
|
100
|
-
|
101
|
-
it "should raise exception if illegal data address" do
|
102
|
-
lambda { @slave.write_multiple_coils(501, [1,0]) }.should raise_error(ModBus::Errors::IllegalDataAddress)
|
103
|
-
end
|
104
|
-
|
105
|
-
# Preset multiple registers
|
106
|
-
it "should preset multiple registers" do
|
107
|
-
@slave.write_multiple_registers(4, [1, 2, 3, 0xAACC]).should == @slave
|
108
|
-
@slave.read_holding_registers(3, 5).should == [0, 1, 2, 3, 0xAACC]
|
109
|
-
end
|
110
|
-
|
111
|
-
it "should raise exception if illegal data address" do
|
112
|
-
lambda { @slave.write_multiple_registers(501, [1, 2]) }.should raise_error(ModBus::Errors::IllegalDataAddress)
|
113
|
-
end
|
114
|
-
|
115
|
-
after(:all) do
|
116
|
-
@cl.close unless @cl.closed?
|
117
|
-
@srv.stop
|
118
|
-
end
|
119
|
-
|
120
|
-
end
|
data/spec/ext_spec.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
# -*- coding: ascii
|
2
|
-
require 'rmodbus'
|
3
|
-
|
4
|
-
describe Array do
|
5
|
-
before do
|
6
|
-
@arr = [1,0,1,1, 0,0,1,1, 1,1,0,1, 0,1,1,0, 1,0,1]
|
7
|
-
@test = [0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0]
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should return string reprisent 16bit" do
|
11
|
-
@arr.pack_to_word.should == "\xcd\x6b\x5"
|
12
|
-
end
|
13
|
-
|
14
|
-
it "fixed bug for divisible 8 data " do
|
15
|
-
([0] * 8).pack_to_word.should == "\x00"
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should unpack to @test" do
|
19
|
-
"test".unpack_bits == @test
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should turn an array into 32b ints" do
|
23
|
-
[20342, 17344].to_32i.should == [1136676726]
|
24
|
-
[20342, 17344, 20342, 17344].to_32i.size.should == 2
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should turn an array into 32b floats big endian" do
|
28
|
-
[20342, 17344].to_32f[0].should be_within(0.1).of(384.620788574219)
|
29
|
-
[20342, 17344, 20342, 17344].to_32f.size.should == 2
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should turn a an array into 32b floats (little endian)" do
|
33
|
-
[17344, 20342].to_32f_le[0].should be_within(0.1).of(384.620788574219)
|
34
|
-
[17344, 20342, 17344, 20342].to_32f_le.size.should == 2
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should turn an array from 32b ints into 16b ints, big endian" do
|
38
|
-
[1136676726].from_32i.should == [20342, 17344]
|
39
|
-
[1136676726, 1136676725].from_32i.should == [20342, 17344, 20341, 17344]
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should turn an array from 32b floats into 16b ints, big endian" do
|
43
|
-
[384.620788].from_32f.should == [20342, 17344]
|
44
|
-
[384.620788, 384.620788].from_32f.should == [20342, 17344, 20342, 17344]
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should raise exception if uneven number of elements" do
|
48
|
-
lambda { [20342, 17344, 123].to_32f }.should raise_error(StandardError)
|
49
|
-
lambda { [20342, 17344, 123].to_32i }.should raise_error(StandardError)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
data/spec/logging_spec.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
# -*- coding: ascii
|
2
|
-
require 'rmodbus'
|
3
|
-
|
4
|
-
describe ModBus::TCPClient do
|
5
|
-
before(:each) do
|
6
|
-
@uid = 1
|
7
|
-
@sock = double('Socket')
|
8
|
-
@adu = "\000\001\000\000\000\001\001"
|
9
|
-
|
10
|
-
Socket.should_receive(:tcp).with('127.0.0.1', 1502, nil, nil, hash_including(:connect_timeout)).and_return(@sock)
|
11
|
-
@sock.stub(:read).with(0).and_return('')
|
12
|
-
|
13
|
-
@slave = ModBus::TCPClient.new('127.0.0.1', 1502).with_slave(@uid)
|
14
|
-
@slave.debug = true
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'should log rec\send bytes' do
|
18
|
-
request, response = "\x3\x0\x6b\x0\x3", "\x3\x6\x2\x2b\x0\x0\x0\x64"
|
19
|
-
mock_query(request,response)
|
20
|
-
$stdout.should_receive(:puts).with("Tx (12 bytes): [00][01][00][00][00][06][01][03][00][6b][00][03]")
|
21
|
-
$stdout.should_receive(:puts).with("Rx (15 bytes): [00][01][00][00][00][09][01][03][06][02][2b][00][00][00][64]")
|
22
|
-
@slave.query(request)
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should don't logging if debug disable" do
|
26
|
-
@slave.debug = false
|
27
|
-
request, response = "\x3\x0\x6b\x0\x3", "\x3\x6\x2\x2b\x0\x0\x0\x64"
|
28
|
-
mock_query(request,response)
|
29
|
-
@slave.query(request)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should log warn message if transaction mismatch" do
|
33
|
-
@adu[0,2] = @slave.transaction.next.to_word
|
34
|
-
@sock.should_receive(:write).with(@adu)
|
35
|
-
@sock.should_receive(:read).with(7).and_return("\000\002\000\000\000\001" + @uid.chr)
|
36
|
-
@sock.should_receive(:read).with(7).and_return("\000\001\000\000\000\001" + @uid.chr)
|
37
|
-
|
38
|
-
$stdout.should_receive(:puts).with("Tx (7 bytes): [00][01][00][00][00][01][01]")
|
39
|
-
$stdout.should_receive(:puts).with("Rx (7 bytes): [00][02][00][00][00][01][01]")
|
40
|
-
$stdout.should_receive(:puts).with("Transaction number mismatch. A packet is ignored.")
|
41
|
-
$stdout.should_receive(:puts).with("Rx (7 bytes): [00][01][00][00][00][01][01]")
|
42
|
-
|
43
|
-
@slave.query('')
|
44
|
-
end
|
45
|
-
|
46
|
-
def mock_query(request, response)
|
47
|
-
@adu = @slave.transaction.next.to_word + "\x0\x0\x0\x9" + @uid.chr + request
|
48
|
-
@sock.should_receive(:write).with(@adu[0,4] + "\0\6" + @uid.chr + request)
|
49
|
-
@sock.should_receive(:read).with(7).and_return(@adu[0,7])
|
50
|
-
@sock.should_receive(:read).with(8).and_return(response)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
begin
|
55
|
-
require "serialport"
|
56
|
-
describe ModBus::RTUClient do
|
57
|
-
before do
|
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)
|
64
|
-
@sp.should_receive(:flow_control=).with(SerialPort::NONE)
|
65
|
-
@sp.stub(:read_timeout=)
|
66
|
-
@sp.stub(:flush_input)
|
67
|
-
|
68
|
-
@slave = ModBus::RTUClient.new("/dev/port1", 9600, :data_bits => 7, :stop_bits => 2, :parity => SerialPort::ODD).with_slave(1)
|
69
|
-
@slave.read_retries = 0
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'should log rec\send bytes' do
|
74
|
-
request = "\x3\x0\x1\x0\x1"
|
75
|
-
@sp.should_receive(:write).with("\1#{request}\xd5\xca")
|
76
|
-
@sp.should_receive(:flush_input) # Clean a garbage
|
77
|
-
@sp.should_receive(:read).with(2).and_return("\x1\x3")
|
78
|
-
@sp.should_receive(:read).with(1).and_return("\x2")
|
79
|
-
@sp.should_receive(:read).with(4).and_return("\xff\xff\xb9\xf4")
|
80
|
-
|
81
|
-
@slave.debug = true
|
82
|
-
$stdout.should_receive(:puts).with("Tx (8 bytes): [01][03][00][01][00][01][d5][ca]")
|
83
|
-
$stdout.should_receive(:puts).with("Rx (7 bytes): [01][03][02][ff][ff][b9][f4]")
|
84
|
-
|
85
|
-
@slave.query(request).should == "\xff\xff"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
rescue LoadError
|
89
|
-
end
|
data/spec/proxy_spec.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
# -*- coding: ascii
|
2
|
-
require 'rmodbus'
|
3
|
-
|
4
|
-
describe Array do
|
5
|
-
before do
|
6
|
-
@slave = double('ModBus Slave')
|
7
|
-
@coil_proxy = ModBus::ReadWriteProxy.new(@slave, :coil)
|
8
|
-
@discrete_input_proxy = ModBus::ReadOnlyProxy.new(@slave, :discrete_input)
|
9
|
-
@holding_register_proxy = ModBus::ReadWriteProxy.new(@slave, :holding_register)
|
10
|
-
@input_register_proxy = ModBus::ReadOnlyProxy.new(@slave, :input_register)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Handle all of the coil methods
|
14
|
-
it "should call read_coil" do
|
15
|
-
@slave.should_receive(:read_coil).with(0, 1)
|
16
|
-
@coil_proxy[0]
|
17
|
-
end
|
18
|
-
it "should call read_coils" do
|
19
|
-
@slave.should_receive(:read_coils).with(0, 2)
|
20
|
-
@coil_proxy[0..1]
|
21
|
-
end
|
22
|
-
it "should call write_coil" do
|
23
|
-
@slave.should_receive(:write_coil).with(0, 1)
|
24
|
-
@coil_proxy[0] = 1
|
25
|
-
end
|
26
|
-
it "should call write_coils" do
|
27
|
-
@slave.should_receive(:write_coils).with(0, [0, 0])
|
28
|
-
@coil_proxy[0..1] = [0, 0]
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
# Discrete input tests
|
33
|
-
it "should call read_discrete_input" do
|
34
|
-
@slave.should_receive(:read_discrete_input).with(0, 1)
|
35
|
-
@discrete_input_proxy[0]
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should call read_discrete_inputs" do
|
39
|
-
@slave.should_receive(:read_discrete_inputs).with(0, 2)
|
40
|
-
@discrete_input_proxy[0..1]
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
# Holding Register Tess
|
45
|
-
it "should call read_holding_register" do
|
46
|
-
@slave.should_receive(:read_holding_register).with(0, 1)
|
47
|
-
@holding_register_proxy[0]
|
48
|
-
end
|
49
|
-
it "should call read_holding_registers" do
|
50
|
-
@slave.should_receive(:read_holding_registers).with(0, 2)
|
51
|
-
@holding_register_proxy[0..1]
|
52
|
-
end
|
53
|
-
it "should call write_holding_register" do
|
54
|
-
@slave.should_receive(:write_holding_register).with(0, 1)
|
55
|
-
@holding_register_proxy[0] = 1
|
56
|
-
end
|
57
|
-
it "should call write_holding_registers" do
|
58
|
-
@slave.should_receive(:write_holding_registers).with(0, [0, 0])
|
59
|
-
@holding_register_proxy[0..1] = [0, 0]
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
# Input Register Tests
|
64
|
-
it "should call read_discrete_input" do
|
65
|
-
@slave.should_receive(:read_input_register).with(0, 1)
|
66
|
-
@input_register_proxy[0]
|
67
|
-
end
|
68
|
-
|
69
|
-
it "should call read_discrete_inputs" do
|
70
|
-
@slave.should_receive(:read_input_registers).with(0, 2)
|
71
|
-
@input_register_proxy[0..1]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
@@ -1,92 +0,0 @@
|
|
1
|
-
# -*- coding: ascii
|
2
|
-
require 'rmodbus'
|
3
|
-
|
4
|
-
#Use public wrap method
|
5
|
-
class ModBus::Client
|
6
|
-
include ModBus::RTU
|
7
|
-
def test_read_method(msg)
|
8
|
-
io = TestIO.new(msg)
|
9
|
-
read_rtu_response(io)
|
10
|
-
end
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
class TestIO
|
15
|
-
def initialize(msg)
|
16
|
-
@msg = msg
|
17
|
-
end
|
18
|
-
|
19
|
-
def read(num)
|
20
|
-
result = @msg[0,num]
|
21
|
-
@msg = @msg[num..-1]
|
22
|
-
result
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe "#read_rtu_response" do
|
27
|
-
before do
|
28
|
-
@cl_mb = ModBus::Client.new
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should read response for 'read coils'" do
|
32
|
-
resp = make_resp("\x1\x3\xcd\x6b\x05")
|
33
|
-
@cl_mb.test_read_method(resp).should == resp
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should read response for 'read discrete inputs'" do
|
37
|
-
resp = make_resp("\x2\x3\xac\xdb\x35")
|
38
|
-
@cl_mb.test_read_method(resp).should == resp
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should read response for 'read holding registers'" do
|
42
|
-
resp = make_resp("\x3\x6\x2\x2b\x0\x0\x0\x64")
|
43
|
-
@cl_mb.test_read_method(resp).should == resp
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should read response for 'read input registers'" do
|
47
|
-
resp = make_resp("\x4\x2\x0\xa")
|
48
|
-
@cl_mb.test_read_method(resp).should == resp
|
49
|
-
end
|
50
|
-
|
51
|
-
it "should read response for 'write single coil'" do
|
52
|
-
resp = make_resp("\x5\x0\xac\xff\x0")
|
53
|
-
@cl_mb.test_read_method(resp).should == resp
|
54
|
-
end
|
55
|
-
|
56
|
-
it "should read response for 'write single register'" do
|
57
|
-
resp = make_resp("\x6\x0\x1\x0\x3")
|
58
|
-
@cl_mb.test_read_method(resp).should == resp
|
59
|
-
end
|
60
|
-
|
61
|
-
it "should read response for 'write multiple coils'" do
|
62
|
-
resp = make_resp("\xf\x0\x13\x0\xa")
|
63
|
-
@cl_mb.test_read_method(resp).should == resp
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should read response for 'write multiple registers'" do
|
67
|
-
resp = make_resp("\x10\x0\x1\x0\x2")
|
68
|
-
@cl_mb.test_read_method(resp).should == resp
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should read response 'mask write register'" do
|
72
|
-
resp = make_resp("\x16\x0\x4\x0\xf2\x0\x25")
|
73
|
-
@cl_mb.test_read_method(resp).should == resp
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should read exception codes" do
|
77
|
-
resp = make_resp("\x84\x3")
|
78
|
-
@cl_mb.test_read_method(resp).should == resp
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should raise exception if function is illegal" do
|
82
|
-
resp = make_resp("\x1f\x0\x1\x0\x2")
|
83
|
-
lambda{ @cl_mb.test_read_method(resp)}.should raise_error {
|
84
|
-
ModBus::Errors::IllegalFunction
|
85
|
-
}
|
86
|
-
end
|
87
|
-
|
88
|
-
def make_resp(msg)
|
89
|
-
"\x1" + msg + "\x2\x2" # slave + msg + mock_crc
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
@@ -1,163 +0,0 @@
|
|
1
|
-
# -*- coding: ascii
|
2
|
-
require "spec_helper"
|
3
|
-
|
4
|
-
describe "response mismach" do
|
5
|
-
include RaiseResponseMatcher
|
6
|
-
before(:each) do
|
7
|
-
@slave = ModBus::Client::Slave.new(1, nil)
|
8
|
-
@slave.raise_exception_on_mismatch = true
|
9
|
-
end
|
10
|
-
|
11
|
-
it "should raise error if function code is mismatch" do
|
12
|
-
request = "\x1\x0\x13\x0\x12"
|
13
|
-
response = "\x2\x3\xcd\xb6\x5"
|
14
|
-
mock_query!(request, response)
|
15
|
-
|
16
|
-
lambda{ @slave.read_coils(0x13,0x12) }.should raise_response_mismatch(
|
17
|
-
"Function code is mismatch (expected 1, got 2)",
|
18
|
-
request, response)
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "read coils" do
|
22
|
-
it "should raise error if count of byte is mismatch" do
|
23
|
-
request = "\x1\x0\x13\x0\x12"
|
24
|
-
response = "\x1\x2\xcd\xb6"
|
25
|
-
mock_query!(request, response)
|
26
|
-
|
27
|
-
lambda{ @slave.read_coils(0x13,0x12) }.should raise_response_mismatch(
|
28
|
-
"Byte count is mismatch (expected 3, got 2 bytes)",
|
29
|
-
request, response)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
describe "read discrete inputs" do
|
34
|
-
it "should raise error if count of byte is mismatch" do
|
35
|
-
request = "\x2\x0\x13\x0\x12"
|
36
|
-
response = "\x2\x2\xcd\xb6"
|
37
|
-
mock_query!(request, response)
|
38
|
-
|
39
|
-
lambda{ @slave.read_discrete_inputs(0x13,0x12) }.should raise_response_mismatch(
|
40
|
-
"Byte count is mismatch (expected 3, got 2 bytes)",
|
41
|
-
request, response)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe "read holding registesrs" do
|
46
|
-
it "should raise error if count of registers is mismatch" do
|
47
|
-
request = "\x3\x0\x8\x0\x1"
|
48
|
-
response = "\x3\x4\x0\xa\x0\xb"
|
49
|
-
mock_query!(request, response)
|
50
|
-
|
51
|
-
lambda{ @slave.read_holding_registers(0x8,0x1) }.should raise_response_mismatch(
|
52
|
-
"Register count is mismatch (expected 1, got 2 regs)",
|
53
|
-
request, response)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe "read input registesrs" do
|
58
|
-
it "should raise error if count of registers is mismatch" do
|
59
|
-
request = "\x4\x0\x8\x0\x2"
|
60
|
-
response = "\x4\x2\xa\x0"
|
61
|
-
mock_query!(request, response)
|
62
|
-
|
63
|
-
lambda{ @slave.read_input_registers(0x8,0x2) }.should raise_response_mismatch(
|
64
|
-
"Register count is mismatch (expected 2, got 1 regs)",
|
65
|
-
request, response)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe "write single coil" do
|
70
|
-
it "should raise error if address of coil is mismatch" do
|
71
|
-
request = "\x5\x0\x8\xff\x0"
|
72
|
-
response = "\x5\x0\x9\xff\x0"
|
73
|
-
mock_query!(request, response)
|
74
|
-
|
75
|
-
lambda{ @slave.write_coil(8,true) }.should raise_response_mismatch(
|
76
|
-
"Address is mismatch (expected 8, got 9)",
|
77
|
-
request, response)
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should raise error if value of coil is mismatch" do
|
81
|
-
request = "\x5\x0\x8\xff\x0"
|
82
|
-
response = "\x5\x0\x8\x0\x0"
|
83
|
-
mock_query!(request, response)
|
84
|
-
|
85
|
-
lambda{ @slave.write_coil(8,true) }.should raise_response_mismatch(
|
86
|
-
"Value is mismatch (expected 0xff00, got 0x0)",
|
87
|
-
request, response)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
describe "write single register" do
|
92
|
-
it "should raise error if address of register is mismatch" do
|
93
|
-
request = "\x6\x0\x8\xa\xb"
|
94
|
-
response = "\x6\x0\x9\xa\xb"
|
95
|
-
mock_query!(request, response)
|
96
|
-
|
97
|
-
lambda{ @slave.write_single_register(8,0x0a0b) }.should raise_response_mismatch(
|
98
|
-
"Address is mismatch (expected 8, got 9)",
|
99
|
-
request, response)
|
100
|
-
end
|
101
|
-
|
102
|
-
it "should raise error if value of register is mismatch" do
|
103
|
-
request = "\x6\x0\x8\xa\xb"
|
104
|
-
response = "\x6\x0\x8\x9\xb"
|
105
|
-
mock_query!(request, response)
|
106
|
-
|
107
|
-
lambda{ @slave.write_single_register(8,0x0a0b) }.should raise_response_mismatch(
|
108
|
-
"Value is mismatch (expected 0xa0b, got 0x90b)",
|
109
|
-
request, response)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
describe "write multiple coils" do
|
114
|
-
it "should raise error if address of first coil is mismatch" do
|
115
|
-
request = "\xf\x0\x13\x0\xa\2\xcd\x01"
|
116
|
-
response = "\xf\x0\x14\x0\xa"
|
117
|
-
mock_query!(request, response)
|
118
|
-
|
119
|
-
lambda{ @slave.write_coils(0x13,[1,0,1,1, 0,0,1,1, 1,0]) }.should raise_response_mismatch(
|
120
|
-
"Address is mismatch (expected 19, got 20)",
|
121
|
-
request, response)
|
122
|
-
end
|
123
|
-
|
124
|
-
it "should raise error if quantity of coils is mismatch" do
|
125
|
-
request = "\xf\x0\x13\x0\xa\2\xcd\x01"
|
126
|
-
response = "\xf\x0\x13\x0\x9"
|
127
|
-
mock_query!(request, response)
|
128
|
-
|
129
|
-
lambda{ @slave.write_coils(0x13,[1,0,1,1, 0,0,1,1, 1,0]) }.should raise_response_mismatch(
|
130
|
-
"Quantity is mismatch (expected 10, got 9)",
|
131
|
-
request, response)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
describe "write multiple registers" do
|
136
|
-
it "should raise error if address of first register is mismatch" do
|
137
|
-
request = "\x10\x0\x1\x0\x2\x4\x0\xa\x1\x2"
|
138
|
-
response = "\x10\x0\x2\x0\x2"
|
139
|
-
mock_query!(request, response)
|
140
|
-
|
141
|
-
lambda{ @slave.write_holding_registers(0x1,[0xa,0x102]) }.should raise_response_mismatch(
|
142
|
-
"Address is mismatch (expected 1, got 2)",
|
143
|
-
request, response)
|
144
|
-
end
|
145
|
-
|
146
|
-
it "should raise error if quantity of registers is mismatch" do
|
147
|
-
request = "\x10\x0\x1\x0\x2\x4\x0\xa\x1\x2"
|
148
|
-
response = "\x10\x0\x2\x0\x1"
|
149
|
-
mock_query!(request, response)
|
150
|
-
|
151
|
-
lambda{ @slave.write_holding_registers(0x1,[0xa,0x102]) }.should raise_response_mismatch(
|
152
|
-
"Quantity is mismatch (expected 2, got 1)",
|
153
|
-
request, response)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
|
158
|
-
private
|
159
|
-
def mock_query!(request, response)
|
160
|
-
@slave.should_receive(:send_pdu).with(request)
|
161
|
-
@slave.should_receive(:read_pdu).and_return(response)
|
162
|
-
end
|
163
|
-
end
|
data/spec/rtu_client_spec.rb
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
# -*- coding: ascii
|
2
|
-
require 'rmodbus'
|
3
|
-
|
4
|
-
describe ModBus::RTUClient do
|
5
|
-
before do
|
6
|
-
@sp = double('Serial port')
|
7
|
-
|
8
|
-
SerialPort.should_receive(:new).with("/dev/port1", 9600, 8, 1, 0).and_return(@sp)
|
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)
|
13
|
-
@sp.should_receive(:flow_control=).with(SerialPort::NONE)
|
14
|
-
@sp.stub(:flush_input)
|
15
|
-
|
16
|
-
@cl = ModBus::RTUClient.new("/dev/port1", 9600, :data_bits => 8, :stop_bits => 1, :parity => SerialPort::NONE)
|
17
|
-
@slave = @cl.with_slave(1)
|
18
|
-
@slave.read_retries = 1
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should ignore frame with other UID" do
|
22
|
-
request = "\x10\x0\x1\x0\x1\x2\xff\xff"
|
23
|
-
@sp.should_receive(:write).with("\1#{request}\xA6\x31")
|
24
|
-
@sp.should_receive(:read).with(2).and_return("\x2\x10")
|
25
|
-
@sp.should_receive(:read).with(6).and_return("\x0\x1\x0\x1\x1C\x08")
|
26
|
-
lambda {@slave.query(request)}.should raise_error(ModBus::Errors::ModBusTimeout)
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should ignored frame with incorrect CRC" do
|
30
|
-
request = "\x10\x0\x1\x0\x1\x2\xff\xff"
|
31
|
-
@sp.should_receive(:write).with("\1#{request}\xA6\x31")
|
32
|
-
@sp.should_receive(:read).with(2).and_return("\x2\x10")
|
33
|
-
@sp.should_receive(:read).with(6).and_return("\x0\x1\x0\x1\x1C\x08")
|
34
|
-
lambda {@slave.query(request)}.should raise_error(ModBus::Errors::ModBusTimeout)
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should return value of registers"do
|
38
|
-
request = stab_valid_request
|
39
|
-
@slave.query(request).should == "\xff\xff"
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'should sugar connect method' do
|
43
|
-
port, baud = "/dev/port1", 4800
|
44
|
-
SerialPort.should_receive(:new).with(port, baud, 8, 1, SerialPort::NONE).and_return(@sp)
|
45
|
-
@sp.should_receive(:closed?).and_return(false)
|
46
|
-
@sp.should_receive(:close)
|
47
|
-
@sp.should_receive(:flow_control=).with(SerialPort::NONE)
|
48
|
-
ModBus::RTUClient.connect(port, baud) do |cl|
|
49
|
-
cl.port.should == port
|
50
|
-
cl.baud.should == baud
|
51
|
-
cl.data_bits.should == 8
|
52
|
-
cl.stop_bits.should == 1
|
53
|
-
cl.parity.should == SerialPort::NONE
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'should have closed? method' do
|
58
|
-
@sp.should_receive(:closed?).and_return(false)
|
59
|
-
@cl.closed?.should == false
|
60
|
-
|
61
|
-
@sp.should_receive(:closed?).and_return(false)
|
62
|
-
@sp.should_receive(:close)
|
63
|
-
|
64
|
-
@cl.close
|
65
|
-
|
66
|
-
@sp.should_receive(:closed?).and_return(true)
|
67
|
-
@cl.closed?.should == true
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'should give slave object in block' do
|
71
|
-
@cl.with_slave(1) do |slave|
|
72
|
-
slave.uid = 1
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def stab_valid_request
|
77
|
-
request = "\x3\x0\x1\x0\x1"
|
78
|
-
@sp.should_receive(:write).with("\1#{request}\xd5\xca")
|
79
|
-
@sp.should_receive(:read).with(2).and_return("\x1\x3")
|
80
|
-
@sp.should_receive(:read).with(1).and_return("\x2")
|
81
|
-
@sp.should_receive(:read).with(4).and_return("\xff\xff\xb9\xf4")
|
82
|
-
|
83
|
-
request
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|