#!/usr/bin/python
#===============================================================================
# CERN (BE-CO-HT)
# Pulse test script
#===============================================================================
# author: Denia Bouhired(t.stana@cern.ch)
#
# date of creation:
#
# version: 1.0
#
# description:
# This script is used during manual upgrade of conv-ttl boards.
# It is used to:
# - Scan barcode of board
# - Read hw version
# - Read gw version
# - Read unique temperature chip ID
# - Output information on log file
#
#===============================================================================
# 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
#===============================================================================

#===============================================================================
#  TODO: 
#===============================================================================


import sys
sys.path.append("../ei2c")	
import time
from ei2c import *
import ei2cdefine
import binascii
import re
import subprocess
import os
import traceback

##-------------------------------------------------------------------------------------------------
## 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("./men-on", shell=True, stdout=None, stderr=None)
    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("./men-off", shell=True, stdout=None, stderr=None)
    time.sleep(1)

##-------------------------------------------------------------------------------------------------
# Define registers memory address
IDREG = 0x00		# Board ID register
SRREG = 0x04		# Status register
UIDREGLS = 0xac		# 1-wire chip Unique ID - LSB
UIDREGMS = 0xb0		# 1-wire chip Unique ID - MSB

# Status register offsets
CSR_GWVERS_OFS     = 0
CSR_HWVERS_OFS     = 22

# Target version
gwvers_target = 4.1
gwvers_gold_target = 0.3

##-------------------------------------------------------------------------------------------------
## Method to check hardware and gateware version
##-------------------------------------------------------------------------------------------------
def gw_hw_version():
    hwvers = (testelma.read(slot, SRREG) & 0x0fc00000) >> CSR_HWVERS_OFS
    gwvers = (testelma.read(slot, SRREG) & 0xFF) >> CSR_GWVERS_OFS 
    
    #print ("maj is %d, min is %d" % int(hwvers >> 2), int(hwvers & 0x03))
    hwvers = int(hwvers >> 2)+float(hwvers & 0x03)/10
    gwvers = int(gwvers >> 4)+float(gwvers & 0xF)/10
    
    return hwvers, gwvers;

