Skip to content

Commit f8da120

Browse files
authored
Merge pull request #765 from PHOENIXCONTACT/rework/driver-api
Rework of Driver APIs
2 parents 29e2ef0 + d6ac7e0 commit f8da120

38 files changed

+333
-361
lines changed

docs/migrations/v8_to_v10.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,12 @@ These feature were infrequently used and has been removed to simplify the codeba
7676

7777
- Moryx.Tools.FunctionResult: Moved to Moryx.Tools
7878
- 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.
79+
80+
## Reworked driver APIs
81+
82+
All driver APIs have been reworked to use TPL async/await instead of callbacks for the following reasons:
83+
84+
- The same logic looks almost synchronous.
85+
- Cleaner and integrates seamlessly with .NET’s exception system.
86+
- You can chain tasks with LINQ-like methods or await syntax.
87+
- Async stack-traces in IDE show the actual logical call flow — even across await boundaries.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
2+
// Licensed under the Apache License, Version 2.0
3+
4+
namespace Moryx.AbstractionLayer.Drivers.Axis;
5+
6+
/// <summary>
7+
/// Defines a axis movement
8+
/// </summary>
9+
public class AxisMovement
10+
{
11+
/// <summary>
12+
/// The axis which should be moved
13+
/// </summary>
14+
public Axes Axis { get; }
15+
16+
/// <summary>
17+
/// Target position of the axis to move to
18+
/// </summary>
19+
public double? TargetPosition { get; }
20+
21+
/// <summary>
22+
/// Predefined position of the axis to move to
23+
/// </summary>
24+
public AxisPosition? PredefinedPosition { get; }
25+
26+
/// <summary>
27+
/// Creates a new instance of <see cref="AxisMovement"/> with a target position
28+
/// </summary>
29+
/// <param name="axis">The axis which should be moved</param>
30+
/// <param name="targetPosition">Target position of the axis to move to</param>
31+
public AxisMovement(Axes axis, double targetPosition)
32+
{
33+
Axis = axis;
34+
TargetPosition = targetPosition;
35+
}
36+
37+
/// <summary>
38+
/// Creates a new instance of <see cref="AxisMovement"/> with a predefined position
39+
/// </summary>
40+
/// <param name="axis">The axis which should be moved</param>
41+
/// <param name="predefinedPosition">Predefined position of the axis to move to</param>
42+
public AxisMovement(Axes axis, AxisPosition predefinedPosition)
43+
{
44+
Axis = axis;
45+
PredefinedPosition = predefinedPosition;
46+
}
47+
}

src/Moryx.AbstractionLayer/Drivers/Axis/AxisMovementResponse.cs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,8 @@ namespace Moryx.AbstractionLayer.Drivers.Axis
66
/// <summary>
77
/// Response of the marking file setup
88
/// </summary>
9-
public class AxisMovementResponse : TransmissionResult
9+
public class AxisMovementResponse
1010
{
11-
/// <summary>
12-
/// Successfull movement of the axis
13-
/// </summary>
14-
public AxisMovementResponse() : base()
15-
{
1611

17-
}
18-
19-
/// <summary>
20-
/// Faulty movement of the axis
21-
/// </summary>
22-
/// <param name="errorMessage">Occured error</param>
23-
public AxisMovementResponse(string errorMessage) : base(new TransmissionError(errorMessage))
24-
{
25-
26-
}
2712
}
2813
}

src/Moryx.AbstractionLayer/Drivers/Axis/IAxesController.cs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,13 @@ namespace Moryx.AbstractionLayer.Drivers.Axis
99
public interface IAxesController : IDriver
1010
{
1111
/// <summary>
12-
/// Will move the axis of the laser to the given position
12+
/// Will move the axes of the system to the given position
1313
/// </summary>
14-
/// <param name="axis">The axis which should be moved</param>
15-
/// <param name="targetPosition">The target position of the axis</param>
16-
/// <param name="callback">The callback which will be executed after the axis movement</param>
17-
void MoveAxis(Axes axis, double targetPosition, DriverResponse<AxisMovementResponse> callback);
18-
19-
/// <summary>
20-
/// Will move the axis of the laser to the given position
21-
/// </summary>
22-
/// <param name="axis">The axis which should be moved</param>
23-
/// <param name="targetPosition">The target position of the axis</param>
24-
/// <param name="callback">The callback which will be executed after the axis movement</param>
25-
void MoveAxis(Axes axis, AxisPosition targetPosition, DriverResponse<AxisMovementResponse> callback);
14+
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.</param>
15+
/// <param name="movement">Array of axes which should be moved</param>
16+
/// <exception cref="DriverStateException">Will be thrown when the driver is in wrong state</exception>
17+
/// <exception cref="MoveAxesException">Will be thrown for errors during moving axes</exception>
18+
/// <exception cref="OperationCanceledException">The cancellation token was canceled. This exception is stored into the returned task.</exception>
19+
Task<AxisMovementResponse> MoveAxesAsync(CancellationToken cancellationToken = default, params AxisMovement[] movement);
2620
}
2721
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
2+
// Licensed under the Apache License, Version 2.0
3+
4+
namespace Moryx.AbstractionLayer.Drivers.Axis;
5+
6+
/// <summary>
7+
/// Exception type which will be used for errors during moving axes of <see cref="IAxesController"/>
8+
/// </summary>
9+
public class MoveAxesException : Exception
10+
{
11+
}

