~ubuntu-branches/ubuntu/raring/pymodbus/raring-proposed

« back to all changes in this revision

Viewing changes to pymodbus/client/async.py

  • Committer: Package Import Robot
  • Author(s): W. Martin Borgert
  • Date: 2011-10-26 07:26:28 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20111026072628-fvzyi6tnb8iipomp
Tags: 0.9.0+r175-1
* Update from trunk to get a number of upstream fixes.
* Removed examples/tools/ (not present in previous version
  anyway) from source because there are different licenses
  involved. Needs clarification.
* Dont't install unit tests.
* Debian patches not necessary anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
Implementation of a Modbus Client Using Twisted
3
3
--------------------------------------------------
4
4
 
5
 
Example Run::
6
 
 
 
5
Example run::
 
6
 
 
7
    from twisted.internet import reactor, protocol
 
8
    from pymodbus.client.async import ModbusClientProtocol
 
9
 
 
10
    def printResult(result):
 
11
        print "Result: %d" % result.bits[0]
 
12
 
 
13
    def process(client):
 
14
        result = client.write_coil(1, True)
 
15
        result.addCallback(printResult)
 
16
        reactor.callLater(1, reactor.stop)
 
17
 
 
18
    defer = protocol.ClientCreator(reactor, ModbusClientProtocol
 
19
            ).connectTCP("localhost", 502)
 
20
    defer.addCallback(process)
 
21
 
 
22
Another example::
 
23
 
 
24
    from twisted.internet import reactor
7
25
    from pymodbus.client.async import ModbusClientFactory
8
 
    from pymodbus.bit_read_message import ReadCoilsRequest
9
 
 
10
 
    def clientTest():
11
 
        requests = [ ReadCoilsRequest(0,99) ]
12
 
        p = reactor.connectTCP("localhost", 502, ModbusClientFactory(requests))
13
 
    
 
26
 
 
27
    def process():
 
28
        factory = reactor.connectTCP("localhost", 502, ModbusClientFactory())
 
29
        reactor.stop()
 
30
 
14
31
    if __name__ == "__main__":
15
 
       reactor.callLater(1, clientTest)
 
32
       reactor.callLater(1, process)
16
33
       reactor.run()
