#! /usr/bin/python
"""
Author: Maciej Suminski <maciej.suminski@cern.ch>
Copyright: CERN 2017
License: GPLv3

Tests CONV-TTL-BLO pulse rejection module.
"""

import os
import sys
import time

sys.path.append("../PyBECO")
from PyBECO.boards import PyConvTTL, PyConvTTLException
from PyBECO.fec import Elma, ElmaException

# crate credentials
sys.path.append("../ei2c")
import ei2cdefine as cfg

# settings
address = cfg.HNAME if cfg.ENABLED and cfg.HNAME else raw_input("Hostname: ")
user = cfg.USER if cfg.ENABLED and cfg.USER else raw_input("User: ")
password = cfg.PWD if cfg.ENABLED and cfg.PWD else raw_input("Password: ")
slot = int(input("Slot number: "))
cooldown_time = 20	# number seconds of cool down time between tests

elma = Elma(address, user, password)
convttl = PyConvTTL(slot, elma)

# display status
print(convttl.status)

# verify gateware and hardware number
if convttl.status.hw_version[0] != 4:
    print("ERROR: Expected hardware version 4.x, but it is %d.%d" % convttl.status.hw_version)
    # sys.exit(1) # TODO uncomment

if convttl.status.gw_version[0] != 4:
    print("ERROR: Expected gateware version 4.x, but it is %d.%d" % convttl.status.gw_version)
    sys.exit(1)

# selectt the test data set depending on the pulse duration switch
if(convttl.status.switch[1]):
    # short pulse
    print("Running short pulse tests")
    tests = (
        {'freq': 2000000,   'seconds': 1},
        {'freq': 1333333,   'seconds': 6.5},
        {'freq': 1000000,   'seconds': 10},
        {'freq':  800000,   'seconds': 26},
        {'freq':  666667,   'seconds': 36.6},
        {'freq':  571428.6, 'seconds': 120, 'continuous': True}
    )
else:
    # long pulse
    print("Running long pulse tests")
    tests = (
        {'freq':  104166.7, 'seconds': 1},
        {'freq':   92592.5, 'seconds': 3},
        {'freq':   83333.3, 'seconds': 6.5},
        {'freq':   75757.8, 'seconds': 10},
        {'freq':   69444.4, 'seconds': 20},
        {'freq':   55555.6, 'seconds': 60},
        {'freq':   52083.3, 'seconds': 120, 'continuous': True},
    )

# run tests
for test in tests:
    old_counters = None
    freq = test['freq']
    seconds = test['seconds']
    pulses = freq * seconds
    continuous = True if 'continuous' in test and test['continous'] else False

#############################################################################################
# test if the guaranteed number of pulses is repeated

    # clear counters
    for ch in range(1, 7):
        convttl.pulse_counter_set(ch, (0, 0))

    # clear errors (including missed pulse flags)
    convttl.error.clear()

    print("------")
    print("TEST: accept %d pulses at %d Hz (%f s)" % (pulses, freq, seconds))
    print("Start the pulse burst generator (%d pulses)" % int(pulses))
    print("	./pulsegen.py -c %d -f %F" % (pulses, freq))
    print("")
    print("Pulse counters:")

    test_run = True

    # test if all pulses pass through
    while(test_run):
        if(old_counters != convttl.pulse_counters):
            print(convttl.pulse_counters)

        old_counters = convttl.pulse_counters

        for ch in range(1, 7):
            pulse_missed_errors = (convttl.ERRORS_MASK_FLIM_MISSED(ch),
                    convttl.ERRORS_MASK_FWDG_MISSED(ch))

            if old_counters[ch - 1][0] != 0 and old_counters[ch - 1][1] != 0:
                print("WARNING: Both pulse counters are increasing, check if it is ok")

            pulse_count = max(old_counters[ch - 1])

            # check if there were any pulses missed
            if any(error in convttl.error for error in pulse_missed_errors):
                if(pulse_count <= pulses):
                    print("TEST FAILED: channel %d missed a pulse (%d)" % (ch, pulse_count))
                    sys.exit(2)
                test_run = False
                break

            # check if we have reached the number of guaranteed pulses
            if pulse_count >= pulses:
                print("TEST PASSED: repeated %d pulses at frequency %d" % (pulse_count, freq))
                test_run = False
                break

    print("waiting %d seconds of cool-down period" % cooldown_time)
    time.sleep(cooldown_time)

#############################################################################################
# test if pulses are rejected after the counter threshold has been reached

    if continuous:  # we cannot perform this test for frequencies that
        continue    # are meant to repeat pulses without rejecting any

    # clear counters
    for ch in range(1, 7):
        convttl.pulse_counter_set(ch, (0, 0))

    # clear errors (including missed pulse flags)
    convttl.error.clear()

    print("")
    print("------")
    print("")
    print("TEST: reject pulses after repeating %d pulses at %d Hz" % (pulses, freq))
    print("Start the pulse burst generator (%d pulses)" % (pulses * 2))
    print("	./pulsegen.py -c %d -f %F" % (pulses * 2, freq))
    print("")
    print("Pulse counters:")

    test_run = True
    passed = [False for _ in range(6)]  # passed test flags for each channel

    # test if pulses are rejected after a certain threshold
    while(test_run):

        if(old_counters != convttl.pulse_counters):
            print(convttl.pulse_counters)

        old_counters = convttl.pulse_counters

        for ch in range(1, 7):
            pulse_missed_errors = (convttl.ERRORS_MASK_FLIM_MISSED(ch), convttl.ERRORS_MASK_FWDG_MISSED(ch))

            if old_counters[ch - 1][0] != 0 and old_counters[ch - 1][1] != 0:
                print("WARNING: Both pulse counters are increasing, check if it is ok")

            pulse_count = max(old_counters[ch - 1])

            # check if there were any pulses missed
            if any(error in convttl.error for error in pulse_missed_errors):
                if(pulse_count <= pulses):
                    print("TEST FAILED: channel %d missed a pulse too early (%d)" % (ch, pulse_count))
                    sys.exit(2)
                elif not passed[ch - 1]:
                    print("TEST PASSED: rejected %d pulse at channel %d" % (pulse_count, ch))
                    passed[ch - 1] = True

            # even if the test was passed, wait for the end of current pulse burst
            if(pulse_count >= pulses * 2):
                if not any(error in convttl.error for error in pulse_missed_errors):
                    print("TEST FAILED: repeated %d pulses, none rejected" % (pulse_count))
                    sys.exit(2)
                test_run = False

    if any(passed):
        print("TEST PASSED")

    print("waiting %d seconds of cool-down period" % cooldown_time)
    time.sleep(cooldown_time)
