From 388dd88e6a66ce5eaad6d1392c742d43f328af30 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Wed, 17 Dec 2008 23:40:36 +0100 Subject: * host/proto: - added documentation. - fixed small discordance between documentation and behaviour. --- host/proto/doc/proto.txt | 128 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 host/proto/doc/proto.txt (limited to 'host/proto/doc/proto.txt') diff --git a/host/proto/doc/proto.txt b/host/proto/doc/proto.txt new file mode 100644 index 00000000..afbeffbb --- /dev/null +++ b/host/proto/doc/proto.txt @@ -0,0 +1,128 @@ +======================================= + proto - Host proto communication API. +======================================= +:Author: Nicolas Schodet + +Introduction +============ + +This module handles the communication protocol defined in the *proto* AVR +module. It can be used to communicate through a read serial port with an +embedded program running on an AVR, or using a pseudo-terminal or standard +input/output to communicate with a program compiled for the host system. + +This module also handles the master part of the protocol: + +- Acknowledgement from the slave device. +- Retransmission if no acknowledgement is received. +- Retransmission if the slave signals an error. + +This module does not handle higher level protocols, such as duplicates +handling or frame sequence number. + +To understand this documentation, you should be familiar with the protocol, +which is explained in the AVR module documentation. + +Usage +===== + +Initialisation +-------------- + +First, create a Proto instance. For example to connect with a real serial +port:: + + proto = Proto (serial.Serial ('/dev/ttyS0'), time.time, 0.1) + +To connect to a program running on host, with a logging output:: + + def log (text): + print text + proto = Proto (proto.popen_io.PopenIO ('test_program.host'), time.time, 0.1, + log = log) + +Synchronisation +--------------- + +You need to synchronise regularly with the remote program. You have two +options. + +The first one can be used if you have nothing else to execute apart from the +protocol handling. In this case, just call the wait function. If a argument +is given, this should be a callable object which will return True to stop +waiting. + +The wait function will only return if all frames have been sent and the +condition argument returns True. + +Example, wait forever:: + + proto.wait () + +Or, wait until an internal counter has reached a value:: + + proto.wait (lambda: my_counter == 3) + +The second option should be used if you need concurrent access to several +sources (GUI interface, several proto, other events...). In this case, the +sync function should be called regularly (at least every timeout period), and +the read function should be called if data is available on the proto file +descriptor which can be retrieved as usual using the fileno function. + +Example:: + + while not proto.sync (): + fds = select.select ((proto, other_input), (), (), 0.1)[0] + for fd in fds: + fd.read () + +Sending a frame +--------------- + +To send a frame, use the send function. + +First argument is the command character. Then comes the frame arguments format +followed by the frame arguments. The format follows the struct module fmt +string. + +Examples:: + + proto.send ('z') # Send !z + proto.send ('a', 'b', 1) # Send !a01 + proto.send ('b', 'bhl', 1, 2, 84942856) # Send !b01000205102008 + +The frame is not sent immediately, but once wait or sync is called and all the +previously enqueued frames are acknowledged. + +Receiving a frame +----------------- + +When a frame is received, a user callback will be called if it has been +registered. + +To register a callback, use the register function. The first argument is the +frame command to bind to this callback, the second one is the frame arguments +format, and the last one is the callback. + +Here, the distinction between signed and unsigned arguments is important. + +If a frame is received with the registered command and a number of bytes +matching the frame arguments format, the callback is called with arguments +decoded. + +For example:: + + def my_callback1 (a, b): + print "callback1", a, b + def my_callback2 (a): + print "callback2", a + proto.register ('x', 'bB', my_callback1) + proto.register ('y', 'l', my_callback2) + + # If !xffff is received, this will print: + # callback1 255 -1 + # If !y05102008 is received, this will print: + # callback2 84942856 + +Keep in mind that the protocol can not make the distinction between the format +'bbbb' and 'l' as it uses the same number of bytes. -- cgit v1.2.3