17
34
"""
18
 
import struct
19
35
from collections import deque
20
 
 
21
 
from twisted.internet import reactor, defer, protocol
22
 
 
 
36
from twisted.internet import defer, protocol
23
37
from pymodbus.factory import ClientDecoder
24
38
from pymodbus.exceptions import ConnectionException
25
 
from pymodbus.transaction import ModbusSocketFramer
 
39
from pymodbus.transaction import ModbusSocketFramer, ModbusTransactionManager
26
40
from pymodbus.client.common import ModbusClientMixin
27
41
 
28
42
#---------------------------------------------------------------------------#
32
46
_logger = logging.getLogger(__name__)
33
47
 
34
48
#---------------------------------------------------------------------------#
35
 
# Client Protocols
 
49
# A manager for the transaction identifiers
 
50
#---------------------------------------------------------------------------#
 
51
_manager = ModbusTransactionManager()
 
52
 
 
53
 
 
54
#---------------------------------------------------------------------------#
 
55
# Connected Client Protocols
36
56
#---------------------------------------------------------------------------#
37
57
class ModbusClientProtocol(protocol.Protocol, ModbusClientMixin):
38
58
    '''
39
59
    This represents the base modbus client protocol.  All the application
40
60
    layer code is deferred to a higher level wrapper.
41
61
    '''
42
 
    __tid = 0
43
62
 
44
63
    def __init__(self, framer=None):
45
64
        ''' Initializes the framer module
47
66
        :param framer: The framer to use for the protocol
48
67
        '''
49
68
        self.framer = framer or ModbusSocketFramer(ClientDecoder())
50
 
        self._requests = deque() # link queue to tid
 
69
        self._requests = deque()  # link queue to tid
51
70
        self._connected = False
52
71
 
53
72
    def connectionMade(self):
69
88
 
70
89
        :param data: The data returned from the server
71
90
        '''
72
 
        self.framer.processIncomingPacket(data, self._callback)
 
91
        def _callback(reply): # todo errback/callback
 
92
            if self._requests:
 
93
                self._requests.popleft().callback(reply)
 
94
 
 
95
        self.framer.processIncomingPacket(data, _callback)
73
96
 
74
97
    def execute(self, request):
75
98
        ''' Starts the producer to send the next request to
76
99
        consumer.write(Frame(request))
77
100
        '''
78
 
        request.transaction_id = self.__getNextTID()
 
101
        request.transaction_id = _manager.getNextTID()
79
102
        #self.handler[request.transaction_id] = request
80
103
        packet = self.framer.buildPacket(request)
81
104
        self.transport.write(packet)
82
105
        return self._buildResponse()
83
106
 
84
 
    def _callback(self, reply):
85
 
        ''' The callback to call with the response message
86
 
 
87
 
        :param reply: The decoded response message
88
 
        '''
89
 
        # todo errback/callback
90
 
        if self._requests:
91
 
            self._requests.popleft().callback(reply)
92
 
 
93
107
    def _buildResponse(self):
94
108
        ''' Helper method to return a deferred response
95
109
        for the current request.
103
117
        self._requests.append(d)
104
118
        return d
105
119
 
106
 
    def __getNextTID(self):
107
 
        ''' Used to retrieve the next transaction id
108
 
        :return: The next unique transaction id
109
 
 
110
 
        As the transaction identifier is represented with two
111
 
        bytes, the highest TID is 0xffff
112
 
 
113
 
        ..todo:: Remove this and use the transaction manager
114
 
        '''
115
 
        tid = (ModbusClientProtocol.__tid + 1) & 0xffff
116
 
        ModbusClientProtocol.__tid = tid
117
 
        return tid
118
 
 
119
120
    #----------------------------------------------------------------------#
120
121
    # Extra Functions
121
122
    #----------------------------------------------------------------------#
125
126
    #               self.retry -= 1
126
127
 
127
128
#---------------------------------------------------------------------------#
 
129
# Not Connected Client Protocol
 
130
#---------------------------------------------------------------------------#
 
131
class ModbusUdpClientProtocol(protocol.DatagramProtocol, ModbusClientMixin):
 
132
    '''
 
133
    This represents the base modbus client protocol.  All the application
 
134
    layer code is deferred to a higher level wrapper.
 
135
    '''
 
136
    __tid = 0
 
137
 
 
138
    def __init__(self, framer=None):
 
139
        ''' Initializes the framer module
 
140
 
 
141
        :param framer: The framer to use for the protocol
 
142
        '''
 
143
        self.framer = framer or ModbusSocketFramer(ClientDecoder())
 
144
        self._requests = deque()  # link queue to tid
 
145
 
 
146
    def datagramReceived(self, data, (host, port)):
 
147
        ''' Get response, check for valid message, decode result
 
148
 
 
149
        :param data: The data returned from the server
 
150
        '''
 
151
        def _callback(reply): # todo errback/callback
 
152
            if self._requests:
 
153
                self._requests.popleft().callback(reply)
 
154
 
 
155
        _logger.debug("Datagram from: %s:%d" % (host, port))
 
156
        self.framer.processIncomingPacket(data, _callback)
 
157
 
 
158
    def execute(self, request):
 
159
        ''' Starts the producer to send the next request to
 
160
        consumer.write(Frame(request))
 
161
        '''
 
162
        request.transaction_id = _manager.getNextTID()
 
163
        #self.handler[request.transaction_id] = request
 
164
        packet = self.framer.buildPacket(request)
 
165
        self.transport.write(packet)
 
166
        return self._buildResponse()
 
167
 
 
168
    def _buildResponse(self):
 
169
        ''' Helper method to return a deferred response
 
170
        for the current request.
 
171
 
 
172
        :returns: A defer linked to the latest request
 
173
        '''
 
174
        d = defer.Deferred()
 
175
        self._requests.append(d)
 
176
        return d
 
177
 
 
178
 
 
179
#---------------------------------------------------------------------------#
128
180
# Client Factories
129
181
#---------------------------------------------------------------------------#
130
182
class ModbusClientFactory(protocol.ReconnectingClientFactory):
132
184
 
133
185
    protocol = ModbusClientProtocol
134
186
 
135
 
#---------------------------------------------------------------------------# 
 
187
#---------------------------------------------------------------------------#
136
188
# Exported symbols
137
 
#---------------------------------------------------------------------------# 
 
189
#---------------------------------------------------------------------------#
138
190
__all__ = [
139
 
    "ModbusClientProtocol", "ModbusClientFactory",
 
191
    "ModbusClientProtocol", "ModbusUdpClientProtocol",
 
192
    "ModbusClientFactory",
140
193
]