2
Bit Reading Request/Response messages
3
--------------------------------------
7
from pymodbus.pdu import ModbusRequest
8
from pymodbus.pdu import ModbusResponse
9
from pymodbus.pdu import ModbusExceptions as merror
10
from pymodbus.utilities import pack_bitstring, unpack_bitstring
12
class ReadBitsRequestBase(ModbusRequest):
13
''' Base class for Messages Requesting bit values '''
17
def __init__(self, address, count, **kwargs):
18
''' Initializes the read request data
20
:param address: The start address to read from
21
:param count: The number of bits after 'address' to read
23
ModbusRequest.__init__(self, **kwargs)
24
self.address = address
28
''' Encodes a request pdu
30
:returns: The encoded pdu
32
return struct.pack('>HH', self.address, self.count)
34
def decode(self, data):
35
''' Decodes a request pdu
37
:param data: The packet data to decode
39
self.address, self.count = struct.unpack('>HH', data)
42
''' Returns a string representation of the instance
44
:returns: A string representation of the instance
46
return "ReadBitRequest(%d,%d)" % (self.address, self.count)
48
class ReadBitsResponseBase(ModbusResponse):
49
''' Base class for Messages responding to bit-reading values '''
51
_rtu_byte_count_pos = 2
53
def __init__(self, values, **kwargs):
54
''' Initializes a new instance
56
:param values: The requested values to be returned
58
ModbusResponse.__init__(self, **kwargs)
59
self.bits = values or []
62
''' Encodes response pdu
64
:returns: The encoded packet message
66
result = pack_bitstring(self.bits)
67
packet = struct.pack(">B", len(result)) + result
70
def decode(self, data):
71
''' Decodes response pdu
73
:param data: The packet data to decode
75
self.byte_count = struct.unpack(">B", data[0])[0]
76
self.bits = unpack_bitstring(data[1:])
78
def setBit(self, address, value=1):
79
''' Helper function to set the specified bit
81
:param address: The bit to set
82
:param value: The value to set the bit to
84
self.bits[address] = (value != 0)
86
def resetBit(self, address):
87
''' Helper function to set the specified bit to 0
89
:param address: The bit to reset
91
self.setBit(address, 0)
93
def getBit(self, address):
94
''' Helper function to get the specified bit's value
96
:param address: The bit to query
97
:returns: The value of the requested bit
99
return self.bits[address]
102
''' Returns a string representation of the instance
104
:returns: A string representation of the instance
106
return "ReadBitResponse(%d)" % len(self.bits)
108
class ReadCoilsRequest(ReadBitsRequestBase):
110
This function code is used to read from 1 to 2000(0x7d0) contiguous status
111
of coils in a remote device. The Request PDU specifies the starting
112
address, ie the address of the first coil specified, and the number of
113
coils. In the PDU Coils are addressed starting at zero. Therefore coils
114
numbered 1-16 are addressed as 0-15.
118
def __init__(self, address=None, count=None, **kwargs):
119
''' Initializes a new instance
121
:param address: The address to start reading from
122
:param count: The number of bits to read
124
ReadBitsRequestBase.__init__(self, address, count, **kwargs)
126
def execute(self, context):
127
''' Run a read coils request against a datastore
129
Before running the request, we make sure that the request is in
130
the max valid range (0x001-0x7d0). Next we make sure that the
131
request is valid against the current datastore.
133
:param context: The datastore to request from
134
:returns: The initializes response message, exception message otherwise
136
if not (1 <= self.count <= 0x7d0):
137
return self.doException(merror.IllegalValue)
138
if not context.validate(self.function_code, self.address, self.count):
139
return self.doException(merror.IllegalAddress)
140
values = context.getValues(self.function_code, self.address, self.count)
141
return ReadCoilsResponse(values)
143
class ReadCoilsResponse(ReadBitsResponseBase):
145
The coils in the response message are packed as one coil per bit of
146
the data field. Status is indicated as 1= ON and 0= OFF. The LSB of the
147
first data byte contains the output addressed in the query. The other
148
coils follow toward the high order end of this byte, and from low order
149
to high order in subsequent bytes.
151
If the returned output quantity is not a multiple of eight, the
152
remaining bits in the final data byte will be padded with zeros
153
(toward the high order end of the byte). The Byte Count field specifies
154
the quantity of complete bytes of data.
158
def __init__(self, values=None, **kwargs):
159
''' Intializes a new instance
161
:param values: The request values to respond with
163
ReadBitsResponseBase.__init__(self, values, **kwargs)
165
class ReadDiscreteInputsRequest(ReadBitsRequestBase):
167
This function code is used to read from 1 to 2000(0x7d0) contiguous status
168
of discrete inputs in a remote device. The Request PDU specifies the
169
starting address, ie the address of the first input specified, and the
170
number of inputs. In the PDU Discrete Inputs are addressed starting at
171
zero. Therefore Discrete inputs numbered 1-16 are addressed as 0-15.
175
def __init__(self, address=None, count=None, **kwargs):
176
''' Intializes a new instance
178
:param address: The address to start reading from
179
:param count: The number of bits to read
181
ReadBitsRequestBase.__init__(self, address, count, **kwargs)
183
def execute(self, context):
184
''' Run a read discrete input request against a datastore
186
Before running the request, we make sure that the request is in
187
the max valid range (0x001-0x7d0). Next we make sure that the
188
request is valid against the current datastore.
190
:param context: The datastore to request from
191
:returns: The initializes response message, exception message otherwise
193
if not (1 <= self.count <= 0x7d0):
194
return self.doException(merror.IllegalValue)
195
if not context.validate(self.function_code, self.address, self.count):
196
return self.doException(merror.IllegalAddress)
197
values = context.getValues(self.function_code, self.address, self.count)
198
return ReadDiscreteInputsResponse(values)
200
class ReadDiscreteInputsResponse(ReadBitsResponseBase):
202
The discrete inputs in the response message are packed as one input per
203
bit of the data field. Status is indicated as 1= ON; 0= OFF. The LSB of
204
the first data byte contains the input addressed in the query. The other
205
inputs follow toward the high order end of this byte, and from low order
206
to high order in subsequent bytes.
208
If the returned input quantity is not a multiple of eight, the
209
remaining bits in the final data byte will be padded with zeros
210
(toward the high order end of the byte). The Byte Count field specifies
211
the quantity of complete bytes of data.
215
def __init__(self, values=None, **kwargs):
216
''' Intializes a new instance
218
:param values: The request values to respond with
220
ReadBitsResponseBase.__init__(self, values, **kwargs)
222
#---------------------------------------------------------------------------#
224
#---------------------------------------------------------------------------#
226
"ReadCoilsRequest", "ReadCoilsResponse",
227
"ReadDiscreteInputsRequest", "ReadDiscreteInputsResponse",