#!   /usr/bin/env   python
#    coding: utf8

# Copyright CERN, 2011
# Author: Marek Guminski<marek.guminski@creotech.pl>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org

# Import system modules
import sys
import time
import os
import struct

import utilities as util
TOPDIRNAME=util.TOPDIRNAME
abspath = util.find_prj_topdir(TOPDIRNAME);


# helper libraries
import numpy 
# import matplotlib.pyplot as plt
import shutil
import psutil
import subprocess
# Import specific modules

sys.path.append(abspath+util.fmcmasterfip_commonpath)
sys.path.append(abspath+util.fmcmasterfip_regspath)
# sys.path.append('regs')
import onewire as ow
import ds18b20 
import spi as ospi
import wbslave
import eeprom_24aa64
import i2c

# useful functions


# addressing
import masterfip_csr;
import masterfip_pts_csr;
import carrier_addrtable;




"""
FMC masterFIP class
"""

class adc_conf:
    def __init__(self):
        self.samples_before     = 256;
        self.samples_after      = 0xffff; 
        self.trigger_channel    = 1;
        self.trigger_threshold  = 2048;
        self.undersampling      = 1;
        self.output_file        = "/tmp/data.bin";
        self.output_img        = "/tmp/image.png";
        
    

class fmcmasterfip:

    
    EEPROM_ADDR                 = 0x50
    
    # Carrier specific components
    #------------------------------------

    # Masterfip core registers
    MASTERFIP_CORE_ADDR         = 0x00010000

    # # Masterfip PTS core registers
    # MASTERFIP_CORE_PTS          = 0x00011000

    # Carrier CSR address
    CARRIER_CSR_ADDR            = 0x00011000

    # MasterFIP FMC eeprom
    MASTERFIP_I2C_EEPROM_ADDR   = 0x00012000
    
    # MasterFIP FMC eeprom
    MASTERFIP_PTS_CSR_ADDR      = 0x00013000

    freq_options    = [ 31250, 1e6, 25e5, 5e6 ]

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


    def __init__(self, carrier, topdirpath, firmware = None ):
        
        ###################################################################
        ###################### module initialization ####################
        ###################################################################
        self.carrier        = carrier;
        self.firmware       = firmware;
        self.topdirpath     = topdirpath;
        
        ###################################################################
        ###################### firmware update ####################
        ###################################################################
        self.load_firmware( )


        ###################################################################
        #################### interfaces initialization ####################
        ###################################################################
        
        # creation of interfaces to modules controlling external devices
        self.fmc_sys_i2c    = i2c.COpenCoresI2C(self.carrier, self.MASTERFIP_I2C_EEPROM_ADDR, 199)
        self.fmc_eeprom_24aa64  = eeprom_24aa64.C24AA64(self.fmc_sys_i2c, self.EEPROM_ADDR)

        # creation of interfaces to modules controlling main functionality
        self.fipcore        = wbslave.wbslave(carrier, self.MASTERFIP_CORE_ADDR, masterfip_csr.addr)
        self.carrier_csr    = wbslave.wbslave(carrier, self.CARRIER_CSR_ADDR, carrier_addrtable.addr)
        self.fippts         = wbslave.wbslave(carrier, self.MASTERFIP_PTS_CSR_ADDR, masterfip_pts_csr.addr)
        
                ###################################################################
        ###################### firmware initialization ####################
        ###################################################################
        self.verify_bitstream_type();
        self.verify_carrier_status();
        
        self.rst_core()
        time.sleep(0.5)
        
        
        ###################################################################
        ################# ADC interrupt initialization ####################
        ###################################################################
        #should be done by ADC driver, but for some reason its not
        self.carrier.write( 0x01404,1 )
        self.carrier.write( 0x21504,1 )
        
