Skip to content

ICanOpenNode Interface

A single CANopen node running on top of the CanKit.Pro L2 demux (arc42 §5.3, ADR-5; FR-CO-012). Combines an NMT slave state machine, a local Object Dictionary, an SDO server (for the local OD) and an SDO client (for remote nodes on the same bus), plus the SYNC, EMCY, heartbeat producer/consumer, node-guarding and PDO plumbing of CiA 301 §7.

public interface ICanOpenNode : System.IDisposable

Implements IDisposable

Remarks

One instance represents one CANopen node identity (1..127) on one physical bus, and serves both roles a CANopen application takes: a device (its own object dictionary, PDOs it produces and consumes, configured by a master over SDO) and a tool or master (the SDO client, the NMT master, heartbeat and node-guarding consumers, the SYNC producer). Profile says which of the two this instance is; the default of 1F80h follows that profile. Two or more nodes may share the same underlying ICanBusService so a process-hosted master and one or more simulated slaves can coexist on a virtual bus.

The object dictionary is the single source of truth for the node's communication parameters. The methods below that configure a service — StartHeartbeatProducer(TimeSpan), AddHeartbeatConsumer(byte, TimeSpan), StartSyncProducer(TimeSpan), ConfigureTpdo(int, PdoMapping, TpdoTransmission, Nullable<uint>, Nullable<TimeSpan>, Nullable<TimeSpan>), ConfigureRpdo(int, PdoMapping, Nullable<uint>, RpdoTransmission) — are writes to the corresponding CiA 301 objects (1017h, 1016h, 1005h/1006h, 1800h/1A00h, 1400h/1600h), and a value those objects accept from a master over SDO, or from the application through ObjectDictionary, takes effect the same way. A value that is not implementable is rejected before it is stored, so the dictionary never describes behaviour the node does not have.

Disposing.IDisposable.Dispose fails every open transfer with ObjectDisposedException (on the node's actor: a subscriber that holds the actor for longer than the actor's five-second shutdown timeout, which is reported through BackgroundExceptionOccurred, delays that until it returns), stops the producers and starts no further delivery afterwards (a subscriber that is running when the disposal finishes is not interrupted). It blocks for up to two seconds on the node's reader and event pump to let them finish; DisposeAsync(this ICanOpenNode) waits for the same without holding a thread. Either may be called from a subscriber of this node, whichever thread it runs on (an event, ApplicationReset, BackgroundExceptionOccurred): the task that thread belongs to is then not waited for, and it ends when the subscriber returns.

Properties

ICanOpenNode.ActiveFlyingMasterNodeId Property

Node-id of the active NMT master, once one is known: this node's own id when FlyingMasterRole is Active.

System.Nullable<byte> ActiveFlyingMasterNodeId { get; }

Property Value

Nullable<Byte>

ICanOpenNode.ActiveFlyingMasterPriority Property

Priority level (0 highest, 2 lowest) of ActiveFlyingMasterNodeId.

System.Nullable<ushort> ActiveFlyingMasterPriority { get; }

Property Value

Nullable<UInt16>

ICanOpenNode.DeviceDescription Property

What the device description the node was opened with produced — the entries loaded and everything the node could not take as written — or null when the node was opened without one and carries the built-in CiA 301 defaults.

CanKit.Pro.CANopen.DeviceDescriptionReport? DeviceDescription { get; }

Property Value

DeviceDescriptionReport

ICanOpenNode.FlyingMasterRole Property

Role in the flying-master election. Inactive until StartFlyingMaster(ushort, TimeSpan) or until bits 0 and 5 of 1F80h are set.

CanKit.Pro.CANopen.Nmt.FlyingMasterRole FlyingMasterRole { get; }

Property Value

FlyingMasterRole

ICanOpenNode.NodeId Property

Node identifier (1..127) this instance answers as on the bus. 0xFF while an LSS slave has no active node-id yet (CiA 305): nothing on the bus is addressed with it.

byte NodeId { get; }

Property Value

Byte

ICanOpenNode.ObjectDictionary Property

The local Object Dictionary (FR-CO-001). Shared by SDO server, PDO mapping and application code. Created with the communication-profile objects CiA 301 requires of a device that supports SDO, PDO, SYNC, EMCY, heartbeat and guarding (1000h, 1001h, 1005h, 1006h, 100Ch, 100Dh, 1010h, 1011h, 1014h, 1016h, 1017h, 1018h, 1200h, and per PDO up to PdoCount the records 1400h/1600h/1800h/ 1A00h + n − 1 — 1400h–1403h, 1600h–1603h, 1800h–1803h, 1A00h–1A03h for the default four), each at its CiA 301 default. 1000h and 1018h carry placeholder values (device type 0, vendor-id 0 = "no vendor-id assigned") that the application replaces with its own; the remaining objects are managed by the node and take values, not re-declarations.

CanKit.Pro.CANopen.ObjectDictionary ObjectDictionary { get; }

Property Value

ObjectDictionary

ICanOpenNode.Options Property

Options this node was constructed with.

CanKit.Pro.CANopen.CanOpenNodeOptions Options { get; }

Property Value

CanOpenNodeOptions

ICanOpenNode.State Property

Current NMT slave state of this node.

CanKit.Pro.CANopen.Nmt.NmtState State { get; }

Property Value

NmtState

Methods

ICanOpenNode.AddHeartbeatConsumer(byte, TimeSpan) Method

Registers (or replaces) a heartbeat consumer for producerNodeId in a free sub-index of 1016h (consumer heartbeat time; the array grows as consumers are added): if no heartbeat is received within timeout (1..65535 ms), the node raises HeartbeatTimeout. The timeout is armed immediately, so a producer that never appears is reported too.

void AddHeartbeatConsumer(byte producerNodeId, System.TimeSpan timeout);

Parameters

producerNodeId Byte

timeout TimeSpan

ICanOpenNode.BindPeerDeviceDescription(byte, CanOpenDeviceDescription) Method

Binds the EDS or DCF of remote node nodeId. Client SDO transfers to that node then proceed only for (index, sub-index) pairs the description declares (Contains(ushort, byte)). Replaces a description already bound for the same node-id. The description is read at the start of each transfer, without synchronization against an edit of the bound instance in place (Objects): edit it only while no call that reads it is running, or bind another one.

void BindPeerDeviceDescription(byte nodeId, CanKit.Pro.CANopen.CanOpenDeviceDescription description);

Parameters

nodeId Byte

description CanOpenDeviceDescription

Exceptions

ArgumentException
description is a DCF whose commissioned node-id is not nodeId. An EDS has no commissioned node-id and may be bound to any node. A rejected bind leaves the description already stored for that node in place.

Remarks

Without a description bound for the server, SdoUploadAsync(byte, ushort, byte, SdoTransferMode, CancellationToken) and SdoDownloadAsync(byte, ushort, byte, ReadOnlyMemory<byte>, SdoTransferMode, CancellationToken) transfer only 1000h:00, 1001h:00 and 1018h:00–04 (IsAllowedWithoutPeerDescription(ushort, byte)). Once a description is bound, those objects are allowed only when the file lists them. A refused transfer throws PeerSdoAccessException before any frame is sent.

ICanOpenNode.ConfigureRpdo(int, PdoMapping, Nullable<uint>, RpdoTransmission) Method

Configures (or replaces) RPDO pdoIndex (1..PdoCount) by writing its communication record 1400h + n − 1 and mapping record 1600h + n − 1. Incoming frames matching the COB-ID unpack into the local OD and raise RpdoReceived — immediately, or with the next SYNC for Synchronous. cobId is the 1400h:01 word (bit 31 set = configured but disabled; bit 29 selects an extended CAN frame; bit 30, the RTR bit of a TPDO, has no meaning for an RPDO and is accepted and ignored); the CAN-ID must not be one CiA 301 §7.3.5 restricts. The writes are one transaction on the actor loop, as for ConfigureTpdo(int, PdoMapping, TpdoTransmission, Nullable<uint>, Nullable<TimeSpan>, Nullable<TimeSpan>).

void ConfigureRpdo(int pdoIndex, CanKit.Pro.CANopen.Pdo.PdoMapping mapping, System.Nullable<uint> cobId=null, CanKit.Pro.CANopen.Pdo.RpdoTransmission transmission=CanKit.Pro.CANopen.Pdo.RpdoTransmission.EventDriven);

Parameters

pdoIndex Int32

mapping PdoMapping

cobId Nullable<UInt32>

transmission RpdoTransmission

Exceptions

ArgumentException
A value was rejected; see ConfigureTpdo(int, PdoMapping, TpdoTransmission, Nullable<uint>, Nullable<TimeSpan>, Nullable<TimeSpan>).

ICanOpenNode.ConfigureTpdo(int, PdoMapping, TpdoTransmission, Nullable<uint>, Nullable<TimeSpan>, Nullable<TimeSpan>) Method

