#!   /usr/bin/python
#    coding: utf8
##________________________________________________________________________________________________
##
##                                        CONV-TTL-RS485 PTS
##
##                                         CERN,BE/CO-HT
##________________________________________________________________________________________________
##
##------------------------------------------------------------------------------------------------
##
##                                  CONV-TTL-RS485 PTS main program
##
##------------------------------------------------------------------------------------------------
##
## Description  This is the main program of the PTS suite. It is the high-level program of the
##              suite, running scripts to turn the test system on and off and downloading bitfiles
##              to the DUT FPGA(s) before finally running the test programs. This latter part is
##              handled by JPTS (jpts.py), a Python program that cycles through the various tests
##              to be performed and writes results to log (.log) and info (.inf) files.
##
##              Each board has a barcode associated to it, which can be either read via a barcode
##              reader device, or manually input by the user from a keyboard. The barcode is used
##              as part of the output file names to identify a DUT board.
##
##              The program begins by asking for this barcode and downloading a bitstream to the
##              FPGA once the board has been plugged in. Then, JPTS gets called in an external
##              shell to run the tests defined for a board's PTS.
##
##              After the tests have finished running, the log and info files get stored to a USB
##              stick provided with the test system.
##
## Authors      Julian Lewis (Julian.Lewis@cern.ch)
##              Theodor Stana (t.stana@cern.ch)
## Website      http://www.ohwr.org/projects/conv-ttl-rs485
## Date         30/10/2014
##-------------------------------------------------------------------------------------------------
##
##-------------------------------------------------------------------------------------------------
##                               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
##-------------------------------------------------------------------------------------------------

##-------------------------------------------------------------------------------------------------
##                                            Import
##-------------------------------------------------------------------------------------------------

import sys
sys.path.append('.')
sys.path.append("pyts")

import time
import traceback
import os
import subprocess
import re

# Import ptsdefine module to avoid wrong `make's
from ptsdefine import *

##-------------------------------------------------------------------------------------------------
## Method to turn on the VME crate.
##-------------------------------------------------------------------------------------------------
## It calls the men-on script which sends the necessary SMTP commands to the ELMA crate to turn on
## power to the VME backplane.
##-------------------------------------------------------------------------------------------------
def men_on():
    print("Switching on the ELMA crate")
    subprocess.call("shell/men-on", shell=True, stdout=fnull, stderr=fnull)
    time.sleep(1)

##-------------------------------------------------------------------------------------------------
## Method to turn off the VME crate.
##-------------------------------------------------------------------------------------------------
## It calls the men-off script which sends the necessary SMTP commands to the ELMA crate to turn off
## power to the VME backplane.
##-------------------------------------------------------------------------------------------------
def men_off():
    print("Switching off the ELMA crate")
    subprocess.call("shell/men-off", shell=True, stdout=fnull, stderr=fnull)
    time.sleep(1)

