Exemple #1
0
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        # Maps status light names to the light field/pane index.
        self._nameToField = {}  # type: typing.Dict[str, int]
        self._defaultBackgroundColour = self.GetBackgroundColour()
        self._notificationColour = wx.YELLOW

        listener = cockpit.gui.EvtEmitter(self, events.UPDATE_STATUS_LIGHT)
        listener.Bind(cockpit.gui.EVT_COCKPIT, self._OnNewStatus)

        # Some lights that we know we need.
        events.publish(events.UPDATE_STATUS_LIGHT, 'image count', '')
        events.publish(events.UPDATE_STATUS_LIGHT, 'device waiting', '')
Exemple #2
0
 def receiveData(self, action, *args):
     """This function is called when data is received from the hardware."""
     # print 'receiveData received %s' % action
     if action == 'new image':
         (image, timestamp) = args
         transform = self.transform
         if transform.rot90:
             image = np.rot90(image, transform.rot90)
         if transform.flip_h:
             image = np.fliplr(image)
         if transform.flip_v:
             image = np.flipud(image)
         events.publish('new image %s' % self.name, image, timestamp)
Exemple #3
0
 def receiveData(self, *args):
     """This function is called when data is received from the hardware."""
     (image, timestamp) = args
     if not isinstance(image, Exception):
         events.publish(events.NEW_IMAGE % self.name, image, timestamp)
     else:
         # Handle the dropped frame by publishing an empty image of the correct
         # size. Use the handler to fetch the size, as this will use a cached value,
         # if available.
         events.publish(events.NEW_IMAGE % self.name,
                        np.zeros(self.handlers[0].getImageSize(), dtype=np.int16),
                        timestamp)
         raise image
Exemple #4
0
 def updateMouseInfo(self, x, y):
     # Test that all required values have been populated. Use any(...),
     # because ```if None in [...]:``` will throw an exception when an
     # element in the list is an array with more than one element.
     if any(req is None
            for req in [self.imageData, self.imageShape, self.w, self.h]):
         return
     # First we have to convert from screen- to data-coordinates.
     coords = numpy.array(self.canvasToIndices(x, y), dtype=np.uint)
     shape = numpy.array(self.imageShape, dtype=np.uint)
     if (coords < shape).all() and (coords >= 0).all():
         value = self.imageData[coords[0], coords[1]]
         events.publish("image pixel info", coords[::-1], value)
Exemple #5
0
 def setEnabled(self, shouldEnable=True):
     try:
         self.isEnabled = self.callbacks['setEnabled'](self.name,
                                                       shouldEnable)
     except:
         self.isEnabled = False
         raise
     if self.isEnabled != shouldEnable:
         raise Exception("Problem enabling device with handler %s" % self)
     # Subscribe / unsubscribe to the prepare-for-experiment event.
     func = [events.unsubscribe, events.subscribe][shouldEnable]
     func('prepare for experiment', self.prepareForExperiment)
     events.publish(events.CAMERA_ENABLE, self, self.isEnabled)
Exemple #6
0
 def sendXYPositionUpdates(self):
     while True:
         prevX, prevY = self.positionCache[:2]
         x, y = self.getPosition(shouldUseCache=False)[:2]
         delta = abs(x - prevX) + abs(y - prevY)
         if delta < 2:
             # No movement since last time; done moving.
             for axis in [0, 1]:
                 events.publish(events.STAGE_STOPPED, '%d nanomover' % axis)
             return
         for axis in [0, 1]:
             events.publish(events.STAGE_MOVER, axis)
         time.sleep(.1)
Exemple #7
0
 def sendXYPositionUpdates(self):
     while True:
         prevX, prevY = self.positionCache[:2]
         x, y, z = self.getPosition(shouldUseCache=False)
         delta = abs(x - prevX) + abs(y - prevY)
         if delta < 2:
             # No movement since last time; done moving.
             for axis in [0, 1]:
                 events.publish('stage stopped', '%d nanomover' % axis)
             return
         for axis, val in enumerate([x, y]):
             events.publish('stage mover', '%d nanomover' % axis, axis,
                            self.axisSignMapper[axis] * val)
         time.sleep(.1)
