PLC4Net: PLC4X suite for .NET
PLC4Net is a comprehensive suite of libraries and tools to use PLC4X and .NET side-by-side.
PLC4Net | PLC4Net.Templates | PLC4NetCLI | PLC4NetPS |
---|---|---|---|
PLC4Net is a suite, curated by MASES Group, can be supported by the open-source community.
Its primary scope is to support other, public or internal, MASES Group projects: open-source community and commercial entities can use it for their needs and support this project, moreover there are dedicated community and commercial subscription plans.
The repository code and releases may contain bugs, the release cycle depends from critical discovered issues and/or enhancement requested from this or other projects.
Looking for the help of experts? MASES Group can help you design, build, deploy, and manage applications based PLC.
This project aims to create a set of libraries and tools to direct access, from .NET, all the features available in the PLC4X since, as stated in PLC4X GitHub repository, the support for C# was abandoned. And, still in PLC4X protocols page, the main supported languages are Java and Go. This project mutuated the name of the PLC4X support for .NET and implements almost all Java classes in .NET giving to a developer the same programming experience of Java. The following snippets demonstrate the comparison between the Java code and the C# counterpart offered from this project.
Try-with-resource statement:
String cString = "s7://10.10.64.20";
PlcConnection plcConnection = null;
try (plcConnection = PlcDriverManager.getDefault()
.getConnectionManager()
.getConnection(cString))
{
... do something with the connection here ...
}
becomes a using
clause:
const string cString = "s7://10.10.64.20";
using (var plcConnection = PlcDriverManager.Default
.ConnectionManager
.GetConnection(cString))
{
... do something with the connection here ...
}
The following Java snippet:
// Check if this connection support reading of data.
if (!plcConnection.getMetadata().isReadSupported()) {
logger.error("This connection doesn't support reading.");
return;
}
becomes in C#:
if (!plcConnection.Metadata.IsReadSupported())
{
Console.WriteLine("This connection doesn't support reading.");
return;
}
The following Java snippet:
// Create a new read request:
// - Give the single item requested an alias name
PlcReadRequest.Builder builder = plcConnection.readRequestBuilder();
builder.addTagAddress("value-1", "%Q0.4:BOOL");
builder.addTagAddress("value-2", "%Q0:BYTE");
builder.addTagAddress("value-3", "%I0.2:BOOL");
builder.addTagAddress("value-4", "%DB.DB1.4:INT");
PlcReadRequest readRequest = builder.build();
PlcReadResponse response = readRequest.execute().get(5000, TimeUnit.MILLISECONDS);
becomes in C#:
// Create a new read request:
// - Give the single item requested an alias name
PlcReadRequest.Builder builder = plcConnection.ReadRequestBuilder();
builder.AddTagAddress("value-1", "%Q0.4:BOOL");
builder.AddTagAddress("value-2", "%Q0:BYTE");
builder.AddTagAddress("value-3", "%I0.2:BOOL");
builder.AddTagAddress("value-4", "%DB.DB1.4:INT");
PlcRequest readRequest = builder.Build();
var cf = readRequest.Execute<PlcReadResponse>();
var response = cf.Get();
The following Java snippet:
for (String tagName : response.getTagNames()) {
if(response.getResponseCode(tagName) == PlcResponseCode.OK) {
int numValues = response.getNumberOfValues(tagName);
// If it's just one element, output just one single line.
if(numValues == 1) {
logger.info("Value[" + tagName + "]: "
+ response.getObject(tagName));
}
// If it's more than one element, output each in a single row.
else {
logger.info("Value[" + tagName + "]:");
for(int i = 0; i < numValues; i++) {
logger.info(" - " + response.getObject(tagName, i));
}
}
}
// Something went wrong, to output an error message instead.
else {
logger.error("Error[" + tagName + "]: "
+ response.getResponseCode(tagName).name());
}
}
becomes in C#:
foreach (Java.Lang.String tagName in response.TagNames)
{
if (response.GetResponseCode(tagName) == PlcResponseCode.OK)
{
int numValues = response.GetNumberOfValues(tagName);
// If it's just one element, output just one single line.
if (numValues == 1)
{
Console.WriteLine($"Value[{tagName}]: {response.GetObject(tagName)}");
}
// If it's more than one element, output each in a single row.
else
{
Console.WriteLine($"Value[{tagName}]:");
for (int i = 0; i < numValues; i++)
{
Console.WriteLine($" - {response.GetObject(tagName, i)}");
}
}
}
// Something went wrong, to output an error message instead.
else
{
Console.WriteLine($"Error[{tagName}]: {response.GetResponseCode(tagName).Name()}");
}
}
See PLC4Net usage for other examples.
Do you like the project?
- Request your free community subscription.
Do you want to help us?
- put a ⭐ on this project
- open issues to request features or report bugs 🐛
- improves the project with Pull Requests
This project adheres to the Contributor Covenant code of conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to [email protected].
- Roadmap
- Current state
- Usage
- Performance tips
- APIs extensibility
- JVM callbacks
- PLC4Net CLI usage
- PLC4Net Docker usage
- PLC4Net PowerShell usage
- PLC4Net Command-line switches
- V0.12.0+: First version based on PLC4X 0.12.0
PLC4Net uses JNet, and indeed JCOBridge with its features, to obtain many benefits:
- Cyber-security:
- JVM and CLR, or CoreCLR, runs in the same process, but are insulated from each other;
- JCOBridge does not make any code injection into JVM;
- JCOBridge does not use any other communication mechanism than JNI;
- .NET (CLR) inherently inherits the cyber-security levels of running JVM;
- Direct access the JVM from any .NET application:
- Any Java/Scala/Kotlin/... class can be directly managed;
- No need to learn new APIs: we try to expose the same APIs in C# style;
- No extra validation cycle on protocol and functionality: bug fix, improvements, new features are immediately available;
- Documentation is shared;
- Dynamic code: it helps to write a Java/Scala/Kotlin/etc seamless language code directly inside a standard .NET application written in C#/VB.NET: look at this simple example and APIs extensibility.
Have a look at the following JCOBridge resources:
- Release notes
- Community Edition
- Commercial Edition
- Latest release: