Skip to content

Commit f50efc8

Browse files
committed
Fix UpdateParameter Loop
1 parent 676a8d5 commit f50efc8

File tree

4 files changed

+129
-32
lines changed

4 files changed

+129
-32
lines changed

RDMSharp/RDM/Device/AbstractRDMCache.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ public AbstractRDMCache()
7171

7272
}
7373

74+
protected void InvokeParameterValueAdded(ParameterValueAddedEventArgs e)
75+
{
76+
this.ParameterValueAdded?.InvokeFailSafe(this, e);
77+
}
78+
7479

7580
protected void updateParameterValuesDependeciePropertyBag(ERDM_Parameter parameter, DataTreeBranch dataTreeBranch)
7681
{

RDMSharp/RDM/Device/AbstractRemoteRDMDevice.cs

Lines changed: 91 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Concurrent;
55
using System.Collections.Generic;
66
using System.Data.Common;
7+
using System.Diagnostics;
78
using System.Linq;
89
using System.Reflection;
910
using System.Reflection.Metadata;
@@ -108,7 +109,6 @@ private set
108109

109110
private DateTime lastSendQueuedMessage;
110111

111-
private SemaphoreSlim presentSemaphoreSlim = new SemaphoreSlim(1);
112112
private bool present;
113113
public bool Present
114114
{
@@ -170,6 +170,7 @@ private void Instance_PresentUpdateTimerElapsed(object sender, EventArgs e)
170170
private async void DeviceModel_Initialized(object sender, EventArgs e)
171171
{
172172
deviceModel.Initialized -= DeviceModel_Initialized;
173+
deviceModel.ParameterValueAdded -= DeviceModel_ParameterValueAdded;
173174
await collectParameters();
174175
}
175176
private async Task collectParameters()
@@ -288,41 +289,88 @@ private async Task requestParameter(ERDM_Parameter parameter, object payload = n
288289
}
289290
}
290291

292+
private SemaphoreSlim updateSenaphoreSlim = new SemaphoreSlim(1);
291293
private async Task updateParameters()
292294
{
293295
if (QueuedSupported && deviceModel.KnownNotSupportedParameters.Contains(ERDM_Parameter.QUEUED_MESSAGE))
294296
QueuedSupported = false;
295297

296-
if (QueuedSupported && !deviceModel.KnownNotSupportedParameters.Contains(ERDM_Parameter.QUEUED_MESSAGE))
298+
if (updateSenaphoreSlim.CurrentCount == 0)
299+
return;
300+
301+
await updateSenaphoreSlim.WaitAsync();
302+
try
297303
{
298-
if (DateTime.UtcNow - lastSendQueuedMessage < TimeSpan.FromMilliseconds(GlobalTimers.Instance.QueuedUpdateTime))
299-
return;
300-
ParameterBag parameterBag = new ParameterBag(ERDM_Parameter.QUEUED_MESSAGE, this.DeviceModel.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId);
301-
var define = MetadataFactory.GetDefine(parameterBag);
302-
if (define.GetRequest.HasValue)
304+
if (QueuedSupported && !deviceModel.KnownNotSupportedParameters.Contains(ERDM_Parameter.QUEUED_MESSAGE))
303305
{
304-
byte mc = 0;
305-
do
306+
if (DateTime.UtcNow - lastSendQueuedMessage < TimeSpan.FromMilliseconds(GlobalTimers.Instance.QueuedUpdateTime))
307+
return;
308+
ParameterBag parameterBag = new ParameterBag(ERDM_Parameter.QUEUED_MESSAGE, this.DeviceModel.ManufacturerID, DeviceInfo.DeviceModelId, DeviceInfo.SoftwareVersionId);
309+
var define = MetadataFactory.GetDefine(parameterBag);
310+
if (define.GetRequest.HasValue)
306311
{
307-
lastSendQueuedMessage = DateTime.UtcNow;
308-
mc = await requestGetParameterWithPayload(parameterBag, define, UID, Subdevice, ERDM_Status.ADVISORY);
309-
await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenQueuedUpdateRequests);
310-
312+
byte mc = 0;
313+
do
314+
{
315+
var cts = new CancellationTokenSource();
316+
cts.CancelAfter(TimeSpan.FromMilliseconds(GlobalTimers.Instance.ParameterUpdateTimerInterval));
317+
var task = Task.Run(async () =>
318+
{
319+
lastSendQueuedMessage = DateTime.UtcNow;
320+
321+
Stopwatch sw = new Stopwatch();
322+
sw?.Restart();
323+
mc = await requestGetParameterWithPayload(parameterBag, define, UID, Subdevice, ERDM_Status.ADVISORY);
324+
sw?.Stop();
325+
Logger?.LogTrace($"Queued Parameter update took {sw.ElapsedMilliseconds}ms for {mc} messages.");
326+
}, cts.Token);
327+
await task;
328+
329+
if (task.IsCompletedSuccessfully)
330+
await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenQueuedUpdateRequests);
331+
else
332+
{
333+
Logger?.LogTrace(task.Exception, $"Queue Parameter update failed: {task.Exception?.Message}");
334+
return;
335+
}
336+
337+
}
338+
while (mc != 0);
339+
return;
311340
}
312-
while (mc != 0);
313-
return;
341+
}
342+
while (ParameterUpdatedBag.TryPeek(out ParameterUpdatedBag bag))
343+
{
344+
if (DateTime.UtcNow - bag.Timestamp < TimeSpan.FromMilliseconds(GlobalTimers.Instance.NonQueuedUpdateTime))
345+
return;
346+
347+
var cts = new CancellationTokenSource();
348+
cts.CancelAfter(TimeSpan.FromMilliseconds(GlobalTimers.Instance.ParameterUpdateTimerInterval));
349+
var task = Task.Run(async () =>
350+
{
351+
Stopwatch sw = new Stopwatch();
352+
sw?.Restart();
353+
await requestParameter(bag.Parameter, bag.Index);
354+
sw?.Stop();
355+
Logger?.LogTrace($"Parameter update for {bag.Parameter} with index {bag.Index} took {sw.ElapsedMilliseconds}ms");
356+
357+
UpdateParameterUpdatedBag(bag.Parameter, bag.Index);
358+
}, cts.Token);
359+
await task;
360+
361+
if (task.IsCompletedSuccessfully)
362+
await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenNonQueuedUpdateRequests);
363+
else
364+
Logger?.LogTrace(task.Exception, $"Parameter update for {bag.Parameter} with index {bag.Index} failed: {task.Exception?.Message}");
314365
}
315366
}
316-
while (ParameterUpdatedBag.TryPeek(out ParameterUpdatedBag bag))
367+
catch (Exception ex)
317368
{
318-
if (DateTime.UtcNow - bag.Timestamp < TimeSpan.FromMilliseconds(GlobalTimers.Instance.NonQueuedUpdateTime))
319-
return;
320-
321-
await requestParameter(bag.Parameter, bag.Index);
322-
323-
UpdateParameterUpdatedBag(bag.Parameter, bag.Index);
324-
325-
await Task.Delay(GlobalTimers.Instance.UpdateDelayBetweenNonQueuedUpdateRequests);
369+
Logger?.LogError(ex);
370+
}
371+
finally
372+
{
373+
updateSenaphoreSlim.Release();
326374
}
327375
}
328376

@@ -335,11 +383,29 @@ private async Task getDeviceModelAndCollectAllParameters()
335383
if (!deviceModel.IsInitialized)
336384
{
337385
deviceModel.Initialized += DeviceModel_Initialized;
338-
await deviceModel.Initialize();
386+
deviceModel.ParameterValueAdded += DeviceModel_ParameterValueAdded;
387+
if (!deviceModel.IsInitializing)
388+
await deviceModel.Initialize();
389+
else
390+
InvkoeDeviceModelParameterValueAdded();
339391
}
340392
else
393+
{
394+
InvkoeDeviceModelParameterValueAdded();
341395
await collectParameters();
396+
}
397+
void InvkoeDeviceModelParameterValueAdded()
398+
{
399+
foreach (var item in this.deviceModel.ParameterValues)
400+
base.InvokeParameterValueAdded(new ParameterValueAddedEventArgs(item.Key, item.Value));
401+
}
402+
}
403+
404+
private void DeviceModel_ParameterValueAdded(object sender, ParameterValueAddedEventArgs e)
405+
{
406+
base.InvokeParameterValueAdded(e);
342407
}
408+
343409
private async Task collectAllParametersOnRoot()
344410
{
345411
await requestParameters();

RDMSharp/RDM/Device/RDMDeviceModel.cs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Generic;
55
using System.ComponentModel;
66
using System.Linq;
7+
using System.Threading;
78
using System.Threading.Tasks;
89

910
namespace RDMSharp
@@ -72,9 +73,21 @@ internal async Task<RDMPersonalityModel> getPersonalityModel(IRDMRemoteDevice re
7273
public new bool IsDisposed { get; private set; }
7374

7475
public bool IsInitialized { get; private set; } = false;
76+
public bool IsInitializing { get; private set; } = false;
7577

7678
public event EventHandler Initialized;
77-
public event PropertyChangedEventHandler PropertyChanged;
79+
public event PropertyChangedEventHandler PropertyChanged;
80+
public new event EventHandler<ParameterValueAddedEventArgs> ParameterValueAdded
81+
{
82+
add
83+
{
84+
base.ParameterValueAdded += value;
85+
}
86+
remove
87+
{
88+
base.ParameterValueAdded -= value;
89+
}
90+
}
7891

7992
public readonly ushort ManufacturerID;
8093
public readonly EManufacturer Manufacturer;
@@ -156,16 +169,29 @@ internal RDMDeviceModel(UID uid, SubDevice subdevice, RDMDeviceInfo deviceInfo)
156169
this.ParameterValueAdded += RDMDeviceModel_ParameterValueAdded;
157170
}
158171

172+
private SemaphoreSlim initializeSemaphoreSlim = new SemaphoreSlim(1);
159173
internal async Task Initialize()
160174
{
161175
if (IsInitialized)
162176
return;
177+
if (initializeSemaphoreSlim.CurrentCount == 0)
178+
return;
179+
IsInitializing = true;
163180

164-
await requestSupportedParameters();
165-
await requestBlueprintParameters();
166-
await requestPersonalityBlueprintParameters();
181+
await initializeSemaphoreSlim.WaitAsync();
182+
try
183+
{
184+
await requestSupportedParameters();
185+
await requestBlueprintParameters();
186+
await requestPersonalityBlueprintParameters();
167187

168-
IsInitialized = true;
188+
IsInitialized = true;
189+
}
190+
finally
191+
{
192+
initializeSemaphoreSlim.Release();
193+
IsInitializing = false;
194+
}
169195
Initialized?.Invoke(this, EventArgs.Empty);
170196
}
171197

RDMSharp/RDM/GlobalTimers.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ public static GlobalTimers Instance
1717
}
1818

1919
public const int DefaultQueuedUpdateTime = 4000; // 4 seconds
20-
public const int DefaultNonQueuedUpdateTime = 4000; // 4 seconds
20+
public const int DefaultNonQueuedUpdateTime = 10000; // 10 seconds
2121
public const int DefaultUpdateDelayBetweenRequests = 50; // 50 milliseconds
2222
public const int DefaultUpdateDelayBetweenQueuedUpdateRequests = 200; // 200 milliseconds
23-
public const int DefaultUpdateDelayBetweenNonQueuedUpdateRequests = 200; // 200 milliseconds
23+
public const int DefaultUpdateDelayBetweenNonQueuedUpdateRequests = 500; // 500 milliseconds
2424
public const int DefaultPresentLostTime = 15000; // 15 seconds
2525

2626
public const int DefaultDiscoveryTimeout = 5; // 5 milliseconds

0 commit comments

Comments
 (0)