Exemple #8
0
 def publishPosition(self):
     for i in range(3):
         events.publish('stage mover', '%d nanomover' % i, i,
                        (self.curPosition[i]))
     label = 'Stage up'
     color = (170, 170, 170)
     if 10000 < self.curPosition[2] < 16000:
         label = 'Stage middle'
         color = (255, 255, 0)
     elif self.curPosition[2] < 10000:
         label = 'Stage DOWN'
         color = (255, 0, 0)
     events.publish('update status light', 'stage vertical position', label,
                    color)
Exemple #9
0
 def sendXYPositionUpdates(self):
     prevX, prevY, prevZ = self.xyPositionCache
     while True:
         x, y, z = self.getXYPosition(shouldUseCache=False)
         delta = abs(x - prevX) + abs(y - prevY) + abs(z - prevZ)
         if delta < .3:
             # No movement since last time; done moving.
             for axis in [0, 1, 2]:
                 events.publish(events.STAGE_STOPPED, '%d PI mover' % axis)
             return
         for axis in [0, 1, 2]:
             events.publish(events.STAGE_MOVER, axis)
         (prevX, prevY, prevZ) = (x, y, z)
         time.sleep(0.1)
Exemple #10
0
 def sendXYPositionUpdates(self):
     prevX, prevY, prevZ = self.xyPositionCache
     while True:
         x, y, z = self.getXYPosition(shouldUseCache=False)
         delta = abs(x - prevX) + abs(y - prevY) + abs(z - prevZ)
         if delta < .3:
             # No movement since last time; done moving.
             for axis in [0, 1, 2]:
                 events.publish('stage stopped', '%d PI mover' % axis)
             return
         for axis, val in enumerate([x, y, z]):
             events.publish('stage mover', '%d PI mover' % axis, axis, val)
         (prevX, prevY, prevZ) = (x, y, z)
         time.sleep(0.1)
Exemple #11
0
    def ChangeStepSize(self, direction: int) -> None:
        if direction == +1:
            guess_new = SensibleNextStepSize
        elif direction == -1:
            guess_new = SensiblePreviousStepSize
        else:
            raise ValueError(
                'direction must be -1 (decrease) or +1 (increase)')
        old_step_sizes = self.GetStepSizes()
        new_step_sizes = tuple([guess_new(x) for x in old_step_sizes])
        self._step_sizes[self.curHandlerIndex] = new_step_sizes

        for axis, step_size in enumerate(self.GetStepSizes()):
            events.publish('stage step size', axis, step_size)
Exemple #12
0
    def setEnabled(self, setState):
        if self.state == deviceHandler.STATES.constant != setState:
            if 'setExposing' in self.callbacks:
                self.callbacks['setExposing'](self.name, False)

        if setState == deviceHandler.STATES.constant:
            if self.state == setState:
                # Turn off the light
                self.callbacks['setEnabled'](self.name, False)
                # Update setState since used to set self.state later
                setState = deviceHandler.STATES.disabled
                events.publish(events.LIGHT_SOURCE_ENABLE, self, False)
            else:
                # Turn on the light continuously.
                self.callbacks['setEnabled'](self.name, True)
                if 'setExposing' in self.callbacks:
                    self.callbacks['setExposing'](self.name, True)
                # We indicate that the light source is disabled to prevent
                # it being switched off by an exposure, but this event is
                # used to update controls, so we need to chain it with a
                # manual update.
                events.oneShotSubscribe(
                    events.LIGHT_SOURCE_ENABLE,
                    lambda *args: self.notifyListeners(self, setState))
                events.publish(events.LIGHT_SOURCE_ENABLE, self, False)
        elif setState == deviceHandler.STATES.enabled:
            self.callbacks['setEnabled'](self.name, True)
            events.publish(events.LIGHT_SOURCE_ENABLE, self, True)
        else:
            self.callbacks['setEnabled'](self.name, False)
            events.publish(events.LIGHT_SOURCE_ENABLE, self, False)
        self.state = setState
 def sendXYPositionUpdates(self):
     while True:
         prevX, prevY = self.xyPositionCache
         x, y = self.getXYPosition(shouldUseCache = False)
         delta = abs(x - prevX) + abs(y - prevY)
         if delta < 5.:
             # No movement since last time; done moving.
             for axis in [0, 1]:
                 events.publish(events.STAGE_STOPPED, '%d PI mover' % axis)
             with self.xyLock:
                 self.xyMotionTargets = [None, None]
             return
         for axis in [0, 1]:
             events.publish(events.STAGE_MOVER, axis)
         time.sleep(.01)
Exemple #14
0
 def wrapper(*args, **kwargs):
     wasInVideoMode = imager.amInVideoMode
     if wasInVideoMode:
         imager.shouldStopVideoMode = True
         tstart = time.time()
         while imager.amInVideoMode:
             time.sleep(0.05)
             if time.time() > tstart + 1.:
                 print("Timeout pausing video mode - abort and restart.")
                 events.publish(events.USER_ABORT)
                 break
     result = func(*args, **kwargs)
     if wasInVideoMode:
         imager.videoMode()
     return result
Exemple #15
0
 def run(self):
     prevCounts = list(self.imagesReceived)
     self.updateText()
     while not self.shouldStop:
         if prevCounts != self.imagesReceived:
             # Have received new images since the last update;
             # update the display.
             with self.imageCountLock:
                 self.updateText()
                 prevCounts = list(self.imagesReceived)
         else:
             # No images; wait a bit.
             time.sleep(.1)
     # Clear the status light.
     events.publish(events.UPDATE_STATUS_LIGHT, 'image count', '')
Exemple #16
0
    def onExit(self):
        self._SaveWindowPositions()

        try:
            events.publish("user abort")
        except Exception as e:
            cockpit.util.logger.log.error("Error during logout: %s" % e)
            cockpit.util.logger.log.error(traceback.format_exc())

        import cockpit.gui.loggingWindow
        cockpit.gui.loggingWindow.window.WriteToLogger(cockpit.util.logger.log)

        # Manually clear out any parent-less windows that still exist. This
        # can catch some windows that are spawned by WX and then abandoned,
        # typically because of bugs in the program. If we don't do this, then
        # sometimes the program will continue running, invisibly, and must
        # be killed via Task Manager.
        for window in wx.GetTopLevelWindows():
            cockpit.util.logger.log.error("Destroying %s" % window)
            window.Destroy()

        # Call any deviec onExit code to, for example, close shutters and
        # switch of lasers.
        for dev in cockpit.depot.getAllDevices():
            try:
                dev.onExit()
            except:
                pass
        # The following cleanup code used to be in main(), after App.MainLoop(),
        # where it was never reached.
        # HACK: manually exit the program. If we don't do this, then there's a small
        # possibility that non-daemonic threads (i.e. ones that don't exit when the
        # main thread exits) will hang around uselessly, forcing the program to be
        # manually shut down via Task Manager or equivalent. Why do we have non-daemonic
        # threads? That's tricky to track down. Daemon status is inherited from the
        # parent thread, and must be manually set otherwise. Since it's easy to get
        # wrong, we'll just leave this here to catch any failures to set daemon
        # status.
        badThreads = []
        for thread in threading.enumerate():
            if not thread.daemon:
                badThreads.append(thread)
        if badThreads:
            cockpit.util.logger.log.error("Still have non-daemon threads %s" %
                                          map(str, badThreads))
            for thread in badThreads:
                cockpit.util.logger.log.error(str(thread.__dict__))
        os._exit(0)
Exemple #17
0
    def deleteTilesList(self, tilesToDelete):
        for tile in tilesToDelete:
            tile.wipe()
            del self.tiles[self.tiles.index(tile)]
        self.SetCurrent(self.context)

        # Rerender all megatiles that are now invalid.
        dirtied = []
        for megaTile in self.megaTiles:
            for tile in tilesToDelete:
                if megaTile.intersectsBox(tile.box):
                    dirtied.append(megaTile)
                    break
        self.rerenderMegatiles(dirtied)
        self.Refresh()
        events.publish('mosaic update')
 def sendXYPositionUpdates(self):
     while True:
         prevX, prevY = self.xyPositionCache
         x, y = self.getXYPosition(shouldUseCache = False)
         delta = abs(x - prevX) + abs(y - prevY)
         if delta < 5.:
             # No movement since last time; done moving.
             for axis in [0, 1]:
                 events.publish('stage stopped', '%d PI mover' % axis)
             with self.xyLock:
                 self.xyMotionTargets = [None, None]
             return
         for axis, val in enumerate([x, y]):
             events.publish('stage mover', '%d PI mover' % axis, axis,
                     self.axisSignMapper[axis] * val)
         curPosition = (x, y)
         time.sleep(.01)
