diff --git a/.github/actions/build_nuget/action.yml b/.github/actions/build_nuget/action.yml index ed709f2..d8c2fd0 100644 --- a/.github/actions/build_nuget/action.yml +++ b/.github/actions/build_nuget/action.yml @@ -31,6 +31,30 @@ runs: - name: Build Nuget Package for ${{ inputs.projectPath }} shell: bash working-directory: ${{ inputs.projectPath }} - run: dotnet pack --include-source --include-symbols /p:ContinuousIntegrationBuild=true /p:PackageVersion=${{ steps.gitversion.outputs.nugetVersionV2 }} -c Release -o ${{ inputs.outputDirectory }} + run: | + echo "Building NuGet package for ${{ inputs.projectPath }}" + echo "Package version: ${{ steps.gitversion.outputs.nugetVersionV2 }}" + echo "Output directory: ${{ inputs.outputDirectory }}" + + # Create output directory if it doesn't exist + mkdir -p ${{ inputs.outputDirectory }} + + # Build the package + dotnet pack \ + --include-source \ + --include-symbols \ + /p:ContinuousIntegrationBuild=true \ + /p:PackageVersion=${{ steps.gitversion.outputs.nugetVersionV2 }} \ + -c Release \ + -o ${{ inputs.outputDirectory }} + + # Verify package was created + if [ ! "$(ls -A ${{ inputs.outputDirectory }})" ]; then + echo "ERROR: No package was created in ${{ inputs.outputDirectory }}" + exit 1 + fi + + echo "Successfully created package(s):" + ls -la ${{ inputs.outputDirectory }} \ No newline at end of file diff --git a/.github/actions/publish_nuget/action.yml b/.github/actions/publish_nuget/action.yml index d014d8d..e8b1339 100644 --- a/.github/actions/publish_nuget/action.yml +++ b/.github/actions/publish_nuget/action.yml @@ -18,10 +18,12 @@ runs: - name: Publish Nuget Packages shell: bash - working-directory: ${{ inputs.projectPath }} run: | for file in ${{ inputs.nugetPackageDirectory }}/*.nupkg; do - dotnet nuget push $file -k ${{ inputs.nugetApiKey }} -s ${{ inputs.nugetPackageSource }} --skip-duplicate + if [ -f "$file" ]; then + echo "Publishing $file to ${{ inputs.nugetPackageSource }}" + dotnet nuget push "$file" -k ${{ inputs.nugetApiKey }} -s ${{ inputs.nugetPackageSource }} --skip-duplicate + fi done \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e698e49 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,31 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + # Enable version updates for NuGet + - package-ecosystem: "nuget" + directory: "/src" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + reviewers: + - "domdeger" + commit-message: + prefix: "deps" + prefix-development: "deps-dev" + include: "scope" + + # Enable version updates for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 + reviewers: + - "domdeger" + commit-message: + prefix: "ci" + include: "scope" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..e641b3d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,27 @@ +## Description +Brief description of what this PR does. + +## Type of change +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +## How Has This Been Tested? +Please describe the tests that you ran to verify your changes. + +- [ ] Unit tests +- [ ] Integration tests +- [ ] Manual testing + +## Checklist: +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published in downstream modules diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e73e86a..cc3337f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,15 +14,32 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.0.x + dotnet-version: | + 7.0.x + 8.0.x + 9.0.x + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: csharp + - name: Restore dependencies run: dotnet restore ./src @@ -32,6 +49,9 @@ jobs: - name: Test run: dotnet test ./src --no-build --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage --filter Category!=IntegrationTest + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + - name: Merge Code Coverage files with Reportgenerator uses: danielpalme/ReportGenerator-GitHub-Action@5.2.0 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 76f56f3..dbd5e4a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ jobs: name: Build Nuget Packages runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -23,7 +23,21 @@ jobs: updateAssemblyInfo: true useConfigFile: true - - run: mkdir -p $PWD/npks + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Create output directory + run: mkdir -p $PWD/npkgs - uses: ./.github/actions/build_nuget name: Build Nuget Package for Conversion @@ -75,31 +89,63 @@ jobs: name: Build Nuget Package for Vendors.Ifm with: projectPath: ./src/Vendors/Ifm - outputDirectory: ../../../npkgs + outputDirectory: ../../npkgs - - run: echo $PWD - - run: ls -la $PWD/npkgs - - name: Publish Nuget Package for ${{ inputs.projectPath }} + - name: Verify packages were created + run: | + if [ ! "$(ls -A $PWD/npkgs)" ]; then + echo "No packages were created!" + exit 1 + fi + echo "Created packages:" + ls -la $PWD/npkgs + + - name: Publish Nuget Package for packages uses: actions/upload-artifact@v4 with: - name: packages + name: nuget-packages path: ./npkgs + retention-days: 30 publish: name: Publish Nuget Packages runs-on: ubuntu-latest needs: pack + environment: production steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 with: - name: packages + name: nuget-packages path: ./packages - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.0.x + dotnet-version: 9.0.x + + - name: Verify downloaded packages + run: | + echo "Downloaded packages:" + ls -la $PWD/packages + if [ ! "$(ls -A $PWD/packages)" ]; then + echo "No packages downloaded!" + exit 1 + fi + + - name: Validate package versions + run: | + echo "Validating package versions..." + for file in $PWD/packages/*.nupkg; do + if [ -f "$file" ]; then + filename=$(basename "$file") + echo "Checking if $filename already exists on NuGet.org..." + # Extract package name and version from filename + # This is a basic validation - you might want to enhance this + echo "Package: $filename" + fi + done - run: echo "$GITHUB_CONTEXT" - name: Upload Packages to release @@ -107,16 +153,12 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | for file in $PWD/packages/*.nupkg; do - gh release upload ${{ github.event.release.tag_name }} $file + if [ -f "$file" ]; then + echo "Uploading $file to release ${{ github.event.release.tag_name }}" + gh release upload ${{ github.event.release.tag_name }} "$file" --clobber + fi done - # - uses: ./.github/actions/publish_nuget - # name: Publish Nuget Packages to GitHub - # with: - # nugetApiKey: ${{ secrets.GITHUB_TOKEN }} - # nugetPackageSource: ${{ vars.NUGET_PACKAGE_SOURCE }} - # nugetPackageDirectory: $PWD/packages - - uses: ./.github/actions/publish_nuget name: Publish Nuget Packages to Nuget.org with: diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..102ef0e --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,73 @@ +name: Security Scan + +on: + schedule: + # Run weekly on Mondays at 9 AM UTC + - cron: '0 9 * * 1' + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + security: + name: Security Scan + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + actions: read + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Restore dependencies + run: dotnet restore ./src + + - name: Run .NET security scan + run: | + dotnet list ./src package --vulnerable --include-transitive --include-prerelease > vulnerability-report.txt 2>&1 || true + if grep -q "has the following vulnerable packages" vulnerability-report.txt; then + echo "Vulnerable packages found:" + cat vulnerability-report.txt + echo "::warning::Vulnerable NuGet packages detected" + else + echo "No vulnerable packages found" + fi + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: csharp + + - name: Build for security analysis + run: dotnet build ./src --no-restore + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:csharp" + + - name: Upload vulnerability report + if: always() + uses: actions/upload-artifact@v4 + with: + name: vulnerability-report + path: vulnerability-report.txt + retention-days: 30 diff --git a/samples/01_convert_iol_data_with_iodd/Program.cs b/samples/01_convert_iol_data_with_iodd/Program.cs index 45f13a2..5128fdd 100644 --- a/samples/01_convert_iol_data_with_iodd/Program.cs +++ b/samples/01_convert_iol_data_with_iodd/Program.cs @@ -6,10 +6,11 @@ using IOLinkNET.IODD; using IOLinkNET.IODD.Resolution; - // First we need to parse an IODD definition. This can be done by using the IODDParser class. Or by directly retrieving the IODD from the IODD finder with the IODDFinderPublicClient class. IODDParser parser = new(); -var device = parser.Parse(XElement.Load("../iodds/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml")); +var device = parser.Parse( + XElement.Load("./iodds/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml") +); // Now we can use the IoddConverter class to convert the data. var converter = new IoddConverter(); @@ -19,7 +20,6 @@ void DecodeParameterData() { - // Retrieve the parameter data from the device var data = Convert.FromBase64String("SGVsbG9IZWxsb0hlbGxvSGVsbG9IZWxsb0hlbGxvSGVsbG9IZWxsbw=="); diff --git a/samples/03_work_with_iodds/03_work_with_iodds.csproj b/samples/03_work_with_iodds/03_work_with_iodds.csproj new file mode 100644 index 0000000..5b7791d --- /dev/null +++ b/samples/03_work_with_iodds/03_work_with_iodds.csproj @@ -0,0 +1,21 @@ + + + + + + + + + Exe + net8.0 + 03_work_with_iodds + enable + enable + + + + iodds\%(RecursiveDir)/%(FileName)%(Extension) + Always + + + diff --git a/samples/03_work_with_iodds/Program.cs b/samples/03_work_with_iodds/Program.cs new file mode 100644 index 0000000..f16159d --- /dev/null +++ b/samples/03_work_with_iodds/Program.cs @@ -0,0 +1,84 @@ +using System.Xml.Linq; +using IOLinkNET.IODD; +using IOLinkNET.IODD.Structure.Datatypes; +using IOLinkNET.IODD.Structure.Structure.Menu; + +// Load the IODD file and parse it. +IODDParser parser = new(); +var iodd = parser.Parse( + XElement.Load("./iodds/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml") +); + +var parameters = iodd.ProfileBody.DeviceFunction.VariableCollection; + +PrintDeviceInformation(); +AnalyzeDeviceVariables(); +AnalyzeProcessData(); +DisplayMenuStructure(); + +void PrintDeviceInformation() +{ + Console.WriteLine( + $"Vendor: {iodd.ProfileBody.DeviceIdentity.VendorName} ({iodd.ProfileBody.DeviceIdentity.VendorId}), Device: {iodd.ProfileBody.DeviceIdentity.DeviceId}" + ); +} + +void AnalyzeDeviceVariables() +{ + Console.WriteLine($"Device has {parameters.Count()} parameters:"); + foreach (var parameter in parameters) + { + Console.WriteLine($"\t{parameter.Name.TextId} ({parameter.Index})"); + } + + var parameterWithUnresolvedData = parameters.First(p => p.Index == 147); + + Console.WriteLine( + $"\nParameter with unresolved data type: {parameterWithUnresolvedData.Name.TextId}:" + ); + + var parameterDataType = parameterWithUnresolvedData.Datatype as RecordT; + foreach (var field in parameterDataType!.Items) + { + Console.WriteLine( + $"\t{field.Name.TextId} DataType: ({field.Type}), DataTypeRef: {field.Ref}" + ); + } +} + +void AnalyzeProcessData() +{ + var processData = iodd.ProfileBody.DeviceFunction.ProcessDataCollection; + if (processData.Count() == 1) + { + Console.WriteLine("Device has no process data condition."); + + var processDataType = processData.First().ProcessDataIn!.Datatype as RecordT; + foreach (var field in processDataType!.Items) + { + Console.WriteLine( + $"\t{field.Name.TextId} DataType: ({field.Type}), DataTypeRef: {field.Ref}" + ); + } + } + else + { + var condition = processData.First(pd => pd.Condition is not null).Condition; + Console.WriteLine($"Device has process data condition: {condition!.VariableId}"); + } +} + +void DisplayMenuStructure() +{ + var menuStructure = iodd.ProfileBody.DeviceFunction.UserInterface; + Console.WriteLine($"Device has {menuStructure.MenuCollection.Count()} menus:"); + + foreach (var menu in menuStructure.MenuCollection) + { + Console.WriteLine($"\t{menu.Menu.Name}"); + foreach (var subMenu in menu.Menu.MenuRefs ?? Enumerable.Empty()) + { + Console.WriteLine($"\t\t{subMenu.MenuId}"); + } + } +} diff --git a/samples/samples.sln b/samples/samples.sln index dff4004..0990733 100644 --- a/samples/samples.sln +++ b/samples/samples.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "01_convert_iol_data_with_io EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "02_read_process_data_from_ifm_iotcore", "02_read_process_data_from_ifm_iotcore\02_read_process_data_from_ifm_iotcore.csproj", "{5C06058D-B10A-4903-8E0C-E88779DEBD02}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "02_read_process_data_from_ifm_iotcore", "03_work_with_iodds\03_work_with_iodds.csproj", "{4CE6306D-5438-4087-81F5-A27450A0368A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +26,9 @@ Global {5C06058D-B10A-4903-8E0C-E88779DEBD02}.Debug|Any CPU.Build.0 = Debug|Any CPU {5C06058D-B10A-4903-8E0C-E88779DEBD02}.Release|Any CPU.ActiveCfg = Release|Any CPU {5C06058D-B10A-4903-8E0C-E88779DEBD02}.Release|Any CPU.Build.0 = Release|Any CPU + {4CE6306D-5438-4087-81F5-A27450A0368A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CE6306D-5438-4087-81F5-A27450A0368A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CE6306D-5438-4087-81F5-A27450A0368A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CE6306D-5438-4087-81F5-A27450A0368A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/Conversion/IIoddDataConverter.cs b/src/Conversion/IIoddDataConverter.cs deleted file mode 100644 index 0234db9..0000000 --- a/src/Conversion/IIoddDataConverter.cs +++ /dev/null @@ -1,8 +0,0 @@ -using IOLinkNET.IODD.Resolution; - -namespace IOLinkNET.Conversion; - -public interface IIoddDataConverter -{ - object Convert(ParsableDatatype datatypeDef, ReadOnlySpan data); -} \ No newline at end of file diff --git a/src/Conversion/IoddConverter.cs b/src/Conversion/IoddConverter.cs deleted file mode 100644 index 7b0a670..0000000 --- a/src/Conversion/IoddConverter.cs +++ /dev/null @@ -1,13 +0,0 @@ -using IOLinkNET.IODD.Resolution; - -namespace IOLinkNET.Conversion; - -public class IoddConverter : IIoddDataConverter -{ - public object Convert(ParsableDatatype datatypeDef, ReadOnlySpan data) => datatypeDef switch - { - ParsableComplexDataTypeDef complexType => IoddComplexConverter.Convert(complexType, data), - ParsableSimpleDatatypeDef simpleType => IoddScalarReader.Convert(simpleType, data), - _ => throw new NotImplementedException() - }; -} \ No newline at end of file diff --git a/src/Conversion/IoddScalarWriter.cs b/src/Conversion/IoddScalarWriter.cs deleted file mode 100644 index c0eb47f..0000000 --- a/src/Conversion/IoddScalarWriter.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Buffers.Binary; -using System.Numerics; -using System.Text; - -using Conversion.Extensions; - -using IOLinkNET.IODD.Resolution; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace Conversion; - -public class IoddScalarWriter -{ - public static byte[] Write(ParsableSimpleDatatypeDef typeDef, object value) - => typeDef switch - { - { Datatype: KindOfSimpleType.Boolean } => BitConverter.GetBytes((bool)value), - { Datatype: KindOfSimpleType.Float } => WriteFloat(value), - { Datatype: KindOfSimpleType.UInteger } => WriteUInt(value, typeDef.Length), - { Datatype: KindOfSimpleType.Integer } => WriteInt(value, typeDef.Length), - { Datatype: KindOfSimpleType.OctetString } => Convert.FromHexString((string)value), - ParsableStringDef s => WriteString(s, (string)value), - _ => throw new NotImplementedException() - }; - - private static byte[] WriteUInt(object value, ushort bitLength) - => bitLength switch - { - <= 2 => throw new ArgumentOutOfRangeException(nameof(bitLength), bitLength, "Invalid bitLength for UInt -> byte[] write"), - <= 16 => WriteInt(value, bitLength, Convert.ToUInt16), - <= 32 => WriteInt(value, bitLength, Convert.ToUInt32), - <= 64 => WriteInt(value, bitLength, Convert.ToUInt64), - _ => throw new ArgumentOutOfRangeException(nameof(bitLength), bitLength, "Invalid bitLength for UInt -> byte[] write") - }; - - private static byte[] WriteInt(object value, ushort bitLength) - => bitLength switch - { - <= 2 => throw new ArgumentOutOfRangeException(nameof(bitLength), bitLength, "Invalid bitLength for Int -> byte[] write"), - <= 16 => WriteInt(value, bitLength, Convert.ToInt16), - <= 32 => WriteInt(value, bitLength, Convert.ToInt32), - <= 64 => WriteInt(value, bitLength, Convert.ToInt64), - _ => throw new ArgumentOutOfRangeException(nameof(bitLength), bitLength, "Invalid bitLength for Int -> byte[] write") - }; - - private static byte[] WriteString(ParsableStringDef stringDef, string value) - => stringDef.Encoding switch - { - StringTEncoding.ASCII => Encoding.ASCII.GetBytes(value), - StringTEncoding.UTF8 => Encoding.UTF8.GetBytes(value), - _ => throw new NotImplementedException($"Encoding {stringDef.Encoding} is not supported.") - }; - - private static byte[] WriteFloat(object value) - { - var bytes = new byte[4]; - BinaryPrimitives.WriteSingleBigEndian(bytes, (float)value); - return bytes; - } - - private static byte[] WriteInt(object value, ushort bitLength, Func conversionFunc) where R : IBinaryInteger - { - R val = conversionFunc(value); - byte[] bytes = new byte[val.GetByteCount()]; - val.WriteBigEndian(bytes); - - byte[] limitedBytes = bytes.TruncateToBitLength(bitLength); - return R.IsNegative(val) ? limitedBytes.PinNegativeIntToRequiredBitLength(bitLength) : limitedBytes; - } -} \ No newline at end of file diff --git a/src/Device/Contract/IMasterConnection.cs b/src/Device/Contract/IMasterConnection.cs deleted file mode 100644 index 592b528..0000000 --- a/src/Device/Contract/IMasterConnection.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace IOLinkNET.Device.Contract; - -public interface IMasterConnection -{ - Task GetPortCountAsync(CancellationToken cancellationToken = default); - - Task GetPortInformationAsync(byte portNumber, CancellationToken cancellationToken = default); - - Task GetPortInformationsAsync(CancellationToken cancellationToken = default); - - Task> ReadIndexAsync(byte portNumber, ushort index, byte subIindex = 0, CancellationToken cancellationToken = default); - - Task> ReadProcessDataInAsync(byte portNumber, CancellationToken cancellationToken = default); - - Task> ReadProcessDataOutAsync(byte portNumber, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/Device/IOLinkNET.Device.csproj b/src/Device/IOLinkNET.Device.csproj deleted file mode 100644 index 6b86efe..0000000 --- a/src/Device/IOLinkNET.Device.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - IOLinkNET.Device - 0.1.0.0 - 0.1.0.0 - 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 - 0.1.0 - - - LICENSE - README.md - - - - - - \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d4de15f..3206055 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,9 +1,17 @@ - net8.0 + net7.0;net8.0;net9.0 enable enable + + + + 11.0 + + + 12.0 + 0.1.0 diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 5260d29..66a4278 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -3,12 +3,12 @@ true - - - - - + + + + + - + \ No newline at end of file diff --git a/src/IODD.Parser/Helpers/XElementExtensions.cs b/src/IODD.Parser/Helpers/XElementExtensions.cs deleted file mode 100644 index 5a06383..0000000 --- a/src/IODD.Parser/Helpers/XElementExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Xml.Linq; - -namespace IOLinkNET.IODD.Helpers; - -internal static class XElementExtensions -{ - public static T ReadMandatoryAttribute(this XElement element, string attributeName) - where T : IParsable - { - string value = element.ReadMandatoryAttribute(attributeName); - return T.Parse(value, null); - } - - public static string ReadMandatoryAttribute(this XElement element, string attributeName, XNamespace? xmlNamespace = null) - { - XName fqName = xmlNamespace is not null ? xmlNamespace.GetName(attributeName) : attributeName; - - XAttribute attribute = element.Attribute(fqName) ?? throw new ArgumentOutOfRangeException($"{attributeName} does not exist on this element"); - return attribute.Value; - } - - public static string? ReadOptionalAttribute(this XElement element, string attributeName) - { - XAttribute? attribute = element.Attribute(element.Name + attributeName) - ?? element.Attribute(attributeName); - return attribute?.Value; - } - - public static T? ReadOptionalAttribute(this XElement element, string attributeName) - where T : IParsable - { - string? value = element.ReadOptionalAttribute(attributeName); - return value is not null ? T.Parse(value, null) : default; - } -} \ No newline at end of file diff --git a/src/IODD.Parser/IODDParserConstants.cs b/src/IODD.Parser/IODDParserConstants.cs deleted file mode 100644 index 2ecbd40..0000000 --- a/src/IODD.Parser/IODDParserConstants.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Standard.Constants; - -namespace IOLinkNET.IODD; - -internal class IODDParserConstants -{ - public static readonly XNamespace XSIXmlNamespace = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance"); - public static readonly XName DeviceIdentityName = IODDConstants.IODDXmlNamespace.GetName("DeviceIdentity"); - - public static readonly XName DeviceFunctionName = IODDConstants.IODDXmlNamespace.GetName("DeviceFunction"); - - public static readonly XName ExternalTextCollectionName = IODDConstants.IODDXmlNamespace.GetName("ExternalTextCollection"); - - public static readonly XName DatatypeCollectionName = IODDConstants.IODDXmlNamespace.GetName("DatatypeCollection"); - - public static readonly XName DatatypeName = IODDConstants.IODDXmlNamespace.GetName("Datatype"); - - public static readonly XName DatatypeRefName = IODDConstants.IODDXmlNamespace.GetName("DatatypeRef"); - - public static readonly XName SimpleDatatypeName = IODDConstants.IODDXmlNamespace.GetName("SimpleDatatype"); - - public static readonly XName SingleValueName = IODDConstants.IODDXmlNamespace.GetName("SingleValue"); -} \ No newline at end of file diff --git a/src/IODD.Parser/Parts/Datatypes/ArrayTParser.cs b/src/IODD.Parser/Parts/Datatypes/ArrayTParser.cs deleted file mode 100644 index cc8d3eb..0000000 --- a/src/IODD.Parser/Parts/Datatypes/ArrayTParser.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class ArrayTParser -{ - public static ArrayT Parse(XElement elem, IParserPartLocator parserLocator, byte? fixedLengthRestriction = null) - { - string? id = elem.ReadOptionalAttribute("id"); - byte count = fixedLengthRestriction ?? elem.ReadMandatoryAttribute("count"); - bool subindexAccessSupported = elem.ReadOptionalAttribute("subindexAccessSupported"); - DatatypeRefT? typeRef = parserLocator.ParseOptional(elem.Descendants(IODDParserConstants.DatatypeRefName).FirstOrDefault()); - - return new ArrayT(id, count, SimpleTypeParser.Parse(elem.Descendants(IODDParserConstants.SimpleDatatypeName).FirstOrDefault()), typeRef, subindexAccessSupported); - } -} \ No newline at end of file diff --git a/src/IODD.Parser/Parts/Datatypes/SimpleTypeParser.cs b/src/IODD.Parser/Parts/Datatypes/SimpleTypeParser.cs deleted file mode 100644 index e0ab594..0000000 --- a/src/IODD.Parser/Parts/Datatypes/SimpleTypeParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parser.Parts.Datatypes; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class SimpleTypeParser -{ - public static SimpleDatatypeT? Parse(string typeName, XElement dataTypeElement, byte? fixedLengthRestriction = null) - => typeName switch - { - DatatypeNames.BooleanT => BooleanTParser.Parse(dataTypeElement), - DatatypeNames.IntegerT => IntegerTParser.ParseInt(dataTypeElement), - DatatypeNames.UIntegerT => IntegerTParser.ParseUInt(dataTypeElement), - DatatypeNames.StringT => StringTParser.Parse(dataTypeElement, fixedLengthRestriction), - DatatypeNames.Float32T => Float32TParser.Parse(dataTypeElement), - DatatypeNames.OctetStringT => OctetStringTParser.Parse(dataTypeElement, fixedLengthRestriction), - _ => null - }; - - public static SimpleDatatypeT? Parse(XElement? dataTypeElement) - => dataTypeElement is null ? null : Parse(dataTypeElement.ReadMandatoryAttribute("type", IODDParserConstants.XSIXmlNamespace), dataTypeElement); - -} \ No newline at end of file diff --git a/src/IODD.Parser/Parts/DeviceFunction/ProcessDataItemTParser.cs b/src/IODD.Parser/Parts/DeviceFunction/ProcessDataItemTParser.cs deleted file mode 100644 index 26b59e6..0000000 --- a/src/IODD.Parser/Parts/DeviceFunction/ProcessDataItemTParser.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; -using IOLinkNET.IODD.Parts.Datatypes; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.ProcessData; - -namespace IOLinkNET.IODD.Parts.DeviceFunction; - -internal class ProcessDataItemParser : IParserPart -{ - private static readonly IEnumerable Names = new[] { IODDDeviceFunctionNames.ProcessDataInName, IODDDeviceFunctionNames.ProcessDataOutName }; - private readonly IParserPartLocator _parserLocator; - - public ProcessDataItemParser(IParserPartLocator parserLocator) - { - _parserLocator = parserLocator; - } - - public bool CanParse(XName name) - => Names.Contains(name); - - public ProcessDataItemT Parse(XElement element) - { - DatatypeT? datatypeT = DatatypeTParser.ParseOptional(element.Descendants(IODDParserConstants.DatatypeName).FirstOrDefault(), _parserLocator); - DatatypeRefT? datatypeRef = _parserLocator.ParseOptional(element.Descendants(IODDParserConstants.DatatypeRefName).FirstOrDefault()); - var id = element.ReadMandatoryAttribute("id"); - ushort bitLength = element.ReadMandatoryAttribute("bitLength"); - - return new ProcessDataItemT(datatypeT, datatypeRef, id, bitLength); - } -} \ No newline at end of file diff --git a/src/IODD.Resolution/Model/ResolvedCondition.cs b/src/IODD.Resolution/Model/ResolvedCondition.cs deleted file mode 100644 index 8710403..0000000 --- a/src/IODD.Resolution/Model/ResolvedCondition.cs +++ /dev/null @@ -1,7 +0,0 @@ - -using IOLinkNET.IODD.Structure.DeviceFunction; -using IOLinkNET.IODD.Structure.ProcessData; - -namespace IOLinkNET.IODD.Resolution; - -public record ResolvedCondition(ConditionT ConditionDef, VariableT VariableDef); \ No newline at end of file diff --git a/src/IODD.Standard/IOLinkNET.IODD.Standard.csproj b/src/IODD.Standard/IOLinkNET.IODD.Standard.csproj deleted file mode 100644 index 3cc3797..0000000 --- a/src/IODD.Standard/IOLinkNET.IODD.Standard.csproj +++ /dev/null @@ -1,34 +0,0 @@ - - - IOLinkNET.IODD.Standard - 0.1.0.0 - 0.1.0.0 - 0.1.0 - - - LICENSE - README.md - IOLinkNET is a library allows you to rapidly integrate and interact with devices that are using the IO-Link technology. - https://github.com/domdeger/IOLink.NET/ - https://github.com/domdeger/IOLink.NET/ - Github - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - - \ No newline at end of file diff --git a/src/IODD.Standard/Structure/StandardDefinitionReader.cs b/src/IODD.Standard/Structure/StandardDefinitionReader.cs deleted file mode 100644 index ad04e26..0000000 --- a/src/IODD.Standard/Structure/StandardDefinitionReader.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Standard.Constants; - -namespace IOLinkNET.IODD.Standard.Structure; -public static class StandardDefinitionReader -{ - private static readonly XElement _ioddStandardDefinitions; - - static StandardDefinitionReader() - { - var standardDefinitionPath = "./XML/IODD-StandardDefinitions1.1.xml"; - - if (!File.Exists(standardDefinitionPath)) - { - throw new FileNotFoundException($"IODD-StandardDefinitions1.1.xml must be present to use {nameof(StandardDefinitionReader)}"); - } - - using (var reader = new StreamReader(standardDefinitionPath)) - { - _ioddStandardDefinitions = XElement.Load(reader); - } - } - - public static XElement GetVariableCollection() - { - var variableCollection = _ioddStandardDefinitions.Elements(IODDStandardDefinitionNames.VariableCollectionName).Single(); - return variableCollection ?? throw new InvalidOperationException("VariableCollection cannot be null in standard definitions"); - } - - public static XElement GetDatatypeCollection() - { - var dataTypeCollection = _ioddStandardDefinitions.Elements(IODDStandardDefinitionNames.DatatypeCollectionName).Single(); - return dataTypeCollection ?? throw new InvalidOperationException("DatatypeCollection cannot be null in standard definitions"); - } -} diff --git a/src/IODD.Structure/Interfaces/ExternalTextCollection/IExternalTextCollectionT.cs b/src/IODD.Structure/Interfaces/ExternalTextCollection/IExternalTextCollectionT.cs deleted file mode 100644 index 1c703d8..0000000 --- a/src/IODD.Structure/Interfaces/ExternalTextCollection/IExternalTextCollectionT.cs +++ /dev/null @@ -1,9 +0,0 @@ -using IOLinkNET.IODD.Structure.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Structure.ExternalTextCollection; - -namespace IOLinkNET.IODD.Structure.Interfaces.ExternalTextCollection; -public interface IExternalTextCollectionT -{ - PrimaryLanguageT PrimaryLanguage { get; } - IEnumerable TextDefinitions { get; } -} diff --git a/src/IODD.Structure/Interfaces/IDatatypeOrTypeRef.cs b/src/IODD.Structure/Interfaces/IDatatypeOrTypeRef.cs deleted file mode 100644 index 8390afb..0000000 --- a/src/IODD.Structure/Interfaces/IDatatypeOrTypeRef.cs +++ /dev/null @@ -1,10 +0,0 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Structure.Interfaces; - -public interface IDatatypeOrTypeRef -{ - DatatypeT? Type { get; } - DatatypeRefT? Ref { get; } -} \ No newline at end of file diff --git a/src/IODD.Structure/Interfaces/IIODevice.cs b/src/IODD.Structure/Interfaces/IIODevice.cs deleted file mode 100644 index e0d261c..0000000 --- a/src/IODD.Structure/Interfaces/IIODevice.cs +++ /dev/null @@ -1,13 +0,0 @@ -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Interfaces.ExternalTextCollection; -using IOLinkNET.IODD.Structure.Interfaces.Profile; -using IOLinkNET.IODD.Structure.Profile; -using IOLinkNET.IODD.Structure.Structure.ExternalTextCollection; - -namespace IOLinkNET.IODD.Structure.Interfaces; -public interface IIODevice -{ - IProfileBodyT ProfileBody { get; } - IExternalTextCollectionT ExternalTextCollection { get; } - IEnumerable StandardDatatypeCollection { get; } -} diff --git a/src/IODD.Structure/Structure/Common/DatatypeRefT.cs b/src/IODD.Structure/Structure/Common/DatatypeRefT.cs deleted file mode 100644 index d6303cb..0000000 --- a/src/IODD.Structure/Structure/Common/DatatypeRefT.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Common; - -public record DatatypeRefT(string DatatypeId); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Common/TextRefT.cs b/src/IODD.Structure/Structure/Common/TextRefT.cs deleted file mode 100644 index 700b82a..0000000 --- a/src/IODD.Structure/Structure/Common/TextRefT.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Common; - -public record TextRefT(string TextId); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Datatypes/AbstractValueT.cs b/src/IODD.Structure/Structure/Datatypes/AbstractValueT.cs deleted file mode 100644 index a979fa8..0000000 --- a/src/IODD.Structure/Structure/Datatypes/AbstractValueT.cs +++ /dev/null @@ -1,4 +0,0 @@ -using IOLinkNET.IODD.Structure.Common; -namespace IOLinkNET.IODD.Structure.Datatypes; - -public abstract record AbstractValueT(TextRefT? Name); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Datatypes/BooleanT.cs b/src/IODD.Structure/Structure/Datatypes/BooleanT.cs deleted file mode 100644 index ec24d14..0000000 --- a/src/IODD.Structure/Structure/Datatypes/BooleanT.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record BooleanT(string? Id, IEnumerable> SingleValues) : SimpleDatatypeT(Id); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Datatypes/ComplexDatatypeT.cs b/src/IODD.Structure/Structure/Datatypes/ComplexDatatypeT.cs deleted file mode 100644 index 579781d..0000000 --- a/src/IODD.Structure/Structure/Datatypes/ComplexDatatypeT.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public abstract record ComplexDatatypeT(string? Id, bool SubindexAccessSupported = true) : DatatypeT(Id); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Datatypes/DatatypeT.cs b/src/IODD.Structure/Structure/Datatypes/DatatypeT.cs deleted file mode 100644 index 9c5307f..0000000 --- a/src/IODD.Structure/Structure/Datatypes/DatatypeT.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public abstract record DatatypeT(string? Id); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Datatypes/ProcessDataInUnionT.cs b/src/IODD.Structure/Structure/Datatypes/ProcessDataInUnionT.cs deleted file mode 100644 index 7cd05d0..0000000 --- a/src/IODD.Structure/Structure/Datatypes/ProcessDataInUnionT.cs +++ /dev/null @@ -1,5 +0,0 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Structure.Structure.Datatypes; -public record ProcessDataInUnionT(string Id, SimpleDatatypeT? Type, DatatypeRefT? Ref) : ProcessDataUnionT(Id, Type, Ref); diff --git a/src/IODD.Structure/Structure/Datatypes/ProcessDataOutUnionT.cs b/src/IODD.Structure/Structure/Datatypes/ProcessDataOutUnionT.cs deleted file mode 100644 index 0ebeec4..0000000 --- a/src/IODD.Structure/Structure/Datatypes/ProcessDataOutUnionT.cs +++ /dev/null @@ -1,5 +0,0 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Structure.Structure.Datatypes; -public record ProcessDataOutUnionT(string Id, SimpleDatatypeT? Type, DatatypeRefT? Ref) : ProcessDataUnionT(Id, Type, Ref); diff --git a/src/IODD.Structure/Structure/Datatypes/ProcessDataUnionT.cs b/src/IODD.Structure/Structure/Datatypes/ProcessDataUnionT.cs deleted file mode 100644 index 5c4e849..0000000 --- a/src/IODD.Structure/Structure/Datatypes/ProcessDataUnionT.cs +++ /dev/null @@ -1,9 +0,0 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Interfaces; - -namespace IOLinkNET.IODD.Structure.Structure.Datatypes; -public record ProcessDataUnionT(string? Id, SimpleDatatypeT? Type, DatatypeRefT? Ref) : DatatypeT(Id), IDatatypeOrTypeRef -{ - DatatypeT? IDatatypeOrTypeRef.Type => Type; -} diff --git a/src/IODD.Structure/Structure/Datatypes/SingleValueT.cs b/src/IODD.Structure/Structure/Datatypes/SingleValueT.cs deleted file mode 100644 index 32b7d1b..0000000 --- a/src/IODD.Structure/Structure/Datatypes/SingleValueT.cs +++ /dev/null @@ -1,5 +0,0 @@ -using IOLinkNET.IODD.Structure.Common; - -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record SingleValueT(T LowerValue, T UpperValue, TextRefT? Name) : AbstractValueT(Name) where T : struct; \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Datatypes/TextDefinitionT.cs b/src/IODD.Structure/Structure/Datatypes/TextDefinitionT.cs deleted file mode 100644 index 0498a66..0000000 --- a/src/IODD.Structure/Structure/Datatypes/TextDefinitionT.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Structure.Datatypes; -public record TextDefinitionT(string Id, string Value); diff --git a/src/IODD.Structure/Structure/Datatypes/TimeT.cs b/src/IODD.Structure/Structure/Datatypes/TimeT.cs deleted file mode 100644 index 9318507..0000000 --- a/src/IODD.Structure/Structure/Datatypes/TimeT.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record TimeT(string? Id) : SimpleDatatypeT(Id); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Datatypes/TimespanT.cs b/src/IODD.Structure/Structure/Datatypes/TimespanT.cs deleted file mode 100644 index ff2333b..0000000 --- a/src/IODD.Structure/Structure/Datatypes/TimespanT.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record TimeSpanT(string? Id) : SimpleDatatypeT(Id); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Datatypes/ValueRangeT.cs b/src/IODD.Structure/Structure/Datatypes/ValueRangeT.cs deleted file mode 100644 index 8907984..0000000 --- a/src/IODD.Structure/Structure/Datatypes/ValueRangeT.cs +++ /dev/null @@ -1,5 +0,0 @@ -using IOLinkNET.IODD.Structure.Common; - -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record ValueRangeT(T LowerValue, T UpperValue, TextRefT? Name) : AbstractValueT(Name) where T : struct; \ No newline at end of file diff --git a/src/IODD.Structure/Structure/DeviceFunction/StdVariableRefT.cs b/src/IODD.Structure/Structure/DeviceFunction/StdVariableRefT.cs deleted file mode 100644 index 56542a3..0000000 --- a/src/IODD.Structure/Structure/DeviceFunction/StdVariableRefT.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace IOLinkNET.IODD.Structure.DeviceFunction; - -public record StdVariableRefT(string Id, uint FixedLengthRestriction, string defaultValue); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/ExternalTextCollection/ExternalTextCollectionT.cs b/src/IODD.Structure/Structure/ExternalTextCollection/ExternalTextCollectionT.cs deleted file mode 100644 index c9198f5..0000000 --- a/src/IODD.Structure/Structure/ExternalTextCollection/ExternalTextCollectionT.cs +++ /dev/null @@ -1,5 +0,0 @@ -using IOLinkNET.IODD.Structure.Interfaces.ExternalTextCollection; -using IOLinkNET.IODD.Structure.Structure.Datatypes; - -namespace IOLinkNET.IODD.Structure.Structure.ExternalTextCollection; -public record ExternalTextCollectionT(PrimaryLanguageT PrimaryLanguage, IEnumerable TextDefinitions): IExternalTextCollectionT; diff --git a/src/IODD.Structure/Structure/ExternalTextCollection/PrimaryLanguageT.cs b/src/IODD.Structure/Structure/ExternalTextCollection/PrimaryLanguageT.cs deleted file mode 100644 index 322512c..0000000 --- a/src/IODD.Structure/Structure/ExternalTextCollection/PrimaryLanguageT.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Structure.ExternalTextCollection; -public record PrimaryLanguageT(string LanguageCode); diff --git a/src/IODD.Structure/Structure/IODevice.cs b/src/IODD.Structure/Structure/IODevice.cs deleted file mode 100644 index 293d6ea..0000000 --- a/src/IODD.Structure/Structure/IODevice.cs +++ /dev/null @@ -1,8 +0,0 @@ -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Interfaces; -using IOLinkNET.IODD.Structure.Interfaces.ExternalTextCollection; -using IOLinkNET.IODD.Structure.Interfaces.Profile; - -namespace IOLinkNET.IODD.Structure; - -public record IODevice(IProfileBodyT ProfileBody, IExternalTextCollectionT ExternalTextCollection, IEnumerable StandardDatatypeCollection): IIODevice; \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Menu/MenuCollectionT.cs b/src/IODD.Structure/Structure/Menu/MenuCollectionT.cs deleted file mode 100644 index a3451c9..0000000 --- a/src/IODD.Structure/Structure/Menu/MenuCollectionT.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Structure.Menu; -public record MenuCollectionT(MenuT Menu); diff --git a/src/IODD.Structure/Structure/Menu/MenuItemRefT.cs b/src/IODD.Structure/Structure/Menu/MenuItemRefT.cs deleted file mode 100644 index 4b3c28c..0000000 --- a/src/IODD.Structure/Structure/Menu/MenuItemRefT.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace IOLinkNET.IODD.Structure.Structure.Menu; -public record MenuItemRefT(string Id, string? Name); diff --git a/src/IODD.Structure/Structure/ProcessData/ProcessDataItemT.cs b/src/IODD.Structure/Structure/ProcessData/ProcessDataItemT.cs deleted file mode 100644 index e4c67b9..0000000 --- a/src/IODD.Structure/Structure/ProcessData/ProcessDataItemT.cs +++ /dev/null @@ -1,10 +0,0 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Interfaces; - -namespace IOLinkNET.IODD.Structure.ProcessData; - -public record ProcessDataItemT(DatatypeT? Datatype, DatatypeRefT? Ref, string Id, ushort BitLength) : IDatatypeOrTypeRef -{ - public DatatypeT? Type => Datatype; -} diff --git a/src/IODD.Structure/Structure/ProcessData/ProcessDataT.cs b/src/IODD.Structure/Structure/ProcessData/ProcessDataT.cs deleted file mode 100644 index 2dff16c..0000000 --- a/src/IODD.Structure/Structure/ProcessData/ProcessDataT.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace IOLinkNET.IODD.Structure.ProcessData; - -public record ProcessDataT(ConditionT? Condition, ProcessDataItemT? ProcessDataIn, ProcessDataItemT? ProcessDataOut); \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Profile/DeviceFunctionT.cs b/src/IODD.Structure/Structure/Profile/DeviceFunctionT.cs deleted file mode 100644 index e70e7c9..0000000 --- a/src/IODD.Structure/Structure/Profile/DeviceFunctionT.cs +++ /dev/null @@ -1,9 +0,0 @@ -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.DeviceFunction; -using IOLinkNET.IODD.Structure.Interfaces.Menu; -using IOLinkNET.IODD.Structure.Interfaces.Profile; -using IOLinkNET.IODD.Structure.ProcessData; - -namespace IOLinkNET.IODD.Structure.Profile; - -public record DeviceFunctionT(IEnumerable DatatypeCollection, IEnumerable VariableCollection, IEnumerable ProcessDataCollection, IUserInterfaceT UserInterface): IDeviceFunctionT; \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Profile/DeviceIdentity.cs b/src/IODD.Structure/Structure/Profile/DeviceIdentity.cs deleted file mode 100644 index c73076b..0000000 --- a/src/IODD.Structure/Structure/Profile/DeviceIdentity.cs +++ /dev/null @@ -1,6 +0,0 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Interfaces.Profile; - -namespace IOLinkNET.IODD.Structure.Profile; - -public record DeviceIdentityT(ushort VendorId, uint DeviceId, string VendorName, TextRefT VendorText, TextRefT VendorUrl, TextRefT DeviceName, TextRefT DeviceFamily): IDeviceIdentityT; \ No newline at end of file diff --git a/src/IODD.Structure/Structure/Profile/ProfileBodyT.cs b/src/IODD.Structure/Structure/Profile/ProfileBodyT.cs deleted file mode 100644 index 59429f7..0000000 --- a/src/IODD.Structure/Structure/Profile/ProfileBodyT.cs +++ /dev/null @@ -1,5 +0,0 @@ -using IOLinkNET.IODD.Structure.Interfaces.Profile; - -namespace IOLinkNET.IODD.Structure.Profile; - -public record ProfileBodyT(IDeviceIdentityT DeviceIdentity, IDeviceFunctionT DeviceFunction): IProfileBodyT; \ No newline at end of file diff --git a/src/IOLink.NET.Core/Contracts/IDeviceDefinitionProvider.cs b/src/IOLink.NET.Core/Contracts/IDeviceDefinitionProvider.cs new file mode 100644 index 0000000..c411730 --- /dev/null +++ b/src/IOLink.NET.Core/Contracts/IDeviceDefinitionProvider.cs @@ -0,0 +1,13 @@ +namespace IOLink.NET.Core.Contracts; + +// Forward declaration - IODevice will be defined in IOLink.NET.IODD +// This interface provides abstraction for device definition providers +public interface IDeviceDefinitionProvider +{ + Task GetDeviceDefinitionAsync( + ushort vendorId, + uint deviceId, + string productId, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Device/Contract/IDeviceInformation.cs b/src/IOLink.NET.Core/Contracts/IDeviceInformation.cs similarity index 79% rename from src/Device/Contract/IDeviceInformation.cs rename to src/IOLink.NET.Core/Contracts/IDeviceInformation.cs index a5a698b..686ed36 100644 --- a/src/Device/Contract/IDeviceInformation.cs +++ b/src/IOLink.NET.Core/Contracts/IDeviceInformation.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.Device.Contract; +namespace IOLink.NET.Core.Contracts; public interface IDeviceInformation { @@ -7,5 +7,4 @@ public interface IDeviceInformation public uint DeviceId { get; } public string ProductId { get; } - -} \ No newline at end of file +} diff --git a/src/IOLink.NET.Core/Contracts/IIODDProvider.cs b/src/IOLink.NET.Core/Contracts/IIODDProvider.cs new file mode 100644 index 0000000..9bc8ce6 --- /dev/null +++ b/src/IOLink.NET.Core/Contracts/IIODDProvider.cs @@ -0,0 +1,11 @@ +namespace IOLink.NET.Core.Contracts; + +public interface IIODDProvider +{ + Task GetIODDPackageAsync( + ushort vendorId, + uint deviceId, + string productId, + CancellationToken cancellationToken = default + ); +} diff --git a/src/IOLink.NET.Core/Contracts/IMasterConnection.cs b/src/IOLink.NET.Core/Contracts/IMasterConnection.cs new file mode 100644 index 0000000..3c69cd2 --- /dev/null +++ b/src/IOLink.NET.Core/Contracts/IMasterConnection.cs @@ -0,0 +1,32 @@ +namespace IOLink.NET.Core.Contracts; + +public interface IMasterConnection +{ + Task GetPortCountAsync(CancellationToken cancellationToken = default); + + Task GetPortInformationAsync( + byte portNumber, + CancellationToken cancellationToken = default + ); + + Task GetPortInformationsAsync( + CancellationToken cancellationToken = default + ); + + Task> ReadIndexAsync( + byte portNumber, + ushort index, + byte subIindex = 0, + CancellationToken cancellationToken = default + ); + + Task> ReadProcessDataInAsync( + byte portNumber, + CancellationToken cancellationToken = default + ); + + Task> ReadProcessDataOutAsync( + byte portNumber, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Device/Contract/IPortInformation.cs b/src/IOLink.NET.Core/Contracts/IPortInformation.cs similarity index 79% rename from src/Device/Contract/IPortInformation.cs rename to src/IOLink.NET.Core/Contracts/IPortInformation.cs index b4d18ef..a7c4105 100644 --- a/src/Device/Contract/IPortInformation.cs +++ b/src/IOLink.NET.Core/Contracts/IPortInformation.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.Device.Contract; +namespace IOLink.NET.Core.Contracts; public interface IPortInformation { @@ -7,4 +7,4 @@ public interface IPortInformation byte PortNumber { get; } IDeviceInformation? DeviceInformation { get; } -} \ No newline at end of file +} diff --git a/src/Device/Contract/PortStatus.cs b/src/IOLink.NET.Core/Contracts/PortStatus.cs similarity index 68% rename from src/Device/Contract/PortStatus.cs rename to src/IOLink.NET.Core/Contracts/PortStatus.cs index e1d98c4..808772a 100644 --- a/src/Device/Contract/PortStatus.cs +++ b/src/IOLink.NET.Core/Contracts/PortStatus.cs @@ -1,3 +1,5 @@ +namespace IOLink.NET.Core.Contracts; + [Flags] public enum PortStatus : byte { @@ -5,5 +7,5 @@ public enum PortStatus : byte Connected = 1, IOLink = 2, Error = 4, - DI = 8 -} \ No newline at end of file + DI = 8, +} diff --git a/src/IOLink.NET.Core/Extensions/ByteArrayExtensions.cs b/src/IOLink.NET.Core/Extensions/ByteArrayExtensions.cs new file mode 100644 index 0000000..2d7eecf --- /dev/null +++ b/src/IOLink.NET.Core/Extensions/ByteArrayExtensions.cs @@ -0,0 +1,27 @@ +namespace IOLink.NET.Core.Extensions; + +public static class ByteArrayExtensions +{ + /// + /// If we have a negative integer, the resulting bytearray will be filled with 1s on the left, that may exceed the given bit length. + /// This method will set the first (8 - bitLength % 8) bits to 0. + /// Requires big-endian byte array. + /// + public static byte[] PinNegativeIntToRequiredBitLength(this byte[] data, ushort bitLength) + { + if (bitLength % 8 == 0) + { + // In this case we have a full byte and don't need to pin anything + return data; + } + var mask = (byte)(-1 << bitLength % 8); + data[0] ^= mask; + return data; + } + + public static byte[] TruncateToBitLength(this byte[] data, ushort bitLength) + { + var requiredByteLength = bitLength / 8 + (bitLength % 8 != 0 ? 1 : 0); + return data[(data.Length - requiredByteLength)..]; + } +} diff --git a/src/IODD.Structure/IOLinkNET.IODD.Structure.csproj b/src/IOLink.NET.Core/IOLink.NET.Core.csproj similarity index 60% rename from src/IODD.Structure/IOLinkNET.IODD.Structure.csproj rename to src/IOLink.NET.Core/IOLink.NET.Core.csproj index c0d46ce..52e8a7e 100644 --- a/src/IODD.Structure/IOLinkNET.IODD.Structure.csproj +++ b/src/IOLink.NET.Core/IOLink.NET.Core.csproj @@ -1,6 +1,6 @@ - + - IOLinkNET.IODD.Structure + IOLink.NET.Core 0.1.0.0 0.1.0.0 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 @@ -9,13 +9,13 @@ LICENSE README.md - IOLinkNET is a library allows you to rapidly integrate and interact with devices that are using the IO-Link technology. - https://github.com/domdeger/IOLink.NET/ + IOLink.NET Core - Contains core contracts and models for the IO-Link technology. + https://github.com/domdeger/IOLink.NET/ https://github.com/domdeger/IOLink.NET/ Github - - + + - \ No newline at end of file + diff --git a/src/Device/Model/DeviceInformation.cs b/src/IOLink.NET.Core/Models/DeviceInformation.cs similarity index 83% rename from src/Device/Model/DeviceInformation.cs rename to src/IOLink.NET.Core/Models/DeviceInformation.cs index 1d6f343..dab84e5 100644 --- a/src/Device/Model/DeviceInformation.cs +++ b/src/IOLink.NET.Core/Models/DeviceInformation.cs @@ -1,6 +1,6 @@ -using IOLinkNET.Device.Contract; +using IOLink.NET.Core.Contracts; -namespace IOLinkNET.Device.Model; +namespace IOLink.NET.Core.Models; public class DeviceInformation : IDeviceInformation { @@ -11,10 +11,9 @@ public DeviceInformation(ushort VendorId, uint DeviceId, string ProductId) this.ProductId = ProductId; } - public ushort VendorId { get; } public uint DeviceId { get; } public string ProductId { get; } -} \ No newline at end of file +} diff --git a/src/Device/Model/PortInformation.cs b/src/IOLink.NET.Core/Models/PortInformation.cs similarity index 60% rename from src/Device/Model/PortInformation.cs rename to src/IOLink.NET.Core/Models/PortInformation.cs index aa51e1e..c2f5d25 100644 --- a/src/Device/Model/PortInformation.cs +++ b/src/IOLink.NET.Core/Models/PortInformation.cs @@ -1,10 +1,14 @@ -using IOLinkNET.Device.Contract; +using IOLink.NET.Core.Contracts; -namespace IOLinkNET.Device.Model; +namespace IOLink.NET.Core.Models; public class PortInformation : IPortInformation { - public PortInformation(byte portNumber, PortStatus status, IDeviceInformation? deviceInformation) + public PortInformation( + byte portNumber, + PortStatus status, + IDeviceInformation? deviceInformation + ) { PortNumber = portNumber; Status = status; @@ -16,4 +20,4 @@ public PortInformation(byte portNumber, PortStatus status, IDeviceInformation? d public byte PortNumber { get; } public IDeviceInformation? DeviceInformation { get; } -} \ No newline at end of file +} diff --git a/src/IODD.Provider/IOLinkNET.IODD.Provider.csproj b/src/IOLink.NET.IODD/IOLink.NET.IODD.csproj similarity index 51% rename from src/IODD.Provider/IOLinkNET.IODD.Provider.csproj rename to src/IOLink.NET.IODD/IOLink.NET.IODD.csproj index 121d3ab..9ae05ef 100644 --- a/src/IODD.Provider/IOLinkNET.IODD.Provider.csproj +++ b/src/IOLink.NET.IODD/IOLink.NET.IODD.csproj @@ -1,20 +1,23 @@ - + + + false + - - + - IOLinkNET.IODD.Provider + IOLink.NET.IODD 0.1.0.0 0.1.0.0 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 0.1.0 + false LICENSE README.md - IOLinkNET is a library allows you to rapidly integrate and interact with devices that are using the IO-Link technology. - https://github.com/domdeger/IOLink.NET/ + IOLink.NET IODD - Complete IODD (IO Device Description) processing library including parsing, resolution, structure definitions and standard definitions. + https://github.com/domdeger/IOLink.NET/ https://github.com/domdeger/IOLink.NET/ Github @@ -22,4 +25,7 @@ - \ No newline at end of file + + + + diff --git a/src/IODD.Parser/Helpers/ParserPartLocatorExtensions.cs b/src/IOLink.NET.IODD/Parser/Helpers/ParserPartLocatorExtensions.cs similarity index 88% rename from src/IODD.Parser/Helpers/ParserPartLocatorExtensions.cs rename to src/IOLink.NET.IODD/Parser/Helpers/ParserPartLocatorExtensions.cs index 0746a83..f8623bd 100644 --- a/src/IODD.Parser/Helpers/ParserPartLocatorExtensions.cs +++ b/src/IOLink.NET.IODD/Parser/Helpers/ParserPartLocatorExtensions.cs @@ -1,22 +1,22 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Parser; - -namespace IOLinkNET.IODD.Helpers -{ - internal static class ParserPartLocatorExtensions - { - public static T? ParseOptional(this IParserPartLocator locator, XElement? element) - where T : class - { - return element is null ? null : locator.Parse(element); - } - - public static T ParseMandatory(this IParserPartLocator locator, XElement? element) - { - return element is null - ? throw new ArgumentNullException(nameof(element)) - : locator.Parse(element) ?? throw new InvalidOperationException("Could not parse the element as expected."); - } - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Parser; + +namespace IOLink.NET.IODD.Helpers +{ + internal static class ParserPartLocatorExtensions + { + public static T? ParseOptional(this IParserPartLocator locator, XElement? element) + where T : class + { + return element is null ? null : locator.Parse(element); + } + + public static T ParseMandatory(this IParserPartLocator locator, XElement? element) + { + return element is null + ? throw new ArgumentNullException(nameof(element)) + : locator.Parse(element) ?? throw new InvalidOperationException("Could not parse the element as expected."); + } + } +} diff --git a/src/IOLink.NET.IODD/Parser/Helpers/XElementExtensions.cs b/src/IOLink.NET.IODD/Parser/Helpers/XElementExtensions.cs new file mode 100644 index 0000000..2483763 --- /dev/null +++ b/src/IOLink.NET.IODD/Parser/Helpers/XElementExtensions.cs @@ -0,0 +1,62 @@ +using System.Xml.Linq; + +namespace IOLink.NET.IODD.Helpers; + +internal static class XElementExtensions +{ + public static T ReadMandatoryAttribute(this XElement element, string attributeName) + where T : IParsable + { + string value = element.ReadMandatoryAttribute(attributeName); + return T.Parse(value, null); + } + + // Overload for string specifically + public static string ReadMandatoryAttributeAsString(this XElement element, string attributeName) + { + return element.ReadMandatoryAttribute(attributeName); + } + + public static string ReadMandatoryAttribute( + this XElement element, + string attributeName, + XNamespace? xmlNamespace = null + ) + { + XName fqName = xmlNamespace is not null + ? xmlNamespace.GetName(attributeName) + : attributeName; + + XAttribute attribute = + element.Attribute(fqName) + ?? throw new ArgumentOutOfRangeException( + $"{attributeName} does not exist on this element" + ); + return attribute.Value; + } + + public static string? ReadOptionalAttribute(this XElement element, string attributeName) + { + XAttribute? attribute = + element.Attribute(element.Name + attributeName) ?? element.Attribute(attributeName); + return attribute?.Value; + } + + public static T? ReadOptionalAttribute(this XElement element, string attributeName) + where T : IParsable + { + string? value = element.ReadOptionalAttribute(attributeName); + return value is not null ? T.Parse(value, null) : default; + } + + // Overload for bool specifically + public static bool ReadOptionalAttributeAsBool( + this XElement element, + string attributeName, + bool defaultValue = false + ) + { + string? value = element.ReadOptionalAttribute(attributeName); + return value is not null ? bool.Parse(value) : defaultValue; + } +} diff --git a/src/IODD.Parser/IODDParser.cs b/src/IOLink.NET.IODD/Parser/IODDParser.cs similarity index 54% rename from src/IODD.Parser/IODDParser.cs rename to src/IOLink.NET.IODD/Parser/IODDParser.cs index 04c7e8a..71595b7 100644 --- a/src/IODD.Parser/IODDParser.cs +++ b/src/IOLink.NET.IODD/Parser/IODDParser.cs @@ -1,53 +1,66 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Parser.Parts.ExternalTextCollection; -using IOLinkNET.IODD.Parser.Parts.Menu; -using IOLinkNET.IODD.Parts; -using IOLinkNET.IODD.Parts.DeviceFunction; -using IOLinkNET.IODD.Standard.Structure; -using IOLinkNET.IODD.Structure; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Profile; -using IOLinkNET.IODD.Structure.Structure.ExternalTextCollection; - -namespace IOLinkNET.IODD; - -public class IODDParser -{ - private readonly IParserPartLocator _partLocator = new ParserPartLocator(); - public IODDParser() - { - _partLocator.AddPart(new DeviceIdentityParser(_partLocator)); - _partLocator.AddPart(new TextRefTParser()); - _partLocator.AddPart(new DatatypeRefTParser()); - _partLocator.AddPart(new DatatypeCollectionTParser(_partLocator)); - _partLocator.AddPart(new ProcessDataParser(_partLocator)); - _partLocator.AddPart(new ProcessDataItemParser(_partLocator)); - _partLocator.AddPart(new ConditionTParser()); - _partLocator.AddPart(new DeviceFunctionTParser(_partLocator)); - _partLocator.AddPart(new VariableTParser(_partLocator)); - _partLocator.AddPart(new MenuCollectionTParser(_partLocator)); - _partLocator.AddPart(new UIMenuRefTParser(_partLocator)); - _partLocator.AddPart(new UserInterfaceParser(_partLocator)); - _partLocator.AddPart(new ExternalTextCollectionTParser()); - } - - public static bool IsIODDFile(XDocument xml) - { - return xml.Descendants().Any(d => d.Name.LocalName == "DeviceIdentity"); - } - - public IODevice Parse(XElement iodd) - { - ExternalTextCollectionT externalTextCollection = _partLocator.Parse(iodd.Descendants(IODDParserConstants.ExternalTextCollectionName).First()); - _partLocator.AddPart(new MenuElementParser(_partLocator, externalTextCollection)); - IEnumerable standardDataTypeCollection = _partLocator.ParseMandatory>(StandardDefinitionReader.GetDatatypeCollection()); - - DeviceIdentityT deviceIdentity = _partLocator.Parse(iodd.Descendants(IODDParserConstants.DeviceIdentityName).First()); - DeviceFunctionT deviceFunction = _partLocator.Parse(iodd.Descendants(IODDParserConstants.DeviceFunctionName).First()); - - return new IODevice(new ProfileBodyT(deviceIdentity, deviceFunction), externalTextCollection, standardDataTypeCollection); - } -} \ No newline at end of file +using System.Xml.Linq; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Parser.Parts.ExternalTextCollection; +using IOLink.NET.IODD.Parser.Parts.Menu; +using IOLink.NET.IODD.Parts; +using IOLink.NET.IODD.Parts.DeviceFunction; +using IOLink.NET.IODD.Standard.Structure; +using IOLink.NET.IODD.Structure; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Profile; +using IOLink.NET.IODD.Structure.Structure.ExternalTextCollection; + +namespace IOLink.NET.IODD.Parser; + +public class IODDParser +{ + private readonly IParserPartLocator _partLocator = new ParserPartLocator(); + + public IODDParser() + { + _partLocator.AddPart(new DeviceIdentityParser(_partLocator)); + _partLocator.AddPart(new TextRefTParser()); + _partLocator.AddPart(new DatatypeRefTParser()); + _partLocator.AddPart(new DatatypeCollectionTParser(_partLocator)); + _partLocator.AddPart(new ProcessDataParser(_partLocator)); + _partLocator.AddPart(new ProcessDataItemParser(_partLocator)); + _partLocator.AddPart(new ConditionTParser()); + _partLocator.AddPart(new DeviceFunctionTParser(_partLocator)); + _partLocator.AddPart(new VariableTParser(_partLocator)); + _partLocator.AddPart(new MenuCollectionTParser(_partLocator)); + _partLocator.AddPart(new UIMenuRefTParser(_partLocator)); + _partLocator.AddPart(new UserInterfaceParser(_partLocator)); + _partLocator.AddPart(new ExternalTextCollectionTParser()); + } + + public static bool IsIODDFile(XDocument xml) + { + return xml.Descendants().Any(d => d.Name.LocalName == "DeviceIdentity"); + } + + public IODevice Parse(XElement iodd) + { + ExternalTextCollectionT externalTextCollection = + _partLocator.Parse( + iodd.Descendants(IODDParserConstants.ExternalTextCollectionName).First() + ); + _partLocator.AddPart(new MenuElementParser(_partLocator, externalTextCollection)); + IEnumerable standardDataTypeCollection = _partLocator.ParseMandatory< + IEnumerable + >(StandardDefinitionReader.GetDatatypeCollection()); + + DeviceIdentityT deviceIdentity = _partLocator.Parse( + iodd.Descendants(IODDParserConstants.DeviceIdentityName).First() + ); + DeviceFunctionT deviceFunction = _partLocator.Parse( + iodd.Descendants(IODDParserConstants.DeviceFunctionName).First() + ); + + return new IODevice( + new ProfileBodyT(deviceIdentity, deviceFunction), + externalTextCollection, + standardDataTypeCollection + ); + } +} diff --git a/src/IOLink.NET.IODD/Parser/IODDParserConstants.cs b/src/IOLink.NET.IODD/Parser/IODDParserConstants.cs new file mode 100644 index 0000000..d0d9d09 --- /dev/null +++ b/src/IOLink.NET.IODD/Parser/IODDParserConstants.cs @@ -0,0 +1,39 @@ +using System.Xml.Linq; +using IOLink.NET.IODD.Standard.Constants; + +namespace IOLink.NET.IODD.Parser; + +internal class IODDParserConstants +{ + public static readonly XNamespace XSIXmlNamespace = XNamespace.Get( + "http://www.w3.org/2001/XMLSchema-instance" + ); + public static readonly XName DeviceIdentityName = IODDConstants.IODDXmlNamespace.GetName( + "DeviceIdentity" + ); + + public static readonly XName DeviceFunctionName = IODDConstants.IODDXmlNamespace.GetName( + "DeviceFunction" + ); + + public static readonly XName ExternalTextCollectionName = + IODDConstants.IODDXmlNamespace.GetName("ExternalTextCollection"); + + public static readonly XName DatatypeCollectionName = IODDConstants.IODDXmlNamespace.GetName( + "DatatypeCollection" + ); + + public static readonly XName DatatypeName = IODDConstants.IODDXmlNamespace.GetName("Datatype"); + + public static readonly XName DatatypeRefName = IODDConstants.IODDXmlNamespace.GetName( + "DatatypeRef" + ); + + public static readonly XName SimpleDatatypeName = IODDConstants.IODDXmlNamespace.GetName( + "SimpleDatatype" + ); + + public static readonly XName SingleValueName = IODDConstants.IODDXmlNamespace.GetName( + "SingleValue" + ); +} diff --git a/src/IODD.Parser/Interface/IParserPart.cs b/src/IOLink.NET.IODD/Parser/Interface/IParserPart.cs similarity index 79% rename from src/IODD.Parser/Interface/IParserPart.cs rename to src/IOLink.NET.IODD/Parser/Interface/IParserPart.cs index ff98df9..79e4de4 100644 --- a/src/IODD.Parser/Interface/IParserPart.cs +++ b/src/IOLink.NET.IODD/Parser/Interface/IParserPart.cs @@ -1,13 +1,13 @@ -using System.Xml.Linq; - -namespace IOLinkNET.IODD.Parser; - -internal interface IParserPart : IParserPart -{ - T Parse(XElement element); -} - -internal interface IParserPart -{ - bool CanParse(XName target); -} \ No newline at end of file +using System.Xml.Linq; + +namespace IOLink.NET.IODD.Parser; + +internal interface IParserPart : IParserPart +{ + T Parse(XElement element); +} + +internal interface IParserPart +{ + bool CanParse(XName target); +} diff --git a/src/IODD.Parser/Interface/IParserPartLocator.cs b/src/IOLink.NET.IODD/Parser/Interface/IParserPartLocator.cs similarity index 76% rename from src/IODD.Parser/Interface/IParserPartLocator.cs rename to src/IOLink.NET.IODD/Parser/Interface/IParserPartLocator.cs index e65e13f..06d95e4 100644 --- a/src/IODD.Parser/Interface/IParserPartLocator.cs +++ b/src/IOLink.NET.IODD/Parser/Interface/IParserPartLocator.cs @@ -1,9 +1,9 @@ -using System.Xml.Linq; - -namespace IOLinkNET.IODD.Parser; - -internal interface IParserPartLocator -{ - T Parse(XElement element); - void AddPart(IParserPart part); -} \ No newline at end of file +using System.Xml.Linq; + +namespace IOLink.NET.IODD.Parser; + +internal interface IParserPartLocator +{ + T Parse(XElement element); + void AddPart(IParserPart part); +} diff --git a/src/IODD.Parser/Parts/Constants/IODDDeviceFunctionNames.cs b/src/IOLink.NET.IODD/Parser/Parts/Constants/IODDDeviceFunctionNames.cs similarity index 95% rename from src/IODD.Parser/Parts/Constants/IODDDeviceFunctionNames.cs rename to src/IOLink.NET.IODD/Parser/Parts/Constants/IODDDeviceFunctionNames.cs index a9edf0a..e01c445 100644 --- a/src/IODD.Parser/Parts/Constants/IODDDeviceFunctionNames.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Constants/IODDDeviceFunctionNames.cs @@ -1,60 +1,60 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Standard.Constants; - -namespace IOLinkNET.IODD.Parts.Constants; - -public static class IODDDeviceFunctionNames -{ - public static readonly XName DatatypeCollectionName = IODDConstants.IODDXmlNamespace.GetName("DatatypeCollection"); - - public static readonly XName DatatypeName = IODDConstants.IODDXmlNamespace.GetName("Datatype"); - - public static readonly XName VariableCollectionName = IODDConstants.IODDXmlNamespace.GetName("VariableCollection"); - - public static readonly XName VariableName = IODDConstants.IODDXmlNamespace.GetName("Variable"); - - public static readonly XName StandardVariableRefName = IODDConstants.IODDXmlNamespace.GetName("StdVariableRef"); - - public static readonly XName RecordItemName = IODDConstants.IODDXmlNamespace.GetName("RecordItem"); - - public static readonly XName RecordItemInfoName = IODDConstants.IODDXmlNamespace.GetName("RecordItemInfo"); - - public static readonly XName ConditionName = IODDConstants.IODDXmlNamespace.GetName("Condition"); - - public static readonly XName ProcessDataName = IODDConstants.IODDXmlNamespace.GetName("ProcessData"); - - public static readonly XName ProcessDataInName = IODDConstants.IODDXmlNamespace.GetName("ProcessDataIn"); - - public static readonly XName ProcessDataOutName = IODDConstants.IODDXmlNamespace.GetName("ProcessDataOut"); - - public static readonly XName ProcessDataCollectionName = IODDConstants.IODDXmlNamespace.GetName("ProcessDataCollection"); - - public static readonly XName UserInterfaceName = IODDConstants.IODDXmlNamespace.GetName("UserInterface"); - - public static readonly XName MenuCollectionName = IODDConstants.IODDXmlNamespace.GetName("MenuCollection"); - - public static readonly XName IdentificationMenuName = IODDConstants.IODDXmlNamespace.GetName("IdentificationMenu"); - - public static readonly XName ParameterMenuName = IODDConstants.IODDXmlNamespace.GetName("ParameterMenu"); - - public static readonly XName ObservationMenuName = IODDConstants.IODDXmlNamespace.GetName("ObservationMenu"); - - public static readonly XName DiagnosisMenuName = IODDConstants.IODDXmlNamespace.GetName("DiagnosisMenu"); - - public static readonly XName ObserverRoleMenuSetName = IODDConstants.IODDXmlNamespace.GetName("ObserverRoleMenuSet"); - - public static readonly XName MaintenanceRoleMenuSetName = IODDConstants.IODDXmlNamespace.GetName("MaintenanceRoleMenuSet"); - - public static readonly XName SpecialistRoleMenuSetName = IODDConstants.IODDXmlNamespace.GetName("SpecialistRoleMenuSet"); - - public static readonly XName MenuName = IODDConstants.IODDXmlNamespace.GetName("Menu"); - - public static readonly XName MenuItemName = IODDConstants.IODDXmlNamespace.GetName("Name"); - - public static readonly XName VariableRefName = IODDConstants.IODDXmlNamespace.GetName("VariableRef"); - - public static readonly XName MenuRefName = IODDConstants.IODDXmlNamespace.GetName("MenuRef"); - - public static readonly XName RecordItemRefName = IODDConstants.IODDXmlNamespace.GetName("RecordItemRef"); -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Standard.Constants; + +namespace IOLink.NET.IODD.Parts.Constants; + +public static class IODDDeviceFunctionNames +{ + public static readonly XName DatatypeCollectionName = IODDConstants.IODDXmlNamespace.GetName("DatatypeCollection"); + + public static readonly XName DatatypeName = IODDConstants.IODDXmlNamespace.GetName("Datatype"); + + public static readonly XName VariableCollectionName = IODDConstants.IODDXmlNamespace.GetName("VariableCollection"); + + public static readonly XName VariableName = IODDConstants.IODDXmlNamespace.GetName("Variable"); + + public static readonly XName StandardVariableRefName = IODDConstants.IODDXmlNamespace.GetName("StdVariableRef"); + + public static readonly XName RecordItemName = IODDConstants.IODDXmlNamespace.GetName("RecordItem"); + + public static readonly XName RecordItemInfoName = IODDConstants.IODDXmlNamespace.GetName("RecordItemInfo"); + + public static readonly XName ConditionName = IODDConstants.IODDXmlNamespace.GetName("Condition"); + + public static readonly XName ProcessDataName = IODDConstants.IODDXmlNamespace.GetName("ProcessData"); + + public static readonly XName ProcessDataInName = IODDConstants.IODDXmlNamespace.GetName("ProcessDataIn"); + + public static readonly XName ProcessDataOutName = IODDConstants.IODDXmlNamespace.GetName("ProcessDataOut"); + + public static readonly XName ProcessDataCollectionName = IODDConstants.IODDXmlNamespace.GetName("ProcessDataCollection"); + + public static readonly XName UserInterfaceName = IODDConstants.IODDXmlNamespace.GetName("UserInterface"); + + public static readonly XName MenuCollectionName = IODDConstants.IODDXmlNamespace.GetName("MenuCollection"); + + public static readonly XName IdentificationMenuName = IODDConstants.IODDXmlNamespace.GetName("IdentificationMenu"); + + public static readonly XName ParameterMenuName = IODDConstants.IODDXmlNamespace.GetName("ParameterMenu"); + + public static readonly XName ObservationMenuName = IODDConstants.IODDXmlNamespace.GetName("ObservationMenu"); + + public static readonly XName DiagnosisMenuName = IODDConstants.IODDXmlNamespace.GetName("DiagnosisMenu"); + + public static readonly XName ObserverRoleMenuSetName = IODDConstants.IODDXmlNamespace.GetName("ObserverRoleMenuSet"); + + public static readonly XName MaintenanceRoleMenuSetName = IODDConstants.IODDXmlNamespace.GetName("MaintenanceRoleMenuSet"); + + public static readonly XName SpecialistRoleMenuSetName = IODDConstants.IODDXmlNamespace.GetName("SpecialistRoleMenuSet"); + + public static readonly XName MenuName = IODDConstants.IODDXmlNamespace.GetName("Menu"); + + public static readonly XName MenuItemName = IODDConstants.IODDXmlNamespace.GetName("Name"); + + public static readonly XName VariableRefName = IODDConstants.IODDXmlNamespace.GetName("VariableRef"); + + public static readonly XName MenuRefName = IODDConstants.IODDXmlNamespace.GetName("MenuRef"); + + public static readonly XName RecordItemRefName = IODDConstants.IODDXmlNamespace.GetName("RecordItemRef"); +} diff --git a/src/IODD.Parser/Parts/Constants/IODDExternalCollectionNames.cs b/src/IOLink.NET.IODD/Parser/Parts/Constants/IODDExternalCollectionNames.cs similarity index 69% rename from src/IODD.Parser/Parts/Constants/IODDExternalCollectionNames.cs rename to src/IOLink.NET.IODD/Parser/Parts/Constants/IODDExternalCollectionNames.cs index b767df5..b10cfbd 100644 --- a/src/IODD.Parser/Parts/Constants/IODDExternalCollectionNames.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Constants/IODDExternalCollectionNames.cs @@ -1,8 +1,8 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Standard.Constants; +using IOLink.NET.IODD.Standard.Constants; -namespace IOLinkNET.IODD.Parser.Parts.Constants; +namespace IOLink.NET.IODD.Parser.Parts.Constants; public static class IODDExternalCollectionNames { public static readonly XName PrimaryLanguageName = IODDConstants.IODDXmlNamespace.GetName("PrimaryLanguage"); diff --git a/src/IODD.Parser/Parts/Constants/IODDStandardDefinitionNames.cs b/src/IOLink.NET.IODD/Parser/Parts/Constants/IODDStandardDefinitionNames.cs similarity index 57% rename from src/IODD.Parser/Parts/Constants/IODDStandardDefinitionNames.cs rename to src/IOLink.NET.IODD/Parser/Parts/Constants/IODDStandardDefinitionNames.cs index 456870d..e6ccfec 100644 --- a/src/IODD.Parser/Parts/Constants/IODDStandardDefinitionNames.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Constants/IODDStandardDefinitionNames.cs @@ -1,8 +1,8 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Standard.Constants; +using IOLink.NET.IODD.Standard.Constants; -namespace IOLinkNET.IODD.Parser.Parts.Constants; +namespace IOLink.NET.IODD.Parser.Parts.Constants; public static class IODDStandardDefinitionNames { public static readonly XName VariableName = IODDConstants.IODDXmlNamespace.GetName("Variable"); diff --git a/src/IODD.Parser/Parts/Constants/IODDTextRefNames.cs b/src/IOLink.NET.IODD/Parser/Parts/Constants/IODDTextRefNames.cs similarity index 88% rename from src/IODD.Parser/Parts/Constants/IODDTextRefNames.cs rename to src/IOLink.NET.IODD/Parser/Parts/Constants/IODDTextRefNames.cs index b30cda4..f69719b 100644 --- a/src/IODD.Parser/Parts/Constants/IODDTextRefNames.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Constants/IODDTextRefNames.cs @@ -1,22 +1,22 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Standard.Constants; - -namespace IOLinkNET.IODD.Parts.Constants; - -public static class IODDTextRefNames -{ - public static readonly XName VendorTextName = IODDConstants.IODDXmlNamespace.GetName("VendorText"); - - public static readonly XName VendorUrlName = IODDConstants.IODDXmlNamespace.GetName("VendorUrl"); - - public static readonly XName VendorLogoName = IODDConstants.IODDXmlNamespace.GetName("VendorLogo"); - - public static readonly XName DeviceNameName = IODDConstants.IODDXmlNamespace.GetName("DeviceName"); - - public static readonly XName DeviceFamilyName = IODDConstants.IODDXmlNamespace.GetName("DeviceFamily"); - - public static readonly XName Name = IODDConstants.IODDXmlNamespace.GetName("Name"); - - public static readonly XName DescriptionName = IODDConstants.IODDXmlNamespace.GetName("Description"); -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Standard.Constants; + +namespace IOLink.NET.IODD.Parts.Constants; + +public static class IODDTextRefNames +{ + public static readonly XName VendorTextName = IODDConstants.IODDXmlNamespace.GetName("VendorText"); + + public static readonly XName VendorUrlName = IODDConstants.IODDXmlNamespace.GetName("VendorUrl"); + + public static readonly XName VendorLogoName = IODDConstants.IODDXmlNamespace.GetName("VendorLogo"); + + public static readonly XName DeviceNameName = IODDConstants.IODDXmlNamespace.GetName("DeviceName"); + + public static readonly XName DeviceFamilyName = IODDConstants.IODDXmlNamespace.GetName("DeviceFamily"); + + public static readonly XName Name = IODDConstants.IODDXmlNamespace.GetName("Name"); + + public static readonly XName DescriptionName = IODDConstants.IODDXmlNamespace.GetName("Description"); +} diff --git a/src/IODD.Parser/Parts/DatatypeCollectionTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DatatypeCollectionTParser.cs similarity index 80% rename from src/IODD.Parser/Parts/DatatypeCollectionTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/DatatypeCollectionTParser.cs index 06f65cb..921f36c 100644 --- a/src/IODD.Parser/Parts/DatatypeCollectionTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/DatatypeCollectionTParser.cs @@ -1,36 +1,36 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Parts.Constants; -using IOLinkNET.IODD.Parts.Datatypes; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts; - -internal class DatatypeCollectionTParser : IParserPart> -{ - private readonly IParserPartLocator _partLocator; - - public DatatypeCollectionTParser(IParserPartLocator partLocator) - { - _partLocator = partLocator; - } - - public bool CanParse(XName name) - => name == IODDParserConstants.DatatypeCollectionName; - - public IEnumerable Parse(XElement element) - { - IEnumerable dataTypeElements = element.Descendants(IODDDeviceFunctionNames.DatatypeName); - List dataTypeCollection = new(); - - foreach (XElement dataTypeElement in dataTypeElements) - { - DatatypeT convertedType = DatatypeTParser.Parse(dataTypeElement, _partLocator); - dataTypeCollection.Add(convertedType); - } - - return dataTypeCollection; - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Parts.Constants; +using IOLink.NET.IODD.Parts.Datatypes; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts; + +internal class DatatypeCollectionTParser : IParserPart> +{ + private readonly IParserPartLocator _partLocator; + + public DatatypeCollectionTParser(IParserPartLocator partLocator) + { + _partLocator = partLocator; + } + + public bool CanParse(XName name) + => name == IODDParserConstants.DatatypeCollectionName; + + public IEnumerable Parse(XElement element) + { + IEnumerable dataTypeElements = element.Descendants(IODDDeviceFunctionNames.DatatypeName); + List dataTypeCollection = new(); + + foreach (XElement dataTypeElement in dataTypeElements) + { + DatatypeT convertedType = DatatypeTParser.Parse(dataTypeElement, _partLocator); + dataTypeCollection.Add(convertedType); + } + + return dataTypeCollection; + } +} diff --git a/src/IODD.Parser/Parts/DatatypeRefTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DatatypeRefTParser.cs similarity index 70% rename from src/IODD.Parser/Parts/DatatypeRefTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/DatatypeRefTParser.cs index 144737a..94f9da2 100644 --- a/src/IODD.Parser/Parts/DatatypeRefTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/DatatypeRefTParser.cs @@ -1,21 +1,21 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Common; - -namespace IOLinkNET.IODD.Parts; - -internal class DatatypeRefTParser : IParserPart -{ - public bool CanParse(XName name) - => name == IODDParserConstants.DatatypeRefName; - - public DatatypeRefT Parse(XElement element) - { - string datatypeId = element.ReadMandatoryAttribute("datatypeId"); - - return new DatatypeRefT(datatypeId); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Common; + +namespace IOLink.NET.IODD.Parts; + +internal class DatatypeRefTParser : IParserPart +{ + public bool CanParse(XName name) + => name == IODDParserConstants.DatatypeRefName; + + public DatatypeRefT Parse(XElement element) + { + string datatypeId = element.ReadMandatoryAttribute("datatypeId"); + + return new DatatypeRefT(datatypeId); + } +} diff --git a/src/IOLink.NET.IODD/Parser/Parts/Datatypes/ArrayTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/ArrayTParser.cs new file mode 100644 index 0000000..5a0700f --- /dev/null +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/ArrayTParser.cs @@ -0,0 +1,34 @@ +using System.Xml.Linq; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class ArrayTParser +{ + public static ArrayT Parse( + XElement elem, + IParserPartLocator parserLocator, + byte? fixedLengthRestriction = null + ) + { + string? id = elem.ReadOptionalAttribute("id"); + byte count = fixedLengthRestriction ?? elem.ReadMandatoryAttribute("count"); + bool subindexAccessSupported = elem.ReadOptionalAttributeAsBool("subindexAccessSupported"); + DatatypeRefT? typeRef = parserLocator.ParseOptional( + elem.Descendants(IODDParserConstants.DatatypeRefName).FirstOrDefault() + ); + + return new ArrayT( + id, + count, + SimpleTypeParser.Parse( + elem.Descendants(IODDParserConstants.SimpleDatatypeName).FirstOrDefault() + ), + typeRef, + subindexAccessSupported + ); + } +} diff --git a/src/IODD.Parser/Parts/Datatypes/BooleanTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/BooleanTParser.cs similarity index 66% rename from src/IODD.Parser/Parts/Datatypes/BooleanTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/BooleanTParser.cs index 2e4a773..24fe022 100644 --- a/src/IODD.Parser/Parts/Datatypes/BooleanTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/BooleanTParser.cs @@ -1,17 +1,17 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; - -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class BooleanTParser -{ - public static BooleanT Parse(XElement elem) - { - string? id = elem.ReadOptionalAttribute("id"); - - return new BooleanT(id, Enumerable.Empty>()); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; + +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class BooleanTParser +{ + public static BooleanT Parse(XElement elem) + { + string? id = elem.ReadOptionalAttribute("id"); + + return new BooleanT(id, Enumerable.Empty>()); + } +} diff --git a/src/IODD.Parser/Parts/Datatypes/ComplexTypeParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/ComplexTypeParser.cs similarity index 79% rename from src/IODD.Parser/Parts/Datatypes/ComplexTypeParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/ComplexTypeParser.cs index 429f561..f576fb0 100644 --- a/src/IODD.Parser/Parts/Datatypes/ComplexTypeParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/ComplexTypeParser.cs @@ -1,17 +1,17 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class ComplexTypeParser -{ - public static ComplexDatatypeT? Parse(string typeName, XElement dataTypeElement, IParserPartLocator partLocator, byte? fixedLengthRestriction = null) - => typeName switch - { - DatatypeNames.ArrayT => ArrayTParser.Parse(dataTypeElement, partLocator, fixedLengthRestriction), - DatatypeNames.RecordT => RecordTParser.Parse(dataTypeElement, partLocator), - _ => null - }; -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class ComplexTypeParser +{ + public static ComplexDatatypeT? Parse(string typeName, XElement dataTypeElement, IParserPartLocator partLocator, byte? fixedLengthRestriction = null) + => typeName switch + { + DatatypeNames.ArrayT => ArrayTParser.Parse(dataTypeElement, partLocator, fixedLengthRestriction), + DatatypeNames.RecordT => RecordTParser.Parse(dataTypeElement, partLocator), + _ => null + }; +} diff --git a/src/IODD.Parser/Parts/Datatypes/DataTypeTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/DataTypeTParser.cs similarity index 85% rename from src/IODD.Parser/Parts/Datatypes/DataTypeTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/DataTypeTParser.cs index 5cd5da8..be3b7d2 100644 --- a/src/IODD.Parser/Parts/Datatypes/DataTypeTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/DataTypeTParser.cs @@ -1,24 +1,24 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class DatatypeTParser -{ - public static DatatypeT Parse(XElement elem, IParserPartLocator partLocator, byte? fixedLengthRestriction = null) - { - string typeName = elem.ReadMandatoryAttribute("type", IODDParserConstants.XSIXmlNamespace); - return (DatatypeT?)SimpleTypeParser.Parse(typeName, elem, fixedLengthRestriction) ?? ComplexTypeParser.Parse(typeName, elem, partLocator, fixedLengthRestriction) ?? ProcessDataUnionTypeParser.Parse(typeName, elem, partLocator) - ?? throw new NotSupportedException($"Could not parse data type with name {typeName}."); - } - - public static DatatypeT? ParseOptional(XElement? element, IParserPartLocator partLocator) - => element is not null ? Parse(element, partLocator) : null; - - public static DatatypeT? ParseOptional(XElement? element, byte fixedLengthRestriction, IParserPartLocator partLocator) - => element is not null ? Parse(element, partLocator, fixedLengthRestriction) : null; -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class DatatypeTParser +{ + public static DatatypeT Parse(XElement elem, IParserPartLocator partLocator, byte? fixedLengthRestriction = null) + { + string typeName = elem.ReadMandatoryAttribute("type", IODDParserConstants.XSIXmlNamespace); + return (DatatypeT?)SimpleTypeParser.Parse(typeName, elem, fixedLengthRestriction) ?? ComplexTypeParser.Parse(typeName, elem, partLocator, fixedLengthRestriction) ?? ProcessDataUnionTypeParser.Parse(typeName, elem, partLocator) + ?? throw new NotSupportedException($"Could not parse data type with name {typeName}."); + } + + public static DatatypeT? ParseOptional(XElement? element, IParserPartLocator partLocator) + => element is not null ? Parse(element, partLocator) : null; + + public static DatatypeT? ParseOptional(XElement? element, byte fixedLengthRestriction, IParserPartLocator partLocator) + => element is not null ? Parse(element, partLocator, fixedLengthRestriction) : null; +} diff --git a/src/IODD.Parser/Parts/Datatypes/DatatypeNames.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/DatatypeNames.cs similarity index 89% rename from src/IODD.Parser/Parts/Datatypes/DatatypeNames.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/DatatypeNames.cs index 4b95152..4124265 100644 --- a/src/IODD.Parser/Parts/Datatypes/DatatypeNames.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/DatatypeNames.cs @@ -1,24 +1,24 @@ -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class DatatypeNames -{ - public const string BooleanT = "BooleanT"; - - public const string IntegerT = "IntegerT"; - - public const string UIntegerT = "UIntegerT"; - - public const string StringT = "StringT"; - - public const string Float32T = "Float32T"; - - public const string OctetStringT = "OctetStringT"; - - public const string RecordT = "RecordT"; - - public const string ArrayT = "ArrayT"; - - public const string ProcessDataInUnionT = "ProcessDataInUnionT"; - - public const string ProcessDataOutUnionT = "ProcessDataOutUnionT"; -} \ No newline at end of file +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class DatatypeNames +{ + public const string BooleanT = "BooleanT"; + + public const string IntegerT = "IntegerT"; + + public const string UIntegerT = "UIntegerT"; + + public const string StringT = "StringT"; + + public const string Float32T = "Float32T"; + + public const string OctetStringT = "OctetStringT"; + + public const string RecordT = "RecordT"; + + public const string ArrayT = "ArrayT"; + + public const string ProcessDataInUnionT = "ProcessDataInUnionT"; + + public const string ProcessDataOutUnionT = "ProcessDataOutUnionT"; +} diff --git a/src/IODD.Parser/Parts/Datatypes/Float32TParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/Float32TParser.cs similarity index 69% rename from src/IODD.Parser/Parts/Datatypes/Float32TParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/Float32TParser.cs index e0742e1..a8323ad 100644 --- a/src/IODD.Parser/Parts/Datatypes/Float32TParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/Float32TParser.cs @@ -1,17 +1,17 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; - -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class Float32TParser -{ - public static Float32T Parse(XElement elem) - { - string? id = elem.ReadOptionalAttribute("id"); - - return new Float32T(id, Enumerable.Empty>(), Enumerable.Empty>()); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; + +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class Float32TParser +{ + public static Float32T Parse(XElement elem) + { + string? id = elem.ReadOptionalAttribute("id"); + + return new Float32T(id, Enumerable.Empty>(), Enumerable.Empty>()); + } +} diff --git a/src/IODD.Parser/Parts/Datatypes/IntegerTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/IntegerTParser.cs similarity index 83% rename from src/IODD.Parser/Parts/Datatypes/IntegerTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/IntegerTParser.cs index 75c452e..4f758c9 100644 --- a/src/IODD.Parser/Parts/Datatypes/IntegerTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/IntegerTParser.cs @@ -1,26 +1,26 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; - -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class IntegerTParser -{ - public static IntegerT ParseInt(XElement elem) - { - string? id = elem.ReadOptionalAttribute("id"); - ushort bitLength = elem.ReadMandatoryAttribute("bitLength"); - - return new IntegerT(id, bitLength, Enumerable.Empty>(), Enumerable.Empty>()); - } - - public static UIntegerT ParseUInt(XElement elem) - { - string? id = elem.ReadOptionalAttribute("id"); - ushort bitLength = elem.ReadMandatoryAttribute("bitLength"); - - return new UIntegerT(id, bitLength, Enumerable.Empty>(), Enumerable.Empty>()); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; + +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class IntegerTParser +{ + public static IntegerT ParseInt(XElement elem) + { + string? id = elem.ReadOptionalAttribute("id"); + ushort bitLength = elem.ReadMandatoryAttribute("bitLength"); + + return new IntegerT(id, bitLength, Enumerable.Empty>(), Enumerable.Empty>()); + } + + public static UIntegerT ParseUInt(XElement elem) + { + string? id = elem.ReadOptionalAttribute("id"); + ushort bitLength = elem.ReadMandatoryAttribute("bitLength"); + + return new UIntegerT(id, bitLength, Enumerable.Empty>(), Enumerable.Empty>()); + } +} diff --git a/src/IODD.Parser/Parts/Datatypes/OctetStringTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/OctetStringTParser.cs similarity index 70% rename from src/IODD.Parser/Parts/Datatypes/OctetStringTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/OctetStringTParser.cs index a0851f5..1f15f36 100644 --- a/src/IODD.Parser/Parts/Datatypes/OctetStringTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/OctetStringTParser.cs @@ -1,9 +1,9 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Structure.Datatypes; -namespace IOLinkNET.IODD.Parser.Parts.Datatypes; +namespace IOLink.NET.IODD.Parser.Parts.Datatypes; internal static class OctetStringTParser { public static OctetStringT Parse(XElement elem, byte? fixedLengthRestriction = null) diff --git a/src/IODD.Parser/Parts/Datatypes/ProcessDataUnionTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/ProcessDataUnionTParser.cs similarity index 71% rename from src/IODD.Parser/Parts/Datatypes/ProcessDataUnionTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/ProcessDataUnionTParser.cs index c866df3..dda1c03 100644 --- a/src/IODD.Parser/Parts/Datatypes/ProcessDataUnionTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/ProcessDataUnionTParser.cs @@ -1,11 +1,11 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Datatypes; -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Datatypes; +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Structure.Datatypes; -namespace IOLinkNET.IODD.Parser.Parts.Datatypes; +namespace IOLink.NET.IODD.Parser.Parts.Datatypes; internal static class ProcessDataUnionTParser { public static ProcessDataUnionT? Parse(XElement elem, IParserPartLocator parserLocator) diff --git a/src/IODD.Parser/Parts/Datatypes/ProcessDataUnionTypeParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/ProcessDataUnionTypeParser.cs similarity index 79% rename from src/IODD.Parser/Parts/Datatypes/ProcessDataUnionTypeParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/ProcessDataUnionTypeParser.cs index 11cd87d..4ad240f 100644 --- a/src/IODD.Parser/Parts/Datatypes/ProcessDataUnionTypeParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/ProcessDataUnionTypeParser.cs @@ -1,11 +1,11 @@ using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Parser.Parts.Datatypes; -using IOLinkNET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Parser.Parts.Datatypes; +using IOLink.NET.IODD.Structure.Datatypes; -namespace IOLinkNET.IODD.Parts.Datatypes; +namespace IOLink.NET.IODD.Parts.Datatypes; internal static class ProcessDataUnionTypeParser { @@ -20,4 +20,4 @@ internal static class ProcessDataUnionTypeParser public static DatatypeT? Parse(XElement? dataTypeElement, IParserPartLocator partLocator) => dataTypeElement is null ? null : Parse(dataTypeElement.ReadMandatoryAttribute("type", IODDParserConstants.XSIXmlNamespace), dataTypeElement, partLocator); -} \ No newline at end of file +} diff --git a/src/IODD.Parser/Parts/Datatypes/RecordTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/RecordTParser.cs similarity index 84% rename from src/IODD.Parser/Parts/Datatypes/RecordTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/RecordTParser.cs index b70e864..5812375 100644 --- a/src/IODD.Parser/Parts/Datatypes/RecordTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/RecordTParser.cs @@ -1,35 +1,35 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class RecordTParser -{ - public static RecordT Parse(XElement elem, IParserPartLocator parserLocator) - { - string? id = elem.ReadOptionalAttribute("id"); - ushort bitLenght = elem.ReadMandatoryAttribute("bitLength"); - - _ = bool.TryParse(elem.ReadOptionalAttribute("subindexAccessSupported"), out bool subindexAccessSupported); - - return new RecordT(id, bitLenght, elem.Descendants(IODDDeviceFunctionNames.RecordItemName).Select(elem => ParseRecordItem(elem, parserLocator)), subindexAccessSupported); - } - - private static RecordItemT ParseRecordItem(XElement elem, IParserPartLocator parserLocator) - { - byte subIndex = elem.ReadMandatoryAttribute("subindex"); - ushort bitOffset = elem.ReadMandatoryAttribute("bitOffset"); - - TextRefT name = parserLocator.ParseMandatory(elem.Elements(IODDTextRefNames.Name).First()); - TextRefT? description = parserLocator.ParseOptional(elem.Elements(IODDTextRefNames.DescriptionName).FirstOrDefault()); - DatatypeRefT? typeRef = parserLocator.ParseOptional(elem.Elements(IODDParserConstants.DatatypeRefName).FirstOrDefault()); - - return new RecordItemT(subIndex, bitOffset, name, description, SimpleTypeParser.Parse(elem.Descendants(IODDParserConstants.SimpleDatatypeName).FirstOrDefault()), typeRef); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class RecordTParser +{ + public static RecordT Parse(XElement elem, IParserPartLocator parserLocator) + { + string? id = elem.ReadOptionalAttribute("id"); + ushort bitLenght = elem.ReadMandatoryAttribute("bitLength"); + + _ = bool.TryParse(elem.ReadOptionalAttribute("subindexAccessSupported"), out bool subindexAccessSupported); + + return new RecordT(id, bitLenght, elem.Descendants(IODDDeviceFunctionNames.RecordItemName).Select(elem => ParseRecordItem(elem, parserLocator)), subindexAccessSupported); + } + + private static RecordItemT ParseRecordItem(XElement elem, IParserPartLocator parserLocator) + { + byte subIndex = elem.ReadMandatoryAttribute("subindex"); + ushort bitOffset = elem.ReadMandatoryAttribute("bitOffset"); + + TextRefT name = parserLocator.ParseMandatory(elem.Elements(IODDTextRefNames.Name).First()); + TextRefT? description = parserLocator.ParseOptional(elem.Elements(IODDTextRefNames.DescriptionName).FirstOrDefault()); + DatatypeRefT? typeRef = parserLocator.ParseOptional(elem.Elements(IODDParserConstants.DatatypeRefName).FirstOrDefault()); + + return new RecordItemT(subIndex, bitOffset, name, description, SimpleTypeParser.Parse(elem.Descendants(IODDParserConstants.SimpleDatatypeName).FirstOrDefault()), typeRef); + } +} diff --git a/src/IOLink.NET.IODD/Parser/Parts/Datatypes/SimpleTypeParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/SimpleTypeParser.cs new file mode 100644 index 0000000..dc271df --- /dev/null +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/SimpleTypeParser.cs @@ -0,0 +1,37 @@ +using System.Xml.Linq; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Parser.Parts.Datatypes; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class SimpleTypeParser +{ + public static SimpleDatatypeT? Parse( + string typeName, + XElement dataTypeElement, + byte? fixedLengthRestriction = null + ) => + typeName switch + { + DatatypeNames.BooleanT => BooleanTParser.Parse(dataTypeElement), + DatatypeNames.IntegerT => IntegerTParser.ParseInt(dataTypeElement), + DatatypeNames.UIntegerT => IntegerTParser.ParseUInt(dataTypeElement), + DatatypeNames.StringT => StringTParser.Parse(dataTypeElement, fixedLengthRestriction), + DatatypeNames.Float32T => Float32TParser.Parse(dataTypeElement), + DatatypeNames.OctetStringT => OctetStringTParser.Parse( + dataTypeElement, + fixedLengthRestriction + ), + _ => null, + }; + + public static SimpleDatatypeT? Parse(XElement? dataTypeElement) => + dataTypeElement is null + ? null + : Parse( + dataTypeElement.ReadMandatoryAttribute("type", IODDParserConstants.XSIXmlNamespace), + dataTypeElement + ); +} diff --git a/src/IODD.Parser/Parts/Datatypes/StringTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/StringTParser.cs similarity index 83% rename from src/IODD.Parser/Parts/Datatypes/StringTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Datatypes/StringTParser.cs index a9317f6..8b5b027 100644 --- a/src/IODD.Parser/Parts/Datatypes/StringTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Datatypes/StringTParser.cs @@ -1,26 +1,26 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; - -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Parts.Datatypes; - -internal static class StringTParser -{ - public static StringT Parse(XElement elem, byte? fixedLengthRestriction = null) - { - string? id = elem.ReadOptionalAttribute("id"); - byte fixedLength = fixedLengthRestriction ?? elem.ReadMandatoryAttribute("fixedLength"); - string encoding = elem.ReadMandatoryAttribute("encoding"); - - return new StringT(id, fixedLength, ParseEncoding(encoding)); - } - - private static StringTEncoding ParseEncoding(string value) => value switch - { - "UTF-8" => StringTEncoding.UTF8, - "ASCII" => StringTEncoding.ASCII, - _ => throw new NotImplementedException("") - }; -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; + +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Parts.Datatypes; + +internal static class StringTParser +{ + public static StringT Parse(XElement elem, byte? fixedLengthRestriction = null) + { + string? id = elem.ReadOptionalAttribute("id"); + byte fixedLength = fixedLengthRestriction ?? elem.ReadMandatoryAttribute("fixedLength"); + string encoding = elem.ReadMandatoryAttribute("encoding"); + + return new StringT(id, fixedLength, ParseEncoding(encoding)); + } + + private static StringTEncoding ParseEncoding(string value) => value switch + { + "UTF-8" => StringTEncoding.UTF8, + "ASCII" => StringTEncoding.ASCII, + _ => throw new NotImplementedException("") + }; +} diff --git a/src/IODD.Parser/Parts/DeviceFunction/ConditionTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/ConditionTParser.cs similarity index 70% rename from src/IODD.Parser/Parts/DeviceFunction/ConditionTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/ConditionTParser.cs index 6a933da..680ece1 100644 --- a/src/IODD.Parser/Parts/DeviceFunction/ConditionTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/ConditionTParser.cs @@ -1,23 +1,23 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.ProcessData; - -namespace IOLinkNET.IODD.Parts.DeviceFunction; - -internal class ConditionTParser : IParserPart -{ - public bool CanParse(XName name) - => name == IODDDeviceFunctionNames.ConditionName; - - public ConditionT Parse(XElement element) - { - string variableId = element.ReadMandatoryAttribute("variableId"); - byte subIndex = element.ReadOptionalAttribute("subIndex"); - int value = element.ReadMandatoryAttribute("value"); - return new ConditionT(variableId, subIndex, value); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.ProcessData; + +namespace IOLink.NET.IODD.Parts.DeviceFunction; + +internal class ConditionTParser : IParserPart +{ + public bool CanParse(XName name) + => name == IODDDeviceFunctionNames.ConditionName; + + public ConditionT Parse(XElement element) + { + string variableId = element.ReadMandatoryAttribute("variableId"); + byte subIndex = element.ReadOptionalAttribute("subIndex"); + int value = element.ReadMandatoryAttribute("value"); + return new ConditionT(variableId, subIndex, value); + } +} diff --git a/src/IODD.Parser/Parts/DeviceFunction/DeviceFunctionTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/DeviceFunctionTParser.cs similarity index 80% rename from src/IODD.Parser/Parts/DeviceFunction/DeviceFunctionTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/DeviceFunctionTParser.cs index 76d1266..8c8def9 100644 --- a/src/IODD.Parser/Parts/DeviceFunction/DeviceFunctionTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/DeviceFunctionTParser.cs @@ -1,58 +1,58 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.DeviceFunction; -using IOLinkNET.IODD.Structure.ProcessData; -using IOLinkNET.IODD.Structure.Profile; -using IOLinkNET.IODD.Structure.Structure.Menu; - -namespace IOLinkNET.IODD.Parts.DeviceFunction; - -internal class DeviceFunctionTParser : IParserPart -{ - private readonly IParserPartLocator _parserLocator; - private readonly StandardVariableRefTParser _standardVariableRefTParser; - - public DeviceFunctionTParser(IParserPartLocator parserLocator) - { - _parserLocator = parserLocator; - _standardVariableRefTParser = new(parserLocator); - } - public bool CanParse(XName name) - => name == IODDParserConstants.DeviceFunctionName; - - public DeviceFunctionT Parse(XElement element) - { - var dataTypeCollection = _parserLocator - .ParseOptional>(element - .Descendants(IODDDeviceFunctionNames.DatatypeCollectionName) - .FirstOrDefault() - )? - .ToArray() ?? Array.Empty(); - - var variableCollection = element - .Descendants(IODDDeviceFunctionNames.VariableName) - .Select(_parserLocator.ParseMandatory) - .Concat(element - .Descendants(IODDDeviceFunctionNames.StandardVariableRefName) - .Select(_standardVariableRefTParser.Parse) - .ToArray()); - - var pdCollection = element - .Descendants(IODDDeviceFunctionNames.ProcessDataCollectionName) - .Descendants(IODDDeviceFunctionNames.ProcessDataName) - .Select(_parserLocator.ParseMandatory) - .ToArray(); - - var userInterface = element - .Descendants(IODDDeviceFunctionNames.UserInterfaceName) - .Select(_parserLocator.ParseMandatory) - .First(); - - return new DeviceFunctionT(dataTypeCollection, variableCollection, pdCollection, userInterface); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.DeviceFunction; +using IOLink.NET.IODD.Structure.ProcessData; +using IOLink.NET.IODD.Structure.Profile; +using IOLink.NET.IODD.Structure.Structure.Menu; + +namespace IOLink.NET.IODD.Parts.DeviceFunction; + +internal class DeviceFunctionTParser : IParserPart +{ + private readonly IParserPartLocator _parserLocator; + private readonly StandardVariableRefTParser _standardVariableRefTParser; + + public DeviceFunctionTParser(IParserPartLocator parserLocator) + { + _parserLocator = parserLocator; + _standardVariableRefTParser = new(parserLocator); + } + public bool CanParse(XName name) + => name == IODDParserConstants.DeviceFunctionName; + + public DeviceFunctionT Parse(XElement element) + { + var dataTypeCollection = _parserLocator + .ParseOptional>(element + .Descendants(IODDDeviceFunctionNames.DatatypeCollectionName) + .FirstOrDefault() + )? + .ToArray() ?? Array.Empty(); + + var variableCollection = element + .Descendants(IODDDeviceFunctionNames.VariableName) + .Select(_parserLocator.ParseMandatory) + .Concat(element + .Descendants(IODDDeviceFunctionNames.StandardVariableRefName) + .Select(_standardVariableRefTParser.Parse) + .ToArray()); + + var pdCollection = element + .Descendants(IODDDeviceFunctionNames.ProcessDataCollectionName) + .Descendants(IODDDeviceFunctionNames.ProcessDataName) + .Select(_parserLocator.ParseMandatory) + .ToArray(); + + var userInterface = element + .Descendants(IODDDeviceFunctionNames.UserInterfaceName) + .Select(_parserLocator.ParseMandatory) + .First(); + + return new DeviceFunctionT(dataTypeCollection, variableCollection, pdCollection, userInterface); + } +} diff --git a/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/ProcessDataItemTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/ProcessDataItemTParser.cs new file mode 100644 index 0000000..b2616f2 --- /dev/null +++ b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/ProcessDataItemTParser.cs @@ -0,0 +1,42 @@ +using System.Xml.Linq; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Parts.Constants; +using IOLink.NET.IODD.Parts.Datatypes; +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.ProcessData; + +namespace IOLink.NET.IODD.Parts.DeviceFunction; + +internal class ProcessDataItemParser : IParserPart +{ + private static readonly IEnumerable Names = new[] + { + IODDDeviceFunctionNames.ProcessDataInName, + IODDDeviceFunctionNames.ProcessDataOutName, + }; + private readonly IParserPartLocator _parserLocator; + + public ProcessDataItemParser(IParserPartLocator parserLocator) + { + _parserLocator = parserLocator; + } + + public bool CanParse(XName name) => Names.Contains(name); + + public ProcessDataItemT Parse(XElement element) + { + DatatypeT? datatypeT = DatatypeTParser.ParseOptional( + element.Descendants(IODDParserConstants.DatatypeName).FirstOrDefault(), + _parserLocator + ); + DatatypeRefT? datatypeRef = _parserLocator.ParseOptional( + element.Descendants(IODDParserConstants.DatatypeRefName).FirstOrDefault() + ); + var id = element.ReadMandatoryAttributeAsString("id"); + ushort bitLength = element.ReadMandatoryAttribute("bitLength"); + + return new ProcessDataItemT(datatypeT, datatypeRef, id, bitLength); + } +} diff --git a/src/IODD.Parser/Parts/DeviceFunction/ProcessDataParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/ProcessDataParser.cs similarity index 81% rename from src/IODD.Parser/Parts/DeviceFunction/ProcessDataParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/ProcessDataParser.cs index 81da1d7..f0e3825 100644 --- a/src/IODD.Parser/Parts/DeviceFunction/ProcessDataParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/ProcessDataParser.cs @@ -1,31 +1,31 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.ProcessData; - -namespace IOLinkNET.IODD.Parts.DeviceFunction; - -internal class ProcessDataParser : IParserPart -{ - private readonly IParserPartLocator _parserLocator; - - public ProcessDataParser(IParserPartLocator parserLocator) - { - _parserLocator = parserLocator; - } - - public bool CanParse(XName name) - => name == IODDDeviceFunctionNames.ProcessDataName; - - public ProcessDataT Parse(XElement element) - { - ConditionT? condition = _parserLocator.ParseOptional(element.Descendants(IODDDeviceFunctionNames.ConditionName).FirstOrDefault()); - ProcessDataItemT? pdin = _parserLocator.ParseOptional(element.Descendants(IODDDeviceFunctionNames.ProcessDataInName).FirstOrDefault()); - ProcessDataItemT? pdout = _parserLocator.ParseOptional(element.Descendants(IODDDeviceFunctionNames.ProcessDataOutName).FirstOrDefault()); - - return new ProcessDataT(condition, pdin, pdout); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.ProcessData; + +namespace IOLink.NET.IODD.Parts.DeviceFunction; + +internal class ProcessDataParser : IParserPart +{ + private readonly IParserPartLocator _parserLocator; + + public ProcessDataParser(IParserPartLocator parserLocator) + { + _parserLocator = parserLocator; + } + + public bool CanParse(XName name) + => name == IODDDeviceFunctionNames.ProcessDataName; + + public ProcessDataT Parse(XElement element) + { + ConditionT? condition = _parserLocator.ParseOptional(element.Descendants(IODDDeviceFunctionNames.ConditionName).FirstOrDefault()); + ProcessDataItemT? pdin = _parserLocator.ParseOptional(element.Descendants(IODDDeviceFunctionNames.ProcessDataInName).FirstOrDefault()); + ProcessDataItemT? pdout = _parserLocator.ParseOptional(element.Descendants(IODDDeviceFunctionNames.ProcessDataOutName).FirstOrDefault()); + + return new ProcessDataT(condition, pdin, pdout); + } +} diff --git a/src/IODD.Parser/Parts/DeviceFunction/RecordItemInfoParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/RecordItemInfoParser.cs similarity index 70% rename from src/IODD.Parser/Parts/DeviceFunction/RecordItemInfoParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/RecordItemInfoParser.cs index 7261c6d..2a718f7 100644 --- a/src/IODD.Parser/Parts/DeviceFunction/RecordItemInfoParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/RecordItemInfoParser.cs @@ -1,28 +1,28 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.DeviceFunction; - -namespace IOLinkNET.IODD.Parts.DeviceFunction; - -internal class RecordItemInfoParser : IParserPart -{ - - public RecordItemInfoParser() - { - } - - public bool CanParse(XName name) - => name == IODDDeviceFunctionNames.RecordItemInfoName; - - public RecordItemInfoT Parse(XElement element) - { - byte subIndex = element.ReadMandatoryAttribute("subIndex"); - string? defaultValue = element.ReadOptionalAttribute("defaultValue"); - - return new RecordItemInfoT(subIndex, defaultValue); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.DeviceFunction; + +namespace IOLink.NET.IODD.Parts.DeviceFunction; + +internal class RecordItemInfoParser : IParserPart +{ + + public RecordItemInfoParser() + { + } + + public bool CanParse(XName name) + => name == IODDDeviceFunctionNames.RecordItemInfoName; + + public RecordItemInfoT Parse(XElement element) + { + byte subIndex = element.ReadMandatoryAttribute("subIndex"); + string? defaultValue = element.ReadOptionalAttribute("defaultValue"); + + return new RecordItemInfoT(subIndex, defaultValue); + } +} diff --git a/src/IODD.Parser/Parts/DeviceFunction/StandardVariableRefTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/StandardVariableRefTParser.cs similarity index 82% rename from src/IODD.Parser/Parts/DeviceFunction/StandardVariableRefTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/StandardVariableRefTParser.cs index 9d2f791..84636ad 100644 --- a/src/IODD.Parser/Parts/DeviceFunction/StandardVariableRefTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/StandardVariableRefTParser.cs @@ -1,16 +1,16 @@ using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Parser.Parts.Constants; -using IOLinkNET.IODD.Parts.Constants; -using IOLinkNET.IODD.Parts.Datatypes; -using IOLinkNET.IODD.Standard.Structure; -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.DeviceFunction; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Parser.Parts.Constants; +using IOLink.NET.IODD.Parts.Constants; +using IOLink.NET.IODD.Parts.Datatypes; +using IOLink.NET.IODD.Standard.Structure; +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.DeviceFunction; -namespace IOLinkNET.IODD.Parts.DeviceFunction; +namespace IOLink.NET.IODD.Parts.DeviceFunction; internal class StandardVariableRefTParser { @@ -40,4 +40,4 @@ public VariableT Parse(XElement element) var id = stdVariable.ReadMandatoryAttribute("id"); return new VariableT(id, index, dataType, dataTypeRef, name, description, accessRights, recordItemInfos); } -} \ No newline at end of file +} diff --git a/src/IODD.Parser/Parts/DeviceFunction/VariableTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/VariableTParser.cs similarity index 80% rename from src/IODD.Parser/Parts/DeviceFunction/VariableTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/VariableTParser.cs index bca3ef2..bb16e23 100644 --- a/src/IODD.Parser/Parts/DeviceFunction/VariableTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/DeviceFunction/VariableTParser.cs @@ -1,38 +1,38 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; -using IOLinkNET.IODD.Parts.Datatypes; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.DeviceFunction; - -namespace IOLinkNET.IODD.Parts.DeviceFunction; - -internal class VariableTParser : IParserPart -{ - private readonly IParserPartLocator _parserLocator; - - public VariableTParser(IParserPartLocator parserLocator) - { - _parserLocator = parserLocator; - } - public bool CanParse(XName name) - => name == IODDDeviceFunctionNames.VariableName; - - public VariableT Parse(XElement element) - { - DatatypeT? dataType = DatatypeTParser.ParseOptional(element.Descendants(IODDParserConstants.DatatypeName).FirstOrDefault(), _parserLocator); - DatatypeRefT? dataTypeRef = _parserLocator.ParseOptional(element.Descendants(IODDParserConstants.DatatypeRefName).FirstOrDefault()); - TextRefT name = _parserLocator.ParseMandatory(element.Element(IODDTextRefNames.Name)); - TextRefT? description = _parserLocator.ParseOptional(element.Element(IODDTextRefNames.DescriptionName)); - AccessRightsT accessRights = AccessRightsTConverter.Parse(element.ReadMandatoryAttribute("accessRights")); - IEnumerable recordItemInfos = element.Descendants(IODDDeviceFunctionNames.RecordItemInfoName).Select(_parserLocator.Parse); - ushort index = element.ReadMandatoryAttribute("index"); - var id = element.ReadMandatoryAttribute("id"); - - return new VariableT(id, index, dataType, dataTypeRef, name, description, accessRights, recordItemInfos); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; +using IOLink.NET.IODD.Parts.Datatypes; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.DeviceFunction; + +namespace IOLink.NET.IODD.Parts.DeviceFunction; + +internal class VariableTParser : IParserPart +{ + private readonly IParserPartLocator _parserLocator; + + public VariableTParser(IParserPartLocator parserLocator) + { + _parserLocator = parserLocator; + } + public bool CanParse(XName name) + => name == IODDDeviceFunctionNames.VariableName; + + public VariableT Parse(XElement element) + { + DatatypeT? dataType = DatatypeTParser.ParseOptional(element.Descendants(IODDParserConstants.DatatypeName).FirstOrDefault(), _parserLocator); + DatatypeRefT? dataTypeRef = _parserLocator.ParseOptional(element.Descendants(IODDParserConstants.DatatypeRefName).FirstOrDefault()); + TextRefT name = _parserLocator.ParseMandatory(element.Element(IODDTextRefNames.Name)); + TextRefT? description = _parserLocator.ParseOptional(element.Element(IODDTextRefNames.DescriptionName)); + AccessRightsT accessRights = AccessRightsTConverter.Parse(element.ReadMandatoryAttribute("accessRights")); + IEnumerable recordItemInfos = element.Descendants(IODDDeviceFunctionNames.RecordItemInfoName).Select(_parserLocator.Parse); + ushort index = element.ReadMandatoryAttribute("index"); + var id = element.ReadMandatoryAttribute("id"); + + return new VariableT(id, index, dataType, dataTypeRef, name, description, accessRights, recordItemInfos); + } +} diff --git a/src/IODD.Parser/Parts/DeviceIdentityParser.cs b/src/IOLink.NET.IODD/Parser/Parts/DeviceIdentityParser.cs similarity index 87% rename from src/IODD.Parser/Parts/DeviceIdentityParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/DeviceIdentityParser.cs index f61ad73..78100cb 100644 --- a/src/IODD.Parser/Parts/DeviceIdentityParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/DeviceIdentityParser.cs @@ -1,44 +1,44 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Profile; - -namespace IOLinkNET.IODD.Parts; - -internal class DeviceIdentityParser : IParserPart -{ - private readonly IParserPartLocator _parserLocator; - - public DeviceIdentityParser(IParserPartLocator parserLocator) - { - _parserLocator = parserLocator; - } - public static XName Target => IODDParserConstants.DeviceIdentityName; - - public bool CanParse(XName name) => name == Target; - - public DeviceIdentityT Parse(XElement element) - { - uint deviceId = element.ReadMandatoryAttribute("deviceId"); - ushort vendorId = element.ReadMandatoryAttribute("vendorId"); - string vendorName = element.ReadMandatoryAttribute("vendorName"); - (TextRefT deviceName, TextRefT vendorText, TextRefT vendorUrl, TextRefT deviceFamilyName) = GetChildTextRefs(element); - - return new DeviceIdentityT(vendorId, deviceId, vendorName, vendorText, vendorUrl, deviceName, deviceFamilyName); - } - - private (TextRefT DeviceName, TextRefT VendorName, TextRefT VendorUrl, TextRefT DeviceFamilyName) GetChildTextRefs(XElement element) - { - TextRefT vendorTextRef = _parserLocator.ParseMandatory(element.Descendants(IODDTextRefNames.VendorTextName).FirstOrDefault()); - TextRefT vendorUrlRef = _parserLocator.ParseMandatory(element.Descendants(IODDTextRefNames.VendorUrlName).FirstOrDefault()); - - TextRefT deviceName = _parserLocator.ParseMandatory(element.Descendants(IODDTextRefNames.DeviceNameName).FirstOrDefault()); - TextRefT deviceFamiliy = _parserLocator.ParseMandatory(element.Descendants(IODDTextRefNames.DeviceFamilyName).FirstOrDefault()); - - return (deviceName, vendorTextRef, vendorUrlRef, deviceFamiliy); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Profile; + +namespace IOLink.NET.IODD.Parts; + +internal class DeviceIdentityParser : IParserPart +{ + private readonly IParserPartLocator _parserLocator; + + public DeviceIdentityParser(IParserPartLocator parserLocator) + { + _parserLocator = parserLocator; + } + public static XName Target => IODDParserConstants.DeviceIdentityName; + + public bool CanParse(XName name) => name == Target; + + public DeviceIdentityT Parse(XElement element) + { + uint deviceId = element.ReadMandatoryAttribute("deviceId"); + ushort vendorId = element.ReadMandatoryAttribute("vendorId"); + string vendorName = element.ReadMandatoryAttribute("vendorName"); + (TextRefT deviceName, TextRefT vendorText, TextRefT vendorUrl, TextRefT deviceFamilyName) = GetChildTextRefs(element); + + return new DeviceIdentityT(vendorId, deviceId, vendorName, vendorText, vendorUrl, deviceName, deviceFamilyName); + } + + private (TextRefT DeviceName, TextRefT VendorName, TextRefT VendorUrl, TextRefT DeviceFamilyName) GetChildTextRefs(XElement element) + { + TextRefT vendorTextRef = _parserLocator.ParseMandatory(element.Descendants(IODDTextRefNames.VendorTextName).FirstOrDefault()); + TextRefT vendorUrlRef = _parserLocator.ParseMandatory(element.Descendants(IODDTextRefNames.VendorUrlName).FirstOrDefault()); + + TextRefT deviceName = _parserLocator.ParseMandatory(element.Descendants(IODDTextRefNames.DeviceNameName).FirstOrDefault()); + TextRefT deviceFamiliy = _parserLocator.ParseMandatory(element.Descendants(IODDTextRefNames.DeviceFamilyName).FirstOrDefault()); + + return (deviceName, vendorTextRef, vendorUrlRef, deviceFamiliy); + } +} diff --git a/src/IODD.Parser/Parts/ExternalTextCollection/ExternalTextCollectionTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/ExternalTextCollection/ExternalTextCollectionTParser.cs similarity index 79% rename from src/IODD.Parser/Parts/ExternalTextCollection/ExternalTextCollectionTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/ExternalTextCollection/ExternalTextCollectionTParser.cs index 695f1da..b3867c8 100644 --- a/src/IODD.Parser/Parts/ExternalTextCollection/ExternalTextCollectionTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/ExternalTextCollection/ExternalTextCollectionTParser.cs @@ -1,10 +1,10 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Parser.Parts.Constants; -using IOLinkNET.IODD.Structure.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Structure.ExternalTextCollection; +using IOLink.NET.IODD.Parser.Parts.Constants; +using IOLink.NET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Structure.ExternalTextCollection; -namespace IOLinkNET.IODD.Parser.Parts.ExternalTextCollection; +namespace IOLink.NET.IODD.Parser.Parts.ExternalTextCollection; internal class ExternalTextCollectionTParser : IParserPart { public bool CanParse(XName name) => name == IODDParserConstants.ExternalTextCollectionName; diff --git a/src/IODD.Parser/Parts/ExternalTextCollection/PrimaryLanguageTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/ExternalTextCollection/PrimaryLanguageTParser.cs similarity index 58% rename from src/IODD.Parser/Parts/ExternalTextCollection/PrimaryLanguageTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/ExternalTextCollection/PrimaryLanguageTParser.cs index 9e9bd23..7533000 100644 --- a/src/IODD.Parser/Parts/ExternalTextCollection/PrimaryLanguageTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/ExternalTextCollection/PrimaryLanguageTParser.cs @@ -1,9 +1,9 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Structure.Structure.ExternalTextCollection; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Structure.Structure.ExternalTextCollection; -namespace IOLinkNET.IODD.Parser.Parts.ExternalTextCollection; +namespace IOLink.NET.IODD.Parser.Parts.ExternalTextCollection; internal static class PrimaryLanguageTParser { public static PrimaryLanguageT Parse(XElement element) diff --git a/src/IODD.Parser/Parts/ExternalTextCollection/TextDefinitionTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/ExternalTextCollection/TextDefinitionTParser.cs similarity index 63% rename from src/IODD.Parser/Parts/ExternalTextCollection/TextDefinitionTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/ExternalTextCollection/TextDefinitionTParser.cs index d7ad45f..0f5a343 100644 --- a/src/IODD.Parser/Parts/ExternalTextCollection/TextDefinitionTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/ExternalTextCollection/TextDefinitionTParser.cs @@ -1,9 +1,9 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Structure.Structure.Datatypes; -namespace IOLinkNET.IODD.Parser.Parts.ExternalTextCollection; +namespace IOLink.NET.IODD.Parser.Parts.ExternalTextCollection; internal static class TextDefinitionTParser { public static TextDefinitionT Parse(XElement element) diff --git a/src/IODD.Parser/Parts/Menu/MenuCollectionTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Menu/MenuCollectionTParser.cs similarity index 76% rename from src/IODD.Parser/Parts/Menu/MenuCollectionTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Menu/MenuCollectionTParser.cs index 0f12aea..1c06ad4 100644 --- a/src/IODD.Parser/Parts/Menu/MenuCollectionTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Menu/MenuCollectionTParser.cs @@ -1,9 +1,9 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Parts.Constants; -using IOLinkNET.IODD.Structure.Structure.Menu; +using IOLink.NET.IODD.Parts.Constants; +using IOLink.NET.IODD.Structure.Structure.Menu; -namespace IOLinkNET.IODD.Parser.Parts.Menu; +namespace IOLink.NET.IODD.Parser.Parts.Menu; internal class MenuCollectionTParser : IParserPart { private readonly IParserPartLocator _parserLocator; diff --git a/src/IODD.Parser/Parts/Menu/MenuElementParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Menu/MenuElementParser.cs similarity index 89% rename from src/IODD.Parser/Parts/Menu/MenuElementParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Menu/MenuElementParser.cs index b9957f3..ad7c55a 100644 --- a/src/IODD.Parser/Parts/Menu/MenuElementParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Menu/MenuElementParser.cs @@ -1,11 +1,11 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; -using IOLinkNET.IODD.Structure.Structure.ExternalTextCollection; -using IOLinkNET.IODD.Structure.Structure.Menu; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; +using IOLink.NET.IODD.Structure.Structure.ExternalTextCollection; +using IOLink.NET.IODD.Structure.Structure.Menu; -namespace IOLinkNET.IODD.Parser.Parts.Menu; +namespace IOLink.NET.IODD.Parser.Parts.Menu; internal class MenuElementParser : IParserPart { private readonly IParserPartLocator _parserLocator; diff --git a/src/IODD.Parser/Parts/Menu/MenuSetTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Menu/MenuSetTParser.cs similarity index 90% rename from src/IODD.Parser/Parts/Menu/MenuSetTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Menu/MenuSetTParser.cs index 32f3a14..e0461cc 100644 --- a/src/IODD.Parser/Parts/Menu/MenuSetTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Menu/MenuSetTParser.cs @@ -1,15 +1,15 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; -using IOLinkNET.IODD.Structure.Structure.Menu; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; +using IOLink.NET.IODD.Structure.Structure.Menu; -namespace IOLinkNET.IODD.Parser.Parts.Menu; +namespace IOLink.NET.IODD.Parser.Parts.Menu; internal static class MenuSetTParser { public static MenuSetT Parse(XElement element, IEnumerable menuCollections) diff --git a/src/IODD.Parser/Parts/Menu/UIMenuRefTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Menu/UIMenuRefTParser.cs similarity index 75% rename from src/IODD.Parser/Parts/Menu/UIMenuRefTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Menu/UIMenuRefTParser.cs index 7c20b32..94369b9 100644 --- a/src/IODD.Parser/Parts/Menu/UIMenuRefTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Menu/UIMenuRefTParser.cs @@ -1,11 +1,11 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; -using IOLinkNET.IODD.Structure.ProcessData; -using IOLinkNET.IODD.Structure.Structure.Menu; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; +using IOLink.NET.IODD.Structure.ProcessData; +using IOLink.NET.IODD.Structure.Structure.Menu; -namespace IOLinkNET.IODD.Parser.Parts.Menu; +namespace IOLink.NET.IODD.Parser.Parts.Menu; internal class UIMenuRefTParser : IParserPart { private readonly IParserPartLocator _parserLocator; diff --git a/src/IODD.Parser/Parts/Menu/UIRecordItemRefTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Menu/UIRecordItemRefTParser.cs similarity index 82% rename from src/IODD.Parser/Parts/Menu/UIRecordItemRefTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Menu/UIRecordItemRefTParser.cs index 9cc82d1..8f78112 100644 --- a/src/IODD.Parser/Parts/Menu/UIRecordItemRefTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Menu/UIRecordItemRefTParser.cs @@ -1,11 +1,11 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Structure.Menu; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Structure.Menu; -namespace IOLinkNET.IODD.Parser.Parts.Menu; +namespace IOLink.NET.IODD.Parser.Parts.Menu; internal static class UIRecordItemRefTParser { public static UIRecordItemRefT Parse(XElement element) diff --git a/src/IODD.Parser/Parts/Menu/UIVariableRefTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Menu/UIVariableRefTParser.cs similarity index 81% rename from src/IODD.Parser/Parts/Menu/UIVariableRefTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Menu/UIVariableRefTParser.cs index 1c5650e..34a76e5 100644 --- a/src/IODD.Parser/Parts/Menu/UIVariableRefTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Menu/UIVariableRefTParser.cs @@ -1,11 +1,11 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Structure.Menu; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Structure.Menu; -namespace IOLinkNET.IODD.Parser.Parts.Menu; +namespace IOLink.NET.IODD.Parser.Parts.Menu; internal static class UIVariableRefTParser { public static UIVariableRefT Parse(XElement element) diff --git a/src/IODD.Parser/Parts/Menu/UserInterfaceParser.cs b/src/IOLink.NET.IODD/Parser/Parts/Menu/UserInterfaceParser.cs similarity index 89% rename from src/IODD.Parser/Parts/Menu/UserInterfaceParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/Menu/UserInterfaceParser.cs index 02fd130..222d1ad 100644 --- a/src/IODD.Parser/Parts/Menu/UserInterfaceParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/Menu/UserInterfaceParser.cs @@ -1,10 +1,10 @@ -using System.Xml.Linq; +using System.Xml.Linq; -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; -using IOLinkNET.IODD.Structure.Structure.Menu; +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; +using IOLink.NET.IODD.Structure.Structure.Menu; -namespace IOLinkNET.IODD.Parser.Parts.Menu; +namespace IOLink.NET.IODD.Parser.Parts.Menu; internal class UserInterfaceParser : IParserPart { private readonly IParserPartLocator _parserLocator; diff --git a/src/IODD.Parser/Parts/ParserPartLocator.cs b/src/IOLink.NET.IODD/Parser/Parts/ParserPartLocator.cs similarity index 89% rename from src/IODD.Parser/Parts/ParserPartLocator.cs rename to src/IOLink.NET.IODD/Parser/Parts/ParserPartLocator.cs index c1a7d24..5892ef1 100644 --- a/src/IODD.Parser/Parts/ParserPartLocator.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/ParserPartLocator.cs @@ -1,38 +1,38 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Parser; - -namespace IOLinkNET.IODD.Parts; - -internal class ParserPartLocator : IParserPartLocator -{ - private readonly IList _parserParts = new List(); - - public ParserPartLocator(IEnumerable parts) - { - AddParts(parts); - } - - public ParserPartLocator() - { - - } - - public void AddPart(IParserPart part) => _parserParts.Add(part); - - private void AddParts(IEnumerable parts) - { - foreach (IParserPart part in parts) - { - AddPart(part); - } - } - - public T Parse(XElement element) - { - IParserPart part = _parserParts.OfType>().FirstOrDefault(part => part.CanParse(element.Name)) - ?? throw new InvalidOperationException($"Could not find suitable implementation part for {typeof(T).Name}."); - - return part.Parse(element); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Parser; + +namespace IOLink.NET.IODD.Parts; + +internal class ParserPartLocator : IParserPartLocator +{ + private readonly IList _parserParts = new List(); + + public ParserPartLocator(IEnumerable parts) + { + AddParts(parts); + } + + public ParserPartLocator() + { + + } + + public void AddPart(IParserPart part) => _parserParts.Add(part); + + private void AddParts(IEnumerable parts) + { + foreach (IParserPart part in parts) + { + AddPart(part); + } + } + + public T Parse(XElement element) + { + IParserPart part = _parserParts.OfType>().FirstOrDefault(part => part.CanParse(element.Name)) + ?? throw new InvalidOperationException($"Could not find suitable implementation part for {typeof(T).Name}."); + + return part.Parse(element); + } +} diff --git a/src/IODD.Parser/Parts/TextRefTParser.cs b/src/IOLink.NET.IODD/Parser/Parts/TextRefTParser.cs similarity index 75% rename from src/IODD.Parser/Parts/TextRefTParser.cs rename to src/IOLink.NET.IODD/Parser/Parts/TextRefTParser.cs index d2e14e2..ce4d911 100644 --- a/src/IODD.Parser/Parts/TextRefTParser.cs +++ b/src/IOLink.NET.IODD/Parser/Parts/TextRefTParser.cs @@ -1,25 +1,25 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Helpers; -using IOLinkNET.IODD.Parts.Constants; - -using IOLinkNET.IODD.Parser; -using IOLinkNET.IODD.Structure.Common; - -namespace IOLinkNET.IODD.Parts; - -internal class TextRefTParser : IParserPart -{ - private static readonly IEnumerable Targets = new[] { IODDTextRefNames.DeviceFamilyName, IODDTextRefNames.DeviceNameName, - IODDTextRefNames.VendorTextName, IODDTextRefNames.VendorUrlName, IODDTextRefNames.Name, IODDTextRefNames.DescriptionName }; - - public bool CanParse(XName name) - => Targets.Contains(name); - - public TextRefT Parse(XElement element) - { - string textId = element.ReadMandatoryAttribute("textId"); - - return new TextRefT(textId); - } -} \ No newline at end of file +using System.Xml.Linq; + +using IOLink.NET.IODD.Helpers; +using IOLink.NET.IODD.Parts.Constants; + +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure.Common; + +namespace IOLink.NET.IODD.Parts; + +internal class TextRefTParser : IParserPart +{ + private static readonly IEnumerable Targets = new[] { IODDTextRefNames.DeviceFamilyName, IODDTextRefNames.DeviceNameName, + IODDTextRefNames.VendorTextName, IODDTextRefNames.VendorUrlName, IODDTextRefNames.Name, IODDTextRefNames.DescriptionName }; + + public bool CanParse(XName name) + => Targets.Contains(name); + + public TextRefT Parse(XElement element) + { + string textId = element.ReadMandatoryAttribute("textId"); + + return new TextRefT(textId); + } +} diff --git a/src/IODD.Provider/Contracts/IDeviceDefinitionProvider.cs b/src/IOLink.NET.IODD/Provider/Contracts/IDeviceDefinitionProvider.cs similarity index 72% rename from src/IODD.Provider/Contracts/IDeviceDefinitionProvider.cs rename to src/IOLink.NET.IODD/Provider/Contracts/IDeviceDefinitionProvider.cs index 58994fe..a7d946b 100644 --- a/src/IODD.Provider/Contracts/IDeviceDefinitionProvider.cs +++ b/src/IOLink.NET.IODD/Provider/Contracts/IDeviceDefinitionProvider.cs @@ -1,8 +1,8 @@ -using IOLinkNET.IODD.Structure; +using IOLink.NET.IODD.Structure; -namespace IOLinkNET.IODD.Provider; +namespace IOLink.NET.IODD.Provider; public interface IDeviceDefinitionProvider { Task GetDeviceDefinitionAsync(ushort vendorId, uint deviceId, string productId, CancellationToken cancellationToken = default); -} \ No newline at end of file +} diff --git a/src/IODD.Provider/Contracts/IIODDProvider.cs b/src/IOLink.NET.IODD/Provider/Contracts/IIODDProvider.cs similarity index 81% rename from src/IODD.Provider/Contracts/IIODDProvider.cs rename to src/IOLink.NET.IODD/Provider/Contracts/IIODDProvider.cs index 79e7890..21814d0 100644 --- a/src/IODD.Provider/Contracts/IIODDProvider.cs +++ b/src/IOLink.NET.IODD/Provider/Contracts/IIODDProvider.cs @@ -1,6 +1,6 @@ -namespace IOLinkNET.IODD.Provider; +namespace IOLink.NET.IODD.Provider; public interface IIODDProvider { Task GetIODDPackageAsync(ushort vendorId, uint deviceId, string productId, CancellationToken cancellationToken = default); -} \ No newline at end of file +} diff --git a/src/IODD.Provider/Data/IODDFinderSearchEntry.cs b/src/IOLink.NET.IODD/Provider/Data/IODDFinderSearchEntry.cs similarity index 74% rename from src/IODD.Provider/Data/IODDFinderSearchEntry.cs rename to src/IOLink.NET.IODD/Provider/Data/IODDFinderSearchEntry.cs index cf34d67..f8d333c 100644 --- a/src/IODD.Provider/Data/IODDFinderSearchEntry.cs +++ b/src/IOLink.NET.IODD/Provider/Data/IODDFinderSearchEntry.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Provider.Data; +namespace IOLink.NET.IODD.Provider.Data; public record IODDFinderSearchEntry(uint VendorId, uint DeviceId, string ProductId, uint IoddId, string IoLinkRev); diff --git a/src/IODD.Provider/Data/IODDFinderSearchResponse.cs b/src/IOLink.NET.IODD/Provider/Data/IODDFinderSearchResponse.cs similarity index 67% rename from src/IODD.Provider/Data/IODDFinderSearchResponse.cs rename to src/IOLink.NET.IODD/Provider/Data/IODDFinderSearchResponse.cs index 5d1553f..c23fddd 100644 --- a/src/IODD.Provider/Data/IODDFinderSearchResponse.cs +++ b/src/IOLink.NET.IODD/Provider/Data/IODDFinderSearchResponse.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Provider.Data; +namespace IOLink.NET.IODD.Provider.Data; public record IODDFinderSearchResponse(IEnumerable Content); diff --git a/src/IODD.Provider/DeviceDefinitionProvider.cs b/src/IOLink.NET.IODD/Provider/DeviceDefinitionProvider.cs similarity index 94% rename from src/IODD.Provider/DeviceDefinitionProvider.cs rename to src/IOLink.NET.IODD/Provider/DeviceDefinitionProvider.cs index 2229767..2fc81e7 100644 --- a/src/IODD.Provider/DeviceDefinitionProvider.cs +++ b/src/IOLink.NET.IODD/Provider/DeviceDefinitionProvider.cs @@ -1,8 +1,9 @@ using System.IO.Compression; using System.Xml.Linq; -using IOLinkNET.IODD.Structure; +using IOLink.NET.IODD.Parser; +using IOLink.NET.IODD.Structure; -namespace IOLinkNET.IODD.Provider; +namespace IOLink.NET.IODD.Provider; public class DeviceDefinitionProvider : IDeviceDefinitionProvider { diff --git a/src/IODD.Provider/IODDFinderPublicClient.cs b/src/IOLink.NET.IODD/Provider/IODDFinderPublicClient.cs similarity index 96% rename from src/IODD.Provider/IODDFinderPublicClient.cs rename to src/IOLink.NET.IODD/Provider/IODDFinderPublicClient.cs index 532d9e7..132d836 100644 --- a/src/IODD.Provider/IODDFinderPublicClient.cs +++ b/src/IOLink.NET.IODD/Provider/IODDFinderPublicClient.cs @@ -1,8 +1,8 @@ using System.Net.Http; using System.Net.Http.Json; -using IOLinkNET.IODD.Provider.Data; +using IOLink.NET.IODD.Provider.Data; -namespace IOLinkNET.IODD.Provider; +namespace IOLink.NET.IODD.Provider; public class IODDFinderPublicClient : IIODDProvider { diff --git a/src/IODD.Resolution/Common/DefaultTypeResolverFactory.cs b/src/IOLink.NET.IODD/Resolution/Common/DefaultTypeResolverFactory.cs similarity index 74% rename from src/IODD.Resolution/Common/DefaultTypeResolverFactory.cs rename to src/IOLink.NET.IODD/Resolution/Common/DefaultTypeResolverFactory.cs index 26edd0f..43b0864 100644 --- a/src/IODD.Resolution/Common/DefaultTypeResolverFactory.cs +++ b/src/IOLink.NET.IODD/Resolution/Common/DefaultTypeResolverFactory.cs @@ -1,7 +1,7 @@ -using IOLinkNET.IODD.Resolution.Contracts; -using IOLinkNET.IODD.Structure; +using IOLink.NET.IODD.Resolution.Contracts; +using IOLink.NET.IODD.Structure; -namespace IOLinkNET.IODD.Resolution.Common; +namespace IOLink.NET.IODD.Resolution.Common; public class DefaultTypeResolverFactory : ITypeResolverFactory { @@ -10,4 +10,4 @@ public IProcessDataTypeResolver CreateProcessDataTypeResolver(IODevice deviceDef public IParameterTypeResolver CreateParameterTypeResolver(IODevice deviceDefinition) => new ParameterTypeResolver(deviceDefinition); -} \ No newline at end of file +} diff --git a/src/IODD.Resolution/Contracts/IParameterTypeResolver.cs b/src/IOLink.NET.IODD/Resolution/Contracts/IParameterTypeResolver.cs similarity index 69% rename from src/IODD.Resolution/Contracts/IParameterTypeResolver.cs rename to src/IOLink.NET.IODD/Resolution/Contracts/IParameterTypeResolver.cs index 480082d..3323062 100644 --- a/src/IODD.Resolution/Contracts/IParameterTypeResolver.cs +++ b/src/IOLink.NET.IODD/Resolution/Contracts/IParameterTypeResolver.cs @@ -1,6 +1,6 @@ -namespace IOLinkNET.IODD.Resolution.Contracts; +namespace IOLink.NET.IODD.Resolution.Contracts; public interface IParameterTypeResolver { ParsableDatatype GetParameter(int index, byte? subIndex = null); -} \ No newline at end of file +} diff --git a/src/IODD.Resolution/Contracts/IProcessDataTypeResolver.cs b/src/IOLink.NET.IODD/Resolution/Contracts/IProcessDataTypeResolver.cs similarity index 96% rename from src/IODD.Resolution/Contracts/IProcessDataTypeResolver.cs rename to src/IOLink.NET.IODD/Resolution/Contracts/IProcessDataTypeResolver.cs index 42d4972..b97bda6 100644 --- a/src/IODD.Resolution/Contracts/IProcessDataTypeResolver.cs +++ b/src/IOLink.NET.IODD/Resolution/Contracts/IProcessDataTypeResolver.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.IODD.Resolution.Contracts; +namespace IOLink.NET.IODD.Resolution.Contracts; public interface IProcessDataTypeResolver { @@ -27,4 +27,4 @@ public interface IProcessDataTypeResolver /// The currently active condition value /// A representation of the iodd data type that can be used to convert binary IO-Link data. ParsableDatatype? ResolveProcessDataOut(int? condition = null); -} \ No newline at end of file +} diff --git a/src/IODD.Resolution/Contracts/ITypeResolverFactory.cs b/src/IOLink.NET.IODD/Resolution/Contracts/ITypeResolverFactory.cs similarity index 89% rename from src/IODD.Resolution/Contracts/ITypeResolverFactory.cs rename to src/IOLink.NET.IODD/Resolution/Contracts/ITypeResolverFactory.cs index 9b82b27..7889958 100644 --- a/src/IODD.Resolution/Contracts/ITypeResolverFactory.cs +++ b/src/IOLink.NET.IODD/Resolution/Contracts/ITypeResolverFactory.cs @@ -1,6 +1,6 @@ -using IOLinkNET.IODD.Structure; +using IOLink.NET.IODD.Structure; -namespace IOLinkNET.IODD.Resolution.Contracts; +namespace IOLink.NET.IODD.Resolution.Contracts; public interface ITypeResolverFactory { @@ -16,4 +16,4 @@ public interface ITypeResolverFactory /// The device definition. /// IParameterTypeResolver CreateParameterTypeResolver(IODevice deviceDefinition); -} \ No newline at end of file +} diff --git a/src/IODD.Resolution/Model/KindOfSimpleType.cs b/src/IOLink.NET.IODD/Resolution/Model/KindOfSimpleType.cs similarity index 75% rename from src/IODD.Resolution/Model/KindOfSimpleType.cs rename to src/IOLink.NET.IODD/Resolution/Model/KindOfSimpleType.cs index 232dc98..2f56a05 100644 --- a/src/IODD.Resolution/Model/KindOfSimpleType.cs +++ b/src/IOLink.NET.IODD/Resolution/Model/KindOfSimpleType.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public enum KindOfSimpleType { @@ -9,4 +9,4 @@ public enum KindOfSimpleType String, OctetString, TimespanT -} \ No newline at end of file +} diff --git a/src/IODD.Resolution/Model/ParsableArray.cs b/src/IOLink.NET.IODD/Resolution/Model/ParsableArray.cs similarity index 82% rename from src/IODD.Resolution/Model/ParsableArray.cs rename to src/IOLink.NET.IODD/Resolution/Model/ParsableArray.cs index 6a6febf..958565e 100644 --- a/src/IODD.Resolution/Model/ParsableArray.cs +++ b/src/IOLink.NET.IODD/Resolution/Model/ParsableArray.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public record ParsableArray(string Name, ParsableSimpleDatatypeDef Type, bool SubindexAccessSupported, ushort Length) : ParsableComplexDataTypeDef(Name, SubindexAccessSupported); diff --git a/src/IODD.Resolution/Model/ParsableComplexDataTypeDef.cs b/src/IOLink.NET.IODD/Resolution/Model/ParsableComplexDataTypeDef.cs similarity index 78% rename from src/IODD.Resolution/Model/ParsableComplexDataTypeDef.cs rename to src/IOLink.NET.IODD/Resolution/Model/ParsableComplexDataTypeDef.cs index 1b2ce0f..05de1f3 100644 --- a/src/IODD.Resolution/Model/ParsableComplexDataTypeDef.cs +++ b/src/IOLink.NET.IODD/Resolution/Model/ParsableComplexDataTypeDef.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public record ParsableComplexDataTypeDef(string Name, bool SubindexAccessSupported) : ParsableDatatype(Name, SubindexAccessSupported); diff --git a/src/IODD.Resolution/Model/ParsableDatatype.cs b/src/IOLink.NET.IODD/Resolution/Model/ParsableDatatype.cs similarity index 68% rename from src/IODD.Resolution/Model/ParsableDatatype.cs rename to src/IOLink.NET.IODD/Resolution/Model/ParsableDatatype.cs index 401b952..efd7d74 100644 --- a/src/IODD.Resolution/Model/ParsableDatatype.cs +++ b/src/IOLink.NET.IODD/Resolution/Model/ParsableDatatype.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public record ParsableDatatype(string Name, bool SubindexAccessSupported = true); diff --git a/src/IODD.Resolution/Model/ParsableRecord.cs b/src/IOLink.NET.IODD/Resolution/Model/ParsableRecord.cs similarity index 83% rename from src/IODD.Resolution/Model/ParsableRecord.cs rename to src/IOLink.NET.IODD/Resolution/Model/ParsableRecord.cs index f1c6a94..06f07de 100644 --- a/src/IODD.Resolution/Model/ParsableRecord.cs +++ b/src/IOLink.NET.IODD/Resolution/Model/ParsableRecord.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public record ParsableRecord(string Name, ushort Length, bool SubindexAccessSupported, IEnumerable Entries) : ParsableComplexDataTypeDef(Name, SubindexAccessSupported); diff --git a/src/IODD.Resolution/Model/ParsableRecordItem.cs b/src/IOLink.NET.IODD/Resolution/Model/ParsableRecordItem.cs similarity index 75% rename from src/IODD.Resolution/Model/ParsableRecordItem.cs rename to src/IOLink.NET.IODD/Resolution/Model/ParsableRecordItem.cs index c9e637f..c2749b0 100644 --- a/src/IODD.Resolution/Model/ParsableRecordItem.cs +++ b/src/IOLink.NET.IODD/Resolution/Model/ParsableRecordItem.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public record ParsableRecordItem(ParsableSimpleDatatypeDef Type, string Name, ushort BitOffset, ushort Subindex); diff --git a/src/IODD.Resolution/Model/ParsableSimpleDatatypeDef.cs b/src/IOLink.NET.IODD/Resolution/Model/ParsableSimpleDatatypeDef.cs similarity index 76% rename from src/IODD.Resolution/Model/ParsableSimpleDatatypeDef.cs rename to src/IOLink.NET.IODD/Resolution/Model/ParsableSimpleDatatypeDef.cs index df2d4e5..71db61c 100644 --- a/src/IODD.Resolution/Model/ParsableSimpleDatatypeDef.cs +++ b/src/IOLink.NET.IODD/Resolution/Model/ParsableSimpleDatatypeDef.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public record ParsableSimpleDatatypeDef(string Name, KindOfSimpleType Datatype, ushort Length) : ParsableDatatype(Name); diff --git a/src/IODD.Resolution/Model/ParsableStringDef.cs b/src/IOLink.NET.IODD/Resolution/Model/ParsableStringDef.cs similarity index 65% rename from src/IODD.Resolution/Model/ParsableStringDef.cs rename to src/IOLink.NET.IODD/Resolution/Model/ParsableStringDef.cs index 8e73e3b..9bcbd96 100644 --- a/src/IODD.Resolution/Model/ParsableStringDef.cs +++ b/src/IOLink.NET.IODD/Resolution/Model/ParsableStringDef.cs @@ -1,5 +1,5 @@ -using IOLinkNET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Datatypes; -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public record ParsableStringDef(string Name, ushort Length, StringTEncoding Encoding) : ParsableSimpleDatatypeDef(Name, KindOfSimpleType.String, Length); diff --git a/src/IOLink.NET.IODD/Resolution/Model/ResolvedCondition.cs b/src/IOLink.NET.IODD/Resolution/Model/ResolvedCondition.cs new file mode 100644 index 0000000..481641c --- /dev/null +++ b/src/IOLink.NET.IODD/Resolution/Model/ResolvedCondition.cs @@ -0,0 +1,7 @@ + +using IOLink.NET.IODD.Structure.DeviceFunction; +using IOLink.NET.IODD.Structure.ProcessData; + +namespace IOLink.NET.IODD.Resolution; + +public record ResolvedCondition(ConditionT ConditionDef, VariableT VariableDef); diff --git a/src/IODD.Resolution/Resolver/DatatypeResolver.cs b/src/IOLink.NET.IODD/Resolution/Resolver/DatatypeResolver.cs similarity index 80% rename from src/IODD.Resolution/Resolver/DatatypeResolver.cs rename to src/IOLink.NET.IODD/Resolution/Resolver/DatatypeResolver.cs index 659b734..10b5c63 100644 --- a/src/IODD.Resolution/Resolver/DatatypeResolver.cs +++ b/src/IOLink.NET.IODD/Resolution/Resolver/DatatypeResolver.cs @@ -1,7 +1,7 @@ -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Interfaces; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Interfaces; -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; internal class DatatypeResolver { @@ -15,4 +15,4 @@ public DatatypeResolver(IEnumerable datatypes, IEnumerable public DatatypeT Resolve(IDatatypeOrTypeRef resolvee) => resolvee.Type ?? _datatypes.FirstOrDefault(type => type.Id == resolvee.Ref?.DatatypeId) ?? throw new ArgumentOutOfRangeException(nameof(resolvee), "Datatype could not be resolved."); -} \ No newline at end of file +} diff --git a/src/IODD.Resolution/Resolver/ParameterTypeResolver.cs b/src/IOLink.NET.IODD/Resolution/Resolver/ParameterTypeResolver.cs similarity index 91% rename from src/IODD.Resolution/Resolver/ParameterTypeResolver.cs rename to src/IOLink.NET.IODD/Resolution/Resolver/ParameterTypeResolver.cs index a55f417..6b8160e 100644 --- a/src/IODD.Resolution/Resolver/ParameterTypeResolver.cs +++ b/src/IOLink.NET.IODD/Resolution/Resolver/ParameterTypeResolver.cs @@ -1,8 +1,8 @@ -using IOLinkNET.IODD.Resolution.Contracts; -using IOLinkNET.IODD.Structure; -using IOLinkNET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Resolution.Contracts; +using IOLink.NET.IODD.Structure; +using IOLink.NET.IODD.Structure.Datatypes; -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public class ParameterTypeResolver : IParameterTypeResolver { @@ -43,4 +43,4 @@ public ParsableDatatype GetParameter(int index, byte? subIndex = null) return _converter.Convert(variable); } -} \ No newline at end of file +} diff --git a/src/IODD.Resolution/Resolver/ParsableDatatypeConverter.cs b/src/IOLink.NET.IODD/Resolution/Resolver/ParsableDatatypeConverter.cs similarity index 94% rename from src/IODD.Resolution/Resolver/ParsableDatatypeConverter.cs rename to src/IOLink.NET.IODD/Resolution/Resolver/ParsableDatatypeConverter.cs index 21130b0..8692a82 100644 --- a/src/IODD.Resolution/Resolver/ParsableDatatypeConverter.cs +++ b/src/IOLink.NET.IODD/Resolution/Resolver/ParsableDatatypeConverter.cs @@ -1,127 +1,127 @@ -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.DeviceFunction; -using IOLinkNET.IODD.Structure.ProcessData; -using IOLinkNET.IODD.Structure.Structure.Datatypes; - -namespace IOLinkNET.IODD.Resolution; - -internal class ParsableDatatypeConverter -{ - private readonly DatatypeResolver _datatypeResolver; - - public ParsableDatatypeConverter(DatatypeResolver datatypeResolver) - { - _datatypeResolver = datatypeResolver; - } - - public ParsableDatatype Convert(ProcessDataItemT processDataIn) => ConvertInternal(_datatypeResolver.Resolve(processDataIn), processDataIn.Id); - public ParsableDatatype Convert(DatatypeT type) => ConvertInternal(type); - - internal ParsableDatatype Convert(DatatypeT type, string name) => ConvertInternal(type, name); - public ParsableDatatype Convert(VariableT variable) => ConvertInternal(_datatypeResolver.Resolve(variable), variable.Id); - - private ParsableDatatype ConvertInternal(DatatypeT type, string? name = null) - => type switch - { - ComplexDatatypeT complex => ConvertComplex(complex, name), - SimpleDatatypeT simple => ConvertScalar(simple, name), - ProcessDataUnionT processDataUnion => ConvertProcessDataUnion(processDataUnion, name), - _ => throw new InvalidOperationException($"{type.GetType().Name} cannot be converted to a parsable datatype.") - }; - - private static ParsableSimpleDatatypeDef ConvertScalar(SimpleDatatypeT scalarType, string? name = null) - { - var kindOfDataType = DetermineKindOfDatatype(scalarType); - var length = DetermineScalarBitLength(scalarType); - var typeFriendlyName = name ?? scalarType.Id ?? string.Empty; - - return kindOfDataType switch - { - KindOfSimpleType.String => new ParsableStringDef(typeFriendlyName, ((StringT)scalarType).FixedLength, ((StringT)scalarType).Encoding), - _ => new ParsableSimpleDatatypeDef(typeFriendlyName, kindOfDataType, length) - }; - } - - private static ushort DetermineScalarBitLength(SimpleDatatypeT scalarType) - => scalarType switch - { - UIntegerT uInteger => uInteger.BitLength, - IntegerT integer => integer.BitLength, - StringT stringT => (ushort)(stringT.FixedLength * 8), - OctetStringT octetString => (ushort)(octetString.FixedLength * 8), - BooleanT => 1, - TimeSpanT => 64, - TimeT => 64, - Float32T => 32, - _ => throw new InvalidOperationException($"Length cannot be determined for {scalarType.GetType().Name}.") - }; - - private static KindOfSimpleType DetermineKindOfDatatype(SimpleDatatypeT scalarType) - => scalarType switch - { - UIntegerT => KindOfSimpleType.UInteger, - IntegerT => KindOfSimpleType.Integer, - Float32T => KindOfSimpleType.Float, - StringT => KindOfSimpleType.String, - OctetStringT => KindOfSimpleType.OctetString, - BooleanT => KindOfSimpleType.Boolean, - TimeSpanT => KindOfSimpleType.TimespanT, - _ => throw new InvalidOperationException($"{scalarType.GetType().Name} cannot be mapped to a simple type.") - }; - - private ParsableDatatype ConvertComplex(ComplexDatatypeT complexType, string? name = null) - => complexType switch - { - RecordT recordT => ConvertRecord(recordT, name), - ArrayT arrayT => ConvertArray(arrayT, name), - _ => throw new InvalidOperationException($"{complexType.GetType().Name} cannot be converted to a parsable datatype.") - }; - - private ParsableDatatype ConvertProcessDataUnion(ProcessDataUnionT processDataUnion, string? name = null) - => processDataUnion switch - { - ProcessDataInUnionT processDataInUnion => ConvertProcessDataInUnion(processDataInUnion, name), - ProcessDataOutUnionT processDataOutUnion => ConvertProcessDataOutUnion(processDataOutUnion, name), - ProcessDataUnionT processDataUnionT => ConvertProcessDataUnionType(processDataUnionT, name), - _ => throw new InvalidOperationException($"{processDataUnion.GetType().Name} cannot be converted to a parsable datatype.") - }; - - private ParsableDatatype ConvertProcessDataUnionType(ProcessDataUnionT processDataUnion, string? name = null) - { - var processDataUnionName = processDataUnion.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); - - return new ParsableDatatype(processDataUnionName); - } - - private ParsableDatatype ConvertProcessDataInUnion(ProcessDataInUnionT processDataInUnion, string? name = null) - { - var processDataInUnionName = processDataInUnion.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); - - return new ParsableDatatype(processDataInUnionName); - } - - private ParsableDatatype ConvertProcessDataOutUnion(ProcessDataOutUnionT processDataOutUnion, string? name = null) - { - var processDataOutUnionName = processDataOutUnion.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); - - return new ParsableDatatype(processDataOutUnionName); - } - - private ParsableRecord ConvertRecord(RecordT recordType, string? name = null) - { - var parsableRecordItems = recordType.Items.Select(rItem => new ParsableRecordItem( - ConvertScalar(_datatypeResolver.Resolve(rItem) as SimpleDatatypeT ?? throw new InvalidOperationException("RecordItem did not contain simple type."), rItem.Name.TextId), - rItem.Name.TextId, rItem.BitOffset, rItem.Subindex)); - var recordName = recordType.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); - - return new ParsableRecord(recordName, recordType.BitLength, recordType.SubindexAccessSupported, parsableRecordItems); - } - - private ParsableArray ConvertArray(ArrayT arrayType, string? name = null) - { - var arrayName = arrayType.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); - var arrayParsableUnderlyingType = ConvertScalar(_datatypeResolver.Resolve(arrayType) as SimpleDatatypeT ?? throw new InvalidOperationException("Array did not contain simple type.")); - - return new ParsableArray(arrayName, arrayParsableUnderlyingType, arrayType.SubindexAccessSupported, arrayType.Count); - } -} \ No newline at end of file +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.DeviceFunction; +using IOLink.NET.IODD.Structure.ProcessData; +using IOLink.NET.IODD.Structure.Structure.Datatypes; + +namespace IOLink.NET.IODD.Resolution; + +internal class ParsableDatatypeConverter +{ + private readonly DatatypeResolver _datatypeResolver; + + public ParsableDatatypeConverter(DatatypeResolver datatypeResolver) + { + _datatypeResolver = datatypeResolver; + } + + public ParsableDatatype Convert(ProcessDataItemT processDataIn) => ConvertInternal(_datatypeResolver.Resolve(processDataIn), processDataIn.Id); + public ParsableDatatype Convert(DatatypeT type) => ConvertInternal(type); + + internal ParsableDatatype Convert(DatatypeT type, string name) => ConvertInternal(type, name); + public ParsableDatatype Convert(VariableT variable) => ConvertInternal(_datatypeResolver.Resolve(variable), variable.Id); + + private ParsableDatatype ConvertInternal(DatatypeT type, string? name = null) + => type switch + { + ComplexDatatypeT complex => ConvertComplex(complex, name), + SimpleDatatypeT simple => ConvertScalar(simple, name), + ProcessDataUnionT processDataUnion => ConvertProcessDataUnion(processDataUnion, name), + _ => throw new InvalidOperationException($"{type.GetType().Name} cannot be converted to a parsable datatype.") + }; + + private static ParsableSimpleDatatypeDef ConvertScalar(SimpleDatatypeT scalarType, string? name = null) + { + var kindOfDataType = DetermineKindOfDatatype(scalarType); + var length = DetermineScalarBitLength(scalarType); + var typeFriendlyName = name ?? scalarType.Id ?? string.Empty; + + return kindOfDataType switch + { + KindOfSimpleType.String => new ParsableStringDef(typeFriendlyName, ((StringT)scalarType).FixedLength, ((StringT)scalarType).Encoding), + _ => new ParsableSimpleDatatypeDef(typeFriendlyName, kindOfDataType, length) + }; + } + + private static ushort DetermineScalarBitLength(SimpleDatatypeT scalarType) + => scalarType switch + { + UIntegerT uInteger => uInteger.BitLength, + IntegerT integer => integer.BitLength, + StringT stringT => (ushort)(stringT.FixedLength * 8), + OctetStringT octetString => (ushort)(octetString.FixedLength * 8), + BooleanT => 1, + TimeSpanT => 64, + TimeT => 64, + Float32T => 32, + _ => throw new InvalidOperationException($"Length cannot be determined for {scalarType.GetType().Name}.") + }; + + private static KindOfSimpleType DetermineKindOfDatatype(SimpleDatatypeT scalarType) + => scalarType switch + { + UIntegerT => KindOfSimpleType.UInteger, + IntegerT => KindOfSimpleType.Integer, + Float32T => KindOfSimpleType.Float, + StringT => KindOfSimpleType.String, + OctetStringT => KindOfSimpleType.OctetString, + BooleanT => KindOfSimpleType.Boolean, + TimeSpanT => KindOfSimpleType.TimespanT, + _ => throw new InvalidOperationException($"{scalarType.GetType().Name} cannot be mapped to a simple type.") + }; + + private ParsableDatatype ConvertComplex(ComplexDatatypeT complexType, string? name = null) + => complexType switch + { + RecordT recordT => ConvertRecord(recordT, name), + ArrayT arrayT => ConvertArray(arrayT, name), + _ => throw new InvalidOperationException($"{complexType.GetType().Name} cannot be converted to a parsable datatype.") + }; + + private ParsableDatatype ConvertProcessDataUnion(ProcessDataUnionT processDataUnion, string? name = null) + => processDataUnion switch + { + ProcessDataInUnionT processDataInUnion => ConvertProcessDataInUnion(processDataInUnion, name), + ProcessDataOutUnionT processDataOutUnion => ConvertProcessDataOutUnion(processDataOutUnion, name), + ProcessDataUnionT processDataUnionT => ConvertProcessDataUnionType(processDataUnionT, name), + _ => throw new InvalidOperationException($"{processDataUnion.GetType().Name} cannot be converted to a parsable datatype.") + }; + + private ParsableDatatype ConvertProcessDataUnionType(ProcessDataUnionT processDataUnion, string? name = null) + { + var processDataUnionName = processDataUnion.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); + + return new ParsableDatatype(processDataUnionName); + } + + private ParsableDatatype ConvertProcessDataInUnion(ProcessDataInUnionT processDataInUnion, string? name = null) + { + var processDataInUnionName = processDataInUnion.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); + + return new ParsableDatatype(processDataInUnionName); + } + + private ParsableDatatype ConvertProcessDataOutUnion(ProcessDataOutUnionT processDataOutUnion, string? name = null) + { + var processDataOutUnionName = processDataOutUnion.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); + + return new ParsableDatatype(processDataOutUnionName); + } + + private ParsableRecord ConvertRecord(RecordT recordType, string? name = null) + { + var parsableRecordItems = recordType.Items.Select(rItem => new ParsableRecordItem( + ConvertScalar(_datatypeResolver.Resolve(rItem) as SimpleDatatypeT ?? throw new InvalidOperationException("RecordItem did not contain simple type."), rItem.Name.TextId), + rItem.Name.TextId, rItem.BitOffset, rItem.Subindex)); + var recordName = recordType.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); + + return new ParsableRecord(recordName, recordType.BitLength, recordType.SubindexAccessSupported, parsableRecordItems); + } + + private ParsableArray ConvertArray(ArrayT arrayType, string? name = null) + { + var arrayName = arrayType.Id ?? name ?? throw new NullReferenceException("Name needs to be set."); + var arrayParsableUnderlyingType = ConvertScalar(_datatypeResolver.Resolve(arrayType) as SimpleDatatypeT ?? throw new InvalidOperationException("Array did not contain simple type.")); + + return new ParsableArray(arrayName, arrayParsableUnderlyingType, arrayType.SubindexAccessSupported, arrayType.Count); + } +} diff --git a/src/IODD.Resolution/Resolver/ProcessDataTypeResolver.cs b/src/IOLink.NET.IODD/Resolution/Resolver/ProcessDataTypeResolver.cs similarity index 93% rename from src/IODD.Resolution/Resolver/ProcessDataTypeResolver.cs rename to src/IOLink.NET.IODD/Resolution/Resolver/ProcessDataTypeResolver.cs index 71f209e..8400051 100644 --- a/src/IODD.Resolution/Resolver/ProcessDataTypeResolver.cs +++ b/src/IOLink.NET.IODD/Resolution/Resolver/ProcessDataTypeResolver.cs @@ -1,8 +1,8 @@ -using IOLinkNET.IODD.Resolution.Contracts; -using IOLinkNET.IODD.Structure; -using IOLinkNET.IODD.Structure.ProcessData; +using IOLink.NET.IODD.Resolution.Contracts; +using IOLink.NET.IODD.Structure; +using IOLink.NET.IODD.Structure.ProcessData; -namespace IOLinkNET.IODD.Resolution; +namespace IOLink.NET.IODD.Resolution; public class ProcessDataTypeResolver : IProcessDataTypeResolver { @@ -55,4 +55,4 @@ private ResolvedCondition ResolveConditionInternal(IEnumerable pro private ParsableDatatype ResolveProcessData(ProcessDataItemT processData) => _converter.Convert(processData); -} \ No newline at end of file +} diff --git a/src/IODD.Standard/Constants/IODDConstants.cs b/src/IOLink.NET.IODD/Standard/Constants/IODDConstants.cs similarity index 66% rename from src/IODD.Standard/Constants/IODDConstants.cs rename to src/IOLink.NET.IODD/Standard/Constants/IODDConstants.cs index 4477cb8..af8d540 100644 --- a/src/IODD.Standard/Constants/IODDConstants.cs +++ b/src/IOLink.NET.IODD/Standard/Constants/IODDConstants.cs @@ -1,6 +1,6 @@ -using System.Xml.Linq; +using System.Xml.Linq; -namespace IOLinkNET.IODD.Standard.Constants; +namespace IOLink.NET.IODD.Standard.Constants; public class IODDConstants { public static readonly XNamespace IODDXmlNamespace = XNamespace.Get("http://www.io-link.com/IODD/2010/10"); diff --git a/src/IODD.Standard/Constants/IODDStandardDefinitionNames.cs b/src/IOLink.NET.IODD/Standard/Constants/IODDStandardDefinitionNames.cs similarity index 84% rename from src/IODD.Standard/Constants/IODDStandardDefinitionNames.cs rename to src/IOLink.NET.IODD/Standard/Constants/IODDStandardDefinitionNames.cs index 7fac67c..6b8eade 100644 --- a/src/IODD.Standard/Constants/IODDStandardDefinitionNames.cs +++ b/src/IOLink.NET.IODD/Standard/Constants/IODDStandardDefinitionNames.cs @@ -1,6 +1,6 @@ -using System.Xml.Linq; +using System.Xml.Linq; -namespace IOLinkNET.IODD.Standard.Constants; +namespace IOLink.NET.IODD.Standard.Constants; public static class IODDStandardDefinitionNames { public static readonly XName VariableName = IODDConstants.IODDXmlNamespace.GetName("Variable"); diff --git a/src/IODD.Standard/Definition/IODDMenuUserRoleDefinitions.cs b/src/IOLink.NET.IODD/Standard/Definition/IODDMenuUserRoleDefinitions.cs similarity index 97% rename from src/IODD.Standard/Definition/IODDMenuUserRoleDefinitions.cs rename to src/IOLink.NET.IODD/Standard/Definition/IODDMenuUserRoleDefinitions.cs index def961a..022084b 100644 --- a/src/IODD.Standard/Definition/IODDMenuUserRoleDefinitions.cs +++ b/src/IOLink.NET.IODD/Standard/Definition/IODDMenuUserRoleDefinitions.cs @@ -1,6 +1,6 @@ -using System.Xml.Serialization; +using System.Xml.Serialization; -namespace IOLinkNET.IODD.Standard.Definition.IODDMenuUserRoleDefinitions; +namespace IOLink.NET.IODD.Standard.Definition.IODDMenuUserRoleDefinitions; [XmlRoot(ElementName = "DocumentInfo")] public class DocumentInfo diff --git a/src/IOLink.NET.IODD/Standard/Structure/StandardDefinitionReader.cs b/src/IOLink.NET.IODD/Standard/Structure/StandardDefinitionReader.cs new file mode 100644 index 0000000..e5fb8f4 --- /dev/null +++ b/src/IOLink.NET.IODD/Standard/Structure/StandardDefinitionReader.cs @@ -0,0 +1,47 @@ +using System.Reflection; +using System.Xml.Linq; +using IOLink.NET.IODD.Standard.Constants; + +namespace IOLink.NET.IODD.Standard.Structure; + +public static class StandardDefinitionReader +{ + private static readonly XElement _ioddStandardDefinitions; + + static StandardDefinitionReader() + { + var assembly = Assembly.GetExecutingAssembly(); + var resourceName = "IOLink.NET.IODD.Standard.XML.IODD-StandardDefinitions1.1.xml"; + + using var stream = + assembly.GetManifestResourceStream(resourceName) + ?? throw new FileNotFoundException( + $"IODD-StandardDefinitions1.1.xml must be present to use {nameof(StandardDefinitionReader)}" + ); + + using var reader = new StreamReader(stream); + _ioddStandardDefinitions = XElement.Load(reader); + } + + public static XElement GetVariableCollection() + { + var variableCollection = _ioddStandardDefinitions + .Elements(IODDStandardDefinitionNames.VariableCollectionName) + .Single(); + return variableCollection + ?? throw new InvalidOperationException( + "VariableCollection cannot be null in standard definitions" + ); + } + + public static XElement GetDatatypeCollection() + { + var dataTypeCollection = _ioddStandardDefinitions + .Elements(IODDStandardDefinitionNames.DatatypeCollectionName) + .Single(); + return dataTypeCollection + ?? throw new InvalidOperationException( + "DatatypeCollection cannot be null in standard definitions" + ); + } +} diff --git a/src/IODD.Standard/Structure/StandardMenuUserRoleReader.cs b/src/IOLink.NET.IODD/Standard/Structure/StandardMenuUserRoleReader.cs similarity index 56% rename from src/IODD.Standard/Structure/StandardMenuUserRoleReader.cs rename to src/IOLink.NET.IODD/Standard/Structure/StandardMenuUserRoleReader.cs index 5deab48..3ef76ae 100644 --- a/src/IODD.Standard/Structure/StandardMenuUserRoleReader.cs +++ b/src/IOLink.NET.IODD/Standard/Structure/StandardMenuUserRoleReader.cs @@ -1,9 +1,10 @@ -using System.Xml.Serialization; +using System.Reflection; +using System.Xml.Serialization; +using IOLink.NET.IODD.Standard.Definition; +using IOLink.NET.IODD.Standard.Definition.IODDMenuUserRoleDefinitions; -using IOLinkNET.IODD.Standard.Definition; -using IOLinkNET.IODD.Standard.Definition.IODDMenuUserRoleDefinitions; +namespace IOLink.NET.IODD.Standard.Structure; -namespace IOLinkNET.Visualization.Structure.Structure; public static class StandardMenuUserRoleReader { private static readonly IODDMenuUserRoleDefinitions? _ioddMenuUserRoleDefinitions; @@ -18,11 +19,17 @@ public static class StandardMenuUserRoleReader static StandardMenuUserRoleReader() { - XmlSerializer serializer = new XmlSerializer(typeof(IODDMenuUserRoleDefinitions)); - using (var reader = new StreamReader("./XML/Tool-MenuUserRole_X113.xml")) - { - _ioddMenuUserRoleDefinitions = (IODDMenuUserRoleDefinitions?)serializer.Deserialize(reader); - } + var assembly = Assembly.GetExecutingAssembly(); + var resourceName = "IOLink.NET.IODD.Standard.XML.Tool-MenuUserRole_X113.xml"; + + using var stream = + assembly.GetManifestResourceStream(resourceName) + ?? throw new FileNotFoundException( + $"Tool-MenuUserRole_X113.xml must be present to use {nameof(StandardMenuUserRoleReader)}" + ); + + var serializer = new XmlSerializer(typeof(IODDMenuUserRoleDefinitions)); + _ioddMenuUserRoleDefinitions = (IODDMenuUserRoleDefinitions?)serializer.Deserialize(stream); } public static string GetStandardMenuUserRoleText(string id, string lang) diff --git a/src/IODD.Standard/XML/IODD-StandardDefinitions1.1.xml b/src/IOLink.NET.IODD/Standard/XML/IODD-StandardDefinitions1.1.xml similarity index 100% rename from src/IODD.Standard/XML/IODD-StandardDefinitions1.1.xml rename to src/IOLink.NET.IODD/Standard/XML/IODD-StandardDefinitions1.1.xml diff --git a/src/IODD.Standard/XML/Tool-MenuUserRole_X113.xml b/src/IOLink.NET.IODD/Standard/XML/Tool-MenuUserRole_X113.xml similarity index 100% rename from src/IODD.Standard/XML/Tool-MenuUserRole_X113.xml rename to src/IOLink.NET.IODD/Standard/XML/Tool-MenuUserRole_X113.xml diff --git a/src/IOLink.NET.IODD/Structure/Interfaces/ExternalTextCollection/IExternalTextCollectionT.cs b/src/IOLink.NET.IODD/Structure/Interfaces/ExternalTextCollection/IExternalTextCollectionT.cs new file mode 100644 index 0000000..c3edd8e --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Interfaces/ExternalTextCollection/IExternalTextCollectionT.cs @@ -0,0 +1,9 @@ +using IOLink.NET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Structure.ExternalTextCollection; + +namespace IOLink.NET.IODD.Structure.Interfaces.ExternalTextCollection; +public interface IExternalTextCollectionT +{ + PrimaryLanguageT PrimaryLanguage { get; } + IEnumerable TextDefinitions { get; } +} diff --git a/src/IOLink.NET.IODD/Structure/Interfaces/IDatatypeOrTypeRef.cs b/src/IOLink.NET.IODD/Structure/Interfaces/IDatatypeOrTypeRef.cs new file mode 100644 index 0000000..38da9c6 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Interfaces/IDatatypeOrTypeRef.cs @@ -0,0 +1,10 @@ +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Structure.Interfaces; + +public interface IDatatypeOrTypeRef +{ + DatatypeT? Type { get; } + DatatypeRefT? Ref { get; } +} diff --git a/src/IOLink.NET.IODD/Structure/Interfaces/IIODevice.cs b/src/IOLink.NET.IODD/Structure/Interfaces/IIODevice.cs new file mode 100644 index 0000000..2d631dc --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Interfaces/IIODevice.cs @@ -0,0 +1,13 @@ +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Interfaces.ExternalTextCollection; +using IOLink.NET.IODD.Structure.Interfaces.Profile; +using IOLink.NET.IODD.Structure.Profile; +using IOLink.NET.IODD.Structure.Structure.ExternalTextCollection; + +namespace IOLink.NET.IODD.Structure.Interfaces; +public interface IIODevice +{ + IProfileBodyT ProfileBody { get; } + IExternalTextCollectionT ExternalTextCollection { get; } + IEnumerable StandardDatatypeCollection { get; } +} diff --git a/src/IODD.Structure/Interfaces/Menu/IMenuSetT.cs b/src/IOLink.NET.IODD/Structure/Interfaces/Menu/IMenuSetT.cs similarity index 68% rename from src/IODD.Structure/Interfaces/Menu/IMenuSetT.cs rename to src/IOLink.NET.IODD/Structure/Interfaces/Menu/IMenuSetT.cs index 45d8d86..97db34b 100644 --- a/src/IODD.Structure/Interfaces/Menu/IMenuSetT.cs +++ b/src/IOLink.NET.IODD/Structure/Interfaces/Menu/IMenuSetT.cs @@ -1,6 +1,6 @@ -using IOLinkNET.IODD.Structure.Structure.Menu; +using IOLink.NET.IODD.Structure.Structure.Menu; -namespace IOLinkNET.IODD.Structure.Interfaces.Menu; +namespace IOLink.NET.IODD.Structure.Interfaces.Menu; public interface IMenuSetT { UIMenuRefSimpleT IdentificationMenu { get; } diff --git a/src/IODD.Structure/Interfaces/Menu/IUserInterfaceT.cs b/src/IOLink.NET.IODD/Structure/Interfaces/Menu/IUserInterfaceT.cs similarity index 69% rename from src/IODD.Structure/Interfaces/Menu/IUserInterfaceT.cs rename to src/IOLink.NET.IODD/Structure/Interfaces/Menu/IUserInterfaceT.cs index a03979f..7867e00 100644 --- a/src/IODD.Structure/Interfaces/Menu/IUserInterfaceT.cs +++ b/src/IOLink.NET.IODD/Structure/Interfaces/Menu/IUserInterfaceT.cs @@ -1,6 +1,6 @@ -using IOLinkNET.IODD.Structure.Structure.Menu; +using IOLink.NET.IODD.Structure.Structure.Menu; -namespace IOLinkNET.IODD.Structure.Interfaces.Menu; +namespace IOLink.NET.IODD.Structure.Interfaces.Menu; public interface IUserInterfaceT { IEnumerable MenuCollection { get; } diff --git a/src/IODD.Structure/Interfaces/Profile/IDeviceFunctionT.cs b/src/IOLink.NET.IODD/Structure/Interfaces/Profile/IDeviceFunctionT.cs similarity index 51% rename from src/IODD.Structure/Interfaces/Profile/IDeviceFunctionT.cs rename to src/IOLink.NET.IODD/Structure/Interfaces/Profile/IDeviceFunctionT.cs index 5a8236d..be7b677 100644 --- a/src/IODD.Structure/Interfaces/Profile/IDeviceFunctionT.cs +++ b/src/IOLink.NET.IODD/Structure/Interfaces/Profile/IDeviceFunctionT.cs @@ -1,9 +1,9 @@ -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.DeviceFunction; -using IOLinkNET.IODD.Structure.Interfaces.Menu; -using IOLinkNET.IODD.Structure.ProcessData; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.DeviceFunction; +using IOLink.NET.IODD.Structure.Interfaces.Menu; +using IOLink.NET.IODD.Structure.ProcessData; -namespace IOLinkNET.IODD.Structure.Interfaces.Profile; +namespace IOLink.NET.IODD.Structure.Interfaces.Profile; public interface IDeviceFunctionT { IEnumerable DatatypeCollection { get; } diff --git a/src/IODD.Structure/Interfaces/Profile/IDeviceIdentityT.cs b/src/IOLink.NET.IODD/Structure/Interfaces/Profile/IDeviceIdentityT.cs similarity index 72% rename from src/IODD.Structure/Interfaces/Profile/IDeviceIdentityT.cs rename to src/IOLink.NET.IODD/Structure/Interfaces/Profile/IDeviceIdentityT.cs index 82233d2..aba3bbe 100644 --- a/src/IODD.Structure/Interfaces/Profile/IDeviceIdentityT.cs +++ b/src/IOLink.NET.IODD/Structure/Interfaces/Profile/IDeviceIdentityT.cs @@ -1,6 +1,6 @@ -using IOLinkNET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Common; -namespace IOLinkNET.IODD.Structure.Interfaces.Profile; +namespace IOLink.NET.IODD.Structure.Interfaces.Profile; public interface IDeviceIdentityT { ushort VendorId { get; } diff --git a/src/IODD.Structure/Interfaces/Profile/IProfileBodyT.cs b/src/IOLink.NET.IODD/Structure/Interfaces/Profile/IProfileBodyT.cs similarity index 68% rename from src/IODD.Structure/Interfaces/Profile/IProfileBodyT.cs rename to src/IOLink.NET.IODD/Structure/Interfaces/Profile/IProfileBodyT.cs index d41eebb..e10fd8f 100644 --- a/src/IODD.Structure/Interfaces/Profile/IProfileBodyT.cs +++ b/src/IOLink.NET.IODD/Structure/Interfaces/Profile/IProfileBodyT.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.IODD.Structure.Interfaces.Profile; +namespace IOLink.NET.IODD.Structure.Interfaces.Profile; public interface IProfileBodyT { IDeviceIdentityT DeviceIdentity { get; } diff --git a/src/IOLink.NET.IODD/Structure/Structure/Common/DatatypeRefT.cs b/src/IOLink.NET.IODD/Structure/Structure/Common/DatatypeRefT.cs new file mode 100644 index 0000000..4a906f7 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Common/DatatypeRefT.cs @@ -0,0 +1,3 @@ +namespace IOLink.NET.IODD.Structure.Common; + +public record DatatypeRefT(string DatatypeId); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Common/TextRefT.cs b/src/IOLink.NET.IODD/Structure/Structure/Common/TextRefT.cs new file mode 100644 index 0000000..145daa0 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Common/TextRefT.cs @@ -0,0 +1,3 @@ +namespace IOLink.NET.IODD.Structure.Common; + +public record TextRefT(string TextId); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/AbstractValueT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/AbstractValueT.cs new file mode 100644 index 0000000..5867655 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/AbstractValueT.cs @@ -0,0 +1,4 @@ +using IOLink.NET.IODD.Structure.Common; +namespace IOLink.NET.IODD.Structure.Datatypes; + +public abstract record AbstractValueT(TextRefT? Name); diff --git a/src/IODD.Structure/Structure/Datatypes/AccessRightsT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/AccessRightsT.cs similarity index 90% rename from src/IODD.Structure/Structure/Datatypes/AccessRightsT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/AccessRightsT.cs index 9923472..57f5622 100644 --- a/src/IODD.Structure/Structure/Datatypes/AccessRightsT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/AccessRightsT.cs @@ -1,24 +1,24 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public enum AccessRightsT -{ - ReadOnly, - ReadWrite, - WriteOnly - -} - -public static class AccessRightsTConverter -{ - public static AccessRightsT? ParseOptional(string accessRights) => accessRights.ToLower(System.Globalization.CultureInfo.CurrentCulture) switch - { - "ro" => AccessRightsT.ReadOnly, - "rw" => AccessRightsT.ReadWrite, - "wo" => AccessRightsT.WriteOnly, - _ => null - }; - - public static AccessRightsT Parse(string? accessRights) - => ParseOptional(accessRights ?? throw new ArgumentNullException(nameof(accessRights))) - ?? throw new ArgumentOutOfRangeException($"{accessRights} could not parsed to AccessRightsT."); -} \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Datatypes; + +public enum AccessRightsT +{ + ReadOnly, + ReadWrite, + WriteOnly + +} + +public static class AccessRightsTConverter +{ + public static AccessRightsT? ParseOptional(string accessRights) => accessRights.ToLower(System.Globalization.CultureInfo.CurrentCulture) switch + { + "ro" => AccessRightsT.ReadOnly, + "rw" => AccessRightsT.ReadWrite, + "wo" => AccessRightsT.WriteOnly, + _ => null + }; + + public static AccessRightsT Parse(string? accessRights) + => ParseOptional(accessRights ?? throw new ArgumentNullException(nameof(accessRights))) + ?? throw new ArgumentOutOfRangeException($"{accessRights} could not parsed to AccessRightsT."); +} diff --git a/src/IODD.Structure/Structure/Datatypes/ArrayT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ArrayT.cs similarity index 64% rename from src/IODD.Structure/Structure/Datatypes/ArrayT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/ArrayT.cs index 8134518..e6eaf30 100644 --- a/src/IODD.Structure/Structure/Datatypes/ArrayT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ArrayT.cs @@ -1,10 +1,10 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Interfaces; - -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record ArrayT(string? Id, byte Count, SimpleDatatypeT? Type, DatatypeRefT? Ref, bool SubindexAccessSupported = true) - : ComplexDatatypeT(Id, SubindexAccessSupported), IDatatypeOrTypeRef -{ - DatatypeT? IDatatypeOrTypeRef.Type => Type; -} +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Interfaces; + +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record ArrayT(string? Id, byte Count, SimpleDatatypeT? Type, DatatypeRefT? Ref, bool SubindexAccessSupported = true) + : ComplexDatatypeT(Id, SubindexAccessSupported), IDatatypeOrTypeRef +{ + DatatypeT? IDatatypeOrTypeRef.Type => Type; +} diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/BooleanT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/BooleanT.cs new file mode 100644 index 0000000..97e4158 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/BooleanT.cs @@ -0,0 +1,3 @@ +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record BooleanT(string? Id, IEnumerable> SingleValues) : SimpleDatatypeT(Id); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ComplexDatatypeT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ComplexDatatypeT.cs new file mode 100644 index 0000000..e1cd258 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ComplexDatatypeT.cs @@ -0,0 +1,3 @@ +namespace IOLink.NET.IODD.Structure.Datatypes; + +public abstract record ComplexDatatypeT(string? Id, bool SubindexAccessSupported = true) : DatatypeT(Id); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/DatatypeT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/DatatypeT.cs new file mode 100644 index 0000000..d03f6d6 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/DatatypeT.cs @@ -0,0 +1,3 @@ +namespace IOLink.NET.IODD.Structure.Datatypes; + +public abstract record DatatypeT(string? Id); diff --git a/src/IODD.Structure/Structure/Datatypes/DisplayFormat.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/DisplayFormat.cs similarity index 93% rename from src/IODD.Structure/Structure/Datatypes/DisplayFormat.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/DisplayFormat.cs index 4e9f5d2..b4ce449 100644 --- a/src/IODD.Structure/Structure/Datatypes/DisplayFormat.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/DisplayFormat.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.IODD.Structure.Structure.Datatypes; +namespace IOLink.NET.IODD.Structure.Structure.Datatypes; public enum DisplayFormat { Bin, diff --git a/src/IODD.Structure/Structure/Datatypes/Float32T.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/Float32T.cs similarity index 67% rename from src/IODD.Structure/Structure/Datatypes/Float32T.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/Float32T.cs index 4a3d620..cb7eed5 100644 --- a/src/IODD.Structure/Structure/Datatypes/Float32T.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/Float32T.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record Float32T(string? Id, IEnumerable> SingleValues, IEnumerable> ValueRanges) : NumberT(Id); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record Float32T(string? Id, IEnumerable> SingleValues, IEnumerable> ValueRanges) : NumberT(Id); diff --git a/src/IODD.Structure/Structure/Datatypes/IntegerT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/IntegerT.cs similarity index 63% rename from src/IODD.Structure/Structure/Datatypes/IntegerT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/IntegerT.cs index 42b835b..d1fb2b6 100644 --- a/src/IODD.Structure/Structure/Datatypes/IntegerT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/IntegerT.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record IntegerT(string? Id, ushort BitLength, IEnumerable> SingleValues, IEnumerable> ValueRanges) : NumberT(Id); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record IntegerT(string? Id, ushort BitLength, IEnumerable> SingleValues, IEnumerable> ValueRanges) : NumberT(Id); diff --git a/src/IODD.Structure/Structure/Datatypes/NumberT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/NumberT.cs similarity index 57% rename from src/IODD.Structure/Structure/Datatypes/NumberT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/NumberT.cs index 5c8da0d..aee805e 100644 --- a/src/IODD.Structure/Structure/Datatypes/NumberT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/NumberT.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public abstract record NumberT(string? Id) : SimpleDatatypeT(Id); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Datatypes; + +public abstract record NumberT(string? Id) : SimpleDatatypeT(Id); diff --git a/src/IODD.Structure/Structure/Datatypes/OctetStringT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/OctetStringT.cs similarity index 50% rename from src/IODD.Structure/Structure/Datatypes/OctetStringT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/OctetStringT.cs index cf0d67b..5c95ffb 100644 --- a/src/IODD.Structure/Structure/Datatypes/OctetStringT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/OctetStringT.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record OctetStringT(string? Id, byte FixedLength) : SimpleDatatypeT(Id); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record OctetStringT(string? Id, byte FixedLength) : SimpleDatatypeT(Id); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ProcessDataInUnionT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ProcessDataInUnionT.cs new file mode 100644 index 0000000..446d0df --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ProcessDataInUnionT.cs @@ -0,0 +1,5 @@ +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Structure.Structure.Datatypes; +public record ProcessDataInUnionT(string Id, SimpleDatatypeT? Type, DatatypeRefT? Ref) : ProcessDataUnionT(Id, Type, Ref); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ProcessDataOutUnionT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ProcessDataOutUnionT.cs new file mode 100644 index 0000000..2a66318 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ProcessDataOutUnionT.cs @@ -0,0 +1,5 @@ +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Structure.Structure.Datatypes; +public record ProcessDataOutUnionT(string Id, SimpleDatatypeT? Type, DatatypeRefT? Ref) : ProcessDataUnionT(Id, Type, Ref); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ProcessDataUnionT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ProcessDataUnionT.cs new file mode 100644 index 0000000..70aed0b --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ProcessDataUnionT.cs @@ -0,0 +1,9 @@ +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Interfaces; + +namespace IOLink.NET.IODD.Structure.Structure.Datatypes; +public record ProcessDataUnionT(string? Id, SimpleDatatypeT? Type, DatatypeRefT? Ref) : DatatypeT(Id), IDatatypeOrTypeRef +{ + DatatypeT? IDatatypeOrTypeRef.Type => Type; +} diff --git a/src/IODD.Structure/Structure/Datatypes/RecordItemT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/RecordItemT.cs similarity index 61% rename from src/IODD.Structure/Structure/Datatypes/RecordItemT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/RecordItemT.cs index ffa6107..e21bd38 100644 --- a/src/IODD.Structure/Structure/Datatypes/RecordItemT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/RecordItemT.cs @@ -1,10 +1,10 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Interfaces; - -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record RecordItemT(byte Subindex, ushort BitOffset, TextRefT Name, TextRefT? Description, SimpleDatatypeT? Type, DatatypeRefT? Ref) - : IDatatypeOrTypeRef -{ - DatatypeT? IDatatypeOrTypeRef.Type => Type; -} +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Interfaces; + +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record RecordItemT(byte Subindex, ushort BitOffset, TextRefT Name, TextRefT? Description, SimpleDatatypeT? Type, DatatypeRefT? Ref) + : IDatatypeOrTypeRef +{ + DatatypeT? IDatatypeOrTypeRef.Type => Type; +} diff --git a/src/IODD.Structure/Structure/Datatypes/RecordT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/RecordT.cs similarity index 79% rename from src/IODD.Structure/Structure/Datatypes/RecordT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/RecordT.cs index 0b88a6e..f08fe91 100644 --- a/src/IODD.Structure/Structure/Datatypes/RecordT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/RecordT.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record RecordT(string? Id, ushort BitLength, IEnumerable Items, bool SubindexAccessSupported = true) - : ComplexDatatypeT(Id, SubindexAccessSupported); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record RecordT(string? Id, ushort BitLength, IEnumerable Items, bool SubindexAccessSupported = true) + : ComplexDatatypeT(Id, SubindexAccessSupported); diff --git a/src/IODD.Structure/Structure/Datatypes/SimpleDatatypeT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/SimpleDatatypeT.cs similarity index 56% rename from src/IODD.Structure/Structure/Datatypes/SimpleDatatypeT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/SimpleDatatypeT.cs index 9c60e00..18bca7f 100644 --- a/src/IODD.Structure/Structure/Datatypes/SimpleDatatypeT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/SimpleDatatypeT.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public abstract record SimpleDatatypeT(string? Id) : DatatypeT(Id); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Datatypes; + +public abstract record SimpleDatatypeT(string? Id) : DatatypeT(Id); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/SingleValueT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/SingleValueT.cs new file mode 100644 index 0000000..6af181f --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/SingleValueT.cs @@ -0,0 +1,5 @@ +using IOLink.NET.IODD.Structure.Common; + +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record SingleValueT(T LowerValue, T UpperValue, TextRefT? Name) : AbstractValueT(Name) where T : struct; diff --git a/src/IODD.Structure/Structure/Datatypes/StringT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/StringT.cs similarity index 82% rename from src/IODD.Structure/Structure/Datatypes/StringT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/StringT.cs index bc2dfa3..0e3000d 100644 --- a/src/IODD.Structure/Structure/Datatypes/StringT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/StringT.cs @@ -1,16 +1,16 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record StringT(string? Id, byte FixedLength, StringTEncoding Encoding) : SimpleDatatypeT(Id); - -public static class StringTEncodingConstats -{ - public const string UTF8 = "UTF-8"; - - public const string ASCII = "US-ASCII"; -} - -public enum StringTEncoding -{ - UTF8, - ASCII -} \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record StringT(string? Id, byte FixedLength, StringTEncoding Encoding) : SimpleDatatypeT(Id); + +public static class StringTEncodingConstats +{ + public const string UTF8 = "UTF-8"; + + public const string ASCII = "US-ASCII"; +} + +public enum StringTEncoding +{ + UTF8, + ASCII +} diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/TextDefinitionT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/TextDefinitionT.cs new file mode 100644 index 0000000..562be8d --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/TextDefinitionT.cs @@ -0,0 +1,2 @@ +namespace IOLink.NET.IODD.Structure.Structure.Datatypes; +public record TextDefinitionT(string Id, string Value); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/TimeT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/TimeT.cs new file mode 100644 index 0000000..def96b4 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/TimeT.cs @@ -0,0 +1,3 @@ +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record TimeT(string? Id) : SimpleDatatypeT(Id); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/TimespanT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/TimespanT.cs new file mode 100644 index 0000000..0e100fe --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/TimespanT.cs @@ -0,0 +1,3 @@ +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record TimeSpanT(string? Id) : SimpleDatatypeT(Id); diff --git a/src/IODD.Structure/Structure/Datatypes/UIntegerT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/UIntegerT.cs similarity index 62% rename from src/IODD.Structure/Structure/Datatypes/UIntegerT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Datatypes/UIntegerT.cs index c6b0b8a..3e33afe 100644 --- a/src/IODD.Structure/Structure/Datatypes/UIntegerT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/UIntegerT.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Structure.Datatypes; - -public record UIntegerT(string? Id, ushort BitLength, IEnumerable> SingleValues, IEnumerable> ValueRanges) : NumberT(Id); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record UIntegerT(string? Id, ushort BitLength, IEnumerable> SingleValues, IEnumerable> ValueRanges) : NumberT(Id); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ValueRangeT.cs b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ValueRangeT.cs new file mode 100644 index 0000000..6a4ff23 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Datatypes/ValueRangeT.cs @@ -0,0 +1,5 @@ +using IOLink.NET.IODD.Structure.Common; + +namespace IOLink.NET.IODD.Structure.Datatypes; + +public record ValueRangeT(T LowerValue, T UpperValue, TextRefT? Name) : AbstractValueT(Name) where T : struct; diff --git a/src/IODD.Structure/Structure/DeviceFunction/AbstractVariableT.cs b/src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/AbstractVariableT.cs similarity index 50% rename from src/IODD.Structure/Structure/DeviceFunction/AbstractVariableT.cs rename to src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/AbstractVariableT.cs index 9ef5057..c6e45a7 100644 --- a/src/IODD.Structure/Structure/DeviceFunction/AbstractVariableT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/AbstractVariableT.cs @@ -1,9 +1,9 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Interfaces; - -namespace IOLinkNET.IODD.Structure.DeviceFunction; - -public record AbstractVariableT(DatatypeT? Type, DatatypeRefT? Ref, TextRefT Name, TextRefT? Description, - AccessRightsT AccessRights, IEnumerable RecordItemInfos, - bool Dynamic = false, bool ModifiesOtherVariables = false, bool ExcludedFromDataStorage = false) : IDatatypeOrTypeRef; \ No newline at end of file +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Interfaces; + +namespace IOLink.NET.IODD.Structure.DeviceFunction; + +public record AbstractVariableT(DatatypeT? Type, DatatypeRefT? Ref, TextRefT Name, TextRefT? Description, + AccessRightsT AccessRights, IEnumerable RecordItemInfos, + bool Dynamic = false, bool ModifiesOtherVariables = false, bool ExcludedFromDataStorage = false) : IDatatypeOrTypeRef; diff --git a/src/IODD.Structure/Structure/DeviceFunction/RecordItemInfoT.cs b/src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/RecordItemInfoT.cs similarity index 65% rename from src/IODD.Structure/Structure/DeviceFunction/RecordItemInfoT.cs rename to src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/RecordItemInfoT.cs index 0c20bb6..515dc5e 100644 --- a/src/IODD.Structure/Structure/DeviceFunction/RecordItemInfoT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/RecordItemInfoT.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Structure.DeviceFunction; - -public record RecordItemInfoT(byte SubIndex, object? DefaultValue, bool ModifiesOtherVariables = false, bool ExcludedFromDataStorage = false); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.DeviceFunction; + +public record RecordItemInfoT(byte SubIndex, object? DefaultValue, bool ModifiesOtherVariables = false, bool ExcludedFromDataStorage = false); diff --git a/src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/StdVariableRefT.cs b/src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/StdVariableRefT.cs new file mode 100644 index 0000000..13138a6 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/StdVariableRefT.cs @@ -0,0 +1,3 @@ +namespace IOLink.NET.IODD.Structure.DeviceFunction; + +public record StdVariableRefT(string Id, uint FixedLengthRestriction, string defaultValue); diff --git a/src/IODD.Structure/Structure/DeviceFunction/VariableT.cs b/src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/VariableT.cs similarity index 72% rename from src/IODD.Structure/Structure/DeviceFunction/VariableT.cs rename to src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/VariableT.cs index 7c07f72..980d3e8 100644 --- a/src/IODD.Structure/Structure/DeviceFunction/VariableT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/DeviceFunction/VariableT.cs @@ -1,9 +1,9 @@ -using IOLinkNET.IODD.Structure.Common; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace IOLinkNET.IODD.Structure.DeviceFunction; - -public record VariableT(string Id, ushort Index, DatatypeT? Datatype, DatatypeRefT? DatatypeRef, TextRefT Name, TextRefT? Description, - AccessRightsT AccessRights, IEnumerable RecordItemInfos, - bool Dynamic = false, bool ModifiesOtherVariables = false, bool ExcludedFromDataStorage = false) - : AbstractVariableT(Datatype, DatatypeRef, Name, Description, AccessRights, RecordItemInfos, Dynamic, ModifiesOtherVariables, ExcludedFromDataStorage); \ No newline at end of file +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.IODD.Structure.DeviceFunction; + +public record VariableT(string Id, ushort Index, DatatypeT? Datatype, DatatypeRefT? DatatypeRef, TextRefT Name, TextRefT? Description, + AccessRightsT AccessRights, IEnumerable RecordItemInfos, + bool Dynamic = false, bool ModifiesOtherVariables = false, bool ExcludedFromDataStorage = false) + : AbstractVariableT(Datatype, DatatypeRef, Name, Description, AccessRights, RecordItemInfos, Dynamic, ModifiesOtherVariables, ExcludedFromDataStorage); diff --git a/src/IOLink.NET.IODD/Structure/Structure/ExternalTextCollection/ExternalTextCollectionT.cs b/src/IOLink.NET.IODD/Structure/Structure/ExternalTextCollection/ExternalTextCollectionT.cs new file mode 100644 index 0000000..a61ef83 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/ExternalTextCollection/ExternalTextCollectionT.cs @@ -0,0 +1,5 @@ +using IOLink.NET.IODD.Structure.Interfaces.ExternalTextCollection; +using IOLink.NET.IODD.Structure.Structure.Datatypes; + +namespace IOLink.NET.IODD.Structure.Structure.ExternalTextCollection; +public record ExternalTextCollectionT(PrimaryLanguageT PrimaryLanguage, IEnumerable TextDefinitions): IExternalTextCollectionT; diff --git a/src/IOLink.NET.IODD/Structure/Structure/ExternalTextCollection/PrimaryLanguageT.cs b/src/IOLink.NET.IODD/Structure/Structure/ExternalTextCollection/PrimaryLanguageT.cs new file mode 100644 index 0000000..06e2853 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/ExternalTextCollection/PrimaryLanguageT.cs @@ -0,0 +1,2 @@ +namespace IOLink.NET.IODD.Structure.Structure.ExternalTextCollection; +public record PrimaryLanguageT(string LanguageCode); diff --git a/src/IOLink.NET.IODD/Structure/Structure/IODevice.cs b/src/IOLink.NET.IODD/Structure/Structure/IODevice.cs new file mode 100644 index 0000000..3873faf --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/IODevice.cs @@ -0,0 +1,8 @@ +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Interfaces; +using IOLink.NET.IODD.Structure.Interfaces.ExternalTextCollection; +using IOLink.NET.IODD.Structure.Interfaces.Profile; + +namespace IOLink.NET.IODD.Structure; + +public record IODevice(IProfileBodyT ProfileBody, IExternalTextCollectionT ExternalTextCollection, IEnumerable StandardDatatypeCollection): IIODevice; diff --git a/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuCollectionT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuCollectionT.cs new file mode 100644 index 0000000..bfe1639 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuCollectionT.cs @@ -0,0 +1,2 @@ +namespace IOLink.NET.IODD.Structure.Structure.Menu; +public record MenuCollectionT(MenuT Menu); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuItemRefT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuItemRefT.cs new file mode 100644 index 0000000..d750b3d --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuItemRefT.cs @@ -0,0 +1,2 @@ +namespace IOLink.NET.IODD.Structure.Structure.Menu; +public record MenuItemRefT(string Id, string? Name); diff --git a/src/IODD.Structure/Structure/Menu/MenuSetT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuSetT.cs similarity index 63% rename from src/IODD.Structure/Structure/Menu/MenuSetT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Menu/MenuSetT.cs index edea5d6..8d49ded 100644 --- a/src/IODD.Structure/Structure/Menu/MenuSetT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuSetT.cs @@ -1,4 +1,4 @@ -using IOLinkNET.IODD.Structure.Interfaces.Menu; +using IOLink.NET.IODD.Structure.Interfaces.Menu; -namespace IOLinkNET.IODD.Structure.Structure.Menu; +namespace IOLink.NET.IODD.Structure.Structure.Menu; public record MenuSetT(UIMenuRefSimpleT IdentificationMenu, UIMenuRefSimpleT? ParameterMenu, UIMenuRefSimpleT? ObservationMenu, UIMenuRefSimpleT? DiagnosisMenu): IMenuSetT; diff --git a/src/IODD.Structure/Structure/Menu/MenuT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuT.cs similarity index 76% rename from src/IODD.Structure/Structure/Menu/MenuT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Menu/MenuT.cs index 6a43c1a..0bd0c08 100644 --- a/src/IODD.Structure/Structure/Menu/MenuT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/MenuT.cs @@ -1,2 +1,2 @@ -namespace IOLinkNET.IODD.Structure.Structure.Menu; +namespace IOLink.NET.IODD.Structure.Structure.Menu; public record MenuT(string Id, string? Name, IEnumerable? VariableRefs, IEnumerable? MenuRefs, IEnumerable? RecordItemRefs); diff --git a/src/IODD.Structure/Structure/Menu/UIDataItemRefT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIDataItemRefT.cs similarity index 55% rename from src/IODD.Structure/Structure/Menu/UIDataItemRefT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Menu/UIDataItemRefT.cs index 2fec660..1d14fde 100644 --- a/src/IODD.Structure/Structure/Menu/UIDataItemRefT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIDataItemRefT.cs @@ -1,5 +1,5 @@ -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Structure.Datatypes; -namespace IOLinkNET.IODD.Structure.Structure.Menu; +namespace IOLink.NET.IODD.Structure.Structure.Menu; public record UIDataItemRefT(string VariableId, decimal? Gradient, decimal? Offset, uint? UnitCode, AccessRightsT? AccessRights, string? ButtonValue, DisplayFormat? DisplayFormat); diff --git a/src/IODD.Structure/Structure/Menu/UIMenuRefSimpleT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIMenuRefSimpleT.cs similarity index 53% rename from src/IODD.Structure/Structure/Menu/UIMenuRefSimpleT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Menu/UIMenuRefSimpleT.cs index 8b3256e..d0810d5 100644 --- a/src/IODD.Structure/Structure/Menu/UIMenuRefSimpleT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIMenuRefSimpleT.cs @@ -1,2 +1,2 @@ -namespace IOLinkNET.IODD.Structure.Structure.Menu; +namespace IOLink.NET.IODD.Structure.Structure.Menu; public record UIMenuRefSimpleT(string? MenuId, MenuT? Menu); diff --git a/src/IODD.Structure/Structure/Menu/UIMenuRefT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIMenuRefT.cs similarity index 50% rename from src/IODD.Structure/Structure/Menu/UIMenuRefT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Menu/UIMenuRefT.cs index 6e107f3..bad1c81 100644 --- a/src/IODD.Structure/Structure/Menu/UIMenuRefT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIMenuRefT.cs @@ -1,4 +1,4 @@ -using IOLinkNET.IODD.Structure.ProcessData; +using IOLink.NET.IODD.Structure.ProcessData; -namespace IOLinkNET.IODD.Structure.Structure.Menu; +namespace IOLink.NET.IODD.Structure.Structure.Menu; public record UIMenuRefT(string MenuId, ConditionT? Condition) : UIMenuRefSimpleT(MenuId, null); diff --git a/src/IODD.Structure/Structure/Menu/UIRecordItemRefT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIRecordItemRefT.cs similarity index 66% rename from src/IODD.Structure/Structure/Menu/UIRecordItemRefT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Menu/UIRecordItemRefT.cs index c19a7dc..020c87b 100644 --- a/src/IODD.Structure/Structure/Menu/UIRecordItemRefT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIRecordItemRefT.cs @@ -1,5 +1,5 @@ -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Structure.Datatypes; -namespace IOLinkNET.IODD.Structure.Structure.Menu; +namespace IOLink.NET.IODD.Structure.Structure.Menu; public record UIRecordItemRefT(string VariableId, byte SubIndex, decimal? Gradient, decimal? Offset, uint? UnitCode, AccessRightsT? AccessRights, string? ButtonValue, DisplayFormat? DisplayFormat) : UIDataItemRefT(VariableId, Gradient, Offset, UnitCode, AccessRights, ButtonValue, DisplayFormat); diff --git a/src/IODD.Structure/Structure/Menu/UIVariableRefT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIVariableRefT.cs similarity index 65% rename from src/IODD.Structure/Structure/Menu/UIVariableRefT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Menu/UIVariableRefT.cs index dc0e711..639e23e 100644 --- a/src/IODD.Structure/Structure/Menu/UIVariableRefT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/UIVariableRefT.cs @@ -1,5 +1,5 @@ -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Structure.Datatypes; -namespace IOLinkNET.IODD.Structure.Structure.Menu; +namespace IOLink.NET.IODD.Structure.Structure.Menu; public record UIVariableRefT(string VariableId, decimal? Gradient, decimal? Offset, uint? UnitCode, AccessRightsT? AccessRights, string? ButtonValue, DisplayFormat? DisplayFormat) : UIDataItemRefT(VariableId, Gradient, Offset, UnitCode, AccessRights, ButtonValue, DisplayFormat); diff --git a/src/IODD.Structure/Structure/Menu/UserInterfaceT.cs b/src/IOLink.NET.IODD/Structure/Structure/Menu/UserInterfaceT.cs similarity index 56% rename from src/IODD.Structure/Structure/Menu/UserInterfaceT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Menu/UserInterfaceT.cs index af84422..c99637c 100644 --- a/src/IODD.Structure/Structure/Menu/UserInterfaceT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Menu/UserInterfaceT.cs @@ -1,5 +1,5 @@ -using IOLinkNET.IODD.Structure.Interfaces; -using IOLinkNET.IODD.Structure.Interfaces.Menu; +using IOLink.NET.IODD.Structure.Interfaces; +using IOLink.NET.IODD.Structure.Interfaces.Menu; -namespace IOLinkNET.IODD.Structure.Structure.Menu; +namespace IOLink.NET.IODD.Structure.Structure.Menu; public record UserInterfaceT(IEnumerable MenuCollection, IMenuSetT ObserverRoleMenuSet, IMenuSetT MaintenanceRoleMenuSet, IMenuSetT SpecialistRoleMenuSet): IUserInterfaceT; diff --git a/src/IODD.Structure/Structure/ProcessData/ConditionT.cs b/src/IOLink.NET.IODD/Structure/Structure/ProcessData/ConditionT.cs similarity index 53% rename from src/IODD.Structure/Structure/ProcessData/ConditionT.cs rename to src/IOLink.NET.IODD/Structure/Structure/ProcessData/ConditionT.cs index 720edd1..4a4880b 100644 --- a/src/IODD.Structure/Structure/ProcessData/ConditionT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/ProcessData/ConditionT.cs @@ -1,3 +1,3 @@ -namespace IOLinkNET.IODD.Structure.ProcessData; - -public record ConditionT(string VariableId, byte? Subindex, int Value); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.ProcessData; + +public record ConditionT(string VariableId, byte? Subindex, int Value); diff --git a/src/IOLink.NET.IODD/Structure/Structure/ProcessData/ProcessDataItemT.cs b/src/IOLink.NET.IODD/Structure/Structure/ProcessData/ProcessDataItemT.cs new file mode 100644 index 0000000..0cbb4ac --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/ProcessData/ProcessDataItemT.cs @@ -0,0 +1,10 @@ +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.Interfaces; + +namespace IOLink.NET.IODD.Structure.ProcessData; + +public record ProcessDataItemT(DatatypeT? Datatype, DatatypeRefT? Ref, string Id, ushort BitLength) : IDatatypeOrTypeRef +{ + public DatatypeT? Type => Datatype; +} diff --git a/src/IOLink.NET.IODD/Structure/Structure/ProcessData/ProcessDataT.cs b/src/IOLink.NET.IODD/Structure/Structure/ProcessData/ProcessDataT.cs new file mode 100644 index 0000000..354b5d8 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/ProcessData/ProcessDataT.cs @@ -0,0 +1,3 @@ +namespace IOLink.NET.IODD.Structure.ProcessData; + +public record ProcessDataT(ConditionT? Condition, ProcessDataItemT? ProcessDataIn, ProcessDataItemT? ProcessDataOut); diff --git a/src/IOLink.NET.IODD/Structure/Structure/Profile/DeviceFunctionT.cs b/src/IOLink.NET.IODD/Structure/Structure/Profile/DeviceFunctionT.cs new file mode 100644 index 0000000..30417a4 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Profile/DeviceFunctionT.cs @@ -0,0 +1,9 @@ +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.DeviceFunction; +using IOLink.NET.IODD.Structure.Interfaces.Menu; +using IOLink.NET.IODD.Structure.Interfaces.Profile; +using IOLink.NET.IODD.Structure.ProcessData; + +namespace IOLink.NET.IODD.Structure.Profile; + +public record DeviceFunctionT(IEnumerable DatatypeCollection, IEnumerable VariableCollection, IEnumerable ProcessDataCollection, IUserInterfaceT UserInterface): IDeviceFunctionT; diff --git a/src/IOLink.NET.IODD/Structure/Structure/Profile/DeviceIdentity.cs b/src/IOLink.NET.IODD/Structure/Structure/Profile/DeviceIdentity.cs new file mode 100644 index 0000000..a3b7412 --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Profile/DeviceIdentity.cs @@ -0,0 +1,6 @@ +using IOLink.NET.IODD.Structure.Common; +using IOLink.NET.IODD.Structure.Interfaces.Profile; + +namespace IOLink.NET.IODD.Structure.Profile; + +public record DeviceIdentityT(ushort VendorId, uint DeviceId, string VendorName, TextRefT VendorText, TextRefT VendorUrl, TextRefT DeviceName, TextRefT DeviceFamily): IDeviceIdentityT; diff --git a/src/IOLink.NET.IODD/Structure/Structure/Profile/ProfileBodyT.cs b/src/IOLink.NET.IODD/Structure/Structure/Profile/ProfileBodyT.cs new file mode 100644 index 0000000..38550ab --- /dev/null +++ b/src/IOLink.NET.IODD/Structure/Structure/Profile/ProfileBodyT.cs @@ -0,0 +1,5 @@ +using IOLink.NET.IODD.Structure.Interfaces.Profile; + +namespace IOLink.NET.IODD.Structure.Profile; + +public record ProfileBodyT(IDeviceIdentityT DeviceIdentity, IDeviceFunctionT DeviceFunction): IProfileBodyT; diff --git a/src/IODD.Structure/Structure/Profile/ProfileHeaderT.cs b/src/IOLink.NET.IODD/Structure/Structure/Profile/ProfileHeaderT.cs similarity index 74% rename from src/IODD.Structure/Structure/Profile/ProfileHeaderT.cs rename to src/IOLink.NET.IODD/Structure/Structure/Profile/ProfileHeaderT.cs index 2918ce7..e4a3f5d 100644 --- a/src/IODD.Structure/Structure/Profile/ProfileHeaderT.cs +++ b/src/IOLink.NET.IODD/Structure/Structure/Profile/ProfileHeaderT.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.IODD.Structure.Profile; - -public record ProfileHeaderT(string ProfileIdentification = "IO Device Profile", string ProfileRevision = "1.1", - string ProfileName = "Device Profile for IO Devices", string ProfileSource = "IO-Link Consortium", string ProfileClassID = "Device"); \ No newline at end of file +namespace IOLink.NET.IODD.Structure.Profile; + +public record ProfileHeaderT(string ProfileIdentification = "IO Device Profile", string ProfileRevision = "1.1", + string ProfileName = "Device Profile for IO Devices", string ProfileSource = "IO-Link Consortium", string ProfileClassID = "Device"); diff --git a/src/Vendors/Ifm/Data/IfmIoTCoreEnums.cs b/src/IOLink.NET.Vendors.Ifm/Data/IfmIoTCoreEnums.cs similarity index 99% rename from src/Vendors/Ifm/Data/IfmIoTCoreEnums.cs rename to src/IOLink.NET.Vendors.Ifm/Data/IfmIoTCoreEnums.cs index 5d0c303..a84620d 100644 --- a/src/Vendors/Ifm/Data/IfmIoTCoreEnums.cs +++ b/src/IOLink.NET.Vendors.Ifm/Data/IfmIoTCoreEnums.cs @@ -19,4 +19,4 @@ internal enum IfmIoTCorePortStatus PreOperate = 1, Operate = 2, CommunicationError = 3 -} \ No newline at end of file +} diff --git a/src/Vendors/Ifm/Data/IfmIoTCoreRequests.cs b/src/IOLink.NET.Vendors.Ifm/Data/IfmIoTCoreRequests.cs similarity index 97% rename from src/Vendors/Ifm/Data/IfmIoTCoreRequests.cs rename to src/IOLink.NET.Vendors.Ifm/Data/IfmIoTCoreRequests.cs index cf19a98..d51496c 100644 --- a/src/Vendors/Ifm/Data/IfmIoTCoreRequests.cs +++ b/src/IOLink.NET.Vendors.Ifm/Data/IfmIoTCoreRequests.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.Vendors.Ifm.Data; +namespace IOLink.NET.Vendors.Ifm.Data; public record IfmIoTCoreServiceRequestBase(string Adr, string Code = "request", int Cid = 1337); @@ -24,4 +24,4 @@ public record IfmIoTGetDataMultiParameters(IEnumerable Datatosend); public record IfmIoTGetTreeParameters(string? Adr, int? Level); -public record IfmIoTAcyclicParameters(int index, int? subindex); \ No newline at end of file +public record IfmIoTAcyclicParameters(int index, int? subindex); diff --git a/src/Vendors/Ifm/Data/IfmIoTCoreResponseBase.cs b/src/IOLink.NET.Vendors.Ifm/Data/IfmIoTCoreResponseBase.cs similarity index 90% rename from src/Vendors/Ifm/Data/IfmIoTCoreResponseBase.cs rename to src/IOLink.NET.Vendors.Ifm/Data/IfmIoTCoreResponseBase.cs index 070060e..3c3fd3c 100644 --- a/src/Vendors/Ifm/Data/IfmIoTCoreResponseBase.cs +++ b/src/IOLink.NET.Vendors.Ifm/Data/IfmIoTCoreResponseBase.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Nodes; -namespace IOLinkNET.Vendors.Ifm.Data; +namespace IOLink.NET.Vendors.Ifm.Data; public record IfmIoTCoreResponseBase(T Data, int Cid, int Code); @@ -15,4 +15,4 @@ public record IfmIoTCoreGetDataMultiEntry(int Code, JsonValue Data); public record IfmIoTCorePortTreeResponse(IfmIoTCoreTreeStructure Data, int Cid, int Code) : IfmIoTCoreComplexResponse(Data, Cid, Code); -public record IfmIoTCoreTreeStructure(IEnumerable? Subs, string Identifier); \ No newline at end of file +public record IfmIoTCoreTreeStructure(IEnumerable? Subs, string Identifier); diff --git a/src/Vendors/Ifm/IIfmIoTCoreClient.cs b/src/IOLink.NET.Vendors.Ifm/IIfmIoTCoreClient.cs similarity index 93% rename from src/Vendors/Ifm/IIfmIoTCoreClient.cs rename to src/IOLink.NET.Vendors.Ifm/IIfmIoTCoreClient.cs index 6c64d34..92604cd 100644 --- a/src/Vendors/Ifm/IIfmIoTCoreClient.cs +++ b/src/IOLink.NET.Vendors.Ifm/IIfmIoTCoreClient.cs @@ -1,8 +1,8 @@ -using IOLinkNET.Vendors.Ifm.Data; +using IOLink.NET.Vendors.Ifm.Data; using Refit; -namespace IOLinkNET.Vendors.Ifm; +namespace IOLink.NET.Vendors.Ifm; public interface IIfmIoTCoreClient { diff --git a/src/IOLink.NET.Vendors.Ifm/IOLink.NET.Vendors.Ifm.csproj b/src/IOLink.NET.Vendors.Ifm/IOLink.NET.Vendors.Ifm.csproj new file mode 100644 index 0000000..1d9ec90 --- /dev/null +++ b/src/IOLink.NET.Vendors.Ifm/IOLink.NET.Vendors.Ifm.csproj @@ -0,0 +1,28 @@ + + + + + + + + + + IOLink.NET.Vendors.Ifm + 0.1.0.0 + 0.1.0.0 + 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 + 0.1.0 + + + LICENSE + README.md + IOLinkNET is a library allows you to rapidly integrate and interact with devices that are using the IO-Link technology. + https://github.com/domdeger/IOLink.NET/ + https://github.com/domdeger/IOLink.NET/ + Github + + + + + + diff --git a/src/Vendors/Ifm/IOLinkNET.Vendors.Ifm.csproj b/src/IOLink.NET.Vendors.Ifm/IOLinkNET.Vendors.Ifm.csproj similarity index 89% rename from src/Vendors/Ifm/IOLinkNET.Vendors.Ifm.csproj rename to src/IOLink.NET.Vendors.Ifm/IOLinkNET.Vendors.Ifm.csproj index 789aa1e..1d9ec90 100644 --- a/src/Vendors/Ifm/IOLinkNET.Vendors.Ifm.csproj +++ b/src/IOLink.NET.Vendors.Ifm/IOLinkNET.Vendors.Ifm.csproj @@ -3,11 +3,11 @@ - + - IOLinkNET.Vendors.Ifm + IOLink.NET.Vendors.Ifm 0.1.0.0 0.1.0.0 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 diff --git a/src/Vendors/Ifm/IfmIoTCoreClientFactory.cs b/src/IOLink.NET.Vendors.Ifm/IfmIoTCoreClientFactory.cs similarity index 58% rename from src/Vendors/Ifm/IfmIoTCoreClientFactory.cs rename to src/IOLink.NET.Vendors.Ifm/IfmIoTCoreClientFactory.cs index ad65779..40543ef 100644 --- a/src/Vendors/Ifm/IfmIoTCoreClientFactory.cs +++ b/src/IOLink.NET.Vendors.Ifm/IfmIoTCoreClientFactory.cs @@ -1,16 +1,13 @@ using Refit; -namespace IOLinkNET.Vendors.Ifm; +namespace IOLink.NET.Vendors.Ifm; public static class IfmIoTCoreClientFactory { public static IIfmIoTCoreClient Create(string baseUrl) { - var httpClient = new HttpClient - { - BaseAddress = new Uri(baseUrl) - }; + var httpClient = new HttpClient { BaseAddress = new Uri(baseUrl) }; return RestService.For(httpClient); } -} \ No newline at end of file +} diff --git a/src/Vendors/Ifm/IfmIoTCoreMasterConnection.cs b/src/IOLink.NET.Vendors.Ifm/IfmIoTCoreMasterConnection.cs similarity index 54% rename from src/Vendors/Ifm/IfmIoTCoreMasterConnection.cs rename to src/IOLink.NET.Vendors.Ifm/IfmIoTCoreMasterConnection.cs index 900b823..e289333 100644 --- a/src/Vendors/Ifm/IfmIoTCoreMasterConnection.cs +++ b/src/IOLink.NET.Vendors.Ifm/IfmIoTCoreMasterConnection.cs @@ -1,10 +1,9 @@ using System.Text.Json; +using IOLink.NET.Core.Contracts; +using IOLink.NET.Core.Models; +using IOLink.NET.Vendors.Ifm.Data; -using IOLinkNET.Device.Contract; -using IOLinkNET.Device.Model; -using IOLinkNET.Vendors.Ifm.Data; - -namespace IOLinkNET.Vendors.Ifm; +namespace IOLink.NET.Vendors.Ifm; public class IfmIotCoreMasterConnection : IMasterConnection { @@ -17,7 +16,10 @@ public IfmIotCoreMasterConnection(IIfmIoTCoreClient client) public async Task GetPortCountAsync(CancellationToken cancellationToken = default) { - var portTree = await _client.GetPortTreeAsync(new IfmIoTGetPortTreeRequest(), cancellationToken); + var portTree = await _client.GetPortTreeAsync( + new IfmIoTGetPortTreeRequest(), + cancellationToken + ); if (portTree.Data.Subs == null) { @@ -26,20 +28,37 @@ public async Task GetPortCountAsync(CancellationToken cancellationToken = return (byte)portTree.Data.Subs.Count(); } - public async Task GetPortInformationAsync(byte portNumber, CancellationToken cancellationToken = default) + + public async Task GetPortInformationAsync( + byte portNumber, + CancellationToken cancellationToken = default + ) { var statusPath = IfmIoTCoreServicePathBuilder.PortDeviceStatusPath(portNumber); var productNamePath = IfmIoTCoreServicePathBuilder.PortDeviceProductNamePath(portNumber); var vendorIdPath = IfmIoTCoreServicePathBuilder.PortDeviceVendorIdPath(portNumber); var deviceIdPath = IfmIoTCoreServicePathBuilder.PortDeviceIdPath(portNumber); - var masterCycleTimeActualPath = IfmIoTCoreServicePathBuilder.PortMasterCycleTimeActualPath(portNumber); + var masterCycleTimeActualPath = IfmIoTCoreServicePathBuilder.PortMasterCycleTimeActualPath( + portNumber + ); var modePath = IfmIoTCoreServicePathBuilder.PortModePath(portNumber); var comSpeedPath = IfmIoTCoreServicePathBuilder.PortComSpeedPath(portNumber); - - var resp = await _client.GetDataMultiAsync(new IfmIoTGetDataMultiRequest(new[] { - statusPath, productNamePath, vendorIdPath, deviceIdPath, - masterCycleTimeActualPath, modePath, comSpeedPath }), cancellationToken); + var resp = await _client.GetDataMultiAsync( + new IfmIoTGetDataMultiRequest( + new[] + { + statusPath, + productNamePath, + vendorIdPath, + deviceIdPath, + masterCycleTimeActualPath, + modePath, + comSpeedPath, + } + ), + cancellationToken + ); var mode = resp.Data[modePath].Data.Deserialize(); var status = resp.Data[statusPath].Data.Deserialize(); @@ -50,22 +69,27 @@ public async Task GetPortInformationAsync(byte portNumber, Can var comSpeed = resp.Data[comSpeedPath].Data.Deserialize(); - var deviceInfo = new DeviceInformation(resp.Data[vendorIdPath].Data.Deserialize(), - resp.Data[deviceIdPath].Data.Deserialize(), - resp.Data[productNamePath].Data.Deserialize()! - ); + var deviceInfo = new DeviceInformation( + resp.Data[vendorIdPath].Data.Deserialize(), + resp.Data[deviceIdPath].Data.Deserialize(), + resp.Data[productNamePath].Data.Deserialize()! + ); // ToDo: extract and complete this logic. - var portStatus = status == IfmIoTCorePortStatus.NotConnected ? PortStatus.Disconnected : PortStatus.Connected; + var portStatus = + status == IfmIoTCorePortStatus.NotConnected + ? PortStatus.Disconnected + : PortStatus.Connected; var iolstatus = mode == IfmIotCorePortMode.IOLink ? PortStatus.IOLink : PortStatus.DI; var portInfo = new PortInformation(portNumber, portStatus | iolstatus, deviceInfo); return portInfo; - } - public async Task GetPortInformationsAsync(CancellationToken cancellationToken = default) + public async Task GetPortInformationsAsync( + CancellationToken cancellationToken = default + ) { var tasks = new List>(); for (byte i = 1; i <= await GetPortCountAsync(); i++) @@ -75,9 +99,17 @@ public async Task GetPortInformationsAsync(CancellationToken return await Task.WhenAll(tasks); } - public async Task> ReadIndexAsync(byte portNumber, ushort index, byte subIndex = 0, CancellationToken cancellationToken = default) + public async Task> ReadIndexAsync( + byte portNumber, + ushort index, + byte subIndex = 0, + CancellationToken cancellationToken = default + ) { - var resp = await _client.GetDeviceAcyclicDataAsync(new IfmIoTReadAcyclicRequest(portNumber, index, subIndex), cancellationToken); + var resp = await _client.GetDeviceAcyclicDataAsync( + new IfmIoTReadAcyclicRequest(portNumber, index, subIndex), + cancellationToken + ); if (resp?.Data == null) { return null; @@ -85,14 +117,28 @@ public async Task> ReadIndexAsync(byte portNumber, ushort i return Convert.FromHexString(resp.Data.Value); } - public async Task> ReadProcessDataInAsync(byte portNumber, CancellationToken cancellationToken = default) + + public async Task> ReadProcessDataInAsync( + byte portNumber, + CancellationToken cancellationToken = default + ) { - var resp = await _client.GetDevicePdinDataAsync(new IfmIoTReadPdInRequest(portNumber), cancellationToken); + var resp = await _client.GetDevicePdinDataAsync( + new IfmIoTReadPdInRequest(portNumber), + cancellationToken + ); return Convert.FromHexString(resp.Data.Value); } - public async Task> ReadProcessDataOutAsync(byte portNumber, CancellationToken cancellationToken = default) + + public async Task> ReadProcessDataOutAsync( + byte portNumber, + CancellationToken cancellationToken = default + ) { - var resp = await _client.GetDevicePdoutDataAsync(new IfmIoTReadPdOutRequest(portNumber), cancellationToken); + var resp = await _client.GetDevicePdoutDataAsync( + new IfmIoTReadPdOutRequest(portNumber), + cancellationToken + ); return Convert.FromHexString(resp.Data.Value); } -} \ No newline at end of file +} diff --git a/src/Vendors/Ifm/IfmIoTCoreMasterConnectionFactory.cs b/src/IOLink.NET.Vendors.Ifm/IfmIoTCoreMasterConnectionFactory.cs similarity index 88% rename from src/Vendors/Ifm/IfmIoTCoreMasterConnectionFactory.cs rename to src/IOLink.NET.Vendors.Ifm/IfmIoTCoreMasterConnectionFactory.cs index 9dfb0da..d2eb0fd 100644 --- a/src/Vendors/Ifm/IfmIoTCoreMasterConnectionFactory.cs +++ b/src/IOLink.NET.Vendors.Ifm/IfmIoTCoreMasterConnectionFactory.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.Vendors.Ifm; +namespace IOLink.NET.Vendors.Ifm; public static class IfmIoTCoreMasterConnectionFactory { @@ -7,4 +7,4 @@ public static IfmIotCoreMasterConnection Create(string baseUrl) var iotCoreClient = IfmIoTCoreClientFactory.Create(baseUrl); return new IfmIotCoreMasterConnection(iotCoreClient); } -} \ No newline at end of file +} diff --git a/src/Vendors/Ifm/IfmIoTCoreServicePathBuilder.cs b/src/IOLink.NET.Vendors.Ifm/IfmIoTCoreServicePathBuilder.cs similarity index 96% rename from src/Vendors/Ifm/IfmIoTCoreServicePathBuilder.cs rename to src/IOLink.NET.Vendors.Ifm/IfmIoTCoreServicePathBuilder.cs index b291faf..d727d29 100644 --- a/src/Vendors/Ifm/IfmIoTCoreServicePathBuilder.cs +++ b/src/IOLink.NET.Vendors.Ifm/IfmIoTCoreServicePathBuilder.cs @@ -1,4 +1,4 @@ -namespace IOLinkNET.Vendors.Ifm; +namespace IOLink.NET.Vendors.Ifm; internal static class IfmIoTCoreServicePathBuilder { @@ -15,4 +15,4 @@ internal static class IfmIoTCoreServicePathBuilder public static string PortModePath(byte portNumber) => $"/iolinkmaster/port[{portNumber}]/mode"; public static string PortComSpeedPath(byte portNumber) => $"/iolinkmaster/port[{portNumber}]/comspeed"; -} \ No newline at end of file +} diff --git a/src/IOLink.NET.Visualization/IODDConversion/IODDUserInterfaceConverter.cs b/src/IOLink.NET.Visualization/IODDConversion/IODDUserInterfaceConverter.cs new file mode 100644 index 0000000..9d6c25a --- /dev/null +++ b/src/IOLink.NET.Visualization/IODDConversion/IODDUserInterfaceConverter.cs @@ -0,0 +1,263 @@ +using IOLink.NET.Integration; +using IOLink.NET.IODD.Standard.Structure; +using IOLink.NET.IODD.Structure; +using IOLink.NET.IODD.Structure.Interfaces; +using IOLink.NET.IODD.Structure.Interfaces.Menu; +using IOLink.NET.IODD.Structure.Structure.Menu; +using IOLink.NET.Visualization.Structure.Structure; + +namespace IOLink.NET.Visualization.IODDConversion; + +public class IODDUserInterfaceConverter +{ + private readonly IIODevice _ioDevice; + private readonly IODDPortReader _ioddPortReader; + private readonly IUserInterfaceT _userInterface; + + public IODDUserInterfaceConverter(IIODevice ioDevice, IODDPortReader ioddPortReader) + { + _ioDevice = ioDevice; + _ioddPortReader = ioddPortReader; + _userInterface = ioDevice.ProfileBody.DeviceFunction.UserInterface; + } + + public UIInterface Convert() + { + if (_userInterface == null) + { + throw new ArgumentNullException("User Interface not present in IODD"); + } + + var observerRoleMenuSet = _userInterface.ObserverRoleMenuSet; + var maintenanceRoleMenuSet = _userInterface.MaintenanceRoleMenuSet; + var specialistRoleMenuSet = _userInterface.SpecialistRoleMenuSet; + + var convertedObserverRoleMenuSet = new MenuSet( + ConvertUIMenu( + observerRoleMenuSet.IdentificationMenu, + StandardMenuUserRoleReader.IdentificationMenu + ) + ?? throw new InvalidOperationException( + "Observerrole Menu must provide Identification Menu" + ), + ConvertUIMenu( + observerRoleMenuSet.ParameterMenu, + StandardMenuUserRoleReader.ParameterMenu + ), + ConvertUIMenu( + observerRoleMenuSet.ObservationMenu, + StandardMenuUserRoleReader.ObservationMenu + ), + ConvertUIMenu( + observerRoleMenuSet.DiagnosisMenu, + StandardMenuUserRoleReader.DiagnosisMenu + ), + _ioddPortReader + ); + + var convertedMaintenanceRoleMenuSet = new MenuSet( + ConvertUIMenu( + maintenanceRoleMenuSet.IdentificationMenu, + StandardMenuUserRoleReader.IdentificationMenu + ) + ?? throw new InvalidOperationException( + "Maintenancerole Menu must provide Identification Menu" + ), + ConvertUIMenu( + maintenanceRoleMenuSet.ParameterMenu, + StandardMenuUserRoleReader.ParameterMenu + ), + ConvertUIMenu( + maintenanceRoleMenuSet.ObservationMenu, + StandardMenuUserRoleReader.ObservationMenu + ), + ConvertUIMenu( + maintenanceRoleMenuSet.DiagnosisMenu, + StandardMenuUserRoleReader.DiagnosisMenu + ), + _ioddPortReader + ); + var convertedSpecialistRoleMenuSet = new MenuSet( + ConvertUIMenu( + specialistRoleMenuSet.IdentificationMenu, + StandardMenuUserRoleReader.IdentificationMenu + ) + ?? throw new InvalidOperationException( + "Specialistrole Menu must provide Identification Menu" + ), + ConvertUIMenu( + specialistRoleMenuSet.ParameterMenu, + StandardMenuUserRoleReader.ParameterMenu + ), + ConvertUIMenu( + specialistRoleMenuSet.ObservationMenu, + StandardMenuUserRoleReader.ObservationMenu + ), + ConvertUIMenu( + specialistRoleMenuSet.DiagnosisMenu, + StandardMenuUserRoleReader.DiagnosisMenu + ), + _ioddPortReader + ); + + return new UIInterface( + convertedObserverRoleMenuSet, + convertedMaintenanceRoleMenuSet, + convertedSpecialistRoleMenuSet, + _ioddPortReader + ); + } + + private UIMenu? ConvertUIMenu(UIMenuRefSimpleT? menu, string displayNameRef) + { + if (menu?.MenuId is not null) + { + var standardMenuName = GetExternalRefText(menu, displayNameRef); + var referencedMenu = + _userInterface.MenuCollection.Where(x => x.Menu.Id == menu.MenuId).FirstOrDefault() + ?? throw new InvalidOperationException("Referenced Menu not found"); + var menuName = + referencedMenu.Menu.Name == string.Empty + ? standardMenuName + : referencedMenu.Menu.Name; + + return new UIMenu( + menu.MenuId, + menuName, + null, + ConvertVariableRefs(referencedMenu.Menu.VariableRefs), + ConvertMenuRefs(referencedMenu.Menu.MenuRefs), + ConvertRecordItemRefs(referencedMenu.Menu.RecordItemRefs), + _ioddPortReader + ); + } + + return null; + } + + private UIMenu? ConvertUIMenu(UIMenuRefT? menu, string displayNameRef) + { + if (menu?.MenuId is not null) + { + var standardMenuName = GetExternalRefText(menu, displayNameRef); + var referencedMenu = + _userInterface.MenuCollection.Where(x => x.Menu.Id == menu.MenuId).FirstOrDefault() + ?? throw new InvalidOperationException("Referenced Menu not found"); + var menuName = + referencedMenu.Menu.Name == string.Empty + ? standardMenuName + : referencedMenu.Menu.Name; + + return new UIMenu( + menu.MenuId, + menuName, + menu.Condition, + ConvertVariableRefs(referencedMenu.Menu.VariableRefs), + ConvertMenuRefs(referencedMenu.Menu.MenuRefs), + ConvertRecordItemRefs(referencedMenu.Menu.RecordItemRefs), + _ioddPortReader + ); + } + + return null; + } + + private List? ConvertVariableRefs(IEnumerable? uiVariableRefs) + { + if (uiVariableRefs == null) + { + return null; + } + + var variables = new List(); + + foreach (UIVariableRefT uiVariableRef in uiVariableRefs) + { + var variable = _ioDevice + .ProfileBody.DeviceFunction.VariableCollection.Where(x => + x.Id == uiVariableRef.VariableId + ) + .SingleOrDefault(); + + variables.Add( + new UIVariable( + uiVariableRef.VariableId, + variable, + uiVariableRef.Gradient, + uiVariableRef.Offset, + uiVariableRef.UnitCode, + uiVariableRef.AccessRights, + uiVariableRef.ButtonValue, + uiVariableRef.DisplayFormat, + _ioddPortReader + ) + ); + } + + return variables; + } + + private List? ConvertMenuRefs(IEnumerable? menuRefs) + { + if (menuRefs == null) + { + return null; + } + + var menus = new List(); + + foreach (UIMenuRefT menuRef in menuRefs) + { + var convertedMenu = ConvertUIMenu(menuRef, string.Empty); + if (convertedMenu is not null) + { + menus.Add(convertedMenu); + } + } + + return menus; + } + + private List? ConvertRecordItemRefs( + IEnumerable? uiRecordItemRefs + ) + { + if (uiRecordItemRefs == null) + { + return null; + } + + var recordItems = new List(); + + foreach (UIRecordItemRefT itemRef in uiRecordItemRefs) + { + var recordItemVariable = _ioDevice + .ProfileBody.DeviceFunction.VariableCollection.Where(x => + x.Id == itemRef.VariableId + ) + .SingleOrDefault(); + + recordItems.Add( + new UIRecordItem( + itemRef.VariableId, + recordItemVariable, + itemRef.SubIndex, + itemRef.Gradient, + itemRef.Offset, + itemRef.UnitCode, + itemRef.AccessRights, + itemRef.ButtonValue, + itemRef.DisplayFormat, + _ioddPortReader + ) + ); + } + + return recordItems; + } + + private static string GetExternalRefText(UIMenuRefSimpleT? menu, string displayNameRef) => + menu?.Menu?.Name == string.Empty + ? StandardMenuUserRoleReader.GetStandardMenuUserRoleText(displayNameRef, string.Empty) + : menu?.Menu?.Name ?? string.Empty; +} diff --git a/src/IODD.Resolution/IOLinkNET.IODD.Resolution.csproj b/src/IOLink.NET.Visualization/IOLink.NET.Visualization.csproj similarity index 63% rename from src/IODD.Resolution/IOLinkNET.IODD.Resolution.csproj rename to src/IOLink.NET.Visualization/IOLink.NET.Visualization.csproj index ae9cc82..ebaee16 100644 --- a/src/IODD.Resolution/IOLinkNET.IODD.Resolution.csproj +++ b/src/IOLink.NET.Visualization/IOLink.NET.Visualization.csproj @@ -1,9 +1,9 @@ - + - + - IOLinkNET.IODD.Resolution + IOLink.NET.Visualization 0.1.0.0 0.1.0.0 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 @@ -12,8 +12,8 @@ LICENSE README.md - IOLinkNET is a library allows you to rapidly integrate and interact with devices that are using the IO-Link technology. - https://github.com/domdeger/IOLink.NET/ + IOLink.NET Visualization - UI and visualization components for IOLink.NET including menu conversion and display structures. + https://github.com/domdeger/IOLink.NET/ https://github.com/domdeger/IOLink.NET/ Github @@ -21,4 +21,4 @@ - \ No newline at end of file + diff --git a/src/Visualization/IOLinkNET.Visualization.csproj b/src/IOLink.NET.Visualization/IOLinkNET.Visualization.csproj similarity index 100% rename from src/Visualization/IOLinkNET.Visualization.csproj rename to src/IOLink.NET.Visualization/IOLinkNET.Visualization.csproj diff --git a/src/Visualization/Menu/MenuDataReader.cs b/src/IOLink.NET.Visualization/Menu/MenuDataReader.cs similarity index 72% rename from src/Visualization/Menu/MenuDataReader.cs rename to src/IOLink.NET.Visualization/Menu/MenuDataReader.cs index f023829..71ad65d 100644 --- a/src/Visualization/Menu/MenuDataReader.cs +++ b/src/IOLink.NET.Visualization/Menu/MenuDataReader.cs @@ -1,12 +1,11 @@ -using IOLinkNET.Integration; -using IOLinkNET.IODD.Structure; -using IOLinkNET.IODD.Structure.Interfaces.Menu; -using IOLinkNET.Visualization.IODDConversion; -using IOLinkNET.Visualization.Structure.Structure; +using IOLink.NET.Integration; +using IOLink.NET.IODD.Structure; +using IOLink.NET.IODD.Structure.Interfaces.Menu; +using IOLink.NET.Visualization.IODDConversion; +using IOLink.NET.Visualization.Structure.Structure; +using static IOLink.NET.Integration.IODDPortReader; -using static IOLinkNET.Integration.IODDPortReader; - -namespace IOLinkNET.Visualization.Menu +namespace IOLink.NET.Visualization.Menu { public class MenuDataReader { @@ -28,7 +27,8 @@ public async Task InitializeForPortAsync(byte port) public IUserInterfaceT GetIODDRawMenuStructure() { - return _device?.ProfileBody.DeviceFunction.UserInterface ?? throw new InvalidOperationException("MenuDataReader is not initialized"); + return _device?.ProfileBody.DeviceFunction.UserInterface + ?? throw new InvalidOperationException("MenuDataReader is not initialized"); } public UIInterface GetReadableMenus() diff --git a/src/Visualization.Structure/IOLinkNET.Visualization.Structure.csproj b/src/IOLink.NET.Visualization/Structure/IOLinkNET.Visualization.Structure.csproj similarity index 100% rename from src/Visualization.Structure/IOLinkNET.Visualization.Structure.csproj rename to src/IOLink.NET.Visualization/Structure/IOLinkNET.Visualization.Structure.csproj diff --git a/src/Visualization.Structure/Interfaces/IReadable.cs b/src/IOLink.NET.Visualization/Structure/Interfaces/IReadable.cs similarity index 52% rename from src/Visualization.Structure/Interfaces/IReadable.cs rename to src/IOLink.NET.Visualization/Structure/Interfaces/IReadable.cs index 9897330..b9f2314 100644 --- a/src/Visualization.Structure/Interfaces/IReadable.cs +++ b/src/IOLink.NET.Visualization/Structure/Interfaces/IReadable.cs @@ -1,6 +1,6 @@ -using IOLinkNET.Integration; +using IOLink.NET.Integration; -namespace IOLinkNET.Visualization.Structure.Interfaces; +namespace IOLink.NET.Visualization.Structure.Interfaces; internal interface IReadable { IODDPortReader IoddPortReader { get; } diff --git a/src/Visualization.Structure/Structure/MenuSet.cs b/src/IOLink.NET.Visualization/Structure/Structure/MenuSet.cs similarity index 80% rename from src/Visualization.Structure/Structure/MenuSet.cs rename to src/IOLink.NET.Visualization/Structure/Structure/MenuSet.cs index 0449d96..b04e070 100644 --- a/src/Visualization.Structure/Structure/MenuSet.cs +++ b/src/IOLink.NET.Visualization/Structure/Structure/MenuSet.cs @@ -1,7 +1,7 @@ -using IOLinkNET.Integration; -using IOLinkNET.Visualization.Structure.Interfaces; +using IOLink.NET.Integration; +using IOLink.NET.Visualization.Structure.Interfaces; -namespace IOLinkNET.Visualization.Structure.Structure; +namespace IOLink.NET.Visualization.Structure.Structure; public record MenuSet(UIMenu IdentificationMenu, UIMenu? ParameterMenu, UIMenu? ObservationMenu, UIMenu? DiagnosisMenu, IODDPortReader IoddPortReader) : IReadable { public async Task ReadAsync() diff --git a/src/Visualization.Structure/Structure/RoleMenu.cs b/src/IOLink.NET.Visualization/Structure/Structure/RoleMenu.cs similarity index 82% rename from src/Visualization.Structure/Structure/RoleMenu.cs rename to src/IOLink.NET.Visualization/Structure/Structure/RoleMenu.cs index 93a4ff9..371a289 100644 --- a/src/Visualization.Structure/Structure/RoleMenu.cs +++ b/src/IOLink.NET.Visualization/Structure/Structure/RoleMenu.cs @@ -1,7 +1,7 @@ -using IOLinkNET.Integration; -using IOLinkNET.Visualization.Structure.Interfaces; +using IOLink.NET.Integration; +using IOLink.NET.Visualization.Structure.Interfaces; -namespace IOLinkNET.Visualization.Structure.Structure +namespace IOLink.NET.Visualization.Structure.Structure { public record RoleMenu(UIMenu IdentificationMenu, UIMenu? ParameterMenu, UIMenu? ObservationMenu, UIMenu? DiagnosisMenu, IODDPortReader IoddPortReader) : IReadable { diff --git a/src/Visualization.Structure/Structure/UIInterface.cs b/src/IOLink.NET.Visualization/Structure/Structure/UIInterface.cs similarity index 70% rename from src/Visualization.Structure/Structure/UIInterface.cs rename to src/IOLink.NET.Visualization/Structure/Structure/UIInterface.cs index 8bee6ac..41b959c 100644 --- a/src/Visualization.Structure/Structure/UIInterface.cs +++ b/src/IOLink.NET.Visualization/Structure/Structure/UIInterface.cs @@ -1,7 +1,7 @@ -using IOLinkNET.Integration; -using IOLinkNET.Visualization.Structure.Interfaces; +using IOLink.NET.Integration; +using IOLink.NET.Visualization.Structure.Interfaces; -namespace IOLinkNET.Visualization.Structure.Structure; +namespace IOLink.NET.Visualization.Structure.Structure; public record UIInterface(MenuSet ObserverRoleMenu, MenuSet MaintenanceRoleMenu, MenuSet SpecialistRoleMenu, IODDPortReader IoddPortReader) : IReadable { public async Task ReadAsync() diff --git a/src/Visualization.Structure/Structure/UIMenu.cs b/src/IOLink.NET.Visualization/Structure/Structure/UIMenu.cs similarity index 81% rename from src/Visualization.Structure/Structure/UIMenu.cs rename to src/IOLink.NET.Visualization/Structure/Structure/UIMenu.cs index a9d2345..9a6c91d 100644 --- a/src/Visualization.Structure/Structure/UIMenu.cs +++ b/src/IOLink.NET.Visualization/Structure/Structure/UIMenu.cs @@ -1,8 +1,8 @@ -using IOLinkNET.Integration; -using IOLinkNET.IODD.Structure.ProcessData; -using IOLinkNET.Visualization.Structure.Interfaces; +using IOLink.NET.Integration; +using IOLink.NET.IODD.Structure.ProcessData; +using IOLink.NET.Visualization.Structure.Interfaces; -namespace IOLinkNET.Visualization.Structure.Structure; +namespace IOLink.NET.Visualization.Structure.Structure; public record UIMenu(string Id, string? Name, ConditionT? Condition, IEnumerable? Variables, IEnumerable? SubMenus, IEnumerable? RecordItems, IODDPortReader IoddPortReader) : IReadable { public async Task ReadAsync() diff --git a/src/Visualization.Structure/Structure/UIRecordItem.cs b/src/IOLink.NET.Visualization/Structure/Structure/UIRecordItem.cs similarity index 74% rename from src/Visualization.Structure/Structure/UIRecordItem.cs rename to src/IOLink.NET.Visualization/Structure/Structure/UIRecordItem.cs index 5f72771..0039da5 100644 --- a/src/Visualization.Structure/Structure/UIRecordItem.cs +++ b/src/IOLink.NET.Visualization/Structure/Structure/UIRecordItem.cs @@ -1,10 +1,10 @@ -using IOLinkNET.Integration; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.DeviceFunction; -using IOLinkNET.IODD.Structure.Structure.Datatypes; -using IOLinkNET.Visualization.Structure.Interfaces; +using IOLink.NET.Integration; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.DeviceFunction; +using IOLink.NET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.Visualization.Structure.Interfaces; -namespace IOLinkNET.Visualization.Structure.Structure; +namespace IOLink.NET.Visualization.Structure.Structure; public record UIRecordItem(string VariableId, VariableT? Variable, byte SubIndex, decimal? Gradient, decimal? Offset, uint? UnitCode, AccessRightsT? AccessRights, string? ButtonValue, DisplayFormat? DisplayFormat, IODDPortReader IoddPortReader) : IReadable { public object? Value; diff --git a/src/Visualization.Structure/Structure/UIVariable.cs b/src/IOLink.NET.Visualization/Structure/Structure/UIVariable.cs similarity index 62% rename from src/Visualization.Structure/Structure/UIVariable.cs rename to src/IOLink.NET.Visualization/Structure/Structure/UIVariable.cs index b194470..5cdeb70 100644 --- a/src/Visualization.Structure/Structure/UIVariable.cs +++ b/src/IOLink.NET.Visualization/Structure/Structure/UIVariable.cs @@ -1,10 +1,10 @@ -using IOLinkNET.Integration; -using IOLinkNET.IODD.Structure.Datatypes; -using IOLinkNET.IODD.Structure.DeviceFunction; -using IOLinkNET.IODD.Structure.Structure.Datatypes; -using IOLinkNET.Visualization.Structure.Interfaces; +using IOLink.NET.Integration; +using IOLink.NET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Structure.DeviceFunction; +using IOLink.NET.IODD.Structure.Structure.Datatypes; +using IOLink.NET.Visualization.Structure.Interfaces; -namespace IOLinkNET.Visualization.Structure.Structure; +namespace IOLink.NET.Visualization.Structure.Structure; public record UIVariable(string VariableId, VariableT? Variable, decimal? Gradient, decimal? Offset, uint? UnitCode, AccessRightsT? AccessRights, string? ButtonValue, DisplayFormat? DisplayFormat, IODDPortReader IoddPortReader) : IReadable { public object? Value; diff --git a/src/IOLink.NET.sln b/src/IOLink.NET.sln index 0c0273a..1379fe2 100644 --- a/src/IOLink.NET.sln +++ b/src/IOLink.NET.sln @@ -3,139 +3,137 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLinkNET.IODD.Parser", "IODD.Parser\IOLinkNET.IODD.Parser.csproj", "{BF0C1D43-DE5A-4321-AC58-BF3CB9E39ED2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLink.NET.Core", "IOLink.NET.Core\IOLink.NET.Core.csproj", "{6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLinkNET.IODD.Structure", "IODD.Structure\IOLinkNET.IODD.Structure.csproj", "{4964A6A7-6C03-48FB-AC79-1802B3E21579}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLink.NET.IODD", "IOLink.NET.IODD\IOLink.NET.IODD.csproj", "{87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLinkNET.IODD.Resolution", "IODD.Resolution\IOLinkNET.IODD.Resolution.csproj", "{A3E33463-D3F4-44D7-9BA7-D29B39D814D2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLink.NET", "IOLink.NET\IOLink.NET.csproj", "{68850978-D7F8-3884-BA75-81C94EE2BBA2}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{A87B4B20-7BB8-452F-934A-8860F6252B80}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLink.NET.Visualization", "IOLink.NET.Visualization\IOLink.NET.Visualization.csproj", "{217116F3-47B7-AC9F-419A-3A7BFA55E53E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Conversion.Tests", "Tests\Conversion.Tests\Conversion.Tests.csproj", "{E15B2355-25E7-4BA4-B541-1878426EADDA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLink.NET.Vendors.Ifm", "IOLink.NET.Vendors.Ifm\IOLink.NET.Vendors.Ifm.csproj", "{F5825307-61B0-FA2A-9637-678A14B12F4E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IODD.Parser.Tests", "Tests\IODD.Parser.Tests\IODD.Parser.Tests.csproj", "{DE82F0B8-0063-477D-97D9-B484B2BAA55A}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IODD.Resolution.Tests", "Tests\IODD.Resolution.Tests\IODD.Resolution.Tests.csproj", "{50A473CC-55EF-4DC4-9B8B-6E3D3ECC193C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IOLink.NET.Tests", "Tests\IOLink.NET.Tests\IOLink.NET.Tests.csproj", "{7FD3341D-CD95-4C92-B393-01499B33E713}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLinkNET.Conversion", "Conversion\IOLinkNET.Conversion.csproj", "{44A65C0C-C0C8-4FF1-BA39-51652259580F}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vendors.Ifm", "Tests\Vendors.Ifm\Vendors.Ifm.csproj", "{BC34E0AF-56D8-4ED0-8A3C-575219A0D922}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLinkNET.IODD.Provider", "IODD.Provider\IOLinkNET.IODD.Provider.csproj", "{8A1B5417-9CFC-4821-A006-4938A8EE4ED3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IODD.Provider.Tests", "Tests\IODD.Provider.Tests\IODD.Provider.Tests.csproj", "{D79F2EA0-3E3E-419A-9C2C-72133FD18799}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Device", "Device\IOLinkNET.Device.csproj", "{973D98F0-A935-41B2-B7B4-728ED935C29F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLinkNET.Integration", "Integration\IOLinkNET.Integration.csproj", "{E588E446-3E1E-432E-8DF0-9496C845D476}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Integration.Tests", "Tests\Integration.Tests\Integration.Tests.csproj", "{07726DDE-3D02-4572-8B0E-3ADB429412B2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Vendors", "Vendors", "{59FD2624-BFA2-4199-9A85-7659DBCB49D9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ifm", "Vendors\Ifm\IOLinkNET.Vendors.Ifm.csproj", "{BC850865-5225-49D5-86C6-EA5F03A49CDD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vendors.Ifm", "Tests\Vendors.Ifm\Vendors.Ifm.csproj", "{D3134702-1B3E-40B2-95C7-0C0B1305A417}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLinkNET.Visualization", "Visualization\IOLinkNET.Visualization.csproj", "{D91EC38B-B260-42F5-94E6-4277514DFD9F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOLinkNET.Visualization.Structure", "Visualization.Structure\IOLinkNET.Visualization.Structure.csproj", "{02BE1194-6105-4C66-A105-B9C4B4A41498}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Visualization.Tests", "Tests\Visualization.Tests\Visualization.Tests.csproj", "{0E89DBC2-CDCE-4A84-9818-1951940EF9FC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IOLinkNET.IODD.Standard", "IODD.Standard\IOLinkNET.IODD.Standard.csproj", "{6218F666-CCD6-469E-A8A4-1C8966F98FFB}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IOLink.NET.Core.Tests", "Tests\IOLink.NET.Core.Tests\IOLink.NET.Core.Tests.csproj", "{03519BC5-67C4-40C7-96F8-218B9C4DE1D2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BF0C1D43-DE5A-4321-AC58-BF3CB9E39ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BF0C1D43-DE5A-4321-AC58-BF3CB9E39ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BF0C1D43-DE5A-4321-AC58-BF3CB9E39ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BF0C1D43-DE5A-4321-AC58-BF3CB9E39ED2}.Release|Any CPU.Build.0 = Release|Any CPU - {4964A6A7-6C03-48FB-AC79-1802B3E21579}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4964A6A7-6C03-48FB-AC79-1802B3E21579}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4964A6A7-6C03-48FB-AC79-1802B3E21579}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4964A6A7-6C03-48FB-AC79-1802B3E21579}.Release|Any CPU.Build.0 = Release|Any CPU - {A3E33463-D3F4-44D7-9BA7-D29B39D814D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A3E33463-D3F4-44D7-9BA7-D29B39D814D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A3E33463-D3F4-44D7-9BA7-D29B39D814D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A3E33463-D3F4-44D7-9BA7-D29B39D814D2}.Release|Any CPU.Build.0 = Release|Any CPU - {E15B2355-25E7-4BA4-B541-1878426EADDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E15B2355-25E7-4BA4-B541-1878426EADDA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E15B2355-25E7-4BA4-B541-1878426EADDA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E15B2355-25E7-4BA4-B541-1878426EADDA}.Release|Any CPU.Build.0 = Release|Any CPU - {DE82F0B8-0063-477D-97D9-B484B2BAA55A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DE82F0B8-0063-477D-97D9-B484B2BAA55A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DE82F0B8-0063-477D-97D9-B484B2BAA55A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DE82F0B8-0063-477D-97D9-B484B2BAA55A}.Release|Any CPU.Build.0 = Release|Any CPU - {50A473CC-55EF-4DC4-9B8B-6E3D3ECC193C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {50A473CC-55EF-4DC4-9B8B-6E3D3ECC193C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {50A473CC-55EF-4DC4-9B8B-6E3D3ECC193C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {50A473CC-55EF-4DC4-9B8B-6E3D3ECC193C}.Release|Any CPU.Build.0 = Release|Any CPU - {44A65C0C-C0C8-4FF1-BA39-51652259580F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {44A65C0C-C0C8-4FF1-BA39-51652259580F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {44A65C0C-C0C8-4FF1-BA39-51652259580F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {44A65C0C-C0C8-4FF1-BA39-51652259580F}.Release|Any CPU.Build.0 = Release|Any CPU - {8A1B5417-9CFC-4821-A006-4938A8EE4ED3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A1B5417-9CFC-4821-A006-4938A8EE4ED3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A1B5417-9CFC-4821-A006-4938A8EE4ED3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A1B5417-9CFC-4821-A006-4938A8EE4ED3}.Release|Any CPU.Build.0 = Release|Any CPU - {D79F2EA0-3E3E-419A-9C2C-72133FD18799}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D79F2EA0-3E3E-419A-9C2C-72133FD18799}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D79F2EA0-3E3E-419A-9C2C-72133FD18799}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D79F2EA0-3E3E-419A-9C2C-72133FD18799}.Release|Any CPU.Build.0 = Release|Any CPU - {973D98F0-A935-41B2-B7B4-728ED935C29F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {973D98F0-A935-41B2-B7B4-728ED935C29F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {973D98F0-A935-41B2-B7B4-728ED935C29F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {973D98F0-A935-41B2-B7B4-728ED935C29F}.Release|Any CPU.Build.0 = Release|Any CPU - {E588E446-3E1E-432E-8DF0-9496C845D476}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E588E446-3E1E-432E-8DF0-9496C845D476}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E588E446-3E1E-432E-8DF0-9496C845D476}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E588E446-3E1E-432E-8DF0-9496C845D476}.Release|Any CPU.Build.0 = Release|Any CPU - {07726DDE-3D02-4572-8B0E-3ADB429412B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {07726DDE-3D02-4572-8B0E-3ADB429412B2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {07726DDE-3D02-4572-8B0E-3ADB429412B2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {07726DDE-3D02-4572-8B0E-3ADB429412B2}.Release|Any CPU.Build.0 = Release|Any CPU - {BC850865-5225-49D5-86C6-EA5F03A49CDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BC850865-5225-49D5-86C6-EA5F03A49CDD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BC850865-5225-49D5-86C6-EA5F03A49CDD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BC850865-5225-49D5-86C6-EA5F03A49CDD}.Release|Any CPU.Build.0 = Release|Any CPU - {D3134702-1B3E-40B2-95C7-0C0B1305A417}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D3134702-1B3E-40B2-95C7-0C0B1305A417}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D3134702-1B3E-40B2-95C7-0C0B1305A417}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D3134702-1B3E-40B2-95C7-0C0B1305A417}.Release|Any CPU.Build.0 = Release|Any CPU - {D91EC38B-B260-42F5-94E6-4277514DFD9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D91EC38B-B260-42F5-94E6-4277514DFD9F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D91EC38B-B260-42F5-94E6-4277514DFD9F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D91EC38B-B260-42F5-94E6-4277514DFD9F}.Release|Any CPU.Build.0 = Release|Any CPU - {02BE1194-6105-4C66-A105-B9C4B4A41498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {02BE1194-6105-4C66-A105-B9C4B4A41498}.Debug|Any CPU.Build.0 = Debug|Any CPU - {02BE1194-6105-4C66-A105-B9C4B4A41498}.Release|Any CPU.ActiveCfg = Release|Any CPU - {02BE1194-6105-4C66-A105-B9C4B4A41498}.Release|Any CPU.Build.0 = Release|Any CPU - {0E89DBC2-CDCE-4A84-9818-1951940EF9FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E89DBC2-CDCE-4A84-9818-1951940EF9FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E89DBC2-CDCE-4A84-9818-1951940EF9FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E89DBC2-CDCE-4A84-9818-1951940EF9FC}.Release|Any CPU.Build.0 = Release|Any CPU - {6218F666-CCD6-469E-A8A4-1C8966F98FFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6218F666-CCD6-469E-A8A4-1C8966F98FFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6218F666-CCD6-469E-A8A4-1C8966F98FFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6218F666-CCD6-469E-A8A4-1C8966F98FFB}.Release|Any CPU.Build.0 = Release|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Debug|x64.ActiveCfg = Debug|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Debug|x64.Build.0 = Debug|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Debug|x86.ActiveCfg = Debug|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Debug|x86.Build.0 = Debug|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Release|Any CPU.Build.0 = Release|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Release|x64.ActiveCfg = Release|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Release|x64.Build.0 = Release|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Release|x86.ActiveCfg = Release|Any CPU + {6C7C4E2A-8B5A-4D1E-9F2B-1A2B3C4D5E6F}.Release|x86.Build.0 = Release|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Debug|Any CPU.Build.0 = Debug|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Debug|x64.ActiveCfg = Debug|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Debug|x64.Build.0 = Debug|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Debug|x86.ActiveCfg = Debug|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Debug|x86.Build.0 = Debug|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Release|Any CPU.ActiveCfg = Release|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Release|Any CPU.Build.0 = Release|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Release|x64.ActiveCfg = Release|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Release|x64.Build.0 = Release|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Release|x86.ActiveCfg = Release|Any CPU + {87F7A0BA-19A4-9B1B-3D5C-5EA118F83103}.Release|x86.Build.0 = Release|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Debug|x64.ActiveCfg = Debug|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Debug|x64.Build.0 = Debug|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Debug|x86.ActiveCfg = Debug|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Debug|x86.Build.0 = Debug|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Release|Any CPU.Build.0 = Release|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Release|x64.ActiveCfg = Release|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Release|x64.Build.0 = Release|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Release|x86.ActiveCfg = Release|Any CPU + {68850978-D7F8-3884-BA75-81C94EE2BBA2}.Release|x86.Build.0 = Release|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Debug|x64.ActiveCfg = Debug|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Debug|x64.Build.0 = Debug|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Debug|x86.ActiveCfg = Debug|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Debug|x86.Build.0 = Debug|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Release|Any CPU.Build.0 = Release|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Release|x64.ActiveCfg = Release|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Release|x64.Build.0 = Release|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Release|x86.ActiveCfg = Release|Any CPU + {217116F3-47B7-AC9F-419A-3A7BFA55E53E}.Release|x86.Build.0 = Release|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Debug|x64.ActiveCfg = Debug|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Debug|x64.Build.0 = Debug|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Debug|x86.ActiveCfg = Debug|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Debug|x86.Build.0 = Debug|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Release|Any CPU.Build.0 = Release|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Release|x64.ActiveCfg = Release|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Release|x64.Build.0 = Release|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Release|x86.ActiveCfg = Release|Any CPU + {F5825307-61B0-FA2A-9637-678A14B12F4E}.Release|x86.Build.0 = Release|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Debug|x64.ActiveCfg = Debug|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Debug|x64.Build.0 = Debug|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Debug|x86.ActiveCfg = Debug|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Debug|x86.Build.0 = Debug|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Release|Any CPU.Build.0 = Release|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Release|x64.ActiveCfg = Release|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Release|x64.Build.0 = Release|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Release|x86.ActiveCfg = Release|Any CPU + {7FD3341D-CD95-4C92-B393-01499B33E713}.Release|x86.Build.0 = Release|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Debug|x64.ActiveCfg = Debug|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Debug|x64.Build.0 = Debug|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Debug|x86.ActiveCfg = Debug|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Debug|x86.Build.0 = Debug|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Release|Any CPU.Build.0 = Release|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Release|x64.ActiveCfg = Release|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Release|x64.Build.0 = Release|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Release|x86.ActiveCfg = Release|Any CPU + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922}.Release|x86.Build.0 = Release|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Debug|x64.ActiveCfg = Debug|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Debug|x64.Build.0 = Debug|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Debug|x86.ActiveCfg = Debug|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Debug|x86.Build.0 = Debug|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Release|Any CPU.Build.0 = Release|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Release|x64.ActiveCfg = Release|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Release|x64.Build.0 = Release|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Release|x86.ActiveCfg = Release|Any CPU + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {E15B2355-25E7-4BA4-B541-1878426EADDA} = {A87B4B20-7BB8-452F-934A-8860F6252B80} - {DE82F0B8-0063-477D-97D9-B484B2BAA55A} = {A87B4B20-7BB8-452F-934A-8860F6252B80} - {50A473CC-55EF-4DC4-9B8B-6E3D3ECC193C} = {A87B4B20-7BB8-452F-934A-8860F6252B80} - {D79F2EA0-3E3E-419A-9C2C-72133FD18799} = {A87B4B20-7BB8-452F-934A-8860F6252B80} - {07726DDE-3D02-4572-8B0E-3ADB429412B2} = {A87B4B20-7BB8-452F-934A-8860F6252B80} - {BC850865-5225-49D5-86C6-EA5F03A49CDD} = {59FD2624-BFA2-4199-9A85-7659DBCB49D9} - {D3134702-1B3E-40B2-95C7-0C0B1305A417} = {A87B4B20-7BB8-452F-934A-8860F6252B80} - {0E89DBC2-CDCE-4A84-9818-1951940EF9FC} = {A87B4B20-7BB8-452F-934A-8860F6252B80} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {93263C67-134C-47AF-937F-1667CA44144A} + {7FD3341D-CD95-4C92-B393-01499B33E713} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {BC34E0AF-56D8-4ED0-8A3C-575219A0D922} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {03519BC5-67C4-40C7-96F8-218B9C4DE1D2} = {0AB3BF05-4346-4AA6-1389-037BE0695223} EndGlobalSection EndGlobal diff --git a/src/Conversion/Extensions/ByteArrayExtensions.cs b/src/IOLink.NET/Conversion/Extensions/ByteArrayExtensions.cs similarity index 90% rename from src/Conversion/Extensions/ByteArrayExtensions.cs rename to src/IOLink.NET/Conversion/Extensions/ByteArrayExtensions.cs index 6b69163..8766460 100644 --- a/src/Conversion/Extensions/ByteArrayExtensions.cs +++ b/src/IOLink.NET/Conversion/Extensions/ByteArrayExtensions.cs @@ -1,11 +1,11 @@ -namespace Conversion.Extensions; +namespace IOLink.NET.Conversion.Extensions; public static class ByteArrayExtensions { /// /// If we have a negative integer, the resulting bytearray will be filled with 1s on the left, that may exceed the given bit length. /// This method will set the first (8 - bitLength % 8) bits to 0. - /// Requires big-endian byte array. + /// Requires big-endian byte array. public static byte[] PinNegativeIntToRequiredBitLength(this byte[] data, ushort bitLength) { if (bitLength % 8 == 0) @@ -18,10 +18,9 @@ public static byte[] PinNegativeIntToRequiredBitLength(this byte[] data, ushort return data; } - public static byte[] TruncateToBitLength(this byte[] data, ushort bitLength) { var requiredByteLength = bitLength / 8 + (bitLength % 8 != 0 ? 1 : 0); return data[(data.Length - requiredByteLength)..]; } -} \ No newline at end of file +} diff --git a/src/IOLink.NET/Conversion/IIoddDataConverter.cs b/src/IOLink.NET/Conversion/IIoddDataConverter.cs new file mode 100644 index 0000000..3a0807a --- /dev/null +++ b/src/IOLink.NET/Conversion/IIoddDataConverter.cs @@ -0,0 +1,9 @@ +using IOLink.NET.IODD.Resolution; + +namespace IOLink.NET.Conversion; + +public interface IIoddDataConverter +{ + object Convert(ParsableDatatype datatypeDef, ReadOnlySpan data); + byte[] ConvertToBytes(object value, ParsableDatatype datatypeDef); +} diff --git a/src/Conversion/IOLinkNET.Conversion.csproj b/src/IOLink.NET/Conversion/IOLinkNET.Conversion.csproj similarity index 100% rename from src/Conversion/IOLinkNET.Conversion.csproj rename to src/IOLink.NET/Conversion/IOLinkNET.Conversion.csproj diff --git a/src/Conversion/IoddComplexConverter.cs b/src/IOLink.NET/Conversion/IoddComplexConverter.cs similarity index 94% rename from src/Conversion/IoddComplexConverter.cs rename to src/IOLink.NET/Conversion/IoddComplexConverter.cs index 2573d42..604c333 100644 --- a/src/Conversion/IoddComplexConverter.cs +++ b/src/IOLink.NET/Conversion/IoddComplexConverter.cs @@ -1,59 +1,59 @@ -using System.Collections; - -using IOLinkNET.IODD.Resolution; - -namespace IOLinkNET.Conversion; - -internal static class IoddComplexConverter -{ - public static object Convert(ParsableComplexDataTypeDef complexTypeDef, ReadOnlySpan data) - => complexTypeDef switch - { - ParsableRecord recordType => ConvertRecordType(recordType, data), - ParsableArray arrayTypeDef => ConvertArrayT(arrayTypeDef, data), - _ => throw new InvalidOperationException($"Type {complexTypeDef.GetType().Name} is not supported.") - }; - - private static IEnumerable<(string key, object value)> ConvertArrayT(ParsableArray arrayTypeDef, ReadOnlySpan data) - { - var result = new List<(string key, object value)>(); - var bits = new BitArray(data.ToArray().Reverse().ToArray()); - var arrayBitLength = arrayTypeDef.Length * arrayTypeDef.Type.Length; - for (var i = 1; i <= arrayTypeDef.Length; i++) - { - var itemOffset = (ushort)(arrayBitLength - i * arrayTypeDef.Type.Length); - var itemData = ReadWithPadding(bits, itemOffset, arrayTypeDef.Type.Length); - result.Add(($"{arrayTypeDef.Name}_{i}", IoddScalarReader.Convert(arrayTypeDef.Type, itemData))); - } - - return result; - } - - private static IEnumerable<(string key, object value)> ConvertRecordType(ParsableRecord recordType, ReadOnlySpan data) - { - var result = new List<(string key, object value)>(); - var bits = new BitArray(data.ToArray().Reverse().ToArray()); - foreach (ParsableRecordItem? recordItemDef in recordType.Entries.OrderBy(x => x.BitOffset)) - { - var translatedOffset = (ushort)(recordType.Length - recordItemDef.BitOffset); - result.Add((recordItemDef.Name, - IoddScalarReader.Convert(recordItemDef.Type, - ReadWithPadding(bits, recordItemDef.BitOffset, recordItemDef.Type.Length).ToArray().Reverse().ToArray()))); - } - - return result; - } - - private static ReadOnlySpan ReadWithPadding(BitArray bits, ushort offset, ushort length) - { - var result = new byte[length / 8 + (length % 8 != 0 ? 1 : 0)]; - - for (var i = 0; i < length; i++) - { - var bit = bits[offset + i]; - result[i / 8] |= (byte)(bit ? 1 << (i % 8) : 0); - } - - return result; - } -} \ No newline at end of file +using System.Collections; + +using IOLink.NET.IODD.Resolution; + +namespace IOLink.NET.Conversion; + +internal static class IoddComplexConverter +{ + public static object Convert(ParsableComplexDataTypeDef complexTypeDef, ReadOnlySpan data) + => complexTypeDef switch + { + ParsableRecord recordType => ConvertRecordType(recordType, data), + ParsableArray arrayTypeDef => ConvertArrayT(arrayTypeDef, data), + _ => throw new InvalidOperationException($"Type {complexTypeDef.GetType().Name} is not supported.") + }; + + private static IEnumerable<(string key, object value)> ConvertArrayT(ParsableArray arrayTypeDef, ReadOnlySpan data) + { + var result = new List<(string key, object value)>(); + var bits = new BitArray(data.ToArray().Reverse().ToArray()); + var arrayBitLength = arrayTypeDef.Length * arrayTypeDef.Type.Length; + for (var i = 1; i <= arrayTypeDef.Length; i++) + { + var itemOffset = (ushort)(arrayBitLength - i * arrayTypeDef.Type.Length); + var itemData = ReadWithPadding(bits, itemOffset, arrayTypeDef.Type.Length); + result.Add(($"{arrayTypeDef.Name}_{i}", IoddScalarReader.Convert(arrayTypeDef.Type, itemData))); + } + + return result; + } + + private static IEnumerable<(string key, object value)> ConvertRecordType(ParsableRecord recordType, ReadOnlySpan data) + { + var result = new List<(string key, object value)>(); + var bits = new BitArray(data.ToArray().Reverse().ToArray()); + foreach (ParsableRecordItem? recordItemDef in recordType.Entries.OrderBy(x => x.BitOffset)) + { + var translatedOffset = (ushort)(recordType.Length - recordItemDef.BitOffset); + result.Add((recordItemDef.Name, + IoddScalarReader.Convert(recordItemDef.Type, + ReadWithPadding(bits, recordItemDef.BitOffset, recordItemDef.Type.Length).ToArray().Reverse().ToArray()))); + } + + return result; + } + + private static ReadOnlySpan ReadWithPadding(BitArray bits, ushort offset, ushort length) + { + var result = new byte[length / 8 + (length % 8 != 0 ? 1 : 0)]; + + for (var i = 0; i < length; i++) + { + var bit = bits[offset + i]; + result[i / 8] |= (byte)(bit ? 1 << (i % 8) : 0); + } + + return result; + } +} diff --git a/src/IOLink.NET/Conversion/IoddComplexWriter.cs b/src/IOLink.NET/Conversion/IoddComplexWriter.cs new file mode 100644 index 0000000..fe0d2f1 --- /dev/null +++ b/src/IOLink.NET/Conversion/IoddComplexWriter.cs @@ -0,0 +1,135 @@ +using System.Collections; +using IOLink.NET.IODD.Resolution; + +namespace IOLink.NET.Conversion; + +public static class IoddComplexWriter +{ + public static byte[] Write(ParsableComplexDataTypeDef complexTypeDef, object value) => + complexTypeDef switch + { + ParsableRecord recordType => WriteRecordType(recordType, value), + ParsableArray arrayTypeDef => WriteArrayType(arrayTypeDef, value), + _ => throw new InvalidOperationException( + $"Type {complexTypeDef.GetType().Name} is not supported." + ), + }; + + private static byte[] WriteArrayType(ParsableArray arrayTypeDef, object value) + { + if (value is not IEnumerable enumerable) + { + throw new ArgumentException( + "Value must be an enumerable for array types", + nameof(value) + ); + } + + var items = enumerable.ToList(); + if (items.Count != arrayTypeDef.Length) + { + throw new ArgumentException( + $"Array length mismatch. Expected {arrayTypeDef.Length}, got {items.Count}", + nameof(value) + ); + } + + var totalBitLength = arrayTypeDef.Length * arrayTypeDef.Type.Length; + var bits = new BitArray(totalBitLength); + + for (var i = 0; i < arrayTypeDef.Length; i++) + { + var itemBytes = IoddScalarWriter.Write(arrayTypeDef.Type, items[i]); + var itemBits = new BitArray(itemBytes); + var itemOffset = i * arrayTypeDef.Type.Length; + + for (var j = 0; j < arrayTypeDef.Type.Length && j < itemBits.Length; j++) + { + bits[itemOffset + j] = itemBits[j]; + } + } + + return ConvertBitArrayToBytes(bits); + } + + private static byte[] WriteRecordType(ParsableRecord recordType, object value) + { + if (value is not IEnumerable<(string key, object value)> keyValuePairs) + { + throw new ArgumentException( + "Value must be an enumerable of key-value pairs for record types", + nameof(value) + ); + } + + var pairs = keyValuePairs.ToDictionary(kvp => kvp.key, kvp => kvp.value); + var bits = new BitArray(recordType.Length); + + foreach (var recordItem in recordType.Entries) + { + if (!pairs.TryGetValue(recordItem.Name, out var itemValue)) + { + throw new ArgumentException( + $"Missing value for record item '{recordItem.Name}'", + nameof(value) + ); + } + + // For bit-packed records, handle small bit lengths directly + var itemBits = ConvertValueToBits(recordItem.Type, itemValue); + + for (var i = 0; i < recordItem.Type.Length && i < itemBits.Length; i++) + { + bits[recordItem.BitOffset + i] = itemBits[i]; + } + } + + return ConvertBitArrayToBytes(bits); + } + + private static BitArray ConvertValueToBits(ParsableSimpleDatatypeDef typeDef, object value) + { + // For very small bit lengths, handle the conversion directly + if ( + typeDef.Length <= 8 + && ( + typeDef.Datatype == KindOfSimpleType.UInteger + || typeDef.Datatype == KindOfSimpleType.Integer + ) + ) + { + var numericValue = Convert.ToUInt64(value); + var bits = new BitArray(typeDef.Length); + + for (var i = 0; i < typeDef.Length; i++) + { + bits[i] = (numericValue & (1UL << i)) != 0; + } + + return bits; + } + + // For larger or other types, use the scalar writer + var bytes = IoddScalarWriter.Write(typeDef, value); + + // For multi-field records, we need to account for the reader's field-level reversal + // The reader will reverse the bytes of each field individually, so we pre-reverse them + var reversedBytes = bytes.Reverse().ToArray(); + return new BitArray(reversedBytes); + } + + private static byte[] ConvertBitArrayToBytes(BitArray bits) + { + var bytes = new byte[(bits.Length + 7) / 8]; + + // Match the reader's bit packing logic + for (var i = 0; i < bits.Length; i++) + { + var bit = bits[i]; + bytes[i / 8] |= (byte)(bit ? 1 << (i % 8) : 0); + } + + // Reverse to compensate for the reader's reversal + return bytes.Reverse().ToArray(); + } +} diff --git a/src/IOLink.NET/Conversion/IoddConverter.cs b/src/IOLink.NET/Conversion/IoddConverter.cs new file mode 100644 index 0000000..e7dc522 --- /dev/null +++ b/src/IOLink.NET/Conversion/IoddConverter.cs @@ -0,0 +1,25 @@ +using IOLink.NET.IODD.Resolution; + +namespace IOLink.NET.Conversion; + +public class IoddConverter : IIoddDataConverter +{ + public object Convert(ParsableDatatype datatypeDef, ReadOnlySpan data) => + datatypeDef switch + { + ParsableComplexDataTypeDef complexType => IoddComplexConverter.Convert( + complexType, + data + ), + ParsableSimpleDatatypeDef simpleType => IoddScalarReader.Convert(simpleType, data), + _ => throw new NotImplementedException(), + }; + + public byte[] ConvertToBytes(object value, ParsableDatatype datatypeDef) => + datatypeDef switch + { + ParsableComplexDataTypeDef complexType => IoddComplexWriter.Write(complexType, value), + ParsableSimpleDatatypeDef simpleType => IoddScalarWriter.Write(simpleType, value), + _ => throw new NotImplementedException(), + }; +} diff --git a/src/Conversion/IoddScalarReader.cs b/src/IOLink.NET/Conversion/IoddScalarReader.cs similarity index 97% rename from src/Conversion/IoddScalarReader.cs rename to src/IOLink.NET/Conversion/IoddScalarReader.cs index 2673473..4a25806 100644 --- a/src/Conversion/IoddScalarReader.cs +++ b/src/IOLink.NET/Conversion/IoddScalarReader.cs @@ -3,10 +3,10 @@ using System.Collections; using System.Text; -using IOLinkNET.IODD.Resolution; -using IOLinkNET.IODD.Structure.Datatypes; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Structure.Datatypes; -namespace IOLinkNET.Conversion; +namespace IOLink.NET.Conversion; public class IoddScalarReader { @@ -124,4 +124,4 @@ private static string ConvertString(ParsableStringDef stringDef, ReadOnlySpan Encoding.UTF8.GetString(data), _ => throw new NotImplementedException($"Encoding {stringDef.Encoding} is not supported.") }; -} \ No newline at end of file +} diff --git a/src/IOLink.NET/Conversion/IoddScalarWriter.cs b/src/IOLink.NET/Conversion/IoddScalarWriter.cs new file mode 100644 index 0000000..54c24ba --- /dev/null +++ b/src/IOLink.NET/Conversion/IoddScalarWriter.cs @@ -0,0 +1,93 @@ +using System.Buffers.Binary; +using System.Numerics; +using System.Text; +using IOLink.NET.Conversion.Extensions; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.Conversion; + +public class IoddScalarWriter +{ + public static byte[] Write(ParsableSimpleDatatypeDef typeDef, object value) => + typeDef switch + { + { Datatype: KindOfSimpleType.Boolean } => BitConverter.GetBytes((bool)value), + { Datatype: KindOfSimpleType.Float } => WriteFloat(value), + { Datatype: KindOfSimpleType.UInteger } => WriteUInt(value, typeDef.Length), + { Datatype: KindOfSimpleType.Integer } => WriteInt(value, typeDef.Length), + { Datatype: KindOfSimpleType.OctetString } => Convert.FromHexString((string)value), + ParsableStringDef s => WriteString(s, (string)value), + _ => throw new NotImplementedException(), + }; + + private static byte[] WriteUInt(object value, ushort bitLength) => + bitLength switch + { + <= 2 => throw new ArgumentOutOfRangeException( + nameof(bitLength), + bitLength, + "Invalid bitLength for UInt -> byte[] write" + ), + <= 16 => WriteInt(value, bitLength, Convert.ToUInt16), + <= 32 => WriteInt(value, bitLength, Convert.ToUInt32), + <= 64 => WriteInt(value, bitLength, Convert.ToUInt64), + _ => throw new ArgumentOutOfRangeException( + nameof(bitLength), + bitLength, + "Invalid bitLength for UInt -> byte[] write" + ), + }; + + private static byte[] WriteInt(object value, ushort bitLength) => + bitLength switch + { + <= 2 => throw new ArgumentOutOfRangeException( + nameof(bitLength), + bitLength, + "Invalid bitLength for Int -> byte[] write" + ), + <= 16 => WriteInt(value, bitLength, Convert.ToInt16), + <= 32 => WriteInt(value, bitLength, Convert.ToInt32), + <= 64 => WriteInt(value, bitLength, Convert.ToInt64), + _ => throw new ArgumentOutOfRangeException( + nameof(bitLength), + bitLength, + "Invalid bitLength for Int -> byte[] write" + ), + }; + + private static byte[] WriteString(ParsableStringDef stringDef, string value) => + stringDef.Encoding switch + { + StringTEncoding.ASCII => Encoding.ASCII.GetBytes(value), + StringTEncoding.UTF8 => Encoding.UTF8.GetBytes(value), + _ => throw new NotImplementedException( + $"Encoding {stringDef.Encoding} is not supported." + ), + }; + + private static byte[] WriteFloat(object value) + { + var bytes = new byte[4]; + BinaryPrimitives.WriteSingleBigEndian(bytes, (float)value); + return bytes; + } + + private static byte[] WriteInt( + object value, + ushort bitLength, + Func conversionFunc + ) + where R : IBinaryInteger + { + R val = conversionFunc(value); + byte[] bytes = new byte[val.GetByteCount()]; + val.WriteBigEndian(bytes); + + byte[] limitedBytes = bytes.TruncateToBitLength(bitLength); + return R.IsNegative(val) + ? limitedBytes.PinNegativeIntToRequiredBitLength(bitLength) + : limitedBytes; + } +} diff --git a/src/IODD.Parser/IOLinkNET.IODD.Parser.csproj b/src/IOLink.NET/IOLink.NET.csproj similarity index 60% rename from src/IODD.Parser/IOLinkNET.IODD.Parser.csproj rename to src/IOLink.NET/IOLink.NET.csproj index 60a6aed..83ae481 100644 --- a/src/IODD.Parser/IOLinkNET.IODD.Parser.csproj +++ b/src/IOLink.NET/IOLink.NET.csproj @@ -1,10 +1,10 @@ - + - - + + - IOLinkNET.IODD.Parser + IOLink.NET 0.1.0.0 0.1.0.0 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 @@ -13,13 +13,13 @@ LICENSE README.md - IOLinkNET is a library allows you to rapidly integrate and interact with devices that are using the IO-Link technology. + IOLink.NET - Main library for interacting with devices using IO-Link technology including data conversion and integration functionality. https://github.com/domdeger/IOLink.NET/ https://github.com/domdeger/IOLink.NET/ Github - - + + - \ No newline at end of file + diff --git a/src/Integration/Extensions/PortReaderBuilderExtensions.cs b/src/IOLink.NET/Integration/Extensions/PortReaderBuilderExtensions.cs similarity index 90% rename from src/Integration/Extensions/PortReaderBuilderExtensions.cs rename to src/IOLink.NET/Integration/Extensions/PortReaderBuilderExtensions.cs index 04b135b..2891e90 100644 --- a/src/Integration/Extensions/PortReaderBuilderExtensions.cs +++ b/src/IOLink.NET/Integration/Extensions/PortReaderBuilderExtensions.cs @@ -1,8 +1,8 @@ -using IOLinkNET.Conversion; -using IOLinkNET.IODD.Provider; -using IOLinkNET.IODD.Resolution.Common; +using IOLink.NET.Conversion; +using IOLink.NET.IODD.Provider; +using IOLink.NET.IODD.Resolution.Common; -namespace IOLinkNET.Integration; +namespace IOLink.NET.Integration; public static class PortReaderBuilderExtensions { @@ -51,4 +51,4 @@ public static PortReaderBuilder WithDefaultIoddConverter(this PortReaderBuilder return builder; } -} \ No newline at end of file +} diff --git a/src/Integration/IODDPortReader.cs b/src/IOLink.NET/Integration/IODDPortReader.cs similarity index 61% rename from src/Integration/IODDPortReader.cs rename to src/IOLink.NET/Integration/IODDPortReader.cs index 0973ab4..059aee3 100644 --- a/src/Integration/IODDPortReader.cs +++ b/src/IOLink.NET/Integration/IODDPortReader.cs @@ -1,11 +1,11 @@ -using IOLinkNET.Conversion; -using IOLinkNET.Device.Contract; -using IOLinkNET.IODD.Provider; -using IOLinkNET.IODD.Resolution; -using IOLinkNET.IODD.Resolution.Contracts; -using IOLinkNET.IODD.Structure; +using IOLink.NET.Conversion; +using IOLink.NET.Core.Contracts; +using IOLink.NET.IODD.Provider; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Resolution.Contracts; +using IOLink.NET.IODD.Structure; -namespace IOLinkNET.Integration; +namespace IOLink.NET.Integration; public class IODDPortReader { @@ -14,10 +14,13 @@ public class IODDPortReader private readonly IIoddDataConverter _ioddDataConverter; private readonly ITypeResolverFactory _typeResolverFactory; private PortReaderInitilizationResult? _initilizationState; - private PortReaderInitilizationResult InitilizationState => _initilizationState ?? throw new InvalidOperationException("PortReader is not initialized"); - public IODDPortReader(IMasterConnection connection, IDeviceDefinitionProvider deviceDefinitionProvider, - IIoddDataConverter ioddDataConverter, ITypeResolverFactory typeResolverFactory) + public IODDPortReader( + IMasterConnection connection, + IDeviceDefinitionProvider deviceDefinitionProvider, + IIoddDataConverter ioddDataConverter, + ITypeResolverFactory typeResolverFactory + ) { _connection = connection; _deviceDefinitionProvider = deviceDefinitionProvider; @@ -25,12 +28,18 @@ public IODDPortReader(IMasterConnection connection, IDeviceDefinitionProvider de _typeResolverFactory = typeResolverFactory; } - public IODevice Device { - get + private PortReaderInitilizationResult InitilizationState => + _initilizationState ?? throw new InvalidOperationException("PortReader is not initialized"); + + public IODevice Device + { + get { - _ = _initilizationState ?? throw new InvalidOperationException("PortReader is not initialized"); - return InitilizationState.DeviceDefinition; - } + _ = + _initilizationState + ?? throw new InvalidOperationException("PortReader is not initialized"); + return InitilizationState.DeviceDefinition; + } } public async Task InitializeForPortAsync(byte port) @@ -43,22 +52,39 @@ public async Task InitializeForPortAsync(byte port) if (portInfo.DeviceInformation is null) { - throw new InvalidOperationException($"Device information is not available for requested port {port}"); + throw new InvalidOperationException( + $"Device information is not available for requested port {port}" + ); } - var deviceDefinition = await _deviceDefinitionProvider.GetDeviceDefinitionAsync(portInfo.DeviceInformation.VendorId, portInfo.DeviceInformation.DeviceId, portInfo.DeviceInformation.ProductId); + var deviceDefinition = await _deviceDefinitionProvider.GetDeviceDefinitionAsync( + portInfo.DeviceInformation.VendorId, + portInfo.DeviceInformation.DeviceId, + portInfo.DeviceInformation.ProductId + ); var pdDataResolver = _typeResolverFactory.CreateProcessDataTypeResolver(deviceDefinition); var paramDataResolver = _typeResolverFactory.CreateParameterTypeResolver(deviceDefinition); var (pdInType, pdOutType) = await GetProcessDataTypesAsync(port, pdDataResolver); - _initilizationState = new PortReaderInitilizationResult(pdInType, pdOutType, port, pdDataResolver, paramDataResolver, deviceDefinition); + _initilizationState = new PortReaderInitilizationResult( + pdInType, + pdOutType, + port, + pdDataResolver, + paramDataResolver, + deviceDefinition + ); } public virtual async Task ReadConvertedParameterAsync(ushort index, byte subindex) { var paramTypeDef = InitilizationState.ParameterTypeResolver.GetParameter(index, subindex); - var value = await _connection.ReadIndexAsync(InitilizationState.Port, index, paramTypeDef.SubindexAccessSupported ? subindex : (byte)0); + var value = await _connection.ReadIndexAsync( + InitilizationState.Port, + index, + paramTypeDef.SubindexAccessSupported ? subindex : (byte)0 + ); var convertedValue = _ioddDataConverter.Convert(paramTypeDef, value.Span); @@ -91,14 +117,21 @@ public async Task ReadConvertedProcessDataOutAsync() return convertedValue; } - private async Task<(ParsableDatatype? PdIn, ParsableDatatype? PdOut)> GetProcessDataTypesAsync(byte port, IProcessDataTypeResolver processDataTypeResolver) + private async Task<(ParsableDatatype? PdIn, ParsableDatatype? PdOut)> GetProcessDataTypesAsync( + byte port, + IProcessDataTypeResolver processDataTypeResolver + ) { ParsableDatatype? pdInType; ParsableDatatype? pdOutType; if (processDataTypeResolver.HasCondition()) { var condition = processDataTypeResolver.ResolveCondition(); - var conditionValue = await _connection.ReadIndexAsync(port, condition.VariableDef.Index, condition.ConditionDef.Subindex ?? 0); + var conditionValue = await _connection.ReadIndexAsync( + port, + condition.VariableDef.Index, + condition.ConditionDef.Subindex ?? 0 + ); pdInType = processDataTypeResolver.ResolveProcessDataIn(conditionValue.Span[0]); pdOutType = processDataTypeResolver.ResolveProcessDataOut(conditionValue.Span[0]); } @@ -110,5 +143,13 @@ public async Task ReadConvertedProcessDataOutAsync() return (pdInType, pdOutType); } - public record PortReaderInitilizationResult(ParsableDatatype? PdIn, ParsableDatatype? PdOut, byte Port, IProcessDataTypeResolver ProcessDataTypeResolver, IParameterTypeResolver ParameterTypeResolver, IODevice DeviceDefinition); + + public record PortReaderInitilizationResult( + ParsableDatatype? PdIn, + ParsableDatatype? PdOut, + byte Port, + IProcessDataTypeResolver ProcessDataTypeResolver, + IParameterTypeResolver ParameterTypeResolver, + IODevice DeviceDefinition + ); } diff --git a/src/Integration/IOLinkNET.Integration.csproj b/src/IOLink.NET/Integration/IOLinkNET.Integration.csproj similarity index 100% rename from src/Integration/IOLinkNET.Integration.csproj rename to src/IOLink.NET/Integration/IOLinkNET.Integration.csproj diff --git a/src/Integration/PortReaderBuilder.cs b/src/IOLink.NET/Integration/PortReaderBuilder.cs similarity index 85% rename from src/Integration/PortReaderBuilder.cs rename to src/IOLink.NET/Integration/PortReaderBuilder.cs index b549ebc..264c0ca 100644 --- a/src/Integration/PortReaderBuilder.cs +++ b/src/IOLink.NET/Integration/PortReaderBuilder.cs @@ -1,9 +1,9 @@ -using IOLinkNET.Conversion; -using IOLinkNET.Device.Contract; -using IOLinkNET.IODD.Provider; -using IOLinkNET.IODD.Resolution.Contracts; +using IOLink.NET.Conversion; +using IOLink.NET.Core.Contracts; +using IOLink.NET.IODD.Provider; +using IOLink.NET.IODD.Resolution.Contracts; -namespace IOLinkNET.Integration; +namespace IOLink.NET.Integration; public class PortReaderBuilder { @@ -33,7 +33,9 @@ public PortReaderBuilder WithMasterConnection(IMasterConnection masterConnection return this; } - public PortReaderBuilder WithDeviceDefinitionProvider(IDeviceDefinitionProvider deviceDefinitionProvider) + public PortReaderBuilder WithDeviceDefinitionProvider( + IDeviceDefinitionProvider deviceDefinitionProvider + ) { if (deviceDefinitionProvider is null) { @@ -103,6 +105,11 @@ public IODDPortReader Build() throw new InvalidOperationException("TypeResolverFactory is not set"); } - return new IODDPortReader(_masterConnection, _deviceDefinitionProvider, _ioddDataConverter, _typeResolverFactory); + return new IODDPortReader( + _masterConnection, + _deviceDefinitionProvider, + _ioddDataConverter, + _typeResolverFactory + ); } -} \ No newline at end of file +} diff --git a/src/Tests/Conversion.Tests/Conversion.Tests.csproj b/src/Tests/Conversion.Tests/Conversion.Tests.csproj deleted file mode 100644 index ba922c0..0000000 --- a/src/Tests/Conversion.Tests/Conversion.Tests.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - false - 0.1.0.0 - 0.1.0.0 - 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 - 0.1.0 - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - TestData\%(RecursiveDir)/%(FileName)%(Extension) - Always - - - \ No newline at end of file diff --git a/src/Tests/Conversion.Tests/IoddConverterIntegrationTests.cs b/src/Tests/Conversion.Tests/IoddConverterIntegrationTests.cs deleted file mode 100644 index 291e945..0000000 --- a/src/Tests/Conversion.Tests/IoddConverterIntegrationTests.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Xml.Linq; - -using FluentAssertions; - -using IOLinkNET.Conversion; -using IOLinkNET.IODD; -using IOLinkNET.IODD.Resolution; - -namespace Conversion.Tests; - -public class IoddConverterIntegrationTests -{ - [Fact] - public void ShouldConvertProcessDataForRealDevice393780() - { - var data = Convert.FromBase64String("gAEDAAAAAAAAgAA="); - IODDParser parser = new(); - var device = parser.Parse(XElement.Load("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml")); - var converter = new IoddConverter(); - - var pdResolver = new ProcessDataTypeResolver(device); - var convertibleType = pdResolver.ResolveProcessDataIn()!; - - var result = (converter.Convert(convertibleType, data) as List<(string, object)>)!.ToDictionary(x => x.Item1, y => y.Item2); - - result.Should().ContainKey("TI_PDObject_75").WhoseValue.Should().BeOfType().And.Be(false); - result.Should().ContainKey("TI_PDObject_55").WhoseValue.Should().BeOfType().And.Be(false); - result.Should().ContainKey("TI_PDObject_78").WhoseValue.Should().BeOfType().And.Be(false); - result.Should().ContainKey("TI_PDObject_33").WhoseValue.Should().BeOfType().And.Be(false); - result.Should().ContainKey("TI_PDObject_47").WhoseValue.Should().BeOfType().And.Be(false); - result.Should().ContainKey("TI_PDI_FirstBitHeader").WhoseValue.Should().Be(128); - result.Should().ContainKey("TI_PDI_FirstByte").WhoseValue.Should().Be(1); - result.Should().ContainKey("TI_PDI_SecondByte").WhoseValue.Should().Be(3); - result.Should().ContainKey("TI_PDI_ThirdByte").WhoseValue.Should().Be(0); - result.Should().ContainKey("TI_PDI_FourthByte").WhoseValue.Should().Be(0); - result.Should().ContainKey("TI_PDI_FifthByte").WhoseValue.Should().Be(0); - result.Should().ContainKey("TI_PDI_SixthByte").WhoseValue.Should().Be(0); - result.Should().ContainKey("TI_PDI_SeventhByte").WhoseValue.Should().Be(0); - result.Should().ContainKey("TI_PDI_EighthByte").WhoseValue.Should().Be(0); - result.Should().ContainKey("TI_PDI_SecondBitHeader").WhoseValue.Should().Be(128); - } - - [Fact] - public void ShouldConvertProcessDataForRealDevice459267() - { - var data = Convert.FromBase64String("cHA="); - IODDParser parser = new(); - var device = parser.Parse(XElement.Load("TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml")); - var pdResolver = new ProcessDataTypeResolver(device); - var converter = new IoddConverter(); - - var convertibleType = pdResolver.ResolveProcessDataIn()!; - var result = (converter.Convert(convertibleType, data) as List<(string, object)>)!.ToDictionary(x => x.Item1, y => y.Item2); - - result.Should().ContainKey("TN_PDI_BDC1").WhoseValue.Should().BeOfType().And.Be(false); - result.Should().ContainKey("TN_PDI_PDV").WhoseValue.Should().Be(1799); - } -} \ No newline at end of file diff --git a/src/Tests/Conversion.Tests/IoddConverterTests.cs b/src/Tests/Conversion.Tests/IoddConverterTests.cs deleted file mode 100644 index 47d1409..0000000 --- a/src/Tests/Conversion.Tests/IoddConverterTests.cs +++ /dev/null @@ -1,110 +0,0 @@ -using FluentAssertions; - -using IOLinkNET.Conversion; -using IOLinkNET.IODD.Resolution; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace Conversion.Tests; - -public class IoddConverterTests -{ - [Fact] - public void CanConvertWithPaddedBitOffset() - { - var converter = new IoddConverter(); - var recordItem = new ParsableRecordItem(new ParsableSimpleDatatypeDef("uint_1", KindOfSimpleType.UInteger, 4), "Test", 0, 1); - var recordItem1 = new ParsableRecordItem(new ParsableSimpleDatatypeDef("uint_2", KindOfSimpleType.UInteger, 4), "Test", 4, 1); - var testRecord = new ParsableRecord("Test", 8, true, new[] { recordItem, recordItem1 }); - - object result = converter.Convert(testRecord, [/*1111 1111*/ 0xff]); - _ = result.Should().BeAssignableTo>(); - } - - [Fact] - public void CanConvertRecordT() - { - byte[] data = Convert.FromBase64String("AB0AHAAdABMALgATAC4="); - byte[] binaryData = new byte[] - { 0b00000000, 0b00011101, 0b00000000, 0b00011100, 0b00000000, 0b00011101, 0b00000000, - 0b00010011, 0b00000000, 0b00101110, 0b00000000, 0b00010011, 0b00000000, 0b00101110 }; - - _ = data.Should().BeEquivalentTo(binaryData); - var converter = new IoddConverter(); - - var testRecord = new ParsableRecord("DemoRecord", 112, true, new[] { - new ParsableRecordItem(new ParsableSimpleDatatypeDef("TI_VAR_Device_Temp_Device_Temp", KindOfSimpleType.Integer, 16), "TI_VAR_Device_Temp_Device_Temp", 96, 1), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Startup", KindOfSimpleType.Integer, 16), "TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Startup", 80, 2), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Startup", KindOfSimpleType.Integer, 16), "TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Startup", 64, 3), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("TI_VAR_Device_Temp_Minimum_Device_Temp_Lifetime", KindOfSimpleType.Integer, 16), "TI_VAR_Device_Temp_Minimum_Device_Temp_Lifetime", 48, 4), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("TI_VAR_Device_Temp_Maximum_Device_Temp_Lifetime", KindOfSimpleType.Integer, 16), "TI_VAR_Device_Temp_Maximum_Device_Temp_Lifetime", 32, 5), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Reset", KindOfSimpleType.Integer, 16), "TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Reset", 16, 6), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Reset", KindOfSimpleType.Integer, 16), "TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Reset", 0, 7), - }); - - object result = converter.Convert(testRecord, data); - - _ = result.Should().BeAssignableTo>(); - } - - [Fact] - public void CanConvertRecordFromIODDSystemDescription() - { - /* - This test case verifies that the recordt conversion is working correctly for the record definition from the - IO-Link system description: https://io-link.com/share/Downloads/Package-2020/IOL-Interface-Spec_10002_V113_Jun19.pdf - page 280. - */ - var converter = new IoddConverter(); - - var recordDef = new ParsableRecord("IOLinkDemoRecord", 40, true, new[] { - new ParsableRecordItem(new ParsableSimpleDatatypeDef("NewBit", KindOfSimpleType.Boolean, 1), "NewBit", 32, 1), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("DR4", KindOfSimpleType.Boolean, 1), "DR4", 33, 2), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("CR3", KindOfSimpleType.Boolean, 1), "CR3", 34, 3), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("CR2", KindOfSimpleType.Boolean, 1), "CR2", 35, 4), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("Control", KindOfSimpleType.Boolean, 1), "Control", 38, 5), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("Setpoint", KindOfSimpleType.OctetString, 16), "Setpoint", 16, 6), - new ParsableRecordItem(new ParsableStringDef("Unit", 8, StringTEncoding.ASCII), "Unit", 8, 7), - new ParsableRecordItem(new ParsableSimpleDatatypeDef("Enable", KindOfSimpleType.OctetString, 8), "Enable", 0, 8), - }); - var data = new byte[] { 0b01001001, 0xF8, 0x23, 0x41, 0xC3 }; - var result = converter.Convert(recordDef, data); - - result.Should().NotBeNull(); - result.Should().BeAssignableTo>(); - var record = result as IEnumerable<(string, object)>; - record.Should().HaveCount(8); - record.Should().Contain(x => x.Item1 == "NewBit" && (bool)x.Item2 == true); - record.Should().Contain(x => x.Item1 == "DR4" && (bool)x.Item2 == false); - record.Should().Contain(x => x.Item1 == "CR3" && (bool)x.Item2 == false); - record.Should().Contain(x => x.Item1 == "CR2" && (bool)x.Item2 == true); - record.Should().Contain(x => x.Item1 == "Control" && (bool)x.Item2 == true); - record.Should().Contain(x => x.Item1 == "Setpoint" && (string)x.Item2 == "F823"); - record.Should().Contain(x => x.Item1 == "Unit" && (string)x.Item2 == "A"); - record.Should().Contain(x => x.Item1 == "Enable" && (string)x.Item2 == "C3"); - } - - [Fact] - public void CanConvertArray() - { - /* - This test case verifies that the array conversion is working correctly for the array definition from the - IO-Link system description: https://io-link.com/share/Downloads/Package-2020/IOL-Interface-Spec_10002_V113_Jun19.pdf - page 278. - */ - var arrayDefinition = new ParsableArray("V_SomeArray", new ParsableSimpleDatatypeDef("uint_1", KindOfSimpleType.UInteger, 3), true, 5); - var converter = new IoddConverter(); - - byte[] data = [0b0101101, 0b00111101]; - object result = converter.Convert(arrayDefinition, data); - - _ = result.Should().BeAssignableTo>(); - var array = result as IEnumerable<(string, object)>; - - _ = array.Should().HaveCount(5); - _ = array.Should().Contain(x => x.Item1 == "V_SomeArray_1" && (byte)x.Item2 == 2); - _ = array.Should().Contain(x => x.Item1 == "V_SomeArray_2" && (byte)x.Item2 == 6); - _ = array.Should().Contain(x => x.Item1 == "V_SomeArray_3" && (byte)x.Item2 == 4); - _ = array.Should().Contain(x => x.Item1 == "V_SomeArray_4" && (byte)x.Item2 == 7); - _ = array.Should().Contain(x => x.Item1 == "V_SomeArray_5" && (byte)x.Item2 == 5); - } -} \ No newline at end of file diff --git a/src/Tests/Conversion.Tests/Usings.cs b/src/Tests/Conversion.Tests/Usings.cs deleted file mode 100644 index 8c927eb..0000000 --- a/src/Tests/Conversion.Tests/Usings.cs +++ /dev/null @@ -1 +0,0 @@ -global using Xunit; \ No newline at end of file diff --git a/src/Tests/IODD.Parser.Tests/IODD.Parser.Tests.csproj b/src/Tests/IODD.Parser.Tests/IODD.Parser.Tests.csproj deleted file mode 100644 index 2cbcbdf..0000000 --- a/src/Tests/IODD.Parser.Tests/IODD.Parser.Tests.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - false - 0.1.0.0 - 0.1.0.0 - 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 - 0.1.0 - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - TestData\%(RecursiveDir)/%(FileName)%(Extension) - Always - - - \ No newline at end of file diff --git a/src/Tests/IODD.Parser.Tests/Usings.cs b/src/Tests/IODD.Parser.Tests/Usings.cs deleted file mode 100644 index bd45f39..0000000 --- a/src/Tests/IODD.Parser.Tests/Usings.cs +++ /dev/null @@ -1,2 +0,0 @@ -global using Xunit; -global using FluentAssertions; \ No newline at end of file diff --git a/src/Tests/IODD.Provider.Tests/DeviceDefinitionProviderTests.cs b/src/Tests/IODD.Provider.Tests/DeviceDefinitionProviderTests.cs deleted file mode 100644 index 411b1af..0000000 --- a/src/Tests/IODD.Provider.Tests/DeviceDefinitionProviderTests.cs +++ /dev/null @@ -1,29 +0,0 @@ -using IOLinkNET.IODD.Provider; - -namespace IODD.Provider.Tests; - -public class DeviceDefinitionProviderTests -{ - private readonly Uri _baseUrl = new("https://ioddfinder.io-link.com/"); - - [Fact] - public async Task DoesLoadDeviceDefinitionAsync() - { - var client = new IODDFinderPublicClient(_baseUrl); - var provider = new DeviceDefinitionProvider(client); - var definition = await provider.GetDeviceDefinitionAsync(888, 200710, "50142212"); - - definition.ProfileBody.DeviceIdentity.VendorId.Should().Be(888); - } - - [Fact] - public async Task DoesLoadDeviceDefinitionForIfmDeviceAsync() - { - var client = new IODDFinderPublicClient(_baseUrl); - var provider = new DeviceDefinitionProvider(client); - var definition = await provider.GetDeviceDefinitionAsync(310, 1367, "VVB001 Status B"); - - definition.ProfileBody.DeviceIdentity.VendorId.Should().Be(310); - definition.ProfileBody.DeviceIdentity.DeviceId.Should().Be(1367); - } -} diff --git a/src/Tests/IODD.Provider.Tests/IODD.Provider.Tests.csproj b/src/Tests/IODD.Provider.Tests/IODD.Provider.Tests.csproj deleted file mode 100644 index 5d25bbe..0000000 --- a/src/Tests/IODD.Provider.Tests/IODD.Provider.Tests.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - false - 0.1.0.0 - 0.1.0.0 - 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 - 0.1.0 - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - \ No newline at end of file diff --git a/src/Tests/IODD.Provider.Tests/Usings.cs b/src/Tests/IODD.Provider.Tests/Usings.cs deleted file mode 100644 index 7fef4b0..0000000 --- a/src/Tests/IODD.Provider.Tests/Usings.cs +++ /dev/null @@ -1,2 +0,0 @@ -global using Xunit; -global using FluentAssertions; \ No newline at end of file diff --git a/src/Tests/IODD.Resolution.Tests/IODD.Resolution.Tests.csproj b/src/Tests/IODD.Resolution.Tests/IODD.Resolution.Tests.csproj deleted file mode 100644 index ca06e56..0000000 --- a/src/Tests/IODD.Resolution.Tests/IODD.Resolution.Tests.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - false - 0.1.0.0 - 0.1.0.0 - 0.1.0+15.Branch.main.Sha.d6058282db27fe28bc9c33e5aed16016287219d5 - 0.1.0 - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - TestData\%(RecursiveDir)/%(FileName)%(Extension) - Always - - - \ No newline at end of file diff --git a/src/Tests/IODD.Resolution.Tests/ParameterResolverTests.cs b/src/Tests/IODD.Resolution.Tests/ParameterResolverTests.cs deleted file mode 100644 index ebc1db3..0000000 --- a/src/Tests/IODD.Resolution.Tests/ParameterResolverTests.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD; -using IOLinkNET.IODD.Resolution; -using IOLinkNET.IODD.Structure; - -namespace IODD.Resolution.Tests; - -public class ParameterResolverTests -{ - readonly IODevice _iodd; - public ParameterResolverTests() - { - IODDParser parser = new(); - _iodd = parser.Parse(XElement.Load("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml")) - ?? throw new NullReferenceException(); - } - - [Fact] - public void CanResolveRecordType() - { - var parameterResolver = new ParameterTypeResolver(_iodd); - - var param = parameterResolver.GetParameter(210); - param.Should().NotBeNull(); - param.Should().BeOfType(); - var recordParam = param as ParsableRecord; - - recordParam!.Name.Should().Be("V_Inversion_Record"); - recordParam!.Entries?.Should().NotBeEmpty(); - recordParam!.Entries.Should().HaveElementAt(0, new(new ParsableSimpleDatatypeDef("TI_VAR_Inversion_P0P4", KindOfSimpleType.Boolean, 1), "TI_VAR_Inversion_P0P4", 0, 1)); - recordParam!.Entries.Should().EndWith(new ParsableRecordItem(new ParsableSimpleDatatypeDef("TI_VAR_Inversion_P3P2", KindOfSimpleType.Boolean, 1), "TI_VAR_Inversion_P3P2", 7, 8)); - } - - [Fact] - public void CanResolveScalarViaSubindex() - { - var parameterResolver = new ParameterTypeResolver(_iodd); - - var param = parameterResolver.GetParameter(210, 1); - param.Should().NotBeNull().And.BeOfType().And.NotBeNull(); - - var simpleDatatype = param as ParsableSimpleDatatypeDef; - simpleDatatype!.Datatype.Should().Be(KindOfSimpleType.Boolean); - simpleDatatype!.Name.Should().Be("V_Inversion_Record_1"); - } - - [Fact] - public void CanResolveScalar() - { - var parameterResolver = new ParameterTypeResolver(_iodd); - - var param = parameterResolver.GetParameter(112); - param.Should().NotBeNull().And.BeOfType().And.NotBeNull(); - - var simpleDatatype = param as ParsableSimpleDatatypeDef; - simpleDatatype!.Datatype.Should().Be(KindOfSimpleType.UInteger); - simpleDatatype!.Name.Should().Be("V_Diag_Level_Config"); - } - - [Fact] - public void CanResolveArray() - { - var parameterResolver = new ParameterTypeResolver(_iodd); - - var param = parameterResolver.GetParameter(113); - param.Should().NotBeNull().And.BeOfType().And.NotBeNull(); - - var arrayParam = param as ParsableArray ?? throw new InvalidOperationException("Did not receive an array."); - arrayParam.Name.Should().Be("V_EventCodeSupp"); - arrayParam.Length.Should().Be(5); - arrayParam.Type.Should().BeOfType().And.NotBeNull(); - arrayParam.Type.Datatype.Should().Be(KindOfSimpleType.UInteger); - arrayParam!.Type.Should().BeOfType().And.NotBeNull(); - - } -} \ No newline at end of file diff --git a/src/Tests/IODD.Resolution.Tests/Usings.cs b/src/Tests/IODD.Resolution.Tests/Usings.cs deleted file mode 100644 index bd45f39..0000000 --- a/src/Tests/IODD.Resolution.Tests/Usings.cs +++ /dev/null @@ -1,2 +0,0 @@ -global using Xunit; -global using FluentAssertions; \ No newline at end of file diff --git a/src/Tests/IOLink.NET.Core.Tests/Contracts/InterfaceContractTests.cs b/src/Tests/IOLink.NET.Core.Tests/Contracts/InterfaceContractTests.cs new file mode 100644 index 0000000..e14ba75 --- /dev/null +++ b/src/Tests/IOLink.NET.Core.Tests/Contracts/InterfaceContractTests.cs @@ -0,0 +1,207 @@ +namespace IOLink.NET.Core.Tests.Contracts; + +public class InterfaceContractTests +{ + [Fact] + public void IDeviceInformation_HasCorrectProperties() + { + // Arrange + var interfaceType = typeof(IDeviceInformation); + + // Act & Assert + interfaceType.GetProperty(nameof(IDeviceInformation.VendorId)).ShouldNotBeNull(); + interfaceType.GetProperty(nameof(IDeviceInformation.DeviceId)).ShouldNotBeNull(); + interfaceType.GetProperty(nameof(IDeviceInformation.ProductId)).ShouldNotBeNull(); + + // Verify property types + interfaceType + .GetProperty(nameof(IDeviceInformation.VendorId))! + .PropertyType.ShouldBe(typeof(ushort)); + interfaceType + .GetProperty(nameof(IDeviceInformation.DeviceId))! + .PropertyType.ShouldBe(typeof(uint)); + interfaceType + .GetProperty(nameof(IDeviceInformation.ProductId))! + .PropertyType.ShouldBe(typeof(string)); + } + + [Fact] + public void IPortInformation_HasCorrectProperties() + { + // Arrange + var interfaceType = typeof(IPortInformation); + + // Act & Assert + interfaceType.GetProperty(nameof(IPortInformation.Status)).ShouldNotBeNull(); + interfaceType.GetProperty(nameof(IPortInformation.PortNumber)).ShouldNotBeNull(); + interfaceType.GetProperty(nameof(IPortInformation.DeviceInformation)).ShouldNotBeNull(); + + // Verify property types + interfaceType + .GetProperty(nameof(IPortInformation.Status))! + .PropertyType.ShouldBe(typeof(PortStatus)); + interfaceType + .GetProperty(nameof(IPortInformation.PortNumber))! + .PropertyType.ShouldBe(typeof(byte)); + interfaceType + .GetProperty(nameof(IPortInformation.DeviceInformation))! + .PropertyType.ShouldBe(typeof(IDeviceInformation)); + } + + [Fact] + public void IMasterConnection_HasCorrectMethods() + { + // Arrange + var interfaceType = typeof(IMasterConnection); + + // Act & Assert + var methods = interfaceType.GetMethods(); + + // Verify all expected methods exist + methods.Any(m => m.Name == nameof(IMasterConnection.GetPortCountAsync)).ShouldBeTrue(); + methods + .Any(m => m.Name == nameof(IMasterConnection.GetPortInformationAsync)) + .ShouldBeTrue(); + methods + .Any(m => m.Name == nameof(IMasterConnection.GetPortInformationsAsync)) + .ShouldBeTrue(); + methods.Any(m => m.Name == nameof(IMasterConnection.ReadIndexAsync)).ShouldBeTrue(); + methods.Any(m => m.Name == nameof(IMasterConnection.ReadProcessDataInAsync)).ShouldBeTrue(); + methods + .Any(m => m.Name == nameof(IMasterConnection.ReadProcessDataOutAsync)) + .ShouldBeTrue(); + } + + [Fact] + public void IMasterConnection_GetPortCountAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IMasterConnection); + var method = interfaceType.GetMethod(nameof(IMasterConnection.GetPortCountAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(1); + parameters[0].ParameterType.ShouldBe(typeof(CancellationToken)); + parameters[0].HasDefaultValue.ShouldBeTrue(); + } + + [Fact] + public void IMasterConnection_GetPortInformationAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IMasterConnection); + var method = interfaceType.GetMethod(nameof(IMasterConnection.GetPortInformationAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(2); + parameters[0].ParameterType.ShouldBe(typeof(byte)); + parameters[0].Name.ShouldBe("portNumber"); + parameters[1].ParameterType.ShouldBe(typeof(CancellationToken)); + parameters[1].HasDefaultValue.ShouldBeTrue(); + } + + [Fact] + public void IMasterConnection_ReadIndexAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IMasterConnection); + var method = interfaceType.GetMethod(nameof(IMasterConnection.ReadIndexAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task>)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(4); + parameters[0].ParameterType.ShouldBe(typeof(byte)); + parameters[0].Name.ShouldBe("portNumber"); + parameters[1].ParameterType.ShouldBe(typeof(ushort)); + parameters[1].Name.ShouldBe("index"); + parameters[2].ParameterType.ShouldBe(typeof(byte)); + parameters[2].Name.ShouldBe("subIindex"); + parameters[2].HasDefaultValue.ShouldBeTrue(); + parameters[2].DefaultValue.ShouldBe((byte)0); + parameters[3].ParameterType.ShouldBe(typeof(CancellationToken)); + parameters[3].HasDefaultValue.ShouldBeTrue(); + } + + [Fact] + public void IIODDProvider_HasCorrectMethods() + { + // Arrange + var interfaceType = typeof(IIODDProvider); + + // Act & Assert + var methods = interfaceType.GetMethods(); + methods.Any(m => m.Name == nameof(IIODDProvider.GetIODDPackageAsync)).ShouldBeTrue(); + } + + [Fact] + public void IIODDProvider_GetIODDPackageAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IIODDProvider); + var method = interfaceType.GetMethod(nameof(IIODDProvider.GetIODDPackageAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(4); + parameters[0].ParameterType.ShouldBe(typeof(ushort)); + parameters[0].Name.ShouldBe("vendorId"); + parameters[1].ParameterType.ShouldBe(typeof(uint)); + parameters[1].Name.ShouldBe("deviceId"); + parameters[2].ParameterType.ShouldBe(typeof(string)); + parameters[2].Name.ShouldBe("productId"); + parameters[3].ParameterType.ShouldBe(typeof(CancellationToken)); + parameters[3].HasDefaultValue.ShouldBeTrue(); + } + + [Fact] + public void IDeviceDefinitionProvider_HasCorrectMethods() + { + // Arrange + var interfaceType = typeof(IDeviceDefinitionProvider<>); + + // Act & Assert + var methods = interfaceType.GetMethods(); + methods + .Any(m => m.Name == nameof(IDeviceDefinitionProvider.GetDeviceDefinitionAsync)) + .ShouldBeTrue(); + } + + [Fact] + public void IDeviceDefinitionProvider_GetDeviceDefinitionAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IDeviceDefinitionProvider); // Using string as generic type parameter + var method = interfaceType.GetMethod( + nameof(IDeviceDefinitionProvider.GetDeviceDefinitionAsync) + ); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(4); + parameters[0].ParameterType.ShouldBe(typeof(ushort)); + parameters[0].Name.ShouldBe("vendorId"); + parameters[1].ParameterType.ShouldBe(typeof(uint)); + parameters[1].Name.ShouldBe("deviceId"); + parameters[2].ParameterType.ShouldBe(typeof(string)); + parameters[2].Name.ShouldBe("productId"); + parameters[3].ParameterType.ShouldBe(typeof(CancellationToken)); + parameters[3].HasDefaultValue.ShouldBeTrue(); + } +} diff --git a/src/Tests/IOLink.NET.Core.Tests/Contracts/PortStatusTests.cs b/src/Tests/IOLink.NET.Core.Tests/Contracts/PortStatusTests.cs new file mode 100644 index 0000000..dd493ef --- /dev/null +++ b/src/Tests/IOLink.NET.Core.Tests/Contracts/PortStatusTests.cs @@ -0,0 +1,109 @@ +namespace IOLink.NET.Core.Tests.Contracts; + +public class PortStatusTests +{ + [Fact] + public void PortStatus_HasCorrectValues() + { + // Assert + ((byte)PortStatus.Disconnected).ShouldBe((byte)0); + ((byte)PortStatus.Connected).ShouldBe((byte)1); + ((byte)PortStatus.IOLink).ShouldBe((byte)2); + ((byte)PortStatus.Error).ShouldBe((byte)4); + ((byte)PortStatus.DI).ShouldBe((byte)8); + } + + [Fact] + public void PortStatus_CanBeCombinedWithFlags() + { + // Arrange & Act + var combinedStatus = PortStatus.Connected | PortStatus.IOLink; + + // Assert + combinedStatus.HasFlag(PortStatus.Connected).ShouldBeTrue(); + combinedStatus.HasFlag(PortStatus.IOLink).ShouldBeTrue(); + combinedStatus.HasFlag(PortStatus.Error).ShouldBeFalse(); + combinedStatus.HasFlag(PortStatus.DI).ShouldBeFalse(); + // Note: Disconnected (0) will always return true for HasFlag, so we don't test it here + } + + [Fact] + public void PortStatus_AllFlagsCombination() + { + // Arrange & Act + var allFlags = PortStatus.Connected | PortStatus.IOLink | PortStatus.Error | PortStatus.DI; + + // Assert + allFlags.HasFlag(PortStatus.Connected).ShouldBeTrue(); + allFlags.HasFlag(PortStatus.IOLink).ShouldBeTrue(); + allFlags.HasFlag(PortStatus.Error).ShouldBeTrue(); + allFlags.HasFlag(PortStatus.DI).ShouldBeTrue(); + ((byte)allFlags).ShouldBe((byte)15); // 1 + 2 + 4 + 8 = 15 + } + + [Theory] + [InlineData(PortStatus.Disconnected, 0)] + [InlineData(PortStatus.Connected, 1)] + [InlineData(PortStatus.IOLink, 2)] + [InlineData(PortStatus.Error, 4)] + [InlineData(PortStatus.DI, 8)] + public void PortStatus_IndividualValuesAreCorrect(PortStatus status, byte expectedValue) + { + // Assert + ((byte)status).ShouldBe(expectedValue); + } + + [Fact] + public void PortStatus_IsMarkedWithFlagsAttribute() + { + // Arrange + var portStatusType = typeof(PortStatus); + + // Act + var hasFlagsAttribute = portStatusType + .GetCustomAttributes(typeof(FlagsAttribute), false) + .Any(); + + // Assert + hasFlagsAttribute.ShouldBeTrue(); + } + + [Fact] + public void PortStatus_IsOfTypeByte() + { + // Assert + typeof(PortStatus).GetEnumUnderlyingType().ShouldBe(typeof(byte)); + } + + [Theory] + [InlineData(PortStatus.Connected | PortStatus.IOLink, true, true, false, false)] + [InlineData(PortStatus.Error | PortStatus.DI, false, false, true, true)] + [InlineData(PortStatus.Connected | PortStatus.Error, true, false, true, false)] + public void PortStatus_ComplexFlagCombinations( + PortStatus status, + bool shouldBeConnected, + bool shouldBeIOLink, + bool shouldBeError, + bool shouldBeDI + ) + { + // Assert + status.HasFlag(PortStatus.Connected).ShouldBe(shouldBeConnected); + status.HasFlag(PortStatus.IOLink).ShouldBe(shouldBeIOLink); + status.HasFlag(PortStatus.Error).ShouldBe(shouldBeError); + status.HasFlag(PortStatus.DI).ShouldBe(shouldBeDI); + } + + [Fact] + public void PortStatus_DisconnectedDoesNotHaveAnyFlags() + { + // Arrange + var disconnectedStatus = PortStatus.Disconnected; + + // Assert + disconnectedStatus.HasFlag(PortStatus.Connected).ShouldBeFalse(); + disconnectedStatus.HasFlag(PortStatus.IOLink).ShouldBeFalse(); + disconnectedStatus.HasFlag(PortStatus.Error).ShouldBeFalse(); + disconnectedStatus.HasFlag(PortStatus.DI).ShouldBeFalse(); + } +} diff --git a/src/Tests/IOLink.NET.Core.Tests/Extensions/ByteArrayExtensionsTests.cs b/src/Tests/IOLink.NET.Core.Tests/Extensions/ByteArrayExtensionsTests.cs new file mode 100644 index 0000000..4d7c8fe --- /dev/null +++ b/src/Tests/IOLink.NET.Core.Tests/Extensions/ByteArrayExtensionsTests.cs @@ -0,0 +1,214 @@ +namespace IOLink.NET.Core.Tests.Extensions; + +public class ByteArrayExtensionsTests +{ + [Fact] + public void PinNegativeIntToRequiredBitLength_WhenBitLengthIsMultipleOf8_ReturnsOriginalData() + { + // Arrange + byte[] data = { 0xFF, 0xFF, 0xFF, 0xFF }; + ushort bitLength = 32; // Multiple of 8 + + // Act + var result = data.PinNegativeIntToRequiredBitLength(bitLength); + + // Assert + result.ShouldBe(data); + result.ShouldBeSameAs(data); // Should return the same reference + } + + [Fact] + public void PinNegativeIntToRequiredBitLength_WhenBitLengthIsNotMultipleOf8_MasksFirstByte() + { + // Arrange + byte[] data = { 0xFF, 0xFF }; + ushort bitLength = 10; // 10 % 8 = 2, mask = (-1 << 2) = 0xFC + + // Act + var result = data.PinNegativeIntToRequiredBitLength(bitLength); + + // Assert + result[0].ShouldBe((byte)0x03); // 0xFF ^ 0xFC = 0x03 + result[1].ShouldBe((byte)0xFF); // Second byte unchanged + result.ShouldBeSameAs(data); // Should return the same reference + } + + [Theory] + [InlineData(9, 0x01)] // 9 % 8 = 1, mask = (-1 << 1) = 0xFE, 0xFF ^ 0xFE = 0x01 + [InlineData(10, 0x03)] // 10 % 8 = 2, mask = (-1 << 2) = 0xFC, 0xFF ^ 0xFC = 0x03 + [InlineData(11, 0x07)] // 11 % 8 = 3, mask = (-1 << 3) = 0xF8, 0xFF ^ 0xF8 = 0x07 + [InlineData(12, 0x0F)] // 12 % 8 = 4, mask = (-1 << 4) = 0xF0, 0xFF ^ 0xF0 = 0x0F + public void PinNegativeIntToRequiredBitLength_VariousBitLengths_MasksCorrectly( + ushort bitLength, + byte expectedFirstByte + ) + { + // Arrange + byte[] data = { 0xFF, 0xFF }; + + // Act + var result = data.PinNegativeIntToRequiredBitLength(bitLength); + + // Assert + result[0].ShouldBe(expectedFirstByte); + result[1].ShouldBe((byte)0xFF); + } + + [Fact] + public void PinNegativeIntToRequiredBitLength_WithSingleByte_WorksCorrectly() + { + // Arrange + byte[] data = { 0xFF }; + ushort bitLength = 5; // 5 % 8 = 5, mask first (8-5=3) bits + + // Act + var result = data.PinNegativeIntToRequiredBitLength(bitLength); + + // Assert + // mask = (-1 << 5) = 0xE0, 0xFF ^ 0xE0 = 0x1F + result[0].ShouldBe((byte)0x1F); + } + + [Fact] + public void TruncateToBitLength_WhenExactByteLength_ReturnsLastBytes() + { + // Arrange + byte[] data = { 0x01, 0x02, 0x03, 0x04 }; + ushort bitLength = 16; // 2 bytes + + // Act + var result = data.TruncateToBitLength(bitLength); + + // Assert + result.Length.ShouldBe(2); + result[0].ShouldBe((byte)0x03); + result[1].ShouldBe((byte)0x04); + } + + [Fact] + public void TruncateToBitLength_WhenBitLengthRequiresPartialByte_RoundsUpByteLength() + { + // Arrange + byte[] data = { 0x01, 0x02, 0x03, 0x04 }; + ushort bitLength = 17; // 2.125 bytes, so 3 bytes needed + + // Act + var result = data.TruncateToBitLength(bitLength); + + // Assert + result.Length.ShouldBe(3); + result[0].ShouldBe((byte)0x02); + result[1].ShouldBe((byte)0x03); + result[2].ShouldBe((byte)0x04); + } + + [Theory] + [InlineData(8, 1)] // 8 bits = 1 byte + [InlineData(9, 2)] // 9 bits = 2 bytes (rounded up) + [InlineData(16, 2)] // 16 bits = 2 bytes + [InlineData(17, 3)] // 17 bits = 3 bytes (rounded up) + [InlineData(24, 3)] // 24 bits = 3 bytes + [InlineData(25, 4)] // 25 bits = 4 bytes (rounded up) + public void TruncateToBitLength_VariousBitLengths_ReturnsCorrectByteLength( + ushort bitLength, + int expectedByteLength + ) + { + // Arrange + byte[] data = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + + // Act + var result = data.TruncateToBitLength(bitLength); + + // Assert + result.Length.ShouldBe(expectedByteLength); + } + + [Fact] + public void TruncateToBitLength_WhenBitLengthEqualsDataLength_ReturnsAllData() + { + // Arrange + byte[] data = { 0x01, 0x02, 0x03 }; + ushort bitLength = 24; // 3 bytes + + // Act + var result = data.TruncateToBitLength(bitLength); + + // Assert + result.Length.ShouldBe(3); + result.ShouldBe(data); + } + + [Fact] + public void TruncateToBitLength_WhenBitLengthExceedsDataLength_ReturnsAllData() + { + // Arrange + byte[] data = { 0x01, 0x02 }; + ushort bitLength = 32; // 4 bytes, but data only has 2 + // requiredByteLength = 32/8 + 0 = 4 + // But data.Length - requiredByteLength = 2 - 4 = -2, which causes ArgumentOutOfRangeException + + // Act & Assert + // The current implementation doesn't handle this case gracefully + Should.Throw(() => data.TruncateToBitLength(bitLength)); + } + + [Fact] + public void TruncateToBitLength_WithEmptyArray_ThrowsException() + { + // Arrange + byte[] data = Array.Empty(); + ushort bitLength = 8; + // requiredByteLength = 8/8 + 0 = 1 + // data.Length - requiredByteLength = 0 - 1 = -1, which causes ArgumentOutOfRangeException + + // Act & Assert + Should.Throw(() => data.TruncateToBitLength(bitLength)); + } + + [Fact] + public void TruncateToBitLength_WithZeroBitLength_ReturnsEmptyArray() + { + // Arrange + byte[] data = { 0x01, 0x02, 0x03 }; + ushort bitLength = 0; + // requiredByteLength = 0/8 + 0 = 0 + // data.Length - requiredByteLength = 3 - 0 = 3, so we get data[3..] which is empty + + // Act + var result = data.TruncateToBitLength(bitLength); + + // Assert + result.Length.ShouldBe(0); + } + + [Fact] + public void PinNegativeIntToRequiredBitLength_WithEmptyArray_ReturnsEmptyArray() + { + // Arrange + byte[] data = Array.Empty(); + ushort bitLength = 8; + + // Act + var result = data.PinNegativeIntToRequiredBitLength(bitLength); + + // Assert + result.Length.ShouldBe(0); + result.ShouldBeSameAs(data); + } + + [Fact] + public void ByteArrayExtensions_MethodsAreExtensionMethods() + { + // Arrange + byte[] data = { 0x01, 0x02 }; + + // Act & Assert + // This test verifies that the methods can be called as extension methods + var result1 = data.TruncateToBitLength(8); + var result2 = data.PinNegativeIntToRequiredBitLength(8); + + result1.ShouldNotBeNull(); + result2.ShouldNotBeNull(); + } +} diff --git a/src/Tests/IOLink.NET.Core.Tests/GlobalUsings.cs b/src/Tests/IOLink.NET.Core.Tests/GlobalUsings.cs new file mode 100644 index 0000000..9d7ba5f --- /dev/null +++ b/src/Tests/IOLink.NET.Core.Tests/GlobalUsings.cs @@ -0,0 +1,6 @@ +global using IOLink.NET.Core.Contracts; +global using IOLink.NET.Core.Extensions; +global using IOLink.NET.Core.Models; +global using NSubstitute; +global using Shouldly; +global using Xunit; diff --git a/src/Tests/IOLink.NET.Core.Tests/IOLink.NET.Core.Tests.csproj b/src/Tests/IOLink.NET.Core.Tests/IOLink.NET.Core.Tests.csproj new file mode 100644 index 0000000..5d6f006 --- /dev/null +++ b/src/Tests/IOLink.NET.Core.Tests/IOLink.NET.Core.Tests.csproj @@ -0,0 +1,21 @@ + + + + false + true + + + + + + + + + + + + + + + + diff --git a/src/Tests/IOLink.NET.Core.Tests/Models/DeviceInformationTests.cs b/src/Tests/IOLink.NET.Core.Tests/Models/DeviceInformationTests.cs new file mode 100644 index 0000000..3bb5ba6 --- /dev/null +++ b/src/Tests/IOLink.NET.Core.Tests/Models/DeviceInformationTests.cs @@ -0,0 +1,109 @@ +namespace IOLink.NET.Core.Tests.Models; + +public class DeviceInformationTests +{ + [Fact] + public void Constructor_SetsPropertiesCorrectly() + { + // Arrange + ushort expectedVendorId = 123; + uint expectedDeviceId = 456789; + string expectedProductId = "TEST-PRODUCT-123"; + + // Act + var deviceInfo = new DeviceInformation( + expectedVendorId, + expectedDeviceId, + expectedProductId + ); + + // Assert + deviceInfo.VendorId.ShouldBe(expectedVendorId); + deviceInfo.DeviceId.ShouldBe(expectedDeviceId); + deviceInfo.ProductId.ShouldBe(expectedProductId); + } + + [Fact] + public void VendorId_IsReadOnly() + { + // Arrange + var deviceInfo = new DeviceInformation(123, 456, "test"); + + // Act & Assert + deviceInfo.VendorId.ShouldBe((ushort)123); + // Property should not have a setter (read-only) + typeof(DeviceInformation) + .GetProperty(nameof(DeviceInformation.VendorId))! + .CanWrite.ShouldBeFalse(); + } + + [Fact] + public void DeviceId_IsReadOnly() + { + // Arrange + var deviceInfo = new DeviceInformation(123, 456, "test"); + + // Act & Assert + deviceInfo.DeviceId.ShouldBe((uint)456); + // Property should not have a setter (read-only) + typeof(DeviceInformation) + .GetProperty(nameof(DeviceInformation.DeviceId))! + .CanWrite.ShouldBeFalse(); + } + + [Fact] + public void ProductId_IsReadOnly() + { + // Arrange + string expectedProductId = "test-product"; + var deviceInfo = new DeviceInformation(123, 456, expectedProductId); + + // Act & Assert + deviceInfo.ProductId.ShouldBe(expectedProductId); + // Property should not have a setter (read-only) + typeof(DeviceInformation) + .GetProperty(nameof(DeviceInformation.ProductId))! + .CanWrite.ShouldBeFalse(); + } + + [Theory] + [InlineData((ushort)0, (uint)0, "")] + [InlineData((ushort)1, (uint)1, "A")] + [InlineData( + (ushort)65535, + (uint)4294967295, + "VERY-LONG-PRODUCT-ID-WITH-SPECIAL-CHARS-!@#$%^&*()" + )] + public void Constructor_HandlesEdgeCases(ushort vendorId, uint deviceId, string productId) + { + // Act + var deviceInfo = new DeviceInformation(vendorId, deviceId, productId); + + // Assert + deviceInfo.VendorId.ShouldBe(vendorId); + deviceInfo.DeviceId.ShouldBe(deviceId); + deviceInfo.ProductId.ShouldBe(productId); + } + + [Fact] + public void Constructor_WithNullProductId_AllowsNull() + { + // Arrange & Act - The actual implementation accepts null values + var deviceInfo = new DeviceInformation(123, 456, null!); + + // Assert + deviceInfo.VendorId.ShouldBe((ushort)123); + deviceInfo.DeviceId.ShouldBe((uint)456); + deviceInfo.ProductId.ShouldBeNull(); + } + + [Fact] + public void ImplementsIDeviceInformation() + { + // Arrange & Act + var deviceInfo = new DeviceInformation(123, 456, "test"); + + // Assert + deviceInfo.ShouldBeAssignableTo(); + } +} diff --git a/src/Tests/IOLink.NET.Core.Tests/Models/PortInformationTests.cs b/src/Tests/IOLink.NET.Core.Tests/Models/PortInformationTests.cs new file mode 100644 index 0000000..6a4e700 --- /dev/null +++ b/src/Tests/IOLink.NET.Core.Tests/Models/PortInformationTests.cs @@ -0,0 +1,130 @@ +namespace IOLink.NET.Core.Tests.Models; + +public class PortInformationTests +{ + [Fact] + public void Constructor_SetsPropertiesCorrectly() + { + // Arrange + byte expectedPortNumber = 5; + PortStatus expectedStatus = PortStatus.Connected | PortStatus.IOLink; + var deviceInfo = new DeviceInformation(123, 456, "test-device"); + + // Act + var portInfo = new PortInformation(expectedPortNumber, expectedStatus, deviceInfo); + + // Assert + portInfo.PortNumber.ShouldBe(expectedPortNumber); + portInfo.Status.ShouldBe(expectedStatus); + portInfo.DeviceInformation.ShouldBe(deviceInfo); + } + + [Fact] + public void Constructor_WithNullDeviceInformation_SetsDeviceInformationToNull() + { + // Arrange + byte portNumber = 3; + PortStatus status = PortStatus.Disconnected; + + // Act + var portInfo = new PortInformation(portNumber, status, null); + + // Assert + portInfo.PortNumber.ShouldBe(portNumber); + portInfo.Status.ShouldBe(status); + portInfo.DeviceInformation.ShouldBeNull(); + } + + [Fact] + public void PortNumber_IsReadOnly() + { + // Arrange + var portInfo = new PortInformation(1, PortStatus.Connected, null); + + // Act & Assert + portInfo.PortNumber.ShouldBe((byte)1); + // Property should not have a setter (read-only) + typeof(PortInformation) + .GetProperty(nameof(PortInformation.PortNumber))! + .CanWrite.ShouldBeFalse(); + } + + [Fact] + public void Status_IsReadOnly() + { + // Arrange + var expectedStatus = PortStatus.Error; + var portInfo = new PortInformation(1, expectedStatus, null); + + // Act & Assert + portInfo.Status.ShouldBe(expectedStatus); + // Property should not have a setter (read-only) + typeof(PortInformation) + .GetProperty(nameof(PortInformation.Status))! + .CanWrite.ShouldBeFalse(); + } + + [Fact] + public void DeviceInformation_IsReadOnly() + { + // Arrange + var deviceInfo = new DeviceInformation(123, 456, "test"); + var portInfo = new PortInformation(1, PortStatus.Connected, deviceInfo); + + // Act & Assert + portInfo.DeviceInformation.ShouldBe(deviceInfo); + // Property should not have a setter (read-only) + typeof(PortInformation) + .GetProperty(nameof(PortInformation.DeviceInformation))! + .CanWrite.ShouldBeFalse(); + } + + [Theory] + [InlineData((byte)0, PortStatus.Disconnected)] + [InlineData((byte)1, PortStatus.Connected)] + [InlineData((byte)8, PortStatus.IOLink)] + [InlineData((byte)16, PortStatus.Error)] + [InlineData((byte)255, PortStatus.DI)] + [InlineData((byte)128, PortStatus.Connected | PortStatus.IOLink | PortStatus.Error)] + public void Constructor_HandlesVariousPortNumbersAndStatuses(byte portNumber, PortStatus status) + { + // Arrange + var deviceInfo = new DeviceInformation(100, 200, "test-device"); + + // Act + var portInfo = new PortInformation(portNumber, status, deviceInfo); + + // Assert + portInfo.PortNumber.ShouldBe(portNumber); + portInfo.Status.ShouldBe(status); + portInfo.DeviceInformation.ShouldBe(deviceInfo); + } + + [Fact] + public void ImplementsIPortInformation() + { + // Arrange & Act + var portInfo = new PortInformation(1, PortStatus.Connected, null); + + // Assert + portInfo.ShouldBeAssignableTo(); + } + + [Fact] + public void Constructor_WithAllPortStatusFlags_WorksCorrectly() + { + // Arrange + var allFlags = PortStatus.Connected | PortStatus.IOLink | PortStatus.Error | PortStatus.DI; + var deviceInfo = new DeviceInformation(999, 888, "complex-device"); + + // Act + var portInfo = new PortInformation(7, allFlags, deviceInfo); + + // Assert + portInfo.Status.ShouldBe(allFlags); + portInfo.Status.HasFlag(PortStatus.Connected).ShouldBeTrue(); + portInfo.Status.HasFlag(PortStatus.IOLink).ShouldBeTrue(); + portInfo.Status.HasFlag(PortStatus.Error).ShouldBeTrue(); + portInfo.Status.HasFlag(PortStatus.DI).ShouldBeTrue(); + } +} diff --git a/src/Tests/IOLink.NET.Tests/DeviceDefinitionProviderTests.cs b/src/Tests/IOLink.NET.Tests/DeviceDefinitionProviderTests.cs new file mode 100644 index 0000000..7ddf9af --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/DeviceDefinitionProviderTests.cs @@ -0,0 +1,18 @@ +using IOLink.NET.IODD.Provider; + +namespace IOLink.NET.Tests; + +public class DeviceDefinitionProviderTests +{ + private readonly Uri _baseUrl = new("https://ioddfinder.io-link.com/"); + + [Fact] + public async Task DoesLoadDeviceDefinitionAsync() + { + var client = new IODDFinderPublicClient(_baseUrl); + var provider = new DeviceDefinitionProvider(client); + var definition = await provider.GetDeviceDefinitionAsync(888, 200710, "50142212"); + + definition.ProfileBody.DeviceIdentity.VendorId.ShouldBe((ushort)888); + } +} diff --git a/src/Tests/IOLink.NET.Tests/EventCodeParserTests.cs b/src/Tests/IOLink.NET.Tests/EventCodeParserTests.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/Tests/IOLink.NET.Tests/GlobalUsings.cs b/src/Tests/IOLink.NET.Tests/GlobalUsings.cs new file mode 100644 index 0000000..4de3ec0 --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/GlobalUsings.cs @@ -0,0 +1,11 @@ +global using Shouldly; +global using IOLink.NET.Conversion; +global using IOLink.NET.IODD.Parser; +global using Xunit; + + + + + + + diff --git a/src/Tests/IODD.Provider.Tests/IODDFinderPublicClientTests.cs b/src/Tests/IOLink.NET.Tests/IODDFinderPublicClientTests.cs similarity index 67% rename from src/Tests/IODD.Provider.Tests/IODDFinderPublicClientTests.cs rename to src/Tests/IOLink.NET.Tests/IODDFinderPublicClientTests.cs index 2c90673..f77b99c 100644 --- a/src/Tests/IODD.Provider.Tests/IODDFinderPublicClientTests.cs +++ b/src/Tests/IOLink.NET.Tests/IODDFinderPublicClientTests.cs @@ -1,17 +1,25 @@ -using IOLinkNET.IODD.Provider; - -namespace IODD.Provider.Tests; - -public class IODDFinderPublicClientTests -{ - private readonly Uri _baseUrl = new("https://ioddfinder.io-link.com/"); - [Fact] - public async Task DoesLoadIoddAsync() - { - var client = new IODDFinderPublicClient(_baseUrl); - var iodd = await client.GetIODDPackageAsync(888, 131329, ""); - - iodd.Should().NotBeNull(); - iodd.CanRead.Should().BeTrue(); - } -} \ No newline at end of file +using IOLink.NET.IODD.Provider; + +namespace IOLink.NET.Tests; + +public class IODDFinderPublicClientTests +{ + private readonly Uri _baseUrl = new("https://ioddfinder.io-link.com/"); + + [Fact] + public async Task DoesLoadIoddAsync() + { + var client = new IODDFinderPublicClient(_baseUrl); + var iodd = await client.GetIODDPackageAsync(888, 131329, ""); + + iodd.ShouldNotBeNull(); + iodd.CanRead.ShouldBeTrue(); + } +} + + + + + + + diff --git a/src/Tests/IOLink.NET.Tests/IODDPortReaderTests.cs b/src/Tests/IOLink.NET.Tests/IODDPortReaderTests.cs new file mode 100644 index 0000000..0462c14 --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/IODDPortReaderTests.cs @@ -0,0 +1,254 @@ +using System.Xml.Linq; +using IOLink.NET.Conversion; +using IOLink.NET.Core.Contracts; +using IOLink.NET.Integration; +using IOLink.NET.IODD; +using IOLink.NET.IODD.Provider; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Resolution.Contracts; +using IOLink.NET.IODD.Structure; +using NSubstitute; +using Shouldly; + +namespace IOLink.NET.Tests; + +public class IODDPortReaderTests +{ + [Theory] + [InlineData( + 888, + 328205, + "BNI IOL-727-S51-P012", + "Balluff", + "TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml" + )] + [InlineData( + 888, + 459267, + "BCS012N", + "Balluff", + "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml" + )] + public async Task CanInitializeForPortAsync( + ushort vendorId, + uint deviceId, + string productId, + string vendorName, + string ioddPath + ) + { + var (portReader, ioddProvider, masterConnection) = PreparePortReader( + vendorId, + deviceId, + productId, + vendorName, + ioddPath + ); + + await portReader.InitializeForPortAsync(1); + + await ioddProvider + .Received() + .GetDeviceDefinitionAsync(vendorId, deviceId, productId, Arg.Any()); + await masterConnection.Received().GetPortInformationAsync(1, Arg.Any()); + } + + [Fact] + public async Task ShouldThrowIfPortIsNotInIOLinkModeAsync() + { + var (portReader, _, masterConnection) = PreparePortReader( + 888, + 459267, + "BCS012N", + "Balluff", + "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml" + ); + var portInfo = Substitute.For(); + portInfo.Status.Returns(PortStatus.Connected); + masterConnection.GetPortInformationAsync(1, Arg.Any()).Returns(portInfo); + + var initTask = () => portReader.InitializeForPortAsync(1); + + await Should.ThrowAsync(initTask); + } + + [Fact] + public async Task ShouldThrowIfNoDeviceInfoAsync() + { + var (portReader, _, masterConnection) = PreparePortReader( + 888, + 459267, + "BCS012N", + "Balluff", + "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml" + ); + var portInfo = Substitute.For(); + portInfo.Status.Returns(PortStatus.Connected | PortStatus.IOLink); + portInfo.DeviceInformation.Returns(null as IDeviceInformation); + + masterConnection.GetPortInformationAsync(1, Arg.Any()).Returns(portInfo); + + var initTask = () => portReader.InitializeForPortAsync(1); + + await Should.ThrowAsync(initTask); + } + + [Fact] + public async Task ShouldThrowIfUninitializedParameterReadAsync() + { + var (portReader, _, _) = PreparePortReader( + 888, + 459267, + "BCS012N", + "Balluff", + "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml" + ); + var readParamTask = () => portReader.ReadConvertedParameterAsync(58, 0); + + await Should.ThrowAsync(readParamTask); + } + + [Fact] + public async Task ShouldThrowIfUninitializedProcessDataInReadAsync() + { + var (portReader, _, _) = PreparePortReader( + 888, + 459267, + "BCS012N", + "Balluff", + "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml" + ); + var readParamTask = portReader.ReadConvertedProcessDataInAsync; + + await Should.ThrowAsync(readParamTask); + } + + [Fact] + public async Task ShouldThrowIfUninitializedProcessDataOutReadAsync() + { + var (portReader, _, _) = PreparePortReader( + 888, + 459267, + "BCS012N", + "Balluff", + "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml" + ); + var readParamTask = portReader.ReadConvertedProcessDataOutAsync; + + await Should.ThrowAsync(readParamTask); + } + + [Fact] + public async Task CanReadConvertedProcessDataInWithConditionAsync() + { + var (portReader, _, masterConnection) = PreparePortReader( + 1222, + 18, + "CSS 01411.2-xx", + "STEGO", + "TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml" + ); + masterConnection.ReadIndexAsync(1, 66).Returns(new byte[] { 0x00 }); + masterConnection + .ReadProcessDataInAsync(1) + .Returns(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0 }); + await portReader.InitializeForPortAsync(1); + + var pd = + (await portReader.ReadConvertedProcessDataInAsync()) as IEnumerable<(string, object)>; + pd.ShouldNotBeNull(); + + // Debug: Let's examine what's actually in the collection + var pdList = pd.ToList(); + var targetItem = pdList.FirstOrDefault(x => x.Item1 == "TN_PDI_Feuchte"); + targetItem.ShouldNotBe(default); // This should pass if the item exists + targetItem.Item2.ShouldBe(0); + } + + [Theory] + [InlineData( + 888, + 459267, + "BCS012N", + "Balluff", + "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml" + )] + public async Task CanReadConvertedParameterAsync( + ushort vendorId, + uint deviceId, + string productId, + string vendorName, + string ioddPath + ) + { + var (portReader, _, masterConnection) = PreparePortReader( + vendorId, + deviceId, + productId, + vendorName, + ioddPath + ); + masterConnection.ReadIndexAsync(1, 58).Returns(new byte[] { 0x00, 0x00, 0x00, 0x04 }); + await portReader.InitializeForPortAsync(1); + + var converted = await portReader.ReadConvertedParameterAsync(58, 0); + converted.ShouldBe(4); + } + + private (IODDPortReader, IDeviceDefinitionProvider, IMasterConnection) PreparePortReader( + ushort vendorId, + uint deviceId, + string productId, + string vendorName, + string ioddPath + ) + { + var ioddParser = new IODDParser(); + var device = ioddParser.Parse(XElement.Load(ioddPath)); + var ioddProvider = Substitute.For(); + ioddProvider + .GetDeviceDefinitionAsync(vendorId, deviceId, productId, Arg.Any()) + .Returns(device); + + var masterConnection = GetMasterConnectionMock(vendorId, deviceId, productId, vendorName); + var typeResolverFactory = Substitute.For(); + typeResolverFactory + .CreateParameterTypeResolver(Arg.Any()) + .Returns(d => new ParameterTypeResolver(d.Arg())); + typeResolverFactory + .CreateProcessDataTypeResolver(Arg.Any()) + .Returns(d => new ProcessDataTypeResolver(d.Arg())); + + var portReader = new IODDPortReader( + masterConnection, + ioddProvider, + new IoddConverter(), + typeResolverFactory + ); + + return (portReader, ioddProvider, masterConnection); + } + + private IMasterConnection GetMasterConnectionMock( + ushort vendorId, + uint deviceId, + string productId, + string vendorName + ) + { + var portInfo = Substitute.For(); + var deviceInfo = Substitute.For(); + deviceInfo.VendorId.Returns(vendorId); + deviceInfo.DeviceId.Returns(deviceId); + deviceInfo.ProductId.Returns(productId); + + portInfo.PortNumber.Returns((byte)1); + portInfo.Status.Returns(PortStatus.Connected | PortStatus.IOLink); + portInfo.DeviceInformation.Returns(deviceInfo); + + var masterConnection = Substitute.For(); + masterConnection.GetPortInformationAsync(1, Arg.Any()).Returns(portInfo); + + return masterConnection; + } +} diff --git a/src/Tests/IOLink.NET.Tests/IODDUserInterfaceConverterTests.cs b/src/Tests/IOLink.NET.Tests/IODDUserInterfaceConverterTests.cs new file mode 100644 index 0000000..e66f7f4 --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/IODDUserInterfaceConverterTests.cs @@ -0,0 +1,121 @@ +using IOLink.NET.Conversion; +using IOLink.NET.Core.Contracts; +using IOLink.NET.Integration; +using IOLink.NET.IODD.Provider; +using IOLink.NET.IODD.Resolution.Contracts; +using IOLink.NET.IODD.Structure.Interfaces; +using IOLink.NET.IODD.Structure.Structure.Menu; +using IOLink.NET.Visualization.IODDConversion; +using NSubstitute; +using NSubstitute.ReturnsExtensions; +using Shouldly; + +namespace IOLink.NET.Tests; + +public class IODDUserInterfaceConverterTests +{ + [Fact] + public void ConversionThrowsIfUserInterfaceIsNotPresent() + { + var deviceSub = Substitute.For(); + deviceSub.ProfileBody.DeviceFunction.UserInterface.ReturnsNull(); + var ioddUserInterfaceConverter = new IODDUserInterfaceConverter( + deviceSub, + GetSubstituteForIODDPortReader() + ); + + var convertAction = () => ioddUserInterfaceConverter.Convert(); + + Should.Throw(convertAction, "User Interface not present in IODD"); + } + + [Fact] + public void MissingObserverRoleMenuIdentificationSubMenuShouldThrow() + { + var deviceSub = Substitute.For(); + deviceSub.ProfileBody.DeviceFunction.UserInterface.ObserverRoleMenuSet.IdentificationMenu.Returns( + new UIMenuRefSimpleT(null, null) + ); + var ioddUserInterfaceConverter = new IODDUserInterfaceConverter( + deviceSub, + GetSubstituteForIODDPortReader() + ); + var convertAction = () => ioddUserInterfaceConverter.Convert(); + + Should.Throw( + convertAction, + "Observerrole Menu must provide Identification Menu" + ); + } + + [Fact] + public void MissingMaintenanceRoleMenuIdentificationSubMenuShouldThrow() + { + var deviceSub = Substitute.For(); + var menuList = new List() + { + new(new("M_OR_Ident", null, null, null, null)), + }; + deviceSub.ProfileBody.DeviceFunction.UserInterface.MenuCollection.Returns(menuList); + deviceSub.ProfileBody.DeviceFunction.UserInterface.ObserverRoleMenuSet.IdentificationMenu.Returns( + new UIMenuRefSimpleT("M_OR_Ident", null) + ); + deviceSub.ProfileBody.DeviceFunction.UserInterface.MaintenanceRoleMenuSet.IdentificationMenu.Returns( + new UIMenuRefSimpleT(null, null) + ); + + var ioddUserInterfaceConverter = new IODDUserInterfaceConverter( + deviceSub, + GetSubstituteForIODDPortReader() + ); + var convertAction = () => ioddUserInterfaceConverter.Convert(); + + Should.Throw( + convertAction, + "Maintenancerole Menu must provide Identification Menu" + ); + } + + [Fact] + public void MissingSpecialistRoleMenuIdentificationSubMenuShouldThrow() + { + var deviceSub = Substitute.For(); + + var menuList = new List() + { + new(new("M_OR_Ident", null, null, null, null)), + new(new("M_MR_SR_Ident", null, null, null, null)), + }; + + deviceSub.ProfileBody.DeviceFunction.UserInterface.MenuCollection.Returns(menuList); + deviceSub.ProfileBody.DeviceFunction.UserInterface.ObserverRoleMenuSet.IdentificationMenu.Returns( + new UIMenuRefSimpleT("M_OR_Ident", null) + ); + deviceSub.ProfileBody.DeviceFunction.UserInterface.MaintenanceRoleMenuSet.IdentificationMenu.Returns( + new UIMenuRefSimpleT("M_MR_SR_Ident", null) + ); + deviceSub.ProfileBody.DeviceFunction.UserInterface.SpecialistRoleMenuSet.IdentificationMenu.Returns( + new UIMenuRefSimpleT(null, null) + ); + var ioddUserInterfaceConverter = new IODDUserInterfaceConverter( + deviceSub, + GetSubstituteForIODDPortReader() + ); + var convertAction = () => ioddUserInterfaceConverter.Convert(); + + Should.Throw( + convertAction, + "Specialistrole Menu must provide Identification Menu" + ); + } + + private static IODDPortReader GetSubstituteForIODDPortReader() + { + return Substitute.For( + Substitute.For(), + Substitute.For(), + Substitute.For(), + Substitute.For() + ); + } +} diff --git a/src/Tests/IOLink.NET.Tests/IOLink.NET.Tests.csproj b/src/Tests/IOLink.NET.Tests/IOLink.NET.Tests.csproj new file mode 100644 index 0000000..ee406f4 --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/IOLink.NET.Tests.csproj @@ -0,0 +1,31 @@ + + + + false + true + + + + + + + + + + + + + + + + + + + + + PreserveNewest + TestData\%(Filename)%(Extension) + + + + diff --git a/src/Tests/IOLink.NET.Tests/IoddComplexWriterTests.cs b/src/Tests/IOLink.NET.Tests/IoddComplexWriterTests.cs new file mode 100644 index 0000000..daf1c8f --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/IoddComplexWriterTests.cs @@ -0,0 +1,298 @@ +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Structure.Datatypes; +using Shouldly; + +namespace IOLink.NET.Tests; + +public class IoddComplexWriterTests +{ + [Fact] + public void WriteArrayType_WithValidData_ShouldReturnCorrectBytes() + { + // Arrange + var elementType = new ParsableSimpleDatatypeDef("element", KindOfSimpleType.UInteger, 8); + var arrayType = new ParsableArray("testArray", elementType, true, 3); + var values = new object[] { 1, 2, 3 }; + + // Act + var result = IoddComplexWriter.Write(arrayType, values); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(3); // 3 bytes for 3 8-bit elements + } + + [Fact] + public void WriteArrayType_WithWrongLength_ShouldThrowArgumentException() + { + // Arrange + var elementType = new ParsableSimpleDatatypeDef("element", KindOfSimpleType.UInteger, 8); + var arrayType = new ParsableArray("testArray", elementType, true, 3); + var values = new object[] { 1, 2 }; // Wrong length + + // Act & Assert + var act = () => IoddComplexWriter.Write(arrayType, values); + Should.Throw(act, "Array length mismatch. Expected 3, got 2*"); + } + + [Fact] + public void WriteArrayType_WithNonEnumerable_ShouldThrowArgumentException() + { + // Arrange + var elementType = new ParsableSimpleDatatypeDef("element", KindOfSimpleType.UInteger, 8); + var arrayType = new ParsableArray("testArray", elementType, true, 3); + var value = "not enumerable"; + + // Act & Assert + var act = () => IoddComplexWriter.Write(arrayType, value); + Should.Throw(act, "Value must be an enumerable for array types*"); + } + + [Fact] + public void WriteArrayType_With4BitElements_ShouldPackCorrectly() + { + // Arrange + var elementType = new ParsableSimpleDatatypeDef("element", KindOfSimpleType.UInteger, 4); + var arrayType = new ParsableArray("testArray", elementType, true, 2); + var values = new object[] { 5, 10 }; // 0101, 1010 + + // Act + var result = IoddComplexWriter.Write(arrayType, values); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(1); // 2 4-bit elements should fit in 1 byte + } + + [Fact] + public void WriteRecordType_WithValidData_ShouldReturnCorrectBytes() + { + // Arrange + var field1 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field1", KindOfSimpleType.UInteger, 4), + "field1", + 0, + 1 + ); + var field2 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field2", KindOfSimpleType.UInteger, 4), + "field2", + 4, + 2 + ); + + var recordType = new ParsableRecord("testRecord", 8, true, new[] { field1, field2 }); + var values = new (string key, object value)[] { ("field1", 5), ("field2", 10) }; + + // Act + var result = IoddComplexWriter.Write(recordType, values); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(1); // 8 bits = 1 byte + } + + [Fact] + public void WriteRecordType_WithMissingField_ShouldThrowArgumentException() + { + // Arrange + var field1 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field1", KindOfSimpleType.UInteger, 4), + "field1", + 0, + 1 + ); + var field2 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field2", KindOfSimpleType.UInteger, 4), + "field2", + 4, + 2 + ); + + var recordType = new ParsableRecord("testRecord", 8, true, new[] { field1, field2 }); + var values = new (string key, object value)[] + { + ("field1", 5), + // Missing field2 + }; + + // Act & Assert + var act = () => IoddComplexWriter.Write(recordType, values); + Should.Throw(act, "Missing value for record item 'field2'*"); + } + + [Fact] + public void WriteRecordType_WithNonKeyValuePairs_ShouldThrowArgumentException() + { + // Arrange + var field1 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field1", KindOfSimpleType.UInteger, 8), + "field1", + 0, + 1 + ); + + var recordType = new ParsableRecord("testRecord", 8, true, new[] { field1 }); + var value = "not key-value pairs"; + + // Act & Assert + var act = () => IoddComplexWriter.Write(recordType, value); + Should.Throw( + act, + "Value must be an enumerable of key-value pairs for record types*" + ); + } + + [Fact] + public void WriteRecordType_ComplexRecord_ShouldHandleMultipleFields() + { + // Arrange + var field1 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("temp", KindOfSimpleType.Integer, 16), + "temperature", + 0, + 1 + ); + var field2 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("humid", KindOfSimpleType.UInteger, 8), + "humidity", + 16, + 2 + ); + var field3 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("active", KindOfSimpleType.Boolean, 1), + "isActive", + 24, + 3 + ); + + var recordType = new ParsableRecord( + "sensorData", + 25, + true, + new[] { field1, field2, field3 } + ); + var values = new (string key, object value)[] + { + ("temperature", 250), + ("humidity", 65), + ("isActive", true), + }; + + // Act + var result = IoddComplexWriter.Write(recordType, values); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(4); // 25 bits = 4 bytes (rounded up) + } + + [Fact] + public void Write_WithUnsupportedComplexType_ShouldThrowInvalidOperationException() + { + // Arrange + var unsupportedType = new TestUnsupportedComplexType(); + var value = new object(); + + // Act & Assert + var act = () => IoddComplexWriter.Write(unsupportedType, value); + Should.Throw( + act, + "Type TestUnsupportedComplexType is not supported." + ); + } + + [Theory] + [InlineData(1, new byte[] { 0x01 })] + [InlineData(2, new byte[] { 0x01, 0x02 })] + [InlineData(3, new byte[] { 0x01, 0x02, 0x03 })] + public void WriteArrayType_WithDifferentLengths_ShouldHandleCorrectly( + int length, + byte[] expectedValues + ) + { + // Arrange + var elementType = new ParsableSimpleDatatypeDef("element", KindOfSimpleType.UInteger, 8); + var arrayType = new ParsableArray("testArray", elementType, true, (ushort)length); + var values = expectedValues.Cast().ToArray(); + + // Act + var result = IoddComplexWriter.Write(arrayType, values); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(length); + } + + [Fact] + public void WriteArrayType_WithBooleanElements_ShouldPackBitsCorrectly() + { + // Arrange + var elementType = new ParsableSimpleDatatypeDef("element", KindOfSimpleType.Boolean, 1); + var arrayType = new ParsableArray("boolArray", elementType, true, 8); + var values = new object[] { true, false, true, true, false, false, true, false }; + + // Act + var result = IoddComplexWriter.Write(arrayType, values); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(1); // 8 bits = 1 byte + } + + [Fact] + public void WriteRecordType_WithBitPackedFields_ShouldHandleOffsets() + { + // Arrange - Create a record with fields at different bit offsets + var field1 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("f1", KindOfSimpleType.UInteger, 3), + "field1", + 0, + 1 + ); + var field2 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("f2", KindOfSimpleType.UInteger, 2), + "field2", + 3, + 2 + ); + var field3 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("f3", KindOfSimpleType.UInteger, 3), + "field3", + 5, + 3 + ); + + var recordType = new ParsableRecord( + "packedRecord", + 8, + true, + new[] { field1, field2, field3 } + ); + var values = new (string key, object value)[] + { + ("field1", 5), // 101 + ("field2", 2), // 10 + ( + "field3", + 3 + ) // 011 + , + }; + + // Act + var result = IoddComplexWriter.Write(recordType, values); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(1); // 8 bits = 1 byte + } + + // Helper class for testing unsupported types + private record TestUnsupportedComplexType(string Name, bool SubindexAccessSupported) + : ParsableComplexDataTypeDef(Name, SubindexAccessSupported) + { + public TestUnsupportedComplexType() + : this("test", true) { } + } +} diff --git a/src/Tests/IOLink.NET.Tests/IoddConverterWriterIntegrationTests.cs b/src/Tests/IOLink.NET.Tests/IoddConverterWriterIntegrationTests.cs new file mode 100644 index 0000000..66e8a02 --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/IoddConverterWriterIntegrationTests.cs @@ -0,0 +1,337 @@ +using System.Xml.Linq; +using IOLink.NET.Conversion; +using IOLink.NET.IODD; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Structure.Datatypes; +using Shouldly; + +namespace IOLink.NET.Tests; + +public class IoddConverterWriterIntegrationTests +{ + [Fact] + public void ConvertToBytes_RealDeviceProcessData_ShouldRoundTripCorrectly() + { + // Arrange + var originalData = Convert.FromBase64String("gAEDAAAAAAAAgAA="); + IODDParser parser = new(); + var device = parser.Parse( + XElement.Load("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml") + ); + var converter = new IoddConverter(); + + var pdResolver = new ProcessDataTypeResolver(device); + var convertibleType = pdResolver.ResolveProcessDataIn()!; + + // First convert from bytes to objects + var convertedObjects = + converter.Convert(convertibleType, originalData) as IEnumerable<(string, object)>; + + // Act - Convert back to bytes + var resultBytes = converter.ConvertToBytes(convertedObjects!, convertibleType); + + // Assert + resultBytes.ShouldBeEquivalentTo(originalData); + } + + [Fact] + public void ConvertToBytes_SimpleRecordData_ShouldMatchExpectedFormat() + { + // Arrange + var converter = new IoddConverter(); + var recordItem1 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("uint_1", KindOfSimpleType.UInteger, 4), + "field1", + 0, + 1 + ); + var recordItem2 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("uint_2", KindOfSimpleType.UInteger, 4), + "field2", + 4, + 1 + ); + var testRecord = new ParsableRecord( + "TestRecord", + 8, + true, + new[] { recordItem1, recordItem2 } + ); + + var inputData = new (string, object)[] + { + ("field1", 15), // 1111 in binary + ( + "field2", + 15 + ) // 1111 in binary + , + }; + + // Act + var result = converter.ConvertToBytes(inputData, testRecord); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(1); + result[0].ShouldBe((byte)0xFF); // 11111111 in binary + } + + [Fact] + public void ConvertToBytes_ComplexRecordFromIODD_ShouldHandleCorrectly() + { + // Arrange + var converter = new IoddConverter(); + var testRecord = new ParsableRecord( + "DemoRecord", + 112, + true, + new[] + { + new ParsableRecordItem( + new ParsableSimpleDatatypeDef( + "TI_VAR_Device_Temp_Device_Temp", + KindOfSimpleType.Integer, + 16 + ), + "TI_VAR_Device_Temp_Device_Temp", + 96, + 1 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef( + "TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Startup", + KindOfSimpleType.Integer, + 16 + ), + "TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Startup", + 80, + 2 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef( + "TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Startup", + KindOfSimpleType.Integer, + 16 + ), + "TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Startup", + 64, + 3 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef( + "TI_VAR_Device_Temp_Minimum_Device_Temp_Lifetime", + KindOfSimpleType.Integer, + 16 + ), + "TI_VAR_Device_Temp_Minimum_Device_Temp_Lifetime", + 48, + 4 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef( + "TI_VAR_Device_Temp_Maximum_Device_Temp_Lifetime", + KindOfSimpleType.Integer, + 16 + ), + "TI_VAR_Device_Temp_Maximum_Device_Temp_Lifetime", + 32, + 5 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef( + "TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Reset", + KindOfSimpleType.Integer, + 16 + ), + "TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Reset", + 16, + 6 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef( + "TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Reset", + KindOfSimpleType.Integer, + 16 + ), + "TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Reset", + 0, + 7 + ), + } + ); + + var inputData = new (string, object)[] + { + ("TI_VAR_Device_Temp_Device_Temp", 29), + ("TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Startup", 28), + ("TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Startup", 29), + ("TI_VAR_Device_Temp_Minimum_Device_Temp_Lifetime", 19), + ("TI_VAR_Device_Temp_Maximum_Device_Temp_Lifetime", 46), + ("TI_VAR_Device_Temp_Minimum_Device_Temp_Since_Reset", 19), + ("TI_VAR_Device_Temp_Maximum_Device_Temp_Since_Reset", 46), + }; + + // Act + var result = converter.ConvertToBytes(inputData, testRecord); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(14); // 112 bits = 14 bytes + } + + [Fact] + public void ConvertToBytes_ArrayData_ShouldHandleMultipleElements() + { + // Arrange + var converter = new IoddConverter(); + var elementType = new ParsableSimpleDatatypeDef("element", KindOfSimpleType.UInteger, 16); + var arrayType = new ParsableArray("testArray", elementType, true, 4); + var inputData = new object[] { 1000, 2000, 3000, 4000 }; + + // Act + var result = converter.ConvertToBytes(inputData, arrayType); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(8); // 4 * 16 bits = 64 bits = 8 bytes + } + + [Fact] + public void ConvertToBytes_MixedDataTypes_ShouldHandleCorrectly() + { + // Arrange + var converter = new IoddConverter(); + var testRecord = new ParsableRecord( + "MixedRecord", + 33, + true, + new[] + { + new ParsableRecordItem( + new ParsableSimpleDatatypeDef("intField", KindOfSimpleType.Integer, 16), + "intField", + 0, + 1 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef("uintField", KindOfSimpleType.UInteger, 8), + "uintField", + 16, + 2 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef("boolField", KindOfSimpleType.Boolean, 1), + "boolField", + 24, + 3 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef("smallUint", KindOfSimpleType.UInteger, 8), + "smallUint", + 25, + 4 + ), + } + ); + + var inputData = new (string, object)[] + { + ("intField", -1000), + ("uintField", 200), + ("boolField", true), + ("smallUint", 50), + }; + + // Act + var result = converter.ConvertToBytes(inputData, testRecord); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(5); // 33 bits = 5 bytes (rounded up) + } + + [Fact] + public void ConvertToBytes_FloatData_ShouldHandleCorrectly() + { + // Arrange + var converter = new IoddConverter(); + var floatType = new ParsableSimpleDatatypeDef("floatValue", KindOfSimpleType.Float, 32); + var value = 3.14159f; + + // Act + var result = converter.ConvertToBytes(value, floatType); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(4); // 32 bits = 4 bytes + } + + [Fact] + public void ConvertToBytes_StringData_ShouldHandleEncoding() + { + // Arrange + var converter = new IoddConverter(); + var stringType = new ParsableStringDef("textValue", 20, StringTEncoding.UTF8); + var value = "Test String"; + + // Act + var result = converter.ConvertToBytes(value, stringType); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(value.Length); + } + + [Fact] + public void ConvertToBytes_EdgeCaseBitLengths_ShouldHandleCorrectly() + { + // Test with odd bit lengths that don't align to byte boundaries + // Arrange + var converter = new IoddConverter(); + var testRecord = new ParsableRecord( + "EdgeCaseRecord", + 13, + true, + new[] + { + new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field1", KindOfSimpleType.UInteger, 5), + "field1", + 0, + 1 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field2", KindOfSimpleType.UInteger, 3), + "field2", + 5, + 2 + ), + new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field3", KindOfSimpleType.UInteger, 5), + "field3", + 8, + 3 + ), + } + ); + + var inputData = new (string, object)[] + { + ("field1", 31), // 5 bits: 11111 + ("field2", 7), // 3 bits: 111 + ( + "field3", + 15 + ) // 5 bits: 01111 + , + }; + + // Act + var result = converter.ConvertToBytes(inputData, testRecord); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(2); // 13 bits = 2 bytes (rounded up) + } +} diff --git a/src/Tests/IOLink.NET.Tests/IoddConverterWriterTests.cs b/src/Tests/IOLink.NET.Tests/IoddConverterWriterTests.cs new file mode 100644 index 0000000..0f00907 --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/IoddConverterWriterTests.cs @@ -0,0 +1,198 @@ +using IOLink.NET.Conversion; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Structure.Datatypes; +using Shouldly; + +namespace IOLink.NET.Tests; + +public class IoddConverterWriterTests +{ + private readonly IoddConverter _converter = new(); + + [Fact] + public void ConvertToBytes_WithSimpleType_ShouldUseScalarWriter() + { + // Arrange + var typeDef = new ParsableSimpleDatatypeDef("test", KindOfSimpleType.UInteger, 8); + var value = 42; + + // Act + var result = _converter.ConvertToBytes(value, typeDef); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(1); + result[0].ShouldBe((byte)42); + } + + [Fact] + public void ConvertToBytes_WithComplexArrayType_ShouldUseComplexWriter() + { + // Arrange + var elementType = new ParsableSimpleDatatypeDef("element", KindOfSimpleType.UInteger, 8); + var arrayType = new ParsableArray("testArray", elementType, true, 3); + var values = new object[] { 10, 20, 30 }; + + // Act + var result = _converter.ConvertToBytes(values, arrayType); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(3); + } + + [Fact] + public void ConvertToBytes_WithComplexRecordType_ShouldUseComplexWriter() + { + // Arrange + var field1 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field1", KindOfSimpleType.UInteger, 8), + "field1", + 0, + 1 + ); + var field2 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("field2", KindOfSimpleType.UInteger, 8), + "field2", + 8, + 2 + ); + + var recordType = new ParsableRecord("testRecord", 16, true, new[] { field1, field2 }); + var values = new (string key, object value)[] { ("field1", 100), ("field2", 200) }; + + // Act + var result = _converter.ConvertToBytes(values, recordType); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBe(2); + } + + [Fact] + public void ConvertToBytes_WithUnsupportedType_ShouldThrowNotImplementedException() + { + // Arrange + var unsupportedType = new TestUnsupportedDatatype(); + var value = new object(); + + // Act & Assert + var act = () => _converter.ConvertToBytes(value, unsupportedType); + Should.Throw(act); + } + + [Theory] + [InlineData(KindOfSimpleType.Integer, 16, -1000)] + [InlineData(KindOfSimpleType.UInteger, 16, 1000)] + [InlineData(KindOfSimpleType.Float, 32, 3.14f)] + [InlineData(KindOfSimpleType.Boolean, 1, true)] + public void ConvertToBytes_WithDifferentSimpleTypes_ShouldHandleCorrectly( + KindOfSimpleType type, + ushort bitLength, + object value + ) + { + // Arrange + var typeDef = new ParsableSimpleDatatypeDef("test", type, bitLength); + + // Act + var result = _converter.ConvertToBytes(value, typeDef); + + // Assert + result.ShouldNotBeNull(); + result.Length.ShouldBeGreaterThan(0); + } + + [Fact] + public void ConvertToBytes_StringType_ShouldHandleCorrectly() + { + // Arrange + var typeDef = new ParsableStringDef("test", 10, StringTEncoding.ASCII); + var value = "Hello"; + + // Act + var result = _converter.ConvertToBytes(value, typeDef); + + // Assert + result.ShouldNotBeNull(); + result.ShouldBeEquivalentTo(new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F }); + } + + [Fact] + public void ConvertToBytes_RoundTrip_ShouldProduceSameResult() + { + // Arrange + var typeDef = new ParsableSimpleDatatypeDef("test", KindOfSimpleType.Integer, 16); + var originalValue = -12345; + + // Act + var bytes = _converter.ConvertToBytes(originalValue, typeDef); + var convertedBack = _converter.Convert(typeDef, bytes); + + // Assert + convertedBack.ShouldBe(originalValue); + } + + [Fact] + public void ConvertToBytes_ComplexRoundTrip_ShouldProduceSameResult() + { + // Arrange + var field1 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("temperature", KindOfSimpleType.Integer, 16), + "temperature", + 0, + 1 + ); + var field2 = new ParsableRecordItem( + new ParsableSimpleDatatypeDef("humidity", KindOfSimpleType.UInteger, 8), + "humidity", + 16, + 2 + ); + + var recordType = new ParsableRecord("sensorData", 24, true, new[] { field1, field2 }); + var originalValues = new (string key, object value)[] + { + ("temperature", -250), + ("humidity", 65), + }; + + // Act + var bytes = _converter.ConvertToBytes(originalValues, recordType); + var convertedBack = _converter.Convert(recordType, bytes) as IEnumerable<(string, object)>; + + // Assert + convertedBack.ShouldNotBeNull(); + var resultDict = convertedBack!.ToDictionary(x => x.Item1, x => x.Item2); + resultDict["temperature"].ShouldBe(-250); + resultDict["humidity"].ShouldBe(65); + } + + [Fact] + public void ConvertToBytes_ArrayRoundTrip_ShouldProduceSameResult() + { + // Arrange + var elementType = new ParsableSimpleDatatypeDef("element", KindOfSimpleType.Integer, 16); + var arrayType = new ParsableArray("testArray", elementType, true, 3); + var originalValues = new object[] { (short)-100, (short)0, (short)100 }; + + // Act + var bytes = _converter.ConvertToBytes(originalValues, arrayType); + var convertedBack = _converter.Convert(arrayType, bytes) as IEnumerable<(string, object)>; + + // Assert + convertedBack.ShouldNotBeNull(); + var resultList = convertedBack!.Select(x => x.Item2).ToArray(); + // Use a more lenient comparison that ignores order + resultList.ShouldAllBe(x => originalValues.Contains(x)); + resultList.Length.ShouldBe(originalValues.Length); + } + + // Helper class for testing unsupported types + private record TestUnsupportedDatatype(string Name, bool SubindexAccessSupported) + : ParsableDatatype(Name, SubindexAccessSupported) + { + public TestUnsupportedDatatype() + : this("test", true) { } + } +} diff --git a/src/Tests/Conversion.Tests/IoddScalarConverterTests.cs b/src/Tests/IOLink.NET.Tests/IoddScalarConverterTests.cs similarity index 55% rename from src/Tests/Conversion.Tests/IoddScalarConverterTests.cs rename to src/Tests/IOLink.NET.Tests/IoddScalarConverterTests.cs index fd635d0..c5732f1 100644 --- a/src/Tests/Conversion.Tests/IoddScalarConverterTests.cs +++ b/src/Tests/IOLink.NET.Tests/IoddScalarConverterTests.cs @@ -1,135 +1,164 @@ -using FluentAssertions; - -using IOLinkNET.Conversion; -using IOLinkNET.IODD.Resolution; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace Conversion.Tests; - -public class IoddScalarConverterTests -{ - [Fact] - public void CanConvert4BitPositiveInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 4); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b0000_0100 }); - _ = result.Should().Be(4); - } - - [Fact] - public void CanConvert4BitNegativeInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 4); - - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b0000_1100 }); - - _ = result.Should().Be(-4); - } - - [Fact] - public void CanConvert17BitPositiveInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 17); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b00000000, 0b01101110, 0b01011010 }); - _ = result.Should().Be(28250); - } - - [Fact] - public void CanConvert17BitNegativeInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 17); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b00000001, 0b10010001, 0b10100110 }); - _ = result.Should().Be(-28250); - } - - [Fact] - public void CanConvert32BitNegativeInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 32); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b11111110, 0b01010000, 0b11110000, 0b00001100 }); - _ = result.Should().Be(-28250100); - _ = result.Should().BeOfType(); - } - - [Fact] - public void CanConvert33BitNegativeInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 33); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b0000001, 0b11111110, 0b01010000, 0b11110000, 0b00001100 }); - _ = result.Should().Be(-28250100); - _ = result.Should().BeOfType(); - } - - [Fact] - public static void CanConvert12BitUInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.UInteger, 12); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b00000000, 0b0000_0100 }); - _ = result.Should().Be(4); - _ = result.Should().BeOfType(); - } - - [Fact] - public static void CanConvert4BitUInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.UInteger, 4); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b0000_0100 }); - _ = result.Should().Be(4); - _ = result.Should().BeOfType(); - } - - [Fact] - public static void CanConvert17BitUInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.UInteger, 17); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b00000001, 0b01101110, 0b01011010 }); - _ = result.Should().Be(93786); - _ = result.Should().BeOfType(); - } - - [Fact] - public static void CanConvert48BitUInteger() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.UInteger, 48); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b00000000, 0b00000000, 0b00000000, 0b00000001, 0b01101110, 0b01011010 }); - _ = result.Should().Be(93786); - _ = result.Should().BeOfType(); - } - - [Fact] - public static void CanConvertPositiveFloat32() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Float, 32); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b00111111, 0b01000000, 0b00000000, 0b00000000 }); - _ = result.Should().Be(0.75); - _ = result.Should().BeOfType(); - } - - [Fact] - public static void CanConvertNegativeFloat32() - { - var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Float, 32); - object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b10111111, 0b01000000, 0b00000000, 0b00000000 }); - _ = result.Should().Be(-0.75); - _ = result.Should().BeOfType(); - } - - - [Fact] - public static void CanConvertAsciiString() - { - var typeDef = new ParsableStringDef("intp", 32, StringTEncoding.ASCII); - object result = IoddScalarReader.Convert(typeDef, "Hello"u8); - _ = result.Should().Be("Hello"); - _ = result.Should().BeOfType(); - } - - [Fact] - public static void CanConvertUtf8String() - { - var typeDef = new ParsableStringDef("intp", 32, StringTEncoding.UTF8); - object result = IoddScalarReader.Convert(typeDef, "Hello"u8); - _ = result.Should().Be("Hello"); - _ = result.Should().BeOfType(); - } -} \ No newline at end of file +using Shouldly; +using IOLink.NET.Conversion; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Structure.Datatypes; + +namespace IOLink.NET.Tests; + +public class IoddScalarConverterTests +{ + [Fact] + public void CanConvert4BitPositiveInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 4); + object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b0000_0100 }); + result.ShouldBe(4); + } + + [Fact] + public void CanConvert4BitNegativeInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 4); + + object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b0000_1100 }); + + result.ShouldBe(-4); + } + + [Fact] + public void CanConvert17BitPositiveInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 17); + object result = IoddScalarReader.Convert( + typeDef, + new byte[] { 0b00000000, 0b01101110, 0b01011010 } + ); + result.ShouldBe(28250); + } + + [Fact] + public void CanConvert17BitNegativeInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 17); + object result = IoddScalarReader.Convert( + typeDef, + new byte[] { 0b00000001, 0b10010001, 0b10100110 } + ); + result.ShouldBe(-28250); + } + + [Fact] + public void CanConvert32BitNegativeInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 32); + object result = IoddScalarReader.Convert( + typeDef, + new byte[] { 0b11111110, 0b01010000, 0b11110000, 0b00001100 } + ); + result.ShouldBe(-28250100); + _ = result.ShouldBeOfType(); + } + + [Fact] + public void CanConvert33BitNegativeInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 33); + object result = IoddScalarReader.Convert( + typeDef, + new byte[] { 0b0000001, 0b11111110, 0b01010000, 0b11110000, 0b00001100 } + ); + result.ShouldBe(-28250100); + _ = result.ShouldBeOfType(); + } + + [Fact] + public static void CanConvert12BitUInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.UInteger, 12); + object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b00000000, 0b0000_0100 }); + result.ShouldBe(4); + _ = result.ShouldBeOfType(); + } + + [Fact] + public static void CanConvert4BitUInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.UInteger, 4); + object result = IoddScalarReader.Convert(typeDef, new byte[] { 0b0000_0100 }); + result.ShouldBe(4); + _ = result.ShouldBeOfType(); + } + + [Fact] + public static void CanConvert17BitUInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.UInteger, 17); + object result = IoddScalarReader.Convert( + typeDef, + new byte[] { 0b00000001, 0b01101110, 0b01011010 } + ); + result.ShouldBe(93786); + _ = result.ShouldBeOfType(); + } + + [Fact] + public static void CanConvert48BitUInteger() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.UInteger, 48); + object result = IoddScalarReader.Convert( + typeDef, + new byte[] { 0b00000000, 0b00000000, 0b00000000, 0b00000001, 0b01101110, 0b01011010 } + ); + result.ShouldBe(93786); + _ = result.ShouldBeOfType(); + } + + [Fact] + public static void CanConvertPositiveFloat32() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Float, 32); + object result = IoddScalarReader.Convert( + typeDef, + new byte[] { 0b00111111, 0b01000000, 0b00000000, 0b00000000 } + ); + result.ShouldBe(0.75); + _ = result.ShouldBeOfType(); + } + + [Fact] + public static void CanConvertNegativeFloat32() + { + var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Float, 32); + object result = IoddScalarReader.Convert( + typeDef, + new byte[] { 0b10111111, 0b01000000, 0b00000000, 0b00000000 } + ); + result.ShouldBe(-0.75); + _ = result.ShouldBeOfType(); + } + + [Fact] + public static void CanConvertAsciiString() + { + var typeDef = new ParsableStringDef("intp", 32, StringTEncoding.ASCII); + object result = IoddScalarReader.Convert(typeDef, "Hello"u8); + result.ShouldBe("Hello"); + _ = result.ShouldBeOfType(); + } + + [Fact] + public static void CanConvertUtf8String() + { + var typeDef = new ParsableStringDef("intp", 32, StringTEncoding.UTF8); + object result = IoddScalarReader.Convert(typeDef, "Hello"u8); + result.ShouldBe("Hello"); + _ = result.ShouldBeOfType(); + } +} + + + + + + + diff --git a/src/Tests/Conversion.Tests/IoddScalarWriterTests.cs b/src/Tests/IOLink.NET.Tests/IoddScalarWriterTests.cs similarity index 65% rename from src/Tests/Conversion.Tests/IoddScalarWriterTests.cs rename to src/Tests/IOLink.NET.Tests/IoddScalarWriterTests.cs index d4f0a85..96f31ce 100644 --- a/src/Tests/Conversion.Tests/IoddScalarWriterTests.cs +++ b/src/Tests/IOLink.NET.Tests/IoddScalarWriterTests.cs @@ -1,27 +1,24 @@ using System.Reflection.Metadata; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Structure.Datatypes; +using Shouldly; -using FluentAssertions; - -using IOLinkNET.IODD.Resolution; -using IOLinkNET.IODD.Structure.Datatypes; - -namespace Conversion.Tests; +namespace IOLink.NET.Tests; public class IoddScalarWriterTests { [Theory] - [InlineData([4, new byte[] { 0b0000_0100 }])] - [InlineData([7, new byte[] { 0b0000_0111 }])] - [InlineData([-4, new byte[] { 0b0000_1100 }])] - [InlineData([-7, new byte[] { 0b0000_1001 }])] + [InlineData(4, new byte[] { 0b0000_0100 })] + [InlineData(7, new byte[] { 0b0000_0111 })] + [InlineData(-4, new byte[] { 0b0000_1100 })] + [InlineData(-7, new byte[] { 0b0000_1001 })] public void CanWrite4BitInteger(int value, byte[] expected) { var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 4); byte[] result = IoddScalarWriter.Write(typeDef, value); - result.Should().BeEquivalentTo(expected); + result.ShouldBeEquivalentTo(expected); } - [Theory] [InlineData(28250, new byte[] { 0b00000000, 0b01101110, 0b01011010 })] [InlineData(-28250, new byte[] { 0b00000001, 0b10010001, 0b10100110 })] @@ -29,42 +26,61 @@ public void CanConvert17BitInteger(int value, byte[] expected) { var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 17); byte[] result = IoddScalarWriter.Write(typeDef, value); - result.Should().BeEquivalentTo(expected); + result.ShouldBeEquivalentTo(expected); } - [Theory] [InlineData(-28250100, new byte[] { 0b11111110, 0b01010000, 0b11110000, 0b00001100 })] public void CanConvert32BitNegativeInteger(int value, byte[] expected) { var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 32); byte[] result = IoddScalarWriter.Write(typeDef, value); - result.Should().BeEquivalentTo(expected); + result.ShouldBeEquivalentTo(expected); } [Theory] - [InlineData(-28250100, new byte[] { 0b0000001, 0b11111110, 0b01010000, 0b11110000, 0b00001100 })] + [InlineData( + -28250100, + new byte[] { 0b0000001, 0b11111110, 0b01010000, 0b11110000, 0b00001100 } + )] public void CanConvert33BitNegativeInteger(int value, byte[] expected) { var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Integer, 33); byte[] result = IoddScalarWriter.Write(typeDef, value); - result.Should().BeEquivalentTo(expected); + result.ShouldBeEquivalentTo(expected); } [Theory] [InlineData(12, 4, new byte[] { 0b00000000, 0b0000_0100 })] [InlineData(4, 4, new byte[] { 0b0000_0100 })] [InlineData(17, 93786, new byte[] { 0b00000001, 0b01101110, 0b01011010 })] - [InlineData(48, 93786, new byte[] { 0b00000000, 0b00000000, 0b00000000, 0b00000001, 0b01101110, 0b01011010 })] - [InlineData(64, ulong.MaxValue, new byte[]{0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111 })] + [InlineData( + 48, + 93786, + new byte[] { 0b00000000, 0b00000000, 0b00000000, 0b00000001, 0b01101110, 0b01011010 } + )] + [InlineData( + 64, + ulong.MaxValue, + new byte[] + { + 0b1111_1111, + 0b1111_1111, + 0b1111_1111, + 0b1111_1111, + 0b1111_1111, + 0b1111_1111, + 0b1111_1111, + 0b1111_1111, + } + )] public static void CanConvertUInteger(ushort bitLength, ulong value, byte[] expected) { var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.UInteger, bitLength); byte[] result = IoddScalarWriter.Write(typeDef, value); - result.Should().BeEquivalentTo(expected); + result.ShouldBeEquivalentTo(expected); } - [Theory] [InlineData(0.75, new byte[] { 0b00111111, 0b01000000, 0b00000000, 0b00000000 })] [InlineData(-0.75, new byte[] { 0b10111111, 0b01000000, 0b00000000, 0b00000000 })] @@ -72,16 +88,15 @@ public static void CanConvertPositiveFloat32(float value, byte[] expected) { var typeDef = new ParsableSimpleDatatypeDef("intp", KindOfSimpleType.Float, 32); byte[] result = IoddScalarWriter.Write(typeDef, value); - result.Should().BeEquivalentTo(expected); + result.ShouldBeEquivalentTo(expected); } - [Fact] public static void CanConvertAsciiString() { var typeDef = new ParsableStringDef("intp", 32, StringTEncoding.ASCII); byte[] result = IoddScalarWriter.Write(typeDef, "Hello"); - result.Should().BeEquivalentTo(new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F }); + result.ShouldBeEquivalentTo(new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F }); } [Fact] @@ -89,6 +104,8 @@ public static void CanConvertUtf8String() { var typeDef = new ParsableStringDef("intp", 32, StringTEncoding.UTF8); byte[] result = IoddScalarWriter.Write(typeDef, "Hello😀"); - result.Should().BeEquivalentTo(new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0xF0, 0x9F, 0x98, 0x80 }); + result.ShouldBeEquivalentTo( + new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0xF0, 0x9F, 0x98, 0x80 } + ); } -} \ No newline at end of file +} diff --git a/src/Tests/IOLink.NET.Tests/MenuDataReaderTests.cs b/src/Tests/IOLink.NET.Tests/MenuDataReaderTests.cs new file mode 100644 index 0000000..0061e18 --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/MenuDataReaderTests.cs @@ -0,0 +1,224 @@ +using System.Xml.Linq; +using IOLink.NET.Conversion; +using IOLink.NET.Core.Contracts; +using IOLink.NET.Integration; +using IOLink.NET.IODD; +using IOLink.NET.IODD.Provider; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Resolution.Contracts; +using IOLink.NET.IODD.Structure; +using IOLink.NET.Visualization.Menu; +using NSubstitute; +using Shouldly; + +namespace IOLink.NET.Tests; + +public class MenuDataReaderTests +{ + [Fact] + public void CanInitializeMenuDataReader() + { + var menuDataReader = new MenuDataReader(GetSubstituteForIODDPortReader()); + menuDataReader.ShouldNotBeNull(); + } + + [Fact] + public void GetIODDRawMenuStructure_ShouldThrowIfNotInitialized() + { + var menuDataReaderAction = () => + new MenuDataReader(GetSubstituteForIODDPortReader()).GetIODDRawMenuStructure(); + + Should.Throw(menuDataReaderAction); + } + + [Fact] + public void GetReadableMenus_ShouldThrowIfNotInitialized() + { + var menuDataReaderAction = () => + new MenuDataReader(GetSubstituteForIODDPortReader()).GetReadableMenus(); + + Should.Throw(menuDataReaderAction); + } + + [Theory] + [InlineData( + 310, + 733, + "TV7105", + "ifm electronic gmbh ", + "TestData/ifm-0002DD-20230324-IODD1.1.xml" + )] + [InlineData( + 888, + 328205, + "BNI IOL-727-S51-P012", + "Balluff", + "TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml" + )] + [InlineData( + 888, + 459267, + "BCS012N", + "Balluff", + "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml" + )] + /*[InlineData(1222, 18, "CSS 01411.2-xx", "STEGO Elektrotechnik GmbH", "TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml")]*/ + public async Task CanReadMenus( + ushort vendorId, + uint deviceId, + string productId, + string vendorName, + string ioddPath + ) + { + var (_, _, masterConnection, menuDataReader) = PreparePortReader( + vendorId, + deviceId, + productId, + vendorName, + ioddPath + ); + masterConnection + .ReadProcessDataInAsync(1) + .Returns(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0 }); + await menuDataReader.InitializeForPortAsync(1); + var readableMenus = menuDataReader.GetReadableMenus(); + await readableMenus.ReadAsync(); + + readableMenus.ShouldNotBeNull(); + } + + [Theory] + [InlineData( + 310, + 733, + "TV7105", + "ifm electronic gmbh ", + "TestData/ifm-0002DD-20230324-IODD1.1.xml", + 46 + )] + [InlineData( + 888, + 328205, + "BNI IOL-727-S51-P012", + "Balluff", + "TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", + 84 + )] + [InlineData( + 888, + 459267, + "BCS012N", + "Balluff", + "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml", + 8 + )] + public async Task ProvidesRawIoddMenuStructure( + ushort vendorId, + uint deviceId, + string productId, + string vendorName, + string ioddPath, + int menuCollectionCount + ) + { + var (_, _, _, menuDataReader) = PreparePortReader( + vendorId, + deviceId, + productId, + vendorName, + ioddPath + ); + await menuDataReader.InitializeForPortAsync(1); + var rawMenuStructure = menuDataReader.GetIODDRawMenuStructure(); + + rawMenuStructure.ShouldNotBeNull(); + + rawMenuStructure.MaintenanceRoleMenuSet.IdentificationMenu.ShouldNotBeNull(); + rawMenuStructure.ObserverRoleMenuSet.IdentificationMenu.ShouldNotBeNull(); + rawMenuStructure.SpecialistRoleMenuSet.IdentificationMenu.ShouldNotBeNull(); + + rawMenuStructure.MenuCollection.Count().ShouldBe(menuCollectionCount); + } + + private static IODDPortReader GetSubstituteForIODDPortReader() + { + return Substitute.For( + Substitute.For(), + Substitute.For(), + new IoddConverter(), + Substitute.For() + ); + } + + private ( + IODDPortReader, + IDeviceDefinitionProvider, + IMasterConnection, + MenuDataReader + ) PreparePortReader( + ushort vendorId, + uint deviceId, + string productId, + string vendorName, + string ioddPath + ) + { + var ioddParser = new IODDParser(); + var device = ioddParser.Parse(XElement.Load(ioddPath)); + var ioddProvider = Substitute.For(); + ioddProvider + .GetDeviceDefinitionAsync(vendorId, deviceId, productId, Arg.Any()) + .Returns(device); + + var masterConnection = GetMasterConnectionMock(vendorId, deviceId, productId, vendorName); + var typeResolverFactory = Substitute.For(); + typeResolverFactory + .CreateParameterTypeResolver(Arg.Any()) + .Returns(d => new ParameterTypeResolver(d.Arg())); + typeResolverFactory + .CreateProcessDataTypeResolver(Arg.Any()) + .Returns(d => new ProcessDataTypeResolver(d.Arg())); + + var portReader = Substitute.For( + masterConnection, + ioddProvider, + new IoddConverter(), + typeResolverFactory + ); + var menuDataReader = new MenuDataReader(portReader); + + portReader + .ReadConvertedParameterAsync(Arg.Any(), Arg.Any()) + .Returns(string.Empty); + + return (portReader, ioddProvider, masterConnection, menuDataReader); + } + + private IMasterConnection GetMasterConnectionMock( + ushort vendorId, + uint deviceId, + string productId, + string vendorName + ) + { + var portInfo = Substitute.For(); + var deviceInfo = Substitute.For(); + deviceInfo.VendorId.Returns(vendorId); + deviceInfo.DeviceId.Returns(deviceId); + deviceInfo.ProductId.Returns(productId); + + portInfo.PortNumber.Returns((byte)1); + portInfo.Status.Returns(PortStatus.Connected | PortStatus.IOLink); + portInfo.DeviceInformation.Returns(deviceInfo); + + var masterConnection = Substitute.For(); + masterConnection.GetPortInformationAsync(1, Arg.Any()).Returns(portInfo); + + masterConnection + .ReadIndexAsync(portInfo.PortNumber, Arg.Any()) + .Returns(new byte[] { 0 }); + + return masterConnection; + } +} diff --git a/src/Tests/IOLink.NET.Tests/ParameterResolverTests.cs b/src/Tests/IOLink.NET.Tests/ParameterResolverTests.cs new file mode 100644 index 0000000..5e2f2dc --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/ParameterResolverTests.cs @@ -0,0 +1,109 @@ +using System.Xml.Linq; +using IOLink.NET.IODD; +using IOLink.NET.IODD.Resolution; +using IOLink.NET.IODD.Structure; + +namespace IOLink.NET.Tests; + +public class ParameterResolverTests +{ + readonly IODevice _iodd; + + public ParameterResolverTests() + { + IODDParser parser = new(); + _iodd = + parser.Parse( + XElement.Load("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml") + ) ?? throw new NullReferenceException(); + } + + [Fact] + public void CanResolveRecordType() + { + var parameterResolver = new ParameterTypeResolver(_iodd); + + var param = parameterResolver.GetParameter(210); + param.ShouldNotBeNull(); + param.ShouldBeOfType(); + var recordParam = param as ParsableRecord; + + recordParam!.Name.ShouldBe("V_Inversion_Record"); + recordParam!.Entries?.ShouldNotBeEmpty(); + recordParam! + .Entries?.ElementAt(0) + .ShouldBe( + new( + new ParsableSimpleDatatypeDef( + "TI_VAR_Inversion_P0P4", + KindOfSimpleType.Boolean, + 1 + ), + "TI_VAR_Inversion_P0P4", + 0, + 1 + ) + ); + recordParam! + .Entries?.Last() + .ShouldBe( + new ParsableRecordItem( + new ParsableSimpleDatatypeDef( + "TI_VAR_Inversion_P3P2", + KindOfSimpleType.Boolean, + 1 + ), + "TI_VAR_Inversion_P3P2", + 7, + 8 + ) + ); + } + + [Fact] + public void CanResolveScalarViaSubindex() + { + var parameterResolver = new ParameterTypeResolver(_iodd); + + var param = parameterResolver.GetParameter(210, 1); + param.ShouldNotBeNull(); + param.ShouldBeOfType(); + + var simpleDatatype = param as ParsableSimpleDatatypeDef; + simpleDatatype!.Datatype.ShouldBe(KindOfSimpleType.Boolean); + simpleDatatype!.Name.ShouldBe("V_Inversion_Record_1"); + } + + [Fact] + public void CanResolveScalar() + { + var parameterResolver = new ParameterTypeResolver(_iodd); + + var param = parameterResolver.GetParameter(112); + param.ShouldNotBeNull(); + param.ShouldBeOfType(); + + var simpleDatatype = param as ParsableSimpleDatatypeDef; + simpleDatatype!.Datatype.ShouldBe(KindOfSimpleType.UInteger); + simpleDatatype!.Name.ShouldBe("V_Diag_Level_Config"); + } + + [Fact] + public void CanResolveArray() + { + var parameterResolver = new ParameterTypeResolver(_iodd); + + var param = parameterResolver.GetParameter(113); + param.ShouldNotBeNull(); + param.ShouldBeOfType(); + + var arrayParam = + param as ParsableArray + ?? throw new InvalidOperationException("Did not receive an array."); + arrayParam.Name.ShouldBe("V_EventCodeSupp"); + arrayParam.Length.ShouldBe((ushort)5); + arrayParam.Type.ShouldBeOfType(); + arrayParam.Type.Datatype.ShouldBe(KindOfSimpleType.UInteger); + arrayParam!.Type.ShouldBeOfType(); + } +} diff --git a/src/Tests/IODD.Parser.Tests/ParserTest.cs b/src/Tests/IOLink.NET.Tests/ParserTest.cs similarity index 66% rename from src/Tests/IODD.Parser.Tests/ParserTest.cs rename to src/Tests/IOLink.NET.Tests/ParserTest.cs index aedf11b..a286ddd 100644 --- a/src/Tests/IODD.Parser.Tests/ParserTest.cs +++ b/src/Tests/IOLink.NET.Tests/ParserTest.cs @@ -1,77 +1,91 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD.Standard.Structure; -using IOLinkNET.IODD.Structure; - -namespace IOLinkNET.IODD.Tests; - -public class ParserTest -{ - [Theory] - [InlineData("TestData/ifm-0002DD-20230324-IODD1.1.xml", 310, 733)] - [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", 888, 328205)] - [InlineData("TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml", 888, 459267)] - [InlineData("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml", 888, 393780)] - [InlineData("TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml", 1222, 18)] - public void ShouldParseIODDDeviceIdentity(string path, ushort expectedVendorId, uint expectedDeviceId) - { - IODDParser parser = new(); - var device = parser.Parse(XElement.Load(path)); - - device.Should().NotBeNull(); - device.ProfileBody.DeviceIdentity.VendorId.Should().Be(expectedVendorId); - device.ProfileBody.DeviceIdentity.DeviceId.Should().Be(expectedDeviceId); - } - - [Theory] - [InlineData("TestData/ifm-0002DD-20230324-IODD1.1.xml", true, 46)] - [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", true, 84)] - [InlineData("TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml", true, 8)] - [InlineData("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml", true, 79)] - [InlineData("TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml", true, 26)] - public void ShouldParseIODDDeviceFunctionUserInterface(string path, bool hasMenus, int menuCollectionCount) - { - IODDParser parser = new(); - var device = parser.Parse(XElement.Load(path)); - - if (hasMenus) - { - device.ProfileBody.DeviceFunction.UserInterface.Should().NotBeNull(); - device.ProfileBody.DeviceFunction.UserInterface.MenuCollection?.Count().Should().Be(menuCollectionCount); - } - else - { - device.ProfileBody.DeviceFunction.UserInterface.Should().BeNull(); - } - } - - [Theory] - [InlineData("TestData/ifm-0002DD-20230324-IODD1.1.xml", 161)] - [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", 436)] - [InlineData("TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml", 61)] - [InlineData("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml", 268)] - [InlineData("TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml", 152)] - public void ShouldParseIODDExternalTextCollection(string path, int externalTextCollectionTextDefinitionCount) - { - IODDParser parser = new(); - var device = parser.Parse(XElement.Load(path)); - - device.ExternalTextCollection.Should().NotBeNull(); - device.ExternalTextCollection.TextDefinitions.Count().Should().Be(externalTextCollectionTextDefinitionCount); - } - - [Theory] - [InlineData("TestData/ifm-0002DD-20230324-IODD1.1.xml")] - [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml")] - [InlineData("TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml")] - [InlineData("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml")] - [InlineData("TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml")] - public void ShouldParseStandardDefinitions(string path) - { - IODDParser parser = new(); - var device = parser.Parse(XElement.Load(path)); - - device.StandardDatatypeCollection.Should().NotBeNull(); - device.StandardDatatypeCollection.Should().HaveCount(2); - } -} \ No newline at end of file +using System.Xml.Linq; +using IOLink.NET.IODD.Standard.Structure; +using IOLink.NET.IODD.Structure; + +namespace IOLink.NET.Tests; + +public class ParserTest +{ + [Theory] + [InlineData("TestData/ifm-0002DD-20230324-IODD1.1.xml", 310, 733)] + [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", 888, 328205)] + [InlineData("TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml", 888, 459267)] + [InlineData("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml", 888, 393780)] + [InlineData("TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml", 1222, 18)] + public void ShouldParseIODDDeviceIdentity( + string path, + ushort expectedVendorId, + uint expectedDeviceId + ) + { + IODDParser parser = new(); + var device = parser.Parse(XElement.Load(path)); + + device.ShouldNotBeNull(); + device.ProfileBody.DeviceIdentity.VendorId.ShouldBe(expectedVendorId); + device.ProfileBody.DeviceIdentity.DeviceId.ShouldBe(expectedDeviceId); + } + + [Theory] + [InlineData("TestData/ifm-0002DD-20230324-IODD1.1.xml", true, 46)] + [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", true, 84)] + [InlineData("TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml", true, 8)] + [InlineData("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml", true, 79)] + [InlineData("TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml", true, 26)] + public void ShouldParseIODDDeviceFunctionUserInterface( + string path, + bool hasMenus, + int menuCollectionCount + ) + { + IODDParser parser = new(); + var device = parser.Parse(XElement.Load(path)); + + if (hasMenus) + { + device.ProfileBody.DeviceFunction.UserInterface.ShouldNotBeNull(); + device + .ProfileBody.DeviceFunction.UserInterface.MenuCollection?.Count() + .ShouldBe(menuCollectionCount); + } + else + { + device.ProfileBody.DeviceFunction.UserInterface.ShouldBeNull(); + } + } + + [Theory] + [InlineData("TestData/ifm-0002DD-20230324-IODD1.1.xml", 161)] + [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", 436)] + [InlineData("TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml", 61)] + [InlineData("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml", 268)] + [InlineData("TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml", 152)] + public void ShouldParseIODDExternalTextCollection( + string path, + int externalTextCollectionTextDefinitionCount + ) + { + IODDParser parser = new(); + var device = parser.Parse(XElement.Load(path)); + + device.ExternalTextCollection.ShouldNotBeNull(); + device + .ExternalTextCollection.TextDefinitions.Count() + .ShouldBe(externalTextCollectionTextDefinitionCount); + } + + [Theory] + [InlineData("TestData/ifm-0002DD-20230324-IODD1.1.xml")] + [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml")] + [InlineData("TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml")] + [InlineData("TestData/Balluff-BISM4A308240107S4-CCM-20210928-IODD1.1.xml")] + [InlineData("TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml")] + public void ShouldParseStandardDefinitions(string path) + { + IODDParser parser = new(); + var device = parser.Parse(XElement.Load(path)); + + device.StandardDatatypeCollection.ShouldNotBeNull(); + device.StandardDatatypeCollection.Count().ShouldBe(2); + } +} diff --git a/src/Tests/IOLink.NET.Tests/PortReaderBuilderTests.cs b/src/Tests/IOLink.NET.Tests/PortReaderBuilderTests.cs new file mode 100644 index 0000000..a7ce1a8 --- /dev/null +++ b/src/Tests/IOLink.NET.Tests/PortReaderBuilderTests.cs @@ -0,0 +1,86 @@ +using IOLink.NET.Conversion; +using IOLink.NET.Core.Contracts; +using IOLink.NET.Integration; +using IOLink.NET.IODD.Provider; +using IOLink.NET.IODD.Resolution.Contracts; +using NSubstitute; +using Shouldly; + +namespace IOLink.NET.Tests; + +public class PortReaderBuilderTests +{ + [Fact] + public void ShouldThrowExceptionWhenNecessaryParametersMissing() + { + var builderAction = () => PortReaderBuilder.NewPortReader().Build(); + + Should.Throw(builderAction); + } + + [Fact] + public void ShouldThrowExceptionWhenMasterConnectionIsMissing() + { + var builderAction = () => + PortReaderBuilder + .NewPortReader() + .WithDeviceDefinitionProvider(Substitute.For()) + .Build(); + + Should.Throw(builderAction); + } + + [Fact] + public void ShouldThrowExceptionWhenDeviceDefinitionProviderIsMissing() + { + var builderAction = () => + PortReaderBuilder + .NewPortReader() + .WithMasterConnection(Substitute.For()) + .Build(); + + Should.Throw(builderAction); + } + + [Fact] + public void ShouldThrowExceptionWhenIoddDataConverterIsMissing() + { + var builderAction = () => + PortReaderBuilder + .NewPortReader() + .WithMasterConnection(Substitute.For()) + .WithDeviceDefinitionProvider(Substitute.For()) + .Build(); + + Should.Throw(builderAction); + } + + [Fact] + public void ShouldThrowExceptionWhenTypeResolverFactoryIsMissing() + { + var builderAction = () => + PortReaderBuilder + .NewPortReader() + .WithMasterConnection(Substitute.For()) + .WithDeviceDefinitionProvider(Substitute.For()) + .WithIoddDataConverter(Substitute.For()) + .Build(); + + Should.Throw(builderAction); + } + + [Fact] + public void ShouldBuildPortReader() + { + var builderAction = () => + PortReaderBuilder + .NewPortReader() + .WithMasterConnection(Substitute.For()) + .WithDeviceDefinitionProvider(Substitute.For()) + .WithIoddDataConverter(Substitute.For()) + .WithTypeResolverFactory(Substitute.For()) + .Build(); + + Should.NotThrow(builderAction); + } +} diff --git a/src/Tests/IODD.Resolution.Tests/ProcessDataResolverTests.cs b/src/Tests/IOLink.NET.Tests/ProcessDataResolverTests.cs similarity index 64% rename from src/Tests/IODD.Resolution.Tests/ProcessDataResolverTests.cs rename to src/Tests/IOLink.NET.Tests/ProcessDataResolverTests.cs index 6b8b38b..a82a7c7 100644 --- a/src/Tests/IODD.Resolution.Tests/ProcessDataResolverTests.cs +++ b/src/Tests/IOLink.NET.Tests/ProcessDataResolverTests.cs @@ -1,24 +1,30 @@ -using System.Xml.Linq; - -using IOLinkNET.IODD; -using IOLinkNET.IODD.Resolution; - -namespace IODD.Resolution.Tests; - -public class ProcessDataResolverTests -{ - [Theory] - [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", false, null)] - public void CanResolveProcessData(string iodd, bool hasCondition, int? condition) - { - var parser = new IODDParser(); - var device = parser.Parse(XElement.Load(iodd)); - var pdResolver = new ProcessDataTypeResolver(device); - - pdResolver.HasCondition().Should().Be(hasCondition); - - var parsablePdIn = pdResolver.ResolveProcessDataIn(condition); - parsablePdIn.Should().NotBeNull(); - parsablePdIn.Should().BeOfType(); - } -} \ No newline at end of file +using System.Xml.Linq; +using IOLink.NET.IODD; +using IOLink.NET.IODD.Resolution; + +namespace IOLink.NET.Tests; + +public class ProcessDataResolverTests +{ + [Theory] + [InlineData("TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", false, null)] + public void CanResolveProcessData(string iodd, bool hasCondition, int? condition) + { + var parser = new IODDParser(); + var device = parser.Parse(XElement.Load(iodd)); + var pdResolver = new ProcessDataTypeResolver(device); + + pdResolver.HasCondition().ShouldBe(hasCondition); + + var parsablePdIn = pdResolver.ResolveProcessDataIn(condition); + parsablePdIn.ShouldNotBeNull(); + parsablePdIn.ShouldBeOfType(); + } +} + + + + + + + diff --git a/src/Tests/Integration.Tests/GlobalUsings.cs b/src/Tests/Integration.Tests/GlobalUsings.cs deleted file mode 100644 index 8c927eb..0000000 --- a/src/Tests/Integration.Tests/GlobalUsings.cs +++ /dev/null @@ -1 +0,0 @@ -global using Xunit; \ No newline at end of file diff --git a/src/Tests/Integration.Tests/IODDPortReaderTests.cs b/src/Tests/Integration.Tests/IODDPortReaderTests.cs deleted file mode 100644 index cb2aadf..0000000 --- a/src/Tests/Integration.Tests/IODDPortReaderTests.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System.Xml.Linq; - -using FluentAssertions; - -using IOLinkNET.Conversion; -using IOLinkNET.Device.Contract; -using IOLinkNET.Integration; -using IOLinkNET.IODD; -using IOLinkNET.IODD.Provider; -using IOLinkNET.IODD.Resolution; -using IOLinkNET.IODD.Resolution.Contracts; -using IOLinkNET.IODD.Structure; - -using NSubstitute; - -namespace Integration.Tests; - -public class IODDPortReaderTests -{ - [Theory] - [InlineData(888, 328205, "BNI IOL-727-S51-P012", "Balluff", "TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml")] - [InlineData(888, 459267, "BCS012N", "Balluff", "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml")] - public async Task CanInitializeForPortAsync(ushort vendorId, uint deviceId, string productId, string vendorName, string ioddPath) - { - var (portReader, ioddProvider, masterConnection) = PreparePortReader(vendorId, deviceId, productId, vendorName, ioddPath); - - await portReader.InitializeForPortAsync(1); - - await ioddProvider.Received().GetDeviceDefinitionAsync(vendorId, deviceId, productId, Arg.Any()); - await masterConnection.Received().GetPortInformationAsync(1, Arg.Any()); - } - - [Fact] - public async Task ShouldThrowIfPortIsNotInIOLinkModeAsync() - { - var (portReader, _, masterConnection) = PreparePortReader(888, 459267, "BCS012N", "Balluff", "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml"); - var portInfo = Substitute.For(); - portInfo.Status.Returns(PortStatus.Connected); - masterConnection.GetPortInformationAsync(1, Arg.Any()).Returns(portInfo); - - var initTask = () => portReader.InitializeForPortAsync(1); - - await initTask.Should().ThrowAsync(); - } - - [Fact] - public async Task ShouldThrowIfNoDeviceInfoAsync() - { - var (portReader, _, masterConnection) = PreparePortReader(888, 459267, "BCS012N", "Balluff", "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml"); - var portInfo = Substitute.For(); - portInfo.Status.Returns(PortStatus.Connected | PortStatus.IOLink); - portInfo.DeviceInformation.Returns(null as IDeviceInformation); - - masterConnection.GetPortInformationAsync(1, Arg.Any()).Returns(portInfo); - - var initTask = () => portReader.InitializeForPortAsync(1); - - await initTask.Should().ThrowAsync(); - } - - [Fact] - public async Task ShouldThrowIfUninitializedParameterReadAsync() - { - var (portReader, _, _) = PreparePortReader(888, 459267, "BCS012N", "Balluff", "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml"); - var readParamTask = () => portReader.ReadConvertedParameterAsync(58, 0); - - await readParamTask.Should().ThrowAsync(); - } - - [Fact] - public async Task ShouldThrowIfUninitializedProcessDataInReadAsync() - { - var (portReader, _, _) = PreparePortReader(888, 459267, "BCS012N", "Balluff", "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml"); - var readParamTask = portReader.ReadConvertedProcessDataInAsync; - - await readParamTask.Should().ThrowAsync(); - } - - [Fact] - public async Task ShouldThrowIfUninitializedProcessDataOutReadAsync() - { - var (portReader, _, _) = PreparePortReader(888, 459267, "BCS012N", "Balluff", "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml"); - var readParamTask = portReader.ReadConvertedProcessDataOutAsync; - - await readParamTask.Should().ThrowAsync(); - } - - [Fact] - public async Task CanReadConvertedProcessDataInWithConditionAsync() - { - var (portReader, _, masterConnection) = PreparePortReader(1222, 18, "CSS 01411.2-xx", "STEGO", "TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml"); - masterConnection.ReadIndexAsync(1, 66).Returns(new byte[] { 0x00 }); - masterConnection.ReadProcessDataInAsync(1).Returns(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0 }); - await portReader.InitializeForPortAsync(1); - - var pd = (await portReader.ReadConvertedProcessDataInAsync()) as IEnumerable<(string, object)>; - pd.Should().ContainEquivalentOf(("TN_PDI_Feuchte", 0)); - } - - [Theory] - [InlineData(888, 459267, "BCS012N", "Balluff", "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml")] - public async Task CanReadConvertedParameterAsync(ushort vendorId, uint deviceId, string productId, string vendorName, string ioddPath) - { - var (portReader, _, masterConnection) = PreparePortReader(vendorId, deviceId, productId, vendorName, ioddPath); - masterConnection.ReadIndexAsync(1, 58).Returns(new byte[] { 0x00, 0x00, 0x00, 0x04 }); - await portReader.InitializeForPortAsync(1); - - var converted = await portReader.ReadConvertedParameterAsync(58, 0); - converted.Should().Be(4); - } - - private (IODDPortReader, IDeviceDefinitionProvider, IMasterConnection) PreparePortReader(ushort vendorId, uint deviceId, string productId, string vendorName, string ioddPath) - { - var ioddParser = new IODDParser(); - var device = ioddParser.Parse(XElement.Load(ioddPath)); - var ioddProvider = Substitute.For(); - ioddProvider.GetDeviceDefinitionAsync(vendorId, deviceId, productId, Arg.Any()) - .Returns(device); - - var masterConnection = GetMasterConnectionMock(vendorId, deviceId, productId, vendorName); - var typeResolverFactory = Substitute.For(); - typeResolverFactory.CreateParameterTypeResolver(Arg.Any()).Returns(d => new ParameterTypeResolver(d.Arg())); - typeResolverFactory.CreateProcessDataTypeResolver(Arg.Any()).Returns(d => new ProcessDataTypeResolver(d.Arg())); - - var portReader = new IODDPortReader(masterConnection, ioddProvider, new IoddConverter(), typeResolverFactory); - - return (portReader, ioddProvider, masterConnection); - } - - private IMasterConnection GetMasterConnectionMock(ushort vendorId, uint deviceId, string productId, string vendorName) - { - var portInfo = Substitute.For(); - var deviceInfo = Substitute.For(); - deviceInfo.VendorId.Returns(vendorId); - deviceInfo.DeviceId.Returns(deviceId); - deviceInfo.ProductId.Returns(productId); - - portInfo.PortNumber.Returns((byte)1); - portInfo.Status.Returns(PortStatus.Connected | PortStatus.IOLink); - portInfo.DeviceInformation.Returns(deviceInfo); - - var masterConnection = Substitute.For(); - masterConnection.GetPortInformationAsync(1, Arg.Any()) - .Returns(portInfo); - - return masterConnection; - } -} \ No newline at end of file diff --git a/src/Tests/Integration.Tests/Integration.Tests.csproj b/src/Tests/Integration.Tests/Integration.Tests.csproj deleted file mode 100644 index bda2b1c..0000000 --- a/src/Tests/Integration.Tests/Integration.Tests.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - false - true - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - TestData\%(RecursiveDir)/%(FileName)%(Extension) - Always - - - - - - - - - - diff --git a/src/Tests/Integration.Tests/PortReaderBuilderTests.cs b/src/Tests/Integration.Tests/PortReaderBuilderTests.cs deleted file mode 100644 index 6ea8b1c..0000000 --- a/src/Tests/Integration.Tests/PortReaderBuilderTests.cs +++ /dev/null @@ -1,78 +0,0 @@ -using FluentAssertions; - -using IOLinkNET.Conversion; -using IOLinkNET.Device.Contract; -using IOLinkNET.Integration; -using IOLinkNET.IODD.Provider; -using IOLinkNET.IODD.Resolution.Contracts; - -using NSubstitute; - -namespace Integration.Tests; - -public class PortReaderBuilderTests -{ - [Fact] - public void ShouldThrowExceptionWhenNecessaryParametersMissing() - { - var builderAction = () => PortReaderBuilder.NewPortReader().Build(); - - builderAction.Should().Throw(); - } - - [Fact] - public void ShouldThrowExceptionWhenMasterConnectionIsMissing() - { - var builderAction = () => PortReaderBuilder.NewPortReader() - .WithDeviceDefinitionProvider(Substitute.For()) - .Build(); - - builderAction.Should().Throw(); - } - - [Fact] - public void ShouldThrowExceptionWhenDeviceDefinitionProviderIsMissing() - { - var builderAction = () => PortReaderBuilder.NewPortReader() - .WithMasterConnection(Substitute.For()) - .Build(); - - builderAction.Should().Throw(); - } - - [Fact] - public void ShouldThrowExceptionWhenIoddDataConverterIsMissing() - { - var builderAction = () => PortReaderBuilder.NewPortReader() - .WithMasterConnection(Substitute.For()) - .WithDeviceDefinitionProvider(Substitute.For()) - .Build(); - - builderAction.Should().Throw(); - } - - [Fact] - public void ShouldThrowExceptionWhenTypeResolverFactoryIsMissing() - { - var builderAction = () => PortReaderBuilder.NewPortReader() - .WithMasterConnection(Substitute.For()) - .WithDeviceDefinitionProvider(Substitute.For()) - .WithIoddDataConverter(Substitute.For()) - .Build(); - - builderAction.Should().Throw(); - } - - [Fact] - public void ShouldBuildPortReader() - { - var builderAction = () => PortReaderBuilder.NewPortReader() - .WithMasterConnection(Substitute.For()) - .WithDeviceDefinitionProvider(Substitute.For()) - .WithIoddDataConverter(Substitute.For()) - .WithTypeResolverFactory(Substitute.For()) - .Build(); - - builderAction.Should().NotThrow(); - } -} \ No newline at end of file diff --git a/src/Tests/Vendors.Ifm/Configuration/MasterConfiguration.cs b/src/Tests/Vendors.Ifm/Configuration/MasterConfiguration.cs index 19f8301..179b624 100644 --- a/src/Tests/Vendors.Ifm/Configuration/MasterConfiguration.cs +++ b/src/Tests/Vendors.Ifm/Configuration/MasterConfiguration.cs @@ -1,6 +1,13 @@ -namespace Vendors.Ifm.Configuration; +namespace Vendors.Ifm.Configuration; public static class MasterConfiguration { public static readonly string IP = "192.168.2.194"; } + + + + + + + diff --git a/src/Tests/Vendors.Ifm/Data/IfmIoTCoreRequestsTests.cs b/src/Tests/Vendors.Ifm/Data/IfmIoTCoreRequestsTests.cs new file mode 100644 index 0000000..95495d8 --- /dev/null +++ b/src/Tests/Vendors.Ifm/Data/IfmIoTCoreRequestsTests.cs @@ -0,0 +1,171 @@ +namespace IOLink.NET.Vendors.Ifm.Tests.Data; + +public class IfmIoTCoreRequestsTests +{ + [Fact] + public void IfmIoTCoreServiceRequestBase_Constructor_SetsPropertiesCorrectly() + { + // Arrange + var adr = "test-address"; + var code = "test-code"; + var cid = 42; + + // Act + var request = new IfmIoTCoreServiceRequestBase(adr, code, cid); + + // Assert + request.Adr.ShouldBe(adr); + request.Code.ShouldBe(code); + request.Cid.ShouldBe(cid); + } + + [Fact] + public void IfmIoTCoreServiceRequestBase_DefaultValues_AreCorrect() + { + // Arrange + var adr = "test-address"; + + // Act + var request = new IfmIoTCoreServiceRequestBase(adr); + + // Assert + request.Adr.ShouldBe(adr); + request.Code.ShouldBe("request"); + request.Cid.ShouldBe(1337); + } + + [Fact] + public void IfmIoTCoreServiceParameterizedRequest_Constructor_SetsPropertiesCorrectly() + { + // Arrange + var adr = "test-address"; + var data = "test-data"; + var code = "custom-code"; + var cid = 999; + + // Act + var request = new IfmIoTCoreServiceParameterizedRequest(adr, data, code, cid); + + // Assert + request.Adr.ShouldBe(adr); + request.Data.ShouldBe(data); + request.Code.ShouldBe(code); + request.Cid.ShouldBe(cid); + } + + [Fact] + public void IfmIoTReadAcyclicRequest_Constructor_SetsCorrectAddress() + { + // Arrange + var port = 3; + var index = 0x1234; + var subindex = 0x56; + + // Act + var request = new IfmIoTReadAcyclicRequest(port, index, subindex); + + // Assert + request.Adr.ShouldBe("iolinkmaster/port[3]/iolinkdevice/iolreadacyclic"); + request.Data.ShouldNotBeNull(); + request.Data.index.ShouldBe(index); + request.Data.subindex.ShouldBe(subindex); + } + + [Fact] + public void IfmIoTReadPdInRequest_Constructor_SetsCorrectAddress() + { + // Arrange + var port = 5; + + // Act + var request = new IfmIoTReadPdInRequest(port); + + // Assert + request.Adr.ShouldBe("iolinkmaster/port[5]/iolinkdevice/pdin/getdata"); + } + + [Fact] + public void IfmIoTReadPdOutRequest_Constructor_SetsCorrectAddress() + { + // Arrange + var port = 7; + + // Act + var request = new IfmIoTReadPdOutRequest(port); + + // Assert + request.Adr.ShouldBe("iolinkmaster/port[7]/iolinkdevice/pdout/getdata"); + } + + [Fact] + public void IfmIoTGetDataMultiRequest_Constructor_SetsCorrectProperties() + { + // Arrange + var paths = new[] { "path1", "path2", "path3" }; + + // Act + var request = new IfmIoTGetDataMultiRequest(paths); + + // Assert + request.Adr.ShouldBe("GetDataMulti"); + request.Data.ShouldNotBeNull(); + request.Data.Datatosend.ShouldBe(paths); + } + + [Fact] + public void IfmIoTGetPortTreeRequest_Constructor_SetsCorrectProperties() + { + // Act + var request = new IfmIoTGetPortTreeRequest(); + + // Assert + request.Adr.ShouldBe("gettree"); + request.Data.ShouldNotBeNull(); + request.Data.Adr.ShouldBe("iolinkmaster/"); + request.Data.Level.ShouldBe(1); + } + + [Theory] + [InlineData(9, 0x01)] // Test with the expectedIndex parameter + [InlineData(0xFFFF, 0xFF)] + [InlineData(0, 0)] + public void IfmIoTAcyclicParameters_Constructor_SetsPropertiesCorrectly( + int expectedIndex, + int? subindex + ) + { + // Act + var parameters = new IfmIoTAcyclicParameters(expectedIndex, subindex); + + // Assert + parameters.index.ShouldBe(expectedIndex); + parameters.subindex.ShouldBe(subindex); + } + + [Fact] + public void IfmIoTGetDataMultiParameters_Constructor_SetsPropertiesCorrectly() + { + // Arrange + var datatosend = new[] { "data1", "data2", "data3" }; + + // Act + var parameters = new IfmIoTGetDataMultiParameters(datatosend); + + // Assert + parameters.Datatosend.ShouldBe(datatosend); + } + + [Theory] + [InlineData("test-address", 2)] + [InlineData(null, null)] + [InlineData("", 0)] + public void IfmIoTGetTreeParameters_Constructor_SetsPropertiesCorrectly(string? adr, int? level) + { + // Act + var parameters = new IfmIoTGetTreeParameters(adr, level); + + // Assert + parameters.Adr.ShouldBe(adr); + parameters.Level.ShouldBe(level); + } +} diff --git a/src/Tests/Vendors.Ifm/Data/IfmIoTCoreResponsesTests.cs b/src/Tests/Vendors.Ifm/Data/IfmIoTCoreResponsesTests.cs new file mode 100644 index 0000000..841f315 --- /dev/null +++ b/src/Tests/Vendors.Ifm/Data/IfmIoTCoreResponsesTests.cs @@ -0,0 +1,197 @@ +using System.Text.Json.Nodes; + +namespace IOLink.NET.Vendors.Ifm.Tests.Data; + +public class IfmIoTCoreResponsesTests +{ + [Fact] + public void IfmIoTCoreResponseBase_Constructor_SetsPropertiesCorrectly() + { + // Arrange + var data = "test-data"; + var cid = 123; + var code = 456; + + // Act + var response = new IfmIoTCoreResponseBase(data, cid, code); + + // Assert + response.Data.ShouldBe(data); + response.Cid.ShouldBe(cid); + response.Code.ShouldBe(code); + } + + [Fact] + public void IfmIoTCoreValueWrapper_Constructor_SetsValueCorrectly() + { + // Arrange + var value = "wrapped-value"; + + // Act + var wrapper = new IfmIoTCoreValueWrapper(value); + + // Assert + wrapper.Value.ShouldBe(value); + } + + [Fact] + public void IfmIoTCoreScalarResponse_Constructor_SetsPropertiesCorrectly() + { + // Arrange + var wrapper = new IfmIoTCoreValueWrapper("test-value"); + var cid = 789; + var code = 200; + + // Act + var response = new IfmIoTCoreScalarResponse(wrapper, cid, code); + + // Assert + response.Data.ShouldBe(wrapper); + response.Cid.ShouldBe(cid); + response.Code.ShouldBe(code); + } + + [Fact] + public void IfmIoTCoreComplexResponse_Constructor_SetsPropertiesCorrectly() + { + // Arrange + var data = new Dictionary { { "key1", 1 }, { "key2", 2 } }; + var cid = 999; + var code = 201; + + // Act + var response = new IfmIoTCoreComplexResponse>(data, cid, code); + + // Assert + response.Data.ShouldBe(data); + response.Cid.ShouldBe(cid); + response.Code.ShouldBe(code); + } + + [Fact] + public void IfmIoTCoreGetDataMultiEntry_Constructor_SetsPropertiesCorrectly() + { + // Arrange + var code = 100; + var jsonValue = JsonValue.Create("test-json-value"); + + // Act + var entry = new IfmIoTCoreGetDataMultiEntry(code, jsonValue!); + + // Assert + entry.Code.ShouldBe(code); + entry.Data.ShouldBe(jsonValue); + } + + [Fact] + public void IfmIoTCorePortTreeResponse_Constructor_SetsPropertiesCorrectly() + { + // Arrange + var treeStructure = new IfmIoTCoreTreeStructure(null, "root"); + var cid = 555; + var code = 202; + + // Act + var response = new IfmIoTCorePortTreeResponse(treeStructure, cid, code); + + // Assert + response.Data.ShouldBe(treeStructure); + response.Cid.ShouldBe(cid); + response.Code.ShouldBe(code); + } + + [Fact] + public void IfmIoTCoreTreeStructure_Constructor_WithoutSubs_SetsPropertiesCorrectly() + { + // Arrange + var identifier = "leaf-node"; + + // Act + var structure = new IfmIoTCoreTreeStructure(null, identifier); + + // Assert + structure.Subs.ShouldBeNull(); + structure.Identifier.ShouldBe(identifier); + } + + [Fact] + public void IfmIoTCoreTreeStructure_Constructor_WithSubs_SetsPropertiesCorrectly() + { + // Arrange + var child1 = new IfmIoTCoreTreeStructure(null, "child1"); + var child2 = new IfmIoTCoreTreeStructure(null, "child2"); + var subs = new[] { child1, child2 }; + var identifier = "parent-node"; + + // Act + var structure = new IfmIoTCoreTreeStructure(subs, identifier); + + // Assert + structure.Subs.ShouldBe(subs); + structure.Subs!.Count().ShouldBe(2); + structure.Identifier.ShouldBe(identifier); + } + + [Fact] + public void IfmIoTCoreTreeStructure_NestedStructure_WorksCorrectly() + { + // Arrange + var grandChild = new IfmIoTCoreTreeStructure(null, "grandchild"); + var child = new IfmIoTCoreTreeStructure(new[] { grandChild }, "child"); + var root = new IfmIoTCoreTreeStructure(new[] { child }, "root"); + + // Act & Assert + root.Identifier.ShouldBe("root"); + root.Subs.ShouldNotBeNull(); + root.Subs!.First().Identifier.ShouldBe("child"); + root.Subs.First().Subs.ShouldNotBeNull(); + root.Subs.First().Subs!.First().Identifier.ShouldBe("grandchild"); + root.Subs.First().Subs!.First().Subs.ShouldBeNull(); + } + + [Theory] + [InlineData(42)] + [InlineData("string-value")] + [InlineData(true)] + public void IfmIoTCoreValueWrapper_GenericTypes_WorkCorrectly(T value) + { + // Act + var wrapper = new IfmIoTCoreValueWrapper(value); + + // Assert + wrapper.Value.ShouldBe(value); + } + + [Fact] + public void IfmIoTCoreScalarResponse_InheritsFromResponseBase() + { + // Arrange + var wrapper = new IfmIoTCoreValueWrapper(42); + var response = new IfmIoTCoreScalarResponse(wrapper, 1, 2); + + // Act & Assert + response.ShouldBeAssignableTo>>(); + } + + [Fact] + public void IfmIoTCoreComplexResponse_InheritsFromResponseBase() + { + // Arrange + var data = new List { "item1", "item2" }; + var response = new IfmIoTCoreComplexResponse>(data, 1, 2); + + // Act & Assert + response.ShouldBeAssignableTo>>(); + } + + [Fact] + public void IfmIoTCorePortTreeResponse_InheritsFromComplexResponse() + { + // Arrange + var treeStructure = new IfmIoTCoreTreeStructure(null, "test"); + var response = new IfmIoTCorePortTreeResponse(treeStructure, 1, 2); + + // Act & Assert + response.ShouldBeAssignableTo>(); + } +} diff --git a/src/Tests/Vendors.Ifm/GlobalUsings.cs b/src/Tests/Vendors.Ifm/GlobalUsings.cs index 2af8a54..ee88cb0 100644 --- a/src/Tests/Vendors.Ifm/GlobalUsings.cs +++ b/src/Tests/Vendors.Ifm/GlobalUsings.cs @@ -1,2 +1,9 @@ +global using System.Reflection; +global using System.Text.Json; +global using IOLink.NET.Core.Contracts; +global using IOLink.NET.Core.Models; +global using IOLink.NET.Vendors.Ifm; +global using IOLink.NET.Vendors.Ifm.Data; +global using NSubstitute; +global using Shouldly; global using Xunit; - diff --git a/src/Tests/Vendors.Ifm/IIfmIoTCoreClientInterfaceTests.cs b/src/Tests/Vendors.Ifm/IIfmIoTCoreClientInterfaceTests.cs new file mode 100644 index 0000000..270dfb7 --- /dev/null +++ b/src/Tests/Vendors.Ifm/IIfmIoTCoreClientInterfaceTests.cs @@ -0,0 +1,242 @@ +using Refit; + +namespace IOLink.NET.Vendors.Ifm.Tests; + +public class IIfmIoTCoreClientInterfaceTests +{ + [Fact] + public void IIfmIoTCoreClient_IsPublicInterface() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + + // Act & Assert + interfaceType.IsInterface.ShouldBeTrue(); + interfaceType.IsPublic.ShouldBeTrue(); + } + + [Fact] + public void GetMasterDeviceTagAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var method = interfaceType.GetMethod(nameof(IIfmIoTCoreClient.GetMasterDeviceTagAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task>)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(1); + parameters[0].ParameterType.ShouldBe(typeof(CancellationToken)); + } + + [Fact] + public void GetMasterDeviceTagAsync_HasGetAttribute() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var method = interfaceType.GetMethod(nameof(IIfmIoTCoreClient.GetMasterDeviceTagAsync)); + + // Act + var getAttribute = method!.GetCustomAttribute(); + + // Assert + getAttribute.ShouldNotBeNull(); + getAttribute!.Path.ShouldBe("/devicetag/applicationtag/getdata"); + } + + [Fact] + public void GetDeviceAcyclicDataAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var method = interfaceType.GetMethod(nameof(IIfmIoTCoreClient.GetDeviceAcyclicDataAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task>)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(2); + parameters[0].ParameterType.ShouldBe(typeof(IfmIoTReadAcyclicRequest)); + parameters[0].Name.ShouldBe("request"); + parameters[1].ParameterType.ShouldBe(typeof(CancellationToken)); + parameters[1].Name.ShouldBe("cancellationToken"); + } + + [Fact] + public void GetDeviceAcyclicDataAsync_HasPostAttribute() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var method = interfaceType.GetMethod(nameof(IIfmIoTCoreClient.GetDeviceAcyclicDataAsync)); + + // Act + var postAttribute = method!.GetCustomAttribute(); + + // Assert + postAttribute.ShouldNotBeNull(); + postAttribute!.Path.ShouldBe(""); + } + + [Fact] + public void GetDevicePdinDataAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var method = interfaceType.GetMethod(nameof(IIfmIoTCoreClient.GetDevicePdinDataAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task>)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(2); + parameters[0].ParameterType.ShouldBe(typeof(IfmIoTReadPdInRequest)); + parameters[1].ParameterType.ShouldBe(typeof(CancellationToken)); + } + + [Fact] + public void GetDevicePdoutDataAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var method = interfaceType.GetMethod(nameof(IIfmIoTCoreClient.GetDevicePdoutDataAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task>)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(2); + parameters[0].ParameterType.ShouldBe(typeof(IfmIoTReadPdOutRequest)); + parameters[1].ParameterType.ShouldBe(typeof(CancellationToken)); + } + + [Fact] + public void GetDataMultiAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var method = interfaceType.GetMethod(nameof(IIfmIoTCoreClient.GetDataMultiAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe( + typeof(Task>>) + ); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(2); + parameters[0].ParameterType.ShouldBe(typeof(IfmIoTGetDataMultiRequest)); + parameters[1].ParameterType.ShouldBe(typeof(CancellationToken)); + } + + [Fact] + public void GetPortTreeAsync_HasCorrectSignature() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var method = interfaceType.GetMethod(nameof(IIfmIoTCoreClient.GetPortTreeAsync)); + + // Act & Assert + method.ShouldNotBeNull(); + method!.ReturnType.ShouldBe(typeof(Task)); + + var parameters = method.GetParameters(); + parameters.Length.ShouldBe(2); + parameters[0].ParameterType.ShouldBe(typeof(IfmIoTGetPortTreeRequest)); + parameters[1].ParameterType.ShouldBe(typeof(CancellationToken)); + } + + [Fact] + public void AllAsyncMethods_HavePostAttribute() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var postMethods = new[] + { + nameof(IIfmIoTCoreClient.GetDeviceAcyclicDataAsync), + nameof(IIfmIoTCoreClient.GetDevicePdinDataAsync), + nameof(IIfmIoTCoreClient.GetDevicePdoutDataAsync), + nameof(IIfmIoTCoreClient.GetDataMultiAsync), + nameof(IIfmIoTCoreClient.GetPortTreeAsync), + }; + + // Act & Assert + foreach (var methodName in postMethods) + { + var method = interfaceType.GetMethod(methodName); + method.ShouldNotBeNull(); + + var postAttribute = method!.GetCustomAttribute(); + postAttribute.ShouldNotBeNull($"Method {methodName} should have PostAttribute"); + } + } + + [Fact] + public void IIfmIoTCoreClient_AllMethods_ReturnTask() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var methods = interfaceType.GetMethods(); + + // Act & Assert + foreach (var method in methods) + { + method.ReturnType.IsGenericType.ShouldBeTrue(); + method.ReturnType.GetGenericTypeDefinition().ShouldBe(typeof(Task<>)); + } + } + + [Fact] + public void IIfmIoTCoreClient_AllMethods_TakeCancellationToken() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var methods = interfaceType.GetMethods(); + + // Act & Assert + foreach (var method in methods) + { + var parameters = method.GetParameters(); + parameters + .Last() + .ParameterType.ShouldBe( + typeof(CancellationToken), + $"Method {method.Name} should have CancellationToken as last parameter" + ); + } + } + + [Fact] + public void IIfmIoTCoreClient_HasExpectedMethodCount() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var methods = interfaceType.GetMethods(); + + // Act & Assert + methods.Length.ShouldBe(6); // All the async methods we expect + } + + [Theory] + [InlineData("GetMasterDeviceTagAsync")] + [InlineData("GetDeviceAcyclicDataAsync")] + [InlineData("GetDevicePdinDataAsync")] + [InlineData("GetDevicePdoutDataAsync")] + [InlineData("GetDataMultiAsync")] + [InlineData("GetPortTreeAsync")] + public void IIfmIoTCoreClient_HasExpectedMethod(string methodName) + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + + // Act + var method = interfaceType.GetMethod(methodName); + + // Assert + method.ShouldNotBeNull(); + } +} diff --git a/src/Tests/Vendors.Ifm/IfmIoTCoreIntegrationTest.cs b/src/Tests/Vendors.Ifm/IfmIoTCoreIntegrationTest.cs index 63ac236..84c5dba 100644 --- a/src/Tests/Vendors.Ifm/IfmIoTCoreIntegrationTest.cs +++ b/src/Tests/Vendors.Ifm/IfmIoTCoreIntegrationTest.cs @@ -1,13 +1,11 @@ -using FluentAssertions; - -using IOLinkNET.Conversion; -using IOLinkNET.Integration; -using IOLinkNET.IODD.Provider; -using IOLinkNET.IODD.Resolution.Common; -using IOLinkNET.Vendors.Ifm; -using IOLinkNET.Visualization.Menu; -using IOLinkNET.Visualization.Structure.Structure; - +using IOLink.NET.Conversion; +using IOLink.NET.Integration; +using IOLink.NET.IODD.Provider; +using IOLink.NET.IODD.Resolution.Common; +using IOLink.NET.Vendors.Ifm; +using IOLink.NET.Visualization.Menu; +using IOLink.NET.Visualization.Structure.Structure; +using Shouldly; using Vendors.Ifm.Configuration; namespace Vendors.Ifm; @@ -25,15 +23,19 @@ public async Task ShouldConvertProcessDataAsync() var masterConnection = new IfmIotCoreMasterConnection(masterClient); var definitionProvider = new DeviceDefinitionProvider(new IODDFinderPublicClient()); - var portReader = new IODDPortReader(masterConnection, definitionProvider, new IoddConverter(), new DefaultTypeResolverFactory()); + var portReader = new IODDPortReader( + masterConnection, + definitionProvider, + new IoddConverter(), + new DefaultTypeResolverFactory() + ); await portReader.InitializeForPortAsync(3); var result = await portReader.ReadConvertedProcessDataInAsync(); - result.Should().NotBeNull(); + result.ShouldNotBeNull(); } - [Fact] public async Task ShouldConvertParameterDataAsync() { @@ -41,12 +43,17 @@ public async Task ShouldConvertParameterDataAsync() var masterConnection = new IfmIotCoreMasterConnection(masterClient); var definitionProvider = new DeviceDefinitionProvider(new IODDFinderPublicClient()); - var portReader = new IODDPortReader(masterConnection, definitionProvider, new IoddConverter(), new DefaultTypeResolverFactory()); + var portReader = new IODDPortReader( + masterConnection, + definitionProvider, + new IoddConverter(), + new DefaultTypeResolverFactory() + ); await portReader.InitializeForPortAsync(3); var result500 = await portReader.ReadConvertedParameterAsync(561, 0); - result500.Should().NotBeNull(); + result500.ShouldNotBeNull(); } [Fact] @@ -56,7 +63,12 @@ public async Task ShouldReadMenuValues() var masterConnection = new IfmIotCoreMasterConnection(masterClient); var definitionProvider = new DeviceDefinitionProvider(new IODDFinderPublicClient()); - var portReader = new IODDPortReader(masterConnection, definitionProvider, new IoddConverter(), new DefaultTypeResolverFactory()); + var portReader = new IODDPortReader( + masterConnection, + definitionProvider, + new IoddConverter(), + new DefaultTypeResolverFactory() + ); await portReader.InitializeForPortAsync(3); @@ -65,10 +77,10 @@ public async Task ShouldReadMenuValues() var dS1 = await portReader.ReadConvertedParameterAsync(581, 0); var dr1 = await portReader.ReadConvertedParameterAsync(582, 0); - V_SP_FH1.Should().Be(600); - rP_FL1.Should().Be(500); - dS1.Should().Be(0); - dr1.Should().Be(0); + V_SP_FH1.ShouldBe(600); + rP_FL1.ShouldBe(500); + dS1.ShouldBe(0); + dr1.ShouldBe(0); } [Fact] @@ -78,7 +90,12 @@ public async Task ShouldReadAllMenuValuesWithMenuDataReader() var masterConnection = new IfmIotCoreMasterConnection(masterClient); var definitionProvider = new DeviceDefinitionProvider(new IODDFinderPublicClient()); - var portReader = new IODDPortReader(masterConnection, definitionProvider, new IoddConverter(), new DefaultTypeResolverFactory()); + var portReader = new IODDPortReader( + masterConnection, + definitionProvider, + new IoddConverter(), + new DefaultTypeResolverFactory() + ); var menuDataReader = new MenuDataReader(portReader); await portReader.InitializeForPortAsync(3); @@ -87,9 +104,9 @@ public async Task ShouldReadAllMenuValuesWithMenuDataReader() var readableMenus = menuDataReader.GetReadableMenus(); await readableMenus.ReadAsync(); - readableMenus.ObserverRoleMenu.IdentificationMenu.Should().NotBeNull(); - readableMenus.MaintenanceRoleMenu.IdentificationMenu.Should().NotBeNull(); - readableMenus.SpecialistRoleMenu.IdentificationMenu.Should().NotBeNull(); + readableMenus.ObserverRoleMenu.IdentificationMenu.ShouldNotBeNull(); + readableMenus.MaintenanceRoleMenu.IdentificationMenu.ShouldNotBeNull(); + readableMenus.SpecialistRoleMenu.IdentificationMenu.ShouldNotBeNull(); TestMenuSetIdentificationMenu(readableMenus.ObserverRoleMenu); TestMenuSetIdentificationMenu(readableMenus.MaintenanceRoleMenu); @@ -100,50 +117,47 @@ private static void TestMenuSetIdentificationMenu(MenuSet menuSet) { var identificationMenuVariables = menuSet.IdentificationMenu.Variables?.ToList(); var V_VendorName = identificationMenuVariables?[0]; - V_VendorName.Should().NotBeNull(); - V_VendorName?.VariableId.Should().Be("V_VendorName"); - V_VendorName?.Variable?.Id.Should().Be("V_VendorName"); - V_VendorName?.Value.Should().Be("ifm electronic gmbh"); + V_VendorName.ShouldNotBeNull(); + V_VendorName?.VariableId.ShouldBe("V_VendorName"); + V_VendorName?.Variable?.Id.ShouldBe("V_VendorName"); + V_VendorName?.Value.ShouldBe("ifm electronic gmbh"); var V_ProductName = identificationMenuVariables?[1]; - V_ProductName.Should().NotBeNull(); - V_ProductName?.VariableId.Should().Be("V_ProductName"); - V_ProductName?.Variable?.Id.Should().Be("V_ProductName"); - V_ProductName?.Value.Should().Be("TV7105"); - + V_ProductName.ShouldNotBeNull(); + V_ProductName?.VariableId.ShouldBe("V_ProductName"); + V_ProductName?.Variable?.Id.ShouldBe("V_ProductName"); + V_ProductName?.Value.ShouldBe("TV7105"); var V_ProductText = identificationMenuVariables?[2]; - V_ProductText.Should().NotBeNull(); - V_ProductText?.VariableId.Should().Be("V_ProductText"); - V_ProductText?.Variable?.Id.Should().Be("V_ProductText"); - V_ProductText?.Value.Should().Be("Electronic Temperature Sensor"); - + V_ProductText.ShouldNotBeNull(); + V_ProductText?.VariableId.ShouldBe("V_ProductText"); + V_ProductText?.Variable?.Id.ShouldBe("V_ProductText"); + V_ProductText?.Value.ShouldBe("Electronic Temperature Sensor"); var V_SerialNumber = identificationMenuVariables?[3]; - V_SerialNumber.Should().NotBeNull(); - V_SerialNumber?.VariableId.Should().Be("V_SerialNumber"); - V_SerialNumber?.Variable?.Id.Should().Be("V_SerialNumber"); - V_SerialNumber?.Value.Should().Be("100001845450"); - + V_SerialNumber.ShouldNotBeNull(); + V_SerialNumber?.VariableId.ShouldBe("V_SerialNumber"); + V_SerialNumber?.Variable?.Id.ShouldBe("V_SerialNumber"); + V_SerialNumber?.Value.ShouldBe("100001845450"); var V_HardwareRevision = identificationMenuVariables?[4]; - V_HardwareRevision.Should().NotBeNull(); - V_HardwareRevision?.VariableId.Should().Be("V_HardwareRevision"); - V_HardwareRevision?.Variable?.Id.Should().Be("V_HardwareRevision"); - V_HardwareRevision?.Value.Should().Be("AE"); - + V_HardwareRevision.ShouldNotBeNull(); + V_HardwareRevision?.VariableId.ShouldBe("V_HardwareRevision"); + V_HardwareRevision?.Variable?.Id.ShouldBe("V_HardwareRevision"); + V_HardwareRevision?.Value.ShouldBe("AE"); var V_FirmwareRevision = identificationMenuVariables?[5]; - V_FirmwareRevision.Should().NotBeNull(); - V_FirmwareRevision?.VariableId.Should().Be("V_FirmwareRevision"); - V_FirmwareRevision?.Variable?.Id.Should().Be("V_FirmwareRevision"); - V_FirmwareRevision?.Value.Should().Be("106 "); - + V_FirmwareRevision.ShouldNotBeNull(); + V_FirmwareRevision?.VariableId.ShouldBe("V_FirmwareRevision"); + V_FirmwareRevision?.Variable?.Id.ShouldBe("V_FirmwareRevision"); + V_FirmwareRevision?.Value.ShouldBe("106 "); var V_ApplicationSpecificTag = identificationMenuVariables?[6]; - V_ApplicationSpecificTag.Should().NotBeNull(); - V_ApplicationSpecificTag?.VariableId.Should().Be("V_ApplicationSpecificTag"); - V_ApplicationSpecificTag?.Variable?.Id.Should().Be("V_ApplicationSpecificTag"); - V_ApplicationSpecificTag?.Value.Should().Be("***\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + V_ApplicationSpecificTag.ShouldNotBeNull(); + V_ApplicationSpecificTag?.VariableId.ShouldBe("V_ApplicationSpecificTag"); + V_ApplicationSpecificTag?.Variable?.Id.ShouldBe("V_ApplicationSpecificTag"); + V_ApplicationSpecificTag + ?.Value?.ToString() + .ShouldBe("***\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); } -} \ No newline at end of file +} diff --git a/src/Tests/Vendors.Ifm/IfmIoTCoreMasterInformationTests.cs b/src/Tests/Vendors.Ifm/IfmIoTCoreMasterInformationTests.cs index 622e32a..7d42291 100644 --- a/src/Tests/Vendors.Ifm/IfmIoTCoreMasterInformationTests.cs +++ b/src/Tests/Vendors.Ifm/IfmIoTCoreMasterInformationTests.cs @@ -1,8 +1,6 @@ -using FluentAssertions; - -using IOLinkNET.Vendors.Ifm; -using IOLinkNET.Vendors.Ifm.Data; - +using Shouldly; +using IOLink.NET.Vendors.Ifm; +using IOLink.NET.Vendors.Ifm.Data; using Vendors.Ifm.Configuration; namespace Vendors.Ifm; @@ -13,14 +11,15 @@ namespace Vendors.Ifm; public class IfmIoTCoreMasterInformationTests { private readonly string _baseUrl = $"http://{MasterConfiguration.IP}/"; + [Fact] public async Task CanGetMasterDeviceTagAsync() { var client = IfmIoTCoreClientFactory.Create(_baseUrl); var result = await client.GetMasterDeviceTagAsync(default); - result.Should().NotBeNull(); - result.Data.Value.Should().NotBeNull(); + result.ShouldNotBeNull(); + result.Data.Value.ShouldNotBeNull(); } [Fact] @@ -30,8 +29,8 @@ public async Task CanGetDeviceAcyclicDataAsync() var req = new IfmIoTReadAcyclicRequest(3, 18, 0); var result = await client.GetDeviceAcyclicDataAsync(req, default); - result.Should().NotBeNull(); - result.Data.Value.Should().NotBeNull(); + result.ShouldNotBeNull(); + result.Data.Value.ShouldNotBeNull(); } [Fact] @@ -41,8 +40,8 @@ public async Task CanGetDevicePdinDataAsync() var req = new IfmIoTReadPdInRequest(3); var result = await client.GetDevicePdinDataAsync(req, default); - result.Should().NotBeNull(); - result.Data.Value.Should().NotBeNull(); + result.ShouldNotBeNull(); + result.Data.Value.ShouldNotBeNull(); } [Fact(Skip = "Devices not always have PDOut data")] @@ -52,17 +51,19 @@ public async Task CanGetDevicePdoutDataAsync() var req = new IfmIoTReadPdOutRequest(3); var result = await client.GetDevicePdoutDataAsync(req, default); - result.Should().NotBeNull(); + result.ShouldNotBeNull(); } [Fact] public async Task CanGetDataMultiAsync() { var client = IfmIoTCoreClientFactory.Create(_baseUrl); - var req = new IfmIoTGetDataMultiRequest(new[] { "/processdatamaster/temperature", "/deviceinfo/serialnumber" }); + var req = new IfmIoTGetDataMultiRequest( + new[] { "/processdatamaster/temperature", "/deviceinfo/serialnumber" } + ); var result = await client.GetDataMultiAsync(req, default); - result.Should().NotBeNull(); + result.ShouldNotBeNull(); } [Fact] @@ -72,6 +73,13 @@ public async Task CanGetPortTreeAsync() var req = new IfmIoTGetPortTreeRequest(); var result = await client.GetPortTreeAsync(req, default); - result.Should().NotBeNull(); + result.ShouldNotBeNull(); } -} \ No newline at end of file +} + + + + + + + diff --git a/src/Tests/Vendors.Ifm/IfmIotCoreMasterConnectionTests.cs b/src/Tests/Vendors.Ifm/IfmIotCoreMasterConnectionTests.cs index 9562243..d18d3d5 100644 --- a/src/Tests/Vendors.Ifm/IfmIotCoreMasterConnectionTests.cs +++ b/src/Tests/Vendors.Ifm/IfmIotCoreMasterConnectionTests.cs @@ -1,7 +1,5 @@ -using FluentAssertions; - -using IOLinkNET.Vendors.Ifm; - +using IOLink.NET.Vendors.Ifm; +using Shouldly; using Vendors.Ifm.Configuration; namespace Vendors.Ifm; @@ -10,7 +8,6 @@ namespace Vendors.Ifm; [Collection("IfmIoTCoreIntegrationTest")] public class IfmIotCoreMasterConnectionTests { - private readonly string _baseUrl = $"http://{MasterConfiguration.IP}/"; [Fact] @@ -20,7 +17,7 @@ public async Task CanGetPortCountAsync() var masterConnection = new IfmIotCoreMasterConnection(masterClient); var result = await masterConnection.GetPortCountAsync(); - result.Should().Be(4); + result.ShouldBe((byte)4); } [Fact] @@ -30,7 +27,7 @@ public async Task CanIdentifyPortAsync() var masterConnection = new IfmIotCoreMasterConnection(masterClient); var result = await masterConnection.GetPortInformationAsync(3); - result.Should().NotBeNull(); + result.ShouldNotBeNull(); } [Fact] @@ -40,7 +37,7 @@ public async Task CanGetPortInformationsAsync() var masterConnection = new IfmIotCoreMasterConnection(masterClient); var result = await masterConnection.GetPortInformationsAsync(); - result.Should().NotBeNull(); - result.Length.Should().Be(4); + result.ShouldNotBeNull(); + result.Length.ShouldBe(4); } -} \ No newline at end of file +} diff --git a/src/Tests/Vendors.Ifm/SimplifiedVendorsIfmTests.cs b/src/Tests/Vendors.Ifm/SimplifiedVendorsIfmTests.cs new file mode 100644 index 0000000..1ef758a --- /dev/null +++ b/src/Tests/Vendors.Ifm/SimplifiedVendorsIfmTests.cs @@ -0,0 +1,103 @@ +namespace IOLink.NET.Vendors.Ifm.Tests; + +public class SimplifiedVendorsIfmTests +{ + [Fact] + public void IfmIoTCoreClientFactory_Create_WithValidUrl_ReturnsClient() + { + // Arrange + var baseUrl = "https://test.example.com"; + + // Act + var client = IfmIoTCoreClientFactory.Create(baseUrl); + + // Assert + client.ShouldNotBeNull(); + client.ShouldBeAssignableTo(); + } + + [Fact] + public void IfmIoTCoreMasterConnectionFactory_Create_WithValidUrl_ReturnsConnection() + { + // Arrange + var baseUrl = "https://test.example.com"; + + // Act + var connection = IfmIoTCoreMasterConnectionFactory.Create(baseUrl); + + // Assert + connection.ShouldNotBeNull(); + connection.ShouldBeOfType(); + connection.ShouldBeAssignableTo(); + } + + [Fact] + public void IfmIotCoreMasterConnection_Constructor_WithValidClient_CreatesInstance() + { + // Arrange + var mockClient = Substitute.For(); + + // Act + var connection = new IfmIotCoreMasterConnection(mockClient); + + // Assert + connection.ShouldNotBeNull(); + connection.ShouldBeAssignableTo(); + } + + [Fact] + public void IfmIotCoreMasterConnection_Constructor_WithValidClient_DoesNotThrow() + { + // Arrange + var client = Substitute.For(); + + // Act & Assert + Should.NotThrow(() => new IfmIotCoreMasterConnection(client)); + } + + [Fact] + public void IIfmIoTCoreClient_IsPublicInterface() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + + // Act & Assert + interfaceType.IsInterface.ShouldBeTrue(); + interfaceType.IsPublic.ShouldBeTrue(); + } + + [Fact] + public void IIfmIoTCoreClient_HasExpectedMethods() + { + // Arrange + var interfaceType = typeof(IIfmIoTCoreClient); + var expectedMethods = new[] + { + "GetMasterDeviceTagAsync", + "GetDeviceAcyclicDataAsync", + "GetDevicePdinDataAsync", + "GetDevicePdoutDataAsync", + "GetDataMultiAsync", + "GetPortTreeAsync", + }; + + // Act & Assert + foreach (var methodName in expectedMethods) + { + var method = interfaceType.GetMethod(methodName); + method.ShouldNotBeNull($"Method {methodName} should exist"); + } + } + + [Theory] + [InlineData("")] + [InlineData(" ")] + public void FactoryMethods_WithInvalidUrl_ThrowException(string invalidUrl) + { + // Act & Assert - URI constructor throws UriFormatException for invalid URIs + Should.Throw(() => IfmIoTCoreClientFactory.Create(invalidUrl)); + Should.Throw( + () => IfmIoTCoreMasterConnectionFactory.Create(invalidUrl) + ); + } +} diff --git a/src/Tests/Vendors.Ifm/Vendors.Ifm.csproj b/src/Tests/Vendors.Ifm/Vendors.Ifm.csproj index 2d77f96..95c87ec 100644 --- a/src/Tests/Vendors.Ifm/Vendors.Ifm.csproj +++ b/src/Tests/Vendors.Ifm/Vendors.Ifm.csproj @@ -7,7 +7,8 @@ - + + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -20,10 +21,10 @@ - - - - + + + + diff --git a/src/Tests/Visualization.Tests/GlobalUsings.cs b/src/Tests/Visualization.Tests/GlobalUsings.cs deleted file mode 100644 index 8c927eb..0000000 --- a/src/Tests/Visualization.Tests/GlobalUsings.cs +++ /dev/null @@ -1 +0,0 @@ -global using Xunit; \ No newline at end of file diff --git a/src/Tests/Visualization.Tests/IODDUserInterfaceConverterTests.cs b/src/Tests/Visualization.Tests/IODDUserInterfaceConverterTests.cs deleted file mode 100644 index f061341..0000000 --- a/src/Tests/Visualization.Tests/IODDUserInterfaceConverterTests.cs +++ /dev/null @@ -1,83 +0,0 @@ -using FluentAssertions; - -using IOLinkNET.Conversion; -using IOLinkNET.Device.Contract; -using IOLinkNET.Integration; -using IOLinkNET.IODD.Provider; -using IOLinkNET.IODD.Resolution.Contracts; -using IOLinkNET.IODD.Structure.Interfaces; -using IOLinkNET.IODD.Structure.Structure.Menu; -using IOLinkNET.Visualization.IODDConversion; - -using NSubstitute; -using NSubstitute.ReturnsExtensions; - -namespace Visualization.Tests; -public class IODDUserInterfaceConverterTests -{ - [Fact] - public void ConversionThrowsIfUserInterfaceIsNotPresent() - { - var deviceSub = Substitute.For(); - deviceSub.ProfileBody.DeviceFunction.UserInterface.ReturnsNull(); - var ioddUserInterfaceConverter = new IODDUserInterfaceConverter(deviceSub, GetSubstituteForIODDPortReader()); - - var convertAction = () => ioddUserInterfaceConverter.Convert(); - - convertAction.Should().Throw().WithMessage("*User Interface not present in IODD*"); - } - - [Fact] - public void MissingObserverRoleMenuIdentificationSubMenuShouldThrow() - { - var deviceSub = Substitute.For(); - deviceSub.ProfileBody.DeviceFunction.UserInterface.ObserverRoleMenuSet.IdentificationMenu.Returns(new UIMenuRefSimpleT(null, null)); - var ioddUserInterfaceConverter = new IODDUserInterfaceConverter(deviceSub, GetSubstituteForIODDPortReader()); - var convertAction = () => ioddUserInterfaceConverter.Convert(); - - convertAction.Should().Throw().WithMessage("*Observerrole Menu must provide Identification Menu*"); - } - - [Fact] - public void MissingMaintenanceRoleMenuIdentificationSubMenuShouldThrow() - { - var deviceSub = Substitute.For(); - var menuList = new List() { - new(new("M_OR_Ident", null, null, null, null)) - }; - deviceSub.ProfileBody.DeviceFunction.UserInterface.MenuCollection.Returns(menuList); - deviceSub.ProfileBody.DeviceFunction.UserInterface.ObserverRoleMenuSet.IdentificationMenu.Returns(new UIMenuRefSimpleT("M_OR_Ident", null)); - deviceSub.ProfileBody.DeviceFunction.UserInterface.MaintenanceRoleMenuSet.IdentificationMenu.Returns(new UIMenuRefSimpleT(null, null)); - - var ioddUserInterfaceConverter = new IODDUserInterfaceConverter(deviceSub, GetSubstituteForIODDPortReader()); - var convertAction = () => ioddUserInterfaceConverter.Convert(); - - convertAction.Should().Throw().WithMessage("*Maintenancerole Menu must provide Identification Menu*"); - } - - [Fact] - public void MissingSpecialistRoleMenuIdentificationSubMenuShouldThrow() - { - var deviceSub = Substitute.For(); - - var menuList = new List() { - new(new("M_OR_Ident", null, null, null, null)), - new(new("M_MR_SR_Ident", null, null, null, null)) - }; - - deviceSub.ProfileBody.DeviceFunction.UserInterface.MenuCollection.Returns(menuList); - deviceSub.ProfileBody.DeviceFunction.UserInterface.ObserverRoleMenuSet.IdentificationMenu.Returns(new UIMenuRefSimpleT("M_OR_Ident", null)); - deviceSub.ProfileBody.DeviceFunction.UserInterface.MaintenanceRoleMenuSet.IdentificationMenu.Returns(new UIMenuRefSimpleT("M_MR_SR_Ident", null)); - deviceSub.ProfileBody.DeviceFunction.UserInterface.SpecialistRoleMenuSet.IdentificationMenu.Returns(new UIMenuRefSimpleT(null, null)); - var ioddUserInterfaceConverter = new IODDUserInterfaceConverter(deviceSub, GetSubstituteForIODDPortReader()); - var convertAction = () => ioddUserInterfaceConverter.Convert(); - - convertAction.Should().Throw().WithMessage("*Specialistrole Menu must provide Identification Menu*"); - } - - private static IODDPortReader GetSubstituteForIODDPortReader() - { - return Substitute.For(Substitute.For(), Substitute.For(), Substitute.For(), Substitute.For()); - } - -} diff --git a/src/Tests/Visualization.Tests/MenuDataReaderTests.cs b/src/Tests/Visualization.Tests/MenuDataReaderTests.cs deleted file mode 100644 index da14b85..0000000 --- a/src/Tests/Visualization.Tests/MenuDataReaderTests.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System.Xml.Linq; - -using FluentAssertions; - -using IOLinkNET.Conversion; -using IOLinkNET.Device.Contract; -using IOLinkNET.Integration; -using IOLinkNET.IODD; -using IOLinkNET.IODD.Provider; -using IOLinkNET.IODD.Resolution; -using IOLinkNET.IODD.Resolution.Contracts; -using IOLinkNET.IODD.Structure; -using IOLinkNET.Visualization.Menu; - -using NSubstitute; - -namespace Visualization.Tests; - -public class MenuDataReaderTests -{ - [Fact] - public void CanInitializeMenuDataReader() - { - var menuDataReader = new MenuDataReader(GetSubstituteForIODDPortReader()); - menuDataReader.Should().NotBeNull(); - } - - [Fact] - public void GetIODDRawMenuStructure_ShouldThrowIfNotInitialized() - { - var menuDataReaderAction = () => new MenuDataReader(GetSubstituteForIODDPortReader()).GetIODDRawMenuStructure(); - - menuDataReaderAction.Should().Throw(); - } - - [Fact] - public void GetReadableMenus_ShouldThrowIfNotInitialized() - { - var menuDataReaderAction = () => new MenuDataReader(GetSubstituteForIODDPortReader()).GetReadableMenus(); - - menuDataReaderAction.Should().Throw(); - } - - - [Theory] - [InlineData(310, 733, "TV7105", "ifm electronic gmbh ", "TestData/ifm-0002DD-20230324-IODD1.1.xml")] - [InlineData(888, 328205, "BNI IOL-727-S51-P012", "Balluff", "TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml")] - [InlineData(888, 459267, "BCS012N", "Balluff", "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml")] - /*[InlineData(1222, 18, "CSS 01411.2-xx", "STEGO Elektrotechnik GmbH", "TestData/STEGO-SmartSensor-CSS014-08-20190726-IODD1.1.xml")]*/ - public async Task CanReadMenus(ushort vendorId, uint deviceId, string productId, string vendorName, string ioddPath) - { - var (_, _, masterConnection, menuDataReader) = PreparePortReader(vendorId, deviceId, productId, vendorName, ioddPath); - masterConnection.ReadProcessDataInAsync(1).Returns(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0 }); - await menuDataReader.InitializeForPortAsync(1); - var readableMenus = menuDataReader.GetReadableMenus(); - await readableMenus.ReadAsync(); - - readableMenus.Should().NotBeNull(); - } - - [Theory] - [InlineData(310, 733, "TV7105", "ifm electronic gmbh ", "TestData/ifm-0002DD-20230324-IODD1.1.xml", 46)] - [InlineData(888, 328205, "BNI IOL-727-S51-P012", "Balluff", "TestData/Balluff-BNI_IOL-727-S51-P012-20220211-IODD1.1.xml", 84)] - [InlineData(888, 459267, "BCS012N", "Balluff", "TestData/Balluff-BCS_R08RRE-PIM80C-20150206-IODD1.1.xml", 8)] - public async Task ProvidesRawIoddMenuStructure(ushort vendorId, uint deviceId, string productId, string vendorName, string ioddPath, int menuCollectionCount) - { - var (_, _, _, menuDataReader) = PreparePortReader(vendorId, deviceId, productId, vendorName, ioddPath); - await menuDataReader.InitializeForPortAsync(1); - var rawMenuStructure = menuDataReader.GetIODDRawMenuStructure(); - - rawMenuStructure.Should().NotBeNull(); - - rawMenuStructure.MaintenanceRoleMenuSet.IdentificationMenu.Should().NotBeNull(); - rawMenuStructure.ObserverRoleMenuSet.IdentificationMenu.Should().NotBeNull(); - rawMenuStructure.SpecialistRoleMenuSet.IdentificationMenu.Should().NotBeNull(); - - rawMenuStructure.MenuCollection.Count().Should().Be(menuCollectionCount); - } - - private static IODDPortReader GetSubstituteForIODDPortReader() - { - return Substitute.For(Substitute.For(), Substitute.For(), new IoddConverter(), Substitute.For()); - } - - private (IODDPortReader, IDeviceDefinitionProvider, IMasterConnection, MenuDataReader) PreparePortReader(ushort vendorId, uint deviceId, string productId, string vendorName, string ioddPath) - { - var ioddParser = new IODDParser(); - var device = ioddParser.Parse(XElement.Load(ioddPath)); - var ioddProvider = Substitute.For(); - ioddProvider.GetDeviceDefinitionAsync(vendorId, deviceId, productId, Arg.Any()) - .Returns(device); - - var masterConnection = GetMasterConnectionMock(vendorId, deviceId, productId, vendorName); - var typeResolverFactory = Substitute.For(); - typeResolverFactory.CreateParameterTypeResolver(Arg.Any()).Returns(d => new ParameterTypeResolver(d.Arg())); - typeResolverFactory.CreateProcessDataTypeResolver(Arg.Any()).Returns(d => new ProcessDataTypeResolver(d.Arg())); - - var portReader = Substitute.For(masterConnection, ioddProvider, new IoddConverter(), typeResolverFactory); - var menuDataReader = new MenuDataReader(portReader); - - portReader.ReadConvertedParameterAsync(Arg.Any(), Arg.Any()).Returns(string.Empty); - - return (portReader, ioddProvider, masterConnection, menuDataReader); - } - - private IMasterConnection GetMasterConnectionMock(ushort vendorId, uint deviceId, string productId, string vendorName) - { - var portInfo = Substitute.For(); - var deviceInfo = Substitute.For(); - deviceInfo.VendorId.Returns(vendorId); - deviceInfo.DeviceId.Returns(deviceId); - deviceInfo.ProductId.Returns(productId); - - portInfo.PortNumber.Returns((byte)1); - portInfo.Status.Returns(PortStatus.Connected | PortStatus.IOLink); - portInfo.DeviceInformation.Returns(deviceInfo); - - var masterConnection = Substitute.For(); - masterConnection.GetPortInformationAsync(1, Arg.Any()) - .Returns(portInfo); - - masterConnection.ReadIndexAsync(portInfo.PortNumber, Arg.Any()).Returns((byte[])[0]); - - return masterConnection; - } -} \ No newline at end of file diff --git a/src/Tests/Visualization.Tests/Visualization.Tests.csproj b/src/Tests/Visualization.Tests/Visualization.Tests.csproj deleted file mode 100644 index 982a8e4..0000000 --- a/src/Tests/Visualization.Tests/Visualization.Tests.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - - false - true - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - TestData\%(RecursiveDir)/%(FileName)%(Extension) - Always - - - - - - - - - - - diff --git a/src/Visualization/IODDConversion/IODDUserInterfaceConverter.cs b/src/Visualization/IODDConversion/IODDUserInterfaceConverter.cs deleted file mode 100644 index 8379977..0000000 --- a/src/Visualization/IODDConversion/IODDUserInterfaceConverter.cs +++ /dev/null @@ -1,184 +0,0 @@ -using IOLinkNET.Integration; -using IOLinkNET.IODD.Structure; -using IOLinkNET.IODD.Structure.Interfaces; -using IOLinkNET.IODD.Structure.Interfaces.Menu; -using IOLinkNET.IODD.Structure.Structure.Menu; -using IOLinkNET.Visualization.Structure.Structure; - -namespace IOLinkNET.Visualization.IODDConversion; -internal class IODDUserInterfaceConverter -{ - private readonly IIODevice _ioDevice; - private readonly IODDPortReader _ioddPortReader; - private readonly IUserInterfaceT _userInterface; - - public IODDUserInterfaceConverter(IIODevice ioDevice, IODDPortReader ioddPortReader) - { - _ioDevice = ioDevice; - _ioddPortReader = ioddPortReader; - _userInterface = ioDevice.ProfileBody.DeviceFunction.UserInterface; - } - - public UIInterface Convert() - { - if (_userInterface == null) - { - throw new ArgumentNullException("User Interface not present in IODD"); - } - - var observerRoleMenuSet = _userInterface.ObserverRoleMenuSet; - var maintenanceRoleMenuSet = _userInterface.MaintenanceRoleMenuSet; - var specialistRoleMenuSet = _userInterface.SpecialistRoleMenuSet; - - var convertedObserverRoleMenuSet = new MenuSet( - ConvertUIMenu(observerRoleMenuSet.IdentificationMenu, StandardMenuUserRoleReader.IdentificationMenu) ?? throw new InvalidOperationException("Observerrole Menu must provide Identification Menu"), - ConvertUIMenu(observerRoleMenuSet.ParameterMenu, StandardMenuUserRoleReader.ParameterMenu), - ConvertUIMenu(observerRoleMenuSet.ObservationMenu, StandardMenuUserRoleReader.ObservationMenu), - ConvertUIMenu(observerRoleMenuSet.DiagnosisMenu, StandardMenuUserRoleReader.DiagnosisMenu), - _ioddPortReader - ); - - var convertedMaintenanceRoleMenuSet = new MenuSet( - ConvertUIMenu(maintenanceRoleMenuSet.IdentificationMenu, StandardMenuUserRoleReader.IdentificationMenu) ?? throw new InvalidOperationException("Maintenancerole Menu must provide Identification Menu"), - ConvertUIMenu(maintenanceRoleMenuSet.ParameterMenu, StandardMenuUserRoleReader.ParameterMenu), - ConvertUIMenu(maintenanceRoleMenuSet.ObservationMenu, StandardMenuUserRoleReader.ObservationMenu), - ConvertUIMenu(maintenanceRoleMenuSet.DiagnosisMenu, StandardMenuUserRoleReader.DiagnosisMenu), - _ioddPortReader - ); - var convertedSpecialistRoleMenuSet = new MenuSet( - ConvertUIMenu(specialistRoleMenuSet.IdentificationMenu, StandardMenuUserRoleReader.IdentificationMenu) ?? throw new InvalidOperationException("Specialistrole Menu must provide Identification Menu"), - ConvertUIMenu(specialistRoleMenuSet.ParameterMenu, StandardMenuUserRoleReader.ParameterMenu), - ConvertUIMenu(specialistRoleMenuSet.ObservationMenu, StandardMenuUserRoleReader.ObservationMenu), - ConvertUIMenu(specialistRoleMenuSet.DiagnosisMenu, StandardMenuUserRoleReader.DiagnosisMenu), - _ioddPortReader - ); - - return new UIInterface(convertedObserverRoleMenuSet, convertedMaintenanceRoleMenuSet, convertedSpecialistRoleMenuSet, _ioddPortReader); - } - - private UIMenu? ConvertUIMenu(UIMenuRefSimpleT? menu, string displayNameRef) - { - if (menu?.MenuId is not null) - { - var standardMenuName = GetExternalRefText(menu, displayNameRef); - var referencedMenu = _userInterface.MenuCollection.Where(x => x.Menu.Id == menu.MenuId).FirstOrDefault() ?? throw new InvalidOperationException("Referenced Menu not found"); - var menuName = referencedMenu.Menu.Name == string.Empty ? standardMenuName : referencedMenu.Menu.Name; - - return new UIMenu(menu.MenuId, - menuName, - null, - ConvertVariableRefs(referencedMenu.Menu.VariableRefs), - ConvertMenuRefs(referencedMenu.Menu.MenuRefs), - ConvertRecordItemRefs(referencedMenu.Menu.RecordItemRefs), - _ioddPortReader - ); - } - - return null; - } - - private UIMenu? ConvertUIMenu(UIMenuRefT? menu, string displayNameRef) - { - if (menu?.MenuId is not null) - { - var standardMenuName = GetExternalRefText(menu, displayNameRef); - var referencedMenu = _userInterface.MenuCollection.Where(x => x.Menu.Id == menu.MenuId).FirstOrDefault() ?? throw new InvalidOperationException("Referenced Menu not found"); - var menuName = referencedMenu.Menu.Name == string.Empty ? standardMenuName : referencedMenu.Menu.Name; - - return new UIMenu(menu.MenuId, - menuName, - menu.Condition, - ConvertVariableRefs(referencedMenu.Menu.VariableRefs), - ConvertMenuRefs(referencedMenu.Menu.MenuRefs), - ConvertRecordItemRefs(referencedMenu.Menu.RecordItemRefs), - _ioddPortReader - ); - } - - return null; - } - - private List? ConvertVariableRefs(IEnumerable? uiVariableRefs) - { - if (uiVariableRefs == null) - { - return null; - } - - var variables = new List(); - - foreach (UIVariableRefT uiVariableRef in uiVariableRefs) - { - var variable = _ioDevice.ProfileBody.DeviceFunction.VariableCollection.Where(x => x.Id == uiVariableRef.VariableId).SingleOrDefault(); - - variables.Add(new UIVariable(uiVariableRef.VariableId, - variable, - uiVariableRef.Gradient, - uiVariableRef.Offset, - uiVariableRef.UnitCode, - uiVariableRef.AccessRights, - uiVariableRef.ButtonValue, - uiVariableRef.DisplayFormat, - _ioddPortReader) - ); - } - - return variables; - } - - private List? ConvertMenuRefs(IEnumerable? menuRefs) - { - if (menuRefs == null) - { - return null; - } - - var menus = new List(); - - foreach (UIMenuRefT menuRef in menuRefs) - { - var convertedMenu = ConvertUIMenu(menuRef, string.Empty); - if (convertedMenu is not null) - { - menus.Add(convertedMenu); - } - } - - return menus; - } - - private List? ConvertRecordItemRefs(IEnumerable? uiRecordItemRefs) - { - if (uiRecordItemRefs == null) - { - return null; - } - - var recordItems = new List(); - - foreach (UIRecordItemRefT itemRef in uiRecordItemRefs) - { - var recordItemVariable = _ioDevice.ProfileBody.DeviceFunction.VariableCollection.Where(x => x.Id == itemRef.VariableId).SingleOrDefault(); - - recordItems.Add(new UIRecordItem(itemRef.VariableId, - recordItemVariable, - itemRef.SubIndex, - itemRef.Gradient, - itemRef.Offset, - itemRef.UnitCode, - itemRef.AccessRights, - itemRef.ButtonValue, - itemRef.DisplayFormat, - _ioddPortReader) - ); - } - - return recordItems; - } - - - private static string GetExternalRefText(UIMenuRefSimpleT? menu, string displayNameRef) => - menu?.Menu?.Name == string.Empty - ? StandardMenuUserRoleReader.GetStandardMenuUserRoleText(displayNameRef, string.Empty) - : menu?.Menu?.Name ?? string.Empty; -}