Skip to content
9 changes: 9 additions & 0 deletions docs/migrations/v8_to_v10.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,12 @@ These feature were infrequently used and has been removed to simplify the codeba

- Moryx.Tools.FunctionResult: Moved to Moryx.Tools
- Moryx.AbstractionLayer namespace: All classes have been moved to more specific domain namespaces e.g. Moryx.AbstractionLayer.Resources, Moryx.AbstractionLayer.Products, Moryx.AbstractionLayer.Processes etc.

## Reworked driver APIs

All driver APIs have been reworked to use TPL async/await instead of callbacks for the following reasons:

- The same logic looks almost synchronous.
- Cleaner and integrates seamlessly with .NET’s exception system.
- You can chain tasks with LINQ-like methods or await syntax.
- Async stack-traces in IDE show the actual logical call flow — even across await boundaries.
47 changes: 47 additions & 0 deletions src/Moryx.AbstractionLayer/Drivers/Axis/AxisMovement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

namespace Moryx.AbstractionLayer.Drivers.Axis;

/// <summary>
/// Defines a axis movement
/// </summary>
public class AxisMovement
{
/// <summary>
/// The axis which should be moved
/// </summary>
public Axes Axis { get; }

/// <summary>
/// Target position of the axis to move to
/// </summary>
public double? TargetPosition { get; }

/// <summary>
/// Predefined position of the axis to move to
/// </summary>
public AxisPosition? PredefinedPosition { get; }

/// <summary>
/// Creates a new instance of <see cref="AxisMovement"/> with a target position
/// </summary>
/// <param name="axis">The axis which should be moved</param>
/// <param name="targetPosition">Target position of the axis to move to</param>
public AxisMovement(Axes axis, double targetPosition)
{
Axis = axis;
TargetPosition = targetPosition;
}

/// <summary>
/// Creates a new instance of <see cref="AxisMovement"/> with a predefined position
/// </summary>
/// <param name="axis">The axis which should be moved</param>
/// <param name="predefinedPosition">Predefined position of the axis to move to</param>
public AxisMovement(Axes axis, AxisPosition predefinedPosition)
{
Axis = axis;
PredefinedPosition = predefinedPosition;
}
}
17 changes: 1 addition & 16 deletions src/Moryx.AbstractionLayer/Drivers/Axis/AxisMovementResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,8 @@ namespace Moryx.AbstractionLayer.Drivers.Axis
/// <summary>
/// Response of the marking file setup
/// </summary>
public class AxisMovementResponse : TransmissionResult
public class AxisMovementResponse
{
/// <summary>
/// Successfull movement of the axis
/// </summary>
public AxisMovementResponse() : base()
{

}

/// <summary>
/// Faulty movement of the axis
/// </summary>
/// <param name="errorMessage">Occured error</param>
public AxisMovementResponse(string errorMessage) : base(new TransmissionError(errorMessage))
{

}
}
}
20 changes: 7 additions & 13 deletions src/Moryx.AbstractionLayer/Drivers/Axis/IAxesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,13 @@ namespace Moryx.AbstractionLayer.Drivers.Axis
public interface IAxesController : IDriver
{
/// <summary>
/// Will move the axis of the laser to the given position
/// Will move the axes of the system to the given position
/// </summary>
/// <param name="axis">The axis which should be moved</param>
/// <param name="targetPosition">The target position of the axis</param>
/// <param name="callback">The callback which will be executed after the axis movement</param>
void MoveAxis(Axes axis, double targetPosition, DriverResponse<AxisMovementResponse> callback);

/// <summary>
/// Will move the axis of the laser to the given position
/// </summary>
/// <param name="axis">The axis which should be moved</param>
/// <param name="targetPosition">The target position of the axis</param>
/// <param name="callback">The callback which will be executed after the axis movement</param>
void MoveAxis(Axes axis, AxisPosition targetPosition, DriverResponse<AxisMovementResponse> callback);
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.</param>
/// <param name="movement">Array of axes which should be moved</param>
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
/// <exception cref="MoveAxesException">Will be thrown for errors during moving axes</exception>
/// <exception cref="OperationCanceledException">The cancellation token was canceled. This exception is stored into the returned task.</exception>
Task<AxisMovementResponse> MoveAxesAsync(CancellationToken cancellationToken = default, params AxisMovement[] movement);
}
}
11 changes: 11 additions & 0 deletions src/Moryx.AbstractionLayer/Drivers/Axis/MoveAxesException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

