mirror of
https://github.com/OpenLogics/MewtocolNet.git
synced 2025-12-06 03:01:24 +00:00
Adjusted for new mewtocol ver
This commit is contained in:
@@ -19,6 +19,9 @@ public class TestRegisterCollection : RegisterCollection {
|
||||
[Register("R16B")]
|
||||
public bool TestR16B { get; set; }
|
||||
|
||||
[Register("R902")]
|
||||
public bool Test { get; set; }
|
||||
|
||||
[BitRegister("DT1000", 0), PollLevel(3)]
|
||||
public bool? TestDT100_Word_Duplicate_SingleBit { get; set; }
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Examples.WPF.ViewModels;
|
||||
using MewtocolNet;
|
||||
using MewtocolNet.ComCassette;
|
||||
using MewtocolNet.Logging;
|
||||
using MewtocolNet.Registers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -106,25 +107,44 @@ public partial class ConnectView : UserControl {
|
||||
b.Struct<float>("DDT1016").PollLevel(2).Build();
|
||||
b.Struct<TimeSpan>("DDT1018").PollLevel(2).Build();
|
||||
|
||||
b.String("DT1024", 32).PollLevel(3).Build();
|
||||
b.String("DT1042", 5).PollLevel(4).Build();
|
||||
b.Struct<DateAndTime>("DDT1020").PollLevel(2).Build();
|
||||
b.Struct<DateAndTime>("DDT1022").PollLevel(2).Build();
|
||||
|
||||
b.String("DT1028", 32).PollLevel(3).Build();
|
||||
b.String("DT1046", 5).PollLevel(4).Build();
|
||||
|
||||
b.Struct<Word>("DT1000").AsArray(5).PollLevel(1).Build();
|
||||
|
||||
})
|
||||
.WithHeartbeatTask(async () => {
|
||||
.WithHeartbeatTask(async (plc) => {
|
||||
|
||||
await heartbeatSetter.WriteAsync((short)new Random().Next(short.MinValue, short.MaxValue));
|
||||
var randShort = (short)new Random().Next(short.MinValue, short.MaxValue);
|
||||
|
||||
if (outputContactReference.Value != null)
|
||||
await outputContactReference.WriteAsync(!outputContactReference.Value.Value);
|
||||
//write direct
|
||||
//await heartbeatSetter.WriteAsync(randShort);
|
||||
//or by anonymous
|
||||
await plc.Register.Struct<short>("DT1000").WriteAsync(randShort);
|
||||
|
||||
//write a register without a reference
|
||||
bool randBool = new Random().Next(0, 2) == 1;
|
||||
await plc.Register.Bool("Y4").WriteAsync(randBool);
|
||||
|
||||
if (testBoolReference.Value != null)
|
||||
await testBoolReference.WriteAsync(!testBoolReference.Value.Value);
|
||||
|
||||
await plc.Register.Struct<DateAndTime>("DDT1022").WriteAsync(DateAndTime.FromDateTime(DateTime.UtcNow));
|
||||
|
||||
})
|
||||
.Build();
|
||||
|
||||
//connect to it
|
||||
await App.ViewModel.Plc.ConnectAsync();
|
||||
await App.ViewModel.Plc.ConnectAsync(async () => {
|
||||
|
||||
await App.ViewModel.Plc.RestartProgramAsync();
|
||||
|
||||
});
|
||||
|
||||
await App.ViewModel.Plc.AwaitFirstDataCycleAsync();
|
||||
|
||||
if (App.ViewModel.Plc.IsConnected) {
|
||||
|
||||
|
||||
@@ -49,6 +49,21 @@
|
||||
Fill="Lime"
|
||||
IsEnabled="{Binding Plc.IsConnected}"/>
|
||||
|
||||
<Run>
|
||||
<Run.Style>
|
||||
<Style TargetType="Run">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Plc.IsRunMode, Mode=OneWay}" Value="True">
|
||||
<Setter Property="Text" Value="RUN MODE"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Plc.IsRunMode, Mode=OneWay}" Value="False">
|
||||
<Setter Property="Text" Value="NO RUN MODE"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Run.Style>
|
||||
</Run>
|
||||
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
@@ -156,10 +171,13 @@
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GridSplitter Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="3"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="Gray"
|
||||
@@ -179,6 +197,7 @@
|
||||
Margin="10"/>
|
||||
|
||||
<DataGrid Grid.Row="1"
|
||||
Grid.RowSpan="3"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding Plc.Registers, Mode=OneWay}">
|
||||
@@ -219,14 +238,14 @@
|
||||
<DataGridTemplateColumn Width="15">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{Binding MemoryAreaHash, Mode=OneWay, Converter={StaticResource hashColor}}"/>
|
||||
<Border Background="{Binding MemoryArea, Mode=OneWay, Converter={StaticResource hashColor}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<TextBlock Text="Property Bindings"
|
||||
<TextBlock Text="Memory Areas"
|
||||
Grid.Column="2"
|
||||
FontSize="18"
|
||||
Margin="10"/>
|
||||
@@ -238,6 +257,43 @@
|
||||
BorderBrush="LightBlue"
|
||||
BorderThickness="1.5">
|
||||
|
||||
<DataGrid IsReadOnly="True"
|
||||
AutoGenerateColumns="False"
|
||||
ItemsSource="{Binding Plc.MemoryAreas, Mode=OneWay}">
|
||||
|
||||
<DataGrid.Columns>
|
||||
|
||||
<DataGridTextColumn Header="Address Range" Binding="{Binding AddressRange, Mode=OneWay}"/>
|
||||
|
||||
<DataGridTemplateColumn Width="15">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{Binding Converter={StaticResource hashColor}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTextColumn Header="Words" Binding="{Binding UnderlyingWordsString, Mode=OneWay}"/>
|
||||
|
||||
</DataGrid.Columns>
|
||||
|
||||
</DataGrid>
|
||||
|
||||
</Border>
|
||||
|
||||
<TextBlock Text="Property Bindings"
|
||||
Grid.Column="2"
|
||||
Grid.Row="2"
|
||||
FontSize="18"
|
||||
Margin="10"/>
|
||||
|
||||
<Border Grid.Column="2"
|
||||
Grid.Row="3"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="LightBlue"
|
||||
BorderThickness="1.5">
|
||||
|
||||
<ScrollViewer>
|
||||
|
||||
<StackPanel>
|
||||
|
||||
92
MewtocolNet/CustomTypes/DateAndTime.cs
Normal file
92
MewtocolNet/CustomTypes/DateAndTime.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MewtocolNet {
|
||||
|
||||
/// <summary>
|
||||
/// A DateAndTime struct of 4 bytes represented as seconds from 2001-01-01 in the PLC<br/>
|
||||
/// This also works for the PLC type TIME_OF_DAY and DATE
|
||||
/// </summary>
|
||||
public struct DateAndTime : MewtocolExtTypeInit2Word {
|
||||
|
||||
internal DateTime value;
|
||||
|
||||
public DateAndTime(int year = 2001, int month = 1, int day = 1, int hour = 0, int minute = 0, int second = 0) {
|
||||
|
||||
var minDate = MinDate;
|
||||
var maxDate = MaxDate;
|
||||
|
||||
if (year < 2001 || year > 2099)
|
||||
throw new NotSupportedException("Year must be between 2001 and 2099");
|
||||
|
||||
if (month < 1 || month > 12)
|
||||
throw new NotSupportedException("Month must be between 1 and 12");
|
||||
|
||||
if (day < 1 || day > 32)
|
||||
throw new NotSupportedException("Day must be between 1 and 32");
|
||||
|
||||
if (day < 1 || day > 32)
|
||||
throw new NotSupportedException("Month must be between 1 and 32");
|
||||
|
||||
var dt = new DateTime(year, month, day, hour, minute, second);
|
||||
|
||||
if (dt < minDate)
|
||||
throw new Exception($"The minimal DATE_AND_TIME repesentation is {minDate}");
|
||||
|
||||
if (dt > maxDate)
|
||||
throw new Exception($"The maximal DATE_AND_TIME repesentation is {maxDate}");
|
||||
|
||||
value = dt;
|
||||
|
||||
}
|
||||
|
||||
public static DateAndTime FromBytes(byte[] bytes) {
|
||||
|
||||
var secondsFrom = BitConverter.ToUInt32(bytes, 0);
|
||||
|
||||
return FromDateTime(MinDate + TimeSpan.FromSeconds(secondsFrom));
|
||||
|
||||
}
|
||||
|
||||
public static DateAndTime FromDateTime(DateTime time) => new DateAndTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second);
|
||||
|
||||
//operations
|
||||
|
||||
public static TimeSpan operator -(DateAndTime a, DateAndTime b) => a.value - b.value;
|
||||
|
||||
public static DateAndTime operator +(DateAndTime a, TimeSpan b) => FromDateTime(a.value + b);
|
||||
|
||||
public static bool operator ==(DateAndTime a, DateAndTime b) => a.value == b.value;
|
||||
|
||||
public static bool operator !=(DateAndTime a, DateAndTime b) => a.value != b.value;
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
|
||||
if ((obj == null) || !this.GetType().Equals(obj.GetType())) {
|
||||
return false;
|
||||
} else {
|
||||
return (DateAndTime)obj == this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override int GetHashCode() => value.GetHashCode();
|
||||
|
||||
public byte[] ToByteArray() => BitConverter.GetBytes(SecondsSinceStart());
|
||||
|
||||
public DateTime ToDateTime() => value;
|
||||
|
||||
private uint SecondsSinceStart() => (uint)(value - MinDate).TotalSeconds;
|
||||
|
||||
private static DateTime MinDate => new DateTime(2001, 01, 01, 0, 0, 0);
|
||||
|
||||
private static DateTime MaxDate => new DateTime(2099, 12, 31, 23, 59, 59);
|
||||
|
||||
//string ops
|
||||
|
||||
public override string ToString() => $"DT#{value:yyyy-MM-dd-HH:mm:ss}";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -82,8 +82,11 @@ namespace MewtocolNet {
|
||||
|
||||
typeCode = (int)t;
|
||||
discontinued = t.IsDiscontinued();
|
||||
|
||||
#if Debug
|
||||
exrt = t.IsEXRTPLC();
|
||||
tested = t.WasTestedLive();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using MewtocolNet.Events;
|
||||
using MewtocolNet.ProgramParsing;
|
||||
using MewtocolNet.RegisterBuilding;
|
||||
using MewtocolNet.RegisterBuilding.BuilderPatterns;
|
||||
using MewtocolNet.Registers;
|
||||
using MewtocolNet.UnderlyingRegisters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -69,6 +71,11 @@ namespace MewtocolNet {
|
||||
/// </summary>
|
||||
int PollerCycleDurationMs { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Shorthand indicator if the plc is in RUN mode
|
||||
/// </summary>
|
||||
bool IsRunMode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently queued message count
|
||||
/// </summary>
|
||||
@@ -96,10 +103,12 @@ namespace MewtocolNet {
|
||||
|
||||
IEnumerable<IRegister> Registers { get; }
|
||||
|
||||
RBuildAnon Register { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Tries to establish a connection with the device asynchronously
|
||||
/// </summary>
|
||||
/// <param name="onConnected">A callback for excecuting something right after the plc connected</param>
|
||||
/// <param name="onConnected">A callback for excecuting something inside the plc connetion process</param>
|
||||
/// <returns></returns>
|
||||
Task ConnectAsync(Func<Task> onConnected = null);
|
||||
|
||||
@@ -187,6 +196,11 @@ namespace MewtocolNet {
|
||||
/// </summary>
|
||||
string Explain();
|
||||
|
||||
/// <summary>
|
||||
/// A readonly list of the underlying memory areas
|
||||
/// </summary>
|
||||
IReadOnlyList<IMemoryArea> MemoryAreas { get; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace MewtocolNet.Logging {
|
||||
/// <summary>
|
||||
/// Defines the default output logger targets
|
||||
/// </summary>
|
||||
public static LoggerTargets DefaultTargets { get; set; } = LoggerTargets.Console;
|
||||
public static LoggerTargets DefaultTargets { get; set; } = LoggerTargets.None;
|
||||
|
||||
internal static Action<DateTime, LogLevel, string> LogInvoked;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace MewtocolNet.Logging {
|
||||
|
||||
OnNewLogMessage((d, l, m) => {
|
||||
|
||||
if(isConsoleApplication && DefaultTargets.HasFlag(LoggerTargets.Console)) {
|
||||
if(isConsoleApplication || DefaultTargets.HasFlag(LoggerTargets.Console)) {
|
||||
|
||||
switch (l) {
|
||||
case LogLevel.Error:
|
||||
|
||||
@@ -379,12 +379,12 @@ namespace MewtocolNet
|
||||
/// <summary>
|
||||
/// A builder for attaching register collections
|
||||
/// </summary>
|
||||
public PostInit<T> WithRegisters(Action<RBuild> builder) {
|
||||
public PostInit<T> WithRegisters(Action<RBuildMulti> builder) {
|
||||
|
||||
try {
|
||||
|
||||
var plc = (MewtocolInterface)(object)intf;
|
||||
var regBuilder = new RBuild(plc);
|
||||
var regBuilder = new RBuildMulti(plc);
|
||||
|
||||
builder.Invoke(regBuilder);
|
||||
|
||||
@@ -406,7 +406,7 @@ namespace MewtocolNet
|
||||
/// </summary>
|
||||
/// <param name="heartBeatAsync"></param>
|
||||
/// <returns></returns>
|
||||
public EndInitSetup<T> WithHeartbeatTask(Func<Task> heartBeatAsync, bool executeInProg = false) {
|
||||
public EndInitSetup<T> WithHeartbeatTask(Func<IPlc,Task> heartBeatAsync, bool executeInProg = false) {
|
||||
try {
|
||||
|
||||
var plc = (MewtocolInterface)(object)this.intf;
|
||||
@@ -426,6 +426,14 @@ namespace MewtocolNet
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repeats the passed method each time the hearbeat is triggered,
|
||||
/// use
|
||||
/// </summary>
|
||||
/// <param name="heartBeatAsync"></param>
|
||||
/// <returns></returns>
|
||||
public EndInitSetup<T> WithHeartbeatTask(Func<Task> heartBeatAsync, bool executeInProg = false) => WithHeartbeatTask(heartBeatAsync, executeInProg);
|
||||
|
||||
/// <summary>
|
||||
/// Builds and returns the final plc interface
|
||||
/// </summary>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using MewtocolNet.Events;
|
||||
using MewtocolNet.Helpers;
|
||||
using MewtocolNet.Logging;
|
||||
using MewtocolNet.RegisterBuilding.BuilderPatterns;
|
||||
using MewtocolNet.Registers;
|
||||
using MewtocolNet.UnderlyingRegisters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@@ -156,6 +158,9 @@ namespace MewtocolNet {
|
||||
/// <inheritdoc/>
|
||||
public int BytesPerSecondDownstream => bytesPerSecondDownstream;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsRunMode => PlcInfo.IsRunMode;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public MewtocolVersion MewtocolVersion {
|
||||
get => mewtocolVersion;
|
||||
@@ -168,6 +173,9 @@ namespace MewtocolNet {
|
||||
/// <inheritdoc/>
|
||||
public string ConnectionInfo => GetConnectionInfo();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public RBuildAnon Register => new RBuildAnon(this);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public read/write Properties / Fields
|
||||
@@ -191,6 +199,21 @@ namespace MewtocolNet {
|
||||
Disconnected += MewtocolInterface_Disconnected;
|
||||
RegisterChanged += OnRegisterChanged;
|
||||
|
||||
PropertyChanged += (s, e) => {
|
||||
if (e.PropertyName == nameof(PlcInfo)) {
|
||||
PlcInfo.PropertyChanged += (s1, e1) => {
|
||||
if (e1.PropertyName == nameof(PlcInfo.IsRunMode))
|
||||
OnPropChange(nameof(IsRunMode));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
memoryManager.MemoryLayoutChanged += () => {
|
||||
|
||||
OnPropChange(nameof(MemoryAreas));
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
internal MewtocolInterface Build () {
|
||||
@@ -269,10 +292,19 @@ namespace MewtocolNet {
|
||||
|
||||
if (callBack != null) {
|
||||
|
||||
await Task.Run(callBack);
|
||||
await callBack();
|
||||
|
||||
Logger.Log($">> OnConnected run complete <<", LogLevel.Verbose, this);
|
||||
|
||||
//run all register collection on online tasks
|
||||
foreach (var col in registerCollections) {
|
||||
|
||||
await col.OnInterfaceLinkedAndOnline(this);
|
||||
|
||||
}
|
||||
|
||||
Logger.Log($">> OnConnected register collections run complete <<", LogLevel.Verbose, this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -281,7 +313,14 @@ namespace MewtocolNet {
|
||||
protected virtual Task ReconnectAsync(int conTimeout) => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task AwaitFirstDataCycleAsync() => await firstPollTask;
|
||||
public async Task AwaitFirstDataCycleAsync() {
|
||||
|
||||
if(firstPollTask != null && !firstPollTask.IsCompleted)
|
||||
await firstPollTask;
|
||||
|
||||
await Task.CompletedTask;
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task DisconnectAsync() {
|
||||
@@ -842,22 +881,8 @@ namespace MewtocolNet {
|
||||
isReconnectingStage = false;
|
||||
isConnectingStage = false;
|
||||
|
||||
if (!usePoller) {
|
||||
firstPollTask.RunSynchronously();
|
||||
}
|
||||
|
||||
Connected?.Invoke(this, new PlcConnectionArgs());
|
||||
|
||||
PolledCycle += OnPollCycleDone;
|
||||
void OnPollCycleDone() {
|
||||
|
||||
if(firstPollTask != null && !firstPollTask.IsCompleted)
|
||||
firstPollTask.RunSynchronously();
|
||||
|
||||
PolledCycle -= OnPollCycleDone;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private protected void OnReconnected () {
|
||||
@@ -982,8 +1007,12 @@ namespace MewtocolNet {
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Explain() => memoryManager.ExplainLayout();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReadOnlyList<IMemoryArea> MemoryAreas => memoryManager.GetAllMemoryAreas();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,10 +18,11 @@ namespace MewtocolNet {
|
||||
public abstract partial class MewtocolInterface {
|
||||
|
||||
private bool heartbeatNeedsRun = false;
|
||||
private bool heartbeatTimerRunning = false;
|
||||
|
||||
internal Task heartbeatTask = Task.CompletedTask;
|
||||
|
||||
internal Func<Task> heartbeatCallbackTask;
|
||||
internal Func<IPlc, Task> heartbeatCallbackTask;
|
||||
internal bool execHeartBeatCallbackTaskInProg = false;
|
||||
|
||||
internal Task pollCycleTask;
|
||||
@@ -73,6 +74,7 @@ namespace MewtocolNet {
|
||||
|
||||
heartBeatTimer.Elapsed -= PollTimerTick;
|
||||
heartBeatTimer.Dispose();
|
||||
heartbeatTimerRunning = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -82,12 +84,15 @@ namespace MewtocolNet {
|
||||
|
||||
if (!IsConnected) return;
|
||||
|
||||
if(!heartbeatTimerRunning) {
|
||||
heartBeatTimer = new System.Timers.Timer();
|
||||
heartBeatTimer.Interval = 3000;
|
||||
heartBeatTimer.Elapsed += PollTimerTick;
|
||||
heartBeatTimer.Start();
|
||||
heartbeatTimerRunning = true;
|
||||
}
|
||||
|
||||
if (!usePoller) return;
|
||||
if (!usePoller || PollerActive) return;
|
||||
|
||||
bool hasCyclic = memoryManager.HasCyclicPollableRegisters();
|
||||
bool hasFirstCycle = memoryManager.HasSingleCyclePollableRegisters();
|
||||
@@ -154,7 +159,7 @@ namespace MewtocolNet {
|
||||
}
|
||||
|
||||
if(heartbeatCallbackTask != null && (plcInfo.IsRunMode || execHeartBeatCallbackTaskInProg))
|
||||
await heartbeatCallbackTask();
|
||||
await heartbeatCallbackTask(this);
|
||||
|
||||
Logger.LogVerbose("End heartbeat", this);
|
||||
|
||||
@@ -235,6 +240,12 @@ namespace MewtocolNet {
|
||||
|
||||
sw.Stop();
|
||||
|
||||
if (firstPollTask != null && !firstPollTask.IsCompleted) {
|
||||
firstPollTask.RunSynchronously();
|
||||
firstPollTask = null;
|
||||
Logger.Log("poll cycle first done");
|
||||
}
|
||||
|
||||
pollerFirstCycleCompleted = true;
|
||||
PollerCycleDurationMs = (int)sw.ElapsedMilliseconds;
|
||||
|
||||
@@ -296,11 +307,6 @@ namespace MewtocolNet {
|
||||
collection.OnInterfaceLinked(this);
|
||||
}
|
||||
|
||||
Connected += (s,e) => {
|
||||
if (collection != null)
|
||||
collection.OnInterfaceLinkedAndOnline(this);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
AddRegisters(regBuild.assembler.assembled.ToArray());
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<PropertyGroup>
|
||||
|
||||
<IsPublishable>false</IsPublishable>
|
||||
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<PackageId>Mewtocol.NET</PackageId>
|
||||
<Version>0.0.0</Version>
|
||||
@@ -17,7 +16,6 @@
|
||||
<PackageTags>plc;panasonic;mewtocol;automation;</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<UserSecretsId>2ccdcc9b-94a3-4e76-8827-453ab889ea33</UserSecretsId>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
@@ -25,6 +23,11 @@
|
||||
<OutputPath>..\Builds\MewtocolNet</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DocumentationFile>..\Builds\MewtocolNet\Debug\MewtocolNet.xml</DocumentationFile>
|
||||
<OutputPath>..\Builds\MewtocolNet\Debug</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>MewtocolTests</_Parameter1>
|
||||
|
||||
@@ -15,35 +15,35 @@ namespace MewtocolNet {
|
||||
/// <summary>
|
||||
/// Is in RUN mode, otherwise its PROG Mode
|
||||
/// </summary>
|
||||
RunMode = 1,
|
||||
RunMode = 1 << 0,
|
||||
/// <summary>
|
||||
/// Is in test mode, otherwise ok
|
||||
/// </summary>
|
||||
TestMode = 2,
|
||||
TestMode = 1 << 1,
|
||||
/// <summary>
|
||||
/// Is BRK/1 step executed
|
||||
/// </summary>
|
||||
BreakPointPerOneStep = 4,
|
||||
BreakPointPerOneStep = 1 << 2,
|
||||
/// <summary>
|
||||
/// Is BRK command enabled
|
||||
/// </summary>
|
||||
BreakEnabled = 16,
|
||||
BreakEnabled = 1 << 3,
|
||||
/// <summary>
|
||||
/// Is outputting to external device
|
||||
/// </summary>
|
||||
ExternalOutput = 32,
|
||||
ExternalOutput = 1 << 4,
|
||||
/// <summary>
|
||||
/// Is 1 step exec enabled
|
||||
/// </summary>
|
||||
OneStepExecEnabled = 64,
|
||||
OneStepExecEnabled = 1 << 5,
|
||||
/// <summary>
|
||||
/// Is a message displayed?
|
||||
/// </summary>
|
||||
MessageInstructionDisplayed = 128,
|
||||
MessageInstructionDisplayed = 1 << 6,
|
||||
/// <summary>
|
||||
/// Is in remote mode
|
||||
/// </summary>
|
||||
RemoteMode = 255,
|
||||
RemoteMode = 1 << 7,
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using MewtocolNet.Registers;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MewtocolNet.RegisterAttributes {
|
||||
|
||||
@@ -57,7 +58,7 @@ namespace MewtocolNet.RegisterAttributes {
|
||||
/// and the plc connection is established
|
||||
/// </summary>
|
||||
/// <param name="plc">The parent interface</param>
|
||||
public virtual void OnInterfaceLinkedAndOnline(MewtocolInterface plc) { }
|
||||
public virtual Task OnInterfaceLinkedAndOnline(MewtocolInterface plc) => Task.CompletedTask;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace MewtocolNet.RegisterBuilding {
|
||||
private static ParseResult TryBuildBoolean(string plcAddrName) {
|
||||
|
||||
//regex to find special register values
|
||||
var patternBool = new Regex(@"(?<prefix>X|Y|R)(?<area>[0-9]{0,3})(?<special>(?:[0-9]|[A-F]){1})?");
|
||||
var patternBool = new Regex(@"(?<prefix>X|Y|R)(?<area>[0-9]{0,3})(?<special>(?:[0-9]|[A-F]){1})");
|
||||
|
||||
var match = patternBool.Match(plcAddrName);
|
||||
|
||||
|
||||
@@ -34,10 +34,13 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
|
||||
|
||||
//bool constructor
|
||||
|
||||
public StructStp<bool> Bool(string fpAddr, string name = null) {
|
||||
internal StructStp<bool> Bool(string fpAddr, string name = null) {
|
||||
|
||||
var data = AddressTools.ParseAddress(fpAddr, name);
|
||||
|
||||
if (!data.regType.IsBoolean())
|
||||
throw new NotSupportedException($"The address '{fpAddr}' was no boolean FP address");
|
||||
|
||||
data.dotnetVarType = typeof(bool);
|
||||
|
||||
return new StructStp<bool>(data) {
|
||||
@@ -48,10 +51,13 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
|
||||
|
||||
//struct constructor
|
||||
|
||||
public StructStp<T> Struct<T>(string fpAddr, string name = null) where T : struct {
|
||||
internal StructStp<T> Struct<T>(string fpAddr, string name = null) where T : struct {
|
||||
|
||||
var data = AddressTools.ParseAddress(fpAddr, name);
|
||||
|
||||
if (data.regType.IsBoolean())
|
||||
throw new NotSupportedException($"The address '{fpAddr}' was no DT address");
|
||||
|
||||
data.dotnetVarType = typeof(T);
|
||||
|
||||
return new StructStp<T>(data) {
|
||||
@@ -62,10 +68,13 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
|
||||
|
||||
//string constructor
|
||||
|
||||
public StringStp<string> String(string fpAddr, int sizeHint, string name = null) {
|
||||
internal StringStp<string> String(string fpAddr, int sizeHint, string name = null) {
|
||||
|
||||
var data = AddressTools.ParseAddress(fpAddr, name);
|
||||
|
||||
if (data.regType.IsBoolean())
|
||||
throw new NotSupportedException($"The address '{fpAddr}' was no string address");
|
||||
|
||||
data.dotnetVarType = typeof(string);
|
||||
data.byteSizeHint = (uint)sizeHint;
|
||||
|
||||
@@ -82,6 +91,8 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
|
||||
//structs can lead to arrays
|
||||
public class StructStp<T> : ArrayStp<T> where T : struct {
|
||||
|
||||
internal StructStp() {}
|
||||
|
||||
internal StructStp(StepData data) {
|
||||
|
||||
this.Data = data;
|
||||
@@ -89,30 +100,13 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
|
||||
|
||||
}
|
||||
|
||||
public void Build() => builder.Assemble(this);
|
||||
|
||||
public void Build(out IRegister<T> reference) => reference = (IRegister<T>)builder.Assemble(this);
|
||||
|
||||
public StructStpOut<T> PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new StructStpOut<T>().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class StructStpOut<T> : SBaseRB where T : struct {
|
||||
|
||||
public void Build() => builder.Assemble(this);
|
||||
|
||||
public void Build(out IRegister<T> reference) => reference = (IRegister<T>)builder.Assemble(this);
|
||||
|
||||
}
|
||||
|
||||
//strings can lead to arrays
|
||||
public class StringStp<T> : ArrayStp<T> where T : class {
|
||||
|
||||
internal StringStp() { }
|
||||
|
||||
internal StringStp(StepData data) {
|
||||
|
||||
this.Data = data;
|
||||
@@ -120,25 +114,6 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
|
||||
|
||||
}
|
||||
|
||||
public void Build() => builder.Assemble(this);
|
||||
|
||||
public void Build(out IStringRegister reference) => reference = (IStringRegister)builder.Assemble(this);
|
||||
|
||||
public StringOutStp PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new StringOutStp().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class StringOutStp : SBaseRB {
|
||||
|
||||
public void Build() => builder.Assemble(this);
|
||||
|
||||
public void Build(out IStringRegister reference) => reference = (IStringRegister)builder.Assemble(this);
|
||||
|
||||
}
|
||||
|
||||
//arrays
|
||||
@@ -199,66 +174,21 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
|
||||
|
||||
//1D array
|
||||
|
||||
public class TypedArr1D<T> : TypedArr1DOut<T> {
|
||||
public class TypedArr1D<T> : TypedArr1DOut<T> { }
|
||||
|
||||
public TypedArr1DOut<T> PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new TypedArr1DOut<T>().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TypedArr1DOut<T> : SBaseRB {
|
||||
|
||||
public IArrayRegister<T> Build() => (IArrayRegister<T>)builder.Assemble(this);
|
||||
|
||||
public void Build(out IArrayRegister<T> reference) => reference = (IArrayRegister<T>)builder.Assemble(this);
|
||||
|
||||
}
|
||||
public class TypedArr1DOut<T> : SBaseRB { }
|
||||
|
||||
//2D array
|
||||
|
||||
public class TypedArr2D<T> : TypedArr2DOut<T> {
|
||||
public class TypedArr2D<T> : TypedArr2DOut<T> { }
|
||||
|
||||
public TypedArr2DOut<T> PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new TypedArr2DOut<T>().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TypedArr2DOut<T> : SBaseRB {
|
||||
|
||||
public IArrayRegister2D<T> Build() => (IArrayRegister2D<T>)builder.Assemble(this);
|
||||
|
||||
public void Build(out IArrayRegister2D<T> reference) => reference = (IArrayRegister2D<T>)builder.Assemble(this);
|
||||
|
||||
}
|
||||
public class TypedArr2DOut<T> : SBaseRB { }
|
||||
|
||||
//3D array
|
||||
|
||||
public class TypedArr3D<T> : SBaseRB {
|
||||
public class TypedArr3D<T> : SBaseRB { }
|
||||
|
||||
public TypedArr3DOut<T> PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new TypedArr3DOut<T>().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TypedArr3DOut<T> : SBaseRB {
|
||||
|
||||
public IArrayRegister3D<T> Build() => (IArrayRegister3D<T>)builder.Assemble(this);
|
||||
|
||||
public void Build(out IArrayRegister3D<T> reference) => reference = (IArrayRegister3D<T>)builder.Assemble(this);
|
||||
|
||||
}
|
||||
public class TypedArr3DOut<T> : SBaseRB { }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
130
MewtocolNet/RegisterBuilding/BuilderPatterns/RBuildAnon.cs
Normal file
130
MewtocolNet/RegisterBuilding/BuilderPatterns/RBuildAnon.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using MewtocolNet.Registers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
|
||||
|
||||
/// <summary>
|
||||
/// An anonymous register build interface
|
||||
/// </summary>
|
||||
public class RBuildAnon : RBuild {
|
||||
|
||||
internal RBuildAnon(MewtocolInterface plc) : base(plc) { }
|
||||
|
||||
public new MultStructStp<bool> Bool(string fpAddr) => new MultStructStp<bool>().Map(base.Bool(fpAddr));
|
||||
|
||||
public new MultStructStp<T> Struct<T>(string fpAddr) where T : struct => new MultStructStp<T>().Map(base.Struct<T>(fpAddr));
|
||||
|
||||
public new MultStringStp<string> String(string fpAddr, int sizeHint) => new MultStringStp<string>().Map(base.String(fpAddr, sizeHint));
|
||||
|
||||
public class MultStructStp<T> : MultArrayStp<T> where T : struct {
|
||||
|
||||
public async Task WriteAsync(T value) {
|
||||
|
||||
var reg = (IRegister<T>)builder.Assemble(this);
|
||||
await reg.WriteAsync(value);
|
||||
|
||||
}
|
||||
|
||||
public async Task<T> ReadAsync() {
|
||||
|
||||
var reg = (IRegister<T>)builder.Assemble(this);
|
||||
return await reg.ReadAsync();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class MultStringStp<T> : MultArrayStp<T> where T : class {
|
||||
|
||||
public async Task WriteAsync(string value) {
|
||||
|
||||
var reg = (IStringRegister)builder.Assemble(this);
|
||||
await reg.WriteAsync(value);
|
||||
|
||||
}
|
||||
|
||||
public async Task<string> ReadAsync() {
|
||||
|
||||
var reg = (IStringRegister)builder.Assemble(this);
|
||||
return await reg.ReadAsync();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class MultArrayStp<T> : ArrayStp<T> {
|
||||
|
||||
public new MultTypedArr1D<T> AsArray(int i) => new MultTypedArr1D<T>().Map(base.AsArray(i));
|
||||
|
||||
public new MultTypedArr2D<T> AsArray(int i1, int i2) => new MultTypedArr2D<T>().Map(base.AsArray(i1, i2));
|
||||
|
||||
public new MultTypedArr3D<T> AsArray(int i1, int i2, int i3) => new MultTypedArr3D<T>().Map(base.AsArray(i1, i2, i3));
|
||||
|
||||
}
|
||||
|
||||
//1D array
|
||||
|
||||
public class MultTypedArr1D<T> : TypedArr1D<T> {
|
||||
|
||||
public async Task WriteAsync(T[] value) {
|
||||
|
||||
var reg = (IArrayRegister<T>)builder.Assemble(this);
|
||||
await reg.WriteAsync(value);
|
||||
|
||||
}
|
||||
|
||||
public async Task<T[]> ReadAsync() {
|
||||
|
||||
var reg = (IArrayRegister<T>)builder.Assemble(this);
|
||||
return await reg.ReadAsync();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//2D array
|
||||
|
||||
public class MultTypedArr2D<T> : TypedArr2D<T> {
|
||||
|
||||
public async Task WriteAsync(T[,] value) {
|
||||
|
||||
var reg = (IArrayRegister2D<T>)builder.Assemble(this);
|
||||
await reg.WriteAsync(value);
|
||||
|
||||
}
|
||||
|
||||
public async Task<T[,]> ReadAsync() {
|
||||
|
||||
var reg = (IArrayRegister2D<T>)builder.Assemble(this);
|
||||
return await reg.ReadAsync();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//3D array
|
||||
|
||||
public class MultTypedArr3D<T> : TypedArr3D<T> {
|
||||
|
||||
public async Task WriteAsync(T[,,] value) {
|
||||
|
||||
var reg = (IArrayRegister3D<T>)builder.Assemble(this);
|
||||
await reg.WriteAsync(value);
|
||||
|
||||
}
|
||||
|
||||
public async Task<T[,,]> ReadAsync() {
|
||||
|
||||
var reg = (IArrayRegister3D<T>)builder.Assemble(this);
|
||||
return await reg.ReadAsync();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
142
MewtocolNet/RegisterBuilding/BuilderPatterns/RBuildMulti.cs
Normal file
142
MewtocolNet/RegisterBuilding/BuilderPatterns/RBuildMulti.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using MewtocolNet.Registers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
|
||||
|
||||
public class RBuildMulti : RBuild {
|
||||
|
||||
internal RBuildMulti(MewtocolInterface plc) : base(plc) {}
|
||||
|
||||
//bool constructor
|
||||
public new MultStructStp<bool> Bool(string fpAddr, string name = null) => new MultStructStp<bool>().Map(base.Bool(fpAddr, name));
|
||||
|
||||
//struct constructor
|
||||
public new MultStructStp<T> Struct<T>(string fpAddr, string name = null) where T : struct => new MultStructStp<T>().Map(base.Struct<T>(fpAddr, name));
|
||||
|
||||
//string constructor
|
||||
public new MultStringStp<string> String(string fpAddr, int sizeHint, string name = null) => new MultStringStp<string>().Map(base.String(fpAddr, sizeHint, name));
|
||||
|
||||
public class MultStructStp<T> : MultArrayStp<T> where T : struct {
|
||||
|
||||
public void Build() => builder.Assemble(this);
|
||||
|
||||
public void Build(out IRegister<T> reference) => reference = (IRegister<T>)builder.Assemble(this);
|
||||
|
||||
public StructStpOut<T> PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new StructStpOut<T>().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class StructStpOut<T> : SBaseRB where T : struct {
|
||||
|
||||
public void Build() => builder.Assemble(this);
|
||||
|
||||
public void Build(out IRegister<T> reference) => reference = (IRegister<T>)builder.Assemble(this);
|
||||
|
||||
}
|
||||
|
||||
public class MultStringStp<T> : MultArrayStp<T> where T : class {
|
||||
|
||||
public void Build() => builder.Assemble(this);
|
||||
|
||||
public void Build(out IStringRegister reference) => reference = (IStringRegister)builder.Assemble(this);
|
||||
|
||||
public StringOutStp PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new StringOutStp().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class StringOutStp : SBaseRB {
|
||||
|
||||
public void Build() => builder.Assemble(this);
|
||||
|
||||
public void Build(out IStringRegister reference) => reference = (IStringRegister)builder.Assemble(this);
|
||||
|
||||
}
|
||||
|
||||
public class MultArrayStp<T> : ArrayStp<T> {
|
||||
|
||||
public new MultTypedArr1D<T> AsArray(int i) => new MultTypedArr1D<T>().Map(base.AsArray(i));
|
||||
|
||||
public new MultTypedArr2D<T> AsArray(int i1, int i2) => new MultTypedArr2D<T>().Map(base.AsArray(i1, i2));
|
||||
|
||||
public new MultTypedArr3D<T> AsArray(int i1, int i2, int i3) => new MultTypedArr3D<T>().Map(base.AsArray(i1, i2, i3));
|
||||
|
||||
}
|
||||
|
||||
//1D array
|
||||
|
||||
public class MultTypedArr1D<T> : TypedArr1D<T> {
|
||||
|
||||
public MultTypedArr1DOut<T> PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new MultTypedArr1DOut<T>().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class MultTypedArr1DOut<T> : TypedArr1DOut<T> {
|
||||
|
||||
public IArrayRegister<T> Build() => (IArrayRegister<T>)builder.Assemble(this);
|
||||
|
||||
public void Build(out IArrayRegister<T> reference) => reference = (IArrayRegister<T>)builder.Assemble(this);
|
||||
|
||||
}
|
||||
|
||||
//2D array
|
||||
|
||||
public class MultTypedArr2D<T> : TypedArr2D<T> {
|
||||
|
||||
public MultTypedArr2DOut<T> PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new MultTypedArr2DOut<T>().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class MultTypedArr2DOut<T> : TypedArr2DOut<T> {
|
||||
|
||||
public IArrayRegister2D<T> Build() => (IArrayRegister2D<T>)builder.Assemble(this);
|
||||
|
||||
public void Build(out IArrayRegister2D<T> reference) => reference = (IArrayRegister2D<T>)builder.Assemble(this);
|
||||
|
||||
}
|
||||
|
||||
//3D array
|
||||
|
||||
public class MultTypedArr3D<T> : TypedArr3D<T> {
|
||||
|
||||
public MultTypedArr3DOut<T> PollLevel(int level) {
|
||||
|
||||
Data.pollLevel = level;
|
||||
return new MultTypedArr3DOut<T>().Map(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class MultTypedArr3DOut<T> : TypedArr3DOut<T> {
|
||||
|
||||
public IArrayRegister3D<T> Build() => (IArrayRegister3D<T>)builder.Assemble(this);
|
||||
|
||||
public void Build(out IArrayRegister3D<T> reference) => reference = (IArrayRegister3D<T>)builder.Assemble(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MewtocolNet.Events;
|
||||
using MewtocolNet.UnderlyingRegisters;
|
||||
|
||||
namespace MewtocolNet.Registers {
|
||||
|
||||
@@ -20,6 +21,11 @@ namespace MewtocolNet.Registers {
|
||||
/// </summary>
|
||||
bool IsAutoGenerated { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The readonly memory area of the register
|
||||
/// </summary>
|
||||
IMemoryArea MemoryArea { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of the underlying register
|
||||
/// </summary>
|
||||
|
||||
@@ -66,6 +66,9 @@ namespace MewtocolNet.Registers {
|
||||
/// <inheritdoc/>
|
||||
public RegisterPrefix RegisterType { get; internal set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IMemoryArea MemoryArea => underlyingMemory;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => name;
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace MewtocolNet.Registers {
|
||||
//if string correct the sizing of the byte hint was wrong
|
||||
var reservedSize = BitConverter.ToInt16(bytes, 0);
|
||||
|
||||
if (reservedStringLength != reservedSize && attachedInterface.PlcInfo.IsRunMode)
|
||||
if (reservedStringLength != reservedSize && attachedInterface.PlcInfo.IsRunMode && !attachedInterface.isConnectingStage)
|
||||
throw new NotSupportedException(
|
||||
$"The STRING register at {GetMewName()} is not correctly sized, " +
|
||||
$"the size should be STRING[{reservedSize}] instead of STRING[{reservedStringLength}]"
|
||||
|
||||
@@ -127,6 +127,15 @@ namespace MewtocolNet.TypeConversion {
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
//default Datetime DDT conversion
|
||||
new PlcTypeConversion<DateAndTime>(RegisterPrefix.DDT) {
|
||||
HoldingRegisterType = typeof(StructRegister<DateAndTime>),
|
||||
PlcVarType = PlcVarType.DATE_AND_TIME,
|
||||
FromRaw = (reg, bytes) => DateAndTime.FromBytes(bytes),
|
||||
ToRaw = (reg, value) => value.ToByteArray(),
|
||||
},
|
||||
|
||||
//default string DT Range conversion Example bytes: (04 00 03 00 XX XX XX)
|
||||
//first 4 bytes are reserved size (2 bytes) and used size (2 bytes)
|
||||
//the remaining bytes are the ascii bytes for the string
|
||||
|
||||
@@ -2,17 +2,21 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MewtocolNet.UnderlyingRegisters {
|
||||
|
||||
public class AreaBase {
|
||||
internal class AreaBase : IMemoryArea {
|
||||
|
||||
private MewtocolInterface mewInterface;
|
||||
private int pollLevel;
|
||||
|
||||
internal RegisterPrefix registerType;
|
||||
|
||||
internal ulong addressStart;
|
||||
internal ulong addressEnd;
|
||||
|
||||
@@ -23,12 +27,25 @@ namespace MewtocolNet.UnderlyingRegisters {
|
||||
/// </summary>
|
||||
internal List<LinkedRegisterGroup> managedRegisters = new List<LinkedRegisterGroup>();
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public ulong AddressStart => addressStart;
|
||||
public ulong AddressEnd => addressEnd;
|
||||
|
||||
internal AreaBase(MewtocolInterface mewIf) {
|
||||
//interface
|
||||
|
||||
public string AddressRange => GetAddressRangeString();
|
||||
|
||||
public IReadOnlyList<Word> UnderlyingWords => GetUnderlyingWords();
|
||||
|
||||
public string UnderlyingWordsString => string.Join(" ", GetUnderlyingWords());
|
||||
|
||||
public int PollLevel => pollLevel;
|
||||
|
||||
internal AreaBase(MewtocolInterface mewIf, int pollLvl) {
|
||||
|
||||
mewInterface = mewIf;
|
||||
pollLevel = pollLvl;
|
||||
|
||||
}
|
||||
|
||||
@@ -49,6 +66,9 @@ namespace MewtocolNet.UnderlyingRegisters {
|
||||
addressStart = addFrom;
|
||||
addressEnd = addTo;
|
||||
|
||||
OnPropChange(nameof(AddressRange));
|
||||
OnPropChange(nameof(UnderlyingWords));
|
||||
|
||||
}
|
||||
|
||||
public void UpdateAreaRegisterValues() {
|
||||
@@ -61,6 +81,9 @@ namespace MewtocolNet.UnderlyingRegisters {
|
||||
var bytes = this.GetUnderlyingBytes(regStart, addLen);
|
||||
register.SetValueFromBytes(bytes);
|
||||
|
||||
OnPropChange(nameof(UnderlyingWords));
|
||||
OnPropChange(nameof(UnderlyingWordsString));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -112,6 +135,8 @@ namespace MewtocolNet.UnderlyingRegisters {
|
||||
|
||||
var bitArr = new BitArray(underlyingBefore);
|
||||
|
||||
bitArr[bitIndex] = value;
|
||||
|
||||
bitArr.CopyTo(underlyingBefore, 0);
|
||||
|
||||
SetUnderlyingBytes(underlyingBefore, reg.MemoryAddress);
|
||||
@@ -131,22 +156,45 @@ namespace MewtocolNet.UnderlyingRegisters {
|
||||
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
private List<Word> GetUnderlyingWords () {
|
||||
|
||||
var bytes = GetUnderlyingBytes((uint)AddressStart, (int)(addressEnd - AddressStart) + 1);
|
||||
var words = new List<Word>();
|
||||
|
||||
for (int i = 0; i < bytes.Length / 2; i += 2) {
|
||||
|
||||
words.Add(new Word(new byte[] { bytes[i], bytes[i + 1] }));
|
||||
|
||||
}
|
||||
|
||||
return words;
|
||||
|
||||
}
|
||||
|
||||
private string GetAddressRangeString() {
|
||||
|
||||
switch (registerType) {
|
||||
case RegisterPrefix.X:
|
||||
case RegisterPrefix.Y:
|
||||
case RegisterPrefix.R:
|
||||
return $"W{registerType}{AddressStart}-{AddressEnd} ({managedRegisters.Count} Registers)";
|
||||
return $"W{registerType}{AddressStart}-{AddressEnd}";
|
||||
case RegisterPrefix.DT:
|
||||
case RegisterPrefix.DDT:
|
||||
return $"DT{AddressStart}-{AddressEnd} ({managedRegisters.Count} Registers)";
|
||||
return $"DT{AddressStart}-{AddressEnd}";
|
||||
}
|
||||
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
public override string ToString() => $"{GetAddressRangeString()} ({managedRegisters.Count} Registers)";
|
||||
|
||||
private protected void OnPropChange([CallerMemberName] string propertyName = null) {
|
||||
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
using MewtocolNet.Registers;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace MewtocolNet.UnderlyingRegisters {
|
||||
|
||||
internal interface IMemoryArea {
|
||||
public interface IMemoryArea : INotifyPropertyChanged {
|
||||
|
||||
string GetName();
|
||||
string AddressRange { get; }
|
||||
|
||||
byte[] GetUnderlyingBytes(Register reg);
|
||||
IReadOnlyList<Word> UnderlyingWords { get; }
|
||||
|
||||
void SetUnderlyingBytes(Register reg, byte[] bytes);
|
||||
string UnderlyingWordsString { get; }
|
||||
|
||||
void UpdateAreaRegisterValues();
|
||||
int PollLevel { get; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ namespace MewtocolNet.UnderlyingRegisters {
|
||||
//create a new area
|
||||
if (targetArea == null) {
|
||||
|
||||
targetArea = new AreaBase(mewInterface) {
|
||||
targetArea = new AreaBase(mewInterface, pollLevelFound.level) {
|
||||
addressStart = regInsAddStart,
|
||||
addressEnd = regInsAddEnd,
|
||||
registerType = insertReg.RegisterType,
|
||||
@@ -455,6 +455,20 @@ namespace MewtocolNet.UnderlyingRegisters {
|
||||
|
||||
}
|
||||
|
||||
internal IReadOnlyList<IMemoryArea> GetAllMemoryAreas() {
|
||||
|
||||
List<IMemoryArea> areas = new List<IMemoryArea>();
|
||||
|
||||
foreach (var lvl in pollLevels) {
|
||||
|
||||
areas.AddRange(lvl.GetAllAreas());
|
||||
|
||||
}
|
||||
|
||||
return areas;
|
||||
|
||||
}
|
||||
|
||||
internal bool HasSingleCyclePollableRegisters() {
|
||||
|
||||
bool hasCyclicPollableLevels = pollLevels.Any(x => x.level != MewtocolNet.PollLevel.FirstIteration);
|
||||
|
||||
9
nuget.config
Normal file
9
nuget.config
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="LocalMewtocolNetNuget" value="Builds/MewtocolNet/Debug" />
|
||||
</packageSources>
|
||||
<activePackageSource>
|
||||
<add key="All" value="(Aggregate source)" />
|
||||
</activePackageSource>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user