Configures (or replaces) TPDO pdoIndex (1..PdoCount) by writing its communication record 1800h + n − 1 and mapping record 1A00h + n − 1, in the CiA 301 §7.5.2.38 re-mapping order (PDO invalidated, mapping rewritten, parameters set, PDO validated). Values not provided use CiA 301 defaults: the COB-ID is the pre-defined connection set entry, the inhibit time is 0 (off), and the event timer is DefaultTpdoEventTimerInterval for EventTimer and 0 otherwise. The writes are one transaction on the node's actor loop and under the dictionary's write gate: the method returns with the configuration applied, and neither another caller, nor an SDO download, nor a direct dictionary write interleaves with the sequence.

void ConfigureTpdo(int pdoIndex, CanKit.Pro.CANopen.Pdo.PdoMapping mapping, CanKit.Pro.CANopen.Pdo.TpdoTransmission transmission=CanKit.Pro.CANopen.Pdo.TpdoTransmission.EventDriven, System.Nullable<uint> cobId=null, System.Nullable<System.TimeSpan> eventTimerInterval=null, System.Nullable<System.TimeSpan> inhibitTime=null);

Parameters

pdoIndex Int32

TPDO number 1..CanOpenNodeOptions.PdoCount (or the description's higher count).

mapping PdoMapping

The mapped objects; copied into the mapping record. Every target must exist in the OD, be PDO-mappable and readable, and have the mapped bit length. A dummy entry 0001h–0007h (sub-index 0) touches no object but must have its data type's bit length too (DummyBitLength(ushort)).

transmission TpdoTransmission

Trigger mode; see TpdoTransmission. Cyclic "every n-th SYNC" is configured by writing the raw byte to 1800h:02 instead.

cobId Nullable<UInt32>

The 1800h:01 word: a CAN-ID plus the CiA 301 control bits — bit 31 set configures the PDO but leaves it disabled ("PDO does not exist"), bit 30 set forbids RTR on it. Bit 29 selects a 29-bit CAN-ID; PDOs above 4 require an explicit COB-ID.

eventTimerInterval Nullable<TimeSpan>

Event timer for EventTimer, 1..65535 ms; ignored for the other modes.

inhibitTime Nullable<TimeSpan>

Minimum interval between two transmissions of an event-driven TPDO (1800h:03, in multiples of 100 µs, at most 6.5535 s). Has no effect on the synchronous and RTR-only modes, per CiA 301 §7.5.2.37.

Exceptions

ArgumentException
A value was rejected; the message names the CiA 301 abort code the same write would have produced over SDO. The PDO is left disabled. Also thrown, before anything is written, when the PDO is not declared on this node (a bound description omits its records), or when the bound description declares no inhibit time (1800h:03) or no event timer (1800h:05) — both optional per CiA 301 Table 71 — and a non-zero value is requested for the absent one.

ICanOpenNode.GetPeerDeviceDescription(byte) Method

The description bound for nodeId, or null.

CanKit.Pro.CANopen.CanOpenDeviceDescription? GetPeerDeviceDescription(byte nodeId);

Parameters

nodeId Byte

Returns

CanOpenDeviceDescription

ICanOpenNode.ObserveForeignPdoAsync(byte, uint, ReadOnlyMemory<byte>, CanOpenDeviceDescription, IForeignPdoSink, CancellationToken) Method

Decodes a PDO payload of peerNodeId and writes each mapped object to sink. Nothing is written to this node's object dictionary, and a frame that is not one of this node's own RPDOs is still not applied when it arrives: this method is the only path that splits a peer PDO.

System.Threading.Tasks.Task<CanKit.Pro.CANopen.ForeignPdoObserveResult> ObserveForeignPdoAsync(byte peerNodeId, uint cobId, System.ReadOnlyMemory<byte> payload, CanKit.Pro.CANopen.CanOpenDeviceDescription peerDescription, CanKit.Pro.CANopen.IForeignPdoSink sink, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));

Parameters

peerNodeId Byte

The node whose PDO this payload is (1..127).

cobId UInt32

The observed ID, with bit 29 set for an extended frame.

payload ReadOnlyMemory<Byte>

The PDO data, 0..8 bytes.

peerDescription CanOpenDeviceDescription

EDS or DCF of the peer. Supplies the COB-ID and the mapping when the live read of that record fails.

sink IForeignPdoSink

Where each decoded object is written.

cancellationToken CancellationToken

Cancels an in-flight mapping upload. Cancellation is not a failed read: the file is not used in its place.

Returns

Task<ForeignPdoObserveResult>

Exceptions