##-------------------------------------------------------------------------------------------------
## Main "method" of PTS
##-------------------------------------------------------------------------------------------------
if __name__ == '__main__':

    print "\nHello and Welcome to the CONV-TTL-RS485 PTS!\n"

    # Open NULL File and turn the crate off
    fnull = open(os.devnull, "w")

    # Clear the log dir (if any) and (re-)create it to store log and info files
    subprocess.call("rm -rf ./log; mkdir log; chmod 777 log", shell=True, stdout=fnull, stderr=fnull)

    # Turn off the VME crate
    men_off()

    # Scan the first barcode
    while True:
        sn1 = raw_input("--> Scan the 1st barcode: ")
        if (not len(sn1)):
            sn1 = "0"
        m = re.search(r"[^a-z\-A-Z0-9_]+",sn1)
        if m:
            print "Bad character in barcode"
        else:
            break

    # Scan the second barcode
    while True:
        sn2 = raw_input("--> Scan the 2nd barcode: ")
        if len(sn2) > 2:
            m = re.search(r"[^a-z\-A-Z0-9_]+",sn2)
            if m:
                print "Bad character in barcode"
            else:
                break
        else:
            sn2 = "0"
            break

    # Ask the user to plug in the board, turn on the crate and call the script to download bitstream
    # to FPGA
    msg = "\n--> Plug the CONV-TTL-RS485 board '%s-%s' into the VME crate.\n    Then type 'ok': " % (sn1, sn2)
    ok = raw_input(msg)
    while True:
        if ok.find("ok") != -1 or ok.find("OK") != -1:
            break
        else:
            ok = raw_input("--> Please type 'ok' to continue: ")
    print "\n"

    men_on()

    print "Loading FPGA bitstream..."
    ret = subprocess.call("cd boot; ./program", shell=True, stdout=fnull, stderr=fnull)
    time.sleep(1)

    if (ret != 0):
        print "ERROR: Bitstream download fail. Check JTAG connectivity."
    else:
        # Run JPTS in another shell script; JPTS will handle running each of the test scripts
        cmd = "xterm -e ./jpts -s %s %s" % (sn1, sn2)
        print "Running tests :%s\n" % (cmd)
        subprocess.call(cmd, shell=True, stdout=fnull, stderr=fnull)
        ret = subprocess.call("grep FAIL log/*.log", shell=True, stdout=fnull, stderr=fnull)

        if (ret == 0):
            print "Errors in tests, not downloading release bitstream"
            print ""
        else:
            # After JPTS has finished, download release bitstream to EEPROM chip if none of the tests has failed
            print "Loading CONV-TTL-RS485 golden and release bitstream...\n"
            ret = subprocess.call("cd boot; ./flash", shell=True, stdout=fnull, stderr=fnull)
            if (ret != 0):
                print "ERROR: Bitstream download failed"
            else:
                time.sleep(1)

                # ... power-cycle the crate
                print "VME crate power-cycle..."
                men_off()
                time.sleep(5)
                men_on()

                time.sleep(10)

                # .. and run the flash test
                cmd = "xterm -e python ./flashtest.py"
                subprocess.call(cmd, shell=True, stdout=fnull, stderr=fnull)

        # After all testing has finished, grep the log files for PASS and FAIL messages and print the outcomes to the console
        subprocess.call("grep PASS log/*.log", shell=True, stdout=sys.stdout, stderr=sys.stderr)
        subprocess.call("grep FAIL log/*.log", shell=True, stdout=sys.stdout, stderr=sys.stderr)

        # Save results on USB key...
        print "\nSaving test results on USB key"
        try:
            subprocess.call("mkdir -p /media/pts/log", shell=True, stdout=sys.stdout, stderr=sys.stderr)
            subprocess.call("cp log/*.log /media/pts/log", shell=True, stdout=sys.stdout, stderr=sys.stderr)
            subprocess.call("cp log/*.inf /media/pts/log", shell=True, stdout=sys.stdout, stderr=sys.stderr)
        except e:
            print "ERROR: No access to USB key at /media/pts"
            print e

    # We're done, turn off the VME crate
    print "\nTesting completed!"
    men_off()

    # Finally, print anything that went wrong throughout the test programs by grepping the log and info files and
    # exit when the user desires.
    msg = "\n--> To see all the PTS errors, type 'ok': "
    ok = raw_input(msg)
    if ok.find("ok") != -1:
        subprocess.call("grep FAIL log/*.log", shell=True, stdout=sys.stdout, stderr=sys.stderr)
        subprocess.call("grep ERROR log/*.inf", shell=True, stdout=sys.stdout, stderr=sys.stderr)
        subprocess.call("grep WARNING log/*.inf", shell=True, stdout=sys.stdout, stderr=sys.stderr)
        print ""

    print "--> You may now unplug the CONV-TTL-RS485 board %s-%s\n" % (sn1, sn2)

    msg = "--> To exit PTS, type 'ok': "
    ok = raw_input(msg)
    while True:
        if ok.find("ok") != -1 or ok.find("OK") != -1:
            print "Exited PTS"
            time.sleep(1)
            sys.exit(1)
        else:
            ok = raw_input("--> To exit PTS, type 'ok': ")

