Skip to content

IsoTpFrameCodec Class

Deterministic, side-effect-free codec for ISO 15765-2 (ISO-TP) Protocol-Control-Information frames on classic CAN and CAN-FD. This assembly deliberately contains no scheduler, no channel, no runtime and no vendor-adapter reference; every method here is a pure function over spans and value types.

public static class IsoTpFrameCodec

Inheritance Object → IsoTpFrameCodec

Remarks

The codec is agnostic about how the produced payload will be wrapped in a CanFrame — callers know whether they want classic CAN or CAN-FD and construct the frame with the appropriate factory (this avoids the inverted-frame-kind defect of the earlier prototype; see FR-TP-003).

Frame-length capacity is controlled by the isCanFd flag passed to the builders: classic CAN yields at most 8 bytes on the wire; CAN-FD yields up to 64 bytes and pads to the next valid CAN-FD DLC step (8, 12, 16, 20, 24, 32, 48, 64).

Fields

IsoTpFrameCodec.CanFdMaxData Field

Maximum CAN data-length for a CAN-FD frame (64 bytes).

public const int CanFdMaxData = 64;

Field Value

Int32

IsoTpFrameCodec.ClassicCanMaxData Field

Maximum CAN data-length for a classic-CAN frame (8 bytes).

public const int ClassicCanMaxData = 8;

Field Value

Int32

IsoTpFrameCodec.DefaultPaddingByte Field

Default padding byte per ISO 15765-2 recommendation (`0xCC` is a common choice; `0xAA` and `0x00` are also seen). Only used when the caller requests padding.

public const byte DefaultPaddingByte = 204;

Field Value

Byte

IsoTpFrameCodec.FirstConsecutiveSequenceNumber Field

Sequence number the first Consecutive Frame after a First Frame must carry.

public const byte FirstConsecutiveSequenceNumber = 1;

Field Value

Byte

IsoTpFrameCodec.MaxClassicFirstFrameLength Field

Maximum length that fits in the 12-bit classic First-Frame length field.

public const int MaxClassicFirstFrameLength = 4095;

Field Value

Int32

IsoTpFrameCodec.MaxFdFirstFrameLength Field

Maximum length that fits in the 32-bit CAN-FD First-Frame escape length field.

public const uint MaxFdFirstFrameLength = 4294967295;

Field Value

UInt32

IsoTpFrameCodec.SequenceNumberModulus Field

Modulus for the CF sequence number (SN wraps 0..15).

public const int SequenceNumberModulus = 16;

Field Value

Int32

Methods

IsoTpFrameCodec.BuildConsecutiveFrame(IsoTpEndpoint, byte, ReadOnlySpan<byte>, bool, bool, byte) Method

Writes a Consecutive-Frame CAN payload with sequence number sequenceNumber (0..15) and the given data chunk. Allocates and returns a freshly sized Byte[].

public static byte[] BuildConsecutiveFrame(in CanKit.Pro.IsoTp.IsoTpEndpoint endpoint, byte sequenceNumber, System.ReadOnlySpan<byte> chunk, bool isCanFd, bool padding, byte paddingByte=204);

Parameters

endpoint IsoTpEndpoint

sequenceNumber Byte

chunk ReadOnlySpan<Byte>

isCanFd Boolean

padding Boolean

paddingByte Byte

Returns

Byte[]

IsoTpFrameCodec.BuildConsecutiveFrame(Span<byte>, IsoTpEndpoint, byte, ReadOnlySpan<byte>, bool, bool, byte) Method

Writes a Consecutive-Frame CAN payload into destination. Returns the actual number of bytes written.

public static int BuildConsecutiveFrame(System.Span<byte> destination, in CanKit.Pro.IsoTp.IsoTpEndpoint endpoint, byte sequenceNumber, System.ReadOnlySpan<byte> chunk, bool isCanFd, bool padding, byte paddingByte=204);

Parameters

destination Span<Byte>

endpoint IsoTpEndpoint

sequenceNumber Byte

chunk ReadOnlySpan<Byte>

isCanFd Boolean

padding Boolean

paddingByte Byte

Returns

Int32

Exceptions

