Source code for tsip.hlapi

# -*- coding: utf-7 -*-
"""
High-level API.

"""

import struct
import binascii

from tsip.config import *
from tsip.llapi import *
from tsip.structs import *


class PackError(Exception):
    def __init__(self, packet):
        self.packet = packet

    def __repr__(self):
        return 'unable to pack packet %s' % (self.packet)


[docs]class Packet(object): """ TSIP packet. Check the TSIP reference documentation for the description of individual packets. The argument(s) to `Packet()` can be either individual values, a single tuple or a single list. Examples:: >>> pkt = Packet(0x1f) # Request software versions. >>> pkt = Packet(0x1e, 0x4b) # Request cold-start. >>> pkt = Packet( (0x23, -37.1, 144.1, 10.0) ) # Set initial position (tuple). >>> pkt = Packet( [0x8e, 0x4f, 0.1] ) # Set PPS with to 0.1s (list) """ _fields = [] """The data fields of the packet.""" def __init__(self, *fields): # Allow `*fields` to be either individual arguments or a list or tuple. # Because `fields` will always be a tuple anyway, passing a list or # tuple will result in `fields` being a nested structure.A # # Packet(1,2,3) -> (1,2,3) -> self.fields = fields # Packet((1,2,3)) -> ((1,2,3)) -> self.fields = fields[0] # Packet([1,2,3]) -> [(1,2,3)] -> self.fields = fields[0] # try: fields[0][0] # Passed list or tuple to `Packet()`? self.fields = fields[0] except TypeError: self.fields = fields # Packets are equal if their fields are equal # def __eq__(self, other): return self.fields == other.fields # Make self.fields accessible as indexes on the # packet instance. # def __getitem__(self, index): return self.fields[index] def __setitem__(self, index, value): self.fields[index] = value def __iter__(self): # TODO: tests for __iter__ return iter(self.fields) def __len__(self): # TODO: tests for __len__ return len(self.fields) def _set_fields(self, fields): self._fields = list(fields) def _get_fields(self): return self._fields fields = property(_get_fields, _set_fields)
[docs] def pack(self): """Return binary format of packet. The returned string is the binary format of the packet with stuffing and framing applied. It is ready to be sent to the GPS. """ # Possible structs for packet ID. # try: structs_ = get_structs_for_fields([self.fields[0]]) except (TypeError): # TypeError, if self.fields[0] is a wrong argument to `chr()`. raise PackError(self) # Possible structs for packet ID subcode # if structs_ == []: try: structs_ = get_structs_for_fields([self.fields[0], self.fields[1]]) except (IndexError, TypeError): # IndexError, if no self.fields[1] # TypeError, if self.fields[1] is a wrong argument to `chr()`. raise PackError(self) # Try to pack the packet with any of the possible structs. # for struct_ in structs_: try: return struct_.pack(*self.fields) except struct.error: pass # We only get here if the ``return`` inside the``for`` loop # above wasn't reached, i.e. none of the `structs_` matched. # raise PackError(self)
@classmethod
[docs] def unpack(cls, rawpacket): """Instantiate `Packet` from binary string. :param rawpacket: TSIP pkt in binary format. :type rawpacket: String. `rawpacket` must already have framing (DLE...DLE/ETX) removed and byte stuffing reversed. """ structs_ = get_structs_for_rawpacket(rawpacket) for struct_ in structs_: try: return cls(*struct_.unpack(rawpacket)) except struct.error: raise # Try next one. pass # Packet ID 0xff is a pseudo-packet representing # packets unknown to `python-TSIP` in their raw format. # return cls(0xff, rawpacket)
def __repr__(self): return 'Packet%s' % (str(tuple(self.fields)))
class GPS(gps): def __init__(self, conn): super(GPS, self).__init__(conn) def read(self): pkt = super(GPS, self).read() return Packet.unpack(unstuff(unframe(pkt))) def write(self, packet): super(GPS, self).write(frame(stuff(packet.pack())))