Table of Contents

PLCOnNet: .NET suite for PLC4X™

PLCOnNet is a comprehensive suite of libraries and tools to use PLC4X™ and .NET side-by-side.

Libraries and Tools

PLCOnNet PLCOnNet.Templates PLCOnNetCLI PLCOnNetPS
PLCOnNet nuget
downloads
PLCOnNet.Templates nuget
downloads
PLCOnNetCLI nuget
downloads
PLCOnNetPS

Pipelines

CI_BUILD CodeQL CI_RELEASE

Project disclaimer

PLCOnNet is a suite for PLC4X™, 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.


Scope of the project

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.

Initialization

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 ...
}

Check supported feature

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

Prepare request

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

Analyze returned information

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 PLCOnNet usage for other examples.

Community and Contribution

Do you like the project?

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 coc_reporting@masesgroup.com.