Only update console, when content changes
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
|
|
||||||
|
namespace Sharp7.Monitor;
|
||||||
|
|
||||||
public static class CustomStyles
|
public static class CustomStyles
|
||||||
{
|
{
|
||||||
public static Style Error { get; } = new Style(foreground: Color.Red);
|
public static Style Error { get; } = new Style(foreground: Color.Red);
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
using System.Collections;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Threading.Tasks;
|
using System.Reactive.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Sharp7.Read;
|
|
||||||
using Sharp7.Rx;
|
using Sharp7.Rx;
|
||||||
using Sharp7.Rx.Enums;
|
using Sharp7.Rx.Enums;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Cli;
|
using Spectre.Console.Cli;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
|
namespace Sharp7.Monitor;
|
||||||
|
|
||||||
internal sealed class ReadPlcCommand : AsyncCommand<ReadPlcCommand.Settings>
|
internal sealed class ReadPlcCommand : AsyncCommand<ReadPlcCommand.Settings>
|
||||||
{
|
{
|
||||||
public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
|
public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
|
||||||
@@ -27,9 +27,9 @@ internal sealed class ReadPlcCommand : AsyncCommand<ReadPlcCommand.Settings>
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IRenderable FormatCellData(VariableRecord record)
|
private static IRenderable FormatCellData(object value)
|
||||||
{
|
{
|
||||||
return record.Value switch
|
return value switch
|
||||||
{
|
{
|
||||||
IRenderable renderable => renderable,
|
IRenderable renderable => renderable,
|
||||||
Exception ex => new Text(ex.Message, CustomStyles.Error),
|
Exception ex => new Text(ex.Message, CustomStyles.Error),
|
||||||
@@ -42,10 +42,10 @@ internal sealed class ReadPlcCommand : AsyncCommand<ReadPlcCommand.Settings>
|
|||||||
long => FormatNo(),
|
long => FormatNo(),
|
||||||
ulong => FormatNo(),
|
ulong => FormatNo(),
|
||||||
|
|
||||||
_ => new Text(record.Value.ToString() ?? "")
|
_ => new Text(value.ToString() ?? "")
|
||||||
};
|
};
|
||||||
|
|
||||||
Markup FormatNo() => new($"[blue]0x{record.Value:X2}[/] {record.Value}");
|
Markup FormatNo() => new($"[blue]0x{value:X2}[/] {value}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task RunProgram(Settings settings, CancellationToken token)
|
private static async Task RunProgram(Settings settings, CancellationToken token)
|
||||||
@@ -99,9 +99,10 @@ internal sealed class ReadPlcCommand : AsyncCommand<ReadPlcCommand.Settings>
|
|||||||
while (!token.IsCancellationRequested)
|
while (!token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
foreach (var record in variableContainer.VariableRecords)
|
foreach (var record in variableContainer.VariableRecords)
|
||||||
|
if (record.HasUpdate(out var value))
|
||||||
table.Rows.Update(
|
table.Rows.Update(
|
||||||
record.RowIdx, 1,
|
record.RowIdx, 1,
|
||||||
FormatCellData(record)
|
FormatCellData(value)
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.Refresh();
|
ctx.Refresh();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Sharp7.Read;
|
namespace Sharp7.Monitor;
|
||||||
|
|
||||||
public static class StringHelper
|
public static class StringHelper
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ using Sharp7.Rx.Enums;
|
|||||||
using Sharp7.Rx.Interfaces;
|
using Sharp7.Rx.Interfaces;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
|
|
||||||
|
namespace Sharp7.Monitor;
|
||||||
|
|
||||||
public class VariableContainer : IDisposable
|
public class VariableContainer : IDisposable
|
||||||
{
|
{
|
||||||
private readonly IDisposable subscriptions;
|
private readonly IDisposable subscriptions;
|
||||||
|
|||||||
@@ -1,6 +1,55 @@
|
|||||||
public class VariableRecord
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Sharp7.Monitor;
|
||||||
|
|
||||||
|
public class VariableRecord
|
||||||
{
|
{
|
||||||
|
private object value = new();
|
||||||
|
private int valueUpdated;
|
||||||
public required string Address { get; init; }
|
public required string Address { get; init; }
|
||||||
public required int RowIdx { get; init; }
|
public required int RowIdx { get; init; }
|
||||||
public object Value { get; set; }
|
|
||||||
|
public object Value
|
||||||
|
{
|
||||||
|
get => value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!IsEquivalent(this.value, value))
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
valueUpdated = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsEquivalent(object oldValue, object newValue)
|
||||||
|
{
|
||||||
|
// Special treatmant for byte arrays
|
||||||
|
if (oldValue is byte[] oldArray && newValue is byte[] newArray)
|
||||||
|
{
|
||||||
|
if (oldArray.Length != newArray.Length) return false;
|
||||||
|
|
||||||
|
for (var i = 0; i < oldArray.Length; i++)
|
||||||
|
if (oldArray[i] != newArray[i]) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// all other types read from PLC have value compare semantics.
|
||||||
|
return oldValue == newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasUpdate([NotNullWhen(true)] out object? newValue)
|
||||||
|
{
|
||||||
|
if (Interlocked.Exchange(ref valueUpdated, 0) == 1)
|
||||||
|
{
|
||||||
|
newValue = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newValue = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user