ICanBusService Interface¶
One demultiplexing service instance per ICanBus: it turns the single RX stream exposed by ICanBus.FrameObserved into N independent, filtered read-only ISubscriptions, so multiple protocol instances (ISO-TP, J1939, CANopen, …) can each see their own view of the bus without competing over ICanBus.ReceiveAsync(Int32, Int32, CancellationToken) (arc42 §5.3, ADR-5; FR-RAW-010..013).
Derived
↳ CanBusService
Implements IDisposable
Remarks¶
The service is built purely on top of the public ICanBus.FrameObserved surface (a read-only CanFrameView per frame, with no disposal/ownership concerns), so it works identically for every adapter with no per-adapter changes. Disposing the service unwinds all outstanding subscriptions and detaches its handler from the underlying bus (FR-RAW-012). Dispose is idempotent.
Echoes. When the bus is configured for echo (WorkMode == ChannelWorkMode.Echo)
it reports the host's own transmissions back through the same RX stream, flagged as such.
A subscription receives them only if it asked for them, and the flag rides along on every
delivered CanFrameEvent either way. The default is off because the frames a
protocol layer sends are not frames it received: a J1939 node that treats its own Address
Claim as a competitor's, or a CANopen node that acts on its own PDO, is broken in a way
that only shows up on hardware that happens to echo. Before this flag existed each of those
layers each carried their own answer to "is this mine?" — comparing NAMEs, comparing source
addresses, guarding on actor affinity. Those checks are still there and still needed; what
changed is that the flag and the timestamp are now available to a caller who wants them.
Two limits, both of which make the gate a convenience rather than a guarantee.
First, it can only drop what the adapter flags: an adapter that echoes without setting
IsEcho — CanKit.Adapter.Virtual in
ChannelWorkMode.Echo does — delivers its echo to every subscription regardless of
includeEcho. Second, and more important, the flag is host-scoped: it says
something on this host transmitted the frame, not which of the possibly several protocol
instances sharing this service did. A sibling instance's traffic is flagged identically
to one's own.
So includeEcho: false suits a single consumer that owns its bus. A protocol layer
that may share a service — every one in this repository does, by documented design — asks
for echoes instead, and must then tell its own traffic apart by something it actually
owns. That is not a workaround for a missing feature: the demux genuinely cannot attribute
a transmission to a local instance.
How far each layer takes that is a per-layer decision, not a guarantee this interface makes. The J1939 transport rejects its own source address, and J1939 rejects its own NAME on an Address Claim. CANopen deliberately does not filter its own non-SYNC traffic by node-id — the state that predates the echo gate — so a CANopen node on a flagging adapter still observes its own PDOs and heartbeats.
Properties¶
ICanBusService.Bus Property¶
The underlying bus this service demultiplexes.
Property Value¶
ICanBusService.SubscriptionCount Property¶
Number of currently registered (not yet disposed) subscriptions. Primarily for diagnostics/tests: after disposing every subscription it returns to zero, proving no registry entries leak (FR-RAW-012).
Property Value¶
Methods¶
ICanBusService.FindOverlappingFilterSubscriptions() Method¶
Diagnostic: finds every pair of currently registered, still-undisposed CanIdFilter-based subscriptions whose ID spaces overlap, and the range of CAN IDs each pair shares (FR-RAW-041, "Should") -- helps catch misconfiguration when multiple protocol instances were meant to have disjoint ID ranges but don't. Subscriptions registered via the generic Subscribe(Func<CanFrameEvent,bool>, Nullable<int>, bool) predicate overload are opaque and are not analyzable, so they are skipped.
System.Collections.Generic.IReadOnlyList<CanKit.Pro.RawCan.FilterOverlap> FindOverlappingFilterSubscriptions();
Returns¶
IReadOnlyList<FilterOverlap>
One FilterOverlap per overlapping pair, each naming the two subscriptions
and the ID range on which they collide. Empty when no two filters share ID space.
ICanBusService.SendConfirmed(CanFrame, Nullable<TimeSpan>, CancellationToken) Method¶
Sends frame and asynchronously confirms it was actually sent, using
a uniform abstraction regardless of whether the underlying bus has hardware TX echo
enabled (arc42 §6.3, ADR-7; FR-RAW-030). When the bus both declares
Echo and has WorkMode == ChannelWorkMode.Echo configured,
confirmation comes from an actually-matched echo frame (FR-RAW-031, including correct
FIFO matching of multiple concurrent byte-identical sends — no cross-matching or crash);
otherwise it is a documented approximation based on driver acceptance
(IsApproximated, FR-RAW-032). Never hangs: timeout,
bus-off, and outright rejection all resolve the returned task within bounded time
(FR-RAW-033) — see TxConfirmation for exactly how.
System.Threading.Tasks.Task<CanKit.Pro.RawCan.TxConfirmation> SendConfirmed(CanKit.Abstractions.API.Can.Definitions.CanFrame frame, System.Nullable<System.TimeSpan> timeout=null, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));
Parameters¶
frame CanFrame
The frame to send. As with ICanBus.Transmit(CanFrame@), the caller remains the owner (TX-lease) and is responsible for disposing it after this call returns/completes — ICanBusService never disposes it.
Maximum time to wait for an echo before failing with Timeout (FR-RAW-034); null uses DefaultConfirmTimeout. Ignored on the approximated path (driver acceptance is synchronous/immediate). Must be positive.
cancellationToken CancellationToken
Caller-supplied cancellation; cancels the returned task per standard .NET convention, distinct from the domain-level Timeout outcome.
Returns¶
ICanBusService.Subscribe(CanIdFilter, Nullable<int>, bool) Method¶
Registers a subscription using the allocation-free ID-range/mask fast path (FR-RAW-010/013).
CanKit.Pro.RawCan.ISubscription Subscribe(CanKit.Pro.RawCan.CanIdFilter filter, System.Nullable<int> bufferCapacity=null, bool includeEcho=false);
Parameters¶
filter CanIdFilter
ID-range or acceptance-code/mask filter.
bufferCapacity Nullable<Int32>
Bounded buffer capacity for this subscription; null uses DefaultBufferCapacity.
includeEcho Boolean
Whether this subscription also receives the local host's own transmit echoes; false by default. See the predicate overload above.
Returns¶
ICanBusService.Subscribe(Func<CanFrameEvent,bool>, Nullable<int>, bool) Method¶
Registers a subscription that receives every frame for which predicate returns true; a null predicate accepts all frames (FR-RAW-010).
CanKit.Pro.RawCan.ISubscription Subscribe(System.Func<CanKit.Pro.RawCan.CanFrameEvent,bool>? predicate=null, System.Nullable<int> bufferCapacity=null, bool includeEcho=false);
Parameters¶
predicate Func<CanFrameEvent,Boolean>
Per-frame filter, or null to accept all frames. Runs on the bus's dispatch thread before the payload is copied, so the Frame it inspects aliases the adapter's RX lease and must not be retained beyond the call. It is never offered an echo unless includeEcho is set.
bufferCapacity Nullable<Int32>
Bounded buffer capacity for this subscription; null uses DefaultBufferCapacity. When the buffer is full the oldest buffered frame is dropped so dispatch never blocks (FR-RAW-011).
includeEcho Boolean
Whether this subscription also receives the local host's own transmit echoes. Defaults
to false: a protocol layer that sees its own transmissions come back as if they
were peer traffic misbehaves in ways that are tedious to diagnose, so opting in is a
decision the caller makes deliberately (see the remarks below).
Returns¶
Events¶
ICanBusService.BackgroundExceptionOccurred Event¶
Raised when a caller-supplied subscription filter predicate throws during dispatch (FR-RAW-023-style fault channel). The failing frame is isolated to that subscription (delivery to the other subscriptions continues), and the exception is surfaced here instead of being silently swallowed. Invoked synchronously on the bus's dispatch thread, so handlers must return quickly and must not call back into the service.