rmodbus 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,140 @@
1
+ # RModBus - free implementation of ModBus protocol in Ruby.
2
+ #
3
+ # Copyright (C) 2010 - 2011 Timin Aleksey
4
+ # Copyright (C) 2010 Kelley Reynolds
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+
16
+ module ModBus
17
+ module RTU
18
+ private
19
+
20
+ # We have to read specific amounts of numbers of bytes from the network depending on the function code and content
21
+ def read_rtu_response(io)
22
+ # Read the slave_id and function code
23
+ msg = io.read(2)
24
+ function_code = msg.getbyte(1)
25
+ case function_code
26
+ when 1,2,3,4 then
27
+ # read the third byte to find out how much more
28
+ # we need to read + CRC
29
+ msg += io.read(1)
30
+ msg += io.read(msg.getbyte(2)+2)
31
+ when 5,6,15,16 then
32
+ # We just read in an additional 6 bytes
33
+ msg += io.read(6)
34
+ when 22 then
35
+ msg += io.read(8)
36
+ when 0x80..0xff then
37
+ msg += io.read(4)
38
+ else
39
+ raise ModBus::Errors::IllegalFunction, "Illegal function: #{function_code}"
40
+ end
41
+ end
42
+
43
+ def read_rtu_request(io)
44
+ # Read the slave_id and function code
45
+ msg = io.read(2)
46
+
47
+ # If msg is nil, then our client never sent us anything and it's time to disconnect
48
+ return if msg.nil?
49
+
50
+ function_code = msg.getbyte(1)
51
+ if [1, 2, 3, 4, 5, 6].include?(function_code)
52
+ # read 6 more bytes and return the message total message
53
+ msg += io.read(6)
54
+ elsif [15, 16].include?(function_code)
55
+ # Read in first register, register count, and data bytes
56
+ msg += io.read(5)
57
+ # Read in however much data we need to + 2 CRC bytes
58
+ msg += io.read(msg.getbyte(6) + 2)
59
+ else
60
+ raise ModBus::Errors::IllegalFunction, "Illegal function: #{function_code}"
61
+ end
62
+
63
+ log "Server RX (#{msg.size} bytes): #{logging_bytes(msg)}"
64
+
65
+ msg
66
+ end
67
+
68
+ def serv_rtu_requests(io, &blk)
69
+ loop do
70
+ # read the RTU message
71
+ msg = read_rtu_request(io)
72
+ # If there is no RTU message, we're done serving this client
73
+ break if msg.nil?
74
+
75
+ if msg.getbyte(0) == @uid and msg[-2,2].unpack('n')[0] == crc16(msg[0..-3])
76
+ pdu = yield msg
77
+ resp = @uid.chr + pdu
78
+ resp << crc16(resp).to_word
79
+ log "Server TX (#{resp.size} bytes): #{logging_bytes(resp)}"
80
+ io.write resp
81
+ end
82
+ end
83
+ end
84
+
85
+ # Calc CRC16 for massage
86
+ def crc16(msg)
87
+ crc_lo = 0xff
88
+ crc_hi = 0xff
89
+
90
+ msg.unpack('c*').each do |byte|
91
+ i = crc_hi ^ byte
92
+ crc_hi = crc_lo ^ CrcHiTable[i]
93
+ crc_lo = CrcLoTable[i]
94
+ end
95
+
96
+ return ((crc_hi << 8) + crc_lo)
97
+ end
98
+
99
+ CrcHiTable = [
100
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
101
+ 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
102
+ 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
103
+ 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
104
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
105
+ 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
106
+ 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
107
+ 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
108
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
109
+ 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
110
+ 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
111
+ 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
112
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
113
+ 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
114
+ 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
115
+ 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
116
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
117
+ 0x40]
118
+ CrcLoTable = [
119
+ 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
120
+ 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
121
+ 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
122
+ 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
123
+ 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
124
+ 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
125
+ 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
126
+ 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
127
+ 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
128
+ 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
129
+ 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
130
+ 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
131
+ 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
132
+ 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
133
+ 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
134
+ 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
135
+ 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
136
+ 0x40]
137
+
138
+ end
139
+ end
140
+
@@ -0,0 +1,41 @@
1
+ # RModBus - free implementation of ModBus protocol in Ruby.
2
+ #
3
+ # Copyright (C) 2009-2011 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ module ModBus
15
+ # RTU client implementation
16
+ # @example
17
+ # RTUClient.connect('/dev/ttyS1', 9600) do |cl|
18
+ # cl.with_slave(uid) do |slave|
19
+ # slave.holding_registers[0..100]
20
+ # end
21
+ # end
22
+ #
23
+ # @see RTUClient#open_connection
24
+ # @see Client#initialize
25
+ class RTUClient < Client
26
+ include RTU
27
+ include SP
28
+
29
+ protected
30
+ # Open serial port
31
+ # @see SP#open_serial_port
32
+ def open_connection(port, baud=9600, opts = {})
33
+ open_serial_port(port, baud, opts)
34
+ end
35
+
36
+ # @private
37
+ def get_slave(uid, io)
38
+ RTUSlave.new(uid, io)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,61 @@
1
+ # RModBus - free implementation of ModBus protocol in Ruby.
2
+ #
3
+ # Copyright (C) 2010-2011 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ require 'serialport'
15
+
16
+ module ModBus
17
+ # RTU server implementation
18
+ # @example
19
+ # srv = RTUServer.new('/dev/ttyS1', 9600, 1)
20
+ # srv.coils = [1,0,1,1]
21
+ # srv.discrete_inputs = [1,1,0,0]
22
+ # srv.holding_registers = [1,2,3,4]
23
+ # srv.input_registers = [1,2,3,4]
24
+ # srv.debug = true
25
+ # srv.start
26
+ class RTUServer
27
+ include Common
28
+ include Server
29
+ include RTU
30
+ include SP
31
+
32
+ # Init RTU server
33
+ # @param [Integer] uid slave device
34
+ # @see SP#open_serial_port
35
+ def initialize(port, baud=9600, uid=1, opts = {})
36
+ Thread.abort_on_exception = true
37
+ @sp = open_serial_port(port, baud, opts)
38
+ @uid = uid
39
+ end
40
+
41
+ # Start server
42
+ def start
43
+ @serv = Thread.new do
44
+ serv_rtu_requests(@sp) do |msg|
45
+ exec_req(msg[1..-3], @coils, @discrete_inputs, @holding_registers, @input_registers)
46
+ end
47
+ end
48
+ end
49
+
50
+ # Stop server
51
+ def stop
52
+ Thread.kill(@serv)
53
+ @sp.close
54
+ end
55
+
56
+ # Join server
57
+ def join
58
+ @serv.join
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,59 @@
1
+ # RModBus - free implementation of ModBus protocol in Ruby.
2
+ #
3
+ # Copyright (C) 2011 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ module ModBus
15
+ # RTU slave implementation
16
+ # @example
17
+ # RTUClient.connect(port, baud, opts) do |cl|
18
+ # cl.with_slave(uid) do |slave|
19
+ # slave.holding_registers[0..100]
20
+ # end
21
+ # end
22
+ #
23
+ # @see RTUClient#open_connection
24
+ # @see Client#with_slave
25
+ # @see Slave
26
+ class RTUSlave < Slave
27
+ include RTU
28
+
29
+ protected
30
+
31
+ # overide method for RTU implamentaion
32
+ # @see Slave#query
33
+ def send_pdu(pdu)
34
+ msg = @uid.chr + pdu
35
+ msg << crc16(msg).to_word
36
+ @io.write msg
37
+
38
+ log "Tx (#{msg.size} bytes): " + logging_bytes(msg)
39
+ end
40
+
41
+ # overide method for RTU implamentaion
42
+ # @see Slave#query
43
+ def read_pdu
44
+ msg = read_rtu_response(@io)
45
+
46
+ log "Rx (#{msg.size} bytes): " + logging_bytes(msg)
47
+
48
+ if msg.getbyte(0) == @uid
49
+ return msg[1..-3] if msg[-2,2].unpack('n')[0] == crc16(msg[0..-3])
50
+ log "Ignore package: don't match CRC"
51
+ else
52
+ log "Ignore package: don't match uid ID"
53
+ end
54
+ loop do
55
+ #waite timeout
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,41 @@
1
+ # RModBus - free implementation of ModBus protocol in Ruby.
2
+ #
3
+ # Copyright (C) 2009-2011 Timin Aleksey
4
+ # Copyright (C) 2010 Kelley Reynolds
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ module ModBus
16
+ # RTU over TCP client implementation
17
+ # @example
18
+ # RTUViaTCPClient.connect('127.0.0.1', 10002) do |cl|
19
+ # cl.with_slave(uid) do |slave|
20
+ # slave.holding_registers[0..100]
21
+ # end
22
+ # end
23
+ #
24
+ # @see RTUViaTCPClient#open_connection
25
+ # @see Client#initialize
26
+ class RTUViaTCPClient < Client
27
+ include RTU
28
+ include TCP
29
+
30
+ protected
31
+ # Open TCP\IP connection
32
+ # @see TCP#open_tcp_connection
33
+ def open_connection(ipaddr, port = 10002, opts = {})
34
+ io = open_tcp_connection(ipaddr, port, opts)
35
+ end
36
+
37
+ def get_slave(uid, io)
38
+ RTUViaTCPSlave.new(uid, io)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,50 @@
1
+ # RModBus - free implementation of ModBus protocol in Ruby.
2
+ #
3
+ # Copyright (C) 2010 Timin Aleksey
4
+ # Copyright (C) 2010 Kelley Reynolds
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+
16
+ require 'gserver'
17
+
18
+ module ModBus
19
+ # RTU over TCP server implementation
20
+ # @example
21
+ # srv = RTUViaTCPServer.new(10002, 1)
22
+ # srv.coils = [1,0,1,1]
23
+ # srv.discrete_inputs = [1,1,0,0]
24
+ # srv.holding_registers = [1,2,3,4]
25
+ # srv.input_registers = [1,2,3,4]
26
+ # srv.debug = true
27
+ # srv.start
28
+ class RTUViaTCPServer < GServer
29
+ include Common
30
+ include RTU
31
+ include Server
32
+
33
+ # Init server
34
+ # @param [Integer] port listen port
35
+ # @param [Integer] uid slave device
36
+ def initialize(port = 10002, uid = 1)
37
+ @uid = uid
38
+ super(port)
39
+ end
40
+
41
+ protected
42
+ # Serve requests
43
+ # @param [TCPSocket] io socket
44
+ def serve(io)
45
+ serv_rtu_requests(io) do |msg|
46
+ exec_req(msg[1..-3], @coils, @discrete_inputs, @holding_registers, @input_registers)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,58 @@
1
+ # RModBus - free implementation of ModBus protocol in Ruby.
2
+ #
3
+ # Copyright (C) 2011 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ module ModBus
15
+ # RTU over TCP slave implementation
16
+ # @example
17
+ # RTUViaTCP.connect('127.0.0.1', 10002) do |cl|
18
+ # cl.with_slave(uid) do |slave|
19
+ # slave.holding_registers[0..100]
20
+ # end
21
+ # end
22
+ #
23
+ # @see RTUViaTCPClient#open_connection
24
+ # @see Client#with_slave
25
+ # @see Slave
26
+ class RTUViaTCPSlave < Slave
27
+ include RTU
28
+
29
+ protected
30
+ # overide method for RTU over TCP implamentaion
31
+ # @see Slave#query
32
+ def send_pdu(pdu)
33
+ msg = @uid.chr + pdu
34
+ msg << crc16(msg).to_word
35
+ @io.write msg
36
+
37
+ log "Tx (#{msg.size} bytes): " + logging_bytes(msg)
38
+ end
39
+
40
+ # overide method for RTU over TCP implamentaion
41
+ # @see Slave#query
42
+ def read_pdu
43
+ # Read the response appropriately
44
+ msg = read_rtu_response(@io)
45
+
46
+ log "Rx (#{msg.size} bytes): " + logging_bytes(msg)
47
+ if msg.getbyte(0) == @uid
48
+ return msg[1..-3] if msg[-2,2].unpack('n')[0] == crc16(msg[0..-3])
49
+ log "Ignore package: don't match CRC"
50
+ else
51
+ log "Ignore package: don't match uid ID"
52
+ end
53
+ loop do
54
+ #waite timeout
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,142 @@
1
+ # RModBus - free implementation of ModBus protocol in Ruby.
2
+ #
3
+ # Copyright (C) 2010 Timin Aleksey
4
+ # Copyright (C) 2010 Kelley Reynolds
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+
16
+ module ModBus
17
+ # Module for implementation ModBus server
18
+ module Server
19
+ Funcs = [1,2,3,4,5,6,15,16]
20
+
21
+ attr_accessor :coils, :discrete_inputs, :holding_registers, :input_registers, :uid
22
+ @coils = []
23
+ @discrete_inputs = []
24
+ @holding_registers =[]
25
+ @input_registers = []
26
+
27
+ private
28
+
29
+ def exec_req(req, coils, discrete_inputs, holding_registers, input_registers)
30
+ func = req.getbyte(0)
31
+
32
+ unless Funcs.include?(func)
33
+ params = { :err => 1 }
34
+ end
35
+
36
+ case func
37
+ when 1
38
+ params = parse_read_func(req, coils)
39
+ if params[:err] == 0
40
+ val = coils[params[:addr],params[:quant]].pack_to_word
41
+ pdu = func.chr + val.size.chr + val
42
+ end
43
+ when 2
44
+ params = parse_read_func(req, discrete_inputs)
45
+ if params[:err] == 0
46
+ val = discrete_inputs[params[:addr],params[:quant]].pack_to_word
47
+ pdu = func.chr + val.size.chr + val
48
+ end
49
+ when 3
50
+ params = parse_read_func(req, holding_registers)
51
+ if params[:err] == 0
52
+ pdu = func.chr + (params[:quant] * 2).chr + holding_registers[params[:addr],params[:quant]].pack('n*')
53
+ end
54
+ when 4
55
+ params = parse_read_func(req, input_registers)
56
+ if params[:err] == 0
57
+ pdu = func.chr + (params[:quant] * 2).chr + input_registers[params[:addr],params[:quant]].pack('n*')
58
+ end
59
+ when 5
60
+ params = parse_write_coil_func(req)
61
+ if params[:err] == 0
62
+ coils[params[:addr]] = params[:val]
63
+ pdu = req
64
+ end
65
+ when 6
66
+ params = parse_write_register_func(req)
67
+ if params[:err] == 0
68
+ holding_registers[params[:addr]] = params[:val]
69
+ pdu = req
70
+ end
71
+ when 15
72
+ params = parse_write_multiple_coils_func(req)
73
+ if params[:err] == 0
74
+ coils[params[:addr],params[:quant]] = params[:val][0,params[:quant]]
75
+ pdu = req[0,5]
76
+ end
77
+ when 16
78
+ params = parse_write_multiple_registers_func(req)
79
+ if params[:err] == 0
80
+ holding_registers[params[:addr],params[:quant]] = params[:val][0,params[:quant]]
81
+ pdu = req[0,5]
82
+ end
83
+ end
84
+
85
+ if params[:err] == 0
86
+ pdu
87
+ else
88
+ pdu = (func | 0x80).chr + params[:err].chr
89
+ end
90
+ end
91
+
92
+ def parse_read_func(req, field)
93
+ quant = req[3,2].unpack('n')[0]
94
+
95
+ return { :err => 3} unless quant <= 0x7d
96
+
97
+ addr = req[1,2].unpack('n')[0]
98
+ return { :err => 2 } unless addr + quant <= field.size
99
+
100
+ return { :err => 0, :quant => quant, :addr => addr }
101
+ end
102
+
103
+ def parse_write_coil_func(req)
104
+ addr = req[1,2].unpack('n')[0]
105
+ return { :err => 2 } unless addr <= @coils.size
106
+
107
+ val = req[3,2].unpack('n')[0]
108
+ return { :err => 3 } unless val == 0 or val == 0xff00
109
+
110
+ val = 1 if val == 0xff00
111
+ return { :err => 0, :addr => addr, :val => val }
112
+ end
113
+
114
+ def parse_write_register_func(req)
115
+ addr = req[1,2].unpack('n')[0]
116
+ return { :err => 2 } unless addr <= @coils.size
117
+
118
+ val = req[3,2].unpack('n')[0]
119
+
120
+ return { :err => 0, :addr => addr, :val => val }
121
+ end
122
+
123
+ def parse_write_multiple_coils_func(req)
124
+ params = parse_read_func(req, @coils)
125
+
126
+ if params[:err] == 0
127
+ params = {:err => 0, :addr => params[:addr], :quant => params[:quant], :val => req[6,params[:quant]].unpack_bits }
128
+ end
129
+ params
130
+ end
131
+
132
+ def parse_write_multiple_registers_func(req)
133
+ params = parse_read_func(req, @holding_registers)
134
+
135
+ if params[:err] == 0
136
+ params = {:err => 0, :addr => params[:addr], :quant => params[:quant], :val => req[6,params[:quant] * 2].unpack('n*')}
137
+ end
138
+ params
139
+ end
140
+
141
+ end
142
+ end