fwtool 1.0.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.
@@ -0,0 +1 @@
1
+ __pycache__
fwtool-1.0.0/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright 2026 Mohammad Mohsen <kuro.ece@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the “Software”), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
+
fwtool-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,446 @@
1
+ Metadata-Version: 2.4
2
+ Name: fwtool
3
+ Version: 1.0.0
4
+ Summary: A command-line interface for working with a custom firmware header placed at the beginning of a binary image.
5
+ Author-email: Mohammad Mohsen <kuro.ece@gmail.com>
6
+ License: Copyright 2026 Mohammad Mohsen <kuro.ece@gmail.com>
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
9
+ this software and associated documentation files (the “Software”), to deal in
10
+ the Software without restriction, including without limitation the rights to
11
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12
+ the Software, and to permit persons to whom the Software is furnished to do so,
13
+ subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ License-File: LICENSE
26
+ Classifier: Programming Language :: Python
27
+ Requires-Python: >=3.13
28
+ Requires-Dist: crccheck>=1.3.1
29
+ Description-Content-Type: text/markdown
30
+
31
+ # fwtool
32
+
33
+ `fwtool` is a command-line utility for creating, updating, inspecting, and verifying
34
+ a custom firmware metadata header prepended to a binary image.
35
+
36
+ It is intended for firmware packaging workflows where a raw application binary is
37
+ post-processed into a single flashable image:
38
+
39
+ - a fixed-size header is placed at the beginning
40
+ - the firmware payload follows immediately after
41
+ - the header contains version, payload size, and CRC information
42
+
43
+ This is useful for bootloaders or firmware update logic that need to validate
44
+ and identify an application image before booting or programming it.
45
+
46
+ ---
47
+
48
+ ## What it does
49
+
50
+ `fwtool` supports four main operations:
51
+
52
+ 1. **Attach** a new header to a raw firmware binary
53
+ 2. **Edit** an existing header in a packaged binary
54
+ 3. **Print** the parsed contents of an existing header
55
+ 4. **Verify** that an existing header matches the payload
56
+
57
+ ---
58
+
59
+ ## Header format
60
+
61
+ The tool generates a **256-byte header** with the following layout:
62
+
63
+ | Offset | Size | Field | Description |
64
+ |--------------|------|---------|----------------------------------------------------|
65
+ | `0x00..0x03` | 4 | magic | ASCII string `XLAB` |
66
+ | `0x04..0x07` | 4 | version | Little-endian bytes: `[0x00, patch, minor, major]` |
67
+ | `0x08..0x0B` | 4 | size | Payload size in bytes, little-endian `uint32` |
68
+ | `0x0C..0x0F` | 4 | crc32 | CRC-32/MPEG-2 of payload, little-endian `uint32` |
69
+ | `0x10..0xFF` | 240 | padding | Filled with `0xFF` |
70
+ ### Notes
71
+
72
+ - The CRC is calculated over the **payload only**, not over the header.
73
+ - The size stored in the header is the **payload size only**.
74
+ - The version is stored as:
75
+ - byte 0: `0x00`
76
+ - byte 1: patch
77
+ - byte 2: minor
78
+ - byte 3: major
79
+
80
+ For example, version `1.2.3` is stored as:
81
+
82
+ ```text
83
+ 00 03 02 01
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Typical use case
89
+
90
+ A common workflow looks like this:
91
+
92
+ 1. Link the firmware application so that it expects to execute after the reserved header space.
93
+ 2. Build the raw application binary.
94
+ 3. Use `fwtool` to prepend the metadata header.
95
+ 4. Program the resulting combined binary into flash.
96
+
97
+ For example:
98
+
99
+ ```text
100
+ Flash address 0x08004000:
101
+ [256-byte metadata header]
102
+ [firmware payload]
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Installation
108
+
109
+ ### Requirements
110
+
111
+ - Python 3.9+
112
+ - [`crccheck`](https://pypi.org/project/crccheck/)
113
+
114
+ ### Install dependency manually
115
+
116
+ ```bash
117
+ pip install crccheck
118
+ ```
119
+
120
+ ### Run directly
121
+
122
+ If you have the script as `fwtool.py`, you can run it with:
123
+
124
+ ```bash
125
+ python fwtool.py ...
126
+ ```
127
+
128
+ ### Install as a CLI tool
129
+
130
+ If the project includes a `pyproject.toml`, install it in editable mode:
131
+
132
+ ```bash
133
+ pip install -e .
134
+ ```
135
+
136
+ Then run it as:
137
+
138
+ ```bash
139
+ fwtool ...
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Usage
145
+
146
+ ```bash
147
+ fwtool binary [version] [output] [options]
148
+ ```
149
+
150
+ ### Positional arguments
151
+
152
+ - `binary`
153
+ Path to input binary file
154
+
155
+ - `version`
156
+ Firmware version string such as:
157
+ - `1`
158
+ - `1.2`
159
+ - `1.2.3`
160
+
161
+ - `output`
162
+ Output path for attach/edit operations
163
+
164
+ ### Options
165
+
166
+ - `--mode {attach,edit}`
167
+ Select how the tool treats the input file:
168
+ - `attach`: input is a raw binary without a header
169
+ - `edit`: input already contains a header and it will be replaced
170
+
171
+ - `--in-place`
172
+ Modify the input file directly instead of writing to a separate output file
173
+
174
+ - `--print-header`
175
+ Parse and print the header from an existing packaged binary
176
+
177
+ - `--verify-header`
178
+ Verify header magic, payload size, and payload CRC against the payload
179
+
180
+ - `--json`
181
+ Print machine-readable JSON output for `--print-header` or `--verify-header`
182
+
183
+ - `--quiet`
184
+ Suppress output for `--verify-header` and use exit code only
185
+
186
+ ---
187
+
188
+ ## Examples
189
+
190
+ ### 1. Attach a new header to a raw binary
191
+
192
+ ```bash
193
+ fwtool firmware.bin 1.2.3 packaged.bin --mode attach
194
+ ```
195
+
196
+ This creates:
197
+
198
+ ```text
199
+ packaged.bin = [256-byte header][firmware.bin payload]
200
+ ```
201
+
202
+ ---
203
+
204
+ ### 2. Replace the header of an existing packaged binary
205
+
206
+ ```bash
207
+ fwtool packaged.bin 1.2.4 updated.bin --mode edit
208
+ ```
209
+
210
+ This keeps the payload but replaces the header with updated metadata.
211
+
212
+ ---
213
+
214
+ ### 3. Replace the header in place
215
+
216
+ ```bash
217
+ fwtool packaged.bin 1.2.4 --mode edit --in-place
218
+ ```
219
+
220
+ This modifies `packaged.bin` directly.
221
+
222
+ ---
223
+
224
+ ### 4. Attach a header in place
225
+
226
+ ```bash
227
+ fwtool firmware.bin 1.2.3 --mode attach --in-place
228
+ ```
229
+
230
+ This replaces the raw input file with a packaged binary containing the header.
231
+
232
+ ---
233
+
234
+ ### 5. Print header contents
235
+
236
+ ```bash
237
+ fwtool packaged.bin --print-header
238
+ ```
239
+
240
+ Example output:
241
+
242
+ ```text
243
+ magic: b'XLAB'
244
+ version: 1.2.3
245
+ size: 123456 bytes
246
+ crc32: 0x1a2b3c4d
247
+ ```
248
+
249
+ ---
250
+
251
+ ### 6. Print header contents as JSON
252
+
253
+ ```bash
254
+ fwtool packaged.bin --print-header --json
255
+ ```
256
+
257
+ Example output:
258
+
259
+ ```json
260
+ {
261
+ \"magic_ascii\": \"XLAB\",
262
+ \"magic_hex\": \"584c4142\",
263
+ \"version\": {
264
+ \"major\": 1,
265
+ \"minor\": 2,
266
+ \"patch\": 3,
267
+ \"string\": \"1.2.3\"
268
+ },
269
+ \"size\": 123456,
270
+ \"crc\": {
271
+ \"int\": 439041101,
272
+ \"hex\": \"0x1a2b3c4d\"
273
+ }
274
+ }
275
+ ```
276
+
277
+ ---
278
+
279
+ ### 7. Verify a packaged binary
280
+
281
+ ```bash
282
+ fwtool packaged.bin --verify-header
283
+ ```
284
+
285
+ Example output:
286
+
287
+ ```text
288
+ magic: OK
289
+ version: 1.2.3
290
+ size: OK (header=123456, actual=123456)
291
+ crc32: OK (header=0x1a2b3c4d, actual=0x1a2b3c4d)
292
+ verification: OK
293
+ ```
294
+
295
+ ---
296
+
297
+ ### 8. Verify quietly using only the exit code
298
+
299
+ ```bash
300
+ fwtool packaged.bin --verify-header --quiet
301
+ echo $?
302
+ ```
303
+
304
+ Exit code meanings:
305
+
306
+ - `0`: verification passed
307
+ - `1`: verification failed
308
+
309
+ ---
310
+
311
+ ### 9. Verify with JSON output
312
+
313
+ ```bash
314
+ fwtool packaged.bin --verify-header --json
315
+ ```
316
+
317
+ Example output:
318
+
319
+ ```json
320
+ {
321
+ \"ok\": true,
322
+ \"magic_ok\": true,
323
+ \"size_ok\": true,
324
+ \"crc_ok\": true,
325
+ \"header\": {
326
+ \"magic_ascii\": \"XLAB\",
327
+ \"magic_hex\": \"584c4142\",
328
+ \"version\": {
329
+ \"major\": 1,
330
+ \"minor\": 2,
331
+ \"patch\": 3,
332
+ \"string\": \"1.2.3\"
333
+ },
334
+ \"size\": 123456,
335
+ \"crc\": {
336
+ \"int\": 439041101,
337
+ \"hex\": \"0x1a2b3c4d\"
338
+ }
339
+ },
340
+ \"payload\": {
341
+ \"size\": 123456,
342
+ \"crc\": {
343
+ \"int\": 439041101,
344
+ \"hex\": \"0x1a2b3c4d\"
345
+ }
346
+ }
347
+ }
348
+ ```
349
+
350
+ ---
351
+
352
+ ## Version handling
353
+
354
+ Accepted version formats:
355
+
356
+ - `1` → `1.0.0`
357
+ - `1.2` → `1.2.0`
358
+ - `1.2.3` → `1.2.3`
359
+
360
+ Rules:
361
+
362
+ - missing components are filled with zero
363
+ - extra components are ignored
364
+ - each component must be in the range `0..255`
365
+
366
+ ---
367
+
368
+ ## Verification behavior
369
+
370
+ When `--verify-header` is used, the tool checks:
371
+
372
+ - the magic field is `XLAB`
373
+ - the payload size matches the size stored in the header
374
+ - the payload CRC matches the CRC stored in the header
375
+
376
+ The header itself is **not** included in the size or CRC calculation.
377
+
378
+ ---
379
+
380
+ ## Exit codes
381
+
382
+ ### General operations
383
+
384
+ - `0` on success
385
+ - non-zero on failure
386
+
387
+ ### `--verify-header`
388
+
389
+ - `0` if verification succeeds
390
+ - `1` if verification fails
391
+
392
+ ---
393
+
394
+ ## Common workflow example
395
+
396
+ Build a raw firmware image:
397
+
398
+ ```bash
399
+ arm-none-eabi-objcopy -O binary app.elf app.bin
400
+ ```
401
+
402
+ Attach metadata header:
403
+
404
+ ```bash
405
+ fwtool app.bin 1.2.3 app_packed.bin --mode attach
406
+ ```
407
+
408
+ Program the combined image to flash:
409
+
410
+ ```bash
411
+ st-flash write app_packed.bin 0x08004000
412
+ ```
413
+
414
+ ---
415
+
416
+ ## Notes for embedded use
417
+
418
+ If your firmware image is packaged with a prepended header, the application must
419
+ typically be linked to execute **after** the reserved header region.
420
+
421
+ Example:
422
+
423
+ - metadata region starts at `0x08004000`
424
+ - header size is `0x100`
425
+ - application is linked to start at `0x08004100`
426
+
427
+ Then the combined image can be programmed at `0x08004000`, and the application
428
+ payload will land at the correct runtime address.
429
+
430
+ ---
431
+
432
+ ## Development
433
+
434
+ ### Run tests
435
+
436
+ If you have a `pytest` test suite:
437
+
438
+ ```bash
439
+ pytest -q
440
+ ```
441
+
442
+ ---
443
+
444
+ ## License
445
+
446
+ MIT License