#!/usr/bin/python
# Reference only: the beamline scientist's laser-delay script, attached to request 2.
# Kept verbatim (Python 2 era, CaChannel/epicsPV) as the behavioural spec for the BEC
# LaserDelay device. Do not import or run it from BEC code.

from CaChannel import ca, CaChannel
from epicsPV import epicsPV
from math import *
from numpy import *
import time

#Possible values of Laser: Duetto, KML, XITON, PI
Laser="Duetto"
Beamline="SuperXAS"
#LaserTriggerMode: "internal" or "external" External means from Event receiver.


LaserTriggerMode="external"

# Units of time are nanoseconds

#If internal triggering is used, set LaserPeriod (time between two laser pulses) as it is set at the laser
LaserPeriod=0
if (LaserTriggerMode=="internal"): LaserPeriod=2000.2


#Timing mode "DelayAndPhase" - use both Delay card and phase shifter, "Delay" - use only delay card, "Phase" - use only phase shifter
if (Laser=="Duetto"):
     TimingMode="DelayAndPhase"

#Index Of delay channel (as in EPICS name) used for laser
DelayChIndex=1
EVRChIndex=2

#For SuperXAS 1 corresponds to the old (KML) phase shifter
#For SuperXAS 2 corresponds to ES4 phase shifter
PhaseShifterIndex=2



#change only for another synchrotron
RFPeriod=2.0

DelayCh=CaChannel()
DelayChFine=CaChannel()
EVRCh=CaChannel()
PhaseV1=CaChannel()
PhaseV2=CaChannel()


def ConnectEpics():

	global CavityPeriod, Laser, Beamline
	global DelayCh, DelayChFine, EVRCh, PhaseV1, PhaseV2

	if (Laser=="Duetto"):
		CavityPeriod=12.01

	if (Beamline=="SuperXAS"):
		DN="X10DA-ES2-TIM:SET"+str(DelayChIndex)
		EVRChName="X10DA-ES2-TIM:EVR-FPS"+str(EVRChIndex)
		if (PhaseShifterIndex==1):
			PhaseV1Name="X10DA-LAS-PHSH:V1"
			PhaseV2Name="X10DA-LAS-PHSH:V2"
		if (PhaseShifterIndex==2):
			PhaseV1Name="X10DA-ES4:AO-02"
			PhaseV2Name="X10DA-ES4:AO-01"

	if (Beamline=="Phoenix"):
		DN="X07MB-ES-TIM:SET"+str(DelayChIndex)
		EVRChName="X07MB-ES-TIM:EVR-FPS"+str(EVRChIndex)
		PhaseV1Name="X07MB-ES1-PP2:VO2"
		PhaseV2Name="X07MB-ES1-PP2:VO1"

	DelayChName=DN+"-DELAY"
	DelayChFineName=DN+"-FINE"








	if ((TimingMode=="Delay") or (TimingMode=="DelayAndPhase")):
		DelayCh.searchw(DelayChName)
		DelayChFine.searchw(DelayChFineName)

	if ((TimingMode=="Phase") or (TimingMode=="DelayAndPhase")):
		PhaseV1.searchw(PhaseV1Name)
		PhaseV2.searchw(PhaseV2Name)

	if (LaserTriggerMode=="external"):
		EVRCh.searchw(EVRChName)

#Maybe will be useful to automatically set pulse width for different lasers
#def SetPulseWidth():


