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.31.0
next-version: 0.32.0
branches:
main:
regex: ^master$|^main$
Expand Down
43 changes: 25 additions & 18 deletions docfx/articles/connectors/WebAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,52 +63,59 @@ Entry.Plc.Connector.ConcurrentRequestDelay = 100; // Setting the waiting period

## 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.
The WebAPI connector provides sophisticated batch reading and writing operations with configurable priority levels and chunk settings. This feature enables efficient and controlled data exchange with the PLC while respecting different operational requirements.

### Priority Levels

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

- `Low`: For background or non-critical operations that can tolerate longer response times
- `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
- `UserInterface`: Priority for operations triggered by direct user interaction, ensuring responsive UI feedback
- `High`: For time-critical operations requiring minimal latency
- `Custom`: User-defined priority level for specialized scenarios

### 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:
Each priority level has its own configuration for chunk size and inter-chunk delay, allowing fine-tuned control over batch processing:

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

### Using Batch Operations

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

```C#
// Batch read with normal priority
// Regular 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);
// UI-triggered batch operation with higher responsiveness
await connector.WriteBatchAsync(primitives, eAccessPriority.UserInterface);

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

// Custom will take chunkSize and interchunkDelay arguments into consieration.
// Time-critical batch operation
await connector.WriteBatchAsync(primitives, eAccessPriority.High);

// Custom batch operation with specific settings
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
> Choose appropriate priority levels based on your application's needs:
> - Use `Normal` for regular operations that don't require special handling
> - Use `Low` for background updates or non-critical data that can tolerate delays
> - Use `UserInterface` for operations triggered by user actions requiring quick feedback
> - Use `High` for time-critical operations needing minimal latency
> - Use `Custom` when you need specific chunk size and delay settings

