diff --git a/.github/workflows/dotnet-master.yml b/.github/workflows/dotnet-master.yml
index 33f1588..01940af 100644
--- a/.github/workflows/dotnet-master.yml
+++ b/.github/workflows/dotnet-master.yml
@@ -4,12 +4,25 @@ on:
push:
branches: [ "master" ]
+# master branch does a dotnet pack just to test the pipeline, without actually pushing anything to nuget.org.
+# version numbers here do not matters.
+env:
+ VERSION_MAJOR: 0
+ VERSION_MINOR: 0
+ VERSION_SUFFIX: "-anything"
+
jobs:
build:
runs-on: windows-latest
steps:
+ - name: Get current date
+ id: date
+ run: echo "::set-output name=date::$(date +'%Y%m%d')"
+ - name: Set Version variable
+ id: version
+ run: echo "::set-output name=PRODUCT_VERSION::${{ env.VERSION_MAJOR }}.${{ env.VERSION_MINOR }}.${{ steps.date.outputs.date }}.${{ github.run_attempt }}${{ env.VERSION_SUFFIX }}"
- uses: actions/checkout@v3
- name: Setup .NET6
uses: actions/setup-dotnet@v2
@@ -25,3 +38,5 @@ jobs:
run: dotnet build -c Release --no-restore SmartIOT.Connector.sln
- name: Test
run: dotnet test -c Release --no-build --verbosity normal SmartIOT.Connector.sln
+ - name: Pack
+ run: dotnet pack -c Release /p:version=${{ steps.version.outputs.PRODUCT_VERSION }} SmartIOT.Connector.sln
diff --git a/Apps/SmartIOT.Connector.App/Program.cs b/Apps/SmartIOT.Connector.App/Program.cs
index 9bcc1fa..b424e97 100644
--- a/Apps/SmartIOT.Connector.App/Program.cs
+++ b/Apps/SmartIOT.Connector.App/Program.cs
@@ -50,6 +50,7 @@ public static void Main(string[] args)
builder.Logging.AddSerilog(dispose: true);
// Add SmartIOT.Connector services to the container.
+ builder.Services.AddSingleton(configuration.Configuration);
builder.Services.AddSmartIOTConnector(cfg =>
{
cfg.WithAutoDiscoverConnectorFactories()
diff --git a/Core/SmartIOT.Connector.Core/Model/Tag.cs b/Core/SmartIOT.Connector.Core/Model/Tag.cs
index 6e20227..4d09208 100644
--- a/Core/SmartIOT.Connector.Core/Model/Tag.cs
+++ b/Core/SmartIOT.Connector.Core/Model/Tag.cs
@@ -1,4 +1,5 @@
using SmartIOT.Connector.Core.Conf;
+using System.Net.Http.Headers;
namespace SmartIOT.Connector.Core.Model;
@@ -39,24 +40,43 @@ public Tag(TagConfiguration tagConfiguration)
IsInitialized = false;
}
+#pragma warning disable S2551 // Shared resources should not be used for locking: we purposefully lock on "this" to avoid races between tag-scheduler and services that request tag write.
+
///
- /// Questo metodo copia i dati ricevuti in argomento allo startOffset indicato.
- /// Lo startOffset deve essere passato in valore assoluto, quindi se un tag inizia al byte 100
- /// e il metodo intende scrivere i byte dal 110 al 120 passerà come argomenti startOffset = 110 e un array di lunghezza = 11.
- /// In ogni caso, il metodo imposta il flag di richiesta scrittura: se l'array passato in argomento non provoca nessuna variazione
- /// dei dati, il flag viene alzato comunque (e come effetto verrà scritto l'intero tag).
+ /// This method copies the data received as an argument to the specified startOffset.
+ /// The startOffset must be passed as an absolute value, so if a tag starts at byte 100
+ /// and the method intends to write bytes from 110 to 120, it will pass startOffset = 110 and an array of length = 11 as arguments.
+ /// The method performs a range check to determine the intersection of the passed range, compared to the definition
+ /// of the tag. If there is no intersection, false is returned and nothing is copied.
+ /// If there at least 1 byte of intersection, that range is copied, flag is set and true is returned.
+ /// Be aware the flag IsWriteSynchronizationRequested is set even if the underlying data is not changed: no byte compare is performed to check for modifications.
///
- public void RequestTagWrite(byte[] data, int startOffset)
+ public bool TryMergeData(ReadOnlySpan data, int startOffset, int size)
{
-#pragma warning disable S2551 // Shared resources should not be used for locking: we purposefully lock on "this" to avoid races between tag-scheduler and services that request tag write.
- lock (this)
+ if (startOffset + size > ByteOffset && startOffset < ByteOffset + Size)
{
- Array.Copy(data, 0, Data, startOffset - ByteOffset, data.Length);
- IsWriteSynchronizationRequested = true;
+ int start = Math.Max(startOffset, ByteOffset);
+ int end = Math.Min(startOffset + size, ByteOffset + Data.Length);
+
+ lock (this)
+ {
+ data.Slice(start - startOffset, end - start).CopyTo(Data.AsSpan().Slice(start - ByteOffset));
+ IsWriteSynchronizationRequested = true;
+ }
+
+ return true;
}
-#pragma warning restore S2551 // Shared resources should not be used for locking
+
+ return false;
+ }
+
+ public bool TryMergeData(ReadOnlySpan data, int startOffset)
+ {
+ return TryMergeData(data, startOffset, data.Length);
}
+#pragma warning restore S2551 // Shared resources should not be used for locking
+
///
/// This method returns a copy of the current bytes stored in the tag
///
diff --git a/Core/SmartIOT.Connector.Core/SmartIotConnector.cs b/Core/SmartIOT.Connector.Core/SmartIotConnector.cs
index 22258cf..6e4cdcd 100644
--- a/Core/SmartIOT.Connector.Core/SmartIotConnector.cs
+++ b/Core/SmartIOT.Connector.Core/SmartIotConnector.cs
@@ -271,40 +271,10 @@ public void RequestTagWrite(string deviceId, string tagId, int startOffset, byte
.Where(tag => string.Equals(tag.TagId, tagId, StringComparison.InvariantCultureIgnoreCase) && tag.TagType == TagType.WRITE)
)
{
- lock (tag)
- {
- bool changes = MergeData(tag, startOffset, data);
- if (changes)
- tag.IsWriteSynchronizationRequested = true;
- }
+ tag.TryMergeData(data, startOffset, data.Length);
}
}
- private bool MergeData(Model.Tag tag, int startOffset, byte[] data)
- {
- var somethingChanged = false;
-
- if (startOffset + data.Length > tag.ByteOffset && startOffset < tag.ByteOffset + tag.Size)
- {
- int start = Math.Max(startOffset, tag.ByteOffset);
- int end = Math.Min(startOffset + data.Length, tag.ByteOffset + tag.Data.Length);
-
- for (int i = start; i < end; i++)
- {
- byte newValue = data[i - startOffset];
- if (!somethingChanged)
- {
- byte oldValue = tag.Data[i - tag.ByteOffset];
- if (oldValue != newValue)
- somethingChanged = true;
- }
- tag.Data[i - tag.ByteOffset] = newValue;
- }
- }
-
- return somethingChanged;
- }
-
public async Task RunInitializationActionAsync(Func, IList, Task> initAction)
{
foreach (var scheduler in _schedulers)
diff --git a/Core/SmartIOT.Connector.RestApi/Services/DeviceService.cs b/Core/SmartIOT.Connector.RestApi/Services/DeviceService.cs
index 2f53873..cf6e013 100644
--- a/Core/SmartIOT.Connector.RestApi/Services/DeviceService.cs
+++ b/Core/SmartIOT.Connector.RestApi/Services/DeviceService.cs
@@ -105,7 +105,7 @@ public void SetTagData(string deviceId, string tagId, TagData tagData)
if (tagData.StartOffset + tagData.Bytes.Length > tag.ByteOffset + tag.Size)
throw new DeviceException($"Data packet is too big. Requested: [{tagData.StartOffset}..{tagData.StartOffset + tagData.Bytes.Length - 1}], accepted: [{tag.ByteOffset}..{tag.ByteOffset + tag.Size - 1}]");
- tag.RequestTagWrite(tagData.Bytes, tagData.StartOffset);
+ tag.TryMergeData(tagData.Bytes, tagData.StartOffset);
}
public Tag? GetTag(string deviceId, string tagId)
diff --git a/Tests/SmartIOT.Connector.Core.Tests/TagSchedulerEngineTests.cs b/Tests/SmartIOT.Connector.Core.Tests/TagSchedulerEngineTests.cs
index bad6b5a..a7905d5 100644
--- a/Tests/SmartIOT.Connector.Core.Tests/TagSchedulerEngineTests.cs
+++ b/Tests/SmartIOT.Connector.Core.Tests/TagSchedulerEngineTests.cs
@@ -225,7 +225,7 @@ public void Test_partial_reads()
// quando viene letto il tag20, simulo la richiesta di scrittura
driver.ReadTagCallback = (data, startOffset, length) =>
{
- tag22.RequestTagWrite(new byte[] { 100, 101 }, 10);
+ Assert.True(tag22.TryMergeData(new byte[] { 100, 101 }, 10));
driver.ReadTagCallback = null; // autoreset alla prima invocazione
};
@@ -466,7 +466,7 @@ public void Test_read_write_cycle(bool pduWriteOptimizationEnabled, int singlePd
}
// verifica di scrittura in errore
- tag22.RequestTagWrite(new byte[] { 33 }, 10); // richiesta di modifica dati
+ Assert.True(tag22.TryMergeData(new byte[] { 33 }, 10)); // richiesta di modifica dati
driver.WriteReturns = 1;
@@ -529,8 +529,8 @@ public void Test_read_write_cycle(bool pduWriteOptimizationEnabled, int singlePd
// verifica di scrittura ottimizzata a seconda della dimensione della PDU
driver.ResetInvocations();
- tag22.RequestTagWrite(new byte[] { 100, 101, 102 }, 10);
- tag22.RequestTagWrite(new byte[] { 200, 201 }, 20);
+ Assert.True(tag22.TryMergeData(new byte[] { 100, 101, 102 }, 10));
+ Assert.True(tag22.TryMergeData(new byte[] { 200, 201 }, 20));
t22 = engine.GetNextTagSchedule();
Assert.Equal(tag22, t22.Tag);