cfsr-decoder 1.1.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.
- cfsr_decoder-1.1.0/LICENSE +21 -0
- cfsr_decoder-1.1.0/PKG-INFO +41 -0
- cfsr_decoder-1.1.0/README.md +23 -0
- cfsr_decoder-1.1.0/cfsr_decode.py +211 -0
- cfsr_decoder-1.1.0/cfsr_decoder.egg-info/PKG-INFO +41 -0
- cfsr_decoder-1.1.0/cfsr_decoder.egg-info/SOURCES.txt +9 -0
- cfsr_decoder-1.1.0/cfsr_decoder.egg-info/dependency_links.txt +1 -0
- cfsr_decoder-1.1.0/cfsr_decoder.egg-info/entry_points.txt +2 -0
- cfsr_decoder-1.1.0/cfsr_decoder.egg-info/top_level.txt +1 -0
- cfsr_decoder-1.1.0/pyproject.toml +28 -0
- cfsr_decoder-1.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 GaneshMba4066
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cfsr-decoder
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Zero-dependency ARM Cortex-M fault status register decoder CLI
|
|
5
|
+
Author-email: Trust & Thread <contact@trustandthread.com>
|
|
6
|
+
Project-URL: Homepage, https://www.trustandthread.com
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/GaneshMba4066/cfsr-decoder/issues
|
|
8
|
+
Project-URL: Documentation, https://www.trustandthread.com/firmware-checklist/
|
|
9
|
+
Keywords: arm,cortex-m,stm32,hardfault,firmware,debugging,cfsr
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
14
|
+
Requires-Python: >=3.6
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# cfsr-decoder
|
|
20
|
+
|
|
21
|
+
A zero-dependency ARM Cortex-M fault status register decoder for embedded systems students, hobbyists, and firmware engineers.
|
|
22
|
+
|
|
23
|
+
Whenever an STM32, RP2040, NXP, or SAM microcontroller locks up in an infinite `HardFault_Handler` loop, the CPU writes the failure cause into the ARM core registers (`CFSR`, `HFSR`, `BFAR`, `MMFAR`).
|
|
24
|
+
|
|
25
|
+
Decoding those bitmasks manually from the ARM Architecture Reference Manual is slow. `cfsr-decode` turns raw hex register dumps into clear, plain-English diagnostics and recovery steps.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Quick Start (Zero Dependencies)
|
|
30
|
+
|
|
31
|
+
Runs directly with standard Python 3.6+:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# General syntax
|
|
35
|
+
python cfsr_decode.py <CFSR_HEX> [BFAR_HEX] [MMFAR_HEX] [HFSR_HEX]
|
|
36
|
+
|
|
37
|
+
# Try a realistic unaligned access fault
|
|
38
|
+
python cfsr_decode.py 0x00010200 0x20001FF7
|
|
39
|
+
|
|
40
|
+
# View all built-in examples
|
|
41
|
+
python cfsr_decode.py --example
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# cfsr-decoder
|
|
2
|
+
|
|
3
|
+
A zero-dependency ARM Cortex-M fault status register decoder for embedded systems students, hobbyists, and firmware engineers.
|
|
4
|
+
|
|
5
|
+
Whenever an STM32, RP2040, NXP, or SAM microcontroller locks up in an infinite `HardFault_Handler` loop, the CPU writes the failure cause into the ARM core registers (`CFSR`, `HFSR`, `BFAR`, `MMFAR`).
|
|
6
|
+
|
|
7
|
+
Decoding those bitmasks manually from the ARM Architecture Reference Manual is slow. `cfsr-decode` turns raw hex register dumps into clear, plain-English diagnostics and recovery steps.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Quick Start (Zero Dependencies)
|
|
12
|
+
|
|
13
|
+
Runs directly with standard Python 3.6+:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# General syntax
|
|
17
|
+
python cfsr_decode.py <CFSR_HEX> [BFAR_HEX] [MMFAR_HEX] [HFSR_HEX]
|
|
18
|
+
|
|
19
|
+
# Try a realistic unaligned access fault
|
|
20
|
+
python cfsr_decode.py 0x00010200 0x20001FF7
|
|
21
|
+
|
|
22
|
+
# View all built-in examples
|
|
23
|
+
python cfsr_decode.py --example
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
cfsr-decode: ARM Cortex-M Fault Register Decoder (CFSR / HFSR / MMFAR / BFAR)
|
|
4
|
+
Free & Open Source (MIT) by Trust & Thread — https://www.trustandthread.com
|
|
5
|
+
|
|
6
|
+
Zero dependencies. Pure stdlib Python 3.6+. Run:
|
|
7
|
+
python3 cfsr_decode.py <CFSR_HEX> [BFAR_HEX] [MMFAR_HEX] [HFSR_HEX]
|
|
8
|
+
python3 cfsr_decode.py --example
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
VERSION = "1.1.0"
|
|
14
|
+
SITE = "https://www.trustandthread.com"
|
|
15
|
+
|
|
16
|
+
UFSR_BITS = [
|
|
17
|
+
(1 << 9, "DIVBYZERO", "Integer divide by zero executed (SDIV/UDIV).",
|
|
18
|
+
"Set CCR.DIV_0_TRP deliberately, or guard divisors before executing."),
|
|
19
|
+
(1 << 8, "UNALIGNED", "Unaligned memory access with alignment trapping enabled.",
|
|
20
|
+
"Unaligned LDM/STM/STRD/LDRD or CCR.UNALIGN_TRP triggered. Fix the pointer or the packed struct."),
|
|
21
|
+
(1 << 3, "NOCP", "Coprocessor access with CPACR disabled (classic: FPU used before it is enabled).",
|
|
22
|
+
"Enable FPU in CPACR before any float code runs — check startup code and ISRs that use float."),
|
|
23
|
+
(1 << 2, "INVPC", "Invalid PC load — integrity check failed on EXC_RETURN.",
|
|
24
|
+
"Corrupted exception stack frame or wrong EXC_RETURN value returned from an ISR."),
|
|
25
|
+
(1 << 1, "INVSTATE", "Attempted invalid instruction-set state (e.g. EPSR.T=0, ARM-mode branch).",
|
|
26
|
+
"Bad function pointer, corrupted link register, or branch to data. Check BL/BX targets."),
|
|
27
|
+
(1 << 0, "UNDEFINSTR", "Undefined instruction executed.",
|
|
28
|
+
"Usually PC ran into data or flash was read incorrectly (wrong clock/flash latency). Check the LR/PC."),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
BFSR_BITS = [
|
|
32
|
+
(1 << 7, "BFARVALID", "BFAR holds the valid faulting address.",
|
|
33
|
+
"Inspect BFAR — it points at the exact offending access."),
|
|
34
|
+
(1 << 5, "LSPERR", "Bus fault during floating-point lazy state preservation.",
|
|
35
|
+
"Fault in FP stack frame push on exception entry. Check stack region validity."),
|
|
36
|
+
(1 << 4, "STKERR", "Bus fault on stacking for exception entry.",
|
|
37
|
+
"Stack pointer invalid or stack overflowed into unmapped memory."),
|
|
38
|
+
(1 << 3, "UNSTKERR", "Bus fault on unstacking for exception return.",
|
|
39
|
+
"Stack frame corrupted or SP altered before exception return."),
|
|
40
|
+
(1 << 2, "IMPRECISERR", "Imprecise data bus error (async, from write buffer).",
|
|
41
|
+
"The reported PC is NOT the faulting instruction. Enable write buffering flush or use precise mode to localize."),
|
|
42
|
+
(1 << 1, "PRECISERR", "Precise data bus error on a valid address.",
|
|
43
|
+
"BFAR is valid — the faulting instruction and address are both known."),
|
|
44
|
+
(1 << 0, "IBUSERR", "Instruction bus error during prefetch.",
|
|
45
|
+
"Branch into unmapped/non-executable memory. Check the branch target and linker script regions."),
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
MMFSR_BITS = [
|
|
49
|
+
(1 << 7, "MMARVALID", "MMFAR holds the valid faulting address.",
|
|
50
|
+
"Inspect MMFAR — it points at the exact offending access."),
|
|
51
|
+
(1 << 5, "MLSPERR", "MemManage fault during FP lazy state preservation.",
|
|
52
|
+
"MPU rejects stack frame push on exception entry. Check stack region MPU config."),
|
|
53
|
+
(1 << 4, "MSTKERR", "MemManage fault on stacking for exception entry.",
|
|
54
|
+
"MPU blocks exception stack push — classic MPU stack-overflow signature."),
|
|
55
|
+
(1 << 3, "MUNSTKERR", "MemManage fault on unstacking for exception return.",
|
|
56
|
+
"MPU blocks exception stack pop. Stack region changed while exception active."),
|
|
57
|
+
(1 << 1, "DACCVIOL", "Data access violation (MPU region or null-pointer dereference).",
|
|
58
|
+
"MMFAR shows the address. Address 0x0 usually means a NULL pointer was dereferenced."),
|
|
59
|
+
(1 << 0, "IACCVIOL", "Instruction access violation (execute-never region or bad branch).",
|
|
60
|
+
"Jumped into a non-executable MPU region. Check function pointers and XN attributes."),
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
HFSR_BITS = [
|
|
64
|
+
(1 << 30, "FORCED", "HardFault is an escalated configurable fault (configurable fault handler missing or itself faulted).",
|
|
65
|
+
"CFSR holds the real cause. A fault handler was missing, or the handler faulted again."),
|
|
66
|
+
(1 << 1, "VECTTBL", "Fault on vector table read (bad VTOR or corrupted vector table).",
|
|
67
|
+
"Check VTOR value and that the vector table is in mapped, readable memory."),
|
|
68
|
+
(1 << 31, "DEBUGEVT", "HardFault triggered by debug event.",
|
|
69
|
+
"Only relevant under a debugger (DCFSR holds details)."),
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
def parse_hex(tok, name):
|
|
73
|
+
t = tok.strip().lower().replace("0x", "").replace("0X", "")
|
|
74
|
+
try:
|
|
75
|
+
return int(t, 16)
|
|
76
|
+
except ValueError:
|
|
77
|
+
sys.exit(f"error: {name} value '{tok}' is not valid hex")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def banner(char="=", width=66):
|
|
81
|
+
return char * width
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def report(cfsr, bfar=None, mmfar=None, hfsr=None):
|
|
85
|
+
out = []
|
|
86
|
+
w = out.append
|
|
87
|
+
w(banner())
|
|
88
|
+
w(" TRUST & THREAD :: ARM CORTEX-M FAULT REGISTER DECODER v" + VERSION)
|
|
89
|
+
w(banner())
|
|
90
|
+
w(f" CFSR : 0x{cfsr:08X}")
|
|
91
|
+
if hfsr is not None:
|
|
92
|
+
w(f" HFSR : 0x{hfsr:08X}")
|
|
93
|
+
if mmfar is not None:
|
|
94
|
+
w(f" MMFAR: 0x{mmfar:08X}")
|
|
95
|
+
if bfar is not None:
|
|
96
|
+
w(f" BFAR : 0x{bfar:08X}")
|
|
97
|
+
w(banner("-"))
|
|
98
|
+
|
|
99
|
+
ufsr = (cfsr >> 16) & 0xFFFF
|
|
100
|
+
bfsr = (cfsr >> 8) & 0xFF
|
|
101
|
+
mmfsr = cfsr & 0xFF
|
|
102
|
+
found = 0
|
|
103
|
+
|
|
104
|
+
def section(title, val, table):
|
|
105
|
+
nonlocal found
|
|
106
|
+
if not val:
|
|
107
|
+
return
|
|
108
|
+
w(f"\n [!] {title} (0x{val:0{'4' if table is UFSR_BITS else '2'}X}):")
|
|
109
|
+
for mask, name, desc, fix in table:
|
|
110
|
+
if val & mask:
|
|
111
|
+
w(f" * {name:<12} {desc}")
|
|
112
|
+
w(f" {'':<12} -> {fix}")
|
|
113
|
+
found += 1
|
|
114
|
+
|
|
115
|
+
section("UsageFault", ufsr, UFSR_BITS)
|
|
116
|
+
section("BusFault", bfsr, BFSR_BITS)
|
|
117
|
+
section("MemManage Fault", mmfsr, MMFSR_BITS)
|
|
118
|
+
|
|
119
|
+
if hfsr is not None:
|
|
120
|
+
if hfsr & (1 << 30):
|
|
121
|
+
w("\n [!] HardFault: FORCED — escalated configurable fault (see CFSR above).")
|
|
122
|
+
found += 1
|
|
123
|
+
if hfsr & (1 << 1):
|
|
124
|
+
w("\n [!] HardFault: VECTTBL — vector table read fault (check VTOR).")
|
|
125
|
+
found += 1
|
|
126
|
+
if hfsr & (1 << 31):
|
|
127
|
+
w("\n [!] HardFault: DEBUGEVT — debug event escalated (debugger context).")
|
|
128
|
+
found += 1
|
|
129
|
+
|
|
130
|
+
if mmfsr & (1 << 7) and mmfar is not None:
|
|
131
|
+
tip = "NULL POINTER DEREFERENCE" if mmfar == 0 else "inspect this MPU region / linker map"
|
|
132
|
+
w(f"\n [>] MMFAR = 0x{mmfar:08X} ({tip})")
|
|
133
|
+
if bfsr & (1 << 7) and bfar is not None:
|
|
134
|
+
region = classify_address(bfar)
|
|
135
|
+
w(f" [>] BFAR = 0x{bfar:08X} ({region})")
|
|
136
|
+
|
|
137
|
+
if found == 0:
|
|
138
|
+
w("\n [?] No standard bits set. If this is a HardFault, capture CFSR/HFSR at")
|
|
139
|
+
w(" the fault handler entry (See 'HardFault in handlers' in the checklist).")
|
|
140
|
+
|
|
141
|
+
w("\n" + banner())
|
|
142
|
+
w(" NEXT STEPS & REMEDIATION:")
|
|
143
|
+
w(" 1. Free register-level crash checklist (5 min read):")
|
|
144
|
+
w(f" --> {SITE}/firmware-checklist/")
|
|
145
|
+
w(" 2. Production-grade C HardFault handlers + memory templates ($49):")
|
|
146
|
+
w(f" --> {SITE}/toolkit/")
|
|
147
|
+
w(" 3. Need this crash root-caused in 48 hours? Book engineering triage ($199):")
|
|
148
|
+
w(f" --> {SITE}/consultation/")
|
|
149
|
+
w(banner() + "\n")
|
|
150
|
+
print("\n".join(out))
|
|
151
|
+
return 0 if found else 2
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def classify_address(addr):
|
|
155
|
+
if addr == 0:
|
|
156
|
+
return "NULL pointer"
|
|
157
|
+
if 0x00000000 <= addr < 0x20000000:
|
|
158
|
+
return "Code / flash region"
|
|
159
|
+
if 0x20000000 <= addr < 0x40000000:
|
|
160
|
+
return "SRAM region"
|
|
161
|
+
if 0x40000000 <= addr < 0x60000000:
|
|
162
|
+
return "Peripheral region (bit-band / APB / AHB)"
|
|
163
|
+
if 0xE0000000 <= addr < 0xE0100000:
|
|
164
|
+
return "Private peripheral bus (SCB/NVIC/sysctl)"
|
|
165
|
+
if 0x60000000 <= addr < 0xA0000000:
|
|
166
|
+
return "External RAM region"
|
|
167
|
+
return "Vendor-specific / external memory region"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
EXAMPLE = """
|
|
171
|
+
# Realistic example: unaligned access fault with known address
|
|
172
|
+
python cfsr_decode.py 0x00010200 0x20001FF7
|
|
173
|
+
|
|
174
|
+
# Null-pointer dereference caught by MPU (MemManage):
|
|
175
|
+
python cfsr_decode.py 0x00000082 0x00000000 0x00000000
|
|
176
|
+
|
|
177
|
+
# HardFault with FORCED set (escalated fault) + faulting address:
|
|
178
|
+
python cfsr_decode.py 0x00008200 0x40021000 -- 0x40000000
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def usage():
|
|
183
|
+
print(__doc__.strip())
|
|
184
|
+
print(EXAMPLE)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def main():
|
|
188
|
+
args = sys.argv[1:]
|
|
189
|
+
if not args or args[0] in ("-h", "--help"):
|
|
190
|
+
usage()
|
|
191
|
+
return 1
|
|
192
|
+
if args[0] == "--example":
|
|
193
|
+
print(EXAMPLE)
|
|
194
|
+
return 0
|
|
195
|
+
if args[0] in ("-v", "--version"):
|
|
196
|
+
print(f"cfsr-decode v{VERSION}")
|
|
197
|
+
return 0
|
|
198
|
+
|
|
199
|
+
vals = [a for a in args if a != "--"]
|
|
200
|
+
if len(vals) < 1 or len(vals) > 4:
|
|
201
|
+
usage()
|
|
202
|
+
return 1
|
|
203
|
+
cfsr = parse_hex(vals[0], "CFSR")
|
|
204
|
+
bfar = parse_hex(vals[1], "BFAR") if len(vals) > 1 else None
|
|
205
|
+
mmfar = parse_hex(vals[2], "MMFAR") if len(vals) > 2 else None
|
|
206
|
+
hfsr = parse_hex(vals[3], "HFSR") if len(vals) > 3 else None
|
|
207
|
+
return report(cfsr, bfar, mmfar, hfsr)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
if __name__ == "__main__":
|
|
211
|
+
sys.exit(main())
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cfsr-decoder
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Zero-dependency ARM Cortex-M fault status register decoder CLI
|
|
5
|
+
Author-email: Trust & Thread <contact@trustandthread.com>
|
|
6
|
+
Project-URL: Homepage, https://www.trustandthread.com
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/GaneshMba4066/cfsr-decoder/issues
|
|
8
|
+
Project-URL: Documentation, https://www.trustandthread.com/firmware-checklist/
|
|
9
|
+
Keywords: arm,cortex-m,stm32,hardfault,firmware,debugging,cfsr
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
14
|
+
Requires-Python: >=3.6
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# cfsr-decoder
|
|
20
|
+
|
|
21
|
+
A zero-dependency ARM Cortex-M fault status register decoder for embedded systems students, hobbyists, and firmware engineers.
|
|
22
|
+
|
|
23
|
+
Whenever an STM32, RP2040, NXP, or SAM microcontroller locks up in an infinite `HardFault_Handler` loop, the CPU writes the failure cause into the ARM core registers (`CFSR`, `HFSR`, `BFAR`, `MMFAR`).
|
|
24
|
+
|
|
25
|
+
Decoding those bitmasks manually from the ARM Architecture Reference Manual is slow. `cfsr-decode` turns raw hex register dumps into clear, plain-English diagnostics and recovery steps.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Quick Start (Zero Dependencies)
|
|
30
|
+
|
|
31
|
+
Runs directly with standard Python 3.6+:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# General syntax
|
|
35
|
+
python cfsr_decode.py <CFSR_HEX> [BFAR_HEX] [MMFAR_HEX] [HFSR_HEX]
|
|
36
|
+
|
|
37
|
+
# Try a realistic unaligned access fault
|
|
38
|
+
python cfsr_decode.py 0x00010200 0x20001FF7
|
|
39
|
+
|
|
40
|
+
# View all built-in examples
|
|
41
|
+
python cfsr_decode.py --example
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cfsr_decode
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cfsr-decoder"
|
|
7
|
+
version = "1.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Trust & Thread", email="contact@trustandthread.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "Zero-dependency ARM Cortex-M fault status register decoder CLI"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.6"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Topic :: Software Development :: Embedded Systems",
|
|
19
|
+
]
|
|
20
|
+
keywords = ["arm", "cortex-m", "stm32", "hardfault", "firmware", "debugging", "cfsr"]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
"Homepage" = "https://www.trustandthread.com"
|
|
24
|
+
"Bug Tracker" = "https://github.com/GaneshMba4066/cfsr-decoder/issues"
|
|
25
|
+
"Documentation" = "https://www.trustandthread.com/firmware-checklist/"
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
cfsr-decode = "cfsr_decode:main"
|