from ch.psi.pshell.imaging.Overlays import *
import ch.psi.pshell.imaging.Overlay as Overlay
import ch.psi.pshell.imaging.Pen as Pen
import java.awt.Font as Font
import java.awt.Point as Point
import java.awt.Color as Color
import ch.psi.pshell.crlogic.CrlogicPositioner as CrlogicPositioner
import ch.psi.pshell.crlogic.CrlogicSensor as CrlogicSensor




def on_command_started(info):
    print "Start"
def on_command_finished(info):
    print "Finished: "  + str(info.script) + str(info.error)
###################################################################################################
# Layout setup
###################################################################################################
import ch.psi.pshell.data.LayoutSF as LayoutSF

LayoutSF.setExperimentArguments([pv, motor, pe, cv, energy, sin])



#Librariesenergy
#import Jama.Matrix
#sys.path.append('/Users/gobbo_a/dev/pshell/config/home/script/Lib/diffcalc')



crlogic_config = {}
crlogic_config["class"] = "ch.psi.pshell.crlogic.CrlogicScan"
crlogic_config["prefix"] = "MTEST-HW3-CRL"
crlogic_config["ioc"] = "MTEST-VME-HW3.psi.ch"
crlogic_config["integrationTime"] = 0.01
crlogic_config["additionalBacklash"] = 0.0


#LOCAL DEFINITIONS


"""
from ch.psi.pshell.imaging.Utils import *
from ch.psi.pshell.imaging.Overlays import *
import ch.psi.pshell.imaging.Pen as Pen
import java.awt.Font as Font
import java.awt.Point as Point
old  = ov if globals().has_key("ov") else  None
r = show_panel(img)
ov1 = Text(Pen(Color.ORANGE), "TEXT", Font("Verdana", Font.PLAIN, 12) , Point(20,20), )
ov2 = Rect(Pen(Color.ORANGE),Point(50,50), Point(100,100),  )
ov3 = Rect(Pen(Color.RED),Point(150,150), Point(200,200),  )
ov4 = Rect(Pen(Color.GREEN),Point(250,250), Point(300,300),  )
ov5 = Text(Pen(Color.ORANGE), "TEXT 2", Font("Verdana", Font.PLAIN, 12) , Point(-50,-50), )
ov5.setAnchor(Overlay.ANCHOR_VIEWPORT_OR_IMAGE_BOTTOM_RIGHT)
ov5.setFixed(True)
ov1.setFixed(True)
ov2.setFixed(True)
ov2.setAnchor(Overlay.ANCHOR_VIEWPORT_TOP_LEFT)
ov2.setMovable(True)
ov2.setSolid(True)
ov3.setFixed(True)
ov3.setMovable(True)
ov3.setSolid(True)
ov4.setMovable(True)
ov4.setSolid(True)
ov=[ov1,ov2, ov3, ov4, ov5]
r.updateOverlays(ov, old)
"""

#from jeputils import *

#det.data.monitored=True
import random

#State listener: cleanup can be made at end of execution
def onStateChange(state, former, script):
    if state == State.Closing:
        #print "Closing the app"
        pass
    elif script is not None: 
        if state.isProcessing():
            #print "Started script " + script
            pass
        elif former.isProcessing():
            #print "Finished script " + script
            pass             


class Listener(ContextListener):
    def onContextStateChanged(self, state, former):
        onStateChange(state, former, get_context().runningScriptName)


def scan_e(start, end, step, settling_time = 0, accumulation_time = None, name = None):
    """
    """
    if name is not None:
        set_exec_pars(name = name)
    print get_exec_pars().path
    lscan(inp,out, start, end, step,settling_time)
    

#Simulated Devices

#run("tutorial/devices")
#run("src/main/assembly/help/Tutorial/devices")
#run("devices")

class SimulatedOutput(Writable):
    def write(self, value):
        pass


