CRC-protected line framing for embedded serial links
Project description
crclink
CRC-protected, line-based transport framing for serial-style embedded links.
crclink ships both sides of the wire: a Python library for the host and a C firmware companion for the device, so the same frames build, verify, and decode on either end.
- Host (Python): this package. Encode, decode, and verify frames, plus a
crclinkCLI. Install withuv add crclink. - Device (C): a no-heap, no-runtime-dependency implementation under src/c/. It builds and CRC-stamps frames straight to a serial sink and verifies/reads incoming flat-JSON commands. See src/c/README.md.
Both sides compute CRC-16/XMODEM over the same coverage, so a frame built on one verifies on the other; the test suites cross-check both directions.
Features
- JSON line framing with a trailing crc key.
- Text line framing with trailing CRC suffix.
- CRC-16/XMODEM validation.
- Matching Python (host) and C (device) implementations.
CRC engine
crclink computes CRC-16/XMODEM through crcglot rather than reimplementing it. crcglot owns the algorithm and its parameters; crclink just names the algorithm and calls the engine (crcglot.compute(data, "crc16-xmodem")), so the CRC definition lives in one place. crcglot is pure-stdlib, so depending on it at runtime pulls in no extra packages. crclink pins crcglot>=0.21.0.
See docs/crcglot-integration.md for the integration details: the host vs. firmware split and the cross-end test vectors.
CLI
Installing crclink puts a crclink command on your path. It encodes and decodes single frames, and verifies a whole file of them.
# Encode (prints the framed line)
crclink encode-json '{"t":1234,"v":42}' # -> {"t":1234,"v":42,"crc":"1352"}
crclink encode-text "PING" # -> PING e0e7
crclink encode-text "PING" --prefix 0x # -> PING 0xe0e7
# Decode and verify one frame (prints a JSON result, exit 1 on a bad CRC)
crclink decode-json '{"t":1234,"v":42,"crc":"1352"}'
crclink decode-text "PING e0e7"
# Verify every frame in a file, line by line
crclink verify-file frames.jsonl --format json # a file of JSON lines
crclink verify-file log.txt --format text # a file of text lines
crclink verify-file mixed.lines # auto-detect each line
cat frames | crclink verify-file - # read from stdin
verify-file skips blank lines, reports each line as ok or FAIL with its number and reason, prints a verified X/Y summary, and exits non-zero if any line fails (so it slots into a shell pipeline). With auto (the default) a line starting with { is treated as JSON and anything else as text. Use --quiet to print only failures and the summary.
On the device (C)
The firmware speaks the same frames both ways: verify an incoming command, read its fields by key, then build and CRC-stamp the reply. Numbers are converted for you, with no heap and no runtime dependencies. Here a host sends the monitor command mem byte 0x1234 and the device returns the byte at that address (cmd: uint32 -> v: uint8):
#include "crclink_json.h" // build the reply frame
#include "crclink_json_read.h" // read the incoming command
void handle_line(const char *line) { // {"cmd":"mem byte 0x1234","crc":"5993"}
if (crclink_json_verify(line) != 0) return; // bad CRC: drop the frame
char cmd[32];
if (crclink_json_get_str(line, "cmd", cmd, sizeof cmd) < 0) return;
uint32_t addr; // pull the address out (your parser)
if (sscanf(cmd, "mem byte %" SCNx32, &addr) != 1) return;
uint8_t value = *(volatile uint8_t *)(uintptr_t)addr; // read the address
crclink_json_t j;
crclink_json_start(&j, uart_sink, NULL); // your per-byte serial sink
crclink_json_int_add(&j, "v", value);
crclink_json_end(&j); // -> {"v":42,"crc":"37c2"}
}
The reply streams out a byte at a time through your sink and decodes on the host with crclink.decode_json_frame. See src/c/README.md for the builder and reader APIs in full, failure handling, and filling a C struct from a command.
Install
uv add crclink
Development
uv sync
uv run pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file crclink-0.1.0.tar.gz.
File metadata
- Download URL: crclink-0.1.0.tar.gz
- Upload date:
- Size: 95.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b979202290844a00607735ba6177dea6df8d153e7938c9d6e1dddd639c08bba
|
|
| MD5 |
af08f1e8a82eceb87b6563f9f318cdb1
|
|
| BLAKE2b-256 |
ef44532d340c41c9246ca249bdd95010b81d43923ce9a14a270aa9d01f03ae38
|
File details
Details for the file crclink-0.1.0-py3-none-any.whl.
File metadata
- Download URL: crclink-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd1b044935446c992fce55323aec615ba694c2dbf143eeee7cd76b5a54b1152e
|
|
| MD5 |
bfd428d302ea3f8b1ab7d61ab006a2ef
|
|
| BLAKE2b-256 |
96e03c5f98970bea14da1329d25f795a26ed147d77720c0d155ec6bab14c0e34
|