Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion GitVersion.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mode: ContinuousDeployment
next-version: 0.30.0
next-version: 0.31.0
branches:
main:
regex: ^master$|^main$
Expand Down
52 changes: 52 additions & 0 deletions docfx/articles/connectors/WebAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,55 @@ Entry.Plc.Connector.ConcurrentRequestMaxCount = 1; // Reducing to a single reque
Entry.Plc.Connector.ConcurrentRequestDelay = 100; // Setting the waiting period to 100ms
```

## Batch Operations

The WebAPI connector now supports enhanced batch reading and writing operations with configurable priority levels and chunk settings. This feature allows for more efficient and controlled data exchange with the PLC.

### Priority Levels

Batch operations support four priority levels through the `eAccessPriority` enum:

- `Normal`: Standard priority for regular operations (default)
- `Low`: Lower priority for background or less important operations
- `Prioritare`: Higher priority for time-critical operations
- `Custom`: User-defined priority level for special cases

### Configurable Batch Settings

Each priority level can have its own configuration for chunk size and inter-chunk delay. This allows for fine-tuned control over how batch operations are processed:

```C#
// Configure batch settings for different priority levels
Entry.Plc.Connector.BatchSettings[eAccessPriority.Normal] = (chunkSize: 250, interChunkDelay: 250);
Entry.Plc.Connector.BatchSettings[eAccessPriority.Low] = (chunkSize: 100, interChunkDelay: 500);
Entry.Plc.Connector.BatchSettings[eAccessPriority.Prioritare] = (chunkSize: 500, interChunkDelay: 100);
```

### Using Batch Operations

Here's how to perform batch operations with different priority levels:

```C#
// Batch read with normal priority
await connector.ReadBatchAsync(primitives, eAccessPriority.Normal);

// Batch write with high priority and custom chunk settings
await connector.WriteBatchAsync(primitives, eAccessPriority.Prioritare);

// Background batch operation with low priority
await connector.ReadBatchAsync(primitives, eAccessPriority.Low);