namespace Moryx.AbstractionLayer.Drivers.Axis;

/// <summary>
/// Exception type which will be used for errors during moving axes of <see cref="IAxesController"/>
/// </summary>
public class MoveAxesException : Exception
{
}
1 change: 1 addition & 0 deletions src/Moryx.AbstractionLayer/Drivers/Axis/NumberedAxis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public struct NumberedAxis : IEquatable<NumberedAxis>
/// Axis
/// </summary>
public Axes Axis { get; }

/// <summary>
/// Number
/// </summary>
Expand Down
36 changes: 18 additions & 18 deletions src/Moryx.AbstractionLayer/Drivers/Camera/ICameraDriver.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

namespace Moryx.AbstractionLayer.Drivers.Camera
namespace Moryx.AbstractionLayer.Drivers.Camera;

/// <summary>
/// Interface for camera devices, that provide image data
/// </summary>
public interface ICameraDriver<TImage> : IDriver where TImage : class
{
/// <summary>
/// Interface for camera devices, that provide image data
/// Capture a single image from the camera
/// </summary>
public interface ICameraDriver<TImage> : IDriver where TImage : class
{
/// <summary>
/// Eventhandler to continously provide images from a camera
/// </summary>
event EventHandler<TImage> CapturedImage;
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.</param>
/// <returns>
/// The image that was captured or null in case no image
/// could be retrieved
/// </returns>
/// <exception cref="OperationCanceledException">The cancellation token was canceled. This exception is stored into the returned task.</exception>
Task<TImage> CaptureImageAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Capture a single image from the camera
/// </summary>
/// <returns>
/// The image that was captured or null in case no image
/// could be retrieved
/// </returns>
Task<TImage?> CaptureImage();
}
/// <summary>
/// Event to continuously provide images from a camera
/// </summary>
event EventHandler<TImage> CapturedImage;
}

4 changes: 2 additions & 2 deletions src/Moryx.AbstractionLayer/Drivers/Driver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Moryx.AbstractionLayer.Drivers
/// </summary>
public abstract class Driver : Resource, IDriver, IStateContext
{
/// <see cref="IDriver"/>
/// <inheritdoc />
public IDriverState CurrentState { get; private set; }

void IStateContext.SetState(IState state)
Expand All @@ -20,7 +20,7 @@ void IStateContext.SetState(IState state)
StateChanged?.Invoke(this, CurrentState);
}

/// <seealso cref="IDriver"/>
/// <inheritdoc />
public event EventHandler<IDriverState> StateChanged;
}
}
19 changes: 0 additions & 19 deletions src/Moryx.AbstractionLayer/Drivers/DriverNotRunningException.cs

This file was deleted.

25 changes: 25 additions & 0 deletions src/Moryx.AbstractionLayer/Drivers/DriverStateException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

namespace Moryx.AbstractionLayer.Drivers
{
/// <summary>
/// Exception for busy drivers. The driver cannot handle requests.
/// </summary>
public class DriverStateException : Exception
{
/// <summary>
/// Information about the required state of the driver for the execution
/// </summary>
public StateClassification RequiredState { get; }

/// <summary>
/// Initializes a new instance of the <see cref="DriverStateException"/> class.
/// </summary>
public DriverStateException(StateClassification requiredState)
: base($"Cannot handle the driver request. Driver is not in state {requiredState}!")
{
RequiredState = requiredState;
}
}
}
3 changes: 3 additions & 0 deletions src/Moryx.AbstractionLayer/Drivers/InOut/IInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,21 @@ public interface IInput<out TIn>
/// Single value input
/// Only available for <see cref="SupportedAccess.Single"/>
/// </summary>
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
TIn Value { get; }

/// <summary>
/// Index based input
/// Only available for <see cref="SupportedAccess.Index"/>
/// </summary>
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
TIn this[int index] { get; }

/// <summary>
/// Key based input
/// Only available for <see cref="SupportedAccess.Key"/>
/// </summary>
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
TIn this[string key] { get; }

