Example #1
0
 def _poll_exposure(self, readout_args):
     timer = CountdownTimer(duration=self._timeout)
     try:
         try:
             # See if the command has finished.
             while self._exposure_proc.poll() is None:
                 # Sleep if not done yet.
                 timer.sleep()
         except subprocess.TimeoutExpired:
             self.logger.warning(
                 f'Timeout on exposure process for {self.name}')
             self._exposure_proc.kill()
             outs, errs = self._exposure_proc.communicate(timeout=10)
             if errs is not None and errs > '':
                 self.logger.error(f'Camera exposure errors: {errs}')
     except (RuntimeError, error.PanError) as err:
         # Error returned by driver at some point while polling
         self.logger.error(
             'Error while waiting for exposure on {}: {}'.format(self, err))
         raise err
     else:
         # Camera type specific readout function
         self._readout(*readout_args)
     finally:
         self.logger.debug(f'Setting exposure event for {self.name}')
         self._exposure_proc = None
         self._is_exposing_event.clear(
         )  # Make sure this gets set regardless of readout errors
Example #2
0
def test_countdown_timer_non_blocking():
    timer = CountdownTimer(0)
    assert timer.is_non_blocking
    assert timer.time_left() == 0

    for arg, expected_duration in [(2, 2.0), (0.5, 0.5), (1 * u.second, 1.0)]:
        timer = CountdownTimer(arg)
        assert timer.duration == expected_duration
Example #3
0
def test_countdown_timer_bad_input():
    with pytest.raises(ValueError):
        assert CountdownTimer('d')

    with pytest.raises(ValueError):
        assert CountdownTimer(current_time())

    with pytest.raises(AssertionError):
        assert CountdownTimer(-1)
Example #4
0
    def slew_to_target(self, blocking=False, timeout=180):
        """ Slews to the currently assigned target coordinates.

        Slews the mount to the coordinates that have been assigned by `~set_target_coordinates`.
        If no coordinates have been set, do nothing and return `False`, otherwise
        return response from the mount.

        If `blocking=True` then wait for up to `timeout` seconds for the mount
        to reach the `is_tracking` state. If a timeout occurs, raise a `pocs.error.Timeout`
        exception.

        Args:
            blocking (bool, optional): If command should block while slewing to
                home, default False.
            timeout (int, optional): Maximum time spent slewing to home, default
                180 seconds.

        Returns:
            bool: indicating success
        """
        success = False

        if self.is_parked:
            self.logger.info("Mount is parked")
        elif not self.has_target:
            self.logger.info("Target Coordinates not set")
        else:
            self.logger.debug('Slewing to target')
            success = self.query('slew_to_target')

            self.logger.debug("Mount response: {}".format(success))
            if success:
                if blocking:
                    # Set up the timeout timer
                    self.logger.debug(
                        f'Setting slew timeout timer for {timeout} sec')
                    timeout_timer = CountdownTimer(timeout)
                    block_time = 3  # seconds

                    while self.is_tracking is False:
                        if timeout_timer.expired():
                            self.logger.warning(
                                f'slew_to_target timout: {timeout} seconds')
                            raise error.Timeout('Problem slewing to target')

                        self.logger.debug(
                            f'Slewing to target, sleeping for {block_time} seconds'
                        )
                        timeout_timer.sleep(max_sleep=block_time)

                    self.logger.debug(f'Done with slew_to_target block')
            else:
                self.logger.warning('Problem with slew_to_target')

        return success
Example #5
0
    def _readout(self, filename=None, header=None):
        self.logger.debug(f'Calling _readout for {self}')
        timer = CountdownTimer(duration=self.readout_time)
        # Get example FITS file from test data directory
        file_path = os.path.join(os.environ['POCS'], 'tests', 'data', 'unsolved.fits')
        fake_data = fits.getdata(file_path)

        if header.get('IMAGETYP') == 'Dark Frame':
            # Replace example data with a bunch of random numbers
            fake_data = np.random.randint(low=975, high=1026,
                                          size=fake_data.shape,
                                          dtype=fake_data.dtype)
        self.logger.debug(f'Writing filename={filename!r} for {self}')
        fits_utils.write_fits(fake_data, header, filename)

        # Sleep for the remainder of the readout time.
        timer.sleep()
