#!/usr/bin/python
#===============================================================================
# CERN (BE-CO-HT)
# Pulse test script
#===============================================================================
# author: Theodor Stana (t.stana@cern.ch)
#
# date of creation:
#
# version: 1.1
#
# description:
#   This script works in conjunction with the pulsetest (v15.15) FPGA gateware
#   and drives the pulse generators to generate pulses as per the user's desire.
#
#===============================================================================
# GNU LESSER GENERAL PUBLIC LICENSE
#===============================================================================
# This source file is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version. This source is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details. You should have
# received a copy of the GNU Lesser General Public License along with this
# source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
#===============================================================================
# last changes:
#    2014-07-02    Theodor Stana     Setting the frequency to 0 Hz does not
#                                    enable the channel
#===============================================================================
#  TODO: -
#===============================================================================
import time
import sys
import time
sys.path.append("../ei2c")
from ei2c import *
import ei2cdefine
import binascii

IDREG = 0x00
FWVREG = 0x04
C1IREG = 0x100
C1OREG = 0x104
C2IREG = 0x108
C2OREG = 0x10C
C3IREG = 0x110
C3OREG = 0x114
C4IREG = 0x118
C4OREG = 0x11C
C5IREG = 0x120
C5OREG = 0x124
C6IREG = 0x128
C6OREG = 0x12C
CNTRST = 0X130
CHENREG = 0x200
C1DELREG = 0x204
C2DELREG = 0x208
C3DELREG = 0x20C
C4DELREG = 0x210
C5DELREG = 0x214
C6DELREG = 0x218
C1WDTHREG = 0x21C
C2WDTHREG = 0x220
C3WDTHREG = 0x224
C4WDTHREG = 0x228
C5WDTHREG = 0x22C
C6WDTHREG = 0x230
C1FREQREG = 0x234
C2FREQREG = 0x238
C3FREQREG = 0x23C
C4FREQREG = 0x240
C5FREQREG = 0x244
C6FREQREG = 0x248

CTB_CLK_PER = 50*(10**(-9))
#CTB_CLK_PER = 8*(10**(-9))

MAXFREQ = 5000

