rmodbus 0.5.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/NEWS.md +52 -0
  2. data/README.md +87 -0
  3. data/Rakefile +22 -36
  4. data/examples/perfomance_rtu.rb +35 -37
  5. data/examples/perfomance_tcp.rb +36 -38
  6. data/examples/use_rtu_via_tcp_modbus.rb +8 -5
  7. data/examples/use_tcp_modbus.rb +10 -6
  8. data/lib/rmodbus/client.rb +52 -174
  9. data/lib/rmodbus/common.rb +45 -18
  10. data/lib/rmodbus/{exceptions.rb → errors.rb} +3 -0
  11. data/lib/rmodbus/ext.rb +25 -2
  12. data/lib/rmodbus/proxy.rb +54 -0
  13. data/lib/rmodbus/{crc16.rb → rtu.rb} +73 -2
  14. data/lib/rmodbus/rtu_client.rb +20 -116
  15. data/lib/rmodbus/rtu_server.rb +28 -57
  16. data/lib/rmodbus/rtu_slave.rb +59 -0
  17. data/lib/rmodbus/rtu_via_tcp_client.rb +22 -86
  18. data/lib/rmodbus/rtu_via_tcp_server.rb +31 -95
  19. data/lib/rmodbus/rtu_via_tcp_slave.rb +58 -0
  20. data/lib/rmodbus/{parsers.rb → server.rb} +24 -15
  21. data/lib/rmodbus/slave.rb +268 -0
  22. data/lib/rmodbus/sp.rb +45 -0
  23. data/lib/rmodbus/tcp.rb +49 -0
  24. data/lib/rmodbus/tcp_client.rb +19 -88
  25. data/lib/rmodbus/tcp_server.rb +16 -19
  26. data/lib/rmodbus/tcp_slave.rb +64 -0
  27. data/lib/rmodbus/version.rb +17 -0
  28. data/lib/rmodbus.rb +20 -4
  29. data/spec/client_spec.rb +19 -45
  30. data/spec/exception_spec.rb +26 -27
  31. data/spec/ext_spec.rb +24 -1
  32. data/spec/logging_spec.rb +31 -37
  33. data/spec/proxy_spec.rb +73 -0
  34. data/spec/read_rtu_response_spec.rb +2 -4
  35. data/spec/rtu_client_spec.rb +17 -19
  36. data/spec/rtu_server_spec.rb +1 -3
  37. data/spec/rtu_via_tcp_client_spec.rb +69 -63
  38. data/spec/slave_spec.rb +55 -0
  39. data/spec/tcp_client_spec.rb +77 -69
  40. data/spec/tcp_server_spec.rb +34 -49
  41. metadata +123 -37
  42. data/AUTHORS +0 -3
  43. data/ChangeLog +0 -82
  44. data/LICENSE +0 -675
  45. data/README +0 -53
  46. data/examples/add_new_function.rb +0 -19
@@ -1,72 +1,78 @@
1
- begin
2
- require 'rubygems'
3
- rescue
4
- end
5
1
  require 'rmodbus'
6
-
7
2
  include ModBus
8
3
 
9
4
  describe RTUViaTCPClient do
5
+ describe "method 'query'" do
6
+ before do
7
+ @sock = mock('Socked')
8
+ TCPSocket.should_receive(:new).with("127.0.0.1", 10002).and_return(@sock)
9
+ @sock.stub!(:read_timeout=)
10
+ @sock.stub!(:read)
11
+
12
+ @cl = RTUViaTCPClient.new("127.0.0.1")
13
+ @slave = @cl.with_slave(1)
14
+ @slave.read_retries = 0
15
+ end
10
16
 
