Post

Bitlab Tooklit🔧

Bitlab Tooklit🔧

PyPI CI Downloads License: MIT

bitlab is an open-source toolkit built for embedded systems, binary data, and digital communications, the kind of bit-twiddling every firmware engineer ends up hand-rolling at some point: parity checking, Hamming error correction, CRC, and hardware register bit-fields.

1
pip install bitlab

🧠 Design. Understand. Ship it.

Most CRC libraries hand you a black box. bitlab is built around three layers instead:

LayerWhat it’s for
ComputeFast, production-ready functions (crc32(), pack(), …)
ExplainThe same computation, narrated bit by bit — for learning or debugging
ExportCompiled-and-tested C source, ready to drop onto the embedded target
1
2
3
4
5
6
7
8
>>> from bitlab.crc import explain, CRC8_SMBUS
>>> print(explain(b"AB", CRC8_SMBUS))
CRC algorithm: CRC-8/SMBUS
  width=8  poly=0x07  init=0x00  refin=False  refout=False  xorout=0x00
Byte 0: 0x41 -> XORed in, register = 0x41
    bit 0: MSB=0 -> shift left -> 0x82
    ...
Final CRC: 0x87

And when you’re ready for hardware, the same config exports straight to a firmware-ready C function:

1
2
>>> from bitlab.crc import export_c, CRC32_ISO_HDLC
>>> print(export_c(CRC32_ISO_HDLC, function_name="my_crc32"))

The test suite actually compiles every generated C function with gcc and checks the output against the official CRC catalogue values, not just “a CRC that happens to run.”

📦 Seven modules, one toolkit

1
2
3
4
5
6
7
8
bitlab/
 ├── bitutils/    foundational bit ops shared by every submodule
 ├── parity/      parity bit checking + Hamming(7,4) error correction
 ├── crc/         CRC-8/16/32, generic engine, explain(), export_c()
 ├── registers/   hardware register bit-field mapper, explain(), export_c()
 ├── arch/        IEEE 754, endianness, Gray code, Q-format fixed-point
 ├── comms/       COBS framing, explain_cobs(), export_c()
 └── ecc/         Reed-Solomon burst error correction, explain(), export_c()

A couple of favorites:

Registers — define a hardware register’s layout once, then pack/unpack named fields instead of shifting magic numbers by hand:

1
2
3
4
5
6
7
8
from bitlab.registers import Register, export_c

reg = Register("UART_CR1", size_bits=8)
reg.add_field("ENABLE", bit_index=0)
reg.add_field("MODE", bit_range=(1, 3))
reg.add_field("TXIE", bit_index=7)

reg.pack(ENABLE=1, MODE=0b101, TXIE=1)   # -> 0x8B

export_c(reg) spits out portable #define position/mask macros with SET_/GET_ helpers.

Reed-Solomon — parity and Hamming(7,4) only catch isolated single-bit errors. Real noisy channels (scratched CDs, deep-space telemetry, a QR code under a coffee stain) throw burst errors instead:

1
2
3
4
5
6
7
from bitlab.ecc import rs_encode, rs_decode

encoded = rs_encode(b"Hello, World!", nsym=10)
corrupted = bytearray(encoded)
corrupted[0] ^= 0xFF
corrupted[5] ^= 0xFF
rs_decode(bytes(corrupted), nsym=10)   # -> b'Hello, World!'

Only the encoder exports to C, deliberately — real RS systems (satellite telemetry, QR scanners, RAID 6) encode on the resource-constrained side and decode where there’s compute to spare, so a generated decoder would just be dead weight to maintain.

🛠️ One CLI, every module

1
2
3
4
bitlab crc explain "AB" --preset crc8
bitlab registers export-c --name UART_CR1 --size 8 --field ENABLE:0 --field MODE:1-3
bitlab arch q-encode 0.5 --format Q1.15
bitlab ecc encode 4002 --nsym 10

Every topic gets an explain_* trace, but C export is only added where it actually replaces code people reimplement by hand — IEEE 754 and Gray code skip it on purpose, since C already gives bit-exact float access via a union, and Gray code is a one-liner (n ^ (n >> 1)) that doesn’t need generated boilerplate.

The Reed-Solomon module was cross-validated during development against the independent reedsolo library — byte-for-byte identical output across thousands of randomized trials, and the two real bugs that surfaced along the way are documented honestly in the changelog rather than smoothed over. bitlab itself stays zero-dependency; reedsolo is only a dev-time test dependency.

At its core, bitlab is the toolkit I wished I had for the electronics/firmware side of things. Parity and CRC and register bit-fields are the stuff you either reimplement badly every project, or never really understand because the library hides the algorithm from you. This one tries not to.

🐍 Python — PyPI 💻 GitHub 🗂️ LinkedIn

This post is licensed under CC BY 4.0 by the author.