##-------------------------------------------------------------------------------------------------
## Main "method" of upgrade module
##-------------------------------------------------------------------------------------------------
if __name__ == "__main__":

	men_off()
        # Get the IP, user and password for the ELMA crate from ei2cdefine.py
        ip   = ei2cdefine.HNAME
        user = ei2cdefine.USER
	pwd  = ei2cdefine.PWD
	slot = ei2cdefine.SLOT
	testelma = EI2C(ip, user, pwd)
	testelma.open()
	while True:
	    
            print "=============================================\n"
	    ans = raw_input("Would you like to upgrade conv-ttl-xxx board (y/n): ")            
	    if (ans == "y"):
		upgrade = True
	    elif (ans == "n"): 
		upgrade = False
		break
	    else:
		print ("Wrong input !\n")
		sys.exit(1)

	    print ("Start conv-ttl-xxx gateware upgrade")
	    print "=============================================\n"
	    # Scan the barcode
	    while True:
		sn1 = raw_input("--> Scan the PCB 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    
	    
	    # 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-XXX board '%s' into the VME crate.\n    Then type 'ok': " % (sn1)
            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"
         
            print "=============================================\n"
 	    men_on()
            time.sleep(8)
	    # Get board ID and gateware version, fail if incorrect

	    bloid = testelma.read(slot, IDREG)



	    if ( bloid == 0x54424c4f ):
		     print("This is a CONV-TTL-BLO board \n ")
	             gwpath = "gw-blo"
	    elif ( bloid == 0x54343835):
		     print("This is a CONV-TTL-RS485 board \n ")
		     gwpath = "gw-rs485"
            else:
		     print("Wrong board ID (%s)" % binascii.unhexlify("%s" % \
			    "{0:x}".format(bloid)))
		     sys.exit(1)    

	    #Check that the board inserted is correct
	    while True:
		check = raw_input("--> Is this correct (y/n): ")	    
		if (check == "y"):
         	   print ("Current board information: \n")
                   break
	  	elif (check == "n"): 
	           print ("Wrong board inserted... Aborting ...")
		   sys.exit(1)
	    	else:
		   print ("Wrong input !\n")

	    (hwvers, gwvers) = gw_hw_version()
	    
	    if (hwvers == 0.0):
                print("Hardware version is (v3.0) or earlier\n" )
	    else:
        	print("Hardware version is (%2.1f)\n" % hwvers )
		  	
            print("Gateware version is (%2.1f)\n" % gwvers )

	    print "=============================================\n"

	    #Check whether upgrade is required
	    if (gwvers == gwvers_target):
		print("Board gateware already at latest version ... Nothing to do ...\n ")
		#print("Script Exiting ...")
		upgrade=False
	    else: 
		print("Gateware version does not match target ... Gateware will be upgraded ...\n")
	    
    

	    #ans = raw_input("Would you like to upgrade (y/n): ")
	    
	    #if (ans == "y"):
	#	upgrade = True
	    #elif (ans == "n"): 
	#	upgrade = False
	    #else:
		#print ("Wrong input !\n")
		#sys.exit(1)
	    
	    if (upgrade== True): 
	 	  	
	
		print "=============================================\n"
		print "Loading FPGA bitstream... \n"
		#ret = subprocess.call(["cd ./" + gwpath + "; ./flash;"], shell=True, stdout=None, stderr=None)	 
		ret = subprocess.call(["cd ./" + gwpath + "; xc3sprog -c xpc flash_load.bit; xc3sprog -c xpc -I golden-v" + str(gwvers_gold_target)+".bin:w:0:bin; xc3sprog -c xpc flash_load.bit; xc3sprog -c xpc -I release-v" + str(gwvers_target) +".bin:w:1507328:bin"], shell=True, stdout=None, stderr=None)	 
		print "Bitstream successfully loaded... \n"	 
		print "Crate restarting... \n"

		# Turn off the VME crate
		men_off()
		# Turn on the VME crate
		men_on()

	    	time.sleep(10)
		print "=============================================\n"

	        print ("Upgrade complete: \n")
	    (hwvers_new, gwvers_new) = gw_hw_version()	    
	    
            if (hwvers_new == 0.0):
                print("Hardware version is (v3.0) or earlier\n" )
	    else:
        	print("Hardware version is (%2.1f)\n" % hwvers_new )
            print("Gateware version is (%2.1f)\n" % gwvers_new )         
	    print "=============================================\n"
            #Read unique board ID
	    IDMS = testelma.read(slot, UIDREGMS) 
	    IDLS = testelma.read(slot, UIDREGLS)   
	    
	
	    #Generate log file
	    #subprocess.call("cd./log; chmod 777 log", shell=True, stdout=None, stderr=None)

	    # Generate output file named according to current time

	    fname = time.strftime("gw-upgrade-%Y-%m-%d", time.localtime()) + ".txt"
	    ret = subprocess.call(["ls ./log | grep " + fname], shell=True, stdout=None, stderr=None)
	    #print ("%d" % ret) 
	    if (ret != 0):
	    	f     = open("./log/" + fname, "w")
		print(" File not found ... Create new one \n ")
		f.write("\n")
		f.write("CONV-TTL-XXX Upgrade log created on %s \n" % time.strftime("%Y-%m-%d-%Hh%Mm%Ss", time.localtime()))
		
		f.write("--------------------------------------------------------------------------------- \n")
		f.write("* Target version is (v%2.1f)\n" % gwvers_target)
		f.write("* Hardware (v0.0) means board is (v3.0) or earlier \n")
		f.write("\n")
		f.write("--------------------------------------------------------------------------------- \n")
		f.write("Barcode | PCB ID | HW version | Old gw version | New gw version\n")
		f.write("--------------------------------------------------------------------------------- \n")
		f.close()

            print("Upgrade log can be found in ./log/%s \n" %  fname)
	    
	    f     = open("./log/" + fname, "a")
	    f.write("%s \t %d%d \t (%2.1f) \t (%2.1f) \t (%2.1f) \n" % (sn1, IDMS, IDLS, hwvers, gwvers, gwvers_new) )
	   
	    f.close()

	    men_off()
          
            #Remove board from crate
	    msg = "\n--> Remove the CONV-TTL-XXX board '%s' from the VME crate.\n    Then type 'ok': " % (sn1)
            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"
	    
	  

 
  