11
- before do
12
- @sock = mock('Socked')
13
- TCPSocket.should_receive(:new).with("127.0.0.1", 10002).and_return(@sock)
14
- @sock.stub!(:read_timeout=)
15
- @sock.stub!(:read)
16
-
17
- @mb_client = RTUViaTCPClient.new("127.0.0.1")
18
- @mb_client.read_retries = 0
19
- end
20
-
21
- it "should ignore frame with other UID" do
22
- request = "\x10\x0\x1\x0\x1\x2\xff\xff"
23
- @sock.should_receive(:write).with("\1#{request}\xA6\x31")
24
- @sock.should_receive(:read).with(2).and_return("\x2\x10")
25
- @sock.should_receive(:read).with(6).and_return("\x0\x1\x0\x1\x1C\x08")
26
- lambda {@mb_client.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
- @sock.should_receive(:write).with("\1#{request}\xA6\x31")
32
- @sock.should_receive(:read).with(2).and_return("\x2\x10")
33
- @sock.should_receive(:read).with(6).and_return("\x0\x1\x0\x1\x1C\x08")
34
- lambda {@mb_client.query(request)}.should raise_error(ModBus::Errors::ModBusTimeout)
35
- end
17
+ it "should ignore frame with other UID" do
18
+ request = "\x10\x0\x1\x0\x1\x2\xff\xff"
19
+ @sock.should_receive(:write).with("\1#{request}\xA6\x31")
20
+ @sock.should_receive(:read).with(2).and_return("\x2\x10")
21
+ @sock.should_receive(:read).with(6).and_return("\x0\x1\x0\x1\x1C\x08")
22
+ lambda {@slave.query(request)}.should raise_error(ModBus::Errors::ModBusTimeout)
23
+ end
24
+
25
+ it "should ignored frame with incorrect CRC" do
26
+ request = "\x10\x0\x1\x0\x1\x2\xff\xff"
27
+ @sock.should_receive(:write).with("\1#{request}\xA6\x31")
28
+ @sock.should_receive(:read).with(2).and_return("\x2\x10")
29
+ @sock.should_receive(:read).with(6).and_return("\x0\x1\x0\x1\x1C\x08")
30
+ lambda {@slave.query(request)}.should raise_error(ModBus::Errors::ModBusTimeout)
31
+ end
32
+
33
+ it "should return value of registers"do
34
+ request = "\x3\x0\x1\x0\x1"
35
+ @sock.should_receive(:write).with("\1#{request}\xd5\xca")
36
+ @sock.should_receive(:read).with(2).and_return("\x1\x3")
37
+ @sock.should_receive(:read).with(1).and_return("\x2")
38
+ @sock.should_receive(:read).with(4).and_return("\xff\xff\xb9\xf4")
39
+ @slave.query(request).should == "\xff\xff"
40
+ end
41
+
42
+ it 'should sugar connect method' do
43
+ ipaddr, port = '127.0.0.1', 502
44
+ TCPSocket.should_receive(:new).with(ipaddr, port).and_return(@sock)
45
+ @sock.should_receive(:closed?).and_return(false)
46
+ @sock.should_receive(:close)
47
+ RTUViaTCPClient.connect(ipaddr, port) do |cl|
48
+ cl.ipaddr.should == ipaddr
49
+ cl.port.should == port
50
+ end
51
+ end
52
+
53
+ it 'should have closed? method' do
54
+ @sock.should_receive(:closed?).and_return(false)
55
+ @cl.closed?.should == false
56
+
57
+ @sock.should_receive(:closed?).and_return(false)
58
+ @sock.should_receive(:close)
59
+
60
+ @cl.close
61
+
62
+ @sock.should_receive(:closed?).and_return(true)
63
+ @cl.closed?.should == true
64
+ end
65
+
66
+ it 'should give slave object in block' do
67
+ @cl.with_slave(1) do |slave|
68
+ slave.uid = 1
69
+ end
70
+ end
71
+ end
36
72
 
37
- it "should return value of registers"do
38
- request = "\x3\x0\x1\x0\x1"
39
- @sock.should_receive(:write).with("\1#{request}\xd5\xca")
40
- @sock.should_receive(:read).with(2).and_return("\x1\x3")
41
- @sock.should_receive(:read).with(1).and_return("\x2")
42
- @sock.should_receive(:read).with(4).and_return("\xff\xff\xb9\xf4")
43
- @mb_client.query(request).should == "\xff\xff"
44
- end
45
-
46
- it 'should sugar connect method' do
47
- ipaddr, port, slave = '127.0.0.1', 502, 3
48
- TCPSocket.should_receive(:new).with(ipaddr, port).and_return(@sock)
49
- @sock.should_receive(:closed?).and_return(false)
50
- @sock.should_receive(:close)
51
- RTUViaTCPClient.connect(ipaddr, port, slave) do |cl|
52
- cl.ipaddr.should == ipaddr
53
- cl.port.should == port
54
- cl.slave.should == slave
73
+ it "should tune connection timeout" do
74
+ timeout(0.5) do
75
+ lambda { RTUViaTCPClient.new('81.123.231.11', 1999, :connect_timeout => 0.1) }.should raise_error(ModBusTimeout)
55
76
  end
56
77
  end
57
-
58
- it 'should have closed? method' do
59
- @sock.should_receive(:closed?).and_return(false)
60
- @mb_client.closed?.should == false
61
-
62
- @sock.should_receive(:closed?).and_return(false)
63
- @sock.should_receive(:close)
64
-
65
- @mb_client.close
66
-
67
- @sock.should_receive(:closed?).and_return(true)
68
- @mb_client.closed?.should == true
69
- end
70
-
71
78
  end
72
-
@@ -0,0 +1,55 @@
1
+ require 'rmodbus'
2
+ include ModBus
3
+
4
+ describe Slave do
5
+ before do
6
+ @slave = Client.new.with_slave(1)
7
+
8
+ @slave.stub!(:query).and_return('')
9
+ end
10
+
11
+ it "should support function 'read coils'" do
12
+ @slave.should_receive(:query).with("\x1\x0\x13\x0\x13").and_return("\xcd\x6b\x5")
13
+ @slave.read_coils(0x13,0x13).should == [1,0,1,1, 0,0,1,1, 1,1,0,1, 0,1,1,0, 1,0,1]
14
+ end
15
+
16
+ it "should support function 'read discrete inputs'" do
17
+ @slave.should_receive(:query).with("\x2\x0\xc4\x0\x16").and_return("\xac\xdb\x35")
18
+ @slave.read_discrete_inputs(0xc4,0x16).should == [0,0,1,1, 0,1,0,1, 1,1,0,1, 1,0,1,1, 1,0,1,0, 1,1]
19
+ end
20
+
21
+ it "should support function 'read holding registers'" do
22
+ @slave.should_receive(:query).with("\x3\x0\x6b\x0\x3").and_return("\x2\x2b\x0\x0\x0\x64")
23
+ @slave.read_holding_registers(0x6b,0x3).should == [0x022b, 0x0000, 0x0064]
24
+ end
25
+
26
+ it "should support function 'read input registers'" do
27
+ @slave.should_receive(:query).with("\x4\x0\x8\x0\x1").and_return("\x0\xa")
28
+ @slave.read_input_registers(0x8,0x1).should == [0x000a]
29
+ end
30
+
31
+ it "should support function 'write single coil'" do
32
+ @slave.should_receive(:query).with("\x5\x0\xac\xff\x0").and_return("\xac\xff\x00")
33
+ @slave.write_single_coil(0xac,0x1).should == @slave
34
+ end
35
+
36
+ it "should support function 'write single register'" do
37
+ @slave.should_receive(:query).with("\x6\x0\x1\x0\x3").and_return("\x1\x0\x3")
38
+ @slave.write_single_register(0x1,0x3).should == @slave
39
+ end
40
+
41
+ it "should support function 'write multiple coils'" do
42
+ @slave.should_receive(:query).with("\xf\x0\x13\x0\xa\x2\xcd\x1").and_return("\x13\x0\xa")
43
+ @slave.write_multiple_coils(0x13,[1,0,1,1, 0,0,1,1, 1,0]).should == @slave
44
+ end
45
+
46
+ it "should support function 'write multiple registers'" do
47
+ @slave.should_receive(:query).with("\x10\x0\x1\x0\x3\x6\x0\xa\x1\x2\xf\xf").and_return("\x1\x0\x3")
48
+ @slave.write_multiple_registers(0x1,[0x000a,0x0102, 0xf0f]).should == @slave
49
+ end
50
+
51
+ it "should support function 'mask write register'" do
52
+ @slave.should_receive(:query).with("\x16\x0\x4\x0\xf2\x0\2").and_return("\x4\x0\xf2\x0\x2")
53
+ @slave.mask_write_register(0x4, 0xf2, 0x2).should == @slave
54
+ end
55
+ end
@@ -1,73 +1,81 @@
1
- require 'rmodbus/tcp_client'
2
-
3
- include ModBus
4
-
5
- describe TCPClient, "method 'query'" do
6
-
7
- UID = 1
8
-
9
- before(:each) do
10
- @sock = mock("Socket")
11
- @adu = "\000\001\000\000\000\001\001"
12
-
13
- TCPSocket.should_receive(:new).with('127.0.0.1', 1502).and_return(@sock)
14
- @sock.stub!(:read).with(0).and_return('')
15
-
16
- @mb_client = TCPClient.new('127.0.0.1', 1502)
17
- end
18
-
19
- it 'should send valid MBAP Header' do
20
- @adu[0,2] = @mb_client.transaction.next.to_word
21
- @sock.should_receive(:write).with(@adu)
22
- @sock.should_receive(:read).with(7).and_return(@adu)
23
- @mb_client.query('').should == nil
24
- end
25
-
26
- it 'should throw exception if get other transaction' do
27
- @adu[0,2] = @mb_client.transaction.next.to_word
28
- @sock.should_receive(:write).with(@adu)
29
- @sock.should_receive(:read).with(7).and_return("\000\002\000\000\000\001" + UID.chr)
30
- begin
31
- @mb_client.query('').should == nil
32
- rescue Exception => ex
33
- ex.class.should == Errors::ModBusException
1
+ require 'rmodbus'
2
+
3
+ describe TCPClient do
4
+ describe "method 'query'" do
5
+ before(:each) do
6
+ @uid = 1
7
+ @sock = mock("Socket")
8
+ @adu = "\000\001\000\000\000\001\001"
9
+
10
+ TCPSocket.should_receive(:new).with('127.0.0.1', 1502).and_return(@sock)
11
+ @sock.stub!(:read).with(0).and_return('')
12
+ @cl = ModBus::TCPClient.new('127.0.0.1', 1502)
13
+ @slave = @cl.with_slave(@uid)
34
14
  end
35
- end
36
-
37
- it 'should return only data from PDU' do
38
- request = "\x3\x0\x6b\x0\x3"
39
- response = "\x3\x6\x2\x2b\x0\x0\x0\x64"
40
- @adu = @mb_client.transaction.next.to_word + "\x0\x0\x0\x9" + UID.chr + request
41
- @sock.should_receive(:write).with(@adu[0,4] + "\0\6" + UID.chr + request)
42
- @sock.should_receive(:read).with(7).and_return(@adu[0,7])
43
- @sock.should_receive(:read).with(8).and_return(response)
44
-
45
- @mb_client.query(request).should == response[2..-1]
46
- end
47
-
48
- it 'should sugar connect method' do
49
- ipaddr, port, slave = '127.0.0.1', 502, 3
50
- TCPSocket.should_receive(:new).with(ipaddr, port).and_return(@sock)
51
- @sock.should_receive(:closed?).and_return(false)
52
- @sock.should_receive(:close)
53
- TCPClient.connect(ipaddr, port, slave) do |cl|
54
- cl.ipaddr.should == ipaddr
55
- cl.port.should == port
56
- cl.slave.should == slave
15
+
16
+ it 'should send valid MBAP Header' do
17
+ @adu[0,2] = @slave.transaction.next.to_word
18
+ @sock.should_receive(:write).with(@adu)
19
+ @sock.should_receive(:read).with(7).and_return(@adu)
20
+ @slave.query('').should == nil
21
+ end
22
+
23
+ it 'should throw exception if get other transaction' do
24
+ @adu[0,2] = @slave.transaction.next.to_word
25
+ @sock.should_receive(:write).with(@adu)
26
+ @sock.should_receive(:read).with(7).and_return("\000\002\000\000\000\001" + @uid.chr)
27
+ begin
28
+ @slave.query('').should == nil
29
+ rescue Exception => ex
30
+ ex.class.should == Errors::ModBusException
31
+ end
32
+ end
33
+
34
+ it 'should return only data from PDU' do
35
+ request = "\x3\x0\x6b\x0\x3"
36
+ response = "\x3\x6\x2\x2b\x0\x0\x0\x64"
37
+ @adu = @slave.transaction.next.to_word + "\x0\x0\x0\x9" + @uid.chr + request
38
+ @sock.should_receive(:write).with(@adu[0,4] + "\0\6" + @uid.chr + request)
39
+ @sock.should_receive(:read).with(7).and_return(@adu[0,7])
40
+ @sock.should_receive(:read).with(8).and_return(response)
41
+
42
+ @slave.query(request).should == response[2..-1]
43
+ end
44
+
45
+ it 'should sugar connect method' do
46
+ ipaddr, port = '127.0.0.1', 502
47
+ TCPSocket.should_receive(:new).with(ipaddr, port).and_return(@sock)
48
+ @sock.should_receive(:closed?).and_return(false)
49
+ @sock.should_receive(:close)
50
+ TCPClient.connect(ipaddr, port) do |cl|
51
+ cl.ipaddr.should == ipaddr
52
+ cl.port.should == port
53
+ end
54
+ end
55
+
56
+ it 'should have closed? method' do
57
+ @sock.should_receive(:closed?).and_return(false)
58
+ @cl.closed?.should == false
59
+
60
+ @sock.should_receive(:closed?).and_return(false)
61
+ @sock.should_receive(:close)
62
+
63
+ @cl.close
64
+
65
+ @sock.should_receive(:closed?).and_return(true)
66
+ @cl.closed?.should == true
67
+ end
68
+
69
+ it 'should give slave object in block' do
70
+ @cl.with_slave(1) do |slave|
71
+ slave.uid = 1
72
+ end
73
+ end
74
+ end
75
+
76
+ it "should tune connection timeout" do
77
+ timeout(0.5) do
78
+ lambda { ModBus::TCPClient.new('81.123.231.11', 1999, :connect_timeout => 0.1) }.should raise_error(ModBusTimeout)
57
79
  end
58
80
  end
59
-
60
- it 'should have closed? method' do
61
- @sock.should_receive(:closed?).and_return(false)
62
- @mb_client.closed?.should == false
63
-
64
- @sock.should_receive(:closed?).and_return(false)
65
- @sock.should_receive(:close)
66
-
67
- @mb_client.close
68
-
69
- @sock.should_receive(:closed?).and_return(true)
70
- @mb_client.closed?.should == true
71
- end
72
-
73
81
  end
@@ -1,7 +1,6 @@
1
- require 'lib/rmodbus'
1
+ require 'rmodbus'
2
2
 
3
3
  describe TCPServer do
4
-
5
4
  before do
6
5
  @server = ModBus::TCPServer.new(8502,1)
7
6
  @server.coils = [1,0,1,1]
@@ -9,104 +8,90 @@ describe TCPServer do
9
8
  @server.holding_registers = [1,2,3,4]
10
9
  @server.input_registers = [1,2,3,4]
11
10
  @server.start
12
- @client = ModBus::TCPClient.new('127.0.0.1', 8502, 1)
13
- @client.read_retries = 0
11
+ @cl = ModBus::TCPClient.new('127.0.0.1', 8502)
12
+ @slave = @cl.with_slave(1)
13
+ @slave.read_retries = 0
14
14
  end
15
15
 
16
16
  it "should silent if UID has mismatched" do
17
- @client.close
18
- client = ModBus::TCPClient.new('127.0.0.1', 8502, 2)
19
- begin
20
- client.read_coils(1,3)
21
- rescue ModBus::Errors::ModBusException => ex
22
- ex.message.should == "Server did not respond"
17
+ @cl.close
18
+ ModBus::TCPClient.connect('127.0.0.1', 8502) do |cl|
19
+ lambda { cl.with_slave(2).read_coils(1,3) }.should raise_exception(
20
+ ModBus::Errors::ModBusException,
21
+ "Server did not respond"
22
+ )
23
23
  end
24
- client.close
25
- end
26
-
27
- it "should silent if protocol identifer has mismatched" do
28
- @client.close
29
- client = TCPSocket.new('127.0.0.1', 8502)
30
- begin
31
- client.write "\0\0\1\0\0\6\1"
32
- rescue ModBus::Errors::ModBusException => ex
33
- ex.message.should == "Server did not respond"
34
- end
35
- client.close
36
24
  end
37
25
 
38
26
  it "should send exception if function not supported" do
39
- begin
40
- @client.query('0x43')
41
- rescue ModBus::Errors::IllegalFunction => ex
42
- ex.message.should == "The function code received in the query is not an allowable action for the server"
43
- end
27
+ lambda { @slave.query('0x43') }.should raise_exception(
28
+ ModBus::Errors::IllegalFunction,
29
+ "The function code received in the query is not an allowable action for the server"
30
+ )
44
31
  end
45
32
 
46
33
  it "should send exception if quanity of out more 0x7d" do
47
- begin
48
- @client.read_coils(0, 0x7e)
49
- rescue ModBus::Errors::IllegalDataValue => ex
50
- ex.message.should == "A value contained in the query data field is not an allowable value for server"
51
- end
34
+ lambda { @slave.read_coils(0, 0x7e) }.should raise_exception(
35
+ ModBus::Errors::IllegalDataValue,
36
+ "A value contained in the query data field is not an allowable value for server"
37
+ )
52
38
  end
53
39
 
54
40
  it "should send exception if addr not valid" do
55
- begin
56
- @client.read_coils(2, 8)
57
- rescue ModBus::Errors::IllegalDataAddress => ex
58
- ex.message.should == "The data address received in the query is not an allowable address for the server"
59
- end
41
+ lambda { @slave.read_coils(2, 8) }.should raise_exception(
42
+ ModBus::Errors::IllegalDataAddress,
43
+ "The data address received in the query is not an allowable address for the server"
44
+ )
60
45
  end
61
46
 
62
47
  it "should calc a many requests" do
63
- @client.read_coils(1,2)
64
- @client.write_multiple_registers(0,[9,9,9,])
65
- @client.read_holding_registers(0,3).should == [9,9,9]
48
+ @slave.read_coils(1,2)
49
+ @slave.write_multiple_registers(0,[9,9,9,])
50
+ @slave.read_holding_registers(0,3).should == [9,9,9]
66
51
  end
67
52
 
68
53
  it "should supported function 'read coils'" do
69
- @client.read_coils(0,3).should == @server.coils[0,3]
54
+ @slave.read_coils(0,3).should == @server.coils[0,3]
70
55
  end
71
56
 
72
57
  it "should supported function 'read discrete inputs'" do
73
- @client.read_discrete_inputs(1,3).should == @server.discrete_inputs[1,3]
58
+ @slave.read_discrete_inputs(1,3).should == @server.discrete_inputs[1,3]
74
59
  end
75
60
 
76
61
  it "should supported function 'read holding registers'" do
77
- @client.read_holding_registers(0,3).should == @server.holding_registers[0,3]
62
+ @slave.read_holding_registers(0,3).should == @server.holding_registers[0,3]
78
63
  end
79
64
 
80
65
  it "should supported function 'read input registers'" do
81
- @client.read_input_registers(2,2).should == @server.input_registers[2,2]
66
+ @slave.read_input_registers(2,2).should == @server.input_registers[2,2]
82
67
  end
83
68
 
84
69
  it "should supported function 'write single coil'" do
85
70
  @server.coils[3] = 0
86
- @client.write_single_coil(3,1)
71
+ @slave.write_single_coil(3,1)
87
72
  @server.coils[3].should == 1
88
73
  end
89
74
 
90
75
  it "should supported function 'write single register'" do
91
76
  @server.holding_registers[3] = 25
92
- @client.write_single_register(3,35)
77
+ @slave.write_single_register(3,35)
93
78
  @server.holding_registers[3].should == 35
94
79
  end
95
80
 
96
81
  it "should supported function 'write multiple coils'" do
97
82
  @server.coils = [1,1,1,0, 0,0,0,0, 0,0,0,0, 0,1,1,1]
98
- @client.write_multiple_coils(3, [1, 0,1,0,1, 0,1,0,1])
83
+ @slave.write_multiple_coils(3, [1, 0,1,0,1, 0,1,0,1])
99
84
  @server.coils.should == [1,1,1,1, 0,1,0,1, 0,1,0,1, 0,1,1,1]
100
85
  end
101
86
 
102
87
  it "should supported function 'write multiple registers'" do
103
88
  @server.holding_registers = [1,2,3,4,5,6,7,8,9]
104
- @client.write_multiple_registers(3,[1,2,3,4,5])
89
+ @slave.write_multiple_registers(3,[1,2,3,4,5])
105
90
  @server.holding_registers.should == [1,2,3,1,2,3,4,5,9]
106
91
  end
107
92
 
108
93
  after do
109
- @client.close
94
+ @cl.close
110
95
  @server.stop unless @server.stopped?
111
96
  while GServer.in_service?(8502)
112
97
  end