#!/usr/bin/env python
#
# This file is Copyright (c) 2010 by the GPSD project
# BSD terms apply: see the file COPYING in the distribution root for details.
#
# Display GPS output.  Hexify it if necessary.
#
import os, sys, termios, socket, select, getopt, curses.ascii
import gps.packet as sniffer

# The spec says 82, but some receivers (TN-200, GSW 2.3.2) output 86 characters
NMEA_MAX = 86

# Lowest debug level at which packet getter begins to emit messages, minus one
BASELEVEL = sniffer.LOG_IO

highhalf_latch = True

def hexdump(st):
    dmp = ""
    for (_i, ch) in enumerate(st):
        if curses.ascii.isprint(ord(ch)) or curses.ascii.isspace(ord(ch)):
            dmp += ch
        else:
            dmp += "\\x%02x" % ord(ch)
    return dmp

debuglevel = 0

def reporter(errlevel, msg):
    if errlevel <= debuglevel:
        sys.stdout.write(msg)

def printusage():
    sys.stderr.write("usage: gpscat [-s speed] [-p] [-t] [-D debuglevel] serial-port\n")

if __name__ == '__main__':
    buf = ""
    try:
        try:
            (options, arguments) = getopt.getopt(sys.argv[1:], "hps:tD:V")
        except getopt.GetoptError, msg:
            print "gpscat: " + str(msg)
            raise SystemExit, 1

        speed = None
        parity = None
        stopbits = None
        rawmode = True
        typeflag = False
        for (switch, val) in options:
            if switch == '-p':
                rawmode = False
            elif switch == '-s':
                if val[-2] in ('N', 'E', 'O'):
                    parity = val[-2]
                    stopbits = int(val[-1])
                    val = val[:-2]
                speed = int(val)
            elif switch == '-t':
                typeflag = True
                rawmode = False
            elif switch == '-D':
                debuglevel = BASELEVEL + int(val)
            elif switch == '-h':
                printusage()
                raise SystemExit, 0

        if (len(arguments) != 1):
            printusage()
            raise SystemExit, 1

        if "rfcomm" in arguments[0]:     # Bluetooth special case
            s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM)
            s.connect((arguments[0], 1))
            tty = s.fileno()
        else:                            # Ordinary device
            tty = os.open(arguments[0], os.O_RDWR)

        if speed != None:
            (iflag, oflag, cflag, lflag, ispeed, ospeed, cc) = termios.tcgetattr(tty)
            try:
                ispeed = ospeed = eval("termios.B%d" % speed)
            except AttributeError:
                sys.stderr.write("gpscat: unknown baud rate %d\n" % speed)
                raise SystemExit, 1
            if stopbits:
                cflag &= ~termios.CSIZE
                cflag |= (termios.CS8, termios.CS7)[stopbits-1]
            if parity:
                if parity == 'N':
                    iflag &= ~termios.PARENB
                    iflag &= ~termios.INPCK
                elif parity == 'O':
                    iflag |= termios.INPCK
                    cflag |= termios.PARENB
                    cflag |= termios.PARODD
                elif parity == 'E':
                    iflag |= termios.INPCK
                    cflag |= termios.PARENB
                    cflag &= ~termios.PARODD
            termios.tcsetattr(tty, termios.TCSANOW,
                         [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])

        poller = select.poll()
        poller.register(tty, select.POLLIN)

        buf = ""
        if not rawmode:
            getter = sniffer.new()
            sniffer.register_report(reporter)
        seqno = 0
        while True:
            (fd, event) = poller.poll()[0]
            if fd == tty and event == select.POLLIN:
                if rawmode:
                    buf += os.read(tty, NMEA_MAX)
                    sys.stdout.write(hexdump(buf))
                    buf = ""
                else:
                    (length, ptype, packet, counter) = getter.get(tty)
                    seqno += 1
                    if length == 0:
                        break
                    if typeflag:
                        sys.stdout.write(`ptype` + " (" + repr(length) + "@" + repr(counter-length) + "): " + hexdump(packet))
                        sys.stdout.write("\n")
                    else:
                        sys.stdout.write(hexdump(packet) + "\n")
    except KeyboardInterrupt:
        if rawmode:
            sys.stdout.write("\n")
        raise SystemExit, 0

# Local variables:
# mode: python
# end:


