rmodbus 0.5.0 → 1.0.0
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.
- data/NEWS.md +52 -0
- data/README.md +87 -0
- data/Rakefile +22 -36
- data/examples/perfomance_rtu.rb +35 -37
- data/examples/perfomance_tcp.rb +36 -38
- data/examples/use_rtu_via_tcp_modbus.rb +8 -5
- data/examples/use_tcp_modbus.rb +10 -6
- data/lib/rmodbus/client.rb +52 -174
- data/lib/rmodbus/common.rb +45 -18
- data/lib/rmodbus/{exceptions.rb → errors.rb} +3 -0
- data/lib/rmodbus/ext.rb +25 -2
- data/lib/rmodbus/proxy.rb +54 -0
- data/lib/rmodbus/{crc16.rb → rtu.rb} +73 -2
- data/lib/rmodbus/rtu_client.rb +20 -116
- data/lib/rmodbus/rtu_server.rb +28 -57
- data/lib/rmodbus/rtu_slave.rb +59 -0
- data/lib/rmodbus/rtu_via_tcp_client.rb +22 -86
- data/lib/rmodbus/rtu_via_tcp_server.rb +31 -95
- data/lib/rmodbus/rtu_via_tcp_slave.rb +58 -0
- data/lib/rmodbus/{parsers.rb → server.rb} +24 -15
- data/lib/rmodbus/slave.rb +268 -0
- data/lib/rmodbus/sp.rb +45 -0
- data/lib/rmodbus/tcp.rb +49 -0
- data/lib/rmodbus/tcp_client.rb +19 -88
- data/lib/rmodbus/tcp_server.rb +16 -19
- data/lib/rmodbus/tcp_slave.rb +64 -0
- data/lib/rmodbus/version.rb +17 -0
- data/lib/rmodbus.rb +20 -4
- data/spec/client_spec.rb +19 -45
- data/spec/exception_spec.rb +26 -27
- data/spec/ext_spec.rb +24 -1
- data/spec/logging_spec.rb +31 -37
- data/spec/proxy_spec.rb +73 -0
- data/spec/read_rtu_response_spec.rb +2 -4
- data/spec/rtu_client_spec.rb +17 -19
- data/spec/rtu_server_spec.rb +1 -3
- data/spec/rtu_via_tcp_client_spec.rb +69 -63
- data/spec/slave_spec.rb +55 -0
- data/spec/tcp_client_spec.rb +77 -69
- data/spec/tcp_server_spec.rb +34 -49
- metadata +123 -37
- data/AUTHORS +0 -3
- data/ChangeLog +0 -82
- data/LICENSE +0 -675
- data/README +0 -53
- data/examples/add_new_function.rb +0 -19
data/NEWS.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
Release 1.0.0
|
2
|
+
=====================================
|
3
|
+
New API for client part of library
|
4
|
+
---------------------------------------
|
5
|
+
|
6
|
+
Example:
|
7
|
+
|
8
|
+
require 'rmodbus'
|
9
|
+
|
10
|
+
ModBus::TCPClient.new('127.0.0.1', 8502) do |cl|
|
11
|
+
cl.with_slave(1) do |slave|
|
12
|
+
# Read a single holding register at address 16
|
13
|
+
slave.holding_registers[16]
|
14
|
+
|
15
|
+
# Write a single holding register at address 16
|
16
|
+
slave.holding_registers[16] = 123
|
17
|
+
|
18
|
+
# Read holding registers 16 through 20
|
19
|
+
slave.holding_registers[16..20]
|
20
|
+
|
21
|
+
# Write holding registers 16 through 20 with some values
|
22
|
+
slave.holding_registers[16..20] = [1, 2, 3, 4, 5]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
for more information [see](http://rdoc.info/gems/rmodbus/1.0.0/frames)
|
27
|
+
|
28
|
+
Conversion to/from 32bit registers
|
29
|
+
-----------------------------------
|
30
|
+
|
31
|
+
Some modbus devices use two registers to store 32bit values.
|
32
|
+
RModbus provides some helper functions to go back and forth between these two things when reading/writing.
|
33
|
+
The built-in examples assume registers in a particular order but it's trivial to change.
|
34
|
+
|
35
|
+
# Reading values in multiple registers (you can read more than 2 and convert them all so long as they are in multiples of 2)
|
36
|
+
res = slave.holding_registers[0..1]
|
37
|
+
res.inspect => [20342, 17344]
|
38
|
+
res.to_32i => [1136676726]
|
39
|
+
res.to_32f => [384.620788574219]
|
40
|
+
|
41
|
+
# Writing 32b values to multiple registers
|
42
|
+
cl.holding_registers[0..1] = [1136676726].from_32i
|
43
|
+
cl.holding_registers[0..1] => [20342, 17344]
|
44
|
+
cl.holding_registers[2..3] = [384.620788574219].from_32f
|
45
|
+
cl.holding_registers[2..3] => [20342, 17344]
|
46
|
+
|
47
|
+
Support JRuby
|
48
|
+
--------------------------------------
|
49
|
+
Now you could use RModBus on JRuby without RTU implementation.
|
50
|
+
|
51
|
+
RTU classes requires gem [serialport](https://github.com/hparra/ruby-serialport) which
|
52
|
+
currently not compatible with JRuby
|
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
RModBus
|
2
|
+
==========================
|
3
|
+
|
4
|
+
**RModBus** - free implementation of protocol ModBus.
|
5
|
+
|
6
|
+
Features
|
7
|
+
---------------------------
|
8
|
+
- Ruby 1.8, Ruby 1.9, JRuby (without serial ModBus RTU)
|
9
|
+
- TCP, RTU, RTU over TCP protocols
|
10
|
+
- Client(master) and server(slave)
|
11
|
+
- 16, 32 -bit and float registers
|
12
|
+
|
13
|
+
Support functions
|
14
|
+
---------------------------
|
15
|
+
* Read Coils (0x01)
|
16
|
+
* Read Discrete Inputs (0x02)
|
17
|
+
* Read Holding Registers (0x03)
|
18
|
+
* Read Input Registers (0x04)
|
19
|
+
* Write Single Coil (0x05)
|
20
|
+
* Write Single Register (0x06)
|
21
|
+
* Write Multiple Coils (0x0F)
|
22
|
+
* Write Multiple registers (0x10)
|
23
|
+
* Mask Write register (0x16)
|
24
|
+
|
25
|
+
Installation
|
26
|
+
------------------------------------
|
27
|
+
|
28
|
+
Download and install RModBus with the following
|
29
|
+
|
30
|
+
**$ gem install rmodbus**
|
31
|
+
|
32
|
+
Example
|
33
|
+
------------------------------------
|
34
|
+
|
35
|
+
require 'rmodbus'
|
36
|
+
|
37
|
+
ModBus::TCPClient.new('127.0.0.1', 8502) do |cl|
|
38
|
+
cl.with_slave(1) do |slave|
|
39
|
+
# Read a single holding register at address 16
|
40
|
+
slave.holding_registers[16]
|
41
|
+
|
42
|
+
# Write a single holding register at address 16
|
43
|
+
slave.holding_registers[16] = 123
|
44
|
+
|
45
|
+
# Read holding registers 16 through 20
|
46
|
+
slave.holding_registers[16..20]
|
47
|
+
|
48
|
+
# Write holding registers 16 through 20 with some values
|
49
|
+
slave.holding_registers[16..20] = [1, 2, 3, 4, 5]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
Conversion to/from 32bit registers
|
55
|
+
-----------------------------------
|
56
|
+
|
57
|
+
Some modbus devices use two registers to store 32bit values.
|
58
|
+
RModbus provides some helper functions to go back and forth between these two things when reading/writing.
|
59
|
+
The built-in examples assume registers in a particular order but it's trivial to change.
|
60
|
+
|
61
|
+
# Reading values in multiple registers (you can read more than 2 and convert them all so long as they are in multiples of 2)
|
62
|
+
res = slave.holding_registers[0..1]
|
63
|
+
res.inspect => [20342, 17344]
|
64
|
+
res.to_32i => [1136676726]
|
65
|
+
res.to_32f => [384.620788574219]
|
66
|
+
|
67
|
+
# Writing 32b values to multiple registers
|
68
|
+
cl.holding_registers[0..1] = [1136676726].from_32i
|
69
|
+
cl.holding_registers[0..1] => [20342, 17344]
|
70
|
+
cl.holding_registers[2..3] = [384.620788574219].from_32f
|
71
|
+
cl.holding_registers[2..3] => [20342, 17344]
|
72
|
+
|
73
|
+
GitHub
|
74
|
+
----------------------------------
|
75
|
+
|
76
|
+
You can checkout source code from GitHub repositry
|
77
|
+
|
78
|
+
**$ git clone git://github.com/flipback/RModBus.git**
|
79
|
+
|
80
|
+
Reference
|
81
|
+
----------------------------------
|
82
|
+
|
83
|
+
Home page: http://rmodbus.heroku.com
|
84
|
+
|
85
|
+
RModBud on GitHub: http://github.com/flipback/RModBus
|
86
|
+
|
87
|
+
ModBus community: http://www.modbus-ida.org
|
data/Rakefile
CHANGED
@@ -1,45 +1,31 @@
|
|
1
|
-
|
2
|
-
if RUBY_VERSION.to_f >= 1.9
|
3
|
-
require 'fileutils'
|
4
|
-
else
|
5
|
-
require 'ftools'
|
6
|
-
end
|
1
|
+
# encoding: utf-8
|
7
2
|
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
8
5
|
begin
|
9
|
-
|
10
|
-
rescue
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
t.rcov = false
|
13
|
+
require 'rake'
|
14
|
+
require 'rspec/core'
|
15
|
+
require 'rspec/core/rake_task'
|
16
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
17
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
18
|
+
if RUBY_PLATFORM == "java"
|
19
|
+
spec.pattern.exclude("spec/rtu_client_spec.rb", "spec/rtu_server_spec.rb")
|
21
20
|
end
|
22
|
-
rescue Exception
|
23
|
-
puts 'RSpec not available. Install it with: sudo gem install rspec'
|
24
21
|
end
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
sitedir = CONFIG['sitelibdir']
|
31
|
-
rmodbus_dest = File.join(sitedir, 'rmodbus')
|
32
|
-
|
33
|
-
File::makedirs(rmodbus_dest, true)
|
34
|
-
File::chmod(0755, rmodbus_dest)
|
23
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
24
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
25
|
+
spec.rcov = true
|
26
|
+
end
|
35
27
|
|
36
|
-
|
28
|
+
task :default => :spec
|
37
29
|
|
38
|
-
|
39
|
-
|
40
|
-
target_dir = File.join(sitedir, fn_dir)
|
41
|
-
File::makedirs(target_dir) unless File.exist?(target_dir)
|
42
|
-
File::install(File.join('lib', fn), File.join(sitedir, fn), 0644, true)
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
30
|
+
require 'yard'
|
31
|
+
YARD::Rake::YardocTask.new
|
data/examples/perfomance_rtu.rb
CHANGED
@@ -10,49 +10,47 @@ TIMES = 100
|
|
10
10
|
|
11
11
|
srv = RTUServer.new 'com3', BAUD
|
12
12
|
srv.coils = [0,1] * 50
|
13
|
-
srv.
|
13
|
+
srv.discrete_inputs = [1,0] * 50
|
14
14
|
srv.holding_registers = [0,1,2,3,4,5,6,7,8,9] * 10
|
15
15
|
srv.input_registers = [0,1,2,3,4,5,6,7,8,9] * 10
|
16
16
|
srv.start
|
17
17
|
|
18
18
|
|
19
|
-
cl = RTUClient.new
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
TIMES.times { cl.write_multiple_registers 0, [0,1,2,3,4,5,6,7,8,9] * 10 }
|
19
|
+
cl = RTUClient.new('com4', BAUD)
|
20
|
+
cl.with_slave(1) do |slave|
|
21
|
+
Benchmark.bmbm do |x|
|
22
|
+
x.report('Read coils') do
|
23
|
+
TIMES.times { slave.read_coils 0, 100 }
|
24
|
+
end
|
25
|
+
|
26
|
+
x.report('Read discrete inputs') do
|
27
|
+
TIMES.times { slave.read_discrete_inputs 0, 100 }
|
28
|
+
end
|
29
|
+
|
30
|
+
x.report('Read holding registers') do
|
31
|
+
TIMES.times { slave.read_holding_registers 0, 100 }
|
32
|
+
end
|
33
|
+
|
34
|
+
x.report('Read input registers') do
|
35
|
+
TIMES.times { slave.read_input_registers 0, 100 }
|
36
|
+
end
|
37
|
+
|
38
|
+
x.report('Write single coil') do
|
39
|
+
TIMES.times { slave.write_single_coil 0, 1 }
|
40
|
+
end
|
41
|
+
|
42
|
+
x.report('Write single register') do
|
43
|
+
TIMES.times { slave.write_single_register 100, 0xAAAA }
|
44
|
+
end
|
45
|
+
|
46
|
+
x.report('Write multiple coils') do
|
47
|
+
TIMES.times { slave.write_multiple_coils 0, [1,0] * 50 }
|
48
|
+
end
|
49
|
+
|
50
|
+
x.report('Write multiple registers') do
|
51
|
+
TIMES.times { slave.write_multiple_registers 0, [0,1,2,3,4,5,6,7,8,9] * 10 }
|
52
|
+
end
|
54
53
|
end
|
55
54
|
end
|
56
|
-
|
57
55
|
srv.stop
|
58
56
|
cl.close
|
data/examples/perfomance_tcp.rb
CHANGED
@@ -9,49 +9,47 @@ TIMES = 1000
|
|
9
9
|
|
10
10
|
srv = ModBus::TCPServer.new 1502
|
11
11
|
srv.coils = [0,1] * 50
|
12
|
-
srv.
|
12
|
+
srv.discrete_inputs = [1,0] * 50
|
13
13
|
srv.holding_registers = [0,1,2,3,4,5,6,7,8,9] * 10
|
14
14
|
srv.input_registers = [0,1,2,3,4,5,6,7,8,9] * 10
|
15
15
|
srv.start
|
16
16
|
|
17
17
|
|
18
|
-
cl = TCPClient.new
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
TIMES.times { cl.write_multiple_registers 0, [0,1,2,3,4,5,6,7,8,9] * 10 }
|
18
|
+
cl = TCPClient.new('127.0.0.1', 1502)
|
19
|
+
cl.with_slave(1) do |slave|
|
20
|
+
Benchmark.bmbm do |x|
|
21
|
+
x.report('Read coils') do
|
22
|
+
TIMES.times { slave.read_coils 0, 100 }
|
23
|
+
end
|
24
|
+
|
25
|
+
x.report('Read discrete inputs') do
|
26
|
+
TIMES.times { slave.read_discrete_inputs 0, 100 }
|
27
|
+
end
|
28
|
+
|
29
|
+
x.report('Read holding registers') do
|
30
|
+
TIMES.times { slave.read_holding_registers 0, 100 }
|
31
|
+
end
|
32
|
+
|
33
|
+
x.report('Read input registers') do
|
34
|
+
TIMES.times { slave.read_input_registers 0, 100 }
|
35
|
+
end
|
36
|
+
|
37
|
+
x.report('Write single coil') do
|
38
|
+
TIMES.times { slave.write_single_coil 0, 1 }
|
39
|
+
end
|
40
|
+
|
41
|
+
x.report('Write single register') do
|
42
|
+
TIMES.times { slave.write_single_register 100, 0xAAAA }
|
43
|
+
end
|
44
|
+
|
45
|
+
x.report('Write multiple coils') do
|
46
|
+
TIMES.times { slave.write_multiple_coils 0, [1,0] * 50 }
|
47
|
+
end
|
48
|
+
|
49
|
+
x.report('Write multiple registers') do
|
50
|
+
TIMES.times { slave.write_multiple_registers 0, [0,1,2,3,4,5,6,7,8,9] * 10 }
|
51
|
+
end
|
53
52
|
end
|
54
53
|
end
|
55
|
-
|
56
|
-
srv.stop
|
57
54
|
cl.close
|
55
|
+
srv.stop
|
@@ -9,11 +9,14 @@ srv.input_registers = [1,2,3,4]
|
|
9
9
|
srv.debug = true
|
10
10
|
srv.start
|
11
11
|
|
12
|
-
ModBus::RTUViaTCPClient.connect('127.0.0.1', 10002
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
ModBus::RTUViaTCPClient.connect('127.0.0.1', 10002) do |cl|
|
13
|
+
cl.with_slave(1) do |slave|
|
14
|
+
slave.debug = true
|
15
|
+
regs = slave.holding_registers
|
16
|
+
puts regs[0..3]
|
17
|
+
regs[0..3] = [2,0,1,1]
|
18
|
+
puts regs[0..3]
|
19
|
+
end
|
17
20
|
end
|
18
21
|
|
19
22
|
srv.shutdown
|
data/examples/use_tcp_modbus.rb
CHANGED
@@ -3,17 +3,21 @@ require 'rmodbus'
|
|
3
3
|
|
4
4
|
srv = ModBus::TCPServer.new(8502,1)
|
5
5
|
srv.coils = [1,0,1,1]
|
6
|
-
srv.
|
6
|
+
srv.discrete_inputs = [1,1,0,0]
|
7
7
|
srv.holding_registers = [1,2,3,4]
|
8
8
|
srv.input_registers = [1,2,3,4]
|
9
9
|
srv.debug = true
|
10
10
|
srv.audit = true
|
11
11
|
srv.start
|
12
12
|
|
13
|
-
ModBus::TCPClient.connect('127.0.0.1', 8502
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
ModBus::TCPClient.connect('127.0.0.1', 8502) do |cl|
|
14
|
+
cl.with_slave(1) do |slave|
|
15
|
+
slave.debug = true
|
16
|
+
regs = slave.holding_registers
|
17
|
+
puts regs[0..3]
|
18
|
+
regs[0..3] = [2,0,1,1]
|
19
|
+
puts regs[0..3]
|
20
|
+
end
|
18
21
|
end
|
22
|
+
|
19
23
|
srv.stop
|