#!/usr/bin/env python

import sys
import time
import signal
import select
import getopt
import serial

modulations = ["WFM", "NFM", "AM", "USB", "LSB", "CW", "SFM", "WAM", "NAM"]

port = "/dev/ttyS0"
bps = 9600
debug = False

def connect():
    global port, bps
    ser = serial.Serial(port=port, baudrate=bps, timeout=0.2)
    while len(ser.readlines()) == 0:
        ser.write("\r")
    return ser

def cmd(ser, cmd, getresp=True):
    ser.write(str(cmd)+"\r")
    if debug:
        print ">>>: [%s]" % cmd
    resp = [r.strip() for r in ser.readlines()]

    if len(resp) == 1:
        resp = resp[0]

    if getresp:
        if debug:
            print "<<<: [%s]" % str(resp)
        return resp
    else:
        return ""

def disconnect(ser):
    ser.close()

def q_squelch(ser):
    da = cmd(ser, "DA")[2:].strip()
    db = cmd(ser, "DB")[2:].strip()
    print "Squelch - AUDIO: %s  LEVEL: %s" % (da, db)

def q_smeter(ser):
    lm = cmd(ser, "LM")
    if lm[2] == " ":
        sq = "open"
    else:
        sq = "closed"
    val = int(lm[3:])
    print "S-Meter: %d, squelch %s" % (val, sq)

def do_status(ser):
    st = cmd(ser, "RX")
    parts = st.split(' ')

    # Check mode
    if parts[0] == "VF":
        print "Mode: 1-VFO"
    elif parts[0] == "VS":
        print "Mode: VFO-Search"
        parts.pop(0)
    elif st[0][0] != "V":
        print "Unknown RX reply: [%s]" % st
    else:
        print "Mode: VFO-%s" % parts[0][1]

    # Freq
    freq = float(parts[1][2:])
    print "Freq: %.04fMHz" % (freq / 1000000.0)

    # Modulation
    mod = int(parts[4][2:])
    print "Modulation: %s" % modulations[mod]

    # Attenuator
    if parts[5][2] == "0":
        print "Attenuator: OFF"
    else:
        print "Attenuator: ON"

    # Noise limiter
    nl = cmd(ser, "NL")
    if nl[2] == "0":
        print "Noiselimiter: OFF"
    else:
        print "Noiselimiter: ON"

    # Do other status queries
    q_smeter(ser)
    q_squelch(ser)

def do_search(ser, param):
    Fs, Fe = param.split(":")
    print "Starting VFO search of %sMHz to %sMHz" % (Fs, Fe)
    cmd(ser, "VA%s" % Fs)
    cmd(ser, "VB%s" % Fe)
    cmd(ser, "VS")
    time.sleep(0.5)
    ser.readlines()

def lc_decode(line):
    global lc_timer
    if not line[0:2] == "LC":
        return

    if debug:
        print "<<<:",
        print line
        
    parts = line[2:].split(' ')
    if parts[0][0] == "%":
        print "CLOSED -",
        sm = int(parts[0][1:])
        print "S-Meter: %d" % sm,
        print "Duration: %.01fs" % (time.time() - lc_timer)
        lc_timer = time.time()
    else:
        lc_timer = time.time()
        print "OPEN   -",

        sm = int(parts[0])
        print "S-Meter: %d" % sm,

        freq = float(parts[2][2:]) / 1000000.0
        print "Freq: %.04fMHz" % freq
    

def do_lc(ser):
    global lc_timer
    signal.signal(signal.SIGINT, lambda x,y: 1)

    print "== Live monitoring started. CTRL-C to stop."
    cmd(ser, "LC1", getresp=False)
    lc_timer = time.time()

    while True:
        try:
            line = ser.readline()
        except select.error:
            break
        lc_decode(line.strip())

    cmd(ser, "LC0")
    print "== Live monitoring stopped"
    print