ArgumentOutOfRangeException
The chunk does not fit in a Consecutive Frame for the requested frame kind / addressing, or destination is too small.

IsoTpFrameCodec.BuildFirstFrame(IsoTpEndpoint, int, ReadOnlySpan<byte>, bool) Method

Writes a First-Frame CAN payload announcing a segmented PDU of totalLength bytes and containing the first firstChunk user bytes. Allocates and returns a freshly sized Byte[].

public static byte[] BuildFirstFrame(in CanKit.Pro.IsoTp.IsoTpEndpoint endpoint, int totalLength, System.ReadOnlySpan<byte> firstChunk, bool isCanFd);

Parameters

endpoint IsoTpEndpoint

totalLength Int32

firstChunk ReadOnlySpan<Byte>

isCanFd Boolean

Returns

Byte[]

IsoTpFrameCodec.BuildFirstFrame(Span<byte>, IsoTpEndpoint, int, ReadOnlySpan<byte>, bool) Method

Writes a First-Frame CAN payload into destination. First Frames never use padding — they always fill the underlying CAN frame completely.

public static int BuildFirstFrame(System.Span<byte> destination, in CanKit.Pro.IsoTp.IsoTpEndpoint endpoint, int totalLength, System.ReadOnlySpan<byte> firstChunk, bool isCanFd);

Parameters

destination Span<Byte>

endpoint IsoTpEndpoint

totalLength Int32

firstChunk ReadOnlySpan<Byte>

isCanFd Boolean

Returns

Int32

Exceptions

ArgumentOutOfRangeException
totalLength is negative or exceeds the addressable range for the requested frame kind; classic-CAN cannot address totals > 4095 (FF escape form is CAN-FD-only per ISO 15765-2).

Remarks

User bytes copied from firstChunk are capped to min(firstChunk.Length, frame capacity, totalLength) so the on-wire data never exceeds the PDU size announced in the FF_DL field (fixes bugbot 3596393504).

IsoTpFrameCodec.BuildFlowControl(IsoTpEndpoint, FlowStatus, byte, byte, bool, bool, byte) Method

Writes a Flow-Control CAN payload with the given flowStatus, blockSize and stMinRaw. Allocates and returns a freshly sized Byte[].

public static byte[] BuildFlowControl(in CanKit.Pro.IsoTp.IsoTpEndpoint endpoint, CanKit.Pro.IsoTp.FlowStatus flowStatus, byte blockSize, byte stMinRaw, bool isCanFd, bool padding, byte paddingByte=204);

Parameters

endpoint IsoTpEndpoint

flowStatus FlowStatus

blockSize Byte

stMinRaw Byte

isCanFd Boolean

padding Boolean

paddingByte Byte

Returns

Byte[]

IsoTpFrameCodec.BuildFlowControl(Span<byte>, IsoTpEndpoint, FlowStatus, byte, byte, bool, bool, byte) Method

Writes a Flow-Control CAN payload into destination. Returns the actual number of bytes written. Padding is applied <em>after</em> the BS/STmin bytes, so those are never overwritten (fixes review §1.1 point 3).

public static int BuildFlowControl(System.Span<byte> destination, in CanKit.Pro.IsoTp.IsoTpEndpoint endpoint, CanKit.Pro.IsoTp.FlowStatus flowStatus, byte blockSize, byte stMinRaw, bool isCanFd, bool padding, byte paddingByte=204);

Parameters

destination Span<Byte>

endpoint IsoTpEndpoint

flowStatus FlowStatus

blockSize Byte

stMinRaw Byte

isCanFd Boolean

padding Boolean

paddingByte Byte

Returns

Int32

IsoTpFrameCodec.BuildSingleFrame(IsoTpEndpoint, ReadOnlySpan<byte>, bool, bool, byte) Method

Writes a Single-Frame CAN payload for the given userData into a freshly allocated Byte[] and returns it. See BuildSingleFrame(Span<byte>, IsoTpEndpoint, ReadOnlySpan<byte>, bool, bool, byte) for the span-based, allocation-free variant.

public static byte[] BuildSingleFrame(in CanKit.Pro.IsoTp.IsoTpEndpoint endpoint, System.ReadOnlySpan<byte> userData, bool isCanFd, bool padding, byte paddingByte=204);