> [!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.
Expand Down
36 changes: 33 additions & 3 deletions src/AXSharp.compiler/src/AXSharp.Cs.Compiler/Helpers/CsHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,25 @@ public static string GetAttributeNameValue(this IDeclaration declaration, string
return declaration.GetPropertyValue("AttributeName", memberName);
}

public static string CreateGenericSwapperMethodToPlainer(string methodName, string pocoTypeName, bool isExtended)
//public static string CreateGenericSwapperMethodToPlainer(string methodName,
// string pocoTypeName,
// bool isExtended)
//{
// var qualifier = isExtended ? "override" : "virtual";
// return $"public async {qualifier} Task<T> {methodName}<T>(eAccessPriority priority = eAccessPriority.Normal){{\n return await (dynamic)this.{methodName}Async(priority);\n}}";
//}

public static string CreateGenericSwapperMethodToPlainerOnliners(string methodName,
string pocoTypeName,
bool isExtended)
{
var qualifier = isExtended ? "override" : "virtual";
return $"public async {qualifier} Task<T> {methodName}<T>(eAccessPriority priority = eAccessPriority.Normal){{\n return await (dynamic)this.{methodName}Async(priority);\n}}";
}

public static string CreateGenericSwapperMethodToPlainerShadows(string methodName,
string pocoTypeName,
bool isExtended)
{
var qualifier = isExtended ? "override" : "virtual";
return $"public async {qualifier} Task<T> {methodName}<T>(){{\n return await (dynamic)this.{methodName}Async();\n}}";
Expand All @@ -54,12 +72,24 @@ public static string CreateGenericHasChangedMethodMethod(string methodName, stri
return sb.ToString();
}

public static string CreateGenericSwapperMethodFromPlainer(string methodName, string pocoTypeName, bool isExtended)
//public static string CreateGenericSwapperMethodFromPlainer(string methodName, string pocoTypeName, bool isExtended)
//{
// var qualifier = isExtended ? "override" : "virtual";
// return $"public async {qualifier} Task {methodName}<T>(T plain){{\n await this.{methodName}Async((dynamic)plain);\n}}";
//}

public static string CreateGenericSwapperMethodFromPlainerOnliner(string methodName, string pocoTypeName, bool isExtended)
{
var qualifier = isExtended ? "override" : "virtual";
return $"public async {qualifier} Task {methodName}<T>(T plain, eAccessPriority priority = eAccessPriority.Normal){{\n await this.{methodName}Async((dynamic)plain, priority);\n}}";
}

public static string CreateGenericSwapperMethodFromPlainerShadow(string methodName, string pocoTypeName, bool isExtended)
{
var qualifier = isExtended ? "override" : "virtual";
return $"public async {qualifier} Task {methodName}<T>(T plain){{\n await this.{methodName}Async((dynamic)plain);\n}}";
}

/// <summary>
/// Gets fully qualified name of poco type for a given type declaration.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,11 @@ public static CsOnlinerPlainerOnlineToPlainBuilder Create(IxNodeVisitor visitor,
{
var builder = new CsOnlinerPlainerOnlineToPlainBuilder(sourceBuilder);

builder.AddToSource(CsHelpers.CreateGenericSwapperMethodToPlainer(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", false));
builder.AddToSource(CsHelpers.CreateGenericSwapperMethodToPlainerOnliners(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", false));

builder.AddToSource($"public async Task<{semantics.GetFullyQualifiedPocoName()}> {MethodName}Async(){{\n");
builder.AddToSource($"public async Task<{semantics.GetFullyQualifiedPocoName()}> {MethodName}Async(eAccessPriority priority = eAccessPriority.Normal){{\n");
builder.AddToSource($"{semantics.GetFullyQualifiedPocoName()} plain = new {semantics.GetFullyQualifiedPocoName()}();");
builder.AddToSource("await this.ReadAsync<IgnoreOnPocoOperation>();");
builder.AddToSource("await this.ReadAsync<IgnoreOnPocoOperation>(priority);");

semantics.Fields.ToList().ForEach(p => p.Accept(visitor, builder));

Expand All @@ -161,13 +161,13 @@ public static CsOnlinerPlainerOnlineToPlainBuilder Create(IxNodeVisitor visitor,
{
var builder = new CsOnlinerPlainerOnlineToPlainBuilder(sourceBuilder);

builder.AddToSource(CsHelpers.CreateGenericSwapperMethodToPlainer(MethodName,$"{semantics.GetFullyQualifiedPocoName()}", isExtended));
builder.AddToSource(CsHelpers.CreateGenericSwapperMethodToPlainerOnliners(MethodName,$"{semantics.GetFullyQualifiedPocoName()}", isExtended));

var qualifier = isExtended ? "new" : string.Empty;

builder.AddToSource($"public {qualifier} async Task<{semantics.GetFullyQualifiedPocoName()}> {MethodName}Async(){{\n");
builder.AddToSource($"public {qualifier} async Task<{semantics.GetFullyQualifiedPocoName()}> {MethodName}Async(eAccessPriority priority = eAccessPriority.Normal){{\n");
builder.AddToSource($"{semantics.GetFullyQualifiedPocoName()} plain = new {semantics.GetFullyQualifiedPocoName()}();");
builder.AddToSource("await this.ReadAsync<IgnoreOnPocoOperation>();");
builder.AddToSource("await this.ReadAsync<IgnoreOnPocoOperation>(priority);");

if (isExtended)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,13 @@ public static CsOnlinerPlainerPlainToOnlineBuilder Create(IxNodeVisitor visitor,
{
var builder = new CsOnlinerPlainerPlainToOnlineBuilder(sourceBuilder);

builder.AddToSource(CsHelpers.CreateGenericSwapperMethodFromPlainer(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", false));
builder.AddToSource(CsHelpers.CreateGenericSwapperMethodFromPlainerOnliner(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", false));

builder.AddToSource($"public async Task<IEnumerable<ITwinPrimitive>> {MethodName}Async({semantics.GetFullyQualifiedPocoName()} plain){{\n");
builder.AddToSource($"public async Task<IEnumerable<ITwinPrimitive>> {MethodName}Async({semantics.GetFullyQualifiedPocoName()} plain, eAccessPriority priority = eAccessPriority.Normal){{\n");

semantics.Fields.ToList().ForEach(p => p.Accept(visitor, builder));

builder.AddToSource("return await this.WriteAsync<IgnoreOnPocoOperation>();");
builder.AddToSource("return await this.WriteAsync<IgnoreOnPocoOperation>(priority);");

builder.AddToSource($"}}");

Expand All @@ -169,12 +169,12 @@ public static CsOnlinerPlainerPlainToOnlineBuilder Create(IxNodeVisitor visitor,
{
var builder = new CsOnlinerPlainerPlainToOnlineBuilder(sourceBuilder);

builder.AddToSource(CsHelpers.CreateGenericSwapperMethodFromPlainer(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", isExtended));
builder.AddToSource(CsHelpers.CreateGenericSwapperMethodFromPlainerOnliner(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", isExtended));

//var qualifier = isExtended ? "new" : string.Empty;
var qualifier = string.Empty;

builder.AddToSource($"public {qualifier} async Task<IEnumerable<ITwinPrimitive>> {MethodName}Async({semantics.GetFullyQualifiedPocoName()} plain){{\n");
builder.AddToSource($"public {qualifier} async Task<IEnumerable<ITwinPrimitive>> {MethodName}Async({semantics.GetFullyQualifiedPocoName()} plain, eAccessPriority priority = eAccessPriority.Normal){{\n");


if (isExtended)
Expand All @@ -184,7 +184,7 @@ public static CsOnlinerPlainerPlainToOnlineBuilder Create(IxNodeVisitor visitor,

semantics.Fields.ToList().ForEach(p => p.Accept(visitor, builder));

builder.AddToSource("return await this.WriteAsync<IgnoreOnPocoOperation>();");
builder.AddToSource("return await this.WriteAsync<IgnoreOnPocoOperation>(priority);");

builder.AddToSource($"}}");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public static CsOnlinerPlainerPlainToShadowBuilder Create(IxNodeVisitor visitor,
{
var builder = new CsOnlinerPlainerPlainToShadowBuilder(sourceBuilder);

builder.AddToSource(CsHelpers.CreateGenericSwapperMethodFromPlainer(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", false));
builder.AddToSource(CsHelpers.CreateGenericSwapperMethodFromPlainerShadow(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", false));

builder.AddToSource($"public async Task<IEnumerable<ITwinPrimitive>> {MethodName}Async({semantics.GetFullyQualifiedPocoName()} plain){{\n");

Expand All @@ -143,7 +143,7 @@ public static CsOnlinerPlainerPlainToShadowBuilder Create(IxNodeVisitor visitor,
{
var builder = new CsOnlinerPlainerPlainToShadowBuilder(sourceBuilder);

builder.AddToSource(CsHelpers.CreateGenericSwapperMethodFromPlainer(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", isExtended));
builder.AddToSource(CsHelpers.CreateGenericSwapperMethodFromPlainerShadow(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", isExtended));

//var qualifier = isExtended ? "new" : string.Empty;
var qualifier = string.Empty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public static CsOnlinerPlainerShadowToPlainBuilder Create(IxNodeVisitor visitor,
{
var builder = new CsOnlinerPlainerShadowToPlainBuilder(sourceBuilder);

builder.AddToSource(CsHelpers.CreateGenericSwapperMethodToPlainer(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", false));
builder.AddToSource(CsHelpers.CreateGenericSwapperMethodToPlainerShadows(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", false));

builder.AddToSource($"public async Task<{semantics.GetFullyQualifiedPocoName()}> {MethodName}Async(){{\n");
builder.AddToSource($"{semantics.GetFullyQualifiedPocoName()} plain = new {semantics.GetFullyQualifiedPocoName()}();");
Expand All @@ -143,7 +143,7 @@ public static CsOnlinerPlainerShadowToPlainBuilder Create(IxNodeVisitor visitor,
{
var builder = new CsOnlinerPlainerShadowToPlainBuilder(sourceBuilder);

builder.AddToSource(CsHelpers.CreateGenericSwapperMethodToPlainer(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", isExtended));
builder.AddToSource(CsHelpers.CreateGenericSwapperMethodToPlainerShadows(MethodName, $"{semantics.GetFullyQualifiedPocoName()}", isExtended));

var qualifier = isExtended ? "new" : string.Empty;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ public Connector.Connector GetConnector()
throw new NotImplementedException();
}

public Task<T> OnlineToPlain<T>()
public Task<T> OnlineToPlain<T>(eAccessPriority priority = eAccessPriority.Normal)
{
throw new NotImplementedException();
}

public Task PlainToOnline<T>(T plain)
public Task PlainToOnline<T>(T plain, eAccessPriority priority = eAccessPriority.Normal)
{
throw new NotImplementedException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ public AbstractMotor(AXSharp.Connector.ITwinObject parent, string readableTail,
PostConstruct(parent, readableTail, symbolTail);
}

public async virtual Task<T> OnlineToPlain<T>()
public async virtual Task<T> OnlineToPlain<T>(eAccessPriority priority = eAccessPriority.Normal)
{
return await (dynamic)this.OnlineToPlainAsync();
return await (dynamic)this.OnlineToPlainAsync(priority);
}

public async Task<global::Pocos.AbstractMotor> OnlineToPlainAsync()
public async Task<global::Pocos.AbstractMotor> OnlineToPlainAsync(eAccessPriority priority = eAccessPriority.Normal)
{
global::Pocos.AbstractMotor plain = new global::Pocos.AbstractMotor();
await this.ReadAsync<IgnoreOnPocoOperation>();
await this.ReadAsync<IgnoreOnPocoOperation>(priority);
plain.Run = Run.LastValue;
plain.ReverseDirection = ReverseDirection.LastValue;
return plain;
Expand All @@ -60,20 +60,20 @@ public async virtual Task<T> OnlineToPlain<T>()
return plain;
}

public async virtual Task PlainToOnline<T>(T plain)
public async virtual Task PlainToOnline<T>(T plain, eAccessPriority priority = eAccessPriority.Normal)
{
await this.PlainToOnlineAsync((dynamic)plain);
await this.PlainToOnlineAsync((dynamic)plain, priority);
}

public async Task<IEnumerable<ITwinPrimitive>> PlainToOnlineAsync(global::Pocos.AbstractMotor plain)
public async Task<IEnumerable<ITwinPrimitive>> PlainToOnlineAsync(global::Pocos.AbstractMotor plain, eAccessPriority priority = eAccessPriority.Normal)
{
#pragma warning disable CS0612
Run.LethargicWrite(plain.Run);
#pragma warning restore CS0612
#pragma warning disable CS0612
ReverseDirection.LethargicWrite(plain.ReverseDirection);
#pragma warning restore CS0612
return await this.WriteAsync<IgnoreOnPocoOperation>();
return await this.WriteAsync<IgnoreOnPocoOperation>(priority);
}

[Obsolete("This method should not be used if you indent to access the controllers data. Use `PlainToOnline` instead.")]
Expand Down
Loading