def test_running_backend_same_as_requested(self): # run enzel backend test.start_backend(ENZEL_CONFIG) # check if the role is enzel role = model.getMicroscope().role self.assertEqual(role, "enzel") # run enzel backend again test.start_backend(ENZEL_CONFIG) # it should still be enzel. role = model.getMicroscope().role self.assertEqual(role, "enzel")
def test_running_backend_different_from_requested(self): # run sparc backend test.start_backend(SPARC_CONFIG) # check if the role is sparc role = model.getMicroscope().role self.assertEqual(role, "sparc") # now run another backend (enzel) test.start_backend(ENZEL_CONFIG) # check if the role now is enzel instead of sparc role = model.getMicroscope().role self.assertEqual(role, "enzel")
def setUpClass(cls): try: test.start_backend(SECOM_CONFIG) except LookupError: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return except IOError as exp: logging.error(str(exp)) raise # create some streams connected to the backend cls.microscope = model.getMicroscope() cls.ccd = model.getComponent(role="ccd") cls.ebeam = model.getComponent(role="e-beam") cls.sed = model.getComponent(role="se-detector") cls.light = model.getComponent(role="light") cls.light_filter = model.getComponent(role="filter") s1 = stream.FluoStream("fluo1", cls.ccd, cls.ccd.data, cls.light, cls.light_filter) s1.excitation.value = sorted(s1.excitation.choices)[0] s2 = stream.FluoStream("fluo2", cls.ccd, cls.ccd.data, cls.light, cls.light_filter) s2.excitation.value = sorted(s2.excitation.choices)[-1] s3 = stream.BrightfieldStream("bf", cls.ccd, cls.ccd.data, cls.light) cls.streams = [s1, s2, s3]
def OnInit(self): """ Initialize the GUI This method is automatically called from the :wx:`App` constructor """ gui.legend_logo = "legend_logo_delmic.png" if self._is_standalone: microscope = None gui.icon = img.getIcon("icon/ico_gui_viewer_256.png") gui.name = odemis.__shortname__ + " Viewer" if "delphi" == self._is_standalone: gui.logo = img.getBitmap("logo_delphi.png") gui.legend_logo = "legend_logo_delphi.png" else: gui.icon = img.getIcon("icon/ico_gui_full_256.png") gui.name = odemis.__shortname__ try: microscope = model.getMicroscope() except (IOError, Pyro4.errors.CommunicationError) as e: logging.exception("Failed to connect to back-end") msg = ("The Odemis GUI could not connect to the Odemis back-end:" "\n\n{0}\n\n" "Launch user interface anyway?").format(e) answer = wx.MessageBox(msg, "Connection error", style=wx.YES | wx.NO | wx.ICON_ERROR) if answer == wx.NO: sys.exit(1) microscope = None else: if microscope.role == "delphi": gui.logo = img.getBitmap("logo_delphi.png") gui.legend_logo = "legend_logo_delphi.png" # TODO: if microscope.ghost is not empty => wait and/or display a special # "hardware status" tab. if microscope and microscope.role == "mbsem": self.main_data = guimodel.FastEMMainGUIData(microscope) else: self.main_data = guimodel.MainGUIData(microscope) # Load the main frame self.main_frame = main_xrc.xrcfr_main(None) self.init_gui() try: from odemis.gui.dev.powermate import Powermate self.dev_powermate = Powermate(self.main_data) except (LookupError, NotImplementedError) as ex: logging.debug("Not using Powermate: %s", ex) except Exception: logging.exception("Failed to load Powermate support") # Application successfully launched return True
def setUpClass(cls): if driver.get_backend_status() == driver.BACKEND_RUNNING: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return # run the backend as a daemon # we cannot run it normally as the child would also think he's in a unittest cmd = ODEMISD_CMD + ODEMISD_ARG + [SPARC_CONFIG] ret = subprocess.call(cmd) if ret != 0: logging.error("Failed starting backend with '%s'", cmd) time.sleep(1) # time to start # Find CCD & SEM components cls.microscope = model.getMicroscope() for comp in model.getComponents(): if comp.role == "ccd": cls.ccd = comp elif comp.role == "spectrometer": cls.spec = comp elif comp.role == "e-beam": cls.ebeam = comp elif comp.role == "se-detector": cls.sed = comp elif comp.role == "light": cls.light = comp elif comp.role == "filter": cls.light_filter = comp
def setUp(self): if self.backend_was_running: self.skipTest("Running backend found") self.opm = acq.path.OpticalPathManager(model.getMicroscope()) # Speed it up self.ccd.exposureTime.value = self.ccd.exposureTime.range[0] self.spccd.exposureTime.value = self.spccd.exposureTime.range[0]
def setUpClass(cls): if driver.get_backend_status() in driver.BACKEND_RUNNING: microscope = model.getMicroscope() if microscope.role != "meteor": logging.info( "There is already running backend. It will be turned off, and the backend of METEOR will be turned on." ) test.stop_backend() test.start_backend(METEOR_CONFIG) else: logging.info( "There is METEOR backend already running. It will be used." ) else: try: logging.info("METEOR backend will be turned on.") test.start_backend(METEOR_CONFIG) except Exception: raise # get the stage components cls.stage = model.getComponent(role="stage-bare") # get the metadata stage_md = cls.stage.getMetadata() cls.stage_grid_centers = stage_md[model.MD_SAMPLE_CENTERS] cls.stage_loading = stage_md[model.MD_FAV_POS_DEACTIVE]
def setUpClass(cls): if driver.get_backend_status() == driver.BACKEND_RUNNING: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return # run the backend as a daemon # we cannot run it normally as the child would also think he's in a unittest cmd = ODEMISD_CMD + ODEMISD_ARG + [SPARC_CONFIG] ret = subprocess.call(cmd) if ret != 0: logging.error("Failed starting backend with '%s'", cmd) time.sleep(1) # time to start # Find CCD & SEM components cls.microscope = model.getMicroscope() for comp in model.getComponents(): if comp.role == "ccd": cls.ccd = comp elif comp.role == "spectrometer": cls.spec = comp elif comp.role == "e-beam": cls.ebeam = comp elif comp.role == "se-detector": cls.sed = comp
def setUpClass(cls): try: test.start_backend(SPARC2_FOCUS2_CONFIG) except LookupError: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return except IOError as exp: logging.error(str(exp)) raise # find components by their role cls.ccd = model.getComponent(role="ccd0") cls.spccd = model.getComponent(role="sp-ccd3") cls.focus = model.getComponent(role="focus") cls.spgr = model.getComponent(role="spectrograph") cls.spgr_ded = model.getComponent(role="spectrograph-dedicated") cls.bl = model.getComponent(role="brightlight") cls.microscope = model.getMicroscope() cls.optmngr = path.OpticalPathManager(cls.microscope) cls.specline_ccd = stream.BrightfieldStream("Spectrograph_line_ccd", cls.ccd, cls.ccd.data, cls.bl) cls.specline_spccd = stream.BrightfieldStream( "Spectrograph line_spccd", cls.spccd, cls.spccd.data, cls.bl) # The good focus position is the start up position cls._good_focus = cls.focus.position.value["z"]
def get_backend_status(): try: # Fast path: if no back-end file, for sure, it is stopped. # The main goal is to avoid showing confusing error messages from Pyro. if not os.path.exists(model.BACKEND_FILE): return BACKEND_STOPPED model._core._microscope = None # force reset of the microscope microscope = model.getMicroscope() if not microscope.ghosts.value: return BACKEND_RUNNING else: # Not all components are working => we are "starting" (or borked) return BACKEND_STARTING except (IOError, CommunicationError): if os.path.exists(model.BACKEND_FILE): logging.debug( "No microscope found, it's sign the back-end is not responding" ) return BACKEND_DEAD else: logging.debug("Back-end %s file doesn't exists", model.BACKEND_FILE) return BACKEND_STOPPED except: logging.exception("Unresponsive back-end") return BACKEND_DEAD return BACKEND_DEAD # Note: unreachable, but leave in case code will be changed
def start_backend(config): """ Start the backend by checking the currently running backend. Basically 2 cases/scenarios: 1. If no running backend => run the requested one. 2. If there is running backend => a. If the running backend is same as requested one => do nothing b. If the running backend is different from the requested one => stop the running, and run the requested one. In case the backend fails to start a IOError will be raised. config (str): path to the microscope config file. """ # check if a backend is running if driver.get_backend_status() in (driver.BACKEND_RUNNING, driver.BACKEND_STARTING): current_model = model.getMicroscope().model try: req_model = modelgen.Instantiator(open(config)).ast except Exception as exp: raise ValueError(exp) if current_model == req_model: logging.info("Backend for %s already running", config) return else: logging.info( "There is a backend running already, it will be turned off, and the backend \ %s will be run instead.", config) stop_backend() run_backend(config) # check if no backend is running else: run_backend(config)
def __init__(self, standalone=False): """ standalone (boolean): do not try to connect to the backend """ # Replace the standard 'get_resources' with our augmented one, that # can handle more control types. See the xhandler package for more info. main_xrc.get_resources = odemis_get_resources # Declare attributes BEFORE calling the super class constructor # because it will call 'OnInit' which uses them. # HTTP documentation http server process self.http_proc = None self.main_data = None self.main_frame = None self._tab_controller = None self._is_standalone = standalone if not standalone: try: driver.speedUpPyroConnect(model.getMicroscope()) except Exception: logging.exception("Failed to speed up start up") # Output catcher using a helper class wx.App.outputWindowClass = OdemisOutputWindow # Constructor of the parent class # ONLY CALL IT AT THE END OF :py:method:`__init__` BECAUSE OnInit will # be called # and it needs the attributes defined in this constructor! wx.App.__init__(self, redirect=True)
def test_secom(self): """ Check it properly detects that a SECOM is missing a component """ # Start the backend try: broken_config_path = CONFIG_PATH + "sim/secom-sim.odm.yaml" test.start_backend(broken_config_path) except LookupError: logging.info("A running backend is already found, skipping tests") self.skipTest("Running backend found") except IOError as exp: logging.error(str(exp)) raise # Check it fails microscope = model.getMicroscope() gdata = MainGUIData(microscope) self.assertEqual(gdata.microscope, microscope) self.assertEqual(gdata.role, microscope.role) self.assertIsInstance(gdata.ccd, model.ComponentBase) self.assertIn(gdata.ccd, gdata.ccds) self.assertIsInstance(gdata.stage, model.ComponentBase) self.assertIsNone(gdata.spectrograph) self.assertIsNotNone(gdata.opm) self.assertIsNotNone(gdata.settings_obs) test.stop_backend()
def setUpClass(cls): try: test.start_backend(SPARC2_FOCUS2_CONFIG) except LookupError: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return except IOError as exp: logging.error(str(exp)) raise # find components by their role cls.ccd = model.getComponent(role="ccd0") cls.spccd = model.getComponent(role="sp-ccd3") cls.focus = model.getComponent(role="focus") cls.spgr = model.getComponent(role="spectrograph") cls.spgr_ded = model.getComponent(role="spectrograph-dedicated") cls.bl = model.getComponent(role="brightlight") cls.microscope = model.getMicroscope() cls.optmngr = path.OpticalPathManager(cls.microscope) cls.specline_ccd = stream.BrightfieldStream("Spectrograph_line_ccd", cls.ccd, cls.ccd.data, cls.bl) cls.specline_spccd = stream.BrightfieldStream ("Spectrograph line_spccd", cls.spccd, cls.spccd.data, cls.bl) # The good focus position is the start up position cls._good_focus = cls.focus.position.value["z"]
def test_no_running_backend(self): # check if there is no running backend backend_status = driver.get_backend_status() self.assertIn(backend_status, [driver.BACKEND_STOPPED, driver.BACKEND_DEAD]) # run enzel test.start_backend(ENZEL_CONFIG) # now check if the role is enzel role = model.getMicroscope().role self.assertEqual(role, "enzel")
def list_components(pretty=True): """ pretty (bool): if True, display with pretty-printing """ # We actually just browse as a tree the microscope try: microscope = model.getMicroscope() except Exception: raise IOError("Failed to contact the back-end") print_component_tree(microscope, pretty=pretty)
def get_detector(comp_name): """ return the actuator component with the given name comp_name (string): name of the component to find raises LookupError if the component doesn't exist other exception if there is an error while contacting the backend """ # isinstance() doesn't work, so we just list every component in microscope.detectors microscope = model.getMicroscope() return get_component_from_set(comp_name, microscope.detectors)
def setUpClass(cls): try: test.start_backend(ENZEL_CONFIG) except LookupError: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return except IOError as exp: logging.error(str(exp)) raise # create some streams connected to the backend cls.microscope = model.getMicroscope() cls.ccd = model.getComponent(role="ccd") cls.ebeam = model.getComponent(role="e-beam") cls.sed = model.getComponent(role="se-detector") cls.light = model.getComponent(role="light") cls.focus = model.getComponent(role="focus") cls.light_filter = model.getComponent(role="filter") cls.stage = model.getComponent(role="stage") # Make sure the lens is referenced cls.focus.reference({'z'}).result() # The 5DoF stage is not referenced automatically, so let's do it now stage_axes = set(cls.stage.axes.keys()) cls.stage.reference(stage_axes).result() # Create 1 sem stream and 2 fm streams to be used in testing ss1 = stream.SEMStream( "sem1", cls.sed, cls.sed.data, cls.ebeam, emtvas={"dwellTime", "scale", "magnification", "pixelSize"}) cls.ccd.exposureTime.value = cls.ccd.exposureTime.range[0] # go fast fs1 = stream.FluoStream("fluo1", cls.ccd, cls.ccd.data, cls.light, cls.light_filter, focuser=cls.focus) fs1.excitation.value = sorted(fs1.excitation.choices)[0] fs2 = stream.FluoStream("fluo2", cls.ccd, cls.ccd.data, cls.light, cls.light_filter, focuser=cls.focus) fs2.excitation.value = sorted(fs2.excitation.choices)[-1] cls.sem_streams = [ss1] cls.fm_streams = [fs1, fs2]
def getCurrentPositionLabel(current_pos, stage): """ Determine where lies the current stage position :param current_pos: (dict str->float) Current position of the stage :param stage: (Actuator) the stage component :return: (int) a value representing stage position from the constants LOADING, IMAGING, TILTED, COATING..etc """ role = model.getMicroscope().role if role == 'enzel': return _getCurrentEnzelPositionLabel(current_pos, stage) elif role == 'meteor': return _getCurrentMeteorPositionLabel(current_pos, stage) else: raise LookupError("Unhandled microscope role %s" % role)
def setUpClass(cls): if TEST_NOHW is True: raise unittest.SkipTest( "No simulator running or HW present. Skip fastem ROA tests.") # get the hardware components cls.microscope = model.getMicroscope() cls.asm = model.getComponent(role="asm") cls.mppc = model.getComponent(role="mppc") cls.multibeam = model.getComponent(role="multibeam") cls.descanner = model.getComponent(role="descanner") cls.stage = model.getComponent( role="stage" ) # TODO replace with stage-scan when ROA conversion method available cls.stage.reference({"x", "y"}).result()
def __init__(self, standalone=False, file_name=None): """ Args: standalone: (bool or str) False, if not standalone, name string otherwise file_name: (str) Path to the file to open on launch """ # Replace the standard 'get_resources' with our augmented one, that # can handle more control types. See the xhandler package for more info. main_xrc.get_resources = odemis_get_resources # Declare attributes BEFORE calling the super class constructor # because it will call 'OnInit' which uses them. self.main_data = None self.main_frame = None self.tab_controller = None self._is_standalone = standalone self._snapshot_controller = None self._menu_controller = None self.plugins = [] # List of instances of plugin.Plugins # User input devices self.dev_powermate = None l = logging.getLogger() self.log_level = l.getEffectiveLevel() if not self._is_standalone: try: driver.speedUpPyroConnect(model.getMicroscope()) except Exception: logging.exception("Failed to speed up start up") # Output catcher using a helper class wx.App.outputWindowClass = OdemisOutputWindow # Constructor of the parent class # ONLY CALL IT AT THE END OF :py:method:`__init__` BECAUSE OnInit will # be called # and it needs the attributes defined in this constructor! wx.App.__init__(self, redirect=True) if file_name: tab = self.main_data.getTabByName('analysis') self.main_data.tab.value = tab wx.CallLater(500, tab.load_data, file_name)
def list_components(pretty=True): """ pretty (bool): if True, display with pretty-printing """ # Show the root first, and don't use it for the graph, because its "children" # are actually "dependencies", and it'd multiple parents in the graph. microscope = model.getMicroscope() subcomps = model.getComponents() - {microscope} print_component(microscope, pretty) if pretty: graph = build_graph_children(subcomps) print_component_graph(graph, pretty, 1) else: # The "pretty" code would do the same, but much slower for c in subcomps: print_component(c, pretty)
def test_speedUpPyroConnect(self): need_stop = False if driver.get_backend_status() != driver.BACKEND_RUNNING: need_stop = True cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_CONFIG] ret = subprocess.call(cmd) if ret != 0: logging.error("Failed starting backend with '%s'", cmd) time.sleep(1) # time to start else: model._components._microscope = None # force reset of the microscope for next connection speedUpPyroConnect(model.getMicroscope()) if need_stop: cmd = ODEMISD_CMD + ["--kill"] subprocess.call(cmd)
def get_backend_status(): try: model._core._microscope = None # force reset of the microscope microscope = model.getMicroscope() if len(microscope.name) > 0: return BACKEND_RUNNING except (IOError, CommunicationError): logging.info("Failed to find microscope") if os.path.exists(model.BACKEND_FILE): return BACKEND_DEAD else: logging.info("Back-end %s file doesn't exists", model.BACKEND_FILE) return BACKEND_STOPPED except: logging.exception("Unresponsive back-end") return BACKEND_DEAD return BACKEND_DEAD
def test_speedUpPyroConnect(self): try: test.start_backend(SECOM_CONFIG) need_stop = True except LookupError: logging.info("A running backend is already found, will not stop it") need_stop = False except IOError as exp: logging.error(str(exp)) raise model._components._microscope = None # force reset of the microscope for next connection speedUpPyroConnect(model.getMicroscope()) time.sleep(2) if need_stop: test.stop_backend()
def test_speedUpPyroConnect(self): try: test.start_backend(SECOM_CONFIG) need_stop = True except LookupError: logging.info( "A running backend is already found, will not stop it") need_stop = False except IOError as exp: logging.error(str(exp)) raise model._components._microscope = None # force reset of the microscope for next connection speedUpPyroConnect(model.getMicroscope()) time.sleep(2) if need_stop: test.stop_backend()
def wait_backend_ready(): """ Wait until the backend is ready of clearly failed return (bool): True if the backend is ready, False if it failed to start """ left = 30 # s tstart = time.time() # First, wait a bit to make sure the backend is started sys.stdout.write(" Sleeping for {0} seconds...\r".format(left)) time.sleep(5) left -= 5 try: model._core._microscope = None # force reset of the microscope microscope = model.getMicroscope() nghosts = len(microscope.ghosts.value) # Components still to start except Exception: logging.error("Back-end unreachable") return False try: while left > 0: left -= 1 sys.stdout.flush() sys.stdout.write(" Sleeping for {0} seconds...\r".format(left)) time.sleep(1) # TODO: detect the backend stopped prev_nghosts = nghosts nghosts = len(microscope.ghosts.value) if nghosts == 0: break # Everything is started elif nghosts < prev_nghosts: # Allow to wait 3 s more per component started left += 3 * (prev_nghosts - nghosts) print logging.info("Back-end took %d s to start", time.time() - tstart) except KeyboardInterrupt: print "\n Sleep interrupted..." return True
def setUpClass(cls): try: test.start_backend(SPARC_CONFIG) except LookupError: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return except IOError as exp: logging.error(str(exp)) raise # Find CCD & SEM components cls.microscope = model.getMicroscope() cls.ccd = model.getComponent(role="ccd") cls.spec = model.getComponent(role="spectrometer") cls.ebeam = model.getComponent(role="e-beam") cls.sed = model.getComponent(role="se-detector") cls.lenswitch = model.getComponent(role="lens-switch") cls.spec_det_sel = model.getComponent(role="spec-det-selector") cls.ar_spec_sel = model.getComponent(role="ar-spec-selector")
def setUpClass(cls): try: test.start_backend(CRYOSECOM_CONFIG) except LookupError: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return except IOError as exp: logging.error(str(exp)) raise # create some streams connected to the backend cls.microscope = model.getMicroscope() cls.ccd = model.getComponent(role="ccd") cls.ebeam = model.getComponent(role="e-beam") cls.sed = model.getComponent(role="se-detector") cls.light = model.getComponent(role="light") cls.focus = model.getComponent(role="focus") cls.light_filter = model.getComponent(role="filter") cls.stage = model.getComponent(role="stage") # Create 1 sem stream and 2 fm streams to be used in testing ss1 = stream.SEMStream( "sem1", cls.sed, cls.sed.data, cls.ebeam, emtvas={"dwellTime", "scale", "magnification", "pixelSize"}) fs1 = stream.FluoStream("fluo1", cls.ccd, cls.ccd.data, cls.light, cls.light_filter, focuser=cls.focus) fs1.excitation.value = sorted(fs1.excitation.choices)[0] fs2 = stream.FluoStream("fluo2", cls.ccd, cls.ccd.data, cls.light, cls.light_filter) fs2.excitation.value = sorted(fs2.excitation.choices)[-1] cls.sem_streams = [ss1] cls.fm_streams = [fs1, fs2]
def stop_move(): """ stop the move of every axis of every actuators """ # We actually just browse as a tree the microscope try: microscope = model.getMicroscope() actuators = microscope.actuators except Exception: logging.error("Failed to contact the back-end") return 127 ret = 0 for actuator in actuators: try: actuator.stop() except Exception: logging.error("Failed to stop actuator %s", actuator.name) ret = 127 return ret
def get_backend_status(): try: model._core._microscope = None # force reset of the microscope microscope = model.getMicroscope() if not microscope.ghosts.value: return BACKEND_RUNNING else: # Not all components are working => we are "starting" (or borked) return BACKEND_STARTING except (IOError, CommunicationError): logging.info("Failed to find microscope") if os.path.exists(model.BACKEND_FILE): return BACKEND_DEAD else: logging.info("Back-end %s file doesn't exists", model.BACKEND_FILE) return BACKEND_STOPPED except: logging.exception("Unresponsive back-end") return BACKEND_DEAD return BACKEND_DEAD
def get_backend_status(): try: model._core._microscope = None # force reset of the microscope microscope = model.getMicroscope() if not microscope.ghosts.value: return BACKEND_RUNNING else: # Not all components are working => we are "starting" (or borked) return BACKEND_STARTING except (IOError, CommunicationError): if os.path.exists(model.BACKEND_FILE): logging.debug("No microscope found, it's sign the back-end is not responding") return BACKEND_DEAD else: logging.debug("Back-end %s file doesn't exists", model.BACKEND_FILE) return BACKEND_STOPPED except: logging.exception("Unresponsive back-end") return BACKEND_DEAD return BACKEND_DEAD # Note: unreachable, but leave in case code will be changed
def test_secom_missing_stage(self): """ Check it properly detects that a SECOM is missing a component """ # Start the backend try: broken_config_path = os.path.dirname( __file__) + "/secom-sim-no-stage.odm.yaml" test.start_backend(broken_config_path) except LookupError: logging.info("A running backend is already found, skipping tests") self.skipTest("Running backend found") except IOError as exp: logging.error(str(exp)) raise # Check it fails microscope = model.getMicroscope() with self.assertRaises(KeyError): MainGUIData(microscope) test.stop_backend()
def wait_backend_ready(): """ Wait until the backend is ready of clearly failed return (bool): True if the backend is ready, False if it failed to start """ left = 30 # s tstart = time.time() # First, wait a bit to make sure the backend is started logging.info("Sleeping for %g seconds...", left) time.sleep(5) left -= 5 try: model._core._microscope = None # force reset of the microscope microscope = model.getMicroscope() nghosts = len(microscope.ghosts.value) # Components still to start except Exception: logging.error("Back-end unreachable, probably failed to start") return False try: while left > 0: left -= 1 time.sleep(1) # TODO: detect the backend stopped prev_nghosts = nghosts nghosts = len(microscope.ghosts.value) if nghosts == 0: break # Everything is started elif nghosts < prev_nghosts: # Allow to wait 3 s more per component started left += 3 * (prev_nghosts - nghosts) logging.info("Back-end took %d s to start", time.time() - tstart) except KeyboardInterrupt: logging.info("Sleep interrupted...") return True
def OnInit(self): """ Application initialization, automatically run from the :wx:`App` constructor. """ if self._is_standalone: microscope = None else: try: microscope = model.getMicroscope() except (IOError, Pyro4.errors.CommunicationError), e: logging.exception("Failed to connect to back-end") msg = ("The Odemis GUI could not connect to the Odemis back-end:" "\n\n{0}\n\n" "Launch user interface anyway?").format(e) answer = wx.MessageBox(msg, "Connection error", style=wx.YES | wx.NO | wx.ICON_ERROR) if answer == wx.NO: sys.exit(1) microscope = None
def setUpClass(cls): if driver.get_backend_status() == driver.BACKEND_RUNNING: logging.info("A running backend is already found, skipping tests") cls.backend_was_running = True return # run the backend as a daemon # we cannot run it normally as the child would also think he's in a unittest cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_CONFIG] ret = subprocess.call(cmd) if ret != 0: logging.error("Failed starting backend with '%s'", cmd) time.sleep(1) # time to start # create some streams connected to the backend cls.microscope = model.getMicroscope() for comp in model.getComponents(): if comp.role == "ccd": cls.ccd = comp elif comp.role == "spectrometer": cls.spec = comp elif comp.role == "e-beam": cls.ebeam = comp elif comp.role == "se-detector": cls.sed = comp elif comp.role == "light": cls.light = comp elif comp.role == "filter": cls.light_filter = comp s1 = stream.FluoStream("fluo1", cls.ccd, cls.ccd.data, cls.light, cls.light_filter) s2 = stream.FluoStream("fluo2", cls.ccd, cls.ccd.data, cls.light, cls.light_filter) s2.excitation.value = s2.excitation.range[1] s3 = stream.BrightfieldStream("bf", cls.ccd, cls.ccd.data, cls.light) cls.streams = [s1, s2, s3]
def acquire_spec(wls, wle, res, dt, filename): """ wls (float): start wavelength in m wle (float): end wavelength in m res (int): number of points to acquire dt (float): dwell time in seconds filename (str): filename to save to """ # TODO: take a progressive future to update and know if it's the end ebeam = model.getComponent(role="e-beam") sed = model.getComponent(role="se-detector") mchr = model.getComponent(role="monochromator") try: sgrh = model.getComponent(role="spectrograph") except LookupError: sgrh = model.getComponent(role="spectrograph-dedicated") opm = acq.path.OpticalPathManager(model.getMicroscope()) prev_dt = ebeam.dwellTime.value prev_res = ebeam.resolution.value prev_scale = ebeam.scale.value prev_trans = ebeam.translation.value prev_wl = sgrh.position.value["wavelength"] # Create a stream for monochromator scan mchr_s = MonochromatorScanStream("Spectrum", mchr, ebeam, sgrh, opm=opm) mchr_s.startWavelength.value = wls mchr_s.endWavelength.value = wle mchr_s.numberOfPixels.value = res mchr_s.dwellTime.value = dt mchr_s.emtTranslation.value = ebeam.translation.value # Create SEM survey stream survey_s = stream.SEMStream("Secondary electrons survey", sed, sed.data, ebeam, emtvas={"translation", "scale", "resolution", "dwellTime"}, ) # max FoV, with scale 4 survey_s.emtTranslation.value = (0, 0) survey_s.emtScale.value = (4, 4) survey_s.emtResolution.value = (v / 4 for v in ebeam.resolution.range[1]) survey_s.emtDwellTime.value = 10e-6 # 10µs is hopefully enough # Acquire using the acquisition manager # Note: the monochromator scan stream is unknown to the acquisition manager, # so it'll be done last expt = acq.estimateTime([survey_s, mchr_s]) f = acq.acquire([survey_s, mchr_s]) try: # Note: the timeout is important, as it allows to catch KeyboardInterrupt das, e = f.result(2 * expt + 1) except KeyboardInterrupt: logging.info("Stopping before end of acquisition") f.cancel() return finally: logging.debug("Restoring hardware settings") if prev_res != (1, 1): ebeam.resolution.value = prev_res ebeam.dwellTime.value = prev_dt sgrh.moveAbs({"wavelength": prev_wl}) ebeam.scale.value = prev_scale ebeam.translation.value = prev_trans if prev_res != (1, 1): ebeam.resolution.value = prev_res ebeam.dwellTime.value = prev_dt if e: logging.error("Acquisition failed: %s", e) if das: # Save the file exporter = dataio.find_fittest_converter(filename) exporter.export(filename, das) logging.info("Spectrum successfully saved to %s", filename) raw_input("Press Enter to close.")
def OnInit(self): """ Initialize the GUI This method is automatically called from the :wx:`App` constructor """ gui.legend_logo = "legend_logo_delmic.png" if self._is_standalone: microscope = None gui.icon = img.getIcon("icon/ico_gui_viewer_256.png") gui.name = odemis.__shortname__ + " Viewer" if "delphi" == self._is_standalone: gui.logo = img.getBitmap("logo_delphi.png") gui.legend_logo = "legend_logo_delphi.png" else: gui.icon = img.getIcon("icon/ico_gui_full_256.png") gui.name = odemis.__shortname__ try: microscope = model.getMicroscope() except (IOError, Pyro4.errors.CommunicationError) as e: logging.exception("Failed to connect to back-end") msg = ("The Odemis GUI could not connect to the Odemis back-end:" "\n\n{0}\n\n" "Launch user interface anyway?").format(e) answer = wx.MessageBox(msg, "Connection error", style=wx.YES | wx.NO | wx.ICON_ERROR) if answer == wx.NO: sys.exit(1) microscope = None else: if microscope.role == "delphi": gui.logo = img.getBitmap("logo_delphi.png") gui.legend_logo = "legend_logo_delphi.png" logging.info("\n\n************ Starting Odemis GUI ************\n") logging.info("Odemis GUI v%s (from %s)", odemis.__version__, __file__) logging.info("wxPython v%s", wx.version()) # TODO: if microscope.ghost is not empty => wait and/or display a special # "hardware status" tab. self.main_data = guimodel.MainGUIData(microscope) # Load the main frame self.main_frame = main_xrc.xrcfr_main(None) self.init_gui() try: from odemis.gui.dev.powermate import Powermate self.dev_powermate = Powermate(self.main_data) except (LookupError, NotImplementedError) as ex: logging.debug("Not using Powermate: %s", ex) except Exception: logging.exception("Failed to load Powermate support") # Application successfully launched return True
def main(args): """ Handles the command line arguments args is the list of arguments passed return (int): value to return to the OS as program exit code """ # arguments handling parser = argparse.ArgumentParser(prog="odemis-cli", description=odemis.__fullname__) parser.add_argument('--version', dest="version", action='store_true', help="show program's version number and exit") opt_grp = parser.add_argument_group('Options') opt_grp.add_argument("--log-level", dest="loglev", metavar="<level>", type=int, default=0, help="set verbosity level (0-2, default = 0)") opt_grp.add_argument("--machine", dest="machine", action="store_true", default=False, help="display in a machine-friendly way (i.e., no pretty printing)") dm_grp = parser.add_argument_group('Microscope management') dm_grpe = dm_grp.add_mutually_exclusive_group() dm_grpe.add_argument("--kill", "-k", dest="kill", action="store_true", default=False, help="kill the running back-end") dm_grpe.add_argument("--check", dest="check", action="store_true", default=False, help="check for a running back-end (only returns exit code)") dm_grpe.add_argument("--scan", dest="scan", action="store_true", default=False, help="scan for possible devices to connect (the back-end must be stopped)") dm_grpe.add_argument("--list", "-l", dest="list", action="store_true", default=False, help="list the components of the microscope") dm_grpe.add_argument("--list-prop", "-L", dest="listprop", metavar="<component>", help="list the properties of a component") dm_grpe.add_argument("--set-attr", "-s", dest="setattr", nargs=3, action='append', metavar=("<component>", "<attribute>", "<value>"), help="set the attribute of a component (lists are delimited by commas," " dictionary keys are delimited by colon)") dm_grpe.add_argument("--move", "-m", dest="move", nargs=3, action='append', metavar=("<component>", "<axis>", "<distance>"), help=u"move the axis by the amount of µm.") dm_grpe.add_argument("--position", "-p", dest="position", nargs=3, action='append', metavar=("<component>", "<axis>", "<position>"), help=u"move the axis to the given position in µm.") dm_grpe.add_argument("--stop", "-S", dest="stop", action="store_true", default=False, help="immediately stop all the actuators in all directions.") dm_grpe.add_argument("--acquire", "-a", dest="acquire", nargs="+", metavar=("<component>", "data-flow"), help="acquire an image (default data-flow is \"data\")") dm_grp.add_argument("--output", "-o", dest="output", help="name of the file where the image should be saved after acquisition. The file format is derived from the extension (TIFF and HDF5 are supported).") dm_grpe.add_argument("--live", dest="live", nargs="+", metavar=("<component>", "data-flow"), help="display and update an image on the screen (default data-flow is \"data\")") options = parser.parse_args(args[1:]) # To allow printing unicode even with pipes ensure_output_encoding() # Cannot use the internal feature, because it doesn't support multiline if options.version: print (odemis.__fullname__ + " " + odemis.__version__ + "\n" + odemis.__copyright__ + "\n" + "Licensed under the " + odemis.__license__) return 0 # Set up logging before everything else if options.loglev < 0: parser.error("log-level must be positive.") # TODO: allow to put logging level so low that nothing is ever output loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG] loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)] # change the log format to be more descriptive handler = logging.StreamHandler() logging.getLogger().setLevel(loglev) handler.setFormatter(logging.Formatter('%(asctime)s (%(module)s) %(levelname)s: %(message)s')) logging.getLogger().addHandler(handler) # anything to do? if (not options.check and not options.kill and not options.scan and not options.list and not options.stop and options.move is None and options.position is None and options.listprop is None and options.setattr is None and options.acquire is None and options.live is None): logging.error("no action specified.") return 127 if options.acquire is not None and options.output is None: logging.error("name of the output file must be specified.") return 127 logging.debug("Trying to find the backend") status = get_backend_status() if options.check: logging.info("Status of back-end is %s", status) return status_to_xtcode[status] # scan needs to have the backend stopped if options.scan: if status == BACKEND_RUNNING: logging.error("Back-end running while trying to scan for devices") return 127 try: return scan() except Exception: logging.exception("Unexpected error while performing scan.") return 127 # check if there is already a backend running if status == BACKEND_STOPPED: logging.error("No running back-end") return 127 elif status == BACKEND_DEAD: logging.error("Back-end appears to be non-responsive.") return 127 try: if options.kill: return kill_backend() logging.debug("Executing the actions") if options.list: return list_components(pretty=not options.machine) elif options.listprop is not None: # Speed up is only worthy if many VAs are accessed odemis.util.driver.speedUpPyroConnect(model.getMicroscope()) return list_properties(options.listprop, pretty=not options.machine) elif options.setattr is not None: for c, a, v in options.setattr: ret = set_attr(c, a, v) if ret != 0: return ret elif options.position is not None: for c, a, d in options.position: ret = move_abs(c, a, d) # TODO warn if same axis multiple times if ret != 0: return ret time.sleep(0.5) elif options.move is not None: for c, a, d in options.move: ret = move(c, a, d) # TODO move commands to the same actuator should be agglomerated if ret != 0: return ret time.sleep(0.5) # wait a bit for the futures to close nicely elif options.stop: return stop_move() elif options.acquire is not None: component = options.acquire[0] if len(options.acquire) == 1: dataflows = ["data"] else: dataflows = options.acquire[1:] filename = options.output.decode(sys.getfilesystemencoding()) return acquire(component, dataflows, filename) elif options.live is not None: component = options.live[0] if len(options.live) == 1: dataflow = "data" elif len(options.live) == 2: dataflow = options.acquire[2] else: logging.error("live command accepts only one data-flow") return 127 return live_display(component, dataflow) except: logging.exception("Unexpected error while performing action.") return 127 return 0