#!/usr/bin/python -i

import sys
sys.ps1="IRENA-USB> "
sys.ps2="IRENA-USB. "

import usb

idevs = []

def findirena():
    global idevs, h
    idevs = []
    for bus in usb.busses():
        for dev in bus.devices:
            if dev.idVendor==0xffff and (dev.idProduct & 0xff00) == 0xee00:
                idevs.append(dev)
                
    print>>sys.stderr, len(idevs), "[EI]RENA devices found"
    for dev in idevs:
        for conf in dev.configurations:
            for intf in conf.interfaces:
                for alt in intf:
                    for ep in alt.endpoints:
                        print >>sys.stderr, dev.filename, conf.value, alt.interfaceNumber, alt.alternateSetting, "IO"[not (ep.address&0x80)], ep.address&0x7f, ep.type, ep.maxPacketSize

    for dev in idevs:
        try:
            h = dev.open()
            h.claimInterface(0)
            print >>sys.stderr, dev.filename, ", interface 0 claimed"
            break
        except:
            pass

verbosity = 1

def Boot(f="flash/IRENA.RBF"):
    altera_from_file(f)

def set_clock():
    from time import strftime,gmtime
    Cmd(strftime("clock %Y-%m-%d %H:%M:%S", gmtime()))

def cmd(c):
    if verbosity>2:
        sys.stderr.write("send: %s\n" % (c.strip()))
    h.bulkWrite(2, c, 100000)
    return resp()

def resp():
    r = "".join([chr(i) for i in h.bulkRead(0x82, 64,10000)]).strip('\0').strip()
    if verbosity>1:
        sys.stderr.write("rcvd: %s\n" % r)
    return r

def cmdn(r):
    try:
        return int(r[1:4]);
    except:
        pass
    return 0

def block_out(b):
    return h.bulkWrite(5, b, 1000)

import numpy
from numpy import array

def block_in(to=1000):
    return array(h.bulkRead(0x85, 512, to), "UInt8");

def stream_into_file(filename, count=0x800):
    f = open(filename, "w")
    while count>0:
        a = block_in(10000).tostring()
        f.write(a)
        count-=1
    f.close()

def fat_from_file(filename, erase=""):
    f = open(filename)
    count = 0x800
    wcount = 0
    sector = 0
    cmd("usb/discard")
    while count>0:
        a=numpy.fromstring(f.read(512), "UInt8")
        if (a.min()<0xff):
            block_out(a.tostring())
            r=cmd("usb/bcopy")
            if 262!=cmdn(r):
                print>>sys.stderr, r
                break
            r=cmd("flash/write %d %s" % (sector, erase))
            print>>sys.stderr, r
            if 234!=cmdn(r):
                break
            wcount += 1
        sector += 1
        count -=1
    f.close()
    cmd("file/mount")
    return wcount

def altera_from_file(filename):
    f = open(filename)
    print>>sys.stderr, cmd("altera/reset")
    while True:
        b = f.read(512)
        if len(b)<512:
            if not len(b):
                break;
            b+='\0'*(512-len(b))
        block_out(b)
        r=cmd("altera/usb")
        if cmdn(r)>500:
            print>>sys.stderr, r
            break
    print r

c=cmd

def messages(n=100):
    while (n):
        r=cmd("message");
        if (100==cmdn(r)):
            break
        print>>sys.stderr,r;
        n-=1

def flashbuffer():
    for a in range(0,0x200,16):
        r=cmd("flash/dump %d" % a);
        print>>sys.stderr,r;
        if cmdn(r)!=238:
            break

def directory(dir="/"):
    r=cmd("file/list '%s'" % dir);
    print >>sys.stderr, r
    while cmdn(r)!=220:
        r=cmd("file/list");
        print >>sys.stderr, r
        if cmdn(r)>500:
            break

def set_clock():
    from time import strftime,gmtime
    Cmd(strftime("clock %Y-%m-%d %H:%M:%S", gmtime()))

def hk2mvolt(ch="adc_Ibias"):
    r = cmd("var/print "+ch).split()[1]
    return 3300*(int(r)&0xffff)/0x10000;

def housekeeping():
    print >>sys.stderr, "dac  ", hk2mvolt("dac")
    print >>sys.stderr, "Ibias", hk2mvolt("adc_Ibias")
    print >>sys.stderr, "Ipcsa", hk2mvolt("adc_Ipcsa")
    print >>sys.stderr, "Imcsa", hk2mvolt("adc_Imcsa")
    print >>sys.stderr, "Ifet ", hk2mvolt("adc_Ifet")
    print >>sys.stderr, "dac  ", hk2mvolt("adc_dac")
    print >>sys.stderr, "Vprim", hk2mvolt("adc_Vprim")
    print >>sys.stderr, "Vbias", hk2mvolt("adc_Vbias")
    print >>sys.stderr, "Vfet ", hk2mvolt("adc_Vfet")
    print >>sys.stderr, "Vpcsa", hk2mvolt("adc_Vpcsa")
    print >>sys.stderr, "Vmcsa", hk2mvolt("adc_Vmcsa")