Parameters

endpoint IsoTpEndpoint

userData ReadOnlySpan<Byte>

isCanFd Boolean

padding Boolean

paddingByte Byte

Returns

Byte[]

IsoTpFrameCodec.BuildSingleFrame(Span<byte>, IsoTpEndpoint, ReadOnlySpan<byte>, bool, bool, byte) Method

Writes a Single-Frame CAN payload for the given userData into destination. Returns the actual number of bytes written; the destination buffer must be at least ClassicCanMaxData (or CanFdMaxData for CAN-FD) bytes long.

public static int BuildSingleFrame(System.Span<byte> destination, in CanKit.Pro.IsoTp.IsoTpEndpoint endpoint, System.ReadOnlySpan<byte> userData, bool isCanFd, bool padding, byte paddingByte=204);

Parameters

destination Span<Byte>

endpoint IsoTpEndpoint

userData ReadOnlySpan<Byte>

isCanFd Boolean

padding Boolean

paddingByte Byte

Returns

Int32

Exceptions

ArgumentOutOfRangeException
userData is empty, exceeds the Single-Frame capacity for the requested frame-kind/addressing combination, or destination is too small.

Remarks

ISO 15765-2 does not define an empty Single Frame: on classic CAN the SF_DL low-nibble range is 1..7, and on CAN-FD the escape-form LEN byte likewise starts at 1. A zero-length SF is therefore rejected at build time to prevent producing an on-wire frame that no conformant peer could parse (fixes bugbot 3594958440).

IsoTpFrameCodec.ConsecutiveFrameMaxDataLength(bool, bool) Method

Returns the maximum number of user-data bytes carried in a Consecutive Frame. CF uses a 1-byte PCI on both classic CAN and CAN-FD.

public static int ConsecutiveFrameMaxDataLength(bool isCanFd, bool usesAddressExtension);

Parameters

isCanFd Boolean

usesAddressExtension Boolean

Returns

Int32

IsoTpFrameCodec.DecodeStMin(byte) Method

Decodes an ISO 15765-2 STmin raw byte into a TimeSpan. Reserved values (0x80..0xF0 and 0xFA..0xFF) are treated as 0x7F = 127 ms per the specification, which fixes review §1.1 point 6 / FR-TP-007 / FR-RAW-052.

public static System.TimeSpan DecodeStMin(byte raw);

Parameters

raw Byte

Returns

TimeSpan

IsoTpFrameCodec.EncodeStMin(TimeSpan) Method

Encodes a TimeSpan STmin value as an ISO 15765-2 raw byte. - 0..127 ms in 1-ms steps → 0x00..0x7F - 100..900 µs in 100-µs steps → 0xF1..0xF9

public static byte EncodeStMin(System.TimeSpan value);

Parameters

value TimeSpan

Returns

Byte

Exceptions

ArgumentOutOfRangeException
value is negative.

Remarks

The commonly-used values 0 ms and 1 ms encode as 0x00 and 0x01 respectively (fixes review §1.1 point 5). Values that fall between the two ISO 15765-2 ranges (e.g. 999 µs) or exceed 127 ms are clamped to the nearest representable value.

IsoTpFrameCodec.FirstFrameMaxDataLength(bool, bool, bool) Method

Returns the number of user-data bytes carried in the First Frame of a segmented PDU.

public static int FirstFrameMaxDataLength(bool isCanFd, bool usesAddressExtension, bool useLongLength);

Parameters

isCanFd Boolean

true for CAN-FD, false for classic CAN.

usesAddressExtension Boolean

true when the endpoint burns the first payload byte for an address-extension byte.

useLongLength Boolean

true when the FF must carry the 32-bit CAN-FD escape length (for total lengths > 4095); ignored for classic CAN.

Returns

Int32

Remarks

Classic-CAN FF has a 2-byte PCI, so the classic capacity is 8 - 2 - extension (6 bytes without extension). CAN-FD FF uses the same 2-byte PCI for lengths up to 4095, or a 6-byte PCI (`FF nibble | 0x00`, `0x00`, then a 32-bit length) when useLongLength is true.

