em-modbus 0.1.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/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +373 -0
- data/README.md +30 -0
- data/Rakefile +15 -0
- data/em-modbus.gemspec +26 -0
- data/examples/client.rb +33 -0
- data/examples/client_batch.rb +47 -0
- data/examples/server.rb +43 -0
- data/lib/modbus/adu/adu.rb +5 -0
- data/lib/modbus/adu/rtu_adu.rb +18 -0
- data/lib/modbus/adu/tcp_adu.rb +82 -0
- data/lib/modbus/client.rb +64 -0
- data/lib/modbus/connection/base.rb +41 -0
- data/lib/modbus/connection/connection.rb +7 -0
- data/lib/modbus/connection/protocol_data.rb +78 -0
- data/lib/modbus/connection/tcp_client.rb +82 -0
- data/lib/modbus/connection/tcp_server.rb +36 -0
- data/lib/modbus/exceptions.rb +106 -0
- data/lib/modbus/modbus.rb +12 -0
- data/lib/modbus/pdu/exception.rb +56 -0
- data/lib/modbus/pdu/pdu.rb +87 -0
- data/lib/modbus/pdu/read_holding_registers.rb +26 -0
- data/lib/modbus/pdu/read_input_registers.rb +26 -0
- data/lib/modbus/pdu/read_input_status.rb +147 -0
- data/lib/modbus/pdu/read_registers.rb +135 -0
- data/lib/modbus/pdu/write_multiple_registers.rb +158 -0
- data/lib/modbus/register/base.rb +19 -0
- data/lib/modbus/register/bit_register.rb +49 -0
- data/lib/modbus/register/register.rb +7 -0
- data/lib/modbus/register/word_register.rb +30 -0
- data/lib/modbus/server.rb +120 -0
- data/lib/modbus/transaction/base.rb +25 -0
- data/lib/modbus/transaction/client.rb +162 -0
- data/lib/modbus/transaction/server.rb +95 -0
- data/lib/modbus/transaction/transaction.rb +39 -0
- data/lib/modbus/version.rb +7 -0
- data/lib/modbus.rb +2 -0
- data/spec/adi_spec.rb +16 -0
- data/spec/spec_helper.rb +1 -0
- metadata +162 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
# Copyright © 2016 Andy Rohr <andy.rohr@mindclue.ch>
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
|
5
|
+
module Modbus
|
6
|
+
|
7
|
+
class PDU
|
8
|
+
|
9
|
+
# PDU for modbus function "read input status" (request message)
|
10
|
+
#
|
11
|
+
class ReadInputStatusRequest < PDU
|
12
|
+
FUNC_CODE = 0x02
|
13
|
+
|
14
|
+
attr_accessor :start_addr, :bit_count
|
15
|
+
|
16
|
+
|
17
|
+
# Initializes a new PDU instance. Decodes from protocol data if given.
|
18
|
+
#
|
19
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
20
|
+
#
|
21
|
+
def initialize(data = nil, func_code = nil)
|
22
|
+
@start_addr = 0
|
23
|
+
@bit_count = 0
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Decodes a PDU from protocol data.
|
29
|
+
#
|
30
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
31
|
+
#
|
32
|
+
def decode(data)
|
33
|
+
@start_addr = data.shift_word
|
34
|
+
@bit_count = data.shift_word
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# Encodes a PDU into protocol data.
|
39
|
+
#
|
40
|
+
# @return [Modbus::ProtocolData] The protocol data representation of this object.
|
41
|
+
#
|
42
|
+
def encode
|
43
|
+
data = super
|
44
|
+
data.push_word @start_addr
|
45
|
+
data.push_word @bit_count
|
46
|
+
data
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Returns the length of the PDU in bytes.
|
51
|
+
#
|
52
|
+
# @return [Integer] The length.
|
53
|
+
#
|
54
|
+
def length
|
55
|
+
5
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# Validates the PDU. Raises exceptions if validation fails.
|
60
|
+
#
|
61
|
+
def validate
|
62
|
+
fail ClientError, "Register count must be in (1..127), got '#{@bit_count.inspect}'" unless (1..127).include?(@bit_count)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# PDU for modbus function "read input status" (response message)
|
69
|
+
#
|
70
|
+
class ReadInputStatusResponse < PDU
|
71
|
+
FUNC_CODE = 0x02
|
72
|
+
|
73
|
+
attr_accessor :bit_values
|
74
|
+
|
75
|
+
|
76
|
+
# Initializes a new PDU instance. Decodes from protocol data if given.
|
77
|
+
#
|
78
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
79
|
+
#
|
80
|
+
def initialize(data = nil, func_code = nil)
|
81
|
+
@bit_values = []
|
82
|
+
super
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# Decodes a PDU from protocol data.
|
87
|
+
#
|
88
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
89
|
+
#
|
90
|
+
def decode(data)
|
91
|
+
byte_count = data.shift_byte
|
92
|
+
byte_count.times do
|
93
|
+
byte = data.shift_byte
|
94
|
+
|
95
|
+
8.times do |bit|
|
96
|
+
@bit_values.push byte[bit] == 1
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
# Encodes a PDU into protocol data.
|
103
|
+
#
|
104
|
+
# @return [Modbus::ProtocolData] The protocol data representation of this object.
|
105
|
+
#
|
106
|
+
def encode
|
107
|
+
data = super
|
108
|
+
data.push_byte byte_count
|
109
|
+
@bit_values.each do |value|
|
110
|
+
data.push_byte value
|
111
|
+
end
|
112
|
+
data
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
# Returns the length of the register values in bytes.
|
117
|
+
#
|
118
|
+
# @return [Integer] The length.
|
119
|
+
#
|
120
|
+
def byte_count
|
121
|
+
@bit_values.size
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
# Returns the length of the PDU in bytes.
|
126
|
+
#
|
127
|
+
# @return [Integer] The length.
|
128
|
+
#
|
129
|
+
def length
|
130
|
+
# +1 for func_code, +1 for byte_count
|
131
|
+
byte_count + 2
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# Validates the PDU. Raises exceptions if validation fails.
|
136
|
+
#
|
137
|
+
def validate
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end # Modbus
|
146
|
+
|
147
|
+
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# Copyright © 2016 Andy Rohr <andy.rohr@mindclue.ch>
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
|
5
|
+
module Modbus
|
6
|
+
|
7
|
+
class PDU
|
8
|
+
|
9
|
+
# Base class PDU for modbus function "read holding register" (request message)
|
10
|
+
#
|
11
|
+
class ReadRegistersRequest < PDU
|
12
|
+
attr_accessor :start_addr, :reg_count
|
13
|
+
|
14
|
+
|
15
|
+
# Initializes a new PDU instance. Decodes from protocol data if given.
|
16
|
+
#
|
17
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
18
|
+
#
|
19
|
+
def initialize(data = nil, func_code = nil)
|
20
|
+
@start_addr = 0
|
21
|
+
@reg_count = 0
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Decodes a PDU from protocol data.
|
27
|
+
#
|
28
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
29
|
+
#
|
30
|
+
def decode(data)
|
31
|
+
@start_addr = data.shift_word
|
32
|
+
@reg_count = data.shift_word
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# Encodes a PDU into protocol data.
|
37
|
+
#
|
38
|
+
# @return [Modbus::ProtocolData] The protocol data representation of this object.
|
39
|
+
#
|
40
|
+
def encode
|
41
|
+
data = super
|
42
|
+
data.push_word @start_addr
|
43
|
+
data.push_word @reg_count
|
44
|
+
data
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
# Returns the length of the PDU in bytes.
|
49
|
+
#
|
50
|
+
# @return [Integer] The length.
|
51
|
+
#
|
52
|
+
def length
|
53
|
+
5
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# Validates the PDU. Raises exceptions if validation fails.
|
58
|
+
#
|
59
|
+
def validate
|
60
|
+
fail ClientError, "Register count must be in (1..127), got '#{@reg_count.inspect}'" unless (1..127).include?(@reg_count)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# PDU for modbus function "read holding register" (response message)
|
67
|
+
#
|
68
|
+
class ReadRegistersResponse < PDU
|
69
|
+
attr_accessor :reg_values
|
70
|
+
|
71
|
+
|
72
|
+
# Initializes a new PDU instance. Decodes from protocol data if given.
|
73
|
+
#
|
74
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
75
|
+
#
|
76
|
+
def initialize(data = nil, func_code = nil)
|
77
|
+
@reg_values = []
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Decodes a PDU from protocol data.
|
83
|
+
#
|
84
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
85
|
+
#
|
86
|
+
def decode(data)
|
87
|
+
byte_count = data.shift_byte
|
88
|
+
byte_count.div(2).times { @reg_values.push data.shift_word }
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Encodes a PDU into protocol data.
|
93
|
+
#
|
94
|
+
# @return [Modbus::ProtocolData] The protocol data representation of this object.
|
95
|
+
#
|
96
|
+
def encode
|
97
|
+
data = super
|
98
|
+
data.push_byte byte_count
|
99
|
+
@reg_values.each { |value| data.push_word value }
|
100
|
+
data
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# Returns the length of the register values in bytes.
|
105
|
+
#
|
106
|
+
# @return [Integer] The length.
|
107
|
+
#
|
108
|
+
def byte_count
|
109
|
+
@reg_values.size * 2
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# Returns the length of the PDU in bytes.
|
114
|
+
#
|
115
|
+
# @return [Integer] The length.
|
116
|
+
#
|
117
|
+
def length
|
118
|
+
# +1 for func_code, +1 for byte_count
|
119
|
+
byte_count + 2
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
# Validates the PDU. Raises exceptions if validation fails.
|
124
|
+
#
|
125
|
+
def validate
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end # Modbus
|
134
|
+
|
135
|
+
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# Copyright © 2016 Andy Rohr <andy.rohr@mindclue.ch>
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
|
5
|
+
module Modbus
|
6
|
+
|
7
|
+
class PDU
|
8
|
+
|
9
|
+
# PDU for modbus function "read holding register" (request message)
|
10
|
+
#
|
11
|
+
class WriteMultipleRegistersRequest < PDU
|
12
|
+
FUNC_CODE = 0x10
|
13
|
+
|
14
|
+
attr_accessor :start_addr, :reg_values
|
15
|
+
|
16
|
+
|
17
|
+
# Initializes a new PDU instance. Decodes from protocol data if given.
|
18
|
+
#
|
19
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
20
|
+
#
|
21
|
+
def initialize(data = nil, func_code = nil)
|
22
|
+
@start_addr = 0
|
23
|
+
@reg_values = []
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Decodes a PDU from protocol data.
|
29
|
+
#
|
30
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
31
|
+
#
|
32
|
+
def decode(data)
|
33
|
+
@start_addr = data.shift_word
|
34
|
+
|
35
|
+
reg_count = data.shift_word
|
36
|
+
fail ClientError, "Register count must be in (1..127), got #{reg_count}" unless (1..127).include?(reg_count)
|
37
|
+
|
38
|
+
byte_count = data.shift_byte
|
39
|
+
fail ClientError, "Byte count does not match available data, expected #{byte_count} bytes, got #{data.size} bytes." unless byte_count == data.size
|
40
|
+
|
41
|
+
reg_count.times { @reg_values.push data.shift_word }
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# Encodes a PDU into protocol data.
|
46
|
+
#
|
47
|
+
# @return [Modbus::ProtocolData] The protocol data representation of this object.
|
48
|
+
#
|
49
|
+
def encode
|
50
|
+
data = super
|
51
|
+
data.push_word @start_addr
|
52
|
+
data.push_word reg_count
|
53
|
+
data.push_byte byte_count
|
54
|
+
@reg_values.each { |value| data.push_word value }
|
55
|
+
data
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# Returns the length of the register values in bytes.
|
60
|
+
#
|
61
|
+
# @return [Integer] The length.
|
62
|
+
#
|
63
|
+
def byte_count
|
64
|
+
reg_count * 2
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# Returns the number of registers to write.
|
69
|
+
#
|
70
|
+
# @return [Integer] The number of registers.
|
71
|
+
#
|
72
|
+
def reg_count
|
73
|
+
@reg_values.size
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# Returns the length of the PDU in bytes.
|
78
|
+
#
|
79
|
+
# @return [Integer] The length.
|
80
|
+
#
|
81
|
+
def length
|
82
|
+
# +1 for func_code, +2 for starting address, +2 for reg_count, +1 for byte_count
|
83
|
+
byte_count + 6
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# Validates the PDU. Raises exceptions if validation fails.
|
88
|
+
#
|
89
|
+
def validate
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
# PDU for modbus function "read holding register" (response message)
|
97
|
+
#
|
98
|
+
class WriteMultipleRegistersResponse < PDU
|
99
|
+
FUNC_CODE = 0x10
|
100
|
+
|
101
|
+
attr_accessor :start_addr, :reg_count
|
102
|
+
|
103
|
+
|
104
|
+
# Initializes a new PDU instance. Decodes from protocol data if given.
|
105
|
+
#
|
106
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
107
|
+
#
|
108
|
+
def initialize(data = nil, func_code = nil)
|
109
|
+
@start_addr = 0
|
110
|
+
@reg_count = 0
|
111
|
+
super
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# Decodes a PDU from protocol data.
|
116
|
+
#
|
117
|
+
# @param data [Modbus::ProtocolData] The protocol data to decode.
|
118
|
+
#
|
119
|
+
def decode(data)
|
120
|
+
@start_addr = data.shift_word
|
121
|
+
@reg_count = data.shift_word
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
# Encodes a PDU into protocol data.
|
126
|
+
#
|
127
|
+
# @return [Modbus::ProtocolData] The protocol data representation of this object.
|
128
|
+
#
|
129
|
+
def encode
|
130
|
+
data = super
|
131
|
+
data.push_word @start_addr
|
132
|
+
data.push_word @reg_count
|
133
|
+
data
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
# Returns the length of the PDU in bytes.
|
138
|
+
#
|
139
|
+
# @return [Integer] The length.
|
140
|
+
#
|
141
|
+
def length
|
142
|
+
5
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
# Validates the PDU. Raises exceptions if validation fails.
|
147
|
+
#
|
148
|
+
def validate
|
149
|
+
fail ClientError, "Register count must be in (1..127), got '#{@reg_count.inspect}'" unless (1..127).include?(@reg_count)
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
end # Modbus
|
157
|
+
|
158
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# Copyright © 2016 Andy Rohr <andy.rohr@mindclue.ch>
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module Modbus
|
7
|
+
|
8
|
+
class BitRegister < Register
|
9
|
+
|
10
|
+
def initialize(addr)
|
11
|
+
super
|
12
|
+
@bits = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def update(bit, value)
|
17
|
+
fail ArgumentError unless (0..15).include? bit
|
18
|
+
fail ArgumentError unless [true, false].include? value
|
19
|
+
@bits[bit] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def value
|
24
|
+
result = 0
|
25
|
+
|
26
|
+
@bits.each do |bit, bit_value|
|
27
|
+
value = bit_value ? 1 : 0
|
28
|
+
result |= (value << bit)
|
29
|
+
end
|
30
|
+
|
31
|
+
result
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def write(value)
|
36
|
+
return unless @handler
|
37
|
+
|
38
|
+
values = @bits.keys.map do |bit|
|
39
|
+
bit_value = value[bit] == 1
|
40
|
+
{:addr => [@addr, bit].join('.'), :value => bit_value}
|
41
|
+
end
|
42
|
+
|
43
|
+
@handler.write_values values
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright © 2016 Andy Rohr <andy.rohr@mindclue.ch>
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module Modbus
|
7
|
+
|
8
|
+
class WordRegister < Register
|
9
|
+
attr_reader :value
|
10
|
+
|
11
|
+
|
12
|
+
def initialize(addr)
|
13
|
+
super
|
14
|
+
@value = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def update(value)
|
19
|
+
fail ArgumentError unless (0..65535).include? value
|
20
|
+
@value = value
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def write(value)
|
25
|
+
@handler.write_values [{:addr => @addr.to_s, :value => value}] if @handler
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# Copyright © 2016 Andy Rohr <andy.rohr@mindclue.ch>
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Modbus
|
7
|
+
|
8
|
+
class Server
|
9
|
+
attr_reader :registers
|
10
|
+
|
11
|
+
|
12
|
+
def initialize(uri, handler)
|
13
|
+
@uri = URI uri
|
14
|
+
@handler = handler
|
15
|
+
@registers = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def add_register(addr, handler = nil)
|
20
|
+
log.info "Adding register @ #{addr}"
|
21
|
+
|
22
|
+
reg_addr, bit = addr.split('.')
|
23
|
+
reg_addr = reg_addr.to_i
|
24
|
+
|
25
|
+
register_class = bit ? BitRegister : WordRegister
|
26
|
+
reg = get_register reg_addr, register_class
|
27
|
+
reg.handler = handler
|
28
|
+
|
29
|
+
value = bit ? false : 0
|
30
|
+
update_register addr, value
|
31
|
+
|
32
|
+
reg
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def update_register(addr, value)
|
37
|
+
reg_addr, bit = addr.split('.')
|
38
|
+
reg = @registers.fetch reg_addr.to_i
|
39
|
+
|
40
|
+
case reg
|
41
|
+
when WordRegister
|
42
|
+
reg.update value
|
43
|
+
when BitRegister
|
44
|
+
reg.update bit.to_i, value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def start
|
50
|
+
EM.start_server @uri.host, @uri.port, Modbus::Connection::TCPServer, self
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def client_connected(signature)
|
55
|
+
log.info "client connected (signature #{signature})"
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def client_disconnected(signature)
|
60
|
+
log.info "client disconnected (signature #{signature})"
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def read_registers(start_addr, reg_count)
|
65
|
+
(0..reg_count-1).map do |idx|
|
66
|
+
addr = start_addr + idx
|
67
|
+
read_register addr
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def write_registers(start_addr, reg_values)
|
73
|
+
reg_values.each_with_index do |value, idx|
|
74
|
+
addr = start_addr + idx
|
75
|
+
write_register addr, value
|
76
|
+
end
|
77
|
+
|
78
|
+
reg_values.size
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
|
85
|
+
def log
|
86
|
+
@handler.log
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def get_register(addr, klass)
|
91
|
+
@registers[addr] ||= klass.new(addr)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def read_register(addr)
|
96
|
+
reg = @registers.fetch addr
|
97
|
+
reg.value
|
98
|
+
|
99
|
+
rescue IndexError
|
100
|
+
log.warn "read_register @ #{addr} failed (IllegalDataAddress)"
|
101
|
+
fail IllegalDataAddress
|
102
|
+
rescue => e
|
103
|
+
log.warn "read_register @ #{addr} failed. Error: #{e.message} (#{e.class}), Line: #{e.backtrace.first}"
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def write_register(addr, value)
|
108
|
+
reg = @registers.fetch addr
|
109
|
+
reg.write value
|
110
|
+
|
111
|
+
rescue IndexError
|
112
|
+
log.warn "write_register @ #{addr} failed (IllegalDataAddress)"
|
113
|
+
fail IllegalDataAddress
|
114
|
+
rescue => e
|
115
|
+
log.warn "write_register @ #{addr} failed. Error: #{e.message}, Line: #{e.backtrace.first}"
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Copyright © 2016 Andy Rohr <andy.rohr@mindclue.ch>
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
|
5
|
+
module Modbus
|
6
|
+
module Transaction
|
7
|
+
|
8
|
+
class Base
|
9
|
+
|
10
|
+
|
11
|
+
# Initializes a new Transaction instance.
|
12
|
+
#
|
13
|
+
# @param conn [Modbus::Connection::TCPServer] An EM connection object to work on.
|
14
|
+
#
|
15
|
+
def initialize(conn)
|
16
|
+
@conn = conn
|
17
|
+
end
|
18
|
+
|
19
|
+
end # Base
|
20
|
+
|
21
|
+
end # Transaction
|
22
|
+
|
23
|
+
end # Modbus
|
24
|
+
|
25
|
+
|