def CurrentSituation(FromScopeXrayMinusLaser):

	global LaserPeriod, OffsetT
	if (TimingMode=="Delay"):
		PhaseT=0
	if (TimingMode=="Phase"):
		DelayCardT=0

	if (LaserTriggerMode=="external"):
	    LaserPeriod=1000*EVRCh.getw()
	    print ("LaserPeriod=", LaserPeriod)

	if ((TimingMode=="Delay") or (TimingMode=="DelayAndPhase")):
		dt1=DelayCh.getw()
		dt2=DelayChFine.getw()
		DelayCardT=2.0*dt1+0.01*dt2



	if ((TimingMode=="Phase") or (TimingMode=="DelayAndPhase")):
		PhaseT=GetPhaseT()
		Ph=FromScopeXrayMinusLaser%CavityPeriod
		OffsetPhaseT=-PhaseT-Ph
	OffsetT=-DelayCardT-FromScopeXrayMinusLaser

	print ("LaserPeriod=", LaserPeriod)
	print ("OffsetT=", OffsetT)
	print ("Current PhaseT", PhaseT)
	print ("Offset Phse shifter T", OffsetPhaseT)
	qwe=(LaserPeriod, OffsetT, OffsetPhaseT, PhaseT)
# 	print ("qwe=",qwe)
	savetxt("Timing.offset", qwe)



def GetPhaseT():
	v1=PhaseV1.getw()
	v2=PhaseV2.getw()
	phi=atan2(v2,v1)
	T=RFPeriod*phi/(2*pi)
	return T



def SetVoltages(phi):

	#Vmax may be different for different lasers or phase shifters
	#if (PhaseShifterIndex==1):
	Vmax=1.0

	V1=Vmax*cos(phi)
	V2=Vmax*sin(phi)
	PhaseV1.putw(V1)
	PhaseV2.putw(V2)
	#set values via epics
	print (V1, V2)
	time.sleep(0.1)




def MovePhaseShifter(RelativeDelay):



	NumStepsPerPeriod=36
	DelayStep=sign(RelativeDelay)*RFPeriod/NumStepsPerPeriod

	#read current values of

	CurT=GetPhaseT()
	for t1 in arange(0,RelativeDelay, DelayStep):
		phi1=2*pi*(CurT+t1)/RFPeriod
		SetVoltages(phi1)

	phi1=2*pi*(CurT+RelativeDelay)/RFPeriod
	SetVoltages(phi1)




def MoveDelayCard(NewDelayTime):
	print ("ndt,lp", NewDelayTime, LaserPeriod)
	t1=NewDelayTime%LaserPeriod
	t2=int(t1/2.0)
	t3=int((t1%2.0)/0.009999)
	print ("t1 t2 t3 ",t1,t2,t3)
	DelayCh.putw(t2)
	DelayChFine.putw(t3)



def SetDelay(t=0):
	global LaserPeriod, OffsetT
	a=loadtxt("Timing.offset")
	LaserPeriod=a[0]
	OffsetT=a[1]
	print ("a1=",a[1])
	OffsetPhaseT=a[2]
	print ("OffsetPhaseT from File", OffsetPhaseT)
	CurrentPhaseT=a[3]
	print ("Current value of PhaseT", CurrentPhaseT)

	TotalT=-OffsetT-t
	ForPhaseShifter=-t%CavityPeriod-OffsetPhaseT
	print ("-t/Cavity", -t%CavityPeriod, "-OffsetPhaseT", OffsetPhaseT, "-CurrentPhaseT", CurrentPhaseT)
	MoveDelayCard(TotalT)
	print ("Relative Phase shifter delay", ForPhaseShifter-CurrentPhaseT)
	MovePhaseShifter(ForPhaseShifter-CurrentPhaseT)
	print ("OffsetT before save=", OffsetT)
	savetxt("Timing.offset",(LaserPeriod,OffsetT,OffsetPhaseT,ForPhaseShifter))


def main():


        ConnectEpics()
#        CurSit=-20.015+15.46
#	#CurSit=-14.58+15.46
#	CurSit=546.04-546.92
        #CurSit=0.1
        #CurrentSituation(FromScopeXrayMinusLaser=CurSit)

        print ("------------------")

        SetDelay(-4.9)

#	SetDelay(0.5)
#	time.sleep(5)
#	SetDelay(.5)
if __name__=="__main__":
	main()
#MovePhaseShifter(2.0)
#MoveDelayCard(25.)
#time.sleep(10)