Exemple #19
0
 def onSaveExposureSettings(self, name, event=None):
     dialog = wx.FileDialog(
         self,
         style=wx.FD_SAVE,
         wildcard='*.txt',
         defaultFile=name + '.txt',
         message="Please select where to save the settings.",
         defaultDir=cockpit.util.files.getUserSaveDir())
     if dialog.ShowModal() != wx.ID_OK:
         # User cancelled.
         self.pathButton.setOption(name)
         return
     settings = dict()
     events.publish('save exposure settings', settings)
     handle = open(dialog.GetPath(), 'w')
     handle.write(json.dumps(settings))
     handle.close()
     self.pathButton.setOption(name)
Exemple #20
0
 def waitFor(self, seconds):
     if seconds <= 0:
         return False
     print("Waiting for %.2f seconds" % seconds)
     endTime = time.time() + seconds
     curTime = time.time()
     while curTime < endTime and not self.shouldAbort:
         if int(curTime + .25) != int(curTime):
             remaining = endTime - curTime
             # Advanced to a new second; update the status light.
             displayMinutes = remaining // 60
             displaySeconds = (remaining - displayMinutes * 60) // 1
             events.publish(events.UPDATE_STATUS_LIGHT, 'device waiting',
                            ('Waiting for %02d:%02d' %
                             (displayMinutes, displaySeconds)))
         time.sleep(.25)
         curTime = time.time()
     return True
Exemple #21
0
 def sendXYZPositionUpdates(self):
     print("foo")
     while True:
         for ch in range(2):
             if self.xyzMotionTargets[ch] is not None:
                 if (ctl.GetProperty_i32(d_handle, ch, ctl.Property.CHANNEL_STATE) & ctl.ChannelState.ACTIVELY_MOVING == 0):
                     self.xyzMotionTargets[ch] = None
                     events.publish(events.STAGE_STOPPED, '%d SmaractMover' % ch)
                     print('stopped %d\n' % ch)
                 else:
                     #print('xyzMT '+str(ch)+' '+str(self.xyzMotionTargets))
                     events.publish(events.STAGE_MOVER, ch)
                     time.sleep(0.1)
         if self.xyzMotionTargets[0] is None:
             if self.xyzMotionTargets[1] is None:
                 if self.xyzMotionTargets[2] is None:
                     print("bar")
                     return
Exemple #22
0
 def setExposureTime(self, value, outermost=True):
     ## Set the exposure time on self and update that on lights
     # that share the same shutter if this is the outermost call.
     # \param value: new exposure time
     # \param outermost: flag indicating that we should update others.
     self.callbacks['setExposureTime'](self.name, value)
     # Publish event to update control labels.
     events.publish('light exposure update', self)
     # Update exposure times for lights that share the same shutter.
     s = self.__class__.__lightToShutter.get(self, None)
     self.exposureTime = value
     if s and outermost:
         if hasattr(s, 'setExposureTime'):
             s.setExposureTime(value)
         for other in self.__class__.__shutterToLights[s].difference([self
                                                                      ]):
             other.setExposureTime(value, outermost=False)
             events.publish('light exposure update', other)
Exemple #23
0
 def setPath(self, name):
     #store current path to text file
     if name == 'Save...':
         self.onSaveExposureSettings(self.currentPath)
     #load stored path
     elif name == 'Load...':
         self.onLoadExposureSettings()
     #update settings for current path
     elif name == 'Update' and self.currentPath != None:
         events.publish('save exposure settings',
                        self.paths[self.currentPath])
         self.pathButton.setOption(self.currentPath)
     #create newe stored path with current settings.
     elif name == 'New...':
         self.createNewPath()
     else:
         events.publish('load exposure settings', self.paths[name])
         self.currentPath = name
         self.pathButton.setOption(name)
