def displayRealImage(self, msg): path = msg # no abort then display the image if self.abort: # add a new deffered object d = self.protocol.addDeferred("realSent") d.addCallback(self.displayRealImage_thread) if(self.timer.IsRunning()): self.timer.Stop() self.parent.parent.parent.expGauge.SetValue(self.endTimer) # get stats data = als.getData(path) stats_list = als.calcStats(data) # change the gui with thread safety wx.CallAfter(self.safePlot, data, stats_list) self.parent.parent.parent.expGauge.SetValue(0) self.startTimer = 0 thread.start_new_thread(self.exposeTimer, (self.timeToSend,))
def connectionMade(self): """ Executes when conncetion is made to filter. """ ## Add a callback that will open up the rest of the gui when the camera is done setting up #gui = self.factory.gui # get gui for adding the callback method #d = defer.Deferred() #d.addCallback(gui.onConnectCallback) #self._deferreds["status"] = d self.gui = self.factory.gui self.gui.takeImage.filterInstance.protocol2 = self logger.info("connection made to filter") filterInstance = self.gui.takeImage.filterInstance filterInstance.filterConnection = True #self.filterWatchThread = threading.Thread(target=filterInstance.filterWatch, args=()) #self.filterWatchThread.daemon = True filterInstance.logFunction = filterInstance.logFilter logString = als.getLogString('filter connect', 'pre') filterInstance.log(filterInstance.logFunction, logString) logString = als.getLogString('filter getFilter', 'pre') filterInstance.log(filterInstance.logFunction, logString) d = self.sendCommand('getFilter') d.addCallback(filterInstance.getFilterCallback)
def __init__(self): wx.Frame.__init__(self, parent=None, title="Data Sender", size=(500, 400)) self.protocol = None # main sizers self.vertSizer = wx.BoxSizer(wx.VERTICAL) self.horzSizer = wx.BoxSizer(wx.HORIZONTAL) # Widgets self.statTxt = wx.StaticText(self, id=100, label="Command Prompt") self.enterTxt = wx.TextCtrl(self, id=101, size=(200, -1)) self.btn = wx.Button(self, id=102, size=(100, -1), label="OK") self.vertSizer.Add(self.statTxt, flag=wx.ALIGN_CENTER) als.AddLinearSpacer(self.vertSizer, 10) self.vertSizer.Add(self.enterTxt, flag=wx.ALIGN_CENTER) als.AddLinearSpacer(self.vertSizer, 10) self.vertSizer.Add(self.btn, flag=wx.ALIGN_CENTER) self.Bind(wx.EVT_BUTTON, self.onButton, id=102) self.SetSizer(self.vertSizer) self.vertSizer.Fit(self)
def onExpose(self, event): """ Executes when the expose button is pressed. It checks that the variable self.exposeToSend is a float. It it passes then this value is sent to Evora. If it fails a dialog box tells the user the varible is not a number and will not send it to Evora. """ if als.isNumber(self.timeToSend): print float(self.timeToSend) else: dialog = wx.MessageDialog(None, "Exposure time not a number...will not expose.", "", wx.OK|wx.ICON_ERROR) dialog.ShowModal() if self.nameToSend is "": dialog = wx.MessageDialog(None,"No name was given...will not expose", "", wx.OK|wx.ICON_ERROR) dialog.ShowModal() else: print self.nameToSend if als.isNumber(self.timeToSend) and self.nameToSend is not "": self.protocol.sendLine("Exposing with name " + str(self.nameToSend) + " and time " + str(self.timeToSend) + " s") line = self.getAttributesToSend() self.protocol.sendLine(line)
def displaySeriesImage(self, msg): msg = msg.split(",") imNum = int(msg[0]) print type(imNum) time = float(msg[1]) path = msg[2] print "Got:", msg # no abort then display the image if(self.abort and imNum <= int(self.seriesImageNumber)): print "Entered to display series image" # add a new deffered object d = self.protocol.addDeferred("seriesSent") d.addCallback(self.displaySeriesImage_thread) if(self.timer.IsRunning()): self.timer.Stop() self.parent.parent.parent.expGauge.SetValue(self.endTimer) # get stats data = als.getData(path) stats_list = als.calcStats(data) # change the gui with thread safety wx.CallAfter(self.safePlot, data, stats_list) self.parent.parent.parent.expGauge.SetValue(0) self.startTimer = 0 if(self.seriesImageNumber != None): if(imNum < int(self.seriesImageNumber)): thread.start_new_thread(self.exposeTimer, (time,))
def displayRealImage_callback(self, msg): path = msg # path to image (/tmp/image_date.fits) if(msg != "None"): # get data data = als.getData(path) stats_list = als.calcStats(data) # change the gui with thread safety wx.CallAfter(self.safePlot, data, stats_list)
def exposeCallback(self, msg): ### May need to thread to a different method if to slow results = msg.split(",") # immediatly reset button self.abort = False self.expButton.Enable(True) if(self.stopExp.IsEnabled()): self.stopExp.Enable(False) ## complete progress bar for image acquisition # check to see if timer is still going and stop it (callback might come in early) if(self.timer.IsRunning()): self.timer.Stop() # finish out gauge and then reset it self.parent.parent.parent.expGauge.SetValue(self.endTimer) # get success; success = int(results[0]) # 1 for true 0 for false #print success # at the end of the callback reset the gauge (signifies a reset for exposure) self.parent.parent.parent.expGauge.SetValue(0) self.startTimer = 0 print self.parent.parent.parent.imageOpen print "opened window" if(success == 1): # get name of image and path filePath = results[1].split("/") name = filePath[-1].rstrip() path = "" for i in filePath[:-1]: path += i + "/" print path, name # get data data = als.getData(path+name) stats_list = als.calcStats(data) # change the gui with thread safety wx.CallAfter(self.safePlot, data, stats_list) else: print "Successfully Aborted" pass
def onCool(self, event): if als.isNumber(self.tempToSend): if(float(self.tempToSend) >= -80.0 and float(self.tempToSend) <= -10.0): print float(self.tempToSend) if self.parent.exposureInstance.abort: dialog = wx.MessageDialog(None, "Do you want to changing temperature during exposure?", "", wx.OK | wx.CANCEL|wx.ICON_QUESTION) answer = dialog.ShowModal() dialog.Destroy() if answer == wx.ID_OK: d = self.protocol.sendCommand("setTEC " + str(int(self.tempToSend))) d.addCallback(self.cooling_callback) if(not self.stopCool.IsEnabled()): self.stopCool.Enable(True) else: d = self.protocol.sendCommand("setTEC " + str(int(self.tempToSend))) d.addCallback(self.cooling_callback) if(not self.stopCool.IsEnabled()): self.stopCool.Enable(True) else: dialog = wx.MessageDialog(None, "Temperature is not within the bounds.", "", wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() else: dialog = wx.MessageDialog(None, "Temperature specified is not a number.", "", wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy()
def onCool(self, event): if als.isNumber(self.tempToSend): print float(self.tempToSend) self.protocol.sendLine("temperature " + str(self.tempToSend)) else: dialog = wx.MessageDialog(None, "Temperature specified is not a number.", "", wx.OK|wx.ICON_ERROR) dialog.ShowModal()
def onOpen(self, event): """ Opens when user selects to load an image. Allows user to select a load a saved fits/fit image. """ logger.info("Trying to open image") openFileDialog = wx.FileDialog(self, "Open Image File", "", "", "Image (*.fits;*.fit)|*.fits.*;*.fits;*.fit", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) if openFileDialog.ShowModal() == wx.ID_CANCEL: return fileName = openFileDialog.GetFilename() fileName = fileName.split(".") if fileName[-1] in ["fits", "fit"]: data = als.getData(openFileDialog.GetPath()) stats_list = als.calcStats(data) self.parent.takeImage.exposureInstance.safePlot(data, stats_list)
def clientConnectionLost(self, transport, reason): """ Executes when client has lost connection normally. """ filterInstance = self.gui.takeImage.filterInstance filterInstance.logFunction = filterInstance.logFilter logString = als.getLogString("filter connectLost 1", 'post') filterInstance.log(filterInstance.logFunction, logString) logger.info("connection lost normally on port 5503")
def clientConnectionFailed(self, transport, reason): """ Called when client connection is lost unexpectedly. """ exposureInstance = self.gui.takeImage.exposureInstance exposureInstance.logFunction = exposureInstance.logExposure logString = als.getLogString("connectFailed 1", 'post') exposureInstance.log(exposureInstance.logFunction, logString) logger.warning("connection to E. server failed on port 5502")
def clientConnectionLost(self, transport, reason): """ Called when client connection is lost normally. """ exposureInstance = self.gui.takeImage.exposureInstance exposureInstance.logFunction = exposureInstance.logExposure logString = als.getLogString("connectLost 1", 'post') exposureInstance.log(exposureInstance.logFunction, logString) logger.info("connection to E. server lost normally on port 5502")
def clientConnectionFailed(self, transport, reason): """ Executes when client has lost connection unexpectedly. """ filterInstance = self.gui.takeImage.filterInstance filterInstance.logFunction = filterInstance.logFilter logString = als.getLogString("filter connectFailed 1", 'post') filterInstance.log(filterInstance.logFunction, logString) logger.warning("connection failed on port 5503")
def threadSafeLogStatus(self, string): """ Note: This should be called with with wx.CallAfter to update a GUI element. Pre: Takes in a string. Post: Displays that string in the log status box in the log tab of the gui. """ msg = als.timeStamp() + " " + string val = self.logBox.GetValue() self.logBox.SetValue(val + msg + "\n") self.logBox.SetInsertionPointEnd()
def callShutdown(self, msg): """ When the camera sends it has shutdown successfully then this runs and locks down the GUI. """ self.logFunction = self.logMain logString = als.getLogString("shutdown " + msg, 'post') self.logMethod(self.logFunction, logString) self.takeImage.tempInstance.isConnected = False bitmap = wx.StaticBitmap(self.stats, -1, size=(90, 17)) self.stats.AddWidget(bitmap, pos=0, horizontalalignment=EnhancedStatusBar.ESB_ALIGN_RIGHT) self.stats.SetStatusText("Current Temp: ... C", 0) self.joinThreads("temp", demonized=False) self.connection.disconnect() self.connected = False self.enableConnections(True, False, False)
def callStartup(self, msg): """ When connect is sent to the server and is done this will set the state of the GUI. """ self.logFunction = self.logMain logString = als.getLogString('connect ' + msg, 'post') self.logMethod(self.logFunction, logString) result = int(msg) self.connected = True # boolean to tell if connected to server self.enableConnections(False, True, True) # grey and un-grey camera menu options self.disableButtons("connect", False) # enable gui functionality self.takeImage.tempInstance.isConnected = True # setups infinite loop in watchTemp method t = threading.Thread(target=self.takeImage.tempInstance.watchTemp, args=(), name="temp thread") t.daemon = True t.start() self.active_threads["temp"] = t logger.info("Started up from callStartup method")
def onConnectCallback(self, msg): """ When a connection is made successfully the server sends a status which goes throught this. If the camera status is uninitialized then it runs the startup routine else it sets the state of the GUI to connect.. """ #msg = args[0] #thread = args[1] logger.debug(msg + " Startup callback entered") self.connected = True # get the number of clients status = int(msg.split(",")[0]) self.logFunction = self.logMain logString = als.getLogString('status ' + str(status), 'post') self.logMethod(self.logFunction, logString) logger.debug("status from connect callback: " + str(status)) if(status == 20075): # camera is uninitialized d = self.protocol.sendCommand("connect") d.addCallback(self.callStartup) elif(status == 20002): # if camera is already initialized then start server like regular # start temperature thread t = threading.Thread(target=self.takeImage.tempInstance.watchTemp, args=(), name="temp thread") self.takeImage.tempInstance.isConnected = True # setups infinite loop in watchTemp method t.daemon = True # Enable disconnect and shutdown and disable connect menu items self.enableConnections(False, True, True) self.disableButtons("connect", False) t.start() self.active_threads["temp"] = t else: # camera drivers are broken needs reinstall? pass
def kseriesExposure(self, protocol, imType, itime, filter="", readTime=3, numexp=1, binning=1, numAccum=1, accumCycleTime=0, kCycleTime=0): """ This handles multiple image acquisition using the camera kinetic series capability. The basic arguements are the passed in protocol, the image type, integration time, filter type, readout index, number of exposures, and binning type. In the future this function could be modified to include accumulations or add time the kinetic cycle time. Accumulations are how many images should be readout as one, and kCycleTime can add time between each exposure that is taken. """ global isAborted isAborted = False retval,width,height = andor.GetDetector() logger.debug('GetDetector: ' + str(retval) + " " + str(width) + " " + str(height)) logger.debug("SetAcquisitionMode: " + str(andor.SetAcquisitionMode(3))) logger.debug('SetReadMode: ' + str(andor.SetReadMode(4))) logger.debug('SetImage: ' + str(andor.SetImage(binning,binning,1,width,1,height))) logger.debug('GetDetector (again): ' + str(andor.GetDetector())) if(imType == "bias"): itime = 0 andor.SetShutter(1,2,0,0) # TLL mode high, shutter mode Permanently Closed, 0 millisec open/close logger.debug('SetExposureTime: ' + str(andor.SetExposureTime(0))) else: if(imType in ['flat', 'object']): andor.SetShutter(1,0,5,5) else: andor.SetShutter(1,2,0,0) logger.debug('SetExposureTime: ' + str(andor.SetExposureTime(itime))) # TLL mode high, shutter mode Fully Auto, 5 millisec open/close logger.debug("SetNumberOfAccumulations: " + str(andor.SetNumberAccumulations(numAccum))) # number of exposures to be combined logger.debug("SetAccumulationTime: " + str(andor.SetAccumulationCycleTime(accumCycleTime))) logger.debug("SetNumberOfKinetics: " + str(andor.SetNumberKinetics(numexp))) # this is the number of exposures the user wants logger.debug('SetKineticTime: ' + str(andor.SetKineticCycleTime(accumCycleTime))) logger.debug("SetTriggerMode: " + str(andor.SetTriggerMode(0))) logger.debug("Timings: " + str(andor.GetAcquisitionTimings())) logger.debug("SetHSSpeed: " + str(andor.SetHSSpeed(0, readTime))) # default readTime is index 3 which is 0.5 MHz or ~6 sec # write headers attributes = [imType, binning, itime, filter] header = self.getHeader(attributes) logger.debug('StartAcquisition: ' + str(andor.StartAcquisition())) status = andor.GetStatus() logger.debug(str(status)) imageAcquired = False counter = 1 while(status[1] == andor.DRV_ACQUIRING): status = andor.GetStatus() progress = andor.GetAcquisitionProgress() runtime = 0 if(progress[2] == counter or (not isAborted and progress[2] == 0 and imageAcquired)): runtime -= time.clock() data = np.zeros(width//binning*height//binning, dtype='uint16') # reserve room for image results = andor.GetMostRecentImage16(data) # store image data logger.debug(str(results) + " " + 'success={}'.format(results == 20002)) # print if the results were successful logger.debug('image number: ' + str(progress[2])) if(results == andor.DRV_SUCCESS): # if the array filled store successfully data=data.reshape(width//binning,height//binning) # reshape into image logger.debug(str(data.shape) + " " + str(data.dtype)) hdu = fits.PrimaryHDU(data,do_not_scale_image_data=True,uint=True, header=header) #filename = time.strftime('/data/forTCC/image_%Y%m%d_%H%M%S.fits') filename = als.getImagePath('series') hdu.writeto(filename,clobber=True) logger.debug("wrote: {}".format(filename)) protocol.sendData("seriesSent"+str(counter)+" "+str(counter)+","+str(itime)+","+filename) # make a new header and write time to it for new exposure. header = self.getHeader(attributes) if(counter == numexp): logger.info("entered abort") isAborted = True imageAcquired = True counter += 1 runtime += time.clock() logger.debug("Took %f seconds to write." % runtime) return "series 1,"+str(counter) # exits with 1 for success
def realTimeExposure(self, protocol, imType, itime, binning=1): """ Inputs are the Evora server protocol, the image type, the integration time, and the binning size. Runs camera in RunTillAbort mode. """ #global acquired retval,width,height = andor.GetDetector() logger.debug('GetDetector: ' + str(retval) + " " + str(width) + " " + str(height)) logger.debug("SetAcquisitionMode: " + str(andor.SetAcquisitionMode(5))) logger.debug('SetReadMode: ' + str(andor.SetReadMode(4))) logger.debug('SetImage: ' + str(andor.SetImage(binning,binning,1,width,1,height))) logger.debug('GetDetector (again): ' + str(andor.GetDetector())) logger.debug('SetExposureTime: ' + str(andor.SetExposureTime(itime))) logger.debug('SetKineticTime: ' + str(andor.SetKineticCycleTime(0))) if(imType == "bias"): andor.SetShutter(1,2,0,0) # TLL mode high, shutter mode Permanently Closed, 0 millisec open/close logger.debug('SetExposureTime: ' + str(andor.SetExposureTime(0))) else: if(imType in ['flat', 'object']): andor.SetShutter(1,0,5,5) else: andor.SetShutter(1,2,0,0) logger.debug('SetExposureTime: ' + str(andor.SetExposureTime(itime))) # TLL mode high, shutter mode Fully Auto, 5 millisec open/close data = np.zeros(width//binning*height//binning, dtype='uint16') logger.debug("SetHSSpeed: " + str(andor.SetHSSpeed(0, 1))) # read time on real is fast because they aren't science images logger.debug('StartAcquisition: ' + str(andor.StartAcquisition())) status = andor.GetStatus() logger.debug(str(status)) workingImNum = 1 start = time.time() end = 0 while(status[1]==andor.DRV_ACQUIRING): progress = andor.GetAcquisitionProgress() currImNum = progress[2] # won't update until an acquisition is done status = andor.GetStatus() if(status[1] == andor.DRV_ACQUIRING and currImNum == workingImNum): logger.debug("Progress: " + str(andor.GetAcquisitionProgress())) results = andor.GetMostRecentImage16(data) # store image data logger.debug(str(results) + 'success={}'.format(results == 20002)) # print if the results were successful if(results == andor.DRV_SUCCESS): # if the array filled store successfully data=data.reshape(width//binning,height//binning) # reshape into image logger.debug(str(data.shape) + " " + str(data.dtype)) hdu = fits.PrimaryHDU(data,do_not_scale_image_data=True,uint=True) #filename = time.strftime('/tmp/image_%Y%m%d_%H%M%S.fits') filename = als.getImagePath('real') hdu.writeto(filename,clobber=True) logger.debug("wrote: {}".format(filename)) data = np.zeros(width//binning*height//binning, dtype='uint16') protocol.sendData("realSent " + filename) workingImNum += 1 end = time.time() logger.debug("Took %f seconds" % (end-start)) start = time.time() return "real 1" # exits with 1 for success
def expose(self, imType=None, expnum=None, itime=2, binning=1, filter="", readTime=3): """ expNum is deprecated and should be removed. This handles a single exposure and no more. Inputs are the image type integration time, binning type filter type, as a string, and the index for the specified horizontal readout time. """ if expnum is None: self.num += 1 expnum = self.num else: self.num = expnum if imType is None: # if the image type is not specified it defaults to object imType = "object" retval, width, height = andor.GetDetector() logger.debug('GetDetector: ' + str(retval) + " " + str(width) + " " + str(height)) # print 'SetImage:', andor.SetImage(1,1,1,width,1,height) logger.debug('SetReadMode: ' + str(andor.SetReadMode(4))) logger.debug('SetAcquisitionMode: ' + str(andor.SetAcquisitionMode(1))) logger.debug('SetImage: ' + str(andor.SetImage(binning,binning,1,width,1,height))) logger.debug('GetDetector (again): ' + str(andor.GetDetector())) if(imType == "bias"): andor.SetShutter(1,2,0,0) # TLL mode high, shutter mode Permanently Closed, 0 millisec open/close logger.debug('SetExposureTime: ' + str(andor.SetExposureTime(0))) else: if(imType in ['flat', 'object']): andor.SetShutter(1,0,5,5) else: andor.SetShutter(1,2,0,0) logger.debug('SetExposureTime: ' + str(andor.SetExposureTime(itime))) # TLL mode high, shutter mode Fully Auto, 5 millisec open/close # set Readout speeds 0, 1, 2, or 3 #print("SetVSSpeed:", andor.SetVSSpeed(3)) logger.debug("SetHSSpeed: " + str(andor.SetHSSpeed(0, readTime))) # default readTime is index 3 which is 0.5 MHz or ~6 sec results, expTime, accTime, kTime = andor.GetAcquisitionTimings() logger.debug("Adjusted Exposure Time: " + str([results, expTime, accTime, kTime])) attributes = [imType, binning, itime, filter] header = self.getHeader(attributes) logger.debug('StartAcquisition: ' + str(andor.StartAcquisition())) status = andor.GetStatus() logger.debug(str(status)) while status[1] == andor.DRV_ACQUIRING: status = andor.GetStatus() data = np.zeros(width//binning*height//binning, dtype='uint16') logger.debug(str(data.shape)) result = andor.GetAcquiredData16(data) success = None if(result == 20002): success = 1 # for true else: success = 0 # for false logger.debug(str(result) + 'success={}'.format(result == 20002)) filename = None if success == 1: data=data.reshape(width//binning,height//binning) logger.debug(str(data.shape) + " " + str(data.dtype)) hdu = fits.PrimaryHDU(data,do_not_scale_image_data=True,uint=True, header=header) #filename = time.strftime('/data/forTCC/image_%Y%m%d_%H%M%S.fits') filename = als.getImagePath('expose') hdu.writeto(filename,clobber=True) logger.debug("wrote: {}".format(filename)) return "expose " + str(success) + ","+str(filename) + "," + str(itime)
def parseCommand(self, command): """ This method parses the command inputed by the user from the command promp text control box. If the command is good it will return a list with the command that is sent to the server followed by the necessary arguments. If the command is bad then a string is sent back that will be displayed to the user about what went wrong. For any help commands this is delt with outside the parser. """ scriptLine = command.split() print(scriptLine) command = None subcommand = None commandList = ["expose", "filter", "help", "set"] exposeSub = ["abort", "bias", "dark", "flat", "object", "help"] filterSub = ["home", "status", "help"] helpSub = ["expose", "filter", "set"] setSub = ["binning", "filter", "temp", "warmup", "help"] runList = [] # first entry is the command to send the next entries depend on the command being sent try: command = scriptLine[0] subcommand = scriptLine[1] except IndexError: return "ERROR: command and/or subcommand not given..." else: if command in commandList: # Possible commands (the order of time=X.X, basename=somename, and number=XX is ambiguous) # expose abort # expose bias basename=bias number=XX # expose dark time=X.X basename=dark number=XX # expose flat time=X.X basename=flat number=XX # expose object time=X.X basename=object number=XX # expose help abort # expose help bias # expose help dark # expose help flat # expose help object if command == "expose": if subcommand in exposeSub: if subcommand == "abort": runList.append("abort") # only command to send return runList elif subcommand == "bias": print("exposing of this type") try: arg1 = scriptLine[2] arg2 = scriptLine[3] except IndexError: return "ERROR: no basename or number arguements..." else: if len(scriptLine[0:]) > 4: return 'ERROR: too many arguments given in "expose bias"...' arg1 = arg1.split("=") arg2 = arg2.split("=") argDict = {} print(arg1, arg2) if (len(arg1) == 2 and (arg1[0] in ["basename", "number"])) and ( len(arg2) == 2 and (arg2[0] in ["basename", "number"]) ): # map arguements to be able to call them in order argDict[arg1[0]] = arg1[1] argDict[arg2[0]] = arg2[1] if als.isInt(argDict["number"]): if int(argDict["number"]) > 0: if argDict["basename"].strip() is not "": # final stop; everything has been checked so now we build up the list to return runList.append("series") runList.append(subcommand) runList.append(int(argDict["number"])) runList.append(argDict["basename"]) print("The specified number of exposures is", float(argDict["number"])) return runList # [series, bias, number, basename] else: return "ERROR: basename specified is empty..." else: return "ERROR: number of exposures needs to be above 0..." else: return "ERROR: specified number of exposures is not number..." else: return "SyntaxError: basename or number of exposures is incorrectly specified..." elif subcommand in ["dark", "flat", "object"]: print("exposing of this type") try: arg1 = scriptLine[2] arg2 = scriptLine[3] arg3 = scriptLine[4] except IndexError: return "ERROR: no time, basename, and/or exposure number given..." else: if len(scriptLine[0:]) > 5: return 'ERROR: too many arugments given in "expose (dark/flat/object)"' arg1 = arg1.split("=") arg2 = arg2.split("=") arg3 = arg3.split("=") argDict = {} print(arg1, arg2, arg3) # Makes sure that when args are split by equals that there are two entries and that the first one is # either time or basename. if ( (len(arg1) == 2 and (arg1[0] in ["time", "basename", "number"])) and (len(arg2) == 2 and (arg2[0] in ["time", "basename", "number"])) and (len(arg3) == 2 and (arg3[0] in ["time", "basename", "number"])) ): # map arguments to be able to call them in order argDict[arg1[0]] = arg1[1] argDict[arg2[0]] = arg2[1] argDict[arg3[0]] = arg3[1] if als.isNumber(argDict["time"]) and als.isInt(argDict["number"]): # final stop; everything has been checked so now we build up the list to return if float(argDict["time"]) >= 0 or int(argDict["number"]) > 0: if argDict["basename"].strip() is not "": runList.append("series") runList.append(subcommand) runList.append(int(argDict["number"])) runList.append(float(argDict["time"])) runList.append(argDict["basename"]) print("The specified time is", float(argDict["time"])) print("The specified number of exposures is", float(argDict["number"])) return runList # [series, dark/flat/object, number, time, basename] else: return "ERROR: specified basename is empty..." else: return "ERROR: specified time is negative or the number of images is not 1 or more..." else: return "ERROR: specified time and/or number of exposures not a number..." else: return ( "SyntaxError: time argument, basename, and/or number of exposures is wrong..." ) else: try: helpArg = scriptLine[2] except IndexError: return 'ERROR: argument after "help" not given...' else: if len(scriptLine[0:]) > 3: return 'ERROR: too many arguments after "help"...' runList.append(command) runList.append(subcommand) runList.append(helpArg) return runList else: return "ERROR: not a recognized subcommand...", subcommand # possible commands (only one arg): # set binning (1 or 2) # set filter (1, 2, 3, 4, 5, or 6) # set temp (-80 to -10) # set help (binning, filter temp) if command == "set": if subcommand in setSub: try: arg1 = scriptLine[2] except IndexError: return 'ERROR: didn\'t specify an argument after "subcommand"...' else: if len(scriptLine[0:]) > 3: return "ERROR: there are too many arguments specified..." if subcommand == "binning": if als.isInt(arg1): if int(arg1) == 1 or int(arg1) == 2: runList.append(command) runList.append(subcommand) runList.append(arg1) return runList # [set, binning, 1] else: return "ValueError: binning value is out of range, must be 1 or 2..." else: return "SyntaxError: binning value is not an int..." if subcommand == "temp": if als.isInt(arg1): if int(arg1) >= -80 and int(arg1) <= -10: runList.append("setTEC") runList.append(arg1) return runList else: return "ValueError: temperature out of range of -80 to -10..." elif arg1 == "warmup": runList.append("warmup") # command for sending warmup return runList else: return "SyntaxError: temperature is not a number..." if subcommand == "filter": if als.isInt(arg1): if int(arg1) >= 1 and int(arg1) <= 6: # 6 filter positions: (1, 2, 3, 4, 5, 6) runList.append(command) runList.appedn(subcommand) runList.append(arg1) return runList else: return ( "ValueError: filter position out of range, must specify int from 1 to 6..." ) else: return "SyntaxError: filter position given is not an int..." if subcommand == "help": if arg1 in ["binning", "temp"]: runList.append(command) runList.append(subcommand) runList.append(arg1) return runList else: return 'ERROR: %s after "help" is not recognized...' % arg1 else: return "ERROR: %s is not a recognized subcommand..." % subcommand # possible commands # filter home # will slew filter to home # filter status # will give details on the state of connection # filter help (filter or home) # gives details on how to run the command and what it does if command == "filter": if subcommand in filterSub: # home, status, help if subcommand == "home": runList.append(command) runList.append(subcommand) return runList if subcommand == "status": runList.append(command) runList.append(subcommand) return runList if subcommand == "help": try: arg1 = scriptLine[2] except IndexError: return 'ERROR: no argument after "filter help" specified...' else: if len(scriptLine[0:]) > 3: # make sure there aren't anymore args given than needed return 'ERROR: extra argument after "help" given...' if arg1 == "home": print("slews to filter") if arg1 == "status": print("gives the status of the filter") runList.append(command) runList.append(subcommand) runList.append(arg1) return runList else: return "ERROR: %s is not a recognized subcommand..." % subcommand # possible commands # help expose # help set # help filter if command == "help": if subcommand in helpSub: runList.append(command) runList.append(subcommand) return runList else: return "ERROR: %s is not a recognized subcommand..." % subcommand else: return "ERROR: %s is not a recognized command..." % command
def executeCommand(self, runList): """ This will take the known order of runList from the command and then send it to the server while also displaying pertanent information. It will essentially be reusing methods, whenever possible from the acquisitionClasses.py file. Returns: Nothing is returned through this method. """ val = self.parent.scriptStatus.activityText.GetValue() print(val) if type(runList) == list: self.parent.scriptStatus.activityText.SetValue(val + str(runList) + "\n") self.parent.scriptStatus.activityText.SetInsertionPointEnd() print(runList) print("sending command") # surround in str to get rid of unicode, otherwise fails at sending sendCommand = str(runList[0]) if sendCommand == "series": imtype = str(runList[1]) number = str(runList[2]) exposeClass = self.parent.parent.parent.takeImage.exposureInstance exposeClass.seriesImageNumber = int(number) exposeClass.logFunction = ( self.logScript ) # point to the correct log function that prints to log tab and script status # example runList (['series', 'bias', int(number), 'basename']) if imtype == "bias": basename = str(runList[3]) exposeClass.currentImage = basename overwrite = None if als.checkForFile("/data/copyfile/" + self.currentImage + "_001.fits"): dialog = wx.MessageDialog( None, "Do you want to change temperature during exposure?", "", wx.OK | wx.CANCEL | wx.ICON_QUESTION, ) overwrite = dialog.ShowModal() dialog.Destroy() if overwrite is not None or overwrite == wx.ID_OK: d = self.protocol.addDeferred("seriesSent") d.addCallback(exposeClass.displaySeriesImage_thread) d = self.protocol.sendCommand( sendCommand + " " + imtype + " " + number + " 0 " + str(self.parent.parent.parent.binning) ) d.addCallback(exposeClass.seriesCallback) # start timer thread.start_new_thread(exposeClass.exposeTimer, (0,)) if imtype in ["flat", "object", "dark"]: exposeClass.expButton.Enable(False) exposeClass.stopExp.Enable(True) exposeClass.abort = True itime = str(runList[3]) basename = str(runList[4]) exposeClass.currentImage = basename overwrite = None if als.checkForFile("/data/copyfile/" + self.currentImage + "_001.fits"): dialog = wx.MessageDialog( None, "Do you want to change temperature during exposure?", "", wx.OK | wx.CANCEL | wx.ICON_QUESTION, ) overwrite = dialog.ShowModal() dialog.Destroy() if overwrite is not None or overwrite == wx.ID_OK: for i in range(int(number)): d = self.protocol.addDeferred("seriesSent" + str(i + 1)) d.addCallback(exposeClass.displaySeriesImage_thread) d = self.protocol.sendCommand( sendCommand + " " + imtype + " " + number + " " + itime + " " + str(self.parent.parent.parent.binning) ) d.addCallback(exposeClass.seriesCallback) # start timer thread.start_new_thread(exposeClass.exposeTimer, (float(itime),)) if sendCommand == "abort": exposeClass = self.parent.parent.parent.takeImage.exposureInstance exposeClass.onStop(None) if sendCommand == "expose" and runList[1] == "help": # report on all the help options helpString = "" if runList[2] == "abort": helpString += ( '"expose abort" is used to stop the current exposure. This can be ' + "an exposure started through the imaging or scripting tab. Invoke with " + '"expose abort".' ) if runList[2] == "bias": helpString += ( '"expose bias" is used to take a number of biases in one command. Invoke this ' + 'command with "expose bias arg1 arg2", where arg1 and arg2, in no particular ' + "order, are time=XX in seconds and basename=imagename." ) if runList[2] == "dark": helpString += ( '"expose dark" is used to take a number of darks in one command. Invoke this ' + 'command with "expose dark arg1 arg2 arg3", where arg1, arg2, and arg3, in no particular ' + "order, are time=XX in seconds, number=XX as an int, and basename=imagename." ) if runList[2] == "flat": helpString += ( '"expose flat" is used to take a number of darks in one command. Invoke this ' + 'command with "expose flat arg1 arg2 arg3", where arg1, arg2, and arg3, in no particular ' + "order, are time=XX in seconds, number=XX as an int, and basename=imagename." ) if runList[2] == "object": helpString += ( '"expose object" is used to take a number of darks in one command. Invoke this ' + 'command with "expose object arg1 arg2 arg3", where arg1, arg2, and arg3, in no particular ' + "order, are time=XX in seconds, number=XX as an int, and basename=imagename." ) self.sendToStatus(helpString) ### Deal with set commands # command: set temp XX if sendCommand == "setTEC": temp = int(runList[1]) tempClass = self.parent.parent.parent.takeImage.tempInstance tempClass.tempToSend = temp tempClass.onCool(None) # command: set temp warmup if sendCommand == "warmup": tempClass = self.parent.parent.parent.takeImage.tempInstance tempClass.onStopCooling(None) # command: set filter X if sendCommand == "set": if runList[1] == "filter": pos = int(runList[2]) # command: set binning X if sendCommand == "set": if runList[1] == "binning": topInstance = self.parent.parent.parent bin = str(runList[2]) if bin == "1": topInstance.on1x1(None) file = topInstance.menuBar.GetMenu(0) file.FindItemById(1120).Check(check=True) else: topInstance.on2x2(None) file = topInstance.menuBar.GetMenu(0) file.FindItemById(1121).Check(check=True) # command: set help binning # set help temp # set help filter if sendCommand == "set": if runList[1] == "help": if runList[2] == "binning": helpBinning = ( '"set binning" is used to set the binning type of the CCD. To invoke use the following ' + 'command: "set binning arg1", where arg1 is the binning type of 1 or 2.' ) self.sendToStatus(helpBinning) if runList[2] == "temp": helpTemp = ( '"set temp" is used to set the temperature of the CCD. To invoke use the following ' + 'command: "set temp arg1", where arg1 is an int between -80 to -10 ' + "or warmup." ) self.sendToStatus(helpTemp) if runList[2] == "filter": helpFilter = ( '"set filter" is used to set the filter wheel position. To invoke use the following ' + 'command: "set filter arg1", where arg1 is an int between 1 and 6.' ) self.sendToStatus(helpFilter) # command: help expose # help set # help filter if sendCommand == "help": if runList[1] == "expose": helpExpose = '"expose" command is explicitely for taking several images in one command. ' helpExpose += 'This is invoked by typing "expose imageType" where imageType is either ' helpExpose += 'bias, dark, flat, or object. Use "expose help" followed by image type to ' helpExpose += 'see what arguments are needed (e.g. "expose help bias").' self.sendToStatus(helpExpose) if runList[1] == "set": helpSet = '"set" command is used to set the camera attributes of binning, temperature, and ' helpSet += 'filter position. Use "set help" followed by one of the attributes (binning, temp, ' helpSet += 'filter) to get info on the need arguements (e.g. "set help temp").' self.sendToStatus(helpSet) if runList[1] == "filter": helpFilter = '"filter" command is used to control the filter attributes.' self.sendToStatus(helpFilter) else: print("something went wrong") print(runList) dialog = wx.MessageDialog(None, runList, "", wx.OK | wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() self.commandBox.SetFocus()
def sendToStatus(self, string): send = als.timeStamp() send += " " + string wx.CallAfter(self.threadSafeScriptingStatus, send)
def onExpose(self, event): """ Executes when the expose button is pressed. It checks that the variable self.exposeToSend is a float. It it passes then this value is sent to Evora. If it fails a dialog box tells the user the varible is not a number and will not send it to Evora. """ if als.isNumber(self.timeToSend): if(float(self.timeToSend) < 0): dialog = wx.MessageDialog(None, "Exposure time can not be less than 0...will not expose", "", wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() else: dialog = wx.MessageDialog(None, "Exposure time not a number...will not expose.", "", wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialong.Destroy() if self.nameToSend is "": dialog = wx.MessageDialog(None,"No name was given...will not expose", "", wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() else: pass if als.isNumber(self.timeToSend) and self.nameToSend is not "": #self.protocol.sendLine("Exposing with name " + str(self.nameToSend) + " and time " + str(self.timeToSend) + " s") line = self.getAttributesToSend().split() # get image type imType = int(line[0]) itime = float(line[3]) #self.expButton.SetLabel("Abort") if(imType == 1): # single exposure self.expButton.Enable(False) self.stopExp.Enable(True) self.abort = True line = " ".join(line[1:]) # bring all the parameters together d = self.protocol.sendCommand("expose " + line) d.addCallback(self.expose_callback_thread) thread.start_new_thread(self.exposeTimer, (itime,)) if(imType == 2): # real time exposure self.expButton.Enable(False) self.stopExp.Enable(True) self.abort = True line = " ".join(line[1:]) # start callback that looks for a path leading to a real image d = self.protocol.addDeferred("realSent") d.addCallback(self.displayRealImage_thread) d = self.protocol.sendCommand("real " + line) d.addCallback(self.realCallback) # this will clear the image path queue # start timer thread.start_new_thread(self.exposeTimer, (itime,)) if(imType == 3): # series exposure dialog = wx.TextEntryDialog(None, "How many exposure?", "Entry", "1", wx.OK | wx.CANCEL) answer = dialog.ShowModal() dialog.Destroy() if answer == wx.ID_OK: self.seriesImageNumber = dialog.GetValue() if(als.isInt(self.seriesImageNumber)): print "Number of image to be taken:", int(self.seriesImageNumber) self.expButton.Enable(False) self.stopExp.Enable(True) self.abort = True line[2] = self.seriesImageNumber line = " ".join(line[1:]) d = self.protocol.addDeferred("seriesSent") d.addCallback(self.displaySeriesImage_thread) d = self.protocol.sendCommand("series " + str(line)) d.addCallback(self.seriesCallback) # start timer thread.start_new_thread(self.exposeTimer, (itime,)) else: dialog = wx.MessageDialog(None, "Entry was not a valid integer!", "", wx.OK | wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy()