TestBench.tools
GitHub

Binary Frame Workbench

Declare a custom frame layout once; decode fields and check the CRC of every pasted frame.

Examples
Checksum
Fields
NameOffsetTypeEndian

3 frames · 2 OK · 1 FAIL

#LenChecksumseqtempstatus
18OK72251
28OK82350
38FAIL92450
Frame 1, byte by byte
A50061072003E140151860A7

computed 0x0A18 over bytes 0–5, frame carries 0x0A18

The link carries the layout only — never your frames — and sits after the #, which browsers do not send to the server.

This workbench decodes binary frames from a custom protocol. Declare the layout once — typed fields at fixed offsets, and where the checksum sits and what it covers — then paste any number of hex frames: each one gets its fields decoded and its checksum marked OK or FAIL, with the bytes coloured by the field they belong to. The layout exports as a FrameTerm project, so the same definition runs against live serial traffic in the desktop app.

Worked example: FrameTerm's demo protocol

FrameTerm's built-in demo sends 8-byte frames: a sync byte A5, a length byte, a sequence number, a temperature as a signed 16-bit big-endian value in tenths of a degree, a status byte, and a CRC-16/MODBUS sent low byte first. Every tenth frame is corrupted on purpose.

A5 06 07 00 E1 01 18 0A → OK seq 7 · temp 225 · status 1
A5 06 08 00 EB 00 DC 7E → OK seq 8 · temp 235 · status 0
A5 06 09 00 F5 00 2B DD → FAIL seq 9 · temp 245 · status 0

Temperature 225 is 22.5 °C. These rows are not typed in by hand: they come from running FrameTerm's own engine on the same layout, and this page's decoder is tested against them.

Why the checksum fails when the data is right

A FAIL on a frame you believe is good is almost always the layout. Take the classic Modbus RTU request to read ten holding registers:

01 03 00 00 00 0A C5 CD
CRC-16/MODBUS over bytes 0–5 = 0xCDC5
little-endian (low byte first): frame carries 0xCDC5 → OK
big-endian (high byte first): frame carries 0xC5CD → FAIL

Same bytes, same algorithm, opposite verdict — only the checksum's byte order changed. The other two usual suspects are coverage (a sync byte the CRC skips) and the variant (CRC-16/MODBUS versus CRC-16/CCITT-FALSE). The selected frame always shows the value computed, the value carried and the byte range covered, so the mismatch is visible rather than guessed at.

Parameters

ParameterValueNotes
Field typesu8 · s8 · u16 · s16 · u32 · s32 · f32per-field byte order
ChecksumsCRC-16/MODBUS · CRC-16/CCITT-FALSE · CRC-32 · CRC-8 · XOR8 · SUM8
Placementbytes from end + coverage rangeone layout fits frames of any length
Short framesfield shows N/Aonly that field degrades
Project files.ftproj import / exportopens in FrameTerm
Sharelayout in the URL fragmentframes are never included

The layout model is FrameTerm's, deliberately: when pasted frames are not enough, FrameTerm runs the exported layout on a live serial port or TCP link, with framing, highlight rules and a send composer.

Python equivalent

Python
# The same decode in Python: FrameTerm's demo frame
import struct

frame = bytes.fromhex("A5 06 07 00 E1 01 18 0A")

def crc16_modbus(data: bytes) -> int:
    crc = 0xFFFF
    for b in data:
        crc ^= b
        for _ in range(8):
            crc = (crc >> 1) ^ 0xA001 if crc & 1 else crc >> 1
    return crc

body, carried = frame[:-2], struct.unpack("<H", frame[-2:])[0]
print("checksum", "OK" if crc16_modbus(body) == carried else "FAIL")
seq = frame[2]
temp = struct.unpack(">h", frame[3:5])[0]   # s16 big-endian
status = frame[5]
print(seq, temp, status)                    # 7 225 1

FAQ

▸How do I decode a custom binary protocol frame?

Write down the layout once — where each field starts, how many bytes it takes, whether it is signed, float or unsigned, and which byte comes first — plus where the checksum sits and which bytes it covers. Then every frame is just that layout applied to bytes. This tool takes the layout as a table, so pasting twenty frames decodes twenty rows instead of twenty sessions with a calculator.

▸Why does my CRC fail when the bytes look right?

Usually one of three settings, not the data: the byte order of the checksum in the frame (Modbus RTU sends the CRC low byte first, so 0xCDC5 travels as C5 CD), the coverage range (many protocols exclude a sync byte from the CRC), or the algorithm variant (CRC-16/MODBUS and CRC-16/CCITT-FALSE are both 'CRC-16' and give different answers). The selected frame shows the computed value, the value the frame carries and the exact byte range covered, so you can see which of the three it is.

▸What do 'bytes from end' and 'coverage' mean?

They place the checksum relative to the end of the frame, which is what makes one layout work for frames of different lengths. 'Bytes from end' = 2 means the checksum starts two bytes before the end. Coverage runs from 'coverage from byte' up to the coverage end — with the end set to 2, the checksum covers everything before itself. A protocol with a 7E sync byte the CRC skips sets coverage to start at byte 1.

▸What is the difference between little-endian and big-endian fields?

Byte order inside a multi-byte field. The bytes 34 12 read as a little-endian u16 are 0x1234 = 4660; read big-endian they are 0x3412 = 13330. Modbus registers and most network protocols are big-endian; x86, ARM Cortex-M and most binary structs on a microcontroller are little-endian. Getting it wrong never errors — it just produces a plausible wrong number, which is why the decoded value sits next to the coloured bytes it came from.

▸Can I open this layout in FrameTerm?

Yes. 'Export .ftproj' writes a FrameTerm project file with the same checksum and field definitions, and FrameTerm opens it directly — then the layout runs against live serial or TCP traffic instead of pasted frames. Importing a .ftproj works the other way, and keeps the project's framing, highlights and macros so exporting again loses nothing.

▸Is anything uploaded when I share a link?

No. A share link carries only the layout, never the frames, and it sits after the # in the URL — the part browsers keep to themselves and do not send to any server. Frames, imports and exports are all handled in your browser.

Related tools