bitlab 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bitlab-0.1.0 → bitlab-0.2.0}/CHANGELOG.md +34 -7
- bitlab-0.2.0/PKG-INFO +325 -0
- bitlab-0.2.0/README.md +301 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/pyproject.toml +4 -1
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/__init__.py +7 -5
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/cli.py +66 -0
- bitlab-0.2.0/src/bitlab/registers/__init__.py +25 -0
- bitlab-0.2.0/src/bitlab/registers/codegen.py +128 -0
- bitlab-0.2.0/src/bitlab/registers/core.py +181 -0
- bitlab-0.2.0/src/bitlab/registers/explain.py +74 -0
- bitlab-0.2.0/tests/test_registers_codegen.py +123 -0
- bitlab-0.2.0/tests/test_registers_core.py +94 -0
- bitlab-0.2.0/tests/test_registers_explain.py +33 -0
- bitlab-0.1.0/PKG-INFO +0 -266
- bitlab-0.1.0/README.md +0 -242
- {bitlab-0.1.0 → bitlab-0.2.0}/.github/workflows/ci.yml +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/.github/workflows/publish.yml +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/.gitignore +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/CONTRIBUTING.md +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/LICENSE +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/bitutils/__init__.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/bitutils/core.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/crc/__init__.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/crc/codegen.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/crc/engine.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/crc/explain.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/crc/functions.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/crc/presets.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/parity/__init__.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/parity/hamming.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/parity/parity.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/src/bitlab/py.typed +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/tests/__init__.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/tests/test_bitutils.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/tests/test_crc_codegen.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/tests/test_crc_engine.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/tests/test_crc_explain.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/tests/test_crc_functions.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/tests/test_hamming.py +0 -0
- {bitlab-0.1.0 → bitlab-0.2.0}/tests/test_parity.py +0 -0
|
@@ -8,9 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
10
|
### Planned
|
|
11
|
-
- Register field mapper (`bitlab.registers`) — define a hardware register's
|
|
12
|
-
bit layout in Python, pack/unpack values, export to C `#define`s or a
|
|
13
|
-
bitfield struct.
|
|
14
11
|
- Computer architecture toolkit (`bitlab.arch`) — IEEE 754 float
|
|
15
12
|
deconstruction, endianness swapping, Gray code, Q-format fixed-point
|
|
16
13
|
conversion.
|
|
@@ -19,10 +16,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
19
16
|
- Reed-Solomon burst error correction — planned as a later, dedicated
|
|
20
17
|
release given its complexity.
|
|
21
18
|
|
|
22
|
-
## [0.
|
|
19
|
+
## [0.2.0] - 15-07-2026
|
|
23
20
|
|
|
24
21
|
### Added
|
|
25
|
-
- **
|
|
22
|
+
- **New `bitlab.registers` submodule**: hardware register bit-field
|
|
23
|
+
mapping, the signature embedded-dev feature.
|
|
24
|
+
- `Register(name, size_bits=8)` — define a register's layout with
|
|
25
|
+
`add_field(name, bit_index=...)` or `add_field(name, bit_range=(start, end))`.
|
|
26
|
+
Validates overlapping fields and out-of-bounds fields at definition time.
|
|
27
|
+
- `pack(**values)` / `unpack(raw)` — convert between named field values
|
|
28
|
+
and a raw integer.
|
|
29
|
+
- `get_field(raw, name)` / `set_field(raw, name, value)` — read/modify a
|
|
30
|
+
single field via read-modify-write, preserving other bits.
|
|
31
|
+
- `reserved_ranges()` — reports unassigned bit ranges.
|
|
32
|
+
- `explain(reg, **values)`: datasheet-style bit diagram, field list, and
|
|
33
|
+
(when field values are given) a step-by-step pack trace.
|
|
34
|
+
- `export_c(reg, style="defines"|"struct")`:
|
|
35
|
+
- `"defines"` (default) — portable `#define` position/mask macros plus
|
|
36
|
+
`SET_`/`GET_` helper macros. Recommended: plain bitwise ops behave
|
|
37
|
+
identically on every compiler/target.
|
|
38
|
+
- `"struct"` — a C bit-field struct, with an explicit comment noting
|
|
39
|
+
that C leaves bit-field allocation order implementation-defined
|
|
40
|
+
(C99 6.7.2.1p10), so exact hardware bit placement should be verified
|
|
41
|
+
against your compiler's documentation.
|
|
42
|
+
- Both C export styles are validated by actually compiling the generated
|
|
43
|
+
code with `gcc` and comparing the result to Python's `pack()`.
|
|
44
|
+
- `bitlab registers explain` and `bitlab registers export-c` CLI
|
|
45
|
+
subcommands, using a `--field NAME:BIT` / `NAME:START-END` syntax.
|
|
46
|
+
- 21 new tests (77 total), including compiled-C correctness checks for both
|
|
47
|
+
export styles.
|
|
48
|
+
|
|
49
|
+
## [0.1.0] - 14-07-2026
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
- **Renamed the project from `parity-toolkit` to `bitlab`**, and
|
|
26
53
|
restructured it as submodules under one umbrella package rather than a
|
|
27
54
|
flat namespace, to give the project room to grow beyond parity:
|
|
28
55
|
```
|
|
@@ -58,7 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
58
85
|
vs. table-driven CRC implementations and end-to-end compilation of
|
|
59
86
|
generated C source.
|
|
60
87
|
|
|
61
|
-
---
|
|
62
88
|
|
|
63
|
-
[Unreleased]: https://github.com/KenKambi/bitlab/compare/v0.
|
|
89
|
+
[Unreleased]: https://github.com/KenKambi/bitlab/compare/v0.2.0...HEAD
|
|
90
|
+
[0.2.0]: https://github.com/KenKambi/bitlab/compare/v0.1.0...v0.2.0
|
|
64
91
|
[0.1.0]: https://github.com/KenKambi/bitlab/releases/tag/v0.1.0
|
bitlab-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bitlab
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A toolkit for embedded systems, binary data, and digital communications: parity, Hamming codes, and CRC — with C code export.
|
|
5
|
+
Project-URL: Homepage, https://github.com/KenKambi/bitlab
|
|
6
|
+
Project-URL: Issues, https://github.com/KenKambi/bitlab/issues
|
|
7
|
+
License: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: bit-manipulation,bitfield,c-code-generation,crc,crc16,crc32,crc8,embedded,error-correction,error-detection,hamming-code,microcontroller,parity,register,serial,uart
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Topic :: Communications
|
|
15
|
+
Classifier: Topic :: Education
|
|
16
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.8
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: build; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
22
|
+
Requires-Dist: twine; extra == 'dev'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# bitlab
|
|
26
|
+
|
|
27
|
+
[](https://pypi.org/project/bitlab/)
|
|
28
|
+
[](https://github.com/KenKambi/bitlab/actions/workflows/ci.yml)
|
|
29
|
+
[](https://pepy.tech/projects/bitlab)
|
|
30
|
+
[](LICENSE)
|
|
31
|
+
|
|
32
|
+
**Design. Understand. Ship it.**
|
|
33
|
+
|
|
34
|
+
bitlab is a toolkit for embedded systems, binary data, and digital
|
|
35
|
+
communications — parity checking, Hamming error correction, CRC, and
|
|
36
|
+
hardware register bit-fields.
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
| Layer | What it's for |
|
|
40
|
+
|---|---|
|
|
41
|
+
| **Compute** | Fast, production-ready functions (`crc32()`, `pack()`, ...) |
|
|
42
|
+
| **Explain** | The same computation, narrated step by step — for learning or debugging |
|
|
43
|
+
| **Export** | Generate compiled-and-tested C source for the embedded target |
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install bitlab
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## See it in 20 seconds
|
|
51
|
+
|
|
52
|
+
Most CRC libraries give you a black box. `explain()` shows you the real
|
|
53
|
+
algorithm running, bit by bit:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
>>> from bitlab.crc import explain, CRC8_SMBUS
|
|
57
|
+
>>> print(explain(b"AB", CRC8_SMBUS))
|
|
58
|
+
CRC algorithm: CRC-8/SMBUS
|
|
59
|
+
width=8 poly=0x07 init=0x00 refin=False refout=False xorout=0x00
|
|
60
|
+
|
|
61
|
+
Input bytes (2 total): 41 42
|
|
62
|
+
|
|
63
|
+
Initial register: 0x00
|
|
64
|
+
|
|
65
|
+
Byte 0: 0x41 -> XORed in, register = 0x41
|
|
66
|
+
bit 0: MSB=0 -> shift left -> 0x82
|
|
67
|
+
bit 1: MSB=1 -> shift left, XOR polynomial -> 0x03
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
Final CRC: 0x87
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
And when you're ready for hardware, the same configuration exports straight
|
|
74
|
+
to a firmware-ready C function — no rewriting the algorithm by hand:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
>>> from bitlab.crc import export_c, CRC32_ISO_HDLC
|
|
78
|
+
>>> print(export_c(CRC32_ISO_HDLC, function_name="my_crc32"))
|
|
79
|
+
```
|
|
80
|
+
```c
|
|
81
|
+
uint32_t my_crc32(const uint8_t *data, size_t len)
|
|
82
|
+
{
|
|
83
|
+
uint32_t crc = 0xFFFFFFFFU;
|
|
84
|
+
for (size_t i = 0; i < len; i++) {
|
|
85
|
+
uint8_t idx = (uint8_t)(crc ^ data[i]);
|
|
86
|
+
crc = (crc >> 8) ^ my_crc32_table[idx];
|
|
87
|
+
}
|
|
88
|
+
return (crc ^ 0xFFFFFFFFU);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The test suite compiles every
|
|
93
|
+
generated C function with `gcc` and checks the output against the official
|
|
94
|
+
CRC catalogue check values.
|
|
95
|
+
|
|
96
|
+
## Modules
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
bitlab/
|
|
100
|
+
├── bitutils/ foundational bit ops shared by every submodule
|
|
101
|
+
├── parity/ parity bit checking + Hamming(7,4) error correction
|
|
102
|
+
├── crc/ CRC-8/16/32, generic engine, explain(), export_c()
|
|
103
|
+
└── registers/ hardware register bit-field mapper, explain(), export_c()
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `bitlab.crc` — crc8/16/32, explain
|
|
107
|
+
|
|
108
|
+
Real hardware (Ethernet, Modbus, firmware integrity checks) uses CRC, not
|
|
109
|
+
simple parity. All four built-in presets are verified against the official
|
|
110
|
+
CRC-catalogue check values, not just "a CRC that happens to run."
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from bitlab.crc import crc8, crc16, crc32
|
|
114
|
+
|
|
115
|
+
crc8(b"hello") # CRC-8/SMBUS
|
|
116
|
+
crc16(b"hello") # CRC-16/CCITT-FALSE (default)
|
|
117
|
+
crc16(b"hello", variant="modbus") # CRC-16/MODBUS
|
|
118
|
+
crc32(b"hello") # CRC-32/ISO-HDLC (Ethernet, zlib, PNG)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Custom polynomials work the same way:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from bitlab.crc import crc, CRCConfig
|
|
125
|
+
|
|
126
|
+
my_crc = CRCConfig(
|
|
127
|
+
name="my-custom-crc",
|
|
128
|
+
width=16, poly=0x8005, init=0xFFFF,
|
|
129
|
+
refin=True, refout=True, xorout=0x0000,
|
|
130
|
+
check=0x4B37, # CRC of b"123456789", used to self-test your config
|
|
131
|
+
)
|
|
132
|
+
crc(b"some data", my_crc)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### `bitlab.registers` — embedded, explaim
|
|
136
|
+
Firmware engineers hand-write register bitmasks constantly. Define the
|
|
137
|
+
layout once, pack/unpack named fields instead of shifting magic numbers by
|
|
138
|
+
hand, and export it straight to C.
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from bitlab.registers import Register, explain, export_c
|
|
142
|
+
|
|
143
|
+
reg = Register("UART_CR1", size_bits=8)
|
|
144
|
+
reg.add_field("ENABLE", bit_index=0)
|
|
145
|
+
reg.add_field("MODE", bit_range=(1, 3))
|
|
146
|
+
reg.add_field("TXIE", bit_index=7)
|
|
147
|
+
|
|
148
|
+
reg.pack(ENABLE=1, MODE=0b101, TXIE=1) # -> 0x8B
|
|
149
|
+
reg.unpack(0x8B) # -> {'ENABLE': 1, 'MODE': 5, 'TXIE': 1}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
>>> print(explain(reg, ENABLE=1, MODE=5, TXIE=1))
|
|
154
|
+
Register: UART_CR1 (8-bit)
|
|
155
|
+
|
|
156
|
+
Bit: 7 6 5 4 3 2 1 0
|
|
157
|
+
Field: TXIE . . . MODE MODE MODE ENABLE
|
|
158
|
+
|
|
159
|
+
Fields (MSB to LSB):
|
|
160
|
+
TXIE bit 7 (max 1)
|
|
161
|
+
MODE bits 1-3 (max 7)
|
|
162
|
+
ENABLE bit 0 (max 1)
|
|
163
|
+
|
|
164
|
+
Reserved (unassigned):
|
|
165
|
+
bits 4-6
|
|
166
|
+
|
|
167
|
+
Packing UART_CR1(ENABLE=1, MODE=5, TXIE=1):
|
|
168
|
+
ENABLE=1 -> 0b1 shifted left 0 -> 0x01 | running value = 0x01
|
|
169
|
+
MODE=5 -> 0b101 shifted left 1 -> 0x0A | running value = 0x0B
|
|
170
|
+
TXIE=1 -> 0b1 shifted left 7 -> 0x80 | running value = 0x8B
|
|
171
|
+
|
|
172
|
+
Final packed value: 0x8B (0b10001011)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`export_c(reg)` gives you portable `#define` position/mask macros with
|
|
176
|
+
`SET_`/`GET_` helpers (the recommended, compiler-independent style).
|
|
177
|
+
`export_c(reg, style="struct")` gives you a readable C bit-field struct
|
|
178
|
+
instead — with an explicit comment flagging that C leaves struct bit-field
|
|
179
|
+
ordering implementation-defined, so you know to double-check it against
|
|
180
|
+
your compiler before trusting exact hardware placement.
|
|
181
|
+
|
|
182
|
+
```c
|
|
183
|
+
#define UART_CR1_ENABLE_POS 0U
|
|
184
|
+
#define UART_CR1_ENABLE_MASK (0x1U << UART_CR1_ENABLE_POS)
|
|
185
|
+
|
|
186
|
+
#define UART_CR1_SET_ENABLE(reg, val) \
|
|
187
|
+
((reg) = ((uint8_t)(reg) & ~UART_CR1_ENABLE_MASK) | \
|
|
188
|
+
(((uint8_t)(val) << UART_CR1_ENABLE_POS) & UART_CR1_ENABLE_MASK))
|
|
189
|
+
#define UART_CR1_GET_ENABLE(reg) \
|
|
190
|
+
(((uint8_t)(reg) & UART_CR1_ENABLE_MASK) >> UART_CR1_ENABLE_POS)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### `bitlab.parity` — parity bit, Hamming(7,4)
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
from bitlab.parity import get_parity_bit, append_parity, check_parity
|
|
197
|
+
|
|
198
|
+
get_parity_bit(0b1011, "even", 4) # -> 1
|
|
199
|
+
append_parity(0b1011, "even", 4) # -> 0b11011
|
|
200
|
+
check_parity(0b11011, "even", 4) # -> True
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from bitlab.parity import encode_hamming, decode_hamming
|
|
205
|
+
|
|
206
|
+
codeword = encode_hamming(0b1101)
|
|
207
|
+
corrupted = codeword ^ 0b0000100 # simulate a single-bit flip
|
|
208
|
+
decode_hamming(corrupted)
|
|
209
|
+
# HammingDecodeResult(data=13, error_position=6, corrected=True, codeword=...)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### `bitlab.bitutils` — shared foundation
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from bitlab.bitutils import popcount, reflect, rotate_left, rotate_right
|
|
216
|
+
|
|
217
|
+
popcount(0b1011) # -> 3
|
|
218
|
+
reflect(0b1100, 4) # -> 0b0011
|
|
219
|
+
rotate_left(0b10000001, 1, 8) # -> 0b00000011
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## CLI
|
|
223
|
+
|
|
224
|
+
One `bitlab` command covers every module:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
bitlab crc explain "AB" --preset crc8
|
|
228
|
+
bitlab crc export-c --preset crc32 --name my_crc32
|
|
229
|
+
|
|
230
|
+
bitlab registers explain --name UART_CR1 --size 8 \
|
|
231
|
+
--field ENABLE:0 --field MODE:1-3 --field TXIE:7 --pack ENABLE=1,MODE=5,TXIE=1
|
|
232
|
+
bitlab registers export-c --name UART_CR1 --size 8 \
|
|
233
|
+
--field ENABLE:0 --field MODE:1-3 --field TXIE:7 --style defines
|
|
234
|
+
|
|
235
|
+
bitlab parity bit 0b1011 --type even --width 4
|
|
236
|
+
bitlab hamming encode 13
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Run `bitlab --help`, `bitlab crc --help`, `bitlab registers --help` for full usage.
|
|
240
|
+
|
|
241
|
+
## API reference
|
|
242
|
+
|
|
243
|
+
### `bitlab.crc`
|
|
244
|
+
|
|
245
|
+
| Function | Description |
|
|
246
|
+
|---|---|
|
|
247
|
+
| `crc8(data)` | CRC-8/SMBUS. |
|
|
248
|
+
| `crc16(data, variant="ccitt")` | CRC-16/CCITT-FALSE or CRC-16/MODBUS. |
|
|
249
|
+
| `crc32(data)` | CRC-32/ISO-HDLC (Ethernet/zlib/PNG). |
|
|
250
|
+
| `crc(data, config)` | Generic entry point. `config` is a `CRCConfig` or a preset name string. |
|
|
251
|
+
| `explain(data, config, max_bytes=4)` | Step-by-step trace of the computation. |
|
|
252
|
+
| `export_c(config, function_name=None)` | Table-driven C99 source implementing `config`. |
|
|
253
|
+
| `build_table(config)` | The 256-entry lookup table (also used by `export_c`). |
|
|
254
|
+
| `compute_bitwise(data, config)` | Canonical bit-by-bit reference implementation. |
|
|
255
|
+
| `compute_table(data, config, table=None)` | Fast table-driven implementation. |
|
|
256
|
+
| `self_test(config)` | Verifies a config against its `check` value. |
|
|
257
|
+
| `CRCConfig` | Dataclass: `name, width, poly, init, refin, refout, xorout, check`. |
|
|
258
|
+
| `CRC8_SMBUS`, `CRC16_CCITT_FALSE`, `CRC16_MODBUS`, `CRC32_ISO_HDLC` | Built-in preset configs. |
|
|
259
|
+
|
|
260
|
+
### `bitlab.registers`
|
|
261
|
+
|
|
262
|
+
| Function | Description |
|
|
263
|
+
|---|---|
|
|
264
|
+
| `Register(name, size_bits=8)` | Define a register. |
|
|
265
|
+
| `.add_field(name, bit_index=... \| bit_range=(start, end), description=None)` | Add a named field. Raises on overlap or out-of-bounds. |
|
|
266
|
+
| `.pack(**values)` | Pack named field values into a raw integer. |
|
|
267
|
+
| `.unpack(raw)` | Unpack a raw integer into `{field_name: value}`. |
|
|
268
|
+
| `.get_field(raw, name)` / `.set_field(raw, name, value)` | Read/modify a single field (read-modify-write). |
|
|
269
|
+
| `.reserved_ranges()` | Unassigned bit ranges. |
|
|
270
|
+
| `.layout()` | Fields ordered MSB to LSB. |
|
|
271
|
+
| `explain(reg, **values)` | Bit diagram, field list, and (if values given) a pack trace. |
|
|
272
|
+
| `export_c(reg, style="defines"\|"struct")` | C99 source: portable macros or a bit-field struct. |
|
|
273
|
+
|
|
274
|
+
### `bitlab.parity`
|
|
275
|
+
|
|
276
|
+
| Function | Description |
|
|
277
|
+
|---|---|
|
|
278
|
+
| `get_parity_bit(value, type="even", bit_width=8)` | Computes the parity bit for `value`. |
|
|
279
|
+
| `append_parity(value, type="even", bit_width=8)` | Returns `value` with a parity bit appended as bit `bit_width`. |
|
|
280
|
+
| `check_parity(value_with_parity, type="even", bit_width=8)` | Returns `True` if the parity bit matches the data. |
|
|
281
|
+
| `generate_parity_array(values, type="even", bit_width=8)` | Parity bit for each value in a sequence. |
|
|
282
|
+
| `check_parity_array(values_with_parity, type="even", bit_width=8)` | Parity check for each value in a sequence. |
|
|
283
|
+
| `compute_message_parity(message, type="even")` | Single overall parity bit for a whole string. |
|
|
284
|
+
| `flip_random_bit(value, bit_width=8)` | Flips one random bit — useful for simulating errors in tests. |
|
|
285
|
+
| `encode_hamming(data)` | Encodes a 4-bit value (0–15) into a 7-bit Hamming codeword. |
|
|
286
|
+
| `decode_hamming(codeword)` | Decodes a 7-bit codeword, correcting a single-bit error if present. |
|
|
287
|
+
|
|
288
|
+
### `bitlab.bitutils`
|
|
289
|
+
|
|
290
|
+
| Function | Description |
|
|
291
|
+
|---|---|
|
|
292
|
+
| `popcount(n)` | Number of 1-bits. |
|
|
293
|
+
| `has_odd_parity(n)` | True if `n` has an odd number of 1-bits. |
|
|
294
|
+
| `get_bit` / `set_bit` / `flip_bit` | Single-bit read/write/toggle. |
|
|
295
|
+
| `reflect(value, width)` | Bit-mirror the lowest `width` bits. |
|
|
296
|
+
| `rotate_left` / `rotate_right` | Bitwise rotation within a fixed-width register. |
|
|
297
|
+
|
|
298
|
+
## Roadmap
|
|
299
|
+
|
|
300
|
+
- **v0.3.0 — Computer architecture toolkit** (`bitlab.arch`): IEEE 754
|
|
301
|
+
float deconstruction, endianness swapping, Gray code, Q-format
|
|
302
|
+
fixed-point conversion.
|
|
303
|
+
- **v0.4.0 — Protocol framing** (`bitlab.comms`): COBS (Consistent Overhead
|
|
304
|
+
Byte Stuffing).
|
|
305
|
+
- **v1.0.0 — Reed-Solomon** (`bitlab.ecc`): burst error correction (QR
|
|
306
|
+
codes, satellite comms) — planned as a dedicated release given its
|
|
307
|
+
complexity.
|
|
308
|
+
|
|
309
|
+
See [CHANGELOG.md](CHANGELOG.md) for full release history.
|
|
310
|
+
|
|
311
|
+
## Development
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
pip install -e ".[dev]"
|
|
315
|
+
pytest # 77 tests, including compiling and running generated
|
|
316
|
+
# C against gcc for both crc and registers
|
|
317
|
+
python -m build # produce a wheel + sdist in dist/
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full dev workflow and release
|
|
321
|
+
process.
|
|
322
|
+
|
|
323
|
+
## License
|
|
324
|
+
|
|
325
|
+
MIT
|
bitlab-0.2.0/README.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# bitlab
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/bitlab/)
|
|
4
|
+
[](https://github.com/KenKambi/bitlab/actions/workflows/ci.yml)
|
|
5
|
+
[](https://pepy.tech/projects/bitlab)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
**Design. Understand. Ship it.**
|
|
9
|
+
|
|
10
|
+
bitlab is a toolkit for embedded systems, binary data, and digital
|
|
11
|
+
communications — parity checking, Hamming error correction, CRC, and
|
|
12
|
+
hardware register bit-fields.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
| Layer | What it's for |
|
|
16
|
+
|---|---|
|
|
17
|
+
| **Compute** | Fast, production-ready functions (`crc32()`, `pack()`, ...) |
|
|
18
|
+
| **Explain** | The same computation, narrated step by step — for learning or debugging |
|
|
19
|
+
| **Export** | Generate compiled-and-tested C source for the embedded target |
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install bitlab
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## See it in 20 seconds
|
|
27
|
+
|
|
28
|
+
Most CRC libraries give you a black box. `explain()` shows you the real
|
|
29
|
+
algorithm running, bit by bit:
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
>>> from bitlab.crc import explain, CRC8_SMBUS
|
|
33
|
+
>>> print(explain(b"AB", CRC8_SMBUS))
|
|
34
|
+
CRC algorithm: CRC-8/SMBUS
|
|
35
|
+
width=8 poly=0x07 init=0x00 refin=False refout=False xorout=0x00
|
|
36
|
+
|
|
37
|
+
Input bytes (2 total): 41 42
|
|
38
|
+
|
|
39
|
+
Initial register: 0x00
|
|
40
|
+
|
|
41
|
+
Byte 0: 0x41 -> XORed in, register = 0x41
|
|
42
|
+
bit 0: MSB=0 -> shift left -> 0x82
|
|
43
|
+
bit 1: MSB=1 -> shift left, XOR polynomial -> 0x03
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
Final CRC: 0x87
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
And when you're ready for hardware, the same configuration exports straight
|
|
50
|
+
to a firmware-ready C function — no rewriting the algorithm by hand:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
>>> from bitlab.crc import export_c, CRC32_ISO_HDLC
|
|
54
|
+
>>> print(export_c(CRC32_ISO_HDLC, function_name="my_crc32"))
|
|
55
|
+
```
|
|
56
|
+
```c
|
|
57
|
+
uint32_t my_crc32(const uint8_t *data, size_t len)
|
|
58
|
+
{
|
|
59
|
+
uint32_t crc = 0xFFFFFFFFU;
|
|
60
|
+
for (size_t i = 0; i < len; i++) {
|
|
61
|
+
uint8_t idx = (uint8_t)(crc ^ data[i]);
|
|
62
|
+
crc = (crc >> 8) ^ my_crc32_table[idx];
|
|
63
|
+
}
|
|
64
|
+
return (crc ^ 0xFFFFFFFFU);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The test suite compiles every
|
|
69
|
+
generated C function with `gcc` and checks the output against the official
|
|
70
|
+
CRC catalogue check values.
|
|
71
|
+
|
|
72
|
+
## Modules
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
bitlab/
|
|
76
|
+
├── bitutils/ foundational bit ops shared by every submodule
|
|
77
|
+
├── parity/ parity bit checking + Hamming(7,4) error correction
|
|
78
|
+
├── crc/ CRC-8/16/32, generic engine, explain(), export_c()
|
|
79
|
+
└── registers/ hardware register bit-field mapper, explain(), export_c()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `bitlab.crc` — crc8/16/32, explain
|
|
83
|
+
|
|
84
|
+
Real hardware (Ethernet, Modbus, firmware integrity checks) uses CRC, not
|
|
85
|
+
simple parity. All four built-in presets are verified against the official
|
|
86
|
+
CRC-catalogue check values, not just "a CRC that happens to run."
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from bitlab.crc import crc8, crc16, crc32
|
|
90
|
+
|
|
91
|
+
crc8(b"hello") # CRC-8/SMBUS
|
|
92
|
+
crc16(b"hello") # CRC-16/CCITT-FALSE (default)
|
|
93
|
+
crc16(b"hello", variant="modbus") # CRC-16/MODBUS
|
|
94
|
+
crc32(b"hello") # CRC-32/ISO-HDLC (Ethernet, zlib, PNG)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Custom polynomials work the same way:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from bitlab.crc import crc, CRCConfig
|
|
101
|
+
|
|
102
|
+
my_crc = CRCConfig(
|
|
103
|
+
name="my-custom-crc",
|
|
104
|
+
width=16, poly=0x8005, init=0xFFFF,
|
|
105
|
+
refin=True, refout=True, xorout=0x0000,
|
|
106
|
+
check=0x4B37, # CRC of b"123456789", used to self-test your config
|
|
107
|
+
)
|
|
108
|
+
crc(b"some data", my_crc)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `bitlab.registers` — embedded, explaim
|
|
112
|
+
Firmware engineers hand-write register bitmasks constantly. Define the
|
|
113
|
+
layout once, pack/unpack named fields instead of shifting magic numbers by
|
|
114
|
+
hand, and export it straight to C.
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from bitlab.registers import Register, explain, export_c
|
|
118
|
+
|
|
119
|
+
reg = Register("UART_CR1", size_bits=8)
|
|
120
|
+
reg.add_field("ENABLE", bit_index=0)
|
|
121
|
+
reg.add_field("MODE", bit_range=(1, 3))
|
|
122
|
+
reg.add_field("TXIE", bit_index=7)
|
|
123
|
+
|
|
124
|
+
reg.pack(ENABLE=1, MODE=0b101, TXIE=1) # -> 0x8B
|
|
125
|
+
reg.unpack(0x8B) # -> {'ENABLE': 1, 'MODE': 5, 'TXIE': 1}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
>>> print(explain(reg, ENABLE=1, MODE=5, TXIE=1))
|
|
130
|
+
Register: UART_CR1 (8-bit)
|
|
131
|
+
|
|
132
|
+
Bit: 7 6 5 4 3 2 1 0
|
|
133
|
+
Field: TXIE . . . MODE MODE MODE ENABLE
|
|
134
|
+
|
|
135
|
+
Fields (MSB to LSB):
|
|
136
|
+
TXIE bit 7 (max 1)
|
|
137
|
+
MODE bits 1-3 (max 7)
|
|
138
|
+
ENABLE bit 0 (max 1)
|
|
139
|
+
|
|
140
|
+
Reserved (unassigned):
|
|
141
|
+
bits 4-6
|
|
142
|
+
|
|
143
|
+
Packing UART_CR1(ENABLE=1, MODE=5, TXIE=1):
|
|
144
|
+
ENABLE=1 -> 0b1 shifted left 0 -> 0x01 | running value = 0x01
|
|
145
|
+
MODE=5 -> 0b101 shifted left 1 -> 0x0A | running value = 0x0B
|
|
146
|
+
TXIE=1 -> 0b1 shifted left 7 -> 0x80 | running value = 0x8B
|
|
147
|
+
|
|
148
|
+
Final packed value: 0x8B (0b10001011)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`export_c(reg)` gives you portable `#define` position/mask macros with
|
|
152
|
+
`SET_`/`GET_` helpers (the recommended, compiler-independent style).
|
|
153
|
+
`export_c(reg, style="struct")` gives you a readable C bit-field struct
|
|
154
|
+
instead — with an explicit comment flagging that C leaves struct bit-field
|
|
155
|
+
ordering implementation-defined, so you know to double-check it against
|
|
156
|
+
your compiler before trusting exact hardware placement.
|
|
157
|
+
|
|
158
|
+
```c
|
|
159
|
+
#define UART_CR1_ENABLE_POS 0U
|
|
160
|
+
#define UART_CR1_ENABLE_MASK (0x1U << UART_CR1_ENABLE_POS)
|
|
161
|
+
|
|
162
|
+
#define UART_CR1_SET_ENABLE(reg, val) \
|
|
163
|
+
((reg) = ((uint8_t)(reg) & ~UART_CR1_ENABLE_MASK) | \
|
|
164
|
+
(((uint8_t)(val) << UART_CR1_ENABLE_POS) & UART_CR1_ENABLE_MASK))
|
|
165
|
+
#define UART_CR1_GET_ENABLE(reg) \
|
|
166
|
+
(((uint8_t)(reg) & UART_CR1_ENABLE_MASK) >> UART_CR1_ENABLE_POS)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### `bitlab.parity` — parity bit, Hamming(7,4)
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from bitlab.parity import get_parity_bit, append_parity, check_parity
|
|
173
|
+
|
|
174
|
+
get_parity_bit(0b1011, "even", 4) # -> 1
|
|
175
|
+
append_parity(0b1011, "even", 4) # -> 0b11011
|
|
176
|
+
check_parity(0b11011, "even", 4) # -> True
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from bitlab.parity import encode_hamming, decode_hamming
|
|
181
|
+
|
|
182
|
+
codeword = encode_hamming(0b1101)
|
|
183
|
+
corrupted = codeword ^ 0b0000100 # simulate a single-bit flip
|
|
184
|
+
decode_hamming(corrupted)
|
|
185
|
+
# HammingDecodeResult(data=13, error_position=6, corrected=True, codeword=...)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `bitlab.bitutils` — shared foundation
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
from bitlab.bitutils import popcount, reflect, rotate_left, rotate_right
|
|
192
|
+
|
|
193
|
+
popcount(0b1011) # -> 3
|
|
194
|
+
reflect(0b1100, 4) # -> 0b0011
|
|
195
|
+
rotate_left(0b10000001, 1, 8) # -> 0b00000011
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## CLI
|
|
199
|
+
|
|
200
|
+
One `bitlab` command covers every module:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
bitlab crc explain "AB" --preset crc8
|
|
204
|
+
bitlab crc export-c --preset crc32 --name my_crc32
|
|
205
|
+
|
|
206
|
+
bitlab registers explain --name UART_CR1 --size 8 \
|
|
207
|
+
--field ENABLE:0 --field MODE:1-3 --field TXIE:7 --pack ENABLE=1,MODE=5,TXIE=1
|
|
208
|
+
bitlab registers export-c --name UART_CR1 --size 8 \
|
|
209
|
+
--field ENABLE:0 --field MODE:1-3 --field TXIE:7 --style defines
|
|
210
|
+
|
|
211
|
+
bitlab parity bit 0b1011 --type even --width 4
|
|
212
|
+
bitlab hamming encode 13
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Run `bitlab --help`, `bitlab crc --help`, `bitlab registers --help` for full usage.
|
|
216
|
+
|
|
217
|
+
## API reference
|
|
218
|
+
|
|
219
|
+
### `bitlab.crc`
|
|
220
|
+
|
|
221
|
+
| Function | Description |
|
|
222
|
+
|---|---|
|
|
223
|
+
| `crc8(data)` | CRC-8/SMBUS. |
|
|
224
|
+
| `crc16(data, variant="ccitt")` | CRC-16/CCITT-FALSE or CRC-16/MODBUS. |
|
|
225
|
+
| `crc32(data)` | CRC-32/ISO-HDLC (Ethernet/zlib/PNG). |
|
|
226
|
+
| `crc(data, config)` | Generic entry point. `config` is a `CRCConfig` or a preset name string. |
|
|
227
|
+
| `explain(data, config, max_bytes=4)` | Step-by-step trace of the computation. |
|
|
228
|
+
| `export_c(config, function_name=None)` | Table-driven C99 source implementing `config`. |
|
|
229
|
+
| `build_table(config)` | The 256-entry lookup table (also used by `export_c`). |
|
|
230
|
+
| `compute_bitwise(data, config)` | Canonical bit-by-bit reference implementation. |
|
|
231
|
+
| `compute_table(data, config, table=None)` | Fast table-driven implementation. |
|
|
232
|
+
| `self_test(config)` | Verifies a config against its `check` value. |
|
|
233
|
+
| `CRCConfig` | Dataclass: `name, width, poly, init, refin, refout, xorout, check`. |
|
|
234
|
+
| `CRC8_SMBUS`, `CRC16_CCITT_FALSE`, `CRC16_MODBUS`, `CRC32_ISO_HDLC` | Built-in preset configs. |
|
|
235
|
+
|
|
236
|
+
### `bitlab.registers`
|
|
237
|
+
|
|
238
|
+
| Function | Description |
|
|
239
|
+
|---|---|
|
|
240
|
+
| `Register(name, size_bits=8)` | Define a register. |
|
|
241
|
+
| `.add_field(name, bit_index=... \| bit_range=(start, end), description=None)` | Add a named field. Raises on overlap or out-of-bounds. |
|
|
242
|
+
| `.pack(**values)` | Pack named field values into a raw integer. |
|
|
243
|
+
| `.unpack(raw)` | Unpack a raw integer into `{field_name: value}`. |
|
|
244
|
+
| `.get_field(raw, name)` / `.set_field(raw, name, value)` | Read/modify a single field (read-modify-write). |
|
|
245
|
+
| `.reserved_ranges()` | Unassigned bit ranges. |
|
|
246
|
+
| `.layout()` | Fields ordered MSB to LSB. |
|
|
247
|
+
| `explain(reg, **values)` | Bit diagram, field list, and (if values given) a pack trace. |
|
|
248
|
+
| `export_c(reg, style="defines"\|"struct")` | C99 source: portable macros or a bit-field struct. |
|
|
249
|
+
|
|
250
|
+
### `bitlab.parity`
|
|
251
|
+
|
|
252
|
+
| Function | Description |
|
|
253
|
+
|---|---|
|
|
254
|
+
| `get_parity_bit(value, type="even", bit_width=8)` | Computes the parity bit for `value`. |
|
|
255
|
+
| `append_parity(value, type="even", bit_width=8)` | Returns `value` with a parity bit appended as bit `bit_width`. |
|
|
256
|
+
| `check_parity(value_with_parity, type="even", bit_width=8)` | Returns `True` if the parity bit matches the data. |
|
|
257
|
+
| `generate_parity_array(values, type="even", bit_width=8)` | Parity bit for each value in a sequence. |
|
|
258
|
+
| `check_parity_array(values_with_parity, type="even", bit_width=8)` | Parity check for each value in a sequence. |
|
|
259
|
+
| `compute_message_parity(message, type="even")` | Single overall parity bit for a whole string. |
|
|
260
|
+
| `flip_random_bit(value, bit_width=8)` | Flips one random bit — useful for simulating errors in tests. |
|
|
261
|
+
| `encode_hamming(data)` | Encodes a 4-bit value (0–15) into a 7-bit Hamming codeword. |
|
|
262
|
+
| `decode_hamming(codeword)` | Decodes a 7-bit codeword, correcting a single-bit error if present. |
|
|
263
|
+
|
|
264
|
+
### `bitlab.bitutils`
|
|
265
|
+
|
|
266
|
+
| Function | Description |
|
|
267
|
+
|---|---|
|
|
268
|
+
| `popcount(n)` | Number of 1-bits. |
|
|
269
|
+
| `has_odd_parity(n)` | True if `n` has an odd number of 1-bits. |
|
|
270
|
+
| `get_bit` / `set_bit` / `flip_bit` | Single-bit read/write/toggle. |
|
|
271
|
+
| `reflect(value, width)` | Bit-mirror the lowest `width` bits. |
|
|
272
|
+
| `rotate_left` / `rotate_right` | Bitwise rotation within a fixed-width register. |
|
|
273
|
+
|
|
274
|
+
## Roadmap
|
|
275
|
+
|
|
276
|
+
- **v0.3.0 — Computer architecture toolkit** (`bitlab.arch`): IEEE 754
|
|
277
|
+
float deconstruction, endianness swapping, Gray code, Q-format
|
|
278
|
+
fixed-point conversion.
|
|
279
|
+
- **v0.4.0 — Protocol framing** (`bitlab.comms`): COBS (Consistent Overhead
|
|
280
|
+
Byte Stuffing).
|
|
281
|
+
- **v1.0.0 — Reed-Solomon** (`bitlab.ecc`): burst error correction (QR
|
|
282
|
+
codes, satellite comms) — planned as a dedicated release given its
|
|
283
|
+
complexity.
|
|
284
|
+
|
|
285
|
+
See [CHANGELOG.md](CHANGELOG.md) for full release history.
|
|
286
|
+
|
|
287
|
+
## Development
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
pip install -e ".[dev]"
|
|
291
|
+
pytest # 77 tests, including compiling and running generated
|
|
292
|
+
# C against gcc for both crc and registers
|
|
293
|
+
python -m build # produce a wheel + sdist in dist/
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full dev workflow and release
|
|
297
|
+
process.
|
|
298
|
+
|
|
299
|
+
## License
|
|
300
|
+
|
|
301
|
+
MIT
|