Skip to content

Commit

Permalink
#4 Implement WriteMultipleRegisters.
Browse files Browse the repository at this point in the history
  • Loading branch information
OrangeTux committed Nov 7, 2015
1 parent 385668a commit 290aead
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 6 deletions.
80 changes: 78 additions & 2 deletions modbus/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
WRITE_SINGLE_COIL = 5
WRITE_SINGLE_REGISTER = 6
WRITE_MULTIPLE_COILS = 15
WRITE_SINGLE_REGISTERS = 16
WRITE_MULTIPLE_REGISTERS = 16

READ_FILE_RECORD = 20
WRITE_FILE_RECORD = 21
Expand Down Expand Up @@ -649,7 +649,7 @@ def __init__(self, starting_address, quantity, byte_count, values):

if not(expected_byte_count == byte_count):
raise IllegalDataValueError('Byte count is not correct. It is {0},'
'but is {1}.'
'but should be {1}.'
.format(byte_count,
expected_byte_count))

Expand All @@ -673,6 +673,81 @@ def create_from_request_pdu(cls, pdu):

return cls(starting_address, quantity, byte_count, values)


class WriteMultipleRegisters(WriteMultipleValueFunction):
""" Implement Modbus function 16 (0x10) Write Multiple Registers.
"This function code is used to write a block of contiguous registers (1 to
123 registers) in a remote device.
The requested written values are specified in the request data field. Data
is packed as two bytes per register.
The normal response returns the function code, starting address, and
quantity of registers written."
- MODBUS Application Protocol Specification V1.1b3, chapter 6.12
The request PDU with function code 16 must be at least 8 bytes:
+------------------+----------------+
| Field | Length (bytes) |
+------------------+----------------+
| Function code | 1 |
| Starting Address | 2 |
| Quantity | 2 |
| Byte count | 1 |
| Value | Quantity * 2 |
+------------------+----------------+
The PDU can unpacked to this::
>>> struct.unpack('>BHHBB', b'\x0f\x00d\x00\x01\x02\x00\x05')
(16, 100, 1, 2, 5)
The reponse PDU is 5 bytes and contains following structure:
+------------------+----------------+
| Field | Length (bytes) |
+------------------+----------------+
| Function code | 1 |
| Starting address | 2 |
| Quantity | 2 |
+------------------+----------------+
"""
function_code = WRITE_MULTIPLE_REGISTERS

def __init__(self, starting_address, quantity, byte_count, values):
if not(1 <= quantity <= 0x7B):
raise IllegalDataValueError('Quantify field of request must be a '
'value between 0 and '
'{0}.'.format(0x7B0))

# Values are 16 bit, so each value takes up 2 bytes.
if byte_count != (len(values) * 2):
raise IllegalDataValueError('Byte count is not correct. It is {0},'
'but should be {1}.'
.format(byte_count, len(values)))

WriteMultipleValueFunction.__init__(self, starting_address, values)

@classmethod
def create_from_request_pdu(cls, pdu):
""" Create instance from request PDU.
:param pdu: A request PDU.
:return: Instance of this class.
"""
_, starting_address, quantity, byte_count = \
struct.unpack('>BHHB', pdu[:6])

# Values are 16 bit, so each value takes up 2 bytes.
fmt = '>' + ('H' * int((byte_count / 2)))

values = list(struct.unpack(fmt, pdu[6:]))
return cls(starting_address, quantity, byte_count, values)

function_code_to_function_map = {
READ_COILS: ReadCoils,
READ_DISCRETE_INPUTS: ReadDiscreteInputs,
Expand All @@ -681,4 +756,5 @@ def create_from_request_pdu(cls, pdu):
WRITE_SINGLE_COIL: WriteSingleCoil,
WRITE_SINGLE_REGISTER: WriteSingleRegister,
WRITE_MULTIPLE_COILS: WriteMultipleCoils,
WRITE_MULTIPLE_REGISTERS: WriteMultipleRegisters,
}
4 changes: 4 additions & 0 deletions scripts/data_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ def single_coil(slave_id, address, value):
print(value)


@server.route(slave_ids=[1], function_codes=[15, 16], addresses=set(range(100, 200)))
def multiple_coils(slave_id, address, value):
print(value)

if __name__ == '__main__':
try:
server.serve_forever()
Expand Down
10 changes: 6 additions & 4 deletions scripts/log_server.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
#!/usr/bin/env python
from logging import info
from SocketServer import BaseRequestHandler, TCPServer
try:
from socketserver import BaseRequestHandler, TCPServer
except ImportError:
from socketserver import BaseRequestHandler, TCPServer


class LogHandler(BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
info('{0} wrote: {1}'.format(self.client_address[0], self.data))
print('{0} wrote: {1}'.format(self.client_address[0], self.data))
self.request.sendall(self.data)


if __name__ == '__main__':
HOST, PORT = 'localhost', 1337
HOST, PORT = 'localhost', 1338
server = TCPServer((HOST, PORT), LogHandler)

try:
Expand Down

0 comments on commit 290aead

Please sign in to comment.