Adjusted for new mewtocol ver

This commit is contained in:
Felix Weiß
2023-08-13 23:31:34 +02:00
parent 111eacb785
commit 4fb9910d54
26 changed files with 696 additions and 168 deletions

View File

@@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MewtocolNet\MewtocolNet.csproj" /> <ProjectReference Include="..\MewtocolNet\MewtocolNet.csproj"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -19,6 +19,9 @@ public class TestRegisterCollection : RegisterCollection {
[Register("R16B")] [Register("R16B")]
public bool TestR16B { get; set; } public bool TestR16B { get; set; }
[Register("R902")]
public bool Test { get; set; }
[BitRegister("DT1000", 0), PollLevel(3)] [BitRegister("DT1000", 0), PollLevel(3)]
public bool? TestDT100_Word_Duplicate_SingleBit { get; set; } public bool? TestDT100_Word_Duplicate_SingleBit { get; set; }

View File

@@ -2,6 +2,7 @@
using Examples.WPF.ViewModels; using Examples.WPF.ViewModels;
using MewtocolNet; using MewtocolNet;
using MewtocolNet.ComCassette; using MewtocolNet.ComCassette;
using MewtocolNet.Logging;
using MewtocolNet.Registers; using MewtocolNet.Registers;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -106,25 +107,44 @@ public partial class ConnectView : UserControl {
b.Struct<float>("DDT1016").PollLevel(2).Build(); b.Struct<float>("DDT1016").PollLevel(2).Build();
b.Struct<TimeSpan>("DDT1018").PollLevel(2).Build(); b.Struct<TimeSpan>("DDT1018").PollLevel(2).Build();
b.String("DT1024", 32).PollLevel(3).Build(); b.Struct<DateAndTime>("DDT1020").PollLevel(2).Build();
b.String("DT1042", 5).PollLevel(4).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) //write direct
await outputContactReference.WriteAsync(!outputContactReference.Value.Value); //await heartbeatSetter.WriteAsync(randShort);
//or by anonymous
await plc.Register.Struct<short>("DT1000").WriteAsync(randShort);
if(testBoolReference.Value != null) //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 testBoolReference.WriteAsync(!testBoolReference.Value.Value);
await plc.Register.Struct<DateAndTime>("DDT1022").WriteAsync(DateAndTime.FromDateTime(DateTime.UtcNow));
}) })
.Build(); .Build();
//connect to it //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) { if (App.ViewModel.Plc.IsConnected) {

View File

@@ -49,6 +49,21 @@
Fill="Lime" Fill="Lime"
IsEnabled="{Binding Plc.IsConnected}"/> 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> <TextBlock.Style>
<Style TargetType="TextBlock"> <Style TargetType="TextBlock">
<Style.Triggers> <Style.Triggers>
@@ -156,10 +171,13 @@
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="auto"/> <RowDefinition Height="auto"/>
<RowDefinition/> <RowDefinition/>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<GridSplitter Grid.Column="1" <GridSplitter Grid.Column="1"
Grid.Row="1" Grid.Row="1"
Grid.RowSpan="3"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Background="Gray" Background="Gray"
@@ -179,6 +197,7 @@
Margin="10"/> Margin="10"/>
<DataGrid Grid.Row="1" <DataGrid Grid.Row="1"
Grid.RowSpan="3"
AutoGenerateColumns="False" AutoGenerateColumns="False"
IsReadOnly="True" IsReadOnly="True"
ItemsSource="{Binding Plc.Registers, Mode=OneWay}"> ItemsSource="{Binding Plc.Registers, Mode=OneWay}">
@@ -219,14 +238,14 @@
<DataGridTemplateColumn Width="15"> <DataGridTemplateColumn Width="15">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate> <DataTemplate>
<Border Background="{Binding MemoryAreaHash, Mode=OneWay, Converter={StaticResource hashColor}}"/> <Border Background="{Binding MemoryArea, Mode=OneWay, Converter={StaticResource hashColor}}"/>
</DataTemplate> </DataTemplate>
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
</DataGrid.Columns> </DataGrid.Columns>
</DataGrid> </DataGrid>
<TextBlock Text="Property Bindings" <TextBlock Text="Memory Areas"
Grid.Column="2" Grid.Column="2"
FontSize="18" FontSize="18"
Margin="10"/> Margin="10"/>
@@ -238,6 +257,43 @@
BorderBrush="LightBlue" BorderBrush="LightBlue"
BorderThickness="1.5"> 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> <ScrollViewer>
<StackPanel> <StackPanel>

