#!   /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_addrtable;
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
    #------------------------------------
    # Carrier CSR address
    CARRIER_CSR_ADDR            = 0x00001200
    # Carrier One Wire
    CARR_ONEWIRE_ADDR           = 0x00001100

    CROSSBAR_MAIN               = 0x20000
    
    #------------------------------------
    # MasterFIP FMC address
    # eeprom
    MASTERFIP_I2C_EEPROM        = CROSSBAR_MAIN + 0x1000
    # ADC configuration
    MASTERFIP_SPI_ADC           = CROSSBAR_MAIN + 0x1100
    # SI570 configuration (not mount)
    MASTERFIP_I2C_SI570         = CROSSBAR_MAIN + 0x1200
    # ADC core registers
    MASTERFIP_CSR_ADC           = CROSSBAR_MAIN + 0x1300
    # Thermometer
    MASTERFIP_OW_THERM          = CROSSBAR_MAIN + 0x1400
    # Masterfip core registers
    MASTERFIP_CORE_ADDR         = CROSSBAR_MAIN + 0x8000

    SAMPLING_FREQ_ADDR_IN_BINARY_DATA = 72;

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

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


    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.carr_onewire   = ow.COpenCoresOneWire(self.carrier, self.CARR_ONEWIRE_ADDR, 199, 39) #for 40 MHz clock
        self.carr_ds18b20   = ds18b20.CDS18B20(self.carr_onewire, 0)
        
        
        self.fmc_onewire    = ow.COpenCoresOneWire(self.carrier, self.MASTERFIP_OW_THERM, 499, 99) #for 40 MHz clock
        self.fmc_ds18b20    = ds18b20.CDS18B20(self.fmc_onewire, 0)

        self.fmc_sys_i2c    = i2c.COpenCoresI2C(self.carrier, self.MASTERFIP_I2C_EEPROM, 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_addrtable.addr)
        self.carrier_csr    = wbslave.wbslave(carrier, self.CARRIER_CSR_ADDR, carrier_addrtable.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):
        return self.fmc_ds18b20.read_serial_number()

    # Returns FMC temperature
    def get_temp(self):
        serial_number = self.fmc_ds18b20.read_serial_number()
        if(serial_number == -1):
            return -1
        else:
            return self.fmc_ds18b20.read_temp(serial_number)
    
    # 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('rstn', 0xCAFE0003)
        time.sleep(0.5)
        self.fipcore.write_regname('rstn', 0xCAFE0000)
        time.sleep(0.5)
        self.fipcore.write_regname('rstn', 0xCAFE0003)
        time.sleep(1)
    
    def rst_fd(self):
        self.fipcore.write_regname('rstn', 0xCAFE0003)
        time.sleep(0.5)
        self.fipcore.write_regname('rstn', 0xCAFE0001)
        time.sleep(0.5)
        self.fipcore.write_regname('rstn', 0xCAFE0003)
        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):
        print self.fipcore.read_regname('speed')
        return self.freq_options[ self.fipcore.read_regname('speed') ]

     # Disable EXT_SYNC test pulse
    def disable_ext_sync_tst(self):
        self.fipcore.write_regname('ext_sync', 0)

    # 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_data_ctrl', 0x3)
        self.fipcore.write_regname('tx_data_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_data_ctrl')
        rx_data_reg1 = self.fipcore.read_regname('rx_data_reg1')
        rx_data_reg2 = self.fipcore.read_regname('rx_data_reg2')
        rx_data_reg3 = self.fipcore.read_regname('rx_data_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 ]
