This commit is contained in:
Felix Weiß
2022-06-20 17:09:56 +02:00
5 changed files with 194 additions and 91 deletions

2
.gitignore vendored
View File

@@ -13,6 +13,8 @@
#ignore builds #ignore builds
Builds/ Builds/
.vscode
# User-specific files (MonoDevelop/Xamarin Studio) # User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs *.userprefs

26
.vscode/launch.json vendored
View File

@@ -1,26 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/Examples/bin/Debug/net5.0/Examples.dll",
"args": [],
"cwd": "${workspaceFolder}/Examples",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

42
.vscode/tasks.json vendored
View File

@@ -1,42 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Examples/Examples.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/Examples/Examples.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"${workspaceFolder}/Examples/Examples.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}

21
LICENSE.md Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 WOLF Medizintechnik GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

194
README.md
View File

@@ -1,39 +1,187 @@
# MewtocolNet # MewtocolNet
A 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 software was written by WOLF Medizintechnik GmbH (@WOmed/dev).
# Features
> Features that are not checked still need implementation
- [x] Read out stats from your PLC
- [x] Read and write registers in real time
- [X] Dynamic register type casting from properties
- [ ] Change run / prog modes
- [ ] Write byte blocks in a whole chain
- [ ] Upload programs to the PLC
- [ ] Download programs from the PLC
- [ ] Reading / writing PLC system registers
# Support
## .NET Support
This library was written in **netstandard2.0** and should by compatible with a lot of .NET environments.
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
> 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
|PLC Type|Supported|Tested|
|--------|---------|------|
FPX C14 |✔ |✔ |
FPX C30 |✔ |✔ |
FPX-H C14|✔ |✔ |
FPX-H C30|✔ |✔ |
FP Sigma |✔ |❌ |
Where is the RS232/Serial support?
> Support for the serial protocol will be added soon, feel free to contribute
# Protocol description
Panasonic has published a [protocol definition](https://mediap.industry.panasonic.eu/assets/custom-upload/Factory%20&%20Automation/PLC/Manuals/mn_all_plcs_mewtocol_user_pidsx_en.pdf) on their site.
Refer to this site if you want to see the general functionality or add / report missing features.
> This library is at the time not feature complete, but all essential features are provided
# Usage # Usage
1. Connecting to a PLC See [More examples](/Examples) here
## Connecting to a PLC
Connecting to a PLC is as simple as
```C# ```C#
//Create a new interface class with your PLCs IP address and port //attaching a logger
MewtocolInterface interf = new MewtocolInterface("127.0.0.1", 9094); Logger.LogLevel = LogLevel.Verbose;
Logger.OnNewLogMessage((date, msg) => {
Console.WriteLine($"{date.ToString("HH:mm:ss")} {msg}");
});
//Setup the dataregisters of the PLC you want to read //setting up a new PLC interface
interf.AddRegister<short>("Test Integer",1204); MewtocolInterface interf = new MewtocolInterface("10.237.191.3");
interf.AddRegister<string>(1101, 4);
//attaches an auto reader that polls the registers await interf.ConnectAsync();
interf.WithPoller(); ```
//triggers when a dataregister changes its value You can also use the callbacks of the `ConnectAsync()` method to do something after the initial connection establishment.
interf.RegisterChanged += (o) => {
Console.WriteLine($"DT{o.MemoryAdress} {(o.Name != null ? $"({o.Name}) " : "")}changed to {o.GetValueString()}");
};
//Connects to the PLC asynchronous and invokes connected or failed ```C#
await interf.ConnectAsync( await interf.ConnectAsync(
(plcinf) => { //PLC connected
(plc) => {
Console.WriteLine("Connected to PLC:\n" + plcinf.ToString()); if(plcinf.OperationMode.RunMode)
Console.WriteLine("PLC is in RUN");
//read back a register value
var statusNum = (NRegister<short>)interf.Registers[1204];
Console.WriteLine($"Status num is: {statusNum.Value}");
}, },
//Connection failed
() => { () => {
Console.WriteLine("Failed connection"); Console.WriteLine("PLC failed to connect");
} }
); );
``` ```
## Reading data registers / contacts
- Create a new class that inherits from `RegisterCollectionBase`
```C#
public class TestRegisters : RegisterCollectionBase {
//corresponds to a R100 boolean register in the PLC
[Register(100, RegisterType.R)]
public bool TestBool1 { get; private set; }
//corresponds to a XD input of the PLC
[Register(RegisterType.X, SpecialAddress.D)]
public bool TestBoolInputXD { get; private set; }
//corresponds to a DT7012 - DT7013 as a 32bit time value that gets parsed as a timespan (TIME)
//the smallest value to communicate to the PLC is 10ms
[Register(7012)]
public TimeSpan TestTime { get; private set; }
//corresponds to a DT1101 - DT1104 string register in the PLC with (STRING[4])
[Register(1101, 4)]
public string TestString1 { get; private set; }
}
```
- Connect to the PLC and attach the register collection and logger
- attach an automatic poller by chaining `.WithPoller()` after the register attachment
```C#
//attaching a logger
Logger.LogLevel = LogLevel.Verbose;
Logger.OnNewLogMessage((date, msg) => {
Console.WriteLine($"{date.ToString("HH:mm:ss")} {msg}");
});
//setting up a new PLC interface and register collection
MewtocolInterface interf = new MewtocolInterface("192.168.115.3");
TestRegisters registers = new TestRegisters();
//attaching the register collection and an automatic poller
interf.WithRegisterCollection(registers).WithPoller();
await interf.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
> Note! this is not your only option to read registers, see here
## Writing data registers / contacts
⚠ **Never set a register by setting the property, always use one of the provided methods**
### Synchronous
Sets the register without feedback if it was set
```C#
//inverts the boolean register
interf.SetRegister(nameof(registers.TestBool1), !registers.TestBool1);
//set the current second to the PLCs TIME register
interf.SetRegister(nameof(registers.TestTime), TimeSpan.FromSeconds(DateTime.Now.Second));
//writes 'Test' to the PLCs string register
interf.SetRegister(nameof(registers.TestString1), "Test");
```
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#
interf.AddRegister<bool>(105, _name: "ManualBoolRegister");
```
Reading the value of the manually added register
```C#
//get the value as a string
string value = interf.GetRegister("ManualBoolRegister").GetValueString();
//get the value by casting
bool value2 = interf.GetRegister<BRegister>("ManualBoolRegister").Value;
//for double casted ones like numbers
var value2 = interf.GetRegister<NRegister<short>>("NumberRegister").Value;
```
### Asynchronous
Sets the register waiting for the PLC to confirm it was set
```C#
//inverts the boolean register
interf.SetRegisterAsync(nameof(registers.TestBool1), !registers.TestBool1);
```