ArgumentNullException
peerDescription or sink is null.

ArgumentOutOfRangeException
peerNodeId is outside 1..127, cobId is not a valid base or extended PDO key, or payload is longer than 8 bytes.

Remarks

Which PDO the COB-ID belongs to is read live from 1400h:01 / 1800h:01 when a peer description bound for peerNodeId declares the record; without a binding the peer-SDO gate refuses every PDO record before a frame is sent, and the whole observation is decoded from peerDescription. A value that comes back is used ahead of peerDescription, including a PDO the device marks invalid (bit 31 set) or a CAN-ID the file does not name. The same entry in the file ($NODEID resolved to peerNodeId) is used only when that upload aborts, times out, is refused by the peer-SDO gate, or does not return a word. A CAN-ID CiA 301 §7.3.5 restricts is not accepted from either source. Observations of one peer are serialized, so two of them do not fail each other on the one-transfer-per-server limit.

The live reads of one observation are one snapshot of the peer: the peer's SDO channel is taken without waiting and held to the end, so a safety transaction that starts meanwhile waits for it and another SDO call of this node to that peer is refused as in flight. A channel busy at the start — a call in flight, a safety transaction — makes every live read of that observation "already in flight", and the whole snapshot is the file's; a live COB-ID is never combined with the file's mapping because a caller came in between.

The mapping is the live record 1600h–17FFh or 1A00h–1BFFh, uploaded over the same SDO client. A pair the bound peer description does not allow is refused before a frame is sent and is a failed live read. An upload that aborts or times out, or an invalid mapping exceeding 64 bits, makes the live record unavailable and the mapping in the file is used instead. Mapping counts FEh/FFh decode an MPDO multiplexer. A record neither the device nor the file can supply is not decoded.

The split follows the same length rule as an RPDO this node consumes: fewer bytes than the mapping writes nothing; extra bytes are ignored; a dummy entry 0001h–0007h consumes its bits and writes no signal.

ICanOpenNode.RemoveHeartbeatConsumer(byte) Method

Removes a previously-registered heartbeat consumer for producerNodeId (clears its 1016h entry). No-op if none was registered.

void RemoveHeartbeatConsumer(byte producerNodeId);

Parameters

producerNodeId Byte

ICanOpenNode.RestoreDefaultParameters() Method

Marks the stored power-on values for discarding: the next NMT reset restores the CiA 301 defaults the node was created with (the local equivalent of a master writing "load" to 1011h:01; per §7.5.2.14 the defaults become valid with the reset, not before).

void RestoreDefaultParameters();

ICanOpenNode.SdoDownloadAsync(byte, ushort, byte, ReadOnlyMemory<byte>, SdoTransferMode, CancellationToken) Method

Writes an object to serverNodeId's OD. Auto selects the transport from the data length: at or above SdoBlockThresholdBytes block transfer, and below it the CiA 301 split — 1..4 bytes expedited, an empty value and 5 bytes and up segmented (the expedited encoding cannot express 0 bytes). The threshold is checked first, so it also decides the expedited range: a threshold of 1..4 (which the options permit) sends a short payload by block transfer rather than expedited. Pass Block to force block transfer below that threshold; the expedited/segmented split itself is dictated by CiA 301 and is not selectable. Refused locally with PeerSdoAccessException when the pair is not allowed for serverNodeId; see BindPeerDeviceDescription(byte, CanOpenDeviceDescription). One transfer per server is in flight at a time: with one in flight — a safety transaction with that server counts as one for its whole length — the call fails with InvalidOperationException before anything is sent.

System.Threading.Tasks.Task SdoDownloadAsync(byte serverNodeId, ushort index, byte subindex, System.ReadOnlyMemory<byte> data, CanKit.Pro.CANopen.Sdo.SdoTransferMode mode=CanKit.Pro.CANopen.Sdo.SdoTransferMode.Auto, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));

Parameters

serverNodeId Byte

index UInt16

subindex Byte

data ReadOnlyMemory<Byte>

mode SdoTransferMode

cancellationToken CancellationToken

Returns

Task

Remarks

Not gated by this node's NMT state, as SdoUploadAsync(byte, ushort, byte, SdoTransferMode, CancellationToken).

