This commit is contained in:
Felix Weiß
2023-08-21 16:10:17 +02:00

197
README.md
View File

@@ -1,28 +1,47 @@
[![Publish pipeline](https://github.com/WOmed/MewtocolNet/actions/workflows/publish-pipeline.yml/badge.svg)](https://github.com/WOmed/MewtocolNet/actions/workflows/publish-pipeline.yml) [![Publish pipeline](https://github.com/WOmed/MewtocolNet/actions/workflows/publish-pipeline.yml/badge.svg)](https://github.com/WOmed/MewtocolNet/actions/workflows/publish-pipeline.yml)
[![Test pipeline](https://github.com/WOmed/MewtocolNet/actions/workflows/test-pipeline.yml/badge.svg)](https://github.com/WOmed/MewtocolNet/actions/workflows/test-pipeline.yml) [![Test pipeline](https://github.com/WOmed/MewtocolNet/actions/workflows/test-pipeline.yml/badge.svg)](https://github.com/WOmed/MewtocolNet/actions/workflows/test-pipeline.yml)
[![GitHub tag](https://img.shields.io/github/v/tag/WOmed/MewtocolNet?label=Package%20Version)](https://github.com/WOmed/MewtocolNet/pkgs/nuget/Mewtocol.NET) [![GitHub tag](https://img.shields.io/github/v/tag/WOmed/MewtocolNet?label=Package%20Version)](https://github.com/WOmed/MewtocolNet/pkgs/nuget/Mewtocol.NET)
[![gencov](https://github.com/WOmed/MewtocolNet/blob/badges/Builds/TestResults/badge_combined_master.svg)](https://htmlpreview.github.io/?https://github.com/WOmed/MewtocolNet/blob/badges/Builds/TestResults/summary_master.html) [![gencov](../badges/Builds/TestResults/badge_combined_master.svg)](https://htmlpreview.github.io/?https://github.com/WOmed/MewtocolNet/blob/badges/Builds/TestResults/summary_master.html)
![GitHub](https://img.shields.io/github/license/WOmed/MewtocolNet?label=License) ![GitHub](https://img.shields.io/github/license/WOmed/MewtocolNet?label=License)
![Status](https://img.shields.io/badge/Status-In%20dev-orange) ![Status](https://img.shields.io/badge/Status-Stable-orange)
# MewtocolNet # MewtocolNet
An easy to use Mewtocol protocol library to interface with Panasonic PLCs over TCP/Serial. An easy to use Mewtocol protocol library to interface with Panasonic PLCs over TCP/Serial.
## Disclaimer > ⚠️ This library is not an official panasonic product nor does panasonic provide financial support or limitations in any form.
This library is not an official panasonic product nor does panasonic provide financial support or limitations in any form. > This software was written by WOLF Medizintechnik GmbH (@WOmed/dev).
This software was written by WOLF Medizintechnik GmbH (@WOmed/dev).
# PLC Support
## For a full list check [this table](../master_auto_docs/plctypes.md)
> This library was only tested with a few PLCs, other types that support the Panasonic Mewtocol protocol might work.
> Use at your own risk, others might follow with community feedback
# Features # Features
> Features that are not checked still need implementation ## Fully implemented
- [x] Read out stats from your PLC - [x] TCP/IP and Serial Port support
- [x] Get type and hardware information of PLCs
- [x] Get PLC program metadata such as program version and IDs
- [x] Read and write registers in real time - [x] Read and write registers in real time
- [x] Dynamic register type casting from properties - [x] Basic data types / structures support
- [x] Change run / prog modes - [x] Fast readback cycles due to a MemoryManager that optimizes TCP / Serial frames by combining areas
- [x] Write / read byte blocks in a whole chain - [x] Fully customizable heartbeats and polling levels (tell the interface when you need register updates)
- [x] Easy to use builder patterns for interface and register generation
- [x] Register type casting from property attributes
- [x] Change RUN / PROG modes
- [x] Delete Programs
- [x] Write / read low level byte blocks to areas
- [x] Scanning for network devices and change network settings (WDConfigurator features)
# Planned
- [ ] Upload / Download programs to the PLC - [ ] Upload / Download programs to the PLC
- [ ] Reading / writing PLC system registers - [ ] Reading / writing PLC system registers
- [ ] Advanced data structures like SDTs and SDT Arrays
- [ ] Custom open source program compiler for PLC cpus
# Support # Support
@@ -32,18 +51,7 @@ This library was written in **netstandard2.0** and should be compatible with a l
For a full list of supported .NET clrs see [this page](https://docs.microsoft.com/de-de/dotnet/standard/net-standard?tabs=net-standard-2-0#select-net-standard-version) For a full list of supported .NET clrs see [this page](https://docs.microsoft.com/de-de/dotnet/standard/net-standard?tabs=net-standard-2-0#select-net-standard-version)
## PLC Support # Installation
> This library was only tested with a few PLCs, other types that support the Panasonic Mewtocol protocol might work.
> Use at your own risk, others might follow with community feedback
For a **Support List** check [this table](AutoTools.DocBuilder/Docs/plctypes.md)
Where is the RS232/Serial support?
> Support for the serial protocol will be added soon, feel free to contribute
# Installing
Use the dotnet CLI and run Use the dotnet CLI and run
```Shell ```Shell
@@ -57,51 +65,56 @@ Refer to this site if you want to see the general functionality or add / report
> This library is at the time not feature complete, but all essential features are provided > This library is at the time not feature complete, but all essential features are provided
# Usage # Examples
See [More examples](/Examples) here To see a full list of examples [click here](/Examples).
## Connecting to a PLC ## Connecting to a PLC
Connecting to a PLC is as simple as Connecting to a PLC is as simple as
```C# ```C#
//attaching a logger using MewtocolNet;
Logger.LogLevel = LogLevel.Verbose;
Logger.OnNewLogMessage((date, msg) => {
Console.WriteLine($"{date.ToString("HH:mm:ss")} {msg}");
});
//setting up a new PLC interface using (var plc = Mewtocol.Ethernet("192.168.178.55").Build()) {
MewtocolInterface plc = new MewtocolInterface("192.168.115.5");
await plc.ConnectAsync(); await plc.ConnectAsync();
if (!plc.IsConnected) {
Console.WriteLine("Failed to connect to the plc...");
} else {
Console.WriteLine(plc.PlcInfo);
}
}
``` ```
## Reading data registers / contacts ## Reading data registers / contacts
[Detailed instructions](https://github.com/WOmed/MewtocolNet/wiki/Attribute-handled-reading) [Detailed instructions](https://github.com/WOmed/MewtocolNet/wiki/Attribute-handled-reading)
- Create a new class that inherits from `RegisterCollectionBase` - Create a new class that inherits from `RegisterCollection`
```C# ```C#
public class TestRegisters : RegisterCollectionBase { using MewtocolNet;
using MewtocolNet.RegisterAttributes;
public class TestRegisters : RegisterCollection {
//corresponds to a R100 boolean register in the PLC //corresponds to a R100 boolean register in the PLC
[Register(100, RegisterType.R)] [Register("R100")]
public bool TestBool1 { get; private set; } public bool TestBool1 { get; private set; }
//corresponds to a XD input of the PLC //corresponds to a XD input of the PLC
[Register(RegisterType.X, SpecialAddress.D)] [Register("XD")]
public bool TestBoolInputXD { get; private set; } public bool TestBoolInputXD { get; private set; }
//corresponds to a DT7012 - DT7013 as a 32bit time value that gets parsed as a timespan (TIME) //corresponds to a DDT7012 - DDT7013 as a 32bit time value that gets parsed as a timespan (TIME)
//the smallest value to communicate to the PLC is 10ms //the smallest value to communicate to the PLC is 10ms
[Register(7012)] [Register("DDT7012")]
public TimeSpan TestTime { get; private set; } public TimeSpan TestTime { get; private set; }
//corresponds to a DT1101 - DT1104 string register in the PLC with (STRING[4]) //corresponds to a DT1101 - DT1104 string register in the PLC with (STRING[4])
[Register(1101, 4)] [Register("DT1101", "STRING[4]")]
public string TestString1 { get; private set; } public string TestString1 { get; private set; }
} }
@@ -111,80 +124,68 @@ public class TestRegisters : RegisterCollectionBase {
- attach an automatic poller by chaining `.WithPoller()` after the register attachment - attach an automatic poller by chaining `.WithPoller()` after the register attachment
```C# ```C#
//setting up a new PLC interface and register collection TestRegisters registers = null;
MewtocolInterface plc = new MewtocolInterface("192.168.115.5");
TestRegisters registers = new TestRegisters();
//attaching the register collection and an automatic poller //setting up a new PLC serial interface and tell it to use the register collection
plc.WithRegisterCollection(registers).WithPoller(); var plc = Mewtocol.Serial("COM4", BaudRate._19200)
.WithPoller()
.WithRegisterCollections(c => {
registers = c.AddCollection<TestRegisters>();
// or use
// c.AddCollection(new TestRegisters());
// if you want to pass data to a constructor
})
.Build();
//connect to it
await plc.ConnectAsync(async () => {
//restart the plc program during the connection process
await plc.RestartProgramAsync();
});
//wait for the first data cycle of the poller module
//otherwise the property value might still be unset or null
await App.ViewModel.Plc.AwaitFirstDataCycleAsync();
if (App.ViewModel.Plc.IsConnected) {
Console.WriteLine(registers.TestBool1);
}
await plc.ConnectAsync(
(plcinf) => {
//reading a value from the register collection
Console.WriteLine($"Time Value is: {registers.TestTime}");
}
);
``` ```
- Your properties are getting automatically updated after the initial connection - Your properties are getting automatically updated after the initial connection
> Note! this is not your only option to read registers, see here > Note! this is not your only option to read registers, see here
## Writing data registers / contacts ## Reading & Writing
Registers are stored in an underlying layer for automatic handling, each register has a unique name and address. In addition to the automatic property binding you can use these patterns:
Classes that derive from `RegisterCollectionBase` reference these registers automatically using attributes. ### Reading & Writing by using the anonymous builder pattern
All the heavy lifting is done automatically for you, setting this up is described [here](https://github.com/WOmed/MewtocolNet/wiki/Attribute-handled-reading)
### Asynchronous
This operations awaits a task to make sure the register was actually set to your desired value before progressing
```C# ```C#
//sets the register to false await plc.Register.Struct<short>("DT100").WriteAsync(100);
await plc.SetRegisterAsync(nameof(registers.TestBool1), false);
//set the current second to the PLCs TIME register var value = await plc.Register.Struct<short>("DT100").ReadAsync();
await plc.SetRegisterAsync(nameof(registers.TestTime), TimeSpan.FromSeconds(DateTime.Now.Second));
``` ```
### Reading & Writing by using the direct reference from the builder pattern
### Synchronous
Sets the register without feedback if it was set
You can use the method to set a register
```C# ```C#
//inverts the boolean register
plc.SetRegister(nameof(registers.TestBool1), !registers.TestBool1);
//set the current second to the PLCs TIME register IRegister<bool> outputContactReference;
plc.SetRegister(nameof(registers.TestTime), TimeSpan.FromSeconds(DateTime.Now.Second));
//writes 'Test' to the PLCs string register var plc = Mewtocol.Ethernet("127.0.0.1")
plc.SetRegister(nameof(registers.TestString1), "Test"); .WithRegisters(b => {
```
b.Bool("Y4").Build(out outputContactReference);
or write to a register in your `RegisterCollectionBase` directly (you need to attach a register collection to your interface beforehand)
})
```C# .Build();
//inverts the boolean register
registers.TestBool1 = true; await plc.ConnectAsync();
```
await outputContactReference.WriteAsync(true);
You can also set a register by calling its name directly (Must be either in an attached register collection or added to the list manually)
Adding registers to a manual list
```C#
plc.AddRegister<bool>(105, _name: "ManualBoolRegister");
```
Reading the value of the manually added register
```C#
//get the value as a string
string value = plc.GetRegister("ManualBoolRegister").GetValueString();
//get the value by casting
bool value2 = plc.GetRegister<BRegister>("ManualBoolRegister").Value;
//for double casted ones like numbers
var value2 = plc.GetRegister<NRegister<short>>("NumberRegister").Value;
``` ```