class SimulatedInput(Readable):
    def __init__(self):
        self.x = 0.0

    def read(self):
        self.x = self.x + 0.1
        noise = (random.random() - 0.5) / 20.0
        return math.sin(self.x)  + noise


sout = SimulatedOutput()
sinp = SimulatedInput()

for m in mu, delta, gamma, eta, chi, phi:
    m.setSpeed(m.config.defaultSpeed)
#Controler Evenrt Listener




clistener = Listener()
get_context().addListener(clistener)



def trig_scienta():
    time.sleep(1.0)

en_val = None
class SimulatedEnergy(Writable):
    def write(self, value):
        self.put(value)

    def put(self, value, timeout = None):
        global en_val
        en_val = value

    def close(self):
        pass

    @staticmethod
    def test ():
        return "asd"


class SimulatedEnergyReadback(Readable):
    def read(self):
        global en_val
        return en_val;
    
    def get(self):
        return self.read()

    def close(self):
        pass

sim_energy = SimulatedEnergy()
sim_energy_readback = SimulatedEnergyReadback()


class beam_ok(ReadonlyRegisterBase):
    def doRead(self):
        return True
add_device(beam_ok(), True)

#Device utilities
def integrate_image():
    data = scienta.data.read()
    #Integrate and plot
    (width,height) = scienta.getImageSize().tolist()
    integration = []
    for i in range(width):
        p=0.0
        for j in range(height):
            p=p+data[j*width+i]
        integration.append(p)
    return integration

def trig_scienta():
    #scienta.start()
    #scienta.waitReady(-1)
    time.sleep(1.0)
    pass


#Pseudo-Devices
class ImageIntegrator(ReadableArray):
    def getSize(self):
        (width,height) = scienta.getImageSize().tolist()
        return width

    def read(self):
        return to_array(integrate_image(),'d')

integration = ImageIntegrator()


"""
class Interlock(DeviceAdapter):
     def onValueChanging(self, device, value, former):
        if value > 5.0:
            raise Exception("Interlocked")
    


motor.addListener(Interlock())
"""

#This procedude is used to emulate file names generated by FDA
"""
import ch.psi.pshell.data.LayoutTable
class Layout( ch.psi.pshell.data.LayoutTable):
    def getLogFileName(self):        
        return time.strftime('%Y%m%d%H%M%S') + '_' + get_exec_pars().name + '_logs'
    
    def getDatasetName(self, scan):        
        return time.strftime('%Y%m%d%H%M%S') + '_' + get_exec_pars().name + '_' +  str(get_exec_pars().index).zfill(4)
        
get_context().dataManager.setLayout(Layout())

"""

"""
import ch.psi.pshell.data.LayoutTable
class DataLayout( ch.psi.pshell.data.LayoutTable):
    def getLogFileName(self):
        return time.strftime('%Y%m%d_%H%M') + '_' + get_exec_pars().script + '_logs'
    
    def getDatasetName(self, scan):
        print get_exec_pars().count
        data_file =  time.strftime('%Y%m%d_%H%M') + '_' + get_exec_pars().name  + '_' + str(get_exec_pars().count).zfill(4)        
        print "Opened data file: " + get_exec_pars().path + "/" + data_file
        return data_file
get_context().dataManager.setLayout(DataLayout())
"""

#Interlocks
"""
class MyInterlock1 (Interlock):
#Motor and Positioners
    def __init__(self):
        Interlock.__init__(self, (motor, pe))

    def check(self, (m, p)):
        if p>50.0 and (m<50 and m>40):
            return False
        return True

interlock1 = MyInterlock1()
"""

"""
#Motor group
class MyInterlock2(Interlock):
    def __init__(self):
        Interlock.__init__(self, (table, pe))

    def check(self, ((m1,m2), p)):
        if p<500 and (m1>4 and m2>4):
            return False
        return True

interlock2 = MyInterlock2()

"""