Dump = None
DoDump = None
DontDump = False
DumpData = ""
DumpDest = None

DumpBlocks = 0

def Start(f):
    global Dump, DoDump, DontDump, DumpDest, DumpBlocks
    if Dump:
        print >>sys.stderr, "Still writing to", repr(DumpDest)
        return
    import threading
    def func(f):
        global DoDump, DontDump, DumpData, DumpBlocks
        fn = False
        if isinstance(f, str):
            f = open(f, "a+")
            fn = True
        # else f better has a write() method
        while not DontDump:
            DoDump.wait()
	    if not DontDump:
                try:
                    s = block_in(5000).tostring()
                    f.write(s)
                    f.flush()
                    DumpData = s
                    DumpBlocks += 1
                except usb.USBError:
                    pass
	if fn:
            f.close()
    DumpBlocks = 0
    Dump = threading.Thread(target=func, args=(f,))
    Dump.setDaemon(True)
    DoDump = threading.Event()
    DontDump = False
    Dump.start()
    DoDump.set()
    DumpDest = f
    print >>sys.stderr, "Started writing data to", repr(DumpDest)

def Stop():
    global Dump, DoDump, DontDump
    DontDump = True
    if Dump != None:
        DoDump.set()
        Dump.join()
        print >>sys.stderr, "Stopped writing data to", repr(DumpDest)
        print >>sys.stderr, DumpBlocks, "blocks written"
    else:
        print >>sys.stderr, "No data output in progess"
    DoDump = None
    Dump = None

def Status():
    if Dump != None:
        print >>sys.stderr, "Writing data to", repr(DumpDest)
        print >>sys.stderr, DumpBlocks, "blocks written"
    else:
        print >>sys.stderr, "No data output in progess"

def Pause(yes=True):
    if yes:
        DoDump.clear()
    else:
        DoDump.set()

def reset(s="run/spi/fifos"):
    Cmd("direna/reset %s" % s)

def Cmd(c):
    print >>sys.stderr, c, ": ", cmd(c)

RFIFO = 0x8000  # Read a packet from a fifo
RNOOP = 0x8001  # Do nothing
SPIDE = 0x8002  # word to return for nothing
MSTAT = 0x8005
MSTAT_ERR    = 0x0001
MSTAT_FFULL  = 0x00f0
MSTAT_FEMPTY = 0x0f00
MSTAT_FPAKET = 0xf000
MSTAT_HK     = 0x1110
MSTAT_F1     = 0x2220
MSTAT_F2     = 0x4440
MSTAT_F3     = 0x8880
MERRC = 0x8006
MERRC_SPIOVFL = 0x0001
MERRC_FFULL   = 0x00f0
MERRC_FEMPTY = 0x0f00
MERRC_FPAKET = 0xf000
MRSTS = 0x8007
MRSTS_RUN    = 0x0001
MRSTS_CLOCK  = 0x0008
MRSTS_FIFO   = 0x00f0
MRSTS_SPI    = 0x0100
MCONF =0x800b
MCSET =0x800a
MCCLR =0x8009
MCONF_CLOCK   = 0x0008
MCONF_FIFO    = 0x00f0
MCONF_FIFO_DIS= 0x0100
MCONF_FEND_DIS= 0x0200
MCONF_CORE_DIS= 0x0400

MCLCK = 0x800c
MCLCK_L = MCLCK
MCLCK_H = MCLCK+3

WHK   = 0x8010
RHKS  = 0x8010
RF1S  = 0x8011
RF2S  = 0x8012
RF3S  = 0x8013
RHK   = 0x8014
RF1   = 0x8015
RF2   = 0x8016
RF3   = 0x8017
HKSZ  = 0x8018
HKMA  = 0x8019
HKHV  = 0x801a

def Areg(r, v=None, verb=True):
    if v==None:
        r = cmd("altera/reg %s" % str(r))
    else:
        r = cmd("altera/reg %s %s" % (str(r),str(v)))
    if verb:
        print >>sys.stderr, r
    if r[1:4]=="255":
        return int(r.split()[5],0)

def Async(w, verb=True):
    r = cmd("altera/sync %s" % str(w))
    if verb:
        print >>sys.stderr, r
    if r[1:4]=="256":
        return int(r.split()[4],0)

def Var(r, v=None, verb=True):
    if v==None:
        r = cmd("var/print %s" % str(r))
    else:
        r = cmd("var %s=0x%x" % (r,v))
    if verb:
        print >>sys.stderr, r
    if r[1:3]=="30":
        return int(r.split()[-1],0)

        
def FifoDump(n, fifo=RF1, verb=False):
    Async(0, verb=False)
    Async(RNOOP, verb=False)
    Async(fifo, verb=False)
    Async(RNOOP, verb=False)
    r = []
    for i in range(n):
        d = Async(RNOOP)
        r.append(d)
    return r

findirena()