// Custom will take chunkSize and interchunkDelay arguments into consieration.
await connector.WriteBatchAsync(primitives, eAccessPriority.Custom, chunkSize: 300, interChunkDelay: 150);
```

> [!TIP]
> Use appropriate priority levels based on your application's needs:
> - Use `Normal` for regular operations
> - Use `Low` for background updates or non-critical data
> - Use `Prioritare` for time-sensitive operations
> - Use custom chunk settings for specific performance requirements

> [!NOTE]
> The actual performance of batch operations depends on various factors including network conditions, PLC load, and the size of data being transferred. Monitor the connector's logs for insights into batch operation performance.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ public int ConcurrentRequestDelay
return concurrentRequestDelay;
}

set => SetField(ref concurrentRequestDelay, value, nameof(concurrentRequestDelay));
set => SetField(ref concurrentRequestDelay, value, nameof(ConcurrentRequestDelay));
}


Expand All @@ -215,7 +215,7 @@ public int ConcurrentRequestMaxCount
return concurrentRequestMaxCount;
}

set => SetField(ref concurrentRequestMaxCount, value, nameof(concurrentRequestMaxCount));
set => SetField(ref concurrentRequestMaxCount, value, nameof(ConcurrentRequestMaxCount));
}


Expand Down Expand Up @@ -266,20 +266,30 @@ public bool IsRwLoopSuspended
public abstract Connector BuildAndStart();

/// <summary>
/// Reads batch of value items from the plc.
/// Reads batch of value items from the PLC.
/// For `Normal` priority, all primitives are processed in a single chunk.
/// For `Low` priority, primitives are split into smaller chunks with a delay between processing each chunk.
/// </summary>
/// <param name="primitives">Primitive items to be read.</param>
public abstract Task ReadBatchAsync(IEnumerable<ITwinPrimitive> primitives);
/// <param name="primitives">Primitive items to be written.</param>
/// <param name="priority">Access priority for the operation.</param>
/// <param name="chunkSize">Size of each chunk for processing primitives. Default is 250 for Low priority.</param>
/// <param name="interChunkDelay">Delay between processing chunks in milliseconds. Default is 250 for Low priority.</param>
public abstract Task ReadBatchAsync(IEnumerable<ITwinPrimitive> primitives, eAccessPriority priority = eAccessPriority.Normal, int chunkSize = 250, int interChunkDelay = 250);

internal abstract Task ReadBatchAsyncCyclic(IEnumerable<ITwinPrimitive> primitives);
internal abstract Task ReadBatchAsyncCyclic(IEnumerable<ITwinPrimitive> primitives, eAccessPriority priority = eAccessPriority.Normal, int chunkSize = 250, int interChunkDelay = 250);

/// <summary>
/// Writes batch of value items to the plc.
/// Writes batch of value items to the PLC.
/// For `Normal` priority, all primitives are processed in a single chunk.
/// For `Low` priority, primitives are split into smaller chunks with a delay between processing each chunk.
/// </summary>
/// <param name="primitives">Primitive items to be written.</param>
public abstract Task WriteBatchAsync(IEnumerable<ITwinPrimitive> primitives);
/// <param name="priority">Access priority for the operation.</param>
/// <param name="chunkSize">Size of each chunk for processing primitives. Default is 250 for Low priority.</param>
/// <param name="interChunkDelay">Delay between processing chunks in milliseconds. Default is 250 for Low priority.</param>
public abstract Task WriteBatchAsync(IEnumerable<ITwinPrimitive> primitives, eAccessPriority priority = eAccessPriority.Normal, int chunkSize = 250, int interChunkDelay = 250);

internal abstract Task WriteBatchAsyncCyclic(IEnumerable<ITwinPrimitive> primitives);
internal abstract Task WriteBatchAsyncCyclic(IEnumerable<ITwinPrimitive> primitives, eAccessPriority priority = eAccessPriority.Normal, int chunkSize = 250, int interChunkDelay = 250);

/// <summary>
/// Return symbol path combining parent's and member's symbol.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace AXSharp.Connector;

/// <summary>
/// Specifies the access priority levels for connector operations.
/// </summary>
public enum eAccessPriority
{
/// <summary>
/// Standard access priority. Used for regular operations.
/// </summary>
Normal,
/// <summary>
/// Lower than normal access priority. Used for background or less important operations.
/// </summary>
Low,
/// <summary>
/// Higher than normal access priority. Used for time-critical or prioritized operations.
/// </summary>
Prioritare,

/// <summary>
/// Represents a custom access priority level. This can be used for operations that require a user-defined priority.
/// </summary>
Custom
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ private void RwCycle()
/// Reads batch of value items from the plc.
/// </summary>
/// <param name="primitives">Value items to be read.</param>
public override async Task ReadBatchAsync(IEnumerable<ITwinPrimitive> primitives)
/// <param name="priority"></param>
public override async Task ReadBatchAsync(IEnumerable<ITwinPrimitive> primitives,
eAccessPriority priority = eAccessPriority.Normal, int chunkSize = 250, int interChunkDelay = 250)
{
ArgumentNullException.ThrowIfNull(primitives);

Expand All @@ -74,7 +76,10 @@ await Task.Run(() =>
/// Writes batch of value items to the plc.
/// </summary>
/// <param name="primitives">Value items to be written.</param>
public override async Task WriteBatchAsync(IEnumerable<ITwinPrimitive> primitives)
/// <param name="priority">Determined this batch priority</param>
/// <param name="chunkSize">Size of each chunk for processing primitives. Default is 250 for Low priority.</param>
/// <param name="interChunkDelay">Delay between processing chunks in milliseconds. Default is 250 for Low priority.</param>
public override async Task WriteBatchAsync(IEnumerable<ITwinPrimitive> primitives, eAccessPriority priority = eAccessPriority.Normal, int chunkSize = 250, int interChunkDelay = 250)
{
ArgumentNullException.ThrowIfNull(primitives);

Expand All @@ -98,7 +103,8 @@ public override void ReloadConnector()
{
}

internal override async Task ReadBatchAsyncCyclic(IEnumerable<ITwinPrimitive> primitives)
internal override async Task ReadBatchAsyncCyclic(IEnumerable<ITwinPrimitive> primitives,
eAccessPriority priority = eAccessPriority.Normal, int chunkSize = 250, int interChunkDelay = 250)
{
ArgumentNullException.ThrowIfNull(primitives);

Expand All @@ -113,7 +119,7 @@ await Task.Run(() =>
});
}

internal override async Task WriteBatchAsyncCyclic(IEnumerable<ITwinPrimitive> primitives)
internal override async Task WriteBatchAsyncCyclic(IEnumerable<ITwinPrimitive> primitives, eAccessPriority priority = eAccessPriority.Normal, int chunkSize = 250, int interChunkDelay = 250)
{
ArgumentNullException.ThrowIfNull(primitives);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public async void should_read_huge()
output.WriteLine($"Number of items {huge.Count}");
var s = new Stopwatch();
s.Start();
await connector.ReadBatchAsync(huge);
await ((Connector)connector).ReadBatchAsync(huge);
s.Stop();

output.WriteLine($"Whole {s.ElapsedMilliseconds} | per item: {((double)(s.ElapsedMilliseconds) / ((double)huge.Count))}");
Expand Down Expand Up @@ -269,7 +269,7 @@ public async Task should_write_huge()

output.WriteLine($"Whole {s.ElapsedMilliseconds} | per item: {((double)(s.ElapsedMilliseconds) / ((double)huge.Count))}");

await connector.ReadBatchAsync(huge);
await ((Connector)connector).ReadBatchAsync(huge);

Assert.Equal(48, myBYTE.Cyclic);
Assert.True(myBOOL.Cyclic);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespace AXSharp.Connector.S71500.WebAPITests;

public static class TestConnector
{
private static string TargetIp { get; } = Environment.GetEnvironmentVariable("AXTARGET") ?? "10.222.6.1";
private static string UserName { get; } = Environment.GetEnvironmentVariable("AX_USERNAME") ?? "adm";
private static string Password { get; } = Environment.GetEnvironmentVariable("AX_TARGET_PWD");
private static string TargetIp { get; } = "192.168.100.210";
private static string UserName { get; } = "adm";
private static string Password { get; } = "123ABCDabcd$#!";


public static WebApiConnector TestApiConnector
Expand All @@ -23,7 +23,7 @@ public static WebApiConnector TestApiConnector
}
}

private static string CertificatePath = "certs\\Communication.cer";
private static string CertificatePath = "..\\..\\..\\..\\ax-test-project\\certs\\plc_line\\plc_line.cer";

static string GetCertPath()
{
Expand All @@ -49,8 +49,8 @@ public static ax_test_projectTwinController SecurePlc
if (securePlc == null)
{
securePlc = new(ConnectorAdapterBuilder.Build()
.CreateWebApi(TargetIp, Environment.GetEnvironmentVariable("AX_USERNAME"),
Environment.GetEnvironmentVariable("AX_TARGET_PWD"), CertificateValidation, true));
.CreateWebApi(TargetIp, UserName, Password
, CertificateValidation, true));

SecurePlc.Connector.BuildAndStart();
}
Expand Down
Loading