Example #6
0
 def get_periodic_status():
     while self.connected:
         status = self.status
         self.logger.trace(f'Periodic status call: {status!r}')
         self.db.insert_current('status', status)
         CountdownTimer(
             self.get_config('status_check_interval',
                             default=60)).sleep()
Example #7
0
    def slew_to_home(self, blocking=False, timeout=180):
        """Slews the mount to the home position.

        Note:
            Home position and Park position are not the same thing

        Args:
            blocking (bool, optional): If command should block while slewing to
                home, default False.
            timeout (int, optional): Maximum time spent slewing to home, default 180 seconds.

        Returns:
            bool: indicating success

        Args:
            blocking (bool, optional): If command should block while slewing to
                home, default False.
        """
        response = 0

        # Set up the timeout timer
        timeout_timer = CountdownTimer(timeout)
        block_time = 3  # seconds

        if not self.is_parked:
            # Reset target coordinates
            self._target_coordinates = None
            # Start the slew
            response = self.query('slew_to_home')
            if response and blocking:
                while self.is_home is False:
                    if timeout_timer.expired():
                        self.logger.warning(
                            f'slew_to_home timout: {timeout} seconds')
                        response = 0
                        break
                    self.logger.debug(
                        f'Slewing to home, sleeping for {block_time} seconds')
                    timeout_timer.sleep(max_sleep=block_time)
        else:
            self.logger.info('Mount is parked')

        return response
Example #8
0
def test_countdown_timer_sleep_log(caplog):
    count_time = 1
    timer = CountdownTimer(count_time)
    # Default is a debug level
    timer.sleep()
    assert caplog.records[-1].levelname == 'DEBUG'
    assert caplog.records[-1].message.startswith('Sleeping for')

    timer.restart()
    timer.sleep(log_level='info')
    assert caplog.records[-1].levelname == 'INFO'
    assert caplog.records[-1].message.startswith('Sleeping for')
Example #9
0
def test_countdown_timer_sleep():
    count_time = 1
    timer = CountdownTimer(count_time)
    assert timer.time_left() > 0
    assert timer.expired() is False
    assert timer.is_non_blocking is False

    counter = 0.
    while timer.time_left() > 0.5:
        assert timer.sleep(max_sleep=0.1)
        counter += 0.1

    # Wait for the remaining half second
    assert timer.sleep() is False

    assert counter == pytest.approx(0.5)
    assert timer.time_left() == 0
    assert timer.expired() is True
    assert timer.sleep() is False
Example #10
0
 def _poll_exposure(self,
                    readout_args,
                    exposure_time,
                    timeout=None,
                    interval=0.01):
     """ Wait until camera is no longer exposing or the timeout is reached. If the timeout is
     reached, an `error.Timeout` is raised.
     """
     if timeout is None:
         timer_duration = self._timeout + self._readout_time + exposure_time.to_value(
             u.second)
     else:
         timer_duration = timeout
     self.logger.debug(
         f"Polling exposure with timeout of {timer_duration} seconds.")
     timer = CountdownTimer(duration=timer_duration)
     try:
         while self.is_exposing:
             if timer.expired():
                 msg = f"Timeout (timer.duration={timer.duration!r}) waiting for exposure on"
                 f" {self} to complete"
                 raise error.Timeout(msg)
             time.sleep(interval)
     except Exception as err:
         # Error returned by driver at some point while polling
         self.logger.error(
             f'Error while waiting for exposure on {self}: {err!r}')
         self._exposure_error = repr(err)
         raise err
     else:
         # Camera type specific readout function
         try:
             self._readout(*readout_args)
         except Exception as err:
             self.logger.error(f"Error during readout on {self}: {err!r}")
             self._exposure_error = repr(err)
             raise err
     finally:
         # Make sure this gets set regardless of any errors
         self._is_exposing_event.clear()