View 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}";
}
}

View File

@@ -82,8 +82,11 @@ namespace MewtocolNet {
typeCode = (int)t; typeCode = (int)t;
discontinued = t.IsDiscontinued(); discontinued = t.IsDiscontinued();
#if Debug
exrt = t.IsEXRTPLC(); exrt = t.IsEXRTPLC();
tested = t.WasTestedLive(); tested = t.WasTestedLive();
#endif
} }

View File

@@ -1,7 +1,9 @@
using MewtocolNet.Events; using MewtocolNet.Events;
using MewtocolNet.ProgramParsing; using MewtocolNet.ProgramParsing;
using MewtocolNet.RegisterBuilding; using MewtocolNet.RegisterBuilding;
using MewtocolNet.RegisterBuilding.BuilderPatterns;
using MewtocolNet.Registers; using MewtocolNet.Registers;
using MewtocolNet.UnderlyingRegisters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
@@ -69,6 +71,11 @@ namespace MewtocolNet {
/// </summary> /// </summary>
int PollerCycleDurationMs { get; } int PollerCycleDurationMs { get; }
/// <summary>
/// Shorthand indicator if the plc is in RUN mode
/// </summary>
bool IsRunMode { get; }
/// <summary> /// <summary>
/// Currently queued message count /// Currently queued message count
/// </summary> /// </summary>
@@ -96,10 +103,12 @@ namespace MewtocolNet {
IEnumerable<IRegister> Registers { get; } IEnumerable<IRegister> Registers { get; }
RBuildAnon Register { get; }
/// <summary> /// <summary>
/// Tries to establish a connection with the device asynchronously /// Tries to establish a connection with the device asynchronously
/// </summary> /// </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> /// <returns></returns>
Task ConnectAsync(Func<Task> onConnected = null); Task ConnectAsync(Func<Task> onConnected = null);
@@ -187,6 +196,11 @@ namespace MewtocolNet {
/// </summary> /// </summary>
string Explain(); string Explain();
/// <summary>
/// A readonly list of the underlying memory areas
/// </summary>
IReadOnlyList<IMemoryArea> MemoryAreas { get; }
} }
} }

View File

