##_______________________________________________________________________________________________
##
##                                      CONV-TTL-RS485 PTS
##
##                                         CERN,BE/CO-HT
##_______________________________________________________________________________________________
##
##-----------------------------------------------------------------------------------------------
##
##                                   CONV-TTL-RS485 flash test
##
##-----------------------------------------------------------------------------------------------
##
## Description  This test checks that the release and golden gatewares downloaded to the FPGA are
##              the proper version. A gateware download is performed by pts.py prior to this
##              script being run. This script is then run to check that the release gateware the
##              FPGA boots up to is the correct version. MultiBoot is then performed via the FPGA
##              gateware and the gateware version of the golden gateware is checked for
##              correctness.
##
##
## Authors      Julian Lewis (Julian.Lewis@cern.ch)
##              Theodor-Adrian Stana (t.stana@cern.ch)
## Website      http://www.ohwr.org/projects/pts
## Date         05/11/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 system modules
import sys
sys.path.append("log/")
import time
import os, errno, re, sys, struct
import os.path
import traceback
import glob
import binascii

# Import common modules
from ctypes import *
from ptsexcept import *
from vv_pts import *
from ptsdefine import *

##-------------------------------------------------------------------------------------------------
##                                             main                                              --
##-------------------------------------------------------------------------------------------------

def main(bus,tname,inf,log):

    """
    tests : Flash chip IC62
    uses  : golden-v0.0_release-v1.0.bin and flashtest.py
    """

    GWVERS_RELEASE = 1.0
    GWVERS_GOLDEN = 0.0

    # Set the precision of gateware versions based on the number of digits the
    # fractional part thereof has; this is done to avoid exceptions in the
    # printing to file below
    #
    # gwvers can be between 0.0 to 15.15 (four bits major, four bits minor)
    r = GWVERS_RELEASE - int(GWVERS_RELEASE)
    r *= 100
    r = int(r)
    pr = 1
    if (r < 20) and (r >= 10):
        pr = 2

    g = GWVERS_GOLDEN - int(GWVERS_GOLDEN)
    g *= 100
    g = int(g)
    pg = 1
    if (g < 20) and (g >= 10):
        pg = 2

    pel = PTS_ERROR_LOGGER(inf,log)

    try:

        # Get board ID and convert it to string
        bid = bus.vv_read(0x00)
        bid = binascii.unhexlify("%s" % "{0:x}".format(bid))

        # and now check if appropriate
        if (bid == "T485"):
            msg = "Board ID correct: %s\n" % bid
            inf.write(msg)
        else:
            msg = "ERROR: Board ID (%s) incorrect, check IC62" % bid
            pel.set(msg)

        # Get gateware version and convert it to major-minor float number
        gwvers = bus.vv_read(0x04) & 0xff
        maj = float(gwvers >> 4)
        min = float(gwvers & 0x0f)
        if min < 10:
            p = 1 # decimal precision for printing below
            min /= 10
        else:
            p = 2 # decimal precision for printing below
            min /= 100
        gwvers = maj + min

        # and now check if appropriate
        if (gwvers == GWVERS_RELEASE):
            msg = "Release gateware version correct: %2.*f\n" % (p, gwvers)
            inf.write(msg)
        else:
            msg = "ERROR: Release gateware version (%2.*f) incorrect - expected %2.*f" % (p, gwvers, pr, GWVERS_RELEASE)
            pel.set(msg)

        # Fall-back to golden addres by performing IPROG from wrong address
        print("Trying fallback to golden gateware...")
        bus.vv_write(0x108, 0x44 | (0x0b << 24))
        bus.vv_write(0x10c, 0x180000 | (0x0b << 24)) # release bitstream at 0x170000
        bus.vv_write(0x100, 0x10000)
        try:
            # This write will issue IPROG and an NACK, so we avoid the exception here
            bus.vv_write(0x100, 0x20000)
        except:
           pass

        # Try to read out gateware version and time out after 60 seconds
        t0 = time.time()
        t1 = t0 + 60
        while (1):
            try:
                if (time.time() >= t1):
                    msg = "ERROR: Timeout, fallback unsuccessful"
                    print msg
                    pel.set(msg)
                    break

                # Get board ID and convert it to string
                bid = bus.vv_read(0x00)
                bid = binascii.unhexlify("%s" % "{0:x}".format(bid))

                # and now check if appropriate
                if (bid == "T485"):
                    msg = "Board ID correct: %s\n" % bid
                    inf.write(msg)
                else:
                    msg = "ERROR: Board ID (%s) incorrect, check IC62" % bid
                    pel.set(msg)

                # Read gateware version after fall-back
                gwvers = bus.vv_read(0x04) & 0xff
                maj = float(gwvers >> 4)
                min = float(gwvers & 0x0f)
                if min < 10:
                    p = 1 # decimal precision for printing below
                    min /= 10
                else:
                    p = 2 # decimal precision for printing below
                    min /= 100
                gwvers = maj + min

                # and now check if appropriate
                if (gwvers == GWVERS_GOLDEN):
                    msg = "Golden gateware version correct: %2.*f\n" % (p, gwvers)
                    inf.write(msg)
                else:
                    msg = "ERROR: Golden gateware version (%2.*f) incorrect - expected %2.*f" % (p, gwvers, pg, GWVERS_GOLDEN)
                    pel.set(msg)

                # FPGA up from booting, end the loop
                break
            except BusException:
                continue

        return pel.get()

    except BusException, e:
        raise PtsError("SKT Exception: %s" % (e))

    except BusWarning, e:
        raise PtsError("SKT Warning: %s" % (e))

if __name__ == '__main__':

    bus = SKT(ELMASLOT)
    os.chdir("log")
    logname = glob.glob('*.log')
    infname = glob.glob('*.inf')
    log = open(logname[0],'a')
    inf = open(infname[0],'a')

    msg = "Run:1 Begin: test08"
    print msg
    log.write(msg + '\n')
    inf.write(msg + '\n')
    try:
        print main.__doc__
        ret = main(bus, 'test08', inf, log)
        if (ret == 0):
            msg = "PASS: test08"
            log.write(msg + '\n')
            inf.write(msg + '\n')
            print msg
        else:
            msg = "FAIL: test08->flashtest.py\n"
            log.write(msg + '\n')
            inf.write(msg + '\n')
            print msg
    except Exception as e:
        msg = "FAIL: test08->flashtest.py (%s)" % e
        log.write(msg + '\n')
        inf.write(msg + '\n')
        print msg

    msg = "Run:1 End: test08"
    print msg
    log.write(msg + '\n')
    inf.write(msg + '\n')

