{"id":37315035,"url":"https://github.com/dborgards/eds-dcf-net","last_synced_at":"2026-07-05T22:00:30.732Z","repository":{"id":329003708,"uuid":"1117723120","full_name":"dborgards/eds-dcf-net","owner":"dborgards","description":"C# .NET CANopen library for EDS, DCF, CPJ, XDD and XDC (CiA 306 / CiA 311)","archived":false,"fork":false,"pushed_at":"2026-07-05T15:23:45.000Z","size":1368,"stargazers_count":2,"open_issues_count":8,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-07-05T16:18:00.853Z","etag":null,"topics":["canopen","cia","csharp","csharp-library","dcf","dotnet","dotnet-core","eds","fieldbus","industrial-automation","xdc","xdd"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dborgards.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"dborgards","buy_me_a_coffee":"dborgards"}},"created_at":"2025-12-16T18:10:08.000Z","updated_at":"2026-07-03T18:33:58.000Z","dependencies_parsed_at":"2026-02-26T11:07:50.078Z","dependency_job_id":"fe0f5cff-6f12-4b42-9cac-dd757309d41d","html_url":"https://github.com/dborgards/eds-dcf-net","commit_stats":null,"previous_names":["dborgards/eds-dcf-net"],"tags_count":69,"template":false,"template_full_name":null,"purl":"pkg:github/dborgards/eds-dcf-net","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dborgards%2Feds-dcf-net","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dborgards%2Feds-dcf-net/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dborgards%2Feds-dcf-net/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dborgards%2Feds-dcf-net/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dborgards","download_url":"https://codeload.github.com/dborgards/eds-dcf-net/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dborgards%2Feds-dcf-net/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35167263,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["canopen","cia","csharp","csharp-library","dcf","dotnet","dotnet-core","eds","fieldbus","industrial-automation","xdc","xdd"],"created_at":"2026-01-16T03:08:27.331Z","updated_at":"2026-07-05T22:00:30.695Z","avatar_url":"https://github.com/dborgards.png","language":"C#","funding_links":["https://github.com/sponsors/dborgards","https://buymeacoffee.com/dborgards"],"categories":[],"sub_categories":[],"readme":"# EdsDcfNet\n\n[![Build Status](https://github.com/dborgards/eds-dcf-net/actions/workflows/build.yml/badge.svg)](https://github.com/dborgards/eds-dcf-net/actions/workflows/build.yml)\n[![Semantic Release](https://img.shields.io/badge/semantic--release-conventionalcommits-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)\n[![NuGet Version](https://img.shields.io/nuget/v/EdsDcfNet)](https://www.nuget.org/packages/EdsDcfNet)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/EdsDcfNet)](https://www.nuget.org/packages/EdsDcfNet)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![codecov](https://codecov.io/gh/dborgards/eds-dcf-net/branch/main/graph/badge.svg)](https://codecov.io/gh/dborgards/eds-dcf-net)\n\nA comprehensive, easy-to-use C# .NET library for CANopen file formats:\nCiA DS 306 (EDS, DCF, CPJ) and CiA 311 (XDD, XDC).\n\n## Features\n\n✨ **Simple API** - Intuitive, fluent API style for quick integration\n\n📖 **Read \u0026 Write EDS** - Parse and generate Electronic Data Sheets\n\n📝 **Read \u0026 Write DCF** - Process and create Device Configuration Files\n\n🌐 **Read \u0026 Write CPJ** - Parse and create Nodelist Project files (CiA 306-3 network topologies)\n\n🧩 **Read \u0026 Write XDD/XDC** - Parse and generate CiA 311 XML device descriptions/configurations\n\n🔄 **EDS to DCF Conversion** - Easy conversion with configuration parameters\n\n🎯 **Type-Safe** - Fully typed models for all CANopen objects\n\n📦 **Modular** - Support for modular devices (bus couplers + modules)\n\n✅ **CiA DS 306 v1.4 / CiA 311 v1.1 Compliant** - Implemented according to official specification\n\n## Quick Start\n\n### Reading an EDS File\n\n```csharp\nusing EdsDcfNet;\n\n// Read EDS file\nvar eds = CanOpenFile.Eds.ReadFile(\"device.eds\");\n\n// Display device information\nConsole.WriteLine($\"Device: {eds.DeviceInfo.ProductName}\");\nConsole.WriteLine($\"Vendor: {eds.DeviceInfo.VendorName}\");\nConsole.WriteLine($\"Product Number: 0x{eds.DeviceInfo.ProductNumber:X}\");\n```\n\n### Writing an EDS File\n\n```csharp\nusing EdsDcfNet;\n\nvar eds = CanOpenFile.Eds.ReadFile(\"device.eds\");\neds.FileInfo.FileRevision++;\nCanOpenFile.Eds.WriteFile(eds, \"device_updated.eds\");\n```\n\n### Async File I/O (`async`/`await`)\n\n```csharp\nusing EdsDcfNet;\nusing System.Threading;\n\nusing var cts = new CancellationTokenSource();\n\nvar eds = await CanOpenFile.Eds.ReadFileAsync(\"device.eds\", cancellationToken: cts.Token);\neds.FileInfo.FileRevision++;\nawait CanOpenFile.Eds.WriteFileAsync(eds, \"device_updated.eds\", cancellationToken: cts.Token);\n```\n\n### Stream-based I/O\n\n```csharp\nusing EdsDcfNet;\nusing System.IO;\n\nusing var stream = File.OpenRead(\"device.eds\");\nvar eds = CanOpenFile.Eds.ReadStream(stream);\n\nusing var outStream = new MemoryStream();\nCanOpenFile.Eds.WriteStream(eds, outStream);\n```\n\n\u003e Stream ownership: stream overloads do **not** dispose input/output streams.  \n\u003e The caller remains responsible for stream lifetime.\n\n## Canonical API (format entry points)\n\nFor new code, use the format-specific entry points on `CanOpenFile` instead of the\nlegacy static `Read*` / `Write*` overloads:\n\n| Format | Entry point | Example |\n|--------|-------------|---------|\n| EDS | `CanOpenFile.Eds` | `CanOpenFile.Eds.ReadFile(\"device.eds\")` |\n| DCF | `CanOpenFile.Dcf` | `CanOpenFile.Dcf.WriteFile(dcf, \"out.dcf\")` |\n| CPJ | `CanOpenFile.Cpj` | `CanOpenFile.Cpj.ReadFile(\"network.cpj\")` |\n| XDD | `CanOpenFile.Xdd` | `CanOpenFile.Xdd.ReadFile(\"device.xdd\")` |\n| XDC | `CanOpenFile.Xdc` | `CanOpenFile.Xdc.ReadFile(\"device.xdc\")` |\n\nThese entry points accept `CanOpenFileOptions` (read limits) and `CanOpenWriteOptions`\n(pre-write validation) in one place. Legacy facade overloads remain for backward\ncompatibility and delegate to the same operations; overloads that only supply default\nparameters are marked `[Obsolete]` (advisory) and will be removed in a future major release.\n\nEDS-to-DCF conversion lives on the EDS entry point: `CanOpenFile.Eds.ConvertToDcf(...)`.\nThe legacy `CanOpenFile.EdsToDcf(...)` methods delegate there.\n\n```csharp\nusing EdsDcfNet;\n\nvar eds = CanOpenFile.Eds.ReadFile(\"device.eds\");\nvar dcf = CanOpenFile.Eds.ConvertToDcf(eds, nodeId: 2, baudrate: 500);\nCanOpenFile.Dcf.WriteFile(dcf, \"device_node2.dcf\", CanOpenWriteOptions.Validated);\n```\n\n## Migration Guide\n\nIf your code still calls the legacy `CanOpenFile.Read*` / `Write*` / `EdsToDcf` static\nmethods, move to the format entry points in the table above. Default-parameter facade\noverloads are marked `[Obsolete]` (advisory) and delegate to the same implementation;\nthey remain available until a future major release.\n\n### Facade → format entry point\n\nEach format uses the same method names on its entry point (`Eds`, `Dcf`, `Cpj`, `Xdd`,\n`Xdc`). Replace the legacy facade prefix with the matching entry point:\n\n| Legacy facade method | Canonical replacement |\n|----------------------|------------------------|\n| `ReadEds(...)`, `ReadDcf(...)`, … | `Eds.ReadFile(...)`, `Dcf.ReadFile(...)`, … |\n| `ReadEdsFromString(...)`, … | `Eds.ReadString(...)`, `Dcf.ReadString(...)`, … |\n| `ReadEds(stream, ...)`, … | `Eds.ReadStream(stream, ...)`, `Dcf.ReadStream(stream, ...)`, … |\n| `ReadEdsAsync(path, ...)`, … | `Eds.ReadFileAsync(path, ...)`, `Dcf.ReadFileAsync(path, ...)`, … |\n| `ReadEdsAsync(stream, ...)`, … | `Eds.ReadStreamAsync(stream, ...)`, … |\n| `WriteEds(...)`, … | `Eds.WriteFile(...)`, `Dcf.WriteFile(...)`, … |\n| `WriteEds(model, stream)`, … | `Eds.WriteStream(model, stream)`, … |\n| `WriteEdsAsync(...)`, … | `Eds.WriteFileAsync(...)`, `Eds.WriteStreamAsync(...)`, … |\n| `WriteEdsToString(...)`, … | `Eds.WriteToString(...)`, `Dcf.WriteToString(...)`, … |\n| `EdsToDcf(...)` | `Eds.ConvertToDcf(...)` |\n\n`CanOpenFile.Validate(...)` is unchanged.\n\n### Input size limits\n\nPass `CanOpenFileOptions` instead of a bare `maxInputSize` parameter:\n\n```csharp\n// Before\nvar xdd = CanOpenFile.ReadXdd(\"device.xdd\", maxInputSize: 50L * 1024 * 1024);\n\n// After\nvar xdd = CanOpenFile.Xdd.ReadFile(\n    \"device.xdd\",\n    new CanOpenFileOptions { MaxInputSize = 50L * 1024 * 1024 });\n```\n\n### Pre-write validation\n\nUse `CanOpenWriteOptions.Validated` on the format entry point write methods (see\n[Validating models before write operations](#validating-models-before-write-operations)).\n\n### EDS-to-DCF conversion\n\n```csharp\n// Before\nvar dcf = CanOpenFile.EdsToDcf(eds, nodeId: 2, baudrate: 500);\n\n// After\nvar dcf = CanOpenFile.Eds.ConvertToDcf(eds, nodeId: 2, baudrate: 500);\n```\n\nFor deterministic generated timestamps (recommended in tests and reproducible builds),\npass an explicit `DateTime` to `ConvertToDcf`:\n\n```csharp\nvar dcf = CanOpenFile.Eds.ConvertToDcf(\n    eds, nodeId: 2, timestamp: DateTime.UtcNow, baudrate: 500);\n```\n\n### Example migration\n\n```csharp\n// Before\nvar eds = CanOpenFile.ReadEds(\"device.eds\");\nvar dcf = CanOpenFile.EdsToDcf(eds, nodeId: 2, baudrate: 500);\nCanOpenFile.WriteDcf(dcf, \"device_node2.dcf\");\n\n// After\nvar eds = CanOpenFile.Eds.ReadFile(\"device.eds\");\nvar dcf = CanOpenFile.Eds.ConvertToDcf(eds, nodeId: 2, baudrate: 500);\nCanOpenFile.Dcf.WriteFile(dcf, \"device_node2.dcf\");\n```\n\n## Output Encoding Policy\n\nAll writer APIs that persist text (`CanOpenFile.Eds`, `.Dcf`, `.Cpj`, `.Xdd`, and `.Xdc`\nwrite methods) write **UTF-8 without BOM** by default for file and stream output.\n\nThis is an intentional interoperability choice:\n- CiA DS 306 is historically ASCII-oriented.\n- UTF-8 keeps full ASCII compatibility for 7-bit content.\n- UTF-8 also preserves non-ASCII characters in names/comments instead of replacing them.\n\n### Guidance for strict ASCII toolchains\n\nIf a downstream tool only accepts strict ASCII, keep model text in 7-bit ASCII characters,\nor transcode explicitly to strict ASCII at your boundary and fail fast on non-ASCII content.\n\n```csharp\nusing EdsDcfNet;\nusing System.IO;\nusing System.Text;\n\nvar asciiStrict = Encoding.GetEncoding(\n    \"us-ascii\",\n    EncoderFallback.ExceptionFallback,\n    DecoderFallback.ExceptionFallback);\n\nvar dcf = CanOpenFile.Dcf.ReadFile(\"device.dcf\");\nvar text = CanOpenFile.Dcf.WriteToString(dcf);\nFile.WriteAllText(\"device_ascii.dcf\", text, asciiStrict);\n```\n\n### Reading an XDD File (CiA 311 XML)\n\n```csharp\nusing EdsDcfNet;\n\n// Read XDD file\nvar xdd = CanOpenFile.Xdd.ReadFile(\"device.xdd\");\n\nConsole.WriteLine($\"Device: {xdd.DeviceInfo.ProductName}\");\nConsole.WriteLine($\"Vendor: {xdd.DeviceInfo.VendorName}\");\n```\n\n### Reading a DCF File\n\n```csharp\nusing EdsDcfNet;\n\n// Read DCF file\nvar dcf = CanOpenFile.Dcf.ReadFile(\"configured_device.dcf\");\n\nConsole.WriteLine($\"Node ID: {dcf.DeviceCommissioning.NodeId}\");\nConsole.WriteLine($\"Baudrate: {dcf.DeviceCommissioning.Baudrate} kbit/s\");\n```\n\n### Reading an XDC File (CiA 311 XML)\n\n```csharp\nusing EdsDcfNet;\n\n// Read XDC file\nvar xdc = CanOpenFile.Xdc.ReadFile(\"configured_device.xdc\");\n\nConsole.WriteLine($\"Node ID: {xdc.DeviceCommissioning.NodeId}\");\nConsole.WriteLine($\"Baudrate: {xdc.DeviceCommissioning.Baudrate} kbit/s\");\n```\n\n### Working with ApplicationProcess (CiA 311 §6.4.5)\n\nXDD/XDC files may include an `ApplicationProcess` element describing device parameters\nat the application level. The typed model gives full programmatic access to all\nsub-constructs.\n\n```csharp\nusing EdsDcfNet;\n\nvar xdd = CanOpenFile.Xdd.ReadFile(\"device.xdd\");\n\nif (xdd.ApplicationProcess is { } ap)\n{\n    // Iterate parameters\n    foreach (var param in ap.ParameterList)\n    {\n        var displayName = param.LabelGroup.GetDisplayName() ?? param.UniqueId;\n        Console.WriteLine($\"Parameter: {displayName}\");\n    }\n\n    // Inspect data type definitions\n    if (ap.DataTypeList is { } dtl)\n    {\n        foreach (var enumType in dtl.Enums)\n            Console.WriteLine($\"Enum type: {enumType.Name}\");\n    }\n}\n```\n\n### Converting EDS to DCF\n\n```csharp\nusing EdsDcfNet;\n\n// Read EDS\nvar eds = CanOpenFile.Eds.ReadFile(\"device.eds\");\n\n// Convert to DCF with node ID and baudrate\nvar dcf = CanOpenFile.Eds.ConvertToDcf(eds, nodeId: 2, baudrate: 500, nodeName: \"MyDevice\");\n\n// Save DCF\nCanOpenFile.Dcf.WriteFile(dcf, \"device_node2.dcf\");\n```\n\n### Validating models before write operations\n\nUse the validation API to detect invalid commissioning values and inconsistent\nobject-list definitions before serializing files.\n\n```csharp\nusing EdsDcfNet;\nusing EdsDcfNet.Validation;\n\nvar dcf = CanOpenFile.Dcf.ReadFile(\"configured_device.dcf\");\n\nIReadOnlyList\u003cValidationIssue\u003e issues = CanOpenFile.Validate(dcf);\nif (issues.Count \u003e 0)\n{\n    foreach (var issue in issues)\n        Console.WriteLine(issue);\n}\n```\n\n`CanOpenFile.Validate(...)` is the recommended entry point and routes to the\nfull model validator, returning path-based `ValidationIssue` entries.\nCurrent checks include:\n\n- commissioning constraints (Node-ID range `1..127` for commissioned nodes; `NodeId == 0` is accepted only when commissioning is omitted, baudrate range with `0` accepted for that omitted state, key string limits)\n- device info constraints (name/order-code length, granularity limit)\n- object dictionary consistency (list membership, duplicates, missing entries)\n- object-level constraints (object type validity, parameter-name length, SubNumber mismatch)\n\nTo validate automatically before writing, pass `CanOpenWriteOptions.Validated` to the\nformat-specific entry points:\n\n```csharp\nusing EdsDcfNet;\n\nvar dcf = CanOpenFile.Dcf.ReadFile(\"configured_device.dcf\");\n\n// Throws ModelValidationException when the model has validation issues.\nCanOpenFile.Dcf.WriteFile(dcf, \"updated.dcf\", CanOpenWriteOptions.Validated);\n```\n\nThe same option works on `CanOpenFile.Eds`, `.Cpj`, `.Xdd`, and `.Xdc` write methods.\nLegacy `CanOpenFile.WriteDcf(...)` overloads delegate to these entry points.\n\n### Working with Nodelist Projects (CPJ)\n\n```csharp\nusing EdsDcfNet;\nusing EdsDcfNet.Models;\n\n// Read a CPJ file describing the network topology\nvar cpj = CanOpenFile.Cpj.ReadFile(\"nodelist.cpj\");\n\nforeach (var network in cpj.Networks)\n{\n    Console.WriteLine($\"Network: {network.NetName}\");\n    foreach (var node in network.Nodes.Values)\n    {\n        Console.WriteLine($\"  Node {node.NodeId}: {node.Name} ({node.DcfFileName})\");\n    }\n}\n\n// Create a new CPJ\nvar project = new NodelistProject();\nproject.Networks.Add(new NetworkTopology\n{\n    NetName = \"Production Line 1\",\n    Nodes =\n    {\n        [2] = new NetworkNode { NodeId = 2, Present = true, Name = \"PLC\", DcfFileName = \"plc.dcf\" },\n        [3] = new NetworkNode { NodeId = 3, Present = true, Name = \"IO Module\", DcfFileName = \"io.dcf\" }\n    }\n});\nCanOpenFile.Cpj.WriteFile(project, \"network.cpj\");\n```\n\n### Working with Object Dictionary\n\n```csharp\nusing EdsDcfNet.Extensions;\n\nvar dcf = CanOpenFile.Dcf.ReadFile(\"device.dcf\");\n\n// Get object\nvar deviceType = dcf.ObjectDictionary.GetObject(0x1000);\n\n// Set value (returns true if object exists, false if not found)\nbool set = dcf.ObjectDictionary.SetParameterValue(0x1000, \"0x00000191\");\n\n// Browse PDO objects\nvar tpdos = dcf.ObjectDictionary.GetPdoCommunicationParameters(transmit: true);\n```\n\n## API Overview\n\n### Main Class: `CanOpenFile`\n\nWriter encoding note: all file/stream write methods on the format entry points use UTF-8 without BOM.\n\nEach format exposes read/write operations via a static property (`Eds`, `Dcf`, `Cpj`, `Xdd`, `Xdc`).\nThe shared surface on every format entry point includes:\n\n```csharp\n// Read (file, string, stream; sync and async)\nTModel ReadFile(string filePath, CanOpenFileOptions? options = null)\nTask\u003cTModel\u003e ReadFileAsync(string filePath, CanOpenFileOptions? options = null, CancellationToken cancellationToken = default)\nTModel ReadString(string content, CanOpenFileOptions? options = null)\nTModel ReadStream(Stream stream, CanOpenFileOptions? options = null)\nTask\u003cTModel\u003e ReadStreamAsync(Stream stream, CanOpenFileOptions? options = null, CancellationToken cancellationToken = default)\n\n// Write (file, stream, string; sync and async; optional CanOpenWriteOptions)\nvoid WriteFile(TModel model, string filePath)\nvoid WriteFile(TModel model, string filePath, CanOpenWriteOptions? options)\nvoid WriteStream(TModel model, Stream stream)\nvoid WriteStream(TModel model, Stream stream, CanOpenWriteOptions? options)\nTask WriteFileAsync(TModel model, string filePath, CancellationToken cancellationToken = default)\nTask WriteFileAsync(TModel model, string filePath, CanOpenWriteOptions? options, CancellationToken cancellationToken = default)\nTask WriteStreamAsync(TModel model, Stream stream, CancellationToken cancellationToken = default)\nTask WriteStreamAsync(TModel model, Stream stream, CanOpenWriteOptions? options, CancellationToken cancellationToken = default)\nstring WriteToString(TModel model)\n```\n\nFormat-specific model types:\n\n| Entry point | Read/write model |\n|-------------|------------------|\n| `CanOpenFile.Eds` | `ElectronicDataSheet` |\n| `CanOpenFile.Dcf` | `DeviceConfigurationFile` |\n| `CanOpenFile.Cpj` | `NodelistProject` |\n| `CanOpenFile.Xdd` | `ElectronicDataSheet` |\n| `CanOpenFile.Xdc` | `DeviceConfigurationFile` |\n\nEDS-to-DCF conversion:\n\n```csharp\nDeviceConfigurationFile ConvertToDcf(ElectronicDataSheet eds, byte nodeId,\n                                     ushort baudrate = 250, string? nodeName = null)\n```\n\nModel validation:\n\n```csharp\nIReadOnlyList\u003cValidationIssue\u003e Validate(ElectronicDataSheet eds)\nIReadOnlyList\u003cValidationIssue\u003e Validate(DeviceConfigurationFile dcf)\n```\n\nLegacy static `Read*` / `Write*` / `EdsToDcf` facade methods remain for backward compatibility\nand delegate to these entry points; default-parameter-only overloads are marked `[Obsolete]`.\n\n### Input Size Limits and Tuning\n\nAll read APIs apply a safe default input-size limit of **10 MB**\n(`IniParser.DefaultMaxInputSize`) to reduce denial-of-service risk from\nunexpectedly large payloads.\n\nYou can override this limit per operation when you need to process larger files:\n\n```csharp\nvar xdd = CanOpenFile.Xdd.ReadFile(\n    \"large-device.xdd\",\n    new CanOpenFileOptions { MaxInputSize = 50L * 1024 * 1024 });\n```\n\nGuidance:\n- Keep the default whenever possible.\n- Increase limits only for trusted sources and known use cases.\n- Set the limit just high enough for your expected maximum file size.\n\n## Supported Features\n\n- ✅ Complete EDS parsing and writing\n- ✅ Complete DCF parsing and writing\n- ✅ CPJ nodelist project parsing and writing (CiA 306-3 network topologies)\n- ✅ XDD parsing and writing (CiA 311 XML device description)\n- ✅ XDC parsing and writing (CiA 311 XML device configuration)\n- ✅ All Object Types (NULL, DOMAIN, DEFTYPE, DEFSTRUCT, VAR, ARRAY, RECORD)\n- ✅ Sub-objects and sub-indexes\n- ✅ Compact Storage (CompactSubObj, CompactPDO)\n- ✅ Object Links\n- ✅ Modular device concept\n- ✅ Hexadecimal, decimal, and octal numbers\n- ✅ $NODEID formula evaluation (e.g., $NODEID+0x200)\n- ✅ CANopen Safety (EN 50325-5) - SRDOMapping, InvertedSRAD\n- ✅ Comments and additional sections\n\n## Error Handling\n\nWriter APIs expose format-specific exceptions with context:\n\n- `EdsWriter` / `CanOpenFile.Eds` write methods: `EdsWriteException`\n- `DcfWriter` / `CanOpenFile.Dcf` write methods: `DcfWriteException`\n- `CpjWriter` / `CanOpenFile.Cpj` write methods: `CpjWriteException`\n- `XddWriter` / `CanOpenFile.Xdd` write methods: `XddWriteException`\n- `XdcWriter` / `CanOpenFile.Xdc` write methods: `XdcWriteException`\n\nWhen a failure can be attributed to a concrete generated section/element,\nthe exception contains a `SectionName` value (for example `DeviceInfo`,\n`Topology`, `DeviceProfile`, or `deviceCommissioning`).\n\n## Examples\n\nComplete examples can be found in the `examples/EdsDcfNet.Examples` project.\n\n## Performance Benchmarks\n\nA dedicated BenchmarkDotNet project is available at:\n\n- `benchmarks/EdsDcfNet.Benchmarks`\n\nRun all benchmarks:\n\n```bash\ndotnet run -c Release -p benchmarks/EdsDcfNet.Benchmarks -- --filter \"*\"\n```\n\nBaseline scenario definitions and artifact locations are documented in:\n\n- `benchmarks/EdsDcfNet.Benchmarks/BASELINE.md`\n\n## Project Structure\n\n```\neds-dcf-net/\n├── src/\n│   └── EdsDcfNet/              # Main library\n│       ├── Models/             # Data models\n│       ├── Parsers/            # EDS/DCF/CPJ/XDD/XDC parsers\n│       ├── Writers/            # EDS/DCF/CPJ/XDD/XDC writers\n│       ├── Utilities/          # Helper classes\n│       ├── Exceptions/         # Custom exceptions\n│       └── Extensions/         # Extension methods\n├── benchmarks/\n│   └── EdsDcfNet.Benchmarks/   # BenchmarkDotNet throughput/memory benchmarks\n├── examples/\n│   └── EdsDcfNet.Examples/     # Example application\n└── docs/\n    ├── architecture/           # ARC42 software architecture\n    └── cia/                    # CiA DS 306 specification\n```\n\n## Requirements\n\n**For consuming the NuGet package:**\n\n- Any .NET implementation compatible with .NET Standard 2.0\n  (e.g., .NET Framework 4.6.1+, .NET Core 2.0+, .NET 5+, Unity, Xamarin)\n\n**For building this repository (library, tests, examples):**\n\n- .NET SDK 10.0 or higher\n- C# 13.0 (as provided by the .NET 10 SDK)\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file\n\n## Specification\n\nBased on:\n- **CiA DS 306 Version 1.4.0** (December 15, 2021)\n- **CiA 311** XML device description/configuration concepts (XDD/XDC)\n\n## Support\n\nFor questions or issues:\n- GitHub Issues: https://github.com/dborgards/eds-dcf-net/issues\n\n---\n\n**EdsDcfNet** - Professional CANopen EDS/DCF/CPJ/XDD/XDC processing in C# .NET\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdborgards%2Feds-dcf-net","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdborgards%2Feds-dcf-net","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdborgards%2Feds-dcf-net/lists"}