All Downloads are FREE. Search and download functionalities are using the official Maven repository.

zaber.motion.ascii.Stream Maven / Gradle / Ivy

Go to download

A library that aims to provide easy-to-use API for communication with Zaber devices using Zaber ASCII Protocol.

There is a newer version: 6.7.0
Show newest version
// ===== THIS FILE IS GENERATED FROM A TEMPLATE ===== //
// ============== DO NOT EDIT DIRECTLY ============== //

package zaber.motion.ascii;

import zaber.motion.ArrayUtility;
import zaber.motion.Units;
import zaber.motion.Measurement;
import zaber.motion.protobufs.Main;
import zaber.motion.gateway.Call;
import zaber.motion.RotationDirection;
import zaber.motion.exceptions.MotionLibException;

import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * A handle for a stream with this ID on the device.
 * Streams provide a way to execute or store a sequence of actions.
 * Stream methods append actions to a queue which executes or stores actions in a first in, first out order.
 */
public class Stream {
    private Device device;

    /**
     * @return Device that controls this stream.
     */
    public Device getDevice() {
        return this.device;
    }

    private int streamId;

    /**
     * @return The number that identifies the stream on the device.
     */
    public int getStreamId() {
        return this.streamId;
    }


    /**
     * @return Current mode of the stream.
     */
    public StreamMode getMode() {
        return this.retrieveMode();
    }


    /**
     * @return An array of axes definitions the stream is set up to control.
     */
    public StreamAxisDefinition[] getAxes() {
        return this.retrieveAxes();
    }

    public Stream(
        Device device, int streamId) {
        this.device = device;
        this.streamId = streamId;
    }

