Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 11 additions & 15 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,21 @@
"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",
"name": "C#: 02_read_process_data_from_ifm_iotcore Debug",
"type": "dotnet",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/src/Tests/IODD.Parser.Tests/bin/Debug/net7.0/IODD.Parser.Tests.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Tests/IODD.Parser.Tests",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
"projectPath": "${workspaceFolder}/samples/02_read_process_data_from_ifm_iotcore/02_read_process_data_from_ifm_iotcore.csproj"
},
{
"name": ".NET Core Attach",
"name": "C#: IOLink.NET.ConsoleRunner",
"type": "coreclr",
"request": "attach"
"request": "launch",
"program": "${workspaceFolder}/src/Tests/IOLink.NET.ConsoleRunner/bin/Debug/net9.0/IOLink.NET.ConsoleRunner.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Tests/IOLink.NET.ConsoleRunner",
"console": "integratedTerminal",
"stopAtEntry": false,
"preLaunchTask": "build: ConsoleRunner"
}
]
}
66 changes: 60 additions & 6 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,75 @@
"type": "process",
"args": [
"build",
"${workspaceFolder}/src/Tests/IODD.Parser.Tests/IODD.Parser.Tests.csproj",
"${file}",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
"problemMatcher": "$msCompile",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
}
},
{
"label": "build: current project",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${fileDirname}",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "build: solution",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/src/IOLink.NET.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "build: ConsoleRunner",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/src/Tests/IOLink.NET.ConsoleRunner/IOLink.NET.ConsoleRunner.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/src/Tests/IODD.Parser.Tests/IODD.Parser.Tests.csproj",
"${file}",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "watch",
Expand All @@ -33,9 +85,11 @@
"watch",
"run",
"--project",
"${workspaceFolder}/src/Tests/IODD.Parser.Tests/IODD.Parser.Tests.csproj"
"${file}"
],
"problemMatcher": "$msCompile"
"problemMatcher": "$msCompile",
"group": "build",
"isBackground": true
}
]
}
26 changes: 10 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,23 @@ IOLink.NET also provides a parser for the IO Device Description or short [IODD](

## Getting started

IOLinkNET offers a modular toolset to work with IOLink data and device descriptions. Since we do not know the requirements specific to your project we have provide you with different components that you are free to orchestrate in order to achieve your goals. Otherwise we also maintain a default implementation.
IOLink.NET offers a modular toolset to work with IOLink data and device descriptions. Since we do not know the requirements specific to your project we have provide you with different components that you are free to orchestrate in order to achieve your goals. Otherwise we also maintain a default implementation.

Different Usage samples are provided in the samples/ folder. It is still work in progress but growing steadily.

## Overview

Decoding IO-Link data requires us to complete different workloads before hands. First of all we need to source the IODD package for the device we are working with. Then the IODD package has to be searched for the correct description file which in turn has be to parsed. The raw IODD format has some shortcomings when it comes to automatic processing so it needs to be preprocessed.

Based on the preprocessed IODD structure we are able to select the correct data types and decode/encode the given payloads. As you notice there is plenty of work to do for IOLinkNET. In this section we describe the functionality of the different projects.

| Package | Purpose |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| IOLinkNET.IODD.Structure | Contains model to represent the XML structure of an IODD. |
| IOLinkNET.IODD.Provider | Functionality to retrieve IODD packages from e.g. the IODDFinderAPI |
| IOLinkNET.IODD.Parser | Parser components to transform XML IODD to IOLinkNET.IODD.Structure format |
| IOLinkNET.IODD.Resolution | Defines favorable and self-contained format for data type representation and utility to create those from IOLinkNET.IODD.Structure format. |
| IOLinkNET.IODD.Standard | Contains IODD Standard components to support IO-Link Standards |
| IOLinkNET.Conversion | Defines functionality to convert from and to iolink data. |
| IOLinkNET.Device | Defines contracts how communication with io link masters. |
| IOLinkNET.Vendors.\* | Provides vendor specific implementation of the Device interfaces. |
| IOLinkNET.Integration | Orchestrates the modules to functionality that can read process data or parameter data from a device implementation. |
| IOLinkNET.Visualization | Base implementation to provide easy to use components which are useful for data visualization e.g. device readable menu structure |
| IOLinkNET.Visualization.Structure | Contains visualization models which are more usable than using IODD structures with references |
Based on the preprocessed IODD structure we are able to select the correct data types and decode/encode the given payloads. As you notice there is plenty of work to do for IOLink.NET. In this section we describe the functionality of the different projects.

| Package | Purpose |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| IOLink.NET.Core | Contains core contracts, models, and extensions that define the foundation interfaces for device communication and data structures |
| IOLink.NET | Main library containing Conversion and Integration functionality for working with IO-Link data |
| IOLink.NET.IODD | Complete IODD (IO Device Description) handling including Structure, Provider, Parser, Resolution, and Standard components |
| IOLink.NET.Vendors.Ifm | IFM vendor specific implementation for communicating with IFM IO-Link masters |
| IOLink.NET.Visualization | Base implementation to provide easy to use components which are useful for data visualization e.g. device readable menu structure |

## Supporters

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<PackageReference Include="IOLinkNET.Integration" Version="0.2.5" />
<PackageReference Include="IOLinkNET.Vendors.Ifm" Version="0.2.5" />

</ItemGroup>

<ItemGroup>
<PackageReference Include="IOLink.NET" Version="1.0.3" />
<PackageReference Include="IOLink.NET.Vendors.Ifm" Version="1.0.3" />
</ItemGroup>

<PropertyGroup>
Expand Down
57 changes: 42 additions & 15 deletions samples/02_read_process_data_from_ifm_iotcore/Program.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,61 @@
using IOLinkNET.Integration;
using IOLinkNET.Vendors.Ifm;
// First initialize a master connection with a master device that supports the IoT Core api e.g. IFM AL1350 using the provided ConnectionFactory.
using IOLink.NET.Integration;
using IOLink.NET.Vendors.Ifm;


// First initialize a master connection with a master device that supports the IoT Core api e.g. IFM AL1350 using the provided ConnectionFactory.
var masterConnection = IfmIoTCoreMasterConnectionFactory.Create("http://192.168.0.113");
var masterConnection = IfmIoTCoreMasterConnectionFactory.Create("http://192.168.1.177");

// Create a port reader with the master connection and configure IOLinkNET to use the public IODD finder api and its default conversion stack.
var portReader = PortReaderBuilder.NewPortReader()
var portReader = PortReaderBuilder
.NewPortReader()
.WithMasterConnection(masterConnection)
.WithConverterDefaults()
.WithPublicIODDFinderApi()
.Build();


// Initialize the port reader for port 1.
await portReader.InitializeForPortAsync(1);

await portReader.InitializeForPortAsync(4, CancellationToken.None);

Console.WriteLine("Reading Process & Acyclic data from configured master.");
while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape))
while (true)
{
// Read the process data from the device.
var processData = await portReader.ReadConvertedProcessDataInAsync();
var processData = await portReader.ReadConvertedProcessDataInAsync(CancellationToken.None);

// Read the parameter 19, subindex 0 from the device. It is device specific what this parameter represents or if it is even available.
var parameter = await portReader.ReadConvertedParameterAsync(19, 0);
var parameter = await portReader.ReadConvertedParameterAsync(19, 0, CancellationToken.None);
if (parameter is List<ValueTuple<string, object>> parameterValues)
{
// Print the parameter values to the console.
Console.WriteLine("Parameter 19, Subindex 0:");
foreach (var value in parameterValues)
{
Console.WriteLine($" {value.Item1}: {value.Item2}");
}
}
else
{
Console.WriteLine("Parameter 19, Subindex 0 is not available or not convertible.");
}
// Print the process data to the console.
Console.WriteLine(processData);

// Wait 100ms before reading the process data again.
await Task.Delay(100);
// Try to detect an Escape key press, but avoid calling Console.KeyAvailable when there's no console
// or when input is redirected. Use Console.IsInputRedirected as a guard and fall back to catching
// InvalidOperationException just in case.
try
{
if (!Console.IsInputRedirected && Console.KeyAvailable)
{
var key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Escape)
break;
}
}
catch (InvalidOperationException)
{
// No console available or input redirected - continue without key checking.
}

