

import sys
import random
import time
import csr
import i2c
import math
import os
import signal

from ctypes import *
from ptsexcept import *

from regs_lib import *
from ad9510_lib import *



RF_MODE_MASTER = 0;
RF_MODE_SLAVE = 1;


class spec:

    speclib_path = '/../software/spec-sw/tools/libspec.so';
    rflib_path = '/../software/rf-lib.so';
    BASE_ADDR = 0x80000;
    UIDEL = 1;
    SDB_SIG = 0x5344422D;
    GW_ID = 0xd00bb11d;
 
    
    def __init__(self, firmware, bus = -1, allwaysload = True):
        
        self.cwd = os.path.dirname(__file__)
        
        self.bus = bus;
        self.firmware = firmware;
        
        self.speclib = CDLL(self.cwd + self.speclib_path);
        self.rflib = CDLL(self.cwd + self.rflib_path);
        self.speclib.spec_readl.restype = c_uint32;
        
        print  "Initialising SPEC board..." 
        self.card = self.speclib.spec_open( c_int(self.bus), c_int(-1) );
        if(self.card < 1):
            raise PtsCritical("SPEC enumeration failed");
        
        
        self.gwid = self.readl(DDS_REG_GW);   
        if (self.gwid != self.GW_ID ):
            load = True;
        else:
            load = False;
            
        if allwaysload or load:
            print "Firmware loading"
            if( self.speclib.spec_load_bitstream(c_void_p( self.card ), c_char_p( self.cwd + self.firmware ) ) == 0 ):
                raise PtsCritical("Firmware loader failure");
            
        time.sleep(5);
        
              
        self.sdbid = self.speclib.spec_readl( c_void_p(self.card), c_uint32(0) );
        self.gwid = self.readl(DDS_REG_GW);
        self.get_fmc_present();
        
#         Set SPI/I2C pins to inactive state
        self.writel( DDS_REG_CR, 0);
        self.gpio_set( DDS_GPIOR_PLL_SYS_RESET_N(), 1);
        self.gpio_set( DDS_GPIOR_PLL_SYS_CS_N(), 1);
        self.gpio_set( DDS_GPIOR_PLL_VCXO_CS_N(), 1);
        self.gpio_set( DDS_GPIOR_PLL_VCXO_FUNCTION(), 1);
#         self.dds.update_hw();
        self.gpio_set(DDS_GPIOR_ADF_LE(), 1);
        
        # set control voltage on middle value
        self.writel(DDS_REG_OSCDAC, 0x00ff );
        self.writel(DDS_REG_OSCDAC, 0x00ff | ( 1<<16) );
        time.sleep(0.01)
        self.writel(DDS_REG_OSCDAC, 0x00ff );
        time.sleep(0.01)
    
        
    def ledr(self, val):
        tmp = self.readl(DDS_REG_TEST_COMM )
        if( val == 1 ):
            tmp |= DDS_TEST_COMM_LED_R();
        else: 
            tmp &= ~ DDS_TEST_COMM_LED_R();
        self.writel(DDS_REG_TEST_COMM, tmp )
    
    def ledg(self, val):
        tmp = self.readl(DDS_REG_TEST_COMM )
        if( val == 1 ):
            tmp |= DDS_TEST_COMM_LED_G();
        else: 
            tmp &= ~ DDS_TEST_COMM_LED_G();
        self.writel(DDS_REG_TEST_COMM, tmp )
    
    
    def get_fmc_present(self):
#         fmcpresent is pulled low on FMC board
#         the same line is pulled high on spec
#         if line is low then fmc must be connected 
        self.fmc_present = False if ( self.readl(DDS_REG_GPIOR) & DDS_GPIOR_FMC_PRESENT() ) else True;
     
    
#     SPI communication        
    def spi_txrx(self, cs_pin, nbits, value ):
#         10 us
        DEL = 0.00001
        
        time.sleep(DEL)
        self.gpio_set(DDS_GPIOR_PLL_SCLK(), 0)
        time.sleep(DEL)
        self.gpio_set(cs_pin, 0)
        time.sleep(DEL)
        self.gpio_set(DDS_GPIOR_PLL_SCLK(), 0)
        
        rv = 0
        
        for i in range(nbits):
            value <<= 1;
            self.gpio_set(DDS_GPIOR_PLL_SDIO(), value & (1<<nbits));
            time.sleep(DEL)
            self.gpio_set(DDS_GPIOR_PLL_SCLK(), 1);
            time.sleep(DEL)
            rv <<= 1;
            rv |= 1 if self.gpio_get(DDS_GPIOR_PLL_SDIO()) else 0
            time.sleep(DEL)
            self.gpio_set(DDS_GPIOR_PLL_SCLK(), 0);
            time.sleep(DEL)
            
        self.gpio_set( cs_pin, 1);

        return rv


######################## LOWEST LEVEL FUNCTIONS ####################################
    
    def write_eeprom_from_file(self, filename,  offset):
        print filename
        return self.rflib.write_eeprom_from_file(c_void_p(self.card), c_char_p(filename), c_ulong(offset) );
    
    def gpio_set(self, pin, val ):
        # set value on single gpio pin
        curr = self.readl(DDS_REG_GPIOR)
        if( val ):
            self.writel(DDS_REG_GPIOR, pin|curr)
        else:
            self.writel(DDS_REG_GPIOR, curr&(~ pin) )
        
            
    def gpio_get(self, pin):
        # get current value of gpio pin
        return self.readl(DDS_REG_GPIOR) & pin;


    def writel(self, addr, data ):
#         basic write function from speclib
#   void spec_writel(void *card, uint32_t data, uint32_t addr)        
        self.speclib.spec_writel( c_void_p(self.card), c_uint32(data), c_uint32(self.BASE_ADDR + addr) );
    
    def readl(self, addr ):
#         basic read function from speclib
#         uint32_t spec_readl(void *card, uint32_t addr)
        return self.speclib.spec_readl( c_void_p(self.card), c_uint32(self.BASE_ADDR + addr) );
    
        