def do_request(ser, req, param):
    if req == "-F":
        print "Setting frequency to %s MHz" % param
        cmd(ser, "RF%s" % param)
    elif req == "-M":
        print "Setting modulation to %s" % param
        param = param.lower()
        c = 0
        if param == "wfm": c = 0
        elif param == "nfm": c = 1
        elif param == "am": c = 2
        elif param == "usb": c = 3
        elif param == "lsb": c = 4
        elif param == "cw": c = 5
        elif param == "sfm": c = 6
        elif param == "wam": c = 7
        elif param == "nam": c = 8
        cmd(ser, "MD%d" % c)
    elif req == "-A":
        print "Setting audio squelch to %d" % int(param)
        cmd(ser, "DA%d" % int(param))
    elif req == "-L":
        print "Setting level squelch to %d" % int(param)
        cmd(ser, "DB%d" % int(param))
    elif req == "-S":
        print "Setting squelch to %s" % param
        if param.lower() == "open": cmd(ser, "MC2")
        elif param.lower() == "closed": cmd(ser, "MC1")
        else: cmd(ser, "MC0")
    elif req == "--squelch":
        q_squelch(ser)
    elif req == "--s-meter":
        q_smeter(ser)
    elif req == "--attenuator":
        if param.lower() == "on":
            print "Enabling attenuator"
            cmd(ser, "AT1")
        elif param.lower() == "off":
            print "Disabling attenuator"
            cmd(ser, "AT0")
        else:
            print "Unknown attenuator setting"
    elif req == "--nl":
        if param.lower() == "on":
            print "Enabling noise limiter"
            cmd(ser, "NL1")
        elif param.lower() == "off":
            print "Disabling noise limiter"
            cmd(ser, "NL0")
        else:
            print "Unknown attenuator setting"
    elif req == "--status":
        do_status(ser)
    elif req == "--search":
        do_search(ser, param)
    elif req == "--1vfo":
        print "Selecting 1-VFO"
        cmd(ser, "VF")
        time.sleep(0.5)
        ser.readlines()
    elif req == "--vfo":
        param = param.upper()
        print "Selecting VFO-%s" % param
        cmd(ser, "V%s" % param)
        time.sleep(0.5)
        ser.readlines()
    elif req == "--delete-pass":
        print "Deleting all VFO pass frequencies"
        cmd(ser, "PDV%%")
    elif req == "--add-pass":
        print "Adding pass frequency %s MHz" % param
        cmd(ser, "PWV%s" % param)
    elif req == "--lc":
        do_lc(ser)
    elif req == "--off":
        print "Turning receiver off"
        cmd(ser, "QP", getresp=False)
    else:
        print "Unknown request %s" % req
        return False

    return True
    

def usage():
    print "ar8600.py - AR8600 (and others) control program"
    print "ar8600.py [-p <port>] [-b <baudrate>] cmds..."
    print "\t -d \t\t\t Set debug mode"
    print "\t -p <port> \t\t Port is %s" % port
    print "\t -b <baudrate> \t\t Baudrate is %d" % bps
    print "\t -F <freq> \t\t Tune the radio to <freq> MHz."
    print "\t -M <modul> \t\t Set modulation."
    print "\t -S <open/closed/auto> \t Set squelch / monitor."
    print "\t -L <squelch> \t\t Set LEVEL squelch to between 0 and 255."
    print "\t -A <squelch> \t\t Set AUDIO squelch to between 0 and 255."
    print "\t --1vfo \t\t Set 1-VFO mode."
    print "\t --vfo=<a/b> \t\t Select active VFO."
    print "\t --squelch \t\t Get the radio squelch settings"
    print "\t --s-meter \t\t Get S-meter reading"
    print "\t --attenuator=<on/off> \t Enable / disable attenuator."
    print "\t --nl=<on/off> \t\t Enable / disable noise limiter."
    print "\t --search=<f1:f2> \t VFO-search between f1 and f2."
    print "\t --lc \t\t\t Live monitoring of the radio for signal."
    print "\t --status \t\t Report some status parameters of the radio."
    print "\t --delete-pass \t\t Delete VFO pass frequencies."
    print "\t --add-pass <freq> \t Add VFO pass frequency"
    print "\t --off \t\t\t Turn radio OFF"

#############
# Main
###
reqs = []

try:
    opts, extra = getopt.getopt(sys.argv[1:],
                                "dp:b:F:M:L:A:S:",
                                ["off", "squelch", "s-meter", "attenuator=",
                                 "status", "nl=", "search=", "vfo=", "1vfo",
                                 "lc", "delete-pass", "add-pass="])
except getopt.GetoptError:
    usage()
    sys.exit(-1)

for o in opts:
    if o[0] == "-p":
        port = o[1]
    elif o[0] == "-b":
        bps = int(o[1])
    elif o[0] == "-d":
        debug = True
    else:
        reqs.append(o)

ser = connect()

# Process the requests in the
for r in reqs:
    do_request(ser, r[0], r[1])

disconnect(ser)