IsoTpFrameCodec.NextConsecutiveSequenceNumber(byte) Method

Returns the next CF sequence number after current (wraps 0..15).

public static byte NextConsecutiveSequenceNumber(byte current);

Parameters

current Byte

Returns

Byte

IsoTpFrameCodec.NextValidFrameLength(int, bool) Method

Returns the next valid CAN-FD DLC data length that is greater than or equal to dataLength. Classic CAN always pads to 8 bytes.

public static int NextValidFrameLength(int dataLength, bool isCanFd);

Parameters

dataLength Int32

Number of user bytes that must fit (0..64 for CAN-FD, 0..8 for classic).

isCanFd Boolean

true to use the CAN-FD DLC ladder, false to pad to 8.

Returns

Int32

Exceptions

ArgumentOutOfRangeException
dataLength is negative, exceeds 8 for classic CAN, or exceeds 64 for CAN-FD.

IsoTpFrameCodec.SingleFrameMaxDataLength(bool, bool) Method

Returns the maximum number of user-data bytes that fit into a Single Frame on a given frame-kind and addressing mode.

public static int SingleFrameMaxDataLength(bool isCanFd, bool usesAddressExtension);

Parameters

isCanFd Boolean

true for CAN-FD (up to 64-byte frames), false for classic CAN.

usesAddressExtension Boolean

true when the endpoint burns the first payload byte for an address-extension byte.

Returns

Int32

Remarks

Classic-CAN SF uses a 1-byte PCI, so the classic capacity is 8 - 1 - (extension ? 1 : 0). CAN-FD SF supports the same 1-byte PCI plus a 2-byte escape form (`PCI = 0x00`, `LEN` byte) that unlocks the full CAN-FD payload up to 64 - 2 - (extension ? 1 : 0).

IsoTpFrameCodec.SingleFrameShortFormMaxDataLength(bool) Method

Returns the maximum number of Single-Frame data bytes that still fit into the classic 1-byte PCI form (SF_DL in the low nibble, 1..7). Beyond this and up to SingleFrameMaxDataLength(bool, bool) the CAN-FD escape form (`0x00 LEN`) must be used.

public static int SingleFrameShortFormMaxDataLength(bool usesAddressExtension);

Parameters

usesAddressExtension Boolean

Returns

Int32

IsoTpFrameCodec.TryParsePci(ReadOnlySpan<byte>, IsoTpEndpoint, bool, Pci) Method

Bounds-checked parser for the ISO-TP Protocol-Control-Information of a received CAN frame. Never throws IndexOutOfRangeException — a truncated frame returns false with pci set to default (fixes review §1.1 point 6).

public static bool TryParsePci(System.ReadOnlySpan<byte> canPayload, in CanKit.Pro.IsoTp.IsoTpEndpoint endpoint, bool isCanFd, out CanKit.Pro.IsoTp.Pci pci);

Parameters

canPayload ReadOnlySpan<Byte>

Raw CAN data payload (up to 8 bytes for classic CAN, up to 64 bytes for CAN-FD).

endpoint IsoTpEndpoint

Endpoint whose addressing mode decides whether the first payload byte is the address-extension byte.

isCanFd Boolean

true when the caller knows the frame was received as a CAN-FD frame, false for classic CAN. The Single-Frame and First-Frame escape forms (PCI 0x00 LEN … and PCI 0x10 0x00 LEN[4] …) are only defined on CAN-FD per ISO 15765-2, so this flag is required to distinguish a legitimate escape header from a malformed classic-CAN PCI whose SF_DL / FF_DL is zero (fixes review §1.1 point 8 / bugbot 3594958440 / 3594958445).

pci Pci

On success, the parsed PCI view.

Returns

Boolean
true when the frame has enough bytes and a valid PCI nibble; false for truncated frames, reserved PCI nibbles (> 3), reserved Flow-Status values (> 2), escape-form PCIs on classic CAN, or CAN-FD Single-Frame short-form SF_DL values above SingleFrameShortFormMaxDataLength(bool) for the endpoint's addressing mode (those lengths must use the 0x00 LEN escape — 8..15 without address extension, 7..15 with extended/mixed addressing).