CanKit.Pro.CANopen
1.2.3
dotnet add package CanKit.Pro.CANopen --version 1.2.3
NuGet\Install-Package CanKit.Pro.CANopen -Version 1.2.3
<PackageReference Include="CanKit.Pro.CANopen" Version="1.2.3" />
<PackageVersion Include="CanKit.Pro.CANopen" Version="1.2.3" />
<PackageReference Include="CanKit.Pro.CANopen" />
paket add CanKit.Pro.CANopen --version 1.2.3
#r "nuget: CanKit.Pro.CANopen, 1.2.3"
#:package CanKit.Pro.CANopen@1.2.3
#addin nuget:?package=CanKit.Pro.CANopen&version=1.2.3
#tool nuget:?package=CanKit.Pro.CANopen&version=1.2.3
CanKit.Pro.CANopen
Experimental CANopen (CiA 301) node implementation for CanKit.Pro. Provides an in-process
ICanOpenNode that combines a local Object Dictionary, an SDO server + client, an NMT slave
state machine with a heartbeat producer/consumer, a SYNC producer/consumer, structured EMCY
encoding and static TPDO/RPDO mapping — all composed on the CanKit.Pro L2 pipeline
(ICanBusService / IProtocolActor / DeadlineScheduler), exactly like CanKit.Pro.IsoTp,
CanKit.Pro.J1939Tp and CanKit.Pro.Uds.
Coverage
This is a subset of CiA 301, not a complete implementation of it. What the subset covers is every Must, Should and (formerly deferred) Could requirement from SRS §4.3.2 — the requirements this repository set itself:
| SRS id | Feature |
|---|---|
| FR-CO-001 | Local Object Dictionary with typed read/write and data-type enforcement |
| FR-CO-002 | SDO expedited transfer (payloads ≤ 4 bytes) |
| FR-CO-003 | SDO segmented transfer (payloads > 4 bytes, toggle-bit protocol) |
| FR-CO-004 | SDO block transfer (CiA 301 §7.2.4.3.15) — client + server, download + upload, blksize negotiation, optional CRC-16/XMODEM |
| FR-CO-005 | Static TPDO/RPDO mapping (byte-aligned, up to 8 bytes) and dynamic mapping: SDO access to the mapping records 0x1600–0x1603 / 0x1A00–0x1A03 (deactivate → write entries → activate, CiA 301 §7.2.4.6) with read-back and strict abort codes |
| FR-CO-006 | Event/timer TPDO and SYNC-triggered PDO, plus automatic change-of-state emission on application OD writes (CanOpenNodeOptions.EnableChangeOfStateTpdo, default on; bus-originated writes never re-trigger, so no echo loops) |
| FR-CO-007 | NMT master + slave state machine (Start / Stop / Pre-Op / Reset) |
| FR-CO-008 | Heartbeat producer + consumer timeout event |
| FR-CO-009 | Node-Guarding (CiA 301 §7.2.8.3.3) — RTR-based consumer + producer, life-time timeout event |
| FR-CO-010 | SYNC producer and consumer |
| FR-CO-011 | EMCY encode/decode + structured receive event |
| FR-CO-012 | Uses the L2 ICanBusService demux (subscription with COB-ID filter) |
Not implemented
CiA 301 features outside SRS §4.3.2 that a conformance tester or a foreign master will expect and not find here:
- Communication-parameter OD objects: 0x1005/0x1006/0x1007 (SYNC COB-ID, cycle period, sync
window length), 0x1016/0x1017 (heartbeat consumer/producer time), 0x1200ff (SDO server
parameters), 0x1400ff/0x1600ff and 0x1800ff/0x1A00ff communication records. PDO mapping is
configured through the API (
ConfigureTpdo/ConfigureRpdo) and, for the mapping records only, through dynamic mapping over SDO; a master cannot configure this node purely over the OD. - Transmission types beyond
TpdoTransmission(event-driven, event-timer, every SYNC): the CiA 301 byte values 0 (synchronous-acyclic), 2–240 (every n-th SYNC) and 252/253 (RTR-triggered) are not honored, and there are no RTR-triggered PDOs at all. - Inhibit time and sync window length — a change-of-state TPDO is not rate-limited, and a synchronous TPDO is not suppressed once the sync window has closed.
- Dummy mapping entries (0x0001–0x0007), used to pad an RPDO to a peer's layout.
- Life guarding on the producer side (§7.2.8.3.3): this node answers guarding RTRs and can act as a guarding master, but does not supervise its own guard time as a producer.
- Reset-Communication semantics: the NMT command is accepted, but communication parameters are not re-initialized from the OD, because they do not live in the OD (see above).
Open items
- CiA 302 boot-up sequence details. Classic SDO segmented transfers carry a server-side
idle timeout (
CanOpenNodeOptions.SdoServerTimeout, default 5 s) matching the block transfer guard, and block transfer retransmits from the first unconfirmed segment on a partial sub-block ACK (CiA 301 §7.2.4.3.15, bounded byCanOpenNodeOptions.SdoBlockMaxRetransmissions, default 3); the pst>0 fallback from block to segmented transfer is still not implemented (pst=0 is forced). - PDO mapping is byte-aligned only (bit lengths must be multiples of 8); bit-granular mapping entries are rejected with an SDO abort.
SDO block transfer
SdoDownloadAsync auto-selects the block codec when the payload reaches
CanOpenNodeOptions.SdoBlockThresholdBytes (default 128 bytes). SdoUploadAsync keeps the
classic expedited/segmented path under SdoTransferMode.Auto (size unknown up front); pass
SdoTransferMode.Block to force block upload. Callers can also force Expedited /
Segmented / Block on either API. The block size advertised by this node is
CanOpenNodeOptions.SdoBlockSize (default 127; peers with a smaller window renegotiate
downward). CRC-16/XMODEM is exchanged when both endpoints set the "cc" / "sc" bit
(SdoBlockCrcSupported, default true).
Node-guarding
StartNodeGuardingConsumer(nodeId, guardTime, lifeTimeFactor) polls 0x700 + nodeId with an
RTR every guardTime and raises NodeGuardingTimeout after guardTime × lifeTimeFactor
without a valid reply. The producer side answers the RTR with (toggle << 7) | state and
flips the toggle bit on every reply; heartbeat and node-guarding are mutually exclusive on
the same producer (RespondToNodeGuardingRtr gates the reply, and an active heartbeat
producer takes precedence per CiA 301 §7.2.8.3).
Quick start
using CanKit.Core;
using CanKit.Pro.CANopen;
using var bus = CanBus.Open("virtual://demo/0",
cfg => cfg.SetProtocolMode(CanProtocolMode.Can20).Baud(500_000));
using var node = CanOpen.OpenNode(bus, nodeId: 0x11);
// FR-CO-001: populate the local OD.
node.ObjectDictionary.AddU32(0x1000, 0x00, 0x00030191, OdAccess.ReadOnly); // device type
node.ObjectDictionary.AddU32(0x2000, 0x00, 0xDEADBEEF);
// FR-CO-002: SDO expedited read from another node on the same bus.
var value = await otherNode.SdoUploadAsync(serverNodeId: 0x11, index: 0x1000, subindex: 0x00);
// FR-CO-008: heartbeat producer + local consumer for a peer.
node.StartHeartbeatProducer(TimeSpan.FromMilliseconds(200));
node.AddHeartbeatConsumer(producerNodeId: 0x12, timeout: TimeSpan.FromMilliseconds(500));
node.HeartbeatTimeout += (s, e) => Console.WriteLine($"missed HB from 0x{e.ProducerNodeId:X2}");
// FR-CO-007: bring the network up as an NMT master.
await node.SendNmtCommandAsync(NmtCommand.Start, targetNodeId: 0);
See tests/CanKit.Pro.Tests/TestCases/CANopen for end-to-end examples that exercise every FR-CO
requirement over the CanKit.Adapter.Virtual loopback bus.
Layout
CanKit.Pro.CANopen/
CanOpen.cs // factory
CanOpenNode.cs // implementation of ICanOpenNode
CanOpenNodeOptions.cs
CanOpenCobId.cs // pre-defined connection set constants
ObjectDictionary.cs, OdEntry.cs
Nmt/NmtState.cs // NMT enum + command specifier
Sdo/ // codec, abort codes, exception, block-transfer codec + mode enum
CanOpenNode.SdoBlock.cs // partial: SDO block transfer (client + server)
CanOpenNode.NodeGuarding.cs // partial: node-guarding consumer + producer
Pdo/PdoMapping.cs // mapping + transmission types
Emcy/EmcyMessage.cs // 8-byte encode/decode
Install
dotnet add package CanKit.Pro.CANopen
# plus a CanKit adapter for the hardware you actually talk to, e.g.
dotnet add package CanKit.Adapter.Virtual # loopback, no hardware
Dependencies: CanKit.Abstractions, CanKit.Pro.Actor, CanKit.Pro.RawCan, CanKit.Pro.Reliability.
Part of CanKit.Pro — higher CAN protocol layers built on top of CanKit, which is consumed as a NuGet package rather than forked.
License
MIT — see LICENSE. CanKit itself is a separate project licensed under Apache-2.0; see THIRD-PARTY-NOTICES.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- CanKit.Abstractions (>= 0.5.6)
- CanKit.Pro.Actor (>= 1.2.3)
- CanKit.Pro.RawCan (>= 1.2.3)
- CanKit.Pro.Reliability (>= 1.2.3)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.12)
- System.Memory (>= 4.6.3)
- System.Threading.Channels (>= 10.0.12)
-
net10.0
- CanKit.Abstractions (>= 0.5.6)
- CanKit.Pro.Actor (>= 1.2.3)
- CanKit.Pro.RawCan (>= 1.2.3)
- CanKit.Pro.Reliability (>= 1.2.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|