#!/usr/bin/python
#===============================================================================
# CERN (BE-CO-HT)
# Register test for CONV-TTL-BLO
#===============================================================================
# author: Theodor Stana (t.stana@cern.ch)
#
# date of creation: 2013-08-13
#
# version: 1.0
#
# description:
#
#   This module runs the communication test by reading and writing to addresses
#   in a RAM on the CONV-TTL-BLO regtest gateware for the FPGA.
#
#   Without too much modification, it can be used in two modes:
#       - read and write address 0
#       - read and write the whole RAM
#
#   To select between one of two modes, you need to comment or uncomment the
#   proper code, as marked below.
#
#===============================================================================
# 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
#===============================================================================
# last changes:
#    2013-08-13    Theodor Stana     File created
#    2014-03-06    Theodor Stana     Added description above
#===============================================================================
#  TODO: -
#===============================================================================

import random
import sys
import time
sys.path.append("../ei2c")
from ei2c import *
import ei2cdefine


RAMSTART = 0x000
RAMEND   = 0xFFF

if __name__ == "__main__":

  # Get the IP, user and password for the ELMA crate from ei2cdefine.py
  ip   = ei2cdefine.HNAME
  user = ei2cdefine.USER
  pwd  = ei2cdefine.PWD
  testelma = EI2C(ip, user, pwd)
  testelma.open()

  # Ask for slot number
  while 1:
    try:
      slot = raw_input("Slot no.: ")
      slot = int(slot)
      break
    except TypeError as e:
      print("Please input a decimal slot number.")
    except SlotError as e:
      print(e.strerror)
    except KeyboardInterrupt:
      sys.exit();
    except:
      print("Unexpected error: ", sys.exc_info()[0])

  # Ask how long to run the test
  print "How long would you like to run the test?"
  while 1:
    try:
      hrs = raw_input("  hrs: ")
      hrs = int(hrs)
      if (hrs < 0):
        raise Exception
      break
    except KeyboardInterrupt:
      sys.exit()
    except:
      print "    Hours must be a decimal number >= 0!"

  while 1:
    try:
      mins = raw_input("  mins: ")
      mins = int(mins)
      if (mins < 0):
        raise Exception
      break
    except KeyboardInterrupt:
      sys.exit()
    except:
      print "    Minutes must be a decimal number >= 0!"

  while 1:
    try:
      secs = raw_input("  secs: ")
      secs = int(secs)
      if (secs < 0):
        raise Exception
      break
    except KeyboardInterrupt:
      sys.exit()
    except:
      print "    Seconds must be a decimal number >= 0!"

  # Compute test end time according to current time
  #
  # time.time() returns time since start of epoch
  # in seconds, so add secs, mins and hrs to that
  start_time = time.time()
  end_time  = start_time + secs + 60*mins + 3600*hrs

  # Generate output file named according to current time
  fname = time.strftime("c-%Y-%m-%d-%Hh%M", time.localtime()) + ".txt"
  f     = open(fname, "w")

  # Write current time and start of test to output file
  f.write("------------------------------------------------------------\r\n")
  f.write("Nr. slots: %d\n" % nrslots)
  f.write("Runtime: %d hrs, %d mins, %d s\n" % (hrs, mins, secs))
  f.write("------------------------------------------------------------\r\n")
  f.write("%s: starting test\r\n" % time.strftime("%Y-%m-%d-%Hh%Mm%Ss", time.localtime())) 
  print "%s: starting test" % time.strftime("%Y-%m-%d-%Hh%Mm%Ss", time.localtime())
  f.write("------------------------------------------------------------\r\n")

  # Open I2C connection
  testelma.open()

  # Init counters
  wexcep_cnt   = 0
  rexcep_cnt   = 0
  mismatch_cnt = 0

  br = 0
  # Run test loop for the specified time
  while time.time() < end_time:

    #--------------------------------------------------------------------------
    # Comment/uncomment here for accessing address 0
    #--------------------------------------------------------------------------
    if br:
      break

    addr = 0x000
    wval = 0x55443322

    for i in range(1, nrslots+1):
      if br:
        break

      try:
        testelma.write(i, addr, wval)
      except EI2CException as e:
        f.write("wex %i / %s / %s\r\n" % (i, time.strftime("%Y-%m-%d-%Hh%Mm%Ss",time.localtime()), e.strerror))
        wexcep_cnt += 1

      # Try a read from CONV-TTL-BLO, exception if unsuccessful
      try:
        rval = testelma.read(i, addr)
        #f.write("r:%x\r\n" % rval)

        # Check if read value is same as written value
        if rval != wval:
          mismatch_cnt += 1
          f.write("mis %i / %s / %03x : %08x != %08x\r\n" % (i, time.strftime("%Y-%m-%d-%Hh%Mm%Ss",time.localtime()), addr, wval, rval))