if __name__ == "__main__":
    # Get the IP, user and password for the ELMA crate from ei2cdefine.py
    ip   = ei2cdefine.HNAME
    user = ei2cdefine.USER
    pwd  = ei2cdefine.PWD
    testelma = EI2C(ip, user, pwd)
    testelma.open()

    # Ask for slot number
    while 1:
        try:
            slot = raw_input("Slot no.: ")
            slot = int(slot)
            break
        except TypeError as e:
            print("Please input a decimal slot number.")
        except SlotError as e:
            print(e.strerror)
        except KeyboardInterrupt:
            sys.exit();
        except:
            print("Unexpected error: ", sys.exc_info()[0])

    # Get board ID and gateware version, fail if incorrect
    bloid = testelma.read(slot, 0x00)
    fwvers = testelma.read(slot, 0x04) & 0xFF

    if ( bloid != 0x54424c4f ):
        print("Wrong board ID (%s)" % binascii.unhexlify("%s" % \
            "{0:x}".format(bloid)))
        sys.exit(1)
    if ( fwvers != 0xff ):
        print("Wrong version number (0x%02x)" % fwvers)
        sys.exit(1)

    # Reset chan. counters
    testelma.write(slot, CHENREG, 0x00);
    testelma.write(slot, CNTRST, 1);
    testelma.write(slot, CNTRST, 0);

    # First, setup the channel enable variable
    chen = 0x00;

    # Setup channel output pulse widths to 1.2us
    testelma.write(slot, C1WDTHREG, 1.2*(10**(-6))/CTB_CLK_PER)
    testelma.write(slot, C2WDTHREG, 1.2*(10**(-6))/CTB_CLK_PER)
    testelma.write(slot, C3WDTHREG, 1.2*(10**(-6))/CTB_CLK_PER)
    testelma.write(slot, C4WDTHREG, 1.2*(10**(-6))/CTB_CLK_PER)
    testelma.write(slot, C5WDTHREG, 1.2*(10**(-6))/CTB_CLK_PER)
    testelma.write(slot, C6WDTHREG, 1.2*(10**(-6))/CTB_CLK_PER)

    # Setup channel delays and frequencies
    farr = [0,0,0,0,0,0]

    print("")

    freq = input("CH1 freq (Hz): ")
    if (freq == 0):
        print("  CH1 not enabled")
    else:
        chen |= (1 << 0)
        if (freq > MAXFREQ):
            freq = MAXFREQ
            print("  Automatically setting channel frequency to %d Hz" % MAXFREQ)
        farr[0] = freq
        freq = 1/(freq * CTB_CLK_PER)
        testelma.write(slot, C1FREQREG, int(freq))
        #print(freq)
        #print(hex(int(freq)))

    freq = input("CH2 freq (Hz): ")
    if (freq == 0):
        print("  CH2 not enabled")
    else:
        chen |= (1 << 1)
        if (freq > MAXFREQ):
            freq = MAXFREQ
            print("  Automatically setting channel frequency to %d Hz" % MAXFREQ)
        farr[1] = freq
        freq = 1/(freq * CTB_CLK_PER)
        testelma.write(slot, C2FREQREG, int(freq))
        #print(freq)
        #print(hex(int(freq)))

    freq = input("CH3 freq (Hz): ")
    if (freq == 0):
        print("  CH3 not enabled")
    else:
        chen |= (1 << 2)
        if (freq > MAXFREQ):
            freq = MAXFREQ
            print("  Automatically setting channel frequency to %d Hz" % MAXFREQ)
        farr[2] = freq
        freq = 1/(freq * CTB_CLK_PER)
        testelma.write(slot, C3FREQREG, int(freq))
        #print(freq)
        #print(hex(int(freq)))

    freq = input("CH4 freq (Hz): ")
    if (freq == 0):
        print("  CH4 not enabled")
    else:
        chen |= (1 << 3)
        if (freq > MAXFREQ):
            freq = MAXFREQ
            print("  Automatically setting channel frequency to %d Hz" % MAXFREQ)
        farr[3] = freq
        freq = 1/(freq * CTB_CLK_PER)
        testelma.write(slot, C4FREQREG, int(freq))
        #print(freq)
        #print(hex(int(freq)))

    freq = input("CH5 freq (Hz): ")
    if (freq == 0):
        print("  CH5 not enabled")
    else:
        chen |= (1 << 4);
        if (freq > MAXFREQ):
            freq = MAXFREQ
            print("  Automatically setting channel frequency to %d Hz" % MAXFREQ)
        farr[4] = freq
        freq = 1/(freq * CTB_CLK_PER)
        testelma.write(slot, C5FREQREG, int(freq))
        #print(freq)
        #print(hex(int(freq)))

    freq = input("CH6 freq (Hz): ")
    if (freq == 0):
        print("  CH6 not enabled")
    else:
        chen |= (1 << 5);
        if (freq > MAXFREQ):
            freq = MAXFREQ
            print("  Automatically setting channel frequency to %d Hz" % MAXFREQ)
        farr[5] = freq
        freq = 1/(freq * CTB_CLK_PER)
        testelma.write(slot, C6FREQREG, int(freq))
        #print(freq)
        #print(hex(int(freq)))

    # Ask how long to run the test
    print("")
    print("How long would you like to run the test?")
    while 1:
        try:
            hrs = raw_input("  hrs: ")
            hrs = int(hrs)
            if (hrs < 0):
                raise Exception
            break
        except KeyboardInterrupt:
            sys.exit()
        except:
            print("    Hours must be a decimal number >= 0!")

    while 1:
        try:
            mins = raw_input("  mins: ")
            mins = int(mins)
            if (mins < 0):
                raise Exception
            break
        except KeyboardInterrupt:
            sys.exit()
        except:
            print("    Minutes must be a decimal number >= 0!")

    while 1:
        try:
            secs = raw_input("  secs: ")
            secs = int(secs)
            if (secs < 0):
                raise Exception
            break
        except KeyboardInterrupt:
            sys.exit()
        except:
            print("    Seconds must be a decimal number >= 0!")

    # Compute test end time according to current time
    #
    # time.time() returns time since start of epoch
    # in seconds, so add secs, mins and hrs to that
    start_time = time.time()
    end_time = start_time + secs + 60*mins + 3600*hrs

    # Generate output file named according to current time
    fname = time.strftime("p-%Y-%m-%d-%Hh%M", time.localtime()) + ".txt"
    f     = open(fname, "w")

    # Write current time and start of test to output file
    f.write("------------------------------------------------------------\n")
    f.write("%s: starting test\n" % time.strftime("%Y-%m-%d-%Hh%Mm%Ss", time.localtime()))
    print("%s: starting test" % time.strftime("%Y-%m-%d-%Hh%Mm%Ss", time.localtime()))
    f.write("------------------------------------------------------------\n")

    # Enable the needed channels and start generating pulses
    testelma.write(slot, CHENREG, chen)

    # Run test loop for the specified time
    while time.time() < end_time:
        pass

    # Disable all channels
    while (testelma.read(slot, CHENREG) != 0x00):
        testelma.write(slot, CHENREG, 0x00)


    f.write("%s: ending test\n" % time.strftime("%Y-%m-%d-%Hh%Mm%Ss", time.localtime()))
    print("%s: ending test" % time.strftime("%Y-%m-%d-%Hh%Mm%Ss", time.localtime()))
    f.write("------------------------------------------------------------\n")
    secs = int(end_time - start_time)
    f.write("pulses sent and received:\n")

    # Read counter registers
    i = testelma.read(slot, C1IREG)
    o = testelma.read(slot, C1OREG)
    f.write("ch %d (f = %d) / i: %d / o: %d\n" % (1, farr[0], i, o))

    i = testelma.read(slot, C2IREG)
    o = testelma.read(slot, C2OREG)
    f.write("ch %d (f = %d) / i: %d / o: %d\n" % (2, farr[1], i, o))

    i = testelma.read(slot, C3IREG)
    o = testelma.read(slot, C3OREG)
    f.write("ch %d (f = %d) / i: %d / o: %d\n" % (3, farr[2], i, o))

    i = testelma.read(slot, C4IREG)
    o = testelma.read(slot, C4OREG)
    f.write("ch %d (f = %d) / i: %d / o: %d\n" % (4, farr[3], i, o))

    i = testelma.read(slot, C5IREG)
    o = testelma.read(slot, C5OREG)
    f.write("ch %d (f = %d) / i: %d / o: %d\n" % (5, farr[4], i, o))

    i = testelma.read(slot, C6IREG)
    o = testelma.read(slot, C6OREG)
    f.write("ch %d (f = %d) / i: %d / o: %d\n" % (6, farr[5], i, o))

    testelma.close()

    f.write("------------------------------------------------------------\n")

    # Close output file
    f.close()

    # Print output file name
    print("")
    print("Test results can be found in " + fname)

