"""This module difines a component used to carry the Digital Cross Correlator 
system out into ACS.

Classes
=======
DigitalXCorrelator: ACS component used to communicate with
an FPGA system that performs a digital cross-correlation.

Exceptions
==========
The DigitalXCorrelator component raises the following exceptions:

- `ComponentErrorsImpl`: 
    
    * CouldntGetAttributeExImpl: raised when an error occured retrieving attributes 
      from CDB.
    * FileIOErrorExImpl: raised when an error occured writing output file.

- `ACSErrTypeFPGAConnectionImpl`: raised when the connection to FPGA failed
- `ACSErrTypeFPGACommunicationImpl`: raised when an error occured during 
   communication with FPGA

Authors
=======

Digital Cross Correlator System Designers
-----------------------------------------
Giampaolo Serra, gserra@oa-cagliari.inaf.it
Giovanni Busonera, giovannibusonera@gmail.com

ACS Component
-------------
Author: Marco Buttu, mbuttu@oa-cagliari.inaf.it
Last Modified: Thu Sep 24 10:51:30 CEST 2009
"""
import DXC__POA
from Acspy.Servants.ContainerServices import ContainerServices
from Acspy.Servants.ComponentLifecycle import ComponentLifecycle
from Acspy.Servants.ACSComponent import ACSComponent
from Acspy.Common.CDBAccess import CDBaccess
import ACSErrTypeFPGAConnectionImpl
import ACSErrTypeFPGACommunicationImpl
import ComponentErrorsImpl
import Acspy.Util.ACSCorba



import datetime
from math import *
import corr2serial # The Giovanni's module defines an high level API to communicate with FPGA

__docformat__ = 'restructuredtext'

# A list of ordered keys of full_res dictionary in save_coeff method
ordered_key_list = ['x_2', 'y_2', 'y90_2', 'xy', 'xy90']#, 'real', 'imm', 'module', 'phase']

class DigitalXCorrelator(DXC__POA.DigitalXCorrelator, ACSComponent, ContainerServices, ComponentLifecycle):
    """The DigitalXCorrelator ACS component uses the serial port to communicate with
    an FPGA system that perform a digital cross-correlation.
    That system was designed by Giampaolo Serra (INAF, Cagliari) and Giovanni Busonera (CRS4).

    Methods
    =======

    - `__init__`: constructor.
    - `initialize`: called by manager, initializes the component.
    - `cleanUp`: called by manager, releases the component.
    - `save_coeff`: saves to file the cross-correlation coefficients. It take two arguments:
       the target antenna azimuth and elevation.

    Exceptions
    ==========

    - `ComponentErrorsImpl`: 
        
        * CouldntGetAttributeExImpl: raised when an error occured retrieving attributes 
          from CDB.
        * FileIOErrorExImpl: raised when an error occured writing output file.

    - `ACSErrTypeFPGAConnectionImpl`: raised when the connection to FPGA failed
    - `ACSErrTypeFPGACommunicationImpl`: raised when an error occured during communication 
       with FPGA"""
   
    def __init__(self):
        ACSComponent.__init__(self)
        ContainerServices.__init__(self)
        self.corr = corr2serial.Correlator()
	self.name=ContainerServices.getName(self)

    def initialize(self):
        """Retrieve the CDB parameters."""
#        dal=Acspy.Util.ACSCorba.cdb()
         
	try:
#	    dao=dal.get_DAO_Servant("alma/%s" %self.name)
            print self.name
#	    self.port = int(dao.get_double("PORT"))
#            self.baudrate = int(dao.get_double("BAUDRATE"))
#            self.out_file_name = dao.get_string("OUT_FILE_FP")
#            self.max_attempts =int(dao.get_double("MAX_ATTEMPTS"))
            self.max_attempts =1