#          br = 1
#          break

      except EI2CException as e:
        f.write("rex %i / %s / %s\r\n" % (i, time.strftime("%Y-%m-%d-%Hh%Mm%Ss",time.localtime()), e.strerror))
        rexcep_cnt += 1

    #--------------------------------------------------------------------------
    # Comment/uncomment here for accessing the whole RAM
    #--------------------------------------------------------------------------
#    for i in range(1, nrslots+1):
#      if br:
#        break
#
#      # pull back address counter and go to next slot
#      addr = RAMSTART
#
#      while addr < RAMEND:
#
#        # Write the regaddress value to the register
#        wval = addr
#
#        #f.write("a:%x w:%x " % (addr, wval))
#
#        # Try a write to CONV-TTL-BLO, exception if unsuccessful
#        try:
#          testelma.write(i, addr, wval)
#        except EI2CException as e:
#          f.write("wex %i / %s / %s\r\n" % (i, time.strftime("%Y-%m-%d-%Hh%Mm%Ss",time.localtime()), e.strerror))
#          wexcep_cnt += 1
##          br = 1
##          break
#
#        # Try a read from CONV-TTL-BLO, exception if unsuccessful
#        try:
#          rval = testelma.read(i, addr)
#          #f.write("r:%x\r\n" % rval)
#
#          # Check if read value is same as written value
#          if rval != wval:
#            mismatch_cnt += 1
#            f.write("mis %i / %s / %03x : %08x != %08x\r\n" % (i, time.strftime("%Y-%m-%d-%Hh%Mm%Ss",time.localtime()), addr, wval, rval))
##            br = 1
##            break
#
#        except EI2CException as e:
#          f.write("rex %i / %s / %s\r\n" % (i, time.strftime("%Y-%m-%d-%Hh%Mm%Ss",time.localtime()), e.strerror))
#          rexcep_cnt += 1
##          br = 1
##          break
#
#        # Increment regaddr, reset on overflow above 2^12
#        addr += 4

  # Compute run time
  run_time = time.time() - start_time

  # Close I2C connection and print final values
  testelma.close()

  f.write("------------------------------------------------------------\r\n")
  f.write("%s: ending test\r\n" % time.strftime("%Y-%m-%d-%Hh%Mm%Ss", time.localtime()))
  print "%s: ending test" % time.strftime("%Y-%m-%d-%Hh%Mm%Ss", time.localtime())
  print "Ran for %d seconds" % run_time
  f.write("Ran for %d seconds\r\n" % run_time)
  f.write("------------------------------------------------------------\r\n")
  f.write("Write transactions: %d\r\n" % testelma.write_cnt)
  f.write("Write exceptions: %d\r\n\r\n" % wexcep_cnt)
  f.write("Read transactions: %d\r\n" % testelma.read_cnt)
  f.write("Read exceptions:  %d\r\n\r\n" % rexcep_cnt)
  f.write("R/W mismatches:   %d\r\n" % mismatch_cnt)
  f.write("------------------------------------------------------------\r\n")

  # Close output file
  f.close()

  # Print output file name
  print
  print "Test results can be found in " + fname