"""
#Discrete Positioner
class MyInterlock3(Interlock):
    def __init__(self):
        Interlock.__init__(self,  (tab, pe))

    def check(self, (tab, p)):
        if p<500 and tab=="Out":
            return False
        return True

interlock3 = MyInterlock3()
"""
"""

import ch.psi.pshell.data.LayoutTable
class DataLayout( ch.psi.pshell.data.LayoutTable):
    def getLogFileName(self):
        return time.strftime('%Y%m%d_%H%M') + '_' + get_exec_pars().name + '_logs'
    
    def getDatasetName(self, scan):
        print get_exec_pars().count
        data_file =  time.strftime('%Y%m%d_%H%M') + '_' + get_exec_pars().name  + '_' + str(get_exec_pars().count).zfill(4)        
        print "Opened data file: " + get_exec_pars().path + "/" + data_file
        return data_file
get_context().dataManager.setLayout(DataLayout())
"""


#run("CPython/wrapper")

class SimulatedImage(ReadonlyRegisterBase, ReadonlyRegisterMatrix, ReadableCalibratedMatrix):
    def __init__(self, size_x=1280, size_y=960, number_of_dead_pixels=100, noise=0.1, beam_size_x=100, beam_size_y=20):        
        self.size_x, self.size_y, self.number_of_dead_pixels, self.noise, self.beam_size_x, self.beam_size_y = \
                    size_x, size_y, number_of_dead_pixels, noise, beam_size_x, beam_size_y 
        self.sc = None
        
    def doRead(self):
        if self.sc is None:
            self.sc = new_simulated_camera(self.size_x, self.size_y, self.number_of_dead_pixels, self.noise, self.beam_size_x, self.beam_size_y)
        ret = get_image()
        return Convert.reshape(ret,self.size_y, self.size_x)

    def getWidth(self):
        return self.width

    def getHeight(self):
        return self.height

    def getCalibration(self):
        return MatrixCalibration(-1.0, 1.0, 0.0, 0.0)

#add_device(RegisterMatrixSource("sim", SimulatedImage()), True)
#sim.polling = -250




def get_next_fid(folder, prefix, ext):
    try:
        import glob   
        files = glob.glob(folder + prefix + '*_*.dat')
        last = max(files)
        index = int (last[last.rfind('_')+1 : last.rfind('.')]) + 1
        return index
    except:
        return 0

def wait_channel(name, value, timeout =None, type='s'):
    print "Waiting " + str(name) + " = " + str(value)
    cawait(name, value, timeout = timeout, type=type)
    print "Done waiting"

def convert_file(input_file_name, output_file_name, field = 0, pol = 0, keithley_3 = False):   
    sep = "\t"
    line_sep = "\n"
    with open(input_file_name) as inp:
        lines = inp.readlines()
        with open(output_file_name, "wb") as out:
            out.write("Energy" + sep + "rbkenergy" + sep + "Mag" + sep + "Pol" + sep + "Io" + sep + "TEY" + sep + "Norm" + line_sep)
            s = sep + " "    #File format has a space before numeric values
            for line in lines[1:]:
                line = line.strip()
                if line=="": break
                try:                   
                    (Ecrbk,CADC1, CADC2, NORM, CADC3, CADC4, MCurr, cffrbk, ID1Erbk, ID2Erbk, vTime) = line.split(" ")                   
                    #out.write(Ecrbk + sep + Ecrbk + sep + str(field) + sep + str(pol) + sep + CADC1 + sep + CADC2 + sep + (CADC3 if keithley_3 else NORM) + line_sep)
                    out.write(" " + Ecrbk + s + Ecrbk + s + str(field) + s + str(pol) + s + CADC1 + s + CADC2 + s + (CADC3 if keithley_3 else NORM) + line_sep)
                except:
                    traceback.print_exc()           

def plot_file(file, title = None):
    """
    """
    table = Table.load(file, "\t", '#')
    plots = plot(table, title = title)


    


