Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
7059d99
feat(canopen): add DisposeAsync, and let a node be disposed from its …
dborgards Oct 3, 2026
4991838
fix(canopen): dispose from the actor and the reader's failure report …
dborgards Oct 3, 2026
9792880
fix(canopen): run the dispose cleanup in place on the actor, make a c…
dborgards Oct 3, 2026
47145c4
fix(canopen): release a waiting DisposeAsync when the disposal throws…
dborgards Oct 3, 2026
c636a17
feat(canopen): offer DisposeAsync as an extension instead of widening…
dborgards Oct 3, 2026
22dca28
fix(canopen): a subscriber that loses the disposal race still ends th…
dborgards Oct 3, 2026
db290f5
fix(canopen): stop a reset at a subscriber that disposed the node; wa…
dborgards Oct 3, 2026
5292c1a
fix(canopen): drop queued events and stop the reset round when a subs…
dborgards Oct 3, 2026
d9c4eae
fix(canopen): end an event's round at the subscriber that disposed th…
dborgards Oct 3, 2026
bd88c12
fix(canopen): a losing Dispose from the pump stops delivery too, Back…
dborgards Oct 3, 2026
c20bef4
fix(canopen): nested disposals restore the outer thread markers; cove…
dborgards Oct 3, 2026
decf158
fix(canopen): report nothing once the disposal has finished
dborgards Oct 3, 2026
65830c9
fix(canopen): drop the events a stopped pump skipped; state the deliv…
dborgards Oct 3, 2026
b443730
refactor(canopen): no empty loop body when dropping skipped events; d…
dborgards Oct 3, 2026
70db3e8
test(isotp): await the failure report instead of reading it as soon a…
dborgards Oct 3, 2026
a1b75b6
Merge remote-tracking branch 'origin/main' into feat/canopen-disposea…
dborgards Oct 4, 2026
476630f
fix(canopen): keep every active disposal marker of a thread, not only…
dborgards Oct 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/CanKit.Pro.CANopen/CanOpenNode.CommunicationProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,9 @@ private void PerformNmtReset(bool communicationOnly)
// the hook lets the application restore what the description does not hold.
RaiseApplicationReset(communicationOnly ? NmtCommand.ResetCommunication : NmtCommand.ResetNode);

// A subscriber may have disposed the node; its timers are gone and nothing is announced.
if (Volatile.Read(ref _disposed) != 0) return;
Comment thread
dborgards marked this conversation as resolved.

_state = NmtState.PreOperational;
// Boot-up (0x00) first; a heartbeat with the new state follows only when the producer is
// active, in which case §7.2.8.3.2.2 regards the boot-up as its first heartbeat — and the
Expand Down
2 changes: 1 addition & 1 deletion src/CanKit.Pro.CANopen/CanOpenNode.FlyingMaster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ private void RaiseFlyingMaster(FlyingMasterSignal signal, byte? otherNodeId, ush
var args = new FlyingMasterChangedEventArgs(signal, _flyingMasterRole, otherNodeId, otherPriority);
// The dispatcher reports a subscriber throw and keeps going, so a timeout or an
// EMCY already queued is still delivered. A second catch here would only repeat that.
EnqueueEvent(() => FlyingMasterChanged?.Invoke(this, args));
EnqueueEvent(() => DeliverToSubscribers(FlyingMasterChanged, args));
}

private OdWriteDecision ValidateFlyingMasterTimingWrite(byte subindex, byte[] value)
Expand Down
6 changes: 3 additions & 3 deletions src/CanKit.Pro.CANopen/CanOpenNode.NodeGuarding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ private void RaiseLifeGuardingEvent(LifeGuardingState state)
var args = new LifeGuardingEventArgs(state, _guardTime, _lifeTimeFactor);
EnqueueEvent(() =>
{
try { LifeGuardingEvent?.Invoke(this, args); }
try { DeliverToSubscribers(LifeGuardingEvent, args); }
catch (Exception ex) { RaiseBackgroundException(ex); }
});
}
Expand All @@ -354,7 +354,7 @@ private void RaiseNodeGuardingReceived(byte producer, NmtState state, bool toggl
var args = new NodeGuardingReceivedEventArgs(producer, state, toggle, ts);
EnqueueEvent(() =>
{
try { NodeGuardingReceived?.Invoke(this, args); }
try { DeliverToSubscribers(NodeGuardingReceived, args); }
catch (Exception ex) { RaiseBackgroundException(ex); }
}, critical: false, key: null, emcyProducer: -1, producer);
}
Expand All @@ -364,7 +364,7 @@ private void RaiseNodeGuardingTimeout(byte producer, TimeSpan guardTime, byte li
var args = new NodeGuardingTimeoutEventArgs(producer, guardTime, lifeTimeFactor);
EnqueueEvent(() =>
{
try { NodeGuardingTimeout?.Invoke(this, args); }
try { DeliverToSubscribers(NodeGuardingTimeout, args); }
catch (Exception ex) { RaiseBackgroundException(ex); }
}, critical: true, EventKey.NodeGuardingTimeout(producer), emcyProducer: -1, producer);
}
Expand Down
Loading
Loading