Exemple #24
0
    def videoMode(self):
        if not self.activeCameras:
            # No cameras, no video mode.
            events.publish(cockpit.events.VIDEO_MODE_TOGGLE, False)
            return
        if self.amInVideoMode:
            # Just cancel the current video mode.
            events.publish(cockpit.events.VIDEO_MODE_TOGGLE, False)
            self.stopVideo()
            return

        events.publish(cockpit.events.VIDEO_MODE_TOGGLE, True)
        self.shouldStopVideoMode = False
        self.amInVideoMode = True
        while not self.shouldStopVideoMode:
            if not self.activeLights:
                break
            # HACK: only wait for one camera.
            camera = list(self.activeCameras)[0]
            # Some cameras drop frames, i.e., takeImage() returns but
            # an image is never received.  If that happens, videoMode
            # waits forever since there's no NEW_IMAGE event hence the
            # timeout.  On top of the time to actual acquire the
            # image, we add 5 seconds for any processing and transfer
            # which should be more than enough (see issue #584).
            timeout = 5.0 + (
                (camera.getExposureTime() + camera.getTimeBetweenExposures()) /
                1000)
            try:
                events.executeAndWaitForOrTimeout(events.NEW_IMAGE %
                                                  (camera.name),
                                                  self.takeImage,
                                                  timeout,
                                                  shouldBlock=True,
                                                  shouldStopVideo=False)
            except Exception as e:
                print("Video mode failed:", e)
                events.publish(cockpit.events.VIDEO_MODE_TOGGLE, False)
                traceback.print_exc()
                break
        self.amInVideoMode = False
        events.publish(cockpit.events.VIDEO_MODE_TOGGLE, False)
Exemple #25
0
    def onIdle(self, event):
        if self.pendingImages.empty():  # or not self.IsShownOnScreen():
            return
        # Draw as many images as possible in 50ms.
        t = time.time()
        newTiles = []
        self.SetCurrent(self.context)
        while not self.pendingImages.empty() and (time.time() - t < 0.05):
            data, pos, size, scalings, layer = self.pendingImages.get()
            newTiles.append(Tile(data, pos, size, scalings, layer))
        self.tiles.extend(newTiles)
        for megaTile in self.megaTiles:
            megaTile.prerenderTiles(newTiles, self)

        self.tilesToRefresh.update(newTiles)

        self.Refresh()
        events.publish('mosaic update')
        if not self.pendingImages.empty():
            event.RequestMore()
Exemple #26
0
    def toggleState(self, *args, **kwargs):
        if self.state == STATES.enabling:
            # Already processing a previous toggle request.
            return
        getIsEnabled = getattr(self, 'getIsEnabled',
                               None) or self.callbacks.get(
                                   'getIsEnabled', None)
        setEnabled = getattr(self, 'setEnabled', None) or self.callbacks.get(
            'setEnabled', None)
        if not all([getIsEnabled, setEnabled]):
            raise Exception(
                'toggleState dependencies not implemented for %s.' % self.name)

        # Do nothing if lock locked as en/disable already in progress.
        if not self.enableLock.acquire(False):
            return
        events.publish(events.DEVICE_STATUS, self, STATES.enabling)
        try:
            setEnabled(not (getIsEnabled()))
        except Exception as e:
            events.publish(events.DEVICE_STATUS, self, STATES.error)
            raise Exception('Problem encountered en/disabling %s:\n%s' %
                            (self.name, e))
        finally:
            self.enableLock.release()
        events.publish(events.DEVICE_STATUS, self, getIsEnabled())