Cancelling cancellationToken ends the returned task as cancelled and sends the server an abort (0800 0000h). During a block download the sub-block being sent stops before its next segment, but the segment it had already started to hand to the bus is not recalled: it can reach the bus after the abort, and after the initiate of a transfer to the same server started right after the cancellation (#377). The task does not wait for the abort to be on the wire.

ICanOpenNode.SdoDownloadAsync(byte, ushort, byte, ReadOnlyMemory<byte>, CancellationToken) Method

Writes an object to serverNodeId's OD using Auto. Source-compatible overload for callers that pass a positional CancellationToken after data.

System.Threading.Tasks.Task SdoDownloadAsync(byte serverNodeId, ushort index, byte subindex, System.ReadOnlyMemory<byte> data, System.Threading.CancellationToken cancellationToken);

Parameters

serverNodeId Byte

index UInt16

subindex Byte

data ReadOnlyMemory<Byte>

cancellationToken CancellationToken

Returns

Task

ICanOpenNode.SdoUploadAsync(byte, ushort, byte, SdoTransferMode, CancellationToken) Method

Reads an object from serverNodeId's OD. Auto uses the classic client because the payload length is unknown until the server replies — whether that reply is expedited or segmented is the server's choice and is handled transparently. Pass Block to force block transfer (CiA 301 §7.2.4.3.12–7.2.4.3.15). (FR-CO-002 / FR-CO-003 / FR-CO-004). Refused locally with PeerSdoAccessException when the pair is not allowed for serverNodeId; see BindPeerDeviceDescription(byte, CanOpenDeviceDescription). One transfer per server is in flight at a time: with one in flight — a safety transaction with that server counts as one for its whole length — the call fails with InvalidOperationException before anything is sent.

System.Threading.Tasks.Task<byte[]> SdoUploadAsync(byte serverNodeId, ushort index, byte subindex, CanKit.Pro.CANopen.Sdo.SdoTransferMode mode=CanKit.Pro.CANopen.Sdo.SdoTransferMode.Auto, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));

Parameters

serverNodeId Byte

index UInt16

subindex Byte

mode SdoTransferMode

cancellationToken CancellationToken

Returns

Task<Byte[]>

Remarks

The client is not gated by this node's NMT state: it transfers in Stopped too, as SendSyncAsync(CancellationToken) sends (#254). What CiA 301 Table 37 rules out in Stopped is applied to this node's SDO server.

ICanOpenNode.SdoUploadAsync(byte, ushort, byte, CancellationToken) Method

Reads an object from serverNodeId's OD using Auto (the server's initiate response decides expedited vs. segmented; the size is unknown up front so Auto does not select block upload — pass Block explicitly). Source-compatible overload for callers that pass a positional CancellationToken.

System.Threading.Tasks.Task<byte[]> SdoUploadAsync(byte serverNodeId, ushort index, byte subindex, System.Threading.CancellationToken cancellationToken);

Parameters

serverNodeId Byte

index UInt16

subindex Byte

cancellationToken CancellationToken

Returns

Task<Byte[]>

ICanOpenNode.SendEmcyAsync(ushort, byte, ReadOnlyMemory<byte>, CancellationToken) Method

Transmits an EMCY frame from this node on the COB-ID configured in 1014h, after writing errorRegister to 1001h so the error register a master reads over SDO is the one the last EMCY carried: the write and the transmission are one ordered step on the node's actor loop, and every EMCY of this node goes out through one ordered path, so overlapping calls reach the bus in the order the register was written. In NMT state Stopped the EMCY is held and the most recent one is transmitted when the node leaves Stopped (CiA 301 §7.3.2.2.4). The returned task faults with InvalidOperationException when EMCY is disabled (bit 31 of 1014h set).

System.Threading.Tasks.Task SendEmcyAsync(ushort errorCode, byte errorRegister, System.ReadOnlyMemory<byte> manufacturerSpecific=default(System.ReadOnlyMemory<byte>), System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));

Parameters

errorCode UInt16

errorRegister Byte

manufacturerSpecific ReadOnlyMemory<Byte>

cancellationToken CancellationToken

Returns

Task

ICanOpenNode.SendNmtCommandAsync(NmtCommand, byte, CancellationToken) Method

Sends an NMT master command (COB-ID 0x000). targetNodeId zero means broadcast to all nodes. This method only transmits the command and does not apply it to the local node. Whether the node obeys it anyway depends on the adapter: one that delivers the node's own transmits back (a loopback, or hardware in an echo mode) hands it to the receive path, where it is applied via NmtCommandReceived; one that does not (Normal mode on a non-echoing adapter) leaves the node's own NMT state alone, which then follows the boot-up of an active flying master (bit 2 of 1F80h clear) or another master. Do not rely on either.

System.Threading.Tasks.Task SendNmtCommandAsync(CanKit.Pro.CANopen.Nmt.NmtCommand command, byte targetNodeId, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));