// Wait 500ms before reading the process data again.
await Task.Delay(500);
}

65 changes: 64 additions & 1 deletion src/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -366,4 +366,67 @@ dotnet_naming_style.s_camelcase.word_separator =
dotnet_naming_style.s_camelcase.capitalization = camel_case

dotnet_diagnostic.IDE0130.severity = none
dotnet_diagnostic.IDE0230.severity = none
dotnet_diagnostic.IDE0230.severity = none
dotnet_diagnostic.CS0618.severity = none

#### Async/Await Conventions ####

# CA2007: Do not directly await a Task without calling ConfigureAwait
dotnet_diagnostic.CA2007.severity = error

# Require CancellationToken parameter in async methods
# This is enforced through custom analyzers and code review
# AsyncFixer01: Unnecessary async/await usage
dotnet_diagnostic.AsyncFixer01.severity = error

# AsyncFixer02: Long-running or blocking operations under an async method
dotnet_diagnostic.AsyncFixer02.severity = error

# AsyncFixer03: Fire & forget async void methods
dotnet_diagnostic.AsyncFixer03.severity = error

# AsyncFixer04: Fire & forget async call inside a using block
dotnet_diagnostic.AsyncFixer04.severity = error

# AsyncFixer05: Downcasting from a nested task to an outer task
dotnet_diagnostic.AsyncFixer05.severity = error