Exemple #27
0
    def onLoadExposureSettings(self, event=None):
        dialog = wx.FileDialog(
            self,
            style=wx.FD_OPEN,
            wildcard='*.txt',
            message="Please select the settings file to load.",
            defaultDir=cockpit.util.files.getUserSaveDir())
        if dialog.ShowModal() != wx.ID_OK:
            # User cancelled.
            self.pathButton.setOption(self.currentPath)
            return
        handle = open(dialog.GetPath(), 'r')
        modeName = os.path.splitext(os.path.basename(handle.name))[0]
        #get name for new mode
        # abuse get value dialog which will also return a string.
        name = cockpit.gui.dialogs.getNumberDialog.getNumberFromUser(
            parent=self.topPanel,
            default=modeName,
            title='New Path Name',
            prompt='Name')
        if name not in self.paths:
            self.pathList.append(name)
        self.paths[name] = json.loads('\n'.join(handle.readlines()))
        handle.close()
        events.publish('load exposure settings', self.paths[name])
        #update button list
        self.pathButton.setOptions(
            map(lambda name: (name, lambda n=name: self.setPath(n)),
                self.pathList))
        #and set button value.
        self.pathButton.setOption(name)
        self.currentPath = name

        # If we're using the listbox approach to show/hide light controls,
        # then make sure all enabled lights are shown and vice versa.
        if self.lightList is not None:
            for i, name in enumerate(self.lightList.GetItems()):
                handler = depot.getHandlerWithName(name)
                self.lightList.SetStringSelection(name, handler.getIsEnabled())
            self.onLightSelect()
Exemple #28
0
 def prepareHandlers(self):
     # Store the pre-experiment altitude.
     self.initialAltitude = cockpit.interfaces.stageMover.getPosition()[-1]
     # Ensure that we're the only ones moving things around.
     cockpit.interfaces.stageMover.waitForStop()
     # TODO: Handling multiple movers on an axis is broken. Do not proceed if
     # anything but the innermost Z mover is selected. Needs a proper fix.
     if (cockpit.interfaces.stageMover.mover.curHandlerIndex <
             len(depot.getSortedStageMovers()[2]) - 1):
         wx.MessageBox("Wrong axis mover selected.")
         raise Exception("Wrong axis mover selected.")
     # Prepare our position.
     cockpit.interfaces.stageMover.goToZ(self.altBottom, shouldBlock=True)
     self.zStart = cockpit.interfaces.stageMover.getAllPositions()[-1][-1]
     events.publish('prepare for experiment', self)
     # Prepare cameras.
     for camera in self.cameras:
         # We set the expsoure time here. This needs to be set before
         # the action table is generated, since the action table
         # uses camera.getExposureTime to figure out timings.
         exposureTime = float(self.getExposureTimeForCamera(camera))
         camera.setExposureTime(exposureTime)
Exemple #29
0
    def OnAddChannel(self, event: wx.CommandEvent) -> None:
        """Add current channel configuration to list."""
        name = wx.GetTextFromUser('Enter name for new channel:',
                                  caption='Add new channel',
                                  parent=self)
        if not name:
            return
        new_channel = {}
        events.publish('save exposure settings', new_channel)

        if name not in self._channels:
            menu = event.GetEventObject()
            self.Bind(wx.EVT_MENU, self.OnApplyChannel,
                      menu.Append(wx.ID_ANY, item=name))
        else:
            answer = wx.MessageBox('There is already a channel named "%s".'
                                   ' Replace it?' % name,
                                   caption='Channel already exists',
                                   parent=self,
                                   style=wx.YES_NO)
            if answer != wx.YES:
                return

        self._channels[name] = new_channel
Exemple #30
0
 def imageSite(self, siteId, cycleNum, experimentStart):
     events.publish(events.UPDATE_STATUS_LIGHT, 'device waiting',
                    'Waiting for stage motion')
     cockpit.interfaces.stageMover.waitForStop()
     cockpit.interfaces.stageMover.goToSite(siteId, shouldBlock=True)
     self.waitFor(float(self.delayBeforeImaging.GetValue()))
     if self.shouldAbort:
         return
     # Try casting the site ID to an int, which it probably is, so that
     # we can use %03d (fills with zeros) instead of %s (variable width,
     # so screws with sorting).
     try:
         siteId = '%03d' % int(siteId)
     except ValueError:
         # Not actually an int.
         pass
     filename = "%s_t%03d_p%s_%s" % (time.strftime(
         '%Y%m%d-%H%M',
         experimentStart), cycleNum, siteId, self.fileBase.GetValue())
     self.experimentPanel.setFilename(filename)
     start = time.time()
     events.executeAndWaitFor(events.EXPERIMENT_COMPLETE,
                              self.experimentPanel.runExperiment)
     print("Imaging took %.2fs" % (time.time() - start))