frame.py
Go to the documentation of this file.
00001 """
00002 frame.py
00003 
00004 By Paul Malmsten, 2010
00005 pmalmsten@gmail.com
00006 
00007 Represents an API frame for communicating with an XBee
00008 """
00009 import struct
00010 
00011 class APIFrame:
00012     """
00013     Represents a frame of data to be sent to or which was received 
00014     from an XBee device
00015     """
00016     
00017     START_BYTE = '\x7E'
00018     ESCAPE_BYTE = '\x7D'
00019     XON_BYTE = '\x11'
00020     XOFF_BYTE = '\x13'
00021     ESCAPE_BYTES = (START_BYTE, ESCAPE_BYTE, XON_BYTE, XOFF_BYTE)
00022     
00023     def __init__(self, data='', escaped=False):
00024         self.data = data
00025         self.raw_data = ''
00026         self.escaped = escaped
00027         self._unescape_next_byte = False
00028         
00029     def checksum(self):
00030         """
00031         checksum: None -> single checksum byte
00032         
00033         checksum adds all bytes of the binary, unescaped data in the 
00034         frame, saves the last byte of the result, and subtracts it from 
00035         0xFF. The final result is the checksum
00036         """
00037         total = 0
00038         
00039         # Add together all bytes
00040         for byte in self.data:
00041             total += ord(byte)
00042             
00043         # Only keep the last byte
00044         total = total & 0xFF
00045         
00046         # Subtract from 0xFF
00047         return chr(0xFF - total)
00048 
00049     def verify(self, chksum):
00050         """
00051         verify: 1 byte -> boolean
00052         
00053         verify checksums the frame, adds the expected checksum, and 
00054         determines whether the result is correct. The result should 
00055         be 0xFF.
00056         """
00057         total = 0
00058         
00059         # Add together all bytes
00060         for byte in self.data:
00061             total += ord(byte)
00062             
00063         # Add checksum too
00064         total += ord(chksum)
00065         
00066         # Only keep low bits
00067         total &= 0xFF
00068         
00069         # Check result
00070         return total == 0xFF
00071 
00072     def len_bytes(self):
00073         """
00074         len_data: None -> (MSB, LSB) 16-bit integer length, two bytes
00075         
00076         len_bytes counts the number of bytes to be sent and encodes the 
00077         data length in two bytes, big-endian (most significant first).
00078         """
00079         count = len(self.data)
00080         return struct.pack("> h", count)
00081         
00082     def output(self):
00083         """
00084         output: None -> valid API frame (binary data)
00085         
00086         output will produce a valid API frame for transmission to an 
00087         XBee module.
00088         """
00089         # start is one byte long, length is two bytes
00090         # data is n bytes long (indicated by length)
00091         # chksum is one byte long
00092         data = self.len_bytes() + self.data + self.checksum()
00093 
00094         # Only run the escaoe process if it hasn't been already
00095         if self.escaped and len(self.raw_data) < 1:
00096             self.raw_data = APIFrame.escape(data)
00097 
00098         if self.escaped:
00099             data = self.raw_data
00100 
00101         # Never escape start byte
00102         return APIFrame.START_BYTE + data
00103 
00104     @staticmethod
00105     def escape(data):
00106         """
00107         escape: byte string -> byte string
00108 
00109         When a 'special' byte is encountered in the given data string,
00110         it is preceded by an escape byte and XORed with 0x20.
00111         """
00112 
00113         escaped_data = ""
00114         for byte in data:
00115             if byte in APIFrame.ESCAPE_BYTES:
00116                 escaped_data += APIFrame.ESCAPE_BYTE
00117                 escaped_data += chr(0x20 ^ ord(byte))
00118             else:
00119                 escaped_data += byte
00120         
00121         return escaped_data
00122 
00123     def fill(self, byte):
00124         """
00125         fill: byte -> None
00126 
00127         Adds the given raw byte to this APIFrame. If this APIFrame is marked
00128         as escaped and this byte is an escape byte, the next byte in a call
00129         to fill() will be unescaped.
00130         """
00131 
00132         if self._unescape_next_byte:
00133             byte = chr(ord(byte) ^ 0x20) 
00134             self._unescape_next_byte = False
00135         elif self.escaped and byte == APIFrame.ESCAPE_BYTE:
00136             self._unescape_next_byte = True
00137             return
00138 
00139         self.raw_data += byte
00140 
00141     def remaining_bytes(self):
00142         remaining = 3
00143 
00144         if len(self.raw_data) >= 3:
00145             # First two bytes are the length of the data
00146             raw_len = self.raw_data[1:3]
00147             data_len = struct.unpack("> h", raw_len)[0]
00148 
00149             remaining += data_len
00150 
00151             # Don't forget the checksum
00152             remaining += 1
00153 
00154         return remaining - len(self.raw_data)
00155         
00156     def parse(self):
00157         """
00158         parse: None -> None
00159         
00160         Given a valid API frame, parse extracts the data contained
00161         inside it and verifies it against its checksum
00162         """
00163         if len(self.raw_data) < 3:
00164             ValueError("parse() may only be called on a frame containing at least 3 bytes of raw data (see fill())")
00165 
00166         # First two bytes are the length of the data
00167         raw_len = self.raw_data[1:3]
00168         
00169         # Unpack it
00170         data_len = struct.unpack("> h", raw_len)[0]
00171         
00172         # Read the data
00173         data = self.raw_data[3:3 + data_len]
00174         chksum = self.raw_data[-1]
00175 
00176         # Checksum check
00177         self.data = data
00178         if not self.verify(chksum):
00179             raise ValueError("Invalid checksum")


rosserial_xbee
Author(s): Adam Stambler
autogenerated on Fri Dec 6 2013 20:35:48