Example #11
0
def test_countdown_timer():
    count_time = 1
    timer = CountdownTimer(count_time)
    assert timer.time_left() > 0
    assert timer.expired() is False
    assert timer.is_non_blocking is False

    counter = 0.
    while timer.time_left() > 0:
        time.sleep(0.1)
        counter += 0.1

    assert counter == pytest.approx(1)
    assert timer.time_left() == 0
    assert timer.expired() is True
Example #12
0
    def wait(self, delay=None):
        """ Send POCS to wait.

        Loops for `delay` number of seconds. If `delay` is more than 30.0 seconds,
        then check for status signals (which are updated every 60 seconds by default).

        Keyword Arguments:
            delay {float|None} -- Number of seconds to wait. If default `None`, look up value in
                config, otherwise 2.5 seconds.
        """
        if delay is None:  # pragma: no cover
            delay = self.get_config('wait_delay', default=2.5)

        sleep_timer = CountdownTimer(delay)
        self.logger.info(f'Starting a wait timer of {delay} seconds')
        while not sleep_timer.expired() and not self.interrupted:
            self.logger.debug(
                f'Wait timer: {sleep_timer.time_left():.02f} / {delay:.02f}')
            sleep_timer.sleep(max_sleep=30)

        is_expired = sleep_timer.expired()
        self.logger.debug(f'Leaving wait timer: expired={is_expired}')
        return is_expired
Example #13
0
    def _efw_poll(self, filterwheel_ID, position, move_event, timeout):
        """
        Polls filter wheel until the current move is complete.

        Also monitors for errors while polling and checks position after the move is complete.
        Optionally sets a threading.Event to signal the end of the move. Has an optional timeout
        to raise an TimeoutError is the move takes longer than expected.

        Args:
            filterwheel_ID (int): integer ID of the filterwheel that is moving.
            position (int): position to move the filter wheel. Must be an integer >= 0.
            move_event (threading.Event, optional): Event to set once the move is complete
            timeout (u.Quantity, optional): maximum time to wait for the move to complete. Should
                be a Quantity with time units. If a numeric type without units is given seconds
                will be assumed.

            Raises:
                `panoptes.utils.error.PanError`: raised if the driver returns an error or if the final
                    position is not as expected.
                `panoptes.utils.error.Timeout`: raised if the move does not end within the period of
                    time specified by the timeout argument.
        """
        if timeout is not None:
            timer = CountdownTimer(duration=timeout)

        try:
            # No status query function in the SDK. Only way to check on progress of move
            # is to keep issuing the same move command until we stop getting the MOVING
            # error code back.
            error_code = self._CDLL.EFWSetPosition(
                ctypes.c_int(filterwheel_ID), ctypes.c_int(position))
            while error_code == ErrorCode.MOVING:
                if timeout is not None and timer.expired():
                    msg = "Timeout waiting for filterwheel {} to move to {}".format(
                        filterwheel_ID, position)
                    raise error.Timeout(msg)
                time.sleep(0.1)
                error_code = self._CDLL.EFWSetPosition(
                    ctypes.c_int(filterwheel_ID), ctypes.c_int(position))

            if error_code != ErrorCode.SUCCESS:
                # Got some sort of error while polling.
                msg = "Error while moving filterwheel {} to {}: {}".format(
                    filterwheel_ID, position,
                    ErrorCode(error_code).name)
                self.logger.error(msg)
                raise error.PanError(msg)

            final_position = self.get_position(filterwheel_ID)
            if final_position != position:
                msg = "Tried to move filterwheel {} to {}, but ended up at {}.".format(
                    filterwheel_ID, position, final_position)
                self.logger.error(msg)
                raise error.PanError(msg)

            self.logger.debug(
                f"Filter wheel {filterwheel_ID} moved to {position}.")
        finally:
            # Regardless must always set the Event when the move has stopped.
            if move_event is not None:
                move_event.set()