#	    self.samples==int(dao.get_double("SAMPLES"))
	    self.port=0
	    self.baudrate=115200
	    self.samples=25000000 
	    self.out_file_name="/home/almamgr/outfile"
	    
	
	
	except Exception, ex:
            self.getLogger().logError("Error... cannot get attributes from CDB. " + str(e))
            raise ComponentErrorsImpl.CouldntGetAttributeExImpl()
        
        # Connecting to FPGA module
        try:
            err = self.corr.connect(self.port, self.baudrate)

	    self.corr.set_samples(self.samples)
		    
        except Exception:
            self.getLogger().logDebug("Error in initialize: cannot connect to FPGA")
            self.getLogger().logError("Error... cannot connect to FPGA")
            raise ACSErrTypeFPGAConnectionImpl.CannotConnectExImpl()
        try:
            # Version 051:
            dt = datetime.datetime.now()
            file_id = "_%04d%02d%02d_%02d%02d" %(dt.year, dt.month, dt.day, dt.hour, dt.minute)
            self.out_file = open(self.out_file_name + file_id, 'a', 0)
            self.out_file.write("Azimuth".ljust(15) + "Elevation".ljust(15))
            for item in ordered_key_list:
                self.out_file.write(item.ljust(15))
            self.out_file.write("Timestamp".ljust(30))
            # End 051

            # self.out_file = open(out_file, 'w', 0) # V.05
        except IOError:
            self.getLogger().logDebug("Error in initialize: cannot create out_file")
            self.getLogger().logError("Error creating out_file")
            raise ComponentErrorsImpl.FileIOErrorExImpl()
	
    def cleanUp(self):
        self.corr.disconnect()
        self.out_file.close()

    def save_coord(self, azimuth, elevation):
	try:
	
		self.out_file.write("\n")
		self.out_file.write(("#%.4f" %azimuth).ljust(15))
 		self.out_file.write(("%.4f" %elevation).ljust(15))
		self.out_file.write(("%s" %datetime.datetime.now()).ljust(30))
		

	except IOError:
            self.getLogger().logError("Error writing out_file")
            raise ComponentErrorsImpl.FileIOErrorExImpl()


    def save_coeff(self, azimuth, elevation):
        """Write cross correlation coefficients to output file.

        Parameters
        ==========

        - `azimuth`: target antenna azimuth.
        - `elevation`: target antenna elevation.

        Exceptions
        ==========

        - `ComponentErrorsImpl.CouldntGetAttributeExImpl`: raised when an error occured 
           retrieving attributes from CDB.
        - `ComponentErrorrsImpl.FileIOErrorExImpl`: raised when an error occured writing 
           output file.
        - `ACSErrTypeFPGAConnectionImpl.CannotConnectExImpl`: raised when the connection 
           to FPGA failed.
        - `ACSErrTypeFPGACommunicationImpl.CannotRunExImpl`: raised when we cannot run 
           the correlation.
        - `ACSErrTypeFPGACommunicationImpl.CannotGetCoefficientsExImpl`: raised when we 
           cannot get the coefficients.
        """

        try:
            self.corr.disconnect()
            err = self.corr.connect(self.port, self.baudrate)
	    self.corr.set_samples(self.samples)

        except Exception:
            self.getLogger().logDebug("Error in save_coeff: cannot connect to FPGA")
            self.getLogger().logError("Error... cannot connect to FPGA")
            raise ACSErrTypeFPGAConnectionImpl.CannotConnectExImpl()

#       # Running Correlation
        try:
            err = self.corr.run()
        except Exception:
            self.getLogger().logError("Error running correlation.")
            raise ACSErrTypeFPGACommunicationImpl.CannotRunExImpl()

        i = 0
        while err and i < self.max_attempts:
            try:
                self.corr.disconnect()
                err = self.corr.connect(self.port, self.baudrate)
            except Exception:
                self.getLogger().logError("Error... cannot connect to FPGA")
                raise ACSErrTypeFPGAConnectionImpl.CannotConnectExImpl()

            i += 1
            self.getLogger().logInfo("Attempt %d failed. Retrying..." %i)
            self.corr.reset()
            err = self.corr.connect(self.port, self.baudrate)
            try:
                err = self.corr.run()    
		print "correlation done"
            except Exception:
                self.getLogger().logError("Error running correlation.")
                raise ACSErrTypeFPGACommunicationImpl.CannotRunExImpl()

        if err and i == self.max_attempts:
            self.getLogger().logError(
                    "Error... cannot get correlator coefficient in %d attempts" %self.max_attempts
            )
            self.corr.disconnect()
            raise ACSErrTypeFPGACommunicationImpl.CannotRunExImpl()

        # Getting coefficient    
        try:
            self.corr.getCoeff()
	    self.corr.reset()
	    
        except Exception:
            raise ACSErrTypeFPGACommunicationImpl.CannotGetCoefficientsExImpl()

#        module = sqrt(self.corr.get_real()**2 + self.corr.get_imm()**2) 
#        phase_tmp = atan2(self.corr.get_imm() ,  self.corr.get_real())
#        DPI= 2*pi
#	phase = (phase_tmp + DPI) % DPI         
        try:
            
#            full_res = self.corr.coeff.copy()
            full_res = self.corr.results.copy()
#            full_res.update({'module': module, 'phase': phase})
#            print full_res
            # Write values (V. 051)
            self.out_file.write("\n")
            self.out_file.write(("%.4f" %azimuth).ljust(15))
            self.out_file.write(("%.4f" %elevation).ljust(15))
            for item in ordered_key_list:
                self.out_file.write(("%.4f" %full_res[item]).ljust(15))
            self.out_file.write(("%s" %datetime.datetime.now()).ljust(30))
        except IOError:
            self.getLogger().logError("Error writing out_file")
            raise ComponentErrorsImpl.FileIOErrorExImpl()