Parameters

command NmtCommand

targetNodeId Byte

cancellationToken CancellationToken

Returns

Task

ICanOpenNode.SendSyncAsync(CancellationToken) Method

Transmits a single SYNC frame (payload-less) on the SYNC COB-ID configured in 1005h.

System.Threading.Tasks.Task SendSyncAsync(System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));

Parameters

cancellationToken CancellationToken

Returns

Task

Remarks

This is a raw send, not the producer: it is not gated by the NMT state and not by bit 30 of 1005h ("device generates SYNC"), so a node in Stopped, or one that is not configured to produce SYNC, transmits when asked. The periodic producer (StartSyncProducer(TimeSpan)) is the one that follows CiA 301 Table 37.

ICanOpenNode.StartFlyingMaster(ushort, TimeSpan) Method

Joins the NMT flying-master election at priorityLevel (0 highest, 2 lowest). Writes that level to 1F90h:03 and sets bits 0 and 5 of 1F80h. The first election after this call is a cold boot: if no master answers, the node broadcasts NMT Reset Communication and runs the election again as a warm boot. That reset restores power-on values, so this method records 1F80h, 1F81h, 1F89h and 1F90h as power-on values before it starts; call StoreParameters() first if the rest of the configuration must survive the same reset. After the node becomes the active master it boots the slaves assigned in 1F81h (see the package README).

void StartFlyingMaster(ushort priorityLevel, System.TimeSpan activeMasterHeartbeatTimeout);

Parameters

priorityLevel UInt16

0, 1 or 2. Lower wins. Equal priority does not depose an active master; in a timeslot race the lower node-id waits less and claims first.

activeMasterHeartbeatTimeout TimeSpan

While this node stands by, a heartbeat consumer (1016h) for the active master is installed at this timeout unless one already exists. A timeout starts a new election. When this node becomes the active master and 1017h is 0, the producer is started at half this timeout so peers can see the loss.

Exceptions

ArgumentOutOfRangeException
priorityLevel is above 2, or activeMasterHeartbeatTimeout is outside 1..65535 ms.

ArgumentException
1F90h:04 is not greater than 127 times 1F90h:05, so the timeslots would not keep a better priority ahead of a worse one.

ICanOpenNode.StartHeartbeatProducer(TimeSpan) Method

Starts (or replaces) the local heartbeat producer with interval: writes 1017h (producer heartbeat time, 1..65535 ms). While the producer is active the node uses the heartbeat protocol and does not answer node-guarding RTRs (CiA 301 §7.2.8.3.2.2).

void StartHeartbeatProducer(System.TimeSpan interval);

Parameters

interval TimeSpan

ICanOpenNode.StartNodeGuardingConsumer(byte, TimeSpan, byte) Method

Starts the node-guarding consumer for producerNodeId: sends an RTR on 0x700 + producerNodeId every guardTime and expects the peer to reply with a one-byte data frame (toggle bit in bit 7, NMT state in bits 0..6). If guardTime × lifeTimeFactor elapses without a valid response the node raises NodeGuardingTimeout. Replaces any existing consumer for the same peer.

void StartNodeGuardingConsumer(byte producerNodeId, System.TimeSpan guardTime, byte lifeTimeFactor);

Parameters

producerNodeId Byte

guardTime TimeSpan

lifeTimeFactor Byte

ICanOpenNode.StartSyncProducer(TimeSpan) Method

Starts a periodic SYNC producer with the given interval: writes 1006h (communication cycle period, in µs) and sets bit 30 of 1005h ("device generates SYNC"). SYNC is not transmitted in NMT state Stopped (CiA 301 Table 37).

void StartSyncProducer(System.TimeSpan interval);

Parameters

interval TimeSpan

ICanOpenNode.StopFlyingMaster() Method

Leaves the election: clears bits 0 and 5 of 1F80h and drops a heartbeat consumer this node installed for the active master. Recorded as the power-on value of 1F80h, so a later reset does not rejoin.

void StopFlyingMaster();

ICanOpenNode.StopHeartbeatProducer() Method

Stops the local heartbeat producer: writes 1017h = 0.

void StopHeartbeatProducer();

ICanOpenNode.StopNodeGuardingConsumer(byte) Method

Stops the node-guarding consumer for producerNodeId. No-op when none is running.

void StopNodeGuardingConsumer(byte producerNodeId);

Parameters

producerNodeId Byte

ICanOpenNode.StopSyncProducer() Method

Stops the periodic SYNC producer: clears bit 30 of 1005h.

void StopSyncProducer();

ICanOpenNode.StoreParameters() Method

Takes the current values of the node's communication-profile objects as the power-on values an NMT reset restores — the local equivalent of a master writing "save" to 1010h:01. Without a store, a reset restores the CiA 301 defaults the node was created with, so a device configured through ConfigureTpdo(int, PdoMapping, TpdoTransmission, Nullable<uint>, Nullable<TimeSpan>, Nullable<TimeSpan>) / ConfigureRpdo(int, PdoMapping, Nullable<uint>, RpdoTransmission) calls this once its configuration is complete.

void StoreParameters();

ICanOpenNode.TriggerTpdoAsync(int, CancellationToken) Method

Requests a TPDO transmission from the application (CiA 301 "internal event"). Event-driven TPDOs (FEh/FFh) transmit subject to their inhibit time; a synchronous-acyclic TPDO (00h) transmits after the next SYNC. The other types do not react to an event, so the call sends nothing for them: a cyclic TPDO (01h–F0h) is transmitted by the SYNC, and an RTR-only TPDO (FCh/FDh) by an RTR. The node still respects the current NMT state (only fires in Operational); a call that sends nothing completes normally, as for a PDO that is not valid.

System.Threading.Tasks.Task TriggerTpdoAsync(int pdoIndex, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));

Parameters

pdoIndex Int32

cancellationToken CancellationToken

Returns

Task

ICanOpenNode.UnbindPeerDeviceDescription(byte) Method

Drops the description bound for nodeId. No-op when none is bound. Afterwards the mandatory-object exemption applies to that node again.

void UnbindPeerDeviceDescription(byte nodeId);

Parameters

nodeId Byte

Events

ICanOpenNode.ApplicationReset Event

Raised synchronously on the actor loop during an NMT Reset Node or Reset Communication, after the communication-profile objects have been restored and before the boot-up is transmitted: the application restores its own object dictionary objects in the handler, and the node announces itself only when the handler has returned — a master reacting to the boot-up never reads a value the reset had not reached. When layer setting services are on, the pending node-id is already the active one and the pre-defined COB-IDs already name it. The handler runs on the loop the node's own work runs on, so it must not wait for the node (an SDO transfer, StoreParameters(), a configuration method); its exception is reported through BackgroundExceptionOccurred and does not stop the reset.

event EventHandler<NmtResetEventArgs>? ApplicationReset;

Event Type

EventHandler<NmtResetEventArgs>

ICanOpenNode.BackgroundExceptionOccurred Event

Raised on background exceptions from the actor loop / subscription reader.

Raised on a thread-pool thread, never on the node's actor loop or its event pump, so a handler may wait on the node -- an SDO transfer, StoreParameters(), a configuration method, IDisposable.Dispose -- without deadlocking the actor (#356). Reports are delivered one at a time, in the order they were made; a handler that blocks holds up the reports behind it, not the node. Each handler is called on its own, so one that throws does not keep the report from the handlers after it; its exception is dropped. A failure that happens once the disposal has finished is not reported; one that happened before may reach its handlers after IDisposable.Dispose has returned. A handler that disposes the node ends that report's round: the handlers after it are not called, unless the node was already disposed when the round began.

event EventHandler<Exception>? BackgroundExceptionOccurred;

Event Type

EventHandler<Exception>

ICanOpenNode.EmcyReceived Event

Raised when an EMCY frame is received on the bus (FR-CO-011). Not discarded when the event queue is over EventQueueCapacity. While a handler is behind, an EMCY identical to one still waiting (same producer, code, register and manufacturer field) is folded into it, unless another event about that producer was queued in between, and a producer with EventQueueCapacity distinct emergencies already waiting has its further ones discarded, reported once per burst on BackgroundExceptionOccurred. The producer is the COB-ID minus 080h, the pre-defined connection set: for a peer whose 1014h was moved off that set, ProducerNodeId is not the peer's node-id, and the folding above is keyed on it as well. An EMCY frame shorter than eight bytes (CiA 301 §7.2.7.3.1) raises no event: it is dropped, not padded, and the first one from each producer is reported on BackgroundExceptionOccurred as a CanOpenTransportException; later ones from that producer are dropped without a report.

event EventHandler<EmcyReceivedEventArgs>? EmcyReceived;

Event Type

EventHandler<EmcyReceivedEventArgs>

ICanOpenNode.FlyingMasterChanged Event

