CanFrameEvent Struct¶
One frame as a subscription saw it: the frame itself, whether it is this host's own transmit echo, and the timestamp the adapter recorded for it (FR-RAW-015).
Implements IEquatable<CanFrameEvent>
Remarks¶
This is what Frames yields. It exists because the bus already
knows all three facts — ICanBus.FrameObserved carries them on
CanReceiveDataView — and the demux used to forward only the frame, discarding the
other two before any subscriber could see them.
That loss was not cosmetic: the echo flag and the timestamp were simply unavailable above the demux, however much a caller wanted them. What it is not is a replacement for the self-traffic checks the protocol layers carry. IsEcho is host-scoped and only as reliable as the adapter that sets it, so J1939 still compares NAMEs, the J1939 transport still compares source addresses, and CANopen's actor-provenance guard answers a different question entirely (which thread applied an OD write, not which node sent a frame). All three are retained deliberately — see the remarks on IsEcho for why the flag cannot stand in for them.
A CanKit.Pro type rather than the upstream CanReceiveDataView: the payload of a
buffered frame has to be copied (the adapter may return the RX lease to its pool while a
subscriber has not read it yet), and rebuilding an upstream event payload around a copied
frame would tie this package's public surface to a type it does not own. Note that the
copy is made for buffered events only — see Frame for the two lifetimes.
Constructors¶
CanFrameEvent(CanFrameView, bool, TimeSpan) Constructor¶
Creates an event. The caller is responsible for frame owning its payload; see the remarks on CanFrameEvent.
public CanFrameEvent(CanKit.Abstractions.API.Can.Definitions.CanFrameView frame, bool isEcho, System.TimeSpan receiveTimestamp);
Parameters¶
frame CanFrameView
isEcho Boolean
receiveTimestamp TimeSpan
Properties¶
CanFrameEvent.Frame Property¶
The frame.
Property Value¶
Remarks¶
<b>Two lifetimes, depending on where you received this event.</b> An event read from Frames or TryRead(CanFrameEvent) owns its payload buffer and stays valid indefinitely — the demux copies the payload before buffering it, precisely so the adapter may release the RX lease meanwhile.
An event handed to a subscription predicate does not. The predicate runs on the dispatch thread before the copy is made, so its Frame aliases the adapter's RX lease and must not be retained past the call — a rejected frame is never copied at all, which is what keeps filtering allocation-free. Inspect it, return, and keep nothing.
CanFrameEvent.IsEcho Property¶
True when the bus reported this frame as the local host's own transmit echo.
Property Value¶
Remarks¶
<b>Host, not instance.</b> The bit means "something on this host transmitted this", and nothing finer. Where several protocol instances share one ICanBusService — which every protocol factory in this repository documents as supported — a sibling instance's transmission is flagged exactly like this one's own. Deciding "did *I* send this?" needs an instance-level identity the demux does not have: a source address, a NAME, a node-id.
CanFrameEvent.ReceiveTimestamp Property¶
The receive timestamp the adapter recorded, as reported by the bus. Zero on adapters that do not timestamp; not comparable across buses.
Property Value¶
Methods¶
CanFrameEvent.Equals(CanFrameEvent) Method¶
Value equality over the frame's kind, ID, flags and <em>payload bytes</em>, plus IsEcho and ReceiveTimestamp.
Parameters¶
other CanFrameEvent
Returns¶
Remarks¶
Deliberately not delegating to CanFrameView's own equality. That type is
a record struct holding a System.ReadOnlyMemory<>, whose generated comparison
tests the memory segment — the backing object, offset and length — rather than the
bytes. Since the demux allocates a fresh array per delivered frame, two events carrying
an identical frame to two subscriptions would otherwise never compare equal, which is
the opposite of what a caller writing a == b means.
The cost is that comparison is O(payload), up to 64 bytes for CAN FD. That is the right trade for a type callers compare in assertions and deduplication, but it makes this a poor dictionary key on a hot path.
Operators¶
CanFrameEvent.operator ==(CanFrameEvent, CanFrameEvent) Operator¶
Equality operator.
public static bool operator ==(CanKit.Pro.RawCan.CanFrameEvent left, CanKit.Pro.RawCan.CanFrameEvent right);
Parameters¶
left CanFrameEvent
right CanFrameEvent
Returns¶
CanFrameEvent.operator !=(CanFrameEvent, CanFrameEvent) Operator¶
Inequality operator.
public static bool operator !=(CanKit.Pro.RawCan.CanFrameEvent left, CanKit.Pro.RawCan.CanFrameEvent right);
Parameters¶
left CanFrameEvent
right CanFrameEvent