
This is a bit long, sorry... I have a PyGTK program that uses threads and pyserial's blocking methods to interact with an RS232 connected device. I'd like to throw out the threading awfulness and redo it in Twisted, if possible, but I'm a little lost. The real protocol is a bit convoluted, but basically: - You can issue single character commands to the device that give a fixed length response, such as sending 'C' and getting an eight-digit hex string back (the program flash CRC) - You can put the device into "programming mode" (command 'P'), where it takes an arbitrary length sequence of records, verifying each record and stopping when it sees the special "end record" - The device will send back '!' to indicate an error - The device will send back '>' to indicate that it's ready for more commands I know I need to use the SerialPort transport, and since that takes a protocol I've tried to sketch one out but can't seem to get very far. I want to have methods that can be called from the UI, returning deferreds to which UI responses can be added as callbacks. I also want to be able to monitor progress of the programming, so I need a callback for that separate from the deferred itself. I figure that calling, say, device.program(program, progress_cb) should return a Deferred and queue the command, and that somehow the dataReceived() method should be the start of a chain of events that either: - updates state and waits for the next piece of data, or - calls back on the appropriate Deferred I'd also like to structure things so that successive calls to the DeviceProtocol object queue up, something like: ---- class DeviceProtocol(Protocol): def dataReceived(self, data): # ...? def checksum(self): res = defer.Deferred() # When ready, send 'C' over the serial line (ie. # self.transport.write('C')) # Somehow callback via a deferred when the checksum comes back return res def program(self, program_records, progress_cb): res = defer.Deferred() # When ready, send 'P' over the serial line # Write all the data in "program_records", checking each # response, calling back via a deferred when done. # ... return res def connectionLost(self): # maybe have something here, like calling the errback of all # pending deferreds def go(reactor): # callbacks/errbacks not shown device = DeviceProtocol() transport = SerialPort(device, portname, reactor) program_result_1 = device.program(records, good_programming_progress) program_result_1.addCallbacks(programming_done, programming_err) checksum_result = device.checksum() checksum_result.addCallbacks(checksum, checksum_err) # This will fail at some point: program_result_2 = device.program(bad_records) cp_deferred.addCallbacks(programming_done, programming_err) if __name__ == "__main__": reactor.callWhenRunning(go, reactor) reactor.run() ---- But I'm really lost as to how to start structuring things within the protocol object itself. Should I even be doing this in a Protocol subclass, or should I be putting some of this functionality into a Factory of some sort (eg. a ClientFactory)? And if so, how do I actually connect the factory to the serial port transport? Or am I on the wrong track altogether? More to the point, has a problem like this already been solved somewhere? Is the solution obvious to Twisted gurus? Any help would be appreciated. Cheers, Jason