/**
   * Execute one step of the loop
   *
   * @param context
   * @param device
   * @param condition
   * @param readback
   * @param value
   * @throws Exception
   */
  private void executeStep(
      final ScanContext context,
      final Device device,
      final NumericValueCondition condition,
      final Device readback,
      double value)
      throws Exception {
    logger.log(
        Level.INFO,
        "Loop setting {0} = {1}{2}",
        new Object[] {device.getAlias(), value, (condition != null ? " (waiting)" : "")});

    // Set device to value for current step of loop
    do_skip = false;
    synchronized (this) {
      thread = Thread.currentThread();
    }
    try {
      if (command.getCompletion())
        device.write(value, TimeDuration.ofSeconds(command.getTimeout()));
      else device.write(value);

      // .. wait for device to reach value
      if (condition != null) {
        condition.setDesiredValue(value);
        condition.await();
      }

      // Log the device's value?
      if (context.isAutomaticLogMode()) {
        final DataLog log = context.getDataLog().get();
        final long serial = log.getNextScanDataSerial();
        log.log(readback.getAlias(), VTypeHelper.createSample(serial, readback.read()));
      }
    } catch (InterruptedException ex) { // Ignore if 'next' was requested
      if (!do_skip) throw ex;
    } finally {
      synchronized (this) {
        thread = null;
      }
    }

    // Execute loop body or show some estimate of progress
    // (not including nested commands)
    if (do_skip) context.workPerformed(implementation.size());
    else context.execute(implementation);

    // If there are no commands that inc. the work units, do it yourself
    if (implementation.size() <= 0) context.workPerformed(1);
  }