Raised when this node becomes the active master, yields, forces a new election, loses the active master, sees an inconsistent claim, or times out a mandatory slave.

event EventHandler<FlyingMasterChangedEventArgs>? FlyingMasterChanged;

Event Type

EventHandler<FlyingMasterChangedEventArgs>

ICanOpenNode.HeartbeatReceived Event

Raised when a heartbeat or bootup frame is received from any node. Data frames on 0x700 + node-id are heartbeats; a node-guarding response is reported through NodeGuardingReceived instead when a guarding consumer is registered for the producer.

event EventHandler<HeartbeatReceivedEventArgs>? HeartbeatReceived;

Event Type

EventHandler<HeartbeatReceivedEventArgs>

ICanOpenNode.HeartbeatTimeout Event

Raised when a configured heartbeat consumer detects a missing heartbeat. Not discarded when the event queue is over EventQueueCapacity — losing it would leave the peer looking alive. While a timeout for the same producer is still waiting for the handler, a further one is folded into it rather than queued again, unless a heartbeat from that producer was queued in between. The event that waits then reports the newest settings.

event EventHandler<HeartbeatTimeoutEventArgs>? HeartbeatTimeout;

Event Type

EventHandler<HeartbeatTimeoutEventArgs>

ICanOpenNode.LifeGuardingEvent Event

Producer-side life guarding (CiA 301 §7.2.8.2.2.2 / §7.2.8.3.2.1): raised with Occurred when this node, being guarded by a master, was not polled within its node life time (100Ch guard time × 100Dh life time factor, both from the object dictionary), and with Resolved when a poll arrives again afterwards. Guarding starts with the first RTR the node answers; both objects at 0 (the default) disable it, and so does an RTR the node does not answer -- with the heartbeat producer on, or with RespondToNodeGuardingRtr off.

event EventHandler<LifeGuardingEventArgs>? LifeGuardingEvent;

Event Type

EventHandler<LifeGuardingEventArgs>

ICanOpenNode.NmtCommandReceived Event

Raised for every NMT master command whose target matches this node (or the broadcast target 0) and which the node applies. Delivered on the node's event queue, after the node has acted on the command — for a reset, possibly after the boot-up is on the bus; to restore application objects before that, use ApplicationReset. While this node is the active flying master it ignores a command addressed to its own node-id, and it does not apply a broadcast reset or stop to itself.

event EventHandler<NmtCommandReceivedEventArgs>? NmtCommandReceived;

Event Type

EventHandler<NmtCommandReceivedEventArgs>

ICanOpenNode.NodeGuardingReceived Event

Raised whenever a node-guarding response (data frame on 0x700 + producer with the toggle bit in bit 7 and the NMT state in bits 0..6) is received for a configured node-guarding consumer (FR-CO-009 / CiA 301 §7.2.8.3.2.1). A response whose toggle bit repeats the previous one is "handled as if it was not received" (§7.2.8.3.2.1): it raises no event and does not re-arm the life time, so a producer that stops alternating is reported through NodeGuardingTimeout.

event EventHandler<NodeGuardingReceivedEventArgs>? NodeGuardingReceived;

Event Type

EventHandler<NodeGuardingReceivedEventArgs>

ICanOpenNode.NodeGuardingTimeout Event

Raised when a configured node-guarding consumer's life-time (guardTime × lifeTimeFactor) elapses without seeing an answer to the RTR poll (FR-CO-009). Not discarded when the event queue is over EventQueueCapacity — losing it would leave the peer looking alive. While a timeout for the same producer is still waiting for the handler, a further one is folded into it rather than queued again, unless a guarding response from that producer was queued in between. The event that waits then reports the newest settings.

event EventHandler<NodeGuardingTimeoutEventArgs>? NodeGuardingTimeout;

Event Type

EventHandler<NodeGuardingTimeoutEventArgs>

ICanOpenNode.RpdoReceived Event

Raised after an RPDO the local node has mapped is received and unpacked into the OD — immediately for an event-driven RPDO, with the next SYNC for a synchronous one.

event EventHandler<RpdoReceivedEventArgs>? RpdoReceived;

Event Type

EventHandler<RpdoReceivedEventArgs>

ICanOpenNode.SyncReceived Event

Raised whenever a SYNC frame is received on the configured SYNC COB-ID (1005h), either from a remote producer or from this node's own producer if echo is on. Not raised in NMT state Stopped, where SYNC is not active (CiA 301 Table 37).

event EventHandler<SyncReceivedEventArgs>? SyncReceived;

Event Type

EventHandler<SyncReceivedEventArgs>