# VSTHRD100: Avoid async void methods
dotnet_diagnostic.VSTHRD100.severity = error

# VSTHRD101: Avoid unsupported async delegates
dotnet_diagnostic.VSTHRD101.severity = error

# VSTHRD103: Call async methods when in an async method
dotnet_diagnostic.VSTHRD103.severity = suggestion

# VSTHRD110: Observe result of async calls
dotnet_diagnostic.VSTHRD110.severity = suggestion

# VSTHRD111: Use ConfigureAwait(bool)
dotnet_diagnostic.VSTHRD111.severity = error

# VSTHRD114: Avoid returning null from a Task-returning method
dotnet_diagnostic.VSTHRD114.severity = error

# VSTHRD200: Use Async suffix for async methods
dotnet_diagnostic.VSTHRD200.severity = suggestion

# CA1849: Call async methods when in an async method
dotnet_diagnostic.CA1849.severity = suggestion

# CA2016: Forward the CancellationToken parameter to methods that take one
dotnet_diagnostic.CA2016.severity = error

# Custom rule: Async methods should have CancellationToken parameter
# This requires custom implementation but documents the requirement
# dotnet_diagnostic.CustomAsync001.severity = error

#### Test Files - Relaxed Async/Await Rules ####
[Tests/**/*.cs]

# Allow more flexibility in test files for async/await patterns
dotnet_diagnostic.AsyncFixer01.severity = suggestion
dotnet_diagnostic.VSTHRD111.severity = suggestion
dotnet_diagnostic.CA2007.severity = suggestion
dotnet_diagnostic.CA2016.severity = suggestion
7 changes: 7 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,11 @@
<CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
<CopyDocumentationFilesFromPackages>true</CopyDocumentationFilesFromPackages>
</PropertyGroup>

<!-- Async analyzers for all projects -->
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" PrivateAssets="all" />
<PackageReference Include="AsyncFixer" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" PrivateAssets="all" />
</ItemGroup>
</Project>
5 changes: 5 additions & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />

<!-- Async analyzers -->
<PackageVersion Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.11.20" />
<PackageVersion Include="AsyncFixer" Version="1.6.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion src/IOLink.NET.Core/Contracts/IDeviceDefinitionProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ Task<T> GetDeviceDefinitionAsync(
ushort vendorId,
uint deviceId,
string productId,
CancellationToken cancellationToken = default
CancellationToken cancellationToken
);
}
Loading
Loading