# -*- coding: utf-8 -*-
"""
state_decoder
=============

Module for decoding the internal state of the HP3562A DSA, using the
GPIB command "DSBN" (Dump State BiNary).

This file can be exectued as a python script. Use '-h' for more informations. 
"""

from HP3562A import format_header, decode_float, decode_string, decode_header, read_trace
from HP3562A.trace_decoder import decode_trace, HEADER as TRACE_HEADER
from HP3562A.enum_types import *

HEADER = [("Y coordinates", EYCOORD, 'h', 2),
          ("# of disp elements", int, "h", 2),
          ("First element", int, "h", 2),
          ("Total elements", int, 'h', 2),
          ("Display sampling", EDISPSMP, 'h', 2),
          ("Scaling", ESCAL, 'h', 2),
          ("Data pointer", long, 'l', 4),
          ("In data", long, 'l', 4),
          ("Log/linear x-axis", bool, 'h', 2),
          ("Sampled display data", bool, 'h', 2),
          ("Plot/Graph mode", bool, 'h', 2),
          ("Phase wrap", bool, 'h', 2),
          ("Not used", None, None, 36),
          ("X scale factor", decode_float, None, 4),
          ("Grid min Y scale", decode_float, None, 4),
          ("Grid max Y scale", decode_float, None, 4),
          ("/div", decode_float, None, 4),
          ("Min value of data", decode_float, None, 4),
          ("Max value of data", decode_float, None, 4),
          ("Y cumulative min", decode_float, None, 4),
          ("Y cumulative max", decode_float, None, 4),
          ("Y scale factor", decode_float, None, 4),
          ("Not used", None, None, 16),
          ("Stop value", decode_float, None, 8),
          ("Left grid", decode_float, None, 8),
          ("Right grid", decode_float, None, 8),
          ("Left data", decode_float, None, 8),
          ("Right data", decode_float, None, 8),          
    ]

def decode_coord(data):
    """
    Decode the data (as generated by the HP3562A DSA in response to a
    "DSBN" command), and returns a dict (header)

    header is the dictionnary of the header of the dumped data block,
    """
    header, idx = decode_header(data, HEADER)
    trace_header, idx = decode_header(data, TRACE_HEADER, idx)
    trace = read_trace(data, idx, trace_header["Number of elements"])
    return header, trace_header, trace
    

def main():
    import sys
    import optparse
    import numpy
    
    opt = optparse.OptionParser("A simple tool for displaying dumped coord data block")
    opt.add_option('-f', '--filename', default=None,
                   dest='filename',
                   help='Output filename. If not set, read from stdin')
    opt.add_option('-m', '--mode', default='binary',
                   dest='mode',
                   help='Dumping mode (may be "binary" [default], "ascii" or "ansi")',
                   )
    opt.add_option('-d', '--display-header', default=False,
                   action="store_true",
                   dest="displayheader",
                   help="Display the trace header")
    opt.add_option('-P', '--noplot-trace', default=True,
                   action="store_false",
                   dest="plot",
                   help="Do not display the plot of the trace")
    opt.add_option('-x', '--xmode', default='lin',
                   dest='xmode',
                   help='X coordinate mode (may be "lin" [default] or "log")')
    opt.add_option('-y', '--ymode', default='lin',
                   dest='ymode',
                   help='Y coordinate mode (may be "lin" [default], "log" or "db")')
    
    options, argv = opt.parse_args(sys.argv)


    if options.filename is None:
        print "Can't deal stdin for now..."
        sys.exit(1)
    try:
        coord_header, header, data = decode_coord(open(options.filename, 'rb').read())
    except Exception, e:
        print "ERROR: can't read %s an interpret it as a HP3562 trace"%options.filename
        print e
        sys.exit(1)

    if options.displayheader:
        print format_header(coord_header, HEADER, 100)
        print format_header(header, TRACE_HEADER, 100)
    if options.plot:
        f0 = header['Start freq value']
        dx = header['Delta X-axis']
        n = header['Number of elements']
        x = numpy.linspace(f0, f0+dx*n, len(data)) 
        y = data.copy()

        ym = coord_header['Min value of data']
        yM = coord_header['Max value of data']
        ys = coord_header['Y scale factor']
        
        y[y<ym] = ym
        y *= ys
        
        import pylab
        pylab.ylabel(header['Amplitude units'])
        pylab.grid()
        pylab.plot(x, y)
        pylab.xlabel('frequency (%s)'%header["X axis units"])
        pylab.ylabel("%s (%s)"%(coord_header['Y coordinates'], header['Amplitude units']) )
        pylab.show()
    
if __name__ == "__main__":
    main()
