~ubuntu-branches/ubuntu/quantal/pymodbus/quantal

« back to all changes in this revision

Viewing changes to pymodbus/bit_write_message.py

  • Committer: Bazaar Package Importer
  • Author(s): W. Martin Borgert
  • Date: 2011-08-17 09:34:29 UTC
  • Revision ID: james.westby@ubuntu.com-20110817093429-cvgff034imbs899m
Tags: upstream-0.9.0
ImportĀ upstreamĀ versionĀ 0.9.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Bit Writing Request/Response
 
3
------------------------------
 
4
 
 
5
TODO write mask request/response
 
6
"""
 
7
import struct
 
8
from pymodbus.constants import ModbusStatus
 
9
from pymodbus.pdu import ModbusRequest
 
10
from pymodbus.pdu import ModbusResponse
 
11
from pymodbus.pdu import ModbusExceptions as merror
 
12
from pymodbus.exceptions import ParameterException
 
13
from pymodbus.utilities import pack_bitstring, unpack_bitstring
 
14
 
 
15
#---------------------------------------------------------------------------#
 
16
# Local Constants
 
17
#---------------------------------------------------------------------------#
 
18
# These are defined in the spec to turn a coil on/off
 
19
#---------------------------------------------------------------------------#
 
20
_turn_coil_on  = struct.pack(">H", ModbusStatus.On)
 
21
_turn_coil_off = struct.pack(">H", ModbusStatus.Off)
 
22
 
 
23
class WriteSingleCoilRequest(ModbusRequest):
 
24
    '''
 
25
    This function code is used to write a single output to either ON or OFF
 
26
    in a remote device.
 
27
 
 
28
    The requested ON/OFF state is specified by a constant in the request
 
29
    data field. A value of FF 00 hex requests the output to be ON. A value
 
30
    of 00 00 requests it to be OFF. All other values are illegal and will
 
31
    not affect the output.
 
32
 
 
33
    The Request PDU specifies the address of the coil to be forced. Coils
 
34
    are addressed starting at zero. Therefore coil numbered 1 is addressed
 
35
    as 0. The requested ON/OFF state is specified by a constant in the Coil
 
36
    Value field. A value of 0XFF00 requests the coil to be ON. A value of
 
37
    0X0000 requests the coil to be off. All other values are illegal and
 
38
    will not affect the coil.
 
39
    '''
 
40
    function_code = 5
 
41
    _rtu_frame_size = 8
 
42
 
 
43
    def __init__(self, address=None, value=None, **kwargs):
 
44
        ''' Initializes a new instance
 
45
 
 
46
        :param address: The variable address to write
 
47
        :param value: The value to write at address
 
48
        '''
 
49
        ModbusRequest.__init__(self, **kwargs)
 
50
        self.address = address
 
51
        self.value = True if value else False
 
52
 
 
53
    def encode(self):
 
54
        ''' Encodes write coil request
 
55
 
 
56
        :returns: The byte encoded message
 
57
        '''
 
58
        result  = struct.pack('>H', self.address)
 
59
        result += _turn_coil_on if self.value else _turn_coil_off
 
60
        return result
 
61
 
 
62
    def decode(self, data):
 
63
        ''' Decodes a write coil request
 
64
 
 
65
        :param data: The packet data to decode
 
66
        '''
 
67
        self.address, value = struct.unpack('>HH', data)
 
68
        self.value = True if value == ModbusStatus.On else False
 
69
 
 
70
    def execute(self, context):
 
71
        ''' Run a write coil request against a datastore
 
72
 
 
73
        :param context: The datastore to request from
 
74
        :returns: The populated response or exception message
 
75
        '''
 
76
        #if self.value not in [ModbusStatus.Off, ModbusStatus.On]:
 
77
        #    return self.doException(merror.IllegalValue)
 
78
        if not context.validate(self.function_code, self.address, 1):
 
79
            return self.doException(merror.IllegalAddress)
 
80
 
 
81
        context.setValues(self.function_code, self.address, self.value)
 
82
        values = context.getValues(self.function_code, self.address, 1)
 
83
        return WriteSingleCoilResponse(self.address, values[0])
 
84
 
 
85
    def __str__(self):
 
86
        ''' Returns a string representation of the instance
 
87
 
 
88
        :return: A string representation of the instance
 
89
        '''
 
90
        return "WriteCoilRequest(%d, %s) => " % (self.address, self.value)
 
91
 
 
92
class WriteSingleCoilResponse(ModbusResponse):
 
93
    '''
 
94
    The normal response is an echo of the request, returned after the coil
 
95
    state has been written.
 
96
    '''
 
97
    function_code = 5
 
98
    _rtu_frame_size = 8
 
99
 
 
100
    def __init__(self, address=None, value=None, **kwargs):
 
101
        ''' Initializes a new instance
 
102
 
 
103
        :param address: The variable address written to
 
104
        :param value: The value written at address
 
105
        '''
 
106
        ModbusResponse.__init__(self, **kwargs)
 
107
        self.address = address
 
108
        self.value = value
 
109
 
 
110
    def encode(self):
 
111
        ''' Encodes write coil response
 
112
 
 
113
        :return: The byte encoded message
 
114
        '''
 
115
        result  = struct.pack('>H', self.address)
 
116
        result += _turn_coil_on if self.value else _turn_coil_off
 
117
        return result
 
118
 
 
119
    def decode(self, data):
 
120
        ''' Decodes a write coil response
 
121
 
 
122
        :param data: The packet data to decode
 
123
        '''
 
124
        self.address, value = struct.unpack('>HH', data)
 
125
        self.value = (value == ModbusStatus.On)
 
126
 
 
127
    def __str__(self):
 
128
        ''' Returns a string representation of the instance
 
129
 
 
130
        :returns: A string representation of the instance
 
131
        '''
 
132
        return "WriteCoilResponse(%d) => %d" % (self.address, self.value)
 
133
 
 
134
class WriteMultipleCoilsRequest(ModbusRequest):
 
135
    '''
 
136
    "This function code is used to force each coil in a sequence of coils to
 
137
    either ON or OFF in a remote device. The Request PDU specifies the coil
 
138
    references to be forced. Coils are addressed starting at zero. Therefore
 
139
    coil numbered 1 is addressed as 0.
 
140
 
 
141
    The requested ON/OFF states are specified by contents of the request
 
142
    data field. A logical '1' in a bit position of the field requests the
 
143
    corresponding output to be ON. A logical '0' requests it to be OFF."
 
144
    '''
 
145
    function_code = 15
 
146
    _rtu_byte_count_pos = 6
 
147
 
 
148
    def __init__(self, address=None, values=None, **kwargs):
 
149
        ''' Initializes a new instance
 
150
 
 
151
        :param address: The starting request address
 
152
        :param values: The values to write
 
153
        '''
 
154
        ModbusRequest.__init__(self, **kwargs)
 
155
        self.address = address
 
156
        if not values: values = []
 
157
        elif not hasattr(values, '__iter__'): values = [values]
 
158
        self.values  = values
 
159
        self.byte_count = (len(self.values) + 7) / 8
 
160
 
 
161
    def encode(self):
 
162
        ''' Encodes write coils request
 
163
 
 
164
        :returns: The byte encoded message
 
165
        '''
 
166
        count   = len(self.values)
 
167
        self.byte_count = (count + 7) / 8
 
168
        packet  = struct.pack('>HHB', self.address, count, self.byte_count)
 
169
        packet += pack_bitstring(self.values)
 
170
        return packet
 
171
 
 
172
    def decode(self, data):
 
173
        ''' Decodes a write coils request
 
174
 
 
175
        :param data: The packet data to decode
 
176
        '''
 
177
        self.address, count, self.byte_count = struct.unpack('>HHB', data[0:5])
 
178
        values = unpack_bitstring(data[5:])
 
179
        self.values = values[:count]
 
180
 
 
181
    def execute(self, context):
 
182
        ''' Run a write coils request against a datastore
 
183
 
 
184
        :param context: The datastore to request from
 
185
        :returns: The populated response or exception message
 
186
        '''
 
187
        count = len(self.values)
 
188
        if not (1 <= count <= 0x07b0):
 
189
            return self.doException(merror.IllegalValue)
 
190
        if (self.byte_count != (count + 7) / 8):
 
191
            return self.doException(merror.IllegalValue)
 
192
        if not context.validate(self.function_code, self.address, count):
 
193
            return self.doException(merror.IllegalAddress)
 
194
 
 
195
        context.setValues(self.function_code, self.address, self.values)
 
196
        return WriteMultipleCoilsResponse(self.address, count)
 
197
 
 
198
    def __str__(self):
 
199
        ''' Returns a string representation of the instance
 
200
 
 
201
        :returns: A string representation of the instance
 
202
        '''
 
203
        params = (self.address, len(self.values))
 
204
        return "WriteNCoilRequest (%d) => %d " % params
 
205
 
 
206
class WriteMultipleCoilsResponse(ModbusResponse):
 
207
    '''
 
208
    The normal response returns the function code, starting address, and
 
209
    quantity of coils forced.
 
210
    '''
 
211
    function_code = 15
 
212
    _rtu_frame_size = 8
 
213
 
 
214
    def __init__(self, address=None, count=None, **kwargs):
 
215
        ''' Initializes a new instance
 
216
 
 
217
        :param address: The starting variable address written to
 
218
        :param count: The number of values written
 
219
        '''
 
220
        ModbusResponse.__init__(self, **kwargs)
 
221
        self.address = address
 
222
        self.count = count
 
223
 
 
224
    def encode(self):
 
225
        ''' Encodes write coils response
 
226
 
 
227
        :returns: The byte encoded message
 
228
        '''
 
229
        return struct.pack('>HH', self.address, self.count)
 
230
 
 
231
    def decode(self, data):
 
232
        ''' Decodes a write coils response
 
233
 
 
234
        :param data: The packet data to decode
 
235
        '''
 
236
        self.address, self.count = struct.unpack('>HH', data)
 
237
 
 
238
    def __str__(self):
 
239
        ''' Returns a string representation of the instance
 
240
 
 
241
        :returns: A string representation of the instance
 
242
        '''
 
243
        return "WriteNCoilResponse(%d, %d)" % (self.address, self.count)
 
244
 
 
245
#---------------------------------------------------------------------------# 
 
246
# Exported symbols
 
247
#---------------------------------------------------------------------------# 
 
248
__all__ = [
 
249
    "WriteSingleCoilRequest", "WriteSingleCoilResponse",
 
250
    "WriteMultipleCoilsRequest", "WriteMultipleCoilsResponse",
 
251
]