#         Make sure that serial data output is enabled
        self.fipcore.write_regname('test',0)
        
        self.busfreq = self.get_bus_freq()
        
    # Returns FMC unique ID
    def get_unique_id(self):
        tmp = self.fipcore.read_regname("ds1820_id_msb") << 32;
        tmp |= self.fipcore.read_regname("ds1820_id_lsb");
        return tmp;

    # Returns FMC temperature
    def get_temp(self):
        return (self.fipcore.read_regname("ds1820_temper")/16);
    
    # write to EEPROM on system i2c bus
    def sys_i2c_eeprom_write(self, addr, data):
        return self.fmc_eeprom_24aa64.wr_data(addr, data)

    # read from  EEPROM on system i2c bus
    def sys_i2c_eeprom_read(self, addr, size):
        return self.fmc_eeprom_24aa64.rd_data(addr, size)
    
            
    def load_firmware(self):
        self.carrier.program(self.firmware);
    
    def set_firmware_path(self, firmware):
        self.firmware = firmware;

        
        
        
###############################################################################################
    def verify_carrier_status(self):
        if ( self.carrier_csr.read_regname("stat.fmc_pres") ):
            util.crit_msg("FMC slot NOT populated");
        else:
            util.info_msg("FMC slot populated");

        if ( self.carrier_csr.read_regname("stat.p2l_pll_lck") ):
            util.info_msg("GN4142 core PLL locked");
        else:
            util.crit_msg("GN4142 core PLL NOT locked");
        
        if ( self.carrier_csr.read_regname("stat.sys_pll_lck") ):
            util.info_msg("System PLL locked");
        else:
            util.crit_msg("System PLL NOT locked");
        


    # Read bitstream type
    def verify_bitstream_type(self):
        
        # read carrier status register 
        tmp = self.carrier_csr.read_regname("carrier");
        if( tmp == 0xFFFFFFFF):
            util.crit_msg( "No access to masterfip core" )
            
        elif( tmp != 0x10003):
            util.crit_msg( "Wrong bitstream type loaded 0x%8X" % tmp )
            
        else:
            util.info_msg( "Access to masterfip core OK 0x%8X" % tmp )
            
        return True 


###############################################################################################
    # Reset the masterFIP core
    def rst_core(self):
#         self.send_id_dat(0x7F14)
        self.fipcore.write_regname('tx_ctrl', 0 )
        time.sleep(0.01)
        
        self.fipcore.write_regname('rst.core', 1)
        time.sleep(1)

        self.fippts.write_regname('rst.core', 1)
    
    def rst_fd(self):
        self.fipcore.write_regname('rst.fd', 1)
        time.sleep(1)


    # Read masterFIP ID
    def read_masterfip_id(self):
        util.info_msg( "ID byte: 0x%08X"%(self.fipcore.read_regname('id')) )

    # Read WorldFIP speed    
    def read_speed(self):
        util.info_msg("Speed  : 0x%08X"%(self.fipcore.read_regname('speed')) )

    def get_bus_freq(self):
        return self.freq_options[ self.fipcore.read_regname('speed') ]


    # Send ID_DAT    
    def send_id_dat(self, varid):
        
        self.fipcore.write_regname('tx_ctrl', 1)
        self.fipcore.write_regname('tx_ctrl', 0)
        self.fipcore.write_regname('tx_payld_ctrl', 0x3)
        self.fipcore.write_regname('tx_payld_reg1', varid)
        self.fipcore.write_regname('tx_ctrl', 0x202)
    
    
    # Read RP_DAT
    def read_rp_dat(self):
        
        rx_stat      = self.fipcore.read_regname('rx_stat')
        rx_data_ctrl = self.fipcore.read_regname('rx_payld_ctrl')
        rx_data_reg1 = self.fipcore.read_regname('rx_payld_reg1')
        rx_data_reg2 = self.fipcore.read_regname('rx_payld_reg2')
        rx_data_reg3 = self.fipcore.read_regname('rx_payld_reg3')
        rx_data     = rx_data_reg3 << 32*2 | rx_data_reg2 << 32*1 | rx_data_reg1 << 32*0 
        return [ rx_stat, rx_data_ctrl, rx_data ]