from mathutils import estimate_peak_indexes, fit_gaussians, create_fit_point_list, Gaussian,fit_harmonic,HarmonicOscillator
import java.awt.Color as Color

def fit(ydata, xdata = None):
    if xdata is None:
        xdata = frange(0, len(ydata), 1)
    max_y= max(ydata)    
    index_max = ydata.index(max_y)    
    max_x= xdata[index_max]
    print "Max index:" + str(index_max),
    print " x:" + str(max_x),
    print " y:" + str(max_y)
    
    gaussians = fit_gaussians(ydata, xdata, [index_max,])
    p = plot([ydata],["data"],[xdata], title="Fit" )[0] 

    if gaussians[0] is None:  #Fitting error
        p.addMarker(max_x, None, "Max="+str(round(max_x,2)), Color.GRAY)
        print "Fitting error - using max value"
        return (None, max_x, None)
    
    (norm, mean, sigma) = gaussians[0]

    fitted_gaussian_function = Gaussian(norm, mean, sigma)    
    scale_x = [float(min(xdata)), float(max(xdata)) ]
    points = max((len(xdata)+1), 100)
    resolution = (scale_x[1]-scale_x[0]) / points    
    fit_y = []
    fit_x = frange(scale_x[0],scale_x[1],resolution, True)
    for x in fit_x:
        fit_y.append(fitted_gaussian_function.value(x))    
    p.addSeries(LinePlotSeries("fit"))
    p.getSeries(1).setData(fit_x, fit_y)    
    
    if abs(mean - xdata[index_max]) < ((scale_x[0] + scale_x[1])/2):
        print "Mean -> " +  str(mean)
        p.addMarker(mean, None, "Mean="+str(round(norm,2)), Color.MAGENTA.darker())
        return (norm, mean, sigma)
    else:
        p.addMarker(max_x, None, "Max="+str(round(max_x,2)), Color.GRAY)
        print "Invalid gaussian fit: " +  str(mean) + " - using max value"
        return (None, max_x, None)

def hfit(ydata, xdata = None):
    if xdata is None:
        xdata = frange(0, len(ydata), 1)

    max_y= max(ydata)    
    index_max = ydata.index(max_y)    
    max_x= xdata[index_max]
        
    start,end = min(xdata), max(xdata)
    (amplitude, angular_frequency, phase) = fit_harmonic(ydata, xdata)
    fitted_harmonic_function = HarmonicOscillator(amplitude, angular_frequency, phase)
    
    print "amplitude = ", amplitude
    print "angular frequency = ", angular_frequency
    print "phase = ", phase

    f = angular_frequency/ (2* math.pi)  
    print "frequency = ", f  

    resolution = 0.01
    fit_y = []
    for x in frange(start,end,resolution, True):
        fit_y.append(fitted_harmonic_function.value(x))
    fit_x = frange(start, end+resolution, resolution)

    p = plot(ydata,"data", xdata, title="HFit")[0]
    p.addSeries(LinePlotSeries("fit"))
    p.getSeries(1).setData(fit_x, fit_y)    

    #m = (phase + math.pi)/ angular_frequency
    m = -phase / angular_frequency
    if (m<start):
        m+=(1.0/f)
        
    if start <=m <=end:
        print "fit = ", m
        p.addMarker(m, None, "Fit="+str(round(m ,2)), Color.MAGENTA.darker())
        return (amplitude, angular_frequency, phase, True, m)
    else:
        print "max = ",max_x
        p.addMarker(max_x, None, "Max="+str(round(max_x ,2)), Color.MAGENTA.darker())        
        return (amplitude, angular_frequency, phase, False, max_x)

from mathutils import fft, get_modulus

