Bitlab Tooklit🔧
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:
| Layer | What it’s for |
|---|---|
| Compute | Fast, production-ready functions (crc32(), pack(), …) |
| Explain | The same computation, narrated bit by bit — for learning or debugging |
| Export | Compiled-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