    /**
     * Setup the stream to control the specified axes and to queue actions on the device.
     * Allows use of lockstep axes in a stream.
     * @param axes Definition of the stream axes.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setupLiveCompositeAsync(
        StreamAxisDefinition... axes) {
        Main.StreamSetupLiveCompositeRequest.Builder builder = Main.StreamSetupLiveCompositeRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.addAllAxes(Arrays.asList(axes).stream()
            .map(a -> StreamAxisDefinition.toProtobuf(a)).collect(Collectors.toList()));
        return Call.callAsync("device/stream_setup_live_composite", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Setup the stream to control the specified axes and to queue actions on the device.
     * Allows use of lockstep axes in a stream.
     * @param axes Definition of the stream axes.
     */
    public void setupLiveComposite(
        StreamAxisDefinition... axes) {
        try {
            setupLiveCompositeAsync(axes).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Setup the stream to control the specified axes and to queue actions on the device.
     * @param axes Numbers of physical axes to setup the stream on.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setupLiveAsync(
        int... axes) {
        Main.StreamSetupLiveRequest.Builder builder = Main.StreamSetupLiveRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.addAllAxes(
            Arrays.asList(ArrayUtility.toObjectArray(axes))
        );
        return Call.callAsync("device/stream_setup_live", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Setup the stream to control the specified axes and to queue actions on the device.
     * @param axes Numbers of physical axes to setup the stream on.
     */
    public void setupLive(
        int... axes) {
        try {
            setupLiveAsync(axes).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Setup the stream to control the specified axes and queue actions into a stream buffer.
     * Allows use of lockstep axes in a stream.
     * @param streamBuffer The stream buffer to queue actions in.
     * @param axes Definition of the stream axes.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setupStoreCompositeAsync(
        StreamBuffer streamBuffer, StreamAxisDefinition... axes) {
        Main.StreamSetupStoreCompositeRequest.Builder builder = Main.StreamSetupStoreCompositeRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setStreamBuffer(streamBuffer.getBufferId());
        builder = builder.addAllAxes(Arrays.asList(axes).stream()
            .map(a -> StreamAxisDefinition.toProtobuf(a)).collect(Collectors.toList()));
        return Call.callAsync("device/stream_setup_store_composite", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Setup the stream to control the specified axes and queue actions into a stream buffer.
     * Allows use of lockstep axes in a stream.
     * @param streamBuffer The stream buffer to queue actions in.
     * @param axes Definition of the stream axes.
     */
    public void setupStoreComposite(
        StreamBuffer streamBuffer, StreamAxisDefinition... axes) {
        try {
            setupStoreCompositeAsync(streamBuffer, axes).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Setup the stream to control the specified axes and queue actions into a stream buffer.
     * @param streamBuffer The stream buffer to queue actions in.
     * @param axes Numbers of physical axes to setup the stream on.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setupStoreAsync(
        StreamBuffer streamBuffer, int... axes) {
        Main.StreamSetupStoreRequest.Builder builder = Main.StreamSetupStoreRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setStreamBuffer(streamBuffer.getBufferId());
        builder = builder.addAllAxes(
            Arrays.asList(ArrayUtility.toObjectArray(axes))
        );
        return Call.callAsync("device/stream_setup_store", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Setup the stream to control the specified axes and queue actions into a stream buffer.
     * @param streamBuffer The stream buffer to queue actions in.
     * @param axes Numbers of physical axes to setup the stream on.
     */
    public void setupStore(
        StreamBuffer streamBuffer, int... axes) {
        try {
            setupStoreAsync(streamBuffer, axes).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Setup the stream to use a specified number of axes, and to queue actions in a stream buffer.
     * Afterwards, you may call the resulting stream buffer on arbitrary axes.
     * This mode does not allow for unit conversions.
     * @param streamBuffer The stream buffer to queue actions in.
     * @param axesCount The number of axes in the stream.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setupStoreArbitraryAxesAsync(
        StreamBuffer streamBuffer, int axesCount) {
        Main.StreamSetupStoreArbitraryAxesRequest.Builder builder = Main.StreamSetupStoreArbitraryAxesRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setStreamBuffer(streamBuffer.getBufferId());
        builder = builder.setAxesCount(axesCount);
        return Call.callAsync("device/stream_setup_store_arbitrary_axes", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Setup the stream to use a specified number of axes, and to queue actions in a stream buffer.
     * Afterwards, you may call the resulting stream buffer on arbitrary axes.
     * This mode does not allow for unit conversions.
     * @param streamBuffer The stream buffer to queue actions in.
     * @param axesCount The number of axes in the stream.
     */
    public void setupStoreArbitraryAxes(
        StreamBuffer streamBuffer, int axesCount) {
        try {
            setupStoreArbitraryAxesAsync(streamBuffer, axesCount).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Append the actions in a stream buffer to the queue.
     * @param streamBuffer The stream buffer to call.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture callAsync(
        StreamBuffer streamBuffer) {
        Main.StreamCallRequest.Builder builder = Main.StreamCallRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setStreamBuffer(streamBuffer.getBufferId());
        return Call.callAsync("device/stream_call", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Append the actions in a stream buffer to the queue.
     * @param streamBuffer The stream buffer to call.
     */
    public void call(
        StreamBuffer streamBuffer) {
        try {
            callAsync(streamBuffer).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue an absolute line movement in the stream.
     * @param endpoint Positions for the axes to move to, relative to their home positions.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture lineAbsoluteAsync(
        Measurement... endpoint) {
        Main.StreamLineRequest.Builder builder = Main.StreamLineRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamLineRequest.Type.ABS);

        builder = builder.addAllEndpoint(Arrays.asList(endpoint).stream()
            .map(p -> Measurement.toProtobuf(p)).collect(Collectors.toList()));
        return Call.callAsync("device/stream_line", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue an absolute line movement in the stream.
     * @param endpoint Positions for the axes to move to, relative to their home positions.
     */
    public void lineAbsolute(
        Measurement... endpoint) {
        try {
            lineAbsoluteAsync(endpoint).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue a relative line movement in the stream.
     * @param endpoint Positions for the axes to move to, relative to their positions before movement.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture lineRelativeAsync(
        Measurement... endpoint) {
        Main.StreamLineRequest.Builder builder = Main.StreamLineRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamLineRequest.Type.REL);

        builder = builder.addAllEndpoint(Arrays.asList(endpoint).stream()
            .map(p -> Measurement.toProtobuf(p)).collect(Collectors.toList()));
        return Call.callAsync("device/stream_line", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue a relative line movement in the stream.
     * @param endpoint Positions for the axes to move to, relative to their positions before movement.
     */
    public void lineRelative(
        Measurement... endpoint) {
        try {
            lineRelativeAsync(endpoint).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue an absolute line movement in the stream, targeting a subset of the stream axes.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param endpoint Positions for the axes to move to, relative to their home positions.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture lineAbsoluteOnAsync(
        int[] targetAxesIndices, Measurement[] endpoint) {
        Main.StreamLineRequest.Builder builder = Main.StreamLineRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamLineRequest.Type.ABS);

        builder = builder.addAllTargetAxesIndices(
            Arrays.asList(ArrayUtility.toObjectArray(targetAxesIndices))
        );
        builder = builder.addAllEndpoint(Arrays.asList(endpoint).stream()
            .map(p -> Measurement.toProtobuf(p)).collect(Collectors.toList()));
        return Call.callAsync("device/stream_line", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue an absolute line movement in the stream, targeting a subset of the stream axes.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param endpoint Positions for the axes to move to, relative to their home positions.
     */
    public void lineAbsoluteOn(
        int[] targetAxesIndices, Measurement[] endpoint) {
        try {
            lineAbsoluteOnAsync(targetAxesIndices, endpoint).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue a relative line movement in the stream, targeting a subset of the stream axes.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param endpoint Positions for the axes to move to, relative to their positions before movement.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture lineRelativeOnAsync(
        int[] targetAxesIndices, Measurement[] endpoint) {
        Main.StreamLineRequest.Builder builder = Main.StreamLineRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamLineRequest.Type.REL);

        builder = builder.addAllTargetAxesIndices(
            Arrays.asList(ArrayUtility.toObjectArray(targetAxesIndices))
        );
        builder = builder.addAllEndpoint(Arrays.asList(endpoint).stream()
            .map(p -> Measurement.toProtobuf(p)).collect(Collectors.toList()));
        return Call.callAsync("device/stream_line", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue a relative line movement in the stream, targeting a subset of the stream axes.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param endpoint Positions for the axes to move to, relative to their positions before movement.
     */
    public void lineRelativeOn(
        int[] targetAxesIndices, Measurement[] endpoint) {
        try {
            lineRelativeOnAsync(targetAxesIndices, endpoint).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue an absolute arc movement on the first two axes of the stream.
     * Absolute meaning that the home positions of the axes is treated as the origin.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimensions of the position of the center of the circle on which the arc exists.
     * @param centerY The second dimensions of the position of the center of the circle on which the arc exists.
     * @param endX The first dimensions of the end position of the arc.
     * @param endY The second dimensions of the end position of the arc.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture arcAbsoluteAsync(
        RotationDirection rotationDirection, Measurement centerX, Measurement centerY, Measurement endX, Measurement endY) {
        Main.StreamArcRequest.Builder builder = Main.StreamArcRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamArcRequest.Type.ABS);

        builder = builder.setRotationDirection(rotationDirection.getValue());
        builder = builder.setCenterX(Measurement.toProtobuf(centerX));
        builder = builder.setCenterY(Measurement.toProtobuf(centerY));
        builder = builder.setEndX(Measurement.toProtobuf(endX));
        builder = builder.setEndY(Measurement.toProtobuf(endY));
        return Call.callAsync("device/stream_arc", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue an absolute arc movement on the first two axes of the stream.
     * Absolute meaning that the home positions of the axes is treated as the origin.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimensions of the position of the center of the circle on which the arc exists.
     * @param centerY The second dimensions of the position of the center of the circle on which the arc exists.
     * @param endX The first dimensions of the end position of the arc.
     * @param endY The second dimensions of the end position of the arc.
     */
    public void arcAbsolute(
        RotationDirection rotationDirection, Measurement centerX, Measurement centerY, Measurement endX, Measurement endY) {
        try {
            arcAbsoluteAsync(rotationDirection, centerX, centerY, endX, endY).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue a relative arc movement on the first two axes of the stream.
     * Relative meaning that the current position of the axes is treated as the origin.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimensions of the position of the center of the circle on which the arc exists.
     * @param centerY The second dimensions of the position of the center of the circle on which the arc exists.
     * @param endX The first dimensions of the end position of the arc.
     * @param endY The second dimensions of the end position of the arc.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture arcRelativeAsync(
        RotationDirection rotationDirection, Measurement centerX, Measurement centerY, Measurement endX, Measurement endY) {
        Main.StreamArcRequest.Builder builder = Main.StreamArcRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamArcRequest.Type.REL);

        builder = builder.setRotationDirection(rotationDirection.getValue());
        builder = builder.setCenterX(Measurement.toProtobuf(centerX));
        builder = builder.setCenterY(Measurement.toProtobuf(centerY));
        builder = builder.setEndX(Measurement.toProtobuf(endX));
        builder = builder.setEndY(Measurement.toProtobuf(endY));
        return Call.callAsync("device/stream_arc", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue a relative arc movement on the first two axes of the stream.
     * Relative meaning that the current position of the axes is treated as the origin.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimensions of the position of the center of the circle on which the arc exists.
     * @param centerY The second dimensions of the position of the center of the circle on which the arc exists.
     * @param endX The first dimensions of the end position of the arc.
     * @param endY The second dimensions of the end position of the arc.
     */
    public void arcRelative(
        RotationDirection rotationDirection, Measurement centerX, Measurement centerY, Measurement endX, Measurement endY) {
        try {
            arcRelativeAsync(rotationDirection, centerX, centerY, endX, endY).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue an absolute arc movement in the stream.
     * The movement will only target the specified subset of axes in the stream.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimensions of the position of the center of the circle on which the arc exists.
     * @param centerY The second dimensions of the position of the center of the circle on which the arc exists.
     * @param endX The first dimensions of the end position of the arc.
     * @param endY The second dimensions of the end position of the arc.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture arcAbsoluteOnAsync(
        int[] targetAxesIndices, RotationDirection rotationDirection, Measurement centerX, Measurement centerY, Measurement endX, Measurement endY) {
        Main.StreamArcRequest.Builder builder = Main.StreamArcRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamArcRequest.Type.ABS);

        builder = builder.setRotationDirection(rotationDirection.getValue());
        builder = builder.setCenterX(Measurement.toProtobuf(centerX));
        builder = builder.setCenterY(Measurement.toProtobuf(centerY));
        builder = builder.setEndX(Measurement.toProtobuf(endX));
        builder = builder.setEndY(Measurement.toProtobuf(endY));
        builder = builder.addAllTargetAxesIndices(
            Arrays.asList(ArrayUtility.toObjectArray(targetAxesIndices))
        );
        return Call.callAsync("device/stream_arc", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue an absolute arc movement in the stream.
     * The movement will only target the specified subset of axes in the stream.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimensions of the position of the center of the circle on which the arc exists.
     * @param centerY The second dimensions of the position of the center of the circle on which the arc exists.
     * @param endX The first dimensions of the end position of the arc.
     * @param endY The second dimensions of the end position of the arc.
     */
    public void arcAbsoluteOn(
        int[] targetAxesIndices, RotationDirection rotationDirection, Measurement centerX, Measurement centerY, Measurement endX, Measurement endY) {
        try {
            arcAbsoluteOnAsync(targetAxesIndices, rotationDirection, centerX, centerY, endX, endY).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue a relative arc movement in the stream.
     * The movement will only target the specified subset of axes in the stream.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimensions of the position of the center of the circle on which the arc exists.
     * @param centerY The second dimensions of the position of the center of the circle on which the arc exists.
     * @param endX The first dimensions of the end position of the arc.
     * @param endY The second dimensions of the end position of the arc.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture arcRelativeOnAsync(
        int[] targetAxesIndices, RotationDirection rotationDirection, Measurement centerX, Measurement centerY, Measurement endX, Measurement endY) {
        Main.StreamArcRequest.Builder builder = Main.StreamArcRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamArcRequest.Type.REL);

        builder = builder.setRotationDirection(rotationDirection.getValue());
        builder = builder.setCenterX(Measurement.toProtobuf(centerX));
        builder = builder.setCenterY(Measurement.toProtobuf(centerY));
        builder = builder.setEndX(Measurement.toProtobuf(endX));
        builder = builder.setEndY(Measurement.toProtobuf(endY));
        builder = builder.addAllTargetAxesIndices(
            Arrays.asList(ArrayUtility.toObjectArray(targetAxesIndices))
        );
        return Call.callAsync("device/stream_arc", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue a relative arc movement in the stream.
     * The movement will only target the specified subset of axes in the stream.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimensions of the position of the center of the circle on which the arc exists.
     * @param centerY The second dimensions of the position of the center of the circle on which the arc exists.
     * @param endX The first dimensions of the end position of the arc.
     * @param endY The second dimensions of the end position of the arc.
     */
    public void arcRelativeOn(
        int[] targetAxesIndices, RotationDirection rotationDirection, Measurement centerX, Measurement centerY, Measurement endX, Measurement endY) {
        try {
            arcRelativeOnAsync(targetAxesIndices, rotationDirection, centerX, centerY, endX, endY).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue an absolute circle movement on the first two axes of the stream.
     * Absolute meaning that the home positions of the axes are treated as the origin.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimension of the position of the center of the circle.
     * @param centerY The second dimension of the position of the center of the circle.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture circleAbsoluteAsync(
        RotationDirection rotationDirection, Measurement centerX, Measurement centerY) {
        Main.StreamCircleRequest.Builder builder = Main.StreamCircleRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamCircleRequest.Type.ABS);

        builder = builder.setRotationDirection(rotationDirection.getValue());
        builder = builder.setCenterX(Measurement.toProtobuf(centerX));
        builder = builder.setCenterY(Measurement.toProtobuf(centerY));
        return Call.callAsync("device/stream_circle", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue an absolute circle movement on the first two axes of the stream.
     * Absolute meaning that the home positions of the axes are treated as the origin.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimension of the position of the center of the circle.
     * @param centerY The second dimension of the position of the center of the circle.
     */
    public void circleAbsolute(
        RotationDirection rotationDirection, Measurement centerX, Measurement centerY) {
        try {
            circleAbsoluteAsync(rotationDirection, centerX, centerY).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue a relative circle movement on the first two axes of the stream.
     * Relative meaning that the current position of the axes is treated as the origin.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimension of the position of the center of the circle.
     * @param centerY The second dimension of the position of the center of the circle.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture circleRelativeAsync(
        RotationDirection rotationDirection, Measurement centerX, Measurement centerY) {
        Main.StreamCircleRequest.Builder builder = Main.StreamCircleRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamCircleRequest.Type.REL);

        builder = builder.setRotationDirection(rotationDirection.getValue());
        builder = builder.setCenterX(Measurement.toProtobuf(centerX));
        builder = builder.setCenterY(Measurement.toProtobuf(centerY));
        return Call.callAsync("device/stream_circle", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue a relative circle movement on the first two axes of the stream.
     * Relative meaning that the current position of the axes is treated as the origin.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimension of the position of the center of the circle.
     * @param centerY The second dimension of the position of the center of the circle.
     */
    public void circleRelative(
        RotationDirection rotationDirection, Measurement centerX, Measurement centerY) {
        try {
            circleRelativeAsync(rotationDirection, centerX, centerY).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue an absolute circle movement in the stream.
     * The movement will only target the specified subset of axes in the stream.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimension of the position of the center of the circle.
     * @param centerY The second dimension of the position of the center of the circle.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture circleAbsoluteOnAsync(
        int[] targetAxesIndices, RotationDirection rotationDirection, Measurement centerX, Measurement centerY) {
        Main.StreamCircleRequest.Builder builder = Main.StreamCircleRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamCircleRequest.Type.ABS);

        builder = builder.setRotationDirection(rotationDirection.getValue());
        builder = builder.setCenterX(Measurement.toProtobuf(centerX));
        builder = builder.setCenterY(Measurement.toProtobuf(centerY));
        builder = builder.addAllTargetAxesIndices(
            Arrays.asList(ArrayUtility.toObjectArray(targetAxesIndices))
        );
        return Call.callAsync("device/stream_circle", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue an absolute circle movement in the stream.
     * The movement will only target the specified subset of axes in the stream.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimension of the position of the center of the circle.
     * @param centerY The second dimension of the position of the center of the circle.
     */
    public void circleAbsoluteOn(
        int[] targetAxesIndices, RotationDirection rotationDirection, Measurement centerX, Measurement centerY) {
        try {
            circleAbsoluteOnAsync(targetAxesIndices, rotationDirection, centerX, centerY).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Queue a relative circle movement in the stream.
     * The movement will only target the specified subset of axes in the stream.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimension of the position of the center of the circle.
     * @param centerY The second dimension of the position of the center of the circle.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture circleRelativeOnAsync(
        int[] targetAxesIndices, RotationDirection rotationDirection, Measurement centerX, Measurement centerY) {
        Main.StreamCircleRequest.Builder builder = Main.StreamCircleRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());
        builder = builder.setType(Main.StreamCircleRequest.Type.REL);

        builder = builder.setRotationDirection(rotationDirection.getValue());
        builder = builder.setCenterX(Measurement.toProtobuf(centerX));
        builder = builder.setCenterY(Measurement.toProtobuf(centerY));
        builder = builder.addAllTargetAxesIndices(
            Arrays.asList(ArrayUtility.toObjectArray(targetAxesIndices))
        );
        return Call.callAsync("device/stream_circle", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Queue a relative circle movement in the stream.
     * The movement will only target the specified subset of axes in the stream.
     * @param targetAxesIndices Indices of the axes in the stream the movement targets.
     * Refers to the axes provided during the stream setup or further execution.
     * Indices are zero-based.
     * @param rotationDirection The direction of the rotation.
     * @param centerX The first dimension of the position of the center of the circle.
     * @param centerY The second dimension of the position of the center of the circle.
     */
    public void circleRelativeOn(
        int[] targetAxesIndices, RotationDirection rotationDirection, Measurement centerX, Measurement centerY) {
        try {
            circleRelativeOnAsync(targetAxesIndices, rotationDirection, centerX, centerY).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Wait for a digital input channel to reach a given value.
     * @param channelNumber The number of the digital input channel.
     * Channel numbers are numbered from one.
     * @param value The value that the stream should wait for.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture waitDigitalInputAsync(
        int channelNumber, boolean value) {
        Main.StreamWaitDigitalInputRequest.Builder builder = Main.StreamWaitDigitalInputRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setChannelNumber(channelNumber);
        builder = builder.setValue(value);
        return Call.callAsync("device/stream_wait_digital_input", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Wait for a digital input channel to reach a given value.
     * @param channelNumber The number of the digital input channel.
     * Channel numbers are numbered from one.
     * @param value The value that the stream should wait for.
     */
    public void waitDigitalInput(
        int channelNumber, boolean value) {
        try {
            waitDigitalInputAsync(channelNumber, value).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Wait for the value of a analog input channel to reach a condition concerning a given value.
     * @param channelNumber The number of the analog input channel.
     * Channel numbers are numbered from one.
     * @param condition A condition (e.g. {@literal <,} {@literal <=,} ==, !=).
     * @param value The value that the condition concerns, in volts.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture waitAnalogInputAsync(
        int channelNumber, String condition, double value) {
        Main.StreamWaitAnalogInputRequest.Builder builder = Main.StreamWaitAnalogInputRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setChannelNumber(channelNumber);
        builder = builder.setCondition(condition);
        builder = builder.setValue(value);
        return Call.callAsync("device/stream_wait_analog_input", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Wait for the value of a analog input channel to reach a condition concerning a given value.
     * @param channelNumber The number of the analog input channel.
     * Channel numbers are numbered from one.
     * @param condition A condition (e.g. {@literal <,} {@literal <=,} ==, !=).
     * @param value The value that the condition concerns, in volts.
     */
    public void waitAnalogInput(
        int channelNumber, String condition, double value) {
        try {
            waitAnalogInputAsync(channelNumber, condition, value).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Set the value of a digital output channel.
     * @param channelNumber The number of the digital output channel.
     * Channel numbers are numbered from one.
     * @param value The value to set the channel to.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setDigitalOutputAsync(
        int channelNumber, boolean value) {
        Main.StreamSetDigitalOutputRequest.Builder builder = Main.StreamSetDigitalOutputRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setChannelNumber(channelNumber);
        builder = builder.setValue(value);
        return Call.callAsync("device/stream_set_digital_output", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Set the value of a digital output channel.
     * @param channelNumber The number of the digital output channel.
     * Channel numbers are numbered from one.
     * @param value The value to set the channel to.
     */
    public void setDigitalOutput(
        int channelNumber, boolean value) {
        try {
            setDigitalOutputAsync(channelNumber, value).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Set the value of an analog output channel.
     * @param channelNumber The number of the analog output channel.
     * Channel numbers are numbered from one.
     * @param value The value to set the channel to, in volts.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setAnalogOutputAsync(
        int channelNumber, double value) {
        Main.StreamSetAnalogOutputRequest.Builder builder = Main.StreamSetAnalogOutputRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setChannelNumber(channelNumber);
        builder = builder.setValue(value);
        return Call.callAsync("device/stream_set_analog_output", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Set the value of an analog output channel.
     * @param channelNumber The number of the analog output channel.
     * Channel numbers are numbered from one.
     * @param value The value to set the channel to, in volts.
     */
    public void setAnalogOutput(
        int channelNumber, double value) {
        try {
            setAnalogOutputAsync(channelNumber, value).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Toggle the value of a digital output channel.
     * @param channelNumber The number of the digital output channel.
     * Channel numbers are numbered from one.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture toggleDigitalOutputAsync(
        int channelNumber) {
        Main.StreamToggleDigitalOutputRequest.Builder builder = Main.StreamToggleDigitalOutputRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setChannelNumber(channelNumber);
        return Call.callAsync("device/stream_toggle_digital_output", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Toggle the value of a digital output channel.
     * @param channelNumber The number of the digital output channel.
     * Channel numbers are numbered from one.
     */
    public void toggleDigitalOutput(
        int channelNumber) {
        try {
            toggleDigitalOutputAsync(channelNumber).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Wait a specified time.
     * @param time Amount of time to wait.
     * @param unit Units of time.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture waitAsync(
        double time, Units unit) {
        Main.StreamWaitRequest.Builder builder = Main.StreamWaitRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setTime(time);
        builder = builder.setUnit(unit.getName());
        return Call.callAsync("device/stream_wait", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Wait a specified time.
     * @param time Amount of time to wait.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture waitAsync(
        double time) {
        return waitAsync(time, Units.NATIVE);
    }

    /**
     * Wait a specified time.
     * @param time Amount of time to wait.
     * @param unit Units of time.
     */
    public void wait(
        double time, Units unit) {
        try {
            waitAsync(time, unit).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Wait a specified time.
     * @param time Amount of time to wait.
     */
    public void wait(
        double time) {
        wait(time, Units.NATIVE);
    }

    /**
     * Waits until the live stream executes all queued actions.
     * @param throwErrorOnFault Determines whether to throw error when fault is observed.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture waitUntilIdleAsync(
        boolean throwErrorOnFault) {
        Main.StreamWaitUntilIdleRequest.Builder builder = Main.StreamWaitUntilIdleRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setThrowErrorOnFault(throwErrorOnFault);
        return Call.callAsync("device/stream_wait_until_idle", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Waits until the live stream executes all queued actions.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture waitUntilIdleAsync() {
        return waitUntilIdleAsync(true);
    }

    /**
     * Waits until the live stream executes all queued actions.
     * @param throwErrorOnFault Determines whether to throw error when fault is observed.
     */
    public void waitUntilIdle(
        boolean throwErrorOnFault) {
        try {
            waitUntilIdleAsync(throwErrorOnFault).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Waits until the live stream executes all queued actions.
     */
    public void waitUntilIdle() {
        waitUntilIdle(true);
    }

    /**
     * Cork the front of the stream's action queue, blocking execution.
     * Execution resumes upon uncorking the queue, or when the number of queued actions reaches its limit.
     * Corking eliminates discontinuities in motion due to subsequent stream commands reaching the device late.
     * You can only cork an idle live stream.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture corkAsync() {
        Main.StreamCorkRequest.Builder builder = Main.StreamCorkRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        return Call.callAsync("device/stream_cork", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Cork the front of the stream's action queue, blocking execution.
     * Execution resumes upon uncorking the queue, or when the number of queued actions reaches its limit.
     * Corking eliminates discontinuities in motion due to subsequent stream commands reaching the device late.
     * You can only cork an idle live stream.
     */
    public void cork() {
        try {
            corkAsync().get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Uncork the front of the queue, unblocking command execution.
     * You can only uncork an idle live stream that is corked.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture uncorkAsync() {
        Main.StreamUncorkRequest.Builder builder = Main.StreamUncorkRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        return Call.callAsync("device/stream_uncork", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Uncork the front of the queue, unblocking command execution.
     * You can only uncork an idle live stream that is corked.
     */
    public void uncork() {
        try {
            uncorkAsync().get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Returns a boolean value indicating whether the live stream is executing a queued action.
     * @return A CompletableFuture that can be completed to get the result:
     * True if the stream is executing a queued action.
     */
    public CompletableFuture isBusyAsync() {
        Main.StreamIsBusyRequest.Builder builder = Main.StreamIsBusyRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        CompletableFuture response = Call.callAsync(
            "device/stream_is_busy",
            builder.build(),
            Main.StreamIsBusyResponse.parser());
        return response
            .thenApply(r -> r.getIsBusy());
    }

    /**
     * Returns a boolean value indicating whether the live stream is executing a queued action.
     * @return True if the stream is executing a queued action.
     */
    public boolean isBusy() {
        try {
            return isBusyAsync().get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Gets the maximum speed of the live stream.
     * Converts the units using the first axis of the stream.
     * @param unit Units of velocity.
     * @return A CompletableFuture that can be completed to get the result:
     * The maximum speed of the stream.
     */
    public CompletableFuture getMaxSpeedAsync(
        Units unit) {
        Main.StreamGetMaxSpeedRequest.Builder builder = Main.StreamGetMaxSpeedRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setUnit(unit.getName());
        CompletableFuture response = Call.callAsync(
            "device/stream_get_max_speed",
            builder.build(),
            Main.StreamGetMaxSpeedResponse.parser());
        return response
            .thenApply(r -> r.getMaxSpeed());
    }

    /**
     * Gets the maximum speed of the live stream.
     * Converts the units using the first axis of the stream.
     * @return A CompletableFuture that can be completed to get the result:
     * The maximum speed of the stream.
     */
    public CompletableFuture getMaxSpeedAsync() {
        return getMaxSpeedAsync(Units.NATIVE);
    }

    /**
     * Gets the maximum speed of the live stream.
     * Converts the units using the first axis of the stream.
     * @param unit Units of velocity.
     * @return The maximum speed of the stream.
     */
    public double getMaxSpeed(
        Units unit) {
        try {
            return getMaxSpeedAsync(unit).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Gets the maximum speed of the live stream.
     * Converts the units using the first axis of the stream.
     * @return The maximum speed of the stream.
     */
    public double getMaxSpeed() {
        return getMaxSpeed(Units.NATIVE);
    }

    /**
     * Sets the maximum speed of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxSpeed Maximum speed at which any stream action is executed.
     * @param unit Units of velocity.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setMaxSpeedAsync(
        double maxSpeed, Units unit) {
        Main.StreamSetMaxSpeedRequest.Builder builder = Main.StreamSetMaxSpeedRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setMaxSpeed(maxSpeed);
        builder = builder.setUnit(unit.getName());
        return Call.callAsync("device/stream_set_max_speed", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Sets the maximum speed of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxSpeed Maximum speed at which any stream action is executed.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setMaxSpeedAsync(
        double maxSpeed) {
        return setMaxSpeedAsync(maxSpeed, Units.NATIVE);
    }

    /**
     * Sets the maximum speed of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxSpeed Maximum speed at which any stream action is executed.
     * @param unit Units of velocity.
     */
    public void setMaxSpeed(
        double maxSpeed, Units unit) {
        try {
            setMaxSpeedAsync(maxSpeed, unit).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Sets the maximum speed of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxSpeed Maximum speed at which any stream action is executed.
     */
    public void setMaxSpeed(
        double maxSpeed) {
        setMaxSpeed(maxSpeed, Units.NATIVE);
    }

    /**
     * Gets the maximum tangential acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param unit Units of acceleration.
     * @return A CompletableFuture that can be completed to get the result:
     * The maximum tangential acceleration of the live stream.
     */
    public CompletableFuture getMaxTangentialAccelerationAsync(
        Units unit) {
        Main.StreamGetMaxTangentialAccelerationRequest.Builder builder = Main.StreamGetMaxTangentialAccelerationRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setUnit(unit.getName());
        CompletableFuture response = Call.callAsync(
            "device/stream_get_max_tangential_acceleration",
            builder.build(),
            Main.StreamGetMaxTangentialAccelerationResponse.parser());
        return response
            .thenApply(r -> r.getMaxTangentialAcceleration());
    }

    /**
     * Gets the maximum tangential acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @return A CompletableFuture that can be completed to get the result:
     * The maximum tangential acceleration of the live stream.
     */
    public CompletableFuture getMaxTangentialAccelerationAsync() {
        return getMaxTangentialAccelerationAsync(Units.NATIVE);
    }

    /**
     * Gets the maximum tangential acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param unit Units of acceleration.
     * @return The maximum tangential acceleration of the live stream.
     */
    public double getMaxTangentialAcceleration(
        Units unit) {
        try {
            return getMaxTangentialAccelerationAsync(unit).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Gets the maximum tangential acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @return The maximum tangential acceleration of the live stream.
     */
    public double getMaxTangentialAcceleration() {
        return getMaxTangentialAcceleration(Units.NATIVE);
    }

    /**
     * Sets the maximum tangential acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxTangentialAcceleration Maximum tangential acceleration at which any stream action is executed.
     * @param unit Units of acceleration.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setMaxTangentialAccelerationAsync(
        double maxTangentialAcceleration, Units unit) {
        Main.StreamSetMaxTangentialAccelerationRequest.Builder builder = Main.StreamSetMaxTangentialAccelerationRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setMaxTangentialAcceleration(maxTangentialAcceleration);
        builder = builder.setUnit(unit.getName());
        return Call.callAsync("device/stream_set_max_tangential_acceleration", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Sets the maximum tangential acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxTangentialAcceleration Maximum tangential acceleration at which any stream action is executed.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setMaxTangentialAccelerationAsync(
        double maxTangentialAcceleration) {
        return setMaxTangentialAccelerationAsync(maxTangentialAcceleration, Units.NATIVE);
    }

    /**
     * Sets the maximum tangential acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxTangentialAcceleration Maximum tangential acceleration at which any stream action is executed.
     * @param unit Units of acceleration.
     */
    public void setMaxTangentialAcceleration(
        double maxTangentialAcceleration, Units unit) {
        try {
            setMaxTangentialAccelerationAsync(maxTangentialAcceleration, unit).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Sets the maximum tangential acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxTangentialAcceleration Maximum tangential acceleration at which any stream action is executed.
     */
    public void setMaxTangentialAcceleration(
        double maxTangentialAcceleration) {
        setMaxTangentialAcceleration(maxTangentialAcceleration, Units.NATIVE);
    }

    /**
     * Gets the maximum centripetal acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param unit Units of acceleration.
     * @return A CompletableFuture that can be completed to get the result:
     * The maximum centripetal acceleration of the live stream.
     */
    public CompletableFuture getMaxCentripetalAccelerationAsync(
        Units unit) {
        Main.StreamGetMaxCentripetalAccelerationRequest.Builder builder = Main.StreamGetMaxCentripetalAccelerationRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setUnit(unit.getName());
        CompletableFuture response = Call.callAsync(
            "device/stream_get_max_centripetal_acceleration",
            builder.build(),
            Main.StreamGetMaxCentripetalAccelerationResponse.parser());
        return response
            .thenApply(r -> r.getMaxCentripetalAcceleration());
    }

    /**
     * Gets the maximum centripetal acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @return A CompletableFuture that can be completed to get the result:
     * The maximum centripetal acceleration of the live stream.
     */
    public CompletableFuture getMaxCentripetalAccelerationAsync() {
        return getMaxCentripetalAccelerationAsync(Units.NATIVE);
    }

    /**
     * Gets the maximum centripetal acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param unit Units of acceleration.
     * @return The maximum centripetal acceleration of the live stream.
     */
    public double getMaxCentripetalAcceleration(
        Units unit) {
        try {
            return getMaxCentripetalAccelerationAsync(unit).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Gets the maximum centripetal acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @return The maximum centripetal acceleration of the live stream.
     */
    public double getMaxCentripetalAcceleration() {
        return getMaxCentripetalAcceleration(Units.NATIVE);
    }

    /**
     * Sets the maximum centripetal acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxCentripetalAcceleration Maximum centripetal acceleration at which any stream action is executed.
     * @param unit Units of acceleration.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setMaxCentripetalAccelerationAsync(
        double maxCentripetalAcceleration, Units unit) {
        Main.StreamSetMaxCentripetalAccelerationRequest.Builder builder = Main.StreamSetMaxCentripetalAccelerationRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        builder = builder.setMaxCentripetalAcceleration(maxCentripetalAcceleration);
        builder = builder.setUnit(unit.getName());
        return Call.callAsync("device/stream_set_max_centripetal_acceleration", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Sets the maximum centripetal acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxCentripetalAcceleration Maximum centripetal acceleration at which any stream action is executed.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture setMaxCentripetalAccelerationAsync(
        double maxCentripetalAcceleration) {
        return setMaxCentripetalAccelerationAsync(maxCentripetalAcceleration, Units.NATIVE);
    }

    /**
     * Sets the maximum centripetal acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxCentripetalAcceleration Maximum centripetal acceleration at which any stream action is executed.
     * @param unit Units of acceleration.
     */
    public void setMaxCentripetalAcceleration(
        double maxCentripetalAcceleration, Units unit) {
        try {
            setMaxCentripetalAccelerationAsync(maxCentripetalAcceleration, unit).get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Sets the maximum centripetal acceleration of the live stream.
     * Converts the units using the first axis of the stream.
     * @param maxCentripetalAcceleration Maximum centripetal acceleration at which any stream action is executed.
     */
    public void setMaxCentripetalAcceleration(
        double maxCentripetalAcceleration) {
        setMaxCentripetalAcceleration(maxCentripetalAcceleration, Units.NATIVE);
    }

    /**
     * Returns a string which represents the stream.
     * @return String which represents the stream.
     */
    public String toString() {
        Main.StreamToStringRequest.Builder builder = Main.StreamToStringRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        Main.StreamToStringResponse response = Call.callSync(
            "device/stream_to_string",
            builder.build(),
            Main.StreamToStringResponse.parser());
        return response.getToStr();
    }


    /**
     * Disable the stream.
     * If the stream is not setup, this command does nothing.
     * Once disabled, the stream will no longer accept stream commands.
     * The stream will process the rest of the commands in the queue until it is empty.
     * @return A CompletableFuture that can be completed to know when the work is complete.
     */
    public CompletableFuture disableAsync() {
        Main.StreamDisableRequest.Builder builder = Main.StreamDisableRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        return Call.callAsync("device/stream_disable", builder.build(), null)
            .thenApply(r -> (Void) null);
    }

    /**
     * Disable the stream.
     * If the stream is not setup, this command does nothing.
     * Once disabled, the stream will no longer accept stream commands.
     * The stream will process the rest of the commands in the queue until it is empty.
     */
    public void disable() {
        try {
            disableAsync().get();
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MotionLibException) {
                throw (MotionLibException) e.getCause();
            } else {
                throw new MotionLibException(e.getCause());
            }
        } catch (InterruptedException e) {
            throw new MotionLibException(e);
        }
    }

    /**
     * Gets the axes of the stream.
     * @return An array of axis numbers of the axes the stream is set up to control.
     */
    private StreamAxisDefinition[] retrieveAxes() {
        Main.StreamGetAxesRequest.Builder builder = Main.StreamGetAxesRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        Main.StreamGetAxesResponse response = Call.callSync(
            "device/stream_get_axes",
            builder.build(),
            Main.StreamGetAxesResponse.parser());
        return response.getAxesList().stream()
            .map(resp -> StreamAxisDefinition.fromProtobuf(resp)).toArray(StreamAxisDefinition[]::new);
    }


    /**
     * Get the mode of the stream.
     * @return Mode of the stream.
     */
    private StreamMode retrieveMode() {
        Main.StreamGetModeRequest.Builder builder = Main.StreamGetModeRequest.newBuilder();
        builder = builder.setInterfaceId(getDevice().getConnection().getInterfaceId());
        builder = builder.setDevice(getDevice().getDeviceAddress());
        builder = builder.setStreamId(getStreamId());

        Main.StreamGetModeResponse response = Call.callSync(
            "device/stream_get_mode",
            builder.build(),
            Main.StreamGetModeResponse.parser());
        return StreamMode.valueOf(response.getMode());
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy