#! /usr/bin/env python
# -*- Encoding: utf-8 -*-

# Author: Laurent Le Guillou
# Intercalibration NIST/DKD


import sys, os, os.path
import subprocess
import getopt
import time
import numpy as np

import pyfits
import xmlrpclib
import struct

import dice.testbench.motor as dtm
import dice.testbench.multimeter.keithley6514 as multi
import dice.testbench.temperature.digisense as dttd
import dice.testbench.temperature.lakeshore325 as LK
import dice.testbench.monochromator.sp_dk240 as mono

# ---------------------------------------------------------

def temperature_measurements(f):
    # Measure DigiSense temperature 

    dg_temperature = DG.measure()
    print >>f, "# TEMP_DIGISENSE   %s  %s" % (str(time.time()),
                                              str(dg_temperature))
    f.flush()

    # Measure Lakeshore325 temperatures 

    lk_time = time.time()
    lk_temp_A = L.get_temperature("A")
    lk_temp_B = L.get_temperature("B")
    
    print >>f, "# TEMP_LAKESHORE_A   %s  %s" % (str(lk_time),
                                                str(lk_temp_A))
    print >>f, "# TEMP_LAKESHORE_B   %s  %s" % (str(lk_time),
                                                str(lk_temp_B))
    f.flush()

# --------------------------------------------------------------------------

def Keithley6514_initialize(K, Krange, samples):
    K.reset()
    K.write("CURR:RANG %s" % Krange) 
    K.write("FUNC 'CURR:DC'")
    K.write("SYST:ZCH OFF")
    # K.write("TRIG:COUN %d" % samples)
    K.write("TRIG:COUN 1")
    K.write(":SENS:CURR:NPLC 1") # 1 seems to be the default
    K.write(":DISP:ENAB OFF")

def Keithley6514_read(K, samples):
    result = []
    for i in xrange(samples):
        time.sleep(0.1)
        K.write("READ?")
        data_str = K.read()
        parts = data_str.split(',')
        # if (len(parts) != 3*samples):
        #     print >>sys.stderr, "No data. stop."
        #     return None
        values_str = parts[0::3]
        values = np.array([float(v) for v in values_str])
        result.append(list(values.flatten()))
    return np.array(result).flatten()

# --------------------------------------------------------------------------

lamp = "Unknown"
wlmin =  300.0 # nm
wlmax = 1000.0 # nm
step = 5.0 # nm
grating = 2
slit_width = 625 # microns
#slit_width = 200 # microns
#slit_width = 1000 # microns


NIST_range = '2e-6' # A
NIST_samples = 20

# --------------------------------------------------------------------------

for arg in sys.argv[1:]:
    print arg
    if '=' not in arg:
        print >>sys.stderr, "error: invalid argument [%s]" % arg
        sys.exit(2)
    eqparts = arg.split('=')
    print eqparts
    if len(eqparts) != 2:
        print >>sys.stderr, "error: invalid argument format [%s]" % arg
        sys.exit(3)
    
    param = eqparts[0]
    print param
    if param not in ['lamp', 'step', 'wlmin', 'wlmax', 'grating', 'slit_width', 'NIST_range', 'NIST_samples']: 
        print >>sys.stderr, "error: invalid parameter [%s]" % arg
        sys.exit(4)

    exec(arg)

# --------------------------------------------------------------------------
# output data file

filename = "spectrum-%s-%f.data" % (lamp, time.time())
datafile = open(filename, 'w')

# --------------------------------------------------------------------------
# Initialisation du banc (moteurs)

B = dtm.Bench()
B.open()
B.setup()
z=-1590.0 # mm
B.sensor_move_absolute("Z", z, unit="mm")

print >>datafile, "#-----------------------------------------------------"
print >>datafile, "# Bench zsensor = ", z

# --------------------------------------------------------------------------
# Initialisation du Keithley - NIST

NIST = multi.Multimeter('/dev/ttyS3')
NIST.open()
NIST.write("*IDN?")
NIST_id = NIST.read()

NIST.reset()
Keithley6514_initialize(NIST, NIST_range, NIST_samples)

# Position reference NIST
xnist =  152.5 # mm
ynist =  147.5 # mm

print >>datafile, "#-----------------------------------------------------"
print >>datafile, "# NIST multimeter = ", NIST_id
print >>datafile, "#    range =  ", NIST_range
print >>datafile, "#    samples =  ", NIST_samples
print >>datafile, "# NIST position = (", xnist, ", ", ynist, ")"


# --------- Init Monochromator SP DK240 ------------------------------------

M = mono.Monochromator(port = '/dev/ttyS4')
M.open()

# choose the slit width
in_width, out_width, other = M.get_slits()
if (in_width  != slit_width):
    M.set_entrance_slit(slit_width)
if (out_width != slit_width):
    M.set_exit_slit(slit_width)
in_width, out_width, other = M.get_slits()

print >>datafile, "#-----------------------------------------------------"
print >>datafile, "# Monochromator SP DK240 "
print >>datafile, "# Slit width = ", in_width, out_width

datafile.flush()

# --------- Init DigiSense Temperature monitor -----------------------------

DG = dttd.Temperature("/dev/ttyS0")
DG.open()

print >>datafile, "#-----------------------------------------------------"
print >>datafile, "# Temperature Monitor DIGISENSE "
print >>datafile, "# Ambient Temperature"
print >>datafile, "#-----------------------------------------------------"

# --------- Init LakeShore 325 ----------------------------

L = LK.LakeShore(port = "/dev/ttyUSB-pl2303-3")
L.open()

# A -> NIST support  / ambient
# B -> spectral lamp metallic support

print >>datafile, "#-----------------------------------------------------"
print >>datafile, "# Temperature Monitor LakeShore "
print >>datafile, "# A: Ambient Temperature / NIST"
print >>datafile, "# B: Lamp metallic support"
print >>datafile, "#-----------------------------------------------------"

# ==========================================================================

# ----------------------------------------------------------------------
# Choisir le réseau 

print "Selecting the grating %d..." % grating
ng, g, density, blaze = M.get_grating()
print ng, g, grating
if grating != g:
    M.set_grating(grating)
print "Done."

print >>datafile, "#     grating = ", grating

datafile.flush()


# ------------------------------------------------------------------
# Mettre la NIST dans le faisceau

B.sensor_move_absolute("X", xnist, unit="mm")
B.sensor_move_absolute("Y", ynist, unit="mm")
xsensor, ysensor, zsensor = B.sensor_position(unit="mm")
print >>datafile, "# NIST in beam (OFF)"
print >>datafile, "#     xsensor = ", xsensor
print >>datafile, "#     ysensor = ", ysensor
print >>datafile, "#     zsensor = ", zsensor

waverange = np.arange(wlmin, wlmax + step, step)

# ------------------------------------------------------------------
# Start spectra avec la NIST
print "Starting lambda scan... (NIST)"
print >>datafile, \
    "# time   grating  lambda(nm)   current(A)"

for wave in waverange:
    wave = float(wave) # for numpy strange types
    print "Setting the monochromator wavelength to ", wave
    w = M.get_wavelength()
    if abs(wave - w) > 0.01:
        M.set_wavelength(wave)

    w = M.get_wavelength()
         
    time.sleep(5)
    nist_on = Keithley6514_read(NIST, NIST_samples)
    nist_on_mean = nist_on.mean()
    nist_on_std  = nist_on.std()
    print "NIST current ON = ", \
        nist_on_mean, nist_on_std
    time.sleep(1)

    for value in nist_on:
        print >>datafile, \
            time.time(), grating, w, value


    temperature_measurements(datafile)

    datafile.flush()
        
# ==========================================================================