/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions src/Moryx.AbstractionLayer/Drivers/InOut/IOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,21 @@ public interface IOutput<TOut>
/// Single value output
/// Only available for <see cref="SupportedAccess.Single"/>
/// </summary>
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
TOut Value { get; set; }

/// <summary>
/// Index based output
/// Only available for <see cref="SupportedAccess.Index"/>
/// </summary>
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
TOut this[int index] { get; set; }

/// <summary>
/// Key based output
/// Only available for <see cref="SupportedAccess.Key"/>
/// </summary>
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
TOut this[string key] { get; set; }
}
}
37 changes: 13 additions & 24 deletions src/Moryx.AbstractionLayer/Drivers/Marking/IMarkingLaserDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,24 @@ namespace Moryx.AbstractionLayer.Drivers.Marking
public interface IMarkingLaserDriver : IDriver
{
/// <summary>
/// Set up marking file as a preperation for the marking process
/// Set up marking file as a preparation for the marking process
/// </summary>
void SetMarkingFile(MarkingFile file, DriverResponse<MarkingFileResponse> callback);
/// <param name="file">The marking file used for the marking system</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.</param>
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
/// <exception cref="MarkingFileException">Will be thrown when errors occur during setting the marking file</exception>
/// <exception cref="OperationCanceledException">The cancellation token was canceled. This exception is stored into the returned task.</exception>
Task<MarkingFileResponse> SetMarkingFileAsync(MarkingFile file, CancellationToken cancellationToken = default);

/// <summary>
/// Will start the marking process and executes the given callback after finish
/// </summary>
/// <param name="config">The configuration for the marking process.</param>
/// <param name="callback">The callback which will be executed after the marking process</param>
void Mark(MarkingConfiguration config, DriverResponse<MarkingResponse> callback);

/// <summary>
/// Triggers a message to get the last error
/// </summary>
void RequestLastError();

/// <summary>
/// Triggers a message to get the last warning
/// </summary>
void RequestLastWarning();

/// <summary>
/// Will be fired if an error occured
/// </summary>
event EventHandler<NotificationResponse> ErrorOccured;

/// <summary>
/// Will be fired of a warning occured
/// </summary>
event EventHandler<NotificationResponse> WarningOccured;
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.</param>
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
/// <exception cref="MarkingException">Will be thrown when errors occur during marking execution</exception>
/// <exception cref="SegmentsNotSupportedException">Exception if the system does not support segments</exception>
/// <exception cref="OperationCanceledException">The cancellation token was canceled. This exception is stored into the returned task.</exception>
Task<MarkingResponse> MarkAsync(MarkingConfiguration config, CancellationToken cancellationToken = default);
}
}
19 changes: 0 additions & 19 deletions src/Moryx.AbstractionLayer/Drivers/Marking/IMarkingLaserState.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ public MarkingConfiguration()
/// </summary>
/// <param name="resizingFactor">The factor for resizing the marking file. 1 is original size.</param>
/// <param name="angle">The angle of rotation in ° clockwise around the mid point of the image field. 0 is no rotation.</param>
/// <param name="xaxis">Displacement along the X-axis in mm.</param>
/// <param name="yaxis">Displacement along the Y-axis in mm.</param>
/// <param name="xAxis">Displacement along the X-axis in mm.</param>
/// <param name="yAxis">Displacement along the Y-axis in mm.</param>
/// <returns>This object.</returns>
public MarkingConfiguration SetTransformation(double resizingFactor, double angle, double xaxis, double yaxis)
public MarkingConfiguration SetTransformation(double resizingFactor, double angle, double xAxis, double yAxis)
{
ResizingFactor = resizingFactor;
Angle = angle;
XAxis = xaxis;
YAxis = yaxis;
XAxis = xAxis;
YAxis = yAxis;
return this;
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/Moryx.AbstractionLayer/Drivers/Marking/MarkingException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

namespace Moryx.AbstractionLayer.Drivers.Marking;

/// <summary>
/// Exception type which will be used for errors during marking execution of the <see cref="IMarkingLaserDriver"/>
/// </summary>
public class MarkingException : Exception
{
}
Loading
Loading