def plot_spectrum(signal, sampling_freq, plots = None):
    signal = to_list(signal) 
    number_of_samples = len(signal)
    time_vector = [x / sampling_freq for x in frange(0, number_of_samples, 1)]    
    tranform = fft(signal)
    two_side_spectrum = [x / number_of_samples for x in get_modulus(tranform)]
    spectrum = [two_side_spectrum[0],] + [x * 2 for x in two_side_spectrum[1:len(two_side_spectrum)/2 + 1] ]
    number_of_samples = len(tranform)    # Signal may have been padded to next power of two
    freq_vector = [x * sampling_freq / float(number_of_samples) for x in frange(0, len(spectrum) , 1)]
    if plots is None:
        plots = plot([signal,spectrum], ["signal", "spectrum"],[time_vector, freq_vector], title = "Spectrum")
    else:
        plots[0].getSeries(0).setData(time_vector,signal)
        plots[1].getSeries(0).setData(freq_vector,spectrum)
    return plots
     

def elog(title, message, attachments = [], author = get_context().getUser().name, category = "Info", domain = "", logbook = "SwissFEL test", encoding=1):
    typ = "pshell"
    entry = ""    
    cmd = 'G_CS_ELOG_add -l "' + logbook+ '" '
    cmd = cmd + '-a "Author=' + author + '" '
    cmd = cmd + '-a "Type=' + typ + '" '
    cmd = cmd + '-a "Entry=' + entry + '" '
    cmd = cmd + '-a "Title=' + title + '" '
    cmd = cmd + '-a "Category=' + category + '" '
    cmd = cmd + '-a "Domain=' + domain + '" '
    for attachment in attachments:
        cmd = cmd + '-f "' + attachment + '" '
    cmd = cmd + '-n ' + str(encoding)
    cmd = cmd + ' "' + message + '"'
    print cmd
    print exec_cmd(cmd)


#CAS
class ArrayDevice(ReadonlyRegisterBase, ReadonlyRegisterArray):
    def doRead(self):
        return self.take()

    def getSize(self):
        global scan_result
        return len(self.take())   

    def append(self, value):
        c = self.take()
        c.append(value)
        self.set(c)
        
    def set(self, value):
        self.onReadout(to_array(value, 'd'))


class ScalarDevice(RegisterBase):    
    def doRead(self):
        return self.val if hasattr(self, 'val') else 0.0 

    def doWrite(self, val):
        self.val = val        

    def test(self):
        self.setCache(1.0, None)

"""
add_device(ArrayDevice("scan_pos"), True)
add_device(ArrayDevice("scan_val"), True)
add_device(ScalarDevice("scan_start"), True)
add_device(ScalarDevice("scan_stop"), True)
add_device(ScalarDevice("scan_step"), True)

scan_start.write(0.0)
scan_stop.write(40.0)
scan_step.write(1.0)



import ch.psi.pshell.epics.CAS as CAS
#CAS.setServerPort(12345)
cas1=CAS("PSHELL:scanpos",scan_pos, "double")
cas2=CAS("PSHELL:scanval",scan_val, "double")
cas3=CAS("PSHELL:scanstart",scan_start, "double")
cas4=CAS("PSHELL:scanstop",scan_stop, "double")
cas5=CAS("PSHELL:scanstep",scan_step, "double")

#scan_pos.set([] )
#scan_val.set([])
#TODO: this is workaround to CAS not supporting dynamic arrays
MAX_ARRAY_DEV_SIZE = 5000
scan_pos.set([0.0,] * MAX_ARRAY_DEV_SIZE )
scan_val.set([0.0,] * MAX_ARRAY_DEV_SIZE )


#cas6= CAS("PSHELL:var",sin)
"""

def plot_numpy_array(na, title = None):
    plot( Convert.reshape(na.getData(),na.getDimensions()),title=title)



def run_fda(file_name, arguments={}):
    """
    Run FDA loop
    """
    import ch.psi.fda.ProcessorFDA as ProcessorFDA
    ProcessorFDA().execute(file_name,arguments)




#Convex hull plots
def clear_convex_hull_plot(title):
    plots = get_plots(title = title)
    if len(plots)>0:
        plots[0].clear() 
 
def add_convex_hull_plot(title, x,y, name=None, clear = False, x_range = None, y_range = None):
    plots = get_plots(title = title)
    p = None
    if len(plots)==0:
        p = plot(None,name=name, title = title)[0]       
        if x_range is not None:
            p.getAxis(p.AxisId.X).setRange(x_range[0], x_range[1])
        if y_range is not None:
            p.getAxis(p.AxisId.Y).setRange(y_range[0], y_range[1])
        p.setLegendVisible(True)       
    else:
        p = plots[0]   
        if clear:
            p.clear()
        p.addSeries(LinePlotSeries(name))                   
    s = p.getSeries(name)       
    s.setLinesVisible(False)
    s.setPointSize(3)
    x, y = to_array(x,'d') , to_array(y,'d')
    s.setData(x, y)   

    #Convex Hull
    #In the first time the plot shows, it takes some time for the color to be assigned
    timeout = 0
    while s.color is None and timeout<1000:
        time.sleep(0.001)
        timeout = timeout + 1
    hull = LinePlotSeries(name + "Hull", s.color)   
    p.addSeries(hull)    
    #Bounding box
    #x1,x2,y1,y2 = min(x), max(x), min(y), max(y)   
    #(hx,hy) = ([x1,x2, x2, x1, x1], [y1, y1, y2, y2, y1])            
    (hx,hy) = convex_hull(x=x, y=y)
    hx.append(hx[0]); hy.append(hy[0])                                
    hull.setLineWidth(2)
    hull.setData(to_array(hx,'d') , to_array(hy,'d'))    
    hull.setColor(s.color)
    return [hx,hy]




class CamtoolValue(Readable):
    def __init__(self, channel, alias = None):        
        self.channel=channel
        set_device_alias(self, channel if (alias is None) else alias)
        
    def read(self):
        return  camtool.getValue(self.channel)

class CamtoolArray(ReadableArray):
    def __init__(self, channel, alias = None):              
        self.channel=channel
        set_device_alias(self, channel if (alias is None) else alias)
        
    def read(self):
        return  camtool.getValue(self.channel)        

    def getSize(self):
        return len(camtool.getValue(self.channel))



class CamtoolImage(ReadableMatrix):
    def __init__(self, alias = None):             
        set_device_alias(self, camtool.getCurrentCamera() + " image" if (alias is None) else alias)
        
    def read(self):
        return camtool.getData().matrix

    def getWidth(self):
        return camtool.getData().width

    def getHeight(self):
        return camtool.getData().height   


def wait_camtool_message(number_messages = 1, timeout = 10000):
    for i in range (number_messages):
        if not camtool.stream.waitCacheChange(timeout): raise Exception("Timeout receiving from Camtool")


def get_camtool_stats(number_images=1, async = True, interval=-1, good_region = False):
    #return  [CamtoolValue("gr_x_fit_mean"), CamtoolValue("gr_y_fit_mean"),  CamtoolValue("gr_x_fit_standard_deviation"),  CamtoolValue("gr_y_fit_standard_deviation")]        
    ret = []
    wait_camtool_message()
    prefix = "gr_" if good_region else ""
    for ident in [prefix+"x_fit_mean", prefix+"y_fit_mean", prefix+"x_fit_standard_deviation", prefix+"y_fit_standard_deviation"]:        
        child = camtool.stream.getChild(ident)
        av = create_averager(child, number_images, interval)
        av.monitored = async
        ret.append(av)
    return ret



"""
import ch.psi.fda.LayoutFDA
class DataLayout( ch.psi.fda.LayoutFDA):
    def getLogFileName(self):
        return time.strftime('%Y%m%d_%H%M') + '_' + get_exec_pars().name + '_logs'
    
    def getDatasetName(self, scan):
        return  time.strftime('%Y%m%d_%H%M') + '_' + get_exec_pars().name  + '_' + str(get_exec_pars().count-1).zfill(4)        
get_context().dataManager.setLayout(DataLayout())

"""


def is_panel():
    return get_exec_pars().source == CommandSource.plugin

def is_ui():
    return get_exec_pars().source == CommandSource.ui


class AnalogOutput(RegisterBase):    
    def doRead(self):
        return self.val if hasattr(self, 'val') else 0.0 

    def doWrite(self, val):
        self.val = val

class Sinusoid(ReadonlyRegisterBase):
    def doRead(self):
        noise = (random.random() - 0.5) * 0.15
        return round(math.sin(1.0*time.time())  + noise , 3)

class Bpm(ReadonlyRegisterBase):
    def doRead(self):
        noise = (random.random() - 0.5) * 0.15
        return round(math.sin(0.5*math.radians(phase.read()))  + noise , 3)

class SinusoidWaveform(ReadonlyRegisterBase, ReadonlyRegisterArray):
    def doRead(self):
        time.sleep(0.001)
        ret = []
        x = random.random()
        for i in range (20):
            ret.append(math.sin(x))
            x = x + 0.1
        return ret

    def getSize(self):
        return len(self.take(-1))    #only reads if cache is None

class SinusoidImage(ReadonlyRegisterBase, ReadonlyRegisterMatrix):
    def doRead(self):
        time.sleep(0.001)
        (width, height) = (200, 100)
        ret = []
        x = random.random();
        base = []        
        for i in range (width):
            base.append( math.sin(x))
            x = x + 0.05
        for i in range (height):
            noise = (random.random() - 0.5)/5.0 
            ret.append([x+noise for x in base])
        return to_array(ret,'d')
    def getWidth(self):
        return len(self.take(-1)[0])

    def getHeight(self):
        return len(self.take(-1))
"""        

add_device(Bpm("bpm_x"), True)
add_device(Sinusoid("amplitude"), True)
add_device(Sinusoid("power"), True)
add_device(SinusoidWaveform("waveform1"), True)
add_device(SinusoidImage("detector1"), True)
import ch.psi.pshell.imaging.RegisterMatrixSource as RegisterMatrixSource
add_device(RegisterMatrixSource("image1", detector1), True)

bpm_x.setPolling(100)
waveform1.setPolling(1000)
image1.setPolling(-200)

add_device(DummyPositioner("phase"),True)
"""

class DigitalInput(ReadonlyRegisterBase):
    def doRead(self):
        return  False if (int(time.time()) %2 == 0 ) else True

add_device(DigitalInput("di"),True)      
di.polling=1000



###  Diffcalc
GEOMETRY_PREFERENCE = "geometry"

def get_geometry():
    """
    """
    setting = get_setting(GEOMETRY_PREFERENCE)
    if setting is None or (len(setting.strip()) == 0):
        return None
    return setting

def set_geometry(value, apply = None):
    """
    """
    if value is None or  (len(value.strip()) == 0):
        set_setting(GEOMETRY_PREFERENCE, "" )
        for name in "wavelength", "hkl_group", "h", "k", "l":
            dev = get_device(name)
            if dev is not None:
                remove_device(dev)
        return
    filename = get_context().setup.expandPath("{script}/geometry/"+ str(value)+".py")
    if not os.path.isfile(filename):
        raise Exception("Invalid geometry file: " + value)
    former = get_geometry()
    if ((apply is None) and former != value) or (apply==True) :
        set_setting(GEOMETRY_PREFERENCE, value )
        run(filename)       

def is_geometry_set():
    return get_device("wavelength") is not None


mu.moveAsync(0.0)
eta.moveAsync(0.0)
delta.moveAsync(45.0)
gamma.moveAsync(0.0)
energy.write(9.5) 