#! /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

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

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: "))

# array storing frequencies and number of guaranteed pulses to pass
tests = (
    # {'freq': 4000, 'pulses': 10000},
    {'freq': 2000000, 'pulses': 2000000},
)



##############################################

# flags for possible causes of a missed pulse
MISS_FLIMIT = 1
MISS_WDOG   = 2

def missed_pulse(status, channel):
    """ Checks if pulse has been missed for given channel.

    :param status: PyConvTTLStatus object to be checked
    :param channel: Channel number (1-6)
    :returns: 0 if there were not any pulses missed
              MISS_FLIMIT if at least one pulse has been missed due to frequency limit error
              MISS_WDOG if at least one pulse has been missed due to frequency watchdog error
              Both flags (MISS_FLIMIT & MISS_WDOG) can be set at the same time
    """
    res = 0

    if channel < 1 or channel > 6:
        raise RuntimeException("Invalid channel %d" % channel)

    if(status.error_register & (1 << (1 + channel))):
        res |= MISS_FLIMIT

    if(status.error_register & (1 << (7 + channel))):
        res |= MISS_WDOG

    return res

##############################################

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

# display status
print(convttl.status)

# verify gateware and hardware number
# TODO uncomment
# if not convttl.status.hw_version.startswith('4'):
    # print("ERROR: Expected hardware version 4.x, but it is %s" % convttl.status.hw_version)
    # sys.exit(1)

if not convttl.status.gw_version.startswith('4'):
    print("ERROR: Expected gateware version 4.x, but it is %s" % convttl.status.gw_version)
    sys.exit(1)

# TODO verify if the dip switch is set correctly
if(convttl.status.switch[1]):
    #print("short")
    pass
else:
    #print("long")
    pass

for test in tests:
    old_counters = None
    pulses = test['pulses']
    freq = test['freq']

#############################################################################################

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

    # clear errors (including missed pulse flags)
    convttl.status.clear_errors_current()

    print("------")
    print("TEST: accept %d pulses at %d Hz" % (pulses, freq))
    print("Start the pulse burst generator (%d pulses)\n" % int(pulses))
    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(0, 6):
            if old_counters[ch][0] != 0 and old_counters[ch][1] != 0:
                print("WARNING: Both pulse counters are increasing, check if it is ok")

            pulse_count = max(old_counters[ch])

            # check if there were any pulses missed
            if missed_pulse(convttl.status, ch + 1):
                if(pulse_count <= pulses):
                    print("TEST FAILED: channel %d missed a pulse" % ch)
                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" % (pulses, freq))
                test_run = False
                break

#############################################################################################

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

    # clear errors (including missed pulse flags)
    convttl.status.clear_errors_current()

    print("------")
    print("TEST: reject pulses after repeating %d pulses at %d Hz" % (pulses, freq))
    print("Start the pulse burst generator (%d pulses)\n" % pulses * 2)
    print("Pulse counters:")

    test_run = True

    # 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(0, 6):
            if old_counters[ch][0] != 0 and old_counters[ch][1] != 0:
                print("WARNING: Both pulse counters are increasing, check if it is ok")

            pulse_count = max(old_counters[ch])

            # check if there were any pulses missed
            if missed_pulse(convttl.status, ch + 1):
                if(pulse_count <= pulses):
                    print("TEST FAILED: channel %d missed a pulse too early" % ch)
                else:
                    print("TEST PASSED: rejected %d pulse at channel %d" % (pulse_count, ch))

                test_run = False
                break

            if(pulse_count == pulses * 2):
                print("TEST FAILED: repeated %d pulses, none rejected" % (pulse_count))
                test_run = False