src/Moryx.AbstractionLayer/Drivers/Axis/NumberedAxis.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public struct NumberedAxis : IEquatable<NumberedAxis>
1212
/// Axis
1313
/// </summary>
1414
public Axes Axis { get; }
15+
1516
/// <summary>
1617
/// Number
1718
/// </summary>
Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
22
// Licensed under the Apache License, Version 2.0
33

4-
namespace Moryx.AbstractionLayer.Drivers.Camera
4+
namespace Moryx.AbstractionLayer.Drivers.Camera;
5+
6+
/// <summary>
7+
/// Interface for camera devices, that provide image data
8+
/// </summary>
9+
public interface ICameraDriver<TImage> : IDriver where TImage : class
510
{
611
/// <summary>
7-
/// Interface for camera devices, that provide image data
12+
/// Capture a single image from the camera
813
/// </summary>
9-
public interface ICameraDriver<TImage> : IDriver where TImage : class
10-
{
11-
/// <summary>
12-
/// Eventhandler to continously provide images from a camera
13-
/// </summary>
14-
event EventHandler<TImage> CapturedImage;
14+
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.</param>
15+
/// <returns>
16+
/// The image that was captured or null in case no image
17+
/// could be retrieved
18+
/// </returns>
19+
/// <exception cref="OperationCanceledException">The cancellation token was canceled. This exception is stored into the returned task.</exception>
20+
Task<TImage> CaptureImageAsync(CancellationToken cancellationToken = default);
1521

16-
/// <summary>
17-
/// Capture a single image from the camera
18-
/// </summary>
19-
/// <returns>
20-
/// The image that was captured or null in case no image
21-
/// could be retrieved
22-
/// </returns>
23-
Task<TImage?> CaptureImage();
24-
}
22+
/// <summary>
23+
/// Event to continuously provide images from a camera
24+
/// </summary>
25+
event EventHandler<TImage> CapturedImage;
2526
}
26-

src/Moryx.AbstractionLayer/Drivers/Driver.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Moryx.AbstractionLayer.Drivers
1111
/// </summary>
1212
public abstract class Driver : Resource, IDriver, IStateContext
1313
{
14-
/// <see cref="IDriver"/>
14+
/// <inheritdoc />
1515
public IDriverState CurrentState { get; private set; }
1616

1717
void IStateContext.SetState(IState state)
@@ -20,7 +20,7 @@ void IStateContext.SetState(IState state)
2020
StateChanged?.Invoke(this, CurrentState);
2121
}
2222

23-
/// <seealso cref="IDriver"/>
23+
/// <inheritdoc />
2424
public event EventHandler<IDriverState> StateChanged;
2525
}
2626
}

src/Moryx.AbstractionLayer/Drivers/DriverNotRunningException.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
2+
// Licensed under the Apache License, Version 2.0
3+
4+
namespace Moryx.AbstractionLayer.Drivers
5+
{
6+
/// <summary>
7+
/// Exception for busy drivers. The driver cannot handle requests.
8+
/// </summary>
9+
public class DriverStateException : Exception
10+
{
11+
/// <summary>
12+
/// Information about the required state of the driver for the execution
13+
/// </summary>
14+
public StateClassification RequiredState { get; }
15+
16+
/// <summary>
17+
/// Initializes a new instance of the <see cref="DriverStateException"/> class.
18+
/// </summary>
19+
public DriverStateException(StateClassification requiredState)
20+
: base($"Cannot handle the driver request. Driver is not in state {requiredState}!")
21+
{
22+
RequiredState = requiredState;
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)