@@ -16,7 +16,7 @@ namespace MewtocolNet.Logging {
/// <summary> /// <summary>
/// Defines the default output logger targets /// Defines the default output logger targets
/// </summary> /// </summary>
public static LoggerTargets DefaultTargets { get; set; } = LoggerTargets.Console; public static LoggerTargets DefaultTargets { get; set; } = LoggerTargets.None;
internal static Action<DateTime, LogLevel, string> LogInvoked; internal static Action<DateTime, LogLevel, string> LogInvoked;
@@ -26,7 +26,7 @@ namespace MewtocolNet.Logging {
OnNewLogMessage((d, l, m) => { OnNewLogMessage((d, l, m) => {
if(isConsoleApplication && DefaultTargets.HasFlag(LoggerTargets.Console)) { if(isConsoleApplication || DefaultTargets.HasFlag(LoggerTargets.Console)) {
switch (l) { switch (l) {
case LogLevel.Error: case LogLevel.Error:

View File

@@ -379,12 +379,12 @@ namespace MewtocolNet
/// <summary> /// <summary>
/// A builder for attaching register collections /// A builder for attaching register collections
/// </summary> /// </summary>
public PostInit<T> WithRegisters(Action<RBuild> builder) { public PostInit<T> WithRegisters(Action<RBuildMulti> builder) {
try { try {
var plc = (MewtocolInterface)(object)intf; var plc = (MewtocolInterface)(object)intf;
var regBuilder = new RBuild(plc); var regBuilder = new RBuildMulti(plc);
builder.Invoke(regBuilder); builder.Invoke(regBuilder);
@@ -406,7 +406,7 @@ namespace MewtocolNet
/// </summary> /// </summary>
/// <param name="heartBeatAsync"></param> /// <param name="heartBeatAsync"></param>
/// <returns></returns> /// <returns></returns>
public EndInitSetup<T> WithHeartbeatTask(Func<Task> heartBeatAsync, bool executeInProg = false) { public EndInitSetup<T> WithHeartbeatTask(Func<IPlc,Task> heartBeatAsync, bool executeInProg = false) {
try { try {
var plc = (MewtocolInterface)(object)this.intf; 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> /// <summary>
/// Builds and returns the final plc interface /// Builds and returns the final plc interface
/// </summary> /// </summary>

View File

@@ -1,10 +1,12 @@
using MewtocolNet.Events; using MewtocolNet.Events;
using MewtocolNet.Helpers; using MewtocolNet.Helpers;
using MewtocolNet.Logging; using MewtocolNet.Logging;
using MewtocolNet.RegisterBuilding.BuilderPatterns;
using MewtocolNet.Registers; using MewtocolNet.Registers;
using MewtocolNet.UnderlyingRegisters; using MewtocolNet.UnderlyingRegisters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@@ -156,6 +158,9 @@ namespace MewtocolNet {
/// <inheritdoc/> /// <inheritdoc/>
public int BytesPerSecondDownstream => bytesPerSecondDownstream; public int BytesPerSecondDownstream => bytesPerSecondDownstream;
/// <inheritdoc/>
public bool IsRunMode => PlcInfo.IsRunMode;
/// <inheritdoc/> /// <inheritdoc/>
public MewtocolVersion MewtocolVersion { public MewtocolVersion MewtocolVersion {
get => mewtocolVersion; get => mewtocolVersion;
@@ -168,6 +173,9 @@ namespace MewtocolNet {
/// <inheritdoc/> /// <inheritdoc/>
public string ConnectionInfo => GetConnectionInfo(); public string ConnectionInfo => GetConnectionInfo();
/// <inheritdoc/>
public RBuildAnon Register => new RBuildAnon(this);
#endregion #endregion
#region Public read/write Properties / Fields #region Public read/write Properties / Fields
@@ -191,6 +199,21 @@ namespace MewtocolNet {
Disconnected += MewtocolInterface_Disconnected; Disconnected += MewtocolInterface_Disconnected;
RegisterChanged += OnRegisterChanged; 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 () { internal MewtocolInterface Build () {
@@ -269,10 +292,19 @@ namespace MewtocolNet {
if (callBack != null) { if (callBack != null) {
await Task.Run(callBack); await callBack();
Logger.Log($">> OnConnected run complete <<", LogLevel.Verbose, this); 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(); protected virtual Task ReconnectAsync(int conTimeout) => throw new NotImplementedException();
/// <inheritdoc/> /// <inheritdoc/>
public async Task AwaitFirstDataCycleAsync() => await firstPollTask; public async Task AwaitFirstDataCycleAsync() {
if(firstPollTask != null && !firstPollTask.IsCompleted)
await firstPollTask;
await Task.CompletedTask;
}
/// <inheritdoc/> /// <inheritdoc/>
public async Task DisconnectAsync() { public async Task DisconnectAsync() {
@@ -842,22 +881,8 @@ namespace MewtocolNet {
isReconnectingStage = false; isReconnectingStage = false;
isConnectingStage = false; isConnectingStage = false;
if (!usePoller) {
firstPollTask.RunSynchronously();
}
Connected?.Invoke(this, new PlcConnectionArgs()); Connected?.Invoke(this, new PlcConnectionArgs());
PolledCycle += OnPollCycleDone;
void OnPollCycleDone() {
if(firstPollTask != null && !firstPollTask.IsCompleted)
firstPollTask.RunSynchronously();
PolledCycle -= OnPollCycleDone;
}
} }
private protected void OnReconnected () { private protected void OnReconnected () {
@@ -982,8 +1007,12 @@ namespace MewtocolNet {
#endregion #endregion
/// <inheritdoc/>
public string Explain() => memoryManager.ExplainLayout(); public string Explain() => memoryManager.ExplainLayout();
/// <inheritdoc/>
public IReadOnlyList<IMemoryArea> MemoryAreas => memoryManager.GetAllMemoryAreas();
} }
} }

View File

@@ -18,10 +18,11 @@ namespace MewtocolNet {
public abstract partial class MewtocolInterface { public abstract partial class MewtocolInterface {
private bool heartbeatNeedsRun = false; private bool heartbeatNeedsRun = false;
private bool heartbeatTimerRunning = false;
internal Task heartbeatTask = Task.CompletedTask; internal Task heartbeatTask = Task.CompletedTask;
internal Func<Task> heartbeatCallbackTask; internal Func<IPlc, Task> heartbeatCallbackTask;
internal bool execHeartBeatCallbackTaskInProg = false; internal bool execHeartBeatCallbackTaskInProg = false;
internal Task pollCycleTask; internal Task pollCycleTask;
@@ -73,6 +74,7 @@ namespace MewtocolNet {
heartBeatTimer.Elapsed -= PollTimerTick; heartBeatTimer.Elapsed -= PollTimerTick;
heartBeatTimer.Dispose(); heartBeatTimer.Dispose();
heartbeatTimerRunning = false;
} }
@@ -82,12 +84,15 @@ namespace MewtocolNet {
if (!IsConnected) return; if (!IsConnected) return;
if(!heartbeatTimerRunning) {
heartBeatTimer = new System.Timers.Timer(); heartBeatTimer = new System.Timers.Timer();
heartBeatTimer.Interval = 3000; heartBeatTimer.Interval = 3000;
heartBeatTimer.Elapsed += PollTimerTick; heartBeatTimer.Elapsed += PollTimerTick;
heartBeatTimer.Start(); heartBeatTimer.Start();
heartbeatTimerRunning = true;
}
if (!usePoller) return; if (!usePoller || PollerActive) return;
bool hasCyclic = memoryManager.HasCyclicPollableRegisters(); bool hasCyclic = memoryManager.HasCyclicPollableRegisters();
bool hasFirstCycle = memoryManager.HasSingleCyclePollableRegisters(); bool hasFirstCycle = memoryManager.HasSingleCyclePollableRegisters();
@@ -154,7 +159,7 @@ namespace MewtocolNet {
} }
if(heartbeatCallbackTask != null && (plcInfo.IsRunMode || execHeartBeatCallbackTaskInProg)) if(heartbeatCallbackTask != null && (plcInfo.IsRunMode || execHeartBeatCallbackTaskInProg))
await heartbeatCallbackTask(); await heartbeatCallbackTask(this);
Logger.LogVerbose("End heartbeat", this); Logger.LogVerbose("End heartbeat", this);
@@ -235,6 +240,12 @@ namespace MewtocolNet {
sw.Stop(); sw.Stop();
if (firstPollTask != null && !firstPollTask.IsCompleted) {
firstPollTask.RunSynchronously();
firstPollTask = null;
Logger.Log("poll cycle first done");
}
pollerFirstCycleCompleted = true; pollerFirstCycleCompleted = true;
PollerCycleDurationMs = (int)sw.ElapsedMilliseconds; PollerCycleDurationMs = (int)sw.ElapsedMilliseconds;
@@ -296,11 +307,6 @@ namespace MewtocolNet {
collection.OnInterfaceLinked(this); collection.OnInterfaceLinked(this);
} }
Connected += (s,e) => {
if (collection != null)
collection.OnInterfaceLinkedAndOnline(this);
};
} }
AddRegisters(regBuild.assembler.assembled.ToArray()); AddRegisters(regBuild.assembler.assembled.ToArray());

View File

@@ -3,7 +3,6 @@
<PropertyGroup> <PropertyGroup>
<IsPublishable>false</IsPublishable> <IsPublishable>false</IsPublishable>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Mewtocol.NET</PackageId> <PackageId>Mewtocol.NET</PackageId>
<Version>0.0.0</Version> <Version>0.0.0</Version>
@@ -17,7 +16,6 @@
<PackageTags>plc;panasonic;mewtocol;automation;</PackageTags> <PackageTags>plc;panasonic;mewtocol;automation;</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<UserSecretsId>2ccdcc9b-94a3-4e76-8827-453ab889ea33</UserSecretsId> <UserSecretsId>2ccdcc9b-94a3-4e76-8827-453ab889ea33</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'"> <PropertyGroup Condition="'$(Configuration)'=='Release'">
@@ -25,6 +23,11 @@
<OutputPath>..\Builds\MewtocolNet</OutputPath> <OutputPath>..\Builds\MewtocolNet</OutputPath>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DocumentationFile>..\Builds\MewtocolNet\Debug\MewtocolNet.xml</DocumentationFile>
<OutputPath>..\Builds\MewtocolNet\Debug</OutputPath>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo"> <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>MewtocolTests</_Parameter1> <_Parameter1>MewtocolTests</_Parameter1>

View File

@@ -15,35 +15,35 @@ namespace MewtocolNet {
/// <summary> /// <summary>
/// Is in RUN mode, otherwise its PROG Mode /// Is in RUN mode, otherwise its PROG Mode
/// </summary> /// </summary>
RunMode = 1, RunMode = 1 << 0,
/// <summary> /// <summary>
/// Is in test mode, otherwise ok /// Is in test mode, otherwise ok
/// </summary> /// </summary>
TestMode = 2, TestMode = 1 << 1,
/// <summary> /// <summary>
/// Is BRK/1 step executed /// Is BRK/1 step executed
/// </summary> /// </summary>
BreakPointPerOneStep = 4, BreakPointPerOneStep = 1 << 2,
/// <summary> /// <summary>
/// Is BRK command enabled /// Is BRK command enabled
/// </summary> /// </summary>
BreakEnabled = 16, BreakEnabled = 1 << 3,
/// <summary> /// <summary>
/// Is outputting to external device /// Is outputting to external device
/// </summary> /// </summary>
ExternalOutput = 32, ExternalOutput = 1 << 4,
/// <summary> /// <summary>
/// Is 1 step exec enabled /// Is 1 step exec enabled
/// </summary> /// </summary>
OneStepExecEnabled = 64, OneStepExecEnabled = 1 << 5,
/// <summary> /// <summary>
/// Is a message displayed? /// Is a message displayed?
/// </summary> /// </summary>
MessageInstructionDisplayed = 128, MessageInstructionDisplayed = 1 << 6,
/// <summary> /// <summary>
/// Is in remote mode /// Is in remote mode
/// </summary> /// </summary>
RemoteMode = 255, RemoteMode = 1 << 7,
} }

View File

@@ -1,6 +1,7 @@
using MewtocolNet.Registers; using MewtocolNet.Registers;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace MewtocolNet.RegisterAttributes { namespace MewtocolNet.RegisterAttributes {
@@ -57,7 +58,7 @@ namespace MewtocolNet.RegisterAttributes {
/// and the plc connection is established /// and the plc connection is established
/// </summary> /// </summary>
/// <param name="plc">The parent interface</param> /// <param name="plc">The parent interface</param>
public virtual void OnInterfaceLinkedAndOnline(MewtocolInterface plc) { } public virtual Task OnInterfaceLinkedAndOnline(MewtocolInterface plc) => Task.CompletedTask;
} }

View File

@@ -30,7 +30,7 @@ namespace MewtocolNet.RegisterBuilding {
private static ParseResult TryBuildBoolean(string plcAddrName) { private static ParseResult TryBuildBoolean(string plcAddrName) {
//regex to find special register values //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); var match = patternBool.Match(plcAddrName);

View File

@@ -34,10 +34,13 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
//bool constructor //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); 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); data.dotnetVarType = typeof(bool);
return new StructStp<bool>(data) { return new StructStp<bool>(data) {
@@ -48,10 +51,13 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
//struct constructor //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); var data = AddressTools.ParseAddress(fpAddr, name);
if (data.regType.IsBoolean())
throw new NotSupportedException($"The address '{fpAddr}' was no DT address");
data.dotnetVarType = typeof(T); data.dotnetVarType = typeof(T);
return new StructStp<T>(data) { return new StructStp<T>(data) {
@@ -62,10 +68,13 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
//string constructor //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); 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.dotnetVarType = typeof(string);
data.byteSizeHint = (uint)sizeHint; data.byteSizeHint = (uint)sizeHint;
@@ -82,6 +91,8 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
//structs can lead to arrays //structs can lead to arrays
public class StructStp<T> : ArrayStp<T> where T : struct { public class StructStp<T> : ArrayStp<T> where T : struct {
internal StructStp() {}
internal StructStp(StepData data) { internal StructStp(StepData data) {
this.Data = 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 //strings can lead to arrays
public class StringStp<T> : ArrayStp<T> where T : class { public class StringStp<T> : ArrayStp<T> where T : class {
internal StringStp() { }
internal StringStp(StepData data) { internal StringStp(StepData data) {
this.Data = 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 //arrays
@@ -199,66 +174,21 @@ namespace MewtocolNet.RegisterBuilding.BuilderPatterns {
//1D array //1D array
public class TypedArr1D<T> : TypedArr1DOut<T> { public class TypedArr1D<T> : TypedArr1DOut<T> { }
public TypedArr1DOut<T> PollLevel(int level) { public class TypedArr1DOut<T> : SBaseRB { }
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);
}
//2D array //2D array
public class TypedArr2D<T> : TypedArr2DOut<T> { public class TypedArr2D<T> : TypedArr2DOut<T> { }
public TypedArr2DOut<T> PollLevel(int level) { public class TypedArr2DOut<T> : SBaseRB { }
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);
}
//3D array //3D array
public class TypedArr3D<T> : SBaseRB { public class TypedArr3D<T> : SBaseRB { }
public TypedArr3DOut<T> PollLevel(int level) { public class TypedArr3DOut<T> : SBaseRB { }
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);
}
#endregion #endregion

View 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();
}
}
}
}

View 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);
}
}
}

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using MewtocolNet.Events; using MewtocolNet.Events;
using MewtocolNet.UnderlyingRegisters;
namespace MewtocolNet.Registers { namespace MewtocolNet.Registers {
@@ -20,6 +21,11 @@ namespace MewtocolNet.Registers {
/// </summary> /// </summary>
bool IsAutoGenerated { get; } bool IsAutoGenerated { get; }
/// <summary>
/// The readonly memory area of the register
/// </summary>
IMemoryArea MemoryArea { get; }
/// <summary> /// <summary>
/// Type of the underlying register /// Type of the underlying register
/// </summary> /// </summary>

View File

@@ -66,6 +66,9 @@ namespace MewtocolNet.Registers {
/// <inheritdoc/> /// <inheritdoc/>
public RegisterPrefix RegisterType { get; internal set; } public RegisterPrefix RegisterType { get; internal set; }
/// <inheritdoc/>
public IMemoryArea MemoryArea => underlyingMemory;
/// <inheritdoc/> /// <inheritdoc/>
public string Name => name; public string Name => name;

View File

@@ -123,7 +123,7 @@ namespace MewtocolNet.Registers {
//if string correct the sizing of the byte hint was wrong //if string correct the sizing of the byte hint was wrong
var reservedSize = BitConverter.ToInt16(bytes, 0); var reservedSize = BitConverter.ToInt16(bytes, 0);
if (reservedStringLength != reservedSize && attachedInterface.PlcInfo.IsRunMode) if (reservedStringLength != reservedSize && attachedInterface.PlcInfo.IsRunMode && !attachedInterface.isConnectingStage)
throw new NotSupportedException( throw new NotSupportedException(
$"The STRING register at {GetMewName()} is not correctly sized, " + $"The STRING register at {GetMewName()} is not correctly sized, " +
$"the size should be STRING[{reservedSize}] instead of STRING[{reservedStringLength}]" $"the size should be STRING[{reservedSize}] instead of STRING[{reservedStringLength}]"

View File

@@ -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) //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) //first 4 bytes are reserved size (2 bytes) and used size (2 bytes)
//the remaining bytes are the ascii bytes for the string //the remaining bytes are the ascii bytes for the string

View File

@@ -2,17 +2,21 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MewtocolNet.UnderlyingRegisters { namespace MewtocolNet.UnderlyingRegisters {
public class AreaBase { internal class AreaBase : IMemoryArea {
private MewtocolInterface mewInterface; private MewtocolInterface mewInterface;
private int pollLevel;
internal RegisterPrefix registerType; internal RegisterPrefix registerType;
internal ulong addressStart; internal ulong addressStart;
internal ulong addressEnd; internal ulong addressEnd;
@@ -23,12 +27,25 @@ namespace MewtocolNet.UnderlyingRegisters {
/// </summary> /// </summary>
internal List<LinkedRegisterGroup> managedRegisters = new List<LinkedRegisterGroup>(); internal List<LinkedRegisterGroup> managedRegisters = new List<LinkedRegisterGroup>();
public event PropertyChangedEventHandler PropertyChanged;
public ulong AddressStart => addressStart; public ulong AddressStart => addressStart;
public ulong AddressEnd => addressEnd; 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; mewInterface = mewIf;
pollLevel = pollLvl;
} }
@@ -49,6 +66,9 @@ namespace MewtocolNet.UnderlyingRegisters {
addressStart = addFrom; addressStart = addFrom;
addressEnd = addTo; addressEnd = addTo;
OnPropChange(nameof(AddressRange));
OnPropChange(nameof(UnderlyingWords));
} }
public void UpdateAreaRegisterValues() { public void UpdateAreaRegisterValues() {
@@ -61,6 +81,9 @@ namespace MewtocolNet.UnderlyingRegisters {
var bytes = this.GetUnderlyingBytes(regStart, addLen); var bytes = this.GetUnderlyingBytes(regStart, addLen);
register.SetValueFromBytes(bytes); register.SetValueFromBytes(bytes);
OnPropChange(nameof(UnderlyingWords));
OnPropChange(nameof(UnderlyingWordsString));
} }
} }
@@ -112,6 +135,8 @@ namespace MewtocolNet.UnderlyingRegisters {
var bitArr = new BitArray(underlyingBefore); var bitArr = new BitArray(underlyingBefore);
bitArr[bitIndex] = value;
bitArr.CopyTo(underlyingBefore, 0); bitArr.CopyTo(underlyingBefore, 0);
SetUnderlyingBytes(underlyingBefore, reg.MemoryAddress); 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) { switch (registerType) {
case RegisterPrefix.X: case RegisterPrefix.X:
case RegisterPrefix.Y: case RegisterPrefix.Y:
case RegisterPrefix.R: case RegisterPrefix.R:
return $"W{registerType}{AddressStart}-{AddressEnd} ({managedRegisters.Count} Registers)"; return $"W{registerType}{AddressStart}-{AddressEnd}";
case RegisterPrefix.DT: case RegisterPrefix.DT:
case RegisterPrefix.DDT: case RegisterPrefix.DDT:
return $"DT{AddressStart}-{AddressEnd} ({managedRegisters.Count} Registers)"; return $"DT{AddressStart}-{AddressEnd}";
} }
return ""; return "";
} }
public override string ToString() => $"{GetAddressRangeString()} ({managedRegisters.Count} Registers)";
private protected void OnPropChange([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
} }
} }

View File

@@ -1,16 +1,18 @@
using MewtocolNet.Registers; using MewtocolNet.Registers;
using System.Collections.Generic;
using System.ComponentModel;
namespace MewtocolNet.UnderlyingRegisters { 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; }
} }

View File

@@ -221,7 +221,7 @@ namespace MewtocolNet.UnderlyingRegisters {
//create a new area //create a new area
if (targetArea == null) { if (targetArea == null) {
targetArea = new AreaBase(mewInterface) { targetArea = new AreaBase(mewInterface, pollLevelFound.level) {
addressStart = regInsAddStart, addressStart = regInsAddStart,
addressEnd = regInsAddEnd, addressEnd = regInsAddEnd,
registerType = insertReg.RegisterType, 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() { internal bool HasSingleCyclePollableRegisters() {
bool hasCyclicPollableLevels = pollLevels.Any(x => x.level != MewtocolNet.PollLevel.FirstIteration); bool hasCyclicPollableLevels = pollLevels.Any(x => x.level != MewtocolNet.PollLevel.FirstIteration);

9
nuget.config Normal file
View 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>